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) )
大致有以下过程:
- 在虚拟文件系统VFS中的查找对应与字符设备对应 **struct inode**节点
- 遍历字符设备列表(chardevs数组),根据inod节点中的 cdev_t设备号找到cdev对象
- 创建struct file对象(系统采用一个数组来管理一个进程中的多个被打开的设备,每个文件描述符作为数组下标标识了一个设备对象)
- 初始化struct file对象,将 struct file对象中的 file_operations成员指向 struct cdev对象中的 file_operations成员(file->fops = cdev->fops)
- 回调file->fops->open函数
inode结构体
VFS inode 包含文件访问权限、属主、组、大小、生成时间、访问时间、最后修改时间等信息。它是Linux 管理文件系统的最基本单位,也是文件系统连接任何子目录、文件的桥梁。
内核使用inode结构体在内核内部表示一个文件。因此,它与表示一个已经打开的文件描述符的结构体(即file 文件结构)是不同的,我们可以使用多个file 文件结构表示同一个文件的多个文件描述符,但此时,所有的这些file文件结构全部都必须只能指向一个inode结构体。
inode结构体包含了一大堆文件相关的信息,但是就针对驱动代码来说,我们只要关心其中的两个域即可:
- dev_t i_rdev; 表示设备文件的结点,这个域实际上包含了设备号。
- struct cdev *i_cdev; struct cdev是内核的一个内部结构,它是用来表示字符设备的,当inode结点指向一个字符设备文件时,此域为一个指向inode结构的指针。
file文件结构体
在设备驱动中,这也是个非常重要的数据结构,必须要注意一点,这里的file与用户空间程序中的FILE指针是不同的,用户空间FILE是定义在C库中,从来不会出现在内核中。而struct file,却是内核当中的数据结构,因此,它也不会出现在用户层程序中。
file结构体指示一个已经打开的文件(设备对应于设备文件),其实系统中的每个打开的文件在内核空间都有一个相应的struct file结构体,它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数,直至文件被关闭。如果文件被关闭,内核就会释放相应的数据结构。