zoukankan      html  css  js  c++  java
  • input子系统学习笔记六 按键驱动实例分析下【转】

    转自: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.   
    7.                 spin_lock_irqsave(&dev->event_lock, flags);//调用 spin_lock_irqsave()函数对将事件锁锁定。  
    8.                 add_input_randomness(type,code,value);//add_input_randomness()函数对事件发送没有一点用处,只是用来对随机数熵池增加一些贡献,因为按键输入是一种随机事件,所以对熵池是有贡献的。  
    9.                 input_handle_event(dev, type, code, value);//调用 input_handle_event()函数来继续输入子系统的相关模块发送数据。该函数较为复杂,下面单独进行分析。  
    10.                 spin_unlock_irqrestore(&dev->event_lock, flags);  
    11.         }  
    12. }  

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

            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.   
    8.         handle = rcu_dereference(dev->grab);/*得到 dev->grab 的指针。 
    9.         grab 是强制为 input device 的 handler,这时要调用 handler的 event 函数。*/  
    10.         if (handle)  
    11.         handle->handler->event(handle, type, code, value);  
    12.         else {  
    13.         bool filtered = false;  
    14.   
    15.   
    16.         /*表示如果没有为 input device 强制指定 handler,为 grab 赋值,即就会遍历 input device->h_list 上的 handle 成员。如果该 handle 被打开,表示该设备已经被一个用户进程使用。就会调用与输入设备对应的 handler 的 event()函数。注意,只有在 handle 被打开的情况下才会接收到事件,这就是说,只有设备被用户程序使用时,才有必要向用户空间导出信息。*/  
    17.         list_for_each_entry_rcu(handle, &dev->h_list, d_node) {  
    18.         if (!handle->open)  
    19.                 continue;  
    20.   
    21.         handler = handle->handler;  
    22.         if (!handler->filter) {  
    23.                 if (filtered)  
    24.                         break;  
    25.   
    26.                 handler->event(handle, type, code, value);  
    27.   
    28.         } else if (handler->filter(handle, type, code, value))  
    29.                 filtered = true;  
    30.         }  
    31.         }  
  • 相关阅读:
    Balanced Number [ZOJ 3416]
    动态树
    Jason的特殊爱好 [FZU 2113]
    Raney引理
    Tri Tiling [POJ 2663]
    糖尿病的虾青素+胰岛素疗法 (转)
    JAVASCRIPT 开发工具:aptana ,WebStorm
    众志和达,英文SOUL 存储与数据安全提供商
    健身音乐及其它
    nodejs + CompoundJS 资源
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/10788577.html
Copyright © 2011-2022 走看看