Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (229 commits)
  USB: remove unused usb_buffer_alloc and usb_buffer_free macros
  usb: musb: update gfp/slab.h includes
  USB: ftdi_sio: fix legacy SIO-device header
  USB: kl5usb105: reimplement using generic framework
  USB: kl5usb105: minor clean ups
  USB: kl5usb105: fix memory leak
  USB: io_ti: use kfifo to implement write buffering
  USB: io_ti: remove unsused private counter
  USB: ti_usb: use kfifo to implement write buffering
  USB: ir-usb: fix incorrect write-buffer length
  USB: aircable: fix incorrect write-buffer length
  USB: safe_serial: straighten out read processing
  USB: safe_serial: reimplement read using generic framework
  USB: safe_serial: reimplement write using generic framework
  usb-storage: always print quirks
  USB: usb-storage: trivial debug improvements
  USB: oti6858: use port write fifo
  USB: oti6858: use kfifo to implement write buffering
  USB: cypress_m8: use kfifo to implement write buffering
  USB: cypress_m8: remove unused drain define
  ...

Fix up conflicts (due to usb_buffer_alloc/free renaming) in
	drivers/input/tablet/acecad.c
	drivers/input/tablet/kbtab.c
	drivers/input/tablet/wacom_sys.c
	drivers/media/video/gspca/gspca.c
	sound/usb/usbaudio.c
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 7b85b69..df61975 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -783,13 +783,12 @@
 {
 	struct usbhid_device *usbhid = hid->driver_data;
 
-	usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL,
+	usbhid->inbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
 			&usbhid->inbuf_dma);
-	usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL,
+	usbhid->outbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
 			&usbhid->outbuf_dma);
-	usbhid->cr = usb_buffer_alloc(dev, sizeof(*usbhid->cr), GFP_KERNEL,
-			&usbhid->cr_dma);
-	usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL,
+	usbhid->cr = kmalloc(sizeof(*usbhid->cr), GFP_KERNEL);
+	usbhid->ctrlbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
 			&usbhid->ctrlbuf_dma);
 	if (!usbhid->inbuf || !usbhid->outbuf || !usbhid->cr ||
 			!usbhid->ctrlbuf)
@@ -844,10 +843,10 @@
 {
 	struct usbhid_device *usbhid = hid->driver_data;
 
-	usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
-	usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
-	usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
-	usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
+	usb_free_coherent(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
+	usb_free_coherent(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
+	kfree(usbhid->cr);
+	usb_free_coherent(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
 }
 
 static int usbhid_parse(struct hid_device *hid)
@@ -1007,9 +1006,8 @@
 
 	usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
 			     usbhid->ctrlbuf, 1, hid_ctrl, hid);
-	usbhid->urbctrl->setup_dma = usbhid->cr_dma;
 	usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
-	usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
+	usbhid->urbctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
 	if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
 		usbhid_init_reports(hid);
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index ec20400..693fd3e 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -75,7 +75,6 @@
 
 	struct urb *urbctrl;                                            /* Control URB */
 	struct usb_ctrlrequest *cr;                                     /* Control request struct */
-	dma_addr_t cr_dma;                                              /* Control request struct dma */
 	struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE];  		/* Control fifo */
 	unsigned char ctrlhead, ctrltail;                               /* Control fifo head & tail */
 	char *ctrlbuf;                                                  /* Control buffer */
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index f843443..bb14c82 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -74,7 +74,6 @@
 	unsigned char *new;
 	struct usb_ctrlrequest *cr;
 	unsigned char *leds;
-	dma_addr_t cr_dma;
 	dma_addr_t new_dma;
 	dma_addr_t leds_dma;
 };
@@ -197,11 +196,11 @@
 		return -1;
 	if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
 		return -1;
-	if (!(kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
+	if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
 		return -1;
-	if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma)))
+	if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
 		return -1;
-	if (!(kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
+	if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
 		return -1;
 
 	return 0;
@@ -211,9 +210,9 @@
 {
 	usb_free_urb(kbd->irq);
 	usb_free_urb(kbd->led);
-	usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
-	usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
-	usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
+	usb_free_coherent(dev, 8, kbd->new, kbd->new_dma);
+	kfree(kbd->cr);
+	usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma);
 }
 
 static int usb_kbd_probe(struct usb_interface *iface,
@@ -304,9 +303,8 @@
 	usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
 			     (void *) kbd->cr, kbd->leds, 1,
 			     usb_kbd_led, kbd);
-	kbd->led->setup_dma = kbd->cr_dma;
 	kbd->led->transfer_dma = kbd->leds_dma;
-	kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
+	kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
 	error = input_register_device(kbd->dev);
 	if (error)
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index 72ab4b2..79b2bf8 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -142,7 +142,7 @@
 	if (!mouse || !input_dev)
 		goto fail1;
 
-	mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma);
+	mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);
 	if (!mouse->data)
 		goto fail1;
 
@@ -205,7 +205,7 @@
 fail3:	
 	usb_free_urb(mouse->irq);
 fail2:	
-	usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
+	usb_free_coherent(dev, 8, mouse->data, mouse->data_dma);
 fail1:	
 	input_free_device(input_dev);
 	kfree(mouse);
@@ -221,7 +221,7 @@
 		usb_kill_urb(mouse->irq);
 		input_unregister_device(mouse->dev);
 		usb_free_urb(mouse->irq);
-		usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
+		usb_free_coherent(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
 		kfree(mouse);
 	}
 }
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 9b3353b..c1087ce 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -533,8 +533,8 @@
 	if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
 		return 0;
 
-	xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN,
-				       GFP_KERNEL, &xpad->odata_dma);
+	xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
+					 GFP_KERNEL, &xpad->odata_dma);
 	if (!xpad->odata)
 		goto fail1;
 
@@ -554,7 +554,7 @@
 
 	return 0;
 
- fail2:	usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
+ fail2:	usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
  fail1:	return error;
 }
 
@@ -568,7 +568,7 @@
 {
 	if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX) {
 		usb_free_urb(xpad->irq_out);
-		usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
+		usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
 				xpad->odata, xpad->odata_dma);
 	}
 }
@@ -788,8 +788,8 @@
 	if (!xpad || !input_dev)
 		goto fail1;
 
-	xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN,
-				       GFP_KERNEL, &xpad->idata_dma);
+	xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN,
+					 GFP_KERNEL, &xpad->idata_dma);
 	if (!xpad->idata)
 		goto fail1;
 
@@ -942,7 +942,7 @@
  fail5:	usb_kill_urb(xpad->irq_in);
  fail4:	usb_free_urb(xpad->irq_in);
  fail3:	xpad_deinit_output(xpad);
- fail2:	usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
+ fail2:	usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
  fail1:	input_free_device(input_dev);
 	kfree(xpad);
 	return error;
@@ -964,7 +964,7 @@
 			usb_kill_urb(xpad->irq_in);
 		}
 		usb_free_urb(xpad->irq_in);
-		usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
+		usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
 				xpad->idata, xpad->idata_dma);
 		kfree(xpad);
 	}
diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c
index e8bbc61..bce5712 100644
--- a/drivers/input/misc/ati_remote.c
+++ b/drivers/input/misc/ati_remote.c
@@ -624,13 +624,13 @@
 static int ati_remote_alloc_buffers(struct usb_device *udev,
 				    struct ati_remote *ati_remote)
 {
-	ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC,
-					     &ati_remote->inbuf_dma);
+	ati_remote->inbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
+					       &ati_remote->inbuf_dma);
 	if (!ati_remote->inbuf)
 		return -1;
 
-	ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC,
-					      &ati_remote->outbuf_dma);
+	ati_remote->outbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
+					        &ati_remote->outbuf_dma);
 	if (!ati_remote->outbuf)
 		return -1;
 
@@ -653,10 +653,10 @@
 	usb_free_urb(ati_remote->irq_urb);
 	usb_free_urb(ati_remote->out_urb);
 
-	usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
+	usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
 		ati_remote->inbuf, ati_remote->inbuf_dma);
 
-	usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
+	usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
 		ati_remote->outbuf, ati_remote->outbuf_dma);
 }
 
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index 2124b99..e148749 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -589,7 +589,7 @@
 	int i, pipe, maxp;
 
 	for (i = 0; i < 2; i++) {
-		ar2->buf[i] = usb_buffer_alloc(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]);
+		ar2->buf[i] = usb_alloc_coherent(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]);
 		if (!ar2->buf[i])
 			return -ENOMEM;
 
@@ -617,7 +617,7 @@
 
 	for (i = 0; i < 2; i++) {
 		usb_free_urb(ar2->urb[i]);
-		usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
+		usb_free_coherent(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
 	}
 }
 
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index 86457fe..2b0eba6 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -102,7 +102,6 @@
 	struct cm109_ctl_packet *ctl_data;
 	dma_addr_t ctl_dma;
 	struct usb_ctrlrequest *ctl_req;
-	dma_addr_t ctl_req_dma;
 	struct urb *urb_ctl;
 	/*
 	 * The 3 bitfields below are protected by ctl_submit_lock.
@@ -629,15 +628,13 @@
 
 static void cm109_usb_cleanup(struct cm109_dev *dev)
 {
-	if (dev->ctl_req)
-		usb_buffer_free(dev->udev, sizeof(*(dev->ctl_req)),
-				dev->ctl_req, dev->ctl_req_dma);
+	kfree(dev->ctl_req);
 	if (dev->ctl_data)
-		usb_buffer_free(dev->udev, USB_PKT_LEN,
-				dev->ctl_data, dev->ctl_dma);
+		usb_free_coherent(dev->udev, USB_PKT_LEN,
+				  dev->ctl_data, dev->ctl_dma);
 	if (dev->irq_data)
-		usb_buffer_free(dev->udev, USB_PKT_LEN,
-				dev->irq_data, dev->irq_dma);
+		usb_free_coherent(dev->udev, USB_PKT_LEN,
+				  dev->irq_data, dev->irq_dma);
 
 	usb_free_urb(dev->urb_irq);	/* parameter validation in core/urb */
 	usb_free_urb(dev->urb_ctl);	/* parameter validation in core/urb */
@@ -686,18 +683,17 @@
 		goto err_out;
 
 	/* allocate usb buffers */
-	dev->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN,
-					 GFP_KERNEL, &dev->irq_dma);
+	dev->irq_data = usb_alloc_coherent(udev, USB_PKT_LEN,
+					   GFP_KERNEL, &dev->irq_dma);
 	if (!dev->irq_data)
 		goto err_out;
 
-	dev->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN,
-					 GFP_KERNEL, &dev->ctl_dma);
+	dev->ctl_data = usb_alloc_coherent(udev, USB_PKT_LEN,
+					   GFP_KERNEL, &dev->ctl_dma);
 	if (!dev->ctl_data)
 		goto err_out;
 
-	dev->ctl_req = usb_buffer_alloc(udev, sizeof(*(dev->ctl_req)),
-					GFP_KERNEL, &dev->ctl_req_dma);
+	dev->ctl_req = kmalloc(sizeof(*(dev->ctl_req)), GFP_KERNEL);
 	if (!dev->ctl_req)
 		goto err_out;
 
@@ -735,10 +731,8 @@
 	usb_fill_control_urb(dev->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
 			     (void *)dev->ctl_req, dev->ctl_data, USB_PKT_LEN,
 			     cm109_urb_ctl_callback, dev);
-	dev->urb_ctl->setup_dma = dev->ctl_req_dma;
 	dev->urb_ctl->transfer_dma = dev->ctl_dma;
-	dev->urb_ctl->transfer_flags |= URB_NO_SETUP_DMA_MAP |
-					URB_NO_TRANSFER_DMA_MAP;
+	dev->urb_ctl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 	dev->urb_ctl->dev = udev;
 
 	/* find out the physical bus location */
diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c
index 86afdd1..a93c525 100644
--- a/drivers/input/misc/keyspan_remote.c
+++ b/drivers/input/misc/keyspan_remote.c
@@ -464,7 +464,7 @@
 	remote->in_endpoint = endpoint;
 	remote->toggle = -1;	/* Set to -1 so we will always not match the toggle from the first remote message. */
 
-	remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma);
+	remote->in_buffer = usb_alloc_coherent(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma);
 	if (!remote->in_buffer) {
 		error = -ENOMEM;
 		goto fail1;
@@ -543,7 +543,7 @@
 	return 0;
 
  fail3:	usb_free_urb(remote->irq_urb);
- fail2:	usb_buffer_free(udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
+ fail2:	usb_free_coherent(udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
  fail1:	kfree(remote);
 	input_free_device(input_dev);
 
@@ -564,7 +564,7 @@
 		input_unregister_device(remote->input);
 		usb_kill_urb(remote->irq_urb);
 		usb_free_urb(remote->irq_urb);
-		usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
+		usb_free_coherent(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
 		kfree(remote);
 	}
 }
diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c
index 668913d..bf170f6 100644
--- a/drivers/input/misc/powermate.c
+++ b/drivers/input/misc/powermate.c
@@ -64,7 +64,6 @@
 	dma_addr_t data_dma;
 	struct urb *irq, *config;
 	struct usb_ctrlrequest *configcr;
-	dma_addr_t configcr_dma;
 	struct usb_device *udev;
 	struct input_dev *input;
 	spinlock_t lock;
@@ -182,8 +181,6 @@
 	usb_fill_control_urb(pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0),
 			     (void *) pm->configcr, NULL, 0,
 			     powermate_config_complete, pm);
-	pm->config->setup_dma = pm->configcr_dma;
-	pm->config->transfer_flags |= URB_NO_SETUP_DMA_MAP;
 
 	if (usb_submit_urb(pm->config, GFP_ATOMIC))
 		printk(KERN_ERR "powermate: usb_submit_urb(config) failed");
@@ -276,13 +273,12 @@
 
 static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm)
 {
-	pm->data = usb_buffer_alloc(udev, POWERMATE_PAYLOAD_SIZE_MAX,
-				    GFP_ATOMIC, &pm->data_dma);
+	pm->data = usb_alloc_coherent(udev, POWERMATE_PAYLOAD_SIZE_MAX,
+				      GFP_ATOMIC, &pm->data_dma);
 	if (!pm->data)
 		return -1;
 
-	pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)),
-					GFP_ATOMIC, &pm->configcr_dma);
+	pm->configcr = kmalloc(sizeof(*(pm->configcr)), GFP_KERNEL);
 	if (!pm->configcr)
 		return -1;
 
@@ -291,10 +287,9 @@
 
 static void powermate_free_buffers(struct usb_device *udev, struct powermate_device *pm)
 {
-	usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE_MAX,
-			pm->data, pm->data_dma);
-	usb_buffer_free(udev, sizeof(*(pm->configcr)),
-			pm->configcr, pm->configcr_dma);
+	usb_free_coherent(udev, POWERMATE_PAYLOAD_SIZE_MAX,
+			  pm->data, pm->data_dma);
+	kfree(pm->configcr);
 }
 
 /* Called whenever a USB device matching one in our supported devices table is connected */
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
index 93a22ac..41201c6 100644
--- a/drivers/input/misc/yealink.c
+++ b/drivers/input/misc/yealink.c
@@ -111,7 +111,6 @@
 	struct yld_ctl_packet	*ctl_data;
 	dma_addr_t		ctl_dma;
 	struct usb_ctrlrequest	*ctl_req;
-	dma_addr_t		ctl_req_dma;
 	struct urb		*urb_ctl;
 
 	char phys[64];			/* physical device path */
@@ -836,12 +835,9 @@
 	usb_free_urb(yld->urb_irq);
 	usb_free_urb(yld->urb_ctl);
 
-	usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)),
-			yld->ctl_req, yld->ctl_req_dma);
-	usb_buffer_free(yld->udev, USB_PKT_LEN,
-			yld->ctl_data, yld->ctl_dma);
-	usb_buffer_free(yld->udev, USB_PKT_LEN,
-			yld->irq_data, yld->irq_dma);
+	kfree(yld->ctl_req);
+	usb_free_coherent(yld->udev, USB_PKT_LEN, yld->ctl_data, yld->ctl_dma);
+	usb_free_coherent(yld->udev, USB_PKT_LEN, yld->irq_data, yld->irq_dma);
 
 	kfree(yld);
 	return err;
@@ -886,18 +882,17 @@
 		return usb_cleanup(yld, -ENOMEM);
 
 	/* allocate usb buffers */
-	yld->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN,
-					GFP_ATOMIC, &yld->irq_dma);
+	yld->irq_data = usb_alloc_coherent(udev, USB_PKT_LEN,
+					   GFP_ATOMIC, &yld->irq_dma);
 	if (yld->irq_data == NULL)
 		return usb_cleanup(yld, -ENOMEM);
 
-	yld->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN,
-					GFP_ATOMIC, &yld->ctl_dma);
+	yld->ctl_data = usb_alloc_coherent(udev, USB_PKT_LEN,
+					   GFP_ATOMIC, &yld->ctl_dma);
 	if (!yld->ctl_data)
 		return usb_cleanup(yld, -ENOMEM);
 
-	yld->ctl_req = usb_buffer_alloc(udev, sizeof(*(yld->ctl_req)),
-					GFP_ATOMIC, &yld->ctl_req_dma);
+	yld->ctl_req = kmalloc(sizeof(*(yld->ctl_req)), GFP_KERNEL);
 	if (yld->ctl_req == NULL)
 		return usb_cleanup(yld, -ENOMEM);
 
@@ -936,10 +931,8 @@
 	usb_fill_control_urb(yld->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
 			(void *)yld->ctl_req, yld->ctl_data, USB_PKT_LEN,
 			urb_ctl_callback, yld);
-	yld->urb_ctl->setup_dma	= yld->ctl_req_dma;
 	yld->urb_ctl->transfer_dma	= yld->ctl_dma;
-	yld->urb_ctl->transfer_flags	|= URB_NO_SETUP_DMA_MAP |
-					URB_NO_TRANSFER_DMA_MAP;
+	yld->urb_ctl->transfer_flags	|= URB_NO_TRANSFER_DMA_MAP;
 	yld->urb_ctl->dev = udev;
 
 	/* find out the physical bus location */
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 53ec7dd..05edd75 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -806,8 +806,8 @@
 	if (!dev->urb)
 		goto err_free_devs;
 
-	dev->data = usb_buffer_alloc(dev->udev, dev->info->datalen, GFP_KERNEL,
-				     &dev->urb->transfer_dma);
+	dev->data = usb_alloc_coherent(dev->udev, dev->info->datalen, GFP_KERNEL,
+				       &dev->urb->transfer_dma);
 	if (!dev->data)
 		goto err_free_urb;
 
@@ -862,8 +862,8 @@
 	return 0;
 
  err_free_buffer:
-	usb_buffer_free(dev->udev, dev->info->datalen,
-			dev->data, dev->urb->transfer_dma);
+	usb_free_coherent(dev->udev, dev->info->datalen,
+			  dev->data, dev->urb->transfer_dma);
  err_free_urb:
 	usb_free_urb(dev->urb);
  err_free_devs:
@@ -881,8 +881,8 @@
 	if (dev) {
 		usb_kill_urb(dev->urb);
 		input_unregister_device(dev->input);
-		usb_buffer_free(dev->udev, dev->info->datalen,
-				dev->data, dev->urb->transfer_dma);
+		usb_free_coherent(dev->udev, dev->info->datalen,
+				  dev->data, dev->urb->transfer_dma);
 		usb_free_urb(dev->urb);
 		kfree(dev);
 	}
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index b89879b..6dedded 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -715,15 +715,15 @@
 	if (!dev->tp_urb)
 		goto err_free_bt_urb;
 
-	dev->bt_data = usb_buffer_alloc(dev->udev,
-					dev->cfg.bt_datalen, GFP_KERNEL,
-					&dev->bt_urb->transfer_dma);
+	dev->bt_data = usb_alloc_coherent(dev->udev,
+					  dev->cfg.bt_datalen, GFP_KERNEL,
+					  &dev->bt_urb->transfer_dma);
 	if (!dev->bt_data)
 		goto err_free_urb;
 
-	dev->tp_data = usb_buffer_alloc(dev->udev,
-					dev->cfg.tp_datalen, GFP_KERNEL,
-					&dev->tp_urb->transfer_dma);
+	dev->tp_data = usb_alloc_coherent(dev->udev,
+					  dev->cfg.tp_datalen, GFP_KERNEL,
+					  &dev->tp_urb->transfer_dma);
 	if (!dev->tp_data)
 		goto err_free_bt_buffer;
 
@@ -765,10 +765,10 @@
 	return 0;
 
 err_free_buffer:
-	usb_buffer_free(dev->udev, dev->cfg.tp_datalen,
+	usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
 		dev->tp_data, dev->tp_urb->transfer_dma);
 err_free_bt_buffer:
-	usb_buffer_free(dev->udev, dev->cfg.bt_datalen,
+	usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
 		dev->bt_data, dev->bt_urb->transfer_dma);
 err_free_urb:
 	usb_free_urb(dev->tp_urb);
@@ -788,10 +788,10 @@
 	usb_set_intfdata(iface, NULL);
 
 	input_unregister_device(dev->input);
-	usb_buffer_free(dev->udev, dev->cfg.tp_datalen,
-			dev->tp_data, dev->tp_urb->transfer_dma);
-	usb_buffer_free(dev->udev, dev->cfg.bt_datalen,
-			dev->bt_data, dev->bt_urb->transfer_dma);
+	usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
+			  dev->tp_data, dev->tp_urb->transfer_dma);
+	usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
+			  dev->bt_data, dev->bt_urb->transfer_dma);
 	usb_free_urb(dev->tp_urb);
 	usb_free_urb(dev->bt_urb);
 	kfree(dev);
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c
index 37d0539..aea9a93 100644
--- a/drivers/input/tablet/acecad.c
+++ b/drivers/input/tablet/acecad.c
@@ -155,7 +155,7 @@
 		goto fail1;
 	}
 
-	acecad->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &acecad->data_dma);
+	acecad->data = usb_alloc_coherent(dev, 8, GFP_KERNEL, &acecad->data_dma);
 	if (!acecad->data) {
 		err= -ENOMEM;
 		goto fail1;
@@ -235,7 +235,7 @@
 
 	return 0;
 
- fail2:	usb_buffer_free(dev, 8, acecad->data, acecad->data_dma);
+ fail2:	usb_free_coherent(dev, 8, acecad->data, acecad->data_dma);
  fail1: input_free_device(input_dev);
 	kfree(acecad);
 	return err;
@@ -249,7 +249,7 @@
 
 	input_unregister_device(acecad->input);
 	usb_free_urb(acecad->irq);
-	usb_buffer_free(acecad->usbdev, 8, acecad->data, acecad->data_dma);
+	usb_free_coherent(acecad->usbdev, 8, acecad->data, acecad->data_dma);
 	kfree(acecad);
 }
 
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index 4be039d..51b80b0 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -1711,8 +1711,8 @@
 		goto fail1;
         }
 
-	aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH,
-					GFP_ATOMIC, &aiptek->data_dma);
+	aiptek->data = usb_alloc_coherent(usbdev, AIPTEK_PACKET_LENGTH,
+					  GFP_ATOMIC, &aiptek->data_dma);
         if (!aiptek->data) {
 		dev_warn(&intf->dev, "cannot allocate usb buffer\n");
 		goto fail1;
@@ -1884,8 +1884,8 @@
 
  fail4:	sysfs_remove_group(&intf->dev.kobj, &aiptek_attribute_group);
  fail3: usb_free_urb(aiptek->urb);
- fail2:	usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data,
-			aiptek->data_dma);
+ fail2:	usb_free_coherent(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data,
+			  aiptek->data_dma);
  fail1: usb_set_intfdata(intf, NULL);
 	input_free_device(inputdev);
 	kfree(aiptek);
@@ -1909,9 +1909,9 @@
 		input_unregister_device(aiptek->inputdev);
 		sysfs_remove_group(&intf->dev.kobj, &aiptek_attribute_group);
 		usb_free_urb(aiptek->urb);
-		usb_buffer_free(interface_to_usbdev(intf),
-				AIPTEK_PACKET_LENGTH,
-				aiptek->data, aiptek->data_dma);
+		usb_free_coherent(interface_to_usbdev(intf),
+				  AIPTEK_PACKET_LENGTH,
+				  aiptek->data, aiptek->data_dma);
 		kfree(aiptek);
 	}
 }
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index 866a9ee..8ea6afe 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -850,8 +850,8 @@
 	gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
 
 	/* Allocate some data for incoming reports */
-	gtco->buffer = usb_buffer_alloc(gtco->usbdev, REPORT_MAX_SIZE,
-					GFP_KERNEL, &gtco->buf_dma);
+	gtco->buffer = usb_alloc_coherent(gtco->usbdev, REPORT_MAX_SIZE,
+					  GFP_KERNEL, &gtco->buf_dma);
 	if (!gtco->buffer) {
 		err("No more memory for us buffers");
 		error = -ENOMEM;
@@ -982,8 +982,8 @@
  err_free_urb:
 	usb_free_urb(gtco->urbinfo);
  err_free_buf:
-	usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE,
-			gtco->buffer, gtco->buf_dma);
+	usb_free_coherent(gtco->usbdev, REPORT_MAX_SIZE,
+			  gtco->buffer, gtco->buf_dma);
  err_free_devs:
 	input_free_device(input_dev);
 	kfree(gtco);
@@ -1005,8 +1005,8 @@
 		input_unregister_device(gtco->inputdevice);
 		usb_kill_urb(gtco->urbinfo);
 		usb_free_urb(gtco->urbinfo);
-		usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE,
-				gtco->buffer, gtco->buf_dma);
+		usb_free_coherent(gtco->usbdev, REPORT_MAX_SIZE,
+				  gtco->buffer, gtco->buf_dma);
 		kfree(gtco);
 	}
 
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
index b9969f1..290f4e5 100644
--- a/drivers/input/tablet/kbtab.c
+++ b/drivers/input/tablet/kbtab.c
@@ -122,7 +122,7 @@
 	if (!kbtab || !input_dev)
 		goto fail1;
 
-	kbtab->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &kbtab->data_dma);
+	kbtab->data = usb_alloc_coherent(dev, 8, GFP_KERNEL, &kbtab->data_dma);
 	if (!kbtab->data)
 		goto fail1;
 
@@ -173,7 +173,7 @@
 	return 0;
 
  fail3:	usb_free_urb(kbtab->irq);
- fail2:	usb_buffer_free(dev, 8, kbtab->data, kbtab->data_dma);
+ fail2:	usb_free_coherent(dev, 8, kbtab->data, kbtab->data_dma);
  fail1:	input_free_device(input_dev);
 	kfree(kbtab);
 	return error;
@@ -187,7 +187,7 @@
 
 	input_unregister_device(kbtab->dev);
 	usb_free_urb(kbtab->irq);
-	usb_buffer_free(kbtab->usbdev, 8, kbtab->data, kbtab->data_dma);
+	usb_free_coherent(kbtab->usbdev, 8, kbtab->data, kbtab->data_dma);
 	kfree(kbtab);
 }
 
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index d90f4e0..2dc0c07 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -465,8 +465,8 @@
 		goto fail1;
 	}
 
-	wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX,
-					   GFP_KERNEL, &wacom->data_dma);
+	wacom_wac->data = usb_alloc_coherent(dev, WACOM_PKGLEN_MAX,
+					     GFP_KERNEL, &wacom->data_dma);
 	if (!wacom_wac->data) {
 		error = -ENOMEM;
 		goto fail1;
@@ -536,7 +536,7 @@
 
  fail4:	wacom_remove_shared_data(wacom_wac);
  fail3:	usb_free_urb(wacom->irq);
- fail2:	usb_buffer_free(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
+ fail2:	usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
  fail1:	input_free_device(input_dev);
 	kfree(wacom);
 	return error;
@@ -551,7 +551,7 @@
 	usb_kill_urb(wacom->irq);
 	input_unregister_device(wacom->wacom_wac.input);
 	usb_free_urb(wacom->irq);
-	usb_buffer_free(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
+	usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
 			wacom->wacom_wac.data, wacom->data_dma);
 	wacom_remove_shared_data(&wacom->wacom_wac);
 	kfree(wacom);
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 0b0ae2e..29a8bbf 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -1290,8 +1290,8 @@
 static void usbtouch_free_buffers(struct usb_device *udev,
 				  struct usbtouch_usb *usbtouch)
 {
-	usb_buffer_free(udev, usbtouch->type->rept_size,
-	                usbtouch->data, usbtouch->data_dma);
+	usb_free_coherent(udev, usbtouch->type->rept_size,
+			  usbtouch->data, usbtouch->data_dma);
 	kfree(usbtouch->buffer);
 }
 
@@ -1335,8 +1335,8 @@
 	if (!type->process_pkt)
 		type->process_pkt = usbtouch_process_pkt;
 
-	usbtouch->data = usb_buffer_alloc(udev, type->rept_size,
-	                                  GFP_KERNEL, &usbtouch->data_dma);
+	usbtouch->data = usb_alloc_coherent(udev, type->rept_size,
+					    GFP_KERNEL, &usbtouch->data_dma);
 	if (!usbtouch->data)
 		goto out_free;
 
diff --git a/drivers/media/dvb/dvb-usb/usb-urb.c b/drivers/media/dvb/dvb-usb/usb-urb.c
index f9702e3..86d6893 100644
--- a/drivers/media/dvb/dvb-usb/usb-urb.c
+++ b/drivers/media/dvb/dvb-usb/usb-urb.c
@@ -96,8 +96,9 @@
 		while (stream->buf_num) {
 			stream->buf_num--;
 			deb_mem("freeing buffer %d\n",stream->buf_num);
-			usb_buffer_free(stream->udev, stream->buf_size,
-					stream->buf_list[stream->buf_num], stream->dma_addr[stream->buf_num]);
+			usb_free_coherent(stream->udev, stream->buf_size,
+					  stream->buf_list[stream->buf_num],
+					  stream->dma_addr[stream->buf_num]);
 		}
 	}
 
@@ -116,7 +117,7 @@
 	for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
 		deb_mem("allocating buffer %d\n",stream->buf_num);
 		if (( stream->buf_list[stream->buf_num] =
-					usb_buffer_alloc(stream->udev, size, GFP_ATOMIC,
+					usb_alloc_coherent(stream->udev, size, GFP_ATOMIC,
 					&stream->dma_addr[stream->buf_num]) ) == NULL) {
 			deb_mem("not enough memory for urb-buffer allocation.\n");
 			usb_free_stream_buffers(stream);
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 53baccb..fe1b803 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -1257,7 +1257,7 @@
 		if(!dec->irq_urb) {
 			return -ENOMEM;
 		}
-		dec->irq_buffer = usb_buffer_alloc(dec->udev,IRQ_PACKET_SIZE,
+		dec->irq_buffer = usb_alloc_coherent(dec->udev,IRQ_PACKET_SIZE,
 					GFP_ATOMIC, &dec->irq_dma_handle);
 		if(!dec->irq_buffer) {
 			usb_free_urb(dec->irq_urb);
@@ -1550,8 +1550,8 @@
 
 	usb_free_urb(dec->irq_urb);
 
-	usb_buffer_free(dec->udev,IRQ_PACKET_SIZE,
-			   dec->irq_buffer, dec->irq_dma_handle);
+	usb_free_coherent(dec->udev,IRQ_PACKET_SIZE,
+			  dec->irq_buffer, dec->irq_dma_handle);
 
 	if (dec->rc_input_dev) {
 		input_unregister_device(dec->rc_input_dev);
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
index 6615021..52f25aa 100644
--- a/drivers/media/video/au0828/au0828-video.c
+++ b/drivers/media/video/au0828/au0828-video.c
@@ -177,7 +177,7 @@
 				usb_unlink_urb(urb);
 
 			if (dev->isoc_ctl.transfer_buffer[i]) {
-				usb_buffer_free(dev->usbdev,
+				usb_free_coherent(dev->usbdev,
 					urb->transfer_buffer_length,
 					dev->isoc_ctl.transfer_buffer[i],
 					urb->transfer_dma);
@@ -247,7 +247,7 @@
 		}
 		dev->isoc_ctl.urb[i] = urb;
 
-		dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->usbdev,
+		dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->usbdev,
 			sb_size, GFP_KERNEL, &urb->transfer_dma);
 		if (!dev->isoc_ctl.transfer_buffer[i]) {
 			printk("unable to allocate %i bytes for transfer"
diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c
index f5e1a23..912a4d7 100644
--- a/drivers/media/video/cx231xx/cx231xx-core.c
+++ b/drivers/media/video/cx231xx/cx231xx-core.c
@@ -676,11 +676,11 @@
 				usb_unlink_urb(urb);
 
 			if (dev->video_mode.isoc_ctl.transfer_buffer[i]) {
-				usb_buffer_free(dev->udev,
-						urb->transfer_buffer_length,
-						dev->video_mode.isoc_ctl.
-						transfer_buffer[i],
-						urb->transfer_dma);
+				usb_free_coherent(dev->udev,
+						  urb->transfer_buffer_length,
+						  dev->video_mode.isoc_ctl.
+						  transfer_buffer[i],
+						  urb->transfer_dma);
 			}
 			usb_free_urb(urb);
 			dev->video_mode.isoc_ctl.urb[i] = NULL;
@@ -767,8 +767,8 @@
 		dev->video_mode.isoc_ctl.urb[i] = urb;
 
 		dev->video_mode.isoc_ctl.transfer_buffer[i] =
-		    usb_buffer_alloc(dev->udev, sb_size, GFP_KERNEL,
-				     &urb->transfer_dma);
+		    usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL,
+				       &urb->transfer_dma);
 		if (!dev->video_mode.isoc_ctl.transfer_buffer[i]) {
 			cx231xx_err("unable to allocate %i bytes for transfer"
 				    " buffer %i%s\n",
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index d3813ed..331e1ca 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -970,7 +970,7 @@
 				usb_unlink_urb(urb);
 
 			if (dev->isoc_ctl.transfer_buffer[i]) {
-				usb_buffer_free(dev->udev,
+				usb_free_coherent(dev->udev,
 					urb->transfer_buffer_length,
 					dev->isoc_ctl.transfer_buffer[i],
 					urb->transfer_dma);
@@ -1045,7 +1045,7 @@
 		}
 		dev->isoc_ctl.urb[i] = urb;
 
-		dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
+		dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
 			sb_size, GFP_KERNEL, &urb->transfer_dma);
 		if (!dev->isoc_ctl.transfer_buffer[i]) {
 			em28xx_err("unable to allocate %i bytes for transfer"
diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/video/gspca/benq.c
index 43ac4af..fce8d94 100644
--- a/drivers/media/video/gspca/benq.c
+++ b/drivers/media/video/gspca/benq.c
@@ -117,13 +117,13 @@
 			return -ENOMEM;
 		}
 		gspca_dev->urb[n] = urb;
-		urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,
+		urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev,
 						SD_PKT_SZ * SD_NPKT,
 						GFP_KERNEL,
 						&urb->transfer_dma);
 
 		if (urb->transfer_buffer == NULL) {
-			err("usb_buffer_alloc failed");
+			err("usb_alloc_coherent failed");
 			return -ENOMEM;
 		}
 		urb->dev = gspca_dev->dev;
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index efe6159..678675b 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -213,7 +213,7 @@
 		goto error;
 	}
 
-	buffer = usb_buffer_alloc(dev, buffer_len,
+	buffer = usb_alloc_coherent(dev, buffer_len,
 				GFP_KERNEL, &urb->transfer_dma);
 	if (!buffer) {
 		ret = -ENOMEM;
@@ -232,10 +232,10 @@
 	return ret;
 
 error_submit:
-	usb_buffer_free(dev,
-			urb->transfer_buffer_length,
-			urb->transfer_buffer,
-			urb->transfer_dma);
+	usb_free_coherent(dev,
+			  urb->transfer_buffer_length,
+			  urb->transfer_buffer,
+			  urb->transfer_dma);
 error_buffer:
 	usb_free_urb(urb);
 error:
@@ -272,10 +272,10 @@
 	if (urb) {
 		gspca_dev->int_urb = NULL;
 		usb_kill_urb(urb);
-		usb_buffer_free(gspca_dev->dev,
-				urb->transfer_buffer_length,
-				urb->transfer_buffer,
-				urb->transfer_dma);
+		usb_free_coherent(gspca_dev->dev,
+				  urb->transfer_buffer_length,
+				  urb->transfer_buffer,
+				  urb->transfer_dma);
 		usb_free_urb(urb);
 	}
 }
@@ -605,10 +605,10 @@
 		gspca_dev->urb[i] = NULL;
 		usb_kill_urb(urb);
 		if (urb->transfer_buffer != NULL)
-			usb_buffer_free(gspca_dev->dev,
-					urb->transfer_buffer_length,
-					urb->transfer_buffer,
-					urb->transfer_dma);
+			usb_free_coherent(gspca_dev->dev,
+					  urb->transfer_buffer_length,
+					  urb->transfer_buffer,
+					  urb->transfer_dma);
 		usb_free_urb(urb);
 	}
 }
@@ -760,13 +760,13 @@
 			return -ENOMEM;
 		}
 		gspca_dev->urb[n] = urb;
-		urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,
+		urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev,
 						bsize,
 						GFP_KERNEL,
 						&urb->transfer_dma);
 
 		if (urb->transfer_buffer == NULL) {
-			err("usb_buffer_alloc failed");
+			err("usb_alloc_coherent failed");
 			return -ENOMEM;
 		}
 		urb->dev = gspca_dev->dev;
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index d2f0ee2..7cfccfd 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -92,8 +92,8 @@
 		buf = list_entry(p, struct hdpvr_buffer, buff_list);
 
 		urb = buf->urb;
-		usb_buffer_free(urb->dev, urb->transfer_buffer_length,
-				urb->transfer_buffer, urb->transfer_dma);
+		usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+				  urb->transfer_buffer, urb->transfer_dma);
 		usb_free_urb(urb);
 		tmp = p->next;
 		list_del(p);
@@ -143,8 +143,8 @@
 		}
 		buf->urb = urb;
 
-		mem = usb_buffer_alloc(dev->udev, dev->bulk_in_size, GFP_KERNEL,
-				       &urb->transfer_dma);
+		mem = usb_alloc_coherent(dev->udev, dev->bulk_in_size, GFP_KERNEL,
+					 &urb->transfer_dma);
 		if (!mem) {
 			v4l2_err(&dev->v4l2_dev,
 				 "cannot allocate usb transfer buffer\n");
diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/video/tlg2300/pd-main.c
index c267e0c..256cc55 100644
--- a/drivers/media/video/tlg2300/pd-main.c
+++ b/drivers/media/video/tlg2300/pd-main.c
@@ -454,8 +454,8 @@
 
 	device_init_wakeup(&udev->dev, 1);
 #ifdef CONFIG_PM
-	pd->udev->autosuspend_disabled = 0;
 	pd->udev->autosuspend_delay = HZ * PM_SUSPEND_DELAY;
+	usb_enable_autosuspend(pd->udev);
 
 	if (in_hibernation(pd)) {
 		INIT_WORK(&pd->pm_work, hibernation_resume);
diff --git a/drivers/media/video/tlg2300/pd-video.c b/drivers/media/video/tlg2300/pd-video.c
index c750fd1..d0cc012 100644
--- a/drivers/media/video/tlg2300/pd-video.c
+++ b/drivers/media/video/tlg2300/pd-video.c
@@ -478,10 +478,10 @@
 			goto out;
 
 		video->urb_array[i] = urb;
-		mem = usb_buffer_alloc(udev,
-					ISO_PKT_SIZE * PK_PER_URB,
-					GFP_KERNEL,
-					&urb->transfer_dma);
+		mem = usb_alloc_coherent(udev,
+					 ISO_PKT_SIZE * PK_PER_URB,
+					 GFP_KERNEL,
+					 &urb->transfer_dma);
 
 		urb->complete	= urb_complete_iso;	/* handler */
 		urb->dev	= udev;
@@ -521,8 +521,8 @@
 		if (urb == NULL)
 			return i;
 
-		mem = usb_buffer_alloc(udev, buf_size, gfp_flags,
-					&urb->transfer_dma);
+		mem = usb_alloc_coherent(udev, buf_size, gfp_flags,
+					 &urb->transfer_dma);
 		if (mem == NULL)
 			return i;
 
@@ -542,7 +542,7 @@
 	for (i = 0; i < num; i++) {
 		urb = urb_array[i];
 		if (urb) {
-			usb_buffer_free(urb->dev,
+			usb_free_coherent(urb->dev,
 					urb->transfer_buffer_length,
 					urb->transfer_buffer,
 					urb->transfer_dma);
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index f7aae22..b9dd74f 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -2493,10 +2493,10 @@
 		}
 		usbvision->sbuf[bufIdx].urb = urb;
 		usbvision->sbuf[bufIdx].data =
-			usb_buffer_alloc(usbvision->dev,
-					 sb_size,
-					 GFP_KERNEL,
-					 &urb->transfer_dma);
+			usb_alloc_coherent(usbvision->dev,
+					   sb_size,
+					   GFP_KERNEL,
+					   &urb->transfer_dma);
 		urb->dev = dev;
 		urb->context = usbvision;
 		urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp);
@@ -2552,10 +2552,10 @@
 	for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
 		usb_kill_urb(usbvision->sbuf[bufIdx].urb);
 		if (usbvision->sbuf[bufIdx].data){
-			usb_buffer_free(usbvision->dev,
-					sb_size,
-					usbvision->sbuf[bufIdx].data,
-					usbvision->sbuf[bufIdx].urb->transfer_dma);
+			usb_free_coherent(usbvision->dev,
+					  sb_size,
+					  usbvision->sbuf[bufIdx].data,
+					  usbvision->sbuf[bufIdx].urb->transfer_dma);
 		}
 		usb_free_urb(usbvision->sbuf[bufIdx].urb);
 		usbvision->sbuf[bufIdx].urb = NULL;
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 821a996..53f3ef4 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -739,7 +739,7 @@
 
 	for (i = 0; i < UVC_URBS; ++i) {
 		if (stream->urb_buffer[i]) {
-			usb_buffer_free(stream->dev->udev, stream->urb_size,
+			usb_free_coherent(stream->dev->udev, stream->urb_size,
 				stream->urb_buffer[i], stream->urb_dma[i]);
 			stream->urb_buffer[i] = NULL;
 		}
@@ -780,7 +780,7 @@
 	for (; npackets > 1; npackets /= 2) {
 		for (i = 0; i < UVC_URBS; ++i) {
 			stream->urb_size = psize * npackets;
-			stream->urb_buffer[i] = usb_buffer_alloc(
+			stream->urb_buffer[i] = usb_alloc_coherent(
 				stream->dev->udev, stream->urb_size,
 				gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
 			if (!stream->urb_buffer[i]) {
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index df0a636..1fc0871 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -512,8 +512,8 @@
 	netdev = dev->netdev;
 
 	/* free up our allocated buffer */
-	usb_buffer_free(urb->dev, urb->transfer_buffer_length,
-			urb->transfer_buffer, urb->transfer_dma);
+	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+			  urb->transfer_buffer, urb->transfer_dma);
 
 	atomic_dec(&dev->active_tx_urbs);
 
@@ -610,8 +610,8 @@
 			return -ENOMEM;
 		}
 
-		buf = usb_buffer_alloc(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
-				       &urb->transfer_dma);
+		buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
+					 &urb->transfer_dma);
 		if (!buf) {
 			dev_err(netdev->dev.parent,
 				"No memory left for USB buffer\n");
@@ -631,8 +631,8 @@
 				netif_device_detach(dev->netdev);
 
 			usb_unanchor_urb(urb);
-			usb_buffer_free(dev->udev, RX_BUFFER_SIZE, buf,
-					urb->transfer_dma);
+			usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
+					  urb->transfer_dma);
 			break;
 		}
 
@@ -773,7 +773,7 @@
 		goto nomem;
 	}
 
-	buf = usb_buffer_alloc(dev->udev, size, GFP_ATOMIC, &urb->transfer_dma);
+	buf = usb_alloc_coherent(dev->udev, size, GFP_ATOMIC, &urb->transfer_dma);
 	if (!buf) {
 		dev_err(netdev->dev.parent, "No memory left for USB buffer\n");
 		usb_free_urb(urb);
@@ -816,7 +816,7 @@
 	 */
 	if (!context) {
 		usb_unanchor_urb(urb);
-		usb_buffer_free(dev->udev, size, buf, urb->transfer_dma);
+		usb_free_coherent(dev->udev, size, buf, urb->transfer_dma);
 
 		dev_warn(netdev->dev.parent, "couldn't find free context\n");
 
@@ -841,7 +841,7 @@
 		can_free_echo_skb(netdev, context->echo_index);
 
 		usb_unanchor_urb(urb);
-		usb_buffer_free(dev->udev, size, buf, urb->transfer_dma);
+		usb_free_coherent(dev->udev, size, buf, urb->transfer_dma);
 		dev_kfree_skb(skb);
 
 		atomic_dec(&dev->active_tx_urbs);
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
index 418825d..197c352 100644
--- a/drivers/net/usb/ipheth.c
+++ b/drivers/net/usb/ipheth.c
@@ -128,17 +128,13 @@
 	if (rx_urb == NULL)
 		goto free_tx_urb;
 
-	tx_buf = usb_buffer_alloc(iphone->udev,
-				  IPHETH_BUF_SIZE,
-				  GFP_KERNEL,
-				  &tx_urb->transfer_dma);
+	tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
+				    GFP_KERNEL, &tx_urb->transfer_dma);
 	if (tx_buf == NULL)
 		goto free_rx_urb;
 
-	rx_buf = usb_buffer_alloc(iphone->udev,
-				  IPHETH_BUF_SIZE,
-				  GFP_KERNEL,
-				  &rx_urb->transfer_dma);
+	rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
+				    GFP_KERNEL, &rx_urb->transfer_dma);
 	if (rx_buf == NULL)
 		goto free_tx_buf;
 
@@ -150,8 +146,8 @@
 	return 0;
 
 free_tx_buf:
-	usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, tx_buf,
-			tx_urb->transfer_dma);
+	usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, tx_buf,
+			  tx_urb->transfer_dma);
 free_rx_urb:
 	usb_free_urb(rx_urb);
 free_tx_urb:
@@ -162,10 +158,10 @@
 
 static void ipheth_free_urbs(struct ipheth_device *iphone)
 {
-	usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf,
-			iphone->rx_urb->transfer_dma);
-	usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
-			iphone->tx_urb->transfer_dma);
+	usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf,
+			  iphone->rx_urb->transfer_dma);
+	usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
+			  iphone->tx_urb->transfer_dma);
 	usb_free_urb(iphone->rx_urb);
 	usb_free_urb(iphone->tx_urb);
 }
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 46890dc..d6078b8 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -1155,13 +1155,13 @@
 	if (!kaweth->irq_urb)
 		goto err_tx_and_rx;
 
-	kaweth->intbuffer = usb_buffer_alloc(	kaweth->dev,
+	kaweth->intbuffer = usb_alloc_coherent(	kaweth->dev,
 						INTBUFFERSIZE,
 						GFP_KERNEL,
 						&kaweth->intbufferhandle);
 	if (!kaweth->intbuffer)
 		goto err_tx_and_rx_and_irq;
-	kaweth->rx_buf = usb_buffer_alloc(	kaweth->dev,
+	kaweth->rx_buf = usb_alloc_coherent(	kaweth->dev,
 						KAWETH_BUF_SIZE,
 						GFP_KERNEL,
 						&kaweth->rxbufferhandle);
@@ -1202,9 +1202,9 @@
 
 err_intfdata:
 	usb_set_intfdata(intf, NULL);
-	usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle);
+	usb_free_coherent(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle);
 err_all_but_rxbuf:
-	usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle);
+	usb_free_coherent(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle);
 err_tx_and_rx_and_irq:
 	usb_free_urb(kaweth->irq_urb);
 err_tx_and_rx:
@@ -1241,8 +1241,8 @@
 	usb_free_urb(kaweth->tx_urb);
 	usb_free_urb(kaweth->irq_urb);
 
-	usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle);
-	usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle);
+	usb_free_coherent(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle);
+	usb_free_coherent(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle);
 
 	free_netdev(netdev);
 }
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 16341ff..0d5081d 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -514,7 +514,7 @@
 	iface->needs_remote_wakeup = 1;		/* autosuspend (15s delay) */
 	device_init_wakeup(dev, 1);
 	usb_dev->autosuspend_delay = 15 * HZ;
-	usb_dev->autosuspend_disabled = 0;
+	usb_enable_autosuspend(usb_dev);
 #endif
 
 	result = i2400m_setup(i2400m, I2400M_BRI_MAC_REINIT);
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index abd083a..82ab532 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -215,7 +215,7 @@
 	return;
 
 free:
-	usb_buffer_free(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma);
+	usb_free_coherent(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma);
 }
 
 static void ar9170_usb_rx_completed(struct urb *urb)
@@ -296,7 +296,7 @@
 	if (!urb)
 		goto out;
 
-	ibuf = usb_buffer_alloc(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma);
+	ibuf = usb_alloc_coherent(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma);
 	if (!ibuf)
 		goto out;
 
@@ -309,8 +309,8 @@
 	err = usb_submit_urb(urb, GFP_KERNEL);
 	if (err) {
 		usb_unanchor_urb(urb);
-		usb_buffer_free(aru->udev, 64, urb->transfer_buffer,
-				urb->transfer_dma);
+		usb_free_coherent(aru->udev, 64, urb->transfer_buffer,
+				  urb->transfer_dma);
 	}
 
 out:
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index d91ad1a..c257940 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -664,15 +664,15 @@
 	urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!urb)
 		return NULL;
-	buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_KERNEL,
-		                  &urb->transfer_dma);
+	buffer = usb_alloc_coherent(udev, USB_MAX_RX_SIZE, GFP_KERNEL,
+				    &urb->transfer_dma);
 	if (!buffer) {
 		usb_free_urb(urb);
 		return NULL;
 	}
 
 	usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_DATA_IN),
-		          buffer, USB_MAX_RX_SIZE,
+			  buffer, USB_MAX_RX_SIZE,
 			  rx_urb_complete, usb);
 	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
@@ -683,8 +683,8 @@
 {
 	if (!urb)
 		return;
-	usb_buffer_free(urb->dev, urb->transfer_buffer_length,
-		        urb->transfer_buffer, urb->transfer_dma);
+	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+			  urb->transfer_buffer, urb->transfer_dma);
 	usb_free_urb(urb);
 }
 
diff --git a/drivers/staging/rt2860/iface/rtmp_usb.h b/drivers/staging/rt2860/iface/rtmp_usb.h
index 6bb384a..33479cc 100644
--- a/drivers/staging/rt2860/iface/rtmp_usb.h
+++ b/drivers/staging/rt2860/iface/rtmp_usb.h
@@ -81,8 +81,8 @@
 #define RT28XX_PUT_DEVICE							usb_put_dev
 #define RTUSB_ALLOC_URB(iso)							usb_alloc_urb(iso, GFP_ATOMIC)
 #define RTUSB_SUBMIT_URB(pUrb)							usb_submit_urb(pUrb, GFP_ATOMIC)
-#define RTUSB_URB_ALLOC_BUFFER(pUsb_Dev, BufSize, pDma_addr)			usb_buffer_alloc(pUsb_Dev, BufSize, GFP_ATOMIC, pDma_addr)
-#define RTUSB_URB_FREE_BUFFER(pUsb_Dev, BufSize, pTransferBuf, Dma_addr)	usb_buffer_free(pUsb_Dev, BufSize, pTransferBuf, Dma_addr)
+#define RTUSB_URB_ALLOC_BUFFER(pUsb_Dev, BufSize, pDma_addr)			usb_alloc_coherent(pUsb_Dev, BufSize, GFP_ATOMIC, pDma_addr)
+#define RTUSB_URB_FREE_BUFFER(pUsb_Dev, BufSize, pTransferBuf, Dma_addr)	usb_free_coherent(pUsb_Dev, BufSize, pTransferBuf, Dma_addr)
 
 #define RTUSB_FREE_URB(pUrb)	usb_free_urb(pUrb)
 
diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
index a78ade0..aa81951 100644
--- a/drivers/staging/udlfb/udlfb.c
+++ b/drivers/staging/udlfb/udlfb.c
@@ -1508,8 +1508,8 @@
 		urb = unode->urb;
 
 		/* Free each separately allocated piece */
-		usb_buffer_free(urb->dev, dev->urbs.size,
-			urb->transfer_buffer, urb->transfer_dma);
+		usb_free_coherent(urb->dev, dev->urbs.size,
+				  urb->transfer_buffer, urb->transfer_dma);
 		usb_free_urb(urb);
 		kfree(node);
 	}
@@ -1543,8 +1543,8 @@
 		}
 		unode->urb = urb;
 
-		buf = usb_buffer_alloc(dev->udev, MAX_TRANSFER, GFP_KERNEL,
-					&urb->transfer_dma);
+		buf = usb_alloc_coherent(dev->udev, MAX_TRANSFER, GFP_KERNEL,
+					 &urb->transfer_dma);
 		if (!buf) {
 			kfree(unode);
 			usb_free_urb(urb);
diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c
index bc26740..da30658 100644
--- a/drivers/staging/usbip/stub_rx.c
+++ b/drivers/staging/usbip/stub_rx.c
@@ -21,7 +21,7 @@
 
 #include "usbip_common.h"
 #include "stub.h"
-#include "../../usb/core/hcd.h"
+#include <linux/usb/hcd.h>
 
 
 static int is_clear_halt_cmd(struct urb *urb)
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index e3fa421..5240816 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -562,7 +562,7 @@
 /* there may be more cases to tweak the flags. */
 static unsigned int tweak_transfer_flags(unsigned int flags)
 {
-	flags &= ~(URB_NO_TRANSFER_DMA_MAP|URB_NO_SETUP_DMA_MAP);
+	flags &= ~URB_NO_TRANSFER_DMA_MAP;
 	return flags;
 }
 
diff --git a/drivers/staging/usbip/vhci.h b/drivers/staging/usbip/vhci.h
index 5e37517..41a1fe5 100644
--- a/drivers/staging/usbip/vhci.h
+++ b/drivers/staging/usbip/vhci.h
@@ -18,7 +18,7 @@
  */
 
 #include <linux/platform_device.h>
-#include "../../usb/core/hcd.h"
+#include <linux/usb/hcd.h>
 
 
 struct vhci_device {
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 25f01b5..e213d3f 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -94,19 +94,19 @@
 	} while (0)
 
 #define uea_enters(usb_dev) \
-	uea_vdbg(usb_dev, "entering %s\n", __func__)
+	uea_vdbg(usb_dev, "entering %s\n" , __func__)
 
 #define uea_leaves(usb_dev) \
-	uea_vdbg(usb_dev, "leaving  %s\n", __func__)
+	uea_vdbg(usb_dev, "leaving  %s\n" , __func__)
 
-#define uea_err(usb_dev, format,args...) \
-	dev_err(&(usb_dev)->dev ,"[UEAGLE-ATM] " format , ##args)
+#define uea_err(usb_dev, format, args...) \
+	dev_err(&(usb_dev)->dev , "[UEAGLE-ATM] " format , ##args)
 
-#define uea_warn(usb_dev, format,args...) \
-	dev_warn(&(usb_dev)->dev ,"[Ueagle-atm] " format, ##args)
+#define uea_warn(usb_dev, format, args...) \
+	dev_warn(&(usb_dev)->dev , "[Ueagle-atm] " format, ##args)
 
-#define uea_info(usb_dev, format,args...) \
-	dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args)
+#define uea_info(usb_dev, format, args...) \
+	dev_info(&(usb_dev)->dev , "[ueagle-atm] " format, ##args)
 
 struct intr_pkt;
 
@@ -289,7 +289,7 @@
 #define IS_ISDN(x) \
 	((x)->annex & ANNEXB)
 
-#define INS_TO_USBDEV(ins) ins->usb_dev
+#define INS_TO_USBDEV(ins) (ins->usb_dev)
 
 #define GET_STATUS(data) \
 	((data >> 8) & 0xf)
@@ -304,7 +304,7 @@
  * The FW_GET_BYTE() macro is provided only for consistency.
  */
 
-#define FW_GET_BYTE(p)	*((__u8 *) (p))
+#define FW_GET_BYTE(p) (*((__u8 *) (p)))
 
 #define FW_DIR "ueagle-atm/"
 #define UEA_FW_NAME_MAX 30
@@ -315,7 +315,7 @@
 
 #define ACK_TIMEOUT msecs_to_jiffies(3000)
 
-#define UEA_INTR_IFACE_NO 	0
+#define UEA_INTR_IFACE_NO	0
 #define UEA_US_IFACE_NO		1
 #define UEA_DS_IFACE_NO		2
 
@@ -326,9 +326,9 @@
 #define UEA_INTR_PIPE		0x04
 #define UEA_ISO_DATA_PIPE	0x08
 
-#define UEA_E1_SET_BLOCK    	0x0001
+#define UEA_E1_SET_BLOCK	0x0001
 #define UEA_E4_SET_BLOCK	0x002c
-#define UEA_SET_MODE     	0x0003
+#define UEA_SET_MODE		0x0003
 #define UEA_SET_2183_DATA	0x0004
 #define UEA_SET_TIMEOUT		0x0011
 
@@ -366,7 +366,7 @@
 	u8 string_header[E4_L1_STRING_HEADER];
 	u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
 	struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
-	u8 code [0];
+	u8 code[0];
 } __attribute__ ((packed));
 
 /* structures describing a block within a DSP page */
@@ -428,7 +428,8 @@
 #define E4_MODEMREADY  0x1
 
 #define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
-#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf))
+#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | \
+	((st) & 0xf) << 4 | ((s) & 0xf))
 
 #define E1_MAKESA(a, b, c, d)						\
 	(((c) & 0xff) << 24 |						\
@@ -473,7 +474,7 @@
 	__be16 wFunction;
 	__be16 wOffset;
 	__be16 wAddress;
-	__be32 dwData [6];
+	__be32 dwData[6];
 } __attribute__ ((packed));
 
 /* structures representing swap information */
@@ -534,11 +535,13 @@
 
 static struct usb_driver uea_driver;
 static DEFINE_MUTEX(uea_mutex);
-static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};
+static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III",
+								"Eagle IV"};
 
 static int modem_index;
 static unsigned int debug;
-static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};
+static unsigned int altsetting[NB_MODEM] = {
+				[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};
 static int sync_wait[NB_MODEM];
 static char *cmv_file[NB_MODEM];
 static int annex[NB_MODEM];
@@ -555,7 +558,7 @@
 		"file name with configuration and management variables");
 module_param_array(annex, uint, NULL, 0644);
 MODULE_PARM_DESC(annex,
-                 "manually set annex a/b (0=auto, 1=annex a, 2=annex b)");
+		"manually set annex a/b (0=auto, 1=annex a, 2=annex b)");
 
 #define uea_wait(sc, cond, timeo) \
 ({ \
@@ -602,7 +605,8 @@
 	return (ret == size) ? 0 : -EIO;
 }
 
-static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *context)
+static void uea_upload_pre_firmware(const struct firmware *fw_entry,
+								void *context)
 {
 	struct usb_device *usb = context;
 	const u8 *pfw;
@@ -707,7 +711,8 @@
 	}
 
 	ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev,
-				      GFP_KERNEL, usb, uea_upload_pre_firmware);
+					GFP_KERNEL, usb,
+					uea_upload_pre_firmware);
 	if (ret)
 		uea_err(usb, "firmware %s is not available\n", fw_name);
 	else
@@ -876,7 +881,7 @@
 	if (ret < 0) {
 		uea_err(INS_TO_USBDEV(sc),
 		       "requesting firmware %s failed with error %d\n",
-		        dsp_name, ret);
+			dsp_name, ret);
 		return ret;
 	}
 
@@ -994,14 +999,17 @@
 
 		blockidx = &p->page_header[blockno];
 		blocksize = E4_PAGE_BYTES(blockidx->PageSize);
-		blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset);
+		blockoffset = sc->dsp_firm->data + le32_to_cpu(
+							blockidx->PageOffset);
 
 		bi.dwSize = cpu_to_be32(blocksize);
 		bi.dwAddress = cpu_to_be32(le32_to_cpu(blockidx->PageAddress));
 
 		uea_dbg(INS_TO_USBDEV(sc),
-		       "sending block %u for DSP page %u size %u address %x\n",
-		       blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
+			"sending block %u for DSP page "
+			"%u size %u address %x\n",
+			blockno, pageno, blocksize,
+			le32_to_cpu(blockidx->PageAddress));
 
 		/* send block info through the IDMA pipe */
 		if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
@@ -1042,7 +1050,8 @@
 
 	p = (struct l1_code *) sc->dsp_firm->data;
 	if (pageno >= le16_to_cpu(p->page_header[0].PageNumber)) {
-		uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
+		uea_err(INS_TO_USBDEV(sc), "invalid DSP "
+						"page %u requested\n", pageno);
 		return;
 	}
 
@@ -1059,7 +1068,7 @@
 			__uea_load_page_e4(sc, i, 1);
 	}
 
-	uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n");
+	uea_dbg(INS_TO_USBDEV(sc) , "sending start bi\n");
 
 	bi.wHdr = cpu_to_be16(UEA_BIHDR);
 	bi.bBootPage = 0;
@@ -1139,8 +1148,10 @@
 	uea_enters(INS_TO_USBDEV(sc));
 	uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, "
 			"offset : 0x%04x, data : 0x%08x\n",
-			E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function),
-			E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address),
+			E1_FUNCTION_TYPE(function),
+			E1_FUNCTION_SUBTYPE(function),
+			E1_GETSA1(address), E1_GETSA2(address),
+			E1_GETSA3(address),
 			E1_GETSA4(address), offset, data);
 
 	/* we send a request, but we expect a reply */
@@ -1157,7 +1168,8 @@
 	cmv.wOffsetAddress = cpu_to_le16(offset);
 	put_unaligned_le32(data >> 16 | data << 16, &cmv.dwData);
 
-	ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
+	ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START,
+							sizeof(cmv), &cmv);
 	if (ret < 0)
 		return ret;
 	ret = wait_cmv_ack(sc);
@@ -1191,7 +1203,8 @@
 	cmv.wOffset = cpu_to_be16(offset);
 	cmv.dwData[0] = cpu_to_be32(data);
 
-	ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
+	ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START,
+							sizeof(cmv), &cmv);
 	if (ret < 0)
 		return ret;
 	ret = wait_cmv_ack(sc);
@@ -1208,7 +1221,7 @@
 		uea_err(INS_TO_USBDEV(sc),
 			"reading cmv failed with error %d\n", ret);
 	else
-	 	*data = sc->data;
+		*data = sc->data;
 
 	return ret;
 }
@@ -1216,13 +1229,14 @@
 static inline int uea_read_cmv_e4(struct uea_softc *sc,
 		u8 size, u16 group, u16 address, u16 offset, u32 *data)
 {
-	int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size),
+	int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS,
+							E4_REQUESTREAD, size),
 			  group, address, offset, 0);
 	if (ret < 0)
 		uea_err(INS_TO_USBDEV(sc),
 			"reading cmv failed with error %d\n", ret);
 	else {
-	 	*data = sc->data;
+		*data = sc->data;
 		/* size is in 16-bit word quantities */
 		if (size > 2)
 			*(data + 1) = sc->data1;
@@ -1245,7 +1259,8 @@
 static inline int uea_write_cmv_e4(struct uea_softc *sc,
 		u8 size, u16 group, u16 address, u16 offset, u32 data)
 {
-	int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size),
+	int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS,
+							E4_REQUESTWRITE, size),
 			  group, address, offset, data);
 	if (ret < 0)
 		uea_err(INS_TO_USBDEV(sc),
@@ -1442,27 +1457,29 @@
 		return ret;
 
 	switch (sc->stats.phy.state) {
-		case 0x0:	/* not yet synchronized */
-		case 0x1:
-		case 0x3:
-		case 0x4:
-			uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n");
-			return 0;
-		case 0x5:	/* initialization */
-		case 0x6:
-		case 0x9:
-		case 0xa:
-			uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n");
-			return 0;
-		case 0x2:	/* fail ... */
-			uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
-					" (may be try other cmv/dsp)\n");
-			return -EAGAIN;
-		case 0x7: 	/* operational */
-			break;
-		default:
-			uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state);
-			return 0;
+	case 0x0:	/* not yet synchronized */
+	case 0x1:
+	case 0x3:
+	case 0x4:
+		uea_dbg(INS_TO_USBDEV(sc), "modem not yet "
+						"synchronized\n");
+		return 0;
+	case 0x5:	/* initialization */
+	case 0x6:
+	case 0x9:
+	case 0xa:
+		uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n");
+		return 0;
+	case 0x2:	/* fail ... */
+		uea_info(INS_TO_USBDEV(sc), "modem synchronization "
+				"failed (may be try other cmv/dsp)\n");
+		return -EAGAIN;
+	case 0x7:	/* operational */
+		break;
+	default:
+		uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n",
+						sc->stats.phy.state);
+		return 0;
 	}
 
 	if (data != 7) {
@@ -1502,9 +1519,9 @@
 	if (sc->stats.phy.flags) {
 		uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n",
 		       sc->stats.phy.flags);
-		if (sc->stats.phy.flags & 1) //delineation LOSS
+		if (sc->stats.phy.flags & 1) /* delineation LOSS */
 			return -EAGAIN;
-		if (sc->stats.phy.flags & 0x4000) //Reset Flag
+		if (sc->stats.phy.flags & 0x4000) /* Reset Flag */
 			return -EAGAIN;
 		return 0;
 	}
@@ -1618,7 +1635,8 @@
 	if (ret < 0) {
 		/* if caller can handle old version, try to provide it */
 		if (*ver == 1) {
-			uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, "
+			uea_warn(INS_TO_USBDEV(sc), "requesting "
+							"firmware %s failed, "
 				"try to get older cmvs\n", cmv_name);
 			return request_cmvs_old(sc, cmvs, fw);
 		}
@@ -1632,8 +1650,8 @@
 	data = (u8 *) (*fw)->data;
 	if (size < 4 || strncmp(data, "cmv2", 4) != 0) {
 		if (*ver == 1) {
-			uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, "
-				"try to get older cmvs\n", cmv_name);
+			uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted,"
+				" try to get older cmvs\n", cmv_name);
 			release_firmware(*fw);
 			return request_cmvs_old(sc, cmvs, fw);
 		}
@@ -1670,7 +1688,7 @@
 	int i, ret, len;
 	void *cmvs_ptr;
 	const struct firmware *cmvs_fw;
-	int ver = 1; // we can handle v1 cmv firmware version;
+	int ver = 1; /* we can handle v1 cmv firmware version; */
 
 	/* Enter in R-IDLE (cmv) until instructed otherwise */
 	ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1);
@@ -1685,7 +1703,7 @@
 			sc->stats.phy.firmid);
 
 	/* get options */
- 	ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+	ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
 	if (ret < 0)
 		return ret;
 
@@ -1697,9 +1715,10 @@
 			"please update your firmware\n");
 
 		for (i = 0; i < len; i++) {
-			ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v1[i].address),
-						get_unaligned_le16(&cmvs_v1[i].offset),
-						get_unaligned_le32(&cmvs_v1[i].data));
+			ret = uea_write_cmv_e1(sc,
+				get_unaligned_le32(&cmvs_v1[i].address),
+				get_unaligned_le16(&cmvs_v1[i].offset),
+				get_unaligned_le32(&cmvs_v1[i].data));
 			if (ret < 0)
 				goto out;
 		}
@@ -1707,9 +1726,10 @@
 		struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
 
 		for (i = 0; i < len; i++) {
-			ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v2[i].address),
-						(u16) get_unaligned_le32(&cmvs_v2[i].offset),
-						get_unaligned_le32(&cmvs_v2[i].data));
+			ret = uea_write_cmv_e1(sc,
+				get_unaligned_le32(&cmvs_v2[i].address),
+				(u16) get_unaligned_le32(&cmvs_v2[i].offset),
+				get_unaligned_le32(&cmvs_v2[i].data));
 			if (ret < 0)
 				goto out;
 		}
@@ -1722,7 +1742,8 @@
 	/* Enter in R-ACT-REQ */
 	ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2);
 	uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
-	uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+	uea_info(INS_TO_USBDEV(sc), "modem started, waiting "
+						"synchronization...\n");
 out:
 	release_firmware(cmvs_fw);
 	return ret;
@@ -1733,7 +1754,7 @@
 	int i, ret, len;
 	void *cmvs_ptr;
 	const struct firmware *cmvs_fw;
-	int ver = 2; // we can only handle v2 cmv firmware version;
+	int ver = 2; /* we can only handle v2 cmv firmware version; */
 
 	/* Enter in R-IDLE (cmv) until instructed otherwise */
 	ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1);
@@ -1750,7 +1771,7 @@
 
 
 	/* get options */
- 	ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+	ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
 	if (ret < 0)
 		return ret;
 
@@ -1760,10 +1781,10 @@
 
 		for (i = 0; i < len; i++) {
 			ret = uea_write_cmv_e4(sc, 1,
-						get_unaligned_le32(&cmvs_v2[i].group),
-						get_unaligned_le32(&cmvs_v2[i].address),
-						get_unaligned_le32(&cmvs_v2[i].offset),
-						get_unaligned_le32(&cmvs_v2[i].data));
+				get_unaligned_le32(&cmvs_v2[i].group),
+				get_unaligned_le32(&cmvs_v2[i].address),
+				get_unaligned_le32(&cmvs_v2[i].offset),
+				get_unaligned_le32(&cmvs_v2[i].data));
 			if (ret < 0)
 				goto out;
 		}
@@ -1776,7 +1797,8 @@
 	/* Enter in R-ACT-REQ */
 	ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2);
 	uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
-	uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+	uea_info(INS_TO_USBDEV(sc), "modem started, waiting "
+						"synchronization...\n");
 out:
 	release_firmware(cmvs_fw);
 	return ret;
@@ -1812,7 +1834,7 @@
 	uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL);
 	uea_request(sc, UEA_SET_MODE, UEA_BOOT_IDMA, 0, NULL);
 
- 	/* enter reset mode */
+	/* enter reset mode */
 	uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL);
 
 	/* original driver use 200ms, but windows driver use 100ms */
@@ -1824,7 +1846,7 @@
 	uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL);
 
 	if (UEA_CHIP_VERSION(sc) != EAGLE_IV) {
- 		/* clear tx and rx mailboxes */
+		/* clear tx and rx mailboxes */
 		uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
 		uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
 		uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
@@ -1835,9 +1857,11 @@
 		return ret;
 
 	if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
-		sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1);
+		sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE,
+							E4_MODEMREADY, 1);
 	else
-		sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY);
+		sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE,
+							E1_MODEMREADY);
 
 	/* demask interrupt */
 	sc->booting = 0;
@@ -1937,7 +1961,8 @@
 	value = 0;
 	ret = uea_send_modem_cmd(sc->usb_dev, 0xe, 1, &value);
 	if (ret < 0)
-		uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret);
+		uea_err(sc->usb_dev, "elsa de-assert failed with error"
+								" %d\n", ret);
 
 err1:
 	release_firmware(fw_entry);
@@ -1966,13 +1991,15 @@
 		if (UEA_CHIP_VERSION(sc) == ADI930
 				&& cmv->bFunction ==  E1_MAKEFUNCTION(2, 2)) {
 			cmv->wIndex = cpu_to_le16(dsc->idx);
-			put_unaligned_le32(dsc->address, &cmv->dwSymbolicAddress);
+			put_unaligned_le32(dsc->address,
+						&cmv->dwSymbolicAddress);
 			cmv->wOffsetAddress = cpu_to_le16(dsc->offset);
 		} else
 			goto bad2;
 	}
 
-	if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) {
+	if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE,
+							E1_MODEMREADY)) {
 		wake_up_cmv_ack(sc);
 		uea_leaves(INS_TO_USBDEV(sc));
 		return;
@@ -2021,7 +2048,8 @@
 	if (be16_to_cpu(cmv->wFunction) != dsc->function)
 		goto bad2;
 
-	if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) {
+	if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE,
+						E4_MODEMREADY, 1)) {
 		wake_up_cmv_ack(sc);
 		uea_leaves(INS_TO_USBDEV(sc));
 		return;
@@ -2048,14 +2076,16 @@
 	return;
 }
 
-static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr)
+static void uea_schedule_load_page_e1(struct uea_softc *sc,
+						struct intr_pkt *intr)
 {
 	sc->pageno = intr->e1_bSwapPageNo;
 	sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4;
 	queue_work(sc->work_q, &sc->task);
 }
 
-static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr)
+static void uea_schedule_load_page_e4(struct uea_softc *sc,
+						struct intr_pkt *intr)
 {
 	sc->pageno = intr->e4_bSwapPageNo;
 	queue_work(sc->work_q, &sc->task);
@@ -2263,8 +2293,8 @@
 
 static DEVICE_ATTR(stat_status, S_IWUGO | S_IRUGO, read_status, reboot);
 
-static ssize_t read_human_status(struct device *dev, struct device_attribute *attr,
-		char *buf)
+static ssize_t read_human_status(struct device *dev,
+			struct device_attribute *attr, char *buf)
 {
 	int ret = -ENODEV;
 	int modem_state;
@@ -2289,7 +2319,7 @@
 		case 0xa:
 			modem_state = 1;
 			break;
-		case 0x7: 	/* operational */
+		case 0x7:	/* operational */
 			modem_state = 2;
 			break;
 		case 0x2:	/* fail ... */
@@ -2324,7 +2354,8 @@
 	return ret;
 }
 
-static DEVICE_ATTR(stat_human_status, S_IWUGO | S_IRUGO, read_human_status, NULL);
+static DEVICE_ATTR(stat_human_status, S_IWUGO | S_IRUGO,
+				read_human_status, NULL);
 
 static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
 		char *buf)
@@ -2358,25 +2389,25 @@
 
 static DEVICE_ATTR(stat_delin, S_IWUGO | S_IRUGO, read_delin, NULL);
 
-#define UEA_ATTR(name, reset) 					\
+#define UEA_ATTR(name, reset)					\
 								\
-static ssize_t read_##name(struct device *dev, 			\
+static ssize_t read_##name(struct device *dev,			\
 		struct device_attribute *attr, char *buf)	\
-{ 								\
-	int ret = -ENODEV; 					\
-	struct uea_softc *sc; 					\
- 								\
-	mutex_lock(&uea_mutex); 				\
+{								\
+	int ret = -ENODEV;					\
+	struct uea_softc *sc;					\
+								\
+	mutex_lock(&uea_mutex);					\
 	sc = dev_to_uea(dev);					\
-	if (!sc) 						\
-		goto out; 					\
+	if (!sc)						\
+		goto out;					\
 	ret = snprintf(buf, 10, "%08x\n", sc->stats.phy.name);	\
 	if (reset)						\
 		sc->stats.phy.name = 0;				\
-out: 								\
-	mutex_unlock(&uea_mutex); 				\
-	return ret; 						\
-} 								\
+out:								\
+	mutex_unlock(&uea_mutex);				\
+	return ret;						\
+}								\
 								\
 static DEVICE_ATTR(stat_##name, S_IRUGO, read_##name, NULL)
 
@@ -2527,12 +2558,14 @@
 	else if (sc->driver_info & AUTO_ANNEX_B)
 		sc->annex = ANNEXB;
 	else
-		sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA;
+		sc->annex = (le16_to_cpu
+		(sc->usb_dev->descriptor.bcdDevice) & 0x80) ? ANNEXB : ANNEXA;
 
 	alt = altsetting[sc->modem_index];
 	/* ADI930 don't support iso */
 	if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) {
-		if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) {
+		if (alt <= 8 &&
+			usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) {
 			uea_dbg(usb, "set alternate %u for 2 interface\n", alt);
 			uea_info(usb, "using iso mode\n");
 			usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ;
@@ -2621,40 +2654,74 @@
  * List of supported VID/PID
  */
 static const struct usb_device_id uea_ids[] = {
-	{USB_DEVICE(ANALOG_VID,	ADI930_PID_PREFIRM),	.driver_info = ADI930 | PREFIRM},
-	{USB_DEVICE(ANALOG_VID,	ADI930_PID_PSTFIRM),	.driver_info = ADI930 | PSTFIRM},
-	{USB_DEVICE(ANALOG_VID,	EAGLE_I_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(ANALOG_VID,	EAGLE_I_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM},
-	{USB_DEVICE(ANALOG_VID,	EAGLE_II_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
-	{USB_DEVICE(ANALOG_VID,	EAGLE_II_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM},
-	{USB_DEVICE(ANALOG_VID,	EAGLE_IIC_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
-	{USB_DEVICE(ANALOG_VID,	EAGLE_IIC_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM},
-	{USB_DEVICE(ANALOG_VID,	EAGLE_III_PID_PREFIRM),	.driver_info = EAGLE_III | PREFIRM},
-	{USB_DEVICE(ANALOG_VID,	EAGLE_III_PID_PSTFIRM),	.driver_info = EAGLE_III | PSTFIRM},
-	{USB_DEVICE(ANALOG_VID,	EAGLE_IV_PID_PREFIRM),	.driver_info = EAGLE_IV | PREFIRM},
-	{USB_DEVICE(ANALOG_VID,	EAGLE_IV_PID_PSTFIRM),	.driver_info = EAGLE_IV | PSTFIRM},
-	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_A_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_A_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
-	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_B_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_B_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
-	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_A_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
-	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_A_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A},
-	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_B_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
-	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_B_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B},
-	{USB_DEVICE(ELSA_VID,	ELSA_PID_PREFIRM),	.driver_info = ADI930 | PREFIRM},
-	{USB_DEVICE(ELSA_VID,	ELSA_PID_PSTFIRM),	.driver_info = ADI930 | PSTFIRM},
-	{USB_DEVICE(ELSA_VID,	ELSA_PID_A_PREFIRM),	.driver_info = ADI930 | PREFIRM},
-	{USB_DEVICE(ELSA_VID,	ELSA_PID_A_PSTFIRM),	.driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A},
-	{USB_DEVICE(ELSA_VID,	ELSA_PID_B_PREFIRM),	.driver_info = ADI930 | PREFIRM},
-	{USB_DEVICE(ELSA_VID,	ELSA_PID_B_PSTFIRM),	.driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B},
-	{USB_DEVICE(USR_VID,	MILLER_A_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(USR_VID,	MILLER_A_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM  | AUTO_ANNEX_A},
-	{USB_DEVICE(USR_VID,	MILLER_B_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(USR_VID,	MILLER_B_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM  | AUTO_ANNEX_B},
-	{USB_DEVICE(USR_VID,	HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(USR_VID,	HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
-	{USB_DEVICE(USR_VID,	HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(USR_VID,	HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
+	{USB_DEVICE(ANALOG_VID,	ADI930_PID_PREFIRM),
+		.driver_info = ADI930 | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	ADI930_PID_PSTFIRM),
+		.driver_info = ADI930 | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_I_PID_PREFIRM),
+		.driver_info = EAGLE_I | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_I_PID_PSTFIRM),
+		.driver_info = EAGLE_I | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_II_PID_PREFIRM),
+		.driver_info = EAGLE_II | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_II_PID_PSTFIRM),
+		.driver_info = EAGLE_II | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_IIC_PID_PREFIRM),
+		.driver_info = EAGLE_II | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_IIC_PID_PSTFIRM),
+		.driver_info = EAGLE_II | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_III_PID_PREFIRM),
+		.driver_info = EAGLE_III | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_III_PID_PSTFIRM),
+		.driver_info = EAGLE_III | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_IV_PID_PREFIRM),
+		.driver_info = EAGLE_IV | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_IV_PID_PSTFIRM),
+		.driver_info = EAGLE_IV | PSTFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_A_PID_PREFIRM),
+		.driver_info = EAGLE_I | PREFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_A_PID_PSTFIRM),
+		.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_B_PID_PREFIRM),
+		.driver_info = EAGLE_I | PREFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_B_PID_PSTFIRM),
+		.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_A_PID_PREFIRM),
+		.driver_info = EAGLE_II | PREFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_A_PID_PSTFIRM),
+		.driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_B_PID_PREFIRM),
+		.driver_info = EAGLE_II | PREFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_B_PID_PSTFIRM),
+		.driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_PREFIRM),
+		.driver_info = ADI930 | PREFIRM},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_PSTFIRM),
+		.driver_info = ADI930 | PSTFIRM},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_A_PREFIRM),
+		.driver_info = ADI930 | PREFIRM},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_A_PSTFIRM),
+		.driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_B_PREFIRM),
+		.driver_info = ADI930 | PREFIRM},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_B_PSTFIRM),
+		.driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B},
+	{USB_DEVICE(USR_VID,	MILLER_A_PID_PREFIRM),
+		.driver_info = EAGLE_I | PREFIRM},
+	{USB_DEVICE(USR_VID,	MILLER_A_PID_PSTFIRM),
+		.driver_info = EAGLE_I | PSTFIRM  | AUTO_ANNEX_A},
+	{USB_DEVICE(USR_VID,	MILLER_B_PID_PREFIRM),
+		.driver_info = EAGLE_I | PREFIRM},
+	{USB_DEVICE(USR_VID,	MILLER_B_PID_PSTFIRM),
+		.driver_info = EAGLE_I | PSTFIRM  | AUTO_ANNEX_B},
+	{USB_DEVICE(USR_VID,	HEINEKEN_A_PID_PREFIRM),
+		.driver_info = EAGLE_I | PREFIRM},
+	{USB_DEVICE(USR_VID,	HEINEKEN_A_PID_PSTFIRM),
+		.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
+	{USB_DEVICE(USR_VID,	HEINEKEN_B_PID_PREFIRM),
+		.driver_info = EAGLE_I | PREFIRM},
+	{USB_DEVICE(USR_VID,	HEINEKEN_B_PID_PSTFIRM),
+		.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
 	{}
 };
 
diff --git a/drivers/usb/c67x00/c67x00-hcd.h b/drivers/usb/c67x00/c67x00-hcd.h
index e8c6d94..74e4462 100644
--- a/drivers/usb/c67x00/c67x00-hcd.h
+++ b/drivers/usb/c67x00/c67x00-hcd.h
@@ -28,7 +28,7 @@
 #include <linux/spinlock.h>
 #include <linux/list.h>
 #include <linux/usb.h>
-#include "../core/hcd.h"
+#include <linux/usb/hcd.h>
 #include "c67x00.h"
 
 /*
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 5e1a253..0c2f14f 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -892,7 +892,7 @@
 	struct usb_device *usb_dev = interface_to_usbdev(acm->control);
 
 	for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++)
-		usb_buffer_free(usb_dev, acm->writesize, wb->buf, wb->dmah);
+		usb_free_coherent(usb_dev, acm->writesize, wb->buf, wb->dmah);
 }
 
 static void acm_read_buffers_free(struct acm *acm)
@@ -901,8 +901,8 @@
 	int i, n = acm->rx_buflimit;
 
 	for (i = 0; i < n; i++)
-		usb_buffer_free(usb_dev, acm->readsize,
-					acm->rb[i].base, acm->rb[i].dma);
+		usb_free_coherent(usb_dev, acm->readsize,
+				  acm->rb[i].base, acm->rb[i].dma);
 }
 
 /* Little helper: write buffers allocate */
@@ -912,13 +912,13 @@
 	struct acm_wb *wb;
 
 	for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
-		wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
+		wb->buf = usb_alloc_coherent(acm->dev, acm->writesize, GFP_KERNEL,
 		    &wb->dmah);
 		if (!wb->buf) {
 			while (i != 0) {
 				--i;
 				--wb;
-				usb_buffer_free(acm->dev, acm->writesize,
+				usb_free_coherent(acm->dev, acm->writesize,
 				    wb->buf, wb->dmah);
 			}
 			return -ENOMEM;
@@ -1177,7 +1177,7 @@
 	tty_port_init(&acm->port);
 	acm->port.ops = &acm_port_ops;
 
-	buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
+	buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
 	if (!buf) {
 		dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
 		goto alloc_fail2;
@@ -1210,11 +1210,11 @@
 	for (i = 0; i < num_rx_buf; i++) {
 		struct acm_rb *rb = &(acm->rb[i]);
 
-		rb->base = usb_buffer_alloc(acm->dev, readsize,
+		rb->base = usb_alloc_coherent(acm->dev, readsize,
 				GFP_KERNEL, &rb->dma);
 		if (!rb->base) {
 			dev_dbg(&intf->dev,
-				"out of memory (read bufs usb_buffer_alloc)\n");
+				"out of memory (read bufs usb_alloc_coherent)\n");
 			goto alloc_fail7;
 		}
 	}
@@ -1306,7 +1306,7 @@
 alloc_fail5:
 	acm_write_buffers_free(acm);
 alloc_fail4:
-	usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
+	usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
 alloc_fail2:
 	kfree(acm);
 alloc_fail:
@@ -1356,8 +1356,8 @@
 	stop_data_traffic(acm);
 
 	acm_write_buffers_free(acm);
-	usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer,
-								acm->ctrl_dma);
+	usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer,
+			  acm->ctrl_dma);
 	acm_read_buffers_free(acm);
 
 	if (!acm->combined_interfaces)
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 4a8e87e..5eeb570 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -124,8 +124,8 @@
 	unsigned char clocal;				/* termios CLOCAL */
 	unsigned int ctrl_caps;				/* control capabilities from the class specific header */
 	unsigned int susp_count;			/* number of suspended interfaces */
-	int combined_interfaces:1;			/* control and data collapsed */
-	int is_int_ep:1;				/* interrupt endpoints contrary to spec used */
+	unsigned int combined_interfaces:1;		/* control and data collapsed */
+	unsigned int is_int_ep:1;			/* interrupt endpoints contrary to spec used */
 	u8 bInterval;
 	struct acm_wb *delayed_wb;			/* write queued for a device about to be woken */
 };
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 189141c..094c76b 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -276,14 +276,14 @@
 
 static void cleanup(struct wdm_device *desc)
 {
-	usb_buffer_free(interface_to_usbdev(desc->intf),
-			desc->wMaxPacketSize,
-			desc->sbuf,
-			desc->validity->transfer_dma);
-	usb_buffer_free(interface_to_usbdev(desc->intf),
-			desc->wMaxCommand,
-			desc->inbuf,
-			desc->response->transfer_dma);
+	usb_free_coherent(interface_to_usbdev(desc->intf),
+			  desc->wMaxPacketSize,
+			  desc->sbuf,
+			  desc->validity->transfer_dma);
+	usb_free_coherent(interface_to_usbdev(desc->intf),
+			  desc->wMaxCommand,
+			  desc->inbuf,
+			  desc->response->transfer_dma);
 	kfree(desc->orq);
 	kfree(desc->irq);
 	kfree(desc->ubuf);
@@ -705,17 +705,17 @@
 	if (!desc->ubuf)
 		goto err;
 
-	desc->sbuf = usb_buffer_alloc(interface_to_usbdev(intf),
+	desc->sbuf = usb_alloc_coherent(interface_to_usbdev(intf),
 					desc->wMaxPacketSize,
 					GFP_KERNEL,
 					&desc->validity->transfer_dma);
 	if (!desc->sbuf)
 		goto err;
 
-	desc->inbuf = usb_buffer_alloc(interface_to_usbdev(intf),
-					desc->bMaxPacketSize0,
-					GFP_KERNEL,
-					&desc->response->transfer_dma);
+	desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf),
+					 desc->bMaxPacketSize0,
+					 GFP_KERNEL,
+					 &desc->response->transfer_dma);
 	if (!desc->inbuf)
 		goto err2;
 
@@ -742,15 +742,15 @@
 	return rv;
 err3:
 	usb_set_intfdata(intf, NULL);
-	usb_buffer_free(interface_to_usbdev(desc->intf),
-			desc->bMaxPacketSize0,
+	usb_free_coherent(interface_to_usbdev(desc->intf),
+			  desc->bMaxPacketSize0,
 			desc->inbuf,
 			desc->response->transfer_dma);
 err2:
-	usb_buffer_free(interface_to_usbdev(desc->intf),
-			desc->wMaxPacketSize,
-			desc->sbuf,
-			desc->validity->transfer_dma);
+	usb_free_coherent(interface_to_usbdev(desc->intf),
+			  desc->wMaxPacketSize,
+			  desc->sbuf,
+			  desc->validity->transfer_dma);
 err:
 	free_urbs(desc);
 	kfree(desc->ubuf);
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 93b5f85..2250095 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -27,7 +27,7 @@
  *	v0.11 - add proto_bias option (Pete Zaitcev)
  *	v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
  *	v0.13 - alloc space for statusbuf (<status> not on stack);
- *		use usb_buffer_alloc() for read buf & write buf;
+ *		use usb_alloc_coherent() for read buf & write buf;
  *      none  - Maintained in Linux kernel after v0.13
  */
 
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index 3ba2fff..2c69654 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -14,7 +14,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/usb.h>
-#include "hcd.h"
+#include <linux/usb/hcd.h>
 
 
 /*
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 0d3af6a..83126b0 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -1,12 +1,14 @@
 #include <linux/usb.h>
 #include <linux/usb/ch9.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/quirks.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/device.h>
 #include <asm/byteorder.h>
 #include "usb.h"
-#include "hcd.h"
+
 
 #define USB_MAXALTSETTING		128	/* Hard limit */
 #define USB_MAXENDPOINTS		30	/* Hard limit */
@@ -19,32 +21,6 @@
 	return (n == 1 ? "" : "s");
 }
 
-/* FIXME: this is a kludge */
-static int find_next_descriptor_more(unsigned char *buffer, int size,
-    int dt1, int dt2, int dt3, int *num_skipped)
-{
-	struct usb_descriptor_header *h;
-	int n = 0;
-	unsigned char *buffer0 = buffer;
-
-	/* Find the next descriptor of type dt1 or dt2 or dt3 */
-	while (size > 0) {
-		h = (struct usb_descriptor_header *) buffer;
-		if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2 ||
-				h->bDescriptorType == dt3)
-			break;
-		buffer += h->bLength;
-		size -= h->bLength;
-		++n;
-	}
-
-	/* Store the number of descriptors skipped and return the
-	 * number of bytes skipped */
-	if (num_skipped)
-		*num_skipped = n;
-	return buffer - buffer0;
-}
-
 static int find_next_descriptor(unsigned char *buffer, int size,
     int dt1, int dt2, int *num_skipped)
 {
@@ -69,47 +45,41 @@
 	return buffer - buffer0;
 }
 
-static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
+static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
 		int inum, int asnum, struct usb_host_endpoint *ep,
-		int num_ep, unsigned char *buffer, int size)
+		unsigned char *buffer, int size)
 {
-	unsigned char *buffer_start = buffer;
-	struct usb_ss_ep_comp_descriptor	*desc;
-	int retval;
-	int num_skipped;
+	struct usb_ss_ep_comp_descriptor *desc;
 	int max_tx;
-	int i;
 
+	/* The SuperSpeed endpoint companion descriptor is supposed to
+	 * be the first thing immediately following the endpoint descriptor.
+	 */
 	desc = (struct usb_ss_ep_comp_descriptor *) buffer;
-	if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) {
+	if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP ||
+			size < USB_DT_SS_EP_COMP_SIZE) {
 		dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
 				" interface %d altsetting %d ep %d: "
 				"using minimum values\n",
 				cfgno, inum, asnum, ep->desc.bEndpointAddress);
-		/*
-		 * The next descriptor is for an Endpoint or Interface,
-		 * no extra descriptors to copy into the companion structure,
-		 * and we didn't eat up any of the buffer.
-		 */
-		return 0;
-	}
-	memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE);
-	desc = &ep->ss_ep_comp->desc;
-	buffer += desc->bLength;
-	size -= desc->bLength;
 
-	/* Eat up the other descriptors we don't care about */
-	ep->ss_ep_comp->extra = buffer;
-	i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
-			USB_DT_INTERFACE, &num_skipped);
-	ep->ss_ep_comp->extralen = i;
-	buffer += i;
-	size -= i;
-	retval = buffer - buffer_start;
-	if (num_skipped > 0)
-		dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
-				num_skipped, plural(num_skipped),
-				"SuperSpeed endpoint companion");
+		/* Fill in some default values.
+		 * Leave bmAttributes as zero, which will mean no streams for
+		 * bulk, and isoc won't support multiple bursts of packets.
+		 * With bursts of only one packet, and a Mult of 1, the max
+		 * amount of data moved per endpoint service interval is one
+		 * packet.
+		 */
+		ep->ss_ep_comp.bLength = USB_DT_SS_EP_COMP_SIZE;
+		ep->ss_ep_comp.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
+		if (usb_endpoint_xfer_isoc(&ep->desc) ||
+				usb_endpoint_xfer_int(&ep->desc))
+			ep->ss_ep_comp.wBytesPerInterval =
+					ep->desc.wMaxPacketSize;
+		return;
+	}
+
+	memcpy(&ep->ss_ep_comp, desc, USB_DT_SS_EP_COMP_SIZE);
 
 	/* Check the various values */
 	if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) {
@@ -117,47 +87,48 @@
 				"config %d interface %d altsetting %d ep %d: "
 				"setting to zero\n", desc->bMaxBurst,
 				cfgno, inum, asnum, ep->desc.bEndpointAddress);
-		desc->bMaxBurst = 0;
-	}
-	if (desc->bMaxBurst > 15) {
+		ep->ss_ep_comp.bMaxBurst = 0;
+	} else if (desc->bMaxBurst > 15) {
 		dev_warn(ddev, "Endpoint with bMaxBurst = %d in "
 				"config %d interface %d altsetting %d ep %d: "
 				"setting to 15\n", desc->bMaxBurst,
 				cfgno, inum, asnum, ep->desc.bEndpointAddress);
-		desc->bMaxBurst = 15;
+		ep->ss_ep_comp.bMaxBurst = 15;
 	}
-	if ((usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_int(&ep->desc))
-			&& desc->bmAttributes != 0) {
+
+	if ((usb_endpoint_xfer_control(&ep->desc) ||
+			usb_endpoint_xfer_int(&ep->desc)) &&
+				desc->bmAttributes != 0) {
 		dev_warn(ddev, "%s endpoint with bmAttributes = %d in "
 				"config %d interface %d altsetting %d ep %d: "
 				"setting to zero\n",
 				usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk",
 				desc->bmAttributes,
 				cfgno, inum, asnum, ep->desc.bEndpointAddress);
-		desc->bmAttributes = 0;
-	}
-	if (usb_endpoint_xfer_bulk(&ep->desc) && desc->bmAttributes > 16) {
+		ep->ss_ep_comp.bmAttributes = 0;
+	} else if (usb_endpoint_xfer_bulk(&ep->desc) &&
+			desc->bmAttributes > 16) {
 		dev_warn(ddev, "Bulk endpoint with more than 65536 streams in "
 				"config %d interface %d altsetting %d ep %d: "
 				"setting to max\n",
 				cfgno, inum, asnum, ep->desc.bEndpointAddress);
-		desc->bmAttributes = 16;
-	}
-	if (usb_endpoint_xfer_isoc(&ep->desc) && desc->bmAttributes > 2) {
+		ep->ss_ep_comp.bmAttributes = 16;
+	} else if (usb_endpoint_xfer_isoc(&ep->desc) &&
+			desc->bmAttributes > 2) {
 		dev_warn(ddev, "Isoc endpoint has Mult of %d in "
 				"config %d interface %d altsetting %d ep %d: "
 				"setting to 3\n", desc->bmAttributes + 1,
 				cfgno, inum, asnum, ep->desc.bEndpointAddress);
-		desc->bmAttributes = 2;
+		ep->ss_ep_comp.bmAttributes = 2;
 	}
-	if (usb_endpoint_xfer_isoc(&ep->desc)) {
+
+	if (usb_endpoint_xfer_isoc(&ep->desc))
 		max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) *
 			(desc->bmAttributes + 1);
-	} else if (usb_endpoint_xfer_int(&ep->desc)) {
+	else if (usb_endpoint_xfer_int(&ep->desc))
 		max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
-	} else {
-		goto valid;
-	}
+	else
+		max_tx = 999999;
 	if (desc->wBytesPerInterval > max_tx) {
 		dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
 				"config %d interface %d altsetting %d ep %d: "
@@ -166,10 +137,8 @@
 				desc->wBytesPerInterval,
 				cfgno, inum, asnum, ep->desc.bEndpointAddress,
 				max_tx);
-		desc->wBytesPerInterval = max_tx;
+		ep->ss_ep_comp.wBytesPerInterval = max_tx;
 	}
-valid:
-	return retval;
 }
 
 static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
@@ -291,61 +260,19 @@
 				cfgno, inum, asnum, d->bEndpointAddress,
 				maxp);
 	}
-	/* Allocate room for and parse any SS endpoint companion descriptors */
-	if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) {
-		endpoint->extra = buffer;
-		i = find_next_descriptor_more(buffer, size, USB_DT_SS_ENDPOINT_COMP,
-				USB_DT_ENDPOINT, USB_DT_INTERFACE, &n);
-		endpoint->extralen = i;
-		buffer += i;
-		size -= i;
 
-		/* Allocate space for the SS endpoint companion descriptor */
-		endpoint->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp),
-				GFP_KERNEL);
-		if (!endpoint->ss_ep_comp)
-			return -ENOMEM;
+	/* Parse a possible SuperSpeed endpoint companion descriptor */
+	if (to_usb_device(ddev)->speed == USB_SPEED_SUPER)
+		usb_parse_ss_endpoint_companion(ddev, cfgno,
+				inum, asnum, endpoint, buffer, size);
 
-		/* Fill in some default values (may be overwritten later) */
-		endpoint->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE;
-		endpoint->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
-		endpoint->ss_ep_comp->desc.bMaxBurst = 0;
-		/*
-		 * Leave bmAttributes as zero, which will mean no streams for
-		 * bulk, and isoc won't support multiple bursts of packets.
-		 * With bursts of only one packet, and a Mult of 1, the max
-		 * amount of data moved per endpoint service interval is one
-		 * packet.
-		 */
-		if (usb_endpoint_xfer_isoc(&endpoint->desc) ||
-				usb_endpoint_xfer_int(&endpoint->desc))
-			endpoint->ss_ep_comp->desc.wBytesPerInterval =
-				endpoint->desc.wMaxPacketSize;
-
-		if (size > 0) {
-			retval = usb_parse_ss_endpoint_companion(ddev, cfgno,
-					inum, asnum, endpoint, num_ep, buffer,
-					size);
-			if (retval >= 0) {
-				buffer += retval;
-				retval = buffer - buffer0;
-			}
-		} else {
-			dev_warn(ddev, "config %d interface %d altsetting %d "
-				"endpoint 0x%X has no "
-				"SuperSpeed companion descriptor\n",
-				cfgno, inum, asnum, d->bEndpointAddress);
-			retval = buffer - buffer0;
-		}
-	} else {
-		/* Skip over any Class Specific or Vendor Specific descriptors;
-		 * find the next endpoint or interface descriptor */
-		endpoint->extra = buffer;
-		i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
-				USB_DT_INTERFACE, &n);
-		endpoint->extralen = i;
-		retval = buffer - buffer0 + i;
-	}
+	/* Skip over any Class Specific or Vendor Specific descriptors;
+	 * find the next endpoint or interface descriptor */
+	endpoint->extra = buffer;
+	i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
+			USB_DT_INTERFACE, &n);
+	endpoint->extralen = i;
+	retval = buffer - buffer0 + i;
 	if (n > 0)
 		dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
 		    n, plural(n), "endpoint");
@@ -478,9 +405,10 @@
 	return buffer - buffer0 + i;
 }
 
-static int usb_parse_configuration(struct device *ddev, int cfgidx,
+static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
     struct usb_host_config *config, unsigned char *buffer, int size)
 {
+	struct device *ddev = &dev->dev;
 	unsigned char *buffer0 = buffer;
 	int cfgno;
 	int nintf, nintf_orig;
@@ -549,6 +477,16 @@
 			}
 
 			inum = d->bInterfaceNumber;
+
+			if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) &&
+			    n >= nintf_orig) {
+				dev_warn(ddev, "config %d has more interface "
+				    "descriptors, than it declares in "
+				    "bNumInterfaces, ignoring interface "
+				    "number: %d\n", cfgno, inum);
+				continue;
+			}
+
 			if (inum >= nintf_orig)
 				dev_warn(ddev, "config %d has an invalid "
 				    "interface number: %d but max is %d\n",
@@ -722,7 +660,6 @@
 	int ncfg = dev->descriptor.bNumConfigurations;
 	int result = 0;
 	unsigned int cfgno, length;
-	unsigned char *buffer;
 	unsigned char *bigbuffer;
 	struct usb_config_descriptor *desc;
 
@@ -751,17 +688,16 @@
 	if (!dev->rawdescriptors)
 		goto err2;
 
-	buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
-	if (!buffer)
+	desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
+	if (!desc)
 		goto err2;
-	desc = (struct usb_config_descriptor *)buffer;
 
 	result = 0;
 	for (; cfgno < ncfg; cfgno++) {
 		/* We grab just the first descriptor so we know how long
 		 * the whole configuration is */
 		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
-		    buffer, USB_DT_CONFIG_SIZE);
+		    desc, USB_DT_CONFIG_SIZE);
 		if (result < 0) {
 			dev_err(ddev, "unable to read config index %d "
 			    "descriptor/%s: %d\n", cfgno, "start", result);
@@ -800,7 +736,7 @@
 
 		dev->rawdescriptors[cfgno] = bigbuffer;
 
-		result = usb_parse_configuration(&dev->dev, cfgno,
+		result = usb_parse_configuration(dev, cfgno,
 		    &dev->config[cfgno], bigbuffer, length);
 		if (result < 0) {
 			++cfgno;
@@ -810,7 +746,7 @@
 	result = 0;
 
 err:
-	kfree(buffer);
+	kfree(desc);
 out_not_authorized:
 	dev->descriptor.bNumConfigurations = cfgno;
 err2:
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 19bc03a..3449742 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -1,7 +1,8 @@
 /*
  * devices.c
  * (C) Copyright 1999 Randy Dunlap.
- * (C) Copyright 1999,2000 Thomas Sailer <sailer@ife.ee.ethz.ch>. (proc file per device)
+ * (C) Copyright 1999,2000 Thomas Sailer <sailer@ife.ee.ethz.ch>.
+ *     (proc file per device)
  * (C) Copyright 1999 Deti Fliegl (new USB architecture)
  *
  * This program is free software; you can redistribute it and/or modify
@@ -55,11 +56,11 @@
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/usb/hcd.h>
 #include <linux/mutex.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include "usb.h"
-#include "hcd.h"
 
 /* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
 #define ALLOW_SERIAL_NUMBER
@@ -138,8 +139,8 @@
 	char *class_name;
 };
 
-static const struct class_info clas_info[] =
-{					/* max. 5 chars. per name string */
+static const struct class_info clas_info[] = {
+	/* max. 5 chars. per name string */
 	{USB_CLASS_PER_INTERFACE,	">ifc"},
 	{USB_CLASS_AUDIO,		"audio"},
 	{USB_CLASS_COMM,		"comm."},
@@ -191,8 +192,10 @@
 
 	if (speed == USB_SPEED_HIGH) {
 		switch (le16_to_cpu(desc->wMaxPacketSize) & (0x03 << 11)) {
-		case 1 << 11:	bandwidth = 2; break;
-		case 2 << 11:	bandwidth = 3; break;
+		case 1 << 11:
+			bandwidth = 2; break;
+		case 2 << 11:
+			bandwidth = 3; break;
 		}
 	}
 
@@ -200,7 +203,7 @@
 	switch (usb_endpoint_type(desc)) {
 	case USB_ENDPOINT_XFER_CONTROL:
 		type = "Ctrl";
-		if (speed == USB_SPEED_HIGH) 	/* uframes per NAK */
+		if (speed == USB_SPEED_HIGH)	/* uframes per NAK */
 			interval = desc->bInterval;
 		else
 			interval = 0;
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 3466fdc..c2f62a3 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -43,6 +43,7 @@
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/usb/hcd.h>	/* for usbcore internals */
 #include <linux/cdev.h>
 #include <linux/notifier.h>
 #include <linux/security.h>
@@ -50,9 +51,7 @@
 #include <asm/byteorder.h>
 #include <linux/moduleparam.h>
 
-#include "hcd.h"	/* for usbcore internals */
 #include "usb.h"
-#include "hub.h"
 
 #define USB_MAXBUS			64
 #define USB_DEVICE_MAX			USB_MAXBUS * 128
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 2f3dc4c..ded550e 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -26,8 +26,9 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/usb/quirks.h>
+#include <linux/usb/hcd.h>
 #include <linux/pm_runtime.h>
-#include "hcd.h"
+
 #include "usb.h"
 
 
@@ -333,7 +334,8 @@
 	usb_cancel_queued_reset(intf);
 
 	/* Unbound interfaces are always runtime-PM-disabled and -suspended */
-	pm_runtime_disable(dev);
+	if (driver->supports_autosuspend)
+		pm_runtime_disable(dev);
 	pm_runtime_set_suspended(dev);
 
 	usb_autosuspend_device(udev);
@@ -388,7 +390,8 @@
 	intf->needs_remote_wakeup = 0;
 
 	/* Unbound interfaces are always runtime-PM-disabled and -suspended */
-	pm_runtime_disable(dev);
+	if (driver->supports_autosuspend)
+		pm_runtime_disable(dev);
 	pm_runtime_set_suspended(dev);
 
 	/* Undo any residual pm_autopm_get_interface_* calls */
@@ -437,14 +440,17 @@
 
 	iface->condition = USB_INTERFACE_BOUND;
 
-	/* Claimed interfaces are initially inactive (suspended).  They are
-	 * runtime-PM-enabled only if the driver has autosuspend support.
-	 * They are sensitive to their children's power states.
+	/* Claimed interfaces are initially inactive (suspended) and
+	 * runtime-PM-enabled, but only if the driver has autosuspend
+	 * support.  Otherwise they are marked active, to prevent the
+	 * device from being autosuspended, but left disabled.  In either
+	 * case they are sensitive to their children's power states.
 	 */
-	pm_runtime_set_suspended(dev);
 	pm_suspend_ignore_children(dev, false);
 	if (driver->supports_autosuspend)
 		pm_runtime_enable(dev);
+	else
+		pm_runtime_set_active(dev);
 
 	/* if interface was already added, bind now; else let
 	 * the future device_add() bind it, bypassing probe()
@@ -1355,13 +1361,9 @@
  *
  * The caller must hold @udev's device lock.
  */
-int usb_enable_autosuspend(struct usb_device *udev)
+void usb_enable_autosuspend(struct usb_device *udev)
 {
-	if (udev->autosuspend_disabled) {
-		udev->autosuspend_disabled = 0;
-		usb_autosuspend_device(udev);
-	}
-	return 0;
+	pm_runtime_allow(&udev->dev);
 }
 EXPORT_SYMBOL_GPL(usb_enable_autosuspend);
 
@@ -1374,16 +1376,9 @@
  *
  * The caller must hold @udev's device lock.
  */
-int usb_disable_autosuspend(struct usb_device *udev)
+void usb_disable_autosuspend(struct usb_device *udev)
 {
-	int rc = 0;
-
-	if (!udev->autosuspend_disabled) {
-		rc = usb_autoresume_device(udev);
-		if (rc == 0)
-			udev->autosuspend_disabled = 1;
-	}
-	return rc;
+	pm_runtime_forbid(&udev->dev);
 }
 EXPORT_SYMBOL_GPL(usb_disable_autosuspend);
 
@@ -1485,9 +1480,6 @@
  * 0, a delayed autosuspend request for @intf's device is attempted.  The
  * attempt may fail (see autosuspend_check()).
  *
- * If the driver has set @intf->needs_remote_wakeup then autosuspend will
- * take place only if the device's remote-wakeup facility is enabled.
- *
  * This routine can run only in process context.
  */
 void usb_autopm_put_interface(struct usb_interface *intf)
@@ -1530,7 +1522,7 @@
 	atomic_dec(&intf->pm_usage_cnt);
 	pm_runtime_put_noidle(&intf->dev);
 
-	if (!udev->autosuspend_disabled) {
+	if (udev->dev.power.runtime_auto) {
 		/* Optimization: Don't schedule a delayed autosuspend if
 		 * the timer is already running and the expiration time
 		 * wouldn't change.
@@ -1672,14 +1664,14 @@
 /* Internal routine to check whether we may autosuspend a device. */
 static int autosuspend_check(struct usb_device *udev)
 {
-	int			i;
+	int			w, i;
 	struct usb_interface	*intf;
 	unsigned long		suspend_time, j;
 
 	/* Fail if autosuspend is disabled, or any interfaces are in use, or
 	 * any interface drivers require remote wakeup but it isn't available.
 	 */
-	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+	w = 0;
 	if (udev->actconfig) {
 		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
 			intf = udev->actconfig->interface[i];
@@ -1693,12 +1685,7 @@
 				continue;
 			if (atomic_read(&intf->dev.power.usage_count) > 0)
 				return -EBUSY;
-			if (intf->needs_remote_wakeup &&
-					!udev->do_remote_wakeup) {
-				dev_dbg(&udev->dev, "remote wakeup needed "
-						"for autosuspend\n");
-				return -EOPNOTSUPP;
-			}
+			w |= intf->needs_remote_wakeup;
 
 			/* Don't allow autosuspend if the device will need
 			 * a reset-resume and any of its interface drivers
@@ -1714,6 +1701,11 @@
 			}
 		}
 	}
+	if (w && !device_can_wakeup(&udev->dev)) {
+		dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n");
+		return -EOPNOTSUPP;
+	}
+	udev->do_remote_wakeup = w;
 
 	/* If everything is okay but the device hasn't been idle for long
 	 * enough, queue a delayed autosuspend request.
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 2c95153..9a34ccb 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -18,8 +18,8 @@
  */
 
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include "usb.h"
-#include "hcd.h"
 
 static inline const char *plural(int n)
 {
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 1528653..1cf2d1e 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -21,6 +21,7 @@
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -33,7 +34,6 @@
 #endif
 
 #include "usb.h"
-#include "hcd.h"
 
 
 /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 2f8cedd..12742f1 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -38,14 +38,12 @@
 #include <asm/unaligned.h>
 #include <linux/platform_device.h>
 #include <linux/workqueue.h>
-#include <linux/mutex.h>
 #include <linux/pm_runtime.h>
 
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 
 #include "usb.h"
-#include "hcd.h"
-#include "hub.h"
 
 
 /*-------------------------------------------------------------------------*/
@@ -1261,6 +1259,51 @@
 	*dma_handle = 0;
 }
 
+static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+	enum dma_data_direction dir;
+
+	if (urb->transfer_flags & URB_SETUP_MAP_SINGLE)
+		dma_unmap_single(hcd->self.controller,
+				urb->setup_dma,
+				sizeof(struct usb_ctrlrequest),
+				DMA_TO_DEVICE);
+	else if (urb->transfer_flags & URB_SETUP_MAP_LOCAL)
+		hcd_free_coherent(urb->dev->bus,
+				&urb->setup_dma,
+				(void **) &urb->setup_packet,
+				sizeof(struct usb_ctrlrequest),
+				DMA_TO_DEVICE);
+
+	dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+	if (urb->transfer_flags & URB_DMA_MAP_SG)
+		dma_unmap_sg(hcd->self.controller,
+				urb->sg,
+				urb->num_sgs,
+				dir);
+	else if (urb->transfer_flags & URB_DMA_MAP_PAGE)
+		dma_unmap_page(hcd->self.controller,
+				urb->transfer_dma,
+				urb->transfer_buffer_length,
+				dir);
+	else if (urb->transfer_flags & URB_DMA_MAP_SINGLE)
+		dma_unmap_single(hcd->self.controller,
+				urb->transfer_dma,
+				urb->transfer_buffer_length,
+				dir);
+	else if (urb->transfer_flags & URB_MAP_LOCAL)
+		hcd_free_coherent(urb->dev->bus,
+				&urb->transfer_dma,
+				&urb->transfer_buffer,
+				urb->transfer_buffer_length,
+				dir);
+
+	/* Make it safe to call this routine more than once */
+	urb->transfer_flags &= ~(URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
+			URB_DMA_MAP_SG | URB_DMA_MAP_PAGE |
+			URB_DMA_MAP_SINGLE | URB_MAP_LOCAL);
+}
+
 static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
 			   gfp_t mem_flags)
 {
@@ -1272,11 +1315,8 @@
 	 * unless it uses pio or talks to another transport,
 	 * or uses the provided scatter gather list for bulk.
 	 */
-	if (is_root_hub(urb->dev))
-		return 0;
 
-	if (usb_endpoint_xfer_control(&urb->ep->desc)
-	    && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
+	if (usb_endpoint_xfer_control(&urb->ep->desc)) {
 		if (hcd->self.uses_dma) {
 			urb->setup_dma = dma_map_single(
 					hcd->self.controller,
@@ -1286,27 +1326,64 @@
 			if (dma_mapping_error(hcd->self.controller,
 						urb->setup_dma))
 				return -EAGAIN;
-		} else if (hcd->driver->flags & HCD_LOCAL_MEM)
+			urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
+		} else if (hcd->driver->flags & HCD_LOCAL_MEM) {
 			ret = hcd_alloc_coherent(
 					urb->dev->bus, mem_flags,
 					&urb->setup_dma,
 					(void **)&urb->setup_packet,
 					sizeof(struct usb_ctrlrequest),
 					DMA_TO_DEVICE);
+			if (ret)
+				return ret;
+			urb->transfer_flags |= URB_SETUP_MAP_LOCAL;
+		}
 	}
 
 	dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-	if (ret == 0 && urb->transfer_buffer_length != 0
+	if (urb->transfer_buffer_length != 0
 	    && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
 		if (hcd->self.uses_dma) {
-			urb->transfer_dma = dma_map_single (
-					hcd->self.controller,
-					urb->transfer_buffer,
-					urb->transfer_buffer_length,
-					dir);
-			if (dma_mapping_error(hcd->self.controller,
+			if (urb->num_sgs) {
+				int n = dma_map_sg(
+						hcd->self.controller,
+						urb->sg,
+						urb->num_sgs,
+						dir);
+				if (n <= 0)
+					ret = -EAGAIN;
+				else
+					urb->transfer_flags |= URB_DMA_MAP_SG;
+				if (n != urb->num_sgs) {
+					urb->num_sgs = n;
+					urb->transfer_flags |=
+							URB_DMA_SG_COMBINED;
+				}
+			} else if (urb->sg) {
+				struct scatterlist *sg = urb->sg;
+				urb->transfer_dma = dma_map_page(
+						hcd->self.controller,
+						sg_page(sg),
+						sg->offset,
+						urb->transfer_buffer_length,
+						dir);
+				if (dma_mapping_error(hcd->self.controller,
 						urb->transfer_dma))
-				return -EAGAIN;
+					ret = -EAGAIN;
+				else
+					urb->transfer_flags |= URB_DMA_MAP_PAGE;
+			} else {
+				urb->transfer_dma = dma_map_single(
+						hcd->self.controller,
+						urb->transfer_buffer,
+						urb->transfer_buffer_length,
+						dir);
+				if (dma_mapping_error(hcd->self.controller,
+						urb->transfer_dma))
+					ret = -EAGAIN;
+				else
+					urb->transfer_flags |= URB_DMA_MAP_SINGLE;
+			}
 		} else if (hcd->driver->flags & HCD_LOCAL_MEM) {
 			ret = hcd_alloc_coherent(
 					urb->dev->bus, mem_flags,
@@ -1314,55 +1391,16 @@
 					&urb->transfer_buffer,
 					urb->transfer_buffer_length,
 					dir);
-
-			if (ret && usb_endpoint_xfer_control(&urb->ep->desc)
-			    && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
-				hcd_free_coherent(urb->dev->bus,
-					&urb->setup_dma,
-					(void **)&urb->setup_packet,
-					sizeof(struct usb_ctrlrequest),
-					DMA_TO_DEVICE);
+			if (ret == 0)
+				urb->transfer_flags |= URB_MAP_LOCAL;
 		}
+		if (ret && (urb->transfer_flags & (URB_SETUP_MAP_SINGLE |
+				URB_SETUP_MAP_LOCAL)))
+			unmap_urb_for_dma(hcd, urb);
 	}
 	return ret;
 }
 
-static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
-{
-	enum dma_data_direction dir;
-
-	if (is_root_hub(urb->dev))
-		return;
-
-	if (usb_endpoint_xfer_control(&urb->ep->desc)
-	    && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
-		if (hcd->self.uses_dma)
-			dma_unmap_single(hcd->self.controller, urb->setup_dma,
-					sizeof(struct usb_ctrlrequest),
-					DMA_TO_DEVICE);
-		else if (hcd->driver->flags & HCD_LOCAL_MEM)
-			hcd_free_coherent(urb->dev->bus, &urb->setup_dma,
-					(void **)&urb->setup_packet,
-					sizeof(struct usb_ctrlrequest),
-					DMA_TO_DEVICE);
-	}
-
-	dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-	if (urb->transfer_buffer_length != 0
-	    && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
-		if (hcd->self.uses_dma)
-			dma_unmap_single(hcd->self.controller,
-					urb->transfer_dma,
-					urb->transfer_buffer_length,
-					dir);
-		else if (hcd->driver->flags & HCD_LOCAL_MEM)
-			hcd_free_coherent(urb->dev->bus, &urb->transfer_dma,
-					&urb->transfer_buffer,
-					urb->transfer_buffer_length,
-					dir);
-	}
-}
-
 /*-------------------------------------------------------------------------*/
 
 /* may be called in any context with a valid urb->dev usecount
@@ -1391,21 +1429,20 @@
 	 * URBs must be submitted in process context with interrupts
 	 * enabled.
 	 */
-	status = map_urb_for_dma(hcd, urb, mem_flags);
-	if (unlikely(status)) {
-		usbmon_urb_submit_error(&hcd->self, urb, status);
-		goto error;
+
+	if (is_root_hub(urb->dev)) {
+		status = rh_urb_enqueue(hcd, urb);
+	} else {
+		status = map_urb_for_dma(hcd, urb, mem_flags);
+		if (likely(status == 0)) {
+			status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
+			if (unlikely(status))
+				unmap_urb_for_dma(hcd, urb);
+		}
 	}
 
-	if (is_root_hub(urb->dev))
-		status = rh_urb_enqueue(hcd, urb);
-	else
-		status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
-
 	if (unlikely(status)) {
 		usbmon_urb_submit_error(&hcd->self, urb, status);
-		unmap_urb_for_dma(hcd, urb);
- error:
 		urb->hcpriv = NULL;
 		INIT_LIST_HEAD(&urb->urb_list);
 		atomic_dec(&urb->use_count);
@@ -1775,6 +1812,75 @@
 	}
 }
 
+/**
+ * usb_alloc_streams - allocate bulk endpoint stream IDs.
+ * @interface:		alternate setting that includes all endpoints.
+ * @eps:		array of endpoints that need streams.
+ * @num_eps:		number of endpoints in the array.
+ * @num_streams:	number of streams to allocate.
+ * @mem_flags:		flags hcd should use to allocate memory.
+ *
+ * Sets up a group of bulk endpoints to have num_streams stream IDs available.
+ * Drivers may queue multiple transfers to different stream IDs, which may
+ * complete in a different order than they were queued.
+ */
+int usb_alloc_streams(struct usb_interface *interface,
+		struct usb_host_endpoint **eps, unsigned int num_eps,
+		unsigned int num_streams, gfp_t mem_flags)
+{
+	struct usb_hcd *hcd;
+	struct usb_device *dev;
+	int i;
+
+	dev = interface_to_usbdev(interface);
+	hcd = bus_to_hcd(dev->bus);
+	if (!hcd->driver->alloc_streams || !hcd->driver->free_streams)
+		return -EINVAL;
+	if (dev->speed != USB_SPEED_SUPER)
+		return -EINVAL;
+
+	/* Streams only apply to bulk endpoints. */
+	for (i = 0; i < num_eps; i++)
+		if (!usb_endpoint_xfer_bulk(&eps[i]->desc))
+			return -EINVAL;
+
+	return hcd->driver->alloc_streams(hcd, dev, eps, num_eps,
+			num_streams, mem_flags);
+}
+EXPORT_SYMBOL_GPL(usb_alloc_streams);
+
+/**
+ * usb_free_streams - free bulk endpoint stream IDs.
+ * @interface:	alternate setting that includes all endpoints.
+ * @eps:	array of endpoints to remove streams from.
+ * @num_eps:	number of endpoints in the array.
+ * @mem_flags:	flags hcd should use to allocate memory.
+ *
+ * Reverts a group of bulk endpoints back to not using stream IDs.
+ * Can fail if we are given bad arguments, or HCD is broken.
+ */
+void usb_free_streams(struct usb_interface *interface,
+		struct usb_host_endpoint **eps, unsigned int num_eps,
+		gfp_t mem_flags)
+{
+	struct usb_hcd *hcd;
+	struct usb_device *dev;
+	int i;
+
+	dev = interface_to_usbdev(interface);
+	hcd = bus_to_hcd(dev->bus);
+	if (dev->speed != USB_SPEED_SUPER)
+		return;
+
+	/* Streams only apply to bulk endpoints. */
+	for (i = 0; i < num_eps; i++)
+		if (!usb_endpoint_xfer_bulk(&eps[i]->desc))
+			return;
+
+	hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags);
+}
+EXPORT_SYMBOL_GPL(usb_free_streams);
+
 /* Protect against drivers that try to unlink URBs after the device
  * is gone, by waiting until all unlinks for @udev are finished.
  * Since we don't currently track URBs by device, simply wait until
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
deleted file mode 100644
index a3cdb09..0000000
--- a/drivers/usb/core/hcd.h
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- * Copyright (c) 2001-2002 by David Brownell
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __USB_CORE_HCD_H
-#define __USB_CORE_HCD_H
-
-#ifdef __KERNEL__
-
-#include <linux/rwsem.h>
-
-#define MAX_TOPO_LEVEL		6
-
-/* This file contains declarations of usbcore internals that are mostly
- * used or exposed by Host Controller Drivers.
- */
-
-/*
- * USB Packet IDs (PIDs)
- */
-#define USB_PID_EXT			0xf0	/* USB 2.0 LPM ECN */
-#define USB_PID_OUT			0xe1
-#define USB_PID_ACK			0xd2
-#define USB_PID_DATA0			0xc3
-#define USB_PID_PING			0xb4	/* USB 2.0 */
-#define USB_PID_SOF			0xa5
-#define USB_PID_NYET			0x96	/* USB 2.0 */
-#define USB_PID_DATA2			0x87	/* USB 2.0 */
-#define USB_PID_SPLIT			0x78	/* USB 2.0 */
-#define USB_PID_IN			0x69
-#define USB_PID_NAK			0x5a
-#define USB_PID_DATA1			0x4b
-#define USB_PID_PREAMBLE		0x3c	/* Token mode */
-#define USB_PID_ERR			0x3c	/* USB 2.0: handshake mode */
-#define USB_PID_SETUP			0x2d
-#define USB_PID_STALL			0x1e
-#define USB_PID_MDATA			0x0f	/* USB 2.0 */
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * USB Host Controller Driver (usb_hcd) framework
- *
- * Since "struct usb_bus" is so thin, you can't share much code in it.
- * This framework is a layer over that, and should be more sharable.
- *
- * @authorized_default: Specifies if new devices are authorized to
- *                      connect by default or they require explicit
- *                      user space authorization; this bit is settable
- *                      through /sys/class/usb_host/X/authorized_default.
- *                      For the rest is RO, so we don't lock to r/w it.
- */
-
-/*-------------------------------------------------------------------------*/
-
-struct usb_hcd {
-
-	/*
-	 * housekeeping
-	 */
-	struct usb_bus		self;		/* hcd is-a bus */
-	struct kref		kref;		/* reference counter */
-
-	const char		*product_desc;	/* product/vendor string */
-	char			irq_descr[24];	/* driver + bus # */
-
-	struct timer_list	rh_timer;	/* drives root-hub polling */
-	struct urb		*status_urb;	/* the current status urb */
-#ifdef CONFIG_USB_SUSPEND
-	struct work_struct	wakeup_work;	/* for remote wakeup */
-#endif
-
-	/*
-	 * hardware info/state
-	 */
-	const struct hc_driver	*driver;	/* hw-specific hooks */
-
-	/* Flags that need to be manipulated atomically */
-	unsigned long		flags;
-#define HCD_FLAG_HW_ACCESSIBLE	0x00000001
-#define HCD_FLAG_SAW_IRQ	0x00000002
-
-	unsigned		rh_registered:1;/* is root hub registered? */
-
-	/* The next flag is a stopgap, to be removed when all the HCDs
-	 * support the new root-hub polling mechanism. */
-	unsigned		uses_new_polling:1;
-	unsigned		poll_rh:1;	/* poll for rh status? */
-	unsigned		poll_pending:1;	/* status has changed? */
-	unsigned		wireless:1;	/* Wireless USB HCD */
-	unsigned		authorized_default:1;
-	unsigned		has_tt:1;	/* Integrated TT in root hub */
-
-	int			irq;		/* irq allocated */
-	void __iomem		*regs;		/* device memory/io */
-	u64			rsrc_start;	/* memory/io resource start */
-	u64			rsrc_len;	/* memory/io resource length */
-	unsigned		power_budget;	/* in mA, 0 = no limit */
-
-	/* bandwidth_mutex should be taken before adding or removing
-	 * any new bus bandwidth constraints:
-	 *   1. Before adding a configuration for a new device.
-	 *   2. Before removing the configuration to put the device into
-	 *      the addressed state.
-	 *   3. Before selecting a different configuration.
-	 *   4. Before selecting an alternate interface setting.
-	 *
-	 * bandwidth_mutex should be dropped after a successful control message
-	 * to the device, or resetting the bandwidth after a failed attempt.
-	 */
-	struct mutex		bandwidth_mutex;
-
-
-#define HCD_BUFFER_POOLS	4
-	struct dma_pool		*pool [HCD_BUFFER_POOLS];
-
-	int			state;
-#	define	__ACTIVE		0x01
-#	define	__SUSPEND		0x04
-#	define	__TRANSIENT		0x80
-
-#	define	HC_STATE_HALT		0
-#	define	HC_STATE_RUNNING	(__ACTIVE)
-#	define	HC_STATE_QUIESCING	(__SUSPEND|__TRANSIENT|__ACTIVE)
-#	define	HC_STATE_RESUMING	(__SUSPEND|__TRANSIENT)
-#	define	HC_STATE_SUSPENDED	(__SUSPEND)
-
-#define	HC_IS_RUNNING(state) ((state) & __ACTIVE)
-#define	HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
-
-	/* more shared queuing code would be good; it should support
-	 * smarter scheduling, handle transaction translators, etc;
-	 * input size of periodic table to an interrupt scheduler.
-	 * (ohci 32, uhci 1024, ehci 256/512/1024).
-	 */
-
-	/* The HC driver's private data is stored at the end of
-	 * this structure.
-	 */
-	unsigned long hcd_priv[0]
-			__attribute__ ((aligned(sizeof(unsigned long))));
-};
-
-/* 2.4 does this a bit differently ... */
-static inline struct usb_bus *hcd_to_bus(struct usb_hcd *hcd)
-{
-	return &hcd->self;
-}
-
-static inline struct usb_hcd *bus_to_hcd(struct usb_bus *bus)
-{
-	return container_of(bus, struct usb_hcd, self);
-}
-
-struct hcd_timeout {	/* timeouts we allocate */
-	struct list_head	timeout_list;
-	struct timer_list	timer;
-};
-
-/*-------------------------------------------------------------------------*/
-
-
-struct hc_driver {
-	const char	*description;	/* "ehci-hcd" etc */
-	const char	*product_desc;	/* product/vendor string */
-	size_t		hcd_priv_size;	/* size of private data */
-
-	/* irq handler */
-	irqreturn_t	(*irq) (struct usb_hcd *hcd);
-
-	int	flags;
-#define	HCD_MEMORY	0x0001		/* HC regs use memory (else I/O) */
-#define	HCD_LOCAL_MEM	0x0002		/* HC needs local memory */
-#define	HCD_USB11	0x0010		/* USB 1.1 */
-#define	HCD_USB2	0x0020		/* USB 2.0 */
-#define	HCD_USB3	0x0040		/* USB 3.0 */
-#define	HCD_MASK	0x0070
-
-	/* called to init HCD and root hub */
-	int	(*reset) (struct usb_hcd *hcd);
-	int	(*start) (struct usb_hcd *hcd);
-
-	/* NOTE:  these suspend/resume calls relate to the HC as
-	 * a whole, not just the root hub; they're for PCI bus glue.
-	 */
-	/* called after suspending the hub, before entering D3 etc */
-	int	(*pci_suspend)(struct usb_hcd *hcd);
-
-	/* called after entering D0 (etc), before resuming the hub */
-	int	(*pci_resume)(struct usb_hcd *hcd, bool hibernated);
-
-	/* cleanly make HCD stop writing memory and doing I/O */
-	void	(*stop) (struct usb_hcd *hcd);
-
-	/* shutdown HCD */
-	void	(*shutdown) (struct usb_hcd *hcd);
-
-	/* return current frame number */
-	int	(*get_frame_number) (struct usb_hcd *hcd);
-
-	/* manage i/o requests, device state */
-	int	(*urb_enqueue)(struct usb_hcd *hcd,
-				struct urb *urb, gfp_t mem_flags);
-	int	(*urb_dequeue)(struct usb_hcd *hcd,
-				struct urb *urb, int status);
-
-	/* hw synch, freeing endpoint resources that urb_dequeue can't */
-	void 	(*endpoint_disable)(struct usb_hcd *hcd,
-			struct usb_host_endpoint *ep);
-
-	/* (optional) reset any endpoint state such as sequence number
-	   and current window */
-	void 	(*endpoint_reset)(struct usb_hcd *hcd,
-			struct usb_host_endpoint *ep);
-
-	/* root hub support */
-	int	(*hub_status_data) (struct usb_hcd *hcd, char *buf);
-	int	(*hub_control) (struct usb_hcd *hcd,
-				u16 typeReq, u16 wValue, u16 wIndex,
-				char *buf, u16 wLength);
-	int	(*bus_suspend)(struct usb_hcd *);
-	int	(*bus_resume)(struct usb_hcd *);
-	int	(*start_port_reset)(struct usb_hcd *, unsigned port_num);
-
-		/* force handover of high-speed port to full-speed companion */
-	void	(*relinquish_port)(struct usb_hcd *, int);
-		/* has a port been handed over to a companion? */
-	int	(*port_handed_over)(struct usb_hcd *, int);
-
-		/* CLEAR_TT_BUFFER completion callback */
-	void	(*clear_tt_buffer_complete)(struct usb_hcd *,
-				struct usb_host_endpoint *);
-
-	/* xHCI specific functions */
-		/* Called by usb_alloc_dev to alloc HC device structures */
-	int	(*alloc_dev)(struct usb_hcd *, struct usb_device *);
-		/* Called by usb_disconnect to free HC device structures */
-	void	(*free_dev)(struct usb_hcd *, struct usb_device *);
-
-	/* Bandwidth computation functions */
-	/* Note that add_endpoint() can only be called once per endpoint before
-	 * check_bandwidth() or reset_bandwidth() must be called.
-	 * drop_endpoint() can only be called once per endpoint also.
-	 * A call to xhci_drop_endpoint() followed by a call to xhci_add_endpoint() will
-	 * add the endpoint to the schedule with possibly new parameters denoted by a
-	 * different endpoint descriptor in usb_host_endpoint.
-	 * A call to xhci_add_endpoint() followed by a call to xhci_drop_endpoint() is
-	 * not allowed.
-	 */
-		/* Allocate endpoint resources and add them to a new schedule */
-	int 	(*add_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);
-		/* Drop an endpoint from a new schedule */
-	int 	(*drop_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);
-		/* Check that a new hardware configuration, set using
-		 * endpoint_enable and endpoint_disable, does not exceed bus
-		 * bandwidth.  This must be called before any set configuration
-		 * or set interface requests are sent to the device.
-		 */
-	int	(*check_bandwidth)(struct usb_hcd *, struct usb_device *);
-		/* Reset the device schedule to the last known good schedule,
-		 * which was set from a previous successful call to
-		 * check_bandwidth().  This reverts any add_endpoint() and
-		 * drop_endpoint() calls since that last successful call.
-		 * Used for when a check_bandwidth() call fails due to resource
-		 * or bandwidth constraints.
-		 */
-	void	(*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
-		/* Returns the hardware-chosen device address */
-	int	(*address_device)(struct usb_hcd *, struct usb_device *udev);
-		/* Notifies the HCD after a hub descriptor is fetched.
-		 * Will block.
-		 */
-	int	(*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
-			struct usb_tt *tt, gfp_t mem_flags);
-	int	(*reset_device)(struct usb_hcd *, struct usb_device *);
-};
-
-extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
-extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
-		int status);
-extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
-
-extern int usb_hcd_submit_urb(struct urb *urb, gfp_t mem_flags);
-extern int usb_hcd_unlink_urb(struct urb *urb, int status);
-extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
-		int status);
-extern void usb_hcd_flush_endpoint(struct usb_device *udev,
-		struct usb_host_endpoint *ep);
-extern void usb_hcd_disable_endpoint(struct usb_device *udev,
-		struct usb_host_endpoint *ep);
-extern void usb_hcd_reset_endpoint(struct usb_device *udev,
-		struct usb_host_endpoint *ep);
-extern void usb_hcd_synchronize_unlinks(struct usb_device *udev);
-extern int usb_hcd_alloc_bandwidth(struct usb_device *udev,
-		struct usb_host_config *new_config,
-		struct usb_host_interface *old_alt,
-		struct usb_host_interface *new_alt);
-extern int usb_hcd_get_frame_number(struct usb_device *udev);
-
-extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
-		struct device *dev, const char *bus_name);
-extern struct usb_hcd *usb_get_hcd(struct usb_hcd *hcd);
-extern void usb_put_hcd(struct usb_hcd *hcd);
-extern int usb_add_hcd(struct usb_hcd *hcd,
-		unsigned int irqnum, unsigned long irqflags);
-extern void usb_remove_hcd(struct usb_hcd *hcd);
-
-struct platform_device;
-extern void usb_hcd_platform_shutdown(struct platform_device *dev);
-
-#ifdef CONFIG_PCI
-struct pci_dev;
-struct pci_device_id;
-extern int usb_hcd_pci_probe(struct pci_dev *dev,
-				const struct pci_device_id *id);
-extern void usb_hcd_pci_remove(struct pci_dev *dev);
-extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
-
-#ifdef CONFIG_PM_SLEEP
-extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
-#endif
-#endif /* CONFIG_PCI */
-
-/* pci-ish (pdev null is ok) buffer alloc/mapping support */
-int hcd_buffer_create(struct usb_hcd *hcd);
-void hcd_buffer_destroy(struct usb_hcd *hcd);
-
-void *hcd_buffer_alloc(struct usb_bus *bus, size_t size,
-	gfp_t mem_flags, dma_addr_t *dma);
-void hcd_buffer_free(struct usb_bus *bus, size_t size,
-	void *addr, dma_addr_t dma);
-
-/* generic bus glue, needed for host controllers that don't use PCI */
-extern irqreturn_t usb_hcd_irq(int irq, void *__hcd);
-
-extern void usb_hc_died(struct usb_hcd *hcd);
-extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
-
-/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
-#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
-#define	usb_dotoggle(dev, ep, out)  ((dev)->toggle[out] ^= (1 << (ep)))
-#define usb_settoggle(dev, ep, out, bit) \
-		((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | \
-		 ((bit) << (ep)))
-
-/* -------------------------------------------------------------------------- */
-
-/* Enumeration is only for the hub driver, or HCD virtual root hubs */
-extern struct usb_device *usb_alloc_dev(struct usb_device *parent,
-					struct usb_bus *, unsigned port);
-extern int usb_new_device(struct usb_device *dev);
-extern void usb_disconnect(struct usb_device **);
-
-extern int usb_get_configuration(struct usb_device *dev);
-extern void usb_destroy_configuration(struct usb_device *dev);
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * HCD Root Hub support
- */
-
-#include "hub.h"
-
-/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
-#define DeviceRequest \
-	((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
-#define DeviceOutRequest \
-	((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
-
-#define InterfaceRequest \
-	((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
-
-#define EndpointRequest \
-	((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
-#define EndpointOutRequest \
-	((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
-
-/* class requests from the USB 2.0 hub spec, table 11-15 */
-/* GetBusState and SetHubDescriptor are optional, omitted */
-#define ClearHubFeature		(0x2000 | USB_REQ_CLEAR_FEATURE)
-#define ClearPortFeature	(0x2300 | USB_REQ_CLEAR_FEATURE)
-#define GetHubDescriptor	(0xa000 | USB_REQ_GET_DESCRIPTOR)
-#define GetHubStatus		(0xa000 | USB_REQ_GET_STATUS)
-#define GetPortStatus		(0xa300 | USB_REQ_GET_STATUS)
-#define SetHubFeature		(0x2000 | USB_REQ_SET_FEATURE)
-#define SetPortFeature		(0x2300 | USB_REQ_SET_FEATURE)
-
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * Generic bandwidth allocation constants/support
- */
-#define FRAME_TIME_USECS	1000L
-#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */
-		/* Trying not to use worst-case bit-stuffing
-		 * of (7/6 * 8 * bytecount) = 9.33 * bytecount */
-		/* bytecount = data payload byte count */
-
-#define NS_TO_US(ns)	((ns + 500L) / 1000L)
-			/* convert & round nanoseconds to microseconds */
-
-
-/*
- * Full/low speed bandwidth allocation constants/support.
- */
-#define BW_HOST_DELAY	1000L		/* nanoseconds */
-#define BW_HUB_LS_SETUP	333L		/* nanoseconds */
-			/* 4 full-speed bit times (est.) */
-
-#define FRAME_TIME_BITS			12000L	/* frame = 1 millisecond */
-#define FRAME_TIME_MAX_BITS_ALLOC	(90L * FRAME_TIME_BITS / 100L)
-#define FRAME_TIME_MAX_USECS_ALLOC	(90L * FRAME_TIME_USECS / 100L)
-
-/*
- * Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
- * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
- * to preallocate bandwidth)
- */
-#define USB2_HOST_DELAY	5	/* nsec, guess */
-#define HS_NSECS(bytes) (((55 * 8 * 2083) \
-	+ (2083UL * (3 + BitTime(bytes))))/1000 \
-	+ USB2_HOST_DELAY)
-#define HS_NSECS_ISO(bytes) (((38 * 8 * 2083) \
-	+ (2083UL * (3 + BitTime(bytes))))/1000 \
-	+ USB2_HOST_DELAY)
-#define HS_USECS(bytes) NS_TO_US (HS_NSECS(bytes))
-#define HS_USECS_ISO(bytes) NS_TO_US (HS_NSECS_ISO(bytes))
-
-extern long usb_calc_bus_time(int speed, int is_input,
-			int isoc, int bytecount);
-
-/*-------------------------------------------------------------------------*/
-
-extern void usb_set_device_state(struct usb_device *udev,
-		enum usb_device_state new_state);
-
-/*-------------------------------------------------------------------------*/
-
-/* exported only within usbcore */
-
-extern struct list_head usb_bus_list;
-extern struct mutex usb_bus_list_lock;
-extern wait_queue_head_t usb_kill_urb_queue;
-
-extern int usb_find_interface_driver(struct usb_device *dev,
-	struct usb_interface *interface);
-
-#define usb_endpoint_out(ep_dir)	(!((ep_dir) & USB_DIR_IN))
-
-#ifdef CONFIG_PM
-extern void usb_root_hub_lost_power(struct usb_device *rhdev);
-extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
-extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg);
-#endif /* CONFIG_PM */
-
-#ifdef CONFIG_USB_SUSPEND
-extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
-#else
-static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
-{
-	return;
-}
-#endif /* CONFIG_USB_SUSPEND */
-
-
-/*
- * USB device fs stuff
- */
-
-#ifdef CONFIG_USB_DEVICEFS
-
-/*
- * these are expected to be called from the USB core/hub thread
- * with the kernel lock held
- */
-extern void usbfs_update_special(void);
-extern int usbfs_init(void);
-extern void usbfs_cleanup(void);
-
-#else /* CONFIG_USB_DEVICEFS */
-
-static inline void usbfs_update_special(void) {}
-static inline int usbfs_init(void) { return 0; }
-static inline void usbfs_cleanup(void) { }
-
-#endif /* CONFIG_USB_DEVICEFS */
-
-/*-------------------------------------------------------------------------*/
-
-#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
-
-struct usb_mon_operations {
-	void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
-	void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
-	void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status);
-	/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
-};
-
-extern struct usb_mon_operations *mon_ops;
-
-static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb)
-{
-	if (bus->monitored)
-		(*mon_ops->urb_submit)(bus, urb);
-}
-
-static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
-    int error)
-{
-	if (bus->monitored)
-		(*mon_ops->urb_submit_error)(bus, urb, error);
-}
-
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
-		int status)
-{
-	if (bus->monitored)
-		(*mon_ops->urb_complete)(bus, urb, status);
-}
-
-int usb_mon_register(struct usb_mon_operations *ops);
-void usb_mon_deregister(void);
-
-#else
-
-static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
-static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
-    int error) {}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
-		int status) {}
-
-#endif /* CONFIG_USB_MON || CONFIG_USB_MON_MODULE */
-
-/*-------------------------------------------------------------------------*/
-
-/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
-/* bleech -- resurfaced in 2.4.11 or 2.4.12 */
-#define bitmap 	DeviceRemovable
-
-
-/*-------------------------------------------------------------------------*/
-
-/* random stuff */
-
-#define	RUN_CONTEXT (in_irq() ? "in_irq" \
-		: (in_interrupt() ? "in_interrupt" : "can sleep"))
-
-
-/* This rwsem is for use only by the hub driver and ehci-hcd.
- * Nobody else should touch it.
- */
-extern struct rw_semaphore ehci_cf_port_reset_rwsem;
-
-/* Keep track of which host controller drivers are loaded */
-#define USB_UHCI_LOADED		0
-#define USB_OHCI_LOADED		1
-#define USB_EHCI_LOADED		2
-extern unsigned long usb_hcds_loaded;
-
-#endif /* __KERNEL__ */
-
-#endif /* __USB_CORE_HCD_H */
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 0940ccd..83e7bbb 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -19,6 +19,7 @@
 #include <linux/ioctl.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/usb/hcd.h>
 #include <linux/kthread.h>
 #include <linux/mutex.h>
 #include <linux/freezer.h>
@@ -28,8 +29,6 @@
 #include <asm/byteorder.h>
 
 #include "usb.h"
-#include "hcd.h"
-#include "hub.h"
 
 /* if we are in debug mode, always announce new devices */
 #ifdef DEBUG
@@ -154,11 +153,11 @@
 
 static inline char *portspeed(int portstatus)
 {
-	if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))
+	if (portstatus & USB_PORT_STAT_HIGH_SPEED)
     		return "480 Mb/s";
-	else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))
+	else if (portstatus & USB_PORT_STAT_LOW_SPEED)
 		return "1.5 Mb/s";
-	else if (portstatus & (1 << USB_PORT_FEAT_SUPERSPEED))
+	else if (portstatus & USB_PORT_STAT_SUPER_SPEED)
 		return "5.0 Gb/s";
 	else
 		return "12 Mb/s";
@@ -745,8 +744,20 @@
 				!(portstatus & USB_PORT_STAT_CONNECTION) ||
 				!udev ||
 				udev->state == USB_STATE_NOTATTACHED)) {
-			clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
-			portstatus &= ~USB_PORT_STAT_ENABLE;
+			/*
+			 * USB3 protocol ports will automatically transition
+			 * to Enabled state when detect an USB3.0 device attach.
+			 * Do not disable USB3 protocol ports.
+			 * FIXME: USB3 root hub and external hubs are treated
+			 * differently here.
+			 */
+			if (hdev->descriptor.bDeviceProtocol != 3 ||
+			    (!hdev->parent &&
+			     !(portstatus & USB_PORT_STAT_SUPER_SPEED))) {
+				clear_port_feature(hdev, port1,
+						   USB_PORT_FEAT_ENABLE);
+				portstatus &= ~USB_PORT_STAT_ENABLE;
+			}
 		}
 
 		/* Clear status-change flags; we'll debounce later */
@@ -1784,7 +1795,6 @@
 		 * sysfs power/wakeup controls wakeup enabled/disabled
 		 */
 		device_init_wakeup(&udev->dev, 0);
-		device_set_wakeup_enable(&udev->dev, 1);
 	}
 
 	/* Tell the runtime-PM framework the device is active */
@@ -3038,7 +3048,7 @@
 
 		/* maybe switch power back on (e.g. root hub was reset) */
 		if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
-				&& !(portstatus & (1 << USB_PORT_FEAT_POWER)))
+				&& !(portstatus & USB_PORT_STAT_POWER))
 			set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
 
 		if (portstatus & USB_PORT_STAT_ENABLE)
@@ -3076,7 +3086,7 @@
 		if (!(hcd->driver->flags & HCD_USB3))
 			udev->speed = USB_SPEED_UNKNOWN;
 		else if ((hdev->parent == NULL) &&
-				(portstatus & (1 << USB_PORT_FEAT_SUPERSPEED)))
+				(portstatus & USB_PORT_STAT_SUPER_SPEED))
 			udev->speed = USB_SPEED_SUPER;
 		else
 			udev->speed = USB_SPEED_UNKNOWN;
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
deleted file mode 100644
index de8081f..0000000
--- a/drivers/usb/core/hub.h
+++ /dev/null
@@ -1,205 +0,0 @@
-#ifndef __LINUX_HUB_H
-#define __LINUX_HUB_H
-
-/*
- * Hub protocol and driver data structures.
- *
- * Some of these are known to the "virtual root hub" code
- * in host controller drivers.
- */
-
-#include <linux/list.h>
-#include <linux/workqueue.h>
-#include <linux/compiler.h>	/* likely()/unlikely() */
-
-/*
- * Hub request types
- */
-
-#define USB_RT_HUB	(USB_TYPE_CLASS | USB_RECIP_DEVICE)
-#define USB_RT_PORT	(USB_TYPE_CLASS | USB_RECIP_OTHER)
-
-/*
- * Hub class requests
- * See USB 2.0 spec Table 11-16
- */
-#define HUB_CLEAR_TT_BUFFER	8
-#define HUB_RESET_TT		9
-#define HUB_GET_TT_STATE	10
-#define HUB_STOP_TT		11
-
-/*
- * Hub Class feature numbers
- * See USB 2.0 spec Table 11-17
- */
-#define C_HUB_LOCAL_POWER	0
-#define C_HUB_OVER_CURRENT	1
-
-/*
- * Port feature numbers
- * See USB 2.0 spec Table 11-17
- */
-#define USB_PORT_FEAT_CONNECTION	0
-#define USB_PORT_FEAT_ENABLE		1
-#define USB_PORT_FEAT_SUSPEND		2	/* L2 suspend */
-#define USB_PORT_FEAT_OVER_CURRENT	3
-#define USB_PORT_FEAT_RESET		4
-#define USB_PORT_FEAT_L1		5	/* L1 suspend */
-#define USB_PORT_FEAT_POWER		8
-#define USB_PORT_FEAT_LOWSPEED		9
-/* This value was never in Table 11-17 */
-#define USB_PORT_FEAT_HIGHSPEED		10
-/* This value is also fake */
-#define USB_PORT_FEAT_SUPERSPEED	11
-#define USB_PORT_FEAT_C_CONNECTION	16
-#define USB_PORT_FEAT_C_ENABLE		17
-#define USB_PORT_FEAT_C_SUSPEND		18
-#define USB_PORT_FEAT_C_OVER_CURRENT	19
-#define USB_PORT_FEAT_C_RESET		20
-#define USB_PORT_FEAT_TEST              21
-#define USB_PORT_FEAT_INDICATOR         22
-#define USB_PORT_FEAT_C_PORT_L1         23
-
-/*
- * Hub Status and Hub Change results
- * See USB 2.0 spec Table 11-19 and Table 11-20
- */
-struct usb_port_status {
-	__le16 wPortStatus;
-	__le16 wPortChange;
-} __attribute__ ((packed));
-
-/*
- * wPortStatus bit field
- * See USB 2.0 spec Table 11-21
- */
-#define USB_PORT_STAT_CONNECTION	0x0001
-#define USB_PORT_STAT_ENABLE		0x0002
-#define USB_PORT_STAT_SUSPEND		0x0004
-#define USB_PORT_STAT_OVERCURRENT	0x0008
-#define USB_PORT_STAT_RESET		0x0010
-#define USB_PORT_STAT_L1		0x0020
-/* bits 6 to 7 are reserved */
-#define USB_PORT_STAT_POWER		0x0100
-#define USB_PORT_STAT_LOW_SPEED		0x0200
-#define USB_PORT_STAT_HIGH_SPEED        0x0400
-#define USB_PORT_STAT_TEST              0x0800
-#define USB_PORT_STAT_INDICATOR         0x1000
-/* bits 13 to 15 are reserved */
-
-/*
- * wPortChange bit field
- * See USB 2.0 spec Table 11-22
- * Bits 0 to 4 shown, bits 5 to 15 are reserved
- */
-#define USB_PORT_STAT_C_CONNECTION	0x0001
-#define USB_PORT_STAT_C_ENABLE		0x0002
-#define USB_PORT_STAT_C_SUSPEND		0x0004
-#define USB_PORT_STAT_C_OVERCURRENT	0x0008
-#define USB_PORT_STAT_C_RESET		0x0010
-#define USB_PORT_STAT_C_L1		0x0020
-
-/*
- * wHubCharacteristics (masks)
- * See USB 2.0 spec Table 11-13, offset 3
- */
-#define HUB_CHAR_LPSM		0x0003 /* D1 .. D0 */
-#define HUB_CHAR_COMPOUND	0x0004 /* D2       */
-#define HUB_CHAR_OCPM		0x0018 /* D4 .. D3 */
-#define HUB_CHAR_TTTT           0x0060 /* D6 .. D5 */
-#define HUB_CHAR_PORTIND        0x0080 /* D7       */
-
-struct usb_hub_status {
-	__le16 wHubStatus;
-	__le16 wHubChange;
-} __attribute__ ((packed));
-
-/*
- * Hub Status & Hub Change bit masks
- * See USB 2.0 spec Table 11-19 and Table 11-20
- * Bits 0 and 1 for wHubStatus and wHubChange
- * Bits 2 to 15 are reserved for both
- */
-#define HUB_STATUS_LOCAL_POWER	0x0001
-#define HUB_STATUS_OVERCURRENT	0x0002
-#define HUB_CHANGE_LOCAL_POWER	0x0001
-#define HUB_CHANGE_OVERCURRENT	0x0002
-
-
-/*
- * Hub descriptor
- * See USB 2.0 spec Table 11-13
- */
-
-#define USB_DT_HUB			(USB_TYPE_CLASS | 0x09)
-#define USB_DT_HUB_NONVAR_SIZE		7
-
-struct usb_hub_descriptor {
-	__u8  bDescLength;
-	__u8  bDescriptorType;
-	__u8  bNbrPorts;
-	__le16 wHubCharacteristics;
-	__u8  bPwrOn2PwrGood;
-	__u8  bHubContrCurrent;
-		/* add 1 bit for hub status change; round to bytes */
-	__u8  DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8];
-	__u8  PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8];
-} __attribute__ ((packed));
-
-
-/* port indicator status selectors, tables 11-7 and 11-25 */
-#define HUB_LED_AUTO	0
-#define HUB_LED_AMBER	1
-#define HUB_LED_GREEN	2
-#define HUB_LED_OFF	3
-
-enum hub_led_mode {
-	INDICATOR_AUTO = 0,
-	INDICATOR_CYCLE,
-	/* software blinks for attention:  software, hardware, reserved */
-	INDICATOR_GREEN_BLINK, INDICATOR_GREEN_BLINK_OFF,
-	INDICATOR_AMBER_BLINK, INDICATOR_AMBER_BLINK_OFF,
-	INDICATOR_ALT_BLINK, INDICATOR_ALT_BLINK_OFF
-} __attribute__ ((packed));
-
-struct usb_device;
-
-/* Transaction Translator Think Times, in bits */
-#define HUB_TTTT_8_BITS		0x00
-#define HUB_TTTT_16_BITS	0x20
-#define HUB_TTTT_24_BITS	0x40
-#define HUB_TTTT_32_BITS	0x60
-
-/*
- * As of USB 2.0, full/low speed devices are segregated into trees.
- * One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
- * The other type grows from high speed hubs when they connect to
- * full/low speed devices using "Transaction Translators" (TTs).
- *
- * TTs should only be known to the hub driver, and high speed bus
- * drivers (only EHCI for now).  They affect periodic scheduling and
- * sometimes control/bulk error recovery.
- */
-struct usb_tt {
-	struct usb_device	*hub;	/* upstream highspeed hub */
-	int			multi;	/* true means one TT per port */
-	unsigned		think_time;	/* think time in ns */
-
-	/* for control/bulk error recovery (CLEAR_TT_BUFFER) */
-	spinlock_t		lock;
-	struct list_head	clear_list;	/* of usb_tt_clear */
-	struct work_struct	clear_work;
-};
-
-struct usb_tt_clear {
-	struct list_head	clear_list;
-	unsigned		tt;
-	u16			devinfo;
-	struct usb_hcd		*hcd;
-	struct usb_host_endpoint	*ep;
-};
-
-extern int usb_hub_clear_tt_buffer(struct urb *urb);
-extern void usb_ep0_reinit(struct usb_device *);
-
-#endif /* __LINUX_HUB_H */
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 111a01a..1a27618 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -40,9 +40,9 @@
 #include <linux/notifier.h>
 #include <linux/seq_file.h>
 #include <linux/smp_lock.h>
+#include <linux/usb/hcd.h>
 #include <asm/byteorder.h>
 #include "usb.h"
-#include "hcd.h"
 
 #define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO)
 #define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO)
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index cd22027..a73e08f 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -14,9 +14,9 @@
 #include <linux/device.h>
 #include <linux/scatterlist.h>
 #include <linux/usb/quirks.h>
+#include <linux/usb/hcd.h>	/* for usbcore internals */
 #include <asm/byteorder.h>
 
-#include "hcd.h"	/* for usbcore internals */
 #include "usb.h"
 
 static void cancel_async_set_config(struct usb_device *udev);
@@ -226,8 +226,7 @@
 	struct urb *urb;
 	struct usb_host_endpoint *ep;
 
-	ep = (usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out)
-			[usb_pipeendpoint(pipe)];
+	ep = usb_pipe_endpoint(usb_dev, pipe);
 	if (!ep || len < 0)
 		return -EINVAL;
 
@@ -259,9 +258,6 @@
 		kfree(io->urbs);
 		io->urbs = NULL;
 	}
-	if (io->dev->dev.dma_mask != NULL)
-		usb_buffer_unmap_sg(io->dev, usb_pipein(io->pipe),
-				    io->sg, io->nents);
 	io->dev = NULL;
 }
 
@@ -364,7 +360,6 @@
 {
 	int i;
 	int urb_flags;
-	int dma;
 	int use_sg;
 
 	if (!io || !dev || !sg
@@ -376,114 +371,76 @@
 	spin_lock_init(&io->lock);
 	io->dev = dev;
 	io->pipe = pipe;
-	io->sg = sg;
-	io->nents = nents;
-
-	/* not all host controllers use DMA (like the mainstream pci ones);
-	 * they can use PIO (sl811) or be software over another transport.
-	 */
-	dma = (dev->dev.dma_mask != NULL);
-	if (dma)
-		io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
-						sg, nents);
-	else
-		io->entries = nents;
-
-	/* initialize all the urbs we'll use */
-	if (io->entries <= 0)
-		return io->entries;
 
 	if (dev->bus->sg_tablesize > 0) {
-		io->urbs = kmalloc(sizeof *io->urbs, mem_flags);
 		use_sg = true;
+		io->entries = 1;
 	} else {
-		io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
 		use_sg = false;
+		io->entries = nents;
 	}
+
+	/* initialize all the urbs we'll use */
+	io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
 	if (!io->urbs)
 		goto nomem;
 
-	urb_flags = 0;
-	if (dma)
-		urb_flags |= URB_NO_TRANSFER_DMA_MAP;
+	urb_flags = URB_NO_INTERRUPT;
 	if (usb_pipein(pipe))
 		urb_flags |= URB_SHORT_NOT_OK;
 
-	if (use_sg) {
-		io->urbs[0] = usb_alloc_urb(0, mem_flags);
-		if (!io->urbs[0]) {
-			io->entries = 0;
+	for_each_sg(sg, sg, io->entries, i) {
+		struct urb *urb;
+		unsigned len;
+
+		urb = usb_alloc_urb(0, mem_flags);
+		if (!urb) {
+			io->entries = i;
 			goto nomem;
 		}
+		io->urbs[i] = urb;
 
-		io->urbs[0]->dev = NULL;
-		io->urbs[0]->pipe = pipe;
-		io->urbs[0]->interval = period;
-		io->urbs[0]->transfer_flags = urb_flags;
+		urb->dev = NULL;
+		urb->pipe = pipe;
+		urb->interval = period;
+		urb->transfer_flags = urb_flags;
+		urb->complete = sg_complete;
+		urb->context = io;
+		urb->sg = sg;
 
-		io->urbs[0]->complete = sg_complete;
-		io->urbs[0]->context = io;
-		/* A length of zero means transfer the whole sg list */
-		io->urbs[0]->transfer_buffer_length = length;
-		if (length == 0) {
-			for_each_sg(sg, sg, io->entries, i) {
-				io->urbs[0]->transfer_buffer_length +=
-					sg_dma_len(sg);
+		if (use_sg) {
+			/* There is no single transfer buffer */
+			urb->transfer_buffer = NULL;
+			urb->num_sgs = nents;
+
+			/* A length of zero means transfer the whole sg list */
+			len = length;
+			if (len == 0) {
+				for_each_sg(sg, sg, nents, i)
+					len += sg->length;
 			}
-		}
-		io->urbs[0]->sg = io;
-		io->urbs[0]->num_sgs = io->entries;
-		io->entries = 1;
-	} else {
-		urb_flags |= URB_NO_INTERRUPT;
-		for_each_sg(sg, sg, io->entries, i) {
-			unsigned len;
-
-			io->urbs[i] = usb_alloc_urb(0, mem_flags);
-			if (!io->urbs[i]) {
-				io->entries = i;
-				goto nomem;
-			}
-
-			io->urbs[i]->dev = NULL;
-			io->urbs[i]->pipe = pipe;
-			io->urbs[i]->interval = period;
-			io->urbs[i]->transfer_flags = urb_flags;
-
-			io->urbs[i]->complete = sg_complete;
-			io->urbs[i]->context = io;
-
+		} else {
 			/*
-			 * Some systems need to revert to PIO when DMA is temporarily
-			 * unavailable.  For their sakes, both transfer_buffer and
-			 * transfer_dma are set when possible.
-			 *
-			 * Note that if IOMMU coalescing occurred, we cannot
-			 * trust sg_page anymore, so check if S/G list shrunk.
+			 * Some systems can't use DMA; they use PIO instead.
+			 * For their sakes, transfer_buffer is set whenever
+			 * possible.
 			 */
-			if (io->nents == io->entries && !PageHighMem(sg_page(sg)))
-				io->urbs[i]->transfer_buffer = sg_virt(sg);
+			if (!PageHighMem(sg_page(sg)))
+				urb->transfer_buffer = sg_virt(sg);
 			else
-				io->urbs[i]->transfer_buffer = NULL;
+				urb->transfer_buffer = NULL;
 
-			if (dma) {
-				io->urbs[i]->transfer_dma = sg_dma_address(sg);
-				len = sg_dma_len(sg);
-			} else {
-				/* hc may use _only_ transfer_buffer */
-				len = sg->length;
-			}
-
+			len = sg->length;
 			if (length) {
 				len = min_t(unsigned, len, length);
 				length -= len;
 				if (length == 0)
 					io->entries = i + 1;
 			}
-			io->urbs[i]->transfer_buffer_length = len;
 		}
-		io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
+		urb->transfer_buffer_length = len;
 	}
+	io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
 
 	/* transaction state */
 	io->count = io->entries;
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index f073c5c..f22d03d 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -71,6 +71,10 @@
 	/* SKYMEDI USB_DRIVE */
 	{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* BUILDWIN Photo Frame */
+	{ USB_DEVICE(0x1908, 0x1315), .driver_info =
+			USB_QUIRK_HONOR_BNUMINTERFACES },
+
 	/* INTEL VALUE SSD */
 	{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
 
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 43c002e..06863be 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -383,13 +383,24 @@
 static const char on_string[] = "on";
 static const char auto_string[] = "auto";
 
+static void warn_level(void) {
+	static int level_warned;
+
+	if (!level_warned) {
+		level_warned = 1;
+		printk(KERN_WARNING "WARNING! power/level is deprecated; "
+				"use power/control instead\n");
+	}
+}
+
 static ssize_t
 show_level(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev = to_usb_device(dev);
 	const char *p = auto_string;
 
-	if (udev->state != USB_STATE_SUSPENDED && udev->autosuspend_disabled)
+	warn_level();
+	if (udev->state != USB_STATE_SUSPENDED && !udev->dev.power.runtime_auto)
 		p = on_string;
 	return sprintf(buf, "%s\n", p);
 }
@@ -401,8 +412,9 @@
 	struct usb_device *udev = to_usb_device(dev);
 	int len = count;
 	char *cp;
-	int rc;
+	int rc = count;
 
+	warn_level();
 	cp = memchr(buf, '\n', count);
 	if (cp)
 		len = cp - buf;
@@ -411,17 +423,17 @@
 
 	if (len == sizeof on_string - 1 &&
 			strncmp(buf, on_string, len) == 0)
-		rc = usb_disable_autosuspend(udev);
+		usb_disable_autosuspend(udev);
 
 	else if (len == sizeof auto_string - 1 &&
 			strncmp(buf, auto_string, len) == 0)
-		rc = usb_enable_autosuspend(udev);
+		usb_enable_autosuspend(udev);
 
 	else
 		rc = -EINVAL;
 
 	usb_unlock_device(udev);
-	return (rc < 0 ? rc : count);
+	return rc;
 }
 
 static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 45a32da..7c05555 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -6,7 +6,7 @@
 #include <linux/log2.h>
 #include <linux/usb.h>
 #include <linux/wait.h>
-#include "hcd.h"
+#include <linux/usb/hcd.h>
 
 #define to_urb(d) container_of(d, struct urb, kref)
 
@@ -308,8 +308,7 @@
 	 * will be required to set urb->ep directly and we will eliminate
 	 * urb->pipe.
 	 */
-	ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
-			[usb_pipeendpoint(urb->pipe)];
+	ep = usb_pipe_endpoint(dev, urb->pipe);
 	if (!ep)
 		return -ENOENT;
 
@@ -333,9 +332,12 @@
 		is_out = usb_endpoint_dir_out(&ep->desc);
 	}
 
-	/* Cache the direction for later use */
-	urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
-			(is_out ? URB_DIR_OUT : URB_DIR_IN);
+	/* Clear the internal flags and cache the direction for later use */
+	urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |
+			URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
+			URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
+			URB_DMA_SG_COMBINED);
+	urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN);
 
 	if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
 			dev->state < USB_STATE_CONFIGURED)
@@ -396,8 +398,8 @@
 		return -EPIPE;		/* The most suitable error code :-) */
 
 	/* enforce simple/standard policy */
-	allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
-			URB_NO_INTERRUPT | URB_DIR_MASK | URB_FREE_BUFFER);
+	allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
+			URB_FREE_BUFFER);
 	switch (xfertype) {
 	case USB_ENDPOINT_XFER_BULK:
 		if (is_out)
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 0561430..397b678 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -32,6 +32,7 @@
 #include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
@@ -41,7 +42,6 @@
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
 
-#include "hcd.h"
 #include "usb.h"
 
 
@@ -593,76 +593,6 @@
 }
 EXPORT_SYMBOL_GPL(usb_lock_device_for_reset);
 
-static struct usb_device *match_device(struct usb_device *dev,
-				       u16 vendor_id, u16 product_id)
-{
-	struct usb_device *ret_dev = NULL;
-	int child;
-
-	dev_dbg(&dev->dev, "check for vendor %04x, product %04x ...\n",
-	    le16_to_cpu(dev->descriptor.idVendor),
-	    le16_to_cpu(dev->descriptor.idProduct));
-
-	/* see if this device matches */
-	if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
-	    (product_id == le16_to_cpu(dev->descriptor.idProduct))) {
-		dev_dbg(&dev->dev, "matched this device!\n");
-		ret_dev = usb_get_dev(dev);
-		goto exit;
-	}
-
-	/* look through all of the children of this device */
-	for (child = 0; child < dev->maxchild; ++child) {
-		if (dev->children[child]) {
-			usb_lock_device(dev->children[child]);
-			ret_dev = match_device(dev->children[child],
-					       vendor_id, product_id);
-			usb_unlock_device(dev->children[child]);
-			if (ret_dev)
-				goto exit;
-		}
-	}
-exit:
-	return ret_dev;
-}
-
-/**
- * usb_find_device - find a specific usb device in the system
- * @vendor_id: the vendor id of the device to find
- * @product_id: the product id of the device to find
- *
- * Returns a pointer to a struct usb_device if such a specified usb
- * device is present in the system currently.  The usage count of the
- * device will be incremented if a device is found.  Make sure to call
- * usb_put_dev() when the caller is finished with the device.
- *
- * If a device with the specified vendor and product id is not found,
- * NULL is returned.
- */
-struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
-{
-	struct list_head *buslist;
-	struct usb_bus *bus;
-	struct usb_device *dev = NULL;
-
-	mutex_lock(&usb_bus_list_lock);
-	for (buslist = usb_bus_list.next;
-	     buslist != &usb_bus_list;
-	     buslist = buslist->next) {
-		bus = container_of(buslist, struct usb_bus, bus_list);
-		if (!bus->root_hub)
-			continue;
-		usb_lock_device(bus->root_hub);
-		dev = match_device(bus->root_hub, vendor_id, product_id);
-		usb_unlock_device(bus->root_hub);
-		if (dev)
-			goto exit;
-	}
-exit:
-	mutex_unlock(&usb_bus_list_lock);
-	return dev;
-}
-
 /**
  * usb_get_current_frame_number - return current bus frame number
  * @dev: the device whose bus is being queried
@@ -775,7 +705,7 @@
  * @urb: urb whose transfer_buffer/setup_packet will be mapped
  *
  * Return value is either null (indicating no buffer could be mapped), or
- * the parameter.  URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP are
+ * the parameter.  URB_NO_TRANSFER_DMA_MAP is
  * added to urb->transfer_flags if the operation succeeds.  If the device
  * is connected to this system through a non-DMA controller, this operation
  * always succeeds.
@@ -803,17 +733,11 @@
 			urb->transfer_buffer, urb->transfer_buffer_length,
 			usb_pipein(urb->pipe)
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-		if (usb_pipecontrol(urb->pipe))
-			urb->setup_dma = dma_map_single(controller,
-					urb->setup_packet,
-					sizeof(struct usb_ctrlrequest),
-					DMA_TO_DEVICE);
 	/* FIXME generic api broken like pci, can't report errors */
 	/* if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; */
 	} else
 		urb->transfer_dma = ~0;
-	urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP
-				| URB_NO_SETUP_DMA_MAP);
+	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 	return urb;
 }
 EXPORT_SYMBOL_GPL(usb_buffer_map);
@@ -881,18 +805,13 @@
 			urb->transfer_dma, urb->transfer_buffer_length,
 			usb_pipein(urb->pipe)
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-		if (usb_pipecontrol(urb->pipe))
-			dma_unmap_single(controller,
-					urb->setup_dma,
-					sizeof(struct usb_ctrlrequest),
-					DMA_TO_DEVICE);
 	}
-	urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
-				| URB_NO_SETUP_DMA_MAP);
+	urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP;
 }
 EXPORT_SYMBOL_GPL(usb_buffer_unmap);
 #endif  /*  0  */
 
+#if 0
 /**
  * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
  * @dev: device to which the scatterlist will be mapped
@@ -936,6 +855,7 @@
 			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE) ? : -ENOMEM;
 }
 EXPORT_SYMBOL_GPL(usb_buffer_map_sg);
+#endif
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
  * XXX please determine whether the sync is to transfer ownership of
@@ -972,6 +892,7 @@
 EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg);
 #endif
 
+#if 0
 /**
  * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
  * @dev: device to which the scatterlist will be mapped
@@ -997,6 +918,7 @@
 			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 EXPORT_SYMBOL_GPL(usb_buffer_unmap_sg);
+#endif
 
 /* To disable USB, kernel command line is 'nousb' not 'usbcore.nousb' */
 #ifdef MODULE
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 11a3e0f..649c0c5 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -710,6 +710,43 @@
 	  Say "y" to link the driver statically, or "m" to build a
 	  dynamically linked module called "gadgetfs".
 
+config USB_FUNCTIONFS
+	tristate "Function Filesystem (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  The Function Filesystem (FunctioFS) lets one create USB
+	  composite functions in user space in the same way as GadgetFS
+	  lets one create USB gadgets in user space.  This allows creation
+	  of composite gadgets such that some of the functions are
+	  implemented in kernel space (for instance Ethernet, serial or
+	  mass storage) and other are implemented in user space.
+
+	  Say "y" to link the driver statically, or "m" to build
+	  a dynamically linked module called "g_ffs".
+
+config USB_FUNCTIONFS_ETH
+	bool "Include CDC ECM (Ethernet) function"
+	depends on USB_FUNCTIONFS && NET
+	help
+	  Include an CDC ECM (Ethernet) funcion in the CDC ECM (Funcion)
+	  Filesystem.  If you also say "y" to the RNDIS query below the
+	  gadget will have two configurations.
+
+config USB_FUNCTIONFS_RNDIS
+	bool "Include RNDIS (Ethernet) function"
+	depends on USB_FUNCTIONFS && NET
+	help
+	  Include an RNDIS (Ethernet) funcion in the Funcion Filesystem.
+	  If you also say "y" to the CDC ECM query above the gadget will
+	  have two configurations.
+
+config USB_FUNCTIONFS_GENERIC
+	bool "Include 'pure' configuration"
+	depends on USB_FUNCTIONFS && (USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)
+	help
+	  Include a configuration with FunctionFS and no Ethernet
+	  configuration.
+
 config USB_FILE_STORAGE
 	tristate "File-backed Storage Gadget"
 	depends on BLOCK
@@ -863,11 +900,30 @@
 
 	  If unsure, say "y".
 
+config USB_G_HID
+	tristate "HID Gadget"
+	help
+	  The HID gadget driver provides generic emulation of USB
+	  Human Interface Devices (HID).
+
+	  For more information, see Documentation/usb/gadget_hid.txt which
+	  includes sample code for accessing the device files.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "g_hid".
 
 # put drivers that need isochronous transfer support (for audio
 # or video class gadget drivers), or specific hardware, here.
+config USB_G_WEBCAM
+	tristate "USB Webcam Gadget"
+	depends on VIDEO_DEV
+	help
+	  The Webcam Gadget acts as a composite USB Audio and Video Class
+	  device. It provides a userspace API to process UVC control requests
+	  and stream video data to the host.
 
-# - none yet
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "g_webcam".
 
 endchoice
 
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 43b51da..9bcde11 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -20,7 +20,7 @@
 obj-$(CONFIG_USB_FSL_USB2)	+= fsl_usb2_udc.o
 fsl_usb2_udc-objs		:= fsl_udc_core.o
 ifeq ($(CONFIG_ARCH_MXC),y)
-fsl_usb2_udc-objs		+= fsl_mx3_udc.o
+fsl_usb2_udc-objs		+= fsl_mxc_udc.o
 endif
 obj-$(CONFIG_USB_M66592)	+= m66592-udc.o
 obj-$(CONFIG_USB_R8A66597)	+= r8a66597-udc.o
@@ -43,18 +43,24 @@
 g_printer-objs			:= printer.o
 g_cdc-objs			:= cdc2.o
 g_multi-objs			:= multi.o
+g_hid-objs			:= hid.o
 g_nokia-objs			:= nokia.o
+g_webcam-objs			:= webcam.o
 
 obj-$(CONFIG_USB_ZERO)		+= g_zero.o
 obj-$(CONFIG_USB_AUDIO)		+= g_audio.o
 obj-$(CONFIG_USB_ETH)		+= g_ether.o
 obj-$(CONFIG_USB_GADGETFS)	+= gadgetfs.o
+obj-$(CONFIG_USB_FUNCTIONFS)	+= g_ffs.o
+obj-$(CONFIG_USB_ETH_FUNCTIONFS)	+= g_eth_ffs.o
 obj-$(CONFIG_USB_FILE_STORAGE)	+= g_file_storage.o
 obj-$(CONFIG_USB_MASS_STORAGE)	+= g_mass_storage.o
 obj-$(CONFIG_USB_G_SERIAL)	+= g_serial.o
 obj-$(CONFIG_USB_G_PRINTER)	+= g_printer.o
 obj-$(CONFIG_USB_MIDI_GADGET)	+= g_midi.o
 obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
+obj-$(CONFIG_USB_G_HID)		+= g_hid.o
 obj-$(CONFIG_USB_G_MULTI)	+= g_multi.o
 obj-$(CONFIG_USB_G_NOKIA)	+= g_nokia.o
+obj-$(CONFIG_USB_G_WEBCAM)	+= g_webcam.o
 
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 75a256f..d623c7b 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -48,10 +48,9 @@
 
 	spin_lock_irq(&ep->udc->lock);
 	list_for_each_entry(req, &ep->queue, queue) {
-		req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC);
+		req_copy = kmemdup(req, sizeof(*req_copy), GFP_ATOMIC);
 		if (!req_copy)
 			goto fail;
-		memcpy(req_copy, req, sizeof(*req_copy));
 		list_add_tail(&req_copy->queue, queue_data);
 	}
 	spin_unlock_irq(&ep->udc->lock);
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 09289bb..391d169 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -36,7 +36,7 @@
  */
 
 /* big enough to hold our biggest descriptor */
-#define USB_BUFSIZ	512
+#define USB_BUFSIZ	1024
 
 static struct usb_composite_driver *composite;
 
@@ -85,7 +85,7 @@
  * This function returns the value of the function's bind(), which is
  * zero for success else a negative errno value.
  */
-int __init usb_add_function(struct usb_configuration *config,
+int usb_add_function(struct usb_configuration *config,
 		struct usb_function *function)
 {
 	int	value = -EINVAL;
@@ -215,7 +215,7 @@
  * Returns the interface ID which was allocated; or -ENODEV if no
  * more interface IDs can be allocated.
  */
-int __init usb_interface_id(struct usb_configuration *config,
+int usb_interface_id(struct usb_configuration *config,
 		struct usb_function *function)
 {
 	unsigned id = config->next_interface_id;
@@ -480,7 +480,7 @@
  * assigns global resources including string IDs, and per-configuration
  * resources such as interface IDs and endpoints.
  */
-int __init usb_add_config(struct usb_composite_dev *cdev,
+int usb_add_config(struct usb_composite_dev *cdev,
 		struct usb_configuration *config)
 {
 	int				status = -EINVAL;
@@ -677,7 +677,7 @@
  * ensure that for example different functions don't wrongly assign
  * different meanings to the same identifier.
  */
-int __init usb_string_id(struct usb_composite_dev *cdev)
+int usb_string_id(struct usb_composite_dev *cdev)
 {
 	if (cdev->next_string_id < 254) {
 		/* string id 0 is reserved */
@@ -898,7 +898,19 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void /* __init_or_exit */
+static ssize_t composite_show_suspended(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct usb_gadget *gadget = dev_to_usb_gadget(dev);
+	struct usb_composite_dev *cdev = get_gadget_data(gadget);
+
+	return sprintf(buf, "%d\n", cdev->suspended);
+}
+
+static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
+
+static void
 composite_unbind(struct usb_gadget *gadget)
 {
 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
@@ -944,10 +956,11 @@
 	}
 	kfree(cdev);
 	set_gadget_data(gadget, NULL);
+	device_remove_file(&gadget->dev, &dev_attr_suspended);
 	composite = NULL;
 }
 
-static void __init
+static void
 string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s)
 {
 	struct usb_string		*str = tab->strings;
@@ -960,7 +973,7 @@
 	}
 }
 
-static void __init
+static void
 string_override(struct usb_gadget_strings **tab, u8 id, const char *s)
 {
 	while (*tab) {
@@ -969,7 +982,7 @@
 	}
 }
 
-static int __init composite_bind(struct usb_gadget *gadget)
+static int composite_bind(struct usb_gadget *gadget)
 {
 	struct usb_composite_dev	*cdev;
 	int				status = -ENOMEM;
@@ -1004,6 +1017,14 @@
 	 */
 	usb_ep_autoconfig_reset(cdev->gadget);
 
+	/* standardized runtime overrides for device ID data */
+	if (idVendor)
+		cdev->desc.idVendor = cpu_to_le16(idVendor);
+	if (idProduct)
+		cdev->desc.idProduct = cpu_to_le16(idProduct);
+	if (bcdDevice)
+		cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
+
 	/* composite gadget needs to assign strings for whole device (like
 	 * serial number), register function drivers, potentially update
 	 * power state and consumption, etc
@@ -1015,14 +1036,6 @@
 	cdev->desc = *composite->dev;
 	cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
-	/* standardized runtime overrides for device ID data */
-	if (idVendor)
-		cdev->desc.idVendor = cpu_to_le16(idVendor);
-	if (idProduct)
-		cdev->desc.idProduct = cpu_to_le16(idProduct);
-	if (bcdDevice)
-		cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
-
 	/* strings can't be assigned before bind() allocates the
 	 * releavnt identifiers
 	 */
@@ -1036,6 +1049,10 @@
 		string_override(composite->strings,
 			cdev->desc.iSerialNumber, iSerialNumber);
 
+	status = device_create_file(&gadget->dev, &dev_attr_suspended);
+	if (status)
+		goto fail;
+
 	INFO(cdev, "%s ready\n", composite->name);
 	return 0;
 
@@ -1064,6 +1081,8 @@
 	}
 	if (composite->suspend)
 		composite->suspend(cdev);
+
+	cdev->suspended = 1;
 }
 
 static void
@@ -1084,6 +1103,8 @@
 				f->resume(f);
 		}
 	}
+
+	cdev->suspended = 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1092,7 +1113,6 @@
 	.speed		= USB_SPEED_HIGH,
 
 	.bind		= composite_bind,
-	/* .unbind		= __exit_p(composite_unbind), */
 	.unbind		= composite_unbind,
 
 	.setup		= composite_setup,
@@ -1121,7 +1141,7 @@
  * while it was binding.  That would usually be done in order to wait for
  * some userspace participation.
  */
-int __init usb_composite_register(struct usb_composite_driver *driver)
+int usb_composite_register(struct usb_composite_driver *driver)
 {
 	if (!driver || !driver->dev || !driver->bind || composite)
 		return -EINVAL;
@@ -1142,7 +1162,7 @@
  * This function is used to unregister drivers using the composite
  * driver framework.
  */
-void /* __exit */ usb_composite_unregister(struct usb_composite_driver *driver)
+void usb_composite_unregister(struct usb_composite_driver *driver)
 {
 	if (composite != driver)
 		return;
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index 47e8e72..09084fd 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -128,7 +128,7 @@
  * with identifiers (for interfaces, strings, endpoints, and more)
  * as needed by a given function instance.
  */
-struct usb_descriptor_header **__init
+struct usb_descriptor_header **
 usb_copy_descriptors(struct usb_descriptor_header **src)
 {
 	struct usb_descriptor_header **tmp;
@@ -175,7 +175,7 @@
  * intended use is to help remembering the endpoint descriptor to use
  * when enabling a given endpoint.
  */
-struct usb_endpoint_descriptor *__init
+struct usb_endpoint_descriptor *
 usb_find_endpoint(
 	struct usb_descriptor_header **src,
 	struct usb_descriptor_header **copy,
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 5e09664..4f9e578 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -47,6 +47,7 @@
 #include <linux/platform_device.h>
 #include <linux/usb.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/hcd.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -55,9 +56,6 @@
 #include <asm/unaligned.h>
 
 
-#include "../core/hcd.h"
-
-
 #define DRIVER_DESC	"USB Host+Gadget Emulator"
 #define DRIVER_VERSION	"02 May 2005"
 
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 3568de2..8a83248 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -34,12 +34,12 @@
 
 
 /* we must assign addresses for configurable endpoints (like net2280) */
-static __initdata unsigned epnum;
+static unsigned epnum;
 
 // #define MANY_ENDPOINTS
 #ifdef MANY_ENDPOINTS
 /* more than 15 configurable endpoints */
-static __initdata unsigned in_epnum;
+static unsigned in_epnum;
 #endif
 
 
@@ -59,7 +59,7 @@
  * NOTE:  each endpoint is unidirectional, as specified by its USB
  * descriptor; and isn't specific to a configuration or altsetting.
  */
-static int __init
+static int
 ep_matches (
 	struct usb_gadget		*gadget,
 	struct usb_ep			*ep,
@@ -187,7 +187,7 @@
 	return 1;
 }
 
-static struct usb_ep * __init
+static struct usb_ep *
 find_ep (struct usb_gadget *gadget, const char *name)
 {
 	struct usb_ep	*ep;
@@ -229,7 +229,7 @@
  *
  * On failure, this returns a null endpoint descriptor.
  */
-struct usb_ep * __init usb_ep_autoconfig (
+struct usb_ep *usb_ep_autoconfig (
 	struct usb_gadget		*gadget,
 	struct usb_endpoint_descriptor	*desc
 )
@@ -304,7 +304,7 @@
  * state such as ep->driver_data and the record of assigned endpoints
  * used by usb_ep_autoconfig().
  */
-void __init usb_ep_autoconfig_reset (struct usb_gadget *gadget)
+void usb_ep_autoconfig_reset (struct usb_gadget *gadget)
 {
 	struct usb_ep	*ep;
 
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 400e1eb..d47a123 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -116,7 +116,7 @@
 };
 
 
-static struct usb_interface_descriptor acm_control_interface_desc __initdata = {
+static struct usb_interface_descriptor acm_control_interface_desc = {
 	.bLength =		USB_DT_INTERFACE_SIZE,
 	.bDescriptorType =	USB_DT_INTERFACE,
 	/* .bInterfaceNumber = DYNAMIC */
@@ -127,7 +127,7 @@
 	/* .iInterface = DYNAMIC */
 };
 
-static struct usb_interface_descriptor acm_data_interface_desc __initdata = {
+static struct usb_interface_descriptor acm_data_interface_desc = {
 	.bLength =		USB_DT_INTERFACE_SIZE,
 	.bDescriptorType =	USB_DT_INTERFACE,
 	/* .bInterfaceNumber = DYNAMIC */
@@ -138,7 +138,7 @@
 	/* .iInterface = DYNAMIC */
 };
 
-static struct usb_cdc_header_desc acm_header_desc __initdata = {
+static struct usb_cdc_header_desc acm_header_desc = {
 	.bLength =		sizeof(acm_header_desc),
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
@@ -146,7 +146,7 @@
 };
 
 static struct usb_cdc_call_mgmt_descriptor
-acm_call_mgmt_descriptor __initdata = {
+acm_call_mgmt_descriptor = {
 	.bLength =		sizeof(acm_call_mgmt_descriptor),
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
@@ -154,14 +154,14 @@
 	/* .bDataInterface = DYNAMIC */
 };
 
-static struct usb_cdc_acm_descriptor acm_descriptor __initdata = {
+static struct usb_cdc_acm_descriptor acm_descriptor = {
 	.bLength =		sizeof(acm_descriptor),
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
 	.bmCapabilities =	USB_CDC_CAP_LINE,
 };
 
-static struct usb_cdc_union_desc acm_union_desc __initdata = {
+static struct usb_cdc_union_desc acm_union_desc = {
 	.bLength =		sizeof(acm_union_desc),
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
@@ -171,7 +171,7 @@
 
 /* full speed support: */
 
-static struct usb_endpoint_descriptor acm_fs_notify_desc __initdata = {
+static struct usb_endpoint_descriptor acm_fs_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 	.bEndpointAddress =	USB_DIR_IN,
@@ -180,21 +180,21 @@
 	.bInterval =		1 << GS_LOG2_NOTIFY_INTERVAL,
 };
 
-static struct usb_endpoint_descriptor acm_fs_in_desc __initdata = {
+static struct usb_endpoint_descriptor acm_fs_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 	.bEndpointAddress =	USB_DIR_IN,
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_endpoint_descriptor acm_fs_out_desc __initdata = {
+static struct usb_endpoint_descriptor acm_fs_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 	.bEndpointAddress =	USB_DIR_OUT,
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *acm_fs_function[] __initdata = {
+static struct usb_descriptor_header *acm_fs_function[] = {
 	(struct usb_descriptor_header *) &acm_iad_descriptor,
 	(struct usb_descriptor_header *) &acm_control_interface_desc,
 	(struct usb_descriptor_header *) &acm_header_desc,
@@ -210,7 +210,7 @@
 
 /* high speed support: */
 
-static struct usb_endpoint_descriptor acm_hs_notify_desc __initdata = {
+static struct usb_endpoint_descriptor acm_hs_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 	.bEndpointAddress =	USB_DIR_IN,
@@ -219,21 +219,21 @@
 	.bInterval =		GS_LOG2_NOTIFY_INTERVAL+4,
 };
 
-static struct usb_endpoint_descriptor acm_hs_in_desc __initdata = {
+static struct usb_endpoint_descriptor acm_hs_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_endpoint_descriptor acm_hs_out_desc __initdata = {
+static struct usb_endpoint_descriptor acm_hs_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *acm_hs_function[] __initdata = {
+static struct usb_descriptor_header *acm_hs_function[] = {
 	(struct usb_descriptor_header *) &acm_iad_descriptor,
 	(struct usb_descriptor_header *) &acm_control_interface_desc,
 	(struct usb_descriptor_header *) &acm_header_desc,
@@ -571,7 +571,7 @@
 /*-------------------------------------------------------------------------*/
 
 /* ACM function driver setup/binding */
-static int __init
+static int
 acm_bind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct usb_composite_dev *cdev = c->cdev;
@@ -719,7 +719,7 @@
  * handle all the ones it binds.  Caller is also responsible
  * for calling @gserial_cleanup() before module unload.
  */
-int __init acm_bind_config(struct usb_configuration *c, u8 port_num)
+int acm_bind_config(struct usb_configuration *c, u8 port_num)
 {
 	struct f_acm	*acm;
 	int		status;
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 4e595324..544257a8 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -113,7 +113,7 @@
 
 /* interface descriptor: */
 
-static struct usb_interface_descriptor ecm_control_intf __initdata = {
+static struct usb_interface_descriptor ecm_control_intf = {
 	.bLength =		sizeof ecm_control_intf,
 	.bDescriptorType =	USB_DT_INTERFACE,
 
@@ -126,7 +126,7 @@
 	/* .iInterface = DYNAMIC */
 };
 
-static struct usb_cdc_header_desc ecm_header_desc __initdata = {
+static struct usb_cdc_header_desc ecm_header_desc = {
 	.bLength =		sizeof ecm_header_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
@@ -134,7 +134,7 @@
 	.bcdCDC =		cpu_to_le16(0x0110),
 };
 
-static struct usb_cdc_union_desc ecm_union_desc __initdata = {
+static struct usb_cdc_union_desc ecm_union_desc = {
 	.bLength =		sizeof(ecm_union_desc),
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
@@ -142,7 +142,7 @@
 	/* .bSlaveInterface0 =	DYNAMIC */
 };
 
-static struct usb_cdc_ether_desc ecm_desc __initdata = {
+static struct usb_cdc_ether_desc ecm_desc = {
 	.bLength =		sizeof ecm_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_ETHERNET_TYPE,
@@ -157,7 +157,7 @@
 
 /* the default data interface has no endpoints ... */
 
-static struct usb_interface_descriptor ecm_data_nop_intf __initdata = {
+static struct usb_interface_descriptor ecm_data_nop_intf = {
 	.bLength =		sizeof ecm_data_nop_intf,
 	.bDescriptorType =	USB_DT_INTERFACE,
 
@@ -172,7 +172,7 @@
 
 /* ... but the "real" data interface has two bulk endpoints */
 
-static struct usb_interface_descriptor ecm_data_intf __initdata = {
+static struct usb_interface_descriptor ecm_data_intf = {
 	.bLength =		sizeof ecm_data_intf,
 	.bDescriptorType =	USB_DT_INTERFACE,
 
@@ -187,7 +187,7 @@
 
 /* full speed support: */
 
-static struct usb_endpoint_descriptor fs_ecm_notify_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ecm_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -197,7 +197,7 @@
 	.bInterval =		1 << LOG2_STATUS_INTERVAL_MSEC,
 };
 
-static struct usb_endpoint_descriptor fs_ecm_in_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ecm_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -205,7 +205,7 @@
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_endpoint_descriptor fs_ecm_out_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ecm_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -213,7 +213,7 @@
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *ecm_fs_function[] __initdata = {
+static struct usb_descriptor_header *ecm_fs_function[] = {
 	/* CDC ECM control descriptors */
 	(struct usb_descriptor_header *) &ecm_control_intf,
 	(struct usb_descriptor_header *) &ecm_header_desc,
@@ -231,7 +231,7 @@
 
 /* high speed support: */
 
-static struct usb_endpoint_descriptor hs_ecm_notify_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ecm_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -240,7 +240,7 @@
 	.wMaxPacketSize =	cpu_to_le16(ECM_STATUS_BYTECOUNT),
 	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
 };
-static struct usb_endpoint_descriptor hs_ecm_in_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ecm_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -249,7 +249,7 @@
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_endpoint_descriptor hs_ecm_out_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ecm_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -258,7 +258,7 @@
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *ecm_hs_function[] __initdata = {
+static struct usb_descriptor_header *ecm_hs_function[] = {
 	/* CDC ECM control descriptors */
 	(struct usb_descriptor_header *) &ecm_control_intf,
 	(struct usb_descriptor_header *) &ecm_header_desc,
@@ -597,7 +597,7 @@
 
 /* ethernet function driver setup/binding */
 
-static int __init
+static int
 ecm_bind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct usb_composite_dev *cdev = c->cdev;
@@ -763,7 +763,8 @@
  * Caller must have called @gether_setup().  Caller is also responsible
  * for calling @gether_cleanup() before module unload.
  */
-int __init ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int
+ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
 {
 	struct f_ecm	*ecm;
 	int		status;
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
new file mode 100644
index 0000000..d69eccf
--- /dev/null
+++ b/drivers/usb/gadget/f_fs.c
@@ -0,0 +1,2442 @@
+/*
+ * f_fs.c -- user mode filesystem api for usb composite funtcion controllers
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ *
+ * Based on inode.c (GadgetFS):
+ * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003 Agilent Technologies
+ *
+ * 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
+ */
+
+
+/* #define DEBUG */
+/* #define VERBOSE_DEBUG */
+
+#include <linux/blkdev.h>
+#include <linux/pagemap.h>
+#include <asm/unaligned.h>
+#include <linux/smp_lock.h>
+
+#include <linux/usb/composite.h>
+#include <linux/usb/functionfs.h>
+
+
+#define FUNCTIONFS_MAGIC	0xa647361 /* Chosen by a honest dice roll ;) */
+
+
+/* Debuging *****************************************************************/
+
+#define ffs_printk(level, fmt, args...) printk(level "f_fs: " fmt "\n", ## args)
+
+#define FERR(...)  ffs_printk(KERN_ERR,  __VA_ARGS__)
+#define FINFO(...) ffs_printk(KERN_INFO, __VA_ARGS__)
+
+#ifdef DEBUG
+#  define FDBG(...) ffs_printk(KERN_DEBUG, __VA_ARGS__)
+#else
+#  define FDBG(...) do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE_DEBUG
+#  define FVDBG FDBG
+#else
+#  define FVDBG(...) do { } while (0)
+#endif /* VERBOSE_DEBUG */
+
+#define ENTER()    FVDBG("%s()", __func__)
+
+#ifdef VERBOSE_DEBUG
+#  define ffs_dump_mem(prefix, ptr, len) \
+	print_hex_dump_bytes("f_fs" prefix ": ", DUMP_PREFIX_NONE, ptr, len)
+#else
+#  define ffs_dump_mem(prefix, ptr, len) do { } while (0)
+#endif
+
+
+/* The data structure and setup file ****************************************/
+
+enum ffs_state {
+	/* Waiting for descriptors and strings. */
+	/* In this state no open(2), read(2) or write(2) on epfiles
+	 * may succeed (which should not be the problem as there
+	 * should be no such files opened in the firts place). */
+	FFS_READ_DESCRIPTORS,
+	FFS_READ_STRINGS,
+
+	/* We've got descriptors and strings.  We are or have called
+	 * functionfs_ready_callback().  functionfs_bind() may have
+	 * been called but we don't know. */
+	/* This is the only state in which operations on epfiles may
+	 * succeed. */
+	FFS_ACTIVE,
+
+	/* All endpoints have been closed.  This state is also set if
+	 * we encounter an unrecoverable error.  The only
+	 * unrecoverable error is situation when after reading strings
+	 * from user space we fail to initialise EP files or
+	 * functionfs_ready_callback() returns with error (<0). */
+	/* In this state no open(2), read(2) or write(2) (both on ep0
+	 * as well as epfile) may succeed (at this point epfiles are
+	 * unlinked and all closed so this is not a problem; ep0 is
+	 * also closed but ep0 file exists and so open(2) on ep0 must
+	 * fail). */
+	FFS_CLOSING
+};
+
+
+enum ffs_setup_state {
+	/* There is no setup request pending. */
+	FFS_NO_SETUP,
+	/* User has read events and there was a setup request event
+	 * there.  The next read/write on ep0 will handle the
+	 * request. */
+	FFS_SETUP_PENDING,
+	/* There was event pending but before user space handled it
+	 * some other event was introduced which canceled existing
+	 * setup.  If this state is set read/write on ep0 return
+	 * -EIDRM.  This state is only set when adding event. */
+	FFS_SETUP_CANCELED
+};
+
+
+
+struct ffs_epfile;
+struct ffs_function;
+
+struct ffs_data {
+	struct usb_gadget		*gadget;
+
+	/* Protect access read/write operations, only one read/write
+	 * at a time.  As a consequence protects ep0req and company.
+	 * While setup request is being processed (queued) this is
+	 * held. */
+	struct mutex			mutex;
+
+	/* Protect access to enpoint related structures (basically
+	 * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for
+	 * endpint zero. */
+	spinlock_t			eps_lock;
+
+	/* XXX REVISIT do we need our own request? Since we are not
+	 * handling setup requests immidiatelly user space may be so
+	 * slow that another setup will be sent to the gadget but this
+	 * time not to us but another function and then there could be
+	 * a race.  Is taht the case? Or maybe we can use cdev->req
+	 * after all, maybe we just need some spinlock for that? */
+	struct usb_request		*ep0req;		/* P: mutex */
+	struct completion		ep0req_completion;	/* P: mutex */
+	int				ep0req_status;		/* P: mutex */
+
+	/* reference counter */
+	atomic_t			ref;
+	/* how many files are opened (EP0 and others) */
+	atomic_t			opened;
+
+	/* EP0 state */
+	enum ffs_state			state;
+
+	/*
+	 * Possible transations:
+	 * + FFS_NO_SETUP       -> FFS_SETUP_PENDING  -- P: ev.waitq.lock
+	 *               happens only in ep0 read which is P: mutex
+	 * + FFS_SETUP_PENDING  -> FFS_NO_SETUP       -- P: ev.waitq.lock
+	 *               happens only in ep0 i/o  which is P: mutex
+	 * + FFS_SETUP_PENDING  -> FFS_SETUP_CANCELED -- P: ev.waitq.lock
+	 * + FFS_SETUP_CANCELED -> FFS_NO_SETUP       -- cmpxchg
+	 */
+	enum ffs_setup_state		setup_state;
+
+#define FFS_SETUP_STATE(ffs)					\
+	((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state,	\
+				       FFS_SETUP_CANCELED, FFS_NO_SETUP))
+
+	/* Events & such. */
+	struct {
+		u8				types[4];
+		unsigned short			count;
+		/* XXX REVISIT need to update it in some places, or do we? */
+		unsigned short			can_stall;
+		struct usb_ctrlrequest		setup;
+
+		wait_queue_head_t		waitq;
+	} ev; /* the whole structure, P: ev.waitq.lock */
+
+	/* Flags */
+	unsigned long			flags;
+#define FFS_FL_CALL_CLOSED_CALLBACK 0
+#define FFS_FL_BOUND                1
+
+	/* Active function */
+	struct ffs_function		*func;
+
+	/* Device name, write once when file system is mounted.
+	 * Intendet for user to read if she wants. */
+	const char			*dev_name;
+	/* Private data for our user (ie. gadget).  Managed by
+	 * user. */
+	void				*private_data;
+
+	/* filled by __ffs_data_got_descs() */
+	/* real descriptors are 16 bytes after raw_descs (so you need
+	 * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the
+	 * first full speed descriptor).  raw_descs_length and
+	 * raw_fs_descs_length do not have those 16 bytes added. */
+	const void			*raw_descs;
+	unsigned			raw_descs_length;
+	unsigned			raw_fs_descs_length;
+	unsigned			fs_descs_count;
+	unsigned			hs_descs_count;
+
+	unsigned short			strings_count;
+	unsigned short			interfaces_count;
+	unsigned short			eps_count;
+	unsigned short			_pad1;
+
+	/* filled by __ffs_data_got_strings() */
+	/* ids in stringtabs are set in functionfs_bind() */
+	const void			*raw_strings;
+	struct usb_gadget_strings	**stringtabs;
+
+	/* File system's super block, write once when file system is mounted. */
+	struct super_block		*sb;
+
+	/* File permissions, written once when fs is mounted*/
+	struct ffs_file_perms {
+		umode_t				mode;
+		uid_t				uid;
+		gid_t				gid;
+	}				file_perms;
+
+	/* The endpoint files, filled by ffs_epfiles_create(),
+	 * destroyed by ffs_epfiles_destroy(). */
+	struct ffs_epfile		*epfiles;
+};
+
+/* Reference counter handling */
+static void ffs_data_get(struct ffs_data *ffs);
+static void ffs_data_put(struct ffs_data *ffs);
+/* Creates new ffs_data object. */
+static struct ffs_data *__must_check ffs_data_new(void) __attribute__((malloc));
+
+/* Opened counter handling. */
+static void ffs_data_opened(struct ffs_data *ffs);
+static void ffs_data_closed(struct ffs_data *ffs);
+
+/* Called with ffs->mutex held; take over ownerrship of data. */
+static int __must_check
+__ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len);
+static int __must_check
+__ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len);
+
+
+/* The function structure ***************************************************/
+
+struct ffs_ep;
+
+struct ffs_function {
+	struct usb_configuration	*conf;
+	struct usb_gadget		*gadget;
+	struct ffs_data			*ffs;
+
+	struct ffs_ep			*eps;
+	u8				eps_revmap[16];
+	short				*interfaces_nums;
+
+	struct usb_function		function;
+};
+
+
+static struct ffs_function *ffs_func_from_usb(struct usb_function *f)
+{
+	return container_of(f, struct ffs_function, function);
+}
+
+static void ffs_func_free(struct ffs_function *func);
+
+
+static void ffs_func_eps_disable(struct ffs_function *func);
+static int __must_check ffs_func_eps_enable(struct ffs_function *func);
+
+
+static int ffs_func_bind(struct usb_configuration *,
+			 struct usb_function *);
+static void ffs_func_unbind(struct usb_configuration *,
+			    struct usb_function *);
+static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);
+static void ffs_func_disable(struct usb_function *);
+static int ffs_func_setup(struct usb_function *,
+			  const struct usb_ctrlrequest *);
+static void ffs_func_suspend(struct usb_function *);
+static void ffs_func_resume(struct usb_function *);
+
+
+static int ffs_func_revmap_ep(struct ffs_function *func, u8 num);
+static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf);
+
+
+
+/* The endpoints structures *************************************************/
+
+struct ffs_ep {
+	struct usb_ep			*ep;	/* P: ffs->eps_lock */
+	struct usb_request		*req;	/* P: epfile->mutex */
+
+	/* [0]: full speed, [1]: high speed */
+	struct usb_endpoint_descriptor	*descs[2];
+
+	u8				num;
+
+	int				status;	/* P: epfile->mutex */
+};
+
+struct ffs_epfile {
+	/* Protects ep->ep and ep->req. */
+	struct mutex			mutex;
+	wait_queue_head_t		wait;
+
+	struct ffs_data			*ffs;
+	struct ffs_ep			*ep;	/* P: ffs->eps_lock */
+
+	struct dentry			*dentry;
+
+	char				name[5];
+
+	unsigned char			in;	/* P: ffs->eps_lock */
+	unsigned char			isoc;	/* P: ffs->eps_lock */
+
+	unsigned char			_pad;
+};
+
+
+static int  __must_check ffs_epfiles_create(struct ffs_data *ffs);
+static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
+
+static struct inode *__must_check
+ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
+		   const struct file_operations *fops,
+		   struct dentry **dentry_p);
+
+
+/* Misc helper functions ****************************************************/
+
+static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
+	__attribute__((warn_unused_result, nonnull));
+static char *ffs_prepare_buffer(const char * __user buf, size_t len)
+	__attribute__((warn_unused_result, nonnull));
+
+
+/* Control file aka ep0 *****************************************************/
+
+static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct ffs_data *ffs = req->context;
+
+	complete_all(&ffs->ep0req_completion);
+}
+
+
+static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
+{
+	struct usb_request *req = ffs->ep0req;
+	int ret;
+
+	req->zero     = len < le16_to_cpu(ffs->ev.setup.wLength);
+
+	spin_unlock_irq(&ffs->ev.waitq.lock);
+
+	req->buf      = data;
+	req->length   = len;
+
+	INIT_COMPLETION(ffs->ep0req_completion);
+
+	ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
+	if (unlikely(ret < 0))
+		return ret;
+
+	ret = wait_for_completion_interruptible(&ffs->ep0req_completion);
+	if (unlikely(ret)) {
+		usb_ep_dequeue(ffs->gadget->ep0, req);
+		return -EINTR;
+	}
+
+	ffs->setup_state = FFS_NO_SETUP;
+	return ffs->ep0req_status;
+}
+
+static int __ffs_ep0_stall(struct ffs_data *ffs)
+{
+	if (ffs->ev.can_stall) {
+		FVDBG("ep0 stall\n");
+		usb_ep_set_halt(ffs->gadget->ep0);
+		ffs->setup_state = FFS_NO_SETUP;
+		return -EL2HLT;
+	} else {
+		FDBG("bogus ep0 stall!\n");
+		return -ESRCH;
+	}
+}
+
+
+static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
+			     size_t len, loff_t *ptr)
+{
+	struct ffs_data *ffs = file->private_data;
+	ssize_t ret;
+	char *data;
+
+	ENTER();
+
+	/* Fast check if setup was canceled */
+	if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED)
+		return -EIDRM;
+
+	/* Acquire mutex */
+	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
+	if (unlikely(ret < 0))
+		return ret;
+
+
+	/* Check state */
+	switch (ffs->state) {
+	case FFS_READ_DESCRIPTORS:
+	case FFS_READ_STRINGS:
+		/* Copy data */
+		if (unlikely(len < 16)) {
+			ret = -EINVAL;
+			break;
+		}
+
+		data = ffs_prepare_buffer(buf, len);
+		if (unlikely(IS_ERR(data))) {
+			ret = PTR_ERR(data);
+			break;
+		}
+
+		/* Handle data */
+		if (ffs->state == FFS_READ_DESCRIPTORS) {
+			FINFO("read descriptors");
+			ret = __ffs_data_got_descs(ffs, data, len);
+			if (unlikely(ret < 0))
+				break;
+
+			ffs->state = FFS_READ_STRINGS;
+			ret = len;
+		} else {
+			FINFO("read strings");
+			ret = __ffs_data_got_strings(ffs, data, len);
+			if (unlikely(ret < 0))
+				break;
+
+			ret = ffs_epfiles_create(ffs);
+			if (unlikely(ret)) {
+				ffs->state = FFS_CLOSING;
+				break;
+			}
+
+			ffs->state = FFS_ACTIVE;
+			mutex_unlock(&ffs->mutex);
+
+			ret = functionfs_ready_callback(ffs);
+			if (unlikely(ret < 0)) {
+				ffs->state = FFS_CLOSING;
+				return ret;
+			}
+
+			set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags);
+			return len;
+		}
+		break;
+
+
+	case FFS_ACTIVE:
+		data = NULL;
+		/* We're called from user space, we can use _irq
+		 * rather then _irqsave */
+		spin_lock_irq(&ffs->ev.waitq.lock);
+		switch (FFS_SETUP_STATE(ffs)) {
+		case FFS_SETUP_CANCELED:
+			ret = -EIDRM;
+			goto done_spin;
+
+		case FFS_NO_SETUP:
+			ret = -ESRCH;
+			goto done_spin;
+
+		case FFS_SETUP_PENDING:
+			break;
+		}
+
+		/* FFS_SETUP_PENDING */
+		if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) {
+			spin_unlock_irq(&ffs->ev.waitq.lock);
+			ret = __ffs_ep0_stall(ffs);
+			break;
+		}
+
+		/* FFS_SETUP_PENDING and not stall */
+		len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
+
+		spin_unlock_irq(&ffs->ev.waitq.lock);
+
+		data = ffs_prepare_buffer(buf, len);
+		if (unlikely(IS_ERR(data))) {
+			ret = PTR_ERR(data);
+			break;
+		}
+
+		spin_lock_irq(&ffs->ev.waitq.lock);
+
+		/* We are guaranteed to be still in FFS_ACTIVE state
+		 * but the state of setup could have changed from
+		 * FFS_SETUP_PENDING to FFS_SETUP_CANCELED so we need
+		 * to check for that.  If that happened we copied data
+		 * from user space in vain but it's unlikely. */
+		/* For sure we are not in FFS_NO_SETUP since this is
+		 * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP
+		 * transition can be performed and it's protected by
+		 * mutex. */
+
+		if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) {
+			ret = -EIDRM;
+done_spin:
+			spin_unlock_irq(&ffs->ev.waitq.lock);
+		} else {
+			/* unlocks spinlock */
+			ret = __ffs_ep0_queue_wait(ffs, data, len);
+		}
+		kfree(data);
+		break;
+
+
+	default:
+		ret = -EBADFD;
+		break;
+	}
+
+
+	mutex_unlock(&ffs->mutex);
+	return ret;
+}
+
+
+
+static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
+				     size_t n)
+{
+	/* We are holding ffs->ev.waitq.lock and ffs->mutex and we need
+	 * to release them. */
+
+	struct usb_functionfs_event events[n];
+	unsigned i = 0;
+
+	memset(events, 0, sizeof events);
+
+	do {
+		events[i].type = ffs->ev.types[i];
+		if (events[i].type == FUNCTIONFS_SETUP) {
+			events[i].u.setup = ffs->ev.setup;
+			ffs->setup_state = FFS_SETUP_PENDING;
+		}
+	} while (++i < n);
+
+	if (n < ffs->ev.count) {
+		ffs->ev.count -= n;
+		memmove(ffs->ev.types, ffs->ev.types + n,
+			ffs->ev.count * sizeof *ffs->ev.types);
+	} else {
+		ffs->ev.count = 0;
+	}
+
+	spin_unlock_irq(&ffs->ev.waitq.lock);
+	mutex_unlock(&ffs->mutex);
+
+	return unlikely(__copy_to_user(buf, events, sizeof events))
+		? -EFAULT : sizeof events;
+}
+
+
+static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
+			    size_t len, loff_t *ptr)
+{
+	struct ffs_data *ffs = file->private_data;
+	char *data = NULL;
+	size_t n;
+	int ret;
+
+	ENTER();
+
+	/* Fast check if setup was canceled */
+	if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED)
+		return -EIDRM;
+
+	/* Acquire mutex */
+	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
+	if (unlikely(ret < 0))
+		return ret;
+
+
+	/* Check state */
+	if (ffs->state != FFS_ACTIVE) {
+		ret = -EBADFD;
+		goto done_mutex;
+	}
+
+
+	/* We're called from user space, we can use _irq rather then
+	 * _irqsave */
+	spin_lock_irq(&ffs->ev.waitq.lock);
+
+	switch (FFS_SETUP_STATE(ffs)) {
+	case FFS_SETUP_CANCELED:
+		ret = -EIDRM;
+		break;
+
+	case FFS_NO_SETUP:
+		n = len / sizeof(struct usb_functionfs_event);
+		if (unlikely(!n)) {
+			ret = -EINVAL;
+			break;
+		}
+
+		if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) {
+			ret = -EAGAIN;
+			break;
+		}
+
+		if (unlikely(wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq, ffs->ev.count))) {
+			ret = -EINTR;
+			break;
+		}
+
+		return __ffs_ep0_read_events(ffs, buf,
+					     min(n, (size_t)ffs->ev.count));
+
+
+	case FFS_SETUP_PENDING:
+		if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
+			spin_unlock_irq(&ffs->ev.waitq.lock);
+			ret = __ffs_ep0_stall(ffs);
+			goto done_mutex;
+		}
+
+		len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
+
+		spin_unlock_irq(&ffs->ev.waitq.lock);
+
+		if (likely(len)) {
+			data = kmalloc(len, GFP_KERNEL);
+			if (unlikely(!data)) {
+				ret = -ENOMEM;
+				goto done_mutex;
+			}
+		}
+
+		spin_lock_irq(&ffs->ev.waitq.lock);
+
+		/* See ffs_ep0_write() */
+		if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) {
+			ret = -EIDRM;
+			break;
+		}
+
+		/* unlocks spinlock */
+		ret = __ffs_ep0_queue_wait(ffs, data, len);
+		if (likely(ret > 0) && unlikely(__copy_to_user(buf, data, len)))
+			ret = -EFAULT;
+		goto done_mutex;
+
+	default:
+		ret = -EBADFD;
+		break;
+	}
+
+	spin_unlock_irq(&ffs->ev.waitq.lock);
+done_mutex:
+	mutex_unlock(&ffs->mutex);
+	kfree(data);
+	return ret;
+}
+
+
+
+static int ffs_ep0_open(struct inode *inode, struct file *file)
+{
+	struct ffs_data *ffs = inode->i_private;
+
+	ENTER();
+
+	if (unlikely(ffs->state == FFS_CLOSING))
+		return -EBUSY;
+
+	file->private_data = ffs;
+	ffs_data_opened(ffs);
+
+	return 0;
+}
+
+
+static int ffs_ep0_release(struct inode *inode, struct file *file)
+{
+	struct ffs_data *ffs = file->private_data;
+
+	ENTER();
+
+	ffs_data_closed(ffs);
+
+	return 0;
+}
+
+
+static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
+{
+	struct ffs_data *ffs = file->private_data;
+	struct usb_gadget *gadget = ffs->gadget;
+	long ret;
+
+	ENTER();
+
+	if (code == FUNCTIONFS_INTERFACE_REVMAP) {
+		struct ffs_function *func = ffs->func;
+		ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV;
+	} else if (gadget->ops->ioctl) {
+		lock_kernel();
+		ret = gadget->ops->ioctl(gadget, code, value);
+		unlock_kernel();
+	} else {
+		ret = -ENOTTY;
+	}
+
+	return ret;
+}
+
+
+static const struct file_operations ffs_ep0_operations = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+
+	.open =		ffs_ep0_open,
+	.write =	ffs_ep0_write,
+	.read =		ffs_ep0_read,
+	.release =	ffs_ep0_release,
+	.unlocked_ioctl =	ffs_ep0_ioctl,
+};
+
+
+/* "Normal" endpoints operations ********************************************/
+
+
+static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
+{
+	ENTER();
+	if (likely(req->context)) {
+		struct ffs_ep *ep = _ep->driver_data;
+		ep->status = req->status ? req->status : req->actual;
+		complete(req->context);
+	}
+}
+
+
+static ssize_t ffs_epfile_io(struct file *file,
+			     char __user *buf, size_t len, int read)
+{
+	struct ffs_epfile *epfile = file->private_data;
+	struct ffs_ep *ep;
+	char *data = NULL;
+	ssize_t ret;
+	int halt;
+
+	goto first_try;
+	do {
+		spin_unlock_irq(&epfile->ffs->eps_lock);
+		mutex_unlock(&epfile->mutex);
+
+first_try:
+		/* Are we still active? */
+		if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) {
+			ret = -ENODEV;
+			goto error;
+		}
+
+		/* Wait for endpoint to be enabled */
+		ep = epfile->ep;
+		if (!ep) {
+			if (file->f_flags & O_NONBLOCK) {
+				ret = -EAGAIN;
+				goto error;
+			}
+
+			if (unlikely(wait_event_interruptible
+				     (epfile->wait, (ep = epfile->ep)))) {
+				ret = -EINTR;
+				goto error;
+			}
+		}
+
+		/* Do we halt? */
+		halt = !read == !epfile->in;
+		if (halt && epfile->isoc) {
+			ret = -EINVAL;
+			goto error;
+		}
+
+		/* Allocate & copy */
+		if (!halt && !data) {
+			data = kzalloc(len, GFP_KERNEL);
+			if (unlikely(!data))
+				return -ENOMEM;
+
+			if (!read &&
+			    unlikely(__copy_from_user(data, buf, len))) {
+				ret = -EFAULT;
+				goto error;
+			}
+		}
+
+		/* We will be using request */
+		ret = ffs_mutex_lock(&epfile->mutex,
+				     file->f_flags & O_NONBLOCK);
+		if (unlikely(ret))
+			goto error;
+
+		/* We're called from user space, we can use _irq rather then
+		 * _irqsave */
+		spin_lock_irq(&epfile->ffs->eps_lock);
+
+		/* While we were acquiring mutex endpoint got disabled
+		 * or changed? */
+	} while (unlikely(epfile->ep != ep));
+
+	/* Halt */
+	if (unlikely(halt)) {
+		if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep))
+			usb_ep_set_halt(ep->ep);
+		spin_unlock_irq(&epfile->ffs->eps_lock);
+		ret = -EBADMSG;
+	} else {
+		/* Fire the request */
+		DECLARE_COMPLETION_ONSTACK(done);
+
+		struct usb_request *req = ep->req;
+		req->context  = &done;
+		req->complete = ffs_epfile_io_complete;
+		req->buf      = data;
+		req->length   = len;
+
+		ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+
+		spin_unlock_irq(&epfile->ffs->eps_lock);
+
+		if (unlikely(ret < 0)) {
+			/* nop */
+		} else if (unlikely(wait_for_completion_interruptible(&done))) {
+			ret = -EINTR;
+			usb_ep_dequeue(ep->ep, req);
+		} else {
+			ret = ep->status;
+			if (read && ret > 0 &&
+			    unlikely(copy_to_user(buf, data, ret)))
+				ret = -EFAULT;
+		}
+	}
+
+	mutex_unlock(&epfile->mutex);
+error:
+	kfree(data);
+	return ret;
+}
+
+
+static ssize_t
+ffs_epfile_write(struct file *file, const char __user *buf, size_t len,
+		 loff_t *ptr)
+{
+	ENTER();
+
+	return ffs_epfile_io(file, (char __user *)buf, len, 0);
+}
+
+static ssize_t
+ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr)
+{
+	ENTER();
+
+	return ffs_epfile_io(file, buf, len, 1);
+}
+
+static int
+ffs_epfile_open(struct inode *inode, struct file *file)
+{
+	struct ffs_epfile *epfile = inode->i_private;
+
+	ENTER();
+
+	if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
+		return -ENODEV;
+
+	file->private_data = epfile;
+	ffs_data_opened(epfile->ffs);
+
+	return 0;
+}
+
+static int
+ffs_epfile_release(struct inode *inode, struct file *file)
+{
+	struct ffs_epfile *epfile = inode->i_private;
+
+	ENTER();
+
+	ffs_data_closed(epfile->ffs);
+
+	return 0;
+}
+
+
+static long ffs_epfile_ioctl(struct file *file, unsigned code,
+			     unsigned long value)
+{
+	struct ffs_epfile *epfile = file->private_data;
+	int ret;
+
+	ENTER();
+
+	if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
+		return -ENODEV;
+
+	spin_lock_irq(&epfile->ffs->eps_lock);
+	if (likely(epfile->ep)) {
+		switch (code) {
+		case FUNCTIONFS_FIFO_STATUS:
+			ret = usb_ep_fifo_status(epfile->ep->ep);
+			break;
+		case FUNCTIONFS_FIFO_FLUSH:
+			usb_ep_fifo_flush(epfile->ep->ep);
+			ret = 0;
+			break;
+		case FUNCTIONFS_CLEAR_HALT:
+			ret = usb_ep_clear_halt(epfile->ep->ep);
+			break;
+		case FUNCTIONFS_ENDPOINT_REVMAP:
+			ret = epfile->ep->num;
+			break;
+		default:
+			ret = -ENOTTY;
+		}
+	} else {
+		ret = -ENODEV;
+	}
+	spin_unlock_irq(&epfile->ffs->eps_lock);
+
+	return ret;
+}
+
+
+static const struct file_operations ffs_epfile_operations = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+
+	.open =		ffs_epfile_open,
+	.write =	ffs_epfile_write,
+	.read =		ffs_epfile_read,
+	.release =	ffs_epfile_release,
+	.unlocked_ioctl =	ffs_epfile_ioctl,
+};
+
+
+
+/* File system and super block operations ***********************************/
+
+/*
+ * Mounting the filesystem creates a controller file, used first for
+ * function configuration then later for event monitoring.
+ */
+
+
+static struct inode *__must_check
+ffs_sb_make_inode(struct super_block *sb, void *data,
+		  const struct file_operations *fops,
+		  const struct inode_operations *iops,
+		  struct ffs_file_perms *perms)
+{
+	struct inode *inode;
+
+	ENTER();
+
+	inode = new_inode(sb);
+
+	if (likely(inode)) {
+		struct timespec current_time = CURRENT_TIME;
+
+		inode->i_mode    = perms->mode;
+		inode->i_uid     = perms->uid;
+		inode->i_gid     = perms->gid;
+		inode->i_atime   = current_time;
+		inode->i_mtime   = current_time;
+		inode->i_ctime   = current_time;
+		inode->i_private = data;
+		if (fops)
+			inode->i_fop = fops;
+		if (iops)
+			inode->i_op  = iops;
+	}
+
+	return inode;
+}
+
+
+/* Create "regular" file */
+
+static struct inode *ffs_sb_create_file(struct super_block *sb,
+					const char *name, void *data,
+					const struct file_operations *fops,
+					struct dentry **dentry_p)
+{
+	struct ffs_data	*ffs = sb->s_fs_info;
+	struct dentry	*dentry;
+	struct inode	*inode;
+
+	ENTER();
+
+	dentry = d_alloc_name(sb->s_root, name);
+	if (unlikely(!dentry))
+		return NULL;
+
+	inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms);
+	if (unlikely(!inode)) {
+		dput(dentry);
+		return NULL;
+	}
+
+	d_add(dentry, inode);
+	if (dentry_p)
+		*dentry_p = dentry;
+
+	return inode;
+}
+
+
+/* Super block */
+
+static const struct super_operations ffs_sb_operations = {
+	.statfs =	simple_statfs,
+	.drop_inode =	generic_delete_inode,
+};
+
+struct ffs_sb_fill_data {
+	struct ffs_file_perms perms;
+	umode_t root_mode;
+	const char *dev_name;
+};
+
+static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
+{
+	struct ffs_sb_fill_data *data = _data;
+	struct inode	*inode;
+	struct dentry	*d;
+	struct ffs_data	*ffs;
+
+	ENTER();
+
+	/* Initialize data */
+	ffs = ffs_data_new();
+	if (unlikely(!ffs))
+		goto enomem0;
+
+	ffs->sb              = sb;
+	ffs->dev_name        = data->dev_name;
+	ffs->file_perms      = data->perms;
+
+	sb->s_fs_info        = ffs;
+	sb->s_blocksize      = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb->s_magic          = FUNCTIONFS_MAGIC;
+	sb->s_op             = &ffs_sb_operations;
+	sb->s_time_gran      = 1;
+
+	/* Root inode */
+	data->perms.mode = data->root_mode;
+	inode = ffs_sb_make_inode(sb, NULL,
+				  &simple_dir_operations,
+				  &simple_dir_inode_operations,
+				  &data->perms);
+	if (unlikely(!inode))
+		goto enomem1;
+	d = d_alloc_root(inode);
+	if (unlikely(!d))
+		goto enomem2;
+	sb->s_root = d;
+
+	/* EP0 file */
+	if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
+					 &ffs_ep0_operations, NULL)))
+		goto enomem3;
+
+	return 0;
+
+enomem3:
+	dput(d);
+enomem2:
+	iput(inode);
+enomem1:
+	ffs_data_put(ffs);
+enomem0:
+	return -ENOMEM;
+}
+
+
+static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
+{
+	ENTER();
+
+	if (!opts || !*opts)
+		return 0;
+
+	for (;;) {
+		char *end, *eq, *comma;
+		unsigned long value;
+
+		/* Option limit */
+		comma = strchr(opts, ',');
+		if (comma)
+			*comma = 0;
+
+		/* Value limit */
+		eq = strchr(opts, '=');
+		if (unlikely(!eq)) {
+			FERR("'=' missing in %s", opts);
+			return -EINVAL;
+		}
+		*eq = 0;
+
+		/* Parse value */
+		value = simple_strtoul(eq + 1, &end, 0);
+		if (unlikely(*end != ',' && *end != 0)) {
+			FERR("%s: invalid value: %s", opts, eq + 1);
+			return -EINVAL;
+		}
+
+		/* Interpret option */
+		switch (eq - opts) {
+		case 5:
+			if (!memcmp(opts, "rmode", 5))
+				data->root_mode  = (value & 0555) | S_IFDIR;
+			else if (!memcmp(opts, "fmode", 5))
+				data->perms.mode = (value & 0666) | S_IFREG;
+			else
+				goto invalid;
+			break;
+
+		case 4:
+			if (!memcmp(opts, "mode", 4)) {
+				data->root_mode  = (value & 0555) | S_IFDIR;
+				data->perms.mode = (value & 0666) | S_IFREG;
+			} else {
+				goto invalid;
+			}
+			break;
+
+		case 3:
+			if (!memcmp(opts, "uid", 3))
+				data->perms.uid = value;
+			else if (!memcmp(opts, "gid", 3))
+				data->perms.gid = value;
+			else
+				goto invalid;
+			break;
+
+		default:
+invalid:
+			FERR("%s: invalid option", opts);
+			return -EINVAL;
+		}
+
+		/* Next iteration */
+		if (!comma)
+			break;
+		opts = comma + 1;
+	}
+
+	return 0;
+}
+
+
+/* "mount -t functionfs dev_name /dev/function" ends up here */
+
+static int
+ffs_fs_get_sb(struct file_system_type *t, int flags,
+	      const char *dev_name, void *opts, struct vfsmount *mnt)
+{
+	struct ffs_sb_fill_data data = {
+		.perms = {
+			.mode = S_IFREG | 0600,
+			.uid = 0,
+			.gid = 0
+		},
+		.root_mode = S_IFDIR | 0500,
+	};
+	int ret;
+
+	ENTER();
+
+	ret = functionfs_check_dev_callback(dev_name);
+	if (unlikely(ret < 0))
+		return ret;
+
+	ret = ffs_fs_parse_opts(&data, opts);
+	if (unlikely(ret < 0))
+		return ret;
+
+	data.dev_name = dev_name;
+	return get_sb_single(t, flags, &data, ffs_sb_fill, mnt);
+}
+
+static void
+ffs_fs_kill_sb(struct super_block *sb)
+{
+	void *ptr;
+
+	ENTER();
+
+	kill_litter_super(sb);
+	ptr = xchg(&sb->s_fs_info, NULL);
+	if (ptr)
+		ffs_data_put(ptr);
+}
+
+static struct file_system_type ffs_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "functionfs",
+	.get_sb		= ffs_fs_get_sb,
+	.kill_sb	= ffs_fs_kill_sb,
+};
+
+
+
+/* Driver's main init/cleanup functions *************************************/
+
+
+static int functionfs_init(void)
+{
+	int ret;
+
+	ENTER();
+
+	ret = register_filesystem(&ffs_fs_type);
+	if (likely(!ret))
+		FINFO("file system registered");
+	else
+		FERR("failed registering file system (%d)", ret);
+
+	return ret;
+}
+
+static void functionfs_cleanup(void)
+{
+	ENTER();
+
+	FINFO("unloading");
+	unregister_filesystem(&ffs_fs_type);
+}
+
+
+
+/* ffs_data and ffs_function construction and destruction code **************/
+
+static void ffs_data_clear(struct ffs_data *ffs);
+static void ffs_data_reset(struct ffs_data *ffs);
+
+
+static void ffs_data_get(struct ffs_data *ffs)
+{
+	ENTER();
+
+	atomic_inc(&ffs->ref);
+}
+
+static void ffs_data_opened(struct ffs_data *ffs)
+{
+	ENTER();
+
+	atomic_inc(&ffs->ref);
+	atomic_inc(&ffs->opened);
+}
+
+static void ffs_data_put(struct ffs_data *ffs)
+{
+	ENTER();
+
+	if (unlikely(atomic_dec_and_test(&ffs->ref))) {
+		FINFO("%s(): freeing", __func__);
+		ffs_data_clear(ffs);
+		BUG_ON(mutex_is_locked(&ffs->mutex) ||
+		       spin_is_locked(&ffs->ev.waitq.lock) ||
+		       waitqueue_active(&ffs->ev.waitq) ||
+		       waitqueue_active(&ffs->ep0req_completion.wait));
+		kfree(ffs);
+	}
+}
+
+
+
+static void ffs_data_closed(struct ffs_data *ffs)
+{
+	ENTER();
+
+	if (atomic_dec_and_test(&ffs->opened)) {
+		ffs->state = FFS_CLOSING;
+		ffs_data_reset(ffs);
+	}
+
+	ffs_data_put(ffs);
+}
+
+
+static struct ffs_data *ffs_data_new(void)
+{
+	struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
+	if (unlikely(!ffs))
+		return 0;
+
+	ENTER();
+
+	atomic_set(&ffs->ref, 1);
+	atomic_set(&ffs->opened, 0);
+	ffs->state = FFS_READ_DESCRIPTORS;
+	mutex_init(&ffs->mutex);
+	spin_lock_init(&ffs->eps_lock);
+	init_waitqueue_head(&ffs->ev.waitq);
+	init_completion(&ffs->ep0req_completion);
+
+	/* XXX REVISIT need to update it in some places, or do we? */
+	ffs->ev.can_stall = 1;
+
+	return ffs;
+}
+
+
+static void ffs_data_clear(struct ffs_data *ffs)
+{
+	ENTER();
+
+	if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags))
+		functionfs_closed_callback(ffs);
+
+	BUG_ON(ffs->gadget);
+
+	if (ffs->epfiles)
+		ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
+
+	kfree(ffs->raw_descs);
+	kfree(ffs->raw_strings);
+	kfree(ffs->stringtabs);
+}
+
+
+static void ffs_data_reset(struct ffs_data *ffs)
+{
+	ENTER();
+
+	ffs_data_clear(ffs);
+
+	ffs->epfiles = NULL;
+	ffs->raw_descs = NULL;
+	ffs->raw_strings = NULL;
+	ffs->stringtabs = NULL;
+
+	ffs->raw_descs_length = 0;
+	ffs->raw_fs_descs_length = 0;
+	ffs->fs_descs_count = 0;
+	ffs->hs_descs_count = 0;
+
+	ffs->strings_count = 0;
+	ffs->interfaces_count = 0;
+	ffs->eps_count = 0;
+
+	ffs->ev.count = 0;
+
+	ffs->state = FFS_READ_DESCRIPTORS;
+	ffs->setup_state = FFS_NO_SETUP;
+	ffs->flags = 0;
+}
+
+
+static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
+{
+	unsigned i, count;
+
+	ENTER();
+
+	if (WARN_ON(ffs->state != FFS_ACTIVE
+		 || test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
+		return -EBADFD;
+
+	ffs_data_get(ffs);
+
+	ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
+	if (unlikely(!ffs->ep0req))
+		return -ENOMEM;
+	ffs->ep0req->complete = ffs_ep0_complete;
+	ffs->ep0req->context = ffs;
+
+	/* Get strings identifiers */
+	for (count = ffs->strings_count, i = 0; i < count; ++i) {
+		struct usb_gadget_strings **lang;
+
+		int id = usb_string_id(cdev);
+		if (unlikely(id < 0)) {
+			usb_ep_free_request(cdev->gadget->ep0, ffs->ep0req);
+			ffs->ep0req = NULL;
+			return id;
+		}
+
+		lang = ffs->stringtabs;
+		do {
+			(*lang)->strings[i].id = id;
+			++lang;
+		} while (*lang);
+	}
+
+	ffs->gadget = cdev->gadget;
+	return 0;
+}
+
+
+static void functionfs_unbind(struct ffs_data *ffs)
+{
+	ENTER();
+
+	if (!WARN_ON(!ffs->gadget)) {
+		usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
+		ffs->ep0req = NULL;
+		ffs->gadget = NULL;
+		ffs_data_put(ffs);
+	}
+}
+
+
+static int ffs_epfiles_create(struct ffs_data *ffs)
+{
+	struct ffs_epfile *epfile, *epfiles;
+	unsigned i, count;
+
+	ENTER();
+
+	count = ffs->eps_count;
+	epfiles = kzalloc(count * sizeof *epfiles, GFP_KERNEL);
+	if (!epfiles)
+		return -ENOMEM;
+
+	epfile = epfiles;
+	for (i = 1; i <= count; ++i, ++epfile) {
+		epfile->ffs = ffs;
+		mutex_init(&epfile->mutex);
+		init_waitqueue_head(&epfile->wait);
+		sprintf(epfiles->name, "ep%u",  i);
+		if (!unlikely(ffs_sb_create_file(ffs->sb, epfiles->name, epfile,
+						 &ffs_epfile_operations,
+						 &epfile->dentry))) {
+			ffs_epfiles_destroy(epfiles, i - 1);
+			return -ENOMEM;
+		}
+	}
+
+	ffs->epfiles = epfiles;
+	return 0;
+}
+
+
+static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
+{
+	struct ffs_epfile *epfile = epfiles;
+
+	ENTER();
+
+	for (; count; --count, ++epfile) {
+		BUG_ON(mutex_is_locked(&epfile->mutex) ||
+		       waitqueue_active(&epfile->wait));
+		if (epfile->dentry) {
+			d_delete(epfile->dentry);
+			dput(epfile->dentry);
+			epfile->dentry = NULL;
+		}
+	}
+
+	kfree(epfiles);
+}
+
+
+static int functionfs_add(struct usb_composite_dev *cdev,
+			  struct usb_configuration *c,
+			  struct ffs_data *ffs)
+{
+	struct ffs_function *func;
+	int ret;
+
+	ENTER();
+
+	func = kzalloc(sizeof *func, GFP_KERNEL);
+	if (unlikely(!func))
+		return -ENOMEM;
+
+	func->function.name    = "Function FS Gadget";
+	func->function.strings = ffs->stringtabs;
+
+	func->function.bind    = ffs_func_bind;
+	func->function.unbind  = ffs_func_unbind;
+	func->function.set_alt = ffs_func_set_alt;
+	/*func->function.get_alt = ffs_func_get_alt;*/
+	func->function.disable = ffs_func_disable;
+	func->function.setup   = ffs_func_setup;
+	func->function.suspend = ffs_func_suspend;
+	func->function.resume  = ffs_func_resume;
+
+	func->conf   = c;
+	func->gadget = cdev->gadget;
+	func->ffs = ffs;
+	ffs_data_get(ffs);
+
+	ret = usb_add_function(c, &func->function);
+	if (unlikely(ret))
+		ffs_func_free(func);
+
+	return ret;
+}
+
+static void ffs_func_free(struct ffs_function *func)
+{
+	ENTER();
+
+	ffs_data_put(func->ffs);
+
+	kfree(func->eps);
+	/* eps and interfaces_nums are allocated in the same chunk so
+	 * only one free is required.  Descriptors are also allocated
+	 * in the same chunk. */
+
+	kfree(func);
+}
+
+
+static void ffs_func_eps_disable(struct ffs_function *func)
+{
+	struct ffs_ep *ep         = func->eps;
+	struct ffs_epfile *epfile = func->ffs->epfiles;
+	unsigned count            = func->ffs->eps_count;
+	unsigned long flags;
+
+	spin_lock_irqsave(&func->ffs->eps_lock, flags);
+	do {
+		/* pending requests get nuked */
+		if (likely(ep->ep))
+			usb_ep_disable(ep->ep);
+		epfile->ep = NULL;
+
+		++ep;
+		++epfile;
+	} while (--count);
+	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+}
+
+static int ffs_func_eps_enable(struct ffs_function *func)
+{
+	struct ffs_data *ffs      = func->ffs;
+	struct ffs_ep *ep         = func->eps;
+	struct ffs_epfile *epfile = ffs->epfiles;
+	unsigned count            = ffs->eps_count;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&func->ffs->eps_lock, flags);
+	do {
+		struct usb_endpoint_descriptor *ds;
+		ds = ep->descs[ep->descs[1] ? 1 : 0];
+
+		ep->ep->driver_data = ep;
+		ret = usb_ep_enable(ep->ep, ds);
+		if (likely(!ret)) {
+			epfile->ep = ep;
+			epfile->in = usb_endpoint_dir_in(ds);
+			epfile->isoc = usb_endpoint_xfer_isoc(ds);
+		} else {
+			break;
+		}
+
+		wake_up(&epfile->wait);
+
+		++ep;
+		++epfile;
+	} while (--count);
+	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+
+	return ret;
+}
+
+
+/* Parsing and building descriptors and strings *****************************/
+
+
+/* This validates if data pointed by data is a valid USB descriptor as
+ * well as record how many interfaces, endpoints and strings are
+ * required by given configuration.  Returns address afther the
+ * descriptor or NULL if data is invalid. */
+
+enum ffs_entity_type {
+	FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
+};
+
+typedef int (*ffs_entity_callback)(enum ffs_entity_type entity,
+				   u8 *valuep,
+				   struct usb_descriptor_header *desc,
+				   void *priv);
+
+static int __must_check ffs_do_desc(char *data, unsigned len,
+				    ffs_entity_callback entity, void *priv)
+{
+	struct usb_descriptor_header *_ds = (void *)data;
+	u8 length;
+	int ret;
+
+	ENTER();
+
+	/* At least two bytes are required: length and type */
+	if (len < 2) {
+		FVDBG("descriptor too short");
+		return -EINVAL;
+	}
+
+	/* If we have at least as many bytes as the descriptor takes? */
+	length = _ds->bLength;
+	if (len < length) {
+		FVDBG("descriptor longer then available data");
+		return -EINVAL;
+	}
+
+#define __entity_check_INTERFACE(val)  1
+#define __entity_check_STRING(val)     (val)
+#define __entity_check_ENDPOINT(val)   ((val) & USB_ENDPOINT_NUMBER_MASK)
+#define __entity(type, val) do {					\
+		FVDBG("entity " #type "(%02x)", (val));			\
+		if (unlikely(!__entity_check_ ##type(val))) {		\
+			FVDBG("invalid entity's value");		\
+			return -EINVAL;					\
+		}							\
+		ret = entity(FFS_ ##type, &val, _ds, priv);		\
+		if (unlikely(ret < 0)) {				\
+			FDBG("entity " #type "(%02x); ret = %d",	\
+			     (val), ret);				\
+			return ret;					\
+		}							\
+	} while (0)
+
+	/* Parse descriptor depending on type. */
+	switch (_ds->bDescriptorType) {
+	case USB_DT_DEVICE:
+	case USB_DT_CONFIG:
+	case USB_DT_STRING:
+	case USB_DT_DEVICE_QUALIFIER:
+		/* function can't have any of those */
+		FVDBG("descriptor reserved for gadget: %d", _ds->bDescriptorType);
+		return -EINVAL;
+
+	case USB_DT_INTERFACE: {
+		struct usb_interface_descriptor *ds = (void *)_ds;
+		FVDBG("interface descriptor");
+		if (length != sizeof *ds)
+			goto inv_length;
+
+		__entity(INTERFACE, ds->bInterfaceNumber);
+		if (ds->iInterface)
+			__entity(STRING, ds->iInterface);
+	}
+		break;
+
+	case USB_DT_ENDPOINT: {
+		struct usb_endpoint_descriptor *ds = (void *)_ds;
+		FVDBG("endpoint descriptor");
+		if (length != USB_DT_ENDPOINT_SIZE &&
+		    length != USB_DT_ENDPOINT_AUDIO_SIZE)
+			goto inv_length;
+		__entity(ENDPOINT, ds->bEndpointAddress);
+	}
+		break;
+
+	case USB_DT_OTG:
+		if (length != sizeof(struct usb_otg_descriptor))
+			goto inv_length;
+		break;
+
+	case USB_DT_INTERFACE_ASSOCIATION: {
+		struct usb_interface_assoc_descriptor *ds = (void *)_ds;
+		FVDBG("interface association descriptor");
+		if (length != sizeof *ds)
+			goto inv_length;
+		if (ds->iFunction)
+			__entity(STRING, ds->iFunction);
+	}
+		break;
+
+	case USB_DT_OTHER_SPEED_CONFIG:
+	case USB_DT_INTERFACE_POWER:
+	case USB_DT_DEBUG:
+	case USB_DT_SECURITY:
+	case USB_DT_CS_RADIO_CONTROL:
+		/* TODO */
+		FVDBG("unimplemented descriptor: %d", _ds->bDescriptorType);
+		return -EINVAL;
+
+	default:
+		/* We should never be here */
+		FVDBG("unknown descriptor: %d", _ds->bDescriptorType);
+		return -EINVAL;
+
+	inv_length:
+		FVDBG("invalid length: %d (descriptor %d)",
+		      _ds->bLength, _ds->bDescriptorType);
+		return -EINVAL;
+	}
+
+#undef __entity
+#undef __entity_check_DESCRIPTOR
+#undef __entity_check_INTERFACE
+#undef __entity_check_STRING
+#undef __entity_check_ENDPOINT
+
+	return length;
+}
+
+
+static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
+				     ffs_entity_callback entity, void *priv)
+{
+	const unsigned _len = len;
+	unsigned long num = 0;
+
+	ENTER();
+
+	for (;;) {
+		int ret;
+
+		if (num == count)
+			data = NULL;
+
+		/* Record "descriptor" entitny */
+		ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv);
+		if (unlikely(ret < 0)) {
+			FDBG("entity DESCRIPTOR(%02lx); ret = %d", num, ret);
+			return ret;
+		}
+
+		if (!data)
+			return _len - len;
+
+		ret = ffs_do_desc(data, len, entity, priv);
+		if (unlikely(ret < 0)) {
+			FDBG("%s returns %d", __func__, ret);
+			return ret;
+		}
+
+		len -= ret;
+		data += ret;
+		++num;
+	}
+}
+
+
+static int __ffs_data_do_entity(enum ffs_entity_type type,
+				u8 *valuep, struct usb_descriptor_header *desc,
+				void *priv)
+{
+	struct ffs_data *ffs = priv;
+
+	ENTER();
+
+	switch (type) {
+	case FFS_DESCRIPTOR:
+		break;
+
+	case FFS_INTERFACE:
+		/* Interfaces are indexed from zero so if we
+		 * encountered interface "n" then there are at least
+		 * "n+1" interfaces. */
+		if (*valuep >= ffs->interfaces_count)
+			ffs->interfaces_count = *valuep + 1;
+		break;
+
+	case FFS_STRING:
+		/* Strings are indexed from 1 (0 is magic ;) reserved
+		 * for languages list or some such) */
+		if (*valuep > ffs->strings_count)
+			ffs->strings_count = *valuep;
+		break;
+
+	case FFS_ENDPOINT:
+		/* Endpoints are indexed from 1 as well. */
+		if ((*valuep & USB_ENDPOINT_NUMBER_MASK) > ffs->eps_count)
+			ffs->eps_count = (*valuep & USB_ENDPOINT_NUMBER_MASK);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int __ffs_data_got_descs(struct ffs_data *ffs,
+				char *const _data, size_t len)
+{
+	unsigned fs_count, hs_count;
+	int fs_len, ret = -EINVAL;
+	char *data = _data;
+
+	ENTER();
+
+	if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC ||
+		     get_unaligned_le32(data + 4) != len))
+		goto error;
+	fs_count = get_unaligned_le32(data +  8);
+	hs_count = get_unaligned_le32(data + 12);
+
+	if (!fs_count && !hs_count)
+		goto einval;
+
+	data += 16;
+	len  -= 16;
+
+	if (likely(fs_count)) {
+		fs_len = ffs_do_descs(fs_count, data, len,
+				      __ffs_data_do_entity, ffs);
+		if (unlikely(fs_len < 0)) {
+			ret = fs_len;
+			goto error;
+		}
+
+		data += fs_len;
+		len  -= fs_len;
+	} else {
+		fs_len = 0;
+	}
+
+	if (likely(hs_count)) {
+		ret = ffs_do_descs(hs_count, data, len,
+				   __ffs_data_do_entity, ffs);
+		if (unlikely(ret < 0))
+			goto error;
+	} else {
+		ret = 0;
+	}
+
+	if (unlikely(len != ret))
+		goto einval;
+
+	ffs->raw_fs_descs_length = fs_len;
+	ffs->raw_descs_length    = fs_len + ret;
+	ffs->raw_descs           = _data;
+	ffs->fs_descs_count      = fs_count;
+	ffs->hs_descs_count      = hs_count;
+
+	return 0;
+
+einval:
+	ret = -EINVAL;
+error:
+	kfree(_data);
+	return ret;
+}
+
+
+
+static int __ffs_data_got_strings(struct ffs_data *ffs,
+				  char *const _data, size_t len)
+{
+	u32 str_count, needed_count, lang_count;
+	struct usb_gadget_strings **stringtabs, *t;
+	struct usb_string *strings, *s;
+	const char *data = _data;
+
+	ENTER();
+
+	if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
+		     get_unaligned_le32(data + 4) != len))
+		goto error;
+	str_count  = get_unaligned_le32(data + 8);
+	lang_count = get_unaligned_le32(data + 12);
+
+	/* if one is zero the other must be zero */
+	if (unlikely(!str_count != !lang_count))
+		goto error;
+
+	/* Do we have at least as many strings as descriptors need? */
+	needed_count = ffs->strings_count;
+	if (unlikely(str_count < needed_count))
+		goto error;
+
+	/* If we don't need any strings just return and free all
+	 * memory */
+	if (!needed_count) {
+		kfree(_data);
+		return 0;
+	}
+
+	/* Allocate */
+	{
+		/* Allocate everything in one chunk so there's less
+		 * maintanance. */
+		struct {
+			struct usb_gadget_strings *stringtabs[lang_count + 1];
+			struct usb_gadget_strings stringtab[lang_count];
+			struct usb_string strings[lang_count*(needed_count+1)];
+		} *d;
+		unsigned i = 0;
+
+		d = kmalloc(sizeof *d, GFP_KERNEL);
+		if (unlikely(!d)) {
+			kfree(_data);
+			return -ENOMEM;
+		}
+
+		stringtabs = d->stringtabs;
+		t = d->stringtab;
+		i = lang_count;
+		do {
+			*stringtabs++ = t++;
+		} while (--i);
+		*stringtabs = NULL;
+
+		stringtabs = d->stringtabs;
+		t = d->stringtab;
+		s = d->strings;
+		strings = s;
+	}
+
+	/* For each language */
+	data += 16;
+	len -= 16;
+
+	do { /* lang_count > 0 so we can use do-while */
+		unsigned needed = needed_count;
+
+		if (unlikely(len < 3))
+			goto error_free;
+		t->language = get_unaligned_le16(data);
+		t->strings  = s;
+		++t;
+
+		data += 2;
+		len -= 2;
+
+		/* For each string */
+		do { /* str_count > 0 so we can use do-while */
+			size_t length = strnlen(data, len);
+
+			if (unlikely(length == len))
+				goto error_free;
+
+			/* user may provide more strings then we need,
+			 * if that's the case we simply ingore the
+			 * rest */
+			if (likely(needed)) {
+				/* s->id will be set while adding
+				 * function to configuration so for
+				 * now just leave garbage here. */
+				s->s = data;
+				--needed;
+				++s;
+			}
+
+			data += length + 1;
+			len -= length + 1;
+		} while (--str_count);
+
+		s->id = 0;   /* terminator */
+		s->s = NULL;
+		++s;
+
+	} while (--lang_count);
+
+	/* Some garbage left? */
+	if (unlikely(len))
+		goto error_free;
+
+	/* Done! */
+	ffs->stringtabs = stringtabs;
+	ffs->raw_strings = _data;
+
+	return 0;
+
+error_free:
+	kfree(stringtabs);
+error:
+	kfree(_data);
+	return -EINVAL;
+}
+
+
+
+
+/* Events handling and management *******************************************/
+
+static void __ffs_event_add(struct ffs_data *ffs,
+			    enum usb_functionfs_event_type type)
+{
+	enum usb_functionfs_event_type rem_type1, rem_type2 = type;
+	int neg = 0;
+
+	/* Abort any unhandled setup */
+	/* We do not need to worry about some cmpxchg() changing value
+	 * of ffs->setup_state without holding the lock because when
+	 * state is FFS_SETUP_PENDING cmpxchg() in several places in
+	 * the source does nothing. */
+	if (ffs->setup_state == FFS_SETUP_PENDING)
+		ffs->setup_state = FFS_SETUP_CANCELED;
+
+	switch (type) {
+	case FUNCTIONFS_RESUME:
+		rem_type2 = FUNCTIONFS_SUSPEND;
+		/* FALL THGOUTH */
+	case FUNCTIONFS_SUSPEND:
+	case FUNCTIONFS_SETUP:
+		rem_type1 = type;
+		/* discard all similar events */
+		break;
+
+	case FUNCTIONFS_BIND:
+	case FUNCTIONFS_UNBIND:
+	case FUNCTIONFS_DISABLE:
+	case FUNCTIONFS_ENABLE:
+		/* discard everything other then power management. */
+		rem_type1 = FUNCTIONFS_SUSPEND;
+		rem_type2 = FUNCTIONFS_RESUME;
+		neg = 1;
+		break;
+
+	default:
+		BUG();
+	}
+
+	{
+		u8 *ev  = ffs->ev.types, *out = ev;
+		unsigned n = ffs->ev.count;
+		for (; n; --n, ++ev)
+			if ((*ev == rem_type1 || *ev == rem_type2) == neg)
+				*out++ = *ev;
+			else
+				FVDBG("purging event %d", *ev);
+		ffs->ev.count = out - ffs->ev.types;
+	}
+
+	FVDBG("adding event %d", type);
+	ffs->ev.types[ffs->ev.count++] = type;
+	wake_up_locked(&ffs->ev.waitq);
+}
+
+static void ffs_event_add(struct ffs_data *ffs,
+			  enum usb_functionfs_event_type type)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
+	__ffs_event_add(ffs, type);
+	spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
+}
+
+
+/* Bind/unbind USB function hooks *******************************************/
+
+static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
+				    struct usb_descriptor_header *desc,
+				    void *priv)
+{
+	struct usb_endpoint_descriptor *ds = (void *)desc;
+	struct ffs_function *func = priv;
+	struct ffs_ep *ffs_ep;
+
+	/* If hs_descriptors is not NULL then we are reading hs
+	 * descriptors now */
+	const int isHS = func->function.hs_descriptors != NULL;
+	unsigned idx;
+
+	if (type != FFS_DESCRIPTOR)
+		return 0;
+
+	if (isHS)
+		func->function.hs_descriptors[(long)valuep] = desc;
+	else
+		func->function.descriptors[(long)valuep]    = desc;
+
+	if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
+		return 0;
+
+	idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;
+	ffs_ep = func->eps + idx;
+
+	if (unlikely(ffs_ep->descs[isHS])) {
+		FVDBG("two %sspeed descriptors for EP %d",
+		      isHS ? "high" : "full",
+		      ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+		return -EINVAL;
+	}
+	ffs_ep->descs[isHS] = ds;
+
+	ffs_dump_mem(": Original  ep desc", ds, ds->bLength);
+	if (ffs_ep->ep) {
+		ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress;
+		if (!ds->wMaxPacketSize)
+			ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize;
+	} else {
+		struct usb_request *req;
+		struct usb_ep *ep;
+
+		FVDBG("autoconfig");
+		ep = usb_ep_autoconfig(func->gadget, ds);
+		if (unlikely(!ep))
+			return -ENOTSUPP;
+		ep->driver_data = func->eps + idx;;
+
+		req = usb_ep_alloc_request(ep, GFP_KERNEL);
+		if (unlikely(!req))
+			return -ENOMEM;
+
+		ffs_ep->ep  = ep;
+		ffs_ep->req = req;
+		func->eps_revmap[ds->bEndpointAddress &
+				 USB_ENDPOINT_NUMBER_MASK] = idx + 1;
+	}
+	ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength);
+
+	return 0;
+}
+
+
+static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
+				   struct usb_descriptor_header *desc,
+				   void *priv)
+{
+	struct ffs_function *func = priv;
+	unsigned idx;
+	u8 newValue;
+
+	switch (type) {
+	default:
+	case FFS_DESCRIPTOR:
+		/* Handled in previous pass by __ffs_func_bind_do_descs() */
+		return 0;
+
+	case FFS_INTERFACE:
+		idx = *valuep;
+		if (func->interfaces_nums[idx] < 0) {
+			int id = usb_interface_id(func->conf, &func->function);
+			if (unlikely(id < 0))
+				return id;
+			func->interfaces_nums[idx] = id;
+		}
+		newValue = func->interfaces_nums[idx];
+		break;
+
+	case FFS_STRING:
+		/* String' IDs are allocated when fsf_data is bound to cdev */
+		newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id;
+		break;
+
+	case FFS_ENDPOINT:
+		/* USB_DT_ENDPOINT are handled in
+		 * __ffs_func_bind_do_descs(). */
+		if (desc->bDescriptorType == USB_DT_ENDPOINT)
+			return 0;
+
+		idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1;
+		if (unlikely(!func->eps[idx].ep))
+			return -EINVAL;
+
+		{
+			struct usb_endpoint_descriptor **descs;
+			descs = func->eps[idx].descs;
+			newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress;
+		}
+		break;
+	}
+
+	FVDBG("%02x -> %02x", *valuep, newValue);
+	*valuep = newValue;
+	return 0;
+}
+
+static int ffs_func_bind(struct usb_configuration *c,
+			 struct usb_function *f)
+{
+	struct ffs_function *func = ffs_func_from_usb(f);
+	struct ffs_data *ffs = func->ffs;
+
+	const int full = !!func->ffs->fs_descs_count;
+	const int high = gadget_is_dualspeed(func->gadget) &&
+		func->ffs->hs_descs_count;
+
+	int ret;
+
+	/* Make it a single chunk, less management later on */
+	struct {
+		struct ffs_ep eps[ffs->eps_count];
+		struct usb_descriptor_header
+			*fs_descs[full ? ffs->fs_descs_count + 1 : 0];
+		struct usb_descriptor_header
+			*hs_descs[high ? ffs->hs_descs_count + 1 : 0];
+		short inums[ffs->interfaces_count];
+		char raw_descs[high ? ffs->raw_descs_length
+				    : ffs->raw_fs_descs_length];
+	} *data;
+
+	ENTER();
+
+	/* Only high speed but not supported by gadget? */
+	if (unlikely(!(full | high)))
+		return -ENOTSUPP;
+
+	/* Allocate */
+	data = kmalloc(sizeof *data, GFP_KERNEL);
+	if (unlikely(!data))
+		return -ENOMEM;
+
+	/* Zero */
+	memset(data->eps, 0, sizeof data->eps);
+	memcpy(data->raw_descs, ffs->raw_descs + 16, sizeof data->raw_descs);
+	memset(data->inums, 0xff, sizeof data->inums);
+	for (ret = ffs->eps_count; ret; --ret)
+		data->eps[ret].num = -1;
+
+	/* Save pointers */
+	func->eps             = data->eps;
+	func->interfaces_nums = data->inums;
+
+	/* Go throught all the endpoint descriptors and allocate
+	 * endpoints first, so that later we can rewrite the endpoint
+	 * numbers without worying that it may be described later on. */
+	if (likely(full)) {
+		func->function.descriptors = data->fs_descs;
+		ret = ffs_do_descs(ffs->fs_descs_count,
+				   data->raw_descs,
+				   sizeof data->raw_descs,
+				   __ffs_func_bind_do_descs, func);
+		if (unlikely(ret < 0))
+			goto error;
+	} else {
+		ret = 0;
+	}
+
+	if (likely(high)) {
+		func->function.hs_descriptors = data->hs_descs;
+		ret = ffs_do_descs(ffs->hs_descs_count,
+				   data->raw_descs + ret,
+				   (sizeof data->raw_descs) - ret,
+				   __ffs_func_bind_do_descs, func);
+	}
+
+	/* Now handle interface numbers allocation and interface and
+	 * enpoint numbers rewritting.  We can do that in one go
+	 * now. */
+	ret = ffs_do_descs(ffs->fs_descs_count +
+			   (high ? ffs->hs_descs_count : 0),
+			   data->raw_descs, sizeof data->raw_descs,
+			   __ffs_func_bind_do_nums, func);
+	if (unlikely(ret < 0))
+		goto error;
+
+	/* And we're done */
+	ffs_event_add(ffs, FUNCTIONFS_BIND);
+	return 0;
+
+error:
+	/* XXX Do we need to release all claimed endpoints here? */
+	return ret;
+}
+
+
+/* Other USB function hooks *************************************************/
+
+static void ffs_func_unbind(struct usb_configuration *c,
+			    struct usb_function *f)
+{
+	struct ffs_function *func = ffs_func_from_usb(f);
+	struct ffs_data *ffs = func->ffs;
+
+	ENTER();
+
+	if (ffs->func == func) {
+		ffs_func_eps_disable(func);
+		ffs->func = NULL;
+	}
+
+	ffs_event_add(ffs, FUNCTIONFS_UNBIND);
+
+	ffs_func_free(func);
+}
+
+
+static int ffs_func_set_alt(struct usb_function *f,
+			    unsigned interface, unsigned alt)
+{
+	struct ffs_function *func = ffs_func_from_usb(f);
+	struct ffs_data *ffs = func->ffs;
+	int ret = 0, intf;
+
+	if (alt != (unsigned)-1) {
+		intf = ffs_func_revmap_intf(func, interface);
+		if (unlikely(intf < 0))
+			return intf;
+	}
+
+	if (ffs->func)
+		ffs_func_eps_disable(ffs->func);
+
+	if (ffs->state != FFS_ACTIVE)
+		return -ENODEV;
+
+	if (alt == (unsigned)-1) {
+		ffs->func = NULL;
+		ffs_event_add(ffs, FUNCTIONFS_DISABLE);
+		return 0;
+	}
+
+	ffs->func = func;
+	ret = ffs_func_eps_enable(func);
+	if (likely(ret >= 0))
+		ffs_event_add(ffs, FUNCTIONFS_ENABLE);
+	return ret;
+}
+
+static void ffs_func_disable(struct usb_function *f)
+{
+	ffs_func_set_alt(f, 0, (unsigned)-1);
+}
+
+static int ffs_func_setup(struct usb_function *f,
+			  const struct usb_ctrlrequest *creq)
+{
+	struct ffs_function *func = ffs_func_from_usb(f);
+	struct ffs_data *ffs = func->ffs;
+	unsigned long flags;
+	int ret;
+
+	ENTER();
+
+	FVDBG("creq->bRequestType = %02x", creq->bRequestType);
+	FVDBG("creq->bRequest     = %02x", creq->bRequest);
+	FVDBG("creq->wValue       = %04x", le16_to_cpu(creq->wValue));
+	FVDBG("creq->wIndex       = %04x", le16_to_cpu(creq->wIndex));
+	FVDBG("creq->wLength      = %04x", le16_to_cpu(creq->wLength));
+
+	/* Most requests directed to interface go throught here
+	 * (notable exceptions are set/get interface) so we need to
+	 * handle them.  All other either handled by composite or
+	 * passed to usb_configuration->setup() (if one is set).  No
+	 * matter, we will handle requests directed to endpoint here
+	 * as well (as it's straightforward) but what to do with any
+	 * other request? */
+
+	if (ffs->state != FFS_ACTIVE)
+		return -ENODEV;
+
+	switch (creq->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_INTERFACE:
+		ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex));
+		if (unlikely(ret < 0))
+			return ret;
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex));
+		if (unlikely(ret < 0))
+			return ret;
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
+	ffs->ev.setup = *creq;
+	ffs->ev.setup.wIndex = cpu_to_le16(ret);
+	__ffs_event_add(ffs, FUNCTIONFS_SETUP);
+	spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
+
+	return 0;
+}
+
+static void ffs_func_suspend(struct usb_function *f)
+{
+	ENTER();
+	ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND);
+}
+
+static void ffs_func_resume(struct usb_function *f)
+{
+	ENTER();
+	ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME);
+}
+
+
+
+/* Enpoint and interface numbers reverse mapping ****************************/
+
+static int ffs_func_revmap_ep(struct ffs_function *func, u8 num)
+{
+	num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK];
+	return num ? num : -EDOM;
+}
+
+static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)
+{
+	short *nums = func->interfaces_nums;
+	unsigned count = func->ffs->interfaces_count;
+
+	for (; count; --count, ++nums) {
+		if (*nums >= 0 && *nums == intf)
+			return nums - func->interfaces_nums;
+	}
+
+	return -EDOM;
+}
+
+
+/* Misc helper functions ****************************************************/
+
+static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
+{
+	return nonblock
+		? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN
+		: mutex_lock_interruptible(mutex);
+}
+
+
+static char *ffs_prepare_buffer(const char * __user buf, size_t len)
+{
+	char *data;
+
+	if (unlikely(!len))
+		return NULL;
+
+	data = kmalloc(len, GFP_KERNEL);
+	if (unlikely(!data))
+		return ERR_PTR(-ENOMEM);
+
+	if (unlikely(__copy_from_user(data, buf, len))) {
+		kfree(data);
+		return ERR_PTR(-EFAULT);
+	}
+
+	FVDBG("Buffer from user space:");
+	ffs_dump_mem("", data, len);
+
+	return data;
+}
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
new file mode 100644
index 0000000..1e00ff9
--- /dev/null
+++ b/drivers/usb/gadget/f_hid.c
@@ -0,0 +1,673 @@
+/*
+ * f_hid.c -- USB HID function driver
+ *
+ * Copyright (C) 2010 Fabien Chouteau <fabien.chouteau@barco.com>
+ *
+ * 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/kernel.h>
+#include <linux/utsname.h>
+#include <linux/module.h>
+#include <linux/hid.h>
+#include <linux/cdev.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/smp_lock.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/usb/g_hid.h>
+
+static int major, minors;
+static struct class *hidg_class;
+
+/*-------------------------------------------------------------------------*/
+/*                            HID gadget struct                            */
+
+struct f_hidg {
+	/* configuration */
+	unsigned char			bInterfaceSubClass;
+	unsigned char			bInterfaceProtocol;
+	unsigned short			report_desc_length;
+	char				*report_desc;
+	unsigned short			report_length;
+
+	/* recv report */
+	char				*set_report_buff;
+	unsigned short			set_report_length;
+	spinlock_t			spinlock;
+	wait_queue_head_t		read_queue;
+
+	/* send report */
+	struct mutex			lock;
+	bool				write_pending;
+	wait_queue_head_t		write_queue;
+	struct usb_request		*req;
+
+	int				minor;
+	struct cdev			cdev;
+	struct usb_function		func;
+	struct usb_ep			*in_ep;
+	struct usb_endpoint_descriptor	*fs_in_ep_desc;
+	struct usb_endpoint_descriptor	*hs_in_ep_desc;
+};
+
+static inline struct f_hidg *func_to_hidg(struct usb_function *f)
+{
+	return container_of(f, struct f_hidg, func);
+}
+
+/*-------------------------------------------------------------------------*/
+/*                           Static descriptors                            */
+
+static struct usb_interface_descriptor hidg_interface_desc = {
+	.bLength		= sizeof hidg_interface_desc,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	/* .bInterfaceNumber	= DYNAMIC */
+	.bAlternateSetting	= 0,
+	.bNumEndpoints		= 1,
+	.bInterfaceClass	= USB_CLASS_HID,
+	/* .bInterfaceSubClass	= DYNAMIC */
+	/* .bInterfaceProtocol	= DYNAMIC */
+	/* .iInterface		= DYNAMIC */
+};
+
+static struct hid_descriptor hidg_desc = {
+	.bLength			= sizeof hidg_desc,
+	.bDescriptorType		= HID_DT_HID,
+	.bcdHID				= 0x0101,
+	.bCountryCode			= 0x00,
+	.bNumDescriptors		= 0x1,
+	/*.desc[0].bDescriptorType	= DYNAMIC */
+	/*.desc[0].wDescriptorLenght	= DYNAMIC */
+};
+
+/* High-Speed Support */
+
+static struct usb_endpoint_descriptor hidg_hs_in_ep_desc = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_IN,
+	.bmAttributes		= USB_ENDPOINT_XFER_INT,
+	/*.wMaxPacketSize	= DYNAMIC */
+	.bInterval		= 4, /* FIXME: Add this field in the
+				      * HID gadget configuration?
+				      * (struct hidg_func_descriptor)
+				      */
+};
+
+static struct usb_descriptor_header *hidg_hs_descriptors[] = {
+	(struct usb_descriptor_header *)&hidg_interface_desc,
+	(struct usb_descriptor_header *)&hidg_desc,
+	(struct usb_descriptor_header *)&hidg_hs_in_ep_desc,
+	NULL,
+};
+
+/* Full-Speed Support */
+
+static struct usb_endpoint_descriptor hidg_fs_in_ep_desc = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_IN,
+	.bmAttributes		= USB_ENDPOINT_XFER_INT,
+	/*.wMaxPacketSize	= DYNAMIC */
+	.bInterval		= 10, /* FIXME: Add this field in the
+				       * HID gadget configuration?
+				       * (struct hidg_func_descriptor)
+				       */
+};
+
+static struct usb_descriptor_header *hidg_fs_descriptors[] = {
+	(struct usb_descriptor_header *)&hidg_interface_desc,
+	(struct usb_descriptor_header *)&hidg_desc,
+	(struct usb_descriptor_header *)&hidg_fs_in_ep_desc,
+	NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+/*                              Char Device                                */
+
+static ssize_t f_hidg_read(struct file *file, char __user *buffer,
+			size_t count, loff_t *ptr)
+{
+	struct f_hidg	*hidg     = (struct f_hidg *)file->private_data;
+	char		*tmp_buff = NULL;
+	unsigned long	flags;
+
+	if (!count)
+		return 0;
+
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
+
+	spin_lock_irqsave(&hidg->spinlock, flags);
+
+#define READ_COND (hidg->set_report_buff != NULL)
+
+	while (!READ_COND) {
+		spin_unlock_irqrestore(&hidg->spinlock, flags);
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		if (wait_event_interruptible(hidg->read_queue, READ_COND))
+			return -ERESTARTSYS;
+
+		spin_lock_irqsave(&hidg->spinlock, flags);
+	}
+
+
+	count = min_t(unsigned, count, hidg->set_report_length);
+	tmp_buff = hidg->set_report_buff;
+	hidg->set_report_buff = NULL;
+
+	spin_unlock_irqrestore(&hidg->spinlock, flags);
+
+	if (tmp_buff != NULL) {
+		/* copy to user outside spinlock */
+		count -= copy_to_user(buffer, tmp_buff, count);
+		kfree(tmp_buff);
+	} else
+		count = -ENOMEM;
+
+	return count;
+}
+
+static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_hidg *hidg = (struct f_hidg *)ep->driver_data;
+
+	if (req->status != 0) {
+		ERROR(hidg->func.config->cdev,
+			"End Point Request ERROR: %d\n", req->status);
+	}
+
+	hidg->write_pending = 0;
+	wake_up(&hidg->write_queue);
+}
+
+static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
+			    size_t count, loff_t *offp)
+{
+	struct f_hidg *hidg  = (struct f_hidg *)file->private_data;
+	ssize_t status = -ENOMEM;
+
+	if (!access_ok(VERIFY_READ, buffer, count))
+		return -EFAULT;
+
+	mutex_lock(&hidg->lock);
+
+#define WRITE_COND (!hidg->write_pending)
+
+	/* write queue */
+	while (!WRITE_COND) {
+		mutex_unlock(&hidg->lock);
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		if (wait_event_interruptible_exclusive(
+				hidg->write_queue, WRITE_COND))
+			return -ERESTARTSYS;
+
+		mutex_lock(&hidg->lock);
+	}
+
+	count  = min_t(unsigned, count, hidg->report_length);
+	status = copy_from_user(hidg->req->buf, buffer, count);
+
+	if (status != 0) {
+		ERROR(hidg->func.config->cdev,
+			"copy_from_user error\n");
+		mutex_unlock(&hidg->lock);
+		return -EINVAL;
+	}
+
+	hidg->req->status   = 0;
+	hidg->req->zero     = 0;
+	hidg->req->length   = count;
+	hidg->req->complete = f_hidg_req_complete;
+	hidg->req->context  = hidg;
+	hidg->write_pending = 1;
+
+	status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC);
+	if (status < 0) {
+		ERROR(hidg->func.config->cdev,
+			"usb_ep_queue error on int endpoint %zd\n", status);
+		hidg->write_pending = 0;
+		wake_up(&hidg->write_queue);
+	} else {
+		status = count;
+	}
+
+	mutex_unlock(&hidg->lock);
+
+	return status;
+}
+
+static unsigned int f_hidg_poll(struct file *file, poll_table *wait)
+{
+	struct f_hidg	*hidg  = (struct f_hidg *)file->private_data;
+	unsigned int	ret = 0;
+
+	poll_wait(file, &hidg->read_queue, wait);
+	poll_wait(file, &hidg->write_queue, wait);
+
+	if (WRITE_COND)
+		ret |= POLLOUT | POLLWRNORM;
+
+	if (READ_COND)
+		ret |= POLLIN | POLLRDNORM;
+
+	return ret;
+}
+
+#undef WRITE_COND
+#undef READ_COND
+
+static int f_hidg_release(struct inode *inode, struct file *fd)
+{
+	fd->private_data = NULL;
+	return 0;
+}
+
+static int f_hidg_open(struct inode *inode, struct file *fd)
+{
+	struct f_hidg *hidg =
+		container_of(inode->i_cdev, struct f_hidg, cdev);
+
+	fd->private_data = hidg;
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+/*                                usb_function                             */
+
+static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_hidg *hidg = (struct f_hidg *)req->context;
+
+	if (req->status != 0 || req->buf == NULL || req->actual == 0) {
+		ERROR(hidg->func.config->cdev, "%s FAILED\n", __func__);
+		return;
+	}
+
+	spin_lock(&hidg->spinlock);
+
+	hidg->set_report_buff = krealloc(hidg->set_report_buff,
+					 req->actual, GFP_ATOMIC);
+
+	if (hidg->set_report_buff == NULL) {
+		spin_unlock(&hidg->spinlock);
+		return;
+	}
+	hidg->set_report_length = req->actual;
+	memcpy(hidg->set_report_buff, req->buf, req->actual);
+
+	spin_unlock(&hidg->spinlock);
+
+	wake_up(&hidg->read_queue);
+
+	return;
+}
+
+static int hidg_setup(struct usb_function *f,
+		const struct usb_ctrlrequest *ctrl)
+{
+	struct f_hidg			*hidg = func_to_hidg(f);
+	struct usb_composite_dev	*cdev = f->config->cdev;
+	struct usb_request		*req  = cdev->req;
+	int status = 0;
+	__u16 value, length;
+
+	value	= __le16_to_cpu(ctrl->wValue);
+	length	= __le16_to_cpu(ctrl->wLength);
+
+	VDBG(cdev, "hid_setup crtl_request : bRequestType:0x%x bRequest:0x%x "
+		"Value:0x%x\n", ctrl->bRequestType, ctrl->bRequest, value);
+
+	switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
+		  | HID_REQ_GET_REPORT):
+		VDBG(cdev, "get_report\n");
+
+		/* send an empty report */
+		length = min_t(unsigned, length, hidg->report_length);
+		memset(req->buf, 0x0, length);
+
+		goto respond;
+		break;
+
+	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
+		  | HID_REQ_GET_PROTOCOL):
+		VDBG(cdev, "get_protocol\n");
+		goto stall;
+		break;
+
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
+		  | HID_REQ_SET_REPORT):
+		VDBG(cdev, "set_report | wLenght=%d\n", ctrl->wLength);
+		req->context  = hidg;
+		req->complete = hidg_set_report_complete;
+		goto respond;
+		break;
+
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
+		  | HID_REQ_SET_PROTOCOL):
+		VDBG(cdev, "set_protocol\n");
+		goto stall;
+		break;
+
+	case ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8
+		  | USB_REQ_GET_DESCRIPTOR):
+		switch (value >> 8) {
+		case HID_DT_REPORT:
+			VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: REPORT\n");
+			length = min_t(unsigned short, length,
+						   hidg->report_desc_length);
+			memcpy(req->buf, hidg->report_desc, length);
+			goto respond;
+			break;
+
+		default:
+			VDBG(cdev, "Unknown decriptor request 0x%x\n",
+				 value >> 8);
+			goto stall;
+			break;
+		}
+		break;
+
+	default:
+		VDBG(cdev, "Unknown request 0x%x\n",
+			 ctrl->bRequest);
+		goto stall;
+		break;
+	}
+
+stall:
+	return -EOPNOTSUPP;
+
+respond:
+	req->zero = 0;
+	req->length = length;
+	status = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+	if (status < 0)
+		ERROR(cdev, "usb_ep_queue error on ep0 %d\n", value);
+	return status;
+}
+
+static void hidg_disable(struct usb_function *f)
+{
+	struct f_hidg *hidg = func_to_hidg(f);
+
+	usb_ep_disable(hidg->in_ep);
+	hidg->in_ep->driver_data = NULL;
+
+	return;
+}
+
+static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct usb_composite_dev		*cdev = f->config->cdev;
+	struct f_hidg				*hidg = func_to_hidg(f);
+	const struct usb_endpoint_descriptor	*ep_desc;
+	int status = 0;
+
+	VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
+
+	if (hidg->in_ep != NULL) {
+		/* restart endpoint */
+		if (hidg->in_ep->driver_data != NULL)
+			usb_ep_disable(hidg->in_ep);
+
+		ep_desc = ep_choose(f->config->cdev->gadget,
+				hidg->hs_in_ep_desc, hidg->fs_in_ep_desc);
+		status = usb_ep_enable(hidg->in_ep, ep_desc);
+		if (status < 0) {
+			ERROR(cdev, "Enable endpoint FAILED!\n");
+			goto fail;
+		}
+		hidg->in_ep->driver_data = hidg;
+	}
+fail:
+	return status;
+}
+
+const struct file_operations f_hidg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= f_hidg_open,
+	.release	= f_hidg_release,
+	.write		= f_hidg_write,
+	.read		= f_hidg_read,
+	.poll		= f_hidg_poll,
+};
+
+static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_ep		*ep;
+	struct f_hidg		*hidg = func_to_hidg(f);
+	int			status;
+	dev_t			dev;
+
+	/* allocate instance-specific interface IDs, and patch descriptors */
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto fail;
+	hidg_interface_desc.bInterfaceNumber = status;
+
+
+	/* allocate instance-specific endpoints */
+	status = -ENODEV;
+	ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc);
+	if (!ep)
+		goto fail;
+	ep->driver_data = c->cdev;	/* claim */
+	hidg->in_ep = ep;
+
+	/* preallocate request and buffer */
+	status = -ENOMEM;
+	hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL);
+	if (!hidg->req)
+		goto fail;
+
+
+	hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL);
+	if (!hidg->req->buf)
+		goto fail;
+
+	/* set descriptor dynamic values */
+	hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass;
+	hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
+	hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
+	hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
+	hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT;
+	hidg_desc.desc[0].wDescriptorLength =
+		cpu_to_le16(hidg->report_desc_length);
+
+	hidg->set_report_buff = NULL;
+
+	/* copy descriptors */
+	f->descriptors = usb_copy_descriptors(hidg_fs_descriptors);
+	if (!f->descriptors)
+		goto fail;
+
+	hidg->fs_in_ep_desc = usb_find_endpoint(hidg_fs_descriptors,
+						f->descriptors,
+						&hidg_fs_in_ep_desc);
+
+	if (gadget_is_dualspeed(c->cdev->gadget)) {
+		hidg_hs_in_ep_desc.bEndpointAddress =
+			hidg_fs_in_ep_desc.bEndpointAddress;
+		f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
+		if (!f->hs_descriptors)
+			goto fail;
+		hidg->hs_in_ep_desc = usb_find_endpoint(hidg_hs_descriptors,
+							f->hs_descriptors,
+							&hidg_hs_in_ep_desc);
+	} else {
+		hidg->hs_in_ep_desc = NULL;
+	}
+
+	mutex_init(&hidg->lock);
+	spin_lock_init(&hidg->spinlock);
+	init_waitqueue_head(&hidg->write_queue);
+	init_waitqueue_head(&hidg->read_queue);
+
+	/* create char device */
+	cdev_init(&hidg->cdev, &f_hidg_fops);
+	dev = MKDEV(major, hidg->minor);
+	status = cdev_add(&hidg->cdev, dev, 1);
+	if (status)
+		goto fail;
+
+	device_create(hidg_class, NULL, dev, NULL, "%s%d", "hidg", hidg->minor);
+
+	return 0;
+
+fail:
+	ERROR(f->config->cdev, "hidg_bind FAILED\n");
+	if (hidg->req != NULL) {
+		kfree(hidg->req->buf);
+		if (hidg->in_ep != NULL)
+			usb_ep_free_request(hidg->in_ep, hidg->req);
+	}
+
+	usb_free_descriptors(f->hs_descriptors);
+	usb_free_descriptors(f->descriptors);
+
+	return status;
+}
+
+static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_hidg *hidg = func_to_hidg(f);
+
+	device_destroy(hidg_class, MKDEV(major, hidg->minor));
+	cdev_del(&hidg->cdev);
+
+	/* disable/free request and end point */
+	usb_ep_disable(hidg->in_ep);
+	usb_ep_dequeue(hidg->in_ep, hidg->req);
+	kfree(hidg->req->buf);
+	usb_ep_free_request(hidg->in_ep, hidg->req);
+
+	/* free descriptors copies */
+	usb_free_descriptors(f->hs_descriptors);
+	usb_free_descriptors(f->descriptors);
+
+	kfree(hidg->report_desc);
+	kfree(hidg->set_report_buff);
+	kfree(hidg);
+}
+
+/*-------------------------------------------------------------------------*/
+/*                                 Strings                                 */
+
+#define CT_FUNC_HID_IDX	0
+
+static struct usb_string ct_func_string_defs[] = {
+	[CT_FUNC_HID_IDX].s	= "HID Interface",
+	{},			/* end of list */
+};
+
+static struct usb_gadget_strings ct_func_string_table = {
+	.language	= 0x0409,	/* en-US */
+	.strings	= ct_func_string_defs,
+};
+
+static struct usb_gadget_strings *ct_func_strings[] = {
+	&ct_func_string_table,
+	NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+/*                             usb_configuration                           */
+
+int __init hidg_bind_config(struct usb_configuration *c,
+			    struct hidg_func_descriptor *fdesc, int index)
+{
+	struct f_hidg *hidg;
+	int status;
+
+	if (index >= minors)
+		return -ENOENT;
+
+	/* maybe allocate device-global string IDs, and patch descriptors */
+	if (ct_func_string_defs[CT_FUNC_HID_IDX].id == 0) {
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			return status;
+		ct_func_string_defs[CT_FUNC_HID_IDX].id = status;
+		hidg_interface_desc.iInterface = status;
+	}
+
+	/* allocate and initialize one new instance */
+	hidg = kzalloc(sizeof *hidg, GFP_KERNEL);
+	if (!hidg)
+		return -ENOMEM;
+
+	hidg->minor = index;
+	hidg->bInterfaceSubClass = fdesc->subclass;
+	hidg->bInterfaceProtocol = fdesc->protocol;
+	hidg->report_length = fdesc->report_length;
+	hidg->report_desc_length = fdesc->report_desc_length;
+	hidg->report_desc = kmemdup(fdesc->report_desc,
+				    fdesc->report_desc_length,
+				    GFP_KERNEL);
+	if (!hidg->report_desc) {
+		kfree(hidg);
+		return -ENOMEM;
+	}
+
+	hidg->func.name    = "hid";
+	hidg->func.strings = ct_func_strings;
+	hidg->func.bind    = hidg_bind;
+	hidg->func.unbind  = hidg_unbind;
+	hidg->func.set_alt = hidg_set_alt;
+	hidg->func.disable = hidg_disable;
+	hidg->func.setup   = hidg_setup;
+
+	status = usb_add_function(c, &hidg->func);
+	if (status)
+		kfree(hidg);
+
+	return status;
+}
+
+int __init ghid_setup(struct usb_gadget *g, int count)
+{
+	int status;
+	dev_t dev;
+
+	hidg_class = class_create(THIS_MODULE, "hidg");
+
+	status = alloc_chrdev_region(&dev, 0, count, "hidg");
+	if (!status) {
+		major = MAJOR(dev);
+		minors = count;
+	}
+
+	return status;
+}
+
+void ghid_cleanup(void)
+{
+	if (major) {
+		unregister_chrdev_region(MKDEV(major, 0), minors);
+		major = minors = 0;
+	}
+
+	class_destroy(hidg_class);
+	hidg_class = NULL;
+}
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index f4911c0..7d05a0b 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -163,6 +163,10 @@
  * ro setting are not allowed when the medium is loaded or if CD-ROM
  * emulation is being used.
  *
+ * When a LUN receive an "eject" SCSI request (Start/Stop Unit),
+ * if the LUN is removable, the backing file is released to simulate
+ * ejection.
+ *
  *
  * This function is heavily based on "File-backed Storage Gadget" by
  * Alan Stern which in turn is heavily based on "Gadget Zero" by David
@@ -302,7 +306,6 @@
 
 
 #define FSG_NO_INTR_EP 1
-#define FSG_BUFFHD_STATIC_BUFFER 1
 #define FSG_NO_DEVICE_STRINGS    1
 #define FSG_NO_OTG               1
 #define FSG_NO_INTR_EP           1
@@ -1385,12 +1388,50 @@
 
 static int do_start_stop(struct fsg_common *common)
 {
-	if (!common->curlun) {
+	struct fsg_lun	*curlun = common->curlun;
+	int		loej, start;
+
+	if (!curlun) {
 		return -EINVAL;
-	} else if (!common->curlun->removable) {
-		common->curlun->sense_data = SS_INVALID_COMMAND;
+	} else if (!curlun->removable) {
+		curlun->sense_data = SS_INVALID_COMMAND;
 		return -EINVAL;
 	}
+
+	loej = common->cmnd[4] & 0x02;
+	start = common->cmnd[4] & 0x01;
+
+	/* eject code from file_storage.c:do_start_stop() */
+
+	if ((common->cmnd[1] & ~0x01) != 0 ||	  /* Mask away Immed */
+		(common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
+		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		return -EINVAL;
+	}
+
+	if (!start) {
+		/* Are we allowed to unload the media? */
+		if (curlun->prevent_medium_removal) {
+			LDBG(curlun, "unload attempt prevented\n");
+			curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
+			return -EINVAL;
+		}
+		if (loej) {	/* Simulate an unload/eject */
+			up_read(&common->filesem);
+			down_write(&common->filesem);
+			fsg_lun_close(curlun);
+			up_write(&common->filesem);
+			down_read(&common->filesem);
+		}
+	} else {
+
+		/* Our emulation doesn't support mounting; the medium is
+		 * available for use as soon as it is loaded. */
+		if (!fsg_lun_is_open(curlun)) {
+			curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
+			return -EINVAL;
+		}
+	}
 	return 0;
 }
 
@@ -2701,10 +2742,8 @@
 	/* Maybe allocate device-global string IDs, and patch descriptors */
 	if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
 		rc = usb_string_id(cdev);
-		if (rc < 0) {
-			kfree(common);
-			return ERR_PTR(rc);
-		}
+		if (unlikely(rc < 0))
+			goto error_release;
 		fsg_strings[FSG_STRING_INTERFACE].id = rc;
 		fsg_intf_desc.iInterface = rc;
 	}
@@ -2712,9 +2751,9 @@
 	/* Create the LUNs, open their backing files, and register the
 	 * LUN devices in sysfs. */
 	curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL);
-	if (!curlun) {
-		kfree(common);
-		return ERR_PTR(-ENOMEM);
+	if (unlikely(!curlun)) {
+		rc = -ENOMEM;
+		goto error_release;
 	}
 	common->luns = curlun;
 
@@ -2762,13 +2801,19 @@
 
 
 	/* Data buffers cyclic list */
-	/* Buffers in buffhds are static -- no need for additional
-	 * allocation. */
 	bh = common->buffhds;
-	i = FSG_NUM_BUFFERS - 1;
+	i = FSG_NUM_BUFFERS;
+	goto buffhds_first_it;
 	do {
 		bh->next = bh + 1;
-	} while (++bh, --i);
+		++bh;
+buffhds_first_it:
+		bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
+		if (unlikely(!bh->buf)) {
+			rc = -ENOMEM;
+			goto error_release;
+		}
+	} while (--i);
 	bh->next = common->buffhds;
 
 
@@ -2867,10 +2912,7 @@
 
 static void fsg_common_release(struct kref *ref)
 {
-	struct fsg_common *common =
-		container_of(ref, struct fsg_common, ref);
-	unsigned i = common->nluns;
-	struct fsg_lun *lun = common->luns;
+	struct fsg_common *common = container_of(ref, struct fsg_common, ref);
 
 	/* If the thread isn't already dead, tell it to exit now */
 	if (common->state != FSG_STATE_TERMINATED) {
@@ -2881,17 +2923,29 @@
 		complete(&common->thread_notifier);
 	}
 
-	/* Beware tempting for -> do-while optimization: when in error
-	 * recovery nluns may be zero. */
+	if (likely(common->luns)) {
+		struct fsg_lun *lun = common->luns;
+		unsigned i = common->nluns;
 
-	for (; i; --i, ++lun) {
-		device_remove_file(&lun->dev, &dev_attr_ro);
-		device_remove_file(&lun->dev, &dev_attr_file);
-		fsg_lun_close(lun);
-		device_unregister(&lun->dev);
+		/* In error recovery common->nluns may be zero. */
+		for (; i; --i, ++lun) {
+			device_remove_file(&lun->dev, &dev_attr_ro);
+			device_remove_file(&lun->dev, &dev_attr_file);
+			fsg_lun_close(lun);
+			device_unregister(&lun->dev);
+		}
+
+		kfree(common->luns);
 	}
 
-	kfree(common->luns);
+	{
+		struct fsg_buffhd *bh = common->buffhds;
+		unsigned i = FSG_NUM_BUFFERS;
+		do {
+			kfree(bh->buf);
+		} while (++bh, --i);
+	}
+
 	if (common->free_storage_on_release)
 		kfree(common);
 }
@@ -2906,11 +2960,13 @@
 
 	DBG(fsg, "unbind\n");
 	fsg_common_put(fsg->common);
+	usb_free_descriptors(fsg->function.descriptors);
+	usb_free_descriptors(fsg->function.hs_descriptors);
 	kfree(fsg);
 }
 
 
-static int __init fsg_bind(struct usb_configuration *c, struct usb_function *f)
+static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct fsg_dev		*fsg = fsg_from_func(f);
 	struct usb_gadget	*gadget = c->cdev->gadget;
@@ -2946,7 +3002,9 @@
 			fsg_fs_bulk_in_desc.bEndpointAddress;
 		fsg_hs_bulk_out_desc.bEndpointAddress =
 			fsg_fs_bulk_out_desc.bEndpointAddress;
-		f->hs_descriptors = fsg_hs_function;
+		f->hs_descriptors = usb_copy_descriptors(fsg_hs_function);
+		if (unlikely(!f->hs_descriptors))
+			return -ENOMEM;
 	}
 
 	return 0;
@@ -2978,7 +3036,11 @@
 
 	fsg->function.name        = FSG_DRIVER_DESC;
 	fsg->function.strings     = fsg_strings_array;
-	fsg->function.descriptors = fsg_fs_function;
+	fsg->function.descriptors = usb_copy_descriptors(fsg_fs_function);
+	if (unlikely(!fsg->function.descriptors)) {
+		rc = -ENOMEM;
+		goto error_free_fsg;
+	}
 	fsg->function.bind        = fsg_bind;
 	fsg->function.unbind      = fsg_unbind;
 	fsg->function.setup       = fsg_setup;
@@ -2993,11 +3055,19 @@
 	 * call to usb_add_function() was successful. */
 
 	rc = usb_add_function(c, &fsg->function);
+	if (unlikely(rc))
+		goto error_free_all;
 
-	if (likely(rc == 0))
-		fsg_common_get(fsg->common);
-	else
-		kfree(fsg);
+	fsg_common_get(fsg->common);
+	return 0;
+
+error_free_all:
+	usb_free_descriptors(fsg->function.descriptors);
+	/* fsg_bind() might have copied those; or maybe not? who cares
+	 * -- free it just in case. */
+	usb_free_descriptors(fsg->function.hs_descriptors);
+error_free_fsg:
+	kfree(fsg);
 
 	return rc;
 }
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 56b0221..882484a 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -122,7 +122,7 @@
 
 /* interface descriptor: */
 
-static struct usb_interface_descriptor rndis_control_intf __initdata = {
+static struct usb_interface_descriptor rndis_control_intf = {
 	.bLength =		sizeof rndis_control_intf,
 	.bDescriptorType =	USB_DT_INTERFACE,
 
@@ -135,7 +135,7 @@
 	/* .iInterface = DYNAMIC */
 };
 
-static struct usb_cdc_header_desc header_desc __initdata = {
+static struct usb_cdc_header_desc header_desc = {
 	.bLength =		sizeof header_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
@@ -143,7 +143,7 @@
 	.bcdCDC =		cpu_to_le16(0x0110),
 };
 
-static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor __initdata = {
+static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
 	.bLength =		sizeof call_mgmt_descriptor,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
@@ -152,7 +152,7 @@
 	.bDataInterface =	0x01,
 };
 
-static struct usb_cdc_acm_descriptor rndis_acm_descriptor __initdata = {
+static struct usb_cdc_acm_descriptor rndis_acm_descriptor = {
 	.bLength =		sizeof rndis_acm_descriptor,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
@@ -160,7 +160,7 @@
 	.bmCapabilities =	0x00,
 };
 
-static struct usb_cdc_union_desc rndis_union_desc __initdata = {
+static struct usb_cdc_union_desc rndis_union_desc = {
 	.bLength =		sizeof(rndis_union_desc),
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
@@ -170,7 +170,7 @@
 
 /* the data interface has two bulk endpoints */
 
-static struct usb_interface_descriptor rndis_data_intf __initdata = {
+static struct usb_interface_descriptor rndis_data_intf = {
 	.bLength =		sizeof rndis_data_intf,
 	.bDescriptorType =	USB_DT_INTERFACE,
 
@@ -198,7 +198,7 @@
 
 /* full speed support: */
 
-static struct usb_endpoint_descriptor fs_notify_desc __initdata = {
+static struct usb_endpoint_descriptor fs_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -208,7 +208,7 @@
 	.bInterval =		1 << LOG2_STATUS_INTERVAL_MSEC,
 };
 
-static struct usb_endpoint_descriptor fs_in_desc __initdata = {
+static struct usb_endpoint_descriptor fs_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -216,7 +216,7 @@
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_endpoint_descriptor fs_out_desc __initdata = {
+static struct usb_endpoint_descriptor fs_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -224,7 +224,7 @@
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
 
-static struct usb_descriptor_header *eth_fs_function[] __initdata = {
+static struct usb_descriptor_header *eth_fs_function[] = {
 	(struct usb_descriptor_header *) &rndis_iad_descriptor,
 	/* control interface matches ACM, not Ethernet */
 	(struct usb_descriptor_header *) &rndis_control_intf,
@@ -242,7 +242,7 @@
 
 /* high speed support: */
 
-static struct usb_endpoint_descriptor hs_notify_desc __initdata = {
+static struct usb_endpoint_descriptor hs_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -251,7 +251,7 @@
 	.wMaxPacketSize =	cpu_to_le16(STATUS_BYTECOUNT),
 	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
 };
-static struct usb_endpoint_descriptor hs_in_desc __initdata = {
+static struct usb_endpoint_descriptor hs_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -260,7 +260,7 @@
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_endpoint_descriptor hs_out_desc __initdata = {
+static struct usb_endpoint_descriptor hs_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 
@@ -269,7 +269,7 @@
 	.wMaxPacketSize =	cpu_to_le16(512),
 };
 
-static struct usb_descriptor_header *eth_hs_function[] __initdata = {
+static struct usb_descriptor_header *eth_hs_function[] = {
 	(struct usb_descriptor_header *) &rndis_iad_descriptor,
 	/* control interface matches ACM, not Ethernet */
 	(struct usb_descriptor_header *) &rndis_control_intf,
@@ -594,7 +594,7 @@
 
 /* ethernet function driver setup/binding */
 
-static int __init
+static int
 rndis_bind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct usb_composite_dev *cdev = c->cdev;
@@ -786,7 +786,8 @@
  * Caller must have called @gether_setup().  Caller is also responsible
  * for calling @gether_cleanup() before module unload.
  */
-int __init rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int
+rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
 {
 	struct f_rndis	*rndis;
 	int		status;
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c
new file mode 100644
index 0000000..fc2611f
--- /dev/null
+++ b/drivers/usb/gadget/f_uvc.c
@@ -0,0 +1,661 @@
+/*
+ *	uvc_gadget.c  --  USB Video Class Gadget driver
+ *
+ *	Copyright (C) 2009-2010
+ *	    Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ *	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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/video.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-event.h>
+
+#include "uvc.h"
+
+unsigned int uvc_trace_param;
+
+/* --------------------------------------------------------------------------
+ * Function descriptors
+ */
+
+/* string IDs are assigned dynamically */
+
+#define UVC_STRING_ASSOCIATION_IDX		0
+#define UVC_STRING_CONTROL_IDX			1
+#define UVC_STRING_STREAMING_IDX		2
+
+static struct usb_string uvc_en_us_strings[] = {
+	[UVC_STRING_ASSOCIATION_IDX].s = "UVC Camera",
+	[UVC_STRING_CONTROL_IDX].s = "Video Control",
+	[UVC_STRING_STREAMING_IDX].s = "Video Streaming",
+	{  }
+};
+
+static struct usb_gadget_strings uvc_stringtab = {
+	.language = 0x0409,	/* en-us */
+	.strings = uvc_en_us_strings,
+};
+
+static struct usb_gadget_strings *uvc_function_strings[] = {
+	&uvc_stringtab,
+	NULL,
+};
+
+#define UVC_INTF_VIDEO_CONTROL			0
+#define UVC_INTF_VIDEO_STREAMING		1
+
+static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
+	.bLength		= USB_DT_INTERFACE_ASSOCIATION_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE_ASSOCIATION,
+	.bFirstInterface	= 0,
+	.bInterfaceCount	= 2,
+	.bFunctionClass		= USB_CLASS_VIDEO,
+	.bFunctionSubClass	= 0x03,
+	.bFunctionProtocol	= 0x00,
+	.iFunction		= 0,
+};
+
+static struct usb_interface_descriptor uvc_control_intf __initdata = {
+	.bLength		= USB_DT_INTERFACE_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bInterfaceNumber	= UVC_INTF_VIDEO_CONTROL,
+	.bAlternateSetting	= 0,
+	.bNumEndpoints		= 1,
+	.bInterfaceClass	= USB_CLASS_VIDEO,
+	.bInterfaceSubClass	= 0x01,
+	.bInterfaceProtocol	= 0x00,
+	.iInterface		= 0,
+};
+
+static struct usb_endpoint_descriptor uvc_control_ep __initdata = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_IN,
+	.bmAttributes		= USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize		= cpu_to_le16(16),
+	.bInterval		= 8,
+};
+
+static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = {
+	.bLength		= UVC_DT_CONTROL_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_CS_ENDPOINT,
+	.bDescriptorSubType	= UVC_EP_INTERRUPT,
+	.wMaxTransferSize	= cpu_to_le16(16),
+};
+
+static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = {
+	.bLength		= USB_DT_INTERFACE_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bInterfaceNumber	= UVC_INTF_VIDEO_STREAMING,
+	.bAlternateSetting	= 0,
+	.bNumEndpoints		= 0,
+	.bInterfaceClass	= USB_CLASS_VIDEO,
+	.bInterfaceSubClass	= 0x02,
+	.bInterfaceProtocol	= 0x00,
+	.iInterface		= 0,
+};
+
+static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = {
+	.bLength		= USB_DT_INTERFACE_SIZE,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bInterfaceNumber	= UVC_INTF_VIDEO_STREAMING,
+	.bAlternateSetting	= 1,
+	.bNumEndpoints		= 1,
+	.bInterfaceClass	= USB_CLASS_VIDEO,
+	.bInterfaceSubClass	= 0x02,
+	.bInterfaceProtocol	= 0x00,
+	.iInterface		= 0,
+};
+
+static struct usb_endpoint_descriptor uvc_streaming_ep = {
+	.bLength		= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_IN,
+	.bmAttributes		= USB_ENDPOINT_XFER_ISOC,
+	.wMaxPacketSize		= cpu_to_le16(512),
+	.bInterval		= 1,
+};
+
+static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
+	(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
+	(struct usb_descriptor_header *) &uvc_streaming_ep,
+	NULL,
+};
+
+static const struct usb_descriptor_header * const uvc_hs_streaming[] = {
+	(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
+	(struct usb_descriptor_header *) &uvc_streaming_ep,
+	NULL,
+};
+
+/* --------------------------------------------------------------------------
+ * Control requests
+ */
+
+static void
+uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct uvc_device *uvc = req->context;
+	struct v4l2_event v4l2_event;
+	struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
+
+	if (uvc->event_setup_out) {
+		uvc->event_setup_out = 0;
+
+		memset(&v4l2_event, 0, sizeof(v4l2_event));
+		v4l2_event.type = UVC_EVENT_DATA;
+		uvc_event->data.length = req->actual;
+		memcpy(&uvc_event->data.data, req->buf, req->actual);
+		v4l2_event_queue(uvc->vdev, &v4l2_event);
+	}
+}
+
+static int
+uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+	struct uvc_device *uvc = to_uvc(f);
+	struct v4l2_event v4l2_event;
+	struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
+
+	/* printk(KERN_INFO "setup request %02x %02x value %04x index %04x %04x\n",
+	 *	ctrl->bRequestType, ctrl->bRequest, le16_to_cpu(ctrl->wValue),
+	 *	le16_to_cpu(ctrl->wIndex), le16_to_cpu(ctrl->wLength));
+	 */
+
+	if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) {
+		INFO(f->config->cdev, "invalid request type\n");
+		return -EINVAL;
+	}
+
+	/* Stall too big requests. */
+	if (le16_to_cpu(ctrl->wLength) > UVC_MAX_REQUEST_SIZE)
+		return -EINVAL;
+
+	memset(&v4l2_event, 0, sizeof(v4l2_event));
+	v4l2_event.type = UVC_EVENT_SETUP;
+	memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req));
+	v4l2_event_queue(uvc->vdev, &v4l2_event);
+
+	return 0;
+}
+
+static int
+uvc_function_get_alt(struct usb_function *f, unsigned interface)
+{
+	struct uvc_device *uvc = to_uvc(f);
+
+	INFO(f->config->cdev, "uvc_function_get_alt(%u)\n", interface);
+
+	if (interface == uvc->control_intf)
+		return 0;
+	else if (interface != uvc->streaming_intf)
+		return -EINVAL;
+	else
+		return uvc->state == UVC_STATE_STREAMING ? 1 : 0;
+}
+
+static int
+uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
+{
+	struct uvc_device *uvc = to_uvc(f);
+	struct v4l2_event v4l2_event;
+	struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
+
+	INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
+
+	if (interface == uvc->control_intf) {
+		if (alt)
+			return -EINVAL;
+
+		if (uvc->state == UVC_STATE_DISCONNECTED) {
+			memset(&v4l2_event, 0, sizeof(v4l2_event));
+			v4l2_event.type = UVC_EVENT_CONNECT;
+			uvc_event->speed = f->config->cdev->gadget->speed;
+			v4l2_event_queue(uvc->vdev, &v4l2_event);
+
+			uvc->state = UVC_STATE_CONNECTED;
+		}
+
+		return 0;
+	}
+
+	if (interface != uvc->streaming_intf)
+		return -EINVAL;
+
+	/* TODO
+	if (usb_endpoint_xfer_bulk(&uvc->desc.vs_ep))
+		return alt ? -EINVAL : 0;
+	*/
+
+	switch (alt) {
+	case 0:
+		if (uvc->state != UVC_STATE_STREAMING)
+			return 0;
+
+		if (uvc->video.ep)
+			usb_ep_disable(uvc->video.ep);
+
+		memset(&v4l2_event, 0, sizeof(v4l2_event));
+		v4l2_event.type = UVC_EVENT_STREAMOFF;
+		v4l2_event_queue(uvc->vdev, &v4l2_event);
+
+		uvc->state = UVC_STATE_CONNECTED;
+		break;
+
+	case 1:
+		if (uvc->state != UVC_STATE_CONNECTED)
+			return 0;
+
+		if (uvc->video.ep)
+			usb_ep_enable(uvc->video.ep, &uvc_streaming_ep);
+
+		memset(&v4l2_event, 0, sizeof(v4l2_event));
+		v4l2_event.type = UVC_EVENT_STREAMON;
+		v4l2_event_queue(uvc->vdev, &v4l2_event);
+
+		uvc->state = UVC_STATE_STREAMING;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void
+uvc_function_disable(struct usb_function *f)
+{
+	struct uvc_device *uvc = to_uvc(f);
+	struct v4l2_event v4l2_event;
+
+	INFO(f->config->cdev, "uvc_function_disable\n");
+
+	memset(&v4l2_event, 0, sizeof(v4l2_event));
+	v4l2_event.type = UVC_EVENT_DISCONNECT;
+	v4l2_event_queue(uvc->vdev, &v4l2_event);
+
+	uvc->state = UVC_STATE_DISCONNECTED;
+}
+
+/* --------------------------------------------------------------------------
+ * Connection / disconnection
+ */
+
+void
+uvc_function_connect(struct uvc_device *uvc)
+{
+	struct usb_composite_dev *cdev = uvc->func.config->cdev;
+	int ret;
+
+	if ((ret = usb_function_activate(&uvc->func)) < 0)
+		INFO(cdev, "UVC connect failed with %d\n", ret);
+}
+
+void
+uvc_function_disconnect(struct uvc_device *uvc)
+{
+	struct usb_composite_dev *cdev = uvc->func.config->cdev;
+	int ret;
+
+	if ((ret = usb_function_deactivate(&uvc->func)) < 0)
+		INFO(cdev, "UVC disconnect failed with %d\n", ret);
+}
+
+/* --------------------------------------------------------------------------
+ * USB probe and disconnect
+ */
+
+static int
+uvc_register_video(struct uvc_device *uvc)
+{
+	struct usb_composite_dev *cdev = uvc->func.config->cdev;
+	struct video_device *video;
+
+	/* TODO reference counting. */
+	video = video_device_alloc();
+	if (video == NULL)
+		return -ENOMEM;
+
+	video->parent = &cdev->gadget->dev;
+	video->minor = -1;
+	video->fops = &uvc_v4l2_fops;
+	video->release = video_device_release;
+	strncpy(video->name, cdev->gadget->name, sizeof(video->name));
+
+	uvc->vdev = video;
+	video_set_drvdata(video, uvc);
+
+	return video_register_device(video, VFL_TYPE_GRABBER, -1);
+}
+
+#define UVC_COPY_DESCRIPTOR(mem, dst, desc) \
+	do { \
+		memcpy(mem, desc, (desc)->bLength); \
+		*(dst)++ = mem; \
+		mem += (desc)->bLength; \
+	} while (0);
+
+#define UVC_COPY_DESCRIPTORS(mem, dst, src) \
+	do { \
+		const struct usb_descriptor_header * const *__src; \
+		for (__src = src; *__src; ++__src) { \
+			memcpy(mem, *__src, (*__src)->bLength); \
+			*dst++ = mem; \
+			mem += (*__src)->bLength; \
+		} \
+	} while (0)
+
+static struct usb_descriptor_header ** __init
+uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
+{
+	struct uvc_input_header_descriptor *uvc_streaming_header;
+	struct uvc_header_descriptor *uvc_control_header;
+	const struct uvc_descriptor_header * const *uvc_streaming_cls;
+	const struct usb_descriptor_header * const *uvc_streaming_std;
+	const struct usb_descriptor_header * const *src;
+	struct usb_descriptor_header **dst;
+	struct usb_descriptor_header **hdr;
+	unsigned int control_size;
+	unsigned int streaming_size;
+	unsigned int n_desc;
+	unsigned int bytes;
+	void *mem;
+
+	uvc_streaming_cls = (speed == USB_SPEED_FULL)
+			  ? uvc->desc.fs_streaming : uvc->desc.hs_streaming;
+	uvc_streaming_std = (speed == USB_SPEED_FULL)
+			  ? uvc_fs_streaming : uvc_hs_streaming;
+
+	/* Descriptors layout
+	 *
+	 * uvc_iad
+	 * uvc_control_intf
+	 * Class-specific UVC control descriptors
+	 * uvc_control_ep
+	 * uvc_control_cs_ep
+	 * uvc_streaming_intf_alt0
+	 * Class-specific UVC streaming descriptors
+	 * uvc_{fs|hs}_streaming
+	 */
+
+	/* Count descriptors and compute their size. */
+	control_size = 0;
+	streaming_size = 0;
+	bytes = uvc_iad.bLength + uvc_control_intf.bLength
+	      + uvc_control_ep.bLength + uvc_control_cs_ep.bLength
+	      + uvc_streaming_intf_alt0.bLength;
+	n_desc = 5;
+
+	for (src = (const struct usb_descriptor_header**)uvc->desc.control; *src; ++src) {
+		control_size += (*src)->bLength;
+		bytes += (*src)->bLength;
+		n_desc++;
+	}
+	for (src = (const struct usb_descriptor_header**)uvc_streaming_cls; *src; ++src) {
+		streaming_size += (*src)->bLength;
+		bytes += (*src)->bLength;
+		n_desc++;
+	}
+	for (src = uvc_streaming_std; *src; ++src) {
+		bytes += (*src)->bLength;
+		n_desc++;
+	}
+
+	mem = kmalloc((n_desc + 1) * sizeof(*src) + bytes, GFP_KERNEL);
+	if (mem == NULL)
+		return NULL;
+
+	hdr = mem;
+	dst = mem;
+	mem += (n_desc + 1) * sizeof(*src);
+
+	/* Copy the descriptors. */
+	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_iad);
+	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_intf);
+
+	uvc_control_header = mem;
+	UVC_COPY_DESCRIPTORS(mem, dst,
+		(const struct usb_descriptor_header**)uvc->desc.control);
+	uvc_control_header->wTotalLength = cpu_to_le16(control_size);
+	uvc_control_header->bInCollection = 1;
+	uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
+
+	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
+	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep);
+	UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0);
+
+	uvc_streaming_header = mem;
+	UVC_COPY_DESCRIPTORS(mem, dst,
+		(const struct usb_descriptor_header**)uvc_streaming_cls);
+	uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
+	uvc_streaming_header->bEndpointAddress = uvc_streaming_ep.bEndpointAddress;
+
+	UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
+
+	*dst = NULL;
+	return hdr;
+}
+
+static void
+uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = c->cdev;
+	struct uvc_device *uvc = to_uvc(f);
+
+	INFO(cdev, "uvc_function_unbind\n");
+
+	if (uvc->vdev) {
+		if (uvc->vdev->minor == -1)
+			video_device_release(uvc->vdev);
+		else
+			video_unregister_device(uvc->vdev);
+		uvc->vdev = NULL;
+	}
+
+	if (uvc->control_ep)
+		uvc->control_ep->driver_data = NULL;
+	if (uvc->video.ep)
+		uvc->video.ep->driver_data = NULL;
+
+	if (uvc->control_req) {
+		usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
+		kfree(uvc->control_buf);
+	}
+
+	kfree(f->descriptors);
+	kfree(f->hs_descriptors);
+
+	kfree(uvc);
+}
+
+static int __init
+uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = c->cdev;
+	struct uvc_device *uvc = to_uvc(f);
+	struct usb_ep *ep;
+	int ret = -EINVAL;
+
+	INFO(cdev, "uvc_function_bind\n");
+
+	/* Allocate endpoints. */
+	ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
+	if (!ep) {
+		INFO(cdev, "Unable to allocate control EP\n");
+		goto error;
+	}
+	uvc->control_ep = ep;
+	ep->driver_data = uvc;
+
+	ep = usb_ep_autoconfig(cdev->gadget, &uvc_streaming_ep);
+	if (!ep) {
+		INFO(cdev, "Unable to allocate streaming EP\n");
+		goto error;
+	}
+	uvc->video.ep = ep;
+	ep->driver_data = uvc;
+
+	/* Allocate interface IDs. */
+	if ((ret = usb_interface_id(c, f)) < 0)
+		goto error;
+	uvc_iad.bFirstInterface = ret;
+	uvc_control_intf.bInterfaceNumber = ret;
+	uvc->control_intf = ret;
+
+	if ((ret = usb_interface_id(c, f)) < 0)
+		goto error;
+	uvc_streaming_intf_alt0.bInterfaceNumber = ret;
+	uvc_streaming_intf_alt1.bInterfaceNumber = ret;
+	uvc->streaming_intf = ret;
+
+	/* Copy descriptors. */
+	f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
+	f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
+
+	/* Preallocate control endpoint request. */
+	uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
+	uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL);
+	if (uvc->control_req == NULL || uvc->control_buf == NULL) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	uvc->control_req->buf = uvc->control_buf;
+	uvc->control_req->complete = uvc_function_ep0_complete;
+	uvc->control_req->context = uvc;
+
+	/* Avoid letting this gadget enumerate until the userspace server is
+	 * active.
+	 */
+	if ((ret = usb_function_deactivate(f)) < 0)
+		goto error;
+
+	/* Initialise video. */
+	ret = uvc_video_init(&uvc->video);
+	if (ret < 0)
+		goto error;
+
+	/* Register a V4L2 device. */
+	ret = uvc_register_video(uvc);
+	if (ret < 0) {
+		printk(KERN_INFO "Unable to register video device\n");
+		goto error;
+	}
+
+	return 0;
+
+error:
+	uvc_function_unbind(c, f);
+	return ret;
+}
+
+/* --------------------------------------------------------------------------
+ * USB gadget function
+ */
+
+/**
+ * uvc_bind_config - add a UVC function to a configuration
+ * @c: the configuration to support the UVC instance
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * Caller must have called @uvc_setup(). Caller is also responsible for
+ * calling @uvc_cleanup() before module unload.
+ */
+int __init
+uvc_bind_config(struct usb_configuration *c,
+		const struct uvc_descriptor_header * const *control,
+		const struct uvc_descriptor_header * const *fs_streaming,
+		const struct uvc_descriptor_header * const *hs_streaming)
+{
+	struct uvc_device *uvc;
+	int ret = 0;
+
+	/* TODO Check if the USB device controller supports the required
+	 * features.
+	 */
+	if (!gadget_is_dualspeed(c->cdev->gadget))
+		return -EINVAL;
+
+	uvc = kzalloc(sizeof(*uvc), GFP_KERNEL);
+	if (uvc == NULL)
+		return -ENOMEM;
+
+	uvc->state = UVC_STATE_DISCONNECTED;
+
+	/* Validate the descriptors. */
+	if (control == NULL || control[0] == NULL ||
+	    control[0]->bDescriptorSubType != UVC_DT_HEADER)
+		goto error;
+
+	if (fs_streaming == NULL || fs_streaming[0] == NULL ||
+	    fs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER)
+		goto error;
+
+	if (hs_streaming == NULL || hs_streaming[0] == NULL ||
+	    hs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER)
+		goto error;
+
+	uvc->desc.control = control;
+	uvc->desc.fs_streaming = fs_streaming;
+	uvc->desc.hs_streaming = hs_streaming;
+
+	/* Allocate string descriptor numbers. */
+	if ((ret = usb_string_id(c->cdev)) < 0)
+		goto error;
+	uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret;
+	uvc_iad.iFunction = ret;
+
+	if ((ret = usb_string_id(c->cdev)) < 0)
+		goto error;
+	uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret;
+	uvc_control_intf.iInterface = ret;
+
+	if ((ret = usb_string_id(c->cdev)) < 0)
+		goto error;
+	uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret;
+	uvc_streaming_intf_alt0.iInterface = ret;
+	uvc_streaming_intf_alt1.iInterface = ret;
+
+	/* Register the function. */
+	uvc->func.name = "uvc";
+	uvc->func.strings = uvc_function_strings;
+	uvc->func.bind = uvc_function_bind;
+	uvc->func.unbind = uvc_function_unbind;
+	uvc->func.get_alt = uvc_function_get_alt;
+	uvc->func.set_alt = uvc_function_set_alt;
+	uvc->func.disable = uvc_function_disable;
+	uvc->func.setup = uvc_function_setup;
+
+	ret = usb_add_function(c, &uvc->func);
+	if (ret)
+		kfree(uvc);
+
+	return 0;
+
+error:
+	kfree(uvc);
+	return ret;
+}
+
+module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(trace, "Trace level bitmask");
+
diff --git a/drivers/usb/gadget/f_uvc.h b/drivers/usb/gadget/f_uvc.h
new file mode 100644
index 0000000..8a5db7c
--- /dev/null
+++ b/drivers/usb/gadget/f_uvc.h
@@ -0,0 +1,376 @@
+/*
+ *	f_uvc.h  --  USB Video Class Gadget driver
+ *
+ *	Copyright (C) 2009-2010
+ *	    Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ *	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.
+ *
+ */
+
+#ifndef _F_UVC_H_
+#define _F_UVC_H_
+
+#include <linux/usb/composite.h>
+
+#define USB_CLASS_VIDEO_CONTROL		1
+#define USB_CLASS_VIDEO_STREAMING	2
+
+struct uvc_descriptor_header {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+} __attribute__ ((packed));
+
+struct uvc_header_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u16 bcdUVC;
+	__u16 wTotalLength;
+	__u32 dwClockFrequency;
+	__u8  bInCollection;
+	__u8  baInterfaceNr[];
+} __attribute__((__packed__));
+
+#define UVC_HEADER_DESCRIPTOR(n)	uvc_header_descriptor_##n
+
+#define DECLARE_UVC_HEADER_DESCRIPTOR(n) 			\
+struct UVC_HEADER_DESCRIPTOR(n) {				\
+	__u8  bLength;						\
+	__u8  bDescriptorType;					\
+	__u8  bDescriptorSubType;				\
+	__u16 bcdUVC;						\
+	__u16 wTotalLength;					\
+	__u32 dwClockFrequency;					\
+	__u8  bInCollection;					\
+	__u8  baInterfaceNr[n];					\
+} __attribute__ ((packed))
+
+struct uvc_input_terminal_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bTerminalID;
+	__u16 wTerminalType;
+	__u8  bAssocTerminal;
+	__u8  iTerminal;
+} __attribute__((__packed__));
+
+struct uvc_output_terminal_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bTerminalID;
+	__u16 wTerminalType;
+	__u8  bAssocTerminal;
+	__u8  bSourceID;
+	__u8  iTerminal;
+} __attribute__((__packed__));
+
+struct uvc_camera_terminal_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bTerminalID;
+	__u16 wTerminalType;
+	__u8  bAssocTerminal;
+	__u8  iTerminal;
+	__u16 wObjectiveFocalLengthMin;
+	__u16 wObjectiveFocalLengthMax;
+	__u16 wOcularFocalLength;
+	__u8  bControlSize;
+	__u8  bmControls[3];
+} __attribute__((__packed__));
+
+struct uvc_selector_unit_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bUnitID;
+	__u8  bNrInPins;
+	__u8  baSourceID[0];
+	__u8  iSelector;
+} __attribute__((__packed__));
+
+#define UVC_SELECTOR_UNIT_DESCRIPTOR(n)	\
+	uvc_selector_unit_descriptor_##n
+
+#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n) 		\
+struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) {			\
+	__u8  bLength;						\
+	__u8  bDescriptorType;					\
+	__u8  bDescriptorSubType;				\
+	__u8  bUnitID;						\
+	__u8  bNrInPins;					\
+	__u8  baSourceID[n];					\
+	__u8  iSelector;					\
+} __attribute__ ((packed))
+
+struct uvc_processing_unit_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bUnitID;
+	__u8  bSourceID;
+	__u16 wMaxMultiplier;
+	__u8  bControlSize;
+	__u8  bmControls[2];
+	__u8  iProcessing;
+} __attribute__((__packed__));
+
+struct uvc_extension_unit_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bUnitID;
+	__u8  guidExtensionCode[16];
+	__u8  bNumControls;
+	__u8  bNrInPins;
+	__u8  baSourceID[0];
+	__u8  bControlSize;
+	__u8  bmControls[0];
+	__u8  iExtension;
+} __attribute__((__packed__));
+
+#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
+	uvc_extension_unit_descriptor_##p_##n
+
+#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) 		\
+struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) {			\
+	__u8  bLength;						\
+	__u8  bDescriptorType;					\
+	__u8  bDescriptorSubType;				\
+	__u8  bUnitID;						\
+	__u8  guidExtensionCode[16];				\
+	__u8  bNumControls;					\
+	__u8  bNrInPins;					\
+	__u8  baSourceID[p];					\
+	__u8  bControlSize;					\
+	__u8  bmControls[n];					\
+	__u8  iExtension;					\
+} __attribute__ ((packed))
+
+struct uvc_control_endpoint_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u16 wMaxTransferSize;
+} __attribute__((__packed__));
+
+#define UVC_DT_HEADER				1
+#define UVC_DT_INPUT_TERMINAL			2
+#define UVC_DT_OUTPUT_TERMINAL			3
+#define UVC_DT_SELECTOR_UNIT			4
+#define UVC_DT_PROCESSING_UNIT			5
+#define UVC_DT_EXTENSION_UNIT			6
+
+#define UVC_DT_HEADER_SIZE(n)			(12+(n))
+#define UVC_DT_INPUT_TERMINAL_SIZE		8
+#define UVC_DT_OUTPUT_TERMINAL_SIZE		9
+#define UVC_DT_CAMERA_TERMINAL_SIZE(n)		(15+(n))
+#define UVC_DT_SELECTOR_UNIT_SIZE(n)		(6+(n))
+#define UVC_DT_PROCESSING_UNIT_SIZE(n)		(9+(n))
+#define UVC_DT_EXTENSION_UNIT_SIZE(p,n)		(24+(p)+(n))
+#define UVC_DT_CONTROL_ENDPOINT_SIZE		5
+
+struct uvc_input_header_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bNumFormats;
+	__u16 wTotalLength;
+	__u8  bEndpointAddress;
+	__u8  bmInfo;
+	__u8  bTerminalLink;
+	__u8  bStillCaptureMethod;
+	__u8  bTriggerSupport;
+	__u8  bTriggerUsage;
+	__u8  bControlSize;
+	__u8  bmaControls[];
+} __attribute__((__packed__));
+
+#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
+	uvc_input_header_descriptor_##n_##p
+
+#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p)		\
+struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) {			\
+	__u8  bLength;						\
+	__u8  bDescriptorType;					\
+	__u8  bDescriptorSubType;				\
+	__u8  bNumFormats;					\
+	__u16 wTotalLength;					\
+	__u8  bEndpointAddress;					\
+	__u8  bmInfo;						\
+	__u8  bTerminalLink;					\
+	__u8  bStillCaptureMethod;				\
+	__u8  bTriggerSupport;					\
+	__u8  bTriggerUsage;					\
+	__u8  bControlSize;					\
+	__u8  bmaControls[p][n];				\
+} __attribute__ ((packed))
+
+struct uvc_output_header_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bNumFormats;
+	__u16 wTotalLength;
+	__u8  bEndpointAddress;
+	__u8  bTerminalLink;
+	__u8  bControlSize;
+	__u8  bmaControls[];
+} __attribute__((__packed__));
+
+#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
+	uvc_output_header_descriptor_##n_##p
+
+#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p)		\
+struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) {			\
+	__u8  bLength;						\
+	__u8  bDescriptorType;					\
+	__u8  bDescriptorSubType;				\
+	__u8  bNumFormats;					\
+	__u16 wTotalLength;					\
+	__u8  bEndpointAddress;					\
+	__u8  bTerminalLink;					\
+	__u8  bControlSize;					\
+	__u8  bmaControls[p][n];				\
+} __attribute__ ((packed))
+
+struct uvc_format_uncompressed {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bFormatIndex;
+	__u8  bNumFrameDescriptors;
+	__u8  guidFormat[16];
+	__u8  bBitsPerPixel;
+	__u8  bDefaultFrameIndex;
+	__u8  bAspectRatioX;
+	__u8  bAspectRatioY;
+	__u8  bmInterfaceFlags;
+	__u8  bCopyProtect;
+} __attribute__((__packed__));
+
+struct uvc_frame_uncompressed {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bFrameIndex;
+	__u8  bmCapabilities;
+	__u16 wWidth;
+	__u16 wHeight;
+	__u32 dwMinBitRate;
+	__u32 dwMaxBitRate;
+	__u32 dwMaxVideoFrameBufferSize;
+	__u32 dwDefaultFrameInterval;
+	__u8  bFrameIntervalType;
+	__u32 dwFrameInterval[];
+} __attribute__((__packed__));
+
+#define UVC_FRAME_UNCOMPRESSED(n) \
+	uvc_frame_uncompressed_##n
+
+#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) 			\
+struct UVC_FRAME_UNCOMPRESSED(n) {				\
+	__u8  bLength;						\
+	__u8  bDescriptorType;					\
+	__u8  bDescriptorSubType;				\
+	__u8  bFrameIndex;					\
+	__u8  bmCapabilities;					\
+	__u16 wWidth;						\
+	__u16 wHeight;						\
+	__u32 dwMinBitRate;					\
+	__u32 dwMaxBitRate;					\
+	__u32 dwMaxVideoFrameBufferSize;			\
+	__u32 dwDefaultFrameInterval;				\
+	__u8  bFrameIntervalType;				\
+	__u32 dwFrameInterval[n];				\
+} __attribute__ ((packed))
+
+struct uvc_format_mjpeg {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bFormatIndex;
+	__u8  bNumFrameDescriptors;
+	__u8  bmFlags;
+	__u8  bDefaultFrameIndex;
+	__u8  bAspectRatioX;
+	__u8  bAspectRatioY;
+	__u8  bmInterfaceFlags;
+	__u8  bCopyProtect;
+} __attribute__((__packed__));
+
+struct uvc_frame_mjpeg {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bFrameIndex;
+	__u8  bmCapabilities;
+	__u16 wWidth;
+	__u16 wHeight;
+	__u32 dwMinBitRate;
+	__u32 dwMaxBitRate;
+	__u32 dwMaxVideoFrameBufferSize;
+	__u32 dwDefaultFrameInterval;
+	__u8  bFrameIntervalType;
+	__u32 dwFrameInterval[];
+} __attribute__((__packed__));
+
+#define UVC_FRAME_MJPEG(n) \
+	uvc_frame_mjpeg_##n
+
+#define DECLARE_UVC_FRAME_MJPEG(n) 				\
+struct UVC_FRAME_MJPEG(n) {					\
+	__u8  bLength;						\
+	__u8  bDescriptorType;					\
+	__u8  bDescriptorSubType;				\
+	__u8  bFrameIndex;					\
+	__u8  bmCapabilities;					\
+	__u16 wWidth;						\
+	__u16 wHeight;						\
+	__u32 dwMinBitRate;					\
+	__u32 dwMaxBitRate;					\
+	__u32 dwMaxVideoFrameBufferSize;			\
+	__u32 dwDefaultFrameInterval;				\
+	__u8  bFrameIntervalType;				\
+	__u32 dwFrameInterval[n];				\
+} __attribute__ ((packed))
+
+struct uvc_color_matching_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubType;
+	__u8  bColorPrimaries;
+	__u8  bTransferCharacteristics;
+	__u8  bMatrixCoefficients;
+} __attribute__((__packed__));
+
+#define UVC_DT_INPUT_HEADER			1
+#define UVC_DT_OUTPUT_HEADER			2
+#define UVC_DT_FORMAT_UNCOMPRESSED		4
+#define UVC_DT_FRAME_UNCOMPRESSED		5
+#define UVC_DT_FORMAT_MJPEG			6
+#define UVC_DT_FRAME_MJPEG			7
+#define UVC_DT_COLOR_MATCHING			13
+
+#define UVC_DT_INPUT_HEADER_SIZE(n, p)		(13+(n*p))
+#define UVC_DT_OUTPUT_HEADER_SIZE(n, p)		(9+(n*p))
+#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE		27
+#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n)	(26+4*(n))
+#define UVC_DT_FORMAT_MJPEG_SIZE		11
+#define UVC_DT_FRAME_MJPEG_SIZE(n)		(26+4*(n))
+#define UVC_DT_COLOR_MATCHING_SIZE		6
+
+extern int uvc_bind_config(struct usb_configuration *c,
+			   const struct uvc_descriptor_header * const *control,
+			   const struct uvc_descriptor_header * const *fs_streaming,
+			   const struct uvc_descriptor_header * const *hs_streaming);
+
+#endif /* _F_UVC_H_ */
+
diff --git a/drivers/usb/gadget/fsl_mx3_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c
similarity index 89%
rename from drivers/usb/gadget/fsl_mx3_udc.c
rename to drivers/usb/gadget/fsl_mxc_udc.c
index 20a802e..d0b8bde 100644
--- a/drivers/usb/gadget/fsl_mx3_udc.c
+++ b/drivers/usb/gadget/fsl_mxc_udc.c
@@ -50,12 +50,14 @@
 		goto egusb;
 	}
 
-	freq = clk_get_rate(mxc_usb_clk);
-	if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
-	    (freq < 59999000 || freq > 60001000)) {
-		dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
-		ret = -EINVAL;
-		goto eclkrate;
+	if (!cpu_is_mx51()) {
+		freq = clk_get_rate(mxc_usb_clk);
+		if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
+		    (freq < 59999000 || freq > 60001000)) {
+			dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
+			ret = -EINVAL;
+			goto eclkrate;
+		}
 	}
 
 	ret = clk_enable(mxc_usb_clk);
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index fa3d142..08a9a62 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -489,7 +489,7 @@
 	case USB_ENDPOINT_XFER_ISOC:
 		/* Calculate transactions needed for high bandwidth iso */
 		mult = (unsigned char)(1 + ((max >> 11) & 0x03));
-		max = max & 0x8ff;	/* bit 0~10 */
+		max = max & 0x7ff;	/* bit 0~10 */
 		/* 3 transactions at most */
 		if (mult > 3)
 			goto en_done;
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
new file mode 100644
index 0000000..4b0e4a0
--- /dev/null
+++ b/drivers/usb/gadget/g_ffs.c
@@ -0,0 +1,426 @@
+#include <linux/module.h>
+#include <linux/utsname.h>
+
+
+/*
+ * kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module.  So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+
+#include "composite.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+
+#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
+#  if defined USB_ETH_RNDIS
+#    undef USB_ETH_RNDIS
+#  endif
+#  ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+#    define USB_ETH_RNDIS y
+#  endif
+
+#  include "f_ecm.c"
+#  include "f_subset.c"
+#  ifdef USB_ETH_RNDIS
+#    include "f_rndis.c"
+#    include "rndis.c"
+#  endif
+#  include "u_ether.c"
+
+static u8 gfs_hostaddr[ETH_ALEN];
+#else
+#  if !defined CONFIG_USB_FUNCTIONFS_GENERIC
+#    define CONFIG_USB_FUNCTIONFS_GENERIC
+#  endif
+#  define gether_cleanup() do { } while (0)
+#  define gether_setup(gadget, hostaddr)   ((int)0)
+#endif
+
+#include "f_fs.c"
+
+
+#define DRIVER_NAME	"g_ffs"
+#define DRIVER_DESC	"USB Function Filesystem"
+#define DRIVER_VERSION	"24 Aug 2004"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Michal Nazarewicz");
+MODULE_LICENSE("GPL");
+
+
+static unsigned short gfs_vendor_id    = 0x0525;	/* XXX NetChip */
+static unsigned short gfs_product_id   = 0xa4ac;	/* XXX */
+
+static struct usb_device_descriptor gfs_dev_desc = {
+	.bLength		= sizeof gfs_dev_desc,
+	.bDescriptorType	= USB_DT_DEVICE,
+
+	.bcdUSB			= cpu_to_le16(0x0200),
+	.bDeviceClass		= USB_CLASS_PER_INTERFACE,
+
+	/* Vendor and product id can be overridden by module parameters.  */
+	/* .idVendor		= cpu_to_le16(gfs_vendor_id), */
+	/* .idProduct		= cpu_to_le16(gfs_product_id), */
+	/* .bcdDevice		= f(hardware) */
+	/* .iManufacturer	= DYNAMIC */
+	/* .iProduct		= DYNAMIC */
+	/* NO SERIAL NUMBER */
+	.bNumConfigurations	= 1,
+};
+
+#define GFS_MODULE_PARAM_DESC(name, field) \
+	MODULE_PARM_DESC(name, "Value of the " #field " field of the device descriptor sent to the host.  Takes effect only prior to the user-space driver registering to the FunctionFS.")
+
+module_param_named(usb_class,    gfs_dev_desc.bDeviceClass,    byte,   0644);
+GFS_MODULE_PARAM_DESC(usb_class, bDeviceClass);
+module_param_named(usb_subclass, gfs_dev_desc.bDeviceSubClass, byte,   0644);
+GFS_MODULE_PARAM_DESC(usb_subclass, bDeviceSubClass);
+module_param_named(usb_protocol, gfs_dev_desc.bDeviceProtocol, byte,   0644);
+GFS_MODULE_PARAM_DESC(usb_protocol, bDeviceProtocol);
+module_param_named(usb_vendor,   gfs_vendor_id,                ushort, 0644);
+GFS_MODULE_PARAM_DESC(usb_vendor, idVendor);
+module_param_named(usb_product,  gfs_product_id,               ushort, 0644);
+GFS_MODULE_PARAM_DESC(usb_product, idProduct);
+
+
+
+static const struct usb_descriptor_header *gfs_otg_desc[] = {
+	(const struct usb_descriptor_header *)
+	&(const struct usb_otg_descriptor) {
+		.bLength		= sizeof(struct usb_otg_descriptor),
+		.bDescriptorType	= USB_DT_OTG,
+
+		/* REVISIT SRP-only hardware is possible, although
+		 * it would not be called "OTG" ... */
+		.bmAttributes		= USB_OTG_SRP | USB_OTG_HNP,
+	},
+
+	NULL
+};
+
+/* string IDs are assigned dynamically */
+
+enum {
+	GFS_STRING_MANUFACTURER_IDX,
+	GFS_STRING_PRODUCT_IDX,
+#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+	GFS_STRING_RNDIS_CONFIG_IDX,
+#endif
+#ifdef CONFIG_USB_FUNCTIONFS_ETH
+	GFS_STRING_ECM_CONFIG_IDX,
+#endif
+#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
+	GFS_STRING_GENERIC_CONFIG_IDX,
+#endif
+};
+
+static       char gfs_manufacturer[50];
+static const char gfs_driver_desc[] = DRIVER_DESC;
+static const char gfs_short_name[]  = DRIVER_NAME;
+
+static struct usb_string gfs_strings[] = {
+	[GFS_STRING_MANUFACTURER_IDX].s = gfs_manufacturer,
+	[GFS_STRING_PRODUCT_IDX].s = gfs_driver_desc,
+#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+	[GFS_STRING_RNDIS_CONFIG_IDX].s = "FunctionFS + RNDIS",
+#endif
+#ifdef CONFIG_USB_FUNCTIONFS_ETH
+	[GFS_STRING_ECM_CONFIG_IDX].s = "FunctionFS + ECM",
+#endif
+#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
+	[GFS_STRING_GENERIC_CONFIG_IDX].s = "FunctionFS",
+#endif
+	{  } /* end of list */
+};
+
+static struct usb_gadget_strings *gfs_dev_strings[] = {
+	&(struct usb_gadget_strings) {
+		.language	= 0x0409,	/* en-us */
+		.strings	= gfs_strings,
+	},
+	NULL,
+};
+
+
+#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+static int gfs_do_rndis_config(struct usb_configuration *c);
+
+static struct usb_configuration gfs_rndis_config_driver = {
+	.label			= "FunctionFS + RNDIS",
+	.bind			= gfs_do_rndis_config,
+	.bConfigurationValue	= 1,
+	/* .iConfiguration	= DYNAMIC */
+	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
+};
+#  define gfs_add_rndis_config(cdev) \
+	usb_add_config(cdev, &gfs_rndis_config_driver)
+#else
+#  define gfs_add_rndis_config(cdev) 0
+#endif
+
+
+#ifdef CONFIG_USB_FUNCTIONFS_ETH
+static int gfs_do_ecm_config(struct usb_configuration *c);
+
+static struct usb_configuration gfs_ecm_config_driver = {
+	.label			= "FunctionFS + ECM",
+	.bind			= gfs_do_ecm_config,
+	.bConfigurationValue	= 1,
+	/* .iConfiguration	= DYNAMIC */
+	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
+};
+#  define gfs_add_ecm_config(cdev) \
+	usb_add_config(cdev, &gfs_ecm_config_driver)
+#else
+#  define gfs_add_ecm_config(cdev) 0
+#endif
+
+
+#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
+static int gfs_do_generic_config(struct usb_configuration *c);
+
+static struct usb_configuration gfs_generic_config_driver = {
+	.label			= "FunctionFS",
+	.bind			= gfs_do_generic_config,
+	.bConfigurationValue	= 2,
+	/* .iConfiguration	= DYNAMIC */
+	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
+};
+#  define gfs_add_generic_config(cdev) \
+	usb_add_config(cdev, &gfs_generic_config_driver)
+#else
+#  define gfs_add_generic_config(cdev) 0
+#endif
+
+
+static int gfs_bind(struct usb_composite_dev *cdev);
+static int gfs_unbind(struct usb_composite_dev *cdev);
+
+static struct usb_composite_driver gfs_driver = {
+	.name		= gfs_short_name,
+	.dev		= &gfs_dev_desc,
+	.strings	= gfs_dev_strings,
+	.bind		= gfs_bind,
+	.unbind		= gfs_unbind,
+};
+
+
+static struct ffs_data *gfs_ffs_data;
+static unsigned long gfs_registered;
+
+
+static int  gfs_init(void)
+{
+	ENTER();
+
+	return functionfs_init();
+}
+module_init(gfs_init);
+
+static void  gfs_exit(void)
+{
+	ENTER();
+
+	if (test_and_clear_bit(0, &gfs_registered))
+		usb_composite_unregister(&gfs_driver);
+
+	functionfs_cleanup();
+}
+module_exit(gfs_exit);
+
+
+static int functionfs_ready_callback(struct ffs_data *ffs)
+{
+	int ret;
+
+	ENTER();
+
+	if (WARN_ON(test_and_set_bit(0, &gfs_registered)))
+		return -EBUSY;
+
+	gfs_ffs_data = ffs;
+	ret = usb_composite_register(&gfs_driver);
+	if (unlikely(ret < 0))
+		clear_bit(0, &gfs_registered);
+	return ret;
+}
+
+static void functionfs_closed_callback(struct ffs_data *ffs)
+{
+	ENTER();
+
+	if (test_and_clear_bit(0, &gfs_registered))
+		usb_composite_unregister(&gfs_driver);
+}
+
+
+static int functionfs_check_dev_callback(const char *dev_name)
+{
+	return 0;
+}
+
+
+
+static int gfs_bind(struct usb_composite_dev *cdev)
+{
+	int ret;
+
+	ENTER();
+
+	if (WARN_ON(!gfs_ffs_data))
+		return -ENODEV;
+
+	ret = gether_setup(cdev->gadget, gfs_hostaddr);
+	if (unlikely(ret < 0))
+		goto error_quick;
+
+	gfs_dev_desc.idVendor  = cpu_to_le16(gfs_vendor_id);
+	gfs_dev_desc.idProduct = cpu_to_le16(gfs_product_id);
+
+	snprintf(gfs_manufacturer, sizeof gfs_manufacturer, "%s %s with %s",
+		 init_utsname()->sysname, init_utsname()->release,
+		 cdev->gadget->name);
+	ret = usb_string_id(cdev);
+	if (unlikely(ret < 0))
+		goto error;
+	gfs_strings[GFS_STRING_MANUFACTURER_IDX].id = ret;
+	gfs_dev_desc.iManufacturer = ret;
+
+	ret = usb_string_id(cdev);
+	if (unlikely(ret < 0))
+		goto error;
+	gfs_strings[GFS_STRING_PRODUCT_IDX].id = ret;
+	gfs_dev_desc.iProduct = ret;
+
+#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+	ret = usb_string_id(cdev);
+	if (unlikely(ret < 0))
+		goto error;
+	gfs_strings[GFS_STRING_RNDIS_CONFIG_IDX].id = ret;
+	gfs_rndis_config_driver.iConfiguration = ret;
+#endif
+
+#ifdef CONFIG_USB_FUNCTIONFS_ETH
+	ret = usb_string_id(cdev);
+	if (unlikely(ret < 0))
+		goto error;
+	gfs_strings[GFS_STRING_ECM_CONFIG_IDX].id = ret;
+	gfs_ecm_config_driver.iConfiguration = ret;
+#endif
+
+#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
+	ret = usb_string_id(cdev);
+	if (unlikely(ret < 0))
+		goto error;
+	gfs_strings[GFS_STRING_GENERIC_CONFIG_IDX].id = ret;
+	gfs_generic_config_driver.iConfiguration = ret;
+#endif
+
+	ret = functionfs_bind(gfs_ffs_data, cdev);
+	if (unlikely(ret < 0))
+		goto error;
+
+	ret = gfs_add_rndis_config(cdev);
+	if (unlikely(ret < 0))
+		goto error_unbind;
+
+	ret = gfs_add_ecm_config(cdev);
+	if (unlikely(ret < 0))
+		goto error_unbind;
+
+	ret = gfs_add_generic_config(cdev);
+	if (unlikely(ret < 0))
+		goto error_unbind;
+
+	return 0;
+
+error_unbind:
+	functionfs_unbind(gfs_ffs_data);
+error:
+	gether_cleanup();
+error_quick:
+	gfs_ffs_data = NULL;
+	return ret;
+}
+
+static int gfs_unbind(struct usb_composite_dev *cdev)
+{
+	ENTER();
+
+	/* We may have been called in an error recovery frem
+	 * composite_bind() after gfs_unbind() failure so we need to
+	 * check if gfs_ffs_data is not NULL since gfs_bind() handles
+	 * all error recovery itself.  I'd rather we werent called
+	 * from composite on orror recovery, but what you're gonna
+	 * do...? */
+
+	if (gfs_ffs_data) {
+		gether_cleanup();
+		functionfs_unbind(gfs_ffs_data);
+		gfs_ffs_data = NULL;
+	}
+
+	return 0;
+}
+
+
+static int __gfs_do_config(struct usb_configuration *c,
+			   int (*eth)(struct usb_configuration *c, u8 *ethaddr),
+			   u8 *ethaddr)
+{
+	int ret;
+
+	if (WARN_ON(!gfs_ffs_data))
+		return -ENODEV;
+
+	if (gadget_is_otg(c->cdev->gadget)) {
+		c->descriptors = gfs_otg_desc;
+		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+	}
+
+	if (eth) {
+		ret = eth(c, ethaddr);
+		if (unlikely(ret < 0))
+			return ret;
+	}
+
+	ret = functionfs_add(c->cdev, c, gfs_ffs_data);
+	if (unlikely(ret < 0))
+		return ret;
+
+	return 0;
+}
+
+#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+static int gfs_do_rndis_config(struct usb_configuration *c)
+{
+	ENTER();
+
+	return __gfs_do_config(c, rndis_bind_config, gfs_hostaddr);
+}
+#endif
+
+#ifdef CONFIG_USB_FUNCTIONFS_ETH
+static int gfs_do_ecm_config(struct usb_configuration *c)
+{
+	ENTER();
+
+	return __gfs_do_config(c,
+			       can_support_ecm(c->cdev->gadget)
+			     ? ecm_bind_config : geth_bind_config,
+			       gfs_hostaddr);
+}
+#endif
+
+#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
+static int gfs_do_generic_config(struct usb_configuration *c)
+{
+	ENTER();
+
+	return __gfs_do_config(c, NULL, NULL);
+}
+#endif
diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c
new file mode 100644
index 0000000..7757226
--- /dev/null
+++ b/drivers/usb/gadget/hid.c
@@ -0,0 +1,298 @@
+/*
+ * hid.c -- HID Composite driver
+ *
+ * Based on multi.c
+ *
+ * Copyright (C) 2010 Fabien Chouteau <fabien.chouteau@barco.com>
+ *
+ * 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/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+
+#define DRIVER_DESC		"HID Gadget"
+#define DRIVER_VERSION		"2010/03/16"
+
+/*-------------------------------------------------------------------------*/
+
+#define HIDG_VENDOR_NUM		0x0525	/* XXX NetChip */
+#define HIDG_PRODUCT_NUM	0xa4ac	/* Linux-USB HID gadget */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module.  So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+
+#include "composite.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+
+#include "f_hid.c"
+
+
+struct hidg_func_node {
+	struct list_head node;
+	struct hidg_func_descriptor *func;
+};
+
+static LIST_HEAD(hidg_func_list);
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_device_descriptor device_desc = {
+	.bLength =		sizeof device_desc,
+	.bDescriptorType =	USB_DT_DEVICE,
+
+	.bcdUSB =		cpu_to_le16(0x0200),
+
+	/* .bDeviceClass =		USB_CLASS_COMM, */
+	/* .bDeviceSubClass =	0, */
+	/* .bDeviceProtocol =	0, */
+	.bDeviceClass =		0xEF,
+	.bDeviceSubClass =	2,
+	.bDeviceProtocol =	1,
+	/* .bMaxPacketSize0 = f(hardware) */
+
+	/* Vendor and product id can be overridden by module parameters.  */
+	.idVendor =		cpu_to_le16(HIDG_VENDOR_NUM),
+	.idProduct =		cpu_to_le16(HIDG_PRODUCT_NUM),
+	/* .bcdDevice = f(hardware) */
+	/* .iManufacturer = DYNAMIC */
+	/* .iProduct = DYNAMIC */
+	/* NO SERIAL NUMBER */
+	.bNumConfigurations =	1,
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+	.bLength =		sizeof otg_descriptor,
+	.bDescriptorType =	USB_DT_OTG,
+
+	/* REVISIT SRP-only hardware is possible, although
+	 * it would not be called "OTG" ...
+	 */
+	.bmAttributes =		USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
+	NULL,
+};
+
+
+/* string IDs are assigned dynamically */
+
+#define STRING_MANUFACTURER_IDX		0
+#define STRING_PRODUCT_IDX		1
+
+static char manufacturer[50];
+
+static struct usb_string strings_dev[] = {
+	[STRING_MANUFACTURER_IDX].s = manufacturer,
+	[STRING_PRODUCT_IDX].s = DRIVER_DESC,
+	{  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+	&stringtab_dev,
+	NULL,
+};
+
+
+
+/****************************** Configurations ******************************/
+
+static int __init do_config(struct usb_configuration *c)
+{
+	struct hidg_func_node *e;
+	int func = 0, status = 0;
+
+	if (gadget_is_otg(c->cdev->gadget)) {
+		c->descriptors = otg_desc;
+		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+	}
+
+	list_for_each_entry(e, &hidg_func_list, node) {
+		status = hidg_bind_config(c, e->func, func++);
+		if (status)
+			break;
+	}
+
+	return status;
+}
+
+static struct usb_configuration config_driver = {
+	.label			= "HID Gadget",
+	.bind			= do_config,
+	.bConfigurationValue	= 1,
+	/* .iConfiguration = DYNAMIC */
+	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
+};
+
+/****************************** Gadget Bind ******************************/
+
+static int __init hid_bind(struct usb_composite_dev *cdev)
+{
+	struct usb_gadget *gadget = cdev->gadget;
+	struct list_head *tmp;
+	int status, gcnum, funcs = 0;
+
+	list_for_each(tmp, &hidg_func_list)
+		funcs++;
+
+	if (!funcs)
+		return -ENODEV;
+
+	/* set up HID */
+	status = ghid_setup(cdev->gadget, funcs);
+	if (status < 0)
+		return status;
+
+	gcnum = usb_gadget_controller_number(gadget);
+	if (gcnum >= 0)
+		device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
+	else
+		device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
+
+
+	/* Allocate string descriptor numbers ... note that string
+	 * contents can be overridden by the composite_dev glue.
+	 */
+
+	/* device descriptor strings: manufacturer, product */
+	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+		init_utsname()->sysname, init_utsname()->release,
+		gadget->name);
+	status = usb_string_id(cdev);
+	if (status < 0)
+		return status;
+	strings_dev[STRING_MANUFACTURER_IDX].id = status;
+	device_desc.iManufacturer = status;
+
+	status = usb_string_id(cdev);
+	if (status < 0)
+		return status;
+	strings_dev[STRING_PRODUCT_IDX].id = status;
+	device_desc.iProduct = status;
+
+	/* register our configuration */
+	status = usb_add_config(cdev, &config_driver);
+	if (status < 0)
+		return status;
+
+	dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
+
+	return 0;
+}
+
+static int __exit hid_unbind(struct usb_composite_dev *cdev)
+{
+	ghid_cleanup();
+	return 0;
+}
+
+static int __init hidg_plat_driver_probe(struct platform_device *pdev)
+{
+	struct hidg_func_descriptor *func = pdev->dev.platform_data;
+	struct hidg_func_node *entry;
+
+	if (!func) {
+		dev_err(&pdev->dev, "Platform data missing\n");
+		return -ENODEV;
+	}
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	entry->func = func;
+	list_add_tail(&entry->node, &hidg_func_list);
+
+	return 0;
+}
+
+static int __devexit hidg_plat_driver_remove(struct platform_device *pdev)
+{
+	struct hidg_func_node *e, *n;
+
+	list_for_each_entry_safe(e, n, &hidg_func_list, node) {
+		list_del(&e->node);
+		kfree(e);
+	}
+
+	return 0;
+}
+
+
+/****************************** Some noise ******************************/
+
+
+static struct usb_composite_driver hidg_driver = {
+	.name		= "g_hid",
+	.dev		= &device_desc,
+	.strings	= dev_strings,
+	.bind		= hid_bind,
+	.unbind		= __exit_p(hid_unbind),
+};
+
+static struct platform_driver hidg_plat_driver = {
+	.remove		= __devexit_p(hidg_plat_driver_remove),
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "hidg",
+	},
+};
+
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Fabien Chouteau, Peter Korsgaard");
+MODULE_LICENSE("GPL");
+
+static int __init hidg_init(void)
+{
+	int status;
+
+	status = platform_driver_probe(&hidg_plat_driver,
+				hidg_plat_driver_probe);
+	if (status < 0)
+		return status;
+
+	status = usb_composite_register(&hidg_driver);
+	if (status < 0)
+		platform_driver_unregister(&hidg_plat_driver);
+
+	return status;
+}
+module_init(hidg_init);
+
+static void __exit hidg_cleanup(void)
+{
+	platform_driver_unregister(&hidg_plat_driver);
+	usb_composite_unregister(&hidg_driver);
+}
+module_exit(hidg_cleanup);
diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h
index ff61e48..cd16231 100644
--- a/drivers/usb/gadget/pxa27x_udc.h
+++ b/drivers/usb/gadget/pxa27x_udc.h
@@ -360,7 +360,7 @@
 	 * Specific pxa endpoint data, needed for hardware initialization
 	 */
 	unsigned		dir_in:1;
-	unsigned		addr:3;
+	unsigned		addr:4;
 	unsigned		config:2;
 	unsigned		interface:3;
 	unsigned		alternate:3;
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 07f4178..1da755a 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -715,7 +715,7 @@
 	return 0;
 }
 
-static int __init get_ether_addr(const char *str, u8 *dev_addr)
+static int get_ether_addr(const char *str, u8 *dev_addr)
 {
 	if (str) {
 		unsigned	i;
@@ -764,7 +764,7 @@
  *
  * Returns negative errno, or zero on success
  */
-int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
+int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
 {
 	struct eth_dev		*dev;
 	struct net_device	*net;
diff --git a/drivers/usb/gadget/uvc.h b/drivers/usb/gadget/uvc.h
new file mode 100644
index 0000000..0a705e6
--- /dev/null
+++ b/drivers/usb/gadget/uvc.h
@@ -0,0 +1,241 @@
+/*
+ *	uvc_gadget.h  --  USB Video Class Gadget driver
+ *
+ *	Copyright (C) 2009-2010
+ *	    Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ *	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.
+ *
+ */
+
+#ifndef _UVC_GADGET_H_
+#define _UVC_GADGET_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+
+#define UVC_EVENT_FIRST			(V4L2_EVENT_PRIVATE_START + 0)
+#define UVC_EVENT_CONNECT		(V4L2_EVENT_PRIVATE_START + 0)
+#define UVC_EVENT_DISCONNECT		(V4L2_EVENT_PRIVATE_START + 1)
+#define UVC_EVENT_STREAMON		(V4L2_EVENT_PRIVATE_START + 2)
+#define UVC_EVENT_STREAMOFF		(V4L2_EVENT_PRIVATE_START + 3)
+#define UVC_EVENT_SETUP			(V4L2_EVENT_PRIVATE_START + 4)
+#define UVC_EVENT_DATA			(V4L2_EVENT_PRIVATE_START + 5)
+#define UVC_EVENT_LAST			(V4L2_EVENT_PRIVATE_START + 5)
+
+struct uvc_request_data
+{
+	unsigned int length;
+	__u8 data[60];
+};
+
+struct uvc_event
+{
+	union {
+		enum usb_device_speed speed;
+		struct usb_ctrlrequest req;
+		struct uvc_request_data data;
+	};
+};
+
+#define UVCIOC_SEND_RESPONSE		_IOW('U', 1, struct uvc_request_data)
+
+#define UVC_INTF_CONTROL		0
+#define UVC_INTF_STREAMING		1
+
+/* ------------------------------------------------------------------------
+ * UVC constants & structures
+ */
+
+/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
+#define UVC_STREAM_EOH				(1 << 7)
+#define UVC_STREAM_ERR				(1 << 6)
+#define UVC_STREAM_STI				(1 << 5)
+#define UVC_STREAM_RES				(1 << 4)
+#define UVC_STREAM_SCR				(1 << 3)
+#define UVC_STREAM_PTS				(1 << 2)
+#define UVC_STREAM_EOF				(1 << 1)
+#define UVC_STREAM_FID				(1 << 0)
+
+struct uvc_streaming_control {
+	__u16 bmHint;
+	__u8  bFormatIndex;
+	__u8  bFrameIndex;
+	__u32 dwFrameInterval;
+	__u16 wKeyFrameRate;
+	__u16 wPFrameRate;
+	__u16 wCompQuality;
+	__u16 wCompWindowSize;
+	__u16 wDelay;
+	__u32 dwMaxVideoFrameSize;
+	__u32 dwMaxPayloadTransferSize;
+	__u32 dwClockFrequency;
+	__u8  bmFramingInfo;
+	__u8  bPreferedVersion;
+	__u8  bMinVersion;
+	__u8  bMaxVersion;
+} __attribute__((__packed__));
+
+/* ------------------------------------------------------------------------
+ * Debugging, printing and logging
+ */
+
+#ifdef __KERNEL__
+
+#include <linux/usb.h>	/* For usb_endpoint_* */
+#include <linux/usb/gadget.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-fh.h>
+
+#include "uvc_queue.h"
+
+#define UVC_TRACE_PROBE				(1 << 0)
+#define UVC_TRACE_DESCR				(1 << 1)
+#define UVC_TRACE_CONTROL			(1 << 2)
+#define UVC_TRACE_FORMAT			(1 << 3)
+#define UVC_TRACE_CAPTURE			(1 << 4)
+#define UVC_TRACE_CALLS				(1 << 5)
+#define UVC_TRACE_IOCTL				(1 << 6)
+#define UVC_TRACE_FRAME				(1 << 7)
+#define UVC_TRACE_SUSPEND			(1 << 8)
+#define UVC_TRACE_STATUS			(1 << 9)
+
+#define UVC_WARN_MINMAX				0
+#define UVC_WARN_PROBE_DEF			1
+
+extern unsigned int uvc_trace_param;
+
+#define uvc_trace(flag, msg...) \
+	do { \
+		if (uvc_trace_param & flag) \
+			printk(KERN_DEBUG "uvcvideo: " msg); \
+	} while (0)
+
+#define uvc_warn_once(dev, warn, msg...) \
+	do { \
+		if (!test_and_set_bit(warn, &dev->warnings)) \
+			printk(KERN_INFO "uvcvideo: " msg); \
+	} while (0)
+
+#define uvc_printk(level, msg...) \
+	printk(level "uvcvideo: " msg)
+
+/* ------------------------------------------------------------------------
+ * Driver specific constants
+ */
+
+#define DRIVER_VERSION				"0.1.0"
+#define DRIVER_VERSION_NUMBER			KERNEL_VERSION(0, 1, 0)
+
+#define DMA_ADDR_INVALID			(~(dma_addr_t)0)
+
+#define UVC_NUM_REQUESTS			4
+#define UVC_MAX_REQUEST_SIZE			64
+#define UVC_MAX_EVENTS				4
+
+#define USB_DT_INTERFACE_ASSOCIATION_SIZE	8
+#define USB_CLASS_MISC				0xef
+
+/* ------------------------------------------------------------------------
+ * Structures
+ */
+
+struct uvc_video
+{
+	struct usb_ep *ep;
+
+	/* Frame parameters */
+	u8 bpp;
+	u32 fcc;
+	unsigned int width;
+	unsigned int height;
+	unsigned int imagesize;
+
+	/* Requests */
+	unsigned int req_size;
+	struct usb_request *req[UVC_NUM_REQUESTS];
+	__u8 *req_buffer[UVC_NUM_REQUESTS];
+	struct list_head req_free;
+	spinlock_t req_lock;
+
+	void (*encode) (struct usb_request *req, struct uvc_video *video,
+			struct uvc_buffer *buf);
+
+	/* Context data used by the completion handler */
+	__u32 payload_size;
+	__u32 max_payload_size;
+
+	struct uvc_video_queue queue;
+	unsigned int fid;
+};
+
+enum uvc_state
+{
+	UVC_STATE_DISCONNECTED,
+	UVC_STATE_CONNECTED,
+	UVC_STATE_STREAMING,
+};
+
+struct uvc_device
+{
+	struct video_device *vdev;
+	enum uvc_state state;
+	struct usb_function func;
+	struct uvc_video video;
+
+	/* Descriptors */
+	struct {
+		const struct uvc_descriptor_header * const *control;
+		const struct uvc_descriptor_header * const *fs_streaming;
+		const struct uvc_descriptor_header * const *hs_streaming;
+	} desc;
+
+	unsigned int control_intf;
+	struct usb_ep *control_ep;
+	struct usb_request *control_req;
+	void *control_buf;
+
+	unsigned int streaming_intf;
+
+	/* Events */
+	unsigned int event_length;
+	unsigned int event_setup_out : 1;
+};
+
+static inline struct uvc_device *to_uvc(struct usb_function *f)
+{
+	return container_of(f, struct uvc_device, func);
+}
+
+struct uvc_file_handle
+{
+	struct v4l2_fh vfh;
+	struct uvc_video *device;
+};
+
+#define to_uvc_file_handle(handle) \
+	container_of(handle, struct uvc_file_handle, vfh)
+
+extern struct v4l2_file_operations uvc_v4l2_fops;
+
+/* ------------------------------------------------------------------------
+ * Functions
+ */
+
+extern int uvc_video_enable(struct uvc_video *video, int enable);
+extern int uvc_video_init(struct uvc_video *video);
+extern int uvc_video_pump(struct uvc_video *video);
+
+extern void uvc_endpoint_stream(struct uvc_device *dev);
+
+extern void uvc_function_connect(struct uvc_device *uvc);
+extern void uvc_function_disconnect(struct uvc_device *uvc);
+
+#endif /* __KERNEL__ */
+
+#endif /* _UVC_GADGET_H_ */
+
diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c
new file mode 100644
index 0000000..4389199
--- /dev/null
+++ b/drivers/usb/gadget/uvc_queue.c
@@ -0,0 +1,583 @@
+/*
+ *	uvc_queue.c  --  USB Video Class driver - Buffers management
+ *
+ *	Copyright (C) 2005-2010
+ *	    Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ *	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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include "uvc.h"
+
+/* ------------------------------------------------------------------------
+ * Video buffers queue management.
+ *
+ * Video queues is initialized by uvc_queue_init(). The function performs
+ * basic initialization of the uvc_video_queue struct and never fails.
+ *
+ * Video buffer allocation and freeing are performed by uvc_alloc_buffers and
+ * uvc_free_buffers respectively. The former acquires the video queue lock,
+ * while the later must be called with the lock held (so that allocation can
+ * free previously allocated buffers). Trying to free buffers that are mapped
+ * to user space will return -EBUSY.
+ *
+ * Video buffers are managed using two queues. However, unlike most USB video
+ * drivers that use an in queue and an out queue, we use a main queue to hold
+ * all queued buffers (both 'empty' and 'done' buffers), and an irq queue to
+ * hold empty buffers. This design (copied from video-buf) minimizes locking
+ * in interrupt, as only one queue is shared between interrupt and user
+ * contexts.
+ *
+ * Use cases
+ * ---------
+ *
+ * Unless stated otherwise, all operations that modify the irq buffers queue
+ * are protected by the irq spinlock.
+ *
+ * 1. The user queues the buffers, starts streaming and dequeues a buffer.
+ *
+ *    The buffers are added to the main and irq queues. Both operations are
+ *    protected by the queue lock, and the later is protected by the irq
+ *    spinlock as well.
+ *
+ *    The completion handler fetches a buffer from the irq queue and fills it
+ *    with video data. If no buffer is available (irq queue empty), the handler
+ *    returns immediately.
+ *
+ *    When the buffer is full, the completion handler removes it from the irq
+ *    queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue.
+ *    At that point, any process waiting on the buffer will be woken up. If a
+ *    process tries to dequeue a buffer after it has been marked ready, the
+ *    dequeing will succeed immediately.
+ *
+ * 2. Buffers are queued, user is waiting on a buffer and the device gets
+ *    disconnected.
+ *
+ *    When the device is disconnected, the kernel calls the completion handler
+ *    with an appropriate status code. The handler marks all buffers in the
+ *    irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so
+ *    that any process waiting on a buffer gets woken up.
+ *
+ *    Waking up up the first buffer on the irq list is not enough, as the
+ *    process waiting on the buffer might restart the dequeue operation
+ *    immediately.
+ *
+ */
+
+void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
+{
+	mutex_init(&queue->mutex);
+	spin_lock_init(&queue->irqlock);
+	INIT_LIST_HEAD(&queue->mainqueue);
+	INIT_LIST_HEAD(&queue->irqqueue);
+	queue->type = type;
+}
+
+/*
+ * Allocate the video buffers.
+ *
+ * Pages are reserved to make sure they will not be swapped, as they will be
+ * filled in the URB completion handler.
+ *
+ * Buffers will be individually mapped, so they must all be page aligned.
+ */
+int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
+		unsigned int buflength)
+{
+	unsigned int bufsize = PAGE_ALIGN(buflength);
+	unsigned int i;
+	void *mem = NULL;
+	int ret;
+
+	if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
+		nbuffers = UVC_MAX_VIDEO_BUFFERS;
+
+	mutex_lock(&queue->mutex);
+
+	if ((ret = uvc_free_buffers(queue)) < 0)
+		goto done;
+
+	/* Bail out if no buffers should be allocated. */
+	if (nbuffers == 0)
+		goto done;
+
+	/* Decrement the number of buffers until allocation succeeds. */
+	for (; nbuffers > 0; --nbuffers) {
+		mem = vmalloc_32(nbuffers * bufsize);
+		if (mem != NULL)
+			break;
+	}
+
+	if (mem == NULL) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	for (i = 0; i < nbuffers; ++i) {
+		memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
+		queue->buffer[i].buf.index = i;
+		queue->buffer[i].buf.m.offset = i * bufsize;
+		queue->buffer[i].buf.length = buflength;
+		queue->buffer[i].buf.type = queue->type;
+		queue->buffer[i].buf.sequence = 0;
+		queue->buffer[i].buf.field = V4L2_FIELD_NONE;
+		queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
+		queue->buffer[i].buf.flags = 0;
+		init_waitqueue_head(&queue->buffer[i].wait);
+	}
+
+	queue->mem = mem;
+	queue->count = nbuffers;
+	queue->buf_size = bufsize;
+	ret = nbuffers;
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+/*
+ * Free the video buffers.
+ *
+ * This function must be called with the queue lock held.
+ */
+int uvc_free_buffers(struct uvc_video_queue *queue)
+{
+	unsigned int i;
+
+	for (i = 0; i < queue->count; ++i) {
+		if (queue->buffer[i].vma_use_count != 0)
+			return -EBUSY;
+	}
+
+	if (queue->count) {
+		vfree(queue->mem);
+		queue->count = 0;
+	}
+
+	return 0;
+}
+
+static void __uvc_query_buffer(struct uvc_buffer *buf,
+		struct v4l2_buffer *v4l2_buf)
+{
+	memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
+
+	if (buf->vma_use_count)
+		v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
+
+	switch (buf->state) {
+	case UVC_BUF_STATE_ERROR:
+	case UVC_BUF_STATE_DONE:
+		v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
+		break;
+	case UVC_BUF_STATE_QUEUED:
+	case UVC_BUF_STATE_ACTIVE:
+		v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
+		break;
+	case UVC_BUF_STATE_IDLE:
+	default:
+		break;
+	}
+}
+
+int uvc_query_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf)
+{
+	int ret = 0;
+
+	mutex_lock(&queue->mutex);
+	if (v4l2_buf->index >= queue->count) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	__uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+/*
+ * Queue a video buffer. Attempting to queue a buffer that has already been
+ * queued will return -EINVAL.
+ */
+int uvc_queue_buffer(struct uvc_video_queue *queue,
+	struct v4l2_buffer *v4l2_buf)
+{
+	struct uvc_buffer *buf;
+	unsigned long flags;
+	int ret = 0;
+
+	uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
+
+	if (v4l2_buf->type != queue->type ||
+	    v4l2_buf->memory != V4L2_MEMORY_MMAP) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
+			"and/or memory (%u).\n", v4l2_buf->type,
+			v4l2_buf->memory);
+		return -EINVAL;
+	}
+
+	mutex_lock(&queue->mutex);
+	if (v4l2_buf->index >= queue->count) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	buf = &queue->buffer[v4l2_buf->index];
+	if (buf->state != UVC_BUF_STATE_IDLE) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
+			"(%u).\n", buf->state);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+	    v4l2_buf->bytesused > buf->buf.length) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		buf->buf.bytesused = 0;
+	else
+		buf->buf.bytesused = v4l2_buf->bytesused;
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	if (queue->flags & UVC_QUEUE_DISCONNECTED) {
+		spin_unlock_irqrestore(&queue->irqlock, flags);
+		ret = -ENODEV;
+		goto done;
+	}
+	buf->state = UVC_BUF_STATE_QUEUED;
+
+	ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
+	queue->flags &= ~UVC_QUEUE_PAUSED;
+
+	list_add_tail(&buf->stream, &queue->mainqueue);
+	list_add_tail(&buf->queue, &queue->irqqueue);
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
+{
+	if (nonblocking) {
+		return (buf->state != UVC_BUF_STATE_QUEUED &&
+			buf->state != UVC_BUF_STATE_ACTIVE)
+			? 0 : -EAGAIN;
+	}
+
+	return wait_event_interruptible(buf->wait,
+		buf->state != UVC_BUF_STATE_QUEUED &&
+		buf->state != UVC_BUF_STATE_ACTIVE);
+}
+
+/*
+ * Dequeue a video buffer. If nonblocking is false, block until a buffer is
+ * available.
+ */
+int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf, int nonblocking)
+{
+	struct uvc_buffer *buf;
+	int ret = 0;
+
+	if (v4l2_buf->type != queue->type ||
+	    v4l2_buf->memory != V4L2_MEMORY_MMAP) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
+			"and/or memory (%u).\n", v4l2_buf->type,
+			v4l2_buf->memory);
+		return -EINVAL;
+	}
+
+	mutex_lock(&queue->mutex);
+	if (list_empty(&queue->mainqueue)) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
+	if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0)
+		goto done;
+
+	uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n",
+		buf->buf.index, buf->state, buf->buf.bytesused);
+
+	switch (buf->state) {
+	case UVC_BUF_STATE_ERROR:
+		uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data "
+			"(transmission error).\n");
+		ret = -EIO;
+	case UVC_BUF_STATE_DONE:
+		buf->state = UVC_BUF_STATE_IDLE;
+		break;
+
+	case UVC_BUF_STATE_IDLE:
+	case UVC_BUF_STATE_QUEUED:
+	case UVC_BUF_STATE_ACTIVE:
+	default:
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
+			"(driver bug?).\n", buf->state);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	list_del(&buf->stream);
+	__uvc_query_buffer(buf, v4l2_buf);
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+/*
+ * Poll the video queue.
+ *
+ * This function implements video queue polling and is intended to be used by
+ * the device poll handler.
+ */
+unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
+		poll_table *wait)
+{
+	struct uvc_buffer *buf;
+	unsigned int mask = 0;
+
+	mutex_lock(&queue->mutex);
+	if (list_empty(&queue->mainqueue))
+		goto done;
+
+	buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
+
+	poll_wait(file, &buf->wait, wait);
+	if (buf->state == UVC_BUF_STATE_DONE ||
+	    buf->state == UVC_BUF_STATE_ERROR)
+		mask |= POLLOUT | POLLWRNORM;
+
+done:
+	mutex_unlock(&queue->mutex);
+	return mask;
+}
+
+/*
+ * VMA operations.
+ */
+static void uvc_vm_open(struct vm_area_struct *vma)
+{
+	struct uvc_buffer *buffer = vma->vm_private_data;
+	buffer->vma_use_count++;
+}
+
+static void uvc_vm_close(struct vm_area_struct *vma)
+{
+	struct uvc_buffer *buffer = vma->vm_private_data;
+	buffer->vma_use_count--;
+}
+
+static struct vm_operations_struct uvc_vm_ops = {
+	.open		= uvc_vm_open,
+	.close		= uvc_vm_close,
+};
+
+/*
+ * Memory-map a buffer.
+ *
+ * This function implements video buffer memory mapping and is intended to be
+ * used by the device mmap handler.
+ */
+int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
+{
+	struct uvc_buffer *uninitialized_var(buffer);
+	struct page *page;
+	unsigned long addr, start, size;
+	unsigned int i;
+	int ret = 0;
+
+	start = vma->vm_start;
+	size = vma->vm_end - vma->vm_start;
+
+	mutex_lock(&queue->mutex);
+
+	for (i = 0; i < queue->count; ++i) {
+		buffer = &queue->buffer[i];
+		if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+			break;
+	}
+
+	if (i == queue->count || size != queue->buf_size) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	/*
+	 * VM_IO marks the area as being an mmaped region for I/O to a
+	 * device. It also prevents the region from being core dumped.
+	 */
+	vma->vm_flags |= VM_IO;
+
+	addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+	while (size > 0) {
+		page = vmalloc_to_page((void *)addr);
+		if ((ret = vm_insert_page(vma, start, page)) < 0)
+			goto done;
+
+		start += PAGE_SIZE;
+		addr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	vma->vm_ops = &uvc_vm_ops;
+	vma->vm_private_data = buffer;
+	uvc_vm_open(vma);
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+/*
+ * Enable or disable the video buffers queue.
+ *
+ * The queue must be enabled before starting video acquisition and must be
+ * disabled after stopping it. This ensures that the video buffers queue
+ * state can be properly initialized before buffers are accessed from the
+ * interrupt handler.
+ *
+ * Enabling the video queue initializes parameters (such as sequence number,
+ * sync pattern, ...). If the queue is already enabled, return -EBUSY.
+ *
+ * Disabling the video queue cancels the queue and removes all buffers from
+ * the main queue.
+ *
+ * This function can't be called from interrupt context. Use
+ * uvc_queue_cancel() instead.
+ */
+int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
+{
+	unsigned int i;
+	int ret = 0;
+
+	mutex_lock(&queue->mutex);
+	if (enable) {
+		if (uvc_queue_streaming(queue)) {
+			ret = -EBUSY;
+			goto done;
+		}
+		queue->sequence = 0;
+		queue->flags |= UVC_QUEUE_STREAMING;
+		queue->buf_used = 0;
+	} else {
+		uvc_queue_cancel(queue, 0);
+		INIT_LIST_HEAD(&queue->mainqueue);
+
+		for (i = 0; i < queue->count; ++i)
+			queue->buffer[i].state = UVC_BUF_STATE_IDLE;
+
+		queue->flags &= ~UVC_QUEUE_STREAMING;
+	}
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+/*
+ * Cancel the video buffers queue.
+ *
+ * Cancelling the queue marks all buffers on the irq queue as erroneous,
+ * wakes them up and removes them from the queue.
+ *
+ * If the disconnect parameter is set, further calls to uvc_queue_buffer will
+ * fail with -ENODEV.
+ *
+ * This function acquires the irq spinlock and can be called from interrupt
+ * context.
+ */
+void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
+{
+	struct uvc_buffer *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	while (!list_empty(&queue->irqqueue)) {
+		buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+				       queue);
+		list_del(&buf->queue);
+		buf->state = UVC_BUF_STATE_ERROR;
+		wake_up(&buf->wait);
+	}
+	/* This must be protected by the irqlock spinlock to avoid race
+	 * conditions between uvc_queue_buffer and the disconnection event that
+	 * could result in an interruptible wait in uvc_dequeue_buffer. Do not
+	 * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED
+	 * state outside the queue code.
+	 */
+	if (disconnect)
+		queue->flags |= UVC_QUEUE_DISCONNECTED;
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+}
+
+struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+		struct uvc_buffer *buf)
+{
+	struct uvc_buffer *nextbuf;
+	unsigned long flags;
+
+	if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
+	    buf->buf.length != buf->buf.bytesused) {
+		buf->state = UVC_BUF_STATE_QUEUED;
+		buf->buf.bytesused = 0;
+		return buf;
+	}
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	list_del(&buf->queue);
+	if (!list_empty(&queue->irqqueue))
+		nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+					   queue);
+	else
+		nextbuf = NULL;
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+
+	buf->buf.sequence = queue->sequence++;
+	do_gettimeofday(&buf->buf.timestamp);
+
+	wake_up(&buf->wait);
+	return nextbuf;
+}
+
+struct uvc_buffer *uvc_queue_head(struct uvc_video_queue *queue)
+{
+	struct uvc_buffer *buf = NULL;
+
+	if (!list_empty(&queue->irqqueue))
+		buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+				       queue);
+	else
+		queue->flags |= UVC_QUEUE_PAUSED;
+
+	return buf;
+}
+
diff --git a/drivers/usb/gadget/uvc_queue.h b/drivers/usb/gadget/uvc_queue.h
new file mode 100644
index 0000000..7f5a33f
--- /dev/null
+++ b/drivers/usb/gadget/uvc_queue.h
@@ -0,0 +1,89 @@
+#ifndef _UVC_QUEUE_H_
+#define _UVC_QUEUE_H_
+
+#ifdef __KERNEL__
+
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/videodev2.h>
+
+/* Maximum frame size in bytes, for sanity checking. */
+#define UVC_MAX_FRAME_SIZE	(16*1024*1024)
+/* Maximum number of video buffers. */
+#define UVC_MAX_VIDEO_BUFFERS	32
+
+/* ------------------------------------------------------------------------
+ * Structures.
+ */
+
+enum uvc_buffer_state {
+	UVC_BUF_STATE_IDLE	= 0,
+	UVC_BUF_STATE_QUEUED	= 1,
+	UVC_BUF_STATE_ACTIVE	= 2,
+	UVC_BUF_STATE_DONE	= 3,
+	UVC_BUF_STATE_ERROR	= 4,
+};
+
+struct uvc_buffer {
+	unsigned long vma_use_count;
+	struct list_head stream;
+
+	/* Touched by interrupt handler. */
+	struct v4l2_buffer buf;
+	struct list_head queue;
+	wait_queue_head_t wait;
+	enum uvc_buffer_state state;
+};
+
+#define UVC_QUEUE_STREAMING		(1 << 0)
+#define UVC_QUEUE_DISCONNECTED		(1 << 1)
+#define UVC_QUEUE_DROP_INCOMPLETE	(1 << 2)
+#define UVC_QUEUE_PAUSED		(1 << 3)
+
+struct uvc_video_queue {
+	enum v4l2_buf_type type;
+
+	void *mem;
+	unsigned int flags;
+	__u32 sequence;
+
+	unsigned int count;
+	unsigned int buf_size;
+	unsigned int buf_used;
+	struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
+	struct mutex mutex;	/* protects buffers and mainqueue */
+	spinlock_t irqlock;	/* protects irqqueue */
+
+	struct list_head mainqueue;
+	struct list_head irqqueue;
+};
+
+extern void uvc_queue_init(struct uvc_video_queue *queue,
+		enum v4l2_buf_type type);
+extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
+		unsigned int nbuffers, unsigned int buflength);
+extern int uvc_free_buffers(struct uvc_video_queue *queue);
+extern int uvc_query_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf);
+extern int uvc_queue_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf);
+extern int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf, int nonblocking);
+extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable);
+extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
+extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+		struct uvc_buffer *buf);
+extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
+		struct file *file, poll_table *wait);
+extern int uvc_queue_mmap(struct uvc_video_queue *queue,
+		struct vm_area_struct *vma);
+static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
+{
+	return queue->flags & UVC_QUEUE_STREAMING;
+}
+extern struct uvc_buffer *uvc_queue_head(struct uvc_video_queue *queue);
+
+#endif /* __KERNEL__ */
+
+#endif /* _UVC_QUEUE_H_ */
+
diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c
new file mode 100644
index 0000000..a7989f2
--- /dev/null
+++ b/drivers/usb/gadget/uvc_v4l2.c
@@ -0,0 +1,374 @@
+/*
+ *	uvc_v4l2.c  --  USB Video Class Gadget driver
+ *
+ *	Copyright (C) 2009-2010
+ *	    Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ *	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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+
+#include "uvc.h"
+#include "uvc_queue.h"
+
+/* --------------------------------------------------------------------------
+ * Requests handling
+ */
+
+static int
+uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
+{
+	struct usb_composite_dev *cdev = uvc->func.config->cdev;
+	struct usb_request *req = uvc->control_req;
+
+	if (data->length < 0)
+		return usb_ep_set_halt(cdev->gadget->ep0);
+
+	req->length = min(uvc->event_length, data->length);
+	req->zero = data->length < uvc->event_length;
+	req->dma = DMA_ADDR_INVALID;
+
+	memcpy(req->buf, data->data, data->length);
+
+	return usb_ep_queue(cdev->gadget->ep0, req, GFP_KERNEL);
+}
+
+/* --------------------------------------------------------------------------
+ * V4L2
+ */
+
+struct uvc_format
+{
+	u8 bpp;
+	u32 fcc;
+};
+
+static struct uvc_format uvc_formats[] = {
+	{ 16, V4L2_PIX_FMT_YUYV  },
+	{ 0,  V4L2_PIX_FMT_MJPEG },
+};
+
+static int
+uvc_v4l2_get_format(struct uvc_video *video, struct v4l2_format *fmt)
+{
+	fmt->fmt.pix.pixelformat = video->fcc;
+	fmt->fmt.pix.width = video->width;
+	fmt->fmt.pix.height = video->height;
+	fmt->fmt.pix.field = V4L2_FIELD_NONE;
+	fmt->fmt.pix.bytesperline = video->bpp * video->width / 8;
+	fmt->fmt.pix.sizeimage = video->imagesize;
+	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+	fmt->fmt.pix.priv = 0;
+
+	return 0;
+}
+
+static int
+uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt)
+{
+	struct uvc_format *format;
+	unsigned int imagesize;
+	unsigned int bpl;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(uvc_formats); ++i) {
+		format = &uvc_formats[i];
+		if (format->fcc == fmt->fmt.pix.pixelformat)
+			break;
+	}
+
+	if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) {
+		printk(KERN_INFO "Unsupported format 0x%08x.\n",
+			fmt->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	bpl = format->bpp * fmt->fmt.pix.width / 8;
+	imagesize = bpl ? bpl * fmt->fmt.pix.height : fmt->fmt.pix.sizeimage;
+
+	video->fcc = format->fcc;
+	video->bpp = format->bpp;
+	video->width = fmt->fmt.pix.width;
+	video->height = fmt->fmt.pix.height;
+	video->imagesize = imagesize;
+
+	fmt->fmt.pix.field = V4L2_FIELD_NONE;
+	fmt->fmt.pix.bytesperline = bpl;
+	fmt->fmt.pix.sizeimage = imagesize;
+	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+	fmt->fmt.pix.priv = 0;
+
+	return 0;
+}
+
+static int
+uvc_v4l2_open(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_device *uvc = video_get_drvdata(vdev);
+	struct uvc_file_handle *handle;
+	int ret;
+
+	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+	if (handle == NULL)
+		return -ENOMEM;
+
+	ret = v4l2_fh_init(&handle->vfh, vdev);
+	if (ret < 0)
+		goto error;
+
+	ret = v4l2_event_init(&handle->vfh);
+	if (ret < 0)
+		goto error;
+
+	ret = v4l2_event_alloc(&handle->vfh, 8);
+	if (ret < 0)
+		goto error;
+
+	v4l2_fh_add(&handle->vfh);
+
+	handle->device = &uvc->video;
+	file->private_data = &handle->vfh;
+
+	uvc_function_connect(uvc);
+	return 0;
+
+error:
+	v4l2_fh_exit(&handle->vfh);
+	return ret;
+}
+
+static int
+uvc_v4l2_release(struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_device *uvc = video_get_drvdata(vdev);
+	struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
+	struct uvc_video *video = handle->device;
+
+	uvc_function_disconnect(uvc);
+
+	uvc_video_enable(video, 0);
+	mutex_lock(&video->queue.mutex);
+	if (uvc_free_buffers(&video->queue) < 0)
+		printk(KERN_ERR "uvc_v4l2_release: Unable to free "
+				"buffers.\n");
+	mutex_unlock(&video->queue.mutex);
+
+	file->private_data = NULL;
+	v4l2_fh_del(&handle->vfh);
+	v4l2_fh_exit(&handle->vfh);
+	kfree(handle);
+	return 0;
+}
+
+static long
+uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_device *uvc = video_get_drvdata(vdev);
+	struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
+	struct usb_composite_dev *cdev = uvc->func.config->cdev;
+	struct uvc_video *video = &uvc->video;
+	int ret = 0;
+
+	switch (cmd) {
+	/* Query capabilities */
+	case VIDIOC_QUERYCAP:
+	{
+		struct v4l2_capability *cap = arg;
+
+		memset(cap, 0, sizeof *cap);
+		strncpy(cap->driver, "g_uvc", sizeof(cap->driver));
+		strncpy(cap->card, cdev->gadget->name, sizeof(cap->card));
+		strncpy(cap->bus_info, dev_name(&cdev->gadget->dev),
+			sizeof cap->bus_info);
+		cap->version = DRIVER_VERSION_NUMBER;
+		cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+		break;
+	}
+
+	/* Get & Set format */
+	case VIDIOC_G_FMT:
+	{
+		struct v4l2_format *fmt = arg;
+
+		if (fmt->type != video->queue.type)
+			return -EINVAL;
+
+		return uvc_v4l2_get_format(video, fmt);
+	}
+
+	case VIDIOC_S_FMT:
+	{
+		struct v4l2_format *fmt = arg;
+
+		if (fmt->type != video->queue.type)
+			return -EINVAL;
+
+		return uvc_v4l2_set_format(video, fmt);
+	}
+
+	/* Buffers & streaming */
+	case VIDIOC_REQBUFS:
+	{
+		struct v4l2_requestbuffers *rb = arg;
+
+		if (rb->type != video->queue.type ||
+		    rb->memory != V4L2_MEMORY_MMAP)
+			return -EINVAL;
+
+		ret = uvc_alloc_buffers(&video->queue, rb->count,
+					video->imagesize);
+		if (ret < 0)
+			return ret;
+
+		rb->count = ret;
+		ret = 0;
+		break;
+	}
+
+	case VIDIOC_QUERYBUF:
+	{
+		struct v4l2_buffer *buf = arg;
+
+		if (buf->type != video->queue.type)
+			return -EINVAL;
+
+		return uvc_query_buffer(&video->queue, buf);
+	}
+
+	case VIDIOC_QBUF:
+		if ((ret = uvc_queue_buffer(&video->queue, arg)) < 0)
+			return ret;
+
+		return uvc_video_pump(video);
+
+	case VIDIOC_DQBUF:
+		return uvc_dequeue_buffer(&video->queue, arg,
+			file->f_flags & O_NONBLOCK);
+
+	case VIDIOC_STREAMON:
+	{
+		int *type = arg;
+
+		if (*type != video->queue.type)
+			return -EINVAL;
+
+		return uvc_video_enable(video, 1);
+	}
+
+	case VIDIOC_STREAMOFF:
+	{
+		int *type = arg;
+
+		if (*type != video->queue.type)
+			return -EINVAL;
+
+		return uvc_video_enable(video, 0);
+	}
+
+	/* Events */
+        case VIDIOC_DQEVENT:
+	{
+		struct v4l2_event *event = arg;
+
+		ret = v4l2_event_dequeue(&handle->vfh, event,
+					 file->f_flags & O_NONBLOCK);
+		if (ret == 0 && event->type == UVC_EVENT_SETUP) {
+			struct uvc_event *uvc_event = (void *)&event->u.data;
+
+			/* Tell the complete callback to generate an event for
+			 * the next request that will be enqueued by
+			 * uvc_event_write.
+			 */
+			uvc->event_setup_out =
+				!(uvc_event->req.bRequestType & USB_DIR_IN);
+			uvc->event_length = uvc_event->req.wLength;
+		}
+
+		return ret;
+	}
+
+	case VIDIOC_SUBSCRIBE_EVENT:
+	{
+		struct v4l2_event_subscription *sub = arg;
+
+		if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
+			return -EINVAL;
+
+		return v4l2_event_subscribe(&handle->vfh, arg);
+	}
+
+	case VIDIOC_UNSUBSCRIBE_EVENT:
+		return v4l2_event_unsubscribe(&handle->vfh, arg);
+
+	case UVCIOC_SEND_RESPONSE:
+		ret = uvc_send_response(uvc, arg);
+		break;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	return ret;
+}
+
+static long
+uvc_v4l2_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
+}
+
+static int
+uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_device *uvc = video_get_drvdata(vdev);
+
+	return uvc_queue_mmap(&uvc->video.queue, vma);
+}
+
+static unsigned int
+uvc_v4l2_poll(struct file *file, poll_table *wait)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_device *uvc = video_get_drvdata(vdev);
+	struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
+	unsigned int mask = 0;
+
+	poll_wait(file, &handle->vfh.events->wait, wait);
+	if (v4l2_event_pending(&handle->vfh))
+		mask |= POLLPRI;
+
+	mask |= uvc_queue_poll(&uvc->video.queue, file, wait);
+
+	return mask;
+}
+
+struct v4l2_file_operations uvc_v4l2_fops = {
+	.owner		= THIS_MODULE,
+	.open		= uvc_v4l2_open,
+	.release	= uvc_v4l2_release,
+	.ioctl		= uvc_v4l2_ioctl,
+	.mmap		= uvc_v4l2_mmap,
+	.poll		= uvc_v4l2_poll,
+};
+
diff --git a/drivers/usb/gadget/uvc_video.c b/drivers/usb/gadget/uvc_video.c
new file mode 100644
index 0000000..de8cbc4
--- /dev/null
+++ b/drivers/usb/gadget/uvc_video.c
@@ -0,0 +1,386 @@
+/*
+ *	uvc_video.c  --  USB Video Class Gadget driver
+ *
+ *	Copyright (C) 2009-2010
+ *	    Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ *	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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <media/v4l2-dev.h>
+
+#include "uvc.h"
+#include "uvc_queue.h"
+
+/* --------------------------------------------------------------------------
+ * Video codecs
+ */
+
+static int
+uvc_video_encode_header(struct uvc_video *video, struct uvc_buffer *buf,
+		u8 *data, int len)
+{
+	data[0] = 2;
+	data[1] = UVC_STREAM_EOH | video->fid;
+
+	if (buf->buf.bytesused - video->queue.buf_used <= len - 2)
+		data[1] |= UVC_STREAM_EOF;
+
+	return 2;
+}
+
+static int
+uvc_video_encode_data(struct uvc_video *video, struct uvc_buffer *buf,
+		u8 *data, int len)
+{
+	struct uvc_video_queue *queue = &video->queue;
+	unsigned int nbytes;
+	void *mem;
+
+	/* Copy video data to the USB buffer. */
+	mem = queue->mem + buf->buf.m.offset + queue->buf_used;
+	nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
+
+	memcpy(data, mem, nbytes);
+	queue->buf_used += nbytes;
+
+	return nbytes;
+}
+
+static void
+uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
+		struct uvc_buffer *buf)
+{
+	void *mem = req->buf;
+	int len = video->req_size;
+	int ret;
+
+	/* Add a header at the beginning of the payload. */
+	if (video->payload_size == 0) {
+		ret = uvc_video_encode_header(video, buf, mem, len);
+		video->payload_size += ret;
+		mem += ret;
+		len -= ret;
+	}
+
+	/* Process video data. */
+	len = min((int)(video->max_payload_size - video->payload_size), len);
+	ret = uvc_video_encode_data(video, buf, mem, len);
+
+	video->payload_size += ret;
+	len -= ret;
+
+	req->length = video->req_size - len;
+	req->zero = video->payload_size == video->max_payload_size;
+
+	if (buf->buf.bytesused == video->queue.buf_used) {
+		video->queue.buf_used = 0;
+		buf->state = UVC_BUF_STATE_DONE;
+		uvc_queue_next_buffer(&video->queue, buf);
+		video->fid ^= UVC_STREAM_FID;
+
+		video->payload_size = 0;
+	}
+
+	if (video->payload_size == video->max_payload_size ||
+	    buf->buf.bytesused == video->queue.buf_used)
+		video->payload_size = 0;
+}
+
+static void
+uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
+		struct uvc_buffer *buf)
+{
+	void *mem = req->buf;
+	int len = video->req_size;
+	int ret;
+
+	/* Add the header. */
+	ret = uvc_video_encode_header(video, buf, mem, len);
+	mem += ret;
+	len -= ret;
+
+	/* Process video data. */
+	ret = uvc_video_encode_data(video, buf, mem, len);
+	len -= ret;
+
+	req->length = video->req_size - len;
+
+	if (buf->buf.bytesused == video->queue.buf_used) {
+		video->queue.buf_used = 0;
+		buf->state = UVC_BUF_STATE_DONE;
+		uvc_queue_next_buffer(&video->queue, buf);
+		video->fid ^= UVC_STREAM_FID;
+	}
+}
+
+/* --------------------------------------------------------------------------
+ * Request handling
+ */
+
+/*
+ * I somehow feel that synchronisation won't be easy to achieve here. We have
+ * three events that control USB requests submission:
+ *
+ * - USB request completion: the completion handler will resubmit the request
+ *   if a video buffer is available.
+ *
+ * - USB interface setting selection: in response to a SET_INTERFACE request,
+ *   the handler will start streaming if a video buffer is available and if
+ *   video is not currently streaming.
+ *
+ * - V4L2 buffer queueing: the driver will start streaming if video is not
+ *   currently streaming.
+ *
+ * Race conditions between those 3 events might lead to deadlocks or other
+ * nasty side effects.
+ *
+ * The "video currently streaming" condition can't be detected by the irqqueue
+ * being empty, as a request can still be in flight. A separate "queue paused"
+ * flag is thus needed.
+ *
+ * The paused flag will be set when we try to retrieve the irqqueue head if the
+ * queue is empty, and cleared when we queue a buffer.
+ *
+ * The USB request completion handler will get the buffer at the irqqueue head
+ * under protection of the queue spinlock. If the queue is empty, the streaming
+ * paused flag will be set. Right after releasing the spinlock a userspace
+ * application can queue a buffer. The flag will then cleared, and the ioctl
+ * handler will restart the video stream.
+ */
+static void
+uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct uvc_video *video = req->context;
+	struct uvc_buffer *buf;
+	unsigned long flags;
+	int ret;
+
+	switch (req->status) {
+	case 0:
+		break;
+
+	case -ESHUTDOWN:
+		printk(KERN_INFO "VS request cancelled.\n");
+		goto requeue;
+
+	default:
+		printk(KERN_INFO "VS request completed with status %d.\n",
+			req->status);
+		goto requeue;
+	}
+
+	spin_lock_irqsave(&video->queue.irqlock, flags);
+	buf = uvc_queue_head(&video->queue);
+	if (buf == NULL) {
+		spin_unlock_irqrestore(&video->queue.irqlock, flags);
+		goto requeue;
+	}
+
+	video->encode(req, video, buf);
+
+	if ((ret = usb_ep_queue(ep, req, GFP_ATOMIC)) < 0) {
+		printk(KERN_INFO "Failed to queue request (%d).\n", ret);
+		usb_ep_set_halt(ep);
+		spin_unlock_irqrestore(&video->queue.irqlock, flags);
+		goto requeue;
+	}
+	spin_unlock_irqrestore(&video->queue.irqlock, flags);
+
+	return;
+
+requeue:
+	spin_lock_irqsave(&video->req_lock, flags);
+	list_add_tail(&req->list, &video->req_free);
+	spin_unlock_irqrestore(&video->req_lock, flags);
+}
+
+static int
+uvc_video_free_requests(struct uvc_video *video)
+{
+	unsigned int i;
+
+	for (i = 0; i < UVC_NUM_REQUESTS; ++i) {
+		if (video->req[i]) {
+			usb_ep_free_request(video->ep, video->req[i]);
+			video->req[i] = NULL;
+		}
+
+		if (video->req_buffer[i]) {
+			kfree(video->req_buffer[i]);
+			video->req_buffer[i] = NULL;
+		}
+	}
+
+	INIT_LIST_HEAD(&video->req_free);
+	video->req_size = 0;
+	return 0;
+}
+
+static int
+uvc_video_alloc_requests(struct uvc_video *video)
+{
+	unsigned int i;
+	int ret = -ENOMEM;
+
+	BUG_ON(video->req_size);
+
+	for (i = 0; i < UVC_NUM_REQUESTS; ++i) {
+		video->req_buffer[i] = kmalloc(video->ep->maxpacket, GFP_KERNEL);
+		if (video->req_buffer[i] == NULL)
+			goto error;
+
+		video->req[i] = usb_ep_alloc_request(video->ep, GFP_KERNEL);
+		if (video->req[i] == NULL)
+			goto error;
+
+		video->req[i]->buf = video->req_buffer[i];
+		video->req[i]->length = 0;
+		video->req[i]->dma = DMA_ADDR_INVALID;
+		video->req[i]->complete = uvc_video_complete;
+		video->req[i]->context = video;
+
+		list_add_tail(&video->req[i]->list, &video->req_free);
+	}
+
+	video->req_size = video->ep->maxpacket;
+	return 0;
+
+error:
+	uvc_video_free_requests(video);
+	return ret;
+}
+
+/* --------------------------------------------------------------------------
+ * Video streaming
+ */
+
+/*
+ * uvc_video_pump - Pump video data into the USB requests
+ *
+ * This function fills the available USB requests (listed in req_free) with
+ * video data from the queued buffers.
+ */
+int
+uvc_video_pump(struct uvc_video *video)
+{
+	struct usb_request *req;
+	struct uvc_buffer *buf;
+	unsigned long flags;
+	int ret;
+
+	/* FIXME TODO Race between uvc_video_pump and requests completion
+	 * handler ???
+	 */
+
+	while (1) {
+		/* Retrieve the first available USB request, protected by the
+		 * request lock.
+		 */
+		spin_lock_irqsave(&video->req_lock, flags);
+		if (list_empty(&video->req_free)) {
+			spin_unlock_irqrestore(&video->req_lock, flags);
+			return 0;
+		}
+		req = list_first_entry(&video->req_free, struct usb_request,
+					list);
+		list_del(&req->list);
+		spin_unlock_irqrestore(&video->req_lock, flags);
+
+		/* Retrieve the first available video buffer and fill the
+		 * request, protected by the video queue irqlock.
+		 */
+		spin_lock_irqsave(&video->queue.irqlock, flags);
+		buf = uvc_queue_head(&video->queue);
+		if (buf == NULL) {
+			spin_unlock_irqrestore(&video->queue.irqlock, flags);
+			break;
+		}
+
+		video->encode(req, video, buf);
+
+		/* Queue the USB request */
+		if ((ret = usb_ep_queue(video->ep, req, GFP_KERNEL)) < 0) {
+			printk(KERN_INFO "Failed to queue request (%d)\n", ret);
+			usb_ep_set_halt(video->ep);
+			spin_unlock_irqrestore(&video->queue.irqlock, flags);
+			break;
+		}
+		spin_unlock_irqrestore(&video->queue.irqlock, flags);
+	}
+
+	spin_lock_irqsave(&video->req_lock, flags);
+	list_add_tail(&req->list, &video->req_free);
+	spin_unlock_irqrestore(&video->req_lock, flags);
+	return 0;
+}
+
+/*
+ * Enable or disable the video stream.
+ */
+int
+uvc_video_enable(struct uvc_video *video, int enable)
+{
+	unsigned int i;
+	int ret;
+
+	if (video->ep == NULL) {
+		printk(KERN_INFO "Video enable failed, device is "
+			"uninitialized.\n");
+		return -ENODEV;
+	}
+
+	if (!enable) {
+		for (i = 0; i < UVC_NUM_REQUESTS; ++i)
+			usb_ep_dequeue(video->ep, video->req[i]);
+
+		uvc_video_free_requests(video);
+		uvc_queue_enable(&video->queue, 0);
+		return 0;
+	}
+
+	if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
+		return ret;
+
+	if ((ret = uvc_video_alloc_requests(video)) < 0)
+		return ret;
+
+	if (video->max_payload_size) {
+		video->encode = uvc_video_encode_bulk;
+		video->payload_size = 0;
+	} else
+		video->encode = uvc_video_encode_isoc;
+
+	return uvc_video_pump(video);
+}
+
+/*
+ * Initialize the UVC video stream.
+ */
+int
+uvc_video_init(struct uvc_video *video)
+{
+	INIT_LIST_HEAD(&video->req_free);
+	spin_lock_init(&video->req_lock);
+
+	video->fcc = V4L2_PIX_FMT_YUYV;
+	video->bpp = 16;
+	video->width = 320;
+	video->height = 240;
+	video->imagesize = 320 * 240 * 2;
+
+	/* Initialize the video buffers queue. */
+	uvc_queue_init(&video->queue, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	return 0;
+}
+
diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c
new file mode 100644
index 0000000..417fd68
--- /dev/null
+++ b/drivers/usb/gadget/webcam.c
@@ -0,0 +1,399 @@
+/*
+ *	webcam.c -- USB webcam gadget driver
+ *
+ *	Copyright (C) 2009-2010
+ *	    Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ *	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.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/usb/video.h>
+
+#include "f_uvc.h"
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module.  So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+#include "composite.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+
+#include "f_uvc.c"
+#include "uvc_queue.c"
+#include "uvc_v4l2.c"
+#include "uvc_video.c"
+
+/* --------------------------------------------------------------------------
+ * Device descriptor
+ */
+
+#define WEBCAM_VENDOR_ID		0x1d6b	/* Linux Foundation */
+#define WEBCAM_PRODUCT_ID		0x0102	/* Webcam A/V gadget */
+#define WEBCAM_DEVICE_BCD		0x0010	/* 0.10 */
+
+static char webcam_vendor_label[] = "Linux Foundation";
+static char webcam_product_label[] = "Webcam gadget";
+static char webcam_config_label[] = "Video";
+
+/* string IDs are assigned dynamically */
+
+#define STRING_MANUFACTURER_IDX		0
+#define STRING_PRODUCT_IDX		1
+#define STRING_DESCRIPTION_IDX		2
+
+static struct usb_string webcam_strings[] = {
+	[STRING_MANUFACTURER_IDX].s = webcam_vendor_label,
+	[STRING_PRODUCT_IDX].s = webcam_product_label,
+	[STRING_DESCRIPTION_IDX].s = webcam_config_label,
+	{  }
+};
+
+static struct usb_gadget_strings webcam_stringtab = {
+	.language = 0x0409,	/* en-us */
+	.strings = webcam_strings,
+};
+
+static struct usb_gadget_strings *webcam_device_strings[] = {
+	&webcam_stringtab,
+	NULL,
+};
+
+static struct usb_device_descriptor webcam_device_descriptor = {
+	.bLength		= USB_DT_DEVICE_SIZE,
+	.bDescriptorType	= USB_DT_DEVICE,
+	.bcdUSB			= cpu_to_le16(0x0200),
+	.bDeviceClass		= USB_CLASS_MISC,
+	.bDeviceSubClass	= 0x02,
+	.bDeviceProtocol	= 0x01,
+	.bMaxPacketSize0	= 0, /* dynamic */
+	.idVendor		= cpu_to_le16(WEBCAM_VENDOR_ID),
+	.idProduct		= cpu_to_le16(WEBCAM_PRODUCT_ID),
+	.bcdDevice		= cpu_to_le16(WEBCAM_DEVICE_BCD),
+	.iManufacturer		= 0, /* dynamic */
+	.iProduct		= 0, /* dynamic */
+	.iSerialNumber		= 0, /* dynamic */
+	.bNumConfigurations	= 0, /* dynamic */
+};
+
+DECLARE_UVC_HEADER_DESCRIPTOR(1);
+
+static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
+	.bLength		= UVC_DT_HEADER_SIZE(1),
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubType	= UVC_DT_HEADER,
+	.bcdUVC			= cpu_to_le16(0x0100),
+	.wTotalLength		= 0, /* dynamic */
+	.dwClockFrequency	= cpu_to_le32(48000000),
+	.bInCollection		= 0, /* dynamic */
+	.baInterfaceNr[0]	= 0, /* dynamic */
+};
+
+static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
+	.bLength		= UVC_DT_CAMERA_TERMINAL_SIZE(3),
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubType	= UVC_DT_INPUT_TERMINAL,
+	.bTerminalID		= 1,
+	.wTerminalType		= cpu_to_le16(0x0201),
+	.bAssocTerminal		= 0,
+	.iTerminal		= 0,
+	.wObjectiveFocalLengthMin	= cpu_to_le16(0),
+	.wObjectiveFocalLengthMax	= cpu_to_le16(0),
+	.wOcularFocalLength		= cpu_to_le16(0),
+	.bControlSize		= 3,
+	.bmControls[0]		= 2,
+	.bmControls[1]		= 0,
+	.bmControls[2]		= 0,
+};
+
+static const struct uvc_processing_unit_descriptor uvc_processing = {
+	.bLength		= UVC_DT_PROCESSING_UNIT_SIZE(2),
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubType	= UVC_DT_PROCESSING_UNIT,
+	.bUnitID		= 2,
+	.bSourceID		= 1,
+	.wMaxMultiplier		= cpu_to_le16(16*1024),
+	.bControlSize		= 2,
+	.bmControls[0]		= 1,
+	.bmControls[1]		= 0,
+	.iProcessing		= 0,
+};
+
+static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
+	.bLength		= UVC_DT_OUTPUT_TERMINAL_SIZE,
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubType	= UVC_DT_OUTPUT_TERMINAL,
+	.bTerminalID		= 3,
+	.wTerminalType		= cpu_to_le16(0x0101),
+	.bAssocTerminal		= 0,
+	.bSourceID		= 2,
+	.iTerminal		= 0,
+};
+
+DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2);
+
+static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
+	.bLength		= UVC_DT_INPUT_HEADER_SIZE(1, 2),
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubType	= UVC_DT_INPUT_HEADER,
+	.bNumFormats		= 2,
+	.wTotalLength		= 0, /* dynamic */
+	.bEndpointAddress	= 0, /* dynamic */
+	.bmInfo			= 0,
+	.bTerminalLink		= 3,
+	.bStillCaptureMethod	= 0,
+	.bTriggerSupport	= 0,
+	.bTriggerUsage		= 0,
+	.bControlSize		= 1,
+	.bmaControls[0][0]	= 0,
+	.bmaControls[1][0]	= 4,
+};
+
+static const struct uvc_format_uncompressed uvc_format_yuv = {
+	.bLength		= UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubType	= UVC_DT_FORMAT_UNCOMPRESSED,
+	.bFormatIndex		= 1,
+	.bNumFrameDescriptors	= 2,
+	.guidFormat		=
+		{ 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00,
+		 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71},
+	.bBitsPerPixel		= 16,
+	.bDefaultFrameIndex	= 1,
+	.bAspectRatioX		= 0,
+	.bAspectRatioY		= 0,
+	.bmInterfaceFlags	= 0,
+	.bCopyProtect		= 0,
+};
+
+DECLARE_UVC_FRAME_UNCOMPRESSED(1);
+DECLARE_UVC_FRAME_UNCOMPRESSED(3);
+
+static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
+	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubType	= UVC_DT_FRAME_UNCOMPRESSED,
+	.bFrameIndex		= 1,
+	.bmCapabilities		= 0,
+	.wWidth			= cpu_to_le16(640),
+	.wHeight		= cpu_to_le16(360),
+	.dwMinBitRate		= cpu_to_le32(18432000),
+	.dwMaxBitRate		= cpu_to_le32(55296000),
+	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
+	.dwDefaultFrameInterval	= cpu_to_le32(666666),
+	.bFrameIntervalType	= 3,
+	.dwFrameInterval[0]	= cpu_to_le32(666666),
+	.dwFrameInterval[1]	= cpu_to_le32(1000000),
+	.dwFrameInterval[2]	= cpu_to_le32(5000000),
+};
+
+static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
+	.bLength		= UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubType	= UVC_DT_FRAME_UNCOMPRESSED,
+	.bFrameIndex		= 2,
+	.bmCapabilities		= 0,
+	.wWidth			= cpu_to_le16(1280),
+	.wHeight		= cpu_to_le16(720),
+	.dwMinBitRate		= cpu_to_le32(29491200),
+	.dwMaxBitRate		= cpu_to_le32(29491200),
+	.dwMaxVideoFrameBufferSize	= cpu_to_le32(1843200),
+	.dwDefaultFrameInterval	= cpu_to_le32(5000000),
+	.bFrameIntervalType	= 1,
+	.dwFrameInterval[0]	= cpu_to_le32(5000000),
+};
+
+static const struct uvc_format_mjpeg uvc_format_mjpg = {
+	.bLength		= UVC_DT_FORMAT_MJPEG_SIZE,
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubType	= UVC_DT_FORMAT_MJPEG,
+	.bFormatIndex		= 2,
+	.bNumFrameDescriptors	= 2,
+	.bmFlags		= 0,
+	.bDefaultFrameIndex	= 1,
+	.bAspectRatioX		= 0,
+	.bAspectRatioY		= 0,
+	.bmInterfaceFlags	= 0,
+	.bCopyProtect		= 0,
+};
+
+DECLARE_UVC_FRAME_MJPEG(1);
+DECLARE_UVC_FRAME_MJPEG(3);
+
+static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
+	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(3),
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubType	= UVC_DT_FRAME_MJPEG,
+	.bFrameIndex		= 1,
+	.bmCapabilities		= 0,
+	.wWidth			= cpu_to_le16(640),
+	.wHeight		= cpu_to_le16(360),
+	.dwMinBitRate		= cpu_to_le32(18432000),
+	.dwMaxBitRate		= cpu_to_le32(55296000),
+	.dwMaxVideoFrameBufferSize	= cpu_to_le32(460800),
+	.dwDefaultFrameInterval	= cpu_to_le32(666666),
+	.bFrameIntervalType	= 3,
+	.dwFrameInterval[0]	= cpu_to_le32(666666),
+	.dwFrameInterval[1]	= cpu_to_le32(1000000),
+	.dwFrameInterval[2]	= cpu_to_le32(5000000),
+};
+
+static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
+	.bLength		= UVC_DT_FRAME_MJPEG_SIZE(1),
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubType	= UVC_DT_FRAME_MJPEG,
+	.bFrameIndex		= 2,
+	.bmCapabilities		= 0,
+	.wWidth			= cpu_to_le16(1280),
+	.wHeight		= cpu_to_le16(720),
+	.dwMinBitRate		= cpu_to_le32(29491200),
+	.dwMaxBitRate		= cpu_to_le32(29491200),
+	.dwMaxVideoFrameBufferSize	= cpu_to_le32(1843200),
+	.dwDefaultFrameInterval	= cpu_to_le32(5000000),
+	.bFrameIntervalType	= 1,
+	.dwFrameInterval[0]	= cpu_to_le32(5000000),
+};
+
+static const struct uvc_color_matching_descriptor uvc_color_matching = {
+	.bLength		= UVC_DT_COLOR_MATCHING_SIZE,
+	.bDescriptorType	= USB_DT_CS_INTERFACE,
+	.bDescriptorSubType	= UVC_DT_COLOR_MATCHING,
+	.bColorPrimaries	= 1,
+	.bTransferCharacteristics	= 1,
+	.bMatrixCoefficients	= 4,
+};
+
+static const struct uvc_descriptor_header * const uvc_control_cls[] = {
+	(const struct uvc_descriptor_header *) &uvc_control_header,
+	(const struct uvc_descriptor_header *) &uvc_camera_terminal,
+	(const struct uvc_descriptor_header *) &uvc_processing,
+	(const struct uvc_descriptor_header *) &uvc_output_terminal,
+	NULL,
+};
+
+static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
+	(const struct uvc_descriptor_header *) &uvc_input_header,
+	(const struct uvc_descriptor_header *) &uvc_format_yuv,
+	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
+	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
+	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
+	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
+	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
+	(const struct uvc_descriptor_header *) &uvc_color_matching,
+	NULL,
+};
+
+static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
+	(const struct uvc_descriptor_header *) &uvc_input_header,
+	(const struct uvc_descriptor_header *) &uvc_format_yuv,
+	(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
+	(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
+	(const struct uvc_descriptor_header *) &uvc_format_mjpg,
+	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
+	(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
+	(const struct uvc_descriptor_header *) &uvc_color_matching,
+	NULL,
+};
+
+/* --------------------------------------------------------------------------
+ * USB configuration
+ */
+
+static int __init
+webcam_config_bind(struct usb_configuration *c)
+{
+	return uvc_bind_config(c, uvc_control_cls, uvc_fs_streaming_cls,
+			       uvc_hs_streaming_cls);
+}
+
+static struct usb_configuration webcam_config_driver = {
+	.label			= webcam_config_label,
+	.bind			= webcam_config_bind,
+	.bConfigurationValue	= 1,
+	.iConfiguration		= 0, /* dynamic */
+	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
+	.bMaxPower		= CONFIG_USB_GADGET_VBUS_DRAW / 2,
+};
+
+static int /* __init_or_exit */
+webcam_unbind(struct usb_composite_dev *cdev)
+{
+	return 0;
+}
+
+static int __init
+webcam_bind(struct usb_composite_dev *cdev)
+{
+	int ret;
+
+	/* Allocate string descriptor numbers ... note that string contents
+	 * can be overridden by the composite_dev glue.
+	 */
+	if ((ret = usb_string_id(cdev)) < 0)
+		goto error;
+	webcam_strings[STRING_MANUFACTURER_IDX].id = ret;
+	webcam_device_descriptor.iManufacturer = ret;
+
+	if ((ret = usb_string_id(cdev)) < 0)
+		goto error;
+	webcam_strings[STRING_PRODUCT_IDX].id = ret;
+	webcam_device_descriptor.iProduct = ret;
+
+	if ((ret = usb_string_id(cdev)) < 0)
+		goto error;
+	webcam_strings[STRING_DESCRIPTION_IDX].id = ret;
+	webcam_config_driver.iConfiguration = ret;
+
+	/* Register our configuration. */
+	if ((ret = usb_add_config(cdev, &webcam_config_driver)) < 0)
+		goto error;
+
+	INFO(cdev, "Webcam Video Gadget\n");
+	return 0;
+
+error:
+	webcam_unbind(cdev);
+	return ret;
+}
+
+/* --------------------------------------------------------------------------
+ * Driver
+ */
+
+static struct usb_composite_driver webcam_driver = {
+	.name		= "g_webcam",
+	.dev		= &webcam_device_descriptor,
+	.strings	= webcam_device_strings,
+	.bind		= webcam_bind,
+	.unbind		= webcam_unbind,
+};
+
+static int __init
+webcam_init(void)
+{
+	return usb_composite_register(&webcam_driver);
+}
+
+static void __exit
+webcam_cleanup(void)
+{
+	usb_composite_unregister(&webcam_driver);
+}
+
+module_init(webcam_init);
+module_exit(webcam_cleanup);
+
+MODULE_AUTHOR("Laurent Pinchart");
+MODULE_DESCRIPTION("Webcam Video Gadget");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1.0");
+
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 8d3df03..f865be2 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -207,6 +207,21 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ohci-hcd.
 
+config USB_OHCI_HCD_OMAP1
+	bool "OHCI support for OMAP1/2 chips"
+	depends on USB_OHCI_HCD && (ARCH_OMAP1 || ARCH_OMAP2)
+	default y
+	---help---
+	  Enables support for the OHCI controller on OMAP1/2 chips.
+
+config USB_OHCI_HCD_OMAP3
+	bool "OHCI support for OMAP3 and later chips"
+	depends on USB_OHCI_HCD && (ARCH_OMAP3 || ARCH_OMAP4)
+	default y
+	---help---
+	  Enables support for the on-chip OHCI controller on
+	  OMAP3 and later chips.
+
 config USB_OHCI_HCD_PPC_SOC
 	bool "OHCI support for on-chip PPC USB controller"
 	depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index e3a74e7..faa6174 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -69,6 +69,15 @@
 	au_sync();
 }
 
+static int au1xxx_ehci_setup(struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	int ret = ehci_init(hcd);
+
+	ehci->need_io_watchdog = 0;
+	return ret;
+}
+
 static const struct hc_driver ehci_au1xxx_hc_driver = {
 	.description		= hcd_name,
 	.product_desc		= "Au1xxx EHCI",
@@ -86,7 +95,7 @@
 	 * FIXME -- ehci_init() doesn't do enough here.
 	 * See ehci-ppc-soc for a complete implementation.
 	 */
-	.reset			= ehci_init,
+	.reset			= au1xxx_ehci_setup,
 	.start			= ehci_run,
 	.stop			= ehci_stop,
 	.shutdown		= ehci_shutdown,
@@ -215,26 +224,17 @@
 		msleep(10);
 
 	/* Root hub was already suspended. Disable irq emission and
-	 * mark HW unaccessible, bail out if RH has been resumed. Use
-	 * the spinlock to properly synchronize with possible pending
-	 * RH suspend or resume activity.
-	 *
-	 * This is still racy as hcd->state is manipulated outside of
-	 * any locks =P But that will be a different fix.
+	 * mark HW unaccessible.  The PM and USB cores make sure that
+	 * the root hub is either suspended or stopped.
 	 */
 	spin_lock_irqsave(&ehci->lock, flags);
-	if (hcd->state != HC_STATE_SUSPENDED) {
-		rc = -EINVAL;
-		goto bail;
-	}
+	ehci_prepare_ports_for_controller_suspend(ehci);
 	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 	(void)ehci_readl(ehci, &ehci->regs->intr_enable);
 
 	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
 	au1xxx_stop_ehc();
-
-bail:
 	spin_unlock_irqrestore(&ehci->lock, flags);
 
 	// could save FLADJ in case of Vaux power loss
@@ -264,6 +264,7 @@
 	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
 		int	mask = INTR_MASK;
 
+		ehci_prepare_ports_for_controller_resume(ehci);
 		if (!hcd->self.root_hub->do_remote_wakeup)
 			mask &= ~STS_PCD;
 		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 0e26aa1..5cd967d 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -313,6 +313,7 @@
 	struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
 	void __iomem *non_ehci = hcd->regs;
 
+	ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd));
 	if (!fsl_deep_sleep())
 		return 0;
 
@@ -327,6 +328,7 @@
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	void __iomem *non_ehci = hcd->regs;
 
+	ehci_prepare_ports_for_controller_resume(ehci);
 	if (!fsl_deep_sleep())
 		return 0;
 
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 13ead00..ef3e88f 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -31,13 +31,12 @@
 #include <linux/list.h>
 #include <linux/interrupt.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
 
-#include "../core/hcd.h"
-
 #include <asm/byteorder.h>
 #include <asm/io.h>
 #include <asm/irq.h>
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index c7178bc..e7d3d8d 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -106,12 +106,75 @@
 	ehci->owned_ports = 0;
 }
 
+static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
+		bool suspending)
+{
+	int		port;
+	u32		temp;
+
+	/* If remote wakeup is enabled for the root hub but disabled
+	 * for the controller, we must adjust all the port wakeup flags
+	 * when the controller is suspended or resumed.  In all other
+	 * cases they don't need to be changed.
+	 */
+	if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup ||
+			device_may_wakeup(ehci_to_hcd(ehci)->self.controller))
+		return;
+
+	/* clear phy low-power mode before changing wakeup flags */
+	if (ehci->has_hostpc) {
+		port = HCS_N_PORTS(ehci->hcs_params);
+		while (port--) {
+			u32 __iomem	*hostpc_reg;
+
+			hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
+					+ HOSTPC0 + 4 * port);
+			temp = ehci_readl(ehci, hostpc_reg);
+			ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
+		}
+		msleep(5);
+	}
+
+	port = HCS_N_PORTS(ehci->hcs_params);
+	while (port--) {
+		u32 __iomem	*reg = &ehci->regs->port_status[port];
+		u32		t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
+		u32		t2 = t1 & ~PORT_WAKE_BITS;
+
+		/* If we are suspending the controller, clear the flags.
+		 * If we are resuming the controller, set the wakeup flags.
+		 */
+		if (!suspending) {
+			if (t1 & PORT_CONNECT)
+				t2 |= PORT_WKOC_E | PORT_WKDISC_E;
+			else
+				t2 |= PORT_WKOC_E | PORT_WKCONN_E;
+		}
+		ehci_vdbg(ehci, "port %d, %08x -> %08x\n",
+				port + 1, t1, t2);
+		ehci_writel(ehci, t2, reg);
+	}
+
+	/* enter phy low-power mode again */
+	if (ehci->has_hostpc) {
+		port = HCS_N_PORTS(ehci->hcs_params);
+		while (port--) {
+			u32 __iomem	*hostpc_reg;
+
+			hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
+					+ HOSTPC0 + 4 * port);
+			temp = ehci_readl(ehci, hostpc_reg);
+			ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg);
+		}
+	}
+}
+
 static int ehci_bus_suspend (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	int			port;
 	int			mask;
-	u32 __iomem		*hostpc_reg = NULL;
+	int			changed;
 
 	ehci_dbg(ehci, "suspend root hub\n");
 
@@ -155,15 +218,13 @@
 	 */
 	ehci->bus_suspended = 0;
 	ehci->owned_ports = 0;
+	changed = 0;
 	port = HCS_N_PORTS(ehci->hcs_params);
 	while (port--) {
 		u32 __iomem	*reg = &ehci->regs->port_status [port];
 		u32		t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
-		u32		t2 = t1;
+		u32		t2 = t1 & ~PORT_WAKE_BITS;
 
-		if (ehci->has_hostpc)
-			hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
-				+ HOSTPC0 + 4 * (port & 0xff));
 		/* keep track of which ports we suspend */
 		if (t1 & PORT_OWNER)
 			set_bit(port, &ehci->owned_ports);
@@ -172,40 +233,45 @@
 			set_bit(port, &ehci->bus_suspended);
 		}
 
-		/* enable remote wakeup on all ports */
+		/* enable remote wakeup on all ports, if told to do so */
 		if (hcd->self.root_hub->do_remote_wakeup) {
 			/* only enable appropriate wake bits, otherwise the
 			 * hardware can not go phy low power mode. If a race
 			 * condition happens here(connection change during bits
 			 * set), the port change detection will finally fix it.
 			 */
-			if (t1 & PORT_CONNECT) {
+			if (t1 & PORT_CONNECT)
 				t2 |= PORT_WKOC_E | PORT_WKDISC_E;
-				t2 &= ~PORT_WKCONN_E;
-			} else {
+			else
 				t2 |= PORT_WKOC_E | PORT_WKCONN_E;
-				t2 &= ~PORT_WKDISC_E;
-			}
-		} else
-			t2 &= ~PORT_WAKE_BITS;
+		}
 
 		if (t1 != t2) {
 			ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
 				port + 1, t1, t2);
 			ehci_writel(ehci, t2, reg);
-			if (hostpc_reg) {
-				u32	t3;
+			changed = 1;
+		}
+	}
 
-				spin_unlock_irq(&ehci->lock);
-				msleep(5);/* 5ms for HCD enter low pwr mode */
-				spin_lock_irq(&ehci->lock);
-				t3 = ehci_readl(ehci, hostpc_reg);
-				ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
-				t3 = ehci_readl(ehci, hostpc_reg);
-				ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
+	if (changed && ehci->has_hostpc) {
+		spin_unlock_irq(&ehci->lock);
+		msleep(5);	/* 5 ms for HCD to enter low-power mode */
+		spin_lock_irq(&ehci->lock);
+
+		port = HCS_N_PORTS(ehci->hcs_params);
+		while (port--) {
+			u32 __iomem	*hostpc_reg;
+			u32		t3;
+
+			hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
+					+ HOSTPC0 + 4 * port);
+			t3 = ehci_readl(ehci, hostpc_reg);
+			ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
+			t3 = ehci_readl(ehci, hostpc_reg);
+			ehci_dbg(ehci, "Port %d phy low-power mode %s\n",
 					port, (t3 & HOSTPC_PHCD) ?
 					"succeeded" : "failed");
-			}
 		}
 	}
 
@@ -291,6 +357,25 @@
 	msleep(8);
 	spin_lock_irq(&ehci->lock);
 
+	/* clear phy low-power mode before resume */
+	if (ehci->bus_suspended && ehci->has_hostpc) {
+		i = HCS_N_PORTS(ehci->hcs_params);
+		while (i--) {
+			if (test_bit(i, &ehci->bus_suspended)) {
+				u32 __iomem	*hostpc_reg;
+
+				hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
+						+ HOSTPC0 + 4 * i);
+				temp = ehci_readl(ehci, hostpc_reg);
+				ehci_writel(ehci, temp & ~HOSTPC_PHCD,
+						hostpc_reg);
+			}
+		}
+		spin_unlock_irq(&ehci->lock);
+		msleep(5);
+		spin_lock_irq(&ehci->lock);
+	}
+
 	/* manually resume the ports we suspended during bus_suspend() */
 	i = HCS_N_PORTS (ehci->hcs_params);
 	while (i--) {
@@ -659,7 +744,7 @@
 		 * Even if OWNER is set, so the port is owned by the
 		 * companion controller, khubd needs to be able to clear
 		 * the port-change status bits (especially
-		 * USB_PORT_FEAT_C_CONNECTION).
+		 * USB_PORT_STAT_C_CONNECTION).
 		 */
 
 		switch (wValue) {
@@ -675,16 +760,25 @@
 				goto error;
 			if (ehci->no_selective_suspend)
 				break;
-			if (temp & PORT_SUSPEND) {
-				if ((temp & PORT_PE) == 0)
-					goto error;
-				/* resume signaling for 20 msec */
-				temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
-				ehci_writel(ehci, temp | PORT_RESUME,
-						status_reg);
-				ehci->reset_done [wIndex] = jiffies
-						+ msecs_to_jiffies (20);
+			if (!(temp & PORT_SUSPEND))
+				break;
+			if ((temp & PORT_PE) == 0)
+				goto error;
+
+			/* clear phy low-power mode before resume */
+			if (hostpc_reg) {
+				temp1 = ehci_readl(ehci, hostpc_reg);
+				ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
+						hostpc_reg);
+				spin_unlock_irqrestore(&ehci->lock, flags);
+				msleep(5);/* wait to leave low-power mode */
+				spin_lock_irqsave(&ehci->lock, flags);
 			}
+			/* resume signaling for 20 msec */
+			temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
+			ehci_writel(ehci, temp | PORT_RESUME, status_reg);
+			ehci->reset_done[wIndex] = jiffies
+					+ msecs_to_jiffies(20);
 			break;
 		case USB_PORT_FEAT_C_SUSPEND:
 			clear_bit(wIndex, &ehci->port_c_suspend);
@@ -729,12 +823,12 @@
 
 		// wPortChange bits
 		if (temp & PORT_CSC)
-			status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+			status |= USB_PORT_STAT_C_CONNECTION << 16;
 		if (temp & PORT_PEC)
-			status |= 1 << USB_PORT_FEAT_C_ENABLE;
+			status |= USB_PORT_STAT_C_ENABLE << 16;
 
 		if ((temp & PORT_OCC) && !ignore_oc){
-			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
+			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
 
 			/*
 			 * Hubs should disable port power on over-current.
@@ -791,7 +885,7 @@
 		if ((temp & PORT_RESET)
 				&& time_after_eq(jiffies,
 					ehci->reset_done[wIndex])) {
-			status |= 1 << USB_PORT_FEAT_C_RESET;
+			status |= USB_PORT_STAT_C_RESET << 16;
 			ehci->reset_done [wIndex] = 0;
 
 			/* force reset to complete */
@@ -833,7 +927,7 @@
 		 */
 
 		if (temp & PORT_CONNECT) {
-			status |= 1 << USB_PORT_FEAT_CONNECTION;
+			status |= USB_PORT_STAT_CONNECTION;
 			// status may be from integrated TT
 			if (ehci->has_hostpc) {
 				temp1 = ehci_readl(ehci, hostpc_reg);
@@ -842,11 +936,11 @@
 				status |= ehci_port_speed(ehci, temp);
 		}
 		if (temp & PORT_PE)
-			status |= 1 << USB_PORT_FEAT_ENABLE;
+			status |= USB_PORT_STAT_ENABLE;
 
 		/* maybe the port was unsuspended without our knowledge */
 		if (temp & (PORT_SUSPEND|PORT_RESUME)) {
-			status |= 1 << USB_PORT_FEAT_SUSPEND;
+			status |= USB_PORT_STAT_SUSPEND;
 		} else if (test_bit(wIndex, &ehci->suspended_ports)) {
 			clear_bit(wIndex, &ehci->suspended_ports);
 			ehci->reset_done[wIndex] = 0;
@@ -855,13 +949,13 @@
 		}
 
 		if (temp & PORT_OC)
-			status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+			status |= USB_PORT_STAT_OVERCURRENT;
 		if (temp & PORT_RESET)
-			status |= 1 << USB_PORT_FEAT_RESET;
+			status |= USB_PORT_STAT_RESET;
 		if (temp & PORT_POWER)
-			status |= 1 << USB_PORT_FEAT_POWER;
+			status |= USB_PORT_STAT_POWER;
 		if (test_bit(wIndex, &ehci->port_c_suspend))
-			status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+			status |= USB_PORT_STAT_C_SUSPEND << 16;
 
 #ifndef	VERBOSE_DEBUG
 	if (status & ~0xffff)	/* only if wPortChange is interesting */
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 0cd6c77..5450e62 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -116,6 +116,8 @@
 #define	OMAP_UHH_DEBUG_CSR				(0x44)
 
 /* EHCI Register Set */
+#define EHCI_INSNREG04					(0xA0)
+#define EHCI_INSNREG04_DISABLE_UNSUSPEND		(1 << 5)
 #define	EHCI_INSNREG05_ULPI				(0xA4)
 #define	EHCI_INSNREG05_ULPI_CONTROL_SHIFT		31
 #define	EHCI_INSNREG05_ULPI_PORTSEL_SHIFT		24
@@ -352,8 +354,8 @@
 		reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
 
 	/* Bypass the TLL module for PHY mode operation */
-	 if (omap_rev() <= OMAP3430_REV_ES2_1) {
-		dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1 \n");
+	if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) {
+		dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n");
 		if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
 			(omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
 				(omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
@@ -382,6 +384,18 @@
 	dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
 
 
+	/*
+	 * An undocumented "feature" in the OMAP3 EHCI controller,
+	 * causes suspended ports to be taken out of suspend when
+	 * the USBCMD.Run/Stop bit is cleared (for example when
+	 * we do ehci_bus_suspend).
+	 * This breaks suspend-resume if the root-hub is allowed
+	 * to suspend. Writing 1 to this undocumented register bit
+	 * disables this feature and restores normal behavior.
+	 */
+	ehci_omap_writel(omap->ehci_base, EHCI_INSNREG04,
+				EHCI_INSNREG04_DISABLE_UNSUSPEND);
+
 	if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) ||
 		(omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) ||
 			(omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) {
@@ -659,6 +673,9 @@
 		goto err_add_hcd;
 	}
 
+	/* root ports should always stay powered */
+	ehci_port_power(omap->ehci, 1);
+
 	return 0;
 
 err_add_hcd:
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index ead5f4f..d43d176 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -109,6 +109,9 @@
 		return retval;
 
 	switch (pdev->vendor) {
+	case PCI_VENDOR_ID_NEC:
+		ehci->need_io_watchdog = 0;
+		break;
 	case PCI_VENDOR_ID_INTEL:
 		ehci->need_io_watchdog = 0;
 		if (pdev->device == 0x27cc) {
@@ -284,23 +287,15 @@
 		msleep(10);
 
 	/* Root hub was already suspended. Disable irq emission and
-	 * mark HW unaccessible, bail out if RH has been resumed. Use
-	 * the spinlock to properly synchronize with possible pending
-	 * RH suspend or resume activity.
-	 *
-	 * This is still racy as hcd->state is manipulated outside of
-	 * any locks =P But that will be a different fix.
+	 * mark HW unaccessible.  The PM and USB cores make sure that
+	 * the root hub is either suspended or stopped.
 	 */
 	spin_lock_irqsave (&ehci->lock, flags);
-	if (hcd->state != HC_STATE_SUSPENDED) {
-		rc = -EINVAL;
-		goto bail;
-	}
+	ehci_prepare_ports_for_controller_suspend(ehci);
 	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 	(void)ehci_readl(ehci, &ehci->regs->intr_enable);
 
 	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- bail:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 
 	// could save FLADJ in case of Vaux power loss
@@ -330,6 +325,7 @@
 				!hibernated) {
 		int	mask = INTR_MASK;
 
+		ehci_prepare_ports_for_controller_resume(ehci);
 		if (!hcd->self.root_hub->do_remote_wakeup)
 			mask &= ~STS_PCD;
 		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 8952177..11a79c4 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -663,7 +663,7 @@
 	 */
 	i = urb->num_sgs;
 	if (len > 0 && i > 0) {
-		sg = urb->sg->sg;
+		sg = urb->sg;
 		buf = sg_dma_address(sg);
 
 		/* urb->transfer_buffer_length may be smaller than the
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 556c0b4..650a687 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -536,6 +536,16 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* Prepare the PORTSC wakeup flags during controller suspend/resume */
+
+#define ehci_prepare_ports_for_controller_suspend(ehci)		\
+		ehci_adjust_port_wakeup_flags(ehci, true);
+
+#define ehci_prepare_ports_for_controller_resume(ehci)		\
+		ehci_adjust_port_wakeup_flags(ehci, false);
+
+/*-------------------------------------------------------------------------*/
+
 #ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
 
 /*
@@ -556,20 +566,20 @@
 		case 0:
 			return 0;
 		case 1:
-			return (1<<USB_PORT_FEAT_LOWSPEED);
+			return USB_PORT_STAT_LOW_SPEED;
 		case 2:
 		default:
-			return (1<<USB_PORT_FEAT_HIGHSPEED);
+			return USB_PORT_STAT_HIGH_SPEED;
 		}
 	}
-	return (1<<USB_PORT_FEAT_HIGHSPEED);
+	return USB_PORT_STAT_HIGH_SPEED;
 }
 
 #else
 
 #define	ehci_is_TDI(e)			(0)
 
-#define	ehci_port_speed(ehci, portsc)	(1<<USB_PORT_FEAT_HIGHSPEED)
+#define	ehci_port_speed(ehci, portsc)	USB_PORT_STAT_HIGH_SPEED
 #endif
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/fhci-dbg.c b/drivers/usb/host/fhci-dbg.c
index e799f86..6fe5500 100644
--- a/drivers/usb/host/fhci-dbg.c
+++ b/drivers/usb/host/fhci-dbg.c
@@ -20,7 +20,7 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/usb.h>
-#include "../core/hcd.h"
+#include <linux/usb/hcd.h>
 #include "fhci.h"
 
 void fhci_dbg_isr(struct fhci_hcd *fhci, int usb_er)
diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c
index 15379c6..9045337 100644
--- a/drivers/usb/host/fhci-hcd.c
+++ b/drivers/usb/host/fhci-hcd.c
@@ -25,12 +25,12 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include <linux/of_platform.h>
 #include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <asm/qe.h>
 #include <asm/fsl_gtm.h>
-#include "../core/hcd.h"
 #include "fhci.h"
 
 void fhci_start_sof_timer(struct fhci_hcd *fhci)
diff --git a/drivers/usb/host/fhci-hub.c b/drivers/usb/host/fhci-hub.c
index 0cfaedc..348fe62 100644
--- a/drivers/usb/host/fhci-hub.c
+++ b/drivers/usb/host/fhci-hub.c
@@ -22,9 +22,9 @@
 #include <linux/errno.h>
 #include <linux/io.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include <linux/gpio.h>
 #include <asm/qe.h>
-#include "../core/hcd.h"
 #include "fhci.h"
 
 /* virtual root hub specific descriptor */
diff --git a/drivers/usb/host/fhci-mem.c b/drivers/usb/host/fhci-mem.c
index 5591bfb..b0b88f5 100644
--- a/drivers/usb/host/fhci-mem.c
+++ b/drivers/usb/host/fhci-mem.c
@@ -21,7 +21,7 @@
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/usb.h>
-#include "../core/hcd.h"
+#include <linux/usb/hcd.h>
 #include "fhci.h"
 
 static void init_td(struct td *td)
diff --git a/drivers/usb/host/fhci-q.c b/drivers/usb/host/fhci-q.c
index f73c923..03be749 100644
--- a/drivers/usb/host/fhci-q.c
+++ b/drivers/usb/host/fhci-q.c
@@ -22,7 +22,7 @@
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/usb.h>
-#include "../core/hcd.h"
+#include <linux/usb/hcd.h>
 #include "fhci.h"
 
 /* maps the hardware error code to the USB error code */
diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c
index ff43747..4f2cbdc 100644
--- a/drivers/usb/host/fhci-sched.c
+++ b/drivers/usb/host/fhci-sched.c
@@ -24,9 +24,9 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include <asm/qe.h>
 #include <asm/fsl_gtm.h>
-#include "../core/hcd.h"
 #include "fhci.h"
 
 static void recycle_frame(struct fhci_usb *usb, struct packet *pkt)
diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c
index 5701347..7be548c 100644
--- a/drivers/usb/host/fhci-tds.c
+++ b/drivers/usb/host/fhci-tds.c
@@ -22,7 +22,7 @@
 #include <linux/list.h>
 #include <linux/io.h>
 #include <linux/usb.h>
-#include "../core/hcd.h"
+#include <linux/usb/hcd.h>
 #include "fhci.h"
 
 #define DUMMY_BD_BUFFER  0xdeadbeef
diff --git a/drivers/usb/host/fhci.h b/drivers/usb/host/fhci.h
index 72dae1c..71c3caa 100644
--- a/drivers/usb/host/fhci.h
+++ b/drivers/usb/host/fhci.h
@@ -20,13 +20,14 @@
 
 #include <linux/kernel.h>
 #include <linux/types.h>
+#include <linux/bug.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/kfifo.h>
 #include <linux/io.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include <asm/qe.h>
-#include "../core/hcd.h"
 
 #define USB_CLOCK	48000000
 
@@ -515,9 +516,13 @@
 
 static inline void *cq_get(struct kfifo *kfifo)
 {
-	void *p = NULL;
+	unsigned int sz;
+	void *p;
 
-	kfifo_out(kfifo, (void *)&p, sizeof(p));
+	sz = kfifo_out(kfifo, (void *)&p, sizeof(p));
+	if (sz != sizeof(p))
+		return NULL;
+
 	return p;
 }
 
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
index 8a12f29..ca0e98d 100644
--- a/drivers/usb/host/imx21-hcd.c
+++ b/drivers/usb/host/imx21-hcd.c
@@ -56,8 +56,8 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 
-#include "../core/hcd.h"
 #include "imx21-hcd.h"
 
 #ifdef DEBUG
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 92de71d..d9e8212 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -65,6 +65,7 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/usb/isp116x.h>
+#include <linux/usb/hcd.h>
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
@@ -72,7 +73,6 @@
 #include <asm/system.h>
 #include <asm/byteorder.h>
 
-#include "../core/hcd.h"
 #include "isp116x.h"
 
 #define DRIVER_VERSION	"03 Nov 2005"
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index 217fb51..20a0dfe0 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -77,6 +77,7 @@
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <linux/usb/isp1362.h>
+#include <linux/usb/hcd.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/io.h>
@@ -95,7 +96,6 @@
 #define	STUB_DEBUG_FILE
 #endif
 
-#include "../core/hcd.h"
 #include "../core/usb.h"
 #include "isp1362.h"
 
@@ -1265,7 +1265,7 @@
 
 	/* don't submit to a dead or disabled port */
 	if (!((isp1362_hcd->rhport[0] | isp1362_hcd->rhport[1]) &
-	      (1 << USB_PORT_FEAT_ENABLE)) ||
+	      USB_PORT_STAT_ENABLE) ||
 	    !HC_IS_RUNNING(hcd->state)) {
 		kfree(ep);
 		retval = -ENODEV;
@@ -2217,7 +2217,7 @@
 static void remove_debug_file(struct isp1362_hcd *isp1362_hcd)
 {
 	if (isp1362_hcd->pde)
-		remove_proc_entry(proc_filename, 0);
+		remove_proc_entry(proc_filename, NULL);
 }
 
 #endif
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index 9f01293..dbcafa2 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
@@ -21,7 +22,6 @@
 #include <asm/unaligned.h>
 #include <asm/cacheflush.h>
 
-#include "../core/hcd.h"
 #include "isp1760-hcd.h"
 
 static struct kmem_cache *qtd_cachep;
@@ -111,7 +111,7 @@
 	u32 ping;
 };
 
-#define ehci_port_speed(priv, portsc) (1 << USB_PORT_FEAT_HIGHSPEED)
+#define ehci_port_speed(priv, portsc) USB_PORT_STAT_HIGH_SPEED
 
 static unsigned int isp1760_readl(__u32 __iomem *regs)
 {
@@ -713,12 +713,11 @@
 	u32 dw3;
 
 	dw3 = le32_to_cpu(ptd->dw3);
-	if (dw3 & DW3_HALT_BIT)
+	if (dw3 & DW3_HALT_BIT) {
 		error = -EPIPE;
 
-	if (dw3 & DW3_ERROR_BIT) {
-		printk(KERN_ERR "error bit is set in DW3\n");
-		error = -EPIPE;
+		if (dw3 & DW3_ERROR_BIT)
+			pr_err("error bit is set in DW3\n");
 	}
 
 	if (dw3 & DW3_QTD_ACTIVE) {
@@ -1923,7 +1922,7 @@
 		 * Even if OWNER is set, so the port is owned by the
 		 * companion controller, khubd needs to be able to clear
 		 * the port-change status bits (especially
-		 * USB_PORT_FEAT_C_CONNECTION).
+		 * USB_PORT_STAT_C_CONNECTION).
 		 */
 
 		switch (wValue) {
@@ -1987,7 +1986,7 @@
 
 		/* wPortChange bits */
 		if (temp & PORT_CSC)
-			status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+			status |= USB_PORT_STAT_C_CONNECTION << 16;
 
 
 		/* whoever resumes must GetPortStatus to complete it!! */
@@ -2007,7 +2006,7 @@
 			/* resume completed? */
 			else if (time_after_eq(jiffies,
 					priv->reset_done)) {
-				status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+				status |= USB_PORT_STAT_C_SUSPEND << 16;
 				priv->reset_done = 0;
 
 				/* stop resume signaling */
@@ -2031,7 +2030,7 @@
 		if ((temp & PORT_RESET)
 				&& time_after_eq(jiffies,
 					priv->reset_done)) {
-			status |= 1 << USB_PORT_FEAT_C_RESET;
+			status |= USB_PORT_STAT_C_RESET << 16;
 			priv->reset_done = 0;
 
 			/* force reset to complete */
@@ -2062,18 +2061,18 @@
 			printk(KERN_ERR "Warning: PORT_OWNER is set\n");
 
 		if (temp & PORT_CONNECT) {
-			status |= 1 << USB_PORT_FEAT_CONNECTION;
+			status |= USB_PORT_STAT_CONNECTION;
 			/* status may be from integrated TT */
 			status |= ehci_port_speed(priv, temp);
 		}
 		if (temp & PORT_PE)
-			status |= 1 << USB_PORT_FEAT_ENABLE;
+			status |= USB_PORT_STAT_ENABLE;
 		if (temp & (PORT_SUSPEND|PORT_RESUME))
-			status |= 1 << USB_PORT_FEAT_SUSPEND;
+			status |= USB_PORT_STAT_SUSPEND;
 		if (temp & PORT_RESET)
-			status |= 1 << USB_PORT_FEAT_RESET;
+			status |= USB_PORT_STAT_RESET;
 		if (temp & PORT_POWER)
-			status |= 1 << USB_PORT_FEAT_POWER;
+			status |= USB_PORT_STAT_POWER;
 
 		put_unaligned(cpu_to_le32(status), (__le32 *) buf);
 		break;
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index 4293cfd..8f0259e 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -13,8 +13,8 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/usb/isp1760.h>
+#include <linux/usb/hcd.h>
 
-#include "../core/hcd.h"
 #include "isp1760-hcd.h"
 
 #ifdef CONFIG_PPC_OF
@@ -36,7 +36,7 @@
 	struct resource memory;
 	struct of_irq oirq;
 	int virq;
-	u64 res_len;
+	resource_size_t res_len;
 	int ret;
 	const unsigned int *prop;
 	unsigned int devflags = 0;
@@ -45,13 +45,12 @@
 	if (ret)
 		return -ENXIO;
 
-	res = request_mem_region(memory.start, memory.end - memory.start + 1,
-			dev_name(&dev->dev));
+	res_len = resource_size(&memory);
+
+	res = request_mem_region(memory.start, res_len, dev_name(&dev->dev));
 	if (!res)
 		return -EBUSY;
 
-	res_len = memory.end - memory.start + 1;
-
 	if (of_irq_map_one(dp, 0, &oirq)) {
 		ret = -ENODEV;
 		goto release_reg;
@@ -92,7 +91,7 @@
 	return ret;
 
 release_reg:
-	release_mem_region(memory.start, memory.end - memory.start + 1);
+	release_mem_region(memory.start, res_len);
 	return ret;
 }
 
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index afe59be..fc57655 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -32,6 +32,7 @@
 #include <linux/list.h>
 #include <linux/usb.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/hcd.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/workqueue.h>
@@ -43,7 +44,6 @@
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
-#include "../core/hcd.h"
 
 #define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
 #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
@@ -1006,9 +1006,14 @@
 #define PLATFORM_DRIVER		ohci_hcd_s3c2410_driver
 #endif
 
-#ifdef CONFIG_ARCH_OMAP
+#ifdef CONFIG_USB_OHCI_HCD_OMAP1
 #include "ohci-omap.c"
-#define PLATFORM_DRIVER		ohci_hcd_omap_driver
+#define OMAP1_PLATFORM_DRIVER	ohci_hcd_omap_driver
+#endif
+
+#ifdef CONFIG_USB_OHCI_HCD_OMAP3
+#include "ohci-omap3.c"
+#define OMAP3_PLATFORM_DRIVER	ohci_hcd_omap3_driver
 #endif
 
 #ifdef CONFIG_ARCH_LH7A404
@@ -1092,6 +1097,8 @@
 
 #if	!defined(PCI_DRIVER) &&		\
 	!defined(PLATFORM_DRIVER) &&	\
+	!defined(OMAP1_PLATFORM_DRIVER) &&	\
+	!defined(OMAP3_PLATFORM_DRIVER) &&	\
 	!defined(OF_PLATFORM_DRIVER) &&	\
 	!defined(SA1111_DRIVER) &&	\
 	!defined(PS3_SYSTEM_BUS_DRIVER) && \
@@ -1133,6 +1140,18 @@
 		goto error_platform;
 #endif
 
+#ifdef OMAP1_PLATFORM_DRIVER
+	retval = platform_driver_register(&OMAP1_PLATFORM_DRIVER);
+	if (retval < 0)
+		goto error_omap1_platform;
+#endif
+
+#ifdef OMAP3_PLATFORM_DRIVER
+	retval = platform_driver_register(&OMAP3_PLATFORM_DRIVER);
+	if (retval < 0)
+		goto error_omap3_platform;
+#endif
+
 #ifdef OF_PLATFORM_DRIVER
 	retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
 	if (retval < 0)
@@ -1200,6 +1219,14 @@
 	platform_driver_unregister(&PLATFORM_DRIVER);
  error_platform:
 #endif
+#ifdef OMAP1_PLATFORM_DRIVER
+	platform_driver_unregister(&OMAP1_PLATFORM_DRIVER);
+ error_omap1_platform:
+#endif
+#ifdef OMAP3_PLATFORM_DRIVER
+	platform_driver_unregister(&OMAP3_PLATFORM_DRIVER);
+ error_omap3_platform:
+#endif
 #ifdef PS3_SYSTEM_BUS_DRIVER
 	ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
  error_ps3:
diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
new file mode 100644
index 0000000..2cc8a50
--- /dev/null
+++ b/drivers/usb/host/ohci-omap3.c
@@ -0,0 +1,735 @@
+/*
+ * ohci-omap3.c - driver for OHCI on OMAP3 and later processors
+ *
+ * Bus Glue for OMAP3 USBHOST 3 port OHCI controller
+ * This controller is also used in later OMAPs and AM35x chips
+ *
+ * Copyright (C) 2007-2010 Texas Instruments, Inc.
+ * Author: Vikram Pandita <vikram.pandita@ti.com>
+ * Author: Anand Gadiyar <gadiyar@ti.com>
+ *
+ * Based on ehci-omap.c and some other ohci glue layers
+ *
+ * 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
+ *
+ * TODO (last updated Mar 10th, 2010):
+ *	- add kernel-doc
+ *	- Factor out code common to EHCI to a separate file
+ *	- Make EHCI and OHCI coexist together
+ *	  - needs newer silicon versions to actually work
+ *	  - the last one to be loaded currently steps on the other's toes
+ *	- Add hooks for configuring transceivers, etc. at init/exit
+ *	- Add aggressive clock-management code
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <plat/usb.h>
+
+/*
+ * OMAP USBHOST Register addresses: VIRTUAL ADDRESSES
+ *	Use ohci_omap_readl()/ohci_omap_writel() functions
+ */
+
+/* TLL Register Set */
+#define	OMAP_USBTLL_REVISION				(0x00)
+#define	OMAP_USBTLL_SYSCONFIG				(0x10)
+#define	OMAP_USBTLL_SYSCONFIG_CACTIVITY			(1 << 8)
+#define	OMAP_USBTLL_SYSCONFIG_SIDLEMODE			(1 << 3)
+#define	OMAP_USBTLL_SYSCONFIG_ENAWAKEUP			(1 << 2)
+#define	OMAP_USBTLL_SYSCONFIG_SOFTRESET			(1 << 1)
+#define	OMAP_USBTLL_SYSCONFIG_AUTOIDLE			(1 << 0)
+
+#define	OMAP_USBTLL_SYSSTATUS				(0x14)
+#define	OMAP_USBTLL_SYSSTATUS_RESETDONE			(1 << 0)
+
+#define	OMAP_USBTLL_IRQSTATUS				(0x18)
+#define	OMAP_USBTLL_IRQENABLE				(0x1C)
+
+#define	OMAP_TLL_SHARED_CONF				(0x30)
+#define	OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN		(1 << 6)
+#define	OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN		(1 << 5)
+#define	OMAP_TLL_SHARED_CONF_USB_DIVRATION		(1 << 2)
+#define	OMAP_TLL_SHARED_CONF_FCLK_REQ			(1 << 1)
+#define	OMAP_TLL_SHARED_CONF_FCLK_IS_ON			(1 << 0)
+
+#define	OMAP_TLL_CHANNEL_CONF(num)			(0x040 + 0x004 * num)
+#define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT		24
+#define	OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF		(1 << 11)
+#define	OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE		(1 << 10)
+#define	OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE		(1 << 9)
+#define	OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE		(1 << 8)
+#define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS		(1 << 1)
+#define	OMAP_TLL_CHANNEL_CONF_CHANEN			(1 << 0)
+
+#define OMAP_TLL_CHANNEL_COUNT				3
+
+/* UHH Register Set */
+#define	OMAP_UHH_REVISION				(0x00)
+#define	OMAP_UHH_SYSCONFIG				(0x10)
+#define	OMAP_UHH_SYSCONFIG_MIDLEMODE			(1 << 12)
+#define	OMAP_UHH_SYSCONFIG_CACTIVITY			(1 << 8)
+#define	OMAP_UHH_SYSCONFIG_SIDLEMODE			(1 << 3)
+#define	OMAP_UHH_SYSCONFIG_ENAWAKEUP			(1 << 2)
+#define	OMAP_UHH_SYSCONFIG_SOFTRESET			(1 << 1)
+#define	OMAP_UHH_SYSCONFIG_AUTOIDLE			(1 << 0)
+
+#define	OMAP_UHH_SYSSTATUS				(0x14)
+#define OMAP_UHH_SYSSTATUS_UHHRESETDONE			(1 << 0)
+#define OMAP_UHH_SYSSTATUS_OHCIRESETDONE		(1 << 1)
+#define OMAP_UHH_SYSSTATUS_EHCIRESETDONE		(1 << 2)
+#define	OMAP_UHH_HOSTCONFIG				(0x40)
+#define	OMAP_UHH_HOSTCONFIG_ULPI_BYPASS			(1 << 0)
+#define	OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS		(1 << 0)
+#define	OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS		(1 << 11)
+#define	OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS		(1 << 12)
+#define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN		(1 << 2)
+#define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN		(1 << 3)
+#define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN		(1 << 4)
+#define OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN		(1 << 5)
+#define OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS		(1 << 8)
+#define OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS		(1 << 9)
+#define OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS		(1 << 10)
+
+#define	OMAP_UHH_DEBUG_CSR				(0x44)
+
+/*-------------------------------------------------------------------------*/
+
+static inline void ohci_omap_writel(void __iomem *base, u32 reg, u32 val)
+{
+	__raw_writel(val, base + reg);
+}
+
+static inline u32 ohci_omap_readl(void __iomem *base, u32 reg)
+{
+	return __raw_readl(base + reg);
+}
+
+static inline void ohci_omap_writeb(void __iomem *base, u8 reg, u8 val)
+{
+	__raw_writeb(val, base + reg);
+}
+
+static inline u8 ohci_omap_readb(void __iomem *base, u8 reg)
+{
+	return __raw_readb(base + reg);
+}
+
+/*-------------------------------------------------------------------------*/
+
+struct ohci_hcd_omap3 {
+	struct ohci_hcd		*ohci;
+	struct device		*dev;
+
+	struct clk		*usbhost_ick;
+	struct clk		*usbhost2_120m_fck;
+	struct clk		*usbhost1_48m_fck;
+	struct clk		*usbtll_fck;
+	struct clk		*usbtll_ick;
+
+	/* port_mode: TLL/PHY, 2/3/4/6-PIN, DP-DM/DAT-SE0 */
+	enum ohci_omap3_port_mode	port_mode[OMAP3_HS_USB_PORTS];
+	void __iomem		*uhh_base;
+	void __iomem		*tll_base;
+	void __iomem		*ohci_base;
+
+	unsigned		es2_compatibility:1;
+};
+
+/*-------------------------------------------------------------------------*/
+
+static void ohci_omap3_clock_power(struct ohci_hcd_omap3 *omap, int on)
+{
+	if (on) {
+		clk_enable(omap->usbtll_ick);
+		clk_enable(omap->usbtll_fck);
+		clk_enable(omap->usbhost_ick);
+		clk_enable(omap->usbhost1_48m_fck);
+		clk_enable(omap->usbhost2_120m_fck);
+	} else {
+		clk_disable(omap->usbhost2_120m_fck);
+		clk_disable(omap->usbhost1_48m_fck);
+		clk_disable(omap->usbhost_ick);
+		clk_disable(omap->usbtll_fck);
+		clk_disable(omap->usbtll_ick);
+	}
+}
+
+static int ohci_omap3_init(struct usb_hcd *hcd)
+{
+	dev_dbg(hcd->self.controller, "starting OHCI controller\n");
+
+	return ohci_init(hcd_to_ohci(hcd));
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_omap3_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+	int ret;
+
+	/*
+	 * RemoteWakeupConnected has to be set explicitly before
+	 * calling ohci_run. The reset value of RWC is 0.
+	 */
+	ohci->hc_control = OHCI_CTRL_RWC;
+	writel(OHCI_CTRL_RWC, &ohci->regs->control);
+
+	ret = ohci_run(ohci);
+
+	if (ret < 0) {
+		dev_err(hcd->self.controller, "can't start\n");
+		ohci_stop(hcd);
+	}
+
+	return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * convert the port-mode enum to a value we can use in the FSLSMODE
+ * field of USBTLL_CHANNEL_CONF
+ */
+static unsigned ohci_omap3_fslsmode(enum ohci_omap3_port_mode mode)
+{
+	switch (mode) {
+	case OMAP_OHCI_PORT_MODE_UNUSED:
+	case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
+		return 0x0;
+
+	case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
+		return 0x1;
+
+	case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
+		return 0x2;
+
+	case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
+		return 0x3;
+
+	case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
+		return 0x4;
+
+	case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
+		return 0x5;
+
+	case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
+		return 0x6;
+
+	case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
+		return 0x7;
+
+	case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
+		return 0xA;
+
+	case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
+		return 0xB;
+	default:
+		pr_warning("Invalid port mode, using default\n");
+		return 0x0;
+	}
+}
+
+static void ohci_omap3_tll_config(struct ohci_hcd_omap3 *omap)
+{
+	u32 reg;
+	int i;
+
+	/* Program TLL SHARED CONF */
+	reg = ohci_omap_readl(omap->tll_base, OMAP_TLL_SHARED_CONF);
+	reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN;
+	reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN;
+	reg |= OMAP_TLL_SHARED_CONF_USB_DIVRATION;
+	reg |= OMAP_TLL_SHARED_CONF_FCLK_IS_ON;
+	ohci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, reg);
+
+	/* Program each TLL channel */
+	/*
+	 * REVISIT: Only the 3-pin and 4-pin PHY modes have
+	 * actually been tested.
+	 */
+	for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
+
+		/* Enable only those channels that are actually used */
+		if (omap->port_mode[i] == OMAP_OHCI_PORT_MODE_UNUSED)
+			continue;
+
+		reg = ohci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i));
+		reg |= ohci_omap3_fslsmode(omap->port_mode[i])
+				<< OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT;
+		reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS;
+		reg |= OMAP_TLL_CHANNEL_CONF_CHANEN;
+		ohci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg);
+	}
+}
+
+/* omap3_start_ohci
+ *	- Start the TI USBHOST controller
+ */
+static int omap3_start_ohci(struct ohci_hcd_omap3 *omap, struct usb_hcd *hcd)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+	u32 reg = 0;
+	int ret = 0;
+
+	dev_dbg(omap->dev, "starting TI OHCI USB Controller\n");
+
+	/* Get all the clock handles we need */
+	omap->usbhost_ick = clk_get(omap->dev, "usbhost_ick");
+	if (IS_ERR(omap->usbhost_ick)) {
+		dev_err(omap->dev, "could not get usbhost_ick\n");
+		ret =  PTR_ERR(omap->usbhost_ick);
+		goto err_host_ick;
+	}
+
+	omap->usbhost2_120m_fck = clk_get(omap->dev, "usbhost_120m_fck");
+	if (IS_ERR(omap->usbhost2_120m_fck)) {
+		dev_err(omap->dev, "could not get usbhost_120m_fck\n");
+		ret = PTR_ERR(omap->usbhost2_120m_fck);
+		goto err_host_120m_fck;
+	}
+
+	omap->usbhost1_48m_fck = clk_get(omap->dev, "usbhost_48m_fck");
+	if (IS_ERR(omap->usbhost1_48m_fck)) {
+		dev_err(omap->dev, "could not get usbhost_48m_fck\n");
+		ret = PTR_ERR(omap->usbhost1_48m_fck);
+		goto err_host_48m_fck;
+	}
+
+	omap->usbtll_fck = clk_get(omap->dev, "usbtll_fck");
+	if (IS_ERR(omap->usbtll_fck)) {
+		dev_err(omap->dev, "could not get usbtll_fck\n");
+		ret = PTR_ERR(omap->usbtll_fck);
+		goto err_tll_fck;
+	}
+
+	omap->usbtll_ick = clk_get(omap->dev, "usbtll_ick");
+	if (IS_ERR(omap->usbtll_ick)) {
+		dev_err(omap->dev, "could not get usbtll_ick\n");
+		ret = PTR_ERR(omap->usbtll_ick);
+		goto err_tll_ick;
+	}
+
+	/* Now enable all the clocks in the correct order */
+	ohci_omap3_clock_power(omap, 1);
+
+	/* perform TLL soft reset, and wait until reset is complete */
+	ohci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
+			OMAP_USBTLL_SYSCONFIG_SOFTRESET);
+
+	/* Wait for TLL reset to complete */
+	while (!(ohci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
+			& OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
+		cpu_relax();
+
+		if (time_after(jiffies, timeout)) {
+			dev_dbg(omap->dev, "operation timed out\n");
+			ret = -EINVAL;
+			goto err_sys_status;
+		}
+	}
+
+	dev_dbg(omap->dev, "TLL reset done\n");
+
+	/* (1<<3) = no idle mode only for initial debugging */
+	ohci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
+			OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
+			OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
+			OMAP_USBTLL_SYSCONFIG_CACTIVITY);
+
+
+	/* Put UHH in NoIdle/NoStandby mode */
+	reg = ohci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG);
+	reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
+			| OMAP_UHH_SYSCONFIG_SIDLEMODE
+			| OMAP_UHH_SYSCONFIG_CACTIVITY
+			| OMAP_UHH_SYSCONFIG_MIDLEMODE);
+	reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
+	reg &= ~OMAP_UHH_SYSCONFIG_SOFTRESET;
+
+	ohci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
+
+	reg = ohci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
+
+	/* setup ULPI bypass and burst configurations */
+	reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
+			| OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
+			| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
+	reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
+
+	/*
+	 * REVISIT: Pi_CONNECT_STATUS controls MStandby
+	 * assertion and Swakeup generation - let us not
+	 * worry about this for now. OMAP HWMOD framework
+	 * might take care of this later. If not, we can
+	 * update these registers when adding aggressive
+	 * clock management code.
+	 *
+	 * For now, turn off all the Pi_CONNECT_STATUS bits
+	 *
+	if (omap->port_mode[0] == OMAP_OHCI_PORT_MODE_UNUSED)
+		reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
+	if (omap->port_mode[1] == OMAP_OHCI_PORT_MODE_UNUSED)
+		reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
+	if (omap->port_mode[2] == OMAP_OHCI_PORT_MODE_UNUSED)
+		reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
+	 */
+	reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS;
+	reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS;
+	reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
+
+	 if (omap->es2_compatibility) {
+		/*
+		 * All OHCI modes need to go through the TLL,
+		 * unlike in the EHCI case. So use UTMI mode
+		 * for all ports for OHCI, on ES2.x silicon
+		 */
+		dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n");
+		reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
+	} else {
+		dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n");
+		if (omap->port_mode[0] == OMAP_OHCI_PORT_MODE_UNUSED)
+			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
+		else
+			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
+
+		if (omap->port_mode[1] == OMAP_OHCI_PORT_MODE_UNUSED)
+			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
+		else
+			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
+
+		if (omap->port_mode[2] == OMAP_OHCI_PORT_MODE_UNUSED)
+			reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
+		else
+			reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS;
+
+	}
+	ohci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
+	dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
+
+	ohci_omap3_tll_config(omap);
+
+	return 0;
+
+err_sys_status:
+	ohci_omap3_clock_power(omap, 0);
+	clk_put(omap->usbtll_ick);
+
+err_tll_ick:
+	clk_put(omap->usbtll_fck);
+
+err_tll_fck:
+	clk_put(omap->usbhost1_48m_fck);
+
+err_host_48m_fck:
+	clk_put(omap->usbhost2_120m_fck);
+
+err_host_120m_fck:
+	clk_put(omap->usbhost_ick);
+
+err_host_ick:
+	return ret;
+}
+
+static void omap3_stop_ohci(struct ohci_hcd_omap3 *omap, struct usb_hcd *hcd)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(100);
+
+	dev_dbg(omap->dev, "stopping TI EHCI USB Controller\n");
+
+	/* Reset USBHOST for insmod/rmmod to work */
+	ohci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG,
+			OMAP_UHH_SYSCONFIG_SOFTRESET);
+	while (!(ohci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
+				& OMAP_UHH_SYSSTATUS_UHHRESETDONE)) {
+		cpu_relax();
+
+		if (time_after(jiffies, timeout))
+			dev_dbg(omap->dev, "operation timed out\n");
+	}
+
+	while (!(ohci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
+				& OMAP_UHH_SYSSTATUS_OHCIRESETDONE)) {
+		cpu_relax();
+
+		if (time_after(jiffies, timeout))
+			dev_dbg(omap->dev, "operation timed out\n");
+	}
+
+	while (!(ohci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS)
+				& OMAP_UHH_SYSSTATUS_EHCIRESETDONE)) {
+		cpu_relax();
+
+		if (time_after(jiffies, timeout))
+			dev_dbg(omap->dev, "operation timed out\n");
+	}
+
+	ohci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1));
+
+	while (!(ohci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
+				& (1 << 0))) {
+		cpu_relax();
+
+		if (time_after(jiffies, timeout))
+			dev_dbg(omap->dev, "operation timed out\n");
+	}
+
+	ohci_omap3_clock_power(omap, 0);
+
+	if (omap->usbtll_fck != NULL) {
+		clk_put(omap->usbtll_fck);
+		omap->usbtll_fck = NULL;
+	}
+
+	if (omap->usbhost_ick != NULL) {
+		clk_put(omap->usbhost_ick);
+		omap->usbhost_ick = NULL;
+	}
+
+	if (omap->usbhost1_48m_fck != NULL) {
+		clk_put(omap->usbhost1_48m_fck);
+		omap->usbhost1_48m_fck = NULL;
+	}
+
+	if (omap->usbhost2_120m_fck != NULL) {
+		clk_put(omap->usbhost2_120m_fck);
+		omap->usbhost2_120m_fck = NULL;
+	}
+
+	if (omap->usbtll_ick != NULL) {
+		clk_put(omap->usbtll_ick);
+		omap->usbtll_ick = NULL;
+	}
+
+	dev_dbg(omap->dev, "Clock to USB host has been disabled\n");
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_omap3_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"OMAP3 OHCI Host Controller",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset =		ohci_omap3_init,
+	.start =		ohci_omap3_start,
+	.stop =			ohci_stop,
+	.shutdown =		ohci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+#ifdef	CONFIG_PM
+	.bus_suspend =		ohci_bus_suspend,
+	.bus_resume =		ohci_bus_resume,
+#endif
+	.start_port_reset =	ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * configure so an HC device and id are always provided
+ * always called with process context; sleeping is OK
+ */
+
+/**
+ * ohci_hcd_omap3_probe - initialize OMAP-based HCDs
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ */
+static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
+{
+	struct ohci_hcd_omap_platform_data *pdata = pdev->dev.platform_data;
+	struct ohci_hcd_omap3 *omap;
+	struct resource *res;
+	struct usb_hcd *hcd;
+	int ret = -ENODEV;
+	int irq;
+
+	if (usb_disabled())
+		goto err_disabled;
+
+	if (!pdata) {
+		dev_dbg(&pdev->dev, "missing platform_data\n");
+		goto err_pdata;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+
+	omap = kzalloc(sizeof(*omap), GFP_KERNEL);
+	if (!omap) {
+		ret = -ENOMEM;
+		goto err_disabled;
+	}
+
+	hcd = usb_create_hcd(&ohci_omap3_hc_driver, &pdev->dev,
+			dev_name(&pdev->dev));
+	if (!hcd) {
+		ret = -ENOMEM;
+		goto err_create_hcd;
+	}
+
+	platform_set_drvdata(pdev, omap);
+	omap->dev		= &pdev->dev;
+	omap->port_mode[0]	= pdata->port_mode[0];
+	omap->port_mode[1]	= pdata->port_mode[1];
+	omap->port_mode[2]	= pdata->port_mode[2];
+	omap->es2_compatibility	= pdata->es2_compatibility;
+	omap->ohci		= hcd_to_ohci(hcd);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		dev_err(&pdev->dev, "OHCI ioremap failed\n");
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	omap->uhh_base = ioremap(res->start, resource_size(res));
+	if (!omap->uhh_base) {
+		dev_err(&pdev->dev, "UHH ioremap failed\n");
+		ret = -ENOMEM;
+		goto err_uhh_ioremap;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	omap->tll_base = ioremap(res->start, resource_size(res));
+	if (!omap->tll_base) {
+		dev_err(&pdev->dev, "TLL ioremap failed\n");
+		ret = -ENOMEM;
+		goto err_tll_ioremap;
+	}
+
+	ret = omap3_start_ohci(omap, hcd);
+	if (ret) {
+		dev_dbg(&pdev->dev, "failed to start ehci\n");
+		goto err_start;
+	}
+
+	ohci_hcd_init(omap->ohci);
+
+	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+	if (ret) {
+		dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
+		goto err_add_hcd;
+	}
+
+	return 0;
+
+err_add_hcd:
+	omap3_stop_ohci(omap, hcd);
+
+err_start:
+	iounmap(omap->tll_base);
+
+err_tll_ioremap:
+	iounmap(omap->uhh_base);
+
+err_uhh_ioremap:
+	iounmap(hcd->regs);
+
+err_ioremap:
+	usb_put_hcd(hcd);
+
+err_create_hcd:
+	kfree(omap);
+err_pdata:
+err_disabled:
+	return ret;
+}
+
+/*
+ * may be called without controller electrically present
+ * may be called with controller, bus, and devices active
+ */
+
+/**
+ * ohci_hcd_omap3_remove - shutdown processing for OHCI HCDs
+ * @pdev: USB Host Controller being removed
+ *
+ * Reverses the effect of ohci_hcd_omap3_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ */
+static int __devexit ohci_hcd_omap3_remove(struct platform_device *pdev)
+{
+	struct ohci_hcd_omap3 *omap = platform_get_drvdata(pdev);
+	struct usb_hcd *hcd = ohci_to_hcd(omap->ohci);
+
+	usb_remove_hcd(hcd);
+	omap3_stop_ohci(omap, hcd);
+	iounmap(hcd->regs);
+	iounmap(omap->tll_base);
+	iounmap(omap->uhh_base);
+	usb_put_hcd(hcd);
+	kfree(omap);
+
+	return 0;
+}
+
+static void ohci_hcd_omap3_shutdown(struct platform_device *pdev)
+{
+	struct ohci_hcd_omap3 *omap = platform_get_drvdata(pdev);
+	struct usb_hcd *hcd = ohci_to_hcd(omap->ohci);
+
+	if (hcd->driver->shutdown)
+		hcd->driver->shutdown(hcd);
+}
+
+static struct platform_driver ohci_hcd_omap3_driver = {
+	.probe		= ohci_hcd_omap3_probe,
+	.remove		= __devexit_p(ohci_hcd_omap3_remove),
+	.shutdown	= ohci_hcd_omap3_shutdown,
+	.driver		= {
+		.name	= "ohci-omap3",
+	},
+};
+
+MODULE_ALIAS("platform:ohci-omap3");
+MODULE_AUTHOR("Anand Gadiyar <gadiyar@ti.com>");
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index e62b30b..f608dfd 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -34,12 +34,11 @@
 #include <linux/list.h>
 #include <linux/interrupt.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 
-#include "../core/hcd.h"
-
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/unaligned.h>
@@ -3154,10 +3153,10 @@
 	case 0:
 		return 0;
 	case 1:
-		return 1 << USB_PORT_FEAT_LOWSPEED;
+		return USB_PORT_STAT_LOW_SPEED;
 	case 2:
 	default:
-		return 1 << USB_PORT_FEAT_HIGHSPEED;
+		return USB_PORT_STAT_HIGH_SPEED;
 	}
 }
 
@@ -3202,7 +3201,7 @@
 		 * Even if OWNER is set, so the port is owned by the
 		 * companion controller, khubd needs to be able to clear
 		 * the port-change status bits (especially
-		 * USB_PORT_FEAT_C_CONNECTION).
+		 * USB_PORT_STAT_C_CONNECTION).
 		 */
 
 		switch (wValue) {
@@ -3264,11 +3263,11 @@
 
 		/* wPortChange bits */
 		if (temp & PORT_CSC)
-			status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+			status |= USB_PORT_STAT_C_CONNECTION << 16;
 		if (temp & PORT_PEC)
-			status |= 1 << USB_PORT_FEAT_C_ENABLE;
+			status |= USB_PORT_STAT_C_ENABLE << 16;
 		if ((temp & PORT_OCC) && !ignore_oc)
-			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
+			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
 
 		/* whoever resumes must GetPortStatus to complete it!! */
 		if (temp & PORT_RESUME) {
@@ -3286,7 +3285,7 @@
 			/* resume completed? */
 			else if (time_after_eq(jiffies,
 					oxu->reset_done[wIndex])) {
-				status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+				status |= USB_PORT_STAT_C_SUSPEND << 16;
 				oxu->reset_done[wIndex] = 0;
 
 				/* stop resume signaling */
@@ -3309,7 +3308,7 @@
 		if ((temp & PORT_RESET)
 				&& time_after_eq(jiffies,
 					oxu->reset_done[wIndex])) {
-			status |= 1 << USB_PORT_FEAT_C_RESET;
+			status |= USB_PORT_STAT_C_RESET << 16;
 			oxu->reset_done[wIndex] = 0;
 
 			/* force reset to complete */
@@ -3348,20 +3347,20 @@
 		 */
 
 		if (temp & PORT_CONNECT) {
-			status |= 1 << USB_PORT_FEAT_CONNECTION;
+			status |= USB_PORT_STAT_CONNECTION;
 			/* status may be from integrated TT */
 			status |= oxu_port_speed(oxu, temp);
 		}
 		if (temp & PORT_PE)
-			status |= 1 << USB_PORT_FEAT_ENABLE;
+			status |= USB_PORT_STAT_ENABLE;
 		if (temp & (PORT_SUSPEND|PORT_RESUME))
-			status |= 1 << USB_PORT_FEAT_SUSPEND;
+			status |= USB_PORT_STAT_SUSPEND;
 		if (temp & PORT_OC)
-			status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+			status |= USB_PORT_STAT_OVERCURRENT;
 		if (temp & PORT_RESET)
-			status |= 1 << USB_PORT_FEAT_RESET;
+			status |= USB_PORT_STAT_RESET;
 		if (temp & PORT_POWER)
-			status |= 1 << USB_PORT_FEAT_POWER;
+			status |= USB_PORT_STAT_POWER;
 
 #ifndef	OXU_VERBOSE_DEBUG
 	if (status & ~0xffff)	/* only if wPortChange is interesting */
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index d478ffa..6db57ab 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -33,6 +33,7 @@
 #include <linux/list.h>
 #include <linux/interrupt.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/mm.h>
@@ -40,7 +41,6 @@
 #include <linux/slab.h>
 #include <asm/cacheflush.h>
 
-#include "../core/hcd.h"
 #include "r8a66597.h"
 
 MODULE_DESCRIPTION("R8A66597 USB Host Controller Driver");
@@ -1018,10 +1018,10 @@
 	rh->old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST;
 	rh->scount = R8A66597_MAX_SAMPLING;
 	if (connect)
-		rh->port |= 1 << USB_PORT_FEAT_CONNECTION;
+		rh->port |= USB_PORT_STAT_CONNECTION;
 	else
-		rh->port &= ~(1 << USB_PORT_FEAT_CONNECTION);
-	rh->port |= 1 << USB_PORT_FEAT_C_CONNECTION;
+		rh->port &= ~USB_PORT_STAT_CONNECTION;
+	rh->port |= USB_PORT_STAT_C_CONNECTION << 16;
 
 	r8a66597_root_hub_start_polling(r8a66597);
 }
@@ -1059,15 +1059,14 @@
 	u16 speed = get_rh_usb_speed(r8a66597, port);
 	struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
 
-	rh->port &= ~((1 << USB_PORT_FEAT_HIGHSPEED) |
-		      (1 << USB_PORT_FEAT_LOWSPEED));
+	rh->port &= ~(USB_PORT_STAT_HIGH_SPEED | USB_PORT_STAT_LOW_SPEED);
 	if (speed == HSMODE)
-		rh->port |= (1 << USB_PORT_FEAT_HIGHSPEED);
+		rh->port |= USB_PORT_STAT_HIGH_SPEED;
 	else if (speed == LSMODE)
-		rh->port |= (1 << USB_PORT_FEAT_LOWSPEED);
+		rh->port |= USB_PORT_STAT_LOW_SPEED;
 
-	rh->port &= ~(1 << USB_PORT_FEAT_RESET);
-	rh->port |= 1 << USB_PORT_FEAT_ENABLE;
+	rh->port &= USB_PORT_STAT_RESET;
+	rh->port |= USB_PORT_STAT_ENABLE;
 }
 
 /* this function must be called with interrupt disabled */
@@ -1706,7 +1705,7 @@
 	u16 tmp;
 	struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
 
-	if (rh->port & (1 << USB_PORT_FEAT_RESET)) {
+	if (rh->port & USB_PORT_STAT_RESET) {
 		unsigned long dvstctr_reg = get_dvstctr_reg(port);
 
 		tmp = r8a66597_read(r8a66597, dvstctr_reg);
@@ -1718,7 +1717,7 @@
 			r8a66597_usb_connect(r8a66597, port);
 	}
 
-	if (!(rh->port & (1 << USB_PORT_FEAT_CONNECTION))) {
+	if (!(rh->port & USB_PORT_STAT_CONNECTION)) {
 		r8a66597_write(r8a66597, ~ATTCH, get_intsts_reg(port));
 		r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
 	}
@@ -2186,7 +2185,7 @@
 
 		switch (wValue) {
 		case USB_PORT_FEAT_ENABLE:
-			rh->port &= ~(1 << USB_PORT_FEAT_POWER);
+			rh->port &= ~USB_PORT_STAT_POWER;
 			break;
 		case USB_PORT_FEAT_SUSPEND:
 			break;
@@ -2227,12 +2226,12 @@
 			break;
 		case USB_PORT_FEAT_POWER:
 			r8a66597_port_power(r8a66597, port, 1);
-			rh->port |= (1 << USB_PORT_FEAT_POWER);
+			rh->port |= USB_PORT_STAT_POWER;
 			break;
 		case USB_PORT_FEAT_RESET: {
 			struct r8a66597_device *dev = rh->dev;
 
-			rh->port |= (1 << USB_PORT_FEAT_RESET);
+			rh->port |= USB_PORT_STAT_RESET;
 
 			disable_r8a66597_pipe_all(r8a66597, dev);
 			free_usb_address(r8a66597, dev, 1);
@@ -2270,12 +2269,12 @@
 		struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
 		unsigned long dvstctr_reg = get_dvstctr_reg(port);
 
-		if (!(rh->port & (1 << USB_PORT_FEAT_ENABLE)))
+		if (!(rh->port & USB_PORT_STAT_ENABLE))
 			continue;
 
 		dbg("suspend port = %d", port);
 		r8a66597_bclr(r8a66597, UACT, dvstctr_reg);	/* suspend */
-		rh->port |= 1 << USB_PORT_FEAT_SUSPEND;
+		rh->port |= USB_PORT_STAT_SUSPEND;
 
 		if (rh->dev->udev->do_remote_wakeup) {
 			msleep(3);	/* waiting last SOF */
@@ -2301,12 +2300,12 @@
 		struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
 		unsigned long dvstctr_reg = get_dvstctr_reg(port);
 
-		if (!(rh->port & (1 << USB_PORT_FEAT_SUSPEND)))
+		if (!(rh->port & USB_PORT_STAT_SUSPEND))
 			continue;
 
 		dbg("resume port = %d", port);
-		rh->port &= ~(1 << USB_PORT_FEAT_SUSPEND);
-		rh->port |= 1 << USB_PORT_FEAT_C_SUSPEND;
+		rh->port &= ~USB_PORT_STAT_SUSPEND;
+		rh->port |= USB_PORT_STAT_C_SUSPEND < 16;
 		r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg);
 		msleep(50);
 		r8a66597_mdfy(r8a66597, UACT, RESUME | UACT, dvstctr_reg);
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 3b867a8..bcf9f0e 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -45,6 +45,7 @@
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <linux/usb/sl811.h>
+#include <linux/usb/hcd.h>
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
@@ -53,7 +54,6 @@
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 
-#include "../core/hcd.h"
 #include "sl811.h"
 
 
@@ -90,10 +90,10 @@
 
 	/* hub is inactive unless the port is powered */
 	if (is_on) {
-		if (sl811->port1 & (1 << USB_PORT_FEAT_POWER))
+		if (sl811->port1 & USB_PORT_STAT_POWER)
 			return;
 
-		sl811->port1 = (1 << USB_PORT_FEAT_POWER);
+		sl811->port1 = USB_PORT_STAT_POWER;
 		sl811->irq_enable = SL11H_INTMASK_INSRMV;
 	} else {
 		sl811->port1 = 0;
@@ -407,7 +407,7 @@
 
 static inline void start_transfer(struct sl811 *sl811)
 {
-	if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND))
+	if (sl811->port1 & USB_PORT_STAT_SUSPEND)
 		return;
 	if (sl811->active_a == NULL) {
 		sl811->active_a = start(sl811, SL811_EP_A(SL811_HOST_BUF));
@@ -721,23 +721,23 @@
 		 * force the reset and make khubd clean up later.
 		 */
 		if (irqstat & SL11H_INTMASK_RD)
-			sl811->port1 &= ~(1 << USB_PORT_FEAT_CONNECTION);
+			sl811->port1 &= ~USB_PORT_STAT_CONNECTION;
 		else
-			sl811->port1 |= 1 << USB_PORT_FEAT_CONNECTION;
+			sl811->port1 |= USB_PORT_STAT_CONNECTION;
 
-		sl811->port1 |= 1 << USB_PORT_FEAT_C_CONNECTION;
+		sl811->port1 |= USB_PORT_STAT_C_CONNECTION << 16;
 
 	} else if (irqstat & SL11H_INTMASK_RD) {
-		if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)) {
+		if (sl811->port1 & USB_PORT_STAT_SUSPEND) {
 			DBG("wakeup\n");
-			sl811->port1 |= 1 << USB_PORT_FEAT_C_SUSPEND;
+			sl811->port1 |= USB_PORT_STAT_C_SUSPEND << 16;
 			sl811->stat_wake++;
 		} else
 			irqstat &= ~SL11H_INTMASK_RD;
 	}
 
 	if (irqstat) {
-		if (sl811->port1 & (1 << USB_PORT_FEAT_ENABLE))
+		if (sl811->port1 & USB_PORT_STAT_ENABLE)
 			start_transfer(sl811);
 		ret = IRQ_HANDLED;
 		if (retries--)
@@ -819,7 +819,7 @@
 	spin_lock_irqsave(&sl811->lock, flags);
 
 	/* don't submit to a dead or disabled port */
-	if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE))
+	if (!(sl811->port1 & USB_PORT_STAT_ENABLE)
 			|| !HC_IS_RUNNING(hcd->state)) {
 		retval = -ENODEV;
 		kfree(ep);
@@ -1119,9 +1119,9 @@
 	unsigned long	flags;
 	u8		irqstat;
 	u8		signaling = sl811->ctrl1 & SL11H_CTL1MASK_FORCE;
-	const u32	mask = (1 << USB_PORT_FEAT_CONNECTION)
-				| (1 << USB_PORT_FEAT_ENABLE)
-				| (1 << USB_PORT_FEAT_LOWSPEED);
+	const u32	mask = USB_PORT_STAT_CONNECTION
+				| USB_PORT_STAT_ENABLE
+				| USB_PORT_STAT_LOW_SPEED;
 
 	spin_lock_irqsave(&sl811->lock, flags);
 
@@ -1135,8 +1135,8 @@
 	switch (signaling) {
 	case SL11H_CTL1MASK_SE0:
 		DBG("end reset\n");
-		sl811->port1 = (1 << USB_PORT_FEAT_C_RESET)
-				| (1 << USB_PORT_FEAT_POWER);
+		sl811->port1 = (USB_PORT_STAT_C_RESET << 16)
+				 | USB_PORT_STAT_POWER;
 		sl811->ctrl1 = 0;
 		/* don't wrongly ack RD */
 		if (irqstat & SL11H_INTMASK_INSRMV)
@@ -1144,7 +1144,7 @@
 		break;
 	case SL11H_CTL1MASK_K:
 		DBG("end resume\n");
-		sl811->port1 &= ~(1 << USB_PORT_FEAT_SUSPEND);
+		sl811->port1 &= ~USB_PORT_STAT_SUSPEND;
 		break;
 	default:
 		DBG("odd timer signaling: %02x\n", signaling);
@@ -1154,26 +1154,26 @@
 
 	if (irqstat & SL11H_INTMASK_RD) {
 		/* usbcore nukes all pending transactions on disconnect */
-		if (sl811->port1 & (1 << USB_PORT_FEAT_CONNECTION))
-			sl811->port1 |= (1 << USB_PORT_FEAT_C_CONNECTION)
-					| (1 << USB_PORT_FEAT_C_ENABLE);
+		if (sl811->port1 & USB_PORT_STAT_CONNECTION)
+			sl811->port1 |= (USB_PORT_STAT_C_CONNECTION << 16)
+					| (USB_PORT_STAT_C_ENABLE << 16);
 		sl811->port1 &= ~mask;
 		sl811->irq_enable = SL11H_INTMASK_INSRMV;
 	} else {
 		sl811->port1 |= mask;
 		if (irqstat & SL11H_INTMASK_DP)
-			sl811->port1 &= ~(1 << USB_PORT_FEAT_LOWSPEED);
+			sl811->port1 &= ~USB_PORT_STAT_LOW_SPEED;
 		sl811->irq_enable = SL11H_INTMASK_INSRMV | SL11H_INTMASK_RD;
 	}
 
-	if (sl811->port1 & (1 << USB_PORT_FEAT_CONNECTION)) {
+	if (sl811->port1 & USB_PORT_STAT_CONNECTION) {
 		u8	ctrl2 = SL811HS_CTL2_INIT;
 
 		sl811->irq_enable |= SL11H_INTMASK_DONE_A;
 #ifdef USE_B
 		sl811->irq_enable |= SL11H_INTMASK_DONE_B;
 #endif
-		if (sl811->port1 & (1 << USB_PORT_FEAT_LOWSPEED)) {
+		if (sl811->port1 & USB_PORT_STAT_LOW_SPEED) {
 			sl811->ctrl1 |= SL11H_CTL1MASK_LSPD;
 			ctrl2 |= SL811HS_CTL2MASK_DSWAP;
 		}
@@ -1233,7 +1233,7 @@
 
 		switch (wValue) {
 		case USB_PORT_FEAT_ENABLE:
-			sl811->port1 &= (1 << USB_PORT_FEAT_POWER);
+			sl811->port1 &= USB_PORT_STAT_POWER;
 			sl811->ctrl1 = 0;
 			sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
 			sl811->irq_enable = SL11H_INTMASK_INSRMV;
@@ -1241,7 +1241,7 @@
 						sl811->irq_enable);
 			break;
 		case USB_PORT_FEAT_SUSPEND:
-			if (!(sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)))
+			if (!(sl811->port1 & USB_PORT_STAT_SUSPEND))
 				break;
 
 			/* 20 msec of resume/K signaling, other irqs blocked */
@@ -1290,9 +1290,9 @@
 			goto error;
 		switch (wValue) {
 		case USB_PORT_FEAT_SUSPEND:
-			if (sl811->port1 & (1 << USB_PORT_FEAT_RESET))
+			if (sl811->port1 & USB_PORT_STAT_RESET)
 				goto error;
-			if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE)))
+			if (!(sl811->port1 & USB_PORT_STAT_ENABLE))
 				goto error;
 
 			DBG("suspend...\n");
@@ -1303,9 +1303,9 @@
 			port_power(sl811, 1);
 			break;
 		case USB_PORT_FEAT_RESET:
-			if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND))
+			if (sl811->port1 & USB_PORT_STAT_SUSPEND)
 				goto error;
-			if (!(sl811->port1 & (1 << USB_PORT_FEAT_POWER)))
+			if (!(sl811->port1 & USB_PORT_STAT_POWER))
 				break;
 
 			/* 50 msec of reset/SE0 signaling, irqs blocked */
@@ -1314,7 +1314,7 @@
 						sl811->irq_enable);
 			sl811->ctrl1 = SL11H_CTL1MASK_SE0;
 			sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
-			sl811->port1 |= (1 << USB_PORT_FEAT_RESET);
+			sl811->port1 |= USB_PORT_STAT_RESET;
 			mod_timer(&sl811->timer, jiffies
 					+ msecs_to_jiffies(50));
 			break;
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 228f2b0..5b31bae 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -49,6 +49,7 @@
 #include <linux/list.h>
 #include <linux/interrupt.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
@@ -56,7 +57,6 @@
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
-#include "../core/hcd.h"
 
 	/* FIXME ohci.h is ONLY for internal use by the OHCI driver.
 	 * If you're going to try stuff like this, you need to split
@@ -1446,9 +1446,9 @@
 			return;
 		} else {
 			int retval;
-			u8 address = u132->addr[endp->usb_addr].address;
 			struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
 				endp->queue_next];
+			address = u132->addr[endp->usb_addr].address;
 			endp->active = 1;
 			ring->curr_endp = endp;
 			ring->in_use = 1;
@@ -3120,8 +3120,8 @@
 		ftdi_elan_gone_away(pdev);
 		return -ENOMEM;
 	} else {
-		int retval = 0;
 		struct u132 *u132 = hcd_to_u132(hcd);
+		retval = 0;
 		hcd->rsrc_start = 0;
 		mutex_lock(&u132_module_lock);
 		list_add_tail(&u132->u132_list, &u132_static_list);
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 0919706..6637e52 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -38,6 +38,7 @@
 #include <linux/dmapool.h>
 #include <linux/dma-mapping.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include <linux/bitops.h>
 #include <linux/dmi.h>
 
@@ -46,7 +47,6 @@
 #include <asm/irq.h>
 #include <asm/system.h>
 
-#include "../core/hcd.h"
 #include "uhci-hcd.h"
 #include "pci-quirks.h"
 
diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c
index c5305b5..767af26 100644
--- a/drivers/usb/host/whci/debug.c
+++ b/drivers/usb/host/whci/debug.c
@@ -30,7 +30,7 @@
 	struct dentry *pzl_f;
 };
 
-void qset_print(struct seq_file *s, struct whc_qset *qset)
+static void qset_print(struct seq_file *s, struct whc_qset *qset)
 {
 	static const char *qh_type[] = {
 		"ctrl", "isoc", "bulk", "intr", "rsvd", "rsvd", "rsvd", "lpintr", };
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c
index 141d049..ab5a14f 100644
--- a/drivers/usb/host/whci/qset.c
+++ b/drivers/usb/host/whci/qset.c
@@ -443,7 +443,7 @@
 
 	remaining = urb->transfer_buffer_length;
 
-	for_each_sg(urb->sg->sg, sg, urb->num_sgs, i) {
+	for_each_sg(urb->sg, sg, urb->num_sgs, i) {
 		dma_addr_t dma_addr;
 		size_t dma_remaining;
 		dma_addr_t sp, ep;
@@ -561,7 +561,7 @@
 
 	remaining = urb->transfer_buffer_length;
 
-	for_each_sg(urb->sg->sg, sg, urb->sg->nents, i) {
+	for_each_sg(urb->sg, sg, urb->num_sgs, i) {
 		size_t len;
 		size_t sg_remaining;
 		void *orig;
@@ -646,7 +646,7 @@
 	wurb->urb = urb;
 	INIT_WORK(&wurb->dequeue_work, urb_dequeue_work);
 
-	if (urb->sg) {
+	if (urb->num_sgs) {
 		ret = qset_add_urb_sg(whc, qset, urb, mem_flags);
 		if (ret == -EINVAL) {
 			qset_free_stds(qset, urb);
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index 105fa8b..fcbf4ab 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -364,6 +364,30 @@
 		xhci_debug_segment(xhci, seg);
 }
 
+void xhci_dbg_ep_rings(struct xhci_hcd *xhci,
+		unsigned int slot_id, unsigned int ep_index,
+		struct xhci_virt_ep *ep)
+{
+	int i;
+	struct xhci_ring *ring;
+
+	if (ep->ep_state & EP_HAS_STREAMS) {
+		for (i = 1; i < ep->stream_info->num_streams; i++) {
+			ring = ep->stream_info->stream_rings[i];
+			xhci_dbg(xhci, "Dev %d endpoint %d stream ID %d:\n",
+				slot_id, ep_index, i);
+			xhci_debug_segment(xhci, ring->deq_seg);
+		}
+	} else {
+		ring = ep->ring;
+		if (!ring)
+			return;
+		xhci_dbg(xhci, "Dev %d endpoint ring %d:\n",
+				slot_id, ep_index);
+		xhci_debug_segment(xhci, ring->deq_seg);
+	}
+}
+
 void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
 {
 	u32 addr = (u32) erst->erst_dma_addr;
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 208b805..a1a7a97 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -64,15 +64,15 @@
 static unsigned int xhci_port_speed(unsigned int port_status)
 {
 	if (DEV_LOWSPEED(port_status))
-		return 1 << USB_PORT_FEAT_LOWSPEED;
+		return USB_PORT_STAT_LOW_SPEED;
 	if (DEV_HIGHSPEED(port_status))
-		return 1 << USB_PORT_FEAT_HIGHSPEED;
+		return USB_PORT_STAT_HIGH_SPEED;
 	if (DEV_SUPERSPEED(port_status))
-		return 1 << USB_PORT_FEAT_SUPERSPEED;
+		return USB_PORT_STAT_SUPER_SPEED;
 	/*
 	 * FIXME: Yes, we should check for full speed, but the core uses that as
 	 * a default in portspeed() in usb/core/hub.c (which is the only place
-	 * USB_PORT_FEAT_*SPEED is used).
+	 * USB_PORT_STAT_*_SPEED is used).
 	 */
 	return 0;
 }
@@ -205,27 +205,27 @@
 
 		/* wPortChange bits */
 		if (temp & PORT_CSC)
-			status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+			status |= USB_PORT_STAT_C_CONNECTION << 16;
 		if (temp & PORT_PEC)
-			status |= 1 << USB_PORT_FEAT_C_ENABLE;
+			status |= USB_PORT_STAT_C_ENABLE << 16;
 		if ((temp & PORT_OCC))
-			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
+			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
 		/*
 		 * FIXME ignoring suspend, reset, and USB 2.1/3.0 specific
 		 * changes
 		 */
 		if (temp & PORT_CONNECT) {
-			status |= 1 << USB_PORT_FEAT_CONNECTION;
+			status |= USB_PORT_STAT_CONNECTION;
 			status |= xhci_port_speed(temp);
 		}
 		if (temp & PORT_PE)
-			status |= 1 << USB_PORT_FEAT_ENABLE;
+			status |= USB_PORT_STAT_ENABLE;
 		if (temp & PORT_OC)
-			status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+			status |= USB_PORT_STAT_OVERCURRENT;
 		if (temp & PORT_RESET)
-			status |= 1 << USB_PORT_FEAT_RESET;
+			status |= USB_PORT_STAT_RESET;
 		if (temp & PORT_POWER)
-			status |= 1 << USB_PORT_FEAT_POWER;
+			status |= USB_PORT_STAT_POWER;
 		xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
 		put_unaligned(cpu_to_le32(status), (__le32 *) buf);
 		break;
@@ -298,7 +298,6 @@
  * Returns 0 if the status hasn't changed, or the number of bytes in buf.
  * Ports are 0-indexed from the HCD point of view,
  * and 1-indexed from the USB core pointer of view.
- * xHCI instances can have up to 127 ports, so FIXME if you see more than 15.
  *
  * Note that the status change bits will be cleared as soon as a port status
  * change event is generated, so we use the saved status from that event.
@@ -315,14 +314,9 @@
 	ports = HCS_MAX_PORTS(xhci->hcs_params1);
 
 	/* Initial status is no changes */
-	buf[0] = 0;
+	retval = (ports + 8) / 8;
+	memset(buf, 0, retval);
 	status = 0;
-	if (ports > 7) {
-		buf[1] = 0;
-		retval = 2;
-	} else {
-		retval = 1;
-	}
 
 	spin_lock_irqsave(&xhci->lock, flags);
 	/* For each port, did anything change?  If so, set that bit in buf. */
@@ -331,10 +325,7 @@
 			NUM_PORT_REGS*i;
 		temp = xhci_readl(xhci, addr);
 		if (temp & (PORT_CSC | PORT_PEC | PORT_OCC)) {
-			if (i < 7)
-				buf[0] |= 1 << (i + 1);
-			else
-				buf[1] |= 1 << (i - 7);
+			buf[(i + 1) / 8] |= 1 << (i + 1) % 8;
 			status = 1;
 		}
 	}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index d64f572..fd9e03a 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -41,13 +41,13 @@
 
 	seg = kzalloc(sizeof *seg, flags);
 	if (!seg)
-		return 0;
+		return NULL;
 	xhci_dbg(xhci, "Allocating priv segment structure at %p\n", seg);
 
 	seg->trbs = dma_pool_alloc(xhci->segment_pool, flags, &dma);
 	if (!seg->trbs) {
 		kfree(seg);
-		return 0;
+		return NULL;
 	}
 	xhci_dbg(xhci, "// Allocating segment at %p (virtual) 0x%llx (DMA)\n",
 			seg->trbs, (unsigned long long)dma);
@@ -159,7 +159,7 @@
 	ring = kzalloc(sizeof *(ring), flags);
 	xhci_dbg(xhci, "Allocating ring at %p\n", ring);
 	if (!ring)
-		return 0;
+		return NULL;
 
 	INIT_LIST_HEAD(&ring->td_list);
 	if (num_segs == 0)
@@ -196,7 +196,7 @@
 
 fail:
 	xhci_ring_free(xhci, ring);
-	return 0;
+	return NULL;
 }
 
 void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
@@ -247,7 +247,7 @@
 
 #define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
 
-struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
+static struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
 						    int type, gfp_t flags)
 {
 	struct xhci_container_ctx *ctx = kzalloc(sizeof(*ctx), flags);
@@ -265,7 +265,7 @@
 	return ctx;
 }
 
-void xhci_free_container_ctx(struct xhci_hcd *xhci,
+static void xhci_free_container_ctx(struct xhci_hcd *xhci,
 			     struct xhci_container_ctx *ctx)
 {
 	if (!ctx)
@@ -304,6 +304,422 @@
 		(ctx->bytes + (ep_index * CTX_SIZE(xhci->hcc_params)));
 }
 
+
+/***************** Streams structures manipulation *************************/
+
+void xhci_free_stream_ctx(struct xhci_hcd *xhci,
+		unsigned int num_stream_ctxs,
+		struct xhci_stream_ctx *stream_ctx, dma_addr_t dma)
+{
+	struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+
+	if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE)
+		pci_free_consistent(pdev,
+				sizeof(struct xhci_stream_ctx)*num_stream_ctxs,
+				stream_ctx, dma);
+	else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE)
+		return dma_pool_free(xhci->small_streams_pool,
+				stream_ctx, dma);
+	else
+		return dma_pool_free(xhci->medium_streams_pool,
+				stream_ctx, dma);
+}
+
+/*
+ * The stream context array for each endpoint with bulk streams enabled can
+ * vary in size, based on:
+ *  - how many streams the endpoint supports,
+ *  - the maximum primary stream array size the host controller supports,
+ *  - and how many streams the device driver asks for.
+ *
+ * The stream context array must be a power of 2, and can be as small as
+ * 64 bytes or as large as 1MB.
+ */
+struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,
+		unsigned int num_stream_ctxs, dma_addr_t *dma,
+		gfp_t mem_flags)
+{
+	struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+
+	if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE)
+		return pci_alloc_consistent(pdev,
+				sizeof(struct xhci_stream_ctx)*num_stream_ctxs,
+				dma);
+	else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE)
+		return dma_pool_alloc(xhci->small_streams_pool,
+				mem_flags, dma);
+	else
+		return dma_pool_alloc(xhci->medium_streams_pool,
+				mem_flags, dma);
+}
+
+struct xhci_ring *xhci_dma_to_transfer_ring(
+		struct xhci_virt_ep *ep,
+		u64 address)
+{
+	if (ep->ep_state & EP_HAS_STREAMS)
+		return radix_tree_lookup(&ep->stream_info->trb_address_map,
+				address >> SEGMENT_SHIFT);
+	return ep->ring;
+}
+
+/* Only use this when you know stream_info is valid */
+#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
+static struct xhci_ring *dma_to_stream_ring(
+		struct xhci_stream_info *stream_info,
+		u64 address)
+{
+	return radix_tree_lookup(&stream_info->trb_address_map,
+			address >> SEGMENT_SHIFT);
+}
+#endif	/* CONFIG_USB_XHCI_HCD_DEBUGGING */
+
+struct xhci_ring *xhci_stream_id_to_ring(
+		struct xhci_virt_device *dev,
+		unsigned int ep_index,
+		unsigned int stream_id)
+{
+	struct xhci_virt_ep *ep = &dev->eps[ep_index];
+
+	if (stream_id == 0)
+		return ep->ring;
+	if (!ep->stream_info)
+		return NULL;
+
+	if (stream_id > ep->stream_info->num_streams)
+		return NULL;
+	return ep->stream_info->stream_rings[stream_id];
+}
+
+struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
+		unsigned int slot_id, unsigned int ep_index,
+		unsigned int stream_id)
+{
+	struct xhci_virt_ep *ep;
+
+	ep = &xhci->devs[slot_id]->eps[ep_index];
+	/* Common case: no streams */
+	if (!(ep->ep_state & EP_HAS_STREAMS))
+		return ep->ring;
+
+	if (stream_id == 0) {
+		xhci_warn(xhci,
+				"WARN: Slot ID %u, ep index %u has streams, "
+				"but URB has no stream ID.\n",
+				slot_id, ep_index);
+		return NULL;
+	}
+
+	if (stream_id < ep->stream_info->num_streams)
+		return ep->stream_info->stream_rings[stream_id];
+
+	xhci_warn(xhci,
+			"WARN: Slot ID %u, ep index %u has "
+			"stream IDs 1 to %u allocated, "
+			"but stream ID %u is requested.\n",
+			slot_id, ep_index,
+			ep->stream_info->num_streams - 1,
+			stream_id);
+	return NULL;
+}
+
+/* Get the right ring for the given URB.
+ * If the endpoint supports streams, boundary check the URB's stream ID.
+ * If the endpoint doesn't support streams, return the singular endpoint ring.
+ */
+struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
+		struct urb *urb)
+{
+	return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id,
+		xhci_get_endpoint_index(&urb->ep->desc), urb->stream_id);
+}
+
+#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
+static int xhci_test_radix_tree(struct xhci_hcd *xhci,
+		unsigned int num_streams,
+		struct xhci_stream_info *stream_info)
+{
+	u32 cur_stream;
+	struct xhci_ring *cur_ring;
+	u64 addr;
+
+	for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
+		struct xhci_ring *mapped_ring;
+		int trb_size = sizeof(union xhci_trb);
+
+		cur_ring = stream_info->stream_rings[cur_stream];
+		for (addr = cur_ring->first_seg->dma;
+				addr < cur_ring->first_seg->dma + SEGMENT_SIZE;
+				addr += trb_size) {
+			mapped_ring = dma_to_stream_ring(stream_info, addr);
+			if (cur_ring != mapped_ring) {
+				xhci_warn(xhci, "WARN: DMA address 0x%08llx "
+						"didn't map to stream ID %u; "
+						"mapped to ring %p\n",
+						(unsigned long long) addr,
+						cur_stream,
+						mapped_ring);
+				return -EINVAL;
+			}
+		}
+		/* One TRB after the end of the ring segment shouldn't return a
+		 * pointer to the current ring (although it may be a part of a
+		 * different ring).
+		 */
+		mapped_ring = dma_to_stream_ring(stream_info, addr);
+		if (mapped_ring != cur_ring) {
+			/* One TRB before should also fail */
+			addr = cur_ring->first_seg->dma - trb_size;
+			mapped_ring = dma_to_stream_ring(stream_info, addr);
+		}
+		if (mapped_ring == cur_ring) {
+			xhci_warn(xhci, "WARN: Bad DMA address 0x%08llx "
+					"mapped to valid stream ID %u; "
+					"mapped ring = %p\n",
+					(unsigned long long) addr,
+					cur_stream,
+					mapped_ring);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+#endif	/* CONFIG_USB_XHCI_HCD_DEBUGGING */
+
+/*
+ * Change an endpoint's internal structure so it supports stream IDs.  The
+ * number of requested streams includes stream 0, which cannot be used by device
+ * drivers.
+ *
+ * The number of stream contexts in the stream context array may be bigger than
+ * the number of streams the driver wants to use.  This is because the number of
+ * stream context array entries must be a power of two.
+ *
+ * We need a radix tree for mapping physical addresses of TRBs to which stream
+ * ID they belong to.  We need to do this because the host controller won't tell
+ * us which stream ring the TRB came from.  We could store the stream ID in an
+ * event data TRB, but that doesn't help us for the cancellation case, since the
+ * endpoint may stop before it reaches that event data TRB.
+ *
+ * The radix tree maps the upper portion of the TRB DMA address to a ring
+ * segment that has the same upper portion of DMA addresses.  For example, say I
+ * have segments of size 1KB, that are always 64-byte aligned.  A segment may
+ * start at 0x10c91000 and end at 0x10c913f0.  If I use the upper 10 bits, the
+ * key to the stream ID is 0x43244.  I can use the DMA address of the TRB to
+ * pass the radix tree a key to get the right stream ID:
+ *
+ * 	0x10c90fff >> 10 = 0x43243
+ * 	0x10c912c0 >> 10 = 0x43244
+ * 	0x10c91400 >> 10 = 0x43245
+ *
+ * Obviously, only those TRBs with DMA addresses that are within the segment
+ * will make the radix tree return the stream ID for that ring.
+ *
+ * Caveats for the radix tree:
+ *
+ * The radix tree uses an unsigned long as a key pair.  On 32-bit systems, an
+ * unsigned long will be 32-bits; on a 64-bit system an unsigned long will be
+ * 64-bits.  Since we only request 32-bit DMA addresses, we can use that as the
+ * key on 32-bit or 64-bit systems (it would also be fine if we asked for 64-bit
+ * PCI DMA addresses on a 64-bit system).  There might be a problem on 32-bit
+ * extended systems (where the DMA address can be bigger than 32-bits),
+ * if we allow the PCI dma mask to be bigger than 32-bits.  So don't do that.
+ */
+struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
+		unsigned int num_stream_ctxs,
+		unsigned int num_streams, gfp_t mem_flags)
+{
+	struct xhci_stream_info *stream_info;
+	u32 cur_stream;
+	struct xhci_ring *cur_ring;
+	unsigned long key;
+	u64 addr;
+	int ret;
+
+	xhci_dbg(xhci, "Allocating %u streams and %u "
+			"stream context array entries.\n",
+			num_streams, num_stream_ctxs);
+	if (xhci->cmd_ring_reserved_trbs == MAX_RSVD_CMD_TRBS) {
+		xhci_dbg(xhci, "Command ring has no reserved TRBs available\n");
+		return NULL;
+	}
+	xhci->cmd_ring_reserved_trbs++;
+
+	stream_info = kzalloc(sizeof(struct xhci_stream_info), mem_flags);
+	if (!stream_info)
+		goto cleanup_trbs;
+
+	stream_info->num_streams = num_streams;
+	stream_info->num_stream_ctxs = num_stream_ctxs;
+
+	/* Initialize the array of virtual pointers to stream rings. */
+	stream_info->stream_rings = kzalloc(
+			sizeof(struct xhci_ring *)*num_streams,
+			mem_flags);
+	if (!stream_info->stream_rings)
+		goto cleanup_info;
+
+	/* Initialize the array of DMA addresses for stream rings for the HW. */
+	stream_info->stream_ctx_array = xhci_alloc_stream_ctx(xhci,
+			num_stream_ctxs, &stream_info->ctx_array_dma,
+			mem_flags);
+	if (!stream_info->stream_ctx_array)
+		goto cleanup_ctx;
+	memset(stream_info->stream_ctx_array, 0,
+			sizeof(struct xhci_stream_ctx)*num_stream_ctxs);
+
+	/* Allocate everything needed to free the stream rings later */
+	stream_info->free_streams_command =
+		xhci_alloc_command(xhci, true, true, mem_flags);
+	if (!stream_info->free_streams_command)
+		goto cleanup_ctx;
+
+	INIT_RADIX_TREE(&stream_info->trb_address_map, GFP_ATOMIC);
+
+	/* Allocate rings for all the streams that the driver will use,
+	 * and add their segment DMA addresses to the radix tree.
+	 * Stream 0 is reserved.
+	 */
+	for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
+		stream_info->stream_rings[cur_stream] =
+			xhci_ring_alloc(xhci, 1, true, mem_flags);
+		cur_ring = stream_info->stream_rings[cur_stream];
+		if (!cur_ring)
+			goto cleanup_rings;
+		cur_ring->stream_id = cur_stream;
+		/* Set deq ptr, cycle bit, and stream context type */
+		addr = cur_ring->first_seg->dma |
+			SCT_FOR_CTX(SCT_PRI_TR) |
+			cur_ring->cycle_state;
+		stream_info->stream_ctx_array[cur_stream].stream_ring = addr;
+		xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n",
+				cur_stream, (unsigned long long) addr);
+
+		key = (unsigned long)
+			(cur_ring->first_seg->dma >> SEGMENT_SHIFT);
+		ret = radix_tree_insert(&stream_info->trb_address_map,
+				key, cur_ring);
+		if (ret) {
+			xhci_ring_free(xhci, cur_ring);
+			stream_info->stream_rings[cur_stream] = NULL;
+			goto cleanup_rings;
+		}
+	}
+	/* Leave the other unused stream ring pointers in the stream context
+	 * array initialized to zero.  This will cause the xHC to give us an
+	 * error if the device asks for a stream ID we don't have setup (if it
+	 * was any other way, the host controller would assume the ring is
+	 * "empty" and wait forever for data to be queued to that stream ID).
+	 */
+#if XHCI_DEBUG
+	/* Do a little test on the radix tree to make sure it returns the
+	 * correct values.
+	 */
+	if (xhci_test_radix_tree(xhci, num_streams, stream_info))
+		goto cleanup_rings;
+#endif
+
+	return stream_info;
+
+cleanup_rings:
+	for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
+		cur_ring = stream_info->stream_rings[cur_stream];
+		if (cur_ring) {
+			addr = cur_ring->first_seg->dma;
+			radix_tree_delete(&stream_info->trb_address_map,
+					addr >> SEGMENT_SHIFT);
+			xhci_ring_free(xhci, cur_ring);
+			stream_info->stream_rings[cur_stream] = NULL;
+		}
+	}
+	xhci_free_command(xhci, stream_info->free_streams_command);
+cleanup_ctx:
+	kfree(stream_info->stream_rings);
+cleanup_info:
+	kfree(stream_info);
+cleanup_trbs:
+	xhci->cmd_ring_reserved_trbs--;
+	return NULL;
+}
+/*
+ * Sets the MaxPStreams field and the Linear Stream Array field.
+ * Sets the dequeue pointer to the stream context array.
+ */
+void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
+		struct xhci_ep_ctx *ep_ctx,
+		struct xhci_stream_info *stream_info)
+{
+	u32 max_primary_streams;
+	/* MaxPStreams is the number of stream context array entries, not the
+	 * number we're actually using.  Must be in 2^(MaxPstreams + 1) format.
+	 * fls(0) = 0, fls(0x1) = 1, fls(0x10) = 2, fls(0x100) = 3, etc.
+	 */
+	max_primary_streams = fls(stream_info->num_stream_ctxs) - 2;
+	xhci_dbg(xhci, "Setting number of stream ctx array entries to %u\n",
+			1 << (max_primary_streams + 1));
+	ep_ctx->ep_info &= ~EP_MAXPSTREAMS_MASK;
+	ep_ctx->ep_info |= EP_MAXPSTREAMS(max_primary_streams);
+	ep_ctx->ep_info |= EP_HAS_LSA;
+	ep_ctx->deq  = stream_info->ctx_array_dma;
+}
+
+/*
+ * Sets the MaxPStreams field and the Linear Stream Array field to 0.
+ * Reinstalls the "normal" endpoint ring (at its previous dequeue mark,
+ * not at the beginning of the ring).
+ */
+void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
+		struct xhci_ep_ctx *ep_ctx,
+		struct xhci_virt_ep *ep)
+{
+	dma_addr_t addr;
+	ep_ctx->ep_info &= ~EP_MAXPSTREAMS_MASK;
+	ep_ctx->ep_info &= ~EP_HAS_LSA;
+	addr = xhci_trb_virt_to_dma(ep->ring->deq_seg, ep->ring->dequeue);
+	ep_ctx->deq  = addr | ep->ring->cycle_state;
+}
+
+/* Frees all stream contexts associated with the endpoint,
+ *
+ * Caller should fix the endpoint context streams fields.
+ */
+void xhci_free_stream_info(struct xhci_hcd *xhci,
+		struct xhci_stream_info *stream_info)
+{
+	int cur_stream;
+	struct xhci_ring *cur_ring;
+	dma_addr_t addr;
+
+	if (!stream_info)
+		return;
+
+	for (cur_stream = 1; cur_stream < stream_info->num_streams;
+			cur_stream++) {
+		cur_ring = stream_info->stream_rings[cur_stream];
+		if (cur_ring) {
+			addr = cur_ring->first_seg->dma;
+			radix_tree_delete(&stream_info->trb_address_map,
+					addr >> SEGMENT_SHIFT);
+			xhci_ring_free(xhci, cur_ring);
+			stream_info->stream_rings[cur_stream] = NULL;
+		}
+	}
+	xhci_free_command(xhci, stream_info->free_streams_command);
+	xhci->cmd_ring_reserved_trbs--;
+	if (stream_info->stream_ctx_array)
+		xhci_free_stream_ctx(xhci,
+				stream_info->num_stream_ctxs,
+				stream_info->stream_ctx_array,
+				stream_info->ctx_array_dma);
+
+	if (stream_info)
+		kfree(stream_info->stream_rings);
+	kfree(stream_info);
+}
+
+
+/***************** Device context manipulation *************************/
+
 static void xhci_init_endpoint_timer(struct xhci_hcd *xhci,
 		struct xhci_virt_ep *ep)
 {
@@ -328,9 +744,13 @@
 	if (!dev)
 		return;
 
-	for (i = 0; i < 31; ++i)
+	for (i = 0; i < 31; ++i) {
 		if (dev->eps[i].ring)
 			xhci_ring_free(xhci, dev->eps[i].ring);
+		if (dev->eps[i].stream_info)
+			xhci_free_stream_info(xhci,
+					dev->eps[i].stream_info);
+	}
 
 	if (dev->ring_cache) {
 		for (i = 0; i < dev->num_rings_cached; i++)
@@ -344,7 +764,7 @@
 		xhci_free_container_ctx(xhci, dev->out_ctx);
 
 	kfree(xhci->devs[slot_id]);
-	xhci->devs[slot_id] = 0;
+	xhci->devs[slot_id] = NULL;
 }
 
 int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
@@ -590,9 +1010,9 @@
 static inline u32 xhci_get_endpoint_mult(struct usb_device *udev,
 		struct usb_host_endpoint *ep)
 {
-	if (udev->speed != USB_SPEED_SUPER || !ep->ss_ep_comp)
+	if (udev->speed != USB_SPEED_SUPER)
 		return 0;
-	return ep->ss_ep_comp->desc.bmAttributes;
+	return ep->ss_ep_comp.bmAttributes;
 }
 
 static inline u32 xhci_get_endpoint_type(struct usb_device *udev,
@@ -641,13 +1061,8 @@
 			usb_endpoint_xfer_bulk(&ep->desc))
 		return 0;
 
-	if (udev->speed == USB_SPEED_SUPER) {
-		if (ep->ss_ep_comp)
-			return ep->ss_ep_comp->desc.wBytesPerInterval;
-		xhci_warn(xhci, "WARN no SS endpoint companion descriptor.\n");
-		/* Assume no bursts, no multiple opportunities to send. */
-		return ep->desc.wMaxPacketSize;
-	}
+	if (udev->speed == USB_SPEED_SUPER)
+		return ep->ss_ep_comp.wBytesPerInterval;
 
 	max_packet = ep->desc.wMaxPacketSize & 0x3ff;
 	max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11;
@@ -655,6 +1070,9 @@
 	return max_packet * (max_burst + 1);
 }
 
+/* Set up an endpoint with one ring segment.  Do not allocate stream rings.
+ * Drivers will have to call usb_alloc_streams() to do that.
+ */
 int xhci_endpoint_init(struct xhci_hcd *xhci,
 		struct xhci_virt_device *virt_dev,
 		struct usb_device *udev,
@@ -708,12 +1126,9 @@
 		max_packet = ep->desc.wMaxPacketSize;
 		ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
 		/* dig out max burst from ep companion desc */
-		if (!ep->ss_ep_comp) {
-			xhci_warn(xhci, "WARN no SS endpoint companion descriptor.\n");
-			max_packet = 0;
-		} else {
-			max_packet = ep->ss_ep_comp->desc.bMaxBurst;
-		}
+		max_packet = ep->ss_ep_comp.bMaxBurst;
+		if (!max_packet)
+			xhci_warn(xhci, "WARN no SS endpoint bMaxBurst\n");
 		ep_ctx->ep_info2 |= MAX_BURST(max_packet);
 		break;
 	case USB_SPEED_HIGH:
@@ -1003,6 +1418,16 @@
 	xhci->device_pool = NULL;
 	xhci_dbg(xhci, "Freed device context pool\n");
 
+	if (xhci->small_streams_pool)
+		dma_pool_destroy(xhci->small_streams_pool);
+	xhci->small_streams_pool = NULL;
+	xhci_dbg(xhci, "Freed small stream array pool\n");
+
+	if (xhci->medium_streams_pool)
+		dma_pool_destroy(xhci->medium_streams_pool);
+	xhci->medium_streams_pool = NULL;
+	xhci_dbg(xhci, "Freed medium stream array pool\n");
+
 	xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr);
 	if (xhci->dcbaa)
 		pci_free_consistent(pdev, sizeof(*xhci->dcbaa),
@@ -1239,6 +1664,22 @@
 	if (!xhci->segment_pool || !xhci->device_pool)
 		goto fail;
 
+	/* Linear stream context arrays don't have any boundary restrictions,
+	 * and only need to be 16-byte aligned.
+	 */
+	xhci->small_streams_pool =
+		dma_pool_create("xHCI 256 byte stream ctx arrays",
+			dev, SMALL_STREAM_ARRAY_SIZE, 16, 0);
+	xhci->medium_streams_pool =
+		dma_pool_create("xHCI 1KB stream ctx arrays",
+			dev, MEDIUM_STREAM_ARRAY_SIZE, 16, 0);
+	/* Any stream context array bigger than MEDIUM_STREAM_ARRAY_SIZE
+	 * will be allocated with pci_alloc_consistent()
+	 */
+
+	if (!xhci->small_streams_pool || !xhci->medium_streams_pool)
+		goto fail;
+
 	/* Set up the command ring to have one segments for now. */
 	xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, flags);
 	if (!xhci->cmd_ring)
@@ -1330,7 +1771,7 @@
 	 */
 	init_completion(&xhci->addr_dev);
 	for (i = 0; i < MAX_HC_SLOTS; ++i)
-		xhci->devs[i] = 0;
+		xhci->devs[i] = NULL;
 
 	if (scratchpad_alloc(xhci, flags))
 		goto fail;
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 417d37a..edffd81 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -54,7 +54,7 @@
 	struct pci_dev		*pdev = to_pci_dev(hcd->self.controller);
 	int			retval;
 
-	hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 1;
+	hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2;
 
 	xhci->cap_regs = hcd->regs;
 	xhci->op_regs = hcd->regs +
@@ -132,6 +132,8 @@
 	.urb_dequeue =		xhci_urb_dequeue,
 	.alloc_dev =		xhci_alloc_dev,
 	.free_dev =		xhci_free_dev,
+	.alloc_streams =	xhci_alloc_streams,
+	.free_streams =		xhci_free_streams,
 	.add_endpoint =		xhci_add_endpoint,
 	.drop_endpoint =	xhci_drop_endpoint,
 	.endpoint_reset =	xhci_endpoint_reset,
@@ -175,12 +177,12 @@
 	.shutdown = 	usb_hcd_pci_shutdown,
 };
 
-int xhci_register_pci()
+int xhci_register_pci(void)
 {
 	return pci_register_driver(&xhci_pci_driver);
 }
 
-void xhci_unregister_pci()
+void xhci_unregister_pci(void)
 {
 	pci_unregister_driver(&xhci_pci_driver);
 }
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 85d7e8f..36c858e 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -112,6 +112,12 @@
 		return (trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK);
 }
 
+static inline int enqueue_is_link_trb(struct xhci_ring *ring)
+{
+	struct xhci_link_trb *link = &ring->enqueue->link;
+	return ((link->control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK));
+}
+
 /* Updates trb to point to the next TRB in the ring, and updates seg if the next
  * TRB is in a new segment.  This does not skip over link TRBs, and it does not
  * effect the ring dequeue or enqueue pointers.
@@ -193,20 +199,15 @@
 	while (last_trb(xhci, ring, ring->enq_seg, next)) {
 		if (!consumer) {
 			if (ring != xhci->event_ring) {
-				/* If we're not dealing with 0.95 hardware,
-				 * carry over the chain bit of the previous TRB
-				 * (which may mean the chain bit is cleared).
-				 */
-				if (!xhci_link_trb_quirk(xhci)) {
-					next->link.control &= ~TRB_CHAIN;
-					next->link.control |= chain;
+				if (chain) {
+					next->link.control |= TRB_CHAIN;
+
+					/* Give this link TRB to the hardware */
+					wmb();
+					next->link.control ^= TRB_CYCLE;
+				} else {
+					break;
 				}
-				/* Give this link TRB to the hardware */
-				wmb();
-				if (next->link.control & TRB_CYCLE)
-					next->link.control &= (u32) ~TRB_CYCLE;
-				else
-					next->link.control |= (u32) TRB_CYCLE;
 			}
 			/* Toggle the cycle bit after the last ring segment. */
 			if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
@@ -242,10 +243,34 @@
 	int i;
 	union xhci_trb *enq = ring->enqueue;
 	struct xhci_segment *enq_seg = ring->enq_seg;
+	struct xhci_segment *cur_seg;
+	unsigned int left_on_ring;
+
+	/* If we are currently pointing to a link TRB, advance the
+	 * enqueue pointer before checking for space */
+	while (last_trb(xhci, ring, enq_seg, enq)) {
+		enq_seg = enq_seg->next;
+		enq = enq_seg->trbs;
+	}
 
 	/* Check if ring is empty */
-	if (enq == ring->dequeue)
+	if (enq == ring->dequeue) {
+		/* Can't use link trbs */
+		left_on_ring = TRBS_PER_SEGMENT - 1;
+		for (cur_seg = enq_seg->next; cur_seg != enq_seg;
+				cur_seg = cur_seg->next)
+			left_on_ring += TRBS_PER_SEGMENT - 1;
+
+		/* Always need one TRB free in the ring. */
+		left_on_ring -= 1;
+		if (num_trbs > left_on_ring) {
+			xhci_warn(xhci, "Not enough room on ring; "
+					"need %u TRBs, %u TRBs left\n",
+					num_trbs, left_on_ring);
+			return 0;
+		}
 		return 1;
+	}
 	/* Make sure there's an extra empty TRB available */
 	for (i = 0; i <= num_trbs; ++i) {
 		if (enq == ring->dequeue)
@@ -295,7 +320,8 @@
 
 static void ring_ep_doorbell(struct xhci_hcd *xhci,
 		unsigned int slot_id,
-		unsigned int ep_index)
+		unsigned int ep_index,
+		unsigned int stream_id)
 {
 	struct xhci_virt_ep *ep;
 	unsigned int ep_state;
@@ -306,11 +332,16 @@
 	ep_state = ep->ep_state;
 	/* Don't ring the doorbell for this endpoint if there are pending
 	 * cancellations because the we don't want to interrupt processing.
+	 * We don't want to restart any stream rings if there's a set dequeue
+	 * pointer command pending because the device can choose to start any
+	 * stream once the endpoint is on the HW schedule.
+	 * FIXME - check all the stream rings for pending cancellations.
 	 */
 	if (!(ep_state & EP_HALT_PENDING) && !(ep_state & SET_DEQ_PENDING)
 			&& !(ep_state & EP_HALTED)) {
 		field = xhci_readl(xhci, db_addr) & DB_MASK;
-		xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr);
+		field |= EPI_TO_DB(ep_index) | STREAM_ID_TO_DB(stream_id);
+		xhci_writel(xhci, field, db_addr);
 		/* Flush PCI posted writes - FIXME Matthew Wilcox says this
 		 * isn't time-critical and we shouldn't make the CPU wait for
 		 * the flush.
@@ -319,6 +350,31 @@
 	}
 }
 
+/* Ring the doorbell for any rings with pending URBs */
+static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
+		unsigned int slot_id,
+		unsigned int ep_index)
+{
+	unsigned int stream_id;
+	struct xhci_virt_ep *ep;
+
+	ep = &xhci->devs[slot_id]->eps[ep_index];
+
+	/* A ring has pending URBs if its TD list is not empty */
+	if (!(ep->ep_state & EP_HAS_STREAMS)) {
+		if (!(list_empty(&ep->ring->td_list)))
+			ring_ep_doorbell(xhci, slot_id, ep_index, 0);
+		return;
+	}
+
+	for (stream_id = 1; stream_id < ep->stream_info->num_streams;
+			stream_id++) {
+		struct xhci_stream_info *stream_info = ep->stream_info;
+		if (!list_empty(&stream_info->stream_rings[stream_id]->td_list))
+			ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
+	}
+}
+
 /*
  * Find the segment that trb is in.  Start searching in start_seg.
  * If we must move past a segment that has a link TRB with a toggle cycle state
@@ -334,13 +390,14 @@
 	while (cur_seg->trbs > trb ||
 			&cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) {
 		generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic;
-		if (TRB_TYPE(generic_trb->field[3]) == TRB_LINK &&
+		if ((generic_trb->field[3] & TRB_TYPE_BITMASK) ==
+				TRB_TYPE(TRB_LINK) &&
 				(generic_trb->field[3] & LINK_TOGGLE))
 			*cycle_state = ~(*cycle_state) & 0x1;
 		cur_seg = cur_seg->next;
 		if (cur_seg == start_seg)
 			/* Looped over the entire list.  Oops! */
-			return 0;
+			return NULL;
 	}
 	return cur_seg;
 }
@@ -361,14 +418,23 @@
  */
 void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
 		unsigned int slot_id, unsigned int ep_index,
-		struct xhci_td *cur_td, struct xhci_dequeue_state *state)
+		unsigned int stream_id, struct xhci_td *cur_td,
+		struct xhci_dequeue_state *state)
 {
 	struct xhci_virt_device *dev = xhci->devs[slot_id];
-	struct xhci_ring *ep_ring = dev->eps[ep_index].ring;
+	struct xhci_ring *ep_ring;
 	struct xhci_generic_trb *trb;
 	struct xhci_ep_ctx *ep_ctx;
 	dma_addr_t addr;
 
+	ep_ring = xhci_triad_to_transfer_ring(xhci, slot_id,
+			ep_index, stream_id);
+	if (!ep_ring) {
+		xhci_warn(xhci, "WARN can't find new dequeue state "
+				"for invalid stream ID %u.\n",
+				stream_id);
+		return;
+	}
 	state->new_cycle_state = 0;
 	xhci_dbg(xhci, "Finding segment containing stopped TRB.\n");
 	state->new_deq_seg = find_trb_seg(cur_td->start_seg,
@@ -390,7 +456,7 @@
 		BUG();
 
 	trb = &state->new_deq_ptr->generic;
-	if (TRB_TYPE(trb->field[3]) == TRB_LINK &&
+	if ((trb->field[3] & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK) &&
 				(trb->field[3] & LINK_TOGGLE))
 		state->new_cycle_state = ~(state->new_cycle_state) & 0x1;
 	next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr);
@@ -448,11 +514,13 @@
 }
 
 static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
-		unsigned int ep_index, struct xhci_segment *deq_seg,
+		unsigned int ep_index, unsigned int stream_id,
+		struct xhci_segment *deq_seg,
 		union xhci_trb *deq_ptr, u32 cycle_state);
 
 void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
 		unsigned int slot_id, unsigned int ep_index,
+		unsigned int stream_id,
 		struct xhci_dequeue_state *deq_state)
 {
 	struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
@@ -464,7 +532,7 @@
 			deq_state->new_deq_ptr,
 			(unsigned long long)xhci_trb_virt_to_dma(deq_state->new_deq_seg, deq_state->new_deq_ptr),
 			deq_state->new_cycle_state);
-	queue_set_tr_deq(xhci, slot_id, ep_index,
+	queue_set_tr_deq(xhci, slot_id, ep_index, stream_id,
 			deq_state->new_deq_seg,
 			deq_state->new_deq_ptr,
 			(u32) deq_state->new_cycle_state);
@@ -523,7 +591,7 @@
 	struct xhci_ring *ep_ring;
 	struct xhci_virt_ep *ep;
 	struct list_head *entry;
-	struct xhci_td *cur_td = 0;
+	struct xhci_td *cur_td = NULL;
 	struct xhci_td *last_unlinked_td;
 
 	struct xhci_dequeue_state deq_state;
@@ -532,11 +600,10 @@
 	slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
 	ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
 	ep = &xhci->devs[slot_id]->eps[ep_index];
-	ep_ring = ep->ring;
 
 	if (list_empty(&ep->cancelled_td_list)) {
 		xhci_stop_watchdog_timer_in_irq(xhci, ep);
-		ring_ep_doorbell(xhci, slot_id, ep_index);
+		ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
 		return;
 	}
 
@@ -550,15 +617,36 @@
 		xhci_dbg(xhci, "Cancelling TD starting at %p, 0x%llx (dma).\n",
 				cur_td->first_trb,
 				(unsigned long long)xhci_trb_virt_to_dma(cur_td->start_seg, cur_td->first_trb));
+		ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb);
+		if (!ep_ring) {
+			/* This shouldn't happen unless a driver is mucking
+			 * with the stream ID after submission.  This will
+			 * leave the TD on the hardware ring, and the hardware
+			 * will try to execute it, and may access a buffer
+			 * that has already been freed.  In the best case, the
+			 * hardware will execute it, and the event handler will
+			 * ignore the completion event for that TD, since it was
+			 * removed from the td_list for that endpoint.  In
+			 * short, don't muck with the stream ID after
+			 * submission.
+			 */
+			xhci_warn(xhci, "WARN Cancelled URB %p "
+					"has invalid stream ID %u.\n",
+					cur_td->urb,
+					cur_td->urb->stream_id);
+			goto remove_finished_td;
+		}
 		/*
 		 * If we stopped on the TD we need to cancel, then we have to
 		 * move the xHC endpoint ring dequeue pointer past this TD.
 		 */
 		if (cur_td == ep->stopped_td)
-			xhci_find_new_dequeue_state(xhci, slot_id, ep_index, cur_td,
-					&deq_state);
+			xhci_find_new_dequeue_state(xhci, slot_id, ep_index,
+					cur_td->urb->stream_id,
+					cur_td, &deq_state);
 		else
 			td_to_noop(xhci, ep_ring, cur_td);
+remove_finished_td:
 		/*
 		 * The event handler won't see a completion for this TD anymore,
 		 * so remove it from the endpoint ring's TD list.  Keep it in
@@ -572,12 +660,16 @@
 	/* If necessary, queue a Set Transfer Ring Dequeue Pointer command */
 	if (deq_state.new_deq_ptr && deq_state.new_deq_seg) {
 		xhci_queue_new_dequeue_state(xhci,
-				slot_id, ep_index, &deq_state);
+				slot_id, ep_index,
+				ep->stopped_td->urb->stream_id,
+				&deq_state);
 		xhci_ring_cmd_db(xhci);
 	} else {
-		/* Otherwise just ring the doorbell to restart the ring */
-		ring_ep_doorbell(xhci, slot_id, ep_index);
+		/* Otherwise ring the doorbell(s) to restart queued transfers */
+		ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
 	}
+	ep->stopped_td = NULL;
+	ep->stopped_trb = NULL;
 
 	/*
 	 * Drop the lock and complete the URBs in the cancelled TD list.
@@ -734,6 +826,7 @@
 {
 	unsigned int slot_id;
 	unsigned int ep_index;
+	unsigned int stream_id;
 	struct xhci_ring *ep_ring;
 	struct xhci_virt_device *dev;
 	struct xhci_ep_ctx *ep_ctx;
@@ -741,8 +834,19 @@
 
 	slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
 	ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
+	stream_id = TRB_TO_STREAM_ID(trb->generic.field[2]);
 	dev = xhci->devs[slot_id];
-	ep_ring = dev->eps[ep_index].ring;
+
+	ep_ring = xhci_stream_id_to_ring(dev, ep_index, stream_id);
+	if (!ep_ring) {
+		xhci_warn(xhci, "WARN Set TR deq ptr command for "
+				"freed stream ID %u\n",
+				stream_id);
+		/* XXX: Harmless??? */
+		dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING;
+		return;
+	}
+
 	ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
 	slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx);
 
@@ -787,7 +891,8 @@
 	}
 
 	dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING;
-	ring_ep_doorbell(xhci, slot_id, ep_index);
+	/* Restart any rings with pending URBs */
+	ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
 }
 
 static void handle_reset_ep_completion(struct xhci_hcd *xhci,
@@ -796,11 +901,9 @@
 {
 	int slot_id;
 	unsigned int ep_index;
-	struct xhci_ring *ep_ring;
 
 	slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
 	ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
-	ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
 	/* This command will only fail if the endpoint wasn't halted,
 	 * but we don't care.
 	 */
@@ -818,9 +921,9 @@
 				false);
 		xhci_ring_cmd_db(xhci);
 	} else {
-		/* Clear our internal halted state and restart the ring */
+		/* Clear our internal halted state and restart the ring(s) */
 		xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED;
-		ring_ep_doorbell(xhci, slot_id, ep_index);
+		ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
 	}
 }
 
@@ -897,16 +1000,19 @@
 		 * Configure endpoint commands can come from the USB core
 		 * configuration or alt setting changes, or because the HW
 		 * needed an extra configure endpoint command after a reset
-		 * endpoint command.  In the latter case, the xHCI driver is
-		 * not waiting on the configure endpoint command.
+		 * endpoint command or streams were being configured.
+		 * If the command was for a halted endpoint, the xHCI driver
+		 * is not waiting on the configure endpoint command.
 		 */
 		ctrl_ctx = xhci_get_input_control_ctx(xhci,
 				virt_dev->in_ctx);
 		/* Input ctx add_flags are the endpoint index plus one */
 		ep_index = xhci_last_valid_endpoint(ctrl_ctx->add_flags) - 1;
 		/* A usb_set_interface() call directly after clearing a halted
-		 * condition may race on this quirky hardware.
-		 * Not worth worrying about, since this is prototype hardware.
+		 * condition may race on this quirky hardware.  Not worth
+		 * worrying about, since this is prototype hardware.  Not sure
+		 * if this will work for streams, but streams support was
+		 * untested on this prototype.
 		 */
 		if (xhci->quirks & XHCI_RESET_EP_QUIRK &&
 				ep_index != (unsigned int) -1 &&
@@ -919,10 +1025,10 @@
 			xhci_dbg(xhci, "Completed config ep cmd - "
 					"last ep index = %d, state = %d\n",
 					ep_index, ep_state);
-			/* Clear our internal halted state and restart ring */
+			/* Clear internal halted state and restart ring(s) */
 			xhci->devs[slot_id]->eps[ep_index].ep_state &=
 				~EP_HALTED;
-			ring_ep_doorbell(xhci, slot_id, ep_index);
+			ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
 			break;
 		}
 bandwidth_change:
@@ -1018,7 +1124,7 @@
 
 	do {
 		if (start_dma == 0)
-			return 0;
+			return NULL;
 		/* We may get an event for a Link TRB in the middle of a TD */
 		end_seg_dma = xhci_trb_virt_to_dma(cur_seg,
 				&cur_seg->trbs[TRBS_PER_SEGMENT - 1]);
@@ -1040,7 +1146,7 @@
 						 suspect_dma <= end_trb_dma))
 					return cur_seg;
 			}
-			return 0;
+			return NULL;
 		} else {
 			/* Might still be somewhere in this segment */
 			if (suspect_dma >= start_dma && suspect_dma <= end_seg_dma)
@@ -1050,19 +1156,27 @@
 		start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]);
 	} while (cur_seg != start_seg);
 
-	return 0;
+	return NULL;
 }
 
 static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
 		unsigned int slot_id, unsigned int ep_index,
+		unsigned int stream_id,
 		struct xhci_td *td, union xhci_trb *event_trb)
 {
 	struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
 	ep->ep_state |= EP_HALTED;
 	ep->stopped_td = td;
 	ep->stopped_trb = event_trb;
+	ep->stopped_stream = stream_id;
+
 	xhci_queue_reset_ep(xhci, slot_id, ep_index);
 	xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index);
+
+	ep->stopped_td = NULL;
+	ep->stopped_trb = NULL;
+	ep->stopped_stream = 0;
+
 	xhci_ring_cmd_db(xhci);
 }
 
@@ -1119,11 +1233,11 @@
 	struct xhci_ring *ep_ring;
 	unsigned int slot_id;
 	int ep_index;
-	struct xhci_td *td = 0;
+	struct xhci_td *td = NULL;
 	dma_addr_t event_dma;
 	struct xhci_segment *event_seg;
 	union xhci_trb *event_trb;
-	struct urb *urb = 0;
+	struct urb *urb = NULL;
 	int status = -EINPROGRESS;
 	struct xhci_ep_ctx *ep_ctx;
 	u32 trb_comp_code;
@@ -1140,10 +1254,11 @@
 	ep_index = TRB_TO_EP_ID(event->flags) - 1;
 	xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index);
 	ep = &xdev->eps[ep_index];
-	ep_ring = ep->ring;
+	ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
 	ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
 	if (!ep_ring || (ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) {
-		xhci_err(xhci, "ERROR Transfer event pointed to disabled endpoint\n");
+		xhci_err(xhci, "ERROR Transfer event for disabled endpoint "
+				"or incorrect stream ring\n");
 		return -ENODEV;
 	}
 
@@ -1274,7 +1389,7 @@
 				td->urb->actual_length = 0;
 
 			xhci_cleanup_halted_endpoint(xhci,
-					slot_id, ep_index, td, event_trb);
+					slot_id, ep_index, 0, td, event_trb);
 			goto td_cleanup;
 		}
 		/*
@@ -1390,8 +1505,10 @@
 			for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg;
 					cur_trb != event_trb;
 					next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
-				if (TRB_TYPE(cur_trb->generic.field[3]) != TRB_TR_NOOP &&
-						TRB_TYPE(cur_trb->generic.field[3]) != TRB_LINK)
+				if ((cur_trb->generic.field[3] &
+				 TRB_TYPE_BITMASK) != TRB_TYPE(TRB_TR_NOOP) &&
+				    (cur_trb->generic.field[3] &
+				 TRB_TYPE_BITMASK) != TRB_TYPE(TRB_LINK))
 					td->urb->actual_length +=
 						TRB_LEN(cur_trb->generic.field[2]);
 			}
@@ -1423,6 +1540,7 @@
 			 */
 			ep->stopped_td = td;
 			ep->stopped_trb = event_trb;
+			ep->stopped_stream = ep_ring->stream_id;
 		} else if (xhci_requires_manual_halt_cleanup(xhci,
 					ep_ctx, trb_comp_code)) {
 			/* Other types of errors halt the endpoint, but the
@@ -1431,7 +1549,7 @@
 			 * xHCI hardware manually.
 			 */
 			xhci_cleanup_halted_endpoint(xhci,
-					slot_id, ep_index, td, event_trb);
+					slot_id, ep_index, ep_ring->stream_id, td, event_trb);
 		} else {
 			/* Update ring dequeue pointer */
 			while (ep_ring->dequeue != td->last_trb)
@@ -1621,20 +1739,66 @@
 		xhci_err(xhci, "ERROR no room on ep ring\n");
 		return -ENOMEM;
 	}
+
+	if (enqueue_is_link_trb(ep_ring)) {
+		struct xhci_ring *ring = ep_ring;
+		union xhci_trb *next;
+
+		xhci_dbg(xhci, "prepare_ring: pointing to link trb\n");
+		next = ring->enqueue;
+
+		while (last_trb(xhci, ring, ring->enq_seg, next)) {
+
+			/* If we're not dealing with 0.95 hardware,
+			 * clear the chain bit.
+			 */
+			if (!xhci_link_trb_quirk(xhci))
+				next->link.control &= ~TRB_CHAIN;
+			else
+				next->link.control |= TRB_CHAIN;
+
+			wmb();
+			next->link.control ^= (u32) TRB_CYCLE;
+
+			/* Toggle the cycle bit after the last ring segment. */
+			if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
+				ring->cycle_state = (ring->cycle_state ? 0 : 1);
+				if (!in_interrupt()) {
+					xhci_dbg(xhci, "queue_trb: Toggle cycle "
+						"state for ring %p = %i\n",
+						ring, (unsigned int)ring->cycle_state);
+				}
+			}
+			ring->enq_seg = ring->enq_seg->next;
+			ring->enqueue = ring->enq_seg->trbs;
+			next = ring->enqueue;
+		}
+	}
+
 	return 0;
 }
 
 static int prepare_transfer(struct xhci_hcd *xhci,
 		struct xhci_virt_device *xdev,
 		unsigned int ep_index,
+		unsigned int stream_id,
 		unsigned int num_trbs,
 		struct urb *urb,
 		struct xhci_td **td,
 		gfp_t mem_flags)
 {
 	int ret;
+	struct xhci_ring *ep_ring;
 	struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
-	ret = prepare_ring(xhci, xdev->eps[ep_index].ring,
+
+	ep_ring = xhci_stream_id_to_ring(xdev, ep_index, stream_id);
+	if (!ep_ring) {
+		xhci_dbg(xhci, "Can't prepare ring for bad stream ID %u\n",
+				stream_id);
+		return -EINVAL;
+	}
+
+	ret = prepare_ring(xhci, ep_ring,
 			ep_ctx->ep_info & EP_STATE_MASK,
 			num_trbs, mem_flags);
 	if (ret)
@@ -1654,9 +1818,9 @@
 	(*td)->urb = urb;
 	urb->hcpriv = (void *) (*td);
 	/* Add this TD to the tail of the endpoint ring's TD list */
-	list_add_tail(&(*td)->td_list, &xdev->eps[ep_index].ring->td_list);
-	(*td)->start_seg = xdev->eps[ep_index].ring->enq_seg;
-	(*td)->first_trb = xdev->eps[ep_index].ring->enqueue;
+	list_add_tail(&(*td)->td_list, &ep_ring->td_list);
+	(*td)->start_seg = ep_ring->enq_seg;
+	(*td)->first_trb = ep_ring->enqueue;
 
 	return 0;
 }
@@ -1672,7 +1836,7 @@
 
 	xhci_dbg(xhci, "count sg list trbs: \n");
 	num_trbs = 0;
-	for_each_sg(urb->sg->sg, sg, num_sgs, i) {
+	for_each_sg(urb->sg, sg, num_sgs, i) {
 		unsigned int previous_total_trbs = num_trbs;
 		unsigned int len = sg_dma_len(sg);
 
@@ -1722,7 +1886,7 @@
 }
 
 static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
-		unsigned int ep_index, int start_cycle,
+		unsigned int ep_index, unsigned int stream_id, int start_cycle,
 		struct xhci_generic_trb *start_trb, struct xhci_td *td)
 {
 	/*
@@ -1731,7 +1895,7 @@
 	 */
 	wmb();
 	start_trb->field[3] |= start_cycle;
-	ring_ep_doorbell(xhci, slot_id, ep_index);
+	ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
 }
 
 /*
@@ -1805,12 +1969,16 @@
 	struct xhci_generic_trb *start_trb;
 	int start_cycle;
 
-	ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
+	ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
+	if (!ep_ring)
+		return -EINVAL;
+
 	num_trbs = count_sg_trbs_needed(xhci, urb);
 	num_sgs = urb->num_sgs;
 
 	trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id],
-			ep_index, num_trbs, urb, &td, mem_flags);
+			ep_index, urb->stream_id,
+			num_trbs, urb, &td, mem_flags);
 	if (trb_buff_len < 0)
 		return trb_buff_len;
 	/*
@@ -1831,7 +1999,7 @@
 	 *    the amount of memory allocated for this scatter-gather list.
 	 * 3. TRBs buffers can't cross 64KB boundaries.
 	 */
-	sg = urb->sg->sg;
+	sg = urb->sg;
 	addr = (u64) sg_dma_address(sg);
 	this_sg_len = sg_dma_len(sg);
 	trb_buff_len = TRB_MAX_BUFF_SIZE -
@@ -1919,7 +2087,8 @@
 	} while (running_total < urb->transfer_buffer_length);
 
 	check_trb_math(urb, num_trbs, running_total);
-	giveback_first_trb(xhci, slot_id, ep_index, start_cycle, start_trb, td);
+	giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
+			start_cycle, start_trb, td);
 	return 0;
 }
 
@@ -1938,10 +2107,12 @@
 	int running_total, trb_buff_len, ret;
 	u64 addr;
 
-	if (urb->sg)
+	if (urb->num_sgs)
 		return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index);
 
-	ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
+	ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
+	if (!ep_ring)
+		return -EINVAL;
 
 	num_trbs = 0;
 	/* How much data is (potentially) left before the 64KB boundary? */
@@ -1968,7 +2139,8 @@
 				(unsigned long long)urb->transfer_dma,
 				num_trbs);
 
-	ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
+	ret = prepare_transfer(xhci, xhci->devs[slot_id],
+			ep_index, urb->stream_id,
 			num_trbs, urb, &td, mem_flags);
 	if (ret < 0)
 		return ret;
@@ -2038,7 +2210,8 @@
 	} while (running_total < urb->transfer_buffer_length);
 
 	check_trb_math(urb, num_trbs, running_total);
-	giveback_first_trb(xhci, slot_id, ep_index, start_cycle, start_trb, td);
+	giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
+			start_cycle, start_trb, td);
 	return 0;
 }
 
@@ -2055,7 +2228,9 @@
 	u32 field, length_field;
 	struct xhci_td *td;
 
-	ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
+	ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
+	if (!ep_ring)
+		return -EINVAL;
 
 	/*
 	 * Need to copy setup packet into setup TRB, so we can't use the setup
@@ -2076,8 +2251,9 @@
 	 */
 	if (urb->transfer_buffer_length > 0)
 		num_trbs++;
-	ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, num_trbs,
-			urb, &td, mem_flags);
+	ret = prepare_transfer(xhci, xhci->devs[slot_id],
+			ep_index, urb->stream_id,
+			num_trbs, urb, &td, mem_flags);
 	if (ret < 0)
 		return ret;
 
@@ -2132,7 +2308,8 @@
 			/* Event on completion */
 			field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state);
 
-	giveback_first_trb(xhci, slot_id, ep_index, start_cycle, start_trb, td);
+	giveback_first_trb(xhci, slot_id, ep_index, 0,
+			start_cycle, start_trb, td);
 	return 0;
 }
 
@@ -2244,12 +2421,14 @@
  * This should not be used for endpoints that have streams enabled.
  */
 static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
-		unsigned int ep_index, struct xhci_segment *deq_seg,
+		unsigned int ep_index, unsigned int stream_id,
+		struct xhci_segment *deq_seg,
 		union xhci_trb *deq_ptr, u32 cycle_state)
 {
 	dma_addr_t addr;
 	u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
 	u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
+	u32 trb_stream_id = STREAM_ID_FOR_TRB(stream_id);
 	u32 type = TRB_TYPE(TRB_SET_DEQ);
 
 	addr = xhci_trb_virt_to_dma(deq_seg, deq_ptr);
@@ -2260,7 +2439,7 @@
 		return 0;
 	}
 	return queue_command(xhci, lower_32_bits(addr) | cycle_state,
-			upper_32_bits(addr), 0,
+			upper_32_bits(addr), trb_stream_id,
 			trb_slot_id | trb_ep_index | type, false);
 }
 
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 7e42772..40e0a0c 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -21,6 +21,7 @@
  */
 
 #include <linux/irq.h>
+#include <linux/log2.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/slab.h>
@@ -352,11 +353,7 @@
 		if (!xhci->devs[i])
 			continue;
 		for (j = 0; j < 31; ++j) {
-			struct xhci_ring *ring = xhci->devs[i]->eps[j].ring;
-			if (!ring)
-				continue;
-			xhci_dbg(xhci, "Dev %d endpoint ring %d:\n", i, j);
-			xhci_debug_segment(xhci, ring->deq_seg);
+			xhci_dbg_ep_rings(xhci, i, j, &xhci->devs[i]->eps[j]);
 		}
 	}
 
@@ -726,8 +723,21 @@
 		spin_lock_irqsave(&xhci->lock, flags);
 		if (xhci->xhc_state & XHCI_STATE_DYING)
 			goto dying;
-		ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
-				slot_id, ep_index);
+		if (xhci->devs[slot_id]->eps[ep_index].ep_state &
+				EP_GETTING_STREAMS) {
+			xhci_warn(xhci, "WARN: Can't enqueue URB while bulk ep "
+					"is transitioning to using streams.\n");
+			ret = -EINVAL;
+		} else if (xhci->devs[slot_id]->eps[ep_index].ep_state &
+				EP_GETTING_NO_STREAMS) {
+			xhci_warn(xhci, "WARN: Can't enqueue URB while bulk ep "
+					"is transitioning to "
+					"not having streams.\n");
+			ret = -EINVAL;
+		} else {
+			ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
+					slot_id, ep_index);
+		}
 		spin_unlock_irqrestore(&xhci->lock, flags);
 	} else if (usb_endpoint_xfer_int(&urb->ep->desc)) {
 		spin_lock_irqsave(&xhci->lock, flags);
@@ -825,7 +835,12 @@
 	xhci_debug_ring(xhci, xhci->event_ring);
 	ep_index = xhci_get_endpoint_index(&urb->ep->desc);
 	ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];
-	ep_ring = ep->ring;
+	ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
+	if (!ep_ring) {
+		ret = -EINVAL;
+		goto done;
+	}
+
 	xhci_dbg(xhci, "Endpoint ring:\n");
 	xhci_debug_ring(xhci, ep_ring);
 	td = (struct xhci_td *) urb->hcpriv;
@@ -1369,7 +1384,7 @@
 	 * or it will attempt to resend it on the next doorbell ring.
 	 */
 	xhci_find_new_dequeue_state(xhci, udev->slot_id,
-			ep_index, ep->stopped_td,
+			ep_index, ep->stopped_stream, ep->stopped_td,
 			&deq_state);
 
 	/* HW with the reset endpoint quirk will use the saved dequeue state to
@@ -1378,10 +1393,12 @@
 	if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) {
 		xhci_dbg(xhci, "Queueing new dequeue state\n");
 		xhci_queue_new_dequeue_state(xhci, udev->slot_id,
-				ep_index, &deq_state);
+				ep_index, ep->stopped_stream, &deq_state);
 	} else {
 		/* Better hope no one uses the input context between now and the
 		 * reset endpoint completion!
+		 * XXX: No idea how this hardware will react when stream rings
+		 * are enabled.
 		 */
 		xhci_dbg(xhci, "Setting up input context for "
 				"configure endpoint command\n");
@@ -1438,12 +1455,391 @@
 		kfree(virt_ep->stopped_td);
 		xhci_ring_cmd_db(xhci);
 	}
+	virt_ep->stopped_td = NULL;
+	virt_ep->stopped_trb = NULL;
+	virt_ep->stopped_stream = 0;
 	spin_unlock_irqrestore(&xhci->lock, flags);
 
 	if (ret)
 		xhci_warn(xhci, "FIXME allocate a new ring segment\n");
 }
 
+static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,
+		struct usb_device *udev, struct usb_host_endpoint *ep,
+		unsigned int slot_id)
+{
+	int ret;
+	unsigned int ep_index;
+	unsigned int ep_state;
+
+	if (!ep)
+		return -EINVAL;
+	ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, __func__);
+	if (ret <= 0)
+		return -EINVAL;
+	if (ep->ss_ep_comp.bmAttributes == 0) {
+		xhci_warn(xhci, "WARN: SuperSpeed Endpoint Companion"
+				" descriptor for ep 0x%x does not support streams\n",
+				ep->desc.bEndpointAddress);
+		return -EINVAL;
+	}
+
+	ep_index = xhci_get_endpoint_index(&ep->desc);
+	ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state;
+	if (ep_state & EP_HAS_STREAMS ||
+			ep_state & EP_GETTING_STREAMS) {
+		xhci_warn(xhci, "WARN: SuperSpeed bulk endpoint 0x%x "
+				"already has streams set up.\n",
+				ep->desc.bEndpointAddress);
+		xhci_warn(xhci, "Send email to xHCI maintainer and ask for "
+				"dynamic stream context array reallocation.\n");
+		return -EINVAL;
+	}
+	if (!list_empty(&xhci->devs[slot_id]->eps[ep_index].ring->td_list)) {
+		xhci_warn(xhci, "Cannot setup streams for SuperSpeed bulk "
+				"endpoint 0x%x; URBs are pending.\n",
+				ep->desc.bEndpointAddress);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void xhci_calculate_streams_entries(struct xhci_hcd *xhci,
+		unsigned int *num_streams, unsigned int *num_stream_ctxs)
+{
+	unsigned int max_streams;
+
+	/* The stream context array size must be a power of two */
+	*num_stream_ctxs = roundup_pow_of_two(*num_streams);
+	/*
+	 * Find out how many primary stream array entries the host controller
+	 * supports.  Later we may use secondary stream arrays (similar to 2nd
+	 * level page entries), but that's an optional feature for xHCI host
+	 * controllers. xHCs must support at least 4 stream IDs.
+	 */
+	max_streams = HCC_MAX_PSA(xhci->hcc_params);
+	if (*num_stream_ctxs > max_streams) {
+		xhci_dbg(xhci, "xHCI HW only supports %u stream ctx entries.\n",
+				max_streams);
+		*num_stream_ctxs = max_streams;
+		*num_streams = max_streams;
+	}
+}
+
+/* Returns an error code if one of the endpoint already has streams.
+ * This does not change any data structures, it only checks and gathers
+ * information.
+ */
+static int xhci_calculate_streams_and_bitmask(struct xhci_hcd *xhci,
+		struct usb_device *udev,
+		struct usb_host_endpoint **eps, unsigned int num_eps,
+		unsigned int *num_streams, u32 *changed_ep_bitmask)
+{
+	unsigned int max_streams;
+	unsigned int endpoint_flag;
+	int i;
+	int ret;
+
+	for (i = 0; i < num_eps; i++) {
+		ret = xhci_check_streams_endpoint(xhci, udev,
+				eps[i], udev->slot_id);
+		if (ret < 0)
+			return ret;
+
+		max_streams = USB_SS_MAX_STREAMS(
+				eps[i]->ss_ep_comp.bmAttributes);
+		if (max_streams < (*num_streams - 1)) {
+			xhci_dbg(xhci, "Ep 0x%x only supports %u stream IDs.\n",
+					eps[i]->desc.bEndpointAddress,
+					max_streams);
+			*num_streams = max_streams+1;
+		}
+
+		endpoint_flag = xhci_get_endpoint_flag(&eps[i]->desc);
+		if (*changed_ep_bitmask & endpoint_flag)
+			return -EINVAL;
+		*changed_ep_bitmask |= endpoint_flag;
+	}
+	return 0;
+}
+
+static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci,
+		struct usb_device *udev,
+		struct usb_host_endpoint **eps, unsigned int num_eps)
+{
+	u32 changed_ep_bitmask = 0;
+	unsigned int slot_id;
+	unsigned int ep_index;
+	unsigned int ep_state;
+	int i;
+
+	slot_id = udev->slot_id;
+	if (!xhci->devs[slot_id])
+		return 0;
+
+	for (i = 0; i < num_eps; i++) {
+		ep_index = xhci_get_endpoint_index(&eps[i]->desc);
+		ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state;
+		/* Are streams already being freed for the endpoint? */
+		if (ep_state & EP_GETTING_NO_STREAMS) {
+			xhci_warn(xhci, "WARN Can't disable streams for "
+					"endpoint 0x%x\n, "
+					"streams are being disabled already.",
+					eps[i]->desc.bEndpointAddress);
+			return 0;
+		}
+		/* Are there actually any streams to free? */
+		if (!(ep_state & EP_HAS_STREAMS) &&
+				!(ep_state & EP_GETTING_STREAMS)) {
+			xhci_warn(xhci, "WARN Can't disable streams for "
+					"endpoint 0x%x\n, "
+					"streams are already disabled!",
+					eps[i]->desc.bEndpointAddress);
+			xhci_warn(xhci, "WARN xhci_free_streams() called "
+					"with non-streams endpoint\n");
+			return 0;
+		}
+		changed_ep_bitmask |= xhci_get_endpoint_flag(&eps[i]->desc);
+	}
+	return changed_ep_bitmask;
+}
+
+/*
+ * The USB device drivers use this function (though the HCD interface in USB
+ * core) to prepare a set of bulk endpoints to use streams.  Streams are used to
+ * coordinate mass storage command queueing across multiple endpoints (basically
+ * a stream ID == a task ID).
+ *
+ * Setting up streams involves allocating the same size stream context array
+ * for each endpoint and issuing a configure endpoint command for all endpoints.
+ *
+ * Don't allow the call to succeed if one endpoint only supports one stream
+ * (which means it doesn't support streams at all).
+ *
+ * Drivers may get less stream IDs than they asked for, if the host controller
+ * hardware or endpoints claim they can't support the number of requested
+ * stream IDs.
+ */
+int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
+		struct usb_host_endpoint **eps, unsigned int num_eps,
+		unsigned int num_streams, gfp_t mem_flags)
+{
+	int i, ret;
+	struct xhci_hcd *xhci;
+	struct xhci_virt_device *vdev;
+	struct xhci_command *config_cmd;
+	unsigned int ep_index;
+	unsigned int num_stream_ctxs;
+	unsigned long flags;
+	u32 changed_ep_bitmask = 0;
+
+	if (!eps)
+		return -EINVAL;
+
+	/* Add one to the number of streams requested to account for
+	 * stream 0 that is reserved for xHCI usage.
+	 */
+	num_streams += 1;
+	xhci = hcd_to_xhci(hcd);
+	xhci_dbg(xhci, "Driver wants %u stream IDs (including stream 0).\n",
+			num_streams);
+
+	config_cmd = xhci_alloc_command(xhci, true, true, mem_flags);
+	if (!config_cmd) {
+		xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
+		return -ENOMEM;
+	}
+
+	/* Check to make sure all endpoints are not already configured for
+	 * streams.  While we're at it, find the maximum number of streams that
+	 * all the endpoints will support and check for duplicate endpoints.
+	 */
+	spin_lock_irqsave(&xhci->lock, flags);
+	ret = xhci_calculate_streams_and_bitmask(xhci, udev, eps,
+			num_eps, &num_streams, &changed_ep_bitmask);
+	if (ret < 0) {
+		xhci_free_command(xhci, config_cmd);
+		spin_unlock_irqrestore(&xhci->lock, flags);
+		return ret;
+	}
+	if (num_streams <= 1) {
+		xhci_warn(xhci, "WARN: endpoints can't handle "
+				"more than one stream.\n");
+		xhci_free_command(xhci, config_cmd);
+		spin_unlock_irqrestore(&xhci->lock, flags);
+		return -EINVAL;
+	}
+	vdev = xhci->devs[udev->slot_id];
+	/* Mark each endpoint as being in transistion, so
+	 * xhci_urb_enqueue() will reject all URBs.
+	 */
+	for (i = 0; i < num_eps; i++) {
+		ep_index = xhci_get_endpoint_index(&eps[i]->desc);
+		vdev->eps[ep_index].ep_state |= EP_GETTING_STREAMS;
+	}
+	spin_unlock_irqrestore(&xhci->lock, flags);
+
+	/* Setup internal data structures and allocate HW data structures for
+	 * streams (but don't install the HW structures in the input context
+	 * until we're sure all memory allocation succeeded).
+	 */
+	xhci_calculate_streams_entries(xhci, &num_streams, &num_stream_ctxs);
+	xhci_dbg(xhci, "Need %u stream ctx entries for %u stream IDs.\n",
+			num_stream_ctxs, num_streams);
+
+	for (i = 0; i < num_eps; i++) {
+		ep_index = xhci_get_endpoint_index(&eps[i]->desc);
+		vdev->eps[ep_index].stream_info = xhci_alloc_stream_info(xhci,
+				num_stream_ctxs,
+				num_streams, mem_flags);
+		if (!vdev->eps[ep_index].stream_info)
+			goto cleanup;
+		/* Set maxPstreams in endpoint context and update deq ptr to
+		 * point to stream context array. FIXME
+		 */
+	}
+
+	/* Set up the input context for a configure endpoint command. */
+	for (i = 0; i < num_eps; i++) {
+		struct xhci_ep_ctx *ep_ctx;
+
+		ep_index = xhci_get_endpoint_index(&eps[i]->desc);
+		ep_ctx = xhci_get_ep_ctx(xhci, config_cmd->in_ctx, ep_index);
+
+		xhci_endpoint_copy(xhci, config_cmd->in_ctx,
+				vdev->out_ctx, ep_index);
+		xhci_setup_streams_ep_input_ctx(xhci, ep_ctx,
+				vdev->eps[ep_index].stream_info);
+	}
+	/* Tell the HW to drop its old copy of the endpoint context info
+	 * and add the updated copy from the input context.
+	 */
+	xhci_setup_input_ctx_for_config_ep(xhci, config_cmd->in_ctx,
+			vdev->out_ctx, changed_ep_bitmask, changed_ep_bitmask);
+
+	/* Issue and wait for the configure endpoint command */
+	ret = xhci_configure_endpoint(xhci, udev, config_cmd,
+			false, false);
+
+	/* xHC rejected the configure endpoint command for some reason, so we
+	 * leave the old ring intact and free our internal streams data
+	 * structure.
+	 */
+	if (ret < 0)
+		goto cleanup;
+
+	spin_lock_irqsave(&xhci->lock, flags);
+	for (i = 0; i < num_eps; i++) {
+		ep_index = xhci_get_endpoint_index(&eps[i]->desc);
+		vdev->eps[ep_index].ep_state &= ~EP_GETTING_STREAMS;
+		xhci_dbg(xhci, "Slot %u ep ctx %u now has streams.\n",
+			 udev->slot_id, ep_index);
+		vdev->eps[ep_index].ep_state |= EP_HAS_STREAMS;
+	}
+	xhci_free_command(xhci, config_cmd);
+	spin_unlock_irqrestore(&xhci->lock, flags);
+
+	/* Subtract 1 for stream 0, which drivers can't use */
+	return num_streams - 1;
+
+cleanup:
+	/* If it didn't work, free the streams! */
+	for (i = 0; i < num_eps; i++) {
+		ep_index = xhci_get_endpoint_index(&eps[i]->desc);
+		xhci_free_stream_info(xhci, vdev->eps[ep_index].stream_info);
+		vdev->eps[ep_index].stream_info = NULL;
+		/* FIXME Unset maxPstreams in endpoint context and
+		 * update deq ptr to point to normal string ring.
+		 */
+		vdev->eps[ep_index].ep_state &= ~EP_GETTING_STREAMS;
+		vdev->eps[ep_index].ep_state &= ~EP_HAS_STREAMS;
+		xhci_endpoint_zero(xhci, vdev, eps[i]);
+	}
+	xhci_free_command(xhci, config_cmd);
+	return -ENOMEM;
+}
+
+/* Transition the endpoint from using streams to being a "normal" endpoint
+ * without streams.
+ *
+ * Modify the endpoint context state, submit a configure endpoint command,
+ * and free all endpoint rings for streams if that completes successfully.
+ */
+int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
+		struct usb_host_endpoint **eps, unsigned int num_eps,
+		gfp_t mem_flags)
+{
+	int i, ret;
+	struct xhci_hcd *xhci;
+	struct xhci_virt_device *vdev;
+	struct xhci_command *command;
+	unsigned int ep_index;
+	unsigned long flags;
+	u32 changed_ep_bitmask;
+
+	xhci = hcd_to_xhci(hcd);
+	vdev = xhci->devs[udev->slot_id];
+
+	/* Set up a configure endpoint command to remove the streams rings */
+	spin_lock_irqsave(&xhci->lock, flags);
+	changed_ep_bitmask = xhci_calculate_no_streams_bitmask(xhci,
+			udev, eps, num_eps);
+	if (changed_ep_bitmask == 0) {
+		spin_unlock_irqrestore(&xhci->lock, flags);
+		return -EINVAL;
+	}
+
+	/* Use the xhci_command structure from the first endpoint.  We may have
+	 * allocated too many, but the driver may call xhci_free_streams() for
+	 * each endpoint it grouped into one call to xhci_alloc_streams().
+	 */
+	ep_index = xhci_get_endpoint_index(&eps[0]->desc);
+	command = vdev->eps[ep_index].stream_info->free_streams_command;
+	for (i = 0; i < num_eps; i++) {
+		struct xhci_ep_ctx *ep_ctx;
+
+		ep_index = xhci_get_endpoint_index(&eps[i]->desc);
+		ep_ctx = xhci_get_ep_ctx(xhci, command->in_ctx, ep_index);
+		xhci->devs[udev->slot_id]->eps[ep_index].ep_state |=
+			EP_GETTING_NO_STREAMS;
+
+		xhci_endpoint_copy(xhci, command->in_ctx,
+				vdev->out_ctx, ep_index);
+		xhci_setup_no_streams_ep_input_ctx(xhci, ep_ctx,
+				&vdev->eps[ep_index]);
+	}
+	xhci_setup_input_ctx_for_config_ep(xhci, command->in_ctx,
+			vdev->out_ctx, changed_ep_bitmask, changed_ep_bitmask);
+	spin_unlock_irqrestore(&xhci->lock, flags);
+
+	/* Issue and wait for the configure endpoint command,
+	 * which must succeed.
+	 */
+	ret = xhci_configure_endpoint(xhci, udev, command,
+			false, true);
+
+	/* xHC rejected the configure endpoint command for some reason, so we
+	 * leave the streams rings intact.
+	 */
+	if (ret < 0)
+		return ret;
+
+	spin_lock_irqsave(&xhci->lock, flags);
+	for (i = 0; i < num_eps; i++) {
+		ep_index = xhci_get_endpoint_index(&eps[i]->desc);
+		xhci_free_stream_info(xhci, vdev->eps[ep_index].stream_info);
+		vdev->eps[ep_index].stream_info = NULL;
+		/* FIXME Unset maxPstreams in endpoint context and
+		 * update deq ptr to point to normal string ring.
+		 */
+		vdev->eps[ep_index].ep_state &= ~EP_GETTING_NO_STREAMS;
+		vdev->eps[ep_index].ep_state &= ~EP_HAS_STREAMS;
+	}
+	spin_unlock_irqrestore(&xhci->lock, flags);
+
+	return 0;
+}
+
 /*
  * This submits a Reset Device Command, which will set the device state to 0,
  * set the device address to 0, and disable all the endpoints except the default
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index ea389e9..dada2fb 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -26,8 +26,8 @@
 #include <linux/usb.h>
 #include <linux/timer.h>
 #include <linux/kernel.h>
+#include <linux/usb/hcd.h>
 
-#include "../core/hcd.h"
 /* Code sharing between pci-quirks and xhci hcd */
 #include	"xhci-ext-caps.h"
 
@@ -117,7 +117,7 @@
 /* true: no secondary Stream ID Support */
 #define HCC_NSS(p)		((p) & (1 << 7))
 /* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */
-#define HCC_MAX_PSA		(1 << ((((p) >> 12) & 0xf) + 1))
+#define HCC_MAX_PSA(p)		(1 << ((((p) >> 12) & 0xf) + 1))
 /* Extended Capabilities pointer from PCI base - section 5.3.6 */
 #define HCC_EXT_CAPS(p)		XHCI_HCC_EXT_CAPS(p)
 
@@ -444,6 +444,7 @@
 
 /* Endpoint Target - bits 0:7 */
 #define EPI_TO_DB(p)		(((p) + 1) & 0xff)
+#define STREAM_ID_TO_DB(p)	(((p) & 0xffff) << 16)
 
 
 /**
@@ -585,6 +586,10 @@
 /* Interval - period between requests to an endpoint - 125u increments. */
 #define EP_INTERVAL(p)		((p & 0xff) << 16)
 #define EP_INTERVAL_TO_UFRAMES(p)		(1 << (((p) >> 16) & 0xff))
+#define EP_MAXPSTREAMS_MASK	(0x1f << 10)
+#define EP_MAXPSTREAMS(p)	(((p) << 10) & EP_MAXPSTREAMS_MASK)
+/* Endpoint is set up with a Linear Stream Array (vs. Secondary Stream Array) */
+#define	EP_HAS_LSA		(1 << 15)
 
 /* ep_info2 bitmasks */
 /*
@@ -648,8 +653,50 @@
 /* add context bitmasks */
 #define	ADD_EP(x)	(0x1 << x)
 
+struct xhci_stream_ctx {
+	/* 64-bit stream ring address, cycle state, and stream type */
+	u64	stream_ring;
+	/* offset 0x14 - 0x1f reserved for HC internal use */
+	u32	reserved[2];
+};
+
+/* Stream Context Types (section 6.4.1) - bits 3:1 of stream ctx deq ptr */
+#define	SCT_FOR_CTX(p)		(((p) << 1) & 0x7)
+/* Secondary stream array type, dequeue pointer is to a transfer ring */
+#define	SCT_SEC_TR		0
+/* Primary stream array type, dequeue pointer is to a transfer ring */
+#define	SCT_PRI_TR		1
+/* Dequeue pointer is for a secondary stream array (SSA) with 8 entries */
+#define SCT_SSA_8		2
+#define SCT_SSA_16		3
+#define SCT_SSA_32		4
+#define SCT_SSA_64		5
+#define SCT_SSA_128		6
+#define SCT_SSA_256		7
+
+/* Assume no secondary streams for now */
+struct xhci_stream_info {
+	struct xhci_ring		**stream_rings;
+	/* Number of streams, including stream 0 (which drivers can't use) */
+	unsigned int			num_streams;
+	/* The stream context array may be bigger than
+	 * the number of streams the driver asked for
+	 */
+	struct xhci_stream_ctx		*stream_ctx_array;
+	unsigned int			num_stream_ctxs;
+	dma_addr_t			ctx_array_dma;
+	/* For mapping physical TRB addresses to segments in stream rings */
+	struct radix_tree_root		trb_address_map;
+	struct xhci_command		*free_streams_command;
+};
+
+#define	SMALL_STREAM_ARRAY_SIZE		256
+#define	MEDIUM_STREAM_ARRAY_SIZE	1024
+
 struct xhci_virt_ep {
 	struct xhci_ring		*ring;
+	/* Related to endpoints that are configured to use stream IDs only */
+	struct xhci_stream_info		*stream_info;
 	/* Temporary storage in case the configure endpoint command fails and we
 	 * have to restore the device state to the previous state
 	 */
@@ -658,11 +705,17 @@
 #define SET_DEQ_PENDING		(1 << 0)
 #define EP_HALTED		(1 << 1)	/* For stall handling */
 #define EP_HALT_PENDING		(1 << 2)	/* For URB cancellation */
+/* Transitioning the endpoint to using streams, don't enqueue URBs */
+#define EP_GETTING_STREAMS	(1 << 3)
+#define EP_HAS_STREAMS		(1 << 4)
+/* Transitioning the endpoint to not using streams, don't enqueue URBs */
+#define EP_GETTING_NO_STREAMS	(1 << 5)
 	/* ----  Related to URB cancellation ---- */
 	struct list_head	cancelled_td_list;
 	/* The TRB that was last reported in a stopped endpoint ring */
 	union xhci_trb		*stopped_trb;
 	struct xhci_td		*stopped_td;
+	unsigned int		stopped_stream;
 	/* Watchdog timer for stop endpoint command to cancel URBs */
 	struct timer_list	stop_cmd_timer;
 	int			stop_cmds_pending;
@@ -710,14 +763,6 @@
  */
 
 
-struct xhci_stream_ctx {
-	/* 64-bit stream ring address, cycle state, and stream type */
-	u64	stream_ring;
-	/* offset 0x14 - 0x1f reserved for HC internal use */
-	u32	reserved[2];
-};
-
-
 struct xhci_transfer_event {
 	/* 64-bit buffer address, or immediate data */
 	u64	buffer;
@@ -828,6 +873,10 @@
 #define TRB_TO_EP_INDEX(p)		((((p) & (0x1f << 16)) >> 16) - 1)
 #define	EP_ID_FOR_TRB(p)		((((p) + 1) & 0x1f) << 16)
 
+/* Set TR Dequeue Pointer command TRB fields */
+#define TRB_TO_STREAM_ID(p)		((((p) & (0xffff << 16)) >> 16))
+#define STREAM_ID_FOR_TRB(p)		((((p)) & 0xffff) << 16)
+
 
 /* Port Status Change Event TRB fields */
 /* Port ID - bits 31:24 */
@@ -952,6 +1001,10 @@
 /* Allow two commands + a link TRB, along with any reserved command TRBs */
 #define MAX_RSVD_CMD_TRBS	(TRBS_PER_SEGMENT - 3)
 #define SEGMENT_SIZE		(TRBS_PER_SEGMENT*16)
+/* SEGMENT_SHIFT should be log2(SEGMENT_SIZE).
+ * Change this if you change TRBS_PER_SEGMENT!
+ */
+#define SEGMENT_SHIFT		10
 /* TRB buffer pointers can't cross 64KB boundaries */
 #define TRB_MAX_BUFF_SHIFT		16
 #define TRB_MAX_BUFF_SIZE	(1 << TRB_MAX_BUFF_SHIFT)
@@ -993,6 +1046,7 @@
 	 * if we own the TRB (if we are the consumer).  See section 4.9.1.
 	 */
 	u32			cycle_state;
+	unsigned int		stream_id;
 };
 
 struct xhci_erst_entry {
@@ -1088,6 +1142,8 @@
 	/* DMA pools */
 	struct dma_pool	*device_pool;
 	struct dma_pool	*segment_pool;
+	struct dma_pool	*small_streams_pool;
+	struct dma_pool	*medium_streams_pool;
 
 #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
 	/* Poll the rings - for debugging */
@@ -1216,6 +1272,9 @@
 void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep);
 char *xhci_get_slot_state(struct xhci_hcd *xhci,
 		struct xhci_container_ctx *ctx);
+void xhci_dbg_ep_rings(struct xhci_hcd *xhci,
+		unsigned int slot_id, unsigned int ep_index,
+		struct xhci_virt_ep *ep);
 
 /* xHCI memory management */
 void xhci_mem_cleanup(struct xhci_hcd *xhci);
@@ -1242,6 +1301,29 @@
 void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
 		struct xhci_virt_device *virt_dev,
 		unsigned int ep_index);
+struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
+		unsigned int num_stream_ctxs,
+		unsigned int num_streams, gfp_t flags);
+void xhci_free_stream_info(struct xhci_hcd *xhci,
+		struct xhci_stream_info *stream_info);
+void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
+		struct xhci_ep_ctx *ep_ctx,
+		struct xhci_stream_info *stream_info);
+void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
+		struct xhci_ep_ctx *ep_ctx,
+		struct xhci_virt_ep *ep);
+struct xhci_ring *xhci_dma_to_transfer_ring(
+		struct xhci_virt_ep *ep,
+		u64 address);
+struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
+		struct urb *urb);
+struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
+		unsigned int slot_id, unsigned int ep_index,
+		unsigned int stream_id);
+struct xhci_ring *xhci_stream_id_to_ring(
+		struct xhci_virt_device *dev,
+		unsigned int ep_index,
+		unsigned int stream_id);
 struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
 		bool allocate_in_ctx, bool allocate_completion,
 		gfp_t mem_flags);
@@ -1266,6 +1348,12 @@
 irqreturn_t xhci_irq(struct usb_hcd *hcd);
 int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev);
 void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev);
+int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
+		struct usb_host_endpoint **eps, unsigned int num_eps,
+		unsigned int num_streams, gfp_t mem_flags);
+int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
+		struct usb_host_endpoint **eps, unsigned int num_eps,
+		gfp_t mem_flags);
 int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev);
 int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
 			struct usb_tt *tt, gfp_t mem_flags);
@@ -1308,9 +1396,11 @@
 int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id);
 void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
 		unsigned int slot_id, unsigned int ep_index,
-		struct xhci_td *cur_td, struct xhci_dequeue_state *state);
+		unsigned int stream_id, struct xhci_td *cur_td,
+		struct xhci_dequeue_state *state);
 void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
 		unsigned int slot_id, unsigned int ep_index,
+		unsigned int stream_id,
 		struct xhci_dequeue_state *deq_state);
 void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
 		struct usb_device *udev, unsigned int ep_index);
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index 094f91c..1fa6ce3 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -259,7 +259,7 @@
 	}
 
 	/* Allocate buffer for interrupt data */
-	pdata->urbdata = usb_buffer_alloc(pdata->udev, ACD_URB_BUFFER_LEN,
+	pdata->urbdata = usb_alloc_coherent(pdata->udev, ACD_URB_BUFFER_LEN,
 		GFP_KERNEL, &pdata->urb->transfer_dma);
 	if (!pdata->urbdata) {
 		retval = -ENOMEM;
@@ -316,7 +316,7 @@
 		if (pdata->urb) {
 			usb_kill_urb(pdata->urb);
 			if (pdata->urbdata)
-				usb_buffer_free(pdata->udev, ACD_URB_BUFFER_LEN,
+				usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN,
 					pdata->urbdata, pdata->urb->transfer_dma);
 			usb_free_urb(pdata->urb);
 		}
@@ -337,7 +337,7 @@
 		usb_kill_urb(pdata->urb);
 		cancel_delayed_work(&pdata->work);
 		backlight_device_unregister(pdata->bd);
-		usb_buffer_free(pdata->udev, ACD_URB_BUFFER_LEN,
+		usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN,
 			pdata->urbdata, pdata->urb->transfer_dma);
 		usb_free_urb(pdata->urb);
 		kfree(pdata->msgdata);
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 1edb6d3..82e1663 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -73,7 +73,7 @@
 */
 #include "usb_u132.h"
 #include <asm/io.h>
-#include "../core/hcd.h"
+#include <linux/usb/hcd.h>
 
 	/* FIXME ohci.h is ONLY for internal use by the OHCI driver.
 	 * If you're going to try stuff like this, you need to split
@@ -734,7 +734,7 @@
                 dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %"
                         "d\n", urb, status);
         }
-        usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+        usb_free_coherent(urb->dev, urb->transfer_buffer_length,
                 urb->transfer_buffer, urb->transfer_dma);
 }
 
@@ -795,7 +795,7 @@
                         total_size);
                 return -ENOMEM;
         }
-        buf = usb_buffer_alloc(ftdi->udev, total_size, GFP_KERNEL,
+        buf = usb_alloc_coherent(ftdi->udev, total_size, GFP_KERNEL,
                 &urb->transfer_dma);
         if (!buf) {
                 dev_err(&ftdi->udev->dev, "could not get a buffer to write %d c"
@@ -829,7 +829,7 @@
                 dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write "
                         "%d commands totaling %d bytes to the Uxxx\n", retval,
                         urb, command_size, total_size);
-                usb_buffer_free(ftdi->udev, total_size, buf, urb->transfer_dma);
+                usb_free_coherent(ftdi->udev, total_size, buf, urb->transfer_dma);
                 usb_free_urb(urb);
                 return retval;
         }
@@ -1167,7 +1167,7 @@
                 retval = -ENOMEM;
                 goto error_1;
         }
-        buf = usb_buffer_alloc(ftdi->udev, count, GFP_KERNEL,
+        buf = usb_alloc_coherent(ftdi->udev, count, GFP_KERNEL,
                 &urb->transfer_dma);
         if (!buf) {
                 retval = -ENOMEM;
@@ -1192,7 +1192,7 @@
 exit:
         return count;
 error_3:
-	usb_buffer_free(ftdi->udev, count, buf, urb->transfer_dma);
+	usb_free_coherent(ftdi->udev, count, buf, urb->transfer_dma);
 error_2:
 	usb_free_urb(urb);
 error_1:
@@ -1968,7 +1968,7 @@
                         "ence\n");
                 return -ENOMEM;
         }
-        buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
+        buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
         if (!buf) {
                 dev_err(&ftdi->udev->dev, "could not get a buffer for flush seq"
                         "uence\n");
@@ -1985,7 +1985,7 @@
         if (retval) {
                 dev_err(&ftdi->udev->dev, "failed to submit urb containing the "
                         "flush sequence\n");
-                usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma);
+                usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma);
                 usb_free_urb(urb);
                 return -ENOMEM;
         }
@@ -2011,7 +2011,7 @@
                         "quence\n");
                 return -ENOMEM;
         }
-        buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
+        buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
         if (!buf) {
                 dev_err(&ftdi->udev->dev, "could not get a buffer for the reset"
                         " sequence\n");
@@ -2030,7 +2030,7 @@
         if (retval) {
                 dev_err(&ftdi->udev->dev, "failed to submit urb containing the "
                         "reset sequence\n");
-                usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma);
+                usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma);
                 usb_free_urb(urb);
                 return -ENOMEM;
         }
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index d3c8523..7dc9d3c 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -239,8 +239,8 @@
 		    __func__, status);
 	}
 	/* free up our allocated buffer */
-	usb_buffer_free(urb->dev, urb->transfer_buffer_length,
-			urb->transfer_buffer, urb->transfer_dma);
+	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+			  urb->transfer_buffer, urb->transfer_dma);
 	/* tell a waiting writer the interrupt-out-pipe is available again */
 	atomic_dec(&dev->write_busy);
 	wake_up_interruptible(&dev->write_wait);
@@ -421,8 +421,8 @@
 			dbg("%s Unable to allocate urb ", __func__);
 			goto error_no_urb;
 		}
-		buf = usb_buffer_alloc(dev->udev, dev->report_size,
-				       GFP_KERNEL, &int_out_urb->transfer_dma);
+		buf = usb_alloc_coherent(dev->udev, dev->report_size,
+					 GFP_KERNEL, &int_out_urb->transfer_dma);
 		if (!buf) {
 			retval = -ENOMEM;
 			dbg("%s Unable to allocate buffer ", __func__);
@@ -459,8 +459,8 @@
 		break;
 	}
 error:
-	usb_buffer_free(dev->udev, dev->report_size, buf,
-			int_out_urb->transfer_dma);
+	usb_free_coherent(dev->udev, dev->report_size, buf,
+			  int_out_urb->transfer_dma);
 error_no_buffer:
 	usb_free_urb(int_out_urb);
 error_no_urb:
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index aae95a0..30d9303 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -47,7 +47,6 @@
 #include <linux/spinlock.h>
 #include <linux/kref.h>
 #include <linux/usb.h>
-#include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 
 #include "sisusb.h"
@@ -2416,14 +2415,11 @@
 	struct usb_interface *interface;
 	int subminor = iminor(inode);
 
-	lock_kernel();
 	if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
-		unlock_kernel();
 		return -ENODEV;
 	}
 
 	if (!(sisusb = usb_get_intfdata(interface))) {
-		unlock_kernel();
 		return -ENODEV;
 	}
 
@@ -2431,13 +2427,11 @@
 
 	if (!sisusb->present || !sisusb->ready) {
 		mutex_unlock(&sisusb->lock);
-		unlock_kernel();
 		return -ENODEV;
 	}
 
 	if (sisusb->isopen) {
 		mutex_unlock(&sisusb->lock);
-		unlock_kernel();
 		return -EBUSY;
 	}
 
@@ -2446,13 +2440,11 @@
 			if (sisusb_init_gfxdevice(sisusb, 0)) {
 				mutex_unlock(&sisusb->lock);
 				dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
-				unlock_kernel();
 				return -EIO;
 			}
 		} else {
 			mutex_unlock(&sisusb->lock);
 			dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
-			unlock_kernel();
 			return -EIO;
 		}
 	}
@@ -2465,7 +2457,6 @@
 	file->private_data = sisusb;
 
 	mutex_unlock(&sisusb->lock);
-	unlock_kernel();
 
 	return 0;
 }
@@ -2974,13 +2965,12 @@
 	struct sisusb_usb_data *sisusb;
 	struct sisusb_info x;
 	struct sisusb_command y;
-	int	retval = 0;
+	long retval = 0;
 	u32 __user *argp = (u32 __user *)arg;
 
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
 		return -ENODEV;
 
-	lock_kernel();
 	mutex_lock(&sisusb->lock);
 
 	/* Sanity check */
@@ -3039,7 +3029,6 @@
 
 err_out:
 	mutex_unlock(&sisusb->lock);
-	unlock_kernel();
 	return retval;
 }
 
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index b271b05..411e605 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -1187,9 +1187,9 @@
 		 * And so is the hi_font_mask.
 		 */
 		for (i = 0; i < MAX_NR_CONSOLES; i++) {
-			struct vc_data *c = vc_cons[i].d;
-			if (c && c->vc_sw == &sisusb_con)
-				c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
+			struct vc_data *d = vc_cons[i].d;
+			if (d && d->vc_sw == &sisusb_con)
+				d->vc_hi_font_mask = ch512 ? 0x0800 : 0;
 		}
 
 		sisusb->current_font_512 = ch512;
@@ -1249,7 +1249,7 @@
 		mutex_unlock(&sisusb->lock);
 
 	if (dorecalc && c) {
-		int i, rows = c->vc_scan_lines / fh;
+		int rows = c->vc_scan_lines / fh;
 
 		/* Now adjust our consoles' size */
 
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 90aede9..7828c76 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -205,8 +205,8 @@
 	}
 
 	/* free up our allocated buffer */
-	usb_buffer_free(urb->dev, urb->transfer_buffer_length,
-			urb->transfer_buffer, urb->transfer_dma);
+	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+			  urb->transfer_buffer, urb->transfer_dma);
 	up(&dev->limit_sem);
 }
 
@@ -234,7 +234,7 @@
 		goto err_no_buf;
 	}
 	
-	buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
+	buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
 	if (!buf) {
 		retval = -ENOMEM;
 		goto error;
@@ -268,7 +268,7 @@
 error_unanchor:
 	usb_unanchor_urb(urb);
 error:
-	usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
+	usb_free_coherent(dev->udev, count, buf, urb->transfer_dma);
 	usb_free_urb(urb);
 err_no_buf:
 	up(&dev->limit_sem);
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index a21cce6..16dffe9 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -202,7 +202,7 @@
 	urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 	if (usb_pipein (pipe))
 		urb->transfer_flags |= URB_SHORT_NOT_OK;
-	urb->transfer_buffer = usb_buffer_alloc (udev, bytes, GFP_KERNEL,
+	urb->transfer_buffer = usb_alloc_coherent (udev, bytes, GFP_KERNEL,
 			&urb->transfer_dma);
 	if (!urb->transfer_buffer) {
 		usb_free_urb (urb);
@@ -272,8 +272,8 @@
 
 static void simple_free_urb (struct urb *urb)
 {
-	usb_buffer_free (urb->dev, urb->transfer_buffer_length,
-			urb->transfer_buffer, urb->transfer_dma);
+	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+			  urb->transfer_buffer, urb->transfer_dma);
 	usb_free_urb (urb);
 }
 
@@ -977,15 +977,13 @@
 		if (!u)
 			goto cleanup;
 
-		reqp = usb_buffer_alloc (udev, sizeof *reqp, GFP_KERNEL,
-				&u->setup_dma);
+		reqp = kmalloc(sizeof *reqp, GFP_KERNEL);
 		if (!reqp)
 			goto cleanup;
 		reqp->setup = req;
 		reqp->number = i % NUM_SUBCASES;
 		reqp->expected = expected;
 		u->setup_packet = (char *) &reqp->setup;
-		u->transfer_flags |= URB_NO_SETUP_DMA_MAP;
 
 		u->context = &context;
 		u->complete = ctrl_complete;
@@ -1017,10 +1015,7 @@
 		if (!urb [i])
 			continue;
 		urb [i]->dev = udev;
-		if (urb [i]->setup_packet)
-			usb_buffer_free (udev, sizeof (struct usb_ctrlrequest),
-					urb [i]->setup_packet,
-					urb [i]->setup_dma);
+		kfree(urb[i]->setup_packet);
 		simple_free_urb (urb [i]);
 	}
 	kfree (urb);
@@ -1421,7 +1416,7 @@
 
 	urb->number_of_packets = packets;
 	urb->transfer_buffer_length = bytes;
-	urb->transfer_buffer = usb_buffer_alloc (udev, bytes, GFP_KERNEL,
+	urb->transfer_buffer = usb_alloc_coherent (udev, bytes, GFP_KERNEL,
 			&urb->transfer_dma);
 	if (!urb->transfer_buffer) {
 		usb_free_urb (urb);
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index ddf7f9a..e7fa364 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -416,13 +416,13 @@
 
 	} else {
 		/* If IOMMU coalescing occurred, we cannot trust sg_page */
-		if (urb->sg->nents != urb->num_sgs) {
+		if (urb->transfer_flags & URB_DMA_SG_COMBINED) {
 			*flag = 'D';
 			return length;
 		}
 
 		/* Copy up to the first non-addressable segment */
-		for_each_sg(urb->sg->sg, sg, urb->num_sgs, i) {
+		for_each_sg(urb->sg, sg, urb->num_sgs, i) {
 			if (length == 0 || PageHighMem(sg_page(sg)))
 				break;
 			this_len = min_t(unsigned int, sg->length, length);
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index e4af18b..812dc28 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -9,12 +9,13 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/usb/hcd.h>
 #include <linux/slab.h>
 #include <linux/notifier.h>
 #include <linux/mutex.h>
 
 #include "usb_mon.h"
-#include "../core/hcd.h"
+
 
 static void mon_stop(struct mon_bus *mbus);
 static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 4d0be13..a545d65 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -159,11 +159,9 @@
 		if (src == NULL)
 			return 'Z';	/* '0' would be not as pretty. */
 	} else {
-		struct scatterlist *sg = urb->sg->sg;
+		struct scatterlist *sg = urb->sg;
 
-		/* If IOMMU coalescing occurred, we cannot trust sg_page */
-		if (urb->sg->nents != urb->num_sgs ||
-				PageHighMem(sg_page(sg)))
+		if (PageHighMem(sg_page(sg)))
 			return 'D';
 
 		/* For the text interface we copy only the first sg buffer */
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 07fe490..cfd38ed 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -38,6 +38,7 @@
 	default y if ARCH_DAVINCI
 	default y if ARCH_OMAP2430
 	default y if ARCH_OMAP3
+	default y if ARCH_OMAP4
 	default y if (BF54x && !BF544)
 	default y if (BF52x && !BF522 && !BF523)
 
@@ -50,6 +51,9 @@
 comment "OMAP 343x high speed USB support"
 	depends on USB_MUSB_HDRC && ARCH_OMAP3
 
+comment "OMAP 44xx high speed USB support"
+	depends on USB_MUSB_HDRC && ARCH_OMAP4
+
 comment "Blackfin high speed USB Support"
 	depends on USB_MUSB_HDRC && ((BF54x && !BF544) || (BF52x && !BF522 && !BF523))
 
@@ -153,7 +157,7 @@
 config USB_INVENTRA_DMA
 	bool
 	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
-	default ARCH_OMAP2430 || ARCH_OMAP3 || BLACKFIN
+	default ARCH_OMAP2430 || ARCH_OMAP3 || BLACKFIN || ARCH_OMAP4
 	help
 	  Enable DMA transfers using Mentor's engine.
 
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 3a485da..9705f71 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -22,6 +22,10 @@
 	musb_hdrc-objs	+= omap2430.o
 endif
 
+ifeq ($(CONFIG_ARCH_OMAP4),y)
+	musb_hdrc-objs  += omap2430.o
+endif
+
 ifeq ($(CONFIG_BF54x),y)
 	musb_hdrc-objs	+= blackfin.o
 endif
@@ -38,6 +42,10 @@
 	musb_hdrc-objs		+= musb_virthub.o musb_host.o
 endif
 
+ifeq ($(CONFIG_DEBUG_FS),y)
+	musb_hdrc-objs		+= musb_debugfs.o
+endif
+
 # the kconfig must guarantee that only one of the
 # possible I/O schemes will be enabled at a time ...
 # PIO only, or DMA (several potential schemes).
@@ -64,12 +72,6 @@
 
 ################################################################################
 
-# FIXME remove all these extra "-DMUSB_* things, stick to CONFIG_*
-
-ifeq ($(CONFIG_USB_INVENTRA_MUSB_HAS_AHB_ID),y)
-	EXTRA_CFLAGS += -DMUSB_AHB_ID
-endif
-
 # Debugging
 
 ifeq ($(CONFIG_USB_MUSB_DEBUG),y)
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index ec8d324..b611420 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -170,6 +170,13 @@
 		retval = musb_interrupt(musb);
 	}
 
+	/* Start sampling ID pin, when plug is removed from MUSB */
+	if (is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE
+		|| musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+		mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
+		musb->a_wait_bcon = TIMER_DELAY;
+	}
+
 	spin_unlock_irqrestore(&musb->lock, flags);
 
 	return retval;
@@ -180,6 +187,7 @@
 	struct musb *musb = (void *)_musb;
 	unsigned long flags;
 	u16 val;
+	static u8 toggle;
 
 	spin_lock_irqsave(&musb->lock, flags);
 	switch (musb->xceiv->state) {
@@ -187,10 +195,44 @@
 	case OTG_STATE_A_WAIT_BCON:
 		/* Start a new session */
 		val = musb_readw(musb->mregs, MUSB_DEVCTL);
+		val &= ~MUSB_DEVCTL_SESSION;
+		musb_writew(musb->mregs, MUSB_DEVCTL, val);
 		val |= MUSB_DEVCTL_SESSION;
 		musb_writew(musb->mregs, MUSB_DEVCTL, val);
-
+		/* Check if musb is host or peripheral. */
 		val = musb_readw(musb->mregs, MUSB_DEVCTL);
+
+		if (!(val & MUSB_DEVCTL_BDEVICE)) {
+			gpio_set_value(musb->config->gpio_vrsel, 1);
+			musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+		} else {
+			gpio_set_value(musb->config->gpio_vrsel, 0);
+			/* Ignore VBUSERROR and SUSPEND IRQ */
+			val = musb_readb(musb->mregs, MUSB_INTRUSBE);
+			val &= ~MUSB_INTR_VBUSERROR;
+			musb_writeb(musb->mregs, MUSB_INTRUSBE, val);
+
+			val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
+			musb_writeb(musb->mregs, MUSB_INTRUSB, val);
+			if (is_otg_enabled(musb))
+				musb->xceiv->state = OTG_STATE_B_IDLE;
+			else
+				musb_writeb(musb->mregs, MUSB_POWER, MUSB_POWER_HSENAB);
+		}
+		mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
+		break;
+	case OTG_STATE_B_IDLE:
+
+		if (!is_peripheral_enabled(musb))
+			break;
+		/* Start a new session.  It seems that MUSB needs taking
+		 * some time to recognize the type of the plug inserted?
+		 */
+		val = musb_readw(musb->mregs, MUSB_DEVCTL);
+		val |= MUSB_DEVCTL_SESSION;
+		musb_writew(musb->mregs, MUSB_DEVCTL, val);
+		val = musb_readw(musb->mregs, MUSB_DEVCTL);
+
 		if (!(val & MUSB_DEVCTL_BDEVICE)) {
 			gpio_set_value(musb->config->gpio_vrsel, 1);
 			musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
@@ -205,12 +247,27 @@
 			val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
 			musb_writeb(musb->mregs, MUSB_INTRUSB, val);
 
-			val = MUSB_POWER_HSENAB;
-			musb_writeb(musb->mregs, MUSB_POWER, val);
+			/* Toggle the Soft Conn bit, so that we can response to
+			 * the inserting of either A-plug or B-plug.
+			 */
+			if (toggle) {
+				val = musb_readb(musb->mregs, MUSB_POWER);
+				val &= ~MUSB_POWER_SOFTCONN;
+				musb_writeb(musb->mregs, MUSB_POWER, val);
+				toggle = 0;
+			} else {
+				val = musb_readb(musb->mregs, MUSB_POWER);
+				val |= MUSB_POWER_SOFTCONN;
+				musb_writeb(musb->mregs, MUSB_POWER, val);
+				toggle = 1;
+			}
+			/* The delay time is set to 1/4 second by default,
+			 * shortening it, if accelerating A-plug detection
+			 * is needed in OTG mode.
+			 */
+			mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY / 4);
 		}
-		mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
 		break;
-
 	default:
 		DBG(1, "%s state not handled\n", otg_state_string(musb));
 		break;
@@ -222,7 +279,7 @@
 
 void musb_platform_enable(struct musb *musb)
 {
-	if (is_host_enabled(musb)) {
+	if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
 		mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
 		musb->a_wait_bcon = TIMER_DELAY;
 	}
@@ -232,16 +289,12 @@
 {
 }
 
-static void bfin_vbus_power(struct musb *musb, int is_on, int sleeping)
-{
-}
-
 static void bfin_set_vbus(struct musb *musb, int is_on)
 {
-	if (is_on)
-		gpio_set_value(musb->config->gpio_vrsel, 1);
-	else
-		gpio_set_value(musb->config->gpio_vrsel, 0);
+	int value = musb->config->gpio_vrsel_active;
+	if (!is_on)
+		value = !value;
+	gpio_set_value(musb->config->gpio_vrsel, value);
 
 	DBG(1, "VBUS %s, devctl %02x "
 		/* otg %3x conf %08x prcm %08x */ "\n",
@@ -256,7 +309,7 @@
 
 void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
 {
-	if (is_host_enabled(musb))
+	if (!is_otg_enabled(musb) && is_host_enabled(musb))
 		mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
 }
 
@@ -270,7 +323,7 @@
 	return -EIO;
 }
 
-int __init musb_platform_init(struct musb *musb)
+int __init musb_platform_init(struct musb *musb, void *board_data)
 {
 
 	/*
@@ -339,23 +392,10 @@
 	return 0;
 }
 
-int musb_platform_suspend(struct musb *musb)
-{
-	return 0;
-}
-
-int musb_platform_resume(struct musb *musb)
-{
-	return 0;
-}
-
-
 int musb_platform_exit(struct musb *musb)
 {
 
-	bfin_vbus_power(musb, 0 /*off*/, 1);
 	gpio_free(musb->config->gpio_vrsel);
-	musb_platform_suspend(musb);
 
 	return 0;
 }
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index ce2e16f..57624361 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -376,7 +376,7 @@
 	return -EIO;
 }
 
-int __init musb_platform_init(struct musb *musb)
+int __init musb_platform_init(struct musb *musb, void *board_data)
 {
 	void __iomem	*tibase = musb->ctrl_base;
 	u32		revision;
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 705cc4a..fad70bc 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -149,6 +149,87 @@
 
 /*-------------------------------------------------------------------------*/
 
+#ifndef CONFIG_BLACKFIN
+static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset)
+{
+	void __iomem *addr = otg->io_priv;
+	int	i = 0;
+	u8	r;
+	u8	power;
+
+	/* Make sure the transceiver is not in low power mode */
+	power = musb_readb(addr, MUSB_POWER);
+	power &= ~MUSB_POWER_SUSPENDM;
+	musb_writeb(addr, MUSB_POWER, power);
+
+	/* REVISIT: musbhdrc_ulpi_an.pdf recommends setting the
+	 * ULPICarKitControlDisableUTMI after clearing POWER_SUSPENDM.
+	 */
+
+	musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset);
+	musb_writeb(addr, MUSB_ULPI_REG_CONTROL,
+			MUSB_ULPI_REG_REQ | MUSB_ULPI_RDN_WR);
+
+	while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL)
+				& MUSB_ULPI_REG_CMPLT)) {
+		i++;
+		if (i == 10000) {
+			DBG(3, "ULPI read timed out\n");
+			return -ETIMEDOUT;
+		}
+
+	}
+	r = musb_readb(addr, MUSB_ULPI_REG_CONTROL);
+	r &= ~MUSB_ULPI_REG_CMPLT;
+	musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r);
+
+	return musb_readb(addr, MUSB_ULPI_REG_DATA);
+}
+
+static int musb_ulpi_write(struct otg_transceiver *otg,
+		u32 offset, u32 data)
+{
+	void __iomem *addr = otg->io_priv;
+	int	i = 0;
+	u8	r = 0;
+	u8	power;
+
+	/* Make sure the transceiver is not in low power mode */
+	power = musb_readb(addr, MUSB_POWER);
+	power &= ~MUSB_POWER_SUSPENDM;
+	musb_writeb(addr, MUSB_POWER, power);
+
+	musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset);
+	musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)data);
+	musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ);
+
+	while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL)
+				& MUSB_ULPI_REG_CMPLT)) {
+		i++;
+		if (i == 10000) {
+			DBG(3, "ULPI write timed out\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	r = musb_readb(addr, MUSB_ULPI_REG_CONTROL);
+	r &= ~MUSB_ULPI_REG_CMPLT;
+	musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r);
+
+	return 0;
+}
+#else
+#define musb_ulpi_read(a, b)		NULL
+#define musb_ulpi_write(a, b, c)	NULL
+#endif
+
+static struct otg_io_access_ops musb_ulpi_access = {
+	.read = musb_ulpi_read,
+	.write = musb_ulpi_write,
+};
+
+/*-------------------------------------------------------------------------*/
+
 #if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN)
 
 /*
@@ -353,8 +434,7 @@
 	 * which cause occasional OPT A "Did not receive reset after connect"
 	 * errors.
 	 */
-	musb->port1_status &=
-		~(1 << USB_PORT_FEAT_C_CONNECTION);
+	musb->port1_status &= ~(USB_PORT_STAT_C_CONNECTION << 16);
 }
 
 #endif
@@ -530,8 +610,8 @@
 				musb_writeb(mbase, MUSB_DEVCTL, devctl);
 			} else {
 				musb->port1_status |=
-					  (1 << USB_PORT_FEAT_OVER_CURRENT)
-					| (1 << USB_PORT_FEAT_C_OVER_CURRENT);
+					  USB_PORT_STAT_OVERCURRENT
+					| (USB_PORT_STAT_C_OVERCURRENT << 16);
 			}
 			break;
 		default:
@@ -986,7 +1066,8 @@
  * more than selecting one of a bunch of predefined configurations.
  */
 #if defined(CONFIG_USB_TUSB6010) || \
-	defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+	defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \
+	|| defined(CONFIG_ARCH_OMAP4)
 static ushort __initdata fifo_mode = 4;
 #else
 static ushort __initdata fifo_mode = 2;
@@ -996,24 +1077,13 @@
 module_param(fifo_mode, ushort, 0);
 MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration");
 
-
-enum fifo_style { FIFO_RXTX, FIFO_TX, FIFO_RX } __attribute__ ((packed));
-enum buf_mode { BUF_SINGLE, BUF_DOUBLE } __attribute__ ((packed));
-
-struct fifo_cfg {
-	u8		hw_ep_num;
-	enum fifo_style	style;
-	enum buf_mode	mode;
-	u16		maxpacket;
-};
-
 /*
  * tables defining fifo_mode values.  define more if you like.
  * for host side, make sure both halves of ep1 are set up.
  */
 
 /* mode 0 - fits in 2KB */
-static struct fifo_cfg __initdata mode_0_cfg[] = {
+static struct musb_fifo_cfg __initdata mode_0_cfg[] = {
 { .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, },
 { .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, },
 { .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, },
@@ -1022,7 +1092,7 @@
 };
 
 /* mode 1 - fits in 4KB */
-static struct fifo_cfg __initdata mode_1_cfg[] = {
+static struct musb_fifo_cfg __initdata mode_1_cfg[] = {
 { .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
 { .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
 { .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, },
@@ -1031,7 +1101,7 @@
 };
 
 /* mode 2 - fits in 4KB */
-static struct fifo_cfg __initdata mode_2_cfg[] = {
+static struct musb_fifo_cfg __initdata mode_2_cfg[] = {
 { .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, },
 { .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, },
 { .hw_ep_num = 2, .style = FIFO_TX,   .maxpacket = 512, },
@@ -1041,7 +1111,7 @@
 };
 
 /* mode 3 - fits in 4KB */
-static struct fifo_cfg __initdata mode_3_cfg[] = {
+static struct musb_fifo_cfg __initdata mode_3_cfg[] = {
 { .hw_ep_num = 1, .style = FIFO_TX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
 { .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, .mode = BUF_DOUBLE, },
 { .hw_ep_num = 2, .style = FIFO_TX,   .maxpacket = 512, },
@@ -1051,7 +1121,7 @@
 };
 
 /* mode 4 - fits in 16KB */
-static struct fifo_cfg __initdata mode_4_cfg[] = {
+static struct musb_fifo_cfg __initdata mode_4_cfg[] = {
 { .hw_ep_num =  1, .style = FIFO_TX,   .maxpacket = 512, },
 { .hw_ep_num =  1, .style = FIFO_RX,   .maxpacket = 512, },
 { .hw_ep_num =  2, .style = FIFO_TX,   .maxpacket = 512, },
@@ -1082,7 +1152,7 @@
 };
 
 /* mode 5 - fits in 8KB */
-static struct fifo_cfg __initdata mode_5_cfg[] = {
+static struct musb_fifo_cfg __initdata mode_5_cfg[] = {
 { .hw_ep_num =  1, .style = FIFO_TX,   .maxpacket = 512, },
 { .hw_ep_num =  1, .style = FIFO_RX,   .maxpacket = 512, },
 { .hw_ep_num =  2, .style = FIFO_TX,   .maxpacket = 512, },
@@ -1120,7 +1190,7 @@
  */
 static int __init
 fifo_setup(struct musb *musb, struct musb_hw_ep  *hw_ep,
-		const struct fifo_cfg *cfg, u16 offset)
+		const struct musb_fifo_cfg *cfg, u16 offset)
 {
 	void __iomem	*mbase = musb->mregs;
 	int	size = 0;
@@ -1191,17 +1261,23 @@
 	return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0));
 }
 
-static struct fifo_cfg __initdata ep0_cfg = {
+static struct musb_fifo_cfg __initdata ep0_cfg = {
 	.style = FIFO_RXTX, .maxpacket = 64,
 };
 
 static int __init ep_config_from_table(struct musb *musb)
 {
-	const struct fifo_cfg	*cfg;
+	const struct musb_fifo_cfg	*cfg;
 	unsigned		i, n;
 	int			offset;
 	struct musb_hw_ep	*hw_ep = musb->endpoints;
 
+	if (musb->config->fifo_cfg) {
+		cfg = musb->config->fifo_cfg;
+		n = musb->config->fifo_cfg_size;
+		goto done;
+	}
+
 	switch (fifo_mode) {
 	default:
 		fifo_mode = 0;
@@ -1236,6 +1312,7 @@
 			musb_driver_name, fifo_mode);
 
 
+done:
 	offset = fifo_setup(musb, hw_ep, &ep0_cfg, 0);
 	/* assert(offset > 0) */
 
@@ -1461,7 +1538,8 @@
 
 /*-------------------------------------------------------------------------*/
 
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || \
+	defined(CONFIG_ARCH_OMAP4)
 
 static irqreturn_t generic_interrupt(int irq, void *__hci)
 {
@@ -1948,7 +2026,7 @@
 	 * isp1504, non-OTG, etc) mostly hooking up through ULPI.
 	 */
 	musb->isr = generic_interrupt;
-	status = musb_platform_init(musb);
+	status = musb_platform_init(musb, plat->board_data);
 	if (status < 0)
 		goto fail2;
 
@@ -1957,6 +2035,11 @@
 		goto fail3;
 	}
 
+	if (!musb->xceiv->io_ops) {
+		musb->xceiv->io_priv = musb->mregs;
+		musb->xceiv->io_ops = &musb_ulpi_access;
+	}
+
 #ifndef CONFIG_MUSB_PIO_ONLY
 	if (use_dma && dev->dma_mask) {
 		struct dma_controller	*c;
@@ -2057,10 +2140,14 @@
 	if (status < 0)
 		goto fail3;
 
+	status = musb_init_debugfs(musb);
+	if (status < 0)
+		goto fail4;
+
 #ifdef CONFIG_SYSFS
 	status = sysfs_create_group(&musb->controller->kobj, &musb_attr_group);
 	if (status)
-		goto fail4;
+		goto fail5;
 #endif
 
 	dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n",
@@ -2077,6 +2164,9 @@
 
 	return 0;
 
+fail5:
+	musb_exit_debugfs(musb);
+
 fail4:
 	if (!is_otg_enabled(musb) && is_host_enabled(musb))
 		usb_remove_hcd(musb_to_hcd(musb));
@@ -2153,6 +2243,7 @@
 	 *  - Peripheral mode: peripheral is deactivated (or never-activated)
 	 *  - OTG mode: both roles are deactivated (or never-activated)
 	 */
+	musb_exit_debugfs(musb);
 	musb_shutdown(pdev);
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
 	if (musb->board_mode == MUSB_HOST)
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index ac17b00..b22d02d 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -69,7 +69,7 @@
 #include "musb_regs.h"
 
 #include "musb_gadget.h"
-#include "../core/hcd.h"
+#include <linux/usb/hcd.h>
 #include "musb_host.h"
 
 
@@ -213,7 +213,8 @@
  */
 
 #if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP2430) \
-		|| defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_BLACKFIN)
+		|| defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_BLACKFIN) \
+		|| defined(CONFIG_ARCH_OMAP4)
 /* REVISIT indexed access seemed to
  * misbehave (on DaVinci) for at least peripheral IN ...
  */
@@ -596,7 +597,8 @@
 extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode);
 
 #if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) || \
-	defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+	defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
+	defined(CONFIG_ARCH_OMAP4)
 extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout);
 #else
 #define musb_platform_try_idle(x, y)		do {} while (0)
@@ -608,7 +610,7 @@
 #define musb_platform_get_vbus_status(x)	0
 #endif
 
-extern int __init musb_platform_init(struct musb *musb);
+extern int __init musb_platform_init(struct musb *musb, void *board_data);
 extern int musb_platform_exit(struct musb *musb);
 
 #endif	/* __MUSB_CORE_H__ */
diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h
index 9fc1db4..d73afdb 100644
--- a/drivers/usb/musb/musb_debug.h
+++ b/drivers/usb/musb/musb_debug.h
@@ -59,4 +59,17 @@
 
 extern const char *otg_state_string(struct musb *);
 
+#ifdef CONFIG_DEBUG_FS
+extern int musb_init_debugfs(struct musb *musb);
+extern void musb_exit_debugfs(struct musb *musb);
+#else
+static inline int musb_init_debugfs(struct musb *musb)
+{
+	return 0;
+}
+static inline void musb_exit_debugfs(struct musb *musb)
+{
+}
+#endif
+
 #endif				/*  __MUSB_LINUX_DEBUG_H__ */
diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c
new file mode 100644
index 0000000..bba76af
--- /dev/null
+++ b/drivers/usb/musb/musb_debugfs.c
@@ -0,0 +1,294 @@
+/*
+ * MUSB OTG driver debugfs support
+ *
+ * Copyright 2010 Nokia Corporation
+ * Contact: Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/kobject.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#ifdef	CONFIG_ARM
+#include <mach/hardware.h>
+#include <mach/memory.h>
+#include <asm/mach-types.h>
+#endif
+
+#include <asm/uaccess.h>
+
+#include "musb_core.h"
+#include "musb_debug.h"
+
+#ifdef CONFIG_ARCH_DAVINCI
+#include "davinci.h"
+#endif
+
+struct musb_register_map {
+	char			*name;
+	unsigned		offset;
+	unsigned		size;
+};
+
+static const struct musb_register_map musb_regmap[] = {
+	{ "FAddr",		0x00,	8 },
+	{ "Power",		0x01,	8 },
+	{ "Frame",		0x0c,	16 },
+	{ "Index",		0x0e,	8 },
+	{ "Testmode",		0x0f,	8 },
+	{ "TxMaxPp",		0x10,	16 },
+	{ "TxCSRp",		0x12,	16 },
+	{ "RxMaxPp",		0x14,	16 },
+	{ "RxCSR",		0x16,	16 },
+	{ "RxCount",		0x18,	16 },
+	{ "ConfigData",		0x1f,	8 },
+	{ "DevCtl",		0x60,	8 },
+	{ "MISC",		0x61,	8 },
+	{ "TxFIFOsz",		0x62,	8 },
+	{ "RxFIFOsz",		0x63,	8 },
+	{ "TxFIFOadd",		0x64,	16 },
+	{ "RxFIFOadd",		0x66,	16 },
+	{ "VControl",		0x68,	32 },
+	{ "HWVers",		0x6C,	16 },
+	{ "EPInfo",		0x78,	8 },
+	{ "RAMInfo",		0x79,	8 },
+	{ "LinkInfo",		0x7A,	8 },
+	{ "VPLen",		0x7B,	8 },
+	{ "HS_EOF1",		0x7C,	8 },
+	{ "FS_EOF1",		0x7D,	8 },
+	{ "LS_EOF1",		0x7E,	8 },
+	{ "SOFT_RST",		0x7F,	8 },
+	{ "DMA_CNTLch0",	0x204,	16 },
+	{ "DMA_ADDRch0",	0x208,	16 },
+	{ "DMA_COUNTch0",	0x20C,	16 },
+	{ "DMA_CNTLch1",	0x214,	16 },
+	{ "DMA_ADDRch1",	0x218,	16 },
+	{ "DMA_COUNTch1",	0x21C,	16 },
+	{ "DMA_CNTLch2",	0x224,	16 },
+	{ "DMA_ADDRch2",	0x228,	16 },
+	{ "DMA_COUNTch2",	0x22C,	16 },
+	{ "DMA_CNTLch3",	0x234,	16 },
+	{ "DMA_ADDRch3",	0x238,	16 },
+	{ "DMA_COUNTch3",	0x23C,	16 },
+	{ "DMA_CNTLch4",	0x244,	16 },
+	{ "DMA_ADDRch4",	0x248,	16 },
+	{ "DMA_COUNTch4",	0x24C,	16 },
+	{ "DMA_CNTLch5",	0x254,	16 },
+	{ "DMA_ADDRch5",	0x258,	16 },
+	{ "DMA_COUNTch5",	0x25C,	16 },
+	{ "DMA_CNTLch6",	0x264,	16 },
+	{ "DMA_ADDRch6",	0x268,	16 },
+	{ "DMA_COUNTch6",	0x26C,	16 },
+	{ "DMA_CNTLch7",	0x274,	16 },
+	{ "DMA_ADDRch7",	0x278,	16 },
+	{ "DMA_COUNTch7",	0x27C,	16 },
+	{  }	/* Terminating Entry */
+};
+
+static struct dentry *musb_debugfs_root;
+
+static int musb_regdump_show(struct seq_file *s, void *unused)
+{
+	struct musb		*musb = s->private;
+	unsigned		i;
+
+	seq_printf(s, "MUSB (M)HDRC Register Dump\n");
+
+	for (i = 0; i < ARRAY_SIZE(musb_regmap); i++) {
+		switch (musb_regmap[i].size) {
+		case 8:
+			seq_printf(s, "%-12s: %02x\n", musb_regmap[i].name,
+					musb_readb(musb->mregs, musb_regmap[i].offset));
+			break;
+		case 16:
+			seq_printf(s, "%-12s: %04x\n", musb_regmap[i].name,
+					musb_readw(musb->mregs, musb_regmap[i].offset));
+			break;
+		case 32:
+			seq_printf(s, "%-12s: %08x\n", musb_regmap[i].name,
+					musb_readl(musb->mregs, musb_regmap[i].offset));
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int musb_regdump_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, musb_regdump_show, inode->i_private);
+}
+
+static int musb_test_mode_show(struct seq_file *s, void *unused)
+{
+	struct musb		*musb = s->private;
+	unsigned		test;
+
+	test = musb_readb(musb->mregs, MUSB_TESTMODE);
+
+	if (test & MUSB_TEST_FORCE_HOST)
+		seq_printf(s, "force host\n");
+
+	if (test & MUSB_TEST_FIFO_ACCESS)
+		seq_printf(s, "fifo access\n");
+
+	if (test & MUSB_TEST_FORCE_FS)
+		seq_printf(s, "force full-speed\n");
+
+	if (test & MUSB_TEST_FORCE_HS)
+		seq_printf(s, "force high-speed\n");
+
+	if (test & MUSB_TEST_PACKET)
+		seq_printf(s, "test packet\n");
+
+	if (test & MUSB_TEST_K)
+		seq_printf(s, "test K\n");
+
+	if (test & MUSB_TEST_J)
+		seq_printf(s, "test J\n");
+
+	if (test & MUSB_TEST_SE0_NAK)
+		seq_printf(s, "test SE0 NAK\n");
+
+	return 0;
+}
+
+static const struct file_operations musb_regdump_fops = {
+	.open			= musb_regdump_open,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
+static int musb_test_mode_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+
+	return single_open(file, musb_test_mode_show, inode->i_private);
+}
+
+static ssize_t musb_test_mode_write(struct file *file,
+		const char __user *ubuf, size_t count, loff_t *ppos)
+{
+	struct musb		*musb = file->private_data;
+	u8			test = 0;
+	char			buf[18];
+
+	memset(buf, 0x00, sizeof(buf));
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	if (!strncmp(buf, "force host", 9))
+		test = MUSB_TEST_FORCE_HOST;
+
+	if (!strncmp(buf, "fifo access", 11))
+		test = MUSB_TEST_FIFO_ACCESS;
+
+	if (!strncmp(buf, "force full-speed", 15))
+		test = MUSB_TEST_FORCE_FS;
+
+	if (!strncmp(buf, "force high-speed", 15))
+		test = MUSB_TEST_FORCE_HS;
+
+	if (!strncmp(buf, "test packet", 10)) {
+		test = MUSB_TEST_PACKET;
+		musb_load_testpacket(musb);
+	}
+
+	if (!strncmp(buf, "test K", 6))
+		test = MUSB_TEST_K;
+
+	if (!strncmp(buf, "test J", 6))
+		test = MUSB_TEST_J;
+
+	if (!strncmp(buf, "test SE0 NAK", 12))
+		test = MUSB_TEST_SE0_NAK;
+
+	musb_writeb(musb->mregs, MUSB_TESTMODE, test);
+
+	return count;
+}
+
+static const struct file_operations musb_test_mode_fops = {
+	.open			= musb_test_mode_open,
+	.write			= musb_test_mode_write,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
+int __init musb_init_debugfs(struct musb *musb)
+{
+	struct dentry		*root;
+	struct dentry		*file;
+	int			ret;
+
+	root = debugfs_create_dir("musb", NULL);
+	if (IS_ERR(root)) {
+		ret = PTR_ERR(root);
+		goto err0;
+	}
+
+	file = debugfs_create_file("regdump", S_IRUGO, root, musb,
+			&musb_regdump_fops);
+	if (IS_ERR(file)) {
+		ret = PTR_ERR(file);
+		goto err1;
+	}
+
+	file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR,
+			root, musb, &musb_test_mode_fops);
+	if (IS_ERR(file)) {
+		ret = PTR_ERR(file);
+		goto err1;
+	}
+
+	musb_debugfs_root = root;
+
+	return 0;
+
+err1:
+	debugfs_remove_recursive(root);
+
+err0:
+	return ret;
+}
+
+void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb)
+{
+	debugfs_remove_recursive(musb_debugfs_root);
+}
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 53d0645..21b9788 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -351,6 +351,31 @@
 						musb->test_mode_nr =
 							MUSB_TEST_PACKET;
 						break;
+
+					case 0xc0:
+						/* TEST_FORCE_HS */
+						pr_debug("TEST_FORCE_HS\n");
+						musb->test_mode_nr =
+							MUSB_TEST_FORCE_HS;
+						break;
+					case 0xc1:
+						/* TEST_FORCE_FS */
+						pr_debug("TEST_FORCE_FS\n");
+						musb->test_mode_nr =
+							MUSB_TEST_FORCE_FS;
+						break;
+					case 0xc2:
+						/* TEST_FIFO_ACCESS */
+						pr_debug("TEST_FIFO_ACCESS\n");
+						musb->test_mode_nr =
+							MUSB_TEST_FIFO_ACCESS;
+						break;
+					case 0xc3:
+						/* TEST_FORCE_HOST */
+						pr_debug("TEST_FORCE_HOST\n");
+						musb->test_mode_nr =
+							MUSB_TEST_FORCE_HOST;
+						break;
 					default:
 						goto stall;
 					}
diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h
index fa55aac..2442675 100644
--- a/drivers/usb/musb/musb_regs.h
+++ b/drivers/usb/musb/musb_regs.h
@@ -75,6 +75,10 @@
 /* MUSB ULPI VBUSCONTROL */
 #define MUSB_ULPI_USE_EXTVBUS	0x01
 #define MUSB_ULPI_USE_EXTVBUSIND 0x02
+/* ULPI_REG_CONTROL */
+#define MUSB_ULPI_REG_REQ	(1 << 0)
+#define MUSB_ULPI_REG_CMPLT	(1 << 1)
+#define MUSB_ULPI_RDN_WR	(1 << 2)
 
 /* TESTMODE */
 #define MUSB_TEST_FORCE_HOST	0x80
@@ -251,6 +255,12 @@
 /* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */
 #define MUSB_HWVERS		0x6C	/* 8 bit */
 #define MUSB_ULPI_BUSCONTROL	0x70	/* 8 bit */
+#define MUSB_ULPI_INT_MASK	0x72	/* 8 bit */
+#define MUSB_ULPI_INT_SRC	0x73	/* 8 bit */
+#define MUSB_ULPI_REG_DATA	0x74	/* 8 bit */
+#define MUSB_ULPI_REG_ADDR	0x75	/* 8 bit */
+#define MUSB_ULPI_REG_CONTROL	0x76	/* 8 bit */
+#define MUSB_ULPI_RAW_DATA	0x77	/* 8 bit */
 
 #define MUSB_EPINFO		0x78	/* 8 bit */
 #define MUSB_RAMINFO		0x79	/* 8 bit */
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index 7775e1c0..92e85e0 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -183,8 +183,8 @@
 
 void musb_root_disconnect(struct musb *musb)
 {
-	musb->port1_status = (1 << USB_PORT_FEAT_POWER)
-			| (1 << USB_PORT_FEAT_C_CONNECTION);
+	musb->port1_status = USB_PORT_STAT_POWER
+			| (USB_PORT_STAT_C_CONNECTION << 16);
 
 	usb_hcd_poll_rh_status(musb_to_hcd(musb));
 	musb->is_active = 0;
diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h
index 613f95a..f763d62 100644
--- a/drivers/usb/musb/musbhsdma.h
+++ b/drivers/usb/musb/musbhsdma.h
@@ -102,26 +102,16 @@
 
 static inline u32 musb_read_hsdma_count(void __iomem *mbase, u8 bchannel)
 {
-	u32 count = musb_readw(mbase,
+	return musb_readl(mbase,
 		MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH));
-
-	count = count << 16;
-
-	count |= musb_readw(mbase,
-		MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW));
-
-	return count;
 }
 
 static inline void musb_write_hsdma_count(void __iomem *mbase,
 				u8 bchannel, u32 len)
 {
-	musb_writew(mbase,
-		MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW),
-		((u16)((u32) len & 0xFFFF)));
-	musb_writew(mbase,
+	musb_writel(mbase,
 		MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH),
-		((u16)(((u32) len >> 16) & 0xFFFF)));
+		len);
 }
 
 #endif /* CONFIG_BLACKFIN */
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 8259263..e06d65e 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -32,17 +32,11 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
 #include <plat/mux.h>
 
 #include "musb_core.h"
 #include "omap2430.h"
 
-#ifdef CONFIG_ARCH_OMAP3430
-#define	get_cpu_rev()	2
-#endif
-
 
 static struct timer_list musb_idle_timer;
 
@@ -145,10 +139,6 @@
 void musb_platform_disable(struct musb *musb)
 {
 }
-static void omap_vbus_power(struct musb *musb, int is_on, int sleeping)
-{
-}
-
 static void omap_set_vbus(struct musb *musb, int is_on)
 {
 	u8		devctl;
@@ -199,9 +189,10 @@
 	return 0;
 }
 
-int __init musb_platform_init(struct musb *musb)
+int __init musb_platform_init(struct musb *musb, void *board_data)
 {
 	u32 l;
+	struct omap_musb_board_data *data = board_data;
 
 #if defined(CONFIG_ARCH_OMAP2430)
 	omap_cfg_reg(AE5_2430_USB0HS_STP);
@@ -235,7 +226,15 @@
 	musb_writel(musb->mregs, OTG_SYSCONFIG, l);
 
 	l = musb_readl(musb->mregs, OTG_INTERFSEL);
-	l |= ULPI_12PIN;
+
+	if (data->interface_type == MUSB_INTERFACE_UTMI) {
+		/* OMAP4 uses Internal PHY GS70 which uses UTMI interface */
+		l &= ~ULPI_12PIN;       /* Disable ULPI */
+		l |= UTMI_8BIT;         /* Enable UTMI  */
+	} else {
+		l |= ULPI_12PIN;
+	}
+
 	musb_writel(musb->mregs, OTG_INTERFSEL, l);
 
 	pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
@@ -246,8 +245,6 @@
 			musb_readl(musb->mregs, OTG_INTERFSEL),
 			musb_readl(musb->mregs, OTG_SIMENABLE));
 
-	omap_vbus_power(musb, musb->board_mode == MUSB_HOST, 1);
-
 	if (is_host_enabled(musb))
 		musb->board_set_vbus = omap_set_vbus;
 
@@ -272,7 +269,7 @@
 }
 #endif
 
-int musb_platform_suspend(struct musb *musb)
+static int musb_platform_suspend(struct musb *musb)
 {
 	u32 l;
 
@@ -327,8 +324,6 @@
 int musb_platform_exit(struct musb *musb)
 {
 
-	omap_vbus_power(musb, 0 /*off*/, 1);
-
 	musb_platform_suspend(musb);
 
 	return 0;
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 60d3938..05c077f 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -1104,7 +1104,7 @@
 	return -ENODEV;
 }
 
-int __init musb_platform_init(struct musb *musb)
+int __init musb_platform_init(struct musb *musb, void *board_data)
 {
 	struct platform_device	*pdev;
 	struct resource		*mem;
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c
index 78a2097..4569694 100644
--- a/drivers/usb/otg/isp1301_omap.c
+++ b/drivers/usb/otg/isp1301_omap.c
@@ -1654,7 +1654,7 @@
 {
 	return i2c_add_driver(&isp1301_driver);
 }
-module_init(isp_init);
+subsys_initcall(isp_init);
 
 static void __exit isp_exit(void)
 {
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
index 223cdf4..0e88885 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -33,6 +33,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
@@ -41,81 +42,7 @@
 
 /* Register defines */
 
-#define VENDOR_ID_LO			0x00
-#define VENDOR_ID_HI			0x01
-#define PRODUCT_ID_LO			0x02
-#define PRODUCT_ID_HI			0x03
-
-#define FUNC_CTRL			0x04
-#define FUNC_CTRL_SET			0x05
-#define FUNC_CTRL_CLR			0x06
-#define FUNC_CTRL_SUSPENDM		(1 << 6)
-#define FUNC_CTRL_RESET			(1 << 5)
-#define FUNC_CTRL_OPMODE_MASK		(3 << 3) /* bits 3 and 4 */
-#define FUNC_CTRL_OPMODE_NORMAL		(0 << 3)
-#define FUNC_CTRL_OPMODE_NONDRIVING	(1 << 3)
-#define FUNC_CTRL_OPMODE_DISABLE_BIT_NRZI	(2 << 3)
-#define FUNC_CTRL_TERMSELECT		(1 << 2)
-#define FUNC_CTRL_XCVRSELECT_MASK	(3 << 0) /* bits 0 and 1 */
-#define FUNC_CTRL_XCVRSELECT_HS		(0 << 0)
-#define FUNC_CTRL_XCVRSELECT_FS		(1 << 0)
-#define FUNC_CTRL_XCVRSELECT_LS		(2 << 0)
-#define FUNC_CTRL_XCVRSELECT_FS4LS	(3 << 0)
-
-#define IFC_CTRL			0x07
-#define IFC_CTRL_SET			0x08
-#define IFC_CTRL_CLR			0x09
-#define IFC_CTRL_INTERFACE_PROTECT_DISABLE	(1 << 7)
-#define IFC_CTRL_AUTORESUME		(1 << 4)
-#define IFC_CTRL_CLOCKSUSPENDM		(1 << 3)
-#define IFC_CTRL_CARKITMODE		(1 << 2)
-#define IFC_CTRL_FSLSSERIALMODE_3PIN	(1 << 1)
-
-#define TWL4030_OTG_CTRL		0x0A
-#define TWL4030_OTG_CTRL_SET		0x0B
-#define TWL4030_OTG_CTRL_CLR		0x0C
-#define TWL4030_OTG_CTRL_DRVVBUS	(1 << 5)
-#define TWL4030_OTG_CTRL_CHRGVBUS	(1 << 4)
-#define TWL4030_OTG_CTRL_DISCHRGVBUS	(1 << 3)
-#define TWL4030_OTG_CTRL_DMPULLDOWN	(1 << 2)
-#define TWL4030_OTG_CTRL_DPPULLDOWN	(1 << 1)
-#define TWL4030_OTG_CTRL_IDPULLUP	(1 << 0)
-
-#define USB_INT_EN_RISE			0x0D
-#define USB_INT_EN_RISE_SET		0x0E
-#define USB_INT_EN_RISE_CLR		0x0F
-#define USB_INT_EN_FALL			0x10
-#define USB_INT_EN_FALL_SET		0x11
-#define USB_INT_EN_FALL_CLR		0x12
-#define USB_INT_STS			0x13
-#define USB_INT_LATCH			0x14
-#define USB_INT_IDGND			(1 << 4)
-#define USB_INT_SESSEND			(1 << 3)
-#define USB_INT_SESSVALID		(1 << 2)
-#define USB_INT_VBUSVALID		(1 << 1)
-#define USB_INT_HOSTDISCONNECT		(1 << 0)
-
-#define CARKIT_CTRL			0x19
-#define CARKIT_CTRL_SET			0x1A
-#define CARKIT_CTRL_CLR			0x1B
-#define CARKIT_CTRL_MICEN		(1 << 6)
-#define CARKIT_CTRL_SPKRIGHTEN		(1 << 5)
-#define CARKIT_CTRL_SPKLEFTEN		(1 << 4)
-#define CARKIT_CTRL_RXDEN		(1 << 3)
-#define CARKIT_CTRL_TXDEN		(1 << 2)
-#define CARKIT_CTRL_IDGNDDRV		(1 << 1)
-#define CARKIT_CTRL_CARKITPWR		(1 << 0)
-#define CARKIT_PLS_CTRL			0x22
-#define CARKIT_PLS_CTRL_SET		0x23
-#define CARKIT_PLS_CTRL_CLR		0x24
-#define CARKIT_PLS_CTRL_SPKRRIGHT_BIASEN	(1 << 3)
-#define CARKIT_PLS_CTRL_SPKRLEFT_BIASEN	(1 << 2)
-#define CARKIT_PLS_CTRL_RXPLSEN		(1 << 1)
-#define CARKIT_PLS_CTRL_TXPLSEN		(1 << 0)
-
 #define MCPC_CTRL			0x30
-#define MCPC_CTRL_SET			0x31
-#define MCPC_CTRL_CLR			0x32
 #define MCPC_CTRL_RTSOL			(1 << 7)
 #define MCPC_CTRL_EXTSWR		(1 << 6)
 #define MCPC_CTRL_EXTSWC		(1 << 5)
@@ -125,8 +52,6 @@
 #define MCPC_CTRL_HS_UART		(1 << 0)
 
 #define MCPC_IO_CTRL			0x33
-#define MCPC_IO_CTRL_SET		0x34
-#define MCPC_IO_CTRL_CLR		0x35
 #define MCPC_IO_CTRL_MICBIASEN		(1 << 5)
 #define MCPC_IO_CTRL_CTS_NPU		(1 << 4)
 #define MCPC_IO_CTRL_RXD_PU		(1 << 3)
@@ -135,19 +60,13 @@
 #define MCPC_IO_CTRL_RTSTYP		(1 << 0)
 
 #define MCPC_CTRL2			0x36
-#define MCPC_CTRL2_SET			0x37
-#define MCPC_CTRL2_CLR			0x38
 #define MCPC_CTRL2_MCPC_CK_EN		(1 << 0)
 
 #define OTHER_FUNC_CTRL			0x80
-#define OTHER_FUNC_CTRL_SET		0x81
-#define OTHER_FUNC_CTRL_CLR		0x82
 #define OTHER_FUNC_CTRL_BDIS_ACON_EN	(1 << 4)
 #define OTHER_FUNC_CTRL_FIVEWIRE_MODE	(1 << 2)
 
 #define OTHER_IFC_CTRL			0x83
-#define OTHER_IFC_CTRL_SET		0x84
-#define OTHER_IFC_CTRL_CLR		0x85
 #define OTHER_IFC_CTRL_OE_INT_EN	(1 << 6)
 #define OTHER_IFC_CTRL_CEA2011_MODE	(1 << 5)
 #define OTHER_IFC_CTRL_FSLSSERIALMODE_4PIN	(1 << 4)
@@ -156,11 +75,7 @@
 #define OTHER_IFC_CTRL_ALT_INT_REROUTE	(1 << 0)
 
 #define OTHER_INT_EN_RISE		0x86
-#define OTHER_INT_EN_RISE_SET		0x87
-#define OTHER_INT_EN_RISE_CLR		0x88
 #define OTHER_INT_EN_FALL		0x89
-#define OTHER_INT_EN_FALL_SET		0x8A
-#define OTHER_INT_EN_FALL_CLR		0x8B
 #define OTHER_INT_STS			0x8C
 #define OTHER_INT_LATCH			0x8D
 #define OTHER_INT_VB_SESS_VLD		(1 << 7)
@@ -178,13 +93,9 @@
 #define ID_RES_GND			(1 << 0)
 
 #define POWER_CTRL			0xAC
-#define POWER_CTRL_SET			0xAD
-#define POWER_CTRL_CLR			0xAE
 #define POWER_CTRL_OTG_ENAB		(1 << 5)
 
 #define OTHER_IFC_CTRL2			0xAF
-#define OTHER_IFC_CTRL2_SET		0xB0
-#define OTHER_IFC_CTRL2_CLR		0xB1
 #define OTHER_IFC_CTRL2_ULPI_STP_LOW	(1 << 4)
 #define OTHER_IFC_CTRL2_ULPI_TXEN_POL	(1 << 3)
 #define OTHER_IFC_CTRL2_ULPI_4PIN_2430	(1 << 2)
@@ -193,14 +104,10 @@
 #define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT2N	(1 << 0)
 
 #define REG_CTRL_EN			0xB2
-#define REG_CTRL_EN_SET			0xB3
-#define REG_CTRL_EN_CLR			0xB4
 #define REG_CTRL_ERROR			0xB5
 #define ULPI_I2C_CONFLICT_INTEN		(1 << 0)
 
 #define OTHER_FUNC_CTRL2		0xB8
-#define OTHER_FUNC_CTRL2_SET		0xB9
-#define OTHER_FUNC_CTRL2_CLR		0xBA
 #define OTHER_FUNC_CTRL2_VBAT_TIMER_EN	(1 << 0)
 
 /* following registers do not have separate _clr and _set registers */
@@ -328,13 +235,13 @@
 static inline int
 twl4030_usb_set_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
 {
-	return twl4030_usb_write(twl, reg + 1, bits);
+	return twl4030_usb_write(twl, ULPI_SET(reg), bits);
 }
 
 static inline int
 twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
 {
-	return twl4030_usb_write(twl, reg + 2, bits);
+	return twl4030_usb_write(twl, ULPI_CLR(reg), bits);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -393,11 +300,12 @@
 
 	switch (mode) {
 	case T2_USB_MODE_ULPI:
-		twl4030_usb_clear_bits(twl, IFC_CTRL, IFC_CTRL_CARKITMODE);
+		twl4030_usb_clear_bits(twl, ULPI_IFC_CTRL,
+					ULPI_IFC_CTRL_CARKITMODE);
 		twl4030_usb_set_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
-		twl4030_usb_clear_bits(twl, FUNC_CTRL,
-					FUNC_CTRL_XCVRSELECT_MASK |
-					FUNC_CTRL_OPMODE_MASK);
+		twl4030_usb_clear_bits(twl, ULPI_FUNC_CTRL,
+					ULPI_FUNC_CTRL_XCVRSEL_MASK |
+					ULPI_FUNC_CTRL_OPMODE_MASK);
 		break;
 	case -1:
 		/* FIXME: power on defaults */
diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/otg/ulpi.c
index 9010225..b1b3469 100644
--- a/drivers/usb/otg/ulpi.c
+++ b/drivers/usb/otg/ulpi.c
@@ -29,28 +29,6 @@
 #include <linux/usb/otg.h>
 #include <linux/usb/ulpi.h>
 
-/* ULPI register addresses */
-#define ULPI_VID_LOW         0x00    /* Vendor ID low */
-#define ULPI_VID_HIGH        0x01    /* Vendor ID high */
-#define ULPI_PID_LOW         0x02    /* Product ID low */
-#define ULPI_PID_HIGH        0x03    /* Product ID high */
-#define ULPI_ITFCTL          0x07    /* Interface Control */
-#define ULPI_OTGCTL          0x0A    /* OTG Control */
-
-/* add to above register address to access Set/Clear functions */
-#define ULPI_REG_SET         0x01
-#define ULPI_REG_CLEAR       0x02
-
-/* ULPI OTG Control Register bits */
-#define ID_PULL_UP              (1 << 0)        /* enable ID Pull Up */
-#define DP_PULL_DOWN            (1 << 1)        /* enable DP Pull Down */
-#define DM_PULL_DOWN            (1 << 2)        /* enable DM Pull Down */
-#define DISCHRG_VBUS            (1 << 3)        /* Discharge Vbus */
-#define CHRG_VBUS               (1 << 4)        /* Charge Vbus */
-#define DRV_VBUS                (1 << 5)        /* Drive Vbus */
-#define DRV_VBUS_EXT            (1 << 6)        /* Drive Vbus external */
-#define USE_EXT_VBUS_IND        (1 << 7)        /* Use ext. Vbus indicator */
-
 #define ULPI_ID(vendor, product) (((vendor) << 16) | (product))
 
 #define TR_FLAG(flags, a, b)	(((flags) & a) ? b : 0)
@@ -65,28 +43,28 @@
 	unsigned int flags = 0;
 
 	if (otg->flags & USB_OTG_PULLUP_ID)
-		flags |= ID_PULL_UP;
+		flags |= ULPI_OTG_CTRL_ID_PULLUP;
 
 	if (otg->flags & USB_OTG_PULLDOWN_DM)
-		flags |= DM_PULL_DOWN;
+		flags |= ULPI_OTG_CTRL_DM_PULLDOWN;
 
 	if (otg->flags & USB_OTG_PULLDOWN_DP)
-		flags |= DP_PULL_DOWN;
+		flags |= ULPI_OTG_CTRL_DP_PULLDOWN;
 
 	if (otg->flags & USB_OTG_EXT_VBUS_INDICATOR)
-		flags |= USE_EXT_VBUS_IND;
+		flags |= ULPI_OTG_CTRL_EXTVBUSIND;
 
-	return otg_io_write(otg, flags, ULPI_OTGCTL + ULPI_REG_SET);
+	return otg_io_write(otg, flags, ULPI_SET(ULPI_OTG_CTRL));
 }
 
 static int ulpi_init(struct otg_transceiver *otg)
 {
 	int i, vid, pid;
 
-	vid = (otg_io_read(otg, ULPI_VID_HIGH) << 8) |
-	       otg_io_read(otg, ULPI_VID_LOW);
-	pid = (otg_io_read(otg, ULPI_PID_HIGH) << 8) |
-	       otg_io_read(otg, ULPI_PID_LOW);
+	vid = (otg_io_read(otg, ULPI_VENDOR_ID_HIGH) << 8) |
+	       otg_io_read(otg, ULPI_VENDOR_ID_LOW);
+	pid = (otg_io_read(otg, ULPI_PRODUCT_ID_HIGH) << 8) |
+	       otg_io_read(otg, ULPI_PRODUCT_ID_LOW);
 
 	pr_info("ULPI transceiver vendor/product ID 0x%04x/0x%04x\n", vid, pid);
 
@@ -100,19 +78,19 @@
 
 static int ulpi_set_vbus(struct otg_transceiver *otg, bool on)
 {
-	unsigned int flags = otg_io_read(otg, ULPI_OTGCTL);
+	unsigned int flags = otg_io_read(otg, ULPI_OTG_CTRL);
 
-	flags &= ~(DRV_VBUS | DRV_VBUS_EXT);
+	flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT);
 
 	if (on) {
 		if (otg->flags & USB_OTG_DRV_VBUS)
-			flags |= DRV_VBUS;
+			flags |= ULPI_OTG_CTRL_DRVVBUS;
 
 		if (otg->flags & USB_OTG_DRV_VBUS_EXT)
-			flags |= DRV_VBUS_EXT;
+			flags |= ULPI_OTG_CTRL_DRVVBUS_EXT;
 	}
 
-	return otg_io_write(otg, flags, ULPI_OTGCTL + ULPI_REG_SET);
+	return otg_io_write(otg, flags, ULPI_SET(ULPI_OTG_CTRL));
 }
 
 struct otg_transceiver *
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index a0ecb42..bd8aab0 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -425,6 +425,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called mos7720.
 
+config USB_SERIAL_MOS7715_PARPORT
+	bool "Support for parallel port on the Moschip 7715"
+	depends on USB_SERIAL_MOS7720
+	depends on PARPORT=y || PARPORT=USB_SERIAL_MOS7720
+	select PARPORT_NOT_PC
+	---help---
+	Say Y if you have a Moschip 7715 device and would like to use
+	the parallel port it provides.  The port will register with
+	the parport subsystem as a low-level driver.
+
 config USB_SERIAL_MOS7840
 	tristate "USB Moschip 7840/7820 USB Serial Driver"
 	---help---
@@ -485,6 +495,7 @@
 
 config USB_SERIAL_QUALCOMM
 	tristate "USB Qualcomm Serial modem"
+	select USB_SERIAL_WWAN
 	help
 	  Say Y here if you have a Qualcomm USB modem device.  These are
 	  usually wireless cellular modems.
@@ -576,8 +587,12 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called keyspan_pda.
 
+config USB_SERIAL_WWAN
+	tristate
+
 config USB_SERIAL_OPTION
 	tristate "USB driver for GSM and CDMA modems"
+	select USB_SERIAL_WWAN
 	help
 	  Say Y here if you have a GSM or CDMA modem that's connected to USB.
 
@@ -619,6 +634,14 @@
           To compile this driver as a module, choose M here: the
           module will be called vivopay-serial.
 
+config USB_SERIAL_ZIO
+	tristate "ZIO Motherboard USB serial interface driver"
+	help
+	  Say Y here if you want to use ZIO Motherboard.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called zio.
+
 config USB_SERIAL_DEBUG
 	tristate "USB Debugging Device"
 	help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 83c9e43..e54c728 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -52,9 +52,11 @@
 obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS)		+= sierra.o
 obj-$(CONFIG_USB_SERIAL_SPCP8X5)		+= spcp8x5.o
 obj-$(CONFIG_USB_SERIAL_SYMBOL)			+= symbolserial.o
+obj-$(CONFIG_USB_SERIAL_WWAN)			+= usb_wwan.o
 obj-$(CONFIG_USB_SERIAL_TI)			+= ti_usb_3410_5052.o
 obj-$(CONFIG_USB_SERIAL_VISOR)			+= visor.o
 obj-$(CONFIG_USB_SERIAL_WHITEHEAT)		+= whiteheat.o
 obj-$(CONFIG_USB_SERIAL_XIRCOM)			+= keyspan_pda.o
 obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL)	+= vivopay-serial.o
+obj-$(CONFIG_USB_SERIAL_ZIO)			+= zio.o
 
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 4fd7af9..0db6ace 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -1,7 +1,9 @@
 /*
  * AIRcable USB Bluetooth Dongle Driver.
  *
+ * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com>
  * Copyright (C) 2006 Manuel Francisco Naranjo (naranjo.manuel@gmail.com)
+ *
  * This program is free software; you can redistribute it and/or modify it under
  * the terms of the GNU General Public License version 2 as published by the
  * Free Software Foundation.
@@ -42,10 +44,10 @@
  *
  */
 
+#include <asm/unaligned.h>
 #include <linux/tty.h>
 #include <linux/slab.h>
 #include <linux/tty_flip.h>
-#include <linux/circ_buf.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
@@ -55,16 +57,12 @@
 #define AIRCABLE_VID		0x16CA
 #define AIRCABLE_USB_PID	0x1502
 
-/* write buffer size defines */
-#define AIRCABLE_BUF_SIZE	2048
-
 /* Protocol Stuff */
 #define HCI_HEADER_LENGTH	0x4
 #define TX_HEADER_0		0x20
 #define TX_HEADER_1		0x29
 #define RX_HEADER_0		0x00
 #define RX_HEADER_1		0x20
-#define MAX_HCI_FRAMESIZE	60
 #define HCI_COMPLETE_FRAME	64
 
 /* rx_flags */
@@ -74,8 +72,8 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0b2"
-#define DRIVER_AUTHOR "Naranjo, Manuel Francisco <naranjo.manuel@gmail.com>"
+#define DRIVER_VERSION "v2.0"
+#define DRIVER_AUTHOR "Naranjo, Manuel Francisco <naranjo.manuel@gmail.com>, Johan Hovold <jhovold@gmail.com>"
 #define DRIVER_DESC "AIRcable USB Driver"
 
 /* ID table that will be registered with USB core */
@@ -85,226 +83,21 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-
-/* Internal Structure */
-struct aircable_private {
-	spinlock_t rx_lock;		/* spinlock for the receive lines */
-	struct circ_buf *tx_buf;	/* write buffer */
-	struct circ_buf *rx_buf;	/* read buffer */
-	int rx_flags;			/* for throttilng */
-	struct work_struct rx_work;	/* work cue for the receiving line */
-	struct usb_serial_port *port;	/* USB port with which associated */
-};
-
-/* Private methods */
-
-/* Circular Buffer Methods, code from ti_usb_3410_5052 used */
-/*
- * serial_buf_clear
- *
- * Clear out all data in the circular buffer.
- */
-static void serial_buf_clear(struct circ_buf *cb)
+static int aircable_prepare_write_buffer(struct usb_serial_port *port,
+						void *dest, size_t size)
 {
-	cb->head = cb->tail = 0;
-}
+	int count;
+	unsigned char *buf = dest;
 
-/*
- * serial_buf_alloc
- *
- * Allocate a circular buffer and all associated memory.
- */
-static struct circ_buf *serial_buf_alloc(void)
-{
-	struct circ_buf *cb;
-	cb = kmalloc(sizeof(struct circ_buf), GFP_KERNEL);
-	if (cb == NULL)
-		return NULL;
-	cb->buf = kmalloc(AIRCABLE_BUF_SIZE, GFP_KERNEL);
-	if (cb->buf == NULL) {
-		kfree(cb);
-		return NULL;
-	}
-	serial_buf_clear(cb);
-	return cb;
-}
-
-/*
- * serial_buf_free
- *
- * Free the buffer and all associated memory.
- */
-static void serial_buf_free(struct circ_buf *cb)
-{
-	kfree(cb->buf);
-	kfree(cb);
-}
-
-/*
- * serial_buf_data_avail
- *
- * Return the number of bytes of data available in the circular
- * buffer.
- */
-static int serial_buf_data_avail(struct circ_buf *cb)
-{
-	return CIRC_CNT(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
-}
-
-/*
- * serial_buf_put
- *
- * Copy data data from a user buffer and put it into the circular buffer.
- * Restrict to the amount of space available.
- *
- * Return the number of bytes copied.
- */
-static int serial_buf_put(struct circ_buf *cb, const char *buf, int count)
-{
-	int c, ret = 0;
-	while (1) {
-		c = CIRC_SPACE_TO_END(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
-		if (count < c)
-			c = count;
-		if (c <= 0)
-			break;
-		memcpy(cb->buf + cb->head, buf, c);
-		cb->head = (cb->head + c) & (AIRCABLE_BUF_SIZE-1);
-		buf += c;
-		count -= c;
-		ret = c;
-	}
-	return ret;
-}
-
-/*
- * serial_buf_get
- *
- * Get data from the circular buffer and copy to the given buffer.
- * Restrict to the amount of data available.
- *
- * Return the number of bytes copied.
- */
-static int serial_buf_get(struct circ_buf *cb, char *buf, int count)
-{
-	int c, ret = 0;
-	while (1) {
-		c = CIRC_CNT_TO_END(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
-		if (count < c)
-			c = count;
-		if (c <= 0)
-			break;
-		memcpy(buf, cb->buf + cb->tail, c);
-		cb->tail = (cb->tail + c) & (AIRCABLE_BUF_SIZE-1);
-		buf += c;
-		count -= c;
-		ret = c;
-	}
-	return ret;
-}
-
-/* End of circula buffer methods */
-
-static void aircable_send(struct usb_serial_port *port)
-{
-	int count, result;
-	struct aircable_private *priv = usb_get_serial_port_data(port);
-	unsigned char *buf;
-	__le16 *dbuf;
-	dbg("%s - port %d", __func__, port->number);
-	if (port->write_urb_busy)
-		return;
-
-	count = min(serial_buf_data_avail(priv->tx_buf), MAX_HCI_FRAMESIZE);
-	if (count == 0)
-		return;
-
-	buf = kzalloc(count + HCI_HEADER_LENGTH, GFP_ATOMIC);
-	if (!buf) {
-		dev_err(&port->dev, "%s- kzalloc(%d) failed.\n",
-			__func__, count + HCI_HEADER_LENGTH);
-		return;
-	}
-
+	count = kfifo_out_locked(&port->write_fifo, buf + HCI_HEADER_LENGTH,
+					size - HCI_HEADER_LENGTH, &port->lock);
 	buf[0] = TX_HEADER_0;
 	buf[1] = TX_HEADER_1;
-	dbuf = (__le16 *)&buf[2];
-	*dbuf = cpu_to_le16((u16)count);
-	serial_buf_get(priv->tx_buf, buf + HCI_HEADER_LENGTH,
-							MAX_HCI_FRAMESIZE);
+	put_unaligned_le16(count, &buf[2]);
 
-	memcpy(port->write_urb->transfer_buffer, buf,
-	       count + HCI_HEADER_LENGTH);
-
-	kfree(buf);
-	port->write_urb_busy = 1;
-	usb_serial_debug_data(debug, &port->dev, __func__,
-			      count + HCI_HEADER_LENGTH,
-			      port->write_urb->transfer_buffer);
-	port->write_urb->transfer_buffer_length = count + HCI_HEADER_LENGTH;
-	port->write_urb->dev = port->serial->dev;
-	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-
-	if (result) {
-		dev_err(&port->dev,
-			"%s - failed submitting write urb, error %d\n",
-			__func__, result);
-		port->write_urb_busy = 0;
-	}
-
-	schedule_work(&port->work);
+	return count + HCI_HEADER_LENGTH;
 }
 
-static void aircable_read(struct work_struct *work)
-{
-	struct aircable_private *priv =
-		container_of(work, struct aircable_private, rx_work);
-	struct usb_serial_port *port = priv->port;
-	struct tty_struct *tty;
-	unsigned char *data;
-	int count;
-	if (priv->rx_flags & THROTTLED) {
-		if (priv->rx_flags & ACTUALLY_THROTTLED)
-			schedule_work(&priv->rx_work);
-		return;
-	}
-
-	/* By now I will flush data to the tty in packages of no more than
-	 * 64 bytes, to ensure I do not get throttled.
-	 * Ask USB mailing list for better aproach.
-	 */
-	tty = tty_port_tty_get(&port->port);
-
-	if (!tty) {
-		schedule_work(&priv->rx_work);
-		dev_err(&port->dev, "%s - No tty available\n", __func__);
-		return ;
-	}
-
-	count = min(64, serial_buf_data_avail(priv->rx_buf));
-
-	if (count <= 0)
-		goto out; /* We have finished sending everything. */
-
-	tty_prepare_flip_string(tty, &data, count);
-	if (!data) {
-		dev_err(&port->dev, "%s- kzalloc(%d) failed.",
-							__func__, count);
-		goto out;
-	}
-
-	serial_buf_get(priv->rx_buf, data, count);
-
-	tty_flip_buffer_push(tty);
-
-	if (serial_buf_data_avail(priv->rx_buf))
-		schedule_work(&priv->rx_work);
-out:		
-	tty_kref_put(tty);
-	return;
-}
-/* End of private methods */
-
 static int aircable_probe(struct usb_serial *serial,
 			  const struct usb_device_id *id)
 {
@@ -330,247 +123,50 @@
 	return 0;
 }
 
-static int aircable_attach(struct usb_serial *serial)
+static int aircable_process_packet(struct tty_struct *tty,
+			struct usb_serial_port *port, int has_headers,
+			char *packet, int len)
 {
-	struct usb_serial_port *port = serial->port[0];
-	struct aircable_private *priv;
-
-	priv = kzalloc(sizeof(struct aircable_private), GFP_KERNEL);
-	if (!priv) {
-		dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
-			sizeof(struct aircable_private));
-		return -ENOMEM;
+	if (has_headers) {
+		len -= HCI_HEADER_LENGTH;
+		packet += HCI_HEADER_LENGTH;
+	}
+	if (len <= 0) {
+		dbg("%s - malformed packet", __func__);
+		return 0;
 	}
 
-	/* Allocation of Circular Buffers */
-	priv->tx_buf = serial_buf_alloc();
-	if (priv->tx_buf == NULL) {
-		kfree(priv);
-		return -ENOMEM;
-	}
+	tty_insert_flip_string(tty, packet, len);
 
-	priv->rx_buf = serial_buf_alloc();
-	if (priv->rx_buf == NULL) {
-		kfree(priv->tx_buf);
-		kfree(priv);
-		return -ENOMEM;
-	}
-
-	priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
-	priv->port = port;
-	INIT_WORK(&priv->rx_work, aircable_read);
-
-	usb_set_serial_port_data(serial->port[0], priv);
-
-	return 0;
+	return len;
 }
 
-static void aircable_release(struct usb_serial *serial)
-{
-
-	struct usb_serial_port *port = serial->port[0];
-	struct aircable_private *priv = usb_get_serial_port_data(port);
-
-	dbg("%s", __func__);
-
-	if (priv) {
-		serial_buf_free(priv->tx_buf);
-		serial_buf_free(priv->rx_buf);
-		kfree(priv);
-	}
-}
-
-static int aircable_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct aircable_private *priv = usb_get_serial_port_data(port);
-	return serial_buf_data_avail(priv->tx_buf);
-}
-
-static int aircable_write(struct tty_struct *tty, struct usb_serial_port *port,
-			  const unsigned char *source, int count)
-{
-	struct aircable_private *priv = usb_get_serial_port_data(port);
-	int temp;
-
-	dbg("%s - port %d, %d bytes", __func__, port->number, count);
-
-	usb_serial_debug_data(debug, &port->dev, __func__, count, source);
-
-	if (!count) {
-		dbg("%s - write request of 0 bytes", __func__);
-		return count;
-	}
-
-	temp = serial_buf_put(priv->tx_buf, source, count);
-
-	aircable_send(port);
-
-	if (count > AIRCABLE_BUF_SIZE)
-		count = AIRCABLE_BUF_SIZE;
-
-	return count;
-
-}
-
-static void aircable_write_bulk_callback(struct urb *urb)
+static void aircable_process_read_urb(struct urb *urb)
 {
 	struct usb_serial_port *port = urb->context;
-	int status = urb->status;
-	int result;
-
-	dbg("%s - urb status: %d", __func__ , status);
-
-	/* This has been taken from cypress_m8.c cypress_write_int_callback */
-	switch (status) {
-	case 0:
-		/* success */
-		break;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, status);
-		port->write_urb_busy = 0;
-		return;
-	default:
-		/* error in the urb, so we have to resubmit it */
-		dbg("%s - Overflow in write", __func__);
-		dbg("%s - nonzero write bulk status received: %d",
-		    __func__, status);
-		port->write_urb->transfer_buffer_length = 1;
-		port->write_urb->dev = port->serial->dev;
-		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-		if (result)
-			dev_err(&urb->dev->dev,
-			    "%s - failed resubmitting write urb, error %d\n",
-							__func__, result);
-		else
-			return;
-	}
-
-	port->write_urb_busy = 0;
-
-	aircable_send(port);
-}
-
-static void aircable_read_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = urb->context;
-	struct aircable_private *priv = usb_get_serial_port_data(port);
+	char *data = (char *)urb->transfer_buffer;
 	struct tty_struct *tty;
-	unsigned long no_packages, remaining, package_length, i;
-	int result, shift = 0;
-	unsigned char *temp;
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (status) {
-		dbg("%s - urb status = %d", __func__, status);
-		if (status == -EPROTO) {
-			dbg("%s - caught -EPROTO, resubmitting the urb",
-			    __func__);
-			usb_fill_bulk_urb(port->read_urb, port->serial->dev,
-				usb_rcvbulkpipe(port->serial->dev,
-					port->bulk_in_endpointAddress),
-				port->read_urb->transfer_buffer,
-				port->read_urb->transfer_buffer_length,
-				aircable_read_bulk_callback, port);
-
-			result = usb_submit_urb(urb, GFP_ATOMIC);
-			if (result)
-				dev_err(&urb->dev->dev,
-					"%s - failed resubmitting read urb, error %d\n",
-					__func__, result);
-			return;
-		}
-		dbg("%s - unable to handle the error, exiting.", __func__);
-		return;
-	}
-
-	usb_serial_debug_data(debug, &port->dev, __func__,
-				urb->actual_length, urb->transfer_buffer);
+	int has_headers;
+	int count;
+	int len;
+	int i;
 
 	tty = tty_port_tty_get(&port->port);
-	if (tty && urb->actual_length) {
-		if (urb->actual_length <= 2) {
-			/* This is an incomplete package */
-			serial_buf_put(priv->rx_buf, urb->transfer_buffer,
-				       urb->actual_length);
-		} else {
-			temp = urb->transfer_buffer;
-			if (temp[0] == RX_HEADER_0)
-				shift = HCI_HEADER_LENGTH;
+	if (!tty)
+		return;
 
-			remaining = urb->actual_length;
-			no_packages = urb->actual_length / (HCI_COMPLETE_FRAME);
+	has_headers = (urb->actual_length > 2 && data[0] == RX_HEADER_0);
 
-			if (urb->actual_length % HCI_COMPLETE_FRAME != 0)
-				no_packages++;
-
-			for (i = 0; i < no_packages; i++) {
-				if (remaining > (HCI_COMPLETE_FRAME))
-					package_length = HCI_COMPLETE_FRAME;
-				else
-					package_length = remaining;
-				remaining -= package_length;
-
-				serial_buf_put(priv->rx_buf,
-					urb->transfer_buffer + shift +
-					(HCI_COMPLETE_FRAME) * (i),
-					package_length - shift);
-			}
-		}
-		aircable_read(&priv->rx_work);
+	count = 0;
+	for (i = 0; i < urb->actual_length; i += HCI_COMPLETE_FRAME) {
+		len = min_t(int, urb->actual_length - i, HCI_COMPLETE_FRAME);
+		count += aircable_process_packet(tty, port, has_headers,
+								&data[i], len);
 	}
+
+	if (count)
+		tty_flip_buffer_push(tty);
 	tty_kref_put(tty);
-
-	/* Schedule the next read */
-	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
-			  usb_rcvbulkpipe(port->serial->dev,
-				  port->bulk_in_endpointAddress),
-			  port->read_urb->transfer_buffer,
-			  port->read_urb->transfer_buffer_length,
-			  aircable_read_bulk_callback, port);
-
-	result = usb_submit_urb(urb, GFP_ATOMIC);
-	if (result && result != -EPERM)
-		dev_err(&urb->dev->dev,
-			"%s - failed resubmitting read urb, error %d\n",
-			__func__, result);
-}
-
-/* Based on ftdi_sio.c throttle */
-static void aircable_throttle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct aircable_private *priv = usb_get_serial_port_data(port);
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irq(&priv->rx_lock);
-	priv->rx_flags |= THROTTLED;
-	spin_unlock_irq(&priv->rx_lock);
-}
-
-/* Based on ftdi_sio.c unthrottle */
-static void aircable_unthrottle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct aircable_private *priv = usb_get_serial_port_data(port);
-	int actually_throttled;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irq(&priv->rx_lock);
-	actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
-	priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
-	spin_unlock_irq(&priv->rx_lock);
-
-	if (actually_throttled)
-		schedule_work(&priv->rx_work);
 }
 
 static struct usb_driver aircable_driver = {
@@ -589,15 +185,12 @@
 	.usb_driver = 		&aircable_driver,
 	.id_table = 		id_table,
 	.num_ports =		1,
-	.attach =		aircable_attach,
+	.bulk_out_size =	HCI_COMPLETE_FRAME,
 	.probe =		aircable_probe,
-	.release =		aircable_release,
-	.write =		aircable_write,
-	.write_room =		aircable_write_room,
-	.write_bulk_callback =	aircable_write_bulk_callback,
-	.read_bulk_callback =	aircable_read_bulk_callback,
-	.throttle =		aircable_throttle,
-	.unthrottle =		aircable_unthrottle,
+	.process_read_urb =	aircable_process_read_urb,
+	.prepare_write_buffer =	aircable_prepare_write_buffer,
+	.throttle =		usb_serial_generic_throttle,
+	.unthrottle =		usb_serial_generic_unthrottle,
 };
 
 static int __init aircable_init(void)
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 9b66bf1..4e41a2a 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -42,7 +42,7 @@
  * Version information
  */
 
-#define DRIVER_VERSION "v0.5"
+#define DRIVER_VERSION "v0.6"
 #define DRIVER_AUTHOR "Bart Hartgers <bart.hartgers+ark3116@gmail.com>"
 #define DRIVER_DESC "USB ARK3116 serial/IrDA driver"
 #define DRIVER_DEV_DESC "ARK3116 RS232/IrDA"
@@ -355,14 +355,11 @@
 		/* deactivate interrupts */
 		ark3116_write_reg(serial, UART_IER, 0);
 
-		/* shutdown any bulk reads that might be going on */
-		if (serial->num_bulk_out)
-			usb_kill_urb(port->write_urb);
-		if (serial->num_bulk_in)
-			usb_kill_urb(port->read_urb);
+		usb_serial_generic_close(port);
 		if (serial->num_interrupt_in)
 			usb_kill_urb(port->interrupt_in_urb);
 	}
+
 }
 
 static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -675,87 +672,45 @@
  * error for the next block of data as well...
  * For now, let's pretend this can't happen.
  */
-
-static void send_to_tty(struct tty_struct *tty,
-			const unsigned char *chars,
-			size_t size, char flag)
+static void ark3116_process_read_urb(struct urb *urb)
 {
-	if (size == 0)
-		return;
-	if (flag == TTY_NORMAL) {
-		tty_insert_flip_string(tty, chars, size);
-	} else {
-		int i;
-		for (i = 0; i < size; ++i)
-			tty_insert_flip_char(tty, chars[i], flag);
-	}
-}
-
-static void ark3116_read_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port =  urb->context;
+	struct usb_serial_port *port = urb->context;
 	struct ark3116_private *priv = usb_get_serial_port_data(port);
-	const __u8 *data = urb->transfer_buffer;
-	int status = urb->status;
 	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+	char tty_flag = TTY_NORMAL;
 	unsigned long flags;
-	int result;
-	char flag;
 	__u32 lsr;
 
-	switch (status) {
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __func__, status);
+	/* update line status */
+	spin_lock_irqsave(&priv->status_lock, flags);
+	lsr = priv->lsr;
+	priv->lsr &= ~UART_LSR_BRK_ERROR_BITS;
+	spin_unlock_irqrestore(&priv->status_lock, flags);
+
+	if (!urb->actual_length)
 		return;
-	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __func__, status);
-		break;
-	case 0: /* success */
 
-		spin_lock_irqsave(&priv->status_lock, flags);
-		lsr = priv->lsr;
-		/* clear error bits */
-		priv->lsr &= ~UART_LSR_BRK_ERROR_BITS;
-		spin_unlock_irqrestore(&priv->status_lock, flags);
+	tty = tty_port_tty_get(&port->port);
+	if (!tty)
+		return;
 
-		if (unlikely(lsr & UART_LSR_BI))
-			flag = TTY_BREAK;
-		else if (unlikely(lsr & UART_LSR_PE))
-			flag = TTY_PARITY;
-		else if (unlikely(lsr & UART_LSR_FE))
-			flag = TTY_FRAME;
-		else
-			flag = TTY_NORMAL;
+	if (lsr & UART_LSR_BRK_ERROR_BITS) {
+		if (lsr & UART_LSR_BI)
+			tty_flag = TTY_BREAK;
+		else if (lsr & UART_LSR_PE)
+			tty_flag = TTY_PARITY;
+		else if (lsr & UART_LSR_FE)
+			tty_flag = TTY_FRAME;
 
-		tty = tty_port_tty_get(&port->port);
-		if (tty) {
-			/* overrun is special, not associated with a char */
-			if (unlikely(lsr & UART_LSR_OE))
-				tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-			send_to_tty(tty, data, urb->actual_length, flag);
-			tty_flip_buffer_push(tty);
-			tty_kref_put(tty);
-		}
-
-		/* Throttle the device if requested by tty */
-		spin_lock_irqsave(&port->lock, flags);
-		port->throttled = port->throttle_req;
-		if (port->throttled) {
-			spin_unlock_irqrestore(&port->lock, flags);
-			return;
-		} else
-			spin_unlock_irqrestore(&port->lock, flags);
+		/* overrun is special, not associated with a char */
+		if (lsr & UART_LSR_OE)
+			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
 	}
-	/* Continue reading from device */
-	result = usb_submit_urb(urb, GFP_ATOMIC);
-	if (result)
-		dev_err(&urb->dev->dev, "%s - failed resubmitting"
-			" read urb, error %d\n", __func__, result);
+	tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
+							urb->actual_length);
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
 }
 
 static struct usb_driver ark3116_driver = {
@@ -785,7 +740,7 @@
 	.close =		ark3116_close,
 	.break_ctl = 		ark3116_break_ctl,
 	.read_int_callback = 	ark3116_read_int_callback,
-	.read_bulk_callback =	ark3116_read_bulk_callback,
+	.process_read_urb =	ark3116_process_read_urb,
 };
 
 static int __init ark3116_init(void)
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 1295e44..36df352 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2000		William Greathouse (wgreathouse@smva.com)
  *  Copyright (C) 2000-2001 	Greg Kroah-Hartman (greg@kroah.com)
+ *  Copyright (C) 2010		Johan Hovold (jhovold@gmail.com)
  *
  *  This program is largely derived from work by the linux-usb group
  *  and associated source files.  Please see the usb/serial files for
@@ -84,7 +85,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.2"
+#define DRIVER_VERSION "v1.3"
 #define DRIVER_AUTHOR "William Greathouse <wgreathouse@smva.com>"
 #define DRIVER_DESC "USB Belkin Serial converter driver"
 
@@ -95,6 +96,7 @@
 			struct usb_serial_port *port);
 static void belkin_sa_close(struct usb_serial_port *port);
 static void belkin_sa_read_int_callback(struct urb *urb);
+static void belkin_sa_process_read_urb(struct urb *urb);
 static void belkin_sa_set_termios(struct tty_struct *tty,
 			struct usb_serial_port *port, struct ktermios * old);
 static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state);
@@ -112,7 +114,6 @@
 	{ USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) },
 	{ }	/* Terminating entry */
 };
-
 MODULE_DEVICE_TABLE(usb, id_table_combined);
 
 static struct usb_driver belkin_driver = {
@@ -120,7 +121,7 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table_combined,
-	.no_dynamic_id = 	1,
+	.no_dynamic_id =	1,
 };
 
 /* All of the device info needed for the serial converters */
@@ -136,7 +137,7 @@
 	.open =			belkin_sa_open,
 	.close =		belkin_sa_close,
 	.read_int_callback =	belkin_sa_read_int_callback,
-					/* How we get the status info */
+	.process_read_urb =	belkin_sa_process_read_urb,
 	.set_termios =		belkin_sa_set_termios,
 	.break_ctl =		belkin_sa_break_ctl,
 	.tiocmget =		belkin_sa_tiocmget,
@@ -145,7 +146,6 @@
 	.release =		belkin_sa_release,
 };
 
-
 struct belkin_sa_private {
 	spinlock_t		lock;
 	unsigned long		control_state;
@@ -196,62 +196,43 @@
 	return 0;
 }
 
-
 static void belkin_sa_release(struct usb_serial *serial)
 {
-	struct belkin_sa_private *priv;
 	int i;
 
 	dbg("%s", __func__);
 
-	for (i = 0; i < serial->num_ports; ++i) {
-		/* My special items, the standard routines free my urbs */
-		priv = usb_get_serial_port_data(serial->port[i]);
-		kfree(priv);
-	}
+	for (i = 0; i < serial->num_ports; ++i)
+		kfree(usb_get_serial_port_data(serial->port[i]));
 }
 
-
-static int  belkin_sa_open(struct tty_struct *tty,
+static int belkin_sa_open(struct tty_struct *tty,
 					struct usb_serial_port *port)
 {
-	int retval = 0;
+	int retval;
 
 	dbg("%s port %d", __func__, port->number);
 
-	/*Start reading from the device*/
-	/* TODO: Look at possibility of submitting multiple URBs to device to
-	 *       enhance buffering.  Win trace shows 16 initial read URBs.
-	 */
-	port->read_urb->dev = port->serial->dev;
-	retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
-	if (retval) {
-		dev_err(&port->dev, "usb_submit_urb(read bulk) failed\n");
-		goto exit;
-	}
-
-	port->interrupt_in_urb->dev = port->serial->dev;
 	retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (retval) {
-		usb_kill_urb(port->read_urb);
 		dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
+		return retval;
 	}
 
-exit:
-	return retval;
-} /* belkin_sa_open */
+	retval = usb_serial_generic_open(tty, port);
+	if (retval)
+		usb_kill_urb(port->interrupt_in_urb);
 
+	return retval;
+}
 
 static void belkin_sa_close(struct usb_serial_port *port)
 {
 	dbg("%s port %d", __func__, port->number);
 
-	/* shutdown our bulk reads and writes */
-	usb_kill_urb(port->write_urb);
-	usb_kill_urb(port->read_urb);
+	usb_serial_generic_close(port);
 	usb_kill_urb(port->interrupt_in_urb);
-} /* belkin_sa_close */
-
+}
 
 static void belkin_sa_read_int_callback(struct urb *urb)
 {
@@ -310,31 +291,7 @@
 	else
 		priv->control_state &= ~TIOCM_CD;
 
-	/* Now to report any errors */
 	priv->last_lsr = data[BELKIN_SA_LSR_INDEX];
-#if 0
-	/*
-	 * fill in the flip buffer here, but I do not know the relation
-	 * to the current/next receive buffer or characters.  I need
-	 * to look in to this before committing any code.
-	 */
-	if (priv->last_lsr & BELKIN_SA_LSR_ERR) {
-		tty = tty_port_tty_get(&port->port);
-		/* Overrun Error */
-		if (priv->last_lsr & BELKIN_SA_LSR_OE) {
-		}
-		/* Parity Error */
-		if (priv->last_lsr & BELKIN_SA_LSR_PE) {
-		}
-		/* Framing Error */
-		if (priv->last_lsr & BELKIN_SA_LSR_FE) {
-		}
-		/* Break Indicator */
-		if (priv->last_lsr & BELKIN_SA_LSR_BI) {
-		}
-		tty_kref_put(tty);
-	}
-#endif
 	spin_unlock_irqrestore(&priv->lock, flags);
 exit:
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -343,6 +300,53 @@
 			"result %d\n", __func__, retval);
 }
 
+static void belkin_sa_process_read_urb(struct urb *urb)
+{
+	struct usb_serial_port *port = urb->context;
+	struct belkin_sa_private *priv = usb_get_serial_port_data(port);
+	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+	unsigned long flags;
+	unsigned char status;
+	char tty_flag;
+
+	/* Update line status */
+	tty_flag = TTY_NORMAL;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	status = priv->last_lsr;
+	priv->last_lsr &= ~BELKIN_SA_LSR_ERR;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (!urb->actual_length)
+		return;
+
+	tty = tty_port_tty_get(&port->port);
+	if (!tty)
+		return;
+
+	if (status & BELKIN_SA_LSR_ERR) {
+		/* Break takes precedence over parity, which takes precedence
+		 * over framing errors. */
+		if (status & BELKIN_SA_LSR_BI)
+			tty_flag = TTY_BREAK;
+		else if (status & BELKIN_SA_LSR_PE)
+			tty_flag = TTY_PARITY;
+		else if (status & BELKIN_SA_LSR_FE)
+			tty_flag = TTY_FRAME;
+		dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
+
+		/* Overrun is special, not associated with a char. */
+		if (status & BELKIN_SA_LSR_OE)
+			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+	}
+
+	tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
+							urb->actual_length);
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+}
+
 static void belkin_sa_set_termios(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -482,8 +486,7 @@
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->control_state = control_state;
 	spin_unlock_irqrestore(&priv->lock, flags);
-} /* belkin_sa_set_termios */
-
+}
 
 static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state)
 {
@@ -494,7 +497,6 @@
 		dev_err(&port->dev, "Set break_ctl %d\n", break_state);
 }
 
-
 static int belkin_sa_tiocmget(struct tty_struct *tty, struct file *file)
 {
 	struct usb_serial_port *port = tty->driver_data;
@@ -511,7 +513,6 @@
 	return control_state;
 }
 
-
 static int belkin_sa_tiocmset(struct tty_struct *tty, struct file *file,
 			       unsigned int set, unsigned int clear)
 {
@@ -583,7 +584,6 @@
 	return retval;
 }
 
-
 static void __exit belkin_sa_exit (void)
 {
 	usb_deregister(&belkin_driver);
diff --git a/drivers/usb/serial/belkin_sa.h b/drivers/usb/serial/belkin_sa.h
index c66a673..c74b58a 100644
--- a/drivers/usb/serial/belkin_sa.h
+++ b/drivers/usb/serial/belkin_sa.h
@@ -8,10 +8,10 @@
  *  and associated source files.  Please see the usb/serial files for
  *  individual credits and copyrights.
  *
- * 	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 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.
  *
  * See Documentation/usb/usb-serial.txt for more information on using this
  * driver
@@ -66,7 +66,7 @@
 #ifdef WHEN_I_LEARN_THIS
 #define BELKIN_SA_SET_MAGIC_REQUEST	17 /* I don't know, possibly flush */
 					   /* (always in Wininit sequence before flow control) */
-#define BELKIN_SA_RESET 		xx /* Reset the port */
+#define BELKIN_SA_RESET			xx /* Reset the port */
 #define BELKIN_SA_GET_MODEM_STATUS	xx /* Force return of modem status register */
 #endif
 
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 7e8e398..63f7cc4 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -305,10 +305,7 @@
 {
 	dbg("%s - port %d", __func__, port->number);
 
-	/* shutdown our urbs */
-	dbg("%s - shutting down urbs", __func__);
-	usb_kill_urb(port->write_urb);
-	usb_kill_urb(port->read_urb);
+	usb_serial_generic_close(port);
 	usb_kill_urb(port->interrupt_in_urb);
 }
 
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index f347da2..1ee6b2a 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -66,7 +66,7 @@
 	struct usb_serial_port *port;
 	int retval;
 	struct tty_struct *tty = NULL;
-	struct ktermios *termios = NULL, dummy;
+	struct ktermios dummy;
 
 	dbg("%s", __func__);
 
@@ -141,15 +141,14 @@
 				goto reset_open_count;
 			}
 			kref_init(&tty->kref);
-			termios = kzalloc(sizeof(*termios), GFP_KERNEL);
-			if (!termios) {
+			tty_port_tty_set(&port->port, tty);
+			tty->driver = usb_serial_tty_driver;
+			tty->index = co->index;
+			if (tty_init_termios(tty)) {
 				retval = -ENOMEM;
 				err("no more memory");
 				goto free_tty;
 			}
-			memset(&dummy, 0, sizeof(struct ktermios));
-			tty->termios = termios;
-			tty_port_tty_set(&port->port, tty);
 		}
 
 		/* only call the device specific open if this
@@ -161,16 +160,16 @@
 
 		if (retval) {
 			err("could not open USB console port");
-			goto free_termios;
+			goto fail;
 		}
 
 		if (serial->type->set_termios) {
-			termios->c_cflag = cflag;
-			tty_termios_encode_baud_rate(termios, baud, baud);
+			tty->termios->c_cflag = cflag;
+			tty_termios_encode_baud_rate(tty->termios, baud, baud);
+			memset(&dummy, 0, sizeof(struct ktermios));
 			serial->type->set_termios(tty, port, &dummy);
 
 			tty_port_tty_set(&port->port, NULL);
-			kfree(termios);
 			kfree(tty);
 		}
 		set_bit(ASYNCB_INITIALIZED, &port->port.flags);
@@ -180,14 +179,12 @@
 	--port->port.count;
 	/* The console is special in terms of closing the device so
 	 * indicate this port is now acting as a system console. */
-	port->console = 1;
 	port->port.console = 1;
 
 	mutex_unlock(&serial->disc_mutex);
 	return retval;
 
- free_termios:
-	kfree(termios);
+ fail:
 	tty_port_tty_set(&port->port, NULL);
  free_tty:
 	kfree(tty);
@@ -217,7 +214,7 @@
 
 	dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
 
-	if (!port->console) {
+	if (!port->port.console) {
 		dbg("%s - port not opened", __func__);
 		return;
 	}
@@ -313,7 +310,7 @@
 {
 	if (usbcons_info.port) {
 		unregister_console(&usbcons);
-		usbcons_info.port->console = 0;
+		usbcons_info.port->port.console = 0;
 		usbcons_info.port = NULL;
 	}
 }
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index ec9b044..8b8c797 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -34,7 +34,6 @@
  * Function Prototypes
  */
 static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);
-static void cp210x_cleanup(struct usb_serial_port *);
 static void cp210x_close(struct usb_serial_port *);
 static void cp210x_get_termios(struct tty_struct *,
 	struct usb_serial_port *port);
@@ -49,7 +48,6 @@
 		unsigned int, unsigned int);
 static void cp210x_break_ctl(struct tty_struct *, int);
 static int cp210x_startup(struct usb_serial *);
-static void cp210x_disconnect(struct usb_serial *);
 static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
 static int cp210x_carrier_raised(struct usb_serial_port *p);
 
@@ -61,6 +59,8 @@
 	{ USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */
 	{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
 	{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
+	{ USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
+	{ USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */
 	{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
 	{ USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
 	{ USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */
@@ -72,9 +72,12 @@
 	{ USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */
 	{ USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
 	{ USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
+	{ USB_DEVICE(0x10C4, 0x8044) }, /* Cygnal Debug Adapter */
+	{ USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */
 	{ USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
 	{ USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */
 	{ USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
+	{ USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */
 	{ USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
 	{ USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
 	{ USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */
@@ -82,12 +85,15 @@
 	{ USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */
 	{ USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
 	{ USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */
+	{ USB_DEVICE(0x10C4, 0x8149) }, /* West Mountain Radio Computerized Battery Analyzer */
 	{ USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
 	{ USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
 	{ USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
+	{ USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */
 	{ USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */
 	{ USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */
 	{ USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
+	{ USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */
 	{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
 	{ USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
 	{ USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
@@ -105,6 +111,7 @@
 	{ USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
 	{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
 	{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
+	{ USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */
 	{ USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
 	{ USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
 	{ USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */
@@ -115,6 +122,8 @@
 	{ USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */
 	{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
 	{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
+	{ USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
+	{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
 	{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
 	{ USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
 	{ } /* Terminating Entry */
@@ -138,6 +147,8 @@
 	.usb_driver		= &cp210x_driver,
 	.id_table		= id_table,
 	.num_ports		= 1,
+	.bulk_in_size		= 256,
+	.bulk_out_size		= 256,
 	.open			= cp210x_open,
 	.close			= cp210x_close,
 	.break_ctl		= cp210x_break_ctl,
@@ -145,7 +156,6 @@
 	.tiocmget 		= cp210x_tiocmget,
 	.tiocmset		= cp210x_tiocmset,
 	.attach			= cp210x_startup,
-	.disconnect		= cp210x_disconnect,
 	.dtr_rts		= cp210x_dtr_rts,
 	.carrier_raised		= cp210x_carrier_raised
 };
@@ -370,7 +380,6 @@
 
 static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
-	struct usb_serial *serial = port->serial;
 	int result;
 
 	dbg("%s - port %d", __func__, port->number);
@@ -381,49 +390,20 @@
 		return -EPROTO;
 	}
 
-	/* Start reading from the device */
-	usb_fill_bulk_urb(port->read_urb, serial->dev,
-			usb_rcvbulkpipe(serial->dev,
-			port->bulk_in_endpointAddress),
-			port->read_urb->transfer_buffer,
-			port->read_urb->transfer_buffer_length,
-			serial->type->read_bulk_callback,
-			port);
-	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-	if (result) {
-		dev_err(&port->dev, "%s - failed resubmitting read urb, "
-				"error %d\n", __func__, result);
+	result = usb_serial_generic_open(tty, port);
+	if (result)
 		return result;
-	}
 
 	/* Configure the termios structure */
 	cp210x_get_termios(tty, port);
 	return 0;
 }
 
-static void cp210x_cleanup(struct usb_serial_port *port)
-{
-	struct usb_serial *serial = port->serial;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (serial->dev) {
-		/* shutdown any bulk reads that might be going on */
-		if (serial->num_bulk_out)
-			usb_kill_urb(port->write_urb);
-		if (serial->num_bulk_in)
-			usb_kill_urb(port->read_urb);
-	}
-}
-
 static void cp210x_close(struct usb_serial_port *port)
 {
 	dbg("%s - port %d", __func__, port->number);
 
-	/* shutdown our urbs */
-	dbg("%s - shutting down urbs", __func__);
-	usb_kill_urb(port->write_urb);
-	usb_kill_urb(port->read_urb);
+	usb_serial_generic_close(port);
 
 	mutex_lock(&port->serial->disc_mutex);
 	if (!port->serial->disconnected)
@@ -807,17 +787,6 @@
 	return 0;
 }
 
-static void cp210x_disconnect(struct usb_serial *serial)
-{
-	int i;
-
-	dbg("%s", __func__);
-
-	/* Stop reads and writes on all ports */
-	for (i = 0; i < serial->num_ports; ++i)
-		cp210x_cleanup(serial->port[i]);
-}
-
 static int __init cp210x_init(void)
 {
 	int retval;
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index e23c779..f5d0674 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -64,6 +64,7 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 #include <linux/serial.h>
+#include <linux/kfifo.h>
 #include <linux/delay.h>
 #include <linux/uaccess.h>
 #include <asm/unaligned.h>
@@ -79,13 +80,12 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.09"
+#define DRIVER_VERSION "v1.10"
 #define DRIVER_AUTHOR "Lonnie Mendez <dignome@gmail.com>, Neil Whelchel <koyama@firstlight.net>"
 #define DRIVER_DESC "Cypress USB to Serial Driver"
 
 /* write buffer size defines */
 #define CYPRESS_BUF_SIZE	1024
-#define CYPRESS_CLOSING_WAIT	(30*HZ)
 
 static const struct usb_device_id id_table_earthmate[] = {
 	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
@@ -135,7 +135,7 @@
 	int bytes_out;			   /* used for statistics */
 	int cmd_count;			   /* used for statistics */
 	int cmd_ctrl;			   /* always set this to 1 before issuing a command */
-	struct cypress_buf *buf;	   /* write buffer */
+	struct kfifo write_fifo;	   /* write fifo */
 	int write_urb_in_use;		   /* write urb in use indicator */
 	int write_urb_interval;            /* interval to use for write urb */
 	int read_urb_interval;             /* interval to use for read urb */
@@ -157,14 +157,6 @@
 	struct ktermios tmp_termios; 	   /* stores the old termios settings */
 };
 
-/* write buffer structure */
-struct cypress_buf {
-	unsigned int	buf_size;
-	char		*buf_buf;
-	char		*buf_get;
-	char		*buf_put;
-};
-
 /* function prototypes for the Cypress USB to serial device */
 static int  cypress_earthmate_startup(struct usb_serial *serial);
 static int  cypress_hidcom_startup(struct usb_serial *serial);
@@ -190,17 +182,6 @@
 static void cypress_set_dead(struct usb_serial_port *port);
 static void cypress_read_int_callback(struct urb *urb);
 static void cypress_write_int_callback(struct urb *urb);
-/* write buffer functions */
-static struct cypress_buf *cypress_buf_alloc(unsigned int size);
-static void cypress_buf_free(struct cypress_buf *cb);
-static void cypress_buf_clear(struct cypress_buf *cb);
-static unsigned int cypress_buf_data_avail(struct cypress_buf *cb);
-static unsigned int cypress_buf_space_avail(struct cypress_buf *cb);
-static unsigned int cypress_buf_put(struct cypress_buf *cb,
-					const char *buf, unsigned int count);
-static unsigned int cypress_buf_get(struct cypress_buf *cb,
-					char *buf, unsigned int count);
-
 
 static struct usb_serial_driver cypress_earthmate_device = {
 	.driver = {
@@ -503,8 +484,7 @@
 
 	priv->comm_is_ok = !0;
 	spin_lock_init(&priv->lock);
-	priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE);
-	if (priv->buf == NULL) {
+	if (kfifo_alloc(&priv->write_fifo, CYPRESS_BUF_SIZE, GFP_KERNEL)) {
 		kfree(priv);
 		return -ENOMEM;
 	}
@@ -627,7 +607,7 @@
 	priv = usb_get_serial_port_data(serial->port[0]);
 
 	if (priv) {
-		cypress_buf_free(priv->buf);
+		kfifo_free(&priv->write_fifo);
 		kfree(priv);
 	}
 }
@@ -704,6 +684,7 @@
 static void cypress_close(struct usb_serial_port *port)
 {
 	struct cypress_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
 
 	dbg("%s - port %d", __func__, port->number);
 
@@ -713,12 +694,14 @@
 		mutex_unlock(&port->serial->disc_mutex);
 		return;
 	}
-	cypress_buf_clear(priv->buf);
+	spin_lock_irqsave(&priv->lock, flags);
+	kfifo_reset_out(&priv->write_fifo);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
 	dbg("%s - stopping urbs", __func__);
 	usb_kill_urb(port->interrupt_in_urb);
 	usb_kill_urb(port->interrupt_out_urb);
 
-
 	if (stats)
 		dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
 			priv->bytes_in, priv->bytes_out, priv->cmd_count);
@@ -730,7 +713,6 @@
 					const unsigned char *buf, int count)
 {
 	struct cypress_private *priv = usb_get_serial_port_data(port);
-	unsigned long flags;
 
 	dbg("%s - port %d, %d bytes", __func__, port->number, count);
 
@@ -745,9 +727,7 @@
 	if (!count)
 		return count;
 
-	spin_lock_irqsave(&priv->lock, flags);
-	count = cypress_buf_put(priv->buf, buf, count);
-	spin_unlock_irqrestore(&priv->lock, flags);
+	count = kfifo_in_locked(&priv->write_fifo, buf, count, &priv->lock);
 
 finish:
 	cypress_send(port);
@@ -807,9 +787,10 @@
 	} else
 		spin_unlock_irqrestore(&priv->lock, flags);
 
-	count = cypress_buf_get(priv->buf, &port->interrupt_out_buffer[offset],
-				port->interrupt_out_size-offset);
-
+	count = kfifo_out_locked(&priv->write_fifo,
+					&port->interrupt_out_buffer[offset],
+					port->interrupt_out_size - offset,
+					&priv->lock);
 	if (count == 0)
 		return;
 
@@ -875,7 +856,7 @@
 	dbg("%s - port %d", __func__, port->number);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	room = cypress_buf_space_avail(priv->buf);
+	room = kfifo_avail(&priv->write_fifo);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	dbg("%s - returns %d", __func__, room);
@@ -1143,7 +1124,7 @@
 	dbg("%s - port %d", __func__, port->number);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	chars = cypress_buf_data_avail(priv->buf);
+	chars = kfifo_len(&priv->write_fifo);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	dbg("%s - returns %d", __func__, chars);
@@ -1309,7 +1290,7 @@
 	/* process read if there is data other than line status */
 	if (tty && bytes > i) {
 		tty_insert_flip_string_fixed_flag(tty, data + i,
-				bytes - i, tty_flag);
+				tty_flag, bytes - i);
 		tty_flip_buffer_push(tty);
 	}
 
@@ -1397,193 +1378,6 @@
 
 
 /*****************************************************************************
- * Write buffer functions - buffering code from pl2303 used
- *****************************************************************************/
-
-/*
- * cypress_buf_alloc
- *
- * Allocate a circular buffer and all associated memory.
- */
-
-static struct cypress_buf *cypress_buf_alloc(unsigned int size)
-{
-
-	struct cypress_buf *cb;
-
-
-	if (size == 0)
-		return NULL;
-
-	cb = kmalloc(sizeof(struct cypress_buf), GFP_KERNEL);
-	if (cb == NULL)
-		return NULL;
-
-	cb->buf_buf = kmalloc(size, GFP_KERNEL);
-	if (cb->buf_buf == NULL) {
-		kfree(cb);
-		return NULL;
-	}
-
-	cb->buf_size = size;
-	cb->buf_get = cb->buf_put = cb->buf_buf;
-
-	return cb;
-
-}
-
-
-/*
- * cypress_buf_free
- *
- * Free the buffer and all associated memory.
- */
-
-static void cypress_buf_free(struct cypress_buf *cb)
-{
-	if (cb) {
-		kfree(cb->buf_buf);
-		kfree(cb);
-	}
-}
-
-
-/*
- * cypress_buf_clear
- *
- * Clear out all data in the circular buffer.
- */
-
-static void cypress_buf_clear(struct cypress_buf *cb)
-{
-	if (cb != NULL)
-		cb->buf_get = cb->buf_put;
-		/* equivalent to a get of all data available */
-}
-
-
-/*
- * cypress_buf_data_avail
- *
- * Return the number of bytes of data available in the circular
- * buffer.
- */
-
-static unsigned int cypress_buf_data_avail(struct cypress_buf *cb)
-{
-	if (cb != NULL)
-		return (cb->buf_size + cb->buf_put - cb->buf_get)
-							% cb->buf_size;
-	else
-		return 0;
-}
-
-
-/*
- * cypress_buf_space_avail
- *
- * Return the number of bytes of space available in the circular
- * buffer.
- */
-
-static unsigned int cypress_buf_space_avail(struct cypress_buf *cb)
-{
-	if (cb != NULL)
-		return (cb->buf_size + cb->buf_get - cb->buf_put - 1)
-							% cb->buf_size;
-	else
-		return 0;
-}
-
-
-/*
- * cypress_buf_put
- *
- * Copy data data from a user buffer and put it into the circular buffer.
- * Restrict to the amount of space available.
- *
- * Return the number of bytes copied.
- */
-
-static unsigned int cypress_buf_put(struct cypress_buf *cb, const char *buf,
-	unsigned int count)
-{
-
-	unsigned int len;
-
-
-	if (cb == NULL)
-		return 0;
-
-	len  = cypress_buf_space_avail(cb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = cb->buf_buf + cb->buf_size - cb->buf_put;
-	if (count > len) {
-		memcpy(cb->buf_put, buf, len);
-		memcpy(cb->buf_buf, buf+len, count - len);
-		cb->buf_put = cb->buf_buf + count - len;
-	} else {
-		memcpy(cb->buf_put, buf, count);
-		if (count < len)
-			cb->buf_put += count;
-		else /* count == len */
-			cb->buf_put = cb->buf_buf;
-	}
-
-	return count;
-
-}
-
-
-/*
- * cypress_buf_get
- *
- * Get data from the circular buffer and copy to the given buffer.
- * Restrict to the amount of data available.
- *
- * Return the number of bytes copied.
- */
-
-static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf,
-	unsigned int count)
-{
-
-	unsigned int len;
-
-
-	if (cb == NULL)
-		return 0;
-
-	len = cypress_buf_data_avail(cb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = cb->buf_buf + cb->buf_size - cb->buf_get;
-	if (count > len) {
-		memcpy(buf, cb->buf_get, len);
-		memcpy(buf+len, cb->buf_buf, count - len);
-		cb->buf_get = cb->buf_buf + count - len;
-	} else {
-		memcpy(buf, cb->buf_get, count);
-		if (count < len)
-			cb->buf_get += count;
-		else /* count == len */
-			cb->buf_get = cb->buf_buf;
-	}
-
-	return count;
-
-}
-
-/*****************************************************************************
  * Module functions
  *****************************************************************************/
 
diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h
index 1fd360e..67cf608 100644
--- a/drivers/usb/serial/cypress_m8.h
+++ b/drivers/usb/serial/cypress_m8.h
@@ -1,27 +1,32 @@
 #ifndef CYPRESS_M8_H
 #define CYPRESS_M8_H
 
-/* definitions and function prototypes used for the cypress USB to Serial controller */
+/*
+ * definitions and function prototypes used for the cypress USB to Serial
+ * controller
+ */
 
-/* For sending our feature buffer - controlling serial communication states */
-/* Linux HID has no support for serial devices so we do this through the driver */
-#define HID_REQ_GET_REPORT 0x01
-#define HID_REQ_SET_REPORT 0x09
+/*
+ * For sending our feature buffer - controlling serial communication states.
+ * Linux HID has no support for serial devices so we do this through the driver
+ */
+#define HID_REQ_GET_REPORT	0x01
+#define HID_REQ_SET_REPORT	0x09
 
 /* List other cypress USB to Serial devices here, and add them to the id_table */
 
 /* DeLorme Earthmate USB - a GPS device */
-#define	VENDOR_ID_DELORME		 0x1163
-#define PRODUCT_ID_EARTHMATEUSB		 0x0100
-#define PRODUCT_ID_EARTHMATEUSB_LT20	 0x0200
+#define VENDOR_ID_DELORME		0x1163
+#define PRODUCT_ID_EARTHMATEUSB		0x0100
+#define PRODUCT_ID_EARTHMATEUSB_LT20	0x0200
 
 /* Cypress HID->COM RS232 Adapter */
-#define VENDOR_ID_CYPRESS		 0x04b4
-#define PRODUCT_ID_CYPHIDCOM		 0x5500
+#define VENDOR_ID_CYPRESS		0x04b4
+#define PRODUCT_ID_CYPHIDCOM		0x5500
 
 /* Powercom UPS, chip CY7C63723 */
-#define VENDOR_ID_POWERCOM		 0x0d9f
-#define PRODUCT_ID_UPS			 0x0002
+#define VENDOR_ID_POWERCOM		0x0d9f
+#define PRODUCT_ID_UPS			0x0002
 
 /* Nokia CA-42 USB to serial cable */
 #define VENDOR_ID_DAZZLE		0x07d0
@@ -29,17 +34,17 @@
 /* End of device listing */
 
 /* Used for setting / requesting serial line settings */
-#define CYPRESS_SET_CONFIG 0x01
-#define CYPRESS_GET_CONFIG 0x02
+#define CYPRESS_SET_CONFIG	0x01
+#define CYPRESS_GET_CONFIG	0x02
 
 /* Used for throttle control */
-#define THROTTLED 0x1
-#define ACTUALLY_THROTTLED 0x2
+#define THROTTLED		0x1
+#define ACTUALLY_THROTTLED	0x2
 
-/* chiptypes - used in case firmware differs from the generic form ... offering
- * 	different baud speeds/etc.
+/*
+ * chiptypes - used in case firmware differs from the generic form ... offering
+ * different baud speeds/etc.
  */
-
 #define CT_EARTHMATE	0x01
 #define CT_CYPHIDCOM	0x02
 #define CT_CA42V2	0x03
@@ -50,15 +55,15 @@
 /* these are sent / read at byte 0 of the input/output hid reports */
 /* You can find these values defined in the CY4601 USB to Serial design notes */
 
-#define CONTROL_DTR 	0x20	/* data terminal ready - flow control - host to device */
+#define CONTROL_DTR	0x20	/* data terminal ready - flow control - host to device */
 #define UART_DSR	0x20	/* data set ready - flow control - device to host */
-#define CONTROL_RTS 	0x10	/* request to send - flow control - host to device */
+#define CONTROL_RTS	0x10	/* request to send - flow control - host to device */
 #define UART_CTS	0x10	/* clear to send - flow control - device to host */
-#define	UART_RI		0x10	/* ring indicator - modem - device to host */
+#define UART_RI		0x10	/* ring indicator - modem - device to host */
 #define UART_CD		0x40	/* carrier detect - modem - device to host */
-#define CYP_ERROR 	0x08	/* received from input report - device to host */
+#define CYP_ERROR	0x08	/* received from input report - device to host */
 /* Note - the below has nothing to do with the "feature report" reset */
-#define CONTROL_RESET	0x08  	/* sent with output report - host to device */
+#define CONTROL_RESET	0x08	/* sent with output report - host to device */
 
 /* End of RS-232 protocol definitions */
 
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 68b0aa5..3edda3e 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -1703,8 +1703,8 @@
 		/* data length is len-1 (one byte of len is port_status) */
 		--len;
 		if (len > 0) {
-			tty_insert_flip_string_fixed_flag(tty, data, len,
-									flag);
+			tty_insert_flip_string_fixed_flag(tty, data, flag,
+									len);
 			tty_flip_buffer_push(tty);
 		}
 	}
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 5f740a1..504b558 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -13,44 +13,6 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this
  * driver
- *
- * (07/16/2001) gb
- *	remove unused code in empeg_close() (thanks to Oliver Neukum for
- *	pointing this out) and rewrote empeg_set_termios().
- *
- * (05/30/2001) gkh
- *	switched from using spinlock to a semaphore, which fixes lots of
- * problems.
- *
- * (04/08/2001) gb
- *      Identify version on module load.
- *
- * (01/22/2001) gb
- *	Added write_room() and chars_in_buffer() support.
- *
- * (12/21/2000) gb
- *	Moved termio stuff inside the port->active check.
- *	Moved MOD_DEC_USE_COUNT to end of empeg_close().
- *
- * (12/03/2000) gb
- *	Added tty->ldisc.set_termios(port, tty, NULL) to empeg_open().
- *	This notifies the tty driver that the termios have changed.
- *
- * (11/13/2000) gb
- *	Moved tty->low_latency = 1 from empeg_read_bulk_callback() to
- *	empeg_open() (It only needs to be set once - Doh!)
- *
- * (11/11/2000) gb
- *	Updated to work with id_table structure.
- *
- * (11/04/2000) gb
- *	Forked this from visor.c, and hacked it up to work with an
- *	Empeg ltd. empeg-car player.  Constructive criticism welcomed.
- *	I would like to say, 'Thank You' to Greg Kroah-Hartman for the
- *	use of his code, and for his guidance, advice and patience. :)
- *	A 'Thank You' is in order for John Ripley of Empeg ltd for his
- *	advice, and patience too.
- *
  */
 
 #include <linux/kernel.h>
@@ -71,7 +33,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.2"
+#define DRIVER_VERSION "v1.3"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Gary Brubaker <xavyer@ix.netcom.com>"
 #define DRIVER_DESC "USB Empeg Mark I/II Driver"
 
@@ -79,19 +41,8 @@
 #define EMPEG_PRODUCT_ID		0x0001
 
 /* function prototypes for an empeg-car player */
-static int  empeg_open(struct tty_struct *tty, struct usb_serial_port *port);
-static void empeg_close(struct usb_serial_port *port);
-static int  empeg_write(struct tty_struct *tty, struct usb_serial_port *port,
-						const unsigned char *buf,
-						int count);
-static int  empeg_write_room(struct tty_struct *tty);
-static int  empeg_chars_in_buffer(struct tty_struct *tty);
-static void empeg_throttle(struct tty_struct *tty);
-static void empeg_unthrottle(struct tty_struct *tty);
 static int  empeg_startup(struct usb_serial *serial);
 static void empeg_init_termios(struct tty_struct *tty);
-static void empeg_write_bulk_callback(struct urb *urb);
-static void empeg_read_bulk_callback(struct urb *urb);
 
 static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(EMPEG_VENDOR_ID, EMPEG_PRODUCT_ID) },
@@ -105,7 +56,7 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
+	.no_dynamic_id =	1,
 };
 
 static struct usb_serial_driver empeg_device = {
@@ -114,291 +65,16 @@
 		.name =		"empeg",
 	},
 	.id_table =		id_table,
-	.usb_driver = 		&empeg_driver,
+	.usb_driver =		&empeg_driver,
 	.num_ports =		1,
-	.open =			empeg_open,
-	.close =		empeg_close,
-	.throttle =		empeg_throttle,
-	.unthrottle =		empeg_unthrottle,
+	.bulk_out_size =	256,
+	.throttle =		usb_serial_generic_throttle,
+	.unthrottle =		usb_serial_generic_unthrottle,
 	.attach =		empeg_startup,
 	.init_termios =		empeg_init_termios,
-	.write =		empeg_write,
-	.write_room =		empeg_write_room,
-	.chars_in_buffer =	empeg_chars_in_buffer,
-	.write_bulk_callback =	empeg_write_bulk_callback,
-	.read_bulk_callback =	empeg_read_bulk_callback,
 };
 
-#define NUM_URBS			16
-#define URB_TRANSFER_BUFFER_SIZE	4096
-
-static struct urb	*write_urb_pool[NUM_URBS];
-static spinlock_t	write_urb_pool_lock;
-static int		bytes_in;
-static int		bytes_out;
-
-/******************************************************************************
- * Empeg specific driver functions
- ******************************************************************************/
-static int empeg_open(struct tty_struct *tty,struct usb_serial_port *port)
-{
-	struct usb_serial *serial = port->serial;
-	int result = 0;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	bytes_in = 0;
-	bytes_out = 0;
-
-	/* Start reading from the device */
-	usb_fill_bulk_urb(
-		port->read_urb,
-		serial->dev,
-		usb_rcvbulkpipe(serial->dev,
-			port->bulk_in_endpointAddress),
-		port->read_urb->transfer_buffer,
-		port->read_urb->transfer_buffer_length,
-		empeg_read_bulk_callback,
-		port);
-
-	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-
-	if (result)
-		dev_err(&port->dev,
-			"%s - failed submitting read urb, error %d\n",
-							__func__, result);
-
-	return result;
-}
-
-
-static void empeg_close(struct usb_serial_port *port)
-{
-	dbg("%s - port %d", __func__, port->number);
-
-	/* shutdown our bulk read */
-	usb_kill_urb(port->read_urb);
-	/* Uncomment the following line if you want to see some statistics in your syslog */
-	/* dev_info (&port->dev, "Bytes In = %d  Bytes Out = %d\n", bytes_in, bytes_out); */
-}
-
-
-static int empeg_write(struct tty_struct *tty, struct usb_serial_port *port,
-					const unsigned char *buf, int count)
-{
-	struct usb_serial *serial = port->serial;
-	struct urb *urb;
-	const unsigned char *current_position = buf;
-	unsigned long flags;
-	int status;
-	int i;
-	int bytes_sent = 0;
-	int transfer_size;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	while (count > 0) {
-		/* try to find a free urb in our list of them */
-		urb = NULL;
-
-		spin_lock_irqsave(&write_urb_pool_lock, flags);
-
-		for (i = 0; i < NUM_URBS; ++i) {
-			if (write_urb_pool[i]->status != -EINPROGRESS) {
-				urb = write_urb_pool[i];
-				break;
-			}
-		}
-
-		spin_unlock_irqrestore(&write_urb_pool_lock, flags);
-
-		if (urb == NULL) {
-			dbg("%s - no more free urbs", __func__);
-			goto exit;
-		}
-
-		if (urb->transfer_buffer == NULL) {
-			urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC);
-			if (urb->transfer_buffer == NULL) {
-				dev_err(&port->dev,
-					"%s no more kernel memory...\n",
-								__func__);
-				goto exit;
-			}
-		}
-
-		transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
-
-		memcpy(urb->transfer_buffer, current_position, transfer_size);
-
-		usb_serial_debug_data(debug, &port->dev, __func__, transfer_size, urb->transfer_buffer);
-
-		/* build up our urb */
-		usb_fill_bulk_urb(
-			urb,
-			serial->dev,
-			usb_sndbulkpipe(serial->dev,
-					port->bulk_out_endpointAddress),
-			urb->transfer_buffer,
-			transfer_size,
-			empeg_write_bulk_callback,
-			port);
-
-		/* send it down the pipe */
-		status = usb_submit_urb(urb, GFP_ATOMIC);
-		if (status) {
-			dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __func__, status);
-			bytes_sent = status;
-			break;
-		}
-
-		current_position += transfer_size;
-		bytes_sent += transfer_size;
-		count -= transfer_size;
-		bytes_out += transfer_size;
-
-	}
-exit:
-	return bytes_sent;
-}
-
-
-static int empeg_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	unsigned long flags;
-	int i;
-	int room = 0;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&write_urb_pool_lock, flags);
-	/* tally up the number of bytes available */
-	for (i = 0; i < NUM_URBS; ++i) {
-		if (write_urb_pool[i]->status != -EINPROGRESS)
-			room += URB_TRANSFER_BUFFER_SIZE;
-	}
-	spin_unlock_irqrestore(&write_urb_pool_lock, flags);
-	dbg("%s - returns %d", __func__, room);
-	return room;
-
-}
-
-
-static int empeg_chars_in_buffer(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	unsigned long flags;
-	int i;
-	int chars = 0;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&write_urb_pool_lock, flags);
-
-	/* tally up the number of bytes waiting */
-	for (i = 0; i < NUM_URBS; ++i) {
-		if (write_urb_pool[i]->status == -EINPROGRESS)
-			chars += URB_TRANSFER_BUFFER_SIZE;
-	}
-
-	spin_unlock_irqrestore(&write_urb_pool_lock, flags);
-	dbg("%s - returns %d", __func__, chars);
-	return chars;
-}
-
-
-static void empeg_write_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = urb->context;
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (status) {
-		dbg("%s - nonzero write bulk status received: %d",
-		    __func__, status);
-		return;
-	}
-
-	usb_serial_port_softint(port);
-}
-
-
-static void empeg_read_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = urb->context;
-	struct tty_struct *tty;
-	unsigned char *data = urb->transfer_buffer;
-	int result;
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (status) {
-		dbg("%s - nonzero read bulk status received: %d",
-		    __func__, status);
-		return;
-	}
-
-	usb_serial_debug_data(debug, &port->dev, __func__,
-						urb->actual_length, data);
-	tty = tty_port_tty_get(&port->port);
-
-	if (urb->actual_length) {
-		tty_insert_flip_string(tty, data, urb->actual_length);
-		tty_flip_buffer_push(tty);
-		bytes_in += urb->actual_length;
-	}
-	tty_kref_put(tty);
-
-	/* Continue trying to always read  */
-	usb_fill_bulk_urb(
-		port->read_urb,
-		port->serial->dev,
-		usb_rcvbulkpipe(port->serial->dev,
-			port->bulk_in_endpointAddress),
-		port->read_urb->transfer_buffer,
-		port->read_urb->transfer_buffer_length,
-		empeg_read_bulk_callback,
-		port);
-
-	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-
-	if (result)
-		dev_err(&urb->dev->dev,
-			"%s - failed resubmitting read urb, error %d\n",
-							__func__, result);
-
-	return;
-
-}
-
-
-static void empeg_throttle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s - port %d", __func__, port->number);
-	usb_kill_urb(port->read_urb);
-}
-
-
-static void empeg_unthrottle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	int result;
-	dbg("%s - port %d", __func__, port->number);
-
-	port->read_urb->dev = port->serial->dev;
-	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-	if (result)
-		dev_err(&port->dev,
-			"%s - failed submitting read urb, error %d\n",
-							__func__, result);
-}
-
-
-static int  empeg_startup(struct usb_serial *serial)
+static int empeg_startup(struct usb_serial *serial)
 {
 	int r;
 
@@ -414,10 +90,8 @@
 
 	/* continue on with initialization */
 	return r;
-
 }
 
-
 static void empeg_init_termios(struct tty_struct *tty)
 {
 	struct ktermios *termios = tty->termios;
@@ -462,77 +136,28 @@
 	tty_encode_baud_rate(tty, 115200, 115200);
 }
 
-
 static int __init empeg_init(void)
 {
-	struct urb *urb;
-	int i, retval;
-
-	/* create our write urb pool and transfer buffers */
-	spin_lock_init(&write_urb_pool_lock);
-	for (i = 0; i < NUM_URBS; ++i) {
-		urb = usb_alloc_urb(0, GFP_KERNEL);
-		write_urb_pool[i] = urb;
-		if (urb == NULL) {
-			printk(KERN_ERR "empeg: No more urbs???\n");
-			continue;
-		}
-
-		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
-								GFP_KERNEL);
-		if (!urb->transfer_buffer) {
-			printk(KERN_ERR "empeg: %s - out of memory for urb "
-			       "buffers.", __func__);
-			continue;
-		}
-	}
+	int retval;
 
 	retval = usb_serial_register(&empeg_device);
 	if (retval)
-		goto failed_usb_serial_register;
+		return retval;
 	retval = usb_register(&empeg_driver);
-	if (retval)
-		goto failed_usb_register;
-
+	if (retval) {
+		usb_serial_deregister(&empeg_device);
+		return retval;
+	}
 	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
 	       DRIVER_DESC "\n");
 
 	return 0;
-failed_usb_register:
-	usb_serial_deregister(&empeg_device);
-failed_usb_serial_register:
-	for (i = 0; i < NUM_URBS; ++i) {
-		if (write_urb_pool[i]) {
-			kfree(write_urb_pool[i]->transfer_buffer);
-			usb_free_urb(write_urb_pool[i]);
-		}
-	}
-	return retval;
 }
 
-
 static void __exit empeg_exit(void)
 {
-	int i;
-	unsigned long flags;
-
 	usb_deregister(&empeg_driver);
 	usb_serial_deregister(&empeg_device);
-
-	spin_lock_irqsave(&write_urb_pool_lock, flags);
-
-	for (i = 0; i < NUM_URBS; ++i) {
-		if (write_urb_pool[i]) {
-			/* FIXME - uncomment the following usb_kill_urb call
-			 * when the host controllers get fixed to set urb->dev
-			 * = NULL after the urb is finished.  Otherwise this
-			 * call oopses. */
-			/* usb_kill_urb(write_urb_pool[i]); */
-			kfree(write_urb_pool[i]->transfer_buffer);
-			usb_free_urb(write_urb_pool[i]);
-		}
-	}
-	spin_unlock_irqrestore(&write_urb_pool_lock, flags);
 }
 
 
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 1d7c4fa..050211a 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1,6 +1,8 @@
 /*
  * USB FTDI SIO driver
  *
+ *	Copyright (C) 2009 - 2010
+ *	    Johan Hovold (jhovold@gmail.com)
  *	Copyright (C) 1999 - 2001
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *          Bill Ryder (bryder@sgi.com)
@@ -49,8 +51,8 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.5.0"
-#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr"
+#define DRIVER_VERSION "v1.6.0"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
 static int debug;
@@ -59,7 +61,7 @@
 
 struct ftdi_private {
 	struct kref kref;
-	ftdi_chip_type_t chip_type;
+	enum ftdi_chip_type chip_type;
 				/* type of device, either SIO or FT8U232AM */
 	int baud_base;		/* baud base clock for divisor setting */
 	int custom_divisor;	/* custom_divisor kludge, this is for
@@ -69,10 +71,6 @@
 				/* the last data state set - needed for doing
 				 * a break
 				 */
-	int write_offset;       /* This is the offset in the usb data block to
-				 * write the serial data - it varies between
-				 * devices
-				 */
 	int flags;		/* some ASYNC_xxxx flags are supported */
 	unsigned long last_dtr_rts;	/* saved modem control outputs */
 	wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
@@ -87,9 +85,6 @@
 				   be enabled */
 
 	unsigned int latency;		/* latency setting in use */
-	spinlock_t tx_lock;	/* spinlock for transmit state */
-	unsigned long tx_outstanding_bytes;
-	unsigned long tx_outstanding_urbs;
 	unsigned short max_packet_size;
 	struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() and change_speed() */
 };
@@ -768,9 +763,6 @@
 };
 
 
-/* Constants for read urb and write urb */
-#define BUFSZ 512
-
 /* Used for TIOCMIWAIT */
 #define FTDI_STATUS_B0_MASK	(FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD)
 #define FTDI_STATUS_B1_MASK	(FTDI_RS_BI)
@@ -787,13 +779,9 @@
 static int  ftdi_open(struct tty_struct *tty, struct usb_serial_port *port);
 static void ftdi_close(struct usb_serial_port *port);
 static void ftdi_dtr_rts(struct usb_serial_port *port, int on);
-static int  ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
-			const unsigned char *buf, int count);
-static int  ftdi_write_room(struct tty_struct *tty);
-static int  ftdi_chars_in_buffer(struct tty_struct *tty);
-static void ftdi_write_bulk_callback(struct urb *urb);
-static void ftdi_read_bulk_callback(struct urb *urb);
-static void ftdi_process_read(struct usb_serial_port *port);
+static void ftdi_process_read_urb(struct urb *urb);
+static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
+						void *dest, size_t size);
 static void ftdi_set_termios(struct tty_struct *tty,
 			struct usb_serial_port *port, struct ktermios *old);
 static int  ftdi_tiocmget(struct tty_struct *tty, struct file *file);
@@ -802,8 +790,6 @@
 static int  ftdi_ioctl(struct tty_struct *tty, struct file *file,
 			unsigned int cmd, unsigned long arg);
 static void ftdi_break_ctl(struct tty_struct *tty, int break_state);
-static void ftdi_throttle(struct tty_struct *tty);
-static void ftdi_unthrottle(struct tty_struct *tty);
 
 static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base);
 static unsigned short int ftdi_232am_baud_to_divisor(int baud);
@@ -821,19 +807,18 @@
 	.usb_driver = 		&ftdi_driver,
 	.id_table =		id_table_combined,
 	.num_ports =		1,
+	.bulk_in_size =		512,
+	.bulk_out_size =	256,
 	.probe =		ftdi_sio_probe,
 	.port_probe =		ftdi_sio_port_probe,
 	.port_remove =		ftdi_sio_port_remove,
 	.open =			ftdi_open,
 	.close =		ftdi_close,
 	.dtr_rts =		ftdi_dtr_rts,
-	.throttle =		ftdi_throttle,
-	.unthrottle =		ftdi_unthrottle,
-	.write =		ftdi_write,
-	.write_room =		ftdi_write_room,
-	.chars_in_buffer =	ftdi_chars_in_buffer,
-	.read_bulk_callback =	ftdi_read_bulk_callback,
-	.write_bulk_callback =	ftdi_write_bulk_callback,
+	.throttle =		usb_serial_generic_throttle,
+	.unthrottle =		usb_serial_generic_unthrottle,
+	.process_read_urb =	ftdi_process_read_urb,
+	.prepare_write_buffer =	ftdi_prepare_write_buffer,
 	.tiocmget =		ftdi_tiocmget,
 	.tiocmset =		ftdi_tiocmset,
 	.ioctl =		ftdi_ioctl,
@@ -849,9 +834,6 @@
 #define HIGH 1
 #define LOW 0
 
-/* number of outstanding urbs to prevent userspace DoS from happening */
-#define URB_UPPER_LIMIT	42
-
 /*
  * ***************************************************************************
  * Utility functions
@@ -987,7 +969,7 @@
 
 static __u32 get_ftdi_divisor(struct tty_struct *tty,
 						struct usb_serial_port *port)
-{ /* get_ftdi_divisor */
+{
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 	__u32 div_value = 0;
 	int div_okay = 1;
@@ -1211,12 +1193,11 @@
 	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
 		return -EFAULT;
 	return 0;
-} /* get_serial_info */
-
+}
 
 static int set_serial_info(struct tty_struct *tty,
 	struct usb_serial_port *port, struct serial_struct __user *newinfo)
-{ /* set_serial_info */
+{
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 	struct serial_struct new_serial;
 	struct ftdi_private old_priv;
@@ -1279,8 +1260,7 @@
 	else
 		mutex_unlock(&priv->cfg_lock);
 	return 0;
-
-} /* set_serial_info */
+}
 
 
 /* Determine type of FTDI chip based on USB config and descriptor. */
@@ -1294,7 +1274,6 @@
 
 	/* Assume it is not the original SIO device for now. */
 	priv->baud_base = 48000000 / 2;
-	priv->write_offset = 0;
 
 	version = le16_to_cpu(udev->descriptor.bcdDevice);
 	interfaces = udev->actconfig->desc.bNumInterfaces;
@@ -1336,7 +1315,6 @@
 		/* Old device.  Assume it's the original SIO. */
 		priv->chip_type = SIO;
 		priv->baud_base = 12000000 / 16;
-		priv->write_offset = 1;
 	} else if (version < 0x400) {
 		/* Assume it's an FT8U232AM (or FT8U245AM) */
 		/* (It might be a BM because of the iSerialNumber bug,
@@ -1543,7 +1521,6 @@
 	}
 
 	kref_init(&priv->kref);
-	spin_lock_init(&priv->tx_lock);
 	mutex_init(&priv->cfg_lock);
 	init_waitqueue_head(&priv->delta_msr_wait);
 
@@ -1552,28 +1529,7 @@
 	if (quirk && quirk->port_probe)
 		quirk->port_probe(priv);
 
-	/* Increase the size of read buffers */
-	kfree(port->bulk_in_buffer);
-	port->bulk_in_buffer = kmalloc(BUFSZ, GFP_KERNEL);
-	if (!port->bulk_in_buffer) {
-		kfree(priv);
-		return -ENOMEM;
-	}
-	if (port->read_urb) {
-		port->read_urb->transfer_buffer = port->bulk_in_buffer;
-		port->read_urb->transfer_buffer_length = BUFSZ;
-	}
-
 	priv->port = port;
-
-	/* Free port's existing write urb and transfer buffer. */
-	if (port->write_urb) {
-		usb_free_urb(port->write_urb);
-		port->write_urb = NULL;
-	}
-	kfree(port->bulk_out_buffer);
-	port->bulk_out_buffer = NULL;
-
 	usb_set_serial_port_data(port, priv);
 
 	ftdi_determine_type(port);
@@ -1594,7 +1550,7 @@
 	priv->flags |= ASYNC_SPD_CUST;
 	priv->custom_divisor = 77;
 	priv->force_baud = 38400;
-} /* ftdi_USB_UIRT_setup */
+}
 
 /* Setup for the HE-TIRA1 device, which requires hardwired
  * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled.  */
@@ -1607,7 +1563,7 @@
 	priv->custom_divisor = 240;
 	priv->force_baud = 38400;
 	priv->force_rtscts = 1;
-} /* ftdi_HE_TIRA1_setup */
+}
 
 /*
  * Module parameter to control latency timer for NDI FTDI-based USB devices.
@@ -1700,31 +1656,10 @@
 	return 0;
 }
 
-static int ftdi_submit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
-{
-	struct urb *urb = port->read_urb;
-	struct usb_serial *serial = port->serial;
-	int result;
-
-	usb_fill_bulk_urb(urb, serial->dev,
-			   usb_rcvbulkpipe(serial->dev,
-					port->bulk_in_endpointAddress),
-			   urb->transfer_buffer,
-			   urb->transfer_buffer_length,
-			   ftdi_read_bulk_callback, port);
-	result = usb_submit_urb(urb, mem_flags);
-	if (result && result != -EPERM)
-		dev_err(&port->dev,
-			"%s - failed submitting read urb, error %d\n",
-							__func__, result);
-	return result;
-}
-
 static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
-{ /* ftdi_open */
+{
 	struct usb_device *dev = port->serial->dev;
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
-	unsigned long flags;
 	int result;
 
 	dbg("%s", __func__);
@@ -1746,20 +1681,13 @@
 	if (tty)
 		ftdi_set_termios(tty, port, tty->termios);
 
-	/* Not throttled */
-	spin_lock_irqsave(&port->lock, flags);
-	port->throttled = 0;
-	port->throttle_req = 0;
-	spin_unlock_irqrestore(&port->lock, flags);
-
 	/* Start reading from the device */
-	result = ftdi_submit_read_urb(port, GFP_KERNEL);
+	result = usb_serial_generic_open(tty, port);
 	if (!result)
 		kref_get(&priv->kref);
 
 	return result;
-} /* ftdi_open */
-
+}
 
 static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
 {
@@ -1789,22 +1717,16 @@
  * usbserial:__serial_close  only calls ftdi_close if the point is open
  *
  *   This only gets called when it is the last close
- *
- *
  */
-
 static void ftdi_close(struct usb_serial_port *port)
-{ /* ftdi_close */
+{
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 
 	dbg("%s", __func__);
 
-	/* shutdown our bulk read */
-	usb_kill_urb(port->read_urb);
+	usb_serial_generic_close(port);
 	kref_put(&priv->kref, ftdi_sio_priv_release);
-} /* ftdi_close */
-
-
+}
 
 /* The SIO requires the first byte to have:
  *  B0 1
@@ -1813,211 +1735,39 @@
  *
  * The new devices do not require this byte
  */
-static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
-			   const unsigned char *buf, int count)
-{ /* ftdi_write */
-	struct ftdi_private *priv = usb_get_serial_port_data(port);
-	struct urb *urb;
-	unsigned char *buffer;
-	int data_offset ;       /* will be 1 for the SIO and 0 otherwise */
-	int status;
-	int transfer_size;
-	unsigned long flags;
-
-	dbg("%s port %d, %d bytes", __func__, port->number, count);
-
-	if (count == 0) {
-		dbg("write request of 0 bytes");
-		return 0;
-	}
-	spin_lock_irqsave(&priv->tx_lock, flags);
-	if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) {
-		spin_unlock_irqrestore(&priv->tx_lock, flags);
-		dbg("%s - write limit hit", __func__);
-		return 0;
-	}
-	priv->tx_outstanding_urbs++;
-	spin_unlock_irqrestore(&priv->tx_lock, flags);
-
-	data_offset = priv->write_offset;
-	dbg("data_offset set to %d", data_offset);
-
-	/* Determine total transfer size */
-	transfer_size = count;
-	if (data_offset > 0) {
-		/* Original sio needs control bytes too... */
-		transfer_size += (data_offset *
-				((count + (priv->max_packet_size - 1 - data_offset)) /
-				 (priv->max_packet_size - data_offset)));
-	}
-
-	buffer = kmalloc(transfer_size, GFP_ATOMIC);
-	if (!buffer) {
-		dev_err(&port->dev,
-			"%s ran out of kernel memory for urb ...\n", __func__);
-		count = -ENOMEM;
-		goto error_no_buffer;
-	}
-
-	urb = usb_alloc_urb(0, GFP_ATOMIC);
-	if (!urb) {
-		dev_err(&port->dev, "%s - no more free urbs\n", __func__);
-		count = -ENOMEM;
-		goto error_no_urb;
-	}
-
-	/* Copy data */
-	if (data_offset > 0) {
-		/* Original sio requires control byte at start of
-		   each packet. */
-		int user_pktsz = priv->max_packet_size - data_offset;
-		int todo = count;
-		unsigned char *first_byte = buffer;
-		const unsigned char *current_position = buf;
-
-		while (todo > 0) {
-			if (user_pktsz > todo)
-				user_pktsz = todo;
-			/* Write the control byte at the front of the packet*/
-			*first_byte = 1 | ((user_pktsz) << 2);
-			/* Copy data for packet */
-			memcpy(first_byte + data_offset,
-				current_position, user_pktsz);
-			first_byte += user_pktsz + data_offset;
-			current_position += user_pktsz;
-			todo -= user_pktsz;
-		}
-	} else {
-		/* No control byte required. */
-		/* Copy in the data to send */
-		memcpy(buffer, buf, count);
-	}
-
-	usb_serial_debug_data(debug, &port->dev, __func__,
-						transfer_size, buffer);
-
-	/* fill the buffer and send it */
-	usb_fill_bulk_urb(urb, port->serial->dev,
-			usb_sndbulkpipe(port->serial->dev,
-					port->bulk_out_endpointAddress),
-			buffer, transfer_size,
-			ftdi_write_bulk_callback, port);
-
-	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status) {
-		dev_err(&port->dev,
-			"%s - failed submitting write urb, error %d\n",
-			__func__, status);
-		count = status;
-		goto error;
-	} else {
-		spin_lock_irqsave(&priv->tx_lock, flags);
-		priv->tx_outstanding_bytes += count;
-		spin_unlock_irqrestore(&priv->tx_lock, flags);
-	}
-
-	/* we are done with this urb, so let the host driver
-	 * really free it when it is finished with it */
-	usb_free_urb(urb);
-
-	dbg("%s write returning: %d", __func__, count);
-	return count;
-error:
-	usb_free_urb(urb);
-error_no_urb:
-	kfree(buffer);
-error_no_buffer:
-	spin_lock_irqsave(&priv->tx_lock, flags);
-	priv->tx_outstanding_urbs--;
-	spin_unlock_irqrestore(&priv->tx_lock, flags);
-	return count;
-} /* ftdi_write */
-
-
-/* This function may get called when the device is closed */
-
-static void ftdi_write_bulk_callback(struct urb *urb)
+static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
+						void *dest, size_t size)
 {
-	unsigned long flags;
-	struct usb_serial_port *port = urb->context;
 	struct ftdi_private *priv;
-	int data_offset;       /* will be 1 for the SIO and 0 otherwise */
-	unsigned long countback;
-	int status = urb->status;
-
-	/* free up the transfer buffer, as usb_free_urb() does not do this */
-	kfree(urb->transfer_buffer);
-
-	dbg("%s - port %d", __func__, port->number);
+	int count;
+	unsigned long flags;
 
 	priv = usb_get_serial_port_data(port);
-	if (!priv) {
-		dbg("%s - bad port private data pointer - exiting", __func__);
-		return;
-	}
-	/* account for transferred data */
-	countback = urb->transfer_buffer_length;
-	data_offset = priv->write_offset;
-	if (data_offset > 0) {
-		/* Subtract the control bytes */
-		countback -= (data_offset * DIV_ROUND_UP(countback, priv->max_packet_size));
-	}
-	spin_lock_irqsave(&priv->tx_lock, flags);
-	--priv->tx_outstanding_urbs;
-	priv->tx_outstanding_bytes -= countback;
-	spin_unlock_irqrestore(&priv->tx_lock, flags);
 
-	if (status) {
-		dbg("nonzero write bulk status received: %d", status);
-	}
+	if (priv->chip_type == SIO) {
+		unsigned char *buffer = dest;
+		int i, len, c;
 
-	usb_serial_port_softint(port);
-} /* ftdi_write_bulk_callback */
-
-
-static int ftdi_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct ftdi_private *priv = usb_get_serial_port_data(port);
-	int room;
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&priv->tx_lock, flags);
-	if (priv->tx_outstanding_urbs < URB_UPPER_LIMIT) {
-		/*
-		 * We really can take anything the user throws at us
-		 * but let's pick a nice big number to tell the tty
-		 * layer that we have lots of free space
-		 */
-		room = 2048;
+		count = 0;
+		spin_lock_irqsave(&port->lock, flags);
+		for (i = 0; i < size - 1; i += priv->max_packet_size) {
+			len = min_t(int, size - i, priv->max_packet_size) - 1;
+			c = kfifo_out(&port->write_fifo, &buffer[i + 1], len);
+			if (!c)
+				break;
+			buffer[i] = (c << 2) + 1;
+			count += c + 1;
+		}
+		spin_unlock_irqrestore(&port->lock, flags);
 	} else {
-		room = 0;
+		count = kfifo_out_locked(&port->write_fifo, dest, size,
+								&port->lock);
 	}
-	spin_unlock_irqrestore(&priv->tx_lock, flags);
-	return room;
+
+	return count;
 }
 
-static int ftdi_chars_in_buffer(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct ftdi_private *priv = usb_get_serial_port_data(port);
-	int buffered;
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&priv->tx_lock, flags);
-	buffered = (int)priv->tx_outstanding_bytes;
-	spin_unlock_irqrestore(&priv->tx_lock, flags);
-	if (buffered < 0) {
-		dev_err(&port->dev, "%s outstanding tx bytes is negative!\n",
-			__func__);
-		buffered = 0;
-	}
-	return buffered;
-}
+#define FTDI_RS_ERR_MASK (FTDI_RS_BI | FTDI_RS_PE | FTDI_RS_FE | FTDI_RS_OE)
 
 static int ftdi_process_packet(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ftdi_private *priv,
@@ -2045,28 +1795,21 @@
 		priv->prev_status = status;
 	}
 
-	/*
-	 * Although the device uses a bitmask and hence can have multiple
-	 * errors on a packet - the order here sets the priority the error is
-	 * returned to the tty layer.
-	 */
 	flag = TTY_NORMAL;
-	if (packet[1] & FTDI_RS_OE) {
-		flag = TTY_OVERRUN;
-		dbg("OVERRRUN error");
-	}
-	if (packet[1] & FTDI_RS_BI) {
-		flag = TTY_BREAK;
-		dbg("BREAK received");
-		usb_serial_handle_break(port);
-	}
-	if (packet[1] & FTDI_RS_PE) {
-		flag = TTY_PARITY;
-		dbg("PARITY error");
-	}
-	if (packet[1] & FTDI_RS_FE) {
-		flag = TTY_FRAME;
-		dbg("FRAMING error");
+	if (packet[1] & FTDI_RS_ERR_MASK) {
+		/* Break takes precedence over parity, which takes precedence
+		 * over framing errors */
+		if (packet[1] & FTDI_RS_BI) {
+			flag = TTY_BREAK;
+			usb_serial_handle_break(port);
+		} else if (packet[1] & FTDI_RS_PE) {
+			flag = TTY_PARITY;
+		} else if (packet[1] & FTDI_RS_FE) {
+			flag = TTY_FRAME;
+		}
+		/* Overrun is special, not associated with a char */
+		if (packet[1] & FTDI_RS_OE)
+			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
 	}
 
 	len -= 2;
@@ -2074,20 +1817,21 @@
 		return 0;	/* status only */
 	ch = packet + 2;
 
-	if (!(port->console && port->sysrq) && flag == TTY_NORMAL)
-		tty_insert_flip_string(tty, ch, len);
-	else {
+	if (port->port.console && port->sysrq) {
 		for (i = 0; i < len; i++, ch++) {
 			if (!usb_serial_handle_sysrq_char(tty, port, *ch))
 				tty_insert_flip_char(tty, *ch, flag);
 		}
+	} else {
+		tty_insert_flip_string_fixed_flag(tty, ch, flag, len);
 	}
+
 	return len;
 }
 
-static void ftdi_process_read(struct usb_serial_port *port)
+static void ftdi_process_read_urb(struct urb *urb)
 {
-	struct urb *urb = port->read_urb;
+	struct usb_serial_port *port = urb->context;
 	struct tty_struct *tty;
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 	char *data = (char *)urb->transfer_buffer;
@@ -2109,32 +1853,6 @@
 	tty_kref_put(tty);
 }
 
-static void ftdi_read_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = urb->context;
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (urb->status) {
-		dbg("%s - nonzero read bulk status received: %d",
-						__func__, urb->status);
-		return;
-	}
-
-	usb_serial_debug_data(debug, &port->dev, __func__,
-				urb->actual_length, urb->transfer_buffer);
-	ftdi_process_read(port);
-
-	spin_lock_irqsave(&port->lock, flags);
-	port->throttled = port->throttle_req;
-	if (!port->throttled) {
-		spin_unlock_irqrestore(&port->lock, flags);
-		ftdi_submit_read_urb(port, GFP_ATOMIC);
-	} else
-		spin_unlock_irqrestore(&port->lock, flags);
-}
-
 static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
 {
 	struct usb_serial_port *port = tty->driver_data;
@@ -2165,15 +1883,13 @@
 
 }
 
-
 /* old_termios contains the original termios settings and tty->termios contains
  * the new setting to be used
  * WARNING: set_termios calls this with old_termios in kernel space
  */
-
 static void ftdi_set_termios(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ktermios *old_termios)
-{ /* ftdi_termios */
+{
 	struct usb_device *dev = port->serial->dev;
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 	struct ktermios *termios = tty->termios;
@@ -2401,7 +2117,6 @@
 	return update_mctrl(port, set, clear);
 }
 
-
 static int ftdi_ioctl(struct tty_struct *tty, struct file *file,
 					unsigned int cmd, unsigned long arg)
 {
@@ -2470,35 +2185,6 @@
 	return -ENOIOCTLCMD;
 }
 
-static void ftdi_throttle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&port->lock, flags);
-	port->throttle_req = 1;
-	spin_unlock_irqrestore(&port->lock, flags);
-}
-
-void ftdi_unthrottle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	int was_throttled;
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&port->lock, flags);
-	was_throttled = port->throttled;
-	port->throttled = port->throttle_req = 0;
-	spin_unlock_irqrestore(&port->lock, flags);
-
-	if (was_throttled)
-		ftdi_submit_read_urb(port, GFP_KERNEL);
-}
-
 static int __init ftdi_init(void)
 {
 	int retval;
@@ -2529,15 +2215,12 @@
 	return retval;
 }
 
-
 static void __exit ftdi_exit(void)
 {
-
 	dbg("%s", __func__);
 
 	usb_deregister(&ftdi_driver);
 	usb_serial_deregister(&ftdi_sio_device);
-
 }
 
 
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index ff9bf80..213fe3d 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -23,14 +23,16 @@
  */
 
 /* Commands */
-#define FTDI_SIO_RESET 		0 /* Reset the port */
-#define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
-#define FTDI_SIO_SET_FLOW_CTRL	2 /* Set flow control register */
-#define FTDI_SIO_SET_BAUD_RATE	3 /* Set baud rate */
-#define FTDI_SIO_SET_DATA	4 /* Set the data characteristics of the port */
-#define FTDI_SIO_GET_MODEM_STATUS	5 /* Retrieve current value of modem status register */
-#define FTDI_SIO_SET_EVENT_CHAR	6 /* Set the event character */
-#define FTDI_SIO_SET_ERROR_CHAR	7 /* Set the error character */
+#define FTDI_SIO_RESET			0 /* Reset the port */
+#define FTDI_SIO_MODEM_CTRL		1 /* Set the modem control register */
+#define FTDI_SIO_SET_FLOW_CTRL		2 /* Set flow control register */
+#define FTDI_SIO_SET_BAUD_RATE		3 /* Set baud rate */
+#define FTDI_SIO_SET_DATA		4 /* Set the data characteristics of
+					     the port */
+#define FTDI_SIO_GET_MODEM_STATUS	5 /* Retrieve current value of modem
+					     status register */
+#define FTDI_SIO_SET_EVENT_CHAR		6 /* Set the event character */
+#define FTDI_SIO_SET_ERROR_CHAR		7 /* Set the error character */
 #define FTDI_SIO_SET_LATENCY_TIMER	9 /* Set the latency timer */
 #define FTDI_SIO_GET_LATENCY_TIMER	10 /* Get the latency timer */
 
@@ -52,7 +54,7 @@
  */
 
 /* Port Identifier Table */
-#define PIT_DEFAULT 		0 /* SIOA */
+#define PIT_DEFAULT		0 /* SIOA */
 #define PIT_SIOA		1 /* SIOA */
 /* The device this driver is tested with one has only one port */
 #define PIT_SIOB		2 /* SIOB */
@@ -103,20 +105,21 @@
  * wLength:        0
  * Data:           None
  * The BaudDivisor values are calculated as follows:
- * - BaseClock is either 12000000 or 48000000 depending on the device. FIXME: I wish
- *   I knew how to detect old chips to select proper base clock!
+ * - BaseClock is either 12000000 or 48000000 depending on the device.
+ *   FIXME: I wish I knew how to detect old chips to select proper base clock!
  * - BaudDivisor is a fixed point number encoded in a funny way.
  *   (--WRONG WAY OF THINKING--)
  *   BaudDivisor is a fixed point number encoded with following bit weighs:
  *   (-2)(-1)(13..0). It is a radical with a denominator of 4, so values
  *   end with 0.0 (00...), 0.25 (10...), 0.5 (01...), and 0.75 (11...).
  *   (--THE REALITY--)
- *   The both-bits-set has quite different meaning from 0.75 - the chip designers
- *   have decided it to mean 0.125 instead of 0.75.
+ *   The both-bits-set has quite different meaning from 0.75 - the chip
+ *   designers have decided it to mean 0.125 instead of 0.75.
  *   This info looked up in FTDI application note "FT8U232 DEVICES \ Data Rates
  *   and Flow Control Consideration for USB to RS232".
  * - BaudDivisor = (BaseClock / 16) / BaudRate, where the (=) operation should
- *   automagically re-encode the resulting value to take fractions into consideration.
+ *   automagically re-encode the resulting value to take fractions into
+ *   consideration.
  * As all values are integers, some bit twiddling is in order:
  *   BaudDivisor = (BaseClock / 16 / BaudRate) |
  *   (((BaseClock / 2 / BaudRate) & 4) ? 0x4000    // 0.5
@@ -146,7 +149,7 @@
  * not supported by the FT8U232AM).
  */
 
-typedef enum {
+enum ftdi_chip_type {
 	SIO = 1,
 	FT8U232AM = 2,
 	FT232BM = 3,
@@ -154,37 +157,36 @@
 	FT232RL = 5,
 	FT2232H = 6,
 	FT4232H = 7
-} ftdi_chip_type_t;
+};
 
-typedef enum {
- ftdi_sio_b300 = 0,
- ftdi_sio_b600 = 1,
- ftdi_sio_b1200 = 2,
- ftdi_sio_b2400 = 3,
- ftdi_sio_b4800 = 4,
- ftdi_sio_b9600 = 5,
- ftdi_sio_b19200 = 6,
- ftdi_sio_b38400 = 7,
- ftdi_sio_b57600 = 8,
- ftdi_sio_b115200 = 9
-} FTDI_SIO_baudrate_t;
+enum ftdi_sio_baudrate {
+	ftdi_sio_b300 = 0,
+	ftdi_sio_b600 = 1,
+	ftdi_sio_b1200 = 2,
+	ftdi_sio_b2400 = 3,
+	ftdi_sio_b4800 = 4,
+	ftdi_sio_b9600 = 5,
+	ftdi_sio_b19200 = 6,
+	ftdi_sio_b38400 = 7,
+	ftdi_sio_b57600 = 8,
+	ftdi_sio_b115200 = 9
+};
 
 /*
- * The ftdi_8U232AM_xxMHz_byyy constants have been removed. The encoded divisor values
- * are calculated internally.
+ * The ftdi_8U232AM_xxMHz_byyy constants have been removed. The encoded divisor
+ * values are calculated internally.
  */
-
-#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
-#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40
-#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8)
-#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8)
-#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8)
-#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8)
-#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8)
-#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
-#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
-#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
-#define FTDI_SIO_SET_BREAK (0x1 << 14)
+#define FTDI_SIO_SET_DATA_REQUEST	FTDI_SIO_SET_DATA
+#define FTDI_SIO_SET_DATA_REQUEST_TYPE	0x40
+#define FTDI_SIO_SET_DATA_PARITY_NONE	(0x0 << 8)
+#define FTDI_SIO_SET_DATA_PARITY_ODD	(0x1 << 8)
+#define FTDI_SIO_SET_DATA_PARITY_EVEN	(0x2 << 8)
+#define FTDI_SIO_SET_DATA_PARITY_MARK	(0x3 << 8)
+#define FTDI_SIO_SET_DATA_PARITY_SPACE	(0x4 << 8)
+#define FTDI_SIO_SET_DATA_STOP_BITS_1	(0x0 << 11)
+#define FTDI_SIO_SET_DATA_STOP_BITS_15	(0x1 << 11)
+#define FTDI_SIO_SET_DATA_STOP_BITS_2	(0x2 << 11)
+#define FTDI_SIO_SET_BREAK		(0x1 << 14)
 /* FTDI_SIO_SET_DATA */
 
 /*
@@ -287,8 +289,8 @@
  *
  * A value of zero in the hIndex field disables handshaking
  *
- * If Xon/Xoff handshaking is specified, the hValue field should contain the XOFF character
- * and the lValue field contains the XON character.
+ * If Xon/Xoff handshaking is specified, the hValue field should contain the
+ * XOFF character and the lValue field contains the XON character.
  */
 
 /*
@@ -373,7 +375,10 @@
 
 /* FTDI_SIO_SET_ERROR_CHAR */
 
-/* Set the parity error replacement character for the specified communications port */
+/*
+ * Set the parity error replacement character for the specified communications
+ * port
+ */
 
 /*
  *  BmRequestType:  0100 0000b
@@ -496,9 +501,10 @@
  *
  * IN Endpoint
  *
- * The device reserves the first two bytes of data on this endpoint to contain the current
- * values of the modem and line status registers. In the absence of data, the device 
- * generates a message consisting of these two status bytes every 40 ms
+ * The device reserves the first two bytes of data on this endpoint to contain
+ * the current values of the modem and line status registers. In the absence of
+ * data, the device generates a message consisting of these two status bytes
+ * every 40 ms
  *
  * Byte 0: Modem Status
  *
@@ -530,21 +536,21 @@
 #define FTDI_RS0_RI	(1 << 6)
 #define FTDI_RS0_RLSD	(1 << 7)
 
-#define FTDI_RS_DR  1
-#define FTDI_RS_OE (1<<1)
-#define FTDI_RS_PE (1<<2)
-#define FTDI_RS_FE (1<<3)
-#define FTDI_RS_BI (1<<4)
-#define FTDI_RS_THRE (1<<5)
-#define FTDI_RS_TEMT (1<<6)
-#define FTDI_RS_FIFO  (1<<7)
+#define FTDI_RS_DR	1
+#define FTDI_RS_OE	(1<<1)
+#define FTDI_RS_PE	(1<<2)
+#define FTDI_RS_FE	(1<<3)
+#define FTDI_RS_BI	(1<<4)
+#define FTDI_RS_THRE	(1<<5)
+#define FTDI_RS_TEMT	(1<<6)
+#define FTDI_RS_FIFO	(1<<7)
 
 /*
  * OUT Endpoint
  *
- * This device reserves the first bytes of data on this endpoint contain the length
- * and port identifier of the message. For the FTDI USB Serial converter the port 
- * identifier is always 1.
+ * This device reserves the first bytes of data on this endpoint contain the
+ * length and port identifier of the message. For the FTDI USB Serial converter
+ * the port identifier is always 1.
  *
  * Byte 0: Line Status
  *
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 75482cb..94d86c3 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -275,8 +275,8 @@
 /*
  * Hameg HO820 and HO870 interface (using VID 0x0403)
  */
-#define        HAMEG_HO820_PID         0xed74
-#define        HAMEG_HO870_PID         0xed71
+#define HAMEG_HO820_PID			0xed74
+#define HAMEG_HO870_PID			0xed71
 
 /*
  *  MaxStream devices	www.maxstream.net
@@ -289,14 +289,14 @@
  * and Mike Studer (K6EEP) <k6eep@hamsoftware.org>.
  * Ian Abbott <abbotti@mev.co.uk> added a few more from the driver INF file.
  */
-#define FTDI_MHAM_KW_PID 0xEEE8		/* USB-KW interface */
-#define FTDI_MHAM_YS_PID 0xEEE9		/* USB-YS interface */
-#define FTDI_MHAM_Y6_PID 0xEEEA		/* USB-Y6 interface */
-#define FTDI_MHAM_Y8_PID 0xEEEB		/* USB-Y8 interface */
-#define FTDI_MHAM_IC_PID 0xEEEC		/* USB-IC interface */
-#define FTDI_MHAM_DB9_PID 0xEEED	/* USB-DB9 interface */
-#define FTDI_MHAM_RS232_PID 0xEEEE	/* USB-RS232 interface */
-#define FTDI_MHAM_Y9_PID 0xEEEF		/* USB-Y9 interface */
+#define FTDI_MHAM_KW_PID	0xEEE8	/* USB-KW interface */
+#define FTDI_MHAM_YS_PID	0xEEE9	/* USB-YS interface */
+#define FTDI_MHAM_Y6_PID	0xEEEA	/* USB-Y6 interface */
+#define FTDI_MHAM_Y8_PID	0xEEEB	/* USB-Y8 interface */
+#define FTDI_MHAM_IC_PID	0xEEEC	/* USB-IC interface */
+#define FTDI_MHAM_DB9_PID	0xEEED	/* USB-DB9 interface */
+#define FTDI_MHAM_RS232_PID	0xEEEE	/* USB-RS232 interface */
+#define FTDI_MHAM_Y9_PID	0xEEEF	/* USB-Y9 interface */
 
 /* Domintell products  http://www.domintell.com */
 #define FTDI_DOMINTELL_DGQG_PID	0xEF50	/* Master */
@@ -483,9 +483,9 @@
  * Blackfin gnICE JTAG
  * http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:gnice
  */
-#define ADI_VID 		0x0456
-#define ADI_GNICE_PID 		0xF000
-#define ADI_GNICEPLUS_PID 	0xF001
+#define ADI_VID			0x0456
+#define ADI_GNICE_PID		0xF000
+#define ADI_GNICEPLUS_PID	0xF001
 
 /*
  * RATOC REX-USB60F
@@ -611,13 +611,13 @@
 #define SEALEVEL_2802_7_PID	0X2872	/* SeaLINK+8/485 (2802) Port 7 */
 #define SEALEVEL_2802_8_PID	0X2882	/* SeaLINK+8/485 (2802) Port 8 */
 #define SEALEVEL_2803_1_PID	0X2813	/* SeaLINK+8 (2803) Port 1 */
-#define SEALEVEL_2803_2_PID	0X2823 	/* SeaLINK+8 (2803) Port 2 */
-#define SEALEVEL_2803_3_PID	0X2833 	/* SeaLINK+8 (2803) Port 3 */
-#define SEALEVEL_2803_4_PID	0X2843 	/* SeaLINK+8 (2803) Port 4 */
-#define SEALEVEL_2803_5_PID	0X2853 	/* SeaLINK+8 (2803) Port 5 */
-#define SEALEVEL_2803_6_PID	0X2863 	/* SeaLINK+8 (2803) Port 6 */
-#define SEALEVEL_2803_7_PID	0X2873 	/* SeaLINK+8 (2803) Port 7 */
-#define SEALEVEL_2803_8_PID	0X2883 	/* SeaLINK+8 (2803) Port 8 */
+#define SEALEVEL_2803_2_PID	0X2823	/* SeaLINK+8 (2803) Port 2 */
+#define SEALEVEL_2803_3_PID	0X2833	/* SeaLINK+8 (2803) Port 3 */
+#define SEALEVEL_2803_4_PID	0X2843	/* SeaLINK+8 (2803) Port 4 */
+#define SEALEVEL_2803_5_PID	0X2853	/* SeaLINK+8 (2803) Port 5 */
+#define SEALEVEL_2803_6_PID	0X2863	/* SeaLINK+8 (2803) Port 6 */
+#define SEALEVEL_2803_7_PID	0X2873	/* SeaLINK+8 (2803) Port 7 */
+#define SEALEVEL_2803_8_PID	0X2883	/* SeaLINK+8 (2803) Port 8 */
 
 /*
  * JETI SPECTROMETER SPECBOS 1201
@@ -1013,7 +1013,7 @@
  */
 #define EVOLUTION_VID		0xDEEE	/* Vendor ID */
 #define EVOLUTION_ER1_PID	0x0300	/* ER1 Control Module */
-#define EVO_8U232AM_PID	0x02FF	/* Evolution robotics RCM2 (FT232AM)*/
+#define EVO_8U232AM_PID		0x02FF	/* Evolution robotics RCM2 (FT232AM)*/
 #define EVO_HYBRID_PID		0x0302	/* Evolution robotics RCM4 PID (FT232BM)*/
 #define EVO_RCM4_PID		0x0303	/* Evolution robotics RCM4 PID */
 
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index f804acb..a817ced 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -1,6 +1,7 @@
 /*
  * USB Serial Converter Generic functions
  *
+ * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com)
  * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or
@@ -12,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
+#include <linux/sysrq.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
@@ -117,7 +119,6 @@
 
 int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
-	struct usb_serial *serial = port->serial;
 	int result = 0;
 	unsigned long flags;
 
@@ -130,23 +131,8 @@
 	spin_unlock_irqrestore(&port->lock, flags);
 
 	/* if we have a bulk endpoint, start reading from it */
-	if (port->bulk_in_size) {
-		/* Start reading from the device */
-		usb_fill_bulk_urb(port->read_urb, serial->dev,
-				   usb_rcvbulkpipe(serial->dev,
-						port->bulk_in_endpointAddress),
-				   port->read_urb->transfer_buffer,
-				   port->read_urb->transfer_buffer_length,
-				   ((serial->type->read_bulk_callback) ?
-				     serial->type->read_bulk_callback :
-				     usb_serial_generic_read_bulk_callback),
-				   port);
-		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-		if (result)
-			dev_err(&port->dev,
-			    "%s - failed resubmitting read urb, error %d\n",
-							__func__, result);
-	}
+	if (port->bulk_in_size)
+		result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
 
 	return result;
 }
@@ -155,13 +141,22 @@
 static void generic_cleanup(struct usb_serial_port *port)
 {
 	struct usb_serial *serial = port->serial;
+	unsigned long flags;
+	int i;
 
 	dbg("%s - port %d", __func__, port->number);
 
 	if (serial->dev) {
 		/* shutdown any bulk transfers that might be going on */
-		if (port->bulk_out_size)
+		if (port->bulk_out_size) {
 			usb_kill_urb(port->write_urb);
+			for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+				usb_kill_urb(port->write_urbs[i]);
+
+			spin_lock_irqsave(&port->lock, flags);
+			kfifo_reset_out(&port->write_fifo);
+			spin_unlock_irqrestore(&port->lock, flags);
+		}
 		if (port->bulk_in_size)
 			usb_kill_urb(port->read_urb);
 	}
@@ -172,146 +167,68 @@
 	dbg("%s - port %d", __func__, port->number);
 	generic_cleanup(port);
 }
+EXPORT_SYMBOL_GPL(usb_serial_generic_close);
 
-static int usb_serial_multi_urb_write(struct tty_struct *tty,
-	struct usb_serial_port *port, const unsigned char *buf, int count)
+int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port,
+						void *dest, size_t size)
 {
-	unsigned long flags;
-	struct urb *urb;
-	unsigned char *buffer;
-	int status;
-	int towrite;
-	int bwrite = 0;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (count == 0)
-		dbg("%s - write request of 0 bytes", __func__);
-
-	while (count > 0) {
-		towrite = (count > port->bulk_out_size) ?
-			port->bulk_out_size : count;
-		spin_lock_irqsave(&port->lock, flags);
-		if (port->urbs_in_flight >
-		    port->serial->type->max_in_flight_urbs) {
-			spin_unlock_irqrestore(&port->lock, flags);
-			dbg("%s - write limit hit", __func__);
-			return bwrite;
-		}
-		port->tx_bytes_flight += towrite;
-		port->urbs_in_flight++;
-		spin_unlock_irqrestore(&port->lock, flags);
-
-		buffer = kmalloc(towrite, GFP_ATOMIC);
-		if (!buffer) {
-			dev_err(&port->dev,
-			"%s ran out of kernel memory for urb ...\n", __func__);
-			goto error_no_buffer;
-		}
-
-		urb = usb_alloc_urb(0, GFP_ATOMIC);
-		if (!urb) {
-			dev_err(&port->dev, "%s - no more free urbs\n",
-				__func__);
-			goto error_no_urb;
-		}
-
-		/* Copy data */
-		memcpy(buffer, buf + bwrite, towrite);
-		usb_serial_debug_data(debug, &port->dev, __func__,
-				      towrite, buffer);
-		/* fill the buffer and send it */
-		usb_fill_bulk_urb(urb, port->serial->dev,
-			usb_sndbulkpipe(port->serial->dev,
-					port->bulk_out_endpointAddress),
-			buffer, towrite,
-			usb_serial_generic_write_bulk_callback, port);
-
-		status = usb_submit_urb(urb, GFP_ATOMIC);
-		if (status) {
-			dev_err(&port->dev,
-				"%s - failed submitting write urb, error %d\n",
-				__func__, status);
-			goto error;
-		}
-
-		/* This urb is the responsibility of the host driver now */
-		usb_free_urb(urb);
-		dbg("%s write: %d", __func__, towrite);
-		count -= towrite;
-		bwrite += towrite;
-	}
-	return bwrite;
-
-error:
-	usb_free_urb(urb);
-error_no_urb:
-	kfree(buffer);
-error_no_buffer:
-	spin_lock_irqsave(&port->lock, flags);
-	port->urbs_in_flight--;
-	port->tx_bytes_flight -= towrite;
-	spin_unlock_irqrestore(&port->lock, flags);
-	return bwrite;
+	return kfifo_out_locked(&port->write_fifo, dest, size, &port->lock);
 }
 
 /**
  * usb_serial_generic_write_start - kick off an URB write
  * @port:	Pointer to the &struct usb_serial_port data
  *
- * Returns the number of bytes queued on success. This will be zero if there
- * was nothing to send. Otherwise, it returns a negative errno value
+ * Returns zero on success, or a negative errno value
  */
 static int usb_serial_generic_write_start(struct usb_serial_port *port)
 {
-	struct usb_serial *serial = port->serial;
-	unsigned char *data;
-	int result;
-	int count;
+	struct urb *urb;
+	int count, result;
 	unsigned long flags;
-	bool start_io;
+	int i;
 
-	/* Atomically determine whether we can and need to start a USB
-	 * operation. */
+	if (test_and_set_bit_lock(USB_SERIAL_WRITE_BUSY, &port->flags))
+		return 0;
+retry:
 	spin_lock_irqsave(&port->lock, flags);
-	if (port->write_urb_busy)
-		start_io = false;
-	else {
-		start_io = (kfifo_len(&port->write_fifo) != 0);
-		port->write_urb_busy = start_io;
+	if (!port->write_urbs_free || !kfifo_len(&port->write_fifo)) {
+		clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags);
+		spin_unlock_irqrestore(&port->lock, flags);
+		return 0;
 	}
+	i = (int)find_first_bit(&port->write_urbs_free,
+						ARRAY_SIZE(port->write_urbs));
 	spin_unlock_irqrestore(&port->lock, flags);
 
-	if (!start_io)
-		return 0;
-
-	data = port->write_urb->transfer_buffer;
-	count = kfifo_out_locked(&port->write_fifo, data, port->bulk_out_size, &port->lock);
-	usb_serial_debug_data(debug, &port->dev, __func__, count, data);
-
-	/* set up our urb */
-	usb_fill_bulk_urb(port->write_urb, serial->dev,
-			   usb_sndbulkpipe(serial->dev,
-				port->bulk_out_endpointAddress),
-			   port->write_urb->transfer_buffer, count,
-			   ((serial->type->write_bulk_callback) ?
-			     serial->type->write_bulk_callback :
-			     usb_serial_generic_write_bulk_callback),
-			   port);
-
-	/* send the data out the bulk port */
-	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+	urb = port->write_urbs[i];
+	count = port->serial->type->prepare_write_buffer(port,
+						urb->transfer_buffer,
+						port->bulk_out_size);
+	urb->transfer_buffer_length = count;
+	usb_serial_debug_data(debug, &port->dev, __func__, count,
+						urb->transfer_buffer);
+	result = usb_submit_urb(urb, GFP_ATOMIC);
 	if (result) {
-		dev_err(&port->dev,
-			"%s - failed submitting write urb, error %d\n",
+		dev_err(&port->dev, "%s - error submitting urb: %d\n",
 						__func__, result);
-		/* don't have to grab the lock here, as we will
-		   retry if != 0 */
-		port->write_urb_busy = 0;
-	} else
-		result = count;
+		clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags);
+		return result;
+	}
+	clear_bit(i, &port->write_urbs_free);
 
-	return result;
+	spin_lock_irqsave(&port->lock, flags);
+	port->tx_bytes += count;
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* Try sending off another urb, unless in irq context (in which case
+	 * there will be no free urb). */
+	if (!in_irq())
+		goto retry;
+
+	clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags);
+
+	return 0;
 }
 
 /**
@@ -328,7 +245,6 @@
 int usb_serial_generic_write(struct tty_struct *tty,
 	struct usb_serial_port *port, const unsigned char *buf, int count)
 {
-	struct usb_serial *serial = port->serial;
 	int result;
 
 	dbg("%s - port %d", __func__, port->number);
@@ -337,31 +253,23 @@
 	if (!port->bulk_out_size)
 		return -ENODEV;
 
-	if (count == 0) {
-		dbg("%s - write request of 0 bytes", __func__);
+	if (!count)
 		return 0;
-	}
-
-	if (serial->type->max_in_flight_urbs)
-		return usb_serial_multi_urb_write(tty, port,
-						  buf, count);
 
 	count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock);
 	result = usb_serial_generic_write_start(port);
+	if (result)
+		return result;
 
-	if (result >= 0)
-		result = count;
-
-	return result;
+	return count;
 }
 EXPORT_SYMBOL_GPL(usb_serial_generic_write);
 
 int usb_serial_generic_write_room(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	struct usb_serial *serial = port->serial;
 	unsigned long flags;
-	int room = 0;
+	int room;
 
 	dbg("%s - port %d", __func__, port->number);
 
@@ -369,14 +277,7 @@
 		return 0;
 
 	spin_lock_irqsave(&port->lock, flags);
-	if (serial->type->max_in_flight_urbs) {
-		if (port->urbs_in_flight < serial->type->max_in_flight_urbs)
-			room = port->bulk_out_size *
-				(serial->type->max_in_flight_urbs -
-				 port->urbs_in_flight);
-	} else {
-		room = kfifo_avail(&port->write_fifo);
-	}
+	room = kfifo_avail(&port->write_fifo);
 	spin_unlock_irqrestore(&port->lock, flags);
 
 	dbg("%s - returns %d", __func__, room);
@@ -386,7 +287,6 @@
 int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	struct usb_serial *serial = port->serial;
 	unsigned long flags;
 	int chars;
 
@@ -396,61 +296,47 @@
 		return 0;
 
 	spin_lock_irqsave(&port->lock, flags);
-	if (serial->type->max_in_flight_urbs)
-		chars = port->tx_bytes_flight;
-	else
-		chars = kfifo_len(&port->write_fifo);
+	chars = kfifo_len(&port->write_fifo) + port->tx_bytes;
 	spin_unlock_irqrestore(&port->lock, flags);
 
 	dbg("%s - returns %d", __func__, chars);
 	return chars;
 }
 
-
-void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port,
-			gfp_t mem_flags)
+int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
+					gfp_t mem_flags)
 {
-	struct urb *urb = port->read_urb;
-	struct usb_serial *serial = port->serial;
 	int result;
 
-	/* Continue reading from device */
-	usb_fill_bulk_urb(urb, serial->dev,
-			   usb_rcvbulkpipe(serial->dev,
-					port->bulk_in_endpointAddress),
-			   urb->transfer_buffer,
-			   urb->transfer_buffer_length,
-			   ((serial->type->read_bulk_callback) ?
-			     serial->type->read_bulk_callback :
-			     usb_serial_generic_read_bulk_callback), port);
-
-	result = usb_submit_urb(urb, mem_flags);
+	result = usb_submit_urb(port->read_urb, mem_flags);
 	if (result && result != -EPERM) {
-		dev_err(&port->dev,
-			"%s - failed resubmitting read urb, error %d\n",
+		dev_err(&port->dev, "%s - error submitting urb: %d\n",
 							__func__, result);
 	}
+	return result;
 }
-EXPORT_SYMBOL_GPL(usb_serial_generic_resubmit_read_urb);
+EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb);
 
-/* Push data to tty layer and resubmit the bulk read URB */
-static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
+void usb_serial_generic_process_read_urb(struct urb *urb)
 {
-	struct urb *urb = port->read_urb;
-	struct tty_struct *tty = tty_port_tty_get(&port->port);
+	struct usb_serial_port *port = urb->context;
+	struct tty_struct *tty;
 	char *ch = (char *)urb->transfer_buffer;
 	int i;
 
+	if (!urb->actual_length)
+		return;
+
+	tty = tty_port_tty_get(&port->port);
 	if (!tty)
-		goto done;
+		return;
 
 	/* The per character mucking around with sysrq path it too slow for
 	   stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases
 	   where the USB serial is not a console anyway */
-	if (!port->console || !port->sysrq)
+	if (!port->port.console || !port->sysrq)
 		tty_insert_flip_string(tty, ch, urb->actual_length);
 	else {
-		/* Push data to tty */
 		for (i = 0; i < urb->actual_length; i++, ch++) {
 			if (!usb_serial_handle_sysrq_char(tty, port, *ch))
 				tty_insert_flip_char(tty, *ch, TTY_NORMAL);
@@ -458,9 +344,8 @@
 	}
 	tty_flip_buffer_push(tty);
 	tty_kref_put(tty);
-done:
-	usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC);
 }
+EXPORT_SYMBOL_GPL(usb_serial_generic_process_read_urb);
 
 void usb_serial_generic_read_bulk_callback(struct urb *urb)
 {
@@ -479,13 +364,14 @@
 
 	usb_serial_debug_data(debug, &port->dev, __func__,
 						urb->actual_length, data);
+	port->serial->type->process_read_urb(urb);
 
 	/* Throttle the device if requested by tty */
 	spin_lock_irqsave(&port->lock, flags);
 	port->throttled = port->throttle_req;
 	if (!port->throttled) {
 		spin_unlock_irqrestore(&port->lock, flags);
-		flush_and_resubmit_read_urb(port);
+		usb_serial_generic_submit_read_urb(port, GFP_ATOMIC);
 	} else
 		spin_unlock_irqrestore(&port->lock, flags);
 }
@@ -496,30 +382,29 @@
 	unsigned long flags;
 	struct usb_serial_port *port = urb->context;
 	int status = urb->status;
+	int i;
 
 	dbg("%s - port %d", __func__, port->number);
 
-	if (port->serial->type->max_in_flight_urbs) {
-		kfree(urb->transfer_buffer);
+	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+		if (port->write_urbs[i] == urb)
+			break;
+
+	spin_lock_irqsave(&port->lock, flags);
+	port->tx_bytes -= urb->transfer_buffer_length;
+	set_bit(i, &port->write_urbs_free);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	if (status) {
+		dbg("%s - non-zero urb status: %d", __func__, status);
 
 		spin_lock_irqsave(&port->lock, flags);
-		--port->urbs_in_flight;
-		port->tx_bytes_flight -= urb->transfer_buffer_length;
-		if (port->urbs_in_flight < 0)
-			port->urbs_in_flight = 0;
+		kfifo_reset_out(&port->write_fifo);
 		spin_unlock_irqrestore(&port->lock, flags);
 	} else {
-		port->write_urb_busy = 0;
-
-		if (status)
-			kfifo_reset_out(&port->write_fifo);
-		else
-			usb_serial_generic_write_start(port);
+		usb_serial_generic_write_start(port);
 	}
 
-	if (status)
-		dbg("%s - non-zero urb status: %d", __func__, status);
-
 	usb_serial_port_softint(port);
 }
 EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback);
@@ -537,31 +422,31 @@
 	port->throttle_req = 1;
 	spin_unlock_irqrestore(&port->lock, flags);
 }
+EXPORT_SYMBOL_GPL(usb_serial_generic_throttle);
 
 void usb_serial_generic_unthrottle(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
 	int was_throttled;
-	unsigned long flags;
 
 	dbg("%s - port %d", __func__, port->number);
 
 	/* Clear the throttle flags */
-	spin_lock_irqsave(&port->lock, flags);
+	spin_lock_irq(&port->lock);
 	was_throttled = port->throttled;
 	port->throttled = port->throttle_req = 0;
-	spin_unlock_irqrestore(&port->lock, flags);
+	spin_unlock_irq(&port->lock);
 
-	if (was_throttled) {
-		/* Resume reading from device */
-		flush_and_resubmit_read_urb(port);
-	}
+	if (was_throttled)
+		usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
 }
+EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle);
 
+#ifdef CONFIG_MAGIC_SYSRQ
 int usb_serial_handle_sysrq_char(struct tty_struct *tty,
 			struct usb_serial_port *port, unsigned int ch)
 {
-	if (port->sysrq && port->console) {
+	if (port->sysrq && port->port.console) {
 		if (ch && time_before(jiffies, port->sysrq)) {
 			handle_sysrq(ch, tty);
 			port->sysrq = 0;
@@ -571,6 +456,13 @@
 	}
 	return 0;
 }
+#else
+int usb_serial_handle_sysrq_char(struct tty_struct *tty,
+			struct usb_serial_port *port, unsigned int ch)
+{
+	return 0;
+}
+#endif
 EXPORT_SYMBOL_GPL(usb_serial_handle_sysrq_char);
 
 int usb_serial_handle_break(struct usb_serial_port *port)
@@ -600,7 +492,7 @@
 				c++;
 		}
 
-		if (port->write_urb) {
+		if (port->bulk_out_size) {
 			r = usb_serial_generic_write_start(port);
 			if (r < 0)
 				c++;
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 3ef8df0..76e6fb3 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -3020,7 +3020,7 @@
 
 	/* set up our port private structures */
 	for (i = 0; i < serial->num_ports; ++i) {
-		edge_port = kmalloc(sizeof(struct edgeport_port), GFP_KERNEL);
+		edge_port = kzalloc(sizeof(struct edgeport_port), GFP_KERNEL);
 		if (edge_port == NULL) {
 			dev_err(&serial->dev->dev, "%s - Out of memory\n",
 								   __func__);
@@ -3033,7 +3033,6 @@
 			kfree(edge_serial);
 			return -ENOMEM;
 		}
-		memset(edge_port, 0, sizeof(struct edgeport_port));
 		spin_lock_init(&edge_port->ep_lock);
 		edge_port->port = serial->port[i];
 		usb_set_serial_port_data(serial->port[i], edge_port);
diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h
index cb201c1..dced7ec 100644
--- a/drivers/usb/serial/io_edgeport.h
+++ b/drivers/usb/serial/io_edgeport.h
@@ -34,15 +34,15 @@
 
 
 
-/* The following table is used to map the USBx port number to 
+/* The following table is used to map the USBx port number to
  * the device serial number (or physical USB path), */
 #define MAX_EDGEPORTS	64
 
 struct comMapper {
 	char	SerialNumber[MAX_SERIALNUMBER_LEN+1];	/* Serial number/usb path */
-	int	numPorts;			       	/* Number of ports */
-	int	Original[MAX_RS232_PORTS];	       	/* Port numbers set by IOCTL */
-	int	Port[MAX_RS232_PORTS];		       	/* Actual used port numbers */
+	int	numPorts;				/* Number of ports */
+	int	Original[MAX_RS232_PORTS];		/* Port numbers set by IOCTL */
+	int	Port[MAX_RS232_PORTS];			/* Actual used port numbers */
 };
 
 
@@ -51,7 +51,7 @@
 /* /proc/edgeport Interface
  * This interface uses read/write/lseek interface to talk to the edgeport driver
  * the following read functions are supported: */
-#define PROC_GET_MAPPING_TO_PATH 	1
+#define PROC_GET_MAPPING_TO_PATH	1
 #define PROC_GET_COM_ENTRY		2
 #define PROC_GET_EDGE_MANUF_DESCRIPTOR	3
 #define PROC_GET_BOOT_DESCRIPTOR	4
@@ -64,7 +64,7 @@
 
 
 /* the following write functions are supported: */
-#define PROC_SET_COM_MAPPING 		1
+#define PROC_SET_COM_MAPPING		1
 #define PROC_SET_COM_ENTRY		2
 
 
@@ -97,8 +97,8 @@
 	__u8	BoardRev;			/* PCB revision level (chg only if s/w visible) */
 
 	__u8	BootMajorVersion;		/* Boot Firmware version: xx. */
-	__u8	BootMinorVersion;		/*	   		  yy. */
-	__le16	BootBuildNumber;		/*		      	  zzzz (LE format) */
+	__u8	BootMinorVersion;		/*			  yy. */
+	__le16	BootBuildNumber;		/*			  zzzz (LE format) */
 
 	__u8	FirmwareMajorVersion;		/* Operational Firmware version:xx. */
 	__u8	FirmwareMinorVersion;		/*				yy. */
diff --git a/drivers/usb/serial/io_ionsp.h b/drivers/usb/serial/io_ionsp.h
index 092e03d..5cc591b 100644
--- a/drivers/usb/serial/io_ionsp.h
+++ b/drivers/usb/serial/io_ionsp.h
@@ -89,10 +89,10 @@
 //
 
 struct int_status_pkt {
-	__u16      RxBytesAvail;		    // Additional bytes available to
-						    // be read from Bulk IN pipe
-	__u16      TxCredits[ MAX_RS232_PORTS ];   // Additional space available in
-						    // given port's TxBuffer
+	__u16 RxBytesAvail;			// Additional bytes available to
+						// be read from Bulk IN pipe
+	__u16 TxCredits[MAX_RS232_PORTS];	// Additional space available in
+						// given port's TxBuffer
 };
 
 
@@ -115,24 +115,24 @@
 #define	IOSP_CMD_STAT_BIT		0x80		// If set, this is command/status header
 
 #define IS_CMD_STAT_HDR(Byte1)		((Byte1) & IOSP_CMD_STAT_BIT)
-#define IS_DATA_HDR(Byte1)		(! IS_CMD_STAT_HDR(Byte1))
+#define IS_DATA_HDR(Byte1)		(!IS_CMD_STAT_HDR(Byte1))
 
 #define	IOSP_GET_HDR_PORT(Byte1)		((__u8) ((Byte1) & IOSP_PORT_MASK))
-#define	IOSP_GET_HDR_DATA_LEN(Byte1, Byte2)	((__u16) ( ((__u16)((Byte1) & 0x78)) << 5) | (Byte2))
+#define	IOSP_GET_HDR_DATA_LEN(Byte1, Byte2)	((__u16) (((__u16)((Byte1) & 0x78)) << 5) | (Byte2))
 #define	IOSP_GET_STATUS_CODE(Byte1)		((__u8) (((Byte1) &  0x78) >> 3))
 
 
 //
 // These macros build the 1st and 2nd bytes for a data header
 //
-#define	IOSP_BUILD_DATA_HDR1(Port, Len)		((__u8) (((Port) | ((__u8) (((__u16) (Len)) >> 5) & 0x78 ))))
+#define	IOSP_BUILD_DATA_HDR1(Port, Len)		((__u8) (((Port) | ((__u8) (((__u16) (Len)) >> 5) & 0x78))))
 #define	IOSP_BUILD_DATA_HDR2(Port, Len)		((__u8) (Len))
 
 
 //
 // These macros build the 1st and 2nd bytes for a command header
 //
-#define	IOSP_BUILD_CMD_HDR1(Port, Cmd)		((__u8) ( IOSP_CMD_STAT_BIT | (Port) |	((__u8) ((Cmd) << 3)) ))
+#define	IOSP_BUILD_CMD_HDR1(Port, Cmd)		((__u8) (IOSP_CMD_STAT_BIT | (Port) | ((__u8) ((Cmd) << 3))))
 
 
 //--------------------------------------------------------------
@@ -194,24 +194,25 @@
 // Define macros to simplify building of IOSP cmds
 //
 
-#define	MAKE_CMD_WRITE_REG(ppBuf, pLen, Port, Reg, Val)						\
-	do {											\
-		(*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1( (Port), IOSP_WRITE_UART_REG(Reg) );	\
-		(*(ppBuf))[1] = (Val);								\
-												\
-		*ppBuf += 2;									\
-		*pLen  += 2;									\
-	} while (0)
+#define MAKE_CMD_WRITE_REG(ppBuf, pLen, Port, Reg, Val)			\
+do {									\
+	(*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1((Port),			\
+					    IOSP_WRITE_UART_REG(Reg));	\
+	(*(ppBuf))[1] = (Val);						\
+									\
+	*ppBuf += 2;							\
+	*pLen  += 2;							\
+} while (0)
 
-#define	MAKE_CMD_EXT_CMD(ppBuf, pLen, Port, ExtCmd, Param)					\
-	do {											\
-		(*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1( (Port), IOSP_EXT_CMD );			\
-		(*(ppBuf))[1] = (ExtCmd);							\
-		(*(ppBuf))[2] = (Param);							\
-												\
-		*ppBuf += 3;									\
-		*pLen  += 3;									\
-	} while (0)
+#define MAKE_CMD_EXT_CMD(ppBuf, pLen, Port, ExtCmd, Param)		\
+do {									\
+	(*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1((Port), IOSP_EXT_CMD);	\
+	(*(ppBuf))[1] = (ExtCmd);					\
+	(*(ppBuf))[2] = (Param);					\
+									\
+	*ppBuf += 3;							\
+	*pLen  += 3;							\
+} while (0)
 
 
 
@@ -310,16 +311,16 @@
 //
 //	IOSP_CMD_RX_CHECK_REQ
 //
-//  This command is used to assist in the implementation of the 
-//  IOCTL_SERIAL_PURGE Windows IOCTL.  
-//  This IOSP command tries to place a marker at the end of the RX 
-//  queue in the Edgeport. If the Edgeport RX queue is full then 
-//  the Check will be discarded.  
-//  It is up to the device driver to timeout waiting for the 
-//  RX_CHECK_RSP.  If a RX_CHECK_RSP is received, the driver is 
-//	sure that all data has been received from the edgeport and 
+//  This command is used to assist in the implementation of the
+//  IOCTL_SERIAL_PURGE Windows IOCTL.
+//  This IOSP command tries to place a marker at the end of the RX
+//  queue in the Edgeport. If the Edgeport RX queue is full then
+//  the Check will be discarded.
+//  It is up to the device driver to timeout waiting for the
+//  RX_CHECK_RSP.  If a RX_CHECK_RSP is received, the driver is
+//	sure that all data has been received from the edgeport and
 //	may now purge any internal RX buffers.
-//  Note tat the sequence numbers may be used to detect lost 
+//  Note tat the sequence numbers may be used to detect lost
 //  CHECK_REQs.
 
 //  Example for Port 0
@@ -341,7 +342,7 @@
 //
 //	1ssssPPP P1P1P1P1 [ P2P2P2P2P2 ]...
 //
-// 	ssss:	00-07	2-byte status.	ssss identifies which UART register
+//	ssss:	00-07	2-byte status.	ssss identifies which UART register
 //					has changed value, and the new value is in P1.
 //					Note that the ssss values do not correspond to the
 //					16554 register numbers given in 16554.H. Instead,
@@ -383,14 +384,14 @@
 // returns this in order to report
 // changes in modem status lines
 // (CTS, DSR, RI, CD)
-// 
+//
 
 //					0x02	// Available for future expansion
-//					0x03	// 
-//					0x04	// 
-//					0x05	// 
-//					0x06	// 
-//					0x07	// 
+//					0x03	//
+//					0x04	//
+//					0x05	//
+//					0x06	//
+//					0x07	//
 
 
 /****************************************************
@@ -400,7 +401,7 @@
 #define	IOSP_STATUS_LSR_DATA		0x08	// P1 is new value of LSR register (same as STATUS_LSR)
 
 // P2 is errored character read from
-//    RxFIFO after LSR reported an error.													
+//    RxFIFO after LSR reported an error.
 
 #define	IOSP_EXT_STATUS			0x09	// P1 is status/response code, param in P2.
 
@@ -408,7 +409,7 @@
 // Response Codes (P1 values) for 3-byte status messages
 
 #define	IOSP_EXT_STATUS_CHASE_RSP	0	// Reply to CHASE_PORT cmd. P2 is outcome:
-#define	IOSP_EXT_STATUS_CHASE_PASS	0	// 	P2 = 0: All Tx data drained successfully
+#define	IOSP_EXT_STATUS_CHASE_PASS	0	//	P2 = 0: All Tx data drained successfully
 #define	IOSP_EXT_STATUS_CHASE_FAIL	1	//	P2 = 1: Timed out (stuck due to flow
 
 //			control from remote device).
@@ -446,9 +447,9 @@
 // Macros to parse status messages
 //
 
-#define	IOSP_GET_STATUS_LEN(code)	( (code) < 8 ? 2 : ((code) < 0x0A ? 3 : 4) )
+#define	IOSP_GET_STATUS_LEN(code)	((code) < 8 ? 2 : ((code) < 0x0A ? 3 : 4))
 
-#define	IOSP_STATUS_IS_2BYTE(code)	( (code) < 0x08 )
-#define	IOSP_STATUS_IS_3BYTE(code)	( ((code) >= 0x08) && ((code) <= 0x0B) )
-#define	IOSP_STATUS_IS_4BYTE(code)	( ((code) >= 0x0C) && ((code) <= 0x0D) )
+#define	IOSP_STATUS_IS_2BYTE(code)	((code) < 0x08)
+#define	IOSP_STATUS_IS_3BYTE(code)	(((code) >= 0x08) && ((code) <= 0x0B))
+#define	IOSP_STATUS_IS_4BYTE(code)	(((code) >= 0x0C) && ((code) <= 0x0D))
 
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index aa876f7..0fca265 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -36,6 +36,7 @@
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
 #include <linux/serial.h>
+#include <linux/kfifo.h>
 #include <linux/ioctl.h>
 #include <linux/firmware.h>
 #include <linux/uaccess.h>
@@ -56,10 +57,6 @@
 #define EPROM_PAGE_SIZE		64
 
 
-struct edgeport_uart_buf_desc {
-	__u32 count;		/* Number of bytes currently in buffer */
-};
-
 /* different hardware types */
 #define HARDWARE_TYPE_930	0
 #define HARDWARE_TYPE_TIUMP	1
@@ -87,14 +84,6 @@
 	__u8	hardware_type;		/* Type of hardware */
 } __attribute__((packed));
 
-/* circular buffer */
-struct edge_buf {
-	unsigned int	buf_size;
-	char		*buf_buf;
-	char		*buf_get;
-	char		*buf_put;
-};
-
 struct edgeport_port {
 	__u16 uart_base;
 	__u16 dma_address;
@@ -108,7 +97,6 @@
 	int baud_rate;
 	int close_pending;
 	int lsr_event;
-	struct edgeport_uart_buf_desc tx;
 	struct async_icount	icount;
 	wait_queue_head_t	delta_msr_wait;	/* for handling sleeping while
 						   waiting for msr change to
@@ -119,7 +107,7 @@
 	spinlock_t ep_lock;
 	int ep_read_urb_state;
 	int ep_write_urb_in_use;
-	struct edge_buf *ep_out_buf;
+	struct kfifo write_fifo;
 };
 
 struct edgeport_serial {
@@ -249,17 +237,6 @@
 static int edge_create_sysfs_attrs(struct usb_serial_port *port);
 static int edge_remove_sysfs_attrs(struct usb_serial_port *port);
 
-/* circular buffer */
-static struct edge_buf *edge_buf_alloc(unsigned int size);
-static void edge_buf_free(struct edge_buf *eb);
-static void edge_buf_clear(struct edge_buf *eb);
-static unsigned int edge_buf_data_avail(struct edge_buf *eb);
-static unsigned int edge_buf_space_avail(struct edge_buf *eb);
-static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf,
-	unsigned int count);
-static unsigned int edge_buf_get(struct edge_buf *eb, char *buf,
-	unsigned int count);
-
 
 static int ti_vread_sync(struct usb_device *dev, __u8 request,
 				__u16 value, __u16 index, u8 *data, int size)
@@ -590,7 +567,7 @@
 	add_wait_queue(&tty->write_wait, &wait);
 	for (;;) {
 		set_current_state(TASK_INTERRUPTIBLE);
-		if (edge_buf_data_avail(port->ep_out_buf) == 0
+		if (kfifo_len(&port->write_fifo) == 0
 		|| timeout == 0 || signal_pending(current)
 		|| !usb_get_intfdata(port->port->serial->interface))
 			/* disconnect */
@@ -602,7 +579,7 @@
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&tty->write_wait, &wait);
 	if (flush)
-		edge_buf_clear(port->ep_out_buf);
+		kfifo_reset_out(&port->write_fifo);
 	spin_unlock_irqrestore(&port->ep_lock, flags);
 	tty_kref_put(tty);
 
@@ -2089,7 +2066,6 @@
 				const unsigned char *data, int count)
 {
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
-	unsigned long flags;
 
 	dbg("%s - port %d", __func__, port->number);
 
@@ -2103,10 +2079,8 @@
 	if (edge_port->close_pending == 1)
 		return -ENODEV;
 
-	spin_lock_irqsave(&edge_port->ep_lock, flags);
-	count = edge_buf_put(edge_port->ep_out_buf, data, count);
-	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
-
+	count = kfifo_in_locked(&edge_port->write_fifo, data, count,
+							&edge_port->ep_lock);
 	edge_send(tty);
 
 	return count;
@@ -2129,7 +2103,7 @@
 		return;
 	}
 
-	count = edge_buf_get(edge_port->ep_out_buf,
+	count = kfifo_out(&edge_port->write_fifo,
 				port->write_urb->transfer_buffer,
 				port->bulk_out_size);
 
@@ -2185,7 +2159,7 @@
 		return 0;
 
 	spin_lock_irqsave(&edge_port->ep_lock, flags);
-	room = edge_buf_space_avail(edge_port->ep_out_buf);
+	room = kfifo_avail(&edge_port->write_fifo);
 	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
 	dbg("%s - returns %d", __func__, room);
@@ -2207,7 +2181,7 @@
 		return 0;
 
 	spin_lock_irqsave(&edge_port->ep_lock, flags);
-	chars = edge_buf_data_avail(edge_port->ep_out_buf);
+	chars = kfifo_len(&edge_port->write_fifo);
 	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
 	dbg("%s - returns %d", __func__, chars);
@@ -2664,8 +2638,8 @@
 			goto cleanup;
 		}
 		spin_lock_init(&edge_port->ep_lock);
-		edge_port->ep_out_buf = edge_buf_alloc(EDGE_OUT_BUF_SIZE);
-		if (edge_port->ep_out_buf == NULL) {
+		if (kfifo_alloc(&edge_port->write_fifo, EDGE_OUT_BUF_SIZE,
+								GFP_KERNEL)) {
 			dev_err(&serial->dev->dev, "%s - Out of memory\n",
 								__func__);
 			kfree(edge_port);
@@ -2682,7 +2656,7 @@
 cleanup:
 	for (--i; i >= 0; --i) {
 		edge_port = usb_get_serial_port_data(serial->port[i]);
-		edge_buf_free(edge_port->ep_out_buf);
+		kfifo_free(&edge_port->write_fifo);
 		kfree(edge_port);
 		usb_set_serial_port_data(serial->port[i], NULL);
 	}
@@ -2713,7 +2687,7 @@
 
 	for (i = 0; i < serial->num_ports; ++i) {
 		edge_port = usb_get_serial_port_data(serial->port[i]);
-		edge_buf_free(edge_port->ep_out_buf);
+		kfifo_free(&edge_port->write_fifo);
 		kfree(edge_port);
 	}
 	kfree(usb_get_serial_data(serial));
@@ -2763,182 +2737,6 @@
 }
 
 
-/* Circular Buffer */
-
-/*
- * edge_buf_alloc
- *
- * Allocate a circular buffer and all associated memory.
- */
-
-static struct edge_buf *edge_buf_alloc(unsigned int size)
-{
-	struct edge_buf *eb;
-
-
-	if (size == 0)
-		return NULL;
-
-	eb = kmalloc(sizeof(struct edge_buf), GFP_KERNEL);
-	if (eb == NULL)
-		return NULL;
-
-	eb->buf_buf = kmalloc(size, GFP_KERNEL);
-	if (eb->buf_buf == NULL) {
-		kfree(eb);
-		return NULL;
-	}
-
-	eb->buf_size = size;
-	eb->buf_get = eb->buf_put = eb->buf_buf;
-
-	return eb;
-}
-
-
-/*
- * edge_buf_free
- *
- * Free the buffer and all associated memory.
- */
-
-static void edge_buf_free(struct edge_buf *eb)
-{
-	if (eb) {
-		kfree(eb->buf_buf);
-		kfree(eb);
-	}
-}
-
-
-/*
- * edge_buf_clear
- *
- * Clear out all data in the circular buffer.
- */
-
-static void edge_buf_clear(struct edge_buf *eb)
-{
-	if (eb != NULL)
-		eb->buf_get = eb->buf_put;
-	/* equivalent to a get of all data available */
-}
-
-
-/*
- * edge_buf_data_avail
- *
- * Return the number of bytes of data available in the circular
- * buffer.
- */
-
-static unsigned int edge_buf_data_avail(struct edge_buf *eb)
-{
-	if (eb == NULL)
-		return 0;
-	return ((eb->buf_size + eb->buf_put - eb->buf_get) % eb->buf_size);
-}
-
-
-/*
- * edge_buf_space_avail
- *
- * Return the number of bytes of space available in the circular
- * buffer.
- */
-
-static unsigned int edge_buf_space_avail(struct edge_buf *eb)
-{
-	if (eb == NULL)
-		return 0;
-	return ((eb->buf_size + eb->buf_get - eb->buf_put - 1) % eb->buf_size);
-}
-
-
-/*
- * edge_buf_put
- *
- * Copy data data from a user buffer and put it into the circular buffer.
- * Restrict to the amount of space available.
- *
- * Return the number of bytes copied.
- */
-
-static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf,
-	unsigned int count)
-{
-	unsigned int len;
-
-
-	if (eb == NULL)
-		return 0;
-
-	len  = edge_buf_space_avail(eb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = eb->buf_buf + eb->buf_size - eb->buf_put;
-	if (count > len) {
-		memcpy(eb->buf_put, buf, len);
-		memcpy(eb->buf_buf, buf+len, count - len);
-		eb->buf_put = eb->buf_buf + count - len;
-	} else {
-		memcpy(eb->buf_put, buf, count);
-		if (count < len)
-			eb->buf_put += count;
-		else /* count == len */
-			eb->buf_put = eb->buf_buf;
-	}
-
-	return count;
-}
-
-
-/*
- * edge_buf_get
- *
- * Get data from the circular buffer and copy to the given buffer.
- * Restrict to the amount of data available.
- *
- * Return the number of bytes copied.
- */
-
-static unsigned int edge_buf_get(struct edge_buf *eb, char *buf,
-	unsigned int count)
-{
-	unsigned int len;
-
-
-	if (eb == NULL)
-		return 0;
-
-	len = edge_buf_data_avail(eb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = eb->buf_buf + eb->buf_size - eb->buf_get;
-	if (count > len) {
-		memcpy(buf, eb->buf_get, len);
-		memcpy(buf+len, eb->buf_buf, count - len);
-		eb->buf_get = eb->buf_buf + count - len;
-	} else {
-		memcpy(buf, eb->buf_get, count);
-		if (count < len)
-			eb->buf_get += count;
-		else /* count == len */
-			eb->buf_get = eb->buf_buf;
-	}
-
-	return count;
-}
-
-
 static struct usb_serial_driver edgeport_1port_device = {
 	.driver = {
 		.owner		= THIS_MODULE,
diff --git a/drivers/usb/serial/io_ti.h b/drivers/usb/serial/io_ti.h
index cab84f2..1bd67b2 100644
--- a/drivers/usb/serial/io_ti.h
+++ b/drivers/usb/serial/io_ti.h
@@ -1,4 +1,4 @@
-/*****************************************************************************  
+/*****************************************************************************
  *
  *	Copyright (C) 1997-2002 Inside Out Networks, Inc.
  *
@@ -22,10 +22,10 @@
 #define DTK_ADDR_SPACE_I2C_TYPE_II	0x82	/* Addr is placed in I2C area */
 #define DTK_ADDR_SPACE_I2C_TYPE_III	0x83	/* Addr is placed in I2C area */
 
-// UART Defines
-#define UMPMEM_BASE_UART1		0xFFA0  /* UMP UART1 base address          */
-#define UMPMEM_BASE_UART2		0xFFB0  /* UMP UART2 base address          */
-#define UMPMEM_OFFS_UART_LSR		0x05    /* UMP UART LSR register offset    */
+/* UART Defines */
+#define UMPMEM_BASE_UART1		0xFFA0	/* UMP UART1 base address */
+#define UMPMEM_BASE_UART2		0xFFB0	/* UMP UART2 base address */
+#define UMPMEM_OFFS_UART_LSR		0x05	/* UMP UART LSR register offset */
 
 /* Bits per character */
 #define UMP_UART_CHAR5BITS		0x00
@@ -54,7 +54,7 @@
 #define UMP_UART_LSR_RX_MASK		0x10
 #define UMP_UART_LSR_TX_MASK		0x20
 
-#define UMP_UART_LSR_DATA_MASK		( LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK )
+#define UMP_UART_LSR_DATA_MASK		(LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK)
 
 /* Port Settings Constants) */
 #define UMP_MASK_UART_FLAGS_RTS_FLOW		0x0001
@@ -79,50 +79,57 @@
 #define UMP_PORT_DIR_OUT			0x01
 #define UMP_PORT_DIR_IN				0x02
 
-// Address of Port 0
-#define UMPM_UART1_PORT  			0x03
+/* Address of Port 0 */
+#define UMPM_UART1_PORT				0x03
 
-// Commands
-#define	UMPC_SET_CONFIG 		0x05
-#define	UMPC_OPEN_PORT  		0x06
-#define	UMPC_CLOSE_PORT 		0x07
-#define	UMPC_START_PORT 		0x08
-#define	UMPC_STOP_PORT  		0x09
-#define	UMPC_TEST_PORT  		0x0A
-#define	UMPC_PURGE_PORT 		0x0B
+/* Commands */
+#define	UMPC_SET_CONFIG			0x05
+#define	UMPC_OPEN_PORT			0x06
+#define	UMPC_CLOSE_PORT			0x07
+#define	UMPC_START_PORT			0x08
+#define	UMPC_STOP_PORT			0x09
+#define	UMPC_TEST_PORT			0x0A
+#define	UMPC_PURGE_PORT			0x0B
 
-#define	UMPC_COMPLETE_READ		0x80	// Force the Firmware to complete the current Read
-#define	UMPC_HARDWARE_RESET		0x81	// Force UMP back into BOOT Mode
-#define	UMPC_COPY_DNLD_TO_I2C		0x82	// Copy current download image to type 0xf2 record in 16k I2C
-						// firmware will change 0xff record to type 2 record when complete
+/* Force the Firmware to complete the current Read */
+#define	UMPC_COMPLETE_READ		0x80
+/* Force UMP back into BOOT Mode */
+#define	UMPC_HARDWARE_RESET		0x81
+/*
+ * Copy current download image to type 0xf2 record in 16k I2C
+ * firmware will change 0xff record to type 2 record when complete
+ */
+#define	UMPC_COPY_DNLD_TO_I2C		0x82
 
-	// Special function register commands
-	// wIndex is register address
-	// wValue is MSB/LSB mask/data
-#define	UMPC_WRITE_SFR	  		0x83	// Write SFR Register
+/*
+ * Special function register commands
+ * wIndex is register address
+ * wValue is MSB/LSB mask/data
+ */
+#define	UMPC_WRITE_SFR			0x83	/* Write SFR Register */
 
-	// wIndex is register address
-#define	UMPC_READ_SFR	  		0x84	// Read SRF Register
+/* wIndex is register address */
+#define	UMPC_READ_SFR			0x84	/* Read SRF Register */
 
-	// Set or Clear DTR (wValue bit 0 Set/Clear)		wIndex ModuleID (port)
+/* Set or Clear DTR (wValue bit 0 Set/Clear)	wIndex ModuleID (port) */
 #define	UMPC_SET_CLR_DTR		0x85
 
-	// Set or Clear RTS (wValue bit 0 Set/Clear)		wIndex ModuleID (port)
+/* Set or Clear RTS (wValue bit 0 Set/Clear)	wIndex ModuleID (port) */
 #define	UMPC_SET_CLR_RTS		0x86
 
-	// Set or Clear LOOPBACK (wValue bit 0 Set/Clear)	wIndex ModuleID (port)
+/* Set or Clear LOOPBACK (wValue bit 0 Set/Clear) wIndex ModuleID (port) */
 #define	UMPC_SET_CLR_LOOPBACK		0x87
 
-	// Set or Clear BREAK (wValue bit 0 Set/Clear)		wIndex ModuleID (port)
+/* Set or Clear BREAK (wValue bit 0 Set/Clear)	wIndex ModuleID (port) */
 #define	UMPC_SET_CLR_BREAK		0x88
 
-	// Read MSR wIndex ModuleID (port)
+/* Read MSR wIndex ModuleID (port) */
 #define	UMPC_READ_MSR			0x89
 
-	/* Toolkit commands */
-	/* Read-write group */
-#define	UMPC_MEMORY_READ   		0x92
-#define	UMPC_MEMORY_WRITE  		0x93
+/* Toolkit commands */
+/* Read-write group */
+#define	UMPC_MEMORY_READ		0x92
+#define	UMPC_MEMORY_WRITE		0x93
 
 /*
  *	UMP DMA Definitions
@@ -130,8 +137,7 @@
 #define UMPD_OEDB1_ADDRESS		0xFF08
 #define UMPD_OEDB2_ADDRESS		0xFF10
 
-struct out_endpoint_desc_block
-{
+struct out_endpoint_desc_block {
 	__u8 Configuration;
 	__u8 XBufAddr;
 	__u8 XByteCount;
@@ -147,8 +153,8 @@
  * TYPE DEFINITIONS
  * Structures for Firmware commands
  */
-struct ump_uart_config		/* UART settings                    */
-{
+/* UART settings */
+struct ump_uart_config {
 	__u16 wBaudRate;	/* Baud rate                        */
 	__u16 wFlags;		/* Bitmap mask of flags             */
 	__u8 bDataBits;		/* 5..8 - data bits per character   */
@@ -165,8 +171,8 @@
  * TYPE DEFINITIONS
  * Structures for USB interrupts
  */
-struct ump_interrupt			/* Interrupt packet structure       */
-{
+/* Interrupt packet structure */
+struct ump_interrupt {
 	__u8 bICode;			/* Interrupt code (interrupt num)   */
 	__u8 bIInfo;			/* Interrupt information            */
 }  __attribute__((packed));
diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
index 8e1a491..51f83fb 100644
--- a/drivers/usb/serial/io_usbvend.h
+++ b/drivers/usb/serial/io_usbvend.h
@@ -26,7 +26,7 @@
 
 //
 // Definitions of USB product IDs
-// 
+//
 
 #define	USB_VENDOR_ID_ION	0x1608		// Our VID
 #define	USB_VENDOR_ID_TI	0x0451		// TI VID
@@ -54,7 +54,7 @@
 // Product IDs - assigned to match middle digit of serial number (No longer true)
 
 #define ION_DEVICE_ID_80251_NETCHIP	0x020	// This bit is set in the PID if this edgeport hardware$
-						// is based on the 80251+Netchip.  
+						// is based on the 80251+Netchip.
 
 #define ION_DEVICE_ID_GENERATION_1	0x00	// Value for 930 based edgeports
 #define ION_DEVICE_ID_GENERATION_2	0x01	// Value for 80251+Netchip.
@@ -134,7 +134,7 @@
 #define ION_DEVICE_ID_TI_EDGEPORT_416		0x0212  // Edgeport/416
 #define ION_DEVICE_ID_TI_EDGEPORT_1		0x0215	// Edgeport/1 RS232
 #define ION_DEVICE_ID_TI_EDGEPORT_42		0x0217	// Edgeport/42 4 hub 2 RS232
-#define ION_DEVICE_ID_TI_EDGEPORT_22I  		0x021A	// Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232
+#define ION_DEVICE_ID_TI_EDGEPORT_22I		0x021A	// Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232
 #define ION_DEVICE_ID_TI_EDGEPORT_2C		0x021B	// Edgeport/2c RS232
 #define ION_DEVICE_ID_TI_EDGEPORT_221C		0x021C	// Edgeport/221c is a TI based Edgeport/2 with lucent chip and
 							// 2 external hub ports - Large I2C
@@ -142,7 +142,7 @@
 							// 2 external hub ports - Large I2C
 #define ION_DEVICE_ID_TI_EDGEPORT_21C		0x021E	// Edgeport/21c is a TI based Edgeport/2 with lucent chip
 
-// Generation 3 devices -- 3410 based edgport/1 (256 byte I2C) 
+// Generation 3 devices -- 3410 based edgport/1 (256 byte I2C)
 #define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1	0x0240	// Edgeport/1 RS232
 #define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I	0x0241	// Edgeport/1i- RS422 model
 
@@ -176,7 +176,7 @@
 							// Default to /P function
 
 #define ION_DEVICE_ID_PLUS_PWR_HP4CD		0x30C	// 5052 Plus Power HubPort/4CD+ (for Dell)
-#define ION_DEVICE_ID_PLUS_PWR_HP4C		0x30D	// 5052 Plus Power HubPort/4C+ 
+#define ION_DEVICE_ID_PLUS_PWR_HP4C		0x30D	// 5052 Plus Power HubPort/4C+
 #define ION_DEVICE_ID_PLUS_PWR_PCI		0x30E	// 3410 Plus Power PCI Host Controller 4 port
 
 
@@ -217,17 +217,17 @@
 #define ION_DEVICE_ID_MT4X56USB			0x1403	// OEM device
 
 
-#define	GENERATION_ID_FROM_USB_PRODUCT_ID( ProductId )				\
-			( (__u16) ((ProductId >> 8) & (ION_GENERATION_MASK)) )
+#define	GENERATION_ID_FROM_USB_PRODUCT_ID(ProductId)				\
+			((__u16) ((ProductId >> 8) & (ION_GENERATION_MASK)))
 
-#define	MAKE_USB_PRODUCT_ID( OemId, DeviceId )					\
-			( (__u16) (((OemId) << 10) || (DeviceId)) )
+#define	MAKE_USB_PRODUCT_ID(OemId, DeviceId)					\
+			((__u16) (((OemId) << 10) || (DeviceId)))
 
-#define	DEVICE_ID_FROM_USB_PRODUCT_ID( ProductId )				\
-			( (__u16) ((ProductId) & (EDGEPORT_DEVICE_ID_MASK)) )
+#define	DEVICE_ID_FROM_USB_PRODUCT_ID(ProductId)				\
+			((__u16) ((ProductId) & (EDGEPORT_DEVICE_ID_MASK)))
 
-#define	OEM_ID_FROM_USB_PRODUCT_ID( ProductId )					\
-			( (__u16) (((ProductId) >> 10) & 0x3F) )
+#define	OEM_ID_FROM_USB_PRODUCT_ID(ProductId)					\
+			((__u16) (((ProductId) >> 10) & 0x3F))
 
 //
 // Definitions of parameters for download code. Note that these are
@@ -237,7 +237,7 @@
 
 // TxCredits value below which driver won't bother sending (to prevent too many small writes).
 // Send only if above 25%
-#define EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(InitialCredit, MaxPacketSize) (max( ((InitialCredit) / 4), (MaxPacketSize) ))
+#define EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(InitialCredit, MaxPacketSize) (max(((InitialCredit) / 4), (MaxPacketSize)))
 
 #define	EDGE_FW_BULK_MAX_PACKET_SIZE		64	// Max Packet Size for Bulk In Endpoint (EP1)
 #define EDGE_FW_BULK_READ_BUFFER_SIZE		1024	// Size to use for Bulk reads
@@ -263,7 +263,7 @@
 //		wValue = 16-bit address
 //		wIndex = unused (though we could put segment 00: or FF: here)
 //		wLength = # bytes to read/write (max 64)
-//							
+//
 
 #define USB_REQUEST_ION_RESET_DEVICE	0	// Warm reboot Edgeport, retaining USB address
 #define USB_REQUEST_ION_GET_EPIC_DESC	1	// Get Edgeport Compatibility Descriptor
@@ -278,7 +278,7 @@
 #define USB_REQUEST_ION_ENABLE_SUSPEND	9	// Enable/Disable suspend feature
 						// (wValue != 0: Enable; wValue = 0: Disable)
 
-#define USB_REQUEST_ION_SEND_IOSP	10	// Send an IOSP command to the edgeport over the control pipe	
+#define USB_REQUEST_ION_SEND_IOSP	10	// Send an IOSP command to the edgeport over the control pipe
 #define USB_REQUEST_ION_RECV_IOSP	11	// Receive an IOSP command from the edgeport over the control pipe
 
 
@@ -301,8 +301,7 @@
 // this is a "real" Edgeport.
 //
 
-struct edge_compatibility_bits
-{
+struct edge_compatibility_bits {
 	// This __u32 defines which Vendor-specific commands/functionality
 	// the device supports on the default EP0 pipe.
 
@@ -334,24 +333,22 @@
 	__u32	TrueEdgeport		:  1;	// 0001	Set if device is a 'real' Edgeport
 											// (Used only by driver, NEVER set by an EPiC device)
 	__u32	GenUnused		: 31;	// Available for future expansion, must be 0
-
 };
 
 #define EDGE_COMPATIBILITY_MASK0	0x0001
 #define EDGE_COMPATIBILITY_MASK1	0x3FFF
 #define EDGE_COMPATIBILITY_MASK2	0x0001
 
-struct edge_compatibility_descriptor
-{
+struct edge_compatibility_descriptor {
 	__u8	Length;				// Descriptor Length (per USB spec)
 	__u8	DescType;			// Descriptor Type (per USB spec, =DEVICE type)
 	__u8	EpicVer;			// Version of EPiC spec supported
-											// (Currently must be 1)
+						// (Currently must be 1)
 	__u8	NumPorts;			// Number of serial ports supported
 	__u8	iDownloadFile;			// Index of string containing download code filename
-											// 0=no download, FF=download compiled into driver.
-	__u8	Unused[ 3 ];			// Available for future expansion, must be 0
-											// (Currently must be 0).
+						// 0=no download, FF=download compiled into driver.
+	__u8	Unused[3];			// Available for future expansion, must be 0
+						// (Currently must be 0).
 	__u8	MajorVersion;			// Firmware version: xx.
 	__u8	MinorVersion;			//  yy.
 	__le16	BuildNumber;			//  zzzz (LE format)
@@ -359,9 +356,7 @@
 	// The following structure contains __u32s, with each bit
 	// specifying whether the EPiC device supports the given
 	// command or functionality.
-
 	struct edge_compatibility_bits	Supports;
-
 };
 
 // Values for iDownloadFile
@@ -391,8 +386,8 @@
 
 // Define the max block size that may be read or written
 // in a read/write RAM/ROM command.
-#define	MAX_SIZE_REQ_ION_READ_MEM	( (__u16) 64 )
-#define	MAX_SIZE_REQ_ION_WRITE_MEM	( (__u16) 64 )
+#define	MAX_SIZE_REQ_ION_READ_MEM	((__u16)64)
+#define	MAX_SIZE_REQ_ION_WRITE_MEM	((__u16)64)
 
 
 //
@@ -545,7 +540,7 @@
 	__u8		MajorVersion;		// C6 Firmware version: xx.
 	__u8		MinorVersion;		// C7			yy.
 	__le16		BuildNumber;		// C8			zzzz (LE format)
-	
+
 	__u16		EnumRootDescTable;	// CA Root of ROM-based descriptor table
 	__u8		NumDescTypes;		// CC Number of supported descriptor types
 
@@ -597,41 +592,36 @@
 #define I2C_DESC_TYPE_ION		0	// Not defined by TI
 
 
-struct ti_i2c_desc
-{
+struct ti_i2c_desc {
 	__u8	Type;			// Type of descriptor
 	__u16	Size;			// Size of data only not including header
 	__u8	CheckSum;		// Checksum (8 bit sum of data only)
 	__u8	Data[0];		// Data starts here
-}__attribute__((packed));
+} __attribute__((packed));
 
 // for 5152 devices only (type 2 record)
 // for 3410 the version is stored in the WATCHPORT_FIRMWARE_VERSION descriptor
-struct ti_i2c_firmware_rec
-{
+struct ti_i2c_firmware_rec {
 	__u8	Ver_Major;		// Firmware Major version number
 	__u8	Ver_Minor;		// Firmware Minor version number
 	__u8	Data[0];		// Download starts here
-}__attribute__((packed));
+} __attribute__((packed));
 
 
-struct watchport_firmware_version
-{
+struct watchport_firmware_version {
 // Added 2 bytes for version number
 	__u8	Version_Major;		//  Download Version (for Watchport)
 	__u8	Version_Minor;
-}__attribute__((packed));
+} __attribute__((packed));
 
 
 // Structure of header of download image in fw_down.h
-struct ti_i2c_image_header
-{
+struct ti_i2c_image_header {
 	__le16	Length;
 	__u8	CheckSum;
-}__attribute__((packed));
+} __attribute__((packed));
 
-struct ti_basic_descriptor
-{
+struct ti_basic_descriptor {
 	__u8	Power;		// Self powered
 				// bit 7: 1 - power switching supported
 				//        0 - power switching not supported
@@ -663,9 +653,9 @@
 #define TI_I2C_SIZE_MASK		0x1f  // 5 bits
 #define TI_GET_I2C_SIZE(x)		((((x) & TI_I2C_SIZE_MASK)+1)*256)
 
-#define TI_MAX_I2C_SIZE			( 16 * 1024 )
+#define TI_MAX_I2C_SIZE			(16 * 1024)
 
-#define TI_MANUF_VERSION_0		0	
+#define TI_MANUF_VERSION_0		0
 
 // IonConig2 flags
 #define TI_CONFIG2_RS232		0x01
@@ -676,8 +666,7 @@
 #define TI_CONFIG2_WATCHPORT		0x10
 
 
-struct edge_ti_manuf_descriptor
-{
+struct edge_ti_manuf_descriptor {
 	__u8 IonConfig;		//  Config byte for ION manufacturing use
 	__u8 IonConfig2;	//  Expansion
 	__u8 Version;		//  Version
@@ -688,7 +677,7 @@
 	__u8 HubConfig2;	//  Used to configure the Hub
 	__u8 TotalPorts;	//  Total Number of Com Ports for the entire device (All UMPs)
 	__u8 Reserved;		//  Reserved
-}__attribute__((packed));
+} __attribute__((packed));
 
 
 #endif		// if !defined(_USBVEND_H)
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 3fea929..28913fa 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -56,7 +56,6 @@
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
-#include "ipaq.h"
 
 #define KP_RETRIES	100
 
@@ -64,7 +63,7 @@
  * Version Information
  */
 
-#define DRIVER_VERSION "v0.5"
+#define DRIVER_VERSION "v1.0"
 #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
 #define DRIVER_DESC "USB PocketPC PDA driver"
 
@@ -76,20 +75,8 @@
 /* Function prototypes for an ipaq */
 static int  ipaq_open(struct tty_struct *tty,
 			struct usb_serial_port *port);
-static void ipaq_close(struct usb_serial_port *port);
 static int  ipaq_calc_num_ports(struct usb_serial *serial);
 static int  ipaq_startup(struct usb_serial *serial);
-static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port,
-			const unsigned char *buf, int count);
-static int ipaq_write_bulk(struct usb_serial_port *port,
-				const unsigned char *buf, int count);
-static void ipaq_write_gather(struct usb_serial_port *port);
-static void ipaq_read_bulk_callback(struct urb *urb);
-static void ipaq_write_bulk_callback(struct urb *urb);
-static int ipaq_write_room(struct tty_struct *tty);
-static int ipaq_chars_in_buffer(struct tty_struct *tty);
-static void ipaq_destroy_lists(struct usb_serial_port *port);
-
 
 static struct usb_device_id ipaq_id_table [] = {
 	/* The first entry is a placeholder for the insmod-specified device */
@@ -558,7 +545,7 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	ipaq_id_table,
-	.no_dynamic_id = 	1,
+	.no_dynamic_id =	1,
 };
 
 
@@ -569,91 +556,24 @@
 		.name =		"ipaq",
 	},
 	.description =		"PocketPC PDA",
-	.usb_driver = 		&ipaq_driver,
+	.usb_driver =		&ipaq_driver,
 	.id_table =		ipaq_id_table,
+	.bulk_in_size =		256,
+	.bulk_out_size =	256,
 	.open =			ipaq_open,
-	.close =		ipaq_close,
 	.attach =		ipaq_startup,
 	.calc_num_ports =	ipaq_calc_num_ports,
-	.write =		ipaq_write,
-	.write_room =		ipaq_write_room,
-	.chars_in_buffer =	ipaq_chars_in_buffer,
-	.read_bulk_callback =	ipaq_read_bulk_callback,
-	.write_bulk_callback =	ipaq_write_bulk_callback,
 };
 
-static spinlock_t	write_list_lock;
-static int		bytes_in;
-static int		bytes_out;
-
 static int ipaq_open(struct tty_struct *tty,
 			struct usb_serial_port *port)
 {
 	struct usb_serial	*serial = port->serial;
-	struct ipaq_private	*priv;
-	struct ipaq_packet	*pkt;
-	int			i, result = 0;
+	int			result = 0;
 	int			retries = connect_retries;
 
 	dbg("%s - port %d", __func__, port->number);
 
-	bytes_in = 0;
-	bytes_out = 0;
-	priv = kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
-	if (priv == NULL) {
-		dev_err(&port->dev, "%s - Out of memory\n", __func__);
-		return -ENOMEM;
-	}
-	usb_set_serial_port_data(port, priv);
-	priv->active = 0;
-	priv->queue_len = 0;
-	priv->free_len = 0;
-	INIT_LIST_HEAD(&priv->queue);
-	INIT_LIST_HEAD(&priv->freelist);
-
-	for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) {
-		pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL);
-		if (pkt == NULL)
-			goto enomem;
-
-		pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL);
-		if (pkt->data == NULL) {
-			kfree(pkt);
-			goto enomem;
-		}
-		pkt->len = 0;
-		pkt->written = 0;
-		INIT_LIST_HEAD(&pkt->list);
-		list_add(&pkt->list, &priv->freelist);
-		priv->free_len += PACKET_SIZE;
-	}
-
-	/*
-	 * Lose the small buffers usbserial provides. Make larger ones.
-	 */
-
-	kfree(port->bulk_in_buffer);
-	kfree(port->bulk_out_buffer);
-	/* make sure the generic serial code knows */
-	port->bulk_out_buffer = NULL;
-
-	port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
-	if (port->bulk_in_buffer == NULL)
-		goto enomem;
-
-	port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
-	if (port->bulk_out_buffer == NULL) {
-		/* the buffer is useless, free it */
-		kfree(port->bulk_in_buffer);
-		port->bulk_in_buffer = NULL;
-		goto enomem;
-	}
-	port->read_urb->transfer_buffer = port->bulk_in_buffer;
-	port->write_urb->transfer_buffer = port->bulk_out_buffer;
-	port->read_urb->transfer_buffer_length = URBDATA_SIZE;
-	port->bulk_out_size = port->write_urb->transfer_buffer_length
-							= URBDATA_SIZE;
-
 	msleep(1000*initial_wait);
 
 	/*
@@ -663,7 +583,6 @@
 	 * through. Since this has a reasonably high failure rate, we retry
 	 * several times.
 	 */
-
 	while (retries--) {
 		result = usb_control_msg(serial->dev,
 				usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
@@ -673,269 +592,15 @@
 
 		msleep(1000);
 	}
-
 	if (!retries && result) {
-		dev_err(&port->dev, "%s - failed doing control urb, error %d\n",			__func__, result);
-		goto error;
+		dev_err(&port->dev, "%s - failed doing control urb, error %d\n",
+							__func__, result);
+		return result;
 	}
 
-	/* Start reading from the device */
-	usb_fill_bulk_urb(port->read_urb, serial->dev,
-		usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-		port->read_urb->transfer_buffer,
-		port->read_urb->transfer_buffer_length,
-		ipaq_read_bulk_callback, port);
-
-	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-	if (result) {
-		dev_err(&port->dev,
-			"%s - failed submitting read urb, error %d\n",
-			__func__, result);
-		goto error;
-	}
-
-	return 0;
-
-enomem:
-	result = -ENOMEM;
-	dev_err(&port->dev, "%s - Out of memory\n", __func__);
-error:
-	ipaq_destroy_lists(port);
-	kfree(priv);
-	return result;
+	return usb_serial_generic_open(tty, port);
 }
 
-
-static void ipaq_close(struct usb_serial_port *port)
-{
-	struct ipaq_private	*priv = usb_get_serial_port_data(port);
-
-	dbg("%s - port %d", __func__, port->number);
-
-	/*
-	 * shut down bulk read and write
-	 */
-	usb_kill_urb(port->write_urb);
-	usb_kill_urb(port->read_urb);
-	ipaq_destroy_lists(port);
-	kfree(priv);
-	usb_set_serial_port_data(port, NULL);
-
-	/* Uncomment the following line if you want to see some statistics
-	 * in your syslog */
-	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
-}
-
-static void ipaq_read_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port	*port = urb->context;
-	struct tty_struct	*tty;
-	unsigned char		*data = urb->transfer_buffer;
-	int			result;
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (status) {
-		dbg("%s - nonzero read bulk status received: %d",
-		    __func__, status);
-		return;
-	}
-
-	usb_serial_debug_data(debug, &port->dev, __func__,
-						urb->actual_length, data);
-
-	tty = tty_port_tty_get(&port->port);
-	if (tty && urb->actual_length) {
-		tty_insert_flip_string(tty, data, urb->actual_length);
-		tty_flip_buffer_push(tty);
-		bytes_in += urb->actual_length;
-	}
-	tty_kref_put(tty);
-
-	/* Continue trying to always read  */
-	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
-	    usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress),
-	    port->read_urb->transfer_buffer,
-	    port->read_urb->transfer_buffer_length,
-	    ipaq_read_bulk_callback, port);
-	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-	if (result)
-		dev_err(&port->dev,
-			"%s - failed resubmitting read urb, error %d\n",
-			__func__, result);
-	return;
-}
-
-static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port,
-			const unsigned char *buf, int count)
-{
-	const unsigned char	*current_position = buf;
-	int			bytes_sent = 0;
-	int			transfer_size;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	while (count > 0) {
-		transfer_size = min(count, PACKET_SIZE);
-		if (ipaq_write_bulk(port, current_position, transfer_size))
-			break;
-		current_position += transfer_size;
-		bytes_sent += transfer_size;
-		count -= transfer_size;
-		bytes_out += transfer_size;
-	}
-
-	return bytes_sent;
-}
-
-static int ipaq_write_bulk(struct usb_serial_port *port,
-					const unsigned char *buf, int count)
-{
-	struct ipaq_private	*priv = usb_get_serial_port_data(port);
-	struct ipaq_packet	*pkt = NULL;
-	int			result = 0;
-	unsigned long		flags;
-
-	if (priv->free_len <= 0) {
-		dbg("%s - we're stuffed", __func__);
-		return -EAGAIN;
-	}
-
-	spin_lock_irqsave(&write_list_lock, flags);
-	if (!list_empty(&priv->freelist)) {
-		pkt = list_entry(priv->freelist.next, struct ipaq_packet, list);
-		list_del(&pkt->list);
-		priv->free_len -= PACKET_SIZE;
-	}
-	spin_unlock_irqrestore(&write_list_lock, flags);
-	if (pkt == NULL) {
-		dbg("%s - we're stuffed", __func__);
-		return -EAGAIN;
-	}
-
-	memcpy(pkt->data, buf, count);
-	usb_serial_debug_data(debug, &port->dev, __func__, count, pkt->data);
-
-	pkt->len = count;
-	pkt->written = 0;
-	spin_lock_irqsave(&write_list_lock, flags);
-	list_add_tail(&pkt->list, &priv->queue);
-	priv->queue_len += count;
-	if (priv->active == 0) {
-		priv->active = 1;
-		ipaq_write_gather(port);
-		spin_unlock_irqrestore(&write_list_lock, flags);
-		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-		if (result)
-			dev_err(&port->dev,
-				"%s - failed submitting write urb, error %d\n",
-				__func__, result);
-	} else {
-		spin_unlock_irqrestore(&write_list_lock, flags);
-	}
-	return result;
-}
-
-static void ipaq_write_gather(struct usb_serial_port *port)
-{
-	struct ipaq_private	*priv = usb_get_serial_port_data(port);
-	struct usb_serial	*serial = port->serial;
-	int			count, room;
-	struct ipaq_packet	*pkt, *tmp;
-	struct urb		*urb = port->write_urb;
-
-	room = URBDATA_SIZE;
-	list_for_each_entry_safe(pkt, tmp, &priv->queue, list) {
-		count = min(room, (int)(pkt->len - pkt->written));
-		memcpy(urb->transfer_buffer + (URBDATA_SIZE - room),
-		       pkt->data + pkt->written, count);
-		room -= count;
-		pkt->written += count;
-		priv->queue_len -= count;
-		if (pkt->written == pkt->len) {
-			list_move(&pkt->list, &priv->freelist);
-			priv->free_len += PACKET_SIZE;
-		}
-		if (room == 0)
-			break;
-	}
-
-	count = URBDATA_SIZE - room;
-	usb_fill_bulk_urb(port->write_urb, serial->dev,
-		usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
-		port->write_urb->transfer_buffer, count,
-		ipaq_write_bulk_callback, port);
-	return;
-}
-
-static void ipaq_write_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port	*port = urb->context;
-	struct ipaq_private	*priv = usb_get_serial_port_data(port);
-	unsigned long		flags;
-	int			result;
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (status) {
-		dbg("%s - nonzero write bulk status received: %d",
-		    __func__, status);
-		return;
-	}
-
-	spin_lock_irqsave(&write_list_lock, flags);
-	if (!list_empty(&priv->queue)) {
-		ipaq_write_gather(port);
-		spin_unlock_irqrestore(&write_list_lock, flags);
-		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-		if (result)
-			dev_err(&port->dev,
-				"%s - failed submitting write urb, error %d\n",
-				__func__, result);
-	} else {
-		priv->active = 0;
-		spin_unlock_irqrestore(&write_list_lock, flags);
-	}
-
-	usb_serial_port_softint(port);
-}
-
-static int ipaq_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct ipaq_private	*priv = usb_get_serial_port_data(port);
-
-	dbg("%s - freelen %d", __func__, priv->free_len);
-	return priv->free_len;
-}
-
-static int ipaq_chars_in_buffer(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct ipaq_private	*priv = usb_get_serial_port_data(port);
-
-	dbg("%s - queuelen %d", __func__, priv->queue_len);
-	return priv->queue_len;
-}
-
-static void ipaq_destroy_lists(struct usb_serial_port *port)
-{
-	struct ipaq_private	*priv = usb_get_serial_port_data(port);
-	struct ipaq_packet	*pkt, *tmp;
-
-	list_for_each_entry_safe(pkt, tmp, &priv->queue, list) {
-		kfree(pkt->data);
-		kfree(pkt);
-	}
-	list_for_each_entry_safe(pkt, tmp, &priv->freelist, list) {
-		kfree(pkt->data);
-		kfree(pkt);
-	}
-}
-
-
 static int ipaq_calc_num_ports(struct usb_serial *serial)
 {
 	/*
@@ -994,7 +659,6 @@
 static int __init ipaq_init(void)
 {
 	int retval;
-	spin_lock_init(&write_list_lock);
 	retval = usb_serial_register(&ipaq_device);
 	if (retval)
 		goto failed_usb_serial_register;
@@ -1015,7 +679,6 @@
 	return retval;
 }
 
-
 static void __exit ipaq_exit(void)
 {
 	usb_deregister(&ipaq_driver);
diff --git a/drivers/usb/serial/ipaq.h b/drivers/usb/serial/ipaq.h
deleted file mode 100644
index 2b90359..0000000
--- a/drivers/usb/serial/ipaq.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * USB Compaq iPAQ driver
- *
- *	Copyright (C) 2001 - 2002
- *	    Ganesh Varadarajan <ganesh@veritas.com>
- *
- *	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.
- *
- */
-
-#ifndef __LINUX_USB_SERIAL_IPAQ_H
-#define __LINUX_USB_SERIAL_IPAQ_H
-
-/*
- * Since we can't queue our bulk write urbs (don't know why - it just
- * doesn't work), we can send down only one write urb at a time. The simplistic
- * approach taken by the generic usbserial driver will work, but it's not good
- * for performance. Therefore, we buffer upto URBDATA_QUEUE_MAX bytes of write
- * requests coming from the line discipline. This is done by chaining them
- * in lists of struct ipaq_packet, each packet holding a maximum of
- * PACKET_SIZE bytes.
- *
- * ipaq_write() can be called from bottom half context; hence we can't
- * allocate memory for packets there. So we initialize a pool of packets at
- * the first open and maintain a freelist.
- *
- * The value of PACKET_SIZE was empirically determined by
- * checking the maximum write sizes sent down by the ppp ldisc.
- * URBDATA_QUEUE_MAX is set to 64K, which is the maximum TCP window size.
- */
-
-struct ipaq_packet {
-	char			*data;
-	size_t			len;
-	size_t			written;
-	struct list_head	list;
-};
-
-struct ipaq_private {
-	int			active;
-	int			queue_len;
-	int			free_len;
-	struct list_head	queue;
-	struct list_head	freelist;
-};
-
-#define URBDATA_SIZE		4096
-#define URBDATA_QUEUE_MAX	(64 * 1024)
-#define PACKET_SIZE		256
-
-#endif
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index e1d0784..ca77e88 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -34,7 +34,6 @@
  * DCD, DTR, RTS, CTS which are currently faked.
  * It's good enough for PPP at this point. It's based off all kinds of
  * code found in usb/serial and usb/class
- *
  */
 
 #include <linux/kernel.h>
@@ -52,7 +51,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION	"v0.3"
+#define DRIVER_VERSION	"v0.4"
 #define DRIVER_AUTHOR	"Roelf Diedericks"
 #define DRIVER_DESC	"IPWireless tty driver"
 
@@ -65,8 +64,6 @@
 /* Message sizes */
 #define EVENT_BUFFER_SIZE	0xFF
 #define CHAR2INT16(c1, c0)	(((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff))
-#define NUM_BULK_URBS		24
-#define NUM_CONTROL_URBS	16
 
 /* vendor/product pairs that are known work with this driver*/
 #define IPW_VID		0x0bc3
@@ -151,47 +148,6 @@
 
 static int debug;
 
-static void ipw_read_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = urb->context;
-	unsigned char *data = urb->transfer_buffer;
-	struct tty_struct *tty;
-	int result;
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (status) {
-		dbg("%s - nonzero read bulk status received: %d",
-		    __func__, status);
-		return;
-	}
-
-	usb_serial_debug_data(debug, &port->dev, __func__,
-					urb->actual_length, data);
-
-	tty = tty_port_tty_get(&port->port);
-	if (tty && urb->actual_length) {
-		tty_insert_flip_string(tty, data, urb->actual_length);
-		tty_flip_buffer_push(tty);
-	}
-	tty_kref_put(tty);
-
-	/* Continue trying to always read  */
-	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
-			  usb_rcvbulkpipe(port->serial->dev,
-					   port->bulk_in_endpointAddress),
-			  port->read_urb->transfer_buffer,
-			  port->read_urb->transfer_buffer_length,
-			  ipw_read_bulk_callback, port);
-	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-	if (result)
-		dev_err(&port->dev,
-			"%s - failed resubmitting read urb, error %d\n",
-							__func__, result);
-	return;
-}
-
 static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
 	struct usb_device *dev = port->serial->dev;
@@ -229,15 +185,7 @@
 
 	/*--2: Start reading from the device */
 	dbg("%s: setting up bulk read callback", __func__);
-	usb_fill_bulk_urb(port->read_urb, dev,
-			  usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress),
-			  port->bulk_in_buffer,
-			  port->bulk_in_size,
-			  ipw_read_bulk_callback, port);
-	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-	if (result < 0)
-		dbg("%s - usb_submit_urb(read bulk) failed with status %d",
-							__func__, result);
+	usb_serial_generic_open(tty, port);
 
 	/*--3: Tell the modem to open the floodgates on the rx bulk channel */
 	dbg("%s:asking modem for RxRead (RXBULK_ON)", __func__);
@@ -267,35 +215,6 @@
 		dev_err(&port->dev,
 			"initial flowcontrol failed (error = %d)\n", result);
 
-
-	/*--5: raise the dtr */
-	dbg("%s:raising dtr", __func__);
-	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-			 IPW_SIO_SET_PIN,
-			 USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
-			 IPW_PIN_SETDTR,
-			 0,
-			 NULL,
-			 0,
-			 200000);
-	if (result < 0)
-		dev_err(&port->dev,
-				"setting dtr failed (error = %d)\n", result);
-
-	/*--6: raise the rts */
-	dbg("%s:raising rts", __func__);
-	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-			 IPW_SIO_SET_PIN,
-			 USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
-			 IPW_PIN_SETRTS,
-			 0,
-			 NULL,
-			 0,
-			 200000);
-	if (result < 0)
-		dev_err(&port->dev,
-				"setting dtr failed (error = %d)\n", result);
-
 	kfree(buf_flow_init);
 	return 0;
 }
@@ -305,8 +224,8 @@
 	struct usb_device *dev = port->serial->dev;
 	int result;
 
-	/*--1: drop the dtr */
-	dbg("%s:dropping dtr", __func__);
+	dbg("%s: on = %d", __func__, on);
+
 	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 			 IPW_SIO_SET_PIN,
 			 USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
@@ -316,22 +235,20 @@
 			 0,
 			 200000);
 	if (result < 0)
-		dev_err(&port->dev, "dropping dtr failed (error = %d)\n",
+		dev_err(&port->dev, "setting dtr failed (error = %d)\n",
 								result);
 
-	/*--2: drop the rts */
-	dbg("%s:dropping rts", __func__);
 	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 			 IPW_SIO_SET_PIN, USB_TYPE_VENDOR |
-			 		USB_RECIP_INTERFACE | USB_DIR_OUT,
+					USB_RECIP_INTERFACE | USB_DIR_OUT,
 			 on ? IPW_PIN_SETRTS : IPW_PIN_CLRRTS,
 			 0,
 			 NULL,
 			 0,
 			 200000);
 	if (result < 0)
-		dev_err(&port->dev,
-				"dropping rts failed (error = %d)\n", result);
+		dev_err(&port->dev, "setting rts failed (error = %d)\n",
+								result);
 }
 
 static void ipw_close(struct usb_serial_port *port)
@@ -368,83 +285,7 @@
 		dev_err(&port->dev,
 			"Disabling bulk RxRead failed (error = %d)\n", result);
 
-	/* shutdown any in-flight urbs that we know about */
-	usb_kill_urb(port->read_urb);
-	usb_kill_urb(port->write_urb);
-}
-
-static void ipw_write_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = urb->context;
-	int status = urb->status;
-
-	dbg("%s", __func__);
-
-	port->write_urb_busy = 0;
-
-	if (status)
-		dbg("%s - nonzero write bulk status received: %d",
-		    __func__, status);
-
-	usb_serial_port_softint(port);
-}
-
-static int ipw_write(struct tty_struct *tty, struct usb_serial_port *port,
-					const unsigned char *buf, int count)
-{
-	struct usb_device *dev = port->serial->dev;
-	int ret;
-
-	dbg("%s: TOP: count=%d, in_interrupt=%ld", __func__,
-		count, in_interrupt());
-
-	if (count == 0) {
-		dbg("%s - write request of 0 bytes", __func__);
-		return 0;
-	}
-
-	spin_lock_bh(&port->lock);
-	if (port->write_urb_busy) {
-		spin_unlock_bh(&port->lock);
-		dbg("%s - already writing", __func__);
-		return 0;
-	}
-	port->write_urb_busy = 1;
-	spin_unlock_bh(&port->lock);
-
-	count = min(count, port->bulk_out_size);
-	memcpy(port->bulk_out_buffer, buf, count);
-
-	dbg("%s count now:%d", __func__, count);
-
-	usb_fill_bulk_urb(port->write_urb, dev,
-			  usb_sndbulkpipe(dev, port->bulk_out_endpointAddress),
-			  port->write_urb->transfer_buffer,
-			  count,
-			  ipw_write_bulk_callback,
-			  port);
-
-	ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-	if (ret != 0) {
-		port->write_urb_busy = 0;
-		dbg("%s - usb_submit_urb(write bulk) failed with error = %d",
-								__func__, ret);
-		return ret;
-	}
-
-	dbg("%s returning %d", __func__, count);
-	return count;
-}
-
-static int ipw_probe(struct usb_serial_port *port)
-{
-	return 0;
-}
-
-static int ipw_disconnect(struct usb_serial_port *port)
-{
-	usb_set_serial_port_data(port, NULL);
-	return 0;
+	usb_serial_generic_close(port);
 }
 
 static struct usb_serial_driver ipw_device = {
@@ -453,17 +294,12 @@
 		.name =		"ipw",
 	},
 	.description =		"IPWireless converter",
-	.usb_driver = 		&usb_ipw_driver,
+	.usb_driver =		&usb_ipw_driver,
 	.id_table =		usb_ipw_ids,
 	.num_ports =		1,
 	.open =			ipw_open,
 	.close =		ipw_close,
 	.dtr_rts =		ipw_dtr_rts,
-	.port_probe = 		ipw_probe,
-	.port_remove =		ipw_disconnect,
-	.write =		ipw_write,
-	.write_bulk_callback =	ipw_write_bulk_callback,
-	.read_bulk_callback =	ipw_read_bulk_callback,
 };
 
 
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 4a0f519..ccbce40 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -3,6 +3,7 @@
  *
  *	Copyright (C) 2001-2002	Greg Kroah-Hartman (greg@kroah.com)
  *	Copyright (C) 2002	Gary Brubaker (xavyer@ix.netcom.com)
+ *	Copyright (C) 2010	Johan Hovold (jhovold@gmail.com)
  *
  *	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
@@ -72,8 +73,8 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4"
-#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
+#define DRIVER_VERSION "v0.5"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Johan Hovold <jhovold@gmail.com>"
 #define DRIVER_DESC "USB IR Dongle driver"
 
 static int debug;
@@ -87,11 +88,9 @@
 
 static int  ir_startup (struct usb_serial *serial);
 static int  ir_open(struct tty_struct *tty, struct usb_serial_port *port);
-static void ir_close(struct usb_serial_port *port);
-static int  ir_write(struct tty_struct *tty, struct usb_serial_port *port,
-					const unsigned char *buf, int count);
-static void ir_write_bulk_callback (struct urb *urb);
-static void ir_read_bulk_callback (struct urb *urb);
+static int ir_prepare_write_buffer(struct usb_serial_port *port,
+						void *dest, size_t size);
+static void ir_process_read_urb(struct urb *urb);
 static void ir_set_termios(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ktermios *old_termios);
 
@@ -130,10 +129,8 @@
 	.set_termios		= ir_set_termios,
 	.attach			= ir_startup,
 	.open			= ir_open,
-	.close			= ir_close,
-	.write			= ir_write,
-	.write_bulk_callback	= ir_write_bulk_callback,
-	.read_bulk_callback	= ir_read_bulk_callback,
+	.prepare_write_buffer	= ir_prepare_write_buffer,
+	.process_read_urb	= ir_process_read_urb,
 };
 
 static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc)
@@ -198,7 +195,6 @@
 	return NULL;
 }
 
-
 static u8 ir_xbof_change(u8 xbof)
 {
 	u8 result;
@@ -237,7 +233,6 @@
 	return(result);
 }
 
-
 static int ir_startup(struct usb_serial *serial)
 {
 	struct usb_irda_cs_descriptor *irda_desc;
@@ -297,83 +292,22 @@
 
 static int ir_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
-	char *buffer;
-	int result = 0;
+	int i;
 
 	dbg("%s - port %d", __func__, port->number);
 
-	if (buffer_size) {
-		/* override the default buffer sizes */
-		buffer = kmalloc(buffer_size, GFP_KERNEL);
-		if (!buffer) {
-			dev_err(&port->dev, "%s - out of memory.\n", __func__);
-			return -ENOMEM;
-		}
-		kfree(port->read_urb->transfer_buffer);
-		port->read_urb->transfer_buffer = buffer;
-		port->read_urb->transfer_buffer_length = buffer_size;
-
-		buffer = kmalloc(buffer_size, GFP_KERNEL);
-		if (!buffer) {
-			dev_err(&port->dev, "%s - out of memory.\n", __func__);
-			return -ENOMEM;
-		}
-		kfree(port->write_urb->transfer_buffer);
-		port->write_urb->transfer_buffer = buffer;
-		port->write_urb->transfer_buffer_length = buffer_size;
-		port->bulk_out_size = buffer_size;
-	}
+	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+		port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET;
 
 	/* Start reading from the device */
-	usb_fill_bulk_urb(
-		port->read_urb,
-		port->serial->dev,
-		usb_rcvbulkpipe(port->serial->dev,
-			port->bulk_in_endpointAddress),
-		port->read_urb->transfer_buffer,
-		port->read_urb->transfer_buffer_length,
-		ir_read_bulk_callback,
-		port);
-	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-	if (result)
-		dev_err(&port->dev,
-			"%s - failed submitting read urb, error %d\n",
-			__func__, result);
-
-	return result;
+	return usb_serial_generic_open(tty, port);
 }
 
-static void ir_close(struct usb_serial_port *port)
+static int ir_prepare_write_buffer(struct usb_serial_port *port,
+						void *dest, size_t size)
 {
-	dbg("%s - port %d", __func__, port->number);
-
-	/* shutdown our bulk read */
-	usb_kill_urb(port->read_urb);
-}
-
-static int ir_write(struct tty_struct *tty, struct usb_serial_port *port,
-					const unsigned char *buf, int count)
-{
-	unsigned char *transfer_buffer;
-	int result;
-	int transfer_size;
-
-	dbg("%s - port = %d, count = %d", __func__, port->number, count);
-
-	if (count == 0)
-		return 0;
-
-	spin_lock_bh(&port->lock);
-	if (port->write_urb_busy) {
-		spin_unlock_bh(&port->lock);
-		dbg("%s - already writing", __func__);
-		return 0;
-	}
-	port->write_urb_busy = 1;
-	spin_unlock_bh(&port->lock);
-
-	transfer_buffer = port->write_urb->transfer_buffer;
-	transfer_size = min(count, port->bulk_out_size - 1);
+	unsigned char *buf = dest;
+	int count;
 
 	/*
 	 * The first byte of the packet we send to the device contains an
@@ -382,119 +316,57 @@
 	 *
 	 * See section 5.4.2.2 of the USB IrDA spec.
 	 */
-	*transfer_buffer = ir_xbof | ir_baud;
-	++transfer_buffer;
+	*buf = ir_xbof | ir_baud;
 
-	memcpy(transfer_buffer, buf, transfer_size);
-
-	usb_fill_bulk_urb(
-		port->write_urb,
-		port->serial->dev,
-		usb_sndbulkpipe(port->serial->dev,
-			port->bulk_out_endpointAddress),
-		port->write_urb->transfer_buffer,
-		transfer_size + 1,
-		ir_write_bulk_callback,
-		port);
-
-	port->write_urb->transfer_flags = URB_ZERO_PACKET;
-
-	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-	if (result) {
-		port->write_urb_busy = 0;
-		dev_err(&port->dev,
-			"%s - failed submitting write urb, error %d\n",
-			__func__, result);
-	} else
-		result = transfer_size;
-
-	return result;
+	count = kfifo_out_locked(&port->write_fifo, buf + 1, size - 1,
+								&port->lock);
+	return count + 1;
 }
 
-static void ir_write_bulk_callback(struct urb *urb)
+static void ir_process_read_urb(struct urb *urb)
 {
 	struct usb_serial_port *port = urb->context;
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	port->write_urb_busy = 0;
-	if (status) {
-		dbg("%s - nonzero write bulk status received: %d",
-		    __func__, status);
-		return;
-	}
-
-	usb_serial_debug_data(
-		debug,
-		&port->dev,
-		__func__,
-		urb->actual_length,
-		urb->transfer_buffer);
-
-	usb_serial_port_softint(port);
-}
-
-static void ir_read_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = urb->context;
-	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
-	int result;
+	struct tty_struct *tty;
+
+	if (!urb->actual_length)
+		return;
+	/*
+	 * The first byte of the packet we get from the device
+	 * contains a busy indicator and baud rate change.
+	 * See section 5.4.1.2 of the USB IrDA spec.
+	 */
+	if (*data & 0x0f)
+		ir_baud = *data & 0x0f;
+
+	if (urb->actual_length == 1)
+		return;
+
+	tty = tty_port_tty_get(&port->port);
+	if (!tty)
+		return;
+	tty_insert_flip_string(tty, data + 1, urb->actual_length - 1);
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+}
+
+static void ir_set_termios_callback(struct urb *urb)
+{
+	struct usb_serial_port *port = urb->context;
 	int status = urb->status;
 
 	dbg("%s - port %d", __func__, port->number);
 
-	switch (status) {
-	case 0: /* Successful */
-		/*
-		 * The first byte of the packet we get from the device
-		 * contains a busy indicator and baud rate change.
-		 * See section 5.4.1.2 of the USB IrDA spec.
-		 */
-		if ((*data & 0x0f) > 0)
-			ir_baud = *data & 0x0f;
-		usb_serial_debug_data(debug, &port->dev, __func__,
-						urb->actual_length, data);
-		tty = tty_port_tty_get(&port->port);
-		tty_insert_flip_string(tty, data+1, urb->actual_length - 1);
-		tty_flip_buffer_push(tty);
-		tty_kref_put(tty);
+	kfree(urb->transfer_buffer);
 
-		/*
-		 * No break here.
-		 * We want to resubmit the urb so we can read
-		 * again.
-		 */
-
-	case -EPROTO: /* taking inspiration from pl2303.c */
-			/* Continue trying to always read */
-		usb_fill_bulk_urb(
-			port->read_urb,
-			port->serial->dev, 
-			usb_rcvbulkpipe(port->serial->dev,
-				port->bulk_in_endpointAddress),
-			port->read_urb->transfer_buffer,
-			port->read_urb->transfer_buffer_length,
-			ir_read_bulk_callback,
-			port);
-
-		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-		if (result)
-			dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
-				__func__, result);
-			break ;
-	default:
-		dbg("%s - nonzero read bulk status received: %d",
-			__func__, status);
-		break ;
-	}
-	return;
+	if (status)
+		dbg("%s - non-zero urb status: %d", __func__, status);
 }
 
 static void ir_set_termios(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ktermios *old_termios)
 {
+	struct urb *urb;
 	unsigned char *transfer_buffer;
 	int result;
 	speed_t baud;
@@ -548,41 +420,63 @@
 	else
 		ir_xbof = ir_xbof_change(xbof) ;
 
-	/* FIXME need to check to see if our write urb is busy right
-	 * now, or use a urb pool.
-	 *
-	 * send the baud change out on an "empty" data packet
-	 */
-	transfer_buffer = port->write_urb->transfer_buffer;
-	*transfer_buffer = ir_xbof | ir_baud;
-
-	usb_fill_bulk_urb(
-		port->write_urb,
-		port->serial->dev,
-		usb_sndbulkpipe(port->serial->dev,
-			port->bulk_out_endpointAddress),
-		port->write_urb->transfer_buffer,
-		1,
-		ir_write_bulk_callback,
-		port);
-
-	port->write_urb->transfer_flags = URB_ZERO_PACKET;
-
-	result = usb_submit_urb(port->write_urb, GFP_KERNEL);
-	if (result)
-		dev_err(&port->dev,
-				"%s - failed submitting write urb, error %d\n",
-				__func__, result);
-
 	/* Only speed changes are supported */
 	tty_termios_copy_hw(tty->termios, old_termios);
 	tty_encode_baud_rate(tty, baud, baud);
+
+	/*
+	 * send the baud change out on an "empty" data packet
+	 */
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb) {
+		dev_err(&port->dev, "%s - no more urbs\n", __func__);
+		return;
+	}
+	transfer_buffer = kmalloc(1, GFP_KERNEL);
+	if (!transfer_buffer) {
+		dev_err(&port->dev, "%s - out of memory\n", __func__);
+		goto err_buf;
+	}
+
+	*transfer_buffer = ir_xbof | ir_baud;
+
+	usb_fill_bulk_urb(
+		urb,
+		port->serial->dev,
+		usb_sndbulkpipe(port->serial->dev,
+			port->bulk_out_endpointAddress),
+		transfer_buffer,
+		1,
+		ir_set_termios_callback,
+		port);
+
+	urb->transfer_flags = URB_ZERO_PACKET;
+
+	result = usb_submit_urb(urb, GFP_KERNEL);
+	if (result) {
+		dev_err(&port->dev, "%s - failed to submit urb: %d\n",
+							__func__, result);
+		goto err_subm;
+	}
+
+	usb_free_urb(urb);
+
+	return;
+err_subm:
+	kfree(transfer_buffer);
+err_buf:
+	usb_free_urb(urb);
 }
 
 static int __init ir_init(void)
 {
 	int retval;
 
+	if (buffer_size) {
+		ir_device.bulk_in_size = buffer_size;
+		ir_device.bulk_out_size = buffer_size;
+	}
+
 	retval = usb_serial_register(&ir_device);
 	if (retval)
 		goto failed_usb_serial_register;
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 43f13cf..74551cb 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -1044,34 +1044,6 @@
 	if (buf == NULL)
 		return -ENOMEM;
 
-	/* fixup the endpoint buffer size */
-	kfree(port->bulk_out_buffer);
-	port->bulk_out_buffer = kmalloc(512, GFP_KERNEL);
-	port->bulk_out_size = 512;
-	kfree(port->bulk_in_buffer);
-	port->bulk_in_buffer = kmalloc(512, GFP_KERNEL);
-	port->bulk_in_size = 512;
-
-	if (!port->bulk_out_buffer || !port->bulk_in_buffer) {
-		kfree(port->bulk_out_buffer);
-		kfree(port->bulk_in_buffer);
-		kfree(buf);
-		return -ENOMEM;
-	}
-
-	usb_fill_bulk_urb(port->write_urb, port->serial->dev,
-			  usb_sndbulkpipe(port->serial->dev,
-					  port->bulk_out_endpointAddress),
-			  port->bulk_out_buffer, 512,
-			  NULL, NULL);
-
-
-	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
-			  usb_rcvbulkpipe(port->serial->dev,
-					  port->bulk_in_endpointAddress),
-			  port->bulk_in_buffer, 512,
-			  NULL, NULL);
-
 	priv->poll = 0;
 
 	/* initialize writebuf */
@@ -1277,6 +1249,8 @@
 		   },
 	.id_table = id_table,
 	.num_ports = 1,
+	.bulk_in_size = 512,
+	.bulk_out_size = 512,
 	.port_probe = iuu_create_sysfs_attrs,
 	.port_remove = iuu_remove_sysfs_attrs,
 	.open = iuu_open,
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 8eef91b..cdbe8bf 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -1,6 +1,7 @@
 /*
  * KLSI KL5KUSB105 chip RS232 converter driver
  *
+ *   Copyright (C) 2010 Johan Hovold <jhovold@gmail.com>
  *   Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de>
  *
  *   This program is free software; you can redistribute it and/or modify
@@ -34,17 +35,6 @@
  *	implement handshaking or decide that we do not support it
  */
 
-/* History:
- *   0.3a - implemented pools of write URBs
- *   0.3  - alpha version for public testing
- *   0.2  - TIOCMGET works, so autopilot(1) can be used!
- *   0.1  - can be used to do pilot-xfer -p /dev/ttyUSB0 -l
- *
- *   The driver skeleton is mainly based on mct_u232.c and various other
- *   pieces of code shamelessly copied from the drivers/usb/serial/ directory.
- */
-
-
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/init.h>
@@ -64,8 +54,8 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.3a"
-#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>"
+#define DRIVER_VERSION "v0.4"
+#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>, Johan Hovold <jhovold@gmail.com>"
 #define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver"
 
 
@@ -73,23 +63,17 @@
  * Function prototypes
  */
 static int  klsi_105_startup(struct usb_serial *serial);
-static void klsi_105_disconnect(struct usb_serial *serial);
 static void klsi_105_release(struct usb_serial *serial);
 static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port);
 static void klsi_105_close(struct usb_serial_port *port);
-static int  klsi_105_write(struct tty_struct *tty,
-	struct usb_serial_port *port, const unsigned char *buf, int count);
-static void klsi_105_write_bulk_callback(struct urb *urb);
-static int  klsi_105_chars_in_buffer(struct tty_struct *tty);
-static int  klsi_105_write_room(struct tty_struct *tty);
-static void klsi_105_read_bulk_callback(struct urb *urb);
 static void klsi_105_set_termios(struct tty_struct *tty,
 			struct usb_serial_port *port, struct ktermios *old);
-static void klsi_105_throttle(struct tty_struct *tty);
-static void klsi_105_unthrottle(struct tty_struct *tty);
 static int  klsi_105_tiocmget(struct tty_struct *tty, struct file *file);
 static int  klsi_105_tiocmset(struct tty_struct *tty, struct file *file,
 			unsigned int set, unsigned int clear);
+static void klsi_105_process_read_urb(struct urb *urb);
+static int klsi_105_prepare_write_buffer(struct usb_serial_port *port,
+						void *dest, size_t size);
 
 /*
  * All of the device info needed for the KLSI converters.
@@ -107,7 +91,7 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
+	.no_dynamic_id =	1,
 };
 
 static struct usb_serial_driver kl5kusb105d_device = {
@@ -115,26 +99,23 @@
 		.owner =	THIS_MODULE,
 		.name =		"kl5kusb105d",
 	},
-	.description =	     "KL5KUSB105D / PalmConnect",
-	.usb_driver =	     &kl5kusb105d_driver,
-	.id_table =	     id_table,
-	.num_ports =	     1,
-	.open =		     klsi_105_open,
-	.close =	     klsi_105_close,
-	.write =	     klsi_105_write,
-	.write_bulk_callback = klsi_105_write_bulk_callback,
-	.chars_in_buffer =   klsi_105_chars_in_buffer,
-	.write_room =        klsi_105_write_room,
-	.read_bulk_callback = klsi_105_read_bulk_callback,
-	.set_termios =	     klsi_105_set_termios,
-	/*.break_ctl =	     klsi_105_break_ctl,*/
-	.tiocmget =          klsi_105_tiocmget,
-	.tiocmset =          klsi_105_tiocmset,
-	.attach =	     klsi_105_startup,
-	.disconnect =	     klsi_105_disconnect,
-	.release =	     klsi_105_release,
-	.throttle =	     klsi_105_throttle,
-	.unthrottle =	     klsi_105_unthrottle,
+	.description =		"KL5KUSB105D / PalmConnect",
+	.usb_driver =		&kl5kusb105d_driver,
+	.id_table =		id_table,
+	.num_ports =		1,
+	.bulk_out_size =	64,
+	.open =			klsi_105_open,
+	.close =		klsi_105_close,
+	.set_termios =		klsi_105_set_termios,
+	/*.break_ctl =		klsi_105_break_ctl,*/
+	.tiocmget =		klsi_105_tiocmget,
+	.tiocmset =		klsi_105_tiocmset,
+	.attach =		klsi_105_startup,
+	.release =		klsi_105_release,
+	.throttle =		usb_serial_generic_throttle,
+	.unthrottle =		usb_serial_generic_unthrottle,
+	.process_read_urb =	klsi_105_process_read_urb,
+	.prepare_write_buffer =	klsi_105_prepare_write_buffer,
 };
 
 struct klsi_105_port_settings {
@@ -145,18 +126,11 @@
 	__u8	unknown2;
 } __attribute__ ((packed));
 
-/* we implement a pool of NUM_URBS urbs per usb_serial */
-#define NUM_URBS			1
-#define URB_TRANSFER_BUFFER_SIZE	64
 struct klsi_105_private {
 	struct klsi_105_port_settings	cfg;
 	struct ktermios			termios;
 	unsigned long			line_state; /* modem line settings */
-	/* write pool */
-	struct urb			*write_urb_pool[NUM_URBS];
 	spinlock_t			lock;
-	unsigned long			bytes_in;
-	unsigned long			bytes_out;
 };
 
 
@@ -189,7 +163,7 @@
 		 settings->pktlen, settings->baudrate, settings->databits,
 		 settings->unknown1, settings->unknown2);
 	return rc;
-} /* klsi_105_chg_port_settings */
+}
 
 /* translate a 16-bit status value from the device to linux's TIO bits */
 static unsigned long klsi_105_status2linestate(const __u16 status)
@@ -202,6 +176,7 @@
 
 	return res;
 }
+
 /*
  * Read line control via vendor command and return result through
  * *line_state_p
@@ -258,7 +233,7 @@
 static int klsi_105_startup(struct usb_serial *serial)
 {
 	struct klsi_105_private *priv;
-	int i, j;
+	int i;
 
 	/* check if we support the product id (see keyspan.c)
 	 * FIXME
@@ -282,29 +257,9 @@
 
 		priv->line_state    = 0;
 
-		priv->bytes_in	    = 0;
-		priv->bytes_out	    = 0;
 		usb_set_serial_port_data(serial->port[i], priv);
 
 		spin_lock_init(&priv->lock);
-		for (j = 0; j < NUM_URBS; j++) {
-			struct urb *urb = usb_alloc_urb(0, GFP_KERNEL);
-
-			priv->write_urb_pool[j] = urb;
-			if (urb == NULL) {
-				dev_err(&serial->dev->dev, "No more urbs???\n");
-				goto err_cleanup;
-			}
-
-			urb->transfer_buffer =
-				kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
-			if (!urb->transfer_buffer) {
-				dev_err(&serial->dev->dev,
-					"%s - out of memory for urb buffers.\n",
-					__func__);
-				goto err_cleanup;
-			}
-		}
 
 		/* priv->termios is left uninitalized until port opening */
 		init_waitqueue_head(&serial->port[i]->write_wait);
@@ -315,44 +270,11 @@
 err_cleanup:
 	for (; i >= 0; i--) {
 		priv = usb_get_serial_port_data(serial->port[i]);
-		for (j = 0; j < NUM_URBS; j++) {
-			if (priv->write_urb_pool[j]) {
-				kfree(priv->write_urb_pool[j]->transfer_buffer);
-				usb_free_urb(priv->write_urb_pool[j]);
-			}
-		}
+		kfree(priv);
 		usb_set_serial_port_data(serial->port[i], NULL);
 	}
 	return -ENOMEM;
-} /* klsi_105_startup */
-
-
-static void klsi_105_disconnect(struct usb_serial *serial)
-{
-	int i;
-
-	dbg("%s", __func__);
-
-	/* stop reads and writes on all ports */
-	for (i = 0; i < serial->num_ports; ++i) {
-		struct klsi_105_private *priv =
-				usb_get_serial_port_data(serial->port[i]);
-
-		if (priv) {
-			/* kill our write urb pool */
-			int j;
-			struct urb **write_urbs = priv->write_urb_pool;
-
-			for (j = 0; j < NUM_URBS; j++) {
-				if (write_urbs[j]) {
-					usb_kill_urb(write_urbs[j]);
-					usb_free_urb(write_urbs[j]);
-				}
-			}
-		}
-	}
-} /* klsi_105_disconnect */
-
+}
 
 static void klsi_105_release(struct usb_serial *serial)
 {
@@ -360,13 +282,9 @@
 
 	dbg("%s", __func__);
 
-	for (i = 0; i < serial->num_ports; ++i) {
-		struct klsi_105_private *priv =
-				usb_get_serial_port_data(serial->port[i]);
-
-		kfree(priv);
-	}
-} /* klsi_105_release */
+	for (i = 0; i < serial->num_ports; ++i)
+		kfree(usb_get_serial_port_data(serial->port[i]));
+}
 
 static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
@@ -416,18 +334,8 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* READ_ON and urb submission */
-	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
-		      usb_rcvbulkpipe(port->serial->dev,
-				      port->bulk_in_endpointAddress),
-		      port->read_urb->transfer_buffer,
-		      port->read_urb->transfer_buffer_length,
-		      klsi_105_read_bulk_callback,
-		      port);
-
-	rc = usb_submit_urb(port->read_urb, GFP_KERNEL);
+	rc = usb_serial_generic_open(tty, port);
 	if (rc) {
-		dev_err(&port->dev, "%s - failed submitting read urb, "
-			"error %d\n", __func__, rc);
 		retval = rc;
 		goto exit;
 	}
@@ -460,12 +368,10 @@
 exit:
 	kfree(cfg);
 	return retval;
-} /* klsi_105_open */
-
+}
 
 static void klsi_105_close(struct usb_serial_port *port)
 {
-	struct klsi_105_private *priv = usb_get_serial_port_data(port);
 	int rc;
 
 	dbg("%s port %d", __func__, port->number);
@@ -488,239 +394,62 @@
 	mutex_unlock(&port->serial->disc_mutex);
 
 	/* shutdown our bulk reads and writes */
-	usb_kill_urb(port->write_urb);
-	usb_kill_urb(port->read_urb);
-	/* unlink our write pool */
-	/* FIXME */
+	usb_serial_generic_close(port);
+
 	/* wgg - do I need this? I think so. */
 	usb_kill_urb(port->interrupt_in_urb);
-	dev_info(&port->serial->dev->dev,
-		 "port stats: %ld bytes in, %ld bytes out\n",
-		 priv->bytes_in, priv->bytes_out);
-} /* klsi_105_close */
-
+}
 
 /* We need to write a complete 64-byte data block and encode the
  * number actually sent in the first double-byte, LSB-order. That
  * leaves at most 62 bytes of payload.
  */
-#define KLSI_105_DATA_OFFSET	2   /* in the bulk urb data block */
-
-
-static int klsi_105_write(struct tty_struct *tty,
-	struct usb_serial_port *port, const unsigned char *buf, int count)
+#define KLSI_HDR_LEN		2
+static int klsi_105_prepare_write_buffer(struct usb_serial_port *port,
+						void *dest, size_t size)
 {
-	struct klsi_105_private *priv = usb_get_serial_port_data(port);
-	int result, size;
-	int bytes_sent = 0;
+	unsigned char *buf = dest;
+	int count;
 
-	dbg("%s - port %d", __func__, port->number);
+	count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size,
+								&port->lock);
+	put_unaligned_le16(count, buf);
 
-	while (count > 0) {
-		/* try to find a free urb (write 0 bytes if none) */
-		struct urb *urb = NULL;
-		unsigned long flags;
-		int i;
-		/* since the pool is per-port we might not need
-		   the spin lock !? */
-		spin_lock_irqsave(&priv->lock, flags);
-		for (i = 0; i < NUM_URBS; i++) {
-			if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
-				urb = priv->write_urb_pool[i];
-				dbg("%s - using pool URB %d", __func__, i);
-				break;
-			}
-		}
-		spin_unlock_irqrestore(&priv->lock, flags);
-
-		if (urb == NULL) {
-			dbg("%s - no more free urbs", __func__);
-			goto exit;
-		}
-
-		if (urb->transfer_buffer == NULL) {
-			urb->transfer_buffer =
-				kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC);
-			if (urb->transfer_buffer == NULL) {
-				dev_err(&port->dev,
-					"%s - no more kernel memory...\n",
-					__func__);
-				goto exit;
-			}
-		}
-
-		size = min(count, port->bulk_out_size - KLSI_105_DATA_OFFSET);
-		size = min(size, URB_TRANSFER_BUFFER_SIZE -
-							KLSI_105_DATA_OFFSET);
-
-		memcpy(urb->transfer_buffer + KLSI_105_DATA_OFFSET, buf, size);
-
-		/* write payload size into transfer buffer */
-		((__u8 *)urb->transfer_buffer)[0] = (__u8) (size & 0xFF);
-		((__u8 *)urb->transfer_buffer)[1] = (__u8) ((size & 0xFF00)>>8);
-
-		/* set up our urb */
-		usb_fill_bulk_urb(urb, port->serial->dev,
-			      usb_sndbulkpipe(port->serial->dev,
-					      port->bulk_out_endpointAddress),
-			      urb->transfer_buffer,
-			      URB_TRANSFER_BUFFER_SIZE,
-			      klsi_105_write_bulk_callback,
-			      port);
-
-		/* send the data out the bulk port */
-		result = usb_submit_urb(urb, GFP_ATOMIC);
-		if (result) {
-			dev_err(&port->dev,
-				"%s - failed submitting write urb, error %d\n",
-				__func__, result);
-			goto exit;
-		}
-		buf += size;
-		bytes_sent += size;
-		count -= size;
-	}
-exit:
-	/* lockless, but it's for debug info only... */
-	priv->bytes_out += bytes_sent;
-
-	return bytes_sent;	/* that's how much we wrote */
-} /* klsi_105_write */
-
-static void klsi_105_write_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = urb->context;
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (status) {
-		dbg("%s - nonzero write bulk status received: %d", __func__,
-		    status);
-		return;
-	}
-
-	usb_serial_port_softint(port);
-} /* klsi_105_write_bulk_completion_callback */
-
-
-/* return number of characters currently in the writing process */
-static int klsi_105_chars_in_buffer(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	int chars = 0;
-	int i;
-	unsigned long flags;
-	struct klsi_105_private *priv = usb_get_serial_port_data(port);
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	for (i = 0; i < NUM_URBS; ++i) {
-		if (priv->write_urb_pool[i]->status == -EINPROGRESS)
-			chars += URB_TRANSFER_BUFFER_SIZE;
-	}
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	dbg("%s - returns %d", __func__, chars);
-	return chars;
+	return count + KLSI_HDR_LEN;
 }
 
-static int klsi_105_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	unsigned long flags;
-	int i;
-	int room = 0;
-	struct klsi_105_private *priv = usb_get_serial_port_data(port);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	for (i = 0; i < NUM_URBS; ++i) {
-		if (priv->write_urb_pool[i]->status != -EINPROGRESS)
-			room += URB_TRANSFER_BUFFER_SIZE;
-	}
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	dbg("%s - returns %d", __func__, room);
-	return room;
-}
-
-
-
-static void klsi_105_read_bulk_callback(struct urb *urb)
+/* The data received is preceded by a length double-byte in LSB-first order.
+ */
+static void klsi_105_process_read_urb(struct urb *urb)
 {
 	struct usb_serial_port *port = urb->context;
-	struct klsi_105_private *priv = usb_get_serial_port_data(port);
-	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
-	int rc;
-	int status = urb->status;
+	struct tty_struct *tty;
+	unsigned len;
 
-	dbg("%s - port %d", __func__, port->number);
+	/* empty urbs seem to happen, we ignore them */
+	if (!urb->actual_length)
+		return;
 
-	/* The urb might have been killed. */
-	if (status) {
-		dbg("%s - nonzero read bulk status received: %d", __func__,
-		    status);
+	if (urb->actual_length <= KLSI_HDR_LEN) {
+		dbg("%s - malformed packet", __func__);
 		return;
 	}
 
-	/* The data received is again preceded by a length double-byte in LSB-
-	 * first order (see klsi_105_write() )
-	 */
-	if (urb->actual_length == 0) {
-		/* empty urbs seem to happen, we ignore them */
-		/* dbg("%s - emtpy URB", __func__); */
-	       ;
-	} else if (urb->actual_length <= 2) {
-		dbg("%s - size %d URB not understood", __func__,
-		    urb->actual_length);
-		usb_serial_debug_data(debug, &port->dev, __func__,
-				      urb->actual_length, data);
-	} else {
-		int bytes_sent = ((__u8 *) data)[0] +
-				 ((unsigned int) ((__u8 *) data)[1] << 8);
-		tty = tty_port_tty_get(&port->port);
-		/* we should immediately resubmit the URB, before attempting
-		 * to pass the data on to the tty layer. But that needs locking
-		 * against re-entry an then mixed-up data because of
-		 * intermixed tty_flip_buffer_push()s
-		 * FIXME
-		 */
-		usb_serial_debug_data(debug, &port->dev, __func__,
-				      urb->actual_length, data);
+	tty = tty_port_tty_get(&port->port);
+	if (!tty)
+		return;
 
-		if (bytes_sent + 2 > urb->actual_length) {
-			dbg("%s - trying to read more data than available"
-			    " (%d vs. %d)", __func__,
-			    bytes_sent+2, urb->actual_length);
-			/* cap at implied limit */
-			bytes_sent = urb->actual_length - 2;
-		}
-
-		tty_insert_flip_string(tty, data + 2, bytes_sent);
-		tty_flip_buffer_push(tty);
-		tty_kref_put(tty);
-
-		/* again lockless, but debug info only */
-		priv->bytes_in += bytes_sent;
+	len = get_unaligned_le16(data);
+	if (len > urb->actual_length - KLSI_HDR_LEN) {
+		dbg("%s - packet length mismatch", __func__);
+		len = urb->actual_length - KLSI_HDR_LEN;
 	}
-	/* Continue trying to always read  */
-	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
-		      usb_rcvbulkpipe(port->serial->dev,
-				      port->bulk_in_endpointAddress),
-		      port->read_urb->transfer_buffer,
-		      port->read_urb->transfer_buffer_length,
-		      klsi_105_read_bulk_callback,
-		      port);
-	rc = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-	if (rc)
-		dev_err(&port->dev,
-			"%s - failed resubmitting read urb, error %d\n",
-			__func__, rc);
-} /* klsi_105_read_bulk_callback */
 
+	tty_insert_flip_string(tty, data + KLSI_HDR_LEN, len);
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+}
 
 static void klsi_105_set_termios(struct tty_struct *tty,
 				 struct usb_serial_port *port,
@@ -887,8 +616,7 @@
 	klsi_105_chg_port_settings(port, cfg);
 err:
 	kfree(cfg);
-} /* klsi_105_set_termios */
-
+}
 
 #if 0
 static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
@@ -906,7 +634,7 @@
 		lcr |= MCT_U232_SET_BREAK;
 
 	mct_u232_set_line_ctrl(serial, lcr);
-} /* mct_u232_break_ctl */
+}
 #endif
 
 static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file)
@@ -962,29 +690,6 @@
 	return retval;
 }
 
-static void klsi_105_throttle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	dbg("%s - port %d", __func__, port->number);
-	usb_kill_urb(port->read_urb);
-}
-
-static void klsi_105_unthrottle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	int result;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	port->read_urb->dev = port->serial->dev;
-	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-	if (result)
-		dev_err(&port->dev,
-			"%s - failed submitting read urb, error %d\n",
-			__func__, result);
-}
-
-
 
 static int __init klsi_105_init(void)
 {
@@ -1005,7 +710,6 @@
 	return retval;
 }
 
-
 static void __exit klsi_105_exit(void)
 {
 	usb_deregister(&kl5kusb105d_driver);
@@ -1023,5 +727,3 @@
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "enable extensive debugging messages");
-
-/* vim: set sts=8 ts=8 sw=8: */
diff --git a/drivers/usb/serial/kl5kusb105.h b/drivers/usb/serial/kl5kusb105.h
index 1231d9e..22a90ba 100644
--- a/drivers/usb/serial/kl5kusb105.h
+++ b/drivers/usb/serial/kl5kusb105.h
@@ -17,16 +17,16 @@
 /* baud rates */
 
 enum {
-  kl5kusb105a_sio_b115200 = 0,
-  kl5kusb105a_sio_b57600  = 1,
-  kl5kusb105a_sio_b38400  = 2,
-  kl5kusb105a_sio_b19200  = 4,
-  kl5kusb105a_sio_b14400  = 5,
-  kl5kusb105a_sio_b9600   = 6,
-  kl5kusb105a_sio_b4800   = 8,   /* unchecked */
-  kl5kusb105a_sio_b2400   = 9,   /* unchecked */
-  kl5kusb105a_sio_b1200   = 0xa,  /* unchecked */
-  kl5kusb105a_sio_b600    = 0xb   /* unchecked */
+	kl5kusb105a_sio_b115200 = 0,
+	kl5kusb105a_sio_b57600  = 1,
+	kl5kusb105a_sio_b38400  = 2,
+	kl5kusb105a_sio_b19200  = 4,
+	kl5kusb105a_sio_b14400  = 5,
+	kl5kusb105a_sio_b9600   = 6,
+	kl5kusb105a_sio_b4800   = 8,	/* unchecked */
+	kl5kusb105a_sio_b2400   = 9,	/* unchecked */
+	kl5kusb105a_sio_b1200   = 0xa,	/* unchecked */
+	kl5kusb105a_sio_b600    = 0xb	/* unchecked */
 };
 
 /* data bits */
@@ -53,17 +53,16 @@
 #define KL5KUSB105A_CTS			((1<<5) | (1<<4))
 
 #define KL5KUSB105A_WANTS_TO_SEND	0x30
-//#define KL5KUSB105A_DTR			/* Data Terminal Ready */
-//#define KL5KUSB105A_CTS			/* Clear To Send */
-//#define KL5KUSB105A_CD			/* Carrier Detect */
-//#define KL5KUSB105A_DSR			/* Data Set Ready */
-//#define KL5KUSB105A_RxD			/* Receive pin */
+#if 0
+#define KL5KUSB105A_DTR			/* Data Terminal Ready */
+#define KL5KUSB105A_CTS			/* Clear To Send */
+#define KL5KUSB105A_CD			/* Carrier Detect */
+#define KL5KUSB105A_DSR			/* Data Set Ready */
+#define KL5KUSB105A_RxD			/* Receive pin */
 
-//#define KL5KUSB105A_LE
-//#define KL5KUSB105A_RTS		
-//#define KL5KUSB105A_ST		
-//#define KL5KUSB105A_SR		
-//#define KL5KUSB105A_RI			/* Ring Indicator */
-
-/* vim: set ts=8 sts=8: */
-
+#define KL5KUSB105A_LE
+#define KL5KUSB105A_RTS
+#define KL5KUSB105A_ST
+#define KL5KUSB105A_SR
+#define KL5KUSB105A_RI			/* Ring Indicator */
+#endif
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index c113a2a..bd5bd85 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -345,7 +345,8 @@
 
 	/* FIXME: Add rts/dtr methods */
 	if (port->write_urb) {
-		usb_kill_urb(port->write_urb);
+		usb_poison_urb(port->write_urb);
+		kfree(port->write_urb->transfer_buffer);
 		usb_free_urb(port->write_urb);
 		port->write_urb = NULL;
 	}
diff --git a/drivers/usb/serial/kobil_sct.h b/drivers/usb/serial/kobil_sct.h
index a51fbb5..be207f7 100644
--- a/drivers/usb/serial/kobil_sct.h
+++ b/drivers/usb/serial/kobil_sct.h
@@ -23,38 +23,55 @@
 #define SUSBCR_SSL_SETDTR			0x0004
 #define SUSBCR_SSL_CLRDTR			0x0010
 
-#define SUSBCR_SSL_PURGE_TXABORT		0x0100  // Kill the pending/current writes to the comm port.
-#define SUSBCR_SSL_PURGE_RXABORT		0x0200  // Kill the pending/current reads to the comm port.
-#define SUSBCR_SSL_PURGE_TXCLEAR		0x0400  // Kill the transmit queue if there.
-#define SUSBCR_SSL_PURGE_RXCLEAR		0x0800  // Kill the typeahead buffer if there.
+/* Kill the pending/current writes to the comm port. */
+#define SUSBCR_SSL_PURGE_TXABORT		0x0100
+/* Kill the pending/current reads to the comm port. */
+#define SUSBCR_SSL_PURGE_RXABORT		0x0200
+/* Kill the transmit queue if there. */
+#define SUSBCR_SSL_PURGE_TXCLEAR		0x0400
+/* Kill the typeahead buffer if there. */
+#define SUSBCR_SSL_PURGE_RXCLEAR		0x0800
 
 #define SUSBCRequest_GetStatusLineState		4
-#define SUSBCR_GSL_RXCHAR			0x0001  // Any Character received
-#define SUSBCR_GSL_TXEMPTY			0x0004  // Transmitt Queue Empty
-#define SUSBCR_GSL_CTS				0x0008  // CTS changed state
-#define SUSBCR_GSL_DSR				0x0010  // DSR changed state
-#define SUSBCR_GSL_RLSD				0x0020  // RLSD changed state
-#define SUSBCR_GSL_BREAK			0x0040  // BREAK received
-#define SUSBCR_GSL_ERR				0x0080  // Line status error occurred
-#define SUSBCR_GSL_RING				0x0100  // Ring signal detected
+/* Any Character received */
+#define SUSBCR_GSL_RXCHAR			0x0001
+/* Transmitt Queue Empty */
+#define SUSBCR_GSL_TXEMPTY			0x0004
+/* CTS changed state */
+#define SUSBCR_GSL_CTS				0x0008
+/* DSR changed state */
+#define SUSBCR_GSL_DSR				0x0010
+/* RLSD changed state */
+#define SUSBCR_GSL_RLSD				0x0020
+/* BREAK received */
+#define SUSBCR_GSL_BREAK			0x0040
+/* Line status error occurred */
+#define SUSBCR_GSL_ERR				0x0080
+/* Ring signal detected */
+#define SUSBCR_GSL_RING				0x0100
 
 #define SUSBCRequest_Misc			8
-#define SUSBCR_MSC_ResetReader			0x0001	// use a predefined reset sequence
-#define SUSBCR_MSC_ResetAllQueues		0x0002	// use a predefined sequence to reset the internal queues
+/* use a predefined reset sequence */
+#define SUSBCR_MSC_ResetReader			0x0001
+/* use a predefined sequence to reset the internal queues */
+#define SUSBCR_MSC_ResetAllQueues		0x0002
 
 #define SUSBCRequest_GetMisc			0x10
-#define SUSBCR_MSC_GetFWVersion			0x0001	/* get the firmware version from device,
-							   coded like this 0xHHLLBBPP
-							   with HH = Firmware Version High Byte
-							   LL = Firmware Version Low Byte
-							   BB = Build Number
-							   PP = Further Attributes
-							*/
 
-#define SUSBCR_MSC_GetHWVersion			0x0002	/* get the hardware version from device
-							   coded like this 0xHHLLPPRR
-							   with HH = Software Version High Byte
-							   LL = Software Version Low Byte
-							   PP = Further Attributes
-							   RR = Reserved for the hardware ID 
-							*/
+/*
+ * get the firmware version from device, coded like this 0xHHLLBBPP with
+ * HH = Firmware Version High Byte
+ * LL = Firmware Version Low Byte
+ * BB = Build Number
+ * PP = Further Attributes
+ */
+#define SUSBCR_MSC_GetFWVersion			0x0001
+
+/*
+ * get the hardware version from device coded like this 0xHHLLPPRR with
+ * HH = Software Version High Byte
+ * LL = Software Version Low Byte
+ * PP = Further Attributes
+ * RR = Reserved for the hardware ID
+ */
+#define SUSBCR_MSC_GetHWVersion			0x0002
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 2849f8c..7aa01b9 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -549,12 +549,9 @@
 {
 	dbg("%s port %d", __func__, port->number);
 
-	if (port->serial->dev) {
-		/* shutdown our urbs */
-		usb_kill_urb(port->write_urb);
-		usb_kill_urb(port->read_urb);
+	usb_serial_generic_close(port);
+	if (port->serial->dev)
 		usb_kill_urb(port->interrupt_in_urb);
-	}
 } /* mct_u232_close */
 
 
diff --git a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h
index 7417d5c..3a3f5e6 100644
--- a/drivers/usb/serial/mct_u232.h
+++ b/drivers/usb/serial/mct_u232.h
@@ -42,36 +42,44 @@
 #define MCT_U232_SET_REQUEST_TYPE	0x40
 #define MCT_U232_GET_REQUEST_TYPE	0xc0
 
-#define MCT_U232_GET_MODEM_STAT_REQUEST 2  /* Get Modem Status Register (MSR) */
-#define MCT_U232_GET_MODEM_STAT_SIZE    1
+/* Get Modem Status Register (MSR) */
+#define MCT_U232_GET_MODEM_STAT_REQUEST	2
+#define MCT_U232_GET_MODEM_STAT_SIZE	1
 
-#define MCT_U232_GET_LINE_CTRL_REQUEST  6  /* Get Line Control Register (LCR) */
-#define MCT_U232_GET_LINE_CTRL_SIZE     1  /* ... not used by this driver */
+/* Get Line Control Register (LCR) */
+/* ... not used by this driver */
+#define MCT_U232_GET_LINE_CTRL_REQUEST	6
+#define MCT_U232_GET_LINE_CTRL_SIZE	1
 
-#define MCT_U232_SET_BAUD_RATE_REQUEST	5  /* Set Baud Rate Divisor */
-#define MCT_U232_SET_BAUD_RATE_SIZE     4
+/* Set Baud Rate Divisor */
+#define MCT_U232_SET_BAUD_RATE_REQUEST	5
+#define MCT_U232_SET_BAUD_RATE_SIZE	4
 
-#define MCT_U232_SET_LINE_CTRL_REQUEST	7  /* Set Line Control Register (LCR) */
-#define MCT_U232_SET_LINE_CTRL_SIZE     1
+/* Set Line Control Register (LCR) */
+#define MCT_U232_SET_LINE_CTRL_REQUEST	7
+#define MCT_U232_SET_LINE_CTRL_SIZE	1
 
-#define MCT_U232_SET_MODEM_CTRL_REQUEST	10 /* Set Modem Control Register (MCR) */
-#define MCT_U232_SET_MODEM_CTRL_SIZE    1
+/* Set Modem Control Register (MCR) */
+#define MCT_U232_SET_MODEM_CTRL_REQUEST	10
+#define MCT_U232_SET_MODEM_CTRL_SIZE	1
 
-/* This USB device request code is not well understood.  It is transmitted by
-   the MCT-supplied Windows driver whenever the baud rate changes. 
-*/
-#define MCT_U232_SET_UNKNOWN1_REQUEST   11  /* Unknown functionality */
-#define MCT_U232_SET_UNKNOWN1_SIZE       1
+/*
+ * This USB device request code is not well understood.  It is transmitted by
+ * the MCT-supplied Windows driver whenever the baud rate changes.
+ */
+#define MCT_U232_SET_UNKNOWN1_REQUEST	11  /* Unknown functionality */
+#define MCT_U232_SET_UNKNOWN1_SIZE	1
 
-/* This USB device request code appears to control whether CTS is required
-   during transmission.
-   
-   Sending a zero byte allows data transmission to a device which is not
-   asserting CTS.  Sending a '1' byte will cause transmission to be deferred
-   until the device asserts CTS.
-*/
-#define MCT_U232_SET_CTS_REQUEST   12
-#define MCT_U232_SET_CTS_SIZE       1
+/*
+ * This USB device request code appears to control whether CTS is required
+ * during transmission.
+ *
+ * Sending a zero byte allows data transmission to a device which is not
+ * asserting CTS.  Sending a '1' byte will cause transmission to be deferred
+ * until the device asserts CTS.
+ */
+#define MCT_U232_SET_CTS_REQUEST	12
+#define MCT_U232_SET_CTS_SIZE		1
 
 #define MCT_U232_MAX_SIZE		4	/* of MCT_XXX_SIZE */
 
@@ -81,7 +89,8 @@
  * and "Intel solution". They are the regular MCT and "Sitecom" for us.
  * This is pointless to document in the header, see the code for the bits.
  */
-static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result);
+static int mct_u232_calculate_baud_rate(struct usb_serial *serial,
+					speed_t value, speed_t *result);
 
 /*
  * Line Control Register (LCR)
@@ -125,16 +134,16 @@
 /*
  * Line Status Register (LSR)
  */
-#define MCT_U232_LSR_INDEX              1       /* data[index] */
-#define MCT_U232_LSR_ERR                0x80    /* OE | PE | FE | BI */
-#define MCT_U232_LSR_TEMT               0x40    /* transmit register empty */
-#define MCT_U232_LSR_THRE               0x20    /* transmit holding register empty */
-#define MCT_U232_LSR_BI                 0x10    /* break indicator */
-#define MCT_U232_LSR_FE                 0x08    /* framing error */
-#define MCT_U232_LSR_OE                 0x02    /* overrun error */
-#define MCT_U232_LSR_PE                 0x04    /* parity error */
-#define MCT_U232_LSR_OE                 0x02    /* overrun error */
-#define MCT_U232_LSR_DR                 0x01    /* receive data ready */
+#define MCT_U232_LSR_INDEX	1	/* data[index] */
+#define MCT_U232_LSR_ERR	0x80	/* OE | PE | FE | BI */
+#define MCT_U232_LSR_TEMT	0x40	/* transmit register empty */
+#define MCT_U232_LSR_THRE	0x20	/* transmit holding register empty */
+#define MCT_U232_LSR_BI		0x10	/* break indicator */
+#define MCT_U232_LSR_FE		0x08	/* framing error */
+#define MCT_U232_LSR_OE		0x02	/* overrun error */
+#define MCT_U232_LSR_PE		0x04	/* parity error */
+#define MCT_U232_LSR_OE		0x02	/* overrun error */
+#define MCT_U232_LSR_DR		0x01	/* receive data ready */
 
 
 /* -----------------------------------------------------------------------------
@@ -143,10 +152,10 @@
  *
  *  The technical details of the device have been acquired be using "SniffUSB"
  *  and the vendor-supplied device driver (version 2.3A) under Windows98. To
- *  identify the USB vendor-specific requests and to assign them to terminal 
+ *  identify the USB vendor-specific requests and to assign them to terminal
  *  settings (flow control, baud rate, etc.) the program "SerialSettings" from
  *  William G. Greathouse has been proven to be very useful. I also used the
- *  Win98 "HyperTerminal" and "usb-robot" on Linux for testing. The results and 
+ *  Win98 "HyperTerminal" and "usb-robot" on Linux for testing. The results and
  *  observations are summarized below:
  *
  *  The USB requests seem to be directly mapped to the registers of a 8250,
@@ -186,33 +195,33 @@
  *  Data:           LCR (see below)
  *
  *  Bit 7: Divisor Latch Access Bit (DLAB). When set, access to the data
- *  	   transmit/receive register (THR/RBR) and the Interrupt Enable Register
- *  	   (IER) is disabled. Any access to these ports is now redirected to the
- *  	   Divisor Latch Registers. Setting this bit, loading the Divisor
- *  	   Registers, and clearing DLAB should be done with interrupts disabled.
+ *	   transmit/receive register (THR/RBR) and the Interrupt Enable Register
+ *	   (IER) is disabled. Any access to these ports is now redirected to the
+ *	   Divisor Latch Registers. Setting this bit, loading the Divisor
+ *	   Registers, and clearing DLAB should be done with interrupts disabled.
  *  Bit 6: Set Break. When set to "1", the transmitter begins to transmit
- *  	   continuous Spacing until this bit is set to "0". This overrides any
- *  	   bits of characters that are being transmitted.
+ *	   continuous Spacing until this bit is set to "0". This overrides any
+ *	   bits of characters that are being transmitted.
  *  Bit 5: Stick Parity. When parity is enabled, setting this bit causes parity
- *  	   to always be "1" or "0", based on the value of Bit 4.
+ *	   to always be "1" or "0", based on the value of Bit 4.
  *  Bit 4: Even Parity Select (EPS). When parity is enabled and Bit 5 is "0",
- *  	   setting this bit causes even parity to be transmitted and expected.
- *  	   Otherwise, odd parity is used.
+ *	   setting this bit causes even parity to be transmitted and expected.
+ *	   Otherwise, odd parity is used.
  *  Bit 3: Parity Enable (PEN). When set to "1", a parity bit is inserted
- *  	   between the last bit of the data and the Stop Bit. The UART will also
- *  	   expect parity to be present in the received data.
+ *	   between the last bit of the data and the Stop Bit. The UART will also
+ *	   expect parity to be present in the received data.
  *  Bit 2: Number of Stop Bits (STB). If set to "1" and using 5-bit data words,
- *  	   1.5 Stop Bits are transmitted and expected in each data word. For
- *  	   6, 7 and 8-bit data words, 2 Stop Bits are transmitted and expected.
- *  	   When this bit is set to "0", one Stop Bit is used on each data word.
+ *	   1.5 Stop Bits are transmitted and expected in each data word. For
+ *	   6, 7 and 8-bit data words, 2 Stop Bits are transmitted and expected.
+ *	   When this bit is set to "0", one Stop Bit is used on each data word.
  *  Bit 1: Word Length Select Bit #1 (WLSB1)
  *  Bit 0: Word Length Select Bit #0 (WLSB0)
- *  	   Together these bits specify the number of bits in each data word.
- *  	     1 0  Word Length
- *  	     0 0  5 Data Bits
- *  	     0 1  6 Data Bits
- *  	     1 0  7 Data Bits
- *  	     1 1  8 Data Bits
+ *	   Together these bits specify the number of bits in each data word.
+ *	     1 0  Word Length
+ *	     0 0  5 Data Bits
+ *	     0 1  6 Data Bits
+ *	     1 0  7 Data Bits
+ *	     1 1  8 Data Bits
  *
  *  SniffUSB observations: Bit 7 seems not to be used. There seem to be two bugs
  *  in the Win98 driver: the break does not work (bit 6 is not asserted) and the
@@ -234,20 +243,20 @@
  *  Bit 6: Reserved, always 0.
  *  Bit 5: Reserved, always 0.
  *  Bit 4: Loop-Back Enable. When set to "1", the UART transmitter and receiver
- *  	   are internally connected together to allow diagnostic operations. In
- *  	   addition, the UART modem control outputs are connected to the UART
- *  	   modem control inputs. CTS is connected to RTS, DTR is connected to
- *  	   DSR, OUT1 is connected to RI, and OUT 2 is connected to DCD.
+ *	   are internally connected together to allow diagnostic operations. In
+ *	   addition, the UART modem control outputs are connected to the UART
+ *	   modem control inputs. CTS is connected to RTS, DTR is connected to
+ *	   DSR, OUT1 is connected to RI, and OUT 2 is connected to DCD.
  *  Bit 3: OUT 2. An auxiliary output that the host processor may set high or
- *  	   low. In the IBM PC serial adapter (and most clones), OUT 2 is used
- *  	   to tri-state (disable) the interrupt signal from the
- *  	   8250/16450/16550 UART.
+ *	   low. In the IBM PC serial adapter (and most clones), OUT 2 is used
+ *	   to tri-state (disable) the interrupt signal from the
+ *	   8250/16450/16550 UART.
  *  Bit 2: OUT 1. An auxiliary output that the host processor may set high or
- *  	   low. This output is not used on the IBM PC serial adapter.
+ *	   low. This output is not used on the IBM PC serial adapter.
  *  Bit 1: Request to Send (RTS). When set to "1", the output of the UART -RTS
- *  	   line is Low (Active).
+ *	   line is Low (Active).
  *  Bit 0: Data Terminal Ready (DTR). When set to "1", the output of the UART
- *  	   -DTR line is Low (Active).
+ *	   -DTR line is Low (Active).
  *
  *  SniffUSB observations: Bit 2 and 4 seem not to be used but bit 3 has been
  *  seen _always_ set.
@@ -264,22 +273,22 @@
  *  Data:           MSR (see below)
  *
  *  Bit 7: Data Carrier Detect (CD). Reflects the state of the DCD line on the
- *  	   UART.
+ *	   UART.
  *  Bit 6: Ring Indicator (RI). Reflects the state of the RI line on the UART.
  *  Bit 5: Data Set Ready (DSR). Reflects the state of the DSR line on the UART.
  *  Bit 4: Clear To Send (CTS). Reflects the state of the CTS line on the UART.
  *  Bit 3: Delta Data Carrier Detect (DDCD). Set to "1" if the -DCD line has
- *  	   changed state one more more times since the last time the MSR was
- *  	   read by the host.
+ *	   changed state one more more times since the last time the MSR was
+ *	   read by the host.
  *  Bit 2: Trailing Edge Ring Indicator (TERI). Set to "1" if the -RI line has
- *  	   had a low to high transition since the last time the MSR was read by
- *  	   the host.
+ *	   had a low to high transition since the last time the MSR was read by
+ *	   the host.
  *  Bit 1: Delta Data Set Ready (DDSR). Set to "1" if the -DSR line has changed
- *  	   state one more more times since the last time the MSR was read by the
- *  	   host.
+ *	   state one more more times since the last time the MSR was read by the
+ *	   host.
  *  Bit 0: Delta Clear To Send (DCTS). Set to "1" if the -CTS line has changed
- *  	   state one more times since the last time the MSR was read by the
- *  	   host.
+ *	   state one more times since the last time the MSR was read by the
+ *	   host.
  *
  *  SniffUSB observations: the MSR is also returned as first byte on the
  *  interrupt-in endpoint 0x83 to signal changes of modem status lines. The USB
@@ -290,31 +299,34 @@
  * --------------------------
  *
  *  Bit 7   Error in Receiver FIFO. On the 8250/16450 UART, this bit is zero.
- *  	    This bit is set to "1" when any of the bytes in the FIFO have one or
- *  	    more of the following error conditions: PE, FE, or BI.
+ *	    This bit is set to "1" when any of the bytes in the FIFO have one
+ *	    or more of the following error conditions: PE, FE, or BI.
  *  Bit 6   Transmitter Empty (TEMT). When set to "1", there are no words
- *  	    remaining in the transmit FIFO or the transmit shift register. The
- *  	    transmitter is completely idle.
- *  Bit 5   Transmitter Holding Register Empty (THRE). When set to "1", the FIFO
- *  	    (or holding register) now has room for at least one additional word
- *  	    to transmit. The transmitter may still be transmitting when this bit
- *  	    is set to "1".
+ *	    remaining in the transmit FIFO or the transmit shift register. The
+ *	    transmitter is completely idle.
+ *  Bit 5   Transmitter Holding Register Empty (THRE). When set to "1", the
+ *	    FIFO (or holding register) now has room for at least one additional
+ *	    word to transmit. The transmitter may still be transmitting when
+ *	    this bit is set to "1".
  *  Bit 4   Break Interrupt (BI). The receiver has detected a Break signal.
- *  Bit 3   Framing Error (FE). A Start Bit was detected but the Stop Bit did not
- *  	    appear at the expected time. The received word is probably garbled.
- *  Bit 2   Parity Error (PE). The parity bit was incorrect for the word received.
- *  Bit 1   Overrun Error (OE). A new word was received and there was no room in
- *  	    the receive buffer. The newly-arrived word in the shift register is
- *  	    discarded. On 8250/16450 UARTs, the word in the holding register is
- *  	    discarded and the newly- arrived word is put in the holding register.
+ *  Bit 3   Framing Error (FE). A Start Bit was detected but the Stop Bit did
+ *	    not appear at the expected time. The received word is probably
+ *	    garbled.
+ *  Bit 2   Parity Error (PE). The parity bit was incorrect for the word
+ *	    received.
+ *  Bit 1   Overrun Error (OE). A new word was received and there was no room
+ *	    in the receive buffer. The newly-arrived word in the shift register
+ *	    is discarded. On 8250/16450 UARTs, the word in the holding register
+ *	    is discarded and the newly- arrived word is put in the holding
+ *	    register.
  *  Bit 0   Data Ready (DR). One or more words are in the receive FIFO that the
- *  	    host may read. A word must be completely received and moved from the
- *  	    shift register into the FIFO (or holding register for 8250/16450
- *  	    designs) before this bit is set.
+ *	    host may read. A word must be completely received and moved from
+ *	    the shift register into the FIFO (or holding register for
+ *	    8250/16450 designs) before this bit is set.
  *
- *  SniffUSB observations: the LSR is returned as second byte on the interrupt-in
- *  endpoint 0x83 to signal error conditions. Such errors have been seen with
- *  minicom/zmodem transfers (CRC errors).
+ *  SniffUSB observations: the LSR is returned as second byte on the
+ *  interrupt-in endpoint 0x83 to signal error conditions. Such errors have
+ *  been seen with minicom/zmodem transfers (CRC errors).
  *
  *
  * Unknown #1
@@ -364,16 +376,16 @@
  * --------------
  *
  *  SniffUSB observations: the bulk-out endpoint 0x1 and interrupt-in endpoint
- *  0x81 is used to transmit and receive characters. The second interrupt-in 
- *  endpoint 0x83 signals exceptional conditions like modem line changes and 
+ *  0x81 is used to transmit and receive characters. The second interrupt-in
+ *  endpoint 0x83 signals exceptional conditions like modem line changes and
  *  errors. The first byte returned is the MSR and the second byte the LSR.
  *
  *
  * Other observations
  * ------------------
  *
- *  Queued bulk transfers like used in visor.c did not work. 
- *  
+ *  Queued bulk transfers like used in visor.c did not work.
+ *
  *
  * Properties of the USB device used (as found in /var/log/messages)
  * -----------------------------------------------------------------
@@ -411,26 +423,26 @@
  *      bInterface Class:SubClass:Protocol =   00:00:00
  *      iInterface          =   00
  *      Endpoint:
- * 	  bLength             =    7
- * 	  bDescriptorType     =   05
- * 	  bEndpointAddress    =   81 (in)
- * 	  bmAttributes        =   03 (Interrupt)
- * 	  wMaxPacketSize      = 0040
- * 	  bInterval           =   02
+ *	  bLength             =    7
+ *	  bDescriptorType     =   05
+ *	  bEndpointAddress    =   81 (in)
+ *	  bmAttributes        =   03 (Interrupt)
+ *	  wMaxPacketSize      = 0040
+ *	  bInterval           =   02
  *      Endpoint:
- * 	  bLength             =    7
- * 	  bDescriptorType     =   05
- * 	  bEndpointAddress    =   01 (out)
- * 	  bmAttributes        =   02 (Bulk)
- * 	  wMaxPacketSize      = 0040
- * 	  bInterval           =   00
+ *	  bLength             =    7
+ *	  bDescriptorType     =   05
+ *	  bEndpointAddress    =   01 (out)
+ *	  bmAttributes        =   02 (Bulk)
+ *	  wMaxPacketSize      = 0040
+ *	  bInterval           =   00
  *      Endpoint:
- * 	  bLength             =    7
- * 	  bDescriptorType     =   05
- * 	  bEndpointAddress    =   83 (in)
- * 	  bmAttributes        =   03 (Interrupt)
- * 	  wMaxPacketSize      = 0002
- * 	  bInterval           =   02
+ *	  bLength             =    7
+ *	  bDescriptorType     =   05
+ *	  bEndpointAddress    =   83 (in)
+ *	  bmAttributes        =   03 (Interrupt)
+ *	  wMaxPacketSize      = 0002
+ *	  bInterval           =   02
  *
  *
  * Hardware details (added by Martin Hamilton, 2001/12/06)
@@ -440,7 +452,7 @@
  * adaptor, which turns out to simply be a re-badged U232-P9.  We
  * know this because there is a sticky label on the circuit board
  * which says "U232-P9" ;-)
- * 
+ *
  * The circuit board inside the adaptor contains a Philips PDIUSBD12
  * USB endpoint chip and a Philips P87C52UBAA microcontroller with
  * embedded UART.  Exhaustive documentation for these is available at:
@@ -449,7 +461,7 @@
  *   http://www.semiconductors.philips.com/pip/pdiusbd12
  *
  * Thanks to Julian Highfield for the pointer to the Philips database.
- * 
+ *
  */
 
 #endif /* __LINUX_USB_SERIAL_MCT_U232_H */
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 0d47f2c..30922a7 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -34,21 +34,18 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 #include <linux/uaccess.h>
-
+#include <linux/parport.h>
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "1.0.0.4F"
+#define DRIVER_VERSION "2.1"
 #define DRIVER_AUTHOR "Aspire Communications pvt Ltd."
 #define DRIVER_DESC "Moschip USB Serial Driver"
 
 /* default urb timeout */
 #define MOS_WDR_TIMEOUT	(HZ * 5)
 
-#define MOS_PORT1	0x0200
-#define MOS_PORT2	0x0300
-#define MOS_VENREG	0x0000
 #define MOS_MAX_PORT	0x02
 #define MOS_WRITE	0x0E
 #define MOS_READ	0x0D
@@ -63,7 +60,7 @@
 #define NUM_URBS			16	/* URB Count */
 #define URB_TRANSFER_BUFFER_SIZE	32	/* URB Size */
 
-/* This structure holds all of the local port information */
+/* This structure holds all of the local serial port information */
 struct moschip_port {
 	__u8	shadowLCR;		/* last LCR value received */
 	__u8	shadowMCR;		/* last MCR value received */
@@ -74,11 +71,6 @@
 	struct urb		*write_urb_pool[NUM_URBS];
 };
 
-/* This structure holds all of the individual serial device information */
-struct moschip_serial {
-	int interrupt_started;
-};
-
 static int debug;
 
 static struct usb_serial_driver moschip7720_2port_driver;
@@ -94,6 +86,658 @@
 };
 MODULE_DEVICE_TABLE(usb, moschip_port_id_table);
 
+#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
+
+/* initial values for parport regs */
+#define DCR_INIT_VAL       0x0c	/* SLCTIN, nINIT */
+#define ECR_INIT_VAL       0x00	/* SPP mode */
+
+struct urbtracker {
+	struct mos7715_parport  *mos_parport;
+	struct list_head        urblist_entry;
+	struct kref             ref_count;
+	struct urb              *urb;
+};
+
+enum mos7715_pp_modes {
+	SPP = 0<<5,
+	PS2 = 1<<5,      /* moschip calls this 'NIBBLE' mode */
+	PPF = 2<<5,	 /* moschip calls this 'CB-FIFO mode */
+};
+
+struct mos7715_parport {
+	struct parport          *pp;	       /* back to containing struct */
+	struct kref             ref_count;     /* to instance of this struct */
+	struct list_head        deferred_urbs; /* list deferred async urbs */
+	struct list_head        active_urbs;   /* list async urbs in flight */
+	spinlock_t              listlock;      /* protects list access */
+	bool                    msg_pending;   /* usb sync call pending */
+	struct completion       syncmsg_compl; /* usb sync call completed */
+	struct tasklet_struct   urb_tasklet;   /* for sending deferred urbs */
+	struct usb_serial       *serial;       /* back to containing struct */
+	__u8	                shadowECR;     /* parallel port regs... */
+	__u8	                shadowDCR;
+	atomic_t                shadowDSR;     /* updated in int-in callback */
+};
+
+/* lock guards against dereferencing NULL ptr in parport ops callbacks */
+static DEFINE_SPINLOCK(release_lock);
+
+#endif	/* CONFIG_USB_SERIAL_MOS7715_PARPORT */
+
+static const unsigned int dummy; /* for clarity in register access fns */
+
+enum mos_regs {
+	THR,	          /* serial port regs */
+	RHR,
+	IER,
+	FCR,
+	ISR,
+	LCR,
+	MCR,
+	LSR,
+	MSR,
+	SPR,
+	DLL,
+	DLM,
+	DPR,              /* parallel port regs */
+	DSR,
+	DCR,
+	ECR,
+	SP1_REG,          /* device control regs */
+	SP2_REG,          /* serial port 2 (7720 only) */
+	PP_REG,
+	SP_CONTROL_REG,
+};
+
+/*
+ * Return the correct value for the Windex field of the setup packet
+ * for a control endpoint message.  See the 7715 datasheet.
+ */
+static inline __u16 get_reg_index(enum mos_regs reg)
+{
+	static const __u16 mos7715_index_lookup_table[] = {
+		0x00,		/* THR */
+		0x00,		/* RHR */
+		0x01,		/* IER */
+		0x02,		/* FCR */
+		0x02,		/* ISR */
+		0x03,		/* LCR */
+		0x04,		/* MCR */
+		0x05,		/* LSR */
+		0x06,		/* MSR */
+		0x07,		/* SPR */
+		0x00,		/* DLL */
+		0x01,		/* DLM */
+		0x00,		/* DPR */
+		0x01,		/* DSR */
+		0x02,		/* DCR */
+		0x0a,		/* ECR */
+		0x01,		/* SP1_REG */
+		0x02,		/* SP2_REG (7720 only) */
+		0x04,		/* PP_REG (7715 only) */
+		0x08,		/* SP_CONTROL_REG */
+	};
+	return mos7715_index_lookup_table[reg];
+}
+
+/*
+ * Return the correct value for the upper byte of the Wvalue field of
+ * the setup packet for a control endpoint message.
+ */
+static inline __u16 get_reg_value(enum mos_regs reg,
+				  unsigned int serial_portnum)
+{
+	if (reg >= SP1_REG)	      /* control reg */
+		return 0x0000;
+
+	else if (reg >= DPR)	      /* parallel port reg (7715 only) */
+		return 0x0100;
+
+	else			      /* serial port reg */
+		return (serial_portnum + 2) << 8;
+}
+
+/*
+ * Write data byte to the specified device register.  The data is embedded in
+ * the value field of the setup packet. serial_portnum is ignored for registers
+ * not specific to a particular serial port.
+ */
+static int write_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,
+			 enum mos_regs reg, __u8 data)
+{
+	struct usb_device *usbdev = serial->dev;
+	unsigned int pipe = usb_sndctrlpipe(usbdev, 0);
+	__u8 request = (__u8)0x0e;
+	__u8 requesttype = (__u8)0x40;
+	__u16 index = get_reg_index(reg);
+	__u16 value = get_reg_value(reg, serial_portnum) + data;
+	int status = usb_control_msg(usbdev, pipe, request, requesttype, value,
+				     index, NULL, 0, MOS_WDR_TIMEOUT);
+	if (status < 0)
+		dev_err(&usbdev->dev,
+			"mos7720: usb_control_msg() failed: %d", status);
+	return status;
+}
+
+/*
+ * Read data byte from the specified device register.  The data returned by the
+ * device is embedded in the value field of the setup packet.  serial_portnum is
+ * ignored for registers that are not specific to a particular serial port.
+ */
+static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,
+			enum mos_regs reg, __u8 *data)
+{
+	struct usb_device *usbdev = serial->dev;
+	unsigned int pipe = usb_rcvctrlpipe(usbdev, 0);
+	__u8 request = (__u8)0x0d;
+	__u8 requesttype = (__u8)0xc0;
+	__u16 index = get_reg_index(reg);
+	__u16 value = get_reg_value(reg, serial_portnum);
+	int status = usb_control_msg(usbdev, pipe, request, requesttype, value,
+				     index, data, 1, MOS_WDR_TIMEOUT);
+	if (status < 0)
+		dev_err(&usbdev->dev,
+			"mos7720: usb_control_msg() failed: %d", status);
+	return status;
+}
+
+#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
+
+static inline int mos7715_change_mode(struct mos7715_parport *mos_parport,
+				      enum mos7715_pp_modes mode)
+{
+	mos_parport->shadowECR = mode;
+	write_mos_reg(mos_parport->serial, dummy, ECR, mos_parport->shadowECR);
+	return 0;
+}
+
+static void destroy_mos_parport(struct kref *kref)
+{
+	struct mos7715_parport *mos_parport =
+		container_of(kref, struct mos7715_parport, ref_count);
+
+	dbg("%s called", __func__);
+	kfree(mos_parport);
+}
+
+static void destroy_urbtracker(struct kref *kref)
+{
+	struct urbtracker *urbtrack =
+		container_of(kref, struct urbtracker, ref_count);
+	struct mos7715_parport *mos_parport = urbtrack->mos_parport;
+	dbg("%s called", __func__);
+	usb_free_urb(urbtrack->urb);
+	kfree(urbtrack);
+	kref_put(&mos_parport->ref_count, destroy_mos_parport);
+}
+
+/*
+ * This runs as a tasklet when sending an urb in a non-blocking parallel
+ * port callback had to be deferred because the disconnect mutex could not be
+ * obtained at the time.
+ */
+static void send_deferred_urbs(unsigned long _mos_parport)
+{
+	int ret_val;
+	unsigned long flags;
+	struct mos7715_parport *mos_parport = (void *)_mos_parport;
+	struct urbtracker *urbtrack;
+	struct list_head *cursor, *next;
+
+	dbg("%s called", __func__);
+
+	/* if release function ran, game over */
+	if (unlikely(mos_parport->serial == NULL))
+		return;
+
+	/* try again to get the mutex */
+	if (!mutex_trylock(&mos_parport->serial->disc_mutex)) {
+		dbg("%s: rescheduling tasklet", __func__);
+		tasklet_schedule(&mos_parport->urb_tasklet);
+		return;
+	}
+
+	/* if device disconnected, game over */
+	if (unlikely(mos_parport->serial->disconnected)) {
+		mutex_unlock(&mos_parport->serial->disc_mutex);
+		return;
+	}
+
+	spin_lock_irqsave(&mos_parport->listlock, flags);
+	if (list_empty(&mos_parport->deferred_urbs)) {
+		spin_unlock_irqrestore(&mos_parport->listlock, flags);
+		mutex_unlock(&mos_parport->serial->disc_mutex);
+		dbg("%s: deferred_urbs list empty", __func__);
+		return;
+	}
+
+	/* move contents of deferred_urbs list to active_urbs list and submit */
+	list_for_each_safe(cursor, next, &mos_parport->deferred_urbs)
+		list_move_tail(cursor, &mos_parport->active_urbs);
+	list_for_each_entry(urbtrack, &mos_parport->active_urbs,
+			    urblist_entry) {
+		ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC);
+		dbg("%s: urb submitted", __func__);
+		if (ret_val) {
+			dev_err(&mos_parport->serial->dev->dev,
+				"usb_submit_urb() failed: %d", ret_val);
+			list_del(&urbtrack->urblist_entry);
+			kref_put(&urbtrack->ref_count, destroy_urbtracker);
+		}
+	}
+	spin_unlock_irqrestore(&mos_parport->listlock, flags);
+	mutex_unlock(&mos_parport->serial->disc_mutex);
+}
+
+/* callback for parallel port control urbs submitted asynchronously */
+static void async_complete(struct urb *urb)
+{
+	struct urbtracker *urbtrack = urb->context;
+	int status = urb->status;
+	dbg("%s called", __func__);
+	if (unlikely(status))
+		dbg("%s - nonzero urb status received: %d", __func__, status);
+
+	/* remove the urbtracker from the active_urbs list */
+	spin_lock(&urbtrack->mos_parport->listlock);
+	list_del(&urbtrack->urblist_entry);
+	spin_unlock(&urbtrack->mos_parport->listlock);
+	kref_put(&urbtrack->ref_count, destroy_urbtracker);
+}
+
+static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
+				      enum mos_regs reg, __u8 data)
+{
+	struct urbtracker *urbtrack;
+	int ret_val;
+	unsigned long flags;
+	struct usb_ctrlrequest setup;
+	struct usb_serial *serial = mos_parport->serial;
+	struct usb_device *usbdev = serial->dev;
+	dbg("%s called", __func__);
+
+	/* create and initialize the control urb and containing urbtracker */
+	urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC);
+	if (urbtrack == NULL) {
+		dev_err(&usbdev->dev, "out of memory");
+		return -ENOMEM;
+	}
+	kref_get(&mos_parport->ref_count);
+	urbtrack->mos_parport = mos_parport;
+	urbtrack->urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (urbtrack->urb == NULL) {
+		dev_err(&usbdev->dev, "out of urbs");
+		kfree(urbtrack);
+		return -ENOMEM;
+	}
+	setup.bRequestType = (__u8)0x40;
+	setup.bRequest = (__u8)0x0e;
+	setup.wValue = get_reg_value(reg, dummy);
+	setup.wIndex = get_reg_index(reg);
+	setup.wLength = 0;
+	usb_fill_control_urb(urbtrack->urb, usbdev,
+			     usb_sndctrlpipe(usbdev, 0),
+			     (unsigned char *)&setup,
+			     NULL, 0, async_complete, urbtrack);
+	kref_init(&urbtrack->ref_count);
+	INIT_LIST_HEAD(&urbtrack->urblist_entry);
+
+	/*
+	 * get the disconnect mutex, or add tracker to the deferred_urbs list
+	 * and schedule a tasklet to try again later
+	 */
+	if (!mutex_trylock(&serial->disc_mutex)) {
+		spin_lock_irqsave(&mos_parport->listlock, flags);
+		list_add_tail(&urbtrack->urblist_entry,
+			      &mos_parport->deferred_urbs);
+		spin_unlock_irqrestore(&mos_parport->listlock, flags);
+		tasklet_schedule(&mos_parport->urb_tasklet);
+		dbg("tasklet scheduled");
+		return 0;
+	}
+
+	/* bail if device disconnected */
+	if (serial->disconnected) {
+		kref_put(&urbtrack->ref_count, destroy_urbtracker);
+		mutex_unlock(&serial->disc_mutex);
+		return -ENODEV;
+	}
+
+	/* add the tracker to the active_urbs list and submit */
+	spin_lock_irqsave(&mos_parport->listlock, flags);
+	list_add_tail(&urbtrack->urblist_entry, &mos_parport->active_urbs);
+	spin_unlock_irqrestore(&mos_parport->listlock, flags);
+	ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC);
+	mutex_unlock(&serial->disc_mutex);
+	if (ret_val) {
+		dev_err(&usbdev->dev,
+			"%s: submit_urb() failed: %d", __func__, ret_val);
+		spin_lock_irqsave(&mos_parport->listlock, flags);
+		list_del(&urbtrack->urblist_entry);
+		spin_unlock_irqrestore(&mos_parport->listlock, flags);
+		kref_put(&urbtrack->ref_count, destroy_urbtracker);
+		return ret_val;
+	}
+	return 0;
+}
+
+/*
+ * This is the the common top part of all parallel port callback operations that
+ * send synchronous messages to the device.  This implements convoluted locking
+ * that avoids two scenarios: (1) a port operation is called after usbserial
+ * has called our release function, at which point struct mos7715_parport has
+ * been destroyed, and (2) the device has been disconnected, but usbserial has
+ * not called the release function yet because someone has a serial port open.
+ * The shared release_lock prevents the first, and the mutex and disconnected
+ * flag maintained by usbserial covers the second.  We also use the msg_pending
+ * flag to ensure that all synchronous usb messgage calls have completed before
+ * our release function can return.
+ */
+static int parport_prologue(struct parport *pp)
+{
+	struct mos7715_parport *mos_parport;
+
+	spin_lock(&release_lock);
+	mos_parport = pp->private_data;
+	if (unlikely(mos_parport == NULL)) {
+		/* release fn called, port struct destroyed */
+		spin_unlock(&release_lock);
+		return -1;
+	}
+	mos_parport->msg_pending = true;   /* synch usb call pending */
+	INIT_COMPLETION(mos_parport->syncmsg_compl);
+	spin_unlock(&release_lock);
+
+	mutex_lock(&mos_parport->serial->disc_mutex);
+	if (mos_parport->serial->disconnected) {
+		/* device disconnected */
+		mutex_unlock(&mos_parport->serial->disc_mutex);
+		mos_parport->msg_pending = false;
+		complete(&mos_parport->syncmsg_compl);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * This is the the common bottom part of all parallel port functions that send
+ * synchronous messages to the device.
+ */
+static inline void parport_epilogue(struct parport *pp)
+{
+	struct mos7715_parport *mos_parport = pp->private_data;
+	mutex_unlock(&mos_parport->serial->disc_mutex);
+	mos_parport->msg_pending = false;
+	complete(&mos_parport->syncmsg_compl);
+}
+
+static void parport_mos7715_write_data(struct parport *pp, unsigned char d)
+{
+	struct mos7715_parport *mos_parport = pp->private_data;
+	dbg("%s called: %2.2x", __func__, d);
+	if (parport_prologue(pp) < 0)
+		return;
+	mos7715_change_mode(mos_parport, SPP);
+	write_mos_reg(mos_parport->serial, dummy, DPR, (__u8)d);
+	parport_epilogue(pp);
+}
+
+static unsigned char parport_mos7715_read_data(struct parport *pp)
+{
+	struct mos7715_parport *mos_parport = pp->private_data;
+	unsigned char d;
+	dbg("%s called", __func__);
+	if (parport_prologue(pp) < 0)
+		return 0;
+	read_mos_reg(mos_parport->serial, dummy, DPR, &d);
+	parport_epilogue(pp);
+	return d;
+}
+
+static void parport_mos7715_write_control(struct parport *pp, unsigned char d)
+{
+	struct mos7715_parport *mos_parport = pp->private_data;
+	__u8 data;
+	dbg("%s called: %2.2x", __func__, d);
+	if (parport_prologue(pp) < 0)
+		return;
+	data = ((__u8)d & 0x0f) | (mos_parport->shadowDCR & 0xf0);
+	write_mos_reg(mos_parport->serial, dummy, DCR, data);
+	mos_parport->shadowDCR = data;
+	parport_epilogue(pp);
+}
+
+static unsigned char parport_mos7715_read_control(struct parport *pp)
+{
+	struct mos7715_parport *mos_parport = pp->private_data;
+	__u8 dcr;
+	dbg("%s called", __func__);
+	spin_lock(&release_lock);
+	mos_parport = pp->private_data;
+	if (unlikely(mos_parport == NULL)) {
+		spin_unlock(&release_lock);
+		return 0;
+	}
+	dcr = mos_parport->shadowDCR & 0x0f;
+	spin_unlock(&release_lock);
+	return dcr;
+}
+
+static unsigned char parport_mos7715_frob_control(struct parport *pp,
+						  unsigned char mask,
+						  unsigned char val)
+{
+	struct mos7715_parport *mos_parport = pp->private_data;
+	__u8 dcr;
+	dbg("%s called", __func__);
+	mask &= 0x0f;
+	val &= 0x0f;
+	if (parport_prologue(pp) < 0)
+		return 0;
+	mos_parport->shadowDCR = (mos_parport->shadowDCR & (~mask)) ^ val;
+	write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR);
+	dcr = mos_parport->shadowDCR & 0x0f;
+	parport_epilogue(pp);
+	return dcr;
+}
+
+static unsigned char parport_mos7715_read_status(struct parport *pp)
+{
+	unsigned char status;
+	struct mos7715_parport *mos_parport = pp->private_data;
+	dbg("%s called", __func__);
+	spin_lock(&release_lock);
+	mos_parport = pp->private_data;
+	if (unlikely(mos_parport == NULL)) {	/* release called */
+		spin_unlock(&release_lock);
+		return 0;
+	}
+	status = atomic_read(&mos_parport->shadowDSR) & 0xf8;
+	spin_unlock(&release_lock);
+	return status;
+}
+
+static void parport_mos7715_enable_irq(struct parport *pp)
+{
+	dbg("%s called", __func__);
+}
+static void parport_mos7715_disable_irq(struct parport *pp)
+{
+	dbg("%s called", __func__);
+}
+
+static void parport_mos7715_data_forward(struct parport *pp)
+{
+	struct mos7715_parport *mos_parport = pp->private_data;
+	dbg("%s called", __func__);
+	if (parport_prologue(pp) < 0)
+		return;
+	mos7715_change_mode(mos_parport, PS2);
+	mos_parport->shadowDCR &=  ~0x20;
+	write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR);
+	parport_epilogue(pp);
+}
+
+static void parport_mos7715_data_reverse(struct parport *pp)
+{
+	struct mos7715_parport *mos_parport = pp->private_data;
+	dbg("%s called", __func__);
+	if (parport_prologue(pp) < 0)
+		return;
+	mos7715_change_mode(mos_parport, PS2);
+	mos_parport->shadowDCR |= 0x20;
+	write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR);
+	parport_epilogue(pp);
+}
+
+static void parport_mos7715_init_state(struct pardevice *dev,
+				       struct parport_state *s)
+{
+	dbg("%s called", __func__);
+	s->u.pc.ctr = DCR_INIT_VAL;
+	s->u.pc.ecr = ECR_INIT_VAL;
+}
+
+/* N.B. Parport core code requires that this function not block */
+static void parport_mos7715_save_state(struct parport *pp,
+				       struct parport_state *s)
+{
+	struct mos7715_parport *mos_parport;
+	dbg("%s called", __func__);
+	spin_lock(&release_lock);
+	mos_parport = pp->private_data;
+	if (unlikely(mos_parport == NULL)) {	/* release called */
+		spin_unlock(&release_lock);
+		return;
+	}
+	s->u.pc.ctr = mos_parport->shadowDCR;
+	s->u.pc.ecr = mos_parport->shadowECR;
+	spin_unlock(&release_lock);
+}
+
+/* N.B. Parport core code requires that this function not block */
+static void parport_mos7715_restore_state(struct parport *pp,
+					  struct parport_state *s)
+{
+	struct mos7715_parport *mos_parport;
+	dbg("%s called", __func__);
+	spin_lock(&release_lock);
+	mos_parport = pp->private_data;
+	if (unlikely(mos_parport == NULL)) {	/* release called */
+		spin_unlock(&release_lock);
+		return;
+	}
+	write_parport_reg_nonblock(mos_parport, DCR, mos_parport->shadowDCR);
+	write_parport_reg_nonblock(mos_parport, ECR, mos_parport->shadowECR);
+	spin_unlock(&release_lock);
+}
+
+static size_t parport_mos7715_write_compat(struct parport *pp,
+					   const void *buffer,
+					   size_t len, int flags)
+{
+	int retval;
+	struct mos7715_parport *mos_parport = pp->private_data;
+	int actual_len;
+	dbg("%s called: %u chars", __func__, (unsigned int)len);
+	if (parport_prologue(pp) < 0)
+		return 0;
+	mos7715_change_mode(mos_parport, PPF);
+	retval = usb_bulk_msg(mos_parport->serial->dev,
+			      usb_sndbulkpipe(mos_parport->serial->dev, 2),
+			      (void *)buffer, len, &actual_len,
+			      MOS_WDR_TIMEOUT);
+	parport_epilogue(pp);
+	if (retval) {
+		dev_err(&mos_parport->serial->dev->dev,
+			"mos7720: usb_bulk_msg() failed: %d", retval);
+		return 0;
+	}
+	return actual_len;
+}
+
+static struct parport_operations parport_mos7715_ops = {
+	.owner =		THIS_MODULE,
+	.write_data =		parport_mos7715_write_data,
+	.read_data =		parport_mos7715_read_data,
+
+	.write_control =	parport_mos7715_write_control,
+	.read_control =		parport_mos7715_read_control,
+	.frob_control =		parport_mos7715_frob_control,
+
+	.read_status =		parport_mos7715_read_status,
+
+	.enable_irq =		parport_mos7715_enable_irq,
+	.disable_irq =		parport_mos7715_disable_irq,
+
+	.data_forward =		parport_mos7715_data_forward,
+	.data_reverse =		parport_mos7715_data_reverse,
+
+	.init_state =		parport_mos7715_init_state,
+	.save_state =		parport_mos7715_save_state,
+	.restore_state =	parport_mos7715_restore_state,
+
+	.compat_write_data =	parport_mos7715_write_compat,
+
+	.nibble_read_data =	parport_ieee1284_read_nibble,
+	.byte_read_data =	parport_ieee1284_read_byte,
+};
+
+/*
+ * Allocate and initialize parallel port control struct, initialize
+ * the parallel port hardware device, and register with the parport subsystem.
+ */
+static int mos7715_parport_init(struct usb_serial *serial)
+{
+	struct mos7715_parport *mos_parport;
+
+	/* allocate and initialize parallel port control struct */
+	mos_parport = kzalloc(sizeof(struct mos7715_parport), GFP_KERNEL);
+	if (mos_parport == NULL) {
+		dbg("mos7715_parport_init: kzalloc failed");
+		return -ENOMEM;
+	}
+	mos_parport->msg_pending = false;
+	kref_init(&mos_parport->ref_count);
+	spin_lock_init(&mos_parport->listlock);
+	INIT_LIST_HEAD(&mos_parport->active_urbs);
+	INIT_LIST_HEAD(&mos_parport->deferred_urbs);
+	usb_set_serial_data(serial, mos_parport); /* hijack private pointer */
+	mos_parport->serial = serial;
+	tasklet_init(&mos_parport->urb_tasklet, send_deferred_urbs,
+		     (unsigned long) mos_parport);
+	init_completion(&mos_parport->syncmsg_compl);
+
+	/* cycle parallel port reset bit */
+	write_mos_reg(mos_parport->serial, dummy, PP_REG, (__u8)0x80);
+	write_mos_reg(mos_parport->serial, dummy, PP_REG, (__u8)0x00);
+
+	/* initialize device registers */
+	mos_parport->shadowDCR = DCR_INIT_VAL;
+	write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR);
+	mos_parport->shadowECR = ECR_INIT_VAL;
+	write_mos_reg(mos_parport->serial, dummy, ECR, mos_parport->shadowECR);
+
+	/* register with parport core */
+	mos_parport->pp = parport_register_port(0, PARPORT_IRQ_NONE,
+						PARPORT_DMA_NONE,
+						&parport_mos7715_ops);
+	if (mos_parport->pp == NULL) {
+		dev_err(&serial->interface->dev,
+			"Could not register parport\n");
+		kref_put(&mos_parport->ref_count, destroy_mos_parport);
+		return -EIO;
+	}
+	mos_parport->pp->private_data = mos_parport;
+	mos_parport->pp->modes = PARPORT_MODE_COMPAT | PARPORT_MODE_PCSPP;
+	mos_parport->pp->dev = &serial->interface->dev;
+	parport_announce_port(mos_parport->pp);
+
+	return 0;
+}
+#endif	/* CONFIG_USB_SERIAL_MOS7715_PARPORT */
 
 /*
  * mos7720_interrupt_callback
@@ -109,8 +753,6 @@
 	__u8 sp1;
 	__u8 sp2;
 
-	dbg(" : Entering");
-
 	switch (status) {
 	case 0:
 		/* success */
@@ -161,7 +803,7 @@
 			dbg("Serial Port 1: Receiver time out");
 			break;
 		case SERIAL_IIR_MS:
-			dbg("Serial Port 1: Modem status change");
+			/* dbg("Serial Port 1: Modem status change"); */
 			break;
 		}
 
@@ -174,7 +816,7 @@
 			dbg("Serial Port 2: Receiver time out");
 			break;
 		case SERIAL_IIR_MS:
-			dbg("Serial Port 2: Modem status change");
+			/* dbg("Serial Port 2: Modem status change"); */
 			break;
 		}
 	}
@@ -208,6 +850,7 @@
 	case -ECONNRESET:
 	case -ENOENT:
 	case -ESHUTDOWN:
+	case -ENODEV:
 		/* this urb is terminated, clean up */
 		dbg("%s - urb shutting down with status: %d", __func__,
 		    status);
@@ -243,11 +886,21 @@
 			dbg("Serial Port: Receiver time out");
 			break;
 		case SERIAL_IIR_MS:
-			dbg("Serial Port: Modem status change");
+			/* dbg("Serial Port: Modem status change"); */
 			break;
 		}
 	}
 
+#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
+	{       /* update local copy of DSR reg */
+		struct usb_serial_port *port = urb->context;
+		struct mos7715_parport *mos_parport = port->serial->private;
+		if (unlikely(mos_parport == NULL))
+			return;
+		atomic_set(&mos_parport->shadowDSR, data[2]);
+	}
+#endif
+
 exit:
 	result = usb_submit_urb(urb, GFP_ATOMIC);
 	if (result)
@@ -267,7 +920,6 @@
 	int retval;
 	unsigned char *data ;
 	struct usb_serial_port *port;
-	struct moschip_port *mos7720_port;
 	struct tty_struct *tty;
 	int status = urb->status;
 
@@ -276,13 +928,7 @@
 		return;
 	}
 
-	mos7720_port = urb->context;
-	if (!mos7720_port) {
-		dbg("NULL mos7720_port pointer");
-		return ;
-	}
-
-	port = mos7720_port->port;
+	port = urb->context;
 
 	dbg("Entering...%s", __func__);
 
@@ -332,8 +978,6 @@
 		return ;
 	}
 
-	dbg("Entering .........");
-
 	tty = tty_port_tty_get(&mos7720_port->port->port);
 
 	if (tty && mos7720_port->open)
@@ -342,56 +986,6 @@
 }
 
 /*
- * send_mos_cmd
- *	this function will be used for sending command to device
- */
-static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value,
-			__u16 index, u8 *data)
-{
-	int status;
-	u8 *buf;
-	u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
-
-	if (value < MOS_MAX_PORT) {
-		if (product == MOSCHIP_DEVICE_ID_7715)
-			value = 0x0200; /* identifies the 7715's serial port */
-		else
-			value = value*0x100+0x200;
-	} else {
-		value = 0x0000;
-		if ((product == MOSCHIP_DEVICE_ID_7715) &&
-		    (index != 0x08)) {
-			dbg("serial->product== MOSCHIP_DEVICE_ID_7715");
-			/* index = 0x01 ; */
-		}
-	}
-
-	if (request == MOS_WRITE) {
-		value = value + *data;
-		status = usb_control_msg(serial->dev,
-				usb_sndctrlpipe(serial->dev, 0), MOS_WRITE,
-				0x40, value, index, NULL, 0, MOS_WDR_TIMEOUT);
-	} else {
-		buf = kmalloc(1, GFP_KERNEL);
-		if (!buf) {
-			status = -ENOMEM;
-			goto out;
-		}
-		status = usb_control_msg(serial->dev,
-				usb_rcvctrlpipe(serial->dev, 0), MOS_READ,
-				0xc0, value, index, buf, 1, MOS_WDR_TIMEOUT);
-		*data = *buf;
-		kfree(buf);
-	}
-out:
-	if (status < 0)
-		dbg("Command Write failed Value %x index %x", value, index);
-
-	return status;
-}
-
-
-/*
  * mos77xx_probe
  *	this function installs the appropriate read interrupt endpoint callback
  *	depending on whether the device is a 7720 or 7715, thus avoiding costly
@@ -424,11 +1018,10 @@
 	struct usb_serial *serial;
 	struct usb_serial_port *port0;
 	struct urb *urb;
-	struct moschip_serial *mos7720_serial;
 	struct moschip_port *mos7720_port;
 	int response;
 	int port_number;
-	char data;
+	__u8 data;
 	int allocated_urbs = 0;
 	int j;
 
@@ -440,11 +1033,6 @@
 
 	port0 = serial->port[0];
 
-	mos7720_serial = usb_get_serial_data(serial);
-
-	if (mos7720_serial == NULL || port0 == NULL)
-		return -ENODEV;
-
 	usb_clear_halt(serial->dev, port->write_urb->pipe);
 	usb_clear_halt(serial->dev, port->read_urb->pipe);
 
@@ -489,103 +1077,36 @@
 	  * 0x08 : SP1/2 Control Reg
 	  */
 	port_number = port->number - port->serial->minor;
-	send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data);
+	read_mos_reg(serial, port_number, LSR, &data);
+
 	dbg("SS::%p LSR:%x", mos7720_port, data);
 
 	dbg("Check:Sending Command ..........");
 
-	data = 0x02;
-	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data);
-	data = 0x02;
-	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data);
+	write_mos_reg(serial, dummy, SP1_REG, 0x02);
+	write_mos_reg(serial, dummy, SP2_REG, 0x02);
 
-	data = 0x00;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
-	data = 0x00;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
+	write_mos_reg(serial, port_number, IER, 0x00);
+	write_mos_reg(serial, port_number, FCR, 0x00);
 
-	data = 0xCF;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
-	data = 0x03;
-	mos7720_port->shadowLCR  = data;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
-	data = 0x0b;
-	mos7720_port->shadowMCR  = data;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
-	data = 0x0b;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+	write_mos_reg(serial, port_number, FCR, 0xcf);
+	mos7720_port->shadowLCR = 0x03;
+	write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
+	mos7720_port->shadowMCR = 0x0b;
+	write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
 
-	data = 0x00;
-	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
-	data = 0x00;
-	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
-
-/*	data = 0x00;
-	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data);
-	data = 0x03;
-	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
-	data = 0x00;
-	send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT,
-						port_number + 1, &data);
-*/
-	data = 0x00;
-	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
-
+	write_mos_reg(serial, port_number, SP_CONTROL_REG, 0x00);
+	read_mos_reg(serial, dummy, SP_CONTROL_REG, &data);
 	data = data | (port->number - port->serial->minor + 1);
-	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
+	write_mos_reg(serial, dummy, SP_CONTROL_REG, data);
+	mos7720_port->shadowLCR = 0x83;
+	write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
+	write_mos_reg(serial, port_number, THR, 0x0c);
+	write_mos_reg(serial, port_number, IER, 0x00);
+	mos7720_port->shadowLCR = 0x03;
+	write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
+	write_mos_reg(serial, port_number, IER, 0x0c);
 
-	data = 0x83;
-	mos7720_port->shadowLCR  = data;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
-	data = 0x0c;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
-	data = 0x00;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
-	data = 0x03;
-	mos7720_port->shadowLCR  = data;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
-	data = 0x0c;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
-	data = 0x0c;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
-
-	/* see if we've set up our endpoint info yet   *
-	 * (can't set it up in mos7720_startup as the  *
-	 * structures were not set up at that time.)   */
-	if (!mos7720_serial->interrupt_started) {
-		dbg("Interrupt buffer NULL !!!");
-
-		/* not set up yet, so do it now */
-		mos7720_serial->interrupt_started = 1;
-
-		dbg("To Submit URB !!!");
-
-		/* set up our interrupt urb */
-		usb_fill_int_urb(port0->interrupt_in_urb, serial->dev,
-			 usb_rcvintpipe(serial->dev,
-				port->interrupt_in_endpointAddress),
-			 port0->interrupt_in_buffer,
-			 port0->interrupt_in_urb->transfer_buffer_length,
-			 mos7720_interrupt_callback, mos7720_port,
-			 port0->interrupt_in_urb->interval);
-
-		/* start interrupt read for this mos7720 this interrupt *
-		 * will continue as long as the mos7720 is connected    */
-		dbg("Submit URB over !!!");
-		response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL);
-		if (response)
-			dev_err(&port->dev,
-				"%s - Error %d submitting control urb\n",
-				__func__, response);
-	}
-
-	/* set up our bulk in urb */
-	usb_fill_bulk_urb(port->read_urb, serial->dev,
-			  usb_rcvbulkpipe(serial->dev,
-				port->bulk_in_endpointAddress),
-			  port->bulk_in_buffer,
-			  port->read_urb->transfer_buffer_length,
-			  mos7720_bulk_in_callback, mos7720_port);
 	response = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (response)
 		dev_err(&port->dev, "%s - Error %d submitting read urb\n",
@@ -640,7 +1161,6 @@
 {
 	struct usb_serial *serial;
 	struct moschip_port *mos7720_port;
-	char data;
 	int j;
 
 	dbg("mos7720_close:entering...");
@@ -673,13 +1193,10 @@
 	/* these commands must not be issued if the device has
 	 * been disconnected */
 	if (!serial->disconnected) {
-		data = 0x00;
-		send_mos_cmd(serial, MOS_WRITE,
-			port->number - port->serial->minor, 0x04, &data);
-
-		data = 0x00;
-		send_mos_cmd(serial, MOS_WRITE,
-			port->number - port->serial->minor, 0x01, &data);
+		write_mos_reg(serial, port->number - port->serial->minor,
+			      MCR, 0x00);
+		write_mos_reg(serial, port->number - port->serial->minor,
+			      IER, 0x00);
 	}
 	mutex_unlock(&serial->disc_mutex);
 	mos7720_port->open = 0;
@@ -708,8 +1225,8 @@
 		data = mos7720_port->shadowLCR & ~UART_LCR_SBC;
 
 	mos7720_port->shadowLCR  = data;
-	send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
-		     0x03, &data);
+	write_mos_reg(serial, port->number - port->serial->minor,
+		      LCR, mos7720_port->shadowLCR);
 
 	return;
 }
@@ -854,9 +1371,8 @@
 	/* if we are implementing RTS/CTS, toggle that line */
 	if (tty->termios->c_cflag & CRTSCTS) {
 		mos7720_port->shadowMCR &= ~UART_MCR_RTS;
-		status = send_mos_cmd(port->serial, MOS_WRITE,
-				      port->number - port->serial->minor,
-				      UART_MCR, &mos7720_port->shadowMCR);
+		write_mos_reg(port->serial, port->number - port->serial->minor,
+			      MCR, mos7720_port->shadowMCR);
 		if (status != 0)
 			return;
 	}
@@ -889,22 +1405,21 @@
 	/* if we are implementing RTS/CTS, toggle that line */
 	if (tty->termios->c_cflag & CRTSCTS) {
 		mos7720_port->shadowMCR |= UART_MCR_RTS;
-		status = send_mos_cmd(port->serial, MOS_WRITE,
-				      port->number - port->serial->minor,
-				      UART_MCR, &mos7720_port->shadowMCR);
+		write_mos_reg(port->serial, port->number - port->serial->minor,
+			      MCR, mos7720_port->shadowMCR);
 		if (status != 0)
 			return;
 	}
 }
 
+/* FIXME: this function does not work */
 static int set_higher_rates(struct moschip_port *mos7720_port,
 			    unsigned int baud)
 {
-	unsigned char data;
 	struct usb_serial_port *port;
 	struct usb_serial *serial;
 	int port_number;
-
+	enum mos_regs sp_reg;
 	if (mos7720_port == NULL)
 		return -EINVAL;
 
@@ -917,58 +1432,35 @@
 	dbg("Sending Setting Commands ..........");
 	port_number = port->number - port->serial->minor;
 
-	data = 0x000;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
-	data = 0x000;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
-	data = 0x0CF;
-	send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data);
-	data = 0x00b;
-	mos7720_port->shadowMCR  = data;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
-	data = 0x00b;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
-
-	data = 0x000;
-	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
-	data = 0x000;
-	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
-
+	write_mos_reg(serial, port_number, IER, 0x00);
+	write_mos_reg(serial, port_number, FCR, 0x00);
+	write_mos_reg(serial, port_number, FCR, 0xcf);
+	mos7720_port->shadowMCR = 0x0b;
+	write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
+	write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x00);
 
 	/***********************************************
 	 *              Set for higher rates           *
 	 ***********************************************/
-
-	data = baud * 0x10;
-	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
-
-	data = 0x003;
-	send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
-	data = 0x003;
-	send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
-
-	data = 0x02b;
-	mos7720_port->shadowMCR  = data;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
-	data = 0x02b;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+	/* writing baud rate verbatum into uart clock field clearly not right */
+	if (port_number == 0)
+		sp_reg = SP1_REG;
+	else
+		sp_reg = SP2_REG;
+	write_mos_reg(serial, dummy, sp_reg, baud * 0x10);
+	write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x03);
+	mos7720_port->shadowMCR = 0x2b;
+	write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
 
 	/***********************************************
 	 *              Set DLL/DLM
 	 ***********************************************/
-
-	data = mos7720_port->shadowLCR | UART_LCR_DLAB;
-	mos7720_port->shadowLCR  = data;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
-
-	data =  0x001; /* DLL */
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
-	data =  0x000; /* DLM */
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
-
-	data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
-	mos7720_port->shadowLCR  = data;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+	mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB;
+	write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
+	write_mos_reg(serial, port_number, DLL, 0x01);
+	write_mos_reg(serial, port_number, DLM, 0x00);
+	mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
+	write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
 
 	return 0;
 }
@@ -1056,7 +1548,6 @@
 	struct usb_serial *serial;
 	int divisor;
 	int status;
-	unsigned char data;
 	unsigned char number;
 
 	if (mos7720_port == NULL)
@@ -1078,21 +1569,16 @@
 	}
 
 	/* Enable access to divisor latch */
-	data = mos7720_port->shadowLCR | UART_LCR_DLAB;
-	mos7720_port->shadowLCR  = data;
-	send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data);
+	mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB;
+	write_mos_reg(serial, number, LCR, mos7720_port->shadowLCR);
 
 	/* Write the divisor */
-	data = ((unsigned char)(divisor & 0xff));
-	send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data);
-
-	data = ((unsigned char)((divisor & 0xff00) >> 8));
-	send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data);
+	write_mos_reg(serial, number, DLL, (__u8)(divisor & 0xff));
+	write_mos_reg(serial, number, DLM, (__u8)((divisor & 0xff00) >> 8));
 
 	/* Disable access to divisor latch */
-	data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
-	mos7720_port->shadowLCR = data;
-	send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data);
+	mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
+	write_mos_reg(serial, number, LCR, mos7720_port->shadowLCR);
 
 	return status;
 }
@@ -1117,7 +1603,6 @@
 	__u8 lStop;
 	int status;
 	int port_number;
-	char data;
 
 	if (mos7720_port == NULL)
 		return ;
@@ -1196,30 +1681,19 @@
 
 	/* Update the LCR with the correct value */
 	mos7720_port->shadowLCR &=
-			~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
+		~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
 	mos7720_port->shadowLCR |= (lData | lParity | lStop);
 
 
 	/* Disable Interrupts */
-	data = 0x00;
-	send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
-							UART_IER, &data);
-
-	data = 0x00;
-	send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
-
-	data = 0xcf;
-	send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
+	write_mos_reg(serial, port_number, IER, 0x00);
+	write_mos_reg(serial, port_number, FCR, 0x00);
+	write_mos_reg(serial, port_number, FCR, 0xcf);
 
 	/* Send the updated LCR value to the mos7720 */
-	data = mos7720_port->shadowLCR;
-	send_mos_cmd(serial, MOS_WRITE, port_number, UART_LCR, &data);
-
-	data = 0x00b;
-	mos7720_port->shadowMCR = data;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
-	data = 0x00b;
-	send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+	write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
+	mos7720_port->shadowMCR = 0x0b;
+	write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
 
 	/* set up the MCR register and send it to the mos7720 */
 	mos7720_port->shadowMCR = UART_MCR_OUT2;
@@ -1230,21 +1704,15 @@
 		mos7720_port->shadowMCR |= (UART_MCR_XONANY);
 		/* To set hardware flow control to the specified *
 		 * serial port, in SP1/2_CONTROL_REG             */
-		if (port->number) {
-			data = 0x001;
-			send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
-				     0x08, &data);
-		} else {
-			data = 0x002;
-			send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
-				     0x08, &data);
-		}
-	} else {
-		mos7720_port->shadowMCR &= ~(UART_MCR_XONANY);
-	}
+		if (port->number)
+			write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x01);
+		else
+			write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x02);
 
-	data = mos7720_port->shadowMCR;
-	send_mos_cmd(serial, MOS_WRITE, port_number, UART_MCR, &data);
+	} else
+		mos7720_port->shadowMCR &= ~(UART_MCR_XONANY);
+
+	write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
 
 	/* Determine divisor based on baud rate */
 	baud = tty_get_baud_rate(tty);
@@ -1257,8 +1725,7 @@
 	if (baud >= 230400) {
 		set_higher_rates(mos7720_port, baud);
 		/* Enable Interrupts */
-		data = 0x0c;
-		send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
+		write_mos_reg(serial, port_number, IER, 0x0c);
 		return;
 	}
 
@@ -1269,8 +1736,7 @@
 	if (cflag & CBAUD)
 		tty_encode_baud_rate(tty, baud, baud);
 	/* Enable Interrupts */
-	data = 0x0c;
-	send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
+	write_mos_reg(serial, port_number, IER, 0x0c);
 
 	if (port->read_urb->status != -EINPROGRESS) {
 		port->read_urb->dev = serial->dev;
@@ -1308,7 +1774,7 @@
 		return;
 	}
 
-	dbg("setting termios - ASPIRE");
+	dbg("%s\n", "setting termios - ASPIRE");
 
 	cflag = tty->termios->c_cflag;
 
@@ -1326,7 +1792,7 @@
 	change_port_settings(tty, mos7720_port, old_termios);
 
 	if (!port->read_urb) {
-		dbg("URB KILLED !!!!!");
+		dbg("%s", "URB KILLED !!!!!");
 		return;
 	}
 
@@ -1361,8 +1827,7 @@
 
 	count = mos7720_chars_in_buffer(tty);
 	if (count == 0) {
-		send_mos_cmd(port->serial, MOS_READ, port_number,
-							UART_LSR, &data);
+		read_mos_reg(port->serial, port_number, LSR, &data);
 		if ((data & (UART_LSR_TEMT | UART_LSR_THRE))
 					== (UART_LSR_TEMT | UART_LSR_THRE)) {
 			dbg("%s -- Empty", __func__);
@@ -1400,13 +1865,11 @@
 }
 
 static int mos7720_tiocmset(struct tty_struct *tty, struct file *file,
-					unsigned int set, unsigned int clear)
+			    unsigned int set, unsigned int clear)
 {
 	struct usb_serial_port *port = tty->driver_data;
 	struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
 	unsigned int mcr ;
-	unsigned char lmcr;
-
 	dbg("%s - port %d", __func__, port->number);
 	dbg("he was at tiocmget");
 
@@ -1427,10 +1890,8 @@
 		mcr &= ~UART_MCR_LOOP;
 
 	mos7720_port->shadowMCR = mcr;
-	lmcr = mos7720_port->shadowMCR;
-
-	send_mos_cmd(port->serial, MOS_WRITE,
-		port->number - port->serial->minor, UART_MCR, &lmcr);
+	write_mos_reg(port->serial, port->number - port->serial->minor,
+		      MCR, mos7720_port->shadowMCR);
 
 	return 0;
 }
@@ -1440,7 +1901,6 @@
 {
 	unsigned int mcr ;
 	unsigned int arg;
-	unsigned char data;
 
 	struct usb_serial_port *port;
 
@@ -1475,10 +1935,8 @@
 	}
 
 	mos7720_port->shadowMCR = mcr;
-
-	data = mos7720_port->shadowMCR;
-	send_mos_cmd(port->serial, MOS_WRITE,
-		     port->number - port->serial->minor, UART_MCR, &data);
+	write_mos_reg(port->serial, port->number - port->serial->minor,
+		      MCR, mos7720_port->shadowMCR);
 
 	return 0;
 }
@@ -1590,12 +2048,12 @@
 
 static int mos7720_startup(struct usb_serial *serial)
 {
-	struct moschip_serial *mos7720_serial;
 	struct moschip_port *mos7720_port;
 	struct usb_device *dev;
 	int i;
 	char data;
 	u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
+	int ret_val;
 
 	dbg("%s: Entering ..........", __func__);
 
@@ -1606,15 +2064,6 @@
 
 	dev = serial->dev;
 
-	/* create our private serial structure */
-	mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL);
-	if (mos7720_serial == NULL) {
-		dev_err(&dev->dev, "%s - Out of memory\n", __func__);
-		return -ENOMEM;
-	}
-
-	usb_set_serial_data(serial, mos7720_serial);
-
 	/*
 	 * The 7715 uses the first bulk in/out endpoint pair for the parallel
 	 * port, and the second for the serial port.  Because the usbserial core
@@ -1638,16 +2087,12 @@
 		serial->port[1]->interrupt_in_buffer = NULL;
 	}
 
-	/* we set up the pointers to the endpoints in the mos7720_open *
-	 * function, as the structures aren't created yet.             */
 
-	/* set up port private structures */
+	/* set up serial port private structures */
 	for (i = 0; i < serial->num_ports; ++i) {
 		mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
 		if (mos7720_port == NULL) {
 			dev_err(&dev->dev, "%s - Out of memory\n", __func__);
-			usb_set_serial_data(serial, NULL);
-			kfree(mos7720_serial);
 			return -ENOMEM;
 		}
 
@@ -1669,12 +2114,22 @@
 	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 			(__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5*HZ);
 
-	/* LSR For Port 1 */
-	send_mos_cmd(serial, MOS_READ, 0x00, UART_LSR, &data);
-	dbg("LSR:%x", data);
+	/* start the interrupt urb */
+	ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
+	if (ret_val)
+		dev_err(&dev->dev,
+			"%s - Error %d submitting control urb\n",
+			__func__, ret_val);
 
-	/* LSR For Port 2 */
-	send_mos_cmd(serial, MOS_READ, 0x01, UART_LSR, &data);
+#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
+	if (product == MOSCHIP_DEVICE_ID_7715) {
+		ret_val = mos7715_parport_init(serial);
+		if (ret_val < 0)
+			return ret_val;
+	}
+#endif
+	/* LSR For Port 1 */
+	read_mos_reg(serial, 0, LSR, &data);
 	dbg("LSR:%x", data);
 
 	return 0;
@@ -1684,12 +2139,47 @@
 {
 	int i;
 
+#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
+	/* close the parallel port */
+
+	if (le16_to_cpu(serial->dev->descriptor.idProduct)
+	    == MOSCHIP_DEVICE_ID_7715) {
+		struct urbtracker *urbtrack;
+		unsigned long flags;
+		struct mos7715_parport *mos_parport =
+			usb_get_serial_data(serial);
+
+		/* prevent NULL ptr dereference in port callbacks */
+		spin_lock(&release_lock);
+		mos_parport->pp->private_data = NULL;
+		spin_unlock(&release_lock);
+
+		/* wait for synchronous usb calls to return */
+		if (mos_parport->msg_pending)
+			wait_for_completion_timeout(&mos_parport->syncmsg_compl,
+						    MOS_WDR_TIMEOUT);
+
+		parport_remove_port(mos_parport->pp);
+		usb_set_serial_data(serial, NULL);
+		mos_parport->serial = NULL;
+
+		/* if tasklet currently scheduled, wait for it to complete */
+		tasklet_kill(&mos_parport->urb_tasklet);
+
+		/* unlink any urbs sent by the tasklet  */
+		spin_lock_irqsave(&mos_parport->listlock, flags);
+		list_for_each_entry(urbtrack,
+				    &mos_parport->active_urbs,
+				    urblist_entry)
+			usb_unlink_urb(urbtrack->urb);
+		spin_unlock_irqrestore(&mos_parport->listlock, flags);
+
+		kref_put(&mos_parport->ref_count, destroy_mos_parport);
+	}
+#endif
 	/* free private structure allocated for serial port */
 	for (i = 0; i < serial->num_ports; ++i)
 		kfree(usb_get_serial_port_data(serial->port[i]));
-
-	/* free private structure allocated for serial device */
-	kfree(usb_get_serial_data(serial));
 }
 
 static struct usb_driver usb_driver = {
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 2fda1c0..f8424d1 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -26,7 +26,6 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 84d0eda..e280ad8 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -42,35 +42,14 @@
 #include <linux/bitops.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
+#include "usb-wwan.h"
 
 /* Function prototypes */
 static int  option_probe(struct usb_serial *serial,
 			const struct usb_device_id *id);
-static int  option_open(struct tty_struct *tty, struct usb_serial_port *port);
-static void option_close(struct usb_serial_port *port);
-static void option_dtr_rts(struct usb_serial_port *port, int on);
-
-static int  option_startup(struct usb_serial *serial);
-static void option_disconnect(struct usb_serial *serial);
-static void option_release(struct usb_serial *serial);
-static int  option_write_room(struct tty_struct *tty);
-
+static int option_send_setup(struct usb_serial_port *port);
 static void option_instat_callback(struct urb *urb);
 
-static int option_write(struct tty_struct *tty, struct usb_serial_port *port,
-			const unsigned char *buf, int count);
-static int  option_chars_in_buffer(struct tty_struct *tty);
-static void option_set_termios(struct tty_struct *tty,
-			struct usb_serial_port *port, struct ktermios *old);
-static int  option_tiocmget(struct tty_struct *tty, struct file *file);
-static int  option_tiocmset(struct tty_struct *tty, struct file *file,
-				unsigned int set, unsigned int clear);
-static int  option_send_setup(struct usb_serial_port *port);
-#ifdef CONFIG_PM
-static int  option_suspend(struct usb_serial *serial, pm_message_t message);
-static int  option_resume(struct usb_serial *serial);
-#endif
-
 /* Vendor and product IDs */
 #define OPTION_VENDOR_ID			0x0AF0
 #define OPTION_PRODUCT_COLT			0x5000
@@ -380,6 +359,10 @@
 
 #define CINTERION_VENDOR_ID			0x0681
 
+/* Olivetti products */
+#define OLIVETTI_VENDOR_ID			0x0b3c
+#define OLIVETTI_PRODUCT_OLICARD100		0xc000
+
 /* some devices interfaces need special handling due to a number of reasons */
 enum option_blacklist_reason {
 		OPTION_BLACKLIST_NONE = 0,
@@ -675,6 +658,180 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0160, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1060, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1061, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1062, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1063, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1064, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1065, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1066, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1067, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1068, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1069, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1070, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1071, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1072, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1073, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1074, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1075, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1076, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1077, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1078, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1079, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1080, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1081, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1082, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1083, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1084, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1085, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1086, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1087, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1088, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1089, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1090, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1091, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1092, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1093, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1094, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1095, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1096, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1097, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1098, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1099, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1100, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1101, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1102, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1103, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1104, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1105, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1106, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1107, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1108, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1109, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1110, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1111, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1112, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1113, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1114, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1115, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1116, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1117, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1118, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1119, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1120, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1121, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1122, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1123, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1124, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1125, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1126, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1127, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1128, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1129, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1130, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1131, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1132, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1133, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1134, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1135, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1136, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1137, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1138, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1139, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1140, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1141, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1142, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1143, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1144, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1145, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1146, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1147, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1148, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1149, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1150, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1151, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1152, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1153, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1154, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1155, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1156, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1157, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1158, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1159, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1160, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1161, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1162, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1163, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1164, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1165, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1166, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1167, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1168, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1169, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1170, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1244, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1245, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1246, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1247, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1248, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1249, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1250, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1251, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1252, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1253, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1254, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1255, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1256, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1257, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1258, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1259, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1260, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1261, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1262, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1263, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1264, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1265, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1266, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1267, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1268, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1269, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1271, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1274, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1275, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1276, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1277, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1278, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1279, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1280, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1281, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1282, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1283, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1284, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1285, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1286, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1287, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1288, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1289, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1290, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1291, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1292, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1293, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1294, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1295, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1296, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1297, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0027, 0xff, 0xff, 0xff) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) },
@@ -726,6 +883,8 @@
 	{ USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)},
 
 	{ USB_DEVICE(CINTERION_VENDOR_ID, 0x0047) },
+
+	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
 	{ } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
@@ -757,22 +916,22 @@
 	.id_table          = option_ids,
 	.num_ports         = 1,
 	.probe             = option_probe,
-	.open              = option_open,
-	.close             = option_close,
-	.dtr_rts	   = option_dtr_rts,
-	.write             = option_write,
-	.write_room        = option_write_room,
-	.chars_in_buffer   = option_chars_in_buffer,
-	.set_termios       = option_set_termios,
-	.tiocmget          = option_tiocmget,
-	.tiocmset          = option_tiocmset,
-	.attach            = option_startup,
-	.disconnect        = option_disconnect,
-	.release           = option_release,
+	.open              = usb_wwan_open,
+	.close             = usb_wwan_close,
+	.dtr_rts	   = usb_wwan_dtr_rts,
+	.write             = usb_wwan_write,
+	.write_room        = usb_wwan_write_room,
+	.chars_in_buffer   = usb_wwan_chars_in_buffer,
+	.set_termios       = usb_wwan_set_termios,
+	.tiocmget          = usb_wwan_tiocmget,
+	.tiocmset          = usb_wwan_tiocmset,
+	.attach            = usb_wwan_startup,
+	.disconnect        = usb_wwan_disconnect,
+	.release           = usb_wwan_release,
 	.read_int_callback = option_instat_callback,
 #ifdef CONFIG_PM
-	.suspend           = option_suspend,
-	.resume            = option_resume,
+	.suspend           = usb_wwan_suspend,
+	.resume            = usb_wwan_resume,
 #endif
 };
 
@@ -785,13 +944,6 @@
 #define IN_BUFLEN 4096
 #define OUT_BUFLEN 4096
 
-struct option_intf_private {
-	spinlock_t susp_lock;
-	unsigned int suspended:1;
-	int in_flight;
-	struct option_blacklist_info *blacklist_info;
-};
-
 struct option_port_private {
 	/* Input endpoints and buffer for this port */
 	struct urb *in_urbs[N_IN_URB];
@@ -848,8 +1000,7 @@
 static int option_probe(struct usb_serial *serial,
 			const struct usb_device_id *id)
 {
-	struct option_intf_private *data;
-
+	struct usb_wwan_intf_private *data;
 	/* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */
 	if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID &&
 		serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 &&
@@ -862,11 +1013,13 @@
 		serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff)
 		return -ENODEV;
 
-	data = serial->private = kzalloc(sizeof(struct option_intf_private), GFP_KERNEL);
+	data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
+
 	if (!data)
 		return -ENOMEM;
+	data->send_setup = option_send_setup;
 	spin_lock_init(&data->susp_lock);
-	data->blacklist_info = (struct option_blacklist_info*) id->driver_info;
+	data->private = (void *)id->driver_info;
 	return 0;
 }
 
@@ -887,194 +1040,6 @@
 	return OPTION_BLACKLIST_NONE;
 }
 
-static void option_set_termios(struct tty_struct *tty,
-		struct usb_serial_port *port, struct ktermios *old_termios)
-{
-	dbg("%s", __func__);
-	/* Doesn't support option setting */
-	tty_termios_copy_hw(tty->termios, old_termios);
-	option_send_setup(port);
-}
-
-static int option_tiocmget(struct tty_struct *tty, struct file *file)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	unsigned int value;
-	struct option_port_private *portdata;
-
-	portdata = usb_get_serial_port_data(port);
-
-	value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
-		((portdata->dtr_state) ? TIOCM_DTR : 0) |
-		((portdata->cts_state) ? TIOCM_CTS : 0) |
-		((portdata->dsr_state) ? TIOCM_DSR : 0) |
-		((portdata->dcd_state) ? TIOCM_CAR : 0) |
-		((portdata->ri_state) ? TIOCM_RNG : 0);
-
-	return value;
-}
-
-static int option_tiocmset(struct tty_struct *tty, struct file *file,
-			unsigned int set, unsigned int clear)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct option_port_private *portdata;
-
-	portdata = usb_get_serial_port_data(port);
-
-	/* FIXME: what locks portdata fields ? */
-	if (set & TIOCM_RTS)
-		portdata->rts_state = 1;
-	if (set & TIOCM_DTR)
-		portdata->dtr_state = 1;
-
-	if (clear & TIOCM_RTS)
-		portdata->rts_state = 0;
-	if (clear & TIOCM_DTR)
-		portdata->dtr_state = 0;
-	return option_send_setup(port);
-}
-
-/* Write */
-static int option_write(struct tty_struct *tty, struct usb_serial_port *port,
-			const unsigned char *buf, int count)
-{
-	struct option_port_private *portdata;
-	struct option_intf_private *intfdata;
-	int i;
-	int left, todo;
-	struct urb *this_urb = NULL; /* spurious */
-	int err;
-	unsigned long flags;
-
-	portdata = usb_get_serial_port_data(port);
-	intfdata = port->serial->private;
-
-	dbg("%s: write (%d chars)", __func__, count);
-
-	i = 0;
-	left = count;
-	for (i = 0; left > 0 && i < N_OUT_URB; i++) {
-		todo = left;
-		if (todo > OUT_BUFLEN)
-			todo = OUT_BUFLEN;
-
-		this_urb = portdata->out_urbs[i];
-		if (test_and_set_bit(i, &portdata->out_busy)) {
-			if (time_before(jiffies,
-					portdata->tx_start_time[i] + 10 * HZ))
-				continue;
-			usb_unlink_urb(this_urb);
-			continue;
-		}
-		dbg("%s: endpoint %d buf %d", __func__,
-			usb_pipeendpoint(this_urb->pipe), i);
-
-		err = usb_autopm_get_interface_async(port->serial->interface);
-		if (err < 0)
-			break;
-
-		/* send the data */
-		memcpy(this_urb->transfer_buffer, buf, todo);
-		this_urb->transfer_buffer_length = todo;
-
-		spin_lock_irqsave(&intfdata->susp_lock, flags);
-		if (intfdata->suspended) {
-			usb_anchor_urb(this_urb, &portdata->delayed);
-			spin_unlock_irqrestore(&intfdata->susp_lock, flags);
-		} else {
-			intfdata->in_flight++;
-			spin_unlock_irqrestore(&intfdata->susp_lock, flags);
-			err = usb_submit_urb(this_urb, GFP_ATOMIC);
-			if (err) {
-				dbg("usb_submit_urb %p (write bulk) failed "
-					"(%d)", this_urb, err);
-				clear_bit(i, &portdata->out_busy);
-				spin_lock_irqsave(&intfdata->susp_lock, flags);
-				intfdata->in_flight--;
-				spin_unlock_irqrestore(&intfdata->susp_lock, flags);
-				continue;
-			}
-		}
-
-		portdata->tx_start_time[i] = jiffies;
-		buf += todo;
-		left -= todo;
-	}
-
-	count -= left;
-	dbg("%s: wrote (did %d)", __func__, count);
-	return count;
-}
-
-static void option_indat_callback(struct urb *urb)
-{
-	int err;
-	int endpoint;
-	struct usb_serial_port *port;
-	struct tty_struct *tty;
-	unsigned char *data = urb->transfer_buffer;
-	int status = urb->status;
-
-	dbg("%s: %p", __func__, urb);
-
-	endpoint = usb_pipeendpoint(urb->pipe);
-	port =  urb->context;
-
-	if (status) {
-		dbg("%s: nonzero status: %d on endpoint %02x.",
-		    __func__, status, endpoint);
-	} else {
-		tty = tty_port_tty_get(&port->port);
-		if (urb->actual_length) {
-			tty_insert_flip_string(tty, data, urb->actual_length);
-			tty_flip_buffer_push(tty);
-		} else 
-			dbg("%s: empty read urb received", __func__);
-		tty_kref_put(tty);
-
-		/* Resubmit urb so we continue receiving */
-		if (status != -ESHUTDOWN) {
-			err = usb_submit_urb(urb, GFP_ATOMIC);
-			if (err && err != -EPERM)
-				printk(KERN_ERR "%s: resubmit read urb failed. "
-					"(%d)", __func__, err);
-			else
-				usb_mark_last_busy(port->serial->dev);
-		}
-
-	}
-	return;
-}
-
-static void option_outdat_callback(struct urb *urb)
-{
-	struct usb_serial_port *port;
-	struct option_port_private *portdata;
-	struct option_intf_private *intfdata;
-	int i;
-
-	dbg("%s", __func__);
-
-	port =  urb->context;
-	intfdata = port->serial->private;
-
-	usb_serial_port_softint(port);
-	usb_autopm_put_interface_async(port->serial->interface);
-	portdata = usb_get_serial_port_data(port);
-	spin_lock(&intfdata->susp_lock);
-	intfdata->in_flight--;
-	spin_unlock(&intfdata->susp_lock);
-
-	for (i = 0; i < N_OUT_URB; ++i) {
-		if (portdata->out_urbs[i] == urb) {
-			smp_mb__before_clear_bit();
-			clear_bit(i, &portdata->out_busy);
-			break;
-		}
-	}
-}
-
 static void option_instat_callback(struct urb *urb)
 {
 	int err;
@@ -1131,183 +1096,6 @@
 	}
 }
 
-static int option_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct option_port_private *portdata;
-	int i;
-	int data_len = 0;
-	struct urb *this_urb;
-
-	portdata = usb_get_serial_port_data(port);
-
-	for (i = 0; i < N_OUT_URB; i++) {
-		this_urb = portdata->out_urbs[i];
-		if (this_urb && !test_bit(i, &portdata->out_busy))
-			data_len += OUT_BUFLEN;
-	}
-
-	dbg("%s: %d", __func__, data_len);
-	return data_len;
-}
-
-static int option_chars_in_buffer(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct option_port_private *portdata;
-	int i;
-	int data_len = 0;
-	struct urb *this_urb;
-
-	portdata = usb_get_serial_port_data(port);
-
-	for (i = 0; i < N_OUT_URB; i++) {
-		this_urb = portdata->out_urbs[i];
-		/* FIXME: This locking is insufficient as this_urb may
-		   go unused during the test */
-		if (this_urb && test_bit(i, &portdata->out_busy))
-			data_len += this_urb->transfer_buffer_length;
-	}
-	dbg("%s: %d", __func__, data_len);
-	return data_len;
-}
-
-static int option_open(struct tty_struct *tty, struct usb_serial_port *port)
-{
-	struct option_port_private *portdata;
-	struct option_intf_private *intfdata;
-	struct usb_serial *serial = port->serial;
-	int i, err;
-	struct urb *urb;
-
-	portdata = usb_get_serial_port_data(port);
-	intfdata = serial->private;
-
-	dbg("%s", __func__);
-
-	/* Start reading from the IN endpoint */
-	for (i = 0; i < N_IN_URB; i++) {
-		urb = portdata->in_urbs[i];
-		if (!urb)
-			continue;
-		err = usb_submit_urb(urb, GFP_KERNEL);
-		if (err) {
-			dbg("%s: submit urb %d failed (%d) %d",
-				__func__, i, err,
-				urb->transfer_buffer_length);
-		}
-	}
-
-	option_send_setup(port);
-
-	serial->interface->needs_remote_wakeup = 1;
-	spin_lock_irq(&intfdata->susp_lock);
-	portdata->opened = 1;
-	spin_unlock_irq(&intfdata->susp_lock);
-	usb_autopm_put_interface(serial->interface);
-
-	return 0;
-}
-
-static void option_dtr_rts(struct usb_serial_port *port, int on)
-{
-	struct usb_serial *serial = port->serial;
-	struct option_port_private *portdata;
-
-	dbg("%s", __func__);
-	portdata = usb_get_serial_port_data(port);
-	mutex_lock(&serial->disc_mutex);
-	portdata->rts_state = on;
-	portdata->dtr_state = on;
-	if (serial->dev)
-		option_send_setup(port);
-	mutex_unlock(&serial->disc_mutex);
-}
-
-
-static void option_close(struct usb_serial_port *port)
-{
-	int i;
-	struct usb_serial *serial = port->serial;
-	struct option_port_private *portdata;
-	struct option_intf_private *intfdata = port->serial->private;
-
-	dbg("%s", __func__);
-	portdata = usb_get_serial_port_data(port);
-
-	if (serial->dev) {
-		/* Stop reading/writing urbs */
-		spin_lock_irq(&intfdata->susp_lock);
-		portdata->opened = 0;
-		spin_unlock_irq(&intfdata->susp_lock);
-
-		for (i = 0; i < N_IN_URB; i++)
-			usb_kill_urb(portdata->in_urbs[i]);
-		for (i = 0; i < N_OUT_URB; i++)
-			usb_kill_urb(portdata->out_urbs[i]);
-		usb_autopm_get_interface(serial->interface);
-		serial->interface->needs_remote_wakeup = 0;
-	}
-}
-
-/* Helper functions used by option_setup_urbs */
-static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
-		int dir, void *ctx, char *buf, int len,
-		void (*callback)(struct urb *))
-{
-	struct urb *urb;
-
-	if (endpoint == -1)
-		return NULL;		/* endpoint not needed */
-
-	urb = usb_alloc_urb(0, GFP_KERNEL);		/* No ISO */
-	if (urb == NULL) {
-		dbg("%s: alloc for endpoint %d failed.", __func__, endpoint);
-		return NULL;
-	}
-
-		/* Fill URB using supplied data. */
-	usb_fill_bulk_urb(urb, serial->dev,
-		      usb_sndbulkpipe(serial->dev, endpoint) | dir,
-		      buf, len, callback, ctx);
-
-	return urb;
-}
-
-/* Setup urbs */
-static void option_setup_urbs(struct usb_serial *serial)
-{
-	int i, j;
-	struct usb_serial_port *port;
-	struct option_port_private *portdata;
-
-	dbg("%s", __func__);
-
-	for (i = 0; i < serial->num_ports; i++) {
-		port = serial->port[i];
-		portdata = usb_get_serial_port_data(port);
-
-		/* Do indat endpoints first */
-		for (j = 0; j < N_IN_URB; ++j) {
-			portdata->in_urbs[j] = option_setup_urb(serial,
-					port->bulk_in_endpointAddress,
-					USB_DIR_IN, port,
-					portdata->in_buffer[j],
-					IN_BUFLEN, option_indat_callback);
-		}
-
-		/* outdat endpoints */
-		for (j = 0; j < N_OUT_URB; ++j) {
-			portdata->out_urbs[j] = option_setup_urb(serial,
-					port->bulk_out_endpointAddress,
-					USB_DIR_OUT, port,
-					portdata->out_buffer[j],
-					OUT_BUFLEN, option_outdat_callback);
-		}
-	}
-}
-
-
 /** send RTS/DTR state to the port.
  *
  * This is exactly the same as SET_CONTROL_LINE_STATE from the PSTN
@@ -1316,15 +1104,16 @@
 static int option_send_setup(struct usb_serial_port *port)
 {
 	struct usb_serial *serial = port->serial;
-	struct option_intf_private *intfdata =
-		(struct option_intf_private *) serial->private;
+	struct usb_wwan_intf_private *intfdata =
+		(struct usb_wwan_intf_private *) serial->private;
 	struct option_port_private *portdata;
 	int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
 	int val = 0;
 	dbg("%s", __func__);
 
-	if (is_blacklisted(ifNum, intfdata->blacklist_info) ==
-						OPTION_BLACKLIST_SENDSETUP) {
+	if (is_blacklisted(ifNum,
+			   (struct option_blacklist_info *) intfdata->private)
+	    == OPTION_BLACKLIST_SENDSETUP) {
 		dbg("No send_setup on blacklisted interface #%d\n", ifNum);
 		return -EIO;
 	}
@@ -1341,224 +1130,6 @@
 		0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT);
 }
 
-static int option_startup(struct usb_serial *serial)
-{
-	int i, j, err;
-	struct usb_serial_port *port;
-	struct option_port_private *portdata;
-	u8 *buffer;
-
-	dbg("%s", __func__);
-
-	/* Now setup per port private data */
-	for (i = 0; i < serial->num_ports; i++) {
-		port = serial->port[i];
-		portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
-		if (!portdata) {
-			dbg("%s: kmalloc for option_port_private (%d) failed!.",
-					__func__, i);
-			return 1;
-		}
-		init_usb_anchor(&portdata->delayed);
-
-		for (j = 0; j < N_IN_URB; j++) {
-			buffer = (u8 *)__get_free_page(GFP_KERNEL);
-			if (!buffer)
-				goto bail_out_error;
-			portdata->in_buffer[j] = buffer;
-		}
-
-		for (j = 0; j < N_OUT_URB; j++) {
-			buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL);
-			if (!buffer)
-				goto bail_out_error2;
-			portdata->out_buffer[j] = buffer;
-		}
-
-		usb_set_serial_port_data(port, portdata);
-
-		if (!port->interrupt_in_urb)
-			continue;
-		err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
-		if (err)
-			dbg("%s: submit irq_in urb failed %d",
-				__func__, err);
-	}
-	option_setup_urbs(serial);
-	return 0;
-
-bail_out_error2:
-	for (j = 0; j < N_OUT_URB; j++)
-		kfree(portdata->out_buffer[j]);
-bail_out_error:
-	for (j = 0; j < N_IN_URB; j++)
-		if (portdata->in_buffer[j])
-			free_page((unsigned long)portdata->in_buffer[j]);
-	kfree(portdata);
-	return 1;
-}
-
-static void stop_read_write_urbs(struct usb_serial *serial)
-{
-	int i, j;
-	struct usb_serial_port *port;
-	struct option_port_private *portdata;
-
-	/* Stop reading/writing urbs */
-	for (i = 0; i < serial->num_ports; ++i) {
-		port = serial->port[i];
-		portdata = usb_get_serial_port_data(port);
-		for (j = 0; j < N_IN_URB; j++)
-			usb_kill_urb(portdata->in_urbs[j]);
-		for (j = 0; j < N_OUT_URB; j++)
-			usb_kill_urb(portdata->out_urbs[j]);
-	}
-}
-
-static void option_disconnect(struct usb_serial *serial)
-{
-	dbg("%s", __func__);
-
-	stop_read_write_urbs(serial);
-}
-
-static void option_release(struct usb_serial *serial)
-{
-	int i, j;
-	struct usb_serial_port *port;
-	struct option_port_private *portdata;
-
-	dbg("%s", __func__);
-
-	/* Now free them */
-	for (i = 0; i < serial->num_ports; ++i) {
-		port = serial->port[i];
-		portdata = usb_get_serial_port_data(port);
-
-		for (j = 0; j < N_IN_URB; j++) {
-			if (portdata->in_urbs[j]) {
-				usb_free_urb(portdata->in_urbs[j]);
-				free_page((unsigned long)
-					portdata->in_buffer[j]);
-				portdata->in_urbs[j] = NULL;
-			}
-		}
-		for (j = 0; j < N_OUT_URB; j++) {
-			if (portdata->out_urbs[j]) {
-				usb_free_urb(portdata->out_urbs[j]);
-				kfree(portdata->out_buffer[j]);
-				portdata->out_urbs[j] = NULL;
-			}
-		}
-	}
-
-	/* Now free per port private data */
-	for (i = 0; i < serial->num_ports; i++) {
-		port = serial->port[i];
-		kfree(usb_get_serial_port_data(port));
-	}
-}
-
-#ifdef CONFIG_PM
-static int option_suspend(struct usb_serial *serial, pm_message_t message)
-{
-	struct option_intf_private *intfdata = serial->private;
-	int b;
-
-	dbg("%s entered", __func__);
-
-	if (message.event & PM_EVENT_AUTO) {
-		spin_lock_irq(&intfdata->susp_lock);
-		b = intfdata->in_flight;
-		spin_unlock_irq(&intfdata->susp_lock);
-
-		if (b)
-			return -EBUSY;
-	}
-
-	spin_lock_irq(&intfdata->susp_lock);
-	intfdata->suspended = 1;
-	spin_unlock_irq(&intfdata->susp_lock);
-	stop_read_write_urbs(serial);
-
-	return 0;
-}
-
-static void play_delayed(struct usb_serial_port *port)
-{
-	struct option_intf_private *data;
-	struct option_port_private *portdata;
-	struct urb *urb;
-	int err;
-
-	portdata = usb_get_serial_port_data(port);
-	data = port->serial->private;
-	while ((urb = usb_get_from_anchor(&portdata->delayed))) {
-		err = usb_submit_urb(urb, GFP_ATOMIC);
-		if (!err)
-			data->in_flight++;
-	}
-}
-
-static int option_resume(struct usb_serial *serial)
-{
-	int i, j;
-	struct usb_serial_port *port;
-	struct option_intf_private *intfdata = serial->private;
-	struct option_port_private *portdata;
-	struct urb *urb;
-	int err = 0;
-
-	dbg("%s entered", __func__);
-	/* get the interrupt URBs resubmitted unconditionally */
-	for (i = 0; i < serial->num_ports; i++) {
-		port = serial->port[i];
-		if (!port->interrupt_in_urb) {
-			dbg("%s: No interrupt URB for port %d", __func__, i);
-			continue;
-		}
-		err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
-		dbg("Submitted interrupt URB for port %d (result %d)", i, err);
-		if (err < 0) {
-			err("%s: Error %d for interrupt URB of port%d",
-				 __func__, err, i);
-			goto err_out;
-		}
-	}
-
-	for (i = 0; i < serial->num_ports; i++) {
-		/* walk all ports */
-		port = serial->port[i];
-		portdata = usb_get_serial_port_data(port);
-
-		/* skip closed ports */
-		spin_lock_irq(&intfdata->susp_lock);
-		if (!portdata->opened) {
-			spin_unlock_irq(&intfdata->susp_lock);
-			continue;
-		}
-
-		for (j = 0; j < N_IN_URB; j++) {
-			urb = portdata->in_urbs[j];
-			err = usb_submit_urb(urb, GFP_ATOMIC);
-			if (err < 0) {
-				err("%s: Error %d for bulk URB %d",
-					 __func__, err, i);
-				spin_unlock_irq(&intfdata->susp_lock);
-				goto err_out;
-			}
-		}
-		play_delayed(port);
-		spin_unlock_irq(&intfdata->susp_lock);
-	}
-	spin_lock_irq(&intfdata->susp_lock);
-	intfdata->suspended = 0;
-	spin_unlock_irq(&intfdata->susp_lock);
-err_out:
-	return err;
-}
-#endif
-
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index deeacde..e199b0f 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -51,12 +51,13 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 #include <linux/uaccess.h>
+#include <linux/kfifo.h>
 #include "oti6858.h"
 
 #define OTI6858_DESCRIPTION \
 	"Ours Technology Inc. OTi-6858 USB to serial adapter driver"
 #define OTI6858_AUTHOR "Tomasz Michal Lukaszewski <FIXME@FIXME>"
-#define OTI6858_VERSION "0.1"
+#define OTI6858_VERSION "0.2"
 
 static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(OTI6858_VENDOR_ID, OTI6858_PRODUCT_ID) },
@@ -75,18 +76,6 @@
 
 static int debug;
 
-
-/* buffering code, copied from pl2303 driver */
-#define PL2303_BUF_SIZE		1024
-#define PL2303_TMP_BUF_SIZE	1024
-
-struct oti6858_buf {
-	unsigned int	buf_size;
-	char		*buf_buf;
-	char		*buf_get;
-	char		*buf_put;
-};
-
 /* requests */
 #define	OTI6858_REQ_GET_STATUS		(USB_DIR_IN | USB_TYPE_VENDOR | 0x00)
 #define	OTI6858_REQ_T_GET_STATUS	0x01
@@ -161,18 +150,6 @@
 static int oti6858_startup(struct usb_serial *serial);
 static void oti6858_release(struct usb_serial *serial);
 
-/* functions operating on buffers */
-static struct oti6858_buf *oti6858_buf_alloc(unsigned int size);
-static void oti6858_buf_free(struct oti6858_buf *pb);
-static void oti6858_buf_clear(struct oti6858_buf *pb);
-static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb);
-static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb);
-static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf,
-					unsigned int count);
-static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf,
-					unsigned int count);
-
-
 /* device info */
 static struct usb_serial_driver oti6858_device = {
 	.driver = {
@@ -201,7 +178,6 @@
 struct oti6858_private {
 	spinlock_t lock;
 
-	struct oti6858_buf *buf;
 	struct oti6858_control_pkt status;
 
 	struct {
@@ -295,7 +271,7 @@
 	}
 }
 
-void send_data(struct work_struct *work)
+static void send_data(struct work_struct *work)
 {
 	struct oti6858_private *priv = container_of(work,
 			struct oti6858_private, delayed_write_work.work);
@@ -314,9 +290,12 @@
 		return;
 	}
 	priv->flags.write_urb_in_use = 1;
-
-	count = oti6858_buf_data_avail(priv->buf);
 	spin_unlock_irqrestore(&priv->lock, flags);
+
+	spin_lock_irqsave(&port->lock, flags);
+	count = kfifo_len(&port->write_fifo);
+	spin_unlock_irqrestore(&port->lock, flags);
+
 	if (count > port->bulk_out_size)
 		count = port->bulk_out_size;
 
@@ -350,10 +329,9 @@
 		return;
 	}
 
-	spin_lock_irqsave(&priv->lock, flags);
-	oti6858_buf_get(priv->buf, port->write_urb->transfer_buffer, count);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
+	count = kfifo_out_locked(&port->write_fifo,
+					port->write_urb->transfer_buffer,
+					count, &port->lock);
 	port->write_urb->transfer_buffer_length = count;
 	port->write_urb->dev = port->serial->dev;
 	result = usb_submit_urb(port->write_urb, GFP_NOIO);
@@ -376,11 +354,6 @@
 		priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL);
 		if (!priv)
 			break;
-		priv->buf = oti6858_buf_alloc(PL2303_BUF_SIZE);
-		if (priv->buf == NULL) {
-			kfree(priv);
-			break;
-		}
 
 		spin_lock_init(&priv->lock);
 		init_waitqueue_head(&priv->intr_wait);
@@ -397,7 +370,6 @@
 
 	for (--i; i >= 0; --i) {
 		priv = usb_get_serial_port_data(serial->port[i]);
-		oti6858_buf_free(priv->buf);
 		kfree(priv);
 		usb_set_serial_port_data(serial->port[i], NULL);
 	}
@@ -407,17 +379,12 @@
 static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port,
 			const unsigned char *buf, int count)
 {
-	struct oti6858_private *priv = usb_get_serial_port_data(port);
-	unsigned long flags;
-
 	dbg("%s(port = %d, count = %d)", __func__, port->number, count);
 
 	if (!count)
 		return count;
 
-	spin_lock_irqsave(&priv->lock, flags);
-	count = oti6858_buf_put(priv->buf, buf, count);
-	spin_unlock_irqrestore(&priv->lock, flags);
+	count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock);
 
 	return count;
 }
@@ -425,15 +392,14 @@
 static int oti6858_write_room(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	struct oti6858_private *priv = usb_get_serial_port_data(port);
 	int room = 0;
 	unsigned long flags;
 
 	dbg("%s(port = %d)", __func__, port->number);
 
-	spin_lock_irqsave(&priv->lock, flags);
-	room = oti6858_buf_space_avail(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
+	spin_lock_irqsave(&port->lock, flags);
+	room = kfifo_avail(&port->write_fifo);
+	spin_unlock_irqrestore(&port->lock, flags);
 
 	return room;
 }
@@ -441,15 +407,14 @@
 static int oti6858_chars_in_buffer(struct tty_struct *tty)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	struct oti6858_private *priv = usb_get_serial_port_data(port);
 	int chars = 0;
 	unsigned long flags;
 
 	dbg("%s(port = %d)", __func__, port->number);
 
-	spin_lock_irqsave(&priv->lock, flags);
-	chars = oti6858_buf_data_avail(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
+	spin_lock_irqsave(&port->lock, flags);
+	chars = kfifo_len(&port->write_fifo);
+	spin_unlock_irqrestore(&port->lock, flags);
 
 	return chars;
 }
@@ -640,10 +605,10 @@
 
 	dbg("%s(port = %d)", __func__, port->number);
 
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock_irqsave(&port->lock, flags);
 	/* clear out any remaining data in the buffer */
-	oti6858_buf_clear(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
+	kfifo_reset_out(&port->write_fifo);
+	spin_unlock_irqrestore(&port->lock, flags);
 
 	dbg("%s(): after buf_clear()", __func__);
 
@@ -785,18 +750,12 @@
 
 static void oti6858_release(struct usb_serial *serial)
 {
-	struct oti6858_private *priv;
 	int i;
 
 	dbg("%s()", __func__);
 
-	for (i = 0; i < serial->num_ports; ++i) {
-		priv = usb_get_serial_port_data(serial->port[i]);
-		if (priv) {
-			oti6858_buf_free(priv->buf);
-			kfree(priv);
-		}
-	}
+	for (i = 0; i < serial->num_ports; ++i)
+		kfree(usb_get_serial_port_data(serial->port[i]));
 }
 
 static void oti6858_read_int_callback(struct urb *urb)
@@ -889,10 +848,14 @@
 		}
 	} else if (!transient) {
 		unsigned long flags;
+		int count;
+
+		spin_lock_irqsave(&port->lock, flags);
+		count = kfifo_len(&port->write_fifo);
+		spin_unlock_irqrestore(&port->lock, flags);
 
 		spin_lock_irqsave(&priv->lock, flags);
-		if (priv->flags.write_urb_in_use == 0
-				&& oti6858_buf_data_avail(priv->buf) != 0) {
+		if (priv->flags.write_urb_in_use == 0 && count != 0) {
 			schedule_delayed_work(&priv->delayed_write_work, 0);
 			resubmit = 0;
 		}
@@ -1014,165 +977,6 @@
 	}
 }
 
-
-/*
- * oti6858_buf_alloc
- *
- * Allocate a circular buffer and all associated memory.
- */
-static struct oti6858_buf *oti6858_buf_alloc(unsigned int size)
-{
-	struct oti6858_buf *pb;
-
-	if (size == 0)
-		return NULL;
-
-	pb = kmalloc(sizeof(struct oti6858_buf), GFP_KERNEL);
-	if (pb == NULL)
-		return NULL;
-
-	pb->buf_buf = kmalloc(size, GFP_KERNEL);
-	if (pb->buf_buf == NULL) {
-		kfree(pb);
-		return NULL;
-	}
-
-	pb->buf_size = size;
-	pb->buf_get = pb->buf_put = pb->buf_buf;
-
-	return pb;
-}
-
-/*
- * oti6858_buf_free
- *
- * Free the buffer and all associated memory.
- */
-static void oti6858_buf_free(struct oti6858_buf *pb)
-{
-	if (pb) {
-		kfree(pb->buf_buf);
-		kfree(pb);
-	}
-}
-
-/*
- * oti6858_buf_clear
- *
- * Clear out all data in the circular buffer.
- */
-static void oti6858_buf_clear(struct oti6858_buf *pb)
-{
-	if (pb != NULL) {
-		/* equivalent to a get of all data available */
-		pb->buf_get = pb->buf_put;
-	}
-}
-
-/*
- * oti6858_buf_data_avail
- *
- * Return the number of bytes of data available in the circular
- * buffer.
- */
-static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb)
-{
-	if (pb == NULL)
-		return 0;
-	return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
-}
-
-/*
- * oti6858_buf_space_avail
- *
- * Return the number of bytes of space available in the circular
- * buffer.
- */
-static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb)
-{
-	if (pb == NULL)
-		return 0;
-	return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
-}
-
-/*
- * oti6858_buf_put
- *
- * Copy data data from a user buffer and put it into the circular buffer.
- * Restrict to the amount of space available.
- *
- * Return the number of bytes copied.
- */
-static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf,
-					unsigned int count)
-{
-	unsigned int len;
-
-	if (pb == NULL)
-		return 0;
-
-	len  = oti6858_buf_space_avail(pb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = pb->buf_buf + pb->buf_size - pb->buf_put;
-	if (count > len) {
-		memcpy(pb->buf_put, buf, len);
-		memcpy(pb->buf_buf, buf+len, count - len);
-		pb->buf_put = pb->buf_buf + count - len;
-	} else {
-		memcpy(pb->buf_put, buf, count);
-		if (count < len)
-			pb->buf_put += count;
-		else /* count == len */
-			pb->buf_put = pb->buf_buf;
-	}
-
-	return count;
-}
-
-/*
- * oti6858_buf_get
- *
- * Get data from the circular buffer and copy to the given buffer.
- * Restrict to the amount of data available.
- *
- * Return the number of bytes copied.
- */
-static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf,
-					unsigned int count)
-{
-	unsigned int len;
-
-	if (pb == NULL)
-		return 0;
-
-	len = oti6858_buf_data_avail(pb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = pb->buf_buf + pb->buf_size - pb->buf_get;
-	if (count > len) {
-		memcpy(buf, pb->buf_get, len);
-		memcpy(buf+len, pb->buf_buf, count - len);
-		pb->buf_get = pb->buf_buf + count - len;
-	} else {
-		memcpy(buf, pb->buf_get, count);
-		if (count < len)
-			pb->buf_get += count;
-		else /* count == len */
-			pb->buf_get = pb->buf_buf;
-	}
-
-	return count;
-}
-
 /* module description and (de)initialization */
 
 static int __init oti6858_init(void)
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index c28b160..6b60018 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -40,16 +40,6 @@
 
 #define PL2303_CLOSING_WAIT	(30*HZ)
 
-#define PL2303_BUF_SIZE		1024
-#define PL2303_TMP_BUF_SIZE	1024
-
-struct pl2303_buf {
-	unsigned int	buf_size;
-	char		*buf_buf;
-	char		*buf_get;
-	char		*buf_put;
-};
-
 static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
@@ -157,173 +147,12 @@
 
 struct pl2303_private {
 	spinlock_t lock;
-	struct pl2303_buf *buf;
-	int write_urb_in_use;
 	wait_queue_head_t delta_msr_wait;
 	u8 line_control;
 	u8 line_status;
 	enum pl2303_type type;
 };
 
-/*
- * pl2303_buf_alloc
- *
- * Allocate a circular buffer and all associated memory.
- */
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
-{
-	struct pl2303_buf *pb;
-
-	if (size == 0)
-		return NULL;
-
-	pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
-	if (pb == NULL)
-		return NULL;
-
-	pb->buf_buf = kmalloc(size, GFP_KERNEL);
-	if (pb->buf_buf == NULL) {
-		kfree(pb);
-		return NULL;
-	}
-
-	pb->buf_size = size;
-	pb->buf_get = pb->buf_put = pb->buf_buf;
-
-	return pb;
-}
-
-/*
- * pl2303_buf_free
- *
- * Free the buffer and all associated memory.
- */
-static void pl2303_buf_free(struct pl2303_buf *pb)
-{
-	if (pb) {
-		kfree(pb->buf_buf);
-		kfree(pb);
-	}
-}
-
-/*
- * pl2303_buf_clear
- *
- * Clear out all data in the circular buffer.
- */
-static void pl2303_buf_clear(struct pl2303_buf *pb)
-{
-	if (pb != NULL)
-		pb->buf_get = pb->buf_put;
-		/* equivalent to a get of all data available */
-}
-
-/*
- * pl2303_buf_data_avail
- *
- * Return the number of bytes of data available in the circular
- * buffer.
- */
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
-{
-	if (pb == NULL)
-		return 0;
-
-	return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
-}
-
-/*
- * pl2303_buf_space_avail
- *
- * Return the number of bytes of space available in the circular
- * buffer.
- */
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
-{
-	if (pb == NULL)
-		return 0;
-
-	return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
-}
-
-/*
- * pl2303_buf_put
- *
- * Copy data data from a user buffer and put it into the circular buffer.
- * Restrict to the amount of space available.
- *
- * Return the number of bytes copied.
- */
-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
-				   unsigned int count)
-{
-	unsigned int len;
-
-	if (pb == NULL)
-		return 0;
-
-	len  = pl2303_buf_space_avail(pb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = pb->buf_buf + pb->buf_size - pb->buf_put;
-	if (count > len) {
-		memcpy(pb->buf_put, buf, len);
-		memcpy(pb->buf_buf, buf+len, count - len);
-		pb->buf_put = pb->buf_buf + count - len;
-	} else {
-		memcpy(pb->buf_put, buf, count);
-		if (count < len)
-			pb->buf_put += count;
-		else /* count == len */
-			pb->buf_put = pb->buf_buf;
-	}
-
-	return count;
-}
-
-/*
- * pl2303_buf_get
- *
- * Get data from the circular buffer and copy to the given buffer.
- * Restrict to the amount of data available.
- *
- * Return the number of bytes copied.
- */
-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
-				   unsigned int count)
-{
-	unsigned int len;
-
-	if (pb == NULL)
-		return 0;
-
-	len = pl2303_buf_data_avail(pb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = pb->buf_buf + pb->buf_size - pb->buf_get;
-	if (count > len) {
-		memcpy(buf, pb->buf_get, len);
-		memcpy(buf+len, pb->buf_buf, count - len);
-		pb->buf_get = pb->buf_buf + count - len;
-	} else {
-		memcpy(buf, pb->buf_get, count);
-		if (count < len)
-			pb->buf_get += count;
-		else /* count == len */
-			pb->buf_get = pb->buf_buf;
-	}
-
-	return count;
-}
-
 static int pl2303_vendor_read(__u16 value, __u16 index,
 		struct usb_serial *serial, unsigned char *buf)
 {
@@ -372,11 +201,6 @@
 		if (!priv)
 			goto cleanup;
 		spin_lock_init(&priv->lock);
-		priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
-		if (priv->buf == NULL) {
-			kfree(priv);
-			goto cleanup;
-		}
 		init_waitqueue_head(&priv->delta_msr_wait);
 		priv->type = type;
 		usb_set_serial_port_data(serial->port[i], priv);
@@ -404,7 +228,6 @@
 	kfree(buf);
 	for (--i; i >= 0; --i) {
 		priv = usb_get_serial_port_data(serial->port[i]);
-		pl2303_buf_free(priv->buf);
 		kfree(priv);
 		usb_set_serial_port_data(serial->port[i], NULL);
 	}
@@ -422,102 +245,6 @@
 	return retval;
 }
 
-static void pl2303_send(struct usb_serial_port *port)
-{
-	int count, result;
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	if (priv->write_urb_in_use) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return;
-	}
-
-	count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
-			       port->bulk_out_size);
-
-	if (count == 0) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return;
-	}
-
-	priv->write_urb_in_use = 1;
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	usb_serial_debug_data(debug, &port->dev, __func__, count,
-			      port->write_urb->transfer_buffer);
-
-	port->write_urb->transfer_buffer_length = count;
-	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-	if (result) {
-		dev_err(&port->dev, "%s - failed submitting write urb,"
-			" error %d\n", __func__, result);
-		priv->write_urb_in_use = 0;
-		/* TODO: reschedule pl2303_send */
-	}
-
-	usb_serial_port_softint(port);
-}
-
-static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
-				const unsigned char *buf, int count)
-{
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	unsigned long flags;
-
-	dbg("%s - port %d, %d bytes", __func__, port->number, count);
-
-	if (!count)
-		return count;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	count = pl2303_buf_put(priv->buf, buf, count);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	pl2303_send(port);
-
-	return count;
-}
-
-static int pl2303_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	int room = 0;
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	room = pl2303_buf_space_avail(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	dbg("%s - returns %d", __func__, room);
-	return room;
-}
-
-static int pl2303_chars_in_buffer(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	int chars = 0;
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	chars = pl2303_buf_data_avail(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	dbg("%s - returns %d", __func__, chars);
-	return chars;
-}
-
 static void pl2303_set_termios(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -729,22 +456,10 @@
 
 static void pl2303_close(struct usb_serial_port *port)
 {
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	unsigned long flags;
-
 	dbg("%s - port %d", __func__, port->number);
 
-	spin_lock_irqsave(&priv->lock, flags);
-	/* clear out any remaining data in the buffer */
-	pl2303_buf_clear(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	/* shutdown our urbs */
-	dbg("%s - shutting down urbs", __func__);
-	usb_kill_urb(port->write_urb);
-	usb_kill_urb(port->read_urb);
+	usb_serial_generic_close(port);
 	usb_kill_urb(port->interrupt_in_urb);
-
 }
 
 static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -770,10 +485,8 @@
 		pl2303_set_termios(tty, port, &tmp_termios);
 
 	dbg("%s - submitting read urb", __func__);
-	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+	result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
 	if (result) {
-		dev_err(&port->dev, "%s - failed submitting read urb,"
-			" error %d\n", __func__, result);
 		pl2303_close(port);
 		return -EPROTO;
 	}
@@ -953,10 +666,7 @@
 
 	for (i = 0; i < serial->num_ports; ++i) {
 		priv = usb_get_serial_port_data(serial->port[i]);
-		if (priv) {
-			pl2303_buf_free(priv->buf);
-			kfree(priv);
-		}
+		kfree(priv);
 	}
 }
 
@@ -1037,13 +747,31 @@
 			__func__, retval);
 }
 
-static void pl2303_push_data(struct tty_struct *tty,
-		struct usb_serial_port *port, struct urb *urb,
-		u8 line_status)
+static void pl2303_process_read_urb(struct urb *urb)
 {
+	struct usb_serial_port *port = urb->context;
+	struct pl2303_private *priv = usb_get_serial_port_data(port);
+	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
-	/* get tty_flag from status */
 	char tty_flag = TTY_NORMAL;
+	unsigned long flags;
+	u8 line_status;
+	int i;
+
+	/* update line status */
+	spin_lock_irqsave(&priv->lock, flags);
+	line_status = priv->line_status;
+	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
+	spin_unlock_irqrestore(&priv->lock, flags);
+	wake_up_interruptible(&priv->delta_msr_wait);
+
+	if (!urb->actual_length)
+		return;
+
+	tty = tty_port_tty_get(&port->port);
+	if (!tty)
+		return;
+
 	/* break takes precedence over parity, */
 	/* which takes precedence over framing errors */
 	if (line_status & UART_BREAK_ERROR)
@@ -1058,107 +786,17 @@
 	if (line_status & UART_OVERRUN_ERROR)
 		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
 
-	if (tty_flag == TTY_NORMAL && !(port->console && port->sysrq))
-		tty_insert_flip_string(tty, data, urb->actual_length);
-	else {
-		int i;
+	if (port->port.console && port->sysrq) {
 		for (i = 0; i < urb->actual_length; ++i)
 			if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
 				tty_insert_flip_char(tty, data[i], tty_flag);
+	} else {
+		tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
+							urb->actual_length);
 	}
+
 	tty_flip_buffer_push(tty);
-}
-
-static void pl2303_read_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port =  urb->context;
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	struct tty_struct *tty;
-	unsigned long flags;
-	int result;
-	int status = urb->status;
-	u8 line_status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (status) {
-		dbg("%s - urb status = %d", __func__, status);
-		if (status == -EPROTO) {
-			/* PL2303 mysteriously fails with -EPROTO reschedule
-			 * the read */
-			dbg("%s - caught -EPROTO, resubmitting the urb",
-			    __func__);
-			result = usb_submit_urb(urb, GFP_ATOMIC);
-			if (result)
-				dev_err(&urb->dev->dev, "%s - failed"
-					" resubmitting read urb, error %d\n",
-					__func__, result);
-			return;
-		}
-		dbg("%s - unable to handle the error, exiting.", __func__);
-		return;
-	}
-
-	usb_serial_debug_data(debug, &port->dev, __func__,
-			      urb->actual_length, urb->transfer_buffer);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	line_status = priv->line_status;
-	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
-	spin_unlock_irqrestore(&priv->lock, flags);
-	wake_up_interruptible(&priv->delta_msr_wait);
-
-	tty = tty_port_tty_get(&port->port);
-	if (tty && urb->actual_length) {
-		pl2303_push_data(tty, port, urb, line_status);
-	}
 	tty_kref_put(tty);
-	/* Schedule the next read _if_ we are still open */
-	result = usb_submit_urb(urb, GFP_ATOMIC);
-	if (result && result != -EPERM)
-		dev_err(&urb->dev->dev, "%s - failed resubmitting"
-			" read urb, error %d\n", __func__, result);
-}
-
-static void pl2303_write_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port =  urb->context;
-	struct pl2303_private *priv = usb_get_serial_port_data(port);
-	int result;
-	int status = urb->status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	switch (status) {
-	case 0:
-		/* success */
-		break;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __func__,
-		    status);
-		priv->write_urb_in_use = 0;
-		return;
-	default:
-		/* error in the urb, so we have to resubmit it */
-		dbg("%s - Overflow in write", __func__);
-		dbg("%s - nonzero write bulk status received: %d", __func__,
-		    status);
-		port->write_urb->transfer_buffer_length = 1;
-		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-		if (result)
-			dev_err(&urb->dev->dev, "%s - failed resubmitting write"
-				" urb, error %d\n", __func__, result);
-		else
-			return;
-	}
-
-	priv->write_urb_in_use = 0;
-
-	/* send any buffered data */
-	pl2303_send(port);
 }
 
 /* All of the device info needed for the PL2303 SIO serial converter */
@@ -1170,21 +808,19 @@
 	.id_table =		id_table,
 	.usb_driver = 		&pl2303_driver,
 	.num_ports =		1,
+	.bulk_in_size =		256,
+	.bulk_out_size =	256,
 	.open =			pl2303_open,
 	.close =		pl2303_close,
 	.dtr_rts = 		pl2303_dtr_rts,
 	.carrier_raised =	pl2303_carrier_raised,
-	.write =		pl2303_write,
 	.ioctl =		pl2303_ioctl,
 	.break_ctl =		pl2303_break_ctl,
 	.set_termios =		pl2303_set_termios,
 	.tiocmget =		pl2303_tiocmget,
 	.tiocmset =		pl2303_tiocmset,
-	.read_bulk_callback =	pl2303_read_bulk_callback,
+	.process_read_urb =	pl2303_process_read_urb,
 	.read_int_callback =	pl2303_read_int_callback,
-	.write_bulk_callback =	pl2303_write_bulk_callback,
-	.write_room =		pl2303_write_room,
-	.chars_in_buffer =	pl2303_chars_in_buffer,
 	.attach =		pl2303_startup,
 	.release =		pl2303_release,
 };
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 23c09b3..a871645 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -5,7 +5,7 @@
  *	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.
- * 
+ *
  */
 
 #define BENQ_VENDOR_ID			0x04a5
@@ -137,5 +137,5 @@
 #define SANWA_PRODUCT_ID	0x0001
 
 /* ADLINK ND-6530 RS232,RS485 and RS422 adapter */
-#define ADLINK_VENDOR_ID        0x0b63
-#define ADLINK_ND6530_PRODUCT_ID       0x6530
+#define ADLINK_VENDOR_ID		0x0b63
+#define ADLINK_ND6530_PRODUCT_ID	0x6530
diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c
index 7e3bea2..214a3e5 100644
--- a/drivers/usb/serial/qcaux.c
+++ b/drivers/usb/serial/qcaux.c
@@ -50,6 +50,10 @@
 #define SANYO_VENDOR_ID				0x0474
 #define SANYO_PRODUCT_KATANA_LX			0x0754 /* SCP-3800 (Katana LX) */
 
+/* Samsung devices */
+#define SAMSUNG_VENDOR_ID			0x04e8
+#define SAMSUNG_PRODUCT_U520			0x6640 /* SCH-U520 */
+
 static struct usb_device_id id_table[] = {
 	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5740, 0xff, 0x00, 0x00) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5750, 0xff, 0x00, 0x00) },
@@ -61,6 +65,7 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDX650, 0xff, 0xff, 0x00) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) },
 	{ },
 };
 MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 53a2d5a..04bb759 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -15,6 +15,8 @@
 #include <linux/tty_flip.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
+#include <linux/slab.h>
+#include "usb-wwan.h"
 
 #define DRIVER_AUTHOR "Qualcomm Inc"
 #define DRIVER_DESC "Qualcomm USB Serial driver"
@@ -76,6 +78,8 @@
 	{USB_DEVICE(0x1199, 0x900a)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */
 	{USB_DEVICE(0x16d8, 0x8001)},	/* CMDTech Gobi 2000 QDL device (VU922) */
 	{USB_DEVICE(0x16d8, 0x8002)},	/* CMDTech Gobi 2000 Modem device (VU922) */
+	{USB_DEVICE(0x05c6, 0x9204)},	/* Gobi 2000 QDL device */
+	{USB_DEVICE(0x05c6, 0x9205)},	/* Gobi 2000 Modem device */
 	{ }				/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, id_table);
@@ -92,6 +96,8 @@
 
 static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 {
+	struct usb_wwan_intf_private *data;
+	struct usb_host_interface *intf = serial->interface->cur_altsetting;
 	int retval = -ENODEV;
 	__u8 nintf;
 	__u8 ifnum;
@@ -100,33 +106,45 @@
 
 	nintf = serial->dev->actconfig->desc.bNumInterfaces;
 	dbg("Num Interfaces = %d", nintf);
-	ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
+	ifnum = intf->desc.bInterfaceNumber;
 	dbg("This Interface = %d", ifnum);
 
+	data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private),
+					 GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	spin_lock_init(&data->susp_lock);
+
 	switch (nintf) {
 	case 1:
 		/* QDL mode */
-		if (serial->interface->num_altsetting == 2) {
-			struct usb_host_interface *intf;
-
+		/* Gobi 2000 has a single altsetting, older ones have two */
+		if (serial->interface->num_altsetting == 2)
 			intf = &serial->interface->altsetting[1];
-			if (intf->desc.bNumEndpoints == 2) {
-				if (usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) &&
-				    usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
-					dbg("QDL port found");
-					retval = usb_set_interface(serial->dev, ifnum, 1);
-					if (retval < 0) {
-						dev_err(&serial->dev->dev,
-							"Could not set interface, error %d\n",
-							retval);
-						retval = -ENODEV;
-					}
-					return retval;
-				}
+		else if (serial->interface->num_altsetting > 2)
+			break;
+
+		if (intf->desc.bNumEndpoints == 2 &&
+		    usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) &&
+		    usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
+			dbg("QDL port found");
+
+			if (serial->interface->num_altsetting == 1)
+				return 0;
+
+			retval = usb_set_interface(serial->dev, ifnum, 1);
+			if (retval < 0) {
+				dev_err(&serial->dev->dev,
+					"Could not set interface, error %d\n",
+					retval);
+				retval = -ENODEV;
 			}
+			return retval;
 		}
 		break;
 
+	case 3:
 	case 4:
 		/* Composite mode */
 		if (ifnum == 2) {
@@ -161,6 +179,18 @@
 	.usb_driver          = &qcdriver,
 	.num_ports           = 1,
 	.probe               = qcprobe,
+	.open		     = usb_wwan_open,
+	.close		     = usb_wwan_close,
+	.write		     = usb_wwan_write,
+	.write_room	     = usb_wwan_write_room,
+	.chars_in_buffer     = usb_wwan_chars_in_buffer,
+	.attach		     = usb_wwan_startup,
+	.disconnect	     = usb_wwan_disconnect,
+	.release	     = usb_wwan_release,
+#ifdef CONFIG_PM
+	.suspend	     = usb_wwan_suspend,
+	.resume		     = usb_wwan_resume,
+#endif
 };
 
 static int __init qcinit(void)
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 43a0cad..a36e231 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -1,6 +1,7 @@
 /*
  * Safe Encapsulated USB Serial Driver
  *
+ *      Copyright (C) 2010 Johan Hovold <jhovold@gmail.com>
  *      Copyright (C) 2001 Lineo
  *      Copyright (C) 2001 Hewlett-Packard
  *
@@ -84,8 +85,8 @@
 static int safe = 1;
 static int padded = CONFIG_USB_SERIAL_SAFE_PADDED;
 
-#define DRIVER_VERSION "v0.0b"
-#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com"
+#define DRIVER_VERSION "v0.1"
+#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com, Johan Hovold <jhovold@gmail.com>"
 #define DRIVER_DESC "USB Safe Encapsulated Serial"
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
@@ -212,191 +213,80 @@
 	return fcs;
 }
 
-static void safe_read_bulk_callback(struct urb *urb)
+static void safe_process_read_urb(struct urb *urb)
 {
-	struct usb_serial_port *port =  urb->context;
+	struct usb_serial_port *port = urb->context;
 	unsigned char *data = urb->transfer_buffer;
 	unsigned char length = urb->actual_length;
+	int actual_length;
 	struct tty_struct *tty;
-	int result;
-	int status = urb->status;
+	__u16 fcs;
 
-	dbg("%s", __func__);
-
-	if (status) {
-		dbg("%s - nonzero read bulk status received: %d",
-		    __func__, status);
+	if (!length)
 		return;
-	}
 
-	dbg("safe_read_bulk_callback length: %d",
-					port->read_urb->actual_length);
-#ifdef ECHO_RCV
-	{
-		int i;
-		unsigned char *cp = port->read_urb->transfer_buffer;
-		for (i = 0; i < port->read_urb->actual_length; i++) {
-			if ((i % 32) == 0)
-				printk("\nru[%02x] ", i);
-			printk("%02x ", *cp++);
-		}
-		printk("\n");
-	}
-#endif
 	tty = tty_port_tty_get(&port->port);
-	if (safe) {
-		__u16 fcs;
-		fcs = fcs_compute10(data, length, CRC10_INITFCS);
-		if (!fcs) {
-			int actual_length = data[length - 2] >> 2;
-			if (actual_length <= (length - 2)) {
-				dev_info(&urb->dev->dev, "%s - actual: %d\n",
-					 __func__, actual_length);
-				tty_insert_flip_string(tty,
-							data, actual_length);
-				tty_flip_buffer_push(tty);
-			} else {
-				dev_err(&port->dev,
-					"%s - inconsistent lengths %d:%d\n",
-					__func__, actual_length, length);
-			}
-		} else {
-			dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs);
-		}
-	} else {
-		tty_insert_flip_string(tty, data, length);
-		tty_flip_buffer_push(tty);
+	if (!tty)
+		return;
+
+	if (!safe)
+		goto out;
+
+	fcs = fcs_compute10(data, length, CRC10_INITFCS);
+	if (fcs) {
+		dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs);
+		goto err;
 	}
+
+	actual_length = data[length - 2] >> 2;
+	if (actual_length > (length - 2)) {
+		dev_err(&port->dev, "%s - inconsistent lengths %d:%d\n",
+				__func__, actual_length, length);
+		goto err;
+	}
+	dev_info(&urb->dev->dev, "%s - actual: %d\n", __func__, actual_length);
+	length = actual_length;
+out:
+	tty_insert_flip_string(tty, data, length);
+	tty_flip_buffer_push(tty);
+err:
 	tty_kref_put(tty);
-
-	/* Continue trying to always read  */
-	usb_fill_bulk_urb(urb, port->serial->dev,
-			usb_rcvbulkpipe(port->serial->dev,
-					port->bulk_in_endpointAddress),
-			urb->transfer_buffer, urb->transfer_buffer_length,
-			safe_read_bulk_callback, port);
-
-	result = usb_submit_urb(urb, GFP_ATOMIC);
-	if (result)
-		dev_err(&port->dev,
-			"%s - failed resubmitting read urb, error %d\n",
-			__func__, result);
-		/* FIXME: Need a mechanism to retry later if this happens */
 }
 
-static int safe_write(struct tty_struct *tty, struct usb_serial_port *port,
-					const unsigned char *buf, int count)
+static int safe_prepare_write_buffer(struct usb_serial_port *port,
+						void *dest, size_t size)
 {
-	unsigned char *data;
-	int result;
-	int i;
-	int packet_length;
+	unsigned char *buf = dest;
+	int count;
+	int trailer_len;
+	int pkt_len;
+	__u16 fcs;
 
-	dbg("safe_write port: %p %d urb: %p count: %d",
-				port, port->number, port->write_urb, count);
+	trailer_len = safe ? 2 : 0;
 
-	if (!port->write_urb) {
-		dbg("%s - write urb NULL", __func__);
-		return 0;
-	}
+	count = kfifo_out_locked(&port->write_fifo, buf, size - trailer_len,
+								&port->lock);
+	if (!safe)
+		return count;
 
-	dbg("safe_write write_urb: %d transfer_buffer_length",
-	     port->write_urb->transfer_buffer_length);
-
-	if (!port->write_urb->transfer_buffer_length) {
-		dbg("%s - write urb transfer_buffer_length zero", __func__);
-		return 0;
-	}
-	if (count == 0) {
-		dbg("%s - write request of 0 bytes", __func__);
-		return 0;
-	}
-	spin_lock_bh(&port->lock);
-	if (port->write_urb_busy) {
-		spin_unlock_bh(&port->lock);
-		dbg("%s - already writing", __func__);
-		return 0;
-	}
-	port->write_urb_busy = 1;
-	spin_unlock_bh(&port->lock);
-
-	packet_length = port->bulk_out_size;	/* get max packetsize */
-
-	i = packet_length - (safe ? 2 : 0);	/* get bytes to send */
-	count = (count > i) ? i : count;
-
-
-	/* get the data into the transfer buffer */
-	data = port->write_urb->transfer_buffer;
-	memset(data, '0', packet_length);
-
-	memcpy(data, buf, count);
-
-	if (safe) {
-		__u16 fcs;
-
-		/* pad if necessary */
-		if (!padded)
-			packet_length = count + 2;
-		/* set count */
-		data[packet_length - 2] = count << 2;
-		data[packet_length - 1] = 0;
-
-		/* compute fcs and insert into trailer */
-		fcs = fcs_compute10(data, packet_length, CRC10_INITFCS);
-		data[packet_length - 2] |= fcs >> 8;
-		data[packet_length - 1] |= fcs & 0xff;
-
-		/* set length to send */
-		port->write_urb->transfer_buffer_length = packet_length;
+	/* pad if necessary */
+	if (padded) {
+		pkt_len = size;
+		memset(buf + count, '0', pkt_len - count - trailer_len);
 	} else {
-		port->write_urb->transfer_buffer_length = count;
+		pkt_len = count + trailer_len;
 	}
 
-	usb_serial_debug_data(debug, &port->dev, __func__, count,
-					port->write_urb->transfer_buffer);
-#ifdef ECHO_TX
-	{
-		int i;
-		unsigned char *cp = port->write_urb->transfer_buffer;
-		for (i = 0; i < port->write_urb->transfer_buffer_length; i++) {
-			if ((i % 32) == 0)
-				printk("\nsu[%02x] ", i);
-			printk("%02x ", *cp++);
-		}
-		printk("\n");
-	}
-#endif
-	port->write_urb->dev = port->serial->dev;
-	result = usb_submit_urb(port->write_urb, GFP_KERNEL);
-	if (result) {
-		port->write_urb_busy = 0;
-		dev_err(&port->dev,
-			"%s - failed submitting write urb, error %d\n",
-			__func__, result);
-		return 0;
-	}
-	dbg("%s urb: %p submitted", __func__, port->write_urb);
+	/* set count */
+	buf[pkt_len - 2] = count << 2;
+	buf[pkt_len - 1] = 0;
 
-	return count;
-}
+	/* compute fcs and insert into trailer */
+	fcs = fcs_compute10(buf, pkt_len, CRC10_INITFCS);
+	buf[pkt_len - 2] |= fcs >> 8;
+	buf[pkt_len - 1] |= fcs & 0xff;
 
-static int safe_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	int room = 0;		/* Default: no room */
-	unsigned long flags;
-
-	dbg("%s", __func__);
-
-	spin_lock_irqsave(&port->lock, flags);
-	if (port->write_urb_busy)
-		room = port->bulk_out_size - (safe ? 2 : 0);
-	spin_unlock_irqrestore(&port->lock, flags);
-
-	if (room)
-		dbg("safe_write_room returns %d", room);
-	return room;
+	return pkt_len;
 }
 
 static int safe_startup(struct usb_serial *serial)
@@ -421,9 +311,8 @@
 	.id_table =		id_table,
 	.usb_driver =		&safe_driver,
 	.num_ports =		1,
-	.write =		safe_write,
-	.write_room =		safe_write_room,
-	.read_bulk_callback =	safe_read_bulk_callback,
+	.process_read_urb =	safe_process_read_urb,
+	.prepare_write_buffer =	safe_prepare_write_buffer,
 	.attach =		safe_startup,
 };
 
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 5d39191..329d311 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -1,6 +1,7 @@
 /*
  * spcp8x5 USB to serial adaptor driver
  *
+ * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com)
  * Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn)
  * Copyright (C) 2006 S1 Corp.
  *
@@ -29,7 +30,7 @@
 
 
 /* Version Information */
-#define DRIVER_VERSION 	"v0.04"
+#define DRIVER_VERSION	"v0.10"
 #define DRIVER_DESC 	"SPCP8x5 USB to serial adaptor driver"
 
 static int debug;
@@ -64,11 +65,6 @@
 	u16	length;
 };
 
-/* wait 30s before close */
-#define SPCP8x5_CLOSING_WAIT	(30*HZ)
-
-#define SPCP8x5_BUF_SIZE	1024
-
 
 /* spcp8x5 spec register define */
 #define MCR_CONTROL_LINE_RTS		0x02
@@ -155,133 +151,6 @@
 	SPCP835_TYPE,
 };
 
-/* 1st in 1st out buffer 4 driver */
-struct ringbuf {
-	unsigned int	buf_size;
-	char		*buf_buf;
-	char		*buf_get;
-	char		*buf_put;
-};
-
-/* alloc the ring buf and alloc the buffer itself */
-static inline struct ringbuf *alloc_ringbuf(unsigned int size)
-{
-	struct ringbuf *pb;
-
-	if (size == 0)
-		return NULL;
-
-	pb = kmalloc(sizeof(*pb), GFP_KERNEL);
-	if (pb == NULL)
-		return NULL;
-
-	pb->buf_buf = kmalloc(size, GFP_KERNEL);
-	if (pb->buf_buf == NULL) {
-		kfree(pb);
-		return NULL;
-	}
-
-	pb->buf_size = size;
-	pb->buf_get = pb->buf_put = pb->buf_buf;
-
-	return pb;
-}
-
-/* free the ring buf and the buffer itself */
-static inline void free_ringbuf(struct ringbuf *pb)
-{
-	if (pb != NULL) {
-		kfree(pb->buf_buf);
-		kfree(pb);
-	}
-}
-
-/* clear pipo , juest repoint the pointer here */
-static inline void clear_ringbuf(struct ringbuf *pb)
-{
-	if (pb != NULL)
-		pb->buf_get = pb->buf_put;
-}
-
-/* get the number of data in the pipo */
-static inline unsigned int ringbuf_avail_data(struct ringbuf *pb)
-{
-	if (pb == NULL)
-		return 0;
-	return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
-}
-
-/* get the number of space in the pipo */
-static inline unsigned int ringbuf_avail_space(struct ringbuf *pb)
-{
-	if (pb == NULL)
-		return 0;
-	return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
-}
-
-/* put count data into pipo */
-static unsigned int put_ringbuf(struct ringbuf *pb, const char *buf,
-				unsigned int count)
-{
-	unsigned int len;
-
-	if (pb == NULL)
-		return 0;
-
-	len  = ringbuf_avail_space(pb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = pb->buf_buf + pb->buf_size - pb->buf_put;
-	if (count > len) {
-		memcpy(pb->buf_put, buf, len);
-		memcpy(pb->buf_buf, buf+len, count - len);
-		pb->buf_put = pb->buf_buf + count - len;
-	} else {
-		memcpy(pb->buf_put, buf, count);
-		if (count < len)
-			pb->buf_put += count;
-		else /* count == len */
-			pb->buf_put = pb->buf_buf;
-	}
-	return count;
-}
-
-/* get count data from pipo */
-static unsigned int get_ringbuf(struct ringbuf *pb, char *buf,
-				unsigned int count)
-{
-	unsigned int len;
-
-	if (pb == NULL || buf == NULL)
-		return 0;
-
-	len = ringbuf_avail_data(pb);
-	if (count > len)
-		count = len;
-
-	if (count == 0)
-		return 0;
-
-	len = pb->buf_buf + pb->buf_size - pb->buf_get;
-	if (count > len) {
-		memcpy(buf, pb->buf_get, len);
-		memcpy(buf+len, pb->buf_buf, count - len);
-		pb->buf_get = pb->buf_buf + count - len;
-	} else {
-		memcpy(buf, pb->buf_get, count);
-		if (count < len)
-			pb->buf_get += count;
-		else /* count == len */
-			pb->buf_get = pb->buf_buf;
-	}
-
-	return count;
-}
-
 static struct usb_driver spcp8x5_driver = {
 	.name =			"spcp8x5",
 	.probe =		usb_serial_probe,
@@ -293,8 +162,6 @@
 
 struct spcp8x5_private {
 	spinlock_t 	lock;
-	struct ringbuf	*buf;
-	int 		write_urb_in_use;
 	enum spcp8x5_type	type;
 	wait_queue_head_t	delta_msr_wait;
 	u8 			line_control;
@@ -330,24 +197,15 @@
 			goto cleanup;
 
 		spin_lock_init(&priv->lock);
-		priv->buf = alloc_ringbuf(SPCP8x5_BUF_SIZE);
-		if (priv->buf == NULL)
-			goto cleanup2;
-
 		init_waitqueue_head(&priv->delta_msr_wait);
 		priv->type = type;
 		usb_set_serial_port_data(serial->port[i] , priv);
-
 	}
 
 	return 0;
-
-cleanup2:
-	kfree(priv);
 cleanup:
 	for (--i; i >= 0; --i) {
 		priv = usb_get_serial_port_data(serial->port[i]);
-		free_ringbuf(priv->buf);
 		kfree(priv);
 		usb_set_serial_port_data(serial->port[i] , NULL);
 	}
@@ -358,15 +216,9 @@
 static void spcp8x5_release(struct usb_serial *serial)
 {
 	int i;
-	struct spcp8x5_private *priv;
 
-	for (i = 0; i < serial->num_ports; i++) {
-		priv = usb_get_serial_port_data(serial->port[i]);
-		if (priv) {
-			free_ringbuf(priv->buf);
-			kfree(priv);
-		}
-	}
+	for (i = 0; i < serial->num_ports; i++)
+		kfree(usb_get_serial_port_data(serial->port[i]));
 }
 
 /* set the modem control line of the device.
@@ -470,33 +322,6 @@
 	spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type);
 }
 
-/* close the serial port. We should wait for data sending to device 1st and
- * then kill all urb. */
-static void spcp8x5_close(struct usb_serial_port *port)
-{
-	struct spcp8x5_private *priv = usb_get_serial_port_data(port);
-	unsigned long flags;
-	int result;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	/* clear out any remaining data in the buffer */
-	clear_ringbuf(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	/* kill urb */
-	if (port->write_urb != NULL) {
-		result = usb_unlink_urb(port->write_urb);
-		if (result)
-			dev_dbg(&port->dev,
-				"usb_unlink_urb(write_urb) = %d\n", result);
-	}
-	result = usb_unlink_urb(port->read_urb);
-	if (result)
-		dev_dbg(&port->dev, "usb_unlink_urb(read_urb) = %d\n", result);
-}
-
 static void spcp8x5_init_termios(struct tty_struct *tty)
 {
 	/* for the 1st time call this function */
@@ -620,7 +445,7 @@
 }
 
 /* open the serial port. do some usb system call. set termios and get the line
- * status of the device. then submit the read urb */
+ * status of the device. */
 static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
 	struct ktermios tmp_termios;
@@ -655,52 +480,21 @@
 	priv->line_status = status & 0xf0 ;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	dbg("%s - submitting read urb", __func__);
-	port->read_urb->dev = serial->dev;
-	ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
-	if (ret) {
-		spcp8x5_close(port);
-		return -EPROTO;
-	}
 	port->port.drain_delay = 256;
-	return 0;
+
+	return usb_serial_generic_open(tty, port);
 }
 
-/* bulk read call back function. check the status of the urb. if transfer
- * failed return. then update the status and the tty send data to tty subsys.
- * submit urb again.
- */
-static void spcp8x5_read_bulk_callback(struct urb *urb)
+static void spcp8x5_process_read_urb(struct urb *urb)
 {
 	struct usb_serial_port *port = urb->context;
 	struct spcp8x5_private *priv = usb_get_serial_port_data(port);
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
 	unsigned long flags;
-	int result = urb->status;
 	u8 status;
 	char tty_flag;
 
-	dev_dbg(&port->dev, "start, result = %d, urb->actual_length = %d\n,",
-		result, urb->actual_length);
-
-	/* check the urb status */
-	if (result) {
-		if (result == -EPROTO) {
-			/* spcp8x5 mysteriously fails with -EPROTO */
-			/* reschedule the read */
-			urb->dev = port->serial->dev;
-			result = usb_submit_urb(urb , GFP_ATOMIC);
-			if (result)
-				dev_dbg(&port->dev,
-					"failed submitting read urb %d\n",
-					result);
-			return;
-		}
-		dev_dbg(&port->dev, "unable to handle the error, exiting.\n");
-		return;
-	}
-
 	/* get tty_flag from status */
 	tty_flag = TTY_NORMAL;
 
@@ -711,141 +505,33 @@
 	/* wake up the wait for termios */
 	wake_up_interruptible(&priv->delta_msr_wait);
 
-	/* break takes precedence over parity, which takes precedence over
-	 * framing errors */
-	if (status & UART_BREAK_ERROR)
-		tty_flag = TTY_BREAK;
-	else if (status & UART_PARITY_ERROR)
-		tty_flag = TTY_PARITY;
-	else if (status & UART_FRAME_ERROR)
-		tty_flag = TTY_FRAME;
-	dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
+	if (!urb->actual_length)
+		return;
 
 	tty = tty_port_tty_get(&port->port);
-	if (tty && urb->actual_length) {
+	if (!tty)
+		return;
+
+	if (status & UART_STATE_TRANSIENT_MASK) {
+		/* break takes precedence over parity, which takes precedence
+		 * over framing errors */
+		if (status & UART_BREAK_ERROR)
+			tty_flag = TTY_BREAK;
+		else if (status & UART_PARITY_ERROR)
+			tty_flag = TTY_PARITY;
+		else if (status & UART_FRAME_ERROR)
+			tty_flag = TTY_FRAME;
+		dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
+
 		/* overrun is special, not associated with a char */
 		if (status & UART_OVERRUN_ERROR)
 			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-		tty_insert_flip_string_fixed_flag(tty, data,
-						urb->actual_length, tty_flag);
-		tty_flip_buffer_push(tty);
 	}
+
+	tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
+							urb->actual_length);
+	tty_flip_buffer_push(tty);
 	tty_kref_put(tty);
-
-	/* Schedule the next read */
-	urb->dev = port->serial->dev;
-	result = usb_submit_urb(urb , GFP_ATOMIC);
-	if (result)
-		dev_dbg(&port->dev, "failed submitting read urb %d\n", result);
-}
-
-/* get data from ring buffer and then write to usb bus */
-static void spcp8x5_send(struct usb_serial_port *port)
-{
-	int count, result;
-	struct spcp8x5_private *priv = usb_get_serial_port_data(port);
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	if (priv->write_urb_in_use) {
-		dev_dbg(&port->dev, "write urb still used\n");
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return;
-	}
-
-	/* send the 1st urb for writting */
-	memset(port->write_urb->transfer_buffer , 0x00 , port->bulk_out_size);
-	count = get_ringbuf(priv->buf, port->write_urb->transfer_buffer,
-		port->bulk_out_size);
-
-	if (count == 0) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return;
-	}
-
-	/* update the urb status */
-	priv->write_urb_in_use = 1;
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	port->write_urb->transfer_buffer_length = count;
-	port->write_urb->dev = port->serial->dev;
-
-	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-	if (result) {
-		dev_dbg(&port->dev, "failed submitting write urb, error %d\n",
-			result);
-		priv->write_urb_in_use = 0;
-		/* TODO: reschedule spcp8x5_send */
-	}
-
-
-	schedule_work(&port->work);
-}
-
-/* this is the call back function for write urb. NOTE we should not sleep in
- * this routine. check the urb return code and then submit the write urb again
- * to hold the write loop */
-static void spcp8x5_write_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = urb->context;
-	struct spcp8x5_private *priv = usb_get_serial_port_data(port);
-	int result;
-	int status = urb->status;
-
-	switch (status) {
-	case 0:
-		/* success */
-		break;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dev_dbg(&port->dev, "urb shutting down with status: %d\n",
-			status);
-		priv->write_urb_in_use = 0;
-		return;
-	default:
-		/* error in the urb, so we have to resubmit it */
-		dbg("%s - Overflow in write", __func__);
-		dbg("%s - nonzero write bulk status received: %d",
-			__func__, status);
-		port->write_urb->transfer_buffer_length = 1;
-		port->write_urb->dev = port->serial->dev;
-		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
-		if (result)
-			dev_dbg(&port->dev,
-				"failed resubmitting write urb %d\n", result);
-		else
-			return;
-	}
-
-	priv->write_urb_in_use = 0;
-
-	/* send any buffered data */
-	spcp8x5_send(port);
-}
-
-/* write data to ring buffer. and then start the write transfer */
-static int spcp8x5_write(struct tty_struct *tty, struct usb_serial_port *port,
-			 const unsigned char *buf, int count)
-{
-	struct spcp8x5_private *priv = usb_get_serial_port_data(port);
-	unsigned long flags;
-
-	dev_dbg(&port->dev, "%d bytes\n", count);
-
-	if (!count)
-		return count;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	count = put_ringbuf(priv->buf, buf, count);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	spcp8x5_send(port);
-
-	return count;
 }
 
 static int spcp8x5_wait_modem_info(struct usb_serial_port *port,
@@ -953,36 +639,6 @@
 	return result;
 }
 
-/* get the avail space room in ring buffer */
-static int spcp8x5_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct spcp8x5_private *priv = usb_get_serial_port_data(port);
-	int room = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	room = ringbuf_avail_space(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	return room;
-}
-
-/* get the number of avail data in write ring buffer */
-static int spcp8x5_chars_in_buffer(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct spcp8x5_private *priv = usb_get_serial_port_data(port);
-	int chars = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	chars = ringbuf_avail_data(priv->buf);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	return chars;
-}
-
 /* All of the device info needed for the spcp8x5 SIO serial converter */
 static struct usb_serial_driver spcp8x5_device = {
 	.driver = {
@@ -992,21 +648,16 @@
 	.id_table		= id_table,
 	.num_ports		= 1,
 	.open 			= spcp8x5_open,
-	.close 			= spcp8x5_close,
 	.dtr_rts		= spcp8x5_dtr_rts,
 	.carrier_raised		= spcp8x5_carrier_raised,
-	.write 			= spcp8x5_write,
 	.set_termios 		= spcp8x5_set_termios,
 	.init_termios		= spcp8x5_init_termios,
 	.ioctl 			= spcp8x5_ioctl,
 	.tiocmget 		= spcp8x5_tiocmget,
 	.tiocmset 		= spcp8x5_tiocmset,
-	.write_room 		= spcp8x5_write_room,
-	.read_bulk_callback 	= spcp8x5_read_bulk_callback,
-	.write_bulk_callback	= spcp8x5_write_bulk_callback,
-	.chars_in_buffer 	= spcp8x5_chars_in_buffer,
 	.attach 		= spcp8x5_startup,
 	.release 		= spcp8x5_release,
+	.process_read_urb	= spcp8x5_process_read_urb,
 };
 
 static int __init spcp8x5_init(void)
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index e1bfda3..90979a1 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -30,7 +30,7 @@
 #include <linux/spinlock.h>
 #include <linux/ioctl.h>
 #include <linux/serial.h>
-#include <linux/circ_buf.h>
+#include <linux/kfifo.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
 #include <linux/usb.h>
@@ -40,7 +40,7 @@
 
 /* Defines */
 
-#define TI_DRIVER_VERSION	"v0.9"
+#define TI_DRIVER_VERSION	"v0.10"
 #define TI_DRIVER_AUTHOR	"Al Borchers <alborchers@steinerpoint.com>"
 #define TI_DRIVER_DESC		"TI USB 3410/5052 Serial Driver"
 
@@ -82,7 +82,7 @@
 	spinlock_t		tp_lock;
 	int			tp_read_urb_state;
 	int			tp_write_urb_in_use;
-	struct circ_buf		*tp_write_buf;
+	struct kfifo		write_fifo;
 };
 
 struct ti_device {
@@ -144,15 +144,6 @@
 
 static int ti_download_firmware(struct ti_device *tdev);
 
-/* circular buffer */
-static struct circ_buf *ti_buf_alloc(void);
-static void ti_buf_free(struct circ_buf *cb);
-static void ti_buf_clear(struct circ_buf *cb);
-static int ti_buf_data_avail(struct circ_buf *cb);
-static int ti_buf_space_avail(struct circ_buf *cb);
-static int ti_buf_put(struct circ_buf *cb, const char *buf, int count);
-static int ti_buf_get(struct circ_buf *cb, char *buf, int count);
-
 
 /* Data */
 
@@ -450,8 +441,8 @@
 		tport->tp_closing_wait = closing_wait;
 		init_waitqueue_head(&tport->tp_msr_wait);
 		init_waitqueue_head(&tport->tp_write_wait);
-		tport->tp_write_buf = ti_buf_alloc();
-		if (tport->tp_write_buf == NULL) {
+		if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE,
+								GFP_KERNEL)) {
 			dev_err(&dev->dev, "%s - out of memory\n", __func__);
 			kfree(tport);
 			status = -ENOMEM;
@@ -468,7 +459,7 @@
 free_tports:
 	for (--i; i >= 0; --i) {
 		tport = usb_get_serial_port_data(serial->port[i]);
-		ti_buf_free(tport->tp_write_buf);
+		kfifo_free(&tport->write_fifo);
 		kfree(tport);
 		usb_set_serial_port_data(serial->port[i], NULL);
 	}
@@ -490,7 +481,7 @@
 	for (i = 0; i < serial->num_ports; ++i) {
 		tport = usb_get_serial_port_data(serial->port[i]);
 		if (tport) {
-			ti_buf_free(tport->tp_write_buf);
+			kfifo_free(&tport->write_fifo);
 			kfree(tport);
 		}
 	}
@@ -701,7 +692,6 @@
 			const unsigned char *data, int count)
 {
 	struct ti_port *tport = usb_get_serial_port_data(port);
-	unsigned long flags;
 
 	dbg("%s - port %d", __func__, port->number);
 
@@ -713,10 +703,8 @@
 	if (tport == NULL || !tport->tp_is_open)
 		return -ENODEV;
 
-	spin_lock_irqsave(&tport->tp_lock, flags);
-	count = ti_buf_put(tport->tp_write_buf, data, count);
-	spin_unlock_irqrestore(&tport->tp_lock, flags);
-
+	count = kfifo_in_locked(&tport->write_fifo, data, count,
+							&tport->tp_lock);
 	ti_send(tport);
 
 	return count;
@@ -736,7 +724,7 @@
 		return 0;
 
 	spin_lock_irqsave(&tport->tp_lock, flags);
-	room = ti_buf_space_avail(tport->tp_write_buf);
+	room = kfifo_avail(&tport->write_fifo);
 	spin_unlock_irqrestore(&tport->tp_lock, flags);
 
 	dbg("%s - returns %d", __func__, room);
@@ -757,7 +745,7 @@
 		return 0;
 
 	spin_lock_irqsave(&tport->tp_lock, flags);
-	chars = ti_buf_data_avail(tport->tp_write_buf);
+	chars = kfifo_len(&tport->write_fifo);
 	spin_unlock_irqrestore(&tport->tp_lock, flags);
 
 	dbg("%s - returns %d", __func__, chars);
@@ -1309,7 +1297,7 @@
 	if (tport->tp_write_urb_in_use)
 		goto unlock;
 
-	count = ti_buf_get(tport->tp_write_buf,
+	count = kfifo_out(&tport->write_fifo,
 				port->write_urb->transfer_buffer,
 				port->bulk_out_size);
 
@@ -1504,7 +1492,7 @@
 	add_wait_queue(&tport->tp_write_wait, &wait);
 	for (;;) {
 		set_current_state(TASK_INTERRUPTIBLE);
-		if (ti_buf_data_avail(tport->tp_write_buf) == 0
+		if (kfifo_len(&tport->write_fifo) == 0
 		|| timeout == 0 || signal_pending(current)
 		|| tdev->td_urb_error
 		|| port->serial->disconnected)  /* disconnect */
@@ -1518,7 +1506,7 @@
 
 	/* flush any remaining data in the buffer */
 	if (flush)
-		ti_buf_clear(tport->tp_write_buf);
+		kfifo_reset_out(&tport->write_fifo);
 
 	spin_unlock_irq(&tport->tp_lock);
 
@@ -1761,142 +1749,3 @@
 
 	return 0;
 }
-
-
-/* Circular Buffer Functions */
-
-/*
- * ti_buf_alloc
- *
- * Allocate a circular buffer and all associated memory.
- */
-
-static struct circ_buf *ti_buf_alloc(void)
-{
-	struct circ_buf *cb;
-
-	cb = kmalloc(sizeof(struct circ_buf), GFP_KERNEL);
-	if (cb == NULL)
-		return NULL;
-
-	cb->buf = kmalloc(TI_WRITE_BUF_SIZE, GFP_KERNEL);
-	if (cb->buf == NULL) {
-		kfree(cb);
-		return NULL;
-	}
-
-	ti_buf_clear(cb);
-
-	return cb;
-}
-
-
-/*
- * ti_buf_free
- *
- * Free the buffer and all associated memory.
- */
-
-static void ti_buf_free(struct circ_buf *cb)
-{
-	kfree(cb->buf);
-	kfree(cb);
-}
-
-
-/*
- * ti_buf_clear
- *
- * Clear out all data in the circular buffer.
- */
-
-static void ti_buf_clear(struct circ_buf *cb)
-{
-	cb->head = cb->tail = 0;
-}
-
-
-/*
- * ti_buf_data_avail
- *
- * Return the number of bytes of data available in the circular
- * buffer.
- */
-
-static int ti_buf_data_avail(struct circ_buf *cb)
-{
-	return CIRC_CNT(cb->head, cb->tail, TI_WRITE_BUF_SIZE);
-}
-
-
-/*
- * ti_buf_space_avail
- *
- * Return the number of bytes of space available in the circular
- * buffer.
- */
-
-static int ti_buf_space_avail(struct circ_buf *cb)
-{
-	return CIRC_SPACE(cb->head, cb->tail, TI_WRITE_BUF_SIZE);
-}
-
-
-/*
- * ti_buf_put
- *
- * Copy data data from a user buffer and put it into the circular buffer.
- * Restrict to the amount of space available.
- *
- * Return the number of bytes copied.
- */
-
-static int ti_buf_put(struct circ_buf *cb, const char *buf, int count)
-{
-	int c, ret = 0;
-
-	while (1) {
-		c = CIRC_SPACE_TO_END(cb->head, cb->tail, TI_WRITE_BUF_SIZE);
-		if (count < c)
-			c = count;
-		if (c <= 0)
-			break;
-		memcpy(cb->buf + cb->head, buf, c);
-		cb->head = (cb->head + c) & (TI_WRITE_BUF_SIZE-1);
-		buf += c;
-		count -= c;
-		ret += c;
-	}
-
-	return ret;
-}
-
-
-/*
- * ti_buf_get
- *
- * Get data from the circular buffer and copy to the given buffer.
- * Restrict to the amount of data available.
- *
- * Return the number of bytes copied.
- */
-
-static int ti_buf_get(struct circ_buf *cb, char *buf, int count)
-{
-	int c, ret = 0;
-
-	while (1) {
-		c = CIRC_CNT_TO_END(cb->head, cb->tail, TI_WRITE_BUF_SIZE);
-		if (count < c)
-			c = count;
-		if (c <= 0)
-			break;
-		memcpy(buf, cb->buf + cb->tail, c);
-		cb->tail = (cb->tail + c) & (TI_WRITE_BUF_SIZE-1);
-		buf += c;
-		count -= c;
-		ret += c;
-	}
-
-	return ret;
-}
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 3873660..941c2d4 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -289,7 +289,7 @@
 	 * The console is magical.  Do not hang up the console hardware
 	 * or there will be tears.
 	 */
-	if (port->console)
+	if (port->port.console)
 		return;
 	if (drv->close)
 		drv->close(port);
@@ -328,7 +328,7 @@
 	/* The console is magical.  Do not hang up the console hardware
 	 * or there will be tears.
 	 */
-	if (port->console)
+	if (port->port.console)
 		return;
 
 	dbg("%s - port %d", __func__, port->number);
@@ -548,8 +548,12 @@
 
 static void kill_traffic(struct usb_serial_port *port)
 {
+	int i;
+
 	usb_kill_urb(port->read_urb);
 	usb_kill_urb(port->write_urb);
+	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+		usb_kill_urb(port->write_urbs[i]);
 	/*
 	 * This is tricky.
 	 * Some drivers submit the read_urb in the
@@ -568,6 +572,7 @@
 static void port_release(struct device *dev)
 {
 	struct usb_serial_port *port = to_usb_serial_port(dev);
+	int i;
 
 	dbg ("%s - %s", __func__, dev_name(dev));
 
@@ -582,6 +587,10 @@
 	usb_free_urb(port->write_urb);
 	usb_free_urb(port->interrupt_in_urb);
 	usb_free_urb(port->interrupt_out_urb);
+	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {
+		usb_free_urb(port->write_urbs[i]);
+		kfree(port->bulk_out_buffers[i]);
+	}
 	kfifo_free(&port->write_fifo);
 	kfree(port->bulk_in_buffer);
 	kfree(port->bulk_out_buffer);
@@ -901,7 +910,9 @@
 			dev_err(&interface->dev, "No free urbs available\n");
 			goto probe_error;
 		}
-		buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+		buffer_size = serial->type->bulk_in_size;
+		if (!buffer_size)
+			buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
 		port->bulk_in_size = buffer_size;
 		port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
 		port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -918,6 +929,8 @@
 	}
 
 	for (i = 0; i < num_bulk_out; ++i) {
+		int j;
+
 		endpoint = bulk_out_endpoint[i];
 		port = serial->port[i];
 		port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -927,7 +940,9 @@
 		}
 		if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
 			goto probe_error;
-		buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+		buffer_size = serial->type->bulk_out_size;
+		if (!buffer_size)
+			buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
 		port->bulk_out_size = buffer_size;
 		port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
 		port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -941,6 +956,28 @@
 					endpoint->bEndpointAddress),
 				port->bulk_out_buffer, buffer_size,
 				serial->type->write_bulk_callback, port);
+		for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) {
+			set_bit(j, &port->write_urbs_free);
+			port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
+			if (!port->write_urbs[j]) {
+				dev_err(&interface->dev,
+						"No free urbs available\n");
+				goto probe_error;
+			}
+			port->bulk_out_buffers[j] = kmalloc(buffer_size,
+								GFP_KERNEL);
+			if (!port->bulk_out_buffers[j]) {
+				dev_err(&interface->dev,
+					"Couldn't allocate bulk_out_buffer\n");
+				goto probe_error;
+			}
+			usb_fill_bulk_urb(port->write_urbs[j], dev,
+					usb_sndbulkpipe(dev,
+						endpoint->bEndpointAddress),
+					port->bulk_out_buffers[j], buffer_size,
+					serial->type->write_bulk_callback,
+					port);
+		}
 	}
 
 	if (serial->type->read_int_callback) {
@@ -1294,6 +1331,8 @@
 	set_to_generic_if_null(device, write_bulk_callback);
 	set_to_generic_if_null(device, disconnect);
 	set_to_generic_if_null(device, release);
+	set_to_generic_if_null(device, process_read_urb);
+	set_to_generic_if_null(device, prepare_write_buffer);
 }
 
 int usb_serial_register(struct usb_serial_driver *driver)
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h
new file mode 100644
index 0000000..2be298a
--- /dev/null
+++ b/drivers/usb/serial/usb-wwan.h
@@ -0,0 +1,67 @@
+/*
+ * Definitions for USB serial mobile broadband cards
+ */
+
+#ifndef __LINUX_USB_USB_WWAN
+#define __LINUX_USB_USB_WWAN
+
+extern void usb_wwan_dtr_rts(struct usb_serial_port *port, int on);
+extern int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port);
+extern void usb_wwan_close(struct usb_serial_port *port);
+extern int usb_wwan_startup(struct usb_serial *serial);
+extern void usb_wwan_disconnect(struct usb_serial *serial);
+extern void usb_wwan_release(struct usb_serial *serial);
+extern int usb_wwan_write_room(struct tty_struct *tty);
+extern void usb_wwan_set_termios(struct tty_struct *tty,
+				 struct usb_serial_port *port,
+				 struct ktermios *old);
+extern int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file);
+extern int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file,
+			     unsigned int set, unsigned int clear);
+extern int usb_wwan_send_setup(struct usb_serial_port *port);
+extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
+			  const unsigned char *buf, int count);
+extern int usb_wwan_chars_in_buffer(struct tty_struct *tty);
+#ifdef CONFIG_PM
+extern int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message);
+extern int usb_wwan_resume(struct usb_serial *serial);
+#endif
+
+/* per port private data */
+
+#define N_IN_URB 4
+#define N_OUT_URB 4
+#define IN_BUFLEN 4096
+#define OUT_BUFLEN 4096
+
+struct usb_wwan_intf_private {
+	spinlock_t susp_lock;
+	unsigned int suspended:1;
+	int in_flight;
+	int (*send_setup) (struct usb_serial_port *port);
+	void *private;
+};
+
+struct usb_wwan_port_private {
+	/* Input endpoints and buffer for this port */
+	struct urb *in_urbs[N_IN_URB];
+	u8 *in_buffer[N_IN_URB];
+	/* Output endpoints and buffer for this port */
+	struct urb *out_urbs[N_OUT_URB];
+	u8 *out_buffer[N_OUT_URB];
+	unsigned long out_busy;	/* Bit vector of URBs in use */
+	int opened;
+	struct usb_anchor delayed;
+
+	/* Settings for the port */
+	int rts_state;		/* Handshaking pins (outputs) */
+	int dtr_state;
+	int cts_state;		/* Handshaking pins (inputs) */
+	int dsr_state;
+	int dcd_state;
+	int ri_state;
+
+	unsigned long tx_start_time[N_OUT_URB];
+};
+
+#endif /* __LINUX_USB_USB_WWAN */
diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index 28026b4..f2ed6a3 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -16,7 +16,6 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-#define URB_DEBUG_MAX_IN_FLIGHT_URBS	4000
 #define USB_DEBUG_MAX_PACKET_SIZE	8
 #define USB_DEBUG_BRK_SIZE		8
 static char USB_DEBUG_BRK[USB_DEBUG_BRK_SIZE] = {
@@ -44,12 +43,6 @@
 	.no_dynamic_id = 	1,
 };
 
-static int usb_debug_open(struct tty_struct *tty, struct usb_serial_port *port)
-{
-	port->bulk_out_size = USB_DEBUG_MAX_PACKET_SIZE;
-	return usb_serial_generic_open(tty, port);
-}
-
 /* This HW really does not support a serial break, so one will be
  * emulated when ever the break state is set to true.
  */
@@ -69,7 +62,7 @@
 	    memcmp(urb->transfer_buffer, USB_DEBUG_BRK,
 		   USB_DEBUG_BRK_SIZE) == 0) {
 		usb_serial_handle_break(port);
-		usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC);
+		usb_serial_generic_submit_read_urb(port, GFP_ATOMIC);
 		return;
 	}
 
@@ -83,8 +76,7 @@
 	},
 	.id_table =		id_table,
 	.num_ports =		1,
-	.open =			usb_debug_open,
-	.max_in_flight_urbs =	URB_DEBUG_MAX_IN_FLIGHT_URBS,
+	.bulk_out_size =	USB_DEBUG_MAX_PACKET_SIZE,
 	.break_ctl =		usb_debug_break_ctl,
 	.read_bulk_callback =	usb_debug_read_bulk_callback,
 };
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
new file mode 100644
index 0000000..0c70b4a
--- /dev/null
+++ b/drivers/usb/serial/usb_wwan.c
@@ -0,0 +1,665 @@
+/*
+  USB Driver layer for GSM modems
+
+  Copyright (C) 2005  Matthias Urlichs <smurf@smurf.noris.de>
+
+  This driver is free software; you can redistribute it and/or modify
+  it under the terms of Version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
+
+  History: see the git log.
+
+  Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
+
+  This driver exists because the "normal" serial driver doesn't work too well
+  with GSM modems. Issues:
+  - data loss -- one single Receive URB is not nearly enough
+  - controlling the baud rate doesn't make sense
+*/
+
+#define DRIVER_VERSION "v0.7.2"
+#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
+#define DRIVER_DESC "USB Driver for GSM modems"
+
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include "usb-wwan.h"
+
+static int debug;
+
+void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)
+{
+	struct usb_serial *serial = port->serial;
+	struct usb_wwan_port_private *portdata;
+
+	struct usb_wwan_intf_private *intfdata;
+
+	dbg("%s", __func__);
+
+	intfdata = port->serial->private;
+
+	if (!intfdata->send_setup)
+		return;
+
+	portdata = usb_get_serial_port_data(port);
+	mutex_lock(&serial->disc_mutex);
+	portdata->rts_state = on;
+	portdata->dtr_state = on;
+	if (serial->dev)
+		intfdata->send_setup(port);
+	mutex_unlock(&serial->disc_mutex);
+}
+EXPORT_SYMBOL(usb_wwan_dtr_rts);
+
+void usb_wwan_set_termios(struct tty_struct *tty,
+			  struct usb_serial_port *port,
+			  struct ktermios *old_termios)
+{
+	struct usb_wwan_intf_private *intfdata = port->serial->private;
+
+	dbg("%s", __func__);
+
+	/* Doesn't support option setting */
+	tty_termios_copy_hw(tty->termios, old_termios);
+
+	if (intfdata->send_setup)
+		intfdata->send_setup(port);
+}
+EXPORT_SYMBOL(usb_wwan_set_termios);
+
+int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	struct usb_serial_port *port = tty->driver_data;
+	unsigned int value;
+	struct usb_wwan_port_private *portdata;
+
+	portdata = usb_get_serial_port_data(port);
+
+	value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
+	    ((portdata->dtr_state) ? TIOCM_DTR : 0) |
+	    ((portdata->cts_state) ? TIOCM_CTS : 0) |
+	    ((portdata->dsr_state) ? TIOCM_DSR : 0) |
+	    ((portdata->dcd_state) ? TIOCM_CAR : 0) |
+	    ((portdata->ri_state) ? TIOCM_RNG : 0);
+
+	return value;
+}
+EXPORT_SYMBOL(usb_wwan_tiocmget);
+
+int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file,
+		      unsigned int set, unsigned int clear)
+{
+	struct usb_serial_port *port = tty->driver_data;
+	struct usb_wwan_port_private *portdata;
+	struct usb_wwan_intf_private *intfdata;
+
+	portdata = usb_get_serial_port_data(port);
+	intfdata = port->serial->private;
+
+	if (!intfdata->send_setup)
+		return -EINVAL;
+
+	/* FIXME: what locks portdata fields ? */
+	if (set & TIOCM_RTS)
+		portdata->rts_state = 1;
+	if (set & TIOCM_DTR)
+		portdata->dtr_state = 1;
+
+	if (clear & TIOCM_RTS)
+		portdata->rts_state = 0;
+	if (clear & TIOCM_DTR)
+		portdata->dtr_state = 0;
+	return intfdata->send_setup(port);
+}
+EXPORT_SYMBOL(usb_wwan_tiocmset);
+
+/* Write */
+int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
+		   const unsigned char *buf, int count)
+{
+	struct usb_wwan_port_private *portdata;
+	struct usb_wwan_intf_private *intfdata;
+	int i;
+	int left, todo;
+	struct urb *this_urb = NULL;	/* spurious */
+	int err;
+	unsigned long flags;
+
+	portdata = usb_get_serial_port_data(port);
+	intfdata = port->serial->private;
+
+	dbg("%s: write (%d chars)", __func__, count);
+
+	i = 0;
+	left = count;
+	for (i = 0; left > 0 && i < N_OUT_URB; i++) {
+		todo = left;
+		if (todo > OUT_BUFLEN)
+			todo = OUT_BUFLEN;
+
+		this_urb = portdata->out_urbs[i];
+		if (test_and_set_bit(i, &portdata->out_busy)) {
+			if (time_before(jiffies,
+					portdata->tx_start_time[i] + 10 * HZ))
+				continue;
+			usb_unlink_urb(this_urb);
+			continue;
+		}
+		dbg("%s: endpoint %d buf %d", __func__,
+		    usb_pipeendpoint(this_urb->pipe), i);
+
+		err = usb_autopm_get_interface_async(port->serial->interface);
+		if (err < 0)
+			break;
+
+		/* send the data */
+		memcpy(this_urb->transfer_buffer, buf, todo);
+		this_urb->transfer_buffer_length = todo;
+
+		spin_lock_irqsave(&intfdata->susp_lock, flags);
+		if (intfdata->suspended) {
+			usb_anchor_urb(this_urb, &portdata->delayed);
+			spin_unlock_irqrestore(&intfdata->susp_lock, flags);
+		} else {
+			intfdata->in_flight++;
+			spin_unlock_irqrestore(&intfdata->susp_lock, flags);
+			err = usb_submit_urb(this_urb, GFP_ATOMIC);
+			if (err) {
+				dbg("usb_submit_urb %p (write bulk) failed "
+				    "(%d)", this_urb, err);
+				clear_bit(i, &portdata->out_busy);
+				spin_lock_irqsave(&intfdata->susp_lock, flags);
+				intfdata->in_flight--;
+				spin_unlock_irqrestore(&intfdata->susp_lock,
+						       flags);
+				continue;
+			}
+		}
+
+		portdata->tx_start_time[i] = jiffies;
+		buf += todo;
+		left -= todo;
+	}
+
+	count -= left;
+	dbg("%s: wrote (did %d)", __func__, count);
+	return count;
+}
+EXPORT_SYMBOL(usb_wwan_write);
+
+static void usb_wwan_indat_callback(struct urb *urb)
+{
+	int err;
+	int endpoint;
+	struct usb_serial_port *port;
+	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+	int status = urb->status;
+
+	dbg("%s: %p", __func__, urb);
+
+	endpoint = usb_pipeendpoint(urb->pipe);
+	port = urb->context;
+
+	if (status) {
+		dbg("%s: nonzero status: %d on endpoint %02x.",
+		    __func__, status, endpoint);
+	} else {
+		tty = tty_port_tty_get(&port->port);
+		if (urb->actual_length) {
+			tty_insert_flip_string(tty, data, urb->actual_length);
+			tty_flip_buffer_push(tty);
+		} else
+			dbg("%s: empty read urb received", __func__);
+		tty_kref_put(tty);
+
+		/* Resubmit urb so we continue receiving */
+		if (status != -ESHUTDOWN) {
+			err = usb_submit_urb(urb, GFP_ATOMIC);
+			if (err && err != -EPERM)
+				printk(KERN_ERR "%s: resubmit read urb failed. "
+				       "(%d)", __func__, err);
+			else
+				usb_mark_last_busy(port->serial->dev);
+		}
+
+	}
+	return;
+}
+
+static void usb_wwan_outdat_callback(struct urb *urb)
+{
+	struct usb_serial_port *port;
+	struct usb_wwan_port_private *portdata;
+	struct usb_wwan_intf_private *intfdata;
+	int i;
+
+	dbg("%s", __func__);
+
+	port = urb->context;
+	intfdata = port->serial->private;
+
+	usb_serial_port_softint(port);
+	usb_autopm_put_interface_async(port->serial->interface);
+	portdata = usb_get_serial_port_data(port);
+	spin_lock(&intfdata->susp_lock);
+	intfdata->in_flight--;
+	spin_unlock(&intfdata->susp_lock);
+
+	for (i = 0; i < N_OUT_URB; ++i) {
+		if (portdata->out_urbs[i] == urb) {
+			smp_mb__before_clear_bit();
+			clear_bit(i, &portdata->out_busy);
+			break;
+		}
+	}
+}
+
+int usb_wwan_write_room(struct tty_struct *tty)
+{
+	struct usb_serial_port *port = tty->driver_data;
+	struct usb_wwan_port_private *portdata;
+	int i;
+	int data_len = 0;
+	struct urb *this_urb;
+
+	portdata = usb_get_serial_port_data(port);
+
+	for (i = 0; i < N_OUT_URB; i++) {
+		this_urb = portdata->out_urbs[i];
+		if (this_urb && !test_bit(i, &portdata->out_busy))
+			data_len += OUT_BUFLEN;
+	}
+
+	dbg("%s: %d", __func__, data_len);
+	return data_len;
+}
+EXPORT_SYMBOL(usb_wwan_write_room);
+
+int usb_wwan_chars_in_buffer(struct tty_struct *tty)
+{
+	struct usb_serial_port *port = tty->driver_data;
+	struct usb_wwan_port_private *portdata;
+	int i;
+	int data_len = 0;
+	struct urb *this_urb;
+
+	portdata = usb_get_serial_port_data(port);
+
+	for (i = 0; i < N_OUT_URB; i++) {
+		this_urb = portdata->out_urbs[i];
+		/* FIXME: This locking is insufficient as this_urb may
+		   go unused during the test */
+		if (this_urb && test_bit(i, &portdata->out_busy))
+			data_len += this_urb->transfer_buffer_length;
+	}
+	dbg("%s: %d", __func__, data_len);
+	return data_len;
+}
+EXPORT_SYMBOL(usb_wwan_chars_in_buffer);
+
+int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+	struct usb_wwan_port_private *portdata;
+	struct usb_wwan_intf_private *intfdata;
+	struct usb_serial *serial = port->serial;
+	int i, err;
+	struct urb *urb;
+
+	portdata = usb_get_serial_port_data(port);
+	intfdata = serial->private;
+
+	dbg("%s", __func__);
+
+	/* Start reading from the IN endpoint */
+	for (i = 0; i < N_IN_URB; i++) {
+		urb = portdata->in_urbs[i];
+		if (!urb)
+			continue;
+		err = usb_submit_urb(urb, GFP_KERNEL);
+		if (err) {
+			dbg("%s: submit urb %d failed (%d) %d",
+			    __func__, i, err, urb->transfer_buffer_length);
+		}
+	}
+
+	if (intfdata->send_setup)
+		intfdata->send_setup(port);
+
+	serial->interface->needs_remote_wakeup = 1;
+	spin_lock_irq(&intfdata->susp_lock);
+	portdata->opened = 1;
+	spin_unlock_irq(&intfdata->susp_lock);
+	usb_autopm_put_interface(serial->interface);
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_wwan_open);
+
+void usb_wwan_close(struct usb_serial_port *port)
+{
+	int i;
+	struct usb_serial *serial = port->serial;
+	struct usb_wwan_port_private *portdata;
+	struct usb_wwan_intf_private *intfdata = port->serial->private;
+
+	dbg("%s", __func__);
+	portdata = usb_get_serial_port_data(port);
+
+	if (serial->dev) {
+		/* Stop reading/writing urbs */
+		spin_lock_irq(&intfdata->susp_lock);
+		portdata->opened = 0;
+		spin_unlock_irq(&intfdata->susp_lock);
+
+		for (i = 0; i < N_IN_URB; i++)
+			usb_kill_urb(portdata->in_urbs[i]);
+		for (i = 0; i < N_OUT_URB; i++)
+			usb_kill_urb(portdata->out_urbs[i]);
+		usb_autopm_get_interface(serial->interface);
+		serial->interface->needs_remote_wakeup = 0;
+	}
+}
+EXPORT_SYMBOL(usb_wwan_close);
+
+/* Helper functions used by usb_wwan_setup_urbs */
+static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint,
+				      int dir, void *ctx, char *buf, int len,
+				      void (*callback) (struct urb *))
+{
+	struct urb *urb;
+
+	if (endpoint == -1)
+		return NULL;	/* endpoint not needed */
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);	/* No ISO */
+	if (urb == NULL) {
+		dbg("%s: alloc for endpoint %d failed.", __func__, endpoint);
+		return NULL;
+	}
+
+	/* Fill URB using supplied data. */
+	usb_fill_bulk_urb(urb, serial->dev,
+			  usb_sndbulkpipe(serial->dev, endpoint) | dir,
+			  buf, len, callback, ctx);
+
+	return urb;
+}
+
+/* Setup urbs */
+static void usb_wwan_setup_urbs(struct usb_serial *serial)
+{
+	int i, j;
+	struct usb_serial_port *port;
+	struct usb_wwan_port_private *portdata;
+
+	dbg("%s", __func__);
+
+	for (i = 0; i < serial->num_ports; i++) {
+		port = serial->port[i];
+		portdata = usb_get_serial_port_data(port);
+
+		/* Do indat endpoints first */
+		for (j = 0; j < N_IN_URB; ++j) {
+			portdata->in_urbs[j] = usb_wwan_setup_urb(serial,
+								  port->
+								  bulk_in_endpointAddress,
+								  USB_DIR_IN,
+								  port,
+								  portdata->
+								  in_buffer[j],
+								  IN_BUFLEN,
+								  usb_wwan_indat_callback);
+		}
+
+		/* outdat endpoints */
+		for (j = 0; j < N_OUT_URB; ++j) {
+			portdata->out_urbs[j] = usb_wwan_setup_urb(serial,
+								   port->
+								   bulk_out_endpointAddress,
+								   USB_DIR_OUT,
+								   port,
+								   portdata->
+								   out_buffer
+								   [j],
+								   OUT_BUFLEN,
+								   usb_wwan_outdat_callback);
+		}
+	}
+}
+
+int usb_wwan_startup(struct usb_serial *serial)
+{
+	int i, j, err;
+	struct usb_serial_port *port;
+	struct usb_wwan_port_private *portdata;
+	u8 *buffer;
+
+	dbg("%s", __func__);
+
+	/* Now setup per port private data */
+	for (i = 0; i < serial->num_ports; i++) {
+		port = serial->port[i];
+		portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
+		if (!portdata) {
+			dbg("%s: kmalloc for usb_wwan_port_private (%d) failed!.",
+			    __func__, i);
+			return 1;
+		}
+		init_usb_anchor(&portdata->delayed);
+
+		for (j = 0; j < N_IN_URB; j++) {
+			buffer = (u8 *) __get_free_page(GFP_KERNEL);
+			if (!buffer)
+				goto bail_out_error;
+			portdata->in_buffer[j] = buffer;
+		}
+
+		for (j = 0; j < N_OUT_URB; j++) {
+			buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL);
+			if (!buffer)
+				goto bail_out_error2;
+			portdata->out_buffer[j] = buffer;
+		}
+
+		usb_set_serial_port_data(port, portdata);
+
+		if (!port->interrupt_in_urb)
+			continue;
+		err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+		if (err)
+			dbg("%s: submit irq_in urb failed %d", __func__, err);
+	}
+	usb_wwan_setup_urbs(serial);
+	return 0;
+
+bail_out_error2:
+	for (j = 0; j < N_OUT_URB; j++)
+		kfree(portdata->out_buffer[j]);
+bail_out_error:
+	for (j = 0; j < N_IN_URB; j++)
+		if (portdata->in_buffer[j])
+			free_page((unsigned long)portdata->in_buffer[j]);
+	kfree(portdata);
+	return 1;
+}
+EXPORT_SYMBOL(usb_wwan_startup);
+
+static void stop_read_write_urbs(struct usb_serial *serial)
+{
+	int i, j;
+	struct usb_serial_port *port;
+	struct usb_wwan_port_private *portdata;
+
+	/* Stop reading/writing urbs */
+	for (i = 0; i < serial->num_ports; ++i) {
+		port = serial->port[i];
+		portdata = usb_get_serial_port_data(port);
+		for (j = 0; j < N_IN_URB; j++)
+			usb_kill_urb(portdata->in_urbs[j]);
+		for (j = 0; j < N_OUT_URB; j++)
+			usb_kill_urb(portdata->out_urbs[j]);
+	}
+}
+
+void usb_wwan_disconnect(struct usb_serial *serial)
+{
+	dbg("%s", __func__);
+
+	stop_read_write_urbs(serial);
+}
+EXPORT_SYMBOL(usb_wwan_disconnect);
+
+void usb_wwan_release(struct usb_serial *serial)
+{
+	int i, j;
+	struct usb_serial_port *port;
+	struct usb_wwan_port_private *portdata;
+
+	dbg("%s", __func__);
+
+	/* Now free them */
+	for (i = 0; i < serial->num_ports; ++i) {
+		port = serial->port[i];
+		portdata = usb_get_serial_port_data(port);
+
+		for (j = 0; j < N_IN_URB; j++) {
+			usb_free_urb(portdata->in_urbs[j]);
+			free_page((unsigned long)
+				  portdata->in_buffer[j]);
+			portdata->in_urbs[j] = NULL;
+		}
+		for (j = 0; j < N_OUT_URB; j++) {
+			usb_free_urb(portdata->out_urbs[j]);
+			kfree(portdata->out_buffer[j]);
+			portdata->out_urbs[j] = NULL;
+		}
+	}
+
+	/* Now free per port private data */
+	for (i = 0; i < serial->num_ports; i++) {
+		port = serial->port[i];
+		kfree(usb_get_serial_port_data(port));
+	}
+}
+EXPORT_SYMBOL(usb_wwan_release);
+
+#ifdef CONFIG_PM
+int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
+{
+	struct usb_wwan_intf_private *intfdata = serial->private;
+	int b;
+
+	dbg("%s entered", __func__);
+
+	if (message.event & PM_EVENT_AUTO) {
+		spin_lock_irq(&intfdata->susp_lock);
+		b = intfdata->in_flight;
+		spin_unlock_irq(&intfdata->susp_lock);
+
+		if (b)
+			return -EBUSY;
+	}
+
+	spin_lock_irq(&intfdata->susp_lock);
+	intfdata->suspended = 1;
+	spin_unlock_irq(&intfdata->susp_lock);
+	stop_read_write_urbs(serial);
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_wwan_suspend);
+
+static void play_delayed(struct usb_serial_port *port)
+{
+	struct usb_wwan_intf_private *data;
+	struct usb_wwan_port_private *portdata;
+	struct urb *urb;
+	int err;
+
+	portdata = usb_get_serial_port_data(port);
+	data = port->serial->private;
+	while ((urb = usb_get_from_anchor(&portdata->delayed))) {
+		err = usb_submit_urb(urb, GFP_ATOMIC);
+		if (!err)
+			data->in_flight++;
+	}
+}
+
+int usb_wwan_resume(struct usb_serial *serial)
+{
+	int i, j;
+	struct usb_serial_port *port;
+	struct usb_wwan_intf_private *intfdata = serial->private;
+	struct usb_wwan_port_private *portdata;
+	struct urb *urb;
+	int err = 0;
+
+	dbg("%s entered", __func__);
+	/* get the interrupt URBs resubmitted unconditionally */
+	for (i = 0; i < serial->num_ports; i++) {
+		port = serial->port[i];
+		if (!port->interrupt_in_urb) {
+			dbg("%s: No interrupt URB for port %d", __func__, i);
+			continue;
+		}
+		err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
+		dbg("Submitted interrupt URB for port %d (result %d)", i, err);
+		if (err < 0) {
+			err("%s: Error %d for interrupt URB of port%d",
+			    __func__, err, i);
+			goto err_out;
+		}
+	}
+
+	for (i = 0; i < serial->num_ports; i++) {
+		/* walk all ports */
+		port = serial->port[i];
+		portdata = usb_get_serial_port_data(port);
+
+		/* skip closed ports */
+		spin_lock_irq(&intfdata->susp_lock);
+		if (!portdata->opened) {
+			spin_unlock_irq(&intfdata->susp_lock);
+			continue;
+		}
+
+		for (j = 0; j < N_IN_URB; j++) {
+			urb = portdata->in_urbs[j];
+			err = usb_submit_urb(urb, GFP_ATOMIC);
+			if (err < 0) {
+				err("%s: Error %d for bulk URB %d",
+				    __func__, err, i);
+				spin_unlock_irq(&intfdata->susp_lock);
+				goto err_out;
+			}
+		}
+		play_delayed(port);
+		spin_unlock_irq(&intfdata->susp_lock);
+	}
+	spin_lock_irq(&intfdata->susp_lock);
+	intfdata->suspended = 0;
+	spin_unlock_irq(&intfdata->susp_lock);
+err_out:
+	return err;
+}
+EXPORT_SYMBOL(usb_wwan_resume);
+#endif
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages");
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 0949427..eb76aae 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -38,17 +38,9 @@
 /* function prototypes for a handspring visor */
 static int  visor_open(struct tty_struct *tty, struct usb_serial_port *port);
 static void visor_close(struct usb_serial_port *port);
-static int  visor_write(struct tty_struct *tty, struct usb_serial_port *port,
-					const unsigned char *buf, int count);
-static int  visor_write_room(struct tty_struct *tty);
-static void visor_throttle(struct tty_struct *tty);
-static void visor_unthrottle(struct tty_struct *tty);
 static int  visor_probe(struct usb_serial *serial,
 					const struct usb_device_id *id);
 static int  visor_calc_num_ports(struct usb_serial *serial);
-static void visor_release(struct usb_serial *serial);
-static void visor_write_bulk_callback(struct urb *urb);
-static void visor_read_bulk_callback(struct urb *urb);
 static void visor_read_int_callback(struct urb *urb);
 static int  clie_3_5_startup(struct usb_serial *serial);
 static int  treo_attach(struct usb_serial *serial);
@@ -194,18 +186,14 @@
 	.usb_driver =		&visor_driver,
 	.id_table =		id_table,
 	.num_ports =		2,
+	.bulk_out_size =	256,
 	.open =			visor_open,
 	.close =		visor_close,
-	.throttle =		visor_throttle,
-	.unthrottle =		visor_unthrottle,
+	.throttle =		usb_serial_generic_throttle,
+	.unthrottle =		usb_serial_generic_unthrottle,
 	.attach =		treo_attach,
 	.probe =		visor_probe,
 	.calc_num_ports =	visor_calc_num_ports,
-	.release =		visor_release,
-	.write =		visor_write,
-	.write_room =		visor_write_room,
-	.write_bulk_callback =	visor_write_bulk_callback,
-	.read_bulk_callback =	visor_read_bulk_callback,
 	.read_int_callback =	visor_read_int_callback,
 };
 
@@ -219,18 +207,14 @@
 	.usb_driver =		&visor_driver,
 	.id_table =		clie_id_5_table,
 	.num_ports =		2,
+	.bulk_out_size =	256,
 	.open =			visor_open,
 	.close =		visor_close,
-	.throttle =		visor_throttle,
-	.unthrottle =		visor_unthrottle,
+	.throttle =		usb_serial_generic_throttle,
+	.unthrottle =		usb_serial_generic_unthrottle,
 	.attach =		clie_5_attach,
 	.probe =		visor_probe,
 	.calc_num_ports =	visor_calc_num_ports,
-	.release =		visor_release,
-	.write =		visor_write,
-	.write_room =		visor_write_room,
-	.write_bulk_callback =	visor_write_bulk_callback,
-	.read_bulk_callback =	visor_read_bulk_callback,
 	.read_int_callback =	visor_read_int_callback,
 };
 
@@ -244,39 +228,19 @@
 	.usb_driver =		&visor_driver,
 	.id_table =		clie_id_3_5_table,
 	.num_ports =		1,
+	.bulk_out_size =	256,
 	.open =			visor_open,
 	.close =		visor_close,
-	.throttle =		visor_throttle,
-	.unthrottle =		visor_unthrottle,
+	.throttle =		usb_serial_generic_throttle,
+	.unthrottle =		usb_serial_generic_unthrottle,
 	.attach =		clie_3_5_startup,
-	.write =		visor_write,
-	.write_room =		visor_write_room,
-	.write_bulk_callback =	visor_write_bulk_callback,
-	.read_bulk_callback =	visor_read_bulk_callback,
 };
 
-struct visor_private {
-	spinlock_t lock;
-	int bytes_in;
-	int bytes_out;
-	int outstanding_urbs;
-	unsigned char throttled;
-	unsigned char actually_throttled;
-};
-
-/* number of outstanding urbs to prevent userspace DoS from happening */
-#define URB_UPPER_LIMIT	42
-
-static int stats;
-
 /******************************************************************************
  * Handspring Visor specific driver functions
  ******************************************************************************/
 static int visor_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
-	struct usb_serial *serial = port->serial;
-	struct visor_private *priv = usb_get_serial_port_data(port);
-	unsigned long flags;
 	int result = 0;
 
 	dbg("%s - port %d", __func__, port->number);
@@ -287,26 +251,10 @@
 		return -ENODEV;
 	}
 
-	spin_lock_irqsave(&priv->lock, flags);
-	priv->bytes_in = 0;
-	priv->bytes_out = 0;
-	priv->throttled = 0;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	/* Start reading from the device */
-	usb_fill_bulk_urb(port->read_urb, serial->dev,
-			   usb_rcvbulkpipe(serial->dev,
-					    port->bulk_in_endpointAddress),
-			   port->read_urb->transfer_buffer,
-			   port->read_urb->transfer_buffer_length,
-			   visor_read_bulk_callback, port);
-	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-	if (result) {
-		dev_err(&port->dev,
-			"%s - failed submitting read urb, error %d\n",
-							__func__, result);
+	result = usb_serial_generic_open(tty, port);
+	if (result)
 		goto exit;
-	}
 
 	if (port->interrupt_in_urb) {
 		dbg("%s - adding interrupt input for treo", __func__);
@@ -323,13 +271,12 @@
 
 static void visor_close(struct usb_serial_port *port)
 {
-	struct visor_private *priv = usb_get_serial_port_data(port);
 	unsigned char *transfer_buffer;
 
 	dbg("%s - port %d", __func__, port->number);
 
 	/* shutdown our urbs */
-	usb_kill_urb(port->read_urb);
+	usb_serial_generic_close(port);
 	usb_kill_urb(port->interrupt_in_urb);
 
 	mutex_lock(&port->serial->disc_mutex);
@@ -346,192 +293,6 @@
 		}
 	}
 	mutex_unlock(&port->serial->disc_mutex);
-
-	if (stats)
-		dev_info(&port->dev, "Bytes In = %d  Bytes Out = %d\n",
-			 priv->bytes_in, priv->bytes_out);
-}
-
-
-static int visor_write(struct tty_struct *tty, struct usb_serial_port *port,
-					const unsigned char *buf, int count)
-{
-	struct visor_private *priv = usb_get_serial_port_data(port);
-	struct usb_serial *serial = port->serial;
-	struct urb *urb;
-	unsigned char *buffer;
-	unsigned long flags;
-	int status;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (priv->outstanding_urbs > URB_UPPER_LIMIT) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		dbg("%s - write limit hit", __func__);
-		return 0;
-	}
-	priv->outstanding_urbs++;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	buffer = kmalloc(count, GFP_ATOMIC);
-	if (!buffer) {
-		dev_err(&port->dev, "out of memory\n");
-		count = -ENOMEM;
-		goto error_no_buffer;
-	}
-
-	urb = usb_alloc_urb(0, GFP_ATOMIC);
-	if (!urb) {
-		dev_err(&port->dev, "no more free urbs\n");
-		count = -ENOMEM;
-		goto error_no_urb;
-	}
-
-	memcpy(buffer, buf, count);
-
-	usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
-
-	usb_fill_bulk_urb(urb, serial->dev,
-			   usb_sndbulkpipe(serial->dev,
-					    port->bulk_out_endpointAddress),
-			   buffer, count,
-			   visor_write_bulk_callback, port);
-
-	/* send it down the pipe */
-	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status) {
-		dev_err(&port->dev,
-		   "%s - usb_submit_urb(write bulk) failed with status = %d\n",
-							__func__, status);
-		count = status;
-		goto error;
-	} else {
-		spin_lock_irqsave(&priv->lock, flags);
-		priv->bytes_out += count;
-		spin_unlock_irqrestore(&priv->lock, flags);
-	}
-
-	/* we are done with this urb, so let the host driver
-	 * really free it when it is finished with it */
-	usb_free_urb(urb);
-
-	return count;
-error:
-	usb_free_urb(urb);
-error_no_urb:
-	kfree(buffer);
-error_no_buffer:
-	spin_lock_irqsave(&priv->lock, flags);
-	--priv->outstanding_urbs;
-	spin_unlock_irqrestore(&priv->lock, flags);
-	return count;
-}
-
-
-static int visor_write_room(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct visor_private *priv = usb_get_serial_port_data(port);
-	unsigned long flags;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	/*
-	 * We really can take anything the user throws at us
-	 * but let's pick a nice big number to tell the tty
-	 * layer that we have lots of free space, unless we don't.
-	 */
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		dbg("%s - write limit hit", __func__);
-		return 0;
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	return 2048;
-}
-
-
-static void visor_write_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = urb->context;
-	struct visor_private *priv = usb_get_serial_port_data(port);
-	int status = urb->status;
-	unsigned long flags;
-
-	/* free up the transfer buffer, as usb_free_urb() does not do this */
-	kfree(urb->transfer_buffer);
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (status)
-		dbg("%s - nonzero write bulk status received: %d",
-		    __func__, status);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	--priv->outstanding_urbs;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	usb_serial_port_softint(port);
-}
-
-
-static void visor_read_bulk_callback(struct urb *urb)
-{
-	struct usb_serial_port *port = urb->context;
-	struct visor_private *priv = usb_get_serial_port_data(port);
-	unsigned char *data = urb->transfer_buffer;
-	int status = urb->status;
-	struct tty_struct *tty;
-	int result;
-	int available_room = 0;
-
-	dbg("%s - port %d", __func__, port->number);
-
-	if (status) {
-		dbg("%s - nonzero read bulk status received: %d",
-		    __func__, status);
-		return;
-	}
-
-	usb_serial_debug_data(debug, &port->dev, __func__,
-						urb->actual_length, data);
-
-	if (urb->actual_length) {
-		tty = tty_port_tty_get(&port->port);
-		if (tty) {
-			tty_insert_flip_string(tty, data,
-						urb->actual_length);
-			tty_flip_buffer_push(tty);
-			tty_kref_put(tty);
-		}
-		spin_lock(&priv->lock);
-		if (tty)
-			priv->bytes_in += available_room;
-
-	} else {
-		spin_lock(&priv->lock);
-	}
-
-	/* Continue trying to always read if we should */
-	if (!priv->throttled) {
-		usb_fill_bulk_urb(port->read_urb, port->serial->dev,
-				   usb_rcvbulkpipe(port->serial->dev,
-					   port->bulk_in_endpointAddress),
-				   port->read_urb->transfer_buffer,
-				   port->read_urb->transfer_buffer_length,
-				   visor_read_bulk_callback, port);
-		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-		if (result)
-			dev_err(&port->dev,
-			    "%s - failed resubmitting read urb, error %d\n",
-							__func__, result);
-	} else
-		priv->actually_throttled = 1;
-	spin_unlock(&priv->lock);
 }
 
 static void visor_read_int_callback(struct urb *urb)
@@ -575,41 +336,6 @@
 							__func__, result);
 }
 
-static void visor_throttle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct visor_private *priv = usb_get_serial_port_data(port);
-
-	dbg("%s - port %d", __func__, port->number);
-	spin_lock_irq(&priv->lock);
-	priv->throttled = 1;
-	spin_unlock_irq(&priv->lock);
-}
-
-
-static void visor_unthrottle(struct tty_struct *tty)
-{
-	struct usb_serial_port *port = tty->driver_data;
-	struct visor_private *priv = usb_get_serial_port_data(port);
-	int result, was_throttled;
-
-	dbg("%s - port %d", __func__, port->number);
-	spin_lock_irq(&priv->lock);
-	priv->throttled = 0;
-	was_throttled = priv->actually_throttled;
-	priv->actually_throttled = 0;
-	spin_unlock_irq(&priv->lock);
-
-	if (was_throttled) {
-		port->read_urb->dev = port->serial->dev;
-		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-		if (result)
-			dev_err(&port->dev,
-				"%s - failed submitting read urb, error %d\n",
-							__func__, result);
-	}
-}
-
 static int palm_os_3_probe(struct usb_serial *serial,
 						const struct usb_device_id *id)
 {
@@ -777,28 +503,6 @@
 	return num_ports;
 }
 
-static int generic_startup(struct usb_serial *serial)
-{
-	struct usb_serial_port **ports = serial->port;
-	struct visor_private *priv;
-	int i;
-
-	for (i = 0; i < serial->num_ports; ++i) {
-		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-		if (!priv) {
-			while (i-- != 0) {
-				priv = usb_get_serial_port_data(ports[i]);
-				usb_set_serial_port_data(ports[i], NULL);
-				kfree(priv);
-			}
-			return -ENOMEM;
-		}
-		spin_lock_init(&priv->lock);
-		usb_set_serial_port_data(ports[i], priv);
-	}
-	return 0;
-}
-
 static int clie_3_5_startup(struct usb_serial *serial)
 {
 	struct device *dev = &serial->dev->dev;
@@ -849,7 +553,7 @@
 		goto out;
 	}
 
-	result = generic_startup(serial);
+	result = 0;
 out:
 	kfree(data);
 
@@ -867,7 +571,7 @@
 		(le16_to_cpu(serial->dev->descriptor.idVendor)
 						== KYOCERA_VENDOR_ID)) ||
 		(serial->num_interrupt_in == 0))
-		goto generic_startup;
+		return 0;
 
 	dbg("%s", __func__);
 
@@ -897,8 +601,7 @@
 	COPY_PORT(serial->port[1], swap_port);
 	kfree(swap_port);
 
-generic_startup:
-	return generic_startup(serial);
+	return 0;
 }
 
 static int clie_5_attach(struct usb_serial *serial)
@@ -921,20 +624,7 @@
 	serial->port[0]->bulk_out_endpointAddress =
 				serial->port[1]->bulk_out_endpointAddress;
 
-	return generic_startup(serial);
-}
-
-static void visor_release(struct usb_serial *serial)
-{
-	struct visor_private *priv;
-	int i;
-
-	dbg("%s", __func__);
-
-	for (i = 0; i < serial->num_ports; i++) {
-		priv = usb_get_serial_port_data(serial->port[i]);
-		kfree(priv);
-	}
+	return 0;
 }
 
 static int __init visor_init(void)
@@ -1018,8 +708,6 @@
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
-module_param(stats, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(stats, "Enables statistics or not");
 
 module_param(vendor, ushort, 0);
 MODULE_PARM_DESC(vendor, "User specified vendor ID");
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
index 57229cf..88db4d0 100644
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -9,8 +9,9 @@
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
  *
- * See Documentation/usb/usb-serial.txt for more information on using this driver
- * 
+ * See Documentation/usb/usb-serial.txt for more information on using this
+ * driver.
+ *
  */
 
 #ifndef __LINUX_USB_SERIAL_VISOR_H
@@ -65,7 +66,7 @@
 #define ACEECA_MEZ1000_ID		0x0001
 
 #define KYOCERA_VENDOR_ID		0x0C88
-#define KYOCERA_7135_ID			0x0021 
+#define KYOCERA_7135_ID			0x0021
 
 #define FOSSIL_VENDOR_ID		0x0E67
 #define FOSSIL_ABACUS_ID		0x0002
@@ -145,7 +146,7 @@
  * The maximum number of connections currently supported is 2
  */
 struct palm_ext_connection_info {
-	__u8 num_ports;		
+	__u8 num_ports;
 	__u8 endpoint_numbers_different;
 	__le16 reserved1;
 	struct {
diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c
new file mode 100644
index 0000000..f579672
--- /dev/null
+++ b/drivers/usb/serial/zio.c
@@ -0,0 +1,64 @@
+/*
+ * ZIO Motherboard USB driver
+ *
+ * Copyright (C) 2010 Zilogic Systems <code@zilogic.com>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License version
+ *	2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/uaccess.h>
+
+static const struct usb_device_id id_table[] = {
+	{ USB_DEVICE(0x1CBE, 0x0103) },
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver zio_driver = {
+	.name =		"zio",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	id_table,
+	.no_dynamic_id =	1,
+};
+
+static struct usb_serial_driver zio_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"zio",
+	},
+	.id_table =		id_table,
+	.usb_driver =		&zio_driver,
+	.num_ports =		1,
+};
+
+static int __init zio_init(void)
+{
+	int retval;
+
+	retval = usb_serial_register(&zio_device);
+	if (retval)
+		return retval;
+	retval = usb_register(&zio_driver);
+	if (retval)
+		usb_serial_deregister(&zio_device);
+	return retval;
+}
+
+static void __exit zio_exit(void)
+{
+	usb_deregister(&zio_driver);
+	usb_serial_deregister(&zio_device);
+}
+
+module_init(zio_init);
+module_exit(zio_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index fdba2f6..e9cbc14 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -490,13 +490,13 @@
 			  void* pointer, int value )
 {
 	union ata_cdb ata;
-	struct scsi_device srb_dev;
+	/* static to prevent this large struct being placed on the valuable stack */
+	static struct scsi_device srb_dev;
 	struct isd200_info *info = (struct isd200_info *)us->extra;
 	struct scsi_cmnd *srb = &info->srb;
 	int status;
 
 	memset(&ata, 0, sizeof(ata));
-	memset(&srb_dev, 0, sizeof(srb_dev));
 	srb->cmnd = info->cmnd;
 	srb->device = &srb_dev;
 	++srb->serial_number;
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index 198bb3e..1943be5 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -201,8 +201,8 @@
 	if (!onetouch || !input_dev)
 		goto fail1;
 
-	onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN,
-					  GFP_KERNEL, &onetouch->data_dma);
+	onetouch->data = usb_alloc_coherent(udev, ONETOUCH_PKT_LEN,
+					    GFP_KERNEL, &onetouch->data_dma);
 	if (!onetouch->data)
 		goto fail1;
 
@@ -264,8 +264,8 @@
 	return 0;
 
  fail3:	usb_free_urb(onetouch->irq);
- fail2:	usb_buffer_free(udev, ONETOUCH_PKT_LEN,
-			onetouch->data, onetouch->data_dma);
+ fail2:	usb_free_coherent(udev, ONETOUCH_PKT_LEN,
+			  onetouch->data, onetouch->data_dma);
  fail1:	kfree(onetouch);
 	input_free_device(input_dev);
 	return error;
@@ -279,8 +279,8 @@
 		usb_kill_urb(onetouch->irq);
 		input_unregister_device(onetouch->dev);
 		usb_free_urb(onetouch->irq);
-		usb_buffer_free(onetouch->udev, ONETOUCH_PKT_LEN,
-				onetouch->data, onetouch->data_dma);
+		usb_free_coherent(onetouch->udev, ONETOUCH_PKT_LEN,
+				  onetouch->data, onetouch->data_dma);
 	}
 }
 
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index f253ede..4471642 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -147,11 +147,9 @@
 	 * hasn't been mapped for DMA.  Yes, this is clunky, but it's
 	 * easier than always having the caller tell us whether the
 	 * transfer buffer has already been mapped. */
-	us->current_urb->transfer_flags = URB_NO_SETUP_DMA_MAP;
 	if (us->current_urb->transfer_buffer == us->iobuf)
 		us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 	us->current_urb->transfer_dma = us->iobuf_dma;
-	us->current_urb->setup_dma = us->cr_dma;
 
 	/* submit the URB */
 	status = usb_submit_urb(us->current_urb, GFP_NOIO);
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index ccf1dbb..2c897ee 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -365,15 +365,6 @@
 		"FinePix 1400Zoom",
 		US_SC_UFI, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY | US_FL_SINGLE_LUN),
 
-/* Reported by Peter Wächtler <pwaechtler@loewe-komp.de>
- * The device needs the flags only.
- */
-UNUSUAL_DEV(  0x04ce, 0x0002, 0x0074, 0x0074,
-		"ScanLogic",
-		"SL11R-IDE",
-		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_FIX_INQUIRY),
-
 /* Reported by Ondrej Zary <linux@rainbow-software.org>
  * The device reports one sector more and breaks when that sector is accessed
  */
@@ -1853,6 +1844,21 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Hans de Goede <hdegoede@redhat.com>
+ * These Appotech controllers are found in Picture Frames, they provide a
+ * (buggy) emulation of a cdrom drive which contains the windows software
+ * Uploading of pictures happens over the corresponding /dev/sg device. */
+UNUSUAL_DEV( 0x1908, 0x1315, 0x0000, 0x0000,
+		"BUILDWIN",
+		"Photo Frame",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_BAD_SENSE ),
+UNUSUAL_DEV( 0x1908, 0x1320, 0x0000, 0x0000,
+		"BUILDWIN",
+		"Photo Frame",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_BAD_SENSE ),
+
 UNUSUAL_DEV( 0x2116, 0x0320, 0x0001, 0x0001,
 		"ST",
 		"2A",
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index bbeeb92..a7d0bf9 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -407,15 +407,14 @@
 	/* Store our private data in the interface */
 	usb_set_intfdata(intf, us);
 
-	/* Allocate the device-related DMA-mapped buffers */
-	us->cr = usb_buffer_alloc(us->pusb_dev, sizeof(*us->cr),
-			GFP_KERNEL, &us->cr_dma);
+	/* Allocate the control/setup and DMA-mapped buffers */
+	us->cr = kmalloc(sizeof(*us->cr), GFP_KERNEL);
 	if (!us->cr) {
 		US_DEBUGP("usb_ctrlrequest allocation failed\n");
 		return -ENOMEM;
 	}
 
-	us->iobuf = usb_buffer_alloc(us->pusb_dev, US_IOBUF_SIZE,
+	us->iobuf = usb_alloc_coherent(us->pusb_dev, US_IOBUF_SIZE,
 			GFP_KERNEL, &us->iobuf_dma);
 	if (!us->iobuf) {
 		US_DEBUGP("I/O buffer allocation failed\n");
@@ -499,9 +498,6 @@
 		}
 	}
 	us->fflags = (us->fflags & ~mask) | f;
-	dev_info(&us->pusb_intf->dev, "Quirks match for "
-			"vid %04x pid %04x: %x\n",
-			vid, pid, f);
 }
 
 /* Get the unusual_devs entries and the string descriptors */
@@ -511,6 +507,7 @@
 	struct usb_device *dev = us->pusb_dev;
 	struct usb_interface_descriptor *idesc =
 		&us->pusb_intf->cur_altsetting->desc;
+	struct device *pdev = &us->pusb_intf->dev;
 
 	/* Store the entries */
 	us->unusual_dev = unusual_dev;
@@ -524,7 +521,7 @@
 	adjust_quirks(us);
 
 	if (us->fflags & US_FL_IGNORE_DEVICE) {
-		printk(KERN_INFO USB_STORAGE "device ignored\n");
+		dev_info(pdev, "device ignored\n");
 		return -ENODEV;
 	}
 
@@ -535,6 +532,12 @@
 	if (dev->speed != USB_SPEED_HIGH)
 		us->fflags &= ~US_FL_GO_SLOW;
 
+	if (us->fflags)
+		dev_info(pdev, "Quirks match for vid %04x pid %04x: %lx\n",
+				le16_to_cpu(dev->descriptor.idVendor),
+				le16_to_cpu(dev->descriptor.idProduct),
+				us->fflags);
+
 	/* Log a message if a non-generic unusual_dev entry contains an
 	 * unnecessary subclass or protocol override.  This may stimulate
 	 * reports from users that will help us remove unneeded entries
@@ -555,20 +558,20 @@
 			us->protocol == idesc->bInterfaceProtocol)
 			msg += 2;
 		if (msg >= 0 && !(us->fflags & US_FL_NEED_OVERRIDE))
-			printk(KERN_NOTICE USB_STORAGE "This device "
-				"(%04x,%04x,%04x S %02x P %02x)"
-				" has %s in unusual_devs.h (kernel"
-				" %s)\n"
-				"   Please send a copy of this message to "
-				"<linux-usb@vger.kernel.org> and "
-				"<usb-storage@lists.one-eyed-alien.net>\n",
-				le16_to_cpu(ddesc->idVendor),
-				le16_to_cpu(ddesc->idProduct),
-				le16_to_cpu(ddesc->bcdDevice),
-				idesc->bInterfaceSubClass,
-				idesc->bInterfaceProtocol,
-				msgs[msg],
-				utsname()->release);
+			dev_notice(pdev, "This device "
+					"(%04x,%04x,%04x S %02x P %02x)"
+					" has %s in unusual_devs.h (kernel"
+					" %s)\n"
+					"   Please send a copy of this message to "
+					"<linux-usb@vger.kernel.org> and "
+					"<usb-storage@lists.one-eyed-alien.net>\n",
+					le16_to_cpu(ddesc->idVendor),
+					le16_to_cpu(ddesc->idProduct),
+					le16_to_cpu(ddesc->bcdDevice),
+					idesc->bInterfaceSubClass,
+					idesc->bInterfaceProtocol,
+					msgs[msg],
+					utsname()->release);
 	}
 
 	return 0;
@@ -718,8 +721,8 @@
 	/* Start up our control thread */
 	th = kthread_run(usb_stor_control_thread, us, "usb-storage");
 	if (IS_ERR(th)) {
-		printk(KERN_WARNING USB_STORAGE 
-		       "Unable to start control thread\n");
+		dev_warn(&us->pusb_intf->dev,
+				"Unable to start control thread\n");
 		return PTR_ERR(th);
 	}
 	us->ctl_thread = th;
@@ -757,13 +760,9 @@
 {
 	US_DEBUGP("-- %s\n", __func__);
 
-	/* Free the device-related DMA-mapped buffers */
-	if (us->cr)
-		usb_buffer_free(us->pusb_dev, sizeof(*us->cr), us->cr,
-				us->cr_dma);
-	if (us->iobuf)
-		usb_buffer_free(us->pusb_dev, US_IOBUF_SIZE, us->iobuf,
-				us->iobuf_dma);
+	/* Free the buffers */
+	kfree(us->cr);
+	usb_free_coherent(us->pusb_dev, US_IOBUF_SIZE, us->iobuf, us->iobuf_dma);
 
 	/* Remove our private data from the interface */
 	usb_set_intfdata(us->pusb_intf, NULL);
@@ -816,13 +815,14 @@
 static int usb_stor_scan_thread(void * __us)
 {
 	struct us_data *us = (struct us_data *)__us;
+	struct device *dev = &us->pusb_intf->dev;
 
-	dev_dbg(&us->pusb_intf->dev, "device found\n");
+	dev_dbg(dev, "device found\n");
 
 	set_freezable();
 	/* Wait for the timeout to expire or for a disconnect */
 	if (delay_use > 0) {
-		dev_dbg(&us->pusb_intf->dev, "waiting for device to settle "
+		dev_dbg(dev, "waiting for device to settle "
 				"before scanning\n");
 		wait_event_freezable_timeout(us->delay_wait,
 				test_bit(US_FLIDX_DONT_SCAN, &us->dflags),
@@ -840,7 +840,7 @@
 			mutex_unlock(&us->dev_mutex);
 		}
 		scsi_scan_host(us_to_host(us));
-		dev_dbg(&us->pusb_intf->dev, "scan complete\n");
+		dev_dbg(dev, "scan complete\n");
 
 		/* Should we unbind if no devices were detected? */
 	}
@@ -876,8 +876,8 @@
 	 */
 	host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us));
 	if (!host) {
-		printk(KERN_WARNING USB_STORAGE
-			"Unable to allocate the scsi host\n");
+		dev_warn(&intf->dev,
+				"Unable to allocate the scsi host\n");
 		return -ENOMEM;
 	}
 
@@ -925,6 +925,7 @@
 {
 	struct task_struct *th;
 	int result;
+	struct device *dev = &us->pusb_intf->dev;
 
 	/* Make sure the transport and protocol have both been set */
 	if (!us->transport || !us->proto_handler) {
@@ -949,18 +950,18 @@
 		goto BadDevice;
 	snprintf(us->scsi_name, sizeof(us->scsi_name), "usb-storage %s",
 					dev_name(&us->pusb_intf->dev));
-	result = scsi_add_host(us_to_host(us), &us->pusb_intf->dev);
+	result = scsi_add_host(us_to_host(us), dev);
 	if (result) {
-		printk(KERN_WARNING USB_STORAGE
-			"Unable to add the scsi host\n");
+		dev_warn(dev,
+				"Unable to add the scsi host\n");
 		goto BadDevice;
 	}
 
 	/* Start up the thread for delayed SCSI-device scanning */
 	th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan");
 	if (IS_ERR(th)) {
-		printk(KERN_WARNING USB_STORAGE 
-		       "Unable to start the device-scanning thread\n");
+		dev_warn(dev,
+				"Unable to start the device-scanning thread\n");
 		complete(&us->scanning_done);
 		quiesce_and_remove_host(us);
 		result = PTR_ERR(th);
@@ -1046,12 +1047,12 @@
 {
 	int retval;
 
-	printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
+	pr_info("Initializing USB Mass Storage driver...\n");
 
 	/* register the driver, return usb_register return code if error */
 	retval = usb_register(&usb_storage_driver);
 	if (retval == 0) {
-		printk(KERN_INFO "USB Mass Storage support registered.\n");
+		pr_info("USB Mass Storage support registered.\n");
 		usb_usual_set_present(USB_US_TYPE_STOR);
 	}
 	return retval;
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 6971713..89d3bff 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -139,8 +139,7 @@
 	struct usb_ctrlrequest	*cr;		 /* control requests	 */
 	struct usb_sg_request	current_sg;	 /* scatter-gather req.  */
 	unsigned char		*iobuf;		 /* I/O buffer		 */
-	dma_addr_t		cr_dma;		 /* buffer DMA addresses */
-	dma_addr_t		iobuf_dma;
+	dma_addr_t		iobuf_dma;	 /* buffer DMA addresses */
 	struct task_struct	*ctl_thread;	 /* the control thread   */
 
 	/* mutual exclusion and synchronization structures */
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 6152278..d110588 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -387,8 +387,8 @@
 	}
 
 	/* free up our allocated buffer */
-	usb_buffer_free(urb->dev, urb->transfer_buffer_length,
-			urb->transfer_buffer, urb->transfer_dma);
+	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+			  urb->transfer_buffer, urb->transfer_dma);
 	up(&dev->limit_sem);
 }
 
@@ -442,8 +442,8 @@
 		goto error;
 	}
 
-	buf = usb_buffer_alloc(dev->udev, writesize, GFP_KERNEL,
-			       &urb->transfer_dma);
+	buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL,
+				 &urb->transfer_dma);
 	if (!buf) {
 		retval = -ENOMEM;
 		goto error;
@@ -491,7 +491,7 @@
 	usb_unanchor_urb(urb);
 error:
 	if (urb) {
-		usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
+		usb_free_coherent(dev->udev, writesize, buf, urb->transfer_dma);
 		usb_free_urb(urb);
 	}
 	up(&dev->limit_sem);
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c
index 608d61a..84b744c 100644
--- a/drivers/usb/wusbcore/wa-xfer.c
+++ b/drivers/usb/wusbcore/wa-xfer.c
@@ -474,8 +474,6 @@
 		struct wa_xfer_ctl *xfer_ctl =
 			container_of(xfer_hdr0, struct wa_xfer_ctl, hdr);
 		xfer_ctl->bmAttribute = xfer->is_inbound ? 1 : 0;
-		BUG_ON(xfer->urb->transfer_flags & URB_NO_SETUP_DMA_MAP
-		       && xfer->urb->setup_packet == NULL);
 		memcpy(&xfer_ctl->baSetupData, xfer->urb->setup_packet,
 		       sizeof(xfer_ctl->baSetupData));
 		break;
diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h
index 759cda5..3d94c42 100644
--- a/drivers/usb/wusbcore/wusbhc.h
+++ b/drivers/usb/wusbcore/wusbhc.h
@@ -58,9 +58,7 @@
 #include <linux/mutex.h>
 #include <linux/kref.h>
 #include <linux/workqueue.h>
-/* FIXME: Yes, I know: BAD--it's not my fault the USB HC iface is not
- *        public */
-#include <linux/../../drivers/usb/core/hcd.h>
+#include <linux/usb/hcd.h>
 #include <linux/uwb.h>
 #include <linux/usb/wusb.h>
 
diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c
index 8e4eacc..748a74b 100644
--- a/drivers/watchdog/pcwd_usb.c
+++ b/drivers/watchdog/pcwd_usb.c
@@ -600,8 +600,8 @@
 {
 	usb_free_urb(usb_pcwd->intr_urb);
 	if (usb_pcwd->intr_buffer != NULL)
-		usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size,
-				usb_pcwd->intr_buffer, usb_pcwd->intr_dma);
+		usb_free_coherent(usb_pcwd->udev, usb_pcwd->intr_size,
+				  usb_pcwd->intr_buffer, usb_pcwd->intr_dma);
 	kfree(usb_pcwd);
 }
 
@@ -671,7 +671,7 @@
 				le16_to_cpu(endpoint->wMaxPacketSize) : 8);
 
 	/* set up the memory buffer's */
-	usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size,
+	usb_pcwd->intr_buffer = usb_alloc_coherent(udev, usb_pcwd->intr_size,
 					GFP_ATOMIC, &usb_pcwd->intr_dma);
 	if (!usb_pcwd->intr_buffer) {
 		printk(KERN_ERR PFX "Out of memory\n");