USB模組可以分為多連接埠主機(MPH)模組和雙角色(DR)模組,它們都能夠串連一個或者二個外部連接埠,這些模組和外部連接埠總稱為USB介面。Mpc8379的USB模組採用的是DR,它的寄存器和資料結構均基於Intel的EHCI(Enhanced Host Controller Interface Specification for Universal Serial Bus),DR模組可以充當USB匯流排上的主機、外設、以及支援攜帶型On-The-Go(OTG))可協商主機/外設。
DR模組有三個基本操作模式:主機(Host)、裝置和OTG。可以把DR模組配置成使用UTMI、ULPI 或者FS/LS串列收發器中的任何一種PHY介面。由於引腳的限制,UTMI介面只能用在裝置操作模式。值得注意的是,裝置模式下的DR模組不支援LS操作。8377使用的phy晶片smsc3300的介面為ULPI(UTMI + Low Pin Interface)。
風河USB為通用序列匯流排提供USB傳輸初始化(USB hosts)和允許vxWorks目標作為USB外設的支援,USB hosts(又叫USB host stack)和USB外設(又叫USB peripheral stack)都遵循USB 2.0規約。Host Stack使vxWorks可以使用USB裝置,而Peripheral Stack允許Windows機器將vxWorks板當做一個USB裝置。這裡先介紹Host,為USB
Host驅動棧結構:
USB Host Stack驅動包括USB驅動(USBD)、主機控制驅動(HCD)、hub驅動和class驅動。風河為標準介面協議EHCI、UHCI、OHCI提供HCD驅動,另外,還為USB控制器提供了root hub diver,為各種USB外設提供class driver合集。其中,USBD是硬體獨立的,它提供了驅動棧上層(包括USB class drivers)與USB匯流排的通訊通道,還負責電源管理、USB頻寬管理、動態掛載/釋放USB裝置等功能。為vxWorks中所體現的USB
Host Stack組成圖:
這裡從上往下來理解,usbTool是風河提供的USB測試載入器包,從使用usbTool的過程可知,USB在初始化時的步驟如下:
1、先執行usbInit初始化USB2的Host Stack,源碼如下:
STATUS usbInit (void){if (!usbdInitByKernel){/* 為USB驅動設定記憶體空間(預設2M)*/ossPartSizeSet(USB_MEM_PART_SIZE); /* 初始化USB2 Host Stack,主要初始化USBD2.0層的全域變數*/ if (usbdInit() == OK) { usbdInitByKernel = TRUE;#ifdef DEBUG_ANNOUNCE_USB printf("USB2 Host Stack Initialized\n");#endif/*註冊USB Hub Class驅動到USB Host驅動棧,以及初始化USB1.1轉換層*/ if ((usrUsbHubInit() != OK) || (usbdTranslationInit() != OK)) { return ERROR; } } } else { printf("USB2 Host Stack Already Initialized\n"); } return OK;}
2、然後執行usbdInitialize初始化USBD,該函數在系統調用其他USBD函數前必須執行一次以上,有一個公用計數器guUSBDInited ,Initialize函數時會加1,ShutDown時會減1,大於0時表示初識化完成,注意:由於usbdInitialize可以嵌套執行,所以在執行計數器操作時,必須要遵循互斥訪問規則。它用於準備訪問URBs所需的USBD和傳送單元。oss為O/S-independent
services,用於保護互斥訊號量。Host Stack的USBD2.0和Hub class模組的源碼可以參考這兩個目錄:
installDir/target/src/hwif/usb和installDir/target/src/hwif/busCtlr/usb/hub
3、再初始化EHCI、OHCI、UHCI控制器,在usbTool中,這個過程叫做Attach,用於初始化hcd並註冊到vxBus。先後調用usbxhcdInit和vxbUsbxhciRegister兩個函數,前者的使用過程實際上就是調用usbHstHCDRegister,將HCD註冊到USBD中,這裡涉及到一個結構體USBHST_HC_DRIVER,它包含了HCD的函數指標,在HCD初始化時會將它傳給USBD,後者利用這些指標和HCD進行通訊。該結構體定義如下:
typedef struct usbhst_hc_driver { /* 用於此HCD的匯流排數目 */ UINT8 uNumberOfBus; /* 結構體vxbBusTypeInfo儲存匯流排資訊 */ struct vxbBusTypeInfo * pUsbHcdBusType; /*下面均為函數指標*/ /* 從frame number Reg中擷取num*/ USBHST_STATUS (*getFrameNumber) (UINT8 uBusIndex, UINT16 *puFrameNumber); /* 設定frame位寬 */ USBHST_STATUS (*setBitRate) (UINT8 uBusIndex, BOOL bIncrement, UINT32 *puCurrentFrameWidth); /* 判斷匯流排頻寬是否足夠支援介面設定的改動 */ USBHST_STATUS (*isBandwidthAvailable) (UINT8 uBusIndex, UINT8 uDeviceAddress, UINT8 uDeviceSpeed, UCHAR *pCurrentDescriptor, UCHAR *pNewDescriptor); /* 為特定USB endpoint解析並建立pipe */ USBHST_STATUS (*createPipe) (UINT8 uBusIndex, UINT8 uDeviceAddress, UINT8 uDeviceSpeed, UCHAR *pEndPointDescriptor, UINT16 uHighSpeedHubInfo, UINT32 *puPipeHandle); /* 修改預設pipe屬性(address 0,endpoint 0) */ USBHST_STATUS (*modifyDefaultPipe) (UINT8 uBusIndex, UINT32 uDefaultPipeHandle, UINT8 uDeviceSpeed, UINT8 uMaxPacketSize, UINT16 uHighSpeedHubInfo); /* 刪除pipe */ USBHST_STATUS (*deletePipe) (UINT8 uBusIndex, UINT32 uPipeHandle); /* pipe上的請求pending */ USBHST_STATUS (*isRequestPending)(UINT8 uBusIndex, UINT32 uPipeHandle); /* 提交請求到endpoint,URB:USB Request Block */ USBHST_STATUS (*submitURB) (UINT8 uBusIndex, UINT32 uPipeHandle, pUSBHST_URB pURB); USBHST_STATUS (*cancelURB) (UINT8 uBusIndex, UINT32 uPipeHandle, pUSBHST_URB pURB); /* 以下兩個用於處理split transaction時出現的錯誤 */ USBHST_STATUS (*clearTTRequestComplete)(UINT8 uRelativeBusIndex, void * pContext, USBHST_STATUS nStatus); /* Function pointer to submit the status of the reset TT request */ USBHST_STATUS (*resetTTRequestComplete)(UINT8 uRelativeBusIndex, void * pContext, USBHST_STATUS nStatus);} USBHST_HC_DRIVER, *pUSBHST_HC_DRIVER;
後者則分析意義不大,全部都是調用vxbDevRegister註冊到vxBus上。
至於這些驅動,風河已經編譯好了(鬱悶,還是只能看代碼學習),見目錄installDir/target/src/hwif/busCtrl/usb/hcd,三種介面都分開放置了,儘管一次只能使用一種介面,但風河允許同時添加多個介面驅動,從而加強了產品的相容性。到這裡需要注意,添加usbTool就不能添加其他任何Init函數,否則會編譯出錯。
若不是有usbTool,將組件完全包含後,系統若要使用USBD2.0介面,需要在vxWorks啟動時經曆4步初始化過程:
1、根據選擇的組件將USB host控制器註冊到vxBus。該過程是vxBus發現控制器裝置並執行特定的vxBus初始化操作,調用函數為vxbUsbControllerRegister,
2、執行USBD入口函數usbdInit,
3、執行usbHubInit初始化hub class Drivers;
4、執行usbHcdInit將特定的HCD註冊到USBD。
中還有個OSAL,該組件用於為vxWorks關於host Stack的作業系統服務提供一個抽象、簡化的視圖。它包含了進程管理、互斥量、記憶體調度以及系統時間等,在usbd中,就是ossLib庫。需要注意,在編寫USB驅動時,需要有大部分精力是放在互斥訪問和記憶體調度上的。