(2)“熱插拔”調(diào)用。執(zhí)行順序與其意義如下:
Boot Code里調(diào)用:
a.USB class driver初始化入口點;
b.USB class driver調(diào)用usbdlnitialize();
Hot-Swap code調(diào)用:
c.Hot-Swap 鑒別USB主控制器的連接或斷開;
d.Usbdlnitialize();
e.UsbdPciConfigHeaderGet():讀USB主控制器配置頭;
f.UsbdHedAttaeh():連接HCD,將其作為特定的主控制器。
因為熱插拔可以在任何時刻發(fā)生,所以USBD和其Client都必須被寫成可以動態(tài)識別USB設(shè)備被插入還是被拔出。當主控制器連接到系統(tǒng)時,USBD 自動地鑒別與其相連的設(shè)備,并通知相關(guān)的client;同樣,拔出設(shè)備時,也要通知相關(guān)設(shè)備。重要的是,USBD 的client,比如USB class driver,在client初始化時,從不設(shè)想特定的設(shè)備已經(jīng)出現(xiàn);而在其他時候,這些驅(qū)動隨時檢查設(shè)備是否已經(jīng)連接到系統(tǒng)上。
4.4 總線任務(wù)
對每一個連接到USBD 的主控制器,例如插入或拔出設(shè)備,USBD都會產(chǎn)生一個總線任務(wù),來監(jiān)控總線事件。一般情況下,這些任務(wù)是休眠的(不消耗CPU),只有當USB hub報告它的一個端口有變化時,它們才被喚醒。每一個USBD總線任務(wù)有VxWorks任務(wù)名:UsbdBus。
雖然HCD委托USBD來管理,但有可能HCD 親自監(jiān)視主控制器事件。例如WindRiver提供了UHCI和OHCI的HCD來創(chuàng)造這樣的任務(wù)。對于WindRiver的UHCI模塊(usbHcdUheiLib),后臺任務(wù)只是被周期地喚醒,目的是為了檢查超時IRP(用一個中斷來通知OHCI根hub發(fā)生改變)。
用以在USBD和USB之問進行通信的client模塊,除了調(diào)用usbdlnitialize()外,必須調(diào)用usbClientRegister()使其在USBD注冊。當一個client注冊到USBD時,USBD把每一個以后將要用到的client的數(shù)據(jù)結(jié)構(gòu)定位,并跟蹤那個client的請求。
對于每一個client,在client注冊過程中,USBD還創(chuàng)建了一個callback任務(wù)。在成功注冊client后,USBD返回一個句柄USBD_CLIENT_HANDLE。以下對USBD的調(diào)用,將會用到這個句柄。當所有句柄都不需要時,可以調(diào)用usbdClientUnregister()來釋放每一個client的數(shù)據(jù)結(jié)構(gòu)和callback任務(wù)。注意:此時所有client要求的任務(wù)都會被取消。
例如:注冊一個叫USBD_TEST的client,再注銷。
注冊:usbdClientRegister("USBD_TEST',&usbdClientHandle);
注銷:usbdClientUnregister(usbdClientHandle);
4.5 client回調(diào)(callback)任務(wù)
USB操作是嚴格遵守時序的。例如為使中斷傳輸和同步傳輸正確工作.需要依靠時鐘中斷。在一個有幾個不同client出現(xiàn)的主系統(tǒng)中.總是有可能出現(xiàn)一個client打斷其它client傳輸事件的發(fā)生。WindRiver USBD建議用client callback任務(wù)來解決這個問題。許多USB事件可以導致一個USB client的callback任務(wù)。例如, 每當USBD 完成USB IRP后,client的IRP callback函數(shù)被激活。同樣,當USBD識別出一個動態(tài)連接事件后,會激活一個或更多的動態(tài)attach callback操作。但不是馬上激活這些回調(diào)操作, 而是安排合適的相應(yīng)的USBD client的回調(diào)任務(wù)來執(zhí)行callback。
一般的情況下,每一個client的callback任務(wù)處于“休眠”態(tài)(阻塞態(tài))。每一個client的callback,繼承了usbdClientRegister()產(chǎn)生的VxWorks任務(wù)優(yōu)先級。這確保了每一個callback按其client的任務(wù)優(yōu)先級來執(zhí)行,而且可以利用優(yōu)先級來寫client,保證對時間要求嚴格的USB傳輸。由于每一個client有它自己的callback任務(wù),因此在callback期間,它們有很大的靈活性決定可以做什么。例如,允許在不破壞USBD或其它USBD client性能的條件下,使callback執(zhí)行代碼運行至阻塞態(tài)。
Client callback task有VxWorks任務(wù)名:tUsbdCln。
4.6 USBD內(nèi)部Client
當?shù)谝淮纬跏蓟疷SBD時,由USBD產(chǎn)生并注冊一個內(nèi)部client,以跟蹤USB請求。
USBD 可以產(chǎn)生什么類型的USB請求呢? 所有USBD與USB設(shè)備的傳輸,均利用調(diào)用USBD client的形式來完成。例如, 當一個設(shè)備第一次連接到系統(tǒng)時.USBD用一個控制管道(control pipe) 自動地創(chuàng)建設(shè)備需要的所有的control pipe,即USBD client要用usbdPipeCreate()來創(chuàng)建一個與USB endpoint0通話的通道,然后所有USBD 內(nèi)部、外部client通過這個管道來發(fā)送諸如usbdDescriptorGet()或usbdFeatureGet()等的函數(shù),進行操作。
所以,USBD 的一個機制就是USBD 循環(huán)利用它自己的entry point,而內(nèi)部chent跟蹤這些請求。
4.7 動態(tài)連接的注冊
每當一個特定類型的設(shè)備插入或拔出時,USBD client都通知上一層。利用調(diào)用usbdDynamicAttachRegister()操作,client可以指定一個callback操作,以便可以獲取這樣的通知。
USB設(shè)備類型用class,subclass,protocol來區(qū)別。標準的USB 類在usb.h 中定義為USB_CLASS_XXXX。Subclass和protocol根據(jù)class來定義, 因此這些常數(shù)根據(jù)特定的class在頭文件中定義。
有時, 一個client當利用usbdDynamicAttachRegister()進行注冊時,只對特定的class,subclass,protocol感興趣。例如,USB鍵盤類驅(qū)動usbkeyboardLib, 注冊了Human Device Interface (HID) 類,subclass 是USB_SUBCLASS_HID_ BOOT,protocol是USB_PROTOCOL_HID_BOOT _KEYBOARD。通過callback機制的響應(yīng),每當一個設(shè)備完全符合這樣的標準, 從設(shè)備上插入或拔出時,SBD便通知給keyboard class driver。而在其它情況下,client關(guān)注的范圍更廣泛了。常量USBD_NOTIFY(定義在usbdLib.h)可以替代任意的class,subclass,protocol。例如,USB打印機USB驅(qū)動,usbPrinterLib, 其class等于USB_CLASS_PRINTER,subclass 等于USB_SUBCLASS_PRINTER (usbPrinter.h),protocol等于USBD_ NOTIFY_ ALL。典型的,當一個client只調(diào)用一次usbdDynamicAttachRegister()時,對一個client能擁有的并發(fā)通知請求數(shù)目沒有限制。
4.8 Node ID
USB設(shè)備一般用USBD_NODE_ID來區(qū)別。從其作用來看,USBD_ NODE_ ID 是USBD 用來跟蹤一個設(shè)備的句柄。它與USB設(shè)備真正的USB地址無關(guān)。這表明client并不真正關(guān)心想要了解設(shè)備是物理上與哪一個USB主控制器相連。應(yīng)用為每個設(shè)備抽象定義的Node ID, 使client可以不用考慮物理設(shè)備的連接細節(jié)以及USB地址分配, 并允許USBD 在其內(nèi)部對這些進行詳細的管理。
當一個client通知有一個設(shè)備連接或斷開時,USBD經(jīng)常通過USBD_NODE_ID來定位設(shè)備。同樣,當一個client想通過USBD與一個特定的設(shè)備通信時,它必須向USBD傳遞那個設(shè)備的USBD_NODE_ID。
4.9 總線編號(bus enumeration)操作
usbdLib模塊提供了usbdBusCountGet(),usbdRootNodeldGet(),usbdHubPortCountGet(),usbdNodldGet()操作。它們被一起稱作總線編號操作。它們使USBD Client對連接到每一個主控制器上的設(shè)備進行編號。
這些操作對于診斷程序和測試工具很有用,例如usbTool(WindRiver提供的一個測試工具)。但是,利用它們編號之后,調(diào)用者無法知道USB的拓撲結(jié)構(gòu)是否變化。因此, 建議USB class driver的開發(fā)者不要用這些操作。
4.10 數(shù)據(jù)傳輸
一旦client配置完成一個設(shè)備,就開始利用USBD提供的管道和傳輸功能與設(shè)備進行數(shù)據(jù)交換。傳輸種類(分為控制、塊、中斷和同步傳輸)用一個USB_IRP數(shù)據(jù)結(jié)構(gòu)來描述。 USB_IRP 的具體描述請參見HCD_FUNC_IRP_SUBM1T。USB數(shù)據(jù)傳輸被定位于每一個設(shè)備的特定endpoint。在USBD client和特定的設(shè)備endpoint之間的通道被稱作管道(pipe)。每一個管道有以下若干特性:
USBD_NODE_ID;
設(shè)備的endpoim 數(shù)目;
數(shù)據(jù)傳輸方向;
帶寬需求;
延時需求。
為了和設(shè)備交換數(shù)據(jù),client必須先創(chuàng)建管道。作為結(jié)果,USBD得到了一個USBD_PIPE_HANDLE,它被用于隨后對這個管道的所有client操作。
當client企圖創(chuàng)建一個管道時,USBD會檢查是否有足夠的可用帶寬。對于中斷和同步傳輸,帶寬限制是必需的。USBD不允許把90% 以上的可用帶寬分配給中斷和同步管道;而對于控制和塊傳輸,則沒有帶寬的限制。同時,保證至少10% 的帶寬用于控制傳輸,對塊傳輸則不保證會提供任何可用帶寬。
數(shù)據(jù)傳輸?shù)木唧w過程:
(1)創(chuàng)建pipe :usbdPipeCreate(usbdClient Handle,nodeld,endpoint,configvalue,interface,USB_XFRTYPE_BULK,USB_ DIR_OUT,maxPacketSize,0,0,&outPipeHandle);
(2)定義callback:ourlrpCallback(pvoid P);
(3)初始化IRP的數(shù)據(jù)結(jié)構(gòu);
(4)發(fā)送IRP:usbdTransfer(usbdChentHandle,outPipeHandle,&irp)。
5 、小結(jié)
USB在VxWroks下的從下至上驅(qū)動棧分為HC、UCD、USBD和Client Module四層,每一層都相對獨立,并為上一層提供了屏蔽該層次具體特征的接口。作者所說的USB驅(qū)動,實際上主要在USBD這一層次上完成。具體分為Chent注冊,注銷,創(chuàng)建pipe ,配置,數(shù)據(jù)發(fā)送,以及各回調(diào)函數(shù)。當正確地依次調(diào)用時, 會根據(jù)回調(diào)函數(shù)的狀態(tài)和返回值,按正確的時序進行完整的數(shù)據(jù)傳輸。
上述設(shè)計思想構(gòu)成了VxWorks下USB設(shè)備應(yīng)用的基礎(chǔ)。作者的研究詳細地分析了VxWorks的USB協(xié)議棧,證明了該方案的可行性,同時又給出了合理的實現(xiàn)方法。作為實踐成果,作者已在VPN網(wǎng)關(guān)證書讀取系統(tǒng)中,利用該思想編寫的驅(qū)動,順利讀出存儲在USB設(shè)備中的設(shè)備證書和管理員證書,且運行情況良好。作者認為,文中提到的模型完全可以勝任解決USB設(shè)備在VxWorks下的應(yīng)用所面臨的技術(shù)難題