在使用8237A的时候我发现只初始化了原地址,那么目的地址怎么设置,比如我想让Memory->HardDisk 或 Memory->USB怎么去设置,传送到I/O设备的那个扇区(HardDisk)或哪个端点(USB)啊。
在LDD3中也没有说这个问题,如下:
一个简单的使用DMA 例子 示例:下面是一个简单的使用DMA进行传输的驱动程序,它是一个假想的设备,只列出DMA相关的部分来说明驱动程序中如何使用DMA的。
函数dad_transfer是设置DMA对内存buffer的传输操作函数,它使用流式映射将buffer的虚拟地址转换到物理地址,设置好DMA控制器,然后开始传输数据。 int dad_transfer(struct dad_dev *dev, int write, void *buffer, size_t count) { dma_addr_t bus_addr; unsigned long flags; /* Map the buffer for DMA */ dev->dma_dir = (write ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); dev->dma_size = count; //流式映射,将buffer的虚拟地址转化成物理地址 bus_addr = pci_map_single(dev->pci_dev, buffer, count, dev->dma_dir); dev->dma_addr = bus_addr; //DMA传送的buffer物理地址 //将操作控制写入到DMA控制器寄存器,从而建立起设备 writeb(dev->registers.command, DAD_CMD_DISABLEDMA); //设置传输方向--读还是写 writeb(dev->registers.command, write ? DAD_CMD_WR : DAD_CMD_RD); writel(dev->registers.addr, cpu_to_le32(bus_addr));//buffer物理地址 writel(dev->registers.len, cpu_to_le32(count)); //传输的字节数 //开始激活DMA进行数据传输操作 writeb(dev->registers.command, DAD_CMD_ENABLEDMA); return 0; }
函数dad_open打开设备,此时应申请中断号及DMA通道。 int dad_open (struct inode *inode, struct file *filp) {
struct dad_device *my_device;
// SA_INTERRUPT表示快速中断处理且不支持共享 IRQ 信号线 if ( (error = request_irq(my_device.irq, dad_interrupt, SA_INTERRUPT, "dad", NULL)) ) return error; /* or implement blocking open */
if ( (error = request_dma(my_device.dma, "dad")) ) { free_irq(my_device.irq, NULL); return error; /* or implement blocking open */ }
return 0; }
函数dad_dma_prepare初始化DMA控制器,设置DMA控制器的寄存器的值,为 DMA 传输作准备。 int dad_dma_prepare(int channel, int mode, unsigned int buf, unsigned int count) {
unsigned long flags;
flags = claim_dma_lock(); disable_dma(channel); clear_dma_ff(channel); set_dma_mode(channel, mode); set_dma_addr(channel, virt_to_bus(buf)); set_dma_count(channel, count); enable_dma(channel); release_dma_lock(flags);
return 0; }
这里并没有对外部的I/O设备进行设置,那DMA控制器怎么知道往什么I/O设备传送数据。
是不是每个控制器比如USB,HardDisk都有自己的DMA,其实操作的不是8237A而是对这些设备编程?
|