VxWorks下的同類USB設(shè)備管理方法
引言
VxWoAs是美國(guó)Wind River System(WRS)公司開(kāi)發(fā)的嵌入式實(shí)時(shí)操作系統(tǒng)。VxWorks中的I/O子系統(tǒng)為應(yīng)用程序提供了簡(jiǎn)單、統(tǒng)一、與設(shè)備無(wú)關(guān)的訪問(wèn)接口。I/O系統(tǒng)內(nèi)部采用設(shè)備列表、驅(qū)動(dòng)程序列表和文件描述符表來(lái)實(shí)現(xiàn)對(duì)不同設(shè)備的管理與訪問(wèn),從而為開(kāi)發(fā)通用外部設(shè)備驅(qū)動(dòng)程序提供了便利。然而在一些專用系統(tǒng)上,為了縮短設(shè)備的響應(yīng)時(shí)間,提高設(shè)備的讀取速度,有必要將設(shè)備與I/O系統(tǒng)獨(dú)立起來(lái)。由于VxWorks屬于微內(nèi)核,所有的程序均運(yùn)行在同一線性地址空間,這也為設(shè)備與I/O系統(tǒng)的獨(dú)立提供了條件?;赩xWorks的I/O子系統(tǒng)設(shè)備管理的思想,本文提出了一種在VxWorks下對(duì)多個(gè)同類USB設(shè)備進(jìn)行管理的設(shè)計(jì)方案。該方案可使得對(duì)設(shè)備的訪問(wèn)獨(dú)立于I/O子系統(tǒng)。
1 VxW0rks的I/O子系統(tǒng)設(shè)備管理
VxWorks I/O系統(tǒng)內(nèi)部對(duì)設(shè)備的管理主要通過(guò)三張表來(lái)實(shí)現(xiàn),即驅(qū)動(dòng)程序列表、設(shè)備列表和文件描述符表。其中驅(qū)動(dòng)程序列表用來(lái)管理已注冊(cè)的設(shè)備驅(qū)動(dòng)程序,它的大小是固定的,有NUM DRIVERS項(xiàng),每一項(xiàng)對(duì)應(yīng)驅(qū)動(dòng)程序的入口點(diǎn),當(dāng)應(yīng)用程序調(diào)用標(biāo)準(zhǔn)I/O接口函數(shù)時(shí),I/O子系統(tǒng)便可通過(guò)驅(qū)動(dòng)程序列表檢索到設(shè)備的驅(qū)動(dòng)程序,從而實(shí)現(xiàn)對(duì)指定設(shè)備的訪問(wèn)、發(fā)送、接收等操作。系統(tǒng)可利用iosDrvInstall()注冊(cè)設(shè)備驅(qū)動(dòng)程序,并將設(shè)備的人口函數(shù)加入到驅(qū)動(dòng)程序列表。同時(shí)返回一個(gè)drvnum驅(qū)動(dòng)程序號(hào),并將其作為設(shè)備描述符的一部分,從而以此把設(shè)備與其驅(qū)動(dòng)程序聯(lián)系起來(lái)。I/O子系統(tǒng)采用鏈表對(duì)所有設(shè)備進(jìn)行管理,該鏈表稱之為設(shè)備列表。調(diào)用iosDevAdd ()可向系統(tǒng)添加設(shè)備,添加設(shè)備時(shí),應(yīng)指明設(shè)備名稱及驅(qū)動(dòng)程序索引號(hào),該索引號(hào)就是iosDrvInstall ()返回的索引號(hào)。在VxWorks中,一個(gè)設(shè)備可以被多次打開(kāi),但對(duì)于每一次打開(kāi),系統(tǒng)將利用一個(gè)文件描述符來(lái)區(qū)分,本系統(tǒng)將會(huì)維持一張文件描述符表,該表的每一項(xiàng)記錄了與設(shè)備對(duì)應(yīng)的驅(qū)動(dòng)程序號(hào)和設(shè)備ID,這樣,就會(huì)文件描述符與驅(qū)動(dòng)程序、以及設(shè)備之間建立一種聯(lián)系。這樣,在利用標(biāo)準(zhǔn)I/O函數(shù)進(jìn)行讀寫(xiě)時(shí),就可以根據(jù)文件描述符從文件描述符表中找到對(duì)應(yīng)的驅(qū)動(dòng)程序的人口與設(shè)備ID。VxWorks中的這三張表的關(guān)系如圖1所示。
2 USB設(shè)備管理方案設(shè)計(jì)
設(shè)計(jì)獨(dú)立于I/O系統(tǒng)的USB設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)思想主要基于兩點(diǎn),第一是用戶自己管理設(shè)備。第二是通過(guò)驅(qū)動(dòng)程序直接向應(yīng)用程序提供可用于讀寫(xiě)設(shè)備的接口函數(shù)。由于設(shè)備獨(dú)立于I/O系統(tǒng),用戶需要自己設(shè)計(jì)一種設(shè)備管理方法,以便對(duì)多個(gè)接入的USB設(shè)備進(jìn)行合理的管理。然而由于不存在設(shè)備驅(qū)動(dòng)程序列表,故在設(shè)計(jì)時(shí)還需要有一種方法來(lái)解決設(shè)備的訪問(wèn)問(wèn)題。
2.1 USB設(shè)備描述符
設(shè)備描述符實(shí)際上是一個(gè)數(shù)據(jù)結(jié)構(gòu),可在系統(tǒng)中作為一個(gè)邏輯結(jié)構(gòu)體。它是一個(gè)具體設(shè)備的抽象。可與一個(gè)物理設(shè)備相對(duì)應(yīng),是參與設(shè)備管理、訪問(wèn)的主要結(jié)構(gòu)體。鑒于I/O子系統(tǒng)對(duì)設(shè)備的管理,在對(duì)多個(gè)USB設(shè)備進(jìn)行管理時(shí),對(duì)于設(shè)備的存儲(chǔ),可采用雙向鏈表來(lái)進(jìn)行管理,稱之為設(shè)備列表。鏈表對(duì)USB設(shè)備的管理主要通過(guò)設(shè)備頭(USB_BEV_HDR)來(lái)實(shí)現(xiàn)。USB設(shè)備頭是一個(gè)與具體設(shè)備無(wú)關(guān)的數(shù)據(jù)結(jié)構(gòu),它由一個(gè)鏈表節(jié)點(diǎn)和設(shè)備名稱組成。節(jié)點(diǎn)中包含指向有前一個(gè)和下一個(gè)USB設(shè)備的設(shè)備頭的鏈表節(jié)點(diǎn)。實(shí)際上,每一個(gè)USB設(shè)備都會(huì)有更多的數(shù)據(jù)存儲(chǔ)在更大的數(shù)據(jù)結(jié)構(gòu)中。這個(gè)結(jié)構(gòu)就是設(shè)備描述符,而USB設(shè)備頭只是做為USB設(shè)備描述符的起始部分。設(shè)備頭的數(shù)據(jù)結(jié)構(gòu)(USB_DEV_HDR)如下:
其中,USB_DL_NODE是一個(gè)鏈表節(jié)點(diǎn),它由兩個(gè)鏈表節(jié)點(diǎn)指針域組成。分別指向前一個(gè)和下一個(gè)設(shè)備的鏈表節(jié)點(diǎn)。其數(shù)據(jù)結(jié)構(gòu)如下:
這樣,就可以把USB設(shè)備的描述符劃分為兩部分,其中一部分與具體設(shè)備無(wú)關(guān),稱為設(shè)備頭:另外一部分是與具體設(shè)備相關(guān)的設(shè)備特殊數(shù)據(jù),設(shè)備相關(guān)部分包括USB設(shè)備的Node ID、USB管道句柄、端點(diǎn)地址、狀態(tài)等信息。其結(jié)構(gòu)如圖2所示。設(shè)備無(wú)關(guān)部分主要用于設(shè)備管理,而設(shè)備相關(guān)部分則用于對(duì)設(shè)備的訪問(wèn)。
2.2設(shè)備列表設(shè)計(jì)
為了方便對(duì)設(shè)備的管理,USB設(shè)備列表可采用雙向鏈表結(jié)構(gòu),其作用是將所有USB設(shè)備的有關(guān)信息組織起來(lái),從而實(shí)現(xiàn)對(duì)多個(gè)設(shè)備的鏈?zhǔn)焦芾?。前面提到的設(shè)備描述符就是一個(gè)存儲(chǔ)了設(shè)備信息的數(shù)據(jù)結(jié)構(gòu)。而所有USB設(shè)備描述符都是以設(shè)備頭數(shù)據(jù)結(jié)構(gòu)開(kāi)始的,這樣,就可以很方便地將設(shè)備描述符組成一個(gè)鏈表形式的設(shè)備列表。通常鏈表的數(shù)據(jù)結(jié)構(gòu)如下:
圖3所示是一個(gè)空設(shè)備列表,而非空設(shè)備列表則如圖4所示。
對(duì)于同類USB設(shè)備,通常程序只維護(hù)一張?jiān)O(shè)備列表,在注冊(cè)該USB設(shè)備驅(qū)動(dòng)程序時(shí),初始化設(shè)備列表為空,驅(qū)動(dòng)程序只能被真正的注冊(cè)一次,因此,設(shè)備列表也只初始化一次。當(dāng)驅(qū)動(dòng)程序中的回調(diào)函數(shù)檢測(cè)到有設(shè)備動(dòng)態(tài)接人時(shí),系統(tǒng)會(huì)在創(chuàng)建設(shè)備、分配設(shè)備資源的同時(shí)將設(shè)備描述符加入到設(shè)備列表,而且只將其加入到設(shè)備列表的尾部。而在有設(shè)備動(dòng)態(tài)移除時(shí),驅(qū)動(dòng)程序回調(diào)函數(shù)會(huì)捕獲移除動(dòng)作,并根據(jù)設(shè)備的標(biāo)識(shí)遍歷設(shè)備列表,以查找出移除的設(shè)備,然后將其描述符從設(shè)備列表中刪除。遍歷設(shè)備列表其實(shí)就是一個(gè)查找設(shè)備的過(guò)程。查找設(shè)備時(shí),每一個(gè)設(shè)備都需要用唯一的一個(gè)標(biāo)識(shí)來(lái)與其它設(shè)備區(qū)別,從而引出了設(shè)備的唯一標(biāo)識(shí)問(wèn)題。
2.3 USB設(shè)備的標(biāo)識(shí)問(wèn)題
同I/O系統(tǒng)標(biāo)識(shí)設(shè)備一樣,對(duì)于USB設(shè)備的標(biāo)識(shí)。也可以采用設(shè)備名來(lái)標(biāo)識(shí)。這樣可以給用戶一個(gè)直觀的概念,而且便于記憶。利用設(shè)備頭(USB_DEV_HDR)中的name指針域可以為每一個(gè)接入的設(shè)備起一個(gè)名字。這樣,對(duì)于不同的設(shè)備,就可以用名字字符串來(lái)唯一區(qū)分,但這不利于快速訪問(wèn)設(shè)備,因?yàn)樵诿看尾檎以O(shè)備的時(shí)候?qū)τ诿恳粋€(gè)設(shè)備鏈表節(jié)點(diǎn)都要進(jìn)行一次字符串比較,這樣便延長(zhǎng)了查找設(shè)備的時(shí)間。針對(duì)USB設(shè)備及VxWorks下USB協(xié)議棧的特點(diǎn),充分利用USBD對(duì)USB設(shè)備的標(biāo)識(shí),在設(shè)計(jì)中可采用USBD_NODEjD來(lái)標(biāo)識(shí)設(shè)備。在VxWorks中的USB協(xié)議棧中。對(duì)每一個(gè)USB設(shè)備為其分配一個(gè)唯一的USBD_NODE_ID號(hào)。事實(shí)上,VxWorks USBD并不關(guān)心設(shè)備與哪一個(gè)USB主控制器相連,也不關(guān)心物理設(shè)備的連接細(xì)節(jié)以及地址分配,USBD通常只是采用USBD_NODE_ID來(lái)定位設(shè)備。因此,基于USBD對(duì)USB設(shè)備的定位方法,在采用鏈表對(duì)USB設(shè)備進(jìn)行管理時(shí),也可以采用USBD_NODE_ID來(lái)唯一標(biāo)識(shí)一個(gè)USB設(shè)備。在用該方法標(biāo)識(shí)設(shè)備時(shí),可將USBD_NODE_ID nodeld作為USB設(shè)備描述符結(jié)構(gòu)體的一個(gè)成員,其設(shè)備描述符結(jié)構(gòu)改造如下:
由于USBD_NODE_ID是一個(gè)32位無(wú)符號(hào)整型數(shù),因此,在查找設(shè)備時(shí),可以用switch case語(yǔ)句來(lái)完成。
2.4設(shè)備訪問(wèn)技術(shù)
由于設(shè)備是獨(dú)立于I/O系統(tǒng)的,因此不存在驅(qū)動(dòng)程序列表和文件描述符表。設(shè)計(jì)時(shí),可采用驅(qū)動(dòng)程序直接向應(yīng)用程序提供可訪問(wèn)設(shè)備的接口函數(shù),以替代驅(qū)動(dòng)程序列表,而采用USBD_NODE_ID數(shù)組來(lái)存放多個(gè)USB設(shè)備的標(biāo)識(shí),以替代文件描述符表,如:USBD_NODE_ID usbd_node_id[MAX_DEV_NUM]。
對(duì)于同類USB設(shè)備,根據(jù)其Product ID的不同,可將其記為O、l、2……MAX_DEV_NUM號(hào)設(shè)備,并分別將其USBD_NODE_ID存放于數(shù)組的對(duì)應(yīng)位置。這樣,在訪問(wèn)設(shè)備時(shí),就可利用設(shè)備號(hào)來(lái)代替文件描述符,例如在讀取0號(hào)設(shè)備時(shí),由其索引值0,就可得到其USBD_NODE_ID為USBD_NODE_ID usbd_node_id[O],再?gòu)脑O(shè)備列表中查找出nodeld為usbd_node_id[O]的設(shè)備結(jié)構(gòu)體,就可最終得到設(shè)備資源。通過(guò)USBD_NODE_ID數(shù)組來(lái)管理多個(gè)設(shè)備的nodeld如圖5所示。
在讀寫(xiě)設(shè)備時(shí)。可以設(shè)備號(hào)作為設(shè)備的標(biāo)識(shí),并通過(guò)設(shè)備號(hào)在nodeld數(shù)組中得到設(shè)備的nodeId,再?gòu)脑O(shè)備列表中查找到具體的物理設(shè)備的描述符。從而得到設(shè)備資源并對(duì)設(shè)備進(jìn)行訪問(wèn)。以LM9833讀設(shè)備為例,其讀設(shè)備原型代碼如下:
其中,usbScanRead()是驅(qū)動(dòng)程序向用戶應(yīng)用程序提供的接口函數(shù),直接調(diào)用該函數(shù)即可讀取設(shè)備,其它的設(shè)備函數(shù)也是如此,其中設(shè)備號(hào)dev是由用戶根據(jù)不同設(shè)備的不同Product ID(PID)號(hào)制定的,這樣,當(dāng)設(shè)備接入系統(tǒng)時(shí),驅(qū)動(dòng)程序就會(huì)根據(jù)其PID號(hào)判斷其設(shè)備號(hào),并將該設(shè)備的nodeld值存放于數(shù)組的特定位置。由于此時(shí)設(shè)備始終處于就緒狀態(tài),用戶可以隨時(shí)對(duì)設(shè)備進(jìn)行讀寫(xiě)操作,而并不存在打開(kāi)設(shè)備的操作。
讀寫(xiě)設(shè)備時(shí),首先要根據(jù)設(shè)備號(hào)dev從設(shè)備列表中查找出設(shè)備,并將其定位到具體的設(shè)備描述符上。在查找設(shè)備時(shí),遍歷設(shè)備列表,就可找到節(jié)點(diǎn)設(shè)備描述符中nodeId與usbd_node_id[dev]相匹配的設(shè)備描述符結(jié)構(gòu)體,并返回該結(jié)構(gòu)體,然后再由設(shè)備描述符結(jié)構(gòu)體得到設(shè)備的資源信息,從而實(shí)現(xiàn)對(duì)設(shè)備的讀寫(xiě)。圖6所示是查找設(shè)備的一個(gè)簡(jiǎn)單流程。
該方法屏蔽了復(fù)雜的驅(qū)動(dòng)程序列表和文件描述符表,從而提供了一種快速定位和訪問(wèn)設(shè)備的方法。這種方法在專用的系統(tǒng)中,對(duì)同類USB設(shè)備的訪問(wèn)是非常高效的,但不具有通用性,也就是說(shuō),對(duì)于不同類別的設(shè)備。則需要另外一套同樣的機(jī)制來(lái)實(shí)現(xiàn)。
3 結(jié)束語(yǔ)
本文提出了一種獨(dú)立于VxWorks I/O系統(tǒng)的USB設(shè)備管理方法。該方法也是一種獨(dú)立于I/O系統(tǒng)的USB設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)模式,它對(duì)于在專用系統(tǒng)中同類USB設(shè)備的管理是非常有效的。通過(guò)對(duì)USB設(shè)備描述符、設(shè)備列表、以及應(yīng)用程序訪問(wèn)設(shè)備流程的設(shè)計(jì),可以成功實(shí)現(xiàn)獨(dú)立于I/O系統(tǒng)的設(shè)備管理方法。這一種方法可以利用驅(qū)動(dòng)程序直接向應(yīng)用系統(tǒng)提供接口函數(shù)和nodeld數(shù)組。從而摒棄了I/O系統(tǒng)中復(fù)雜的驅(qū)動(dòng)程序列表和文件描述符等概念。目前,這種獨(dú)立于VxWorks I/O系統(tǒng)的USB設(shè)備管理方法已在某大型掃描儀中得到應(yīng)用,并取得了一定的經(jīng)濟(jì)效益。
lele