動(dòng)開(kāi)發(fā)實(shí)戰(zhàn):從I2C設(shè)備樹(shù)到多點(diǎn)觸控上報(bào))
簡(jiǎn)介ET6238驅(qū)動(dòng)是一份面向嵌入式開(kāi)發(fā)者的I2C接口驅(qū)動(dòng)源碼用于控制ET6238芯片驅(qū)動(dòng)最多16行8列LED矩陣顯示適合數(shù)字儀表盤(pán)、信息屏、游戲設(shè)備等需要段位顯示的項(xiàng)目。資源包共2個(gè)文件包含1個(gè)C源文件與1個(gè)頭文件壓縮包僅2KB體量輕便便于直接集成到現(xiàn)有工程。頭文件對(duì)外暴露初始化、命令與數(shù)據(jù)寫(xiě)入、亮度調(diào)節(jié)等接口源文件則實(shí)現(xiàn)I2C底層通信、從設(shè)備地址設(shè)置、LED段位位操作及PWM灰度控制并兼顧超時(shí)重試等錯(cuò)誤處理與同步、異步調(diào)用方式。已有405人學(xué)習(xí)下載可作為快速上手ET6238顯示控制的參考實(shí)現(xiàn)幫助開(kāi)發(fā)者理清I2C尋址、矩陣刷新與亮度調(diào)節(jié)的代碼組織思路減少?gòu)牧阏{(diào)試的時(shí)間成本。1. 從一顆觸摸芯片說(shuō)起ET6238 驅(qū)動(dòng)到底能幫你省下多少事如果你手里有一塊帶 ET6238 觸摸控制器的板子插上電卻發(fā)現(xiàn)系統(tǒng)根本不認(rèn)它或者能識(shí)別但坐標(biāo)亂跳、多點(diǎn)觸控時(shí)斷時(shí)續(xù)那你大概率需要一份能直接編譯進(jìn)內(nèi)核的驅(qū)動(dòng)源碼。ET6238 是一顆電容式觸摸屏控制芯片常見(jiàn)于中小尺寸的工業(yè) HMI、車(chē)載中控和便攜終端。它通過(guò) I2C 總線(xiàn)與主控通信上報(bào)觸摸坐標(biāo)、按壓狀態(tài)和手勢(shì)事件。這份 C 源碼驅(qū)動(dòng)的價(jià)值在于它把芯片初始化、中斷處理、坐標(biāo)解析、多點(diǎn)觸控協(xié)議上報(bào)這一整條鏈路都寫(xiě)清楚了你不需要對(duì)著數(shù)據(jù)手冊(cè)從零啃寄存器直接改改配置就能跑。適合誰(shuí)適合正在做嵌入式 Linux 或裸機(jī)觸摸屏適配的開(kāi)發(fā)者尤其是那些拿到源碼包卻不知道從哪個(gè)文件開(kāi)始看的人。2. 驅(qū)動(dòng)架構(gòu)拆解從 I2C 設(shè)備樹(shù)到 input 子系統(tǒng)的完整鏈路2.1 驅(qū)動(dòng)分層與文件職責(zé)拿到一份 ET6238 驅(qū)動(dòng)源碼先別急著編譯。我一般會(huì)先看目錄結(jié)構(gòu)搞清楚每個(gè)文件在整條鏈路里扮演什么角色。典型的 ET6238 驅(qū)動(dòng)會(huì)分成這么幾塊文件/模塊職責(zé)關(guān)鍵依賴(lài)et6238_core.c芯片初始化、寄存器讀寫(xiě)、固件加載I2C 子系統(tǒng)et6238_ts.c觸摸事件解析、坐標(biāo)轉(zhuǎn)換、上報(bào)input 子系統(tǒng)et6238_irq.c中斷注冊(cè)、中斷處理、喚醒機(jī)制GPIO / 中斷子系統(tǒng)et6238_cfg.h寄存器地址、閾值、分辨率等宏定義無(wú)et6238_i2c.cI2C 設(shè)備匹配、probe/remove 實(shí)現(xiàn)設(shè)備樹(shù) / ACPI這個(gè)分層不是隨便切的。core 層只關(guān)心“怎么讓芯片開(kāi)始工作”ts 層只關(guān)心“怎么把原始數(shù)據(jù)變成 input 事件”irq 層只關(guān)心“什么時(shí)候去讀數(shù)據(jù)”。三層之間通過(guò)函數(shù)指針和回調(diào)銜接改一層基本不影響另外兩層。常見(jiàn)做法是 core 層導(dǎo)出一個(gè)et6238_read_touch_data()給 ts 層調(diào)用irq 層在中斷里觸發(fā)一個(gè)工作隊(duì)列工作隊(duì)列再去調(diào) ts 層的解析函數(shù)。2.2 設(shè)備樹(shù)節(jié)點(diǎn)與 I2C 地址配置ET6238 掛載在 I2C 總線(xiàn)上設(shè)備樹(shù)里必須有一個(gè)對(duì)應(yīng)的節(jié)點(diǎn)。很多新手翻車(chē)就翻在這里地址寫(xiě)錯(cuò)、中斷引腳配錯(cuò)、復(fù)位引腳沒(méi)加驅(qū)動(dòng) probe 直接返回 -ENODEV。i2c1 { status okay; clock-frequency 400000; et6238: touchscreen2a { compatible etek,et6238; reg 0x2a; /* I2C 從機(jī)地址7 位 */ interrupt-parent gpio1; interrupts 12 IRQ_TYPE_EDGE_FALLING; /* INT 引腳下降沿觸發(fā) */ reset-gpios gpio1 13 GPIO_ACTIVE_LOW; /* RST 引腳低有效 */ irq-gpios gpio1 12 GPIO_ACTIVE_LOW; touchscreen-size-x 800; touchscreen-size-y 1280; touchscreen-inverted-x; touchscreen-swapped-x-y; vdd-supply vcc_3v3; status okay; }; };這段設(shè)備樹(shù)里幾個(gè)參數(shù)值得逐條說(shuō)清楚。reg 0x2a是 ET6238 的 I2C 從機(jī)地址具體值看硬件原理圖上的 ADDR 引腳接法接 GND 和接 VCC 地址不一樣。interrupts里的觸發(fā)方式要和芯片 INT 引腳的實(shí)際行為匹配ET6238 一般配下降沿或低電平觸發(fā)配錯(cuò)了要么中斷丟要么中斷風(fēng)暴。touchscreen-size-x/y是觸摸面板的物理分辨率必須和屏參一致否則坐標(biāo)會(huì)縮放錯(cuò)位。touchscreen-inverted-x和touchscreen-swapped-x-y這兩個(gè)屬性是給坐標(biāo)軸方向不對(duì)時(shí)用的先不加跑起來(lái)看坐標(biāo)方向再?zèng)Q定。提示設(shè)備樹(shù)改完記得重新編譯 dtb 并更新到板子上只改 dts 不編譯等于沒(méi)改。2.3 probe 函數(shù)里的初始化順序probe 函數(shù)是驅(qū)動(dòng)的入口順序錯(cuò)了芯片可能起不來(lái)。我見(jiàn)過(guò)有人先注冊(cè) input 設(shè)備再去初始化芯片結(jié)果中斷來(lái)了 input 還沒(méi)準(zhǔn)備好直接空指針。正確的順序應(yīng)該是拿 GPIO → 硬復(fù)位 → I2C 通信驗(yàn)證 → 讀芯片 ID → 加載配置 → 注冊(cè) input → 申請(qǐng)中斷。static int et6238_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct et6238_ts_data *ts; int ret; ts devm_kzalloc(client-dev, sizeof(*ts), GFP_KERNEL); if (!ts) return -ENOMEM; ts-client client; i2c_set_clientdata(client, ts); /* 1. 獲取并復(fù)位 GPIO */ ts-reset_gpio devm_gpiod_get_optional(client-dev, reset, GPIOD_OUT_LOW); if (IS_ERR(ts-reset_gpio)) return PTR_ERR(ts-reset_gpio); /* 2. 硬復(fù)位拉低 10ms 再拉高等待芯片內(nèi)部初始化 */ if (ts-reset_gpio) { gpiod_set_value_cansleep(ts-reset_gpio, 0); msleep(10); gpiod_set_value_cansleep(ts-reset_gpio, 1); msleep(50); /* 數(shù)據(jù)手冊(cè)要求的上電穩(wěn)定時(shí)間 */ } /* 3. 驗(yàn)證 I2C 通信讀芯片 ID */ ret et6238_i2c_read(ts, ET6238_REG_CHIP_ID, ts-chip_id); if (ret 0) { dev_err(client-dev, failed to read chip id: %d\n, ret); return ret; } if (ts-chip_id ! ET6238_CHIP_ID) { dev_err(client-dev, chip id mismatch: 0x%02x\n, ts-chip_id); return -ENODEV; } /* 4. 加載觸摸配置參數(shù) */ ret et6238_load_config(ts); if (ret 0) return ret; /* 5. 注冊(cè) input 設(shè)備 */ ret et6238_input_init(ts); if (ret 0) return ret; /* 6. 申請(qǐng)中斷最后一步 */ ret devm_request_threaded_irq(client-dev, client-irq, NULL, et6238_irq_handler, IRQF_ONESHOT | IRQF_TRIGGER_FALLING, client-name, ts); if (ret 0) { dev_err(client-dev, failed to request irq: %d\n, ret); return ret; } return 0; }這段代碼里每一步都有講究。devm_gpiod_get_optional用 optional 是因?yàn)橛行┌遄訌?fù)位引腳直接接 RC 電路不需要軟件控制。復(fù)位后的msleep(50)是給芯片內(nèi)部固件啟動(dòng)留時(shí)間短了讀 ID 會(huì)失敗。讀 ID 那步是判斷 I2C 通不通的最快方式比讀坐標(biāo)寄存器更可靠。IRQF_ONESHOT表示中斷線(xiàn)程化后只觸發(fā)一次配合IRQF_TRIGGER_FALLING使用避免中斷處理函數(shù)里做 I2C 讀時(shí)被同級(jí)中斷打斷。2.4 中斷處理與坐標(biāo)上報(bào)ET6238 的中斷處理不能直接在硬中斷里做 I2C 讀因?yàn)?I2C 傳輸可能睡眠。常見(jiàn)做法是用request_threaded_irq把中斷線(xiàn)程化或者硬中斷里調(diào)度一個(gè)工作隊(duì)列。下面這段是線(xiàn)程化中斷處理函數(shù)的典型寫(xiě)法static irqreturn_t et6238_irq_handler(int irq, void *dev_id) { struct et6238_ts_data *ts dev_id; u8 touch_num; int ret; /* 讀觸摸點(diǎn)數(shù)量寄存器 */ ret et6238_i2c_read(ts, ET6238_REG_TOUCH_NUM, touch_num); if (ret 0) { dev_err(ts-client-dev, read touch num failed\n); return IRQ_HANDLED; } touch_num 0x0F; /* 低 4 位有效高 4 位保留 */ if (touch_num 0 || touch_num ET6238_MAX_TOUCH) { et6238_report_release(ts); /* 上報(bào)抬起事件 */ return IRQ_HANDLED; } /* 讀取所有觸摸點(diǎn)坐標(biāo) */ ret et6238_read_touch_data(ts, touch_num); if (ret 0) return IRQ_HANDLED; et6238_report_touch(ts, touch_num); return IRQ_HANDLED; }touch_num寄存器低 4 位表示當(dāng)前按下的手指數(shù)量0 表示全部抬起。ET6238_MAX_TOUCH一般是 5 或 10看具體型號(hào)。et6238_report_release里要對(duì)每一個(gè)之前上報(bào)過(guò)的 slot 調(diào)用input_mt_slot和input_mt_report_slot_state(false)漏掉任何一個(gè)都會(huì)導(dǎo)致系統(tǒng)里有個(gè)“幽靈手指”一直按著。et6238_read_touch_data里讀坐標(biāo)時(shí)要注意字節(jié)序ET6238 的坐標(biāo)寄存器是 16 位高字節(jié)在前還是低字節(jié)在前看數(shù)據(jù)手冊(cè)讀反了坐標(biāo)會(huì)變成亂碼。3. 編譯與運(yùn)行從源碼到板子上跑通觸摸3.1 內(nèi)核配置與編譯選項(xiàng)ET6238 驅(qū)動(dòng)要編譯進(jìn)內(nèi)核先得讓 Kconfig 和 Makefile 認(rèn)識(shí)它。在驅(qū)動(dòng)目錄下加兩行# drivers/input/touchscreen/Makefile obj-$(CONFIG_TOUCHSCREEN_ET6238) et6238.o et6238-objs : et6238_core.o et6238_ts.o et6238_irq.o et6238_i2c.o# drivers/input/touchscreen/Kconfig config TOUCHSCREEN_ET6238 tristate ET6238 I2C touchscreen depends on I2C depends on INPUT select INPUT_MT select INPUT_MT_DIRECT help Say Y here to enable ET6238 touchscreen support.tristate表示可以編譯成模塊調(diào)試階段建議編成模塊改完 insmod 就行不用反復(fù)燒內(nèi)核。select INPUT_MT和INPUT_MT_DIRECT必須選上否則多點(diǎn)觸控協(xié)議上報(bào)會(huì)編譯報(bào)錯(cuò)。編譯命令就是標(biāo)準(zhǔn)的內(nèi)核模塊編譯make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- modules -j$(nproc)編完在drivers/input/touchscreen/下會(huì)生成et6238.ko拷到板子上insmod et6238.ko就能加載。3.2 加載后驗(yàn)證觸摸是否正常驅(qū)動(dòng)加載后先看內(nèi)核日志有沒(méi)有 probe 成功dmesg | grep et6238 # 期望輸出類(lèi)似 # et6238 1-002a: chip id: 0x62 # et6238 1-002a: touchscreen registered # input: et6238 as /devices/platform/soc/1c2ac00.i2c/i2c-1/1-002a/input/input3然后確認(rèn) input 設(shè)備節(jié)點(diǎn)出現(xiàn)了ls /dev/input/ # 應(yīng)該能看到 eventX用 cat /proc/bus/input/devices 確認(rèn)哪個(gè)是 et6238 cat /proc/bus/input/devices | grep -A5 et6238最直接的驗(yàn)證是用evtest工具evtest /dev/input/event3 # 手指按上去應(yīng)該能看到 ABS_MT_POSITION_X/Y 事件如果evtest里坐標(biāo)不動(dòng)先查中斷計(jì)數(shù)cat /proc/interrupts | grep et6238 # 按屏幕時(shí)計(jì)數(shù)應(yīng)該增加不增加說(shuō)明中斷沒(méi)觸發(fā)中斷計(jì)數(shù)不漲九成是設(shè)備樹(shù)里中斷觸發(fā)方式配錯(cuò)了或者 INT 引腳被別的驅(qū)動(dòng)占用了。中斷漲但坐標(biāo)不動(dòng)那就是 I2C 讀數(shù)據(jù)失敗用i2cdetect -y 1確認(rèn)芯片地址能不能掃到。3.3 坐標(biāo)校準(zhǔn)與方向調(diào)整坐標(biāo)方向不對(duì)是最常見(jiàn)的問(wèn)題。現(xiàn)象是手指往右滑光標(biāo)往上跑或者左右鏡像。解決方式有兩種改設(shè)備樹(shù)屬性或者改驅(qū)動(dòng)里的坐標(biāo)轉(zhuǎn)換函數(shù)。設(shè)備樹(shù)方式最簡(jiǎn)單加touchscreen-inverted-x、touchscreen-inverted-y、touchscreen-swapped-x-y這三個(gè)屬性的組合就能覆蓋八種方向。如果設(shè)備樹(shù)屬性不夠用就在et6238_report_touch里改static void et6238_report_touch(struct et6238_ts_data *ts, u8 touch_num) { int i; for (i 0; i touch_num; i) { u16 x ts-touch_data[i].x; u16 y ts-touch_data[i].y; /* 坐標(biāo)轉(zhuǎn)換根據(jù)實(shí)際方向調(diào)整 */ if (ts-swap_xy) swap(x, y); if (ts-invert_x) x ts-max_x - x; if (ts-invert_y) y ts-max_y - y; input_mt_slot(ts-input, i); input_mt_report_slot_state(ts-input, MT_TOOL_FINGER, true); input_report_abs(ts-input, ABS_MT_POSITION_X, x); input_report_abs(ts-input, ABS_MT_POSITION_Y, y); } input_mt_sync_frame(ts-input); input_sync(ts-input); }swap_xy交換 X/Y 軸invert_x和invert_y做鏡像翻轉(zhuǎn)。input_mt_sync_frame是收尾動(dòng)作告訴 input 子系統(tǒng)這一幀數(shù)據(jù)完了。漏掉input_sync的話(huà)事件會(huì)攢在緩沖區(qū)里不發(fā)出表現(xiàn)就是觸摸完全沒(méi)反應(yīng)。4. 避坑與排查ET6238 驅(qū)動(dòng)調(diào)試中最容易翻車(chē)的幾個(gè)點(diǎn)4.1 中斷風(fēng)暴導(dǎo)致系統(tǒng)卡死現(xiàn)象加載驅(qū)動(dòng)后系統(tǒng)變卡top里看到irq/xx-et6238占用率很高/proc/interrupts里中斷計(jì)數(shù)瘋漲。原因中斷觸發(fā)方式配成了電平觸發(fā)但芯片 INT 引腳在數(shù)據(jù)沒(méi)讀完后一直保持有效電平導(dǎo)致中斷反復(fù)觸發(fā)。或者中斷處理函數(shù)里沒(méi)有清中斷標(biāo)志。解決把設(shè)備樹(shù)里的IRQ_TYPE_EDGE_FALLING改成邊沿觸發(fā)或者在中斷處理函數(shù)開(kāi)頭先讀一次狀態(tài)寄存器清標(biāo)志。ET6238 一般用下降沿觸發(fā)就夠了不要用電平觸發(fā)。4.2 probe 返回 -ENODEV 但 I2C 能掃到地址現(xiàn)象i2cdetect能看到 0x2a 有設(shè)備但驅(qū)動(dòng) probe 失敗日志報(bào)chip id mismatch。原因讀芯片 ID 的寄存器地址寫(xiě)錯(cuò)了或者讀出來(lái)的字節(jié)序不對(duì)。有些板子 I2C 上拉電阻偏大400kHz 下讀數(shù)據(jù)不穩(wěn)定讀回來(lái)的 ID 是隨機(jī)值。解決先用i2cget手動(dòng)讀一次 ID 寄存器確認(rèn)值對(duì)不對(duì)i2cget -y 1 0x2a 0x00 w # 對(duì)比數(shù)據(jù)手冊(cè)里的 CHIP_ID 默認(rèn)值如果手動(dòng)讀也不對(duì)把 I2C 頻率降到 100kHz 試試。如果手動(dòng)讀對(duì)但驅(qū)動(dòng)讀不對(duì)檢查驅(qū)動(dòng)里et6238_i2c_read的寄存器地址偏移和字節(jié)序處理。4.3 多點(diǎn)觸控只上報(bào)一個(gè)點(diǎn)現(xiàn)象evtest里只能看到一個(gè)手指的坐標(biāo)第二個(gè)手指按上去沒(méi)反應(yīng)。原因input_mt_init_slots時(shí) slot 數(shù)量傳了 1或者ABS_MT_SLOT沒(méi)有正確設(shè)置。還有一種情況是input_mt_report_slot_state的第三個(gè)參數(shù)傳了 false導(dǎo)致 slot 被標(biāo)記為未使用。解決確認(rèn)input_mt_init_slots(ts-input, ET6238_MAX_TOUCH, INPUT_MT_DIRECT)里第二個(gè)參數(shù)是最大觸摸點(diǎn)數(shù)不是 1。每個(gè)觸摸點(diǎn)上報(bào)前必須調(diào)input_mt_slot(ts-input, i)指定 slot 編號(hào)i 從 0 開(kāi)始。4.4 坐標(biāo)跳變或漂移現(xiàn)象手指不動(dòng)坐標(biāo)自己小幅跳動(dòng)或者滑動(dòng)時(shí)坐標(biāo)突然跳到邊緣。原因坐標(biāo)寄存器讀取時(shí)沒(méi)有做有效性判斷讀到了無(wú)效數(shù)據(jù)。ET6238 在觸摸抬起瞬間坐標(biāo)寄存器可能還保留著上一次的值如果此時(shí) touch_num 已經(jīng)變成 0 但代碼還在讀坐標(biāo)就會(huì)上報(bào)臟數(shù)據(jù)。解決在讀坐標(biāo)前先判斷touch_num是否大于 0等于 0 直接上報(bào) release。另外可以在驅(qū)動(dòng)里加一個(gè)簡(jiǎn)單的濾波連續(xù)兩次坐標(biāo)差值超過(guò)閾值就丟棄當(dāng)前幀。4.5 休眠喚醒后觸摸失效現(xiàn)象系統(tǒng) suspend 再 resume 后觸摸沒(méi)反應(yīng)dmesg里也沒(méi)有中斷計(jì)數(shù)增加。原因suspend 時(shí)芯片進(jìn)入了低功耗模式resume 后沒(méi)有重新初始化。或者 GPIO 狀態(tài)在 suspend 時(shí)被改變INT 引腳不再觸發(fā)中斷。解決實(shí)現(xiàn)et6238_suspend和et6238_resume回調(diào)resume 里重新做一次硬復(fù)位和配置加載。如果芯片支持自動(dòng)喚醒確認(rèn)ET6238_REG_POWER_MODE寄存器在 resume 后被正確設(shè)置。5. 二次開(kāi)發(fā)改造從能跑到好用我一般會(huì)動(dòng)這幾個(gè)地方驅(qū)動(dòng)跑通只是第一步真正放到產(chǎn)品里還得改。我拿到一份能跑的 ET6238 驅(qū)動(dòng)后通常會(huì)從三個(gè)方向做二次開(kāi)發(fā)性能調(diào)優(yōu)、功能擴(kuò)展、可維護(hù)性改造。性能調(diào)優(yōu)方面最直接的是改中斷上報(bào)頻率。ET6238 默認(rèn)每次中斷上報(bào)一幀數(shù)據(jù)如果手指快速滑動(dòng)中斷太頻繁會(huì)占 CPU。我一般會(huì)在中斷處理里加一個(gè)簡(jiǎn)單的節(jié)流兩次上報(bào)間隔小于 5ms 就跳過(guò)用jiffies做判斷。另一個(gè)點(diǎn)是 I2C 傳輸優(yōu)化把連續(xù)讀多個(gè)寄存器的操作合并成一次i2c_transfer減少總線(xiàn)開(kāi)銷(xiāo)。實(shí)測(cè)下來(lái)合并傳輸能把一次觸摸讀取從 6 次 I2C 傳輸降到 2 次。功能擴(kuò)展方面ET6238 支持手勢(shì)識(shí)別但很多驅(qū)動(dòng)只實(shí)現(xiàn)了基礎(chǔ)觸摸。我會(huì)在et6238_irq_handler里加一個(gè)手勢(shì)寄存器讀取把雙擊、長(zhǎng)按、滑動(dòng)方向解析出來(lái)通過(guò)input_report_key上報(bào)。手勢(shì)閾值可以在et6238_cfg.h里定義成宏方便不同項(xiàng)目調(diào)整。還有一個(gè)實(shí)用改造是加 sysfs 節(jié)點(diǎn)把固件版本、觸摸點(diǎn)數(shù)、坐標(biāo)范圍暴露出來(lái)產(chǎn)線(xiàn)測(cè)試時(shí)不用接串口就能讀??删S護(hù)性改造方面我會(huì)把芯片相關(guān)的寄存器操作全部收進(jìn)et6238_reg.h和et6238_reg.c用宏定義代替裸地址。這樣換一顆同系列的芯片只需要改寄存器定義文件核心邏輯不動(dòng)。另外加一套 debugfs 接口運(yùn)行時(shí)能動(dòng)態(tài)改閾值和坐標(biāo)方向不用重新編譯驅(qū)動(dòng)。驗(yàn)證改造效果的方法很簡(jiǎn)單改完先insmod加載用evtest看事件流是否正常然后用getevent -lt看時(shí)間戳確認(rèn)上報(bào)間隔穩(wěn)定最后跑一個(gè)滑動(dòng)測(cè)試腳本連續(xù)畫(huà)圈 100 次看有沒(méi)有丟點(diǎn)或跳點(diǎn)。我一般會(huì)寫(xiě)一個(gè)簡(jiǎn)單的 Python 腳本讀/dev/input/eventX統(tǒng)計(jì)每秒事件數(shù)和坐標(biāo)方差方差突然變大就說(shuō)明有臟數(shù)據(jù)。注意改中斷節(jié)流參數(shù)時(shí)不要拍腦袋定值先用evtest測(cè)出實(shí)際觸摸幀率再根據(jù)幀率設(shè)節(jié)流窗口。設(shè)大了會(huì)感覺(jué)觸摸不跟手設(shè)小了等于沒(méi)節(jié)流。從那以后我每次改完驅(qū)動(dòng)都強(qiáng)制走一遍“insmod → evtest 看事件 → getevent 看時(shí)間戳 → 滑動(dòng)測(cè)試腳本跑 100 次”這個(gè)流程少一步都可能把問(wèn)題帶到產(chǎn)線(xiàn)。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取