diff -burN gadget.orig/s3c2410_udc.c gadget/s3c2410_udc.c
--- gadget.orig/s3c2410_udc.c	2006-04-20 23:07:32.000000000 +0800
+++ gadget/s3c2410_udc.c	2006-04-20 23:07:13.000000000 +0800
@@ -18,6 +18,9 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
+ * 2006-04-20   Cool-Idea Technology Corp. (Brian Wang)
+ *   - Solved some race conditions, I think
+ *   - Working: g_ether(CDC, RNDIS), g_file_storage, g_zero
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -58,8 +61,9 @@
 #define ENABLE_SYSFS
 
 #define DRIVER_DESC     "S3C2410 USB Device Controller Gadget"
-#define DRIVER_VERSION  "28 Aug 2005"
-#define DRIVER_AUTHOR	"Herbert Pötzl <herbert@13thfloor.at>, Arnaud Patard <arnaud.patard@rtp-net.org>"
+//#define DRIVER_VERSION  "28 Aug 2005"
+#define DRIVER_VERSION  "20 Apr 2006"
+#define DRIVER_AUTHOR	"Herbert Pötzl <herbert@13thfloor.at>, Arnaud Patard <arnaud.patard@rtp-net.org> Brian Wang <brian@cool-idea.com.tw>"
 
 static const char       gadget_name [] = "s3c2410_udc";
 static const char	driver_desc [] = DRIVER_DESC;
@@ -82,11 +86,12 @@
 static struct s3c2410_udc_mach_info *udc_info;
 
 /*************************** DEBUG FUNCTION ***************************/
+//#define CONFIG_USB_S3C2410_DEBUG  1
 #define DEBUG_NORMAL	1
 #define DEBUG_VERBOSE	2
 
 #ifdef CONFIG_USB_S3C2410_DEBUG
-#define USB_S3C2410_DEBUG_LEVEL 1
+#define USB_S3C2410_DEBUG_LEVEL DEBUG_VERBOSE
 
 static uint32_t s3c2410_ticks=0;
 
@@ -178,6 +183,9 @@
 /*------------------------- I/O ----------------------------------*/
 static void nuke (struct s3c2410_udc *udc, struct s3c2410_ep *ep)
 {
+    int count = 0;
+
+    //printk("%s: EP #%d\n", __FUNCTION__, ep->num);
 	/* Sanity check */
 	if (&ep->queue != NULL)
 		while (!list_empty (&ep->queue)) {
@@ -186,7 +194,10 @@
 			list_del_init (&req->queue);
 			req->req.status = -ESHUTDOWN;
 			req->req.complete (&ep->ep, &req->req);
+            count++;
 		}
+
+    //printk("  - %d items destroyed!\n", count);
 }
 
 /*
@@ -259,7 +270,6 @@
 	int		fifo_reg;
 	u32		ep_csr;
 
-
 	switch(ep->bEndpointAddress&0x7F)
 	{
 		default:
@@ -286,6 +296,21 @@
 			break;
 	}
 
+	udc_writel(idx, S3C2410_UDC_INDEX_REG);
+    {
+        /* Make sure the packet is ready before we read it! */
+        if (idx) {
+            ep_csr = udc_readl(S3C2410_UDC_OUT_CSR1_REG);
+            if (ep_csr & S3C2410_UDC_ICSR1_PKTRDY)
+                return 0;
+        } else {
+            /* EP0 */
+            ep_csr = udc_readl(S3C2410_UDC_EP0_CSR_REG);
+            if (ep_csr & S3C2410_UDC_EP0_CSR_IPKRDY)
+                return 0;
+        }
+    }
+
 	buf = req->req.buf + req->req.actual;
 	prefetch(buf);
 
@@ -300,8 +325,13 @@
 		is_last = 2;
 
 	/* Only ep0 debug messages are interesting */
+#if 1
 	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);
+#else
+	if (!idx)
+		printk("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);
+#endif /* 0 */
 
 	if (is_last)
 	{
@@ -348,7 +378,6 @@
 		}
 	}
 
-
 	return is_last;
 }
 
@@ -376,10 +405,8 @@
 	u32		idx;
 	int		fifo_reg;
 
-	
 	switch(ep->bEndpointAddress&0x7F)
 	{
-		default:
 		case 0: idx = 0;
 			fifo_reg = S3C2410_UDC_EP0_FIFO_REG;
 			break;
@@ -401,25 +428,55 @@
 			idx = 4;
 			fifo_reg = S3C2410_UDC_EP4_FIFO_REG;
 			break;
+		default:
+            printk("%s: Unknown endpoint address: 0x%02x\n", __FUNCTION__, ep->bEndpointAddress);
+            return -EINVAL;
+            break;
+	}
 
+    if (idx != ep->num) {
+        printk("%s: Invalid endpoint address: 0x%02x (EP#%d)\n", __FUNCTION__, ep->bEndpointAddress, ep->num);
+        return -EINVAL;
 	}
 
 	if (!req->req.length) {
 		return 1;
 	}
 
+	udc_writel(idx, S3C2410_UDC_INDEX_REG);
+    {
+        /* Make sure the packet is ready before we read it! */
+        if (idx) {
+            ep_csr = udc_readl(S3C2410_UDC_OUT_CSR1_REG);
+            if (!(ep_csr & S3C2410_UDC_ICSR1_PKTRDY))
+                return 0;
+        } else {
+            /* EP0 */
+            ep_csr = udc_readl(S3C2410_UDC_EP0_CSR_REG);
+            if (!(ep_csr & S3C2410_UDC_EP0_CSR_OPKRDY))
+                return 0;
+        }
+    }
+
 	buf = req->req.buf + req->req.actual;
 	bufferspace = req->req.length - req->req.actual;
 	if (!bufferspace)
 	{
-		dprintk(DEBUG_NORMAL, "read_fifo: Buffer full !!\n");
+		printk("read_fifo: Buffer full !!\n");
 		return -1;
 	}
 
-	udc_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) {
+        /* Maybe we're reading too fast... */
+        if ((req->req.length - req->req.actual) >= ep->ep.maxpacket) {
+            //printk("[POSSIBLE ERROR] %s: reading too fast?\n", __FUNCTION__);
+            dprintk(DEBUG_VERBOSE, "  - fifo_count,%d vs %d\n", fifo_count, ep->ep.maxpacket);
+            dprintk(DEBUG_VERBOSE, "  - req length: %d\n"
+                                   "  -     actual: %d\n",
+                                   req->req.length, req->req.actual);
+        }
+    }
 
 	if (fifo_count > ep->ep.maxpacket)
 		avail = ep->ep.maxpacket;
@@ -448,7 +505,6 @@
 	if (!idx)
 		dprintk(DEBUG_VERBOSE, "fifo_read fifo count : %d [last %d]\n",fifo_count,is_last);
 
-
 	if (is_last) {
 		if (!idx)
 		{
@@ -488,11 +544,9 @@
 		}
 	}
 
-
 	return is_last;
 }
 
-
 static int
 read_fifo_crq(struct usb_ctrlrequest *crq)
 {
@@ -540,13 +594,23 @@
 
 	switch(crq->bRequestType & USB_RECIP_MASK) {
 		case USB_RECIP_INTERFACE:
+            //printk("%s: USB_RECIP_INTERFACE, Do nothing\n", __FUNCTION__);
+			if (crq->wLength != 2)
+                return -1;
 			break;
 		case USB_RECIP_DEVICE:
+            //printk("%s: USB_RECIP_DEVICE\n", __FUNCTION__);
 			status = dev->devstatus;
 			break;
 		case USB_RECIP_ENDPOINT:
+            //printk("%s: USB_RECIP_ENDPOINT, ep_num,%d wLength,%d\n", __FUNCTION__, ep_num, crq->wLength);
+#if 0
 			if (ep_num>4 || crq->wLength > 2)
 				return 1;
+#else
+			if (ep_num>4 || crq->wLength != 2)
+				return 1;
+#endif /* 0 */
 			if (!ep_num) {
 				udc_writel(0, S3C2410_UDC_INDEX_REG);
 				status = udc_readl(S3C2410_UDC_IN_CSR1_REG);
@@ -590,16 +654,16 @@
 	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]);
+    //printk("---- %s curr_EP0_CSR:0x%02x\n", ep0states[dev->ep0state], ep0csr);
 
 	/* clear stall status */
 	if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {
 		/* FIXME */
 		nuke(dev, ep);
-	    	dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n");
+        printk("... clear SENT_STALL ...\n");
 	    	clear_ep0_sst(base_addr);
 		dev->ep0state = EP0_IDLE;
 		return;
@@ -614,7 +678,6 @@
 		dev->ep0state = EP0_IDLE;
 	}
 
-
 	switch (dev->ep0state) {
 	case EP0_IDLE:
 		/* start control request? */
@@ -625,7 +688,7 @@
 
 			len = read_fifo_crq(&crq);
 			if (len != sizeof(crq)) {
-			  	dprintk(DEBUG_NORMAL, "setup begin: fifo READ ERROR"
+			  	printk("setup begin: fifo READ ERROR"
 				    	" wanted %d bytes got %d. Stalling out...\n",
 					sizeof(crq), len);
  				set_ep0_ss(base_addr);
@@ -633,6 +696,19 @@
 			}
 
 			dprintk(DEBUG_NORMAL, "bRequest = %d bRequestType %d wLength = %d\n", crq.bRequest,crq.bRequestType,  crq.wLength);
+            if (0) {
+                u16	w_index  = le16_to_cpu(crq.wIndex);
+                u16	w_value  = le16_to_cpu(crq.wValue);
+                u16	w_length = le16_to_cpu(crq.wLength);
+                printk("  bRequest %d\n"
+                       "  bRequestType %d\n"
+                       "  wLength %d\n"
+                       "  w_index %d\n"
+                       "  w_value %d\n"
+                       "  w_length %d\n",
+                       crq.bRequest,crq.bRequestType,  crq.wLength,
+                       w_index, w_value, w_length);
+            }
 
 			/* cope with automagic for some standard requests. */
 			dev->req_std = (crq.bRequestType & USB_TYPE_MASK)
@@ -693,13 +769,28 @@
 						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);
+                if (ret == -EOPNOTSUPP) {
+                    dprintk(DEBUG_VERBOSE, "******** Operation not supported\n");
+#if 0
+                    {
+                        u16	w_index  = le16_to_cpu(crq.wIndex);
+                        u16	w_value  = le16_to_cpu(crq.wValue);
+                        u16	w_length = le16_to_cpu(crq.wLength);
+                        printk("  bRequest %d\n"
+                                "  bRequestType %d\n"
+                                "  wLength %d\n"
+                                "  w_index %d\n"
+                                "  w_value %d\n"
+                                "  w_length %d\n",
+                                crq.bRequest,crq.bRequestType,  crq.wLength,
+                                w_index, w_value, w_length);
+                    }
+#endif /* 0 */
+                } else
+					printk("dev->driver->setup failed. (%d)\n",ret);
+
+				set_ep0_ss_not_supported(base_addr);
 				dev->ep0state = EP0_IDLE;
 			/* deferred i/o == no response yet */
 			} else if (dev->req_pending) {
@@ -754,6 +845,7 @@
 		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);
+		//printk("ep%01d write csr:%02x %d\n",idx,ep_csr1,req ? 1 : 0);
 
 		if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL)
 		{
@@ -766,6 +858,8 @@
 		if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req)
 		{
 			write_fifo(ep,req);
+		} else {
+            //printk("***** %s: [WARNING] Cannot write FIFO\n", __FUNCTION__);
 		}
 	}
 	else {
@@ -828,7 +922,7 @@
 	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);
+	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 :
@@ -837,7 +931,7 @@
 	 */
 
 	/* RESET */
-	if (usb_status & S3C2410_UDC_USBINT_RESET )
+	if (usb_status & S3C2410_UDC_USBINT_RESET)
 	{
 		dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %x\n",ep0csr,pwr_reg);
 		
@@ -913,7 +1007,6 @@
 		}
 	}
 
-
 	dprintk(DEBUG_VERBOSE,"irq: %d done.\n", irq);
 
 	/* Restore old index */
@@ -958,10 +1051,10 @@
 	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)
 	{
+        dprintk(DEBUG_VERBOSE, "%s: Setting up IN endpoint\n", __FUNCTION__);
 		csr1 = S3C2410_UDC_ICSR1_FFLUSH|S3C2410_UDC_ICSR1_CLRDT;
 		csr2 = S3C2410_UDC_ICSR2_MODEIN|S3C2410_UDC_ICSR2_DMAIEN;
 
@@ -969,11 +1062,13 @@
 		udc_writel(csr1,S3C2410_UDC_IN_CSR1_REG);
 		udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
 		udc_writel(csr2,S3C2410_UDC_IN_CSR2_REG);
+		udc_writel(1 << ep->num, S3C2410_UDC_EP_INT_REG);
 	}
 	else
 	{
 		/* don't flush he in fifo or there will be an interrupt for that
 		 * endpoint */
+        dprintk(DEBUG_VERBOSE, "%s: Setting up OUT endpoint\n", __FUNCTION__);
 		csr1 = S3C2410_UDC_ICSR1_CLRDT;
 		csr2 = S3C2410_UDC_ICSR2_DMAIEN;
 
@@ -996,7 +1091,6 @@
 	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",
@@ -1035,6 +1129,7 @@
 	spin_unlock_irqrestore(&ep->dev->lock, flags);
 
 	dprintk(DEBUG_NORMAL, "%s disabled\n", _ep->name);
+	printk("%s disabled\n", _ep->name);
 
 	return 0;
 }
@@ -1182,6 +1277,7 @@
 	/* kickstart this i/o queue? */
 	if (list_empty(&ep->queue)) {
 		if (ep->bEndpointAddress == 0 /* ep0 */) {
+	        //printk("s3c2410_queue: %s len,%d\n", ep0states[dev->ep0state], _req->length);
 			switch (dev->ep0state) {
 			case EP0_IN_DATA_PHASE:
 				if (write_fifo(ep, req)) {
@@ -1270,6 +1366,7 @@
 static int
 s3c2410_set_halt (struct usb_ep *_ep, int value)
 {
+    printk("[WARNING] %s called!, value,%d\n", __FUNCTION__, value);
 	return 0;
 }
 
@@ -1489,8 +1586,7 @@
 /*
  * 	usb_gadget_unregister_driver
  */
-int
-usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 {
 	struct s3c2410_udc *udc = the_controller;
 
@@ -1504,10 +1600,11 @@
 
 	driver->unbind (&udc->gadget);
 	device_del(&udc->gadget.dev);
+    //udc->gadget.dev.driver = NULL;
 	udc->driver = NULL;
 
-	device_release_driver (&udc->gadget.dev);
-	driver_unregister (&driver->driver);
+	//device_release_driver (&udc->gadget.dev);
+	//driver_unregister (&driver->driver);
 
 	/* Disable udc */
 	udc_disable(udc);
@@ -1656,6 +1753,7 @@
 		retval = -EBUSY;
 		goto err_map;
 	}
+    udc->got_irq = 1;
 	dprintk(DEBUG_VERBOSE, "%s: got irq %i\n", gadget_name, IRQ_USBD);
 
 #ifdef ENABLE_SYSFS
@@ -1691,7 +1789,6 @@
 	release_mem_region(rsrc_start, rsrc_len);
 	
 	dev_set_drvdata(_dev, NULL);
-	kfree(udc);
 
 	if (!IS_ERR(udc_clock) && udc_clock != NULL) {
 		clk_disable(udc_clock);
@@ -1700,6 +1797,7 @@
 		udc_clock = NULL;
 	}
 
+	the_controller = NULL;
 	return 0;
 }
 
diff -burN gadget.orig/s3c2410_udc.h gadget/s3c2410_udc.h
--- gadget.orig/s3c2410_udc.h	2006-04-20 23:07:32.000000000 +0800
+++ gadget/s3c2410_udc.h	2006-04-20 23:07:13.000000000 +0800
@@ -122,19 +122,17 @@
 		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 {				\
+
+#define set_ep0_ss_not_supported(base) do {				\
    	S3C2410_UDC_SETIX(base,EP0);				\
-	maskl(base,S3C2410_UDC_EP0_CSR_SENDSTL,	\
+	maskl(base,S3C2410_UDC_EP0_CSR_SENDSTL|S3C2410_UDC_EP0_CSR_SOPKTRDY|S3C2410_UDC_EP0_CSR_DE,	\
 		BIT_MASK, S3C2410_UDC_EP0_CSR_REG);	\
 } while(0)
-#endif
 
 #define set_ep0_de_out(base) do {			\
    	S3C2410_UDC_SETIX(base,EP0);			\
