All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH][15/17] USB virt 2.6 split driver---USB split driver back-end
@ 2005-11-21 13:19 harry
  0 siblings, 0 replies; only message in thread
From: harry @ 2005-11-21 13:19 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: Type: text/plain, Size: 117 bytes --]

This patch implements the back end of the USB split driver.

Signed-off-by: Harry Butterworth <butterwo@uk.ibm.com>


[-- Attachment #2: p15-usb-usbback.patch --]
[-- Type: text/x-patch, Size: 138210 bytes --]

diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/arch/xen/Kconfig
--- a/linux-2.6-xen-sparse/arch/xen/Kconfig	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/arch/xen/Kconfig	Mon Nov 21 11:10:19 2005
@@ -77,6 +77,29 @@
 	  The network-device backend driver allows the kernel to export its
 	  network devices to other guests via a high-performance shared-memory
 	  interface.
+
+config XEN_USBDEV_BACKEND
+	tristate "USB-device backend driver"
+	depends on XEN_PHYSDEV_ACCESS
+	select USB
+	default m
+	help
+	  The USB-device backend driver allows the kernel to export USB
+	  devices to USB-device frontend drivers running in other domains.
+	  This is not required for USB device access in domain 0 or any domain
+	  given exclusive control over a USB host controller device at the PCI
+	  level.
+	  Say Y or M if you want to use this kernel to export a USB device to
+          another domain running a USB-device frontend driver.
+
+config XEN_USBDEV_BACKEND_TRACE
+	bool "USB-device backend driver tracing"
+	depends on XEN_USBDEV_BACKEND
+	default n
+	help
+	  This option causes the driver to output a continual trace of its
+          activity.
+	  Say N here unless you are trying to debug the driver.
 
 config XEN_TPMDEV_FRONTEND
         bool "TPM-device frontend driver"
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Mon Nov 21 11:10:19 2005
@@ -12,6 +12,7 @@
 obj-$(CONFIG_XEN_BLKDEV_BACKEND)	+= blkback/
 obj-$(CONFIG_XEN_NETDEV_BACKEND)	+= netback/
 obj-$(CONFIG_XEN_TPMDEV_BACKEND)	+= tpmback/
+obj-$(CONFIG_XEN_USBDEV_BACKEND)	+= usbback/
 obj-$(CONFIG_XEN_BLKDEV_FRONTEND)	+= blkfront/
 obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= netfront/
 obj-$(CONFIG_XEN_BLKDEV_TAP)    	+= blktap/
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/Makefile
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/Makefile	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,9 @@
+obj-$(CONFIG_XEN_USBDEV_BACKEND) += usbback.o
+
+usbback-objs :=                \
+usbback_device.o               \
+usbback_driver_backend.o       \
+usbback_driver.o               \
+usbback_driver_port.o          \
+usbback_driver_port_resource.o \
+usbback_module.o
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,38 @@
+/*****************************************************************************/
+/* Implementation of the ASSERT macro                                        */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_ASSERT_H
+#define USBBACK_ASSERT_H
+
+#include <linux/kernel.h>
+
+static inline void assert_failed
+    (const char *function, int line, const char *statement) {
+	printk
+	    (KERN_ERR "usbback assert failed: %s line %d, statement %s\n",
+	     function, line, statement);
+
+	BUG();
+}
+
+#define ASSERT( S ) \
+( ( S ) ? ( (void)0 ) : assert_failed( __PRETTY_FUNCTION__, __LINE__, #S ) )
+
+#endif
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,450 @@
+/*****************************************************************************/
+/* A device object representing the low-level connection to a single         */
+/* front-end.                                                                */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on                                                                  */
+/*                                                                           */
+/* arch/xen/drivers/usbif/backend/control.c                                  */
+/* arch/xen/drivers/usbif/backend/interface.c                                */
+/* arch/xen/drivers/usbif/backend/main.c                                     */
+/* blkback/xenbus.c                                                          */
+/*                                                                           */
+/* original copyright notices follow...                                      */
+/*****************************************************************************/
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/control.c
+ * 
+ * Routines for interfacing with the control plane.
+ * 
+ * Copyright (c) 2004, Keir Fraser
+ */
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/interface.c
+ * 
+ * USB device interface management.
+ * 
+ * by Mark Williamson, Copyright (c) 2004
+ */
+
+/******************************************************************************
+ * arch/xen/drivers/blkif/backend/interface.c
+ * 
+ * Block-device interface management.
+ * 
+ * Copyright (c) 2004, Keir Fraser
+ */
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ * 
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson
+ * Copyright (c) 2004 Intel Research Cambridge
+ * Copyright (c) 2004, 2005 Mark Williamson
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+/*  Xenbus code for blkif backend
+    Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <asm-xen/xen-public/io/usbif.h>
+#include <asm-xen/xenbus.h>
+#include <asm-xen/xenidc.h>
+#include <linux/err.h>
+#include "usbback_assert.h"
+#include "usbback_device.h"
+#include "usbback_driver.h"
+#include "usbback_trace.h"
+
+struct usbback_device {
+	struct xenbus_device *dev;
+	void *drvdata;
+	char *path;
+	xenidc_address address;
+	xenidc_endpoint endpoint;
+};
+
+static inline struct usbback_device *usbback_device_endpoint_to
+    (xenidc_endpoint * endpoint) {
+	/* trace(); */
+
+	return container_of(endpoint, struct usbback_device, endpoint);
+}
+
+void usbback_device_set_drvdata(struct usbback_device *device, void *data)
+{
+	trace();
+
+	device->drvdata = data;
+}
+
+void *usbback_device_get_drvdata(struct usbback_device *device)
+{
+	/* trace(); */
+
+	return device->drvdata;
+}
+
+xenidc_address usbback_device_query_address(struct usbback_device * device)
+{
+	trace();
+
+	return device->address;
+}
+
+static void usbback_device_endpoint_connect(xenidc_endpoint * endpoint)
+{
+	trace();
+
+	/* Transactions and messages received between connect and disconnect are */
+	/* processed normally.                                                   */
+	/* Between connect and completion of the disconnect callback we are      */
+	/* allowed to issue messages and transactions.  We don't actually need   */
+	/* to issue messages or transactions from the backend to the frontend.   */
+
+	usbback_driver_endpoint_connect(usbback_device_endpoint_to(endpoint));
+}
+
+static void usbback_device_endpoint_disconnect
+    (xenidc_endpoint * endpoint, xenidc_callback * callback) {
+	trace();
+
+	/* We must stop issuing messages and transactions and complete the       */
+	/* callback once all of the messages and transactions we are issuing     */
+	/* have completed or failed back to us.                                  */
+
+	/* After the disconnect, any messages or transactions we receive must be */
+	/* failed back and we must flush through any that are in progress.       */
+
+	/* We don't issue any messages or transactions from the BE to the FE but */
+	/* we hang onto the callback until we are internally quiesced.  This     */
+	/* stops the endpoint from reconnecting whilst we are quiescing which    */
+	/* helps to keep the state machines a little bit simpler.                */
+
+	usbback_driver_endpoint_disconnect
+	    (usbback_device_endpoint_to(endpoint), callback);
+}
+
+static void usbback_device_endpoint_message
+    (xenidc_endpoint * endpoint, xenidc_endpoint_message * message) {
+	trace();
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	usbback_driver_message_handler
+	    (usbback_device_endpoint_to(endpoint), message);
+}
+
+static void usbback_device_endpoint_transaction
+    (xenidc_endpoint * endpoint, xenidc_endpoint_transaction * transaction) {
+	/* trace(); */
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	usbback_driver_transaction_handler
+	    (usbback_device_endpoint_to(endpoint), transaction);
+}
+
+static int __usbback_device_resume_or_suspend
+    (struct usbback_device *device, int suspend);
+
+static int usbback_device_init_or_exit
+    (struct usbback_device *device, struct xenbus_device *dev, int exit) {
+	trace();
+
+	{
+		int return_value = 0;
+
+		if (exit) {
+			goto EXIT;
+		}
+
+		memset(device, 0, sizeof(*device));
+
+		device->dev = dev;
+
+		return_value = usbback_driver_probe_usbback_device(device);
+
+		if (return_value != 0) {
+			trace0("Failed to probe driver.");
+
+			goto EXIT_NO_DRIVER;
+		}
+
+		{
+			struct xenbus_transaction *transaction =
+			    xenbus_transaction_start();
+
+			if (IS_ERR(transaction)) {
+				trace0("Error starting transaction.");
+
+				return_value = PTR_ERR(transaction);
+
+				goto EXIT_NO_PATH;
+			}
+
+			return_value = xenbus_gather
+			    (transaction,
+			     dev->nodename, "path", NULL, &device->path, NULL);
+
+			(void)xenbus_transaction_end(transaction, 1);
+		}
+
+		if (XENBUS_EXIST_ERR(return_value)) {
+			trace0("Frontend doesn't seem to exist.");
+
+			goto EXIT_NO_PATH;
+		}
+
+		if (return_value < 0) {
+			trace0("Failed to gather configuration parameters.");
+
+			xenbus_dev_error
+			    (dev,
+			     return_value, "reading %s/path", dev->nodename);
+
+			goto EXIT_NO_PATH;
+		}
+
+		trace1("Gathered configuration: path:%s", device->path);
+
+		return_value = xenidc_endpoint_init
+		    (&device->endpoint,
+		     usbback_device_endpoint_connect,
+		     usbback_device_endpoint_message,
+		     usbback_device_endpoint_transaction,
+		     usbback_device_endpoint_disconnect,
+		     USBIF_BE_INITIATOR_QUOTA,
+		     USBIF_BE_INITIATOR_MAXIMUM_BYTE_COUNT,
+		     USBIF_BE_TARGET_QUOTA, USBIF_BE_TARGET_MAXIMUM_BYTE_COUNT);
+
+		if (return_value != 0) {
+			trace0
+			    ("Failed to initialise endpoint for frontend connection.");
+
+			goto EXIT_NO_ENDPOINT;
+		}
+
+		usbback_driver_claim_port(device, 1, device->path);
+
+		return_value = __usbback_device_resume_or_suspend(device, 0);
+
+		if (return_value != 0) {
+			goto EXIT_NO_RESUME;
+		}
+
+		return 0;
+
+	      EXIT:
+
+		(void)__usbback_device_resume_or_suspend(device, 1);
+
+	      EXIT_NO_RESUME:
+
+		usbback_driver_release_port(device, 1);
+
+		xenidc_endpoint_exit(&device->endpoint);
+
+	      EXIT_NO_ENDPOINT:
+
+		kfree(device->path);
+
+	      EXIT_NO_PATH:
+
+		usbback_driver_remove_usbback_device(device);
+
+	      EXIT_NO_DRIVER:
+
+		return return_value;
+	}
+}
+
+static int usbback_device_init
+    (struct usbback_device *device, struct xenbus_device *dev) {
+	trace();
+
+	return usbback_device_init_or_exit(device, dev, 0);
+}
+
+static void usbback_device_exit(struct usbback_device *device)
+{
+	trace();
+
+	(void)usbback_device_init_or_exit(device, NULL, 1);
+}
+
+static int usbback_device_probe_or_remove(struct xenbus_device *dev, int remove) {
+	trace();
+
+	{
+		int return_value = 0;
+
+		struct usbback_device *device;
+
+		if (remove) {
+			goto REMOVE;
+		}
+
+		device = kmalloc(sizeof(*device), GFP_KERNEL);
+
+		if (device == NULL) {
+			xenbus_dev_error(dev, -ENOMEM,
+					 "allocating backend structure");
+
+			return_value = -ENOMEM;
+
+			goto EXIT_NO_DEVICE;
+		}
+
+		dev->data = device;
+
+		return_value = usbback_device_init(device, dev);
+
+		if (return_value != 0) {
+			goto EXIT_INIT_FAILED;
+		}
+
+		return 0;
+
+	      REMOVE:
+
+		device = dev->data;
+
+		usbback_device_exit(device);
+
+	      EXIT_INIT_FAILED:
+
+		dev->data = NULL;
+
+		kfree(device);
+
+	      EXIT_NO_DEVICE:
+
+		return return_value;
+	}
+}
+
+static int usbback_device_probe
+    (struct xenbus_device *dev, const struct xenbus_device_id *id) {
+	trace();
+
+	return usbback_device_probe_or_remove(dev, 0);
+}
+
+static int usbback_device_remove(struct xenbus_device *dev)
+{
+	trace();
+
+	return usbback_device_probe_or_remove(dev, 1);
+}
+
+static int __usbback_device_resume_or_suspend
+    (struct usbback_device *device, int suspend) {
+	trace();
+
+	{
+		int return_value = 0;
+
+		if (suspend) {
+			goto SUSPEND;
+		}
+
+		xenidc_address_init
+		    (&device->address,
+		     device->dev->nodename,
+		     device->dev->otherend, device->dev->otherend_id);
+
+		xenidc_endpoint_create(&device->endpoint, device->address);
+
+		return 0;
+
+	      SUSPEND:
+
+		xenidc_endpoint_destroy(&device->endpoint);
+
+		return return_value;
+	}
+}
+
+static int usbback_device_resume(struct xenbus_device *dev)
+{
+	trace();
+
+	{
+		struct usbback_device *device = dev->data;
+
+		(void)__usbback_device_resume_or_suspend(device, 1);
+
+		return __usbback_device_resume_or_suspend(device, 0);
+	}
+}
+
+static struct xenbus_device_id usbback_device_ids[] = {
+	{"usb"},
+	{""}
+};
+
+static struct xenbus_driver usbback_device_driver = {
+	.name = "usb",
+	.owner = THIS_MODULE,
+	.ids = usbback_device_ids,
+	.probe = usbback_device_probe,
+	.remove = usbback_device_remove,
+	.resume = usbback_device_resume,
+};
+
+int usbback_device_class_init(void)
+{
+	trace();
+
+	xenbus_register_backend(&usbback_device_driver);
+
+	return 0;
+}
+
+void usbback_device_class_exit(void)
+{
+	trace();
+
+	xenbus_unregister_driver(&usbback_device_driver);
+}
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,42 @@
+/*****************************************************************************/
+/* A device object representing the low-level connection to a single         */
+/* front-end.                                                                */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_DEVICE_H
+#define USBBACK_DEVICE_H
+
+#include <asm-xen/xenidc.h>
+
+extern int usbback_device_class_init(void);
+
+extern void usbback_device_class_exit(void);
+
+struct usbback_device;
+
+extern void usbback_device_set_drvdata
+    (struct usbback_device *device, void *data);
+
+extern void *usbback_device_get_drvdata(struct usbback_device *device);
+
+extern xenidc_address usbback_device_query_address
+    (struct usbback_device *device);
+
+#endif
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,240 @@
+/*****************************************************************************/
+/* Device driver which drives usbback_device devices.                        */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#include <linux/device.h>
+#include <linux/usb.h>
+#include "usbback_assert.h"
+#include "usbback_device.h"
+#include "usbback_driver.h"
+#include "usbback_driver_backend.h"
+#include "usbback_driver_port.h"
+#include "usbback_trace.h"
+
+static int usbback_driver_probe_usb
+    (struct usb_interface *intf, const struct usb_device_id *id) {
+	trace();
+
+	return usbback_driver_port_probe_usb(intf);
+}
+
+static void usbback_driver_disconnect_usb(struct usb_interface *intf)
+{
+	trace();
+
+	usbback_driver_port_disconnect_usb(intf);
+}
+
+static int usbback_driver_probe_or_remove_usbback_device
+    (struct usbback_device *device, int remove) {
+	trace();
+
+	{
+		struct usbback_driver_backend *backend;
+
+		int return_value = 0;
+
+		if (remove) {
+			goto REMOVE;
+		}
+
+		backend = usbback_driver_backend_allocate(device);
+
+		if (backend == NULL) {
+			return_value = -ENOMEM;
+
+			goto EXIT_NO_BACKEND;
+		}
+
+		usbback_device_set_drvdata(device, backend);
+
+		return 0;
+
+	      REMOVE:
+
+		backend = usbback_device_get_drvdata(device);
+
+		usbback_driver_backend_shutdown(backend);
+
+		usbback_device_set_drvdata(device, NULL);
+
+	      EXIT_NO_BACKEND:
+
+		return return_value;
+	}
+}
+
+int usbback_driver_probe_usbback_device(struct usbback_device *device)
+{
+	trace();
+
+	return usbback_driver_probe_or_remove_usbback_device(device, 0);
+}
+
+void usbback_driver_endpoint_connect(struct usbback_device *device)
+{
+	trace();
+
+	{
+		struct usbback_driver_backend *backend =
+		    usbback_device_get_drvdata(device);
+
+		usbback_driver_backend_endpoint_connect(backend);
+	}
+}
+
+void usbback_driver_message_handler
+    (struct usbback_device *device, xenidc_endpoint_message * message) {
+	trace();
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	{
+		struct usbback_driver_backend *backend =
+		    usbback_device_get_drvdata(device);
+
+		usbback_driver_backend_message_handler(backend, message);
+	}
+}
+
+void usbback_driver_transaction_handler
+    (struct usbback_device *device, xenidc_endpoint_transaction * transaction) {
+	/* trace(); */
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	{
+		struct usbback_driver_backend *backend =
+		    usbback_device_get_drvdata(device);
+
+		usbback_driver_backend_transaction_handler(backend,
+							   transaction);
+	}
+}
+
+void usbback_driver_endpoint_disconnect
+    (struct usbback_device *device, xenidc_callback * callback) {
+	trace();
+
+	{
+		struct usbback_driver_backend *backend =
+		    usbback_device_get_drvdata(device);
+
+		usbback_driver_backend_endpoint_disconnect(backend, callback);
+	}
+}
+
+void usbback_driver_claim_port
+    (struct usbback_device *device, u32 port, char *path) {
+	trace();
+
+	{
+		struct usbback_driver_backend *backend =
+		    usbback_device_get_drvdata(device);
+
+		usbback_driver_backend_claim_port(backend, port, path);
+	}
+}
+
+void usbback_driver_release_port(struct usbback_device *device, u32 port) {
+	trace();
+
+	{
+		struct usbback_driver_backend *backend =
+		    usbback_device_get_drvdata(device);
+
+		usbback_driver_backend_release_port(backend, port);
+	}
+}
+
+void usbback_driver_remove_usbback_device(struct usbback_device *device)
+{
+	trace();
+
+	(void)usbback_driver_probe_or_remove_usbback_device(device, 1);
+}
+
+static struct usb_device_id usbback_driver_usb_id_table[] = {
+	{.driver_info = 1},	/* Matches all devices. */
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, usbback_driver_usb_id_table);
+
+struct usb_driver usbback_driver_usb_driver = {
+	.owner = THIS_MODULE,
+	.name = "usbback",
+	.probe = usbback_driver_probe_usb,
+	.disconnect = usbback_driver_disconnect_usb,
+	.id_table = usbback_driver_usb_id_table,
+};
+
+static int usbback_driver_init_or_exit(int exit)
+{
+	trace();
+
+	{
+		int return_value = 0;
+
+		if (exit) {
+			goto EXIT;
+		}
+
+		return_value = usbback_driver_port_class_init();
+
+		if (return_value != 0) {
+			goto EXIT_NO_PORT_CLASS;
+		}
+
+		return_value = usb_register(&usbback_driver_usb_driver);
+
+		if (return_value != 0) {
+			goto EXIT_NO_USB_REGISTER;
+		}
+
+		return 0;
+
+	      EXIT:
+
+		usb_deregister(&usbback_driver_usb_driver);
+
+	      EXIT_NO_USB_REGISTER:
+
+		usbback_driver_port_class_exit();
+
+	      EXIT_NO_PORT_CLASS:
+
+		return return_value;
+	}
+}
+
+int usbback_driver_init(void)
+{
+	trace();
+
+	return usbback_driver_init_or_exit(0);
+}
+
+void usbback_driver_exit(void)
+{
+	trace();
+
+	(void)usbback_driver_init_or_exit(1);
+}
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,53 @@
+/*****************************************************************************/
+/* Device driver which drives usbback_device devices.                        */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_DRIVER_H
+#define USBBACK_DRIVER_H
+
+#include "asm-xen/xenidc.h"
+#include "usbback_device.h"
+
+extern int usbback_driver_init(void);
+
+extern int usbback_driver_probe_usbback_device(struct usbback_device *device);
+
+extern void usbback_driver_endpoint_connect(struct usbback_device *device);
+
+extern void usbback_driver_message_handler
+    (struct usbback_device *device, xenidc_endpoint_message * message);
+
+extern void usbback_driver_transaction_handler
+    (struct usbback_device *device, xenidc_endpoint_transaction * transaction);
+
+extern void usbback_driver_endpoint_disconnect
+    (struct usbback_device *device, xenidc_callback * callback);
+
+extern void usbback_driver_claim_port
+    (struct usbback_device *device, u32 port, char *path);
+
+extern void usbback_driver_release_port
+    (struct usbback_device *device, u32 port);
+
+extern void usbback_driver_remove_usbback_device(struct usbback_device *device);
+
+extern void usbback_driver_exit(void);
+
+#endif
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,554 @@
+/*****************************************************************************/
+/* usbback_driver_backend is the representation in the driver of the         */
+/* back-end side of a single front-end to back-end connection.               */
+/* One of these objects is used by the usbback_driver to manage each         */
+/* usbback_device.                                                           */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on arch/xen/drivers/usbif/backend/main.c, original copyright notice */
+/* follows...                                                                */
+/*****************************************************************************/
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ * 
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson
+ * Copyright (c) 2004 Intel Research Cambridge
+ * Copyright (c) 2004, 2005 Mark Williamson
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+#include <asm-xen/xen-public/io/usbif.h>
+#include "usbback_assert.h"
+#include "usbback_device.h"
+#include "usbback_driver_backend.h"
+#include "usbback_driver_port.h"
+#include "usbback_trace.h"
+
+#define USBBACK_DRIVER_PORT_COUNT 7
+
+typedef struct usbback_driver_backend_callback_struct
+ usbback_driver_backend_callback;
+
+struct usbback_driver_backend_callback_struct {
+	xenidc_callback callback;
+	struct usbback_driver_backend *backend;
+};
+
+struct usbback_driver_backend {
+	struct usbback_device *device;
+	spinlock_t lock;
+	xenidc_callback *endpoint_disconnect_callback;
+	int port_disconnect_callbacks_out;
+	usbback_driver_backend_callback port_disconnect_callback
+	    [USBBACK_DRIVER_PORT_COUNT];
+	struct usbback_driver_port port[USBBACK_DRIVER_PORT_COUNT];
+};
+
+static void usbback_driver_backend_endpoint_disconnect_1
+    (xenidc_callback * callback);
+
+static int usbback_driver_backend_init_or_exit
+    (struct usbback_driver_backend *backend,
+     struct usbback_device *device, int exit) {
+	trace();
+
+	{
+		int return_value = 0;
+
+		if (exit) {
+			goto EXIT;
+		}
+
+		memset(backend, 0, sizeof(*backend));
+
+		backend->device = device;
+
+		spin_lock_init(&backend->lock);
+
+		{
+			int i;
+
+			for (i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++) {
+				xenidc_callback_init
+				    (&backend->port_disconnect_callback[i].
+				     callback,
+				     usbback_driver_backend_endpoint_disconnect_1);
+
+				backend->port_disconnect_callback[i].backend =
+				    backend;
+			}
+		}
+
+		{
+			int i;
+
+			for (i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++) {
+				return_value =
+				    usbback_driver_port_init(&backend->port[i],
+							     backend);
+
+				if (return_value != 0) {
+					goto EXIT_NO_PORT;
+				}
+			}
+
+			return 0;
+
+		      EXIT:
+
+			i = USBBACK_DRIVER_PORT_COUNT;
+
+		      EXIT_NO_PORT:
+
+			i--;
+
+			for (; i >= 0; i--) {
+				usbback_driver_port_shutdown(&backend->port[i]);
+			}
+		}
+
+		return return_value;
+	}
+}
+
+struct usbback_driver_backend *usbback_driver_backend_allocate
+    (struct usbback_device *device) {
+	struct usbback_driver_backend *backend =
+	    (struct usbback_driver_backend *)kmalloc
+	    (sizeof(struct usbback_driver_backend), GFP_KERNEL);
+
+	if ((backend != NULL)
+	    && (usbback_driver_backend_init_or_exit(backend, device, 0) != 0)
+	    ) {
+		kfree(backend);
+
+		backend = NULL;
+	}
+
+	return backend;
+}
+
+void usbback_driver_backend_endpoint_connect
+    (struct usbback_driver_backend *backend) {
+	trace();
+
+	{
+		int i;
+
+		for (i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++) {
+			usbback_driver_port_endpoint_connect(&backend->port[i]);
+		}
+	}
+}
+
+static void usbback_driver_backend_handle_probe
+    (struct usbback_driver_backend *backend,
+     xenidc_endpoint_transaction * transaction);
+
+static void usbback_driver_backend_handle_reset
+    (struct usbback_driver_backend *backend,
+     xenidc_endpoint_transaction * transaction);
+
+static void usbback_driver_backend_handle_io
+    (struct usbback_driver_backend *backend,
+     xenidc_endpoint_transaction * transaction);
+
+void usbback_driver_backend_transaction_handler
+    (struct usbback_driver_backend *backend,
+     xenidc_endpoint_transaction * transaction) {
+	/* trace(); */
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	usbif_transaction_parameters_header header;
+
+	if (xenidc_local_buffer_reference_copy_out
+	    (xenidc_endpoint_transaction_to_parameters_lbr(transaction),
+	     &header, sizeof(header)
+	    )
+	    == sizeof(header)
+	    ) {
+		switch (header.transaction_type) {
+		case USBIF_TRANSACTION_TYPE_PROBE:
+			usbback_driver_backend_handle_probe(backend,
+							    transaction);
+			break;
+		case USBIF_TRANSACTION_TYPE_RESET:
+			usbback_driver_backend_handle_reset(backend,
+							    transaction);
+			break;
+		case USBIF_TRANSACTION_TYPE_IO:
+			usbback_driver_backend_handle_io(backend, transaction);
+			break;
+		default:
+			xenidc_endpoint_transaction_complete
+			    (transaction, XENIDC_ERROR_INVALID_PARAMETER);
+			break;
+		}
+	} else {
+		/* Parameters were underlength. */
+
+		xenidc_endpoint_transaction_complete
+		    (transaction, XENIDC_ERROR_INVALID_PROTOCOL);
+	}
+}
+
+static void usbback_driver_backend_handle_probe
+    (struct usbback_driver_backend *backend,
+     xenidc_endpoint_transaction * transaction) {
+	/* trace(); */
+
+	usbif_probe_transaction_parameters parameters;
+
+	xenidc_error error;
+
+	if (xenidc_local_buffer_reference_copy_out
+	    (xenidc_endpoint_transaction_to_parameters_lbr(transaction),
+	     &parameters, sizeof(parameters)
+	    )
+	    != sizeof(parameters)
+	    ) {
+		error = XENIDC_ERROR_INVALID_PROTOCOL;
+
+		goto COMPLETE;
+	}
+
+	if ((parameters.port <= 0)
+	    || (parameters.port > USBBACK_DRIVER_PORT_COUNT)
+	    ) {
+		error = XENIDC_ERROR_INVALID_PARAMETER;
+
+		goto COMPLETE;
+	}
+
+	{
+		usbif_probe_transaction_status status;
+
+		memset(&status, 0, sizeof(status));
+
+		status.result = usbback_driver_port_usbdev_is_connected
+		    (&backend->port[parameters.port - 1]) ?
+		    USBIF_PROBE_RESULT_DEVICE_PRESENT :
+		    USBIF_PROBE_RESULT_NO_DEVICE;
+
+		if (xenidc_local_buffer_reference_copy_in
+		    (xenidc_endpoint_transaction_to_status_lbr(transaction),
+		     &status, sizeof(status)
+		    )
+		    != sizeof(status)
+		    ) {
+			error = XENIDC_ERROR_INVALID_PROTOCOL;
+
+			goto COMPLETE;
+		}
+	}
+
+	error = XENIDC_ERROR_SUCCESS;
+
+      COMPLETE:
+
+	xenidc_endpoint_transaction_complete(transaction, error);
+}
+
+static void usbback_driver_backend_handle_reset
+    (struct usbback_driver_backend *backend,
+     xenidc_endpoint_transaction * transaction) {
+	trace();
+
+	{
+		usbif_reset_transaction_parameters parameters;
+
+		xenidc_error error;
+
+		if (xenidc_local_buffer_reference_copy_out
+		    (xenidc_endpoint_transaction_to_parameters_lbr(transaction),
+		     &parameters, sizeof(parameters)
+		    )
+		    != sizeof(parameters)
+		    ) {
+			error = XENIDC_ERROR_INVALID_PROTOCOL;
+
+			goto COMPLETE;
+		}
+
+		if ((parameters.port <= 0)
+		    || (parameters.port > USBBACK_DRIVER_PORT_COUNT)
+		    ) {
+			error = XENIDC_ERROR_INVALID_PARAMETER;
+
+			goto COMPLETE;
+		}
+
+		{
+			int result = usbback_driver_port_reset
+			    (&backend->port[parameters.port - 1]);
+
+			if (result < 0) {
+				error = USBIF_XENIDC_ERROR_NO_DEVICE;
+
+				goto COMPLETE;
+			}
+
+			{
+				usbif_reset_transaction_status status;
+
+				memset(&status, 0, sizeof(status));
+
+				status.result = result;
+
+				if (xenidc_local_buffer_reference_copy_in
+				    (xenidc_endpoint_transaction_to_status_lbr
+				     (transaction), &status, sizeof(status)
+				    )
+				    != sizeof(status)
+				    ) {
+					error = XENIDC_ERROR_INVALID_PROTOCOL;
+
+					goto COMPLETE;
+				}
+			}
+		}
+
+		error = XENIDC_ERROR_SUCCESS;
+
+	      COMPLETE:
+
+		xenidc_endpoint_transaction_complete(transaction, error);
+	}
+}
+
+static struct usbback_driver_port
+    *usbback_driver_backend_find_port_by_guest_address(struct
+						       usbback_driver_backend
+						       *backend,
+						       unsigned long
+						       guest_address) {
+	trace();
+
+	{
+		int i;
+
+		for (i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++) {
+			struct usbback_driver_port *port = &backend->port[i];
+
+			if (usbback_driver_port_match_guest_address
+			    (port, guest_address)
+			    ) {
+				return port;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+static void usbback_driver_backend_handle_io
+    (struct usbback_driver_backend *backend,
+     xenidc_endpoint_transaction * transaction) {
+	trace();
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	{
+		usbif_io_transaction_parameters_header header;
+
+		xenidc_error error;
+
+		if (xenidc_local_buffer_reference_copy_out
+		    (xenidc_endpoint_transaction_to_parameters_lbr(transaction),
+		     &header, sizeof(header)
+		    )
+		    != sizeof(header)
+		    ) {
+			error = XENIDC_ERROR_INVALID_PROTOCOL;
+
+			goto COMPLETE;
+		}
+
+		{
+			struct usbback_driver_port *port =
+			    usbback_driver_backend_find_port_by_guest_address
+			    (backend, header.device_number);
+
+			if (port == NULL) {
+				error = USBIF_XENIDC_ERROR_NO_DEVICE;
+
+				goto COMPLETE;
+			}
+
+			usbback_driver_port_handle_io(port, transaction);
+		}
+
+		return;
+
+	      COMPLETE:
+
+		xenidc_endpoint_transaction_complete(transaction, error);
+	}
+}
+
+static void usbback_driver_backend_handle_unlink
+    (struct usbback_driver_backend *backend, xenidc_endpoint_message * message);
+
+void usbback_driver_backend_message_handler
+    (struct usbback_driver_backend *backend,
+     xenidc_endpoint_message * message) {
+	trace();
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	{
+		usbif_message_header header;
+
+		if (xenidc_local_buffer_reference_copy_out
+		    (xenidc_endpoint_message_to_message_lbr(message),
+		     &header, sizeof(header)
+		    )
+		    == sizeof(header)
+		    ) {
+			switch (header.message_type) {
+			case USBIF_MESSAGE_TYPE_UNLINK:
+				usbback_driver_backend_handle_unlink(backend,
+								     message);
+				break;
+			}
+		}
+
+		xenidc_callback_success
+		    (xenidc_endpoint_message_to_callback(message));
+	}
+}
+
+static void usbback_driver_backend_handle_unlink
+    (struct usbback_driver_backend *backend,
+     xenidc_endpoint_message * message) {
+	trace();
+
+	{
+		usbif_unlink_message_body unlink;
+
+		if (xenidc_local_buffer_reference_copy_out
+		    (xenidc_endpoint_message_to_message_lbr(message),
+		     &unlink, sizeof(unlink)
+		    )
+		    == sizeof(unlink)
+		    ) {
+			int i;
+
+			for (i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++) {
+				struct usbback_driver_port *port =
+				    &backend->port[i];
+
+				if (usbback_driver_port_try_unlink
+				    (port, unlink.unlink_id)
+				    ) {
+					break;
+				}
+			}
+		}
+	}
+}
+
+void usbback_driver_backend_endpoint_disconnect
+    (struct usbback_driver_backend *backend, xenidc_callback * callback) {
+	trace();
+
+	backend->endpoint_disconnect_callback = callback;
+
+	backend->port_disconnect_callbacks_out = USBBACK_DRIVER_PORT_COUNT;
+
+	{
+		int i;
+
+		for (i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++) {
+			usbback_driver_port_endpoint_disconnect
+			    (&backend->port[i],
+			     &backend->port_disconnect_callback[i].callback);
+		}
+	}
+}
+
+static void usbback_driver_backend_endpoint_disconnect_1
+    (xenidc_callback * callback) {
+	trace();
+
+	{
+		struct usbback_driver_backend *backend = container_of
+		    (callback, usbback_driver_backend_callback,
+		     callback)->backend;
+
+		spin_lock(&backend->lock);
+
+		if (--backend->port_disconnect_callbacks_out == 0) {
+			xenidc_callback_success(backend->
+						endpoint_disconnect_callback);
+		}
+
+		spin_unlock(&backend->lock);
+	}
+}
+
+void usbback_driver_backend_claim_port
+    (struct usbback_driver_backend *backend, u32 port, char *path) {
+	trace2("port: %d, path: %s", port, path);
+
+	ASSERT((port > 0)
+	       && (port <= USBBACK_DRIVER_PORT_COUNT)
+	    );
+
+	usbback_driver_port_claim(&backend->port[port - 1], path);
+
+	bus_rescan_devices(&usb_bus_type);
+}
+
+void usbback_driver_backend_release_port
+    (struct usbback_driver_backend *backend, u32 port) {
+	trace1("port: %d", port);
+
+	ASSERT((port > 0)
+	       && (port <= USBBACK_DRIVER_PORT_COUNT)
+	    );
+
+	usbback_driver_port_release(&backend->port[port - 1]);
+
+	bus_rescan_devices(&usb_bus_type);
+}
+
+void usbback_driver_backend_shutdown(struct usbback_driver_backend *backend) {
+	trace();
+
+	(void)usbback_driver_backend_init_or_exit(backend, NULL, 1);
+
+	kfree(backend);
+}
+
+struct usbback_device *usbback_driver_backend_query_device
+    (struct usbback_driver_backend *backend) {
+	trace();
+
+	return backend->device;
+}
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,61 @@
+/*****************************************************************************/
+/* usbback_driver_backend is the representation in the driver of the         */
+/* back-end side of a single front-end to back-end connection.               */
+/* One of these objects is used by the usbback_driver to manage each         */
+/* usbback_device.                                                           */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_DRIVER_BACKEND_H
+#define USBBACK_DRIVER_BACKEND_H
+
+#include "asm-xen/xenidc.h"
+#include "usbback_device.h"
+
+struct usbback_driver_backend;
+
+extern struct usbback_driver_backend *usbback_driver_backend_allocate
+    (struct usbback_device *device);
+
+extern void usbback_driver_backend_endpoint_connect
+    (struct usbback_driver_backend *backend);
+
+extern void usbback_driver_backend_transaction_handler
+    (struct usbback_driver_backend *backend,
+     xenidc_endpoint_transaction * transaction);
+
+extern void usbback_driver_backend_message_handler
+    (struct usbback_driver_backend *backend, xenidc_endpoint_message * message);
+
+extern void usbback_driver_backend_endpoint_disconnect
+    (struct usbback_driver_backend *backend, xenidc_callback * callback);
+
+extern void usbback_driver_backend_claim_port
+    (struct usbback_driver_backend *backend, u32 port, char *path);
+
+extern void usbback_driver_backend_release_port
+    (struct usbback_driver_backend *backend, u32 port);
+
+extern void usbback_driver_backend_shutdown
+    (struct usbback_driver_backend *backend);
+
+extern struct usbback_device *usbback_driver_backend_query_device
+    (struct usbback_driver_backend *backend);
+
+#endif
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,1369 @@
+/*****************************************************************************/
+/* Object which manages a single USB device and handles all the IO           */
+/* transactions for that device by assigning usbback_driver_port_resources   */
+/* to process them.                                                          */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on arch/xen/drivers/usbif/backend/main.c, original copyright notice */
+/* follows...                                                                */
+/*****************************************************************************/
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ * 
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson
+ * Copyright (c) 2004 Intel Research Cambridge
+ * Copyright (c) 2004, 2005 Mark Williamson
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+#include <linux/rwsem.h>
+#include <asm-xen/xen-public/io/usbif.h>
+#include "usbback_assert.h"
+#include "usbback_driver_port.h"
+#include "usbback_trace.h"
+
+int usbback_driver_port_class_init(void)
+{
+	trace();
+
+	return usbback_driver_port_resource_class_init();
+}
+
+void usbback_driver_port_class_exit(void)
+{
+	trace();
+
+	usbback_driver_port_resource_class_exit();
+}
+
+extern struct usb_driver usbback_driver_usb_driver;
+
+static DECLARE_RWSEM(usbback_driver_port_list_sem);
+
+static LIST_HEAD(usbback_driver_port_list);
+
+typedef enum {
+	usbback_driver_port_stimulus_pc,	/* Port claim                           */
+	usbback_driver_port_stimulus_pr,	/* Port release                         */
+	usbback_driver_port_stimulus_up,	/* USB probe                            */
+	usbback_driver_port_stimulus_ud,	/* USB disconnect                       */
+	usbback_driver_port_stimulus_cn,	/* endpoint connect                     */
+	usbback_driver_port_stimulus_dn,	/* endpoint disconnect                  */
+	usbback_driver_port_stimulus_rq,	/* Transaction queued/resource freed    */
+	usbback_driver_port_stimulus_sd,	/* Shutdown                             */
+	usbback_driver_port_stimulus_ri,	/* test_io transactions idle (reent)    */
+	usbback_driver_port_stimulus_rr,	/* test_io transactions running (reent) */
+	usbback_driver_port_stimulus_rp,	/* release performed                    */
+} usbback_driver_port_stimulus;
+
+static void usbback_driver_port_handle_stimulus
+    (struct usbback_driver_port *port, usbback_driver_port_stimulus stimulus);
+
+static void usbback_driver_port_perform_release_1(void *data);
+
+static int usbback_driver_port_init_or_exit
+    (struct usbback_driver_port *port, int exit) {
+	trace();
+
+	{
+		int return_value = 0;
+
+		if (exit) {
+			goto EXIT;
+		}
+
+		INIT_LIST_HEAD(&port->link);
+
+		spin_lock_init(&port->lock);
+
+		port->state = usbback_driver_port_state_i;
+
+		INIT_LIST_HEAD(&port->transaction_list);
+		INIT_LIST_HEAD(&port->free_resource_list);
+
+		{
+			int i;
+
+			for (i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++) {
+				struct usbback_driver_port_resource *resource =
+				    &port->resources[i];
+
+				return_value =
+				    usbback_driver_port_resource_init(resource,
+								      port);
+
+				if (return_value != 0) {
+					goto EXIT_NO_RESOURCE;
+				}
+
+				list_add(&resource->link,
+					 &port->free_resource_list);
+			}
+		}
+
+		xenidc_work_init
+		    (&port->perform_release_1_work,
+		     usbback_driver_port_perform_release_1, port);
+
+		return 0;
+
+	      EXIT:
+
+	      EXIT_NO_RESOURCE:
+
+		while (!list_empty(&port->free_resource_list)) {
+			struct usbback_driver_port_resource *resource =
+			    list_entry(port->free_resource_list.next,
+				       struct usbback_driver_port_resource,
+				       link);
+
+			list_del_init(&resource->link);
+
+			usbback_driver_port_resource_exit(resource);
+		}
+
+		return return_value;
+	}
+}
+
+int usbback_driver_port_init
+    (struct usbback_driver_port *port, struct usbback_driver_backend *backend) {
+	trace();
+
+	memset(port, 0, sizeof(*port));
+
+	port->backend = backend;
+
+	return usbback_driver_port_init_or_exit(port, 0);
+}
+
+void usbback_driver_port_claim(struct usbback_driver_port *port, char *path) {
+	trace();
+
+	down_write(&usbback_driver_port_list_sem);
+
+	strncpy(port->path, path, sizeof(port->path));
+
+	list_add_tail(&port->link, &usbback_driver_port_list);
+
+	spin_lock_irq(&port->lock);
+
+	usbback_driver_port_handle_stimulus
+	    (port, usbback_driver_port_stimulus_pc);
+
+	spin_unlock_irq(&port->lock);
+
+	up_write(&usbback_driver_port_list_sem);
+}
+
+void usbback_driver_port_release(struct usbback_driver_port *port)
+{
+	trace();
+
+	down_write(&usbback_driver_port_list_sem);
+
+	list_del_init(&port->link);
+
+	up_write(&usbback_driver_port_list_sem);
+
+	port->release = 0;
+
+	spin_lock_irq(&port->lock);
+
+	usbback_driver_port_handle_stimulus
+	    (port, usbback_driver_port_stimulus_pr);
+
+	spin_unlock_irq(&port->lock);
+
+	xenidc_work_until(port->release);
+}
+
+int usbback_driver_port_probe_usb(struct usb_interface *intf)
+{
+	trace();
+
+	{
+		int return_value = 0;
+
+		struct usb_device *usbdev = interface_to_usbdev(intf);
+
+		struct usbback_driver_port *port = NULL;
+
+		printk
+		    (KERN_INFO "usbback: Probe for usb device %s\n",
+		     usbdev->devpath);
+
+		down_read(&usbback_driver_port_list_sem);
+
+		{
+			struct usbback_driver_port *cur = NULL;
+
+			list_for_each_entry(cur, &usbback_driver_port_list,
+					    link) {
+				printk(KERN_INFO
+				       "usbback: Testing against configured path %s:",
+				       cur->path);
+
+				if (strncmp
+				    (cur->path, usbdev->devpath,
+				     sizeof(cur->path))
+				    == 0) {
+					printk(" matches.\n");
+
+					port = cur;
+
+					break;
+				} else {
+					printk(" doesn't match.\n");
+				}
+			}
+		}
+
+		if (port == NULL) {
+			printk(KERN_INFO "usbback: No match found.\n");
+
+			return_value = -ENODEV;
+
+			goto EXIT_NO_PORT;
+		}
+
+		{
+			int i;
+
+			for (i = 0; i < usbdev->actconfig->desc.bNumInterfaces;
+			     i++) {
+				struct usb_interface *other_intf =
+				    usb_ifnum_to_if(usbdev, i);
+
+				if (other_intf != intf) {
+					if (usb_interface_claimed(other_intf)) {
+						printk
+						    (KERN_INFO
+						     "usbback: An interface of the matching device is "
+						     "already in use by another driver.\n");
+
+						return_value = -EBUSY;
+
+						goto EXIT_INTERFACE_ALREADY_CLAIMED;
+					}
+				}
+			}
+		}
+
+		{
+			int i;
+
+			for (i = 0; i < usbdev->actconfig->desc.bNumInterfaces;
+			     i++) {
+				struct usb_interface *other_intf =
+				    usb_ifnum_to_if(usbdev, i);
+
+				if (other_intf != intf) {
+					int error = usb_driver_claim_interface
+					    (&usbback_driver_usb_driver,
+					     other_intf, port);
+
+					/* We already checked all the interfaces were available. */
+
+					ASSERT(error == 0);
+				}
+			}
+		}
+
+		usbdev = usb_get_dev(usbdev);
+
+		usb_set_intfdata(intf, port);
+
+		spin_lock_irq(&port->lock);
+
+		port->usbdev_is_connected = 1;
+
+		port->usbdev = usbdev;
+
+		usbback_driver_port_handle_stimulus
+		    (port, usbback_driver_port_stimulus_up);
+
+		spin_unlock_irq(&port->lock);
+
+	      EXIT_INTERFACE_ALREADY_CLAIMED:
+
+	      EXIT_NO_PORT:
+
+		up_read(&usbback_driver_port_list_sem);
+
+		return return_value;
+	}
+}
+
+void usbback_driver_port_disconnect_usb(struct usb_interface *intf)
+{
+	trace();
+
+	{
+		struct usbback_driver_port *port = usb_get_intfdata(intf);
+
+		/* Protect against reentrant call when we release other interfaces. */
+
+		if (port != NULL) {
+			ASSERT(port->usbdev_is_connected);
+
+			spin_lock_irq(&port->lock);
+
+			port->usbdev_is_connected = 0;
+
+			port->enabled = 0;
+
+			port->usb_disconnect = 0;
+
+			usbback_driver_port_handle_stimulus
+			    (port, usbback_driver_port_stimulus_ud);
+
+			spin_unlock_irq(&port->lock);
+
+			xenidc_work_until(port->usb_disconnect);
+
+			{
+				struct usb_device *usbdev = port->usbdev;
+
+				{
+					int i;
+
+					for (i = 0;
+					     i <
+					     usbdev->actconfig->desc.
+					     bNumInterfaces; i++) {
+						struct usb_interface *other_intf
+						    =
+						    usb_ifnum_to_if(usbdev, i);
+
+						if (other_intf != intf) {
+							/* Protect against reentrant call when we        */
+							/* release other interfaces.                     */
+
+							usb_set_intfdata
+							    (other_intf, NULL);
+
+							usb_driver_release_interface
+							    (&usbback_driver_usb_driver,
+							     other_intf);
+						}
+					}
+				}
+
+				usb_set_intfdata(intf, NULL);
+
+				usb_put_dev(usbdev);
+			}
+		}
+	}
+}
+
+int usbback_driver_port_reset(struct usbback_driver_port *port)
+{
+	trace();
+
+	{
+		int status = -1;
+
+		spin_lock_irq(&port->lock);
+
+		port->guest_address = 0;
+
+		if (usbback_driver_port_usbdev_is_connected(port)) {
+			if (port->usbdev->speed == USB_SPEED_LOW) {
+				status = USBIF_RESET_RESULT_LOW_SPEED;
+			} else if (port->usbdev->speed == USB_SPEED_HIGH) {
+				status = USBIF_RESET_RESULT_HIGH_SPEED;
+			} else {
+				status = USBIF_RESET_RESULT_FULL_SPEED;
+			}
+
+			port->enabled = 1;
+		} else {
+			port->enabled = 0;
+		}
+
+		spin_unlock_irq(&port->lock);
+
+		return status;
+	}
+}
+
+void usbback_driver_port_set_guest_address
+    (struct usbback_driver_port *port, unsigned long guest_address) {
+	trace();
+
+	port->guest_address = guest_address;
+}
+
+int usbback_driver_port_match_guest_address
+    (struct usbback_driver_port *port, unsigned long guest_address) {
+	trace();
+
+	return (port->enabled && (guest_address == port->guest_address));
+}
+
+void usbback_driver_port_endpoint_connect(struct usbback_driver_port *port)
+{
+	trace();
+
+	{
+		unsigned long flags;
+
+		spin_lock_irqsave(&port->lock, flags);
+
+		usbback_driver_port_handle_stimulus
+		    (port, usbback_driver_port_stimulus_cn);
+
+		spin_unlock_irqrestore(&port->lock, flags);
+	}
+}
+
+void usbback_driver_port_handle_io
+    (struct usbback_driver_port *port,
+     xenidc_endpoint_transaction * transaction) {
+	trace();
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	{
+		unsigned long flags;
+
+		spin_lock_irqsave(&port->lock, flags);
+
+		list_add_tail
+		    (xenidc_endpoint_transaction_to_link(transaction),
+		     &port->transaction_list);
+
+		usbback_driver_port_handle_stimulus
+		    (port, usbback_driver_port_stimulus_rq);
+
+		spin_unlock_irqrestore(&port->lock, flags);
+	}
+}
+
+void usbback_driver_port_endpoint_disconnect
+    (struct usbback_driver_port *port, xenidc_callback * callback) {
+	trace();
+
+	{
+		unsigned long flags;
+
+		spin_lock_irqsave(&port->lock, flags);
+
+		port->endpoint_disconnect_callback = callback;
+
+		usbback_driver_port_handle_stimulus
+		    (port, usbback_driver_port_stimulus_dn);
+
+		spin_unlock_irqrestore(&port->lock, flags);
+	}
+}
+
+int usbback_driver_port_try_unlink
+    (struct usbback_driver_port *port, int unlink_id) {
+	trace();
+
+	{
+		int return_value = 0;
+
+		xenidc_endpoint_transaction *transaction = NULL;
+
+		unsigned long flags;
+
+		spin_lock_irqsave(&port->lock, flags);
+
+		{
+			xenidc_endpoint_transaction *temp;
+
+			list_for_each_entry
+			    (temp,
+			     &port->transaction_list,
+			     XENIDC_ENDPOINT_TRANSACTION_LINK) {
+				usbif_io_transaction_parameters_header header;
+
+				if (xenidc_local_buffer_reference_copy_out
+				    (xenidc_endpoint_transaction_to_parameters_lbr
+				     (transaction), &header, sizeof(header)
+				    )
+				    == sizeof(header)
+				    ) {
+					if (header.unlink_id == unlink_id) {
+						transaction = temp;
+
+						list_del_init
+						    (xenidc_endpoint_transaction_to_link
+						     (transaction)
+						    );
+
+						break;
+					}
+				}
+			}
+		}
+
+		if (transaction == NULL) {
+			int i;
+
+			for (i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++) {
+				struct usbback_driver_port_resource *resource =
+				    &port->resources[i];
+
+				if (usbback_driver_port_resource_try_unlink
+				    (resource, unlink_id)
+				    ) {
+					return_value = 1;
+
+					break;
+				}
+			}
+		}
+
+		spin_unlock_irqrestore(&port->lock, flags);
+
+		if (transaction) {
+			xenidc_endpoint_transaction_complete
+			    (transaction, USBIF_XENIDC_ERROR_UNLINKED);
+
+			return_value = 1;
+		}
+
+		return return_value;
+	}
+}
+
+void usbback_driver_port_shutdown(struct usbback_driver_port *port)
+{
+	trace();
+
+	down_write(&usbback_driver_port_list_sem);
+
+	list_del_init(&port->link);
+
+	up_write(&usbback_driver_port_list_sem);
+
+	port->shutdown = 0;
+
+	spin_lock_irq(&port->lock);
+
+	usbback_driver_port_handle_stimulus
+	    (port, usbback_driver_port_stimulus_sd);
+
+	spin_unlock_irq(&port->lock);
+
+	xenidc_work_until(port->shutdown);
+
+	flush_scheduled_work();
+
+	(void)usbback_driver_port_init_or_exit(port, 1);
+}
+
+static void usbback_driver_port_invalid_stimulus
+    (struct usbback_driver_port *port, usbback_driver_port_stimulus stimulus);
+
+static void usbback_driver_port_purge_io(struct usbback_driver_port *port);
+
+static void usbback_driver_port_test_io(struct usbback_driver_port *port);
+
+static void usbback_driver_port_kick_io(struct usbback_driver_port *port);
+
+static void usbback_driver_port_perform_release
+    (struct usbback_driver_port *port);
+
+static void usbback_driver_port_complete_release
+    (struct usbback_driver_port *port);
+
+static void usbback_driver_port_complete_usb_disconnect
+    (struct usbback_driver_port *port);
+
+static void usbback_driver_port_complete_endpoint_disconnect
+    (struct usbback_driver_port *port);
+
+static void usbback_driver_port_complete_shutdown
+    (struct usbback_driver_port *port);
+
+static void usbback_driver_port_handle_stimulus
+    (struct usbback_driver_port *port, usbback_driver_port_stimulus stimulus) {
+	trace3
+	    ("port %p in state %d received stimulus %d",
+	     port, port->state, stimulus);
+
+	switch (port->state) {
+	case usbback_driver_port_state_i:
+		/* No claimed port                     */
+		/* USB disconnected                    */
+		/* Endpoint disconnected               */
+		/* I/Os idle                           */
+		/* Not performing release              */
+		/* Release not outstanding             */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_pc:
+			port->state = usbback_driver_port_state_i_pc;
+			break;
+		case usbback_driver_port_stimulus_cn:
+			port->state = usbback_driver_port_state_i_cn;
+			break;
+		case usbback_driver_port_stimulus_sd:
+			port->state = usbback_driver_port_state_i_sd;
+			usbback_driver_port_complete_shutdown(port);
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc:
+		/* Claimed port                        */
+		/* USB disconnected                    */
+		/* Endpoint disconnected               */
+		/* I/Os idle                           */
+		/* Not performing release              */
+		/* Release not outstanding             */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_pr:
+			port->state = usbback_driver_port_state_i;
+			usbback_driver_port_complete_release(port);
+			break;
+		case usbback_driver_port_stimulus_up:
+			port->state = usbback_driver_port_state_i_pc_up;
+			break;
+		case usbback_driver_port_stimulus_cn:
+			port->state = usbback_driver_port_state_i_pc_cn;
+			break;
+		case usbback_driver_port_stimulus_sd:
+			port->state = usbback_driver_port_state_i_sd;
+			usbback_driver_port_complete_shutdown(port);
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_cn:
+		/* No claimed port                     */
+		/* USB disconnected                    */
+		/* Endpoint connected                  */
+		/* I/Os idle                           */
+		/* Not performing release              */
+		/* Release not outstanding             */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_pc:
+			port->state = usbback_driver_port_state_i_pc_cn;
+			break;
+		case usbback_driver_port_stimulus_dn:
+			port->state = usbback_driver_port_state_i;
+			usbback_driver_port_complete_endpoint_disconnect(port);
+			break;
+		case usbback_driver_port_stimulus_rq:
+			usbback_driver_port_purge_io(port);
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_sd:
+		/* Removed from port list.             */
+		/* USB disconnected                    */
+		/* Endpoint disconnected               */
+		/* I/Os idle                           */
+		/* Not performing release              */
+		/* Release not outstanding             */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		/* Shutdown                            */
+		switch (stimulus) {
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up:
+		/* Claimed port                        */
+		/* USB probed                          */
+		/* Endpoint disconnected               */
+		/* I/Os idle                           */
+		/* Not performing release              */
+		/* Release not outstanding             */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_pr:
+			port->state = usbback_driver_port_state_i_pc_up_pr;
+			usbback_driver_port_perform_release(port);
+			break;
+		case usbback_driver_port_stimulus_ud:
+			port->state = usbback_driver_port_state_i_pc;
+			usbback_driver_port_complete_usb_disconnect(port);
+			break;
+		case usbback_driver_port_stimulus_cn:
+			port->state = usbback_driver_port_state_i_pc_up_cn;
+			break;
+		case usbback_driver_port_stimulus_sd:
+			port->state = usbback_driver_port_state_i_pc_up_sd;
+			usbback_driver_port_perform_release(port);
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_cn:
+		/* Claimed port                        */
+		/* USB disconnected                    */
+		/* Endpoint connected                  */
+		/* I/Os idle                           */
+		/* Not performing release              */
+		/* Release not outstanding             */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_pr:
+			port->state = usbback_driver_port_state_i_cn;
+			usbback_driver_port_complete_release(port);
+			break;
+		case usbback_driver_port_stimulus_up:
+			port->state = usbback_driver_port_state_i_pc_up_cn;
+			break;
+		case usbback_driver_port_stimulus_dn:
+			port->state = usbback_driver_port_state_i_pc;
+			usbback_driver_port_complete_endpoint_disconnect(port);
+			break;
+		case usbback_driver_port_stimulus_rq:
+			usbback_driver_port_purge_io(port);
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_pr:
+		/* Releasing port.                     */
+		/* USB probed                          */
+		/* Endpoint disconnected               */
+		/* I/Os idle                           */
+		/* Performing release                  */
+		/* Release outstanding                 */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_ud:
+			port->state = usbback_driver_port_state_i_pc_up_pr_ud;
+			usbback_driver_port_complete_usb_disconnect(port);
+			break;
+		case usbback_driver_port_stimulus_cn:
+			port->state = usbback_driver_port_state_i_pc_up_pr_cn;
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_cn:
+		/* Claimed port                        */
+		/* USB probed                          */
+		/* Endpoint connected                  */
+		/* Maybe I/Os in progress              */
+		/* Not performing release              */
+		/* Release not outstanding             */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_pr:
+			port->state = usbback_driver_port_state_i_pc_up_cn_pr;
+			usbback_driver_port_purge_io(port);
+			usbback_driver_port_test_io(port);
+			break;
+		case usbback_driver_port_stimulus_ud:
+			port->state = usbback_driver_port_state_i_pc_up_cn_ud;
+			usbback_driver_port_purge_io(port);
+			usbback_driver_port_test_io(port);
+			break;
+		case usbback_driver_port_stimulus_dn:
+			port->state = usbback_driver_port_state_i_pc_up_cn_dn;
+			usbback_driver_port_purge_io(port);
+			usbback_driver_port_test_io(port);
+			break;
+		case usbback_driver_port_stimulus_rq:
+			usbback_driver_port_kick_io(port);
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_sd:
+		/* Releasing port                      */
+		/* USB probed                          */
+		/* Endpoint disconnected               */
+		/* I/Os idle                           */
+		/* Performing release                  */
+		/* Release not outstanding             */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown outstanding                */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_ud:
+			port->state = usbback_driver_port_state_i_pc_up_sd_ud;
+			usbback_driver_port_complete_usb_disconnect(port);
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_pr_ud:
+		/* Releasing port.                     */
+		/* USB disconnected                    */
+		/* Endpoint disconnected               */
+		/* I/Os idle                           */
+		/* Performing release                  */
+		/* Release outstanding                 */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_cn:
+			port->state =
+			    usbback_driver_port_state_i_pc_up_pr_ud_cn;
+			break;
+		case usbback_driver_port_stimulus_rp:
+			port->state = usbback_driver_port_state_i;
+			usbback_driver_port_complete_release(port);
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_pr_cn:
+		/* Releasing port.                     */
+		/* USB probed                          */
+		/* Endpoint connected                  */
+		/* I/Os idle                           */
+		/* Performing release                  */
+		/* Release outstanding                 */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_ud:
+			port->state =
+			    usbback_driver_port_state_i_pc_up_pr_ud_cn;
+			usbback_driver_port_complete_usb_disconnect(port);
+			break;
+		case usbback_driver_port_stimulus_dn:
+			port->state = usbback_driver_port_state_i_pc_up_pr;
+			usbback_driver_port_complete_endpoint_disconnect(port);
+			break;
+		case usbback_driver_port_stimulus_rq:
+			usbback_driver_port_purge_io(port);
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_cn_pr:
+		/* Claimed port                        */
+		/* USB probed                          */
+		/* Endpoint connected                  */
+		/* I/Os in progress/testing I/Os       */
+		/* Not performing release              */
+		/* Release outstanding                 */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_ud:
+			port->state =
+			    usbback_driver_port_state_i_pc_up_cn_pr_ud;
+			break;
+		case usbback_driver_port_stimulus_dn:
+			port->state =
+			    usbback_driver_port_state_i_pc_up_cn_pr_dn;
+			break;
+		case usbback_driver_port_stimulus_rq:
+			usbback_driver_port_purge_io(port);
+			usbback_driver_port_test_io(port);
+			break;
+		case usbback_driver_port_stimulus_ri:
+			port->state = usbback_driver_port_state_i_pc_up_pr_cn;
+			usbback_driver_port_perform_release(port);
+			break;
+		case usbback_driver_port_stimulus_rr:
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_cn_ud:
+		/* Claimed port                        */
+		/* USB disconnecting                   */
+		/* Endpoint connected                  */
+		/* I/Os in progress/testing I/Os       */
+		/* Not performing release              */
+		/* Release not outstanding             */
+		/* USB disconnect outstanding          */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_pr:
+			port->state =
+			    usbback_driver_port_state_i_pc_up_cn_pr_ud;
+			break;
+		case usbback_driver_port_stimulus_dn:
+			port->state =
+			    usbback_driver_port_state_i_pc_up_cn_ud_dn;
+			break;
+		case usbback_driver_port_stimulus_rq:
+			usbback_driver_port_purge_io(port);
+			usbback_driver_port_test_io(port);
+			break;
+		case usbback_driver_port_stimulus_ri:
+			port->state = usbback_driver_port_state_i_pc_cn;
+			usbback_driver_port_complete_usb_disconnect(port);
+			break;
+		case usbback_driver_port_stimulus_rr:
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_cn_dn:
+		/* Claimed port                        */
+		/* USB probed                          */
+		/* Endpoint disconnecting              */
+		/* I/Os in progress/testing I/Os       */
+		/* Not performing release              */
+		/* Release not outstanding             */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect outstanding     */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_pr:
+			port->state =
+			    usbback_driver_port_state_i_pc_up_cn_pr_dn;
+			break;
+		case usbback_driver_port_stimulus_ud:
+			port->state =
+			    usbback_driver_port_state_i_pc_up_cn_ud_dn;
+			break;
+		case usbback_driver_port_stimulus_rq:
+			usbback_driver_port_purge_io(port);
+			usbback_driver_port_test_io(port);
+			break;
+		case usbback_driver_port_stimulus_ri:
+			port->state = usbback_driver_port_state_i_pc_up;
+			usbback_driver_port_complete_endpoint_disconnect(port);
+			break;
+		case usbback_driver_port_stimulus_rr:
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_sd_ud:
+		/* Releasing port                      */
+		/* USB disconnected                    */
+		/* Endpoint disconnected               */
+		/* I/Os idle                           */
+		/* Performing release                  */
+		/* Release not outstanding             */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown outstanding                */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_rp:
+			port->state = usbback_driver_port_state_i_sd;
+			usbback_driver_port_complete_shutdown(port);
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_pr_ud_cn:
+		/* Releasing port.                     */
+		/* USB disconnected                    */
+		/* Endpoint connected                  */
+		/* I/Os idle                           */
+		/* Performing release                  */
+		/* Release outstanding                 */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_dn:
+			port->state = usbback_driver_port_state_i_pc_up_pr_ud;
+			usbback_driver_port_complete_endpoint_disconnect(port);
+			break;
+		case usbback_driver_port_stimulus_rq:
+			usbback_driver_port_purge_io(port);
+			break;
+		case usbback_driver_port_stimulus_rp:
+			port->state = usbback_driver_port_state_i_cn;
+			usbback_driver_port_complete_release(port);
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_cn_pr_ud:
+		/* Claimed port                        */
+		/* USB disconnecting                   */
+		/* Endpoint connected                  */
+		/* I/Os in progress/testing I/Os       */
+		/* Not performing release              */
+		/* Release outstanding                 */
+		/* USB disconnect outstanding          */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_dn:
+			port->state =
+			    usbback_driver_port_state_i_pc_up_cn_pr_ud_dn;
+			break;
+		case usbback_driver_port_stimulus_rq:
+			usbback_driver_port_purge_io(port);
+			usbback_driver_port_test_io(port);
+			break;
+		case usbback_driver_port_stimulus_ri:
+			port->state = usbback_driver_port_state_i_cn;
+			usbback_driver_port_complete_usb_disconnect(port);
+			usbback_driver_port_complete_release(port);
+			break;
+		case usbback_driver_port_stimulus_rr:
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_cn_pr_dn:
+		/* Claimed port                        */
+		/* USB probed                          */
+		/* Endpoint disconnecting              */
+		/* I/Os in progress/testing I/Os       */
+		/* Not performing release              */
+		/* Release outstanding                 */
+		/* USB disconnect not outstanding      */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_ud:
+			port->state =
+			    usbback_driver_port_state_i_pc_up_cn_pr_ud_dn;
+			break;
+		case usbback_driver_port_stimulus_rq:
+			usbback_driver_port_purge_io(port);
+			usbback_driver_port_test_io(port);
+			break;
+		case usbback_driver_port_stimulus_ri:
+			port->state = usbback_driver_port_state_i_pc_up_pr;
+			usbback_driver_port_perform_release(port);
+			usbback_driver_port_complete_endpoint_disconnect(port);
+			break;
+		case usbback_driver_port_stimulus_rr:
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_cn_ud_dn:
+		/* Claimed port                        */
+		/* USB disconnecting                   */
+		/* Endpoint disconnecting              */
+		/* I/Os in progress/testing I/Os       */
+		/* Not performing release              */
+		/* Release not outstanding             */
+		/* USB disconnect outstanding          */
+		/* Endpoint disconnect not outstanding */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_pr:
+			port->state =
+			    usbback_driver_port_state_i_pc_up_cn_pr_ud_dn;
+			break;
+		case usbback_driver_port_stimulus_rq:
+			usbback_driver_port_purge_io(port);
+			usbback_driver_port_test_io(port);
+			break;
+		case usbback_driver_port_stimulus_ri:
+			port->state = usbback_driver_port_state_i_pc;
+			usbback_driver_port_complete_usb_disconnect(port);
+			usbback_driver_port_complete_endpoint_disconnect(port);
+			break;
+		case usbback_driver_port_stimulus_rr:
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_state_i_pc_up_cn_pr_ud_dn:
+		/* Claimed port                        */
+		/* USB disconnecting                   */
+		/* Endpoint disconnecting              */
+		/* I/Os in progress/testing I/Os       */
+		/* Not performing release              */
+		/* Release outstanding                 */
+		/* USB disconnect outstanding          */
+		/* Endpoint disconnect outstanding     */
+		/* Shutdown not outstanding            */
+		switch (stimulus) {
+		case usbback_driver_port_stimulus_rq:
+			usbback_driver_port_purge_io(port);
+			usbback_driver_port_test_io(port);
+			break;
+		case usbback_driver_port_stimulus_ri:
+			port->state = usbback_driver_port_state_i;
+			usbback_driver_port_complete_usb_disconnect(port);
+			usbback_driver_port_complete_endpoint_disconnect(port);
+			usbback_driver_port_complete_release(port);
+			break;
+		case usbback_driver_port_stimulus_rr:
+			break;
+		default:
+			usbback_driver_port_invalid_stimulus(port, stimulus);
+			break;
+		}
+		break;
+	default:
+		usbback_driver_port_invalid_stimulus(port, stimulus);
+		break;
+	}
+}
+
+static void usbback_driver_port_invalid_stimulus
+    (struct usbback_driver_port *port, usbback_driver_port_stimulus stimulus) {
+	trace();
+
+	printk
+	    (KERN_ERR "usbback: port %p in state %d"
+	     "received invalid stimulus %d", port, port->state, stimulus);
+}
+
+static void usbback_driver_port_purge_io(struct usbback_driver_port *port)
+{
+	trace();
+
+	while (!list_empty(&port->transaction_list)) {
+		xenidc_endpoint_transaction *transaction = list_entry
+		    (port->transaction_list.next,
+		     xenidc_endpoint_transaction,
+		     XENIDC_ENDPOINT_TRANSACTION_LINK);
+
+		list_del_init(xenidc_endpoint_transaction_to_link(transaction));
+
+		xenidc_endpoint_transaction_complete
+		    (transaction, USBIF_XENIDC_ERROR_UNLINKED);
+	}
+
+	{
+		int i;
+
+		for (i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++) {
+			struct usbback_driver_port_resource *resource =
+			    &port->resources[i];
+
+			usbback_driver_port_resource_flush_transaction
+			    (resource);
+		}
+	}
+}
+
+static void usbback_driver_port_test_io(struct usbback_driver_port *port)
+{
+	trace();
+
+	if (port->current_transactions == 0) {
+		usbback_driver_port_handle_stimulus
+		    (port, usbback_driver_port_stimulus_ri);
+	} else {
+		usbback_driver_port_handle_stimulus
+		    (port, usbback_driver_port_stimulus_rr);
+	}
+}
+
+static void usbback_driver_port_kick_io(struct usbback_driver_port *port)
+{
+	trace();
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	while ((!list_empty(&port->transaction_list))
+	       && (!list_empty(&port->free_resource_list))
+	    ) {
+		xenidc_endpoint_transaction *transaction = list_entry
+		    (port->transaction_list.next,
+		     xenidc_endpoint_transaction,
+		     XENIDC_ENDPOINT_TRANSACTION_LINK);
+
+		struct usbback_driver_port_resource *resource = list_entry
+		    (port->free_resource_list.next,
+		     struct usbback_driver_port_resource,
+		     link);
+
+		list_del_init(xenidc_endpoint_transaction_to_link(transaction));
+
+		list_del_init(&resource->link);
+
+		port->current_transactions++;
+
+		usbback_driver_port_resource_start_io(resource, transaction);
+	}
+}
+
+void usbback_driver_port_resource_completed_io
+    (struct usbback_driver_port *port,
+     struct usbback_driver_port_resource *resource) {
+	trace();
+
+	{
+		unsigned long flags;
+
+		spin_lock_irqsave(&port->lock, flags);
+
+		list_add(&resource->link, &port->free_resource_list);
+
+		port->current_transactions--;
+
+		usbback_driver_port_handle_stimulus
+		    (port, usbback_driver_port_stimulus_rq);
+
+		spin_unlock_irqrestore(&port->lock, flags);
+	}
+}
+
+static void usbback_driver_port_perform_release
+    (struct usbback_driver_port *port) {
+	trace();
+
+	usb_get_dev(port->usbdev);
+
+	{
+		int scheduled =
+		    xenidc_work_schedule(&port->perform_release_1_work);
+
+		ASSERT(scheduled);
+	}
+}
+
+static void usbback_driver_port_perform_release_1(void *data)
+{
+	trace();
+
+	{
+		struct usbback_driver_port *port =
+		    (struct usbback_driver_port *)data;
+
+		usb_lock_device(port->usbdev);
+
+		down_write(&usb_bus_type.subsys.rwsem);
+
+		if (port->usbdev_is_connected) {
+			usb_driver_release_interface
+			    (&usbback_driver_usb_driver,
+			     usb_ifnum_to_if(port->usbdev, 0)
+			    );
+		}
+
+		up_write(&usb_bus_type.subsys.rwsem);
+
+		usb_unlock_device(port->usbdev);
+
+		usb_put_dev(port->usbdev);
+
+		spin_lock_irq(&port->lock);
+
+		usbback_driver_port_handle_stimulus
+		    (port, usbback_driver_port_stimulus_rp);
+
+		spin_unlock_irq(&port->lock);
+	}
+}
+
+static void usbback_driver_port_complete_release
+    (struct usbback_driver_port *port) {
+	trace();
+
+	port->release = 1;
+
+	xenidc_work_wake_up();
+}
+
+static void usbback_driver_port_complete_usb_disconnect
+    (struct usbback_driver_port *port) {
+	trace();
+
+	port->usb_disconnect = 1;
+
+	xenidc_work_wake_up();
+}
+
+static void usbback_driver_port_complete_endpoint_disconnect
+    (struct usbback_driver_port *port) {
+	trace();
+
+	xenidc_callback_success(port->endpoint_disconnect_callback);
+}
+
+static void usbback_driver_port_complete_shutdown
+    (struct usbback_driver_port *port) {
+	trace();
+
+	port->shutdown = 1;
+
+	xenidc_work_wake_up();
+}
+
+struct usbback_driver_backend *usbback_driver_port_query_backend
+    (struct usbback_driver_port *port) {
+	trace();
+
+	return port->backend;
+}
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,144 @@
+/*****************************************************************************/
+/* Object which manages a single USB device and handles all the              */
+/* io transactions for that device by assigning                              */
+/* usbback_driver_port_resources to process them.                            */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_DRIVER_PORT_H
+#define USBBACK_DRIVER_PORT_H
+
+#include <asm-xen/xenidc.h>
+#include <linux/usb.h>
+#include "usbback_assert.h"
+#include "usbback_driver_backend.h"
+#include "usbback_driver_port_resource.h"
+#include "usbback_trace.h"
+
+int usbback_driver_port_class_init(void);
+
+void usbback_driver_port_class_exit(void);
+
+int usbback_driver_port_init
+    (struct usbback_driver_port *port, struct usbback_driver_backend *backend);
+
+void usbback_driver_port_claim(struct usbback_driver_port *port, char *path);
+
+void usbback_driver_port_release(struct usbback_driver_port *port);
+
+int usbback_driver_port_probe_usb(struct usb_interface *intf);
+
+void usbback_driver_port_disconnect_usb(struct usb_interface *intf);
+
+/* On success, usbback_driver_port_reset returns */
+/* USBIF_RESET_RESULT_FULL/LOW/HIGH_SPEED */
+
+int usbback_driver_port_reset(struct usbback_driver_port *port);
+
+void usbback_driver_port_set_guest_address
+    (struct usbback_driver_port *port, unsigned long guest_address);
+
+int usbback_driver_port_match_guest_address
+    (struct usbback_driver_port *port, unsigned long guest_address);
+
+void usbback_driver_port_endpoint_connect(struct usbback_driver_port *port);
+
+void usbback_driver_port_handle_io
+    (struct usbback_driver_port *port,
+     xenidc_endpoint_transaction * transaction);
+
+void usbback_driver_port_endpoint_disconnect
+    (struct usbback_driver_port *port, xenidc_callback * callback);
+
+int usbback_driver_port_try_unlink
+    (struct usbback_driver_port *port, int unlink_id);
+
+void usbback_driver_port_shutdown(struct usbback_driver_port *port);
+
+typedef enum {
+	usbback_driver_port_state_i,
+	usbback_driver_port_state_i_pc,
+	usbback_driver_port_state_i_cn,
+	usbback_driver_port_state_i_sd,
+	usbback_driver_port_state_i_pc_up,
+	usbback_driver_port_state_i_pc_cn,
+	usbback_driver_port_state_i_pc_up_pr,
+	usbback_driver_port_state_i_pc_up_cn,
+	usbback_driver_port_state_i_pc_up_sd,
+	usbback_driver_port_state_i_pc_up_pr_ud,
+	usbback_driver_port_state_i_pc_up_pr_cn,
+	usbback_driver_port_state_i_pc_up_cn_pr,
+	usbback_driver_port_state_i_pc_up_cn_ud,
+	usbback_driver_port_state_i_pc_up_cn_dn,
+	usbback_driver_port_state_i_pc_up_sd_ud,
+	usbback_driver_port_state_i_pc_up_pr_ud_cn,
+	usbback_driver_port_state_i_pc_up_cn_pr_ud,
+	usbback_driver_port_state_i_pc_up_cn_pr_dn,
+	usbback_driver_port_state_i_pc_up_cn_ud_dn,
+	usbback_driver_port_state_i_pc_up_cn_pr_ud_dn
+} usbback_driver_port_state;
+
+#define USBBACK_DRIVER_PORT_RESOURCE_COUNT 4
+
+struct usbback_driver_port {
+	struct usbback_driver_backend *backend;
+	struct list_head link;
+	char path[16];		/* FIXME: Magic number. */
+	struct usb_device *usbdev;
+	spinlock_t lock;
+	usbback_driver_port_state state;
+	int usbdev_is_connected;
+	int enabled;
+	unsigned long guest_address;
+	struct list_head transaction_list;
+	struct list_head free_resource_list;
+	unsigned long current_transactions;
+	struct usbback_driver_port_resource resources
+	    [USBBACK_DRIVER_PORT_RESOURCE_COUNT];
+	xenidc_work perform_release_1_work;
+	xenidc_callback *endpoint_disconnect_callback;
+	int release;
+	int usb_disconnect;
+	int shutdown;
+};
+
+static inline struct usb_device *usbback_driver_port_query_usbdev
+    (struct usbback_driver_port *port) {
+	trace();
+
+	ASSERT(port->usbdev != NULL);
+
+	return port->usbdev;
+}
+
+static inline int usbback_driver_port_usbdev_is_connected
+    (struct usbback_driver_port *port) {
+	/*    trace(); */
+
+	return port->usbdev_is_connected;
+}
+
+void usbback_driver_port_resource_completed_io
+    (struct usbback_driver_port *port,
+     struct usbback_driver_port_resource *resource);
+
+struct usbback_driver_backend *usbback_driver_port_query_backend
+    (struct usbback_driver_port *port);
+
+#endif
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,1156 @@
+/*****************************************************************************/
+/* Resource which processes a usbback_transaction by translating it into  */
+/* an URB and submitting it to the USB stack.                                */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on arch/xen/drivers/usbif/backend/main.c, original copyright notice */
+/* follows...                                                                */
+/*****************************************************************************/
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ * 
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson
+ * Copyright (c) 2004 Intel Research Cambridge
+ * Copyright (c) 2004, 2005 Mark Williamson
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+#include <asm-xen/xen-public/io/usbif.h>
+#include "usbback_assert.h"
+#include "usbback_driver_port.h"
+#include "usbback_driver_port_resource.h"
+#include "usbback_trace.h"
+
+static XENIDC_CALLBACK_SERIALISER
+    (usbback_driver_port_resource_submit_urb_serialiser);
+
+static xenidc_rbr_mapper_pool *usbback_driver_port_resource_rbr_mapper_pool;
+
+int usbback_driver_port_resource_class_init(void)
+{
+	trace();
+
+	{
+		xenidc_buffer_resource_list sum =
+		    xenidc_buffer_resource_list_null();
+
+		xenidc_buffer_resource_list bulk_list =
+		    xenidc_grant_table_calculate_buffer_resource_list
+		    (USBIF_MAX_BULK_BYTE_COUNT, USBIF_BULK_BYTE_ALIGNMENT);
+
+		xenidc_buffer_resource_list schedule_list =
+		    xenidc_grant_table_calculate_buffer_resource_list
+		    (USBIF_MAX_SCHEDULE_BYTE_COUNT,
+		     USBIF_SCHEDULE_BYTE_ALIGNMENT);
+
+		xenidc_buffer_resource_list_plus_equals(&sum, &bulk_list);
+		xenidc_buffer_resource_list_plus_equals(&sum, &schedule_list);
+
+		usbback_driver_port_resource_rbr_mapper_pool =
+		    xenidc_allocate_rbr_mapper_pool(sum);
+	}
+
+	return (usbback_driver_port_resource_rbr_mapper_pool != NULL) ?
+	    0 : -ENOMEM;
+}
+
+void usbback_driver_port_resource_class_exit(void)
+{
+	trace();
+
+	xenidc_free_rbr_mapper_pool
+	    (usbback_driver_port_resource_rbr_mapper_pool);
+}
+
+typedef enum {
+	usbback_driver_port_resource_stimulus_st,	/* Start IO          */
+	usbback_driver_port_resource_stimulus_tu,	/* Try unlink        */
+	usbback_driver_port_resource_stimulus_ms,	/* Map success       */
+	usbback_driver_port_resource_stimulus_mf,	/* Map failure       */
+	usbback_driver_port_resource_stimulus_us,	/* URB submitted     */
+	usbback_driver_port_resource_stimulus_un,	/* URB not submitted */
+	usbback_driver_port_resource_stimulus_uc,	/* URB completed     */
+	usbback_driver_port_resource_stimulus_ul,	/* Unlink completed  */
+} usbback_driver_port_resource_stimulus;
+
+static void usbback_driver_port_resource_handle_stimulus
+    (struct usbback_driver_port_resource *resource,
+     usbback_driver_port_resource_stimulus stimulus);
+
+static void usbback_driver_port_resource_submit_urb_1
+    (xenidc_callback * callback);
+
+static void usbback_driver_port_resource_unlink_urb_1(void *data);
+
+static void usbback_driver_port_resource_map_callback
+    (xenidc_callback * callback);
+
+static void usbback_driver_port_resource_unmap_callback
+    (xenidc_callback * callback);
+
+int usbback_driver_port_resource_init
+    (struct usbback_driver_port_resource *resource,
+     struct usbback_driver_port *port) {
+	trace();
+
+	resource->port = port;
+
+	INIT_LIST_HEAD(&resource->link);
+
+	spin_lock_init(&resource->lock);
+
+	resource->state = usbback_driver_port_resource_state_i;
+
+	resource->transaction = NULL;
+
+	xenidc_map_rbr_request_element_init(&resource->request_element[0]);
+	xenidc_map_rbr_request_element_init(&resource->request_element[1]);
+
+	xenidc_reserve_and_map_rbr_request_init
+	    (&resource->reserve_and_map_rbr_request,
+	     usbback_driver_port_resource_map_callback,
+	     usbback_driver_port_resource_unmap_callback);
+
+	resource->rbrs_mapped = 0;
+
+	xenidc_callback_init
+	    (&resource->submit_urb_1_callback,
+	     usbback_driver_port_resource_submit_urb_1);
+
+	xenidc_work_init
+	    (&resource->unlink_urb_1_work,
+	     usbback_driver_port_resource_unlink_urb_1, resource);
+
+	resource->urb =
+	    usb_alloc_urb(USBIF_MAX_SCHEDULE_PACKET_COUNT, GFP_KERNEL);
+
+	return (resource->urb != NULL) ? 0 : -ENOMEM;
+}
+
+void usbback_driver_port_resource_exit
+    (struct usbback_driver_port_resource *resource) {
+	trace();
+
+	usb_free_urb(resource->urb);
+}
+
+void usbback_driver_port_resource_start_io
+    (struct usbback_driver_port_resource *resource,
+     xenidc_endpoint_transaction * transaction) {
+	trace();
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	{
+		unsigned long flags;
+
+		spin_lock_irqsave(&resource->lock, flags);
+
+		resource->transaction_error = XENIDC_ERROR_SUCCESS;
+		resource->transaction_status_length = 0;
+
+		resource->transaction = transaction;
+
+		usbback_driver_port_resource_handle_stimulus
+		    (resource, usbback_driver_port_resource_stimulus_st);
+
+		spin_unlock_irqrestore(&resource->lock, flags);
+	}
+}
+
+int usbback_driver_port_resource_try_unlink
+    (struct usbback_driver_port_resource *resource, int unlink_id) {
+	trace();
+
+	{
+		int return_value = 0;
+
+		unsigned long flags;
+
+		spin_lock_irqsave(&resource->lock, flags);
+
+		if (resource->transaction != NULL) {
+			usbif_io_transaction_parameters_header header;
+
+			if ((xenidc_local_buffer_reference_copy_out
+			     (xenidc_endpoint_transaction_to_parameters_lbr
+			      (resource->transaction), &header, sizeof(header)
+			     )
+			     == sizeof(header)
+			    )
+			    && (header.unlink_id == unlink_id)
+			    ) {
+				usbback_driver_port_resource_handle_stimulus
+				    (resource,
+				     usbback_driver_port_resource_stimulus_tu);
+
+				return_value = 1;
+			}
+		}
+
+		spin_unlock_irqrestore(&resource->lock, flags);
+
+		return return_value;
+	}
+}
+
+void usbback_driver_port_resource_flush_transaction
+    (struct usbback_driver_port_resource *resource) {
+	trace();
+
+	{
+		unsigned long flags;
+
+		spin_lock_irqsave(&resource->lock, flags);
+
+		if (resource->transaction != NULL) {
+			usbback_driver_port_resource_handle_stimulus
+			    (resource,
+			     usbback_driver_port_resource_stimulus_tu);
+		}
+
+		spin_unlock_irqrestore(&resource->lock, flags);
+	}
+}
+
+static void usbback_driver_port_resource_invalid_stimulus
+    (struct usbback_driver_port_resource *resource,
+     usbback_driver_port_resource_stimulus stimulus);
+
+static void usbback_driver_port_resource_map_buffer
+    (struct usbback_driver_port_resource *resource);
+
+static void usbback_driver_port_resource_abort_map
+    (struct usbback_driver_port_resource *resource);
+
+static void usbback_driver_port_resource_submit_urb
+    (struct usbback_driver_port_resource *resource);
+
+static void usbback_driver_port_resource_unlink_urb
+    (struct usbback_driver_port_resource *resource);
+
+static void usbback_driver_port_resource_set_unlinked_error
+    (struct usbback_driver_port_resource *resource);
+
+static void usbback_driver_port_resource_complete
+    (struct usbback_driver_port_resource *resource);
+
+static void usbback_driver_port_resource_handle_stimulus
+    (struct usbback_driver_port_resource *resource,
+     usbback_driver_port_resource_stimulus stimulus) {
+	trace3
+	    ("port resource %p in state %d received stimulus %d",
+	     resource, resource->state, stimulus);
+
+	switch (resource->state) {
+	case usbback_driver_port_resource_state_i:
+		/* Idle */
+		switch (stimulus) {
+		case usbback_driver_port_resource_stimulus_st:
+			resource->state =
+			    usbback_driver_port_resource_state_i_st;
+			usbback_driver_port_resource_map_buffer(resource);
+			break;
+		default:
+			usbback_driver_port_resource_invalid_stimulus
+			    (resource, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_resource_state_i_st:
+		/* Handling request       */
+		/* map_buffer outstanding */
+		switch (stimulus) {
+		case usbback_driver_port_resource_stimulus_tu:
+			resource->state =
+			    usbback_driver_port_resource_state_i_st_tu;
+			usbback_driver_port_resource_abort_map(resource);
+			break;
+		case usbback_driver_port_resource_stimulus_ms:
+			resource->state =
+			    usbback_driver_port_resource_state_i_st_ms;
+			usbback_driver_port_resource_submit_urb(resource);
+			break;
+		case usbback_driver_port_resource_stimulus_mf:
+			resource->state = usbback_driver_port_resource_state_i;
+			usbback_driver_port_resource_complete(resource);
+			break;
+		default:
+			usbback_driver_port_resource_invalid_stimulus
+			    (resource, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_resource_state_i_st_tu:
+		/* Handling request       */
+		/* map_buffer outstanding */
+		/* unlinking              */
+		switch (stimulus) {
+		case usbback_driver_port_resource_stimulus_tu:
+			break;
+		case usbback_driver_port_resource_stimulus_ms:
+			resource->state = usbback_driver_port_resource_state_i;
+			usbback_driver_port_resource_set_unlinked_error
+			    (resource);
+			usbback_driver_port_resource_complete(resource);
+			break;
+		case usbback_driver_port_resource_stimulus_mf:
+			resource->state = usbback_driver_port_resource_state_i;
+			usbback_driver_port_resource_complete(resource);
+			break;
+		default:
+			usbback_driver_port_resource_invalid_stimulus
+			    (resource, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_resource_state_i_st_ms:
+		/* Handling request       */
+		/* submit_urb outstanding */
+		switch (stimulus) {
+		case usbback_driver_port_resource_stimulus_tu:
+			resource->state =
+			    usbback_driver_port_resource_state_i_st_ms_tu;
+			break;
+		case usbback_driver_port_resource_stimulus_us:
+			resource->state =
+			    usbback_driver_port_resource_state_i_st_ms_us;
+			break;
+		case usbback_driver_port_resource_stimulus_un:
+			resource->state = usbback_driver_port_resource_state_i;
+			usbback_driver_port_resource_complete(resource);
+			break;
+		case usbback_driver_port_resource_stimulus_uc:
+			resource->state =
+			    usbback_driver_port_resource_state_i_st_ms_uc;
+			break;
+		default:
+			usbback_driver_port_resource_invalid_stimulus
+			    (resource, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_resource_state_i_st_ms_tu:
+		/* Handling request       */
+		/* submit_urb outstanding */
+		/* unlinking              */
+		switch (stimulus) {
+		case usbback_driver_port_resource_stimulus_tu:
+			break;
+		case usbback_driver_port_resource_stimulus_us:
+			resource->state =
+			    usbback_driver_port_resource_state_i_st_ms_tu_us;
+			usbback_driver_port_resource_unlink_urb(resource);
+			break;
+		case usbback_driver_port_resource_stimulus_un:
+			resource->state = usbback_driver_port_resource_state_i;
+			usbback_driver_port_resource_complete(resource);
+			break;
+		case usbback_driver_port_resource_stimulus_uc:
+			resource->state =
+			    usbback_driver_port_resource_state_i_st_ms_uc;
+			break;
+		default:
+			usbback_driver_port_resource_invalid_stimulus
+			    (resource, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_resource_state_i_st_ms_us:
+		/* Handling request */
+		/* URB submitted    */
+		switch (stimulus) {
+		case usbback_driver_port_resource_stimulus_tu:
+			resource->state =
+			    usbback_driver_port_resource_state_i_st_ms_tu_us;
+			usbback_driver_port_resource_unlink_urb(resource);
+			break;
+		case usbback_driver_port_resource_stimulus_uc:
+			resource->state = usbback_driver_port_resource_state_i;
+			usbback_driver_port_resource_complete(resource);
+			break;
+		default:
+			usbback_driver_port_resource_invalid_stimulus
+			    (resource, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_resource_state_i_st_ms_uc:
+		/* Handling request       */
+		/* submit_urb outstanding */
+		/* URB completed          */
+		switch (stimulus) {
+		case usbback_driver_port_resource_stimulus_tu:
+			break;
+		case usbback_driver_port_resource_stimulus_us:
+			resource->state = usbback_driver_port_resource_state_i;
+			usbback_driver_port_resource_complete(resource);
+			break;
+		default:
+			usbback_driver_port_resource_invalid_stimulus
+			    (resource, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_resource_state_i_st_ms_tu_us:
+		/* Handling request       */
+		/* URB submitted    */
+		/* unlink_urb outstanding */
+		switch (stimulus) {
+		case usbback_driver_port_resource_stimulus_tu:
+			break;
+		case usbback_driver_port_resource_stimulus_uc:
+		case usbback_driver_port_resource_stimulus_ul:
+			resource->state =
+			    usbback_driver_port_resource_state_i_st_ms_tu_us_uc;
+			break;
+		default:
+			usbback_driver_port_resource_invalid_stimulus
+			    (resource, stimulus);
+			break;
+		}
+		break;
+	case usbback_driver_port_resource_state_i_st_ms_tu_us_uc:
+		/* Handling request                        */
+		/* URB submitted or unlink_urb outstanding */
+		switch (stimulus) {
+		case usbback_driver_port_resource_stimulus_tu:
+			break;
+		case usbback_driver_port_resource_stimulus_uc:
+		case usbback_driver_port_resource_stimulus_ul:
+			resource->state = usbback_driver_port_resource_state_i;
+			usbback_driver_port_resource_complete(resource);
+			break;
+		default:
+			usbback_driver_port_resource_invalid_stimulus
+			    (resource, stimulus);
+			break;
+		}
+		break;
+	default:
+		usbback_driver_port_resource_invalid_stimulus(resource,
+							      stimulus);
+		break;
+	}
+}
+
+static void usbback_driver_port_resource_invalid_stimulus
+    (struct usbback_driver_port_resource *resource,
+     usbback_driver_port_resource_stimulus stimulus) {
+	trace();
+
+	printk
+	    (KERN_ERR "usbback: port resource %p in state %d"
+	     "received invalid stimulus %d",
+	     resource, resource->state, stimulus);
+}
+
+static void usbback_driver_port_resource_map_buffer
+    (struct usbback_driver_port_resource *resource) {
+	trace();
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	{
+		usbif_io_transaction_parameters_header header;
+
+		if (xenidc_local_buffer_reference_copy_out
+		    (xenidc_endpoint_transaction_to_parameters_lbr
+		     (resource->transaction), &header, sizeof(header)
+		    )
+		    != sizeof(header)
+		    ) {
+			goto PROTOCOL_ERROR;
+		}
+
+		xenidc_map_rbr_request_element_ensure_removed
+		    (&resource->request_element[0]);
+
+		xenidc_map_rbr_request_element_ensure_removed
+		    (&resource->request_element[1]);
+
+		xenidc_reserve_and_map_rbr_request_add_element
+		    (&resource->reserve_and_map_rbr_request,
+		     &resource->request_element[0]
+		    );
+
+		xenidc_map_rbr_request_element_set_rbr
+		    (&resource->request_element[0],
+		     header.rbr,
+		     (header.direction == USBIF_IO_TRANSACTION_DIRECTION_OUT) ?
+		     XENIDC_MAP_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_READ :
+		     XENIDC_MAP_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_WRITE);
+
+		if (header.io_transaction_type
+		    == USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS) {
+			usbif_isochronous_io_transaction_parameters parameters;
+
+			if (xenidc_local_buffer_reference_copy_out
+			    (xenidc_endpoint_transaction_to_parameters_lbr
+			     (resource->transaction),
+			     &parameters, sizeof(parameters)
+			    )
+			    != sizeof(parameters)
+			    ) {
+				goto PROTOCOL_ERROR;
+			}
+
+			xenidc_reserve_and_map_rbr_request_add_element
+			    (&resource->reserve_and_map_rbr_request,
+			     &resource->request_element[1]
+			    );
+
+			xenidc_map_rbr_request_element_set_rbr
+			    (&resource->request_element[1],
+			     parameters.schedule_rbr,
+			     XENIDC_MAP_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_READ |
+			     XENIDC_MAP_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_WRITE);
+		}
+
+		xenidc_rbr_mapper_pool_reserve_and_map_rbrs
+		    (usbback_driver_port_resource_rbr_mapper_pool,
+		     &resource->reserve_and_map_rbr_request,
+		     usbback_device_query_address
+		     (usbback_driver_backend_query_device
+		      (usbback_driver_port_query_backend(resource->port))
+		     )
+		    );
+	}
+
+	return;
+
+      PROTOCOL_ERROR:
+
+	resource->transaction_error = XENIDC_ERROR_INVALID_PROTOCOL;
+
+	usbback_driver_port_resource_handle_stimulus
+	    (resource, usbback_driver_port_resource_stimulus_mf);
+}
+
+static void usbback_driver_port_resource_abort_map
+    (struct usbback_driver_port_resource *resource) {
+	trace();
+
+	xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs
+	    (&resource->reserve_and_map_rbr_request,
+	     USBIF_XENIDC_ERROR_UNLINKED);
+}
+
+static void usbback_driver_port_resource_map_callback
+    (xenidc_callback * callback) {
+	trace();
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	{
+		xenidc_reserve_and_map_rbr_request *request =
+		    xenidc_reserve_and_map_rbr_request_map_callback_to
+		    (callback);
+
+		struct usbback_driver_port_resource *resource = container_of
+		    (request,
+		     struct usbback_driver_port_resource,
+		     reserve_and_map_rbr_request);
+
+		{
+			unsigned long flags;
+
+			spin_lock_irqsave(&resource->lock, flags);
+
+			resource->transaction_error =
+			    xenidc_callback_query_error(callback);
+
+			if (resource->transaction_error == XENIDC_ERROR_SUCCESS) {
+				resource->rbrs_mapped = 1;
+
+				usbback_driver_port_resource_handle_stimulus
+				    (resource,
+				     usbback_driver_port_resource_stimulus_ms);
+			} else {
+				trace0("failed to map FE buffer");
+
+				usbback_driver_port_resource_handle_stimulus
+				    (resource,
+				     usbback_driver_port_resource_stimulus_mf);
+			}
+
+			spin_unlock_irqrestore(&resource->lock, flags);
+		}
+	}
+}
+
+static void usbback_driver_port_resource_submit_urb
+    (struct usbback_driver_port_resource *resource) {
+	trace();
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	xenidc_callback_serialiser_complete_callback
+	    (&usbback_driver_port_resource_submit_urb_serialiser,
+	     &resource->submit_urb_1_callback, XENIDC_ERROR_SUCCESS);
+}
+
+static void usbback_driver_port_resource_end_io
+    (struct urb *urb, struct pt_regs *regs);
+
+static int check_iso_schedule(struct urb *urb)
+{
+	int i;
+
+	unsigned long total_length = 0;
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		struct usb_iso_packet_descriptor *desc =
+		    &urb->iso_frame_desc[i];
+
+		total_length += desc->length;
+
+		if ((desc->offset > urb->transfer_buffer_length)
+		    ||
+		    (desc->length >
+		     (urb->transfer_buffer_length - desc->offset))
+		    || (total_length > urb->transfer_buffer_length)
+		    ) {
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static void usbback_driver_port_resource_submit_urb_1
+    (xenidc_callback * callback) {
+	trace();
+
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+
+	{
+		struct usbback_driver_port_resource *resource = container_of
+		    (callback,
+		     struct usbback_driver_port_resource,
+		     submit_urb_1_callback);
+
+		usbif_io_transaction_parameters io_parameters;
+
+		{
+			xenidc_buffer_byte_count io_parameters_byte_count =
+			    xenidc_local_buffer_reference_copy_out
+			    (xenidc_endpoint_transaction_to_parameters_lbr
+			     (resource->transaction),
+			     &io_parameters,
+			     sizeof(io_parameters)
+			    );
+
+			if (io_parameters_byte_count <
+			    sizeof(io_parameters.header)) {
+				resource->transaction_error =
+				    XENIDC_ERROR_INVALID_PROTOCOL;
+
+				goto PROTOCOL_ERROR;
+			}
+
+			if (io_parameters.header.io_transaction_type
+			    >= USBIF_IO_TRANSACTION_TYPE_LIMIT) {
+				resource->transaction_error =
+				    XENIDC_ERROR_INVALID_PARAMETER;
+
+				goto PROTOCOL_ERROR;
+			}
+
+			if (io_parameters_byte_count
+			    <
+			    usbif_io_parameters_byte_count
+			    [io_parameters.header.io_transaction_type]
+			    ) {
+				resource->transaction_error =
+				    XENIDC_ERROR_INVALID_PROTOCOL;
+
+				goto PROTOCOL_ERROR;
+			}
+		}
+
+		trace1("io type:%d",
+		       (int)io_parameters.header.io_transaction_type);
+		trace1("dev num:%d", (int)io_parameters.header.device_number);
+		trace1("endpoint:%d", (int)io_parameters.header.endpoint);
+		trace1("direction:%d", (int)io_parameters.header.direction);
+		trace1("unlink_id:%d", (int)io_parameters.header.unlink_id);
+		trace1("flags:%d", (int)io_parameters.header.flags);
+		trace1("rbr type:%d", (int)io_parameters.header.rbr.type);
+		trace1("rbr offset:%d",
+		       (int)io_parameters.header.rbr.byte_offset);
+		trace1("rbr count:%d",
+		       (int)io_parameters.header.rbr.byte_count);
+
+		if (io_parameters.header.io_transaction_type
+		    == USBIF_IO_TRANSACTION_TYPE_CONTROL) {
+			struct usb_ctrlrequest *ctrl =
+			    (struct usb_ctrlrequest *)io_parameters.control.
+			    setup;
+
+			if (ctrl->bRequestType
+			    ==
+			    (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE)
+			    ) {
+				if (ctrl->bRequest == USB_REQ_SET_ADDRESS) {
+					trace1("Set address:%d",
+					       (int)le16_to_cpu(ctrl->wValue));
+
+					usbback_driver_port_set_guest_address
+					    (resource->port,
+					     le16_to_cpu(ctrl->wValue));
+
+					goto HANDLED_SPECIAL_CASE;
+				} else if (ctrl->bRequest ==
+					   USB_REQ_SET_CONFIGURATION) {
+					/* FIXME: what to do for set configuration? */
+
+					goto HANDLED_SPECIAL_CASE;
+				}
+			}
+		}
+
+		{
+			struct urb *urb = resource->urb;
+
+			static const unsigned int pipe_type
+			    [USBIF_IO_TRANSACTION_TYPE_LIMIT] = {
+				[USBIF_IO_TRANSACTION_TYPE_CONTROL] =
+				    PIPE_CONTROL,
+				[USBIF_IO_TRANSACTION_TYPE_BULK] = PIPE_BULK,
+				[USBIF_IO_TRANSACTION_TYPE_INTERRUPT] =
+				    PIPE_INTERRUPT,
+				[USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS] =
+				    PIPE_ISOCHRONOUS
+			};
+
+			unsigned int pipe =
+			    (((io_parameters.header.direction
+			       == USBIF_IO_TRANSACTION_DIRECTION_OUT)
+			      ? (unsigned int)USB_DIR_OUT : (unsigned int)
+			      USB_DIR_IN)
+			     | ((unsigned int)
+				usbback_driver_port_query_usbdev(resource->
+								 port)->
+				devnum << 8)
+			     | ((unsigned int)io_parameters.header.
+				endpoint << 15)
+			     |
+			     (pipe_type
+			      [io_parameters.header.io_transaction_type] << 30)
+			    );
+
+			trace1("pipe:%x", (int)pipe);
+
+			if (io_parameters.header.io_transaction_type
+			    == USBIF_IO_TRANSACTION_TYPE_CONTROL) {
+				memcpy
+				    (resource->setup,
+				     io_parameters.control.setup,
+				     sizeof(resource->setup)
+				    );
+
+				usb_fill_control_urb
+				    (urb,
+				     usbback_driver_port_query_usbdev(resource->
+								      port),
+				     pipe, resource->setup,
+				     resource->request_element[0].mapping,
+				     xenidc_remote_buffer_reference_query_byte_count
+				     (&resource->request_element[0].rbr),
+				     usbback_driver_port_resource_end_io,
+				     resource);
+
+				trace0("control URB");
+
+				trace1("setup[0]:%x", (int)resource->setup[0]);
+				trace1("setup[1]:%x", (int)resource->setup[1]);
+				trace1("setup[2]:%x", (int)resource->setup[2]);
+				trace1("setup[3]:%x", (int)resource->setup[3]);
+				trace1("setup[4]:%x", (int)resource->setup[4]);
+				trace1("setup[5]:%x", (int)resource->setup[5]);
+				trace1("setup[6]:%x", (int)resource->setup[6]);
+				trace1("setup[7]:%x", (int)resource->setup[7]);
+
+				trace1
+				    ("mapping:%x",
+				     (int)resource->request_element[0].mapping);
+
+				trace1
+				    ("count:%x",
+				     (int)
+				     xenidc_remote_buffer_reference_query_byte_count
+				     (&resource->request_element[0].rbr)
+				    );
+			} else if
+			    (io_parameters.header.io_transaction_type
+			     == USBIF_IO_TRANSACTION_TYPE_BULK) {
+				usb_fill_bulk_urb
+				    (urb,
+				     usbback_driver_port_query_usbdev(resource->
+								      port),
+				     pipe, resource->request_element[0].mapping,
+				     xenidc_remote_buffer_reference_query_byte_count
+				     (&resource->request_element[0].rbr),
+				     usbback_driver_port_resource_end_io,
+				     resource);
+
+				trace0("bulk URB");
+			} else if
+			    (io_parameters.header.io_transaction_type
+			     == USBIF_IO_TRANSACTION_TYPE_INTERRUPT) {
+				/* FIXME: hacking the interval like this is a bit unclean. */
+				/* should probably convert back to exponential form for    */
+				/* high speed transfers and then pass the value into       */
+				/* fill_int_urb.                                           */
+				usb_fill_int_urb(urb, usbback_driver_port_query_usbdev(resource->port), pipe, resource->request_element[0].mapping, xenidc_remote_buffer_reference_query_byte_count(&resource->request_element[0].rbr), usbback_driver_port_resource_end_io, resource, 1	/* For the time being... */
+				    );
+
+				/* ...now set the real value. */
+				urb->interval =
+				    io_parameters.interrupt.interval;
+
+				trace0("interrupt URB");
+
+				trace1("interval:%d",
+				       io_parameters.interrupt.interval);
+			} else {
+				ASSERT
+				    (io_parameters.header.io_transaction_type
+				     == USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS);
+
+				/* FIXME: where's usb_fill_isoc_urb ?!? */
+
+				spin_lock_init(&urb->lock);
+				urb->dev =
+				    usbback_driver_port_query_usbdev(resource->
+								     port);
+				urb->pipe = pipe;
+				urb->transfer_buffer =
+				    resource->request_element[0].mapping;
+				urb->transfer_buffer_length =
+				    xenidc_remote_buffer_reference_query_byte_count
+				    (&resource->request_element[0].rbr);
+				urb->complete =
+				    usbback_driver_port_resource_end_io;
+				urb->context = resource;
+				urb->number_of_packets =
+				    io_parameters.isochronous.packet_count;
+				urb->interval =
+				    io_parameters.isochronous.interval;
+				urb->start_frame = 0;
+				urb->transfer_flags |= URB_ISO_ASAP;
+
+				if (io_parameters.isochronous.packet_count
+				    > USBIF_MAX_SCHEDULE_PACKET_COUNT) {
+					resource->transaction_error =
+					    XENIDC_ERROR_TOO_BIG;
+
+					goto SCHEDULE_ERROR;
+				}
+
+				if (xenidc_remote_buffer_reference_query_byte_count(&resource->request_element[1].rbr)
+				    <
+				    (io_parameters.isochronous.packet_count
+				     *
+				     sizeof
+				     (usbif_isochronous_io_schedule_element)
+				    )
+				    ) {
+					resource->transaction_error =
+					    XENIDC_ERROR_INVALID_PARAMETER;
+
+					goto SCHEDULE_ERROR;
+				}
+
+				{
+					usbif_isochronous_io_schedule_element
+					    *schedule_element =
+					    resource->request_element[1].
+					    mapping;
+
+					usbif_isochronous_io_schedule_element
+					    aligned_element;
+
+					int i;
+
+					for (i = 0;
+					     i <
+					     io_parameters.isochronous.
+					     packet_count; i++) {
+						memcpy(&aligned_element,
+						       schedule_element++,
+						       sizeof(aligned_element)
+						    );
+
+						urb->iso_frame_desc[i].offset =
+						    aligned_element.offset;
+						urb->iso_frame_desc[i].length =
+						    aligned_element.length;
+
+						urb->iso_frame_desc[i].
+						    actual_length = 0;
+						urb->iso_frame_desc[i].status =
+						    0;
+					}
+				}
+
+				if (!check_iso_schedule(urb)) {
+					resource->transaction_error =
+					    XENIDC_ERROR_INVALID_PARAMETER;
+
+					goto SCHEDULE_ERROR;
+				}
+
+				trace0("isochronous URB");
+
+				trace1("interval:%d",
+				       io_parameters.isochronous.interval);
+
+				trace1("packet_count:%d",
+				       io_parameters.isochronous.packet_count);
+			}
+
+			/* On the backend, all unlinks are asynchronous. */
+
+			urb->transfer_flags |= URB_ASYNC_UNLINK;
+
+			if (io_parameters.header.
+			    flags & USBIF_IO_FLAGS_SHORT_NOT_OK) {
+				urb->transfer_flags |= URB_SHORT_NOT_OK;
+			}
+			if (io_parameters.header.
+			    flags & USBIF_IO_FLAGS_ZERO_PACKET) {
+				urb->transfer_flags |= URB_ZERO_PACKET;
+			}
+
+			resource->transaction_error =
+			    usbif_error_map_local_to(usb_submit_urb
+						     (urb, GFP_KERNEL));
+
+			if (resource->transaction_error != XENIDC_ERROR_SUCCESS) {
+				printk(KERN_WARNING
+				       "URB %p submission failed.\n", urb);
+
+				goto URB_ERROR;
+			}
+
+			{
+				unsigned long flags;
+
+				spin_lock_irqsave(&resource->lock, flags);
+
+				usbback_driver_port_resource_handle_stimulus
+				    (resource,
+				     usbback_driver_port_resource_stimulus_us);
+
+				spin_unlock_irqrestore(&resource->lock, flags);
+			}
+
+			return;
+		}
+
+	      URB_ERROR:
+
+	      SCHEDULE_ERROR:
+
+	      HANDLED_SPECIAL_CASE:
+
+	      PROTOCOL_ERROR:
+
+		{
+			unsigned long flags;
+
+			spin_lock_irqsave(&resource->lock, flags);
+
+			usbback_driver_port_resource_handle_stimulus
+			    (resource,
+			     usbback_driver_port_resource_stimulus_un);
+
+			spin_unlock_irqrestore(&resource->lock, flags);
+		}
+	}
+}
+
+static void usbback_driver_port_resource_end_io
+    (struct urb *urb, struct pt_regs *regs) {
+	trace();
+
+	{
+		struct usbback_driver_port_resource *resource = urb->context;
+
+		resource->transaction_error =
+		    usbif_error_map_local_to(urb->status);
+
+		if (resource->transaction_error != XENIDC_ERROR_SUCCESS) {
+			printk
+			    (KERN_WARNING "URB %p failed. Status %d\n", urb,
+			     urb->status);
+		}
+
+		resource->transaction_status_length = urb->actual_length;
+
+		if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+			usbif_isochronous_io_schedule_element *schedule_element
+			    = resource->request_element[1].mapping;
+
+			usbif_isochronous_io_schedule_element aligned_element;
+
+			int i;
+
+			for (i = 0; i < urb->number_of_packets; i++) {
+				aligned_element.length =
+				    urb->iso_frame_desc[i].actual_length;
+				aligned_element.error =
+				    usbif_error_map_local_to(urb->
+							     iso_frame_desc[i].
+							     status);
+
+				memcpy
+				    (schedule_element++,
+				     &aligned_element, sizeof(*schedule_element)
+				    );
+			}
+		}
+
+		{
+			unsigned long flags;
+
+			spin_lock_irqsave(&resource->lock, flags);
+
+			usbback_driver_port_resource_handle_stimulus
+			    (resource,
+			     usbback_driver_port_resource_stimulus_uc);
+
+			spin_unlock_irqrestore(&resource->lock, flags);
+		}
+	}
+}
+
+static void usbback_driver_port_resource_unlink_urb
+    (struct usbback_driver_port_resource *resource) {
+	trace();
+
+	usb_get_urb(resource->urb);
+
+	{
+		int scheduled =
+		    xenidc_work_schedule(&resource->unlink_urb_1_work);
+
+		ASSERT(scheduled);
+	}
+}
+
+static void usbback_driver_port_resource_unlink_urb_1(void *data)
+{
+	trace();
+
+	{
+		struct usbback_driver_port_resource *resource =
+		    (struct usbback_driver_port_resource *)data;
+
+		usb_unlink_urb(resource->urb);
+
+		usb_put_urb(resource->urb);
+
+		{
+			unsigned long flags;
+
+			spin_lock_irqsave(&resource->lock, flags);
+
+			usbback_driver_port_resource_handle_stimulus
+			    (resource,
+			     usbback_driver_port_resource_stimulus_ul);
+
+			spin_unlock_irqrestore(&resource->lock, flags);
+		}
+	}
+}
+
+static void usbback_driver_port_resource_set_unlinked_error
+    (struct usbback_driver_port_resource *resource) {
+	trace();
+
+	resource->transaction_error = USBIF_XENIDC_ERROR_UNLINKED;
+}
+
+static void usbback_driver_port_resource_complete
+    (struct usbback_driver_port_resource *resource) {
+	trace();
+
+	resource->completing_transaction = resource->transaction;
+	resource->transaction = NULL;
+
+	if (resource->rbrs_mapped) {
+		resource->rbrs_mapped = 0;
+
+		xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs
+		    (&resource->reserve_and_map_rbr_request);
+	} else {
+		xenidc_callback_success
+		    (xenidc_reserve_and_map_rbr_request_to_unmap_callback
+		     (&resource->reserve_and_map_rbr_request)
+		    );
+	}
+}
+
+static void usbback_driver_port_resource_unmap_callback
+    (xenidc_callback * callback) {
+	trace();
+
+	{
+		xenidc_reserve_and_map_rbr_request *request =
+		    xenidc_reserve_and_map_rbr_request_unmap_callback_to
+		    (callback);
+
+		struct usbback_driver_port_resource *resource = container_of
+		    (request,
+		     struct usbback_driver_port_resource,
+		     reserve_and_map_rbr_request);
+
+		usbif_io_transaction_status status;
+
+		status.length = resource->transaction_status_length;
+
+		if (xenidc_local_buffer_reference_copy_in
+		    (xenidc_endpoint_transaction_to_status_lbr
+		     (resource->completing_transaction), &status, sizeof(status)
+		    )
+		    != sizeof(status)
+		    ) {
+			resource->transaction_error =
+			    XENIDC_ERROR_INVALID_PROTOCOL;
+		}
+
+		xenidc_endpoint_transaction_complete
+		    (resource->completing_transaction,
+		     resource->transaction_error);
+
+		usbback_driver_port_resource_completed_io(resource->port,
+							  resource);
+	}
+}
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,83 @@
+/*****************************************************************************/
+/* Resource which processes an io transaction by translating it into an URB  */
+/* and submitting it to the USB stack.                                       */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_DRIVER_PORT_RESOURCE_H
+#define USBBACK_DRIVER_PORT_RESOURCE_H
+
+#include <asm-xen/xenidc.h>
+#include "usbback_device.h"
+
+int usbback_driver_port_resource_class_init(void);
+
+void usbback_driver_port_resource_class_exit(void);
+
+struct usbback_driver_port;
+struct usbback_driver_port_resource;
+
+int usbback_driver_port_resource_init
+    (struct usbback_driver_port_resource *resource,
+     struct usbback_driver_port *port);
+
+void usbback_driver_port_resource_exit
+    (struct usbback_driver_port_resource *resource);
+
+void usbback_driver_port_resource_start_io
+    (struct usbback_driver_port_resource *resource,
+     xenidc_endpoint_transaction * transaction);
+
+int usbback_driver_port_resource_try_unlink
+    (struct usbback_driver_port_resource *resource, int unlink_id);
+
+void usbback_driver_port_resource_flush_transaction
+    (struct usbback_driver_port_resource *resource);
+
+typedef enum {
+	usbback_driver_port_resource_state_i,
+	usbback_driver_port_resource_state_i_st,
+	usbback_driver_port_resource_state_i_st_tu,
+	usbback_driver_port_resource_state_i_st_ms,
+	usbback_driver_port_resource_state_i_st_ms_tu,
+	usbback_driver_port_resource_state_i_st_ms_us,
+	usbback_driver_port_resource_state_i_st_ms_uc,
+	usbback_driver_port_resource_state_i_st_ms_tu_us,
+	usbback_driver_port_resource_state_i_st_ms_tu_us_uc
+} usbback_driver_port_resource_state;
+
+struct usbback_driver_port_resource {
+	struct usbback_driver_port *port;
+	struct list_head link;
+	spinlock_t lock;
+	usbback_driver_port_resource_state state;
+	xenidc_error transaction_error;
+	unsigned long transaction_status_length;
+	xenidc_endpoint_transaction *transaction;
+	xenidc_endpoint_transaction *completing_transaction;
+	xenidc_reserve_and_map_rbr_request reserve_and_map_rbr_request;
+	xenidc_map_rbr_request_element request_element[2];
+	int rbrs_mapped;
+	struct urb *urb;
+	u8 setup[8];
+	xenidc_callback submit_urb_1_callback;
+	xenidc_work unlink_urb_1_work;
+};
+
+#endif
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,80 @@
+/*****************************************************************************/
+/* Back-end module for Xen USB split driver.                                 */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbback_driver.h"
+#include "usbback_device.h"
+#include "usbback_trace.h"
+
+static int usbback_module_init_or_exit(int exit)
+{
+	trace();
+
+	{
+		int return_value = 0;
+
+		if (exit) {
+			goto EXIT;
+		}
+
+		if ((return_value = usbback_driver_init()) != 0) {
+			goto EXIT_NO_DRIVER;
+		}
+
+		if ((return_value = usbback_device_class_init()) != 0) {
+			goto EXIT_NO_DEVICE_CLASS;
+		}
+
+		return 0;
+
+	      EXIT:
+
+		usbback_device_class_exit();
+
+	      EXIT_NO_DEVICE_CLASS:
+
+		usbback_driver_exit();
+
+	      EXIT_NO_DRIVER:
+
+		return return_value;
+	}
+}
+
+static int __init usbback_module_init(void)
+{
+	trace();
+
+	return usbback_module_init_or_exit(0);
+}
+
+static void __exit usbback_module_exit(void)
+{
+	trace();
+
+	(void)usbback_module_init_or_exit(1);
+}
+
+module_init(usbback_module_init);
+module_exit(usbback_module_exit);
+
+MODULE_LICENSE("GPL");
diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,54 @@
+/*****************************************************************************/
+/* Simple trace macros                                                       */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_TRACE_H
+#define USBBACK_TRACE_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_XEN_USBDEV_BACKEND_TRACE
+
+#define trace0( format ) \
+printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__ )
+
+#define trace1( format, a0 ) \
+printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__, a0 )
+
+#define trace2( format, a0, a1 ) \
+printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__, a0, a1 )
+
+#define trace3( format, a0, a1, a2 ) \
+printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__, a0, a1, a2 )
+
+#define trace() trace0( "" )
+
+#else
+
+#define trace0( format )
+#define trace1( format,a0 )
+#define trace2( format,a0, a1 )
+#define trace3( format,a0, a1, a2 )
+#define trace()
+
+#endif
+
+#endif
diff -r 941c7dbc1353 -r 5a90f01cb37e patches/linux-2.6.12/usb.patch
--- /dev/null	Mon Nov 21 11:09:54 2005
+++ b/patches/linux-2.6.12/usb.patch	Mon Nov 21 11:10:19 2005
@@ -0,0 +1,10 @@
+diff -Naur linux-2.6.12/drivers/usb/core/usb.c linux-2.6.12-usb/drivers/usb/core/usb.c
+--- linux-2.6.12/drivers/usb/core/usb.c	2005-06-17 20:48:29.000000000 +0100
++++ linux-2.6.12-usb/drivers/usb/core/usb.c	2005-09-28 13:01:29.000000000 +0100
+@@ -1561,4 +1561,6 @@
+ #endif
+ EXPORT_SYMBOL (usb_buffer_unmap_sg);
+ 
++EXPORT_SYMBOL (usb_bus_type);
++
+ MODULE_LICENSE("GPL");

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2005-11-21 13:19 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-11-21 13:19 [PATCH][15/17] USB virt 2.6 split driver---USB split driver back-end harry

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.