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()
- static inline int is_event_supported(unsigned int code,
- unsigned long *bm, unsigned int max)
- 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 個參數是鍵值。該函數的代碼如下:
- static void input_handle_event(struct input_dev *dev,
- unsigned int type, unsigned int code, int value)
- int disposition = INPUT_IGNORE_EVENT;//定義了一個 disposition 變量,該變量表示使用什麼樣的方式處理事件。此處初始化為 INPUT_IGNORE_EVENT,表示如果後面沒有對該變量重新指派,則忽略這個事件。
- switch (type) {
- case EV_SYN:
- switch (code) {
- case SYN_CONFIG:
- disposition = INPUT_PASS_TO_ALL;
- break;
- case SYN_REPORT:
- if (!dev->sync) {
- dev->sync = 1;
- disposition = INPUT_PASS_TO_HANDLERS;
- }
- case SYN_MT_REPORT:
- dev->sync = 0;
- disposition = INPUT_PASS_TO_HANDLERS;
- }
- 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 共同處理。 */
- 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)) {
- break;
- }
- value = input_defuzz_abs_event(value,
- dev->abs[code], dev->absfuzz[code]);
- if (dev->abs[code] != value) {
- dev->abs[code] = value;
- case EV_REL:
- if (is_event_supported(code, dev->relbit, REL_MAX) && value)
- case EV_MSC:
- if (is_event_supported(code, dev->mscbit, MSC_MAX))
- disposition = INPUT_PASS_TO_ALL;
- case EV_LED:
- if (is_event_supported(code, dev->ledbit, LED_MAX) &&
- !!test_bit(code, dev->led) != value) {
- __change_bit(code, dev->led);
- 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;
- case EV_REP:
- if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
- dev->rep[code] = value;
- case EV_FF:
- if (value >= 0)
- case EV_PWR:
- 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()函數将事件傳遞到合适的函數,然後對其進行處理,該函數的代碼如下:
- static void input_pass_event(struct input_dev *dev,
- 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)
- handler->event(handle, type, code, value);
- } else if (handler->filter(handle, type, code, value))
- filtered = true;