gpio-keys.c分析

来源:互联网 发布:ubuntu更改文件权限 编辑:程序博客网 时间:2024/06/05 08:48
  1. Driver for keys on GPIO lines capable of generating interrupts.
  2.  *
  3.  * Copyright 2005 Phil Blundell
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License version 2 as
  7.  * published by the Free Software Foundation.
  8.  */

  9. #include <linux/module.h>

  10. #include <linux/init.h>
  11. #include <linux/fs.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/irq.h>
  14. #include <linux/sched.h>
  15. #include <linux/pm.h>
  16. #include <linux/sysctl.h>
  17. #include <linux/proc_fs.h>
  18. #include <linux/delay.h>
  19. #include <linux/platform_device.h>
  20. #include <linux/input.h>
  21. #include <linux/gpio_keys.h>
  22. #include <linux/workqueue.h>

  23. #include <asm/gpio.h>

  24. struct gpio_button_data {
  25.     struct gpio_keys_button *button;
  26.     struct input_dev *input;
  27.     struct timer_list timer;
  28.     struct work_struct work;
  29. };

  30. struct gpio_keys_drvdata {
  31.     struct input_dev *input;
  32.     struct gpio_button_data data[0];
  33. };

  34. static void gpio_keys_report_event(struct work_struct *work)/*中断下半部*/
  35. {
  36.     struct gpio_button_data *bdata =
  37.         container_of(work, struct gpio_button_data, work);
  38.     struct gpio_keys_button *button = bdata->button;
  39.     struct input_dev *input = bdata->input;
  40.     unsigned int type = button->type ?: EV_KEY;
  41.     int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
  42. ///获得按键信息,同时于active_low异或,主要还是根据上升沿下降沿判断按键状态
  43.     input_event(input, type, button->code, !!state);
  44.     input_sync(input);
  45. }

  46. static void gpio_keys_timer(unsigned long _data)
  47. {
  48.     struct gpio_button_data *data = (struct gpio_button_data *)_data;

  49.     schedule_work(&data->work);//调度work
  50. }

  51. static irqreturn_t gpio_keys_isr(int irq, void *dev_id)/*中断服务例程*/
  52. {
  53.     struct gpio_button_data *bdata = dev_id;
  54.     struct gpio_keys_button *button = bdata->button;

  55.     BUG_ON(irq != gpio_to_irq(button->gpio));

  56.     if (button->debounce_interval) /*检测是否在platform device设置了去抖动*/ 
  57.         mod_timer(&bdata->timer,
  58.             jiffies + msecs_to_jiffies(button->debounce_interval));
  59.          /* 延迟msecs_to_jiffies(button->debounce_interval)个jiffies后执行schedule_work()*/ 
  60.     else
  61.         schedule_work(&bdata->work);//put work task in global workqueue,调度work

  62.     return IRQ_HANDLED;
  63. }

  64. static int __devinit gpio_keys_probe(struct platform_device *pdev)
  65. {
  66.     struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
  67.     struct gpio_keys_drvdata *ddata;
  68.     struct input_dev *input;
  69.     int i, error;
  70.     int wakeup = 0;

  71.     ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
  72.             pdata->nbuttons * sizeof(struct gpio_button_data),
  73.             GFP_KERNEL);
  74.     input = input_allocate_device();
  75.     if (!ddata || !input) {
  76.         error = -ENOMEM;
  77.         goto fail1;
  78.     }

  79.     platform_set_drvdata(pdev, ddata);

  80.     input->name = pdev->name;//96行到103行,初始化input_dev一些属性
  81.     input->phys = "gpio-keys/input0";
  82.     input->dev.parent = &pdev->dev;

  83.     input->id.bustype = BUS_HOST;//总线类型
  84.     input->id.vendor = 0x0001;//生产商编号
  85.     input->id.product = 0x0001;//产品编号
  86.     input->id.version = 0x0100;//版本编号

  87.     /* Enable auto repeat feature of Linux input subsystem */
  88.     if (pdata->rep)
  89.         __set_bit(EV_REP, input->evbit); 
  90. /*    如果 设置了 __set_bit(EV_REP, input->evbit)
  91.     也就是重复报告,它的工作机制是这样的:
  92.     如果按键报告了input_event(input, type, button->code,1); 
  93.     之后, 在250ms (可以改)后,依然没有报告 input_event(input, type, button->code,0)
  94.     则 input 会每隔 33ms 继续报告一次 input_event(input, type, button->code,2); 
  95.     直到 报告了 input_event(input, type, button->code,0) 
  96.     才停止 ,这就是我们按住一个按键不松开时,会一直打印键值的原因;*/

  97.     ddata->input = input;

  98.     for (i = 0; i < pdata->nbuttons; i++) {//111-165对每个按键初始化GPIO,并初始化中断
  99.         struct gpio_keys_button *button = &pdata->buttons[i];
  100.         struct gpio_button_data *bdata = &ddata->data[i];
  101.         int irq;
  102.         unsigned int type = button->type ?: EV_KEY;

  103.         bdata->input = input;
  104.         bdata->button = button;
  105.         setup_timer(&bdata->timer,
  106.              gpio_keys_timer, (unsigned long)bdata);//设置timer的值,是一个宏,在<linux/timer.h>
  107.         INIT_WORK(&bdata->work, gpio_keys_report_event);//初始化工作队列,ldk.p124

  108.         error =Cbutton->gpio, button->desc ?: "gpio_keys");
  109.         if (error < 0) {
  110.             pr_err("gpio-keys: failed to request GPIO %d,"
  111.                 " error %d\n", button->gpio, error);
  112.             goto fail2;
  113.         }

  114.         error = gpio_direction_input(button->gpio);//配置gpio的方向
  115.         if (error < 0) {
  116.             pr_err("gpio-keys: failed to configure input"
  117.                 " direction for GPIO %d, error %d\n",
  118.                 button->gpio, error);
  119.             gpio_free(button->gpio);
  120.             goto fail2;
  121.         }

  122.         irq = gpio_to_irq(button->gpio);//将gpio口转化为一个中断号
  123.         if (irq < 0) {
  124.             error = irq;
  125.             pr_err("gpio-keys: Unable to get irq number"
  126.                 " for GPIO %d, error %d\n",
  127.                 button->gpio, error);
  128.             gpio_free(button->gpio);
  129.             goto fail2;
  130.         }

  131.         error = request_irq(irq, gpio_keys_isr,
  132.                  IRQF_SHARED |
  133.                  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
  134.                  button->desc ? button->desc : "gpio_keys",
  135.                  bdata);
  136.         if (error) {
  137.             pr_err("gpio-keys: Unable to claim irq %d; error %d\n",
  138.                 irq, error);
  139.             gpio_free(button->gpio);
  140.             goto fail2;
  141.         }

  142.         if (button->wakeup)
  143.             wakeup = 1;

  144.         input_set_capability(input, type, button->code);
  145.     }

  146.     error = input_register_device(input);//注册input设备
  147.     if (error) {
  148.         pr_err("gpio-keys: Unable to register input device, "
  149.             "error: %d\n", error);
  150.         goto fail2;
  151.     }

  152.     device_init_wakeup(&pdev->dev, wakeup);//电源部分初始化

  153.     return 0;

  154.  fail2:
  155.     while (--i >= 0) {
  156.         free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
  157.         if (pdata->buttons[i].debounce_interval)
  158.             del_timer_sync(&ddata->data[i].timer);
  159.         cancel_work_sync(&ddata->data[i].work);
  160.         gpio_free(pdata->buttons[i].gpio);
  161.     }

  162.     platform_set_drvdata(pdev, NULL);
  163.  fail1:
  164.     input_free_device(input);
  165.     kfree(ddata);

  166.     return error;
  167. }

  168. static int __devexit gpio_keys_remove(struct platform_device *pdev)
  169. {
  170.     struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
  171.     struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
  172.     struct input_dev *input = ddata->input;
  173.     int i;

  174.     device_init_wakeup(&pdev->dev, 0);

  175.     for (i = 0; i < pdata->nbuttons; i++) {
  176.         int irq = gpio_to_irq(pdata->buttons[i].gpio);
  177.         free_irq(irq, &ddata->data[i]);//释放中断号
  178.         if (pdata->buttons[i].debounce_interval)
  179.             del_timer_sync(&ddata->data[i].timer);//删除定时器
  180.         cancel_work_sync(&ddata->data[i].work);
  181.         gpio_free(pdata->buttons[i].gpio);释放gpio
  182.     }

  183.     input_unregister_device(input);释放input设备

  184.     return 0;
  185. }


  186. #ifdef CONFIG_PM
  187. static int gpio_keys_suspend(struct device *dev)
  188. {
  189.     struct platform_device *pdev = to_platform_device(dev);
  190.     struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
  191.     int i;

  192.     if (device_may_wakeup(&pdev->dev)) {
  193.         for (i = 0; i < pdata->nbuttons; i++) {
  194.             struct gpio_keys_button *button = &pdata->buttons[i];
  195.             if (button->wakeup) {
  196.                 int irq = gpio_to_irq(button->gpio);
  197.                 enable_irq_wake(irq);
  198.             }
  199.         }
  200.     }

  201.     return 0;
  202. }

  203. static int gpio_keys_resume(struct device *dev)
  204. {
  205.     struct platform_device *pdev = to_platform_device(dev);
  206.     struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
  207.     int i;

  208.     if (device_may_wakeup(&pdev->dev)) {
  209.         for (i = 0; i < pdata->nbuttons; i++) {
  210.             struct gpio_keys_button *button = &pdata->buttons[i];
  211.             if (button->wakeup) {
  212.                 int irq = gpio_to_irq(button->gpio);
  213.                 disable_irq_wake(irq);
  214.             }
  215.         }
  216.     }

  217.     return 0;
  218. }

  219. static const struct dev_pm_ops gpio_keys_pm_ops = {
  220.     .suspend = gpio_keys_suspend,
  221.     .resume = gpio_keys_resume,
  222. };
  223. #endif

  224. static struct platform_driver gpio_keys_device_driver = {
  225.     .probe = gpio_keys_probe,
  226.     .remove = __devexit_p(gpio_keys_remove),
  227.     .driver = {
  228.         .name = "gpio-keys",
  229.         .owner = THIS_MODULE,
  230. #ifdef CONFIG_PM
  231.         .pm = &gpio_keys_pm_ops,
  232. #endif
  233.     }
  234. };

  235. static int __init gpio_keys_init(void)
  236. {
  237.     return platform_driver_register(&gpio_keys_device_driver);
  238. }

  239. static void __exit gpio_keys_exit(void)
  240. {
  241.     platform_driver_unregister(&gpio_keys_device_driver);
  242. }

  243. module_init(gpio_keys_init);
  244. module_exit(gpio_keys_exit);

  245. MODULE_LICENSE("GPL");
  246. MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
  247. MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");
  248. MODULE_ALIAS("platform:gpio-keys");


  249. 附:两个结构体
  250. 1.    struct gpio_keys_button { 
  251. 2.     /*Configuration parameters */ 
  252. 3.     int code; /* 输入事件代码(KEY_*, SW_*) */ 
  253. 4.     int gpio; /* gpio口 */ 
  254. 5.     int active_low; /* 低电平有效*/ 
  255. 6.     char *desc; /* 功能描述 */ 
  256. 7.     int type; /* 输入事件类型(EV_KEY, EV_SW) */ 
  257. 8.     int wakeup; /* configure thebutton as a wake-up source */ 
  258. 9.     int debounce_interval; /* 去抖动间隔,单位微秒*/ 
  259. 10.    }; 
  260. 11.     
  261. 12.    struct gpio_keys_platform_data { 
  262. 13.     struct gpio_keys_button *buttons; 
  263. 14.     int nbuttons; 
  264. 15.     unsignedint rep:1; /* enable inputsubsystem auto repeat */ 
  265. 16.    };
原创粉丝点击