[ep93xx] add support for the Simplemachines Sim.One board
[openwrt/svn-archive/archive.git] / target / linux / ep93xx / patches-2.6.30 / 005-ep93xx-dma.patch
diff --git a/target/linux/ep93xx/patches-2.6.30/005-ep93xx-dma.patch b/target/linux/ep93xx/patches-2.6.30/005-ep93xx-dma.patch
new file mode 100644 (file)
index 0000000..3664132
--- /dev/null
@@ -0,0 +1,3622 @@
+--- /dev/null
++++ b/arch/arm/mach-ep93xx/dma_ep93xx.c
+@@ -0,0 +1,2940 @@
++/******************************************************************************
++ * arch/arm/mach-ep9312/dma_ep93xx.c
++ *
++ * Support functions for the ep93xx internal DMA channels.
++ * (see also Documentation/arm/ep93xx/dma.txt)
++ *
++ * Copyright (C) 2003  Cirrus Logic
++ *
++ * A large portion of this file is based on the dma api implemented by
++ * Nicolas Pitre, dma-sa1100.c, copyrighted 2000.
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ ****************************************************************************/
++#include <linux/autoconf.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++
++#include <asm/system.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++#include <asm/mach/dma.h>
++#include "dma_ep93xx.h"
++
++/*****************************************************************************
++ *
++ * Debugging macros
++ *
++ ****************************************************************************/
++#undef DEBUG
++//#define DEBUG   1
++#ifdef DEBUG
++#define DPRINTK( fmt, arg... )  printk( fmt, ##arg )
++#else
++#define DPRINTK( fmt, arg... )
++#endif
++
++/*****************************************************************************
++ *
++ * static global variables
++ *
++ ****************************************************************************/
++ep93xx_dma_t dma_chan[MAX_EP93XX_DMA_CHANNELS];
++
++/*
++ *  lock used to protect the list of dma channels while searching for a free
++ *  channel during dma_request.
++ */
++//static spinlock_t dma_list_lock;
++static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED;
++
++/*****************************************************************************
++ *
++ *  Internal DMA processing functions.
++ *
++ ****************************************************************************/
++/*****************************************************************************
++ *
++ *  get_dma_channel_from_handle()
++ *
++ *  If Handle is valid, returns the DMA channel # (0 to 9 for channels 1-10)
++ *  If Handle is not valid, returns -1.
++ *
++ ****************************************************************************/
++static int
++dma_get_channel_from_handle(int handle)
++{
++      int channel;
++
++      /*
++       *  Get the DMA channel # from the handle.
++       */
++      channel = ((int)handle & DMA_HANDLE_SPECIFIER_MASK) >> 28;
++
++      /*
++       *  See if this is a valid handle.
++       */
++      if (dma_chan[channel].last_valid_handle != (int)handle) {
++              DPRINTK("DMA ERROR - invalid handle 0x%x \n", handle);
++              return(-1);
++      }
++
++      /*
++       *  See if this instance is still open
++       */
++      if (!dma_chan[channel].ref_count )
++              return(-1);
++
++      return(channel);
++}
++
++static void dma_m2m_transfer_done(ep93xx_dma_t *dma)
++{
++      unsigned int uiCONTROL;
++      unsigned int M2M_reg_base = dma->reg_base;
++      unsigned int read_back;
++
++      DPRINTK("1  ");
++
++      outl( 0, M2M_reg_base+M2M_OFFSET_INTERRUPT );
++
++      if (dma->total_buffers) {
++              /*
++               * The current_buffer has already been tranfered, so add the
++               * byte count to the total_bytes field.
++               */
++              dma->total_bytes = dma->total_bytes +
++                      dma->buffer_queue[dma->current_buffer].size;
++
++              /*
++               * Mark the current_buffer as used.
++               */
++              dma->buffer_queue[dma->current_buffer].used = TRUE;
++
++              /*
++               * Increment the used buffer counter
++               */
++              dma->used_buffers++;
++
++              DPRINTK("#%d", dma->current_buffer);
++
++              /*
++               * Increment the current_buffer
++               */
++              dma->current_buffer = (dma->current_buffer + 1) %
++                                    MAX_EP93XX_DMA_BUFFERS;
++
++              /*
++               * check if there's a new buffer to transfer.
++               */
++              if (dma->new_buffers && dma->xfer_enable) {
++                      /*
++                       * We have a new buffer to transfer so program in the
++                       * buffer values.  Since a STALL interrupt was
++                       * triggered, we program the buffer descriptor 0
++                       *
++                       * Set the SAR_BASE/DAR_BASE/BCR registers with values
++                       * from the next buffer in the queue.
++                       */
++                      outl( dma->buffer_queue[dma->current_buffer].source,
++                            M2M_reg_base + M2M_OFFSET_SAR_BASE0 );
++
++                      outl( dma->buffer_queue[dma->current_buffer].dest,
++                            M2M_reg_base + M2M_OFFSET_DAR_BASE0 );
++
++                      outl( dma->buffer_queue[dma->current_buffer].size,
++                            M2M_reg_base + M2M_OFFSET_BCR0 );
++
++                      DPRINTK("SAR_BASE0 - 0x%x\n", dma->buffer_queue[dma->current_buffer].source);
++                      DPRINTK("DAR_BASE0 - 0x%x\n", dma->buffer_queue[dma->current_buffer].dest);
++                      DPRINTK("BCR0 - 0x%x\n", dma->buffer_queue[dma->current_buffer].size);
++
++                      /*
++                       * Decrement the new buffer counter
++                       */
++                      dma->new_buffers--;
++
++                      /*
++                       * If there's a second new buffer, we program the
++                       * second buffer descriptor.
++                       */
++                      if (dma->new_buffers) {
++                              outl( dma->buffer_queue[(dma->current_buffer + 1) %
++                                                      MAX_EP93XX_DMA_BUFFERS].source,
++                                    M2M_reg_base+M2M_OFFSET_SAR_BASE1 );
++
++                              outl( dma->buffer_queue[(dma->current_buffer + 1) %
++                                                      MAX_EP93XX_DMA_BUFFERS].dest,
++                                    M2M_reg_base+M2M_OFFSET_DAR_BASE1 );
++
++                              outl( dma->buffer_queue[(dma->current_buffer + 1) %
++                                                      MAX_EP93XX_DMA_BUFFERS].size,
++                                    M2M_reg_base+M2M_OFFSET_BCR1 );
++
++                              uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++                              uiCONTROL |= CONTROL_M2M_NFBINTEN;
++                              outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++
++                              dma->new_buffers--;
++                      }
++              } else {
++                      DPRINTK("2 \n");
++                      /*
++                       * There's a chance we setup both buffer descriptors,
++                       * but didn't service the NFB quickly enough, causing
++                       * the channel to transfer both buffers, then enter the
++                       * stall state.  So, we need to be able to process the
++                       * second buffer.
++                       */
++                      if ((dma->used_buffers + dma->new_buffers) < dma->total_buffers)
++                      {
++                              DPRINTK("3 ");
++
++                              /*
++                               * The current_buffer has already been
++                               * tranferred, so add the byte count to the
++                               * total_bytes field.
++                               */
++                              dma->total_bytes = dma->total_bytes +
++                                      dma->buffer_queue[dma->current_buffer].size;
++
++                              /*
++                               * Mark the current_buffer as used.
++                               */
++                              dma->buffer_queue[dma->current_buffer].used = TRUE;
++
++                              /*
++                               * Increment the used buffer counter
++                               */
++                              dma->used_buffers++;
++
++                              DPRINTK("#%d", dma->current_buffer);
++
++                              /*
++                               * Increment the current buffer pointer.
++                               */
++                              dma->current_buffer = (dma->current_buffer + 1) %
++                                                    MAX_EP93XX_DMA_BUFFERS;
++
++                      }
++
++                      /*
++                       * No new buffers to transfer, so disable the channel.
++                       */
++                      uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++                      uiCONTROL &= ~CONTROL_M2M_ENABLE;
++                      outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++
++                      /*
++                       * Indicate that this channel is in the pause by
++                       * starvation state by setting the pause bit to true.
++                       */
++                      dma->pause = TRUE;
++              }
++      } else {
++              /*
++               * No buffers to transfer, or old buffers to mark as used,
++               * so disable the channel
++               */
++              uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++              uiCONTROL &= ~CONTROL_M2M_ENABLE;
++              outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++
++              /*
++               * Must read the control register back after a write.
++               */
++              read_back = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++
++              /*
++               * Indicate that this channel is in the pause by
++               * starvation state by setting the pause bit to true.
++               */
++              dma->pause = TRUE;
++      }
++}
++
++static void dma_m2m_next_frame_buffer(ep93xx_dma_t *dma)
++{
++      int loop;
++      unsigned int uiCONTROL;
++      unsigned int M2M_reg_base = dma->reg_base;
++
++      DPRINTK("5  ");
++
++      if (dma->total_buffers) {
++              DPRINTK("6  ");
++              /*
++               * The iCurrentBuffer has already been transfered.  so add the
++               * byte count from the current buffer to the total byte count.
++               */
++              dma->total_bytes = dma->total_bytes +
++                      dma->buffer_queue[dma->current_buffer].size;
++
++              /*
++               * Mark the Current Buffer as used.
++               */
++              dma->buffer_queue[dma->current_buffer].used = TRUE;
++
++              /*
++               * Increment the used buffer counter
++               */
++              dma->used_buffers++;
++
++              DPRINTK("#%d", dma->current_buffer);
++
++              if ((dma->buffer_queue[
++                  (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].last) ||
++                  (dma->new_buffers == 0) || (dma->xfer_enable == FALSE)) {
++                      DPRINTK("7  ");
++
++                      /*
++                       * This is the last Buffer in this transaction, so
++                       * disable the NFB interrupt.  We shouldn't get an NFB
++                       * int when the FSM moves to the ON state where it
++                       * would typically get the NFB int indicating a new
++                       * buffer can be programmed.  Instead, once in the ON
++                       * state, the DMA will just proceed to complete the
++                       * transfer of the current buffer, move the FSB
++                       * directly to the STALL state where a STALL interrupt
++                       * will be generated.
++                       */
++                      uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++                      uiCONTROL &= ~CONTROL_M2M_NFBINTEN ;
++                      outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++
++                      /*
++                       * The current buffer has been transferred, so
++                       * increment the current buffer counter to reflect
++                       * this.
++                       */
++                      dma->current_buffer = (dma->current_buffer + 1) %
++                                            MAX_EP93XX_DMA_BUFFERS;
++
++                      DPRINTK("End of NFB handling. \n");
++                      DPRINTK("CONTROL - 0x%x \n",
++                                inl(M2M_reg_base+M2M_OFFSET_CONTROL) );
++                      DPRINTK("STATUS - 0x%x \n",
++                                inl(M2M_reg_base+M2M_OFFSET_STATUS) );
++                      DPRINTK("SAR_BASE0 - 0x%x \n",
++                                inl(M2M_reg_base+M2M_OFFSET_SAR_BASE0) );
++                      DPRINTK("SAR_CUR0 - 0x%x \n",
++                                inl(M2M_reg_base+M2M_OFFSET_SAR_CURRENT0) );
++                      DPRINTK("DAR_BASE0 - 0x%x \n",
++                                inl(M2M_reg_base+M2M_OFFSET_DAR_BASE0) );
++                      DPRINTK("DAR_CUR0 - 0x%x \n",
++                                inl(M2M_reg_base+M2M_OFFSET_DAR_CURRENT0) );
++
++                      DPRINTK("Buffer buf_id   source    size    last    used \n");
++                      for (loop = 0; loop < 32; loop ++)
++                              DPRINTK("%d             0x%x            0x%x             0x%x           %d               %d \n",
++                                      loop, dma->buffer_queue[loop].buf_id,
++                                      dma->buffer_queue[loop].source,
++                                      dma->buffer_queue[loop].size,
++                                      dma->buffer_queue[loop].last,
++                                      dma->buffer_queue[loop].used);
++                      DPRINTK("pause   0x%x           0x%x             0x%x           %d               %d \n",
++                              dma->pause_buf.buf_id, dma->pause_buf.source,
++                              dma->pause_buf.size, dma->pause_buf.last,
++                              dma->pause_buf.used);
++
++                      DPRINTK("Pause - %d \n", dma->pause);
++                      DPRINTK("xfer_enable - %d \n", dma->xfer_enable);
++                      DPRINTK("total bytes - 0x%x \n", dma->total_bytes);
++                      DPRINTK("total buffer - %d \n", dma->total_buffers);
++                      DPRINTK("new buffers - %d \n", dma->new_buffers);
++                      DPRINTK("current buffer - %d \n", dma->current_buffer);
++                      DPRINTK("last buffer - %d \n", dma->last_buffer);
++                      DPRINTK("used buffers - %d \n", dma->used_buffers);
++                      DPRINTK("callback addr - 0x%p \n", dma->callback);
++
++              } else if (dma->new_buffers) {
++                      DPRINTK("8  ");
++                      /*
++                       * We have a new buffer, so increment the current
++                       * buffer to point to the next buffer, which is already
++                       * programmed into the DMA. Next time around, it'll be
++                       * pointing to the current buffer.
++                       */
++                      dma->current_buffer = (dma->current_buffer + 1) %
++                                            MAX_EP93XX_DMA_BUFFERS;
++
++                      /*
++                       * We know we have a new buffer to program as the next
++                       * buffer, so check which set of SAR_BASE/DAR_BASE/BCR
++                       * registers to program.
++                       */
++                      if ( inl(M2M_reg_base+M2M_OFFSET_STATUS) & STATUS_M2M_NB ) {
++                              /*
++                               * Set the SAR_BASE1/DAR_BASE1/BCR1 registers
++                               * with values from the next buffer in the
++                               * queue.
++                               */
++                              outl( dma->buffer_queue[(dma->current_buffer + 1) %
++                                                      MAX_EP93XX_DMA_BUFFERS].source,
++                                    M2M_reg_base+M2M_OFFSET_SAR_BASE1 );
++
++                              outl( dma->buffer_queue[(dma->current_buffer + 1) %
++                                                      MAX_EP93XX_DMA_BUFFERS].dest,
++                                    M2M_reg_base+M2M_OFFSET_DAR_BASE1 );
++
++                              outl( dma->buffer_queue[(dma->current_buffer + 1) %
++                                                      MAX_EP93XX_DMA_BUFFERS].size,
++                                    M2M_reg_base+M2M_OFFSET_BCR1 );
++                      } else {
++                              /*
++                               * Set the SAR_BASE0/DAR_BASE0/BCR0 registers
++                               * with values from the next buffer in the
++                               * queue.
++                               */
++                              outl( dma->buffer_queue[(dma->current_buffer + 1) %
++                                                      MAX_EP93XX_DMA_BUFFERS].source,
++                                    M2M_reg_base+M2M_OFFSET_SAR_BASE0 );
++
++                              outl( dma->buffer_queue[(dma->current_buffer + 1) %
++                                                      MAX_EP93XX_DMA_BUFFERS].dest,
++                                    M2M_reg_base+M2M_OFFSET_DAR_BASE0 );
++
++                              outl( dma->buffer_queue[(dma->current_buffer + 1) %
++                                                      MAX_EP93XX_DMA_BUFFERS].size,
++                                    M2M_reg_base+M2M_OFFSET_BCR0 );
++                      }
++
++                      /*
++                       *  Decrement the new buffers counter
++                       */
++                      dma->new_buffers--;
++              }
++      } else {
++              /*
++               * Total number of buffers is 0 - really we should never get
++               * here, but just in case.
++               */
++              DPRINTK("9 \n");
++
++              /*
++               *  No new buffers to transfer, so Disable the channel
++               */
++              uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++              uiCONTROL &= ~CONTROL_M2M_ENABLE;
++              outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++
++              /*
++               *  Indicate that the channel is paused by starvation.
++               */
++              dma->pause = 1;
++      }
++}
++
++/*****************************************************************************
++ *
++ * dma_m2m_irq_handler
++ *
++ ****************************************************************************/
++static irqreturn_t
++dma_m2m_irq_handler(int irq, void *dev_id)
++{
++      ep93xx_dma_t *dma = (ep93xx_dma_t *)dev_id;
++      unsigned int M2M_reg_base = dma->reg_base;
++      ep93xx_dma_dev_t dma_int = UNDEF_INT;
++      int status;
++
++//    printk("+m2m irq=%d\n", irq);
++
++      /*
++       *  Determine what kind of dma interrupt this is.
++       */
++      status = inl(M2M_reg_base + M2M_OFFSET_INTERRUPT);
++      if ( status & INTERRUPT_M2M_DONEINT )
++              dma_int = DONE; // we're done with a requested dma
++      else if ( status & INTERRUPT_M2M_NFBINT )
++              dma_int = NFB;  // we're done with one dma buffer
++
++      DPRINTK("IRQ: b=%#x st=%#x\n", (int)dma->current_buffer, dma_int);
++
++      switch (dma_int) {
++      /*
++       *  Next Frame Buffer Interrupt.  If there's a new buffer program it
++       *  Check if this is the last buffer in the transfer,
++       *  and if it is, disable the NFB int to prevent being
++       *  interrupted for another buffer when we know there won't be
++       *  another.
++       */
++      case NFB:
++              dma_m2m_next_frame_buffer(dma);
++              break;
++      /*
++       *  Done interrupt generated, indicating that the transfer is complete.
++       */
++      case DONE:
++              dma_m2m_transfer_done(dma);
++              break;
++
++      default:
++              break;
++      }
++
++      if ((dma_int != UNDEF_INT) && dma->callback)
++              dma->callback(dma_int, dma->device, dma->user_data);
++
++      return IRQ_HANDLED;
++}
++
++/*****************************************************************************
++ *
++ * dma_m2p_irq_handler
++ *
++ *
++ *
++ ****************************************************************************/
++static irqreturn_t
++dma_m2p_irq_handler(int irq, void *dev_id)
++{
++      ep93xx_dma_t *dma = (ep93xx_dma_t *) dev_id;
++      unsigned int M2P_reg_base = dma->reg_base;
++      unsigned int read_back;
++      ep93xx_dma_dev_t dma_int = UNDEF_INT;
++      unsigned int loop, uiCONTROL, uiINTERRUPT;
++
++      /*
++       *  Determine what kind of dma interrupt this is.
++       */
++      if ( inl(M2P_reg_base+M2P_OFFSET_INTERRUPT) & INTERRUPT_M2P_STALLINT )
++              dma_int = STALL;
++      else if ( inl(M2P_reg_base+M2P_OFFSET_INTERRUPT) & INTERRUPT_M2P_NFBINT )
++              dma_int = NFB;
++      else if ( inl(M2P_reg_base+M2P_OFFSET_INTERRUPT) & INTERRUPT_M2P_CHERRORINT )
++              dma_int = CHERROR;
++
++      /*
++       *  Stall Interrupt: The Channel is stalled, meaning nothing is
++       *  programmed to transfer right now.  So, we're back to the
++       *  beginnning.  If there's a buffer to transfer, program it into
++       *  max and base 0 registers.
++       */
++      if (dma_int == STALL) {
++              DPRINTK("1  ");
++
++              if (dma->total_buffers) {
++                      /*
++                       * The current_buffer has already been tranfered, so
++                       * add the byte count to the total_bytes field.
++                       */
++                      dma->total_bytes = dma->total_bytes +
++                              dma->buffer_queue[dma->current_buffer].size;
++
++                      /*
++                       *  Mark the current_buffer as used.
++                       */
++                      dma->buffer_queue[dma->current_buffer].used = TRUE;
++
++                      /*
++                       *  Increment the used buffer counter
++                       */
++                      dma->used_buffers++;
++
++                      DPRINTK("#%d", dma->current_buffer);
++
++                      /*
++                       *  Increment the current_buffer
++                       */
++                      dma->current_buffer = (dma->current_buffer + 1) %
++                                            MAX_EP93XX_DMA_BUFFERS;
++
++                      /*
++                       *  check if there's a new buffer to transfer.
++                       */
++                      if (dma->new_buffers && dma->xfer_enable) {
++                              /*
++                               * We have a new buffer to transfer so program
++                               * in the buffer values.  Since a STALL
++                               * interrupt was triggered, we program the
++                               * base0 and maxcnt0
++                               *
++                               * Set the MAXCNT0 register with the buffer
++                               * size
++                               */
++                              outl( dma->buffer_queue[dma->current_buffer].size,
++                                        M2P_reg_base+M2P_OFFSET_MAXCNT0 );
++
++                              /*
++                               * Set the BASE0 register with the buffer base
++                               * address
++                               */
++                              outl( dma->buffer_queue[dma->current_buffer].source,
++                                        M2P_reg_base+M2P_OFFSET_BASE0 );
++
++                              /*
++                               *  Decrement the new buffer counter
++                               */
++                              dma->new_buffers--;
++
++                              if (dma->new_buffers) {
++                                      DPRINTK("A  ");
++                                      /*
++                                       * Set the MAXCNT1 register with the
++                                       * buffer size
++                                       */
++                                      outl( dma->buffer_queue[(dma->current_buffer + 1) %
++                                                                                      MAX_EP93XX_DMA_BUFFERS].size,
++                                                M2P_reg_base+M2P_OFFSET_MAXCNT1 );
++
++                                      /*
++                                       * Set the BASE1 register with the
++                                       * buffer base address
++                                       */
++                                      outl( dma->buffer_queue[dma->current_buffer + 1 %
++                                                                                      MAX_EP93XX_DMA_BUFFERS].source,
++                                                M2P_reg_base+M2P_OFFSET_BASE1 );
++
++                                      /*
++                                       *  Decrement the new buffer counter
++                                       */
++                                      dma->new_buffers--;
++
++                                      /*
++                                       *  Enable the NFB Interrupt.
++                                       */
++                                      uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);
++                                      uiCONTROL |= CONTROL_M2P_NFBINTEN;
++                                      outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );
++                              }
++                      } else {
++                              /*
++                               *  No new buffers.
++                               */
++                              DPRINTK("2 \n");
++
++                              /*
++                               *  There's a chance we setup both buffer descriptors, but
++                               *  didn't service the NFB quickly enough, causing the channel
++                               *  to transfer both buffers, then enter the stall state.
++                               *  So, we need to be able to process the second buffer.
++                               */
++                              if ((dma->used_buffers + dma->new_buffers) < dma->total_buffers) {
++                                      DPRINTK("3 ");
++
++                                      /*
++                                       *  The current_buffer has already been tranfered, so add the
++                                       *  byte count to the total_bytes field.
++                                       */
++                                      dma->total_bytes = dma->total_bytes +
++                                              dma->buffer_queue[dma->current_buffer].size;
++
++                                      /*
++                                       *  Mark the current_buffer as used.
++                                       */
++                                      dma->buffer_queue[dma->current_buffer].used = TRUE;
++
++                                      /*
++                                       *  Increment the used buffer counter
++                                       */
++                                      dma->used_buffers++;
++
++                                      DPRINTK("#%d", dma->current_buffer);
++
++                                      /*
++                                       *  Increment the current buffer pointer.
++                                       */
++                                      dma->current_buffer = (dma->current_buffer + 1) %
++                                              MAX_EP93XX_DMA_BUFFERS;
++
++                              }
++
++                              /*
++                               *  No new buffers to transfer, so disable the channel.
++                               */
++                              uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);
++                              uiCONTROL &= ~CONTROL_M2P_ENABLE;
++                              outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );
++
++                              /*
++                               *  Indicate that this channel is in the pause by starvation
++                               *  state by setting the pause bit to true.
++                               */
++                              dma->pause = TRUE;
++
++                              DPRINTK("STATUS - 0x%x \n",      inl(M2P_reg_base+M2P_OFFSET_STATUS) );
++                              DPRINTK("CONTROL - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_CONTROL) );
++                              DPRINTK("REMAIN - 0x%x \n",      inl(M2P_reg_base+M2P_OFFSET_REMAIN) );
++                              DPRINTK("PPALLOC - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_PPALLOC) );
++                              DPRINTK("BASE0 - 0x%x \n",        inl(M2P_reg_base+M2P_OFFSET_BASE0) );
++                              DPRINTK("MAXCNT0 - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_MAXCNT0) );
++                              DPRINTK("CURRENT0 - 0x%x \n",   inl(M2P_reg_base+M2P_OFFSET_CURRENT0) );
++                              DPRINTK("BASE1 - 0x%x \n",        inl(M2P_reg_base+M2P_OFFSET_BASE1) );
++                              DPRINTK("MAXCNT1 - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_MAXCNT1) );
++                              DPRINTK("CURRENT1 - 0x%x \n",   inl(M2P_reg_base+M2P_OFFSET_CURRENT1) );
++
++                              DPRINTK("Buffer buf_id   source    size    last    used \n");
++                              for (loop = 0; loop < 32; loop ++)
++                                      DPRINTK("%d             0x%x            0x%x             0x%x           %d               %d \n",
++                                                      loop, dma->buffer_queue[loop].buf_id, dma->buffer_queue[loop].source,
++                                                      dma->buffer_queue[loop].size,
++                                                      dma->buffer_queue[loop].last, dma->buffer_queue[loop].used);
++                              DPRINTK("pause   0x%x           0x%x             0x%x           %d               %d \n",
++                                              dma->pause_buf.buf_id, dma->pause_buf.source, dma->pause_buf.size,
++                                              dma->pause_buf.last, dma->pause_buf.used);
++
++                              DPRINTK("Pause - %d \n", dma->pause);
++                              DPRINTK("xfer_enable - %d \n", dma->xfer_enable);
++                              DPRINTK("total bytes - 0x%x \n", dma->total_bytes);
++                              DPRINTK("total buffer - %d \n", dma->total_buffers);
++                              DPRINTK("new buffers - %d \n", dma->new_buffers);
++                              DPRINTK("current buffer - %d \n", dma->current_buffer);
++                              DPRINTK("last buffer - %d \n", dma->last_buffer);
++                              DPRINTK("used buffers - %d \n", dma->used_buffers);
++                              DPRINTK("callback addr - 0x%p \n", dma->callback);
++                      }
++              } else {
++                      /*
++                       *  No buffers to transfer, or old buffers to mark as used,
++                       *  so Disable the channel
++                       */
++                      uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);
++                      uiCONTROL &= ~CONTROL_M2P_ENABLE;
++                      outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );
++
++                      /*
++                       *  Must read the control register back after a write.
++                       */
++                      read_back = inl(M2P_reg_base+M2P_OFFSET_CONTROL);
++
++                      /*
++                       *  Indicate that this channel is in the pause by
++                       *  starvation state by setting the pause bit to true.
++                       */
++                      dma->pause = TRUE;
++              }
++      }
++
++      /*
++       *  Next Frame Buffer Interrupt.  If there's a new buffer program it
++       *  Check if this is the last buffer in the transfer,
++       *  and if it is, disable the NFB int to prevent being
++       *  interrupted for another buffer when we know there won't be
++       *  another.
++       */
++      if (dma_int == NFB) {
++              DPRINTK("5  ");
++
++              if (dma->total_buffers) {
++                      DPRINTK("6  ");
++                      /*
++                       *  The iCurrentBuffer has already been transfered.  so add the
++                       *  byte count from the current buffer to the total byte count.
++                       */
++                      dma->total_bytes = dma->total_bytes +
++                              dma->buffer_queue[dma->current_buffer].size;
++
++                      /*
++                       *  Mark the Current Buffer as used.
++                       */
++                      dma->buffer_queue[dma->current_buffer].used = TRUE;
++
++                      /*
++                       *  Increment the used buffer counter
++                       */
++                      dma->used_buffers++;
++
++                      DPRINTK("#%d", dma->current_buffer);
++
++                      if ((dma->buffer_queue[
++                          (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].last) ||
++                          (dma->new_buffers == 0) || (dma->xfer_enable == FALSE)) {
++                              DPRINTK("7  ");
++
++                              /*
++                               *  This is the last Buffer in this transaction, so disable
++                               *  the NFB interrupt.  We shouldn't get an NFB int when the
++                               *  FSM moves to the ON state where it would typically get the
++                               *  NFB int indicating a new buffer can be programmed.
++                               *  Instead, once in the ON state, the DMA will just proceed
++                               *  to complet the transfer of the current buffer, move the
++                               *  FSB directly to the STALL state where a STALL interrupt
++                               *  will be generated.
++                               */
++                              uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);
++                              uiCONTROL &= ~CONTROL_M2P_NFBINTEN;
++                              outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );
++
++                              /*
++                               *  The current buffer has been transferred, so increment
++                               *  the current buffer counter to reflect this.
++                               */
++                              dma->current_buffer = (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS;
++
++                              DPRINTK("End of NFB handling. \n");
++                              DPRINTK("STATUS - 0x%x \n",      inl(M2P_reg_base+M2P_OFFSET_STATUS) );
++                              DPRINTK("CONTROL - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_CONTROL) );
++                              DPRINTK("REMAIN - 0x%x \n",      inl(M2P_reg_base+M2P_OFFSET_REMAIN) );
++                              DPRINTK("PPALLOC - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_PPALLOC) );
++                              DPRINTK("BASE0 - 0x%x \n",        inl(M2P_reg_base+M2P_OFFSET_BASE0) );
++                              DPRINTK("MAXCNT0 - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_MAXCNT0) );
++                              DPRINTK("CURRENT0 - 0x%x \n",   inl(M2P_reg_base+M2P_OFFSET_CURRENT0) );
++                              DPRINTK("BASE1 - 0x%x \n",        inl(M2P_reg_base+M2P_OFFSET_BASE1) );
++                              DPRINTK("MAXCNT1 - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_MAXCNT1) );
++                              DPRINTK("CURRENT1 - 0x%x \n",   inl(M2P_reg_base+M2P_OFFSET_CURRENT1) );
++
++                              DPRINTK("Buffer buf_id   source    size    last    used \n");
++                              for (loop = 0; loop < 32; loop ++)
++                                      DPRINTK("%d             0x%x            0x%x             0x%x           %d               %d \n",
++                                                      loop, dma->buffer_queue[loop].buf_id, dma->buffer_queue[loop].source,
++                                                      dma->buffer_queue[loop].size,
++                                                      dma->buffer_queue[loop].last, dma->buffer_queue[loop].used);
++                              DPRINTK("pause   0x%x           0x%x             0x%x           %d               %d \n",
++                                              dma->pause_buf.buf_id, dma->pause_buf.source, dma->pause_buf.size,
++                                              dma->pause_buf.last, dma->pause_buf.used);
++
++                              DPRINTK("Pause - %d \n", dma->pause);
++                              DPRINTK("xfer_enable - %d \n", dma->xfer_enable);
++                              DPRINTK("total bytes - 0x%x \n", dma->total_bytes);
++                              DPRINTK("total buffer - %d \n", dma->total_buffers);
++                              DPRINTK("new buffers - %d \n", dma->new_buffers);
++                              DPRINTK("current buffer - %d \n", dma->current_buffer);
++                              DPRINTK("last buffer - %d \n", dma->last_buffer);
++                              DPRINTK("used buffers - %d \n", dma->used_buffers);
++                              DPRINTK("callback addr - 0x%p \n", dma->callback);
++
++                      } else if (dma->new_buffers) {
++                              DPRINTK("8  ");
++                              /*
++                               *  we have a new buffer, so increment the current buffer to
++                               *  point to the next buffer, which is already programmed into
++                               *  the DMA. Next time around, it'll be pointing to the
++                               *  current buffer.
++                               */
++                              dma->current_buffer = (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS;
++
++                              /*
++                               *  we know we have a new buffer to program as the next
++                               *  buffer, so check which set of MAXCNT and BASE registers
++                               *  to program.
++                               */
++                              if ( inl(M2P_reg_base+M2P_OFFSET_STATUS) & STATUS_M2P_NEXTBUFFER ) {
++                                      /*
++                                       *  Set the MAXCNT1 register with the buffer size
++                                       */
++                                      outl( dma->buffer_queue[
++                                            (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].size,
++                                            M2P_reg_base+M2P_OFFSET_MAXCNT1 );
++
++                                      /*
++                                       *  Set the BASE1 register with the buffer base address
++                                       */
++                                      outl( dma->buffer_queue[
++                                            (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].source,
++                                            M2P_reg_base+M2P_OFFSET_BASE1 );
++                              } else {
++                                      /*
++                                       *  Set the MAXCNT0 register with the buffer size
++                                       */
++                                      outl( dma->buffer_queue[
++                                            (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].size,
++                                             M2P_reg_base+M2P_OFFSET_MAXCNT0 );
++
++                                      /*
++                                       *  Set the BASE0 register with the buffer base address
++                                       */
++                                      outl( dma->buffer_queue[
++                                            (dma->current_buffer + 1) % MAX_EP93XX_DMA_BUFFERS].source,
++                                            M2P_reg_base+M2P_OFFSET_BASE0 );
++                              }
++
++                              /*
++                               *  Decrement the new buffers counter
++                               */
++                              dma->new_buffers--;
++                      }
++              } else {
++                      /*
++                       *  Total number of buffers is 0 - really we should never get here,
++                       *  but just in case.
++                       */
++                      DPRINTK("9 \n");
++
++                      /*
++                       *  No new buffers to transfer, so Disable the channel
++                       */
++                      uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);
++                      uiCONTROL &= ~CONTROL_M2P_ENABLE;
++                      outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );
++              }
++      }
++
++      /*
++       *  Channel Error Interrupt, or perhipheral interrupt, specific to the
++       *  memory to/from peripheral channels.
++       */
++      if (dma_int == CHERROR) {
++              /*
++               *  just clear the interrupt, it's really up to the peripheral
++               *  driver to determine if any further action is necessary.
++               */
++              uiINTERRUPT = inl(M2P_reg_base+M2P_OFFSET_INTERRUPT);
++              uiINTERRUPT &= ~INTERRUPT_M2P_CHERRORINT;
++              outl( uiINTERRUPT, M2P_reg_base+M2P_OFFSET_INTERRUPT );
++      }
++
++      /*
++       *  Make sure the interrupt was valid, and if it was, then check
++       *  if a callback function was installed for this DMA channel.  If a
++       *  callback was installed call it.
++       */
++      if ((dma_int != UNDEF_INT) && dma->callback)
++              dma->callback(dma_int, dma->device, dma->user_data);
++
++      return IRQ_HANDLED;
++}
++
++/*****************************************************************************
++ *
++ * ep9312_dma_open_m2p(int device)
++ *
++ * Description: This function will attempt to open a M2P/P2M DMA channel.
++ *                      If the open is successful, the channel number is returned,
++ *                      otherwise a negative number is returned.
++ *
++ * Parameters:
++ *  device:    device for which the dma channel is requested.
++ *
++ ****************************************************************************/
++static int
++dma_open_m2p(int device)
++{
++      int channel = -1;
++      unsigned int loop;
++      unsigned int M2P_reg_base;
++      unsigned int uiPWRCNT;
++      /*unsigned long flags;*/
++
++      DPRINTK("DMA Open M2P with hw dev %d\n", device);
++
++      /*
++       *  Lock the dma channel list.
++       */
++      //spin_lock_irqsave(&dma_list_lock, flags);
++      spin_lock(&dma_list_lock);
++
++      /*
++       * Verify that the device requesting DMA isn't already using a DMA channel
++       */
++      if (device >= 10)
++              loop = 1;                // Rx transfer requested
++      else
++              loop = 0;                // Tx transfer requested
++
++      for (; loop < 10; loop = loop + 2)
++              /*
++               *  Before checking for a matching device, check that the
++               *  channel is in use, otherwise the device field is
++               *  invalid.
++               */
++              if (dma_chan[loop].ref_count)
++                      if (device == dma_chan[loop].device) {
++                              DPRINTK("DMA Open M2P - Error\n");
++                              return(-1);
++                      }
++
++      /*
++       *  Get a DMA channel instance for the given hardware device.
++       *  If this is a TX look for even numbered channels, else look for
++       *  odd numbered channels
++       */
++      if (device >= 10)
++              loop = 1;                /* Rx transfer requested */
++      else
++              loop = 0;                /* Tx transfer requested */
++
++      for (; loop < 10; loop = loop + 2)
++              if (!dma_chan[loop].ref_count) {
++                      /*
++                       *  Capture the channel and increment the reference count.
++                       */
++                      channel = loop;
++                      dma_chan[channel].ref_count++;
++                      break;
++              }
++
++      /*
++       *  Unlock the dma channel list.
++       */
++      //spin_unlock_irqrestore(&dma_list_lock, flags);
++      spin_unlock(&dma_list_lock);
++      /*
++       *  See if we got a valid channel.
++       */
++      if (channel < 0)
++              return(-1);
++
++      /*
++       *  Point regs to the correct dma channel register base.
++       */
++      M2P_reg_base = dma_chan[channel].reg_base;
++
++      /*
++       *  Turn on the clock for the specified DMA channel
++       *  TODO: need to use the correct register name for the
++       *  power control register.
++       */
++      uiPWRCNT = inl(/*SYSCON_PWRCNT*/EP93XX_SYSCON_CLOCK_CONTROL);
++      switch (channel) {
++      case 0:
++              uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH0;
++              break;
++
++      case 1:
++              uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH1;
++              break;
++
++      case 2:
++              uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH2;
++              break;
++
++      case 3:
++              uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH3;
++              break;
++
++      case 4:
++              uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH4;
++              break;
++
++      case 5:
++              uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH5;
++              break;
++
++      case 6:
++              uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH6;
++              break;
++
++      case 7:
++              uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH7;
++              break;
++
++      case 8:
++              uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH8;
++              break;
++
++      case 9:
++              uiPWRCNT |= SYSCON_PWRCNT_DMA_M2PCH9;
++              break;
++
++      default:
++              return(-1);
++      }
++      outl( uiPWRCNT, /*SYSCON_PWRCNT*/EP93XX_SYSCON_CLOCK_CONTROL );
++
++      /*
++       *  Clear out the control register before any further setup.
++       */
++      outl( 0, M2P_reg_base+M2P_OFFSET_CONTROL );
++
++      /*
++       *  Setup the peripheral port value in the DMA channel registers.
++       */
++      if (device < 10)
++              outl( (unsigned int)device, M2P_reg_base+M2P_OFFSET_PPALLOC );
++      else
++              outl( (unsigned int)(device - 10), M2P_reg_base+M2P_OFFSET_PPALLOC );
++
++      /*
++       *  Let's hold on to the value of the Hw device for comparison later.
++       */
++      dma_chan[channel].device = device;
++
++      /*
++       *  Success.
++       */
++      return(channel);
++}
++
++/*****************************************************************************
++ *
++ * dma_open_m2m(int device)
++ *
++ * Description: This function will attempt to open a M2M DMA channel.
++ *                      If the open is successful, the channel number is returned,
++ *                      otherwise a negative number is returned.
++ *
++ * Parameters:
++ *  device:    device for which the dma channel is requested.
++ *
++ ****************************************************************************/
++static int
++dma_open_m2m(int device)
++{
++      int channel = -1;
++      unsigned int loop;
++      unsigned int M2M_reg_base;
++      unsigned int uiPWRCNT, uiCONTROL;
++      /*unsigned long flags;*/
++
++      DPRINTK("DMA Open M2M with hw dev %d\n", device);
++
++      /*
++       *  Lock the dma channel list.
++       */
++      //spin_lock_irqsave(&dma_list_lock, flags);
++      spin_lock(&dma_list_lock);
++
++
++      /*
++       *  Check if this device is already allocated a channel.
++       *  TODO: can one M2M device be allocated multiple channels?
++       */
++      for (loop = 10; loop < 12; loop++)
++              /*
++               *  Before checking for a matching device, check that the
++               *  channel is in use, otherwise the device field is
++               *  invalid.
++               */
++              if (dma_chan[loop].ref_count)
++                      if (device == dma_chan[loop].device) {
++                              DPRINTK("Error - dma_open_m2m - already allocated channel\n");
++
++                              /*
++                               *  Unlock the dma channel list.
++                               */
++                              //spin_unlock_irqrestore(&dma_list_lock, flags);
++                              spin_unlock(&dma_list_lock);
++                              /*
++                               *  Fail.
++                               */
++                              return(-1);
++                      }
++
++      /*
++       *  Get a DMA channel instance for the given hardware device.
++       */
++      for (loop = 10; loop < 12; loop++)
++              if (!dma_chan[loop].ref_count) {
++                      /*
++                       *  Capture the channel and increment the reference count.
++                       */
++                      channel = loop;
++                      dma_chan[channel].ref_count++;
++                      break;
++              }
++
++      /*
++       *  Unlock the dma channel list.
++       */
++      //spin_unlock(dma_list_lock);
++      spin_unlock(&dma_list_lock);
++      //spin_unlock_irqrestore(&dma_list_lock, flags);
++
++      /*
++       *  See if we got a valid channel.
++       */
++      if (channel < 0)
++              return(-1);
++
++      /*
++       *  Point regs to the correct dma channel register base.
++       */
++      M2M_reg_base = dma_chan[channel].reg_base;
++
++      /*
++       *  Turn on the clock for the specified DMA channel
++       *  TODO: need to use the correct register name for the
++       *  power control register.
++       */
++      uiPWRCNT = inl(/*SYSCON_PWRCNT*/EP93XX_SYSCON_CLOCK_CONTROL);
++      switch (channel) {
++      case 10:
++              uiPWRCNT |= SYSCON_PWRCNT_DMA_M2MCH0;
++              break;
++
++      case 11:
++              uiPWRCNT |= SYSCON_PWRCNT_DMA_M2MCH1;
++              break;
++
++      default:
++              return(-1);
++      }
++      outl( uiPWRCNT, /*SYSCON_PWRCNT*/EP93XX_SYSCON_CLOCK_CONTROL);
++
++      DPRINTK("DMA Open - power control: 0x%x \n", inl(SYSCON_PWRCNT) );
++
++      /*
++       *  Clear out the control register before any further setup.
++       */
++      outl( 0, M2M_reg_base+M2M_OFFSET_CONTROL );
++
++      /*
++       *  Setup the transfer mode and the request source selection within
++       *  the DMA M2M channel registers.
++       */
++      switch (device) {
++      case DMA_MEMORY:
++              /*
++               * Clear TM field, set RSS field to 0
++               */
++              uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++              uiCONTROL &= ~(CONTROL_M2M_TM_MASK | CONTROL_M2M_RSS_MASK);
++              outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++              break;
++
++      case DMA_IDE:
++              /*
++               * Set RSS field to 3, Set NO_HDSK, Set PW field to 1
++               */
++              uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++              uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_PW_MASK);
++              uiCONTROL |= (3<<CONTROL_M2M_RSS_SHIFT) |
++                      CONTROL_M2M_NO_HDSK |
++                      (2<<CONTROL_M2M_PW_SHIFT);
++
++              uiCONTROL &= ~(CONTROL_M2M_ETDP_MASK);
++              uiCONTROL &= ~(CONTROL_M2M_DACKP);
++              uiCONTROL &= ~(CONTROL_M2M_DREQP_MASK);
++
++              outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++              inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++              break;
++
++      case DMARx_SSP:
++              /*
++               * Set RSS field to 1, Set NO_HDSK, Set TM field to 2
++               */
++              uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++              uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_TM_MASK);
++              uiCONTROL |= (1<<CONTROL_M2M_RSS_SHIFT) |
++                      CONTROL_M2M_NO_HDSK |
++                      (2<<CONTROL_M2M_TM_SHIFT);
++              outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++              break;
++
++      case DMATx_SSP:
++              /*
++               * Set RSS field to 2, Set NO_HDSK, Set TM field to 1
++               */
++              uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++              uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_TM_MASK);
++              uiCONTROL |= (2<<CONTROL_M2M_RSS_SHIFT) |
++                      CONTROL_M2M_NO_HDSK |
++                      (1<<CONTROL_M2M_TM_SHIFT);
++              outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++              break;
++
++      case DMATx_EXT_DREQ:
++              /*
++               * Set TM field to 2, set RSS field to 0
++               */
++              uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++              uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_TM_MASK);
++              uiCONTROL |= 1<<CONTROL_M2M_TM_SHIFT;
++              outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++              break;
++
++      case DMARx_EXT_DREQ:
++              /*
++               * Set TM field to 2, set RSS field to 0
++               */
++              uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++              uiCONTROL &= ~(CONTROL_M2M_RSS_MASK|CONTROL_M2M_TM_MASK);
++              uiCONTROL |= 2<<CONTROL_M2M_TM_SHIFT;
++              outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++              break;
++
++      default:
++              return -1;
++      }
++
++      /*
++       *  Let's hold on to the value of the Hw device for comparison later.
++       */
++      dma_chan[channel].device = device;
++
++      /*
++       *  Success.
++       */
++      return(channel);
++}
++
++/*****************************************************************************
++ *
++ *  int dma_config_m2m(ep93xx_dma_t * dma, unsigned int flags_m2m,
++ *                       dma_callback callback, unsigned int user_data)
++ *
++ *  Description: Configure the DMA channel and install a callback function.
++ *                       This function will have to be called for every transfer
++ *
++ *  dma:              Pointer to the dma instance data for the M2M channel to
++ *                      configure.
++ *  flags_m2m   Flags used to configure an M2M dma channel and determine
++ *                      if a callback function and user_data information are included
++ *                      in this call.
++ *  callback  function pointer which is called near the end of the
++ *                      dma channel's irq handler.
++ *  user_data   defined by the calling driver.
++ *
++ ****************************************************************************/
++static int
++dma_config_m2m(ep93xx_dma_t * dma, unsigned int flags_m2m,
++                         dma_callback callback, unsigned int user_data)
++{
++      unsigned long flags;
++      unsigned int M2M_reg_base, uiCONTROL;
++
++      /*
++       *  Make sure the channel is disabled before configuring the channel.
++       *
++       *  TODO: Is this correct??   Making a big change here...
++       */
++      /* if (!dma->pause || (!dma->pause && dma->xfer_enable)) */
++      if (dma->xfer_enable) {
++              /*
++               *  DMA channel is not paused, so we can't configure it.
++               */
++              DPRINTK("DMA channel not paused, so can't configure! \n");
++              return(-1);
++      }
++
++      /*
++       *  Mask interrupts.
++       */
++      local_irq_save(flags);
++
++      /*
++       *  Setup a pointer into the dma channel's register set.
++       */
++      M2M_reg_base = dma->reg_base;
++
++      uiCONTROL = inl(M2M_reg_base + M2M_OFFSET_CONTROL);
++      outl(0, M2M_reg_base + M2M_OFFSET_CONTROL);
++      inl(M2M_reg_base + M2M_OFFSET_CONTROL);
++      outl(uiCONTROL, M2M_reg_base + M2M_OFFSET_CONTROL);
++
++      /*
++       *  By default we disable the stall interrupt.
++       */
++      uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++      uiCONTROL &= ~CONTROL_M2M_STALLINTEN;
++      outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++
++      /*
++       *  By default we disable the done interrupt.
++       */
++      uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++      uiCONTROL &= ~CONTROL_M2M_DONEINTEN;
++      outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++
++      /*
++       *  Set up the transfer control fields based on values passed in
++       *  the flags_m2m field.
++       */
++      uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++
++      if ( flags_m2m & DESTINATION_HOLD )
++              uiCONTROL |= CONTROL_M2M_DAH;
++      else
++              uiCONTROL &= ~CONTROL_M2M_DAH;
++
++      if ( flags_m2m & SOURCE_HOLD )
++              uiCONTROL |= CONTROL_M2M_SAH;
++      else
++              uiCONTROL &= ~CONTROL_M2M_SAH;
++
++      uiCONTROL &= ~CONTROL_M2M_TM_MASK;
++      uiCONTROL |= (((flags_m2m & TRANSFER_MODE_MASK) >> TRANSFER_MODE_SHIFT) <<
++                                CONTROL_M2M_TM_SHIFT) & CONTROL_M2M_TM_MASK;
++
++      uiCONTROL &= ~CONTROL_M2M_PWSC_MASK;
++      uiCONTROL |= (((flags_m2m & WAIT_STATES_MASK) >> WAIT_STATES_SHIFT) <<
++                                CONTROL_M2M_PWSC_SHIFT) & CONTROL_M2M_PWSC_MASK;
++
++      outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++      inl(M2M_reg_base + M2M_OFFSET_CONTROL);
++
++      /*
++       *  Save the callback function in the dma instance for this channel.
++       */
++      dma->callback = callback;
++
++      /*
++       *  Save the user data in the the dma instance for this channel.
++       */
++      dma->user_data = user_data;
++
++      /*
++       *  Put the dma instance into the pause state by setting the
++       *  pause bit to true.
++       */
++      dma->pause = TRUE;
++
++      local_irq_restore(flags);
++
++      /*
++       *  Success.
++       */
++      return(0);
++}
++
++/*****************************************************************************
++ *
++ *  int dma_start(int handle, unsigned int channels, unsigned int * handles)
++ *
++ *  Description: Initiate a transfer on up to 3 channels.
++ *
++ *  handle:    handle for the channel to initiate transfer on.
++ *  channels:   number of channels to initiate transfers on.
++ *  handles:  pointer to an array of handles, one for each channel which
++ *                       is to be started.
++ *
++ ****************************************************************************/
++static int
++dma_start_m2m(int channel, ep93xx_dma_t * dma)
++{
++      unsigned long flags;
++      unsigned int M2M_reg_base = dma->reg_base;
++      unsigned int uiCONTROL;
++
++      /*
++       *  Mask interrupts while we get this started.
++       */
++      local_irq_save(flags);
++
++      /*
++       *  Make sure the channel has at least one buffer in the queue.
++       */
++      if (dma->new_buffers < 1) {
++              /*
++               *  Unmask irqs
++               */
++              local_irq_restore(flags);
++
++              DPRINTK("DMA Start: Channel starved.\n");
++
++              /*
++               *  This channel does not have enough buffers queued up,
++               *  so enter the pause by starvation state.
++               */
++              dma->xfer_enable = TRUE;
++              dma->pause = TRUE;
++
++              /*
++               *  Success.
++               */
++              return(0);
++      }
++
++      /*
++       *  Clear any pending interrupts.
++       */
++      outl(0x0, M2M_reg_base+M2M_OFFSET_INTERRUPT);
++
++      /*
++       *  Set up one or both buffer descriptors with values from the next one or
++       *  two buffers in the queue.  By default disable the next frame buffer
++       *  interrupt on the channel.
++       */
++      uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++      uiCONTROL &= ~CONTROL_M2M_NFBINTEN;
++      outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++
++      /*
++       * enable the done interrupt.
++       */
++      uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++      uiCONTROL |= CONTROL_M2M_DONEINTEN;
++      outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++
++      /*
++       *  Update the dma channel instance transfer state.
++       */
++      dma->xfer_enable = TRUE;
++      dma->pause = FALSE;
++
++      /*
++       *  Program up the first buffer descriptor with a source and destination
++       *  and a byte count.
++       */
++      outl( dma->buffer_queue[dma->current_buffer].source,
++            M2M_reg_base+M2M_OFFSET_SAR_BASE0 );
++
++      outl( dma->buffer_queue[dma->current_buffer].dest,
++            M2M_reg_base+M2M_OFFSET_DAR_BASE0 );
++
++      outl( dma->buffer_queue[dma->current_buffer].size,
++            M2M_reg_base+M2M_OFFSET_BCR0 );
++
++      /*
++       *  Decrement the new buffers counter.
++       */
++      dma->new_buffers--;
++
++      /*
++       * Set up the second buffer descriptor with a second buffer if we have
++       * a second buffer.
++       */
++      if (dma->new_buffers) {
++              outl( dma->buffer_queue[(dma->current_buffer + 1) %
++                                      MAX_EP93XX_DMA_BUFFERS].source,
++                    M2M_reg_base+M2M_OFFSET_SAR_BASE1 );
++
++              outl( dma->buffer_queue[(dma->current_buffer + 1) %
++                                      MAX_EP93XX_DMA_BUFFERS].dest,
++                    M2M_reg_base+M2M_OFFSET_DAR_BASE1 );
++
++              outl( dma->buffer_queue[(dma->current_buffer + 1) %
++                                      MAX_EP93XX_DMA_BUFFERS].size,
++                    M2M_reg_base+M2M_OFFSET_BCR1 );
++
++              uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++              uiCONTROL |= CONTROL_M2M_NFBINTEN;
++              outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++
++              dma->new_buffers--;
++      }
++
++      /*
++       *  Now we enable the channel.  This initiates the transfer.
++       */
++      uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++      uiCONTROL |= CONTROL_M2M_ENABLE;
++      outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++      inl(M2M_reg_base + M2M_OFFSET_CONTROL);
++
++      /*
++       *  If this is a memory to memory transfer, we need to s/w trigger the
++       *  transfer by setting the start bit within the control register.
++       */
++      if (dma->device == DMA_MEMORY) {
++              uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++              uiCONTROL |= CONTROL_M2M_START;
++              outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++      }
++
++      DPRINTK("DMA - It's been started!!");
++      DPRINTK("CONTROL - 0x%x \n",    inl(M2M_reg_base+M2M_OFFSET_CONTROL) );
++      DPRINTK("STATUS - 0x%x \n",      inl(M2M_reg_base+M2M_OFFSET_STATUS) );
++      DPRINTK("BCR0 - 0x%x \n",          dma->buffer_queue[dma->current_buffer].size);
++      DPRINTK("SAR_BASE0 - 0x%x \n",  inl(M2M_reg_base+M2M_OFFSET_SAR_BASE0) );
++      DPRINTK("SAR_CUR0 - 0x%x \n",   inl(M2M_reg_base+M2M_OFFSET_SAR_CURRENT0) );
++      DPRINTK("DAR_BASE0 - 0x%x \n",  inl(M2M_reg_base+M2M_OFFSET_DAR_BASE0) );
++      DPRINTK("DAR_CUR0 - 0x%x \n",   inl(M2M_reg_base+M2M_OFFSET_DAR_CURRENT0) );
++
++      /*
++       *  Unmask irqs
++       */
++      local_irq_restore(flags);
++
++      /*
++       *  Success.
++       */
++      return(0);
++}
++
++/*****************************************************************************
++ *
++ *  DMA interface functions
++ *
++ ****************************************************************************/
++
++/*****************************************************************************
++ *
++ *  int dma_init(int handle, unsigned int flags_m2p, unsigned int flags_m2m,
++ *                       dma_callback callback, unsigned int user_data)
++ *
++ *  Description: Configure the DMA channel and install a callback function.
++ *
++ *  handle:    Handle unique the each instance of the dma interface, used
++ *                      to verify this call.
++ *  flags_m2p   Flags used to configure an M2P/P2M dma channel and determine
++ *                      if a callback function and user_data information are included
++ *                      in this call. This field should be NULL if handle represents
++ *                      an M2M channel.
++ *  flags_m2m   Flags used to configure an M2M dma channel and determine
++ *                      if a callback function and user_data information are included
++ *                      in this call. This field should be NULL if handle represents
++ *                      an M2P/P2M channel.
++ *  callback  function pointer which is called near the end of the
++ *                      dma channel's irq handler.
++ *  user_data   defined by the calling driver.
++ *
++ ****************************************************************************/
++int
++ep93xx_dma_config(int handle, unsigned int flags_m2p, unsigned int flags_m2m,
++                dma_callback callback, unsigned int user_data)
++{
++      int  channel;
++      ep93xx_dma_t * dma;
++      unsigned long flags;
++      unsigned int M2P_reg_base, uiCONTROL;
++
++      /*
++       *  Get the DMA hw channel # from the handle.
++       */
++      channel = dma_get_channel_from_handle(handle);
++
++      /*
++       *  See if this is a valid handle.
++       */
++      if (channel < 0) {
++              printk(KERN_ERR
++                         "DMA Config: Invalid dma handle.\n");
++              return(-EINVAL);
++      }
++
++      DPRINTK("DMA Config \n");
++
++      dma = &dma_chan[channel];
++
++      local_irq_save(flags);
++
++      /*
++       *  Check if the channel is currently transferring.
++       */
++      if (dma->xfer_enable) {
++              local_irq_restore(flags);
++              return(-EINVAL);
++      }
++
++      /*
++       *  Check if this is an m2m function.
++       */
++      if (channel >= 10) {
++              local_irq_restore(flags);
++
++              /*
++               *  Call another function to handle m2m config.
++               */
++              return(dma_config_m2m(dma, flags_m2m, callback, user_data));
++      }
++
++      /*
++       *  Setup a pointer into the dma channel's register set.
++       */
++      M2P_reg_base = dma->reg_base;
++
++      /*
++       *  By default we enable the stall interrupt.
++       */
++      uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);
++      uiCONTROL |= CONTROL_M2P_STALLINTEN;
++      outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );
++
++      /*
++       *  Configure the channel for an error from the peripheral.
++       */
++      uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);
++      if ( flags_m2p && CHANNEL_ERROR_INT_ENABLE )
++              uiCONTROL |= CONTROL_M2P_CHERRORINTEN;
++      else
++              uiCONTROL &= ~CONTROL_M2P_CHERRORINTEN;
++      outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );
++
++      uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);
++      if ( flags_m2p && CHANNEL_ABORT )
++              uiCONTROL |= CONTROL_M2P_ABRT;
++      else
++              uiCONTROL &= ~CONTROL_M2P_ABRT;
++      outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );
++
++      uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);
++      if ( flags_m2p && IGNORE_CHANNEL_ERROR )
++              uiCONTROL |= CONTROL_M2P_ICE;
++      else
++              uiCONTROL &= ~CONTROL_M2P_ICE;
++      outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );
++
++      /*
++       *  Save the callback function in the dma instance for this channel.
++       */
++      dma->callback = callback;
++
++      /*
++       *  Save the user data in the the dma instance for this channel.
++       */
++      dma->user_data = user_data;
++
++      /*
++       *  Put the dma instance into the pause state by setting the
++       *  pause bit to true.
++       */
++      dma->pause = TRUE;
++
++      local_irq_restore(flags);
++
++      /*
++       *  Success.
++       */
++      return(0);
++}
++
++/*****************************************************************************
++ *
++ *  int dma_start(int handle, unsigned int channels, unsigned int * handles)
++ *
++ *  Description: Initiate a transfer on up to 3 channels.
++ *
++ *  handle:    handle for the channel to initiate transfer on.
++ *  channels:   number of channels to initiate transfers on.
++ *  handles:  pointer to an array of handles, one for each channel which
++ *                       is to be started.
++ *
++ ****************************************************************************/
++int
++ep93xx_dma_start(int handle, unsigned int channels, unsigned int * handles)
++{
++      ep93xx_dma_t * dma_pointers[3];
++      unsigned int M2P_reg_bases[3];
++      unsigned int loop, uiCONTROL;
++      unsigned long flags;
++      int  channel;
++
++      /*
++       *  Get the DMA hw channel # from the handle.
++       */
++      channel = dma_get_channel_from_handle(handle);
++
++      /*
++       *  See if this is a valid handle.
++       */
++      if (channel < 0) {
++              printk(KERN_ERR "DMA Start: Invalid dma handle.\n");
++              return(-EINVAL);
++      }
++
++      if (channels < 1) {
++              printk(KERN_ERR "DMA Start: Invalid parameter.\n");
++              return(-EINVAL);
++      }
++
++      DPRINTK("DMA Start \n");
++
++      /*
++       *  Mask off registers.
++       */
++      local_irq_save(flags);
++
++      /*
++       *  Check if this is a start multiple.
++       */
++      if (channels > 1) {
++              DPRINTK("DMA ERROR: Start, multiple start not supported yet \n");
++              return(-1);
++      } else {
++              /*
++               *  Check if this channel is already transferring.
++               */
++              if (dma_chan[channel].xfer_enable && !dma_chan[channel].pause) {
++                      printk(KERN_ERR
++                                 "DMA Start: Invalid command for channel %d.\n", channel);
++
++                      /*
++                       *  Unmask irqs
++                       */
++                      local_irq_restore(flags);
++
++                      /*
++                       *  This channel is already transferring, so return an error.
++                       */
++                      return(-EINVAL);
++              }
++
++              /*
++               *  If this is an M2M channel, call a different function.
++               */
++              if (channel >= 10) {
++                      /*
++                       *  Unmask irqs
++                       */
++                      local_irq_restore(flags);
++
++                      /*
++                       *  Call the m2m start function.  Only start one channel.
++                       */
++                      return(dma_start_m2m(channel, &dma_chan[channel]));
++              }
++
++              /*
++               *  Make sure the channel has at least one buffer in the queue.
++               */
++              if (dma_chan[channel].new_buffers < 1) {
++                      DPRINTK("DMA Start: Channel starved.\n");
++
++                      /*
++                       *  This channel does not have enough buffers queued up,
++                       *  so enter the pause by starvation state.
++                       */
++                      dma_chan[channel].xfer_enable = TRUE;
++                      dma_chan[channel].pause = TRUE;
++
++                      /*
++                       *  Unmask irqs
++                       */
++                      local_irq_restore(flags);
++
++                      /*
++                       *  Success.
++                       */
++                      return(0);
++              }
++
++              /*
++               *  Set up a dma instance pointer for this dma channel.
++               */
++              dma_pointers[0] = &dma_chan[channel];
++
++              /*
++               * Set up a pointer to the register set for this channel.
++               */
++              M2P_reg_bases[0] = dma_pointers[0]->reg_base;
++      }
++
++      /*
++       *  Setup both MAXCNT registers with values from the next two buffers
++       *  in the queue, and enable the next frame buffer interrupt on the channel.
++       */
++      for (loop = 0; loop < channels; loop++) {
++              /*
++               *  Check if we need to restore a paused transfer.
++               */
++              if (dma_pointers[loop]->pause_buf.buf_id != -1)
++                      outl( dma_pointers[loop]->pause_buf.size,
++                            M2P_reg_bases[loop]+M2P_OFFSET_MAXCNT0 );
++              else
++                      outl( dma_pointers[loop]->buffer_queue[dma_pointers[loop]->current_buffer].size,
++                            M2P_reg_bases[loop]+M2P_OFFSET_MAXCNT0 );
++      }
++
++      for (loop = 0; loop < channels; loop++) {
++              /*
++               *  Enable the specified dma channels.
++               */
++              uiCONTROL = inl(M2P_reg_bases[loop]+M2P_OFFSET_CONTROL);
++              uiCONTROL |= CONTROL_M2P_ENABLE;
++              outl( uiCONTROL, M2P_reg_bases[loop]+M2P_OFFSET_CONTROL );
++
++              /*
++               *  Update the dma channel instance transfer state.
++               */
++              dma_pointers[loop]->xfer_enable = TRUE;
++              dma_pointers[loop]->pause = FALSE;
++      }
++
++      /*
++       *  Program up the BASE0 registers for all specified channels, this
++       *  will initiate transfers on all specified channels.
++       */
++      for (loop = 0; loop < channels; loop++)
++              /*
++               *  Check if we need to restore a paused transfer.
++               */
++              if (dma_pointers[loop]->pause_buf.buf_id != -1) {
++                      outl( dma_pointers[loop]->pause_buf.source,
++                            M2P_reg_bases[loop]+M2P_OFFSET_BASE0 );
++
++                      /*
++                       *  Set the pause buffer to NULL
++                       */
++                      dma_pointers[loop]->pause_buf.buf_id = -1;
++                      dma_pointers[loop]->pause_buf.size = 0;
++              } else if(dma_pointers[loop]->new_buffers){
++                      outl( dma_pointers[loop]->buffer_queue[
++                                dma_pointers[loop]->current_buffer].source,
++                            M2P_reg_bases[loop]+M2P_OFFSET_BASE0 );
++            dma_pointers[loop]->new_buffers--;
++
++          }
++
++      /*
++       *  Before restoring irqs setup the second MAXCNT/BASE
++       *  register with a second buffer.
++       */
++      for (loop = 0; loop < channels; loop++)
++              if (dma_pointers[loop]->new_buffers) {
++              /*
++               *  By default we enable the next frame buffer interrupt.
++               */
++              uiCONTROL = inl(M2P_reg_bases[loop]+M2P_OFFSET_CONTROL);
++              uiCONTROL |= CONTROL_M2P_NFBINTEN;
++              outl( uiCONTROL, M2P_reg_bases[loop]+M2P_OFFSET_CONTROL );
++
++                      outl( dma_pointers[loop]->buffer_queue[
++                                (dma_pointers[loop]->current_buffer + 1) %
++                                MAX_EP93XX_DMA_BUFFERS].size,
++                            M2P_reg_bases[loop]+M2P_OFFSET_MAXCNT1 );
++
++                      outl( dma_pointers[loop]->buffer_queue[
++                                (dma_pointers[loop]->current_buffer + 1) %
++                                MAX_EP93XX_DMA_BUFFERS].source,
++                            M2P_reg_bases[loop]+M2P_OFFSET_BASE1 );
++            dma_pointers[loop]->new_buffers--;
++              }
++
++      /*
++        DPRINTK("DMA - It's been started!!");
++        DPRINTK("STATUS - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_STATUS) );
++        DPRINTK("CONTROL - 0x%x \n",  inl(M2P_reg_base+M2P_OFFSET_CONTROL) );
++        DPRINTK("REMAIN - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_REMAIN) );
++        DPRINTK("PPALLOC - 0x%x \n",  inl(M2P_reg_base+M2P_OFFSET_PPALLOC) );
++        DPRINTK("BASE0 - 0x%x \n",      inl(M2P_reg_base+M2P_OFFSET_BASE0) );
++        DPRINTK("MAXCNT0 - 0x%x \n",  inl(M2P_reg_base+M2P_OFFSET_MAXCNT0) );
++        DPRINTK("CURRENT0 - 0x%x \n",   inl(M2P_reg_base+M2P_OFFSET_CURRENT0) );
++        DPRINTK("BASE1 - 0x%x \n",      inl(M2P_reg_base+M2P_OFFSET_BASE1) );
++        DPRINTK("MAXCNT1 - 0x%x \n",  inl(M2P_reg_base+M2P_OFFSET_MAXCNT1) );
++        DPRINTK("CURRENT1 - 0x%x \n",   inl(M2P_reg_base+M2P_OFFSET_CURRENT1) );
++
++        DPRINTK("Pause - %d \n", dma_pointers[0]->pause);
++        DPRINTK("xfer_enable - %d \n", dma_pointers[0]->xfer_enable);
++        DPRINTK("total bytes - 0x%x \n", dma_pointers[0]->total_bytes);
++        DPRINTK("total buffer - %d \n", dma_pointers[0]->total_buffers);
++        DPRINTK("new buffers - %d \n", dma_pointers[0]->new_buffers);
++        DPRINTK("current buffer - %d \n", dma_pointers[0]->current_buffer);
++        DPRINTK("last buffer - %d \n", dma_pointers[0]->last_buffer);
++        DPRINTK("used buffers - %d \n", dma_pointers[0]->used_buffers);
++      */
++      /*
++       *  Unmask irqs
++       */
++      local_irq_restore(flags);
++
++      /*
++       *  Success.
++       */
++      return(0);
++}
++
++/*****************************************************************************
++ *
++ *  int ep93xx_dma_add_buffer(int handle, unsigned int * address,
++ *                                             unsigned int size, unsigned int last)
++ *
++ *  Description: Add a buffer entry to the DMA buffer queue.
++ *
++ *  handle:    handle for the channel to add this buffer to.
++ *  address:  Pointer to an integer which is the start address of the
++ *                      buffer which is to be added to the queue.
++ *  size:        size of the buffer in bytes.
++ *  last:        1 if this is the last buffer in this stream, 0 otherwise.
++ *
++ ****************************************************************************/
++int
++ep93xx_dma_add_buffer(int handle, unsigned int source, unsigned int dest,
++                    unsigned int size, unsigned int last,
++                    unsigned int buf_id)
++{
++      unsigned long flags;
++      ep93xx_dma_t * dma;
++      int  channel;
++#if 0
++      static int peak_total_buffers=0;
++#endif
++      /*
++       *  Get the DMA hw channel # from the handle.
++       */
++      channel = dma_get_channel_from_handle(handle);
++
++      /*
++       *  See if this is a valid handle.
++       */
++      if (channel < 0) {
++              printk(KERN_ERR
++                         "DMA Add Buffer: Invalid dma handle.\n");
++              return(-EINVAL);
++      }
++
++      /*
++       *  Get a pointer to the dma instance.
++       */
++      dma = &dma_chan[channel];
++
++#if 0
++      if( dma->total_buffers > peak_total_buffers )
++      {
++          peak_total_buffers=dma->total_buffers;
++          printk("peak_total_buffers=%d\n", peak_total_buffers );
++      }
++#endif
++      /*
++       *  Mask interrupts and hold on to the original state.
++       */
++      local_irq_save(flags);
++
++      /*
++       *  If the buffer queue is full, last_buffer is the same as current_buffer and
++       *  we're not tranfering, or last_buffer is pointing to a used buffer, then exit.
++       *  TODO: do I need to do any more checks?
++       */
++      if (dma->total_buffers >= MAX_EP93XX_DMA_BUFFERS)
++      {
++              DPRINTK("too many dma buffers: MAX_EP93XX_DMA_BUFFERS set to low ?\n");
++              /*
++               *  Restore the state of the irqs
++               */
++              local_irq_restore(flags);
++
++              /*
++               *  Fail.
++               */
++              return(-1);
++      }
++
++      /*
++       *  Add this buffer to the queue
++       */
++      dma->buffer_queue[dma->last_buffer].source = source;
++      dma->buffer_queue[dma->last_buffer].dest = dest;
++      dma->buffer_queue[dma->last_buffer].size = size;
++      dma->buffer_queue[dma->last_buffer].last = last;
++      dma->buffer_queue[dma->last_buffer].buf_id = buf_id;
++
++      /*
++       *  Reset the used field of the buffer structure.
++       */
++      dma->buffer_queue[dma->last_buffer].used = FALSE;
++
++      /*
++       *  Increment the End Item Pointer.
++       */
++      dma->last_buffer = (dma->last_buffer + 1) % MAX_EP93XX_DMA_BUFFERS;
++
++      /*
++       *  Increment the new buffers counter and the total buffers counter
++       */
++      dma->new_buffers++;
++      dma->total_buffers++;
++
++      /*
++       *  restore the interrupt state.
++       */
++      local_irq_restore(flags);
++
++      /*
++       *  Check if the channel was starved into a stopped state.
++       */
++      if (dma->pause && dma->xfer_enable) {
++              if (dma->new_buffers >= 1) {
++                      DPRINTK("DMA - calling start from add after starve. \n");
++
++                      /*
++                       *  The channel was starved into a stopped state, and we've got
++                       *  2 new buffers, so start tranferring again.
++                       */
++                      ep93xx_dma_start(handle, 1, 0);
++              }
++      }
++
++      /*
++       *  Success.
++       */
++      return(0);
++}
++
++/*****************************************************************************
++ *
++ *  int ep93xx_dma_remove_buffer(int handle, unsigned int * address,
++ *                                                            unsigned int * size)
++ *
++ *  Description: Remove a buffer entry from the DMA buffer queue. If
++ *                       buffer was removed successfully, return 0, otherwise
++ *                       return -1.
++ *
++ *  handle:    handle for the channel to remove a buffer from.
++ *  address:  Pointer to an integer which is filled in with the start
++ *                      address of the removed buffer.
++ *  size:        Pointer to an integer which is filled in with the size in
++ *                      bytes of the removed buffer.
++ *
++ ****************************************************************************/
++int
++ep93xx_dma_remove_buffer(int handle, unsigned int * buf_id)
++{
++      unsigned int test;
++      unsigned int loop;
++      int return_val = -1;
++      unsigned long flags;
++      ep93xx_dma_t *dma;
++      int  channel;
++
++      /*
++       *  Get the DMA hw channel # from the handle.
++       */
++      channel = dma_get_channel_from_handle(handle);
++
++      /*
++       *  See if this is a valid handle.
++       */
++      if (channel < 0) {
++              printk(KERN_ERR
++                         "DMA Remove Buffer: Invalid dma handle.\n");
++              return(-EINVAL);
++      }
++
++      dma = &dma_chan[channel];
++
++      /*
++       *  Mask interrupts and hold on to the original state.
++       */
++      local_irq_save(flags);
++
++      /*
++       *  Make sure there are used buffers to be returned.
++       */
++      if (dma->used_buffers) {
++              test = dma->last_buffer;
++
++              for (loop = 0; loop < MAX_EP93XX_DMA_BUFFERS; loop++) {
++                      if (dma->buffer_queue[test].used && (dma->buffer_queue[test].buf_id != -1)) {
++                              /*DPRINTK("buffer %d used \n", test); */
++
++                              /*
++                               *  This is a used buffer, fill in the buf_id pointer
++                               *  with the buf_id for this buffer.
++                               */
++                              *buf_id = dma->buffer_queue[test].buf_id;
++
++                              /*
++                               *  Reset this buffer structure
++                               */
++                              dma->buffer_queue[test].buf_id = -1;
++
++                              /*
++                               *  Decrement the used buffer counter, and the total buffer counter.
++                               */
++                              dma->used_buffers--;
++                              dma->total_buffers--;
++
++                              /*
++                               *  Successful removal of a buffer, so set the return
++                               *  value to 0, then exit this loop.
++                               */
++                              return_val = 0;
++                              break;
++                      }
++
++                      /*
++                       *  This buffer isn't used, let's see if the next one is.
++                       */
++                      test = (test + 1) % MAX_EP93XX_DMA_BUFFERS;
++              }
++      }
++
++      /*
++       *  Restore interrupts.
++       */
++      local_irq_restore(flags);
++
++      /*
++       *  Success.
++       */
++      return(return_val);
++}
++
++/*****************************************************************************
++ *
++ *  int ep93xx_dma_pause(int handle, unsigned int channels,
++ *                                       unsigned int * handles)
++ *
++ *  Description: Disable any ongoing transfer for the given channel, retaining
++ *                       the state of the current buffer transaction so that upon
++ *                       resume, the dma will continue where it left off.
++ *
++ *  handle:    Handle for the channel to be paused.  If this is a pause for
++ *                      for multiple channels, handle is a valid handle for one of
++ *                      the channels to be paused.
++ *  channels:   number of channel to pause transfers on.
++ *  handles:  Pointer to an array of handles, one for each channel which
++ *                      to be paused.  If this pause is intended only for one
++ *                      channel, this field should be set to NULL.
++ *
++ ****************************************************************************/
++int
++ep93xx_dma_pause(int handle, unsigned int channels, unsigned int * handles)
++{
++      unsigned long flags;
++      ep93xx_dma_t * dma;
++      int channel;
++
++      DPRINTK("ep93xx_dma_pause \n");
++
++      /*
++       *  Mask interrupts and hold on to the original state.
++       */
++      local_irq_save(flags);
++
++      /*
++       *  Get the DMA hw channel # from the handle.
++       */
++      channel = dma_get_channel_from_handle(handle);
++
++      /*
++       *  See if this is a valid handle.
++       */
++      if (channel < 0) {
++              /*
++               *  restore interrupts.
++               */
++              local_irq_restore(flags);
++
++              printk(KERN_ERR
++                         "DMA Pause: Invalid dma handle.\n");
++
++              /*
++               *  Fail.
++               */
++              return(-EINVAL);
++      }
++
++      DPRINTK("DMA %d: pause \n", channel);
++
++      /*
++       *  Set up a pointer to the dma instance data.
++       */
++      dma = &dma_chan[channel];
++
++      /*
++       *  Check if we're already paused.
++       */
++      if (dma->pause) {
++              /*
++               *  We're paused, but are we stopped?
++               */
++              if (dma->xfer_enable)
++                      /*
++                       *  Put the channel in the stopped state.
++                       */
++                      dma->xfer_enable = FALSE;
++
++              DPRINTK("DMA Pause - already paused.");
++      } else {
++              /*
++               *  Put the channel into the stopped state.
++               */
++              dma->xfer_enable = FALSE;
++              dma->pause = TRUE;
++      }
++
++      /*
++       *  restore interrupts.
++       */
++      local_irq_restore(flags);
++
++      /*
++       *  Already paused, so exit.
++       */
++      return(0);
++}
++
++/*****************************************************************************
++ *
++ *  void ep93xx_dma_flush(int handle)
++ *
++ *  Description: Flushes all queued buffers and transfers in progress
++ *                       for the given channel.  Return the buffer entries
++ *                       to the calling function.
++ *
++ *  handle:    handle for the channel for which the flush is intended.
++ *
++ ****************************************************************************/
++int
++ep93xx_dma_flush(int handle)
++{
++      unsigned int loop;
++      unsigned long flags;
++      ep93xx_dma_t * dma;
++      int  channel;
++      unsigned int M2P_reg_base,uiCONTROL;
++
++      /*
++       *  Get the DMA hw channel # from the handle.
++       */
++      channel = dma_get_channel_from_handle(handle);
++
++      /*
++       *  See if this is a valid handle.
++       */
++      if (channel < 0) {
++              printk(KERN_ERR "DMA Flush: Invalid dma handle.\n");
++              return(-EINVAL);
++      }
++
++      DPRINTK("DMA %d: flush \n", channel);
++
++      /*
++       *  Set up a pointer to the dma instance data for this channel
++       */
++      dma = &dma_chan[channel];
++
++      /*
++       *  Mask interrupts and hold on to the original state.
++       */
++      local_irq_save(flags);
++
++      /*
++       *  Disable the dma channel
++       */
++      if (channel < 10) {
++              /*
++               *  M2P channel
++               */
++              uiCONTROL = inl(dma->reg_base+M2P_OFFSET_CONTROL);
++              uiCONTROL &= ~CONTROL_M2P_ENABLE;
++              outl( uiCONTROL, dma->reg_base+M2P_OFFSET_CONTROL );
++      } else {
++              /*
++               *  M2M channel
++               */
++              uiCONTROL = inl(dma->reg_base+M2M_OFFSET_CONTROL);
++              uiCONTROL &= ~CONTROL_M2M_ENABLE;
++              outl( uiCONTROL, dma->reg_base+M2M_OFFSET_CONTROL );
++      }
++
++      for (loop = 0; loop < MAX_EP93XX_DMA_BUFFERS; loop++)
++      {
++              dma->buffer_queue[loop].buf_id = -1;
++              dma->buffer_queue[loop].last = 0;
++      }
++
++      /*
++       *  Set the Current and Last item to zero.
++       */
++      dma->current_buffer = 0;
++      dma->last_buffer = 0;
++
++      /*
++       *  Reset the Buffer counters
++       */
++      dma->used_buffers = 0;
++      dma->new_buffers = 0;
++      dma->total_buffers = 0;
++
++      /*
++       *  reset the Total bytes counter.
++       */
++      dma->total_bytes = 0;
++
++    /*
++     * Reset the paused buffer.
++     */
++     dma->pause_buf.last = 0;
++     dma->pause_buf.buf_id = -1;
++
++      M2P_reg_base = dma_chan[channel].reg_base;
++
++      /*
++       *  restore interrupts.
++       */
++      local_irq_restore(flags);
++
++      /*
++       *  Success.
++       */
++      return(0);
++}
++
++/*****************************************************************************
++ *
++ *  int ep93xx_dma_queue_full(int handle)
++ *
++ *  Description: Query to determine if the DMA queue of buffers for
++ *                      a given channel is full.
++ *                      0 = queue is full
++ *                      1 = queue is not full
++ *
++ *  handle:    handle for the channel to query.
++ *
++ ****************************************************************************/
++int
++ep93xx_dma_queue_full(int handle)
++{
++      int list_full = 0;
++      unsigned long flags;
++      int  channel;
++
++      /*
++       *  Get the DMA hw channel # from the handle.
++       */
++      channel = dma_get_channel_from_handle(handle);
++
++      /*
++       *  See if this is a valid handle.
++       */
++      if (channel < 0) {
++              printk(KERN_ERR "DMA Queue Full: Invalid dma handle.\n");
++              return(-EINVAL);
++      }
++
++      DPRINTK("DMA %d: queue full \n", channel);
++
++      /*
++       *  Mask interrupts and hold on to the original state.
++       */
++      local_irq_save(flags);
++
++      /*
++       *  If the last item is equal to the used item then
++       *  the queue is full.
++       */
++      if (dma_chan[channel].total_buffers < MAX_EP93XX_DMA_BUFFERS)
++              list_full =  FALSE;
++      else
++              list_full = TRUE;
++
++      /*
++       *  restore interrupts.
++       */
++      local_irq_restore(flags);
++
++      return(list_full);
++}
++
++/*****************************************************************************
++ *
++ *  int ep93xx_dma_get_position()
++ *
++ *  Description:  Takes two integer pointers and fills them with the start
++ *                and current address of the buffer currently transferring
++ *                on the specified DMA channel.
++ *
++ *  handle         handle for the channel to query.
++ *  *buf_id        buffer id for the current buffer transferring on the
++ *                 dma channel.
++ *  *total         total bytes transferred on the channel.  Only counts
++ *                 whole buffers transferred.
++ *  *current_frac  number of bytes transferred so far in the current buffer.
++ ****************************************************************************/
++int
++ep93xx_dma_get_position(int handle, unsigned int * buf_id,
++                        unsigned int * total, unsigned int * current_frac )
++{
++      int  channel;
++      ep93xx_dma_t * dma;
++      unsigned int buf_id1, total1, current_frac1, buf_id2, total2;
++      unsigned int Status, NextBuffer, StateIsBufNext, M2P_reg_base=0;
++      unsigned int pause1, pause2;
++
++      /*
++       *  Get the DMA hw channel # from the handle.  See if this is a
++       *  valid handle.
++       */
++      channel = dma_get_channel_from_handle(handle);
++      if (channel < 0) {
++              printk(KERN_ERR "DMA Get Position: Invalid dma handle.\n");
++              return(-EINVAL);
++      }
++
++      dma = &dma_chan[channel];
++
++      /*
++       * If DMA moves to a new buffer in the middle of us grabbing the
++       * buffer info, then do it over again.
++       */
++      do{
++              buf_id1 = dma->buffer_queue[dma->current_buffer].buf_id;
++              total1  = dma->total_bytes;
++              pause1  = dma->pause;
++
++              if (channel < 10) {
++                      // M2P
++                      M2P_reg_base = dma->reg_base;
++
++                      Status = inl(M2P_reg_base+M2P_OFFSET_STATUS);
++
++                      NextBuffer = ((Status & STATUS_M2P_NEXTBUFFER) != 0);
++
++                      StateIsBufNext = ((Status & STATUS_M2P_CURRENT_MASK) ==
++                                        STATUS_M2P_DMA_BUF_NEXT);
++
++                      if( NextBuffer ^ StateIsBufNext )
++                              current_frac1 = inl(M2P_reg_base+M2P_OFFSET_CURRENT1) -
++                                              inl(M2P_reg_base+M2P_OFFSET_BASE1);
++                      else
++                              current_frac1 = inl(M2P_reg_base+M2P_OFFSET_CURRENT0) -
++                                              inl(M2P_reg_base+M2P_OFFSET_BASE0);
++
++              } else {
++                      // M2M - TODO implement this for M2M
++                      current_frac1 = 0;
++              }
++
++              buf_id2 = dma->buffer_queue[dma->current_buffer].buf_id;
++              total2 = dma->total_bytes;
++              pause2  = dma->pause;
++
++      } while ( (buf_id1 != buf_id2) || (total1 != total2) || (pause1 != pause2) );
++
++      if (pause1)
++              current_frac1 = 0;
++
++      if (buf_id)
++              *buf_id = buf_id1;
++
++      if (total)
++              *total  = total1;
++
++      if (current_frac)
++              *current_frac = current_frac1;
++
++//    DPRINTK("DMA buf_id %d, total %d, frac %d\n", buf_id1, total1, current_frac1);
++
++      /*
++       *  Success.
++       */
++      return(0);
++}
++
++/*****************************************************************************
++ *
++ *  int ep93xx_dma_get_total(int handle)
++ *
++ *  Description:      Returns the total number of bytes transferred on the
++ *                    specified channel since the channel was requested.
++ *
++ *  handle:    handle for the channel to query.
++ *
++ ****************************************************************************/
++int
++ep93xx_dma_get_total(int handle)
++{
++      int  channel;
++
++      /*
++       *  Get the DMA hw channel # from the handle.
++       */
++      channel = dma_get_channel_from_handle(handle);
++
++      /*
++       *  See if this is a valid handle.
++       */
++      if (channel < 0) {
++              printk(KERN_ERR "DMA Get Total: Invalid dma handle.\n");
++              return(-EINVAL);
++      }
++
++      DPRINTK("DMA %d: total: %d \n", channel, dma_chan[channel].total_bytes);
++
++      /*
++       *  Return the total number of bytes transferred on this channel since
++       *  it was requested.
++       */
++      return(dma_chan[channel].total_bytes);
++}
++
++/*****************************************************************************
++ *
++ *  int ep93xx_dma_is_done(int handle)
++ *
++ *  Description:      Determines if the specified channel is done
++ *                    transferring the requested data.
++ *
++ *  handle:    handle for the channel to query.
++ *
++ ****************************************************************************/
++int
++ep93xx_dma_is_done(int handle)
++{
++      ep93xx_dma_t *dma;
++      int channel;
++
++      /*
++       *  Get the DMA hw channel # from the handle.
++       */
++      channel = dma_get_channel_from_handle(handle);
++
++      /*
++       *  See if this is a valid handle.
++       */
++      if (channel < 0) {
++              printk(KERN_ERR "ep93xx_dma_is_done: Invalid dma handle.\n");
++              return(-EINVAL);
++      }
++
++        /*
++         * Get a pointer to the DMA channel state structure.
++         */
++        dma = &dma_chan[channel];
++
++        /*
++         * See if there are any buffers remaining to be provided to the HW.
++         */
++        if (dma->new_buffers)
++            return 0;
++
++        /*
++         * See if this is a M2P or M2M channel.
++         */
++        if (channel < 10) {
++            /*
++             * If the bytes remaining register of the HW is not zero, then
++             * there is more work to be done.
++             */
++            if (inl(dma->reg_base + M2P_OFFSET_REMAIN) != 0)
++                return 0;
++        } else {
++            /*
++             * If either byte count register in the HW is not zero, then there
++             * is more work to be done.
++             */
++            if ((inl(dma->reg_base + M2M_OFFSET_BCR0) != 0) ||
++                (inl(dma->reg_base + M2M_OFFSET_BCR1) != 0))
++                return 0;
++        }
++
++        /*
++         * The DMA is complete.
++         */
++        return 1;
++}
++
++/*****************************************************************************
++ * ep93xx_dma_request
++ *
++ * Description: This function will allocate a DMA channel for a particular
++ * hardware peripheral.  Before initiating a transfer on the allocated
++ * channel, the channel must be set up and buffers have to queued up.
++ *
++ *  handle:    pointer to an integer which is filled in with a unique
++ *                      handle for this instance of the dma interface.
++ *  device_id   string with the device name, primarily used by /proc.
++ *  device      hardware device ID for which the requested dma channel will
++ *                      transfer data.
++ *
++ ****************************************************************************/
++int
++ep93xx_dma_request(int * handle, const char *device_id,
++                                 ep93xx_dma_dev_t device)
++{
++      ep93xx_dma_t *dma = NULL;
++      int channel;
++      unsigned int error = 0;
++      unsigned int loop;
++      unsigned int M2P_reg_base;
++
++      /*
++       *  Check if the device requesting a DMA channel is a valid device.
++       */
++      if ((device >= UNDEF_DMA) || (device < 0))
++              return(-ENODEV);
++
++      /*
++       *  We've got a valid hardware device requesting a DMA channel.
++       *  Now check if the device should open an M2P or M2M channel
++       */
++      if (device < 20)
++              channel = dma_open_m2p(device);
++      else
++              channel = dma_open_m2m(device);
++
++      /*
++       *  Check if we successfully opened a DMA channel
++       */
++      if (channel < 0) {
++              printk(KERN_ERR "%s: Could not open dma channel for this device.\n",
++                         device_id);
++              return(-EBUSY);
++      }
++
++      dma = &dma_chan[channel];
++
++        if(dma->terminated==1) {
++           free_irq(dma->irq, (void *) dma);
++           dma->terminated=0;
++        }
++
++      /*
++       *  Request the appropriate IRQ for the specified channel
++       */
++      if (channel < 10)
++              error = request_irq(dma->irq, dma_m2p_irq_handler,
++                                  IRQF_DISABLED, device_id, (void *) dma);
++      else
++              error = request_irq(dma->irq, &dma_m2m_irq_handler,
++                                  IRQF_DISABLED, device_id, (void *) dma);
++
++      /*
++       *  Check for any errors during the irq request
++       */
++      if (error) {
++              printk(KERN_ERR "%s: unable to request IRQ %d for DMA channel\n",
++                         device_id, dma->irq);
++              return(error);
++      }
++
++      /*
++       *  Generate a valid handle and exit.
++       *
++       *  Increment the last valid handle.
++       *  Check for wraparound (unlikely, but we like to be complete).
++       */
++      dma->last_valid_handle++;
++
++      if ( (dma->last_valid_handle & DMA_HANDLE_SPECIFIER_MASK) !=
++           (channel << 28) )
++              dma->last_valid_handle = (channel << 28) + 1;
++
++      /*
++       *  Fill in the handle pointer with a valid handle for
++       *  this dma channel instance.
++       */
++      *handle = dma->last_valid_handle;
++
++      DPRINTK("Handle for channel %d: 0x%x\n", channel, *handle);
++
++      /*
++       * Save the device ID and device name.
++       */
++      dma->device = device;
++      dma->device_id = device_id;
++
++      /*
++       *  Init all fields within the dma instance.
++       */
++      for (loop = 0; loop < MAX_EP93XX_DMA_BUFFERS; loop++)
++              dma->buffer_queue[loop].buf_id = -1;
++
++      /*
++       *  Initialize all buffer queue variables.
++       */
++      dma->current_buffer = 0;
++      dma->last_buffer = 0;
++
++      dma->new_buffers = 0;
++      dma->used_buffers = 0;
++      dma->total_buffers = 0;
++
++      /*
++       *  Initialize the total bytes variable
++       */
++      dma->total_bytes = 0;
++
++      /*
++       *  Initialize the transfer and pause state variables to 0.
++       */
++      dma->xfer_enable = 0;
++
++      dma->pause = 0;
++
++      /*
++       *  Initialize the pause buffer structure.
++       */
++      dma->pause_buf.buf_id = -1;
++
++      /*
++       *  Initialize the callback function and user data fields.
++       */
++      dma->callback = NULL;
++
++      /*
++       * User data used as a parameter for the Callback function.  The user
++       * sets up the data and sends it with the callback function.
++       */
++      dma->user_data = 0;
++
++      M2P_reg_base = dma_chan[channel].reg_base;
++
++      /*
++       *  Debugging message.
++       */
++      DPRINTK("Successfully requested dma channel %d\n", channel);
++      DPRINTK("STATUS - 0x%x \n",      inl(M2P_reg_base+M2P_OFFSET_STATUS) );
++      DPRINTK("CONTROL - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_CONTROL) );
++      DPRINTK("REMAIN - 0x%x \n",      inl(M2P_reg_base+M2P_OFFSET_REMAIN) );
++      DPRINTK("PPALLOC - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_PPALLOC) );
++      DPRINTK("BASE0 - 0x%x \n",        inl(M2P_reg_base+M2P_OFFSET_BASE0) );
++      DPRINTK("MAXCNT0 - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_MAXCNT0) );
++      DPRINTK("CURRENT0 - 0x%x \n",   inl(M2P_reg_base+M2P_OFFSET_CURRENT0) );
++      DPRINTK("BASE1 - 0x%x \n",        inl(M2P_reg_base+M2P_OFFSET_BASE1) );
++      DPRINTK("MAXCNT1 - 0x%x \n",    inl(M2P_reg_base+M2P_OFFSET_MAXCNT1) );
++      DPRINTK("CURRENT1 - 0x%x \n",   inl(M2P_reg_base+M2P_OFFSET_CURRENT1) );
++
++      DPRINTK("Buffer source     size    last    used \n");
++      for (loop = 0; loop < 5; loop ++)
++              DPRINTK("%d             0x%x             0x%x           %d               %d \n",
++                      loop, dma->buffer_queue[loop].source, dma->buffer_queue[loop].size,
++                      dma->buffer_queue[loop].last, dma->buffer_queue[loop].used);
++      DPRINTK("pause   0x%x            0x%x           %d               %d \n",
++              dma->pause_buf.source, dma->pause_buf.size,
++              dma->pause_buf.last, dma->pause_buf.used);
++
++      DPRINTK("Pause - %d \n", dma->pause);
++      DPRINTK("xfer_enable - %d \n", dma->xfer_enable);
++      DPRINTK("total bytes - 0x%x \n", dma->total_bytes);
++      DPRINTK("total buffer - %d \n", dma->total_buffers);
++      DPRINTK("new buffers - %d \n", dma->new_buffers);
++      DPRINTK("current buffer - %d \n", dma->current_buffer);
++      DPRINTK("last buffer - %d \n", dma->last_buffer);
++      DPRINTK("used buffers - %d \n", dma->used_buffers);
++
++      DPRINTK("CURRENT1 - 0x%x \n",   inl(M2P_reg_base+M2P_OFFSET_CURRENT1) );
++      DPRINTK("VIC0IRQSTATUS - 0x%x, VIC0INTENABLE - 0x%x \n",
++              *(unsigned int *)(VIC0IRQSTATUS),
++              *(unsigned int *)(VIC0INTENABLE));
++
++      /*
++       *  Success.
++       */
++      return(0);
++}
++
++/*****************************************************************************
++ *
++ * ep93xx_dma_free
++ *
++ * Description: This function will free the dma channel for future requests.
++ *
++ *  handle:    handle for the channel to be freed.
++ *
++ ****************************************************************************/
++int
++ep93xx_dma_free(int handle)
++{
++      ep93xx_dma_t *dma;
++      unsigned int M2M_reg_base, M2P_reg_base, uiCONTROL;
++      int channel;
++
++      /*
++       *  Get the DMA hw channel # from the handle.
++       */
++      channel = dma_get_channel_from_handle(handle);
++
++      /*
++       *  See if this is a valid handle.
++       */
++      if (channel < 0) {
++              printk(KERN_ERR "DMA Free: Invalid dma handle.\n");
++              return(-EINVAL);
++      }
++
++      /*
++       *  Get a pointer to the dma instance.
++       */
++      dma = &dma_chan[channel];
++
++      /*
++       *  Disable the dma channel
++       */
++      if (channel < 10) {
++              /*
++               *  M2P channel
++               */
++              M2P_reg_base = dma->reg_base;
++
++              uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);
++              uiCONTROL &= ~CONTROL_M2P_ENABLE;
++              outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );
++      } else {
++              /*
++               *  M2M channel
++               */
++              M2M_reg_base = dma->reg_base;
++
++              uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);
++              uiCONTROL &= ~CONTROL_M2M_ENABLE;
++              outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );
++      }
++
++      /*
++       *  Free the interrupt servicing this dma channel
++       */
++      //free_irq(dma->irq, (void *) dma);
++        dma->terminated=1;
++
++      /*
++       *  Decrement the reference count for this instance of the dma interface
++       */
++      dma->ref_count--;
++
++      /*
++       *  Set the transfer and pause state variables to 0
++       *  (unititialized state).
++       */
++      dma->xfer_enable = 0;
++      dma->pause = 0;
++
++      /*
++       *  Debugging message.
++       */
++      DPRINTK("Successfully freed dma channel %d\n", channel);
++      /*
++       *  Success.
++       */
++      return(0);
++}
++
++/*****************************************************************************
++ *
++ * ep93xx_dma_init(void)
++ *
++ * Description: This function is called during system initialization to
++ * setup the interrupt number and register set base address for each DMA
++ * channel.
++ *
++ ****************************************************************************/
++static int __init
++ep93xx_dma_init(void)
++{
++      int channel;
++
++      /*
++       * Init some values in each dma instance.
++       */
++      for (channel = 0; channel < MAX_EP93XX_DMA_CHANNELS; channel++) {
++              /*
++               *  IRQ for the specified dma channel.
++               */
++              dma_chan[channel].irq = IRQ_EP93XX_DMAM2P0 + channel;
++
++                 dma_chan[channel].terminated = 0;
++
++              /*
++               *  Initial value of the dma channel handle.
++               */
++              dma_chan[channel].last_valid_handle = channel << 28;
++
++              /*
++               *  Give the instance a pointer to the dma channel register
++               *  base.
++               */
++              if (channel < 10)
++                      dma_chan[channel].reg_base = DMAM2PChannelBase[channel];
++              else
++                      dma_chan[channel].reg_base = DMAM2MChannelBase[channel - 10];
++
++              /*
++               *  Initialize the reference count for this channel.
++               */
++              dma_chan[channel].ref_count = 0;
++      }
++
++      DPRINTK("DMA Interface intitialization complete\n");
++
++      /*
++       * Success
++       */
++      return 0;
++}
++
++arch_initcall(ep93xx_dma_init);
++
++EXPORT_SYMBOL(ep93xx_dma_free);
++EXPORT_SYMBOL(ep93xx_dma_request);
++EXPORT_SYMBOL(ep93xx_dma_flush);
++EXPORT_SYMBOL(ep93xx_dma_pause);
++EXPORT_SYMBOL(ep93xx_dma_remove_buffer);
++EXPORT_SYMBOL(ep93xx_dma_add_buffer);
++EXPORT_SYMBOL(ep93xx_dma_start);
++EXPORT_SYMBOL(ep93xx_dma_config);
+--- /dev/null
++++ b/arch/arm/mach-ep93xx/dma_ep93xx.h
+@@ -0,0 +1,676 @@
++/*****************************************************************************
++ *
++ * arch/arm/mach-ep93xx/dma_ep93xx.h
++ *
++ * DESCRIPTION:    93XX DMA controller API private defintions.
++ *
++ * Copyright Cirrus Logic Corporation, 2003.  All rights reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ ****************************************************************************/
++#ifndef _EP93XX_DMA_H_
++#define _EP93XX_DMA_H_
++
++// as it turns out the ide dma is the biggest dma buffer hog so far
++// in case the HDD is "thinking" (seek/buffer flush)
++// the continueing r/w DMAs to the HDD will be queued up to up to PRD_ENTRIES entries...
++#include <linux/ide.h>
++#define MAX_EP93XX_DMA_BUFFERS      PRD_ENTRIES
++
++#ifndef TRUE
++#define TRUE                        1
++#endif
++
++#ifndef FALSE
++#define FALSE                       0
++#endif
++
++#ifndef NULL
++#define NULL                        0
++#endif
++
++#define EP93XX_DMA_BASE                       (EP93XX_AHB_VIRT_BASE + 0x00000000)
++
++/*****************************************************************************
++ * 0x8000.0000 -> 0x8000.003C M2P Channel 0 Registers (Tx)
++ * 0x8000.0040 -> 0x8000.007C M2P Channel 1 Registers (Rx)
++ * 0x8000.0080 -> 0x8000.00BC M2P Channel 2 Registers (Tx)
++ * 0x8000.00C0 -> 0x8000.00FC M2P Channel 3 Registers (Rx)
++ * 0x8000.0100 -> 0x8000.013C M2M Channel 0 Registers
++ * 0x8000.0140 -> 0x8000.017C M2M Channel 1 Registers
++ * 0x8000.0180 -> 0x8000.01BC Not Used
++ * 0x8000.01C0 -> 0x8000.01FC Not Used
++ * 0x8000.0200 -> 0x8000.023C M2P Channel 5 Registers (Rx)
++ * 0x8000.0240 -> 0x8000.027C M2P Channel 4 Registers (Tx)
++ * 0x8000.0280 -> 0x8000.02BC M2P Channel 7 Registers (Rx)
++ * 0x8000.02C0 -> 0x8000.02FC M2P Channel 6 Registers (Tx)
++ * 0x8000.0300 -> 0x8000.033C M2P Channel 9 Registers (Rx)
++ * 0x8000.0340 -> 0x8000.037C M2P Channel 8 Registers (Tx)
++ * 0x8000.0380 DMA Channel Arbitration register
++ * 0x8000.03C0 DMA Global Interrupt register
++ * 0x8000.03C4 -> 0x8000.03FC Not Used
++ *
++ *
++ * Internal M2P/P2M Channel Register Map
++ *
++ * Offset Name      Access  Bits Reset Value
++ * 0x00   CONTROL   R/W     6    0
++ * 0x04   INTERRUPT R/W TC* 3    0
++ * 0x08   PPALLOC   R/W     4    channel dependant
++ *                               (see reg description)
++ * 0x0C   STATUS    RO      8    0
++ * 0x10   reserved
++ * 0x14   REMAIN    RO      16   0
++ * 0X18   Reserved
++ * 0X1C   Reserved
++ * 0x20   MAXCNT0   R/W     16   0
++ * 0x24   BASE0     R/W     32   0
++ * 0x28   CURRENT0  RO      32   0
++ * 0x2C   Reserved
++ * 0x30   MAXCNT1   R/W     16   0
++ * 0x34   BASE1     R/W     32   0
++ * 0X38   CURRENT1  RO      32   0
++ * 0X3C   Reserved
++ *
++ * M2M Channel Register Map
++ * Offset Name         Access   Bits Reset Value
++ *
++ * 0x00   CONTROL      R/W      22   0
++ * 0x04   INTERRUPT    R/W TC*  3    0
++ * 0x08   Reserved
++ * 0x0C   STATUS       R/W TC*  14   0
++ * 0x10   BCR0         R/W      16   0
++ * 0x14   BCR1         R/W      16   0
++ * 0x18   SAR_BASE0    R/W      32   0
++ * 0x1C   SAR_BASE1    R/W      32   0
++ * 0x20   Reserved
++ * 0x24   SAR_CURRENT0 RO       32   0
++ * 0x28   SAR_CURRENT1 RO       32   0
++ * 0x2C   DAR_BASE0    R/W      32   0
++ * 0x30   DAR_BASE1    R/W      32   0
++ * 0x34   DAR_CURRENT0 RO       32   0
++ * 0X38   Reserved
++ * 0X3C   DAR_CURRENT1 RO       32   0
++ * * Write this location once to clear the bit (see
++ * Interrupt/Status register description for which bits
++ * this rule applies to).
++ *
++ ****************************************************************************/
++
++
++/*----------------------------------------------------------------------------------*/
++/* M2P Registers                                                                    */
++/*----------------------------------------------------------------------------------*/
++/*
++ * M2P CONTROL register bit defines
++ */
++#define CONTROL_M2P_STALLINTEN      0x00000001            /* Enables the STALL interrupt  */
++#define CONTROL_M2P_NFBINTEN        0x00000002            /* Enables the NFB interrupt    */
++#define CONTROL_M2P_CHERRORINTEN    0x00000008      /* Enables the ChError interrupt*/
++#define CONTROL_M2P_ENABLE                0x00000010      /* Enables the channel          */
++#define CONTROL_M2P_ABRT                  0x00000020      /* Determines how DMA behaves in*/
++                                                              /* NEXT state with peripheral   */
++                                                    /* error                        */
++                                                              /* 0: NEXT -> ON, ignore error  */
++                                                              /* 1: NEXT -> STALL, disable ch.*/
++#define CONTROL_M2P_ICE                           0x00000040      /* Ignore Channel Error         */
++
++/*
++ * M2P INTERRUPT register bit defines
++ */
++#define INTERRUPT_M2P_STALLINT      0x00000001            /* Indicates channel stalled.   */
++#define INTERRUPT_M2P_NFBINT        0x00000002                /* Indicates channel is hungry. */
++#define INTERRUPT_M2P_CHERRORINT    0x00000008            /* Peripheral detects error     */
++
++
++/*
++ * STATUS register bit defines
++ */
++#define STATUS_M2P_STALL            0x00000001                /* A '1' indicates channel is       */
++                                                    /* stalled                          */
++#define STATUS_M2P_NFB                            0x00000002      /* A '1' indicates channel has moved*/
++                                                              /* from NEXT state to ON state, but */
++                                                              /* waiting for next buffer to be    */
++                                                    /* programmed.                      */
++#define STATUS_M2P_CHERROR                0x00000008      /* Enables the ChError interrupt    */
++#define STATUS_M2P_CURRENT_MASK     0x00000030      /* Current state of the FSM         */
++#define STATUS_M2P_CURRENT_SHIFT    4
++#define STATUS_M2P_NEXTBUFFER     0x00000040      /* Informs the int handler after an */
++                                                              /* NFB int which pair of maxcnt and */
++                                                    /* base regs to update.             */
++#define STATUS_M2P_BYTES_MASK       0x0000f800                /* number of valid DMA data         */
++#define STATUS_M2P_BYTES_SHIFT      7               /* currently in                     */
++                                                                                          /* packer/unpacker                  */
++
++#define STATUS_M2P_DMA_NO_BUF         0x00000000
++#define STATUS_M2P_DMA_BUF_ON         0x00000010
++#define STATUS_M2P_DMA_BUF_NEXT               0x00000020
++
++/*
++ * Register masks to mask off reserved bits after reading register.
++ */
++#define M2P_MASK_PPALLOC            0x0000000f
++#define M2P_MASK_REMAIN             0x0000ffff
++#define M2P_MASK_MAXCNT0            0x0000ffff
++#define M2P_MASK_BASE0              0xffffffff
++#define M2P_MASK_CURRENT0           0xffffffff
++#define M2P_MASK_MAXCNT1            0x0000ffff
++#define M2P_MASK_BASE1              0xffffffff
++#define M2P_MASK_CURRENT1           0xffffffff
++
++
++/*----------------------------------------------------------------------------------*/
++/* M2M Registers                                                                    */
++/*----------------------------------------------------------------------------------*/
++
++#define CONTROL_M2M_STALLINTEN        0x00000001  /* Enables the STALL interrupt                     */
++#define CONTROL_M2M_SCT                       0x00000002  /* Source Copy Transfer. Setup a                   */
++                                                                                  /* block transfer from 1 memory source             */
++                                                                                  /* location.                                       */
++#define CONTROL_M2M_DONEINTEN 0x00000004  /* Enables the DONE interrupt which                */
++                                                                                  /* indicates if the xfer completed                 */
++                                                                                  /* successfully                                    */
++#define CONTROL_M2M_ENABLE            0x00000008  /* Enables the channel                             */
++#define CONTROL_M2M_START             0x00000010  /* Initiates the xfer. 'software trigger'          */
++#define CONTROL_M2M_BWC_MASK  0x000001e0  /* Bandwidth control. Indicate number of           */
++#define CONTROL_M2M_BWC_SHIFT   5                     /* bytes in a transfer.                            */
++#define CONTROL_M2M_PW_MASK           0x00000600  /* Peripheral width. Used for xfers                */
++#define CONTROL_M2M_PW_SHIFT    9                     /* between memory and external peripheral.         */
++                                                                                  /* 00: byte, 01: halfword, 10: word.               */
++#define CONTROL_M2M_DAH                       0x00000800  /* Destination Address Hold                        */
++#define CONTROL_M2M_SAH                       0x00001000  /* Source Address Hold                             */
++#define CONTROL_M2M_TM_MASK     0x00006000  /* Transfer Mode. 00: sw triggered,                */
++#define CONTROL_M2M_TM_SHIFT    13                    /* 01: hw initiated M2P, 01: hw initiated P2M      */
++#define CONTROL_M2M_ETDP_MASK 0x00018000  /* End-of-Transfer/Terminal Count pin              */
++#define CONTROL_M2M_ETDP_SHIFT  15                /* direction and polarity.                         */
++#define CONTROL_M2M_DACKP             0x00020000  /* DMA acknowledge pin polarity                    */
++
++#define CONTROL_M2M_DREQP_MASK  0x00180000    /* DMA request pin polarity. must be set           */
++#define CONTROL_M2M_DREQP_SHIFT 19                    /* before enable bit.                              */
++#define CONTROL_M2M_NFBINTEN  0x00200000  /* Enables generation of the NFB interrupt.        */
++#define CONTROL_M2M_RSS_MASK    0x00c00000    /* Request source selection:                       */
++#define CONTROL_M2M_RSS_SHIFT 22                      /*              000 - External DReq[0]                     */
++                                                                                  /*          001 - External DReq[1]                     */
++                                                                                  /*          01X - Internal SSPRx                       */
++                                                                                  /*          10X - Internal SSPTx                       */
++                                                                                  /*          11X - Internal IDE                         */
++#define CONTROL_M2M_NO_HDSK           0x01000000  /* No handshake.  When set the peripheral doesn't  */
++                                                                                  /* require the regular handshake protocal. Must    */
++                                                                              /* be set for SSP and IDE operations, optional     */
++                                                                                  /* for external peripherals.                       */
++#define CONTROL_M2M_PWSC_MASK   0xfe000000    /* Peripheral wait states count. Gives the latency */
++#define CONTROL_M2M_PWSC_SHIFT        25                      /* (in PCLK cycles) needed by the peripheral to    */
++                                                                              /* deassert its' request once the M2M xfer w/ DMA  */
++                                                                              /* is complete.                                    */
++
++/*
++ * M2M INTERRUPT register bit defines
++ */
++#define INTERRUPT_M2M_STALLINT        0x00000001      /* Stall interrupt indicates channel stalled. */
++#define INTERRUPT_M2M_DONEINT 0x00000002      /* Transaction done.                          */
++#define INTERRUPT_M2M_NFBINT  0x00000004      /* Next frame buffer interrupt indicates      */
++                                                                                      /* channel requires a new buffer              */
++
++
++
++/*
++ * M2M STATUS register bit defines
++ */
++#define STATUS_M2M_STALL              0x00000001  /* A '1' indicates channel is stalled           */
++#define STATUS_M2M_CURRENTSTATE_MASK  0x0000003e  /* Indicates state of M2M Channel control       */
++#define STATUS_M2M_CURRENTSTATE_SHIFT 1               /* FSM (0-2):                                   */
++                                                                                  /*  000 - IDLE, 001 - STALL, 010 - MEM_RD,      */
++                                                                                  /*  011 - MEM_WR, 100 - BWC_WAIT                */
++                                                                                  /* and M2M buffer FSM (3-2):                    */
++                                                                                  /*  00 - NO_BUF, 01 - BUF_ON, 10 - BUF_NEXT     */
++#define STATUS_M2M_DONE                   0x00000040  /* Transfer completed successfully if 1.        */
++#define STATUS_M2M_TCS_MASK           0x00000180  /* Terminal Count status. Indicates whether or  */
++#define STATUS_M2M_TCS_SHIFT    7                     /* or not the actual byte count reached         */
++                                                                              /* programmed limit for buffer descriptor       */
++#define STATUS_M2M_EOTS_MASK    0x00000600  /* End-of-Transfer status for buffer            */
++#define STATUS_M2M_EOTS_SHIFT   9
++#define STATUS_M2M_NFB                        0x00000800  /* A '1' indicates channel has moved            */
++                                                                                  /* from NEXT state to ON state, but the next    */
++                                                                                  /* byte count reg for next buffer has not been  */
++                                                                                  /* programmed yet.                              */
++#define STATUS_M2M_NB                 0x00001000  /* NextBuffer status. Informs NFB service       */
++                                                                                  /* routine, after NFB int, which pair of buffer */
++                                                                                  /* descriptor registers is free to update.      */
++#define STATUS_M2M_DREQS              0x00002000  /* DREQ status.  Reflects the status of the     */
++                                                                                  /* synchronized external peripherals DMA        */
++                                                                                  /* request signal.                              */
++
++/*
++ * Register masks to mask off reserved bits after reading register.
++ */
++#define M2M_MASK_BCR0             0x0000ffff
++#define M2M_MASK_BCR1             0x0000ffff
++#define M2M_MASK_SAR_BASE0        0xffffffff
++#define M2M_MASK_SAR_BASE1        0xffffffff
++#define M2M_MASK_SAR_CURRENT0     0xffffffff
++#define M2M_MASK_SAR_CURRENT1     0xffffffff
++#define M2M_MASK_DAR_BASE0        0xffffffff
++#define M2M_MASK_DAR_BASE1        0xffffffff
++#define M2M_MASK_DAR_CURRENT0     0xffffffff
++#define M2M_MASK_DAR_CURRENT1     0xffffffff
++
++
++//
++/* 8000_0000 - 8000_ffff: DMA  */
++#define DMA_OFFSET              0x000000
++#define DMA_BASE                (EP93XX_DMA_BASE)
++#define DMAMP_TX_0_CONTROL      (DMA_BASE+0x0000)
++#define DMAMP_TX_0_INTERRUPT    (DMA_BASE+0x0004)
++#define DMAMP_TX_0_PPALLOC      (DMA_BASE+0x0008)
++#define DMAMP_TX_0_STATUS       (DMA_BASE+0x000C)
++#define DMAMP_TX_0_REMAIN       (DMA_BASE+0x0014)
++#define DMAMP_TX_0_MAXCNT0      (DMA_BASE+0x0020)
++#define DMAMP_TX_0_BASE0        (DMA_BASE+0x0024)
++#define DMAMP_TX_0_CURRENT0     (DMA_BASE+0x0028)
++#define DMAMP_TX_0_MAXCNT1      (DMA_BASE+0x0030)
++#define DMAMP_TX_0_BASE1        (DMA_BASE+0x0034)
++#define DMAMP_TX_0_CURRENT1     (DMA_BASE+0x0038)
++
++#define DMAMP_RX_1_CONTROL      (DMA_BASE+0x0040)
++#define DMAMP_RX_1_INTERRUPT    (DMA_BASE+0x0044)
++#define DMAMP_RX_1_PPALLOC      (DMA_BASE+0x0048)
++#define DMAMP_RX_1_STATUS       (DMA_BASE+0x004C)
++#define DMAMP_RX_1_REMAIN       (DMA_BASE+0x0054)
++#define DMAMP_RX_1_MAXCNT0      (DMA_BASE+0x0060)
++#define DMAMP_RX_1_BASE0        (DMA_BASE+0x0064)
++#define DMAMP_RX_1_CURRENT0     (DMA_BASE+0x0068)
++#define DMAMP_RX_1_MAXCNT1      (DMA_BASE+0x0070)
++#define DMAMP_RX_1_BASE1        (DMA_BASE+0x0074)
++#define DMAMP_RX_1_CURRENT1     (DMA_BASE+0x0078)
++
++#define DMAMP_TX_2_CONTROL      (DMA_BASE+0x0080)
++#define DMAMP_TX_2_INTERRUPT    (DMA_BASE+0x0084)
++#define DMAMP_TX_2_PPALLOC      (DMA_BASE+0x0088)
++#define DMAMP_TX_2_STATUS       (DMA_BASE+0x008C)
++#define DMAMP_TX_2_REMAIN       (DMA_BASE+0x0094)
++#define DMAMP_TX_2_MAXCNT0      (DMA_BASE+0x00A0)
++#define DMAMP_TX_2_BASE0        (DMA_BASE+0x00A4)
++#define DMAMP_TX_2_CURRENT0     (DMA_BASE+0x00A8)
++#define DMAMP_TX_2_MAXCNT1      (DMA_BASE+0x00B0)
++#define DMAMP_TX_2_BASE1        (DMA_BASE+0x00B4)
++#define DMAMP_TX_2_CURRENT1     (DMA_BASE+0x00B8)
++
++#define DMAMP_RX_3_CONTROL      (DMA_BASE+0x00C0)
++#define DMAMP_RX_3_INTERRUPT    (DMA_BASE+0x00C4)
++#define DMAMP_RX_3_PPALLOC      (DMA_BASE+0x00C8)
++#define DMAMP_RX_3_STATUS       (DMA_BASE+0x00CC)
++#define DMAMP_RX_3_REMAIN       (DMA_BASE+0x00D4)
++#define DMAMP_RX_3_MAXCNT0      (DMA_BASE+0x00E0)
++#define DMAMP_RX_3_BASE0        (DMA_BASE+0x00E4)
++#define DMAMP_RX_3_CURRENT0     (DMA_BASE+0x00E8)
++#define DMAMP_RX_3_MAXCNT1      (DMA_BASE+0x00F0)
++#define DMAMP_RX_3_BASE1        (DMA_BASE+0x00F4)
++#define DMAMP_RX_3_CURRENT1     (DMA_BASE+0x00F8)
++
++#define DMAMM_0_CONTROL         (DMA_BASE+0x0100)
++#define DMAMM_0_INTERRUPT       (DMA_BASE+0x0104)
++#define DMAMM_0_STATUS          (DMA_BASE+0x010C)
++#define DMAMM_0_BCR0            (DMA_BASE+0x0110)
++#define DMAMM_0_BCR1            (DMA_BASE+0x0114)
++#define DMAMM_0_SAR_BASE0       (DMA_BASE+0x0118)
++#define DMAMM_0_SAR_BASE1       (DMA_BASE+0x011C)
++#define DMAMM_0_SAR_CURRENT0    (DMA_BASE+0x0124)
++#define DMAMM_0_SAR_CURRENT1    (DMA_BASE+0x0128)
++#define DMAMM_0_DAR_BASE0       (DMA_BASE+0x012C)
++#define DMAMM_0_DAR_BASE1       (DMA_BASE+0x0130)
++#define DMAMM_0_DAR_CURRENT0    (DMA_BASE+0x0134)
++#define DMAMM_0_DAR_CURRENT1    (DMA_BASE+0x013C)
++
++#define DMAMM_1_CONTROL         (DMA_BASE+0x0140)
++#define DMAMM_1_INTERRUPT       (DMA_BASE+0x0144)
++#define DMAMM_1_STATUS          (DMA_BASE+0x014C)
++#define DMAMM_1_BCR0            (DMA_BASE+0x0150)
++#define DMAMM_1_BCR1            (DMA_BASE+0x0154)
++#define DMAMM_1_SAR_BASE0       (DMA_BASE+0x0158)
++#define DMAMM_1_SAR_BASE1       (DMA_BASE+0x015C)
++#define DMAMM_1_SAR_CURRENT0    (DMA_BASE+0x0164)
++#define DMAMM_1_SAR_CURRENT1    (DMA_BASE+0x0168)
++#define DMAMM_1_DAR_BASE0       (DMA_BASE+0x016C)
++#define DMAMM_1_DAR_BASE1       (DMA_BASE+0x0170)
++#define DMAMM_1_DAR_CURRENT0    (DMA_BASE+0x0174)
++#define DMAMM_1_DAR_CURRENT1    (DMA_BASE+0x017C)
++
++#define DMAMP_RX_5_CONTROL      (DMA_BASE+0x0200)
++#define DMAMP_RX_5_INTERRUPT    (DMA_BASE+0x0204)
++#define DMAMP_RX_5_PPALLOC      (DMA_BASE+0x0208)
++#define DMAMP_RX_5_STATUS       (DMA_BASE+0x020C)
++#define DMAMP_RX_5_REMAIN       (DMA_BASE+0x0214)
++#define DMAMP_RX_5_MAXCNT0      (DMA_BASE+0x0220)
++#define DMAMP_RX_5_BASE0        (DMA_BASE+0x0224)
++#define DMAMP_RX_5_CURRENT0     (DMA_BASE+0x0228)
++#define DMAMP_RX_5_MAXCNT1      (DMA_BASE+0x0230)
++#define DMAMP_RX_5_BASE1        (DMA_BASE+0x0234)
++#define DMAMP_RX_5_CURRENT1     (DMA_BASE+0x0238)
++
++#define DMAMP_TX_4_CONTROL      (DMA_BASE+0x0240)
++#define DMAMP_TX_4_INTERRUPT    (DMA_BASE+0x0244)
++#define DMAMP_TX_4_PPALLOC      (DMA_BASE+0x0248)
++#define DMAMP_TX_4_STATUS       (DMA_BASE+0x024C)
++#define DMAMP_TX_4_REMAIN       (DMA_BASE+0x0254)
++#define DMAMP_TX_4_MAXCNT0      (DMA_BASE+0x0260)
++#define DMAMP_TX_4_BASE0        (DMA_BASE+0x0264)
++#define DMAMP_TX_4_CURRENT0     (DMA_BASE+0x0268)
++#define DMAMP_TX_4_MAXCNT1      (DMA_BASE+0x0270)
++#define DMAMP_TX_4_BASE1        (DMA_BASE+0x0274)
++#define DMAMP_TX_4_CURRENT1     (DMA_BASE+0x0278)
++
++#define DMAMP_RX_7_CONTROL      (DMA_BASE+0x0280)
++#define DMAMP_RX_7_INTERRUPT    (DMA_BASE+0x0284)
++#define DMAMP_RX_7_PPALLOC      (DMA_BASE+0x0288)
++#define DMAMP_RX_7_STATUS       (DMA_BASE+0x028C)
++#define DMAMP_RX_7_REMAIN       (DMA_BASE+0x0294)
++#define DMAMP_RX_7_MAXCNT0      (DMA_BASE+0x02A0)
++#define DMAMP_RX_7_BASE0        (DMA_BASE+0x02A4)
++#define DMAMP_RX_7_CURRENT0     (DMA_BASE+0x02A8)
++#define DMAMP_RX_7_MAXCNT1      (DMA_BASE+0x02B0)
++#define DMAMP_RX_7_BASE1        (DMA_BASE+0x02B4)
++#define DMAMP_RX_7_CURRENT1     (DMA_BASE+0x02B8)
++
++#define DMAMP_TX_6_CONTROL      (DMA_BASE+0x02C0)
++#define DMAMP_TX_6_INTERRUPT    (DMA_BASE+0x02C4)
++#define DMAMP_TX_6_PPALLOC      (DMA_BASE+0x02C8)
++#define DMAMP_TX_6_STATUS       (DMA_BASE+0x02CC)
++#define DMAMP_TX_6_REMAIN       (DMA_BASE+0x02D4)
++#define DMAMP_TX_6_MAXCNT0      (DMA_BASE+0x02E0)
++#define DMAMP_TX_6_BASE0        (DMA_BASE+0x02E4)
++#define DMAMP_TX_6_CURRENT0     (DMA_BASE+0x02E8)
++#define DMAMP_TX_6_MAXCNT1      (DMA_BASE+0x02F0)
++#define DMAMP_TX_6_BASE1        (DMA_BASE+0x02F4)
++#define DMAMP_TX_6_CURRENT1     (DMA_BASE+0x02F8)
++
++#define DMAMP_RX_9_CONTROL      (DMA_BASE+0x0300)
++#define DMAMP_RX_9_INTERRUPT    (DMA_BASE+0x0304)
++#define DMAMP_RX_9_PPALLOC      (DMA_BASE+0x0308)
++#define DMAMP_RX_9_STATUS       (DMA_BASE+0x030C)
++#define DMAMP_RX_9_REMAIN       (DMA_BASE+0x0314)
++#define DMAMP_RX_9_MAXCNT0      (DMA_BASE+0x0320)
++#define DMAMP_RX_9_BASE0        (DMA_BASE+0x0324)
++#define DMAMP_RX_9_CURRENT0     (DMA_BASE+0x0328)
++#define DMAMP_RX_9_MAXCNT1      (DMA_BASE+0x0330)
++#define DMAMP_RX_9_BASE1        (DMA_BASE+0x0334)
++#define DMAMP_RX_9_CURRENT1     (DMA_BASE+0x0338)
++
++#define DMAMP_TX_8_CONTROL      (DMA_BASE+0x0340)
++#define DMAMP_TX_8_INTERRUPT    (DMA_BASE+0x0344)
++#define DMAMP_TX_8_PPALLOC      (DMA_BASE+0x0348)
++#define DMAMP_TX_8_STATUS       (DMA_BASE+0x034C)
++#define DMAMP_TX_8_REMAIN       (DMA_BASE+0x0354)
++#define DMAMP_TX_8_MAXCNT0      (DMA_BASE+0x0360)
++#define DMAMP_TX_8_BASE0        (DMA_BASE+0x0364)
++#define DMAMP_TX_8_CURRENT0     (DMA_BASE+0x0368)
++#define DMAMP_TX_8_MAXCNT1      (DMA_BASE+0x0370)
++#define DMAMP_TX_8_BASE1        (DMA_BASE+0x0374)
++#define DMAMP_TX_8_CURRENT1     (DMA_BASE+0x0378)
++
++#define DMA_ARBITRATION         (DMA_BASE+0x0380)
++#define DMA_INTERRUPT           (DMA_BASE+0x03C0)
++
++
++/*
++ * DMA Register Base addresses and Offsets
++ */
++#define DMA_M2P_TX_0_BASE       DMAMP_TX_0_CONTROL
++#define DMA_M2P_RX_1_BASE       DMAMP_RX_1_CONTROL
++#define DMA_M2P_TX_2_BASE       DMAMP_TX_2_CONTROL
++#define DMA_M2P_RX_3_BASE       DMAMP_RX_3_CONTROL
++#define DMA_M2M_0_BASE          DMAMM_0_CONTROL
++#define DMA_M2M_1_BASE          DMAMM_1_CONTROL
++#define DMA_M2P_RX_5_BASE       DMAMP_RX_5_CONTROL
++#define DMA_M2P_TX_4_BASE       DMAMP_TX_4_CONTROL
++#define DMA_M2P_RX_7_BASE       DMAMP_RX_7_CONTROL
++#define DMA_M2P_TX_6_BASE       DMAMP_TX_6_CONTROL
++#define DMA_M2P_RX_9_BASE       DMAMP_RX_9_CONTROL
++#define DMA_M2P_TX_8_BASE       DMAMP_TX_8_CONTROL
++
++#define M2P_OFFSET_CONTROL          0x0000
++#define M2P_OFFSET_INTERRUPT        0x0004
++#define M2P_OFFSET_PPALLOC          0x0008
++#define M2P_OFFSET_STATUS           0x000C
++#define M2P_OFFSET_REMAIN           0x0014
++#define M2P_OFFSET_MAXCNT0          0x0020
++#define M2P_OFFSET_BASE0            0x0024
++#define M2P_OFFSET_CURRENT0         0x0028
++#define M2P_OFFSET_MAXCNT1          0x0030
++#define M2P_OFFSET_BASE1            0x0034
++#define M2P_OFFSET_CURRENT1         0x0038
++
++#define M2M_OFFSET_CONTROL          0x0000
++#define M2M_OFFSET_INTERRUPT        0x0004
++#define M2M_OFFSET_STATUS           0x000C
++#define M2M_OFFSET_BCR0             0x0010
++#define M2M_OFFSET_BCR1             0x0014
++#define M2M_OFFSET_SAR_BASE0        0x0018
++#define M2M_OFFSET_SAR_BASE1        0x001C
++#define M2M_OFFSET_SAR_CURRENT0     0x0024
++#define M2M_OFFSET_SAR_CURRENT1     0x0028
++#define M2M_OFFSET_DAR_BASE0        0x002C
++#define M2M_OFFSET_DAR_BASE1        0x0030
++#define M2M_OFFSET_DAR_CURRENT0     0x0034
++#define M2M_OFFSET_DAR_CURRENT1     0x003C
++
++
++
++//-----------------------------------------------------------------------------
++// PWRCNT Register Defines
++//-----------------------------------------------------------------------------
++#define SYSCON_PWRCNT_FIREN             0x80000000
++#define SYSCON_PWRCNT_UARTBAUD          0x20000000
++#define SYSCON_PWRCNT_USHEN             0x10000000
++#define SYSCON_PWRCNT_DMA_M2MCH1        0x08000000
++#define SYSCON_PWRCNT_DMA_M2MCH0        0x04000000
++#define SYSCON_PWRCNT_DMA_M2PCH8        0x02000000
++#define SYSCON_PWRCNT_DMA_M2PCH9        0x01000000
++#define SYSCON_PWRCNT_DMA_M2PCH6        0x00800000
++#define SYSCON_PWRCNT_DMA_M2PCH7        0x00400000
++#define SYSCON_PWRCNT_DMA_M2PCH4        0x00200000
++#define SYSCON_PWRCNT_DMA_M2PCH5        0x00100000
++#define SYSCON_PWRCNT_DMA_M2PCH2        0x00080000
++#define SYSCON_PWRCNT_DMA_M2PCH3        0x00040000
++#define SYSCON_PWRCNT_DMA_M2PCH0        0x00020000
++#define SYSCON_PWRCNT_DMA_M2PCH1        0x00010000
++
++#ifndef __ASSEMBLY__
++/*
++ * DMA Register Base addresses
++ */
++static unsigned int const DMAM2PChannelBase[10] =
++{
++    DMA_M2P_TX_0_BASE,
++    DMA_M2P_RX_1_BASE,
++    DMA_M2P_TX_2_BASE,
++    DMA_M2P_RX_3_BASE,
++    DMA_M2P_TX_4_BASE,
++    DMA_M2P_RX_5_BASE,
++    DMA_M2P_TX_6_BASE,
++    DMA_M2P_RX_7_BASE,
++    DMA_M2P_TX_8_BASE,
++    DMA_M2P_RX_9_BASE
++};
++
++static unsigned int const DMAM2MChannelBase[2] =
++{
++    DMA_M2M_0_BASE,
++    DMA_M2M_1_BASE
++};
++
++#endif /* __ASSEMBLY__ */
++
++/*****************************************************************************
++ *
++ * DMA buffer structure type.
++ *
++ ****************************************************************************/
++typedef struct ep93xx_dma_buffer_s
++{
++    unsigned int    source;     /* buffer physical source address.          */
++    unsigned int    dest;       /* buffer physical destination address,     */
++                                /* only used with the 2 M2M channels.       */
++    unsigned int    size;       /* buffer size in bytes                     */
++    unsigned int    last;       /* 1 if this is the last buffer             */
++                                /* in this transaction.  If 1,              */
++                                /* disable the NFBint so we aren't          */
++                                /* interrupted for another buffer           */
++                                /* when we know there won't be another.     */
++    unsigned int    used;       /* This field is set to 1 by the DMA        */
++                                /* interface after the buffer is transferred*/
++    int    buf_id;              /* unique identifyer specified by the       */
++                                /* the driver which requested the dma       */
++} ep93xx_dma_buffer_t;
++
++typedef ep93xx_dma_buffer_t * ep93xx_dma_buffer_p;
++
++/*****************************************************************************
++ *
++ * Instance definition for the DMA interface.
++ *
++ ****************************************************************************/
++typedef struct ep9312_dma_s
++{
++    /*
++     *  This 1 when the instance is in use, and 0 when it's not.
++     */
++    unsigned int ref_count;
++
++    /*
++     * This is the last valid handle for this instance.  When giving out a
++     * new handle this will be incremented and given out.
++     */
++    int last_valid_handle;
++
++    /*
++     * device specifies one of the 20 DMA hardware ports this
++     * DMA channel will service.
++     */
++    ep93xx_dma_dev_t device;
++
++    /*
++     * DMABufferQueue is the queue of buffer structure pointers which the
++     * dma channel will use to setup transfers.
++     */
++    ep93xx_dma_buffer_t buffer_queue[MAX_EP93XX_DMA_BUFFERS];
++
++    /*
++     * currnt_buffer : This is the buffer currently being transfered on
++     *                 this channel.
++     * last_buffer : This is the last buffer for this transfer.
++     * Note: current_buffer + 1 is already programmed into the dma
++     *       channel as the next buffer to transfer. Don't write
++     *       over either entry.
++     */
++    int current_buffer;
++    int last_buffer;
++
++    /*
++     * The following 3 fields are buffer counters.
++     *
++     * iNewBuffers: Buffers in the queue which have not been transfered.
++     * iUsedBuffers: Buffers in the queue which have have been tranferred,
++     *               and are waiting to be returned.
++     * iTotalBuffers: Total number of buffers in the queue.
++     */
++    int new_buffers;
++    int used_buffers;
++    int total_buffers;
++
++    /*
++     * uiTotalBytes has the total bytes transfered on the channel since the
++     * last flush.  This value does not include the bytes tranfered in the
++     * current buffer.  A byte count is only added after a complete buffer
++     * is tranfered.
++     */
++    unsigned int total_bytes;
++
++    /*
++     *  Interrupt number for this channel
++     */
++    unsigned int irq;
++
++    /*
++     * Indicates whether or not the channel is currently enabled to transfer
++     * data.
++     */
++    unsigned int xfer_enable;
++
++    /*
++     * pause indicates if the dma channel was paused by calling the pause
++     * ioctl.
++     */
++    unsigned int pause;
++
++    /*
++     *  buffer structure used during a pause to capture the current
++     *  address and remaining bytes for the buffer actively being transferred
++     *  on the channel. This buffer will be used to reprogram the dma
++     *  channel upon a resume.
++     */
++    ep93xx_dma_buffer_t pause_buf;
++
++    /*
++     * DMACallback is a function pointer which the calling application can
++     * use install a function to.  this fuction can be used to notify the
++     * calling application of an interrupt.
++     */
++    dma_callback callback;
++
++    /*
++     * User data used as a parameter for the Callback function.  The user
++     * sets up the data and sends it with the callback function.
++     */
++    unsigned int user_data;
++
++    /*
++     * A string representation of the device attached to the channel.
++     */
++    const char * device_id;
++
++    /*
++     * The register base address for this dma channel.
++     */
++    unsigned int reg_base;
++
++    /*
++     * terminated indicates
++     */
++    unsigned int terminated;
++
++
++} ep93xx_dma_t;
++
++/*****************************************************************************
++ *
++ * DMA macros
++ *
++ ****************************************************************************/
++#define DMA_HANDLE_SPECIFIER_MASK   0xF0000000
++#define DMA_CH0_HANDLE_SPECIFIER    0x00000000
++#define DMA_CH1_HANDLE_SPECIFIER    0x10000000
++#define DMA_CH2_HANDLE_SPECIFIER    0x20000000
++#define DMA_CH3_HANDLE_SPECIFIER    0x30000000
++#define DMA_CH4_HANDLE_SPECIFIER    0x40000000
++#define DMA_CH5_HANDLE_SPECIFIER    0x50000000
++#define DMA_CH6_HANDLE_SPECIFIER    0x60000000
++#define DMA_CH7_HANDLE_SPECIFIER    0x70000000
++#define DMA_CH8_HANDLE_SPECIFIER    0x80000000
++#define DMA_CH9_HANDLE_SPECIFIER    0x90000000
++#define DMA_CH10_HANDLE_SPECIFIER   0xA0000000
++#define DMA_CH11_HANDLE_SPECIFIER   0xB0000000
++
++#endif // _DMADRV_H_