linux内核学习之总线驱动设备ksetkobject

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux内核学习之总线驱动设备ksetkobject相关的知识,希望对你有一定的参考价值。

  最近在研究总线的注册、设备与驱动在总线上的注册、驱动如何找到总线上的设备进行匹配、设备又如何找到总线上的设备进行匹配,在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为例子,因为是比较特殊的。不贴代码,详细看内核源码。

  (1)总线注册函数bus_register,kobject是bus_type->p->sysbus->kobj

  注册platform_bus时:

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

    platform_bus的kobject->kset指向bus_kset,。

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

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

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

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

  (2)设备注册函数device_register, kobject是device->kobj

  我先贴个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

 

以上是关于linux内核学习之总线驱动设备ksetkobject的主要内容,如果未能解决你的问题,请参考以下文章

驱动学习之驱动体验

(笔记)Linux内核学习之I/O层和I/O调度机制

Linux音频驱动学习之:ASOC分析

面向对象地分析Linux内核设备驱动——Linux内核设备模型与总线

面向对象地分析Linux内核设备驱动——Linux内核设备模型与总线

Linux驱动学习之驱动开发准备工作