• 20150225 IMX257设备驱动模型之Kset


    20150225 IMX257设备驱动模型之Kset

    2015-02-25 17:00 李海沿

    前面我们实现了一个简单的kobject模型,结果就是成功的在 sysfs的/sys/目录下创建一个kobject的目录,目录下面有attr属性文件,很简单,对kobject的操作其实就是把那四个结构体搞懂就习惯了。博文参考地址:http://www.cnblogs.com/lihaiyan/p/4299390.html

        下面我们来实现设备驱动模型的kset,kset其实和kobject 是差不多的,唯一的一个驱动就是kset目录下面可以包含kobject目录,而kobject目录下面不能包含目录,只能包含属性文件,为了更好理解,可以说kobject就是kset的简化版。

        好了,下面我们正式开始来实现设备驱动模型kset。

    一、kset介绍

    1. kset结构体

    Struct kset{

    Struct list_head list; //连接所包含的kobject对象的链表首部

    Spinlock_t list_lock; //维护list链表的自旋锁

    Struct kobject kobj; //内嵌的kobject结构体,说明kset本身也是一个目录

    Struct kset_uevent_ops *uevent_ops; //热插拔事件

    }

    从上面的结构体可以得知:

    kset 包含kobject 和 一个kset_uevent_ops 热插拔事件结构体

    2. 热插拔事件结构体 kset_uevent_ops

    热插拔事件意思就是当kset目录下有任何变动,包括目录的移动,增加目录或者属性文件等操作。

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

    结构体定义为:

    struct kset_uevnt_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);

    }

    功能:

    filter 过滤事件,决定是否产生事件,如果返回0,将不产生事件。

    name向用户空间传递一个合适的字符串

    uevent通过环境变量传递任何热插拔脚本需要的信息,他会在(udev或mdev)调用之前,提供添加环境变量的机会。

    3. kset操作函数

    void kset_init(struct kset *kset);

    int kset_add(struct kset *kset);

    int kset_register(struct kset *kset);

    void kset_unregister(struct kset *kset);

    二、程序分析

    1. 定义kset结构体

    2. 定义热插拔事件结构体

    函数实现:

    3. 在init初始化函数中

    如图所示,

    第45行: kobject_set_name 是设定kset中的kobject的名字为kset_p

    第46行: 关联kset与热插拔时间处理函数

    第47行: 注册kset, 此时会在sys目录下创建一个名字为kobject的名字的文件夹

    第50行: 设置kset_p的父目录(父kset)为kset_p(注意这一行)

    4. 在exit函数中,卸载kset

    5.总体流程分析

    1.kset_test_init初始化kset

    2.kobject_set_name(&kset_p.kobj,"kset_p");

    3.创建一个struct kset kset_p,目录名字是kset_p

    4.注册kset_register(&kset_p);

    5.添加一个目录kset_p

    6.kobject_set_name(&kset_c.kobj,"kset_c");

    7.创建一个struct kset kset_c,目录名字是kset_c

    8.kset_c.kobj.kset = &kset_p; kset_c的父目录是kset_p,也就是讲kset_p下有一个目录kset_c

    9.注册kset_register(&kset_c);

    10.添加一个目录kset_c

    11.当在kset_p下增加一个kset_c目录,发生热插拔事件,调用uevent_ops

    12.kset_filter被调用,返回0,不传递事件,返回1,传递

    13.kset_name打印名字

    14.kset_uevent打印相关的信息

    6.编译测试

    如图所示:

    在 sys/目录下 ,产生一个 kset_p 的目录,子目录下还有一个kset_c

    然后再看打印信息,可以发现分别调用调用了热插拔时间的三个函数。

    注意 ACTION后面 为add,意思就是添加了一个kset目录

    目录的路径为DEVPATH = /kset_p/kset_c

    我们再观察卸载驱动时的变化

    可以发现,前面ACTION = remove 意思是移除一个kset目录

    7.总结

    kset和kobject的不同之处就是kset下面可以再次包含kset目录,kobject下只能包含属性文件,

    创建kset目录时,首先第一步是定义kset结构体,第二步是实现热插拔的结构体及其相应的函数与,第三步就是在初始化函数中对kset的kobject命名,关联热插拔事件,最后就是注册kset,第四步是当我们不用kset时自然就是卸载kset了。很简单吧。

    搞定这个了,下一步我们就开始 总线-设备-驱动模型 之旅了,

    附上驱动程序:

     1 #include <linux/kernel.h>
     2 #include <linux/init.h>
     3 #include <linux/string.h>
     4 #include <linux/sysfs.h>
     5 #include <linux/stat.h>
     6 #include <linux/kobject.h>
     7 #include <linux/module.h>
     8 #include <linux/device.h>
     9 
    10 //定义两个kset结构体
    11 struct kset kset_p;
    12 struct kset kset_c;
    13 
    14 static int kset_filter(struct kset *kset,struct kobject *kobj){
    15     printk("Filter: kobj %s. 
    ",kobj->name);
    16     return 1;
    17 }
    18 
    19 const char *kset_name(struct kset *kset, struct kobject *kobj){
    20     static char buf[20];
    21     printk("Name: kobj %s. 
    ",kobj->name);
    22     return buf;
    23 }
    24 
    25 static int kset_uevent(struct kset *kset, struct kobject *kobj,struct kobj_uevent_env *env){
    26     int i = 0;
    27     printk("uevent : kobj %s. 
    ",kobj->name);
    28 
    29     while(i < env->envp_idx){    //打印相关的信息
    30         printk("%s .
    ",env->envp[i]);
    31         i++;
    32     }
    33     return 0;
    34 }
    35 
    36 //定义kset发生热插拔(目录下有任何变动)时,调用的函数
    37 struct kset_uevent_ops uevent_ops = {
    38     .filter = kset_filter,
    39     .name = kset_name,
    40     .uevent = kset_uevent,
    41 };
    42 
    43 static int kset_test1_init(void){
    44     printk("<0>kset test init. 
    ");
    45     kobject_set_name(&kset_p.kobj,"kset_p");
    46     kset_p.uevent_ops = &uevent_ops;    //关联热插拔事件处理函数
    47     kset_register(&kset_p);                //注册
    48 
    49     kobject_set_name(&kset_c.kobj,"kset_c");
    50     kset_c.kobj.kset = &kset_p;            //执行kset_c的父目录为kset_p
    51     kset_register(&kset_c);                //注册
    52 
    53     return 0;
    54 }
    55 
    56 static int kset_test1_exit(void){
    57     printk("<0>kset test exit. 
    ");
    58     kset_unregister(&kset_p);         //kset卸载
    59     kset_unregister(&kset_c);
    60     return 0;
    61 }
    62 
    63 module_init(kset_test1_init);
    64 module_exit(kset_test1_exit);
    65 
    66 MODULE_AUTHOR("Lover雪儿");
    67 MODULE_LICENSE("Dual BSD/GPL");
    View Code
  • 相关阅读:
    不一样的图片加载方式
    赢 1000 元现金红包!助力奥运,猜金银牌数赢现金
    接入 SDK 结果翻车了?了解 SDK 的那些事
    关于 IPv6 国家有大动作啦!快来瞅瞅行动计划都说了什么~
    MySQL 那些常见的错误设计规范
    webpack 从 0 到 1 构建 vue
    PHP 网络通信底层原理分析
    内部方案汇总
    taro+vue3 引入 taro-ui-vue3
    springboot+tomcat+vue+nginx 前后端分离配置
  • 原文地址:https://www.cnblogs.com/lihaiyan/p/4299961.html
Copyright © 2020-2023  润新知