《补充 — 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
浙公网安备 33010602011771号