嵌入式Linux驱动开发相关结构体

struct platform_device

参考:include/platform_device.h

对struct device的封装(其中包含struct device)

struct platform_device {
	const char	*name;
	int		id;
	bool		id_auto;
	struct device	dev;	/* struct device */
	u32		num_resources;
	struct resource	*resource;

	const struct platform_device_id	*id_entry;
	char *driver_override; /* Driver name to force a match */

	/* MFD cell pointer */
	struct mfd_cell *mfd_cell;

	/* arch specific additions */
	struct pdev_archdata	archdata;
};

struct device

参考:include/device.h,在第600多行。

对struct device_node的封装(其中包含struct device_node)

/**
 * struct device -基本设备结构体
 * @parent:设备的父设备,设备之间是联系到一起的。大部分情况下,父设备会是一个总线或者主机控制器,如果父设备是空,此设备就是顶端设备,通常情况下这是你不想要的情况
 * @p:存储了关于设备的驱动核心部分的私有数据,详细内容可查看device_private
 * @kobj: 一种最高等级的抽象类,用于派生其他类别
 * @init_name:	设备初始化的名称
 * @type:	设备类型,它定义了设备类型并且传递了典型特有信息
 * @mutex:	用于同步驱动用的自旋锁
 * @bus:	设备所在总线类型
 * @driver:	哪种设备分配给它了
 * @platform_data: 针对设备的平台数据;例如:对于定制板上面的设备,像典型的嵌入式和SOC硬件,linux惊颤使用platform_data去指定特定的扳级数据结构去描述设备和连线方式。那样可以包含什么端口可用,芯片的变量,哪个GPIO引脚工作于复用功能,等等。这样就减少了BSP并且最小化使用关于特定板级的驱动的 #ifdefs
 * @power: 用于设备电压管理,更多信息查看Documentation/power/devices.txt
 * @pm_domain:	系统挂起,休眠,重启期间,提供执行的回调函数。
 * @numa_node:	NUMA node this device is close to.
 * @dma_mask:	Dma mask (if dma'ble device).
 * @dma_mask:	DMA屏蔽码
 * @coherent_dma_mask: 像dma_mask,但是开辟像在64位地址连续分配不是所有硬件都支持这是利用它开辟连续内存
 * @dma_parms:	一个低等级的驱动可以用它去告诉IO内存管理模块关于段的限制
 * @dma_pools:	DMA池
 * @dma_mem:	内部连续内存覆盖
 * @archdata:	用于特定架构
 * @of_node:	连接设备树节点
 * @devt:	用于创建sysfs的dev目录
 * @id:		设备实例
 * @devres_lock: 用于保护设备资源的自旋锁
 * @devres_head: 设备的资源链表
 * @knode_class: 这个节点用于添加设备到类链表
 * @class:	设备类
 * @groups:	可选的属性群
 * @release: 用于回调释放设备。它必须被相应的设备分配器调用(例如,发现设备的总线驱动)
 * LINUX 系统中的人设设备都被设备结构体实例画,设备结构体包换设备模块的信息,在子系统中,情况有所不同。一个设备被裸设备结构体代表的情况是非常少见的。由此,像kobject这种结构体,经常嵌入到更高等级的能代表设备的结构体。
 */
struct device {
	struct device		*parent;
	struct device_private	*p;
	struct kobject kobj;
    /* initial name of the device */
	const char		*init_name; 
	const struct device_type *type;
 
	struct mutex mutex;	/* mutex to synchronize calls to
					 * its driver.
					 */
 
	struct bus_type	*bus; /* type of bus device is on */
	struct device_driver *driver;	/* which driver has allocated this device */
	void	*platform_data;	/* Platform specific data, device core doesn't touch it */
	struct dev_pm_info	power;
	struct dev_pm_domain	*pm_domain;
 
#ifdef CONFIG_NUMA
	int	numa_node;/* NUMA node this device is close to */
#endif
	u64	*dma_mask;	/* dma mask (if dma'able device) */
	u64		coherent_dma_mask;/* Like dma_mask, but for
					     alloc_coherent mappings as
					     not all hardware supports
					     64 bit addresses for consistent
					     allocations such descriptors. */
 
	struct device_dma_parameters *dma_parms;
 
	struct list_head	dma_pools;	/* dma pools (if dma'ble) */
 
	struct dma_coherent_mem	*dma_mem; /* internal for coherent mem override */
#ifdef CONFIG_CMA
	struct cma *cma_area;		/* contiguous memory area for dma allocations */
#endif
	/* arch specific additions */
	struct dev_archdata	archdata;
 
	struct device_node	*of_node; /* associated device tree node */
 
	dev_t			devt;	/* dev_t, creates the sysfs "dev" */
	u32			id;	/* device instance */
 
	spinlock_t		devres_lock;
	struct list_head	devres_head;
 
	struct klist_node	knode_class;
	struct class		*class;
	const struct attribute_group **groups;	/* optional groups */
 
	void	(*release)(struct device *dev);
};

struct device_node

在include/linux/of.h中

struct device_node {
	const char *name;
	const char *type;
	phandle phandle;
	const char *full_name;
	struct fwnode_handle fwnode;

	struct	property *properties;
	struct	property *deadprops; /* removed properties */
	struct	device_node *parent;
	struct	device_node *child;
	struct	device_node *sibling;
	struct	kobject kobj;
	unsigned long _flags;
	void	*data;
#if defined(CONFIG_SPARC)
	const char *path_component_name;
	unsigned int unique_id;
	struct of_irq_controller *irq_trans;
#endif
};

struct platform_driver

struct property

在include/linux/of.h中

struct property {
	char	*name;
	int	length;
	void	*value;
	struct property *next;
	unsigned long _flags;
	unsigned int unique_id;
	struct bin_attribute attr;
};

struct inode/struct file

定义:include/linux/fs.h

应用--->系统调用--->驱动,struct file就是在系统调用这一层被创建。这也说明了有时候我们没有在驱动程序中编写应用程序对应的函数(比如drv_open)也不会报错,因为有sys_open(此函数中可能会做一些处理)。

两者关系-图解

用户空间使用open()系统调用函数打开一个字符设备时( int fd = open("dev/demo", O_RDWR) )大致有以下过程:

  1. 在虚拟文件系统VFS中的查找对应与字符设备对应 **struct inode**节点
  2. 遍历字符设备列表(chardevs数组),根据inod节点中的 cdev_t设备号找到cdev对象
  3. 创建struct file对象(系统采用一个数组来管理一个进程中的多个被打开的设备,每个文件描述符作为数组下标标识了一个设备对象)
  4. 初始化struct file对象,将 struct file对象中的 file_operations成员指向 struct cdev对象中的 file_operations成员(file->fops = cdev->fops)
  5. 回调file->fops->open函数

inode结构体

VFS inode 包含文件访问权限、属主、组、大小、生成时间、访问时间、最后修改时间等信息。它是Linux 管理文件系统的最基本单位,也是文件系统连接任何子目录、文件的桥梁。

内核使用inode结构体在内核内部表示一个文件。因此,它与表示一个已经打开的文件描述符的结构体(即file 文件结构)是不同的,我们可以使用多个file 文件结构表示同一个文件的多个文件描述符,但此时,所有的这些file文件结构全部都必须只能指向一个inode结构体

inode结构体包含了一大堆文件相关的信息,但是就针对驱动代码来说,我们只要关心其中的两个域即可:

  1. dev_t i_rdev; 表示设备文件的结点,这个域实际上包含了设备号。
  2. struct cdev *i_cdev;  struct cdev是内核的一个内部结构,它是用来表示字符设备的,当inode结点指向一个字符设备文件时,此域为一个指向inode结构的指针。

file文件结构体

在设备驱动中,这也是个非常重要的数据结构,必须要注意一点,这里的file与用户空间程序中的FILE指针是不同的,用户空间FILE是定义在C库中,从来不会出现在内核中。而struct file,却是内核当中的数据结构,因此,它也不会出现在用户层程序中。

file结构体指示一个已经打开的文件(设备对应于设备文件),其实系统中的每个打开的文件在内核空间都有一个相应的struct file结构体,它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数,直至文件被关闭。如果文件被关闭,内核就会释放相应的数据结构。

赞赏