最近有這樣一個事情:18名上海某名牌大學學生為了尋求刺激,到某險地進行探險,後迷失森林,然後肚子餓了,衣服穿少了冷,於是與打電話求助當地警員。最後這幫大學生都得以救出,然後飯也吃飽了,衣服也加上了,不過在救援的途中,人民的兒子,年輕的張寧海警員永遠離我們而去了。好好地大學生放著課不上,去外地探險……
好了廢話不多說。繼續我們的input裝置之旅。
從前一節來看,在linux核心中添加一個input裝置變得很簡單了。我們再也不必須去動手寫那些該死的介面函數了。可是你有沒有想過,是誰讓我們的工作變得這麼簡單了呢?答案是linux核心中的input core。她總是那麼癡情,默默地不求回報地為你做許許多多的事情,在你背後默默的支援你愛著你。是的,你所想到的大多數事情,我們的input core都已經為你做好。除了感動,我們還能說什麼呢?(input core對應的實體在linux核心源碼目錄linux-2.6.29/drivers/input/input.c檔案)
在正式接觸我們可愛的input core之前,有必要瞭解一下幾個重要的結構體,這幾個結構體是我們這個故事的主體。
第一個資料結構 struct input_dev。悟性高的哥們馬上就會想到,它就是我們input 裝置在linux核心中的類比,即裡面記錄了一個input裝置的所有資訊。定義於linux-2.6.29/include/linux/input.h中
struct input_dev {
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
struct ff_device *ff;
unsigned int repeat_key;
struct timer_list timer;
int sync;
int abs[ABS_MAX + 1];
int rep[REP_MAX + 1];
unsigned long key[BITS_TO_LONGS(KEY_CNT)];
unsigned long led[BITS_TO_LONGS(LED_CNT)];
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
unsigned long sw[BITS_TO_LONGS(SW_CNT)];
int absmax[ABS_MAX + 1];
int absmin[ABS_MAX + 1];
int absfuzz[ABS_MAX + 1];
int absflat[ABS_MAX + 1];
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
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;
struct list_head node;
};
很強大的一個結構體,因為她把所有的input裝置的資訊都考慮到了,真的是很無私。不過對於我們的akm驅動來說只需要關注幾個小細節,結構中的加粗部分。unsigned long evbit[BITS_TO_LONGS(EV_CNT)]表示此input裝置支援的事件,比如前面的第二節中的set_bit(EV_ABS, akm->input_dev->evbit)設定input_dev->evbit中的相應位讓它支援絕對值座標。類似的還有以下這些事件:EV_KEY -按鍵, EV_REL -相對座標EV_ABS -絕對座標,EV_LED - LED,EV_FF- 力反饋。unsigned
long absbit[BITS_TO_LONGS(ABS_CNT)];設定相應的位以支援某一類絕對值座標。比如第二節中的input_set_abs_params(akm->input_dev, ABS_RX, 0, 23040, 0, 0);它的函數體如下:
static inline void input_set_abs_params(struct input_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);
}
表示支援絕對值x座標,並設定它在座標系中的最大值和最小值,以及幹擾值和平焊位置等。
struct list_head h_list;表示的是和該裝置相關的所有input handle的結構體鏈表(input handle為何物下文馬上會講到)。struct list_head node;所有input裝置群組成的鏈表結構(後面將會知道它對應於input_dev_list)。
Ok 馬上進入第二個結構體struct input_handler(還是來自linux-2.6.29/include/linux/input.h)
struct input_handler {
void *private;
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
void (*disconnect)(struct input_handle *handle);
void (*start)(struct input_handle *handle);
const struct file_operations *fops;
int minor;
const char *name;
const struct input_device_id *id_table;
const struct input_device_id *blacklist;
struct list_head h_list;
struct list_head node;
};
顧名思義:用來處理input裝置的一個結構體。struct list_head h_list表示的是和該裝置相關的所有input handle的結構體鏈表和前面那個一樣;struct list_head node所有input_handle組成的結構體連鏈表(後面將會知道它對應於input_handler_list)。每一個input裝置在註冊時,他都會遍曆input_handler_list鏈表上的每一個input_handler,去找尋他心中的那個她,同理每一個input_handler在註冊時,他也會去input_dev_list上找尋那個屬於他的她。有時候事情往往不會那麼盡如人意,當input_handler還沒出生時,你這個input_dev就一直在那等吧,等到天荒地老,等到海枯石爛。最後來一句,我等到花兒也謝了,你丫到底還來不來啊。注意這裡的input_handler和input_dev並不是一一對應的關係,有時一個input_handler對應好幾個input_dev。於是乎,作為看代碼的我就在想,linux核心開發人員的思想怎麼這麼不單純呢,這不明擺著教育我們搞一夫多妻制嗎,不過管怎樣,還是得記住公司的企業文化,本分點。如果你丫說你同時擁有兩個馬子,我將會無情的向你拋出那句話:“出來混,遲早要還的!”。
前面多次提到那個input_handle(注意區別input_handler),她到底是何方神聖。好吧,就讓我們來一層一層揭開她那神秘的面紗,當你第一次看到她完完全全展現在你面前時,那時候你的滿足感和興奮度和她的害羞度是成正比的。
同樣來自linux-2.6.29/include/linux/input.h
struct input_handle {
void *private;
int open;
const char *name;
struct input_dev *dev;
struct input_handler *handler;
struct list_head d_node;
struct list_head h_node;
};
怎麼啦?是不是很失望,原來就這麼回事啊。嗯,沒錯,兄弟,就這麼回事。人往往都這樣,得到了某樣東西,想想覺得就那麼回事,沒得到呢,那叫一個好奇,那叫一個盼望。好了既然看到她的廬山真面目了,就坦然面對她,作為一個負責的男人,我還是來好好研究一下。
Input_Handle其實也好理解,它就是input_dev和 input_handler粘合劑,通過Input_Handle這麼一攪和,input_dev就和 input_handler發生了點關係,至於什麼樣的關係我們後文將會知道的一清二楚。struct input_dev *dev對應的input裝置。struct input_handler *handler對應該裝置的handler。struct list_head d_node和struct
list_head h_node則分別關聯上前面兩個結構體中的struct list_head h_list。
終於告一段落了,休息,休息一下!