linux下如何用dma从内存传输到设备

问题描述 投票:0回答:1

我从互联网上找到了这段代码,用于 DMA 从内存传输到内存 这段代码工作正常

#include <linux/module.h>
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/slab.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>

void my_dma_transfer_completed(void *param)
{
    struct completion *cmp=(struct completion *)param;
    complete(cmp);
    printk("dma transfer completed callback\n");
}

static int __init dma_init (void)
{
    struct dma_device *dma_dev;
    dma_cap_mask_t mask;
    struct dma_chan *chan;
    struct dma_async_tx_descriptor *chan_desc;
    dma_cookie_t cookie;
    dma_addr_t src_addr,dst_addr;
    u8 *src_buf, *dst_buf;
    struct completion cmp;
    int status;
    
    printk(KERN_INFO "Loading module \n");
    
    dma_cap_zero(mask);
    dma_cap_set(DMA_MEMCPY,mask);
    chan=dma_request_channel(mask,NULL,NULL);
    if(!chan)
    {
        printk("chan request error\n");
        return ENODEV;
    }
    dma_dev = chan->device;
    
    src_buf=dma_alloc_coherent(chan->device->dev,1024,&src_addr,GFP_KERNEL);
    dst_buf=dma_alloc_coherent(chan->device->dev,1024,&dst_addr,GFP_KERNEL);

    memset(src_buf,0x12,1024);
    memset(dst_buf,0x00,1024);
    
    printk("Before %x\n",src_buf[0]);
    printk("Before %x\n",dst_buf[0]);

    chan_desc=dma_dev->device_prep_dma_memcpy(chan,dst_addr,src_addr,1024,DMA_MEM_TO_MEM);
    if(!chan_desc)
    {
        printk("chan desc request error\n");
        status=-1;
        goto free;
    }
    init_completion(&cmp);
    chan_desc->callback=my_dma_transfer_completed;
    chan_desc->callback_param=&cmp;
    cookie=dmaengine_submit(chan_desc);
    
    dma_async_issue_pending(chan);
    if(wait_for_completion_timeout(&cmp,msecs_to_jiffies(3000)) <= 0)
    {
        printk("timout\n");
        status=-1;

    }
    status=dma_async_is_tx_complete(chan,cookie,NULL,NULL); 
    if(status==DMA_SUCCESS)
    {
        printk("complete %d\n",status);
        status=0;
        printk("After %x\n",src_buf[0]);
        printk("After %x\n",dst_buf[0]);
    }
    else
    {
        printk("transfer error\n");
    }
    dmaengine_terminate_all(chan);
    
free:
    dma_free_coherent(chan->device->dev,1024,src_buf,src_addr);
    dma_free_coherent(chan->device->dev,1024,dst_buf,dst_addr);
    
    dma_release_channel(chan);
    return 0; 
} 


static void __exit dma_exit (void) 
{
    printk(KERN_INFO "Exitingg module \n");
}

module_init(dma_init);
module_exit(dma_exit);

MODULE_AUTHOR("Saeed Setareh");
MODULE_DESCRIPTION("DMA");
MODULE_LICENSE("GPL");

但是我需要将数据从内存传输到设备(spi,uart,...)或设备到内存的代码 如何修改上面的代码以将数据从内存传输到设备(spi,uart,...)或设备到内存? linux版本是3.4.113,Orange Pi One板

我没有找到任何将数据从内存传输到设备(spi,uart,...)或设备到内存的代码

linux dma orange-pi
1个回答
0
投票

没有独立于设备、一刀切的 DMA 引擎代码,原因很简单,DMA 传输的设置和管理方式特定于每个设备。某些设备只能在较小的 DMA 窗口上运行。其他的能够在整个总线地址空间上进行分散/聚集操作。一些设备的 DMA 引擎配置有绝对总线地址,其他设备则使用页面大小移位、页面偏移和页面索引的组合。有些设备的 DMA 描述符存储在本地,其他设备将通过辅助收集操作从主机内存等获取 DMA 描述符。

底线是,没有办法熟悉所讨论的特定目标设备,如何在硬件级别配置其 DMA 引擎,然后 - 如果您打算使用 Linux DMA 引擎 - 编写胶水代码来带来这些一起。

您引用的代码是如何使用某些 CPU 上的内存到内存 DMA 引擎的示例。基本上这个东西的作用与

memcpy
相同,但不使用 CPU 周期,并且完全在总线地址上操作,而不是虚拟地址空间。

© www.soinside.com 2019 - 2024. All rights reserved.