1. /****************************************************************************
  2. * I.MX6 gpio-keys driver hacking
  3. * 说明:
  4. * 1. 本文解读gpio-keys驱动是如何注册,最终处理函数在哪里。
  5. * 2. 从最后生成的设备节点来看,我们直接可以通过操作该设备节点来来让系统
  6. * 进行相关操作,譬如关机、挂起等操作。
  7. *
  8. * 2016-3-17 深圳 南山平山村 曾剑锋
  9. ***************************************************************************/
  10.  
  11. static struct platform_driver gpio_keys_device_driver = { <----+
  12. .probe = gpio_keys_probe, ---------*-------+
  13. .remove = __devexit_p(gpio_keys_remove), | |
  14. .driver = { | |
  15. .name = "gpio-keys", | |
  16. .owner = THIS_MODULE, | |
  17. #ifdef CONFIG_PM | |
  18. .pm = &gpio_keys_pm_ops, | |
  19. #endif | |
  20. } | |
  21. }; | |
  22. | |
  23. static int __init gpio_keys_init(void) <------------+ | |
  24. { | | |
  25. return platform_driver_register(&gpio_keys_device_driver); | --+ |
  26. } | |
  27. | |
  28. static void __exit gpio_keys_exit(void) | |
  29. { | |
  30. platform_driver_unregister(&gpio_keys_device_driver); | |
  31. } | |
  32. | |
  33. module_init(gpio_keys_init); -------------+ |
  34. module_exit(gpio_keys_exit); |
  35. |
  36. MODULE_LICENSE("GPL"); |
  37. MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>"); |
  38. MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs"); |
  39. MODULE_ALIAS("platform:gpio-keys"); |
  40. |
  41. static int __devinit gpio_keys_probe(struct platform_device *pdev) <-----+
  42. {
  43. struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
  44. struct gpio_keys_drvdata *ddata;
  45. struct device *dev = &pdev->dev;
  46. struct input_dev *input;
  47. int i, error;
  48. int wakeup = ;
  49.  
  50. ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
  51. pdata->nbuttons * sizeof(struct gpio_button_data),
  52. GFP_KERNEL);
  53. input = input_allocate_device();
  54. if (!ddata || !input) {
  55. dev_err(dev, "failed to allocate state\n");
  56. error = -ENOMEM;
  57. goto fail1;
  58. }
  59.  
  60. ddata->input = input;
  61. ddata->n_buttons = pdata->nbuttons;
  62. ddata->enable = pdata->enable;
  63. ddata->disable = pdata->disable;
  64. mutex_init(&ddata->disable_lock);
  65.  
  66. platform_set_drvdata(pdev, ddata);
  67. input_set_drvdata(input, ddata);
  68.  
  69. input->name = pdata->name ? : pdev->name;
  70. input->phys = "gpio-keys/input0";
  71. input->dev.parent = &pdev->dev;
  72. input->open = gpio_keys_open;
  73. input->close = gpio_keys_close;
  74.  
  75. input->id.bustype = BUS_HOST;
  76. input->id.vendor = 0x0001;
  77. input->id.product = 0x0001;
  78. input->id.version = 0x0100;
  79.  
  80. /* Enable auto repeat feature of Linux input subsystem */
  81. if (pdata->rep)
  82. __set_bit(EV_REP, input->evbit);
  83.  
  84. for (i = ; i < pdata->nbuttons; i++) {
  85. struct gpio_keys_button *button = &pdata->buttons[i];
  86. struct gpio_button_data *bdata = &ddata->data[i];
  87. unsigned int type = button->type ?: EV_KEY;
  88.  
  89. bdata->input = input;
  90. bdata->button = button;
  91.  
  92. error = gpio_keys_setup_key(pdev, bdata, button); -------+
  93. if (error) |
  94. goto fail2; |
  95. |
  96. if (button->wakeup) |
  97. wakeup = ; |
  98. |
  99. input_set_capability(input, type, button->code); |
  100. } |
  101. |
  102. error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group); |
  103. if (error) { |
  104. dev_err(dev, "Unable to export keys/switches, error: %d\n", |
  105. error); |
  106. goto fail2; |
  107. } |
  108. |
  109. error = input_register_device(input); |
  110. if (error) { |
  111. dev_err(dev, "Unable to register input device, error: %d\n", |
  112. error); |
  113. goto fail3; |
  114. } |
  115. |
  116. /* get current state of buttons */ |
  117. for (i = ; i < pdata->nbuttons; i++) |
  118. gpio_keys_report_event(&ddata->data[i]); |
  119. input_sync(input); |
  120. |
  121. device_init_wakeup(&pdev->dev, wakeup); |
  122. |
  123. return ; |
  124. |
  125. fail3: |
  126. sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); |
  127. fail2: |
  128. while (--i >= ) { |
  129. free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]); |
  130. if (ddata->data[i].timer_debounce) |
  131. del_timer_sync(&ddata->data[i].timer); |
  132. cancel_work_sync(&ddata->data[i].work); |
  133. gpio_free(pdata->buttons[i].gpio); |
  134. } |
  135. |
  136. platform_set_drvdata(pdev, NULL); |
  137. fail1: |
  138. input_free_device(input); |
  139. kfree(ddata); |
  140. +---------------------------------------+
  141. return error; |
  142. } |
  143. V
  144. static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
  145. struct gpio_button_data *bdata,
  146. struct gpio_keys_button *button)
  147. {
  148. const char *desc = button->desc ? button->desc : "gpio_keys";
  149. struct device *dev = &pdev->dev;
  150. unsigned long irqflags;
  151. int irq, error;
  152.  
  153. setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);
  154. INIT_WORK(&bdata->work, gpio_keys_work_func); --------------------+
  155. |
  156. error = gpio_request(button->gpio, desc); |
  157. if (error < ) { |
  158. dev_err(dev, "failed to request GPIO %d, error %d\n", |
  159. button->gpio, error); |
  160. goto fail2; |
  161. } |
  162. |
  163. error = gpio_direction_input(button->gpio); |
  164. if (error < ) { |
  165. dev_err(dev, "failed to configure" |
  166. " direction for GPIO %d, error %d\n", |
  167. button->gpio, error); |
  168. goto fail3; |
  169. } |
  170. |
  171. if (button->debounce_interval) { |
  172. error = gpio_set_debounce(button->gpio, |
  173. button->debounce_interval * ); |
  174. /* use timer if gpiolib doesn't provide debounce */ |
  175. if (error < ) |
  176. bdata->timer_debounce = button->debounce_interval; |
  177. } |
  178. |
  179. irq = gpio_to_irq(button->gpio); |
  180. if (irq < ) { |
  181. error = irq; |
  182. dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n", |
  183. button->gpio, error); |
  184. goto fail3; |
  185. } |
  186. |
  187. irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; |
  188. /* |
  189. * If platform has specified that the button can be disabled, |
  190. * we don't want it to share the interrupt line. |
  191. */ |
  192. if (!button->can_disable) |
  193. irqflags |= IRQF_SHARED; |
  194. /* |
  195. * Resume power key early during syscore instead of at device |
  196. * resume time. |
  197. * Some platform like Android need to konw the power key is pressed |
  198. * then to reume the other devcies |
  199. */ |
  200. if (button->wakeup) |
  201. irqflags |= IRQF_NO_SUSPEND | IRQF_EARLY_RESUME; |
  202. |
  203. error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata); |
  204. if (error < ) { |
  205. dev_err(dev, "Unable to claim irq %d; error %d\n", |
  206. irq, error); |
  207. goto fail3; |
  208. } |
  209. |
  210. return ; |
  211. |
  212. fail3: |
  213. gpio_free(button->gpio); |
  214. fail2: |
  215. return error; |
  216. } |
  217. |
  218. static void gpio_keys_work_func(struct work_struct *work) <-------------+
  219. {
  220. struct gpio_button_data *bdata =
  221. container_of(work, struct gpio_button_data, work);
  222.  
  223. gpio_keys_report_event(bdata); -----------+
  224. } |
  225. |
  226. static void gpio_keys_report_event(struct gpio_button_data *bdata) <---------+
  227. {
  228. struct gpio_keys_button *button = bdata->button;
  229. struct input_dev *input = bdata->input;
  230. unsigned int type = button->type ?: EV_KEY;
  231. int state = (gpio_get_value_cansleep(button->gpio) ? : ) ^ button->active_low;
  232. printk("zengjf check gpio-keys positon: %s in line %d.\n", __func__, _LINE__);
  233.  
  234. if (type == EV_ABS) {
  235. if (state)
  236. input_event(input, type, button->code, button->value);
  237. } else {
  238. input_event(input, type, button->code, !!state);
  239. }
  240. input_sync(input);
  241. }
  242.  
  243. /**
  244. * root@android:/ # cat /proc/bus/input/devices
  245. * I: Bus=0019 Vendor=0001 Product=0001 Version=0100
  246. * N: Name="gpio-keys"
  247. * P: Phys=gpio-keys/input0
  248. * S: Sysfs=/devices/platform/gpio-keys/input/input0
  249. * U: Uniq=
  250. * H: Handlers=event0
  251. * B: PROP=0
  252. * B: EV=3
  253. * B: KEY=100000 0 0 0
  254. * ......
  255. */

I.MX6 gpio-keys driver hacking的更多相关文章

  1. I.MX6 PWM buzzer driver hacking with Demo test

    /***************************************************************************** * I.MX6 PWM buzzer dr ...

  2. I.MX6 ar1020 SPI device driver hacking

    /************************************************************************************ * I.MX6 ar1020 ...

  3. I.MX6 AD7606-4 device driver registe hacking

    /********************************************************************** * I.MX6 AD7606-4 device driv ...

  4. I.MX6 bq27441 driver hacking

    /************************************************************************* * I.MX6 bq27441 driver ha ...

  5. I.MX6 Linux I2C device& driver hacking

    /******************************************************************************************* * I.MX6 ...

  6. OK335xS LAN8710 phy driver hacking

    /******************************************************************** * OK335xS LAN8710 phy driver h ...

  7. I.MX6 Ar8031 device register hacking

    /***************************************************************************** * I.MX6 Ar8031 device ...

  8. OK335xS knob driver hacking

    /************************************************************************* * OK335xS knob driver hac ...

  9. I.MX6 Power off register hacking

    /*********************************************************************** * I.MX6 Power off register ...

随机推荐

  1. EXTJS 3.0 资料 控件之 Toolbar 两行的用法

    var toolbarCarType = new Ext.Toolbar({ //width: 500, //autoWidth:true, pressed: false, toggleGroup: ...

  2. ios 基于CAEmitterLayer的雪花,烟花,火焰,爱心等效果demo(转)

    转载自:http://blog.csdn.net/mad2man/article/details/16898369 分类: cocoa SDK2013-11-23 11:52 388人阅读 评论(0) ...

  3. Linux C程序的编译过程

    Linux C程序的编译过程 学习一门语言程序,本人觉得还是得学习它的编译规则,现在,通过小例子小结下自己对C编译的认识. /*test.c     了解C程序的编译*/ #include <s ...

  4. 关于Oracle数据库中SQL空值排序的问题

    在Oracle中进行查询排序时,如果排序字段里面有空值的情况下,排序结果可能会达不到自己想要的结果.   如 select * from tableTest order by VISITS desc ...

  5. hdu 4740 The Donkey of Gui Zhou(暴力搜索)

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4740 [题意]: 森林里有一只驴和一只老虎,驴和老虎互相从来都没有见过,各自自己走过的地方不能走第二次 ...

  6. bootstrap-treeview

    简要教程 bootstrap-treeview是一款效果非常酷的基于bootstrap的jQuery多级列表树插件.该jQuery插件基于Twitter Bootstrap,以简单和优雅的方式来显示一 ...

  7. uva 1103

    弄懂题意后  其实就是一个dfs /************************************************************************* > Aut ...

  8. hdu 1018

    数学题  用的这个方法比较烂 g++超时  c++ 406ms /******************************************************************* ...

  9. firefly 框架 结构图

    原地址:http://www.9miao.com/question-15-54838.html 系统结构:

  10. TaskTracker执行map或reduce任务的过程(二)

    上次说到,当MapLauncher或ReduceLancher(用于执行任务的线程,它们扩展自TaskLauncher),从它们所维护的LinkedList也即队列中获取到TaskInProgress ...