原文地址:linux設備驅動歸納總結(八):1.匯流排、設備和驅動
http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=3631833&fromuid=28801784
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
這幾天一直在看設備模型,內核的代碼看得我越來越沮喪,特別是kboject、kset和ktype之間的關係。但是,設備模型的歸納我打算先跳過這幾個重要結構體,先介紹匯流排、設備和驅動——設備管理的相關內容。先介紹如何使用,有機會介紹大概的原理。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
一、sysfs文件系統
設備模型是2.6內核新引入的特徵。設備模型提供了一個獨立的機制專門來表示設備,並描述其在系統中的拓撲結構。
在2.4內核中,設備的信息放在/proc中。
而在2.6內核,內核把設備相關的信息歸類在新增加sysfs文件系統,並將它掛載到/sys目錄中,把設備信息歸類的同時,讓用戶可以通過用戶空間訪問。
接下來簡單介紹一些sys中的目錄:
block:用於管理塊設備,系統中的每一個塊設備會在該目錄下對應一個子目錄。
bus:用於管理匯流排,沒註冊一條匯流排,在該目錄下有一個對應的子目錄。
其中,每個匯流排子目錄下會有兩個子目錄:devices和drivers。
devices包含里系統中所有屬於該匯流排的的設備。
drivers包含里系統中所有屬於該匯流排的的驅動。
class:將系統中的設備按功能分類。
devices:該目錄提供了系統中設備拓撲結構圖。
dev:該目錄已註冊的設備節點的視圖。
kernel:內核中的相關參數。
module:內核中的模塊信息。
fireware:內核中的固件信息。
Fs:描述內核中的文件系統。
上面的目錄,接下來的章節會常常提起bus和device。
再說說這些目錄,來個簡單的命令:
root@xiaobai-laptop:/sys# ll class/net/eth0
lrwxrwxrwx 1 root root 0 2011-01-31 10:11 class/net/eth0 -> ../../devices/pci0000:00/0000:00:1c.5/0000:86:00.0/net/eth0/
上面的命令也可以看到class/net/eth0的路徑其實就是devices目錄中一個網卡設備的軟連接。
貼個書上的圖:
由上面兩個例子看到,sys中的其他目錄都是將devvice目錄下的數據加以轉換加工而得。上面的圖中,將use設備歸類到bus匯流排上,又把它歸類到class。正是在sys中有很多這樣的結構,內核就有一個完整而且複雜的拓撲結構圖。
而維護這些關係的結構體就包括kobject、kset、ktype和subsystem等數據結構,不過這裡就先不介紹。
通過設備模型,內核就能實現多種不同的任務,如:
1、電源管理和系統關機。
2、與用戶空間通信。這個就比較容易理解,sys目錄向用戶展示了設備模型的結構圖。
3、熱插拔設備。大概意思就是,當設備插入後,內核會根據插入的設備安裝驅動,設備拔出後,內核又會自動卸載驅動。
4、設備類型。將設備歸類。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
在接下來的內容會簡單介紹匯流排、設備和驅動程序的概念和函數調用,以下的函數我將模擬創建一條ubs匯流排,一個usb設備和一個usb驅動。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
二、匯流排
匯流排是處理器和設備之間的通道,在設備模型中,所有的設備都通過匯流排相連,以匯流排來管理設備和驅動函數。匯流排有bus_type結構表示。
/*linux/device.h*/
51 struct bus_type {
52 const char *name;
53 struct bus_attribute *bus_attrs;
54 struct device_attribute *dev_attrs;
55 struct driver_attribute *drv_attrs;
56
57 int (*match)(struct device *dev, struct device_driver *drv);
58 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
59 int (*probe)(struct device *dev);
60 int (*remove)(struct device *dev);
61 void (*shutdown)(struct device *dev);
62
63 int (*suspend)(struct device *dev, pm_message_t state);
64 int (*suspend_late)(struct device *dev, pm_message_t state);
65 int (*resume_early)(struct device *dev);
66 int (*resume)(struct device *dev);
67
68 struct dev_pm_ops *pm;
69
70 struct bus_type_private *p;
71 };
紅色部分是以後將會介紹的成員,其中name是匯流排的名字,
bus_attrs是匯流排的屬性,那些函數指針的操作匯流排的方法,在這一章節先不講匯流排的方法。
匯流排的註冊和刪除:
匯流排的註冊有兩個步驟:
1、定義一個bus_type結構體,並設置好需要設置的結構體成員。
2、調用函數bus_register註冊匯流排。函數原型如下:
/*drivers/base/bus.c*/
865 int bus_register(struct bus_type *bus)
該調用有可能失敗,所以必須檢查它的返回值,如果註冊成功,會在/sys/bus下看到指定名字的匯流排。
匯流排刪除時調用:
/*drivers/base/bus.c*/
946 void bus_unregister(struct bus_type *bus)
接下來貼個函數:
/*8th_devModule_1/1st/bus.c*/
1 #include <linux/module.h>
2 #include <linux/init.h>
3
4 #include <linux/device.h>
5
6 struct bus_type usb_bus = {
7 .name = "usb", //定義匯流排的名字為usb,註冊成功後將在/sys/bus目錄下看到
8 }; //目錄usb,如果你的系統已經有usb匯流排,那你就要換個名字。
9
10 static int __init usb_bus_init(void)
11 {
12 int ret;
13 /*匯流排註冊,必須檢測返回值*/
14 ret = bus_register(&usb_bus);
15 if(ret){
16 printk("bus register failed!\n");
17 return ret;
18 }
19
20 printk("usb bus init\n");
21 return 0;
22 }
23
24 static void __exit usb_bus_exit(void)
25 {
26 bus_unregister(&usb_bus);
27 printk("usb bus bye!\n");
28 }
29
30 module_init(usb_bus_init);
31 module_exit(usb_bus_exit);
32
33 MODULE_LICENSE("GPL");
上面的函數可以看到,我僅僅定義了匯流排的名字為usb,其他的都沒有做。看看效果:
[root: 1st]# insmod bus.ko
usb bus init
[root: 1st]# ls /sys/bus/usb/ //sys/bus目錄下多了一個usb的目錄,但是裡面的東西都是空的,
devices drivers_autoprobe uevent //因為我僅僅設置了匯流排的名字
drivers drivers_probe
匯流排屬性添加和刪除:
個人理解,設置匯流排的屬性後,會在對應的匯流排目錄下增加了一個新的文件,通過對該文件的讀寫訪問,觸發相應的函數操作,從而實現/sys/的文件介面與內核設備模型的數據交互。
/*linux/sysfs.h*/
28 struct attribute {
29 const char *name; //設定該文件的名字
30 struct module *owner; //設定該文件的屬主
31 mode_t mode; //設定該文件的文件操作許可權
32 };
/*linux/device.h*/
38 struct bus_attribute {
39 struct attribute attr;
40 ssize_t (*show)(struct bus_type *bus, char *buf);
41 ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
42 };
bus_attribute中有兩個函數指針,show和store。
當訪問匯流排目錄中的name文件時,就會觸發show函數,一般會將指定的信息存放到數組buf,並傳到用戶空間顯示。
當修改匯流排目錄中的name文件是,就會觸發stroe函數,一般會將從用戶空間傳來的buf指針存放的count個位元組內容存放到內核中。
由此可以看到,通過這樣的文件,就能實現sys目錄下的文件與內核設備模型之間的數據交互。
設置匯流排屬性有兩個步驟:
1、創建並初始化bus_attribute結構,使用宏BUS_ATTR
BUS_ATTR(_name, _mode, _show, _store)
該宏會定義一個名叫bus_attr__name(紅色部分是固定的)的bus_attibute的結構,並且成員name設置為_name,文件許可權mode設置為_mode,兩個函數調用分別人show和store。
2、將bus_attibute添加到指定的匯流排上,使用以下調用:
/*/drivers/base/bus.c*/
123 int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
該函數失敗時返回錯誤號。
一旦調用該函數,會就在指定bus匯流排的目錄下新建一個名叫_name的文件,許可權為_mode,當訪問和修改該文件是會分別調用show和store函數調用。
如果不需要該屬性時,使用以下函數刪除:
/*/drivers/base/bus.c*/
135 void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)
說了這麼多,馬上來個程序:
/*8th_devModule_1/2nd/bus.c*/
1 #include <linux/module.h>
2 #include <linux/init.h>
3
4 #include <linux/device.h>
5
6 #define VER_SIZE 100
7
8 struct bus_type usb_bus = {
9 .name = "usb",
10 };
11
12 char Version[VER_SIZE] =
"xiaobai V1.0";
13
14 static ssize_t
show_bus_version(struct bus_type *bus, char *buf)
15 {
16 return snprintf(buf, VER_SIZE, "%s\n", Version);
17 }
18 static ssize_t
store_bus_version(struct bus_type *bus, const char *buf, size_t count)
19 {
20 return snprintf(Version, VER_SIZE, "%s", buf);
21 }
22 /*該宏會定義一個名叫bus_attr_version的bus_attribute的結構,並且成員name設置為
23 * version,文件許可權mode設置為S_IRUGO|S_IWUGO,並設置show函數為
24 * show_bus_version,stror
函數為stroe_bus_version*/
25 static BUS_ATTR(version, S_IRUGO|S_IWUGO, show_bus_version, store_bus_version);
26
27 static int __init usb_bus_init(void)
28 {
29 int ret;
30
31 /*匯流排註冊*/
32 ret = bus_register(&usb_bus);
33 if(ret){
34 printk("bus register failed!\n");
35 goto err1;
36 }
37 /*為匯流排添加屬性,調用成功後在/sys/bus/usb目錄下有一個version的文件,許可權為
38 * S_IRUGO|S_IWUGO,查看該文件時會調用函數show_bus_version,修改時調用store。*/
39 ret = bus_create_file(&usb_bus, &bus_attr_version);
40 if(ret){
41 printk("bus creat file failed!\n");
42 goto err2;
43 }
44 printk("usb bus init\n");
45 return 0;
46
47 err2:
48 bus_unregister(&usb_bus);
49 err1:
50 return ret;
51 }
52
53 static void __exit usb_bus_exit(void)
54 {
55 bus_remove_file(&usb_bus, &bus_attr_version); //不調用這個也可以的,刪除匯流排時會刪除
56 bus_unregister(&usb_bus);
57 printk("usb bus bye!\n");
58 }
驗證一下:
[root: 2nd]# insmod bus.ko
usb bus init
[root: 2nd]# ls /sys/bus/usb/
devices drivers_autoprobe uevent
drivers drivers_probe
version //多了一個version文件
[root: 2nd]# ls -l /sys/bus/usb/version
//文件的許可權的可讀可寫(S_IRUGO|S_IWUGO)
-rw-rw-rw-
1 root root 4096 Oct 27 23:46 /sys/bus/usb/version
[root: 2nd]# cat /sys/bus/usb/version //讀文件時觸發show函數
xiaobai V1.0
[root: 2nd]# echo "haha"> /sys/bus/usb/version //寫文件是觸發store函數
[root: 2nd]# cat /sys/bus/usb/version
haha
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
三、設備
在最底層,linux系統中每個設備都用一個device結構的表示,如下,我省略掉部分成員:
/*linux/device.h*/
369 struct device {
370 struct klist klist_children;
371 struct klist_node knode_parent; /* node in sibling list */
372 struct klist_node knode_driver;
373 struct klist_node knode_bus;
374 struct device *parent; //指定該設備的父設備,如果不指定(NULL),註冊後的設備目錄
375 ///在sys/device下
376 struct kobject kobj;
377 char bus_id[BUS_ID_SIZE]; /* position on parent bus */ //在匯流排生識別設備的字元串,
385 //同時也是設備註冊後的目錄名字。
386 struct bus_type *bus; /* type of bus device is on */ //指定該設備連接的匯流排
387 struct device_driver *driver; /* which driver has allocated this
388 device */ //管理該設備的驅動函數
389 void *driver_data; /* data private to the driver */ //驅動程序的私有數據
392 struct dev_pm_info power;
422 void (*release)(struct device *dev); //當給設備的最後一個引用被刪除時,調用該函數
423 };
在註冊一個完整的device結構前,至少定義parrent、bus_id、bus和release成員。但我接下來的程序僅僅定義了bus_id(指定目錄的名字)、bus(對應的匯流排,不加也行)和release(這是必須的,不然卸載模塊時會出錯,不信自己試試)。
設備註冊和註銷:
與匯流排的註冊一樣:
1、定義結構體device。
2、調用註冊函數:
int device_register(struct device *dev)
函數失敗返回非零,需要判斷返回值來檢查註冊是否成功。
設備註銷函數:
void device_unregister(struct device *dev)
設備屬性:
這個也是和匯流排屬性差不多,不細講:
設備相關的結構體和匯流排的類似,處理指定文件屬性為,還定義了show和store兩個函數。
/*linux/device.h*/
300 struct device_attribute {
301 struct attribute attr;
302 ssize_t (*show)(struct device *dev, struct device_attribute *attr,
303 char *buf);
304 ssize_t (*store)(struct device *dev, struct device_attribute *attr,
305 const char *buf, size_t count);
306 };
設置設備屬性有兩個步驟:
1、創建並初始化device_attribute結構,使用宏DEVICE_ATTR
DEVICE_ATTR(_name, _mode, _show, _store)
該宏會定義一個名叫dev_attr__name(紅色部分是固定的)的device_attibute的結構,並且成員name設置為_name,文件許可權mode設置為_mode,兩個函數調用分別人show和store。
2、將device_attibute添加到指定的設備上,使用以下調用:
/*drivers/base/core.c*/
430 int device_create_file(struct device *dev, struct device_attribute *attr)
該函數失敗時返回錯誤號。
一旦調用該函數,會就在指定dev設備的目錄下新建一個名叫_name的文件,許可權為_mode,當訪問和修改該文件是會分別調用show和store函數調用。
如果不需要該屬性時,使用以下函數刪除:
/*drivers/base/core.c*/
443 void device_remove_file(struct device *dev, struct device_attribute *attr)
講了這麼多,來個函數,和匯流排那個函數差不多,具體功能就是新建了一個執行名字(usb_device)的的設備目錄,並且裡面有一個屬性文件version。
/*8th_devModule_1/3rd/device.c*/
1 #include <linux/module.h>
2 #include <linux/init.h>
3
4 #include <linux/device.h>
5
6 #define VER_SIZE 100
7
8 extern struct bus_type usb_bus;
9
10 void usb_dev_release(struct device *dev)
11 {
12 printk("<kernel> release\n");
13 }
14
15 struct device usb_device = {
16 .bus_id = "usb_device",
17 .bus = &usb_bus, //指定該設備的匯流排,這樣會在sys/bus/usb/device目錄下有一個軟連接
18 .release = usb_dev_release, //必須要都有release函數,不然卸載時會出錯
19 };
11
12 char Version[VER_SIZE] = "xiaobai V1.0";
13
14 static ssize_t
show_device_version(struct device *dev,
15 struct device_attribute *attr, char *buf)
16 {
17 return snprintf(buf, VER_SIZE, "%s\n", Version);
18 }
19 static ssize_t
store_device_version(struct device *dev,
20 struct device_attribute *attr, const char *buf, size_t count)
21 {
22 return snprintf(Version, VER_SIZE, "%s", buf);
23 }
24 /*該宏會定義一個名叫dev_attr_version的device_attribute的結構,並且成員name設置
25 *
為version,文件許可權mode設置為S_IRUGO|S_IWUGO,並設置show函數為
26 *show_device_version,
,stror函數為stroe_device_version*/
27 static DEVICE_ATTR(version, S_IRUGO|S_IWUGO,
28 show_device_version, store_device_version);
29
30 static int __init usb_device_init(void)
31 {
32 int ret;
33
34 /*設備註冊,註冊成功後在/sys/device目錄下創建目錄usb_device*/
35 ret = device_register(&usb_device);
36 if(ret){
37 printk("device register failed!\n");
38 goto err1;
39 }
40 /*為設備添加屬性,調用成功後在/sys/device/usb_device/目錄下有一個version的
41 * 文件,許可權為S_IRUGO|S_IWUGO,查看該文件時會調用函數show_device_version,
42 * 修改時調用store_device_version。*/
43 ret = device_create_file(&usb_device, &dev_attr_version);
44 if(ret){
45 printk("device creat file failed!\n");
46 goto err2;
47 }
48 printk("usb device init\n");
49 return 0;
50
51 err2:
52 device_unregister(&usb_device);
53 err1:
54 return ret;
55 }
56
57 static void __exit usb_device_exit(void)
58 {
59 device_remove_file(&usb_device, &dev_attr_version);
60 device_unregister(&usb_device);
61 printk("usb device bye!\n");
62 }
63
64 module_init(usb_device_init);
65 module_exit(usb_device_exit);
再看看效果,這是沒有設置匯流排(bus = &usb_bus)時的效果,代碼在8th_devModule_1/3rd/device_bak.c,我沒有編譯,如果需要的話自己編譯運行看看:
[root: 3rd]# insmod device.ko
usb device init
[root: /]# find -name "usb_device" //註冊後查找一下在哪裡有以設備bus_id為名字的目錄
./sys/devices/usb_device ///sys/device下有一個
[root: /]#
[root: /]# ls /sys/devices/usb_device/ //裡面有一個空文件,一個屬性文件version
uevent version
[root: /]# cat /sys/devices/usb_device/version //查看一下version,調用shoe函數
xiaobai V1.0
[root: /]# echo "haha" > /sys/devices/usb_device/version //修改version,調用store函數
[root: /]# cat /sys/devices/usb_device/version
haha
下面的是程序8th_devModule_1/3rd/device.c的效果:
[root: /]# cd review_driver/8th_devModule/8th_devModule_1/3rd/
[root: 3rd]# insmod bus.ko //先載入匯流排的模塊
usb bus init
[root: 3rd]# insmod device.ko //再載入設備的模塊
usb device init
[root: 3rd]# cd /
[root: /]# find -name "usb_device" //查找一下usb_device,發現比沒有指定匯流排時多了一個路徑
./sys/devices/usb_device //這個目錄的出現是因為語句(.bus = &usb_bus,)
./sys/bus/usb/devices/usb_device //這個目錄的出現是因為語句(device_register(&usb_device);)
[root: /]# cat /sys/devices/usb_device/version
xiaobai V1.0
[root: /]# ls -l sys/bus/usb/devices //原來該路徑只是一個軟連接,是該設備歸類到usb_bus匯流排下
lrwxrwxrwx 1 root root 0 Oct 27 13:49 usb_device -> ../../../devices/usb_device
[root: /]# rmmod device
<kernel> release //下載時調用release函數調用,如果沒有設置release,卸載時會出錯。
usb device bye!
[root: /]# rmmod bus
usb bus bye!
[root: /]#
上面的驗證需要先載入bus.ko,bus.c源程序和1st/bus.c的函數沒什麼區別,只是將usb_bus導出到符號表。不然的話,載入模塊時不能找到對應的匯流排。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
四、驅動程序
設備模型跟蹤所有系統所知道的設備。進行跟蹤的主要原因是讓驅動程序協調與設備之間的關係。
先看驅動程序的結構體,我僅僅貼出一些重要的成員:
/*linux/device.h*/
122 struct device_driver {
123 const char *name; //驅動函數的名字,在對應匯流排的driver目錄下顯示
124 struct bus_type *bus; //指定該驅動程序所操作的匯流排類型,必須設置,不然會註冊失敗
125
126 struct module *owner;
127 const char *mod_name; /* used for built-in modules */
128
129 int (*probe) (struct device *dev); //探測函數,以後會講
130 int (*remove) (struct device *dev); //卸載函數,當設備從系統中刪除時調用,以後講
131 void (*shutdown) (struct device *dev); //當系統關機是調用
132 int (*suspend) (struct device *dev, pm_message_t state);
133 int (*resume) (struct device *dev);
134 struct attribute_group **groups;
135
136 struct dev_pm_ops *pm;
137
138 struct driver_private *p;
139 };
和設備不一樣的是,在註冊驅動函數是必須指定該驅動函數對應的匯流排,因為驅動函數註冊成功後,會存放在對應匯流排的driver目錄下,如果沒有匯流排,註冊當然會失敗。
與匯流排的註冊一樣:
1、定義結構體device_driver。
2、調用註冊函數:
214 int driver_register(struct device_driver *drv)
函數失敗返回非零,需要判斷返回值來檢查註冊是否成功。
設備註銷函數:
249 void driver_unregister(struct device_driver *drv)
驅動函數屬性:
這個也是和匯流排屬性差不多,不細講:
驅動函數相關的結構體和匯流排的類似,處理指定文件屬性為,還定義了show和store兩個函數。
155 struct driver_attribute {
156 struct attribute attr;
157 ssize_t (*show)(struct device_driver *driver, char *buf);
158 ssize_t (*store)(struct device_driver *driver, const char *buf,
159 size_t count);
160 };
設置設備屬性有兩個步驟:
1、創建並初始化device_attribute結構,使用宏DEVICE_ATTR
DRIVER_ATTR(_name, _mode, _show, _store)
該宏會定義一個名叫driver_attr__name(紅色部分是固定的)的driver_attibute的結構,並且成員name設置為_name,文件許可權mode設置為_mode,兩個函數調用分別人show和store。
2、將device_attibute添加到指定的驅動函數上,使用以下調用:
/*drivers/base/driver.c*/
93 int driver_create_file(struct device_driver *drv, struct driver_attribute *attr)
該函數失敗時返回錯誤號。
一旦調用該函數,會就在指定dev設備的目錄下新建一個名叫_name的文件,許可權為_mode,當訪問和修改該文件是會分別調用show和store函數調用。
如果不需要該屬性時,使用以下函數刪除:
/*drivers/base/driver.c*/
110 void driver_remove_file(struct device_driver *drv, struct driver_attribute *attr)
貼上函數:
/*8th_devModule_1/4th/driver.c*/
1 #include <linux/module.h>
2 #include <linux/init.h>
3
4 #include <linux/device.h>
5
6 #define VER_SIZE 100
7
8 extern struct bus_type usb_bus;
9
10 struct device_driver usb_driver = {
11 .name = "usb_driver",
12 .bus = &usb_bus,
13 };
14
15 char Version[VER_SIZE] = "xiaobai V1.0";
16
17 static ssize_t
show_driver_version(struct device_driver *drv, char *buf)
18 {
19 return snprintf(buf, VER_SIZE, "%s\n", Version);
20 }
21 static ssize_t
store_driver_version(struct device_driver *drv,
22 const char *buf, size_t count)
23 {
24 return snprintf(Version, VER_SIZE, "%s", buf);
25 }
26 /*該宏會定義一個名叫driver_attr_version的driver_attribute的結構,並且成員
27 * name設置為version,文件許可權mode設置為S_IRUGO|S_IWUGO,並設置show函數為
28 * show_driver_version,stror函數為stroe_driver_version*/
29 static DRIVER_ATTR(version, S_IRUGO|S_IWUGO,
30 show_driver_version, store_driver_version);
31
32 static int __init usb_driver_init(void)
33 {
34 int ret;
35
36 /*驅動註冊,註冊成功後在/sys/bus/usb/driver目錄下創建目錄usb_driver*/
37 ret = driver_register(&usb_driver);
38 if(ret){
39 printk("driver register failed!\n");
40 goto err1;
41 }
42 /*為驅動添加屬性,調用成功後在/sys/bus/usb/dirver目錄下有一個version的
43 * 文件,許可權為S_IRUGO|S_IWUGO,查看該文件時會調用函數show_driver_version,修改時
44 * 調用store_driver_version。*/
45 ret = driver_create_file(&usb_driver, &driver_attr_version);
46 if(ret){
47 printk("driver creat file failed!\n");
48 goto err2;
49 }
50 printk("usb driver init\n");
51 return 0;
52
53 err2:
54 driver_unregister(&usb_driver);
55 err1:
56 return ret;
57 }
58
59 static void __exit usb_driver_exit(void)
60 {
61 driver_remove_file(&usb_driver, &driver_attr_version);
62 driver_unregister(&usb_driver);
63 printk("usb driver bye!\n");
64 }
看看效果,同樣必須先載入bus.ko:
[root: /]# cd review_driver/8th_devModule/8th_devModule_1/4th/
[root: 4th]# insmod bus.ko //必須先載入匯流排
usb bus init
[root: 4th]# insmod driver.ko
usb driver init
[root: 4th]# cd /
[root: /]# find -name "usb_driver" //只有一處創建了usb_driver目錄
./sys/bus/usb/drivers/usb_driver
[root: /]# ls /sys/bus/usb/drivers/usb_driver/
bind uevent unbind version
[root: /]# cat /sys/bus/usb/drivers/usb_driver/version //訪問version文件是觸發show函數
xiaobai V1.0
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
五、總結
這節講得內容其實不多,歸納起來就是四個函數一個屬性結構體。
屬性結構體:xx_attribute。
註冊函數:xx_register。
註銷函數:xx+unregister。
創建屬性文件函數:xx_create_file。
刪除屬性文件函數:xx_remove_file。
其中xx可以是匯流排(bus)、設備(device)或者驅動函數(deriver)。
一但註冊成功,就會在/sys目錄下相應的地方創建一個自己命名的目錄。其中,設備和驅動函數還可以添加到指定的bus目錄下。
匯流排的成功註冊後會在/sys/bus目錄下創建相應的目錄。
設備的成功註冊後會在/sys/device目錄下創建相應的目錄,如果指定匯流排,會在指定匯流排目錄/sys/bus/xx/device下創建一個指向/sys/device目錄的軟連接。
驅動函數的公共註冊會在/sys/bus/xx/driver目錄下創建相應的目錄。
屬性文件提供了shoe和store兩個函數調用,當讀寫文件時會觸發相應的函數調用,實現內核sysfs與用戶空間的數據交互。
三者具體的關係就在後面章節介紹。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx