All of lore.kernel.org
 help / color / mirror / Atom feed
* USB split driver
@ 2006-10-03 17:10 Harry Butterworth
  2006-10-03 22:17 ` Andrew D. Ball
  0 siblings, 1 reply; 4+ messages in thread
From: Harry Butterworth @ 2006-10-03 17:10 UTC (permalink / raw)
  To: xen-devel

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

I've updated this patch to compile against current unstable and
implemented a new protocol which I think fixes the data integrity issue
present in all previous versions where URBs were not correctly stalled
on error.

In this version of the driver, an error in the BE causes the BE URB
queue to stall and all URBs present and subsequently arriving in the BE
to be unlinked and failed back to the FE.

The FE catches the unlinking URBs and hangs onto them until the
callbacks of any failing URBs and any URBs explicitly unlinked by the FE
driver as a result have completed.

After the FE error and unlink completions are quiesced, the FE retries
any URBs that remain back to the BE, sending the first with a flag that
clears the stall in the BE.

This was fairly ugly, and the locking is a bit of a nightmare.  The main
problem is that the USB stack has the semantics that it guarantees that
the URB queue will be stalled only until the URB completion returns
which means that there is a requirement to to URB unlinking nested in
the BE completion.

I have seen a couple of URB errors handled without the kernel crashing
but I would expect there to be some bugs in this code somewhere.

Also the xenbus stuff has been stirred around a few times since I wrote
it correctly and I have lost interest in proving to myself that the
current hooks into xenbus are correct.  The state machines in
ub_xb_channel and uf_xb_channel which coordinate with xenbus were
derived by trial and error and unlike the rest of the code are not
intended to be correct by design.

Someone has messed around with the usb stuff in the python code since
the last version too, possibly to implement usb support for the HVM
guests.  I changed this code to use "usbport" rather than usb and
hopefully it won't conflict.  This is untested.

The driver used to be modular and an older version did correctly handle
module load and unload in both the FE and BE including quiescing ongoing
I/O.  I was told to simplify the driver and remove this functionality.
The current version is therefore not modular.

I had some correspondence with the author of the USB over IP patch and
we came to the conclusion that USB/IP does not address the stalling
requirement above.  We were not 100% sure whether this is a problem but
I think it probably is.  This driver might perhaps be a useful example
of how to solve the problem for the USB/IP code.

I had put this work on hold waiting for an upstream merge of the other
drivers in the hope that it would force a cleanup of some of the xenbus
design.  Recently I discovered that I'll be leaving the IBM Xen team in
the near future and I'm not sure how much more time I can spend on this
so this is an attempt to get the driver in the best possible shape for
someone else to pick up.

The xen core team should decide whether they really want a USB split
driver at all or if they want to go with USB/IP or some common code
approach.

As for this driver, the basic structure of the code is OK.  I think the
locking is probably OK.  Lots more testing is required as well as
regression tests for xm-test.  Some formatting issues probably remain
too.  It's probably a bit too abstract for some of you---if so, you can
always read the .ko files ;-)

Sniff tested against f426f6e646eb.

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

[-- Attachment #2: latest-usb.patch --]
[-- Type: text/x-patch, Size: 413629 bytes --]

diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/Kconfig
--- a/linux-2.6-xen-sparse/drivers/xen/Kconfig	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig	Tue Oct  3 16:29:44 2006
@@ -145,6 +145,29 @@
 	depends on XEN_PCIDEV_BACKEND
 	default n
 
+config XEN_USBDEV_BACKEND
+	bool "USB-device backend driver"
+	depends on XEN_BACKEND
+	select USB
+	default y
+	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 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_BACKEND
 	tristate "TPM-device backend driver"
         depends on XEN_BACKEND
@@ -171,6 +194,30 @@
 	  network interfaces within another guest OS. Unless you are building a
 	  dedicated device-driver domain, or your master control domain
 	  (domain 0), then you almost certainly want to say Y here.
+
+config XEN_USBDEV_FRONTEND
+	bool "USB-device frontend driver"
+	depends on XEN
+	default y
+	select USB
+	help
+	  The USB-device frontend driver allows the kernel to access USB
+	  devices exported by a USB-device backend driver running in another
+	  domain.
+	  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 if you want to use a USB-device backend driver to export a USB
+	  device from another domain to the domain which will run this kernel.
+
+config XEN_USBDEV_FRONTEND_TRACE
+	bool "USB-device frontend driver tracing"
+	depends on XEN_USBDEV_FRONTEND
+	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_SCRUB_PAGES
 	bool "Scrub memory before freeing it to Xen"
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Tue Oct  3 16:29:44 2006
@@ -11,7 +11,9 @@
 obj-$(CONFIG_XEN_BLKDEV_TAP)		+= blktap/
 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_PCIDEV_BACKEND)	+= pciback/
 obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront/
+obj-$(CONFIG_XEN_USBDEV_FRONTEND)	+= usbfront/
diff -r f426f6e646eb -r 404b4ec94253 tools/examples/Makefile
--- a/tools/examples/Makefile	Mon Oct  2 17:04:56 2006
+++ b/tools/examples/Makefile	Tue Oct  3 16:29:44 2006
@@ -29,6 +29,7 @@
 XEN_SCRIPTS += block
 XEN_SCRIPTS += block-enbd block-nbd
 XEN_SCRIPTS += blktap
+XEN_SCRIPTS += usb
 XEN_SCRIPTS += vtpm vtpm-delete
 XEN_SCRIPTS += xen-hotplug-cleanup
 XEN_SCRIPTS += external-device-migrate
diff -r f426f6e646eb -r 404b4ec94253 tools/examples/xen-backend.agent
--- a/tools/examples/xen-backend.agent	Mon Oct  2 17:04:56 2006
+++ b/tools/examples/xen-backend.agent	Tue Oct  3 16:29:44 2006
@@ -9,6 +9,9 @@
 case "$XENBUS_TYPE" in
   tap)
     /etc/xen/scripts/blktap "$ACTION"
+    ;;
+  usb)
+    /etc/xen/scripts/usb "$ACTION"
     ;;
   vbd)
     /etc/xen/scripts/block "$ACTION"
diff -r f426f6e646eb -r 404b4ec94253 tools/examples/xen-backend.rules
--- a/tools/examples/xen-backend.rules	Mon Oct  2 17:04:56 2006
+++ b/tools/examples/xen-backend.rules	Tue Oct  3 16:29:44 2006
@@ -1,4 +1,5 @@
 SUBSYSTEM=="xen-backend", KERNEL=="tap*", RUN+="/etc/xen/scripts/blktap $env{ACTION}"
+SUBSYSTEM=="xen-backend", KERNEL=="usb*", RUN+="/etc/xen/scripts/usb $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vbd*", RUN+="/etc/xen/scripts/block $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="online", RUN+="$env{script} online"
diff -r f426f6e646eb -r 404b4ec94253 tools/examples/xmexample1
--- a/tools/examples/xmexample1	Mon Oct  2 17:04:56 2006
+++ b/tools/examples/xmexample1	Tue Oct  3 16:29:44 2006
@@ -64,6 +64,13 @@
 # and MODE is r for read-only, w for read-write.
 
 disk = [ 'phy:hda1,hda1,w' ]
+
+#----------------------------------------------------------------------------
+# Define USB devices.
+#
+# Specify the USB device path as it appears in /sys/bus/usb/devices in the
+# backend.  This example exports device 3 on bus 1 and device 4 on bus 2.
+#usbport = ['path=1-3','path=2-4']
 
 #----------------------------------------------------------------------------
 # Define to which TPM instance the user domain should communicate.
diff -r f426f6e646eb -r 404b4ec94253 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py	Mon Oct  2 17:04:56 2006
+++ b/tools/python/xen/xend/XendDomainInfo.py	Tue Oct  3 16:29:44 2006
@@ -1794,5 +1794,5 @@
 addControllerClass('pci',  pciif.PciController)
 addControllerClass('ioports', iopif.IOPortsController)
 addControllerClass('irq',  irqif.IRQController)
-addControllerClass('usb',  usbif.UsbifController)
+addControllerClass('usbport', usbif.UsbifController)
 addControllerClass('tap',  BlktapController)
diff -r f426f6e646eb -r 404b4ec94253 tools/python/xen/xend/server/usbif.py
--- a/tools/python/xen/xend/server/usbif.py	Mon Oct  2 17:04:56 2006
+++ b/tools/python/xen/xend/server/usbif.py	Tue Oct  3 16:29:44 2006
@@ -22,6 +22,8 @@
 """Support for virtual USB hubs.
 """
 
+from xen.xend import sxp
+
 from xen.xend.server.DevController import DevController
 
 
@@ -36,7 +38,28 @@
         DevController.__init__(self, vm)
 
 
-    def getDeviceDetails(self, _):
+    def getDeviceDetails(self, config):
         """@see DevController.getDeviceDetails"""
 
-        return (self.allocateDeviceID(), {}, {})
+        path = sxp.child_value(config, 'path')
+
+        devid = self.allocateDeviceID()
+
+        back  = { 'path'   : path,
+                  'handle' : "%i" % devid }
+
+        front = { 'handle' : "%i" % devid }
+
+        return (devid, back, front)
+
+    def configuration(self, devid):
+        """@see DevController.configuration"""
+
+        result = DevController.configuration(self, devid)
+
+        path = self.readBackend(devid,'path')
+
+        if path:
+            result.append(['path', path])
+
+        return result
diff -r f426f6e646eb -r 404b4ec94253 tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py	Mon Oct  2 17:04:56 2006
+++ b/tools/python/xen/xm/create.py	Tue Oct  3 16:29:44 2006
@@ -245,6 +245,10 @@
           fn=append_value, default=0,
           use="Make the domain a TPM interface backend.")
 
+gopts.var('usbif', val='no|yes',
+          fn=set_bool, default=0,
+          use="Make the domain a USB device backend.")
+
 gopts.var('disk', val='phy:DEV,VDEV,MODE[,DOM]',
           fn=append_value, default=[],
           use="""Add a disk device to a domain. The physical device is DEV,
@@ -271,10 +275,13 @@
          For example 'irq=7'.
          This option may be repeated to add more than one IRQ.""")
 
-gopts.var('usbport', val='PATH',
+gopts.var('usbport', val="path=PATH,backend=DOM",
           fn=append_value, default=[],
-          use="""Add a physical USB port to a domain, as specified by the path
-          to that port.  This option may be repeated to add more than one port.""")
+          use="""Map a backend USB port (specified by the backend PATH in the
+          backend domain DOM) to a single-port virtual host controller device
+          in the domain.
+          If backend is not specified the default backend driver domain is
+          used.  This option may be repeated to add more than one port.""")
 
 gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT,backend=DOM,vifname=NAME",
           fn=append_value, default=[],
@@ -528,10 +535,14 @@
         config_devs.append(['device', config_irq])
 
 def configure_usb(config_devs, vals):
-    for path in vals.usbport:
-        config_usb = ['usbport', ['path', path]]
+    for d in vals.usbport:
+        path    = d.get('path')
+        backend = d.get('backend')
+        config_usb = ['usbport']
+        config_usb.append(['path', path])
+        if backend:
+            config_usb.append(['backend', backend])
         config_devs.append(['device', config_usb])
-
 
 def configure_security(config, vals):
     """Create the config for ACM security labels.
@@ -685,6 +696,8 @@
         config.append(['backend', ['netif']])
     if vals.tpmif:
         config.append(['backend', ['tpmif']])
+    if vals.usbif:
+        config.append(['backend', ['usbif']])
     if vals.localtime:
         config.append(['localtime', vals.localtime])
 
@@ -756,7 +769,23 @@
         hexd = map(lambda v: '0x'+v, d)
         ioports.append(hexd)
     vals.ioports = ioports
-        
+
+def preprocess_usb(vals):
+    if not vals.usbport: return
+    usbport = []
+    for port in vals.usbport:
+        d = {}
+        a = port.split(',')
+        for b in a:
+            (k, v) = b.strip().split('=', 1)
+            k = k.strip()
+            v = v.strip()
+            if k not in ['path', 'backend']:
+                err('Invalid usbport specifier: ' + port)
+            d[k] = v
+        usbport.append(d)
+    vals.usbport = usbport
+
 def preprocess_vtpm(vals):
     if not vals.vtpm: return
     vtpms = []
@@ -927,6 +956,7 @@
     preprocess_ioports(vals)
     preprocess_ip(vals)
     preprocess_nfs(vals)
+    preprocess_usb(vals)
     preprocess_vnc(vals)
     preprocess_vtpm(vals)
     preprocess_access_control(vals)
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/Makefile
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/Makefile	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,12 @@
+obj-y = \
+ub_buffer_rsrc_provider.o \
+ub_callback.o             \
+ub_device.o               \
+ub_ep.o                   \
+ub_gw.o                   \
+ub_gw_rsrc.o              \
+ub_rbr_mapper.o           \
+ub_rsrc.o                 \
+ub_ring_channel.o         \
+ub_work.o                 \
+ub_xb_channel.o
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_buffer_rsrc_provider.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_buffer_rsrc_provider.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,196 @@
+/*****************************************************************************/
+/* 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/blkback/blkback.c                                        */
+/*                                                                           */
+/* original copyright notice follows...                                      */
+/*****************************************************************************/
+/******************************************************************************
+ * arch/xen/drivers/blkif/backend/main.c
+ * 
+ * Back-end of the driver for virtual block devices. This portion of the
+ * driver exports a 'unified' block-device interface that can be accessed
+ * by any operating system that implements a compatible front end. A 
+ * reference front-end implementation can be found in:
+ *  arch/xen/drivers/blkif/frontend
+ * 
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Copyright (c) 2005, Christopher Clark
+ */
+
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/gfp.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/pgalloc.h>
+#include <xen/balloon.h>
+#include <xen/driver_util.h>
+#include "ub_buffer_rsrc_provider.h"
+#include "ub_trace.h"
+
+struct ub_buffer_rsrc_provider {
+	spinlock_t                       lock;
+	struct ub_buffer_rsrc_list  rsrcs;
+	struct ub_buffer_rsrc_list  free_rsrcs;
+	struct page                     *page;
+	unsigned long                    mmap_vstart;
+	struct list_head                 page_range_list;
+	struct list_head                *page_range_link;
+};
+
+static int
+alloc_or_free_page_ranges(struct ub_buffer_rsrc_provider *provider,
+int free)
+{
+	int return_value = 0;
+	int i;
+	if (provider->rsrcs.page_ranges == 0)
+		return 0;
+	if (free)
+		goto exit_path;
+	provider->page = balloon_alloc_empty_page_range(
+				provider->rsrcs.page_ranges *
+				provider->rsrcs.page_range_page_count);
+	if (provider->page == NULL) {
+		return_value = -ENOMEM;
+		goto exit_no_page_range;
+	}
+	provider->mmap_vstart = (unsigned long)pfn_to_kaddr(page_to_pfn(
+							provider->page));
+	INIT_LIST_HEAD(&provider->page_range_list);
+	provider->page_range_link = kmalloc(sizeof(struct list_head) *
+				provider->rsrcs.page_ranges, GFP_KERNEL);
+	if (provider->page_range_link == NULL) {
+		return_value = -ENOMEM;
+		goto exit_no_page_range_link;
+	}
+	for (i = 0; i < provider->rsrcs.page_ranges; i++) {
+		struct list_head *link = &provider->page_range_link[i];
+		INIT_LIST_HEAD(link);
+		list_add(link, &provider->page_range_list);
+	}
+	provider->free_rsrcs.page_ranges = provider->rsrcs.page_ranges;
+	provider->free_rsrcs.page_range_page_count =
+				provider->rsrcs.page_range_page_count;
+	return 0;
+ exit_path:
+	kfree(provider->page_range_link);
+ exit_no_page_range_link:
+	balloon_dealloc_empty_page_range(provider->page,
+			provider->rsrcs.page_ranges *
+			provider->rsrcs.page_range_page_count);
+ exit_no_page_range:
+	return return_value;
+}
+
+static int
+ub_buffer_rsrc_provider_init_or_exit(
+struct ub_buffer_rsrc_provider *provider, int exit)
+{
+	int return_value = 0;
+	trace_info("%p", provider);
+	if (exit)
+		goto exit_path;
+	spin_lock_init(&provider->lock);
+	provider->free_rsrcs = ub_buffer_rsrc_list_null();
+	if( ( return_value = alloc_or_free_page_ranges(provider, 0) ) != 0 )
+		goto exit_no_page_ranges;
+	return 0;
+ exit_path:
+	alloc_or_free_page_ranges(provider, 1);
+ exit_no_page_ranges:
+	return return_value;
+}
+
+struct ub_buffer_rsrc_provider *
+ub_allocate_buffer_rsrc_provider(struct ub_buffer_rsrc_list rsrcs)
+{
+	struct ub_buffer_rsrc_provider *provider;
+	trace();
+	provider = kmalloc(sizeof(struct ub_buffer_rsrc_provider),
+								GFP_KERNEL);
+	if (provider != NULL) {
+		provider->rsrcs = rsrcs;
+		if (ub_buffer_rsrc_provider_init_or_exit(provider, 0)
+		    != 0) {
+			kfree(provider);
+			provider = NULL;
+		}
+	}
+	return provider;
+}
+
+void ub_free_buffer_rsrc_provider(
+struct ub_buffer_rsrc_provider *provider)
+{
+	trace();
+	(void)ub_buffer_rsrc_provider_init_or_exit(provider, 1);
+	kfree(provider);
+}
+
+struct ub_buffer_rsrc_list
+ub_buffer_rsrc_provider_query_free_rsrcs(
+struct ub_buffer_rsrc_provider *provider)
+{
+	struct ub_buffer_rsrc_list list;
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&provider->lock, flags);
+	list = provider->free_rsrcs;
+	spin_unlock_irqrestore(&provider->lock, flags);
+	return list;
+}
+
+unsigned long
+ub_buffer_rsrc_provider_allocate_page_range(
+struct ub_buffer_rsrc_provider *provider, unsigned long page_count)
+{
+	unsigned long page_range;
+	unsigned long flags;
+	struct list_head *link;
+	trace();
+	spin_lock_irqsave(&provider->lock, flags);
+	link = provider->page_range_list.next;
+	list_del_init(link);
+	provider->free_rsrcs.page_ranges--;
+	page_range = (provider->mmap_vstart +
+			(PAGE_SIZE * provider->rsrcs.page_range_page_count *
+			(((unsigned long)link -
+				(unsigned long)provider->page_range_link) /
+						sizeof(struct list_head))));
+	spin_unlock_irqrestore(&provider->lock, flags);
+	return page_range;
+}
+
+void ub_buffer_rsrc_provider_free_page_range(
+struct ub_buffer_rsrc_provider *provider, unsigned long page_range)
+{
+	int i;
+	unsigned long flags;
+	trace();
+	i = ((page_range - provider->mmap_vstart) / (PAGE_SIZE *
+			provider->rsrcs.page_range_page_count));
+	spin_lock_irqsave(&provider->lock, flags);
+	list_add(&provider->page_range_link[i], &provider->page_range_list);
+	provider->free_rsrcs.page_ranges++;
+	spin_unlock_irqrestore(&provider->lock, flags);
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_buffer_rsrc_provider.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_buffer_rsrc_provider.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,77 @@
+/*****************************************************************************/
+/* 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 UB_BUFFER_RSRC_PROVIDER_H
+#define UB_BUFFER_RSRC_PROVIDER_H
+
+#include <linux/string.h>
+#include <asm/types.h>
+#include <xen/gnttab.h>
+
+struct ub_buffer_rsrc_list {
+	u32 page_ranges;
+	u32 page_range_page_count;
+};
+
+static inline struct ub_buffer_rsrc_list
+ub_buffer_rsrc_list_null(void)
+{
+	struct ub_buffer_rsrc_list list;
+	memset(&list, 0, sizeof(list));
+	return list;
+}
+
+static inline int
+ub_buffer_rsrc_list_subset_of(struct ub_buffer_rsrc_list *a,
+struct ub_buffer_rsrc_list *b)
+{
+	return ((a->page_ranges <= b->page_ranges) &&
+		(a->page_range_page_count <= b->page_range_page_count));
+}
+
+static inline void
+ub_buffer_rsrc_list_plus_equals(struct ub_buffer_rsrc_list *a,
+struct ub_buffer_rsrc_list *b)
+{
+	a->page_ranges += b->page_ranges;
+	if (b->page_range_page_count > a->page_range_page_count)
+		a->page_range_page_count = b->page_range_page_count;
+}
+
+extern struct ub_buffer_rsrc_provider *
+ub_allocate_buffer_rsrc_provider(
+struct ub_buffer_rsrc_list rsrc_allocation);
+
+extern void
+ub_free_buffer_rsrc_provider(
+struct ub_buffer_rsrc_provider *provider);
+
+extern struct ub_buffer_rsrc_list
+ub_buffer_rsrc_provider_query_free_rsrcs(
+struct ub_buffer_rsrc_provider *provider);
+
+extern unsigned long
+ub_buffer_rsrc_provider_allocate_page_range(
+struct ub_buffer_rsrc_provider *provider, unsigned long page_count);
+
+extern void
+ub_buffer_rsrc_provider_free_page_range(
+struct ub_buffer_rsrc_provider *provider, unsigned long page_range);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_callback.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_callback.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,41 @@
+/*****************************************************************************/
+/* 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 "ub_callback.h"
+
+void ub_callback_serialiser_function(void *context)
+{
+	struct ub_callback_serialiser *serialiser =
+				(struct ub_callback_serialiser *)context;
+	unsigned long flags;
+
+	spin_lock_irqsave(&serialiser->lock, flags);
+	while (!list_empty(&serialiser->list) && !serialiser->running) {
+		struct ub_callback *callback =
+			ub_callback_link_to(serialiser->list.next);
+		list_del_init(ub_callback_to_link(callback));
+		serialiser->running = 1;
+		spin_unlock_irqrestore(&serialiser->lock, flags);
+		ub_callback_complete_synchronously(callback);
+		spin_lock_irqsave(&serialiser->lock, flags);
+		serialiser->running = 0;
+	}
+	spin_unlock_irqrestore(&serialiser->lock, flags);
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_callback.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_callback.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,146 @@
+/*****************************************************************************/
+/* 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 UB_CALLBACK_H
+#define UB_CALLBACK_H
+
+#include <linux/spinlock.h>
+#include <xen/interface/io/usbif.h>
+#include "ub_work.h"
+
+static inline usbif_error usbif_error_map_local_to(int error)
+{
+	switch (error) {
+	case 0:
+		return USBIF_ERROR_SUCCESS;
+	case -ENOTCONN:
+		return USBIF_ERROR_DISCONNECT;
+	case -EPROTO:
+		return USBIF_ERROR_INVALID_PROTOCOL;
+	case -EINVAL:
+		return USBIF_ERROR_INVALID_PARAMETER;
+	case -E2BIG:
+		return USBIF_ERROR_TOO_BIG;
+	case -ENODEV:
+		return USBIF_ERROR_NO_DEVICE;
+	case -ECONNRESET:
+		return USBIF_ERROR_UNLINKED;
+	case -EPIPE:
+		return USBIF_ERROR_PIPE;
+	default:
+		return (usbif_error)error;
+	}
+}
+
+struct ub_callback {
+	struct ub_work work;
+	usbif_error         error;
+};
+
+typedef void ub_callback_function(struct ub_callback *callback);
+
+static inline void
+ub_callback_init(struct ub_callback *callback,
+ub_callback_function *function)
+{
+	ub_work_init(&callback->work, (void (*)(void *))function,
+								callback);
+	callback->error = USBIF_ERROR_SUCCESS;
+}
+
+static inline struct list_head *
+ub_callback_to_link(struct ub_callback *callback)
+{
+	return ub_work_to_link(&callback->work);
+}
+
+static inline struct ub_callback *
+ub_callback_link_to(struct list_head *link)
+{
+	return container_of(ub_work_link_to(link),
+					struct ub_callback, work);
+}
+
+static inline void
+ub_callback_complete(struct ub_callback *callback, usbif_error error)
+{
+	callback->error = error;
+	ub_work_schedule(&callback->work);
+}
+
+static inline void
+ub_callback_success(struct ub_callback *callback)
+{
+	ub_callback_complete(callback, 0);
+}
+
+static inline void
+ub_callback_set_error(struct ub_callback *callback,
+usbif_error error)
+{
+	callback->error = error;
+}
+
+static inline void
+ub_callback_complete_synchronously(struct ub_callback *callback)
+{
+	ub_work_perform_synchronously(&callback->work);
+}
+
+static inline usbif_error
+ub_callback_query_error(struct ub_callback *callback)
+{
+	return callback->error;
+}
+
+struct ub_callback_serialiser {
+	spinlock_t lock;
+	struct list_head list;
+	struct ub_work work;
+	int running;
+};
+
+void ub_callback_serialiser_function(void *context);
+
+#define UB_CALLBACK_SERIALISER_INIT( name ) {			\
+	.lock = SPIN_LOCK_UNLOCKED,					\
+	.list = LIST_HEAD_INIT( name.list ),				\
+	.work = UB_WORK_INIT					\
+		( name.work, ub_callback_serialiser_function, &name ),\
+	.running = 0							\
+}
+
+#define UB_CALLBACK_SERIALISER( name ) \
+struct ub_callback_serialiser name =   \
+UB_CALLBACK_SERIALISER_INIT( name )
+
+static inline void
+ub_callback_serialiser_complete_callback(
+struct ub_callback_serialiser *serialiser,
+struct ub_callback *callback, usbif_error error)
+{
+	unsigned long flags;
+	ub_callback_set_error(callback, error);
+	spin_lock_irqsave(&serialiser->lock, flags);
+	list_add_tail(ub_callback_to_link(callback), &serialiser->list);
+	spin_unlock_irqrestore(&serialiser->lock, flags);
+	ub_work_schedule(&serialiser->work);
+}
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_channel.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_channel.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,159 @@
+/*****************************************************************************/
+/* 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 UB_CHANNEL_H
+#define UB_CHANNEL_H
+
+#include <xen/interface/io/usbif.h>
+#include "ub_callback.h"
+
+struct ub_channel_ibmsg {
+	struct ub_callback callback;
+	struct usbif_request    request;
+};
+
+static inline struct list_head *
+ub_channel_ibmsg_to_link(struct ub_channel_ibmsg *message)
+{
+	return &message->callback.work.link;
+}
+
+static inline struct ub_callback *
+ub_channel_ibmsg_to_callback(struct ub_channel_ibmsg *message)
+{
+	return &message->callback;
+}
+
+static inline struct ub_channel_ibmsg *
+ub_channel_ibmsg_callback_to(struct ub_callback *callback)
+{
+	return container_of(callback, struct ub_channel_ibmsg, callback);
+}
+
+static inline void
+ub_channel_ibmsg_init(struct ub_channel_ibmsg *message,
+ub_callback_function *callback)
+{
+	ub_callback_init(ub_channel_ibmsg_to_callback(message),
+								callback);
+}
+
+struct ub_channel_obmsg {
+	struct ub_callback callback;
+	struct usbif_response   response;
+};
+
+static inline struct list_head *
+ub_channel_obmsg_to_link(struct ub_channel_obmsg *message)
+{
+	return &message->callback.work.link;
+}
+
+static inline struct ub_callback *
+ub_channel_obmsg_to_callback(struct ub_channel_obmsg *message)
+{
+	return &message->callback;
+}
+
+static inline struct ub_channel_obmsg *
+ub_channel_obmsg_callback_to(struct ub_callback *callback)
+{
+	return container_of(callback, struct ub_channel_obmsg, callback);
+}
+
+static inline void
+ub_channel_obmsg_init(struct ub_channel_obmsg *message,
+ub_callback_function *callback)
+{
+	ub_callback_init(ub_channel_obmsg_to_callback(message),
+								callback);
+}
+
+struct ub_channel;
+
+typedef void
+ub_channel_submit_message_function(struct ub_channel *channel,
+struct ub_channel_obmsg *message);
+
+typedef void
+ub_channel_connect_function(void *client_context);
+
+typedef void
+ub_channel_handle_message_function(void *client_context,
+struct ub_channel_ibmsg *message);
+
+typedef void
+ub_channel_disconnect_function(void *client_context,
+struct ub_callback *callback);
+
+struct ub_channel {
+	ub_channel_submit_message_function *submit_message;
+	void                                    *client_context;
+	ub_channel_connect_function        *connect;
+	ub_channel_handle_message_function *handle_message;
+	ub_channel_disconnect_function     *disconnect;
+};
+
+static inline void
+ub_channel_init(struct ub_channel *channel,
+ub_channel_submit_message_function *submit_message )
+{
+	channel->submit_message = submit_message;
+}
+
+static inline void ub_channel_connect(struct ub_channel *channel)
+{
+	channel->connect(channel->client_context);
+}
+
+static inline void
+ub_channel_handle_message(struct ub_channel *channel,
+struct ub_channel_ibmsg *message)
+{
+	channel->handle_message(channel->client_context, message);
+}
+
+static inline void
+ub_channel_disconnect(struct ub_channel *channel,
+struct ub_callback *callback)
+{
+	channel->disconnect(channel->client_context, callback);
+}
+
+static inline void
+ub_channel_install_client(struct ub_channel *channel,
+void *client_context, ub_channel_connect_function *connect,
+ub_channel_handle_message_function *handle_message,
+ub_channel_disconnect_function *disconnect)
+{
+	channel->client_context = client_context;
+	channel->connect        = connect;
+	channel->handle_message = handle_message;
+	channel->disconnect     = disconnect;
+}
+
+static inline void
+ub_channel_submit_message(struct ub_channel *channel,
+struct ub_channel_obmsg *message)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	channel->submit_message(channel, message);
+}
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_device.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_device.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,766 @@
+/*****************************************************************************/
+/* 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@xxxxxxxxxxxxxxx>
+
+    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/err.h>
+#include <linux/init.h>
+#include <linux/rwsem.h>
+#include <linux/usb.h>
+#include <xen/interface/io/usbif.h>
+#include <xen/xenbus.h>
+#include "ub_device.h"
+#include "ub_ep.h"
+#include "ub_trace.h"
+#include "ub_xb_channel.h"
+
+#define UB_DEVICE_EP_COUNT 32
+
+static struct usb_driver ub_device_usb_driver;
+
+static DECLARE_RWSEM(ub_device_list_sem);
+static LIST_HEAD(ub_device_list);
+
+typedef enum {
+	ub_device_state_i,
+	ub_device_state_i_up,
+	ub_device_state_i_cn,
+	ub_device_state_i_up_cn,
+	ub_device_state_i_up_cn_ud,
+	ub_device_state_i_up_cn_dn,
+	ub_device_state_i_up_cn_ud_dn
+} ub_device_state;
+
+typedef enum {
+	ub_device_stimulus_up, /* USB probe              */
+	ub_device_stimulus_ud, /* USB disconnect         */
+	ub_device_stimulus_cn, /* Gateway connect        */
+	ub_device_stimulus_dn, /* Gateway disconnect     */
+	ub_device_stimulus_ed  /* Endpoints disconnected */
+} ub_device_stimulus;
+
+struct ub_ep_disconnect {
+	struct ub_callback  callback;
+	struct ub_device   *device;
+};
+
+struct ub_device {
+	struct xenbus_device   *dev;
+	struct list_head        link;
+	struct usb_device      *usbdev;
+	char                   *path;
+	spinlock_t              lock;
+	ub_device_state         state;
+	int                     usbdev_is_connected;
+	struct ub_ep            ep[UB_DEVICE_EP_COUNT];
+	struct ub_ep_disconnect ep_disconnect[UB_DEVICE_EP_COUNT];
+	int                     ep_disconnects_out;
+	struct ub_callback     *gw_disconnect_callback;
+	int                     usb_disconnect_done;
+	struct ub_xb_channel    channel;
+	struct ub_gw            gw;
+};
+
+static void ub_device_handle_stimulus(struct ub_device *device,
+ub_device_stimulus stimulus);
+
+domid_t ub_device_query_remote_domain(struct ub_device *device)
+{
+	trace();
+	return device->dev->otherend_id;
+}
+
+struct usb_device *ub_device_query_usbdev(struct ub_device *device)
+{
+	trace();
+	return device->usbdev;
+}
+
+static inline struct ub_device *ub_device_gw_to(struct ub_gw *gw)
+{
+	return container_of(gw, struct ub_device, gw);
+}
+
+static int ub_device_probe_usb_device(struct usb_interface *intf,
+const struct usb_device_id *id)
+{
+	int return_value = 0, i;
+	struct usb_device *usbdev = interface_to_usbdev(intf);
+	struct ub_device *device = NULL, *cur = NULL;
+	trace();
+	dev_info(&usbdev->dev, "probe for %s\n", usbdev->dev.bus_id);
+	down_read(&ub_device_list_sem);
+	list_for_each_entry(cur, &ub_device_list, link) {
+		dev_info(&usbdev->dev, "testing path %s\n", cur->path );
+		if (strcmp(cur->path, usbdev->dev.bus_id) == 0) {
+			dev_info(&usbdev->dev, "match found\n" );
+			device = cur;
+			break;
+		} else {
+			dev_info(&usbdev->dev, "does not match\n" );
+		}
+	}
+	if (device == NULL) {
+		dev_info(&usbdev->dev, "no match found\n" );
+		return_value = -ENODEV;
+		goto exit_no_device;
+	}
+	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)) {
+				dev_info(&usbdev->dev,
+						"an interface of the matching "
+						"device is already in use by "
+						"another driver\n");
+				return_value = -EBUSY;
+				goto exit_interface_already_claimed;
+			}
+		}
+	}
+	for (i = 0; i < usbdev->actconfig->desc.bNumInterfaces; i++) {
+		struct usb_interface *other_intf = usb_ifnum_to_if(usbdev, i);
+		if (other_intf != intf) {
+			/* We already checked the interfaces were available. */
+			(void)usb_driver_claim_interface(
+						&ub_device_usb_driver,
+						other_intf, device);
+		}
+	}
+	usbdev = usb_get_dev(usbdev);
+	usb_set_intfdata(intf, device);
+	spin_lock_irq(&device->lock);
+	device->usbdev_is_connected = 1;
+	device->usbdev = usbdev;
+	ub_device_handle_stimulus(device, ub_device_stimulus_up);
+	spin_unlock_irq(&device->lock);
+ exit_interface_already_claimed:
+ exit_no_device:
+	up_read(&ub_device_list_sem);
+	return return_value;
+}
+
+static void ub_device_disconnect_usb_device(struct usb_interface *intf)
+{
+	struct ub_device *device = usb_get_intfdata(intf);
+	trace();
+	/* Protect against reentrant call when we release other interfaces. */
+	if (device != NULL) {
+		struct usb_device *usbdev;
+		int i;
+		spin_lock_irq(&device->lock);
+		device->usbdev_is_connected = 0;
+		device->usb_disconnect_done = 0;
+		ub_device_handle_stimulus(device, ub_device_stimulus_ud);
+		spin_unlock_irq(&device->lock);
+		ub_work_until(device->usb_disconnect_done);
+		usbdev = device->usbdev;
+		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(
+					&ub_device_usb_driver, other_intf);
+			}
+		}
+		usb_set_intfdata(intf, NULL);
+		usb_put_dev(usbdev);
+	}
+}
+
+static void ub_device_gw_connect(struct ub_gw *gw)
+{
+	struct ub_device *device = ub_device_gw_to(gw);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&device->lock, flags);
+	ub_device_handle_stimulus(device, ub_device_stimulus_cn);
+	spin_unlock_irqrestore(&device->lock, flags);
+}
+
+static void
+ub_device_handle_probe(struct ub_device *device, struct ub_gw_tra *tra)
+{
+	tra->status.probe.result = device->usbdev_is_connected ?
+					USBIF_PROBE_RESULT_DEVICE_PRESENT :
+					USBIF_PROBE_RESULT_NO_DEVICE;
+	ub_gw_tra_complete(tra, USBIF_ERROR_SUCCESS);
+}
+
+int ub_device_reset(struct ub_device *device)
+{
+	int status = -1;
+	trace();
+	spin_lock_irq(&device->lock);
+	if (device->usbdev_is_connected) {
+		if (device->usbdev->speed == USB_SPEED_LOW) {
+			status = USBIF_RESET_RESULT_LOW_SPEED;
+		} else if (device->usbdev->speed == USB_SPEED_HIGH) {
+			status = USBIF_RESET_RESULT_HIGH_SPEED;
+		} else {
+			status = USBIF_RESET_RESULT_FULL_SPEED;
+		}
+	}
+	spin_unlock_irq(&device->lock);
+	return status;
+}
+
+static void
+ub_device_handle_reset(struct ub_device *device, struct ub_gw_tra *tra)
+{
+	usbif_error error = USBIF_ERROR_SUCCESS;
+	int result;
+	trace();
+	result = ub_device_reset(device);
+	if (result < 0) {
+		error = USBIF_ERROR_NO_DEVICE;
+		goto complete;
+	}
+	tra->status.reset.result = result;
+ complete:
+	ub_gw_tra_complete(tra, error);
+}
+
+static void
+ub_device_handle_io(struct ub_device *device, struct ub_gw_tra *tra)
+{
+	int ep_index = tra->parameters.io.header.endpoint +
+			( tra->parameters.io.header.direction ? 16 : 0 );
+	trace();
+	if( ep_index < UB_DEVICE_EP_COUNT )
+		ub_ep_handle_io(&device->ep[ep_index], tra);
+	else
+		ub_gw_tra_complete(tra, USBIF_ERROR_INVALID_PARAMETER);
+}
+
+static void
+ub_device_handle_stall(struct ub_device *device, struct ub_gw_tra *tra)
+{
+	int ep_index = tra->parameters.stall.endpoint +
+			( tra->parameters.stall.direction ? 16 : 0 );
+	trace();
+	if( ep_index < UB_DEVICE_EP_COUNT ) {
+		ub_ep_stall(&device->ep[ep_index]);
+		ub_gw_tra_complete(tra, USBIF_ERROR_SUCCESS);
+	} else {
+		ub_gw_tra_complete(tra, USBIF_ERROR_INVALID_PARAMETER);
+	}
+}
+
+static void ub_device_gw_tra(struct ub_gw *gw, struct ub_gw_tra *tra)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	struct ub_device *device = ub_device_gw_to(gw);
+	switch (tra->parameters.header.tra_type) {
+	case USBIF_TRA_TYPE_PROBE:
+		ub_device_handle_probe(device, tra);
+		break;
+	case USBIF_TRA_TYPE_RESET:
+		ub_device_handle_reset(device, tra);
+		break;
+	case USBIF_TRA_TYPE_IO:
+		ub_device_handle_io(device, tra);
+		break;
+	case USBIF_TRA_TYPE_STALL:
+		ub_device_handle_stall(device, tra);
+		break;
+	default:
+		ub_gw_tra_complete(tra, USBIF_ERROR_INVALID_PARAMETER);
+		break;
+	}
+}
+
+static void
+ub_device_gw_disconnect(struct ub_gw *gw, struct ub_callback *callback)
+{
+	struct ub_device *device = ub_device_gw_to(gw);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&device->lock, flags);
+	device->gw_disconnect_callback = callback;
+	ub_device_handle_stimulus(device, ub_device_stimulus_dn);
+	spin_unlock_irqrestore(&device->lock, flags);
+}
+
+static void ub_device_invalid_stimulus(struct ub_device *device,
+ub_device_stimulus stimulus)
+{
+	trace();
+	printk(KERN_ERR "ub: device %p in state %d"
+	     " received invalid stimulus %d", device, device->state, stimulus);
+}
+
+static void ub_device_connect_endpoints(struct ub_device *device)
+{
+	int i;
+	trace();
+	for (i = 0; i < UB_DEVICE_EP_COUNT; i++)
+		ub_ep_connect(&device->ep[i]);
+}
+
+static void ub_device_disconnect_endpoints(struct ub_device *device)
+{
+	int i;
+	trace();
+	device->ep_disconnects_out = UB_DEVICE_EP_COUNT;
+	for (i = 0; i < UB_DEVICE_EP_COUNT; i++)
+		ub_ep_disconnect(&device->ep[i],
+					&device->ep_disconnect[i].callback);
+}
+
+static void ub_device_ep_disconnect_callback(struct ub_callback *callback)
+{
+	struct ub_device *device = container_of(callback,
+			struct ub_ep_disconnect, callback)->device;
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&device->lock, flags);
+	if (--device->ep_disconnects_out == 0)
+		ub_device_handle_stimulus(device, ub_device_stimulus_ed);
+	spin_unlock_irqrestore(&device->lock, flags);
+}
+
+static void ub_device_complete_usb_disconnect(struct ub_device *device)
+{
+	trace();
+	device->usb_disconnect_done = 1;
+	ub_work_wake_up();
+}
+
+static void ub_device_complete_gw_disconnect(struct ub_device *device)
+{
+	trace();
+	ub_callback_success(device->gw_disconnect_callback);
+}
+
+static void
+ub_device_handle_stimulus(struct ub_device *device,
+ub_device_stimulus stimulus)
+{
+	trace_info("device %p in state %d received stimulus %d", device,
+						device->state, stimulus);
+	switch (device->state) {
+	case ub_device_state_i:
+		/* USB disconnected                   */
+		/* Gateway disconnected               */
+		/* Endpoints disconnected             */
+		/* USB disconnect not outstanding     */
+		/* Gateway disconnect not outstanding */
+		switch (stimulus) {
+		case ub_device_stimulus_up:
+			device->state = ub_device_state_i_up;
+			break;
+		case ub_device_stimulus_cn:
+			device->state = ub_device_state_i_cn;
+			break;
+		default:
+			ub_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case ub_device_state_i_up:
+		/* USB probed                         */
+		/* Gateway disconnected               */
+		/* Endpoints disconnected             */
+		/* USB disconnect not outstanding     */
+		/* Gateway disconnect not outstanding */
+		switch (stimulus) {
+		case ub_device_stimulus_ud:
+			device->state = ub_device_state_i;
+			ub_device_complete_usb_disconnect(device);
+			break;
+		case ub_device_stimulus_cn:
+			device->state = ub_device_state_i_up_cn;
+			ub_device_connect_endpoints(device);
+			break;
+		default:
+			ub_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case ub_device_state_i_cn:
+		/* USB disconnected                   */
+		/* Gateway connected                  */
+		/* Endpoints disconnected             */
+		/* USB disconnect not outstanding     */
+		/* Gateway disconnect not outstanding */
+		switch (stimulus) {
+		case ub_device_stimulus_up:
+			device->state = ub_device_state_i_up_cn;
+			ub_device_connect_endpoints(device);
+			break;
+		case ub_device_stimulus_dn:
+			device->state = ub_device_state_i;
+			ub_device_complete_gw_disconnect(device);
+			break;
+		default:
+			ub_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case ub_device_state_i_up_cn:
+		/* USB probed                         */
+		/* Gateway connected                  */
+		/* Endpoints connected                */
+		/* USB disconnect not outstanding     */
+		/* Gateway disconnect not outstanding */
+		switch (stimulus) {
+		case ub_device_stimulus_ud:
+			device->state = ub_device_state_i_up_cn_ud;
+			ub_device_disconnect_endpoints(device);
+			break;
+		case ub_device_stimulus_dn:
+			device->state = ub_device_state_i_up_cn_dn;
+			ub_device_disconnect_endpoints(device);
+			break;
+		default:
+			ub_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case ub_device_state_i_up_cn_ud:
+		/* USB disconnecting                  */
+		/* Gateway connected                  */
+		/* Endpoints disconnecting            */
+		/* USB disconnect outstanding         */
+		/* Gateway disconnect not outstanding */
+		switch (stimulus) {
+		case ub_device_stimulus_dn:
+			device->state = ub_device_state_i_up_cn_ud_dn;
+			break;
+		case ub_device_stimulus_ed:
+			device->state = ub_device_state_i_cn;
+			ub_device_complete_usb_disconnect(device);
+			break;
+		default:
+			ub_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case ub_device_state_i_up_cn_dn:
+		/* USB probed                     */
+		/* Gateway disconnecting          */
+		/* Endpoints disconnecting        */
+		/* USB disconnect not outstanding */
+		/* Gateway disconnect outstanding */
+		switch (stimulus) {
+		case ub_device_stimulus_ud:
+			device->state = ub_device_state_i_up_cn_ud_dn;
+			break;
+		case ub_device_stimulus_ed:
+			device->state = ub_device_state_i_up;
+			ub_device_complete_gw_disconnect(device);
+			break;
+		default:
+			ub_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case ub_device_state_i_up_cn_ud_dn:
+		/* USB disconnecting              */
+		/* Gateway disconnecting          */
+		/* Endpoints disconnecting        */
+		/* USB disconnect outstanding     */
+		/* Gateway disconnect outstanding */
+		switch (stimulus) {
+		case ub_device_stimulus_ed:
+			device->state = ub_device_state_i;
+			ub_device_complete_usb_disconnect(device);
+			ub_device_complete_gw_disconnect(device);
+			break;
+		default:
+			ub_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	default:
+		ub_device_invalid_stimulus(device, stimulus);
+		break;
+	}
+}
+
+static int
+ub_device_init_or_exit(struct ub_device *device, struct xenbus_device *dev,
+int exit)
+{
+	struct xenbus_transaction tra;
+	int return_value = 0, i = UB_DEVICE_EP_COUNT;
+	trace();
+	if (exit)
+		goto exit_path;
+	device->dev = dev;
+	INIT_LIST_HEAD(&device->link);
+	spin_lock_init(&device->lock);
+	device->state = ub_device_state_i;
+	device->usbdev_is_connected = 0;
+	for (i = 0; i < UB_DEVICE_EP_COUNT; i++) {
+		struct ub_ep *ep = &device->ep[i];
+		struct ub_ep_disconnect *ep_disconnect =
+						&device->ep_disconnect[i];
+		return_value = ub_ep_init(ep, device);
+		if (return_value != 0)
+			goto exit_no_ep;
+		ub_callback_init(&ep_disconnect->callback,
+					ub_device_ep_disconnect_callback);
+		ep_disconnect->device = device;
+	}
+	return_value = ub_xb_channel_init(&device->channel);
+	if (return_value != 0)
+		goto exit_no_channel;
+	return_value = ub_gw_init(&device->gw,
+			ub_xb_channel_to_channel(&device->channel),
+			ub_device_gw_connect,
+			ub_device_gw_tra,
+			ub_device_gw_disconnect);
+	if (return_value != 0)
+		goto exit_no_gw;
+	return_value = xenbus_transaction_start(&tra);
+	if (return_value != 0) {
+		trace_info("Error starting tra.");
+		goto exit_no_tra;
+	}
+	return_value = xenbus_gather(tra, dev->nodename, "path", NULL,
+							&device->path, NULL);
+	(void)xenbus_transaction_end(tra, 1);
+	if (return_value < 0) {
+		trace_info("Failed to gather configuration parameters.");
+		goto exit_no_path;
+	}
+	trace_info("path:%s", device->path);
+	down_write(&ub_device_list_sem);
+	list_add_tail(&device->link, &ub_device_list);
+	up_write(&ub_device_list_sem);
+	bus_rescan_devices(&usb_bus_type);
+	ub_xb_channel_connect(&device->channel, dev);
+	return 0;
+ exit_path:
+	ub_xb_channel_disconnect(&device->channel);
+	down_write(&ub_device_list_sem);
+	list_del_init(&device->link);
+	up_write(&ub_device_list_sem);
+	spin_lock_irq(&device->lock);
+	if (device->usbdev_is_connected) {
+		usb_get_dev(device->usbdev);
+		spin_unlock_irq(&device->lock);
+		usb_lock_device(device->usbdev);
+		down_write(&usb_bus_type.subsys.rwsem);
+		if (device->usbdev_is_connected)
+			usb_driver_release_interface(
+					&ub_device_usb_driver,
+					usb_ifnum_to_if(device->usbdev, 0));
+		up_write(&usb_bus_type.subsys.rwsem);
+		usb_unlock_device(device->usbdev);
+		usb_put_dev(device->usbdev);
+		spin_lock_irq(&device->lock);
+	}
+	spin_unlock_irq(&device->lock);
+	kfree(device->path);
+ exit_no_path:
+ exit_no_tra:
+	ub_gw_exit(&device->gw);
+ exit_no_gw:
+	ub_xb_channel_exit(&device->channel);
+ exit_no_channel:
+ exit_no_ep:
+	for( i--; i > 0; i-- ){
+		struct ub_ep *ep = &device->ep[i];
+		ub_ep_exit(ep);
+	}
+	return return_value;
+}
+
+static int ub_device_init(struct ub_device *device, struct xenbus_device *dev)
+{
+	trace();
+	return ub_device_init_or_exit(device, dev, 0);
+}
+
+static void ub_device_exit(struct ub_device *device)
+{
+	trace();
+	(void)ub_device_init_or_exit(device, NULL, 1);
+}
+
+static int
+ub_device_probe_or_remove_xenbus_device(struct xenbus_device *dev, int remove)
+{
+	int return_value = 0;
+	struct ub_device *device;
+	trace();
+	if (remove)
+		goto remove_path;
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (device == NULL) {
+		xenbus_dev_error(dev, -ENOMEM, "allocating device structure");
+		return_value = -ENOMEM;
+		goto exit_no_device;
+	}
+	dev->dev.driver_data = device;
+	return_value = ub_device_init(device, dev);
+	if (return_value != 0)
+		goto exit_no_init;
+	return 0;
+ remove_path:
+	device = dev->dev.driver_data;
+	ub_device_exit(device);
+ exit_no_init:
+	dev->dev.driver_data = NULL;
+	kfree(device);
+ exit_no_device:
+	return return_value;
+}
+
+static int ub_device_probe_xenbus_device(struct xenbus_device *dev,
+const struct xenbus_device_id *id)
+{
+	trace();
+	return ub_device_probe_or_remove_xenbus_device(dev, 0);
+}
+
+static int ub_device_remove_xenbus_device(struct xenbus_device *dev)
+{
+	trace();
+	return ub_device_probe_or_remove_xenbus_device(dev, 1);
+}
+
+static void
+ub_device_frontend_changed(struct xenbus_device *dev, XenbusState state)
+{
+	struct ub_device *device = dev->dev.driver_data;
+	trace();
+	ub_xb_channel_frontend_changed(&device->channel, dev, state);
+}
+
+static struct usb_device_id ub_device_usb_id_table[] = {
+	{.driver_info = 1},	/* Matches all devices. */
+	{}
+};
+
+static struct usb_driver ub_device_usb_driver = {
+	.name       = "ub",
+	.probe      = ub_device_probe_usb_device,
+	.disconnect = ub_device_disconnect_usb_device,
+	.id_table   = ub_device_usb_id_table,
+};
+
+static struct xenbus_device_id ub_device_xenbus_ids[] = {
+	{"usbport"},
+	{""}
+};
+
+static struct xenbus_driver ub_device_xenbus_driver = {
+	.name             = "usbport",
+	.owner            = THIS_MODULE,
+	.ids              = ub_device_xenbus_ids,
+	.probe            = ub_device_probe_xenbus_device,
+	.remove           = ub_device_remove_xenbus_device,
+	.otherend_changed = ub_device_frontend_changed,
+};
+
+static int __init ub_device_class_init(void)
+{
+	int return_value = 0;
+	trace();
+	return_value = ub_ep_class_init();
+	if (return_value != 0)
+		goto exit_no_ep_class;
+	return_value = usb_register(&ub_device_usb_driver);
+	if (return_value != 0)
+		goto exit_no_usb_register;
+	return_value = xenbus_register_backend(&ub_device_xenbus_driver);
+	if (return_value != 0)
+		goto exit_no_xenbus_register;
+	return 0;
+ exit_no_xenbus_register:
+	usb_deregister(&ub_device_usb_driver);
+ exit_no_usb_register:
+	ub_ep_class_exit();
+ exit_no_ep_class:
+	return return_value;
+}
+
+__initcall(ub_device_class_init);
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_device.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_device.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,28 @@
+/*****************************************************************************/
+/* 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 UB_DEVICE_H
+#define UB_DEVICE_H
+
+struct ub_device;
+
+domid_t ub_device_query_remote_domain(struct ub_device *device);
+struct usb_device * ub_device_query_usbdev(struct ub_device *device);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_ep.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_ep.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,416 @@
+/*****************************************************************************/
+/* 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@xxxxxxxxxxxxxxx>
+
+    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/err.h>
+#include <linux/init.h>
+#include <linux/rwsem.h>
+#include <linux/usb.h>
+#include <xen/interface/io/usbif.h>
+#include <xen/xenbus.h>
+#include "ub_device.h"
+#include "ub_ep.h"
+#include "ub_trace.h"
+#include "ub_xb_channel.h"
+
+/* Between disconnect and connect we purge requests with an error indicating */
+/* the device is disconnected.  It either is really disconnected or the      */
+/* gateway is disconnected in which case the FE will not see the error code. */
+/* When connected, we submit requests maintaining submission order.          */
+/* If an IO completes with an error then we are notified before the          */
+/* completion returns to the usb stack allowing us to purge all outstanding  */
+/* requests whilst the URB queue is stalled. In this case requests are       */
+/* purged indicating they have been unlinked so the FE can requeue them and  */
+/* if necessary resubmit after outstanding FE error completions are          */
+/* quiesced.                                                                 */
+/* Explicit unlinks in the FE result in a request to stall the endpoint. All */
+/* queued URBs are unlinked and returned.  The FE can again resubmit any as  */
+/* necessary.                                                                */
+/* The FE can distinguish between which URBs have been intentionally         */
+/* unlinked by the FE and which have been unlinked as a consequence of an    */
+/* unlink or error since the FE sees all FE unlink requests and knows which  */
+/* are which.                                                                */
+/* After an error or unlink, the endpoint stalls and subsequent requests     */
+/* are purged with an unlinked error until one arrives with the clear stall  */
+/* flag set when we go back to normal operation.                             */
+/* If the gateway disconnects then we purge and wait for quiesce before      */
+/* completing the gateway disconnect.                                        */
+
+typedef enum {
+	ub_ep_stimulus_cn, /* Connect                                      */
+	ub_ep_stimulus_dn, /* Disconnect                                   */
+	ub_ep_stimulus_tc, /* tra queued with clear stall flag             */
+	ub_ep_stimulus_tq, /* tra queued without clear stall flag          */
+	ub_ep_stimulus_rc, /* rsrc completed                               */
+	ub_ep_stimulus_st, /* stall                                        */
+	ub_ep_stimulus_ri  /* test_io rsrcs idle (reent)                   */
+} ub_ep_stimulus;
+
+static void ub_ep_handle_stimulus(struct ub_ep *ep, ub_ep_stimulus stimulus);
+
+domid_t ub_ep_query_remote_domain(struct ub_ep *ep)
+{
+	trace();
+	return ub_device_query_remote_domain(ep->device);
+}
+
+struct usb_device *ub_ep_query_usbdev(struct ub_ep *ep)
+{
+	trace();
+	return ub_device_query_usbdev(ep->device);
+}
+
+void ub_ep_connect(struct ub_ep *ep)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&ep->lock, flags);
+	ub_ep_handle_stimulus(ep, ub_ep_stimulus_cn);
+	spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+void ub_ep_disconnect(struct ub_ep *ep, struct ub_callback *callback)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&ep->lock, flags);
+	ep->disconnect_callback = callback;
+	ub_ep_handle_stimulus(ep, ub_ep_stimulus_dn);
+	spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+void ub_ep_handle_io(struct ub_ep *ep, struct ub_gw_tra *tra)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&ep->lock, flags);
+	list_add_tail(ub_gw_tra_to_link(tra), &ep->tra_list);
+	if (tra->parameters.io.header.flags & USBIF_IO_FLAGS_CLEAR_STALL)
+		ub_ep_handle_stimulus(ep, ub_ep_stimulus_tc);
+	else
+		ub_ep_handle_stimulus(ep, ub_ep_stimulus_tq);
+	spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+void ub_ep_stall(struct ub_ep *ep)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&ep->lock, flags);
+	ub_ep_handle_stimulus(ep, ub_ep_stimulus_st);
+	spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static void ub_ep_invalid_stimulus(struct ub_ep *ep, ub_ep_stimulus stimulus)
+{
+	trace();
+	printk(KERN_ERR "ub: ep %p in state %d"
+	     " received invalid stimulus %d", ep, ep->state, stimulus);
+}
+
+static void ub_ep_purge_io(struct ub_ep *ep, usbif_error error)
+{
+	int i;
+	trace();
+	while (!list_empty(&ep->tra_list)) {
+		struct ub_gw_tra *tra = list_entry(ep->tra_list.next,
+				struct ub_gw_tra, callback.work.link);
+		list_del_init(ub_gw_tra_to_link(tra));
+		ub_gw_tra_complete(tra, error);
+	}
+	for (i = 0; i < UB_EP_QUOTA; i++) {
+		struct ub_rsrc *rsrc = ep->rsrcs[i];
+		ub_rsrc_flush_io(rsrc);
+	}
+}
+
+static void ub_ep_test_io(struct ub_ep *ep)
+{
+	trace();
+	if (ep->rsrcs_out == 0)
+		ub_ep_handle_stimulus(ep, ub_ep_stimulus_ri);
+}
+
+static void ub_ep_kick_io(struct ub_ep *ep)
+{
+	trace();
+	while (!list_empty(&ep->tra_list) &&
+				!list_empty(&ep->free_rsrc_list)) {
+		struct ub_gw_tra *tra = list_entry(ep->tra_list.next,
+				struct ub_gw_tra, callback.work.link);
+		struct ub_rsrc *rsrc = list_entry(
+				ep->free_rsrc_list.next,
+				struct ub_rsrc, link);
+		list_del_init(ub_gw_tra_to_link(tra));
+		list_del_init(&rsrc->link);
+		ep->rsrcs_out++;
+		ub_rsrc_start_io(rsrc, tra);
+	}
+}
+
+void ub_ep_rsrc_completed_io(struct ub_ep *ep, struct ub_rsrc *rsrc)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&ep->lock, flags);
+	list_add(&rsrc->link, &ep->free_rsrc_list);
+	ep->rsrcs_out--;
+	ub_ep_handle_stimulus(ep, ub_ep_stimulus_rc);
+	spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static void ub_ep_complete_disconnect(struct ub_ep *ep)
+{
+	trace();
+	ub_callback_success(ep->disconnect_callback);
+}
+
+static void ub_ep_handle_stimulus(struct ub_ep *ep, ub_ep_stimulus stimulus)
+{
+	trace_info("ep %p in state %d received stimulus %d", ep,
+						ep->state, stimulus);
+	switch (ep->state) {
+	case ub_ep_state_i:
+		/* Disconnected               */
+		/* I/Os idle                  */
+		/* Disconnect not outstanding */
+		switch (stimulus) {
+		case ub_ep_stimulus_cn:
+			ep->state = ub_ep_state_i_cn;
+			break;
+		case ub_ep_stimulus_tc:
+		case ub_ep_stimulus_tq:
+			ub_ep_purge_io(ep, USBIF_ERROR_DISCONNECT);
+			break;
+		case ub_ep_stimulus_st:
+			break;
+		default:
+			ub_ep_invalid_stimulus(ep, stimulus);
+			break;
+		}
+		break;
+	case ub_ep_state_i_cn:
+		/* Connected                  */
+		/* Maybe I/Os in progress     */
+		/* Disconnect not outstanding */
+		switch (stimulus) {
+		case ub_ep_stimulus_dn:
+			ep->state = ub_ep_state_i_cn_dn;
+			ub_ep_purge_io(ep, USBIF_ERROR_DISCONNECT);
+			ub_ep_test_io(ep);
+			break;
+		case ub_ep_stimulus_tc:
+		case ub_ep_stimulus_tq:
+		case ub_ep_stimulus_rc:
+			ub_ep_kick_io(ep);
+			break;
+		case ub_ep_stimulus_st:
+			ep->state = ub_ep_state_i_cn_er;
+			ub_ep_purge_io(ep, USBIF_ERROR_UNLINKED);
+			break;
+		default:
+			ub_ep_invalid_stimulus(ep, stimulus);
+			break;
+		}
+		break;
+	case ub_ep_state_i_cn_dn:
+		/* Connected                     */
+		/* I/Os in progress/Testing I/Os */
+		/* Disconnect outstanding        */
+		switch (stimulus) {
+		case ub_ep_stimulus_tc:
+		case ub_ep_stimulus_tq:
+		case ub_ep_stimulus_rc:
+			ub_ep_purge_io(ep, USBIF_ERROR_DISCONNECT);
+			ub_ep_test_io(ep);
+			break;
+		case ub_ep_stimulus_st:
+			break;
+		case ub_ep_stimulus_ri:
+			ep->state = ub_ep_state_i;
+			ub_ep_complete_disconnect(ep);
+			break;
+		default:
+			ub_ep_invalid_stimulus(ep, stimulus);
+			break;
+		}
+		break;
+	case ub_ep_state_i_cn_er:
+		/* Connected                  */
+		/* Maybe I/Os in progress     */
+		/* Disconnect not outstanding */
+		/* Stalling                   */
+		switch (stimulus) {
+		case ub_ep_stimulus_dn:
+			ep->state = ub_ep_state_i_cn_dn;
+			ub_ep_purge_io(ep, USBIF_ERROR_DISCONNECT);
+			ub_ep_test_io(ep);
+			break;
+		case ub_ep_stimulus_tc:
+			ep->state = ub_ep_state_i_cn;
+			ub_ep_kick_io(ep);
+			break;
+		case ub_ep_stimulus_tq:
+			ub_ep_purge_io(ep, USBIF_ERROR_UNLINKED);
+			break;
+		case ub_ep_stimulus_rc:
+		case ub_ep_stimulus_st:
+			break;
+		default:
+			ub_ep_invalid_stimulus(ep, stimulus);
+			break;
+		}
+		break;
+	default:
+		ub_ep_invalid_stimulus(ep, stimulus);
+		break;
+	}
+}
+
+static int
+ub_ep_init_or_exit(struct ub_ep *ep, struct ub_device *device, int exit)
+{
+	int return_value = 0, i = UB_EP_QUOTA;
+	trace();
+	if (exit)
+		goto exit_path;
+	ep->device = device;
+	spin_lock_init(&ep->lock);
+	ep->state = ub_ep_state_i;
+	ep->rsrcs_out = 0;
+	INIT_LIST_HEAD(&ep->tra_list);
+	INIT_LIST_HEAD(&ep->free_rsrc_list);
+	for (i = 0; i < UB_EP_QUOTA; i++) {
+		ep->rsrcs[i]=kzalloc(sizeof(struct ub_rsrc),GFP_KERNEL);
+		if (ep->rsrcs[i]==NULL) {
+			return_value = -ENOMEM;
+			goto exit_no_rsrc;
+		}
+	}
+	for (i = 0; i < UB_EP_QUOTA; i++) {
+		struct ub_rsrc *rsrc = ep->rsrcs[i];
+		return_value = ub_rsrc_init(rsrc, ep);
+		if (return_value != 0)
+			goto exit_no_rsrc_init;
+		list_add(&rsrc->link, &ep->free_rsrc_list);
+	}
+	return 0;
+ exit_path:
+ exit_no_rsrc_init:
+	while (!list_empty(&ep->free_rsrc_list)) {
+		struct ub_rsrc *rsrc = list_entry(ep->free_rsrc_list.next,
+					struct ub_rsrc, link);
+		list_del_init(&rsrc->link);
+		ub_rsrc_exit(rsrc);
+	}
+ exit_no_rsrc:
+	for(i--;i>=0;i--)
+		kfree(ep->rsrcs[i]);
+	return return_value;
+}
+
+int ub_ep_init(struct ub_ep *ep, struct ub_device *device)
+{
+	trace();
+	return ub_ep_init_or_exit(ep, device, 0);
+}
+
+void ub_ep_exit(struct ub_ep *ep)
+{
+	trace();
+	(void)ub_ep_init_or_exit(ep, NULL, 1);
+}
+
+int __init ub_ep_class_init(void)
+{
+	trace();
+	return ub_rsrc_class_init();
+}
+
+void ub_ep_class_exit(void)
+{
+	trace();
+	ub_rsrc_class_exit();
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_ep.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_ep.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,57 @@
+/*****************************************************************************/
+/* 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 UB_EP_H
+#define UB_EP_H
+
+#include "ub_rsrc.h"
+
+#define UB_EP_QUOTA 4
+
+typedef enum {
+	ub_ep_state_i,
+	ub_ep_state_i_cn,
+	ub_ep_state_i_cn_dn,
+	ub_ep_state_i_cn_er
+} ub_ep_state;
+
+struct ub_ep {
+	struct ub_device   *device;
+	spinlock_t          lock;
+	ub_ep_state         state;
+	unsigned long       rsrcs_out;
+	struct list_head    tra_list;
+	struct list_head    free_rsrc_list;
+	struct ub_rsrc     *rsrcs[UB_EP_QUOTA];
+	struct ub_callback *disconnect_callback;
+};
+
+domid_t ub_ep_query_remote_domain(struct ub_ep *ep);
+struct usb_device *ub_ep_query_usbdev(struct ub_ep *ep);
+void ub_ep_connect(struct ub_ep *ep);
+void ub_ep_disconnect(struct ub_ep *ep,struct ub_callback *callback);
+void ub_ep_handle_io(struct ub_ep *ep, struct ub_gw_tra *tra);
+void ub_ep_stall(struct ub_ep *ep);
+void ub_ep_rsrc_completed_io(struct ub_ep *ep, struct ub_rsrc *rsrc);
+int ub_ep_init(struct ub_ep *ep, struct ub_device *device);
+void ub_ep_exit(struct ub_ep *ep);
+int ub_ep_class_init(void);
+void ub_ep_class_exit(void);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_gw.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_gw.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,466 @@
+/*****************************************************************************/
+/* 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 "ub_gw.h"
+#include "ub_trace.h"
+
+typedef enum {
+	ub_gw_stimulus_cc, /* Channel connect.                 */
+	ub_gw_stimulus_cm, /* Channel message.                 */
+	ub_gw_stimulus_cd, /* Channel disconnect.              */
+	ub_gw_stimulus_kc, /* Kick channel messages completed. */
+	ub_gw_stimulus_tc, /* Target rsrc completed.           */
+	ub_gw_stimulus_ti, /* Target rsrcs idle.               */
+	ub_gw_stimulus_lc, /* Client connect completed.        */
+	ub_gw_stimulus_lg, /* Client disconnect called.        */
+	ub_gw_stimulus_ld, /* Client disconnect completed.     */
+} ub_gw_stimulus;
+
+static void ub_gw_handle_stimulus(struct ub_gw *gw,
+ub_gw_stimulus stimulus);
+
+static void ub_gw_channel_connect(void *context)
+{
+	struct ub_gw *gw = context;
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&gw->lock, flags);
+	ub_gw_handle_stimulus(gw, ub_gw_stimulus_cc);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void ub_gw_handle_channel_message(void *context,
+struct ub_channel_ibmsg *message)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	struct ub_gw *gw = context;
+	unsigned long flags;
+	spin_lock_irqsave(&gw->lock, flags);
+	list_add_tail(ub_channel_ibmsg_to_link(message),
+					&gw->channel_message_list);
+	ub_gw_handle_stimulus(gw,ub_gw_stimulus_cm);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void
+ub_gw_channel_disconnect(void *context, struct ub_callback *callback)
+{
+	struct ub_gw *gw = context;
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&gw->lock, flags);
+	gw->channel_disconnect_callback = callback;
+	ub_gw_handle_stimulus(gw, ub_gw_stimulus_cd);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+void ub_gw_submit_channel_message(struct ub_gw *gw,
+struct ub_channel_obmsg *message)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	ub_channel_submit_message(gw->channel, message);
+}
+
+void ub_gw_submit_tra_to_client(struct ub_gw *gw,
+struct ub_gw_tra *tra)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	gw->handle_tra(gw, tra);
+}
+
+static void ub_gw_invalid_stimulus(struct ub_gw *gw,
+ub_gw_stimulus stimulus)
+{
+	trace();
+	printk(KERN_ERR "ub: gw %p in state %d"
+		     "received invalid stimulus %d", gw, gw->state, stimulus);
+}
+
+static void
+ub_gw_kick_channel_messages(struct ub_gw *gw)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	if (!gw->kick_channel_messages_out) {
+		gw->kick_channel_messages_out = 1;
+		(void)ub_work_schedule(&gw->kick_channel_messages_1_work);
+	}
+}
+
+static void ub_gw_kick_channel_messages_1(void *data)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	struct ub_gw *gw = data;
+	unsigned long flags;
+	spin_lock_irqsave(&gw->lock, flags);
+	while ((!list_empty(&gw->channel_message_list)) &&
+		(!list_empty(&gw->target_rsrc_list))) {
+		usbif_error error = USBIF_ERROR_SUCCESS;
+		struct ub_channel_ibmsg *message;
+		struct ub_gw_rsrc *rsrc;
+		message = list_entry(gw->channel_message_list.next,
+					struct ub_channel_ibmsg,
+					callback.work.link);
+		rsrc = list_entry(gw->target_rsrc_list.next,
+					struct ub_gw_rsrc,
+					callback.work.link);
+		list_del_init(ub_channel_ibmsg_to_link(message));
+		list_del_init(ub_gw_rsrc_to_link(rsrc));
+		gw->target_rsrcs_out++;
+		spin_unlock_irqrestore(&gw->lock, flags);
+		ub_gw_rsrc_start_tra(rsrc, &message->request);
+		spin_lock_irqsave(&gw->lock, flags);
+		ub_callback_complete(ub_channel_ibmsg_to_callback(
+							message), error);
+	}
+	gw->kick_channel_messages_out = 0;
+	ub_gw_handle_stimulus(gw, ub_gw_stimulus_kc);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void
+ub_gw_kick_channel_messages_2(struct ub_callback *callback)
+{
+	struct ub_gw_rsrc *rsrc = ub_gw_rsrc_callback_to(callback);
+	struct ub_gw *gw = ub_gw_rsrc_query_gw(rsrc);
+	unsigned long flags;
+	spin_lock_irqsave(&gw->lock, flags);
+	list_add_tail(ub_gw_rsrc_to_link(rsrc), &gw->target_rsrc_list);
+	if (--gw->target_rsrcs_out != 0) {
+		ub_gw_handle_stimulus(gw, ub_gw_stimulus_tc);
+	} else {
+		ub_gw_handle_stimulus(gw, ub_gw_stimulus_ti);
+	}
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void ub_gw_complete_channel_messages(struct ub_gw *gw)
+{
+	trace();
+	while (!list_empty(&gw->channel_message_list)) {
+		struct ub_channel_ibmsg *message = list_entry(
+			gw->channel_message_list.next,
+			struct ub_channel_ibmsg,
+			callback.work.link);
+		list_del_init(ub_channel_ibmsg_to_link(message));
+		ub_callback_success(ub_channel_ibmsg_to_callback(
+								message));
+	}
+}
+
+static void ub_gw_connect_client(struct ub_gw *gw)
+{
+	trace();
+	(void)ub_work_schedule(&gw->connect_client_1_work);
+}
+
+static void ub_gw_connect_client_1(void *data)
+{
+	struct ub_gw *gw = data;
+	unsigned long flags;
+	trace();
+	gw->connect(gw);
+	spin_lock_irqsave(&gw->lock, flags);
+	ub_gw_handle_stimulus(gw, ub_gw_stimulus_lc);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void ub_gw_disconnect_client(struct ub_gw *gw)
+{
+	trace();
+	(void)ub_work_schedule(&gw->disconnect_client_1_work);
+}
+
+static void ub_gw_disconnect_client_1(void *data)
+{
+	struct ub_gw *gw = data;
+	unsigned long flags;
+	trace();
+	gw->disconnect(gw, &gw->disconnect_client_2_callback);
+	spin_lock_irqsave(&gw->lock, flags);
+	ub_gw_handle_stimulus(gw, ub_gw_stimulus_lg);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void ub_gw_disconnect_client_2(struct ub_callback *callback)
+{
+	struct ub_gw *gw = container_of(callback, struct ub_gw,
+						disconnect_client_2_callback);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&gw->lock, flags);
+	ub_gw_handle_stimulus(gw, ub_gw_stimulus_ld);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void ub_gw_test_target_rsrcs(struct ub_gw *gw)
+{
+	trace();
+	if (gw->target_rsrcs_out == 0)
+		ub_gw_handle_stimulus(gw, ub_gw_stimulus_ti);
+}
+
+static void ub_gw_complete_channel_disconnect(struct ub_gw *gw)
+{
+	trace();
+	ub_callback_success(gw->channel_disconnect_callback);
+}
+
+static int ub_gw_init_or_exit(struct ub_gw *gw, int exit)
+{
+	int return_value = 0;
+	u32 i;
+	trace();
+	if (exit)
+		goto exit_path;
+	INIT_LIST_HEAD(&gw->target_rsrc_list);
+	for (i = 0; i < USBIF_QUOTA; i++) {
+		struct ub_gw_rsrc *rsrc = &gw->target_rsrcs[i];
+		ub_gw_rsrc_init(rsrc, gw,
+					ub_gw_kick_channel_messages_2);
+		list_add_tail(ub_gw_rsrc_to_link(rsrc),
+					&gw->target_rsrc_list);
+	}
+	spin_lock_init(&gw->lock);
+	gw->state = ub_gw_state_i;
+	INIT_LIST_HEAD(&gw->channel_message_list);
+	ub_work_init(&gw->kick_channel_messages_1_work,
+			ub_gw_kick_channel_messages_1, gw);
+	ub_work_init(&gw->connect_client_1_work,
+			ub_gw_connect_client_1, gw);
+	ub_work_init(&gw->disconnect_client_1_work,
+			ub_gw_disconnect_client_1, gw);
+	ub_callback_init(&gw->disconnect_client_2_callback,
+			ub_gw_disconnect_client_2);
+	gw->kick_channel_messages_out = 0;
+	gw->target_rsrcs_out = 0;
+	return 0;
+ exit_path:
+	return return_value;
+}
+
+int ub_gw_init(struct ub_gw *gw, struct ub_channel *channel,
+ub_gw_connect_function *connect,
+ub_gw_handle_tra_function *handle_tra,
+ub_gw_disconnect_function *disconnect)
+{
+	trace();
+	gw->channel = channel;
+	gw->connect = connect;
+	gw->handle_tra = handle_tra;
+	gw->disconnect = disconnect;
+	ub_channel_install_client(channel, gw,
+					ub_gw_channel_connect,
+					ub_gw_handle_channel_message,
+					ub_gw_channel_disconnect);
+	return ub_gw_init_or_exit(gw, 0);
+}
+
+void ub_gw_exit(struct ub_gw *gw)
+{
+	trace();
+	(void)ub_gw_init_or_exit(gw, 1);
+}
+
+static void
+ub_gw_handle_stimulus(struct ub_gw *gw,
+ub_gw_stimulus stimulus)
+{
+	switch (gw->state) {
+	case ub_gw_state_i:
+		/* Channel disconnected.       */
+		/* Client disconnected.        */
+		/* No channel messages queued. */
+		/* Target rsrcs idle.          */
+		/* Not kicking cm.             */
+		switch (stimulus) {
+		case ub_gw_stimulus_cc:
+			gw->state = ub_gw_state_i_cc;
+			ub_gw_connect_client(gw);
+			break;
+		default:
+			ub_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case ub_gw_state_i_cc:
+		/* Channel connected.             */
+		/* Client connecting.             */
+		/* Maybe channel messages queued. */
+		/* Target rsrcs idle.             */
+		/* Not kicking cm.                */
+		switch (stimulus) {
+		case ub_gw_stimulus_cm:
+			break;
+		case ub_gw_stimulus_cd:
+			gw->state = ub_gw_state_i_cc_cd;
+			ub_gw_complete_channel_messages(gw);
+			break;
+		case ub_gw_stimulus_lc:
+			gw->state = ub_gw_state_i_cc_lc;
+			ub_gw_kick_channel_messages(gw);
+			break;
+		default:
+			ub_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case ub_gw_state_i_cc_cd:
+		/* Channel disconnecting.      */
+		/* Client connecting.          */
+		/* No channel messages queued. */
+		/* Target rsrcs idle.          */
+		/* Not kicking cm.             */
+		switch (stimulus) {
+		case ub_gw_stimulus_lc:
+			gw->state = ub_gw_state_i_cc_cd_lc;
+			ub_gw_disconnect_client(gw);
+			break;
+		default:
+			ub_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case ub_gw_state_i_cc_lc:
+		/* Channel connected.             */
+		/* Client connected.              */
+		/* Maybe channel messages queued. */
+		/* Maybe target rsrcs busy.       */
+		/* Maybe kicking cm.              */
+		switch (stimulus) {
+		case ub_gw_stimulus_cm:
+			ub_gw_kick_channel_messages(gw);
+			break;
+		case ub_gw_stimulus_cd:
+			gw->state = ub_gw_state_i_cc_lc_cd;
+			ub_gw_complete_channel_messages(gw);
+			ub_gw_kick_channel_messages(gw);
+			break;
+		case ub_gw_stimulus_kc:
+			break;
+		case ub_gw_stimulus_tc:
+		case ub_gw_stimulus_ti:
+			ub_gw_kick_channel_messages(gw);
+			break;
+		default:
+			ub_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case ub_gw_state_i_cc_lc_cd:
+		/* Channel disconnecting.      */
+		/* Client connected.           */
+		/* No channel messages queued. */
+		/* Maybe target rsrcs busy.    */
+		/* Kicking cm.                 */
+		switch (stimulus) {
+		case ub_gw_stimulus_kc:
+			gw->state = ub_gw_state_i_cc_cd_lc;
+			ub_gw_disconnect_client(gw);
+			break;
+		case ub_gw_stimulus_tc:
+		case ub_gw_stimulus_ti:
+			break;
+		default:
+			ub_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case ub_gw_state_i_cc_cd_lc:
+		/* Channel disconnecting.      */
+		/* Calling client disconnect.  */
+		/* No channel messages queued. */
+		/* Maybe target rsrcs busy.    */
+		/* Not kicking cm.             */
+		switch (stimulus) {
+		case ub_gw_stimulus_tc:
+		case ub_gw_stimulus_ti:
+			break;
+		case ub_gw_stimulus_lg:
+			gw->state = ub_gw_state_i_cc_cd_lc_lg;
+			break;
+		case ub_gw_stimulus_ld:
+			gw->state = ub_gw_state_i_cc_cd_lc_ld;
+			break;
+		default:
+			ub_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case ub_gw_state_i_cc_cd_lc_lg:
+		/* Channel disconnecting.      */
+		/* Client disconnecting.       */
+		/* No channel messages queued. */
+		/* Maybe target rsrcs busy.    */
+		/* Not kicking cm.             */
+		switch (stimulus) {
+		case ub_gw_stimulus_tc:
+		case ub_gw_stimulus_ti:
+			break;
+		case ub_gw_stimulus_ld:
+			gw->state = ub_gw_state_i_cc_cd_lc_lg_ld;
+			ub_gw_test_target_rsrcs(gw);
+			break;
+		default:
+			ub_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case ub_gw_state_i_cc_cd_lc_ld:
+		/* Channel disconnecting.                          */
+		/* Client disconnected but call still in progress. */
+		/* No channel messages queued.                     */
+		/* Maybe target rsrcs busy.                        */
+		/* Not kicking cm.                                 */
+		switch (stimulus) {
+		case ub_gw_stimulus_tc:
+		case ub_gw_stimulus_ti:
+			break;
+		case ub_gw_stimulus_lg:
+			gw->state =
+					ub_gw_state_i_cc_cd_lc_lg_ld;
+			ub_gw_test_target_rsrcs(gw);
+			break;
+		default:
+			ub_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case ub_gw_state_i_cc_cd_lc_lg_ld:
+		/* Channel disconnecting.                  */
+		/* Client disconnected.                    */
+		/* No channel messages queued.             */
+		/* Test target rsrcs or target rsrcs busy. */
+		/* Not kicking cm.                         */
+		switch (stimulus) {
+		case ub_gw_stimulus_tc:
+			break;
+		case ub_gw_stimulus_ti:
+			gw->state = ub_gw_state_i;
+			ub_gw_complete_channel_disconnect(gw);
+			break;
+		default:
+			ub_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	default:
+		ub_gw_invalid_stimulus(gw, stimulus);
+		break;
+	}
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_gw.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_gw.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,163 @@
+/*****************************************************************************/
+/* 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 UB_GW_H
+#define UB_GW_H
+
+#include <linux/types.h>
+#include <xen/interface/io/usbif.h>
+#include "ub_callback.h"
+#include "ub_channel.h"
+
+struct ub_gw_rsrc;
+
+struct ub_gw_tra {
+	struct ub_callback callback;
+	union usbif_parameters  parameters;
+	union usbif_status      status;
+};
+
+static inline struct ub_callback *
+ub_gw_tra_to_callback(struct ub_gw_tra *tra)
+{
+	return &tra->callback;
+}
+
+static inline struct ub_gw_tra *
+ub_gw_tra_callback_to(struct ub_callback *callback)
+{
+	return container_of(callback, struct ub_gw_tra, callback);
+}
+
+static inline struct list_head *
+ub_gw_tra_to_link(struct ub_gw_tra *tra)
+{
+	return ub_callback_to_link(ub_gw_tra_to_callback(tra));
+}
+
+static inline struct ub_gw_tra *
+ub_gw_tra_link_to(struct list_head *link)
+{
+	return ub_gw_tra_callback_to(ub_callback_link_to(link));
+}
+
+static inline void
+ub_gw_tra_init(struct ub_gw_tra *tra,
+ub_callback_function *callback)
+{
+	ub_callback_init(ub_gw_tra_to_callback(tra), callback);
+}
+
+static inline void
+ub_gw_tra_complete(struct ub_gw_tra *tra, usbif_error error)
+{
+	ub_callback_complete(ub_gw_tra_to_callback(tra), error);
+}
+
+static inline
+usbif_error ub_gw_tra_query_error(struct ub_gw_tra *tra)
+{
+	return ub_callback_query_error(ub_gw_tra_to_callback(tra));
+}
+
+struct ub_gw_rsrc {
+	struct ub_callback      callback;
+	struct ub_gw           *gw;
+	struct ub_gw_tra        tra;
+	struct ub_channel_obmsg channel_message;
+};
+
+static inline struct list_head *
+ub_gw_rsrc_to_link(struct ub_gw_rsrc *rsrc)
+{
+	return &rsrc->callback.work.link;
+}
+
+static inline struct ub_gw_rsrc *
+ub_gw_rsrc_callback_to(struct ub_callback *callback)
+{
+	return container_of(callback, struct ub_gw_rsrc, callback);
+}
+
+static inline struct ub_gw *
+ub_gw_rsrc_query_gw(struct ub_gw_rsrc *rsrc)
+{
+	return rsrc->gw;
+}
+
+void
+ub_gw_rsrc_init(struct ub_gw_rsrc *rsrc, struct ub_gw *gw,
+ub_callback_function callback);
+
+void
+ub_gw_rsrc_start_tra(struct ub_gw_rsrc *rsrc,
+struct usbif_request *request);
+
+typedef enum {
+	ub_gw_state_i,
+	ub_gw_state_i_cc,
+	ub_gw_state_i_cc_cd,
+	ub_gw_state_i_cc_lc,
+	ub_gw_state_i_cc_lc_cd,
+	ub_gw_state_i_cc_cd_lc,
+	ub_gw_state_i_cc_cd_lc_lg,
+	ub_gw_state_i_cc_cd_lc_ld,
+	ub_gw_state_i_cc_cd_lc_lg_ld
+} ub_gw_state;
+
+struct ub_gw;
+
+typedef void ub_gw_connect_function(struct ub_gw *gw);
+
+typedef void
+ub_gw_handle_tra_function(struct ub_gw *gw,
+struct ub_gw_tra *tra);
+
+typedef void
+ub_gw_disconnect_function(struct ub_gw *gw,
+struct ub_callback *callback);
+
+struct ub_gw {
+	struct ub_channel         *channel;
+	ub_gw_connect_function    *connect;
+	ub_gw_handle_tra_function *handle_tra;
+	ub_gw_disconnect_function *disconnect;
+	struct list_head                target_rsrc_list;
+	struct ub_gw_rsrc          target_rsrcs[USBIF_QUOTA];
+	spinlock_t                      lock;
+	ub_gw_state                state;
+	struct list_head                channel_message_list;
+	struct ub_work             kick_channel_messages_1_work;
+	struct ub_work             connect_client_1_work;
+	struct ub_work             disconnect_client_1_work;
+	struct ub_callback         disconnect_client_2_callback;
+	int                             kick_channel_messages_out:1;
+	u32                             target_rsrcs_out;
+	struct ub_callback        *channel_disconnect_callback;
+};
+
+int
+ub_gw_init(struct ub_gw *gw, struct ub_channel *channel,
+ub_gw_connect_function *connect,
+ub_gw_handle_tra_function *handle_tra,
+ub_gw_disconnect_function *disconnect);
+
+extern void ub_gw_exit(struct ub_gw *gw);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_gw_rsrc.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_gw_rsrc.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,75 @@
+/*****************************************************************************/
+/* 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 "ub_gw.h"
+#include "ub_trace.h"
+
+void
+ub_gw_submit_channel_message(struct ub_gw *gw,
+struct ub_channel_obmsg *message);
+
+void
+ub_gw_submit_tra_to_client(struct ub_gw *gw,
+struct ub_gw_tra *tra);
+
+void
+ub_gw_rsrc_start_tra(struct ub_gw_rsrc *rsrc,
+struct usbif_request *request)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	rsrc->tra.parameters = request->usbif_parameters;
+	memset(&rsrc->tra.status,0, sizeof(rsrc->tra.status));
+	rsrc->channel_message.response.gw_status.id =
+						request->gw_parameters.id;
+	ub_gw_submit_tra_to_client(rsrc->gw, &rsrc->tra);
+}
+
+static void
+ub_gw_rsrc_tra_callback(struct ub_callback *callback)
+{
+	struct ub_gw_rsrc *rsrc = container_of(
+		ub_gw_tra_callback_to(callback),
+		struct ub_gw_rsrc, tra);
+	rsrc->channel_message.response.gw_status.error =
+					ub_callback_query_error(callback);
+	rsrc->channel_message.response.usbif_status = rsrc->tra.status;
+	ub_gw_submit_channel_message(rsrc->gw, &rsrc->channel_message);
+}
+
+static void
+ub_gw_rsrc_channel_message_callback(struct ub_callback *callback)
+{
+	struct ub_gw_rsrc *rsrc = container_of(
+				ub_channel_obmsg_callback_to(callback),
+				struct ub_gw_rsrc,
+				channel_message);
+	ub_callback_success(&rsrc->callback);
+}
+
+void
+ub_gw_rsrc_init(struct ub_gw_rsrc *rsrc, struct ub_gw *gw,
+ub_callback_function callback)
+{
+	trace();
+	ub_callback_init(&rsrc->callback, callback);
+	rsrc->gw = gw;
+	ub_gw_tra_init(&rsrc->tra, ub_gw_rsrc_tra_callback);
+	ub_channel_obmsg_init(&rsrc->channel_message,
+				ub_gw_rsrc_channel_message_callback);
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_rbr_mapper.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_rbr_mapper.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,347 @@
+/*****************************************************************************/
+/* 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 "ub_rbr_mapper.h"
+#include "ub_trace.h"
+
+static UB_CALLBACK_SERIALISER(callback_serialiser);
+
+struct ub_rbr_mapper {
+	struct ub_buffer_rsrc_list      dedicated_rsrcs;
+	struct ub_buffer_rsrc_provider *provider;
+	spinlock_t                           lock;
+	struct ub_buffer_rsrc_list      head_request_rqm;
+	struct list_head                     request_list;
+	int                                  kicking_requests;
+	int                                  head_request_rqm_calculated;
+};
+
+static int ub_rbr_mapper_calc_rbr_rqm(struct usbif_rbr *rbr,
+struct ub_buffer_rsrc_list *list)
+{
+	int request_invalid = 0;
+	trace();
+	*list = ub_buffer_rsrc_list_null();
+	if (rbr->byte_count != 0) {
+		if ((rbr->byte_offset < (USBIF_GRANT_TABLE_REFERENCE_COUNT *
+				PAGE_SIZE)) && (rbr->byte_count <=
+				((USBIF_GRANT_TABLE_REFERENCE_COUNT *
+				PAGE_SIZE) - rbr->byte_offset))) {
+			unsigned long first_page, final_page;
+			list->page_ranges = 1;
+			first_page = rbr->byte_offset / PAGE_SIZE;
+			final_page = (rbr->byte_offset + rbr->byte_count - 1) /
+								PAGE_SIZE;
+			list->page_range_page_count = final_page -
+								first_page + 1;
+		} else {
+			request_invalid = 1;
+		}
+	}
+	return request_invalid;
+}
+
+static int
+ub_rbr_mapper_calc_rqm(struct ub_rbr_mapper_request *request,
+struct ub_buffer_rsrc_list *list)
+{
+	struct ub_rbr_mapper_element *element;
+	trace();
+	*list = ub_buffer_rsrc_list_null();
+	list_for_each_entry(element, &request->request_elements, link) {
+		struct ub_buffer_rsrc_list element_list;
+		if (ub_rbr_mapper_calc_rbr_rqm(&element->rbr,
+							&element_list) != 0)
+			return 1;
+		ub_buffer_rsrc_list_plus_equals(list, &element_list);
+	}
+	return 0;
+}
+
+static void
+ub_rbr_mapper_unmap_rbr(struct ub_rbr_context *context)
+{
+	struct gnttab_unmap_grant_ref unmap[USBIF_GRANT_TABLE_REFERENCE_COUNT];
+	int i;
+	trace();
+	for (i = 0; i < context->page_count; i++) {
+		unmap[i].host_addr = context->mmap_vaddress + (i * PAGE_SIZE);
+		unmap[i].dev_bus_addr = 0;
+		unmap[i].handle = context->handle[i];
+	}
+	if (context->page_count != 0) {
+		int error = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
+						unmap, context->page_count);
+		BUG_ON(error);
+	}
+	for (i = 0; i < context->page_count; i++) {
+		set_phys_to_machine(__pa(context->mmap_vaddress + (i *
+				PAGE_SIZE)) >> PAGE_SHIFT, INVALID_P2M_ENTRY);
+	}
+	if (context->mmap_vaddress != 0)
+		ub_buffer_rsrc_provider_free_page_range(
+				context->provider, context->mmap_vaddress);
+}
+
+static int
+ub_rbr_mapper_map_rbr(struct usbif_rbr *rbr, domid_t domain,
+struct ub_buffer_rsrc_provider *provider, void **mapping,
+int access_flags, struct ub_rbr_context *context)
+{
+	struct gnttab_map_grant_ref map[USBIF_GRANT_TABLE_REFERENCE_COUNT];
+	unsigned long first_page, final_page, page_count;
+	int i, j, error;
+	uint16_t map_flags = GNTMAP_host_map | (((access_flags &
+		UB_ACCESS_FLAGS_WRITE) == 0) ? GNTMAP_readonly : 0);
+	trace();
+	if (rbr->byte_count == 0) {
+		context->page_count    = 0;
+		context->mmap_vaddress = 0;
+		*mapping               = NULL;
+		return 0;
+	}
+	first_page = rbr->byte_offset / PAGE_SIZE;
+	final_page = (rbr->byte_offset + rbr->byte_count - 1) / PAGE_SIZE;
+	page_count = final_page - first_page + 1;
+	context->provider = provider;
+	context->page_count = page_count;
+	context->mmap_vaddress =
+			ub_buffer_rsrc_provider_allocate_page_range(
+						provider, page_count);
+	for (i = 0; i < page_count; i++) {
+		map[i].host_addr = context->mmap_vaddress + (i * PAGE_SIZE);
+		map[i].dom       = domain;
+		map[i].ref       = rbr->reference[first_page + i];
+		map[i].flags     = map_flags;
+	}
+	error = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map,
+								page_count);
+	BUG_ON(error);
+	for (i = 0, j = 0; i < page_count; i++) {
+		if (likely(map[i].status == 0)) {
+			context->handle[j] = map[i].handle;
+			set_phys_to_machine(__pa(context->mmap_vaddress +
+							(j * PAGE_SIZE))
+					     >> PAGE_SHIFT,
+					     FOREIGN_FRAME(map[i].dev_bus_addr
+							       >> PAGE_SHIFT));
+			j++;
+		} else {
+			error = 1;
+			context->page_count--;
+		}
+	}
+	if (error) {
+		ub_rbr_mapper_unmap_rbr(context);
+		return -EINVAL;
+	}
+	*mapping = (void *)(context->mmap_vaddress + (rbr->byte_offset %
+								PAGE_SIZE));
+	return 0;
+}
+
+static void
+ub_rbr_mapper_service_request(
+struct ub_rbr_mapper *pool,
+struct ub_rbr_mapper_request *request)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	int error = 0;
+	struct ub_rbr_mapper_element *element;
+	trace();
+	list_for_each_entry(element, &request->request_elements, link) {
+		if (!error) {
+			error = ub_rbr_mapper_map_rbr(&element->rbr,
+					request->domain, pool->provider,
+					&element->mapping,
+					element->access_flags,
+					&element->context);
+			if (!error)
+				element->mapped = 1;
+		} else {
+			element->mapped = 0;
+		}
+	}
+	if (error)
+		goto error_path;
+	ub_callback_serialiser_complete_callback(&callback_serialiser,
+		ub_rbr_mapper_request_to_map_callback(request),
+		USBIF_ERROR_SUCCESS);
+	return;
+ error_path:
+	list_for_each_entry(element, &request->request_elements, link) {
+		if (element->mapped)
+			ub_rbr_mapper_unmap_rbr(&element->context);
+	}
+	ub_callback_serialiser_complete_callback(&callback_serialiser,
+	     ub_rbr_mapper_request_to_map_callback(request),
+	     usbif_error_map_local_to(error));
+}
+
+static void ub_rbr_mapper_kick_requests(
+struct ub_rbr_mapper *pool)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&pool->lock, flags);
+	while (!pool->kicking_requests && !list_empty(&pool->request_list)) {
+		struct ub_rbr_mapper_request *request =
+				ub_rbr_mapper_request_link_to(
+						pool->request_list.next);
+		struct ub_buffer_rsrc_list free_rsrcs;
+		if (pool->head_request_rqm_calculated)
+			goto skip_calc;
+		if ((ub_rbr_mapper_calc_rqm(request,
+				&pool->head_request_rqm) != 0) ||
+				!ub_buffer_rsrc_list_subset_of(
+				&pool->head_request_rqm,
+				&pool->dedicated_rsrcs)) {
+			list_del_init(ub_rbr_mapper_request_to_link(
+								request));
+			ub_callback_serialiser_complete_callback(
+				&callback_serialiser,
+				ub_rbr_mapper_request_to_map_callback(
+								request),
+				USBIF_ERROR_TOO_BIG);
+			continue;
+		}
+		pool->head_request_rqm_calculated = 1;
+	skip_calc:
+		free_rsrcs = ub_buffer_rsrc_provider_query_free_rsrcs(
+							pool->provider);
+		if (!ub_buffer_rsrc_list_subset_of(
+				&pool->head_request_rqm, &free_rsrcs))
+			break;
+		list_del_init(ub_rbr_mapper_request_to_link(request));
+		pool->head_request_rqm_calculated = 0;
+		pool->kicking_requests = 1;
+		spin_unlock_irqrestore(&pool->lock, flags);
+		ub_rbr_mapper_service_request(pool, request);
+		spin_lock_irqsave(&pool->lock, flags);
+		pool->kicking_requests = 0;
+	}
+	spin_unlock_irqrestore(&pool->lock, flags);
+}
+
+void
+ub_rbr_mapper_reserve_and_map_rbrs(
+struct ub_rbr_mapper *pool,
+struct ub_rbr_mapper_request *request, domid_t domain)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	unsigned long flags;
+	trace();
+	request->pool = pool;
+	request->domain = domain;
+	spin_lock_irqsave(&pool->lock, flags);
+	list_add_tail(ub_rbr_mapper_request_to_link(request),
+							&pool->request_list);
+	spin_unlock_irqrestore(&pool->lock, flags);
+	ub_rbr_mapper_kick_requests(pool);
+}
+
+void
+ub_rbr_mapper_abort_reserve_and_map_rbrs(
+struct ub_rbr_mapper_request *request, usbif_error error)
+{
+	struct ub_rbr_mapper *pool = request->pool;
+	struct ub_rbr_mapper_request *queued_request;
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&pool->lock, flags);
+	list_for_each_entry(queued_request, &pool->request_list,
+					map_callback.work.link) {
+		if (request == queued_request) {
+			list_del_init(ub_rbr_mapper_request_to_link(
+								request));
+			pool->head_request_rqm_calculated = 0;
+			ub_callback_serialiser_complete_callback(
+				&callback_serialiser,
+				ub_rbr_mapper_request_to_map_callback(
+							request),
+				error);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&pool->lock, flags);
+}
+
+void ub_rbr_mapper_unmap_and_unreserve_rbrs(
+struct ub_rbr_mapper_request *request)
+{
+	struct ub_rbr_mapper_element *element;
+	trace();
+	list_for_each_entry(element, &request->request_elements, link) {
+		ub_rbr_mapper_unmap_rbr(&element->context);
+	}
+	ub_rbr_mapper_kick_requests(request->pool);
+	ub_callback_serialiser_complete_callback(&callback_serialiser,
+	     ub_rbr_mapper_request_to_unmap_callback(request),
+	     USBIF_ERROR_SUCCESS);
+}
+
+static int
+ub_rbr_mapper_init_or_exit(struct ub_rbr_mapper *pool,
+int exit)
+{
+	int return_value = 0;
+	trace();
+	if (exit)
+		goto exit;
+	pool->provider = ub_allocate_buffer_rsrc_provider(
+							pool->dedicated_rsrcs);
+	if (pool->provider == NULL)
+		goto exit_no_provider;
+	spin_lock_init(&pool->lock);
+	INIT_LIST_HEAD(&pool->request_list);
+	pool->kicking_requests = 0;
+	pool->head_request_rqm_calculated = 0;
+	return 0;
+ exit:
+	ub_free_buffer_rsrc_provider(pool->provider);
+ exit_no_provider:
+	return return_value;
+}
+
+struct ub_rbr_mapper * ub_rbr_mapper_allocate(void)
+{
+	struct ub_rbr_mapper *pool;
+	trace();
+	pool = (struct ub_rbr_mapper *)kmalloc(sizeof(
+				struct ub_rbr_mapper),GFP_KERNEL);
+	if (pool != NULL) {
+		pool->dedicated_rsrcs.page_ranges = USBIF_QUOTA;
+		pool->dedicated_rsrcs.page_range_page_count =
+			USBIF_GRANT_TABLE_REFERENCE_COUNT;
+		if (ub_rbr_mapper_init_or_exit(pool, 0) != 0) {
+			kfree(pool);
+			pool = NULL;
+		}
+	}
+	return pool;
+}
+
+void ub_rbr_mapper_free(struct ub_rbr_mapper *pool)
+{
+	trace();
+	(void)ub_rbr_mapper_init_or_exit(pool, 1);
+	kfree(pool);
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_rbr_mapper.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_rbr_mapper.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,145 @@
+/*****************************************************************************/
+/* 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 UB_RBR_MAPPER_H
+#define UB_RBR_MAPPER_H
+
+#include "ub_callback.h"
+#include "ub_buffer_rsrc_provider.h"
+
+struct ub_rbr_mapper;
+
+struct ub_rbr_mapper *ub_rbr_mapper_allocate(void);
+
+void ub_rbr_mapper_free(struct ub_rbr_mapper *pool);
+
+#define UB_ACCESS_FLAGS_READ  1
+#define UB_ACCESS_FLAGS_WRITE 2
+
+struct ub_rbr_context {
+	struct ub_buffer_rsrc_provider *provider;
+	unsigned long                   page_count;
+	unsigned long                   mmap_vaddress;
+	grant_handle_t handle[USBIF_GRANT_TABLE_REFERENCE_COUNT];
+};
+
+struct ub_rbr_mapper_element {
+	struct list_head       link;
+	struct usbif_rbr       rbr;
+	int                    access_flags;
+	int                    mapped;
+	void                  *mapping;
+	struct ub_rbr_context  context;
+};
+
+static inline void
+ub_rbr_mapper_element_init(struct ub_rbr_mapper_element *element)
+{
+	memset(element, 0, sizeof(*element));
+	INIT_LIST_HEAD(&element->link);
+}
+
+static inline void
+ub_rbr_mapper_element_set_rbr(struct ub_rbr_mapper_element *element,
+struct usbif_rbr rbr, int access_flags)
+{
+	element->rbr          = rbr;
+	element->access_flags = access_flags;
+}
+
+static inline void
+ub_rbr_mapper_element_ensure_removed(struct ub_rbr_mapper_element *element)
+{
+	list_del_init(&element->link);
+}
+
+struct ub_rbr_mapper_request {
+	struct ub_callback    map_callback;
+	struct ub_callback    unmap_callback;
+	struct ub_rbr_mapper *pool;
+	domid_t               domain;
+	struct list_head      request_elements;
+};
+
+static inline struct ub_callback *
+ub_rbr_mapper_request_to_map_callback(struct ub_rbr_mapper_request *request)
+{
+	return &request->map_callback;
+}
+
+static inline struct ub_rbr_mapper_request *
+ub_rbr_mapper_request_map_callback_to(struct ub_callback *callback)
+{
+	return container_of(callback, struct ub_rbr_mapper_request,
+							map_callback);
+}
+
+static inline struct ub_callback *
+ub_rbr_mapper_request_to_unmap_callback(struct ub_rbr_mapper_request *request)
+{
+	return &request->unmap_callback;
+}
+
+static inline struct ub_rbr_mapper_request *
+ub_rbr_mapper_request_unmap_callback_to(struct ub_callback *callback)
+{
+	return container_of(callback, struct ub_rbr_mapper_request,
+							unmap_callback);
+}
+
+static inline struct list_head *
+ub_rbr_mapper_request_to_link(struct ub_rbr_mapper_request *request)
+{
+	return ub_callback_to_link(
+			ub_rbr_mapper_request_to_map_callback(request));
+}
+
+static inline struct ub_rbr_mapper_request *
+ub_rbr_mapper_request_link_to(struct list_head *link)
+{
+	return ub_rbr_mapper_request_map_callback_to(
+					ub_callback_link_to(link));
+}
+
+static inline void
+ub_rbr_mapper_request_init(struct ub_rbr_mapper_request *request,
+ub_callback_function *map_callback, ub_callback_function *unmap_callback)
+{
+	ub_callback_init(&request->map_callback, map_callback);
+	ub_callback_init(&request->unmap_callback, unmap_callback);
+	INIT_LIST_HEAD(&request->request_elements);
+}
+
+static inline void
+ub_rbr_mapper_request_add_element(struct ub_rbr_mapper_request *request,
+struct ub_rbr_mapper_element *element)
+{
+	list_add(&element->link, &request->request_elements);
+}
+
+void ub_rbr_mapper_reserve_and_map_rbrs(struct ub_rbr_mapper *pool,
+struct ub_rbr_mapper_request *request, domid_t domain);
+
+void ub_rbr_mapper_abort_reserve_and_map_rbrs(
+struct ub_rbr_mapper_request *request, usbif_error error);
+
+void
+ub_rbr_mapper_unmap_and_unreserve_rbrs(struct ub_rbr_mapper_request *request);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_ring_channel.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_ring_channel.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,755 @@
+/*****************************************************************************/
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redisribute 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 disributed 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/interrupt.h>
+#include <xen/interface/io/usbif.h>
+#include <xen/driver_util.h>
+#include <xen/evtchn.h>
+#include "ub_ring_channel.h"
+#include "ub_trace.h"
+
+static inline void
+ub_ring_channel_rsrc_init(struct ub_ring_channel_rsrc *rsrc,
+struct ub_ring_channel *channel, ub_callback_function *callback)
+{
+	trace();
+	ub_channel_ibmsg_init(&rsrc->message, callback);
+	rsrc->channel = channel;
+}
+
+static inline struct list_head *
+ub_ring_channel_rsrc_to_link(struct ub_ring_channel_rsrc *rsrc)
+{
+	return ub_channel_ibmsg_to_link(&rsrc->message);
+}
+
+static inline struct ub_ring_channel_rsrc *
+ub_ring_channel_rsrc_callback_to(struct ub_callback *callback)
+{
+	return container_of(ub_channel_ibmsg_callback_to(callback),
+				struct ub_ring_channel_rsrc, message);
+}
+
+typedef enum {
+	ub_ring_channel_stimulus_cn,/* connect request             */
+	ub_ring_channel_stimulus_mq,/* message queued              */
+	ub_ring_channel_stimulus_dn,/* disconnect request          */
+	ub_ring_channel_stimulus_ri,/* ring interrupt              */
+	ub_ring_channel_stimulus_cs,/* connect successful          */
+	ub_ring_channel_stimulus_cf,/* connect failed              */
+	ub_ring_channel_stimulus_cc,/* connect client completed    */
+	ub_ring_channel_stimulus_dc,/* disconnect client completed */
+	ub_ring_channel_stimulus_ds,/* disconnect successful       */
+	ub_ring_channel_stimulus_ks,/* kick send ring completed    */
+	ub_ring_channel_stimulus_kr,/* kick recv ring completed    */
+	ub_ring_channel_stimulus_rc,/* rsrc completed              */
+	ub_ring_channel_stimulus_rf /* rsrc final completion       */
+} ub_ring_channel_stimulus;
+
+static void
+ub_ring_channel_handle_stimulus(struct ub_ring_channel *channel,
+ub_ring_channel_stimulus stimulus);
+
+void
+ub_ring_channel_connect(struct ub_ring_channel *channel,
+struct ub_ring_channel_connect_request *request)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	channel->current_callback = &request->callback;
+	ub_ring_channel_handle_stimulus(channel,
+					ub_ring_channel_stimulus_cn);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+ub_ring_channel_submit_message(struct ub_channel *base_channel,
+struct ub_channel_obmsg *message)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	struct ub_ring_channel *channel = ub_ring_channel_channel_to(
+								base_channel);
+	unsigned long flags;
+	spin_lock_irqsave(&channel->lock, flags);
+	list_add_tail(ub_channel_obmsg_to_link(message),
+					&channel->message_list);
+	ub_ring_channel_handle_stimulus(channel,
+					ub_ring_channel_stimulus_mq);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+void
+ub_ring_channel_disconnect(struct ub_ring_channel *channel,
+struct ub_callback *callback)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	channel->current_callback = callback;
+	ub_ring_channel_handle_stimulus(channel, ub_ring_channel_stimulus_dn);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static irqreturn_t
+ub_ring_channel_interrupt(int irq, void *context, struct pt_regs *ptregs)
+{
+	struct ub_ring_channel *channel = context;
+	unsigned long flags;
+	spin_lock_irqsave(&channel->lock, flags);
+	ub_ring_channel_handle_stimulus(channel, ub_ring_channel_stimulus_ri);
+	spin_unlock_irqrestore(&channel->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static void
+ub_ring_channel_invalid_stimulus(struct ub_ring_channel *channel,
+ub_ring_channel_stimulus stimulus)
+{
+	trace();
+	printk(KERN_ERR "ub: channel %p in state %d"
+		"received invalid stimulus %d", channel, channel->state,
+		stimulus);
+}
+
+static void
+ub_ring_channel_do_connect(struct ub_ring_channel *channel)
+{
+	trace();
+	(void)ub_work_schedule(&channel->do_connect_1_work);
+}
+
+static void ub_ring_channel_do_connect_1(void *data)
+{
+	struct ub_ring_channel *channel = data;
+	struct ub_ring_channel_connect_request *request =
+			ub_ring_channel_connect_request_callback_to(
+						channel->current_callback);
+	struct gnttab_map_grant_ref map_op;
+	struct gnttab_unmap_grant_ref unmap_op;
+	struct evtchn_bind_interdomain bind_interdomain;
+	struct evtchn_close close;
+	struct usbif_sring *sring;
+	unsigned long flags;
+	trace();
+	memset(&map_op, 0, sizeof(map_op));
+	map_op.host_addr = (unsigned long)channel->ring_area->addr;
+	map_op.flags = GNTMAP_host_map;
+	map_op.dom = request->domain_id;
+	map_op.ref = request->ring_ref;
+	lock_vm_area(channel->ring_area);
+	BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &map_op, 1));
+	unlock_vm_area(channel->ring_area);
+	if (map_op.status != 0) {
+		trace_info("failed to map remote page");
+		goto exit_no_mapping;
+	}
+	channel->ring_handle = map_op.handle;
+	bind_interdomain.remote_dom = request->domain_id;
+	bind_interdomain.remote_port = request->event_channel;
+	if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
+					&bind_interdomain) != 0) {
+		trace_info("failed to bind to remote event channel");
+		goto exit_no_bind;
+	}
+	channel->event_channel = bind_interdomain.local_port;
+	sring = (struct usbif_sring *)channel->ring_area->addr;
+	BACK_RING_INIT(&channel->back_ring, sring, PAGE_SIZE);
+	channel->irq = bind_evtchn_to_irqhandler( channel->event_channel,
+			ub_ring_channel_interrupt, 0, "usbif-backend",
+			channel);
+	if (channel->irq < 0) {
+		trace_info("failed to bind remote irq");
+		goto exit_no_irq;
+	}
+	spin_lock_irqsave(&channel->lock, flags);
+	ub_ring_channel_handle_stimulus(channel,
+					ub_ring_channel_stimulus_cs);
+	spin_unlock_irqrestore(&channel->lock, flags);
+	return;
+ exit_no_irq:
+	close.port = channel->event_channel;
+	BUG_ON(HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0);
+ exit_no_bind:
+	memset(&unmap_op, 0, sizeof(unmap_op));
+	unmap_op.host_addr = (unsigned long)channel->ring_area->addr;
+	unmap_op.handle = channel->ring_handle;
+	unmap_op.dev_bus_addr = 0;
+	lock_vm_area(channel->ring_area);
+	BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unmap_op,
+									1));
+	unlock_vm_area(channel->ring_area);
+ exit_no_mapping:
+	spin_lock_irqsave(&channel->lock, flags);
+	ub_ring_channel_handle_stimulus(channel,
+					ub_ring_channel_stimulus_cf);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+ub_ring_channel_connect_client(struct ub_ring_channel *channel)
+{
+	trace();
+	(void)ub_work_schedule(&channel->connect_client_1_work);
+}
+
+static void ub_ring_channel_connect_client_1(void *data)
+{
+	struct ub_ring_channel *channel = data;
+	unsigned long flags;
+	trace();
+	ub_channel_connect(&channel->channel);
+	spin_lock_irqsave(&channel->lock, flags);
+	ub_ring_channel_handle_stimulus(channel,
+					ub_ring_channel_stimulus_cc);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+ub_ring_channel_disconnect_client(struct ub_ring_channel *channel)
+{
+	trace();
+	(void)ub_work_schedule(&channel->disconnect_client_1_work);
+}
+
+static void ub_ring_channel_disconnect_client_1(void *data)
+{
+	struct ub_ring_channel *channel = data;
+	trace();
+	ub_channel_disconnect(&channel->channel,
+				&channel->disconnect_client_2_callback);
+}
+
+static void
+ub_ring_channel_disconnect_client_2(struct ub_callback *callback)
+{
+	struct ub_ring_channel *channel = container_of(callback,
+		struct ub_ring_channel, disconnect_client_2_callback);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	ub_ring_channel_handle_stimulus(channel,
+					ub_ring_channel_stimulus_dc);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+ub_ring_channel_do_disconnect(struct ub_ring_channel *channel)
+{
+	trace();
+	(void)ub_work_schedule(&channel->do_disconnect_1_work);
+}
+
+static void ub_ring_channel_do_disconnect_1(void *data)
+{
+	struct ub_ring_channel *channel = data;
+	struct gnttab_unmap_grant_ref op;
+	unsigned long flags;
+	trace();
+	unbind_from_irqhandler(channel->irq, channel);
+	memset(&op, 0, sizeof(op));
+	op.host_addr = (unsigned long)channel->ring_area->addr;
+	op.handle = channel->ring_handle;
+	op.dev_bus_addr = 0;
+	lock_vm_area(channel->ring_area);
+	BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
+	unlock_vm_area(channel->ring_area);
+	spin_lock_irqsave(&channel->lock, flags);
+	ub_ring_channel_handle_stimulus(channel,
+					ub_ring_channel_stimulus_ds);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+ub_ring_channel_kick_recv_ring(struct ub_ring_channel *channel)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	if (!channel->recv_ring_kick_out) {
+		channel->recv_ring_kick_out = 1;
+		(void)ub_work_schedule(&channel->kick_recv_ring_1_work);
+	}
+}
+
+static void ub_ring_channel_kick_recv_ring_1(void *data)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	struct ub_ring_channel *channel = data;
+	unsigned long flags;
+	spin_lock_irqsave(&channel->lock, flags);
+	for (;;) {
+		struct usbif_back_ring *back_ring = &channel->back_ring;
+		int progress = 0;
+		RING_IDX rp, rc;
+		rc = back_ring->req_cons;
+		/* To avoid going idle when there is a waiting request we    */
+		/* need a mb() here to make sure we see any requests which   */
+		/* are new this time around the outer 'for' loop.            */
+		/* FIXME: spin_lock below makes this unnecessary?            */
+		mb();
+		rp = back_ring->sring->req_prod;
+		/* To make sure we see the correct data for the requests     */
+		/* found above we need a rmb() here to force reads to be     */
+                /* after the read of back_ring->sring->req_prod.             */
+		rmb();
+		while (!list_empty(&channel->rsrc_list) && (rc != rp) &&
+				!RING_REQUEST_CONS_OVERFLOW(back_ring, rc)) {
+			struct ub_ring_channel_rsrc *rsrc;
+			struct usbif_request *request;
+			rsrc = list_entry(channel->rsrc_list.next,
+				struct ub_ring_channel_rsrc,
+				message.callback.work.link);
+			list_del_init(ub_ring_channel_rsrc_to_link(rsrc));
+			request = RING_GET_REQUEST(back_ring, rc);
+			rsrc->message.request = *request;
+			back_ring->req_cons = ++rc;
+			channel->rsrcs_out++;
+			spin_unlock_irqrestore(&channel->lock, flags);
+			ub_channel_handle_message(&channel->channel,
+							&rsrc->message);
+			progress = 1;
+			spin_lock_irqsave(&channel->lock, flags);
+		}
+		if (!progress)
+		{
+			channel->recv_ring_kick_out = 0;
+			ub_ring_channel_handle_stimulus(channel,
+					ub_ring_channel_stimulus_kr);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+ub_ring_channel_kick_recv_ring_2(struct ub_callback *callback)
+{
+	struct ub_ring_channel_rsrc *rsrc =
+			ub_ring_channel_rsrc_callback_to(callback);
+	struct ub_ring_channel *channel = rsrc->channel;
+	unsigned long flags;
+	if ((ub_callback_query_error(callback) != USBIF_ERROR_SUCCESS) &&
+					(channel->protocol_error != NULL))
+		channel->protocol_error(channel);
+	spin_lock_irqsave(&channel->lock, flags);
+	list_add_tail(ub_ring_channel_rsrc_to_link(rsrc),
+							&channel->rsrc_list);
+	if (--channel->rsrcs_out == 0) {
+		ub_ring_channel_handle_stimulus(channel,
+				ub_ring_channel_stimulus_rf);
+	} else {
+		ub_ring_channel_handle_stimulus(channel,
+				ub_ring_channel_stimulus_rc);
+	}
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+ub_ring_channel_kick_send_ring(struct ub_ring_channel *channel)
+{
+	if (!channel->send_ring_kick_out) {
+		channel->send_ring_kick_out = 1;
+		(void)ub_work_schedule(&channel->kick_send_ring_1_work);
+	}
+}
+
+static void ub_ring_channel_kick_send_ring_1(void *data)
+{
+	struct ub_ring_channel *channel = data;
+	unsigned long flags;
+	spin_lock_irqsave(&channel->lock, flags);
+	for (;;) {
+		struct usbif_back_ring *back_ring = &channel->back_ring;
+		int notify = 0;
+		while (!list_empty(&channel->message_list)) {
+			struct ub_channel_obmsg *message;
+			struct usbif_response *response;
+			message = list_entry(channel->message_list.next,
+						struct ub_channel_obmsg,
+						callback.work.link);
+			list_del_init(ub_channel_obmsg_to_link(message));
+			spin_unlock_irqrestore(&channel->lock, flags);
+			response = RING_GET_RESPONSE(back_ring,
+						back_ring->rsp_prod_pvt);
+			*response = message->response;
+			ub_callback_success(
+				ub_channel_obmsg_to_callback(message));
+			back_ring->rsp_prod_pvt++;
+			notify = 1;
+			spin_lock_irqsave(&channel->lock, flags);
+		}
+		if (notify) {
+			spin_unlock_irqrestore(&channel->lock, flags);
+			RING_PUSH_RESPONSES(back_ring);
+			notify_remote_via_irq(channel->irq);
+			spin_lock_irqsave(&channel->lock, flags);
+		} else {
+			channel->send_ring_kick_out = 0;
+			ub_ring_channel_handle_stimulus(channel,
+					ub_ring_channel_stimulus_ks);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+ub_ring_channel_complete_current_callback(
+struct ub_ring_channel *channel)
+{
+	trace();
+	ub_callback_success(channel->current_callback);
+}
+
+static void
+ub_ring_channel_fail_current_callback(
+struct ub_ring_channel *channel)
+{
+	trace();
+	ub_callback_complete(channel->current_callback,
+							USBIF_ERROR_FAILURE);
+}
+
+static void
+ub_ring_channel_fail_out_messages(struct ub_ring_channel *channel)
+{
+	trace();
+	while (!list_empty(&channel->message_list)) {
+		struct ub_channel_obmsg *message = list_entry(
+			channel->message_list.next,
+			struct ub_channel_obmsg,
+			callback.work.link);
+		list_del_init(ub_channel_obmsg_to_link(message));
+		/* Message completion doesn't guarantee message delivery so  */
+		/* there is no need for an error code here.                  */
+		ub_callback_success(ub_channel_obmsg_to_callback(
+								message));
+	}
+}
+
+static void
+ub_ring_channel_test_rsrcs(struct ub_ring_channel *channel)
+{
+	trace();
+	if (channel->rsrcs_out == 0) {
+		ub_ring_channel_handle_stimulus(channel,
+					ub_ring_channel_stimulus_rf);
+	}
+}
+
+static int
+ub_ring_channel_init_or_exit(struct ub_ring_channel *channel,
+int exit)
+{
+	int return_value = 0, i;
+	trace();
+	if (exit)
+		goto exit_path;
+	if ((channel->ring_area = alloc_vm_area(PAGE_SIZE)) == NULL) {
+		trace_info("failed to allocate ring area");
+		return_value = -ENOMEM;
+		goto exit_no_ring_area;
+	}
+	spin_lock_init(&channel->lock);
+	channel->state = ub_ring_channel_state_i;
+	INIT_LIST_HEAD(&channel->message_list);
+	ub_work_init(&channel->do_connect_1_work,
+		     ub_ring_channel_do_connect_1, channel);
+	ub_work_init(&channel->connect_client_1_work,
+		     ub_ring_channel_connect_client_1, channel);
+	ub_work_init(&channel->disconnect_client_1_work,
+		     ub_ring_channel_disconnect_client_1, channel);
+	ub_callback_init(&channel->disconnect_client_2_callback,
+		     ub_ring_channel_disconnect_client_2);
+	ub_work_init(&channel->do_disconnect_1_work,
+		     ub_ring_channel_do_disconnect_1, channel);
+	ub_work_init(&channel->kick_recv_ring_1_work,
+		     ub_ring_channel_kick_recv_ring_1, channel);
+	ub_work_init(&channel->kick_send_ring_1_work,
+		     ub_ring_channel_kick_send_ring_1, channel);
+	INIT_LIST_HEAD(&channel->rsrc_list);
+	for (i = 0; i < USBIF_QUOTA; i++) {
+		struct ub_ring_channel_rsrc *rsrc = &channel->rsrcs[i];
+		ub_ring_channel_rsrc_init(rsrc, channel,
+				ub_ring_channel_kick_recv_ring_2);
+		list_add_tail(ub_ring_channel_rsrc_to_link(rsrc),
+							&channel->rsrc_list);
+	}
+	channel->recv_ring_kick_out = 0;
+	channel->send_ring_kick_out = 0;
+	channel->rsrcs_out = 0;
+	return 0;
+ exit_path:
+	free_vm_area(channel->ring_area);
+ exit_no_ring_area:
+	return return_value;
+}
+
+int
+ub_ring_channel_init(struct ub_ring_channel *channel,
+void (*protocol_error) (struct ub_ring_channel *channel))
+{
+	trace();
+	ub_channel_init(&channel->channel,
+					ub_ring_channel_submit_message);
+	channel->protocol_error = protocol_error;
+	return ub_ring_channel_init_or_exit(channel, 0);
+}
+
+void ub_ring_channel_exit(struct ub_ring_channel *channel)
+{
+	trace();
+	(void)ub_ring_channel_init_or_exit(channel, 1);
+}
+
+static void ub_ring_channel_handle_stimulus(
+struct ub_ring_channel *channel, ub_ring_channel_stimulus stimulus)
+{
+	switch (channel->state) {
+	case ub_ring_channel_state_i:
+		/* Client disconnected. */
+		/* No messages queued.  */
+		/* Kick send idle.      */
+		/* Kick recv idle.      */
+		/* Target rsrcs idle.   */
+		/* Ring disconnected.   */
+		switch (stimulus) {
+		case ub_ring_channel_stimulus_cn:
+			channel->state = ub_ring_channel_state_i_cn;
+			ub_ring_channel_do_connect(channel);
+			break;
+		default:
+			ub_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case ub_ring_channel_state_i_cn:
+		/* Interface connecting.   */
+		/* Client disconnected.    */
+		/* No messages queued.     */
+		/* Kick send idle.         */
+		/* Kick recv idle.         */
+		/* Target rsrcs idle.      */
+		/* do connect in progress. */
+		switch (stimulus) {
+		case ub_ring_channel_stimulus_ri:
+			break;
+		case ub_ring_channel_stimulus_cs:
+			channel->state = ub_ring_channel_state_i_cn_cs;
+			ub_ring_channel_connect_client(channel);
+			break;
+		case ub_ring_channel_stimulus_cf:
+			channel->state = ub_ring_channel_state_i;
+			ub_ring_channel_fail_current_callback(channel);
+			break;
+		default:
+			ub_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case ub_ring_channel_state_i_cn_cs:
+		/* Interface connecting.      */
+		/* Client connecting.         */
+		/* Maybe messages queued.     */
+		/* Kick send idle.            */
+		/* Kick recv idle.            */
+		/* Target rsrcs idle.         */
+		/* Ring connected.            */
+		/* Connect client in progress */
+		switch (stimulus) {
+		case ub_ring_channel_stimulus_mq:
+		case ub_ring_channel_stimulus_ri:
+			break;
+		case ub_ring_channel_stimulus_cc:
+			channel->state =
+				ub_ring_channel_state_i_cn_cs_cc;
+			ub_ring_channel_complete_current_callback(
+								channel);
+			ub_ring_channel_kick_send_ring(channel);
+			ub_ring_channel_kick_recv_ring(channel);
+			break;
+		default:
+			ub_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case ub_ring_channel_state_i_cn_cs_cc:
+		/* Interface connected.         */
+		/* Client connected.            */
+		/* Maybe messages queued.       */
+		/* Maybe kick send in progress. */
+		/* Maybe kick recv in progress. */
+		/* Maybe target rsrcs busy.     */
+		/* Ring connected.              */
+		switch (stimulus) {
+		case ub_ring_channel_stimulus_mq:
+			ub_ring_channel_kick_send_ring(channel);
+			break;
+		case ub_ring_channel_stimulus_dn:
+			channel->state =
+				ub_ring_channel_state_i_cn_cs_cc_dn;
+			ub_ring_channel_kick_send_ring(channel);
+			ub_ring_channel_kick_recv_ring(channel);
+			break;
+		case ub_ring_channel_stimulus_ri:
+			ub_ring_channel_kick_recv_ring(channel);
+			break;
+		case ub_ring_channel_stimulus_ks:
+		case ub_ring_channel_stimulus_kr:
+			break;
+		case ub_ring_channel_stimulus_rc:
+		case ub_ring_channel_stimulus_rf:
+			ub_ring_channel_kick_recv_ring(channel);
+			break;
+		default:
+			ub_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case ub_ring_channel_state_i_cn_cs_cc_dn:
+		/* Interface disconnecting. */
+		/* Client connected.        */
+		/* Maybe messages queued.   */
+		/* Kick send in progress.   */
+		/* Kick recv in progress.   */
+		/* Maybe target rsrcs busy. */
+		/* Ring connected.          */
+		switch (stimulus) {
+		case ub_ring_channel_stimulus_mq:
+		case ub_ring_channel_stimulus_ri:
+			break;
+		case ub_ring_channel_stimulus_ks:
+		case ub_ring_channel_stimulus_kr:
+			channel->state =
+				ub_ring_channel_state_i_cn_cs_cc_dn_ks;
+			break;
+		case ub_ring_channel_stimulus_rc:
+		case ub_ring_channel_stimulus_rf:
+			break;
+		default:
+			ub_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case ub_ring_channel_state_i_cn_cs_cc_dn_ks:
+		/* Interface disconnecting.           */
+		/* Client connected.                  */
+		/* Maybe messages queued.             */
+		/* One of kick send/recv in progress. */
+		/* Maybe target rsrcs busy.           */
+		/* Ring connected.                    */
+		switch (stimulus) {
+		case ub_ring_channel_stimulus_mq:
+		case ub_ring_channel_stimulus_ri:
+			break;
+		case ub_ring_channel_stimulus_ks:
+		case ub_ring_channel_stimulus_kr:
+			channel->state =
+			    ub_ring_channel_state_i_cn_cs_cc_dn_ks_kr;
+			ub_ring_channel_disconnect_client(channel);
+			ub_ring_channel_fail_out_messages(channel);
+			break;
+		case ub_ring_channel_stimulus_rc:
+		case ub_ring_channel_stimulus_rf:
+			break;
+		default:
+			ub_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case ub_ring_channel_state_i_cn_cs_cc_dn_ks_kr:
+		/* Interface disconnecting. */
+		/* Client disconnecting.    */
+		/* No messages queued.      */
+		/* Kick send/recv idle.     */
+		/* Maybe target rsrcs busy. */
+		/* Ring connected.          */
+		switch (stimulus) {
+		case ub_ring_channel_stimulus_mq:
+			ub_ring_channel_fail_out_messages(channel);
+			break;
+		case ub_ring_channel_stimulus_ri:
+			break;
+		case ub_ring_channel_stimulus_dc:
+			channel->state =
+			    ub_ring_channel_state_i_cn_cs_cc_dn_ks_kr_dc;
+			ub_ring_channel_test_rsrcs(channel);
+			break;
+		case ub_ring_channel_stimulus_rc:
+		case ub_ring_channel_stimulus_rf:
+			break;
+		default:
+			ub_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case ub_ring_channel_state_i_cn_cs_cc_dn_ks_kr_dc:
+		/* Interface disconnecting.                */
+		/* Client disconnected.                    */
+		/* No messages queued.                     */
+		/* Kick send/recv idle.                    */
+		/* Testing target rsrcs/ target rsrcs busy */
+		/* Ring connected.                         */
+		switch (stimulus) {
+		case ub_ring_channel_stimulus_ri:
+		case ub_ring_channel_stimulus_rc:
+			break;
+		case ub_ring_channel_stimulus_rf:
+			channel->state =
+			ub_ring_channel_state_i_cn_cs_cc_dn_ks_kr_dc_rf;
+			ub_ring_channel_do_disconnect(channel);
+			break;
+		default:
+			ub_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case ub_ring_channel_state_i_cn_cs_cc_dn_ks_kr_dc_rf:
+		/* Interface disconnecting. */
+		/* Client disconnected.     */
+		/* No messages queued.      */
+		/* Kick send/recv idle.     */
+		/* Target rsrcs idle.       */
+		/* Disconnecting.           */
+		switch (stimulus) {
+		case ub_ring_channel_stimulus_ri:
+			break;
+		case ub_ring_channel_stimulus_ds:
+			channel->state = ub_ring_channel_state_i;
+			ub_ring_channel_complete_current_callback(
+								channel);
+			break;
+		default:
+			ub_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	default:
+		ub_ring_channel_invalid_stimulus(channel, stimulus);
+		break;
+	}
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_ring_channel.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_ring_channel.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,111 @@
+/*****************************************************************************/
+/* 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 UB_RING_CHANNEL_H
+#define UB_RING_CHANNEL_H
+
+#include <linux/timer.h>
+#include <xen/evtchn.h>
+#include <xen/gnttab.h>
+#include "ub_channel.h"
+
+struct ub_ring_channel;
+
+struct ub_ring_channel_rsrc {
+	struct ub_channel_ibmsg  message;
+	struct ub_ring_channel  *channel;
+};
+
+typedef enum {
+	ub_ring_channel_state_i,
+	ub_ring_channel_state_i_cn,
+	ub_ring_channel_state_i_cn_cs,
+	ub_ring_channel_state_i_cn_cs_cc,
+	ub_ring_channel_state_i_cn_cs_cc_dn,
+	ub_ring_channel_state_i_cn_cs_cc_dn_ks,
+	ub_ring_channel_state_i_cn_cs_cc_dn_ks_kr,
+	ub_ring_channel_state_i_cn_cs_cc_dn_ks_kr_dc,
+	ub_ring_channel_state_i_cn_cs_cc_dn_ks_kr_dc_rf
+} ub_ring_channel_state;
+
+struct ub_ring_channel {
+	struct ub_channel           channel;
+	void (*protocol_error) (struct ub_ring_channel *channel);
+	struct vm_struct                *ring_area;
+	spinlock_t                       lock;
+	ub_ring_channel_state       state;
+	struct list_head                 message_list;
+	struct ub_work              do_connect_1_work;
+	struct ub_work              connect_client_1_work;
+	struct ub_work              disconnect_client_1_work;
+	struct ub_callback          disconnect_client_2_callback;
+	struct ub_work              do_disconnect_1_work;
+	struct ub_work              kick_recv_ring_1_work;
+	struct ub_work              kick_send_ring_1_work;
+	struct list_head                 rsrc_list;
+	struct ub_ring_channel_rsrc rsrcs[USBIF_QUOTA];
+	int                              recv_ring_kick_out;
+	int                              send_ring_kick_out;
+	int                              rsrcs_out;
+	struct ub_callback         *current_callback;
+	grant_handle_t                   ring_handle;
+	unsigned int                     event_channel;
+	int                              irq;
+	struct usbif_back_ring           back_ring;
+};
+
+static inline struct ub_channel *
+ub_ring_channel_to_channel(struct ub_ring_channel *channel)
+{
+	return &channel->channel;
+}
+
+static inline struct ub_ring_channel *
+ub_ring_channel_channel_to(struct ub_channel *channel)
+{
+	return container_of(channel, struct ub_ring_channel, channel);
+}
+
+int ub_ring_channel_init(struct ub_ring_channel *channel,
+void (*protocol_error) (struct ub_ring_channel *channel));
+
+struct ub_ring_channel_connect_request {
+	struct ub_callback callback;
+	domid_t                 domain_id;
+	grant_ref_t             ring_ref;
+	evtchn_port_t           event_channel;
+};
+
+static inline struct ub_ring_channel_connect_request *
+ub_ring_channel_connect_request_callback_to(
+struct ub_callback *callback)
+{
+	return container_of(callback,
+			struct ub_ring_channel_connect_request,callback);
+}
+
+void ub_ring_channel_connect(struct ub_ring_channel *channel,
+struct ub_ring_channel_connect_request *request);
+
+void ub_ring_channel_disconnect(struct ub_ring_channel *channel,
+struct ub_callback *callback);
+
+void ub_ring_channel_exit(struct ub_ring_channel *channel);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_rsrc.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_rsrc.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,529 @@
+/*****************************************************************************/
+/* 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/usb.h>
+#include <xen/interface/io/usbif.h>
+#include "ub_ep.h"
+#include "ub_rbr_mapper.h"
+#include "ub_rsrc.h"
+#include "ub_trace.h"
+
+static struct ub_rbr_mapper *rbr_mapper;
+
+typedef enum {
+	ub_rsrc_stimulus_st, /* Start IO          */
+	ub_rsrc_stimilus_fl, /* Flush IO          */
+	ub_rsrc_stimulus_ms, /* Map success       */
+	ub_rsrc_stimulus_mf, /* Map failure       */
+	ub_rsrc_stimulus_us, /* URB submitted     */
+	ub_rsrc_stimulus_un, /* URB not submitted */
+	ub_rsrc_stimulus_uc  /* URB completed     */
+} ub_rsrc_stimulus;
+
+static void
+ub_rsrc_handle_stimulus(struct ub_rsrc *rsrc, ub_rsrc_stimulus stimulus);
+
+void ub_rsrc_start_io(struct ub_rsrc *rsrc, struct ub_gw_tra *tra)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&rsrc->lock, flags);
+	rsrc->tra_error = USBIF_ERROR_SUCCESS;
+	rsrc->tra = tra;
+	ub_rsrc_handle_stimulus(rsrc, ub_rsrc_stimulus_st);
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+}
+
+void ub_rsrc_flush_io(struct ub_rsrc *rsrc)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&rsrc->lock, flags);
+	if (rsrc->tra != NULL)
+		ub_rsrc_handle_stimulus(rsrc, ub_rsrc_stimilus_fl);
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+}
+
+static void
+ub_rsrc_invalid_stimulus(struct ub_rsrc *rsrc, ub_rsrc_stimulus stimulus)
+{
+	trace();
+	printk(KERN_ERR "ub: port rsrc %p in state %d received"
+		" invalid stimulus %d", rsrc, rsrc->state, stimulus);
+}
+
+static void ub_rsrc_map_buffer(struct ub_rsrc *rsrc)
+{
+	struct usbif_io_tra_parameters_header *header =
+					&rsrc->tra->parameters.io.header;
+	trace();
+	ub_rbr_mapper_element_ensure_removed(&rsrc->request_element[0]);
+	ub_rbr_mapper_element_ensure_removed(&rsrc->request_element[1]);
+	ub_rbr_mapper_request_add_element(&rsrc->rbr_mapper_request,
+						&rsrc->request_element[0]);
+	ub_rbr_mapper_element_set_rbr(&rsrc->request_element[0],
+		     header->rbr,
+		     (header->direction == USBIF_IO_TRA_DIRECTION_OUT) ?
+						UB_ACCESS_FLAGS_READ :
+						UB_ACCESS_FLAGS_WRITE);
+	if (header->io_tra_type == USBIF_IO_TRA_TYPE_ISOCHRONOUS) {
+		struct usbif_isochronous_io_tra_parameters *parameters=
+			&rsrc->tra->parameters.io.isochronous;
+		ub_rbr_mapper_request_add_element(
+					&rsrc->rbr_mapper_request,
+					&rsrc->request_element[1]);
+		ub_rbr_mapper_element_set_rbr(
+			&rsrc->request_element[1],
+			parameters->schedule_rbr,
+			UB_ACCESS_FLAGS_READ |
+			UB_ACCESS_FLAGS_WRITE);
+	}
+	ub_rbr_mapper_reserve_and_map_rbrs(rbr_mapper,
+			&rsrc->rbr_mapper_request,
+			ub_ep_query_remote_domain(rsrc->ep));
+}
+
+static void ub_rsrc_abort_map(struct ub_rsrc *rsrc)
+{
+	trace();
+	ub_rbr_mapper_abort_reserve_and_map_rbrs(
+				&rsrc->rbr_mapper_request,
+				USBIF_ERROR_UNLINKED);
+}
+
+static void ub_rsrc_map_callback(struct ub_callback * callback)
+{
+	struct ub_rbr_mapper_request *request =
+			ub_rbr_mapper_request_map_callback_to(callback);
+	struct ub_rsrc *rsrc = container_of(request,
+			struct ub_rsrc,
+			rbr_mapper_request);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&rsrc->lock, flags);
+	rsrc->tra_error = ub_callback_query_error(callback);
+	if (rsrc->tra_error == USBIF_ERROR_SUCCESS) {
+		rsrc->rbrs_mapped = 1;
+		ub_rsrc_handle_stimulus(rsrc, ub_rsrc_stimulus_ms);
+	} else {
+		trace_info("failed to map FE buffer");
+		ub_rsrc_handle_stimulus(rsrc, ub_rsrc_stimulus_mf);
+	}
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+}
+
+static void ub_rsrc_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 ub_rsrc_submit_urb(struct ub_rsrc *rsrc)
+{
+	static const unsigned int pipe_type[4] = {
+		[USBIF_IO_TRA_TYPE_CONTROL]     = PIPE_CONTROL,
+		[USBIF_IO_TRA_TYPE_BULK]        = PIPE_BULK,
+		[USBIF_IO_TRA_TYPE_INTERRUPT]   = PIPE_INTERRUPT,
+		[USBIF_IO_TRA_TYPE_ISOCHRONOUS] = PIPE_ISOCHRONOUS
+	};
+	union usbif_io_tra_parameters *io_parameters =
+			&rsrc->tra->parameters.io;
+	struct urb *urb = rsrc->urb;
+	struct usb_device * usbdev = ub_ep_query_usbdev(rsrc->ep);
+	unsigned int pipe;
+	trace();
+	if (io_parameters->header.io_tra_type >= 4) {
+		rsrc->tra_error = USBIF_ERROR_INVALID_PARAMETER;
+		goto protocol_error;
+	}
+	if (io_parameters->header.io_tra_type ==
+					USBIF_IO_TRA_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) {
+				goto handled_special_case;
+			} else if (ctrl->bRequest ==
+						USB_REQ_SET_CONFIGURATION) {
+				/* FIXME: what to do for set configuration? */
+				goto handled_special_case;
+			}
+		}
+	}
+	if (io_parameters->header.direction == USBIF_IO_TRA_DIRECTION_OUT) {
+		pipe = USB_DIR_OUT;
+	} else {
+		pipe = USB_DIR_IN;
+	}
+	pipe |= (unsigned int)usbdev->devnum << 8;
+	pipe |= (unsigned int)io_parameters->header.endpoint << 15;
+	pipe |= pipe_type[io_parameters->header.io_tra_type] << 30;
+	if (io_parameters->header.io_tra_type == USBIF_IO_TRA_TYPE_CONTROL) {
+		memcpy(rsrc->setup, io_parameters->control.setup, sizeof(
+							rsrc->setup));
+		usb_fill_control_urb(urb, usbdev, pipe, rsrc->setup,
+				rsrc->request_element[0].mapping,
+				usbif_rbr_query_byte_count(&rsrc->
+						request_element[0].rbr),
+				ub_rsrc_end_io, rsrc);
+	} else if(io_parameters->header.io_tra_type ==
+						USBIF_IO_TRA_TYPE_BULK) {
+		usb_fill_bulk_urb(urb, usbdev, pipe,
+					rsrc->request_element[0].mapping,
+					usbif_rbr_query_byte_count(
+					&rsrc->request_element[0].rbr),
+					ub_rsrc_end_io,
+					rsrc);
+	} else if(io_parameters->header.io_tra_type ==
+					USBIF_IO_TRA_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, usbdev, pipe,
+				rsrc->request_element[0].mapping,
+				usbif_rbr_query_byte_count(&rsrc->
+						request_element[0].rbr),
+				ub_rsrc_end_io, rsrc,
+				1 /* For the time being... */ );
+		/* ...now set the real value. */
+		urb->interval = io_parameters->interrupt.interval;
+	} else {
+		struct usbif_isochronous_io_schedule_element *schedule_element;
+		struct usbif_isochronous_io_schedule_element aligned_element;
+		int i;
+		/* FIXME: where's usb_fill_isoc_urb ?!? */
+		spin_lock_init(&urb->lock);
+		urb->dev = usbdev;
+		urb->pipe = pipe;
+		urb->transfer_buffer = rsrc->request_element[0].mapping;
+		urb->transfer_buffer_length = usbif_rbr_query_byte_count(
+					&rsrc->request_element[0].rbr);
+		urb->complete = ub_rsrc_end_io;
+		urb->context = rsrc;
+		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) {
+			rsrc->tra_error = USBIF_ERROR_TOO_BIG;
+			goto schedule_error;
+		}
+		if (usbif_rbr_query_byte_count(&rsrc->request_element[1].
+				rbr) < (io_parameters->isochronous.packet_count
+				* sizeof(struct
+				usbif_isochronous_io_schedule_element))) {
+			rsrc->tra_error = USBIF_ERROR_INVALID_PARAMETER;
+			goto schedule_error;
+		}
+		schedule_element = rsrc->request_element[1].mapping;
+		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)) {
+			rsrc->tra_error = USBIF_ERROR_INVALID_PARAMETER;
+			goto schedule_error;
+		}
+	}
+	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;
+	rsrc->tra_error = usbif_error_map_local_to(usb_submit_urb(urb,
+								GFP_ATOMIC));
+	if (rsrc->tra_error != USBIF_ERROR_SUCCESS) {
+		printk(KERN_WARNING "URB %p submission failed.\n", urb);
+		goto urb_error;
+	}
+	ub_rsrc_handle_stimulus(rsrc, ub_rsrc_stimulus_us);
+	return;
+ urb_error:
+ schedule_error:
+ handled_special_case:
+ protocol_error:
+	rsrc->completing_tra = rsrc->tra;
+	rsrc->tra = NULL;
+	ub_rsrc_handle_stimulus(rsrc, ub_rsrc_stimulus_un);
+}
+
+static void ub_rsrc_end_io(struct urb *urb, struct pt_regs *regs)
+{
+	struct ub_rsrc *rsrc = urb->context;
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&rsrc->lock, flags);
+	rsrc->completing_tra = rsrc->tra;
+	rsrc->tra = NULL;
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+	rsrc->tra_error = usbif_error_map_local_to(urb->status);
+	if (rsrc->tra_error != USBIF_ERROR_SUCCESS) {
+		printk(KERN_WARNING "URB %p failed. Status %d\n", urb,
+								urb->status);
+		/* Report the error here before completing the rsrc so that  */
+		/* the outstanding rsrc keeps the ep alive for the call.     */
+		ub_ep_stall(rsrc->ep);
+	}
+	rsrc->completing_tra->status.io.length = urb->actual_length;
+	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+		struct usbif_isochronous_io_schedule_element *schedule_element
+				= rsrc->request_element[1].mapping;
+		struct 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));
+		}
+	}
+	spin_lock_irqsave(&rsrc->lock, flags);
+	ub_rsrc_handle_stimulus(rsrc,ub_rsrc_stimulus_uc);
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+}
+
+static void ub_rsrc_unlink_urb(struct ub_rsrc *rsrc)
+{
+	trace();
+	usb_unlink_urb(rsrc->urb);
+}
+
+static void ub_rsrc_set_unlinked_error(struct ub_rsrc *rsrc)
+{
+	trace();
+	rsrc->tra_error = USBIF_ERROR_UNLINKED;
+}
+
+static void ub_rsrc_complete(struct ub_rsrc *rsrc)
+{
+	trace();
+	if (rsrc->rbrs_mapped) {
+		rsrc->rbrs_mapped = 0;
+		ub_rbr_mapper_unmap_and_unreserve_rbrs(
+				&rsrc->rbr_mapper_request);
+	} else {
+		ub_callback_success(
+			ub_rbr_mapper_request_to_unmap_callback(
+				&rsrc->rbr_mapper_request));
+	}
+}
+
+static void ub_rsrc_unmap_callback(struct ub_callback * callback)
+{
+	struct ub_rbr_mapper_request *request =
+		ub_rbr_mapper_request_unmap_callback_to(callback);
+	struct ub_rsrc *rsrc = container_of(request, struct ub_rsrc,
+							rbr_mapper_request);
+	trace();
+	ub_gw_tra_complete(rsrc->completing_tra, rsrc->tra_error);
+	ub_ep_rsrc_completed_io(rsrc->ep, rsrc);
+}
+
+static void
+ub_rsrc_handle_stimulus(struct ub_rsrc *rsrc, ub_rsrc_stimulus stimulus)
+{
+	trace();
+	switch (rsrc->state) {
+	case ub_rsrc_state_i:
+		/* Idle */
+		switch (stimulus) {
+		case ub_rsrc_stimulus_st:
+			rsrc->state = ub_rsrc_state_i_st;
+			ub_rsrc_map_buffer(rsrc);
+			break;
+		default:
+			ub_rsrc_invalid_stimulus(rsrc, stimulus);
+			break;
+		}
+		break;
+	case ub_rsrc_state_i_st:
+		/* Handling request       */
+		/* map_buffer outstanding */
+		switch (stimulus) {
+		case ub_rsrc_stimilus_fl:
+			rsrc->state = ub_rsrc_state_i_st_fl;
+			ub_rsrc_abort_map(rsrc);
+			break;
+		case ub_rsrc_stimulus_ms:
+			rsrc->state = ub_rsrc_state_i_st_ms;
+			ub_rsrc_submit_urb(rsrc);
+			break;
+		case ub_rsrc_stimulus_mf:
+			rsrc->state = ub_rsrc_state_i;
+			ub_rsrc_complete(rsrc);
+			break;
+		default:
+			ub_rsrc_invalid_stimulus(rsrc, stimulus);
+			break;
+		}
+		break;
+	case ub_rsrc_state_i_st_fl:
+		/* Handling request       */
+		/* map_buffer outstanding */
+		/* unlinking              */
+		switch (stimulus) {
+		case ub_rsrc_stimilus_fl:
+			break;
+		case ub_rsrc_stimulus_ms:
+			rsrc->state = ub_rsrc_state_i;
+			ub_rsrc_set_unlinked_error(rsrc);
+			ub_rsrc_complete(rsrc);
+			break;
+		case ub_rsrc_stimulus_mf:
+			rsrc->state = ub_rsrc_state_i;
+			ub_rsrc_complete(rsrc);
+			break;
+		default:
+			ub_rsrc_invalid_stimulus
+			    (rsrc, stimulus);
+			break;
+		}
+		break;
+	case ub_rsrc_state_i_st_ms:
+		/* Handling request       */
+		/* submit_urb outstanding */
+		switch (stimulus) {
+		case ub_rsrc_stimulus_us:
+			rsrc->state = ub_rsrc_state_i_st_ms_us;
+			break;
+		case ub_rsrc_stimulus_un:
+			rsrc->state = ub_rsrc_state_i;
+			ub_rsrc_complete(rsrc);
+			break;
+		default:
+			ub_rsrc_invalid_stimulus(rsrc, stimulus);
+			break;
+		}
+		break;
+	case ub_rsrc_state_i_st_ms_us:
+		/* Handling request */
+		/* URB submitted    */
+		switch (stimulus) {
+		case ub_rsrc_stimilus_fl:
+			rsrc->state = ub_rsrc_state_i_st_ms_us_fl;
+			ub_rsrc_unlink_urb(rsrc);
+			break;
+		case ub_rsrc_stimulus_uc:
+			rsrc->state = ub_rsrc_state_i;
+			ub_rsrc_complete(rsrc);
+			break;
+		default:
+			ub_rsrc_invalid_stimulus(rsrc, stimulus);
+			break;
+		}
+		break;
+	case ub_rsrc_state_i_st_ms_us_fl:
+		/* Handling request             */
+		/* URB outstanding and unlinked */
+		switch (stimulus) {
+		case ub_rsrc_stimilus_fl:
+			break;
+		case ub_rsrc_stimulus_uc:
+			rsrc->state = ub_rsrc_state_i;
+			ub_rsrc_complete(rsrc);
+			break;
+		default:
+			ub_rsrc_invalid_stimulus(rsrc, stimulus);
+			break;
+		}
+		break;
+	default:
+		ub_rsrc_invalid_stimulus(rsrc, stimulus);
+		break;
+	}
+}
+
+int ub_rsrc_init(struct ub_rsrc *rsrc, struct ub_ep *ep)
+{
+	trace();
+	rsrc->ep = ep;
+	INIT_LIST_HEAD(&rsrc->link);
+	spin_lock_init(&rsrc->lock);
+	rsrc->state = ub_rsrc_state_i;
+	rsrc->tra = NULL;
+	ub_rbr_mapper_element_init(&rsrc->request_element[0]);
+	ub_rbr_mapper_element_init(&rsrc->request_element[1]);
+	ub_rbr_mapper_request_init(
+				&rsrc->rbr_mapper_request,
+				ub_rsrc_map_callback,
+				ub_rsrc_unmap_callback);
+	rsrc->rbrs_mapped = 0;
+	rsrc->urb = usb_alloc_urb(USBIF_MAX_SCHEDULE_PACKET_COUNT, GFP_KERNEL);
+	return (rsrc->urb != NULL) ? 0 : -ENOMEM;
+}
+
+void ub_rsrc_exit(struct ub_rsrc *rsrc)
+{
+	trace();
+	usb_free_urb(rsrc->urb);
+}
+
+int ub_rsrc_class_init(void)
+{
+	trace();
+	rbr_mapper = ub_rbr_mapper_allocate();
+	return (rbr_mapper != NULL) ? 0 : -ENOMEM;
+}
+
+void ub_rsrc_class_exit(void)
+{
+	trace();
+	ub_rbr_mapper_free(rbr_mapper);
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_rsrc.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_rsrc.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,61 @@
+/*****************************************************************************/
+/* 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 UB_RSRC_H
+#define UB_RSRC_H
+
+#include "ub_gw.h"
+#include "ub_rbr_mapper.h"
+
+struct ub_ep;
+struct ub_rsrc;
+
+void ub_rsrc_start_io(struct ub_rsrc *rsrc, struct ub_gw_tra *tra);
+void ub_rsrc_flush_io(struct ub_rsrc *rsrc);
+int ub_rsrc_init(struct ub_rsrc *rsrc, struct ub_ep *ep);
+void ub_rsrc_exit(struct ub_rsrc *rsrc);
+int ub_rsrc_class_init(void);
+void ub_rsrc_class_exit(void);
+
+typedef enum {
+	ub_rsrc_state_i,
+	ub_rsrc_state_i_st,
+	ub_rsrc_state_i_st_fl,
+	ub_rsrc_state_i_st_ms,
+	ub_rsrc_state_i_st_ms_us,
+	ub_rsrc_state_i_st_ms_us_fl
+} ub_rsrc_state;
+
+struct ub_rsrc {
+	struct ub_ep                 *ep;
+	struct list_head              link;
+	spinlock_t                    lock;
+	ub_rsrc_state                 state;
+	usbif_error                   tra_error;
+	unsigned long                 tra_status_length;
+	struct ub_gw_tra             *tra;
+	struct ub_gw_tra             *completing_tra;
+	struct ub_rbr_mapper_request  rbr_mapper_request;
+	struct ub_rbr_mapper_element  request_element[2];
+	int                           rbrs_mapped;
+	struct urb                   *urb;
+	u8                            setup[8];
+};
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_trace.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_trace.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,36 @@
+/*****************************************************************************/
+/* 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 UB_TRACE_H
+#define UB_TRACE_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_XEN_USBDEV_BACKEND_TRACE
+
+#define trace_info(format, ...) \
+printk(KERN_INFO "ub %s: " format "\n", __FUNCTION__, ## __VA_ARGS__)
+#define trace() trace_info("")
+#else
+#define trace_info(format, ...)
+#define trace()
+#endif
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_work.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_work.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,72 @@
+/*****************************************************************************/
+/* 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 "ub_work.h"
+
+static void ub_work_function(void *ignored);
+
+DEFINE_SPINLOCK(ub_work_list_lock);
+LIST_HEAD(ub_work_list);
+DECLARE_WORK(ub_work_work, ub_work_function, NULL);
+DECLARE_WAIT_QUEUE_HEAD(ub_work_waitqueue);
+LIST_HEAD(ub_work_condition);
+
+void ub_work_wake_up(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&ub_work_list_lock, flags);
+	while (!list_empty(&ub_work_condition))
+		list_del_init(ub_work_condition.next);
+	spin_unlock_irqrestore(&ub_work_list_lock, flags);
+	wake_up(&ub_work_waitqueue);
+}
+
+int ub_work_schedule(struct ub_work *work)
+{
+	int scheduled = 0;
+	unsigned long flags;
+	spin_lock_irqsave(&ub_work_list_lock, flags);
+	if (list_empty(&work->link)) {
+		list_add_tail(&work->link, &ub_work_list);
+		scheduled = 1;
+	}
+	spin_unlock_irqrestore(&ub_work_list_lock, flags);
+	if (scheduled) {
+		ub_work_wake_up();
+		schedule_work(&ub_work_work);
+	}
+	return scheduled;
+}
+
+static void ub_work_function(void *ignored)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&ub_work_list_lock, flags);
+	while (!list_empty(&ub_work_list)) {
+		struct ub_work *work = list_entry(ub_work_list.next,
+						      struct ub_work,
+						      link);
+		list_del_init(&work->link);
+		spin_unlock_irqrestore(&ub_work_list_lock, flags);
+		ub_work_perform_synchronously(work);
+		spin_lock_irqsave(&ub_work_list_lock, flags);
+	}
+	spin_unlock_irqrestore(&ub_work_list_lock, flags);
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_work.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_work.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,104 @@
+/*****************************************************************************/
+/* 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 UB_WORK_H
+#define UB_WORK_H
+
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+struct ub_work {
+	struct list_head   link;
+	void             (*function)(void *context);
+	void              *context;
+};
+
+#define UB_WORK_INIT( name, fn, ctx ) \
+{ .link = LIST_HEAD_INIT( name.link ), .function = fn, .context = ctx }
+
+#define UB_WORK( name, fn, ctx ) \
+struct ub_work name = UB_WORK_INIT( name, fn, ctx )
+
+static inline void
+ub_work_init(struct ub_work *work, void (*function) (void *context),
+void *context)
+{
+	INIT_LIST_HEAD(&work->link);
+	work->function = function;
+	work->context = context;
+}
+
+static inline struct list_head *ub_work_to_link(struct ub_work *work)
+{
+	return &work->link;
+}
+
+static inline struct ub_work *ub_work_link_to(struct list_head *link)
+{
+	return container_of(link, struct ub_work, link);
+}
+
+int ub_work_schedule(struct ub_work *work);
+
+static inline void
+ub_work_perform_synchronously(struct ub_work *work)
+{
+	work->function(work->context);
+}
+
+extern spinlock_t        ub_work_list_lock;
+extern struct list_head  ub_work_list;
+extern wait_queue_head_t ub_work_waitqueue;
+extern struct list_head  ub_work_condition;
+
+#define ub_work_until( condition )					      \
+do {									      \
+	unsigned long flags;						      \
+	spin_lock_irqsave(&ub_work_list_lock, flags);		      \
+	for (;;) {							      \
+		struct list_head link;					      \
+									      \
+		while (!list_empty(&ub_work_list) && !(condition)) {     \
+			struct ub_work *work;			      \
+			work = list_entry(ub_work_list.next,	      \
+						struct ub_work, link);   \
+			list_del_init(&work->link);			      \
+			spin_unlock_irqrestore(&ub_work_list_lock,       \
+						flags);                       \
+			ub_work_perform_synchronously(work);	      \
+			spin_lock_irqsave(&ub_work_list_lock, flags);    \
+		}							      \
+		if (condition)						      \
+			break;						      \
+		INIT_LIST_HEAD(&link);					      \
+		list_add_tail(&link, &ub_work_condition);		      \
+		spin_unlock_irqrestore(&ub_work_list_lock, flags);	      \
+		wait_event(ub_work_waitqueue, list_empty(&link));	      \
+		spin_lock_irqsave(&ub_work_list_lock, flags);	      \
+	}								      \
+	spin_unlock_irqrestore(&ub_work_list_lock, flags);		      \
+}									      \
+while (0)
+
+void ub_work_wake_up(void);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_xb_channel.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_xb_channel.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,372 @@
+/*****************************************************************************/
+/* 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/err.h>
+#include "ub_xb_channel.h"
+#include "ub_trace.h"
+
+typedef enum {
+	ub_xb_channel_stimulus_cn,
+	ub_xb_channel_stimulus_dn,
+	ub_xb_channel_stimulus_pe, /* Protocol error.       */
+	ub_xb_channel_stimulus_fi, /* Frontend initialised. */
+	ub_xb_channel_stimulus_fc, /* Frontend closing. */
+	ub_xb_channel_stimulus_rs,
+	ub_xb_channel_stimulus_rf
+} ub_xb_channel_stimulus;
+
+static void ub_xb_channel_handle_stimulus(struct ub_xb_channel *channel,
+ub_xb_channel_stimulus stimulus);
+
+void ub_xb_channel_connect(struct ub_xb_channel *channel,
+struct xenbus_device *device)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	channel->device = device;
+	ub_xb_channel_handle_stimulus(channel, ub_xb_channel_stimulus_cn);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+void ub_xb_channel_frontend_initialised(struct ub_xb_channel *channel,
+struct xenbus_device *dev)
+{
+	unsigned long ring_ref;
+	unsigned int event_channel;
+	unsigned long flags;
+	int error;
+	trace_info("%s", dev->otherend);
+	error = xenbus_gather(XBT_NIL, dev->otherend,
+				"ring-ref", "%lu", &ring_ref,
+				"event-channel", "%u", &event_channel, NULL);
+	spin_lock_irqsave(&channel->lock, flags);
+	if(!error) {
+		channel->domain_id     = dev->otherend_id;
+		channel->ring_ref      = ring_ref;
+		channel->event_channel = event_channel;
+		ub_xb_channel_handle_stimulus(channel,
+					ub_xb_channel_stimulus_fi);
+	} else {
+		xenbus_dev_fatal(dev, error,
+				"reading %s/ring-ref and event-channel",
+				dev->otherend);
+		ub_xb_channel_handle_stimulus(channel,
+					ub_xb_channel_stimulus_pe);
+	}
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+void ub_xb_channel_frontend_closing(struct ub_xb_channel *channel,
+struct xenbus_device *dev)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	ub_xb_channel_handle_stimulus(channel, ub_xb_channel_stimulus_fc);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+void ub_xb_channel_frontend_changed(struct ub_xb_channel *channel,
+struct xenbus_device *dev, XenbusState state)
+{
+	trace();
+
+	switch(state) {
+	case XenbusStateUnknown:
+		trace_info( "XenbusStateUnknown" );
+		break;
+	case XenbusStateInitialising:
+		trace_info( "XenbusStateInitialising" );
+		break;
+	case XenbusStateInitWait:
+		trace_info( "XenbusStateInitWait" );
+		break;
+	case XenbusStateInitialised:
+		trace_info( "XenbusStateInitialised" );
+		break;
+	case XenbusStateConnected:
+		trace_info( "XenbusStateConnected" );
+		break;
+	case XenbusStateClosing:
+		trace_info( "XenbusStateClosing" );
+		break;
+	case XenbusStateClosed:
+		trace_info( "XenbusStateClosed" );
+		break;
+	}
+
+	switch(state) {
+	case XenbusStateInitialised:
+	case XenbusStateConnected:
+		ub_xb_channel_frontend_initialised(channel, dev);
+		break;
+	case XenbusStateClosing:
+		ub_xb_channel_frontend_closing(channel, dev);
+		break;
+	case XenbusStateClosed:
+		xenbus_switch_state(dev, XenbusStateClosed);
+		device_unregister(&dev->dev);
+		break;
+	default:
+		break;
+	}
+}
+
+static void ub_xb_channel_protocol_error(struct ub_ring_channel *ring_channel)
+{
+	struct ub_xb_channel *channel =
+				ub_xb_channel_ring_channel_to(ring_channel);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	ub_xb_channel_handle_stimulus(channel, ub_xb_channel_stimulus_pe);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+void ub_xb_channel_disconnect(struct ub_xb_channel *channel)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	channel->disconnected = 0;
+	ub_xb_channel_handle_stimulus(channel, ub_xb_channel_stimulus_dn);
+	spin_unlock_irqrestore(&channel->lock, flags);
+	ub_work_until(channel->disconnected);
+}
+
+static void ub_xb_channel_invalid_stimulus(struct ub_xb_channel *channel,
+ub_xb_channel_stimulus stimulus)
+{
+	trace();
+	printk(KERN_ERR "ub: xb channel %p in state %d"
+		" received invalid stimulus %d", channel, channel->state,
+								stimulus);
+}
+
+static void ub_xb_channel_connect_ring(struct ub_xb_channel *channel)
+{
+	trace();
+	channel->ring_connect.domain_id     = channel->domain_id;
+	channel->ring_connect.ring_ref      = channel->ring_ref;
+	channel->ring_connect.event_channel = channel->event_channel;
+	ub_ring_channel_connect(&channel->channel, &channel->ring_connect);
+}
+
+static void ub_xb_channel_connect_ring_1(struct ub_callback *callback)
+{
+	struct ub_xb_channel *channel = container_of(
+		ub_ring_channel_connect_request_callback_to(callback),
+		struct ub_xb_channel, ring_connect);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	if (ub_callback_query_error(callback) == USBIF_ERROR_SUCCESS) {
+		xenbus_switch_state(channel->device, XenbusStateConnected);
+		ub_xb_channel_handle_stimulus(channel,
+					ub_xb_channel_stimulus_rs);
+	} else {
+		ub_xb_channel_handle_stimulus(channel,
+					ub_xb_channel_stimulus_rf);
+	}
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void ub_xb_channel_disconnect_ring(struct ub_xb_channel *channel)
+{
+	trace();
+	ub_ring_channel_disconnect(&channel->channel,
+						&channel->ring_disconnect);
+}
+
+static void ub_xb_channel_disconnect_ring_1(struct ub_callback *callback)
+{
+	struct ub_xb_channel *channel = container_of(callback,
+		struct ub_xb_channel, ring_disconnect);
+	unsigned long flags;
+	trace();
+	xenbus_switch_state(channel->device, XenbusStateClosing);
+	spin_lock_irqsave(&channel->lock, flags);
+	ub_xb_channel_handle_stimulus(channel, ub_xb_channel_stimulus_rs);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void ub_xb_channel_complete_disconnect(struct ub_xb_channel *channel)
+{
+	trace();
+	channel->disconnected = 1;
+	ub_work_wake_up();
+}
+
+static int ub_xb_channel_init_or_exit(struct ub_xb_channel *channel, int exit)
+{
+	int return_value = 0;
+	trace();
+	if (exit)
+		goto exit_path;
+	if ((return_value = ub_ring_channel_init(&channel->channel,
+				ub_xb_channel_protocol_error)) != 0) {
+		goto exit_no_ring_channel;
+	}
+	spin_lock_init(&channel->lock);
+	channel->state = ub_xb_channel_state_i;
+	ub_callback_init(&channel->ring_connect.callback,
+					ub_xb_channel_connect_ring_1);
+	ub_callback_init(&channel->ring_disconnect,
+					ub_xb_channel_disconnect_ring_1);
+	return 0;
+ exit_path:
+	ub_ring_channel_exit(&channel->channel);
+ exit_no_ring_channel:
+	return return_value;
+}
+
+int ub_xb_channel_init(struct ub_xb_channel *channel)
+{
+	trace();
+	return ub_xb_channel_init_or_exit(channel, 0);
+}
+
+void ub_xb_channel_exit(struct ub_xb_channel *channel)
+{
+	trace();
+	(void)ub_xb_channel_init_or_exit(channel, 1);
+}
+
+static void
+ub_xb_channel_handle_stimulus(struct ub_xb_channel *channel,
+ub_xb_channel_stimulus stimulus) {
+	trace_info("xb channel %p in state %d received stimulus %d", channel,
+						channel->state, stimulus);
+	switch (channel->state) {
+	case ub_xb_channel_state_i:
+		switch (stimulus) {
+		case ub_xb_channel_stimulus_cn:
+			channel->state = ub_xb_channel_state_i_cn;
+			break;
+		default:
+			ub_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	case ub_xb_channel_state_i_cn:
+		switch (stimulus) {
+		case ub_xb_channel_stimulus_dn:
+			channel->state = ub_xb_channel_state_i;
+			ub_xb_channel_complete_disconnect(channel);
+			break;
+		case ub_xb_channel_stimulus_fi:
+			channel->state = ub_xb_channel_state_i_cn_fi;
+			ub_xb_channel_connect_ring(channel);
+			break;
+		default:
+			ub_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	case ub_xb_channel_state_i_cn_fi:
+		switch (stimulus) {
+		case ub_xb_channel_stimulus_dn:
+			channel->state = ub_xb_channel_state_i_cn_fi_dn;
+			break;
+		case ub_xb_channel_stimulus_fi:
+			break;
+		case ub_xb_channel_stimulus_rs:
+			channel->state = ub_xb_channel_state_i_cn_fi_rs;
+			break;
+		case ub_xb_channel_stimulus_rf:
+			channel->state = ub_xb_channel_state_i_cn;
+			break;
+		default:
+			ub_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	case ub_xb_channel_state_i_cn_fi_dn:
+		switch (stimulus) {
+		case ub_xb_channel_stimulus_rs:
+			channel->state = ub_xb_channel_state_i_cn_fi_dn_rs;
+			ub_xb_channel_disconnect_ring(channel);
+			break;
+		case ub_xb_channel_stimulus_rf:
+			channel->state = ub_xb_channel_state_i;
+			ub_xb_channel_complete_disconnect(channel);
+			break;
+		default:
+			ub_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	case ub_xb_channel_state_i_cn_fi_rs:
+		switch (stimulus) {
+		case ub_xb_channel_stimulus_dn:
+			channel->state = ub_xb_channel_state_i_cn_fi_dn_rs;
+			ub_xb_channel_disconnect_ring(channel);
+			break;
+		case ub_xb_channel_stimulus_fi:
+			break;
+		case ub_xb_channel_stimulus_fc:
+			channel->state = ub_xb_channel_state_i_cn_fi_rs_fc;
+			ub_xb_channel_disconnect_ring(channel);
+			break;
+		default:
+			ub_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	case ub_xb_channel_state_i_cn_fi_dn_rs:
+		switch (stimulus) {
+		case ub_xb_channel_stimulus_rs:
+			channel->state = ub_xb_channel_state_i;
+			ub_xb_channel_complete_disconnect(channel);
+			break;
+		default:
+			ub_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	case ub_xb_channel_state_i_cn_fi_rs_fc:
+		switch (stimulus) {
+		case ub_xb_channel_stimulus_dn:
+			channel->state = ub_xb_channel_state_i_cn_fi_dn_rs;
+			break;
+		case ub_xb_channel_stimulus_rs:
+			channel->state = ub_xb_channel_state_i_cn_fi_rs_fc_rs;
+			break;
+		default:
+			ub_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	case ub_xb_channel_state_i_cn_fi_rs_fc_rs:
+		switch (stimulus) {
+		case ub_xb_channel_stimulus_dn:
+			channel->state = ub_xb_channel_state_i;
+			ub_xb_channel_complete_disconnect(channel);
+			break;
+		default:
+			ub_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	default:
+		ub_xb_channel_invalid_stimulus(channel, stimulus);
+		break;
+	}
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbback/ub_xb_channel.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/ub_xb_channel.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,77 @@
+/*****************************************************************************/
+/* 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 UB_XB_CHANNEL_H
+#define UB_XB_CHANNEL_H
+
+#include <xen/xenbus.h>
+#include "ub_ring_channel.h"
+
+typedef enum {
+	ub_xb_channel_state_i,
+	ub_xb_channel_state_i_cn,
+	ub_xb_channel_state_i_cn_fi,
+	ub_xb_channel_state_i_cn_fi_dn,
+	ub_xb_channel_state_i_cn_fi_rs,
+	ub_xb_channel_state_i_cn_fi_dn_rs,
+	ub_xb_channel_state_i_cn_fi_rs_fc,
+	ub_xb_channel_state_i_cn_fi_rs_fc_rs
+} ub_xb_channel_state;
+
+struct ub_xb_channel {
+	struct ub_ring_channel                 channel;
+	spinlock_t                             lock;
+	ub_xb_channel_state                    state;
+	struct xenbus_device                  *device;
+	domid_t                                domain_id;
+	grant_ref_t                            ring_ref;
+	evtchn_port_t                          event_channel;
+	struct ub_ring_channel_connect_request ring_connect;
+	struct ub_callback                     ring_disconnect;
+	int                                    disconnected;
+};
+
+static inline struct ub_channel *
+ub_xb_channel_to_channel(struct ub_xb_channel *channel)
+{
+	return ub_ring_channel_to_channel(&channel->channel);
+}
+
+static inline struct ub_xb_channel *
+ub_xb_channel_ring_channel_to(struct ub_ring_channel *ring_channel)
+{
+	return container_of(ring_channel, struct ub_xb_channel, channel);
+}
+
+static inline struct ub_xb_channel *
+ub_xb_channel_channel_to(struct ub_channel *channel)
+{
+	return ub_xb_channel_ring_channel_to(
+				ub_ring_channel_channel_to(channel));
+}
+
+void ub_xb_channel_connect(struct ub_xb_channel *channel,
+struct xenbus_device *device);
+void ub_xb_channel_frontend_changed(struct ub_xb_channel *channel,
+struct xenbus_device *dev, XenbusState state);
+void ub_xb_channel_disconnect(struct ub_xb_channel *channel);
+int ub_xb_channel_init(struct ub_xb_channel *channel);
+void ub_xb_channel_exit(struct ub_xb_channel *channel);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,16 @@
+obj-$(CONFIG_XEN_USBDEV_FRONTEND) += uf.o
+
+uf-objs :=                \
+uf_buffer_rsrc_provider.o \
+uf_callback.o             \
+uf_device.o               \
+uf_driver.o               \
+uf_ep.o                   \
+uf_gw.o                   \
+uf_gw_rsrc.o              \
+uf_module.o               \
+uf_rbr_provider_pool.o    \
+uf_ring_channel.o         \
+uf_work.o                 \
+uf_xb_channel.o \
+uf_rsrc.o
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_buffer_rsrc_provider.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_buffer_rsrc_provider.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,173 @@
+/*****************************************************************************/
+/* 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/blkback/blkback.c                                        */
+/*                                                                           */
+/* original copyright notice follows...                                      */
+/*****************************************************************************/
+/******************************************************************************
+ * arch/xen/drivers/blkif/backend/main.c
+ * 
+ * Back-end of the driver for virtual block devices. This portion of the
+ * driver exports a 'unified' block-device interface that can be accessed
+ * by any operating system that implements a compatible front end. A 
+ * reference front-end implementation can be found in:
+ *  arch/xen/drivers/blkif/frontend
+ * 
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Copyright (c) 2005, Christopher Clark
+ */
+
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/gfp.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/pgalloc.h>
+#include <xen/balloon.h>
+#include <xen/driver_util.h>
+#include "uf_buffer_rsrc_provider.h"
+#include "uf_trace.h"
+
+struct uf_buffer_rsrc_provider {
+	spinlock_t                           lock;
+	struct uf_buffer_rsrc_list rsrcs;
+	struct uf_buffer_rsrc_list free_rsrcs;
+	grant_ref_t                          grant_ref_pool;
+};
+
+static int
+alloc_or_free_grant_refs(struct uf_buffer_rsrc_provider *provider,
+int free)
+{
+	int return_value = 0;
+	if (provider->rsrcs.grant_references == 0)
+		return 0;
+	if (free)
+		goto exit_path;
+	return_value = gnttab_alloc_grant_references(
+				provider->rsrcs.grant_references,
+				&provider->grant_ref_pool);
+	if (return_value != 0)
+		goto exit_no_grant_references;
+	provider->free_rsrcs.grant_references =
+					provider->rsrcs.grant_references;
+	return 0;
+
+ exit_path:
+	gnttab_free_grant_references(provider->grant_ref_pool);
+
+ exit_no_grant_references:
+	return return_value;
+}
+
+static int
+uf_buffer_rsrc_provider_init_or_exit(
+struct uf_buffer_rsrc_provider *provider, int exit)
+{
+	int return_value = 0;
+	trace();
+	if (exit)
+		goto exit_path;
+	spin_lock_init(&provider->lock);
+	provider->free_rsrcs = uf_buffer_rsrc_list_null();
+	if( ( return_value = alloc_or_free_grant_refs(provider, 0) ) != 0 )
+		goto exit_no_grant_refs;
+	return 0;
+ exit_path:
+	alloc_or_free_grant_refs(provider, 1);
+ exit_no_grant_refs:
+	return return_value;
+}
+
+struct uf_buffer_rsrc_provider *
+uf_allocate_buffer_rsrc_provider(
+struct uf_buffer_rsrc_list rsrcs)
+{
+	struct uf_buffer_rsrc_provider *provider;
+	trace();
+	provider = kmalloc(sizeof(struct uf_buffer_rsrc_provider),
+								GFP_KERNEL);
+	if (provider != NULL) {
+		provider->rsrcs = rsrcs;
+		if (uf_buffer_rsrc_provider_init_or_exit(provider, 0)
+		    != 0) {
+			kfree(provider);
+			provider = NULL;
+		}
+	}
+	return provider;
+}
+
+void uf_free_buffer_rsrc_provider(
+struct uf_buffer_rsrc_provider *provider)
+{
+	trace();
+	(void)uf_buffer_rsrc_provider_init_or_exit(provider, 1);
+	kfree(provider);
+}
+
+struct uf_buffer_rsrc_list
+uf_buffer_rsrc_provider_query_free_rsrcs(
+struct uf_buffer_rsrc_provider *provider)
+{
+	struct uf_buffer_rsrc_list list;
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&provider->lock, flags);
+	list = provider->free_rsrcs;
+	spin_unlock_irqrestore(&provider->lock, flags);
+	return list;
+}
+
+grant_ref_t
+uf_buffer_rsrc_provider_allocate_grant_reference(
+struct uf_buffer_rsrc_provider *provider)
+{
+	grant_ref_t reference;
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&provider->lock, flags);
+	provider->free_rsrcs.grant_references--;
+	reference = gnttab_claim_grant_reference(&provider->grant_ref_pool);
+	spin_unlock_irqrestore(&provider->lock, flags);
+	return reference;
+}
+
+void
+uf_buffer_rsrc_provider_free_grant_reference(
+struct uf_buffer_rsrc_provider *provider, grant_ref_t reference)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&provider->lock, flags);
+	gnttab_release_grant_reference(&provider->grant_ref_pool, reference);
+	provider->free_rsrcs.grant_references++;
+	spin_unlock_irqrestore(&provider->lock, flags);
+}
+
+void
+uf_buffer_rsrc_list_trace(struct uf_buffer_rsrc_list list)
+{
+	trace();
+	printk(KERN_INFO "uf %s: grant_references:%d\n",
+		__PRETTY_FUNCTION__, list.grant_references);
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_buffer_rsrc_provider.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_buffer_rsrc_provider.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,78 @@
+/*****************************************************************************/
+/* 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 UF_BUFFER_RSRC_PROVIDER_H
+#define UF_BUFFER_RSRC_PROVIDER_H
+
+#include <linux/string.h>
+#include <asm/types.h>
+#include <xen/gnttab.h>
+
+struct uf_buffer_rsrc_list {
+	u32 grant_references;
+};
+
+static inline struct uf_buffer_rsrc_list
+uf_buffer_rsrc_list_null(void)
+{
+	struct uf_buffer_rsrc_list list;
+	memset(&list, 0, sizeof(list));
+	return list;
+}
+
+static inline int
+uf_buffer_rsrc_list_subset_of(
+struct uf_buffer_rsrc_list *a,
+struct uf_buffer_rsrc_list *b)
+{
+	return a->grant_references <= b->grant_references;
+}
+
+static inline void
+uf_buffer_rsrc_list_plus_equals(
+struct uf_buffer_rsrc_list *a,
+struct uf_buffer_rsrc_list *b)
+{
+	a->grant_references += b->grant_references;
+}
+
+struct uf_buffer_rsrc_provider *
+uf_allocate_buffer_rsrc_provider(
+struct uf_buffer_rsrc_list rsrc_allocation);
+
+void
+uf_free_buffer_rsrc_provider(
+struct uf_buffer_rsrc_provider *provider);
+
+struct uf_buffer_rsrc_list
+uf_buffer_rsrc_provider_query_free_rsrcs(
+struct uf_buffer_rsrc_provider *provider);
+
+grant_ref_t
+uf_buffer_rsrc_provider_allocate_grant_reference(
+struct uf_buffer_rsrc_provider *provider);
+
+void
+uf_buffer_rsrc_provider_free_grant_reference(
+struct uf_buffer_rsrc_provider *provider, grant_ref_t reference);
+
+void
+uf_buffer_rsrc_list_trace(struct uf_buffer_rsrc_list list);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_callback.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_callback.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,39 @@
+/*****************************************************************************/
+/* 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 "uf_callback.h"
+
+void uf_callback_serialiser_function(void *context)
+{
+	struct uf_callback_serialiser *serialiser = context;
+	unsigned long flags;
+	spin_lock_irqsave(&serialiser->lock, flags);
+	while (!list_empty(&serialiser->list) && !serialiser->running) {
+		struct uf_callback *callback =
+			uf_callback_link_to(serialiser->list.next);
+		list_del_init(uf_callback_to_link(callback));
+		serialiser->running = 1;
+		spin_unlock_irqrestore(&serialiser->lock, flags);
+		uf_callback_complete_synchronously(callback);
+		spin_lock_irqsave(&serialiser->lock, flags);
+		serialiser->running = 0;
+	}
+	spin_unlock_irqrestore(&serialiser->lock, flags);
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_callback.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_callback.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,150 @@
+/*****************************************************************************/
+/* A callback object for use in scheduling completion of asynchronous        */
+/* requests.                                                                 */
+/*                                                                           */
+/* 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 UF_CALLBACK_H
+#define UF_CALLBACK_H
+
+#include <linux/spinlock.h>
+#include <xen/interface/io/usbif.h>
+#include "uf_work.h"
+
+static inline int usbif_error_map_to_local(usbif_error error)
+{
+	switch (error) {
+	case USBIF_ERROR_SUCCESS:
+		return 0;
+	case USBIF_ERROR_DISCONNECT:
+		return -ENOTCONN;
+	case USBIF_ERROR_INVALID_PROTOCOL:
+		return -EPROTO;
+	case USBIF_ERROR_INVALID_PARAMETER:
+		return -EINVAL;
+	case USBIF_ERROR_TOO_BIG:
+		return -E2BIG;
+	case USBIF_ERROR_NO_DEVICE:
+		return -ENODEV;
+	case USBIF_ERROR_UNLINKED:
+		return -ECONNRESET;
+	case USBIF_ERROR_PIPE:
+		return -EPIPE;
+	default:
+		return (int)error;
+	}
+}
+
+struct uf_callback {
+	struct uf_work work;
+	usbif_error error;
+};
+
+typedef void uf_callback_function(struct uf_callback *callback);
+
+static inline void
+uf_callback_init(struct uf_callback *callback,
+uf_callback_function *function)
+{
+	uf_work_init(&callback->work, (void (*)(void *))function,
+								callback);
+	callback->error = USBIF_ERROR_SUCCESS;
+}
+
+static inline struct list_head *
+uf_callback_to_link(struct uf_callback *callback)
+{
+	return uf_work_to_link(&callback->work);
+}
+
+static inline struct uf_callback *
+uf_callback_link_to(struct list_head *link)
+{
+	return container_of(uf_work_link_to(link),
+				struct uf_callback, work);
+}
+
+static inline void
+uf_callback_complete(struct uf_callback *callback,
+usbif_error error)
+{
+	callback->error = error;
+	uf_work_schedule(&callback->work);
+}
+
+static inline void
+uf_callback_success(struct uf_callback *callback)
+{
+	uf_callback_complete(callback, 0);
+}
+
+static inline void
+uf_callback_set_error(struct uf_callback *callback,
+usbif_error error)
+{
+	callback->error = error;
+}
+
+static inline void
+uf_callback_complete_synchronously(struct uf_callback *callback)
+{
+	uf_work_perform_synchronously(&callback->work);
+}
+
+static inline usbif_error
+uf_callback_query_error(struct uf_callback *callback)
+{
+	return callback->error;
+}
+
+struct uf_callback_serialiser {
+	spinlock_t lock;
+	struct list_head list;
+	struct uf_work work;
+	int running;
+};
+
+void uf_callback_serialiser_function(void *context);
+
+#define UF_CALLBACK_SERIALISER_INIT( name ) {			\
+	.lock = SPIN_LOCK_UNLOCKED,					\
+	.list = LIST_HEAD_INIT( name.list ),				\
+	.work = UF_WORK_INIT					\
+		( name.work, uf_callback_serialiser_function, &name ),\
+	.running = 0							\
+}
+
+#define UF_CALLBACK_SERIALISER( name ) \
+struct uf_callback_serialiser name =   \
+UF_CALLBACK_SERIALISER_INIT( name )
+
+static inline void
+uf_callback_serialiser_complete_callback(
+struct uf_callback_serialiser *serialiser,
+struct uf_callback *callback, usbif_error error)
+{
+	unsigned long flags;
+	uf_callback_set_error(callback, error);
+	spin_lock_irqsave(&serialiser->lock, flags);
+	list_add_tail(uf_callback_to_link(callback), &serialiser->list);
+	spin_unlock_irqrestore(&serialiser->lock, flags);
+	uf_work_schedule(&serialiser->work);
+}
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_channel.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_channel.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,159 @@
+/*****************************************************************************/
+/* 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 UF_CHANNEL_H
+#define UF_CHANNEL_H
+
+#include <xen/interface/io/usbif.h>
+#include "uf_callback.h"
+
+struct uf_channel_ibmsg {
+	struct uf_callback callback;
+	struct usbif_response    response;
+};
+
+static inline struct list_head *
+uf_channel_ibmsg_to_link(struct uf_channel_ibmsg *message)
+{
+	return &message->callback.work.link;
+}
+
+static inline struct uf_callback *
+uf_channel_ibmsg_to_callback(struct uf_channel_ibmsg *message)
+{
+	return &message->callback;
+}
+
+static inline struct uf_channel_ibmsg *
+uf_channel_ibmsg_callback_to(struct uf_callback *callback)
+{
+	return container_of(callback, struct uf_channel_ibmsg, callback);
+}
+
+static inline void
+uf_channel_ibmsg_init(struct uf_channel_ibmsg *message,
+uf_callback_function *callback)
+{
+	uf_callback_init(uf_channel_ibmsg_to_callback(message),
+								callback);
+}
+
+struct uf_channel_obmsg {
+	struct uf_callback callback;
+	struct usbif_request     request;
+};
+
+static inline struct list_head *
+uf_channel_obmsg_to_link(struct uf_channel_obmsg *message)
+{
+	return &message->callback.work.link;
+}
+
+static inline struct uf_callback *
+uf_channel_obmsg_to_callback(struct uf_channel_obmsg *message)
+{
+	return &message->callback;
+}
+
+static inline struct uf_channel_obmsg *
+uf_channel_obmsg_callback_to(struct uf_callback *callback)
+{
+	return container_of(callback, struct uf_channel_obmsg, callback);
+}
+
+static inline void
+uf_channel_obmsg_init(struct uf_channel_obmsg *message,
+uf_callback_function *callback)
+{
+	uf_callback_init(uf_channel_obmsg_to_callback(message),
+								callback);
+}
+
+struct uf_channel;
+
+typedef void
+uf_channel_submit_message_function(struct uf_channel *channel,
+struct uf_channel_obmsg *message);
+
+typedef void
+uf_channel_connect_function(void *client_context);
+
+typedef void
+uf_channel_handle_message_function(void *client_context,
+struct uf_channel_ibmsg *message);
+
+typedef void
+uf_channel_disconnect_function(void *client_context,
+struct uf_callback *callback);
+
+struct uf_channel {
+	uf_channel_submit_message_function *submit_message;
+	void                                     *client_context;
+	uf_channel_connect_function        *connect;
+	uf_channel_handle_message_function *handle_message;
+	uf_channel_disconnect_function     *disconnect;
+};
+
+static inline void
+uf_channel_init(struct uf_channel *channel,
+uf_channel_submit_message_function *submit_message )
+{
+	channel->submit_message = submit_message;
+}
+
+static inline void uf_channel_connect(struct uf_channel *channel)
+{
+	channel->connect(channel->client_context);
+}
+
+static inline void
+uf_channel_handle_message(struct uf_channel *channel,
+struct uf_channel_ibmsg *message)
+{
+	channel->handle_message(channel->client_context, message);
+}
+
+static inline void
+uf_channel_disconnect(struct uf_channel *channel,
+struct uf_callback *callback)
+{
+	channel->disconnect(channel->client_context, callback);
+}
+
+static inline void
+uf_channel_install_client(struct uf_channel *channel,
+void *client_context, uf_channel_connect_function *connect,
+uf_channel_handle_message_function *handle_message,
+uf_channel_disconnect_function *disconnect)
+{
+	channel->client_context = client_context;
+	channel->connect        = connect;
+	channel->handle_message = handle_message;
+	channel->disconnect     = disconnect;
+}
+
+static inline void
+uf_channel_submit_message(struct uf_channel *channel,
+struct uf_channel_obmsg *message)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	channel->submit_message(channel, message);
+}
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_device.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_device.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,795 @@
+/*****************************************************************************/
+/* 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/frontend/main.c, original copyright       */
+/* notice follows...                                                         */
+/*****************************************************************************/
+
+/*
+ * Xen Virtual USB Frontend Driver 
+ *
+ * This file contains the first version of the Xen virtual USB hub
+ * that I've managed not to delete by mistake (3rd time lucky!).
+ *
+ * Based on Linux's uhci.c, original copyright notices are displayed
+ * below.  Portions also (c) 2004 Intel Research Cambridge
+ * and (c) 2004, 2005 Mark Williamson
+ *
+ * Contact <mark.williamson@xxxxxxxxxxxx> or
+ * <xen-devel@xxxxxxxxxxxxxxxxxxxxx> regarding this code.
+ *
+ * Still to be (maybe) implemented:
+ * - migration / backend restart support?
+ * - support for building / using as a module
+ */
+
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Johannes Erdfelt <johannes@xxxxxxxxxxx>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx
+ * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx
+ * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ *  - the low-level protocol (fairly simple but lots of small details)
+ *  - working around the horridness of the rest
+ */
+
+/*  Xenbus code for blkif backend
+    Copyright (C) 2005 Rusty Russell <rusty@xxxxxxxxxxxxxxx>
+
+    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 <xen/xenbus.h>
+#include "uf_device.h"
+#include "uf_driver.h"
+#include "uf_xb_channel.h"
+#include "uf_trace.h"
+
+typedef enum {
+	uf_device_state_i,
+	uf_device_state_i_cn,
+	uf_device_state_i_cn_dn,
+	uf_device_state_i_cn_ps,
+	uf_device_state_i_cn_pf,
+	uf_device_state_i_cn_dn_ps,
+	uf_device_state_i_cn_ps_dn,
+	uf_device_state_i_cn_ps_pc,
+	uf_device_state_i_cn_ps_dn_rc
+} uf_device_state;
+
+typedef enum {
+	uf_device_stimulus_cn, /* Gateway connect.        */
+	uf_device_stimulus_dn, /* Gateway disconnect.     */
+	uf_device_stimulus_ps, /* Probe driver success.   */
+	uf_device_stimulus_pf, /* Probe driver failure.   */
+	uf_device_stimulus_rc, /* Remove driver complete. */
+	uf_device_stimulus_pt, /* Polling tick.           */
+	uf_device_stimulus_pc  /* Probe complete.         */
+} uf_device_stimulus;
+
+struct uf_device {
+	struct list_head       lookup_link;
+	struct xenbus_device  *dev;
+	void                  *drvdata;
+	spinlock_t             lock;
+	uf_device_state        state;
+	struct uf_xb_channel   channel;
+	struct uf_gw           gw;
+	struct uf_callback    *gw_disconnect_callback;
+	int                    port_probe_count;
+	struct uf_gw_tra       probe;
+	struct usb_port_status port_status;
+	struct uf_work         probe_driver_1_work;
+	struct uf_work         remove_driver_1_work;
+};
+
+static spinlock_t lookup_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(lookup_list);
+
+static void
+uf_device_handle_stimulus(struct uf_device *device,
+uf_device_stimulus stimulus);
+
+static inline struct uf_device *uf_device_gw_to(struct uf_gw *gw)
+{
+	return container_of(gw, struct uf_device, gw);
+}
+
+void uf_device_set_drvdata(struct uf_device *device, void *data)
+{
+	device->drvdata = data;
+}
+
+void *uf_device_get_drvdata(struct uf_device *device)
+{
+	return device->drvdata;
+}
+
+struct device *uf_device_to_dev(struct uf_device *device)
+{
+	return &device->dev->dev;
+}
+
+static void uf_device_add_to_lookup_list(struct uf_device *device)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&lookup_lock, flags);
+	list_add(&device->lookup_link, &lookup_list);
+	spin_unlock_irqrestore(&lookup_lock, flags);
+}
+
+static void uf_device_del_from_lookup_list(struct uf_device *device)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&lookup_lock, flags);
+	list_del_init(&device->lookup_link);
+	spin_unlock_irqrestore(&lookup_lock, flags);
+}
+
+struct uf_device *uf_device_xenbus_dev_to(struct xenbus_device *dev)
+{
+	struct uf_device * device = NULL;
+	struct uf_device * cur;
+	unsigned long flags;
+	spin_lock_irqsave(&lookup_lock, flags);
+	list_for_each_entry(cur, &lookup_list, lookup_link){
+		if(cur->dev == dev ) {
+			device = cur;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&lookup_lock, flags);
+	return device;
+}
+
+struct uf_device *uf_device_dev_to(struct device *dev)
+{
+	return uf_device_xenbus_dev_to(to_xenbus_device(dev));
+}
+
+int uf_device_query_port_status_changed(struct uf_device *device)
+{
+	int changed;
+	unsigned long flags;
+	spin_lock_irqsave(&device->lock, flags);
+	uf_device_handle_stimulus(device, uf_device_stimulus_pt);
+	changed = (device->port_status.wPortChange != 0);
+	spin_unlock_irqrestore(&device->lock, flags);
+	return changed;
+}
+
+struct usb_port_status uf_device_query_port_status(struct uf_device *device)
+{
+	struct usb_port_status port_status;
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&device->lock, flags);
+	port_status = device->port_status;
+	spin_unlock_irqrestore(&device->lock, flags);
+	return port_status;
+}
+
+void uf_device_set_port_power(struct uf_device *device)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&device->lock, flags);
+	device->port_status.wPortStatus |= USB_PORT_STAT_POWER;
+	spin_unlock_irqrestore(&device->lock, flags);
+}
+
+void uf_device_set_port_reset(struct uf_device *device)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&device->lock, flags);
+	device->port_status.wPortStatus |= USB_PORT_STAT_RESET;
+	device->port_status.wPortStatus &= ~USB_PORT_STAT_ENABLE;
+	uf_device_handle_stimulus(device, uf_device_stimulus_pt);
+	spin_unlock_irqrestore(&device->lock, flags);
+}
+
+void uf_device_clear_port_enable(struct uf_device *device)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&device->lock, flags);
+	device->port_status.wPortStatus &= ~USB_PORT_STAT_ENABLE;
+	spin_unlock_irqrestore(&device->lock, flags);
+}
+
+void uf_device_clear_port_connection_change(struct uf_device *device)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&device->lock, flags);
+	device->port_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
+	spin_unlock_irqrestore(&device->lock, flags);
+}
+
+void uf_device_clear_port_reset_change(struct uf_device *device)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&device->lock, flags);
+	device->port_status.wPortChange &= ~USB_PORT_STAT_C_RESET;
+	spin_unlock_irqrestore(&device->lock, flags);
+}
+
+domid_t uf_device_query_domain(struct uf_device *device)
+{
+	trace();
+	return device->dev->otherend_id;
+}
+
+void uf_device_submit_tra(struct uf_device *device, struct uf_gw_tra *tra)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	trace();
+	uf_gw_submit_tra(&device->gw, tra);
+}
+
+static void uf_device_gw_connect(struct uf_gw *gw)
+{
+	struct uf_device *device = uf_device_gw_to(gw);
+	unsigned long flags;
+	trace();
+	/* Between connect and completion of the disconnect callback we are  */
+	/* allowed to issue tras.                                            */
+	spin_lock_irqsave(&device->lock, flags);
+	uf_device_handle_stimulus(device, uf_device_stimulus_cn);
+	spin_unlock_irqrestore(&device->lock, flags);
+}
+
+static void
+uf_device_gw_disconnect(struct uf_gw *gw, struct uf_callback *callback)
+{
+	struct uf_device *device = uf_device_gw_to(gw);
+	unsigned long flags;
+	trace();
+	/* We must stop issuing tras and complete the callback once  */
+	/* all of the tras we are issuing have completed or failed   */
+	/* back to us.                                               */
+	spin_lock_irqsave(&device->lock, flags);
+	device->gw_disconnect_callback = callback;
+	uf_device_handle_stimulus(device, uf_device_stimulus_dn);
+	spin_unlock_irqrestore(&device->lock, flags);
+}
+
+static void uf_device_invalid_stimulus(struct uf_device *device,
+uf_device_stimulus stimulus)
+{
+	trace();
+	printk(KERN_ERR "uf: device %p in state %d received invalid "
+			"stimulus %d\n", device, device->state, stimulus);
+}
+
+static void uf_device_probe_driver(struct uf_device *device)
+{
+	trace();
+	(void)uf_work_schedule(&device->probe_driver_1_work);
+}
+
+static void uf_device_probe_driver_1(void *data)
+{
+	struct uf_device *device = data;
+	uf_device_stimulus stimulus;
+	unsigned long flags;
+	trace();
+	if (uf_driver_probe(device) == 0) {
+		stimulus = uf_device_stimulus_ps;
+	} else {
+		stimulus = uf_device_stimulus_pf;
+	}
+	spin_lock_irqsave(&device->lock, flags);
+	uf_device_handle_stimulus(device, stimulus);
+	spin_unlock_irqrestore(&device->lock, flags);
+}
+
+static void uf_device_remove_driver(struct uf_device *device)
+{
+	trace();
+	(void)uf_work_schedule(&device->remove_driver_1_work);
+}
+
+static void uf_device_remove_driver_1(void *data)
+{
+	struct uf_device *device = data;
+	unsigned long flags;
+	trace();
+	uf_driver_remove(device);
+	spin_lock_irqsave(&device->lock, flags);
+	uf_device_handle_stimulus(device, uf_device_stimulus_rc);
+	spin_unlock_irqrestore(&device->lock, flags);
+}
+
+static void uf_device_probe_all_ports(struct uf_device *device)
+{
+	device->port_probe_count = 1;
+	if ((device->port_status.wPortStatus & USB_PORT_STAT_RESET) !=
+							USB_PORT_STAT_RESET) {
+		device->probe.parameters.header.tra_type =
+						USBIF_TRA_TYPE_PROBE;
+	} else {
+		device->probe.parameters.header.tra_type =
+						USBIF_TRA_TYPE_RESET;
+	}
+	uf_gw_submit_tra(&device->gw, &device->probe);
+}
+
+static void uf_device_probe_all_ports_1(struct uf_callback *callback)
+{
+	struct uf_device *device = container_of(
+			uf_gw_tra_callback_to(callback),
+			struct uf_device, probe);
+	unsigned long flags;
+	spin_lock_irqsave(&device->lock, flags);
+	if (device->probe.parameters.header.tra_type ==
+						USBIF_TRA_TYPE_PROBE) {
+		if (uf_callback_query_error(callback) ==
+							USBIF_ERROR_SUCCESS) {
+			struct usb_port_status *port_status =
+							&device->port_status;
+			if (device->probe.status.probe.result ==
+					USBIF_PROBE_RESULT_DEVICE_PRESENT) {
+				/* There is a device attached to the port. */
+				if ((port_status->wPortStatus &
+					USB_PORT_STAT_CONNECTION) !=
+						USB_PORT_STAT_CONNECTION) {
+					/* There wasn't a device attached to */
+					/* the port before.                  */
+					port_status->wPortStatus |=
+						USB_PORT_STAT_CONNECTION;
+					port_status->wPortChange |=
+						USB_PORT_STAT_C_CONNECTION;
+				}
+			} else if (device->probe.status.probe.result ==
+						USBIF_PROBE_RESULT_NO_DEVICE) {
+				/* There isn't a device attached to the port.*/
+				if ((port_status->wPortStatus &
+					USB_PORT_STAT_CONNECTION) ==
+						USB_PORT_STAT_CONNECTION) {
+					/* There was a device attached to */
+					/* the port before.               */
+					port_status->wPortStatus &=
+						~USB_PORT_STAT_CONNECTION;
+					port_status->wPortChange |=
+						USB_PORT_STAT_C_CONNECTION;
+				}
+			} else {
+				trace_info("device %p: unexpected result %d "
+					"probing port", device,
+					(int)device->probe.status.probe.
+								result);
+			}
+		} else {
+			trace_info("device %p: error %d probing port",
+				device, usbif_error_map_to_local(
+				uf_callback_query_error(callback)));
+		}
+	} else {
+		struct usb_port_status *port_status = &device->port_status;
+		if ((uf_callback_query_error(callback) ==
+						USBIF_ERROR_SUCCESS) &&
+				((device->probe.status.reset.result ==
+					USBIF_RESET_RESULT_FULL_SPEED) ||
+				(device->probe.status.reset.result ==
+					USBIF_RESET_RESULT_LOW_SPEED)  ||
+				(device->probe.status.reset.result ==
+					USBIF_RESET_RESULT_HIGH_SPEED))) {
+			if (device->probe.status.reset.result ==
+					    USBIF_RESET_RESULT_LOW_SPEED) {
+				port_status->wPortStatus |=
+						USB_PORT_STAT_LOW_SPEED;
+				port_status->wPortStatus &=
+						~USB_PORT_STAT_HIGH_SPEED;
+			} else if (device->probe.status.reset.result ==
+					USBIF_RESET_RESULT_HIGH_SPEED) {
+				port_status->wPortStatus &=
+						~USB_PORT_STAT_LOW_SPEED;
+				port_status->wPortStatus |=
+						USB_PORT_STAT_HIGH_SPEED;
+			} else {
+				port_status->wPortStatus &=
+						~USB_PORT_STAT_LOW_SPEED;
+				port_status->wPortStatus &=
+						~USB_PORT_STAT_HIGH_SPEED;
+			}
+			port_status->wPortStatus &= ~USB_PORT_STAT_RESET;
+			port_status->wPortStatus |= USB_PORT_STAT_ENABLE;
+			port_status->wPortChange |= USB_PORT_STAT_C_RESET;
+		} else {
+			if (uf_callback_query_error(callback) !=
+							USBIF_ERROR_SUCCESS) {
+				printk(KERN_ERR "uf: device %p: error %d"
+					" resetting port", device,
+					usbif_error_map_to_local(
+						uf_callback_query_error(
+								callback)));
+			} else {
+				trace_info("device %p: unexpected result %d"
+				" resetting port", device,
+				(int)device->probe.status.probe.result);
+			}
+			port_status->wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
+			port_status->wPortStatus &= ~USB_PORT_STAT_HIGH_SPEED;
+			port_status->wPortStatus &= ~USB_PORT_STAT_RESET;
+			port_status->wPortChange |= USB_PORT_STAT_C_RESET;
+		}
+	}
+
+	if (--device->port_probe_count == 0)
+		uf_device_handle_stimulus(device,
+						uf_device_stimulus_pc);
+	spin_unlock_irqrestore(&device->lock, flags);
+}
+
+static void uf_device_disconnect_all_ports(struct uf_device *device)
+{
+	struct usb_port_status *port_status = &device->port_status;
+	trace();
+	if ((port_status->wPortStatus & USB_PORT_STAT_CONNECTION) ==
+						USB_PORT_STAT_CONNECTION) {
+		/* There was a device attached to the port before. */
+		port_status->wPortStatus &= ~USB_PORT_STAT_CONNECTION;
+		port_status->wPortChange |= USB_PORT_STAT_C_CONNECTION;
+	}
+}
+
+static void uf_device_complete_gw_disconnect(struct uf_device *device)
+{
+	trace();
+	uf_callback_success(device->gw_disconnect_callback);
+}
+
+static int uf_device_resume_or_suspend(struct uf_device *device, int suspend)
+{
+	trace();
+	if (suspend)
+		goto suspend_path;
+	uf_xb_channel_connect(&device->channel, device->dev);
+	return 0;
+ suspend_path:
+	uf_xb_channel_disconnect(&device->channel);
+	return 0;
+}
+
+static int uf_device_init_or_exit(struct uf_device *device,
+struct xenbus_device *dev, int exit)
+{
+	int return_value = 0;
+	trace();
+	if (exit)
+		goto exit_path;
+	INIT_LIST_HEAD(&device->lookup_link);
+	device->dev = dev;
+	uf_device_add_to_lookup_list(device);
+	spin_lock_init(&device->lock);
+	device->state = uf_device_state_i;
+	uf_gw_tra_init(&device->probe,
+				uf_device_probe_all_ports_1);
+	uf_work_init(&device->probe_driver_1_work,
+				uf_device_probe_driver_1, device);
+	uf_work_init(&device->remove_driver_1_work,
+				uf_device_remove_driver_1, device);
+	return_value = uf_xb_channel_init(&device->channel);
+	if (return_value != 0)
+		goto exit_no_channel;
+	return_value = uf_gw_init(&device->gw,
+			uf_xb_channel_to_channel(&device->channel),
+			uf_device_gw_connect,
+			uf_device_gw_disconnect,
+			USBIF_QUOTA);
+	if (return_value != 0)
+		goto exit_no_gw;
+	return_value = uf_device_resume_or_suspend(device, 0);
+	if (return_value != 0)
+		goto exit_no_resume;
+	return 0;
+ exit_path:
+	(void)uf_device_resume_or_suspend(device, 1);
+ exit_no_resume:
+	uf_gw_exit(&device->gw);
+ exit_no_gw:
+	uf_xb_channel_exit(&device->channel);
+ exit_no_channel:
+	uf_device_del_from_lookup_list(device);
+	return return_value;
+}
+
+static int uf_device_init(struct uf_device *device, struct xenbus_device *dev)
+{
+	trace();
+	return uf_device_init_or_exit(device, dev, 0);
+}
+
+static void uf_device_exit(struct uf_device *device)
+{
+	trace();
+	(void)uf_device_init_or_exit(device, NULL, 1);
+}
+
+static int uf_device_probe_or_remove(struct xenbus_device *dev, int remove)
+{
+	int return_value = 0;
+	struct uf_device *device;
+	trace();
+	if (remove)
+		goto remove_path;
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (device == NULL) {
+		xenbus_dev_error(dev, -ENOMEM,"allocating FE structure");
+		return_value = -ENOMEM;
+		goto exit_no_device;
+	}
+	return_value = uf_device_init(device, dev);
+	if (return_value != 0)
+		goto exit_init_failed;
+	return 0;
+ remove_path:
+	device = uf_device_xenbus_dev_to(dev);
+	uf_device_exit(device);
+ exit_init_failed:
+	kfree(device);
+ exit_no_device:
+	return return_value;
+}
+
+static int
+uf_device_probe(struct xenbus_device *dev, const struct xenbus_device_id *id)
+{
+	trace();
+	return uf_device_probe_or_remove(dev, 0);
+}
+
+static int uf_device_remove(struct xenbus_device *dev)
+{
+	trace();
+	return uf_device_probe_or_remove(dev, 1);
+}
+
+static int uf_device_resume(struct xenbus_device *dev)
+{
+	struct uf_device *device = uf_device_xenbus_dev_to(dev);
+	trace();
+	(void)uf_device_resume_or_suspend(device, 1);
+	return uf_device_resume_or_suspend(device, 0);
+}
+
+static void
+uf_device_backend_changed(struct xenbus_device *dev, XenbusState state)
+{
+	struct uf_device *device = uf_device_xenbus_dev_to(dev);
+	trace();
+	uf_xb_channel_backend_changed(&device->channel, dev, state);
+}
+
+static struct xenbus_device_id uf_device_ids[] = {
+	{"usbport"},
+	{""}
+};
+
+static struct xenbus_driver uf_device_driver = {
+	.name             = "usbport",
+	.owner            = THIS_MODULE,
+	.ids              = uf_device_ids,
+	.probe            = uf_device_probe,
+	.remove           = uf_device_remove,
+	.resume           = uf_device_resume,
+	.otherend_changed = uf_device_backend_changed,
+};
+
+int uf_device_class_init(void)
+{
+	trace();
+	return xenbus_register_frontend(&uf_device_driver);
+}
+
+void uf_device_class_exit(void)
+{
+	trace();
+	xenbus_unregister_driver(&uf_device_driver);
+}
+
+static void uf_device_handle_stimulus(struct uf_device *device,
+uf_device_stimulus stimulus)
+{
+	switch (device->state) {
+	case uf_device_state_i:
+		switch (stimulus) {
+		case uf_device_stimulus_cn:
+			device->state = uf_device_state_i_cn;
+			uf_device_probe_driver(device);
+			break;
+		default:
+			uf_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case uf_device_state_i_cn:
+		/* Probing driver. */
+		switch (stimulus) {
+		case uf_device_stimulus_dn:
+			device->state = uf_device_state_i_cn_dn;
+			break;
+		case uf_device_stimulus_ps:
+			device->state = uf_device_state_i_cn_ps;
+			uf_device_probe_all_ports(device);
+			break;
+		case uf_device_stimulus_pf:
+			device->state = uf_device_state_i_cn_pf;
+			break;
+		case uf_device_stimulus_pt:
+			break;
+		default:
+			uf_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case uf_device_state_i_cn_dn:
+		/* Probing driver.         */
+		/* Gateway disconnecting. */
+		switch (stimulus) {
+		case uf_device_stimulus_ps:
+			device->state = uf_device_state_i_cn_dn_ps;
+			uf_device_remove_driver(device);
+			break;
+		case uf_device_stimulus_pf:
+			device->state = uf_device_state_i;
+			uf_device_disconnect_all_ports(device);
+			uf_device_complete_gw_disconnect(device);
+			break;
+		case uf_device_stimulus_pt:
+			break;
+		default:
+			uf_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case uf_device_state_i_cn_ps:
+		/* Driver Probed. */
+		/* Polling ports. */
+		switch (stimulus) {
+		case uf_device_stimulus_dn:
+			device->state = uf_device_state_i_cn_ps_dn;
+			uf_device_remove_driver(device);
+			break;
+		case uf_device_stimulus_pt:
+			break;
+		case uf_device_stimulus_pc:
+			device->state = uf_device_state_i_cn_ps_pc;
+			break;
+		default:
+			uf_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case uf_device_state_i_cn_pf:
+		/* Driver probe failed. */
+		switch (stimulus) {
+		case uf_device_stimulus_dn:
+			device->state = uf_device_state_i;
+			uf_device_disconnect_all_ports(device);
+			uf_device_complete_gw_disconnect(device);
+			break;
+		default:
+			uf_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case uf_device_state_i_cn_dn_ps:
+		/* Gateway disconnecting. */
+		/* Removing driver.        */
+		switch (stimulus) {
+		case uf_device_stimulus_rc:
+			device->state = uf_device_state_i;
+			uf_device_disconnect_all_ports(device);
+			uf_device_complete_gw_disconnect(device);
+			break;
+		case uf_device_stimulus_pt:
+			break;
+		default:
+			uf_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case uf_device_state_i_cn_ps_dn:
+		/* Gateway disconnecting. */
+		/* Removing driver.        */
+		/* Polling ports.          */
+		switch (stimulus) {
+		case uf_device_stimulus_rc:
+			device->state = uf_device_state_i_cn_ps_dn_rc;
+			break;
+		case uf_device_stimulus_pt:
+			break;
+		case uf_device_stimulus_pc:
+			device->state = uf_device_state_i_cn_dn_ps;
+			break;
+		default:
+			uf_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case uf_device_state_i_cn_ps_pc:
+		/* Driver Probed. */
+		switch (stimulus) {
+		case uf_device_stimulus_dn:
+			device->state = uf_device_state_i_cn_dn_ps;
+			uf_device_remove_driver(device);
+			break;
+		case uf_device_stimulus_pt:
+			device->state = uf_device_state_i_cn_ps;
+			uf_device_probe_all_ports(device);
+			break;
+		default:
+			uf_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	case uf_device_state_i_cn_ps_dn_rc:
+		/* Gateway disconnecting. */
+		/* Polling ports.          */
+		switch (stimulus) {
+		case uf_device_stimulus_pc:
+			device->state = uf_device_state_i;
+			uf_device_disconnect_all_ports(device);
+			uf_device_complete_gw_disconnect(device);
+			break;
+		default:
+			uf_device_invalid_stimulus(device, stimulus);
+			break;
+		}
+		break;
+	default:
+		uf_device_invalid_stimulus(device, stimulus);
+		break;
+	}
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_device.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_device.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,48 @@
+/*****************************************************************************/
+/* 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 UF_DEVICE_H
+#define UF_DEVICE_H
+
+#include <linux/device.h>
+#include <linux/usb.h>
+#include <xen/interface/io/usbif.h>
+#include "../../usb/core/hcd.h"
+#include "uf_gw.h"
+
+int uf_device_class_init(void);
+void uf_device_class_exit(void);
+
+struct uf_device;
+
+void uf_device_set_drvdata(struct uf_device *device, void *data);
+void *uf_device_get_drvdata(struct uf_device *device);
+struct device *uf_device_to_dev(struct uf_device *device);
+struct uf_device *uf_device_dev_to(struct device *dev);
+int uf_device_query_port_status_changed(struct uf_device *device);
+struct usb_port_status uf_device_query_port_status(struct uf_device *device);
+void uf_device_set_port_power(struct uf_device *device);
+void uf_device_set_port_reset(struct uf_device *device);
+void uf_device_clear_port_enable(struct uf_device *device);
+void uf_device_clear_port_connection_change(struct uf_device *device);
+void uf_device_clear_port_reset_change(struct uf_device *device);
+domid_t uf_device_query_domain(struct uf_device *device);
+void uf_device_submit_tra(struct uf_device *device, struct uf_gw_tra *tra);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_driver.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_driver.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,429 @@
+/*****************************************************************************/
+/* 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/frontend/main.c                                    */
+/* pristine-linux-2.6.11/drivers/usb/host/uhci-hcd.c                         */
+/* pristine-linux-2.6.11/drivers/usb/core/hcd-pci.c                          */
+/*                                                                           */
+/* original copyright notices follow...                                      */
+/*****************************************************************************/
+
+/*
+ * Xen Virtual USB Frontend Driver 
+ *
+ * This file contains the first version of the Xen virtual USB hub
+ * that I've managed not to delete by mistake (3rd time lucky!).
+ *
+ * Based on Linux's uhci.c, original copyright notices are displayed
+ * below.  Portions also (c) 2004 Intel Research Cambridge
+ * and (c) 2004, 2005 Mark Williamson
+ *
+ * Contact <mark.williamson@xxxxxxxxxxxx> or
+ * <xen-devel@xxxxxxxxxxxxxxxxxxxxx> regarding this code.
+ *
+ * Still to be (maybe) implemented:
+ * - migration / backend restart support?
+ * - support for building / using as a module
+ */
+
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Johannes Erdfelt <johannes@xxxxxxxxxxx>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx
+ * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx
+ * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ *  - the low-level protocol (fairly simple but lots of small details)
+ *  - working around the horridness of the rest
+ */
+
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx
+ * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx
+ * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ * (C) Copyright 2004 Alan Stern, stern@xxxxxxxxxxxxxxxxxxx
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ *  - the low-level protocol (fairly simple but lots of small details)
+ *  - working around the horridness of the rest
+ */
+
+/*
+ * (C) Copyright David Brownell 2000-2002
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/device.h>
+#include "uf_driver.h"
+#include "uf_ep.h"
+#include "uf_trace.h"
+
+#define UF_DRIVER_EP_COUNT 32
+
+struct uf_hcd {
+	struct uf_ep ep[UF_DRIVER_EP_COUNT];
+};
+
+static struct uf_hcd *uf_hcd_hcd_to_uhcd(struct usb_hcd *hcd)
+{
+	return (struct uf_hcd *)(hcd->hcd_priv);
+}
+
+static struct uf_device *uf_hcd_hcd_to_uf_device(struct usb_hcd *hcd)
+{
+	return uf_device_dev_to(hcd_to_bus(hcd)->controller);
+}
+
+
+static int uf_hcd_start_or_stop(struct usb_hcd *hcd, int stop)
+{
+	int return_value = 0;
+	struct uf_hcd *uhcd = uf_hcd_hcd_to_uhcd(hcd);
+	int i = UF_DRIVER_EP_COUNT;
+	trace();
+	if (stop)
+		goto stop_path;
+	memset(uhcd, 0, sizeof(*uhcd));
+	for (i = 0; i < UF_DRIVER_EP_COUNT; i++) {
+		struct uf_ep *ep = &uhcd->ep[i];
+		return_value = uf_ep_init(ep, uf_hcd_hcd_to_uf_device(hcd));
+		if (return_value != 0)
+			goto exit_no_ep;
+	}
+	hcd->state = HC_STATE_RUNNING;	/* FIXME: breaks encapsulation */
+	return 0;
+ stop_path:
+ exit_no_ep:
+	for( i--; i >= 0; i-- )
+		uf_ep_exit(&uhcd->ep[i]);
+	return return_value;
+}
+
+static int uf_hcd_start(struct usb_hcd *hcd)
+{
+	trace();
+	return uf_hcd_start_or_stop(hcd, 0);
+}
+
+static void uf_hcd_stop(struct usb_hcd *hcd)
+{
+	trace();
+	(void)uf_hcd_start_or_stop(hcd, 1);
+}
+
+static int uf_hcd_get_frame_number(struct usb_hcd *hcd)
+{
+	trace();
+	return 0;
+}
+
+static int
+uf_hcd_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep,
+struct urb *urb, gfp_t mem_flags)
+{
+	struct uf_hcd *uhcd = uf_hcd_hcd_to_uhcd(hcd);
+	int ep_index = usb_pipeendpoint(urb->pipe) +
+				(usb_pipein(urb->pipe) ? 16 : 0);
+	trace();
+	uf_ep_urb_enqueue(&uhcd->ep[ep_index], urb);
+	return 0;
+}
+
+static int uf_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+	struct uf_hcd *uhcd = uf_hcd_hcd_to_uhcd(hcd);
+	int ep_index = usb_pipeendpoint(urb->pipe) +
+				(usb_pipein(urb->pipe) ? 16 : 0);
+	trace();
+	return uf_ep_urb_dequeue(&uhcd->ep[ep_index], urb);
+}
+
+static void
+uf_hcd_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+	trace();
+	/* FIXME: need to call uf_ep_disable for the right endpoint */
+}
+
+static int uf_hcd_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	int changed = 0;
+	struct uf_device *device = uf_hcd_hcd_to_uf_device(hcd);
+	*buf = 0;
+	if (uf_device_query_port_status_changed(device)) {
+		*buf   |= 2;
+		changed = 1;
+	}
+	return changed ? 1 : 0;
+}
+
+static int uf_hcd_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+u16 wIndex, char *buf, u16 wLength)
+{
+	struct uf_device *device = uf_hcd_hcd_to_uf_device(hcd);
+	int return_value = 0;
+	trace();
+	switch (typeReq) {
+	case GetHubStatus:
+		trace_info("GetHubStatus");
+		if ((wValue != 0) || (wIndex != 0) || (wLength != 4))
+			goto error;
+		/* 2 bytes wHubStatus and 2 bytes wHubChange:        */
+		/* Local power supply good, no overcurrect condition */
+		/* No changes.                                       */
+		memset(buf, 0, wLength);
+		break;
+	case GetPortStatus:
+		trace_info("GetPortStatus");
+		if ((wValue != 0) || (wIndex > 1) || (wLength != 4))
+			goto error;
+		{
+			struct usb_port_status port_status =
+				    uf_device_query_port_status(device);
+			memcpy(buf, &port_status, wLength);
+		}
+		break;
+	case GetHubDescriptor:
+		trace_info("GetHubDescriptor");
+		{
+			/* bDescLength             */
+			/* bDescriptorType         */
+			/* bNbrPorts               */
+			/* wHubCharacteristics LSB */
+			/* wHubCharacteristics MSB */
+			/* bPwrOn2PwrGood          */
+			/* bHubContrCurrent        */
+			/* DeviceRemovable         */
+			/* PortPwrCtrlMask         */
+			/* See table 11.23.2.1 of the USB 2.0 specification. */
+
+			char descriptor[] = { 0x09, 0x29, 0x00, 0x00, 0x00,
+						0x01, 0x00, 0x00, 0xFF };
+			descriptor[2] = 1;
+			memcpy(buf, &descriptor, min_t(size_t, sizeof(
+							descriptor), wLength));
+		}
+		break;
+	case SetPortFeature:
+		trace_info("SetPortFeature");
+		if (((wIndex & 0x00FF) > 1) || (wLength != 0))
+			goto error;
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			trace_info("USB_PORT_FEAT_SUSPEND");
+			break;
+		case USB_PORT_FEAT_RESET:
+			trace_info("USB_PORT_FEAT_RESET");
+			uf_device_set_port_reset(device);
+			break;
+		case USB_PORT_FEAT_POWER:
+			trace_info("USB_PORT_FEAT_POWER");
+			uf_device_set_port_power(device);
+			break;
+		default:
+			trace_info("Unknown:%x", wValue);
+			goto error;
+		}
+		break;
+	case ClearPortFeature:
+		trace_info("ClearPortFeature");
+		if (((wIndex & 0x00FF) > 1) || (wLength != 0))
+			goto error;
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			trace_info("USB_PORT_FEAT_ENABLE");
+			uf_device_clear_port_enable(device);
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+			trace_info("USB_PORT_FEAT_SUSPEND");
+			break;
+		case USB_PORT_FEAT_POWER:
+			trace_info("USB_PORT_FEAT_POWER");
+			break;
+		case USB_PORT_FEAT_INDICATOR:
+			trace_info("USB_PORT_FEAT_INDICATOR");
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			trace_info("USB_PORT_C_CONNECTION");
+			uf_device_clear_port_connection_change(device);
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			trace_info("USB_PORT_C_RESET");
+			uf_device_clear_port_reset_change(device);
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			trace_info("USB_PORT_C_ENABLE");
+			break;
+		case USB_PORT_FEAT_C_SUSPEND:
+			trace_info("USB_PORT_C_SUSPEND");
+			break;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			trace_info("USB_PORT_C_OVER_CURRENT");
+			break;
+		default:
+			trace_info("Unknown:%x", wValue);
+			goto error;
+		}
+		break;
+	default:
+		trace_info("Unknown:%x", typeReq);
+	error:
+		return_value = -EPIPE;
+	}
+	return return_value;
+}
+
+static int uf_hcd_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
+{
+	trace();
+	return 0;
+}
+
+static struct hc_driver uf_hc_driver = {
+	.description = "uf_hc_driver",
+	.product_desc = "Xen USB Front-End Driver",
+	.hcd_priv_size = sizeof(struct uf_hcd),
+	/* .irq */
+	.flags = HCD_USB2,
+	/* reset optional. */
+	.start = uf_hcd_start,
+	/* suspend optional. */
+	/* resume optional. */
+	.stop = uf_hcd_stop,
+	.get_frame_number = uf_hcd_get_frame_number,
+	.urb_enqueue = uf_hcd_urb_enqueue,
+	.urb_dequeue = uf_hcd_urb_dequeue,
+	.endpoint_disable = uf_hcd_endpoint_disable,
+	.hub_status_data = uf_hcd_hub_status_data,
+	.hub_control = uf_hcd_hub_control,
+	/* hub_suspend optional. */
+	/* hub_resume optional. */
+	.start_port_reset = uf_hcd_start_port_reset,
+};
+
+static int uf_driver_probe_or_remove(struct uf_device *device, int remove)
+{
+	int return_value = 0;
+	struct usb_hcd *hcd;
+	trace();
+	if (remove)
+		goto remove_path;
+	if (usb_disabled()) {
+		return_value = -ENODEV;
+		goto exit_no_usb;
+	}
+	trace_info( "Trying to allocate %d bytes for uf_hcd", sizeof(struct uf_hcd));
+	if ((hcd = usb_create_hcd(&uf_hc_driver,
+			uf_device_to_dev(device),
+			uf_device_to_dev(device)->bus_id))== NULL) {
+		trace_info("usb_create_hcd failed");
+		return_value = -ENOMEM;
+		goto exit_no_hcd;
+	}
+	uf_device_set_drvdata(device, hcd);
+	if ((return_value = usb_add_hcd(hcd, 0, 0)) != 0) {
+		trace_info("usb_add_hcd failed");
+		goto exit_no_add;
+	}
+	return 0;
+ remove_path:
+	hcd = uf_device_get_drvdata(device);
+	usb_remove_hcd(hcd);
+ exit_no_add:
+	usb_put_hcd(hcd);
+	uf_device_set_drvdata(device, NULL);
+ exit_no_hcd:
+ exit_no_usb:
+	return return_value;
+}
+
+int uf_driver_probe(struct uf_device *device)
+{
+	trace();
+	return uf_driver_probe_or_remove(device, 0);
+}
+
+void uf_driver_remove(struct uf_device *device)
+{
+	trace();
+	uf_driver_probe_or_remove(device, 1);
+}
+
+int uf_driver_class_init(void)
+{
+	trace();
+	return uf_ep_class_init();
+}
+
+void uf_driver_class_exit(void)
+{
+	trace();
+	uf_ep_class_exit();
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_driver.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_driver.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,30 @@
+/*****************************************************************************/
+/* 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 UF_DRIVER_H
+#define UF_DRIVER_H
+
+#include "uf_device.h"
+
+int uf_driver_class_init(void);
+void uf_driver_class_exit(void);
+int uf_driver_probe(struct uf_device *device);
+void uf_driver_remove(struct uf_device *device);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_ep.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_ep.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,452 @@
+/*****************************************************************************/
+/* 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/frontend/main.c                                    */
+/* pristine-linux-2.6.11/drivers/usb/host/uhci-hcd.c                         */
+/* pristine-linux-2.6.11/drivers/usb/core/hcd-pci.c                          */
+/*                                                                           */
+/* original copyright notices follow...                                      */
+/*****************************************************************************/
+
+/*
+ * Xen Virtual USB Frontend Driver
+ *
+ * This file contains the first version of the Xen virtual USB hub
+ * that I've managed not to delete by mistake (3rd time lucky!).
+ *
+ * Based on Linux's uhci.c, original copyright notices are displayed
+ * below.  Portions also (c) 2004 Intel Research Cambridge
+ * and (c) 2004, 2005 Mark Williamson
+ *
+ * Contact <mark.williamson@xxxxxxxxxxxx> or
+ * <xen-devel@xxxxxxxxxxxxxxxxxxxxx> regarding this code.
+ *
+ * Still to be (maybe) implemented:
+ * - migration / backend restart support?
+ * - support for building / using as a module
+ */
+
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Johannes Erdfelt <johannes@xxxxxxxxxxx>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx
+ * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx
+ * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ *  - the low-level protocol (fairly simple but lots of small details)
+ *  - working around the horridness of the rest
+ */
+
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx
+ * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx
+ * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ * (C) Copyright 2004 Alan Stern, stern@xxxxxxxxxxxxxxxxxxx
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ *  - the low-level protocol (fairly simple but lots of small details)
+ *  - working around the horridness of the rest
+ */
+
+/*
+ * (C) Copyright David Brownell 2000-2002
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/device.h>
+#include "uf_ep.h"
+#include "uf_rsrc.h"
+#include "uf_sll.h"
+#include "uf_trace.h"
+
+/* When there is an error, we are supposed to guarantee that the URB queue   */
+/* stalls until the completion handlers of the failing URB and all URBs      */
+/* unlinked as a result have returned. This guarantee is satisfied as        */
+/* follows: when an URB fails in the BE, the BE endpoint unlinks all         */
+/* in-progress URBs and goes into a stalled state such that newly arriving   */
+/* URBs will get returned as unlinked.                                       */
+/* When the FE gets an URB returning with an unlinked or failure error, the  */
+/* FE endpoint stalls and waits for all outstanding requests to the BE to    */
+/* return with error or unlinked status.  Once the FE endpoint is quiesced   */
+/* and all URB completions are done, the FE endpoint restarts any stalled    */
+/* URBs, the first of which gets the CLEAR_STALL flag set to unstall the BE  */
+/* endpoint.                                                                 */
+/* Explicit unlinks by the FE are dealt with by noting in the FE that the    */
+/* URB is to be returned as unlinked rather than retried and then sending a  */
+/* request to the BE to stall the queue and go through the same quiesce      */
+/* process.                                                                  */
+
+typedef enum {
+	uf_ep_stimulus_ue, /* URB enqueue/rsrc became free */
+	uf_ep_stimulus_ud, /* URB dequeue/error            */
+	uf_ep_stimulus_bz, /* Busy count drops to zero     */
+	uf_ep_stimulus_ed, /* endpoint disable             */
+} uf_ep_stimulus;
+
+static void uf_ep_handle_stimulus(struct uf_ep *ep, uf_ep_stimulus stimulus);
+
+void uf_ep_urb_enqueue(struct uf_ep *ep, struct urb *urb)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&ep->lock, flags);
+	uf_slk_init((struct uf_slk *)&urb->hcpriv);
+	uf_sll_add_last(&ep->urb_sll, (struct uf_slk *)&urb->hcpriv);
+	uf_ep_handle_stimulus(ep, uf_ep_stimulus_ue);
+	spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+int uf_ep_urb_dequeue(struct uf_ep *ep, struct urb *urb)
+{
+	/* return -EINPROGRESS iff URB will be unlinked and complete with    */
+	/* -ECONNRESET.                                                      */
+	int done, result = -EINPROGRESS;
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&ep->lock, flags);
+	ep->busy_count++;
+	uf_ep_handle_stimulus(ep, uf_ep_stimulus_ud);
+	done = uf_sll_remove_slk(&ep->urb_sll, (struct uf_slk *)&urb->hcpriv);
+	spin_unlock_irqrestore(&ep->lock, flags);
+	if (done) {
+		urb->hcpriv = 0;
+		urb->status = -ECONNRESET;
+		urb->actual_length = 0;
+		local_irq_save(flags);
+		usb_hcd_giveback_urb(uf_device_get_drvdata(ep->device),urb,0);
+		local_irq_restore(flags);
+	} else {
+		result = uf_rsrc_urb_dequeue(urb);
+	}
+	spin_lock_irqsave(&ep->lock, flags);
+	if (done || (result != -EINPROGRESS))
+		ep->busy_count--;
+	if (ep->busy_count == 0)
+		uf_ep_handle_stimulus(ep, uf_ep_stimulus_bz);
+	spin_unlock_irqrestore(&ep->lock, flags);
+	return result;
+}
+
+void uf_ep_disable(struct uf_ep *ep)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&ep->lock, flags);
+	uf_ep_handle_stimulus(ep, uf_ep_stimulus_ed);
+	spin_unlock_irqrestore(&ep->lock, flags);
+	uf_work_until(ep->state == uf_ep_state_i);
+}
+
+void uf_ep_rsrc_stalled(struct uf_ep *ep)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&ep->lock, flags);
+	if (--ep->busy_count == 0)
+		uf_ep_handle_stimulus(ep, uf_ep_stimulus_bz);
+	spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static void uf_ep_rsrc_completed(struct uf_callback * callback)
+{
+	struct uf_rsrc *rsrc = uf_rsrc_callback_to(callback);
+	struct uf_ep *ep = uf_rsrc_query_ep(rsrc);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&ep->lock, flags);
+	list_del_init(uf_rsrc_to_link(rsrc));
+	list_add(uf_rsrc_to_link(rsrc), &ep->free_rsrc_list);
+	uf_ep_handle_stimulus(ep, uf_ep_stimulus_ue);
+	if (uf_callback_query_error(callback) != USBIF_ERROR_SUCCESS)
+		uf_ep_handle_stimulus(ep, uf_ep_stimulus_ud);
+	if (uf_callback_query_error(callback) == USBIF_ERROR_UNLINKED)
+		ep->busy_count--;
+	if (--ep->busy_count == 0)
+		uf_ep_handle_stimulus(ep, uf_ep_stimulus_bz);
+	spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static void uf_ep_invalid_stimulus(struct uf_ep *ep, uf_ep_stimulus stimulus)
+{
+	trace();
+	printk(KERN_ERR "uf: ep %p in state %d"
+	     "received invalid stimulus %d", ep, ep->state, stimulus);
+}
+
+static void uf_ep_clear_stall(struct uf_ep *ep)
+{
+	trace();
+	ep->clear_stall = 1;
+}
+
+static void uf_ep_kick_urbs(struct uf_ep *ep)
+{
+	trace();
+	while (!uf_sll_is_empty(&ep->urb_sll) &&
+				!list_empty(&ep->free_rsrc_list)) {
+		struct urb *urb = container_of(
+					(void **)uf_sll_remove_first(
+							&ep->urb_sll),
+					struct urb, hcpriv);
+		struct uf_rsrc *rsrc = list_entry(
+					ep->free_rsrc_list.next,
+					struct uf_rsrc,
+					link);
+		list_del_init(uf_rsrc_to_link(rsrc));
+		list_add_tail(uf_rsrc_to_link(rsrc), &ep->used_rsrc_list);
+		ep->busy_count++;
+		uf_rsrc_start_urb(rsrc, urb, ep->clear_stall);
+		ep->clear_stall = 0;
+	}
+	if (ep->busy_count == 0)
+		uf_ep_handle_stimulus(ep, uf_ep_stimulus_bz);
+}
+
+static void uf_ep_restart_urbs(struct uf_ep *ep)
+{
+	struct uf_rsrc *rsrc;
+	trace();
+	list_for_each_entry(rsrc, &ep->used_rsrc_list, link) {
+		ep->busy_count++;
+		uf_rsrc_restart_urb(rsrc, ep->clear_stall);
+		ep->clear_stall = 0;
+	}
+}
+
+static void uf_ep_submit_stall(struct uf_ep *ep)
+{
+	struct usbif_stall_tra_parameters *parameters =
+					&ep->stall_tra.parameters.stall;
+	trace();
+	ep->busy_count++;
+	memset(parameters, 0, sizeof(*parameters));
+	parameters->header.tra_type = USBIF_TRA_TYPE_STALL;
+	uf_device_submit_tra(ep->device, &ep->stall_tra);
+}
+
+static void uf_ep_submit_stall_1(struct uf_callback *callback)
+{
+	struct uf_ep *ep = container_of(uf_gw_tra_callback_to(callback),
+						struct uf_ep, stall_tra);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&ep->lock, flags);
+	if (--ep->busy_count == 0)
+		uf_ep_handle_stimulus(ep, uf_ep_stimulus_bz);
+	spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static void uf_ep_complete_disable(struct uf_ep *ep)
+{
+	uf_work_wake_up();
+}
+
+static void uf_ep_handle_stimulus(struct uf_ep *ep, uf_ep_stimulus stimulus)
+{
+	trace_info("ep %p in state %d received stimulus %d", ep, ep->state,
+								stimulus);
+	switch (ep->state) {
+	/* Idle. */
+	case uf_ep_state_i:
+		switch (stimulus) {
+		case uf_ep_stimulus_ue:
+			ep->state = uf_ep_state_i_ue;
+			uf_ep_kick_urbs(ep);
+			break;
+		case uf_ep_stimulus_ed:
+			uf_ep_complete_disable(ep);
+			break;
+		default:
+			uf_ep_invalid_stimulus(ep, stimulus);
+			break;
+		}
+		break;
+	/* Busy */
+	case uf_ep_state_i_ue:
+		switch (stimulus) {
+		case uf_ep_stimulus_ue:
+			uf_ep_kick_urbs(ep);
+			break;
+		case uf_ep_stimulus_ud:
+			ep->state = uf_ep_state_i_ue_ud;
+			uf_ep_submit_stall(ep);
+			break;
+		case uf_ep_stimulus_bz:
+			ep->state = uf_ep_state_i;
+			uf_ep_complete_disable(ep);
+			break;
+		case uf_ep_stimulus_ed:
+			/* We always call complete_disable when we go idle   */
+			/* so there's no need to remember that this is       */
+			/* outstanding.                                      */
+			break;
+		default:
+			uf_ep_invalid_stimulus(ep, stimulus);
+			break;
+		}
+		break;
+	/* Quiescing for stall. */
+	case uf_ep_state_i_ue_ud:
+		switch (stimulus) {
+		case uf_ep_stimulus_ue:
+		case uf_ep_stimulus_ud:
+			break;
+		case uf_ep_stimulus_bz:
+			ep->state = uf_ep_state_i_ue;
+			uf_ep_clear_stall(ep);
+			uf_ep_restart_urbs(ep);
+			uf_ep_kick_urbs(ep);
+			break;
+		case uf_ep_stimulus_ed:
+			break;
+		default:
+			uf_ep_invalid_stimulus(ep, stimulus);
+			break;
+		}
+		break;
+	default:
+		uf_ep_invalid_stimulus(ep, stimulus);
+		break;
+	}
+}
+
+static int
+uf_ep_init_or_exit(struct uf_ep *ep, struct uf_device *device, int exit)
+{
+	int return_value = 0;
+	int i = UF_EP_QUOTA;
+	trace();
+	if (exit)
+		goto exit_path;
+	ep->device = device;
+	spin_lock_init(&ep->lock);
+	ep->state = uf_ep_state_i;
+	ep->busy_count = 0;
+	ep->clear_stall = 0;
+	uf_sll_init(&ep->urb_sll);
+	INIT_LIST_HEAD(&ep->free_rsrc_list);
+	INIT_LIST_HEAD(&ep->used_rsrc_list);
+	for (i = 0; i < UF_EP_QUOTA; i++) {
+		ep->rsrcs[i]=kzalloc(sizeof(struct uf_rsrc),GFP_KERNEL);
+		if (ep->rsrcs[i]==NULL) {
+			return_value = -ENOMEM;
+			goto exit_no_rsrc;
+		}
+	}
+	for (i = 0; i < UF_EP_QUOTA; i++) {
+		struct uf_rsrc *rsrc = ep->rsrcs[i];
+		return_value = uf_rsrc_init(rsrc, ep, uf_ep_rsrc_completed);
+		if (return_value != 0) {
+			trace_info("uf_rsrc_init failed");
+			goto exit_no_rsrc_init;
+		}
+		list_add(uf_rsrc_to_link(rsrc), &ep->free_rsrc_list);
+	}
+	uf_gw_tra_init(&ep->stall_tra, uf_ep_submit_stall_1);
+	return 0;
+ exit_path:
+ exit_no_rsrc_init:
+	while (!list_empty(&ep->free_rsrc_list)) {
+		struct uf_rsrc *rsrc = list_entry(
+				ep->free_rsrc_list.next,
+				struct uf_rsrc,
+				callback.work.link);
+		list_del_init(uf_rsrc_to_link(rsrc));
+		uf_rsrc_exit(rsrc);
+	}
+ exit_no_rsrc:
+	for(i--;i>=0;i--)
+		kfree(ep->rsrcs[i]);
+	return return_value;
+}
+
+int uf_ep_init(struct uf_ep *ep, struct uf_device *device)
+{
+	trace();
+	return uf_ep_init_or_exit(ep, device, 0);
+}
+
+void uf_ep_exit(struct uf_ep *ep)
+{
+	trace();
+	(void)uf_ep_init_or_exit(ep, NULL, 1);
+}
+
+int uf_ep_class_init(void)
+{
+	trace();
+	return uf_rsrc_class_init();
+}
+
+void uf_ep_class_exit(void)
+{
+	trace();
+	uf_rsrc_class_exit();
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_ep.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_ep.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,63 @@
+/*****************************************************************************/
+/* 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 UF_EP_H
+#define UF_EP_H
+
+#include "uf_device.h"
+#include "uf_rsrc.h"
+#include "uf_sll.h"
+
+#define UF_EP_QUOTA 4
+
+typedef enum {
+	uf_ep_state_i,
+	uf_ep_state_i_ue,
+	uf_ep_state_i_ue_ud
+} uf_ep_state;
+
+struct uf_ep {
+	struct uf_device *device;
+	spinlock_t        lock;
+	uf_ep_state       state;
+	int               busy_count;
+	int               clear_stall;
+	int               stalled;
+	struct uf_sll     urb_sll;
+	struct list_head  free_rsrc_list;
+	struct list_head  used_rsrc_list;
+	struct uf_rsrc   *rsrcs[UF_EP_QUOTA];
+	struct uf_gw_tra  stall_tra;
+};
+
+static inline struct uf_device *uf_ep_query_device(struct uf_ep *ep)
+{
+	return ep->device;
+}
+
+void uf_ep_urb_enqueue(struct uf_ep *ep, struct urb *urb);
+int uf_ep_urb_dequeue(struct uf_ep *ep, struct urb *urb);
+void uf_ep_disable(struct uf_ep *ep);
+void uf_ep_rsrc_stalled(struct uf_ep *ep);
+int uf_ep_init(struct uf_ep *ep, struct uf_device *device);
+void uf_ep_exit(struct uf_ep *ep);
+int uf_ep_class_init(void);
+void uf_ep_class_exit(void);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_gw.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_gw.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,503 @@
+/*****************************************************************************/
+/* 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 "uf_gw.h"
+#include "uf_gw_rsrc.h"
+#include "uf_trace.h"
+
+typedef enum {
+	uf_gw_stimulus_tq, /* Transaction queued.           */
+	uf_gw_stimulus_cc, /* Channel connect.              */
+	uf_gw_stimulus_cd, /* Channel disconnect.           */
+	uf_gw_stimulus_kt, /* Kick tras completed.          */
+	uf_gw_stimulus_ic, /* Initiator rsrc completed. */
+	uf_gw_stimulus_ii, /* Initiator rsrcs idle.     */
+	uf_gw_stimulus_lc, /* Client connect completed.     */
+	uf_gw_stimulus_lg, /* Client disconnect called.     */
+	uf_gw_stimulus_ld, /* Client disconnect completed.  */
+} uf_gw_stimulus;
+
+static void
+uf_gw_handle_stimulus(struct uf_gw *gw,
+uf_gw_stimulus stimulus);
+
+void
+uf_gw_submit_tra(struct uf_gw *gw, struct uf_gw_tra *tra)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	unsigned long flags;
+	spin_lock_irqsave(&gw->lock, flags);
+	list_add_tail(uf_gw_tra_to_link(tra), &gw->tra_list);
+	uf_gw_handle_stimulus(gw, uf_gw_stimulus_tq);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void uf_gw_channel_connect(void *context)
+{
+	struct uf_gw *gw = context;
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&gw->lock, flags);
+	uf_gw_handle_stimulus(gw, uf_gw_stimulus_cc);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void uf_gw_handle_channel_message(void *context,
+struct uf_channel_ibmsg *message)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	struct uf_gw *gw = context;
+	struct uf_gw_rsrc *rsrc;
+	usbif_error error = USBIF_ERROR_INVALID_PROTOCOL;
+	if (message->response.gw_status.id >= gw->initiator_quota)
+		goto complete_channel_message;
+	rsrc = &gw->initiator_rsrcs[message->response.gw_status.id];
+	if (uf_gw_rsrc_handle_response(rsrc, &message->response)
+									!= 0)
+		goto complete_channel_message;
+	error = USBIF_ERROR_SUCCESS;
+ complete_channel_message:
+	uf_callback_complete(uf_channel_ibmsg_to_callback(message),
+									error);
+}
+
+static void uf_gw_channel_disconnect(void *context,
+struct uf_callback *callback)
+{
+	struct uf_gw *gw = context;
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&gw->lock, flags);
+	gw->channel_disconnect_callback = callback;
+	uf_gw_handle_stimulus(gw, uf_gw_stimulus_cd);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+void uf_gw_submit_channel_message(struct uf_gw *gw,
+struct uf_channel_obmsg *message)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	uf_channel_submit_message(gw->channel, message);
+}
+
+static void uf_gw_invalid_stimulus(struct uf_gw *gw,
+uf_gw_stimulus stimulus)
+{
+	trace();
+	printk(KERN_ERR "uf: gw %p in state %d"
+		     "received invalid stimulus %d", gw, gw->state, stimulus);
+}
+
+static void uf_gw_kick_tras(struct uf_gw *gw)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	if (!gw->kick_tras_out) {
+		gw->kick_tras_out = 1;
+		(void)uf_work_schedule(&gw->kick_tras_1_work);
+	}
+}
+
+static void uf_gw_kick_tras_1(void *data)
+{
+	struct uf_gw *gw = data;
+	unsigned long flags;
+	spin_lock_irqsave(&gw->lock, flags);
+	while ((!list_empty(&gw->tra_list)) &&
+			(!list_empty(&gw->initiator_rsrc_list))) {
+		struct uf_gw_tra *tra;
+		struct uf_gw_rsrc *rsrc;
+		tra = list_entry(gw->tra_list.next,
+				struct uf_gw_tra,
+				callback.work.link);
+		rsrc = list_entry(gw->initiator_rsrc_list.next,
+				struct uf_gw_rsrc,
+				callback.work.link);
+		list_del_init(uf_gw_tra_to_link(tra));
+		list_del_init(uf_gw_rsrc_to_link(rsrc));
+		gw->initiator_rsrcs_out++;
+		spin_unlock_irqrestore(&gw->lock, flags);
+		uf_gw_rsrc_start(rsrc, tra);
+		spin_lock_irqsave(&gw->lock, flags);
+	}
+	gw->kick_tras_out = 0;
+	uf_gw_handle_stimulus(gw, uf_gw_stimulus_kt);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void uf_gw_kick_tras_2(struct uf_callback *callback)
+{
+	struct uf_gw_rsrc *rsrc =
+		uf_gw_rsrc_callback_to(callback);
+	struct uf_gw *gw = uf_gw_rsrc_query_gw(rsrc);
+	unsigned long flags;
+	spin_lock_irqsave(&gw->lock, flags);
+	list_add_tail(uf_gw_rsrc_to_link(rsrc),
+					&gw->initiator_rsrc_list);
+	if (--gw->initiator_rsrcs_out != 0) {
+		uf_gw_handle_stimulus(gw, uf_gw_stimulus_ic);
+	} else {
+		uf_gw_handle_stimulus(gw, uf_gw_stimulus_ii);
+	}
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void uf_gw_fail_out_tras(struct uf_gw *gw)
+{
+	trace();
+	while (!list_empty(&gw->tra_list)) {
+		struct uf_gw_tra *tra = list_entry(gw->tra_list.next,
+				struct uf_gw_tra,	callback.work.link);
+		list_del_init(uf_gw_tra_to_link(tra));
+		uf_callback_complete(uf_gw_tra_to_callback(tra),
+						USBIF_ERROR_DISCONNECT);
+	}
+}
+
+static void uf_gw_connect_client(struct uf_gw *gw)
+{
+	trace();
+	(void)uf_work_schedule(&gw->connect_client_1_work);
+}
+
+static void uf_gw_connect_client_1(void *data)
+{
+	struct uf_gw *gw = data;
+	unsigned long flags;
+	trace();
+	gw->connect(gw);
+	spin_lock_irqsave(&gw->lock, flags);
+	uf_gw_handle_stimulus(gw, uf_gw_stimulus_lc);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void uf_gw_disconnect_client(struct uf_gw *gw)
+{
+	trace();
+	(void)uf_work_schedule(&gw->disconnect_client_1_work);
+}
+
+static void uf_gw_disconnect_client_1(void *data)
+{
+	struct uf_gw *gw = data;
+	unsigned long flags;
+	trace();
+	gw->disconnect(gw, &gw->disconnect_client_2_callback);
+	spin_lock_irqsave(&gw->lock, flags);
+	uf_gw_handle_stimulus(gw, uf_gw_stimulus_lg);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void uf_gw_disconnect_client_2(struct uf_callback *callback)
+{
+	struct uf_gw *gw = container_of(callback, struct uf_gw,
+						disconnect_client_2_callback);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&gw->lock, flags);
+	uf_gw_handle_stimulus(gw, uf_gw_stimulus_ld);
+	spin_unlock_irqrestore(&gw->lock, flags);
+}
+
+static void uf_gw_abort_initiator_rsrcs(struct uf_gw *gw)
+{
+	u32 i;
+	trace();
+	for (i = 0; i < gw->initiator_quota; i++)
+		uf_gw_rsrc_abort(&gw->initiator_rsrcs[i],
+						USBIF_ERROR_DISCONNECT);
+}
+
+static void uf_gw_test_initiator_rsrcs(struct uf_gw *gw)
+{
+	trace();
+	if (gw->initiator_rsrcs_out == 0)
+		uf_gw_handle_stimulus(gw, uf_gw_stimulus_ii);
+}
+
+static void uf_gw_complete_channel_disconnect(struct uf_gw *gw)
+{
+	trace();
+	uf_callback_success(gw->channel_disconnect_callback);
+}
+
+static int uf_gw_init_or_exit(struct uf_gw *gw, int exit)
+{
+	int return_value = 0;
+	u32 i;
+	trace();
+	if (exit)
+		goto exit_path;
+	INIT_LIST_HEAD(&gw->initiator_rsrc_list);
+	if (gw->initiator_quota != 0) {
+		/*FIXME: kmalloc > page size*/
+		gw->initiator_rsrcs = kmalloc(sizeof(
+				struct uf_gw_rsrc) *
+				gw->initiator_quota, GFP_KERNEL);
+		if (gw->initiator_rsrcs == NULL) {
+			return_value = -ENOMEM;
+			goto exit_no_initiator_rsrcs;
+		}
+		for (i = 0; i < gw->initiator_quota; i++) {
+			struct uf_gw_rsrc *rsrc =
+					&gw->initiator_rsrcs[i];
+			uf_gw_rsrc_init(rsrc,
+					gw, uf_gw_kick_tras_2, i);
+			list_add_tail(uf_gw_rsrc_to_link(rsrc),
+						&gw->initiator_rsrc_list);
+		}
+	}
+	spin_lock_init(&gw->lock);
+	gw->state = uf_gw_state_i;
+	INIT_LIST_HEAD(&gw->tra_list);
+	uf_work_init(&gw->kick_tras_1_work, uf_gw_kick_tras_1, gw);
+	uf_work_init(&gw->connect_client_1_work,
+					uf_gw_connect_client_1, gw);
+	uf_work_init(&gw->disconnect_client_1_work,
+					uf_gw_disconnect_client_1, gw);
+	uf_callback_init(&gw->disconnect_client_2_callback,
+					uf_gw_disconnect_client_2);
+	gw->kick_tras_out = 0;
+	gw->initiator_rsrcs_out = 0;
+	return 0;
+ exit_path:
+	if (gw->initiator_quota != 0)
+		kfree(gw->initiator_rsrcs);
+ exit_no_initiator_rsrcs:
+	return return_value;
+}
+
+int
+uf_gw_init(struct uf_gw *gw,
+struct uf_channel *channel, uf_gw_connect_function *connect,
+uf_gw_disconnect_function *disconnect, u32 initiator_quota)
+{
+	trace();
+	gw->channel = channel;
+	gw->connect = connect;
+	gw->disconnect = disconnect;
+	gw->initiator_quota = initiator_quota;
+	uf_channel_install_client(channel, gw,
+				uf_gw_channel_connect,
+				uf_gw_handle_channel_message,
+				uf_gw_channel_disconnect);
+	return uf_gw_init_or_exit(gw, 0);
+}
+
+void uf_gw_exit(struct uf_gw *gw)
+{
+	trace();
+	(void)uf_gw_init_or_exit(gw, 1);
+}
+
+static void
+uf_gw_handle_stimulus(struct uf_gw *gw,
+uf_gw_stimulus stimulus)
+{
+	switch (gw->state) {
+	case uf_gw_state_i:
+		/* Channel disconnected.     */
+		/* Client disconnected.      */
+		/* No tras queued.           */
+		/* Initiator rsrcs idle. */
+		/* Not kicking tras.         */
+		switch (stimulus) {
+		case uf_gw_stimulus_cc:
+			gw->state = uf_gw_state_i_cc;
+			uf_gw_connect_client(gw);
+			break;
+		default:
+			uf_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case uf_gw_state_i_cc:
+		/* Channel connected.        */
+		/* Client connecting.        */
+		/* Maybe tras queued.        */
+		/* Initiator rsrcs idle. */
+		/* Not kicking tras.         */
+		switch (stimulus) {
+		case uf_gw_stimulus_tq:
+			break;
+		case uf_gw_stimulus_cd:
+			gw->state = uf_gw_state_i_cc_cd;
+			break;
+		case uf_gw_stimulus_lc:
+			gw->state = uf_gw_state_i_cc_lc;
+			uf_gw_kick_tras(gw);
+			break;
+		default:
+			uf_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case uf_gw_state_i_cc_cd:
+		/* Channel disconnecting.    */
+		/* Client connecting.        */
+		/* Maybe tras queued.        */
+		/* Initiator rsrcs idle. */
+		/* Not kicking tras.         */
+		switch (stimulus) {
+		case uf_gw_stimulus_tq:
+			break;
+		case uf_gw_stimulus_lc:
+			gw->state = uf_gw_state_i_cc_cd_lc;
+			uf_gw_disconnect_client(gw);
+			break;
+		default:
+			uf_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case uf_gw_state_i_cc_lc:
+		/* Channel connected.              */
+		/* Client connected.               */
+		/* Maybe tras queued.              */
+		/* Maybe initiator rsrcs busy. */
+		/* Maybe kicking tras.             */
+		switch (stimulus) {
+		case uf_gw_stimulus_tq:
+			uf_gw_kick_tras(gw);
+			break;
+		case uf_gw_stimulus_cd:
+			gw->state = uf_gw_state_i_cc_lc_cd;
+			uf_gw_kick_tras(gw);
+			break;
+		case uf_gw_stimulus_kt:
+			break;
+		case uf_gw_stimulus_ic:
+		case uf_gw_stimulus_ii:
+			uf_gw_kick_tras(gw);
+			break;
+		default:
+			uf_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case uf_gw_state_i_cc_lc_cd:
+		/* Channel disconnecting.          */
+		/* Client connected.               */
+		/* Maybe tras queued.              */
+		/* Maybe initiator rsrcs busy. */
+		/* Kicking tras.                   */
+		switch (stimulus) {
+		case uf_gw_stimulus_tq:
+			break;
+		case uf_gw_stimulus_kt:
+			gw->state = uf_gw_state_i_cc_cd_lc;
+			uf_gw_disconnect_client(gw);
+			break;
+		case uf_gw_stimulus_ic:
+		case uf_gw_stimulus_ii:
+			break;
+		default:
+			uf_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case uf_gw_state_i_cc_cd_lc:
+		/* Channel disconnecting.          */
+		/* Calling client disconnect.      */
+		/* Maybe tras queued.              */
+		/* Maybe initiator rsrcs busy. */
+		/* Not kicking tras.               */
+		switch (stimulus) {
+		case uf_gw_stimulus_tq:
+			break;
+		case uf_gw_stimulus_ic:
+		case uf_gw_stimulus_ii:
+			break;
+		case uf_gw_stimulus_lg:
+			gw->state = uf_gw_state_i_cc_cd_lc_lg;
+			uf_gw_fail_out_tras(gw);
+			uf_gw_abort_initiator_rsrcs(gw);
+			break;
+		case uf_gw_stimulus_ld:
+			gw->state = uf_gw_state_i_cc_cd_lc_ld;
+			break;
+		default:
+			uf_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case uf_gw_state_i_cc_cd_lc_lg:
+		/* Channel disconnecting.          */
+		/* Client disconnecting.           */
+		/* No tras queued.                 */
+		/* Maybe initiator rsrcs busy. */
+		/* Not kicking tras.               */
+		switch (stimulus) {
+		case uf_gw_stimulus_tq:
+			break;
+		case uf_gw_stimulus_ic:
+		case uf_gw_stimulus_ii:
+			break;
+		case uf_gw_stimulus_ld:
+			gw->state =
+			    uf_gw_state_i_cc_cd_lc_lg_ld;
+			uf_gw_test_initiator_rsrcs(gw);
+			break;
+		default:
+			uf_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case uf_gw_state_i_cc_cd_lc_ld:
+		/* Channel disconnecting.                          */
+		/* Client disconnected but call still in progress. */
+		/* No tras queued.                                 */
+		/* Maybe initiator rsrcs busy.                 */
+		/* Not kicking tras.                               */
+		switch (stimulus) {
+		case uf_gw_stimulus_ic:
+		case uf_gw_stimulus_ii:
+			break;
+		case uf_gw_stimulus_lg:
+			gw->state =
+			    uf_gw_state_i_cc_cd_lc_lg_ld;
+			uf_gw_test_initiator_rsrcs(gw);
+			break;
+		default:
+			uf_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	case uf_gw_state_i_cc_cd_lc_lg_ld:
+		/* Channel disconnecting.                                */
+		/* Client disconnected.                                  */
+		/* No tras queued.                                       */
+		/* Test initiator rsrcs or initiator rsrcs busy. */
+		/* Not kicking tras.                                     */
+		switch (stimulus) {
+		case uf_gw_stimulus_ic:
+			break;
+		case uf_gw_stimulus_ii:
+			gw->state = uf_gw_state_i;
+			uf_gw_complete_channel_disconnect(gw);
+			break;
+		default:
+			uf_gw_invalid_stimulus(gw, stimulus);
+			break;
+		}
+		break;
+	default:
+		uf_gw_invalid_stimulus(gw, stimulus);
+		break;
+	}
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_gw.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_gw.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,123 @@
+/*****************************************************************************/
+/* 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 UF_GW_H
+#define UF_GW_H
+
+#include "uf_callback.h"
+#include "uf_channel.h"
+
+struct uf_gw_rsrc;
+
+struct uf_gw_tra {
+	struct uf_callback callback;
+	union usbif_parameters   parameters;
+	union usbif_status       status;
+};
+
+static inline struct uf_callback *
+uf_gw_tra_to_callback(struct uf_gw_tra *tra)
+{
+	return &tra->callback;
+}
+
+static inline struct uf_gw_tra *
+uf_gw_tra_callback_to(struct uf_callback *callback)
+{
+	return container_of(callback, struct uf_gw_tra, callback);
+}
+
+static inline struct list_head *
+uf_gw_tra_to_link(struct uf_gw_tra *tra)
+{
+	return uf_callback_to_link(uf_gw_tra_to_callback(tra));
+}
+
+static inline struct uf_gw_tra *
+uf_gw_tra_link_to(struct list_head *link)
+{
+	return uf_gw_tra_callback_to(uf_callback_link_to(link));
+}
+
+static inline void uf_gw_tra_init(struct uf_gw_tra *tra,
+uf_callback_function *callback)
+{
+	uf_callback_init(uf_gw_tra_to_callback(tra), callback);
+}
+
+static inline void
+uf_gw_tra_complete(struct uf_gw_tra *tra, usbif_error error)
+{
+	uf_callback_complete(uf_gw_tra_to_callback(tra), error);
+}
+
+static inline
+usbif_error uf_gw_tra_query_error(struct uf_gw_tra *tra)
+{
+	return uf_callback_query_error(uf_gw_tra_to_callback(tra));
+}
+
+typedef enum {
+	uf_gw_state_i,
+	uf_gw_state_i_cc,
+	uf_gw_state_i_cc_cd,
+	uf_gw_state_i_cc_lc,
+	uf_gw_state_i_cc_lc_cd,
+	uf_gw_state_i_cc_cd_lc,
+	uf_gw_state_i_cc_cd_lc_lg,
+	uf_gw_state_i_cc_cd_lc_ld,
+	uf_gw_state_i_cc_cd_lc_lg_ld
+} uf_gw_state;
+
+struct uf_gw;
+
+typedef void uf_gw_connect_function(struct uf_gw *gw);
+
+typedef void uf_gw_disconnect_function(struct uf_gw *gw,
+struct uf_callback *callback);
+
+struct uf_gw {
+	struct uf_channel         *channel;
+	uf_gw_connect_function    *connect;
+	uf_gw_disconnect_function *disconnect;
+	u32                              initiator_quota;
+	struct list_head                 initiator_rsrc_list;
+	struct uf_gw_rsrc     *initiator_rsrcs;
+	spinlock_t                       lock;
+	uf_gw_state                state;
+	struct list_head                 tra_list;
+	struct uf_work             kick_tras_1_work;
+	struct uf_work             connect_client_1_work;
+	struct uf_work             disconnect_client_1_work;
+	struct uf_callback         disconnect_client_2_callback;
+	int                              kick_tras_out;
+	u32                              initiator_rsrcs_out;
+	struct uf_callback        *channel_disconnect_callback;
+};
+
+int uf_gw_init(struct uf_gw *gw,
+struct uf_channel *channel, uf_gw_connect_function *connect,
+uf_gw_disconnect_function *disconnect, u32 initiator_quota);
+
+extern void
+uf_gw_submit_tra(struct uf_gw *gw, struct uf_gw_tra *tra);
+
+extern void uf_gw_exit(struct uf_gw *gw);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_gw_rsrc.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_gw_rsrc.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,211 @@
+/*****************************************************************************/
+/* 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 "uf_gw_rsrc.h"
+#include "uf_trace.h"
+
+void uf_gw_submit_channel_message(struct uf_gw *gw,
+struct uf_channel_obmsg *message);
+
+static void
+uf_gw_rsrc_handle_stimulus(struct uf_gw_rsrc *rsrc,
+uf_gw_rsrc_stimulus stimulus);
+
+void uf_gw_rsrc_start(struct uf_gw_rsrc *rsrc,
+struct uf_gw_tra *tra)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	unsigned long flags;
+	rsrc->tra = tra;
+	rsrc->error = USBIF_ERROR_SUCCESS;
+	rsrc->channel_message.request.usbif_parameters =
+						tra->parameters;
+	spin_lock_irqsave(&rsrc->lock, flags);
+	uf_gw_rsrc_handle_stimulus(rsrc,
+			uf_gw_rsrc_stimulus_st);
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+	uf_gw_submit_channel_message(rsrc->gw,
+						&rsrc->channel_message);
+}
+
+void uf_gw_rsrc_abort(struct uf_gw_rsrc *rsrc,
+usbif_error error)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&rsrc->lock, flags);
+	rsrc->aborted_error = error;
+	uf_gw_rsrc_handle_stimulus(rsrc,
+			uf_gw_rsrc_stimulus_ab);
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+}
+
+static void uf_gw_rsrc_channel_message_callback(
+struct uf_callback *callback)
+{
+	struct uf_gw_rsrc *rsrc = container_of(callback,
+			struct uf_gw_rsrc, channel_message.callback);
+	unsigned long flags;
+	spin_lock_irqsave(&rsrc->lock, flags);
+	uf_gw_rsrc_handle_stimulus(rsrc,
+					uf_gw_rsrc_stimulus_sc);
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+}
+
+int uf_gw_rsrc_handle_response(struct uf_gw_rsrc *rsrc,
+struct usbif_response *response)
+{
+	int return_value = -1;
+	unsigned long flags;
+	spin_lock_irqsave(&rsrc->lock, flags);
+	if ((rsrc->state == uf_gw_rsrc_state_i_st)
+		||(rsrc->state == uf_gw_rsrc_state_i_st_sc)) {
+		rsrc->tra->status = response->usbif_status;
+		rsrc->error = response->gw_status.error;
+		uf_gw_rsrc_handle_stimulus(rsrc,
+					uf_gw_rsrc_stimulus_ts);
+		return_value = 0;
+	}
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+	return return_value;
+}
+
+
+static void
+uf_gw_rsrc_invalid_stimulus(struct uf_gw_rsrc *rsrc,
+uf_gw_rsrc_stimulus stimulus)
+{
+	trace();
+	printk(KERN_ERR "uf: gw initiator rsrc %p in state %d"
+		"received invalid stimulus %d", rsrc, rsrc->state,
+								stimulus);
+}
+
+static void
+uf_gw_rsrc_set_aborted(struct uf_gw_rsrc *rsrc)
+{
+	trace();
+	rsrc->error = rsrc->aborted_error;
+}
+
+static void
+uf_gw_rsrc_complete(struct uf_gw_rsrc *rsrc)
+{
+	uf_callback_complete(&rsrc->tra->callback, rsrc->error);
+	uf_callback_success(&rsrc->callback);
+}
+
+void uf_gw_rsrc_init(struct uf_gw_rsrc *rsrc,
+struct uf_gw *gw, uf_callback_function callback, int id)
+{
+	trace();
+	uf_callback_init(&rsrc->callback, callback);
+	rsrc->gw = gw;
+	rsrc->channel_message.request.gw_parameters.id = id;
+	spin_lock_init(&rsrc->lock);
+	rsrc->state = uf_gw_rsrc_state_i;
+	uf_callback_init(uf_channel_obmsg_to_callback(
+				&rsrc->channel_message),
+				uf_gw_rsrc_channel_message_callback);
+}
+
+static void
+uf_gw_rsrc_handle_stimulus(struct uf_gw_rsrc *rsrc,
+uf_gw_rsrc_stimulus stimulus)
+{
+	switch (rsrc->state) {
+	case uf_gw_rsrc_state_i:
+		switch (stimulus) {
+		case uf_gw_rsrc_stimulus_st:
+			rsrc->state = uf_gw_rsrc_state_i_st;
+			break;
+		case uf_gw_rsrc_stimulus_ab:
+			break;
+		default:
+			uf_gw_rsrc_invalid_stimulus(rsrc,
+								stimulus);
+			break;
+		}
+		break;
+	case uf_gw_rsrc_state_i_st:
+		switch (stimulus) {
+		case uf_gw_rsrc_stimulus_ab:
+			rsrc->state = uf_gw_rsrc_state_i_st_ab;
+			break;
+		case uf_gw_rsrc_stimulus_sc:
+			rsrc->state = uf_gw_rsrc_state_i_st_sc;
+			break;
+		case uf_gw_rsrc_stimulus_ts:
+			rsrc->state = uf_gw_rsrc_state_i_st_ts;
+			break;
+		default:
+			uf_gw_rsrc_invalid_stimulus(rsrc,
+								stimulus);
+			break;
+		}
+		break;
+	case uf_gw_rsrc_state_i_st_ab:
+		switch (stimulus) {
+		case uf_gw_rsrc_stimulus_sc:
+			rsrc->state = uf_gw_rsrc_state_i;
+			uf_gw_rsrc_set_aborted(rsrc);
+			uf_gw_rsrc_complete(rsrc);
+			break;
+		default:
+			uf_gw_rsrc_invalid_stimulus(rsrc,
+								stimulus);
+			break;
+		}
+		break;
+	case uf_gw_rsrc_state_i_st_sc:
+		switch (stimulus) {
+		case uf_gw_rsrc_stimulus_ab:
+			rsrc->state = uf_gw_rsrc_state_i;
+			uf_gw_rsrc_set_aborted(rsrc);
+			uf_gw_rsrc_complete(rsrc);
+			break;
+		case uf_gw_rsrc_stimulus_ts:
+			rsrc->state = uf_gw_rsrc_state_i;
+			uf_gw_rsrc_complete(rsrc);
+			break;
+		default:
+			uf_gw_rsrc_invalid_stimulus(rsrc,
+								stimulus);
+			break;
+		}
+		break;
+	case uf_gw_rsrc_state_i_st_ts:
+		switch (stimulus) {
+		case uf_gw_rsrc_stimulus_ab:
+			break;
+		case uf_gw_rsrc_stimulus_sc:
+			rsrc->state = uf_gw_rsrc_state_i;
+			uf_gw_rsrc_complete(rsrc);
+			break;
+		default:
+			uf_gw_rsrc_invalid_stimulus(rsrc,
+								stimulus);
+			break;
+		}
+		break;
+	default:
+		uf_gw_rsrc_invalid_stimulus(rsrc, stimulus);
+		break;
+	}
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_gw_rsrc.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_gw_rsrc.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,84 @@
+/*****************************************************************************/
+/* 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 UF_GW_RSRC_H
+#define UF_GW_RSRC_H
+
+#include <linux/types.h>
+#include <xen/interface/io/usbif.h>
+#include "uf_channel.h"
+#include "uf_gw.h"
+
+typedef enum {
+	uf_gw_rsrc_state_i,
+	uf_gw_rsrc_state_i_st,
+	uf_gw_rsrc_state_i_st_ab,
+	uf_gw_rsrc_state_i_st_sc,
+	uf_gw_rsrc_state_i_st_ts
+} uf_gw_rsrc_state;
+
+typedef enum {
+	uf_gw_rsrc_stimulus_st,
+	uf_gw_rsrc_stimulus_ab,
+	uf_gw_rsrc_stimulus_sc,
+	uf_gw_rsrc_stimulus_ts,
+} uf_gw_rsrc_stimulus;
+
+struct uf_gw_rsrc {
+	struct uf_callback      callback;
+	struct uf_gw           *gw;
+	spinlock_t                    lock;
+	uf_gw_rsrc_state    state;
+	struct uf_gw_tra       *tra;
+	usbif_error                   aborted_error;
+	usbif_error                   error;
+	struct uf_channel_obmsg channel_message;
+};
+
+static inline struct list_head *
+uf_gw_rsrc_to_link(struct uf_gw_rsrc *rsrc)
+{
+	return &rsrc->callback.work.link;
+}
+
+static inline struct uf_gw_rsrc *
+uf_gw_rsrc_callback_to(struct uf_callback *callback)
+{
+	return container_of(callback, struct uf_gw_rsrc, callback);
+}
+
+static inline struct uf_gw *
+uf_gw_rsrc_query_gw(struct uf_gw_rsrc *rsrc)
+{
+	return rsrc->gw;
+}
+
+void uf_gw_rsrc_init(struct uf_gw_rsrc *rsrc,
+struct uf_gw *gw, uf_callback_function callback, int id);
+
+void uf_gw_rsrc_start(struct uf_gw_rsrc *rsrc,
+struct uf_gw_tra *tra);
+
+void uf_gw_rsrc_abort(struct uf_gw_rsrc *rsrc,
+usbif_error error);
+
+int uf_gw_rsrc_handle_response(struct uf_gw_rsrc *rsrc,
+struct usbif_response *response);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_module.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_module.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,65 @@
+/*****************************************************************************/
+/* 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 "uf_device.h"
+#include "uf_driver.h"
+#include "uf_trace.h"
+
+static int uf_module_init_or_exit(int exit)
+{
+	int return_value = 0;
+	trace();
+	if (usb_disabled()) {
+		return_value = -ENODEV;
+		goto exit_no_usb;
+	}
+	if (exit)
+		goto exit_path;
+	if ((return_value = uf_driver_class_init()) != 0)
+		goto exit_no_driver_class;
+	if ((return_value = uf_device_class_init()) != 0)
+		goto exit_no_device_class;
+	return 0;
+ exit_path:
+	uf_device_class_exit();
+ exit_no_device_class:
+	uf_driver_class_exit();
+ exit_no_driver_class:
+	exit_no_usb:
+	return return_value;
+}
+
+static int __init uf_module_init(void)
+{
+	trace();
+	return uf_module_init_or_exit(0);
+}
+
+static void __exit uf_module_exit(void)
+{
+	trace();
+	(void)uf_module_init_or_exit(1);
+}
+
+module_init(uf_module_init);
+module_exit(uf_module_exit);
+
+MODULE_LICENSE("GPL");
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_rbr_provider_pool.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_rbr_provider_pool.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,339 @@
+/*****************************************************************************/
+/* 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 "uf_rbr_provider_pool.h"
+#include "uf_trace.h"
+
+static UF_CALLBACK_SERIALISER(callback_serialiser);
+
+struct uf_rbr_provider_pool {
+	struct uf_buffer_rsrc_list      dedicated_rsrcs;
+	struct uf_buffer_rsrc_provider *provider;
+	spinlock_t                                lock;
+	struct uf_buffer_rsrc_list      head_request_req;
+	struct list_head                          request_list;
+	int                                       kicking_requests;
+	int                                       head_request_req_calculated;
+};
+
+static int
+uf_rbr_provider_pool_init_or_exit(
+struct uf_rbr_provider_pool *pool, int exit)
+{
+	int return_value = 0;
+	trace();
+	if (exit)
+		goto exit_path;
+	pool->provider = uf_allocate_buffer_rsrc_provider(
+				pool->dedicated_rsrcs);
+	if (pool->provider == NULL)
+		goto exit_no_provider;
+	spin_lock_init(&pool->lock);
+	INIT_LIST_HEAD(&pool->request_list);
+	pool->kicking_requests = 0;
+	pool->head_request_req_calculated = 0;
+	return 0;
+ exit_path:
+	uf_free_buffer_rsrc_provider(pool->provider);
+ exit_no_provider:
+	return return_value;
+}
+
+struct uf_rbr_provider_pool *uf_rbr_provider_pool_allocate(void)
+{
+	struct uf_rbr_provider_pool *pool;
+	trace();
+	pool = (struct uf_rbr_provider_pool *)kmalloc(sizeof(
+			struct uf_rbr_provider_pool), GFP_KERNEL);
+	if (pool != NULL) {
+		pool->dedicated_rsrcs.grant_references = USBIF_QUOTA *
+					USBIF_GRANT_TABLE_REFERENCE_COUNT;
+		if (uf_rbr_provider_pool_init_or_exit(pool, 0) != 0) {
+			kfree(pool);
+			pool = NULL;
+		}
+	}
+	return pool;
+}
+
+void
+uf_rbr_provider_pool_free(struct uf_rbr_provider_pool *pool)
+{
+	trace();
+	(void)uf_rbr_provider_pool_init_or_exit(pool, 1);
+	kfree(pool);
+}
+
+static void
+uf_rbr_provider_pool_kick_requests(
+struct uf_rbr_provider_pool *pool);
+
+void
+uf_rbr_provider_pool_reserve_and_create_rbrs(
+struct uf_rbr_provider_pool *pool,
+struct uf_rbr_provider_request *request, domid_t domain)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	unsigned long flags;
+	trace();
+	request->pool = pool;
+	request->domain = domain;
+	spin_lock_irqsave(&pool->lock, flags);
+	list_add_tail(uf_rbr_provider_request_to_link(request),
+							&pool->request_list);
+	spin_unlock_irqrestore(&pool->lock, flags);
+	uf_rbr_provider_pool_kick_requests(pool);
+}
+
+static int
+uf_rbr_provider_pool_calculate_rbr_rsrcs(void *buffer,
+usbif_buffer_byte_count length, struct uf_buffer_rsrc_list *list)
+{
+	unsigned long first_page, final_page;
+	trace();
+	*list = uf_buffer_rsrc_list_null();
+	if (length == 0)
+		return 0;
+	first_page = (((unsigned long)buffer) / PAGE_SIZE);
+	final_page = (((unsigned long)((char *)buffer+length-1))/PAGE_SIZE);
+	list->grant_references = final_page - first_page + 1;
+	return list->grant_references > USBIF_GRANT_TABLE_REFERENCE_COUNT;
+}
+
+static int uf_rbr_provider_pool_calc_req(
+struct uf_rbr_provider_request *request,
+struct uf_buffer_rsrc_list *list)
+{
+	struct uf_create_rbr_request_element *element;
+	trace();
+	*list = uf_buffer_rsrc_list_null();
+	list_for_each_entry(element, &request->request_elements, link) {
+		struct uf_buffer_rsrc_list element_list;
+		if (uf_rbr_provider_pool_calculate_rbr_rsrcs(
+			element->buffer, element->length, &element_list) != 0)
+			return 1;
+		uf_buffer_rsrc_list_plus_equals(list, &element_list);
+	}
+	return 0;
+}
+
+static void
+uf_rbr_provider_pool_create_rbr(void *buffer,
+usbif_buffer_byte_count length, domid_t domain,
+struct uf_buffer_rsrc_provider *provider, struct usbif_rbr *rbr,
+int access_flags, struct uf_rbr_context *context)
+{
+	int i = 0;
+	unsigned long page, final_page;
+	trace();
+	memset(rbr, 0, sizeof(*rbr));
+	if (length == 0) {
+		context->count = 0;
+		return;
+	}
+	context->provider = provider;
+	context->domain_id = domain;
+	page = (unsigned long)buffer & PAGE_MASK;
+	final_page = ((unsigned long)buffer + length - 1) & PAGE_MASK;
+	for (;;) {
+		rbr->reference[i] = context->reference[i] =
+		uf_buffer_rsrc_provider_allocate_grant_reference(
+								provider);
+		gnttab_grant_foreign_access_ref(context->reference[i],
+			context->domain_id, virt_to_mfn(page), ((access_flags &
+			UF_ACCESS_FLAGS_WRITE) == 0) ? 1 : 0);
+		i++;
+		if (page == final_page)
+			break;
+		page += PAGE_SIZE;
+	}
+	context->count = i;
+	rbr->byte_offset = (unsigned long)buffer & ~PAGE_MASK;
+	rbr->byte_count = length;
+}
+
+static void
+uf_rbr_provider_pool_service_request(
+struct uf_rbr_provider_pool *pool,
+struct uf_rbr_provider_request *request)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	struct uf_create_rbr_request_element *element;
+	trace();
+	list_for_each_entry(element, &request->request_elements, link) {
+		uf_rbr_provider_pool_create_rbr(
+				element->buffer, element->length,
+				request->domain, pool->provider, &element->rbr,
+				element->access_flags, &element->context);
+		element->created = 1;
+	}
+	uf_callback_serialiser_complete_callback(&callback_serialiser,
+		uf_rbr_provider_request_to_create_callback(request),
+		USBIF_ERROR_SUCCESS);
+}
+
+static void uf_rbr_provider_pool_kick_requests(
+struct uf_rbr_provider_pool *pool)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&pool->lock, flags);
+	while ((!pool->kicking_requests) && 
+					(!list_empty(&pool->request_list))) {
+		struct uf_buffer_rsrc_list free_rsrcs;
+		struct uf_rbr_provider_request *request =
+			uf_rbr_provider_request_link_to(
+						pool->request_list.next);
+		if (pool->head_request_req_calculated)
+			goto skip_calc;
+		if ((uf_rbr_provider_pool_calc_req(request,
+				&pool->head_request_req) != 0) ||
+				!uf_buffer_rsrc_list_subset_of(
+				&pool->head_request_req,
+				&pool->dedicated_rsrcs)) {
+			list_del_init(uf_rbr_provider_request_to_link(
+								request));
+			uf_callback_serialiser_complete_callback(
+				&callback_serialiser,
+				uf_rbr_provider_request_to_create_callback(
+								request),
+				USBIF_ERROR_TOO_BIG);
+			continue;
+		}
+		pool->head_request_req_calculated = 1;
+	skip_calc:
+		free_rsrcs =
+			uf_buffer_rsrc_provider_query_free_rsrcs(
+							pool->provider);
+		if (!uf_buffer_rsrc_list_subset_of(
+				&pool->head_request_req, &free_rsrcs))
+			break;
+		list_del_init(uf_rbr_provider_request_to_link(request));
+		pool->head_request_req_calculated = 0;
+		pool->kicking_requests = 1;
+		spin_unlock_irqrestore(&pool->lock, flags);
+		uf_rbr_provider_pool_service_request(pool, request);
+		spin_lock_irqsave(&pool->lock, flags);
+		pool->kicking_requests = 0;
+	}
+	spin_unlock_irqrestore(&pool->lock, flags);
+}
+
+void
+uf_rbr_provider_pool_abort_reserve_and_create_rbrs(
+struct uf_rbr_provider_request *request, usbif_error error)
+{
+	struct uf_rbr_provider_pool *pool = request->pool;
+	unsigned long flags;
+	struct uf_rbr_provider_request *queued_request;
+	trace();
+	spin_lock_irqsave(&pool->lock, flags);
+	list_for_each_entry(queued_request, &pool->request_list,
+				create_callback.work.link) {
+		if (request == queued_request) {
+			list_del_init(uf_rbr_provider_request_to_link(
+								request));
+			pool->head_request_req_calculated = 0;
+			uf_callback_serialiser_complete_callback(
+				&callback_serialiser,
+				uf_rbr_provider_request_to_create_callback(
+							request), error);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&pool->lock, flags);
+}
+
+static void
+uf_rbr_provider_pool_retry_revoke_rbr(
+struct uf_rbr_context *context)
+{
+	int i = 0,j;
+	trace();
+	while (i != context->count) {
+		if (gnttab_end_foreign_access_ref(context->reference[i], 0)) {
+			uf_buffer_rsrc_provider_free_grant_reference(
+				context->provider, context->reference[i]);
+			for (j = i + 1; j < context->count; j++) {
+				context->reference[j-1] =context->reference[j];
+			}
+			--context->count;
+		} else {
+			i++;
+		}
+	}
+	if (context->count == 0) {
+		uf_callback_success(context->callback);
+	} else {
+		printk(KERN_WARNING
+		     "uf failed to end foreign "
+		     "access granted to domain id %d.  Retry in 5 seconds.\n",
+		     context->domain_id);
+		init_timer(&context->timer);
+		context->timer.data = (unsigned long)context;
+		context->timer.expires = jiffies + (5*HZ);
+		context->timer.function = (void (*)(unsigned long))
+				uf_rbr_provider_pool_retry_revoke_rbr;
+		add_timer(&context->timer);
+	}
+}
+
+static void
+uf_rbr_provider_pool_revoke_rbr(struct uf_rbr_context *context,
+struct uf_callback *callback)
+{
+	trace();
+	context->callback = callback;
+	uf_rbr_provider_pool_retry_revoke_rbr(context);
+}
+
+static void
+uf_rbr_provider_pool_revoke_and_unreserve_rbrs_1(
+struct uf_callback *callback)
+{
+	struct uf_rbr_provider_request *request = container_of(callback,
+			struct uf_rbr_provider_request,
+			reserved_callback);
+	struct uf_create_rbr_request_element *element;
+	trace();
+	list_for_each_entry(element, &request->request_elements, link) {
+		if (element->created) {
+			element->created = 0;
+			uf_rbr_provider_pool_revoke_rbr(
+						&element->context, callback);
+			return;
+		}
+	}
+	uf_rbr_provider_pool_kick_requests(request->pool);
+	uf_callback_serialiser_complete_callback(&callback_serialiser,
+		     uf_rbr_provider_request_to_revoke_callback(request),
+							USBIF_ERROR_SUCCESS);
+}
+
+void uf_rbr_provider_pool_revoke_and_unreserve_rbrs(
+struct uf_rbr_provider_request *request)
+{
+	trace();
+	uf_callback_init(&request->reserved_callback,
+		uf_rbr_provider_pool_revoke_and_unreserve_rbrs_1);
+	uf_rbr_provider_pool_revoke_and_unreserve_rbrs_1(
+		&request->reserved_callback);
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_rbr_provider_pool.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_rbr_provider_pool.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,169 @@
+/*****************************************************************************/
+/* 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 UF_RBR_PROVIDER_POOL
+#define UF_RBR_PROVIDER_POOL
+
+#include <xen/interface/io/usbif.h>
+#include "uf_buffer_rsrc_provider.h"
+#include "uf_callback.h"
+
+struct uf_rbr_provider_pool;
+
+struct uf_rbr_provider_pool *uf_rbr_provider_pool_allocate(void);
+
+void uf_rbr_provider_pool_free(struct uf_rbr_provider_pool *pool);
+
+#define UF_ACCESS_FLAGS_READ  1
+#define UF_ACCESS_FLAGS_WRITE 2
+
+struct uf_rbr_context {
+	struct uf_buffer_rsrc_provider *provider;
+	struct timer_list                         timer;
+	struct uf_callback                 *callback;
+	int                                       domain_id;
+	int                                       count;
+	grant_ref_t reference[USBIF_GRANT_TABLE_REFERENCE_COUNT];
+};
+
+struct uf_create_rbr_request_element {
+	struct list_head             link;
+	void                        *buffer;
+	usbif_buffer_byte_count      length;
+	int                          access_flags;
+	struct usbif_rbr             rbr;
+	int                          created;
+	struct uf_rbr_context  context;
+};
+
+static inline void uf_create_rbr_request_element_init(
+struct uf_create_rbr_request_element *element)
+{
+	memset(element, 0, sizeof(*element));
+	INIT_LIST_HEAD(&element->link);
+}
+
+static inline void
+uf_create_rbr_request_element_set_buffer(
+struct uf_create_rbr_request_element *element, void *buffer,
+usbif_buffer_byte_count length, int access_flags)
+{
+	element->buffer = buffer;
+	element->length = length;
+	element->access_flags = access_flags;
+}
+
+static inline struct usbif_rbr
+uf_create_rbr_request_element_query_rbr(
+struct uf_create_rbr_request_element *element)
+{
+	return element->rbr;
+}
+
+static inline void
+uf_create_rbr_request_element_ensure_removed(
+struct uf_create_rbr_request_element *element)
+{
+	list_del_init(&element->link);
+}
+
+struct uf_rbr_provider_request {
+	struct uf_callback create_callback;
+	struct uf_callback revoke_callback;
+	struct uf_rbr_provider_pool *pool;
+	domid_t domain;
+	struct list_head request_elements;
+	struct uf_callback reserved_callback;
+};
+
+static inline struct uf_callback *
+uf_rbr_provider_request_to_create_callback(
+struct uf_rbr_provider_request *request)
+{
+	return &request->create_callback;
+}
+
+static inline struct uf_rbr_provider_request *
+uf_rbr_provider_request_create_callback_to(
+struct uf_callback * callback)
+{
+	return container_of(callback, struct uf_rbr_provider_request,
+							create_callback);
+}
+
+static inline struct uf_callback *
+uf_rbr_provider_request_to_revoke_callback(
+struct uf_rbr_provider_request *request)
+{
+	return &request->revoke_callback;
+}
+
+static inline struct uf_rbr_provider_request *
+uf_rbr_provider_request_revoke_callback_to(
+struct uf_callback * callback)
+{
+	return container_of(callback, struct uf_rbr_provider_request,
+							revoke_callback);
+}
+
+static inline struct list_head * uf_rbr_provider_request_to_link(
+struct uf_rbr_provider_request *request)
+{
+	return uf_callback_to_link(
+		uf_rbr_provider_request_to_create_callback(request));
+}
+
+static inline struct uf_rbr_provider_request *
+uf_rbr_provider_request_link_to(struct list_head *link)
+{
+	return uf_rbr_provider_request_create_callback_to(
+					uf_callback_link_to(link));
+}
+
+static inline void uf_rbr_provider_request_init(
+struct uf_rbr_provider_request *request,
+uf_callback_function *create_callback,
+uf_callback_function *revoke_callback)
+{
+	uf_callback_init(&request->create_callback, create_callback);
+	uf_callback_init(&request->revoke_callback, revoke_callback);
+	INIT_LIST_HEAD(&request->request_elements);
+}
+
+static inline void uf_rbr_provider_request_add_element(
+struct uf_rbr_provider_request *request,
+struct uf_create_rbr_request_element *element)
+{
+	list_add(&element->link, &request->request_elements);
+}
+
+void
+uf_rbr_provider_pool_reserve_and_create_rbrs(
+struct uf_rbr_provider_pool *pool,
+struct uf_rbr_provider_request *request, domid_t domain);
+
+void
+uf_rbr_provider_pool_abort_reserve_and_create_rbrs(
+struct uf_rbr_provider_request *request, usbif_error error);
+
+void
+uf_rbr_provider_pool_revoke_and_unreserve_rbrs(
+struct uf_rbr_provider_request *request);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_ring_channel.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_ring_channel.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,744 @@
+/*****************************************************************************/
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redisrfbute 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 disrfbuted 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/interrupt.h>
+#include <xen/interface/io/usbif.h>
+#include <xen/driver_util.h>
+#include <xen/evtchn.h>
+#include "uf_ring_channel.h"
+#include "uf_trace.h"
+
+static inline void
+uf_ring_channel_rsrc_init(struct uf_ring_channel_rsrc *rsrc,
+struct uf_ring_channel *channel, uf_callback_function *callback)
+{
+	trace();
+	uf_channel_ibmsg_init(&rsrc->message, callback);
+	rsrc->channel = channel;
+}
+
+static inline struct list_head *
+uf_ring_channel_rsrc_to_link(struct uf_ring_channel_rsrc *rsrc)
+{
+	return uf_channel_ibmsg_to_link(&rsrc->message);
+}
+
+static inline struct uf_ring_channel_rsrc *
+uf_ring_channel_rsrc_callback_to(struct uf_callback *callback)
+{
+	return container_of(uf_channel_ibmsg_callback_to(callback),
+				struct uf_ring_channel_rsrc, message);
+}
+
+typedef enum {
+	uf_ring_channel_stimulus_cn,/* connect request             */
+	uf_ring_channel_stimulus_mq,/* message queued              */
+	uf_ring_channel_stimulus_dn,/* disconnect request          */
+	uf_ring_channel_stimulus_ri,/* ring interrupt              */
+	uf_ring_channel_stimulus_cs,/* connect successful          */
+	uf_ring_channel_stimulus_cf,/* connect failed              */
+	uf_ring_channel_stimulus_cc,/* connect client completed    */
+	uf_ring_channel_stimulus_dc,/* disconnect client completed */
+	uf_ring_channel_stimulus_ds,/* disconnect successful       */
+	uf_ring_channel_stimulus_ks,/* kick send ring completed    */
+	uf_ring_channel_stimulus_kr,/* kick recv ring completed    */
+	uf_ring_channel_stimulus_rc,/* rsrc completed              */
+	uf_ring_channel_stimulus_rf /* rsrc final completion       */
+} uf_ring_channel_stimulus;
+
+static void
+uf_ring_channel_handle_stimulus(struct uf_ring_channel *channel,
+uf_ring_channel_stimulus stimulus);
+
+void
+uf_ring_channel_connect(struct uf_ring_channel *channel,
+struct uf_ring_channel_connect_request *request)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	channel->current_callback = &request->callback;
+	uf_ring_channel_handle_stimulus(channel,
+					uf_ring_channel_stimulus_cn);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+uf_ring_channel_submit_message(struct uf_channel *base_channel,
+struct uf_channel_obmsg *message)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	struct uf_ring_channel *channel =
+				uf_ring_channel_channel_to(base_channel);
+	unsigned long flags;
+	spin_lock_irqsave(&channel->lock, flags);
+	list_add_tail(uf_channel_obmsg_to_link(message),
+					&channel->message_list);
+	uf_ring_channel_handle_stimulus(channel,
+					uf_ring_channel_stimulus_mq);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+void
+uf_ring_channel_disconnect(struct uf_ring_channel *channel,
+struct uf_callback *callback)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	channel->current_callback = callback;
+	uf_ring_channel_handle_stimulus(channel,
+					uf_ring_channel_stimulus_dn);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static irqreturn_t
+uf_ring_channel_interrupt(int irq, void *context, struct pt_regs *ptregs)
+{
+	struct uf_ring_channel *channel = context;
+	unsigned long flags;
+	spin_lock_irqsave(&channel->lock, flags);
+	uf_ring_channel_handle_stimulus(channel,
+					uf_ring_channel_stimulus_ri);
+	spin_unlock_irqrestore(&channel->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static void
+uf_ring_channel_invalid_stimulus(struct uf_ring_channel *channel,
+uf_ring_channel_stimulus stimulus)
+{
+	trace();
+	printk(KERN_ERR "uf: channel %p in state %d"
+		"received invalid stimulus %d", channel, channel->state,
+		stimulus);
+}
+
+static void
+uf_ring_channel_do_connect(struct uf_ring_channel *channel)
+{
+	trace();
+	(void)uf_work_schedule(&channel->do_connect_1_work);
+}
+
+static void uf_ring_channel_do_connect_1(void *data)
+{
+	struct uf_ring_channel *channel = data;
+	struct uf_ring_channel_connect_request *request =
+		uf_ring_channel_connect_request_callback_to(
+						channel->current_callback);
+	struct evtchn_alloc_unbound alloc_unbound = {
+		.dom        = DOMID_SELF,
+		.remote_dom = request->domain_id
+	};
+	struct usbif_sring * sring = (struct usbif_sring *)channel->ring;
+	int error;
+	unsigned long flags;
+	trace();
+	SHARED_RING_INIT(sring);
+	FRONT_RING_INIT(&channel->front_ring, sring, PAGE_SIZE);
+	BUG_ON(HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+						&alloc_unbound) != 0);
+	channel->event_channel = alloc_unbound.port;
+	error = bind_evtchn_to_irqhandler(channel->event_channel,
+				uf_ring_channel_interrupt,
+				SA_SAMPLE_RANDOM, "usbif", channel);
+	BUG_ON(error < 0);
+	channel->irq = error;
+	channel->ring_ref = gnttab_claim_grant_reference(
+						&channel->grant_ref_pool);
+	channel->domain_id = request->domain_id;
+	gnttab_grant_foreign_access_ref(channel->ring_ref,
+					channel->domain_id,
+					virt_to_mfn(channel->ring),
+					0 /* not read-only */ );
+	request->ring_ref = channel->ring_ref;
+	request->event_channel = channel->event_channel;
+	spin_lock_irqsave(&channel->lock, flags);
+	uf_ring_channel_handle_stimulus(channel,
+			uf_ring_channel_stimulus_cs);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+uf_ring_channel_connect_client(struct uf_ring_channel *channel)
+{
+	trace();
+	(void)uf_work_schedule(&channel->connect_client_1_work);
+}
+
+static void uf_ring_channel_connect_client_1(void *data)
+{
+	struct uf_ring_channel *channel = data;
+	unsigned long flags;
+	trace();
+	uf_channel_connect(&channel->channel);
+	spin_lock_irqsave(&channel->lock, flags);
+	uf_ring_channel_handle_stimulus(channel,
+					uf_ring_channel_stimulus_cc);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+uf_ring_channel_disconnect_client(struct uf_ring_channel *channel)
+{
+	trace();
+	(void)uf_work_schedule(&channel->disconnect_client_1_work);
+}
+
+static void uf_ring_channel_disconnect_client_1(void *data)
+{
+	struct uf_ring_channel *channel = data;
+	trace();
+	uf_channel_disconnect(&channel->channel,
+				&channel->disconnect_client_2_callback);
+}
+
+static void
+uf_ring_channel_disconnect_client_2(struct uf_callback *callback)
+{
+	struct uf_ring_channel *channel = container_of(callback,
+		struct uf_ring_channel, disconnect_client_2_callback);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	uf_ring_channel_handle_stimulus(channel,
+					uf_ring_channel_stimulus_dc);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+uf_ring_channel_do_disconnect(struct uf_ring_channel *channel)
+{
+	trace();
+	(void)uf_work_schedule(&channel->do_disconnect_1_work);
+}
+
+static void uf_ring_channel_do_disconnect_1(void *data)
+{
+	struct uf_ring_channel *channel = data;
+	unsigned long flags;
+	trace();
+	if (gnttab_end_foreign_access_ref(channel->ring_ref, 1)) {
+		gnttab_release_grant_reference(&channel->grant_ref_pool,
+						channel->ring_ref);
+		unbind_from_irqhandler(channel->irq, channel);
+		spin_lock_irqsave(&channel->lock, flags);
+		uf_ring_channel_handle_stimulus(channel,
+				     uf_ring_channel_stimulus_ds);
+		spin_unlock_irqrestore(&channel->lock, flags);
+	} else {
+		printk(KERN_WARNING
+		     "uf_ring_channel failed to end foreign access "
+		     "granted to domain id %d.  Will retry in 5 seconds.\n",
+		     channel->domain_id);
+		init_timer(&channel->timer);
+		channel->timer.data = (unsigned long)channel;
+		channel->timer.expires = jiffies + (5*HZ);
+		channel->timer.function = (void (*)(unsigned long))
+			    uf_ring_channel_do_disconnect;
+		add_timer(&channel->timer);
+	}
+}
+
+static void
+uf_ring_channel_kick_send_ring(struct uf_ring_channel *channel)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	if (!channel->send_ring_kick_out) {
+		channel->send_ring_kick_out = 1;
+		(void)uf_work_schedule(&channel->kick_send_ring_1_work);
+	}
+}
+
+static void uf_ring_channel_kick_send_ring_1(void *data)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	struct uf_ring_channel *channel = data;
+	unsigned long flags;
+	spin_lock_irqsave(&channel->lock, flags);
+	for (;;) {
+		struct usbif_front_ring *front_ring = &channel->front_ring;
+		int notify = 0;
+		while (!list_empty(&channel->message_list)) {
+			struct uf_channel_obmsg *message;
+			struct usbif_request *request;
+			message = list_entry(channel->message_list.next,
+						struct uf_channel_obmsg,
+						callback.work.link);
+			list_del_init(uf_channel_obmsg_to_link(message));
+			spin_unlock_irqrestore(&channel->lock, flags);
+			request = RING_GET_REQUEST(front_ring,
+						front_ring->req_prod_pvt);
+			*request = message->request;
+			uf_callback_success(
+				uf_channel_obmsg_to_callback(message));
+			front_ring->req_prod_pvt++;
+			notify = 1;
+			spin_lock_irqsave(&channel->lock, flags);
+		}
+		if (notify) {
+			spin_unlock_irqrestore(&channel->lock, flags);
+			RING_PUSH_REQUESTS(front_ring);
+			notify_remote_via_irq(channel->irq);
+			spin_lock_irqsave(&channel->lock, flags);
+		} else {
+			channel->send_ring_kick_out = 0;
+			uf_ring_channel_handle_stimulus(channel,
+					uf_ring_channel_stimulus_ks);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+uf_ring_channel_kick_recv_ring(struct uf_ring_channel *channel)
+{
+	if (!channel->recv_ring_kick_out) {
+		channel->recv_ring_kick_out = 1;
+		(void)uf_work_schedule(&channel->kick_recv_ring_1_work);
+	}
+}
+
+static void uf_ring_channel_kick_recv_ring_1(void *data)
+{
+	struct uf_ring_channel *channel = data;
+	unsigned long flags;
+	spin_lock_irqsave(&channel->lock, flags);
+	for (;;) {
+		struct usbif_front_ring *front_ring = &channel->front_ring;
+		int progress = 0;
+		RING_IDX rp, rc;
+		rc = front_ring->rsp_cons;
+		/* To avoid going idle when there is a waiting response we   */
+		/* need a mb() here to make sure we see any requests which   */
+		/* are new this time around the outer 'for' loop.            */
+		/* FIXME: spin_lock below makes this unnecessary?            */
+		mb();
+		rp = front_ring->sring->rsp_prod;
+		/* To make sure we see the correct data for the requests     */
+		/* found above we need a rmb() here to force reads to be     */
+                /* after the read of front_ring->sring->rsp_prod.            */
+		rmb();
+		/* FIXME: we are trusting sring->rsp_prod here... */
+		while (!list_empty(&channel->rsrc_list) && (rc != rp)) {
+			struct uf_ring_channel_rsrc *rsrc;
+			struct usbif_response *response;
+			rsrc = list_entry(channel->rsrc_list.next,
+				struct uf_ring_channel_rsrc,
+				message.callback.work.link);
+			list_del_init(uf_ring_channel_rsrc_to_link(
+									rsrc));
+			response = RING_GET_RESPONSE(front_ring, rc);
+			rsrc->message.response = *response;
+			front_ring->rsp_cons = ++rc;
+			channel->rsrcs_out++;
+			spin_unlock_irqrestore(&channel->lock, flags);
+			uf_channel_handle_message(&channel->channel,
+							&rsrc->message);
+			progress = 1;
+			spin_lock_irqsave(&channel->lock, flags);
+		}
+		if (!progress)
+		{
+			channel->recv_ring_kick_out = 0;
+			uf_ring_channel_handle_stimulus(channel,
+					uf_ring_channel_stimulus_kr);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+uf_ring_channel_kick_recv_ring_2(struct uf_callback *callback)
+{
+	struct uf_ring_channel_rsrc *rsrc =
+			uf_ring_channel_rsrc_callback_to(callback);
+	struct uf_ring_channel *channel = rsrc->channel;
+	unsigned long flags;
+	if ((uf_callback_query_error(callback) != USBIF_ERROR_SUCCESS)
+					&& (channel->protocol_error != NULL))
+		channel->protocol_error(channel);
+	spin_lock_irqsave(&channel->lock, flags);
+	list_add_tail(uf_ring_channel_rsrc_to_link(rsrc),
+							&channel->rsrc_list);
+	if (--channel->rsrcs_out == 0) {
+		uf_ring_channel_handle_stimulus(channel,
+				uf_ring_channel_stimulus_rf);
+	} else {
+		uf_ring_channel_handle_stimulus(channel,
+				uf_ring_channel_stimulus_rc);
+	}
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void
+uf_ring_channel_complete_current_callback(
+struct uf_ring_channel *channel)
+{
+	trace();
+	uf_callback_success(channel->current_callback);
+}
+
+static void
+uf_ring_channel_fail_current_callback(
+struct uf_ring_channel *channel)
+{
+	trace();
+	uf_callback_complete(channel->current_callback,
+							USBIF_ERROR_FAILURE);
+}
+
+static void
+uf_ring_channel_fail_out_messages(struct uf_ring_channel *channel)
+{
+	trace();
+	while (!list_empty(&channel->message_list)) {
+		struct uf_channel_obmsg *message = list_entry(
+			channel->message_list.next,
+			struct uf_channel_obmsg,
+			callback.work.link);
+		list_del_init(uf_channel_obmsg_to_link(message));
+		uf_callback_success(uf_channel_obmsg_to_callback(
+								message));
+	}
+}
+
+static void
+uf_ring_channel_test_rsrcs(struct uf_ring_channel *channel)
+{
+	trace();
+	if (channel->rsrcs_out == 0) {
+		uf_ring_channel_handle_stimulus(channel,
+					uf_ring_channel_stimulus_rf);
+	}
+}
+
+static int
+uf_ring_channel_init_or_exit(struct uf_ring_channel *channel,
+int exit)
+{
+	int return_value = 0, i;
+	trace();
+	if (exit)
+		goto exit_path;
+	channel->ring = (void *)__get_free_page(GFP_KERNEL);
+	if (channel->ring == NULL) {
+		trace_info("failed to allocate ring");
+		return_value = -ENOMEM;
+		goto exit_no_ring;
+	}
+	return_value = gnttab_alloc_grant_references(1,
+						&channel->grant_ref_pool);
+	if (return_value != 0) {
+		trace_info("failed to allocate grant reference pool");
+		goto exit_no_grant_ref;
+	}
+	spin_lock_init(&channel->lock);
+	channel->state = uf_ring_channel_state_i;
+	INIT_LIST_HEAD(&channel->message_list);
+	uf_work_init(&channel->do_connect_1_work,
+		     uf_ring_channel_do_connect_1, channel);
+	uf_work_init(&channel->connect_client_1_work,
+		     uf_ring_channel_connect_client_1, channel);
+	uf_work_init(&channel->disconnect_client_1_work,
+		     uf_ring_channel_disconnect_client_1, channel);
+	uf_callback_init(&channel->disconnect_client_2_callback,
+		     uf_ring_channel_disconnect_client_2);
+	uf_work_init(&channel->do_disconnect_1_work,
+		     uf_ring_channel_do_disconnect_1, channel);
+	uf_work_init(&channel->kick_send_ring_1_work,
+		     uf_ring_channel_kick_send_ring_1, channel);
+	uf_work_init(&channel->kick_recv_ring_1_work,
+		     uf_ring_channel_kick_recv_ring_1, channel);
+	INIT_LIST_HEAD(&channel->rsrc_list);
+	for (i = 0; i < USBIF_QUOTA; i++) {
+		struct uf_ring_channel_rsrc *rsrc = &channel->rsrcs[i];
+		uf_ring_channel_rsrc_init(rsrc, channel,
+				uf_ring_channel_kick_recv_ring_2);
+		list_add_tail(uf_ring_channel_rsrc_to_link(rsrc),
+							&channel->rsrc_list);
+	}
+	channel->send_ring_kick_out = 0;
+	channel->recv_ring_kick_out = 0;
+	channel->rsrcs_out = 0;
+	return 0;
+ exit_path:
+	gnttab_free_grant_references(channel->grant_ref_pool);
+ exit_no_grant_ref:
+	free_page((unsigned long)channel->ring);
+ exit_no_ring:
+	return return_value;
+}
+
+int
+uf_ring_channel_init(struct uf_ring_channel *channel,
+void (*protocol_error) (struct uf_ring_channel *channel))
+{
+	trace();
+	uf_channel_init(&channel->channel,
+					uf_ring_channel_submit_message);
+	channel->protocol_error = protocol_error;
+	return uf_ring_channel_init_or_exit(channel, 0);
+}
+
+void uf_ring_channel_exit(struct uf_ring_channel *channel)
+{
+	trace();
+	(void)uf_ring_channel_init_or_exit(channel, 1);
+}
+
+static void uf_ring_channel_handle_stimulus(
+struct uf_ring_channel *channel,
+uf_ring_channel_stimulus stimulus)
+{
+	switch (channel->state) {
+	case uf_ring_channel_state_i:
+		/* Client disconnected.   */
+		/* No messages queued.    */
+		/* Kick send idle.        */
+		/* Kick recv idle.        */
+		/* Target rsrcs idle.     */
+		switch (stimulus) {
+		case uf_ring_channel_stimulus_cn:
+			channel->state = uf_ring_channel_state_i_cn;
+			uf_ring_channel_do_connect(channel);
+			break;
+		default:
+			uf_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case uf_ring_channel_state_i_cn:
+		/* Interface connecting.   */
+		/* Client disconnected.    */
+		/* No messages queued.     */
+		/* Kick send idle.         */
+		/* Kick recv idle.         */
+		/* Target rsrcs idle.      */
+		/* do connect in progress. */
+		switch (stimulus) {
+		case uf_ring_channel_stimulus_ri:
+			break;
+		case uf_ring_channel_stimulus_cs:
+			channel->state = uf_ring_channel_state_i_cn_cs;
+			uf_ring_channel_connect_client(channel);
+			break;
+		case uf_ring_channel_stimulus_cf:
+			channel->state = uf_ring_channel_state_i;
+			uf_ring_channel_fail_current_callback(channel);
+			break;
+		default:
+			uf_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case uf_ring_channel_state_i_cn_cs:
+		/* Interface connecting.      */
+		/* Client connecting.         */
+		/* Maybe messages queued.     */
+		/* Kick send idle.            */
+		/* Kick recv idle.            */
+		/* Target rsrcs idle.         */
+		/* Connected.                 */
+		/* Connect client in progress */
+		switch (stimulus) {
+		case uf_ring_channel_stimulus_mq:
+		case uf_ring_channel_stimulus_ri:
+			break;
+		case uf_ring_channel_stimulus_cc:
+			channel->state =
+				uf_ring_channel_state_i_cn_cs_cc;
+			uf_ring_channel_complete_current_callback(
+								channel);
+			uf_ring_channel_kick_send_ring(channel);
+			uf_ring_channel_kick_recv_ring(channel);
+			break;
+		default:
+			uf_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case uf_ring_channel_state_i_cn_cs_cc:
+		/* Interface connected.         */
+		/* Client connected.            */
+		/* Maybe messages queued.       */
+		/* Maybe kick send in progress. */
+		/* Maybe kick recv in progress. */
+		/* Maybe target rsrcs busy.     */
+		/* Connected.                   */
+		switch (stimulus) {
+		case uf_ring_channel_stimulus_mq:
+			uf_ring_channel_kick_send_ring(channel);
+			break;
+		case uf_ring_channel_stimulus_dn:
+			channel->state =
+				uf_ring_channel_state_i_cn_cs_cc_dn;
+			uf_ring_channel_kick_send_ring(channel);
+			uf_ring_channel_kick_recv_ring(channel);
+			break;
+		case uf_ring_channel_stimulus_ri:
+			uf_ring_channel_kick_recv_ring(channel);
+			break;
+		case uf_ring_channel_stimulus_ks:
+		case uf_ring_channel_stimulus_kr:
+			break;
+		case uf_ring_channel_stimulus_rc:
+		case uf_ring_channel_stimulus_rf:
+			uf_ring_channel_kick_recv_ring(channel);
+			break;
+		default:
+			uf_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case uf_ring_channel_state_i_cn_cs_cc_dn:
+		/* Interface disconnecting.     */
+		/* Client connected.            */
+		/* Maybe messages queued.       */
+		/* Kick send in progress.       */
+		/* Kick recv in progress.       */
+		/* Maybe target rsrcs busy.     */
+		/* Connected.                   */
+		switch (stimulus) {
+		case uf_ring_channel_stimulus_mq:
+		case uf_ring_channel_stimulus_ri:
+			break;
+		case uf_ring_channel_stimulus_ks:
+		case uf_ring_channel_stimulus_kr:
+			channel->state =
+				uf_ring_channel_state_i_cn_cs_cc_dn_ks;
+			break;
+		case uf_ring_channel_stimulus_rc:
+		case uf_ring_channel_stimulus_rf:
+			break;
+		default:
+			uf_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case uf_ring_channel_state_i_cn_cs_cc_dn_ks:
+		/* Interface disconnecting.           */
+		/* Client connected.                  */
+		/* Maybe messages queued.             */
+		/* One of kick send/recv in progress. */
+		/* Maybe target rsrcs busy.           */
+		/* Connected.                         */
+		switch (stimulus) {
+		case uf_ring_channel_stimulus_mq:
+		case uf_ring_channel_stimulus_ri:
+			break;
+		case uf_ring_channel_stimulus_ks:
+		case uf_ring_channel_stimulus_kr:
+			channel->state =
+			    uf_ring_channel_state_i_cn_cs_cc_dn_ks_kr;
+			uf_ring_channel_disconnect_client(channel);
+			uf_ring_channel_fail_out_messages(channel);
+			break;
+		case uf_ring_channel_stimulus_rc:
+		case uf_ring_channel_stimulus_rf:
+			break;
+		default:
+			uf_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case uf_ring_channel_state_i_cn_cs_cc_dn_ks_kr:
+		/* Interface disconnecting.     */
+		/* Client disconnecting.        */
+		/* No messages queued.          */
+		/* Kick send/recv idle.         */
+		/* Maybe target rsrcs busy.     */
+		/* Connected.                   */
+		switch (stimulus) {
+		case uf_ring_channel_stimulus_mq:
+			uf_ring_channel_fail_out_messages(channel);
+			break;
+		case uf_ring_channel_stimulus_ri:
+			break;
+		case uf_ring_channel_stimulus_dc:
+			channel->state =
+			    uf_ring_channel_state_i_cn_cs_cc_dn_ks_kr_dc;
+			uf_ring_channel_test_rsrcs(channel);
+			break;
+		case uf_ring_channel_stimulus_rc:
+		case uf_ring_channel_stimulus_rf:
+			break;
+		default:
+			uf_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case uf_ring_channel_state_i_cn_cs_cc_dn_ks_kr_dc:
+		/* Interface disconnecting.                */
+		/* Client disconnected.                    */
+		/* No messages queued.                     */
+		/* Kick send/recv idle.                    */
+		/* Testing target rsrcs/ target rsrcs busy */
+		/* Connected.                              */
+		switch (stimulus) {
+		case uf_ring_channel_stimulus_ri:
+		case uf_ring_channel_stimulus_rc:
+			break;
+		case uf_ring_channel_stimulus_rf:
+			channel->state =
+			uf_ring_channel_state_i_cn_cs_cc_dn_ks_kr_dc_rf;
+			uf_ring_channel_do_disconnect(channel);
+			break;
+		default:
+			uf_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	case uf_ring_channel_state_i_cn_cs_cc_dn_ks_kr_dc_rf:
+		/* Interface disconnecting. */
+		/* Client disconnected.     */
+		/* No messages queued.      */
+		/* Kick send/recv idle.     */
+		/* Target rsrcs idle.       */
+		/* Disconnecting.           */
+		switch (stimulus) {
+		case uf_ring_channel_stimulus_ri:
+			break;
+		case uf_ring_channel_stimulus_ds:
+			channel->state = uf_ring_channel_state_i;
+			uf_ring_channel_complete_current_callback(
+								channel);
+			break;
+		default:
+			uf_ring_channel_invalid_stimulus(channel,
+								stimulus);
+			break;
+		}
+		break;
+	default:
+		uf_ring_channel_invalid_stimulus(channel, stimulus);
+		break;
+	}
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_ring_channel.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_ring_channel.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,114 @@
+/*****************************************************************************/
+/* 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 UF_RING_CHANNEL_H
+#define UF_RING_CHANNEL_H
+
+#include <linux/timer.h>
+#include <xen/gnttab.h>
+#include "uf_channel.h"
+
+struct uf_ring_channel;
+
+struct uf_ring_channel_rsrc {
+	struct uf_channel_ibmsg message;
+	struct uf_ring_channel *channel;
+};
+
+typedef enum {
+	uf_ring_channel_state_i,
+	uf_ring_channel_state_i_cn,
+	uf_ring_channel_state_i_cn_cs,
+	uf_ring_channel_state_i_cn_cs_cc,
+	uf_ring_channel_state_i_cn_cs_cc_dn,
+	uf_ring_channel_state_i_cn_cs_cc_dn_ks,
+	uf_ring_channel_state_i_cn_cs_cc_dn_ks_kr,
+	uf_ring_channel_state_i_cn_cs_cc_dn_ks_kr_dc,
+	uf_ring_channel_state_i_cn_cs_cc_dn_ks_kr_dc_rf
+} uf_ring_channel_state;
+
+struct uf_ring_channel {
+	struct uf_channel           channel;
+	void (*protocol_error) (struct uf_ring_channel *channel);
+	void                       *ring;
+	grant_ref_t                 grant_ref_pool;
+	spinlock_t                  lock;
+	uf_ring_channel_state       state;
+	struct list_head            message_list;
+	struct uf_work              do_connect_1_work;
+	struct uf_work              connect_client_1_work;
+	struct uf_work              disconnect_client_1_work;
+	struct uf_callback          disconnect_client_2_callback;
+	struct uf_work              do_disconnect_1_work;
+	struct uf_work              kick_send_ring_1_work;
+	struct uf_work              kick_recv_ring_1_work;
+	struct list_head            rsrc_list;
+	struct uf_ring_channel_rsrc rsrcs[USBIF_QUOTA];
+	int                         send_ring_kick_out;
+	int                         recv_ring_kick_out;
+	int                         rsrcs_out;
+	struct uf_callback         *current_callback;
+	domid_t                     domain_id;
+	struct timer_list           timer;
+	unsigned int                event_channel;
+	grant_ref_t                 ring_ref;
+	int                         irq;
+	struct usbif_front_ring     front_ring;
+};
+
+static inline struct uf_channel *
+uf_ring_channel_to_channel(struct uf_ring_channel *channel)
+{
+	return &channel->channel;
+}
+
+static inline struct uf_ring_channel *
+uf_ring_channel_channel_to(struct uf_channel *channel)
+{
+	return container_of(channel, struct uf_ring_channel, channel);
+}
+
+int uf_ring_channel_init(struct uf_ring_channel *channel,
+void (*protocol_error) (struct uf_ring_channel *channel));
+
+struct uf_ring_channel_connect_request {
+	struct uf_callback callback;
+	domid_t                  domain_id;
+	grant_ref_t              ring_ref;
+	unsigned int             event_channel;
+};
+
+static inline struct uf_ring_channel_connect_request *
+uf_ring_channel_connect_request_callback_to(
+struct uf_callback *callback)
+{
+	return container_of(callback,
+		struct uf_ring_channel_connect_request, callback);
+}
+
+void uf_ring_channel_connect(struct uf_ring_channel *channel,
+struct uf_ring_channel_connect_request *request);
+
+void
+uf_ring_channel_disconnect(struct uf_ring_channel *channel,
+struct uf_callback *callback);
+
+void uf_ring_channel_exit(struct uf_ring_channel *channel);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_rsrc.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_rsrc.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,597 @@
+/*****************************************************************************/
+/* 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/frontend/main.c, original copyright       */
+/* notice follows...                                                         */
+/*****************************************************************************/
+
+/*
+ * Xen Virtual USB Frontend Driver 
+ *
+ * This file contains the first version of the Xen virtual USB hub
+ * that I've managed not to delete by mistake (3rd time lucky!).
+ *
+ * Based on Linux's uhci.c, original copyright notices are displayed
+ * below.  Portions also (c) 2004 Intel Research Cambridge
+ * and (c) 2004, 2005 Mark Williamson
+ *
+ * Contact <mark.williamson@xxxxxxxxxxxx> or
+ * <xen-devel@xxxxxxxxxxxxxxxxxxxxx> regarding this code.
+ *
+ * Still to be (maybe) implemented:
+ * - migration / backend restart support?
+ * - support for building / using as a module
+ */
+
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Johannes Erdfelt <johannes@xxxxxxxxxxx>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx
+ * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx
+ * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ *  - the low-level protocol (fairly simple but lots of small details)
+ *  - working around the horridness of the rest
+ */
+
+#include "uf_driver.h"
+#include "uf_ep.h"
+#include "uf_rsrc.h"
+#include "uf_rbr_provider_pool.h"
+#include "uf_trace.h"
+
+struct uf_rbr_provider_pool *rbr_provider_pool;
+
+typedef enum {
+	uf_rsrc_stimulus_st, /* Start URB                               */
+	uf_rsrc_stimulus_dq, /* Dequeue URB                             */
+	uf_rsrc_stimulus_cs, /* Create RBRs success                     */
+	uf_rsrc_stimulus_cf, /* Create RBRs failure                     */
+	uf_rsrc_stimulus_tc, /* Transaction completed (success/failure) */
+	uf_rsrc_stimulus_tu, /* Transaction completed (BE unlinked)     */
+	uf_rsrc_stimulus_rc, /* Revoke RBRs complete                    */
+} uf_rsrc_stimulus;
+
+static void
+uf_rsrc_handle_stimulus(struct uf_rsrc *rsrc, uf_rsrc_stimulus stimulus);
+
+void uf_rsrc_start_urb(struct uf_rsrc *rsrc, struct urb *urb, int clear_stall)
+{
+	unsigned long flags;
+	trace();
+	urb->hcpriv = rsrc;
+	spin_lock_irqsave(&rsrc->lock, flags);
+	rsrc->urb = urb;
+	rsrc->clear_stall = clear_stall;
+	rsrc->stalled = 0;
+	uf_rsrc_handle_stimulus(rsrc, uf_rsrc_stimulus_st);
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+}
+
+void uf_rsrc_restart_urb(struct uf_rsrc *rsrc, int clear_stall)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&rsrc->lock, flags);
+	rsrc->clear_stall = clear_stall;
+	rsrc->stalled = 0;
+	uf_rsrc_handle_stimulus(rsrc, uf_rsrc_stimulus_st);
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+}
+
+static DEFINE_RWLOCK(dequeue_lock);
+
+int uf_rsrc_urb_dequeue(struct urb *urb)
+{
+	int result = 0;
+	unsigned long flags;
+	trace();
+	write_lock_irqsave(&dequeue_lock, flags);
+	if (urb->hcpriv != NULL) {
+		struct uf_rsrc *rsrc = (struct uf_rsrc *)urb->hcpriv;
+		unsigned long flags2;
+		spin_lock_irqsave(&rsrc->lock, flags2);
+		uf_rsrc_handle_stimulus(rsrc, uf_rsrc_stimulus_dq);
+		spin_unlock_irqrestore(&rsrc->lock, flags2);
+		result = -EINPROGRESS;
+	}
+	write_unlock_irqrestore(&dequeue_lock, flags);
+	return result;
+}
+
+static void
+uf_rsrc_invalid_stimulus(struct uf_rsrc *rsrc, uf_rsrc_stimulus stimulus)
+{
+	trace();
+	printk(KERN_ERR "uf: hcd rsrc %p in state %d"
+				"received invalid stimulus %d",
+				rsrc, rsrc->state, stimulus);
+}
+
+static void uf_rsrc_create_rbrs(struct uf_rsrc *rsrc)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	trace();
+	uf_create_rbr_request_element_ensure_removed(
+					&rsrc->rbr_request_element[0]);
+	uf_create_rbr_request_element_ensure_removed(
+					&rsrc->rbr_request_element[1]);
+	uf_create_rbr_request_element_set_buffer(
+			&rsrc->rbr_request_element[0],
+			rsrc->urb->transfer_buffer,
+			rsrc->urb->transfer_buffer_length,
+			usb_pipein(rsrc->urb->pipe) ?
+					UF_ACCESS_FLAGS_WRITE :
+					UF_ACCESS_FLAGS_READ);
+	uf_rbr_provider_request_add_element(&rsrc->rbr_request,
+					&rsrc->rbr_request_element[0]);
+	if (usb_pipetype(rsrc->urb->pipe) == PIPE_ISOCHRONOUS) {
+		struct usbif_isochronous_io_schedule_element *element;
+		int i;
+		if (rsrc->urb->number_of_packets > (PAGE_SIZE /
+			sizeof(struct usbif_isochronous_io_schedule_element)))
+			goto schedule_too_big;
+		element = rsrc->schedule;
+		for (i = 0; i < rsrc->urb->number_of_packets; i++) {
+			memset(&element[i], 0, sizeof(element[i]));
+			element[i].offset = rsrc->urb->iso_frame_desc[i].
+									offset;
+			element[i].length = rsrc->urb->iso_frame_desc[i].
+									length;
+		}
+		uf_create_rbr_request_element_set_buffer(
+			&rsrc->rbr_request_element[1],
+			rsrc->schedule,
+			sizeof(struct usbif_isochronous_io_schedule_element) *
+				rsrc->urb->number_of_packets,
+			UF_ACCESS_FLAGS_WRITE | UF_ACCESS_FLAGS_READ);
+		uf_rbr_provider_request_add_element(
+					&rsrc->rbr_request,
+					&rsrc->rbr_request_element[1]);
+	}
+	uf_rbr_provider_pool_reserve_and_create_rbrs(rbr_provider_pool,
+			&rsrc->rbr_request,
+			uf_device_query_domain(uf_ep_query_device(rsrc->ep)));
+	return;
+      schedule_too_big:
+	uf_callback_complete(
+		uf_rbr_provider_request_to_create_callback(
+				&rsrc->rbr_request), USBIF_ERROR_TOO_BIG);
+}
+
+static void uf_rsrc_create_rbrs_1(struct uf_callback * callback)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	struct uf_rsrc *rsrc = container_of(
+		uf_rbr_provider_request_create_callback_to(callback),
+		struct uf_rsrc, rbr_request);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&rsrc->lock, flags);
+	if (uf_callback_query_error(callback) == USBIF_ERROR_SUCCESS) {
+		uf_rsrc_handle_stimulus(rsrc, uf_rsrc_stimulus_cs);
+	} else {
+		uf_rsrc_handle_stimulus(rsrc, uf_rsrc_stimulus_cf);
+	}
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+}
+
+static void uf_rsrc_abort_create_rbrs(struct uf_rsrc *rsrc)
+{
+	trace();
+	uf_rbr_provider_pool_abort_reserve_and_create_rbrs(
+			&rsrc->rbr_request, USBIF_ERROR_UNLINKED);
+}
+
+static void uf_rsrc_set_unlinked_error(struct uf_rsrc *rsrc)
+{
+	trace();
+	uf_callback_set_error(
+		uf_rbr_provider_request_to_create_callback(
+			&rsrc->rbr_request), USBIF_ERROR_UNLINKED);
+}
+
+static void uf_rsrc_submit_tra(struct uf_rsrc *rsrc)
+{
+	/* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */
+	struct urb *urb = rsrc->urb;
+	union usbif_io_tra_parameters *parameters =
+				&rsrc->io_tra.parameters.io;
+	trace();
+	memset(parameters, 0, sizeof(*parameters));
+	parameters->header.header.tra_type = USBIF_TRA_TYPE_IO;
+	parameters->header.device_number = usb_pipedevice(urb->pipe);
+	parameters->header.endpoint = usb_pipeendpoint(urb->pipe);
+	parameters->header.direction = usb_pipein(urb->pipe) ?
+					USBIF_IO_TRA_DIRECTION_IN :
+					USBIF_IO_TRA_DIRECTION_OUT;
+	if (urb->transfer_flags & URB_SHORT_NOT_OK)
+		parameters->header.flags |= USBIF_IO_FLAGS_SHORT_NOT_OK;
+	if (urb->transfer_flags & URB_ZERO_PACKET)
+		parameters->header.flags |= USBIF_IO_FLAGS_ZERO_PACKET;
+	if (rsrc->clear_stall)
+		parameters->header.flags |= USBIF_IO_FLAGS_CLEAR_STALL;
+	parameters->header.rbr = uf_create_rbr_request_element_query_rbr(
+					&rsrc->rbr_request_element[0]);
+	if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+		parameters->header.io_tra_type = USBIF_IO_TRA_TYPE_CONTROL;
+		memcpy(parameters->control.setup,urb->setup_packet, 8);
+	} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+		parameters->header.io_tra_type = USBIF_IO_TRA_TYPE_BULK;
+	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+		parameters->header.io_tra_type = USBIF_IO_TRA_TYPE_INTERRUPT;
+		parameters->interrupt.interval = urb->interval;
+	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+		parameters->header.io_tra_type = USBIF_IO_TRA_TYPE_ISOCHRONOUS;
+		parameters->isochronous.interval = urb->interval;
+		parameters->isochronous.schedule_rbr =
+				uf_create_rbr_request_element_query_rbr(
+					&rsrc->rbr_request_element[1]);
+		parameters->isochronous.packet_count = urb->number_of_packets;
+	}
+
+	uf_device_submit_tra(uf_ep_query_device(rsrc->ep), &rsrc->io_tra);
+}
+
+static void uf_rsrc_submit_tra_1(struct uf_callback *callback)
+{
+	struct uf_rsrc *rsrc = container_of(
+			uf_gw_tra_callback_to(callback),
+			struct uf_rsrc, io_tra);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&rsrc->lock, flags);
+	if (uf_callback_query_error(callback) != USBIF_ERROR_UNLINKED)
+		uf_rsrc_handle_stimulus(rsrc, uf_rsrc_stimulus_tc);
+	else
+		uf_rsrc_handle_stimulus(rsrc, uf_rsrc_stimulus_tu);
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+}
+
+static void uf_rsrc_revoke_rbrs(struct uf_rsrc *rsrc)
+{
+	trace();
+	uf_rbr_provider_pool_revoke_and_unreserve_rbrs(&rsrc->rbr_request);
+}
+
+static void uf_rsrc_revoke_rbrs_1(struct uf_callback *callback)
+{
+	struct uf_rsrc *rsrc = container_of(
+		uf_rbr_provider_request_revoke_callback_to(callback),
+		struct uf_rsrc, rbr_request);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&rsrc->lock, flags);
+	uf_rsrc_handle_stimulus(rsrc, uf_rsrc_stimulus_rc);
+	spin_unlock_irqrestore(&rsrc->lock, flags);
+}
+
+static void uf_rsrc_complete(struct uf_rsrc *rsrc)
+{
+	trace();
+	/* Upcall so schedule work to drop the lock to avoid deadlock. */
+	(void)uf_work_schedule(&rsrc->complete_1_work);
+}
+
+static void uf_rsrc_complete_1(void *context)
+{
+	struct uf_rsrc *rsrc = context;
+	struct urb *urb = rsrc->urb;
+	usbif_error error;
+	unsigned long flags;
+	trace();
+	read_lock_irqsave(&dequeue_lock, flags);
+	urb->hcpriv = 0;
+	read_unlock_irqrestore(&dequeue_lock, flags);
+	if (((error = uf_callback_query_error(
+		uf_rbr_provider_request_to_create_callback(
+		&rsrc->rbr_request))) == USBIF_ERROR_SUCCESS) && ((error =
+		uf_callback_query_error(
+		uf_rbr_provider_request_to_revoke_callback(
+		&rsrc->rbr_request))) == USBIF_ERROR_SUCCESS)) {
+		urb->status = usbif_error_map_to_local(
+			uf_gw_tra_query_error(&rsrc->io_tra));
+		urb->actual_length = rsrc->io_tra.status.io.length;
+		if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+			int i;
+			urb->error_count = 0;
+			for (i = 0; i < urb->number_of_packets; i++) {
+				struct usbif_isochronous_io_schedule_element
+					*schedule = &rsrc->schedule[i];
+				urb->iso_frame_desc[i].actual_length =
+							schedule->length;
+				urb->iso_frame_desc[i].status =
+					usbif_error_map_to_local(schedule->
+								     error);
+				if (urb->iso_frame_desc[i].status != 0)
+					urb->error_count++;
+			}
+		}
+	} else {
+		urb->status = usbif_error_map_to_local(error);
+		urb->actual_length = 0;
+	}
+	local_irq_save(flags);
+	usb_hcd_giveback_urb(
+			uf_device_get_drvdata(uf_ep_query_device(rsrc->ep)),
+			urb, NULL);
+	local_irq_restore(flags);
+	/* uf_ep uses the rsrc callback error value to get the busy count    */
+	/* right.                                                            */
+	/* There are 3 cases to consider for the error value:                */
+	/* 1) Normal completion success or failure: use !UNLINKED.           */
+	/* 2) Unlinked without intermediate stall:  use UNLINKED.            */
+	/* 3) Unlinked after intermediate stall:    use !UNLINKED.           */
+	/*                                                                   */
+	/* In 1 and 3, ep needs to decrement the busy count by 1 on          */
+	/* completion (in case 1 because there is only the rsrc outstanding  */
+	/* and in case 3 because there is only a dequeue outstanding, the    */
+	/* rsrc having previously completed with the stall upcall).          */
+	/* In case 2, the ep needs to decrement the busy count by 2 since    */
+	/* both the rsrc and the unlink are outstanding. This corresponds to */
+	/* an unlink where the URB happened to fail anyway.                  */
+	if(rsrc->stalled)
+		error = USBIF_ERROR_SUCCESS;
+	uf_callback_complete(&rsrc->callback, error);
+}
+
+static void uf_rsrc_stall(struct uf_rsrc *rsrc)
+{
+	trace();
+	rsrc->stalled = 1;
+	/* Upcall so schedule work to drop the lock to avoid deadlock. */
+	(void)uf_work_schedule(&rsrc->stall_1_work);
+}
+
+static void uf_rsrc_stall_1(void *context)
+{
+	struct uf_rsrc *rsrc = context;
+	trace();
+	uf_ep_rsrc_stalled(rsrc->ep);
+}
+
+static void
+uf_rsrc_handle_stimulus(struct uf_rsrc *rsrc, uf_rsrc_stimulus stimulus)
+{
+	trace();
+	switch (rsrc->state) {
+	case uf_rsrc_state_i:
+		/* Initialised.                   */
+		/* Maybe completing previous URB. */
+		switch (stimulus) {
+		case uf_rsrc_stimulus_st:
+			rsrc->state = uf_rsrc_state_i_st;
+			uf_rsrc_create_rbrs(rsrc);
+			break;
+			/* A dequeue is possible whilst we are making the    */
+			/* complete response after we have transitioned back */
+			/* to the i state.                                   */
+		case uf_rsrc_stimulus_dq:
+			uf_rsrc_set_unlinked_error(rsrc);
+			break;
+		default:
+			uf_rsrc_invalid_stimulus(rsrc, stimulus);
+			break;
+		}
+		break;
+	case uf_rsrc_state_i_st:
+		/* Creating RBRs. */
+		switch (stimulus) {
+		case uf_rsrc_stimulus_dq:
+			rsrc->state = uf_rsrc_state_i_st_dq;
+			uf_rsrc_abort_create_rbrs(rsrc);
+			break;
+		case uf_rsrc_stimulus_cs:
+			rsrc->state = uf_rsrc_state_i_st_cs;
+			uf_rsrc_submit_tra(rsrc);
+			break;
+		case uf_rsrc_stimulus_cf:
+			rsrc->state = uf_rsrc_state_i;
+			uf_rsrc_complete(rsrc);
+			break;
+		default:
+			uf_rsrc_invalid_stimulus(rsrc, stimulus);
+			break;
+		}
+		break;
+	case uf_rsrc_state_i_st_dq:
+		/* Creating RBRs. */
+		/* Dequeue URB.   */
+		switch (stimulus) {
+		case uf_rsrc_stimulus_cs:
+			rsrc->state = uf_rsrc_state_i_st_dq_cs;
+			uf_rsrc_set_unlinked_error(rsrc);
+			uf_rsrc_revoke_rbrs(rsrc);
+			break;
+		case uf_rsrc_stimulus_cf:
+			rsrc->state = uf_rsrc_state_i;
+			uf_rsrc_set_unlinked_error(rsrc);
+			uf_rsrc_complete(rsrc);
+			break;
+		default:
+			uf_rsrc_invalid_stimulus(rsrc, stimulus);
+			break;
+		}
+		break;
+	case uf_rsrc_state_i_st_cs:
+		/* Transaction submitted. */
+		switch (stimulus) {
+		case uf_rsrc_stimulus_dq:
+			rsrc->state = uf_rsrc_state_i_st_cs_dq;
+			uf_rsrc_set_unlinked_error(rsrc);
+			break;
+		case uf_rsrc_stimulus_tc:
+			rsrc->state = uf_rsrc_state_i_st_dq_cs;
+			uf_rsrc_revoke_rbrs(rsrc);
+			break;
+		case uf_rsrc_stimulus_tu:
+			rsrc->state = uf_rsrc_state_i_st_cs_tu;
+			uf_rsrc_revoke_rbrs(rsrc);
+			break;
+		default:
+			uf_rsrc_invalid_stimulus(rsrc, stimulus);
+			break;
+		}
+		break;
+	case uf_rsrc_state_i_st_dq_cs:
+		/* Revoking RBRs.                  */
+		/* Dequeue URB/URB success/failure */
+		switch (stimulus) {
+		case uf_rsrc_stimulus_dq:
+			uf_rsrc_set_unlinked_error(rsrc);
+			break;
+		case uf_rsrc_stimulus_rc:
+			rsrc->state = uf_rsrc_state_i;
+			uf_rsrc_complete(rsrc);
+			break;
+		default:
+			uf_rsrc_invalid_stimulus(rsrc, stimulus);
+			break;
+		}
+		break;
+	case uf_rsrc_state_i_st_cs_dq:
+		/* Transaction submitted */
+		/* Dequeue URB.          */
+		switch (stimulus) {
+		case uf_rsrc_stimulus_tc:
+		case uf_rsrc_stimulus_tu:
+			rsrc->state = uf_rsrc_state_i_st_dq_cs;
+			uf_rsrc_revoke_rbrs(rsrc);
+			break;
+		default:
+			uf_rsrc_invalid_stimulus(rsrc, stimulus);
+			break;
+		}
+		break;
+	case uf_rsrc_state_i_st_cs_tu:
+		/* Revoking RBRs.  */
+		/* BE unlinked tra */
+		switch (stimulus) {
+		case uf_rsrc_stimulus_dq:
+			rsrc->state = uf_rsrc_state_i_st_dq_cs;
+			uf_rsrc_set_unlinked_error(rsrc);
+			break;
+		case uf_rsrc_stimulus_rc:
+			rsrc->state = uf_rsrc_state_i_st_cs_tu_rc;
+			uf_rsrc_stall(rsrc);
+			break;
+		default:
+			uf_rsrc_invalid_stimulus(rsrc, stimulus);
+			break;
+		}
+		break;
+	case uf_rsrc_state_i_st_cs_tu_rc:
+		/* Stalled. */
+		switch (stimulus) {
+		case uf_rsrc_stimulus_st:
+			rsrc->state = uf_rsrc_state_i_st;
+			uf_rsrc_create_rbrs(rsrc);
+			break;
+		case uf_rsrc_stimulus_dq:
+			rsrc->state = uf_rsrc_state_i;
+			uf_rsrc_set_unlinked_error(rsrc);
+			uf_rsrc_complete(rsrc);
+			break;
+		default:
+			uf_rsrc_invalid_stimulus(rsrc, stimulus);
+			break;
+		}
+		break;
+	default:
+		uf_rsrc_invalid_stimulus(rsrc, stimulus);
+		break;
+	}
+}
+
+static int uf_rsrc_init_or_exit(struct uf_rsrc *rsrc, struct uf_ep *ep,
+uf_callback_function *callback, int exit)
+{
+	int return_value = 0;
+	trace();
+	if (exit)
+		goto exit_path;
+	INIT_LIST_HEAD(&rsrc->link);
+	uf_callback_init(&rsrc->callback, callback);
+	rsrc->ep = ep;
+	rsrc->schedule = (struct usbif_isochronous_io_schedule_element *)
+						__get_free_page(GFP_KERNEL);
+	if (rsrc->schedule == NULL) {
+		return_value = -ENOMEM;
+		goto exit_no_schedule;
+	}
+	spin_lock_init(&rsrc->lock);
+	rsrc->state = uf_rsrc_state_i;
+	uf_create_rbr_request_element_init(&rsrc->rbr_request_element[0]);
+	uf_create_rbr_request_element_init(&rsrc->rbr_request_element[1]);
+	uf_rbr_provider_request_init(&rsrc->rbr_request,
+					uf_rsrc_create_rbrs_1,
+					uf_rsrc_revoke_rbrs_1);
+	uf_gw_tra_init(&rsrc->io_tra, uf_rsrc_submit_tra_1);
+	uf_work_init(&rsrc->complete_1_work, uf_rsrc_complete_1, rsrc);
+	uf_work_init(&rsrc->stall_1_work, uf_rsrc_stall_1, rsrc);
+	return 0;
+ exit_path:
+	free_page((unsigned long)rsrc->schedule);
+ exit_no_schedule:
+	return return_value;
+}
+
+int uf_rsrc_init(struct uf_rsrc *rsrc, struct uf_ep *ep,
+uf_callback_function *callback)
+{
+	trace();
+	return uf_rsrc_init_or_exit(rsrc, ep, callback, 0);
+}
+
+void uf_rsrc_exit(struct uf_rsrc *rsrc)
+{
+	trace();
+	uf_rsrc_init_or_exit(rsrc, NULL, NULL, 1);
+}
+
+int uf_rsrc_class_init(void)
+{
+	trace();
+	rbr_provider_pool = uf_rbr_provider_pool_allocate();
+	return (rbr_provider_pool != NULL) ? 0 : -ENOMEM;
+}
+
+void uf_rsrc_class_exit(void)
+{
+	trace();
+	uf_rbr_provider_pool_free(rbr_provider_pool);
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_rsrc.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_rsrc.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,81 @@
+/*****************************************************************************/
+/* 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 UF_RSRC_H
+#define UF_RSRC_H
+
+#include <linux/usb.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include "uf_device.h"
+#include "uf_rbr_provider_pool.h"
+
+typedef enum {
+	uf_rsrc_state_i,
+	uf_rsrc_state_i_st,
+	uf_rsrc_state_i_st_dq,
+	uf_rsrc_state_i_st_cs,
+	uf_rsrc_state_i_st_dq_cs,
+	uf_rsrc_state_i_st_cs_dq,
+	uf_rsrc_state_i_st_cs_tu,
+	uf_rsrc_state_i_st_cs_tu_rc
+} uf_rsrc_state;
+
+struct uf_rsrc {
+	struct list_head                              link;
+	struct uf_callback                            callback;
+	struct uf_ep                                 *ep;
+	struct usbif_isochronous_io_schedule_element *schedule;
+	spinlock_t                                    lock;
+	uf_rsrc_state                                 state;
+	struct urb                                   *urb;
+	int                                           clear_stall;
+	int                                           stalled;
+	struct uf_create_rbr_request_element          rbr_request_element[2];
+	struct uf_rbr_provider_request                rbr_request;
+	struct uf_gw_tra                              io_tra;
+	struct uf_work                                complete_1_work;
+	struct uf_work                                stall_1_work;
+};
+
+static inline struct list_head *uf_rsrc_to_link(struct uf_rsrc *rsrc)
+{
+	return &rsrc->link;
+}
+
+static inline struct uf_rsrc *uf_rsrc_callback_to(struct uf_callback *callback)
+{
+	return container_of(callback, struct uf_rsrc, callback);
+}
+
+static inline struct uf_ep *uf_rsrc_query_ep(struct uf_rsrc *rsrc)
+{
+	return rsrc->ep;
+}
+
+void uf_rsrc_start_urb(struct uf_rsrc *rsrc, struct urb *urb, int clear_stall);
+void uf_rsrc_restart_urb(struct uf_rsrc *rsrc, int clear_stall);
+int uf_rsrc_urb_dequeue(struct urb *urb);
+int uf_rsrc_init(struct uf_rsrc *rsrc, struct uf_ep *ep,
+uf_callback_function *callback);
+void uf_rsrc_exit(struct uf_rsrc *rsrc);
+int uf_rsrc_class_init(void);
+void uf_rsrc_class_exit(void);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_sll.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_sll.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,97 @@
+/*****************************************************************************/
+/* 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 UF_SLL_H
+#define UF_SLL_H
+
+struct uf_slk {
+	struct uf_slk *next;
+};
+
+struct uf_sll {
+	struct uf_slk *first;
+	struct uf_slk *last;
+};
+
+static inline void uf_slk_init(struct uf_slk *slk)
+{
+	slk->next = slk;
+}
+
+static inline int uf_slk_is_singular(struct uf_slk *slk)
+{
+	return (slk->next == slk);
+}
+
+static inline void uf_sll_init(struct uf_sll *sll)
+{
+	sll->first = 0;
+}
+
+static inline int uf_sll_is_empty(struct uf_sll *sll)
+{
+	return (sll->first == 0);
+}
+
+static inline void uf_sll_add_last(struct uf_sll *sll, struct uf_slk *slk)
+{
+	slk->next = 0;
+	if (sll->first != 0) {
+		sll->last->next = slk;
+	} else {
+		sll->first = slk;
+	}
+	sll->last = slk;
+}
+
+static inline struct uf_slk *uf_sll_remove_first(struct uf_sll *sll)
+{
+	struct uf_slk *slk = sll->first;
+	if (slk != 0) {
+		sll->first = slk->next;
+		slk->next = slk;
+	}
+	return slk;
+}
+
+static inline int uf_sll_remove_slk(struct uf_sll *sll, struct uf_slk *slk)
+{
+	struct uf_slk *prev_slk = NULL;
+	struct uf_slk *next_slk = sll->first;
+	while (next_slk != NULL) {
+		if (next_slk != slk) {
+			prev_slk = next_slk;
+			next_slk = next_slk->next;
+		} else {
+			next_slk = next_slk->next;
+			if (prev_slk != NULL) {
+				prev_slk->next = next_slk;
+			} else {
+				sll->first = next_slk;
+			}
+			if (next_slk == NULL)
+				sll->last = prev_slk;
+			slk->next = slk;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_trace.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_trace.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,36 @@
+/*****************************************************************************/
+/* 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 UF_TRACE_H
+#define UF_TRACE_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_XEN_USBDEV_FRONTEND_TRACE
+
+#define trace_info(format, ...) \
+printk(KERN_INFO "uf %s: " format "\n", __FUNCTION__, ## __VA_ARGS__)
+#define trace() trace_info("")
+#else
+#define trace_info(format, ...)
+#define trace()
+#endif
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_work.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_work.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,73 @@
+/*****************************************************************************/
+/* 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 "uf_work.h"
+
+static void uf_work_function(void *ignored);
+
+DEFINE_SPINLOCK(uf_work_list_lock);
+LIST_HEAD(uf_work_list);
+DECLARE_WORK(uf_work_work, uf_work_function, NULL);
+DECLARE_WAIT_QUEUE_HEAD(uf_work_waitqueue);
+LIST_HEAD(uf_work_condition);
+
+void uf_work_wake_up(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&uf_work_list_lock, flags);
+	while (!list_empty(&uf_work_condition))
+		list_del_init(uf_work_condition.next);
+	spin_unlock_irqrestore(&uf_work_list_lock, flags);
+	wake_up(&uf_work_waitqueue);
+}
+
+int uf_work_schedule(struct uf_work *work)
+{
+	int scheduled = 0;
+	unsigned long flags;
+	spin_lock_irqsave(&uf_work_list_lock, flags);
+	if (list_empty(&work->link)) {
+		list_add_tail(&work->link, &uf_work_list);
+		scheduled = 1;
+	}
+	spin_unlock_irqrestore(&uf_work_list_lock, flags);
+	if (scheduled) {
+		uf_work_wake_up();
+		schedule_work(&uf_work_work);
+	}
+	return scheduled;
+}
+
+static void uf_work_function(void *ignored)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&uf_work_list_lock, flags);
+	while (!list_empty(&uf_work_list)) {
+		struct uf_work *work = list_entry(
+						uf_work_list.next,
+						struct uf_work,
+						link);
+		list_del_init(&work->link);
+		spin_unlock_irqrestore(&uf_work_list_lock, flags);
+		uf_work_perform_synchronously(work);
+		spin_lock_irqsave(&uf_work_list_lock, flags);
+	}
+	spin_unlock_irqrestore(&uf_work_list_lock, flags);
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_work.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_work.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,105 @@
+/*****************************************************************************/
+/* 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 UF_WORK_H
+#define UF_WORK_H
+
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+struct uf_work {
+	struct list_head link;
+	void (*function) (void *context);
+	void *context;
+};
+
+#define UF_WORK_INIT( name, fn, ctx ) \
+{ .link = LIST_HEAD_INIT( name.link ), .function = fn, .context = ctx }
+
+#define UF_WORK( name, fn, ctx ) \
+struct uf_work name = UF_WORK_INIT( name, fn, ctx )
+
+static inline void
+uf_work_init(struct uf_work *work, void (*function)(void *context),
+void *context)
+{
+	INIT_LIST_HEAD(&work->link);
+	work->function = function;
+	work->context = context;
+}
+
+static inline
+struct list_head *uf_work_to_link(struct uf_work *work)
+{
+	return &work->link;
+}
+
+static inline struct uf_work *
+uf_work_link_to(struct list_head *link)
+{
+	return container_of(link, struct uf_work, link);
+}
+
+int uf_work_schedule(struct uf_work *work);
+
+static inline void
+uf_work_perform_synchronously(struct uf_work *work)
+{
+	work->function(work->context);
+}
+
+extern spinlock_t        uf_work_list_lock;
+extern struct list_head  uf_work_list;
+extern wait_queue_head_t uf_work_waitqueue;
+extern struct list_head  uf_work_condition;
+
+#define uf_work_until( condition )				      \
+do {									      \
+	unsigned long flags;						      \
+	spin_lock_irqsave(&uf_work_list_lock, flags);		      \
+	for (;;) {							      \
+		struct list_head link;					      \
+		while (!list_empty(&uf_work_list) && !(condition)) {    \
+			struct uf_work *work;			      \
+			work = list_entry(uf_work_list.next,	      \
+						 struct uf_work, link); \
+			list_del_init(&work->link);			      \
+			spin_unlock_irqrestore(&uf_work_list_lock,      \
+								flags);       \
+			uf_work_perform_synchronously(work);	      \
+			spin_lock_irqsave(&uf_work_list_lock, flags);   \
+		}							      \
+		if (condition)						      \
+			break;						      \
+		INIT_LIST_HEAD(&link);					      \
+		list_add_tail(&link, &uf_work_condition);		      \
+		spin_unlock_irqrestore(&uf_work_list_lock, flags);      \
+		wait_event(uf_work_waitqueue, list_empty(&link));	      \
+		spin_lock_irqsave(&uf_work_list_lock, flags);	      \
+	}								      \
+	spin_unlock_irqrestore(&uf_work_list_lock, flags);	      \
+}									      \
+while (0)
+
+void uf_work_wake_up(void);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_xb_channel.c
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_xb_channel.c	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,399 @@
+/*****************************************************************************/
+/* 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/err.h>
+#include "uf_xb_channel.h"
+#include "uf_trace.h"
+
+typedef enum {
+	uf_xb_channel_stimulus_cn,
+	uf_xb_channel_stimulus_dn,
+	uf_xb_channel_stimulus_bc,
+	uf_xb_channel_stimulus_pe,
+	uf_xb_channel_stimulus_rs,
+	uf_xb_channel_stimulus_rf
+} uf_xb_channel_stimulus;
+
+static void uf_xb_channel_handle_stimulus(struct uf_xb_channel *channel,
+uf_xb_channel_stimulus stimulus);
+
+void uf_xb_channel_connect(struct uf_xb_channel *channel,
+struct xenbus_device *device)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	channel->device = device;
+	uf_xb_channel_handle_stimulus(channel, uf_xb_channel_stimulus_cn);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+void uf_xb_channel_backend_closing(struct uf_xb_channel *channel,
+struct xenbus_device *dev)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	uf_xb_channel_handle_stimulus(channel, uf_xb_channel_stimulus_bc);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+void uf_xb_channel_backend_changed(struct uf_xb_channel *channel,
+struct xenbus_device *dev, XenbusState state)
+{
+	trace();
+
+	switch(state) {
+	case XenbusStateUnknown:
+		trace_info( "XenbusStateUnknown" );
+		break;
+	case XenbusStateInitialising:
+		trace_info( "XenbusStateInitialising" );
+		break;
+	case XenbusStateInitWait:
+		trace_info( "XenbusStateInitWait" );
+		break;
+	case XenbusStateInitialised:
+		trace_info( "XenbusStateInitialised" );
+		break;
+	case XenbusStateConnected:
+		trace_info( "XenbusStateConnected" );
+		break;
+	case XenbusStateClosing:
+		trace_info( "XenbusStateClosing" );
+		break;
+	case XenbusStateClosed:
+		trace_info( "XenbusStateClosed" );
+		break;
+	}
+
+	switch(state) {
+	case XenbusStateClosing:
+		uf_xb_channel_backend_closing(channel, dev);
+		break;
+	default:
+		break;
+	}
+}
+
+static void uf_xb_channel_protocol_error(struct uf_ring_channel *ring_channel)
+{
+	struct uf_xb_channel *channel =
+			uf_xb_channel_ring_channel_to(ring_channel);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	uf_xb_channel_handle_stimulus(channel, uf_xb_channel_stimulus_pe);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+void uf_xb_channel_disconnect(struct uf_xb_channel *channel)
+{
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	channel->disconnected = 0;
+	uf_xb_channel_handle_stimulus(channel, uf_xb_channel_stimulus_dn);
+	spin_unlock_irqrestore(&channel->lock, flags);
+	uf_work_until(channel->disconnected);
+}
+
+static void uf_xb_channel_invalid_stimulus(struct uf_xb_channel *channel,
+uf_xb_channel_stimulus stimulus)
+{
+	trace();
+	printk(KERN_ERR "uf: xb channel %p in state %d"
+		" received invalid stimulus %d", channel, channel->state,
+								stimulus);
+}
+
+static void uf_xb_channel_connect_ring(struct uf_xb_channel *channel)
+{
+	trace();
+	channel->ring_connect.domain_id = channel->device->otherend_id;
+	uf_ring_channel_connect(&channel->channel, &channel->ring_connect);
+}
+
+static void uf_xb_channel_connect_ring_1(struct uf_callback *callback)
+{
+	struct uf_xb_channel *channel = container_of(
+		uf_ring_channel_connect_request_callback_to(callback),
+		struct uf_xb_channel, ring_connect);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	uf_xb_channel_handle_stimulus(channel, uf_xb_channel_stimulus_rs);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void uf_xb_channel_publish_details(struct uf_xb_channel *channel)
+{
+	trace();
+	uf_work_schedule(&channel->publish_details_1_work);
+}
+
+static void uf_xb_channel_publish_details_1(void *data)
+{
+	struct uf_xb_channel *channel = data;
+	struct xenbus_transaction transaction;
+	int error;
+	unsigned long flags;
+	trace();
+	trace_info("%s", channel->device->nodename);
+ again:
+	error = xenbus_transaction_start(&transaction);
+	if (error) {
+		trace_info("error starting transaction");
+		goto transaction_error;
+	}
+	error = xenbus_printf(transaction, channel->device->nodename,
+				"ring-ref", "%u",
+				channel->ring_connect.ring_ref);
+	if (error) {
+		trace_info("error writing ring-ref to store");
+		goto abort_transaction;
+	}
+	error = xenbus_printf(transaction, channel->device->nodename,
+				"event-channel", "%u",
+				channel->ring_connect.event_channel);
+	if (error) {
+		trace_info("error writing event-channel to store");
+		goto abort_transaction;
+	}
+	error = xenbus_transaction_end(transaction, 0);
+	if (error) {
+		if (error == -EAGAIN) {
+			goto again;
+		} else {
+			trace_info("error committing transaction");
+			goto transaction_error;
+		}
+	}
+	xenbus_switch_state(channel->device, XenbusStateConnected);
+	spin_lock_irqsave(&channel->lock, flags);
+	uf_xb_channel_handle_stimulus(channel,
+					uf_xb_channel_stimulus_rs);
+	spin_unlock_irqrestore(&channel->lock, flags);
+	return;
+ abort_transaction:
+	xenbus_transaction_end(transaction, 1);
+ transaction_error:
+	spin_lock_irqsave(&channel->lock, flags);
+	uf_xb_channel_handle_stimulus(channel,
+					uf_xb_channel_stimulus_rf);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void uf_xb_channel_disconnect_ring(struct uf_xb_channel *channel)
+{
+	trace();
+	uf_ring_channel_disconnect(&channel->channel,
+						&channel->ring_disconnect);
+}
+
+static void uf_xb_channel_disconnect_ring_1(struct uf_callback *callback)
+{
+	struct uf_xb_channel *channel = container_of(callback,
+		struct uf_xb_channel, ring_disconnect);
+	unsigned long flags;
+	trace();
+	spin_lock_irqsave(&channel->lock, flags);
+	uf_xb_channel_handle_stimulus(channel, uf_xb_channel_stimulus_rs);
+	spin_unlock_irqrestore(&channel->lock, flags);
+}
+
+static void uf_xb_channel_complete_disconnect(struct uf_xb_channel *channel)
+{
+	trace();
+	channel->disconnected = 1;
+	uf_work_wake_up();
+}
+
+static int uf_xb_channel_init_or_exit(struct uf_xb_channel *channel, int exit)
+{
+	int return_value = 0;
+	trace();
+	if (exit)
+		goto exit_path;
+	if ((return_value = uf_ring_channel_init(&channel->channel,
+				uf_xb_channel_protocol_error)) != 0) {
+		goto exit_no_ring_channel;
+	}
+	spin_lock_init(&channel->lock);
+	channel->state = uf_xb_channel_state_i;
+	uf_callback_init(&channel->ring_connect.callback,
+					uf_xb_channel_connect_ring_1);
+	uf_work_init(&channel->publish_details_1_work,
+					uf_xb_channel_publish_details_1,
+					channel);
+	uf_callback_init(&channel->ring_disconnect,
+					uf_xb_channel_disconnect_ring_1);
+	return 0;
+ exit_path:
+	uf_ring_channel_exit(&channel->channel);
+ exit_no_ring_channel:
+	return return_value;
+}
+
+int uf_xb_channel_init(struct uf_xb_channel *channel)
+{
+	return uf_xb_channel_init_or_exit(channel, 0);
+}
+
+void uf_xb_channel_exit(struct uf_xb_channel *channel)
+{
+	trace();
+	(void)uf_xb_channel_init_or_exit(channel, 1);
+}
+
+static void uf_xb_channel_handle_stimulus(struct uf_xb_channel *channel,
+uf_xb_channel_stimulus stimulus) {
+	trace_info("xb channel %p in state %d received stimulus %d", channel,
+						channel->state, stimulus);
+	switch (channel->state) {
+	case uf_xb_channel_state_i:
+		switch (stimulus) {
+		case uf_xb_channel_stimulus_cn:
+			channel->state = uf_xb_channel_state_i_cn;
+			uf_xb_channel_connect_ring(channel);
+			break;
+		default:
+			uf_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	case uf_xb_channel_state_i_cn:
+		switch (stimulus) {
+		case uf_xb_channel_stimulus_dn:
+			channel->state = uf_xb_channel_state_i_cn_dn;
+			break;
+		case uf_xb_channel_stimulus_rs:
+			channel->state = uf_xb_channel_state_i_cn_rs;
+			uf_xb_channel_publish_details(channel);
+			break;
+		default:
+			uf_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	case uf_xb_channel_state_i_cn_dn:
+		switch (stimulus) {
+		case uf_xb_channel_stimulus_rs:
+			channel->state = uf_xb_channel_state_i_cn_dn_rs;
+			uf_xb_channel_disconnect_ring(channel);
+			break;
+		default:
+			uf_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	case uf_xb_channel_state_i_cn_rs:
+		switch (stimulus) {
+		case uf_xb_channel_stimulus_dn:
+			channel->state = uf_xb_channel_state_i_cn_rs_dn;
+			break;
+		case uf_xb_channel_stimulus_rs:
+			channel->state = uf_xb_channel_state_i_cn_rs_rs;
+			break;
+		case uf_xb_channel_stimulus_rf:
+			channel->state = uf_xb_channel_state_i_cn_rs_rf;
+			break;
+		default:
+			uf_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	case uf_xb_channel_state_i_cn_dn_rs:
+		switch (stimulus) {
+		case uf_xb_channel_stimulus_rs:
+			channel->state = uf_xb_channel_state_i;
+			uf_xb_channel_complete_disconnect(channel);
+			break;
+		default:
+			uf_xb_channel_invalid_stimulus(channel,	stimulus);
+			break;
+		}
+		break;
+	case uf_xb_channel_state_i_cn_rs_dn:
+		switch (stimulus) {
+		case uf_xb_channel_stimulus_rs:
+		case uf_xb_channel_stimulus_rf:
+			uf_xb_channel_disconnect_ring(channel);
+			channel->state = uf_xb_channel_state_i_cn_dn_rs;
+			break;
+		default:
+			uf_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	case uf_xb_channel_state_i_cn_rs_rs:
+		switch (stimulus) {
+		case uf_xb_channel_stimulus_dn:
+			uf_xb_channel_disconnect_ring(channel);
+			channel->state = uf_xb_channel_state_i_cn_dn_rs;
+			break;
+		case uf_xb_channel_stimulus_bc:
+			channel->state = uf_xb_channel_state_i_cn_rs_rs_bc;
+			uf_xb_channel_disconnect_ring(channel);
+			break;
+		default:
+			uf_xb_channel_invalid_stimulus(channel,	stimulus);
+			break;
+		}
+		break;
+	case uf_xb_channel_state_i_cn_rs_rf:
+		switch (stimulus) {
+		case uf_xb_channel_stimulus_dn:
+			uf_xb_channel_disconnect_ring(channel);
+			channel->state = uf_xb_channel_state_i_cn_dn_rs;
+			break;
+		default:
+			uf_xb_channel_invalid_stimulus(channel, stimulus);
+			break;
+		}
+		break;
+	case uf_xb_channel_state_i_cn_rs_rs_bc:
+		switch (stimulus) {
+		case uf_xb_channel_stimulus_dn:
+			channel->state = uf_xb_channel_state_i_cn_dn_rs;
+			break;
+		case uf_xb_channel_stimulus_rs:
+			channel->state = uf_xb_channel_state_i_cn_rs_rs_bc_rs;
+			break;
+		default:
+			uf_xb_channel_invalid_stimulus(channel,	stimulus);
+			break;
+		}
+		break;
+	case uf_xb_channel_state_i_cn_rs_rs_bc_rs:
+		switch (stimulus) {
+		case uf_xb_channel_stimulus_dn:
+			channel->state = uf_xb_channel_state_i;
+			uf_xb_channel_complete_disconnect(channel);
+			break;
+		default:
+			uf_xb_channel_invalid_stimulus(channel,	stimulus);
+			break;
+		}
+		break;
+	default:
+		uf_xb_channel_invalid_stimulus(channel, stimulus);
+		break;
+	}
+}
diff -r f426f6e646eb -r 404b4ec94253 linux-2.6-xen-sparse/drivers/xen/usbfront/uf_xb_channel.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/uf_xb_channel.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,77 @@
+/*****************************************************************************/
+/* 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 UF_XB_CHANNEL_H
+#define UF_XB_CHANNEL_H
+
+#include <xen/xenbus.h>
+#include "uf_ring_channel.h"
+
+typedef enum {
+	uf_xb_channel_state_i,
+	uf_xb_channel_state_i_cn,
+	uf_xb_channel_state_i_cn_dn,
+	uf_xb_channel_state_i_cn_rs,
+	uf_xb_channel_state_i_cn_dn_rs,
+	uf_xb_channel_state_i_cn_rs_dn,
+	uf_xb_channel_state_i_cn_rs_rs,
+	uf_xb_channel_state_i_cn_rs_rf,
+	uf_xb_channel_state_i_cn_rs_rs_bc,
+	uf_xb_channel_state_i_cn_rs_rs_bc_rs
+} uf_xb_channel_state;
+
+struct uf_xb_channel {
+	struct uf_ring_channel                 channel;
+	spinlock_t                             lock;
+	uf_xb_channel_state                    state;
+	struct xenbus_device                  *device;
+	struct uf_ring_channel_connect_request ring_connect;
+	struct uf_work                         publish_details_1_work;
+	struct uf_callback                     ring_disconnect;
+	int                                    disconnected;
+};
+
+static inline struct uf_channel *
+uf_xb_channel_to_channel(struct uf_xb_channel *channel)
+{
+	return uf_ring_channel_to_channel(&channel->channel);
+}
+
+static inline struct uf_xb_channel *
+uf_xb_channel_ring_channel_to(struct uf_ring_channel *ring_channel)
+{
+	return container_of(ring_channel, struct uf_xb_channel, channel);
+}
+
+static inline struct uf_xb_channel *
+uf_xb_channel_channel_to(struct uf_channel *channel)
+{
+	return uf_xb_channel_ring_channel_to(
+				uf_ring_channel_channel_to(channel));
+}
+
+void uf_xb_channel_connect(struct uf_xb_channel *channel,
+struct xenbus_device *device);
+void uf_xb_channel_backend_changed(struct uf_xb_channel *channel,
+struct xenbus_device *dev, XenbusState state);
+void uf_xb_channel_disconnect(struct uf_xb_channel *channel);
+int uf_xb_channel_init(struct uf_xb_channel *channel);
+void uf_xb_channel_exit(struct uf_xb_channel *channel);
+
+#endif
diff -r f426f6e646eb -r 404b4ec94253 tools/examples/usb
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/tools/examples/usb	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+dir=$(dirname "$0")
+. "$dir/xen-hotplug-common.sh"
+
+success
diff -r f426f6e646eb -r 404b4ec94253 xen/include/public/io/usbif.h
--- /dev/null	Mon Oct  2 17:04:56 2006
+++ b/xen/include/public/io/usbif.h	Tue Oct  3 16:29:44 2006
@@ -0,0 +1,213 @@
+/*****************************************************************************/
+/* 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 the previous usbif.h by Mark Williamson and blkif.h, original    */
+/* copyright notice follows...                                               */
+/*****************************************************************************/
+
+/******************************************************************************
+ * usbif.h
+ * 
+ * Unified block-device I/O interface for Xen guest OSes.
+ * 
+ * Copyright (c) 2003-2004, Keir Fraser
+ */
+
+#ifndef USBIF_H
+#define USBIF_H
+
+#include "../xen.h"
+#include "../grant_table.h"
+#include "ring.h"
+
+typedef uint32_t usbif_error;
+
+#define USBIF_ERROR_SUCCESS           (usbif_error)0
+#define USBIF_ERROR_FAILURE           (usbif_error)1
+#define USBIF_ERROR_DISCONNECT        (usbif_error)2
+#define USBIF_ERROR_INVALID_PROTOCOL  (usbif_error)3
+#define USBIF_ERROR_INVALID_PARAMETER (usbif_error)4
+#define USBIF_ERROR_TOO_BIG           (usbif_error)5
+#define USBIF_ERROR_NO_DEVICE         (usbif_error)6
+#define USBIF_ERROR_UNLINKED          (usbif_error)7
+#define USBIF_ERROR_PIPE              (usbif_error)8
+
+#define USBIF_GRANT_TABLE_REFERENCE_COUNT 16
+
+typedef uint32_t usbif_buffer_byte_count;
+
+struct usbif_rbr {
+	grant_ref_t             reference[USBIF_GRANT_TABLE_REFERENCE_COUNT];
+	usbif_buffer_byte_count byte_offset;
+	usbif_buffer_byte_count byte_count;
+};
+
+static inline usbif_buffer_byte_count
+usbif_rbr_query_byte_count(struct usbif_rbr *rbr)
+{
+	return rbr->byte_count;
+}
+
+struct usbif_tra_parameters_header {
+	uint8_t tra_type;
+	uint8_t reserved[7];
+};
+
+#define USBIF_TRA_TYPE_PROBE 0
+#define USBIF_TRA_TYPE_RESET 1
+#define USBIF_TRA_TYPE_IO    2
+#define USBIF_TRA_TYPE_STALL 3
+
+struct usbif_probe_tra_parameters {
+	struct usbif_tra_parameters_header header;
+	uint8_t                            reserved[8];
+};
+
+struct usbif_probe_tra_status {
+	uint8_t result;
+	uint8_t reserved[7];
+};
+
+#define USBIF_PROBE_RESULT_NO_DEVICE      0
+#define USBIF_PROBE_RESULT_DEVICE_PRESENT 1
+
+struct usbif_reset_tra_parameters {
+	struct usbif_tra_parameters_header header;
+	uint8_t                            reserved[8];
+};
+
+struct usbif_reset_tra_status {
+	uint8_t result;
+	uint8_t reserved[7];
+};
+
+#define USBIF_RESET_RESULT_FULL_SPEED 0
+#define USBIF_RESET_RESULT_LOW_SPEED  1
+#define USBIF_RESET_RESULT_HIGH_SPEED 2
+
+struct usbif_io_tra_parameters_header {
+	struct usbif_tra_parameters_header header;
+	uint8_t                            io_tra_type;
+	uint8_t                            device_number;
+	uint8_t                            endpoint;
+	uint8_t                            direction;
+	uint32_t                           flags;
+	struct usbif_rbr                   rbr;
+};
+
+#define USBIF_IO_TRA_TYPE_CONTROL     0
+#define USBIF_IO_TRA_TYPE_BULK        1
+#define USBIF_IO_TRA_TYPE_INTERRUPT   2
+#define USBIF_IO_TRA_TYPE_ISOCHRONOUS 3
+
+#define USBIF_IO_TRA_DIRECTION_OUT 0
+#define USBIF_IO_TRA_DIRECTION_IN  1
+
+#define USBIF_IO_FLAGS_SHORT_NOT_OK 0x00000001
+#define USBIF_IO_FLAGS_ZERO_PACKET  0x00000002
+#define USBIF_IO_FLAGS_CLEAR_STALL  0x80000000
+
+struct usbif_control_io_tra_parameters {
+	struct usbif_io_tra_parameters_header header;
+	uint8_t                               setup[8];
+};
+
+struct usbif_bulk_io_tra_parameters {
+	struct usbif_io_tra_parameters_header header;
+};
+
+struct usbif_interrupt_io_tra_parameters {
+	struct usbif_io_tra_parameters_header header;
+	uint32_t                              interval;
+};
+
+struct usbif_isochronous_io_tra_parameters {
+	struct usbif_io_tra_parameters_header header;
+	uint32_t                              interval;
+	uint32_t                              packet_count;
+	struct usbif_rbr                      schedule_rbr;
+};
+
+struct usbif_isochronous_io_schedule_element {
+	usbif_buffer_byte_count offset;   /* IN offset into header's rbr */
+	usbif_buffer_byte_count length;   /* IN = expected, OUT = actual */
+	usbif_error             error;    /* OUT for this packet. */
+};
+
+union usbif_io_tra_parameters {
+	struct usbif_io_tra_parameters_header      header;
+	struct usbif_control_io_tra_parameters     control;
+	struct usbif_bulk_io_tra_parameters        bulk;
+	struct usbif_interrupt_io_tra_parameters   interrupt;
+	struct usbif_isochronous_io_tra_parameters isochronous;
+};
+
+struct usbif_io_tra_status {
+	usbif_buffer_byte_count length;
+};
+
+struct usbif_stall_tra_parameters {
+	struct usbif_tra_parameters_header header;
+	uint8_t                            endpoint;
+	uint8_t                            direction;
+	uint8_t                            reserved[6];
+};
+
+struct usbif_ring_gw_parameters_element {
+	uint32_t id;
+};
+
+struct usbif_ring_gw_status_element {
+	uint32_t    id;
+	usbif_error error;
+};
+
+union usbif_parameters {
+	struct usbif_tra_parameters_header header;
+	struct usbif_probe_tra_parameters  probe;
+	struct usbif_reset_tra_parameters  reset;
+	union  usbif_io_tra_parameters     io;
+	struct usbif_stall_tra_parameters  stall;
+};
+
+union usbif_status {
+	struct usbif_probe_tra_status probe;
+	struct usbif_reset_tra_status reset;
+	struct usbif_io_tra_status    io;
+};
+
+struct usbif_request {
+	struct usbif_ring_gw_parameters_element gw_parameters;
+	union usbif_parameters                  usbif_parameters;
+};
+
+struct usbif_response {
+	struct usbif_ring_gw_status_element gw_status;
+	union usbif_status                  usbif_status;
+};
+
+DEFINE_RING_TYPES(usbif, struct usbif_request, struct usbif_response);
+
+#define USBIF_MAX_SCHEDULE_PACKET_COUNT 64
+
+/* USBIF_QUOTA is constrained by lack of flow control in RING macros. */
+#define USBIF_QUOTA (__RING_SIZE(((struct usbif_sring *)0), PAGE_SIZE) - 1)
+
+#endif

[-- 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] 4+ messages in thread
* USB split driver
@ 2006-10-04 21:22 Harry Butterworth
  2006-10-05 23:46 ` Harry Butterworth
  0 siblings, 1 reply; 4+ messages in thread
From: Harry Butterworth @ 2006-10-04 21:22 UTC (permalink / raw)
  To: xen-devel

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

I tried to get my webcam working today and the isoc URB path had a bug
in it which caused all isoc URBs to fail back.  This hammered the new
error recovery code and exposed a couple of bugs which I've fixed in
this latest version of the patch.

I fixed the bug in the handling of isoc URBs and implemented emulation
of the set_interface command in the BE.

The webcam is now discovered but camorama can't connect to it.  None of
the URBs seem to be failing so I'll have to compare with the behaviour
under native Linux to see what the difference is.

Aside from the webcam, all of my other USB devices are now working with
this version of the patch.

[-- Attachment #2: latest-usb.patch.gz --]
[-- Type: application/x-gzip, Size: 57363 bytes --]

[-- 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] 4+ messages in thread

end of thread, other threads:[~2006-10-05 23:46 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-10-03 17:10 USB split driver Harry Butterworth
2006-10-03 22:17 ` Andrew D. Ball
  -- strict thread matches above, loose matches on Subject: below --
2006-10-04 21:22 Harry Butterworth
2006-10-05 23:46 ` Harry Butterworth

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.