1.5
附隨報告的傳遞
輸入子系統裝置報告各種事件通過
input_report_XXX
族函數,例如
程式清單
1
.5
中報告按鍵事件。按鍵、相對座標、絕對座標和同步附隨報告的函數如
程式清單
1
.12
所示。
程式清單
1
.
12
附隨報告函數
/* include/linux/input.h */
static inline void input_report_key(struct input_dev
*dev, unsigned int code, int value)
{
input_event(dev,
EV_KEY, code, !!value);
⑴
}
static inline void input_report_rel(struct input_dev
*dev, unsigned int code, int value)
{
input_event(dev,
EV_REL, code, value);
}
static inline void input_report_abs(struct input_dev
*dev, unsigned int code, int value)
{
input_event(dev,
EV_ABS, code, value);
}
static inline void input_sync(struct input_dev *dev)
{
input_event(dev,
EV_SYN, SYN_REPORT, 0);
}
可以看到,這四個函數都調用了
input_event
,並且在
⑴
處
將按鍵的
value
轉化為布爾類型的值。所以按鍵傳給
input core
的
value
是
0(
釋放
)
或者
1(
按下
)
。
input_event
函數的代碼如
程式清單
1
.13
所示。
程式清單
1
.
13
input_event
/* driver/input/input.c */
void input_event(struct input_dev *dev, unsigned int
type, unsigned int code, int value)
{
unsigned
long flags;
if
(is_event_supported(type, dev->evbit, EV_MAX)) {
spin_lock_irqsave(&dev->event_lock,
flags);
add_input_randomness(type,
code, value);
⑴
input_handle_event(dev,
type, code, value);
⑵
spin_unlock_irqrestore(&dev->event_lock,
flags);
}
}
EXPORT_SYMBOL(input_event);
本函數總共有兩行有效調用:
⑴
由於輸入事件具有隨機性,因此用輸入事件來增加核心熵池的熵。
⑵
呼叫事件分發函數
input_handle_event
,做進一步的傳遞。
input_handle_event
的代碼如所示。
/* driver/input/input.c */
#define INPUT_IGNORE_EVENT
0
#define INPUT_PASS_TO_HANDLERS
1
#define INPUT_PASS_TO_DEVICE
2
#define INPUT_PASS_TO_ALL
(INPUT_PASS_TO_HANDLERS
| INPUT_PASS_TO_DEVICE)
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code,
int value)
{
int
disposition = INPUT_IGNORE_EVENT;
switch
(type) {
····························
case
EV_KEY:
if
(is_event_supported(code, dev->keybit, KEY_MAX) &&
⑴
!!test_bit(code, dev->key) != value) {
⑵
if
(value != 2) {
⑶
__change_bit(code,
dev->key);
⑷
if
(value)
⑸
input_start_autorepeat(dev,
code);
}
disposition
= INPUT_PASS_TO_HANDLERS;
⑹
}
break;
case
EV_ABS:
if
(is_event_supported(code, dev->absbit, ABS_MAX)) {
⑺
value
= input_defuzz_abs_event(value,
⑻
dev->abs[code],
dev->absfuzz[code]);
if
(dev->abs[code] != value) {
⑼
dev->abs[code]
= value;
disposition
= INPUT_PASS_TO_HANDLERS;
}
}
break;
case
EV_REL:
if
(is_event_supported(code, dev->relbit, REL_MAX) && value)
⑽
disposition
= INPUT_PASS_TO_HANDLERS;
break;
························
}
if
(disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
dev->sync
= 0;
if
((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev,
type, code, value);
if
(disposition & INPUT_PASS_TO_HANDLERS)
input_pass_event(dev,
type, code, value);
}
上述代碼中去除了其他事件的部分,線面說明按鍵、相對座標和絕對座標的處理部分:
⑴
檢查按鍵是否為驅動所支援,只有之前註冊過的按鍵才會繼續傳遞。
⑵
檢查報告的按鍵狀態是否和上次相同。如果連續多次報告按鍵按下,則只處理第一次。
⑶
如果不是連擊事件。
⑷
翻轉按鍵的目前狀態
(
按下和釋放
)
。
⑸
如果是按下,則開始連擊計時。
⑹
標記訊息傳遞方向。
⑺
檢查絕對座標軸是否驅動所支援的。
⑻
根據當前報告的值和上次報告的值確定傳給處理常式的絕對值大小。
⑼
如果本次需要報告的絕對值和上次不同,則將事件傳遞給處理函數。
⑽
檢查相對座標軸是否被驅動所支援。
可以看到
input_handle_event
分發事件有兩個方向:驅動的回呼函數
dev->event
和
input core
的
input_pass_event
。下面繼續分析
input_pass_event
,代碼如
程式清單
1
.14
所示。
程式清單
1
.
14
input_pass_event
/* driver/input/input.c */
static void input_pass_event(struct input_dev *dev, unsigned
int type, unsigned int code, int value)
{
struct
input_handle *handle;
rcu_read_lock();
handle =
rcu_dereference(dev->grab);
⑴
if
(handle)
handle->handler->event(handle,
type, code, value);
else
list_for_each_entry_rcu(handle,
&dev->h_list, d_node)
⑵
if
(handle->open)
⑶
handle->handler->event(handle,
type, code, value);
⑷
rcu_read_unlock();
}
這個函數將事件分發給相關的
handler
。
⑴
擷取獨佔裝置的
handle
的指標。如果有獨佔裝置的
handle
,則僅僅將事件傳給獨佔的
handle
對應的
handler
。
⑵
遍曆與此裝置串連的每一個
handle
。
⑶
如果
hnadle
已經被開啟。
⑷
將事件分發給
handler
的事件處理函數。
到這裡,
input core
分發事件的任務已經完成,接下來由各個
handler
處理接收到的事件。