題圖:日本東京有一家專門生產(chǎn)電梯按鈕的公司,該公司把生產(chǎn)過的1000多種電梯按鈕,做成了一面展示墻,按上去每個都會亮。孩子們和大人都很喜歡。
歡迎關(guān)注,每周更新!?
本合集分享的是,我當(dāng)初學(xué)習(xí)Linux驅(qū)動的來時路——《《驅(qū)動之路》開篇:自序&前言》。
正文
Input 子系統(tǒng)框架的復(fù)雜程度有三四層樓那么高。幸運的是,復(fù)雜那部分代碼大佬前輩們已經(jīng)實現(xiàn),我們只需搞懂 Input 子系統(tǒng)的框架,然后套用框架實現(xiàn)具體輸入設(shè)備 driver 端驅(qū)動程序即可。因此,可以說 ai 時代搞懂框架比理解每行代碼更重要。
但是對于 Input 子系統(tǒng)這樣復(fù)雜的框架,要徹底理解從硬件底層到用戶空間的數(shù)據(jù)上報流程談何容易,必須要找到一個抓手作為切入點。
然而,分析gpio_keys.c驅(qū)動正是掌握 Linux Input 子系統(tǒng)數(shù)據(jù)上報流程的絕佳途徑,因為它是一個典型且相對簡單的 Input 驅(qū)動實例。
在分析前,請先回顧《驅(qū)動之路#01:Hello World!》和 Input 子系統(tǒng)的三層架構(gòu):驅(qū)動層、核心層以及事件處理層。

下面是一個 step-by-step 的指南,帶你從gpio_keys.c出發(fā),徹底理解 Input 子系統(tǒng)的工作機制。
特別說明:本文重點在于理解 Input 子系統(tǒng)數(shù)據(jù)上報流程,而非gpio_keys.c驅(qū)動分析。
從module_init開始:驅(qū)動入口函數(shù)
閱讀一個字符設(shè)備驅(qū)動程序從入口函數(shù)開始,在 gpio_keys.c 中可以看到 gpio_keys_init 注冊了 gpio_keys_device_driver。當(dāng) driver 與 device 匹配后,gpio_keys_probe 函數(shù)就會被調(diào)用,接下來重點分析gpio_keys_probe 函數(shù)。

驅(qū)動層到核心層
驅(qū)動核心: gpio_keys_probe 函數(shù)分析
probe函數(shù)在驅(qū)動與設(shè)備匹配成功后被調(diào)用,可以看到 probe函數(shù)有 4 步關(guān)鍵操作。
步驟 1:獲取設(shè)備配置信息
首先通過dev_get_platdata(dev)從平臺設(shè)備中獲取靜態(tài)定義的平臺數(shù)據(jù)。如果沒有靜態(tài)平臺數(shù)據(jù),則再通過gpio_keys_get_devtree_pdata(dev)從設(shè)備樹中解析配置??傊?,無論是設(shè)備樹還是傳統(tǒng)平臺數(shù)據(jù),最終都解析到pdata中。

步驟 2:分配和初始化struct input_dev
通過devm_input_allocate_device()創(chuàng)建一個輸入設(shè)備對象input_dev,這是驅(qū)動層與核心層交互的第一步。

步驟 3:申請 GPIO 和中斷
probe 函數(shù)沒有直接包含中斷處理函數(shù)的實現(xiàn),而是通過調(diào)用 gpio_keys_setup_key() 完成了中斷函數(shù)的注冊、中斷觸發(fā)方式等配置。

步驟 4:注冊輸入設(shè)備
通過 input_register_device()將 input_dev 注冊到 Input 子系統(tǒng)核心層,調(diào)用此函數(shù)后,Input 核心層會接手管理這個輸入設(shè)備并嘗試為它匹配合適的事件處理器(Handler),如 evdev。
注冊成功后,用戶空間就可以看到/dev/input/eventX 設(shè)備節(jié)點了。

以上是 probe 函數(shù)關(guān)鍵操作的分析。
中斷處理函數(shù)分析
中斷處理函數(shù)是數(shù)據(jù)上報流程的起點,當(dāng)用戶按下或松開按鍵時,GPIO 電平變化觸發(fā)中斷,此函數(shù)被執(zhí)行。
經(jīng)過前面分析知道,中斷服務(wù)函數(shù)相關(guān)配置在gpio_keys_setup_key() 中完成,接下來分析 gpio_keys_setup_key() 。
可以看到有兩種IRQ函數(shù)
gpio_keys_gpio_isr:設(shè)備樹中的用gpios描述引腳時調(diào)用;
gpio_keys_irq_isr:設(shè)備樹中的用interrupts描述引腳時調(diào)用。
它們有各自的優(yōu)缺點,但不是本文的重點,這里不展開分析。

我們分析相對簡單的 gpio_keys_irq_isr 中斷函數(shù)的處理流程,其中,
核心:調(diào)用input_event(input, EV_KEY, *bdata->code,1)和input_sync(input)進行上報數(shù)據(jù)。
input_event():向 Input 核心層上報一個原始事件。這個事件包含了事件類型(EV_KEY)、事件碼(如 KEY_POWER)和值(1 或 0)。
input_sync():上報一個同步事件,告訴核心層 “這一組事件已經(jīng)完整上報完畢”。

至此,數(shù)據(jù)已經(jīng)從硬件驅(qū)動層上報到核心層。
核心層到事件層數(shù)據(jù)流
數(shù)據(jù)從核心層傳遞到事件層函數(shù)調(diào)用關(guān)系比較復(fù)雜,調(diào)用關(guān)系如下。
其中,input_handle_event函數(shù)是 Input 核心層的事件分發(fā)中心,它會將事件傳遞給所有與該input_dev關(guān)聯(lián)的input_handler(事件處理器)。
而數(shù)據(jù)從核心層傳遞到事件層,是調(diào)用evdev_events 函數(shù)來實現(xiàn),然后通過evdev_pass_values函數(shù)被分發(fā)到各個客戶端。

當(dāng)用戶空間讀取/dev/input/eventX時,實際上是從對應(yīng)客戶端的環(huán)形緩沖區(qū)中讀取數(shù)據(jù)。數(shù)據(jù)最后保存在每個打開設(shè)備文件的進程所對應(yīng)的evdev_client的環(huán)形緩沖區(qū)中。

數(shù)據(jù)流:gpio_keys.c驅(qū)動->input_event -> input_handle_event -> input_pass_values -> evdev_events -> evdev_pass_values ->寫入evdev_client的 buffer ->用戶空間read讀取。
總結(jié)整個流程
硬件:用戶按下按鍵 -> GPIO 電平變化 -> 觸發(fā)中斷。
驅(qū)動層 (gpio_keys.c):
gpio_keys_irq_isr 或gpio_keys_gpio_isr 中斷服務(wù)程序被調(diào)用。
調(diào)用input_event()和input_sync()向上層(核心層)上報事件。
核心層 (input.c):
input_event()->input_handle_event()接收事件。
核心層將事件分發(fā)給所有匹配的 input_handler。
事件處理層 (evdev.c):
evdev_event()接收事件。
將事件打包成struct input_event并寫入內(nèi)核緩沖區(qū)(buffer)。
喚醒正在等待數(shù)據(jù)的用戶空間應(yīng)用程序。
用戶空間:應(yīng)用程序的 read()調(diào)用返回,讀取到 struct input_event 數(shù)據(jù)并進行解析。
看完本文,可自行閱讀源碼分析,關(guān)鍵代碼閱讀順序:
drivers/input/keyboard/gpio_keys.c- 具體輸入設(shè)備驅(qū)動程序
drivers/input/input.c- 核心框架
drivers/input/evdev.c- 事件處理
include/linux/input.h- 數(shù)據(jù)結(jié)構(gòu)和 API
(完)
本人專注 Linux 驅(qū)動 & Linux/Android BSP 開發(fā)調(diào)試,可接外包項目/技術(shù)支持/問題定位。有需求或交個朋友可加微信:【Chen_WeChat2026】。
更多原創(chuàng)技術(shù)文章:《README 2026》。
審核編輯 黃宇
-
驅(qū)動
+關(guān)注
關(guān)注
12文章
1957瀏覽量
88566 -
子系統(tǒng)
+關(guān)注
關(guān)注
0文章
116瀏覽量
13509
發(fā)布評論請先 登錄
基于 ROS + ADI 芯片方案 的 人形機器人子系統(tǒng)級BOM清單(以腿部子系統(tǒng)為例)
迅為RK3568開發(fā)板驅(qū)動指南GPIO子系統(tǒng)GPIO子系統(tǒng)API函數(shù)的引入
迅為RK3568驅(qū)動指南GPIO子系統(tǒng) GPIO操作函數(shù)實驗
RK3568驅(qū)動指南|第十二篇 GPIO子系統(tǒng)-第135章 GPIO子系統(tǒng)與pinctrl子系統(tǒng)相結(jié)合實驗
驅(qū)動之路#11:Input子系統(tǒng)數(shù)據(jù)上報流程
評論