input子系統框架



 

一、輸入子系統框架

輸入子系統由核心層(Input Core)、驅動層和事件處理層(Event Handler)三部份組成,如下圖所示,一個輸入事件通過 Driver -> InputCore ->Eventhandler -> userspace 的順序到達用戶空間傳給應用程序。

 

                      

 

設備驅動層:將底層的硬件輸入事件轉化爲統一事件形式,向輸入核心(Input Core)彙報。
核心層:承上啓下:對輸入子系統進行了抽象, 對下提供了設備驅動的接口,對上提供了Event Handler層的編程接口。
事件處理層:和用戶層交互,提供設備的read和write等函數。

二、主要數據結構

                                            表 1     Input Subsystemmain data structure

數據結構

用途

定義位置

具體數據結構的分配和初始化

Struct input_dev

驅動層物理Input設備的基本數據結構

Input.h

通常在具體的設備驅動中分配和填充具體的設備結構

Struct Evdev

Struct Mousedev

Struct Keybdev…

Event Handler層邏輯Input設備的數據結構

Evdev.c

Mousedev.c

Keybdev.c

Evdev.c/Mouedev.c …中分配

 

Struct Input_handler

Event Handler的結構

Input.h

Event Handler層,定義一個具體的Event Handler

Struct Input_handle

用來創建驅動層DevHandler鏈表的鏈表項結構

Input.h

Event Handler層中分配,包含在Evdev/Mousedev…中。

Struct input_event

驅動層向核心層上報數據的結構

Input.h

在驅動層中斷函數中創建

 

下面詳解介紹各個數據結構:

(1)設備驅動層

    每個輸入設備用structinput_dev表示,通過input_register_device向核心層註冊輸入設備
struct input_dev {
 const char *name;//
設備名
 const char *phys;
 const char *uniq;
 struct input_id id;//
用於匹配事件處理層handler
 unsigned long evbit[BITS_TO_LONGS(EV_CNT)];//用於記錄支持的事件類型的位圖
 unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//記錄支持的按鍵值的位圖
 unsigned long relbit[BITS_TO_LONGS(REL_CNT)];//記錄支持的相對座標的位圖
 unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];//記錄支持的絕對座標的位圖
 unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
 unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
 unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
 unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
 unsigned long swbit[BITS_TO_LONGS(SW_CNT)];

 

 unsigned int keycodemax;//支持的按鍵值的個數
 unsigned int keycodesize;//每個鍵值的字節數
 void *keycode;//存儲按鍵值的數組首地址
 int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
 int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);

 

 struct ff_device *ff;
 unsigned int repeat_key;//最近一次按鍵值,用於連擊
 struct timer_list timer;//自動連擊計時器
 int sync;//最後一次同步後沒有新的事件置1


 int abs[ABS_MAX + 1];
 int rep[REP_MAX + 1];

 

 unsigned longkey[BITS_TO_LONGS(KEY_CNT)];//反映當前按鍵狀態的位圖
 unsigned long led[BITS_TO_LONGS(LED_CNT)];//反映當前led狀態的位圖
 unsigned long snd[BITS_TO_LONGS(SND_CNT)];//反映當前beep狀態的位圖
 unsigned long sw[BITS_TO_LONGS(SW_CNT)];

 

 int absmax[ABS_MAX + 1];
 int absmin[ABS_MAX + 1];
 int absfuzz[ABS_MAX + 1];
 int absflat[ABS_MAX + 1];

 

 int (*open)(struct input_dev *dev);//打開函數
 void (*close)(struct input_dev *dev);//關閉函數
 int (*flush)(struct input_dev *dev, struct file *file);//斷開連接時沖洗數據
 int (*event)(struct input_dev *dev, unsigned int type, unsigned int code,int value);//回調函數,可選
 struct input_handle *grab;

 

 spinlock_t event_lock;
 struct mutex mutex;
 unsigned int users;
 int going_away;

 

 struct device dev;//設備模型相關
 /*static LIST_HEAD(input_dev_list);input子系統維護的設備鏈表*/
 struct list_head h_list;// 將input_handle加入輸入設備維護的input_handle鏈表
 struct list_head node;//將該設備掛靠到輸入子系統維護的全局input_dev_list設備鏈表上

};

 

input子系統將硬件產生的事件統一用structinput_event來表示。

struct input_event {
        struct timeval time;//事件發生的時間
        unsigned short type;//事件的類型
        unsigned short code;//事件的代碼
        unsigned int value; //事件的值

}

struct input_id {
       __u16 bustype;/*總線類型*/
       __u16 vendor; /*生產商編號*/
       __u16 product; /*產品編號*/
       __u16 version;/* 版本號 */
};

如果需要特定的事件處理器來處理這個設備的話,這幾個就非常重要,因爲子系統核心是通過他們,將設備驅動與事件處理層聯繫起來的。但是因爲觸摸屏驅動所用的事件處理器爲evdev,匹配所有,所有這個初始化也無關緊要。

(2)事件處理層

 input子系統使用structinput_handler代表事件處理層的處理器,通過input_register_handler向核心層註冊。

struct input_handler {
       void *private;
       //
當設備驅動層有事件上報時將導致該函數被調用
       void (*event)(struct input_handle *handle,unsigned int type, unsigned int code, int value);
       //
當調用input_register_device和input_register_handler的時候將導致該函數被調用
       int (*connect)(struct input_handler*handler, struct input_dev *dev, const struct input_device_id *id);
       void (*disconnect)(struct input_handle*handle);
       void (*start)(struct input_handle*handle);
       const struct file_operations*fops;//handler
提供的讀寫等操作函數
       int minor;//次設備號
       const char *name;
       const struct input_device_id *id_table;//
支持的input_dev的設備id
       const struct input_device_id *blacklist;//禁止的input_dev的設備id
       struct list_head h_list ;//將input_handle加入事件處理器維護的input_handle鏈表
       /*staticLIST_HEAD(input_handler_list);input子系統維護的事件處理鏈表*/
       struct list_head node;//將該input_hander掛靠在input_handler_list鏈表中使用
};

 

當input_device或input_handler註冊的時候,如果設備驅動層的input_device和事件處理層的input_handler有相匹配的話,input子系統就新建一個input_handle連聯繫它們。其實質就是:將新建的input_handle分別掛靠在input_dev和input_handler的h_list鏈表上去。這樣一個input_dev就可以根據它的它的input_handle鏈表找到它的事件處理方法

 

input_handler,同樣input_handler也可以根據它的input_handle鏈表找到它能處理的設備input_dev。可以這麼說input_handle是input_dev和input_handler的紐帶。

 

struct input_handle {
     void *private;
     int open;//
//記錄設備的打開次數(有多少個應用程序訪問設備)
     const char *name;
     struct input_dev *dev; //
指向它所關聯的input_dev設備
     struct input_handler *handler; //指向它所關聯input_handler設備處理方法
     struct list_head d_node; //用於將該input_handle加入到它關聯的input_dev的h_list鏈表中
     struct list_head h_node; //用於將該input_handle加入到它關聯的input_handler的h_list鏈表中
};

 

通過input_register_handle向核心層註冊,將自己分別掛在了input_dev input_handlerh_list上。

 

三、工作流程

 

 

 

 

 

 

 

 

 

 

 

發佈了203 篇原創文章 · 獲贊 71 · 訪問量 54萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章