一、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# llclass/net/eth0
lrwxrwxrwx 1 root root 0 2011-01-3110: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 constchar *name;
53 structbus_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)(structdevice *dev);
62
63 int (*suspend)(struct device*dev, pm_message_t state);
64 int (*suspend_late)(structdevice *dev, pm_message_t state);
65 int (*resume_early)(structdevice *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(structbus_type *bus)
该调用有可能失败,所以必须检查它的返回值,如果注册成功,会在/sys/bus下看到指定名字的总线。
总线删除时调用:
/*drivers/base/bus.c*/
946 void bus_unregister(structbus_type *bus)
接下来贴个函数:
/*8th_devModule_1/1st/bus.c*/
1 #include
2 #include
3
4 #include
5
6 structbus_type usb_bus = {
7 .name= "usb", //定义总线的名字为usb,注册成功后将在/sys/bus目录下看到
8 }; //目录usb,如果你的系统已经有usb总线,那你就要换个名字。
9
10 static int __initusb_bus_init(void)
11 {
12 int ret;
13 /*总线注册,必须检测返回值*/
14 ret =bus_register(&usb_bus);
15 if(ret){
16 printk("busregister failed!\n");
17 return ret;
18 }
19
20 printk("usb businit\n");
21 return 0;
22 }
23
24 static void __exitusb_bus_exit(void)
25 {
26 bus_unregister(&usb_bus);
27 printk("usb busbye!\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)(structbus_type *bus, char *buf);
41 ssize_t (*store)(structbus_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。
下面看看BUS_ATTR的定义:
#define BUS_ATTR(_name, _mode, _show, _store) \
struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
bus_attr_##_name!!!!!
2、将bus_attibute添加到指定的总线上,使用以下调用:
/*/drivers/base/bus.c*/
123 int bus_create_file(structbus_type *bus, struct bus_attribute *attr)
该函数失败时返回错误号。
一旦调用该函数,会就在指定bus总线的目录下新建一个名叫_name的文件,权限为_mode,当访问和修改该文件是会分别调用show和store函数调用。
如果不需要该属性时,使用以下函数删除:
/*/drivers/base/bus.c*/
135 voidbus_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 staticssize_tshow_bus_version(struct bus_type*bus, char *buf)
15 {
16 return snprintf(buf,VER_SIZE, "%s\n", Version);
17 }
18 staticssize_tstore_bus_version(structbus_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 staticBUS_ATTR(version, S_IRUGO|S_IWUGO, show_bus_version,store_bus_version);
26
27 static int __initusb_bus_init(void)
28 {
29 int ret;
30
31 /*总线注册*/
32 ret =bus_register(&usb_bus);
33 if(ret){
34 printk("busregister 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 creatfile failed!\n");
42 goto err2;
43 }
44 printk("usb businit\n");
45 return 0;
46
47 err2:
48 bus_unregister(&usb_bus);
49 err1:
50 return ret;
51 }
52
53 static void __exitusb_bus_exit(void)
54 {
55 bus_remove_file(&usb_bus,&bus_attr_version);//不调用这个也可以的,删除总线时会删除
56 bus_unregister(&usb_bus);
57 printk("usb busbye!\n");
58 }
验证一下:
[root: 2nd]# insmod bus.ko
usb bus init
[root: 2nd]# ls /sys/bus/usb/
devices drivers_autoprobe uevent
drivers drivers_probeversion //多了一个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 structdevice *parent;//指定该设备的父设备,如果不指定(NULL),注册后的设备目录
375///在sys/device下
376 struct kobject kobj;
377 char bus_id[BUS_ID_SIZE]; /* position on parent bus */ //在总线生识别设备的字符串,
385//同时也是设备注册后的目录名字。
386 structbus_type *bus; /* type of bus device is on *///指定该设备连接的总线
387 structdevice_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)
函数失败返回非零,需要判断返回值来检查注册是否成功。
设备注销函数:
voiddevice_unregister(struct device *dev)
设备属性:
这个也是和总线属性差不多,不细讲:
设备相关的结构体和总线的类似,处理指定文件属性为,还定义了show和store两个函数。
/*linux/device.h*/
300 struct device_attribute {
301 struct attribute attr;
302 ssize_t (*show)(structdevice *dev, struct device_attribute *attr,
303 char *buf);
304 ssize_t (*store)(structdevice *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。这个跟bus的差不多,可参考上面。
2、将device_attibute添加到指定的设备上,使用以下调用:
/*drivers/base/core.c*/
430 int device_create_file(structdevice *dev, struct device_attribute *attr)
该函数失败时返回错误号。
一旦调用该函数,会就在指定dev设备的目录下新建一个名叫_name的文件,权限为_mode,当访问和修改该文件是会分别调用show和store函数调用。
如果不需要该属性时,使用以下函数删除:
/*drivers/base/core.c*/
443 voiddevice_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 externstruct bus_type usb_bus;
9
10 voidusb_dev_release(struct device *dev)
11 {
12 printk(" release\n");
13 }
14
15 structdevice usb_device = {
16.init_name = "usb_deivce",
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_tshow_device_version(struct device *dev,
15 structdevice_attribute *attr, char *buf)
16 {
17 return snprintf(buf,VER_SIZE, "%s\n", Version);
18 }
19 static ssize_tstore_device_version(struct device*dev,
20 structdevice_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 staticDEVICE_ATTR(version, S_IRUGO|S_IWUGO,
28 show_device_version, store_device_version);
29
30 static int __initusb_device_init(void)
31 {
32 int ret;
33
34 /*设备注册,注册成功后在/sys/device目录下创建目录usb_device*/
35 ret =device_register(&usb_device);
36 if(ret){
37 printk("deviceregister 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("devicecreat file failed!\n");
46 goto err2;
47 }
48 printk("usb deviceinit\n");
49 return 0;
50
51 err2:
52 device_unregister(&usb_device);
53 err1:
54 return ret;
55 }
56
57 static void __exitusb_device_exit(void)
58 {
59 device_remove_file(&usb_device, &dev_attr_version);
60 device_unregister(&usb_device);
61 printk("usb devicebye!\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: /]# cdreview_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 constchar *name;//驱动函数的名字,在对应总线的driver目录下显示
124 structbus_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) (structdevice *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(structdevice_driver *drv)
函数失败返回非零,需要判断返回值来检查注册是否成功。
设备注销函数:
249 voiddriver_unregister(struct device_driver *drv)
驱动函数属性:
这个也是和总线属性差不多,不细讲:
驱动函数相关的结构体和总线的类似,处理指定文件属性为,还定义了show和store两个函数。
155 struct driver_attribute {
156 struct attribute attr;
157 ssize_t (*show)(structdevice_driver *driver, char *buf);
158 ssize_t (*store)(structdevice_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(structdevice_driver *drv, struct driver_attribute *attr)
该函数失败时返回错误号。
一旦调用该函数,会就在指定dev设备的目录下新建一个名叫_name的文件,权限为_mode,当访问和修改该文件是会分别调用show和store函数调用。
如果不需要该属性时,使用以下函数删除:
/*drivers/base/driver.c*/
110 voiddriver_remove_file(struct device_driver *drv, structdriver_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 structdevice_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_tshow_driver_version(struct device_driver*drv, char *buf)
18 {
19 return snprintf(buf,VER_SIZE, "%s\n", Version);
20 }
21 static ssize_tstore_driver_version(structdevice_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 staticDRIVER_ATTR(version, S_IRUGO|S_IWUGO,
30 show_driver_version, store_driver_version);
31
32 static int __initusb_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("driverregister 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("drivercreat file failed!\n");
48 goto err2;
49 }
50 printk("usb driverinit\n");
51 return 0;
52
53 err2:
54 driver_unregister(&usb_driver);
55 err1:
56 return ret;
57 }
58
59 static void __exitusb_driver_exit(void)
60 {
61 driver_remove_file(&usb_driver, &driver_attr_version);
62 driver_unregister(&usb_driver);
63 printk("usb driverbye!\n");
64 }
看看效果,同样必须先加载bus.ko:
[root: /]# cdreview_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与用户空间的数据交互。
--------------------------------------------------------------------------------------------------------------------------
错误修正
按照国嵌的代码(LDD那本书上的代码也一样):
struct device my_bus = {
.bus_id = "my_bus0",
.release = my_bus_release,
};
static int my_match(struct device *dev, struct device_driver *driver)
{
return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
}
编译时,提示 struct device 中没有bus_id 这样的错误。打开/lib/modules/2.6.35-28-generic/build/include/linux/device.h
找到struct device 的定义,里面没有bus_id,但有:
const char *init_name; /* initial name of the device */ 这句。
可见,要把上面结构中的.bus_id = "my_bus0", 改为 .init_name = "my_bus0",
同时上网搜到,return !strncmp(dev->bus_id, driver->name, strlen(driver->name));这句也要改成:
return !strncmp(dev_name(dev), driver->name, strlen(driver->name));
这样编译即可成功!
另注:
如果要设置设备的名字,也不再使用strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE); 而改用:
dev_set_name(&dev, "name");
程序代码在这 里面有代码要按上面的修改 点击打开链接