• 3 linux bus-drv-dev模型 LED驱动实验


    1 bus-drv-dev模型简介

    前面的输入子系统,采用了分层设计,今天就引入驱动设计的分层分离的概念,linux系统中bus-drv-dev模型正是基于这种思想设计的。

    总线bus

    总线就是处理器与设备之间的一个通道,所有的设备通过总线和处理器连接,是一个虚拟的概念。在linux内核中被抽象为bus_type结构体,在include/linux/device.h文件中定义,代码如下图,其中成员match函数主要用于平台注册device和driver的时候,进行匹配用的。

    设备device

    device与硬件相关,被抽象为一个结构体。通过调用platform_device_add函数,将device放入到bus的dev链表中;再从bus的drv链表中取出每一个drv,通过bus的match函数判断drv是否支持dev;若支持,则可以调用drv的probe函数。

    驱动driver

    driver是关于操作硬件设备的稳定的代码,被抽象为一个结构体。同样的道理,调用platform_driver_register将drv放入到bus的drv链表中;在取出dev链表中的dev,通过bus的match函数比较;若有匹配的dev,则可以调用dev的probe函数。

    2 编写LED驱动

    (1)创建两个驱动文件led_dev.c和led_drv.c文件。

    (2)在led_dev.c文件中定义led_device结构体,在入口函数中调用platform_device_register函数注册设备,在出口函数中调用platform_device_unregister函数卸载设备。

    1. /* 分配/设置/注册一个platform_device */  
    2.     
    3. #include <linux/kernel.h>  
    4. #include <linux/types.h>  
    5. #include <linux/interrupt.h>  
    6. #include <linux/list.h>  
    7. #include <linux/timer.h>  
    8. #include <linux/init.h>  
    9. #include <linux/serial_core.h>  
    10. #include <linux/platform_device.h>  
    11.     
    12. static struct resource led_resource[] = {  
    13.     [0] = {  
    14.         .start = 0x56000050,  
    15.         .end   = 0x56000050 + 8 - 1,  
    16.         .flags = IORESOURCE_MEM,  
    17.     },  
    18.     [1] = {  
    19.         .start = 4,  
    20.         .end   = 4,  
    21.         .flags = IORESOURCE_IRQ,  
    22.     }  
    23.     
    24. };  
    25.     
    26. static void led_device_release(struct device * pdev)  
    27. {  
    28.     
    29. }  
    30.     
    31. static struct platform_device led_device = {  
    32.     .name               = "myled",  
    33.     .id                 = -1,  
    34.     .num_resources      = ARRAY_SIZE(led_resource),  
    35.     .resource           = led_resource,  
    36.     .dev = {  
    37.             .release = led_device_release,  
    38.     },  
    39. };  
    40.     
    41. int led_dev_init(void)  
    42. {  
    43.     platform_device_register(&led_device);  
    44.         
    45.     return 0;  
    46. }  
    47.     
    48.     
    49. void led_dev_exit()  
    50. {  
    51.     platform_device_unregister(&led_device);  
    52. }  
    53.     
    54.     
    55. module_init(led_dev_init);  
    56. module_exit(led_dev_exit);  
    57.     
    58. MODULE_LICENSE("GPL");  
      1. (3)led_drv.c文件中,首先定义结构体led_drv,主要实现led_drv_probe函数和led_drv_remove函数。在入口处调用platform_driver_register注册driver驱动,出口处调用platform_driver_unregister卸载驱动。
    59. /* 分配/设置/注册一个platform_drv */  
    60.     
    61. #include <linux/delay.h>  
    62. #include <linux/module.h>  
    63. #include <linux/kernel.h>  
    64. #include <linux/fs.h>  
    65. #include <linux/moduleparam.h>  
    66. #include <linux/interrupt.h>  
    67. #include <linux/ioport.h>  
    68. #include <linux/init.h>  
    69. #include <linux/serio.h>  
    70. #include <linux/err.h>  
    71. #include <linux/rcupdate.h>  
    72. #include <linux/platform_device.h>  
    73. #include <asm/uaccess.h>  
    74. #include <asm/irq.h>  
    75. #include <asm/io.h>  
    76. #include <asm/arch/regs-gpio.h>  
    77. #include <asm/hardware.h>  
    78.     
    79. int major = 0;  
    80. static struct class *cls;  
    81. static struct class_device *led_class_dev;  
    82. volatile unsigned long *gpfcon = NULL;  
    83. volatile unsigned long *gpfdat = NULL;  
    84. static int pin;  
    85.     
    86. static int led_drv_probe(struct platform_device *pdev);  
    87. static int led_drv_remove(struct platform_device *pdev);  
    88.     
    89. struct platform_driver led_drv = {  
    90.     .probe      = led_drv_probe,  
    91.     .remove     = led_drv_remove,  
    92.     .driver     = {  
    93.         .name   = "myled",  
    94.     }  
    95. };  
    96.     
    97. static int led_open(struct inode *inode, struct file *file)  
    98. {  
    99.     //printk("first_drv_open ");  
    100.     
    101.     /* 配置GPF456位输出 */  
    102.     *gpfcon &= ~(0x3<<(pin*2));  
    103.     *gpfcon |= (0x1<<(pin*2));  
    104.     return 0;  
    105. }  
    106.     
    107. static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)  
    108. {  
    109.     int val;  
    110.     //printk("first_drv_wrie ");  
    111.     
    112.     copy_from_user(&val, buf, count);       //  
    113.         
    114.     if(val == 1)  
    115.     {  
    116.         //亮灯  
    117.         *gpfdat &= ~(1<<pin);  
    118.     }  
    119.     else  
    120.     {  
    121.         //灭灯  
    122.         *gpfdat |= (1<<pin);  
    123.     }  
    124.     return 0;  
    125. }  
    126.     
    127. static struct file_operations led_drv_fops = {  
    128.     .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */  
    129.     .open   =   led_open,       
    130.     .write  =   led_write,  
    131. };  
    132.     
    133. static int led_drv_probe(struct platform_device *pdev)  
    134. {  
    135.     struct resource *res;  
    136.         
    137.     /* 根据platform_device的资源进行ioremap */  
    138.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
    139.     gpfcon = (volatile unsigned long *)ioremap(res->start, res->end - res->start +1);  
    140.     gpfdat = gpfcon + 1;  
    141.     
    142.     res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);  
    143.     pin = res->start;  
    144.         
    145.     /* 注册一个字符设备 */  
    146.     major = register_chrdev(0, "led", &led_drv_fops);  
    147.     
    148.     cls = class_create(THIS_MODULE, "leddrv");  
    149.     led_class_dev = class_device_create(cls, NULL, MKDEV(major, 0), NULL,"led");  
    150.     
    151.         
    152.     printk("led_drv_probe, found led ");  
    153.     return 0;  
    154. }  
    155.     
    156.     
    157. static int led_drv_remove(struct platform_device *pdev)  
    158. {  
    159.     /* 根据platform_device的资源进行iounmap */  
    160.     
    161.     /* 卸载一个字符设备 */  
    162.     class_device_unregister(led_class_dev);  
    163.     class_destroy(cls);  
    164.     unregister_chrdev(major, "myled");  
    165.     
    166.     iounmap(gpfcon);  
    167.         
    168.     printk("led_drv_remove, remove led ");  
    169.     return 0;  
    170. }  
    171.     
    172. int led_drv_init(void)  
    173. {  
    174.     platform_driver_register(&led_drv);  
    175.         
    176.     return 0;  
    177. }  
    178.     
    179.     
    180. void led_drv_exit()  
    181. {  
    182.     platform_driver_unregister(&led_drv);  
    183. }  
    184.     
    185.     
    186. module_init(led_drv_init);  
    187. module_exit(led_drv_exit);  
    188.     
    189. MODULE_LICENSE("GPL");  
  • 相关阅读:
    我有推特
    几大浏览器最新的javascript引擎
    有关表达式树
    路由跟踪命令
    利用httpwebrequest解析网站的文本文件
    技术的学习及一些总结
    nhibernate使用记录
    Introducing “Razor” – a new view engine for ASP.NET
    android属性设置
    android连续按两次返回退出程序
  • 原文地址:https://www.cnblogs.com/beijiqie1104/p/11434707.html
Copyright © 2020-2023  润新知