fl2440 platform总线button字符设备驱动

驱动程序:

  1 #include "s3c_driver.h"
  2 
  3 #define DRV_DESC                  "S3C24XX button driver"
  4 
  5 /* Driver version*/
  6 #define DRV_MAJOR_VER             1
  7 #define DRV_MINOR_VER             0
  8 #define DRV_REVER_VER             0
  9 
 10 #define DEV_NAME                  DEV_BUTTON_NAME
 11 
 12 //#define DEV_MAJOR               DEV_BUTTON_MAJOR
 13 #ifndef DEV_MAJOR
 14 #define DEV_MAJOR                 0 /* dynamic major by default */
 15 #endif
 16 
 17 #define BUTTON_UP                 0 /* Button status is up */
 18 #define BUTTON_DOWN               1 /* Button status is pushed down */
 19 #define BUTTON_UNCERTAIN          2 /* Button status uncerntain */
 20 
 21 #define TIMER_DELAY_DOWN          (HZ/50)   /*Remove button push down dithering timer delay 20ms  */
 22 #define TIMER_DELAY_UP            (HZ/10)   /*Remove button up dithering timer delay 100ms  */
 23 
 24 static int debug = DISABLE;
 25 static int dev_major = DEV_MAJOR;
 26 static int dev_minor = 0;
 27 
 28 
 29 /*============================ Platform Device part ===============================*/
 30 /* Button hardware informtation structure*/
 31 struct s3c_button_info                                            //定义按键结构体信息
 32 {
 33     unsigned char           num;       /*Button nubmer  */                        //第几个按键
 34     char *                  name;      /*Button nubmer  */                        //按键名称
 35     int                     nIRQ;      /*Button IRQ number*/                    //按键中断号
 36     unsigned int            setting;   /*Button IRQ Pin Setting*/                //对应管脚设置为中断模式
 37     unsigned int            gpio;      /*Button GPIO port */                    //按键对应管脚
 38 };
 39 
 40 /* The button plaotform device private data structure */
 41 struct s3c_button_platform_data                                    //定义一个platform总线的按键结构体
 42 {
 43     struct s3c_button_info *buttons;
 44     int                     nbuttons;
 45 };
 46 
 47 /* Button hardware informtation data*/
 48 static struct s3c_button_info  s3c_buttons[] = {                //定义每个按键的结构体信息
 49     [0] = {
 50         .num = 1,
 51         .name = "KEY1",
 52         .nIRQ = IRQ_EINT0,
 53         .gpio = S3C2410_GPF(0),
 54         .setting = S3C2410_GPF0_EINT0,
 55     },
 56     [1] = {
 57         .num = 2,
 58         .name = "KEY2",
 59         .nIRQ = IRQ_EINT2,
 60         .gpio = S3C2410_GPF(2),
 61         .setting = S3C2410_GPF2_EINT2,
 62     },
 63     [2] = {
 64         .num = 3,
 65         .name = "KEY3",
 66         .nIRQ = IRQ_EINT3,
 67         .gpio = S3C2410_GPF(3),
 68         .setting = S3C2410_GPF3_EINT3,
 69     },
 70     [3] = {
 71         .num = 4,
 72         .name = "KEY4",
 73         .nIRQ = IRQ_EINT4,
 74         .gpio = S3C2410_GPF(4),
 75         .setting = S3C2410_GPF4_EINT4,
 76     },
 77 };
 78 
 79 /* The button platform device private data */
 80 static struct s3c_button_platform_data s3c_button_data = {                    //定义button的结构体信息
 81     .buttons = s3c_buttons,                                                    //每个button的信息
 82     .nbuttons = ARRAY_SIZE(s3c_buttons),                                    //button的数量
 83 };
 84 
 85 struct button_device                                                        //定义一个button_device的结构体
 86 {
 87     unsigned char                      *status;      /* The buttons Push down or up status */
 88     struct s3c_button_platform_data    *data;        /* The buttons hardware information data */
 89 
 90     struct timer_list                  *timers;      /* The buttons remove dithering timers */
 91     wait_queue_head_t                  waitq;           /* Wait queue for poll()  */
 92     volatile int                       ev_press;     /* Button pressed event */
 93 
 94     struct cdev                        cdev;           
 95     struct class                       *dev_class; 
 96 } button_device;
 97 
 98 static void platform_button_release(struct device * dev)
 99 {
100     return; 
101 }
102 
103 static struct platform_device s3c_button_device = {                    //设备节点结构体
104     .name    = "s3c_button",
105     .id      = 1,
106     .dev     = 
107     {
108         .platform_data = &s3c_button_data, 
109         .release = platform_button_release,
110     },
111 };
112 
113 static irqreturn_t s3c_button_intterupt(int irq,void *de_id)        //中断处理程序
114 {
115     int i;
116     int found = 0;
117     struct s3c_button_platform_data *pdata = button_device.data;
118 
119     for(i=0; i<pdata->nbuttons; i++)
120     {
121         if(irq == pdata->buttons[i].nIRQ)                            //发现某个按键有下降沿
122         {
123             found = 1; 
124             break;
125         }
126     }
127 
128     if(!found) /* An ERROR interrupt  */                            //内核报中断没有中断,返回错误,基本不会发生
129         return IRQ_NONE;
130 
131     /* Only when button is up then we will handle this event */
132     if(BUTTON_UP  == button_device.status[i])                        
133     {
134        button_device.status[i] = BUTTON_UNCERTAIN;
135        mod_timer(&(button_device.timers[i]), jiffies+TIMER_DELAY_DOWN);
136     }
137 
138     return IRQ_HANDLED;
139 }
140 
141 
142 static void button_timer_handler(unsigned long data)
143 {
144     struct s3c_button_platform_data *pdata = button_device.data;
145     int num =(int)data;
146     int status = s3c2410_gpio_getpin( pdata->buttons[num].gpio );
147 
148     if(LOWLEVEL == status)
149     {
150         if(BUTTON_UNCERTAIN == button_device.status[num]) /* Come from interrupt */
151         {
152             //dbg_print("Key pressed!
");
153             button_device.status[num] = BUTTON_DOWN;
154 
155             printk("%s pressed.
", pdata->buttons[num].name);
156 
157             /* Wake up the wait queue for read()/poll() */
158             button_device.ev_press = 1;
159             wake_up_interruptible(&(button_device.waitq));
160         }
161 
162         /* Cancel the dithering  */
163         mod_timer(&(button_device.timers[num]), jiffies+TIMER_DELAY_UP);
164     }
165     else
166     {
167         //dbg_print("Key Released!
");
168         button_device.status[num] = BUTTON_UP;
169      //   enable_irq(pdata->buttons[num].nIRQ);
170     }
171 
172     return ;
173 }
174 
175 
176 /*===================== Button device driver part ===========================*/
177 
178 static int button_open(struct inode *inode, struct file *file)                                    //打开按键
179 { 
180     struct button_device *pdev ;
181     struct s3c_button_platform_data *pdata;
182     int i, result;
183 
184     pdev = container_of(inode->i_cdev,struct button_device, cdev);                                //通过i_cdev找到cdev结构体
185     pdata = pdev->data;
186     file->private_data = pdev;
187 
188     /* Malloc for all the buttons remove dithering timer */
189     pdev->timers = (struct timer_list *) kmalloc(pdata->nbuttons*sizeof(struct timer_list), GFP_KERNEL);            //为cdev结构体中的timer分配内存
190     if(NULL == pdev->timers)
191     {
192         printk("Alloc %s driver for timers failure.
", DEV_NAME);
193         return -ENOMEM;
194     }
195     memset(pdev->timers, 0, pdata->nbuttons*sizeof(struct timer_list));                            //初始化timer内存
196 
197     /* Malloc for all the buttons status buffer */
198     pdev->status = (unsigned char *)kmalloc(pdata->nbuttons*sizeof(unsigned char), GFP_KERNEL);                        //为button状态分配内存空间
199     if(NULL == pdev->status)    
200     {
201         printk("Alloc %s driver for status failure.
", DEV_NAME);
202         result = -ENOMEM; 
203         goto  ERROR;
204     }
205     memset(pdev->status, 0, pdata->nbuttons*sizeof(unsigned char));                                //初始化状态内存
206 
207     init_waitqueue_head(&(pdev->waitq));                                                        //加入等待队列
208 
209     for(i=0; i<pdata->nbuttons; i++)                                                             //初始化button信息
210     {
211         /* Initialize all the buttons status to UP  */
212         pdev->status[i] = BUTTON_UP;                                                             //设置为未按
213 
214         /* Initialize all the buttons' remove dithering timer */
215         setup_timer(&(pdev->timers[i]), button_timer_handler, i);                                //设置定时器及调用函数
216 
217         /* Set all the buttons GPIO to EDGE_FALLING interrupt mode */
218         s3c2410_gpio_cfgpin(pdata->buttons[i].gpio, pdata->buttons[i].setting);            //配置成中断模式
219         irq_set_irq_type(pdata->buttons[i].nIRQ, IRQ_TYPE_EDGE_FALLING);                //中断采用下降沿触发
220 
221         /* Request for button GPIO pin interrupt  */
222         result = request_irq(pdata->buttons[i].nIRQ, s3c_button_intterupt, IRQF_DISABLED, DEV_NAME, (void *)i);
223 //注册给内核,一旦发生pdata->buttons[i].nIRQ中断号的中断之后,调用s3c_button_intterupt中断处理程序
224         if( result )
225         {
226             result = -EBUSY;
227             goto ERROR1;
228         }
229     }
230 
231     return 0;
232 
233 ERROR1:                                                        //出错反向退出
234      kfree((unsigned char *)pdev->status);
235      while(--i) 
236      { 
237          disable_irq(pdata->buttons[i].nIRQ); 
238          free_irq(pdata->buttons[i].nIRQ, (void *)i); 
239      }
240 
241 ERROR:
242      kfree(pdev->timers);
243 
244      return result;
245 }
246 
247 static int button_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)                        //读按键信息函数
248 { 
249     struct button_device *pdev = file->private_data;
250     struct s3c_button_platform_data *pdata;
251     int   i, ret;
252     unsigned int status = 0;
253 
254     pdata = pdev->data;
255 
256     dbg_print("ev_press: %d
", pdev->ev_press);                                            
257     if(!pdev->ev_press)                                                            //按键没有按下
258     {
259          if(file->f_flags & O_NONBLOCK)                                            //如果是非阻塞模式则返回EAGAIN
260          {
261              dbg_print("read() without block mode.
");
262              return -EAGAIN;
263          }
264          else                                                                    //阻塞模式加入等待队列
265          {
266              /* Read() will be blocked here */
267              dbg_print("read() blocked here now.
");
268              wait_event_interruptible(pdev->waitq, pdev->ev_press);                //加入等待队列
269          }
270     }
271 
272     pdev->ev_press = 0;                                                            //将按键设置为未按下
273 
274     for(i=0; i<pdata->nbuttons; i++)                                            //读出按键状态并保存在status中
275     {
276         dbg_print("button[%d] status=%d
", i, pdev->status[i]);
277         status |= (pdev->status[i]<<i);                                         //这里的status[i]是如何保存各个按键状态信息的?
278     }
279 
280     ret = copy_to_user(buf, (void *)&status, min(sizeof(status), count));        //将此按键信息发送给用户空间
281 
282     return ret ? -EFAULT : min(sizeof(status), count);
283 }
284 
285 static unsigned int button_poll(struct file *file, poll_table * wait)            //监视button函数
286 { 
287     struct button_device *pdev = file->private_data;                            
288     unsigned int mask = 0;
289 
290     poll_wait(file, &(pdev->waitq), wait);                                        //加入等待队列
291     if(pdev->ev_press)
292     {
293         mask |= POLLIN | POLLRDNORM; /* The data aviable */                     //按键按下设置mask值
294     }
295 
296     return mask;
297 }
298 
299 static int button_release(struct inode *inode, struct file *file)
300 { 
301     int i;
302     struct button_device *pdev = file->private_data;
303     struct s3c_button_platform_data *pdata;
304     pdata = pdev->data;
305 
306     for(i=0; i<pdata->nbuttons; i++) 
307     {
308         disable_irq(pdata->buttons[i].nIRQ);                            //关中断
309         free_irq(pdata->buttons[i].nIRQ, (void *)i);                    //删中断
310         del_timer(&(pdev->timers[i]));                                    //取消timer
311     }
312 
313     kfree(pdev->timers);                                                //释放timer内存
314     kfree((unsigned char *)pdev->status);                                //释放申请的status内存
315 
316     return 0;
317 }
318 
319 
320 static struct file_operations button_fops = {                             //功能函数
321     .owner = THIS_MODULE,
322     .open = button_open, 
323     .read = button_read,
324     .poll = button_poll, 
325     .release = button_release, 
326 };
327 
328 
329 static int s3c_button_probe(struct platform_device *dev)    
330 {
331     int result = 0;
332     dev_t devno;
333 
334 
335     /* Alloc the device for driver  */ 
336     if (0 != dev_major) 
337     { 
338         devno = MKDEV(dev_major, dev_minor); 
339         result = register_chrdev_region(devno, 1, DEV_NAME); 
340     } 
341     else 
342     { 
343         result = alloc_chrdev_region(&devno, dev_minor, 1, DEV_NAME); 
344         dev_major = MAJOR(devno); 
345     }
346 
347     /* Alloc for device major failure */
348     if (result < 0) 
349     { 
350         printk("%s driver can't get major %d
", DEV_NAME, dev_major); 
351         return result; 
352     }
353 
354     /*  Initialize button_device structure and register cdev*/
355      memset(&button_device, 0, sizeof(button_device));
356      button_device.data = dev->dev.platform_data;
357      cdev_init (&(button_device.cdev), &button_fops);
358      button_device.cdev.owner  = THIS_MODULE;
359 
360      result = cdev_add (&(button_device.cdev), devno , 1); 
361      if (result) 
362      { 
363          printk (KERN_NOTICE "error %d add %s device", result, DEV_NAME); 
364          goto ERROR; 
365      }
366 
367      button_device.dev_class = class_create(THIS_MODULE, DEV_NAME); 
368      if(IS_ERR(button_device.dev_class)) 
369      { 
370          printk("%s driver create class failture
",DEV_NAME); 
371          result =  -ENOMEM; 
372          goto ERROR; 
373      }
374 
375 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)     
376      device_create(button_device.dev_class, NULL, devno, NULL, DEV_NAME);
377 #else
378      device_create (button_device.dev_class, NULL, devno, DEV_NAME);
379 #endif
380 
381      printk("S3C %s driver version %d.%d.%d initiliazed.
", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);
382 
383      return 0;
384 
385 ERROR: 
386      printk("S3C %s driver version %d.%d.%d install failure.
", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);
387      cdev_del(&(button_device.cdev)); 
388      unregister_chrdev_region(devno, 1);
389      return result;
390 }
391 
392 
393 static int s3c_button_remove(struct platform_device *dev)
394 {
395     dev_t devno = MKDEV(dev_major, dev_minor);
396 
397     cdev_del(&(button_device.cdev));
398     device_destroy(button_device.dev_class, devno);
399     class_destroy(button_device.dev_class);
400 
401     unregister_chrdev_region(devno, 1); 
402     printk("S3C %s driver removed
", DEV_NAME);
403 
404     return 0;
405 }
406 
407 
408 /*===================== Platform Device and driver regist part ===========================*/
409 
410 static struct platform_driver s3c_button_driver = { 
411     .probe      = s3c_button_probe, 
412     .remove     = s3c_button_remove, 
413     .driver     = { 
414         .name       = "s3c_button", 
415         .owner      = THIS_MODULE, 
416     },
417 };
418 
419 
420 static int __init s3c_button_init(void)
421 {
422    int       ret = 0;
423 
424    ret = platform_device_register(&s3c_button_device);
425    if(ret)
426    {
427         printk(KERN_ERR "%s: Can't register platform device %d
", __FUNCTION__, ret); 
428         goto fail_reg_plat_dev;
429    }
430    dbg_print("Regist S3C %s Device successfully.
", DEV_NAME);
431 
432    ret = platform_driver_register(&s3c_button_driver);
433    if(ret)
434    {
435         printk(KERN_ERR "%s: Can't register platform driver %d
", __FUNCTION__, ret); 
436         goto fail_reg_plat_drv;
437    }
438    dbg_print("Regist S3C %s Driver successfully.
", DEV_NAME);
439 
440    return 0;
441 
442 fail_reg_plat_drv:
443    platform_driver_unregister(&s3c_button_driver);
444 fail_reg_plat_dev:
445    return ret;
446 }
447 
448 
449 static void s3c_button_exit(void)
450 {
451     platform_driver_unregister(&s3c_button_driver);
452     dbg_print("S3C %s platform device removed.
", DEV_NAME);
453 
454     platform_device_unregister(&s3c_button_device);
455     dbg_print("S3C %s platform driver removed.
", DEV_NAME);
456 }
457 
458 module_init(s3c_button_init);
459 module_exit(s3c_button_exit);
460 
461 module_param(debug, int, S_IRUGO);
462 module_param(dev_major, int, S_IRUGO);
463 module_param(dev_minor, int, S_IRUGO);
464 
465 MODULE_AUTHOR(DRV_AUTHOR);
466 MODULE_DESCRIPTION(DRV_DESC);
467 MODULE_LICENSE("GPL");
468 MODULE_ALIAS("platform:S3C24XX_button");

按键驱动的两个重点:去抖、中断

编写中断程序需要注意的事情:1、Linux不支持中断嵌套  2、中断处理程序不可重用,不可阻塞

应用程序:

  1 /*********************************************************************************
  2  *      Copyright:  (C) 2016 2013dianxin_3
  3  *                  All rights reserved.
  4  *
  5  *       Filename:  buttonapp.c
  6  *    Description:  This file 
  7  *                 
  8  *        Version:  1.0.0(06/12/2016)
  9  *         Author:  xiaohexiansheng <1392195453@qq.com>
 10  *      ChangeLog:  1, Release initial version on "06/12/2016 01:42:50 PM"
 11  *                 
 12  ********************************************************************************/
 13 #include"plat_ioctl.h"
 14 #include<stdio.h>  
 15 #include<stdlib.h>  
 16 #include<fcntl.h>  
 17 #include<unistd.h>  
 18 #include<sys/ioctl.h>  
 19 #include<sys/time.h>  
 20 
 21 #define LED_OFF                   _IO (PLATDRV_MAGIC, 0x18)  
 22 #define LED_ON                    _IO (PLATDRV_MAGIC, 0x19)  
 23 #define BUTTON_STATUS  4   
 24 #define KEY1  0x1   
 25 #define KEY2  0x2   
 26 #define KEY3  0x4   
 27 #define KEY4  0x8   
 28 
 29 int main(int argc, char **argv) 
 30 {
 31     int button_fd;
 32     int led_fd;
 33     int ret;
 34     int but_status;
 35     fd_set rdfds;
 36 
 37     button_fd = open("/dev/button", O_RDWR);
 38     if (button_fd < 0)
 39     {
 40         printf("Open buttons device faild!
");
 41         exit(1);
 42     }
 43 
 44     led_fd = open("/dev/led", O_RDWR);
 45     if (led_fd < 0)
 46     {
 47         printf("Open led device faild!
");
 48         exit(1);
 49     }
 50 
 51     printf("Start select....
");
 52 
 53     FD_ZERO(&rdfds);
 54     FD_SET(button_fd, &rdfds);
 55 
 56     while (1)
 57     {
 58         ret = select(button_fd + 1, &rdfds, NULL, NULL, NULL);
 59         
 60         if (ret < 0)
 61         {
 62             printf("select failure
");
 63             exit(1);
 64         }
 65 
 66         if (ret == 0)
 67         {
 68             printf("select timeout
");
 69         }
 70 
 71         else if (ret > 0)
 72         {
 73             if (FD_ISSET(button_fd, &rdfds) > 0)
 74             {
 75                 read(button_fd, &but_status, sizeof(but_status));
 76             }
 77         }
 78 
 79         if (but_status & KEY1)
 80         {
 81             ioctl(led_fd, LED_ON, 0);
 82             sleep(1);
 83             ioctl(led_fd, LED_OFF, 0);
 84         }
 85 
 86         if (but_status & KEY2)
 87         {
 88             ioctl(led_fd, LED_ON, 1);
 89             sleep(1);
 90             ioctl(led_fd, LED_OFF, 1);
 91         }
 92 
 93         if (but_status & KEY3)
 94         {
 95             ioctl(led_fd, LED_ON, 2);
 96             sleep(1);
 97             ioctl(led_fd, LED_OFF, 2);
 98         }
 99 
100         if (but_status & KEY4)
101         {
102             ioctl(led_fd, LED_ON, 3);
103             sleep(1);
104             ioctl(led_fd, LED_OFF, 3);
105         }
106     }
107     
108     close(button_fd);
109     close(led_fd);
110     return 0;
111 }
原文地址:https://www.cnblogs.com/xiaohexiansheng/p/5577475.html