天天看點

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.         unsigned long flags;  
  3.         /*調用 is_event_supported()函數檢查輸入裝置是否支援該事件*/  
  4.         if (is_event_supported(type, dev->evbit, EV_MAX)) {  
  5.                 spin_lock_irqsave(&dev->event_lock, flags);//調用 spin_lock_irqsave()函數對将事件鎖鎖定。  
  6.                 add_input_randomness(type,code,value);//add_input_randomness()函數對事件發送沒有一點用處,隻是用來對随機數熵池增加一些貢獻,因為按鍵輸入是一種随機事件,是以對熵池是有貢獻的。  
  7.                 input_handle_event(dev, type, code, value);//調用 input_handle_event()函數來繼續輸入子系統的相關子產品發送資料。該函數較為複雜,下面單獨進行分析。  
  8.                 spin_unlock_irqrestore(&dev->event_lock, flags);  
  9.         }  

        is_event_supported()

  1. static inline int is_event_supported(unsigned int code,  
  2. unsigned long *bm, unsigned int 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 個參數是鍵值。該函數的代碼如下:

  1. static void input_handle_event(struct input_dev *dev,  
  2. unsigned int type, unsigned int code, int value)  
  3.         int disposition = INPUT_IGNORE_EVENT;//定義了一個 disposition 變量,該變量表示使用什麼樣的方式處理事件。此處初始化為 INPUT_IGNORE_EVENT,表示如果後面沒有對該變量重新指派,則忽略這個事件。  
  4.         switch (type) {  
  5.         case EV_SYN:  
  6.                 switch (code) {  
  7.                         case SYN_CONFIG:  
  8.                                 disposition = INPUT_PASS_TO_ALL;  
  9.                                 break;  
  10.                         case SYN_REPORT:  
  11.                                 if (!dev->sync) {  
  12.                                         dev->sync = 1;  
  13.                                         disposition = INPUT_PASS_TO_HANDLERS;  
  14.                                 }  
  15.                         case SYN_MT_REPORT:  
  16.                                 dev->sync = 0;  
  17.                                 disposition = INPUT_PASS_TO_HANDLERS;  
  18.                 }  
  19.         break;  
  20.         case EV_KEY:  
  21.         //調用 is_event_supported()函數判斷是否支援該按鍵。  
  22.                 if (is_event_supported(code, dev->keybit, KEY_MAX) &&  
  23.                 !!test_bit(code, dev->key) != value) {  
  24.                         //調用 test_bit()函數來測試按鍵狀态是否改變。  
  25.                         if (value != 2) {  
  26.                                 __change_bit(code,dev->key);/*調用__change_bit()函數改變鍵的狀态。*/  
  27.                                         if (value)  
  28.                                                 input_start_autorepeat(dev, code);/*處理重複按鍵的情況。*/  
  29.                                         else  
  30.                                                 input_stop_autorepeat(dev);  
  31.                         }  
  32.                 disposition = INPUT_PASS_TO_HANDLERS;/*将 disposition變量設定為 INPUT_PASS_TO_HANDLERS,表示事件需要 handler 來處理。disposition 的取值有如下幾種: 
  33.                         1. #define INPUT_IGNORE_EVENT 0 
  34.                         2. #define INPUT_PASS_TO_HANDLERS 1 
  35.                         3. #define INPUT_PASS_TO_DEVICE 2 
  36.                         4.#define INPUT_PASS_TO_ALL(INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) 
  37.                 INPUT_IGNORE_EVENT 表示忽略事件,不對其進行處理。INPUT_PASS_ TO_HANDLERS 表示将事件交給handler處理。INPUT_PASS_TO_DEVICE 表示将事件交給 input_dev 處理。INPUT_PASS_TO_ALL 表示将事件交給 handler 和 input_dev 共同處理。 */  
  38.         case EV_SW:  
  39.                 if (is_event_supported(code, dev->swbit, SW_MAX) &&  
  40.                         !!test_bit(code, dev->sw) != value) {  
  41.                         __change_bit(code, dev->sw);  
  42.                         disposition = INPUT_PASS_TO_HANDLERS;  
  43.                 break;  
  44.         case EV_ABS:  
  45.                 if (is_event_supported(code, dev->absbit, ABS_MAX)) {  
  46.                 if (test_bit(code, input_abs_bypass)) {  
  47.                         break;  
  48.                     }  
  49.         value = input_defuzz_abs_event(value,  
  50.         dev->abs[code], dev->absfuzz[code]);  
  51.                 if (dev->abs[code] != value) {  
  52.                         dev->abs[code] = value;  
  53.         case EV_REL:  
  54.                 if (is_event_supported(code, dev->relbit, REL_MAX) && value)  
  55.         case EV_MSC:  
  56.                 if (is_event_supported(code, dev->mscbit, MSC_MAX))  
  57.                         disposition = INPUT_PASS_TO_ALL;  
  58.         case EV_LED:  
  59.                 if (is_event_supported(code, dev->ledbit, LED_MAX) &&  
  60.                         !!test_bit(code, dev->led) != value) {  
  61.                         __change_bit(code, dev->led);  
  62.         case EV_SND:  
  63.                 if (is_event_supported(code, dev->sndbit, SND_MAX)) {  
  64.                         if (!!test_bit(code, dev->snd) != !!value)  
  65.                 __change_bit(code, dev->snd);  
  66.                 disposition = INPUT_PASS_TO_ALL;  
  67.         case EV_REP:  
  68.         if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {  
  69.                 dev->rep[code] = value;  
  70.         case EV_FF:  
  71.         if (value >= 0)  
  72.         case EV_PWR:  
  73.         if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)/*處理 EV_SYN 事件,這裡并不對其進行關心。*/  
  74.         dev->sync = 0;  
  75.         /*首先判斷 disposition 等于 INPUT_PASS_TO_DEVICE,然後判斷 dev->event 是否對其指定了一個處理函數,如果這些條件都滿足,則調用自定義的 dev->event()函數處理事件。有些事件是發送給裝置,而不是發送給 handler 處理的。event()函數用來向輸入子系統報告一個将要發送給裝置的事件,例如讓 LED 燈點亮事件、蜂鳴器鳴叫事件等。當事件報告給輸入子系統後,就要求裝置處理這個事件。*/  
  76.         if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)  
  77.         dev->event(dev, type, code, value);  
  78.         /*第 87、88 行,如果事件需要 handler 處理,則調用 input_pass_event()函數 
  79.         */  
  80.         if (disposition & INPUT_PASS_TO_HANDLERS)  
  81.                 input_pass_event(dev, type, code, value);  

        input_pass_event()

        input_pass_event()函數将事件傳遞到合适的函數,然後對其進行處理,該函數的代碼如下:

  1. static void input_pass_event(struct input_dev *dev,  
  2.         struct input_handler *handler;  
  3.         struct input_handle *handle;/*配置設定一個 input_handle 結構的指針。*/  
  4.         rcu_read_lock();  
  5.         handle = rcu_dereference(dev->grab);/*得到 dev->grab 的指針。 
  6.         grab 是強制為 input device 的 handler,這時要調用 handler的 event 函數。*/  
  7.         if (handle)  
  8.         handle->handler->event(handle, type, code, value);  
  9.         else {  
  10.         bool filtered = false;  
  11.         /*表示如果沒有為 input device 強制指定 handler,為 grab 指派,即就會周遊 input device->h_list 上的 handle 成員。如果該 handle 被打開,表示該裝置已經被一個使用者程序使用。就會調用與輸入裝置對應的 handler 的 event()函數。注意,隻有在 handle 被打開的情況下才會接收到事件,這就是說,隻有裝置被使用者程式使用時,才有必要向使用者空間導出資訊。*/  
  12.         list_for_each_entry_rcu(handle, &dev->h_list, d_node) {  
  13.         if (!handle->open)  
  14.                 continue;  
  15.         handler = handle->handler;  
  16.         if (!handler->filter) {  
  17.                 if (filtered)  
  18.                 handler->event(handle, type, code, value);  
  19.         } else if (handler->filter(handle, type, code, value))  
  20.                 filtered = true;