Linux设备管理(四):总线、设备、驱动三者之间的联系

/************************************************************************************

*本文为个人学习记录,如有错误,欢迎指正。

*本文参考资料: 

*        https://www.cnblogs.com/andtt/articles/2178905.html

*        https://blog.csdn.net/yueqian_scut/article/details/46694417

*        https://blog.csdn.net/babyzhaoshu521/article/details/60350843

************************************************************************************/

1. 总线

在物理层面上,总线代表着同类设备需要共同遵守的工作时序,不同的总线对于物理电平的要求是不一样的,对于每个比特的电平维持宽度也是不一样,而总线上传递的命令也会有自己的格式约束。如I2C总线、USB总线、PCI总线等等。以I2C总线为例,在同一组I2C总线上连接着不同的I2C设备。

在软件层面上,总线的主要作用是管理设备与驱动。

Linux内核中使用struct bus_type描述一个总线,其中包含了该总线的所有信息。

//所在文件/kernel/drivers/base/base.h
struct bus_type {
    const char        *name;                 //总线类型名称
    struct bus_attribute    *bus_attrs;      //总线属性
    struct device_attribute    *dev_attrs;   //设备属性
    struct driver_attribute    *drv_attrs;   //驱动程序属性

    int (*match)(struct device *dev, struct device_driver *drv);
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
    int (*probe)(struct device *dev);
    int (*remove)(struct device *dev);
    void (*shutdown)(struct device *dev);

    int (*suspend)(struct device *dev, pm_message_t state);
    int (*resume)(struct device *dev);

    const struct dev_pm_ops *pm;

    struct bus_type_private *p;
};

struct bus_type_private {
    struct kset subsys;
    struct kset *drivers_kset;
    struct kset *devices_kset;
    struct klist klist_devices;
    struct klist klist_drivers;
    struct blocking_notifier_head bus_notifier;
    unsigned int drivers_autoprobe:1;
    struct bus_type *bus;
};
struct bus_type

2. 设备

设备代表真实的、具体的物理器件。在软件层面上,用器件的独特的参数属性来代表该器件。如I2C总线上连接的I2C从设备都有一个标识自己的设备地址,由这个设备地址来确定主设备发过来的命令是否该由它来响应。

struct device是一个基类,被设备相关的数据结构包含,其中包含了该设备的信息。

struct device {
    struct device          *parent;
    struct device_private  *p;
    struct kobject kobj;
    const char          *init_name;  /* initial name of the device */
    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;

#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;
    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 */
    struct dev_archdata    archdata;
#ifdef CONFIG_OF
    struct device_node    *of_node;
#endif

    dev_t    devt;    /* dev_t, creates the sysfs "dev" */
    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_private {
    struct klist klist_children;
    struct klist_node knode_parent;
    struct klist_node knode_driver;
    struct klist_node knode_bus;
    void *driver_data;
    struct device *device;
};
struct device

3. 驱动

驱动代表着操作设备的方式和流程。驱动主要包括两部分,第一是通过对SoC的控制寄存器进行编程,按总线要求输出时序和命令,成功地与外围设备进行交互;第二是对第一步中得到的数据进行处理,并向应用层提供特定格式的数据。

struct driver是一个基类,被驱动相关的数据结构包含,其中包含了该驱动的信息。

struct device_driver {
    const char        *name;
    struct bus_type   *bus;
    struct module     *owner;
    const char        *mod_name;    /* used for built-in modules */
    bool suppress_bind_attrs;       /* disables bind/unbind via sysfs */
#if defined(CONFIG_OF)
    const struct of_device_id    *of_match_table;
#endif
    int (*probe) (struct device *dev);
    int (*remove) (struct device *dev);
    void (*shutdown) (struct device *dev);
    int (*suspend) (struct device *dev, pm_message_t state);
    int (*resume) (struct device *dev);
    const struct attribute_group **groups;
    const struct dev_pm_ops *pm;
    struct driver_private *p;
};


struct driver_private {
    struct kobject kobj;
    struct klist klist_devices;
    struct klist_node knode_bus;
    struct module_kobject *mkobj;
    struct device_driver *driver;
};
struct device_driver

4. 总线、设备、驱动三者之间的联系

上图为平台总线设备驱动模型的整体框架。

上图为平台总线设备驱动模型的整体框架。

在总线设备驱动模型中,需关心总线、设备和驱动这3个实体,总线将设备和驱动绑定。

当系统向内核注册每一个驱动程序时,都要通过调用驱动注册函数(xxx_driver_register)将驱动程序注册到总线,并将其放入所属总线的drv链表中,注册驱动的时候会调用所属总线的match函数寻找该总线上与之匹配的每一个设备,如果找到与之匹配的设备则会调用相应的probe函数将相应的设备和驱动进行绑定;同样的当系统向内核注册每一个设备时,都要通过调用设备注册函数(xxx_device_register)将设备注册到总线,并将其放入所属总线的dev链表中,注册设备的时候同样也会调用所属总线的match函数寻找该总线上与之匹配的每一个驱动程序,如果找到与之匹配的驱动程序时会调用相应的probe函数将相应的设备和驱动进行绑定;而这一匹配的过程是由总线自动完成的。

总线在匹配设备和驱动之后驱动要考虑一个这样的问题,设备对应的软件数据结构代表着静态的信息,真实的物理设备此时是否正常还不一定,因此驱动需要探测这个设备是否正常。总线的管理代码中会有这样的逻辑:

 if(match(device, driver) == OK)

  driver->probe();

总线匹配设备和驱动之后,驱动探测到设备正常,开始创建设备文件。调用class_create()、device_create()函数在/dev目录下创建相应的设备文件,其内部原理是通过sysfs文件系统、uevent事件通知机制和后台应用服务mdev程序配合能够成功地在/dev目录创建对应的设备文件。详见Linux设备文件的创建

原文地址:https://www.cnblogs.com/linfeng-learning/p/9324268.html