亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 2406 | 回復(fù): 1
打印 上一主題 下一主題

linux設(shè)備驅(qū)動歸納總結(jié)(八):1.總線、設(shè)備和驅(qū)動 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2011-02-01 20:12 |只看該作者 |倒序瀏覽
linux設(shè)備驅(qū)動歸納總結(jié)(八):1.總線、設(shè)備和驅(qū)動


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

這幾天一直在看設(shè)備模型,內(nèi)核的代碼看得我越來越沮喪,特別是kboject、ksetktype之間的關(guān)系。但是,設(shè)備模型的歸納我打算先跳過這幾個重要結(jié)構(gòu)體,先介紹總線、設(shè)備和驅(qū)動——設(shè)備管理的相關(guān)內(nèi)容。先介紹如何使用,有機會介紹大概的原理。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


一、sysfs文件系統(tǒng)


設(shè)備模型是2.6內(nèi)核新引入的特征。設(shè)備模型提供了一個獨立的機制專門來表示設(shè)備,并描述其在系統(tǒng)中的拓撲結(jié)構(gòu)。

2.4內(nèi)核中,設(shè)備的信息放在/proc中。

而在2.6內(nèi)核,內(nèi)核把設(shè)備相關(guān)的信息歸類在新增加sysfs文件系統(tǒng),并將它掛載到/sys目錄中,把設(shè)備信息歸類的同時,讓用戶可以通過用戶空間訪問。


接下來簡單介紹一些sys中的目錄:

block:用于管理塊設(shè)備,系統(tǒng)中的每一個塊設(shè)備會在該目錄下對應(yīng)一個子目錄。

bus:用于管理總線,沒注冊一條總線,在該目錄下有一個對應(yīng)的子目錄。

其中,每個總線子目錄下會有兩個子目錄:devicesdrivers。

devices包含里系統(tǒng)中所有屬于該總線的的設(shè)備。

drivers包含里系統(tǒng)中所有屬于該總線的的驅(qū)動。

class:將系統(tǒng)中的設(shè)備按功能分類。

devices:該目錄提供了系統(tǒng)中設(shè)備拓撲結(jié)構(gòu)圖。

dev:該目錄已注冊的設(shè)備節(jié)點的視圖。

kernel:內(nèi)核中的相關(guān)參數(shù)。

module:內(nèi)核中的模塊信息。

fireware:內(nèi)核中的固件信息。

Fs:描述內(nèi)核中的文件系統(tǒng)。

上面的目錄,接下來的章節(jié)會常常提起busdevice。


再說說這些目錄,來個簡單的命令:

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目錄中一個網(wǎng)卡設(shè)備的軟連接。


貼個書上的圖:

由上面兩個例子看到,sys中的其他目錄都是將devvice目錄下的數(shù)據(jù)加以轉(zhuǎn)換加工而得。上面的圖中,將use設(shè)備歸類到bus總線上,又把它歸類到class。正是在sys中有很多這樣的結(jié)構(gòu),內(nèi)核就有一個完整而且復(fù)雜的拓撲結(jié)構(gòu)圖。

而維護這些關(guān)系的結(jié)構(gòu)體就包括kobject、ksetktypesubsystem等數(shù)據(jù)結(jié)構(gòu),不過這里就先不介紹。

通過設(shè)備模型,內(nèi)核就能實現(xiàn)多種不同的任務(wù),如:

1、電源管理和系統(tǒng)關(guān)機。

2、與用戶空間通信。這個就比較容易理解,sys目錄向用戶展示了設(shè)備模型的結(jié)構(gòu)圖。

3、熱插拔設(shè)備。大概意思就是,當設(shè)備插入后,內(nèi)核會根據(jù)插入的設(shè)備安裝驅(qū)動,設(shè)備拔出后,內(nèi)核又會自動卸載驅(qū)動。

4、設(shè)備類型。將設(shè)備歸類。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

在接下來的內(nèi)容會簡單介紹總線、設(shè)備和驅(qū)動程序的概念和函數(shù)調(diào)用,以下的函數(shù)我將模擬創(chuàng)建一條ubs總線,一個usb設(shè)備和一個usb驅(qū)動。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


二、總線


總線是處理器和設(shè)備之間的通道,在設(shè)備模型中,所有的設(shè)備都通過總線相連,以總線來管理設(shè)備和驅(qū)動函數(shù)?偩有bus_type結(jié)構(gòu)表示。

/*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是總線的屬性,那些函數(shù)指針的操作總線的方法,在這一章節(jié)先不講總線的方法。


總線的注冊和刪除:

總線的注冊有兩個步驟:

1、定義一個bus_type結(jié)構(gòu)體,并設(shè)置好需要設(shè)置的結(jié)構(gòu)體成員。

2、調(diào)用函數(shù)bus_register注冊總線。函數(shù)原型如下:

/*drivers/base/bus.c*/

865 int bus_register(struct bus_type *bus)

該調(diào)用有可能失敗,所以必須檢查它的返回值,如果注冊成功,會在/sys/bus下看到指定名字的總線。


總線刪除時調(diào)用:

/*drivers/base/bus.c*/

946 void bus_unregister(struct bus_type *bus)


接下來貼個函數(shù):

/*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,如果你的系統(tǒng)已經(jīng)有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");

上面的函數(shù)可以看到,我僅僅定義了總線的名字為usb,其他的都沒有做?纯葱Ч

[root: 1st]# insmod bus.ko

usb bus init

[root: 1st]# ls /sys/bus/usb/ //sys/bus目錄下多了一個usb的目錄,但是里面的東西都是空的,

devices drivers_autoprobe uevent //因為我僅僅設(shè)置了總線的名字

drivers drivers_probe


總線屬性添加和刪除:

個人理解,設(shè)置總線的屬性后,會在對應(yīng)的總線目錄下增加了一個新的文件,通過對該文件的讀寫訪問,觸發(fā)相應(yīng)的函數(shù)操作,從而實現(xiàn)/sys/的文件接口與內(nèi)核設(shè)備模型的數(shù)據(jù)交互

/*linux/sysfs.h*/

28 struct attribute {

29 const char *name; //設(shè)定該文件的名字

30 struct module *owner; //設(shè)定該文件的屬主

31 mode_t mode; //設(shè)定該文件的文件操作權(quán)限

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中有兩個函數(shù)指針,showstore

當訪問總線目錄中的name文件時,就會觸發(fā)show函數(shù),一般會將指定的信息存放到數(shù)組buf,并傳到用戶空間顯示。

當修改總線目錄中的name文件是,就會觸發(fā)stroe函數(shù),一般會將從用戶空間傳來的buf指針存放的count個字節(jié)內(nèi)容存放到內(nèi)核中。

由此可以看到,通過這樣的文件,就能實現(xiàn)sys目錄下的文件與內(nèi)核設(shè)備模型之間的數(shù)據(jù)交互。


設(shè)置總線屬性有兩個步驟:

1、創(chuàng)建并初始化bus_attribute結(jié)構(gòu),使用宏BUS_ATTR

BUS_ATTR(_name, _mode, _show, _store)

該宏會定義一個名叫bus_attr__name(紅色部分是固定的)的bus_attibute的結(jié)構(gòu),并且成員name設(shè)置為_name,文件權(quán)限mode設(shè)置為_mode,兩個函數(shù)調(diào)用分別人showstore。

2、將bus_attibute添加到指定的總線上,使用以下調(diào)用:

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

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

該函數(shù)失敗時返回錯誤號。

一旦調(diào)用該函數(shù),會就在指定bus總線的目錄下新建一個名叫_name的文件,權(quán)限為_mode,當訪問和修改該文件是會分別調(diào)用showstore函數(shù)調(diào)用。


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

/*/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的結(jié)構(gòu),并且成員name設(shè)置為

23 * version,文件權(quán)限mode設(shè)置為S_IRUGO|S_IWUGO,并設(shè)置show函數(shù)為

24 * show_bus_version,stror 函數(shù)為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 /*為總線添加屬性,調(diào)用成功后在/sys/bus/usb目錄下有一個version的文件,權(quán)限為

38 * S_IRUGO|S_IWUGO,查看該文件時會調(diào)用函數(shù)show_bus_version,修改時調(diào)用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); //不調(diào)用這個也可以的,刪除總線時會刪除

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 //文件的權(quán)限的可讀可寫(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 //讀文件時觸發(fā)show函數(shù)

xiaobai V1.0

[root: 2nd]# echo "haha"> /sys/bus/usb/version //寫文件是觸發(fā)store函數(shù)

[root: 2nd]# cat /sys/bus/usb/version

haha


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


三、設(shè)備


在最底層,linux系統(tǒng)中每個設(shè)備都用一個device結(jié)構(gòu)的表示,如下,我省略掉部分成員:

/*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; //指定該設(shè)備的父設(shè)備,如果不指定(NULL),注冊后的設(shè)備目錄

375 ///sys/device

376 struct kobject kobj;

377 char bus_id[BUS_ID_SIZE]; /* position on parent bus */ //在總線生識別設(shè)備的字符串,

385 //同時也是設(shè)備注冊后的目錄名字。

386 struct bus_type *bus; /* type of bus device is on */ //指定該設(shè)備連接的總線

387 struct device_driver *driver; /* which driver has allocated this

388 device */ //管理該設(shè)備的驅(qū)動函數(shù)

389 void *driver_data; /* data private to the driver */ //驅(qū)動程序的私有數(shù)據(jù)

392 struct dev_pm_info power;

422 void (*release)(struct device *dev); //當給設(shè)備的最后一個引用被刪除時,調(diào)用該函數(shù)

423 };

注冊一個完整的device結(jié)構(gòu)前,至少定義parrentbus_id、busrelease成員。但我接下來的程序僅僅定義了bus_id(指定目錄的名字)、bus(對應(yīng)的總線,不加也行)和release(這是必須的,不然卸載模塊時會出錯,不信自己試試)。


設(shè)備注冊和注銷:


與總線的注冊一樣:

1、定義結(jié)構(gòu)體device。

2、調(diào)用注冊函數(shù):

int device_register(struct device *dev)

函數(shù)失敗返回非零,需要判斷返回值來檢查注冊是否成功。


設(shè)備注銷函數(shù):

void device_unregister(struct device *dev)


設(shè)備屬性:


這個也是和總線屬性差不多,不細講:

設(shè)備相關(guān)的結(jié)構(gòu)體和總線的類似,處理指定文件屬性為,還定義了showstore兩個函數(shù)。

/*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 };


設(shè)置設(shè)備屬性有兩個步驟:

1、創(chuàng)建并初始化device_attribute結(jié)構(gòu),使用宏DEVICE_ATTR

DEVICE_ATTR(_name, _mode, _show, _store)

該宏會定義一個名叫dev_attr__name(紅色部分是固定的)的device_attibute的結(jié)構(gòu),并且成員name設(shè)置為_name,文件權(quán)限mode設(shè)置為_mode,兩個函數(shù)調(diào)用分別人showstore。

2、將device_attibute添加到指定的設(shè)備上,使用以下調(diào)用:

/*drivers/base/core.c*/

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

該函數(shù)失敗時返回錯誤號。

一旦調(diào)用該函數(shù),會就在指定dev設(shè)備的目錄下新建一個名叫_name的文件,權(quán)限為_mode,當訪問和修改該文件是會分別調(diào)用showstore函數(shù)調(diào)用。


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

/*drivers/base/core.c*/

443 void device_remove_file(struct device *dev, struct device_attribute *attr)


講了這么多,來個函數(shù),和總線那個函數(shù)差不多,具體功能就是新建了一個執(zhí)行名字(usb_device)的的設(shè)備目錄,并且里面有一個屬性文件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, //指定該設(shè)備的總線,這樣會在sys/bus/usb/device目錄下有一個軟連接

18 .release = usb_dev_release, //必須要都有release函數(shù),不然卸載時會出錯

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的結(jié)構(gòu),并且成員name設(shè)置

25 * version,文件權(quán)限mode設(shè)置為S_IRUGO|S_IWUGO,并設(shè)置show函數(shù)為

26 *show_device_version, ,stror函數(shù)為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 /*設(shè)備注冊,注冊成功后在/sys/device目錄下創(chuàng)建目錄usb_device*/

35 ret = device_register(&usb_device);

36 if(ret){

37 printk("device register failed!\n");

38 goto err1;

39 }

40 /*為設(shè)備添加屬性,調(diào)用成功后在/sys/device/usb_device/目錄下有一個version

41 * 文件,權(quán)限為S_IRUGO|S_IWUGO,查看該文件時會調(diào)用函數(shù)show_device_version,

42 * 修改時調(diào)用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);

再看看效果,這是沒有設(shè)置總線(bus = &usb_bus)時的效果,代碼在8th_devModule_1/3rd/device_bak.c,我沒有編譯,如果需要的話自己編譯運行看看

[root: 3rd]# insmod device.ko

usb device init

[root: /]# find -name "usb_device" //注冊后查找一下在哪里有以設(shè)備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,調(diào)用shoe函數(shù)

xiaobai V1.0

[root: /]# echo "haha" > /sys/devices/usb_device/version //修改version,調(diào)用store函數(shù)

[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 //再加載設(shè)備的模塊

usb device init

[root: 3rd]# cd /

[root: /]# find -name "usb_device" //查找一下usb_device,發(fā)現(xiàn)比沒有指定總線時多了一個路徑

./sys/devices/usb_device //這個目錄的出現(xiàn)是因為語句(.bus = &usb_bus,

./sys/bus/usb/devices/usb_device //這個目錄的出現(xiàn)是因為語句(device_register(&usb_device);

[root: /]# cat /sys/devices/usb_device/version

xiaobai V1.0

[root: /]# ls -l sys/bus/usb/devices //原來該路徑只是一個軟連接,是該設(shè)備歸類到usb_bus總線下

lrwxrwxrwx 1 root root 0 Oct 27 13:49 usb_device -> ../../../devices/usb_device

[root: /]# rmmod device

<kernel> release //下載時調(diào)用release函數(shù)調(diào)用,如果沒有設(shè)置release,卸載時會出錯。

usb device bye!

[root: /]# rmmod bus

usb bus bye!

[root: /]#

上面的驗證需要先加載bus.kobus.c源程序和1st/bus.c的函數(shù)沒什么區(qū)別,只是將usb_bus導(dǎo)出到符號表。不然的話,加載模塊時不能找到對應(yīng)的總線。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


四、驅(qū)動程序


設(shè)備模型跟蹤所有系統(tǒng)所知道的設(shè)備。進行跟蹤的主要原因是讓驅(qū)動程序協(xié)調(diào)與設(shè)備之間的關(guān)系。

先看驅(qū)動程序的結(jié)構(gòu)體,我僅僅貼出一些重要的成員:

/*linux/device.h*/

122 struct device_driver {

123 const char *name; //驅(qū)動函數(shù)的名字,在對應(yīng)總線的driver目錄下顯示

124 struct bus_type *bus; //指定該驅(qū)動程序所操作的總線類型,必須設(shè)置,不然會注冊失敗

125

126 struct module *owner;

127 const char *mod_name; /* used for built-in modules */

128

129 int (*probe) (struct device *dev); //探測函數(shù),以后會講

130 int (*remove) (struct device *dev); //卸載函數(shù),當設(shè)備從系統(tǒng)中刪除時調(diào)用,以后講

131 void (*shutdown) (struct device *dev); //當系統(tǒng)關(guān)機是調(diào)用

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 };

和設(shè)備不一樣的是,在注冊驅(qū)動函數(shù)是必須指定該驅(qū)動函數(shù)對應(yīng)的總線,因為驅(qū)動函數(shù)注冊成功后,會存放在對應(yīng)總線的driver目錄下,如果沒有總線,注冊當然會失敗。


與總線的注冊一樣:

1、定義結(jié)構(gòu)體device_driver。

2、調(diào)用注冊函數(shù):

214 int driver_register(struct device_driver *drv)

函數(shù)失敗返回非零,需要判斷返回值來檢查注冊是否成功。


設(shè)備注銷函數(shù):

249 void driver_unregister(struct device_driver *drv)


驅(qū)動函數(shù)屬性:


這個也是和總線屬性差不多,不細講:

驅(qū)動函數(shù)相關(guān)的結(jié)構(gòu)體和總線的類似,處理指定文件屬性為,還定義了showstore兩個函數(shù)。

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 };


設(shè)置設(shè)備屬性有兩個步驟:

1、創(chuàng)建并初始化device_attribute結(jié)構(gòu),使用宏DEVICE_ATTR

DRIVER_ATTR(_name, _mode, _show, _store)

該宏會定義一個名叫driver_attr__name(紅色部分是固定的)的driver_attibute的結(jié)構(gòu),并且成員name設(shè)置為_name,文件權(quán)限mode設(shè)置為_mode,兩個函數(shù)調(diào)用分別人showstore。

2、將device_attibute添加到指定的驅(qū)動函數(shù)上,使用以下調(diào)用:

/*drivers/base/driver.c*/

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

該函數(shù)失敗時返回錯誤號。

一旦調(diào)用該函數(shù),會就在指定dev設(shè)備的目錄下新建一個名叫_name的文件,權(quán)限為_mode,當訪問和修改該文件是會分別調(diào)用showstore函數(shù)調(diào)用。


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

/*drivers/base/driver.c*/

110 void driver_remove_file(struct device_driver *drv, struct driver_attribute *attr)


貼上函數(shù):

/*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的結(jié)構(gòu),并且成員

27 * name設(shè)置為version,文件權(quán)限mode設(shè)置為S_IRUGO|S_IWUGO,并設(shè)置show函數(shù)為

28 * show_driver_version,stror函數(shù)為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 /*驅(qū)動注冊,注冊成功后在/sys/bus/usb/driver目錄下創(chuàng)建目錄usb_driver*/

37 ret = driver_register(&usb_driver);

38 if(ret){

39 printk("driver register failed!\n");

40 goto err1;

41 }

42 /*為驅(qū)動添加屬性,調(diào)用成功后在/sys/bus/usb/dirver目錄下有一個version

43 * 文件,權(quán)限為S_IRUGO|S_IWUGO,查看該文件時會調(diào)用函數(shù)show_driver_version,修改時

44 * 調(diào)用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" //只有一處創(chuàng)建了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文件是觸發(fā)show函數(shù)

xiaobai V1.0


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


五、總結(jié)


這節(jié)講得內(nèi)容其實不多,歸納起來就是四個函數(shù)一個屬性結(jié)構(gòu)體。

屬性結(jié)構(gòu)體:xx_attribute。

注冊函數(shù):xx_register。

注銷函數(shù):xx+unregister

創(chuàng)建屬性文件函數(shù):xx_create_file。

刪除屬性文件函數(shù):xx_remove_file。

其中xx可以是總線(bus)、設(shè)備(device)或者驅(qū)動函數(shù)(deriver)。

一但注冊成功,就會在/sys目錄下相應(yīng)的地方創(chuàng)建一個自己命名的目錄。其中,設(shè)備和驅(qū)動函數(shù)還可以添加到指定的bus目錄下。

總線的成功注冊后會在/sys/bus目錄下創(chuàng)建相應(yīng)的目錄。

設(shè)備的成功注冊后會在/sys/device目錄下創(chuàng)建相應(yīng)的目錄,如果指定總線,會在指定總線目錄/sys/bus/xx/device下創(chuàng)建一個指向/sys/device目錄的軟連接。

驅(qū)動函數(shù)的公共注冊會在/sys/bus/xx/driver目錄下創(chuàng)建相應(yīng)的目錄。


屬性文件提供了shoestore兩個函數(shù)調(diào)用,當讀寫文件時會觸發(fā)相應(yīng)的函數(shù)調(diào)用,實現(xiàn)內(nèi)核sysfs與用戶空間的數(shù)據(jù)交互。


三者具體的關(guān)系就在后面章節(jié)介紹。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

源代碼: 8th_devModule_1.rar  

論壇徽章:
0
2 [報告]
發(fā)表于 2012-08-16 11:33 |只看該作者
lz寫的不錯啊,通過程序效果來加深理解,謝謝!
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP