一、輸入子系統框架
輸入子系統由核心層(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 |
用來創建驅動層Dev和Handler鏈表的鏈表項結構 |
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_handler的h_list上。
三、工作流程