zoukankan      html  css  js  c++  java
  • linux设备驱动模型(kobject与kset)

    Linux设备模型的目的:为内核建立一个统一的设备模型,从而又一个对系统结构的一般性抽象描述。换句话说,Linux设备模型提取了设备操作的共同属性,进行抽象,并将这部分共同的属性在内核中实现,而为需要新添加设备或驱动提供一般性的统一接口,这使得驱动程序的开发变得更简单了,而程序员只需要去学习接口就行了。

                                         kobject                                                                                                                                   

    1.sysfs文件系统

      1.1 sysfs文件系统与内核结构的关系

    linux内核中的结构 sysfs中的结构             
    kobject (内核对象) 目录  
    kobj_type (属性)  属性文件
    对象之间的关系 符号链接

      1.2 sysfs文件系统的目录结构

    block:所有块设备

    devices:系统所有设备(块设备特殊),对应struct device的层次结构

    bus:系统中所有总线类型(指总线类型而不是总线设备,总线设备在devices下),bus的每个子目录都包含

        --devices:包含到devices目录中设备的软链接

        --drivers:与bus类型匹配的驱动程序

    class:系统中设备类型(如声卡、网卡、显卡等)

    fs:一些文件系统,具体可参考filesystems /fuse.txt中例子

    dev:包含2个子目录

    --char:字符设备链接,链接到devices目录,以<major>:<minor>命名

    --block:块设备链接

    2.设备驱动模型的核心数据结构

    2.1 kobject结构体

      

      name 将显示在sysfs文件系统中,作为一个目录的名字;

      struct kobj_type *ktype 代表kobject的属性,对于sysfs中的普通文件读写操作都是kobjetc->ktype->sysfs_ops指针来完成的,即对default_attrs数组的操作

      kobject始终是sysfs文件系统中的一个目录而不是文件。

    2.2设备属性kobj_type

      下图是kobject与kobj_type的关系:

      

      kobj_type结构体的定义如下:

    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);
    };

      【1】attribute结构体如下:

    struct attribute {
        const char        *name;//属性名字
        struct module        *owner;//
        mode_t            mode;//属性的读写权限
    #ifdef CONFIG_DEBUG_LOCK_ALLOC
        struct lock_class_key    *key;
        struct lock_class_key    skey;
    #endif
    };

      【2】sysfs_ops 属性操作结构体: 

    struct sysfs_ops {
        ssize_t    (*show)(struct kobject *, struct attribute *,char *);//读属性
        ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);//写属性
    };

      【3】release()函数

        当kobject的引用计数为0时,系统自动会调用自定义的release()来释放kobject对象。

        e.g.

          

    3.实例:

    #include <linux/device.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/string.h>
    #include <linux/sysfs.h>
    #include <linux/stat.h>
     
    MODULE_AUTHOR("David Xie");
    MODULE_LICENSE("Dual BSD/GPL");
     
    void obj_test_release(struct kobject *kobject);
    ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);
    ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);
     
    struct attribute test_attr = {
            .name = "kobj_config",
            .mode = S_IRWXUGO,
    };
     
    static struct attribute *def_attrs[] = {
            &test_attr,
            NULL,
    };
     
     
    struct sysfs_ops obj_test_sysops =
    {
            .show = kobj_test_show,
            .store = kobj_test_store,
    };
     
    struct kobj_type ktype = 
    {
            .release = obj_test_release,
            .sysfs_ops=&obj_test_sysops,
            .default_attrs=def_attrs,
    };
     
    void obj_test_release(struct kobject *kobject)
    {
            printk("eric_test: release .
    ");
    }
     
    ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)
    {
            printk("have show.
    ");
            printk("attrname:%s.
    ", attr->name);
            sprintf(buf,"%s
    ",attr->name);
            return strlen(attr->name)+2;
    }
     
    ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)
    {
            printk("havestore
    ");
            printk("write: %s
    ",buf);
            return count;
    }
     
    struct kobject kobj;
    static int kobj_test_init()
    {
            printk("kboject test init.
    ");
            kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");
            return 0;
    }
     
    static int kobj_test_exit()
    {
            printk("kobject test exit.
    ");
            kobject_del(&kobj);
            return 0;
    }
     
    module_init(kobj_test_init);
    module_exit(kobj_test_exit);

                                     kset                                                                                                                                             

     

    kset是具有相同类型的kobject的集合,在sysfs中体现成一个目录;kobject不能包含目录,而kset可以包含目录。kobject通过kset组织成层次化的结构,kset将一系列相同类型的kobject使用(双向)链表连接起来,可以这样 认为,kset充当链表头作用,kset内部内嵌了一个kobject结构。

      1. #include <linux/kobject.h>
      2. struct kset {
      3.     struct list_head list; /* 用于连接kset中所有kobject的链表头 */
      4.     spinlock_t list_lock; /* 扫描kobject组成的链表时使用的锁 */
      5.     struct kobject kobj; /* 嵌入的kobject */
      6.     const struct kset_uevent_ops *uevent_ops; /* kset的uevent操作 */
      7. };

    实例:

    #include <linux/device.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/string.h>
    #include <linux/sysfs.h>
    #include <linux/stat.h>
    #include <linux/kobject.h>
     
    MODULE_AUTHOR("David Xie");
    MODULE_LICENSE("Dual BSD/GPL");
     
    struct kset kset_p;
    struct kset kset_c;
    
    int kset_filter(struct kset *kset, struct kobject *kobj)
    {
            printk("Filter: kobj %s.
    ",kobj->name);
            return 1;
    }
     
    const char *kset_name(struct kset *kset, struct kobject *kobj)
    {
            static char buf[20];
            printk("Name: kobj %s.
    ",kobj->name);
            sprintf(buf,"%s","kset_name");
            return buf;
    }
     
    int kset_uevent(struct kset *kset, struct kobject *kobj,struct kobj_uevent_env *env)
    {
            int i = 0;
            printk("uevent: kobj %s.
    ",kobj->name);
    
            while( i < env->envp_idx){
                    printk("%s.
    ",env->envp[i]);
                    i++;
            }
    
            return 0;
    }
    
    struct kset_uevent_ops uevent_ops = 
    {
            .filter = kset_filter,
            .name   = kset_name,
            .uevent = kset_uevent,
    };
     
    int kset_test_init()
    {
            printk("kset test init.
    ");
            kobject_set_name(&kset_p.kobj,"kset_p");
            kset_p.uevent_ops = &uevent_ops;
            kset_register(&kset_p);
            printk("kset_p finish
    ");
    
            /*下面会调用热插拔函数*/
            kobject_set_name(&kset_c.kobj,"kset_c");
            kset_c.kobj.kset = &kset_p;
            kset_register(&kset_c);
            return 0;
    }
     
    int kset_test_exit()
    {
            printk("kset test exit.
    ");
            kset_unregister(&kset_p);
            kset_unregister(&kset_c);
            return 0;
    }
     
    module_init(kset_test_init);
    module_exit(kset_test_exit);

    热插拔事件kset_uevent_ops

    在Linux系统中,当系统配置发生变化时,如:添加kset到系统;移动kobject, 一个通知会从内核空间发送到用户空间,这就是热插拔事件。热插拔事件会导致用户空间中相应的处理程序(如udev,mdev)被调用, 这些处理程序会通过加载驱动程序, 创建设备节点等来响应热插拔事件。

    Struct kset_uevent_ops {
    int (*filter)(struct kset *kset, struct kobject *kobj);
    const char *(*name)(struct kset *kset, struct kobject *kobj);
    int (*uevent)(struct kset *kset, struct kobject *kobj,
    struct kobj_uevent_env *env);
    }

    当该kset所管理的kobject和kset状态发生变化时(如被加入,移动),这三个函数将被调用。

                         kobject与kset的关系                                                                                                                               

    参考:http://blog.csdn.net/xiahouzuoxin/article/details/8943863 

  • 相关阅读:
    HTML DOM 06 节点关系
    HTML DOM 05 事件(三)
    HTML DOM 05 事件(二)
    HTML DOM 05 事件(一)
    html DOM 04 样式
    html DOM 03 节点的属性
    html DOM 02 获取节点
    html DOM 01 节点概念
    JavaScript 29 计时器
    JavaScript 28 弹出框
  • 原文地址:https://www.cnblogs.com/hello2mhb/p/3365204.html
Copyright © 2011-2022 走看看