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、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!\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 }