From: Javier Jalle <javier.ja...@gaisler.com>

---
 c/src/lib/libbsp/sparc/Makefile.am                |    2 +
 c/src/lib/libbsp/sparc/leon2/Makefile.am          |    2 +
 c/src/lib/libbsp/sparc/leon2/preinstall.am        |    4 +
 c/src/lib/libbsp/sparc/leon3/Makefile.am          |    2 +
 c/src/lib/libbsp/sparc/leon3/preinstall.am        |    4 +
 c/src/lib/libbsp/sparc/shared/include/grpci2dma.h |  263 +++
 c/src/lib/libbsp/sparc/shared/pci/grpci2dma.c     | 2060 +++++++++++++++++++++
 7 files changed, 2337 insertions(+)
 create mode 100644 c/src/lib/libbsp/sparc/shared/include/grpci2dma.h
 create mode 100644 c/src/lib/libbsp/sparc/shared/pci/grpci2dma.c

diff --git a/c/src/lib/libbsp/sparc/Makefile.am 
b/c/src/lib/libbsp/sparc/Makefile.am
index f75790a..0691dd4 100644
--- a/c/src/lib/libbsp/sparc/Makefile.am
+++ b/c/src/lib/libbsp/sparc/Makefile.am
@@ -42,9 +42,11 @@ EXTRA_DIST += shared/timer/tlib_ckinit.c
 # PCI bus
 EXTRA_DIST += shared/include/grpci.h
 EXTRA_DIST += shared/include/grpci2.h
+EXTRA_DIST += shared/include/grpci2dma.h
 EXTRA_DIST += shared/include/pcif.h
 EXTRA_DIST += shared/pci/grpci.c
 EXTRA_DIST += shared/pci/grpci2.c
+EXTRA_DIST += shared/pci/grpci2dma.c
 EXTRA_DIST += shared/pci/pcif.c
 EXTRA_DIST += shared/pci/pci_memreg_sparc_le.c
 EXTRA_DIST += shared/pci/pci_memreg_sparc_be.c
diff --git a/c/src/lib/libbsp/sparc/leon2/Makefile.am 
b/c/src/lib/libbsp/sparc/leon2/Makefile.am
index bafa626..8e424d8 100644
--- a/c/src/lib/libbsp/sparc/leon2/Makefile.am
+++ b/c/src/lib/libbsp/sparc/leon2/Makefile.am
@@ -96,9 +96,11 @@ libbsp_a_SOURCES += ../../sparc/shared/timer/tlib.c
 # PCI
 include_bsp_HEADERS += ../../sparc/shared/include/grpci.h
 include_bsp_HEADERS += ../../sparc/shared/include/grpci2.h
+include_bsp_HEADERS += ../../sparc/shared/include/grpci2dma.h
 include_bsp_HEADERS += ../../sparc/shared/include/pcif.h
 include_bsp_HEADERS += include/at697_pci.h
 libbsp_a_SOURCES += ../../sparc/shared/pci/grpci2.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/grpci2dma.c
 libbsp_a_SOURCES += ../../sparc/shared/pci/grpci.c
 libbsp_a_SOURCES += ../../sparc/shared/pci/pcif.c
 libbsp_a_SOURCES +=  ../../sparc/shared/pci/pci_memreg_sparc_le.c
diff --git a/c/src/lib/libbsp/sparc/leon2/preinstall.am 
b/c/src/lib/libbsp/sparc/leon2/preinstall.am
index 873cc17..f249c3c 100644
--- a/c/src/lib/libbsp/sparc/leon2/preinstall.am
+++ b/c/src/lib/libbsp/sparc/leon2/preinstall.am
@@ -129,6 +129,10 @@ $(PROJECT_INCLUDE)/bsp/grpci2.h: 
../../sparc/shared/include/grpci2.h $(PROJECT_I
        $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/grpci2.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/grpci2.h
 
+$(PROJECT_INCLUDE)/bsp/grpci2dma.h: ../../sparc/shared/include/grpci2dma.h 
$(PROJECT_INCLUDE)/bsp/$(dirstamp)
+       $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/grpci2dma.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/grpci2dma.h
+
 $(PROJECT_INCLUDE)/bsp/pcif.h: ../../sparc/shared/include/pcif.h 
$(PROJECT_INCLUDE)/bsp/$(dirstamp)
        $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/pcif.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/pcif.h
diff --git a/c/src/lib/libbsp/sparc/leon3/Makefile.am 
b/c/src/lib/libbsp/sparc/leon3/Makefile.am
index 9a4737c..fe17bf0 100644
--- a/c/src/lib/libbsp/sparc/leon3/Makefile.am
+++ b/c/src/lib/libbsp/sparc/leon3/Makefile.am
@@ -109,9 +109,11 @@ libbsp_a_SOURCES += \
 # PCI
 include_bsp_HEADERS += ../../sparc/shared/include/grpci.h
 include_bsp_HEADERS += ../../sparc/shared/include/grpci2.h
+include_bsp_HEADERS += ../../sparc/shared/include/grpci2dma.h
 include_bsp_HEADERS += ../../sparc/shared/include/pcif.h
 libbsp_a_SOURCES += ../../sparc/shared/pci/grpci.c
 libbsp_a_SOURCES += ../../sparc/shared/pci/grpci2.c
+libbsp_a_SOURCES += ../../sparc/shared/pci/grpci2dma.c
 libbsp_a_SOURCES +=  ../../sparc/shared/pci/pcif.c
 libbsp_a_SOURCES +=  ../../sparc/shared/pci/pci_memreg_sparc_le.c
 libbsp_a_SOURCES +=  ../../sparc/shared/pci/pci_memreg_sparc_be.c
diff --git a/c/src/lib/libbsp/sparc/leon3/preinstall.am 
b/c/src/lib/libbsp/sparc/leon3/preinstall.am
index d9bdf35..b517758 100644
--- a/c/src/lib/libbsp/sparc/leon3/preinstall.am
+++ b/c/src/lib/libbsp/sparc/leon3/preinstall.am
@@ -149,6 +149,10 @@ $(PROJECT_INCLUDE)/bsp/grpci2.h: 
../../sparc/shared/include/grpci2.h $(PROJECT_I
        $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/grpci2.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/grpci2.h
 
+$(PROJECT_INCLUDE)/bsp/grpci2dma.h: ../../sparc/shared/include/grpci2dma.h 
$(PROJECT_INCLUDE)/bsp/$(dirstamp)
+       $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/grpci2dma.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/grpci2dma.h
+
 $(PROJECT_INCLUDE)/bsp/pcif.h: ../../sparc/shared/include/pcif.h 
$(PROJECT_INCLUDE)/bsp/$(dirstamp)
        $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/pcif.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/pcif.h
diff --git a/c/src/lib/libbsp/sparc/shared/include/grpci2dma.h 
b/c/src/lib/libbsp/sparc/shared/include/grpci2dma.h
new file mode 100644
index 0000000..c1a2663
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/grpci2dma.h
@@ -0,0 +1,263 @@
+/*
+ *  GRPCI2 DMA Driver
+ *
+ *  COPYRIGHT (c) 2017
+ *  Cobham Gaisler AB
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ *
+ *  OVERVIEW
+ *  ========
+ *  This driver controls the DMA on the GRPCI2 device, located 
+ *  at an on-chip AMBA.
+ */
+
+#ifndef __GRPCI2DMA_H__
+#define __GRPCI2DMA_H__
+
+#include <stdint.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Error return codes */
+#define GRPCI2DMA_ERR_OK 0
+#define GRPCI2DMA_ERR_WRONGPTR -1
+#define GRPCI2DMA_ERR_NOINIT -2
+#define GRPCI2DMA_ERR_TOOMANY -3
+#define GRPCI2DMA_ERR_ERROR -4
+#define GRPCI2DMA_ERR_STOPDMA -5
+#define GRPCI2DMA_ERR_NOTFOUND -6
+
+/* Size of a dma descriptors */
+#define GRPCI2DMA_BD_CHAN_SIZE 0x10
+#define GRPCI2DMA_BD_DATA_SIZE 0x10
+
+/* Alignment of dma descriptors */
+#define GRPCI2DMA_BD_CHAN_ALIGN 0x10
+#define GRPCI2DMA_BD_DATA_ALIGN 0x10
+
+/* User-helper functions to allocate/deallocate
+ * channel and data descriptors
+ */
+extern void * grpci2dma_channel_new(int number);
+extern void grpci2dma_channel_delete(void * chanbd);
+extern void * grpci2dma_data_new(int number);
+extern void grpci2dma_data_delete(void * databd);
+
+/* Function:
+ *  -grpci2dma_prepare
+ * Description:
+ *  -Prepare a transfer, initializing the required data descriptors
+ * Parameters:
+ *  -pci_start: Where in PCI/remote starts the transfer
+ *  -ahb_start: Where in AHB/local starts the transfer
+ *  -dir: Direction of the transfer (AHBTOPCI or PCITOAHB)
+ *  -endianness: Endianness of the transfer (LITTLEENDIAN or BIGENDIAN)
+ *  -size: Size in bytes of the transfer (the function will calculate if there
+ *  are enough descriptors)
+ *  -databd: Pointer to the data descriptor buffer
+ *  -bdindex: Where in the buffer to start the transfer
+ *  -bdmax: Maximum index for the data descriptor buffer
+ *  -block_size: Size in bytes for each PCI transaction (or block). Guaranteed 
+ *  to be at least smaller that this value. Put 0 to use default.
+ *  Default is maximum, which is 0x10000*4 bytes.
+ * Returns:
+ *  -WRONGPTR: Wrong input parameters
+ *  -TOOMANY: Not enough data descriptors in the buffer
+ *  -value > 0: A positive return value means the number of data descriptors 
+ *  prepared/used in the buffer, starting from index.
+ */
+#define GRPCI2DMA_AHBTOPCI 1
+#define GRPCI2DMA_PCITOAHB 0
+#define GRPCI2DMA_LITTLEENDIAN 1
+#define GRPCI2DMA_BIGENDIAN 0
+extern int grpci2dma_prepare(
+        uint32_t pci_start, uint32_t ahb_start, int dir, int endianness,
+        int size, void * databd, int bdindex, int bdmax, int block_size);
+
+/* Function:
+ *  -grpci2dma_status
+ * Description:
+ *  -Status of an transfer:
+ * Parameters:
+ *  -databd: Pointer to the data descriptor buffer
+ *  -bdindex: Where in the buffer starts the transfer
+ *  -bdsize: Number of descriptors used by the transfer
+ * Returns:
+ *  -WRONGPTR: Wrong input parameters
+ *  -GRPCI2DMA_BD_DATA_STATUS_ERR: If at least one of the descriptors has an
+ *  error
+ *  -GRPCI2DMA_BD_DATA_STATUS_ENABLED: If at least one of the descriptors is
+ *  enabled, which means that the transfer is still not finished.
+ *  -GRPCI2DMA_BD_DATA_STATUS_DISABLED: If all the descriptors are disabled,
+ *  which means that either the transfer finished or it was never prepared.
+ */
+#define GRPCI2DMA_BD_STATUS_DISABLED 0
+#define GRPCI2DMA_BD_STATUS_ENABLED 1
+#define GRPCI2DMA_BD_STATUS_ERR 2
+extern int grpci2dma_status(void *databd, int bdindex, int bdsize);
+
+/* Function Interrupt-Code ISR callback prototype.
+ * arg     - Custom arg provided by user
+ * cid     - Channel ID that got the interrupt
+ * status  - Error status of the DMA core
+ */
+typedef void (*grpci2dma_isr_t)(void *arg, int cid, unsigned int status);
+
+/* Function:
+ *  -grpci2dma_isr_register
+ * Description:
+ *  -Register an ISR for a channel (and enable interrupts if disabled)
+ * Parameters:
+ *  -chan_no: ID of the channel
+ *  -dmaisr: ISR
+ *  -arg: Argument to pass to the ISR when called
+ * Returns:
+ *  -NOINIT: GRPCI2 DMA not initialized
+ *  -WRONGPTR: Wrong input parameters
+ *  -OK (=0): Done
+ */
+extern int grpci2dma_isr_register(
+        int chan_no, grpci2dma_isr_t dmaisr, void *arg);
+
+/* Function:
+ *  -grpci2dma_isr_unregister
+ * Description:
+ *  -Unregister an ISR for a channel (and enable interrupts if disabled)
+ * Parameters:
+ *  -chan_no: ID of the channel
+ * Returns:
+ *  -NOINIT: GRPCI2 DMA not initialized
+ *  -WRONGPTR: Wrong input parameters
+ *  -OK (=0): Done
+ */
+extern int grpci2dma_isr_unregister(int chan_no);
+
+/* Function:
+ *  -grpci2dma_open
+ * Description:
+ *  -Open a channel (and allocate the descriptor if the user does not provide
+ *  one).
+ * Parameters:
+ *  -chan: Descriptor for the channel (must be aligned to 0x10)
+ * Returns:
+ *  -NOINIT: GRPCI2 DMA not initialized
+ *  -TOOMANY: Maximum number of channels already opened.
+ *  -WRONGPTR: Wrong input parameters
+ *  -ERROR: Inconsistent state found in driver
+ *  -value > 0: A positive return value means the id for the channel.
+ */
+extern int grpci2dma_open(void * chan);
+
+/* Function:
+ *  -grpci2dma_close
+ * Description:
+ *  -Stop and close a channel (and deallocate it if the user did not provide a
+ *  pointer when opening it)
+ * Parameters:
+ *  -chan_no: Id of the channel
+ * Returns:
+ *  -NOINIT: GRPCI2 DMA not initialized
+ *  -NOTFOUND: Channel not opened.
+ *  -STOPDMA: Cannot stop channel.
+ *  -WRONGPTR: Wrong input parameters
+ *  -OK (=0): Done.
+ */
+extern int grpci2dma_close(int chan_no);
+
+/* Function:
+ *  -grpci2dma_start
+ * Description:
+ *  -Start a channel
+ * Parameters:
+ *  -chan_no: Id of the channel
+ *  -options: Maximum number of data descriptors to be executed before moving
+ *  to next channel (up to 0x10000)
+ * Returns:
+ *  -NOINIT: GRPCI2 DMA not initialized
+ *  -WRONGPTR: Wrong input parameters
+ *  -ERROR: Inconsistent state found in driver
+ *  -OK (=0): Done.
+ */
+extern int grpci2dma_start(int chan_no, int options);
+
+/* Function:
+ *  -grpci2dma_stop
+ * Description:
+ *  -Start a channel
+ * Parameters:
+ *  -chan_no: Id of the channel
+ * Returns:
+ *  -NOINIT: GRPCI2 DMA not initialized
+ *  -WRONGPTR: Wrong input parameters
+ *  -ERROR: Inconsistent state found in driver
+ *  -OK (=0): Done.
+ */
+extern int grpci2dma_stop(int chan_no);
+
+/* Function:
+ *  -grpci2dma_push
+ * Description:
+ *  -Push a transfer into a channel (already started or not)
+ * Parameters:
+ *  -chan_no: Id of the channel
+ *  -databd: Pointer to the data descriptor buffer
+ *  -bdindex: Where in the buffer starts the transfer
+ *  -bdsize: Number of descriptors used by the transfer
+ * Returns:
+ *  -NOINIT: GRPCI2 DMA not initialized
+ *  -WRONGPTR: Wrong input parameters
+ *  -NOTFOUND: Channel not opened.
+ *  -OK (=0): Done.
+ */
+extern int grpci2dma_push(int chan_no, void *databd, int bdindex, int bdsize);
+
+/* Function:
+ *  -grpci2dma_active
+ * Description:
+ *  -Check if dma is active
+ * Parameters:
+ * Returns:
+ *  -(!=0): Active.
+ *  -(=0): Not active.
+ */
+extern int grpci2dma_active(void);
+
+/* Function:
+ *  -grpci2dma_interrupt_enable
+ * Description:
+ *  -Enable interrupt for a transfer
+ * Parameters:
+ *  -databd: Pointer to the data descriptor buffer
+ *  -bdindex: Where in the buffer starts the transfer
+ *  -bdmax: Upper limit for index. index < bdmax 
+ *  -options: 
+ *      (=GRPCI2DMA_OPTIONS_ALL)=Enable interrupt on all transfer descriptors.
+ *      (=GRPCI2DMA_OPTIONS_ONE)=Enable interrupt on transfer descriptor
+ *              indicated by bdindex.
+ * Returns:
+ *  -NOINIT: GRPCI2 DMA not initialized
+ *  -WRONGPTR: Wrong input parameters
+ *  -ERROR: Inconsistent state found in driver
+ *  -OK (=0): Done.
+ */
+#define GRPCI2DMA_OPTIONS_ALL 1
+#define GRPCI2DMA_OPTIONS_ONE 0
+extern int grpci2dma_interrupt_enable(
+        void *databd, int bdindex, int bdmax, int options);
+
+/* Debug function: print dma channel and associated data descriptors.
+ * Only prints if driver internal DEBUG flag is defined. */
+extern int grpci2dma_print(int chan_no);
+extern int grpci2dma_print_bd(void * data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRPCI2DMA_H__ */
diff --git a/c/src/lib/libbsp/sparc/shared/pci/grpci2dma.c 
b/c/src/lib/libbsp/sparc/shared/pci/grpci2dma.c
new file mode 100644
index 0000000..558f680
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/pci/grpci2dma.c
@@ -0,0 +1,2060 @@
+/*
+ *  GRPCI2 DMA Driver
+ *
+ *  COPYRIGHT (c) 2017
+ *  Cobham Gaisler AB
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <drvmgr/drvmgr.h>
+#include <rtems.h>
+#include <rtems/bspIo.h>  /* for printk */
+#include <bsp.h>
+#include <bsp/grpci2dma.h>
+
+/* This driver has been prepared for SMP operation
+ */
+/* Use interrupt lock privmitives compatible with SMP defined in
+ * RTEMS 4.11.99 and higher.
+ */
+#if (((__RTEMS_MAJOR__ << 16) | (__RTEMS_MINOR__ << 8) | __RTEMS_REVISION__) 
>= 0x040b63)
+
+#include <rtems/score/isrlock.h> /* spin-lock */
+
+/* map via ISR lock: */
+#define SPIN_DECLARE(lock) ISR_LOCK_MEMBER(lock)
+#define SPIN_INIT(lock, name) _ISR_lock_Initialize(lock, name)
+#define SPIN_LOCK(lock, level) _ISR_lock_Acquire_inline(lock, &level)
+#define SPIN_LOCK_IRQ(lock, level) _ISR_lock_ISR_disable_and_acquire(lock, 
&level)
+#define SPIN_UNLOCK(lock, level) _ISR_lock_Release_inline(lock, &level)
+#define SPIN_UNLOCK_IRQ(lock, level) _ISR_lock_Release_and_ISR_enable(lock, 
&level)
+#define SPIN_IRQFLAGS(k) ISR_lock_Context k
+#define SPIN_ISR_IRQFLAGS(k) SPIN_IRQFLAGS(k)
+
+#else
+
+/* maintain single-core compatibility with older versions of RTEMS: */
+#define SPIN_DECLARE(name)
+#define SPIN_INIT(lock, name)
+#define SPIN_LOCK(lock, level)
+#define SPIN_LOCK_IRQ(lock, level) rtems_interrupt_disable(level)
+#define SPIN_UNLOCK(lock, level)
+#define SPIN_UNLOCK_IRQ(lock, level) rtems_interrupt_enable(level)
+#define SPIN_IRQFLAGS(k) rtems_interrupt_level k
+#define SPIN_ISR_IRQFLAGS(k)
+
+#ifdef RTEMS_SMP
+#error SMP mode not compatible with these interrupt lock primitives
+#endif
+
+#endif
+
+/*#define STATIC*/
+#define STATIC static
+
+/*#define INLINE*/
+#define INLINE inline
+
+/*#define UNUSED*/
+#define UNUSED __attribute__((unused))
+
+/*#define DEBUG 1*/
+
+#ifdef DEBUG
+#define DBG(x...) printf(x)
+#else
+#define DBG(x...) 
+#endif
+
+#define BD_CHAN_EN (1<<BD_CHAN_EN_BIT)
+#define BD_CHAN_ID (0x3<<BD_CHAN_ID_BIT)
+#define BD_CHAN_TYPE (0x3<<BD_CHAN_TYPE_BIT)
+#define BD_CHAN_TYPE_DMA (0x1<<BD_CHAN_TYPE_BIT)
+#define BD_CHAN_BDCNT (0xffff<<BD_CHAN_BDCNT_BIT)
+#define BD_CHAN_EN_BIT 31
+#define BD_CHAN_ID_BIT 22
+#define BD_CHAN_TYPE_BIT 20
+#define BD_CHAN_BDCNT_BIT 0
+
+#define BD_DATA_EN (0x1<<BD_DATA_EN_BIT)
+#define BD_DATA_IE (0x1<<BD_DATA_IE_BIT)
+#define BD_DATA_DR (0x1<<BD_DATA_DR_BIT)
+#define BD_DATA_BE (0x1<<BD_DATA_BE_BIT)
+#define BD_DATA_TYPE (0x3<<BD_DATA_TYPE_BIT)
+#define BD_DATA_TYPE_DATA (0x0<<BD_DATA_TYPE_BIT)
+#define BD_DATA_ER (0x1<<BD_DATA_ER_BIT)
+#define BD_DATA_LEN (0xffff<<BD_DATA_LEN_BIT)
+#define BD_DATA_EN_BIT 31
+#define BD_DATA_IE_BIT 30
+#define BD_DATA_DR_BIT 29
+#define BD_DATA_BE_BIT 28
+#define BD_DATA_TYPE_BIT 20
+#define BD_DATA_ER_BIT 19
+#define BD_DATA_LEN_BIT 0
+
+#define DMACTRL_SAFE (0x1<<DMACTRL_SAFE_BIT)
+#define DMACTRL_WCLEAR (0x1fff<<DMACTRL_ERR_BIT)
+#define DMACTRL_ERR (0x1f<<DMACTRL_ERR_BIT)
+#define DMACTRL_CHIRQ (0xff<<DMACTRL_CHIRQ_BIT)
+#define DMACTRL_ERR (0x1f<<DMACTRL_ERR_BIT)
+#define DMACTRL_NUMCH (0x7<<DMACTRL_NUMCH_BIT)
+#define DMACTRL_DIS (0x1<<DMACTRL_DIS_BIT)
+#define DMACTRL_IE (0x1<<DMACTRL_IE_BIT)
+#define DMACTRL_ACT (0x1<<DMACTRL_ACT_BIT)
+#define DMACTRL_EN (0x1<<DMACTRL_EN_BIT)
+
+#define DMACTRL_SAFE_BIT 31
+#define DMACTRL_CHIRQ_BIT 12
+#define DMACTRL_ERR_BIT 7
+#define DMACTRL_NUMCH_BIT 4
+#define DMACTRL_DIS_BIT 2
+#define DMACTRL_IE_BIT 1
+#define DMACTRL_ACT_BIT 3
+#define DMACTRL_EN_BIT 0
+
+/* GRPCI2 DMA does not allow more than 8 DMA chans */
+#define MAX_DMA_CHANS 8
+
+/* GRPCI2 DMA does not allow transfer of more than 0x10000 words */
+#define MAX_DMA_TRANSFER_SIZE (0x10000*4)
+
+/* We use the following limits as default */ 
+#define MAX_DMA_DATA 128
+
+/* Memory and HW Registers Access routines. All 32-bit access routines */
+#define BD_WRITE(addr, val) (*(volatile unsigned int *)(addr) = (unsigned 
int)(val))
+/*#define BD_READ(addr) (*(volatile unsigned int *)(addr))*/
+#define BD_READ(addr) leon_r32_no_cache((unsigned long)(addr))
+#define REG_WRITE(addr, val) (*(volatile unsigned int *)(addr) = (unsigned 
int)(val))
+#define REG_READ(addr) (*(volatile unsigned int *)(addr))
+
+/*
+ * GRPCI2 DMA Channel descriptor
+ */
+struct grpci2_bd_chan {
+       volatile unsigned int ctrl;     /* 0x00 DMA Control */
+       volatile unsigned int nchan;    /* 0x04 Next DMA Channel Address */
+       volatile unsigned int nbd;      /* 0x08 Next Data Descriptor in channel 
*/
+       volatile unsigned int res;      /* 0x0C Reserved */
+};
+
+/*
+ * GRPCI2 DMA Data descriptor
+ */
+struct grpci2_bd_data {
+       volatile unsigned int ctrl;     /* 0x00 DMA Data Control */
+       volatile unsigned int pci_adr;  /* 0x04 PCI Start Address */
+       volatile unsigned int ahb_adr;  /* 0x08 AHB Start address */
+       volatile unsigned int next;     /* 0x0C Next Data Descriptor in channel 
*/
+};
+
+
+/*
+ * GRPCI2 DMA APB Register MAP
+ */
+struct grpci2dma_regs {
+       volatile unsigned int dma_ctrl;         /* 0x00 */
+       volatile unsigned int dma_bdbase;       /* 0x04 */
+       volatile unsigned int dma_chact;        /* 0x08 */
+};
+
+#define DEVNAME_LEN 11
+/*
+ * GRPCI2 DMA Driver private data struture
+ */
+struct grpci2dma_priv {
+       /* DMA control registers */
+       struct grpci2dma_regs   *regs;
+       char devname[DEVNAME_LEN];
+
+       /* Channel info */
+       struct {
+               /* Channel pointer. Indicates the assigned channel 
+                * for a given cid (used as index). NULL if not assigned.
+                */
+               struct grpci2_bd_chan * ptr;
+               /* Is this channel allocated by the driver */
+               int allocated;
+               /* Last added data descriptor for each channel.
+                * This simplifies/speeds up adding data descriptors
+                * to the channel*/
+               struct grpci2_bd_data * lastdata;
+               /* Is this channel active */
+               int active;
+               /* Interrupt-code Handling 
+                * - isr: Holds the ISR for each channel
+                * - isr_arg: Holds the ISR arg for each channel
+                */
+               grpci2dma_isr_t isr;
+               void * isr_arg;
+
+               /* DMA Channel Semaphore */
+               rtems_id sem;
+       } channel[MAX_DMA_CHANS];
+
+       /* Indicates the number of channels. */
+       int nchans;
+
+       /* Indicates the number of active channels. */
+       int nactive;
+
+       /* Indicates if the number of DMA ISR that have been registered 
+        * into the GRPCI2 DRIVER */
+       int isr_registered;
+
+       /* Callback to register the DMA ISR into the GRPCI2 DRIVER */
+       void (*isr_register)( void (*isr)(void*), void * arg);
+
+       /* Spin-lock ISR protection */
+       SPIN_DECLARE(devlock);
+};
+
+/* The GRPCI2 DMA semaphore */
+rtems_id grpci2dma_sem;
+
+/*
+ * GRPCI2 DMA internal prototypes 
+ */
+/* -Descriptor linked-list functions*/
+STATIC int grpci2dma_channel_list_add(struct grpci2_bd_chan * list, 
+               struct grpci2_bd_chan * chan);
+STATIC int grpci2dma_channel_list_remove(struct grpci2_bd_chan * chan);
+STATIC int grpci2dma_data_list_add(struct grpci2_bd_chan * chan, 
+               struct grpci2_bd_data * data, struct grpci2_bd_data * 
last_chan_data);
+STATIC int grpci2dma_data_list_remove(struct grpci2_bd_chan * chan, 
+               struct grpci2_bd_data * data);
+STATIC int grpci2dma_channel_list_foreach(struct grpci2_bd_chan * chan, 
+               int func( struct grpci2_bd_chan * chan), int maxindex);
+STATIC int grpci2dma_data_list_foreach(struct grpci2_bd_data * data, 
+               int func( struct grpci2_bd_data * data), int maxindex);
+
+/* -DMA ctrl access functions */
+STATIC INLINE int grpci2dma_ctrl_init(void);
+STATIC INLINE int grpci2dma_ctrl_start(struct grpci2_bd_chan * chan);
+STATIC INLINE int grpci2dma_ctrl_stop(void);
+STATIC INLINE int grpci2dma_ctrl_resume(void);
+STATIC INLINE unsigned int grpci2dma_ctrl_status(void);
+STATIC INLINE unsigned int grpci2dma_ctrl_base(void);
+STATIC INLINE unsigned int grpci2dma_ctrl_active(void);
+STATIC INLINE int grpci2dma_ctrl_numch_set(int numch);
+STATIC INLINE int grpci2dma_ctrl_interrupt_status(void);
+STATIC INLINE int grpci2dma_ctrl_interrupt_enable(void);
+STATIC INLINE int grpci2dma_ctrl_interrupt_disable(void);
+STATIC INLINE int grpci2dma_ctrl_interrupt_clear(void);
+
+/* -Descriptor access functions */
+STATIC int grpci2dma_channel_bd_init(struct grpci2_bd_chan * chan);
+STATIC int grpci2dma_data_bd_init(struct grpci2_bd_data * data, 
+               uint32_t pci_adr, uint32_t ahb_adr, int dir, int endianness, 
+               int size, struct grpci2_bd_data * next);
+STATIC int grpci2dma_channel_bd_enable(struct grpci2_bd_chan * chan, 
+               unsigned int options);
+STATIC int grpci2dma_channel_bd_disable(struct grpci2_bd_chan * chan);
+STATIC void grpci2dma_channel_bd_set_cid(struct grpci2_bd_chan * chan, 
+               int cid);
+STATIC int grpci2dma_channel_bd_get_cid(struct grpci2_bd_chan * chan);
+STATIC int grpci2dma_data_bd_status(struct grpci2_bd_data *data);
+STATIC int grpci2dma_data_bd_disable(struct grpci2_bd_data *desc);
+STATIC int grpci2dma_data_bd_interrupt_enable(struct grpci2_bd_data * data);
+STATIC struct grpci2_bd_data * grpci2dma_channel_bd_get_data(
+               struct grpci2_bd_chan * chan);
+STATIC void grpci2dma_channel_bd_set_data(struct grpci2_bd_chan * chan, 
+               struct grpci2_bd_data * data);
+STATIC struct grpci2_bd_chan * grpci2dma_channel_bd_get_next(
+               struct grpci2_bd_chan * chan);
+STATIC struct grpci2_bd_data * grpci2dma_data_bd_get_next(
+               struct grpci2_bd_data * data);
+STATIC void grpci2dma_channel_bd_set_next(struct grpci2_bd_chan * chan, 
+               struct grpci2_bd_chan * next);
+STATIC void grpci2dma_data_bd_set_next(struct grpci2_bd_data * data, 
+               struct grpci2_bd_data * next);
+
+/* -Channel functions */
+STATIC int grpci2dma_channel_open(struct grpci2_bd_chan * chan, int cid);
+STATIC int grpci2dma_channel_free_id(void);
+STATIC struct grpci2_bd_chan * grpci2dma_channel_get_active_list(void);
+STATIC int grpci2dma_channel_start(int chan_no, int options);
+STATIC int grpci2dma_channel_stop(int chan_no);
+STATIC int grpci2dma_channel_push(int chan_no, void *dataptr, int index, 
+               int ndata);
+STATIC int grpci2dma_channel_close(int chan_no);
+STATIC int grpci2dma_channel_isr_unregister(int chan_no);
+
+/* -ISR functions*/
+STATIC void grpci2dma_isr(void *arg);
+
+/* -Init function called by GRPCI2*/
+int grpci2dma_init(void * regs, 
+               void isr_register( void (*isr)(void*), void * arg));
+
+
+#ifdef DEBUG
+STATIC int grpci2dma_channel_print(struct grpci2_bd_chan * chan);
+STATIC int grpci2dma_data_print(struct grpci2_bd_data * data);
+#endif
+
+static struct grpci2dma_priv *grpci2dmapriv = NULL;
+
+/* All data linked list must point to a disabled descriptor at the end.
+ * We use this DISABLED_DESCRIPTOR as a list end for all channels.
+ */
+#define ALIGNED __attribute__((aligned(GRPCI2DMA_BD_DATA_ALIGN)))
+static ALIGNED struct grpci2_bd_data disabled_data = {
+       /*.ctrl=*/0,
+       /*.pci_adr=*/0,
+       /*.ahb_adr=*/0,
+       /*.next=*/0
+};
+#define DISABLED_DESCRIPTOR (&disabled_data)
+
+/*** START OF DESCRIPTOR LINKED-LIST HELPER FUNCTIONS ***/
+
+/* This functions adds a channel descriptor to the DMA channel 
+ * linked list. It assumes that someone has check the input 
+ * parameters already.
+ */
+STATIC int grpci2dma_channel_list_add(struct grpci2_bd_chan * list, 
+               struct grpci2_bd_chan * chan)
+{
+       DBG("Adding channel (0x%08x) to GRPCI2 DMA driver\n", (unsigned int) 
chan);
+
+       /* Add channel to the linnked list */
+       if (list == chan) {
+               /* No previous channels. Finish. */
+               return GRPCI2DMA_ERR_OK;
+       } else {
+               /* Get next chan from list */
+               struct grpci2_bd_chan * nchan = 
grpci2dma_channel_bd_get_next(list);
+               /* Close the circular linked list */
+               grpci2dma_channel_bd_set_next(chan,nchan);
+               /* Attach the new channel in the middle */
+               grpci2dma_channel_bd_set_next(list, chan);
+               return GRPCI2DMA_ERR_OK;
+       }
+}
+
+/* This functions removes a channel descriptor from the DMA channel 
+ * linked list. It assumes that someone has check the input 
+ * parameters already.
+ * It returns 0 if successfull. Otherwise,
+ * it can return:
+ * - ERROR: Different causes:
+ *       x Number of channels is corrupted.
+ */
+STATIC int grpci2dma_channel_list_remove(struct grpci2_bd_chan * chan)
+{
+       DBG("Removing channel (0x%08x) from GRPCI2 DMA driver\n",
+                       (unsigned int) chan);
+
+       /* Remove channel from the linnked list */
+       struct grpci2_bd_chan * nchan = grpci2dma_channel_bd_get_next(chan);
+       if (nchan != chan){
+               /* There are more channels */
+               /* Since this is a circular linked list, we need to find last 
channel 
+                * and update the pointer to the next element */
+               /* Use index to avoid having an infinite loop in case of 
corrupted 
+                * channels */
+               struct grpci2_bd_chan * new_first_chan = nchan;
+               struct grpci2_bd_chan * curr_chan;
+               int i=1;
+               while((nchan != chan) && (i<MAX_DMA_CHANS)){
+                       curr_chan = nchan;
+                       nchan = grpci2dma_channel_bd_get_next(curr_chan);
+                       i++;
+               }
+               if (nchan != chan) {
+                       DBG("Maximum DMA channels exceeded. Maybe 
corrupted?\n");
+                       return GRPCI2DMA_ERR_ERROR;
+               } else {
+                       /* Update the pointer */
+                       grpci2dma_channel_bd_set_next(curr_chan, 
new_first_chan);
+                       return GRPCI2DMA_ERR_OK;
+               }
+       }else{
+               /* There are no more channels */
+               return GRPCI2DMA_ERR_OK;
+       }
+}
+
+/* This functions adds a data descriptor to the channel's data 
+ * linked list. The function assumes, that the data descriptor
+ * points to either a DISABLED_DESCRIPTOR or to linked list of
+ * data descriptors that ends with a DISABLED_DESCRIPTOR. 
+ * It returns the number of active data descriptors
+ * if successfull. Otherwise, it can return:
+ * - ERROR: Different causes:
+ *       x Number of channels is corrupted.
+ *       x Last linked list element is not pointing to the first.
+ */
+STATIC int grpci2dma_data_list_add(struct grpci2_bd_chan * chan, 
+               struct grpci2_bd_data * data, struct grpci2_bd_data * 
last_chan_data)
+{
+       DBG("Adding data (0x%08x) to channel (0x%08x)\n", 
+                       (unsigned int) data, (unsigned int) chan);
+
+       /* Add data to the linnked list */
+       /* 1st- Get current data */
+       struct grpci2_bd_data * first_data = 
grpci2dma_channel_bd_get_data(chan);
+       if (first_data == NULL) {
+               /* Channel should always be pointing to a disabled descriptor */
+               DBG("Channel not pointing to disabled descpriptor\n");
+               return GRPCI2DMA_ERR_ERROR;
+       } else if (first_data == DISABLED_DESCRIPTOR){
+               /* No previous data. Assign this one and finish. */
+               grpci2dma_channel_bd_set_data(chan, data);
+               return GRPCI2DMA_ERR_OK;
+       } else {
+               /* Let's add the data to the last data pointer added to this 
channel */
+               /* Attach the new data */
+               grpci2dma_data_bd_set_next(last_chan_data, data);
+               /* 2nd- Let's check again to make sure that the DMA did not 
finished
+                * while we were inserting the new data */
+               first_data = grpci2dma_channel_bd_get_data(chan);
+               if (first_data == DISABLED_DESCRIPTOR){
+                       grpci2dma_channel_bd_set_data(chan, data);
+               }
+               return GRPCI2DMA_ERR_OK;
+       }
+}
+
+/* This functions removes a data descriptor from the channel's data 
+ * linked list. Note that in a normal execution, the DMA will remove 
+ * the data descriptors from the linked list, so there is no need to
+ * use this function. It returns 0 if successfull. Otherwise, 
+ * it can return:
+ * - WRONGPTR: The chan (or data) pointer is either NULL or not aligned to
+ *      0x10.
+ * - STOPDMA: The DMA is running, cannot add channels while DMA is running.
+ * - TOOMANY: The max number of data is reached.
+ * - ERROR: Different causes:
+ *       x There are no free channel id numbers.
+ *       x Number of channels is corrupted.
+ *       x Last linked list element is not pointing to the first.
+ */
+UNUSED STATIC int grpci2dma_data_list_remove(struct grpci2_bd_chan * chan, 
+               struct grpci2_bd_data * data)
+{
+       DBG("Removing data (0x%08x) from channel (0x%08x)\n", 
+                       (unsigned int) data, (unsigned int) chan);
+
+       /* Remove data from the linked list */
+       /* 1st- Get current DMA data */
+       struct grpci2_bd_data * first_data = 
grpci2dma_channel_bd_get_data(chan);
+       if (first_data == NULL) {
+               /* Channel should always be pointing to a disabled descriptor */
+               DBG("Channel not pointing to disabled descpriptor\n");
+               return GRPCI2DMA_ERR_ERROR;
+       } else if (first_data == DISABLED_DESCRIPTOR){
+               /* No previous data. Cannot detach */
+               DBG("No data to detach.\n");
+               return GRPCI2DMA_ERR_NOTFOUND;
+       } else {
+               /* 2nd- Already available data, let's find the data */
+               if (first_data == data) {
+                       /* 3rd- It is the first one. */
+                       struct grpci2_bd_data *current = first_data;
+                       struct grpci2_bd_data *next = 
grpci2dma_data_bd_get_next(current);
+                       if (next != DISABLED_DESCRIPTOR){
+                               /* There are more data */
+                               /* Set channel next data descriptor to data*/
+                               grpci2dma_channel_bd_set_data(chan, next);
+                               /* Update the removed data */
+                               grpci2dma_data_bd_set_next(data, 
DISABLED_DESCRIPTOR);
+                               return GRPCI2DMA_ERR_OK;
+                       }else{
+                               /* No more data */
+                               /* Clear DMA NBD */
+                               grpci2dma_channel_bd_set_data(chan, 
DISABLED_DESCRIPTOR);
+                               /* Update the removed data */
+                               grpci2dma_data_bd_set_next(data, 
DISABLED_DESCRIPTOR);
+                               return GRPCI2DMA_ERR_OK;
+                       }
+               } else {
+                       /* It is not the first data. Let's find it */
+                       struct grpci2_bd_data * current = first_data;
+                       struct grpci2_bd_data * next = 
grpci2dma_data_bd_get_next(current);
+                       while( (next != data) && (next != DISABLED_DESCRIPTOR) 
&& 
+                                       (next != NULL)){
+                               current = next;
+                               next = grpci2dma_data_bd_get_next(current);
+                       }
+                       if (next != data) {
+                               DBG("Maximum DMA data exceeded. Maybe 
corrupted?\n");
+                               return GRPCI2DMA_ERR_NOTFOUND;
+                       } else {
+                               /* Detach the data */
+                               next = grpci2dma_data_bd_get_next(data);
+                               grpci2dma_data_bd_set_next(current, next);
+                               /* Update the removed data */
+                               grpci2dma_data_bd_set_next(data, 
DISABLED_DESCRIPTOR);
+                               return GRPCI2DMA_ERR_OK;
+                       }
+               }
+       }
+}
+
+/* Iterate through all channel starting in FIRST_CHAN up to MAXINDEX 
+ * and execute FUNC*/
+UNUSED STATIC int grpci2dma_channel_list_foreach(
+               struct grpci2_bd_chan * first_chan, 
+               int func( struct grpci2_bd_chan * chan), int maxindex)
+{
+       if (maxindex <= 0) return 0;
+       if (first_chan == NULL) {
+               /* No previous channels */
+               return 0;
+       } else {
+               /* Available channels */
+               /* Iterate through next channels */
+               /* Use index to avoid having an infinite loop in case of 
corrupted
+                * channels */
+               int i=0;
+               int ret;
+               struct grpci2_bd_chan * curr_chan = first_chan;
+               struct grpci2_bd_chan * nchan;
+               do{
+                       if (curr_chan == NULL) return GRPCI2DMA_ERR_WRONGPTR;
+                       ret = func(curr_chan);
+                       if (ret < 0){
+                               /* error */
+                               return ret;
+                       }
+                       nchan = grpci2dma_channel_bd_get_next(curr_chan);
+                       curr_chan = nchan;
+                       i++;
+               }while((curr_chan != first_chan) && (i < maxindex));
+       }
+       return 0;
+}
+
+/* Iterate through all data starting in FIRST_DATA up to MAXINDEX 
+ * and execute FUNC*/
+STATIC int grpci2dma_data_list_foreach(struct grpci2_bd_data * first_data, 
+               int func( struct grpci2_bd_data * data), int maxindex)
+{
+       if (maxindex <= 0) return 0;
+       if (first_data == NULL) return GRPCI2DMA_ERR_WRONGPTR;
+       /* Available data */
+       /* Iterate through next data */
+       /* Use index to avoid having an infinite loop in case of corrupted 
+        * channels */
+       int i=0;
+       int ret;
+       struct grpci2_bd_data * curr_data = first_data;
+       struct grpci2_bd_data * ndata;
+       while((curr_data != DISABLED_DESCRIPTOR) && (i < maxindex)){
+               if (curr_data == NULL) return GRPCI2DMA_ERR_WRONGPTR;
+               ret = func(curr_data);
+               if (ret < 0){
+                       /* error */
+                       return ret;
+               }
+               ndata = grpci2dma_data_bd_get_next(curr_data);
+               curr_data = ndata;
+               i++;
+       }
+       return 0;
+}
+
+
+/*** END OF DESCRIPTOR LINKED-LIST HELPER FUNCTIONS ***/
+
+/*** START OF DMACTRL ACCESS FUNCTIONS ***/
+
+/* Initialize the DMA Ctrl*/
+STATIC INLINE int grpci2dma_ctrl_init()
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+
+       /* Clear DMA Control: clear IRQ and ERR status */
+       REG_WRITE(&priv->regs->dma_ctrl, 
0|DMACTRL_SAFE|DMACTRL_CHIRQ|DMACTRL_ERR);
+
+       /* Clear DMA BASE */
+       REG_WRITE(&priv->regs->dma_bdbase, 0);
+
+       /* Clear DMA Chan */
+       REG_WRITE(&priv->regs->dma_chact, 0);
+
+       return 0;
+}
+
+
+/* Stop the DMA */
+STATIC INLINE int grpci2dma_ctrl_stop( void )
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+
+       /* Stop DMA */
+       unsigned int ctrl = REG_READ(&priv->regs->dma_ctrl);
+       REG_WRITE(&priv->regs->dma_ctrl, (ctrl & ~(DMACTRL_WCLEAR | 
DMACTRL_EN)) |
+                       DMACTRL_DIS);
+
+       return 0;
+}
+
+/* Start the DMA */
+STATIC INLINE int grpci2dma_ctrl_start( struct grpci2_bd_chan * chan)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+
+       /* Set BDBASE to linked list of chans */
+       REG_WRITE(&priv->regs->dma_bdbase, (unsigned int) chan);
+
+       /* Start DMA */
+       unsigned int ctrl = REG_READ(&priv->regs->dma_ctrl);
+       REG_WRITE(&priv->regs->dma_ctrl, (ctrl & ~(DMACTRL_WCLEAR | 
DMACTRL_DIS)) |
+                       DMACTRL_EN);
+
+       return 0;
+}
+
+/* Resume the DMA */
+STATIC INLINE int grpci2dma_ctrl_resume( void )
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+
+       /* Resume DMA */
+       unsigned int ctrl = REG_READ(&priv->regs->dma_ctrl);
+       REG_WRITE(&priv->regs->dma_ctrl, (ctrl & ~(DMACTRL_WCLEAR | 
DMACTRL_DIS)) |
+                       DMACTRL_EN);
+
+       return 0;
+}
+
+/* Interrupt status*/
+STATIC INLINE int grpci2dma_ctrl_interrupt_status(void)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+
+       unsigned int ctrl = REG_READ(&priv->regs->dma_ctrl);
+       return (ctrl & DMACTRL_IE);
+}
+
+/* Enable interrupts */
+STATIC INLINE int grpci2dma_ctrl_interrupt_enable(void)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+
+       unsigned int ctrl = REG_READ(&priv->regs->dma_ctrl);
+       if (ctrl & DMACTRL_IE){
+               /* Nothing to do. Already enabled */
+               return 0;
+       }
+
+       /* Clear pending CHIRQ and errors */
+       ctrl = ctrl | (DMACTRL_CHIRQ | DMACTRL_ERR);
+
+       /* Enable interrupts */
+       ctrl = ctrl | DMACTRL_IE;
+
+       REG_WRITE(&priv->regs->dma_ctrl, ctrl );
+       return 0;
+}
+
+/* Disable interrupts */
+STATIC INLINE int grpci2dma_ctrl_interrupt_disable(void)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+
+       unsigned int ctrl = REG_READ(&priv->regs->dma_ctrl);
+       if ((ctrl & DMACTRL_IE) == 0){
+               /* Nothing to do. Already disabled */
+               return 0;
+       }
+
+       /* Clear pending CHIRQ and errors */
+       ctrl = ctrl | (DMACTRL_CHIRQ | DMACTRL_ERR);
+
+       /* Disable interrupts */
+       ctrl = ctrl & ~(DMACTRL_IE);
+
+       REG_WRITE(&priv->regs->dma_ctrl, ctrl );
+       return 0;
+}
+
+/* Clear interrupts */
+STATIC INLINE int grpci2dma_ctrl_interrupt_clear(void)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+
+       unsigned int ctrl = REG_READ(&priv->regs->dma_ctrl);
+       REG_WRITE(&priv->regs->dma_ctrl, (ctrl | DMACTRL_ERR | DMACTRL_CHIRQ));
+       return 0;
+}
+
+STATIC INLINE unsigned int grpci2dma_ctrl_status()
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+
+       /* Read DMA */
+       return (REG_READ(&priv->regs->dma_ctrl));
+}
+
+STATIC INLINE unsigned int grpci2dma_ctrl_base()
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+
+       /* Read DMA */
+       return (REG_READ(&priv->regs->dma_bdbase));
+}
+
+UNUSED STATIC INLINE unsigned int grpci2dma_ctrl_active()
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+
+       /* Read DMA */
+       return (REG_READ(&priv->regs->dma_chact));
+}
+
+/* Set the DMA CTRL register NUMCH field */
+STATIC INLINE int grpci2dma_ctrl_numch_set(int numch)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+
+       unsigned int ctrl = REG_READ(&priv->regs->dma_ctrl);
+
+       /* Clear old value */
+       ctrl = (ctrl & ~(DMACTRL_NUMCH));
+
+       /* Put new value */
+       ctrl = (ctrl | ( (numch << DMACTRL_NUMCH_BIT) & DMACTRL_NUMCH));
+
+       REG_WRITE(&priv->regs->dma_ctrl, ctrl & ~(DMACTRL_WCLEAR));
+       return 0;
+}
+
+/*** END OF DMACTRL ACCESS FUNCTIONS ***/
+
+/*** START OF DESCRIPTOR ACCESS FUNCTIONS ***/
+
+STATIC int grpci2dma_data_bd_init(struct grpci2_bd_data * data, 
+               uint32_t pci_adr, uint32_t ahb_adr, int dir, int endianness, 
int size,
+               struct grpci2_bd_data * next)
+{
+       BD_WRITE(&data->ctrl, 0 |
+                       (BD_DATA_EN) |
+                       (BD_DATA_TYPE_DATA) |
+                       (dir == GRPCI2DMA_AHBTOPCI? BD_DATA_DR:0) |
+                       (endianness == GRPCI2DMA_LITTLEENDIAN? BD_DATA_BE:0) |
+                       ( (size << BD_DATA_LEN_BIT) & BD_DATA_LEN )
+                       );
+       BD_WRITE(&data->pci_adr, pci_adr);
+       BD_WRITE(&data->ahb_adr, ahb_adr);
+       BD_WRITE(&data->next, (unsigned int) next);
+       return 0;
+}
+
+STATIC int grpci2dma_channel_bd_init(struct grpci2_bd_chan * chan)
+{
+       BD_WRITE(&chan->ctrl, 0 | BD_CHAN_TYPE_DMA | BD_CHAN_EN);
+       BD_WRITE(&chan->nchan, (unsigned int) chan);
+       BD_WRITE(&chan->nbd, (unsigned int) DISABLED_DESCRIPTOR);
+       return 0;
+}
+
+/* Enable a channel with options.
+ * options include:
+ * - options & 0xFFFF: Maximum data descriptor count before 
+ *      moving to next DMA channel.
+ */
+STATIC int grpci2dma_channel_bd_enable(struct grpci2_bd_chan * chan, 
+               unsigned int options)
+{
+       unsigned int ctrl = BD_READ(&chan->ctrl);
+       ctrl = (ctrl & ~(BD_CHAN_BDCNT));
+       BD_WRITE(&chan->ctrl, (ctrl | BD_CHAN_EN | 
+                               ( (options << BD_CHAN_BDCNT_BIT) & 
BD_CHAN_BDCNT)));
+       return 0;
+}
+
+/* Disable channel.
+ */
+STATIC int grpci2dma_channel_bd_disable(struct grpci2_bd_chan * chan)
+{
+       unsigned int ctrl = BD_READ(&chan->ctrl);
+       BD_WRITE(&chan->ctrl, (ctrl & ~(BD_CHAN_EN)));
+       return 0;
+}
+
+/* Get the CID of a channel.
+ */
+UNUSED STATIC int grpci2dma_channel_bd_get_cid(struct grpci2_bd_chan * chan)
+{
+       /* Get cid from chan */
+       unsigned ctrl = BD_READ(&chan->ctrl);
+       unsigned cid  = (ctrl & (BD_CHAN_ID)) >> BD_CHAN_ID_BIT;
+       return cid;
+}
+
+/* Set the CID of a channel. */
+STATIC void grpci2dma_channel_bd_set_cid(struct grpci2_bd_chan * chan, int cid)
+{
+       /* Set cid from chan */
+       unsigned ctrl = BD_READ(&chan->ctrl);
+       ctrl = (ctrl & ~(BD_CHAN_ID)) | ((cid << BD_CHAN_ID_BIT) & BD_CHAN_ID);
+       BD_WRITE(&chan->ctrl,ctrl);
+       return;
+}
+
+/* Disable data descriptor*/
+UNUSED STATIC int grpci2dma_data_bd_disable(struct grpci2_bd_data *desc)
+{
+       BD_WRITE(&desc->ctrl,0);
+       return 0;
+}
+
+/* Return status of data descriptor*/
+STATIC int grpci2dma_data_bd_status(struct grpci2_bd_data *desc)
+{
+       int status = BD_READ(&desc->ctrl);
+       if (status & BD_DATA_ER) {
+               return GRPCI2DMA_BD_STATUS_ERR;
+       }else if (status & BD_DATA_EN) {
+               return GRPCI2DMA_BD_STATUS_ENABLED;
+       }else {
+               return GRPCI2DMA_BD_STATUS_DISABLED;
+       }
+       return GRPCI2DMA_BD_STATUS_ERR;
+}
+
+/* Enable interrupts in data descriptor*/
+STATIC int grpci2dma_data_bd_interrupt_enable(struct grpci2_bd_data * data)
+{
+       unsigned int ctrl = BD_READ(&data->ctrl);
+       BD_WRITE(&data->ctrl, ctrl | BD_DATA_IE);
+       return 0;
+}
+
+/* Get data descriptor */
+STATIC struct grpci2_bd_data * grpci2dma_channel_bd_get_data(
+               struct grpci2_bd_chan * chan)
+{
+       return  (struct grpci2_bd_data *) BD_READ(&chan->nbd);
+}
+
+/* Set data descriptorl */
+STATIC void grpci2dma_channel_bd_set_data(struct grpci2_bd_chan * chan, 
+               struct grpci2_bd_data * data)
+{
+       BD_WRITE(&chan->nbd, (unsigned int) data);
+}
+
+/* Get next channel */
+STATIC struct grpci2_bd_chan * grpci2dma_channel_bd_get_next(
+               struct grpci2_bd_chan * chan)
+{
+       return  (struct grpci2_bd_chan *) BD_READ(&chan->nchan);
+}
+
+/* Get next data */
+STATIC struct grpci2_bd_data * grpci2dma_data_bd_get_next(
+               struct grpci2_bd_data * data)
+{
+       return  (struct grpci2_bd_data *) BD_READ(&data->next);
+}
+
+/* Set next channel */
+STATIC void grpci2dma_channel_bd_set_next(struct grpci2_bd_chan * chan, 
+               struct grpci2_bd_chan * next)
+{
+       BD_WRITE(&chan->nchan,(unsigned int) next);
+}
+
+/* Set next data */
+STATIC void grpci2dma_data_bd_set_next(struct grpci2_bd_data * data, 
+               struct grpci2_bd_data * next)
+{
+       BD_WRITE(&data->next,(unsigned int) next);
+}
+
+/*** END OF DESCRIPTOR ACCESS FUNCTIONS ***/
+
+/*** START OF CHANNEL FUNCTIONS ***/
+
+STATIC int grpci2dma_channel_open(struct grpci2_bd_chan * chan, int cid)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       int allocated = 0;
+
+       /* Get pointer */
+       if (chan == NULL) {
+               /* User does not provide channel, let's create it */
+               chan = grpci2dma_channel_new(1);
+               allocated = 1;
+       }else{
+               /* Make sure the pointer is not already on the linked list */
+               int i;
+               for (i=0; i<MAX_DMA_CHANS; i++){
+                       if (priv->channel[i].ptr == chan){
+                               return GRPCI2DMA_ERR_WRONGPTR;
+                       }
+               }
+       }
+
+       DBG("Opening channel %d (0x%08x)\n", cid, (unsigned int) chan);
+
+       /* Init channel descriptor */
+       grpci2dma_channel_bd_init(chan);
+
+       /* Assign cid to chan */
+       priv->channel[cid].ptr = chan;
+       grpci2dma_channel_bd_set_cid(chan, cid);
+
+       /* Increase number of channels */
+       priv->nchans++;
+
+       DBG("number of channels: %d\n", priv->nchans);
+
+       /* Initialize channel data */
+       priv->channel[cid].allocated = allocated;
+       priv->channel[cid].active = 0;
+
+       /* Initialize record of last added data */
+       priv->channel[cid].lastdata = DISABLED_DESCRIPTOR;
+
+       return cid;
+}
+
+/* Get first free CID.
+ */
+STATIC int grpci2dma_channel_free_id()
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+
+       /* Find the first free CID */
+       int i;
+       for (i=0; i<MAX_DMA_CHANS; i++){
+               if (priv->channel[i].ptr == NULL){
+                       return i;
+               }
+       }
+       return GRPCI2DMA_ERR_TOOMANY;
+}
+
+/* Get the active channel circular linked list */
+STATIC struct grpci2_bd_chan * grpci2dma_channel_get_active_list()
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       int i;
+       /* Just get the first non NULL associated cid */
+       for (i=0; i< MAX_DMA_CHANS; i++){
+               if ((priv->channel[i].ptr != NULL) && 
(priv->channel[i].active)){
+                       return priv->channel[i].ptr;
+               }
+       }
+       return NULL;
+}
+
+/* Start a channel */
+STATIC int grpci2dma_channel_start(int chan_no, int options)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       struct grpci2_bd_chan *chan;
+       SPIN_IRQFLAGS(irqflags);
+
+       /* Get chan pointer */
+       chan = priv->channel[chan_no].ptr;
+
+       /* Check if channel is active */
+       if (priv->channel[chan_no].active){
+               /* nothing to do */
+               return GRPCI2DMA_ERR_OK;
+       }
+
+       /* Get the max descriptor count */
+       unsigned int desccnt;
+       if (options == 0){
+               /* Default */
+               desccnt = 0xffff;
+       }else{
+               desccnt = options & 0xffff;
+       }
+
+       /* Start the channel by enabling it.
+        * HWNOTE: In GRPCI2 this bit does not work as it is supposed.
+        * So we better add/remove the channel from the active linked 
+        * list. */
+       grpci2dma_channel_bd_enable(chan, desccnt);
+       priv->channel[chan_no].active = 1;
+       priv->nactive++;
+       /* Get active linked list */
+       struct grpci2_bd_chan * list = grpci2dma_channel_get_active_list();
+       if (list == NULL){
+               /* No previous channels. New list */
+               list = chan;
+       }
+       /* Add channel from the linked list */
+       if (grpci2dma_channel_list_add(list, chan) < 0){
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* Increase NUMCH in DMA ctrl */
+       SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+       grpci2dma_ctrl_numch_set( (priv->nactive? priv->nactive -1:0));
+
+       /* Check if DMA is active */
+       if (!grpci2dma_active()){
+               /* Start DMA */
+               grpci2dma_ctrl_start(chan);
+       }
+       SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+
+       DBG("Channel %d started (0x%08x)\n", chan_no, (unsigned int) chan);
+
+       return GRPCI2DMA_ERR_OK;
+}
+
+/* Stop a channel */
+STATIC int grpci2dma_channel_stop(int chan_no)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       struct grpci2_bd_chan *chan;
+       SPIN_IRQFLAGS(irqflags);
+       int resume;
+
+       /* Get chan pointer */
+       chan = priv->channel[chan_no].ptr;
+
+       /* Check if channel is active */
+       if (!priv->channel[chan_no].active){
+               /* nothing to do */
+               return GRPCI2DMA_ERR_OK;
+       }
+
+       /* First remove channel from the linked list */
+       if (grpci2dma_channel_list_remove(chan) < 0){
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* Update driver struct */
+       priv->channel[chan_no].active = 0;
+       priv->nactive--;
+
+       /* Check if DMA is active and it the removed
+        * channel is the active */
+       resume = 0;
+       SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+       if (grpci2dma_active() && (grpci2dma_ctrl_active() == (unsigned 
int)chan)){
+               /* We need to stop the DMA */
+               grpci2dma_ctrl_stop();
+               SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+               /* Wait until DMA stops */
+               while (grpci2dma_active()){}
+               /* We need to check later to resume the DMA */
+               resume = 1;
+       }else{
+               SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+       }
+
+
+       /* Now either the DMA is stopped, or it is processing 
+        * a different channel and the removed channel is no
+        * longer in the linked list */
+
+       /* Now is safe to update the removed channel */
+       grpci2dma_channel_bd_set_next(chan, chan);
+
+       /* Stop the channel by disabling it. 
+        * HWNOTE: In GRPCI2 this bit does not work as it is supposed.
+        * So we better remove the channel from the active linked 
+        * list. */
+       grpci2dma_channel_bd_disable(chan);
+
+       /* Point channel to disabled descriptor */
+       grpci2dma_channel_bd_set_data(chan, DISABLED_DESCRIPTOR);
+
+       DBG("Channel %d stoped (0x%08x)\n", chan_no, (unsigned int) chan);
+
+       /* Decrease NUMCH in DMA ctrl */
+       SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+       grpci2dma_ctrl_numch_set( (priv->nactive? priv->nactive -1:0));
+
+       /* Reactivate DMA only if we stopped */
+       if (resume){
+               /* We have two options, either we stopped when the active
+                * channel was still the active one, or we stopped when
+                * the active channel was a different one */
+               if (grpci2dma_ctrl_active() == (unsigned int) chan){
+                       /* In this case, we need to start the DMA with
+                        * any active channel on the list */
+                       int i;
+                       for (i=0; i<MAX_DMA_CHANS; i++){
+                               if (priv->channel[i].active){
+                                       
grpci2dma_ctrl_start(priv->channel[i].ptr);
+                                       break;
+                               }
+                       }
+               }else{
+                       /* In this case, we need to resume the DMA operation */
+                       /* HWNOTE: The GRPCI2 core does not update the channel 
next 
+                        * data descriptor if we stopped a channel. This means 
that
+                        * we need to resume the DMA from the descriptor is was,
+                        * by only setting the enable bit, and not changing the 
+                        * base register */
+                       grpci2dma_ctrl_resume();
+               }
+       }
+       SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+
+       return GRPCI2DMA_ERR_OK;
+}
+
+STATIC int grpci2dma_channel_push(int chan_no, void *dataptr, int index,
+               int ndata)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       struct grpci2_bd_chan * chan;
+       struct grpci2_bd_data * data = dataptr;
+
+       /* Get channel */
+       chan = priv->channel[chan_no].ptr;
+
+       DBG("Pushing %d data (starting at 0x%08x) to channel %d (0x%08x)\n",
+                       ndata, (unsigned int) &data[index], chan_no, (unsigned 
int) chan);
+
+       /* Get last added data */
+       struct grpci2_bd_data * last_added = priv->channel[chan_no].lastdata;
+
+       /* Add data to channel */
+       grpci2dma_data_list_add(chan, &data[index], last_added);
+
+       /* Update last added */
+       priv->channel[chan_no].lastdata = &data[index + ndata-1];
+
+       return GRPCI2DMA_ERR_OK;
+}
+
+STATIC int grpci2dma_channel_close(int chan_no)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       struct grpci2_bd_chan * chan;
+
+       /* Get channel */
+       chan = priv->channel[chan_no].ptr;
+
+       DBG("Closing channel %d (0x%08x)\n", chan_no, (unsigned int) chan);
+
+       /* Stop channel */
+       if (grpci2dma_channel_stop(chan_no) != GRPCI2DMA_ERR_OK ){
+               DBG("Cannot stop channel!.\n");
+               return GRPCI2DMA_ERR_STOPDMA;
+       }
+
+       /* Unregister channel ISR */
+       grpci2dma_channel_isr_unregister(chan_no);
+
+       /* Free the cid */
+       priv->channel[chan_no].ptr = NULL;
+
+       /* Remove the ISR */
+       priv->channel[chan_no].isr = NULL;
+       priv->channel[chan_no].isr_arg = NULL;
+
+       /* Deallocate channel if needed */
+       if (priv->channel[chan_no].allocated){
+               grpci2dma_channel_delete((void *)chan);
+       }
+
+       /* Decrease number of channels */
+       priv->nchans--;
+
+       DBG("number of channels: %d\n", priv->nchans);
+
+       /* Everything OK */
+       return GRPCI2DMA_ERR_OK;
+}
+
+/* Register channel ISR */
+STATIC int grpci2dma_channel_isr_unregister(int chan_no)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       SPIN_IRQFLAGS(irqflags);
+
+       /* Unregister channel ISR */
+       priv->channel[chan_no].isr = NULL;
+       priv->channel[chan_no].isr_arg = NULL;
+
+       /* Unregister DMA ISR in GRPCI2 if needed */
+       priv->isr_registered--;
+       if(priv->isr_registered == 0){
+               /* Disable DMA Interrupts */
+               SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+               grpci2dma_ctrl_interrupt_disable();
+               SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+               (priv->isr_register)( NULL, NULL);
+       }
+
+       /* Everything OK */
+       return GRPCI2DMA_ERR_OK;
+}
+
+/*** END OF CHANNEL FUNCTIONS ***/
+
+/*** START OF ISR FUNCTIONS ***/
+
+/* PCI DMA Interrupt handler, called when there is a PCI DMA interrupt */
+STATIC void grpci2dma_isr(void *arg)
+{
+       struct grpci2dma_priv *priv = arg;
+       SPIN_ISR_IRQFLAGS(irqflags);
+       unsigned int ctrl = grpci2dma_ctrl_status();
+       /* Clear Interrupts */
+       SPIN_LOCK(&priv->devlock, irqflags);
+       grpci2dma_ctrl_interrupt_clear();
+       SPIN_UNLOCK(&priv->devlock, irqflags);
+       unsigned int sts = (ctrl & DMACTRL_CHIRQ) >> DMACTRL_CHIRQ_BIT;
+       unsigned int errsts = (ctrl & DMACTRL_ERR);
+
+       /* Error interrupt */
+       if(errsts){
+               /* Find which channels had the error.
+                * The GRPCI2DMA core does not indicate which channel
+                * had the error, so we need to get 1st the base descriptor 
register
+                * and see if it a channel. If is not a channel, then the 
active 
+                * channel register tells us which channel is.
+                * After having the channel we need to find out which channel 
was. */
+               struct grpci2_bd_chan * chan =
+                       (struct grpci2_bd_chan *) grpci2dma_ctrl_base();
+               /* Check if the base is a channel descriptor */
+               if ((BD_READ(&chan->ctrl) & BD_CHAN_TYPE) != BD_CHAN_TYPE_DMA){
+                       /* Is not a channel, so the channel is in the channel 
active 
+                        * register */
+                       chan = (struct grpci2_bd_chan *) 
grpci2dma_ctrl_active();
+               }
+               int i;
+               for (i=0; i<MAX_DMA_CHANS; i++){
+                       if (chan == priv->channel[i].ptr){
+                               /* Found */
+                               if (priv->channel[i].isr != NULL){
+                                       
(priv->channel[i].isr)(priv->channel[i].isr_arg,i,errsts);
+                               }else{
+                                       printk("Unhandled GRPCI2 DMA error 
interrupt, sts:0x%02x\n", errsts);
+                               }
+                               break;
+                       }
+               }
+               if (i == MAX_DMA_CHANS){
+                       printk("Unhandled GRPCI2 DMA error interrupt , 
sts:0x%02x\n", errsts);
+               }
+       }
+
+       /* Normal packet interrupt */
+       int cid=0;
+       /* Find which channels have interrupts */
+       while(sts){
+               /* Find if current channel has an interrupt*/
+               if(sts & 0x1){
+                       /* Find if current channel has an ISR */
+                       if (priv->channel[cid].isr != NULL){
+                               (priv->channel[cid].isr)(
+                                               priv->channel[cid].isr_arg, 
cid, errsts);
+                       }else{
+                               printk("Unhandled GRPCI2 DMA interrupt in 
channel %d, sts:0x%02x\n", cid, 0);
+                       }
+               }
+               /* Next channel */
+               sts = sts >> 1;
+               cid++;
+       }
+}
+
+/*** END OF ISR FUNCTIONS ***/
+
+/*** START OF DEBUG HELPERS ***/
+#ifdef DEBUG
+STATIC int grpci2dma_channel_print(struct grpci2_bd_chan * chan)
+{
+       printf("  GRPCI2 DMA channel descriptor\n");
+       printf("          0x%08x  DMA channel control                           
          0x%08x\n", (unsigned int) chan, chan->ctrl);
+       printf("          31     en                                0x%01x       
          Channel descriptor enable.\n", (chan->ctrl >> 31) & (0x1));
+       printf("          24:22  cid                       0x%01x               
  Channel ID.\n", (chan->ctrl >> 22) & (0x7));
+       printf("          21:20  type                      0x%01x               
  Descriptor type. 01=DMA channel descriptor.\n", (chan->ctrl >> 20) & (0x3)); 
+       printf("          15:0   dlen                   0x%04x             Data 
descriptor count.\n", (chan->ctrl >> 0) & (0xffff));
+       printf("\n");
+       printf("          0x%08x  Next DMA channel                              
                  0x%08x\n", (unsigned int) &(chan->nchan), chan->nchan);
+       printf("          31:0   nc                     0x%08x             Next 
DMA channel.\n", chan->nchan);
+       printf("\n");
+       printf("          0x%08x  Next data descriptor                          
          0x%08x\n" , (unsigned int) &(chan->nbd), chan->nbd);
+       printf("          31:0   nd                     0x%08x             Next 
data descriptor.\n", chan->nbd);
+       printf("\n");
+       return 0;
+}
+
+STATIC int grpci2dma_data_print(struct grpci2_bd_data * data)
+{
+       printf("  GRPCI2 DMA data descriptor\n");
+       printf("          0x%08x  DMA data control                              
                  0x%08x\n", (unsigned int) data, data->ctrl);
+       printf("          31     en                                0x%01x       
          Data descriptor enable.\n" , (data->ctrl >> 31) & (0x1));
+       printf("          30     ie                                0x%01x       
          Interrupt generation enable.\n" , (data->ctrl >> 30) & (0x1));
+       printf("          29     dr                                0x%01x       
          Tranfer direction.\n" , (data->ctrl >> 29) & (0x1));
+       printf("          28     be                                0x%01x       
          Bus endianess.\n" , (data->ctrl >> 28) & (0x1));
+       printf("          21:20  type                      0x%01x               
  Descriptor type. 00=DMA data descriptor.\n" , (data->ctrl >> 20) & (0x3));
+       printf("          19     er                                0x%01x       
          Error status.\n" , (data->ctrl >> 19) & (0x1));
+       printf("          15:0   len                    0x%04x             
Transfer lenght (in words) - 1.\n" ,  (data->ctrl >> 0) & (0xffff));
+       printf("\n");
+       printf("          0x%08x  32-bit PCI start address                      
          0x%08x\n" , (unsigned int) &(data->pci_adr), data->pci_adr);
+       printf("          31:0   pa                     0x%08x             PCI 
address.\n" , data->pci_adr);
+       printf("\n");
+       printf("          0x%08x  32-bit AHB start address                      
          0x%08x\n" , (unsigned int) &(data->ahb_adr), data->ahb_adr);
+       printf("          31:0   aa                     0x%08x             AHB 
address.\n" , data->ahb_adr);
+       printf("\n");
+       printf("          0x%08x  Next data descriptor                          
          0x%08x\n" , (unsigned int) &(data->next), data->next);
+       printf("          31:0   nd                     0x%08x             Next 
data descriptor.\n" , data->next);
+       printf("\n");
+       return 0;
+}
+#endif
+/*** END OF DEBUG HELPERS ***/
+
+/*** START OF MEMORY ALLOCATION FUNCTIONS ***/
+
+void * grpci2dma_channel_new(int number)
+{
+       /* Allocate memory */
+       unsigned int * orig_ptr = (unsigned int *) malloc(
+                       (GRPCI2DMA_BD_CHAN_SIZE)*number + 
GRPCI2DMA_BD_CHAN_ALIGN);
+       if (orig_ptr == NULL) return NULL;
+
+       /* Get the aligned pointer */
+       unsigned int aligned_ptr = (
+               ((unsigned int) orig_ptr + GRPCI2DMA_BD_CHAN_ALIGN) &
+                ~(GRPCI2DMA_BD_CHAN_ALIGN - 1));
+
+       /* Save the original pointer just before the aligned pointer */
+       unsigned int ** tmp_ptr =
+               (unsigned int **) (aligned_ptr - sizeof(orig_ptr));
+       *tmp_ptr= orig_ptr;
+
+       /* Return aligned pointer */
+       return (void *) aligned_ptr;
+}
+
+void grpci2dma_channel_delete(void * chan)
+{
+       /* Recover orignal pointer placed just before the aligned pointer */
+       unsigned int * orig_ptr;
+       unsigned int ** tmp_ptr =  (unsigned int **) (chan - sizeof(orig_ptr));
+       orig_ptr = *tmp_ptr;
+
+       /* Deallocate memory */
+       free(orig_ptr);
+}
+
+void * grpci2dma_data_new(int number)
+{
+       /* Allocate memory */
+       unsigned int * orig_ptr = (unsigned int *) malloc(
+                       (GRPCI2DMA_BD_DATA_SIZE)*number + 
GRPCI2DMA_BD_DATA_ALIGN);
+       if (orig_ptr == NULL) return NULL;
+
+       /* Get the aligned pointer */
+       unsigned int aligned_ptr = (
+               ((unsigned int) orig_ptr + GRPCI2DMA_BD_DATA_ALIGN) & 
+               ~(GRPCI2DMA_BD_DATA_ALIGN - 1));
+
+       /* Save the original pointer before the aligned pointer */
+       unsigned int ** tmp_ptr = 
+               (unsigned int **) (aligned_ptr - sizeof(orig_ptr));
+       *tmp_ptr= orig_ptr;
+
+       /* Return aligned pointer */
+       return (void *) aligned_ptr;
+}
+
+void grpci2dma_data_delete(void * data)
+{
+       /* Recover orignal pointer placed just before the aligned pointer */
+       unsigned int * orig_ptr;
+       unsigned int ** tmp_ptr =  (unsigned int **) (data - sizeof(orig_ptr));
+       orig_ptr = *tmp_ptr;
+
+       /* Deallocate memory */
+       free(orig_ptr);
+}
+
+/*** END OF MEMORY ALLOCATION FUNCTIONS ***/
+
+/*** START OF USER API ***/
+
+/* Initialize GRPCI2 DMA: GRPCI2 DRIVER calls this
+ * using a weak function definition */
+int grpci2dma_init(
+               void * regs, void isr_register( void (*isr)(void*), void * arg))
+{
+       struct grpci2dma_priv *priv;
+       int i;
+
+       DBG("Registering GRPCI2 DMA driver with arg: 0x%08x\n",
+                       (unsigned int) regs);
+
+       /* We only allow one GRPCI2 DMA */
+       if (grpci2dmapriv) {
+               DBG("Driver only supports one PCI DMA core\n");
+               return DRVMGR_FAIL;
+       }
+
+       /* Device Semaphore created with count = 1 */
+       if (rtems_semaphore_create(rtems_build_name('G', 'P', '2', 'D'), 1,
+               RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | \
+               RTEMS_NO_INHERIT_PRIORITY | RTEMS_LOCAL | \
+               RTEMS_NO_PRIORITY_CEILING, 0, &grpci2dma_sem) != 
RTEMS_SUCCESSFUL)
+               return -1;
+
+       /* Allocate and init Memory for DMA */
+       int size = sizeof(struct grpci2dma_priv);
+       priv = (struct grpci2dma_priv *) malloc(size);
+       if (priv == NULL)
+               return DRVMGR_NOMEM;
+
+       /* Initialize all fields */
+       memset(priv, 0, size);
+       priv->regs = regs;
+       strncpy(&priv->devname[0], "grpci2dma0", DEVNAME_LEN);
+
+       /* Initialize Spin-lock for GRPCI2dma Device. */
+       SPIN_INIT(&priv->devlock, priv->devname);
+
+       /* Channel Sempahores */
+       for (i=0; i<MAX_DMA_CHANS; i++){
+               /* set to NULL, they are created when openning channels */
+               priv->channel[i].sem = RTEMS_ID_NONE;
+       }
+
+       /* Register device */
+       grpci2dmapriv = priv;
+
+       /* Initialize Ctrl regs */
+       grpci2dma_ctrl_init();
+
+       /* Install DMA ISR */
+       priv->isr_register = isr_register;
+
+       /* Startup actions:
+        * - stop DMA
+        */
+       grpci2dma_ctrl_stop();
+
+       return DRVMGR_OK;
+}
+
+/* Assign ISR Function to DMA IRQ */
+int grpci2dma_isr_register(int chan_no, grpci2dma_isr_t dmaisr, void *data)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       SPIN_IRQFLAGS(irqflags);
+
+       if (!priv){
+               /* DMA not initialized */
+               return GRPCI2DMA_ERR_NOINIT;
+       }
+
+       /* Check isr */
+       if (dmaisr == NULL){
+               /* No ISR */
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Get chan pointer */
+       if ((chan_no < 0 ) || (chan_no >= MAX_DMA_CHANS)) {
+               /* Wrong channel id */
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Check chan is open */
+       if (priv->channel[chan_no].ptr == NULL){
+               /* No channel */
+               return GRPCI2DMA_ERR_NOTFOUND;
+       }
+
+       /* Take driver lock - Wait until we get semaphore */
+       if (rtems_semaphore_obtain(grpci2dma_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+               != RTEMS_SUCCESSFUL){
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* Take channel lock - Wait until we get semaphore */
+       if (rtems_semaphore_obtain(priv->channel[chan_no].sem, RTEMS_WAIT, 
RTEMS_NO_TIMEOUT)
+               != RTEMS_SUCCESSFUL){
+               rtems_semaphore_release(grpci2dma_sem);
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* Register channel ISR */
+       priv->channel[chan_no].isr_arg = data;
+       priv->channel[chan_no].isr = dmaisr;
+
+       /* Register DMA ISR in GRPCI2 if not done yet */
+       if(priv->isr_registered == 0){
+               (priv->isr_register)( grpci2dma_isr, (void *) priv);
+               /* Enable DMA Interrupts */
+               SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+               grpci2dma_ctrl_interrupt_enable();
+               SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+       }
+       priv->isr_registered++;
+
+       /* Release channel sempahore */
+       rtems_semaphore_release(priv->channel[chan_no].sem);
+
+       /* Release driver sempahore */
+       rtems_semaphore_release(grpci2dma_sem);
+
+       return GRPCI2DMA_ERR_OK;
+}
+
+/* Assign ISR Function to DMA IRQ */
+int grpci2dma_isr_unregister(int chan_no)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       int ret;
+
+       if (!priv){
+               /* DMA not initialized */
+               return GRPCI2DMA_ERR_NOINIT;
+       }
+
+       /* Get chan pointer */
+       if ((chan_no < 0 ) || (chan_no >= MAX_DMA_CHANS)) {
+               /* Wrong channel id */
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Check chan is open */
+       if (priv->channel[chan_no].ptr == NULL){
+               /* No channel */
+               return GRPCI2DMA_ERR_NOTFOUND;
+       }
+
+       /* Get chan ISR */
+       if (priv->channel[chan_no].isr == NULL){
+               /* Nothing to do */
+               return GRPCI2DMA_ERR_OK;
+       }
+
+       /* Take driver lock - Wait until we get semaphore */
+       if (rtems_semaphore_obtain(grpci2dma_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+               != RTEMS_SUCCESSFUL){
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* Take channel lock - Wait until we get semaphore */
+       if (rtems_semaphore_obtain(priv->channel[chan_no].sem, RTEMS_WAIT, 
RTEMS_NO_TIMEOUT)
+               != RTEMS_SUCCESSFUL){
+               rtems_semaphore_release(grpci2dma_sem);
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* Unregister channel ISR */
+       ret = grpci2dma_channel_isr_unregister(chan_no);
+
+       /* Release channel sempahore */
+       rtems_semaphore_release(priv->channel[chan_no].sem);
+
+       /* Release driver sempahore */
+       rtems_semaphore_release(grpci2dma_sem);
+
+       return ret;
+}
+
+int grpci2dma_open(void * chanptr)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       int cid;
+       int ret;
+
+       if (!priv){
+               /* DMA not initialized */
+               return GRPCI2DMA_ERR_NOINIT;
+       }
+
+       /* Check alignment */
+       if (((unsigned int ) chanptr) & (GRPCI2DMA_BD_CHAN_ALIGN-1)) {
+               /* Channel is not properly aligned */
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Take driver lock - Wait until we get semaphore */
+       if (rtems_semaphore_obtain(grpci2dma_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+               != RTEMS_SUCCESSFUL){
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* Get free channel id */
+       cid = grpci2dma_channel_free_id();
+       if (cid < 0 ){
+               rtems_semaphore_release(grpci2dma_sem);
+               return GRPCI2DMA_ERR_TOOMANY;
+       }
+
+       /* Open channel */
+       ret = grpci2dma_channel_open((struct grpci2_bd_chan *) chanptr, cid);
+
+       /* Create channel semaphore with count = 1 */
+       if (ret >= 0){
+               if (rtems_semaphore_create(
+                                       rtems_build_name('P', 'D', '0', '0' + 
cid), 1,
+                                       RTEMS_FIFO | 
RTEMS_SIMPLE_BINARY_SEMAPHORE | \
+                                       RTEMS_NO_INHERIT_PRIORITY | RTEMS_LOCAL 
| \
+                                       RTEMS_NO_PRIORITY_CEILING, 0, 
&priv->channel[cid].sem
+                                       ) != RTEMS_SUCCESSFUL) {
+                       priv->channel[cid].sem = RTEMS_ID_NONE;
+                       rtems_semaphore_release(grpci2dma_sem);
+                       return GRPCI2DMA_ERR_ERROR;
+               }
+       }
+
+       /* Release driver semaphore */
+       rtems_semaphore_release(grpci2dma_sem);
+
+       /* Return channel id */
+       return ret;
+}
+
+int grpci2dma_close(int chan_no)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       int ret;
+
+       if (!priv){
+               /* DMA not initialized */
+               return GRPCI2DMA_ERR_NOINIT;
+       }
+
+       /* Get chan pointer */
+       if ((chan_no < 0) || (chan_no >= MAX_DMA_CHANS)){
+               /* Wrong channel id */
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Check chan is open */
+       if (priv->channel[chan_no].ptr == NULL){
+               /* No channel */
+               return GRPCI2DMA_ERR_NOTFOUND;
+       }
+
+       /* Take driver lock - Wait until we get semaphore */
+       if (rtems_semaphore_obtain(grpci2dma_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+               != RTEMS_SUCCESSFUL){
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* Take channel lock - Wait until we get semaphore */
+       if (rtems_semaphore_obtain(priv->channel[chan_no].sem, RTEMS_WAIT, 
RTEMS_NO_TIMEOUT)
+               != RTEMS_SUCCESSFUL){
+               rtems_semaphore_release(grpci2dma_sem);
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* Close channel */
+       ret = grpci2dma_channel_close(chan_no);
+
+       /* Release channel sempahore */
+       rtems_semaphore_release(priv->channel[chan_no].sem);
+
+       /* Delete channel semaphore */
+       if (ret == GRPCI2DMA_ERR_OK){
+               if (rtems_semaphore_delete(priv->channel[chan_no].sem) 
+                               != RTEMS_SUCCESSFUL){
+                       /* Release driver semaphore */
+                       rtems_semaphore_release(grpci2dma_sem);
+                       return GRPCI2DMA_ERR_ERROR;
+               }
+       }
+
+       /* Release driver semaphore */
+       rtems_semaphore_release(grpci2dma_sem);
+
+       return ret;
+}
+
+/* Transfer_size =0 means maximum */
+int grpci2dma_prepare(
+               uint32_t pci_start, uint32_t ahb_start, int dir, int endianness,
+               int size, void * dataptr, int index, int ndata, int 
transfer_size)
+{
+       struct grpci2_bd_data * data = dataptr;
+
+       /* Check data pointer */
+       if ((data == NULL) || 
+                       (((unsigned int ) data) & (GRPCI2DMA_BD_DATA_ALIGN-1))){
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Check indexes */
+       int maxdata = ndata - index;
+       if ((maxdata < 1) || (index < 0)){
+               /* No data descriptors to use */
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Check PCI transfer size */
+       if ( (transfer_size < 0) || 
+                       (transfer_size > MAX_DMA_TRANSFER_SIZE) || 
+                       (transfer_size%4 != 0) ) {
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+       if (transfer_size == 0){
+               transfer_size = MAX_DMA_TRANSFER_SIZE;
+       }
+
+       /* Check total size */
+       if ( (size <=0) || (size % 4 != 0)){
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Calculate number of data descriptors needed */
+       int words = size/4;
+       int blocksize = transfer_size/4;
+       int datacnt = words/blocksize + (words%blocksize != 0? 1: 0);
+       /* Check that we can transfer the data */
+       if (datacnt > maxdata) {
+               return GRPCI2DMA_ERR_TOOMANY;
+       }
+
+       /* Prepare data descriptors */
+       int i;
+       uint32_t pci_adr;
+       uint32_t ahb_adr;
+       int remaining=words;
+       int datasize;
+       struct grpci2_bd_data * next;
+       for (i=0; i<datacnt; i++){
+               /* Get PCI and AHB start addresses */
+               pci_adr = pci_start + i*blocksize;
+               ahb_adr = ahb_start + i*blocksize;
+               /* Get current data size */
+               if (remaining >= blocksize){
+                       datasize = blocksize - 1;
+                       remaining -= blocksize;
+               } else {
+                       datasize = remaining -1;
+                       remaining = 0;
+               }
+               /* Get linked list pointers */
+               if (i == datacnt - 1){
+                       /* Last transfer */
+                       next = DISABLED_DESCRIPTOR;
+               }else{
+                       next = &data[i+index+1];
+               }
+               /* Set Data descriptor */
+               grpci2dma_data_bd_init(&data[i+index], pci_adr, ahb_adr, dir, 
endianness, datasize, next);
+       }
+       /* Return number of transfers used */
+       return datacnt;
+}
+
+int grpci2dma_status(void *dataptr, int index, int ndata)
+{
+       struct grpci2_bd_data * data = dataptr;
+       int i;
+
+       /* Check data pointer */
+       if ((data == NULL) || 
+                       (((unsigned int ) data) & (GRPCI2DMA_BD_DATA_ALIGN-1))){
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Check maxdata */
+       int maxdata = ndata - index;
+       if ((maxdata < 1) || (index < 0)){
+               /* No data descriptors to use */
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Check status of all packets in transfer */
+       int status;
+       for (i=0; i< maxdata; i++){
+               status = grpci2dma_data_bd_status(&data[i+index]); 
+               if (status == GRPCI2DMA_BD_STATUS_ERR){
+                       /* Error in one packet, means error in transfer */
+                       return status;
+               } else if (status == GRPCI2DMA_BD_STATUS_ENABLED){
+                       /* If one packet is enabled, means transfer is not done 
*/
+                       return status;
+               }
+       }
+
+       /* If we reach here it means they are all disabled */
+       return status;
+}
+
+int grpci2dma_print(int chan_no)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       struct grpci2_bd_chan * chan;
+
+       if (!priv){
+               /* DMA not initialized */
+               DBG("DMA not initialized.\n");
+               return GRPCI2DMA_ERR_NOINIT;
+       }
+
+       if ( (chan_no < 0) || (chan_no >= MAX_DMA_CHANS )){
+               /* Wrong chan no*/
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       chan = priv->channel[chan_no].ptr;
+       if (chan == NULL) {
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       #ifdef DEBUG
+       /* Print channel state */
+       grpci2dma_channel_print(chan);
+
+       /* Get current DATA desc */
+       struct grpci2_bd_data * first_data = (struct grpci2_bd_data *) 
BD_READ(&chan->nbd);
+
+       /* Print data state */
+       grpci2dma_data_list_foreach(first_data, grpci2dma_data_print, 
MAX_DMA_DATA);
+       #endif
+       return GRPCI2DMA_ERR_OK;
+}
+
+int grpci2dma_print_bd(void * dataptr)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       struct grpci2_bd_data * data = (struct grpci2_bd_data *) dataptr;
+
+       if (!priv){
+               /* DMA not initialized */
+               DBG("DMA not initialized.\n");
+               return GRPCI2DMA_ERR_NOINIT;
+       }
+
+       if ( data == NULL ){
+               /* Wrong chan no*/
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       #ifdef DEBUG
+       /* Print data state */
+       grpci2dma_data_list_foreach(data, grpci2dma_data_print, MAX_DMA_DATA);
+       #endif
+       return GRPCI2DMA_ERR_OK;
+}
+
+int grpci2dma_interrupt_enable(
+               void *dataptr, int index, int maxindex, int options)
+{
+       struct grpci2_bd_data * data = dataptr;
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       SPIN_IRQFLAGS(irqflags);
+
+       if (!priv){
+               /* DMA not initialized */
+               return GRPCI2DMA_ERR_NOINIT;
+       }
+
+       /* Check data pointer */
+       if ((data == NULL) || 
+                       (((unsigned int ) data) & (GRPCI2DMA_BD_DATA_ALIGN-1))){
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Check index */
+       if ((index < 0) || (maxindex < 1) || (index >= maxindex)){
+               /* No data descriptors to use */
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       if (options & GRPCI2DMA_OPTIONS_ALL){
+               /* Enable all interrupts */
+               if (grpci2dma_data_list_foreach(
+                                       &data[index],
+                                       grpci2dma_data_bd_interrupt_enable, 
maxindex -index)){
+                       return GRPCI2DMA_ERR_ERROR;
+               }
+       }else{
+               /* Enable one packet interrupts */
+               grpci2dma_data_bd_interrupt_enable(&data[index]);
+       }
+
+       /* Finally enable DMA interrupts if they are not already enabled */
+       if (grpci2dma_ctrl_interrupt_status()==0){
+               SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+               grpci2dma_ctrl_interrupt_enable();
+               SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+       }
+
+       DBG("Interrupts enabled for data (0x%08x), index:%d, maxindex:%d, 
%s.\n", 
+                       (unsigned int) data, index, maxindex, 
+                       (options & GRPCI2DMA_OPTIONS_ALL)? "ALL":"ONE" );
+
+       return GRPCI2DMA_ERR_OK;
+}
+
+int grpci2dma_push(int chan_no, void *dataptr, int index, int ndata)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       SPIN_IRQFLAGS(irqflags);
+       int ret;
+
+       if (!priv){
+               /* DMA not initialized */
+               return GRPCI2DMA_ERR_NOINIT;
+       }
+
+       /* Check data pointer */
+       if ((dataptr == NULL) || 
+                       (((unsigned int ) dataptr) & 
(GRPCI2DMA_BD_DATA_ALIGN-1))){
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Check index */
+       if ((ndata < 1) || (index < 0)){
+               /* No data descriptors to use */
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Check chan_no */
+       if ( (chan_no < 0) || (chan_no >= MAX_DMA_CHANS )){
+               /* Wrong chan no*/
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Check chan is open */
+       if (priv->channel[chan_no].ptr == NULL){
+               /* No channel */
+               return GRPCI2DMA_ERR_NOTFOUND;
+       }
+
+       /* Take channel lock - Wait until we get semaphore */
+       if (rtems_semaphore_obtain(priv->channel[chan_no].sem, RTEMS_WAIT, 
RTEMS_NO_TIMEOUT)
+               != RTEMS_SUCCESSFUL){
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* push data to channel */
+       ret = grpci2dma_channel_push(chan_no, dataptr, index, ndata);
+
+       if (ret != GRPCI2DMA_ERR_OK){
+               /* Release channel lock */
+               rtems_semaphore_release(priv->channel[chan_no].sem);
+               return ret;
+       }
+
+       /* Start DMA if it is not active and channel is active*/
+       SPIN_LOCK_IRQ(&priv->devlock, irqflags);
+       if ((!grpci2dma_active()) && (priv->channel[chan_no].active)){
+               grpci2dma_ctrl_start(priv->channel[chan_no].ptr);
+       }
+       SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
+
+       /* Release channel lock */
+       rtems_semaphore_release(priv->channel[chan_no].sem);
+
+       return ret;
+}
+
+/* Start the channel */
+int grpci2dma_start(int chan_no, int options)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       int ret;
+
+       if (!priv){
+               /* DMA not initialized */
+               return GRPCI2DMA_ERR_NOINIT;
+       }
+
+       if ((chan_no < 0 ) || (chan_no >= MAX_DMA_CHANS )) {
+               /* Wrong channel id */
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       if ( options < 0 ) {
+               /* Wrong options */
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Check chan is open */
+       if (priv->channel[chan_no].ptr == NULL){
+               /* No channel */
+               return GRPCI2DMA_ERR_NOTFOUND;
+       }
+
+       /* Take driver lock - Wait until we get semaphore */
+       if (rtems_semaphore_obtain(grpci2dma_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+               != RTEMS_SUCCESSFUL){
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* Take channel lock - Wait until we get semaphore */
+       if (rtems_semaphore_obtain(priv->channel[chan_no].sem, RTEMS_WAIT, 
RTEMS_NO_TIMEOUT)
+               != RTEMS_SUCCESSFUL){
+               rtems_semaphore_release(grpci2dma_sem);
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* Start the channel */
+       ret = grpci2dma_channel_start(chan_no, options);
+
+       /* Release channel lock */
+       rtems_semaphore_release(priv->channel[chan_no].sem);
+
+       /* Release driver lock */
+       rtems_semaphore_release(grpci2dma_sem);
+
+       return ret;
+}
+
+/* Stop the channel, but don't stop ongoing transfers! */
+int grpci2dma_stop(int chan_no)
+{
+       struct grpci2dma_priv *priv = grpci2dmapriv;
+       int ret;
+
+       if (!priv){
+               /* DMA not initialized */
+               return GRPCI2DMA_ERR_NOINIT;
+       }
+
+       if ((chan_no < 0 ) || (chan_no >= MAX_DMA_CHANS)) {
+               /* Wrong channel id */
+               return GRPCI2DMA_ERR_WRONGPTR;
+       }
+
+       /* Check chan is open */
+       if (priv->channel[chan_no].ptr == NULL){
+               /* No channel */
+               return GRPCI2DMA_ERR_NOTFOUND;
+       }
+
+       /* Take driver lock - Wait until we get semaphore */
+       if (rtems_semaphore_obtain(grpci2dma_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+               != RTEMS_SUCCESSFUL){
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* Take channel lock - Wait until we get semaphore */
+       if (rtems_semaphore_obtain(priv->channel[chan_no].sem, RTEMS_WAIT, 
RTEMS_NO_TIMEOUT)
+               != RTEMS_SUCCESSFUL){
+               rtems_semaphore_release(grpci2dma_sem);
+               return GRPCI2DMA_ERR_ERROR;
+       }
+
+       /* Stop the channel */
+       ret = grpci2dma_channel_stop(chan_no);
+
+       /* Release channel lock */
+       rtems_semaphore_release(priv->channel[chan_no].sem);
+
+       /* Release driver lock */
+       rtems_semaphore_release(grpci2dma_sem);
+
+       return ret;
+}
+
+int grpci2dma_active()
+{
+       return ((grpci2dma_ctrl_status()) & DMACTRL_ACT) >> DMACTRL_ACT_BIT;
+}
+
-- 
2.7.4

_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel

Reply via email to