Linux設備驅動之——input子系統(一)

什麼是INPUT    

Input子系統處理輸入事務,任何輸入設備的驅動程序都可以通過Input輸入子系統提供的接口註冊到內核,利用子系統提供的功能來與用戶空間交互。輸入設備一般包括鍵盤,鼠標,觸摸屏等,在內核中都是以輸入設備出現的。下面分析input輸入子系統的結構,以及功能實現。

Linux中input系統主設備號是13

次設備號: 

0-31      joystick(遊戲杆)

32-62  mouse(鼠標)

63   mice(鼠標)

64-95     事件(Event)設備

Input子系統的結構

  1. Input子系統是分層結構的,總共分爲三層: 硬件驅動層,子系統核心層,事件處理層。

(1)其中硬件驅動層負責操作具體的硬件設備,這層的代碼是針對具體的驅動程序的,需要驅動程序的作者來編寫。
(2)子系統核心層是鏈接其他兩個層之間的紐帶與橋樑,向下提供驅動層的接口,向上提供事件處理層的接口。
(3)事件處理層負責與用戶程序打交道,將硬件驅動層傳來的事件報告給用戶程序。

  2.Input子系統的三個重要結構體:

input_dev 是硬件驅動層,代表一個input設備

input_handler 是事件處理層,代表一個事件處理器

input_handle 個人認爲屬於核心層,代表一個配對的input設備與input事件處理器

  1. struct input_handle {    
  2.     void *private;   //每個配對的事件處理器都會分配一個對應的設備結構,如evdev事件處理器的evdev結構,注意這個結構與設備驅動層的input_dev不同,初始化handle時,保存到這裏。     
  3.     int open;        //打開標誌,每個input_handle 打開後才能操作,這個一般通過事件處理器的open方法間接設置     
  4.     const char *name;     
  5.     struct input_dev *dev;  //關聯的input_dev結構     
  6.     struct input_handler *handler; //關聯的input_handler結構     
  7.     struct list_head    d_node;  //input_handle通過d_node連接到了input_dev上的h_list鏈表上     
  8.     struct list_head    h_node;  //input_handle通過h_node連接到了input_handler的h_list鏈表上     
  9. };    
  1. struct input_handler {  
  2.   
  3.     void *private;  
  4.   
  5.     void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);  
  6.     int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);  
  7.     void (*disconnect)(struct input_handle *handle);  
  8.     void (*start)(struct input_handle *handle);  
  9.   
  10.     const struct file_operations *fops;  
  11.     int minor;  
  12.     const char *name;  
  13.   
  14.     const struct input_device_id *id_table;  
  15.     const struct input_device_id *blacklist;  
  16.   
  17.     struct list_head    h_list;  
  18.     struct list_head    node;  
  19. };  
  1. struct input_dev {  
  2.   
  3.     void *private;  
  4.   
  5.     const char *name;  
  6.     const char *phys;  
  7.     const char *uniq;  
  8.     struct input_id id;  
  9. <span style="WHITE-SPACE: pre"> </span>........  
  10.     int (*open)(struct input_dev *dev);  
  11.     void (*close)(struct input_dev *dev);  
  12.     int (*flush)(struct input_dev *dev, struct file *file);  
  13.     int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);  
  14.     struct class_device cdev;  
  15.     union {         /* temporarily so while we switching to struct device */  
  16.         struct device *parent;  
  17.     } dev;  
  18.   
  19.     struct list_head    h_list;  
  20.     struct list_head    node;  
  1. }  

  • 在內核中,input_dev 表示一個 input設備;input_handler 來表示input設備的 interface。 所有的input_dev 用雙向鏈表 input_dev_list 連起來。
  • 在調用 int input_register_device(struct input_dev *dev) 的時候,會將新的 input_dev 加入到這個鏈表中。所有的input_handler     用雙向鏈表 input_handler_list 連起來。
  • 在調用 int input_register_handler(struct input_handler *handler) 的時候,會將新的 input_handler 加入到這個鏈表中。每 個input_dev 和 input_handler 是要關聯上才能工作的,在註冊 input_dev 或者 input_handler的時候,就遍歷上面的列表,找到相匹配的,然後調用 input_handler 的 connect函數來將它們聯繫到一起。
  • 通常在input_handler 的 connect函數中,就會創建 input_handle, input_handle就是負責將 input_dev 和input_handler 聯繫在一起的.



輸入事件

     各層之間通信的基本單位就是事件,任何一個輸入設備的動作都可以抽象成一種事件,如鍵盤的按下,觸摸屏的按下,鼠標的移動等。事件有三種屬性:類型(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_SYN 0x00 // 同步事件

#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_STATUS 0x17 //力反饋狀態
#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.分配一個輸入設備;
2.註冊一個輸入設備;
3.驅動支持什麼事件;
Set_bit告訴inout子系統它支持哪些事件
Set_bit(EV_KEY,button_dev.evbit)
Struct input_dev中有兩個成員,一個是evbit;一個是keybit.分別用來表示設備所支持的事件類型和按鍵類型。
4.驅動事件報告;
5.釋放和註銷設備;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章