1. 概述
在設(shè)備模型中,Bus、Device、Device driver等等,都比較好理解,因?yàn)樗鼈儗?duì)應(yīng)了實(shí)實(shí)在在的東西,所有的邏輯都是圍繞著這些實(shí)體展開的。而本文所要描述的Class就有些不同了,因?yàn)樗翘摂M出來的,只是為了抽象設(shè)備的共性。
舉個(gè)例子,一些年齡相仿、需要獲取的知識(shí)相似的人,聚在一起學(xué)習(xí),就構(gòu)成了一個(gè)班級(jí)(Class)。這個(gè)班級(jí)可以有自己的名稱(如295),但如果離開構(gòu)成它的學(xué)生(device),它就沒有任何存在意義。另外,班級(jí)存在的最大意義是什么呢?是由老師講授的每一個(gè)課程!因?yàn)槔蠋熤恍枰v一遍,一個(gè)班的學(xué)生都可以聽到。不然的話(例如每個(gè)學(xué)生都在家學(xué)習(xí)),就要為每人請(qǐng)一個(gè)老師,講授一遍。而講的內(nèi)容,大多是一樣的,這就是極大的浪費(fèi)。
設(shè)備模型中的Class所提供的功能也一樣了,例如一些相似的device(學(xué)生),需要向用戶空間提供相似的接口(課程),如果每個(gè)設(shè)備的驅(qū)動(dòng)都實(shí)現(xiàn)一遍的話,就會(huì)導(dǎo)致內(nèi)核有大量的冗余代碼,這就是極大的浪費(fèi)。所以,Class說了,我?guī)湍銈儗?shí)現(xiàn)吧,你們會(huì)用就行了。
這就是設(shè)備模型中Class的功能,再結(jié)合內(nèi)核的注釋:A class is a higher-level view of a device that abstracts out low-level implementation details(include/linux/device.h line326),就容易理解了。
2. 數(shù)據(jù)結(jié)構(gòu)描述
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: };
其實(shí)struct class和struct bus很類似,解釋如下:
name,class的名稱,會(huì)在“/sys/class/”目錄下體現(xiàn)。
class_atrrs,該class的默認(rèn)attribute,會(huì)在class注冊(cè)到內(nèi)核時(shí),自動(dòng)在“/sys/class/xxx_class”下創(chuàng)建對(duì)應(yīng)的attribute文件。
dev_attrs,該class下每個(gè)設(shè)備的attribute,會(huì)在設(shè)備注冊(cè)到內(nèi)核時(shí),自動(dòng)在該設(shè)備的sysfs目錄下創(chuàng)建對(duì)應(yīng)的attribute文件。
dev_bin_attrs,類似dev_attrs,只不過是二進(jìn)制類型attribute。
dev_kobj,表示該class下的設(shè)備在/sys/dev/下的目錄,現(xiàn)在一般有char和block兩個(gè),如果dev_kobj為NULL,則默認(rèn)選擇char。
dev_uevent,當(dāng)該class下有設(shè)備發(fā)生變化時(shí),會(huì)調(diào)用class的uevent回調(diào)函數(shù)。
class_release,用于release自身的回調(diào)函數(shù)。
dev_release,用于release class內(nèi)設(shè)備的回調(diào)函數(shù)。在device_release接口中,會(huì)依次檢查Device、Device Type以及Device所在的class,是否注冊(cè)release接口,如果有則調(diào)用相應(yīng)的release接口release設(shè)備指針。
p,和“Linux設(shè)備模型(6)_Bus”中struct bus結(jié)構(gòu)一樣,不再說明。
2.2 struct class_interface
struct class_interface是這樣的一個(gè)結(jié)構(gòu):它允許class driver在class下有設(shè)備添加或移除的時(shí)候,調(diào)用預(yù)先設(shè)置好的回調(diào)函數(shù)(add_dev和remove_dev)。那調(diào)用它們做什么呢?想做什么都行(例如修改設(shè)備的名稱),由具體的class driver實(shí)現(xiàn)。
該結(jié)構(gòu)的定義如下:
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. 功能及內(nèi)部邏輯解析
3.1 class的功能
看完上面的東西,蝸蝸依舊糊里糊涂的,class到底提供了什么功能?怎么使用呢?讓我們先看一下現(xiàn)有Linux系統(tǒng)中有關(guān)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
看上面的例子,發(fā)現(xiàn)input class也沒做什么實(shí)實(shí)在在的事兒,它(input class)的功能,僅僅是:
在/sys/class/目錄下,創(chuàng)建一個(gè)本class的目錄(input)
在本目錄下,創(chuàng)建每一個(gè)屬于該class的設(shè)備的符號(hào)鏈接(如,把“sys/devices/platform/s3c2440-i2c.3/i2c-3/3-0048/input/input2/event2”設(shè)備鏈接到”/sys/class/input/event2”),這樣就可以在本class目錄下,訪問該設(shè)備的所有特性(即attribute)
另外,device在sysfs的目錄下,也會(huì)創(chuàng)建一個(gè)subsystem的符號(hào)鏈接,鏈接到本class的目錄
算了,我們還是先分析一下Class的核心邏輯都做了哪些事情,至于class到底有什么用處,可以在后續(xù)具體的子系統(tǒng)里面(如input子系統(tǒng)),更為細(xì)致的探討。
3.2 class的注冊(cè)
class的注冊(cè),是由__class_register接口(它的實(shí)現(xiàn)位于"drivers/base/class.c, line 609")實(shí)現(xiàn)的,它的處理邏輯和bus的注冊(cè)類似,主要包括:
為class結(jié)構(gòu)中的struct subsys_private類型的指針(cp)分配空間,并初始化其中的字段,包括cp->subsys.kobj.kset、cp->subsys.kobj.ktype等等
調(diào)用kset_register,注冊(cè)該class(回憶“Linux設(shè)備模型(6)_Bus”中的描述,一個(gè)class就是一個(gè)子系統(tǒng),因此注冊(cè)class也是注冊(cè)子系統(tǒng))。該過程結(jié)束后,在/sys/class/目錄下,就會(huì)創(chuàng)建對(duì)應(yīng)該class(子系統(tǒng))的目錄
調(diào)用add_class_attrs接口,將class結(jié)構(gòu)中class_attrs指針?biāo)赶虻腶ttribute,添加到內(nèi)核中。執(zhí)行完后,在/sys/class/xxx_class/目錄下,就會(huì)看到這些attribute對(duì)應(yīng)的文件
3.3 device注冊(cè)時(shí),和class有關(guān)的動(dòng)作
在"Linux設(shè)備模型(5)_device和device driver”中,我們有講過struct device和struct device_driver這兩個(gè)數(shù)據(jù)結(jié)構(gòu),其中struct device結(jié)構(gòu)會(huì)包含一個(gè)struct class指針(這從側(cè)面說明了class是device的集合,甚至,class可以是device的driver)。當(dāng)某個(gè)class driver向內(nèi)核注冊(cè)了一個(gè)class后,需要使用該class的device,通過把自身的class指針指向該class即可,剩下的事情,就由內(nèi)核在注冊(cè)device時(shí)處理了。
本節(jié),我們講一下在device注冊(cè)時(shí),和class有關(guān)的動(dòng)作:
device的注冊(cè)最終是由device_add接口(drivers/base/core.c)實(shí)現(xiàn)了,該接口中和class有關(guān)的動(dòng)作包括:
調(diào)用device_add_class_symlinks接口,創(chuàng)建3.1小節(jié)描述的各種符號(hào)鏈接,即:在對(duì)應(yīng)class的目錄下,創(chuàng)建指向device的符號(hào)鏈接;在device的目錄下,創(chuàng)建名稱為subsystem、指向?qū)?yīng)class目錄的符號(hào)鏈接
調(diào)用device_add_attrs,添加由class指定的attributes(class->dev_attrs)
如果存在對(duì)應(yīng)該class的add_dev回調(diào)函數(shù),調(diào)用該回調(diào)函數(shù)
4. 結(jié)束語
其實(shí)在這篇文章結(jié)束后,蝸蝸依舊沒有弄清楚class在內(nèi)核到底是怎么使用的。不過沒關(guān)系,在后續(xù)的子系統(tǒng)的分析中(如input子系統(tǒng)、RTC子系統(tǒng)等),我們會(huì)看到很多class的使用用例。到時(shí)候,再回過頭總結(jié),就會(huì)很清楚了。
?
評(píng)論
查看更多