码迷,mamicode.com
首页 > 其他好文 > 详细

fl2440 platform总线button字符设备驱动

时间:2016-06-12 15:12:30      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:

驱动程序:

  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!\n");
153             button_device.status[num] = BUTTON_DOWN;
154 
155             printk("%s pressed.\n", 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!\n");
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.\n", 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.\n", 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\n", 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.\n");
262              return -EAGAIN;
263          }
264          else                                                                    //阻塞模式加入等待队列
265          {
266              /* Read() will be blocked here */
267              dbg_print("read() blocked here now.\n");
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\n", 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\n", 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\n",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.\n", 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.\n", 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\n", 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\n", __FUNCTION__, ret); 
428         goto fail_reg_plat_dev;
429    }
430    dbg_print("Regist S3C %s Device successfully.\n", 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\n", __FUNCTION__, ret); 
436         goto fail_reg_plat_drv;
437    }
438    dbg_print("Regist S3C %s Driver successfully.\n", 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.\n", DEV_NAME);
453 
454     platform_device_unregister(&s3c_button_device);
455     dbg_print("S3C %s platform driver removed.\n", 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 /*********************************************************************************
  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!\n");
 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!\n");
 48         exit(1);
 49     }
 50 
 51     printf("Start select....\n");
 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\n");
 63             exit(1);
 64         }
 65 
 66         if (ret == 0)
 67         {
 68             printf("select timeout\n");
 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 }

 

#include "s3c_driver.h"
#define DRV_DESC                  "S3C24XX button driver"
/* Driver version*/#define DRV_MAJOR_VER             1#define DRV_MINOR_VER             0#define DRV_REVER_VER             0
#define DEV_NAME                  DEV_BUTTON_NAME
//#define DEV_MAJOR               DEV_BUTTON_MAJOR#ifndef DEV_MAJOR#define DEV_MAJOR                 0 /* dynamic major by default */#endif
#define BUTTON_UP                 0 /* Button status is up */#define BUTTON_DOWN               1 /* Button status is pushed down */#define BUTTON_UNCERTAIN          2 /* Button status uncerntain */
#define TIMER_DELAY_DOWN          (HZ/50)   /*Remove button push down dithering timer delay 20ms  */#define TIMER_DELAY_UP            (HZ/10)   /*Remove button up dithering timer delay 100ms  */
static int debug = DISABLE;static int dev_major = DEV_MAJOR;static int dev_minor = 0;

/*============================ Platform Device part ===============================*//* Button hardware informtation structure*/struct s3c_button_info//定义按键结构体信息{    unsigned char           num;       /*Button nubmer  *///第几个按键    char *                  name;      /*Button nubmer  *///按键名称    int                     nIRQ;      /*Button IRQ number*///按键中断号    unsigned int            setting;   /*Button IRQ Pin Setting*///对应管脚设置为中断模式    unsigned int            gpio;      /*Button GPIO port *///按键对应管脚};
/* The button plaotform device private data structure */struct s3c_button_platform_data//定义一个platform总线的按键结构体{    struct s3c_button_info *buttons;    int                     nbuttons;};
/* Button hardware informtation data*/static struct s3c_button_info  s3c_buttons[] = {//定义每个按键的结构体信息    [0] = {        .num = 1,        .name = "KEY1",        .nIRQ = IRQ_EINT0,        .gpio = S3C2410_GPF(0),        .setting = S3C2410_GPF0_EINT0,    },    [1] = {        .num = 2,        .name = "KEY2",        .nIRQ = IRQ_EINT2,        .gpio = S3C2410_GPF(2),        .setting = S3C2410_GPF2_EINT2,    },    [2] = {        .num = 3,        .name = "KEY3",        .nIRQ = IRQ_EINT3,        .gpio = S3C2410_GPF(3),        .setting = S3C2410_GPF3_EINT3,    },    [3] = {        .num = 4,        .name = "KEY4",        .nIRQ = IRQ_EINT4,        .gpio = S3C2410_GPF(4),        .setting = S3C2410_GPF4_EINT4,    },};
/* The button platform device private data */static struct s3c_button_platform_data s3c_button_data = {//定义button的结构体信息    .buttons = s3c_buttons,//每个button的信息    .nbuttons = ARRAY_SIZE(s3c_buttons),//button的数量};
struct button_device//定义一个button_device的结构体{    unsigned char                      *status;      /* The buttons Push down or up status */    struct s3c_button_platform_data    *data;        /* The buttons hardware information data */
    struct timer_list                  *timers;      /* The buttons remove dithering timers */    wait_queue_head_t                  waitq;           /* Wait queue for poll()  */    volatile int                       ev_press;     /* Button pressed event */
    struct cdev                        cdev;               struct class                       *dev_class; } button_device;
static void platform_button_release(struct device * dev){    return; }
static struct platform_device s3c_button_device = {//设备节点结构体    .name    = "s3c_button",    .id      = 1,    .dev     =     {        .platform_data = &s3c_button_data,         .release = platform_button_release,    },};
static irqreturn_t s3c_button_intterupt(int irq,void *de_id)//中断处理程序{    int i;    int found = 0;    struct s3c_button_platform_data *pdata = button_device.data;
    for(i=0; i<pdata->nbuttons; i++)    {        if(irq == pdata->buttons[i].nIRQ)//发现某个按键有下降沿        {            found = 1;             break;        }    }
    if(!found) /* An ERROR interrupt  *///内核报中断没有中断,返回错误,基本不会发生        return IRQ_NONE;
    /* Only when button is up then we will handle this event */    if(BUTTON_UP  == button_device.status[i])    {       button_device.status[i] = BUTTON_UNCERTAIN;       mod_timer(&(button_device.timers[i]), jiffies+TIMER_DELAY_DOWN);    }
    return IRQ_HANDLED;}

static void button_timer_handler(unsigned long data){    struct s3c_button_platform_data *pdata = button_device.data;    int num =(int)data;    int status = s3c2410_gpio_getpin( pdata->buttons[num].gpio );
    if(LOWLEVEL == status)    {        if(BUTTON_UNCERTAIN == button_device.status[num]) /* Come from interrupt */        {            //dbg_print("Key pressed!\n");            button_device.status[num] = BUTTON_DOWN;
            printk("%s pressed.\n", pdata->buttons[num].name);
            /* Wake up the wait queue for read()/poll() */            button_device.ev_press = 1;            wake_up_interruptible(&(button_device.waitq));        }
        /* Cancel the dithering  */        mod_timer(&(button_device.timers[num]), jiffies+TIMER_DELAY_UP);    }    else    {        //dbg_print("Key Released!\n");        button_device.status[num] = BUTTON_UP;     //   enable_irq(pdata->buttons[num].nIRQ);    }
    return ;}

/*===================== Button device driver part ===========================*/
static int button_open(struct inode *inode, struct file *file)//打开按键{     struct button_device *pdev ;    struct s3c_button_platform_data *pdata;    int i, result;
    pdev = container_of(inode->i_cdev,struct button_device, cdev);//通过i_cdev找到cdev结构体    pdata = pdev->data;    file->private_data = pdev;
    /* Malloc for all the buttons remove dithering timer */    pdev->timers = (struct timer_list *) kmalloc(pdata->nbuttons*sizeof(struct timer_list), GFP_KERNEL);//为cdev结构体中的timer分配内存    if(NULL == pdev->timers)    {        printk("Alloc %s driver for timers failure.\n", DEV_NAME);        return -ENOMEM;    }    memset(pdev->timers, 0, pdata->nbuttons*sizeof(struct timer_list));//初始化timer内存
    /* Malloc for all the buttons status buffer */    pdev->status = (unsigned char *)kmalloc(pdata->nbuttons*sizeof(unsigned char), GFP_KERNEL);//为button状态分配内存空间    if(NULL == pdev->status)    {        printk("Alloc %s driver for status failure.\n", DEV_NAME);        result = -ENOMEM;         goto  ERROR;    }    memset(pdev->status, 0, pdata->nbuttons*sizeof(unsigned char));//初始化状态内存
    init_waitqueue_head(&(pdev->waitq));//加入等待队列
    for(i=0; i<pdata->nbuttons; i++) //初始化button信息    {        /* Initialize all the buttons status to UP  */        pdev->status[i] = BUTTON_UP; //设置为未按
        /* Initialize all the buttons‘ remove dithering timer */        setup_timer(&(pdev->timers[i]), button_timer_handler, i);//设置定时器及调用函数
        /* Set all the buttons GPIO to EDGE_FALLING interrupt mode */        s3c2410_gpio_cfgpin(pdata->buttons[i].gpio, pdata->buttons[i].setting);//配置成中断模式        irq_set_irq_type(pdata->buttons[i].nIRQ, IRQ_TYPE_EDGE_FALLING);//中断采用下降沿触发
        /* Request for button GPIO pin interrupt  */        result = request_irq(pdata->buttons[i].nIRQ, s3c_button_intterupt, IRQF_DISABLED, DEV_NAME, (void *)i);//注册给内核,一旦发生pdata->buttons[i].nIRQ中断号的中断之后,调用s3c_button_intterupt中断处理程序        if( result )        {            result = -EBUSY;            goto ERROR1;        }    }
    return 0;
ERROR1://出错反向退出     kfree((unsigned char *)pdev->status);     while(--i)      {          disable_irq(pdata->buttons[i].nIRQ);          free_irq(pdata->buttons[i].nIRQ, (void *)i);      }
ERROR:     kfree(pdev->timers);
     return result;}
static int button_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)//读按键信息函数{     struct button_device *pdev = file->private_data;    struct s3c_button_platform_data *pdata;    int   i, ret;    unsigned int status = 0;
    pdata = pdev->data;
    dbg_print("ev_press: %d\n", pdev->ev_press);    if(!pdev->ev_press)//按键没有按下    {         if(file->f_flags & O_NONBLOCK)//如果是非阻塞模式则返回EAGAIN         {             dbg_print("read() without block mode.\n");             return -EAGAIN;         }         else//阻塞模式加入等待队列         {             /* Read() will be blocked here */             dbg_print("read() blocked here now.\n");             wait_event_interruptible(pdev->waitq, pdev->ev_press);//加入等待队列         }    }
    pdev->ev_press = 0;//将按键设置为未按下
    for(i=0; i<pdata->nbuttons; i++)//读出按键状态并保存在status中    {        dbg_print("button[%d] status=%d\n", i, pdev->status[i]);        status |= (pdev->status[i]<<i); //这里的status[i]是如何保存各个按键状态信息的?    }
    ret = copy_to_user(buf, (void *)&status, min(sizeof(status), count));//将此按键信息发送给用户空间
    return ret ? -EFAULT : min(sizeof(status), count);}
static unsigned int button_poll(struct file *file, poll_table * wait)//监视button函数{     struct button_device *pdev = file->private_data;    unsigned int mask = 0;
    poll_wait(file, &(pdev->waitq), wait);//加入等待队列    if(pdev->ev_press)    {        mask |= POLLIN | POLLRDNORM; /* The data aviable */ //按键按下设置mask值    }
    return mask;}
static int button_release(struct inode *inode, struct file *file){     int i;    struct button_device *pdev = file->private_data;    struct s3c_button_platform_data *pdata;    pdata = pdev->data;
    for(i=0; i<pdata->nbuttons; i++)     {        disable_irq(pdata->buttons[i].nIRQ);//关中断        free_irq(pdata->buttons[i].nIRQ, (void *)i);//删中断        del_timer(&(pdev->timers[i]));//取消timer    }
    kfree(pdev->timers);//释放timer内存    kfree((unsigned char *)pdev->status);//释放申请的status内存
    return 0;}

static struct file_operations button_fops = { //功能函数    .owner = THIS_MODULE,    .open = button_open,     .read = button_read,    .poll = button_poll,     .release = button_release, };

static int s3c_button_probe(struct platform_device *dev){    int result = 0;    dev_t devno;

    /* Alloc the device for driver  */     if (0 != dev_major)     {         devno = MKDEV(dev_major, dev_minor);         result = register_chrdev_region(devno, 1, DEV_NAME);     }     else     {         result = alloc_chrdev_region(&devno, dev_minor, 1, DEV_NAME);         dev_major = MAJOR(devno);     }
    /* Alloc for device major failure */    if (result < 0)     {         printk("%s driver can‘t get major %d\n", DEV_NAME, dev_major);         return result;     }
    /*  Initialize button_device structure and register cdev*/     memset(&button_device, 0, sizeof(button_device));     button_device.data = dev->dev.platform_data;     cdev_init (&(button_device.cdev), &button_fops);     button_device.cdev.owner  = THIS_MODULE;
     result = cdev_add (&(button_device.cdev), devno , 1);      if (result)      {          printk (KERN_NOTICE "error %d add %s device", result, DEV_NAME);          goto ERROR;      }
     button_device.dev_class = class_create(THIS_MODULE, DEV_NAME);      if(IS_ERR(button_device.dev_class))      {          printk("%s driver create class failture\n",DEV_NAME);          result =  -ENOMEM;          goto ERROR;      }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)          device_create(button_device.dev_class, NULL, devno, NULL, DEV_NAME);#else     device_create (button_device.dev_class, NULL, devno, DEV_NAME);#endif
     printk("S3C %s driver version %d.%d.%d initiliazed.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);
     return 0;
ERROR:      printk("S3C %s driver version %d.%d.%d install failure.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);     cdev_del(&(button_device.cdev));      unregister_chrdev_region(devno, 1);     return result;}

static int s3c_button_remove(struct platform_device *dev){    dev_t devno = MKDEV(dev_major, dev_minor);
    cdev_del(&(button_device.cdev));    device_destroy(button_device.dev_class, devno);    class_destroy(button_device.dev_class);
    unregister_chrdev_region(devno, 1);     printk("S3C %s driver removed\n", DEV_NAME);
    return 0;}

/*===================== Platform Device and driver regist part ===========================*/
static struct platform_driver s3c_button_driver = {     .probe      = s3c_button_probe,     .remove     = s3c_button_remove,     .driver     = {         .name       = "s3c_button",         .owner      = THIS_MODULE,     },};

static int __init s3c_button_init(void){   int       ret = 0;
   ret = platform_device_register(&s3c_button_device);   if(ret)   {        printk(KERN_ERR "%s: Can‘t register platform device %d\n", __FUNCTION__, ret);         goto fail_reg_plat_dev;   }   dbg_print("Regist S3C %s Device successfully.\n", DEV_NAME);
   ret = platform_driver_register(&s3c_button_driver);   if(ret)   {        printk(KERN_ERR "%s: Can‘t register platform driver %d\n", __FUNCTION__, ret);         goto fail_reg_plat_drv;   }   dbg_print("Regist S3C %s Driver successfully.\n", DEV_NAME);
   return 0;
fail_reg_plat_drv:   platform_driver_unregister(&s3c_button_driver);fail_reg_plat_dev:   return ret;}

static void s3c_button_exit(void){    platform_driver_unregister(&s3c_button_driver);    dbg_print("S3C %s platform device removed.\n", DEV_NAME);
    platform_device_unregister(&s3c_button_device);    dbg_print("S3C %s platform driver removed.\n", DEV_NAME);}
module_init(s3c_button_init);module_exit(s3c_button_exit);
module_param(debug, int, S_IRUGO);module_param(dev_major, int, S_IRUGO);module_param(dev_minor, int, S_IRUGO);
MODULE_AUTHOR(DRV_AUTHOR);MODULE_DESCRIPTION(DRV_DESC);MODULE_LICENSE("GPL");MODULE_ALIAS("platform:S3C24XX_button");

fl2440 platform总线button字符设备驱动

标签:

原文地址:http://www.cnblogs.com/xiaohexiansheng/p/5577475.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!