ISA總線的DMA技術
DMA通道是一種系統(tǒng)全局資源。任何ISA外設想要進行DMA傳輸,首先都必須取得某個DMA通道資源的使用權,并在傳輸結束后釋放所使用DMA通道資源。從這個角度看,DMA通道資源是一種共享的獨占型資源。
Linux在kernel/Dma.c文件中實現(xiàn)了對DMA通道資源的管理。
4.1 對DMA通道資源的描述
Linux在kernel/Dma.c文件中定義了數(shù)據(jù)結構dma_chan來描述DMA通道資源。該結構類型的定義如下:
struct dma_chan {
int lock;
const char *device_id;
};
其中,如果成員lock!=0則表示DMA通道正被某個設備所使用;否則該DMA通道就處于free狀態(tài)。而成員device_id就指向使用該DMA通道的設備名字字符串。
基于上述結構類型dma_chan,Linux定義了全局數(shù)組dma_chan_busy[],以分別描述8個DMA通道資源各自的使用狀態(tài)。如下:
static struct dma_chan dma_chan_busy[MAX_DMA_CHANNELS] = {
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 1, cascade },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 }
};
顯然,在初始狀態(tài)時除了DMA通道4外,其余DMA通道皆處于free狀態(tài)。
4.2 DMA通道資源的申請
任何ISA卡在使用某個DMA通道進行DMA傳輸之前,其設備驅動程序都必須向內核提出DMA通道資源的申請。只有申請獲得成功后才能使用相應的DMA通道。否則就會發(fā)生資源沖突。
函數(shù)request_dma()實現(xiàn)DMA通道資源的申請。其源碼如下:
int request_dma(unsigned int dmanr, const char * device_id)
{
if (dmanr >= MAX_DMA_CHANNELS)
return -EINVAL;
if (xchg(dma_chan_busy[dmanr].lock, 1) != 0)
return -EBUSY;
dma_chan_busy[dmanr].device_id = device_id;
/* old flag was 0, now contains 1 to indicate busy */
return 0;
}
上述函數(shù)的核心實現(xiàn)就是用原子操作xchg()讓成員變量dma_chan_busy[dmanr].lock和值1進行交換操作,xchg()將返回lock成員在交換操作之前的值。因此:如果xchg()返回非0值,這說明dmanr所指定的DMA通道已被其他設備所占用,所以request_dma()函數(shù)返回錯誤值-EBUSY表示指定DMA通道正忙;否則,如果xchg()返回0值,說明dmanr所指定的DMA通道正處于free狀態(tài),于是xchg()將其lock成員設置為1,取得資源的使用權。
4.3 釋放DMA通道資源
DMA傳輸事務完成后,設備驅動程序一定要記得釋放所占用的DMA通道資源。否則別的外設將一直無法使用該DMA通道。
函數(shù)free_dma()釋放指定的DMA通道資源。如下:
void free_dma(unsigned int dmanr)
{
if (dmanr >= MAX_DMA_CHANNELS) {
printk(Trying to free DMA%d
, dmanr);
return;
}
if (xchg(dma_chan_busy[dmanr].lock, 0) == 0) {
printk(Trying to free free DMA%d
, dmanr);
return;
}
} /* free_dma */
顯然,上述函數(shù)的核心實現(xiàn)就是用原子操作xchg()將lock成員清零。
4.4 對/proc/dma文件的實現(xiàn)
文件/proc/dma將列出當前8個DMA通道的使用狀況。Linux在kernel/Dma.c文件中實現(xiàn)了函數(shù)個get_dma_list()函數(shù)來至此/proc/dma文件的實現(xiàn)。函數(shù)get_dma_list()的實現(xiàn)比較簡單。主要就是遍歷數(shù)組dma_chan_busy[],并將那些lock成員為非零值的數(shù)組元素輸出到列表中即可。如下:
int get_dma_list(char *buf)
{
int i, len = 0;
for (i = 0 ; i MAX_DMA_CHANNELS ; i++) {
if (dma_chan_busy.lock) {
len += sprintf(buf+len, %2d: %s
,
i,
dma_chan_busy.device_id);
}
}
return len;
} /* get_dma_list */
5 使用DMA的ISA設備驅動程序
DMA雖然是一種硬件機制,但它離不開軟件(尤其是設備驅動程序)的配合。任何使用DMA進行數(shù)據(jù)傳輸?shù)腎SA設備驅動程序都必須遵循一定的框架。
評論