0
点赞
收藏
分享

微信扫一扫

20150226 IMX257 总线设备驱动模型编程之驱动篇

金刚豆 2022-03-30 阅读 60


20150226 IMX257 总线设备驱动模型编程之驱动篇

2015-02-26 11:42 李海沿

前面我们已经实现了 总线和设备 的驱动程序,接下来我们的任务就是 实现 驱动 了

在实现驱动程序之前,我们来想两个问题:

一、问题分析

1.什么时候驱动程序会在总线上找它可以处理的设备?

在driver_register(&my_driver),驱动注册时,驱动程序会在总线上找它可以处理的设备。

2.为什么说这个驱动可以处理相应的设备?

总线来判断这个驱动是否可以处理相应的设备,在总线中有.match = my_match ,当驱动在总线上找到了设备时,.match 函数就是用来判断这个驱动是否可以处理设备,判断的原则就是,判断设备的dev->bus_id和驱动的driver->name 是否相等,如果相等,则表明这个驱动是可以处理这个设备的。    此时就说明驱动找到了设备,接着,驱动程序就会调用probe这个函数,这就是我们所说的总线设备驱动模型,三者工作作用。


加载总线之后,不管是先加载驱动或者先加载设备都可以,如果先加载驱动的话,在注册设备时就会在总线上寻找驱动,如果先加载设备时,当注册驱动程序时,驱动程序会在总线中寻找有没有相应的设备。

二、程序分析

1.包含总线

和前面的设备程序一样,先包含总线

20150226 IMX257 总线设备驱动模型编程之驱动篇_linux

2.定义驱动结构体

20150226 IMX257 总线设备驱动模型编程之驱动篇_linux_02

注意 struct 的成员 .name ,因为探测驱动与设备是否匹配就是看这个名字

my_probe 和my_remove 就是分别当驱动程序 和 设备 关联 或者 不关联时会调用的函数


3.定义属性文件的结构体

20150226 IMX257 总线设备驱动模型编程之驱动篇_驱动程序_03

关于 static DRIVER_ATTR(drv,S_IRUGO,mydriver_show,NULL);这种宏,此处就不再废话了,不懂的可以看linux源码或者前面我们bus篇中的讲解


4.在init函数中 注册驱动 创建属性文件

可以发现又是和前面的一样,不再废话了。

20150226 IMX257 总线设备驱动模型编程之驱动篇_驱动程序_04


5. 在exit函数中移除驱动

20150226 IMX257 总线设备驱动模型编程之驱动篇_#include_05


三、编译测试

编译,成功生成 mybus.ko mydev.o mydrv.ko:

20150226 IMX257 总线设备驱动模型编程之驱动篇_#include_06

加载

方案一 先加载驱动后加载设备 加载顺序 mybus.ko mydrv.ko mydev.ko

可以发现,一旦我们加载设备,便打印出 驱动中的my_probe的代码:告诉我们驱动找到了设备

20150226 IMX257 总线设备驱动模型编程之驱动篇_#include_07

移除时,发现打印出了驱动中my_remove函数的代码Driver found device unpluged ! 如图所示:

同样我们还发现,mybus已经有俩个使用了 分别是 mydev 和 mydrv

20150226 IMX257 总线设备驱动模型编程之驱动篇_#include_08


下面我们来试试方案二,看看结果怎么样

方案二 先加载设备后加载驱动 加载顺序 mybus.ko mydev.ko mydrv.ko

可以发现,结果一样,一旦我们加载驱动,便打印出 驱动中的my_probe的代码:告诉我们驱动找到了设备

这里更加证实了我们前面问题二中的答案

20150226 IMX257 总线设备驱动模型编程之驱动篇_#include_09


下面我们进入 /sys/bus/my_bus/drivers/my_dev 看看下面有什么文件

20150226 IMX257 总线设备驱动模型编程之驱动篇_驱动程序_10


附上mybus.c 驱动程序

20150226 IMX257 总线设备驱动模型编程之驱动篇_#include_1120150226 IMX257 总线设备驱动模型编程之驱动篇_#include_12

1 #include <linux/device.h>
2 #include <linux/module.h>
3 #include <linux/kernel.h>
4 #include <linux/init.h>
5 #include <linux/string.h>
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("<0>my bus release\n");
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,"%s\n",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("<0>Fail to create version attribute! \n");
49
50 /* 注册总线设备 */
51 ret = device_register(&my_bus);
52 if(ret)
53 printk("<0>Fail to register device: my_bus");
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");

View Code


附上mydev.c 驱动程序

20150226 IMX257 总线设备驱动模型编程之驱动篇_#include_1120150226 IMX257 总线设备驱动模型编程之驱动篇_#include_12

1 #include <linux/device.h>
2 #include <linux/module.h>
3 #include <linux/kernel.h>
4 #include <linux/init.h>
5 #include <linux/string.h>
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("<0>my_dev release !\n");
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, "%s\n", "This is my device");
24 }
25
26 //产生后面的 bus_attr_version 结构体
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("<0>Fail to register device: my_dev");
39 /* 创建属性文件 */
40 if(device_create_file(&my_dev, &dev_attr_dev))
41 printk("<0>Fail to create device file: my_dev");
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");

View Code


附上mydrv.c 驱动程序

20150226 IMX257 总线设备驱动模型编程之驱动篇_#include_1120150226 IMX257 总线设备驱动模型编程之驱动篇_#include_12

1 #include <linux/device.h>
2 #include <linux/module.h>
3 #include <linux/kernel.h>
4 #include <linux/init.h>
5 #include <linux/string.h>
6
7 //包含总线
8 extern struct device my_bus;
9 extern struct bus_type my_bus_type;
10
11 static int my_probe(struct device *dev){
12 printk("<0>Driver found device which my driver can handle !\n");
13 return 0;
14 }
15
16 static int my_remove(struct device *dev){
17 printk("<0>Driver found device unpluged !\n");
18 return 0;
19 }
20 // 驱动结构体
21 struct device_driver my_driver = {
22 .name = "my_dev", //此处声明了 本驱动程序可以处理的设备 名字
23 .bus = &my_bus_type,
24 .probe = my_probe,
25 .remove = my_remove,
26 };
27
28 ssize_t mydriver_show(struct device_driver *driver,char *buf){
29 return sprintf(buf, "%s\n", "This is my driver");
30 }
31
32 //产生后面的 driver_attr_drv 结构体
33 static DRIVER_ATTR(drv,S_IRUGO,mydriver_show,NULL);
34
35 static int __init my_driver_init(void){
36 int ret = 0;
37
38 /* 注册驱动 */
39 ret = driver_register(&my_driver);
40 if(ret)
41 printk("<0>Fail to register driver: my_driver");
42 /* 创建属性文件 */
43 if(driver_create_file(&my_driver, &driver_attr_drv))
44 printk("<0>Fail to create driver file: my_drv");
45
46 return ret;
47 }
48
49 static void my_driver_exit(void){
50 driver_remove_file(&my_driver, &driver_attr_drv);
51 driver_unregister(&my_driver);
52 }
53
54 module_init(my_driver_init);
55 module_exit(my_driver_exit);
56
57
58 MODULE_AUTHOR("Lover雪儿");
59 MODULE_LICENSE("GPL");

View Code


附上makefile程序

20150226 IMX257 总线设备驱动模型编程之驱动篇_#include_1120150226 IMX257 总线设备驱动模型编程之驱动篇_#include_12

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 mydrv.o
13 endif

View Code



好啦,至此,我们的总线-设备-驱动 模型已经实现了,但是并不能说我们已经懂了,这里再次废话一下,很多原理知识虽然乏味,还是要看,光会写程序是没用的,还需要懂为什么。


我也是处于学习阶段,这些都是我的一些简单的经验,能帮助大家快速入门,剩下的还是。。。入门了就会相对跟简单了。

很多人说学习linux驱动很难,那是因为对未知的恐惧,说简单点,就是那么几个结构体,算法和API的使用罢了,不说了,说多了就是欠揍的下场,

任重而道远,加油吧!!!


下面我们的任务就是实现 平台设备驱动程序 platform 的学习了。敬请期待。。。



举报

相关推荐

0 条评论