《补充 — 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

原文地址:https://www.cnblogs.com/zhuangquan/p/12610956.html