Linux input子系統分析之三 input device/handler註冊與註銷分析

上一章我們分析了input子系統主要的數據結構,本章我們主要分析input hander、input device、input handle的註冊與註銷。本章的主要內容如下:

一、input device的註冊與註銷說明

二、input handler的註冊與註銷說明

三、input handle的註冊與註銷說明

四、input事件分發說明


在分析input device、input handler、input handle的註冊與註銷時,我們還是看下這些數據結構的關聯,如下圖所示即為這三個數據結構的關聯,而input device、input handler、input handle的註冊與註銷則註冊用於建立或移除這些數據結構間的關聯。


Linux input子系統分析之三 input device/handler註冊與註銷分析

input device的註冊與註銷說明

Input device的註冊

在前面我們也說了,input 子系統device、handler的註冊與註銷,與設備驅動模型子系統中設備、驅動的註冊與註銷機制類似,針對設備、驅動的註冊,在設備和驅動的註冊接口中,通過遍歷總線上所有已註冊的驅動與設備,進行設備與驅動的匹配檢測,若設備與驅動完成一次匹配則不再繼續遍歷檢測。

而針對input子系統的input device的註冊,其流程與設備驅動模型中設備、驅動的註冊流程相似,其實現的流程大致如下:

  1. 為input_dev創建struct device類型的變量,並設置其所屬的class為input_class,並調用device_add完成device類型變量的註冊,至此完成strcut device類型變量註冊至input_class中,且完成了input_dev對應的sysfs屬性文件的創建,包括 name 、phys、uevent、uniq、bustype、product、vendor version、abs、ev、ff、 key、led、msc、rel 、snd、sw(對應默認屬性input_dev_attr_group、input_dev_id_attr_group、input_dev_caps_attr_group,在調用input_allocate_device、devm_input_allocate_device時,通過調用input_allocate_device時,會設置input dev的struct device類型的成員變量,並設置其所屬的class為input_class、dev_type為input_dev_type);
  2. 將該input_device註冊至input_dev_list;
  3. 遍歷input_handler_list鏈表,針對input_handler_list上每一個input_handler,均與註冊的input_device進行匹配檢測,若匹配檢測成功,則調用input_handler->connect接口,進行input_handler與input_device的綁定(通過調用input_register_handle實現,也可以理解為在input_handler、input_device上完成input_handler、input_device的事件消息的訂閱操作)。因input_handler和input_device可實現多對多的綁定,因此,會遍歷input_handler_list鏈表上所有已註冊的input_handler,而不是檢測到一個input_handler的匹配即返回。


以上即為input_device註冊的主要過程,與設備驅動模型中設備、驅動的註冊流程相比,input_device的註冊相對簡單很多,只是遍歷input_handler_list上每一個input_handler,實現一個input_device可以綁定多個input_handler(也可以理解為在該input_device上,多個input_handler進行了input event消息的訂閱,當input_device上觸發input事件後,則input_device會將input event消息分發給所有訂閱的input handler。同時該input_device也為每一個匹配的input_handler上進行了inject input event消息的訂閱,當input_handler有event發送給input_device時,該input_handler也將該event消息分發給所有訂閱的input device)。

當然以上流程主要是input device註冊主要的處理流程,在input_register_device接口中,也會做一些參數的合理性檢測、存儲input event消息的內存申請等操作。如下為該函數的處理流程,具體的代碼不在此處分析,讀者可自行分析,處理流程也就是這些步驟。


Linux input子系統分析之三 input device/handler註冊與註銷分析

Input device的註銷

該函數實現的功能與上面剛好相反,主要功能如下:

  1. 針對該input device上所有訂閱的input_handle,將其open引用計數設置為0,並設置input device的going_away值為true;
  2. 針對該input device所有訂閱的input_handle,調用其關聯input_handler的disconnect接口,解除input_dev、input_handle、input_handle的關聯;
  3. 將該input_dev對應的struct device類型成員變量從設備驅動模型子系統中刪除(即刪除與input_class的關聯,並移除相關的屬性文件等)


如下是相關函數的定義,相對來說也比較好理解下面的代碼。


Linux input子系統分析之三 input device/handler註冊與註銷分析

input handler的註冊與註銷說明

Input handler的註冊

Input handler的註冊與input device的註冊類似,其接口名稱為input_register_handler,流程如下:

  1. 將該input_device註冊至input_handler_list;
  2. 遍歷input_dev_list鏈表,針對input_dev_list上每一個input_dev,均與註冊的input_device進行匹配檢測,若匹配檢測成功,則調用input_handler->connect接口,進行input_handler與input_device的綁定(通過調用input_register_handle實現,也可以理解為在input_handler、input_device上完成input_handler、input_device的事件消息的訂閱操作)。因input_handler和input_device可實現多對多的綁定,因此,會遍歷input_dev_list鏈表上所有已註冊的input_dev,而不是檢測到一個input_dev的匹配即返回。

如下即為input_register_handler的處理流程


Linux input子系統分析之三 input device/handler註冊與註銷分析

與input device相比,僅需要input_handler註冊至鏈表、遍歷input_dev_list鏈表的每一個input

dev進行匹配檢測並完成匹配綁定操作。


Input handler的註銷

Input handler註銷剛好與註冊相反,針對已綁定的所有input device,均調用input_handler->disconnect,進行解綁操作(主要是調用input_unregister_handle,進行input_handle的註銷,從而解除input device、input handle、input handler的關聯),如下即為input_unregister_handler的代碼實現,邏輯還是比較簡單的,不再贅述。

Linux input子系統分析之三 input device/handler註冊與註銷分析


Input handle的註冊與註銷

Input handle的註冊

Input handle的註冊函數為input_register_handle,input_handle主要用於實現input handler、input device的關聯操作,其主要實現的內容如下:

  1. 完成input_handle與input_handler的關聯;
  2. 完成input_handle與input_dev的關聯。

下面是函數input_register_handle的代碼實現:

  1. 將該input_handle註冊到input_dev的h_list鏈表上;
  2. 將該input_handle註冊到input_handler的h_list鏈表上;
  3. 若該input handler提供start接口,則調用start接口,執行start中的操作。
Linux input子系統分析之三 input device/handler註冊與註銷分析

Input handle的註銷

註銷接口為input_unregister_handle,主要是解除與input_handler、input_dev的關聯,其代碼實現較簡單,此處不再細述。

Input handle的註冊與註銷是如何調用的呢?

在input_register_handler、input_register_device的接口中,當input dev、input handler匹配成功,則會調用input handler的connect函數指針,而其connect函數中,則會完成如下操作:

  1. 調用input_register_handle,完成input handler、input handle、input device的關聯;
  2. 調用input_open_device,執行input device的打開(若該input device已執行過打開操作,則只增加device的引用計數即可,即users++).


而input handle的註銷,則一般在input handler的disconnect接口中調用input_unregister_handle,去除input handler、input handle、input device的關聯。


Input event的事件分發機制

input子系統提供了兩個事件分發接口,即input_event、input_inject_event,其中input_event主要由

input_dev使用,實現將input event分發給input handler;而input_inject_event則主要由input_handler調用,實現將event分發給input device。這兩個函數最終均調用input_handle_event接口進行事件的分發操作,而在input_handle_event接口中,則主要實現如下功能:

  1. 若待分發事件是需要分發給input handler,則調用input_pass_values接口,將input event分發給input handler,最終針對每一個input event,均調用input_handler的events/event接口,由input _handler進行input事件的處理;
  2. 若待分發事件時需要分發給input device,則調用input_dev->event,由input_dev的event接口進行事件的處理即可。


針對需要分發給input handler的事件,還有如下需要說明:

  1. 若input_dev發送了EV_SYN事件,則需要將事件立即分發給input handler,但此時需要保證該input_dev至少存在兩個事件(即若只有一個EV_SYN事件,則並不會將事件發送給input handler);
  2. 若input_dev沒有使用EV_SYN事件,則當該input_dev存儲的event個數大於等於dev->max_vals - 2時,也會將所有存儲的事件分發給所有關聯的input handler。


以上即為本章的內容,主要說明了input handler、input handle、input dev的註冊與註銷以及事件分發接口,相對來說input 子系統核心層的代碼實現還是比較容易理解的。下一章我們將分析一個input handler實例evdev。


分享到:


相關文章: