2.3
evdev_handler
的實現
Linux
輸入子系統已經建立好了幾個
handler
,用來處理幾類常見的事件,如滑鼠、鍵盤、搖杆等。其中最為基礎的是
evdev_handler
,它是在
driver/input/evdev.c
中實現的。它能夠接收任意類型的事件,任意
id
的裝置都可以和它匹配串連,它對應的裝置節點為
/dev/eventX
,次裝置號的範圍為
64
~
95
。
2.3.1
初始化和
input_device_id
如
程式清單
2
.6
所示。
程式清單
2
.
6
evdev_handler
/* driver/input/evdev.c */
static const struct input_device_id evdev_ids[] = {
{
.driver_info = 1 },
/* Matches all devices
*/
{ },
/* Terminating zero entry
*/
};
MODULE_DEVICE_TABLE(input, evdev_ids);
static struct input_handler evdev_handler = {
.event
= evdev_event,
.connect
=
evdev_connect,
.disconnect
=
evdev_disconnect,
.fops
=
&evdev_fops,
.minor
= EVDEV_MINOR_BASE,
.name
= "evdev",
.id_table
=
evdev_ids,
};
static int __init evdev_init(void)
{
return
input_register_handler(&evdev_handler);
}
static void __exit evdev_exit(void)
{
input_unregister_handler(&evdev_handler);
}
module_init(evdev_init);
module_exit(evdev_exit);
初始化的過程非常簡單,就是將
evdev_handler
進行註冊,註冊的過程已經在
2.2
小節講過了。
evdev_handler
只初始化了
id_table
,
根據
程式清單
1
.11
第
⑴
步的分析,我們可以知道這樣的
input_device_id
可以和任意的裝置
id
相匹配。
由
2.2
小節我們知道次裝置號的最高
3
位元用來對每個
handler
在
input_table
中定址,那麼每個
handler
擁有的次裝置號數就是最低
5
位元對應的個數,共
32
個。所以
evdev_handler
最多能夠支援
32
個輸入裝置與之建立串連。
2.3.2
建立串連
evdev_handler
建立串連的函數原型如下:
static int evdev_connect(struct input_handler
*handler, struct input_dev *dev, const struct input_device_id *id);
它的主要任務是申請一個
input_handle
結構體將
handler
和
dev
串連起來。同時建立串連的裝置佔用一個次裝置號,這個次裝置號是
64
~
95
中閒置最小值,如果沒有閒置次裝置號可用則串連失敗。
2.3.3
開啟裝置節點
由於每個與
evdev_handler
建立串連的裝置都佔用了裝置號,所以可以建立對應他們的裝置節點。每次開啟裝置節點,都建立一個
fifo
環形訊息緩衝區,能夠儲存
64
個訊息。
2.3.4
使用者空間讀寫訊息
使用者空間可以往
evdev_handler
串連的裝置節點上寫入訊息,寫入資料的格式如
程式清單
1
.2
,寫入的長度是資料的位元組數。緩衝區寫滿之後從頭開始寫,直接覆蓋之前的訊息並且不會通知使用者程式。由於寫入訊息是通過
input core
分發的,所以寫入的無效訊息根本不會進入訊息緩衝區。
另外需要注意,雖然每個開啟節點的線程都有一個訊息緩衝區,寫入的訊息卻會傳給開啟同一節點的每一個線程。同時也會傳給同一個
input_dev
對應的其它裝置節點。
讀取訊息則只從自己的訊息緩衝區中讀取。讀取的訊息格式也是如
程式清單
1
.2
中的
input_event
一樣。每個訊息只能被讀一次。
2.3.5
事件處理
evdev_handler
從
input core
接收到一個事件之後會將它發送給獨佔裝置的線程
(
如果有
)
或者所有開啟裝置的線程。事件分發之前會先打包成
input_event
的格式,並加上時間戳記。
2.3.6
同步訊息
每個
input_dev
都預設支援同步事件(
EV_SYN
)。但是
evdev_handler
並不使用用同步事件,只是將它作為一個一般的事件寫入緩衝區。由於每次的寫入都是及時的,所以也不需要同步。
2.3.7
evdev_handler
適用範圍
evdev_handler
僅僅將訊息打包成
input_event
的格式,此外不做任何處理。所有裝置發送的附隨報告都能為使用者空間所見。需要直接使用裝置原始事件的程式可以讀取
eventX
,對於滑鼠類或者更複雜的裝置,
evdev_handler
並不合適。