zoukankan      html  css  js  c++  java
  • 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
    ");
    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
    ",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! 
    ");
    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 !
    ");
    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
    ", "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 !
    ");
    13     return 0;
    14 }
    15 
    16 static int my_remove(struct device *dev){
    17     printk("<0>Driver found device unpluged !
    ");
    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
    ", "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 的学习了。敬请期待。。。

  • 相关阅读:
    QT5.4 vs2013静态加载插件的sqlite静态编译
    四个漂亮的CSS样式表
    程序猿写的程序将如何打包成安装包(最简单)
    cocos2d的-X- luaproject的LUA脚本加密
    【【分享】深入浅出WPF全系列教程及源码 】
    C#的StringBuilder 以及string字符串拼接的效率对照
    【Android中Broadcast Receiver组件具体解释 】
    【蜗牛—漫漫IT路之大学篇(九) 】
    【分布式存储系统sheepdog 】
    C#异步调用
  • 原文地址:https://www.cnblogs.com/lihaiyan/p/4301081.html
Copyright © 2011-2022 走看看