]> git.ipfire.org Git - ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.drivers/0013-Staging-USB-IP-add-host-driver.patch
Imported linux-2.6.27.39 suse/xen patches.
[ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.drivers / 0013-Staging-USB-IP-add-host-driver.patch
diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0013-Staging-USB-IP-add-host-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/0013-Staging-USB-IP-add-host-driver.patch
deleted file mode 100644 (file)
index 174e81c..0000000
+++ /dev/null
@@ -1,1959 +0,0 @@
-From 4d7b5c7f8ad49b7f01fb8aed83c560ac43cfbda8 Mon Sep 17 00:00:00 2001
-From: Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>
-Date: Wed, 9 Jul 2008 14:56:51 -0600
-Subject: [PATCH 13/23] Staging: USB/IP: add host driver
-Patch-mainline: 2.6.28
-
-This adds the USB IP client driver
-
-Brian Merrell cleaned up a lot of this code and submitted it for
-inclusion.  Greg also did a lot of cleanup.
-
-Signed-off-by: Brian G. Merrell <bgmerrell@novell.com>
-Cc: Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>
-Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
----
- drivers/staging/usbip/Kconfig     |   11 +
- drivers/staging/usbip/Makefile    |    3 +
- drivers/staging/usbip/stub.h      |   95 ++++++
- drivers/staging/usbip/stub_dev.c  |  483 +++++++++++++++++++++++++++++
- drivers/staging/usbip/stub_main.c |  300 ++++++++++++++++++
- drivers/staging/usbip/stub_rx.c   |  615 +++++++++++++++++++++++++++++++++++++
- drivers/staging/usbip/stub_tx.c   |  371 ++++++++++++++++++++++
- 7 files changed, 1878 insertions(+), 0 deletions(-)
- create mode 100644 drivers/staging/usbip/stub.h
- create mode 100644 drivers/staging/usbip/stub_dev.c
- create mode 100644 drivers/staging/usbip/stub_main.c
- create mode 100644 drivers/staging/usbip/stub_rx.c
- create mode 100644 drivers/staging/usbip/stub_tx.c
-
-diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig
-index c4d68e1..7426235 100644
---- a/drivers/staging/usbip/Kconfig
-+++ b/drivers/staging/usbip/Kconfig
-@@ -23,3 +23,14 @@ config USB_IP_VHCI_HCD
-        To compile this driver as a module, choose M here: the
-        module will be called vhci_hcd.
-+
-+config USB_IP_HOST
-+      tristate "USB IP host driver"
-+      depends on USB_IP_COMMON
-+      default N
-+      ---help---
-+       This enables the USB IP device driver which will run on the
-+       host machine.
-+
-+       To compile this driver as a module, choose M here: the
-+       module will be called usbip.
-diff --git a/drivers/staging/usbip/Makefile b/drivers/staging/usbip/Makefile
-index 6ef4c39..179f421 100644
---- a/drivers/staging/usbip/Makefile
-+++ b/drivers/staging/usbip/Makefile
-@@ -4,6 +4,9 @@ usbip_common_mod-objs := usbip_common.o usbip_event.o
- obj-$(CONFIG_USB_IP_VHCI_HCD) += vhci-hcd.o
- vhci-hcd-objs := vhci_sysfs.o vhci_tx.o vhci_rx.o vhci_hcd.o
-+obj-$(CONFIG_USB_IP_HOST) += usbip.o
-+usbip-objs := stub_dev.o stub_main.o stub_rx.o stub_tx.o
-+
- ifeq ($(CONFIG_USB_DEBUG),y)
-       EXTRA_CFLAGS += -DDEBUG
- endif
-diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h
-new file mode 100644
-index 0000000..f541a3a
---- /dev/null
-+++ b/drivers/staging/usbip/stub.h
-@@ -0,0 +1,95 @@
-+/*
-+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
-+ *
-+ * This 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 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/list.h>
-+#include <linux/spinlock.h>
-+#include <linux/slab.h>
-+#include <linux/string.h>
-+#include <linux/module.h>
-+#include <linux/net.h>
-+
-+struct stub_device {
-+      struct usb_interface *interface;
-+      struct list_head list;
-+
-+      struct usbip_device ud;
-+      __u32 devid;
-+
-+      /*
-+       * stub_priv preserves private data of each urb.
-+       * It is allocated as stub_priv_cache and assigned to urb->context.
-+       *
-+       * stub_priv is always linked to any one of 3 lists;
-+       *      priv_init: linked to this until the comletion of a urb.
-+       *      priv_tx  : linked to this after the completion of a urb.
-+       *      priv_free: linked to this after the sending of the result.
-+       *
-+       * Any of these list operations should be locked by priv_lock.
-+       */
-+      spinlock_t priv_lock;
-+      struct list_head priv_init;
-+      struct list_head priv_tx;
-+      struct list_head priv_free;
-+
-+      /* see comments for unlinking in stub_rx.c */
-+      struct list_head unlink_tx;
-+      struct list_head unlink_free;
-+
-+
-+      wait_queue_head_t tx_waitq;
-+};
-+
-+/* private data into urb->priv */
-+struct stub_priv {
-+      unsigned long seqnum;
-+      struct list_head list;
-+      struct stub_device *sdev;
-+      struct urb *urb;
-+
-+      int unlinking;
-+};
-+
-+struct stub_unlink {
-+      unsigned long seqnum;
-+      struct list_head list;
-+      __u32 status;
-+};
-+
-+
-+extern struct kmem_cache *stub_priv_cache;
-+
-+
-+/*-------------------------------------------------------------------------*/
-+/* prototype declarations */
-+
-+/* stub_tx.c */
-+void stub_complete(struct urb *);
-+void stub_tx_loop(struct usbip_task *);
-+
-+/* stub_dev.c */
-+extern struct usb_driver stub_driver;
-+
-+/* stub_rx.c */
-+void stub_rx_loop(struct usbip_task *);
-+void stub_enqueue_ret_unlink(struct stub_device *, __u32, __u32);
-+
-+/* stub_main.c */
-+int match_busid(char *busid);
-+void stub_device_cleanup_urbs(struct stub_device *sdev);
-diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
-new file mode 100644
-index 0000000..ee455a0
---- /dev/null
-+++ b/drivers/staging/usbip/stub_dev.c
-@@ -0,0 +1,483 @@
-+/*
-+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
-+ *
-+ * This 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 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 "usbip_common.h"
-+#include "stub.h"
-+
-+
-+
-+static int stub_probe(struct usb_interface *interface,
-+                              const struct usb_device_id *id);
-+static void stub_disconnect(struct usb_interface *interface);
-+
-+
-+/*
-+ * Define device IDs here if you want to explicitly limit exportable devices.
-+ * In the most cases, wild card matching will be ok because driver binding can
-+ * be changed dynamically by a userland program.
-+ */
-+static struct usb_device_id stub_table[] = {
-+#if 0
-+      /* just an example */
-+      { USB_DEVICE(0x05ac, 0x0301) },   /* Mac 1 button mouse */
-+      { USB_DEVICE(0x0430, 0x0009) },   /* Plat Home Keyboard */
-+      { USB_DEVICE(0x059b, 0x0001) },   /* Iomega USB Zip 100 */
-+      { USB_DEVICE(0x04b3, 0x4427) },   /* IBM USB CD-ROM */
-+      { USB_DEVICE(0x05a9, 0xa511) },   /* LifeView USB cam */
-+      { USB_DEVICE(0x55aa, 0x0201) },   /* Imation card reader */
-+      { USB_DEVICE(0x046d, 0x0870) },   /* Qcam Express(QV-30) */
-+      { USB_DEVICE(0x04bb, 0x0101) },   /* IO-DATA HD 120GB */
-+      { USB_DEVICE(0x04bb, 0x0904) },   /* IO-DATA USB-ET/TX */
-+      { USB_DEVICE(0x04bb, 0x0201) },   /* IO-DATA USB-ET/TX */
-+      { USB_DEVICE(0x08bb, 0x2702) },   /* ONKYO USB Speaker */
-+      { USB_DEVICE(0x046d, 0x08b2) },   /* Logicool Qcam 4000 Pro */
-+#endif
-+      /* magic for wild card */
-+      { .driver_info = 1 },
-+      { 0, }                                     /* Terminating entry */
-+};
-+MODULE_DEVICE_TABLE(usb, stub_table);
-+
-+struct usb_driver stub_driver = {
-+      .name           = "usbip",
-+      .probe          = stub_probe,
-+      .disconnect     = stub_disconnect,
-+      .id_table       = stub_table,
-+};
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* Define sysfs entries for a usbip-bound device */
-+
-+
-+/*
-+ * usbip_status shows status of usbip as long as this driver is bound to the
-+ * target device.
-+ */
-+static ssize_t show_status(struct device *dev, struct device_attribute *attr,
-+                         char *buf)
-+{
-+      struct stub_device *sdev = dev_get_drvdata(dev);
-+      int status;
-+
-+      if (!sdev) {
-+              dev_err(dev, "sdev is null\n");
-+              return -ENODEV;
-+      }
-+
-+      spin_lock(&sdev->ud.lock);
-+      status = sdev->ud.status;
-+      spin_unlock(&sdev->ud.lock);
-+
-+      return snprintf(buf, PAGE_SIZE, "%d\n", status);
-+}
-+static DEVICE_ATTR(usbip_status, S_IRUGO, show_status, NULL);
-+
-+/*
-+ * usbip_sockfd gets a socket descriptor of an established TCP connection that
-+ * is used to transfer usbip requests by kernel threads. -1 is a magic number
-+ * by which usbip connection is finished.
-+ */
-+static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
-+                          const char *buf, size_t count)
-+{
-+      struct stub_device *sdev = dev_get_drvdata(dev);
-+      int sockfd = 0;
-+      struct socket *socket;
-+
-+      if (!sdev) {
-+              dev_err(dev, "sdev is null\n");
-+              return -ENODEV;
-+      }
-+
-+      sscanf(buf, "%d", &sockfd);
-+
-+      if (sockfd != -1) {
-+              dev_info(dev, "stub up\n");
-+
-+              spin_lock(&sdev->ud.lock);
-+
-+              if (sdev->ud.status != SDEV_ST_AVAILABLE) {
-+                      dev_err(dev, "not ready\n");
-+                      spin_unlock(&sdev->ud.lock);
-+                      return -EINVAL;
-+              }
-+
-+              socket = sockfd_to_socket(sockfd);
-+              if (!socket) {
-+                      spin_unlock(&sdev->ud.lock);
-+                      return -EINVAL;
-+              }
-+
-+#if 0
-+              setnodelay(socket);
-+              setkeepalive(socket);
-+              setreuse(socket);
-+#endif
-+
-+              sdev->ud.tcp_socket = socket;
-+
-+              spin_unlock(&sdev->ud.lock);
-+
-+              usbip_start_threads(&sdev->ud);
-+
-+              spin_lock(&sdev->ud.lock);
-+              sdev->ud.status = SDEV_ST_USED;
-+              spin_unlock(&sdev->ud.lock);
-+
-+      } else {
-+              dev_info(dev, "stub down\n");
-+
-+              spin_lock(&sdev->ud.lock);
-+              if (sdev->ud.status != SDEV_ST_USED) {
-+                      spin_unlock(&sdev->ud.lock);
-+                      return -EINVAL;
-+              }
-+              spin_unlock(&sdev->ud.lock);
-+
-+              usbip_event_add(&sdev->ud, SDEV_EVENT_DOWN);
-+      }
-+
-+      return count;
-+}
-+static DEVICE_ATTR(usbip_sockfd, S_IWUSR, NULL, store_sockfd);
-+
-+static int stub_add_files(struct device *dev)
-+{
-+      int err = 0;
-+
-+      err = device_create_file(dev, &dev_attr_usbip_status);
-+      if (err)
-+              goto err_status;
-+
-+      err = device_create_file(dev, &dev_attr_usbip_sockfd);
-+      if (err)
-+              goto err_sockfd;
-+
-+      err = device_create_file(dev, &dev_attr_usbip_debug);
-+      if (err)
-+              goto err_debug;
-+
-+      return 0;
-+
-+err_debug:
-+      device_remove_file(dev, &dev_attr_usbip_sockfd);
-+
-+err_sockfd:
-+      device_remove_file(dev, &dev_attr_usbip_status);
-+
-+err_status:
-+      return err;
-+}
-+
-+static void stub_remove_files(struct device *dev)
-+{
-+      device_remove_file(dev, &dev_attr_usbip_status);
-+      device_remove_file(dev, &dev_attr_usbip_sockfd);
-+      device_remove_file(dev, &dev_attr_usbip_debug);
-+}
-+
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* Event handler functions called by an event handler thread */
-+
-+static void stub_shutdown_connection(struct usbip_device *ud)
-+{
-+      struct stub_device *sdev = container_of(ud, struct stub_device, ud);
-+
-+      /*
-+       * When removing an exported device, kernel panic sometimes occurred
-+       * and then EIP was sk_wait_data of stub_rx thread. Is this because
-+       * sk_wait_data returned though stub_rx thread was already finished by
-+       * step 1?
-+       */
-+      if (ud->tcp_socket) {
-+              udbg("shutdown tcp_socket %p\n", ud->tcp_socket);
-+              kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
-+      }
-+
-+      /* 1. stop threads */
-+      usbip_stop_threads(ud);
-+
-+      /* 2. close the socket */
-+      /*
-+       * tcp_socket is freed after threads are killed.
-+       * So usbip_xmit do not touch NULL socket.
-+       */
-+      if (ud->tcp_socket) {
-+              sock_release(ud->tcp_socket);
-+              ud->tcp_socket = NULL;
-+      }
-+
-+      /* 3. free used data */
-+      stub_device_cleanup_urbs(sdev);
-+
-+      /* 4. free stub_unlink */
-+      {
-+              unsigned long flags;
-+              struct stub_unlink *unlink, *tmp;
-+
-+              spin_lock_irqsave(&sdev->priv_lock, flags);
-+
-+              list_for_each_entry_safe(unlink, tmp, &sdev->unlink_tx, list) {
-+                      list_del(&unlink->list);
-+                      kfree(unlink);
-+              }
-+
-+              list_for_each_entry_safe(unlink, tmp,
-+                                               &sdev->unlink_free, list) {
-+                      list_del(&unlink->list);
-+                      kfree(unlink);
-+              }
-+
-+              spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+      }
-+}
-+
-+static void stub_device_reset(struct usbip_device *ud)
-+{
-+      struct stub_device *sdev = container_of(ud, struct stub_device, ud);
-+      struct usb_device *udev = interface_to_usbdev(sdev->interface);
-+      int ret;
-+
-+      udbg("device reset");
-+      ret = usb_lock_device_for_reset(udev, sdev->interface);
-+      if (ret < 0) {
-+              dev_err(&udev->dev, "lock for reset\n");
-+
-+              spin_lock(&ud->lock);
-+              ud->status = SDEV_ST_ERROR;
-+              spin_unlock(&ud->lock);
-+
-+              return;
-+      }
-+
-+      /* try to reset the device */
-+      ret = usb_reset_device(udev);
-+
-+      usb_unlock_device(udev);
-+
-+      spin_lock(&ud->lock);
-+      if (ret) {
-+              dev_err(&udev->dev, "device reset\n");
-+              ud->status = SDEV_ST_ERROR;
-+
-+      } else {
-+              dev_info(&udev->dev, "device reset\n");
-+              ud->status = SDEV_ST_AVAILABLE;
-+
-+      }
-+      spin_unlock(&ud->lock);
-+
-+      return;
-+}
-+
-+static void stub_device_unusable(struct usbip_device *ud)
-+{
-+      spin_lock(&ud->lock);
-+      ud->status = SDEV_ST_ERROR;
-+      spin_unlock(&ud->lock);
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/**
-+ * stub_device_alloc - allocate a new stub_device struct
-+ * @interface: usb_interface of a new device
-+ *
-+ * Allocates and initializes a new stub_device struct.
-+ */
-+static struct stub_device *stub_device_alloc(struct usb_interface *interface)
-+{
-+      struct stub_device *sdev;
-+      int busnum = interface_to_busnum(interface);
-+      int devnum = interface_to_devnum(interface);
-+
-+      dev_dbg(&interface->dev, "allocating stub device");
-+
-+      /* yes, it's a new device */
-+      sdev = kzalloc(sizeof(struct stub_device), GFP_KERNEL);
-+      if (!sdev) {
-+              dev_err(&interface->dev, "no memory for stub_device\n");
-+              return NULL;
-+      }
-+
-+      sdev->interface = interface;
-+
-+      /*
-+       * devid is defined with devnum when this driver is first allocated.
-+       * devnum may change later if a device is reset. However, devid never
-+       * changes during a usbip connection.
-+       */
-+      sdev->devid     = (busnum << 16) | devnum;
-+
-+      usbip_task_init(&sdev->ud.tcp_rx, "stub_rx", stub_rx_loop);
-+      usbip_task_init(&sdev->ud.tcp_tx, "stub_tx", stub_tx_loop);
-+
-+      sdev->ud.side = USBIP_STUB;
-+      sdev->ud.status = SDEV_ST_AVAILABLE;
-+      /* sdev->ud.lock = SPIN_LOCK_UNLOCKED; */
-+      spin_lock_init(&sdev->ud.lock);
-+      sdev->ud.tcp_socket = NULL;
-+
-+      INIT_LIST_HEAD(&sdev->priv_init);
-+      INIT_LIST_HEAD(&sdev->priv_tx);
-+      INIT_LIST_HEAD(&sdev->priv_free);
-+      INIT_LIST_HEAD(&sdev->unlink_free);
-+      INIT_LIST_HEAD(&sdev->unlink_tx);
-+      /* sdev->priv_lock = SPIN_LOCK_UNLOCKED; */
-+      spin_lock_init(&sdev->priv_lock);
-+
-+      init_waitqueue_head(&sdev->tx_waitq);
-+
-+      sdev->ud.eh_ops.shutdown = stub_shutdown_connection;
-+      sdev->ud.eh_ops.reset    = stub_device_reset;
-+      sdev->ud.eh_ops.unusable = stub_device_unusable;
-+
-+      usbip_start_eh(&sdev->ud);
-+
-+      udbg("register new interface\n");
-+      return sdev;
-+}
-+
-+static int stub_device_free(struct stub_device *sdev)
-+{
-+      if (!sdev)
-+              return -EINVAL;
-+
-+      kfree(sdev);
-+      udbg("kfree udev ok\n");
-+
-+      return 0;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/*
-+ * If a usb device has multiple active interfaces, this driver is bound to all
-+ * the active interfaces. However, usbip exports *a* usb device (i.e., not *an*
-+ * active interface). Currently, a userland program must ensure that it
-+ * looks at the usbip's sysfs entries of only the first active interface.
-+ *
-+ * TODO: use "struct usb_device_driver" to bind a usb device.
-+ * However, it seems it is not fully supported in mainline kernel yet
-+ * (2.6.19.2).
-+ */
-+static int stub_probe(struct usb_interface *interface,
-+                    const struct usb_device_id *id)
-+{
-+      struct usb_device *udev = interface_to_usbdev(interface);
-+      struct stub_device *sdev = NULL;
-+      char *udev_busid = interface->dev.parent->bus_id;
-+      int err = 0;
-+
-+      dev_dbg(&interface->dev, "Enter\n");
-+
-+      /* check we should claim or not by busid_table */
-+      if (match_busid(udev_busid)) {
-+              dev_info(&interface->dev,
-+                       "this device %s is not in match_busid table. skip!\n",
-+                       udev_busid);
-+
-+              /*
-+               * Return value should be ENODEV or ENOXIO to continue trying
-+               * other matched drivers by the driver core.
-+               * See driver_probe_device() in driver/base/dd.c
-+               */
-+              return -ENODEV;
-+      }
-+
-+      if (udev->descriptor.bDeviceClass ==  USB_CLASS_HUB) {
-+              udbg("this device %s is a usb hub device. skip!\n",
-+                                                              udev_busid);
-+              return -ENODEV;
-+      }
-+
-+      if (!strcmp(udev->bus->bus_name, "vhci_hcd")) {
-+              udbg("this device %s is attached on vhci_hcd. skip!\n",
-+                                                              udev_busid);
-+              return -ENODEV;
-+      }
-+
-+      /* ok. this is my device. */
-+      sdev = stub_device_alloc(interface);
-+      if (!sdev)
-+              return -ENOMEM;
-+
-+      dev_info(&interface->dev, "USB/IP Stub: register a new interface "
-+               "(bus %u dev %u ifn %u)\n", udev->bus->busnum, udev->devnum,
-+               interface->cur_altsetting->desc.bInterfaceNumber);
-+
-+      /* set private data to usb_interface */
-+      usb_set_intfdata(interface, sdev);
-+
-+      err = stub_add_files(&interface->dev);
-+      if (err) {
-+              dev_err(&interface->dev, "create sysfs files for %s\n",
-+                      udev_busid);
-+              return err;
-+      }
-+
-+      return 0;
-+}
-+
-+
-+/*
-+ * called in usb_disconnect() or usb_deregister()
-+ * but only if actconfig(active configuration) exists
-+ */
-+static void stub_disconnect(struct usb_interface *interface)
-+{
-+      struct stub_device *sdev = usb_get_intfdata(interface);
-+
-+      udbg("Enter\n");
-+
-+      /* get stub_device */
-+      if (!sdev) {
-+              err(" could not get device from inteface data");
-+              /* BUG(); */
-+              return;
-+      }
-+
-+      usb_set_intfdata(interface, NULL);
-+
-+
-+      /*
-+       * NOTE:
-+       * rx/tx threads are invoked for each usb_device.
-+       */
-+      stub_remove_files(&interface->dev);
-+
-+      /* 1. shutdown the current connection */
-+      usbip_event_add(&sdev->ud, SDEV_EVENT_REMOVED);
-+
-+      /* 2. wait for the stop of the event handler */
-+      usbip_stop_eh(&sdev->ud);
-+
-+      /* 3. free sdev */
-+      stub_device_free(sdev);
-+
-+
-+      udbg("bye\n");
-+}
-diff --git a/drivers/staging/usbip/stub_main.c b/drivers/staging/usbip/stub_main.c
-new file mode 100644
-index 0000000..c665d7f
---- /dev/null
-+++ b/drivers/staging/usbip/stub_main.c
-@@ -0,0 +1,300 @@
-+/*
-+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
-+ *
-+ * This 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 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 "usbip_common.h"
-+#include "stub.h"
-+
-+/* Version Information */
-+#define DRIVER_VERSION "1.0"
-+#define DRIVER_AUTHOR "Takahiro Hirofuchi"
-+#define DRIVER_DESC "Stub Driver for USB/IP"
-+
-+/* stub_priv is allocated from stub_priv_cache */
-+struct kmem_cache *stub_priv_cache;
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* Define sysfs entries for the usbip driver */
-+
-+
-+/*
-+ * busid_tables defines matching busids that usbip can grab. A user can change
-+ * dynamically what device is locally used and what device is exported to a
-+ * remote host.
-+ */
-+#define MAX_BUSID 16
-+static char busid_table[MAX_BUSID][BUS_ID_SIZE];
-+static spinlock_t busid_table_lock;
-+
-+
-+int match_busid(char *busid)
-+{
-+      int i;
-+
-+      spin_lock(&busid_table_lock);
-+
-+      for (i = 0; i < MAX_BUSID; i++)
-+              if (busid_table[i][0])
-+                      if (!strncmp(busid_table[i], busid, BUS_ID_SIZE)) {
-+                              /* already registerd */
-+                              spin_unlock(&busid_table_lock);
-+                              return 0;
-+                      }
-+
-+      spin_unlock(&busid_table_lock);
-+
-+      return 1;
-+}
-+
-+static ssize_t show_match_busid(struct device_driver *drv, char *buf)
-+{
-+      int i;
-+      char *out = buf;
-+
-+      spin_lock(&busid_table_lock);
-+
-+      for (i = 0; i < MAX_BUSID; i++)
-+              if (busid_table[i][0])
-+                      out += sprintf(out, "%s ", busid_table[i]);
-+
-+      spin_unlock(&busid_table_lock);
-+
-+      out += sprintf(out, "\n");
-+
-+      return out - buf;
-+}
-+
-+static int add_match_busid(char *busid)
-+{
-+      int i;
-+
-+      if (!match_busid(busid))
-+              return 0;
-+
-+      spin_lock(&busid_table_lock);
-+
-+      for (i = 0; i < MAX_BUSID; i++)
-+              if (!busid_table[i][0]) {
-+                      strncpy(busid_table[i], busid, BUS_ID_SIZE);
-+                      spin_unlock(&busid_table_lock);
-+                      return 0;
-+              }
-+
-+      spin_unlock(&busid_table_lock);
-+
-+      return -1;
-+}
-+
-+static int del_match_busid(char *busid)
-+{
-+      int i;
-+
-+      spin_lock(&busid_table_lock);
-+
-+      for (i = 0; i < MAX_BUSID; i++)
-+              if (!strncmp(busid_table[i], busid, BUS_ID_SIZE)) {
-+                      /* found */
-+                      memset(busid_table[i], 0, BUS_ID_SIZE);
-+                      spin_unlock(&busid_table_lock);
-+                      return 0;
-+              }
-+
-+      spin_unlock(&busid_table_lock);
-+
-+      return -1;
-+}
-+
-+static ssize_t store_match_busid(struct device_driver *dev, const char *buf,
-+              size_t count)
-+{
-+      int len;
-+      char busid[BUS_ID_SIZE];
-+
-+      if (count < 5)
-+              return -EINVAL;
-+
-+      /* strnlen() does not include \0 */
-+      len = strnlen(buf + 4, BUS_ID_SIZE);
-+
-+      /* busid needs to include \0 termination */
-+      if (!(len < BUS_ID_SIZE))
-+              return -EINVAL;
-+
-+      strncpy(busid, buf + 4, BUS_ID_SIZE);
-+
-+
-+      if (!strncmp(buf, "add ", 4)) {
-+              if (add_match_busid(busid) < 0)
-+                      return -ENOMEM;
-+              else {
-+                      udbg("add busid %s\n", busid);
-+                      return count;
-+              }
-+      } else if (!strncmp(buf, "del ", 4)) {
-+              if (del_match_busid(busid) < 0)
-+                      return -ENODEV;
-+              else {
-+                      udbg("del busid %s\n", busid);
-+                      return count;
-+              }
-+      } else
-+              return -EINVAL;
-+}
-+
-+static DRIVER_ATTR(match_busid, S_IRUSR|S_IWUSR, show_match_busid,
-+                                                      store_match_busid);
-+
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/* Cleanup functions used to free private data */
-+
-+static struct stub_priv *stub_priv_pop_from_listhead(struct list_head *listhead)
-+{
-+      struct stub_priv *priv, *tmp;
-+
-+      list_for_each_entry_safe(priv, tmp, listhead, list) {
-+              list_del(&priv->list);
-+              return priv;
-+      }
-+
-+      return NULL;
-+}
-+
-+static struct stub_priv *stub_priv_pop(struct stub_device *sdev)
-+{
-+      unsigned long flags;
-+      struct stub_priv *priv;
-+
-+      spin_lock_irqsave(&sdev->priv_lock, flags);
-+
-+      priv = stub_priv_pop_from_listhead(&sdev->priv_init);
-+      if (priv) {
-+              spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+              return priv;
-+      }
-+
-+      priv = stub_priv_pop_from_listhead(&sdev->priv_tx);
-+      if (priv) {
-+              spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+              return priv;
-+      }
-+
-+      priv = stub_priv_pop_from_listhead(&sdev->priv_free);
-+      if (priv) {
-+              spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+              return priv;
-+      }
-+
-+      spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+      return NULL;
-+}
-+
-+void stub_device_cleanup_urbs(struct stub_device *sdev)
-+{
-+      struct stub_priv *priv;
-+
-+      udbg("free sdev %p\n", sdev);
-+
-+      while ((priv = stub_priv_pop(sdev))) {
-+              struct urb *urb = priv->urb;
-+
-+              udbg("   free urb %p\n", urb);
-+              usb_kill_urb(urb);
-+
-+              kmem_cache_free(stub_priv_cache, priv);
-+
-+              if (urb->transfer_buffer != NULL)
-+                      kfree(urb->transfer_buffer);
-+
-+              if (urb->setup_packet != NULL)
-+                      kfree(urb->setup_packet);
-+
-+              usb_free_urb(urb);
-+      }
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int __init usb_stub_init(void)
-+{
-+      int ret;
-+
-+      stub_priv_cache = kmem_cache_create("stub_priv",
-+                                          sizeof(struct stub_priv), 0,
-+                                          SLAB_HWCACHE_ALIGN, NULL);
-+
-+      if (!stub_priv_cache) {
-+              printk(KERN_ERR KBUILD_MODNAME
-+                     ": create stub_priv_cache error\n");
-+              return -ENOMEM;
-+      }
-+
-+      ret = usb_register(&stub_driver);
-+      if (ret) {
-+              printk(KERN_ERR KBUILD_MODNAME ": usb_register failed %d\n",
-+                     ret);
-+              goto error_usb_register;
-+      }
-+
-+      printk(KERN_INFO KBUILD_MODNAME ":"
-+             DRIVER_DESC ":" DRIVER_VERSION "\n");
-+
-+      memset(busid_table, 0, sizeof(busid_table));
-+      spin_lock_init(&busid_table_lock);
-+
-+      ret = driver_create_file(&stub_driver.drvwrap.driver,
-+                               &driver_attr_match_busid);
-+
-+      if (ret) {
-+              printk(KERN_ERR KBUILD_MODNAME ": create driver sysfs\n");
-+              goto error_create_file;
-+      }
-+
-+      return ret;
-+error_create_file:
-+      usb_deregister(&stub_driver);
-+error_usb_register:
-+      kmem_cache_destroy(stub_priv_cache);
-+      return ret;
-+}
-+
-+static void __exit usb_stub_exit(void)
-+{
-+      driver_remove_file(&stub_driver.drvwrap.driver,
-+                         &driver_attr_match_busid);
-+
-+      /*
-+       * deregister() calls stub_disconnect() for all devices. Device
-+       * specific data is cleared in stub_disconnect().
-+       */
-+      usb_deregister(&stub_driver);
-+
-+      kmem_cache_destroy(stub_priv_cache);
-+}
-+
-+module_init(usb_stub_init);
-+module_exit(usb_stub_exit);
-+
-+MODULE_AUTHOR(DRIVER_AUTHOR);
-+MODULE_DESCRIPTION(DRIVER_DESC);
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c
-new file mode 100644
-index 0000000..36ce898
---- /dev/null
-+++ b/drivers/staging/usbip/stub_rx.c
-@@ -0,0 +1,615 @@
-+/*
-+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
-+ *
-+ * This 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 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 "usbip_common.h"
-+#include "stub.h"
-+#include "../../usb/core/hcd.h"
-+
-+
-+static int is_clear_halt_cmd(struct urb *urb)
-+{
-+      struct usb_ctrlrequest *req;
-+
-+      req = (struct usb_ctrlrequest *) urb->setup_packet;
-+
-+       return (req->bRequest == USB_REQ_CLEAR_FEATURE) &&
-+               (req->bRequestType == USB_RECIP_ENDPOINT) &&
-+               (req->wValue == USB_ENDPOINT_HALT);
-+}
-+
-+static int is_set_interface_cmd(struct urb *urb)
-+{
-+      struct usb_ctrlrequest *req;
-+
-+      req = (struct usb_ctrlrequest *) urb->setup_packet;
-+
-+      return (req->bRequest == USB_REQ_SET_INTERFACE) &&
-+                 (req->bRequestType == USB_RECIP_INTERFACE);
-+}
-+
-+static int is_set_configuration_cmd(struct urb *urb)
-+{
-+      struct usb_ctrlrequest *req;
-+
-+      req = (struct usb_ctrlrequest *) urb->setup_packet;
-+
-+      return (req->bRequest == USB_REQ_SET_CONFIGURATION) &&
-+                 (req->bRequestType == USB_RECIP_DEVICE);
-+}
-+
-+static int is_reset_device_cmd(struct urb *urb)
-+{
-+      struct usb_ctrlrequest *req;
-+      __u16 value;
-+      __u16 index;
-+
-+      req = (struct usb_ctrlrequest *) urb->setup_packet;
-+      value = le16_to_cpu(req->wValue);
-+      index = le16_to_cpu(req->wIndex);
-+
-+      if ((req->bRequest == USB_REQ_SET_FEATURE) &&
-+                      (req->bRequestType == USB_RT_PORT) &&
-+                      (value = USB_PORT_FEAT_RESET)) {
-+              dbg_stub_rx("reset_device_cmd, port %u\n", index);
-+              return 1;
-+      } else
-+              return 0;
-+}
-+
-+static int tweak_clear_halt_cmd(struct urb *urb)
-+{
-+      struct usb_ctrlrequest *req;
-+      int target_endp;
-+      int target_dir;
-+      int target_pipe;
-+      int ret;
-+
-+      req = (struct usb_ctrlrequest *) urb->setup_packet;
-+
-+      /*
-+       * The stalled endpoint is specified in the wIndex value. The endpoint
-+       * of the urb is the target of this clear_halt request (i.e., control
-+       * endpoint).
-+       */
-+      target_endp = le16_to_cpu(req->wIndex) & 0x000f;
-+
-+      /* the stalled endpoint direction is IN or OUT?. USB_DIR_IN is 0x80.  */
-+      target_dir = le16_to_cpu(req->wIndex) & 0x0080;
-+
-+      if (target_dir)
-+              target_pipe = usb_rcvctrlpipe(urb->dev, target_endp);
-+      else
-+              target_pipe = usb_sndctrlpipe(urb->dev, target_endp);
-+
-+      ret = usb_clear_halt(urb->dev, target_pipe);
-+      if (ret < 0)
-+              uinfo("clear_halt error: devnum %d endp %d, %d\n",
-+                              urb->dev->devnum, target_endp, ret);
-+      else
-+              uinfo("clear_halt done: devnum %d endp %d\n",
-+                              urb->dev->devnum, target_endp);
-+
-+      return ret;
-+}
-+
-+static int tweak_set_interface_cmd(struct urb *urb)
-+{
-+      struct usb_ctrlrequest *req;
-+      __u16 alternate;
-+      __u16 interface;
-+      int ret;
-+
-+      req = (struct usb_ctrlrequest *) urb->setup_packet;
-+      alternate = le16_to_cpu(req->wValue);
-+      interface = le16_to_cpu(req->wIndex);
-+
-+      dbg_stub_rx("set_interface: inf %u alt %u\n", interface, alternate);
-+
-+      ret = usb_set_interface(urb->dev, interface, alternate);
-+      if (ret < 0)
-+              uinfo("set_interface error: inf %u alt %u, %d\n",
-+                              interface, alternate, ret);
-+      else
-+              uinfo("set_interface done: inf %u alt %u\n",
-+                                                      interface,
-+                                                      alternate);
-+
-+      return ret;
-+}
-+
-+static int tweak_set_configuration_cmd(struct urb *urb)
-+{
-+      struct usb_ctrlrequest *req;
-+      __u16 config;
-+
-+      req = (struct usb_ctrlrequest *) urb->setup_packet;
-+      config = le16_to_cpu(req->wValue);
-+
-+      /*
-+       * I have never seen a multi-config device. Very rare.
-+       * For most devices, this will be called to choose a default
-+       * configuration only once in an initialization phase.
-+       *
-+       * set_configuration may change a device configuration and its device
-+       * drivers will be unbound and assigned for a new device configuration.
-+       * This means this usbip driver will be also unbound when called, then
-+       * eventually reassigned to the device as far as driver matching
-+       * condition is kept.
-+       *
-+       * Unfortunatelly, an existing usbip connection will be dropped
-+       * due to this driver unbinding. So, skip here.
-+       * A user may need to set a special configuration value before
-+       * exporting the device.
-+       */
-+      uinfo("set_configuration (%d) to %s\n", config, urb->dev->dev.bus_id);
-+      uinfo("but, skip!\n");
-+
-+      return 0;
-+      /* return usb_driver_set_configuration(urb->dev, config); */
-+}
-+
-+static int tweak_reset_device_cmd(struct urb *urb)
-+{
-+      struct usb_ctrlrequest *req;
-+      __u16 value;
-+      __u16 index;
-+      int ret;
-+
-+      req = (struct usb_ctrlrequest *) urb->setup_packet;
-+      value = le16_to_cpu(req->wValue);
-+      index = le16_to_cpu(req->wIndex);
-+
-+      uinfo("reset_device (port %d) to %s\n", index, urb->dev->dev.bus_id);
-+
-+      /* all interfaces should be owned by usbip driver, so just reset it.  */
-+      ret = usb_lock_device_for_reset(urb->dev, NULL);
-+      if (ret < 0) {
-+              dev_err(&urb->dev->dev, "lock for reset\n");
-+              return ret;
-+      }
-+
-+      /* try to reset the device */
-+      ret = usb_reset_device(urb->dev);
-+      if (ret < 0)
-+              dev_err(&urb->dev->dev, "device reset\n");
-+
-+      usb_unlock_device(urb->dev);
-+
-+      return ret;
-+}
-+
-+/*
-+ * clear_halt, set_interface, and set_configuration require special tricks.
-+ */
-+static void tweak_special_requests(struct urb *urb)
-+{
-+      if (!urb || !urb->setup_packet)
-+              return;
-+
-+      if (usb_pipetype(urb->pipe) != PIPE_CONTROL)
-+              return;
-+
-+      if (is_clear_halt_cmd(urb))
-+              /* tweak clear_halt */
-+               tweak_clear_halt_cmd(urb);
-+
-+      else if (is_set_interface_cmd(urb))
-+              /* tweak set_interface */
-+              tweak_set_interface_cmd(urb);
-+
-+      else if (is_set_configuration_cmd(urb))
-+              /* tweak set_configuration */
-+              tweak_set_configuration_cmd(urb);
-+
-+      else if (is_reset_device_cmd(urb))
-+              tweak_reset_device_cmd(urb);
-+      else
-+              dbg_stub_rx("no need to tweak\n");
-+}
-+
-+/*
-+ * stub_recv_unlink() unlinks the URB by a call to usb_unlink_urb().
-+ * By unlinking the urb asynchronously, stub_rx can continuously
-+ * process coming urbs.  Even if the urb is unlinked, its completion
-+ * handler will be called and stub_tx will send a return pdu.
-+ *
-+ * See also comments about unlinking strategy in vhci_hcd.c.
-+ */
-+static int stub_recv_cmd_unlink(struct stub_device *sdev,
-+                                              struct usbip_header *pdu)
-+{
-+      struct list_head *listhead = &sdev->priv_init;
-+      struct list_head *ptr;
-+      unsigned long flags;
-+
-+      struct stub_priv *priv;
-+
-+
-+      spin_lock_irqsave(&sdev->priv_lock, flags);
-+
-+      for (ptr = listhead->next; ptr != listhead; ptr = ptr->next) {
-+              priv = list_entry(ptr, struct stub_priv, list);
-+              if (priv->seqnum == pdu->u.cmd_unlink.seqnum) {
-+                      int ret;
-+
-+                      dev_info(&priv->urb->dev->dev, "unlink urb %p\n",
-+                               priv->urb);
-+
-+                      /*
-+                       * This matched urb is not completed yet (i.e., be in
-+                       * flight in usb hcd hardware/driver). Now we are
-+                       * cancelling it. The unlinking flag means that we are
-+                       * now not going to return the normal result pdu of a
-+                       * submission request, but going to return a result pdu
-+                       * of the unlink request.
-+                       */
-+                      priv->unlinking = 1;
-+
-+                      /*
-+                       * In the case that unlinking flag is on, prev->seqnum
-+                       * is changed from the seqnum of the cancelling urb to
-+                       * the seqnum of the unlink request. This will be used
-+                       * to make the result pdu of the unlink request.
-+                       */
-+                      priv->seqnum = pdu->base.seqnum;
-+
-+                      spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+
-+                      /*
-+                       * usb_unlink_urb() is now out of spinlocking to avoid
-+                       * spinlock recursion since stub_complete() is
-+                       * sometimes called in this context but not in the
-+                       * interrupt context.  If stub_complete() is executed
-+                       * before we call usb_unlink_urb(), usb_unlink_urb()
-+                       * will return an error value. In this case, stub_tx
-+                       * will return the result pdu of this unlink request
-+                       * though submission is completed and actual unlinking
-+                       * is not executed. OK?
-+                       */
-+                      /* In the above case, urb->status is not -ECONNRESET,
-+                       * so a driver in a client host will know the failure
-+                       * of the unlink request ?
-+                       */
-+                      ret = usb_unlink_urb(priv->urb);
-+                      if (ret != -EINPROGRESS)
-+                              dev_err(&priv->urb->dev->dev,
-+                                      "failed to unlink a urb %p, ret %d\n",
-+                                      priv->urb, ret);
-+                      return 0;
-+              }
-+      }
-+
-+      dbg_stub_rx("seqnum %d is not pending\n", pdu->u.cmd_unlink.seqnum);
-+
-+      /*
-+       * The urb of the unlink target is not found in priv_init queue. It was
-+       * already completed and its results is/was going to be sent by a
-+       * CMD_RET pdu. In this case, usb_unlink_urb() is not needed. We only
-+       * return the completeness of this unlink request to vhci_hcd.
-+       */
-+      stub_enqueue_ret_unlink(sdev, pdu->base.seqnum, 0);
-+
-+      spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+
-+
-+      return 0;
-+}
-+
-+static int valid_request(struct stub_device *sdev, struct usbip_header *pdu)
-+{
-+      struct usbip_device *ud = &sdev->ud;
-+
-+      if (pdu->base.devid == sdev->devid) {
-+              spin_lock(&ud->lock);
-+              if (ud->status == SDEV_ST_USED) {
-+                      /* A request is valid. */
-+                      spin_unlock(&ud->lock);
-+                      return 1;
-+              }
-+              spin_unlock(&ud->lock);
-+      }
-+
-+      return 0;
-+}
-+
-+static struct stub_priv *stub_priv_alloc(struct stub_device *sdev,
-+                                       struct usbip_header *pdu)
-+{
-+      struct stub_priv *priv;
-+      struct usbip_device *ud = &sdev->ud;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&sdev->priv_lock, flags);
-+
-+      priv = kmem_cache_alloc(stub_priv_cache, GFP_ATOMIC);
-+      if (!priv) {
-+              dev_err(&sdev->interface->dev, "alloc stub_priv\n");
-+              spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+              usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
-+              return NULL;
-+      }
-+
-+      memset(priv, 0, sizeof(struct stub_priv));
-+
-+      priv->seqnum = pdu->base.seqnum;
-+      priv->sdev = sdev;
-+
-+      /*
-+       * After a stub_priv is linked to a list_head,
-+       * our error handler can free allocated data.
-+       */
-+      list_add_tail(&priv->list, &sdev->priv_init);
-+
-+      spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+
-+      return priv;
-+}
-+
-+
-+static struct usb_host_endpoint *get_ep_from_epnum(struct usb_device *udev,
-+              int epnum0)
-+{
-+      struct usb_host_config *config;
-+      int i = 0, j = 0;
-+      struct usb_host_endpoint *ep = NULL;
-+      int epnum;
-+      int found = 0;
-+
-+      if (epnum0 == 0)
-+              return &udev->ep0;
-+
-+      config = udev->actconfig;
-+      if (!config)
-+              return NULL;
-+
-+      for (i = 0; i < config->desc.bNumInterfaces; i++) {
-+              struct usb_host_interface *setting;
-+
-+              setting = config->interface[i]->cur_altsetting;
-+
-+              for (j = 0; j < setting->desc.bNumEndpoints; j++) {
-+                      ep = &setting->endpoint[j];
-+                      epnum = (ep->desc.bEndpointAddress & 0x7f);
-+
-+                      if (epnum == epnum0) {
-+                              /* uinfo("found epnum %d\n", epnum0); */
-+                              found = 1;
-+                              break;
-+                      }
-+              }
-+      }
-+
-+      if (found)
-+              return ep;
-+      else
-+              return NULL;
-+}
-+
-+
-+static int get_pipe(struct stub_device *sdev, int epnum, int dir)
-+{
-+      struct usb_device *udev = interface_to_usbdev(sdev->interface);
-+      struct usb_host_endpoint *ep;
-+      struct usb_endpoint_descriptor *epd = NULL;
-+
-+      ep = get_ep_from_epnum(udev, epnum);
-+      if (!ep) {
-+              dev_err(&sdev->interface->dev, "no such endpoint?, %d\n",
-+                      epnum);
-+              BUG();
-+      }
-+
-+      epd = &ep->desc;
-+
-+
-+#if 0
-+      /* epnum 0 is always control */
-+      if (epnum == 0) {
-+              if (dir == USBIP_DIR_OUT)
-+                      return usb_sndctrlpipe(udev, 0);
-+              else
-+                      return usb_rcvctrlpipe(udev, 0);
-+      }
-+#endif
-+
-+      if (usb_endpoint_xfer_control(epd)) {
-+              if (dir == USBIP_DIR_OUT)
-+                      return usb_sndctrlpipe(udev, epnum);
-+              else
-+                      return usb_rcvctrlpipe(udev, epnum);
-+      }
-+
-+      if (usb_endpoint_xfer_bulk(epd)) {
-+              if (dir == USBIP_DIR_OUT)
-+                      return usb_sndbulkpipe(udev, epnum);
-+              else
-+                      return usb_rcvbulkpipe(udev, epnum);
-+      }
-+
-+      if (usb_endpoint_xfer_int(epd)) {
-+              if (dir == USBIP_DIR_OUT)
-+                      return usb_sndintpipe(udev, epnum);
-+              else
-+                      return usb_rcvintpipe(udev, epnum);
-+      }
-+
-+      if (usb_endpoint_xfer_isoc(epd)) {
-+              if (dir == USBIP_DIR_OUT)
-+                      return usb_sndisocpipe(udev, epnum);
-+              else
-+                      return usb_rcvisocpipe(udev, epnum);
-+      }
-+
-+      /* NOT REACHED */
-+      dev_err(&sdev->interface->dev, "get pipe, epnum %d\n", epnum);
-+      return 0;
-+}
-+
-+static void stub_recv_cmd_submit(struct stub_device *sdev,
-+                               struct usbip_header *pdu)
-+{
-+      int ret;
-+      struct stub_priv *priv;
-+      struct usbip_device *ud = &sdev->ud;
-+      struct usb_device *udev = interface_to_usbdev(sdev->interface);
-+      int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction);
-+
-+
-+      priv = stub_priv_alloc(sdev, pdu);
-+      if (!priv)
-+              return;
-+
-+      /* setup a urb */
-+      if (usb_pipeisoc(pipe))
-+              priv->urb = usb_alloc_urb(pdu->u.cmd_submit.number_of_packets,
-+                                                              GFP_KERNEL);
-+      else
-+              priv->urb = usb_alloc_urb(0, GFP_KERNEL);
-+
-+      if (!priv->urb) {
-+              dev_err(&sdev->interface->dev, "malloc urb\n");
-+              usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
-+              return;
-+      }
-+
-+      /* set priv->urb->transfer_buffer */
-+      if (pdu->u.cmd_submit.transfer_buffer_length > 0) {
-+              priv->urb->transfer_buffer =
-+                      kzalloc(pdu->u.cmd_submit.transfer_buffer_length,
-+                                                              GFP_KERNEL);
-+              if (!priv->urb->transfer_buffer) {
-+                      dev_err(&sdev->interface->dev, "malloc x_buff\n");
-+                      usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
-+                      return;
-+              }
-+      }
-+
-+      /* set priv->urb->setup_packet */
-+      priv->urb->setup_packet = kzalloc(8, GFP_KERNEL);
-+      if (!priv->urb->setup_packet) {
-+              dev_err(&sdev->interface->dev, "allocate setup_packet\n");
-+              usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
-+              return;
-+      }
-+      memcpy(priv->urb->setup_packet, &pdu->u.cmd_submit.setup, 8);
-+
-+      /* set other members from the base header of pdu */
-+      priv->urb->context                = (void *) priv;
-+      priv->urb->dev                    = udev;
-+      priv->urb->pipe                   = pipe;
-+      priv->urb->complete               = stub_complete;
-+
-+      usbip_pack_pdu(pdu, priv->urb, USBIP_CMD_SUBMIT, 0);
-+
-+
-+      if (usbip_recv_xbuff(ud, priv->urb) < 0)
-+              return;
-+
-+      if (usbip_recv_iso(ud, priv->urb) < 0)
-+              return;
-+
-+      /* no need to submit an intercepted request, but harmless? */
-+      tweak_special_requests(priv->urb);
-+
-+      /* urb is now ready to submit */
-+      ret = usb_submit_urb(priv->urb, GFP_KERNEL);
-+
-+      if (ret == 0)
-+              dbg_stub_rx("submit urb ok, seqnum %u\n", pdu->base.seqnum);
-+      else {
-+              dev_err(&sdev->interface->dev, "submit_urb error, %d\n", ret);
-+              usbip_dump_header(pdu);
-+              usbip_dump_urb(priv->urb);
-+
-+              /*
-+               * Pessimistic.
-+               * This connection will be discarded.
-+               */
-+              usbip_event_add(ud, SDEV_EVENT_ERROR_SUBMIT);
-+      }
-+
-+      dbg_stub_rx("Leave\n");
-+      return;
-+}
-+
-+/* recv a pdu */
-+static void stub_rx_pdu(struct usbip_device *ud)
-+{
-+      int ret;
-+      struct usbip_header pdu;
-+      struct stub_device *sdev = container_of(ud, struct stub_device, ud);
-+      struct device *dev = &sdev->interface->dev;
-+
-+      dbg_stub_rx("Enter\n");
-+
-+      memset(&pdu, 0, sizeof(pdu));
-+
-+      /* 1. receive a pdu header */
-+      ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0);
-+      if (ret != sizeof(pdu)) {
-+              dev_err(dev, "recv a header, %d\n", ret);
-+              usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
-+              return;
-+      }
-+
-+      usbip_header_correct_endian(&pdu, 0);
-+
-+      if (dbg_flag_stub_rx)
-+              usbip_dump_header(&pdu);
-+
-+      if (!valid_request(sdev, &pdu)) {
-+              dev_err(dev, "recv invalid request\n");
-+              usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
-+              return;
-+      }
-+
-+      switch (pdu.base.command) {
-+      case USBIP_CMD_UNLINK:
-+              stub_recv_cmd_unlink(sdev, &pdu);
-+              break;
-+
-+      case USBIP_CMD_SUBMIT:
-+              stub_recv_cmd_submit(sdev, &pdu);
-+              break;
-+
-+      default:
-+              /* NOTREACHED */
-+              dev_err(dev, "unknown pdu\n");
-+              usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
-+              return;
-+      }
-+
-+}
-+
-+void stub_rx_loop(struct usbip_task *ut)
-+{
-+      struct usbip_device *ud = container_of(ut, struct usbip_device, tcp_rx);
-+
-+      while (1) {
-+              if (signal_pending(current)) {
-+                      dbg_stub_rx("signal caught!\n");
-+                      break;
-+              }
-+
-+              if (usbip_event_happend(ud))
-+                      break;
-+
-+              stub_rx_pdu(ud);
-+      }
-+}
-diff --git a/drivers/staging/usbip/stub_tx.c b/drivers/staging/usbip/stub_tx.c
-new file mode 100644
-index 0000000..d5563cd
---- /dev/null
-+++ b/drivers/staging/usbip/stub_tx.c
-@@ -0,0 +1,371 @@
-+/*
-+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
-+ *
-+ * This 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 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 "usbip_common.h"
-+#include "stub.h"
-+
-+
-+static void stub_free_priv_and_urb(struct stub_priv *priv)
-+{
-+      struct urb *urb = priv->urb;
-+
-+      kfree(urb->setup_packet);
-+      kfree(urb->transfer_buffer);
-+      list_del(&priv->list);
-+      kmem_cache_free(stub_priv_cache, priv);
-+      usb_free_urb(urb);
-+}
-+
-+/* be in spin_lock_irqsave(&sdev->priv_lock, flags) */
-+void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum,
-+                           __u32 status)
-+{
-+      struct stub_unlink *unlink;
-+
-+      unlink = kzalloc(sizeof(struct stub_unlink), GFP_ATOMIC);
-+      if (!unlink) {
-+              dev_err(&sdev->interface->dev, "alloc stub_unlink\n");
-+              usbip_event_add(&sdev->ud, VDEV_EVENT_ERROR_MALLOC);
-+              return;
-+      }
-+
-+      unlink->seqnum = seqnum;
-+      unlink->status = status;
-+
-+      list_add_tail(&unlink->list, &sdev->unlink_tx);
-+}
-+
-+/**
-+ * stub_complete - completion handler of a usbip urb
-+ * @urb: pointer to the urb completed
-+ * @regs:
-+ *
-+ * When a urb has completed, the USB core driver calls this function mostly in
-+ * the interrupt context. To return the result of a urb, the completed urb is
-+ * linked to the pending list of returning.
-+ *
-+ */
-+void stub_complete(struct urb *urb)
-+{
-+      struct stub_priv *priv = (struct stub_priv *) urb->context;
-+      struct stub_device *sdev = priv->sdev;
-+      unsigned long flags;
-+
-+      dbg_stub_tx("complete! status %d\n", urb->status);
-+
-+
-+      switch (urb->status) {
-+      case 0:
-+              /* OK */
-+              break;
-+      case -ENOENT:
-+              uinfo("stopped by a call of usb_kill_urb() because of"
-+                                      "cleaning up a virtual connection\n");
-+              return;
-+      case -ECONNRESET:
-+              uinfo("unlinked by a call of usb_unlink_urb()\n");
-+              break;
-+      case -EPIPE:
-+              uinfo("endpoint %d is stalled\n", usb_pipeendpoint(urb->pipe));
-+              break;
-+      case -ESHUTDOWN:
-+              uinfo("device removed?\n");
-+              break;
-+      default:
-+              uinfo("urb completion with non-zero status %d\n", urb->status);
-+      }
-+
-+      /* link a urb to the queue of tx. */
-+      spin_lock_irqsave(&sdev->priv_lock, flags);
-+
-+      if (priv->unlinking) {
-+              stub_enqueue_ret_unlink(sdev, priv->seqnum, urb->status);
-+              stub_free_priv_and_urb(priv);
-+      } else
-+              list_move_tail(&priv->list, &sdev->priv_tx);
-+
-+
-+      spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+
-+      /* wake up tx_thread */
-+      wake_up(&sdev->tx_waitq);
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+/* fill PDU */
-+
-+static inline void setup_base_pdu(struct usbip_header_basic *base,
-+              __u32 command, __u32 seqnum)
-+{
-+      base->command = command;
-+      base->seqnum  = seqnum;
-+      base->devid   = 0;
-+      base->ep      = 0;
-+      base->direction   = 0;
-+}
-+
-+static void setup_ret_submit_pdu(struct usbip_header *rpdu, struct urb *urb)
-+{
-+      struct stub_priv *priv = (struct stub_priv *) urb->context;
-+
-+      setup_base_pdu(&rpdu->base, USBIP_RET_SUBMIT, priv->seqnum);
-+
-+      usbip_pack_pdu(rpdu, urb, USBIP_RET_SUBMIT, 1);
-+}
-+
-+static void setup_ret_unlink_pdu(struct usbip_header *rpdu,
-+              struct stub_unlink *unlink)
-+{
-+      setup_base_pdu(&rpdu->base, USBIP_RET_UNLINK, unlink->seqnum);
-+
-+      rpdu->u.ret_unlink.status = unlink->status;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+/* send RET_SUBMIT */
-+
-+static struct stub_priv *dequeue_from_priv_tx(struct stub_device *sdev)
-+{
-+      unsigned long flags;
-+      struct stub_priv *priv, *tmp;
-+
-+      spin_lock_irqsave(&sdev->priv_lock, flags);
-+
-+      list_for_each_entry_safe(priv, tmp, &sdev->priv_tx, list) {
-+              list_move_tail(&priv->list, &sdev->priv_free);
-+              spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+              return priv;
-+      }
-+
-+      spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+
-+      return NULL;
-+}
-+
-+static int stub_send_ret_submit(struct stub_device *sdev)
-+{
-+      unsigned long flags;
-+      struct stub_priv *priv, *tmp;
-+
-+      struct msghdr msg;
-+      struct kvec iov[3];
-+      size_t txsize;
-+
-+      size_t total_size = 0;
-+
-+      while ((priv = dequeue_from_priv_tx(sdev)) != NULL) {
-+              int ret;
-+              struct urb *urb = priv->urb;
-+              struct usbip_header pdu_header;
-+              void *iso_buffer = NULL;
-+
-+              txsize = 0;
-+              memset(&pdu_header, 0, sizeof(pdu_header));
-+              memset(&msg, 0, sizeof(msg));
-+              memset(&iov, 0, sizeof(iov));
-+
-+              dbg_stub_tx("setup txdata urb %p\n", urb);
-+
-+
-+              /* 1. setup usbip_header */
-+              setup_ret_submit_pdu(&pdu_header, urb);
-+              usbip_header_correct_endian(&pdu_header, 1);
-+
-+              iov[0].iov_base = &pdu_header;
-+              iov[0].iov_len  = sizeof(pdu_header);
-+              txsize += sizeof(pdu_header);
-+
-+              /* 2. setup transfer buffer */
-+              if (usb_pipein(urb->pipe) && urb->actual_length > 0) {
-+                      iov[1].iov_base = urb->transfer_buffer;
-+                      iov[1].iov_len  = urb->actual_length;
-+                      txsize += urb->actual_length;
-+              }
-+
-+              /* 3. setup iso_packet_descriptor */
-+              if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-+                      ssize_t len = 0;
-+
-+                      iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len);
-+                      if (!iso_buffer) {
-+                              usbip_event_add(&sdev->ud,
-+                                              SDEV_EVENT_ERROR_MALLOC);
-+                              return -1;
-+                      }
-+
-+                      iov[2].iov_base = iso_buffer;
-+                      iov[2].iov_len  = len;
-+                      txsize += len;
-+              }
-+
-+              ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov,
-+                                   3, txsize);
-+              if (ret != txsize) {
-+                      dev_err(&sdev->interface->dev,
-+                              "sendmsg failed!, retval %d for %zd\n",
-+                              ret, txsize);
-+                      kfree(iso_buffer);
-+                      usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
-+                      return -1;
-+              }
-+
-+              kfree(iso_buffer);
-+              dbg_stub_tx("send txdata\n");
-+
-+              total_size += txsize;
-+      }
-+
-+
-+      spin_lock_irqsave(&sdev->priv_lock, flags);
-+
-+      list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) {
-+              stub_free_priv_and_urb(priv);
-+      }
-+
-+      spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+
-+      return total_size;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+/* send RET_UNLINK */
-+
-+static struct stub_unlink *dequeue_from_unlink_tx(struct stub_device *sdev)
-+{
-+      unsigned long flags;
-+      struct stub_unlink *unlink, *tmp;
-+
-+      spin_lock_irqsave(&sdev->priv_lock, flags);
-+
-+      list_for_each_entry_safe(unlink, tmp, &sdev->unlink_tx, list) {
-+              list_move_tail(&unlink->list, &sdev->unlink_free);
-+              spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+              return unlink;
-+      }
-+
-+      spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+
-+      return NULL;
-+}
-+
-+
-+static int stub_send_ret_unlink(struct stub_device *sdev)
-+{
-+      unsigned long flags;
-+      struct stub_unlink *unlink, *tmp;
-+
-+      struct msghdr msg;
-+      struct kvec iov[1];
-+      size_t txsize;
-+
-+      size_t total_size = 0;
-+
-+      while ((unlink = dequeue_from_unlink_tx(sdev)) != NULL) {
-+              int ret;
-+              struct usbip_header pdu_header;
-+
-+              txsize = 0;
-+              memset(&pdu_header, 0, sizeof(pdu_header));
-+              memset(&msg, 0, sizeof(msg));
-+              memset(&iov, 0, sizeof(iov));
-+
-+              dbg_stub_tx("setup ret unlink %lu\n", unlink->seqnum);
-+
-+              /* 1. setup usbip_header */
-+              setup_ret_unlink_pdu(&pdu_header, unlink);
-+              usbip_header_correct_endian(&pdu_header, 1);
-+
-+              iov[0].iov_base = &pdu_header;
-+              iov[0].iov_len  = sizeof(pdu_header);
-+              txsize += sizeof(pdu_header);
-+
-+              ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov,
-+                                   1, txsize);
-+              if (ret != txsize) {
-+                      dev_err(&sdev->interface->dev,
-+                              "sendmsg failed!, retval %d for %zd\n",
-+                              ret, txsize);
-+                      usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
-+                      return -1;
-+              }
-+
-+
-+              dbg_stub_tx("send txdata\n");
-+
-+              total_size += txsize;
-+      }
-+
-+
-+      spin_lock_irqsave(&sdev->priv_lock, flags);
-+
-+      list_for_each_entry_safe(unlink, tmp, &sdev->unlink_free, list) {
-+              list_del(&unlink->list);
-+              kfree(unlink);
-+      }
-+
-+      spin_unlock_irqrestore(&sdev->priv_lock, flags);
-+
-+      return total_size;
-+}
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+void stub_tx_loop(struct usbip_task *ut)
-+{
-+      struct usbip_device *ud = container_of(ut, struct usbip_device, tcp_tx);
-+      struct stub_device *sdev = container_of(ud, struct stub_device, ud);
-+
-+      while (1) {
-+              if (signal_pending(current)) {
-+                      dbg_stub_tx("signal catched\n");
-+                      break;
-+              }
-+
-+              if (usbip_event_happend(ud))
-+                      break;
-+
-+              /*
-+               * send_ret_submit comes earlier than send_ret_unlink.  stub_rx
-+               * looks at only priv_init queue. If the completion of a URB is
-+               * earlier than the receive of CMD_UNLINK, priv is moved to
-+               * priv_tx queue and stub_rx does not find the target priv. In
-+               * this case, vhci_rx receives the result of the submit request
-+               * and then receives the result of the unlink request. The
-+               * result of the submit is given back to the usbcore as the
-+               * completion of the unlink request. The request of the
-+               * unlink is ignored. This is ok because a driver who calls
-+               * usb_unlink_urb() understands the unlink was too late by
-+               * getting the status of the given-backed URB which has the
-+               * status of usb_submit_urb().
-+               */
-+              if (stub_send_ret_submit(sdev) < 0)
-+                      break;
-+
-+              if (stub_send_ret_unlink(sdev) < 0)
-+                      break;
-+
-+              wait_event_interruptible(sdev->tx_waitq,
-+                              (!list_empty(&sdev->priv_tx) ||
-+                               !list_empty(&sdev->unlink_tx)));
-+      }
-+}
--- 
-1.6.0.2
-