财富坊cff888 /
  • 设备驱动 /
  • 设备驱动模型 /
  • 你好!这里是风筝的博客,

    欢迎和我一起交流。

    前几天去面试,被问到Linux设备驱动模型这个问题,没答好,回来后恶补知识,找了些资料,希望下次能答出个满意答案。


    Linux早期时候,一个驱动对应一个设备,也就对应一个硬件地址,那当有两个一样的设备的时候,就要写两个驱动,显然是不合理的。应该是从Linux2.5开始,就引入了device-bus-driver模型。
    其中设备驱动模型主要结构分为kset、kobject、ktype。

    kset是同类型kobject对象的集合,可以说是一个容器。
    kobject是总线、驱动、设备的三种对象的一个基类,实现公共接口。
    ktype,记录了kobject对象的一些属性。

    设备驱动模型的核心即是kobject,是为了管理日益增多的设备,使得设备在底层都具体统一的接口。他与sysfs文件系统紧密相连,每个注册的kobject都对应sysfs文件系统中的一个目录。为了直观管理,统一存放的路径,使用了kset。但是仅仅有这些目录没有意义,这两个结构体只能表示出设备的层次关系,所以基本不单独使用,会嵌入到更大的结构体中,(如希望在驱动目录下能看到挂在该总线上的各种驱动,而在设备目录下能看到挂在该总线的各种设备,就将kobject嵌入到描述设备以及驱动的结构体中,这样每次注册设备或驱动,都会在sys目录下有描述
    放上一个经典的图:
    这里写图片描述
    这个图其实还漏了一个ktype,kobject都应该包含一个ktype。

    Linux设备模型的目的是:为内核建立起一个统一的设备模型,从而有一个对系统结构的一般性抽象描述。

    我们可以先看下一个小的测试程序:

    #include <linux/device.h>  
    #include <linux/module.h>  
    #include <linux/init.h>  
    #include <linux/sysfs.h>  
    #include <linux/kernel.h>  
    #include <linux/stat.h>  
    #include <linux/slab.h>  
    #include <linux/string.h>
    
    static struct kset * my_kset;  
    struct test_kobj {
        int number;
        struct kobject kobj;/*嵌入更大的结构体*/
    };
    static struct test_kobj * test1;
    static struct attribute my_attr = {  
        .name = "name",  
        .mode = S_IRWXUGO,  
    };  
    /*attribute数组*/  
    static struct attribute *my_attrs[] = {  
        &my_attr, 
        NULL,  /*最后必须为NULL*/
    };
    
    static ssize_t kobject_attr_show(struct kobject *kobj, struct attribute *attr,   
                    char *buf)  
    {  
        struct test_kobj *obj = container_of(kobj, struct test_kobj, kobj);
        ssize_t count = 0;  
        printk("kobject 's number is %d\n", obj->number); 
        printk("kobject 's name is "); 
        count = sprintf(buf, "%s\n", kobject_name(kobj) );  
        return count;  
    }  
    
    static ssize_t kobject_attr_store(struct kobject *kobj, struct attribute *attr,  
                       const char *buf, size_t count)  
    { 
        struct test_kobj *obj = container_of(kobj, struct test_kobj, kobj);
        sscanf(buf, "%d", &obj->number);
        printk("%s\n", __FUNCTION__);  
        return count;  
    }
    
    static struct sysfs_ops my_sys_ops = {  
        .show   = kobject_attr_show,  
        .store  = kobject_attr_store,  
    }; 
    
    void kobject_release(struct kobject *kobj)  
    { 
        struct test_kobj *obj = container_of(kobj, struct test_kobj, kobj);
        kfree(obj);
        printk("%s\n", __FUNCTION__);   
    }
    
    static struct kobj_type my_ktype = {  
        .release        = kobject_release,  
        .sysfs_ops  = &my_sys_ops,  
        .default_attrs  = my_attrs,  
    }; 
    
    static int __init kobject_init_test(void)  
    {  
        int error; 
        my_kset = kset_create_and_add("kobject_test", NULL, NULL);  
        if (!my_kset) {  
            goto out;  
        }  
    
        test1 = kzalloc(sizeof(struct test_kobj), GFP_KERNEL);
        if (!test1) {
            kset_unregister(my_kset);
            return -ENOMEM;
        }
        test1->number= 1;
    
        error = kobject_init_and_add(&test1->kobj, &my_ktype, &my_kset->kobj, "test1");
        if(error){  
            kobject_put(&test1->kobj);  
            goto out;  
        }
    
        printk("%s success.\n", __FUNCTION__);  
        return 0;  
    
    out:  
        printk("%s failed!\n", __FUNCTION__);  
        return -1;  
    }
    
    static void __exit kobject_exit_test(void)  
    {  
        kobject_del(&test1->kobj);
        kobject_put(&test1->kobj);
        kset_unregister(my_kset);  
        printk("%s\n", __FUNCTION__);  
    }
    
    module_init(kobject_init_test);  
    module_exit(kobject_exit_test);  
    
    MODULE_DESCRIPTION("kobject test");  
    MODULE_LICENSE("GPL");  

    这里写图片描述

    可以看到,我们在使用kobject、kset、ktype结构,就在sysfs虚拟文件系统下创建(通过kset_create_and_add和kobject_init_and_add函数)了一些子目录(kobject_test)和属性文件。kset和kobject都可以创建出目录,但是kset的目录下存放kobject目录,kobject下存放属性文件(可以对属性文件进行读写操作,如上图name属性文件,而且kobject目录下也可以存放kobject目录,只需parent指向它即可)。
    这个小程序没看懂?没关系,先看下面的分析:

    我们对着Linux kernel源码分析下,可以下看看三个结构体的成员:

    struct kset {
        struct list_head list;//包含kobject的链表
        spinlock_t list_lock;//在访问链表时加锁
        struct kobject kobj;//嵌入的kobject 
        const struct kset_uevent_ops *uevent_ops;//对发往用户空间的uevent的处理,如热拔插
    };
    struct kobject {
        const char      *name;//名字
        struct list_head    entry;//连接到kset建立层次结构
        struct kobject      *parent;//指向父节点,面向对象的层次架构
        struct kset     *kset;//指向所属的kset 
        struct kobj_type    *ktype;//属性文件 
        struct kernfs_node  *sd; /* sysfs directory entry */
        struct kref     kref;//引用计数
    #ifdef CONFIG_DEBUG_KOBJECT_RELEASE
        struct delayed_work release;
    #endif
        unsigned int state_initialized:1;//初始化状态
        unsigned int state_in_sysfs:1;//是否处在sysfs下了
        unsigned int state_add_uevent_sent:1;
        unsigned int state_remove_uevent_sent:1;
        unsigned int uevent_suppress:1;
    };
    struct kobj_type {
        void (*release)(struct kobject *kobj);/*用于释放kobject占用的资源*/ 
        const struct sysfs_ops *sysfs_ops;/*提供实现以下属性的方法*/ 
        struct attribute **default_attrs;/*用于保存类型属性列表(指针的指针)*/  
        const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
        const void *(*namespace)(struct kobject *kobj);
    };
    

    其实说到设备驱动模型,很容易想到platform,之前我们也说过:财富坊cff888嵌入式Linux驱动学习笔记(五)——学习platform设备驱动
    那我们现在就来具体分析这个吧:
    init/main.c里:

    kernel_init
        ->kernel_init_freeable
            ->do_basic_setup
                ->driver_init

    这是driver_init函数:

    void __init driver_init(void)
    {
        /* These are the core pieces */
        devtmpfs_init();
        devices_init();/*device、dev目录*/
        buses_init();/*bus目录*/
        classes_init();/*class目录*/
        firmware_init();/*firmware目录*/
        hypervisor_init();/*hypervisor目录*/
        /* These are also core pieces, but must come after the
         * core core pieces.
         */
        platform_bus_init();
        cpu_dev_init();
        memory_dev_init();
        container_dev_init();
        of_core_init();
    }

    我们看下devices_init函数:

    int __init devices_init(void)
    {
        devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
        if (!devices_kset)
            return -ENOMEM;
        dev_kobj = kobject_create_and_add("dev", NULL);
        if (!dev_kobj)
            goto dev_kobj_err;
        sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
        if (!sysfs_dev_block_kobj)
            goto block_kobj_err;
        sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
        if (!sysfs_dev_char_kobj)
            goto char_kobj_err;
    
        return 0;
     char_kobj_err:
        kobject_put(sysfs_dev_block_kobj);//删除
     block_kobj_err:
        kobject_put(dev_kobj);
     dev_kobj_err:
        kset_unregister(devices_kset);
        return -ENOMEM;
    }

    这里面调用kset_create_and_add创建kset并返回给devices_kset,注意这里的devices_kset,可以说是/sys下最大的boss之一了,所有的物理设备都会在device目录下管理,/sys/device/目录是内核对系统中所有设备的分层次表达模型,保存了系统所有的设备。
    然后调用kobject_create_and_add函数在/sys/目录下创建dev目录,/sys/dev目录下维护一个按照字符设备和块设备的主次号码(major:minor)链接到真是设备(/sys/devices)的符号链接文件,应用程序通过对这些文件的读写和控制,可以访问实际的设备。
    最后再以dev_kobj为父节点,在/sys/dev/目录下创建block和char目录。

    这里我们先看kobject_create_and_add函数,再分析kset_create_and_add函数:

    struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
    {
        struct kobject *kobj;
        int retval;
    
        kobj = kobject_create();
        if (!kobj)
            return NULL;
    
        retval = kobject_add(kobj, parent, "%s", name);
        /*忽略部分无关代码*/
        return kobj;
    }

    其实里面函数也没啥,先创建kobject,初始化它,再添加,没啥好说的。
    倒是除了kobject_create_and_add函数,还有一个类似的函数:kobject_init_and_add。
    kobject_init_and_add传入一个kobject指针和kobj_type指针,然后进行初始化
    kobject_create_and_add创建一个kobject变量,并返回其指针,它不用传入kobj_type指针

    在kset_create_and_add函数里也会用到kobject,所以我们现在来分析下kset_create_and_add函数:

    struct kset *kset_create_and_add(const char *name,
                     const struct kset_uevent_ops *uevent_ops,
                     struct kobject *parent_kobj)
    {
        struct kset *kset;
        int error;
    
        kset = kset_create(name, uevent_ops, parent_kobj);
        if (!kset)
            return NULL;
        error = kset_register(kset);
        if (error) {
            kfree(kset);
            return NULL;
        }
        return kset;
    }

    里面就是具体的创建和注册kset了。
    先说创建函数:

    static struct kset *kset_create(const char *name,
                    const struct kset_uevent_ops *uevent_ops,
                    struct kobject *parent_kobj)
    {
        struct kset *kset;
        int retval;
    
        kset = kzalloc(sizeof(*kset), GFP_KERNEL);//分配kset空间
        if (!kset)
            return NULL;//失败就返回
        retval = kobject_set_name(&kset->kobj, "%s", name);//设置kset的名字,也即内嵌kobject的名字
        if (retval) {
            kfree(kset);
            return NULL;
        }
        kset->uevent_ops = uevent_ops;//kset属性操作
        kset->kobj.parent = parent_kobj;//设置其parent 
        kset->kobj.ktype = &kset_ktype;//ktype指定为kset_ktype 
        kset->kobj.kset = NULL;
    
        return kset;
    }

    可以看出kset_create函数内容为:
    1)调用kobject_set_name函数设置kobject的名称
    2)设置kobject的uevent_ops、parent为传入的形参uevent_ops、parent_kobj
    3)设置kobject的ktype为系统定义好的ktype变量
    4)设置kobject的所属kset为NULL,意思是kobject所属的kset就是kset本身,因为kset结构体包含了一个kobject成员。

    这里需要一个注意的,就是ktype 这个结构,即kset_ktype

    static struct kobj_type kset_ktype = {
        .sysfs_ops  = &kobj_sysfs_ops,
        .release = kset_release,
    };

    这里填充了一个释放函数,每个kobject必须有一个释放函数,并且这个kobject必须保持直到这个释放函数被调用到。如果这个条件不能被满足,则这个代码是有缺陷的。注意,假如你忘了提供释放函数,内核会提出警告的;不要尝试提供一个空的释放函数来消除这个警告,你会收到kobject维护者的无情嘲笑。
    至于kobj_sysfs_ops,则是关于读写操作相关的操作集:

    static const struct sysfs_ops sysfs_ops = {
        .show   = show,
        .store  = store,
    };

    读文件时,会调用到.show的回调函数。
    写文件时,会调用到.show的回调函数。

    看完了创建函数,接下来是注册函数:

    int kset_register(struct kset *k)
    {
        int err;
        if (!k)
            return -EINVAL;
    
        kset_init(k);//初始化kset
        err = kobject_add_internal(&k->kobj);/*初始化kobject,创建对应的sys目录*/  
        if (err)
            return err;
        kobject_uevent(&k->kobj, KOBJ_ADD);
        return 0;
    }

    kset_init函数主要是对kset初始化,会将初始化引用计数器(即kobj->kref)为1(当计数器引用计数没到0之前不可以被释放)。接着初始化entry链表结点,用于与所属的kset的list成员组成链表(INIT_LIST_HEAD(&kobj->entry)),以及一些参数的赋值。最后,还初始化以list成员为头结点的链表,它和子kobject的entry成员组成链表(INIT_LIST_HEAD(&k->list))。

    kobject_add_internal函数就是关键的kobject函数了:

    static int kobject_add_internal(struct kobject *kobj)
    {
        int error = 0;
        struct kobject *parent;
    
        if (!kobj)
            return -ENOENT;
    
        if (!kobj->name || !kobj->name[0]) {//如果kobject的名字为空.退出 
            WARN(1, "kobject: (%p): attempted to be registered with empty "
                 "name!\n", kobj);
            return -EINVAL;
        }
    
        parent = kobject_get(kobj->parent);//如果kobj-parent为真,则增加kobj->kref计数,即父节点的引用计数
        /* join kset if set, use it as parent if we do not already have one */
        if (kobj->kset) {
            if (!parent)
                parent = kobject_get(&kobj->kset->kobj);//如果parent父节点为NULL那么就用kobj->kset->kobj作其父节点,并增加其引用计数
            kobj_kset_join(kobj);//把kobj的entry成员添加到kobj->kset>list的尾部,现在的层次就是kobj->kset->list指向kobj->entry
            kobj->parent = parent;
        }
        /*删除了部分调试内容*/
        error = create_dir(kobj);//利用kobj创建目录和属性文件,其中会判断,如果parent为NULL那么就在sysfs_root_kn下创建
        if (error) {
            /*删除了部分内容*/
        } else
            kobj->state_in_sysfs = 1;//如果创建成功。将state_in_sysfs建为1。表示该object已经在sysfs中了
    
        return error;
    }

    kobject_add_internal函数内容在注释里都写好了,可以概括为:
    1)如果kobject的parent成员为NULL,则把它指向kset的kobject成员。
    2)如果kobject的kset成员不为NULL,它会调用kobj_kset_join函数把kobject的entry成员添加到kset的list链表中
    3)最后调用create_dir函数创建sys目录

    注册函数里最后一个调用就是kobject_uevent函数了,应该是关于热拔插机制的,这不是我们现在关心的内容。
    好了,经过上面的折腾,就会在/sys/目录下建立一个devices目录。

    接下来继续回到文章开头进入到的devices_init函数:

    void __init driver_init(void)
    {
        /* These are the core pieces */
        devtmpfs_init();
        devices_init();/*device、dev目录*/
        buses_init();/*bus目录*/
        classes_init();/*class目录*/
        firmware_init();/*firmware目录*/
        hypervisor_init();/*hypervisor目录*/
        /* These are also core pieces, but must come after the
         * core core pieces.
         */
        platform_bus_init();
        cpu_dev_init();
        memory_dev_init();
        container_dev_init();
        of_core_init();
    }

    我们之前分析的是devices_init函数,其实接下来几个函数都是一样的,在/sys/目录下创建各个目录。
    只需要记住
    devices_kset对应/sys/devices目录
    bus_kset对应/sys/bus目录
    devices_kset对应/sys/devices目录
    system_kset对应/sys/devices/system目录
    class_kset对应/sys/class目录
    firmware_kobj对应/sys/firmware目录
    hypervisor_kobj对应/sys/hypervisor目录

    接下来看下platform_bus_init函数
    也就是我们之前用的platform总线了!!
    在driver/base/platform.c文件:

    struct bus_type platform_bus_type = {
        .name       = "platform",
        .dev_groups = platform_dev_groups,
        .match      = platform_match,//各种关键字匹配
        .uevent     = platform_uevent,
        .pm     = &platform_dev_pm_ops,
    };
    struct device platform_bus = {
        .init_name  = "platform",
    };
    
    int __init platform_bus_init(void)
    {
        int error;
    
        early_platform_cleanup();
    
        error = device_register(&platform_bus);
        if (error)
            return error;
        error =  bus_register(&platform_bus_type);
        if (error)
            device_unregister(&platform_bus);
        of_platform_register_reconfig_notifier();
        return error;
    }

    这里,device_register就是在/sys/device/目录下创建platform

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

    其实也就包含两个函数,一个初始化,一个添加:

    void device_initialize(struct device *dev)
    {
        dev->kobj.kset = devices_kset;//设置设备的kobject所属集合,devices_kset即对应/sys/devices/ 
        kobject_init(&dev->kobj, &device_ktype);//初始化设备的kobject 
        INIT_LIST_HEAD(&dev->dma_pools);//初始化设备的DMA池,用于传递大数据
        mutex_init(&dev->mutex);
        lockdep_set_novalidate_class(&dev->mutex);
        spin_lock_init(&dev->devres_lock);//初始化自旋锁,用于同步子设备链表 
        INIT_LIST_HEAD(&dev->devres_head);//初始化子设备链表头
        device_pm_init(dev);
        set_dev_node(dev, -1);
    #ifdef CONFIG_GENERIC_MSI_IRQ
        INIT_LIST_HEAD(&dev->msi_list);
    #endif
    }

    注释都写好了,看下device_add函数:

    int device_add(struct device *dev)
    {
        struct device *parent = NULL;
        struct kobject *kobj;
        struct class_interface *class_intf;
        int error = -EINVAL;
        struct kobject *glue_dir = NULL;
    
        dev = get_device(dev);//增加设备的kobject的引用计数
        if (!dev)
            goto done;
    
        if (!dev->p) {
            error = device_private_init(dev);//初始化dev的私有成员,及其链表操作函数
            if (error)
                goto done;
        }
    
        if (dev->init_name) {//保存设备名,以后需要获取时使用dev_name函数获取
            dev_set_name(dev, "%s", dev->init_name);
            dev->init_name = NULL;
        }
    
        /* subsystems can specify simple device enumeration */
        if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
            dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
    
        if (!dev_name(dev)) {
            error = -EINVAL;
            goto name_error;
        }
    
        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
    
        parent = get_device(dev->parent);//返回父节点,增加父节点引用计数,如果没有返回NULL 
        kobj = get_device_parent(dev, parent);//以上层devices为准重设dev->kobj.parent  
        if (kobj)
            dev->kobj.parent = kobj;
    
        /* use parent numa_node */
        if (parent && (dev_to_node(dev) == NUMA_NO_NODE))
            set_dev_node(dev, dev_to_node(parent));
    
        /* first, register with generic layer. */
        /* we require the name to be set before, and pass NULL */
        error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);//设置dev->kobj的名字和父对象,并建立相应目录 
        if (error) {
            glue_dir = get_glue_dir(dev);
            goto Error;
        }
    
        /* notify platform of device entry */
        if (platform_notify)
            platform_notify(dev);
    
        error = device_create_file(dev, &dev_attr_uevent);//建立uevent属性文件  
        if (error)
            goto attrError;
    
        error = device_add_class_symlinks(dev);
        if (error)
            goto SymlinkError;
        error = device_add_attrs(dev);
        if (error)
            goto AttrsError;
        error = bus_add_device(dev);
        if (error)
            goto BusError;
        error = dpm_sysfs_add(dev);
        if (error)
            goto DPMError;
        device_pm_add(dev);
    
        if (MAJOR(dev->devt)) {
            error = device_create_file(dev, &dev_attr_dev);//在sys下产生dev属性文件 
            if (error)
                goto DevAttrError;
    
            error = device_create_sys_dev_entry(dev);//在/sys/dev目录建立对设备的软链接
            if (error)
                goto SysEntryError;
    
            devtmpfs_create_node(dev);
        }
    
        /* Notify clients of device addition.  This call must come
         * after dpm_sysfs_add() and before kobject_uevent().
         */
        if (dev->bus)
            blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                             BUS_NOTIFY_ADD_DEVICE, dev);
    
        kobject_uevent(&dev->kobj, KOBJ_ADD);//向用户空间发出KOBJ_ADD 事件 
        bus_probe_device(dev);//检测驱动中有无适合的设备进行匹配,现在只添加了设备,还没有加载驱动,所以不会进行匹配 
        if (parent)
            klist_add_tail(&dev->p->knode_parent,
                       &parent->p->klist_children);//把该设备的节点挂到其父节点的链表  
    
        if (dev->class) {
            mutex_lock(&dev->class->p->mutex);
            /* tie the class to the device */
            klist_add_tail(&dev->knode_class,
                       &dev->class->p->klist_devices);
    
            /* notify any interfaces that the device is here */
            list_for_each_entry(class_intf,
                        &dev->class->p->interfaces, node)
                if (class_intf->add_dev)
                    class_intf->add_dev(dev, class_intf);
            mutex_unlock(&dev->class->p->mutex);
        }
        /*省略部分error内容*/
    }

    device_add函数是比较重要的,注释基本都写好了,可以概括为:
    1)增加kobj->kref计数
    2)初始化dev的私有成员
    3)设置设备名称
    4)增加父节点引用计数
    5)将dev->kobj添加到dev->kobj.parent对应目录下
    6)dev->kobj下创建属性文件
    7)在/sys/dev目录建立对设备的软链接
    8)驱动检测

    其中,驱动检测函数:bus_probe_device
    我在财富坊cff888嵌入式Linux驱动笔记(五)——学习platform设备驱动分析有,可以看看。

    最后,我们接着看 bus_register(&platform_bus_type);
    篇幅有点长了,函数我就写点重要的即可

    int bus_register(struct bus_type *bus)
    {
        int retval;
        struct subsys_private *priv;
        struct lock_class_key *key = &bus->lock_key;
    
        priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
        if (!priv)
            return -ENOMEM;
    
        priv->bus = bus;
        bus->p = priv;
    
        BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
    
        retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
        if (retval)
            goto out;
    
        priv->subsys.kobj.kset = bus_kset;
        priv->subsys.kobj.ktype = &bus_ktype;
        priv->drivers_autoprobe = 1;
    
        retval = kset_register(&priv->subsys);
        if (retval)
            goto out;
    
        retval = bus_create_file(bus, &bus_attr_uevent);
        if (retval)
            goto bus_uevent_fail;
    
        priv->devices_kset = kset_create_and_add("devices", NULL,
                             &priv->subsys.kobj);
        if (!priv->devices_kset) {
            retval = -ENOMEM;
            goto bus_devices_fail;
        }
    
        priv->drivers_kset = kset_create_and_add("drivers", NULL,
                             &priv->subsys.kobj);
        if (!priv->drivers_kset) {
            retval = -ENOMEM;
            goto bus_drivers_fail;
        }
        /*后面的省略*/
    }

    再次强调:
    priv->subsys.kobj.kset = bus_kset;
    priv->subsys.kobj.ktype = &bus_ktype;
    这里设置了所属的kset和ktype。
    ktype结构体里包含了sysfs_ops结构体,里面就是对文件的读写操作:

    static const struct sysfs_ops bus_sysfs_ops = {
        .show   = bus_attr_show,//读文件
        .store  = bus_attr_store,//写文件
    };

    最后,bus_register函数里还调用了kset_create_and_add函数在/sys/platform/目录下创建devices和drivers目录,里面存放我们platform平台下注册的设备和驱动。

    好了,到此,我们就来再次小小归纳下
    *在kset下还可能会有更深的kset
    *kset包含一个或多个kobject,方便管理
    *kobject并不一定需要kset
    *kobject下有属性文件,·向用户层提供了表示和操作这个 kobject 的属性特征的接口
    *kobject 下还有一些符号链接文件,指向其它的 kobject

    现在,是不是对设备驱动模型有了更为直观的认识?现在回头看看文章开头的小程序,是不是轻而易举的理解了呢?

    最后
    这里有篇文章,是翻译了内核文档(Documentation\kobject.txt),可以看看:
    http://www.cnblogs.com/helloahui/p/3674933.html

    后记:关于uevent,在这里有描述:/bc5/fanqipin/article/details/8287343

    阅读全文
    版权声明:本文为 风筝 博主原创文章,未经博主允许不得转载!!!!!!

    linux设备驱动模型之Kobject、kobj_type、kset

    学习中platform平台驱动中,慢慢发现底层有一个叫做linux设备驱动模型的东西。发现是驱动中十分重要的一部分,现在针对设备驱动模型进行分析。 用户空间程序通过sysfs虚拟文件系统访问设备的相关...
    • fengyuwuzu0519
    • fengyuwuzu0519
    • 2017年07月08日 17:00
    • 322

    Linux内核修炼之kobject,ktype,kset,subsys关系

    随着内核版本的发展,会有一些变化,无论怎样,变化的是形式,不变的是思想!? 那么他们之间具有什么关系?那应该不是‘小3‘也不是'小5‘的关系,总之这种关系超越了人们,构成了Linux,是一种"你...
    • yyplc
    • yyplc
    • 2012年04月16日 14:02
    • 3661

    linux文件系统的系统分析--(十)sysfs和设备模型--kobject、kset和ktype

    前面分析了这么多,是因为设备模型和文件系统的联系很紧密,了解sysfs是为了更好的理解设备模型。 ? ? ? ? 在分析sysfs的时候,我们也看到了sysfs_dirent与kobject的紧密联...
    • dndxhej
    • dndxhej
    • 2012年04月08日 19:08
    • 2534

    Linux设备驱动之Kobject、Kset

    纠结又纠结,虽然看了一些关于kobject 和 kset 的书与文章,但是对于这两个东西,还是不太明白,又分析了一遍2.6.32.2内核的代码,结合前人的努力,终于有了一点眉目。总结一下,给自己做个笔...
    • lizuobin2
    • lizuobin2
    • 2016年05月28日 11:17
    • 1957

    linux对象系统---kobject, ktype, kset, subsys

    本文转自:linux中kobject/ktype/kset/subsys之间的关系 随着内核版本的发展,会有一些变化,无论怎样,变化的是形式,不变的是思想!? 那么他们之间具有什么...
    • duqi_2009
    • duqi_2009
    • 2013年12月05日 17:10
    • 3164

    Linux 设备模型之 (kobject、kset 和 Subsystem)(二)

    问题描述:前文我们知道了/sys是包含内核和驱动的实施信息的,用户可以通过 /sys 这个接口,用户通过这个接口可以一览内核设备的全貌。本文将从Linux内核的角度来看一看这个设备模型是如何构建的。 ...
    • xy010902100449
    • xy010902100449
    • 2015年06月08日 15:17
    • 1240

    kobject, kset, ktype

    ?============================== REF:????????????????????????????????????????????????????? == 1. Docu...
    • ganggexiongqi
    • ganggexiongqi
    • 2011年06月21日 23:21
    • 1479

    Device Module之Kobject,Ktype,Kset(基于kernel 4.11)

    笔者:从最初的希望很快结束NET,INTERRUPT subsystem 到现在才发现,仅仅是NET都是涉及内容深广,且不说 相关协议的内容,仅仅是框架也是十分复杂的,最近又在看USB子系统,与裸板驱...
    • bushipeien
    • bushipeien
    • 2017年06月02日 18:12
    • 391

    kobject kset和ktype分析

    下面,我开始对kobject kset和ktype做分析 先说说关系,ktype与kobject和kset这两者之前的关系较少,让我画一个图,是这样的 ? ktype依赖于kob...
    • u013427264
    • u013427264
    • 2015年01月12日 15:05
    • 511

    linux设备驱动模型之 kset原理与实例分析

    1、 Kset ???????kset是具有相同类型的kobject的集合,在sysfs中体现成一个目录,在内核中用kset数据结构表示,定义为: struct kset { str...
    • u014379540
    • u014379540
    • 2016年09月08日 19:53
    • 340
    内容举报
    返回顶部
    收藏助手
    不良信息举报
    您举报文章:嵌入式Linux驱动笔记(十六)------设备驱动模型(kobject、kset、ktype)
    举报原因:
    原因补充:

    (最多只允许输入30个字)