# HG changeset patch
# Parent 61470dc5e775a696da551b5227663bf2659f8f4b
e1000: start a DMA allocation/mapping abstraction

It currently matches a lot the Linux DMA API but it should be usable by
other OSes too. The Linux DMA API is described at the end of the chapter
15 in the LDD3.

This will be useful to remove Linux specific DMA code from
e1000::set_up_device which should be only device independent code.

diff --git a/rathaxes/samples/e1000/CMakeLists.txt b/rathaxes/samples/e1000/CMakeLists.txt
--- a/rathaxes/samples/e1000/CMakeLists.txt
+++ b/rathaxes/samples/e1000/CMakeLists.txt
@@ -5,6 +5,7 @@
                      log.rti
                      lkm.rti
                      device.rti
+                     dma.rti
                      pci.rti
                      socket.rti
                      ethernet.rti
@@ -12,8 +13,9 @@
                      BLT
                      log.blt
                      lkm.blt
+                     device.blt
+                     dma.blt
                      pci.blt
-                     device.blt
                      socket.blt
                      e1000.blt
                      ethernet.blt)
diff --git a/rathaxes/samples/e1000/dma.blt b/rathaxes/samples/e1000/dma.blt
new file mode 100644
--- /dev/null
+++ b/rathaxes/samples/e1000/dma.blt
@@ -0,0 +1,103 @@
+with DMA, Builtin, LKM, Device
+{
+    template type   DMA::AbstractDMAHandle()
+    {
+        chunk   LKM::includes()
+        {
+            #include <linux/dma-mapping.h>
+        }
+
+        decl    data_types()
+        {
+            dma_addr_t  data;
+        }
+
+        map
+        {
+            k_dma_handle: (dma_addr_t)(${self});
+        }
+    }
+
+    template type   DMA::DMAHandle()
+    {
+        decl    data_types()
+        {
+            ${DMA::AbstractDMAHandle}   data;
+        }
+
+        map
+        {
+            /* XXX: we should use ${DMA::AbstractDMAHandle} here: */
+            dma_handle: (dma_addr_t)(${self});
+        }
+    }
+
+    template type   DMA::AbstractDMADirection()
+    {
+        decl    data_types()
+        {
+            enum dma_data_direction data;
+        }
+
+        map
+        {
+            k_dma_direction: (enum dma_data_direction)(${self});
+        }
+    }
+
+    template type   DMA::DMADirection()
+    {
+        decl    data_types()
+        {
+            RTX_DMA_BIDIRECTIONAL   = DMA_BIDIRECTIONAL,
+            RTX_DMA_TO_DEVICE       = DMA_TO_DEVICE,
+            RTX_DMA_FROM_DEVICE     = DMA_FROM_DEVICE
+        }
+
+        map
+        {
+            /* XXX: we should use ${DMA::AbstractDMADirection} here: */
+            dma_direction: (enum dma_data_direction)(${self});
+        }
+    }
+
+    template sequence   map(Device::AbstractDevice dev, Builtin::symbol buf, Builtin::number size, DMA::DMADirection dir)
+    {
+        chunk  ::CALL()
+        {
+            ((${DMA::DMAHandle})dma_map_single(${dev.k_device}, ${buf}, ${size}, ${dir.dma_direction}));
+        }
+    }
+
+    template sequence   unmap(Device::AbstractDevice dev, DMA::AbstractDMAHandle handle, Builtin::number size, DMA::DMADirection dir)
+    {
+        chunk  ::CALL()
+        {
+            dma_unmap_single(${dev.k_device}, ${handle.k_dma_handle}, ${size}, ${dir.dma_direction});
+        }
+    }
+
+    template sequence   mapping_error(Device::AbstractDevice dev, DMA::AbstractDMAHandle handle)
+    {
+        chunk ::CALL()
+        {
+            dma_mapping_error(${dev.k_device}, ${handle.k_dma_handle});
+        }
+    }
+
+    template sequence   alloc_coherent(Device::AbstractDevice dev, Builtin::number size, DMA::AbstractDMAHandle handle)
+    {
+        chunk  ::CALL()
+        {
+            dma_alloc_coherent(${dev.k_device}, ${size}, &${handle.k_dma_handle}, GFP_KERNEL);
+        }
+    }
+
+    template sequence   free_coherent(Device::AbstractDevice dev, Builtin::number size, Builtin::symbol addr, DMA::AbstractDMAHandle handle)
+    {
+        chunk  ::CALL()
+        {
+            dma_free_coherent(${dev.k_device}, ${size}, ${addr}, ${handle.k_dma_handle});
+        }
+    }
+}
diff --git a/rathaxes/samples/e1000/dma.rti b/rathaxes/samples/e1000/dma.rti
new file mode 100644
--- /dev/null
+++ b/rathaxes/samples/e1000/dma.rti
@@ -0,0 +1,54 @@
+interface DMA : Builtin, LKM, Device
+{
+    provided type   AbstractDMAHandle
+    {
+        chunk       LKM::includes();
+        decl        data_types();
+        attribute   Builtin::symbol.scalar  k_dma_handle;
+    }
+
+    provided type   DMAHandle
+    {
+        decl        data_types();
+        attribute   AbstractDMAHandle.scalar    dma_handle;
+    }
+
+    provided type   AbstractDMADirection
+    {
+        decl        data_types();
+        attribute   Builtin::symbol.scalar  k_dma_direction;
+    }
+
+    provided type   DMADirection
+    {
+        decl        data_types();
+        attribute   AbstractDMADirection.scalar dma_direction;
+    }
+
+    provided sequence   map(Device::AbstractDevice, Builtin::symbol, Builtin::number, DMADirection)
+    {
+        provided chunk  ::CALL(); /* -> DMAHandle */
+    }
+
+    provided sequence   unmap(Device::AbstractDevice, AbstractDMAHandle, Builtin::number, DMADirection)
+    {
+        provided chunk  ::CALL();
+    }
+
+    /* XXX: Until we have a real error handling mechanism: */
+    provided sequence   mapping_error(Device::AbstractDevice, AbstractDMAHandle)
+    {
+        provided chunk  ::CALL(); /* -> != 0 if the mapping failed */
+    }
+
+    provided sequence   alloc_coherent(Device::AbstractDevice, Builtin::number, AbstractDMAHandle)
+    {
+        /* return the addr and the handle via the AbstractDMAHandle ptr: */
+        provided chunk  ::CALL();
+    }
+
+    provided sequence   free_coherent(Device::AbstractDevice, Builtin::number, Builtin::symbol, AbstractDMAHandle)
+    {
+        provided chunk  ::CALL();
+    }
+}
