本文以linux2.4,硬件s2410为平台。关于DMA具体操做编程在内核源码目录下 /kernel/arch/arm/mach-s2410/dma.c.linux
这里并不打算讲解dma具体的实现方法,主要想告诉你们如何学会在本身的程序中使用DMA这个功能。编程
使用DMA功能主要涉及如下几个步骤:数组
1,申请DMA资源数据结构
int s2410_request_dma(const char *device_id, dmach_t channel,dma_callback_t write_cb, dma_callback_t read_cb)函数
功能:这个函数的主要就是申请一个空闲的DMA通道,指针
参数:device_id 哪一个硬件须要使用DMA功能,这是一个字符串,具体定义在/kernel/arch/arm/mach-s3c2410/dma.h中,里面有个数组包含了全部的可使用DMA的硬件模块,此处参数,只须要填充下面数组的红色字符串便可,这么没有所有列出,若是用到本身去查。队列
static dma_type_t dma_types[4][5] = {内存
{资源
{ "XDREQ0", XDREQ0_WR_SRC, XDREQ0_WR_DST, XDREQ0_WR_CTL, \字符串
XDREQ0_WR_SRC_CTL, XDREQ0_WR_DST_CTL, \
XDREQ0_RD_SRC, XDREQ0_RD_DST, XDREQ0_RD_CTL, \
XDREQ0_RD_SRC_CTL, XDREQ0_RD_DST_CTL },
{ "UART0", UART0_WR_SRC, UART0_WR_DST, UART0_WR_CTL, \
UART0_WR_SRC_CTL, UART0_WR_DST_CTL, \
UART0_RD_SRC, UART0_RD_DST, UART0_RD_CTL, \
UART0_RD_SRC_CTL, UART0_RD_DST_CTL },
。。。。。。。。。。。
}
channel:要申请的DMA的通道
write_cb:通常在DMA一次操做完成后须要调用一个函数完成一些善后工做,这个参数是个回调参数指针,当DMA完成一次写操做后后调用这个函数。这个函数的定义形式为
static void dmaout_done_callback(void *buf_id, int size)
read_cb:与上一个参数相似,只是这个函数在DMA完成一次读操做后调用。函数定义形式为static void dmain_done_callback(void *buf_id, int size)
2,DMA队列填充,linux对DMA使用一个队列进行管理,咱们在申请了DMA通道之后接下来的工做就是向DMA缓冲区中填充数据,DMA传输数据问题交由linux来处理,使用函数:
int s2410_dma_queue_buffer(dmach_t channel, void *buf_id, dma_addr_t data, int size, int write)
功能:将须要由DMA传输的缓冲区添加到DMA队列中
参数:channel : 刚刚申请到的DMA通道
buf_id: 私有数据结构,能够存听任何数据,dmain_done_callback(void *buf_id, int size)中的参数buf_id,二者是同一个东西。(这是真滴J)
data:缓冲区首地址
size: 缓冲区的大小
write:0 控制DMA是读取操做
1 控制DMA是写入操做
3, DMA缓冲区的申请。若是你们使用上面的函数必定不会操做成功的o(∩_∩)o。那是由于最重要的俺还没告诉你呢! 原来DMA的传输须要物理地址才行,而咱们用一般方法获得的缓冲区都是虚拟地址,为了获得物理地址的缓冲区,咱们须要使用下面这个函数;
void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
功能:申请一块内存空间
参数:gpf:内存分配参数,
size:须要分配的大小
dma_handle:若是分配成功存放,分配空间的物理地址的首地址,没错这个地址才能放到DMA队列中
返回值:返回申请到空间的逻辑地址的首地址
4,使用上面的几个函数就能够完成DMA的传输了(*^__^*) 。天下没有不散的宴席,有合必有分,因此老是要有离别的时候的,当你使用完了DMA简单的说声byebye就能够了,比起什么什么来够简单吧
void s2410_free_dma(dmach_t channel)
功能:释放DMA通道
参数:要释放的DMA通道
void consistent_free(void *vaddr, size_t size, dma_addr_t handle)
功能:释放申请的DMA缓冲区
参数:vaddr 虚拟地址
size 缓冲区大小
handle 物理地址
这样就就能够完美操做DMA了,下面使用一个从IIS驱动中拿出来的例子,实际演示一下
1, s2410_request_dma("I2SSDO", 2, audio_dmaout_done_callback, NULL);
2, dmabuf = consistent_alloc(GFP_KERNEL|GFP_DMA, dmasize, &dmaphys); // 申请DMA缓冲区
3, s2410_dma_queue_buffer(s->dma_ch, (void *) b, dmaphys , b->size, DMA_BUF_WR);
4, s2410_free_dma(2);
5, consistent_free(dmabuf, dmasize, dmaphys);}
基本上使用DMA就是这个过程了,byebye喽