LINUX設備驅動模型之class

 

轉自 https://blog.csdn.net/qq_20678703/article/details/52754661node

一、LINUX設備驅動模型中的bus、device、driver,。其中bus:實際的總線,device:實際的設備和接口,而driver:對應存在的驅動。linux

2、但本節要介紹的class,是設備類,徹底是抽象出來的概念,沒有對應的實體。所謂設備類,是指提供的用戶接口類似的一類設備的集合,常見的設備類的有block、tty、input、usb等等。安全

三、class對應的代碼在drivers/base/class.c中,對應的頭文件在include/linux/device.h和drivers/base/base.h中。數據結構

仍是先來看class涉及的結構。框架

[cpp]  view plain  copy  
  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就是設備驅動模型中通用的設備類結構。ide

name表明類名稱,會在「/sys/class/」目錄下體現,例如:sys/class/p但和bus/device/driver中的名稱同樣,是初始名稱,實際使用的是內部kobj包含的動態建立的名稱。函數

owner是class所屬的模塊,雖然class是涉及一類設備,但也是由相應的模塊註冊的。好比usb類就是由usb模塊註冊的。this

class_atrrs,該class的默認attribute,會在class註冊到內核時,自動在「/sys/class/xxx_class」下建立對應的attribute文件
spa

dev_attrs,該class下每一個設備的attribute,會在設備註冊到內核時,自動在該設備的sysfs目錄下建立對應的attribute文件。
.net

dev_bin_attrs,相似dev_attrs,只不過是二進制類型attribute。

class_attrs是class給本身添加的屬性,dev_attrs是class給所包含的設備添加的屬性。這裏就像bus中同樣,只是bus是bus、driver、device所有包含的。

dev_kobj是一個kobject指針。若是你的記性很好(至少要比我好得多),你應該記得在device註冊時,會在/sys/dev下建立名爲本身設備號的軟連接。但設備不知道本身屬於塊設備仍是字符設備,因此會請示本身所屬的class,class就是用dev_kobj記錄本類設備應屬於的哪一種設備。表示該class下的設備在/sys/dev/下的目錄,如今通常有char和block兩個,若是dev_kobj爲NULL,則默認選擇char。

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 plain  copy  
  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 plain  copy  
  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 plain  copy  
  1. struct class_attribute {  
  2.     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);  
  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 plain  copy  
  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 plain  copy  
  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 plain  copy  
  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);   //class_kset表明了/sys/class
  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 plain  copy  
  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);  //cls->p->class_subsys.kobj 表明sys/class/下的目錄  例如:sys/class/video4linux
  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 plain  copy  
  1. static struct class *class_get(struct class *cls)  
  2. {  
  3.     if (cls)  
  4.         kset_get(&cls->p->class_subsys);  //class_subsys是一個容器,kset,其容器自己也是一個 kobj
  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 plain  copy  
  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 plain  copy  
  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 plain  copy  
  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)    //就是填充class_private 私有數據結構體。。而後註冊到內核中
  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);  //設備節點列表初始化,初始化klist的結構。若是klist_node結構將要被嵌入引用計數的對       象(所必需的安全的刪除),則得到/放參數用於初始化該採起的功能並釋放嵌入對象的引用。
  20.     INIT_LIST_HEAD(&cp->class_interfaces);  //初始化關聯的子系統接口列表
  21.  
  22.     kset_init(&cp->class_dirs);  
  23.     __mutex_init(&cp->class_mutex, "struct class mutex", key);  
  24.     error = kobject_set_name(&cp->class_subsys.kobj, "%s", cls->name);   //設置類的名字,例如video4linux ,sys/class/video4linux
  25.     if (error) {  
  26.         kfree(cp);  
  27.         return error;  
  28.     }  
  29.   
  30.     /* set the default /sys/dev directory for devices of this class */   //設備默認目錄sys/dev 爲類設備
  31.     if (!cls>dev_kobj) //表示該class下的設備在/sys/dev/下的目錄,如今通常有char和block兩個,若是dev_kobj爲NULL,則默認選擇char。
  32.         cls->dev_kobj = sysfs_dev_char_kobj;  
  33.   
  34. #if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK)  
  35.     /* let the block class directory show up in the root of sysfs */  
  36.     if (cls != &block_class)  
  37.         cp->class_subsys.kobj.kset = class_kset;   //
  38. #else  
  39.     cp->class_subsys.kobj.kset = class_kset;              //設置 例如:video4linux的頂級容器,sys/class
  40. #endif  
  41.     cp->class_subsys.kobj.ktype = &class_ktype;   //設zhi 例如:video4linux的類型
  42.     cp->class = cls;   //將類class 賦給 私有數據結構體class_private
  43.     cls->p = cp;   //將私有數據結構體class_private 賦給類class的私有數據結構體class_private
  44.   
  45.     error = kset_register(&cp->class_subsys);   //註冊進入內核,建立目錄 sys/class/video4linux
  46.     if (error) {  
  47.         kfree(cp);  
  48.         return error;  
  49.     }  
  50.     error = add_class_attrs(class_get(cls));                                                           //添加類屬性,並增長模塊引用計數 
  51.     class_put(cls);   //減小模塊引用計數
  52.     return error;  
  53. }  

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 plain  copy  
  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 plain  copy  
  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;   //填充類的名字,例如:video4linux gpio i2c等等。
  34.     cls->owner = owner;   //填充類所屬模塊
  35.     cls->class_release = class_create_release;   //類的釋放函數
  36.   
  37.     retval = __class_register(cls, key);   //在內核中註冊一個類
  38.  
  39.     if (retval)  
  40.         goto error;  
  41.   
  42.     return cls;  
  43.   
  44. error:  
  45.     kfree(cls);  
  46.     return ERR_PTR(retval);  
  47. }  

class_create()是提供給外界快速建立class的API。應該說,class中能夠提供的一系列函數,這裏都沒有提供,或許能夠在建立後再加上。

類似的函數是在core.c中的device_create(),那是提供一種快速建立device的API。

[cpp]  view plain  copy  
  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 plain  copy  
  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    start被設置,列表遍歷從start開始;不然,從列表的表頭開始。。
  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 plain  copy  
    1. int class_for_each_device(struct class *class, struct 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 *class, struct 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>  
相關文章
相關標籤/搜索