C64x系列DSP/BIOS中設備驅動(dòng)程序的設計
隨著(zhù)新技術(shù)的不斷涌現和DSP實(shí)時(shí)系統的日趨復雜,不同類(lèi)型的外部設備越來(lái)越多。為這些外部設備編寫(xiě)驅動(dòng)程序已經(jīng)成為依賴(lài)操作系統管理硬件的內在要求。但是,由于內存管腳、響應時(shí)間和電源管理等條件的限制,為一個(gè)給定的DSP系統編寫(xiě)設備驅動(dòng)程序有時(shí)候會(huì )很困難。針對設備驅動(dòng)程序開(kāi)發(fā)者遇到的上述難題,TI公司為C64x系列[1]DSP的開(kāi)發(fā)者提供了一種類(lèi)/微型驅動(dòng)模型(class/mini-driver model)[2]。該模型在功能上將設備驅動(dòng)程序分為依賴(lài)硬件層和不依賴(lài)硬件層兩層,兩層之間使用通用接口。實(shí)踐結果表明,采用類(lèi)/微型驅動(dòng)模型進(jìn)行設計后,應用軟件可以復用絕大部分相似設備的驅動(dòng)程序,從而提高驅動(dòng)程序的開(kāi)發(fā)效率。
1 類(lèi)/微型驅動(dòng)模型簡(jiǎn)介
在類(lèi)/微型驅動(dòng)模型中,類(lèi)驅動(dòng)通常用于完成多線(xiàn)程I/O請求的序列化功能和同步功能,同時(shí)對設備實(shí)例進(jìn)行管理。在包括視頻系統I/O和異步I/O的典型實(shí)時(shí)系統中,只有少數的類(lèi)驅動(dòng)需要表示出外部設備的類(lèi)型。
類(lèi)驅動(dòng)通過(guò)每個(gè)外部設備獨有的微型驅動(dòng)對設備進(jìn)行操作。微型驅動(dòng)通過(guò)控制外設的寄存器、內存和中斷資源對外部設備實(shí)現控制。微型驅動(dòng)程序必須將特定的外部設備有效地表示給類(lèi)驅動(dòng)。例如:視頻顯示設備存在一些不同的幀存,應用軟件會(huì )根據不同的I/O操作進(jìn)行幀存的分配,此時(shí)微型驅動(dòng)必須映射視頻顯存,使得類(lèi)驅動(dòng)可以對不連續的內存(分別存放RGB或YUV分量)設計特定的I/O請求。
類(lèi)/微型驅動(dòng)模型允許發(fā)送由開(kāi)發(fā)者定義數據結構的I/O請求包給微型驅動(dòng)來(lái)控制外部設備,此分層結構使設備驅動(dòng)的復用能力得到加強,并且豐富了發(fā)送給微型驅動(dòng)的I/O請求包的結構。
類(lèi)/微型驅動(dòng)模型結構如圖1所示。上層的應用程序不直接控制微型驅動(dòng),而是使用一個(gè)或一個(gè)以上的類(lèi)驅動(dòng)對其進(jìn)行控制。每一個(gè)類(lèi)驅動(dòng)在應用程序代碼中表現為一個(gè)API[3]函數并且通過(guò)微型驅動(dòng)的接口IOM與微型驅動(dòng)進(jìn)行通信。類(lèi)驅動(dòng)使用DSP/BIOS中的API函數實(shí)現諸如同步等的系統服務(wù)。
類(lèi)驅動(dòng)通過(guò)標準的微型驅動(dòng)接口調用微型驅動(dòng)控制硬件設備。到目前為止DSP/BIOS共定義了三種類(lèi)驅動(dòng):流輸入輸出管理模塊(SIO)、管道管理模塊(PIP)和通用輸入輸出模塊(GIO)。在PIP和SIO類(lèi)驅動(dòng)中,調用的API函數已經(jīng)存在于DSP/BIOS的PIP和SIO模塊中。這些API函數需將參數傳給相應的適配模塊(adapter),才能與微型驅動(dòng)交換數據。而在GIO類(lèi)驅動(dòng)中,調用的API函數則直接與微型驅動(dòng)通信(需在CCS2.2以上)。
每一個(gè)微型驅動(dòng)都為類(lèi)驅動(dòng)和DSP/BIOS設備驅動(dòng)管理提供了標準接口。微型驅動(dòng)采用芯片支持庫(Chip Support Library)[4]管理外圍設備的寄存器、內存和中斷資源。
2 類(lèi)驅動(dòng)的編寫(xiě)
SIO和PIP兩個(gè)接口模塊用于支持DSP和外設之間的數據交換。這兩種模塊都可以通過(guò)類(lèi)驅動(dòng)中的適配模塊和微型驅動(dòng)的IOM連接進(jìn)行數據傳輸。SIO的適配模塊稱(chēng)為DIO,PIP的適配模塊稱(chēng)為PIO。
GIO模塊[5]的傳輸模式是基于流輸入輸出模式的同步I/O模式,更適合文件系統I/O。在編寫(xiě)類(lèi)驅動(dòng)時(shí),可以直接調用GIO的讀寫(xiě)API函數,這些函數的接口已經(jīng)內置于微型驅動(dòng)的IOM中。
2.1 SIO模塊和DIO模塊
DSP/BIOS中的SIO模塊為每個(gè)DSP/BIOS線(xiàn)程提供一個(gè)獨立的I/O機制,它支持動(dòng)態(tài)創(chuàng )建。SIO模塊有自己的驅動(dòng)模型,稱(chēng)為DEV。DEV程序和微型驅動(dòng)的編寫(xiě)方法相似,都要實(shí)現函數表中的打開(kāi)、關(guān)閉和緩存管理等函數,然而結構比較復雜。相比之下,DIO模塊可以簡(jiǎn)化SIO模塊和IOM之間的連接,使得通信和同步變得更簡(jiǎn)單。
DIO模塊必須實(shí)現下列基本功能函數:
(1)回調函數 在外設的通道實(shí)例創(chuàng )建結束時(shí),如果微型驅動(dòng)已經(jīng)完成內存分配,那么適配模塊將通過(guò)回調函數通知微型驅動(dòng)待調用函數的地址,同時(shí)回調函數也將通知適配模塊緩存已經(jīng)建立,并最終通知上層應用程序。
(2)傳輸函數 傳輸函數將調用微型驅動(dòng)中的mdSubmitChan函數。微型驅動(dòng)中的mdSubmitChan函數將從適配模塊獲得一塊緩存,并將緩存中的新信息通過(guò)通道實(shí)例通知給中斷服務(wù)程序(ISR)。DIO模塊通過(guò)傳輸函數實(shí)現應用程序與微型驅動(dòng)之間的通信。
2.2 PIP模塊和PIO模塊
DSP/BIOS中PIP模塊提供管理異步I/O的數據管道。每個(gè)管道對象都擁有一塊同樣大小的緩存,這些緩存分別為同樣數量的等長(cháng)小塊。小塊的數量和長(cháng)度在DSP/BIOS中設置。雖然小塊的長(cháng)度是固定的,但應用程序可以把小于這個(gè)長(cháng)度的數據放入緩存小塊中。一個(gè)管道有兩個(gè)結束狀態(tài):寫(xiě)完緩存和讀完緩存。通常,無(wú)論哪個(gè)結束狀態(tài)都會(huì )激活I(lǐng)/O設備。數據通知函數用來(lái)執行讀寫(xiě)同步任務(wù)和通知PIP緩存填滿(mǎn)或清空。寫(xiě)數據時(shí),PIP_alloc函數用來(lái)獲得緩存,PIP_put函數用于將數據寫(xiě)入緩存。寫(xiě)完后,讀數據通知函數notifyReader將被調用。讀數據時(shí),PIP_get函數用來(lái)接收緩存中的數據,PIP_free函數在數據不再被使用時(shí)將緩存清空。清空完后,寫(xiě)數據通知函數notifyWriter將被調用。
PIO模塊通過(guò)PIP模塊從應用程序中獲得緩存,并將獲得的緩存提供給微型驅動(dòng)使用。當微型驅動(dòng)使用完緩存時(shí),PIO模塊還可以將緩存交還給應用程序。
PIO模塊必須實(shí)現下列基本功能函數:
(1)主函數 當應用程序給設備分配緩存時(shí),PIP的緩存管理調用rxPrime和txPrime函數。這兩個(gè)函數調用DSP/BIOS的API函數獲得緩存并提供給微型驅動(dòng)使用。主函數負責給適配模塊和應用程序的緩存分配發(fā)送起始信號。
(2)回調函數 當微型驅動(dòng)已完成內存分配時(shí),適配模塊通過(guò)回調函數rxCallback或txCallback通知微型驅動(dòng)待調用函數的地址,同時(shí)回調函數也通知適配模塊緩存已經(jīng)建立,并最終通知給上層應用程序。
(3)傳輸函數:傳輸函數將調用微型驅動(dòng)中的mdSubmitChan函數。mdSubmitChan函數將從適配模塊中獲得一塊緩存,并將緩存的新信息通過(guò)通道實(shí)例通知給中斷服務(wù)程序(ISR)。PIO模塊通過(guò)傳輸函數實(shí)現應用程序與微型驅動(dòng)之間的通信。
2.3 GIO模塊
GIO模塊在提供必要的同步讀/寫(xiě)API函數及其擴展函數的同時(shí),將代碼和使用數據緩存的大小盡量簡(jiǎn)化。如圖2所示,應用程序可以調用GIO的API函數直接與微型驅動(dòng)的IOM交換數據,這些API函數使得GIO成為了第三種類(lèi)驅動(dòng)。
當調用GIO_create創(chuàng )建一個(gè)外部設備的通道實(shí)例時(shí),GIO在通道實(shí)例中增加了狀態(tài)和I/O請求狀態(tài)結構、IOM數據包(IOM_Packets)及一個(gè)GIO數據對象。GIO創(chuàng )建的通道實(shí)例的數據結構如下:
typedef struct GIO_Obj {
IOM_Fxns *fxns; /* 函數表指針 */
Uns mode; /* 創(chuàng )建模式 */
Uns timeout; /* 超時(shí)時(shí)間 */
IOM_Packet syncPacket; /* 同步時(shí)使用的IOM_Packet */
QUE_Obj freeList; /* 異步I/O隊列 */
Ptr syncObj; /* 同步對象地址 */
Ptr mdChan; /* 通道實(shí)例地址 */
} GIO_Obj, *GIO_Handle;
函數表指針是應用程序和微型驅動(dòng)函數表(fxns)的接口;創(chuàng )建模式包括:輸入(IOM_INPUT)、輸出(IOM_OUTPUT)和雙向(IOM_INOUT);IOM_Packet在類(lèi)驅動(dòng)和微型驅動(dòng)間的異步操作時(shí)使用;同步對象地址指向特定通道的同步信號;通道實(shí)例地址指向微型驅動(dòng)創(chuàng )建的通道實(shí)例。
3 微型驅動(dòng)的設計和實(shí)現
類(lèi)/微型驅動(dòng)模型中的微型驅動(dòng)直接控制外部設備。只要微型驅動(dòng)創(chuàng )建了規定的函數,應用程序就可以方便地通過(guò)DIO適配模塊、PIO適配模塊或(和)GIO類(lèi)驅動(dòng)調用。這些規定的函數包括:通道綁定函數(mdBindDev)、通道創(chuàng )建/刪除函數(mdCreateChan/mdDeleteChan)、I/O請求發(fā)送函數(mdSubmitChan)、中斷服務(wù)函數(ISRs)和設備控制函數(mdControlChan)。這些規定的函數將放入微型驅動(dòng)的函數接口表(IOM_Fxns)中的相應位置,供應用程序通過(guò)適配模塊或GIO類(lèi)驅動(dòng)調用。函數接口表的結構如下:
typedef struct IOM_Fxns
{
IOM_TmdBindDev mdBindDev;
IOM_TmdUnBindDev mdUnBindDev;
IOM_TmdControlChan mdControlChan;
IOM_TmdCreateChan mdCreateChan;
IOM_TmdDeleteChan mdDeleteChan;
IOM_TmdSubmitChan mdSubmitChan;
} IOM_Fxns;
3.1 綁定通道函數
DSP/BIOS設備初始化時(shí)將調用每個(gè)已注冊到微型驅動(dòng)中的綁定函數(mdBindDev)。綁定函數一般要實(shí)現下列功能:根據配置的設備參數和可能存在的全局設備數據初始化外圍設備;掛入中斷服務(wù)函數(ISRs);獲得緩存、McBSPs、McASPs和DMA等資源。
如果微型驅動(dòng)使用多個(gè)外部設備,則DSP/BIOS為每個(gè)外設調用綁定函數。設備參數devid用來(lái)區分設備。如果支持一個(gè)設備,則綁定函數必須檢查是否已經(jīng)有設備綁定。
微型驅動(dòng)如果使用靜態(tài)數據來(lái)減少實(shí)時(shí)處理的動(dòng)態(tài)數據分配,可以使用輸入/輸出數據指針(devp)。輸入/輸出數據指針將傳給通道創(chuàng )建函數(mdCreateChan)。
3.2 通道創(chuàng )建/刪除函數
從應用的觀(guān)點(diǎn)出發(fā),在應用程序和外部設備之間必須有一個(gè)邏輯交流通道用來(lái)交換數據。應用程序通過(guò)微型驅動(dòng)創(chuàng )建一個(gè)或多個(gè)邏輯通道對象作為應用程序的邏輯通道。通道創(chuàng )建函數(mdCreateChan)根據需要創(chuàng )建通道對象并給通道對象設置初始值。通道刪除函數(mdDeleteChan)則刪除已創(chuàng )建好的通道對象。雖然每個(gè)微型驅動(dòng)的通道對象數據結構都略有不同,但有些字段是必須的,如通道模式、等待I/O 包序列和回調函數。以下是一個(gè)常見(jiàn)的通道對象數據結構:
typedef struct ChanObj {
Bool inuse; /*如果為T(mén)RUE,則通道已打開(kāi)*/
Int mode; /*通道模式*/
IOM_Packet *dataPacket; /*I/O 包*/
QUE_Obj pendList; /*等待I/O 包序列*/
Uns *bufptr; /*當前緩存指針*/
Uns bufcnt; /*未處理的緩存數目*/
IOM_TiomCallback cbFxn; /*回調函數*/
Ptr cbArg; /*回調函數參數地址*/
} ChanObj, *ChanHandle;
3.3 I/O請求發(fā)送函數
微型驅動(dòng)中的I/O請求發(fā)送函數(mdSubmitChan)用來(lái)處理IOM_Packet包中的命令字段。根據不同命令字段,微型驅動(dòng)將處理命令或返回錯誤信息(IOM_ENOTIMPL)。
微型驅動(dòng)支持的命令字段有:IOM_READ、IOM_WRITE、IOM_ABORT和IOM_FLUSH。微型驅動(dòng)創(chuàng )建的輸入通道由IOM_READ命令來(lái)執行輸入任務(wù),創(chuàng )建的輸出通道則由IOM_WRITE命令來(lái)執行輸出任務(wù)。要放棄或者刷新已經(jīng)發(fā)送的I/O請求,可以使用IOM_ABORT或IOM_FLUSH命令。當放棄時(shí),I/O請求包隊列中的所有輸入輸出請求都將被放棄。當刷新時(shí),所有的I/O輸出包順序執行,而所有的輸入I/O包都被放棄。
3.4 中斷服務(wù)函數
微型驅動(dòng)的中斷功能就是去處理外部設備的觸發(fā)事件,例如周期性的中斷。中斷通常是表示外設采樣完數據或者處理完數據,也可以用于為DMA提供同步信號,微型驅動(dòng)必須處理這些中斷。通常微型驅動(dòng)中的中斷服務(wù)函數ISRs必須完成以下功能:出列IOM_Packet請求;設置下一次傳送或服務(wù)請求;調用類(lèi)驅動(dòng)的回調函數以保證和應用程序同步,并返回IOM_Packet。
3.5 設備控制函數
微型驅動(dòng)支持的控制操作因不同的外部設備而異。IOM定義了一些通用的控制代碼供驅動(dòng)程序調用。特定設備獨有的控制代碼必須自己編寫(xiě),其特征值必須大于128(IOM_CNTL_USER)。目前IOM支持的通用的控制代碼有:
IOM_CHAN_RESET:將創(chuàng )建的通道實(shí)例重新恢復到初始狀態(tài)。
IOM_CHAN_TIMEDOUT:當應用程序或類(lèi)驅動(dòng)超時(shí)時(shí),此控制代碼將進(jìn)行超時(shí)操作。例如,一個(gè)超時(shí)的IOM_Packet,如果沒(méi)執行回調函數,可能會(huì )被返回類(lèi)驅動(dòng)。
IOM_DEVICE_RESE:外部設備重新恢復到初始狀態(tài),它將影響為這個(gè)外部設備創(chuàng )建的所有通道實(shí)例。
微型驅動(dòng)支持的控制代碼和控制操作必須告訴使用微型驅動(dòng)的應用程序開(kāi)發(fā)者,特別要注明該代碼的針對對象(是針對通道實(shí)例還是針對設備實(shí)例)。例如:改變外設波特率的控制代碼,必須注明是針對某個(gè)通道或者所有通道的,否則容易給應用程序帶來(lái)錯誤。
4 類(lèi)/微型驅動(dòng)模型驅動(dòng)應用實(shí)例——C64x系列DSP/BIOS中PCI設備的驅動(dòng)
4.l 微型驅動(dòng)的設計與編寫(xiě)
(1)設計mdBindDev的部分程序代碼:
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
{
……
QUE_new(device.highPrioQue); /* 建立IOM包隊列 */
QUE_new(device.lowPrioQue);
……
hwiAttrs.ccMask = IRQ_CCMASK_NONE;
/*初始化PCI中斷 */
hwiAttrs.arg = NULL;
IRQ_map(IRQ_EVT_DSPINT, intrId);
HWI_dispatchPlug(intrId, (Fxn)isr, -1, hwiAttrs);
}
(2)設計mdCreateChan的部分程序代碼
static Int mdCreateChan(Ptr *chanp, Ptr devp,String name,Int mode,Ptr chanParams, IOM_Tiom Callback cbFxn, Ptr cbArg)
{
……
chan = MEM_alloc(0, sizeof(ChanObj), 0);
chan->queue = device.highPrioQue; /*通道初始化 */
……
if (device.openCount == 0) {
PCI_intEnable(PCI_EVT_PCIMASTER); /*PCI設備中斷初始化 */
……
IRQ_enable(IRQ_EVT_DSPINT);
}
*chanp = chan; /*返回創(chuàng )建通道 */
}
(3)設計mdSubmitChan的部分程序代碼
static Int mdSubmitChan(Ptr chanp, IOM_Packet *pPacket)
{
ChanHandle chan = (ChanHandle)chanp;/*掛載已創(chuàng )建通道 */
……
req=(C64XX_PCI_Request *)packet->addr;/*I/O請求包地址*/
req->reserved = chan;
……
/*處理讀寫(xiě)請求包 */
if (packet->cmd == IOM_READ || packet->cmd ==IOM_WRITE) {
imask = HWI_disable();
QUE_enqueue(chan->queue, packet)
……
}
……/* 處理其它功能的請求包 */
removePackets(chan, packet->cmd);/*移除已處理的請求包 */
}
中斷服務(wù)函數(ISRs)和設備控制函數(mdControlChan)的結構與以上I/O請求發(fā)送函數(mdSubmitChan)的結構類(lèi)似,本文不再作敘述。
4.2 在DSP/BIOS中注冊微型驅動(dòng)
打開(kāi)DSP/BIOS配置工具,如圖3所示。右鍵點(diǎn)擊User-Defined Devices圖標,選擇插入選項,并重新命名為PCICHAN。右鍵點(diǎn)擊PCICHAN,選擇屬性選項,進(jìn)行注冊,如圖4所示。
4.3 編寫(xiě)類(lèi)驅動(dòng)
本例的類(lèi)驅動(dòng)使用通用輸入輸出模塊,首先右鍵點(diǎn)擊圖3中的GIO Manager,選擇啟動(dòng)GIO。在應用程序中,GIO_create函數使用微型驅動(dòng)PCICHAN來(lái)創(chuàng )建通道實(shí)例,通過(guò)調用GIO_submit函數完成應用程序對PCI設備的讀寫(xiě)操作等。源代碼如下:
(1)創(chuàng )建通道
GIO_Handle pciChan;
C64XX_PCI_Attrs pciChanParam;
C64XX_PCI_Request pciChanRequest;
C64XX_PCI_DevParams pciChanDevParam;
GIO_AppCallback pciChanCallBack;
pciChan= GIO_create('/PCICHAN',IOM_INOUT, status, NULL, NULL);
(2)發(fā)送讀請求包
pciChanRequest.srcAddr = (Ptr)BitsBuffer;
pciChanRequest.dstAddr = (Ptr)m_DspControl.CstartAddr;
pciChanRequest.byteCnt = length+20;
pciChanRequest.options = PCI_WRITE;
pciChanReqSize = sizeof(pciChanRequest);
status = GIO_submit(pciChan,IOM_WRITE,pciChanRequest,pciChanReqSize,NULL);
通過(guò)上述三個(gè)步驟,PCI設備的DSP/BIOS驅動(dòng)設計就基本上完成了。應用程序可以通過(guò)使用類(lèi)驅動(dòng)來(lái)復用PCI設備,這樣極大地提高了驅動(dòng)的工作效率,對PCI外設的控制也大為簡(jiǎn)化了。
參考文獻
1 TMS320C64x Technical Overview. Literature Number: SPRU395B.Texas Instruments Incorporated, January 2001
2 DSP/BIOS Driver Developer’s Guide. Literature Number: SPRU616. Texas Instruments Incorporated,November 2002
3 TMS320C6000 DSP/BIOS Application Programming Interface(API) Reference Guide. Literature Number: SPRU403E.Texas Instruments Incorporated,October 2002
4 TMS320C6000 Chip Support Library API Reference Guide.Literature Number: SPRU401E.Texas Instruments Incorporated,December 2002
5 TMS320C6000 Peripherals Reference Guide.Literature Number:SPRU190D. Texas Instruments Incorporated,February 2001
評論