現在的位置: 首頁 > 綜合 > 正文

linux設備驅動歸納總結(八):1.匯流排、設備和驅動

2018年03月16日 ⁄ 綜合 ⁄ 共 15626字 ⁄ 字型大小 評論關閉

原文地址: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中有兩個函數指針,showstore

當訪問匯流排目錄中的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,兩個函數調用分別人showstore

2、將bus_attibute添加到指定的匯流排上,使用以下調用:

/*/drivers/base/bus.c*/

123 int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)

該函數失敗時返回錯誤號。

一旦調用該函數,會就在指定bus匯流排的目錄下新建一個名叫_name的文件,許可權為_mode,當訪問和修改該文件是會分別調用showstore函數調用。

如果不需要該屬性時,使用以下函數刪除:

/*/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_versionbus_attribute的結構,並且成員name設置為

23 * version,文件許可權mode設置為S_IRUGO|S_IWUGO,並設置show函數為

24 * show_bus_versionstror
函數為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結構前,至少定義parrentbus_idbusrelease成員。但我接下來的程序僅僅定義了bus_id(指定目錄的名字)、bus(對應的匯流排,不加也行)和release(這是必須的,不然卸載模塊時會出錯,不信自己試試)。

設備註冊和註銷:

與匯流排的註冊一樣:

1、定義結構體device

2、調用註冊函數:

int device_register(struct device *dev)

函數失敗返回非零,需要判斷返回值來檢查註冊是否成功。

設備註銷函數:

void device_unregister(struct device *dev)

設備屬性:

這個也是和匯流排屬性差不多,不細講:

設備相關的結構體和匯流排的類似,處理指定文件屬性為,還定義了showstore兩個函數。

/*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,兩個函數調用分別人showstore

2、將device_attibute添加到指定的設備上,使用以下調用:

/*drivers/base/core.c*/

430 int device_create_file(struct device *dev, struct device_attribute *attr)

該函數失敗時返回錯誤號。

一旦調用該函數,會就在指定dev設備的目錄下新建一個名叫_name的文件,許可權為_mode,當訪問和修改該文件是會分別調用showstore函數調用。

如果不需要該屬性時,使用以下函數刪除:

/*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_versiondevice_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.kobus.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)

驅動函數屬性:

這個也是和匯流排屬性差不多,不細講:

驅動函數相關的結構體和匯流排的類似,處理指定文件屬性為,還定義了showstore兩個函數。

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,兩個函數調用分別人showstore

2、將device_attibute添加到指定的驅動函數上,使用以下調用:

/*drivers/base/driver.c*/

93 int driver_create_file(struct device_driver *drv, struct driver_attribute *attr)

該函數失敗時返回錯誤號。

一旦調用該函數,會就在指定dev設備的目錄下新建一個名叫_name的文件,許可權為_mode,當訪問和修改該文件是會分別調用showstore函數調用。

如果不需要該屬性時,使用以下函數刪除:

/*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_versiondriver_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目錄下創建相應的目錄。

屬性文件提供了shoestore兩個函數調用,當讀寫文件時會觸發相應的函數調用,實現內核sysfs與用戶空間的數據交互。

三者具體的關係就在後面章節介紹。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

抱歉!評論已關閉.