事件的生產者 是 input 裝置驅動 // 還可能是 使用者空間通過write介面 上報的事件,這個可以忽略不計.
途徑 input.
c(input core)
,到達 handler,
然後由handler 提供給消費者.
事件的生產者可以看做都是 裝置驅動 ,但是消費者 不一定是 應用程式,可能是 kernel 其他模組,例如 key input 的消費者可以是 console subsystem
;
evdev 監聽之前 和 監聽之後 ,上報流程不一樣, 區別 在 if
(handle->open)
監聽之前,
(handle->open) 為 假,不會傳送到 handler
監聽之後,
(handle->open) 為 真, 會傳送到 handler
input_report_key // 這一句 呼叫 在 驅動檔案裡面,但是 實現在 include/linux/input.h
----
----
----
----
----
-// 往下 為 input core 的實現(input.c)
input_event
(dev, ev_key, code,
!!value)
;// 檢查dev 是否支援該事件
input_handle_event
(dev, type, code, value);if
(disposition & input_pass_to_handlers)
if(disposition & input_flush)
}
上文**重點講解:
list_for_each_entry_rcu
(handle,
&dev->h_list, d_node)
這個會遍歷 該 device 的 handle , 每匹配一次(該 device 和 handler)
,就會產生乙個handle
一般至少會有乙個handle ,就是 device 和 evdev handler 匹配產生的handler
demo 中產生了兩次匹配
1. device 和 evdev handler ,產生了handle 1
2. device 和 kbd handler , 產生了 handle 2
然後會分別檢查 handle->open
1. handle 1 在 裝置被監聽之前,
(handle->open)為假,在監聽之後,
(handle->open)被加1
,為真 2. handle 2
(handle->open) 為 真
然後 呼叫 input_to_handler
1. handle1 對應的 不會呼叫 input_to_handler
2. handle2 對應的 會呼叫 input_to_handler
input_to_handler
(handle, vals, count)
;// 執行兩次
handler->events //如果handler實現了handler->events,則優先呼叫 handler->events ,否則,呼叫 handler->event
----
----
----
----
----
----
----
----
-------
//往下為 handler 的實現 evdev.c
evdev_events // 這裡分析 evdev handler
evdev_pass_values
static
void
__pass_event
(struct evdev_client *client,
const
struct input_event *event)
client->tail =
(client->head -2)
&(client->bufsize -1)
;
client->buffer[client->tail]
.time = event->time;
client->buffer[client->tail]
.type = ev_syn;
client->buffer[client->tail]
.code = syn_dropped;
client->buffer[client->tail]
.value =
0;
client->packet_head = client->tail;
if(wakeup)
wake_up_interruptible
(&evdev->wait)
;
// 緩衝區 由 struct evdev_client *client; 管理 , struct evdev_client *client; 中有 buffer 成員
// struct evdev_client *client; 由 rcu 鍊錶管理.
evdev_open
unsigned
int size =
sizeof
(struct evdev_client)
+ bufsize *
sizeof
(struct input_event)
;// 計算環形佇列緩衝區大小
client =
kzalloc
(size, gfp_kernel | __gfp_nowarn)
;// 申請緩衝區 // client 中 有 buffer 成員
evdev_attach_client
(evdev, client)
;// 將 client 串入鍊錶
list_add_tail_rcu
(&client->node,
&evdev->client_list)
; file->private_data = client;
evdev_open_device
handle->open ++
;
open 了之後,建立了緩衝區.建立緩衝區 ,
64 位元組
這個buffer的作用是,上層open了此節點,但是沒有讀取此節點的資料的時候,會儲存到該緩衝區
在open 之前,evdev handler 就沒有接收到 事件,事件消亡在 input.c
- 阻塞流程
evdev_poll
poll_wait
(file,
&evdev->wait, wait)
;- 喚醒流程
evdev_pass_values
if(v->type == ev_syn && v->code == syn_report)
wakeup = true;
if(wakeup)
wake_up_interruptible
(&evdev->wait)
;
static ssize_t evdev_read
(struct file *file,
char __user *buffer,size_t count, loff_t *ppos)
struct evdev *evdev = client->evdev;
evdev_fetch_next_event
(client,
&event)
*event = client->buffer[client->tail++];
input_event_to_user
(buffer + read,
&event)
input子系統五 多點上報協議
multi touch protocol.txt abs mt position x x 0 abs mt position y y 0 syn mt report abs mt position x x 1 abs mt position y y 1 syn mt report syn repor...
input子系統五 多點上報協議
multi touch protocol.txt 一 type a 1檢測到2點按下,最小事件序列的上報形式為 abs mt position x x 0 abs mt position y y 0 syn mt report abs mt position x x 1 abs mt positio...
input子系統五 總結框架
通過前面的學習,我們可以看到輸入子系統可以分為三大塊 input核心層 input handler層 input裝置層 input核心層的主要功能主要有以下幾點 1 提供函式介面比如 input裝置和input handler的註冊函式 2 申請和維護子系統需要的一些資源 裝置鍊錶和handler鍊...