• 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 }
  • 相关阅读:
    UGUI血条跟随
    unity组件路径自动生成
    双摄像机使用
    Unity 属性雷达图
    unity UGUI UI跟随
    Unity中实现人物平滑转身
    游戏摇杆
    IIS下载无后缀文件的设置
    convert svn repo to git
    Discovery and auto register
  • 原文地址:https://www.cnblogs.com/xiaohexiansheng/p/5577475.html
Copyright © 2020-2023  润新知