总线设备驱动模型【转】

news/2024/7/6 6:33:24

本文转载自:http://blog.csdn.net/coding__madman/article/details/51428400

总线驱动设备模型:

1. 总线设备驱动模型概述

        随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求也越来越高,2.4内核已经难以满足这些需求,为适应这宗形势的需求,从linux2.6内核开始提供了全新的设备模型

2. 总线

    2.1 描述结构

    2.2 注册

    2.3 注销

void  bus_unregister(struct  bus_type *bus)

代码例程:

bus.c

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. #include<linux/module.h>  
  2. #include<linux/init.h>  
  3. #include<linux/kernel.h>  
  4. #include<linux/device.h>  
  5.   
  6. MODULE_LICENSE("GPL");  
  7.   
  8. int my_match(struct device *dev, struct device_driver *drv)  
  9. {  
  10.       
  11.     return 0;  
  12. }  
  13.   
  14. struct bus_type my_bus_type =   
  15. {  
  16.     .name = "my_bus",  
  17.     .match = my_match,  
  18. };  
  19.   
  20. int my_bus_init(void)  
  21. {  
  22.     int ret;  
  23.       
  24.     ret = bus_register(&my_bus_type);  
  25.       
  26.     return ret;  
  27. }  
  28.   
  29. void my_bus_exit(void)  
  30. {  
  31.     bus_unregister(&my_bus_type);  
  32. }  
  33.   
  34.   
  35. module_init(my_bus_init);  
  36. module_exit(my_bus_exit);  


这是上面的总线驱动模块编译运行的效果图!

 

 

下面向上面的my_bus总线上挂载一个驱动!

 

3. 驱动

    3.1 描述结构

    3.2 注册

      int  drvier_register(struct  device  *dev)

    3.3 注销

      void drever_unregister(struct  device_driver  *drv)

4. 设备

    4.1 设备的描述

    4.2 设备的注册

       int device_register(struct device *dev)

    4.3 设备的注销

       void device_unregister(struct device *dev)

driver.c

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. #include<linux/module.h>  
  2. #include<linux/init.h>  
  3. #include<linux/device.h>  
  4. #include<linux/kernel.h>  
  5.   
  6. MODULE_LICENSE("GPL");  
  7.   
  8. extern struct bus_type my_bus_type;  
  9.   
  10. int my_probe(struct device *dev)  
  11. {  
  12.     printk(KERN_WARNING"driver found the device!!!\n");  
  13.       
  14.     return 0;  
  15. }  
  16.   
  17. struct device_driver my_driver =   
  18. {  
  19.     .name = "my_dev",  
  20.     .bus = &my_bus_type,  
  21.     .probe = my_probe, //当找到这个设备时将调用这个函数  
  22. };  
  23.   
  24. int my_device_init(void)  
  25. {  
  26.     int ret;   
  27.       
  28.     ret = driver_register(&my_driver);//注册一个驱动  
  29.       
  30.     return 0;  
  31. }  
  32.   
  33. void my_device_exit(void)  
  34. {  
  35.     driver_unregister(&my_driver);  
  36. }  
  37.   
  38. module_init(my_device_init);  
  39. module_exit(my_device_exit);  

Makefile

 

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. obj-m := bus.o device.o  
  2. KDIR := /home/kernel/linux-ok6410  
  3. all:  
  4.     make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm  
  5. clean:  
  6.     rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order  



 

下面再在总线上挂载一个设备!

device.c

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. #include <linux/device.h>  
  2. #include <linux/module.h>  
  3. #include <linux/kernel.h>  
  4. #include <linux/init.h>  
  5.   
  6. MODULE_LICENSE("GPL");  
  7.   
  8. extern struct bus_type my_bus_type;  
  9.   
  10. struct device my_dev =   
  11. {  
  12.      .init_name = "my_dev",//和驱动名字一样  
  13.      .bus = &my_bus_type,     
  14. };  
  15.   
  16. int my_device_init(void)  
  17. {  
  18.     int ret;  
  19.      ret = device_register(&my_dev);  
  20.      return ret;  
  21.        
  22. }  
  23.   
  24.   
  25. void my_device_exit(void)  
  26. {  
  27.     device_unregister(&my_dev);  
  28. }  
  29.   
  30. module_init(my_device_init);  
  31. module_exit(my_device_exit);  


driver.c

 

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. #include<linux/module.h>  
  2. #include<linux/init.h>  
  3. #include<linux/device.h>  
  4. #include<linux/kernel.h>  
  5.   
  6. MODULE_LICENSE("GPL");  
  7.   
  8. extern struct bus_type my_bus_type;  
  9.   
  10. int my_probe(struct device *dev)  
  11. {  
  12.     printk(KERN_WARNING"driver found the device!!!\n");  
  13.       
  14.     return 0;  
  15. }  
  16.   
  17. struct device_driver my_driver =   
  18. {  
  19.     .name = "my_dev",  
  20.     .bus = &my_bus_type,  
  21.     .probe = my_probe, //当找到这个设备时将调用这个函数  
  22. };  
  23.   
  24. int my_device_init(void)  
  25. {  
  26.     int ret;   
  27.       
  28.     ret = driver_register(&my_driver);//注册一个驱动  
  29.       
  30.     return 0;  
  31. }  
  32.   
  33. void my_device_exit(void)  
  34. {  
  35.     driver_unregister(&my_driver);  
  36. }  
  37.   
  38. module_init(my_device_init);  
  39. module_exit(my_device_exit);  

bus.c

 

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. #include<linux/module.h>  
  2. #include<linux/init.h>  
  3. #include<linux/kernel.h>  
  4. #include<linux/device.h>  
  5.   
  6. MODULE_LICENSE("GPL");  
  7.   
  8. int my_match(struct device *dev, struct device_driver *drv)  
  9. {  
  10.     return !strncmp(dev->kobj.name,drv->name,strlen(drv->name));  
  11. }  
  12.   
  13. struct bus_type my_bus_type =   
  14. {  
  15.     .name = "my_bus",  
  16.     .match = my_match,  
  17. };  
  18.   
  19. EXPORT_SYMBOL(my_bus_type);//输出符号 另一device.c要用到  
  20.   
  21. int my_bus_init(void)  
  22. {  
  23.     int ret;  
  24.       
  25.     ret = bus_register(&my_bus_type);  
  26.       
  27.     return ret;  
  28. }  
  29.   
  30. void my_bus_exit(void)  
  31. {  
  32.     bus_unregister(&my_bus_type);  
  33. }  
  34.   
  35.   
  36. module_init(my_bus_init);  
  37. module_exit(my_bus_exit);  


Makefile

 

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. obj-m := bus.o driver.o device.o  
  2. KDIR := /home/kernel/linux-ok6410  
  3. all:  
  4.     make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm  
  5. clean:  
  6.     rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order  



运行效果图:

 


平台总线驱动设计:

1. 平台总线概述

    平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其优势在于采用了总线的模型对设备与驱动进行了管理,这样提高了程序的可移植性。

2. 平台设备

注册平台设备,使用函数:

    int platform_device_register(struct platform_device *pdev)

3. 平台驱动

平台驱动注册使用函数:

int platform_driver_register(struct platform_driver *)

 

结合上面的基础知识,将案件驱动修改为平台驱动模式!

1. 平台设备注册

2. 平台按键驱动设计

key_dev.c

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. #include<linux/init.h>  
  2. #include<linux/module.h>  
  3. #include<linux/platform_device.h>  
  4. #include<linux/interrupt.h>  
  5.   
  6. MODULE_LICENSE("GPL");  
  7.   
  8. #define GPNCON 0x7F008830  
  9.   
  10. static struct resource key_resource[] = { //定义按键资源  
  11.     [0] = {  
  12.               .start = GPNCON,  
  13.               .end = GPNCON + 8,  
  14.               .flags = IORESOURCE_MEM,//内存地址资源  
  15.           },  
  16.     [1] = {  
  17.               .start = S3C_EINT(0),//按键中断资源  
  18.               .end = S3C_EINT(5),  
  19.               .flags = IORESOURCE_IRQ,//内存地址资源  
  20.           },  
  21. };  
  22.   
  23. struct platform_device key_device =   
  24. {  
  25.     .name = "my_key",  
  26.     .id = 0,  
  27.     .num_resources = ARRAY_SIZE(key_resource),  
  28.     .resource = key_resource,  
  29. };  
  30.   
  31. int keydri_init(void)  
  32. {  
  33.     platform_device_register(&key_device);  
  34.     return 0;  
  35. }  
  36.   
  37. void keydri_exit(void)  
  38. {  
  39.     platform_device_unregister(&key_device);  
  40. }  
  41.   
  42. module_init(keydri_init);  
  43. module_exit(keydri_exit);  

编译运行截图:

 



key_dri.c

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. #include <linux/module.h>  
  2. #include <linux/init.h>  
  3. #include <linux/miscdevice.h> /* for struct miscdevice*/  
  4. #include <linux/interrupt.h>  
  5. #include <linux/fs.h> /* for iormap */  
  6. #include <linux/io.h>  
  7. #include <linux/slab.h> /* for kmalloc */  
  8. #include<linux/uaccess.h> /* for copy_to_usr */  
  9. #include <linux/platform_device.h>  
  10.   
  11. //#define GPNCON  0x7F008830  
  12. //#define GPNDAT  0x7F008834  
  13. MODULE_LICENSE("GPL");  
  14.   
  15. unsigned int *key_base;  
  16.   
  17. struct work_struct *work1;//定义一项工作  
  18.   
  19. struct timer_list key_timer; //定义一个定时器key_timer  
  20.   
  21. unsigned int key_num;  
  22.   
  23. struct resource *res_mem;  
  24. struct resource *res_irq;  
  25. int size;  
  26.   
  27. void work1_func(struct work_struct *work)  
  28. {  
  29.     //启动定时器 jiffies是全局变量,用来表示当前系统时间 1S=1000个滴答数  
  30.     mod_timer(&key_timer,jiffies + HZ/10); //设置100ms超时 1HZ=1S  
  31. }  
  32.   
  33. void key_timer_func(unsigned long data)  
  34. {  
  35.     unsigned int key_val;  
  36.       
  37.     key_val = readw(key_base + 1)&0x01; //只读取最后一位  
  38.     if(key_val == 0)  
  39.     {  
  40.         printk(KERN_WARNING"OK6410 key1 down!\n");  
  41.         key_num = 0;  
  42.     }  
  43.       
  44.     key_val = readw(key_base + 1)&0x20; //只读取最后一位  
  45.     if(key_val == 0)  
  46.     {  
  47.         printk(KERN_WARNING"OK6410 key6 down!\n");  
  48.         key_num = 6;  
  49.     }  
  50.   
  51. }  
  52.   
  53. irqreturn_t key_int(int irq, void *dev_id)  
  54. {  
  55.     //1. 检测是否发生了按键中断 这里可以暂时不做,因为这里没有使用共享中断  
  56.       
  57.     //2. 清除已经发生的按键中断 这个是指硬件内部处理,按键CPU内部不需要做处理  
  58.            
  59.     //3. 提交下半部  
  60.     schedule_work(work1);  
  61.       
  62.     //return 0;  
  63.     return IRQ_HANDLED;  
  64. }  
  65.   
  66. void key_hw_init(void) //按键硬件初始化部分  
  67. {  
  68.     //unsigned int *gpio_config;  
  69.     unsigned short data;  
  70.       
  71.     //gpio_config = ioremap(GPNCON, 4);//将物理地址转化为虚拟地址  
  72.     data = readw(key_base);  
  73.     data &= ~0b110000000011; //先清零  
  74.     data |= 0b100000000010;  //后两位设置成0b10  
  75.     writew(data, key_base);  
  76.       
  77.     //gpio_data = ioremap(GPNDAT, 4);//将物理地址转化为虚拟地址  
  78.       
  79.     printk(KERN_WARNING"init ...!\n");  
  80. }  
  81.   
  82. int key_open(struct inode *node, struct file *filp)  
  83. {  
  84.     printk(KERN_WARNING"open ...!\n");  
  85.       
  86.     return 0;  
  87. }  
  88.   
  89. ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)  
  90. {  
  91.     //将key_value值返回给用户空间  
  92.     printk(KERN_WARNING"in kernel :key num is %d\n",key_num);  
  93.     copy_to_user(buf, &key_num, 4); //buf为用户空间传过来的地址  
  94.       
  95.     return 4;  
  96. }  
  97.   
  98. struct file_operations key_fops =   
  99. {  
  100.     .open = key_open,  
  101.     .read = key_read,  
  102. };  
  103.   
  104. struct miscdevice key_miscdev = //定义一个misdevice结构  
  105. {  
  106.     .minor = 200,  
  107.     .name = "6410key",  
  108.     .fops = &key_fops,//这里key_fops是一个struct file_operations结构  
  109. };  
  110.   
  111. static int __devinit key_probe(struct platform_device *pdev)  
  112. {  
  113.   
  114.     misc_register(&key_miscdev);//注册一个混杂设备驱动设备  
  115.       
  116.     res_irq =  platform_get_resource(pdev, IORESOURCE_IRQ, 0); //取出中断资源  
  117.     request_irq(res_irq->start,key_int,IRQF_TRIGGER_FALLING,"my_key",(void *)1);  
  118.     request_irq(res_irq->end,key_int,IRQF_TRIGGER_FALLING,"my_key",(void *)6);  
  119.       
  120.     res_mem =  platform_get_resource(pdev, IORESOURCE_MEM, 0);//取出地址资源  
  121.       
  122.     size = res_mem->end - res_mem->start + 1;  
  123.     key_base = ioremap(res_mem->start,size);  
  124.       
  125.     key_hw_init();  
  126.       
  127.     work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);  
  128.     INIT_WORK(work1 , work1_func );  
  129.       
  130.     //初始化定时器  
  131.     init_timer(&key_timer);  
  132.     key_timer.function = key_timer_func; //将定义的函数赋值给函数指针  
  133.       
  134.     //注册定时器  
  135.     add_timer(&key_timer);  
  136.       
  137.           
  138.     return 0;  
  139.       
  140. }  
  141.   
  142. static int key_remove(struct platform_device *device)  
  143. {  
  144.     free_irq(S3C_EINT(0), 0);//注销中断 这里irqnumber参数暂时用一个变量来表示(中断号)  
  145.     free_irq(S3C_EINT(5), 0);//注销中断 这里irqnumber参数暂时用一个变量来表示(中断号)  
  146.       
  147.     misc_deregister(&key_miscdev);//注销一个混杂设备驱动  
  148.       
  149.     return 0;  
  150. }  
  151.   
  152. struct platform_driver key_driver =   
  153. {  
  154.     .driver     = {  
  155.         .name   = "my_key",  
  156.         .owner  = THIS_MODULE,  
  157.     },  
  158.     .probe      = key_probe,  
  159.     .remove     = key_remove,  
  160. };  
  161.   
  162. static int key_init(void)  
  163. {  
  164.       
  165.     return platform_driver_register(&key_driver);  
  166.       
  167. }  
  168.   
  169. static void key_exit(void)  
  170. {  
  171.   
  172.     platform_driver_register(&key_driver);//卸载平台驱动  
  173.       
  174.     printk(KERN_WARNING"key up!");  
  175. }  
  176.   
  177. module_init(key_init);  
  178. module_exit(key_exit);  
  179. MODULE_LICENSE("GPL");  
  180. MODULE_DESCRIPTION("key driver");  

Makefile

 

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. obj-m := key_dev.o key_dri.o  
  2. KDIR := /home/kernel/linux-ok6410  
  3. all:  
  4.     make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm  
  5. clean:  
  6.     rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order  

编译运行效果截图:

 



按下按键1或者按下按键6 可以看到驱动程序打印出如下信息! 这里或者创建设备文件,然后用前面博客里面的应用程序来测试也是一样的!

转载于:https://www.cnblogs.com/zzb-Dream-90Time/p/6255231.html


http://www.niftyadmin.cn/n/3336787.html

相关文章

混杂设备动态次设备号分析【转】

本文转载自&#xff1a;http://blog.csdn.net/yongan1006/article/details/6778285 今天看驱动源码时&#xff0c;发现一个MISC_DYNAMIC_MINOR宏&#xff0c;于是分析了一下内核源码。先粘出源码。在misc_register函数中&#xff0c;有如下语句&#xff1a; if (misc->minor…

Linux的fasync驱动异步通知详解【转】

本文转载自&#xff1a;http://blog.csdn.net/coding__madman/article/details/51851338 版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 工作项目用有个需求是监测某个GPIO输入方波的频率&#xff01;通俗的讲就是一个最最简单的测方波频率的示波…

如何将.m4a转.wav文件

昨天现场交付的同事找到我&#xff0c;想把一个.m4a格式的文件转为.wav文件&#xff0c;目的是可以使得现场的媒体服务器将语音播放出来。 我习惯性的打开了adobe audition文件打开语音进行转换&#xff0c;但是该软件提示找不到acc.dll文件。我下载acc.dll文件后&#xff0c;通…

GPIO口及中断API函数【转】

本文转载自&#xff1a;http://blog.sina.com.cn/s/blog_a6559d9201015vx9.htmlG #include <linux/gpio.h> // 标准 GPIO_API int gpio_request(unsigned gpio, const char *label); 获得并占有 GPIO port 的使用权&#xff0c;由参数 gpio 指定具体 port&#xff0c;非空…

Hudson、Jenkins的node节点设置(分布式处理自动化测试用例)

Hudson中分布式部署&#xff0c;node节点设置&#xff0c;假如有2台windwos机器&#xff08;192.168.200.132、192.168.200.133&#xff09;作为SLAVE机器。其实Master/Slave相当于Server和agent的概念。 http://www.cnblogs.com/itech/archive/2011/11/11/2245849.html 新建一…

【Swift】学习笔记(六)——函数

函数 懂编程语言的来说这个是最主要的了&#xff0c;不论什么语言都有函数这个概念。函数就是完毕特定任务的独立代码块。 函数怎么创建&#xff1a; 1、创建一个无參无返回值的函数(实际上全部的函数都有返回值&#xff0c;这个函数返回void&#xff0c;它是一个空元组) func…

媒体服务器(MS)抢救记

文章目录前言一、abrt获取core文件二、gdb分析coredump文件三、sipp模拟呼叫三、valrind工具总结前言 当媒体服务器发行故障后&#xff0c;先后通过分析SIP信令及媒体服务器抓包及服务器日志&#xff0c;定位媒体服务器网元出现故障。 通过abrt抓取进程异常的core文件&#xf…

Linux驱动程序学习【转】

本文转载自&#xff1a; 一直在学习驱动&#xff0c;对于下面这篇文章&#xff0c;本人觉得简洁明了&#xff0c;基本符合我们学习驱动的进度与过程&#xff0c;现转发到自己的博客&#xff0c;希望能与更多的朋友分享。 了解Linux驱动程序技巧学习的方法很重要&#xff0c;学习…