我发现这个代码从互联网上的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 board
我使用“橙子Pi One”板由Linux 3.4.113与“allwinner h3”我发现以下代码从“allwinner h3”文档中的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>
#include <linux/dma/sunxi-dma.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_chan *chan;
dma_cap_mask_t mask;
dma_cookie_t cookie;
struct dma_slave_config config;
struct dma_async_tx_descriptor *tx = NULL;
void *src_buf;
struct completion cmp;
dma_addr_t src_dma;
int status;
printk(KERN_INFO "Loading module \n");
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
dma_cap_set(DMA_CYCLIC, mask);
chan = dma_request_channel(mask, NULL, NULL);
if (!chan)
{
printk("Request channel error\n");
return -EINVAL;
}
src_buf = kmalloc(1024*4, GFP_KERNEL);
if (!src_buf)
{
printk("kmalloc error\n");
dma_release_channel(chan);
return -EINVAL;
}
src_dma = dma_map_single(NULL, src_buf, 1024*4, DMA_TO_DEVICE);
config.direction = DMA_MEM_TO_DEV;
config.src_addr = src_dma;
config.dst_addr = 0x01c;
config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
config.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
config.src_maxburst = 1;
config.dst_maxburst = 1;
config.slave_id = sunxi_slave_id(DRQDST_AUDIO_CODEC, DRQSRC_SDRAM);
dmaengine_slave_config(chan, &config);
tx = dmaengine_prep_dma_cyclic(chan, src_dma, 1024*4, 1024, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if(!tx)
{
printk("chan desc request error\n");
status=-1;
}
init_completion(&cmp);
tx->callback = my_dma_transfer_completed;
tx->callback = NULL;
cookie = dmaengine_submit(tx);
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;
}
else
{
printk("transfer error\n");
}
dmaengine_terminate_all(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("Low Level Driver");
MODULE_LICENSE("GPL");
型
请帮帮我,谢谢
1条答案
按热度按时间xxls0lw81#
对于这一点,没有 * 设备独立 *,一刀切的DMA引擎代码,原因很简单,DMA传输的设置和管理是特定于每个设备的。有些设备只能在一个小的DMA窗口上操作。其他设备能够在整个总线地址空间上进行分散/聚集操作。有些设备的DMA引擎配置有绝对总线地址,一些设备将它们的DMA描述符存储在本地,其它设备将通过辅助收集操作从主机存储器获取DMA描述符,等等。
底线是,没有办法熟悉特定的目标设备,如何在硬件级别上配置其DMA引擎,然后-如果您打算使用Linux DMA引擎-编写粘合代码,将这些放在一起。
你引用的代码是一个如何使用某些CPU上的内存到内存DMA引擎的例子。基本上,这个东西和
memcpy
一样,但是没有使用CPU周期,并且完全在总线地址上操作,而不是虚拟地址空间。