============================================
作者:yuanlulu
http://blog.csdn.net/yuanlulu
版權沒有,但是轉載請保留此段聲明
============================================
1.3 輸入子系統裝置驅動講解
1.3.1 打開和關閉函數
struct input_dev中有open和close兩個函數指針。在與handler第一次連接配接之後會調用open函數,斷開連接配接會調用close。open中應該完成硬體初始化的相關工作,并且申請用到的其他資源,如中斷号。close函數做相反的工作。
1.3.2 事件類型
Linux輸入子系統支援的事件類型如程式清單 1.6<!--[if gte mso 9]><![endif]-->所示。
程式清單 <!--[if supportFields]> STYLEREF 1 /s <![endif]-->1<!--[if supportFields]><![endif]-->.<!--[if supportFields]> SEQ 程式清單
#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
#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
#define EV_CNT (EV_MAX+1)
按鍵事件(EV_KEY)是最簡單的事件類型,用來描述按鍵或者按鈕。報告按鍵事件使用以下函數:
input_report_key(structinput_dev *dev, int code, int value)
code的值在<核心>include/linux/input.h中定義,大小從0到KEY_MAX。value為0時表示按鍵擡起,非0時代表按鍵按下。對同一個按鍵來說,隻有當value的值和上次不同才會産生一次事件。
除了按鍵事件,相對坐标事件(EV_REL)和絕對坐标事件(EV_ABS)也是常用的事件。為了使裝置支援這兩類事件,需要在初始化時對struct input_dev的evbit相應比特置1,并且還要分别在relbit和absbit位圖中為支援的坐标軸置1。參考<!--[if supportFields]> REF _Ref282006937 /r /h <![endif]-->1.2<!--[if gte mso 9]><![endif]--><!--[if supportFields]><![endif]-->節的7、8兩步。
相對坐标事件用來描述類似滑鼠移動的消息。報告相對坐标的函數如下:
input_report_rel(structinput_dev *dev, int code, int value)
code描述坐标軸,value代表相對移動(可正可負)。隻有當value的值非零時才能産生一個有效的事件。
絕對坐标需要額外的工作。初始化時需要填充input_dev中的一些資料域。對于支援的每個坐标軸調用如下函數:
input_set_abs_params(struct input_dev *dev, int axis,int min, int max, int fuzz, int flat);
函數參數從右往左依次代表輸入裝置指針、坐标軸、最小值、最大值、分辨率、基準值。最後兩個參數也可以填為0,代表裝置非常精确并且總能精确的回到中心位置。
input_set_abs_params函數的代碼如<!--[if supportFields]> REF _Ref282008551 /h <![endif]-->程式清單 1.7<!--[if gte mso 9]><![endif]--><!--[if supportFields]><![endif]-->所示。
程式清單 <!--[if supportFields]> STYLEREF 1 /s <![endif]-->1<!--[if supportFields]><![endif]-->.<!--[if supportFields]> SEQ 程式清單
}
另外輸入裝置驅動中經常用到同步事件(EV_SYN),輸入子系統會預設支援此事件,驅動無需注冊。滑鼠、觸摸闆之類的裝置需要用它來提示上層已經發送完了一個完整的事件報告。同步事件的報告形式如下:
input_sync(zlgkpd->input);
1.3.3 keycode、 keycodemax和keycodesize
首先說明掃描碼和鍵值的差別。如程式清單 1.4<!--[if gte mso 9]><![endif]-->所示,例子中包含四個按鍵的值,那麼掃描碼的範圍是0~3,鍵值就是keypad_keycode中的四個值。
keycode、 keycodemax和keycodesize這三個資料域儲存的值分别是鍵值數組的首位址、鍵值的個數和每個鍵值的位元組大小。有了這三個變量,就可以在運作是改變鍵盤的鍵值映射。比如原來數組中的第四個鍵值為KEY_Z,可以根據需要改為KEY_D或者其他的值。這樣同樣的掃描碼就對應的不同的鍵值。
這三個域正确填充之後,核心可以使用input_dev的成員函數來修改鍵值映射。修改映射的函數就是input_dev中的setkeycode、getkeycode這兩個函數指針對應的函數,如果注冊之前不初始化它們,則初始化函數把系統預設的函數賦給它們。
EVIOCGKEYCODE和EVIOCSKEYCODE這兩個ioctl指令分别用來檢視和修改鍵值。
1.3.4 按鍵的自動連擊
我們都有這樣的經曆:按住方向鍵不松開,一直把文檔往某個方向拉。這個功能就是自動連擊,也就是在按鍵擡起之前連續發送按鍵事件。
按鍵連擊事件(EV_REP)的開啟非常簡單,在input_devd的evbit相應比特置1即可。dev->rep[REP_DELAY]和dev->rep[REP_PERIOD]分别存儲連擊的延時和周期,如果驅動不對它們指派,則系統為他們分别賦為250和33。按鍵延時即按鍵到第一次連擊的間隔,按鍵周期即兩次連擊之間的間隔。它們的機關都是毫秒。
1.3.5 總線類型
input_dev中input_id用到了總線類型。輸入子系統支援的總線類型如程式清單 1.8<!--[if gte mso 9]><![endif]-->所示。
程式清單 <!--[if supportFields]> STYLEREF 1 /s <![endif]-->1<!--[if supportFields]><![endif]-->.<!--[if supportFields]> SEQ 程式清單
#define BUS_PCI 0x01
#define BUS_ISAPNP 0x02
#define BUS_USB 0x03
#define BUS_HIL 0x04
#define BUS_BLUETOOTH 0x05
#define BUS_VIRTUAL 0x06
#define BUS_ISA 0x10
#define BUS_I8042 0x11
#define BUS_XTKBD 0x12
#define BUS_RS232 0x13
#define BUS_GAMEPORT 0x14
#define BUS_PARPORT 0x15
#define BUS_AMIGA 0x16
#define BUS_ADB 0x17
#define BUS_I2C 0x18
#define BUS_HOST 0x19
#define BUS_GSC 0x1A
#define BUS_ATARI 0x1B
1.3.6 其他的事件類型
EV_LED和EV_SND事件是針對鍵盤上的led和蜂鳴器。這兩類事件是由輸入子系統核心發送給驅動的。
如果驅動支援這兩類事件的話,應該填充input_dev中的event函數指針,其實這是一個回調函數。另外需要填充input_dev中evbit對應的比特位。
這個回調函數可能在中斷或者中斷的底半部調用,是以event函數不能睡眠且必須盡快結束。