版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、前面看过了设备驱动模型中的bus、device、driver,这三种都是有迹可循的。其中bus代表实际的总线,device代表实际的设备和接口,而driver则对应存在的驱动。但本节要介绍的class,是设备类,完全是抽象出来的概念,没有对应的实体。所谓设备类,是指提供的用户接口相似的一类设备的集合,常见的设备类的有block、tty、input、usb等等。 class对应的代码在drivers/base/class.c中,对应的头文件在include/linux/device.h和drivers/base/base.h中。还是先来看class
2、涉及的结构。cpp view plaincopy1. struct class 2. const char *name; 3. struct module *owner; 4. 5. &
3、#160; struct class_attribute *class_attrs; 6. struct device_attribute *dev_attrs; 7. struct kobject
4、; *dev_kobj; 8. 9. int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); 10. char *(*devnode)(struct device *dev, mode_t *mode);
5、0;11. 12. void (*class_release)(struct class *class); 13. void (*dev_release)(struct device *dev); 14. 15. int (*suspend)(struct device *
6、dev, pm_message_t state); 16. int (*resume)(struct device *dev); 17. 18. const struct dev_pm_ops *pm; 19. 20. struct class_pri
7、vate *p; 21. ; struct class就是设备驱动模型中通用的设备类结构。name代表类名称,但和bus/device/driver中的名称一样,是初始名称,实际使用的是内部kobj包含的动态创建的名称。owner是class所属的模块,虽然class是涉及一类设备,但也是由相应的模块注册的。比如usb类就是由usb模块注册的。class_attrs是class给自己添加的属性,dev_attrs是class给所包含的设备添加的属性。这里就像bus中一样,只是bus是bus、driver、device全部包含的。dev_ko
8、bj是一个kobject指针。如果你的记性很好(至少要比我好得多),你应该记得在device注册时,会在/sys/dev下创建名为自己设备号的软链接。但设备不知道自己属于块设备还是字符设备,所以会请示自己所属的class,class就是用dev_kobj记录本类设备应属于的哪种设备。dev_uevent()是在设备发出uevent消息时添加环境变量用的。还记得在core.c中的dev_uevent()函数,其中就包含对设备所属bus或class中dev_uevent()方法的调用,只是bus结构中定义方法用的函数名是uevent。devnode()返回设备节点的相对路径名。在core.c的de
9、vice_get_devnode()中有调用到。class_release()是在class释放时调用到的。类似于device在结构中为自己定义的release函数。dev_release()自然是在设备释放时调用到的。具体在core.c的device_release()函数中调用。suspend()是在设备休眠时调用。resume()是恢复设备时调用。pm是电源管理用的函数集合,在bus、driver、class中都有看到,只是在device中换成了dev_pm_info结构,但device_type中还是隐藏着dev_pm_ops的指针。可见电源管理还是很重要的,只是这些东西都要结合具体的
10、设备来分析,这里的设备驱动模型能给的,最多是一个函数指针与通用数据的框架。p是指向class_private结构的指针。cpp view plaincopy1. /* 2. * struct class_private - structure to hold the private to the driver core portions of the class structure.
11、3. * 4. * class_subsys - the struct kset that defines this class. This is the main kobject 5. * class_devices - list of devices associated with this cl
12、ass 6. * class_interfaces - list of class_interfaces associated with this class 7. * class_dirs - "glue" directory for virtual devices associated with this class 8
13、. * class_mutex - mutex to protect the children, devices, and interfaces lists. 9. * class - pointer back to the struct class that this structure is associated
14、0;10. * with. 11. * 12. * This structure is the one that is the actual kobject allowing struct 13. * class to be statically allocated safely. Nothing
15、outside of the driver 14. * core should ever touch these fields. 15. */ 16. struct class_private 17. struct kset class_subsys; 18.
16、struct klist class_devices; 19. struct list_head class_interfaces; 20. struct kset class_dirs; 21. struct mutex class_mutex; 22.
17、60; struct class *class; 23. ; 24. #define to_class(obj) 25. container_of(obj, struct class_private, class_subsys.kobj) struct class_private,是class连接到系统中的重要结构。class_subsys是kset类型,
18、代表class在sysfs中的位置。class_devices是klist类型,是class下的设备链表。class_interfaces是list_head类型的类接口链表,设备类接口稍后会介绍。class_dirs也是kset类型,它并未实际在sysfs中体现,反而是其下链接了一系列胶水kobject。记得在core.c中的get_device_parent()函数,好像小蝌蚪找妈妈一样,我们在为新注册的设备寻找sysfs中可以存放的位置。如果发现dev->class存在,而dev->parent->class不存在,就要建立一个胶水目录,在sysfs中隔离这两个实际上有
19、父子关系的设备。linux这么做也是为了在sysfs显示时更清晰一些。但如果父设备下有多个属于同一类的设备,它们需要放在同一胶水目录下。怎么寻找这个胶水目录有没有建立过,就要从这里的class_dirs下的kobject中找了。class_mutex是互斥信号量,用于保护class内部的数据结构。class是指回struct class的指针。cpp view plaincopy1. struct class_interface 2. struct list_head
20、160; node; 3. struct class *class; 4. 5. int (*add_dev) (struct device *, struct class_interfac
21、e *); 6. void (*remove_dev) (struct device *, struct class_interface *); 7. ; struct class_interface就是之前被串在class->p->class_interface上的类接口的结构。用于描述设备类对外的一种接口。node就是class->p->class_interfa
22、ce链表上的节点。class是指向所属class的指针。add_dev()是在有设备添加到所属class时调用的函数。当然,如果class_interface比设备更晚添加到class,也会补上的。remove_dev()是在设备删除时调用的。从结构来看class_interface真是太简单了。我们都怀疑其到底有没有用。但往往看起来简单的内容实际可能更复杂,比如driver,还有这里的class_interface。cpp view plaincopy1. struct class_attribute 2.
23、60; struct attribute attr; 3. ssize_t (*show)(struct class *class, char *buf); 4. ssize_t (*store)(struct class *class, const char *buf, size_t count)
24、; 5. ; 6. 7. #define CLASS_ATTR(_name, _mode, _show, _store) 8. struct class_attribute class_attr_#_name = _ATTR(_name, _mode, _show, _store)
25、; 从bus_attribute,到driver_attribute,到device_attribute,当然也少不了这里的class_attribute。struct attribute封装这种东西,既简单又耐用,何乐而不为? 结构讲完了,下面看看class.c中的实现,还是我喜欢的自上而下式。cpp view plaincopy1. #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
26、2. 3. static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, 4. char *buf) 5.
27、6. struct class_attribute *class_attr = to_class_attr(attr); 7. struct class_private *cp = to_class(kobj); 8. ssize_t ret = -EIO; 9. &
28、#160;10. if (class_attr->show) 11. ret = class_attr->show(cp->class, buf); 12. return ret; 13. 14. 15. static
29、0;ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, 16. const char *buf, size_t count) 17. 18.
30、0; struct class_attribute *class_attr = to_class_attr(attr); 19. struct class_private *cp = to_class(kobj); 20. ssize_t ret = -EIO; 21.
31、;22. if (class_attr->store) 23. ret = class_attr->store(cp->class, buf, count); 24. return ret; 25. 26. 27.
32、static struct sysfs_ops class_sysfs_ops = 28. .show = class_attr_show, 29. .store = class_attr_store, 30. ; class_sysfs_ops就是class定义的sysfs读写函数集合
33、。cpp view plaincopy1. static void class_release(struct kobject *kobj) 2. 3. struct class_private *cp = to_class(kobj); 4. struct class *class = cp->cl
34、ass; 5. 6. pr_debug("class '%s': release.n", class->name); 7. 8. if (class->class_release) 9. class->
35、;class_release(class); 10. else 11. pr_debug("class '%s' does not have a release() function, " 12.
36、160; "be carefuln", class->name); 13. 14. 15. static struct kobj_type class_ktype = 16. .sysfs_ops = &class_sysfs_ops,
37、160;17. .release = class_release, 18. ; class_release()是在class引用计数降为零时调用的释放函数。因为class在结构中提供了class_release的函数指针,所以可以由具体的class调用相应的处理方法。class_ktype是为class对应的kobject(也可以说kset)定义的kobj_type。cpp view plaincopy1. /* Hotplug
38、 events for classes go to the class class_subsys */ 2. static struct kset *class_kset; 3. 4. int _init classes_init(void) 5. 6. class_kset =
39、0;kset_create_and_add("class", NULL, NULL); 7. if (!class_kset) 8. return -ENOMEM; 9. return 0; 10. class_kset代表了
40、/sys/class对应的kset,在classes_init()中创建。classes_init()的作用,和之前见到的buses_init()、devices_init()作用相似,都是构建/sys下的主要目录结构。cpp view plaincopy1. int class_create_file(struct class *cls, const struct class_attribute *attr) 2. 3.
41、;int error; 4. if (cls) 5. error = sysfs_create_file(&cls->p->class_subsys.kobj, 6.
42、60; &attr->attr); 7. else 8. error = -EINVAL; 9. return error; 10. 11.
43、160;12. void class_remove_file(struct class *cls, const struct class_attribute *attr) 13. 14. if (cls) 15. sysfs_remove_file(&cls->p->class_subs
44、ys.kobj, &attr->attr); 16. class_create_file()创建class的属性文件。class_remove_files()删除class的属性文件。这两个都是对外提供的API。cpp view plaincopy1. static struct class *class_get(struct class *cls) 2. 3. if
45、60;(cls) 4. kset_get(&cls->p->class_subsys); 5. return cls; 6. 7. 8. static void class_put(struct class *cls) 9.
46、10. if (cls) 11. kset_put(&cls->p->class_subsys); 12. class_get()增加对cls的引用计数,class_put()减少对cls的引用计数,并在计数降为零时调用相应的释放函数,也就是之前见过的class_release函数。class的引用计数是由class_private结构中的kset来管的,
47、kset又是由其内部kobject来管的,kobject又是调用其结构中的kref来管的。这是一种嵌套的封装技术。cpp view plaincopy1. static int add_class_attrs(struct class *cls) 2. 3. int i; 4. int error = 0; 5.
48、0; 6. if (cls->class_attrs) 7. for (i = 0; attr_name(cls->class_attrsi); i+) 8. e
49、rror = class_create_file(cls, &cls->class_attrsi); 9. if (error) 10. goto erro
50、r; 11. 12. 13. done: 14. return error; 15. error: 16. while (-i >= 0) 17.
51、0; class_remove_file(cls, &cls->class_attrsi); 18. goto done; 19. 20. 21. static void remove_class_attrs(struct class *cls) 22. 2
52、3. int i; 24. 25. if (cls->class_attrs) 26. for (i = 0; attr_name(cls->class_attrsi); i+) 27.
53、 class_remove_file(cls, &cls->class_attrsi); 28. 29. add_class_attrs()把cls->class_attrs中的属性加入sysfs。remove_class_attrs()把cls->class_attrs中的属性删除。到了class这个级别,就和bus一样,除了自己,没有
54、其它结构能为自己添加属性。cpp view plaincopy1. static void klist_class_dev_get(struct klist_node *n) 2. 3. struct device *dev = container_of(n, struct device, knode_class); 4. 5.
55、0; get_device(dev); 6. 7. 8. static void klist_class_dev_put(struct klist_node *n) 9. 10. struct device *dev = container_of(n, struct device, knod
56、e_class); 11. 12. put_device(dev); 13. klist_class_dev_get()增加节点对应设备的引用计数,klist_class_dev_put()减少节点对应设备的引用计数。这是class的设备链表,在节点添加和删除时调用的。相似的klist链表,还有驱动的设备链表,不过由于linux对驱动不太信任,所以没有让驱动占用设备的引用计数。还有总线的设备链表,在添加释放节点时分别调用klist_devices_get(
57、)和list_devices_put(),是在bus.c中定义的。还有设备的子设备链表,在添加释放节点时分别调用klist_children_get()和klist_children_put(),是在device.c中定义的。看来klist中的get()/put()函数,是在初始化klist时设定的,也由创建方负责实现。cpp view plaincopy1. /* This is a #define to keep the compiler from merging dif
58、ferent 2. * instances of the _key variable */ 3. #define class_register(class) 4. (
59、; 5. static struct lock_class_key _key; 6. _class_register(class, &_key); 7. ) 8. 9. int
60、_class_register(struct class *cls, struct lock_class_key *key) 10. 11. struct class_private *cp; 12. int error; 13. 14. pr_debug(&q
61、uot;device class '%s': registeringn", cls->name); 15. 16. cp = kzalloc(sizeof(*cp), GFP_KERNEL); 17. if (!cp) 18. &
62、#160; return -ENOMEM; 19. klist_init(&cp->class_devices, klist_class_dev_get, klist_class_dev_put); 20. INIT_LIST_HEAD(&cp->class_interfaces); 21. kset_init(&
63、;cp->class_dirs); 22. _mutex_init(&cp->class_mutex, "struct class mutex", key); 23. error = kobject_set_name(&cp->class_subsys.kobj, "%s", cls->name);
64、 24. if (error) 25. kfree(cp); 26. return error; 27. 28. 29.
65、; /* set the default /sys/dev directory for devices of this class */ 30. if (!cls->dev_kobj) 31. cls->dev_kobj = sysfs_
66、dev_char_kobj; 32. 33. #if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK) 34. /* let the block class directory show up in the root of sysfs */&
67、#160; 35. if (cls != &block_class) 36. cp->class_subsys.kobj.kset = class_kset; 37. #else 38. cp->class_subsys.kobj.kset =
68、0;class_kset; 39. #endif 40. cp->class_subsys.kobj.ktype = &class_ktype; 41. cp->class = cls; 42. cls->p = cp; 43. 44.
69、 error = kset_register(&cp->class_subsys); 45. if (error) 46. kfree(cp); 47. return error;
70、 48. 49. error = add_class_attrs(class_get(cls); 50. class_put(cls); 51. return error; 52. class_register()将class注册到系统中。之
71、所以把class_register()写成宏定义的形式,似乎是为了_key的不同实例合并,在_class_register()中确实使用了_key,但是是为了调试class中使用的mutex用的。_key的类型lock_class_key是只有使用LOCKDEP定义时才会有内容,写成这样也许是为了在lock_class_key定义为空时减少一些不必要的空间消耗。总之这类trick的做法,是不会影响我们理解代码逻辑的。_class_register()中进行实际的class注册工作:先是分配和初始化class_private结构。可以看到对cp->class_dirs,只是调用kset_i
72、nit()定义,并未实际注册到sysfs中。调用kobject_set_name()创建kobj中实际的类名。cls->dev_kobj如果未设置,这里会被设为sysfs_dev_char_kobj。调用kset_register()将class注册到sysfs中,所属kset为class_kset,使用类型为class_ktype。因为没有设置parent,会以/sys/class为父目录。最后调用add_class_attrs()添加相关的属性文件。在bus、device、driver、class中,最简单的注册过程就是class的注册,因为它不仅和bus一样属于一种顶层结构,而且连
73、通用的属性文件都不需要,所有的操作就围绕在class_private的创建初始化与添加到sysfs上面。cpp view plaincopy1. void class_unregister(struct class *cls) 2. 3. pr_debug("device class '%s': unregisteringn", cls->name); 4.
74、 remove_class_attrs(cls); 5. kset_unregister(&cls->p->class_subsys); 6. class_unregister()取消class的注册。它的操作也简单到了极点。只是这里的class注销也太懒了些。无论是class_unregister(),还是在计数完全释放时调用的class_release(),都找不到释放class_private结构的地方。这是
75、bug吗?我怀着敬畏的心情,查看了linux-3.0.4中的drivers/base/class.c,发现其中的class_release()函数最后添加了释放class_private结构的代码。看来linux-2.6.32还是有较为明显的缺陷。奈何木已成舟,只能先把这个bug在现有代码里改正,至少以后自己编译内核时不会再这个问题上出错。不过说起来,像bus_unregister()、class_unregister()这种函数,估计只有在关机时才可能调用得到,实在是无关紧要。cpp view plaincopy1. /* This is a
76、;#define to keep the compiler from merging different 2. * instances of the _key variable */ 3. #define class_create(owner, name) 4. (
77、; 5. static struct lock_class_key _key; 6. _class_create(owner, name, &_key);
78、0; 7. ) 8. 9. /* 10. * class_create - create a struct class structure 11. * owner: pointer to the module that is to "own" this
79、;struct class 12. * name: pointer to a string for the name of this class. 13. * key: the lock_class_key for this class; used by mutex lock debugging 14.
80、;* 15. * This is used to create a struct class pointer that can then be used 16. * in calls to device_create(). 17. * 18. * Note, the pointer crea
81、ted here is to be destroyed when finished by 19. * making a call to class_destroy(). 20. */ 21. struct class *_class_create(struct module *owner, const char *name,
82、0; 22. struct lock_class_key *key) 23. 24. struct class *cls; 25. int retval;
83、60;26. 27. cls = kzalloc(sizeof(*cls), GFP_KERNEL); 28. if (!cls) 29. retval = -ENOMEM; 30. &
84、#160; goto error; 31. 32. 33. cls->name = name; 34. cls->owner = owner; 35. cls->class_release =&
85、#160;class_create_release; 36. 37. retval = _class_register(cls, key); 38. if (retval) 39. goto error; 40. 41.
86、 return cls; 42. 43. error: 44. kfree(cls); 45. return ERR_PTR(retval); 46. class_create()是提供给外界快速创建class的API。应该说,class中可以提供的一系列函数,这里都没有提供,或许可以在创建后再加上。
87、相似的函数是在core.c中的device_create(),那是提供一种快速创建device的API。cpp view plaincopy1. static void class_create_release(struct class *cls) 2. 3. pr_debug("%s called for %sn", _func_, cls->name);
88、0;4. kfree(cls); 5. 6. 7. /* 8. * class_destroy - destroys a struct class structure 9. * cls: pointer to the struct class that is to b
89、e destroyed 10. * 11. * Note, the pointer to be destroyed must have been created with a call 12. * to class_create(). 13. */ 14. void class_destroy(struct
90、class *cls) 15. 16. if (cls = NULL) | (IS_ERR(cls) 17. return; 18. 19. class_unregister(cls); 20.
91、160;class_destroy()是与class_create()相对的删除class的函数。虽然在class_destroy()中没有看到释放class内存的代码,但这是在class_create_release()中做的。class_create_release()之前已经在class_create()中被作为class结构中定义的class_release()函数,会在class引用计数降为零时被调用。在class中,class结构和class_private结构都是在class引用计数降为零时才释放的。这保证了即使class已经被注销,仍然不会影响其下设备的正常使用。但在bus中,
92、bus_private结构是在bus_unregister()中就被释放的。没有了bus_private,bus下面的device和driver想必都无法正常工作了吧。这或许和bus对应与实际总线有关。总线都没了,下面的设备自然没人用了。 class为了遍历设备链表,特意定义了专门的结构和遍历函数,实现如下。cpp view plaincopy1. struct class_dev_iter 2. struct klist_iter
93、60; ki; 3. const struct device_type *type; 4. ; 5. 6. /* 7. * class_dev_iter_init - initialize class device iterator 8. * it
94、er: class iterator to initialize 9. * class: the class we wanna iterate over 10. * start: the device to start iterating from, if any 11. * type: device_type&
95、#160;of the devices to iterate over, NULL for all 12. * 13. * Initialize class iterator iter such that it iterates over devices 14. * of class. If star
96、t is set, the list iteration will start there, 15. * otherwise if it is NULL, the iteration starts at the beginning of 16. * the list. 17. */ 18.
97、void class_dev_iter_init(struct class_dev_iter *iter, struct class *class, 19. struct device *start, const struct device_type *type) 20.
98、60; 21. struct klist_node *start_knode = NULL; 22. 23. if (start) 24. start_knode = &start->knode_class; 25.
99、60; klist_iter_init_node(&class->p->class_devices, &iter->ki, start_knode); 26. iter->type = type; 27. 28. 29. struct device *class_dev_iter_next(struct class
100、_dev_iter *iter) 30. 31. struct klist_node *knode; 32. struct device *dev; 33. 34. while (1) 35.
101、60; knode = klist_next(&iter->ki); 36. if (!knode) 37. return NULL; 38. &
102、#160; dev = container_of(knode, struct device, knode_class); 39. if (!iter->type | iter->type = dev->type) 40. &
103、#160; return dev; 41. 42. 43. 44. void class_dev_iter_exit(struct class_dev_iter *iter) 45. 46. klist_iter_exit(&iter->ki); 47.
104、 之所以要如此费一番周折,在klist_iter外面加上这一层封装,完全是为了对链表进行选择性遍历。选择的条件就是device_type。device_type是在device结构中使用的类型,其中定义了相似设备使用的一些处理操作,可以说比class的划分还要小一层。class对设备链表如此遍历,也是用心良苦啊。cpp view plaincopy1. int class_for_each_device(struct class *class, struct device *start, &
105、#160;2. void *data, int (*fn)(struct device *, void *) 3. 4. struct class_dev_iter iter; 5. struct device *dev; 6. int error = 0; 7. 8. if (!class) 9. return -EINVAL; 10.
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年山西省财政税务专科学校单招职业适应性测试题库及答案详解(易错题)
- 2025《六国论》中六国经济发展的差异课件
- 河北省2026年单招职业技能考试二类模拟试题及答案解析(普高生)
- 农业产业园新建鸡肉制品加工车间项目可行性研究报告
- 2026年山西老区职业技术学院单招职业适应性测试题库带答案详解(巩固)
- 2026年山西铁道职业技术学院单招职业倾向性测试题库含答案详解(培优)
- 2026年广州工程技术职业学院单招综合素质考试题库附参考答案详解(满分必刷)
- 2026年广西安全工程职业技术学院单招职业倾向性测试题库及1套参考答案详解
- 2026年广东农工商职业技术学院单招职业技能测试题库带答案详解(轻巧夺冠)
- 2026年崇左幼儿师范高等专科学校单招职业倾向性测试题库附参考答案详解(模拟题)
- 2026年常州工业职业技术学院单招职业适应性测试题库及答案详解(历年真题)
- 2026四川成都市金牛国投人力资源服务有限公司招聘金牛区街区规划师8人考试参考试题及答案解析
- CMA质量手册(2025版)-符合27025、评审准则
- 洁净车间安全施工方案
- 《中租联工程机械操作标准-旋挖钻机司机》征求意见稿
- 2023年考研考博-考博英语-煤炭科学研究总院考试历年高频考点真题荟萃带答案
- Peppa-Pig第1-38集英文字幕整理
- 统计用产品分类目录
- 雅培Perclose血管缝合器使用过程中常见问题及解决方法
- 中小学生课外读物负面清单自查表
- YS/T 73-2011副产品氧化锌
评论
0/150
提交评论