zoukankan      html  css  js  c++  java
  • 《补充 — 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

  • 相关阅读:
    嵌入式学习路线
    redhat历史以及对应的内核版本
    " Provisioning profile XXXX can't be found"
    IOS 单例模式
    【IOS】开源项目汇总(更新时间2012611)
    'release' is unavailable: not available in automatic reference counting mode.
    不要使用SBJSON(jsonframework)
    viewDidUnload 和 dealloc 的区别
    unrecognized selector sent to instance 问题的解决方法
    通过xib同样可以让UIView背景透明
  • 原文地址:https://www.cnblogs.com/zhuangquan/p/12610956.html
Copyright © 2011-2022 走看看