什麼是INPUT node
Input子系統處理輸入事務,任何輸入設備的驅動程序均可以經過Input輸入子系統提供的接口註冊到內核,利用子系統提供的功能來與用戶空間交互。輸入設備通常包括鍵盤,鼠標,觸摸屏等,在內核中都是以輸入設備出現的。下面分析input輸入子系統的結構,以及功能實現。 linux
linux中input系統主設備號是13 函數
次設備號: 編碼
0-31 joystick(遊戲杆) spa
32-62 mouse(鼠標) .net
63 mice(鼠標) code
64-95 事件(Event)設備 接口
1. Input子系統是分層結構的,總共分爲三層: 硬件驅動層,子系統核心層,事件處理層。 遊戲
(1)其中硬件驅動層負責操做具體的硬件設備,這層的代碼是針對具體的驅動程序的,須要驅動程序的做者來編寫。
(2)子系統核心層是連接其餘兩個層之間的紐帶與橋樑,向下提供驅動層的接口,向上提供事件處理層的接口。
(3)事件處理層負責與用戶程序打交道,將硬件驅動層傳來的事件報告給用戶程序。
事件
2.Input子系統的三個重要結構體:
input_dev 是硬件驅動層,表明一個input設備
input_handler 是事件處理層,表明一個事件處理器
input_handle 我的認爲屬於核心層,表明一個配對的input設備與input事件處理器
struct input_handle { void *private; //每一個配對的事件處理器都會分配一個對應的設備結構,如evdev事件處理器的evdev結構,注意這個結構與設備驅動層的input_dev不一樣,初始化handle時,保存到這裏。 int open; //打開標誌,每一個input_handle 打開後才能操做,這個通常經過事件處理器的open方法間接設置 const char *name; struct input_dev *dev; //關聯的input_dev結構 struct input_handler *handler; //關聯的input_handler結構 struct list_head d_node; //input_handle經過d_node鏈接到了input_dev上的h_list鏈表上 struct list_head h_node; //input_handle經過h_node鏈接到了input_handler的h_list鏈表上 };
struct input_handler { void *private; void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); 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; int minor; const char *name; const struct input_device_id *id_table; const struct input_device_id *blacklist; struct list_head h_list; struct list_head node; };
struct input_dev {
void *private;
const char *name;
const char *phys;
const char *uniq;
struct input_id id; ........
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 class_device cdev;
union { /* temporarily so while we switching to struct device */
struct device *parent;
} dev;
struct list_head h_list;
struct list_head node;
}
輸入事件
各層之間通訊的基本單位就是事件,任何一個輸入設備的動做均可以抽象成一種事件,如鍵盤的按下,觸摸屏的按下,鼠標的移動等。事件有三種屬性:類型(type),編碼(code),值(value),Input子系統支持的全部事件都定義在input.h中,包括全部支持的類型,所屬類型支持的編碼等。事件傳送的方向是 硬件驅動層-->子系統核心-->事件處理層-->用戶空間
設備有着本身特殊的按鍵鍵碼,我須要將一些標準的按鍵,好比0-9,X-Z等模擬成標準按鍵,好比KEY_0,KEY-Z等,因此須要用到按鍵模擬,具體 方法就是操做/dev/input/event1文件,向它寫入個input_event結構體就能夠模擬按鍵的輸入了。
linux/input.h中有定義,這個文件還定義了標準按鍵的編碼等
struct input_event {
struct timeval time; //按鍵時間
__u16 type; //類型,在下面有定義
__u16 code; //要模擬成什麼按鍵
__s32 value;//是按下仍是釋放
};
code:
事件的代碼.若是事件的類型代碼是EV_KEY,該代碼code爲設備鍵盤代碼.代碼植0~127爲鍵盤上的按鍵代碼,0x110~0x116 爲鼠標上按鍵代碼,其中0x110(BTN_ LEFT)爲鼠標左鍵,0x111(BTN_RIGHT)爲鼠標右鍵,0x112(BTN_ MIDDLE)爲鼠標中鍵.其它代碼含義請參看include/linux/input.h文件. 若是事件的類型代碼是EV_REL,code值表示軌跡的類型.如指示鼠標的X軸方向REL_X(代碼爲0x00),指示鼠標的Y軸方向REL_Y(代碼 爲0x01),指示鼠標中輪子方向REL_WHEEL(代碼爲0x08).
value:
事件的值.若是事件的類型代碼是EV_KEY,當按鍵按下時值爲1,鬆開時值爲0;若是事件的類型代碼是EV_ REL,value的正數值和負數值分別表明兩個不一樣方向的值.
type:
/*
* Event types功能實現
*/
#define EV_SYN0x00 // 表示設備支持全部的事件
#define EV_KEY 0x01 // 鍵盤或者按鍵,表示一個鍵碼
#define EV_REL 0x02 // 鼠標設備,表示一個相對的光標位置結果(相對座標)
#define EV_ABS 0x03 // 手寫板產生的值,其是一個絕對整數值
#define EV_MSC 0x04 // 其餘類型
#define EV_SW 0x05 //
#define EV_LED 0x11 // LED燈設備
#define EV_SND 0x12 // 輸入聲音
#define EV_REP 0x14 // 容許重複按鍵類型
#define EV_FF 0x15 //
#define EV_PWR 0x16 // 電源管理事件
#define EV_FF_STATUS0x17
#define EV_MAX 0x1f
有哪些API
分配/釋放一個輸入設備:
struct input_dev *input_allocate_device(void);
void input_free_device(struct input_dev *dev);
註冊/註銷輸入設備:
int __must_check input_register_device(struct input_dev *);
void input_unregister_device(struct input_dev *);
報告輸入事件:
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);/* 報告指定type、code的輸入事件 */
void input_report_key(struct input_dev *dev, unsigned int code, int value);/* 報告鍵值 */
void input_report_rel(struct input_dev *dev, unsigned int code, int value);/* 報告相對座標 */
void input_report_abs(struct input_dev *dev, unsigned int code, int value);/* 報告絕對座標 */
void input_sync(struct input_dev *dev);/* 報告同步事件 */
Input驅動編寫步驟
1.分配一個輸入設備;