linux内核部件分析之——设备驱动模型之class

来源:互联网 发布:坐炮机的体验知乎 编辑:程序博客网 时间:2024/05/16 15:49

http://blog.csdn.net/bingqingsuimeng/article/details/7929283


前面看过了设备驱动模型中的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涉及的结构。

[cpp] view plaincopy
  1. struct class {  
  2.     const char      *name;  
  3.     struct module       *owner;  
  4.   
  5.     struct class_attribute      *class_attrs;  
  6.     struct device_attribute     *dev_attrs;  
  7.     struct kobject          *dev_kobj;  
  8.   
  9.     int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);  
  10.     char *(*devnode)(struct device *dev, mode_t *mode);  
  11.   
  12.     void (*class_release)(struct class *class);  
  13.     void (*dev_release)(struct device *dev);  
  14.   
  15.     int (*suspend)(struct device *dev, pm_message_t state);  
  16.     int (*resume)(struct device *dev);  
  17.   
  18.     const struct dev_pm_ops *pm;  
  19.   
  20.     struct class_private *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_kobj是一个kobject指针。如果你的记性很好(至少要比我好得多),你应该记得在device注册时,会在/sys/dev下创建名为自己设备号的软链接。但设备不知道自己属于块设备还是字符设备,所以会请示自己所属的class,class就是用dev_kobj记录本类设备应属于的哪种设备。

dev_uevent()是在设备发出uevent消息时添加环境变量用的。还记得在core.c中的dev_uevent()函数,其中就包含对设备所属bus或class中dev_uevent()方法的调用,只是bus结构中定义方法用的函数名是uevent。

devnode()返回设备节点的相对路径名。在core.c的device_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的指针。可见电源管理还是很重要的,只是这些东西都要结合具体的设备来分析,这里的设备驱动模型能给的,最多是一个函数指针与通用数据的框架。

p是指向class_private结构的指针。

[cpp] view plaincopy
  1. /** 
  2.  * struct class_private - structure to hold the private to the driver core portions of the class structure. 
  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 class 
  6.  * @class_interfaces - list of class_interfaces associated with this class 
  7.  * @class_dirs - "glue" directory for virtual devices associated with this class 
  8.  * @class_mutex - mutex to protect the children, devices, and interfaces lists. 
  9.  * @class - pointer back to the struct class that this structure is associated 
  10.  * with. 
  11.  * 
  12.  * This structure is the one that is the actual kobject allowing struct 
  13.  * class to be statically allocated safely.  Nothing outside of the driver 
  14.  * core should ever touch these fields. 
  15.  */  
  16. struct class_private {  
  17.     struct kset class_subsys;  
  18.     struct klist class_devices;  
  19.     struct list_head class_interfaces;  
  20.     struct kset class_dirs;  
  21.     struct mutex class_mutex;  
  22.     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类型,代表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中隔离这两个实际上有父子关系的设备。linux这么做也是为了在sysfs显示时更清晰一些。但如果父设备下有多个属于同一类的设备,它们需要放在同一胶水目录下。怎么寻找这个胶水目录有没有建立过,就要从这里的class_dirs下的kobject中找了。

class_mutex是互斥信号量,用于保护class内部的数据结构。

class是指回struct class的指针。

[cpp] view plaincopy
  1. struct class_interface {  
  2.     struct list_head    node;  
  3.     struct class        *class;  
  4.   
  5.     int (*add_dev)      (struct device *, struct class_interface *);  
  6.     void (*remove_dev)  (struct device *, struct class_interface *);  
  7. };  

struct class_interface就是之前被串在class->p->class_interface上的类接口的结构。用于描述设备类对外的一种接口。
node就是class->p->class_interface链表上的节点。

class是指向所属class的指针。

add_dev()是在有设备添加到所属class时调用的函数。当然,如果class_interface比设备更晚添加到class,也会补上的。

remove_dev()是在设备删除时调用的。

从结构来看class_interface真是太简单了。我们都怀疑其到底有没有用。但往往看起来简单的内容实际可能更复杂,比如driver,还有这里的class_interface。

[cpp] view plaincopy
  1. struct class_attribute {  
  2.     struct attribute attr;  
  3.     ssize_t (*show)(struct class *classchar *buf);  
  4.     ssize_t (*store)(struct class *classconst char *buf, size_t count);  
  5. };  
  6.   
  7. #define CLASS_ATTR(_name, _mode, _show, _store)         \  
  8. struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store)  

从bus_attribute,到driver_attribute,到device_attribute,当然也少不了这里的class_attribute。struct attribute封装这种东西,既简单又耐用,何乐而不为?

 

结构讲完了,下面看看class.c中的实现,还是我喜欢的自上而下式。

[cpp] view plaincopy
  1. #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)  
  2.   
  3. static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr,  
  4.                    char *buf)  
  5. {  
  6.     struct class_attribute *class_attr = to_class_attr(attr);  
  7.     struct class_private *cp = to_class(kobj);  
  8.     ssize_t ret = -EIO;  
  9.   
  10.     if (class_attr->show)  
  11.         ret = class_attr->show(cp->class, buf);  
  12.     return ret;  
  13. }  
  14.   
  15. static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr,  
  16.                 const char *buf, size_t count)  
  17. {  
  18.     struct class_attribute *class_attr = to_class_attr(attr);  
  19.     struct class_private *cp = to_class(kobj);  
  20.     ssize_t ret = -EIO;  
  21.   
  22.     if (class_attr->store)  
  23.         ret = class_attr->store(cp->class, buf, count);  
  24.     return ret;  
  25. }  
  26.   
  27. static struct sysfs_ops class_sysfs_ops = {  
  28.     .show   = class_attr_show,  
  29.     .store  = class_attr_store,  
  30. };  

class_sysfs_ops就是class定义的sysfs读写函数集合。

[cpp] view plaincopy
  1. static void class_release(struct kobject *kobj)  
  2. {  
  3.     struct class_private *cp = to_class(kobj);  
  4.     struct class *class = cp->class;  
  5.   
  6.     pr_debug("class '%s': release.\n"class->name);  
  7.   
  8.     if (class->class_release)  
  9.         class->class_release(class);  
  10.     else  
  11.         pr_debug("class '%s' does not have a release() function, "  
  12.              "be careful\n"class->name);  
  13. }  
  14.   
  15. static struct kobj_type class_ktype = {  
  16.     .sysfs_ops  = &class_sysfs_ops,  
  17.     .release    = class_release,  
  18. };  

class_release()是在class引用计数降为零时调用的释放函数。因为class在结构中提供了class_release的函数指针,所以可以由具体的class调用相应的处理方法。

class_ktype是为class对应的kobject(也可以说kset)定义的kobj_type。

[cpp] view plaincopy
  1. /* Hotplug 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 = kset_create_and_add("class", NULL, NULL);  
  7.     if (!class_kset)  
  8.         return -ENOMEM;  
  9.     return 0;  
  10. }  

class_kset代表了/sys/class对应的kset,在classes_init()中创建。

classes_init()的作用,和之前见到的buses_init()、devices_init()作用相似,都是构建/sys下的主要目录结构。

[cpp] view plaincopy
  1. int class_create_file(struct class *cls, const struct class_attribute *attr)  
  2. {  
  3.     int error;  
  4.     if (cls)  
  5.         error = sysfs_create_file(&cls->p->class_subsys.kobj,  
  6.                       &attr->attr);  
  7.     else  
  8.         error = -EINVAL;  
  9.     return error;  
  10. }  
  11.   
  12. void class_remove_file(struct class *cls, const struct class_attribute *attr)  
  13. {  
  14.     if (cls)  
  15.         sysfs_remove_file(&cls->p->class_subsys.kobj, &attr->attr);  
  16. }  

class_create_file()创建class的属性文件。

class_remove_files()删除class的属性文件。这两个都是对外提供的API。

[cpp] view plaincopy
  1. static struct class *class_get(struct class *cls)  
  2. {  
  3.     if (cls)  
  4.         kset_get(&cls->p->class_subsys);  
  5.     return cls;  
  6. }  
  7.   
  8. static void class_put(struct class *cls)  
  9. {  
  10.     if (cls)  
  11.         kset_put(&cls->p->class_subsys);  
  12. }  

class_get()增加对cls的引用计数,class_put()减少对cls的引用计数,并在计数降为零时调用相应的释放函数,也就是之前见过的class_release函数。

class的引用计数是由class_private结构中的kset来管的,kset又是由其内部kobject来管的,kobject又是调用其结构中的kref来管的。这是一种嵌套的封装技术。

[cpp] view plaincopy
  1. static int add_class_attrs(struct class *cls)  
  2. {  
  3.     int i;  
  4.     int error = 0;  
  5.   
  6.     if (cls->class_attrs) {  
  7.         for (i = 0; attr_name(cls->class_attrs[i]); i++) {  
  8.             error = class_create_file(cls, &cls->class_attrs[i]);  
  9.             if (error)  
  10.                 goto error;  
  11.         }  
  12.     }  
  13. done:  
  14.     return error;  
  15. error:  
  16.     while (--i >= 0)  
  17.         class_remove_file(cls, &cls->class_attrs[i]);  
  18.     goto done;  
  19. }  
  20.   
  21. static void remove_class_attrs(struct class *cls)  
  22. {  
  23.     int i;  
  24.   
  25.     if (cls->class_attrs) {  
  26.         for (i = 0; attr_name(cls->class_attrs[i]); i++)  
  27.             class_remove_file(cls, &cls->class_attrs[i]);  
  28.     }  
  29. }  

add_class_attrs()把cls->class_attrs中的属性加入sysfs。

remove_class_attrs()把cls->class_attrs中的属性删除。

到了class这个级别,就和bus一样,除了自己,没有其它结构能为自己添加属性。

[cpp] view plaincopy
  1. static void klist_class_dev_get(struct klist_node *n)  
  2. {  
  3.     struct device *dev = container_of(n, struct device, knode_class);  
  4.   
  5.     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, knode_class);  
  11.   
  12.     put_device(dev);  
  13. }  

klist_class_dev_get()增加节点对应设备的引用计数,klist_class_dev_put()减少节点对应设备的引用计数。

这是class的设备链表,在节点添加和删除时调用的。相似的klist链表,还有驱动的设备链表,不过由于linux对驱动不太信任,所以没有让驱动占用设备的引用计数。还有总线的设备链表,在添加释放节点时分别调用klist_devices_get()和list_devices_put(),是在bus.c中定义的。还有设备的子设备链表,在添加释放节点时分别调用klist_children_get()和klist_children_put(),是在device.c中定义的。看来klist中的get()/put()函数,是在初始化klist时设定的,也由创建方负责实现。

[cpp] view plaincopy
  1. /* This is a #define to keep the compiler from merging different 
  2.  * instances of the __key variable */  
  3. #define class_register(class)           \  
  4. ({                      \  
  5.     static struct lock_class_key __key; \  
  6.     __class_register(class, &__key);    \  
  7. })  
  8.   
  9. int __class_register(struct class *cls, struct lock_class_key *key)  
  10. {  
  11.     struct class_private *cp;  
  12.     int error;  
  13.   
  14.     pr_debug("device class '%s': registering\n", cls->name);  
  15.   
  16.     cp = kzalloc(sizeof(*cp), GFP_KERNEL);  
  17.     if (!cp)  
  18.         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(&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);  
  24.     if (error) {  
  25.         kfree(cp);  
  26.         return error;  
  27.     }  
  28.   
  29.     /* set the default /sys/dev directory for devices of this class */  
  30.     if (!cls->dev_kobj)  
  31.         cls->dev_kobj = sysfs_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 */  
  35.     if (cls != &block_class)  
  36.         cp->class_subsys.kobj.kset = class_kset;  
  37. #else  
  38.     cp->class_subsys.kobj.kset = class_kset;  
  39. #endif  
  40.     cp->class_subsys.kobj.ktype = &class_ktype;  
  41.     cp->class = cls;  
  42.     cls->p = cp;  
  43.   
  44.     error = kset_register(&cp->class_subsys);  
  45.     if (error) {  
  46.         kfree(cp);  
  47.         return error;  
  48.     }  
  49.     error = add_class_attrs(class_get(cls));  
  50.     class_put(cls);  
  51.     return error;  
  52. }  

class_register()将class注册到系统中。之所以把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_init()定义,并未实际注册到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一样属于一种顶层结构,而且连通用的属性文件都不需要,所有的操作就围绕在class_private的创建初始化与添加到sysfs上面。

[cpp] view plaincopy
  1. void class_unregister(struct class *cls)  
  2. {  
  3.     pr_debug("device class '%s': unregistering\n", cls->name);  
  4.     remove_class_attrs(cls);  
  5.     kset_unregister(&cls->p->class_subsys);  
  6. }  

class_unregister()取消class的注册。它的操作也简单到了极点。

只是这里的class注销也太懒了些。无论是class_unregister(),还是在计数完全释放时调用的class_release(),都找不到释放class_private结构的地方。这是bug吗?

我怀着敬畏的心情,查看了linux-3.0.4中的drivers/base/class.c,发现其中的class_release()函数最后添加了释放class_private结构的代码。看来linux-2.6.32还是有较为明显的缺陷。奈何木已成舟,只能先把这个bug在现有代码里改正,至少以后自己编译内核时不会再这个问题上出错。

不过说起来,像bus_unregister()、class_unregister()这种函数,估计只有在关机时才可能调用得到,实在是无关紧要。

[cpp] view plaincopy
  1. /* This is a #define to keep the compiler from merging different 
  2.  * instances of the __key variable */  
  3. #define class_create(owner, name)       \  
  4. ({                      \  
  5.     static struct lock_class_key __key; \  
  6.     __class_create(owner, name, &__key);    \  
  7. })  
  8.   
  9. /** 
  10.  * class_create - create a struct class structure 
  11.  * @owner: pointer to the module that is to "own" this 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.  * 
  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 created 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,  
  22.                  struct lock_class_key *key)  
  23. {  
  24.     struct class *cls;  
  25.     int retval;  
  26.   
  27.     cls = kzalloc(sizeof(*cls), GFP_KERNEL);  
  28.     if (!cls) {  
  29.         retval = -ENOMEM;  
  30.         goto error;  
  31.     }  
  32.   
  33.     cls->name = name;  
  34.     cls->owner = owner;  
  35.     cls->class_release = class_create_release;  
  36.   
  37.     retval = __class_register(cls, key);  
  38.     if (retval)  
  39.         goto error;  
  40.   
  41.     return cls;  
  42.   
  43. error:  
  44.     kfree(cls);  
  45.     return ERR_PTR(retval);  
  46. }  

class_create()是提供给外界快速创建class的API。应该说,class中可以提供的一系列函数,这里都没有提供,或许可以在创建后再加上。

相似的函数是在core.c中的device_create(),那是提供一种快速创建device的API。

[cpp] view plaincopy
  1. static void class_create_release(struct class *cls)  
  2. {  
  3.     pr_debug("%s called for %s\n", __func__, cls->name);  
  4.     kfree(cls);  
  5. }  
  6.   
  7. /** 
  8.  * class_destroy - destroys a struct class structure 
  9.  * @cls: pointer to the struct class that is to be 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 class *cls)  
  15. {  
  16.     if ((cls == NULL) || (IS_ERR(cls)))  
  17.         return;  
  18.   
  19.     class_unregister(cls);  
  20. }  

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中,bus_private结构是在bus_unregister()中就被释放的。没有了bus_private,bus下面的device和driver想必都无法正常工作了吧。这或许和bus对应与实际总线有关。总线都没了,下面的设备自然没人用了。

 

class为了遍历设备链表,特意定义了专门的结构和遍历函数,实现如下。

[cpp] view plaincopy
  1. struct class_dev_iter {  
  2.     struct klist_iter       ki;  
  3.     const struct device_type    *type;  
  4. };  
  5.   
  6. /** 
  7.  * class_dev_iter_init - initialize class device iterator 
  8.  * @iter: 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 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 @start 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. void class_dev_iter_init(struct class_dev_iter *iter, struct class *class,  
  19.              struct device *start, const struct device_type *type)  
  20. {  
  21.     struct klist_node *start_knode = NULL;  
  22.   
  23.     if (start)  
  24.         start_knode = &start->knode_class;  
  25.     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_dev_iter *iter)  
  30. {  
  31.     struct klist_node *knode;  
  32.     struct device *dev;  
  33.   
  34.     while (1) {  
  35.         knode = klist_next(&iter->ki);  
  36.         if (!knode)  
  37.             return NULL;  
  38.         dev = container_of(knode, struct device, knode_class);  
  39.         if (!iter->type || iter->type == dev->type)  
  40.             return dev;  
  41.     }  
  42. }  
  43.   
  44. void class_dev_iter_exit(struct class_dev_iter *iter)  
  45. {  
  46.     klist_iter_exit(&iter->ki);  
  47. }  

之所以要如此费一番周折,在klist_iter外面加上这一层封装,完全是为了对链表进行选择性遍历。选择的条件就是device_type。device_type是在device结构中使用的类型,其中定义了相似设备使用的一些处理操作,可以说比class的划分还要小一层。class对设备链表如此遍历,也是用心良苦啊。

[cpp] view plaincopy
  1. int class_for_each_device(struct class *classstruct device *start,  
  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.     if (!class->p) {  
  11.         WARN(1, "%s called for class '%s' before it was initialized",  
  12.              __func__, class->name);  
  13.         return -EINVAL;  
  14.     }  
  15.   
  16.     class_dev_iter_init(&iter, class, start, NULL);  
  17.     while ((dev = class_dev_iter_next(&iter))) {  
  18.         error = fn(dev, data);  
  19.         if (error)  
  20.             break;  
  21.     }  
  22.     class_dev_iter_exit(&iter);  
  23.   
  24.     return error;  
  25. }<pre class="cpp" name="code">struct device *class_find_device(struct class *classstruct device *start,  
  26.                  void *data,  
  27.                  int (*match)(struct device *, void *))  
  28. {  
  29.     struct class_dev_iter iter;  
  30.     struct device *dev;  
  31.   
  32.     if (!class)  
  33.         return NULL;  
  34.     if (!class->p) {  
  35.         WARN(1, "%s called for class '%s' before it was initialized",  
  36.              __func__, class->name);  
  37.         return NULL;  
  38.     }  
  39.   
  40.     class_dev_iter_init(&iter, class, start, NULL);  
  41.     while ((dev = class_dev_iter_next(&iter))) {  
  42.         if (match(dev, data)) {  
  43.             get_device(dev);  
  44.             break;  
  45.         }  
  46.     }  
  47.     class_dev_iter_exit(&iter);  
  48.   
  49.     return dev;  
  50. }</pre>  
  51. <pre></pre>  
  52. <p class="cpp" name="code">class_for_each_device()是对class的设备链表上的每个设备调用指定的函数。</p>  
  53. <p class="cpp" name="code">class_find_device()查找class设备链表上的某个设备,使用指定的匹配函数。</p>  
  54. <p class="cpp" name="code"> </p>  
  55. <pre class="cpp" name="code">int class_interface_register(struct class_interface *class_intf)  
  56. {  
  57.     struct class *parent;  
  58.     struct class_dev_iter iter;  
  59.     struct device *dev;  
  60.   
  61.     if (!class_intf || !class_intf->class)  
  62.         return -ENODEV;  
  63.   
  64.     parent = class_get(class_intf->class);  
  65.     if (!parent)  
  66.         return -EINVAL;  
  67.   
  68.     mutex_lock(&parent->p->class_mutex);  
  69.     list_add_tail(&class_intf->node, &parent->p->class_interfaces);  
  70.     if (class_intf->add_dev) {  
  71.         class_dev_iter_init(&iter, parent, NULL, NULL);  
  72.         while ((dev = class_dev_iter_next(&iter)))  
  73.             class_intf->add_dev(dev, class_intf);  
  74.         class_dev_iter_exit(&iter);  
  75.     }  
  76.     mutex_unlock(&parent->p->class_mutex);  
  77.   
  78.     return 0;  
  79. }</pre>  
  80. <p class="cpp" name="code">class_interface_register()把class_interface添加到指定的class上。</p>  
  81. <p class="cpp" name="code">调用class_get()获取class的引用计数。</p>  
  82. <p class="cpp" name="code">使用class->class_mutex进行保护。</p>  
  83. <p class="cpp" name="code">将classs_intf添加到class的接口列表中。</p>  
  84. <p class="cpp" name="code">对已经添加到class上的设备补上add_dev()操作。</p>  
  85. <p class="cpp" name="code">这里使用的class->class_mutex是用来保护class的类接口链表。对于简单的list_head来说,这种mutex保护是应该的。但对于武装到牙齿的klist来说,就完全不必要了,因为klist内置了spinlock来完成互斥的操作。所以之前其它的klist链表操作都没有mutex保护。</p>  
  86. <p class="cpp" name="code">比较spinlock和mutex的话,spinlock操作要比mutex快很多,因为对mutex的操作本身就需要spinlock来保护。但mutex的好处是它可以阻塞。使用spinlock时间太长的话,一是浪费cpu时间,二是禁止了任务抢占。klist是使用spinlock来保护的,这适合大部分情况,但在klist遍历时也可能调用一些未知的操作,它们可能很耗时,甚至可能阻塞,这时最好能使用mutex加以替换。</p>  
  87. <p class="cpp" name="code"> </p>  
  88. <pre class="cpp" name="code">void class_interface_unregister(struct class_interface *class_intf)  
  89. {  
  90.     struct class *parent = class_intf->class;  
  91.     struct class_dev_iter iter;  
  92.     struct device *dev;  
  93.   
  94.     if (!parent)  
  95.         return;  
  96.   
  97.     mutex_lock(&parent->p->class_mutex);  
  98.     list_del_init(&class_intf->node);  
  99.     if (class_intf->remove_dev) {  
  100.         class_dev_iter_init(&iter, parent, NULL, NULL);  
  101.         while ((dev = class_dev_iter_next(&iter)))  
  102.             class_intf->remove_dev(dev, class_intf);  
  103.         class_dev_iter_exit(&iter);  
  104.     }  
  105.     mutex_unlock(&parent->p->class_mutex);  
  106.   
  107.     class_put(parent);  
  108. }</pre>  
  109. <p class="cpp" name="code">class_interface_unregister()从class中去除指定的class_interface。对于这些class_interface来说,自己注销和设备注销效果是一样的,都会调用相应的remove_dev()。</p>  
  110. <p class="cpp" name="code"><br>  
  111. <br>  
  112.  </p>  
  113. <pre class="cpp" name="code">struct class_compat {  
  114.     struct kobject *kobj;  
  115. };  
  116.   
  117. /** 
  118.  * class_compat_register - register a compatibility class 
  119.  * @name: the name of the class 
  120.  * 
  121.  * Compatibility class are meant as a temporary user-space compatibility 
  122.  * workaround when converting a family of class devices to a bus devices. 
  123.  */  
  124. struct class_compat *class_compat_register(const char *name)  
  125. {  
  126.     struct class_compat *cls;  
  127.   
  128.     cls = kmalloc(sizeof(struct class_compat), GFP_KERNEL);  
  129.     if (!cls)  
  130.         return NULL;  
  131.     cls->kobj = kobject_create_and_add(name, &class_kset->kobj);  
  132.     if (!cls->kobj) {  
  133.         kfree(cls);  
  134.         return NULL;  
  135.     }  
  136.     return cls;  
  137. }  
  138.   
  139. void class_compat_unregister(struct class_compat *cls)  
  140. {  
  141.     kobject_put(cls->kobj);  
  142.     kfree(cls);  
  143. }</pre>  
  144. <p class="cpp" name="code">在/sys/class下面,除了class类型的,还有表现起来和class相同的class_compat类型。</p>  
  145. <p class="cpp" name="code">其实class_compat就是单单为了显示一个目录,不会定义对应的属性或者函数。</p>  
  146. <p class="cpp" name="code"> </p>  
  147. <pre class="cpp" name="code">/** 
  148.  * class_compat_create_link - create a compatibility class device link to 
  149.  *                a bus device 
  150.  * @cls: the compatibility class 
  151.  * @dev: the target bus device 
  152.  * @device_link: an optional device to which a "device" link should be created 
  153.  */  
  154. int class_compat_create_link(struct class_compat *cls, struct device *dev,  
  155.                  struct device *device_link)  
  156. {  
  157.     int error;  
  158.   
  159.     error = sysfs_create_link(cls->kobj, &dev->kobj, dev_name(dev));  
  160.     if (error)  
  161.         return error;  
  162.   
  163.     /* 
  164.      * Optionally add a "device" link (typically to the parent), as a 
  165.      * class device would have one and we want to provide as much 
  166.      * backwards compatibility as possible. 
  167.      */  
  168.     if (device_link) {  
  169.         error = sysfs_create_link(&dev->kobj, &device_link->kobj,  
  170.                       "device");  
  171.         if (error)  
  172.             sysfs_remove_link(cls->kobj, dev_name(dev));  
  173.     }  
  174.   
  175.     return error;  
  176. }  
  177.   
  178. void class_compat_remove_link(struct class_compat *cls, struct device *dev,  
  179.                   struct device *device_link)  
  180. {  
  181.     if (device_link)  
  182.         sysfs_remove_link(&dev->kobj, "device");  
  183.     sysfs_remove_link(cls->kobj, dev_name(dev));  
  184. }</pre>  
  185. <p class="cpp" name="code">class_compat_create_link()的目的是在class_compat目录下建立类似于class目录下的,对设备的软链接。这个不是在标准的设备注册时调用的。</p>  
  186. <p class="cpp" name="code"> </p>  
  187. <p class="cpp" name="code"> </p>  
  188. <p class="cpp" name="code">本节我们分析完了设备驱动模型中的class,对设备驱动模型的分析也告一段落。虽然只有五个文件,但已经基本上描绘了设备驱动模型的框架。要加深对它的认识,就要在此基础上不断充实细节,用具体的设备驱动来理解。<br>  
  189. <br>  
  190. </p>  

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 怀孕长妊娠纹了怎么办 坐久了肚子胀疼怎么办 怀孕后胖的太快怎么办 怀孕牙齿全坏了怎么办 怀孕脸胖了好多怎么办 孕晚期不爱吃肉怎么办 怀孕期间胖了怎么办啊 孕期长得太胖怎么办 狗吃马肉脸肿了怎么办 狗过敏了脸肿了怎么办 孕初期外阴很痒怎么办 怀孕了吃了田鸡怎么办 孕妇睡眠质量差怎么办吃什么 39周2天了还不生怎么办 孕中期体重猛长怎么办 4个半月胎位不正怎么办 41周不产生宫缩怎么办 生完孩子胎盘没有脱落怎么办 39周还是臀位怎么办 怀孕7个月胎位不正怎么办 怀孕六个多月胎位不正怎么办 怀孕七个月了胎位不正怎么办 怀孕七个月胎位不正怎么办 怀孕肚子上有妊娠纹怎么办 怀孕九个月肚子长痱子怎么办 怀孕前体重偏胖怎么办 怀孕打胰岛素血糖控制不好怎么办 孕后期憋的难受怎么办 怀孕6个月不想生怎么办 孕六个月不想要怎么办 怀孕9个月喝酒了怎么办 怀孕8个月喝醉了怎么办 怀孕6个月胃酸烧心怎么办 怀孕7个月胃酸怎么办 怀孕5个月胃酸怎么办 怀孕2个月胃酸怎么办 怀孕六个月胃酸烧心怎么办 孕六个月反胃酸怎么办 怀孕三个月胃酸吐酸水怎么办 孕六个月胃难受怎么办 孕6个月胃酸厉害怎么办