[arm 驱动]Linux输入子系统分析
首先說(shuō)明一下,本文是基于Linux-2.6.38版本內(nèi)核來(lái)分析Linux輸入子系統(tǒng)架構(gòu)和原理的。這陣子本來(lái)沒有打算花時(shí)間來(lái)分析Linux input system的,然而當(dāng)在研究S3C6410觸摸屏驅(qū)動(dòng)的時(shí)候悲劇不期而至,內(nèi)核中并沒有實(shí)現(xiàn)6410的觸摸屏驅(qū)動(dòng),不過(guò)有關(guān)于S3C2410觸摸屏的驅(qū)動(dòng),往s3c2410_ts.c文件里面一看,居然實(shí)現(xiàn)過(guò)程中用到了輸入子系統(tǒng)這一神馬機(jī)制。瞄了下代碼,流程基本知道了,但是關(guān)于輸入子系統(tǒng)的原理是怎樣的呢?全部知其然,好吧,就去了解這一神秘的東東吧!Now。。。
1、為何引入input system?
? ? ? 以前我們寫一些輸入設(shè)備(鍵盤、鼠標(biāo)等)的驅(qū)動(dòng)都是采用字符設(shè)備、混雜設(shè)備處理的。問(wèn)題由此而來(lái),Linux開源社區(qū)的大神們看到了這大量輸入設(shè)備如此分散不堪,有木有可以實(shí)現(xiàn)一種機(jī)制,可以對(duì)分散的、不同類別的輸入設(shè)備進(jìn)行統(tǒng)一的驅(qū)動(dòng),所以才出現(xiàn)了輸入子系統(tǒng)。
? ? ? 輸入子系統(tǒng)引入的好處:
(1)統(tǒng)一了物理形態(tài)各異的相似的輸入設(shè)備的處理功能。例如,各種鼠標(biāo),不論P(yáng)S/2、USB、還是藍(lán)牙,都被同樣處理。
(2)提供了用于分發(fā)輸入報(bào)告給用戶應(yīng)用程序的簡(jiǎn)單的事件(event)接口。你的驅(qū)動(dòng)不必創(chuàng)建、管理/dev節(jié)點(diǎn)以及相關(guān)的訪問(wèn)方法。因此它能夠很方便的調(diào)用輸入API以發(fā)送鼠標(biāo)移動(dòng)、鍵盤按鍵,或觸摸事件給用戶空間。X windows這樣的應(yīng)用程序能夠無(wú)縫地運(yùn)行于輸入子系統(tǒng)提供的event接口之上。
(3)抽取出了輸入驅(qū)動(dòng)的通用部分,簡(jiǎn)化了驅(qū)動(dòng),并提供了一致性。例如,輸入子系統(tǒng)提供了一個(gè)底層驅(qū)動(dòng)(成為serio)的集合,支持對(duì)串口和鍵盤控制器等硬件輸入的訪問(wèn)。
注:更多詳細(xì)描述可參見《精通Linux設(shè)備驅(qū)動(dòng)程序開發(fā)》這本書。
2、輸入子系統(tǒng)架構(gòu)
上圖展示了輸入子系統(tǒng)的操作。此子系統(tǒng)包括一前一后運(yùn)行的兩類驅(qū)動(dòng):輸入事件(event)驅(qū)動(dòng)和輸入設(shè)備(device)驅(qū)動(dòng)。
? ? ? ?輸入事件驅(qū)動(dòng)負(fù)責(zé)和應(yīng)用程序的接口;
? ? ? ?而輸入設(shè)備驅(qū)動(dòng)負(fù)責(zé)和底層輸入設(shè)備的通信。
? ? ? ?輸入事件驅(qū)動(dòng)和輸入設(shè)備驅(qū)動(dòng)都可以利用輸入子系統(tǒng)的高效、可重用的核心提供的服務(wù)。
? ? ? ?Now,我們看到輸入子系統(tǒng)中有兩個(gè)類型的驅(qū)動(dòng),當(dāng)我們要為一個(gè)輸入設(shè)備(如觸摸屏)的編寫驅(qū)動(dòng)的時(shí)候,我們是要編寫兩個(gè)驅(qū)動(dòng):輸入設(shè)備驅(qū)動(dòng)和輸入事件驅(qū)動(dòng)??
? ? ? 答案是否定的。在子系統(tǒng)中,事件驅(qū)動(dòng)是標(biāo)準(zhǔn)的,對(duì)所有的輸入類都是可以用的,所以你更可能的是實(shí)現(xiàn)輸入設(shè)備驅(qū)動(dòng)而不是輸入事件驅(qū)動(dòng)。你的設(shè)備可以利用一個(gè)已經(jīng)存在的,合適的輸入事件驅(qū)動(dòng)通過(guò)輸入核心和用戶應(yīng)用程序接口。
3、主要數(shù)據(jù)結(jié)構(gòu)和內(nèi)核編程接口
input_event
include/linux/input.h
evdev產(chǎn)生的每個(gè)事件包都采用此格式。
input_dev
include/linux/input.h
代表一個(gè)輸入設(shè)備。
input_handler
include/linux/serial_core.h
事件驅(qū)動(dòng)支持的入口函數(shù)。
psmouse_protocol
drivers/input/mouse/psmouse-base.c
所支持的PS/2鼠標(biāo)協(xié)議驅(qū)動(dòng)相關(guān)的信息。
psmouse
drivers/input/mouse/psmouse.h
PS/2鼠標(biāo)驅(qū)動(dòng)支持的方法。
內(nèi)核編程接口概述 內(nèi)核接口位置描述
input_register_device()
drivers/input/input.c
向input核心注冊(cè)一個(gè)設(shè)備。
input_unregister_device()
drivers/input/input.c
從input核心移除一個(gè)設(shè)備。
input_report_rel()
include/linux/input.h
在某個(gè)方向產(chǎn)生相對(duì)移動(dòng)。
input_report_abs()
include/linux/input.h
在某個(gè)方向產(chǎn)生絕對(duì)移動(dòng)。
input_report_key()
include/linux/input.h
產(chǎn)生一個(gè)按鍵或按鈕按擊。
input_sync()
include/linux/input.h
表明輸入子系統(tǒng)能收集以前產(chǎn)生的事件,將這些事件組成一個(gè)evdev包,并通過(guò)/dev/input/ inputX發(fā)送給用戶空間。
input_register_handler()
drivers/input/input.c
注冊(cè)一個(gè)用戶事件驅(qū)動(dòng)。
sysfs_create_group()
fs/sysfs/group.c
用特定屬性創(chuàng)建sysfs節(jié)點(diǎn)組。
sysfs_remove_group()
fs/sysfs/group.c
移除用sysfs_create_group()創(chuàng)建的sysfs組。
tty_insert_flip_char()
include/linux/tty_flip.h
發(fā)送一個(gè)字符給線路規(guī)程層。
platform_device_register_simple()
drivers/base/platform.c
創(chuàng)建一個(gè)簡(jiǎn)單平臺(tái)設(shè)備。
platform_device_unregister()
drivers/base/platform.c
卸載一個(gè)平臺(tái)設(shè)備。
4、輸入設(shè)備驅(qū)動(dòng)(注意,以下是結(jié)構(gòu)詳細(xì)描述)
在輸入子系統(tǒng)的設(shè)備驅(qū)動(dòng)中,最重要的數(shù)據(jù)結(jié)構(gòu)是struct input_dev,需要完成的大部分工作都是圍繞著它來(lái)的,它是驅(qū)動(dòng)的主體。每個(gè)struct input_dev代表一個(gè)輸入設(shè)備。/* include/linux/input.h */
struct input_dev {
? ? ? ? const char *name; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*設(shè)備名 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*/
? ? ? ? const char *phys; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? const char *uniq;
? struct input_id id; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*用于匹配事件處理層handler ? */
? ? ? ? unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*用于記錄支持的事件類型的位圖*/
? ? ? ? unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; ? ? ? ? ? ? ? ? ? ? ? /*記錄支持的按鍵值的位圖 ? ? ? ?*/
? ? ? ? unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; ? ? ? ? ? ? ? ? ? ? ? ? /*記錄支持的相對(duì)坐標(biāo)的位圖 ? */
? ? ? ? unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; ? ? ? ? ? ? ? ? ? ? ? /*記錄支持的絕對(duì)坐標(biāo)的位圖 ? */
? ? ? ? unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
? ? ? ? unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; ? ? ? ? ? ? ? ? ? ? ? ?/*led ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; ? ? ? ? ? ? ? ? ? ? ? /*beep ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
? ? ? ? unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
? ? ? ? unsigned int keycodemax; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*支持的按鍵值的個(gè)數(shù) ? ? ? ? ? ? ? ?*/
? ? ? ? unsigned int keycodesize; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*每個(gè)鍵值的字節(jié)數(shù) ? ? ? ? ? ? ? ? ? ?*/
? ? ? ? void *keycode; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*存儲(chǔ)按鍵值的數(shù)組首地址 ? ? ? ? ? ? */
? ? ? ? int(*setkeycode)(struct input_dev *dev, int scancode, int keycode); ? ? ?/* 修改鍵值的函數(shù),可選 ? ? ? ? ? ? */
? ? ? ? int(*getkeycode)(struct input_dev *dev, int scancode, int *keycode); ? ?/* 獲取掃描碼的鍵值,可選 ? ? ? ? */
? ? ? ? structff_device *ff;
? ? ? ? unsigned int repeat_key; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*最近一次按鍵值,用于連擊 ? ? */
? ? ? ? struct timer_list timer; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*自動(dòng)連擊計(jì)時(shí)器 ? ? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? int sync; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*最后一次同步后沒有新的事件置1*/
? ? ? ? int abs[ABS_MAX + 1]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* 當(dāng)前各個(gè)坐標(biāo)的值 ? ? ? ? ? ? ? ? ? ? ? ? ? ?*/
? ? ? ? int rep[REP_MAX + 1]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*自動(dòng)連擊的參數(shù) ? ? ? ? ? ? ?*/
? ? ? ? unsigned longkey[BITS_TO_LONGS(KEY_CNT)]; ? ? ? ? ? ? ? ? ? ? ? ? ? /*反映當(dāng)前按鍵狀態(tài)的位圖 ? ? ? ?*/
? ? ? ? unsigned long led[BITS_TO_LONGS(LED_CNT)]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*反映當(dāng)前l(fā)ed狀態(tài)的位圖 ? ? ? ? ?*/
? ? ? ? unsigned long snd[BITS_TO_LONGS(SND_CNT)]; ? ? ? ? ? ? ? ? ? ? ? ? ? /*反映當(dāng)前beep狀態(tài)的位圖 ? ? ? ?*/
? ? ? ? unsigned long sw[BITS_TO_LONGS(SW_CNT)]; ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? int absmax[ABS_MAX + 1]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*記錄各個(gè)坐標(biāo)的最大值 ? ? ? ? ? ?*/
? ? ? ? int absmin[ABS_MAX + 1]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*記錄各個(gè)坐標(biāo)的最小值 ? ? ? ? ? ?*/
? ? ? ? int absfuzz[ABS_MAX + 1]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*記錄各個(gè)坐標(biāo)的分辨率 ? ? ? ? ? ?*/
? ? ? ? int absflat[ABS_MAX + 1]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*記錄各個(gè)坐標(biāo)的基準(zhǔn)值 ? ? ? ? ? ?*/
? ? ? ? int(*open)(struct input_dev *dev); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*打開函數(shù) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? void(*close)(struct input_dev *dev); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*關(guān)閉函數(shù) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? int(*flush)(struct input_dev *dev, struct file *file); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* 斷開連接時(shí)沖洗數(shù)據(jù) ? ? ? ? ? ? ? ? */
? ? ? ? int(*event)(struct input_dev *dev, unsigned int type, unsigned int code, intvalue); /* 回調(diào)函數(shù),可選 ? ? ? */
struct input_handle *grab;
? ? ? ? spinlock_t event_lock;
? ? ? ? struct mutex mutex;
? ? ? ? unsigned int users;
? ? ? ? int going_away;
? ? ? ? struct device dev;
? ? ? ? struct list_head ? ?h_list;?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*handle鏈表 ? ? ? ? ? ? ? ? ? ? ? ? ? */ ? ?
? ? ? ? struct list_head ??node;?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*input_dev鏈表 ? ? ? ? ? ? ? ? ? ? ? */
};
? ? ? struct input_event是事件傳送的載體,輸入子系統(tǒng)的事件都是包裝成struct input_event傳給用戶空間。??struct input_event成員介紹
/* include/linux/input.h */
struct input_event {
? ? ? ? struct timeval time; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*時(shí)間戳 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? __u16 type; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*事件類型 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? __u16 code; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*事件代碼 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? __s32 value; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*事件值,如坐標(biāo)的偏移值 ? ? ? ?*/
};
struct input_dev注冊(cè)的時(shí)候需要跟匹配的hanlder建立連接,匹配的依據(jù)就是struct input_dev所包含的struct input_id。
?struct input_id成員描述
/* include/linux/input.h */
struct?input_id?{
? ? ? ? __u16bustype; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*總線類型 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? __u16vendor; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*生產(chǎn)商編號(hào) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? __u16product; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*產(chǎn)品編號(hào) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? __u16version; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*版本號(hào) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
};
5、input_dev成員詳解
(1)??打開和關(guān)閉函數(shù)
struct input_dev中有open和close兩個(gè)函數(shù)指針。在與handler第一次連接之后會(huì)調(diào)用open函數(shù),斷開連接會(huì)調(diào)用close。open中應(yīng)該完成硬件初始化的相關(guān)工作,并且申請(qǐng)用到的其他資源,如中斷號(hào)。close函數(shù)做相反的工作。
(2)??事件類型
Linux輸入子系統(tǒng)支持的事件類型如下:
/* include/linux/input.h */
#define EV_SYN ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x00 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*?同步事件 ? ? ? ? ? ? ? ? ? ? ? ? ? ?*/
#define EV_KEY ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x01 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*按鍵事件 ? ? ? ? ? ? ? ? ? ? ? ? ? ?*/
#define EV_REL ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x02 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*相對(duì)坐標(biāo) ? ? ? ? ? ? ? ? ? ? ? ? ? ?*/
#define EV_ABS ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x03 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*絕對(duì)坐標(biāo) ? ? ? ? ? ? ? ? ? ? ? ? ? ?*/
#define EV_MSC ? ? ? ? ? ? ? ? ? ? ? ? ? 0x04
#define EV_SW ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x05
#define EV_LED ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x11 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*led ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
#define EV_SND ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x12 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*beep ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
#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)是最簡(jiǎn)單的事件類型,用來(lái)描述按鍵或者按鈕。報(bào)告按鍵事件使用以下函數(shù):
input_report_key(struct input_dev *dev, int code, int value)
code的值在<內(nèi)核>include/linux/input.h中定義,大小從0到KEY_MAX。value為0時(shí)表示按鍵抬起,非0時(shí)代表按鍵按下。對(duì)同一個(gè)按鍵來(lái)說(shuō),只有當(dāng)value的值和上次不同才會(huì)產(chǎn)生一次事件。
除了按鍵事件,相對(duì)坐標(biāo)事件(EV_REL)和絕對(duì)坐標(biāo)事件(EV_ABS)也是常用的事件。為了使設(shè)備支持這兩類事件,需要在初始化時(shí)對(duì)struct input_dev的evbit相應(yīng)比特置1,并且還要分別在relbit和absbit位圖中為支持的坐標(biāo)軸置1。
相對(duì)坐標(biāo)事件用來(lái)描述類似鼠標(biāo)移動(dòng)的消息。報(bào)告相對(duì)坐標(biāo)的函數(shù)如下:
input_report_rel(structinput_dev *dev, int code, int value)
? ? ? code描述坐標(biāo)軸,value代表相對(duì)移動(dòng)(可正可負(fù))。只有當(dāng)value的值非零時(shí)才能產(chǎn)生一個(gè)有效的事件。
絕對(duì)坐標(biāo)需要額外的工作。初始化時(shí)需要填充input_dev中的一些數(shù)據(jù)域。對(duì)于支持的每個(gè)坐標(biāo)軸調(diào)用如下函數(shù):
input_set_abs_params(struct input_dev *dev, int axis,int min, int max, int fuzz, int flat);
函數(shù)參數(shù)從右往左依次代表輸入設(shè)備指針、坐標(biāo)軸、最小值、最大值、分辨率、基準(zhǔn)值。最后兩個(gè)參數(shù)也可以填為0,代表設(shè)備非常精確并且總能精確的回到中心位置。
input_set_abs_params函數(shù)的代碼
static inline void input_set_abs_params(structinput_dev *dev, int axis, int min, int max, int fuzz, int flat)
{
? ? ? ? dev->absmin[axis]= min;
? ? ? ? dev->absmax[axis]= max;
? ? ? ? dev->absfuzz[axis]= fuzz;
? ? ? ? dev->absflat[axis]= flat;
? ? ? ? dev->absbit[BIT_WORD(axis)]|= BIT_MASK(axis); ? ? ? ? ? ? ? ? ?
/*?這一行已經(jīng)注冊(cè)了坐標(biāo)?*/
}
另外輸入設(shè)備驅(qū)動(dòng)中經(jīng)常用到同步事件(EV_SYN),輸入子系統(tǒng)會(huì)默認(rèn)支持此事件,驅(qū)動(dòng)無(wú)需注冊(cè)。鼠標(biāo)、觸摸板之類的設(shè)備需要用它來(lái)提示上層已經(jīng)發(fā)送完了一個(gè)完整的事件報(bào)告。同步事件的報(bào)告形式如下:
input_sync(zlgkpd->input);
(3)??keycode、?keycodemax和keycodesize
? ? 首先說(shuō)明掃描碼和鍵值的區(qū)別。如程序清單?1.4<!--[if gte mso 9]><![endif]-->所示,例子中包含四個(gè)按鍵的值,那么掃描碼的范圍是0~3,鍵值就是keypad_keycode中的四個(gè)值。
keycode、?keycodemax和keycodesize這三個(gè)數(shù)據(jù)域保存的值分別是鍵值數(shù)組的首地址、鍵值的個(gè)數(shù)和每個(gè)鍵值的字節(jié)大小。有了這三個(gè)變量,就可以在運(yùn)行是改變鍵盤的鍵值映射。比如原來(lái)數(shù)組中的第四個(gè)鍵值為KEY_Z,可以根據(jù)需要改為KEY_D或者其他的值。這樣同樣的掃描碼就對(duì)應(yīng)的不同的鍵值。
這三個(gè)域正確填充之后,內(nèi)核可以使用input_dev的成員函數(shù)來(lái)修改鍵值映射。修改映射的函數(shù)就是input_dev中的setkeycode、getkeycode這兩個(gè)函數(shù)指針對(duì)應(yīng)的函數(shù),如果注冊(cè)之前不初始化它們,則初始化函數(shù)把系統(tǒng)默認(rèn)的函數(shù)賦給它們。
EVIOCGKEYCODE和EVIOCSKEYCODE這兩個(gè)ioctl命令分別用來(lái)查看和修改鍵值。
(4)??按鍵的自動(dòng)連擊
? ?我們都有這樣的經(jīng)歷:按住方向鍵不松開,一直把文檔往某個(gè)方向拉。這個(gè)功能就是自動(dòng)連擊,也就是在按鍵抬起之前連續(xù)發(fā)送按鍵事件。
? ?按鍵連擊事件(EV_REP)的開啟非常簡(jiǎn)單,在input_devd的evbit相應(yīng)比特置1即可。dev->rep[REP_DELAY]和dev->rep[REP_PERIOD]分別存儲(chǔ)連擊的延時(shí)和周期,如果驅(qū)動(dòng)不對(duì)它們賦值,則系統(tǒng)為他們分別賦為250和33。按鍵延時(shí)即按鍵到第一次連擊的間隔,按鍵周期即兩次連擊之間的間隔。它們的單位都是毫秒。
(5)??總線類型
? ?Input_dev中input_id用到了總線類型。輸入子系統(tǒng)支持的總線類型如下所示。
/* include/linux/input.h */
#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
(6)??其他的事件類型
? ? ?EV_LED和EV_SND事件是針對(duì)鍵盤上的led和蜂鳴器。這兩類事件是由輸入子系統(tǒng)內(nèi)核發(fā)送給驅(qū)動(dòng)的。
? ? 如果驅(qū)動(dòng)支持這兩類事件的話,應(yīng)該填充input_dev中的event函數(shù)指針,其實(shí)這是一個(gè)回調(diào)函數(shù)。另外需要填充input_dev中evbit對(duì)應(yīng)的比特位。
這個(gè)回調(diào)函數(shù)可能在中斷或者中斷的底半部調(diào)用,因此event函數(shù)不能睡眠且必須盡快結(jié)束。
本文轉(zhuǎn)自lilin9105 51CTO博客,原文鏈接:http://blog.51cto.com/7071976/1398175,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的[arm 驱动]Linux输入子系统分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 由Effiproz DataBase来看
- 下一篇: 如何解决提示the operation