2014-05-21 112 views
3

我已經爲傳輸模式下的DMA寫入了一個簡單的設備驅動程序,並啓用了DMA以及中斷。 我使用的硬件是帶有Linux 3.4的omap 4460 pandaboard。啓用了DMA的UART Tx模式

下面我分享了代碼的相關部分。 在打開相:

dma_map = ioremap(UART4_DMA_REG,0x1350); 
    if(dma_map == NULL) { 
     printk(KERN_INFO " unable to io_remap DMA region\n"); 
     return -ENOMEM; 
    } 

    printk(KERN_INFO "DMA mapping successful\n"); 

    irq_val = request_irq(45,uart_handler,IRQF_DISABLED,"uart_int",NULL); 
    if(irq_val) { 
     printk(KERN_INFO "cannot assign the requested irq\n"); 
     return -1; 
    } 
    else { 
     printk(KERN_INFO "Requested irq successful\n"); 
    } 

其中UART4_DMA_REG是DMA的基地址寄存器0x4a056000和請求IRQ是45,其線SDMA的1中斷。 在此UART寄存器初始化和DMA啓用後。 現在用戶調用write函數將100個字節的數據複製到內核空間的緩衝區中。

下面的代碼顯示的寫功能:

ssize_t uart_write(struct file *filp,const char __user *buff, size_t count, loff_t *offp) 
{ 
    int no_of_bytes; 
    int maxbytes; 
    struct device *udevice = &devi; 
    int ret_mask; 

    char *kbuf = kmalloc(100,GFP_KERNEL|GFP_DMA); 
    maxbytes = BUFF_SIZE - *offp; 
    if(count > maxbytes)//overflow of buffer 
     no_of_bytes = maxbytes; 
    else 
     no_of_bytes = count;  
    if(no_of_bytes == 0) 
     printk(KERN_INFO "Nothing is there to write to device\n"); 

    bytes_written = no_of_bytes - copy_from_user(kbuf,buff,no_of_bytes);//copy_from_user()returns remaining bytes. 
    printk(KERN_INFO "Write Completed\n"); 
    Uindex = 0; 
    *offp += bytes_written; 

    ret_mask = dma_set_coherent_mask(udevice,DMA_BIT_MASK(32)); 
    if(!ret_mask) 
     printk(KERN_INFO "set mask success \n"); 
    else 
     printk(KERN_INFO "SET MASK NOT SUCCESS \n"); 

    bus_addr = dma_map_single(udevice,kbuf,size,DMA_TO_DEVICE); 
    printk(KERN_INFO "dma_map_single completed"); 
    dma_init(); 
    return bytes_written; 
} 

dma_init();此函數初始化DMA寄存器,使在軟件觸發模式中的信道。

void dma_init() 
{ 
    unsigned int ccr_val; 
    unsigned int csdp_val; 
    irq_line = 1; //for tx line 1 is considered 
    dma_cha_line = 0; //for tx line 0 is considered 

    /* Interrupt Enabled in DMA4_IRQENABLE_Lj and DMA4_CICRi registers */  
    iowrite32(0x1,(dma_map + 0x0018 + (4 * irq_line)));//to unmask the interrupt DMA4_IRQENABLE_Lj 
    iowrite32(0x8,(dma_map + 0x0088 + (0x60 * dma_cha_line)));//condition to generate interrupt CICR reg 

    /* Set the Read Port & Write Port access in CSDP */ 
    csdp_val = ioread32(dma_map + 0x0090 + (0x60 * dma_cha_line)); 
    csdp_val &= ~(0x3 << 7);//Source 
    csdp_val &= ~(0x3 << 14);//Destination 
    csdp_val &= ~(0x3 << 16);//Writing mode without posted 
    csdp_val &= ~(0x1 << 21);//little endian source 
    csdp_val &= ~(0x1 << 19);//little endian destination 
    csdp_val &= ~(0x1 << 13);//destination not packed 
    csdp_val &= ~(0x1 << 6);//source not packed 
    csdp_val &= ~(0x3);//ES is set to 8 bits  
    iowrite32(csdp_val,(dma_map + 0x0090 + (0x60 * dma_cha_line))); 

    /* CEN register configuration */ 
    iowrite32(100,(dma_map + 0x0094 +(0x60 * dma_cha_line)));//EN is set to 1 

    /* CFN register configuration */ 
    iowrite32(1,(dma_map + 0x0098 +(0x60 * dma_cha_line)));//FN is set to 1 

    /* Set the Channel Source & Destination start address */ 
    iowrite32(bus_addr,(dma_map + 0x009C + (0x60 * dma_cha_line)));//Source 
    iowrite32(io_map,(dma_map + 0x00a0 + (0x60 * dma_cha_line)));//Destination 

    /* CCR configuration */ 
    ccr_val = ioread32(dma_map + 0x0080 + (0x60 * dma_cha_line));  
    /* Set the Read Port & Write Port addressing mode in CCR */ 
    /* 
    ccr_val &= ~(0x3 << 12);//Source - constant address mode 
    ccr_val |= (0x1 << 14);//Destination - post incremented address mode-set 14th bit and clear 15th bit 
    ccr_val &= ~(0x1 << 15);  
    */ 
    ccr_val |= (0x1 << 12);//source - post incremented address mode-set 12th bit and clear 13th bit 
    ccr_val &= ~(0x1 << 13);  
    ccr_val &= ~(0x3 << 14);//destination- constant address mode - clear 14 and 15th bit 
    ccr_val |= (0x1 << 26);//high priority on write 
    ccr_val &= ~(0x1 << 6);//low priority on read 
    ccr_val &= ~(0x1f);//CCR[4:0] 
    ccr_val &= ~(0x3 << 19);//CCR [19:20] to 0 
    ccr_val |= (0x1 << 7);// Set the channel enable bit in CCR 
    iowrite32(ccr_val,(dma_map + 0x0080 + (0x60 * dma_cha_line))); 

    /*CSEI,CSFI,CDEI,CDFI*/ 
    iowrite32(1,(dma_map + 0x00a4 +(0x60 * dma_cha_line))); 
    iowrite32(1,(dma_map + 0x00a8 +(0x60 * dma_cha_line))); 
    iowrite32(1,(dma_map + 0x00ac +(0x60 * dma_cha_line))); 
    iowrite32(1,(dma_map + 0x00b0 +(0x60 * dma_cha_line))); 


    printk(KERN_INFO "DMA registers configured\n"); 
} 

現在的問題是:一旦通道被使能(只是調用dma_init後()),ISR(處理)被調用,進入無限循環。我的ISR應該在寫模式下包含什麼?

+0

您可以添加ISR代碼嗎?另外,你說通道在dma_init()調用後啓用,但在dma_init()之後只有一個返回。 – skrrgwasme

+0

@ScottLawson:謝謝你的回覆。但我已經解決了這些問題。首先,由於這是一個字符設備,所以DMA傳輸必須每個DMA請求發生1個元素。我已經將它配置爲每個DMA請求傳送1塊。其次,按照元素傳輸編程指南,不需要配置DMA4_CEN和DMA4_CFN寄存器。但它只在配置這些寄存器時才起作用。 – ddpd

+0

酷!你應該發佈這個答案並接受它。鼓勵你回答你自己的問題。 – skrrgwasme

回答

4

我在經過如此多的擊中和審判之後,對問題進行了整理。首先,由於這是一個字符設備,所以DMA傳輸必須每個DMA請求發生1個元素。我已經將它配置爲每個DMA請求傳送1塊。其次,按照元素傳輸編程指南,不需要配置DMA4_CEN和DMA4_CFN寄存器。但據觀察,只有在配置了這些寄存器的情況下才能工作