转自:http://blog.chinaunix.net/uid-20776117-id-3212095.html

本文接着input子系统学习笔记五 按键驱动实例分析上接续分析这个按键驱动实例!

input_report_key()向子系统报告事件

在 button_interrupt()中断函数中,不需要考虑重复按键的重复点击情况,input_report_key()函数会自动检查这个问题,并报告一次事件给输入子系统。该函数的代码如下:

C++代码
  1. static inline void input_report_key(struct input_dev *dev,unsigned int
  2. code, int value)
  3. {
  4. input_event(dev, EV_KEY, code, !!value);
  5. }

该函数的第 1 个参数是产生事件的输入设备, 第2 个参数是产生的事件, 第3 个参数是事件的值。需要注意的是, 2 个参数可以取类似 BTN_0、 BTN_1、BTN_LEFT、BTN_RIGHT 等值,这些键值被定义在 include/linux/input.h 文件中。当第 2 个参数为按键时,第 3 个参数表示按键的状态,value 值为 0 表示按键释放,非 0 表示按键按下。

input_event()

在 input_report_key()函数中正在起作用的函数是 input_event()函数,该函数用来向输入子系统报告输入设备产生的事件,这个函数非常重要,它的代码如下:

Java代码
  1. void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)
  2. {
  3. unsigned long flags;
  4. /*调用 is_event_supported()函数检查输入设备是否支持该事件*/
  5. if (is_event_supported(type, dev->evbit, EV_MAX)) {
  6. spin_lock_irqsave(&dev->event_lock, flags);//调用 spin_lock_irqsave()函数对将事件锁锁定。
  7. add_input_randomness(type,code,value);//add_input_randomness()函数对事件发送没有一点用处,只是用来对随机数熵池增加一些贡献,因为按键输入是一种随机事件,所以对熵池是有贡献的。
  8. input_handle_event(dev, type, code, value);//调用 input_handle_event()函数来继续输入子系统的相关模块发送数据。该函数较为复杂,下面单独进行分析。
  9. spin_unlock_irqrestore(&dev->event_lock, flags);
  10. }
  11. }

is_event_supported()

C++代码
  1. static inline int is_event_supported(unsigned int code,
  2. unsigned long *bm, unsigned int max)
  3. {
  4. return code <= max && test_bit(code, bm);
  5. }

该函数检查 input_dev.evbit 中的相应位是否设置,如果设置返回 1,否则返回 0。每一种类型的事件都在 input_dev.evbit 中用一个位来表示,构成一个位图,如果某位为 1,表示该输入设备支持这类事件,如果为 0,表示输入设备不支持这类事件。目前 Linux 支持十多种事件类型,所以用一个 long 型变量就可以全部表示了。

input_handle_event()

input_handle_event()函数向输入子系统传送事件信息。第 1 个参数是输入设备 input_dev,第 2 个参数是事件的类型,第 3 个参数是键码,第 4 个参数是键值。该函数的代码如下:

C++代码
  1. static void input_handle_event(struct input_dev *dev,
  2. unsigned int type, unsigned int code, int value)
  3. {
  4. int disposition = INPUT_IGNORE_EVENT;//定义了一个 disposition 变量,该变量表示使用什么样的方式处理事件。此处初始化为 INPUT_IGNORE_EVENT,表示如果后面没有对该变量重新赋值,则忽略这个事件。
  5. switch (type) {
  6. case EV_SYN:
  7. switch (code) {
  8. case SYN_CONFIG:
  9. disposition = INPUT_PASS_TO_ALL;
  10. break;
  11. case SYN_REPORT:
  12. if (!dev->sync) {
  13. dev->sync = 1;
  14. disposition = INPUT_PASS_TO_HANDLERS;
  15. }
  16. break;
  17. case SYN_MT_REPORT:
  18. dev->sync = 0;
  19. disposition = INPUT_PASS_TO_HANDLERS;
  20. break;
  21. }
  22. break;
  23. case EV_KEY:
  24. //调用 is_event_supported()函数判断是否支持该按键。
  25. if (is_event_supported(code, dev->keybit, KEY_MAX) &&
  26. !!test_bit(code, dev->key) != value) {
  27. //调用 test_bit()函数来测试按键状态是否改变。
  28. if (value != 2) {
  29. __change_bit(code,dev->key);/*调用__change_bit()函数改变键的状态。*/
  30. if (value)
  31. input_start_autorepeat(dev, code);/*处理重复按键的情况。*/
  32. else
  33. input_stop_autorepeat(dev);
  34. }
  35. disposition = INPUT_PASS_TO_HANDLERS;/*将 disposition变量设置为 INPUT_PASS_TO_HANDLERS,表示事件需要 handler 来处理。disposition 的取值有如下几种:
  36. 1. #define INPUT_IGNORE_EVENT 0
  37. 2. #define INPUT_PASS_TO_HANDLERS 1
  38. 3. #define INPUT_PASS_TO_DEVICE 2
  39. 4.#define INPUT_PASS_TO_ALL(INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
  40. INPUT_IGNORE_EVENT 表示忽略事件,不对其进行处理。INPUT_PASS_ TO_HANDLERS 表示将事件交给handler处理。INPUT_PASS_TO_DEVICE 表示将事件交给 input_dev 处理。INPUT_PASS_TO_ALL 表示将事件交给 handler 和 input_dev 共同处理。 */
  41. }
  42. break;
  43. case EV_SW:
  44. if (is_event_supported(code, dev->swbit, SW_MAX) &&
  45. !!test_bit(code, dev->sw) != value) {
  46. __change_bit(code, dev->sw);
  47. disposition = INPUT_PASS_TO_HANDLERS;
  48. }
  49. break;
  50. case EV_ABS:
  51. if (is_event_supported(code, dev->absbit, ABS_MAX)) {
  52. if (test_bit(code, input_abs_bypass)) {
  53. disposition = INPUT_PASS_TO_HANDLERS;
  54. break;
  55. }
  56. value = input_defuzz_abs_event(value,
  57. dev->abs[code], dev->absfuzz[code]);
  58. if (dev->abs[code] != value) {
  59. dev->abs[code] = value;
  60. disposition = INPUT_PASS_TO_HANDLERS;
  61. }
  62. }
  63. break;
  64. case EV_REL:
  65. if (is_event_supported(code, dev->relbit, REL_MAX) && value)
  66. disposition = INPUT_PASS_TO_HANDLERS;
  67. break;
  68. case EV_MSC:
  69. if (is_event_supported(code, dev->mscbit, MSC_MAX))
  70. disposition = INPUT_PASS_TO_ALL;
  71. break;
  72. case EV_LED:
  73. if (is_event_supported(code, dev->ledbit, LED_MAX) &&
  74. !!test_bit(code, dev->led) != value) {
  75. __change_bit(code, dev->led);
  76. disposition = INPUT_PASS_TO_ALL;
  77. }
  78. break;
  79. case EV_SND:
  80. if (is_event_supported(code, dev->sndbit, SND_MAX)) {
  81. if (!!test_bit(code, dev->snd) != !!value)
  82. __change_bit(code, dev->snd);
  83. disposition = INPUT_PASS_TO_ALL;
  84. }
  85. break;
  86. case EV_REP:
  87. if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
  88. dev->rep[code] = value;
  89. disposition = INPUT_PASS_TO_ALL;
  90. }
  91. break;
  92. case EV_FF:
  93. if (value >= 0)
  94. disposition = INPUT_PASS_TO_ALL;
  95. break;
  96. case EV_PWR:
  97. disposition = INPUT_PASS_TO_ALL;
  98. break;
  99. }
  100. if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)/*处理 EV_SYN 事件,这里并不对其进行关心。*/
  101. dev->sync = 0;
  102. /*首先判断 disposition 等于 INPUT_PASS_TO_DEVICE,然后判断 dev->event 是否对其指定了一个处理函数,如果这些条件都满足,则调用自定义的 dev->event()函数处理事件。有些事件是发送给设备,而不是发送给 handler 处理的。event()函数用来向输入子系统报告一个将要发送给设备的事件,例如让 LED 灯点亮事件、蜂鸣器鸣叫事件等。当事件报告给输入子系统后,就要求设备处理这个事件。*/
  103. if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
  104. dev->event(dev, type, code, value);
  105. /*第 87、88 行,如果事件需要 handler 处理,则调用 input_pass_event()函数
  106. */
  107. if (disposition & INPUT_PASS_TO_HANDLERS)
  108. input_pass_event(dev, type, code, value);
  109. }

input_pass_event()

input_pass_event()函数将事件传递到合适的函数,然后对其进行处理,该函数的代码如下:

C++代码
  1. static void input_pass_event(struct input_dev *dev,
  2. unsigned int type, unsigned int code, int value)
  3. {
  4. struct input_handler *handler;
  5. struct input_handle *handle;/*分配一个 input_handle 结构的指针。*/
  6. rcu_read_lock();
  7. handle = rcu_dereference(dev->grab);/*得到 dev->grab 的指针。
  8. grab 是强制为 input device 的 handler,这时要调用 handler的 event 函数。*/
  9. if (handle)
  10. handle->handler->event(handle, type, code, value);
  11. else {
  12. bool filtered = false;
  13. /*表示如果没有为 input device 强制指定 handler,为 grab 赋值,即就会遍历 input device->h_list 上的 handle 成员。如果该 handle 被打开,表示该设备已经被一个用户进程使用。就会调用与输入设备对应的 handler 的 event()函数。注意,只有在 handle 被打开的情况下才会接收到事件,这就是说,只有设备被用户程序使用时,才有必要向用户空间导出信息。*/
  14. list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
  15. if (!handle->open)
  16. continue;
  17. handler = handle->handler;
  18. if (!handler->filter) {
  19. if (filtered)
  20. break;
  21. handler->event(handle, type, code, value);
  22. } else if (handler->filter(handle, type, code, value))
  23. filtered = true;
  24. }
  25. }

input子系统学习笔记六 按键驱动实例分析下【转】的更多相关文章

  1. AM335x(TQ335x)学习笔记——GPIO按键驱动移植

    还是按照S5PV210的学习顺序来,我们首先解决按键问题.TQ335x有六个用户按键,分别是上.下.左.右.Enter和ESC.开始我想到的是跟学习S5PV210时一样,编写输入子系统驱动解决按键问题 ...

  2. Linux 驱动学习笔记05--字符驱动实例,实现一个共享内存设备的驱动

    断断续续学驱动,好不容易有空,做了段字符驱动的例子.主要还是跟书上学习在此记录下来,以后说不定能回过头来温故知新. 首先上驱动源码 gmem.c: /************************* ...

  3. 吴裕雄--天生自然JAVA面向对象高级编程学习笔记:宠物商店实例分析

    interface Pet{ // 定义宠物接口 public String getName() ; public String getColor() ; public int getAge() ; ...

  4. memcached学习笔记——存储命令源码分析上篇

    原创文章,转载请标明,谢谢. 上一篇分析过memcached的连接模型,了解memcached是如何高效处理客户端连接,这一篇分析memcached源码中的process_update_command ...

  5. 【opencv学习笔记六】图像的ROI区域选择与复制

    图像的数据量还是比较大的,对整张图片进行处理会影响我们的处理效率,因此常常只对图像中我们需要的部分进行处理,也就是感兴趣区域ROI.今天我们来看一下如何设置图像的感兴趣区域ROI.以及对ROI区域图像 ...

  6. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  7. # go微服务框架kratos学习笔记六(kratos 服务发现 discovery)

    目录 go微服务框架kratos学习笔记六(kratos 服务发现 discovery) http api register 服务注册 fetch 获取实例 fetchs 批量获取实例 polls 批 ...

  8. Spring Boot 学习笔记(六) 整合 RESTful 参数传递

    Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...

  9. Java IO学习笔记六:NIO到多路复用

    作者:Grey 原文地址:Java IO学习笔记六:NIO到多路复用 虽然NIO性能上比BIO要好,参考:Java IO学习笔记五:BIO到NIO 但是NIO也有问题,NIO服务端的示例代码中往往会包 ...

随机推荐

  1. 证明与计算(3): 二分决策图(Binary Decision Diagram, BDD)

    0x01 布尔代数(Boolean algebra) 大名鼎鼎鼎的stephen wolfram在2015年的时候写了一篇介绍George Boole的文章:George Boole: A 200-Y ...

  2. yarn 在Vue框架中的常用命令

    初始化项目 yarn add init 安装vue yarn add vue 安装webpack,webpack-dev-server(是一个小型的Node.js Express服务器) yarn a ...

  3. 每个努力奋斗过的人,被不公正的际遇砸了满头包的时候,都有那么一瞬间的代入感。出生就是hard模式的人,早已经历了太多的劳其筋骨饿其体肤,再多的人为考验只会摧毁人对美好的向往。

    每个努力奋斗过的人,被不公正的际遇砸了满头包的时候,都有那么一瞬间的代入感.出生就是hard模式的人,早已经历了太多的劳其筋骨饿其体肤,再多的人为考验只会摧毁人对美好的向往.

  4. 在vue 里使用腾讯ditu

    https://www.cnblogs.com/mrer/p/7144705.html

  5. Spring Boot 2.x 编写 RESTful API (二) 校验

    用Spring Boot编写RESTful API 学习笔记 约束规则对子类依旧有效 groups 参数 每个约束用注解都有一个 groups 参数 可接收多个 class 类型 (必须是接口) 不声 ...

  6. adb bat 执行滑动事件

    chcp 65001 @echo off echo 开始滑动 set str =0 :start adb shell input swipe 100 150 100 100 choice /t 1 / ...

  7. 【转】Java 线程池

    什么是线程池? 线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程.线程池中线程的数量通常完全取决于可用内存数量和应用程序的需求.然而, ...

  8. gnocchi resource批量删除

    openstack监控告警,采集数据,部署VMware-controller后,之前的celometer采集的大量数据需要删除 1.第一部获取未采集所有虚拟机的IP,并组成grep -v 多条件的格式 ...

  9. [hosts]在hosts中屏蔽一级域名和二级域名的写法

    一级域名,如baidu: 0.0.0.0 baidu.com 二级域名 如有道公开课 0.0.0.0 ke.youdao.com 不带协议名,不带www. 用127.0.0.1也可以.

  10. crontab语法

    *           *        *        *        *           command minute   hour    day   month   week       ...