zoukankan      html  css  js  c++  java
  • linux平台总线驱动设备模型之点亮LED

    这一节里,我们来使用平台驱动设备这一套架构来实现我们之前使用简单的字符设备驱动点亮LED,这里并无实际意义,只是告诉大家如果编写平台总线驱动设备。

    问:如何编写平台总线驱动设备这一套架构的设备驱动?

    答:分为两个.c文件,一个是drv.c,另一个是dev.c;前者实现平台驱动,后者实现平台设备,平台总线不用我们自己实现。

    问:编写平台驱动的核心内容有哪些?

    答:分配、设置、注册一个platform_driver

    问:如何注册平台驱动?

    答:使用platform_driver_register(struct platform_driver *drv)函数,该函数的参数为platform_driver

    问:如何定义platform_driver?

    答:简单示例

    [cpp] view plain?
    1. static struct platform_driver led_driver = {  
    2.     .probe      = led_probe,  
    3.     .remove     = led_remove,  
    4.     .driver     = {  
    5.         .name   = "myled",  
    6.         .owner  = THIS_MODULE,  
    7.     }  
    8. };  
    问:probe函数什么时候被调用?

    答:当系统中有同名的平台设备和平台驱动时,就会调用probe函数。

    问:probe函数有什么作用?

    答:该函数可以做什么由你决定,你可以只打印一条语句,也可以做很复杂的事情。例如,led_probe函数就做了获取资源,映射IO,注册字符设备。

    led_drv.c源码参考:

    [cpp] view plain?
    1. #include <linux/module.h>  
    2.   
    3. #include <linux/init.h>  
    4. #include <linux/fs.h>  
    5. #include <linux/interrupt.h>  
    6. #include <linux/irq.h>  
    7. #include <linux/sched.h>  
    8. #include <linux/pm.h>  
    9. #include <linux/sysctl.h>  
    10. #include <linux/proc_fs.h>  
    11. #include <linux/delay.h>  
    12. #include <linux/platform_device.h>  
    13. #include <linux/input.h>  
    14. #include <linux/gpio_keys.h>  
    15. #include <asm/uaccess.h>   // copy_from_user  
    16. #include <asm/io.h>  // ioremap  
    17.   
    18. static struct class *led_cls;  
    19.   
    20. static volatile unsigned long *gpio_con;  
    21. static volatile unsigned long *gpio_dat;  
    22. static int pin;  
    23. static int major;  
    24.   
    25. static int led_open(struct inode * inode, struct file * filp)  
    26. {  
    27.     *gpio_con &= ~(0x3<<(pin*2));  
    28.     *gpio_con |= (0x1<<(pin*2));  
    29.     return 0;  
    30. }  
    31.   
    32. static ssize_t  
    33. led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)  
    34. {  
    35.     int val;  
    36.     copy_from_user(&val, buf, count);  
    37.     if(val == 1)  
    38.     {  
    39.         /* 点灯 */  
    40.         *gpio_dat  &= ~(1<<pin);   
    41.     }  
    42.     else  
    43.     {  
    44.         /* 灭灯 */  
    45.         *gpio_dat  |= (1<<pin);   
    46.     }  
    47.     return 0;  
    48. }  
    49.   
    50.   
    51. /* File operations struct for character device */  
    52. static const struct file_operations led_fops = {  
    53.     .owner      = THIS_MODULE,  
    54.     .open       = led_open,  
    55.     .write      = led_write,  
    56. };  
    57.   
    58. static int __devinit led_probe(struct platform_device *pdev)  
    59. {  
    60.     struct resource *res;  
    61.       
    62.     printk("led_probe, found led ");  
    63.     /* 根据platform_device的资源进行ioremap */  
    64.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
    65.     gpio_con =  ioremap(res->start, res->end - res->start + 1);  
    66.     gpio_dat = gpio_con + 1;  
    67.   
    68.     res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);  
    69.     pin =  res->start;  
    70.   
    71.     /* 注册字符设备 */  
    72.     major = register_chrdev(0, "myled", &led_fops);  
    73.       
    74.     led_cls = class_create(THIS_MODULE,"myled");  
    75.     device_create(led_cls, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */  
    76.     return 0;  
    77. }  
    78. static int __devexit led_remove(struct platform_device *pdev)  
    79. {  
    80.     printk("led_remove, remove led ");  
    81.     device_destroy(led_cls, MKDEV(major, 0));  
    82.     class_destroy(led_cls);  
    83.     unregister_chrdev(major, "myled");  
    84.     iounmap(gpio_con);  
    85.     return 0;  
    86. }  
    87.   
    88. static struct platform_driver led_driver = {  
    89.     .probe      = led_probe,  
    90.     .remove     = led_remove,  
    91.     .driver     = {  
    92.         .name   = "myled",  
    93.         .owner  = THIS_MODULE,  
    94.     }  
    95. };  
    96.   
    97. /* 分配/设置/注册一个platform_driver */  
    98. static int led_drv_init(void)  
    99. {  
    100.     return platform_driver_register(&led_driver);  
    101. }  
    102.   
    103. static void led_drv_exit(void)  
    104. {  
    105.     platform_driver_unregister(&led_driver);  
    106. }  
    107.   
    108. module_init(led_drv_init);  
    109. module_exit(led_drv_exit);  
    110.   
    111. MODULE_LICENSE("GPL");  
    112. MODULE_AUTHOR("LWJ");  
    113. MODULE_DESCRIPTION("Just for Demo");  


    问:编写平台设备驱动的核心内容有哪些?

    答:分配、设置、注册一个platform_device 

    问:如何注册平台设备?

    答:使用platform_device_register(struct platform_device *pdev)函数,该函数的参数为platform_device

    问:如何定义platform_device?

    答:简单示例:led_device

    [cpp] view plain?
    1. static struct platform_device led_device = {  
    2.     .id         = -1,  
    3.     .name       = "myled",  /* 与led_driver的name一致 */  
    4.     .resource       = led_resources,  
    5.     .num_resources  = ARRAY_SIZE(led_resources),  
    6.     .dev            ={  
    7.         .release    = led_release,  
    8.     },  
    9. };  
    问:如何定义resource?

    答:简单示例:

    [cpp] view plain?
    1. static struct resource led_resources[] = {  
    2.     [0] = {  
    3.         .start  = 0x56000010,      /* TQ2440的LED是GPB5,6,7,8, GPBCON地址是0x56000010 */  
    4.         .end    = 0x56000010 + 8 -1,  
    5.         .flags  = IORESOURCE_MEM,  
    6.     },  
    7.     [1] = {  
    8.         .start  = 5,        /* LED1 */  
    9.         .end    = 5,  
    10.         .flags  = IORESOURCE_IRQ,  
    11.     },  
    12. };  
    led_dev.c源码参考:

    [cpp] view plain?
    1. #include <linux/module.h>  
    2. #include <linux/version.h>  
    3.   
    4. #include <linux/init.h>  
    5.   
    6. #include <linux/kernel.h>  
    7. #include <linux/types.h>  
    8. #include <linux/interrupt.h>  
    9. #include <linux/list.h>  
    10. #include <linux/timer.h>  
    11. #include <linux/init.h>  
    12. #include <linux/serial_core.h>  
    13. #include <linux/platform_device.h>  
    14.   
    15. static struct resource led_resources[] = {  
    16.     [0] = {   //寄存器的起始地址
    17.         .start  = 0x56000010,      /* TQ2440的LED是GPB5,6,7,8, GPBCON地址是0x56000010 */  
    18.         .end    = 0x56000010 + 8 -1,  
    19.         .flags  = IORESOURCE_MEM,  
    20.     },  
    21.     [1] = {   //寄存器的哪一个引脚,以后可以修改这儿来操作让哪个led点亮
    22.         .start  = 5,        /* LED1 */  
    23.         .end    = 5,  
    24.         .flags  = IORESOURCE_IRQ,  
    25.     },  
    26. };  
    27.   
    28. static void led_release(struct device * dev)  
    29. {  
    30. }  
    31.           
    32. static struct platform_device led_device = {  
    33.     .id         = -1,  
    34.     .name       = "myled",  /* 与led_driver的name一致 */  
    35.     .resource       = led_resources,  
    36.     .num_resources  = ARRAY_SIZE(led_resources),  
    37.     .dev            ={  
    38.         .release    = led_release,  
    39.     },  
    40. };  
    41.   
    42. /* 分配/设置/注册一个platform_device */  
    43. static int led_dev_init(void)  
    44. {  
    45.     return platform_device_register(&led_device);  
    46. }  
    47.   
    48. static void led_dev_exit(void)  
    49. {  
    50.     platform_device_unregister(&led_device);  
    51. }  
    52.   
    53. module_init(led_dev_init);  
    54. module_exit(led_dev_exit);  
    55.   
    56. MODULE_LICENSE("GPL");  
    57. MODULE_AUTHOR("LWJ");  
    58. MODULE_DESCRIPTION("Just for Demo");  
    应用测试程序源码:

    [cpp] view plain?
    1. #include <sys/types.h>  
    2. #include <sys/stat.h>  
    3. #include <fcntl.h>  
    4. #include <stdio.h>  
    5.   
    6. /* 9th_led_test on 
    7.  * 9th_led_test off 
    8.  */  
    9. int main(int argc, char **argv)  
    10. {  
    11.     int fd;  
    12.     int val = 1;  
    13.     fd = open("/dev/led", O_RDWR);  
    14.     if (fd < 0)  
    15.     {  
    16.         printf("can't open! ");  
    17.     }  
    18.     if (argc != 2)  
    19.     {  
    20.         printf("Usage : ");  
    21.         printf("%s <on|off> ", argv[0]);  
    22.         return 0;  
    23.     }  
    24.   
    25.     if (strcmp(argv[1], "on") == 0)  
    26.     {  
    27.         val  = 1;  
    28.     }  
    29.     else  
    30.     {  
    31.         val = 0;  
    32.     }  
    33.       
    34.     write(fd, &val, 4);  
    35.     return 0;  
    36. }  
    测试步骤:

    [cpp] view plain?
    1. 9th_led_test        first_drv.ko        sddisk  
    2. Qt                  first_test          second_drv.ko  
    3. TQLedtest           fourth_drv.ko       second_test  
    4. app_test            fourth_test         sixth_drv.ko  
    5. bin                 home                sixth_test  
    6. busybox             led_dev.ko          sixthdrvtest  
    7. buttons_all_drv.ko  led_drv.ko          sys  
    8. buttons_all_test    lib                 third_drv.ko  
    9. buttons_input.ko    linuxrc             third_test  
    10. dev                 mnt                 tmp  
    11. driver_test         opt                 udisk  
    12. etc                 proc                usr  
    13. fifth_drv.ko        root                var  
    14. fifth_test          sbin                web  
    15. [WJ2440]# insmod led_drv.ko   
    16. [WJ2440]# insmod led_dev.ko   
    17. led_probe, found led  
    18. [WJ2440]# rmmod led_dev  
    19. led_remove, remove led  
    20. rmmod: module 'led_dev' not found  
    21. [WJ2440]# lsmod  
    22. led_drv 2800 0 - Live 0xbf003000  
    23. [WJ2440]# insmod led_dev.ko   
    24. led_probe, found led  
    25. [WJ2440]# lsmod  
    26. led_dev 1444 0 - Live 0xbf009000  
    27. led_drv 2800 0 - Live 0xbf003000  
    28. [WJ2440]# ls /dev/led -l   
    29. crw-rw----    1 root     root      252,   0 Jan  2 07:44 /dev/led  
    30. [WJ2440]# ./9th_led_test   
    31. Usage :  
    32. ./9th_led_test <on|off>  
    33. [WJ2440]# ./9th_led_test off  
    34. [WJ2440]# ./9th_led_test on   
    当执行./9th_led_test off时,led1被熄灭;当执行./9th_led_test on时 led1被点亮。如果你需要点亮led2,那么只需要修改led_dev的led_resources改为:
    [cpp] view plain?
    1. static struct resource led_resources[] = {  
    2.     [0] = {  
    3.         .start  = 0x56000010,      /* TQ2440的LED是GPB5,6,7,8, GPBCON地址是0x56000010 */  
    4.         .end    = 0x56000010 + 8 -1,  
    5.         .flags  = IORESOURCE_MEM,  
    6.     },  
    7.     [1] = {  
    8.         .start  = 6,        /* LED2 */  
    9.         .end    = 6,  
    10.         .flags  = IORESOURCE_IRQ,  
    11.     },  
    12. };  
    这样,应用程序不用更改,即可点亮led2,这样一来就实现了,稳定部分不用修改,只需要修改硬件易变部分,并且应用程序不需要任何更改。
  • 相关阅读:
    7、配置私有仓库
    springcloud服务调用 list集合解析错误处理方法
    Mybatis-Plus 条件构造器的使用
    Mybatis-Plus 自定义sql
    Navicat Premium 15 安装与激活
    使用阿里云短信验证
    vue+element 表单el-radio单选框回显不能被选中问题
    类似性别(0、1)判断的table列表数据渲染
    使用docker 简单部署 ElasticSearch 以及 ElasticSearch-Head
    docker 配置镜像加速
  • 原文地址:https://www.cnblogs.com/alan666/p/8312428.html
Copyright © 2011-2022 走看看