微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ISA总线的DMA技术

ISA总线的DMA技术

时间:05-20 来源:互联网 点击:

型的定义如下:

struct dma_chan {

int lock;

const char *device_id;

};

其中,如果成员lock!=0则表示DMA通道正被某个设备所使用;否则该DMA通道就处于free状态。而成员device_id就指向使用该DMA通道的设备名字字符串。

基于上述结构类型dma_chan,Linux定义了全局数组dma_chan_busy[],以分别描述8个DMA通道资源各自的使用状态。如下:

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 }

};

显然,在初始状态时除了DMA通道4外,其余DMA通道皆处于free状态。

4.2 DMA通道资源的申请

任何ISA卡在使用某个DMA通道进行DMA传输之前,其设备驱动程序都必须向内核提出DMA通道资源的申请。只有申请获得成功后才能使用相应的DMA通道。否则就会发生资源冲突。

函数request_dma()实现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;

}

上述函数的核心实现就是用原子操作xchg()让成员变量dma_chan_busy[dmanr].lock和值1进行交换操作,xchg()将返回lock成员在交换操作之前的值。因此:如果xchg()返回非0值,这说明dmanr所指定的DMA通道已被其他设备所占用,所以request_dma()函数返回错误值-EBUSY表示指定DMA通道正忙;否则,如果xchg()返回0值,说明dmanr所指定的DMA通道正处于free状态,于是xchg()将其lock成员设置为1,取得资源的使用权。

4.3 释放DMA通道资源

DMA传输事务完成后,设备驱动程序一定要记得释放所占用的DMA通道资源。否则别的外设将一直无法使用该DMA通道。

函数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 */

显然,上述函数的核心实现就是用原子操作xchg()将lock成员清零。

4.4 对/proc/dma文件的实现

文件/proc/dma将列出当前8个DMA通道的使用状况。Linux在kernel/Dma.c文件中实现了函数个get_dma_list()函数来至此/proc/dma文件的实现。函数get_dma_list()的实现比较简单。主要就是遍历数组dma_chan_busy[],并将那些lock成员为非零值的数组元素输出到列表中即可。如下:

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进行数据传输的ISA设备驱动程序都必须遵循一定的框架。5.1 DMA通道资源的申请与释放

同I/O端口资源类似,设备驱动程序必须在一开始就调用request_dma()函数来向内核申请DMA通道资源的使用权。而且,最好在设备驱动程序的open()方法中完成这个操作,而不是在模块的初始化例程中调用这个函数。因为这在一定程度上可以让多个设备共享DMA通道资源(只要多个设备不同时使用一个DMA通道)。这种共享有点类似于进程对CPU的分时共享。

设备使用完DMA通道后,其驱动程序应该记得调用free_dma()函数来释放所占用的DMA通道资源。通常,最好再驱动程序的release()方法中调用该函数,而不是在模块的卸载例程中进行调用。

还需要注意的一个问题是:资源的申请顺序。为了避免死锁(deadlock),驱动程序一定要在申请了中断号资源后才申请DMA通道资源。释放时则要先释放DMA通道,然后再释放中断号资源。

使用DMA的ISA设备驱动程序的open()方法的如下:

int xxx_open(struct inode * inode, struct file * filp)

{

if((err = request_irq(irq,xxx_ISR,SA_INTERRUPT,”YourDeviceName”,NULL))

return err;

if((err = request_dma(dmanr, “YourDeviceName”)){

free_irq(irq, NULL);

return err;

}

return 0;

}

release()方法的范例代码如下:

void xxx_release(struct inode * inode, struct file * filp)

{

free_dma(dmanr);

free_irq(irq,NULL);

}

5.2 申请DMA缓冲区

由于8237 DMAC只能寻址系

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top