zoukankan      html  css  js  c++  java
  • 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下的所有设备进行匹配操作。

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

     

     

  • 相关阅读:
    程序命名规则
    CSS样式常用命名参考
    转:数据挖掘资料收集
    javascript占位符
    网站目录,文件夹命名规范
    IIS HTTP 500 内部服务器错误完美解决 IIS 服务器无法加载应用程序 '/LM/W3SVC/1/ROOT'。错误是 '没有注册类别
    人事工资合同管理系统菜单截图
    Vs 正则表达式 查找替换 微软权威参考
    什么是DNS,A记录,子域名,CNAME别名,MX记录,TXT记录,SRV 记录,TTL值
    MT主机控制面板Plesk 使用指南
  • 原文地址:https://www.cnblogs.com/zero-jh/p/5205089.html
Copyright © 2011-2022 走看看