本文以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嘍