diff -Naurp linux-2.6.11-rc2-bk1/arch/arm/mach-s3c2410/mach-h1940.c linux-2.6.11-rc2-bk1-h1940/arch/arm/mach-s3c2410/mach-h1940.c
--- linux-2.6.11-rc2-bk1/arch/arm/mach-s3c2410/mach-h1940.c	2005-01-23 22:57:25.000000000 +0100
+++ linux-2.6.11-rc2-bk1-h1940/arch/arm/mach-s3c2410/mach-h1940.c	2005-01-23 23:30:52.000000000 +0100
@@ -94,6 +94,7 @@ static struct platform_device *h1940_dev
 	&s3c_device_wdt,
 	&s3c_device_i2c,
 	&s3c_device_iis,
+	&s3c_device_usbgadget,
 };
 
 static struct s3c24xx_board h1940_board __initdata = {
diff -Naurp linux-2.6.11-rc2-bk1/arch/arm/mach-s3c2410/s3c2410.c linux-2.6.11-rc2-bk1-h1940/arch/arm/mach-s3c2410/s3c2410.c
--- linux-2.6.11-rc2-bk1/arch/arm/mach-s3c2410/s3c2410.c	2005-01-23 22:57:25.000000000 +0100
+++ linux-2.6.11-rc2-bk1-h1940/arch/arm/mach-s3c2410/s3c2410.c	2005-01-23 23:30:52.000000000 +0100
@@ -47,6 +47,7 @@
 
 static struct map_desc s3c2410_iodesc[] __initdata = {
 	IODESC_ENT(USBHOST),
+	IODESC_ENT(USBDEV),
 	IODESC_ENT(CLKPWR),
 	IODESC_ENT(LCD),
 	IODESC_ENT(UART),
diff -Naurp linux-2.6.11-rc2-bk1/drivers/usb/gadget/ether.c linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/ether.c
--- linux-2.6.11-rc2-bk1/drivers/usb/gadget/ether.c	2004-12-24 22:35:39.000000000 +0100
+++ linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/ether.c	2005-01-23 23:30:52.000000000 +0100
@@ -259,6 +259,9 @@ MODULE_PARM_DESC(host_addr, "Host Ethern
 #define	DEV_CONFIG_SUBSET
 #endif
 
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define DEV_CONFIG_CDC
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -363,7 +366,7 @@ device_desc = {
 	.bLength =		sizeof device_desc,
 	.bDescriptorType =	USB_DT_DEVICE,
 
-	.bcdUSB =		__constant_cpu_to_le16 (0x0200),
+	.bcdUSB =		__constant_cpu_to_le16 (0x0110),
 
 	.bDeviceClass =		USB_CLASS_COMM,
 	.bDeviceSubClass =	0,
@@ -2326,6 +2329,8 @@ eth_bind (struct usb_gadget *gadget)
 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
 	} else if (gadget_is_pxa27x(gadget)) {
 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
+	} else if (gadget_is_s3c2410(gadget)) {
+		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
 	} else {
 		/* can't assume CDC works.  don't want to default to
 		 * anything less functional on CDC-capable hardware,
diff -Naurp linux-2.6.11-rc2-bk1/drivers/usb/gadget/gadget_chips.h linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/gadget_chips.h
--- linux-2.6.11-rc2-bk1/drivers/usb/gadget/gadget_chips.h	2004-12-24 22:33:47.000000000 +0100
+++ linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/gadget_chips.h	2005-01-23 23:30:52.000000000 +0100
@@ -74,6 +74,12 @@
 #define	gadget_is_pxa27x(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define gadget_is_s3c2410(g)    !strcmp("s3c2410_udc", (g)->name)
+#else
+#define gadget_is_s3c2410(g)    0
+#endif
+
 // CONFIG_USB_GADGET_AT91RM9200
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_AU1X00
diff -Naurp linux-2.6.11-rc2-bk1/drivers/usb/gadget/Kconfig linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/Kconfig
--- linux-2.6.11-rc2-bk1/drivers/usb/gadget/Kconfig	2005-01-23 22:57:36.000000000 +0100
+++ linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/Kconfig	2005-01-23 23:30:52.000000000 +0100
@@ -162,7 +162,19 @@ config USB_LH7A40X
 	depends on USB_GADGET_LH7A40X
 	default USB_GADGET
 
-
+config USB_GADGET_S3C2410
+	boolean "S3C2410"
+	depends on ARCH_S3C2410
+	help
+	  Samsung's S3C2410 is an ARM-4 processor with an integrated
+	  full speed USB 1.1 device controller.
+	  It has 4 configurable endpoints, as well as endpoint
+	  zero (for control transfers).
+config USB_S3C2410
+	tristate
+	depends on USB_GADGET_S3C2410
+	default USB_GADGET
+											    
 config USB_GADGET_DUMMY_HCD
 	boolean "Dummy HCD (DEVELOPMENT)"
 	depends on USB && EXPERIMENTAL
diff -Naurp linux-2.6.11-rc2-bk1/drivers/usb/gadget/Makefile linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/Makefile
--- linux-2.6.11-rc2-bk1/drivers/usb/gadget/Makefile	2004-12-24 22:33:59.000000000 +0100
+++ linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/Makefile	2005-01-23 23:30:52.000000000 +0100
@@ -7,7 +7,7 @@ obj-$(CONFIG_USB_PXA2XX)	+= pxa2xx_udc.o
 obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 obj-$(CONFIG_USB_OMAP)		+= omap_udc.o
 obj-$(CONFIG_USB_LH7A40X)	+= lh7a40x_udc.o
-
+obj-$(CONFIG_USB_S3C2410)	+= s3c2410_udc.o
 #
 # USB gadget drivers
 #
diff -Naurp linux-2.6.11-rc2-bk1/drivers/usb/gadget/s3c2410_udc.c linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/s3c2410_udc.c
--- linux-2.6.11-rc2-bk1/drivers/usb/gadget/s3c2410_udc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/s3c2410_udc.c	2005-01-23 23:31:08.000000000 +0100
@@ -0,0 +1,1599 @@
+/*
+ * linux/drivers/usb/gadget/s3c2410_udc.c
+ * Samsung on-chip full speed USB device controllers
+ *
+ * Copyright (C) 2004 Herbert Pötzl - Arnaud Patard
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>
+
+#include <linux/usb.h>
+#include <linux/usb_gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/arch/irqs.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-udc.h>
+#include <asm/hardware/clock.h>
+
+#include "s3c2410_udc.h"
+
+#define ENABLE_SYSFS
+
+#define DRIVER_DESC     "S3C2410 USB Device Controller Gadget"
+#define DRIVER_VERSION  "29 Oct 2004"
+#define DRIVER_AUTHOR	"Herbert Pötzl <herbert@13thfloor.at>, Arnaud Patard <arnaud.patard@rtp-net.org>"
+
+static const char       gadget_name [] = "s3c2410_udc";
+static const char	driver_desc [] = DRIVER_DESC;
+
+static struct s3c2410_udc	*the_controller;
+static struct clk      		*udc_clock;
+
+
+/*************************** DEBUG FUNCTION ***************************/
+#define DEBUG_NORMAL	1
+#define DEBUG_VERBOSE	2
+
+#ifdef CONFIG_USB_S3C2410_DEBUG
+#define USB_S3C2410_DEBUG_LEVEL 1
+uint32_t s3c2410_ticks=0;
+static int dprintk(int level, const char *fmt, ...)
+{
+	static char printk_buf[1024];
+	static long prevticks;
+	static int invocation;
+	va_list args;
+	int len;
+	
+	if (level > USB_S3C2410_DEBUG_LEVEL)
+		return 0;
+	
+	if (s3c2410_ticks != prevticks) {
+		prevticks = s3c2410_ticks;
+		invocation = 0;
+	}
+	
+	len = scnprintf(printk_buf, \
+			sizeof(printk_buf), "%1lu.%02d USB: ", \
+			prevticks, invocation++);
+
+	va_start(args, fmt);
+	len = vscnprintf(printk_buf+len, \
+			sizeof(printk_buf)-len, fmt, args);
+	va_end(args);
+	
+	return printk("%s", printk_buf);
+}
+#else
+static int dprintk(int level, const char *fmt, ...)  { return 0; }
+#endif
+#ifdef ENABLE_SYSFS
+static ssize_t s3c2410udc_regs_show(struct device *dev, char *buf)
+{
+	u32 addr_reg,pwr_reg,ep_int_reg,usb_int_reg;
+	u32 ep_int_en_reg, usb_int_en_reg, ep0_csr;
+	u32 ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2;
+	u32 ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2;
+	
+	addr_reg       = __raw_readl(S3C2410_UDC_FUNC_ADDR_REG);
+	pwr_reg        = __raw_readl(S3C2410_UDC_PWR_REG);
+	ep_int_reg     = __raw_readl(S3C2410_UDC_EP_INT_REG);
+	usb_int_reg    = __raw_readl(S3C2410_UDC_USB_INT_REG);
+	ep_int_en_reg  = __raw_readl(S3C2410_UDC_EP_INT_EN_REG);
+	usb_int_en_reg = __raw_readl(S3C2410_UDC_USB_INT_EN_REG);
+	__raw_writel(0, S3C2410_UDC_INDEX_REG);
+	ep0_csr        = __raw_readl(S3C2410_UDC_IN_CSR1_REG);
+	__raw_writel(1, S3C2410_UDC_INDEX_REG);
+	ep1_i_csr1     = __raw_readl(S3C2410_UDC_IN_CSR1_REG);
+	ep1_i_csr2     = __raw_readl(S3C2410_UDC_IN_CSR2_REG);
+	ep1_o_csr1     = __raw_readl(S3C2410_UDC_IN_CSR1_REG);
+	ep1_o_csr2     = __raw_readl(S3C2410_UDC_IN_CSR2_REG);
+	__raw_writel(2, S3C2410_UDC_INDEX_REG);
+	ep2_i_csr1     = __raw_readl(S3C2410_UDC_IN_CSR1_REG);
+	ep2_i_csr2     = __raw_readl(S3C2410_UDC_IN_CSR2_REG);
+	ep2_o_csr1     = __raw_readl(S3C2410_UDC_IN_CSR1_REG);
+	ep2_o_csr2     = __raw_readl(S3C2410_UDC_IN_CSR2_REG);
+
+	
+	return snprintf(buf, PAGE_SIZE,        \
+		 "FUNC_ADDR_REG  : 0x%04X\n"   \
+		 "PWR_REG        : 0x%04X\n"   \
+		 "EP_INT_REG     : 0x%04X\n"   \
+		 "USB_INT_REG    : 0x%04X\n"   \
+		 "EP_INT_EN_REG  : 0x%04X\n"   \
+		 "USB_INT_EN_REG : 0x%04X\n"   \
+		 "EP0_CSR        : 0x%04X\n"   \
+		 "EP1_I_CSR1     : 0x%04X\n"   \
+		 "EP1_I_CSR2     : 0x%04X\n"   \
+		 "EP1_O_CSR1     : 0x%04X\n"   \
+		 "EP1_O_CSR2     : 0x%04X\n"   \
+		 "EP2_I_CSR1     : 0x%04X\n"   \
+		 "EP2_I_CSR2     : 0x%04X\n"   \
+		 "EP2_O_CSR1     : 0x%04X\n"   \
+		 "EP2_O_CSR2     : 0x%04X\n",  \
+		 addr_reg,pwr_reg,ep_int_reg,usb_int_reg,     \
+		 ep_int_en_reg, usb_int_en_reg, ep0_csr,      \
+		 ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2, \
+		 ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2  \
+		 );
+}
+
+static DEVICE_ATTR(regs, 0444,
+		   s3c2410udc_regs_show,
+		   NULL);
+
+
+#endif
+/*------------------------- I/O ----------------------------------*/
+static void nuke (struct s3c2410_udc *udc, struct s3c2410_ep *ep)
+{
+	/* Sanity check */
+	if (&ep->queue != NULL)
+		while (!list_empty (&ep->queue)) {
+			struct s3c2410_request  *req;
+			req = list_entry (ep->queue.next, struct s3c2410_request, queue);
+			list_del_init (&req->queue);
+			req->req.status = -ESHUTDOWN;
+			spin_unlock (&udc->lock);
+			req->req.complete (&ep->ep, &req->req);
+			spin_lock (&udc->lock);
+		}
+}
+
+/*
+ * 	done
+ */
+static void done(struct s3c2410_ep *ep, struct s3c2410_request *req, int status)
+{
+	list_del_init(&req->queue);
+
+	if (likely (req->req.status == -EINPROGRESS))
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	req->req.complete(&ep->ep, &req->req);
+}
+
+static inline void clear_ep_state (struct s3c2410_udc *dev)
+{
+	        unsigned i;
+		
+		/* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
+		 * fifos, and pending transactions mustn't be continued in any case.
+		 */
+		 for (i = 1; i < S3C2410_ENDPOINTS; i++)
+			 nuke(dev, &dev->ep[i]);
+}
+
+static inline int fifo_count_out(void)
+{
+	int tmp;
+	
+	tmp = __raw_readl(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8;
+	tmp |= __raw_readl(S3C2410_UDC_OUT_FIFO_CNT1_REG);
+	
+	return tmp & 0xffff;
+}
+
+/*
+ * 	write_packet
+ */
+static inline int 
+write_packet(u32 fifo, struct s3c2410_request *req, unsigned max)
+{
+	unsigned	len;
+	u8		*buf;
+
+	buf = req->req.buf + req->req.actual;
+	len = min(req->req.length - req->req.actual, max);
+	dprintk(DEBUG_VERBOSE, "write_packet %d %d %d ",req->req.actual,req->req.length,len);
+	req->req.actual += len;
+	dprintk(DEBUG_VERBOSE, "%d\n",req->req.actual);
+
+	max = len;
+	while (max--)
+		 __raw_writel(*buf++,fifo);
+	return len;
+}
+
+/*
+ * 	write_fifo
+ */
+// return:  0 = still running, 1 = completed, negative = errno
+static int write_fifo(struct s3c2410_ep *ep, struct s3c2410_request *req)
+{
+	u8		*buf;
+	unsigned	count;
+	int		is_last;
+	u32		idx,fifo_reg;
+	u32		ep_csr;
+
+
+	switch(ep->bEndpointAddress&0x7F)
+	{
+		default:
+		case 0: idx = 0;
+			fifo_reg = S3C2410_UDC_EP0_FIFO_REG;
+			break;
+		case 1:
+			idx = 1;
+			fifo_reg = S3C2410_UDC_EP1_FIFO_REG;
+			break;
+		case 2:
+			idx = 2;
+			fifo_reg = S3C2410_UDC_EP2_FIFO_REG;
+			break;
+
+		case 3:
+			idx = 3;
+			fifo_reg = S3C2410_UDC_EP3_FIFO_REG;
+			break;
+
+		case 4:
+			idx = 4;
+			fifo_reg = S3C2410_UDC_EP4_FIFO_REG;
+			break;
+
+	}
+	
+	buf = req->req.buf + req->req.actual;
+	prefetch(buf);
+
+	count = ep->ep.maxpacket;
+	count = write_packet(fifo_reg, req, count);
+
+	/* last packet is often short (sometimes a zlp) */
+	if (count < ep->ep.maxpacket)
+		is_last = 1;
+	else if (req->req.length == req->req.actual
+			&& !req->req.zero)
+		is_last = 2;
+	else
+		is_last = 0;
+
+	dprintk(DEBUG_VERBOSE, "Written ep%d %d. %d of %d b [last %d]\n",idx,count,req->req.actual,req->req.length,is_last);
+
+	if (is_last)
+	{
+		/* The order is important. It prevents to send 2 packet at the same time
+		 **/
+		if (!idx)
+		{
+			set_ep0_de_in();
+			ep->dev->ep0state=EP0_IDLE;
+		}
+		else
+		{
+			 __raw_writel(idx, S3C2410_UDC_INDEX_REG);
+			 ep_csr=__raw_readl(S3C2410_UDC_IN_CSR1_REG);
+			 __raw_writel(idx, S3C2410_UDC_INDEX_REG);
+			 __raw_writel(ep_csr|S3C2410_UDC_ICSR1_PKTRDY,S3C2410_UDC_IN_CSR1_REG);
+		}
+		done(ep, req, 0);
+	}
+	else
+	{
+		if (!idx)
+		{
+			set_ep0_ipr();
+		}
+		else
+		{
+			__raw_writel(idx, S3C2410_UDC_INDEX_REG);
+			ep_csr=__raw_readl(S3C2410_UDC_IN_CSR1_REG);
+			__raw_writel(idx, S3C2410_UDC_INDEX_REG);
+			__raw_writel(ep_csr|S3C2410_UDC_ICSR1_PKTRDY,S3C2410_UDC_IN_CSR1_REG);
+		}
+	}
+	return is_last;
+}
+
+static inline int 
+read_packet(u32 fifo, u8 *buf, struct s3c2410_request *req, unsigned avail)
+{
+	unsigned	len;
+
+	len = min(req->req.length - req->req.actual, avail);
+	req->req.actual += len;
+	avail = len;
+
+	while (avail--)
+		*buf++ = (unsigned char)__raw_readl(fifo);
+	return len;
+}
+
+// return:  0 = still running, 1 = queue empty, negative = errno
+static int read_fifo(struct s3c2410_ep *ep, struct s3c2410_request *req)
+{
+	u8		*buf;
+	u32		ep_csr;
+	unsigned	bufferspace;
+	int is_last=1;
+	unsigned avail;
+	int fifo_count = 0;
+	u32		idx,fifo_reg;
+
+
+	switch(ep->bEndpointAddress&0x7F)
+	{
+		default:
+		case 0: idx = 0;
+			fifo_reg = S3C2410_UDC_EP0_FIFO_REG;
+			break;
+		case 1:
+			idx = 1;
+			fifo_reg = S3C2410_UDC_EP1_FIFO_REG;
+			break;
+		case 2:
+			idx = 2;
+			fifo_reg = S3C2410_UDC_EP2_FIFO_REG;
+			break;
+
+		case 3:
+			idx = 3;
+			fifo_reg = S3C2410_UDC_EP3_FIFO_REG;
+			break;
+
+		case 4:
+			idx = 4;
+			fifo_reg = S3C2410_UDC_EP4_FIFO_REG;
+			break;
+
+	}
+
+
+	buf = req->req.buf + req->req.actual;
+	bufferspace = req->req.length - req->req.actual;
+	if (!bufferspace)
+	{
+		dprintk(DEBUG_NORMAL, "read_fifo: Buffer full !!\n");
+		return -1;
+	}
+
+
+	__raw_writel(idx, S3C2410_UDC_INDEX_REG);
+		
+        fifo_count = fifo_count_out();
+	dprintk(DEBUG_VERBOSE, "fifo_read fifo count : %d\n",fifo_count);
+
+	if (fifo_count > ep->ep.maxpacket)
+		avail = ep->ep.maxpacket;
+	else
+		avail = fifo_count;
+
+	fifo_count=read_packet(fifo_reg,buf,req,avail);
+
+	if (fifo_count < ep->ep.maxpacket) {
+		is_last = 1;
+		/* overflowed this request?  flush extra data */
+		if (fifo_count != avail) {
+			req->req.status = -EOVERFLOW;
+		}
+	} else {
+		if (req->req.length == req->req.actual) 
+			is_last = 1;
+		else
+			is_last = 0;
+	}
+
+	__raw_writel(idx, S3C2410_UDC_INDEX_REG);
+	fifo_count = fifo_count_out();		
+	dprintk(DEBUG_VERBOSE, "fifo_read fifo count : %d [last %d]\n",fifo_count,is_last);
+
+/*	if (idx)
+		is_last=0;*/
+	
+	if (is_last) {
+		if (!idx)
+		{
+			set_ep0_de_out();
+			ep->dev->ep0state=EP0_IDLE;
+		}
+		else
+		{
+			__raw_writel(idx, S3C2410_UDC_INDEX_REG);
+			ep_csr=__raw_readl(S3C2410_UDC_OUT_CSR1_REG);
+			__raw_writel(idx, S3C2410_UDC_INDEX_REG);
+			__raw_writel(ep_csr&~S3C2410_UDC_OCSR1_PKTRDY,S3C2410_UDC_OUT_CSR1_REG);
+		}
+		done(ep, req, 0);
+		if (!list_empty(&ep->queue))
+		{
+			is_last=0;
+			req = container_of(ep->queue.next,
+				struct s3c2410_request, queue);
+		}
+		else
+			is_last=1;
+//		is_last = 0;
+
+	}
+	else
+	{
+		if (!idx)
+		{
+			clear_ep0_opr();
+		}
+		else
+		{	
+			__raw_writel(idx, S3C2410_UDC_INDEX_REG);
+			ep_csr=__raw_readl(S3C2410_UDC_OUT_CSR1_REG);
+			__raw_writel(idx, S3C2410_UDC_INDEX_REG);
+			__raw_writel(ep_csr&~S3C2410_UDC_OCSR1_PKTRDY,S3C2410_UDC_OUT_CSR1_REG);
+
+		}
+	}
+	
+
+	return is_last;
+}
+
+
+static int
+read_fifo_crq(struct usb_ctrlrequest *crq)
+{
+	int bytes_read = 0;
+	int fifo_count = 0;
+	int i;
+	
+	
+	unsigned char *pOut = (unsigned char*)crq;
+	
+	__raw_writel(0, S3C2410_UDC_INDEX_REG);
+	
+	fifo_count = fifo_count_out();
+	
+	BUG_ON( fifo_count > 8 );
+	
+	dprintk(DEBUG_VERBOSE, "read_fifo_crq(): fifo_count=%d\n", fifo_count );
+	while( fifo_count-- ) {
+		i = 0;
+		
+		do {
+			*pOut = (unsigned char)__raw_readl(S3C2410_UDC_EP0_FIFO_REG);
+			udelay( 10 );
+			i++;
+		} while((fifo_count_out() != fifo_count) && (i < 10));
+		
+		if ( i == 10 ) {
+			dprintk(DEBUG_NORMAL, "read_fifo(): read failure\n");
+		}
+		
+		pOut++;
+		bytes_read++;
+	}
+	
+	dprintk(DEBUG_VERBOSE, "read_fifo_crq: len=%d %02x:%02x {%x,%x,%x}\n",
+			bytes_read, crq->bRequest, crq->bRequestType,
+			crq->wValue, crq->wIndex, crq->wLength);
+	
+	return bytes_read;
+}
+
+/*------------------------- usb state machine -------------------------------*/
+static void handle_ep0(struct s3c2410_udc *dev)
+{
+	u32			ep0csr;
+	struct s3c2410_ep	*ep = &dev->ep [0];
+	struct s3c2410_request	*req;
+	struct usb_ctrlrequest	crq;
+
+	if (list_empty(&ep->queue))
+    		req = 0;
+	else
+		req = list_entry(ep->queue.next, struct s3c2410_request, queue);
+
+  	
+	__raw_writel(0, S3C2410_UDC_INDEX_REG);
+	ep0csr = __raw_readl(S3C2410_UDC_IN_CSR1_REG);
+
+	/* clear stall status */
+	if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {
+		/* FIXME */
+		nuke(dev, ep);
+	    	dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n");
+	    	clear_ep0_sst();
+	    	ep0csr &= ~(S3C2410_UDC_EP0_CSR_SENTSTL|S3C2410_UDC_EP0_CSR_SENDSTL);
+		__raw_writel(0, S3C2410_UDC_INDEX_REG);
+		__raw_writel(ep0csr, S3C2410_UDC_IN_CSR1_REG);
+		dev->ep0state = EP0_IDLE;
+		return;
+	}
+
+	/* clear setup end */
+	if (ep0csr & S3C2410_UDC_EP0_CSR_SE
+	    	/* && dev->ep0state != EP0_IDLE */) {
+	    	dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...\n");
+		nuke(dev, ep);
+	    	clear_ep0_se();
+		dev->ep0state = EP0_IDLE;
+		return;
+	}
+
+
+	switch (dev->ep0state) {
+	case EP0_IDLE:
+		/* start control request? */
+		if (ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) {
+			int len, ret, tmp;
+			
+			nuke (dev, ep);
+
+			len = read_fifo_crq(&crq);
+			if (len != sizeof(crq)) {
+			  	dprintk(DEBUG_NORMAL, "setup begin: fifo READ ERROR" 
+				    	" wanted %d bytes got %d. Stalling out...\n", 
+					sizeof(crq), len);
+ 				set_ep0_ss();
+				return;
+			}
+
+
+			/* cope with automagic for some standard requests. */
+			dev->req_std = (crq.bRequestType & USB_TYPE_MASK)
+						== USB_TYPE_STANDARD;
+			dev->req_config = 0;
+			dev->req_pending = 1;
+			switch (crq.bRequest) {
+				/* hardware restricts gadget drivers here! */
+				case USB_REQ_SET_CONFIGURATION:
+				    	dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ... \n");
+					if (crq.bRequestType == USB_RECIP_DEVICE) {
+config_change:
+						dev->req_config = 1;
+						clear_ep_state(dev);
+						set_ep0_de_out();
+					}
+					break;
+				/* ... and here, even more ... */
+				case USB_REQ_SET_INTERFACE:
+				    	dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ... \n");
+					if (crq.bRequestType == USB_RECIP_INTERFACE) {
+						goto config_change;
+					}
+					break;
+
+				/* hardware was supposed to hide this */
+				case USB_REQ_SET_ADDRESS:
+				    	dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ... \n");
+					if (crq.bRequestType == USB_RECIP_DEVICE) {
+						tmp = crq.wValue & 0x7F;
+						dev->address = tmp;
+ 						__raw_writel((tmp | 0x80), S3C2410_UDC_FUNC_ADDR_REG);
+						set_ep0_de_out();
+						return;
+					}
+					break;
+				default:
+					clear_ep0_opr();
+					break;
+			}
+
+			if (crq.bRequestType & USB_DIR_IN)
+				dev->ep0state = EP0_IN_DATA_PHASE;
+			else
+				dev->ep0state = EP0_OUT_DATA_PHASE;
+			ret = dev->driver->setup(&dev->gadget, &crq);
+			if (ret < 0) {
+				if (dev->req_config) {
+					dprintk(DEBUG_NORMAL, "config change %02x fail %d?\n",
+						crq.bRequest, ret);
+					return;
+				}
+				if (ret == -EOPNOTSUPP)
+					dprintk(DEBUG_NORMAL, "Operation not supported\n");
+				else
+					dprintk(DEBUG_NORMAL, "dev->driver->setup failed. (%d)\n",ret);
+				dev->ep0state = EP0_STALL;
+			/* deferred i/o == no response yet */
+			} else if (dev->req_pending) {
+			    	dprintk(DEBUG_NORMAL, "dev->req_pending... what now?\n");
+				dev->req_pending=0;
+			}
+			dprintk(DEBUG_VERBOSE, "ep0state %s\n",ep0states[dev->ep0state]);
+		}
+		break;
+	case EP0_IN_DATA_PHASE:			/* GET_DESCRIPTOR etc */
+	    	dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n");
+		if (!(ep0csr & 2) && req)
+		{
+			write_fifo(ep, req);
+		}
+		break;
+	case EP0_OUT_DATA_PHASE:		/* SET_DESCRIPTOR etc */
+	    	dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n");
+		if ((ep0csr & 1) && req ) {
+			read_fifo(ep,req);
+		}
+		break;
+	case EP0_END_XFER:
+	    	dprintk(DEBUG_NORMAL, "EP0_END_XFER ... what now?\n");
+		dev->ep0state=EP0_IDLE;
+		break;
+	case EP0_STALL:
+	    	set_ep0_ss();
+		break;
+	}
+}
+/*
+ * 	handle_ep - Manage I/O endpoints
+ */
+static void handle_ep(struct s3c2410_ep *ep)
+{
+	struct s3c2410_request	*req;
+	int			is_in = ep->bEndpointAddress & USB_DIR_IN;
+	u32			ep_csr1;
+	u32			idx;
+
+	if (likely (!list_empty(&ep->queue)))
+		req = list_entry(ep->queue.next,
+				struct s3c2410_request, queue);
+	else
+		req = 0;
+		
+	idx = (u32)(ep->bEndpointAddress&0x7F);
+
+	if (is_in) {
+		__raw_writel(idx, S3C2410_UDC_INDEX_REG);
+		ep_csr1 = __raw_readl(S3C2410_UDC_IN_CSR1_REG);
+		dprintk(DEBUG_VERBOSE, "ep%01d write csr:%02x ",idx,ep_csr1);
+		
+		if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL)
+		{
+			dprintk(DEBUG_VERBOSE, "st\n");
+			__raw_writel(idx, S3C2410_UDC_INDEX_REG);
+			__raw_writel(0x00,S3C2410_UDC_IN_CSR1_REG);
+			return;
+		}
+
+		if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req)
+		{
+			write_fifo(ep,req);
+		}
+	} 
+	else {
+		__raw_writel(idx, S3C2410_UDC_INDEX_REG);
+		ep_csr1 = __raw_readl(S3C2410_UDC_OUT_CSR1_REG);
+		dprintk(DEBUG_VERBOSE, "ep%01d read csr:%02x\n",idx,ep_csr1);
+		
+		if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL)
+		{
+			__raw_writel(idx, S3C2410_UDC_INDEX_REG);
+			__raw_writel(0x00,S3C2410_UDC_OUT_CSR1_REG);
+			return;
+		}
+		if( (ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req)
+		{
+			read_fifo(ep,req);
+		}
+	}
+}
+
+#include <asm/arch/regs-irq.h>
+/*
+ *      s3c2410_udc_irq - interrupt handler
+ */
+static irqreturn_t
+s3c2410_udc_irq(int irq, void *_dev, struct pt_regs *r)
+{
+	struct s3c2410_udc      *dev = _dev;
+	int usb_status;
+	int usbd_status;
+	int pwr_reg;
+	int ep0csr;
+	int     i;
+	u32	idx;
+
+	
+	spin_lock(&dev->lock);
+	
+	/* Save index */
+	idx = __raw_readl(S3C2410_UDC_INDEX_REG);
+
+	/* Read status registers */
+	usb_status = __raw_readl(S3C2410_UDC_USB_INT_REG);
+	usbd_status = __raw_readl(S3C2410_UDC_EP_INT_REG);
+	pwr_reg = __raw_readl(S3C2410_UDC_PWR_REG);
+
+	S3C2410_UDC_SETIX(EP0);
+	ep0csr = __raw_readl(S3C2410_UDC_IN_CSR1_REG);
+
+	dprintk(DEBUG_NORMAL, "usbs=%02x, usbds=%02x, pwr=%02x ep0csr=%02x\n", usb_status, usbd_status, pwr_reg,ep0csr);
+
+	/*
+	 * Now, handle interrupts. There's two types : 
+	 * - Reset, Resume, Suspend coming -> usb_int_reg
+	 * - EP -> ep_int_reg
+	 */
+
+	/* RESET */
+	if (usb_status & S3C2410_UDC_USBINT_RESET )
+	{
+		dprintk(DEBUG_NORMAL, "USB reset\n");
+		/* clear interrupt */
+		__raw_writel(S3C2410_UDC_USBINT_RESET,
+			S3C2410_UDC_USB_INT_REG);
+
+		__raw_writel(0x00, S3C2410_UDC_INDEX_REG);
+		__raw_writel(0x01,S3C2410_UDC_MAXP_REG);
+		
+		dev->address = 0x00;
+		__raw_writel( 0x80, S3C2410_UDC_FUNC_ADDR_REG);
+
+		dev->gadget.speed = USB_SPEED_FULL;
+		dev->ep0state = EP0_IDLE;
+	}
+
+	/* RESUME */
+	if (usb_status & S3C2410_UDC_USBINT_RESUME)
+	{
+		dprintk(DEBUG_NORMAL, "USB resume\n");
+		
+		/* clear interrupt */
+		__raw_writel(S3C2410_UDC_USBINT_RESUME,
+			S3C2410_UDC_USB_INT_REG);
+
+		if (dev->gadget.speed != USB_SPEED_UNKNOWN
+			&& dev->driver
+			&& dev->driver->resume)
+			dev->driver->resume(&dev->gadget);
+	}
+
+	/* SUSPEND */
+	if (usb_status & S3C2410_UDC_USBINT_SUSPEND)
+	{
+		dprintk(DEBUG_NORMAL, "USB suspend\n");
+			
+		/* clear interrupt */
+		__raw_writel(S3C2410_UDC_USBINT_SUSPEND,
+			S3C2410_UDC_USB_INT_REG);
+				
+		if (dev->gadget.speed != USB_SPEED_UNKNOWN
+				&& dev->driver
+				&& dev->driver->suspend)
+			dev->driver->suspend(&dev->gadget);
+
+		dev->ep0state = EP0_IDLE;
+	}
+
+	/* EP */
+	/* control traffic */
+	/* check on ep0csr != 0 is not a good idea as clearing in_pkt_ready
+	 * generate an interrupt 
+	 */
+	if (usbd_status & S3C2410_UDC_INT_EP0)
+	{
+		dprintk(DEBUG_NORMAL, "USB ep0 irq\n");
+		/* Clear the interrupt bit by setting it to 1 */
+		__raw_writel(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG);
+		handle_ep0(dev);
+	}
+	/* endpoint data transfers */
+	for (i = 1; i < S3C2410_ENDPOINTS; i++) {
+		u32 tmp = 1 << i;
+		if (usbd_status & tmp) {
+			dprintk(DEBUG_VERBOSE, "USB ep%d irq\n", i);
+
+			/* Clear the interrupt bit by setting it to 1 */
+			__raw_writel(tmp, S3C2410_UDC_EP_INT_REG);
+			handle_ep(&dev->ep[i]);
+		}
+	}
+	
+
+	dprintk(DEBUG_NORMAL,"irq: %d done.\n", irq);
+
+	/* Restore old index */
+	__raw_writel(idx,S3C2410_UDC_INDEX_REG);
+
+	spin_unlock(&dev->lock);
+
+	return IRQ_HANDLED;		
+}
+/*------------------------- s3c2410_ep_ops ----------------------------------*/
+
+/*
+ * 	s3c2410_ep_enable
+ */
+static int
+s3c2410_ep_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct s3c2410_udc	*dev;
+	struct s3c2410_ep	*ep;
+	u32			max, tmp;
+	unsigned long		flags;
+	u32			csr1,csr2;
+	u32			int_en_reg;
+
+
+	ep = container_of (_ep, struct s3c2410_ep, ep);
+	if (!_ep || !desc || ep->desc || _ep->name == ep0name
+			|| desc->bDescriptorType != USB_DT_ENDPOINT)
+		return -EINVAL;
+	dev = ep->dev;
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	max = le16_to_cpu (desc->wMaxPacketSize) & 0x1fff;
+
+	spin_lock_irqsave (&dev->lock, flags);
+	_ep->maxpacket = max & 0x7ff;
+	ep->desc = desc;
+	ep->bEndpointAddress = desc->bEndpointAddress;
+
+	/* set max packet */
+	__raw_writel(ep->num, S3C2410_UDC_INDEX_REG);
+	__raw_writel(max>>3,S3C2410_UDC_MAXP_REG);
+
+
+	/* set type, direction, address; reset fifo counters */
+	if (desc->bEndpointAddress & USB_DIR_IN)
+	{
+		csr1 = S3C2410_UDC_ICSR1_FFLUSH|S3C2410_UDC_ICSR1_CLRDT;
+		csr2 = S3C2410_UDC_ICSR2_MODEIN|S3C2410_UDC_ICSR2_DMAIEN;
+		
+		__raw_writel(ep->num, S3C2410_UDC_INDEX_REG);
+		__raw_writel(csr1,S3C2410_UDC_IN_CSR1_REG);
+		__raw_writel(ep->num, S3C2410_UDC_INDEX_REG);
+		__raw_writel(csr2,S3C2410_UDC_IN_CSR2_REG);
+	}
+	else
+	{
+		/* don't flush he in fifo or there will be an interrupt for that
+		 * endpoint */ 
+		csr1 = S3C2410_UDC_ICSR1_CLRDT;
+		csr2 = S3C2410_UDC_ICSR2_DMAIEN;
+
+		__raw_writel(ep->num, S3C2410_UDC_INDEX_REG);
+		__raw_writel(csr1,S3C2410_UDC_IN_CSR1_REG);
+		__raw_writel(ep->num, S3C2410_UDC_INDEX_REG);
+		__raw_writel(csr2,S3C2410_UDC_IN_CSR2_REG);
+		
+		csr1 = S3C2410_UDC_OCSR1_FFLUSH | S3C2410_UDC_OCSR1_CLRDT;
+		csr2 = S3C2410_UDC_OCSR2_DMAIEN;
+		
+		__raw_writel(ep->num, S3C2410_UDC_INDEX_REG);
+		__raw_writel(csr1,S3C2410_UDC_OUT_CSR1_REG);
+		__raw_writel(ep->num, S3C2410_UDC_INDEX_REG);
+		__raw_writel(csr2,S3C2410_UDC_OUT_CSR2_REG);
+	}
+
+	
+	/* enable irqs */
+	int_en_reg = __raw_readl(S3C2410_UDC_EP_INT_EN_REG);
+	__raw_writel(int_en_reg | (1<<ep->num),S3C2410_UDC_EP_INT_EN_REG);
+
+
+	/* print some debug message */
+	tmp = desc->bEndpointAddress;
+	dprintk (DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n",
+		_ep->name,ep->num, tmp, desc->bEndpointAddress & USB_DIR_IN ? "in" : "out", max);
+
+	spin_unlock_irqrestore (&dev->lock, flags);
+	
+	return 0;
+}
+
+/*
+ * s3c2410_ep_disable
+ */
+static int s3c2410_ep_disable (struct usb_ep *_ep)
+{
+	struct s3c2410_ep	*ep = container_of(_ep, struct s3c2410_ep, ep);
+	unsigned long	flags;
+	u32			int_en_reg;
+
+
+	if (!_ep || !ep->desc) {
+		dprintk(DEBUG_NORMAL, "%s not enabled\n",
+			_ep ? ep->ep.name : NULL);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+	ep->desc = 0;
+	
+	nuke (ep->dev, ep);
+
+	/* disable irqs */
+	int_en_reg = __raw_readl(S3C2410_UDC_EP_INT_EN_REG);
+	__raw_writel(int_en_reg & ~(1<<ep->num),S3C2410_UDC_EP_INT_EN_REG);
+
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+	dprintk(DEBUG_NORMAL, "%s disabled\n", _ep->name);
+
+	return 0;
+}
+
+/*
+ * s3c2410_alloc_request
+ */
+static struct usb_request *
+s3c2410_alloc_request (struct usb_ep *_ep, int mem_flags)
+{
+	struct s3c2410_ep	*ep;
+	struct s3c2410_request	*req;
+
+    	dprintk(DEBUG_NORMAL,"s3c2410_alloc_request(ep=%p,flags=%d)\n", _ep, mem_flags);
+
+	ep = container_of (_ep, struct s3c2410_ep, ep);
+	if (!_ep)
+		return 0;
+
+	req = kmalloc (sizeof *req, mem_flags);
+	if (!req)
+		return 0;
+	memset (req, 0, sizeof *req);
+	INIT_LIST_HEAD (&req->queue);
+	return &req->req;
+}
+
+/*
+ * s3c2410_free_request
+ */
+static void
+s3c2410_free_request (struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct s3c2410_ep	*ep;
+	struct s3c2410_request	*req;
+
+    	dprintk(DEBUG_NORMAL, "s3c2410_free_request(ep=%p,req=%p)\n", _ep, _req);
+
+	ep = container_of (_ep, struct s3c2410_ep, ep);
+	if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
+		return;
+
+	req = container_of (_req, struct s3c2410_request, req);
+	WARN_ON (!list_empty (&req->queue));
+	kfree (req);
+}
+
+/*
+ * 	s3c2410_alloc_buffer
+ */
+static void *
+s3c2410_alloc_buffer (
+	struct usb_ep *_ep,
+	unsigned bytes,
+	dma_addr_t *dma,
+	int mem_flags)
+{
+	char *retval;
+
+    	dprintk(DEBUG_NORMAL,"s3c2410_alloc_buffer()\n");
+
+	if (!the_controller->driver)
+		return 0;
+	retval = kmalloc (bytes, mem_flags);
+	*dma = (dma_addr_t) retval;
+	return retval;
+}
+
+/*
+ * s3c2410_free_buffer
+ */
+static void
+s3c2410_free_buffer (
+	struct usb_ep *_ep,
+	void *buf,
+	dma_addr_t dma,
+	unsigned bytes)
+{
+    	dprintk(DEBUG_NORMAL, "s3c2410_free_buffer()\n");
+
+	if (bytes)
+		kfree (buf);
+}
+
+/*
+ * 	s3c2410_queue
+ */
+static int
+s3c2410_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
+{
+	struct s3c2410_request	*req;
+	struct s3c2410_ep	*ep;
+	struct s3c2410_udc	*dev;
+	u32			ep_csr=0;
+	int 			fifo_count=0;
+
+	req = container_of(_req, struct s3c2410_request, req);
+	if (unlikely (!_req || !_req->complete || !_req->buf
+	|| !list_empty(&req->queue))) {
+		if (!_req)
+			dprintk(DEBUG_NORMAL, "s3c2410_queue: 1 X X X\n");
+		else
+		{
+			dprintk(DEBUG_NORMAL, "s3c2410_queue: 0 %01d %01d %01d\n",!_req->complete,!_req->buf, !list_empty(&req->queue));
+		}
+		return -EINVAL;
+	}
+
+	ep = container_of(_ep, struct s3c2410_ep, ep);
+	if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+		dprintk(DEBUG_NORMAL, "s3c2410_queue: inval 2\n");
+		return -EINVAL;
+	}
+
+	dev = ep->dev;
+	if (unlikely (!dev->driver
+			|| dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+		return -ESHUTDOWN;
+	}
+
+	/* iso is always one packet per request, that's the only way
+	 * we can report per-packet status.  that also helps with dma.
+	 */
+	if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
+			&& req->req.length > le16_to_cpu
+						(ep->desc->wMaxPacketSize)))
+		return -EMSGSIZE;
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	if (ep->bEndpointAddress)
+	{
+		__raw_writel(ep->bEndpointAddress&0x7F,S3C2410_UDC_INDEX_REG);
+		ep_csr = __raw_readl(ep->bEndpointAddress&USB_DIR_IN ? S3C2410_UDC_IN_CSR1_REG : S3C2410_UDC_OUT_CSR1_REG);
+		fifo_count=fifo_count_out();
+	}
+	/* kickstart this i/o queue? */
+	if (list_empty(&ep->queue)) {
+		if (ep->bEndpointAddress == 0 /* ep0 */) {
+
+			switch (dev->ep0state) {
+			case EP0_IN_DATA_PHASE:
+				if (write_fifo(ep, req))
+				{
+					req = 0;
+				}
+				break;
+
+			case EP0_OUT_DATA_PHASE:
+				/* nothing to do here */
+				dev->ep0state = EP0_IDLE;
+				break;
+
+			default:
+				return -EL2HLT;
+			}
+		}
+		else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
+				&& (!(ep_csr&S3C2410_UDC_OCSR1_PKTRDY)) && write_fifo(ep, req)) {
+			req = 0;
+		} else if ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY) && fifo_count && read_fifo(ep, req)) {
+			req = 0;
+		}
+
+	}
+
+	/* pio or dma irq handler advances the queue. */
+	if (likely (req != 0))
+		list_add_tail(&req->queue, &ep->queue);
+	dprintk(DEBUG_VERBOSE, "s3c2410_queue normal end\n");
+	return 0;
+}
+
+/* 
+ * 	s3c2410_dequeue
+ */
+static int s3c2410_dequeue (struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct s3c2410_ep	*ep;
+	struct s3c2410_udc	*udc;
+	int			retval = -EINVAL;
+	unsigned long		flags;
+	struct s3c2410_request	*req = 0;
+
+    	dprintk(DEBUG_NORMAL,"s3c2410_dequeue(ep=%p,req=%p)\n", _ep, _req);
+
+	if (!the_controller->driver)
+		return -ESHUTDOWN;
+
+	if (!_ep || !_req)
+		return retval;
+	ep = container_of (_ep, struct s3c2410_ep, ep);
+	udc = container_of (ep->gadget, struct s3c2410_udc, gadget);
+
+	spin_lock_irqsave (&udc->lock, flags);
+	list_for_each_entry (req, &ep->queue, queue) {
+		if (&req->req == _req) {
+			list_del_init (&req->queue);
+			_req->status = -ECONNRESET;
+			retval = 0;
+			break;
+		}
+	}
+	spin_unlock_irqrestore (&udc->lock, flags);
+
+	if (retval == 0) {
+		dprintk(DEBUG_VERBOSE, "dequeued req %p from %s, len %d buf %p\n",
+				req, _ep->name, _req->length, _req->buf);
+
+		_req->complete (_ep, _req);
+		done(ep, req, -ECONNRESET);
+	}
+	return retval;
+
+	return 0;
+}
+
+
+/* 
+ * s3c2410_set_halt
+ */
+static int
+s3c2410_set_halt (struct usb_ep *_ep, int value)
+{
+	return 0;
+}
+
+
+static const struct usb_ep_ops s3c2410_ep_ops = {
+	.enable         = s3c2410_ep_enable,
+	.disable        = s3c2410_ep_disable,
+	
+	.alloc_request  = s3c2410_alloc_request,
+	.free_request   = s3c2410_free_request,
+	
+	.alloc_buffer   = s3c2410_alloc_buffer,
+	.free_buffer    = s3c2410_free_buffer,
+	
+	.queue          = s3c2410_queue,
+	.dequeue        = s3c2410_dequeue,
+	
+	.set_halt       = s3c2410_set_halt,
+};
+
+/*------------------------- usb_gadget_ops ----------------------------------*/
+
+/*
+ * 	s3c2410_g_get_frame
+ */
+static int s3c2410_g_get_frame (struct usb_gadget *_gadget)
+{
+	int tmp;
+	
+	dprintk(DEBUG_VERBOSE,"s3c2410_g_get_frame()\n");
+
+	tmp = __raw_readl(S3C2410_UDC_FRAME_NUM2_REG) << 8;
+	tmp |= __raw_readl(S3C2410_UDC_FRAME_NUM1_REG);
+	
+	return tmp & 0xffff;
+}
+
+/*
+ * 	s3c2410_wakeup
+ */
+static int s3c2410_wakeup (struct usb_gadget *_gadget)
+{
+	
+	dprintk(DEBUG_NORMAL,"s3c2410_wakeup()\n");
+	
+	return 0;
+}
+
+/*
+ * 	s3c2410_set_selfpowered
+ */
+static int s3c2410_set_selfpowered (struct usb_gadget *_gadget, int value)
+{
+	struct s3c2410_udc  *udc;
+	
+	dprintk(DEBUG_NORMAL, "s3c2410_set_selfpowered()\n");
+	
+	udc = container_of (_gadget, struct s3c2410_udc, gadget);
+	
+	if (value)
+		udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
+	else
+		udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+	
+	return 0;
+}
+                                                                                   
+
+
+static const struct usb_gadget_ops s3c2410_ops = {
+	.get_frame          = s3c2410_g_get_frame,
+	.wakeup             = s3c2410_wakeup,
+	.set_selfpowered    = s3c2410_set_selfpowered,
+};
+
+
+/*------------------------- gadget driver handling---------------------------*/
+/*
+ * udc_disable
+ */
+static void udc_disable(struct s3c2410_udc *dev)
+{
+	dprintk(DEBUG_NORMAL, "udc_disable called");
+	
+	/* Set address to 0 */
+	__raw_writel( 0x80, S3C2410_UDC_FUNC_ADDR_REG);
+
+	/* Disable all interrupts */
+	__raw_writel(0x00, S3C2410_UDC_USB_INT_EN_REG);
+	__raw_writel(0x00, S3C2410_UDC_EP_INT_EN_REG);
+
+	/* Set speed to unknown */
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+}
+/*
+ * udc_reinit
+ */
+static void udc_reinit(struct s3c2410_udc *dev)
+{
+	u32     i;
+
+	/* device/ep0 records init */
+	INIT_LIST_HEAD (&dev->gadget.ep_list);
+	INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
+	dev->ep0state = EP0_IDLE;
+	
+
+	for (i = 0; i < S3C2410_ENDPOINTS; i++) {
+		struct s3c2410_ep *ep = &dev->ep[i];
+
+		if (i != 0)
+			list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
+
+		ep->dev = dev;
+		ep->desc = 0;
+		INIT_LIST_HEAD (&ep->queue);
+	}
+}
+
+/*
+ * udc_enable
+ */
+static void udc_enable(struct s3c2410_udc *dev)
+{
+	int i;
+	
+	dprintk(DEBUG_NORMAL, "udc_enable called");
+	
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+	
+	/* Set pad to usb device and usbsuspend to 'normal' */
+	__raw_writel(__raw_readl(S3C2410_MISCCR)&~0x3008,S3C2410_MISCCR);
+
+	/* Set MAXP for all endpoints */
+	for (i = 0; i < S3C2410_ENDPOINTS; i++) {
+		struct s3c2410_ep *ep = &dev->ep[i];
+
+		__raw_writel(i, S3C2410_UDC_INDEX_REG);
+/*		__raw_writel(ep->ep.maxpacket>>3,S3C2410_UDC_MAXP_REG);*/
+		__raw_writel(0x0001,S3C2410_UDC_MAXP_REG);
+	}
+
+	/* Set default power state */
+	__raw_writel(DEFAULT_POWER_STATE, S3C2410_UDC_PWR_REG);
+
+	/* Enable reset and suspend interrupt interrupts */
+	__raw_writel(1<<2 | 1<<0 ,S3C2410_UDC_USB_INT_EN_REG);
+	
+	/* Enable ep0 interrupt */
+	__raw_writel(0x01,S3C2410_UDC_EP_INT_EN_REG);
+}
+
+
+/*
+ * 	nop_release
+ */
+static void nop_release (struct device *dev)
+{
+	        dprintk(DEBUG_NORMAL, "%s %s\n", __FUNCTION__, dev->bus_id);
+}
+/*
+ *	usb_gadget_register_driver
+ */
+int
+usb_gadget_register_driver (struct usb_gadget_driver *driver)
+{
+	struct s3c2410_udc *udc = the_controller;
+	int		retval;
+
+    	dprintk(DEBUG_NORMAL, "usb_gadget_register_driver() '%s'\n",
+		driver->driver.name);
+
+	/* Sanity checks */
+	if (!udc)
+		return -ENODEV;
+	if (udc->driver)
+		return -EBUSY;
+	if (!driver->bind || !driver->unbind || !driver->setup
+			|| driver->speed == USB_SPEED_UNKNOWN)
+		return -EINVAL;
+
+	/* Hook the driver */
+	udc->driver = driver;
+	udc->gadget.dev.driver = &driver->driver;
+
+	/*Bind the driver */
+	device_add(&udc->gadget.dev);
+	dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n", driver->driver.name);
+	if ((retval = driver->bind (&udc->gadget)) != 0) {
+		device_del(&udc->gadget.dev);
+		udc->driver = 0;
+		udc->gadget.dev.driver = 0;
+		return retval;
+	}
+
+        /* driver->driver.bus = 0; */
+
+	/* Enable udc */
+	udc_enable(udc);
+	
+	return 0;
+}
+
+
+/*
+ * 	usb_gadget_unregister_driver
+ */
+int
+usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+{
+	struct s3c2410_udc *udc = the_controller;
+
+	if (!udc)
+		return -ENODEV;
+	if (!driver || driver != udc->driver)
+		return -EINVAL;
+
+    	dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n",
+		driver->driver.name);
+
+	driver->unbind (&udc->gadget);
+	device_del(&udc->gadget.dev);
+	udc->driver = 0;
+
+	device_release_driver (&udc->gadget.dev);
+	driver_unregister (&driver->driver);
+
+	/* Disable udc */
+	udc_disable(udc);
+	
+	return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static struct s3c2410_udc memory = {
+	.gadget = {
+		.ops		= &s3c2410_ops,
+		.ep0		= &memory.ep[0].ep,
+		.name		= gadget_name,
+		.dev = {
+			.bus_id		= "gadget",
+			.release	= nop_release,
+		},
+	},
+
+	/* control endpoint */
+	.ep[0] = {
+		.num		= 0,
+		.ep = {
+			.name		= ep0name,
+			.ops		= &s3c2410_ep_ops,
+			.maxpacket	= EP0_FIFO_SIZE,
+		},
+		.dev		= &memory,
+	},
+
+	/* first group of endpoints */
+	.ep[1] = {
+		.num		= 1,
+		.ep = {
+			.name		= "ep1-bulk",
+			.ops		= &s3c2410_ep_ops,
+			.maxpacket	= EP_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= EP_FIFO_SIZE,
+		.bEndpointAddress = 1,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+	},
+	.ep[2] = {
+		.num		= 2,
+		.ep = {
+			.name		= "ep2-bulk",
+			.ops		= &s3c2410_ep_ops,
+			.maxpacket	= EP_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= EP_FIFO_SIZE,
+		.bEndpointAddress = 2,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+	},
+	.ep[3] = {
+		.num		= 3,
+		.ep = {
+			.name		= "ep3-bulk",
+			.ops		= &s3c2410_ep_ops,
+			.maxpacket	= EP_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= EP_FIFO_SIZE,
+		.bEndpointAddress = 3,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+	},
+	.ep[4] = {
+		.num		= 4,
+		.ep = {
+			.name		= "ep4-bulk",
+			.ops		= &s3c2410_ep_ops,
+			.maxpacket	= EP_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= EP_FIFO_SIZE,
+		.bEndpointAddress = 4,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+	}
+
+};
+
+/*
+ *	probe - binds to the platform device
+ */
+static int __init s3c2410_udc_probe(struct device *_dev)
+{
+	struct s3c2410_udc *udc = &memory;
+	int retval;
+
+
+	dprintk(DEBUG_NORMAL,"s3c2410_udc_probe\n");
+
+	spin_lock_init (&udc->lock);
+
+	device_initialize(&udc->gadget.dev);
+	udc->gadget.dev.parent = _dev;
+	udc->gadget.dev.dma_mask = _dev->dma_mask;
+
+	the_controller = udc;
+	dev_set_drvdata(_dev, udc);
+
+	udc_disable(udc);
+	udc_reinit(udc);
+	
+	/* irq setup after old hardware state is cleaned up */
+	retval = request_irq(IRQ_USBD, s3c2410_udc_irq,
+		SA_INTERRUPT, gadget_name, udc);
+	if (retval != 0) {
+		printk(KERN_ERR "%s: can't get irq %i, err %d\n",
+			gadget_name, IRQ_USBD, retval);
+		return -EBUSY;
+	}
+	dprintk(DEBUG_VERBOSE, "%s: got irq %i\n", gadget_name, IRQ_USBD);
+
+#ifdef ENABLE_SYSFS
+	/* create device files */
+	device_create_file(_dev, &dev_attr_regs);
+#endif
+	return 0;
+}
+
+/*
+ * 	s3c2410_udc_remove
+ */
+static int __exit s3c2410_udc_remove(struct device *_dev)
+{
+	struct s3c2410_udc *udc = _dev->driver_data;
+	
+	dprintk(DEBUG_NORMAL, "s3c2410_udc_remove\n");
+	usb_gadget_unregister_driver(udc->driver);
+	
+	if (udc->got_irq) {
+		free_irq(IRQ_USBD, udc);
+		udc->got_irq = 0;
+	}
+	
+	dev_set_drvdata(_dev, 0);
+	kfree(udc);
+	
+	return 0;
+}
+                                                                               
+static struct device_driver udc_driver = {
+	.name		= "s3c2410-usbgadget",
+	.bus            = &platform_bus_type,
+	.probe          = s3c2410_udc_probe,
+	.remove         = __exit_p(s3c2410_udc_remove),			
+};
+
+static int __init udc_init(void)
+{
+	u32 tmp;
+	dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION);
+	
+	
+	udc_clock = clk_get(NULL, "usb-device");
+	if (!udc_clock) {
+		printk(KERN_INFO "failed to get udc clock source\n");
+		return -ENOENT;
+	}
+	clk_use(udc_clock);
+
+	clk_disable(udc_clock);
+	
+	tmp = __raw_readl(S3C2410_MISCCR);
+	tmp &= ~S3C2410_MISCCR_USBHOST;
+	__raw_writel(tmp, S3C2410_MISCCR);
+
+	tmp = (
+		 0x78 << S3C2410_PLLCON_MDIVSHIFT)
+	      | (0x02 << S3C2410_PLLCON_PDIVSHIFT)
+	      | (0x03 << S3C2410_PLLCON_SDIVSHIFT);
+	__raw_writel(tmp, S3C2410_UPLLCON);
+	
+
+	clk_enable(udc_clock);
+
+	mdelay(10);
+
+	dprintk(DEBUG_VERBOSE, "got and enabled clock\n");
+							
+	return driver_register(&udc_driver);
+}
+
+static void __exit udc_exit(void)
+{
+	if (udc_clock) {
+		clk_disable(udc_clock);
+		clk_unuse(udc_clock);
+		clk_put(udc_clock);
+		udc_clock = NULL;
+	}
+		
+	driver_unregister(&udc_driver);
+}
+
+
+EXPORT_SYMBOL (usb_gadget_unregister_driver);
+EXPORT_SYMBOL (usb_gadget_register_driver);
+
+module_init(udc_init);
+module_exit(udc_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff -Naurp linux-2.6.11-rc2-bk1/drivers/usb/gadget/s3c2410_udc.h linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/s3c2410_udc.h
--- linux-2.6.11-rc2-bk1/drivers/usb/gadget/s3c2410_udc.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/s3c2410_udc.h	2005-01-23 23:31:08.000000000 +0100
@@ -0,0 +1,175 @@
+#ifndef _S3C2410_UDC_H
+#define _S3C2410_UDC_H
+
+struct s3c2410_ep {
+	struct list_head		queue;
+	unsigned long			last_io;	/* jiffies timestamp */
+	struct usb_gadget		*gadget;
+	struct s3c2410_udc		*dev;
+	const struct usb_endpoint_descriptor *desc;
+	struct usb_ep			ep;
+	u8				num;
+
+	unsigned short			fifo_size;
+	u8				bEndpointAddress;
+	u8				bmAttributes;
+
+	unsigned			halted : 1;
+	unsigned			already_seen : 1;
+	unsigned			setup_stage : 1;
+};
+
+
+#define EP0_FIFO_SIZE		8
+#define EP_FIFO_SIZE		64
+#define DEFAULT_POWER_STATE	0x00
+
+static const char ep0name [] = "ep0";
+
+static const char *const ep_name[] = {
+	ep0name,                                /* everyone has ep0 */
+	/* s3c2410 four bidirectional bulk endpoints */
+	"ep1-bulk", "ep2-bulk", "ep3-bulk", "ep4-bulk",
+};
+
+#define S3C2410_ENDPOINTS       ARRAY_SIZE(ep_name)
+
+struct s3c2410_request {
+	struct list_head		queue;		/* ep's requests */
+	struct usb_request		req;
+};
+
+enum ep0_state { 
+        EP0_IDLE,
+        EP0_IN_DATA_PHASE,
+        EP0_OUT_DATA_PHASE,
+        EP0_END_XFER,
+        EP0_STALL,
+};
+
+static const char *ep0states[]= {
+        "EP0_IDLE",
+        "EP0_IN_DATA_PHASE",
+        "EP0_OUT_DATA_PHASE",
+        "EP0_END_XFER",
+        "EP0_STALL",
+};
+
+struct s3c2410_udc {
+	spinlock_t			lock;
+
+	struct s3c2410_ep		ep[S3C2410_ENDPOINTS];
+	int				address;
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver	*driver;
+	struct s3c2410_request		fifo_req;
+	u8				fifo_buf[EP_FIFO_SIZE];
+	u16				devstatus;
+	
+	u32				port_status;
+    	int 	    	    	    	ep0state;
+
+	unsigned			got_irq : 1;
+	
+	unsigned			req_std : 1;
+	unsigned			req_config : 1;
+	unsigned			req_pending : 1;
+};
+
+/****************** MACROS ******************/
+/* #define BIT_MASK	BIT_MASK*/
+#define BIT_MASK	0xFF
+
+#define __raw_maskb(v,m,a)      \
+	        __raw_writeb((__raw_readb(a) & ~(m))|((v)&(m)), (a))
+
+#define __raw_maskw(v,m,a)      \
+	        __raw_writew((__raw_readw(a) & ~(m))|((v)&(m)), (a))
+
+#define __raw_maskl(v,m,a)      \
+	        __raw_writel((__raw_readl(a) & ~(m))|((v)&(m)), (a))
+
+#define clear_ep0_sst() do { 				\
+    	S3C2410_UDC_SETIX(EP0); 			\
+	__raw_writel(0x00, S3C2410_UDC_EP0_CSR_REG); 	\
+} while(0)
+
+#define clear_ep0_se() do {				\
+    	S3C2410_UDC_SETIX(EP0); 			\
+	__raw_maskl(S3C2410_UDC_EP0_CSR_SSE,		\
+	    	BIT_MASK, S3C2410_UDC_EP0_CSR_REG); 	\
+} while(0)
+
+#define clear_ep0_opr() do {				\
+   	S3C2410_UDC_SETIX(EP0);				\
+	__raw_maskl(S3C2410_UDC_EP0_CSR_SOPKTRDY,	\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG); 	\
+} while(0)
+
+#define set_ep0_ipr() do {				\
+   	S3C2410_UDC_SETIX(EP0);				\
+	__raw_maskl(S3C2410_UDC_EP0_CSR_IPKRDY,		\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG); 	\
+} while(0)
+
+#define set_ep0_de() do {				\
+   	S3C2410_UDC_SETIX(EP0);				\
+	__raw_maskl(S3C2410_UDC_EP0_CSR_DE,		\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG);		\
+} while(0)
+
+#define set_ep0_ss() do {				\
+   	S3C2410_UDC_SETIX(EP0);				\
+	__raw_maskl(S3C2410_UDC_EP0_CSR_SENDSTL,	\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG);	\
+} while(0)
+
+#define set_ep0_de_out() do {				\
+   	S3C2410_UDC_SETIX(EP0);				\
+	__raw_maskl((S3C2410_UDC_EP0_CSR_SOPKTRDY 	\
+		| S3C2410_UDC_EP0_CSR_DE),		\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG);		\
+} while(0)
+
+#define set_ep0_sse_out() do {				\
+   	S3C2410_UDC_SETIX(EP0);				\
+	__raw_maskl((S3C2410_UDC_EP0_CSR_SOPKTRDY 	\
+		| S3C2410_UDC_EP0_CSR_SSE),		\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG);		\
+} while(0)
+
+#define set_ep0_de_in() do {				\
+   	S3C2410_UDC_SETIX(EP0);				\
+	__raw_maskl((S3C2410_UDC_EP0_CSR_IPKRDY		\
+		| S3C2410_UDC_EP0_CSR_DE),		\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG);		\
+} while(0)
+
+
+
+#define clear_stall_ep1_out() do {			\
+   	S3C2410_UDC_SETIX(EP1);				\
+	__raw_orl(0, S3C2410_UDC_OUT_CSR1_REG);		\
+} while(0)
+
+
+#define clear_stall_ep2_out() do {			\
+   	S3C2410_UDC_SETIX(EP2);				\
+	__raw_orl(0, S3C2410_UDC_OUT_CSR1_REG);		\
+} while(0)
+
+
+#define clear_stall_ep3_out() do {			\
+   	S3C2410_UDC_SETIX(EP3);				\
+	__raw_orl(0, S3C2410_UDC_OUT_CSR1_REG);		\
+} while(0)
+
+
+#define clear_stall_ep4_out() do {			\
+   	S3C2410_UDC_SETIX(EP4);				\
+	__raw_orl(0, S3C2410_UDC_OUT_CSR1_REG);		\
+} while(0)
+
+#endif
+
+
diff -Naurp linux-2.6.11-rc2-bk1/drivers/usb/gadget/serial.c linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/serial.c
--- linux-2.6.11-rc2-bk1/drivers/usb/gadget/serial.c	2005-01-23 22:57:36.000000000 +0100
+++ linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/serial.c	2005-01-23 23:30:52.000000000 +0100
@@ -485,7 +485,11 @@ static struct usb_gadget_strings gs_stri
 static struct usb_device_descriptor gs_device_desc = {
 	.bLength =		USB_DT_DEVICE_SIZE,
 	.bDescriptorType =	USB_DT_DEVICE,
-	.bcdUSB =		__constant_cpu_to_le16(0x0200),
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+ 	.bcdUSB =		__constant_cpu_to_le16(0x0200),
+#else
+	.bcdUSB =		__constant_cpu_to_le16(0x0110),
+#endif
 	.bDeviceSubClass =	0,
 	.bDeviceProtocol =	0,
 	.idVendor =		__constant_cpu_to_le16(GS_VENDOR_ID),
@@ -1531,6 +1535,9 @@ static int gs_bind(struct usb_gadget *ga
 	} else if (gadget_is_pxa27x(gadget)) {
 		gs_device_desc.bcdDevice =
 			__constant_cpu_to_le16(GS_VERSION_NUM|0x0011);
+ 	} else if (gadget_is_s3c2410(gadget)) {
+ 		gs_device_desc.bcdDevice =
+ 			__constant_cpu_to_le16(GS_VERSION_NUM|0x0012);
 	} else {
 		printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n",
 			gadget->name);
diff -Naurp linux-2.6.11-rc2-bk1/drivers/usb/gadget/zero.c linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/zero.c
--- linux-2.6.11-rc2-bk1/drivers/usb/gadget/zero.c	2004-12-24 22:34:32.000000000 +0100
+++ linux-2.6.11-rc2-bk1-h1940/drivers/usb/gadget/zero.c	2005-01-23 23:30:52.000000000 +0100
@@ -226,7 +226,11 @@ device_desc = {
 	.bLength =		sizeof device_desc,
 	.bDescriptorType =	USB_DT_DEVICE,
 
+#ifdef	CONFIG_USB_GADGET_DUALSPEED
 	.bcdUSB =		__constant_cpu_to_le16 (0x0200),
+#else
+	.bcdUSB =               __constant_cpu_to_le16 (0x0110),
+#endif
 	.bDeviceClass =		USB_CLASS_VENDOR_SPEC,
 
 	.idVendor =		__constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
@@ -1191,6 +1195,8 @@ autoconf_fail:
 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
 	} else if (gadget_is_pxa27x(gadget)) {
 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
+	} else if (gadget_is_s3c2410(gadget)) {
+ 		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
 	} else {
 		/* gadget zero is so simple (for now, no altsettings) that
 		 * it SHOULD NOT have problems with bulk-capable hardware.
diff -Naurp linux-2.6.11-rc2-bk1/drivers/usb/Kconfig linux-2.6.11-rc2-bk1-h1940/drivers/usb/Kconfig
--- linux-2.6.11-rc2-bk1/drivers/usb/Kconfig	2004-12-24 22:34:02.000000000 +0100
+++ linux-2.6.11-rc2-bk1-h1940/drivers/usb/Kconfig	2005-01-23 23:31:19.000000000 +0100
@@ -1,99 +1,388 @@
 #
-# USB device configuration
+# USB Gadget support on a system involves
+#    (a) a peripheral controller, and
+#    (b) the gadget driver using it.
 #
+# NOTE:  Gadget support ** DOES NOT ** depend on host-side CONFIG_USB !!
+#
+#  - Host systems (like PCs) need CONFIG_USB (with "A" jacks).
+#  - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks).
+#  - Some systems have both kinds of of controller.
+#
+# With help from a special transceiver and a "Mini-AB" jack, systems with
+# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG).
+#
+menu "USB Gadget Support"
 
-menu "USB support"
+config USB_GADGET
+	tristate "Support for USB Gadgets"
+	help
+	   USB is a master/slave protocol, organized with one master
+	   host (such as a PC) controlling up to 127 peripheral devices.
+	   The USB hardware is asymmetric, which makes it easier to set up:
+	   you can't connect a "to-the-host" connector to a peripheral.
+
+	   Linux can run in the host, or in the peripheral.  In both cases
+	   you need a low level bus controller driver, and some software
+	   talking to it.  Peripheral controllers are often discrete silicon,
+	   or are integrated with the CPU in a microcontroller.  The more
+	   familiar host side controllers have names like like "EHCI", "OHCI",
+	   or "UHCI", and are usually integrated into southbridges on PC
+	   motherboards.
+
+	   Enable this configuration option if you want to run Linux inside
+	   a USB peripheral device.  Configure one hardware driver for your
+	   peripheral/device side bus controller, and a "gadget driver" for
+	   your peripheral protocol.  (If you use modular gadget drivers,
+	   you may configure more than one.)
+
+	   If in doubt, say "N" and don't enable these drivers; most people
+	   don't have this kind of hardware (except maybe inside Linux PDAs).
+
+config USB_GADGET_DEBUG_FILES
+	boolean "Debugging information files"
+	depends on USB_GADGET && PROC_FS
+	help
+	   Some of the drivers in the "gadget" framework can expose
+	   debugging information in files such as /proc/driver/udc
+	   (for a peripheral controller).  The information in these
+	   files may help when you're troubleshooting or bringing up a
+	   driver on a new board.   Enable these files by choosing "Y"
+	   here.  If in doubt, or to conserve kernel memory, say "N".
 
-# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
-config USB
-	tristate "Support for Host-side USB"
-	depends on USB_ARCH_HAS_HCD
-	---help---
-	  Universal Serial Bus (USB) is a specification for a serial bus
-	  subsystem which offers higher speeds and more features than the
-	  traditional PC serial port.  The bus supplies power to peripherals
-	  and allows for hot swapping.  Up to 127 USB peripherals can be
-	  connected to a single USB host in a tree structure.
+#
+# USB Peripheral Controller Support
+#
+choice
+	prompt "USB Peripheral Controller"
+	depends on USB_GADGET
+	help
+	   A USB device uses a controller to talk to its host.
+	   Systems should have only one such upstream link.
+
+config USB_GADGET_NET2280
+	boolean "NetChip 2280"
+	depends on PCI
+	select USB_GADGET_DUALSPEED
+	help
+	   NetChip 2280 is a PCI based USB peripheral controller which
+	   supports both full and high speed USB 2.0 data transfers.  
+	   
+	   It has six configurable endpoints, as well as endpoint zero
+	   (for control transfers) and several endpoints with dedicated
+	   functions.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "net2280" and force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_NET2280
+	tristate
+	depends on USB_GADGET_NET2280
+	default USB_GADGET
+
+config USB_GADGET_PXA2XX
+	boolean "PXA 2xx or IXP 4xx"
+	depends on ARCH_PXA || ARCH_IXP4XX
+	help
+	   Intel's PXA 2xx series XScale ARM-5TE processors include
+	   an integrated full speed USB 1.1 device controller.  The
+	   controller in the IXP 4xx series is register-compatible.
+
+	   It has fifteen fixed-function endpoints, as well as endpoint
+	   zero (for control transfers).
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "pxa2xx_udc" and force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_PXA2XX
+	tristate
+	depends on USB_GADGET_PXA2XX
+	default USB_GADGET
+
+# if there's only one gadget driver, using only two bulk endpoints,
+# don't waste memory for the other endpoints
+config USB_PXA2XX_SMALL
+	depends on USB_GADGET_PXA2XX
+	bool
+	default n if USB_ETH_RNDIS
+	default y if USB_ZERO
+	default y if USB_ETH
+	default y if USB_G_SERIAL
+
+config USB_GADGET_GOKU
+	boolean "Toshiba TC86C001 'Goku-S'"
+	depends on PCI
+	help
+	   The Toshiba TC86C001 is a PCI device which includes controllers
+	   for full speed USB devices, IDE, I2C, SIO, plus a USB host (OHCI).
+	   
+	   The device controller has three configurable (bulk or interrupt)
+	   endpoints, plus endpoint zero (for control transfers).
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "goku_udc" and to force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_GOKU
+	tristate
+	depends on USB_GADGET_GOKU
+	default USB_GADGET
+
+# this could be built elsewhere (doesn't yet exist)
+config USB_GADGET_SA1100
+	boolean "SA 1100"
+	depends on ARCH_SA1100
+	help
+	   Intel's SA-1100 is an ARM-4 processor with an integrated
+	   full speed USB 1.1 device controller.
+
+	   It has two fixed-function endpoints, as well as endpoint
+	   zero (for control transfers).
+
+config USB_SA1100
+	tristate
+	depends on USB_GADGET_SA1100
+	default USB_GADGET
+
+config USB_GADGET_LH7A40X
+	boolean "LH7A40X"
+	depends on ARCH_LH7A40X
+	help
+    This driver provides USB Device Controller driver for LH7A40x
+
+config USB_LH7A40X
+	tristate
+	depends on USB_GADGET_LH7A40X
+	default USB_GADGET
+
+config USB_GADGET_S3C2410
+	boolean "S3C2410"
+	depends on ARCH_S3C2410 && EXPERIMENTAL
+	help
+	  Samsung's S3C2410 is an ARM-4 processor with an integrated
+	  full speed USB 1.1 device controller.
+	  It has 4 configurable endpoints, as well as endpoint
+	  zero (for control transfers).
+
+config USB_S3C2410
+	tristate
+	depends on USB_GADGET_S3C2410
+	default USB_GADGET
+
+config USB_S3C2410_DEBUG
+	boolean "S3C2410 udc debug messages"
+	depends on USB_GADGET_S3C2410
+
+config USB_GADGET_DUMMY_HCD
+	boolean "Dummy HCD (DEVELOPMENT)"
+	depends on USB && EXPERIMENTAL
+	select USB_GADGET_DUALSPEED
+	help
+	  This host controller driver emulates USB, looping all data transfer
+	  requests back to a USB "gadget driver" in the same host.  The host
+	  side is the master; the gadget side is the slave.  Gadget drivers
+	  can be high, full, or low speed; and they have access to endpoints
+	  like those from NET2280, PXA2xx, or SA1100 hardware.
 	  
-	  The USB host is the root of the tree, the peripherals are the
-	  leaves and the inner nodes are special USB devices called hubs.
-	  Most PCs now have USB host ports, used to connect peripherals
-	  such as scanners, keyboards, mice, modems, cameras, disks,
-	  flash memory, network links, and printers to the PC.
-
-	  Say Y here if your computer has a host-side USB port and you want
-	  to use USB devices.  You then need to say Y to at least one of the
-	  Host Controller Driver (HCD) options below.  Choose a USB 1.1
-	  controller, such as "UHCI HCD support" or "OHCI HCD support",
-	  and "EHCI HCD (USB 2.0) support" except for older systems that
-	  do not have USB 2.0 support.  It doesn't normally hurt to select
-	  them all if you are not certain.
-
-	  If your system has a device-side USB port, used in the peripheral
-	  side of the USB protocol, see the "USB Gadget" framework instead.
-
-	  After choosing your HCD, then select drivers for the USB peripherals
-	  you'll be using.  You may want to check out the information provided
-	  in <file:Documentation/usb/> and especially the links given in
-	  <file:Documentation/usb/usb-help.txt>.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called usbcore.
-
-source "drivers/usb/core/Kconfig"
-
-source "drivers/usb/host/Kconfig"
-
-source "drivers/usb/class/Kconfig"
-
-source "drivers/usb/storage/Kconfig"
-
-source "drivers/usb/input/Kconfig"
-
-source "drivers/usb/image/Kconfig"
-
-source "drivers/usb/media/Kconfig"
-
-source "drivers/usb/net/Kconfig"
-
-comment "USB port drivers"
-	depends on USB
-
-config USB_USS720
-	tristate "USS720 parport driver"
-	depends on USB && PARPORT
-	---help---
-	  This driver is for USB parallel port adapters that use the Lucent
-	  Technologies USS-720 chip. These cables are plugged into your USB
-	  port and provide USB compatibility to peripherals designed with
-	  parallel port interfaces.
-
-	  The chip has two modes: automatic mode and manual mode. In automatic
-	  mode, it looks to the computer like a standard USB printer. Only
-	  printers may be connected to the USS-720 in this mode. The generic
-	  USB printer driver ("USB Printer support", above) may be used in
-	  that mode, and you can say N here if you want to use the chip only
-	  in this mode.
-
-	  Manual mode is not limited to printers, any parallel port
-	  device should work. This driver utilizes manual mode.
-	  Note however that some operations are three orders of magnitude
-	  slower than on a PCI/ISA Parallel Port, so timing critical
-	  applications might not work.
+	  This may help in some stages of creating a driver to embed in a
+	  Linux device, since it lets you debug several parts of the gadget
+	  driver without its hardware or drivers being involved.
+	  
+	  Since such a gadget side driver needs to interoperate with a host
+	  side Linux-USB device driver, this may help to debug both sides
+	  of a USB protocol stack.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "dummy_hcd" and force all
+	  gadget drivers to also be dynamically linked.
+
+config USB_DUMMY_HCD
+	tristate
+	depends on USB_GADGET_DUMMY_HCD
+	default USB_GADGET
+
+config USB_GADGET_OMAP
+	boolean "OMAP USB Device Controller"
+	depends on ARCH_OMAP
+	select ISP1301_OMAP if MACH_OMAP_H2
+	help
+	   Many Texas Instruments OMAP processors have flexible full
+	   speed USB device controllers, with support for up to 30
+	   endpoints (plus endpoint zero).  This driver supports the
+	   controller in the OMAP 1611, and should work with controllers
+	   in other OMAP processors too, given minor tweaks.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "omap_udc" and force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_OMAP
+	tristate
+	depends on USB_GADGET_OMAP
+	default USB_GADGET
+
+config USB_OTG
+	boolean "OTG Support"
+	depends on USB_GADGET_OMAP && ARCH_OMAP_OTG && USB_OHCI_HCD
+	help
+	   The most notable feature of USB OTG is support for a
+	   "Dual-Role" device, which can act as either a device
+	   or a host.  The initial role choice can be changed
+	   later, when two dual-role devices talk to each other.
+
+	   Select this only if your OMAP board has a Mini-AB connector.
+
+endchoice
+
+config USB_GADGET_DUALSPEED
+	bool
+	depends on USB_GADGET
+	default n
+	help
+	  Means that gadget drivers should include extra descriptors
+	  and code to handle dual-speed controllers.
 
-	  Say Y here if you own an USS-720 USB->Parport cable and intend to
-	  connect anything other than a printer to it.
+#
+# USB Gadget Drivers
+#
+choice
+	tristate "USB Gadget Drivers"
+	depends on USB_GADGET
+	default USB_ETH
+
+# this first set of drivers all depend on bulk-capable hardware.
+
+config USB_ZERO
+	tristate "Gadget Zero (DEVELOPMENT)"
+	depends on EXPERIMENTAL
+	help
+	  Gadget Zero is a two-configuration device.  It either sinks and
+	  sources bulk data; or it loops back a configurable number of
+	  transfers.  It also implements control requests, for "chapter 9"
+	  conformance.  The driver needs only two bulk-capable endpoints, so
+	  it can work on top of most device-side usb controllers.  It's
+	  useful for testing, and is also a working example showing how
+	  USB "gadget drivers" can be written.
+
+	  Make this be the first driver you try using on top of any new
+	  USB peripheral controller driver.  Then you can use host-side
+	  test software, like the "usbtest" driver, to put your hardware
+	  and its driver through a basic set of functional tests.
+
+	  Gadget Zero also works with the host-side "usb-skeleton" driver,
+	  and with many kinds of host-side test software.  You may need
+	  to tweak product and vendor IDs before host software knows about
+	  this device, and arrange to select an appropriate configuration.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "g_zero".
+
+config USB_ZERO_HNPTEST
+	boolean "HNP Test Device"
+	depends on USB_ZERO && USB_OTG
+	help
+	  You can configure this device to enumerate using the device
+	  identifiers of the USB-OTG test device.  That means that when
+	  this gadget connects to another OTG device, with this one using
+	  the "B-Peripheral" role, that device will use HNP to let this
+	  one serve as the USB host instead (in the "B-Host" role).
+
+config USB_ETH
+	tristate "Ethernet Gadget"
+	depends on NET
+	help
+	  This driver implements Ethernet style communication, in either
+	  of two ways:
+	  
+	   - The "Communication Device Class" (CDC) Ethernet Control Model.
+	     That protocol is often avoided with pure Ethernet adapters, in
+	     favor of simpler vendor-specific hardware, but is widely
+	     supported by firmware for smart network devices.
+
+	   - On hardware can't implement that protocol, a simple CDC subset
+	     is used, placing fewer demands on USB.
+
+	  RNDIS support is a third option, more demanding than that subset.
+
+	  Within the USB device, this gadget driver exposes a network device
+	  "usbX", where X depends on what other networking devices you have.
+	  Treat it like a two-node Ethernet link:  host, and gadget.
+
+	  The Linux-USB host-side "usbnet" driver interoperates with this
+	  driver, so that deep I/O queues can be supported.  On 2.4 kernels,
+	  use "CDCEther" instead, if you're using the CDC option. That CDC
+	  mode should also interoperate with standard CDC Ethernet class
+	  drivers on other host operating systems.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "g_ether".
+
+config USB_ETH_RNDIS
+	bool "RNDIS support (EXPERIMENTAL)"
+	depends on USB_ETH && EXPERIMENTAL
+	default y
+	help
+	   Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol,
+	   and Microsoft provides redistributable binary RNDIS drivers for
+	   older versions of Windows.
+
+	   If you say "y" here, the Ethernet gadget driver will try to provide
+	   a second device configuration, supporting RNDIS to talk to such
+	   Microsoft USB hosts.
+
+config USB_GADGETFS
+	tristate "Gadget Filesystem (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  This driver provides a filesystem based API that lets user mode
+	  programs implement a single-configuration USB device, including
+	  endpoint I/O and control requests that don't relate to enumeration.
+	  All endpoints, transfer speeds, and transfer types supported by
+	  the hardware are available, through read() and write() calls.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "gadgetfs".
+
+config USB_FILE_STORAGE
+	tristate "File-backed Storage Gadget"
+	# we don't support the SA1100 because of its limitations
+	depends on USB_GADGET_SA1100 = n
+	help
+	  The File-backed Storage Gadget acts as a USB Mass Storage
+	  disk drive.  As its storage repository it can use a regular
+	  file or a block device (in much the same way as the "loop"
+	  device driver), specified as a module parameter.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "g_file_storage".
+
+config USB_FILE_STORAGE_TEST
+	bool "File-backed Storage Gadget testing version"
+	depends on USB_FILE_STORAGE
+	default n
+	help
+	  Say "y" to generate the larger testing version of the
+	  File-backed Storage Gadget, useful for probing the
+	  behavior of USB Mass Storage hosts.  Not needed for
+	  normal operation.
+
+config USB_G_SERIAL
+	tristate "Serial Gadget"
+	help
+	  The Serial Gadget talks to the Linux-USB generic serial driver.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "g_serial".
 
-	  To compile this driver as a module, choose M here: the
-	  module will be called uss720.
 
-source "drivers/usb/serial/Kconfig"
 
-source "drivers/usb/misc/Kconfig"
+# put drivers that need isochronous transfer support (for audio
+# or video class gadget drivers), or specific hardware, here.
 
-source "drivers/usb/atm/Kconfig"
+# - none yet
 
-source "drivers/usb/gadget/Kconfig"
+endchoice
 
 endmenu
-
