一、程序分析
1. 包含总线
既然我们的设备在总线上,自然我们既要包含总线了
如图所示,使用外部声明将我们的总线的结构体包含进来
2. 定义设备结构体
父目录为 my_bus
3. 定义属性文件结构体
属性文件结构体可以有一下得到:
//产生后面的 bus_attr_version 结构体
static DEVICE_ATTR(dev,S_IRUGO,mydev_show,NULL);
如图所示:
4. 在初始化函数中
如图所示:
在初始化函数中,
先初始化设备的名字,这个名字用于于驱动名字进行匹配
然后注册设备,让系统认识这个设备,在/sys/device/my_bus0 下面就会有my_dev这个设备
最后创建属性文件,这个就是在my_dev下面的 dev文件,可以使用cat dev 进行读取,用于传递字符串。
5. 在exit函数中
如图所示就是 移除属性文件,注销设备
二、编译测试
可以发现,在我们的/sys/bus/目录下生成了 my_bus 目录
然后,在 my_bus/devices/ 目录下又生成了 my_dev 目录
查看my_dev的属性文件 cat dev
我们使用cat drivers_autoprobe 命令,为1,意思就是我们驱动会自动探测设备
移除驱动时最好注意顺序
至此,总线-设备-驱动 模型中,我们已经完成其二了,最后的一个驱动篇,加油!
我们的目标是在总线中加入驱动程序,并且驱动程序和设备程序会自动互相探测寻找,然后在match中检测关联。
附上 mybus .c 总线驱动程序
1 #include
2 #include
3 #include
4 #include
5 #include
6
7
8 static char *Version = '$LoverXueEr : 1.0 $';
9
10 //检测驱动是否匹配设备,dev->bus_id 和 driver->name相等的
11 static int my_match(struct device *dev ,struct device_driver *driver){
12 return !strncmp(dev_name(dev),driver->name,strlen(driver->name));
13 }
14
15 static void my_bus_release(struct device *dev){
16 printk('
17 }
18
19 //设置设备的名字 dev_set_name(&dev,'name');
20 struct device my_bus = {
21 .init_name = 'my_bus0',
22 .release = my_bus_release,
23 };
24
25 struct bus_type my_bus_type = {
26 .name = 'my_bus',
27 .match = my_match,
28 };
29 EXPORT_SYMBOL(my_bus); //导出符号
30 EXPORT_SYMBOL(my_bus_type);
31
32 //显示总线版本号
33 static ssize_t show_bus_version(struct bus_type *bus,char *buf){
34 return snprintf(buf,PAGE_SIZE,'%sn',Version);
35 }
36
37 //产生后面的 bus_attr_version 结构体
38 static BUS_ATTR(version,S_IRUGO, show_bus_version, NULL);
39
40 static int __init my_bus_init(void){
41 int ret;
42 /* 注册总线 */
43 ret = bus_register(&my_bus_type);
44 if(ret)
45 return ret;
46 /* 创建属性文件 */
47 if(bus_create_file(&my_bus_type, &bus_attr_version))
48 printk('
49
50 /* 注册总线设备 */
51 ret = device_register(&my_bus);
52 if(ret)
53 printk('
54 return ret;
55 }
56
57 static void my_bus_exit(void){
58 bus_unregister(&my_bus_type);
59 device_unregister(&my_bus);
60 }
61
62 module_init(my_bus_init);
63 module_exit(my_bus_exit);
64
65
66 MODULE_AUTHOR('Lover雪儿');
67 MODULE_LICENSE('GPL');
附上 mydev .c 设备驱动程序
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 //包含总线
8 extern struct device my_bus;
9 extern struct bus_type my_bus_type;
10
11 static void my_dev_release(struct device *dev){
12 printk('
13 }
14
15 //设置设备的名字 dev_set_name(&dev,'name');
16 struct device my_dev = {
17 .bus = &my_bus_type,
18 .parent = &my_bus, //父目录为my_bus
19 .release = my_dev_release,
20 };
21
22 ssize_t mydev_show(struct device *dev,struct device_attribute *attr,char *buf){
23 return sprintf(buf, '%sn', 'This is my device');
24 }
25
26 //产生后面的 dev_attr_dev 结构体
27 static DEVICE_ATTR(dev,S_IRUGO,mydev_show,NULL);
28
29 static int __init my_dev_init(void){
30 int ret = 0;
31
32 /* 初始化设备 以后看驱动与设备是否匹配就看这个名字 */
33 dev_set_name(&my_dev,'my_dev');
34
35 /* 注册设备 */
36 ret = device_register(&my_dev);
37 if(ret)
38 printk('
39 /* 创建属性文件 */
40 if(device_create_file(&my_dev, &dev_attr_dev))
41 printk('
42
43 return ret;
44 }
45
46 static void my_dev_exit(void){
47 device_remove_file(&my_dev, &dev_attr_dev);
48 device_unregister(&my_dev);
49 }
50
51 module_init(my_dev_init);
52 module_exit(my_dev_exit);
53
54
55 MODULE_AUTHOR('Lover雪儿');
56 MODULE_LICENSE('GPL');
附上 MAKEFILE程序
1 ifeq ($(KERNELRELEASE),)
2 KERNELDIR ?= /home/study/system/linux-2.6.31
3 PWD := $(shell pwd)
4 modules:
5 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
6 modules_install:
7 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
8 clean:
9 rm -rf *.o *~ core .depend *.cmd *.ko *.mod.c .tmp_versions *.markers *.order *.symvers
10
11 else
12 obj-m := mybus.o mydev.o
13 endif