0
点赞
收藏
分享

微信扫一扫

20150225 IMX257设备驱动模型之Kset

米小格儿 2022-03-30 阅读 64


20150225 IMX257设备驱动模型之Kset

2015-02-25 17:00 李海沿

前面我们实现了一个简单的kobject模型,结果就是成功的在 sysfs的/sys/目录下创建一个kobject的目录,目录下面有attr属性文件,很简单,对kobject的操作其实就是把那四个结构体搞懂就习惯了。​

    下面我们来实现设备驱动模型的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结构体

20150225 IMX257设备驱动模型之Kset_linux


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

20150225 IMX257设备驱动模型之Kset_linux_02

函数实现:

20150225 IMX257设备驱动模型之Kset_linux_03


3. 在init初始化函数中

20150225 IMX257设备驱动模型之Kset_热插拔_04

如图所示,

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

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

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

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


4. 在exit函数中,卸载kset

20150225 IMX257设备驱动模型之Kset_#include_05


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.编译测试


20150225 IMX257设备驱动模型之Kset_linux_06


如图所示:

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

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

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

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


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

20150225 IMX257设备驱动模型之Kset_热插拔_07

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


7.总结

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

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

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



附上驱动程序:


20150225 IMX257设备驱动模型之Kset_linux_0820150225 IMX257设备驱动模型之Kset_linux_09

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. \n",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. \n",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. \n",kobj->name);
28
29 while(i < env->envp_idx){ //打印相关的信息
30 printk("%s .\n",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. \n");
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. \n");
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



举报

相关推荐

0 条评论