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

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

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

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

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

设备注册和注销:

与总线的注册一样:

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

2 #include

3

4 #include

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("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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值