劉少平
(陜西烽火電子股份有限公司 陜西 寶雞 721006)
嵌入式技術(shù)在工業(yè)和日常生活中變得越來越普及,Linux作為是目前最流行的操作系統(tǒng)之一,在桌面系統(tǒng)、服務(wù)器領(lǐng)域都有大量用戶,在嵌入式領(lǐng)域也備受青睞。盡管Linux內(nèi)核完全由C語言和匯編語言寫成,但是卻頻繁的用到了面向?qū)ο蟮脑O(shè)計思想。具體到驅(qū)動方面,就是為同類的設(shè)備設(shè)計一個框架,而框架的核心層則實現(xiàn)了該設(shè)備通用的一些功能。
Linux系統(tǒng)提供了輸入子系統(tǒng),按鍵、鍵盤、觸摸屏、鼠標等設(shè)備都可以利用它的接口函數(shù)來實現(xiàn)設(shè)備驅(qū)動。基于輸入子系統(tǒng)的優(yōu)越性,這種設(shè)備程序接口得到了很好的應(yīng)用,但目前為止介紹輸入子系統(tǒng)的相關(guān)資料卻較缺乏。文中基于Linux內(nèi)核輸入子系統(tǒng)對設(shè)備驅(qū)動流程進行了研究,并以觸摸屏為例,詳細分析了驅(qū)動實現(xiàn)過程,通過程序移植,觸摸屏校準之后可以正常使用。入設(shè)備的抽象,是內(nèi)核中字符設(shè)備驅(qū)動接口的封裝。輸入子系統(tǒng)由設(shè)備驅(qū)動層、核心層和事件處理層構(gòu)成,如圖1所示。
圖1 輸入子系統(tǒng)Fig.1 Input subsystem
Linux系統(tǒng)主要將設(shè)備分成3種類型:字符設(shè)備、塊設(shè)備和網(wǎng)絡(luò)接口。分別對應(yīng)字符模塊 (charmodule)、塊模塊(block module)和網(wǎng)絡(luò)模塊(network module)[1]。 比如:常用的按鍵、鍵盤、觸摸屏、鼠標等都是典型的字符設(shè)備。對于面向?qū)ο蟮某绦蛟O(shè)計,為了極大提高代碼的可重用能力,引入了輸入子系統(tǒng)。
Linux輸入子系統(tǒng)[2-3]是對物理形態(tài)各異的功能相似的輸
設(shè)備驅(qū)動層(Input Device Drivers)提供對硬件各寄存器的讀寫訪問和將底層硬件對用戶輸入訪問的響應(yīng)轉(zhuǎn)換為標準的輸入事件,通過核心層提交給事件處理層 (Input Event Drivers);核心層(Input Core)對設(shè)備驅(qū)動層提供編程接口,對事件處理層的也提供編程接口;事件處理層為用戶空間的應(yīng)用程序提供了統(tǒng)一訪問設(shè)備的接口和驅(qū)動層提交來的事件處理。
以字符設(shè)備為例,一般的工作原理是底層在這些輸入設(shè)備動作發(fā)生時產(chǎn)生一個中斷(或通過timer定時查詢),然后CPU通過SPI、I2C或者外部存儲器總線讀取鍵值、坐標等數(shù)據(jù),放入一個緩沖區(qū),即字符設(shè)備驅(qū)動管理緩沖區(qū),而驅(qū)動的read()接口讓用戶可以讀取鍵值,坐標等數(shù)據(jù)。
顯然,在這些工作中,只有中斷、讀鍵值與坐標值是與設(shè)備相關(guān)的,而輸入事件的緩沖區(qū)管理以及字符設(shè)備驅(qū)動的文件管理接口對于輸入設(shè)備是通用的。因此,內(nèi)核中的輸入子系統(tǒng)就用來處理公共的工作。所有的輸入事件,內(nèi)核使用統(tǒng)一的數(shù)據(jù)結(jié)構(gòu)input_event來描述,如下:
在input_dev結(jié)構(gòu)體中,一個字段是evbit,它表示響應(yīng)的事件類型。
基于輸入子系統(tǒng)的設(shè)備驅(qū)動層驅(qū)動的實現(xiàn)過程如下:
1)在驅(qū)動模塊加載函數(shù)中設(shè)置輸入設(shè)備支持輸入子系統(tǒng)的事件,Linux內(nèi)核用input_dev代表一個輸入設(shè)備。
2)設(shè)備驅(qū)動通過set_bit()告訴子系統(tǒng)它支持哪些事件,如 :set_bit (EV_KEY,input_dev.evbit)。 通 過 內(nèi) 核 提 供 的input_register_device()函數(shù)向輸入子系統(tǒng)注冊輸入設(shè)備。
3)在鍵被按下/抬起,觸摸屏被觸摸/抬起/移動,鼠標被移動/單擊/抬起時,輸入設(shè)備通過 input_report_xxx()報告發(fā)生的事件及對應(yīng)的鍵值、坐標等狀態(tài)。
驅(qū)動模塊初始化函數(shù)中,除了對驅(qū)動字符設(shè)備注冊外,還要進行中斷申請等多項工作。在設(shè)備驅(qū)動中,將實現(xiàn)open( )、release( )、read( )、fasync( )和 poll( )等函數(shù)。 以觸摸屏[4]為例,常規(guī)的觸摸屏驅(qū)動設(shè)計[5-6]需要處理更多的事務(wù),還要向應(yīng)用層實現(xiàn)設(shè)備的讀取入口函數(shù)等等。而利用輸入子系統(tǒng),通過對input_dev實例的evbit[0]的設(shè)置來支持同步(EN_SYN)、按鍵(EN_KEY)和絕對坐標(EV_ABS)事件。 觸摸屏使用輸入子系統(tǒng)提供的通用輸入事件驅(qū)動程序evdev,將事件信息打包成Input_event類型進行報告。其實現(xiàn)流程大致為:
1)定義一個輸入設(shè)備并進行初始化需要用到的結(jié)構(gòu)體和參數(shù)。設(shè)置input_dev中的device的名字,名字以input0、input1、input2、input3的 形 式 出 現(xiàn) 在 sysfs文 件 系 統(tǒng) 中 :dev_set_name (&dev->dev,”input%d”, (unsigned long)atomic_inc_return(&input_no)-1)。
2)告知輸入子系統(tǒng),使用device_add()函數(shù)將input_dev包含的device結(jié)構(gòu)注冊到Linux設(shè)備模型中,并可以在 sysfs文件系統(tǒng)中表現(xiàn)出來:device_add(&dev->dev);并將input_dev加入input_dev_list鏈表中,input_dev_list鏈表中包含了系統(tǒng)中所有input_dev設(shè)備,如下:
list_add_tail(&dev->node,&input_dev_list);
3)在觸摸屏設(shè)備驅(qū)動的模塊加載函數(shù)中,完成申請設(shè)備號、申請中斷、設(shè)置觸摸屏控制引腳等多項工作:
在觸摸屏設(shè)備驅(qū)動中,一次坐標及按下狀態(tài)的整個報告過程如下:
4) 中斷申請:request_irq(DEV_IRQ, dev_interrupt,0,“dev”,NULL))。觸摸屏驅(qū)動中會產(chǎn)生兩類中斷,一類是觸點中斷(INT-TC),一類是X/Y位置轉(zhuǎn)換中斷(INT-ADC)。在前一類中斷發(fā)生后,若之前處于PEN_UP狀態(tài),則應(yīng)該啟動X/Y位置轉(zhuǎn)換。另外,將抬起中斷也放在INT-TC處理程序中,調(diào)用函數(shù)完成等待隊列和信號的釋放。當(dāng)X/Y位置轉(zhuǎn)換中斷發(fā)生后,應(yīng)讀取X、Y的坐標值,填入緩沖區(qū)。
5)觸摸屏設(shè)備驅(qū)動的讀函數(shù)實現(xiàn)緩沖區(qū)中信息向用戶空間的復(fù)制。當(dāng)緩沖區(qū)有內(nèi)容時,直接復(fù)制;否則,如果用戶阻塞訪問觸摸屏,則進程在等待隊列上睡眠,如果沒有阻塞,立即返回-EAGAIN。
6)在模塊的卸載函數(shù)中,要完成釋放設(shè)備號、釋放中斷等工作。注銷輸入設(shè)備函數(shù)為:
void input_unregister_device(struct input_dev*dev)。
最后,驅(qū)動應(yīng)向應(yīng)用層提供接口函數(shù)。當(dāng)應(yīng)用程序讀取和關(guān)閉該觸摸屏的設(shè)備節(jié)點時,將其調(diào)用,工作流程如圖2所示。通過試驗,使用該流程驅(qū)動的觸摸屏校準之后可以正常使用。
Linux輸入子系統(tǒng)是對分散的、不同類別的輸入設(shè)備進行統(tǒng)一處理的內(nèi)核驅(qū)動模型。具有高效、無Bug和可重用等優(yōu)點。隨著信息技術(shù)的迅速發(fā)展和芯片制造工藝的不斷進步,從軍事電子設(shè)備,現(xiàn)代武器到工業(yè)過程控制,從網(wǎng)絡(luò)通信,辦公自動化到消費電子領(lǐng)域,基于Linux系統(tǒng)的產(chǎn)品將與人們的生活密不可分,并且也將有更多的輸入事件得到Linux輸入子系統(tǒng)的支持。
圖2 流程圖Fig.2 Flow chart
[1]Johnson MK,Troan EW.Linux應(yīng)用程序開發(fā)[M].2版.武延軍,郭松柳,譯.北京:電子工業(yè)出版社,2005.
[2]Hards B.Using the Input Subsystem,PartⅠ[EB/OL].(2003-02).http://www.linuxjournal.com/article/6396.
[3]Hards B.Using the Input Subsystem, PartⅡ[EB/OL].(2003-02).http://www.linuxjournal.com/article/6429.
[4]孫天澤,袁文菊,張海峰.嵌入式設(shè)計及Linux驅(qū)動開發(fā)指南[M].北京:電子工業(yè)出版社,2005.
[5]劉淼.嵌入式系統(tǒng)接口設(shè)計與Linux驅(qū)動程序開發(fā) [M].北京:北京航空航天大學(xué)出版社,2006.
[6]楊衛(wèi)功,丁忠林.嵌入式Linux系統(tǒng)中觸摸屏驅(qū)動的研究[J].微計算機信息,2007,23(1-2):103-105.
YANG Wei-gong,DING Zhong-lin.The embedded Linux system touch screen driver[J].Micro Computer Information,2007,23(1-2):103-105.