diff -urpN -X ../dontdiff linux-2.6.18-rc4/include/asm-arm/arch-s3c2410/dma.h linux-2.6.18-rc4-dma6/include/asm-arm/arch-s3c2410/dma.h
--- linux-2.6.18-rc4/include/asm-arm/arch-s3c2410/dma.h	2006-08-11 11:03:52.000000000 +0100
+++ linux-2.6.18-rc4-dma6/include/asm-arm/arch-s3c2410/dma.h	2006-08-11 20:43:08.000000000 +0100
@@ -1,18 +1,13 @@
-/* linux/include/asm-arm/arch-bast/dma.h
+/* linux/include/asm-arm/arch-s3c2410/dma.h
  *
- * Copyright (C) 2003,2004 Simtec Electronics
+ * Copyright (C) 2003,2004,2006 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *
- * Samsung S3C2410X DMA support
+ * Samsung S3C241XX DMA support
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * Changelog:
- *  ??-May-2003 BJD   Created file
- *  ??-Jun-2003 BJD   Added more dma functionality to go with arch
- *  10-Nov-2004 BJD   Added sys_device support
 */
 
 #ifndef __ASM_ARCH_DMA_H
@@ -21,28 +16,56 @@
 #include <linux/sysdev.h>
 #include "hardware.h"
 
-
 /*
  * This is the maximum DMA address(physical address) that can be DMAd to.
  *
  */
-#define MAX_DMA_ADDRESS		0x20000000
+#define MAX_DMA_ADDRESS		0x40000000
 #define MAX_DMA_TRANSFER_SIZE   0x100000 /* Data Unit is half word  */
 
+/* We use `virtual` dma channels to hide the fact we have only a limited
+ * number of DMA channels, and not of all of them (dependant on the device)
+ * can be attached to any DMA source. We therefore let the DMA core handle
+ * the allocation of hardware channels to clients.
+*/
+
+enum dma_ch {
+	DMACH_XD0,
+	DMACH_XD1,
+	DMACH_SDI,
+	DMACH_SPI0,
+	DMACH_SPI1,
+	DMACH_UART0,
+	DMACH_UART1,
+	DMACH_UART2,
+	DMACH_TIMER,
+	DMACH_I2S_IN,
+	DMACH_I2S_OUT,
+	DMACH_PCM_IN,
+	DMACH_PCM_OUT,
+	DMACH_MIC_IN,
+	DMACH_USB_EP1,
+	DMACH_USB_EP2,
+	DMACH_USB_EP3,
+	DMACH_USB_EP4,
+	DMACH_MAX,		/* the end entry */
+};
+
+#define DMACH_LOW_LEVEL	(1<<28)	/* use this to specifiy hardware ch no */
 
 /* we have 4 dma channels */
 #define S3C2410_DMA_CHANNELS        (4)
 
 /* types */
 
-typedef enum {
+enum s3c2410_dma_state {
 	S3C2410_DMA_IDLE,
 	S3C2410_DMA_RUNNING,
 	S3C2410_DMA_PAUSED
-} s3c2410_dma_state_t;
+};
 
 
-/* s3c2410_dma_loadst_t
+/* enum s3c2410_dma_loadst
  *
  * This represents the state of the DMA engine, wrt to the loaded / running
  * transfers. Since we don't have any way of knowing exactly the state of
@@ -70,44 +93,40 @@ typedef enum {
  * currently running.
 */
 
-typedef enum {
+enum s3c2410_dma_loadst {
 	S3C2410_DMALOAD_NONE,
 	S3C2410_DMALOAD_1LOADED,
 	S3C2410_DMALOAD_1RUNNING,
 	S3C2410_DMALOAD_1LOADED_1RUNNING,
-} s3c2410_dma_loadst_t;
+};
 
-typedef enum {
+enum s3c2410_dma_buffresult {
 	S3C2410_RES_OK,
 	S3C2410_RES_ERR,
 	S3C2410_RES_ABORT
-} s3c2410_dma_buffresult_t;
-
-
-typedef enum s3c2410_dmasrc_e s3c2410_dmasrc_t;
+};
 
-enum s3c2410_dmasrc_e {
-	S3C2410_DMASRC_HW,      /* source is memory */
-	S3C2410_DMASRC_MEM      /* source is hardware */
+enum s3c2410_dmasrc {
+	S3C2410_DMASRC_HW,		/* source is memory */
+	S3C2410_DMASRC_MEM		/* source is hardware */
 };
 
-/* enum s3c2410_chan_op_e
+/* enum s3c2410_chan_op
  *
  * operation codes passed to the DMA code by the user, and also used
  * to inform the current channel owner of any changes to the system state
 */
 
-enum s3c2410_chan_op_e {
+enum s3c2410_chan_op {
 	S3C2410_DMAOP_START,
 	S3C2410_DMAOP_STOP,
 	S3C2410_DMAOP_PAUSE,
 	S3C2410_DMAOP_RESUME,
 	S3C2410_DMAOP_FLUSH,
-	S3C2410_DMAOP_TIMEOUT,           /* internal signal to handler */
+	S3C2410_DMAOP_TIMEOUT,		/* internal signal to handler */
+	S3C2410_DMAOP_STARTED,		/* indicate channel started */
 };
 
-typedef enum s3c2410_chan_op_e s3c2410_chan_op_t;
-
 /* flags */
 
 #define S3C2410_DMAF_SLOW         (1<<0)   /* slow, so don't worry about
@@ -116,104 +135,104 @@ typedef enum s3c2410_chan_op_e s3c2410_c
 
 /* dma buffer */
 
-typedef struct s3c2410_dma_buf_s s3c2410_dma_buf_t;
-
 struct s3c2410_dma_client {
 	char                *name;
 };
 
-typedef struct s3c2410_dma_client s3c2410_dma_client_t;
-
 /* s3c2410_dma_buf_s
  *
  * internally used buffer structure to describe a queued or running
  * buffer.
 */
 
-struct s3c2410_dma_buf_s {
-	s3c2410_dma_buf_t   *next;
-	int                  magic;        /* magic */
-	int                  size;         /* buffer size in bytes */
-	dma_addr_t           data;         /* start of DMA data */
-	dma_addr_t           ptr;          /* where the DMA got to [1] */
-	void                *id;           /* client's id */
+struct s3c2410_dma_buf;
+struct s3c2410_dma_buf {
+	struct s3c2410_dma_buf	*next;
+	int			 magic;		/* magic */
+	int			 size;		/* buffer size in bytes */
+	dma_addr_t		 data;		/* start of DMA data */
+	dma_addr_t		 ptr;		/* where the DMA got to [1] */
+	void			*id;		/* client's id */
 };
 
 /* [1] is this updated for both recv/send modes? */
 
-typedef struct s3c2410_dma_chan_s s3c2410_dma_chan_t;
+struct s3c2410_dma_chan;
 
 /* s3c2410_dma_cbfn_t
  *
  * buffer callback routine type
 */
 
-typedef void (*s3c2410_dma_cbfn_t)(s3c2410_dma_chan_t *, void *buf, int size,
-				   s3c2410_dma_buffresult_t result);
-
-typedef int  (*s3c2410_dma_opfn_t)(s3c2410_dma_chan_t *,
-				   s3c2410_chan_op_t );
-
-struct s3c2410_dma_stats_s {
-	unsigned long          loads;
-	unsigned long          timeout_longest;
-	unsigned long          timeout_shortest;
-	unsigned long          timeout_avg;
-	unsigned long          timeout_failed;
+typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *,
+				   void *buf, int size,
+				   enum s3c2410_dma_buffresult result);
+
+typedef int  (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *,
+				   enum s3c2410_chan_op );
+
+struct s3c2410_dma_stats {
+	unsigned long		loads;
+	unsigned long		timeout_longest;
+	unsigned long		timeout_shortest;
+	unsigned long		timeout_avg;
+	unsigned long		timeout_failed;
 };
 
-typedef struct s3c2410_dma_stats_s s3c2410_dma_stats_t;
+struct s3c2410_dma_map;
 
-/* struct s3c2410_dma_chan_s
+/* struct s3c2410_dma_chan
  *
  * full state information for each DMA channel
 */
 
-struct s3c2410_dma_chan_s {
+struct s3c2410_dma_chan {
 	/* channel state flags and information */
-	unsigned char          number;      /* number of this dma channel */
-	unsigned char          in_use;      /* channel allocated */
-	unsigned char          irq_claimed; /* irq claimed for channel */
-	unsigned char          irq_enabled; /* irq enabled for channel */
-	unsigned char          xfer_unit;   /* size of an transfer */
+	unsigned char		 number;      /* number of this dma channel */
+	unsigned char		 in_use;      /* channel allocated */
+	unsigned char		 irq_claimed; /* irq claimed for channel */
+	unsigned char		 irq_enabled; /* irq enabled for channel */
+	unsigned char		 xfer_unit;   /* size of an transfer */
 
 	/* channel state */
 
-	s3c2410_dma_state_t    state;
-	s3c2410_dma_loadst_t   load_state;
-	s3c2410_dma_client_t  *client;
+	enum s3c2410_dma_state	 state;
+	enum s3c2410_dma_loadst	 load_state;
+	struct s3c2410_dma_client *client;
 
 	/* channel configuration */
-	s3c2410_dmasrc_t       source;
-	unsigned long          dev_addr;
-	unsigned long          load_timeout;
-	unsigned int           flags;        /* channel flags */
+	enum s3c2410_dmasrc	 source;
+	unsigned long		 dev_addr;
+	unsigned long		 load_timeout;
+	unsigned int		 flags;		/* channel flags */
+	
+	struct s3c24xx_dma_map	*map;		/* channel hw maps */
 
 	/* channel's hardware position and configuration */
-	void __iomem           *regs;        /* channels registers */
-	void __iomem           *addr_reg;    /* data address register */
-	unsigned int           irq;          /* channel irq */
-	unsigned long          dcon;         /* default value of DCON */
+	void __iomem		*regs;		/* channels registers */
+	void __iomem		*addr_reg;	/* data address register */
+	unsigned int		 irq;		/* channel irq */
+	unsigned long		 dcon;		/* default value of DCON */
 
 	/* driver handles */
-	s3c2410_dma_cbfn_t     callback_fn;  /* buffer done callback */
-	s3c2410_dma_opfn_t     op_fn;        /* channel operation callback */
+	s3c2410_dma_cbfn_t	 callback_fn;	/* buffer done callback */
+	s3c2410_dma_opfn_t	 op_fn;		/* channel op callback */
 
 	/* stats gathering */
-	s3c2410_dma_stats_t   *stats;
-	s3c2410_dma_stats_t    stats_store;
+	struct s3c2410_dma_stats *stats;
+	struct s3c2410_dma_stats  stats_store;
 
 	/* buffer list and information */
-	s3c2410_dma_buf_t      *curr;        /* current dma buffer */
-	s3c2410_dma_buf_t      *next;        /* next buffer to load */
-	s3c2410_dma_buf_t      *end;         /* end of queue */
+	struct s3c2410_dma_buf	*curr;		/* current dma buffer */
+	struct s3c2410_dma_buf	*next;		/* next buffer to load */
+	struct s3c2410_dma_buf	*end;		/* end of queue */
 
 	/* system device */
 	struct sys_device	dev;
 };
 
 /* the currently allocated channel information */
-extern s3c2410_dma_chan_t s3c2410_chans[];
+extern struct s3c2410_dma_chan s3c2410_chans[];
 
 /* note, we don't really use dma_device_t at the moment */
 typedef unsigned long dma_device_t;
@@ -226,7 +245,7 @@ typedef unsigned long dma_device_t;
 */
 
 extern int s3c2410_dma_request(dmach_t channel,
-			       s3c2410_dma_client_t *, void *dev);
+			       struct s3c2410_dma_client *, void *dev);
 
 
 /* s3c2410_dma_ctrl
@@ -234,7 +253,7 @@ extern int s3c2410_dma_request(dmach_t c
  * change the state of the dma channel
 */
 
-extern int s3c2410_dma_ctrl(dmach_t channel, s3c2410_chan_op_t op);
+extern int s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op);
 
 /* s3c2410_dma_setflags
  *
@@ -249,7 +268,7 @@ extern int s3c2410_dma_setflags(dmach_t 
  * free the dma channel (will also abort any outstanding operations)
 */
 
-extern int s3c2410_dma_free(dmach_t channel, s3c2410_dma_client_t *);
+extern int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *);
 
 /* s3c2410_dma_enqueue
  *
@@ -273,7 +292,7 @@ extern int s3c2410_dma_config(dmach_t ch
  * configure the device we're talking to
 */
 
-extern int s3c2410_dma_devconfig(int channel, s3c2410_dmasrc_t source,
+extern int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source,
 				 int hwcfg, unsigned long devaddr);
 
 /* s3c2410_dma_getposition
diff -urpN -X ../dontdiff linux-2.6.18-rc4/include/asm-arm/arch-s3c2410/map.h linux-2.6.18-rc4-dma6/include/asm-arm/arch-s3c2410/map.h
--- linux-2.6.18-rc4/include/asm-arm/arch-s3c2410/map.h	2006-08-11 11:03:52.000000000 +0100
+++ linux-2.6.18-rc4-dma6/include/asm-arm/arch-s3c2410/map.h	2006-08-11 20:51:37.000000000 +0100
@@ -167,6 +167,11 @@
 #define S3C2440_PA_CAMIF   (0x4F000000)
 #define S3C2440_SZ_CAMIF   SZ_1M
 
+/* AC97 */
+
+#define S3C2440_PA_AC97	   (0x5B000000)
+#define S3C2440_SZ_AC97	   SZ_1M
+
 /* ISA style IO, for each machine to sort out mappings for, if it
  * implements it. We reserve two 16M regions for ISA.
  */
diff -urpN -X ../dontdiff linux-2.6.18-rc4/include/asm-arm/arch-s3c2410/regs-ac97.h linux-2.6.18-rc4-dma6/include/asm-arm/arch-s3c2410/regs-ac97.h
--- linux-2.6.18-rc4/include/asm-arm/arch-s3c2410/regs-ac97.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18-rc4-dma6/include/asm-arm/arch-s3c2410/regs-ac97.h	2006-08-11 20:49:22.000000000 +0100
@@ -0,0 +1,23 @@
+/* linux/include/asm-arm/arch-s3c2410/regs-ac97.h
+ *
+ * Copyright (c) 2006 Simtec Electronics <linux@simtec.co.uk>
+ *		http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C2440 AC97 Controller
+*/
+
+#ifndef __ASM_ARCH_REGS_AC97_H
+#define __ASM_ARCH_REGS_AC97_H __FILE__
+
+#define S3C_AC97_GLBCTRL	(0x00)
+#define S3C_AC97_GLBSTAT	(0x04)
+#define S3C_AC97_CODEC_CMD	(0x08)
+#define S3C_AC97_PCM_ADDR	(0x10)
+#define S3C_AC97_PCM_DATA	(0x18)
+#define S3C_AC97_MIC_DATA	(0x1C)
+
+#endif /* __ASM_ARCH_REGS_AC97_H */
diff -urpN -X ../dontdiff linux-2.6.18-rc4/arch/arm/mach-s3c2410/Kconfig linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/Kconfig
--- linux-2.6.18-rc4/arch/arm/mach-s3c2410/Kconfig	2006-08-11 11:03:37.000000000 +0100
+++ linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/Kconfig	2006-08-13 22:37:29.000000000 +0100
@@ -125,6 +125,13 @@ config S3C2410_CLOCK
 	help
 	  Clock code for the S3C2410, and similar processors
 
+config CPU_S3C2410_DMA
+	bool
+	depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442)
+	default y if CPU_S3C2410 || CPU_S3C2442
+	help
+	  DMA device selection for S3C2410 and compatible CPUs
+
 config CPU_S3C2410
 	bool
 	depends on ARCH_S3C2410
diff -urpN -X ../dontdiff linux-2.6.18-rc4/arch/arm/mach-s3c2410/Makefile linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/Makefile
--- linux-2.6.18-rc4/arch/arm/mach-s3c2410/Makefile	2006-08-11 11:03:37.000000000 +0100
+++ linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/Makefile	2006-08-13 22:35:07.000000000 +0100
@@ -9,51 +9,61 @@ obj-y			:= cpu.o irq.o time.o gpio.o clo
 obj-m			:=
 obj-n			:=
 obj-			:=
+obj-dma-y		:=
+obj-dma-n		:=
+
+# DMA
+obj-$(CONFIG_S3C2410_DMA)	+= dma.o
 
 # S3C2400 support files
-obj-$(CONFIG_CPU_S3C2400)  += s3c2400-gpio.o
+obj-$(CONFIG_CPU_S3C2400)	+= s3c2400-gpio.o
 
 # S3C2410 support files
 
-obj-$(CONFIG_CPU_S3C2410)  += s3c2410.o
-obj-$(CONFIG_CPU_S3C2410)  += s3c2410-gpio.o
-obj-$(CONFIG_S3C2410_DMA)  += dma.o
+obj-$(CONFIG_CPU_S3C2410)	+= s3c2410.o
+obj-$(CONFIG_CPU_S3C2410)	+= s3c2410-gpio.o
+obj-$(CONFIG_CPU_S3C2410_DMA)	+= s3c2410-dma.o
 
 # Power Management support
 
-obj-$(CONFIG_PM)	   += pm.o sleep.o
-obj-$(CONFIG_PM_SIMTEC)	   += pm-simtec.o
+obj-$(CONFIG_PM)		+= pm.o sleep.o
+obj-$(CONFIG_PM_SIMTEC)		+= pm-simtec.o
 
 # S3C2412 support
-obj-$(CONFIG_CPU_S3C2412)  += s3c2412.o
-obj-$(CONFIG_CPU_S3C2412)  += s3c2412-clock.o
+obj-$(CONFIG_CPU_S3C2412)	+= s3c2412.o
+obj-$(CONFIG_CPU_S3C2412)	+= s3c2412-clock.o
 
 #
 # S3C244X support
 
-obj-$(CONFIG_CPU_S3C244X)  += s3c244x.o
-obj-$(CONFIG_CPU_S3C244X)  += s3c244x-irq.o
+obj-$(CONFIG_CPU_S3C244X)	+= s3c244x.o
+obj-$(CONFIG_CPU_S3C244X)	+= s3c244x-irq.o
 
 # Clock control
 
-obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o
+obj-$(CONFIG_S3C2410_CLOCK)	+= s3c2410-clock.o
 
 # S3C2440 support
 
-obj-$(CONFIG_CPU_S3C2440)  += s3c2440.o s3c2440-dsc.o
-obj-$(CONFIG_CPU_S3C2440)  += s3c2440-irq.o
-obj-$(CONFIG_CPU_S3C2440)  += s3c2440-clock.o
-obj-$(CONFIG_CPU_S3C2440)  += s3c2410-gpio.o
+obj-$(CONFIG_CPU_S3C2440)	+= s3c2440.o s3c2440-dsc.o
+obj-$(CONFIG_CPU_S3C2440)	+= s3c2440-irq.o
+obj-$(CONFIG_CPU_S3C2440)	+= s3c2440-clock.o
+obj-$(CONFIG_CPU_S3C2440)	+= s3c2410-gpio.o
+obj-dma-$(CONFIG_CPU_S3C2440)	+= s3c2440-dma.o
 
 # S3C2442 support
 
-obj-$(CONFIG_CPU_S3C2442)  += s3c2442.o
-obj-$(CONFIG_CPU_S3C2442)  += s3c2442-clock.o
+obj-$(CONFIG_CPU_S3C2442)	+= s3c2442.o
+obj-$(CONFIG_CPU_S3C2442)	+= s3c2442-clock.o
 
 # bast extras
 
 obj-$(CONFIG_BAST_PC104_IRQ)	+= bast-irq.o
 
+# merge in dma objects
+
+obj-y				+= $(obj-dma-y)
+
 # machine specific support
 
 obj-$(CONFIG_MACH_ANUBIS)	+= mach-anubis.o
diff -urpN -X ../dontdiff linux-2.6.18-rc4/arch/arm/mach-s3c2410/dma.c linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/dma.c
--- linux-2.6.18-rc4/arch/arm/mach-s3c2410/dma.c	2006-08-11 11:03:37.000000000 +0100
+++ linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/dma.c	2006-08-13 20:36:54.000000000 +0100
@@ -1,35 +1,16 @@
-/* linux/arch/arm/mach-bast/dma.c
+/* linux/arch/arm/mach-s3c2410/dma.c
  *
- * (c) 2003-2005 Simtec Electronics
+ * (c) 2003-2005,2006 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *
  * S3C2410 DMA core
  *
- * http://www.simtec.co.uk/products/EB2410ITX/
+ * http://armlinux.simtec.co.uk/
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * Changelog:
- *  27-Feb-2005 BJD  Added kmem cache for dma descriptors
- *  18-Nov-2004 BJD  Removed error for loading onto stopped channel
- *  10-Nov-2004 BJD  Ensure all external symbols exported for modules
- *  10-Nov-2004 BJD  Use sys_device and sysdev_class for power management
- *  08-Aug-2004 BJD  Apply rmk's suggestions
- *  21-Jul-2004 BJD  Ported to linux 2.6
- *  12-Jul-2004 BJD  Finished re-write and change of API
- *  06-Jul-2004 BJD  Rewrote dma code to try and cope with various problems
- *  23-May-2003 BJD  Created file
- *  19-Aug-2003 BJD  Cleanup, header fix, added URL
- *
- * This file is based on the Sangwook Lee/Samsung patches, re-written due
- * to various ommisions from the code (such as flexible dma configuration)
- * for use with the BAST system board.
- *
- * The re-write is pretty much complete, and should be good enough for any
- * possible DMA function
- */
+*/
 
 
 #ifdef CONFIG_S3C2410_DMA_DEBUG
@@ -55,12 +36,16 @@
 #include <asm/mach/dma.h>
 #include <asm/arch/map.h>
 
+#include "dma.h"
+
 /* io map for dma */
 static void __iomem *dma_base;
 static kmem_cache_t *dma_kmem;
 
+struct s3c24xx_dma_selection dma_sel;
+
 /* dma channel state information */
-s3c2410_dma_chan_t s3c2410_chans[S3C2410_DMA_CHANNELS];
+struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
 
 /* debugging functions */
 
@@ -74,12 +59,11 @@ s3c2410_dma_chan_t s3c2410_chans[S3C2410
 #define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg))
 #else
 static inline void
-dma_wrreg(s3c2410_dma_chan_t *chan, int reg, unsigned long val)
+dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val)
 {
 	pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
 	writel(val, dma_regaddr(chan, reg));
 }
-
 #endif
 
 #define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
@@ -102,7 +86,7 @@ struct s3c2410_dma_regstate {
 */
 
 static void
-dmadbg_capture(s3c2410_dma_chan_t *chan, struct s3c2410_dma_regstate *regs)
+dmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs)
 {
 	regs->dcsrc    = dma_rdreg(chan, S3C2410_DMA_DCSRC);
 	regs->disrc    = dma_rdreg(chan, S3C2410_DMA_DISRC);
@@ -112,7 +96,7 @@ dmadbg_capture(s3c2410_dma_chan_t *chan,
 }
 
 static void
-dmadbg_showregs(const char *fname, int line, s3c2410_dma_chan_t *chan,
+dmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan,
 		 struct s3c2410_dma_regstate *regs)
 {
 	printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n",
@@ -122,7 +106,7 @@ dmadbg_showregs(const char *fname, int l
 }
 
 static void
-dmadbg_showchan(const char *fname, int line, s3c2410_dma_chan_t *chan)
+dmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan)
 {
 	struct s3c2410_dma_regstate state;
 
@@ -132,7 +116,16 @@ dmadbg_showchan(const char *fname, int l
 	       chan->number, fname, line, chan->load_state,
 	       chan->curr, chan->next, chan->end);
 
-	dmadbg_showregs(fname, line, chan, &state);
+	dmadbg_dumpregs(fname, line, chan, &state);
+}
+
+static void
+dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan)
+{
+	struct s3c2410_dma_regstate state;
+
+	dmadbg_capture(chan, &state);
+	dmadbg_dumpregs(fname, line, chan, &state);
 }
 
 #define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan))
@@ -142,12 +135,20 @@ dmadbg_showchan(const char *fname, int l
 #define dbg_showchan(chan) do { } while(0)
 #endif /* CONFIG_S3C2410_DMA_DEBUG */
 
-#define check_channel(chan) \
-  do { if ((chan) >= S3C2410_DMA_CHANNELS) { \
-    printk(KERN_ERR "%s: invalid channel %d\n", __FUNCTION__, (chan)); \
-    return -EINVAL; \
-  } } while(0)
+static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX];
+
+/* lookup_dma_channel
+ *
+ * change the dma channel number given into a real dma channel id 
+*/
 
+static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
+{
+	if (channel & DMACH_LOW_LEVEL)
+		return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
+	else
+		return dma_chan_map[channel];
+}
 
 /* s3c2410_dma_stats_timeout
  *
@@ -155,7 +156,7 @@ dmadbg_showchan(const char *fname, int l
 */
 
 static void
-s3c2410_dma_stats_timeout(s3c2410_dma_stats_t *stats, int val)
+s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val)
 {
 	if (stats == NULL)
 		return;
@@ -174,7 +175,7 @@ s3c2410_dma_stats_timeout(s3c2410_dma_st
 */
 
 static int
-s3c2410_dma_waitforload(s3c2410_dma_chan_t *chan, int line)
+s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line)
 {
 	int timeout = chan->load_timeout;
 	int took;
@@ -221,8 +222,8 @@ s3c2410_dma_waitforload(s3c2410_dma_chan
 */
 
 static inline int
-s3c2410_dma_loadbuffer(s3c2410_dma_chan_t *chan,
-		       s3c2410_dma_buf_t *buf)
+s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan,
+		       struct s3c2410_dma_buf *buf)
 {
 	unsigned long reload;
 
@@ -253,10 +254,14 @@ s3c2410_dma_loadbuffer(s3c2410_dma_chan_
 			 buf->next);
 		reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
 	} else {
-		pr_debug("load_state is %d => autoreload\n", chan->load_state);
+		//pr_debug("load_state is %d => autoreload\n", chan->load_state);
 		reload = S3C2410_DCON_AUTORELOAD;
 	}
 
+	if ((buf->data & 0xf0000000) != 0x30000000) {
+		dmawarn("dmaload: buffer is %p\n", (void *)buf->data);
+	}
+
 	writel(buf->data, chan->addr_reg);
 
 	dma_wrreg(chan, S3C2410_DMA_DCON,
@@ -291,7 +296,7 @@ s3c2410_dma_loadbuffer(s3c2410_dma_chan_
 */
 
 static void
-s3c2410_dma_call_op(s3c2410_dma_chan_t *chan, s3c2410_chan_op_t op)
+s3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op)
 {
 	if (chan->op_fn != NULL) {
 		(chan->op_fn)(chan, op);
@@ -305,11 +310,13 @@ s3c2410_dma_call_op(s3c2410_dma_chan_t *
 */
 
 static inline void
-s3c2410_dma_buffdone(s3c2410_dma_chan_t *chan, s3c2410_dma_buf_t *buf,
-		     s3c2410_dma_buffresult_t result)
+s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf,
+		     enum s3c2410_dma_buffresult result)
 {
+#if 0
 	pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
 		 chan->callback_fn, buf, buf->id, buf->size, result);
+#endif
 
 	if (chan->callback_fn != NULL) {
 		(chan->callback_fn)(chan, buf->id, buf->size, result);
@@ -321,7 +328,7 @@ s3c2410_dma_buffdone(s3c2410_dma_chan_t 
  * start a dma channel going
 */
 
-static int s3c2410_dma_start(s3c2410_dma_chan_t *chan)
+static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
 {
 	unsigned long tmp;
 	unsigned long flags;
@@ -370,7 +377,7 @@ static int s3c2410_dma_start(s3c2410_dma
 	tmp |= S3C2410_DMASKTRIG_ON;
 	dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
 
-	pr_debug("wrote %08lx to DMASKTRIG\n", tmp);
+	pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp);
 
 #if 0
 	/* the dma buffer loads should take care of clearing the AUTO
@@ -384,7 +391,30 @@ static int s3c2410_dma_start(s3c2410_dma
 
 	dbg_showchan(chan);
 
+	/* if we've only loaded one buffer onto the channel, then chec
+	 * to see if we have another, and if so, try and load it so when
+	 * the first buffer is finished, the new one will be loaded onto
+	 * the channel */
+
+	if (chan->next != NULL) {
+		if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
+			
+			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+				pr_debug("%s: buff not yet loaded, no more todo\n",
+					 __FUNCTION__);
+			} else {
+				chan->load_state = S3C2410_DMALOAD_1RUNNING;
+				s3c2410_dma_loadbuffer(chan, chan->next);
+			}
+			
+		} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
+			s3c2410_dma_loadbuffer(chan, chan->next);
+		}
+	}
+	
+	
 	local_irq_restore(flags);
+
 	return 0;
 }
 
@@ -394,7 +424,7 @@ static int s3c2410_dma_start(s3c2410_dma
 */
 
 static int
-s3c2410_dma_canload(s3c2410_dma_chan_t *chan)
+s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
 {
 	if (chan->load_state == S3C2410_DMALOAD_NONE ||
 	    chan->load_state == S3C2410_DMALOAD_1RUNNING)
@@ -403,7 +433,6 @@ s3c2410_dma_canload(s3c2410_dma_chan_t *
 	return 0;
 }
 
-
 /* s3c2410_dma_enqueue
  *
  * queue an given buffer for dma transfer.
@@ -424,11 +453,12 @@ s3c2410_dma_canload(s3c2410_dma_chan_t *
 int s3c2410_dma_enqueue(unsigned int channel, void *id,
 			dma_addr_t data, int size)
 {
-	s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
-	s3c2410_dma_buf_t *buf;
+	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+	struct s3c2410_dma_buf *buf;
 	unsigned long flags;
 
-	check_channel(channel);
+	if (chan == NULL)
+		return -EINVAL;
 
 	pr_debug("%s: id=%p, data=%08x, size=%d\n",
 		 __FUNCTION__, id, (unsigned int)data, size);
@@ -436,12 +466,11 @@ int s3c2410_dma_enqueue(unsigned int cha
 	buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
 	if (buf == NULL) {
 		pr_debug("%s: out of memory (%ld alloc)\n",
-			 __FUNCTION__, sizeof(*buf));
+			 __FUNCTION__, (long)sizeof(*buf));
 		return -ENOMEM;
 	}
 
-	pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);
-
+	//pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);
 	//dbg_showchan(chan);
 
 	buf->next  = NULL;
@@ -505,7 +534,7 @@ int s3c2410_dma_enqueue(unsigned int cha
 EXPORT_SYMBOL(s3c2410_dma_enqueue);
 
 static inline void
-s3c2410_dma_freebuf(s3c2410_dma_buf_t *buf)
+s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf)
 {
 	int magicok = (buf->magic == BUF_MAGIC);
 
@@ -525,10 +554,12 @@ s3c2410_dma_freebuf(s3c2410_dma_buf_t *b
 */
 
 static inline void
-s3c2410_dma_lastxfer(s3c2410_dma_chan_t *chan)
+s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
 {
+#if 0
 	pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
 		 chan->number, chan->load_state);
+#endif
 
 	switch (chan->load_state) {
 	case S3C2410_DMALOAD_NONE:
@@ -537,14 +568,20 @@ s3c2410_dma_lastxfer(s3c2410_dma_chan_t 
 	case S3C2410_DMALOAD_1LOADED:
 		if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
 				/* flag error? */
-			printk(KERN_ERR "dma%d: timeout waiting for load\n",
-			       chan->number);
+			printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
+			       chan->number, __FUNCTION__);
 			return;
 		}
 		break;
 
+	case S3C2410_DMALOAD_1LOADED_1RUNNING:
+		/* I belive in this case we do not have anything to do
+		 * until the next buffer comes along, and we turn off the
+		 * reload */
+		return;
+
 	default:
-		pr_debug("dma%d: lastxfer: unhandled load_state %d with no next",
+		pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n",
 			 chan->number, chan->load_state);
 		return;
 
@@ -560,8 +597,8 @@ s3c2410_dma_lastxfer(s3c2410_dma_chan_t 
 static irqreturn_t
 s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
 {
-	s3c2410_dma_chan_t *chan = (s3c2410_dma_chan_t *)devpw;
-	s3c2410_dma_buf_t  *buf;
+	struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
+	struct s3c2410_dma_buf  *buf;
 
 	buf = chan->curr;
 
@@ -629,7 +666,14 @@ s3c2410_dma_irq(int irq, void *devpw, st
 	} else {
 	}
 
-	if (chan->next != NULL) {
+	/* only reload if the channel is still running... our buffer done
+	 * routine may have altered the state by requesting the dma channel
+	 * to stop or shutdown... */
+
+	/* todo: check that when the channel is shut-down from inside this
+	 * function, we cope with unsetting reload, etc */
+
+	if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
 		unsigned long flags;
 
 		switch (chan->load_state) {
@@ -644,8 +688,8 @@ s3c2410_dma_irq(int irq, void *devpw, st
 		case S3C2410_DMALOAD_1LOADED:
 			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
 				/* flag error? */
-				printk(KERN_ERR "dma%d: timeout waiting for load\n",
-				       chan->number);
+				printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
+				       chan->number, __FUNCTION__);
 				return IRQ_HANDLED;
 			}
 
@@ -670,7 +714,8 @@ s3c2410_dma_irq(int irq, void *devpw, st
 		if (chan->load_state == S3C2410_DMALOAD_NONE) {
 			pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
 				 chan->number, jiffies);
-			s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
+			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
+					 S3C2410_DMAOP_STOP);
 		}
 	}
 
@@ -678,39 +723,34 @@ s3c2410_dma_irq(int irq, void *devpw, st
 	return IRQ_HANDLED;
 }
 
-
+static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel);
 
 /* s3c2410_request_dma
  *
  * get control of an dma channel
 */
 
-int s3c2410_dma_request(unsigned int channel, s3c2410_dma_client_t *client,
+int s3c2410_dma_request(unsigned int channel,
+			struct s3c2410_dma_client *client,
 			void *dev)
 {
-	s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+	struct s3c2410_dma_chan *chan;
 	unsigned long flags;
 	int err;
 
 	pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
 		 channel, client->name, dev);
 
-	check_channel(channel);
-
 	local_irq_save(flags);
 
-	dbg_showchan(chan);
-
-	if (chan->in_use) {
-		if (client != chan->client) {
-			printk(KERN_ERR "dma%d: already in use\n", channel);
-			local_irq_restore(flags);
-			return -EBUSY;
-		} else {
-			printk(KERN_ERR "dma%d: client already has channel\n", channel);
-		}
+	chan = s3c2410_dma_map_channel(channel);
+	if (chan == NULL) {
+		local_irq_restore(flags);
+		return -EBUSY;
 	}
 
+	dbg_showchan(chan);
+
 	chan->client = client;
 	chan->in_use = 1;
 
@@ -718,11 +758,17 @@ int s3c2410_dma_request(unsigned int cha
 		pr_debug("dma%d: %s : requesting irq %d\n",
 			 channel, __FUNCTION__, chan->irq);
 
+		chan->irq_claimed = 1;
+		local_irq_restore(flags);
+
 		err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
 				  client->name, (void *)chan);
 
+		local_irq_save(flags);
+
 		if (err) {
 			chan->in_use = 0;
+			chan->irq_claimed = 0;
 			local_irq_restore(flags);
 
 			printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
@@ -730,7 +776,6 @@ int s3c2410_dma_request(unsigned int cha
 			return err;
 		}
 
-		chan->irq_claimed = 1;
 		chan->irq_enabled = 1;
 	}
 
@@ -756,16 +801,16 @@ EXPORT_SYMBOL(s3c2410_dma_request);
  * allowed to go through.
 */
 
-int s3c2410_dma_free(dmach_t channel, s3c2410_dma_client_t *client)
+int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client)
 {
-	s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
 	unsigned long flags;
 
-	check_channel(channel);
+	if (chan == NULL)
+		return -EINVAL;
 
 	local_irq_save(flags);
 
-
 	if (chan->client != client) {
 		printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
 		       channel, chan->client, client);
@@ -779,15 +824,19 @@ int s3c2410_dma_free(dmach_t channel, s3
 
 		/* possibly flush the channel */
 		s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);
-	}
+	}	
 
 	chan->client = NULL;
 	chan->in_use = 0;
 
 	if (chan->irq_claimed)
 		free_irq(chan->irq, (void *)chan);
+
 	chan->irq_claimed = 0;
 
+	if (!(channel & DMACH_LOW_LEVEL))
+		dma_chan_map[channel] = NULL;
+
 	local_irq_restore(flags);
 
 	return 0;
@@ -795,10 +844,10 @@ int s3c2410_dma_free(dmach_t channel, s3
 
 EXPORT_SYMBOL(s3c2410_dma_free);
 
-static int s3c2410_dma_dostop(s3c2410_dma_chan_t *chan)
+static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
 {
-	unsigned long tmp;
 	unsigned long flags;
+	unsigned long tmp;
 
 	pr_debug("%s:\n", __FUNCTION__);
 
@@ -810,6 +859,7 @@ static int s3c2410_dma_dostop(s3c2410_dm
 
 	tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
 	tmp |= S3C2410_DMASKTRIG_STOP;
+	//tmp &= ~S3C2410_DMASKTRIG_ON;
 	dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
 
 #if 0
@@ -819,6 +869,7 @@ static int s3c2410_dma_dostop(s3c2410_dm
 	dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
 #endif
 
+	/* should stop do this, or should we wait for flush? */
 	chan->state      = S3C2410_DMA_IDLE;
 	chan->load_state = S3C2410_DMALOAD_NONE;
 
@@ -827,17 +878,35 @@ static int s3c2410_dma_dostop(s3c2410_dm
 	return 0;
 }
 
+void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan)
+{
+	unsigned long tmp;
+	unsigned int timeout = 0x10000;
+
+	while (timeout-- > 0) {
+		tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
+
+		if (!(tmp & S3C2410_DMASKTRIG_ON))
+			return;
+	}
+
+	pr_debug("dma%d: failed to stop?\n", chan->number);
+}
+
+
 /* s3c2410_dma_flush
  *
  * stop the channel, and remove all current and pending transfers
 */
 
-static int s3c2410_dma_flush(s3c2410_dma_chan_t *chan)
+static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
 {
-	s3c2410_dma_buf_t *buf, *next;
+	struct s3c2410_dma_buf *buf, *next;
 	unsigned long flags;
 
-	pr_debug("%s:\n", __FUNCTION__);
+	pr_debug("%s: chan %p (%d)\n", __FUNCTION__, chan, chan->number);
+
+	dbg_showchan(chan);
 
 	local_irq_save(flags);
 
@@ -864,18 +933,72 @@ static int s3c2410_dma_flush(s3c2410_dma
 		}
 	}
 
+	dbg_showregs(chan);
+	
+	s3c2410_dma_waitforstop(chan);
+
+#if 0
+	/* should also clear interrupts, according to WinCE BSP */
+	{
+		unsigned long tmp;
+
+		tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
+		tmp |= S3C2410_DCON_NORELOAD;
+		dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
+	}
+#endif
+
+	dbg_showregs(chan);
+
 	local_irq_restore(flags);
 
 	return 0;
 }
 
+int
+s3c2410_dma_started(struct s3c2410_dma_chan *chan)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	dbg_showchan(chan);
+
+	/* if we've only loaded one buffer onto the channel, then chec
+	 * to see if we have another, and if so, try and load it so when
+	 * the first buffer is finished, the new one will be loaded onto
+	 * the channel */
+
+	if (chan->next != NULL) {
+		if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
+			
+			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+				pr_debug("%s: buff not yet loaded, no more todo\n",
+					 __FUNCTION__);
+			} else {
+				chan->load_state = S3C2410_DMALOAD_1RUNNING;
+				s3c2410_dma_loadbuffer(chan, chan->next);
+			}
+			
+		} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
+			s3c2410_dma_loadbuffer(chan, chan->next);
+		}
+	}
+	
+	
+	local_irq_restore(flags);
+
+	return 0;
+
+}
 
 int
-s3c2410_dma_ctrl(dmach_t channel, s3c2410_chan_op_t op)
+s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op)
 {
-	s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
 
-	check_channel(channel);
+	if (chan == NULL)
+		return -EINVAL;
 
 	switch (op) {
 	case S3C2410_DMAOP_START:
@@ -885,14 +1008,15 @@ s3c2410_dma_ctrl(dmach_t channel, s3c241
 		return s3c2410_dma_dostop(chan);
 
 	case S3C2410_DMAOP_PAUSE:
-		return -ENOENT;
-
 	case S3C2410_DMAOP_RESUME:
 		return -ENOENT;
 
 	case S3C2410_DMAOP_FLUSH:
 		return s3c2410_dma_flush(chan);
 
+	case S3C2410_DMAOP_STARTED:
+		return s3c2410_dma_started(chan);
+
 	case S3C2410_DMAOP_TIMEOUT:
 		return 0;
 
@@ -921,12 +1045,19 @@ int s3c2410_dma_config(dmach_t channel,
 		       int xferunit,
 		       int dcon)
 {
-	s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
 
 	pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
 		 __FUNCTION__, channel, xferunit, dcon);
 
-	check_channel(channel);
+	if (chan == NULL)
+		return -EINVAL;
+
+	printk("Initial dcon is %08x\n", dcon);
+
+	dcon |= chan->dcon & dma_sel.dcon_mask;
+
+	printk("New dcon is %08x\n", dcon);
 
 	switch (xferunit) {
 	case 1:
@@ -961,9 +1092,10 @@ EXPORT_SYMBOL(s3c2410_dma_config);
 
 int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
 {
-	s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
 
-	check_channel(channel);
+	if (chan == NULL)
+		return -EINVAL;
 
 	pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags);
 
@@ -981,9 +1113,10 @@ EXPORT_SYMBOL(s3c2410_dma_setflags);
 
 int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
 {
-	s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
 
-	check_channel(channel);
+	if (chan == NULL)
+		return -EINVAL;
 
 	pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn);
 
@@ -996,9 +1129,10 @@ EXPORT_SYMBOL(s3c2410_dma_set_opfn);
 
 int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
 {
-	s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
 
-	check_channel(channel);
+	if (chan == NULL)
+		return -EINVAL;
 
 	pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn);
 
@@ -1024,13 +1158,14 @@ EXPORT_SYMBOL(s3c2410_dma_set_buffdone_f
 */
 
 int s3c2410_dma_devconfig(int channel,
-			  s3c2410_dmasrc_t source,
+			  enum s3c2410_dmasrc source,
 			  int hwcfg,
 			  unsigned long devaddr)
 {
-	s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
 
-	check_channel(channel);
+	if (chan == NULL)
+		return -EINVAL;
 
 	pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
 		 __FUNCTION__, (int)source, hwcfg, devaddr);
@@ -1075,9 +1210,10 @@ EXPORT_SYMBOL(s3c2410_dma_devconfig);
 
 int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
 {
- 	s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+ 	struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
 
- 	check_channel(channel);
+	if (chan == NULL)
+		return -EINVAL;
 
 	if (src != NULL)
  		*src = dma_rdreg(chan, S3C2410_DMA_DCSRC);
@@ -1097,7 +1233,7 @@ EXPORT_SYMBOL(s3c2410_dma_getposition);
 
 static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
 {
-	s3c2410_dma_chan_t *cp = container_of(dev, s3c2410_dma_chan_t, dev);
+	struct s3c2410_dma_chan *cp = container_of(dev, struct s3c2410_dma_chan, dev);
 
 	printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
 
@@ -1127,7 +1263,7 @@ static int s3c2410_dma_resume(struct sys
 #define s3c2410_dma_resume  NULL
 #endif /* CONFIG_PM */
 
-static struct sysdev_class dma_sysclass = {
+struct sysdev_class dma_sysclass = {
 	set_kset_name("s3c24xx-dma"),
 	.suspend	= s3c2410_dma_suspend,
 	.resume		= s3c2410_dma_resume,
@@ -1137,19 +1273,18 @@ static struct sysdev_class dma_sysclass 
 
 static void s3c2410_dma_cache_ctor(void *p, kmem_cache_t *c, unsigned long f)
 {
-	memset(p, 0, sizeof(s3c2410_dma_buf_t));
+	memset(p, 0, sizeof(struct s3c2410_dma_buf));
 }
 
-
 /* initialisation code */
 
 static int __init s3c2410_init_dma(void)
 {
-	s3c2410_dma_chan_t *cp;
+	struct s3c2410_dma_chan *cp;
 	int channel;
 	int ret;
 
-	printk("S3C2410 DMA Driver, (c) 2003-2004 Simtec Electronics\n");
+	printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n");
 
 	dma_base = ioremap(S3C24XX_PA_DMA, 0x200);
 	if (dma_base == NULL) {
@@ -1157,13 +1292,15 @@ static int __init s3c2410_init_dma(void)
 		return -ENOMEM;
 	}
 
+	printk("Registering sysclass\n");
+
 	ret = sysdev_class_register(&dma_sysclass);
 	if (ret != 0) {
 		printk(KERN_ERR "dma sysclass registration failed\n");
 		goto err;
 	}
 
-	dma_kmem = kmem_cache_create("dma_desc", sizeof(s3c2410_dma_buf_t), 0,
+	dma_kmem = kmem_cache_create("dma_desc", sizeof(struct s3c2410_dma_buf), 0,
 				     SLAB_HWCACHE_ALIGN,
 				     s3c2410_dma_cache_ctor, NULL);
 
@@ -1176,7 +1313,7 @@ static int __init s3c2410_init_dma(void)
 	for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) {
 		cp = &s3c2410_chans[channel];
 
-		memset(cp, 0, sizeof(s3c2410_dma_chan_t));
+		memset(cp, 0, sizeof(struct s3c2410_dma_chan));
 
 		/* dma channel irqs are in order.. */
 		cp->number = channel;
@@ -1210,4 +1347,95 @@ static int __init s3c2410_init_dma(void)
 	return ret;
 }
 
-__initcall(s3c2410_init_dma);
+core_initcall(s3c2410_init_dma);
+
+static inline int is_channel_valid(unsigned int channel)
+{
+	return (channel & DMA_CH_VALID);
+}
+
+/* s3c2410_dma_map_channel()
+ *
+ * turn the virtual channel number into a real, and un-used hardware
+ * channel.
+ *
+ * currently this code uses first-free channel from the specified harware
+ * map, not taking into account anything that the board setup code may
+ * have to say about the likely peripheral set to be in use.
+*/
+
+struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
+{
+	struct s3c24xx_dma_map *ch_map;
+	struct s3c2410_dma_chan *dmach;
+	int ch;
+
+	if (dma_sel.map == NULL || channel > dma_sel.map_size)
+		return NULL;
+
+	ch_map = dma_sel.map + channel;
+	
+	for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) {
+		if (!is_channel_valid(ch_map->channels[ch]))
+			continue;
+
+		if (s3c2410_chans[ch].in_use == 0) {			
+			printk("mapped channel %d to %d\n", channel, ch);
+			break;
+		}
+	}
+
+	if (ch >= S3C2410_DMA_CHANNELS)
+		return NULL;
+	
+	/* update our channel mapping */
+
+	dmach = &s3c2410_chans[ch];
+	dma_chan_map[channel] = dmach;
+
+	/* select the channel */
+
+	(dma_sel.select)(dmach, ch_map);
+
+	return dmach;
+}
+
+static void s3c24xx_dma_show_ch(struct s3c24xx_dma_map *map, int ch)
+{
+	/* show the channel configuration */
+
+	printk("%2d: %20s, channels %c%c%c%c\n", ch, map->name,
+	       (is_channel_valid(map->channels[0]) ? '0' : '-'),
+	       (is_channel_valid(map->channels[1]) ? '1' : '-'),
+	       (is_channel_valid(map->channels[2]) ? '2' : '-'),
+	       (is_channel_valid(map->channels[3]) ? '3' : '-'));
+}
+
+static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch)
+{
+	if (1)
+		s3c24xx_dma_show_ch(map, ch);
+
+	return 0;
+}
+
+int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
+{
+	struct s3c24xx_dma_map *nmap;
+	size_t map_sz = sizeof(*nmap) * sel->map_size;
+	int ptr;
+
+	nmap = kmalloc(map_sz, GFP_KERNEL);
+	if (nmap == NULL)
+		return -ENOMEM;
+
+	memcpy(nmap, sel->map, map_sz);
+	memcpy(&dma_sel, sel, sizeof(*sel));
+
+	dma_sel.map = nmap;
+	
+	for (ptr = 0; ptr < sel->map_size; ptr++)
+		s3c24xx_dma_check_entry(nmap+ptr, ptr);
+
+	return 0;
+}
diff -urpN -X ../dontdiff linux-2.6.18-rc4/arch/arm/mach-s3c2410/dma.h linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/dma.h
--- linux-2.6.18-rc4/arch/arm/mach-s3c2410/dma.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/dma.h	2006-08-13 19:39:28.000000000 +0100
@@ -0,0 +1,45 @@
+/* arch/arm/mach-s3c2410/dma.h
+ *
+ * Copyright (C) 2006 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C24XX DMA support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+extern struct sysdev_class dma_sysclass;
+extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
+
+#define DMA_CH_VALID		(1<<31)
+
+struct s3c24xx_dma_addr {
+	unsigned long		from;
+	unsigned long		to;
+};
+
+/* struct s3c24xx_dma_map
+ *
+ * this holds the mapping information for the channel selected
+ * to be connected to the specified device
+*/
+
+struct s3c24xx_dma_map {
+	const char		*name;
+	struct s3c24xx_dma_addr  hw_addr;
+
+	unsigned long		 channels[S3C2410_DMA_CHANNELS];
+};
+
+struct s3c24xx_dma_selection {
+	struct s3c24xx_dma_map	*map;
+	unsigned long		 map_size;
+	unsigned long		 dcon_mask;
+
+	void	(*select)(struct s3c2410_dma_chan *chan,
+			  struct s3c24xx_dma_map *map);
+};
+
+extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
diff -urpN -X ../dontdiff linux-2.6.18-rc4/arch/arm/mach-s3c2410/s3c2410-dma.c linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/s3c2410-dma.c
--- linux-2.6.18-rc4/arch/arm/mach-s3c2410/s3c2410-dma.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/s3c2410-dma.c	2006-08-13 22:24:56.000000000 +0100
@@ -0,0 +1,158 @@
+/* linux/arch/arm/mach-s3c2410/s3c2410-dma.c
+ *
+ * (c) 2006 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 DMA selection
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+
+#include <asm/dma.h>
+#include <asm/arch/dma.h>
+#include "dma.h"
+
+#include "cpu.h"
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-ac97.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-lcd.h>
+#include <asm/arch/regs-sdi.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-spi.h>
+
+static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
+	[DMACH_XD0] = {
+		.name		= "xdreq0",
+		.channels[0]	= S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
+	},
+	[DMACH_XD1] = {
+		.name		= "xdreq1",
+		.channels[1]	= S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
+	},
+	[DMACH_SDI] = {
+		.name		= "sdi",
+		.channels[0]	= S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
+		.channels[2]	= S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
+		.channels[3]	= S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_IIS + S3C2410_IISFIFO,
+		.hw_addr.from	= S3C2410_PA_IIS + S3C2410_IISFIFO,
+	},
+	[DMACH_SPI0] = {
+		.name		= "spi0",
+		.channels[1]	= S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_SPI + S3C2410_SPTDAT,
+		.hw_addr.from	= S3C2410_PA_SPI + S3C2410_SPRDAT,
+	},
+	[DMACH_SPI1] = {
+		.name		= "spi1",
+		.channels[3]	= S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
+		.hw_addr.from	= S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
+	},
+	[DMACH_UART0] = {
+		.name		= "uart0",
+		.channels[0]	= S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_UART0 + S3C2410_UTXH,
+		.hw_addr.from	= S3C2410_PA_UART0 + S3C2410_URXH,
+	},
+	[DMACH_UART1] = {
+		.name		= "uart1",
+		.channels[1]	= S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_UART1 + S3C2410_UTXH,
+		.hw_addr.from	= S3C2410_PA_UART1 + S3C2410_URXH,
+	},
+      	[DMACH_UART2] = {
+		.name		= "uart2",
+		.channels[3]	= S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_UART2 + S3C2410_UTXH,
+		.hw_addr.from	= S3C2410_PA_UART2 + S3C2410_URXH,
+	},
+	[DMACH_TIMER] = {
+		.name		= "timer",
+		.channels[0]	= S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
+		.channels[2]	= S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
+		.channels[3]	= S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
+	},
+	[DMACH_I2S_IN] = {
+		.name		= "i2s-sdi",
+		.channels[1]	= S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
+		.channels[2]	= S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
+		.hw_addr.from	= S3C2410_PA_IIS + S3C2410_IISFIFO,
+	},
+	[DMACH_I2S_OUT] = {		
+		.name		= "i2s-sdo",
+		.channels[2]	= S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_IIS + S3C2410_IISFIFO,
+	},
+	[DMACH_USB_EP1] = {
+		.name		= "usb-ep1",
+		.channels[0]	= S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
+	},
+	[DMACH_USB_EP2] = {
+		.name		= "usb-ep2",
+		.channels[1]	= S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
+	},
+	[DMACH_USB_EP3] = {
+		.name		= "usb-ep3",
+		.channels[2]	= S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
+	},
+	[DMACH_USB_EP4] = {
+		.name		= "usb-ep4",
+		.channels[3]	=S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
+	},
+};
+
+static void s3c2410_dma_select(struct s3c2410_dma_chan *chan,
+			       struct s3c24xx_dma_map *map)
+{
+	chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
+}
+
+static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {
+	.select		= s3c2410_dma_select,
+	.dcon_mask	= 7 << 24,
+	.map		= s3c2410_dma_mappings,
+	.map_size	= ARRAY_SIZE(s3c2410_dma_mappings),
+};
+
+static int s3c2410_dma_add(struct sys_device *sysdev)
+{
+	return s3c24xx_dma_init_map(&s3c2410_dma_sel);
+}
+
+static struct sysdev_driver s3c2410_dma_driver = {
+	.add	= s3c2410_dma_add,
+};
+
+static int __init s3c2410_dma_init(void)
+{
+	return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver);
+}
+
+arch_initcall(s3c2410_dma_init);
+
+/* S3C2442 DMA contains the same selection table as the S3C2410 */
+
+static struct sysdev_driver s3c2442_dma_driver = {
+	.add	= s3c2410_dma_add,
+};
+
+static int __init s3c2442_dma_init(void)
+{
+	return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_dma_driver);
+}
+
+arch_initcall(s3c2442_dma_init);
+
+
diff -urpN -X ../dontdiff linux-2.6.18-rc4/arch/arm/mach-s3c2410/s3c2410.c linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/s3c2410.c
--- linux-2.6.18-rc4/arch/arm/mach-s3c2410/s3c2410.c	2006-08-11 11:03:38.000000000 +0100
+++ linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/s3c2410.c	2006-08-11 20:40:28.000000000 +0100
@@ -50,6 +50,7 @@
 
 static struct map_desc s3c2410_iodesc[] __initdata = {
 	IODESC_ENT(USBHOST),
+	IODESC_ENT(USBDEV),
 	IODESC_ENT(CLKPWR),
 	IODESC_ENT(LCD),
 	IODESC_ENT(TIMER),
diff -urpN -X ../dontdiff linux-2.6.18-rc4/arch/arm/mach-s3c2410/s3c2440-dma.c linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/s3c2440-dma.c
--- linux-2.6.18-rc4/arch/arm/mach-s3c2410/s3c2440-dma.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18-rc4-dma6/arch/arm/mach-s3c2410/s3c2440-dma.c	2006-08-13 19:38:51.000000000 +0100
@@ -0,0 +1,164 @@
+/* linux/arch/arm/mach-s3c2410/s3c2440-dma.c
+ *
+ * (c) 2006 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2440 DMA selection
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+
+#include <asm/dma.h>
+#include <asm/arch/dma.h>
+#include "dma.h"
+
+#include "cpu.h"
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-ac97.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-lcd.h>
+#include <asm/arch/regs-sdi.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-spi.h>
+
+static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
+	[DMACH_XD0] = {
+		.name		= "xdreq0",
+		.channels[0]	= S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
+	},
+	[DMACH_XD1] = {
+		.name		= "xdreq1",
+		.channels[1]	= S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
+	},
+	[DMACH_SDI] = {
+		.name		= "sdi",
+		.channels[0]	= S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
+		.channels[1]	= S3C2440_DCON_CH1_SDI | DMA_CH_VALID,
+		.channels[2]	= S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
+		.channels[3]	= S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_IIS + S3C2410_IISFIFO,
+		.hw_addr.from	= S3C2410_PA_IIS + S3C2410_IISFIFO,
+	},
+	[DMACH_SPI0] = {
+		.name		= "spi0",
+		.channels[1]	= S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_SPI + S3C2410_SPTDAT,
+		.hw_addr.from	= S3C2410_PA_SPI + S3C2410_SPRDAT,
+	},
+	[DMACH_SPI1] = {
+		.name		= "spi1",
+		.channels[3]	= S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
+		.hw_addr.from	= S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
+	},
+	[DMACH_UART0] = {
+		.name		= "uart0",
+		.channels[0]	= S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_UART0 + S3C2410_UTXH,
+		.hw_addr.from	= S3C2410_PA_UART0 + S3C2410_URXH,
+	},
+	[DMACH_UART1] = {
+		.name		= "uart1",
+		.channels[1]	= S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_UART1 + S3C2410_UTXH,
+		.hw_addr.from	= S3C2410_PA_UART1 + S3C2410_URXH,
+	},
+      	[DMACH_UART2] = {
+		.name		= "uart2",
+		.channels[3]	= S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_UART2 + S3C2410_UTXH,
+		.hw_addr.from	= S3C2410_PA_UART2 + S3C2410_URXH,
+	},
+	[DMACH_TIMER] = {
+		.name		= "timer",
+		.channels[0]	= S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
+		.channels[2]	= S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
+		.channels[3]	= S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
+	},
+	[DMACH_I2S_IN] = {
+		.name		= "i2s-sdi",
+		.channels[1]	= S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
+		.channels[2]	= S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
+		.hw_addr.from	= S3C2410_PA_IIS + S3C2410_IISFIFO,
+	},
+	[DMACH_I2S_OUT] = {		
+		.name		= "i2s-sdo",
+		.channels[0]	= S3C2440_DCON_CH0_I2SSDO | DMA_CH_VALID,
+		.channels[2]	= S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
+		.hw_addr.to	= S3C2410_PA_IIS + S3C2410_IISFIFO,
+	},
+	[DMACH_PCM_IN] = {
+		.name		= "pcm-in",
+		.channels[0]	= S3C2440_DCON_CH0_PCMIN | DMA_CH_VALID,
+		.channels[2]	= S3C2440_DCON_CH2_PCMIN | DMA_CH_VALID,
+		.hw_addr.from	= S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+	},
+	[DMACH_PCM_OUT] = {
+		.name		= "pcm-out",
+		.channels[1]	= S3C2440_DCON_CH1_PCMOUT | DMA_CH_VALID,
+		.channels[3]	= S3C2440_DCON_CH3_PCMOUT | DMA_CH_VALID,
+		.hw_addr.to	= S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+	},
+	[DMACH_MIC_IN] = {
+		.name		= "mic-in",
+		.channels[2]	= S3C2440_DCON_CH2_MICIN | DMA_CH_VALID,
+		.channels[3]	= S3C2440_DCON_CH3_MICIN | DMA_CH_VALID,
+		.hw_addr.from	= S3C2440_PA_AC97 + S3C_AC97_MIC_DATA,
+	},
+	[DMACH_USB_EP1] = {
+		.name		= "usb-ep1",
+		.channels[0]	= S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
+	},
+	[DMACH_USB_EP2] = {
+		.name		= "usb-ep2",
+		.channels[1]	= S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
+	},
+	[DMACH_USB_EP3] = {
+		.name		= "usb-ep3",
+		.channels[2]	= S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
+	},
+	[DMACH_USB_EP4] = {
+		.name		= "usb-ep4",
+		.channels[3]	= S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
+	},
+};
+
+static void s3c2440_dma_select(struct s3c2410_dma_chan *chan,
+			       struct s3c24xx_dma_map *map)
+{
+	chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
+}
+
+static struct s3c24xx_dma_selection __initdata s3c2440_dma_sel = {
+	.select		= s3c2440_dma_select,
+	.dcon_mask	= 7 << 24,
+	.map		= s3c2440_dma_mappings,
+	.map_size	= ARRAY_SIZE(s3c2440_dma_mappings),
+};
+
+static int s3c2440_dma_add(struct sys_device *sysdev)
+{
+	return s3c24xx_dma_init_map(&s3c2440_dma_sel);
+}
+
+static struct sysdev_driver s3c2440_dma_driver = {
+	.add	= s3c2440_dma_add,
+};
+
+static int __init s3c2440_dma_init(void)
+{
+	return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_dma_driver);
+}
+
+arch_initcall(s3c2440_dma_init);
+

