zoukankan      html  css  js  c++  java
  • 总线设备驱动模型【转】

    本文转载自: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!!! ");  
    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!!! ");  
    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! ");  
    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! ");  
    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 ...! ");  
    80. }  
    81.   
    82. int key_open(struct inode *node, struct file *filp)  
    83. {  
    84.     printk(KERN_WARNING"open ...! ");  
    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 ",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 可以看到驱动程序打印出如下信息! 这里或者创建设备文件,然后用前面博客里面的应用程序来测试也是一样的!

  • 相关阅读:
    SCCM2012 R2实战系列之七:软件分发(exe)
    man 手册--nc
    挂载虚拟机磁盘文件
    bond模式详解
    Windows下计算md5值
    man手册--iostat
    mount---挂载文件系统
    Linux-swap分区
    sync---强制将被改变的内容立刻写入磁盘
    vmstat---有关进程、虚存、页面交换空间及 CPU信息
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/6255231.html
Copyright © 2011-2022 走看看