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

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");

附上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");

附上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");

附上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

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

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

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

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

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

时间: 2024-11-03 05:30:42

20150226 IMX257 总线设备驱动模型编程之驱动篇的相关文章

20150226 IMX257 总线设备驱动模型编程之平台总线设备platform

20150226 IMX257 总线设备驱动模型编程之平台总线设备platform 2015-02-26 李海沿 前面我们实现了总线设备驱动模型,下面我们来了解一下平台总线,平台设备驱动 分为平台设备和平台驱动两种,和前面所说的设备驱动差不多 platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver.Linux 2.6的设备驱动模型中,把I2C.RTC.LCD等都归纳为platform_device. 一.平台设备介绍 1. p

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

20150226 IMX257 总线设备驱动模型编程之设备篇 2015-02-26 李海沿 前面我们呢实现了总线-设备-驱动模型中的总线,自然,我们的目标就是在我们建立的总线下面创建一个设备. http://www.cnblogs.com/lihaiyan/p/4301072.html 一.程序分析 1. 包含总线 既然我们的设备在总线上,自然我们既要包含总线了 如图所示,使用外部声明将我们的总线的结构体包含进来 2. 定义设备结构体 父目录为 my_bus 3. 定义属性文件结构体 属性文件结

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

20150225 IMX257 总线设备驱动模型编程之总线篇 2015-02-25 19:40 李海沿 从现在开始,我们开始来实现 总线-设备-驱动模型中的总线.. 我们这个程序的目标是在 sysfs文件系统的/sys/bus/ 目录下面建立一个文件夹. 一.总线介绍 1. 总线数据结构bus_type struct bus_type 结构体的定义如下: struct bus_type { const char *name; --总线名 struct bus_attribute *bus_att

20150226 IMX257 混杂设备miscdevice驱动程序

20150226 IMX257 混杂设备miscdevice驱动程序 2015-02-26 16:00 李海沿 在Linux驱动中把无法归类的五花八门的设备定义为混杂设备(用miscdevice结构体表述).miscdevice共享一个主设备号MISC_MAJOR(即10),但次设备号不同. 所有的miscdevice设备形成了一个链表,对设备访问时内核根据次设备号查找对应的miscdevice设备,然后调用其file_operations结构中注册的文件操作接口进行操作. 在内核中用struc

基于platform驱动模型的LED驱动

上一篇博文<platform设备驱动框架搭建分析>主要是根据内核源码来分析platform驱动模型工作的原理,在实际的驱动开发中如何使用Linux的这么一种模型来管理这种类型的设备呢?把tq2440开发板上的LED1当做是平台设备注册到Linux系统中,让系统可以用这种platform驱动来管理他. ①总线层:代码不用我们自己去写,内核已经提供了 ②设备层:向platform总线层注册硬件相关的资源,一般是寄存器地址.内存空间.中断号(序号的一种代表)等等 led_dev.c #include

linux驱动(九)platform驱动模型详解,以及基于platform驱动模型的led驱动

参考: http://blog.csdn.net/qq_28992301/article/details/52385518 http://blog.csdn.net/zoe6553/article/details/6372445 http://blog.chinaunix.net/uid-25014876-id-111745.html 1:什么是platform总线?platform总线是区别于实体总线USB. I2C.SPI .PIC总线的虚拟总线,一些usb设备选址的话需要通过USB总线来进

字符设备驱动、平台设备驱动、设备驱动模型、sysfs的关系

Linux驱动开发的童鞋们来膜拜吧:-)  学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术.对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了.要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码.网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关联的分析.对于开发者而言,能够熟悉某一点并分享出来已很难得,但对于专注传授技术和经验给

[kernel]字符设备驱动、平台设备驱动、设备驱动模型、sysfs几者之间的比较和关联

转自:http://www.2cto.com/kf/201510/444943.html Linux驱动开发经验总结,绝对干货! 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术.对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了.要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码.网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关

Linux RTC驱动模型分析

RTC简介 RTC(real-time clock)简称实时时钟,主要作用是用来记时,产生闹钟等.RTC因为有备份电池,所以即使计算机关机掉电,也不会影响RTC记时.而RTC和系统时间(主要靠软件模拟)的区别在于,RTC会在掉电后数据不丢失,在下次启动依旧可以重新设置当前时间给计算机.而系统时间主要靠软件模拟产生,在掉电之后会丢失,需要在下次计算机重新启动之后重新模拟产生.RTC时间在每次系统启动的时候会使用,在以后需要的时候会将设置的时间写入到RTC中,别的时候获取时间都通过软件可以获得. R