Input 子系統是 Linux 內核中所有輸入設備(鍵盤、鼠標、觸摸屏等)驅動的中間層,為上層提供統一的事件接口。上層應用(如 X Server、終端)無需關心具體有多少設備,只需從 Input 子系統獲取標準化事件(按鍵、座標移動等)。本文基於 Linux Kernel 2.6.25 源碼分析,核心代碼位於 drivers/input/ 目錄。
static void button_interrupt(int irq, void *dummy, struct pt_regs *fp) {
input_report_key(&button_dev, BTN_1, inb(BUTTON_PORT) & 1);
input_sync(&button_dev);
}
static int __init button_init(void) {
request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL);
button_dev.evbit[0] = BIT(EV_KEY);
button_dev.keybit[LONG(BTN_0)] = BIT(BTN_0);
input_register_device(&button_dev);
}
核心 API:
set_bit(EV_KEY, dev->evbit):設置設備支持的事件類型set_bit(BTN_0, dev->keybit):設置支持的按鍵碼input_register_device():註冊 input deviceinput_report_key():上報按鍵事件input_sync():標記一組事件結束input_register_device() 主要執行:
EV_SYN,配置自動重鍵定時器參數。getkeycode/setkeycode 默認操作函數。device_add() 將內嵌的 struct device 註冊到 sysfs,生成 /sys/class/input/inputX。input_dev_list 鏈表。input_handler_list,對每個 handler 調用 input_attach_handler() 進行匹配。匹配邏輯在 input_attach_handler() 中:
blacklist,匹配則拒絕(返回 -ENODEV)。id_table 與 device 的 id 結構,包括總線類型、廠商 ID、產品 ID、版本號,以及事件位圖(evbit、keybit、relbit 等)。handler->connect() 建立連接。這類似於設備模型中 driver 與 device 的匹配,實現了解耦:設備驅動只需註冊為 handler,自動與符合條件的 input device 綁定。
input_register_handler():將 handler 掛入 input_handler_list,並反向遍歷 input_dev_list 進行匹配。input_register_handle():在 connect() 回調中調用,將 struct input_handle 分別掛入 device 的 h_list 和 handler 的 h_list,形成雙向關聯。若 handler 定義了 start(),則調用啟動處理。
圖示總結:input_dev_list 掛載所有 input device;input_handler_list 掛載所有 handler;handle 作為中間節點連接 device 與 handler,構成多對多關係。