input子系統詳解

1、初識linux輸入子系統

linux輸入子系統(linux input subsystem)從上到下由三層實現,分別爲:輸入子系統事件處理層(EventHandler)、輸入子系統核心層(InputCore)和輸入子系統設備驅動層。html

 

對於輸入子系統設備驅動層而言,主要實現對硬件設備的讀寫訪問,中斷設置,並把硬件產生的事件轉換爲核心層定義的規範提交給事件處理層。即將底層的硬件輸入轉化爲統一事件形式,想輸入核心(Input Core)彙報。linux

 

對於核心層而言,爲設備驅動層提供了規範和接口。設備驅動層只要關心如何驅動硬件並得到硬件數據(例如按下的按鍵數據),而後調用核心層提供的接口,核心層會自動把數據提交給事件處理層。承上啓下。爲驅動層提供輸入設備註冊與操做接口,如:input_register_device;通知事件處理層對事件進行處理;在/Proc下產生相應的設備信息編程

 

對於事件處理層而言,則是用戶編程的接口(設備節點),並處理驅動層提交的數據處理。和用戶空間交互。(Linux中在用戶空間將全部的設備都當初文件來處理,因爲在通常的驅動程序中都有提供fops接口,以及在/dev下生成相應的設備文件nod,這些操做在輸入子系統中由事件處理層完成)框架

 

對於linux輸入子系統的框架結構以下圖1所示:函數

 

由上圖所展示的內容就是linux輸入子系統的分層結構。spa

 

/dev/input目錄下顯示的是已經註冊在內核中的設備編程接口,用戶經過open這些設備文件來打開不一樣的輸入設備進行硬件操做。.net

 

事件處理層爲不一樣硬件類型提供了用戶訪問及處理接口。例如當咱們打開設備/dev/input/mice時,會調用到事件處理層的Mouse Handler來處理輸入事件,這也使得設備驅動層無需關心設備文件的操做,由於Mouse Handler已經有了對應事件處理的方法。code

 

輸入子系統由內核代碼drivers/input/input.c構成,它的存在屏蔽了用戶到設備驅動的交互細節,爲設備驅動層和事件處理層提供了相互通訊的統一界面。htm

由上圖可知輸入子系統核心層提供的支持以及如何上報事件到input event drivers。blog

做爲輸入設備的驅動開發者,須要作如下幾步:

  在驅動加載模塊中,設置你的input設備支持的事件類型,類型參見表1設置

    註冊中斷處理函數,例如鍵盤設備須要編寫按鍵的擡起、放下,觸摸屏設備須要編寫按下、擡起、絕對移動,鼠標設備須要編寫單擊、擡起、相對移動,而且須要在必要的時候提交硬件數據(鍵值/座標/狀態等等)

      將輸入設備註冊到輸入子系統中

 

 

表1  Linux輸入子系統支持的數據類型

EV_SYN     0x00    同步事件

EV_KEY     0x01    按鍵事件

EV_REL     0x02    相對座標(如:鼠標移動,報告相對最後一次位置的偏移)

EV_ABS     0x03    絕對座標(如:觸摸屏或操做杆,報告絕對的座標位置)

EV_MSC     0x04    其它

EV_SW      0x05    開關

EV_LED     0x11    按鍵/設備燈

EV_SND     0x12    聲音/警報

EV_REP     0x14    重複

EV_FF      0x15    力反饋

EV_PWR    0x16    電源

EV_FF_STATUS    0x17   力反饋狀態

EV_MAX    0x1f    事件類型最大個數和提供位掩碼支持


由表1可知,設備所能表示的事件種類,一個設備能夠選擇一個或多個事件類型上報給輸入子系統。

 

Linux輸入子系統提供了設備驅動層上報輸入事件的函數,在include/linux/input.h中:

voidinput_report_key(struct input_dev *dev, unsigned int code, int value);      //上報按鍵事件

voidinput_report_rel(struct input_dev *dev, unsigned int code, int value);       //上報相對座標事件

voidinput_report_abs(struct input_dev *dev, unsigned int code, int value);       //上報絕對座標事件

……

當提交輸入設備產生的輸入事件以後,須要調用下面的函數來通知輸入子系統,以處理設備產生的完整事件:

void input_sync(struct input_dev *dev);  

 

 設備描述:

input_dev結構

 實現設備驅動核心工做是:向系統報告按鍵、觸摸屏等輸入事件(event,經過input_event結構描述),再也不須要關心文件操做接口。驅動報告事件通過inputCoreEventhandler到達用戶空間。

 

註冊輸入設備函數:

int input_register_device(struct input_dev *dev)

 

註銷輸入設備函數:

void input_unregister_device(struct input_dev *dev)

 

驅動實現——初始化(事件支持)

set_bit()告訴input輸入子系統支持哪些事件,哪些按鍵。例如:

 

set_bit(EV_KEY,button_dev.evbit)  (其中button_devstruct input_dev類型)

struct input_dev中有兩個成員爲:

evbit:

事件類型(包括

EV_RST,EV_REL,EV_MSC,EV_KEY,EV_ABS,EV_REP等)

keybit:

按鍵類型(當事件類型爲EV_KEY時包括

BTN_LEFT,BTN_0,BTN_1,BTN_MIDDLE等)

驅動實現——報告事件:

用於報告EV_KEY,EV_REL,EV_ABS事件的函數分別爲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)

 

驅動實現——報告結束:

input_sync()同步用於告訴input core子系統報告結束。

 

實例:觸摸屏設備驅動中,一次點擊的整個報告過程以下:

input_reprot_abs(input_dev,ABS_X,x);   //x座標

input_reprot_abs(input_dev,ABS_Y,y);   // y座標

input_reprot_abs(input_dev,ABS_PRESSURE,1);

input_sync(input_dev);//同步結束

 

 

實例分析(按鍵中斷程序):

//按鍵初始化

static int __init button_init(void)

{//申請中斷

if(request_irq(BUTTON_IRQ,button_interrupt,0,」button」,NUll))

      return –EBUSY;

set_bit(EV_KEY,button_dev.evbit); //支持EV_KEY事件

 

set_bit(BTN_0,button_dev.keybit); //支持設備兩個鍵

 

set_bit(BTN_1,button_dev.keybit); //

 

input_register_device(&button_dev);//註冊input設備

}

/*在按鍵中斷中報告事件*/

Static void button_interrupt(int irq,void *dummy,struct pt_regs *fp)

{

input_report_key(&button_dev,BTN_0,inb(BUTTON_PORT0));//讀取寄存器BUTTON_PORT0的值

input_report_key(&button_dev,BTN_1,inb(BUTTON_PORT1));

input_sync(&button_dev);

}

總結:input子系統仍然是字符設備驅動程序,可是代碼量減小不少,input子系統只須要完成兩個工做:初始化和事件報告(這裏在linux中是經過中斷來實現的)。讀者不妨用sourceinsignt 輸入input_init去搜關於輸入子系統的實現

 

 

http://blog.csdn.net/ielife/article/details/7798952

http://www.cnblogs.com/deng-tao/p/6094049.html

http://www.cnblogs.com/myblesh/articles/2367648.html

相關文章
相關標籤/搜索