一、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
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
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');