linux设备驱动归纳总结(八):1.总线、设备和驱动

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

2 #include

3

4 #include

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目录下的文件与内核设备模型之间的数据交互。

设置总线属性有两个步骤:

、创建并初始化bus_attribute结构,使用宏BUS_ATTR

BUS_ATTR(_name, _mode, _show, _store)

该宏会定义一个名叫bus_attr__name(红色部分是固定的)的bus_attibute的结构,并且成员name设置为_name,文件权限mode设置为_mode,两个函数调用分别人show和store。

、将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

2 #include

3

4 #include

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(这是必须的,不然卸载模块时会出错,不信自己试试)。

设备注册和注销:

与总线的注册一样:

、定义结构体device。

、调用注册函数:

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

设置设备属性有两个步骤:

、创建并初始化device_attribute结构,使用宏DEVICE_ATTR

DEVICE_ATTR(_name, _mode, _show, _store)

该宏会定义一个名叫dev_attr__name(红色部分是固定的)的device_attibute的结构,并且成员name设置为_name,文件权限mode设置为_mode,两个函数调用分别人show和store。

、将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

2 #include

3

4 #include

5

6 #define VER_SIZE 100

7

8 extern struct bus_type usb_bus;

10 void usb_dev_release(struct device *dev)

11 {

12 printk(" release\n");

13 }

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

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目录下,如果没有总线,注册当然会失败。

与总线的注册一样:

、定义结构体device_driver。

、调用注册函数:

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

设置设备属性有两个步骤:

、创建并初始化device_attribute结构,使用宏DEVICE_ATTR

DRIVER_ATTR(_name, _mode, _show, _store)

该宏会定义一个名叫driver_attr__name(红色部分是固定的)的driver_attibute的结构,并且成员name设置为_name,文件权限mode设置为_mode,两个函数调用分别人show和store。

、将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

2 #include

3

4 #include

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

源代码: 8th_devModule_1.rar

【Linux开发】linux设备驱动归纳总结(八):1.总线、设备和驱动的更多相关文章

  1. linux设备驱动归纳总结

    前言: (总结已经基本写完,这段时间我会从新排版和修正.错误总会有的,望能指正!) 前段时间学习了嵌入式驱动,趁着没开始找工作,这段时间我会每天抽出时间来复习. 我的总结是根据学习时的笔记(李杨老师授 ...

  2. 【Linux】linux设备驱动归纳总结

    前言: (总结已经基本写完,这段时间我会从新排版和修正.错误总会有的,望能指正!) 前段时间学习了嵌入式驱动,趁着没开始找工作,这段时间我会每天抽出时间来复习. 我的总结是根据学习时的笔记(李杨老师授 ...

  3. Linux设备管理(三)_总线设备的挂接

    扒完了字符设备,我们来看看平台总线设备,平台总线是Linux中的一种虚拟总线,我们知道,总线+设备+驱动是Linux驱动模型的三大组件,设计这样的模型就是将驱动代码和设备信息相分离,对于稍微复杂一点的 ...

  4. 【Linux开发】linux设备驱动归纳总结(八):3.设备管理的分层与面向对象思想

    linux设备驱动归纳总结(八):3.设备管理的分层与面向对象思想 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  5. 【Linux开发】linux设备驱动归纳总结(八):2.总线、设备和驱动的关系

    linux设备驱动归纳总结(八):2.总线.设备和驱动的关系 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  6. 【Linux开发】linux设备驱动归纳总结(八):4.总线热插拔

    linux设备驱动归纳总结(八):4.总线热插拔 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  7. linux设备驱动归纳总结(八):3.设备管理的分层与面向对象思想【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-110738.html linux设备驱动归纳总结(八):3.设备管理的分层与面向对象思想 xxxxxx ...

  8. 【Linux开发】linux设备驱动归纳总结(五):1.在内核空间分配内存

    linux设备驱动归纳总结(五):1.在内核空间分配内存 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  9. 【Linux开发】linux设备驱动归纳总结(四):1.进程管理的相关概念

    linux设备驱动归纳总结(四):1.进程管理的相关概念 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

随机推荐

  1. Spark配置详解

    Spark提供三个位置用来配置系统: Spark属性:控制大部分的应用程序参数,可以用SparkConf对象或者Java系统属性设置 环境变量:可以通过每个节点的 conf/spark-env.sh脚 ...

  2. jvm——Java main方法的执行

    这是什么神仙博客! https://www.cnblogs.com/kaleidoscope/p/9629156.html

  3. Ubuntu:电源管理

    本文适用于Ubuntu 16.04,造冰箱的大熊猫@cnblogs 2018/3/4 在Ubuntu 16.04中,与电源管理相关的选项位于System Settings下的Power对话框中. 要启 ...

  4. 原创:实现atoi函数

    #include <stdio.h> #include <stdlib.h> #include <limits.h> int my_atoi(char *str) ...

  5. javascript类型判断最佳实践

    javascript有8种数据类型 值类型 Number Null Undefined String Symbol Boolean BigInt 引用类型 Object Array Function ...

  6. 创建虚拟机,安装操作系统,xshell6远程链接

    一.创建虚拟机 1. 首先安装vmware,注意在安装中,下面的两项不要勾选,一路下一步 2.完成安装打开之后,创建新的虚拟机 3.虚拟机创建完成,需要改配置 4.然后设置网段 5.查看服务,在运行状 ...

  7. Spring Boot教程(四十一)LDAP来管理用户信息(1)

    LDAP简介 LDAP(轻量级目录访问协议,Lightweight Directory Access Protocol)是实现提供被称为目录服务的信息服务.目录服务是一种特殊的数据库系统,其专门针对读 ...

  8. [ubuntu] 外挂硬盘

    1. 查看磁盘信息 fdisk -l 这里我需要对sda进行分区,所以要进到sda中 2. 进到欲分区磁盘中 $ sudo fdisk /dev/sda Welcome to fdisk (util- ...

  9. python2topython3遇到的问题

  10. Web存储机制—sessionStorage,localStorage使用方法

    Web存储机制,在这里主要聊有关于Web Storage API提供的存储机制,通过该机制,浏览器可以安全地存储键值对,比使用cookie更加直观.接下来简单的了解如何使用这方面的技术. 基本概念 W ...