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!\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 <[email protected]>
 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");

时间: 2024-10-05 20:21:47

fl2440 platform总线button字符设备驱动的相关文章

fl2440 platform总线led字符设备驱动

首先需要知道的是,设备跟驱动是分开的.设备通过struct device来定义,也可以自己将结构体封装到自己定义的device结构体中: 例如:struct platform_device: 1 在include/linux/platform_device.h文件中: //这个位置还是个盲点,我一直没找到这个位置在哪里 2 struct platform_device { 3 const char * name 4 u32 id 5 struct device dev 6 u32 num_res

字符设备驱动、平台设备驱动、设备驱动模型、sysfs的关系

Linux驱动开发的童鞋们来膜拜吧:-)  学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术.对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了.要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码.网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关联的分析.对于开发者而言,能够熟悉某一点并分享出来已很难得,但对于专注传授技术和经验给

[kernel]字符设备驱动、平台设备驱动、设备驱动模型、sysfs几者之间的比较和关联

转自:http://www.2cto.com/kf/201510/444943.html Linux驱动开发经验总结,绝对干货! 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术.对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了.要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码.网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关

linux字符设备驱动

一.字符设备.字符设备驱动与用户空间访问该设备的程序三者之间的关系. 如图,在Linux内核中使用cdev结构体来描述字符设备,通过其成员dev_t来定义设备号(分为主.次设备号)以确定字符设备的唯一性.通过其成员file_operations来定义字符设备驱动提供给VFS的接口函数,如常见的open().read().write()等. 在Linux字符设备驱动中,模块加载函数通过register_chrdev_region( ) 或alloc_chrdev_region( )来静态或者动态获

linux 字符设备驱动开发详解

一.设备的分类及特点 1.字符设备 字符设备是面向数据流的设备,没有请求缓冲区,对设备的存取只能按顺序按字节的存取而不能随机访问.    Linux下的大多设备都是字符设备.应用程序是通过字符设备节点来访问字符设备的.通常至少需要实现 open, close, read, 和 write 等系统调用.    设备节点一般都由mknod命令都创建在/dev目录下,包含了设备的类型.主/次设备号以及设备的访问权限控制等,如:crw-rw----  1 root  root 4, 64 Feb 18

linux设备驱动第三篇:写一个简单的字符设备驱动

在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存. 下面就开始学习如何写一个简单的字符设备驱动.首先我们来分解一下字符设备驱动都有那些结构或者方法组成,也就是说实现一个可以使用的字符设备驱动我们必须做些什么工作. 1.主设备号和次设备号 对于字符设备的访问是通过文件系统中的设备名称进行的.他们通常位于/dev目录下.如下: [plain] vie

linux设备驱动之字符设备驱动模型(2)

在上一篇中我们已经了解了字符设备驱动的原理,也了解了应用层调用内核函数的机制,但是我们每次操作设备,都必须首先通过mknod命令创建一个设备文件名,比如说我们要打开u盘,硬盘等这些设备,难道我们还要自己创建,就如同刘老师常说的一句话,这也太山寨了吧,所以我们今天我们来点比较专业的,让函数帮我们自动创建: 在Linux 下,设备和驱动通常都需要挂接在一种总线上,总线有PCI.USB.I2C.SPI 等等,总线是处理器和设备之间的通道,在设备模型中,所有的设备都通过总线相连,一总线来管理设备和驱动函

Linux字符设备驱动剖析

一.先看看设备应用程序 1.很简单,open设备文件,read.write.ioctl,最后close退出.如下: intmain(int argc ,char *argv[]){ unsigned char val[1] = 1; int fd =open("/dev/LED",O_RDWR);//打开设备 write(fd,val,1);//写入设备,这里代表LED全亮 close(fd);//关闭设备 return 0; } 二./dev目录与文件系统 2./dev是根文件系统下

深入浅出~Linux设备驱动之字符设备驱动

一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见的字符设备有鼠标.键盘.串口.控制台和LED设备等. 块设备:是指可以从设备的任意位置读取一定长度数据的设备.块设备包括硬盘.磁盘.U盘和SD卡等. 每一个字符设备或块设备都在/dev目录下对应一个设备文件.linux用户程序通过设备文件(或称设备节点)来使用驱动程序操作字符设备和块设备