aboutsummaryrefslogtreecommitdiffstats
path: root/bad
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-07-03 11:11:11 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2006-07-03 11:11:11 -0700
commitbbc466d1931e2ca1f095824f455833944d9a35ae (patch)
tree193544144770e17a7cb5a0f9b45a8ed6402180e9 /bad
parentedebd83392a7b67e4b4aa1a3d387f0593d07f053 (diff)
downloadpatches-bbc466d1931e2ca1f095824f455833944d9a35ae.tar.gz
move usbip patches and remove MSI ones.
Diffstat (limited to 'bad')
-rw-r--r--bad/usbip/usb-usbip-build-fix.patch59
-rw-r--r--bad/usbip/usb-usbip-more-dead-code-fix.patch40
-rw-r--r--bad/usbip/usb-usbip-warning-fixes.patch48
-rw-r--r--bad/usbip/usbip.patch4611
4 files changed, 4758 insertions, 0 deletions
diff --git a/bad/usbip/usb-usbip-build-fix.patch b/bad/usbip/usb-usbip-build-fix.patch
new file mode 100644
index 0000000000000..4ff26199efae7
--- /dev/null
+++ b/bad/usbip/usb-usbip-build-fix.patch
@@ -0,0 +1,59 @@
+From akpm@osdl.org Thu Jan 5 22:54:11 2006
+Message-Id: <200601060650.k066omZZ008821@shell0.pdx.osdl.net>
+From: Andrew Morton <akpm@osdl.org>
+Subject: USB: usbip build fix
+To: greg@kroah.com
+Cc: akpm@osdl.org, taka-hir@is.naist.jp
+Date: Thu, 05 Jan 2006 22:50:36 -0800
+
+
+From: Andrew Morton <akpm@osdl.org>
+
+Fix this:
+
+drivers/usb/ip/usbip_common.c: In function `socket_to_addrstr':
+drivers/usb/ip/usbip_common.c:582: dereferencing pointer to incomplete type
+drivers/usb/ip/usbip_common.c:582: dereferencing pointer to incomplete type
+drivers/usb/ip/usbip_common.c:582: dereferencing pointer to incomplete type
+drivers/usb/ip/usbip_common.c:582: dereferencing pointer to incomplete type
+
+And this:
+
+drivers/usb/ip/usbip_common.h: At top level:
+drivers/usb/ip/usbip_common.c:441: warning: `usbip_dump_urb' defined but not used
+
+Cc: Takahiro Hirofuchi <taka-hir@is.naist.jp>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/ip/usbip_common.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/ip/usbip_common.c
++++ gregkh-2.6/drivers/usb/ip/usbip_common.c
+@@ -23,6 +23,7 @@
+ #include <linux/kernel.h>
+ #include <linux/file.h>
+ #include <linux/tcp.h>
++#include <linux/in.h>
+ #include "usbip_common.h"
+
+ static void usbip_dump_buffer(char *, int size);
+@@ -254,7 +255,7 @@ static void usbip_dump_pipe(unsigned int
+
+ }
+
+-
++#if 0
+ static void usbip_dump_usb_device(struct usb_device *dev)
+ {
+ if (dev == NULL) {
+@@ -466,7 +467,7 @@ static void usbip_dump_urb (struct urb *
+ printk(" context :%p\n", purb->context);
+ printk(" complete :%p\n", purb->complete);
+ }
+-
++#endif
+
+ void setquickack(struct socket *socket)
+ {
diff --git a/bad/usbip/usb-usbip-more-dead-code-fix.patch b/bad/usbip/usb-usbip-more-dead-code-fix.patch
new file mode 100644
index 0000000000000..f1ff1eb5705b3
--- /dev/null
+++ b/bad/usbip/usb-usbip-more-dead-code-fix.patch
@@ -0,0 +1,40 @@
+From akpm@osdl.org Thu Jan 5 22:54:28 2006
+Message-Id: <200601060650.k066ooIj008824@shell0.pdx.osdl.net>
+From: Andrew Morton <akpm@osdl.org>
+Subject: USB: usbip more dead code fix
+To: greg@kroah.com
+Cc: akpm@osdl.org, taka-hir@is.naist.jp
+From: akpm@osdl.org
+Date: Thu, 05 Jan 2006 22:50:37 -0800
+
+
+From: Andrew Morton <akpm@osdl.org>
+
+drivers/usb/ip/vhci_hcd.c:639: warning: `vhci_device_unlink_all_urb' defined but not used
+
+Cc: Takahiro Hirofuchi <taka-hir@is.naist.jp>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/ip/vhci_hcd.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- gregkh-2.6.orig/drivers/usb/ip/vhci_hcd.c
++++ gregkh-2.6/drivers/usb/ip/vhci_hcd.c
+@@ -634,7 +634,7 @@ static int vhci_urb_dequeue(struct usb_h
+ return 0;
+ }
+
+-
++#if 0
+ static void vhci_device_unlink_all_urb(struct vhci_device *vdev)
+ {
+ struct vhci_priv *priv, *tmp;
+@@ -674,6 +674,7 @@ static void vhci_device_unlink_all_urb(s
+
+ spin_unlock(&vdev->priv_lock);
+ }
++#endif
+
+ /*
+ * The important thing is that only one context begins cleanup.
diff --git a/bad/usbip/usb-usbip-warning-fixes.patch b/bad/usbip/usb-usbip-warning-fixes.patch
new file mode 100644
index 0000000000000..e6cf05290d8ca
--- /dev/null
+++ b/bad/usbip/usb-usbip-warning-fixes.patch
@@ -0,0 +1,48 @@
+From akpm@osdl.org Thu Jan 19 23:59:29 2006
+Message-Id: <200601200759.k0K7xPcm020721@shell0.pdx.osdl.net>
+Subject: [patch 1/2] usb: usbip warning fixes
+To: greg@kroah.com
+Cc: akpm@osdl.org
+From: akpm@osdl.org
+Date: Thu, 19 Jan 2006 23:59:11 -0800
+
+
+From: Andrew Morton <akpm@osdl.org>
+
+drivers/usb/ip/stub_tx.c: In function `stub_send_txdata':
+drivers/usb/ip/stub_tx.c:158: warning: int format, different type arg (arg 7)
+drivers/usb/ip/vhci_tx.c: In function `vhci_send_txdata':
+drivers/usb/ip/vhci_tx.c:137: warning: int format, different type arg (arg 7)
+
+
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/ip/stub_tx.c | 3 ++-
+ drivers/usb/ip/vhci_tx.c | 3 ++-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/ip/stub_tx.c
++++ gregkh-2.6/drivers/usb/ip/stub_tx.c
+@@ -155,7 +155,8 @@ static int stub_send_txdata(struct stub_
+ int ret;
+ ret = usbip_sendmsg(sdev->ud.tcp_socket, &msg, txsize);
+ if (ret != txsize) {
+- VHCI_ERROR("vhci_sendmsg failed!, retval %d for %d\n", ret, txsize);
++ VHCI_ERROR("vhci_sendmsg failed!, retval %d for %zd\n",
++ ret, txsize);
+ usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
+ return -1;
+ }
+--- gregkh-2.6.orig/drivers/usb/ip/vhci_tx.c
++++ gregkh-2.6/drivers/usb/ip/vhci_tx.c
+@@ -134,7 +134,8 @@ static int vhci_send_txdata(struct vhci_
+ int ret;
+ ret = usbip_sendmsg(vdev->ud.tcp_socket, &msg, txsize);
+ if (ret != txsize) {
+- VHCI_ERROR("vhci_sendmsg failed!, retval %d for %d\n", ret, txsize);
++ VHCI_ERROR("vhci_sendmsg failed!, retval %d for %zd\n",
++ ret, txsize);
+ usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
+ return -1;
+ }
diff --git a/bad/usbip/usbip.patch b/bad/usbip/usbip.patch
new file mode 100644
index 0000000000000..78da15bd294dc
--- /dev/null
+++ b/bad/usbip/usbip.patch
@@ -0,0 +1,4611 @@
+Subject: USB: add USB IP host and client driver
+From: Takahiro Hirofuchi <taka-hir@is.naist.jp>
+
+Implementes a USB over IP host driver and client device. Still a bit
+rough around the edges, but a great first implementation.
+
+See http://usbip.naist.jp/ for more information about this project, and
+a link to the userspace tools needed to get this to work.
+
+---
+ drivers/usb/Kconfig | 2
+ drivers/usb/Makefile | 2
+ drivers/usb/ip/Kconfig | 32 +
+ drivers/usb/ip/Makefile | 13
+ drivers/usb/ip/stub.h | 93 +++
+ drivers/usb/ip/stub_dev.c | 419 +++++++++++++++++
+ drivers/usb/ip/stub_main.c | 319 +++++++++++++
+ drivers/usb/ip/stub_rx.c | 320 +++++++++++++
+ drivers/usb/ip/stub_tx.c | 205 ++++++++
+ drivers/usb/ip/usbip_common.c | 860 +++++++++++++++++++++++++++++++++++
+ drivers/usb/ip/usbip_common.h | 392 ++++++++++++++++
+ drivers/usb/ip/usbip_event.c | 147 ++++++
+ drivers/usb/ip/vhci.h | 110 ++++
+ drivers/usb/ip/vhci_hcd.c | 1026 ++++++++++++++++++++++++++++++++++++++++++
+ drivers/usb/ip/vhci_rx.c | 149 ++++++
+ drivers/usb/ip/vhci_sysfs.c | 265 ++++++++++
+ drivers/usb/ip/vhci_tx.c | 165 ++++++
+ 17 files changed, 4519 insertions(+)
+
+--- gregkh-2.6.orig/drivers/usb/Kconfig
++++ gregkh-2.6/drivers/usb/Kconfig
+@@ -81,6 +81,8 @@ source "drivers/usb/core/Kconfig"
+
+ source "drivers/usb/host/Kconfig"
+
++source "drivers/usb/ip/Kconfig"
++
+ source "drivers/usb/class/Kconfig"
+
+ source "drivers/usb/storage/Kconfig"
+--- gregkh-2.6.orig/drivers/usb/Makefile
++++ gregkh-2.6/drivers/usb/Makefile
+@@ -17,6 +17,8 @@ obj-$(CONFIG_USB_SL811_HCD) += host/
+ obj-$(CONFIG_ETRAX_USB_HOST) += host/
+ obj-$(CONFIG_USB_OHCI_AT91) += host/
+
++obj-$(CONFIG_USB_IP) += ip/
++
+ obj-$(CONFIG_USB_ACM) += class/
+ obj-$(CONFIG_USB_PRINTER) += class/
+
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/Kconfig
+@@ -0,0 +1,32 @@
++#config USB_IP
++# bool "USB IP support (EXPERIMENTAL)"
++# depends on USB && EXPERIMENTAL
++# default N
++# ---help---
++# This enables pushing USB packets over IP to allow remote
++# machines access to USB devices directly. For more details,
++# and links to the userspace utility programs to let this work
++# properly, see http://usbip.naist.jp/
++#
++# If unsure, say N.
++
++config USB_IP_VHCI
++ tristate "USB IP Host controller driver"
++ depends on USB_IP
++ ---help---
++ This enables the USB IP host controller driver which will
++ run on the client machine.
++
++ To compile this driver as a module, choose M here: the
++ module will be called vhci-hcd.
++
++config USB_IP_STUB
++ tristate "USB IP stub driver"
++ depends on USB_IP
++ ---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 stub.
++
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/Makefile
+@@ -0,0 +1,13 @@
++# Makefile for the USB/IP driver
++
++obj-$(CONFIG_USB_IP_VHCI) += vhci-hcd.o
++vhci-hcd-objs := usbip_common.o usbip_event.o vhci_sysfs.o vhci_tx.o vhci_rx.o vhci_hcd.o
++
++obj-$(CONFIG_USB_IP_STUB) += stub.o
++stub-objs := usbip_common.o usbip_event.o stub_dev.o stub_main.o stub_rx.o stub_tx.o
++
++
++ifeq ($(CONFIG_USB_DEBUG),y)
++ EXTRA_CFLAGS += -DDEBUG
++endif
++
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/stub.h
+@@ -0,0 +1,93 @@
++/*
++ * $Id: stub.h 265 2005-09-01 09:24:10Z taka-hir $
++ *
++ * Copyright (C) 2003-2005 Takahiro Hirofuchi <taka-hir@is.naist.jp>
++ *
++ *
++ * 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/list.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++
++struct stub_device {
++ struct usb_interface *interface;
++ struct list_head list;
++
++ struct usbip_device ud;
++
++ /*
++ * stub_priv preserves private data of each urb.
++ * It is allocated as StubPrivCache 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;
++
++};
++
++struct stub_priv {
++ unsigned long seqnum;
++ struct list_head list;
++ struct stub_device *sdev;
++ struct urb *urb;
++
++ /*
++ * This flag is true between usb_submit_urb() and urb->complete()
++ * to show a urb needs usb_unlink_urb().
++ */
++ atomic_t in_submit;
++};
++
++extern kmem_cache_t *StubPrivCache;
++
++#if 0
++enum stub_priv_list_operation {
++ CLEAR_BY_SEQNUM,
++ CLEAR_BY_SDEV,
++ DUMP_ALL
++} ;
++
++int stub_priv_list_data(struct stub_device *, enum stub_priv_list_operation operation, void *arg);
++#endif
++void stub_device_cleanup_urbs(struct stub_device *sdev);
++
++/*
++ * prototype declarations
++ */
++
++
++/* stub_tx.c */
++void stub_complete(struct urb*, struct pt_regs *);
++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_shutdown_connection(struct usbip_device *sdev);
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/stub_dev.c
+@@ -0,0 +1,419 @@
++/*
++ * $Id: stub_dev.c 265 2005-09-01 09:24:10Z taka-hir $
++ *
++ * Copyright (C) 2003-2005 Takahiro Hirofuchi <taka-hir@is.naist.jp>
++ *
++ *
++ * 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 "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);
++
++
++/* Now all devices except USB Hub are claimed. */
++static struct usb_device_id stub_table [] = {
++#if 0
++ { 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
++ { .driver_info = 1 },
++ { } /* Terminating entry */
++};
++
++#include <linux/module.h>
++MODULE_DEVICE_TABLE (usb, stub_table);
++
++/* usb specific object needed to register this driver with the usb subsystem */
++struct usb_driver stub_driver = {
++ .name = "usbip_stub",
++ .probe = stub_probe,
++ .disconnect = stub_disconnect,
++ /* If id_table is null and any other driver claimed,
++ * probe() is always called . */
++ .id_table = stub_table,
++};
++
++
++
++
++
++/* ------------------------------------------------------------ */
++/* ------------------------------------------------------------ */
++/* ------------------------------------------------------------ */
++
++
++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) {
++ VHCI_ERROR("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);
++
++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) {
++ VHCI_ERROR("sdev is null\n");
++ return -ENODEV;
++ }
++
++ sscanf(buf, "%u", &sockfd);
++
++ if (sockfd != 0) {
++ VHCI_INFO("stub up\n");
++
++ spin_lock(&sdev->ud.lock);
++
++ if (sdev->ud.status != SDEV_ST_AVAILABLE) {
++ VHCI_ERROR("not ready\n");
++ spin_unlock(&sdev->ud.lock);
++ return -EINVAL;
++ }
++
++ socket = sockfd_to_socket(sockfd);
++ if (!socket) {
++ spin_unlock(&sdev->ud.lock);
++ return -EINVAL;
++ }
++
++ setnodelay(socket);
++ setkeepalive(socket);
++ setreuse(socket);
++
++ 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 {
++ VHCI_INFO("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 ssize_t show_sockfd(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct stub_device *sdev = dev_get_drvdata(dev);
++
++ if (!sdev) {
++ VHCI_ERROR("sdev is null\n");
++ return -ENODEV;
++ }
++
++ return snprintf(buf, PAGE_SIZE, "%d\n", 0);
++}
++static DEVICE_ATTR(usbip_sockfd, S_IWUGO | S_IRUGO, show_sockfd, store_sockfd);
++
++static void stub_add_files(struct device *dev)
++{
++ device_create_file(dev, &dev_attr_usbip_status);
++ device_create_file(dev, &dev_attr_usbip_sockfd);
++ device_create_file(dev, &dev_attr_usbip_debug);
++}
++
++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);
++}
++
++
++
++/* ------------------------------------------------------------ */
++/* ------------------------------------------------------------ */
++/* ------------------------------------------------------------ */
++
++static void stub_shutdown_connection(struct usbip_device *ud)
++{
++ struct stub_device *sdev = container_of(ud, struct stub_device, ud);
++
++ /* 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 != NULL) {
++ sock_release(ud->tcp_socket);
++ ud->tcp_socket = NULL;
++ }
++
++ /* 3. free used data */
++ //stub_priv_list_data(sdev, CLEAR_BY_SDEV, NULL);
++ stub_device_cleanup_urbs(sdev);
++}
++
++
++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;
++
++ ret = usb_lock_device_for_reset(udev, sdev->interface);
++ if(ret < 0) {
++ VHCI_ERROR("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) {
++ VHCI_ERROR("device reset\n");
++ ud->status = SDEV_ST_ERROR;
++
++ } else {
++ VHCI_INFO("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_devce struct.
++ */
++static struct stub_device * stub_device_alloc(struct usb_interface *interface)
++{
++ struct stub_device *sdev;
++
++
++ /* yes, it's a new device */
++ sdev = (struct stub_device *) kmalloc(sizeof(struct stub_device), GFP_KERNEL);
++ if(!sdev) {
++ VHCI_ERROR("no memory for stub_device\n");
++ return NULL;
++ }
++
++ memset(sdev, 0, sizeof(struct stub_device));
++
++ sdev->interface = interface;
++
++
++ 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;
++ sdev->ud.tcp_socket = NULL;
++
++ INIT_LIST_HEAD(&sdev->priv_init);
++ INIT_LIST_HEAD(&sdev->priv_tx);
++ INIT_LIST_HEAD(&sdev->priv_free);
++ sdev->priv_lock = SPIN_LOCK_UNLOCKED;
++
++ 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);
++
++ VHCI_DEBUG("register new interface\n");
++ return sdev;
++}
++
++static int stub_device_free(struct stub_device *sdev)
++{
++ if( !sdev ) return -EINVAL;
++
++ kfree(sdev);
++ VHCI_DEBUG("kfree udev ok\n");
++
++ return 0;
++}
++
++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;
++
++ VHCI_DEBUG("Enter\n");
++
++ /* We do not claim HUB device */
++ if(udev->descriptor.bDeviceClass == USB_CLASS_HUB) {
++ VHCI_DEBUG("HUB device, we do no claim\n");
++ return -ENOMEM;
++ }
++
++#include <linux/string.h>
++ if(strcmp(udev->bus->bus_name, "VHCI") == 0) {
++ VHCI_DEBUG("dev's bus is VHCI, so do not go anymore!\n");
++ return -ENOMEM;
++ }
++
++
++ if((sdev = stub_device_alloc(interface)) != NULL) {
++ struct usb_device *udev = interface_to_usbdev(interface);
++
++ VHCI_INFO("USB/IP Stub: new inteface register, bus %u dev %u ifn %u\n",
++ udev->bus->busnum, udev->devnum, interface->cur_altsetting->desc.bInterfaceNumber);
++ } else {
++ VHCI_ERROR("error \n"); return -ENOMEM;
++ }
++
++
++ /* init MUTEX LOCKED here? */
++
++
++ {
++ int i;
++ for(i=0; i< interface->num_altsetting; i++) {
++ VHCI_INFO("alt %u ", interface->altsetting[i].desc.bAlternateSetting);
++ printk("NrEp %u ", interface->altsetting[i].desc.bNumEndpoints);
++ printk("Cls %x ", interface->altsetting[i].desc.bInterfaceClass);
++ printk("SCls %x ", interface->altsetting[i].desc.bInterfaceSubClass);
++ printk("Pro %x ", interface->altsetting[i].desc.bInterfaceProtocol);
++ printk("\n");
++ }
++ }
++
++
++#if 0
++ /* set dummy configuration value for being called stub_disconnect */
++ /* Most devices have just one configration. */
++ if(usb_set_configuration (udev, 0) < 0) {
++ VHCI_ERROR("set_configuration failed\n");
++ return -ENODEV;
++ }
++#endif
++
++ /* set private data to usb_interface */
++ usb_set_intfdata(interface, sdev);
++
++
++ stub_add_files(&interface->dev);
++
++ 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);
++ //struct usb_device *udev = interface_to_usbdev(interface);
++
++ VHCI_DEBUG("Enter\n");
++
++ /* get stub_device */
++ if(!sdev) BUG();
++
++ usb_set_intfdata(interface, NULL);
++
++
++ /*
++ * NOTE:
++ * In future, rx/tx threads are invoked for each usb_device.
++ * And, the Stub driver probes each usb_interface.
++ *
++ * But, a usb device driver is responsible for *a* usb_interace.
++ * It's not a good solution.
++ */
++ 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);
++
++
++ VHCI_DEBUG("bye\n");
++}
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/stub_main.c
+@@ -0,0 +1,319 @@
++/*
++ * $Id: stub_main.c 265 2005-09-01 09:24:10Z taka-hir $
++ *
++ * Copyright (C) 2003-2005 Takahiro Hirofuchi <taka-hir@is.naist.jp>
++ *
++ *
++ * 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 "usbip_common.h"
++#include "stub.h"
++
++/* Version Information */
++#define DRIVER_VERSION "$Id: stub_main.c 265 2005-09-01 09:24:10Z taka-hir $"
++#define DRIVER_AUTHOR "Takahiro Hirofuchi <taka-hir@is.naist.jp>"
++#define DRIVER_DESC "Stub Driver for USB/IP"
++
++
++
++/* stub_priv is allocated from StubPrivCache */
++kmem_cache_t *StubPrivCache = NULL;
++
++
++static int __init usb_stub_init(void)
++{
++ int ret;
++
++ StubPrivCache = kmem_cache_create("stub_priv", sizeof(struct stub_priv),
++ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
++ if( !StubPrivCache ) {
++ VHCI_ERROR("create stub_priv_cache\n");
++ return -ENOMEM;
++ }
++
++ ret = usb_register(&stub_driver);
++ if(ret) {
++ VHCI_ERROR("usb_register failed %d\n", ret);
++ return ret;
++ }
++
++
++ info(DRIVER_DESC "" DRIVER_VERSION);
++ return ret;
++}
++
++
++#if 0
++static void free_priv_data(struct stub_priv *priv)
++{
++ int ret;
++ struct urb *urb = priv->urb;
++ VHCI_DEBUG("priv %p urb %p seq %lu\n", priv, urb, priv->seqnum);
++
++ /* A urb in HCD is unlinked asynchronously. */
++ if(atomic_read(&priv->in_submit)) {
++ /* this needs to be synchronous.
++ * because it may free urb and etc before stub_complete is called.
++ * stub_complete may touch a nulled urb.
++ */
++ ret = usb_unlink_urb(urb);
++ if(ret != -EINPROGRESS) {
++ uerr("usb_unlink_urb error, ret %d\n", ret);
++ }
++ }
++
++ /* free priv, buffers and the urb */
++ list_del(&priv->list);
++ kmem_cache_free(StubPrivCache, priv);
++ if(urb->transfer_buffer != NULL)
++ kfree(urb->transfer_buffer);
++ if(urb->setup_packet != NULL)
++ kfree(urb->setup_packet);
++ usb_free_urb(urb);
++}
++
++
++static void free_list_data(struct list_head *listhead)
++{
++ struct stub_priv *priv, *tmp;
++
++ list_for_each_entry_safe(priv, tmp, listhead, list) {
++ free_priv_data(priv);
++ }
++}
++
++static void free_list_data_by_seqnum(struct list_head *listhead, __u32 seqnum)
++{
++ struct stub_priv *priv, *tmp;
++
++ list_for_each_entry_safe(priv, tmp, listhead, list) {
++ if(priv->seqnum == seqnum)
++ free_priv_data(priv);
++ }
++}
++
++
++static int dump_priv_data(struct list_head *listhead, char *out)
++{
++ struct list_head *ptr;
++ struct stub_priv *priv;
++ char *s = out;
++
++
++ for(ptr = listhead->next; ptr != listhead; ptr = ptr->next) {
++ priv = list_entry(ptr, struct stub_priv, list);
++
++ out += sprintf(out, "Sub ");
++ out += sprintf(out, "%10lu ", priv->seqnum);
++
++ switch (usb_pipetype(priv->urb->pipe)) {
++ case PIPE_CONTROL:
++ out += sprintf(out, "%s ", "CTL");
++ break;
++ case PIPE_BULK:
++ out += sprintf(out, "%s ", "BLK");
++ break;
++ case PIPE_INTERRUPT:
++ out += sprintf(out, "%s ", "INT");
++ break;
++ case PIPE_ISOCHRONOUS:
++ out += sprintf(out, "%s ", "ISO");
++ break;
++ }
++
++ if( usb_pipein(priv->urb->pipe) ) {
++ out += sprintf(out, "%s ", "IN ");
++ } else {
++ out += sprintf(out, "%s ", "OUT");
++ }
++
++ out += sprintf(out, "\n");
++ }
++
++ return out - s;
++}
++#endif
++
++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(StubPrivCache, priv);
++ if(urb->transfer_buffer != NULL)
++ kfree(urb->transfer_buffer);
++ if(urb->setup_packet != NULL)
++ kfree(urb->setup_packet);
++ usb_free_urb(urb);
++
++ }
++}
++
++#if 0
++static void free_priv_data(struct stub_priv *priv)
++{
++ int ret;
++ struct urb *urb = priv->urb;
++ VHCI_DEBUG("priv %p urb %p seq %lu\n", priv, urb, priv->seqnum);
++
++ /* A urb in HCD is unlinked asynchronously. */
++ if(atomic_read(&priv->in_submit)) {
++ /* this needs to be synchronous.
++ * because it may free urb and etc before stub_complete is called.
++ * stub_complete may touch a nulled urb.
++ */
++ ret = usb_unlink_urb(urb);
++ if(ret != -EINPROGRESS) {
++ uerr("usb_unlink_urb error, ret %d\n", ret);
++ }
++ }
++
++ /* free priv, buffers and the urb */
++ list_del(&priv->list);
++ kmem_cache_free(StubPrivCache, priv);
++ if(urb->transfer_buffer != NULL)
++ kfree(urb->transfer_buffer);
++ if(urb->setup_packet != NULL)
++ kfree(urb->setup_packet);
++ usb_free_urb(urb);
++}
++
++int stub_priv_list_data(struct stub_device *sdev, enum stub_priv_list_operation operation, void *arg)
++{
++ unsigned long flags;
++ int ret = 0;
++ __u32 seqnum;
++ char *out, *s;
++
++ spin_lock_irqsave(&sdev->priv_lock, flags);
++
++ switch(operation) {
++ case CLEAR_BY_SDEV:
++ free_list_data(&sdev->priv_init);
++ free_list_data(&sdev->priv_tx);
++ free_list_data(&sdev->priv_free);
++ break;
++
++ case CLEAR_BY_SEQNUM:
++ seqnum = *((__u32 *) arg);
++ free_list_data_by_seqnum(&sdev->priv_init, seqnum);
++ free_list_data_by_seqnum(&sdev->priv_tx, seqnum);
++ free_list_data_by_seqnum(&sdev->priv_free, seqnum);
++ break;
++
++ case DUMP_ALL:
++ out = (char *) arg;
++ s = out;
++ out += sprintf(out, "priv_init\n");
++ out += dump_priv_data(&sdev->priv_init, out);
++ out += sprintf(out+ret, "priv_tx\n");
++ out += dump_priv_data(&sdev->priv_init, out);
++ out += sprintf(out+ret, "priv_free\n");
++ out += dump_priv_data(&sdev->priv_init, out);
++ ret = out -s;
++ break;
++
++ default:
++ /* NOTREACHED */
++ VHCI_ERROR("BUG\n");
++ }
++
++ spin_unlock_irqrestore(&sdev->priv_lock, flags);
++
++ return ret;
++}
++#endif
++
++
++static void __exit usb_stub_exit(void)
++{
++ int ret;
++
++ VHCI_DEBUG("enter\n");
++
++
++ /* deregister() calls stub_disconnect() for all devices. Device
++ * specific data is cleared in stub_disconnect(). */
++ usb_deregister(&stub_driver);
++
++
++ ret = kmem_cache_destroy(StubPrivCache);
++ if (ret != 0) {
++ VHCI_ERROR("memory leak of stub_priv, %d\n", ret);
++ }
++
++
++ VHCI_DEBUG("bye\n");
++}
++
++
++
++
++module_init (usb_stub_init);
++module_exit (usb_stub_exit);
++
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/stub_rx.c
+@@ -0,0 +1,320 @@
++/*
++ * $Id: stub_rx.c 276 2005-11-22 08:06:10Z taka-hir $
++ *
++ * Copyright (C) 2003-2005 Takahiro Hirofuchi <taka-hir@is.naist.jp>
++ *
++ *
++ * 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 check_clear_halt(struct urb *urb)
++{
++ struct usb_ctrlrequest *req;
++
++ if (usb_pipetype(urb->pipe) != PIPE_CONTROL) {
++ dbg_stub_rx("not clear halt command\n");
++ return;
++ }
++
++ if (!urb->setup_packet) {
++ dbg_stub_rx("no need for check clear halt\n");
++ return;
++ }
++
++ req = (struct usb_ctrlrequest *)urb->setup_packet;
++
++ if (req->bRequest == USB_REQ_CLEAR_FEATURE &&
++ req->bRequestType == USB_RECIP_ENDPOINT &&
++ req->wValue == USB_ENDPOINT_HALT) {
++ /* CLEAR HALT command */
++ /* the next line is wrong.
++ * because we must clear halt of stalled endpoint. */
++ //int endp = usb_pipeendpoint(urb->pipe);
++
++ /* wIndex is 2bytes and it has target endpoint number. */
++ int endp = (req->wIndex & 0x000f );
++ int in = (req->wIndex & 0x0080 ); /* include USB_DIR_IN bit */
++ //int target_pipe = usb_rcvctrlpipe(urb->dev, endp);
++ int target_pipe ;
++ int ret;
++
++ if (in) {
++ dbg_stub_rx("in\n");
++ target_pipe = usb_rcvctrlpipe(urb->dev, endp);
++ } else {
++ dbg_stub_rx("out\n");
++ target_pipe = usb_sndctrlpipe(urb->dev, endp);
++ }
++
++ dbg_stub_rx("CLEAR HALT command, devnum %d endp %d\n", urb->dev->devnum, endp);
++ ret = usb_clear_halt(urb->dev, target_pipe);
++ if (ret == 0)
++ VHCI_INFO("clear halt ep %d ok\n",endp);
++ else
++ VHCI_INFO("clear halt ep %d failed, ret %d\n", endp, ret);
++ } else if (req->bRequest == USB_REQ_SET_INTERFACE &&
++ req->bRequestType == USB_RECIP_INTERFACE) {
++ /* SET INTERFACE command */
++ __u16 alternate = req->wValue;
++ __u16 interface = req->wIndex;
++
++ dbg_stub_rx("SET INTERFACE command, interface %u alternate %u\n", interface, alternate);
++
++ usb_set_interface(urb->dev, interface, alternate);
++ } else {
++ dbg_stub_rx("not a clear halt command\n");
++ }
++}
++
++static int stub_recv_unlink(struct stub_device *sdev, struct usbip_header *pdu)
++{
++ __u32 seqnum = pdu->u.unlink.seqnum;
++ struct list_head *listhead = &sdev->priv_init;
++ struct list_head *ptr;
++ struct stub_priv *priv;
++ struct urb *urb = NULL;
++ int ret;
++
++ uinfo("recv_unlink: %d\n", seqnum);
++
++ spin_lock(&sdev->priv_lock);
++
++ for(ptr = listhead->next; ptr != listhead; ptr = ptr->next) {
++ priv = list_entry(ptr, struct stub_priv, list);
++ if (priv->seqnum == seqnum) {
++ spin_unlock(&sdev->priv_lock);
++ urb = priv->urb;
++ break;
++ }
++ }
++
++ if (!urb){
++ uinfo("An unlinking urb is already completed.\n");
++ uinfo("Or, to begin with, stub did not recieve the urb\n");
++ spin_unlock(&sdev->priv_lock);
++ return 0;
++ }
++
++ ret = usb_unlink_urb(urb);
++ if (ret != -EINPROGRESS)
++ uerr("faild to unlink a urb %p, ret %d\n", urb, ret);
++
++ spin_unlock(&sdev->priv_lock);
++
++ return 0;
++}
++
++static int valid_request(struct stub_device *sdev, struct usbip_header *pdu)
++{
++ struct usbip_device *ud = &sdev->ud;
++
++ int bus = interface_to_busnum(sdev->interface);
++ int dev = interface_to_devnum(sdev->interface);
++
++ if (pdu->base.busnum == bus && pdu->base.devnum == dev) {
++ 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 void stub_recv_submit(struct stub_device *sdev, struct usbip_header *pdu)
++{
++ int ret;
++ struct stub_priv *priv = NULL;
++ struct usbip_device *ud = &sdev->ud;
++
++
++ /*
++ * After a stub_priv is linked to a list_head,
++ * the error handler can free allocated data.
++ */
++ {
++ unsigned long flag;
++
++ spin_lock_irqsave(&sdev->priv_lock, flag);
++
++ priv = kmem_cache_alloc(StubPrivCache, GFP_ATOMIC);
++ if (!priv) {
++ VHCI_ERROR("malloc stub_priv\n");
++ spin_unlock_irqrestore(&sdev->priv_lock, flag);
++ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
++ return;
++ }
++ memset(priv, 0, sizeof(struct stub_priv));
++
++ priv->seqnum = pdu->base.seqnum;
++ priv->sdev = sdev;
++
++
++ list_add_tail(&priv->list, &sdev->priv_init);
++ spin_unlock_irqrestore(&sdev->priv_lock, flag);
++ }
++
++ /*
++ * setup a urb
++ */
++ if (usb_pipeisoc(pdu->base.pipe))
++ priv->urb = usb_alloc_urb(pdu->u.submit.number_of_packets, GFP_KERNEL);
++ else
++ priv->urb = usb_alloc_urb(0, GFP_KERNEL);
++
++ if (!priv->urb) {
++ VHCI_ERROR("malloc urb\n");
++ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
++ return;
++ }
++
++ /* set priv->urb->transfer_buffer */
++ if (pdu->u.submit.transfer_buffer_length > 0) {
++ priv->urb->transfer_buffer = kmalloc(pdu->u.submit.transfer_buffer_length, GFP_KERNEL);
++ if (!priv->urb->transfer_buffer) {
++ VHCI_ERROR("malloc x_buff\n");
++ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
++ return;
++ }
++ memset(priv->urb->transfer_buffer, 0, pdu->u.submit.transfer_buffer_length);
++ }
++
++ /* set priv->urb->setup_packet */
++ {
++ priv->urb->setup_packet = kmalloc(8, GFP_KERNEL);
++ if (!priv->urb->setup_packet) {
++ VHCI_ERROR("allocate setup_packet\n");
++ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
++ return;
++ }
++ memset(priv->urb->setup_packet, 0, 8);
++ memcpy(priv->urb->setup_packet, &pdu->u.submit.setup, 8);
++ }
++
++ priv->urb->context = (void *) priv;
++ priv->urb->dev = interface_to_usbdev(sdev->interface);
++ priv->urb->pipe = pdu->base.pipe;
++ priv->urb->complete = stub_complete;
++
++ usbip_pack_pdu(pdu, priv->urb, VHC_C_SUBMIT, 0);
++
++
++ if (usbip_recv_xbuff(ud, priv->urb) < 0)
++ return;
++
++ if (usbip_recv_iso(ud, priv->urb) < 0)
++ return;
++
++ check_clear_halt(priv->urb);
++
++ /*
++ * stub_recv_unlink() unlinks the URB by a call to usb_unlink_urb().
++ * By unlinking the urb asynchronously, stub_rx can continuously
++ * process comming urbs. Even if the urb is unlinked, its completion
++ * handler will be called and stub_tx will send a return pdu.
++ */
++
++ atomic_set(&priv->in_submit, 1);
++
++ ret = usb_submit_urb(priv->urb, GFP_KERNEL);
++
++ if (ret == 0) {
++ dbg_stub_rx("submit urb ok, seqnum %u\n", pdu->base.seqnum);
++ } else {
++ VHCI_ERROR("submit_urb error, %d\n", ret);
++
++ /*
++ * Pessimistic.
++ * This connection will be discared.
++ */
++ 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);
++
++
++ dbg_stub_rx("Enter\n");
++
++ memset(&pdu, 0, sizeof(pdu));
++
++
++ /* 1. recieve a pdu header */
++ ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu),0);
++ if (ret != sizeof(pdu)) {
++ VHCI_ERROR("recv a header, %d\n", ret);
++ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
++ return;
++ }
++
++ if (dbg_flag_stub_rx)
++ usbip_dump_header(&pdu);
++
++ if (!valid_request(sdev, &pdu)) {
++ VHCI_ERROR("recv invalid request\n");
++ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
++ return;
++ }
++
++ switch (pdu.base.command) {
++ case VHC_C_UNLINK:
++ stub_recv_unlink(sdev, &pdu);
++ break;
++
++ case VHC_C_SUBMIT:
++ stub_recv_submit(sdev, &pdu);
++ break;
++
++ default:
++ /* NOTREACHED */
++ VHCI_ERROR("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 catched!\n");
++ break;
++ }
++
++ if (usbip_event_happend(ud))
++ break;
++
++ stub_rx_pdu(ud);
++ }
++}
++
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/stub_tx.c
+@@ -0,0 +1,205 @@
++/*
++ * $Id: stub_tx.c 265 2005-09-01 09:24:10Z taka-hir $
++ *
++ * Copyright (C) 2003-2005 Takahiro Hirofuchi <taka-hir@is.naist.jp>
++ *
++ *
++ * 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 DECLARE_WAIT_QUEUE_HEAD(waitq);
++
++/**
++ * 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 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 pt_regs *regs)
++{
++ struct stub_priv *priv = (struct stub_priv *) urb->context;
++ struct stub_device *sdev = priv->sdev;
++
++ dbg_stub_tx("complete! status %d\n", urb->status);
++
++
++ switch (urb->status) {
++ case 0:
++ /* OK */
++ break;
++ case -ENOENT:
++ uinfo("stopped by a call to usb_kill_urb()\n");
++ uinfo("because of cleaning up a virtual connection\n");
++ return;
++ case -ECONNRESET:
++ uinfo("unlinked by a call to usb_unlink_urb()\n");
++ break;
++ case -EPIPE:
++ uinfo("endpoint is stalled\n");
++ break;
++ default:
++ VHCI_ERROR("NOT YET: completion with non-zero status %d\n", urb->status);
++ }
++
++ /* link a urb to the queue of tx. */
++ {
++ unsigned long flags;
++
++ atomic_set(&priv->in_submit, 0);
++
++ spin_lock_irqsave(&sdev->priv_lock, flags);
++ list_move_tail(&priv->list, &sdev->priv_tx);
++ spin_unlock_irqrestore(&sdev->priv_lock, flags);
++ }
++
++ /* wake up tx_thread */
++ wake_up(&waitq);
++}
++
++static void setup_pdu(struct usbip_header *rpdu, struct urb *urb)
++{
++ struct stub_priv *priv = (struct stub_priv *) urb->context;
++
++ rpdu->base.command = VHC_C_RETURN;
++ rpdu->base.pipe = urb->pipe;
++ rpdu->base.seqnum = priv->seqnum;
++
++ usbip_pack_pdu(rpdu, urb, VHC_C_RETURN, 1);
++}
++
++#define MAX_SUBMIT_QUEUE_DEPTH 100
++static struct usbip_header ReturnPDU[MAX_SUBMIT_QUEUE_DEPTH];
++
++/* create msghdr to tx from the StubPrivListPendingTX queue */
++static int stub_send_txdata(struct stub_device *sdev)
++{
++ unsigned long flags;
++ struct stub_priv *priv, *tmp;
++ size_t txsize = 0;
++ int count = 0;
++
++ struct msghdr msg;
++ struct iovec iov[MAX_SUBMIT_QUEUE_DEPTH];
++
++ memset(iov, 0, sizeof(iov));
++ memset(&msg, 0, sizeof(msg));
++ msg.msg_iov = iov;
++ msg.msg_iovlen = 0;
++
++ memset(&ReturnPDU, 0, sizeof(struct usbip_header) * MAX_SUBMIT_QUEUE_DEPTH);
++
++ spin_lock_irqsave(&sdev->priv_lock, flags);
++
++ list_for_each_entry_safe(priv, tmp, &sdev->priv_tx, list) {
++ struct urb *urb = priv->urb;
++
++ dbg_stub_tx("setup txdata for urb %p\n", urb);
++
++ /* 1. setup usbip_header */
++ setup_pdu(&ReturnPDU[count], urb);
++
++ iov[msg.msg_iovlen].iov_base = (void *) &ReturnPDU[count];
++ iov[msg.msg_iovlen].iov_len = sizeof(struct usbip_header);
++ msg.msg_iovlen++;
++ txsize += sizeof(struct usbip_header);
++
++ /* 2. setup transfer buffer */
++ if (usb_pipein(urb->pipe) && urb->transfer_buffer != NULL && urb->actual_length > 0) {
++ iov[msg.msg_iovlen].iov_base = urb->transfer_buffer;
++ iov[msg.msg_iovlen].iov_len = urb->actual_length;
++ msg.msg_iovlen++;
++ txsize += urb->actual_length;
++ }
++
++ /* 3. setup iso_packet_descriptor */
++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++ iov[msg.msg_iovlen].iov_base = &urb->iso_frame_desc[0];
++ iov[msg.msg_iovlen].iov_len = urb->number_of_packets * sizeof(struct usb_iso_packet_descriptor);
++ msg.msg_iovlen++;
++ txsize += urb->number_of_packets * sizeof(struct usb_iso_packet_descriptor);
++ }
++
++ list_move_tail(&priv->list, &sdev->priv_free);
++
++
++ count++;
++ if (count == MAX_SUBMIT_QUEUE_DEPTH) {
++ uinfo("max urbs are processed, %d\n", MAX_SUBMIT_QUEUE_DEPTH);
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&sdev->priv_lock, flags);
++
++ if (txsize > 0) {
++ int ret;
++ ret = usbip_sendmsg(sdev->ud.tcp_socket, &msg, txsize);
++ if (ret != txsize) {
++ VHCI_ERROR("vhci_sendmsg failed!, retval %d for %d\n", ret, txsize);
++ usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
++ return -1;
++ }
++
++ dbg_stub_tx("send txdata \n");
++ }
++
++
++ spin_lock_irqsave(&sdev->priv_lock, flags);
++
++ list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) {
++ struct urb *urb = priv->urb;
++
++ dbg_stub_tx("setup txdata for urb %p\n", urb);
++
++ kfree(urb->transfer_buffer);
++ list_del(&priv->list);
++ kmem_cache_free(StubPrivCache, priv);
++
++ usb_free_urb(urb);
++ }
++
++ spin_unlock_irqrestore(&sdev->priv_lock, flags);
++
++ return txsize;
++}
++
++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;
++
++ if (stub_send_txdata(sdev) < 0)
++ break;
++
++ wait_event_interruptible(waitq, !list_empty(&sdev->priv_tx));
++ }
++}
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/usbip_common.c
+@@ -0,0 +1,860 @@
++/*
++ * $Id: usbip_common.c 265 2005-09-01 09:24:10Z taka-hir $
++ *
++ * Copyright (C) 2003-2005 Takahiro Hirofuchi <taka-hir@is.naist.jp>
++ *
++ *
++ * 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/file.h>
++#include <linux/tcp.h>
++#include "usbip_common.h"
++
++static void usbip_dump_buffer(char *, int size);
++
++/*
++ * Send or receive packet.
++ * I refer drivers/block/nbd.c
++ */
++int usbip_xmit(int send, struct socket *sock, char *buf, int size, int msg_flags)
++{
++ int result;
++ struct msghdr msg;
++ struct kvec iov;
++ int total = 0;
++
++ /* for blocks of if (dbg_flag_xmit) */
++ char *bp = buf;
++ int osize= size;
++
++ dbg_xmit("enter\n");
++
++ if (!sock || !buf || !size) {
++ VHCI_ERROR("usbip_xmit: invalid arg, sock %p buff %p size %d\n",
++ sock, buf, size);
++ return -EINVAL;
++ }
++
++
++ if (dbg_flag_xmit) {
++ if (send) {
++ if (!in_interrupt())
++ printk(KERN_DEBUG "%-10s:", current->comm);
++ else
++ printk(KERN_DEBUG "interupt :");
++
++ printk("usbip_xmit: sending... , sock %p, buf %p, size %d, msg_flags %d\n",
++ sock, buf, size, msg_flags);
++ usbip_dump_buffer(buf, size);
++ }
++ }
++
++
++ do {
++ sock->sk->sk_allocation = GFP_NOIO;
++ iov.iov_base = buf;
++ iov.iov_len = size;
++ msg.msg_name = NULL;
++ msg.msg_namelen = 0;
++ msg.msg_control = NULL;
++ msg.msg_controllen = 0;
++ msg.msg_namelen = 0;
++ msg.msg_flags = msg_flags | MSG_NOSIGNAL;
++
++ if (send)
++ result = kernel_sendmsg(sock, &msg, &iov, 1, size);
++ else
++ result = kernel_recvmsg(sock, &msg, &iov, 1, size, MSG_WAITALL);
++
++ if (result <= 0) {
++ VHCI_DEBUG("usbip_xmit: %s sock %p buf %p size %u ret %d total %d\n",
++ send ? "send" : "receive", sock, buf, size, result, total);
++ goto err;
++ }
++
++ size -= result;
++ buf += result;
++ total += result;
++
++ } while (size > 0);
++
++
++
++ if (dbg_flag_xmit) {
++ if (!send) {
++ if (!in_interrupt())
++ printk(KERN_DEBUG "%-10s:", current->comm);
++ else
++ printk(KERN_DEBUG "interupt :");
++
++ printk("usbip_xmit: receiving....\n");
++ usbip_dump_buffer(bp, osize);
++ printk("usbip_xmit: received, osize %d ret %d size %d total %d\n",
++ osize, result, size, total);
++ }
++
++ if (send) {
++ printk("usbip_xmit: send, total %d\n", total);
++ }
++ }
++
++ return total;
++
++err:
++
++ return result;
++}
++
++int usbip_sendmsg(struct socket *socket, struct msghdr *msg, int len)
++{
++ int rc = 0;
++ mm_segment_t oldfs;
++
++ dbg_xmit("enter\n");
++
++ if (dbg_flag_xmit) {
++ int i;
++ for(i = 0; i < msg->msg_iovlen; i++) {
++ usbip_dump_buffer(msg->msg_iov[i].iov_base,
++ msg->msg_iov[i].iov_len);
++ }
++ }
++
++ if (socket) {
++ oldfs = get_fs();
++ set_fs(get_ds());
++
++ /* Try to avoid resource acquisition deadlocks by using GFP_ATOMIC. */
++ socket->sk->sk_allocation = GFP_ATOMIC;
++ //socket->sk->sk_allocation = GFP_NOIO;
++
++ /* FIXME: ought to loop handling short writes, unless a signal occurs */
++ rc = sock_sendmsg(socket, msg, len);
++
++ set_fs(oldfs);
++ }
++
++ return rc;
++}
++
++
++#if 0
++static int usbip_recvmsg( struct socket *socket, struct msghdr *msg, int len )
++{
++ int rc = 0;
++ mm_segment_t oldfs;
++
++ VHCI_DEBUG("Enter\n");
++
++ if (socket) {
++ oldfs = get_fs();
++ set_fs( get_ds() );
++
++ /* Try to avoid resource acquisition deadlocks by using GFP_ATOMIC. */
++ socket->sk->allocation = GFP_ATOMIC;
++
++ /* FIXME: ought to loop handling short writes, unless a signal occurs */
++ rc = sock_recvmsg(socket, msg, len);
++
++ set_fs( oldfs );
++ }
++
++#ifdef CONFIG_USB_DEBUG
++ {
++ int i;
++ for(i = 0; i < msg->msg_iovlen; i++) {
++ usbip_dump_buffer(msg->msg_iov[i].iov_base,
++ msg->msg_iov[i].iov_len);
++ }
++ }
++#endif
++
++ return rc;
++}
++#endif
++
++
++static void usbip_dump_buffer(char *buff, int bufflen)
++{
++ int i;
++
++ if (bufflen > 128) {
++ for(i = 0; i< 128; i++) {
++ if (i%24 == 0)
++ printk(" ");
++ printk("%02x ", (unsigned char ) buff[i]);
++ if (i%4 == 3) printk("| ");
++ if (i%24 == 23) printk("\n");
++ }
++ printk("... (%d byte)\n", bufflen);
++ return;
++ }
++
++ for(i = 0; i< bufflen; i++) {
++ if (i%24 == 0)
++ printk(" ");
++ printk("%02x ", (unsigned char ) buff[i]);
++ if (i%4 == 3)
++ printk("| ");
++ if (i%24 == 23)
++ printk("\n");
++ }
++ printk("\n");
++
++}
++
++
++static void usbip_dump_pipe(unsigned int p)
++{
++ unsigned char type = usb_pipetype(p);
++ unsigned char ep = usb_pipeendpoint(p);
++ unsigned char dev = usb_pipedevice(p);
++ unsigned char dir = usb_pipein(p);
++
++ printk("dev(%d) ", dev);
++ printk("ep(%d) ", ep);
++ printk("%s ", dir ? "IN" : "OUT");
++/*
++ printk("DT%d ", data ? 1 : 0);
++ printk("%s ", speed ? "LOW" : "FULL");
++*/
++ switch(type) {
++ case PIPE_ISOCHRONOUS :
++ printk("%s ", "ISO");
++ break;
++ case PIPE_INTERRUPT :
++ printk("%s ", "INT");
++ break;
++ case PIPE_CONTROL :
++ printk("%s ", "CTL");
++ break;
++ case PIPE_BULK :
++ printk("%s ", "BLK");
++ break;
++ default :
++ printk("ERR");
++ }
++
++ printk("\n");
++
++}
++
++
++static void usbip_dump_usb_device(struct usb_device *dev)
++{
++ if (dev == NULL) {
++ printk(" dump usb dev: null pointer!!\n");
++ return;
++ }
++
++ printk(" devnum(%d) devpath(%s)", dev->devnum, dev->devpath);
++
++ switch(dev->speed) {
++ case USB_SPEED_HIGH :
++ printk(" SPD_HIGH");
++ break;
++ case USB_SPEED_FULL :
++ printk(" SPD_FULL");
++ break;
++ case USB_SPEED_LOW :
++ printk(" SPD_LOW");
++ break;
++ case USB_SPEED_UNKNOWN :
++ printk(" SPD_UNKNOWN");
++ break;
++ default :
++ printk(" SPD_ERROR");
++ }
++
++ printk(" tt %p, ttport %d", dev->tt, dev->ttport);
++ //printk(" refcnt %d", dev->refcnt.counter);
++ printk("\n");
++
++ printk(" ");
++ {
++ int i;
++ for(i = 0; i < 16; i++) {
++ printk(" %2u", i);
++ }
++ }
++ printk("\n");
++
++ printk(" toggle0(IN) :");
++ {
++ int i;
++ for(i = 0; i< 16; i++){
++ printk(" %2u", ( dev->toggle[0] & (1 << i) ) ? 1 : 0);
++ }
++ }
++ printk("\n");
++
++ printk(" toggle1(OUT):");
++ {
++ int i;
++ for(i = 0; i< 16; i++){
++ printk(" %2u", ( dev->toggle[1] & (1 << i) ) ? 1 : 0);
++ }
++ }
++ printk("\n");
++
++
++ {
++ int i;
++ printk(" epmaxp_in :");
++ for(i = 0; i < 16; i++) {
++ printk(" %2u", dev->ep_in[i]->desc.wMaxPacketSize);
++ }
++ printk("\n");
++
++ printk(" epmaxp_out :");
++ for(i = 0; i < 16; i++) {
++ printk(" %2u", dev->ep_out[i]->desc.wMaxPacketSize);
++ }
++ }
++
++ printk("\n ");
++
++ printk("parent %p, bus %p", dev->parent, dev->bus);
++ printk("\n ");
++
++ printk("descriptor %p, config %p, actconfig %p, rawdescriptors %p",
++ &dev->descriptor, dev->config, dev->actconfig, dev->rawdescriptors);
++ printk("\n ");
++
++ printk("have_langid %d, string_langid %d", dev->have_langid, dev->string_langid);
++ printk("\n ");
++
++ printk("maxchild %d, children %p", dev->maxchild, dev->children);
++
++ printk("\n");
++}
++
++static void usbip_dump_request_type(__u8 rt)
++{
++ switch(rt & USB_RECIP_MASK) {
++ case USB_RECIP_DEVICE:
++ printk("DEVICE");
++ break;
++ case USB_RECIP_INTERFACE:
++ printk("INTERF");
++ break;
++ case USB_RECIP_ENDPOINT:
++ printk("ENDPOI");
++ break;
++ case USB_RECIP_OTHER:
++ printk("OTHER ");
++ break;
++ default:
++ printk("------");
++ }
++}
++
++static void usbip_dump_usb_ctrlrequest(struct usb_ctrlrequest *cmd)
++{
++ if (cmd == NULL) {
++ printk(" %s : null pointer\n", __FUNCTION__);
++ return;
++ }
++
++ printk(" ");
++ printk("bRequestType(%02X) ", cmd->bRequestType);
++ printk("bRequest(%02X) " , cmd->bRequest);
++ printk("wValue(%04X) ", cmd->wValue);
++ printk("wIndex(%04X) ", cmd->wIndex);
++ printk("wLength(%04X) ", cmd->wLength);
++
++ printk("\n ");
++
++ if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
++ printk("STANDARD ");
++ switch(cmd->bRequest){
++ case USB_REQ_GET_STATUS:
++ printk("GET_STATUS");
++ break;
++ case USB_REQ_CLEAR_FEATURE:
++ printk("CLEAR_FEAT");
++ break;
++ case USB_REQ_SET_FEATURE:
++ printk("SET_FEAT ");
++ break;
++ case USB_REQ_SET_ADDRESS:
++ printk("SET_ADDRRS");
++ break;
++ case USB_REQ_GET_DESCRIPTOR:
++ printk("GET_DESCRI");
++ break;
++ case USB_REQ_SET_DESCRIPTOR:
++ printk("SET_DESCRI");
++ break;
++ case USB_REQ_GET_CONFIGURATION:
++ printk("GET_CONFIG");
++ break;
++ case USB_REQ_SET_CONFIGURATION:
++ printk("SET_CONFIG");
++ break;
++ case USB_REQ_GET_INTERFACE:
++ printk("GET_INTERF");
++ break;
++ case USB_REQ_SET_INTERFACE:
++ printk("SET_INTERF");
++ break;
++ case USB_REQ_SYNCH_FRAME:
++ printk("SYNC_FRAME");
++ break;
++ default:
++ printk("REQ(%02X) ", cmd->bRequest);
++ }
++
++ printk(" ");
++ usbip_dump_request_type(cmd->bRequestType);
++
++ }
++ else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) {
++ printk("CLASS ");
++ }
++ else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) {
++ printk("VENDOR ");
++ }
++ else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_RESERVED) {
++ printk("RESERVED");
++ }
++
++ printk("\n");
++}
++
++static void usbip_dump_urb (struct urb *purb)
++{
++ if (!purb) {
++ printk(" dump urb: null pointer!!\n");
++ return;
++ }
++
++ printk(" urb :%p\n", purb);
++ //printk(" next :%p\n", purb->next);
++ printk(" dev :%p\n", purb->dev);
++ usbip_dump_usb_device(purb->dev);
++ printk(" pipe :%08x ", purb->pipe);
++ usbip_dump_pipe(purb->pipe);
++ printk(" status :%d\n", purb->status);
++ printk(" transfer_flags :%08X\n", purb->transfer_flags);
++ printk(" transfer_buffer :%p\n", purb->transfer_buffer);
++ printk(" transfer_buffer_length:%d\n", purb->transfer_buffer_length);
++ printk(" actual_length :%d\n", purb->actual_length);
++ printk(" bandwidth :%d\n", purb->actual_length);
++ printk(" setup_packet :%p\n", purb->setup_packet);
++ if (purb->setup_packet != NULL && usb_pipetype(purb->pipe) == PIPE_CONTROL)
++ usbip_dump_usb_ctrlrequest((struct usb_ctrlrequest *) purb->setup_packet);
++ printk(" start_frame :%d\n", purb->start_frame);
++ printk(" number_of_packets :%d\n", purb->number_of_packets);
++ printk(" interval :%d\n", purb->interval);
++ printk(" error_count :%d\n", purb->error_count);
++ printk(" context :%p\n", purb->context);
++ printk(" complete :%p\n", purb->complete);
++}
++
++
++void setquickack(struct socket *socket)
++{
++ mm_segment_t oldfs;
++ int ret = 1;
++
++ oldfs = get_fs();
++ set_fs(get_ds());
++ ret = socket->ops->setsockopt(socket, SOL_TCP, TCP_QUICKACK, (char *) &ret, sizeof(ret));
++ set_fs(oldfs);
++}
++
++void setnodelay(struct socket *socket)
++{
++ mm_segment_t oldfs;
++ int ret = 1;
++
++ oldfs = get_fs();
++ set_fs(get_ds());
++ ret = socket->ops->setsockopt(socket, SOL_TCP, TCP_NODELAY, (char *) &ret, sizeof(ret));
++ set_fs(oldfs);
++}
++
++void setkeepalive(struct socket *socket)
++{
++ mm_segment_t oldfs;
++ int ret = 1;
++
++ oldfs = get_fs();
++ set_fs(get_ds());
++ ret = socket->ops->setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &ret, sizeof(ret));
++ set_fs(oldfs);
++}
++
++void setreuse(struct socket *socket)
++{
++ socket->sk->sk_reuse = 1;
++}
++
++struct socket *sockfd_to_socket(unsigned int sockfd)
++{
++ struct socket *socket;
++ struct file *file;
++ struct inode *inode;
++
++ file = fget(sockfd);
++ if (!file) {
++ VHCI_ERROR("invalid sockfd\n");
++ return NULL;
++ }
++
++ inode = file->f_dentry->d_inode;
++
++ if (!inode || !S_ISSOCK(inode->i_mode))
++ return NULL;
++
++ socket = SOCKET_I(inode);
++
++ return socket;
++}
++
++int set_sockaddr(struct socket *socket, struct sockaddr_storage *ss)
++{
++ int addrlen;
++ int ret;
++
++ ret = socket->ops->getname(socket, (struct sockaddr *) ss, &addrlen, 1);
++ if (ret) {
++ VHCI_ERROR("getname failed, socket %p\n", socket);
++ return ret;
++ }
++ return ret;
++}
++
++#if 0
++int sprintf_sockaddr(char *buf, struct sockaddr_storage *ss)
++{
++ int ret;
++
++ if (ss->ss_family == AF_INET) {
++ struct sockaddr_in *v4addr = (struct sockaddr_in *) ss;
++ ret = sprintf(buf, "%u.%u.%u.%u(%u)", NIPQUAD(v4addr->sin_addr),
++ v4addr->sin_port);
++
++ } else if (ss->ss_family == AF_INET6) {
++ struct sockaddr_in6 *v6addr = (struct sockaddr_in6 *) ss;
++ ret = sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x(%d)",
++ NIP6(v6addr->sin6_addr), v6addr->sin6_port);
++
++ } else {
++ VHCI_ERROR("unknown sa_family %d", ss->ss_family);
++ ret = -1;
++ }
++
++ return ret;
++}
++#endif
++
++ssize_t socket_to_addrstr(struct socket *socket, char *buf)
++{
++ struct sockaddr uaddr;
++ int uaddrlen;
++ int ret;
++
++ ret = socket->ops->getname(socket, &uaddr, &uaddrlen, 1);
++ if (ret) {
++ VHCI_ERROR("getname failed, socket %p\n", socket);
++ return ret;
++ }
++
++ if (uaddr.sa_family == AF_INET) {
++ struct sockaddr_in *v4addr = (struct sockaddr_in *) &uaddr;
++ ret = sprintf(buf, "%u.%u.%u.%u", NIPQUAD(v4addr->sin_addr.s_addr));
++ } else if (uaddr.sa_family == AF_INET6) {
++ struct sockaddr_in6 *v6addr = (struct sockaddr_in6 *) &uaddr;
++ ret = sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
++ NIP6(v6addr->sin6_addr));
++ } else {
++ VHCI_ERROR("unknown sa_family %d\n", uaddr.sa_family);
++ ret = -1;
++ }
++
++ return ret;
++}
++
++void usbip_dump_header(struct usbip_header *pdu)
++{
++ VHCI_DEBUG("BASE: cmd %u bus %u dev %u seq %u pipe %04x\n",
++ pdu->base.command,
++ pdu->base.busnum,
++ pdu->base.devnum,
++ pdu->base.seqnum,
++ pdu->base.pipe);
++
++#ifdef CONFIG_USB_DEBUG
++ usbip_dump_pipe(pdu->base.pipe);
++#endif
++
++ switch(pdu->base.command) {
++ case VHC_C_SUBMIT:
++ VHCI_DEBUG("SUBMIT: x_flags %u x_len %u bw %u sf %u #p %u iv %u\n",
++ pdu->u.submit.transfer_flags,
++ pdu->u.submit.transfer_buffer_length,
++ pdu->u.submit.bandwidth,
++ pdu->u.submit.start_frame,
++ pdu->u.submit.number_of_packets,
++ pdu->u.submit.interval);
++ break;
++ case VHC_C_UNLINK:
++ VHCI_DEBUG("UNLINK: seq %u\n", pdu->u.unlink.seqnum);
++ break;
++ case VHC_C_RETURN:
++ VHCI_DEBUG("RETURN: st %d x_flags %u al %u bw %u sf %d ec %d\n",
++ pdu->u.ret.status,
++ pdu->u.ret.transfer_flags,
++ pdu->u.ret.actual_length,
++ pdu->u.ret.bandwidth,
++ pdu->u.ret.start_frame,
++ pdu->u.ret.error_count);
++ break;
++ default:
++ /* NOT REACHED */
++ VHCI_DEBUG("UNKNOWN\n");
++ }
++}
++
++int usbip_thread(void *param)
++{
++ struct usbip_task *ut = (struct usbip_task *) param;
++
++ VHCI_DEBUG("Enter\n");
++
++ if (!ut)
++ return -EINVAL;
++
++ lock_kernel();
++ daemonize(ut->name);
++ allow_signal(SIGKILL);
++ ut->thread = current;
++ unlock_kernel();
++
++ /* srv.rb must wait for rx_thread starting */
++ complete(&ut->thread_done);
++
++ /* start of while loop */
++ ut->loop_ops(ut);
++
++
++ /* end of loop */
++ ut->thread = NULL;
++
++ VHCI_DEBUG("bye\n");
++
++ complete_and_exit(&ut->thread_done, 0);
++}
++
++void usbip_start_threads(struct usbip_device *ud)
++{
++ /*
++ * threads are invoked per one device (per one connection).
++ */
++ kernel_thread((int(*)(void *))usbip_thread, (void *)&ud->tcp_rx, 0);
++ kernel_thread((int(*)(void *))usbip_thread, (void *)&ud->tcp_tx, 0);
++
++ /* confirm threads are starting */
++ wait_for_completion(&ud->tcp_rx.thread_done);
++ wait_for_completion(&ud->tcp_tx.thread_done);
++}
++
++void usbip_stop_threads(struct usbip_device *ud)
++{
++ /* kill threads related to this sdev, if v.c. exists */
++ if (ud->tcp_rx.thread != NULL) {
++ send_sig(SIGKILL, ud->tcp_rx.thread, 1);
++ wait_for_completion(&ud->tcp_rx.thread_done);
++ VHCI_DEBUG("rx_thread for ud %p has finished\n", ud);
++ }
++ if (ud->tcp_tx.thread != NULL) {
++ send_sig(SIGKILL, ud->tcp_tx.thread, 1);
++ wait_for_completion(&ud->tcp_tx.thread_done);
++ VHCI_DEBUG("tx_thread for ud %p has finished\n", ud);
++ }
++}
++
++void usbip_task_init(struct usbip_task *ut, char *name, void (*loop_ops)(struct usbip_task *))
++{
++ ut->thread = NULL;
++ init_completion(&ut->thread_done);
++ ut->name = name;
++ ut->loop_ops = loop_ops;
++}
++
++static void usbip_pack_submit_pdu(struct usbip_header *pdu, struct urb *urb, int pack)
++{
++ if (pack) {
++ /* vhci_tx.c */
++ pdu->u.submit.transfer_flags = urb->transfer_flags & ~URB_NO_TRANSFER_DMA_MAP & ~URB_NO_SETUP_DMA_MAP;
++ pdu->u.submit.transfer_buffer_length = urb->transfer_buffer_length;
++ pdu->u.submit.bandwidth = urb->bandwidth;
++ pdu->u.submit.start_frame = urb->start_frame;
++ pdu->u.submit.number_of_packets = urb->number_of_packets;
++ pdu->u.submit.interval = urb->interval;
++ } else {
++ /* stub_rx.c */
++ urb->transfer_flags = pdu->u.submit.transfer_flags;
++ urb->transfer_buffer_length = pdu->u.submit.transfer_buffer_length;
++ urb->bandwidth = pdu->u.submit.bandwidth;
++ urb->start_frame = pdu->u.submit.start_frame;
++ urb->number_of_packets = pdu->u.submit.number_of_packets;
++ urb->interval = pdu->u.submit.interval;
++ }
++}
++
++static void usbip_pack_return_pdu(struct usbip_header *pdu, struct urb *urb, int pack)
++{
++ if (pack) {
++ /* stub_tx.c */
++ pdu->u.ret.transfer_flags = urb->transfer_flags;
++ pdu->u.ret.status = urb->status;
++ pdu->u.ret.actual_length = urb->actual_length;
++ pdu->u.ret.bandwidth = urb->bandwidth;
++ pdu->u.ret.start_frame = urb->start_frame;
++
++ pdu->u.ret.number_of_packets = urb->number_of_packets;
++ } else {
++ /* vhci_rx.c */
++ urb->transfer_flags = pdu->u.ret.transfer_flags;
++ urb->status = pdu->u.ret.status;
++ urb->actual_length = pdu->u.ret.actual_length;
++ urb->bandwidth = pdu->u.ret.bandwidth;
++ urb->start_frame = pdu->u.ret.start_frame;
++
++ urb->error_count = pdu->u.ret.error_count;
++ }
++}
++
++void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd, int pack)
++{
++ switch(cmd) {
++ case VHC_C_SUBMIT:
++ usbip_pack_submit_pdu(pdu, urb, pack);
++ break;
++ case VHC_C_RETURN:
++ usbip_pack_return_pdu(pdu, urb, pack);
++ break;
++ default:
++ /* NOTREACHED */
++ BUG();
++ }
++}
++
++/* some members of urb must be substituted before. */
++int usbip_recv_iso(struct usbip_device *ud, struct urb *urb)
++{
++ int ret;
++ char *iso_frame_desc = (char *) &urb->iso_frame_desc[0];
++ int np = urb->number_of_packets;
++ int size = np * sizeof(struct usb_iso_packet_descriptor);
++
++ if (!usb_pipeisoc(urb->pipe))
++ return 0;
++
++ ret = usbip_xmit(0, ud->tcp_socket, iso_frame_desc, size, 0);
++ if (ret != size ) {
++ VHCI_ERROR("recv iso_frame_descriptor, %d\n", ret);
++ if (ud->side == USBIP_STUB) {
++ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
++ } else {
++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
++ }
++ return -EPIPE;
++ }
++
++ return ret;
++}
++
++int usbip_event_happend(struct usbip_device *ud)
++{
++ int happend = 0;
++
++ spin_lock(&ud->lock);
++
++ if (ud->event != 0)
++ happend = 1;
++
++ spin_unlock(&ud->lock);
++
++ return happend;
++}
++
++/* some members of urb must be substituted before. */
++int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
++{
++ int ret;
++ int size;
++
++ if (ud->side == USBIP_STUB) {
++ /* stub_rx.c */
++ /* the direction of urb must be OUT. */
++ if (usb_pipein(urb->pipe))
++ return 0;
++
++ size = urb->transfer_buffer_length;
++ } else {
++ /* vhci_rx.c */
++ /* the direction of urb must be IN. */
++ if (usb_pipeout(urb->pipe))
++ return 0;
++
++ size = urb->actual_length;
++ }
++
++ /* no need to recv xbuff */
++ if (!(size > 0))
++ return 0;
++
++ ret = usbip_xmit(0, ud->tcp_socket, (char *) urb->transfer_buffer, size, 0);
++ if (ret != size) {
++ VHCI_ERROR("recv xbuf, %d\n", ret);
++ if (ud->side == USBIP_STUB) {
++ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
++ } else {
++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
++ return -EPIPE;
++ }
++ }
++
++ return ret;
++}
++
++#ifdef CONFIG_USB_DEBUG
++unsigned long usbip_debug_flag = 0xffff;
++#else
++unsigned long usbip_debug_flag = 0;
++#endif
++
++static ssize_t show_flag(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%lx\n", usbip_debug_flag);
++}
++
++static ssize_t store_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
++{
++ unsigned long flag;
++
++ sscanf(buf, "%lx", &flag);
++ usbip_debug_flag = flag;
++
++ return count;
++}
++DEVICE_ATTR(usbip_debug, (S_IRUGO | S_IWUSR), show_flag, store_flag);
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/usbip_common.h
+@@ -0,0 +1,392 @@
++/*
++ * $Id: usbip_common.h 265 2005-09-01 09:24:10Z taka-hir $
++ *
++ * Copyright (C) 2003-2005 Takahiro Hirofuchi <taka-hir@is.naist.jp>
++ *
++ *
++ * 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.
++ */
++
++#ifndef __VHCI_COMMON_H
++#define __VHCI_COMMON_H
++
++#if 0
++#include <linux/file.h>
++#include <linux/in.h>
++#include <linux/in6.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/smp_lock.h>
++#include <linux/socket.h>
++#include <linux/usb.h>
++#include <net/sock.h>
++#include <asm-i386/hardirq.h>
++#include <asm/byteorder.h>
++#include <asm/semaphore.h>
++#include <asm/uaccess.h>
++
++#endif
++
++#include <linux/usb.h>
++#include <net/sock.h>
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * define macros to print messages
++ */
++
++/**
++ * VHCI_DEBUG - print debug messages if CONFIG_USB_DEBUG is defined
++ * @fmt:
++ * @args:
++ */
++
++#ifdef CONFIG_USB_DEBUG
++
++#define udbg(fmt, args...) \
++ do{ \
++ printk(KERN_DEBUG "%-10s:(%s,%d) %s: " fmt, \
++ (in_interrupt() ? "interrupt" : (current)->comm),\
++ __FILE__, __LINE__, __FUNCTION__ , ##args); \
++ }while(0)
++
++#define VHCI_DEBUG(fmt, args...) udbg(fmt , ##args)
++
++#else /* CONFIG_USB_DEBUG */
++
++#define udbg(fmt, args...) do{ }while(0)
++#define VHCI_DEBUG(fmt, args...) do{ }while(0)
++
++#endif /* CONFIG_USB_DEBUG */
++
++
++enum {
++ usbip_debug_xmit = (1 << 0),
++ usbip_debug_sysfs = (1 << 1),
++ usbip_debug_urb = (1 << 2),
++ usbip_debug_eh = (1 << 3),
++
++ usbip_debug_stub_cmp = (1 << 8),
++ usbip_debug_stub_dev = (1 << 9),
++ usbip_debug_stub_rx = (1 << 10),
++ usbip_debug_stub_tx = (1 << 11),
++
++ usbip_debug_vhci_rh = (1 << 8),
++ usbip_debug_vhci_hc = (1 << 9),
++ usbip_debug_vhci_rx = (1 << 10),
++ usbip_debug_vhci_tx = (1 << 11),
++ usbip_debug_vhci_sysfs = (1 << 12)
++};
++
++#define dbg_flag_xmit (usbip_debug_flag & usbip_debug_xmit)
++#define dbg_flag_vhci_rh (usbip_debug_flag & usbip_debug_vhci_rh)
++#define dbg_flag_vhci_hc (usbip_debug_flag & usbip_debug_vhci_hc)
++#define dbg_flag_vhci_rx (usbip_debug_flag & usbip_debug_vhci_rx)
++#define dbg_flag_vhci_tx (usbip_debug_flag & usbip_debug_vhci_tx)
++#define dbg_flag_vhci_sysfs (usbip_debug_flag & usbip_debug_vhci_sysfs)
++#define dbg_flag_stub_rx (usbip_debug_flag & usbip_debug_stub_rx)
++#define dbg_flag_stub_tx (usbip_debug_flag & usbip_debug_stub_tx)
++
++extern unsigned long usbip_debug_flag;
++extern struct device_attribute dev_attr_usbip_debug;
++
++#define dbg_with_flag(flag, fmt, args...) \
++ do { \
++ if(flag & usbip_debug_flag) \
++ udbg(fmt , ##args); \
++ } while(0)
++
++#define dbg_sysfs(fmt, args...) dbg_with_flag(usbip_debug_sysfs, fmt , ##args)
++#define dbg_xmit(fmt, args...) dbg_with_flag(usbip_debug_xmit, fmt , ##args)
++#define dbg_urb(fmt, args...) dbg_with_flag(usbip_debug_urb, fmt , ##args)
++#define dbg_eh(fmt, args...) dbg_with_flag(usbip_debug_eh, fmt , ##args)
++
++#define dbg_vhci_rh(fmt, args...) dbg_with_flag(usbip_debug_vhci_rh, fmt , ##args)
++#define dbg_vhci_hc(fmt, args...) dbg_with_flag(usbip_debug_vhci_hc, fmt , ##args)
++#define dbg_vhci_rx(fmt, args...) dbg_with_flag(usbip_debug_vhci_rx, fmt , ##args)
++#define dbg_vhci_tx(fmt, args...) dbg_with_flag(usbip_debug_vhci_tx, fmt , ##args)
++#define dbg_vhci_sysfs(fmt, args...) dbg_with_flag(usbip_debug_vhci_sysfs, fmt , ##args)
++
++#define dbg_stub_cmp(fmt, args...) dbg_with_flag(usbip_debug_stub_cmp, fmt , ##args)
++#define dbg_stub_rx(fmt, args...) dbg_with_flag(usbip_debug_stub_rx, fmt , ##args)
++#define dbg_stub_tx(fmt, args...) dbg_with_flag(usbip_debug_stub_tx, fmt , ##args)
++
++
++/**
++ * VHCI_ERROR - print error messages
++ * @fmt:
++ * @args:
++ */
++#define uerr(fmt, args...) \
++ do { \
++ printk(KERN_ERR "%-10s: ***ERROR*** (%s,%d) %s: " fmt, \
++ (in_interrupt() ? "interrupt" : (current)->comm),\
++ __FILE__, __LINE__, __FUNCTION__ , ##args); \
++ } while(0)
++
++#define VHCI_ERROR(fmt, args...) uerr(fmt , ##args)
++
++#if 0
++#define VHCI_ERROR(fmt, args...) \
++ do{ \
++ if(!in_interrupt()) { \
++ printk(KERN_ERR "%-10s:", current->comm); \
++ } else { \
++ printk(KERN_ERR "interrupt :"); \
++ } \
++ printk("usbip: ***ERROR*** (%s, %d, %s)", __FILE__, __LINE__, __FUNCTION__); \
++ printk("usbip: " fmt , ## args); \
++ }while(0)
++#endif
++
++/**
++ * VHCI_INFO - print information messages
++ * @fmt:
++ * @args:
++ */
++
++#define uinfo(fmt, args...) \
++ do { \
++ printk(KERN_INFO "usbip: " fmt , ## args); \
++ } while(0)
++
++#define VHCI_INFO(fmt, args...) \
++ do { \
++ printk(KERN_INFO "usbip: " fmt , ## args); \
++ } while(0)
++
++
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * USB/IP packet headers.
++ * At now, we define 3 packet types:
++ *
++ * - SUBMIT transfers a USB request. This is corresponding to usb_submit_urb().
++ *
++ * - RETURN transfers a result of a USB request.
++ *
++ * - UNLINK transfers an unlink request of a pending USB request.
++ * This is corresponding to usb_unlink_urb() but not yet implemented.
++ *
++ * TODO:
++ *
++ * - big endian or little endian, aligenment.
++ * - inter-operability between other OSs
++ * - UNLINK and other operations
++ */
++
++/*
++ * A basic header followed by other additional headers.
++ */
++struct usbip_header_basic {
++#define VHC_C_SUBMIT 0x0001
++#define VHC_C_RETURN 0x0002
++#define VHC_C_UNLINK 0x0004
++ __u32 command;
++
++ __u32 busnum;
++ __u32 devnum;
++ __u32 seqnum; /* seaquencial number which identifies URBs */
++ __u32 pipe;
++};
++
++/*
++ * An additional header for a SUBMIT packet.
++ */
++struct usbip_header_submit {
++ __u32 transfer_flags;
++ __u32 transfer_buffer_length;
++ __u32 bandwidth;
++ __u32 start_frame;
++ __u32 number_of_packets;
++ __u32 interval;
++ unsigned char setup[8]; /* CTRL only */
++};
++
++/*
++ * An additional header for a RETURN packet.
++ */
++struct usbip_header_return {
++ __u32 status;
++ __u32 transfer_flags;
++ __u32 actual_length; /* returned data length */
++ __u32 bandwidth;
++ __u32 start_frame; /* ISO and INT */
++ __u32 number_of_packets; /* ISO only */
++ __u32 error_count; /* ISO only */
++};
++
++/*
++ * An additional header for a UNLINK packet.
++ */
++struct usbip_header_unlink {
++ __u32 seqnum; /* URB's seqnum which will be unlinked */
++};
++
++
++/*
++ * All usbip packets use a common header to keep code simple.
++ */
++struct usbip_header {
++ struct usbip_header_basic base;
++
++ union {
++ struct usbip_header_submit submit;
++ struct usbip_header_return ret;
++ struct usbip_header_unlink unlink;
++ } u;
++};
++
++
++
++
++/*-------------------------------------------------------------------------*/
++
++
++int usbip_xmit(int , struct socket *, char *, int , int );
++int usbip_sendmsg(struct socket *, struct msghdr *, int );
++
++
++static inline int interface_to_busnum(struct usb_interface *interface)
++{
++ struct usb_device *udev = interface_to_usbdev(interface);
++ return udev->bus->busnum;
++}
++
++static inline int interface_to_devnum(struct usb_interface *interface)
++{
++ struct usb_device *udev = interface_to_usbdev(interface);
++ return udev->devnum;
++}
++
++static inline int interface_to_infnum(struct usb_interface *interface)
++{
++ return interface->cur_altsetting->desc.bInterfaceNumber;
++}
++
++void setnodelay(struct socket *);
++void setquickack(struct socket *);
++void setkeepalive(struct socket *socket);
++void setreuse(struct socket *);
++struct socket *sockfd_to_socket(unsigned int);
++int set_sockaddr(struct socket *socket, struct sockaddr_storage *ss);
++#define ss_v6_addr(x) (((struct sockaddr_in6 *) &(x))->sin6_addr)
++#define ss_v6_port(x) (((struct sockaddr_in6 *) &(x))->sin6_port)
++#define ss_v4_addr(x) (((struct sockaddr_in *) &(x))->sin_addr)
++#define ss_v4_port(x) (((struct sockaddr_in *) &(x))->sin_port)
++//int sprintf_sockaddr(char *buf, struct sockaddr_storage *ss);
++
++void usbip_dump_header(struct usbip_header *pdu);
++
++
++struct usbip_device;
++
++struct usbip_task {
++ struct task_struct *thread;
++ struct completion thread_done;
++ char *name;
++ void (*loop_ops)(struct usbip_task *);
++};
++
++enum usbip_side {
++ USBIP_VHCI,
++ USBIP_STUB,
++};
++
++/* a common structure for stub_device and vhci_device */
++struct usbip_device{
++ enum usbip_side side;
++
++ enum {
++ /* sdev is available. */
++ SDEV_ST_AVAILABLE = 0x01,
++ /* sdev is now used. */
++ SDEV_ST_USED,
++ /* sdev is unusable because of a fatal error. */
++ SDEV_ST_ERROR,
++
++ /* vdev does not connect a remote device. */
++ VDEV_ST_NULL,
++ /* vdev is used, but the USB address is not assigned yet */
++ VDEV_ST_NOTASSIGNED,
++ VDEV_ST_USED,
++ VDEV_ST_ERROR
++ } status;
++
++ /* lock for status */
++ spinlock_t lock;
++
++ struct socket *tcp_socket;
++ struct sockaddr_storage tcp_ss;
++
++ struct usbip_task tcp_rx;
++ struct usbip_task tcp_tx;
++
++ /* event handler */
++#define USBIP_EH_SHUTDOWN (1 << 0)
++#define USBIP_EH_BYE (1 << 1)
++#define USBIP_EH_RESET (1 << 2)
++#define USBIP_EH_UNUSABLE (1 << 3)
++
++#define SDEV_EVENT_REMOVED ( USBIP_EH_SHUTDOWN | USBIP_EH_RESET | USBIP_EH_BYE )
++#define SDEV_EVENT_DOWN ( USBIP_EH_SHUTDOWN | USBIP_EH_RESET )
++#define SDEV_EVENT_ERROR_TCP ( USBIP_EH_SHUTDOWN | USBIP_EH_RESET )
++#define SDEV_EVENT_ERROR_SUBMIT ( USBIP_EH_SHUTDOWN | USBIP_EH_RESET )
++#define SDEV_EVENT_ERROR_MALLOC ( USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE )
++
++#define VDEV_EVENT_REMOVED ( USBIP_EH_SHUTDOWN | USBIP_EH_BYE )
++#define VDEV_EVENT_DOWN ( USBIP_EH_SHUTDOWN | USBIP_EH_RESET )
++#define VDEV_EVENT_ERROR_TCP ( USBIP_EH_SHUTDOWN | USBIP_EH_RESET )
++#define VDEV_EVENT_ERROR_MALLOC ( USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE)
++
++ unsigned long event;
++ struct usbip_task eh;
++ wait_queue_head_t eh_waitq;
++
++ struct eh_ops {
++ void (*shutdown)(struct usbip_device *);
++ void (*reset)(struct usbip_device *);
++ void (*unusable)(struct usbip_device *);
++ } eh_ops;
++};
++
++
++void usbip_task_init(struct usbip_task *ut, char *, void (*loop_ops)(struct usbip_task *));
++
++void usbip_start_threads(struct usbip_device *ud);
++void usbip_stop_threads(struct usbip_device *ud);
++int usbip_thread(void *param);
++
++void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd, int pack);
++/* some members of urb must be substituted before. */
++int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb);
++/* some members of urb must be substituted before. */
++int usbip_recv_iso(struct usbip_device *ud, struct urb *urb);
++
++
++/* usbip_event.c */
++void usbip_start_eh(struct usbip_device *ud);
++void usbip_stop_eh(struct usbip_device *ud);
++void usbip_event_add(struct usbip_device *ud, unsigned long event);
++int usbip_event_happend(struct usbip_device *ud);
++
++
++#endif
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/usbip_event.c
+@@ -0,0 +1,147 @@
++/*
++ * $Id: usbip_event.c 261 2005-08-30 10:49:17Z taka-hir $
++ *
++ * Copyright (C) 2003-2005 Takahiro Hirofuchi <taka-hir@is.naist.jp>
++ *
++ *
++ * 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"
++
++
++
++
++static void event_handler_loop(struct usbip_task *eh);
++
++void usbip_start_eh(struct usbip_device *ud)
++{
++ struct usbip_task *eh = &ud->eh;
++
++ init_waitqueue_head(&ud->eh_waitq);
++ ud->event = 0;
++
++ usbip_task_init(eh, "usbip_eh", event_handler_loop);
++
++ kernel_thread((int(*)(void *)) usbip_thread, (void *) eh, 0);
++
++ wait_for_completion(&eh->thread_done);
++}
++
++void usbip_stop_eh(struct usbip_device *ud)
++{
++ struct usbip_task *eh = &ud->eh;
++
++// if(eh->thread != NULL) {
++// send_sig(SIGKILL, eh->thread, 1);
++ wait_for_completion(&eh->thread_done);
++ dbg_eh("usbip_eh has finished\n");
++// }
++
++ dbg_eh("bye\n");
++}
++
++
++void usbip_event_add(struct usbip_device *ud, unsigned long event)
++{
++ spin_lock(&ud->lock);
++
++ ud->event |= event;
++
++ wake_up(&ud->eh_waitq);
++
++ spin_unlock(&ud->lock);
++}
++
++
++
++static int event_handler(struct usbip_device *ud)
++{
++
++ dbg_eh("enter\n");
++
++
++ /*
++ * Events are handled by only this thread.
++ */
++ while( usbip_event_happend(ud) ) {
++ dbg_eh("pending event %lx\n", ud->event);
++
++ /*
++ * NOTE: shutdown must come first.
++ * Shutdown the device.
++ */
++ if(ud->event & USBIP_EH_SHUTDOWN) {
++ ud->eh_ops.shutdown(ud);
++
++ ud->event &= ~USBIP_EH_SHUTDOWN;
++
++ break;
++ }
++
++ /* Stop the error handler. */
++ if(ud->event & USBIP_EH_BYE) {
++
++ return -1;
++ }
++
++ /* Reset the device. */
++ if(ud->event & USBIP_EH_RESET) {
++ ud->eh_ops.reset(ud);
++
++ ud->event &= ~USBIP_EH_RESET;
++
++ break;
++ }
++
++ /* Mark the device as unusable. */
++ if(ud->event & USBIP_EH_UNUSABLE) {
++ ud->eh_ops.unusable(ud);
++
++ ud->event &= ~USBIP_EH_UNUSABLE;
++
++ break;
++ }
++
++ /* NOTREACHED */
++ VHCI_ERROR("unknown event\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++
++
++
++static void event_handler_loop(struct usbip_task *ut)
++{
++ struct usbip_device *ud = container_of(ut, struct usbip_device, eh);
++
++ while(1) {
++ if(signal_pending(current)) {
++ dbg_eh("signal catched!\n");
++ break;
++ }
++
++ if( event_handler(ud) < 0)
++ break;
++
++ wait_event_interruptible(ud->eh_waitq, usbip_event_happend(ud));
++ dbg_eh("wakeup\n");
++ }
++}
++
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/vhci.h
+@@ -0,0 +1,110 @@
++/*
++ * $Id: vhci.h 249 2005-08-10 12:15:26Z taka-hir $
++ *
++ * Copyright (C) 2003-2005 Takahiro Hirofuchi <taka-hir@is.naist.jp>
++ *
++ *
++ * 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/platform_device.h>
++
++#define VHCI_DEVICE_INFO_SIZE 80
++
++struct vhci_device {
++ struct usb_device *udev;
++
++ __u32 busnum; /* remote bus num */
++ __u32 devnum; /* remote dev num */
++ __u32 infnum;
++
++ enum usb_device_speed speed;
++
++ char info[VHCI_DEVICE_INFO_SIZE];
++
++ __u32 rhport; /* root hub port number */
++
++ struct usbip_device ud;
++
++ /* vhci_priv is linked to any one of these lists. */
++ spinlock_t priv_lock;
++ struct list_head priv_tx;
++ struct list_head priv_rx;
++
++ wait_queue_head_t waitq;
++};
++
++
++/* urb->hcpriv, use container_of() */
++struct vhci_priv {
++ unsigned long seqnum;
++ struct list_head list;
++
++ struct vhci_device *vdev;
++ struct urb *urb;
++};
++
++
++/*
++ * The number of ports is less than 16 ?
++ * USB_MAXCHILDREN is statically defined to 16 in usb.h. Its maximum value
++ * would be 31 because the event_bits[1] of struct usb_hub is defined as
++ * unsigned long in hub.h
++ */
++#define VHCI_NPORTS 2
++
++/* for usb_bus.hcpriv */
++struct vhci_hcd {
++ struct usb_hcd hcd; /* must come first! */
++ spinlock_t lock;
++
++ struct platform_device pdev;
++
++ u32 port_status[VHCI_NPORTS];
++ int started;
++ struct completion released;
++ unsigned resuming:1;
++ unsigned long re_timeout;
++
++ atomic_t seqnum;
++
++ /*
++ * NOTE:
++ * wIndex shows the port number and begins from 1.
++ * But, the index of this array begins from 0.
++ */
++ struct vhci_device vdev[VHCI_NPORTS];
++
++ /* vhci_device which has not been assiged its address yet */
++ int pending_port;
++};
++
++
++
++/* vhci_hcd.c */
++void rh_port_connect(int rhport, enum usb_device_speed speed);
++void rh_port_disconnect(int rhport);
++extern struct vhci_hcd *the_controller;
++#define hardware (&the_controller->pdev.dev)
++
++struct vhci_device *port_to_vdev(__u32 port);
++
++void vhci_rx_loop(struct usbip_task *ut);
++void vhci_tx_loop(struct usbip_task *ut);
++
++
++/* vhci_sysfs.c */
++extern struct attribute_group dev_attr_group;
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/vhci_hcd.c
+@@ -0,0 +1,1026 @@
++/*
++ * $Id: vhci_hcd.c 267 2005-09-02 17:21:42Z taka-hir $
++ *
++ * Copyright (C) 2003-2005 Takahiro Hirofuchi <taka-hir@is.naist.jp>
++ *
++ *
++ * 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 "../core/hcd.h"
++#include "vhci.h"
++
++#define DRIVER_VERSION " $Id: vhci_hcd.c 267 2005-09-02 17:21:42Z taka-hir $ "
++#define DRIVER_AUTHOR "HIROFUCHI Takahiro <taka-hir@is.naist.jp>"
++#define DRIVER_DESC "Virtual Host Controller Interface Driver for USB/IP"
++#define DRIVER_LICENCE "GPL"
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE(DRIVER_LICENCE);
++
++
++
++
++/* See usb gadget dummy hcd */
++
++
++
++
++static inline struct vhci_hcd *hcd_to_vhci(struct usb_hcd *hcd)
++{
++ return (struct vhci_hcd *) (hcd->hcd_priv);
++}
++
++static int vhci_hub_status (struct usb_hcd *hcd, char *buff);
++static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buff, u16 wLength);
++static int vhci_urb_enqueue (struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags);
++static int vhci_urb_dequeue( struct usb_hcd *hcd, struct urb *urb);
++static int vhci_start(struct usb_hcd *vhci_hcd);
++static void vhci_stop(struct usb_hcd *hcd);
++static int vhci_get_frame_number(struct usb_hcd *hcd);
++
++static const char driver_name[] = "vhci_hcd";
++static const char driver_desc[] = "USB/IP Virtual Host Contoroller";
++
++
++
++
++struct vhci_hcd *the_controller = NULL;
++
++
++void rh_port_connect(int rhport, enum usb_device_speed speed)
++{
++ unsigned long flags;
++
++ dbg_vhci_rh("rh_port_connect %d\n", rhport);
++
++ spin_lock_irqsave (&the_controller->lock, flags);
++
++ the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION
++ | (1 << USB_PORT_FEAT_C_CONNECTION);
++
++ switch (speed) {
++ case USB_SPEED_HIGH:
++ the_controller->port_status[rhport] |= USB_PORT_STAT_HIGH_SPEED;
++ break;
++ case USB_SPEED_LOW:
++ the_controller->port_status[rhport] |= USB_PORT_STAT_LOW_SPEED;
++ break;
++ default:
++ break;
++ }
++
++ //spin_lock(&the_controller->vdev[rhport].ud.lock);
++ //the_controller->vdev[rhport].ud.status = VDEV_CONNECT;
++ //spin_unlock(&the_controller->vdev[rhport].ud.lock);
++
++ the_controller->pending_port = rhport;
++
++ spin_unlock_irqrestore (&the_controller->lock, flags);
++
++}
++
++void rh_port_disconnect(int rhport)
++{
++ unsigned long flags;
++
++ dbg_vhci_rh("rh_port_disconnect %d\n", rhport);
++
++ spin_lock_irqsave (&the_controller->lock, flags);
++ //stop_activity (dum, driver);
++ the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION;
++ the_controller->port_status[rhport] |= (1 << USB_PORT_FEAT_C_CONNECTION);
++
++
++ /* not yet complete the disconnection */
++ //spin_lock(&vdev->ud.lock);
++ //vdev->ud.status = VHC_ST_DISCONNECT;
++ //spin_unlock(&vdev->ud.lock);
++
++ spin_unlock_irqrestore (&the_controller->lock, flags);
++}
++
++
++
++
++
++
++/* See hub_configure in hub.c */
++static inline void hub_descriptor (struct usb_hub_descriptor *desc)
++{
++ memset (desc, 0, sizeof *desc);
++ desc->bDescriptorType = 0x29;
++ desc->bDescLength = 9;
++ desc->wHubCharacteristics = __constant_cpu_to_le16 (0x0001);
++ desc->bNbrPorts = VHCI_NPORTS;
++ desc->bitmap [0] = 0xff;
++ desc->bitmap [1] = 0xff;
++}
++
++
++static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
++{
++ struct vhci_hcd *dum;
++ int retval = 0;
++ unsigned long flags;
++ int rhport;
++
++ /*
++ * NOTE:
++ * wIndex shows the port number and begins from 1.
++ */
++ dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue, wIndex);
++ if (wIndex > VHCI_NPORTS)
++ VHCI_ERROR("invalid port number %d\n", wIndex);
++ rhport = ((__u8 ) (wIndex & 0x00ff)) -1;
++
++ //dum = container_of (hcd, struct vhci_hcd, hcd);
++ dum = hcd_to_vhci(hcd);
++ spin_lock_irqsave (&dum->lock, flags);
++ switch (typeReq) {
++ case ClearHubFeature:
++ dbg_vhci_rh("ClearHubFeature\n");
++ break;
++ case ClearPortFeature:
++ switch (wValue) {
++ case USB_PORT_FEAT_SUSPEND:
++ if (dum->port_status[rhport] & (1 << USB_PORT_FEAT_SUSPEND)) {
++ /* 20msec signaling */
++ dum->resuming = 1;
++ dum->re_timeout = jiffies + msecs_to_jiffies(20);
++ }
++ break;
++ case USB_PORT_FEAT_POWER:
++ dbg_vhci_rh("ClearPortFeature: USB_PORT_FEAT_POWER\n");
++ dum->port_status[rhport] = 0;
++ //dum->address = 0;
++ //dum->hdev = 0;
++ dum->resuming = 0;
++ break;
++ default:
++ dbg_vhci_rh("ClearPortFeature: default %x\n", wValue);
++ dum->port_status[rhport] &= ~(1 << wValue);
++ }
++ break;
++ case GetHubDescriptor:
++ dbg_vhci_rh("GetHubDescriptor\n");
++ hub_descriptor ((struct usb_hub_descriptor *) buf);
++ break;
++ case GetHubStatus:
++ dbg_vhci_rh("GetHubStatus\n");
++ *(u32 *) buf = __constant_cpu_to_le32 (0);
++ break;
++ case GetPortStatus:
++ dbg_vhci_rh("GetPortStatus port %x\n", wIndex);
++ if (wIndex > VHCI_NPORTS || wIndex < 1) {
++ VHCI_ERROR("invalid port number %d\n", wIndex);
++ retval = -EPIPE;
++ }
++
++ /* we do no care of resume. */
++
++ /* whoever resets or resumes must GetPortStatus to
++ * complete it!!
++ * */
++ if (dum->resuming && time_after (jiffies, dum->re_timeout)) {
++ VHCI_ERROR("not yet\n");
++ dum->port_status[rhport] |= (1 << USB_PORT_FEAT_C_SUSPEND);
++ dum->port_status[rhport] &= ~(1 << USB_PORT_FEAT_SUSPEND);
++ dum->resuming = 0;
++ dum->re_timeout = 0;
++ //if (dum->driver && dum->driver->resume) {
++ // spin_unlock (&dum->lock);
++ // dum->driver->resume (&dum->gadget);
++ // spin_lock (&dum->lock);
++ //}
++ }
++
++ if ((dum->port_status[rhport] & (1 << USB_PORT_FEAT_RESET)) != 0
++ && time_after (jiffies, dum->re_timeout)) {
++ dum->port_status[rhport] |= (1 << USB_PORT_FEAT_C_RESET);
++ dum->port_status[rhport] &= ~(1 << USB_PORT_FEAT_RESET);
++ dum->re_timeout = 0;
++
++ if (dum->vdev[rhport].ud.status == VDEV_ST_NOTASSIGNED) {
++ dbg_vhci_rh("enable rhport %d (status %u)\n", rhport, dum->vdev[rhport].ud.status);
++ dum->port_status[rhport] |= USB_PORT_STAT_ENABLE;
++ }
++#if 0
++ if (dum->driver) {
++
++ dum->port_status[rhport] |= USB_PORT_STAT_ENABLE;
++ /* give it the best speed we agree on */
++ dum->gadget.speed = dum->driver->speed;
++ dum->gadget.ep0->maxpacket = 64;
++ switch (dum->gadget.speed) {
++ case USB_SPEED_HIGH:
++ dum->port_status[rhport] |=
++ USB_PORT_STAT_HIGH_SPEED;
++ break;
++ case USB_SPEED_LOW:
++ dum->gadget.ep0->maxpacket = 8;
++ dum->port_status[rhport] |=
++ USB_PORT_STAT_LOW_SPEED;
++ break;
++ default:
++ dum->gadget.speed = USB_SPEED_FULL;
++ break;
++ }
++ }
++#endif
++
++ }
++ ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status[rhport]);
++ ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status[rhport] >> 16);
++
++ dbg_vhci_rh("GetPortStatus bye %x %x\n", ((u16 *)buf)[0], ((u16 *)buf)[1] );
++ break;
++ case SetHubFeature:
++ dbg_vhci_rh("SetHubFeature\n");
++ retval = -EPIPE;
++ break;
++ case SetPortFeature:
++ switch (wValue) {
++ case USB_PORT_FEAT_SUSPEND:
++ dbg_vhci_rh("SetPortFeature: USB_PORT_FEAT_SUSPEND\n");
++ VHCI_ERROR("not yet\n");
++#if 0
++ dum->port_status[rhport] |= (1 << USB_PORT_FEAT_SUSPEND);
++ if (dum->driver->suspend) {
++ spin_unlock (&dum->lock);
++ dum->driver->suspend (&dum->gadget);
++ spin_lock (&dum->lock);
++ }
++#endif
++ break;
++ case USB_PORT_FEAT_RESET:
++ dbg_vhci_rh("SetPortFeature: USB_PORT_FEAT_RESET\n");
++ /* if it's already running, disconnect first */
++ if (dum->port_status[rhport] & USB_PORT_STAT_ENABLE) {
++ dum->port_status[rhport] &= ~(USB_PORT_STAT_ENABLE
++ | USB_PORT_STAT_LOW_SPEED
++ | USB_PORT_STAT_HIGH_SPEED);
++#if 0
++ if (dum->driver) {
++ dev_dbg (hardware, "disconnect\n");
++ stop_activity (dum, dum->driver);
++ }
++#endif
++
++ /* FIXME test that code path! */
++ }
++ /* 50msec reset signaling */
++ dum->re_timeout = jiffies + msecs_to_jiffies(50);
++
++ /* FALLTHROUGH */
++ default:
++ dbg_vhci_rh("SetPortFeature: default %d\n", wValue);
++ dum->port_status[rhport] |= (1 << wValue);
++ }
++ break;
++
++ default:
++ VHCI_ERROR("default: no such request\n");
++ dev_dbg (hardware,
++ "hub control req%04x v%04x i%04x l%d\n",
++ typeReq, wValue, wIndex, wLength);
++
++ /* "protocol stall" on error */
++ retval = -EPIPE;
++ }
++
++ spin_unlock_irqrestore (&dum->lock, flags);
++
++ dbg_vhci_rh("bye\n");
++ return retval;
++}
++
++
++
++
++#define PORT_C_MASK \
++ ((1 << USB_PORT_FEAT_C_CONNECTION) \
++ | (1 << USB_PORT_FEAT_C_ENABLE) \
++ | (1 << USB_PORT_FEAT_C_SUSPEND) \
++ | (1 << USB_PORT_FEAT_C_OVER_CURRENT) \
++ | (1 << USB_PORT_FEAT_C_RESET))
++
++/*
++ * @buf: a bitmap to show which port status has been changed.
++ * bit 0: reserved or used for another purpose?
++ * bit 1: the status of port 0 has been changed.
++ * bit 2: the status of port 1 has been changed.
++ * ...
++ * bit 7: the status of port 6 has been changed.
++ * bit 8: the status of port 7 has been changed.
++ * ...
++ * bit 15: the status of port 14 has been changed.
++ *
++ * So, the maximum number of ports is 31 ( port 0 to port 30) ?
++ *
++ * The return value is the actual transfered length in byte.
++ * If nothing has changed, return 0.
++ * If the number of ports is less than or equal to 6, return 1.
++ */
++static int vhci_hub_status (struct usb_hcd *hcd, char *buf)
++{
++ struct vhci_hcd *dum;
++ unsigned long flags;
++ int retval;
++
++ /* the enough buffer is allocated according to USB_MAXCHILDREN */
++ unsigned long *event_bits = (unsigned long *) buf;
++ int rhport;
++ int changed = 0;
++
++
++ *event_bits = 0;
++ //dbg_vhci_rh("enter\n");
++
++ //dum = container_of (hcd, struct vhci_hcd, hcd);
++ dum = hcd_to_vhci(hcd);
++
++ spin_lock_irqsave (&dum->lock, flags);
++
++ for(rhport = 0; rhport < VHCI_NPORTS; rhport++) {
++
++ if (!(dum->port_status[rhport] & PORT_C_MASK)) {
++ /* The status of a port has not been changed, */
++ //retval = 0;
++ } else {
++ /* The status of a port has been changed, */
++ dbg_vhci_rh("port %d is changed\n", rhport);
++
++ *event_bits |= 1 << ( rhport + 1);
++ //*buf = (1 << 1);
++ dev_dbg (hardware, "port %d status 0x%08x has changes\n", rhport, dum->port_status[rhport]);
++ //retval = 1;
++ //
++ changed = 1;
++ }
++#if 0
++ if (!(dum->port_status[rhport] & PORT_C_MASK))
++ /* The status of a port has not been changed, */
++ retval = 0;
++ else {
++ /* The status of a port has been changed, */
++ *buf = (1 << 1);
++ dev_dbg (hardware, "port status 0x%08x has changes\n", dum->port_status[rhport]);
++ retval = 1;
++ }
++#endif
++ }
++
++ if (changed)
++ retval = 1 + (VHCI_NPORTS / 8);
++ else
++ retval = 0;
++
++ spin_unlock_irqrestore (&dum->lock, flags);
++
++ //dbg_vhci_rh("event_bits %lx\n", *event_bits);
++
++ //dbg_vhci_rh("bye\n");
++ return retval;
++
++}
++
++#if 0
++int devnum_to_port(int devnum)
++{
++ int i;
++ for(i=0; i< VHCI_NPORTS; i++ ) {
++ if (the_controller->vdev[i].dev != NULL)
++ if (the_controller->vdev[i].dev->devnum == devnum)
++ return i;
++ }
++
++ return -1;
++}
++
++static void maybe_set_status (struct urb *urb, int status)
++{
++ spin_lock (&urb->lock);
++ if (urb->status == -EINPROGRESS)
++ urb->status = status;
++ spin_unlock (&urb->lock);
++}
++#endif
++
++
++static struct vhci_device *get_vdev(struct usb_device *udev)
++{
++ int i;
++
++ if (!udev)
++ return NULL;
++
++ for (i=0; i < VHCI_NPORTS; i++)
++ if (the_controller->vdev[i].udev == udev)
++ return port_to_vdev(i);
++
++ return NULL;
++}
++
++
++static void vhci_tx_urb(struct urb *urb)
++{
++ struct vhci_device *vdev = get_vdev(urb->dev);
++ struct vhci_priv *priv;
++ unsigned long flag;
++
++ if (!vdev)
++ BUG();
++
++ spin_lock_irqsave(&vdev->priv_lock, flag);
++
++ priv = kzalloc(sizeof(struct vhci_priv), GFP_ATOMIC);
++ if (!priv) {
++ uerr("malloc vhci_priv\n");
++ spin_unlock_irqrestore(&vdev->priv_lock, flag);
++ usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
++ return;
++ }
++
++ priv->seqnum = atomic_read(&the_controller->seqnum);
++ atomic_inc(&the_controller->seqnum);
++ if (priv->seqnum == 0xffff)
++ uinfo("seqnum max\n");
++
++ priv->vdev = vdev;
++ priv->urb = urb;
++
++ urb->hcpriv = (void *) priv;
++
++
++ list_add_tail(&priv->list, &vdev->priv_tx);
++
++ wake_up(&vdev->waitq);
++ spin_unlock_irqrestore(&vdev->priv_lock, flag);
++}
++
++static int vhci_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags)
++{
++ int ret = 0;
++ unsigned long flags;
++
++ dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n", hcd, urb, mem_flags);
++
++
++
++ /* patch to usb_sg_init() is in 2.5.60 */
++ BUG_ON (!urb->transfer_buffer && urb->transfer_buffer_length);
++
++ spin_lock_irqsave (&the_controller->lock, flags);
++
++ /* check HC is active or not */
++ if (!HC_IS_RUNNING(hcd->state)) {
++ uerr("HC is not running\n");
++ spin_unlock_irqrestore(&the_controller->lock, flags);
++ return -ENODEV;
++ }
++
++ if (urb->status != -EINPROGRESS) {
++ uerr("URB already unlinked!, status %d\n", urb->status);
++ spin_unlock_irqrestore(&the_controller->lock, flags);
++ return urb->status;
++ }
++
++
++ /*
++ * The enumelation process is as follows;
++ *
++ * 1. Get_Descriptor request to DevAddrs(0) EndPoint(0)
++ * to get max packet length of default pipe
++ *
++ * 2. Set_Address request to DevAddr(0) EndPoint(0)
++ *
++ */
++
++ if (usb_pipedevice(urb->pipe) == 0) {
++ __u8 type = usb_pipetype(urb->pipe);
++ struct usb_ctrlrequest *ctrlreq = (struct usb_ctrlrequest *) urb->setup_packet;
++ struct vhci_device *vdev = port_to_vdev(the_controller->pending_port);
++
++ if (type != PIPE_CONTROL || !ctrlreq ) {
++ VHCI_ERROR("invalid request to devnum 0\n");
++ ret = EINVAL;
++ goto no_need_xmit;
++ }
++
++ switch (ctrlreq->bRequest) {
++
++ case USB_REQ_SET_ADDRESS:
++ vdev->udev = urb->dev;
++ dbg_vhci_hc("SetAddress Request (%d) to port %d\n",
++ ctrlreq->wValue, vdev->rhport);
++
++ spin_lock(&vdev->ud.lock);
++ vdev->ud.status = VDEV_ST_USED;
++ spin_unlock(&vdev->ud.lock);
++
++ spin_lock (&urb->lock);
++ if (urb->status == -EINPROGRESS) {
++ /* This request is successfully completed. */
++ /* If not -EINPROGRESS, possibly unlinked. */
++ urb->status = 0;
++ }
++ spin_unlock (&urb->lock);
++
++ goto no_need_xmit;
++
++ case USB_REQ_GET_DESCRIPTOR:
++ if (ctrlreq->wValue == (USB_DT_DEVICE << 8)) {
++ dbg_vhci_hc("Not yet?: Get_Descriptor to device 0( get max pipe size )\n");
++ }
++ vdev->udev = urb->dev;
++ goto out;
++
++ default:
++ /* NOT REACHED */
++ VHCI_ERROR("invalid request to devnum 0 bRequest %u, wValue %u\n",
++ ctrlreq->bRequest, ctrlreq->wValue);
++ ret = -EINVAL;
++ goto no_need_xmit;
++ }
++
++ }
++
++out:
++
++
++ vhci_tx_urb(urb);
++
++
++ spin_unlock_irqrestore (&the_controller->lock, flags);
++
++ return 0;
++
++
++no_need_xmit:
++ //urb->hcpriv = NULL;
++
++ spin_unlock_irqrestore(&the_controller->lock, flags);
++ usb_hcd_giveback_urb(&the_controller->hcd, urb, NULL);
++
++ return 0;
++}
++
++
++/*
++ * vhci_rx gives back the urb after recieving the reply of the urb. If an
++ * unlink pdu is sent or not, vhci_rx recieves a normal return pdu and gives
++ * back its urb. For the driver unlinking the urb, the content of the urb is
++ * not important, but the calling to its completion handler is important; the
++ * completion of unlinking is notified by the completion handler.
++ */
++static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
++{
++ unsigned long flags;
++ struct vhci_priv *priv;
++ struct vhci_device *vdev;
++
++ uinfo("vhci_hcd: dequeue a urb %p\n", urb);
++
++ spin_lock_irqsave (&the_controller->lock, flags);
++
++ priv = urb->hcpriv;
++ if (!priv) {
++ /* URB was never linked! or will be soon given back by vhci_rx. */
++ spin_unlock_irqrestore(&the_controller->lock, flags);
++ return 0;
++ }
++
++ // send unlink request here?
++ vdev = priv->vdev;
++
++ if (!vdev->ud.tcp_socket) {
++ unsigned long flags2;
++ spin_lock_irqsave(&vdev->priv_lock, flags2);
++ uinfo("vhci_hcd: device %p seems to be disconnected\n", vdev);
++
++ list_del(&priv->list);
++ kfree(priv);
++ urb->hcpriv = NULL;
++
++ spin_unlock_irqrestore(&vdev->priv_lock, flags2);
++ }
++
++ if (!vdev->ud.tcp_socket) {
++ spin_unlock_irqrestore(&the_controller->lock, flags);
++
++ uinfo("vhci_hcd: vhci_urb_dequeue() gives back urb %p\n", urb);
++ usb_hcd_giveback_urb(&the_controller->hcd, urb, NULL);
++ } else {
++ spin_unlock_irqrestore(&the_controller->lock, flags);
++ }
++
++ dbg_vhci_hc("leave\n");
++ return 0;
++}
++
++
++static void vhci_device_unlink_all_urb(struct vhci_device *vdev)
++{
++ struct vhci_priv *priv, *tmp;
++ struct urb *urb;
++
++ spin_lock(&vdev->priv_lock);
++
++ list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) {
++ urb = priv->urb;
++ list_del(&priv->list);
++ kfree(priv);
++
++ urb->hcpriv = NULL;
++
++ /* FIXME:
++ * Should i give back a urb to usbcore ?
++ */
++ spin_unlock(&vdev->priv_lock);
++ usb_hcd_giveback_urb(&the_controller->hcd, urb, NULL);
++ spin_lock(&vdev->priv_lock);
++ }
++
++ list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) {
++ urb = priv->urb;
++ list_del(&priv->list);
++ kfree(priv);
++
++ urb->hcpriv = NULL;
++
++ /* FIXME:
++ * Should i give back a urb to usbcore ?
++ */
++ spin_unlock(&vdev->priv_lock);
++ usb_hcd_giveback_urb(&the_controller->hcd, urb, NULL);
++ spin_lock(&vdev->priv_lock);
++ }
++
++ spin_unlock(&vdev->priv_lock);
++}
++
++/*
++ * The important thing is that only one context begins cleanup.
++ * This is why error handling and cleanup become simple.
++ * We do not want to consider race condition as possible.
++ */
++static void vhci_shutdown_connection(struct usbip_device *ud)
++{
++ struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
++
++
++ usbip_stop_threads(&vdev->ud);
++ uinfo("stop threads\n");
++
++ /* active connection is closed */
++ if (vdev->ud.tcp_socket != NULL) {
++ sock_release(vdev->ud.tcp_socket);
++ vdev->ud.tcp_socket = NULL;
++ }
++ uinfo("release socket\n");
++
++ /*
++ * rh_port_disconnect() is a trigger of ...
++ * usb_disable_device():
++ * disable all the endpoints for a USB device.
++ * usb_disable_endpoint():
++ * disable endpoints. pending urbs are unlinked(dequeued).
++ *
++ * NOTE: After calling rh_port_disconnect(), the USB device driver of a
++ * deteched device should release used urbs in a cleanup function(i.e.
++ * xxx_disconnect()). Therefore, vhci_hcd does not need to release
++ * pushed urbs and their private data in this function.
++ *
++ * NOTE: vhci_dequeue() must be considered carefully. When shutdowning
++ * a connection, vhci_shutdown_connection() expects vhci_dequeue()
++ * gives back pushed urbs and frees their private data by request of
++ * the cleanup function of a USB driver. When unlinking a urb with an
++ * active connection, vhci_dequeue() does not give back the urb which
++ * is actually given back by vhci_rx after recieving its return pdu.
++ *
++ */
++ rh_port_disconnect(vdev->rhport);
++
++ /* Comment out. See the upper NOTE */
++#if 0
++ /* the priv lists are freed */
++ vhci_device_unlink_all_urb(vdev);
++ uinfo("unlink all urbs\n");
++#endif
++
++ uinfo("disconnect device\n");
++
++}
++
++
++static void vhci_device_reset(struct usbip_device *ud)
++{
++ struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
++
++ spin_lock(&ud->lock);
++
++ vdev->busnum = 0;
++ vdev->devnum = 0;
++ vdev->speed = 0;
++
++ ud->tcp_socket = NULL;
++
++ //usbip_stop_threads(ud);
++
++ ud->status = VDEV_ST_NULL;
++
++ spin_unlock(&ud->lock);
++
++}
++
++static void vhci_device_unusable(struct usbip_device* ud)
++{
++ spin_lock(&ud->lock);
++
++ ud->status = VDEV_ST_ERROR;
++
++ spin_unlock(&ud->lock);
++}
++
++static void vhci_device_init(struct vhci_device *vdev)
++{
++ memset(vdev, 0, sizeof(*vdev));
++
++ usbip_task_init(&vdev->ud.tcp_rx, "vhci_rx", vhci_rx_loop);
++ usbip_task_init(&vdev->ud.tcp_tx, "vhci_tx", vhci_tx_loop);
++
++ vdev->ud.side = USBIP_VHCI;
++ vdev->ud.status = VDEV_ST_NULL;
++ vdev->ud.lock = SPIN_LOCK_UNLOCKED;
++
++ INIT_LIST_HEAD(&vdev->priv_rx);
++ INIT_LIST_HEAD(&vdev->priv_tx);
++ vdev->priv_lock = SPIN_LOCK_UNLOCKED;
++
++ init_waitqueue_head(&vdev->waitq);
++
++ vdev->ud.eh_ops.shutdown = vhci_shutdown_connection;
++ vdev->ud.eh_ops.reset = vhci_device_reset;
++ vdev->ud.eh_ops.unusable= vhci_device_unusable;
++
++ usbip_start_eh(&vdev->ud);
++}
++
++
++/*----------------------------------------------------------------------*/
++
++static int vhci_start(struct usb_hcd *hcd)
++{
++ //struct vhci_hcd *vhci = hcd_to_vhci(hcd);
++
++ dbg_vhci_hc("enter vhci_start\n");
++
++ hcd->state = HC_STATE_RUNNING;
++
++ return 0;
++}
++
++static void vhci_stop(struct usb_hcd *hcd)
++{
++ struct vhci_hcd *vhci = hcd_to_vhci(hcd);
++
++ dbg_vhci_hc("stop VHCI controller\n");
++
++ {
++ __u32 rhport = 0;
++ struct vhci_device *vdev;
++
++ for( rhport = 0 ; rhport < VHCI_NPORTS; rhport++) {
++ vdev = &vhci->vdev[rhport];
++
++ usbip_event_add(&vdev->ud, VDEV_EVENT_REMOVED);
++ usbip_stop_eh(&vdev->ud);
++ }
++ }
++
++ uinfo("vhci_stop done\n");
++}
++
++/*----------------------------------------------------------------------*/
++
++static int vhci_get_frame_number(struct usb_hcd *hcd)
++{
++ uerr("Not yet implemented\n");
++ return 0;
++}
++
++static struct hc_driver vhci_hc_driver = {
++ .description = driver_name,
++ .product_desc = driver_desc,
++ .hcd_priv_size = sizeof(struct vhci_hcd),
++
++ .flags = HCD_USB2,
++
++ .start = vhci_start,
++ .stop = vhci_stop,
++
++ .urb_enqueue = vhci_urb_enqueue,
++ .urb_dequeue = vhci_urb_dequeue,
++
++ .get_frame_number = vhci_get_frame_number,
++
++ .hub_status_data = vhci_hub_status,
++ .hub_control = vhci_hub_control,
++ //.hub_suspend = vhci_hub_suspend,
++ //.hub_resume = vhci_hub_resume,
++};
++
++static int vhci_hcd_probe(struct device *dev)
++{
++ struct usb_hcd *hcd;
++ struct platform_device *pdev;
++ struct vhci_hcd *vhci;
++ int ret;
++
++ uinfo("proving...\n");
++
++
++ pdev = container_of(dev, struct platform_device, dev);
++ dbg_vhci_hc("name %s id %d\n", pdev->name, pdev->id);
++
++
++ /*
++ * Allocate and initialize hcd.
++ * Our private data is also allocated automatically.
++ */
++ hcd = usb_create_hcd(&vhci_hc_driver, dev, dev->bus_id);
++ if (!hcd)
++ return -ENOMEM;
++
++
++ the_controller = vhci = hcd_to_vhci(hcd);
++ {
++ int port;
++ for(port=0; port < VHCI_NPORTS; port++) {
++ struct vhci_device *vdev = &vhci->vdev[port];
++ vhci_device_init( vdev );
++ vdev->rhport = port;
++ }
++ }
++ atomic_set(&vhci->seqnum, 1);
++ spin_lock_init(&vhci->lock);
++
++
++
++ hcd->product_desc = "USB/IP VHCI driver";
++
++
++ /*
++ * Finish generic HCD structure initialization and register.
++ * Call the driver's reset() and start() routines.
++ */
++ ret = usb_add_hcd(hcd, 0, 0);
++ if (ret != 0) {
++ usb_put_hcd(hcd);
++ return ret;
++ }
++
++ sysfs_create_group(&hcd->self.controller->kobj, &dev_attr_group);
++
++ dbg_vhci_hc("bye\n");
++ return 0;
++}
++
++
++static int vhci_hcd_remove(struct device *dev)
++{
++ struct usb_hcd *hcd;
++
++ hcd = dev_get_drvdata(dev);
++
++ /*
++ * Disconnects the root hub,
++ * then reverses the effects of usb_add_hcd(),
++ * invoking the HCD's stop() methods.
++ */
++ usb_remove_hcd(hcd);
++ usb_put_hcd(hcd);
++ the_controller = NULL;
++
++ sysfs_remove_group(&hcd->self.controller->kobj, &dev_attr_group);
++
++ return 0;
++}
++
++static int vhci_hcd_suspend(struct device *dev, pm_message_t state)
++{
++ struct usb_hcd *hcd;
++
++ dev_dbg(dev, "%s=n", __FUNCTION__);
++ hcd = dev_get_drvdata(dev);
++
++#ifndef CONFIG_USB_SUSPEND
++ uerr("Not yet supported!\n");
++#endif
++
++ hcd->state = HC_STATE_SUSPENDED;
++ return 0;
++}
++
++static int vhci_hcd_resume(struct device *dev)
++{
++ struct usb_hcd *hcd;
++
++ dev_dbg(dev, "%s=n", __FUNCTION__);
++ hcd = dev_get_drvdata(dev);
++ hcd->state = HC_STATE_RUNNING;
++
++#ifndef CONFIG_USB_SUSPEND
++ uerr("Not yet supported!\n");
++#endif
++
++ usb_hcd_poll_rh_status(hcd);
++ return 0;
++}
++
++static struct device_driver vhci_driver = {
++ .name = (char *) driver_name,
++ .bus = &platform_bus_type,
++ .probe = vhci_hcd_probe,
++ .remove = vhci_hcd_remove,
++ .suspend = vhci_hcd_suspend,
++ .resume = vhci_hcd_resume,
++};
++
++/*----------------------------------------------------------------------*/
++
++/* The VHCI 'device' is 'virtual';
++ * it has no hardware and automatic detection.
++ * We need to add this virtual device as a platform device arbitrarily:
++ * 1. platform_device_register()
++ * 2. vhci_driver.probe()
++ */
++static void the_pdev_release(struct device *dev)
++{
++ return;
++}
++
++static struct platform_device the_pdev = {
++ .name = "hc",
++ .dev.driver = &vhci_driver,
++ .dev.release = the_pdev_release
++};
++
++static int __init vhci_init(void)
++{
++ int ret;
++
++ dbg_vhci_hc("enter\n");
++ if (usb_disabled())
++ return -ENODEV;
++
++ info("driver %s, %s\n", driver_name, DRIVER_VERSION);
++ ret = driver_register(&vhci_driver);
++ if (ret < 0)
++ return ret;
++
++ ret = platform_device_register(&the_pdev);
++ if (ret < 0) {
++ driver_unregister(&vhci_driver);
++ return ret;
++ }
++
++ ret = vhci_driver.probe(&the_pdev.dev);
++ if (ret < 0) {
++ platform_device_unregister(&the_pdev);
++ driver_unregister(&vhci_driver);
++ }
++
++ dbg_vhci_hc("bye\n");
++ return ret;
++}
++module_init(vhci_init);
++
++
++static void __exit vhci_cleanup(void)
++{
++ dbg_vhci_hc("enter\n");
++
++ /* device_unregister will call vhci_driver.remove() */
++ platform_device_unregister(&the_pdev);
++ driver_unregister(&vhci_driver);
++
++ dbg_vhci_hc("bye\n");
++}
++module_exit(vhci_cleanup);
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/vhci_rx.c
+@@ -0,0 +1,149 @@
++/*
++ * $Id: vhci_rx.c 265 2005-09-01 09:24:10Z taka-hir $
++ *
++ * Copyright (C) 2003-2005 Takahiro Hirofuchi <taka-hir@is.naist.jp>
++ *
++ *
++ * 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 "../core/hcd.h"
++#include "vhci.h"
++
++/* get URB from transmitted queue */
++static struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum)
++{
++ struct vhci_priv *priv, *tmp;
++ struct urb *urb = NULL;
++
++ spin_lock(&vdev->priv_lock);
++
++ list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) {
++ if (priv->seqnum == seqnum) {
++ urb = priv->urb;
++ dbg_vhci_rx("find urb %p vurb %p seqnum %u\n", urb, priv, seqnum);
++
++ if (urb->status != -EINPROGRESS) {
++ if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
++ uinfo("urb %p was unlinked %ssynchronuously.\n",
++ urb, urb->status == -ENOENT ? "" : "a");
++ } else {
++ uinfo("urb %p may be in a error, status %d\n",
++ urb, urb->status);
++ }
++ }
++
++ list_del(&priv->list);
++ kfree(priv);
++ urb->hcpriv = NULL;
++
++ break;
++ }
++ }
++
++ spin_unlock(&vdev->priv_lock);
++
++
++ return urb;
++}
++
++static void vhci_recv_return(struct vhci_device *vdev, struct usbip_header *pdu)
++{
++ struct usbip_device *ud = &vdev->ud;
++ struct urb *urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum);
++
++ if (!urb) {
++ VHCI_ERROR("cannot find a urb of seqnum %u\n", pdu->base.seqnum);
++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
++ return;
++ }
++
++
++ /* unpack the pdu to a urb */
++ usbip_pack_pdu(pdu, urb, VHC_C_RETURN, 0);
++
++ /* recv transfer buffer */
++ if (usbip_recv_xbuff(ud, urb) < 0)
++ return;
++
++ /* recv iso_packet_descriptor */
++ if (usbip_recv_iso(ud, urb) < 0)
++ return;
++
++ dbg_vhci_rx("now giveback urb %p\n", urb);
++
++ usb_hcd_giveback_urb(&the_controller->hcd, urb, NULL);
++
++ dbg_vhci_rx("Leave\n");
++
++ return;
++}
++
++
++/* recv a pdu */
++static void vhci_rx_pdu(struct usbip_device *ud)
++{
++ int ret;
++ struct usbip_header pdu;
++ struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
++
++
++ dbg_vhci_rx("Enter\n");
++
++ memset(&pdu, 0, sizeof(pdu));
++
++
++ /* 1. recieve a pdu header */
++ ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu),0);
++ if (ret != sizeof(pdu)) {
++ VHCI_ERROR("recv a header, %d\n", ret);
++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
++ return;
++ }
++
++ if (dbg_flag_vhci_rx)
++ usbip_dump_header(&pdu);
++
++ switch(pdu.base.command) {
++ case VHC_C_RETURN:
++ vhci_recv_return(vdev, &pdu);
++ break;
++ default:
++ /* NOTREACHED */
++ VHCI_ERROR("unknown pdu\n");
++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
++ }
++}
++
++void vhci_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_vhci_rx("signal catched!\n");
++ break;
++ }
++
++
++ if (usbip_event_happend(ud)) break;
++
++ vhci_rx_pdu(ud);
++ }
++}
++
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/vhci_sysfs.c
+@@ -0,0 +1,265 @@
++/*
++ * $Id: vhci_sysfs.c 260 2005-08-30 10:35:16Z taka-hir $
++ *
++ * Copyright (C) 2003-2005 Takahiro Hirofuchi <taka-hir@is.naist.jp>
++ *
++ *
++ * 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/in.h>
++#include <linux/in6.h>
++#include "usbip_common.h"
++#include "../core/hcd.h"
++#include "vhci.h"
++
++
++struct vhci_device *port_to_vdev(__u32 port)
++{
++ return &the_controller->vdev[port];
++}
++
++
++static int vhci_proc_vcdown(__u32 rhport)
++{
++ struct vhci_device *vdev = port_to_vdev(rhport);
++
++ dbg_vhci_sysfs("enter\n");
++
++ spin_lock(&vdev->priv_lock);
++
++ if (vdev->ud.status == VDEV_ST_NULL) {
++ VHCI_ERROR("not connected %d\n", vdev->ud.status);
++ spin_unlock(&vdev->priv_lock);
++ return -EINVAL;
++ }
++
++ spin_unlock(&vdev->priv_lock);
++
++ usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
++
++ return 0;
++}
++
++static int vhci_proc_status(char *out)
++{
++ char *s = out;
++ int i = 0;
++
++ /*
++ * prt sta bus dev ipaddr port busid
++ * 000 004 000 000 xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx xxxxxx xxxxxxxxx...
++ * 001 004 000 000 xxx.xxx.xxx.xxx xxxxxx xxxxxxxxx...
++ */
++
++ out += sprintf(out, "prt sta spd bus dev ipaddr port busid\n");
++
++ if (!the_controller) {
++ VHCI_ERROR("the_controller is NULL\n");
++ return 0;
++ }
++
++
++ for (i=0; i < VHCI_NPORTS; i++) {
++ struct vhci_device *vdev = port_to_vdev(i);
++
++ spin_lock(&vdev->ud.lock);
++
++ out += sprintf(out, "%03u %03u ", i, vdev->ud.status);
++
++ if (vdev->ud.status == VDEV_ST_USED) {
++ out += sprintf(out, "%03u %03u %03u ", vdev->speed, vdev->busnum, vdev->devnum);
++
++ if (vdev->ud.tcp_ss.ss_family == AF_INET) {
++ out += sprintf(out, "%03u.%03u.%03u.%03u ",
++ NIPQUAD(ss_v4_addr(vdev->ud.tcp_ss)));
++ out += sprintf(out, "%06d ", ss_v4_port(vdev->ud.tcp_ss));
++
++ } else if (vdev->ud.tcp_ss.ss_family == AF_INET6) {
++ out += sprintf(out, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
++ NIP6(ss_v6_addr(vdev->ud.tcp_ss)));
++ out += sprintf(out, "%06d ", ss_v6_port(vdev->ud.tcp_ss));
++
++ } else {
++ VHCI_ERROR("unknown ss_family %d\n", vdev->ud.tcp_ss.ss_family);
++ }
++
++ out += sprintf(out, "%s", vdev->info);
++
++ } else {
++ out += sprintf(out, "000 000 000 0000:0000:0000:0000:0000:0000:0000:0000 000000 xxx");
++ }
++
++
++ out += sprintf(out, "\n");
++
++ spin_unlock(&vdev->ud.lock);
++ }
++
++
++ return out - s ;
++}
++
++
++
++
++
++
++static int valid_args(__u32 rhport, __u32 busnum, __u32 devnum, enum usb_device_speed speed)
++{
++
++ /* check rhport */
++ if ((rhport < 0) || (rhport >= VHCI_NPORTS)) {
++ VHCI_ERROR("invalid port %u\n", rhport);
++ return -EINVAL;
++ }
++
++ /* check busnum & devnum */
++ if ((busnum<=0) || (busnum>=128) || (devnum<=0) || (devnum>=128)) {
++ VHCI_ERROR("invalid busnum or portnum\n");
++ return -EINVAL;
++ }
++
++ /* check speed */
++ switch(speed) {
++ case USB_SPEED_LOW:
++ case USB_SPEED_FULL:
++ case USB_SPEED_HIGH:
++ break;
++
++ default:
++ VHCI_ERROR("invalid speed\n");
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++
++
++/* -------------------------------------------- */
++
++static ssize_t show_status(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ return vhci_proc_status(buf);
++}
++static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
++
++static ssize_t store_detach(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
++{
++ int err;
++ __u32 rhport = 0;
++
++ sscanf(buf, "%u", &rhport);
++
++ /* check rhport */
++ if ((rhport < 0) || (rhport >= VHCI_NPORTS)) {
++ VHCI_ERROR("invalid port %u\n", rhport);
++ return -EINVAL;
++ }
++
++ err = vhci_proc_vcdown(rhport);
++ if (err < 0) {
++ return -EINVAL;
++ }
++
++ dbg_vhci_sysfs("Leave\n");
++ return count;
++}
++static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach);
++
++static ssize_t store_attach(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct socket *socket;
++ char info[VHCI_DEVICE_INFO_SIZE];
++ __u32 rhport=0, sockfd=0, busnum=0, devnum=0, speed=0;
++ struct vhci_device *vdev;
++
++ memset(info, 0, VHCI_DEVICE_INFO_SIZE);
++ sscanf(buf, "%u %u %u %u %u %s", &rhport, &sockfd, &busnum, &devnum, &speed, info);
++
++ dbg_vhci_sysfs("rhport(%u) sockfd(%u) busnum(%u) devnum(%u) speed(%u)\n",
++ rhport, sockfd, busnum, devnum, speed);
++
++ if (valid_args(rhport, busnum, devnum, speed) < 0) {
++ return -EINVAL;
++ }
++
++ /* check sockfd */
++ socket = sockfd_to_socket(sockfd);
++ if (!socket) {
++ return -EINVAL;
++ }
++
++ setnodelay(socket);
++
++ vdev = port_to_vdev(rhport);
++
++ /* begin a lock */
++ spin_lock(&vdev->ud.lock);
++
++ if (vdev->ud.status != VDEV_ST_NULL) {
++ spin_unlock(&vdev->ud.lock);
++ VHCI_ERROR("port %d already used\n", rhport);
++ return -EINVAL;
++ }
++
++ VHCI_INFO("rhport(%u) sockfd(%u) busnum(%u) devnum(%u) speed(%u)\n",
++ rhport, sockfd, busnum, devnum, speed);
++ VHCI_INFO(" info: %s\n", info);
++
++ vdev->busnum = busnum;
++ vdev->devnum = devnum;
++ vdev->speed = speed;
++ vdev->ud.tcp_socket = socket;
++ set_sockaddr(socket, &vdev->ud.tcp_ss);
++ vdev->ud.status = VDEV_ST_NOTASSIGNED;
++ memcpy(vdev->info, info, VHCI_DEVICE_INFO_SIZE);
++
++ spin_unlock(&vdev->ud.lock);
++ /* end the lock */
++
++ if (vdev->ud.tcp_ss.ss_family == AF_INET)
++ VHCI_INFO("connected to %u.%u.%u.%u(%d)\n",
++ NIPQUAD(ss_v4_addr(vdev->ud.tcp_ss)), ss_v4_port(vdev->ud.tcp_ss));
++ else if (vdev->ud.tcp_ss.ss_family == AF_INET6)
++ VHCI_INFO("connected to %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x(%d)",
++ NIP6(ss_v6_addr(vdev->ud.tcp_ss)), ss_v6_port(vdev->ud.tcp_ss));
++ else
++ VHCI_ERROR("unknown ss_family %d\n", vdev->ud.tcp_ss.ss_family);
++
++
++
++ usbip_start_threads(&vdev->ud);
++ rh_port_connect(rhport, speed);
++
++ return count;
++}
++static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach);
++
++static struct attribute *dev_attrs[] = {
++ &dev_attr_status.attr,
++ &dev_attr_detach.attr,
++ &dev_attr_attach.attr,
++ &dev_attr_usbip_debug.attr,
++ NULL,
++};
++
++struct attribute_group dev_attr_group = {
++ //.name = "usbip",
++ .attrs = dev_attrs,
++};
++
+--- /dev/null
++++ gregkh-2.6/drivers/usb/ip/vhci_tx.c
+@@ -0,0 +1,165 @@
++/*
++ * $Id: vhci_tx.c 260 2005-08-30 10:35:16Z taka-hir $
++ *
++ * Copyright (C) 2003-2005 Takahiro Hirofuchi <taka-hir@is.naist.jp>
++ *
++ *
++ * 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 "../core/hcd.h"
++#include "vhci.h"
++
++
++/* @p: pipe whose dev number modified
++ * @pdev: new devive number */
++static unsigned long vhci_change_pipe_devnum(__u32 p, __u8 pdev)
++{
++ __u32 oldp;
++ oldp = p;
++
++ if (pdev > 0x7f)
++ VHCI_ERROR("invalid devnum %u\n", pdev);
++ pdev &= 0x7f; // 0XXX XXXX confirm MSB be 0
++
++ p &= 0xffff80ff; /* clear p's devnum */
++
++ p |= (pdev << 8);
++
++ dbg_vhci_tx("return new pipe, devnum %u -> %u \n",
++ usb_pipedevice(oldp), usb_pipedevice(p));
++ dbg_vhci_tx(" pipe %08x -> %08x\n", oldp, p);
++ return p;
++}
++
++static void setup_pdu(struct usbip_header *pdup, struct urb *urb)
++{
++ struct vhci_priv *priv = ((struct vhci_priv *)urb->hcpriv);
++ struct vhci_device *vdev = priv->vdev;
++
++ dbg_vhci_tx("URB, local devnum(%u), busnum(%u) devnum(%u)\n",
++ usb_pipedevice(urb->pipe), vdev->busnum, vdev->devnum);
++
++ pdup->base.command = VHC_C_SUBMIT;
++ pdup->base.busnum = vdev->busnum;
++ pdup->base.devnum = vdev->devnum;
++ pdup->base.seqnum = priv->seqnum;
++ pdup->base.pipe = vhci_change_pipe_devnum(urb->pipe, vdev->devnum);
++ usbip_pack_pdu(pdup, urb, VHC_C_SUBMIT, 1);
++
++ if (urb->setup_packet != NULL)
++ memcpy(pdup->u.submit.setup, urb->setup_packet, 8);
++}
++
++#define MAX_SUBMIT_QUEUE_DEPTH 100
++static struct usbip_header SubmitPDU[MAX_SUBMIT_QUEUE_DEPTH];
++
++static int vhci_send_txdata(struct vhci_device *vdev)
++{
++ unsigned long flags;
++ struct vhci_priv *priv, *tmp;
++ size_t txsize = 0;
++ int count = 0; /* the number of queued pdu */
++
++ struct msghdr msg;
++ struct iovec iov[MAX_SUBMIT_QUEUE_DEPTH];
++
++ memset(iov, 0, sizeof(iov));
++ memset(&msg, 0, sizeof(msg));
++ msg.msg_iov = iov;
++ msg.msg_iovlen = 0;
++
++ memset(&SubmitPDU, 0, sizeof(struct usbip_header)*MAX_SUBMIT_QUEUE_DEPTH);
++
++ spin_lock_irqsave(&vdev->priv_lock, flags);
++
++ /* setup txdata to msghdr from queued urbs */
++ list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) {
++ struct urb *urb = priv->urb;
++
++ dbg_vhci_tx("setup txdata %d for urb %p\n", count, urb);
++
++ /* 1. setup usbip_header */
++ setup_pdu(&SubmitPDU[count], urb);
++
++ iov[msg.msg_iovlen].iov_base = (void *)&SubmitPDU[count];
++ iov[msg.msg_iovlen].iov_len = sizeof(struct usbip_header);
++ msg.msg_iovlen ++;
++ txsize += sizeof(struct usbip_header);
++
++ /* 2. setup transfer buffer */
++ if (!usb_pipein(urb->pipe) &&
++ urb->transfer_buffer != NULL &&
++ urb->transfer_buffer_length > 0) {
++ iov[msg.msg_iovlen].iov_base = urb->transfer_buffer;
++ iov[msg.msg_iovlen].iov_len = urb->transfer_buffer_length;
++ msg.msg_iovlen++;
++ txsize += urb->transfer_buffer_length;
++ }
++
++ /* 3. setup iso_packet_descriptor */
++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++ iov[msg.msg_iovlen].iov_base = &urb->iso_frame_desc[0];
++ iov[msg.msg_iovlen].iov_len = urb->number_of_packets * sizeof(struct usb_iso_packet_descriptor);
++ msg.msg_iovlen++;
++ txsize += urb->number_of_packets * sizeof(struct usb_iso_packet_descriptor);
++ }
++
++ list_move_tail(&priv->list, &vdev->priv_rx);
++
++ count++;
++ if (count == MAX_SUBMIT_QUEUE_DEPTH) {
++ dbg_vhci_tx("max urbs are processed, %d\n", MAX_SUBMIT_QUEUE_DEPTH);
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&vdev->priv_lock,flags);
++
++ if (txsize > 0) {
++ int ret;
++ ret = usbip_sendmsg(vdev->ud.tcp_socket, &msg, txsize);
++ if (ret != txsize) {
++ VHCI_ERROR("vhci_sendmsg failed!, retval %d for %d\n", ret, txsize);
++ usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
++ return -1;
++ }
++
++ dbg_vhci_tx("send txdata \n");
++ }
++
++ return txsize;
++}
++
++void vhci_tx_loop(struct usbip_task *ut)
++{
++ struct usbip_device *ud = container_of(ut, struct usbip_device, tcp_tx);
++ struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
++
++ while(1) {
++ if (signal_pending(current)) {
++ VHCI_INFO("vhci_tx signal catched\n");
++ break;
++ }
++
++ if (vhci_send_txdata(vdev) < 0)
++ break;
++
++ wait_event_interruptible(vdev->waitq, !list_empty(&vdev->priv_tx));
++ dbg_vhci_tx("pending urbs ?, now wake up\n");
++ }
++}