input子系统学习笔记六 按键驱动实例分析下

来源:互联网 发布:centos 7.3 gitlab 编辑:程序博客网 时间:2024/06/06 07:10


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

        input_report_key()向子系统报告事件

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

C++代码
  1. staticinlinevoid input_report_key(struct input_dev *dev,unsigned int 
  2. code, int value) 
  3.         input_event(dev, EV_KEY, code, !!value); 

        该函数的第 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,unsignedint type, unsignedint code,int value) 
  2.         unsigned long flags; 
  3.         /*调用 is_event_supported()函数检查输入设备是否支持该事件*/ 
  4.         if (is_event_supported(type, dev->evbit, EV_MAX)) { 
  5.  
  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.         } 

        is_event_supported()

C++代码
  1. staticinlineint is_event_supported(unsignedint code, 
  2. unsigned long *bm, unsignedint max) 
  3.         return code <= max && test_bit(code, bm); 

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

        input_pass_event()

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

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