Index: linux-2.6.20/arch/arm/mach-s3c2410/s3c2410.c
===================================================================
--- linux-2.6.20.orig/arch/arm/mach-s3c2410/s3c2410.c	2007-02-04 19:44:54.000000000 +0100
+++ linux-2.6.20/arch/arm/mach-s3c2410/s3c2410.c	2007-02-15 14:55:33.000000000 +0100
@@ -39,6 +39,7 @@
 /* Initial IO mappings */
 
 static struct map_desc s3c2410_iodesc[] __initdata = {
+	IODESC_ENT(USBDEV),
 	IODESC_ENT(CLKPWR),
 	IODESC_ENT(LCD),
 	IODESC_ENT(TIMER),
Index: linux-2.6.20/drivers/usb/gadget/Kconfig
===================================================================
--- linux-2.6.20.orig/drivers/usb/gadget/Kconfig	2007-02-04 19:44:54.000000000 +0100
+++ linux-2.6.20/drivers/usb/gadget/Kconfig	2007-02-15 14:54:49.000000000 +0100
@@ -187,6 +187,25 @@
 
 	   Select this only if your OMAP board has a Mini-AB connector.
 
+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
+	select USB_GADGET_SELECTED
+
+config USB_S3C2410_DEBUG
+	boolean "S3C2410 udc debug messages"
+	depends on USB_GADGET_S3C2410
+
 config USB_GADGET_AT91
 	boolean "AT91 USB Device Port"
 	depends on ARCH_AT91
Index: linux-2.6.20/drivers/usb/gadget/Makefile
===================================================================
--- linux-2.6.20.orig/drivers/usb/gadget/Makefile	2007-02-04 19:44:54.000000000 +0100
+++ linux-2.6.20/drivers/usb/gadget/Makefile	2007-02-15 14:54:49.000000000 +0100
@@ -7,6 +7,7 @@
 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
 obj-$(CONFIG_USB_AT91)		+= at91_udc.o
 
 #
Index: linux-2.6.20/drivers/usb/gadget/s3c2410_udc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/drivers/usb/gadget/s3c2410_udc.c	2007-02-15 14:54:49.000000000 +0100
@@ -0,0 +1,1897 @@
+/*
+ * linux/drivers/usb/gadget/s3c2410_udc.c
+ * Samsung on-chip full speed USB device controllers
+ *
+ * Copyright (C) 2004-2006 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/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/platform_device.h>
+#include <linux/version.h>
+#include <linux/clk.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/arch/udc.h>
+
+#include <asm/mach-types.h>
+
+#include "s3c2410_udc.h"
+
+#define ENABLE_SYSFS
+
+#define DRIVER_DESC     "S3C2410 USB Device Controller Gadget"
+#define DRIVER_VERSION  "30 Apr 2006"
+#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;
+static struct clk      		*usb_bus_clock;
+static void __iomem 		*base_addr;
+static u64			rsrc_start;
+static u64			rsrc_len;
+
+static inline u32 udc_readl(u32 reg)
+{
+	return readl(base_addr+reg);
+}
+static inline void udc_writel(u32 value, u32 reg)
+{
+	writel(value,base_addr+reg);
+}
+
+static struct s3c2410_udc_mach_info *udc_info;
+
+/*************************** DEBUG FUNCTION ***************************/
+#define DEBUG_NORMAL	1
+#define DEBUG_VERBOSE	2
+
+#ifdef CONFIG_USB_S3C2410_DEBUG
+#define USB_S3C2410_DEBUG_LEVEL 1
+
+static 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, struct device_attribute *attr, 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       = udc_readl(S3C2410_UDC_FUNC_ADDR_REG);
+	pwr_reg        = udc_readl(S3C2410_UDC_PWR_REG);
+	ep_int_reg     = udc_readl(S3C2410_UDC_EP_INT_REG);
+	usb_int_reg    = udc_readl(S3C2410_UDC_USB_INT_REG);
+	ep_int_en_reg  = udc_readl(S3C2410_UDC_EP_INT_EN_REG);
+	usb_int_en_reg = udc_readl(S3C2410_UDC_USB_INT_EN_REG);
+	udc_writel(0, S3C2410_UDC_INDEX_REG);
+	ep0_csr        = udc_readl(S3C2410_UDC_IN_CSR1_REG);
+	udc_writel(1, S3C2410_UDC_INDEX_REG);
+	ep1_i_csr1     = udc_readl(S3C2410_UDC_IN_CSR1_REG);
+	ep1_i_csr2     = udc_readl(S3C2410_UDC_IN_CSR2_REG);
+	ep1_o_csr1     = udc_readl(S3C2410_UDC_IN_CSR1_REG);
+	ep1_o_csr2     = udc_readl(S3C2410_UDC_IN_CSR2_REG);
+	udc_writel(2, S3C2410_UDC_INDEX_REG);
+	ep2_i_csr1     = udc_readl(S3C2410_UDC_IN_CSR1_REG);
+	ep2_i_csr2     = udc_readl(S3C2410_UDC_IN_CSR2_REG);
+	ep2_o_csr1     = udc_readl(S3C2410_UDC_IN_CSR1_REG);
+	ep2_o_csr2     = udc_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 done(struct s3c2410_ep *ep, struct s3c2410_request *req, int status);
+static void nuke (struct s3c2410_udc *udc, struct s3c2410_ep *ep, int status)
+{
+	/* 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);
+			done(ep,req,status);
+		}
+}
+
+/*
+ * 	done
+ */
+static void done(struct s3c2410_ep *ep, struct s3c2410_request *req, int status)
+{
+	unsigned halted = ep->halted;
+
+	list_del_init(&req->queue);
+
+	if (likely (req->req.status == -EINPROGRESS))
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	ep->halted = 1;
+	req->req.complete(&ep->ep, &req->req);
+	ep->halted = halted;
+}
+
+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], -ECONNABORTED);
+}
+
+static inline int fifo_count_out(void)
+{
+	int tmp;
+
+	tmp = udc_readl(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8;
+	tmp |= udc_readl(S3C2410_UDC_OUT_FIFO_CNT1_REG);
+
+	return tmp & 0xffff;
+}
+
+/*
+ * 	write_packet
+ */
+static inline int
+write_packet(int fifo, struct s3c2410_request *req, unsigned max)
+{
+	unsigned	len;
+	u8		*buf;
+
+	buf = req->req.buf + req->req.actual;
+	prefetch(buf);
+
+	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);
+
+	writesb(base_addr+fifo, buf, len);
+	return len;
+}
+
+static void udc_reinit(struct s3c2410_udc *dev);
+
+/*
+ * 	write_fifo
+ *
+ * return:  0 = still running, 1 = completed, negative = errno
+ */
+static int write_fifo(struct s3c2410_ep *ep, struct s3c2410_request *req)
+{
+	unsigned	count;
+	int		is_last;
+	u32		idx;
+	int		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;
+	}
+
+	count = write_packet(fifo_reg, req, ep->ep.maxpacket);
+
+	/* 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 = 0;
+	else
+		is_last = 2;
+
+	/* Only ep0 debug messages are interesting */
+	if (!idx)
+		dprintk(DEBUG_NORMAL, "Written ep%d %d.%d of %d b [last %d,z %d]\n",idx,count,req->req.actual,req->req.length,is_last,req->req.zero);
+
+	if (is_last)
+	{
+		/* The order is important. It prevents to send 2 packet at the same time
+		 **/
+		if (!idx)
+		{
+			/* If we got a reset signal, no need to say 'data sent' */
+			if (! (udc_readl(S3C2410_UDC_USB_INT_REG) & S3C2410_UDC_USBINT_RESET))
+				set_ep0_de_in(base_addr);
+			ep->dev->ep0state=EP0_IDLE;
+		}
+		else
+		{
+			 udc_writel(idx, S3C2410_UDC_INDEX_REG);
+			 ep_csr=udc_readl(S3C2410_UDC_IN_CSR1_REG);
+			 udc_writel(idx, S3C2410_UDC_INDEX_REG);
+			 udc_writel(ep_csr|S3C2410_UDC_ICSR1_PKTRDY,S3C2410_UDC_IN_CSR1_REG);
+		}
+		done(ep, req, 0);
+		is_last=1;
+	}
+	else
+	{
+		if (!idx)
+		{
+			/* If we got a reset signal, no need to say 'data sent' */
+			if (! (udc_readl(S3C2410_UDC_USB_INT_REG) & S3C2410_UDC_USBINT_RESET))
+				set_ep0_ipr(base_addr);
+		}
+		else
+		{
+			udc_writel(idx, S3C2410_UDC_INDEX_REG);
+			ep_csr=udc_readl(S3C2410_UDC_IN_CSR1_REG);
+			udc_writel(idx, S3C2410_UDC_INDEX_REG);
+			udc_writel(ep_csr|S3C2410_UDC_ICSR1_PKTRDY,S3C2410_UDC_IN_CSR1_REG);
+		}
+	}
+
+
+	return is_last;
+}
+
+static inline int
+read_packet(int fifo, u8 *buf, struct s3c2410_request *req, unsigned avail)
+{
+	unsigned	len;
+
+	len = min(req->req.length - req->req.actual, avail);
+	req->req.actual += len;
+
+	readsb(fifo + base_addr, buf, len);
+	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;
+	int		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;
+
+	}
+
+	if (!req->req.length) {
+		return 1;
+	}
+
+	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;
+	}
+
+	udc_writel(idx, S3C2410_UDC_INDEX_REG);
+
+        fifo_count = fifo_count_out();
+	dprintk(DEBUG_NORMAL, "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);
+
+	/* checking this with ep0 is not accurate as we already
+	 * read a control request 
+	 **/
+	if (idx && 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;
+	}
+
+	udc_writel(idx, S3C2410_UDC_INDEX_REG);
+	fifo_count = fifo_count_out();
+
+	/* Only ep0 debug messages are interesting */
+	if (!idx)
+		dprintk(DEBUG_VERBOSE, "fifo_read fifo count : %d [last %d]\n",fifo_count,is_last);
+
+
+	if (is_last) {
+		if (!idx)
+		{
+			set_ep0_de_out(base_addr);
+			ep->dev->ep0state=EP0_IDLE;
+		}
+		else
+		{
+			udc_writel(idx, S3C2410_UDC_INDEX_REG);
+			ep_csr=udc_readl(S3C2410_UDC_OUT_CSR1_REG);
+			udc_writel(idx, S3C2410_UDC_INDEX_REG);
+			udc_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;
+
+	}
+	else
+	{
+		if (!idx)
+		{
+			clear_ep0_opr(base_addr);
+		}
+		else
+		{
+			udc_writel(idx, S3C2410_UDC_INDEX_REG);
+			ep_csr=udc_readl(S3C2410_UDC_OUT_CSR1_REG);
+			udc_writel(idx, S3C2410_UDC_INDEX_REG);
+			udc_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;
+
+	udc_writel(0, S3C2410_UDC_INDEX_REG);
+
+	fifo_count = fifo_count_out();
+
+	dprintk(DEBUG_NORMAL, "read_fifo_crq(): fifo_count=%d\n", fifo_count );
+
+	fifo_count = sizeof(struct usb_ctrlrequest);
+	while( fifo_count-- ) {
+		i = 0;
+
+		do {
+			*pOut = (unsigned char)udc_readl(S3C2410_UDC_EP0_FIFO_REG);
+			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;
+}
+static int s3c2410_get_status(struct s3c2410_udc *dev, struct usb_ctrlrequest  *crq)
+{
+	u16 status = 0;
+	u8 ep_num = crq->wIndex & 0x7F;
+	u8 is_in = crq->wIndex & USB_DIR_IN;
+
+	switch(crq->bRequestType & USB_RECIP_MASK) {
+		case USB_RECIP_INTERFACE:
+			break;
+		case USB_RECIP_DEVICE:
+			status = dev->devstatus;
+			break;
+		case USB_RECIP_ENDPOINT:
+			if (ep_num>4 || crq->wLength > 2)
+				return 1;
+			if (!ep_num) {
+				udc_writel(0, S3C2410_UDC_INDEX_REG);
+				status = udc_readl(S3C2410_UDC_IN_CSR1_REG);
+				status = ( (status & S3C2410_UDC_EP0_CSR_SENDSTL) == S3C2410_UDC_EP0_CSR_SENDSTL);
+			}
+			else {
+				udc_writel(ep_num, S3C2410_UDC_INDEX_REG);
+				if (is_in) {
+					status = udc_readl(S3C2410_UDC_IN_CSR1_REG);
+					status = ( (status & S3C2410_UDC_ICSR1_SENTSTL) == S3C2410_UDC_ICSR1_SENTSTL);
+				}
+				else {
+					status = udc_readl(S3C2410_UDC_OUT_CSR1_REG);
+					status = ( (status & S3C2410_UDC_OCSR1_SENTSTL) == S3C2410_UDC_OCSR1_SENTSTL);
+				}
+			}
+
+			break;
+		default:
+			return 1;
+	}
+
+	/* Seems to be needed to get it working. ouch :( */
+	udelay(0x20);
+	udc_writel(status&0xFF,S3C2410_UDC_EP0_FIFO_REG);
+	udc_writel(status>>8,S3C2410_UDC_EP0_FIFO_REG);
+	set_ep0_de_in(base_addr);
+
+	return 0;
+}
+/*------------------------- 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 = NULL;
+	else
+		req = list_entry(ep->queue.next, struct s3c2410_request, queue);
+
+
+	udc_writel(0, S3C2410_UDC_INDEX_REG);
+	ep0csr = udc_readl(S3C2410_UDC_IN_CSR1_REG);
+	dprintk(DEBUG_NORMAL,"ep0csr %x ep0state %s\n",ep0csr,ep0states[dev->ep0state]);
+
+	/* clear stall status */
+	if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {
+		/* FIXME */
+		nuke(dev, ep, -EPIPE);
+	    	dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n");
+	    	clear_ep0_sst(base_addr);
+		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, 0);
+	    	clear_ep0_se(base_addr);
+		dev->ep0state = EP0_IDLE;
+	}
+
+
+	switch (dev->ep0state) {
+	case EP0_IDLE:
+		/* start control request? */
+		if (ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) {
+			int len, ret, tmp;
+
+			nuke (dev, ep, -EPROTO);
+
+			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(base_addr);
+				return;
+			}
+
+			dprintk(DEBUG_NORMAL, "bRequest = %d bRequestType %d wLength = %d\n", crq.bRequest,crq.bRequestType,  crq.wLength);
+
+
+			/* 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) {
+				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(base_addr);
+					}
+					break;
+				case USB_REQ_SET_INTERFACE:
+				    	dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ... \n");
+					if (crq.bRequestType == USB_RECIP_INTERFACE) {
+						goto config_change;
+					}
+					break;
+
+				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;
+ 						udc_writel((tmp | 0x80), S3C2410_UDC_FUNC_ADDR_REG);
+						set_ep0_de_out(base_addr);
+						return;
+					}
+					break;
+					
+				case USB_REQ_GET_STATUS:
+					dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ... \n");
+					clear_ep0_opr(base_addr);
+					if (!s3c2410_get_status(dev, &crq)) {
+						return;
+					}
+					break;
+
+				default:
+					clear_ep0_opr(base_addr);
+					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);
+
+				set_ep0_ss(base_addr);
+				set_ep0_de_out(base_addr);
+				dev->ep0state = EP0_IDLE;
+			/* deferred i/o == no response yet */
+			} else if (dev->req_pending) {
+			    	dprintk(DEBUG_VERBOSE, "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:
+	    	dprintk(DEBUG_NORMAL, "EP0_STALL ... what now?\n");
+	    	dev->ep0state=EP0_IDLE;
+		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 = NULL;
+
+	idx = (u32)(ep->bEndpointAddress&0x7F);
+
+	if (is_in) {
+		udc_writel(idx, S3C2410_UDC_INDEX_REG);
+		ep_csr1 = udc_readl(S3C2410_UDC_IN_CSR1_REG);
+		dprintk(DEBUG_VERBOSE, "ep%01d write csr:%02x %d\n",idx,ep_csr1,req ? 1 : 0);
+
+		if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL)
+		{
+			dprintk(DEBUG_VERBOSE, "st\n");
+			udc_writel(idx, S3C2410_UDC_INDEX_REG);
+			udc_writel(0x00,S3C2410_UDC_IN_CSR1_REG);
+			return;
+		}
+
+		if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req)
+		{
+			write_fifo(ep,req);
+		}
+	}
+	else {
+		udc_writel(idx, S3C2410_UDC_INDEX_REG);
+		ep_csr1 = udc_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)
+		{
+			udc_writel(idx, S3C2410_UDC_INDEX_REG);
+			udc_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 s3c2410_udc      *dev = _dev;
+	int usb_status;
+	int usbd_status;
+	int pwr_reg;
+	int ep0csr;
+	int     i;
+	u32	idx;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->lock,flags);
+
+	/* Driver connected ? */
+	if (!dev->driver) {
+		/* Clear interrupts */
+		udc_writel( \
+				udc_readl(S3C2410_UDC_USB_INT_REG), \
+				S3C2410_UDC_USB_INT_REG \
+			    );
+		udc_writel( \
+				udc_readl(S3C2410_UDC_EP_INT_REG), \
+				S3C2410_UDC_EP_INT_REG \
+			    );
+	}
+
+	/* Save index */
+	idx = udc_readl(S3C2410_UDC_INDEX_REG);
+
+	/* Read status registers */
+	usb_status = udc_readl(S3C2410_UDC_USB_INT_REG);
+	usbd_status = udc_readl(S3C2410_UDC_EP_INT_REG);
+	pwr_reg = udc_readl(S3C2410_UDC_PWR_REG);
+
+	S3C2410_UDC_SETIX(base_addr,EP0);
+	ep0csr = udc_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 )
+	{
+		/* two kind of reset :
+		 * - reset start -> pwr reg = 8
+		 * - reset end   -> pwr reg = 0
+		 **/
+		dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %x\n",ep0csr,pwr_reg);
+		dev->gadget.speed = USB_SPEED_UNKNOWN;
+		udc_writel(0x00, S3C2410_UDC_INDEX_REG);
+		udc_writel((dev->ep[0].ep.maxpacket&0x7ff)>>3,S3C2410_UDC_MAXP_REG);
+		dev->address = 0;
+
+		dev->ep0state = EP0_IDLE;
+		dev->gadget.speed = USB_SPEED_FULL;
+
+		/* clear interrupt */
+		udc_writel(S3C2410_UDC_USBINT_RESET,
+			S3C2410_UDC_USB_INT_REG);
+
+		udc_writel(idx,S3C2410_UDC_INDEX_REG);
+		spin_unlock_irqrestore(&dev->lock,flags);
+		return IRQ_HANDLED;
+	}
+
+	/* RESUME */
+	if (usb_status & S3C2410_UDC_USBINT_RESUME)
+	{
+		dprintk(DEBUG_NORMAL, "USB resume\n");
+
+		/* clear interrupt */
+		udc_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 */
+		udc_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_VERBOSE, "USB ep0 irq\n");
+		/* Clear the interrupt bit by setting it to 1 */
+		udc_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 */
+			udc_writel(tmp, S3C2410_UDC_EP_INT_REG);
+			handle_ep(&dev->ep[i]);
+		}
+	}
+
+
+	dprintk(DEBUG_VERBOSE,"irq: %d done.\n", irq);
+
+	/* Restore old index */
+	udc_writel(idx,S3C2410_UDC_INDEX_REG);
+
+	spin_unlock_irqrestore(&dev->lock,flags);
+
+	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;
+
+	local_irq_save (flags);
+	_ep->maxpacket = max & 0x7ff;
+	ep->desc = desc;
+	ep->halted = 0;
+	ep->bEndpointAddress = desc->bEndpointAddress;
+
+	/* set max packet */
+	udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
+	udc_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;
+
+		udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
+		udc_writel(csr1,S3C2410_UDC_IN_CSR1_REG);
+		udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
+		udc_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;
+
+		udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
+		udc_writel(csr1,S3C2410_UDC_IN_CSR1_REG);
+		udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
+		udc_writel(csr2,S3C2410_UDC_IN_CSR2_REG);
+
+		csr1 = S3C2410_UDC_OCSR1_FFLUSH | S3C2410_UDC_OCSR1_CLRDT;
+		csr2 = S3C2410_UDC_OCSR2_DMAIEN;
+
+		udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
+		udc_writel(csr1,S3C2410_UDC_OUT_CSR1_REG);
+		udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
+		udc_writel(csr2,S3C2410_UDC_OUT_CSR2_REG);
+	}
+
+
+	/* enable irqs */
+	int_en_reg = udc_readl(S3C2410_UDC_EP_INT_EN_REG);
+	udc_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);
+
+	local_irq_restore (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;
+	}
+
+	local_irq_save(flags);
+
+	printk(KERN_ERR "ep_disable: %s\n",_ep->name);
+
+	ep->desc = NULL;
+	ep->halted = 1;
+
+	nuke (ep->dev, ep, -ESHUTDOWN);
+
+	/* disable irqs */
+	int_en_reg = udc_readl(S3C2410_UDC_EP_INT_EN_REG);
+	udc_writel(int_en_reg & ~(1<<ep->num),S3C2410_UDC_EP_INT_EN_REG);
+
+	local_irq_restore(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, gfp_t mem_flags)
+{
+	struct s3c2410_ep	*ep;
+	struct s3c2410_request	*req;
+
+    	dprintk(DEBUG_VERBOSE,"s3c2410_alloc_request(ep=%p,flags=%d)\n", _ep, mem_flags);
+
+	ep = container_of (_ep, struct s3c2410_ep, ep);
+	if (!_ep)
+		return NULL;
+
+	req = kzalloc (sizeof *req, mem_flags);
+	if (!req)
+		return NULL;
+	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_VERBOSE, "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,
+	gfp_t mem_flags)
+{
+	char *retval;
+
+    	dprintk(DEBUG_VERBOSE,"s3c2410_alloc_buffer()\n");
+
+	if (!the_controller->driver)
+		return NULL;
+	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_VERBOSE, "s3c2410_free_buffer()\n");
+
+	if (bytes)
+		kfree (buf);
+}
+
+/*
+ * 	s3c2410_queue
+ */
+static int
+s3c2410_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct s3c2410_request	*req;
+	struct s3c2410_ep	*ep;
+	struct s3c2410_udc	*dev;
+	u32			ep_csr=0;
+	int 			fifo_count=0;
+	unsigned long		flags;
+
+
+	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;
+	}
+
+	local_irq_save (flags);
+	
+	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));
+		}
+		local_irq_restore(flags);
+		return -EINVAL;
+	}
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	dprintk(DEBUG_VERBOSE,"s3c2410_queue: ep%x len %d\n",ep->bEndpointAddress,_req->length);
+	
+	if (ep->bEndpointAddress) {
+		udc_writel(ep->bEndpointAddress&0x7F,S3C2410_UDC_INDEX_REG);
+		ep_csr = udc_readl(ep->bEndpointAddress&USB_DIR_IN ? S3C2410_UDC_IN_CSR1_REG : S3C2410_UDC_OUT_CSR1_REG);
+		fifo_count=fifo_count_out();
+	}
+	else {
+		udc_writel(0,S3C2410_UDC_INDEX_REG);
+		ep_csr = udc_readl(S3C2410_UDC_IN_CSR1_REG);
+	}
+	/* kickstart this i/o queue? */
+	if (list_empty(&ep->queue) && !ep->halted) {
+		if (ep->bEndpointAddress == 0 /* ep0 */) {
+			switch (dev->ep0state) {
+			case EP0_IN_DATA_PHASE:
+				if (write_fifo(ep, req)) {
+					dev->ep0state = EP0_IDLE;
+					req = NULL;
+				}
+				break;
+
+			case EP0_OUT_DATA_PHASE:
+				if ( (!_req->length) || ((ep_csr & 1) && read_fifo(ep,req))) {
+					dev->ep0state = EP0_IDLE;
+					req = NULL;
+				}
+				break;
+
+			default:
+				local_irq_restore(flags);
+				return -EL2HLT;
+			}
+		}
+		else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
+				&& (!(ep_csr&S3C2410_UDC_OCSR1_PKTRDY)) && write_fifo(ep, req)) {
+			req = NULL;
+		} else if ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY) && fifo_count && read_fifo(ep, req)) {
+			req = NULL;
+		}
+
+	}
+
+	/* pio or dma irq handler advances the queue. */
+	if (likely (req != 0))
+		list_add_tail(&req->queue, &ep->queue);
+
+	local_irq_restore(flags);
+
+	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 = NULL;
+
+    	dprintk(DEBUG_VERBOSE,"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);
+
+	local_irq_save (flags);
+
+	list_for_each_entry (req, &ep->queue, queue) {
+		if (&req->req == _req) {
+			list_del_init (&req->queue);
+			_req->status = -ECONNRESET;
+			retval = 0;
+			break;
+		}
+	}
+
+	if (retval == 0) {
+		dprintk(DEBUG_VERBOSE, "dequeued req %p from %s, len %d buf %p\n",
+				req, _ep->name, _req->length, _req->buf);
+
+		done(ep, req, -ECONNRESET);
+	}
+	local_irq_restore (flags);
+
+	return retval;
+}
+
+
+/*
+ * 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 = udc_readl(S3C2410_UDC_FRAME_NUM2_REG) << 8;
+	tmp |= udc_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 void udc_disable(struct s3c2410_udc *dev);
+static void udc_enable(struct s3c2410_udc *dev);
+
+static int pull_up (struct s3c2410_udc  *udc, int is_on)
+{
+	dprintk(DEBUG_NORMAL, "pull_up()\n");
+	
+	if (udc_info && udc_info->udc_command) {
+		if (is_on)
+			udc_enable(udc);
+		else {
+			if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
+				if (udc->driver && udc->driver->disconnect)
+					udc->driver->disconnect(&udc->gadget);
+			
+			}
+			udc_disable(udc);
+		}
+	}
+	else
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
+static int s3c2410_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+	struct s3c2410_udc  *udc;
+
+	dprintk(DEBUG_NORMAL, "s3c2410_udc_vbus_session()\n");
+	udc = container_of (_gadget, struct s3c2410_udc, gadget);
+
+	udc->vbus = (is_active != 0);
+	pull_up(udc, is_active);
+	return 0;
+}
+
+static int s3c2410_pullup (struct usb_gadget *_gadget, int is_on)
+{
+	struct s3c2410_udc  *udc;
+
+	dprintk(DEBUG_NORMAL, "s3c2410_pullup()\n");
+	udc = container_of (_gadget, struct s3c2410_udc, gadget);
+	is_on = !!is_on;
+	pull_up(udc, is_on);
+	return 0;
+}
+
+static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev)
+{
+	struct s3c2410_udc      *dev = _dev;
+	unsigned int 		value;
+
+	dprintk(DEBUG_NORMAL, "s3c2410_udc_vbus_irq()\n");
+	value = s3c2410_gpio_getpin(udc_info->vbus_pin);
+	if (udc_info->vbus_pin_inverted)
+		value = !value;
+
+	if (value != dev->vbus)
+		s3c2410_udc_vbus_session(&dev->gadget, value);
+
+	return IRQ_HANDLED;
+}
+
+static const struct usb_gadget_ops s3c2410_ops = {
+	.get_frame          = s3c2410_g_get_frame,
+	.wakeup             = s3c2410_wakeup,
+	.set_selfpowered    = s3c2410_set_selfpowered,
+        .pullup             = s3c2410_pullup,
+	.vbus_session	    = s3c2410_udc_vbus_session,
+};
+
+/*------------------------- gadget driver handling---------------------------*/
+/*
+ * udc_disable
+ */
+static void udc_disable(struct s3c2410_udc *dev)
+{
+	dprintk(DEBUG_NORMAL, "udc_disable called\n");
+
+	/* Disable all interrupts */
+	udc_writel(0x00, S3C2410_UDC_USB_INT_EN_REG);
+	udc_writel(0x00, S3C2410_UDC_EP_INT_EN_REG);
+
+	/* Clear the interrupt registers */
+	udc_writel(   S3C2410_UDC_USBINT_RESET  | \
+			S3C2410_UDC_USBINT_RESUME | \
+			S3C2410_UDC_USBINT_SUSPEND, \
+			S3C2410_UDC_USB_INT_REG);
+	udc_writel(   0x1F, S3C2410_UDC_EP_INT_REG);
+	
+
+	/* Good bye, cruel world */
+	if (udc_info && udc_info->udc_command)
+		udc_info->udc_command(S3C2410_UDC_P_DISABLE);
+
+	/* Set address to 0 */
+	/*udc_writel( 0x80, S3C2410_UDC_FUNC_ADDR_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 = NULL;
+		ep->halted = 0;
+		INIT_LIST_HEAD (&ep->queue);
+	}
+}
+
+/*
+ * udc_enable
+ */
+static void udc_enable(struct s3c2410_udc *dev)
+{
+	int i;
+
+	dprintk(DEBUG_NORMAL, "udc_enable called\n");
+
+	/* dev->gadget.speed = USB_SPEED_UNKNOWN; */
+	dev->gadget.speed = USB_SPEED_FULL;
+
+	/* Set MAXP for all endpoints */
+	for (i = 0; i < S3C2410_ENDPOINTS; i++) {
+
+		udc_writel(i, S3C2410_UDC_INDEX_REG);
+		udc_writel((dev->ep[i].ep.maxpacket&0x7ff)>>3,S3C2410_UDC_MAXP_REG);
+	}
+
+	/* Set default power state */
+	udc_writel(DEFAULT_POWER_STATE, S3C2410_UDC_PWR_REG);
+
+	/* Enable reset and suspend interrupt interrupts */
+	udc_writel(1<<2 | 1<<0 ,S3C2410_UDC_USB_INT_EN_REG);
+
+	/* Enable ep0 interrupt */
+	udc_writel(0x01,S3C2410_UDC_EP_INT_EN_REG);
+
+	/* time to say "hello, world" */
+	if (udc_info && udc_info->udc_command)
+		udc_info->udc_command(S3C2410_UDC_P_ENABLE);
+}
+
+
+/*
+ * 	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->setup
+			|| driver->speed != USB_SPEED_FULL) {
+		printk(KERN_ERR "Invalid driver : bind %p setup %p speed %d\n",
+			driver->bind, driver->setup, driver->speed);
+		return -EINVAL;
+	}
+#if defined(MODULE)
+	if (!driver->unbind) {
+		printk(KERN_ERR "Invalid driver : no unbind method\n");
+		return -EINVAL;
+	}
+#endif
+
+	/* 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 = NULL;
+		udc->gadget.dev.driver = NULL;
+		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);
+
+	if (driver->disconnect)
+		driver->disconnect(&udc->gadget);
+
+	if (driver->unbind)
+		driver->unbind (&udc->gadget);
+
+	device_del(&udc->gadget.dev);
+	udc->driver = NULL;
+
+	/* 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 s3c2410_udc_probe(struct platform_device *pdev)
+{
+	struct s3c2410_udc *udc = &memory;
+	int retval;
+	unsigned int irq;
+
+	dprintk(DEBUG_NORMAL,"s3c2410_udc_probe\n");
+
+	usb_bus_clock = clk_get(NULL, "usb-bus");
+	if (IS_ERR(usb_bus_clock)) {
+		printk(KERN_INFO "failed to get usb bus clock source\n");
+		return PTR_ERR(usb_bus_clock);
+	}
+
+	clk_enable(usb_bus_clock);
+
+	udc_clock = clk_get(NULL, "usb-device");
+	if (IS_ERR(udc_clock)) {
+		printk(KERN_INFO "failed to get udc clock source\n");
+		return PTR_ERR(udc_clock);
+	}
+
+	clk_enable(udc_clock);
+
+	mdelay(10);
+
+	dprintk(DEBUG_VERBOSE, "got and enabled clocks\n");
+
+	if (strncmp(pdev->name, "s3c2440", 7) == 0) {
+		printk("Detected S3C2440 - increasing FIFO to 128 bytes\n");
+		memory.ep[1].fifo_size = S3C2440_EP_FIFO_SIZE;
+		memory.ep[2].fifo_size = S3C2440_EP_FIFO_SIZE;
+		memory.ep[3].fifo_size = S3C2440_EP_FIFO_SIZE;
+		memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE;
+	}
+
+	spin_lock_init (&udc->lock);
+	udc_info = pdev->dev.platform_data;
+
+	rsrc_start = S3C2410_PA_USBDEV;
+	rsrc_len   = S3C24XX_SZ_USBDEV;
+
+	if (!request_mem_region(rsrc_start, rsrc_len, gadget_name))
+		return -EBUSY;
+
+	base_addr = ioremap(rsrc_start, rsrc_len);
+	if (!base_addr) {
+		retval = -ENOMEM;
+		goto err_mem;
+	}
+	
+	device_initialize(&udc->gadget.dev);
+	udc->gadget.dev.parent = &pdev->dev;
+	udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+	the_controller = udc;
+	platform_set_drvdata(pdev, udc);
+
+	udc_disable(udc);
+	udc_reinit(udc);
+
+	/* irq setup after old hardware state is cleaned up */
+	retval = request_irq(IRQ_USBD, s3c2410_udc_irq,
+		IRQF_DISABLED, gadget_name, udc);
+
+	if (retval != 0) {
+		printk(KERN_ERR "%s: can't get irq %i, err %d\n",
+			gadget_name, IRQ_USBD, retval);
+		retval = -EBUSY;
+		goto err_map;
+	}
+
+	dprintk(DEBUG_VERBOSE, "%s: got irq %i\n", gadget_name, IRQ_USBD);
+
+	if (udc_info && udc_info->vbus_pin > 0) {
+		irq = s3c2410_gpio_getirq(udc_info->vbus_pin);
+		retval = request_irq(irq, s3c2410_udc_vbus_irq,
+			IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			gadget_name, udc);
+
+		if (retval != 0) {
+			printk(KERN_ERR "%s: can't get vbus irq %i, err %d\n",
+				gadget_name, irq, retval);
+			retval = -EBUSY;
+			goto err_int;
+		}
+
+		dprintk(DEBUG_VERBOSE, "%s: got irq %i\n", gadget_name, irq);
+	}
+	else {
+		udc->vbus = 1;
+	}
+
+#ifdef ENABLE_SYSFS
+	/* create device files */
+	device_create_file(&pdev->dev, &dev_attr_regs);
+#endif
+	return 0;
+err_int:
+	free_irq(IRQ_USBD, udc);
+err_map:
+	iounmap(base_addr);
+err_mem:
+	release_mem_region(rsrc_start, rsrc_len);
+
+	return retval;
+}
+
+/*
+ * 	s3c2410_udc_remove
+ */
+static int s3c2410_udc_remove(struct platform_device *pdev)
+{
+	struct s3c2410_udc *udc = platform_get_drvdata(pdev);
+	unsigned int irq;
+
+	dprintk(DEBUG_NORMAL, "s3c2410_udc_remove\n");
+	usb_gadget_unregister_driver(udc->driver);
+
+	if (udc_info && udc_info->vbus_pin > 0) {
+		irq = s3c2410_gpio_getirq(udc_info->vbus_pin);
+		free_irq(irq, udc);
+	}
+
+	free_irq(IRQ_USBD, udc);
+
+	iounmap(base_addr);
+	release_mem_region(rsrc_start, rsrc_len);
+	
+	platform_set_drvdata(pdev, NULL);
+
+	if (!IS_ERR(udc_clock) && udc_clock != NULL) {
+		clk_disable(udc_clock);
+		clk_put(udc_clock);
+		udc_clock = NULL;
+	}
+
+	if (!IS_ERR(usb_bus_clock) && usb_bus_clock != NULL) {
+		clk_disable(usb_bus_clock);
+		clk_put(usb_bus_clock);
+		usb_bus_clock = NULL;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message)
+{
+	struct s3c2410_udc *udc = platform_get_drvdata(pdev);
+
+	if (udc_info && udc_info->udc_command)
+		udc_info->udc_command(S3C2410_UDC_P_DISABLE);
+
+	return 0;
+}
+
+static int s3c2410_udc_resume(struct platform_device *pdev)
+{
+	struct s3c2410_udc *udc = platform_get_drvdata(pdev);
+
+	if (udc_info && udc_info->udc_command)
+		udc_info->udc_command(S3C2410_UDC_P_ENABLE);
+
+	return 0;
+}
+#else
+#define s3c2410_udc_suspend      NULL
+#define s3c2410_udc_resume       NULL
+#endif
+
+
+static struct platform_driver udc_driver_2410 = {
+	.driver		= {
+		.name 	= "s3c2410-usbgadget",
+		.owner	= THIS_MODULE,
+	},
+	.probe          = s3c2410_udc_probe,
+	.remove         = s3c2410_udc_remove,
+	.suspend	= s3c2410_udc_suspend,
+	.resume		= s3c2410_udc_resume,
+};
+
+static struct platform_driver udc_driver_2440 = {
+	.driver		= {
+		.name	= "s3c2440-usbgadget",
+		.owner	= THIS_MODULE,
+	},
+	.probe          = s3c2410_udc_probe,
+	.remove         = s3c2410_udc_remove,
+	.suspend	= s3c2410_udc_suspend,
+	.resume		= s3c2410_udc_resume,
+};
+
+static int __init udc_init(void)
+{
+	int retval;
+
+	dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION);
+
+	retval = platform_driver_register(&udc_driver_2410);
+	if (retval)
+		return retval;
+
+	return platform_driver_register(&udc_driver_2440);
+}
+
+static void __exit udc_exit(void)
+{
+	platform_driver_unregister(&udc_driver_2410);
+	platform_driver_unregister(&udc_driver_2440);
+}
+
+
+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");
Index: linux-2.6.20/drivers/usb/gadget/s3c2410_udc.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/drivers/usb/gadget/s3c2410_udc.h	2007-02-15 14:54:49.000000000 +0100
@@ -0,0 +1,188 @@
+#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;
+};
+
+
+/* Warning : ep0 has a fifo of 16 bytes */
+/* Don't try to set 32 or 64            */
+#define EP0_FIFO_SIZE		16
+#define EP_FIFO_SIZE		64
+#define DEFAULT_POWER_STATE	0x00
+
+#define S3C2440_EP_FIFO_SIZE	128
+
+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;
+	u8				vbus;
+};
+
+/****************** MACROS ******************/
+/* #define BIT_MASK	BIT_MASK*/
+#define BIT_MASK	0xFF
+
+#define maskb(base,v,m,a)      \
+	        writeb((readb(base+a) & ~(m))|((v)&(m)), (base+a))
+
+#define maskw(base,v,m,a)      \
+	        writew((readw(base+a) & ~(m))|((v)&(m)), (base+a))
+
+#define maskl(base,v,m,a)      \
+	        writel((readl(base+a) & ~(m))|((v)&(m)), (base+a))
+
+#define clear_ep0_sst(base) do {			\
+    	S3C2410_UDC_SETIX(base,EP0); 			\
+	writel(0x00, base+S3C2410_UDC_EP0_CSR_REG); 	\
+} while(0)
+
+#define clear_ep0_se(base) do {				\
+    	S3C2410_UDC_SETIX(base,EP0); 			\
+	maskl(base,S3C2410_UDC_EP0_CSR_SSE,		\
+	    	BIT_MASK, S3C2410_UDC_EP0_CSR_REG); 	\
+} while(0)
+
+#define clear_ep0_opr(base) do {			\
+   	S3C2410_UDC_SETIX(base,EP0);			\
+	maskl(base,S3C2410_UDC_EP0_CSR_SOPKTRDY,	\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG); 	\
+} while(0)
+
+#define set_ep0_ipr(base) do {				\
+   	S3C2410_UDC_SETIX(base,EP0);			\
+	maskl(base,S3C2410_UDC_EP0_CSR_IPKRDY,		\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG); 	\
+} while(0)
+
+#define set_ep0_de(base) do {				\
+   	S3C2410_UDC_SETIX(base,EP0);			\
+	maskl(base,S3C2410_UDC_EP0_CSR_DE,		\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG);	\
+} while(0)
+
+#if 0
+#define set_ep0_ss(base) do {				\
+   	S3C2410_UDC_SETIX(base,EP0);				\
+	maskl(base,S3C2410_UDC_EP0_CSR_SENDSTL|S3C2410_UDC_EP0_CSR_SOPKTRDY,	\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG);	\
+} while(0)
+#else
+#define set_ep0_ss(base) do {				\
+   	S3C2410_UDC_SETIX(base,EP0);				\
+	maskl(base,S3C2410_UDC_EP0_CSR_SENDSTL,	\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG);	\
+} while(0)
+#endif
+
+#define set_ep0_de_out(base) do {			\
+   	S3C2410_UDC_SETIX(base,EP0);			\
+	maskl(base,(S3C2410_UDC_EP0_CSR_SOPKTRDY 	\
+		| S3C2410_UDC_EP0_CSR_DE),		\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG);	\
+} while(0)
+
+#define set_ep0_sse_out(base) do {			\
+   	S3C2410_UDC_SETIX(base,EP0);			\
+	maskl(base,(S3C2410_UDC_EP0_CSR_SOPKTRDY 	\
+		| S3C2410_UDC_EP0_CSR_SSE),		\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG);	\
+} while(0)
+
+#define set_ep0_de_in(base) do {			\
+   	S3C2410_UDC_SETIX(base,EP0);			\
+	maskl(base,(S3C2410_UDC_EP0_CSR_IPKRDY		\
+		| S3C2410_UDC_EP0_CSR_DE),		\
+		BIT_MASK, S3C2410_UDC_EP0_CSR_REG);		\
+} while(0)
+
+
+
+#define clear_stall_ep1_out(base) do {			\
+   	S3C2410_UDC_SETIX(base,EP1);			\
+	orl(0,base+S3C2410_UDC_OUT_CSR1_REG);		\
+} while(0)
+
+
+#define clear_stall_ep2_out(base) do {			\
+   	S3C2410_UDC_SETIX(base,EP2);			\
+	orl(0, base+S3C2410_UDC_OUT_CSR1_REG);		\
+} while(0)
+
+
+#define clear_stall_ep3_out(base) do {			\
+   	S3C2410_UDC_SETIX(base,EP3);			\
+	orl(0,base+S3C2410_UDC_OUT_CSR1_REG);		\
+} while(0)
+
+
+#define clear_stall_ep4_out(base) do {			\
+   	S3C2410_UDC_SETIX(base,EP4);			\
+	orl(0, base+S3C2410_UDC_OUT_CSR1_REG);		\
+} while(0)
+
+#endif
+
+

