1. 程式人生 > >轉《Linux input子系統分析之一:軟體層次》

轉《Linux input子系統分析之一:軟體層次》

本文轉自:https://blog.csdn.net/yueqian_scut/article/details/47903853

輸入輸出是使用者和產品互動的手段,因此輸入驅動開發在Linux驅動開發中很常見。同時,input子系統的分層架構思想在Linux驅動設計中極具代表性和先進性,因此對Linux input子系統進行深入分析很有意義。

一、input子系統知識點

完整的input子系統分析包括以下幾方面:

1) 軟體層次

2) 輸入子系統分層(input_handler,input_core, input_device)

3) 輸入裝置(TS)驅動開發

4) evdev handler分析

5) input裝置模型檢視(sysfs)和執行映象(procfs)

6) tslib分析

7) 應用框架的事件處理分析

筆者一向主張學習嵌入式應儘可能培養具備分析Linux軟體架構的大局觀。本文將從需求的角度去分析Linux輸入所涉及的應用和核心層的相關模組所承擔的角色和完成的功能,讓開發人員能夠對Linux驅動的所涉及的整個軟體層次有清晰的認識。其他知識點將在後文進行闡述,敬請關注。

二、軟體層次分析

Linux輸入所涉及的軟體層次如下圖:


基於Linux核心的應用框架常見於Android和QT。由於Android4.2對觸屏驅動的支援發生過重大的變化(將tslib完成的任務拋給驅動層來完成),所以我們以較為簡單的QT框架來說明Linux輸入的呼叫過程。假設有以下基於QT的通訊錄應用場景,我們重點分析查詢這個button控制元件的輸入響應過程。


1.APP即通訊錄應用,輸入姓名拼音首字母,然後點選查詢,輸出結果(姓名和電話號碼)。APP在QT creator視覺化開發環境上使用所見即所得的方式拖入Button控制元件作為“查詢”按鈕。APP不需要關注按鈕的顯示,也不需要關心使用者通過何種方式按下按鈕,只需要做的是對按鈕的單擊事件進行響應,即通過姓名首字母來對姓名資料庫進行查詢並輸出到結構框中。

2.QT應用框架需要完成APP開發所不需要關注的事情,即對輸入事件進行封裝處理、分發事件到目標控制元件、完成目標控制元件的狀態變化和影象顯示,當然還包括視窗的管理。上述應用圖示是一個LCD屏顯示頁面,LCD的座標點在左上角,如下圖:


對於QT應用框架來說,使用者點選了螢幕,QT的事件處理會收到一個座標事件,即相對LCD座標原點的觸點座標(x,y)。QT會對該座標進行分析,在當前焦點視窗系統中檢測該座標落到哪個控制元件的顯示範圍。明顯,“查詢”按鍵在視窗中有座標範圍,由左上角和右下角兩個座標點確定其範圍。如果判斷使用者觸控的座標落到該範圍,QT即會分發一個單擊事件給“查詢”按鍵控制元件,最終QT通過回撥的方式呼叫APP開發中編寫的查詢邏輯函式,並輸出到結果框中。

3.Tslib,從名稱來看就可明確其是觸控式螢幕TS場景的一箇中間庫。其主要完成觸控座標訊息的去抖、濾波和校準等功能。其最核心的功能是從觸控式螢幕座標系到LCD顯示屏座標系的線性轉換。電子產品的觸控式螢幕一般包括觸控式螢幕和顯示屏兩個部分,觸控式螢幕在顯示屏之上,有電阻和電容分壓原理之分。在TS驅動實現中,觸控式螢幕的座標原點是在螢幕的左下角,即驅動向TSLIB提供的基於左下角為原點的座標系座標,而TSLIB需要向QT應用框架提供基於左上角為原點的座標系統座標,因此TSLIB需要完成座標系的轉換。如下圖:


另外,觸控式螢幕的解析度和LCD顯示屏的解析度也有可能不一樣,因此座標的轉換還要考慮解析度的因素。

4.C library,Tslib必須通過open,read這些標準c介面訪問核心層驅動,而這些介面最終都會使用syscall指令跳轉到核心態。

5.VFS,open、read等介面通過syscall系統呼叫層最終會呼叫到vfs_open、vfs_read等介面。Open所帶引數為輸入裝置檔名,如/dev/input/event1,vfs_open通過lookup在dentry連結串列中找到該裝置檔案對應的inode,進而分析出該檔案是一個字元裝置檔案,交由字元裝置驅動框架的chardev_open進行處理,最終獲得輸入子系統(主裝置號都是13)對應的input-core層定義的file_operations,並封裝到所在程序的file結構中,最後嚮應用層返回file對應的控制代碼fd,而read則是通過該file_operations進行讀轉發和訪問操作。

6.字元裝置驅動框架層。chardev_open通過裝置檔案對應的inode讀出對應的主裝置號是13,並在字元裝置驅動全域性連結串列cdev_map中找到主裝置號13對應的file_operations, 即輸入子系統初始化時向系統註冊的input_fops。如下圖:


如何訪問不同的輸入裝置,如觸控式螢幕和按鍵等等,是由input_fops的open來負責。input_fops即為input-core的組成部分。

7.輸入子系統,輸入子系統對linux的輸入裝置驅動進行了高度抽象,最終分成了三層,包括input核心層、input事件處理層和input裝置驅動層。如下圖:


1)所有的輸入裝置的主裝置號都是13,其通過次裝置來將輸入裝置進行分類,如下圖:


2)對於應用層來說,其並不關心輸入裝置驅動層,其只關心輸入事件處理層,即關注哪種型別的輸入裝置。

3)系統初始化時,事件處理層(input-handler)向input-core註冊自己,並告知input-core其能處理底層裝置驅動的型別和能力,例如event_handler事件處理(evdev.c)能夠處理觸控式螢幕和按鍵驅動。

4)當輸入裝置驅動input-device向input-core註冊時,input-core會給其匹配合適的事件處理層input-handler,最終用input-handle來關聯兩者,並在input-handler的控制下生成使用者訪問的字元裝置檔案,如如/dev/input/event0對應的次裝置號即是64。

8.input核心層,有了以上的分析,我們再繼續分析input-core的input_open_file,假如裝置檔名為/dev/input/event0,那次裝置號即64,input_open_file通過次裝置號得到對應的事件處理層event_handler,並交給該handler進行管理。

9.input事件處理層,event_handler根據次裝置號可以得到該輸入驅動在其管理裝置陣列中evdev_table的偏移(為0),進而得到對應的input_handle,最終找到關聯的輸入裝置驅動input-device。

10.input裝置驅動層,輸入裝置驅動層的open會進行硬體初始化等。

11.VFS層以下我們著重分析了驅動的open過程,接下來我們來分析一下觸屏訊息的產生和讀取過程。

1)可以想象出在QT應用框架中會有一個高優先順序的執行緒一直在等待讀取觸控和按鍵訊息。當沒有訊息產生時,該執行緒處於休眠狀態。

2)當用戶觸屏時,觸控式螢幕會產生一個外部硬體中斷,在輸入裝置驅動的中斷處理中會讀取觸屏座標,並向其對應的input-handler彙報,而input-handler在分析該訊息是否是重複訊息等過程後向開啟該handler的執行緒傳送訊號量進行喚醒,並將該觸屏訊息填入執行緒的訊息佇列。

3)QT應用框架執行緒會通過tslib的介面來讀取該訊息,最終獲得LCD座標系座標,並進行後續處理。

備註:輸入子系統分層(input_handler, input_core, input_device)、輸入裝置(TS)驅動開發、evdev handler分析、input裝置模型檢視(sysfs)和執行映象(procfs)、tslib機制分析、應用框架的事件處理分析等系列知識待後續補充。謝謝!

同時,我們還應該看到,觸控式螢幕可能是I2C匯流排介面、UART介面、USB介面等等,因此觸控式螢幕裝置驅動層不僅作為一個input_device存在,還有可能作為一個I2C裝置而存在等等。而I2C裝置驅動又需要對I2C子系統進行分析。繼續努力吧~~