zoukankan      html  css  js  c++  java
  • Linux平台设备驱动

    之前的一篇博客简单介绍了平台设备驱动模型(http://www.cnblogs.com/ape-ming/p/5107641.html),现在就根据那篇博客所列出来的模板把上一篇博客(http://www.cnblogs.com/ape-ming/p/5110996.html)的例程改成平台设备驱动模型。

    一、平台设备
    根据模板首先要写一个平台设备加载函数:

     1 /*
     2  *    函数名     : button_device_init
     3  *    函数功能: 设备加载
     4  */
     5 
     6 static int __init button_device_init(void)
     7 {
     8     int ret = 0;
     9 
    10     /* 注册平台设备 */
    11     platform_device_register(&button_platform_device);
    12     return ret;
    13 }

    在这个函数里面调用platform_device_register()对设备进行注册。这个时候就需要给定一个平台设备结构体button_platform_device:

    1 static struct platform_device button_platform_device = 
    2 {
    3     .name = "button_dev",
    4     .id = 0,
    5     .num_resources = ARRAY_SIZE(button_resource),
    6     .resource = button_resource,
    7 };

    根据模型在这个结构体里面需指定了设备资源button_resource:

     1 static struct resource button_resource[] = 
     2 {
     3     [0] = 
     4     {
     5         .start = IRQ_EINT(0),
     6         .end = IRQ_EINT(3),
     7         .flags = IORESOURCE_IRQ,
     8     },
     9     [1] = 
    10     {
    11         .start = (resource_size_t)S3C64XX_GPNDAT,
    12         .end = (resource_size_t)S3C64XX_GPNDAT,
    13         .flags = IORESOURCE_MEM,
    14     },
    15 };

    数组第一个元素指定了设备的中断号为IRQ_EINT(0)到IRQ_EINT(3),第二个元素指定了设备的IO资源。

    二、平台驱动
    平台驱动也要先写一个平台驱动加载函数:

     1 /*
     2  *    函数名     : button_driver_init
     3  *    函数功能: 驱动加载
     4  */
     5 
     6 static int __init button_driver_init(void)
     7 {
     8     int ret = 0;
     9     ret = platform_driver_register(&button_platform_driver);
    10     return ret;
    11 }

    在这里面完成了平台驱动的注册,接下来就要有一个平台驱动的结构体button_platform_driver:

     1 static struct platform_driver button_platform_driver = 
     2 {
     3     .probe = button_platform_probe,
     4     .remove = button_platform_remove,
     5     .driver = 
     6     {
     7         .owner = THIS_MODULE,
     8         .name = "button_dev",
     9     },
    10 };

    probe成员所指定的函数就是平台设备与驱动配置之后要执行的第一个函数,匹配的条件就是driver里面的name成员是不是和上面平台设备结构体里面的name成员一致。

     1 /*
     2  *    函数名     : button_platform_probe
     3  *    函数功能: 匹配驱动与设备
     4  */
     5 
     6 static int button_platform_probe(struct platform_device *button_device)
     7 {
     8     int ret = 0;
     9     int i = 0;
    10     int num = 0;
    11     struct resource* irq_resource;
    12     
    13     /* 注册混杂设备驱动 */
    14     ret = misc_register(&misc);
    15     if(ret)
    16     {
    17         printk("can't register miscdev
    ");
    18         return ret;
    19     }
    20 
    21     /* 填充数组 */
    22     irq_resource = platform_get_resource(button_device,IORESOURCE_IRQ,0);
    23     for(num = 0,i = irq_resource->start;i <= irq_resource->end;i++,num++)
    24     {
    25         button_irq[num].irq = i;
    26     }
    27     mem_resource = platform_get_resource(button_device,IORESOURCE_MEM,0);
    28     
    29     /* 申请外部中断 */
    30     for(i = 0;i < sizeof(button_irq)/sizeof(button_irq[0]);i++)
    31     {
    32         ret = request_irq(button_irq[i].irq,button_interrupt,IRQF_TRIGGER_FALLING,button_irq[i].name,(void*)&button_irq[i]);
    33         if(ret != 0)
    34         {
    35             printk("request_irq failure
    ");
    36         }
    37     }
    38 
    39     /* 初始化工作队列 */
    40     INIT_WORK(&button_work,do_buttons);
    41 
    42     /* 初始化内核定时器 */
    43     init_timer(&button_time);
    44     button_time.expires = jiffies + HZ/10;    //100ms
    45     button_time.function = button_do_time;
    46     add_timer(&button_time);
    47 
    48     return ret;
    49 }

    在button_platform_probe()函数中完成混杂设备驱动的注册、用platform_get_resource()获取设备的资源、申请外部中断、初始化工作队列、初始化内核定时器。其实就是把混杂设备驱动模型里面的设备注册函数和open函数所做的工作全部放到button_platform_probe()函数里面完成。之后的操作就跟混杂设备模型编写的按键驱动例程基本一样了。


    这里总结一下:平台设备驱动只是一个框架,其归根到底还是采用混杂设备驱动模型(或字符设备等)的方式进行驱动程序的编写。但是采用平台设备驱动的方式使得板级代码和驱动代码分离开来,在同一类型的驱动中只需要通过相应的函数获取设备资源和数据而不必要去修改驱动代码。

     完整代码:

     1 /*
     2  *    文件名     : button_device.c
     3  *    功能描述: 通过外部中断实现按键驱动程序,平台设备驱动方式
     4  *    驱动模型: platform
     5  *    设备节点: /dev/buttons6410
     6  *    MCU                : S3C6410
     7  *    端口连接: KEY0-GPN0  KEY1-GPN1  KEY2-GPN2  KEY3-GPN3
     8  */
     9 
    10 #include <linux/init.h>
    11 #include <linux/module.h>
    12 #include <linux/fs.h>
    13 #include <linux/device.h>
    14 #include <linux/kernel.h>
    15 #include <linux/irq.h>
    16 #include <linux/platform_device.h>
    17 
    18 #include <mach/gpio-bank-n.h>
    19 #include <mach/regs-gpio.h>
    20 #include <mach/map.h>
    21 #include <mach/regs-clock.h>
    22 #include <plat/gpio-cfg.h>
    23 
    24 
    25 
    26 static struct resource button_resource[] = 
    27 {
    28     [0] = 
    29     {
    30         .start = IRQ_EINT(0),
    31         .end = IRQ_EINT(3),
    32         .flags = IORESOURCE_IRQ,
    33     },
    34     [1] = 
    35     {
    36         .start = (resource_size_t)S3C64XX_GPNDAT,
    37         .end = (resource_size_t)S3C64XX_GPNDAT,
    38         .flags = IORESOURCE_MEM,
    39     },
    40 };
    41 
    42 static struct platform_device button_platform_device = 
    43 {
    44     .name = "button_dev",
    45     .id = 0,
    46     .num_resources = ARRAY_SIZE(button_resource),
    47     .resource = button_resource,
    48 };
    49 
    50 /*
    51  *    函数名     : button_device_init
    52  *    函数功能: 设备加载
    53  */
    54 
    55 static int __init button_device_init(void)
    56 {
    57     int ret = 0;
    58 
    59     /* 注册平台设备 */
    60     platform_device_register(&button_platform_device);
    61     return ret;
    62 }
    63 
    64 /*
    65  *    函数名     : button_device_exit
    66  *    函数功能: 设备卸载
    67  */
    68 
    69 static void __exit button_device_exit(void)
    70 {
    71     /* 注销平台设备*/
    72     platform_device_unregister(&button_platform_device);
    73 }
    74 
    75 module_init(button_device_init);
    76 module_exit(button_device_exit);
    77 MODULE_LICENSE("GPL");
      1 /*
      2  *    文件名     : button_driver.c
      3  *    功能描述: 通过外部中断实现按键驱动程序,平台设备驱动方式
      4  *    驱动模型: platform
      5  *    设备节点: /dev/buttons6410
      6  *    MCU                : S3C6410
      7  *    端口连接: KEY0-GPN0  KEY1-GPN1  KEY2-GPN2  KEY3-GPN3
      8  */
      9 
     10 #include <linux/module.h>
     11 #include <linux/kernel.h>
     12 #include <linux/fs.h>
     13 #include <linux/init.h>
     14 #include <linux/delay.h>
     15 #include <linux/poll.h>
     16 #include <linux/irq.h>
     17 #include <asm/irq.h>
     18 #include <asm/io.h>
     19 #include <linux/interrupt.h>
     20 #include <asm/uaccess.h>
     21 #include <mach/hardware.h>
     22 #include <linux/platform_device.h>
     23 #include <linux/cdev.h>
     24 #include <linux/miscdevice.h>
     25 
     26 #include <mach/map.h>
     27 #include <mach/regs-clock.h>
     28 #include <mach/regs-gpio.h>
     29 
     30 #include <plat/gpio-cfg.h>
     31 #include <mach/gpio-bank-n.h>
     32 #include <mach/gpio-bank-l.h>
     33 
     34 
     35 volatile int isKey_Pressed = 0;    // 按键按下标志 
     36 struct work_struct button_work;    //定义工作队列
     37 struct timer_list button_time;
     38 struct resource* mem_resource;
     39 struct button_irqs
     40 {
     41     unsigned int irq;
     42     int id;
     43     char* name;
     44 };
     45 
     46 static struct button_irqs button_irq[] = 
     47 {
     48     {0,0,"KEY0"},
     49     {0,1,"KEY1"},
     50     {0,2,"KEY2"},
     51     {0,3,"KEY3"},
     52 };
     53 
     54 /* 初始化等待队列 */
     55 DECLARE_WAIT_QUEUE_HEAD(q_buttons);
     56 
     57 static volatile int button_press[4] = {0};
     58 
     59 /*
     60  *    函数名     : do_buttons
     61  *    函数功能: 工作队列处理函数,处理按键工作
     62  */
     63 static void do_buttons(struct work_struct *work)
     64 {
     65     mod_timer(&button_time,jiffies + HZ/10);
     66 }
     67 
     68 /*
     69  *    函数名     : button_interrupt
     70  *    函数功能: 外部中断服务程序
     71  */
     72 static irqreturn_t button_interrupt(int irq, void *dev_id)
     73 {
     74     struct button_irqs *button_id = (struct button_irqs*)dev_id;
     75     switch(button_id->id)
     76     {
     77         case 0:
     78         case 1:
     79         case 2:
     80         case 3:
     81         schedule_work(&button_work);
     82         break;
     83         default: break;
     84     }
     85     return IRQ_HANDLED;
     86 }
     87 
     88 /*
     89  *    函数名     : button_do_time
     90  *    函数功能: 内核定时器服务程序
     91  */
     92 
     93 static void button_do_time(unsigned long arg)
     94 {
     95     int i = 0;
     96     unsigned short tmp = 0;
     97     tmp = readw(mem_resource->start) & 0x000F;
     98     switch(tmp)
     99     {
    100         case 0x0E:
    101             button_press[0] = 1;
    102         break;
    103         case 0x0D:
    104             button_press[1] = 1;
    105         break;
    106         case 0x0B:
    107             button_press[2] = 1;
    108         break;
    109         case 0x07:
    110             button_press[3] = 1;
    111         break;
    112     }
    113     for(i = 0;i < sizeof(button_press)/sizeof(button_press[0]);i++)
    114     {
    115         if(button_press[i] == 0)
    116             continue;
    117             
    118         isKey_Pressed = 1;
    119 
    120         /* 唤醒等待队列 */
    121         wake_up_interruptible(&q_buttons);
    122         break;
    123     }
    124     
    125 }
    126 
    127 
    128 /*
    129  *    函数名     : button_open
    130  *    函数功能: 文件打开
    131  */
    132 static int button_open(struct inode *node, struct file *filp)
    133 {
    134     return 0;
    135 }
    136 
    137 /*
    138  *    函数名     : button_read
    139  *    函数功能: 文件读
    140  */
    141 static ssize_t button_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
    142 {
    143     ssize_t ret = 0;
    144     size_t size = min(count,sizeof(button_press));
    145 
    146     /* 等待队列唤醒 */
    147     wait_event_interruptible(q_buttons,isKey_Pressed);
    148     isKey_Pressed = 0;
    149     
    150     if(copy_to_user((void*)buffer,(const void*)&button_press,size))
    151     {
    152         ret = -1;
    153         printk("copy to user failure
    ");
    154     }
    155     else
    156     {
    157         memset((void*)&button_press,0,sizeof(button_press));
    158         ret = size;
    159     }
    160     return ret;
    161 }
    162 
    163 
    164 static struct file_operations fops = 
    165 {
    166     .owner = THIS_MODULE,
    167     .open = button_open,
    168     .read = button_read,
    169 };
    170 
    171 static struct miscdevice misc = 
    172 {
    173     .minor = MISC_DYNAMIC_MINOR,
    174     .name = "buttons6410",
    175     .fops = &fops,
    176 };
    177 
    178 /*
    179  *    函数名     : button_platform_probe
    180  *    函数功能: 匹配驱动与设备
    181  */
    182 
    183 static int button_platform_probe(struct platform_device *button_device)
    184 {
    185     int ret = 0;
    186     int i = 0;
    187     int num = 0;
    188     struct resource* irq_resource;
    189     
    190     /* 注册混杂设备驱动 */
    191     ret = misc_register(&misc);
    192     if(ret)
    193     {
    194         printk("can't register miscdev
    ");
    195         return ret;
    196     }
    197 
    198     /* 填充数组 */
    199     irq_resource = platform_get_resource(button_device,IORESOURCE_IRQ,0);
    200     for(num = 0,i = irq_resource->start;i <= irq_resource->end;i++,num++)
    201     {
    202         button_irq[num].irq = i;
    203     }
    204     mem_resource = platform_get_resource(button_device,IORESOURCE_MEM,0);
    205     
    206     /* 申请外部中断 */
    207     for(i = 0;i < sizeof(button_irq)/sizeof(button_irq[0]);i++)
    208     {
    209         ret = request_irq(button_irq[i].irq,button_interrupt,IRQF_TRIGGER_FALLING,button_irq[i].name,(void*)&button_irq[i]);
    210         if(ret != 0)
    211         {
    212             printk("request_irq failure
    ");
    213         }
    214     }
    215 
    216     /* 初始化工作队列 */
    217     INIT_WORK(&button_work,do_buttons);
    218 
    219     /* 初始化内核定时器 */
    220     init_timer(&button_time);
    221     button_time.expires = jiffies + HZ/10;    //100ms
    222     button_time.function = button_do_time;
    223     add_timer(&button_time);
    224 
    225     return ret;
    226 }
    227 
    228 /*
    229  *    函数名     : button_platform_remove
    230  *    函数功能: 删除设备
    231  */
    232 
    233 static int button_platform_remove(struct platform_device *button_device)
    234 {
    235     int ret = 0;
    236     int i = 0;
    237 
    238     /* 释放中断 */
    239     for(i = 0;i < sizeof(button_irq)/sizeof(button_irq[0]);i++)
    240     {
    241         free_irq(button_irq[i].irq,(void*)&button_irq[i]);
    242     }
    243 
    244     /* 释放内核定时器 */
    245     del_timer(&button_time);
    246 
    247     /* 卸载混杂设备驱动 */
    248     misc_deregister(&misc);
    249 
    250     return ret;
    251 }
    252 
    253 static struct platform_driver button_platform_driver = 
    254 {
    255     .probe = button_platform_probe,
    256     .remove = button_platform_remove,
    257     .driver = 
    258     {
    259         .owner = THIS_MODULE,
    260         .name = "button_dev",
    261     },
    262 };
    263 
    264 /*
    265  *    函数名     : button_driver_init
    266  *    函数功能: 驱动加载
    267  */
    268 
    269 static int __init button_driver_init(void)
    270 {
    271     int ret = 0;
    272     ret = platform_driver_register(&button_platform_driver);
    273     return ret;
    274 }
    275 
    276 /*
    277  *    函数名     : button_driver_exit
    278  *    函数功能: 驱动卸载
    279  */
    280 
    281 static void __exit button_driver_exit(void)
    282 {
    283     platform_driver_unregister(&button_platform_driver);
    284 }
    285 
    286 module_init(button_driver_init);
    287 module_exit(button_driver_exit);
    288 MODULE_LICENSE("GPL");
  • 相关阅读:
    ★寒门再难出贵子?太现实了!【下】
    ★寒门再难出贵子?太现实了!【下】
    ★寒门再难出贵子?太现实了!【下】
    ★寒门再难出贵子?太现实了!!【上】
    ★寒门再难出贵子?太现实了!!【上】
    ★寒门再难出贵子?太现实了!!【上】
    Linux简介
    UTF-8编码规则【转】
    UTF-8编码规则【转】
    UTF-8编码规则【转】
  • 原文地址:https://www.cnblogs.com/ape-ming/p/5119007.html
Copyright © 2011-2022 走看看