Samsung S3C 系列 SoC 的 DMA 子系統定義了一套完整的操作函數集,涵蓋通道申請/釋放、配置/控制、傳輸排隊、狀態查詢、回調通知等全生命周期。這些接口形成 arch/arm/plat-samsung/include/plat/dma.h,為上層驅動(音頻、LCD、NAND 等)提供統一抽象。本文系統梳理核心枚舉、結構體與函數原型。
s3c2410_dma_buffresultenum s3c2410_dma_buffresult {
S3C2410_RES_OK, // 成功完成
S3C2410_RES_ERR, // 總線/設備錯誤
S3C2410_RES_ABORT // 被主動終止
};
s3c2410_dmasrcenum s3c2410_dmasrc {
S3C2410_DMASRC_HW, // 源為硬件(外設→內存)
S3C2410_DMASRC_MEM, // 源為內存(內存→外設)
S3C_DMA_MEM2MEM, // 內存→內存(雙向)
S3C_DMA_MEM2MEM_SET, // 內存填充
S3C_DMA_MEM2MEM_P, // 硬件輔助內存拷貝
S3C_DMA_PER2PER // 外設→外設
};
s3c2410_chan_openum s3c2410_chan_op {
S3C2410_DMAOP_START, // 啟動通道
S3C2410_DMAOP_STOP, // 停止
S3C2410_DMAOP_PAUSE, // 暫停
S3C2410_DMAOP_RESUME, // 恢復
S3C2410_DMAOP_FLUSH, // 刷新隊列
S3C2410_DMAOP_TIMEOUT, // 內部超時信號
S3C2410_DMAOP_STARTED, // 已啟動通知
S3C2410_DMAOP_ABORT // 異常中止
};
struct s3c2410_dma_client {
char *name; // 驅動名稱,用於調試
};
struct s3c2410_dma_chan; // 前向聲明
// 緩衝完成回調:buf=傳輸緩衝區, size=字節數, result=結果碼
typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *, void *buf, int size, enum s3c2410_dma_buffresult result);
// 通道操作回調:處理 START/STOP 等命令
typedef int (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *, enum s3c2410_chan_op);
| 函數 | 原型 | 功能描述 |
|---|---|---|
| s3c2410_dma_set_opfn | int s3c2410_dma_set_opfn(unsigned int chan, s3c2410_dma_opfn_t rtn); | 註冊通道操作回調 |
| s3c2410_dma_set_buffdone_fn | int s3c2410_dma_set_buffdone_fn(unsigned int chan, s3c2410_dma_cbfn_t rtn); | 註冊傳輸完成回調 |
| s3c2410_dma_request | int s3c2410_dma_request(unsigned int chan, struct s3c2410_dma_client *client, void *dev); | 獨佔申請 DMA 通道 |
| s3c2410_dma_ctrl | int s3c2410_dma_ctrl(unsigned int chan, enum s3c2410_chan_op op); | 改變通道狀態 |
| s3c2410_dma_setflags | int s3c2410_dma_setflags(unsigned int chan, unsigned int flags); | 設置通道標志位 |
| s3c2410_dma_free | int s3c2410_dma_free(unsigned int chan, struct s3c2410_dma_client *client); | 釋放通道(含中止未完成傳輸) |
| s3c2410_dma_enqueue | int s3c2410_dma_enqueue(unsigned int chan, void *id, dma_addr_t data, int size); | 將緩衝區入隊(需 DMA 一致性內存) |
| s3c2410_dma_config | int s3c2410_dma_config(unsigned int chan, int xferunit); | 配置傳輸單元大小 |
| s3c2410_dma_setswap | int s3c2410_dma_setswap(unsigned int chan, unsigned int bytes_swap); | 配置字節交換(大小端轉換) |
| s3c2410_dma_devconfig | int s3c2410_dma_devconfig(unsigned int chan, enum s3c2410_dmasrc source, unsigned long devaddr); | 配置外設地址與傳輸方向 |
| s3c2410_dma_getposition | int s3c2410_dma_getposition(unsigned int chan, dma_addr_t *src, dma_addr_t *dest); | 獲取當前傳輸源/目標地址 |
// 1. 定義客戶端
static struct s3c2410_dma_client my_client = { .name = "my_audio" };
// 2. 申請通道(假設通道 1 用於 I2S TX)
int ret = s3c2410_dma_request(1, &my_client, dev);
if (ret < 0) return ret;
// 3. 註冊回調
s3c2410_dma_set_buffdone_fn(1, my_dma_callback);
s3c2410_dma_set_opfn(1, my_op_callback);
// 4. 配置外設
s3c2410_dma_devconfig(1, S3C2410_DMASRC_MEM, I2S_TX_FIFO_ADDR);
// 5. 配置傳輸參數
s3c2410_dma_config(1, 4); // 32-bit 寬度
// 6. 準備緩衝區(必須 dma_alloc_coherent 或 cache 操作)
void *buf = dma_alloc_coherent(dev, size, &dma_addr, GFP_KERNEL);
// 7. 入隊並啟動
s3c2410_dma_enqueue(1, token, dma_addr, size);
s3c2410_dma_ctrl(1, S3C2410_DMAOP_START);
// 8. 釋放流程
s3c2410_dma_ctrl(1, S3C2410_DMAOP_STOP);
s3c2410_dma_free(1, &my_client);
dma_free_coherent(dev, size, buf, dma_addr);
現代內核(3.0+)推薦使用統一 dmaengine API:
dma_request_chan() / dma_release_chan()dmaengine_prep_slave_single() / dmaengine_submit()dma_async_issue_pending() / dmaengine_terminate_all()S3C DMA 驅動實現 struct dma_device 並註冊到 dmaengine,舊版 s3c2410_dma_* API 通過兼容層映射,新驅動請直接使用 dmaengine 接口。