《补充 — Linux内核device结构体分析(转)》
1、前言
Linux内核中的设备驱动模型,是建立在sysfs设备文件系统和kobject上的,由总线(bus)、设备(device)、驱动(driver)和类(class)所组成的关系结构,在底层,Linux系统中的每个设备都有一个device结构体的实例,本文将对Linux内核的device结构体以及相关结构进行简要分析。
2、device结构体
在Linux内核源码中,struct device结构体的定义在include/linux/device.h中,实现的主要方法在drivers/base/core.c文件中,device结构体的定义如下所示:
struct device { struct device *parent; struct device_private *p; struct kobject kobj; const char *init_name; /* initial name of the device */ 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 */ void *driver_data; /* Driver data, set and get with dev_set/get_drvdata */ struct dev_links_info links; struct dev_pm_info power; struct dev_pm_domain *pm_domain; #ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN struct irq_domain *msi_domain; #endif #ifdef CONFIG_PINCTRL struct dev_pin_info *pins; #endif #ifdef CONFIG_GENERIC_MSI_IRQ struct list_head msi_list; #endif #ifdef CONFIG_NUMA int numa_node; /* NUMA node this device is close to */ #endif const struct dma_map_ops *dma_ops; 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 bit addresses for consistent allocations such descriptors. */ unsigned long dma_pfn_offset; 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_DMA_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 */ struct fwnode_handle *fwnode; /* firmware device 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 iommu_group *iommu_group; struct iommu_fwspec *iommu_fwspec; bool offline_disabled:1; bool offline:1; bool of_node_reused:1; };
部分结构体成员解释:
- parent:指向设备的“父”设备,它所连接的设备,在大多数情况下,父设备是某种总线或主机控制器,如果该成员为NULL,则该设备为顶级设备;
- p:用于保存设备驱动核心部分的私有数据;
- kobj:嵌入的struct kobject对象实例;
- init_name:设备的初始名称
- type:设备的类型,用于标识设备类型并携带特定类型信息;
- mutex:用于同步的互斥锁;
- bus:该设备所处于的总线;
- driver:该设备所分配的驱动程序;
- platform_data:设备中特定的平台数据;
- driver_data:指向驱动程序特定的私有数据;
- of_node:与设备树相联系的结构体指针;
- devt:用于表示设备的设备号;
- devres_lock:保护设备资源的自旋锁;
- devres_head:设备资源的双向链表头;
- knode_class:接入class链表时所需要的klist节点;
- class:指向设备所属class的指针;
- groups:该设备的属性集合;
- release:函数指针,当设备需要释放时调用此函数。
device结构体中有一部分成员不愿意被外界看到,所以抽象出了struct device_private这个结构体,该结构体包括了设备驱动模型内部的链接,结构体定义如下:
struct device_private { struct klist klist_children; struct klist_node knode_parent; struct klist_node knode_driver; struct klist_node knode_bus; struct list_head deferred_probe; struct device *device; };
部分结构体成员解释:
- klist_children:子设备的klist链表;
- knode_parent:接入父设备的klist_children时所需要的klist节点;
- knode_driver:接入驱动的设备链表时所需要的klist节点;
- knode_bus:接入总线的设备链表时所需要的klist节点;
- device:回指struct device结构体的指针。
device结构体中包含了一个struct device_type结构体的指针,用于描述设备的类型,该结构体定义如下:
struct device_type { const char *name; const struct attribute_group **groups; int (*uevent)(struct device *dev, struct kobj_uevent_env *env); char *(*devnode)(struct device *dev, umode_t *mode, kuid_t *uid, kgid_t *gid); void (*release)(struct device *dev); const struct dev_pm_ops *pm; };
该结构体功能类似于kobj_type。
还有一个设备属性结构体,名称为struct device_attribute,是对struct attribute的进一步封装,并提供了设备属性的读写函数指针,结构体定义如下:
/* interface for exporting device attributes */ struct device_attribute { struct attribute attr; ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); };
其它的一些struct device结构体成员,例如archdata、dma和devres等,是一些设备特有的东西,暂时不讨论,本文主要关心设备驱动模型的基本建立。
3.device_node
/* 节点 */ struct device_node { const char *name; /* 节点中属性为name的值 */ const char *type; /* 节点中属性为device_type的值 */ char *full_name; /* 节点的名字,在device_node结构体后面放一个字符串,full_name指向它 */ struct property *properties; /* 链表,连接该节点的所有属性 */ struct device_node *parent; /* 指向父节点 */ struct device_node *child; /* 指向孩子节点 */ struct device_node *sibling; /* 指向兄弟节点 */ }; /* 属性 */ struct property { char *name; /* 属性的名字,指向设备树文件的string block */ int length; /* 属性名字的字节数 */ void *value; /* 属性的值,指向struct block */ struct property *next; /* 链表,连接下一个属性 */ };
在platform_device中有一个成员struct device dev,这个dev中又有一个指针成员struct device_node *of_node,linux的做法就是将这个of_node指针直接指向由设备树转换而来的device_node结构。
例如,有这么一个struct platform_device* of_test.我们可以直接通过of_test->dev.of_node来访问设备树中的信息。
转自:https://www.cnblogs.com/Cqlismy/p/11507216.html