input子系统学习笔记六 按键驱动实例分析下 | 您所在的位置:网站首页 › linux按键驱动实验分析 › input子系统学习笔记六 按键驱动实例分析下 |
本文接着input子系统学习笔记五 按键驱动实例分析上接续分析这个按键驱动实例! input_report_key()向子系统报告事件 在 button_interrupt()中断函数中,不需要考虑重复按键的重复点击情况,input_report_key()函数会自动检查这个问题,并报告一次事件给输入子系统。该函数的代码如下: C++代码 static inline void input_report_key(struct input_dev *dev,unsigned int code, int value) { 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代码 void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value) { unsigned long flags; /*调用 is_event_supported()函数检查输入设备是否支持该事件*/ if (is_event_supported(type, dev->evbit, EV_MAX)) { spin_lock_irqsave(&dev->event_lock, flags);//调用 spin_lock_irqsave()函数对将事件锁锁定。 add_input_randomness(type,code,value);//add_input_randomness()函数对事件发送没有一点用处,只是用来对随机数熵池增加一些贡献,因为按键输入是一种随机事件,所以对熵池是有贡献的。 input_handle_event(dev, type, code, value);//调用 input_handle_event()函数来继续输入子系统的相关模块发送数据。该函数较为复杂,下面单独进行分析。 spin_unlock_irqrestore(&dev->event_lock, flags); } }is_event_supported() C++代码 static inline int is_event_supported(unsigned int code, unsigned long *bm, unsigned int max) { return code sync) { dev->sync = 1; disposition = INPUT_PASS_TO_HANDLERS; } break; case SYN_MT_REPORT: dev->sync = 0; disposition = INPUT_PASS_TO_HANDLERS; break; } break; case EV_KEY: //调用 is_event_supported()函数判断是否支持该按键。 if (is_event_supported(code, dev->keybit, KEY_MAX) && !!test_bit(code, dev->key) != value) { //调用 test_bit()函数来测试按键状态是否改变。 if (value != 2) { __change_bit(code,dev->key);/*调用__change_bit()函数改变键的状态。*/ if (value) input_start_autorepeat(dev, code);/*处理重复按键的情况。*/ else input_stop_autorepeat(dev); } disposition = INPUT_PASS_TO_HANDLERS;/*将 disposition变量设置为 INPUT_PASS_TO_HANDLERS,表示事件需要 handler 来处理。disposition 的取值有如下几种: 1. #define INPUT_IGNORE_EVENT 0 2. #define INPUT_PASS_TO_HANDLERS 1 3. #define INPUT_PASS_TO_DEVICE 2 4.#define INPUT_PASS_TO_ALL(INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) INPUT_IGNORE_EVENT 表示忽略事件,不对其进行处理。INPUT_PASS_ TO_HANDLERS 表示将事件交给handler处理。INPUT_PASS_TO_DEVICE 表示将事件交给 input_dev 处理。INPUT_PASS_TO_ALL 表示将事件交给 handler 和 input_dev 共同处理。 */ } break; case EV_SW: if (is_event_supported(code, dev->swbit, SW_MAX) && !!test_bit(code, dev->sw) != value) { __change_bit(code, dev->sw); disposition = INPUT_PASS_TO_HANDLERS; } break; case EV_ABS: if (is_event_supported(code, dev->absbit, ABS_MAX)) { if (test_bit(code, input_abs_bypass)) { disposition = INPUT_PASS_TO_HANDLERS; break; } value = input_defuzz_abs_event(value, dev->abs[code], dev->absfuzz[code]); if (dev->abs[code] != value) { dev->abs[code] = value; disposition = INPUT_PASS_TO_HANDLERS; } } break; case EV_REL: if (is_event_supported(code, dev->relbit, REL_MAX) && value) disposition = INPUT_PASS_TO_HANDLERS; break; case EV_MSC: if (is_event_supported(code, dev->mscbit, MSC_MAX)) disposition = INPUT_PASS_TO_ALL; break; case EV_LED: if (is_event_supported(code, dev->ledbit, LED_MAX) && !!test_bit(code, dev->led) != value) { __change_bit(code, dev->led); disposition = INPUT_PASS_TO_ALL; } break; case EV_SND: if (is_event_supported(code, dev->sndbit, SND_MAX)) { if (!!test_bit(code, dev->snd) != !!value) __change_bit(code, dev->snd); disposition = INPUT_PASS_TO_ALL; } break; case EV_REP: if (code = 0 && dev->rep[code] != value) { dev->rep[code] = value; disposition = INPUT_PASS_TO_ALL; } break; case EV_FF: if (value >= 0) disposition = INPUT_PASS_TO_ALL; break; case EV_PWR: disposition = INPUT_PASS_TO_ALL; break; } if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)/*处理 EV_SYN 事件,这里并不对其进行关心。*/ dev->sync = 0; /*首先判断 disposition 等于 INPUT_PASS_TO_DEVICE,然后判断 dev->event 是否对其指定了一个处理函数,如果这些条件都满足,则调用自定义的 dev->event()函数处理事件。有些事件是发送给设备,而不是发送给 handler 处理的。event()函数用来向输入子系统报告一个将要发送给设备的事件,例如让 LED 灯点亮事件、蜂鸣器鸣叫事件等。当事件报告给输入子系统后,就要求设备处理这个事件。*/ if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) dev->event(dev, type, code, value); /*第 87、88 行,如果事件需要 handler 处理,则调用 input_pass_event()函数 */ if (disposition & INPUT_PASS_TO_HANDLERS) input_pass_event(dev, type, code, value); }input_pass_event() input_pass_event()函数将事件传递到合适的函数,然后对其进行处理,该函数的代码如下: C++代码 static void input_pass_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct input_handler *handler; struct input_handle *handle;/*分配一个 input_handle 结构的指针。*/ rcu_read_lock(); handle = rcu_dereference(dev->grab);/*得到 dev->grab 的指针。 grab 是强制为 input device 的 handler,这时要调用 handler的 event 函数。*/ if (handle) handle->handler->event(handle, type, code, value); else { bool filtered = false; /*表示如果没有为 input device 强制指定 handler,为 grab 赋值,即就会遍历 input device->h_list 上的 handle 成员。如果该 handle 被打开,表示该设备已经被一个用户进程使用。就会调用与输入设备对应的 handler 的 event()函数。注意,只有在 handle 被打开的情况下才会接收到事件,这就是说,只有设备被用户程序使用时,才有必要向用户空间导出信息。*/ list_for_each_entry_rcu(handle, &dev->h_list, d_node) { if (!handle->open) continue; handler = handle->handler; if (!handler->filter) { if (filtered) break; handler->event(handle, type, code, value); } else if (handler->filter(handle, type, code, value)) filtered = true; } } |
CopyRight 2018-2019 实验室设备网 版权所有 |