これを行うには、単純な char デバイス ドライバーを作成できます。
内部ドライバー (疑似コード):
static ssize_t device_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
{
struct page *page;
dma_addr_t DmaBusAddress;
copy_from_user(addrstr, buf, sizeof(addrstr));
uaddr = simple_strtoul(addrstr, NULL, 0);
/* Get page structure which describes your user space
memory area
*/
res = get_user_pages(...,uaddr,...&page);
/* (optional)Get the kernel virtual address for your user space page
*/
kernel_virtual_address = kmap(page);
DmaBusAddress = dma_map_page(...,page)
/*
or the function below if you use address instead of page
DmaBusAddress = dma_map_single(...kernel_virtual_address,count...);
*/
dev->dma_dir = DMA_TO_DEVICE;/* Write operation */
dev->dma_size = count;
dev->dma_addr = DmaBusAddress;
/* Assume you have already memory map your DMA controller's I/O space
with remap_pfn_range() */
writeRegister(DMA_ADDRESS,dev->dma_addr);
........................
writeRegister(START_DMA_TRANSFER,1); /* enable DMA controller */
}
上記のコードは、ジェネリック DMA レイヤーの使用方法を示しています。
ldd3 からの引用
「IOMMU は、物理メモリがデバイスからアクセス可能なアドレス範囲内に表示されるように調整できます。また、物理的に分散したバッファがデバイスに隣接しているように見える可能性があります。IOMMU を使用するには、一般的な DMA レイヤーを使用する必要があります。virt_to_bus が起動していません。タスクに」
と
「ジェネリック DMA レイヤーは、すべてのアーキテクチャで正しく動作するように細心の注意を払っていますが、適切な動作を行うには、いくつかの規則を順守する必要があります。」
「メモリ マッピングと DMA」の章は、すべての質問に答えるかもしれません。
ここにリンクがあります:
http://free-electrons.com/doc/books/ldd3.pdf