转自: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. wget在linux中安装出现错误解决办法

    在使用wget命令报错 certificate common name 'xxx' doesn't match requestde host name,我们一般的解决办法是查找下载地址,但是有时候更换 ...

  2. mondb 常用命令学习记录

    mondb 常用命令学习记录 一.MongoDB 下载安装 MongoDB官网 提供了可用于 32 位和 64 位系统的预编译二进制包,你可以从MongoDB官网下载安装,MongoDB 预编译二进制 ...

  3. Bayes factor

     bayes因子为什么一定要除以先验机会比,如果是想用样本的作用,来判断支持原来的假设θ_0,H_0的力度,直接用后验概率比不就好了吗?   左边等于右边

  4. mysql排序,同样的sql,mysql 每次查询结果顺序不一致

    某天项目中写了一句排序sql,但是发现每次执行的结果都不同,就是排序顺序不一样. select * from table_tmp order by printStatus asc,dealTime d ...

  5. GIt帮助文档之忽略某些文件——忽略python虚拟环境文件夹(转)

    前言:为避免多个Python项目下安装库之间的冲突,或为轻松打包某个项目,建议在每个项目文件夹下安装Python虚拟环境,并在虚拟环境内进行操作,之后你安装的任何库和执行的任何程序都是在这个环境下运行 ...

  6. dataframe常用处理

    获取列名:data.columns.values.tolist() 复制列: out['serial_number'] = out['2']这样就是新增了一列,复制了‘2’这一列,然后再del out ...

  7. java网页爬数据获取class中的空格

    <ul class=""> <li class="avatar_img"><img src="http://avatar ...

  8. java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock

    原文:java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock 锁 锁是用来控制多个线程访问共享资源的方式,java中可以使用synch ...

  9. java第一课 面向对象的编程概念

    一.什么是对象(object)? 对象是相关状态和行为的软件包. 1.现实社会的对象都有两个共同特征:状态和行为.如:狗有状态(名称,颜色,品种,饥饿)和行为(吠叫,取出,摇尾). 2.软件对象在概念 ...

  10. 【caffe】caffe在linux环境下的安装与编译

    网上的caffe的安装教程繁杂而散乱,对初学者很不友好,尤其对该框架理解不深的童鞋.总的来说,caffe的安装不外乎几个固定的步骤,对每一步有了一定的理解,安装只是time-consuming的问题! ...