Linux2.6環(huán)境下USB設(shè)備的驅(qū)動(dòng)實(shí)現(xiàn)
嵌入式linux系統(tǒng)環(huán)境以其易于移植裁減、內(nèi)核小、效率高、完整、原代碼開放及性能優(yōu)異等特點(diǎn),在嵌入式領(lǐng)域得到了非常廣泛的應(yīng)用。Linux的USB設(shè)備端的源代碼中主要有USB device的海量存儲(chǔ)設(shè)備、串口設(shè)備、網(wǎng)絡(luò)設(shè)備等設(shè)備驅(qū)動(dòng)程序及各種USB device控制器芯片的驅(qū)動(dòng)程序。市場(chǎng)上USB設(shè)備控制器芯片種類繁多,大多數(shù)用戶需要針對(duì)特定應(yīng)用來開發(fā)相關(guān)的USB設(shè)備控制器驅(qū)動(dòng)程序,才能使設(shè)備正常工作在linux操作系統(tǒng)下。
1 USB設(shè)備端驅(qū)動(dòng)系統(tǒng)
Linux Gadget子系統(tǒng)主要分為三層:第一層為芯片驅(qū)動(dòng)層,負(fù)責(zé)將各種USB device控制器抽象為統(tǒng)一的函數(shù)接口,以供上層驅(qū)動(dòng)程序調(diào)用;第二層主要是對(duì)操作函數(shù)的簡單封裝;第三層為設(shè)備驅(qū)動(dòng)層,可根據(jù)系統(tǒng)的需求實(shí)現(xiàn)所對(duì)應(yīng)的功能。圖1所示是Linux Gadget子系統(tǒng)的驅(qū)動(dòng)層次。Linux Gadget子系統(tǒng)的設(shè)備驅(qū)動(dòng)層主要根據(jù)各個(gè)類別的規(guī)范及協(xié)議實(shí)現(xiàn)各種設(shè)備的驅(qū)動(dòng),本設(shè)計(jì)需要使一個(gè)嵌入式設(shè)備擁有移動(dòng)硬盤的功能,所以,可以根據(jù)海量存儲(chǔ)類的規(guī)范及協(xié)議來實(shí)現(xiàn)該功能。
1.1 UDC驅(qū)動(dòng)的基本構(gòu)架
圖2所示是UDC驅(qū)動(dòng)的基本構(gòu)架圖。在控制器驅(qū)動(dòng)程序中,首先應(yīng)注冊(cè)platform驅(qū)動(dòng),調(diào)用其probe函數(shù)搜索設(shè)備,并在probe函數(shù)內(nèi)初始化usb_ep和usb_gadget等結(jié)構(gòu),然后注冊(cè)設(shè)備,并申請(qǐng)中斷,接著等待中斷進(jìn)入中斷服務(wù)子程序,最后聲明和實(shí)現(xiàn)usb_gadget_register_driver注冊(cè)函數(shù)并輸出給上層驅(qū)動(dòng)。在該過程中,聯(lián)系它們的紐帶是一些全局結(jié)構(gòu)體變量。
1.2 Gadget API
Gadget API為Gadget系統(tǒng)定義了統(tǒng)一的數(shù)據(jù)結(jié)構(gòu)和接口函數(shù),它和主機(jī)端的USB Core地位類似,但功能僅限于提供編程接口,如用結(jié)構(gòu)體usb_gadget_ops和usb_ep_ops對(duì)設(shè)備控制器驅(qū)動(dòng)操作函數(shù)和端點(diǎn)操作函數(shù)進(jìn)行重新封裝。比較特殊的是Gadget驅(qū)動(dòng)程序注冊(cè)函數(shù)usb_gadget_register_driver,它們是由設(shè)備控制器(UDC)驅(qū)動(dòng)直接提供的,用于將UDC綁定到gadget driver。這增加了Gadget Driver和UDC之間的依賴性。
在設(shè)備端,Gadget系統(tǒng)雖然類似主機(jī)驅(qū)動(dòng)系統(tǒng)分了三層結(jié)構(gòu),但Gadget API只定義了一些數(shù)據(jù)結(jié)構(gòu)、宏和功能函數(shù),并對(duì)UDC驅(qū)動(dòng)程序進(jìn)行了簡單包裝,而沒有驅(qū)動(dòng)管理等功能。
1.3設(shè)備應(yīng)用驅(qū)動(dòng)程序
設(shè)備端應(yīng)用程序(Gadget Driver)用于控制USB設(shè)備功能的實(shí)現(xiàn),使設(shè)備表現(xiàn)出“網(wǎng)絡(luò)連接”、“打印機(jī)”或“大容量存儲(chǔ)設(shè)備”等特性。本文以大容量移動(dòng)存儲(chǔ)設(shè)備為例來實(shí)現(xiàn)移動(dòng)硬盤的功能。
BULK ONLY傳輸指的是主機(jī)和大容量存儲(chǔ)設(shè)備之間的一種數(shù)據(jù)傳輸方式。
2設(shè)備端驅(qū)動(dòng)調(diào)度
在嵌入式Linux操作系統(tǒng)中,Gadget driver和Gadget API可完成部分USB協(xié)議處理、BULK ONLY等傳輸協(xié)議以及指令的解析處理,用戶只需要在設(shè)備控制器驅(qū)動(dòng)程序中完成部分USB協(xié)議處理和Gadget API的銜接工作。
圖3所示的流程圖給出了USB設(shè)備端驅(qū)動(dòng)程序的基本調(diào)度思想。該方案的主要思路是被動(dòng)的接受主機(jī)端的傳輸命令(任何類型的通信都由USB主機(jī)發(fā)起,USB設(shè)備間不能直接通信),然后通過中斷觸發(fā)的方式完成主機(jī)端的數(shù)據(jù)傳輸。當(dāng)產(chǎn)生設(shè)備端中斷時(shí),設(shè)備控制器驅(qū)動(dòng)程序首先判斷中斷類型。當(dāng)其為批量傳輸端點(diǎn)IN中斷時(shí),驅(qū)動(dòng)程序會(huì)將該EP下鏈接的REQ中的數(shù)據(jù)依次寫入U(xiǎn)SB2.0 OTG IP的設(shè)備控制器的內(nèi)存區(qū);當(dāng)其為批量傳輸OUT中斷時(shí),驅(qū)動(dòng)程序會(huì)將設(shè)備控制器內(nèi)存區(qū)的數(shù)據(jù)讀入REQ中的buffer中;當(dāng)其為端點(diǎn)0的控制傳輸中斷時(shí),驅(qū)動(dòng)程序?qū)⒆x取端點(diǎn)緩沖區(qū)的數(shù)據(jù),并解析當(dāng)前的設(shè)備請(qǐng)求。如果主機(jī)傳輸給設(shè)備的設(shè)備請(qǐng)求為USB REO SEDRESS(設(shè)置設(shè)備地址)、USB_REQ_GET_STATUS(獲取設(shè)備狀態(tài))、USB_REQ_SET_FEATURE(設(shè)置設(shè)備特性),設(shè)備控制器驅(qū)動(dòng)程序會(huì)自行響應(yīng)請(qǐng)求。但是,如果是其它設(shè)備請(qǐng)求,如GET_DESCRIPTOR(獲取設(shè)備描述符)時(shí),設(shè)備控制器驅(qū)動(dòng)便會(huì)將該請(qǐng)求提交給Gadget Driver,然后由Gadget Driver排隊(duì)將該設(shè)備請(qǐng)求提交給端點(diǎn),以等待下次控制端點(diǎn)中斷。
控制傳輸比較復(fù)雜,它需要完成建立階段、數(shù)據(jù)傳輸階段和狀態(tài)階段。整個(gè)控制端點(diǎn)中斷的處理可通過四個(gè)狀態(tài)實(shí)現(xiàn),分別是:端點(diǎn)0空閑(EP0_IDLE)、 數(shù)據(jù)IN傳輸(EP0 IN DATA_PHASE)、數(shù)據(jù)OUT傳輸(EP0 OUT DATA_PHASE)和狀態(tài)階段(EPO_STATUS)。
EP0_IDLE狀態(tài)主要處理建立階段的setup令牌,并根據(jù)獲得的設(shè)備請(qǐng)求處理能夠處理的設(shè)備請(qǐng)求,同時(shí)把不能處理的設(shè)備請(qǐng)求(如獲取設(shè)備描述符,配置描述符等)提交給上層Gadget Driver;EP0_OUT_DATA_PHASE狀態(tài)主要處理數(shù)據(jù)階段的OUT傳輸;EP0_OUT_DATA_PHASE狀態(tài)主要處理數(shù)據(jù)階段的IN傳輸;EP0_STATUS狀態(tài)則主要完成控制傳輸過程中的狀態(tài)階段。
在圖3所示的流程圖中,EP0為控制傳輸端點(diǎn),EP1、EP2、EP3為批量傳輸端點(diǎn),它們主要包括端點(diǎn)傳輸類型、端點(diǎn)緩沖區(qū)大小等信息。REQ為Gadget Driver提交的端點(diǎn)請(qǐng)求,主要包含傳輸?shù)臄?shù)據(jù)長度和地址。
評(píng)論