linux裝置驅動那點事兒之輸入子系統理論篇 (2011-08-01 23:41) 分類: linux裝置驅動程式分析
Linux輸入子系統(Input Subsystem)
1.1.input子系統概述
輸入裝置(如按鍵,鍵盤,觸控螢幕,滑鼠等)是典型的字元裝置,其一般的工作機制是低層在按鍵,觸摸等動作發生時產生一個中斷(或驅動通過timer定時查詢),然後cpu通過SPI,I2C或者外部儲存空間匯流排讀取索引值,座標等資料,放一個緩衝區,字元裝置驅動管理該緩衝區,而驅動的read()介面讓使用者可以讀取索引值,座標等資料。
在Linux中,輸入子系統是由輸入子系統裝置驅動層、輸入子系統核心層(Input Core)和輸入子系統事件處理層(Event Handler)組成。其中裝置驅動層提供對硬體各寄存器的讀寫訪問和將底層硬體對使用者輸入訪問的響應轉換為標準的輸入事件,再通過核心層提交給事件處理層;而核心層對下提供了裝置驅動層的編程介面,對上又提供了事件處理層的編程介面;而事件處理層就為我們使用者空間的應用程式提供了統一訪問裝置的介面和驅動層提交來的事件處理。所以這使得我們輸入裝置的驅動部分不在用關心對裝置檔案的操作,而是要關心對各硬體寄存器的操作和提交的輸入事件。
1.2. input子系統結構圖
input子系統結構圖如1所示:
圖1 輸入子系統結構圖
1.3.linux中輸入裝置驅動的分層
linux中輸入裝置驅動的分層如2所示:
圖2 linux中輸入裝置的分層
1.4. 輸入子系統裝置驅動層實現原理
在Linux中,Input裝置用input_dev結構體描述,定義在input.h中。裝置的驅動只需按照如下步驟就可實現了。
1).在驅動模組載入函數中設定Input裝置支援input子系統的哪些事件;
2).將Input裝置註冊到input子系統中;
3).在Input裝置發生輸入操作時(如:鍵盤被按下/抬起、觸控螢幕被觸摸/抬起/移動、滑鼠被移動/單擊/抬起時等),提交所發生的事件及對應的索引值/座標等狀態。
1.5.軟體設計流程
軟體設計流程如3所示
圖 3 input子系統軟體設計流程
1.6.與軟體設計有關的API函數
1.6.1.分配一個輸入裝置
Struct input_dev *input_allocate_device*(void);
1.6.2.註冊一個輸入裝置
Int input_register_device(struct input_dev *dev);
1.6.3.驅動實現-事件支援
Set_bit告訴inout子系統它支援哪些事件
Set_bit(EV_KEY,button_dev.evbit)
Struct input_dev中有兩個成員,一個是evbit;一個是keybit.分別用來表示裝置所支援的事件類型和按鍵類型。
1.6.3.1事件類型
Linux中輸入裝置的事件類型有(這裡只列出了常用的一些,更多請看linux/input.h中):EV_SYN 0x00 同步事件
EV_KEY 0x01 按鍵事件
EV_REL 0x02 相對座標
EV_ABS 0x03 絕對座標
EV_MSC 0x04 其它
EV_LED 0x11 LED
EV_SND 0x12 聲音
EV_REP 0x14 Repeat
EV_FF 0x15 力反饋
1.6.4.驅動實現-報告事件
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_report_abs(input_dev,ABS_X,x);//X座標
Input_report_abs(input_dev,ABS_Y,y);//Y座標
Input_report_abs(input_dev,ABS_PRESSURE,pres);//壓力
input_sync(struct input_dev *dev);//同步
1.6.5釋放與登出裝置
Void input_free_device(struct input_dev *dev);
Void input_unregister_device(struct input_dev *);