1. 概述
在設備模型中,Bus、Device、Device driver等等,都比較好理解,因為它們對應了實實在在的東西,所有的邏輯都是圍繞著這些實體展開的。而本文所要描述的Class就有些不同了,因為它是虛擬出來的,只是為了抽象設備的共性。
舉個例子,一些年齡相仿、需要獲取的知識相似的人,聚在一起學習,就構成了一個班級(Class)。這個班級可以有自己的名稱(如295),但如果離開構成它的學生(device),它就沒有任何存在意義。另外,班級存在的最大意義是什么呢?是由老師講授的每一個課程!因為老師只需要講一遍,一個班的學生都可以聽到。不然的話(例如每個學生都在家學習),就要為每人請一個老師,講授一遍。而講的內容,大多是一樣的,這就是極大的浪費。
設備模型中的Class所提供的功能也一樣了,例如一些相似的device(學生),需要向用戶空間提供相似的接口(課程),如果每個設備的驅動都實現一遍的話,就會導致內核有大量的冗余代碼,這就是極大的浪費。所以,Class說了,我幫你們實現吧,你們會用就行了。
這就是設備模型中Class的功能,再結合內核的注釋:A class is a higher-level view of a device that abstracts out low-level implementation details(include/linux/device.h line326),就容易理解了。
2. 數據結構描述
2.1 struct class
struct class是class的抽象,它的定義如下:
1: /* include/linux/device.h, line 332 */
2: struct class {
3: const char *name;
4: struct module *owner;
5:
6: struct class_attribute *class_attrs;
7: struct device_attribute *dev_attrs;
8: struct bin_attribute *dev_bin_attrs;
9: struct kobject *dev_kobj;
10:
11: int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
12: char *(*devnode)(struct device *dev, umode_t *mode);
13:
14: void (*class_release)(struct class *class);
15: void (*dev_release)(struct device *dev);
16:
17: int (*suspend)(struct device *dev, pm_message_t state);
18: int (*resume)(struct device *dev);
19:
20: const struct kobj_ns_type_operations *ns_type;
21: const void *(*namespace)(struct device *dev);
22:
23: const struct dev_pm_ops *pm;
24:
25: struct subsys_private *p;
26: };
其實struct class和struct bus很類似,解釋如下:
name,class的名稱,會在“/sys/class/”目錄下體現。
class_atrrs,該class的默認attribute,會在class注冊到內核時,自動在“/sys/class/xxx_class”下創建對應的attribute文件。
dev_attrs,該class下每個設備的attribute,會在設備注冊到內核時,自動在該設備的sysfs目錄下創建對應的attribute文件。
dev_bin_attrs,類似dev_attrs,只不過是二進制類型attribute。
dev_kobj,表示該class下的設備在/sys/dev/下的目錄,現在一般有char和block兩個,如果dev_kobj為NULL,則默認選擇char。
dev_uevent,當該class下有設備發生變化時,會調用class的uevent回調函數。
class_release,用于release自身的回調函數。
dev_release,用于release class內設備的回調函數。在device_release接口中,會依次檢查Device、Device Type以及Device所在的class,是否注冊release接口,如果有則調用相應的release接口release設備指針。
p,和“Linux設備模型(6)_Bus”中struct bus結構一樣,不再說明。
2.2 struct class_interface
struct class_interface是這樣的一個結構:它允許class driver在class下有設備添加或移除的時候,調用預先設置好的回調函數(add_dev和remove_dev)。那調用它們做什么呢?想做什么都行(例如修改設備的名稱),由具體的class driver實現。
該結構的定義如下:
1: /* include/linux/device.h, line 434 */
2: struct class_interface {
3: struct list_head node;
4: struct class *class;
5:
6: int (*add_dev) (struct device *, struct class_interface *);
7: void (*remove_dev) (struct device *, struct class_interface *);
8: };
3. 功能及內部邏輯解析
3.1 class的功能
看完上面的東西,蝸蝸依舊糊里糊涂的,class到底提供了什么功能?怎么使用呢?讓我們先看一下現有Linux系統中有關class的狀況(這里以input class為例):
root@android:/ # ls /sys/class/input/ -l???????????????????????????????????????????????????????????????????????????????????????????
lrwxrwxrwx root???? root????????????? 2014-04-23 03:39 event0 -> ../../devices/platform/i2c-gpio.17/i2c-17/17-0066/max77693-muic/input/input0/event0?
lrwxrwxrwx root???? root????????????? 2014-04-23 03:39 event1 -> ../../devices/platform/gpio-keys.0/input/input1/event1?
lrwxrwxrwx root???? root????????????? 2014-04-23 03:39 event10 -> ../../devices/virtual/input/input10/event10?
lrwxrwxrwx root???? root????????????? 2014-04-23 03:39 event2 -> ../../devices/platform/s3c2440-i2c.3/i2c-3/3-0048/input/input2/event2?
…?
lrwxrwxrwx root???? root????????????? 2014-04-23 03:39 event8 -> ../../devices/platform/soc-audio/sound/card0/input8/event8?
lrwxrwxrwx root???? root????????????? 2014-04-23 03:39 event9 -> ../../devices/platform/i2c-gpio.8/i2c-8/8-0020/input/input9/event9?
lrwxrwxrwx root???? root????????????? 2014-04-23 03:39 input0 -> ../../devices/platform/i2c-gpio.17/i2c-17/17-0066/max77693-muic/input/input0?
…?
lrwxrwxrwx root???? root????????????? 2014-04-23 03:39 mice -> ../../devices/virtual/input/mice
root@android:/?# ls /sys/devices/platform/s3c2440-i2c.3/i2c-3/3-0048/input/input2/event2/ -l?????????????
-r--r--r-- root???? root???????? 4096 2014-04-23 04:08 dev?
lrwxrwxrwx root???? root????????????? 2014-04-23 04:08 device -> ../../input2?
drwxr-xr-x root???? root????????????? 2014-04-23 04:08 power?
lrwxrwxrwx root???? root????????????? 2014-04-23 04:08 subsystem -> ../../../../../../../../class/input?
-rw-r--r-- root???? root???????? 4096 2014-04-23 04:08 uevent
root@android:/ # ls /sys/devices/virtual/input/mice/ -l???????????????????????????????????????
-r--r--r-- root???? root???????? 4096 2014-04-23 03:57 dev?
drwxr-xr-x root???? root????????????? 2014-04-23 03:57 power?
lrwxrwxrwx root???? root????????????? 2014-04-23 03:57 subsystem -> ../../../../class/input?
-rw-r--r-- root???? root???????? 4096 2014-04-23 03:57 uevent
看上面的例子,發現input class也沒做什么實實在在的事兒,它(input class)的功能,僅僅是:
在/sys/class/目錄下,創建一個本class的目錄(input)
在本目錄下,創建每一個屬于該class的設備的符號鏈接(如,把“sys/devices/platform/s3c2440-i2c.3/i2c-3/3-0048/input/input2/event2”設備鏈接到”/sys/class/input/event2”),這樣就可以在本class目錄下,訪問該設備的所有特性(即attribute)
另外,device在sysfs的目錄下,也會創建一個subsystem的符號鏈接,鏈接到本class的目錄
算了,我們還是先分析一下Class的核心邏輯都做了哪些事情,至于class到底有什么用處,可以在后續具體的子系統里面(如input子系統),更為細致的探討。
3.2 class的注冊
class的注冊,是由__class_register接口(它的實現位于"drivers/base/class.c, line 609")實現的,它的處理邏輯和bus的注冊類似,主要包括:
為class結構中的struct subsys_private類型的指針(cp)分配空間,并初始化其中的字段,包括cp->subsys.kobj.kset、cp->subsys.kobj.ktype等等
調用kset_register,注冊該class(回憶“Linux設備模型(6)_Bus”中的描述,一個class就是一個子系統,因此注冊class也是注冊子系統)。該過程結束后,在/sys/class/目錄下,就會創建對應該class(子系統)的目錄
調用add_class_attrs接口,將class結構中class_attrs指針所指向的attribute,添加到內核中。執行完后,在/sys/class/xxx_class/目錄下,就會看到這些attribute對應的文件
3.3 device注冊時,和class有關的動作
在"Linux設備模型(5)_device和device driver”中,我們有講過struct device和struct device_driver這兩個數據結構,其中struct device結構會包含一個struct class指針(這從側面說明了class是device的集合,甚至,class可以是device的driver)。當某個class driver向內核注冊了一個class后,需要使用該class的device,通過把自身的class指針指向該class即可,剩下的事情,就由內核在注冊device時處理了。
本節,我們講一下在device注冊時,和class有關的動作:
device的注冊最終是由device_add接口(drivers/base/core.c)實現了,該接口中和class有關的動作包括:
調用device_add_class_symlinks接口,創建3.1小節描述的各種符號鏈接,即:在對應class的目錄下,創建指向device的符號鏈接;在device的目錄下,創建名稱為subsystem、指向對應class目錄的符號鏈接
調用device_add_attrs,添加由class指定的attributes(class->dev_attrs)
如果存在對應該class的add_dev回調函數,調用該回調函數
4. 結束語
其實在這篇文章結束后,蝸蝸依舊沒有弄清楚class在內核到底是怎么使用的。不過沒關系,在后續的子系統的分析中(如input子系統、RTC子系統等),我們會看到很多class的使用用例。到時候,再回過頭總結,就會很清楚了。
?
評論
查看更多