码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-02-26 14:37:16      阅读:153      评论:0      收藏:0      [点我收藏+]

标签:

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

2015-02-26 11:42 李海沿

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

地址:http://www.cnblogs.com/lihaiyan/p/4301079.html

http://www.cnblogs.com/lihaiyan/p/4301072.html

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

一、问题分析

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

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

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

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

 

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

二、程序分析

1.包含总线

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

技术分享

2.定义驱动结构体

技术分享

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

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

 

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

技术分享

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

 

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

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

技术分享

 

5. 在exit函数中移除驱动

技术分享

 

三、编译测试

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

技术分享

加载

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

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

技术分享

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

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

技术分享

 

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

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

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

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

技术分享

 

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

技术分享

 

附上mybus.c 驱动程序

技术分享
 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 驱动程序

技术分享
 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 驱动程序

技术分享
 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程序

技术分享
 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 的学习了。敬请期待。。。

 

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

标签:

原文地址:http://www.cnblogs.com/lihaiyan/p/4301081.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!