转自: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. vscode 打开多个标签页

    默认只打开2个,按如下设置可以支持多开: 路径C:\Users\admin\AppData\Roaming\Code\User下的settings.json添加一条配置:"workbench ...

  2. 【算法】C语言趣味程序设计编程百例精解

    C语言趣味程序设计编程百例精解 C/C++语言经典.实用.趣味程序设计编程百例精解(1)  https://wenku.baidu.com/view/b9f683c08bd63186bcebbc3c. ...

  3. ORM简介

    ORM就是object relational mapping,对象关系映射. 将关系型数据库转化为对象来进行处理. 数据表就是一个类,表的一行就是一个对象,一行的每个字段就是属性. 忽然想到了在MVC ...

  4. Python一些代码

    自定义with open打开文件 # 是使用上下文管理协议自定义open class Open(object): def __init__(self,filepath,mode='r',encodin ...

  5. 图解从 URL 到网页通信原理

    前言 一.文本对话--从请求到响应 二.TCP/IP 协议族介绍 三.基于TCP/IP通信过程 四.TCP建立连接及断开(重点补充) 小结 前言 互联网的原始目的,就是为了传输文本(文本对话).那我们 ...

  6. Iterator和Enumeration的区别

    从源码可以看出,Iterator除了能读取集合的数据之外,也能数据进行删除操作:而Enumeration只能读取集合的数据,而不能对数据进行修改. Iterator支持fail-fast机制,而Enu ...

  7. [PL]如果天空是黑暗的,那就摸黑生存

    “如果天空是黑暗的,那就摸黑生存:如果发出声音是危险的,那就保持沉默:如果自觉无力发光的,那就蜷缩于墙角.但不要习惯了黑暗,就为黑暗辩护:不要为自己的苟且而得意:不要嘲讽那些比自己更勇敢更热情的人们. ...

  8. SNOI 2019 字符串

    SNOI 2019 字符串 题目 题解: 解法一: 记一个数组\(f\),\(f[i]=\min_j\ s[j]\neq s[j+1] (j\geq i)\),直接sort即可,复杂度\(O(nlog ...

  9. Beyas定理

    \(Beyas\)定理 首先由条件概率的计算式有 \[Pr\{A|B\}=\frac{Pr\{A\cap B\}}{Pr\{B\}}\] 结合交换律得到 \[Pr\{A\cap B\}=Pr\{B\} ...

  10. textCNN原理

    一.TextCnn的结构 1. 嵌入层(embedding layer) textcnn使用预先训练好的词向量作embedding layer.对于数据集里的所有词,因为每个词都可以表征成一个向量,因 ...