linux 簡單的DMA例程


一個簡單的使用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_interrupt是中斷處理函數,當DMA傳輸完時,調用這個中斷函數來取消buffer上的DMA映射,從而讓內核程序可以訪問這個buffer。

void dad_interrupt(int irq, void *dev_id, struct pt_regs *regs)

{

  struct dad_dev *dev = (struct dad_dev *) dev_id;

 

  /* Make sure it's really our device interrupting */

 

  /* Unmap the DMA buffer */   pci_unmap_single(dev->pci_dev, dev->dma_addr, dev->dma_size,        dev->dma_dir);

 

/* Only now is it safe to access the buffer, copy to user, etc. */   ...

}

函數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;

}

在與open 相對應的 close 函數中應該釋放DMA及中斷號。

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

{

  struct dad_device *my_device;   free_dma(my_device.dma);   free_irq(my_device.irq, NULL);   ……

}

函數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;

}

函數dad_dma_isdone用來檢查 DMA 傳輸是否成功結束。

int dad_dma_isdone(int channel) {    int residue;    unsigned long flags = claim_dma_lock ();    residue = get_dma_residue(channel);    release_dma_lock(flags);    return (residue == 0); }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM