linux内核学习之总线、驱动、设备、kset、kobject

  最近在研究总线的注册、设备与驱动在总线上的注册、驱动如何找到总线上的设备进行匹配、设备又如何找到总线上的设备进行匹配,在linux2.6以后,这些过程都离不开设备驱动模型,所以也与kset、kobjcet有关。

  kobject就是一个对象,kset就是所有相同对象的集合,linux的设备驱动模型是用C语言实现面向对象。用linux时使用ls命令查看的文件和目录就是对应每一个kobject。

 

  一.设备device、驱动device_driver、总线bus_type、kobject、kset结构如下:

  (1)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;/* Like dma_mask, but for
                         alloc_coherent mappings as
                         not all hardware supports
                         64 bit addresses for consistent
                         allocations such descriptors. */

    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 */
    /* arch specific additions */
    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);
};
View Code

   struct device_private

struct device_private {
    struct klist klist_children;
    struct klist_node knode_parent;
    struct klist_node knode_driver;
    /* knode_bus:
     * 1.注册设备时会将knode_bus成员加入到设备所在总线bus->p->klist_devices链,表示已注册到总线
     * 2.同理,注销设备时会在设备所在总线bus->p->klist_devices链寻找设备->p->knode_bus节点并移除
     */
    struct klist_node knode_bus;  
    void *driver_data;
    /* device:
     * 常指向设备自己,这样就可以通过device_private找到device
     */
    struct device *device; 
};
View Code

  (2)struct device_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;
};
View Code

    struct driver_private

struct driver_private {
    struct kobject kobj;
    struct klist klist_devices;
    /* knode_bus:
     * 1.注册设备时会将knode_bus成员加入到设备所在总线bus->p->klist_devices链,表示已注册到总线
     * 2.同理,注销设备时会在设备所在总线bus->p->klist_devices链寻找设备->p->knode_bus节点并移除
     */
    struct klist_node knode_bus;
    struct module_kobject *mkobj;
    /* driver:
     * 常指向驱动自己, 这样就可以通过driver_private找到device_driver
     */
    struct device_driver *driver; 
};
View Code

  (3)struct bus_type

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 subsys_private *p;
};
View Code

    struct subsys_private

struct subsys_private {
    struct kset subsys;
    struct kset *devices_kset;

    struct kset *drivers_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 list_head class_interfaces;
    struct kset glue_dirs;
    struct mutex class_mutex;
    struct class *class;
};
View Code 

  (4)struct kobject

struct kobject {
    const char        *name;
    struct list_head    entry;
    struct kobject        *parent;
    struct kset        *kset;
    struct kobj_type    *ktype;
    struct sysfs_dirent    *sd;
    struct kref        kref;
    unsigned int state_initialized:1;
    unsigned int state_in_sysfs:1;
    unsigned int state_add_uevent_sent:1;
    unsigned int state_remove_uevent_sent:1;
    unsigned int uevent_suppress:1;
};
View Code

  (5)struct kset

struct kset {
    struct list_head list;
    spinlock_t list_lock;
    struct kobject kobj;
    const struct kset_uevent_ops *uevent_ops;
};
View Code

  设备、驱动、总线结构都含有1个kobject结构。(device->kobj, device_driver->driver_private->kobj, bus_type->p->subsys->kobj).

  在说注册之前,先说一下二个结构bus_kset、devices_kset。这二个结构是在启动内核时调用driver_init中,调用devices_init和buses_init函数初始化的。bus_kset管理所有总线的,devices管理所有物理设备的。其中有一个例外,就是platform_bus结构,平台总线本来就是不存在的,是虚拟出来的一条总线,是一个设备。这里不详说这个。

  

  二.设备、总线、驱动注册

  这里我简单的说一下它们在注册时在干什么,以注册platform_bus、platform_dev、platform_driver为例子,其中platform_dev包含device结构,platform_driver包含device_driver结构。不贴代码,详细看内核源码。

  (1)总线注册device_register(&platform_bus)与bus_register(&platform_bus_type)。

  注册platform_bus时:

    初始化platform_bus->p私有数据。

    platform_bus的kobject->kset指向devices_kset。

    platform_bus的kobject->parent指向devices_kset->kobj。

    platform_bus的kobject->entry节点加入到devices_kset->list链表中。

  注册platform_bus_type时:

    初始化platform_bus_type->p私有数据。

    platform_bus_type的kobject->kset指向bus_kset。

    platform_bus_type的kobject->parent指向bus_kset->kobj,。

    platform_bus_type的kobject->entry节点加入到bus_kset->list链表中。

    初始化platform_bus_type->p->drivers_kset(用来管理总线下的驱动的集合)。

    初始化platform_bus_type->p->devices_kset(总线下的设备的kobject不会加入这个集合, 但是利用软连接链入这个集合)。

  (2)设备注册到总线platform_device_register

  我先贴个device_register函数源码出来:

int device_register(struct device *dev)
{
    device_initialize(dev);
    return device_add(dev);
}
View Code

  而注册platform_device是用platform_device_register函数的:

int platform_device_register(struct platform_device *pdev)
{
    device_initialize(&pdev->dev);
    return platform_device_add(pdev);
}

int platform_device_add(struct platform_device *pdev)
{
    int i, ret = 0;

    if (!pdev)
        return -EINVAL;

    if (!pdev->dev.parent)
        pdev->dev.parent = &platform_bus;

        pdev->dev.bus = &platform_bus_type;
        ...
        ...
        ret = device_add(&pdev->dev);
        ...
        ...
}
View Code

  两者相差指定父设备与总线。device_register只是简单的注册一个设备,然后kobject交给device_kset管理。platform_device_register是注册一个platform_device到platform_bus_type总线下,kobject加入到device_kset但由platform_bus_type总线管理。

  所以注册一个platform_device时:

    初始化platform_device->dev->p私有数据。

    platform_device的kobject->kset指向devices_kset。

    platform_device->dev->parent指向platform_bus。

    platform_device->dev->bus指向platform_bus_type。

    因为platform_device->dev->parent指向platform_bus, 所以platform_device的kobject->parent指向platform_bus->kobj。

    platform_device的kobject->entry节点加入到device_kset->list链表中。

    platform_device->dev->kobj软连接到platform_bus->p->devices_kset中。

    platform_device->dev->p->knode_parent节点加入到platform_bus->p->klist_children链表(klist)中。

    platform_device->dev->p->knode_bus节点加入到platform_bus_type->p->klist_devices链表(klist)中。

    注册platform_device会遍历platform_bus_type下的所有驱动进行匹配操作。

  (3)注册驱动到总线platform_driver_register

   贴个platform_driver_register出来,指定总线并最后调用的driver_register

int platform_driver_register(struct platform_driver *drv)
{
    drv->driver.bus = &platform_bus_type;
    if (drv->probe)
        drv->driver.probe = platform_drv_probe;
    if (drv->remove)
        drv->driver.remove = platform_drv_remove;
    if (drv->shutdown)
        drv->driver.shutdown = platform_drv_shutdown;

    return driver_register(&drv->driver);
}
View Code

  所以注册platform_driver时:

    初始化platform_driver->driver->私有数据。

    platform_driver->driver->bus指向platform_bus_type。

    platform_driver的kobject->kset指向platform_bus_type->p->drivers_kset

    platform_driver的kobject->entry节点加入到platform_bus_type->p->drivers_kset->list链表中。

    platform_driver->driver->p->knode_bus节点加入到platform_bus_type->p->klist_drivers链表(klist)中。

    注册platform_driver会遍历platform_bus_type下的所有设备进行匹配操作。

 

   三、平台总线、驱动、设备注册后的图如下。

 

 

posted @ 2016-02-21 16:03  zer-o  阅读(1046)  评论(0编辑  收藏  举报