All of lore.kernel.org
 help / color / mirror / Atom feed
* USB virt status
@ 2005-10-30 16:43 Harry Butterworth
       [not found] ` <200511041725.11451.mark.williamson@cl.cam.ac.uk>
  0 siblings, 1 reply; 10+ messages in thread
From: Harry Butterworth @ 2005-10-30 16:43 UTC (permalink / raw)
  To: xen-devel; +Cc: mark.williamson, sanjay.kushwaha

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

Here's the latest USB code.  This patch is much less crufty than the one
I sent out a week ago since I just finished the refactoring which was
in-progress in the last patch.

In this patch, the inter-domain communication endpoint object
(xenidc_endpoint) is theoretically code-complete but is substantially
unexecuted so I wouldn't recommend trying to use it unless you want to
help test it.

FIXMEs in the patch indicate the work remaining to complete the USB
driver which include:

1) Implement the xenidc_rbr_provider_pool and the xenidc_rbr_mapper_pool
objects which are used to implement the bulk data transfer between the
FE and BE based on the grant-tables API.

2) Update the usbback_driver_port state machine to handle the cn and dn
stimuli.

3) Some minor bits and pieces here and there.

I also need to hook up the claim and release port interfaces to xenbus.

And of course, lots of testing.

Enjoy.

-- 
Harry Butterworth <harry@hebutterworth.freeserve.co.uk>

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

diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/arch/xen/Kconfig
--- a/linux-2.6-xen-sparse/arch/xen/Kconfig	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/arch/xen/Kconfig	Sun Oct 30 16:03:34 2005
@@ -38,6 +38,14 @@
 	  (e.g., hard drives, network cards). This allows you to configure
 	  such devices and also includes some low-level support that is
 	  otherwise not compiled into the kernel.
+
+config XEN_IDC_TRACE
+	bool "Inter-domain communication code tracing"
+	default y
+	help
+	  This option causes the IDC code to output a continual trace of its
+          activity.
+	  Say N here unless you are trying to debug this code.
 
 config XEN_BLKDEV_BACKEND
 	bool "Block-device backend driver"
@@ -69,6 +77,29 @@
 	  The network-device backend driver allows the kernel to export its
 	  network devices to other guests via a high-performance shared-memory
 	  interface.
+
+config XEN_USBDEV_BACKEND
+	tristate "USB-device backend driver"
+	depends on XEN_PHYSDEV_ACCESS
+	select USB
+	default m
+	help
+	  The USB-device backend driver allows the kernel to export USB
+	  devices to USB-device frontend drivers running in other domains.
+	  This is not required for USB device access in domain 0 or any domain
+	  given exclusive control over a USB host controller device at the PCI
+	  level.
+	  Say Y or M if you want to use this kernel to export a USB device to
+          another domain running a USB-device frontend driver.
+
+config XEN_USBDEV_BACKEND_TRACE
+	bool "USB-device backend driver tracing"
+	depends on XEN_USBDEV_BACKEND
+	default y
+	help
+	  This option causes the driver to output a continual trace of its
+          activity.
+	  Say N here unless you are trying to debug the driver.
 
 config XEN_TPMDEV_FRONTEND
         bool "TPM-device frontend driver"
@@ -128,6 +159,30 @@
 	  are unsure; or if you experience network hangs when this option is
 	  enabled; then you must say N here.
 
+config XEN_USBDEV_FRONTEND
+	tristate "USB-device frontend driver"
+	select USB
+	default m
+	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 or M 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 y
+	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_BLKDEV_TAP
 	bool "Block device tap driver"
 	default n
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Sun Oct 30 16:03:34 2005
@@ -1,4 +1,3 @@
-
 obj-y	+= util.o
 
 obj-y	+= console/
@@ -6,12 +5,14 @@
 obj-y	+= balloon/
 obj-y	+= privcmd/
 obj-y	+= xenbus/
+obj-y	+= xenidc/
 
 obj-$(CONFIG_XEN_BLKDEV_BACKEND)	+= blkback/
 obj-$(CONFIG_XEN_NETDEV_BACKEND)	+= netback/
+obj-$(CONFIG_XEN_USBDEV_BACKEND)	+= usbback/
 obj-$(CONFIG_XEN_TPMDEV_BACKEND)	+= tpmback/
 obj-$(CONFIG_XEN_BLKDEV_FRONTEND)	+= blkfront/
 obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= netfront/
+obj-$(CONFIG_XEN_USBDEV_FRONTEND)	+= usbfront/
 obj-$(CONFIG_XEN_BLKDEV_TAP)    	+= blktap/
 obj-$(CONFIG_XEN_TPMDEV_FRONTEND)	+= tpmfront/
-
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c	Sun Oct 30 16:03:34 2005
@@ -264,6 +264,7 @@
 {
 	return xenbus_register_driver_common(drv, &xenbus_backend);
 }
+EXPORT_SYMBOL(xenbus_register_backend);
 
 void xenbus_unregister_driver(struct xenbus_driver *drv)
 {
diff -r b5903c9aeda5 -r e93b9c54edb3 tools/ioemu/target-i386-dm/Makefile
--- a/tools/ioemu/target-i386-dm/Makefile	Sun Oct 30 09:45:49 2005
+++ b/tools/ioemu/target-i386-dm/Makefile	Sun Oct 30 16:03:34 2005
@@ -188,7 +188,7 @@
 #########################################################
 
 DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DAPIC_SUPPORT
-LIBS+=-lm -L../../libxc -lxenctrl
+LIBS+=-lm -L../../libxc -lxenctrl -lpthread
 ifndef CONFIG_USER_ONLY
 LIBS+=-lz
 endif
diff -r b5903c9aeda5 -r e93b9c54edb3 tools/python/xen/xend/server/usbif.py
--- a/tools/python/xen/xend/server/usbif.py	Sun Oct 30 09:45:49 2005
+++ b/tools/python/xen/xend/server/usbif.py	Sun Oct 30 16:03:34 2005
@@ -22,8 +22,9 @@
 """Support for virtual USB hubs.
 """
 
+from xen.xend import sxp
+
 from xen.xend.server.DevController import DevController
-
 
 class UsbifController(DevController):
     """USB device interface controller. Handles all USB devices
@@ -35,8 +36,16 @@
         """
         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)
diff -r b5903c9aeda5 -r e93b9c54edb3 tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py	Sun Oct 30 09:45:49 2005
+++ b/tools/python/xen/xm/create.py	Sun Oct 30 16:03:34 2005
@@ -222,6 +222,10 @@
           fn=set_bool, default=0,
           use="Make the domain a network interface backend.")
 
+gopts.var('usbif', val='no|yes',
+          fn=set_bool, default=0,
+          use="Make the domain a USB device backend.")
+
 gopts.var('tpmif', val='frontend=DOM',
           fn=append_value, default=[],
           use="""Make the domain a TPM interface backend. If frontend is given,
@@ -242,10 +246,12 @@
          For example '-pci c0,02,1a'.
          The option may be repeated to add more than one pci device.""")
 
-gopts.var('usb', val='PATH',
+gopts.var('usb', val="port=PORT,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="""Add a USB device, as specified by the path to that device in
+          the backend domain, to the specified virtual hub port of a 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('ipaddr', val="IPADDR",
           fn=append_value, default=[],
@@ -427,8 +433,13 @@
         config_devs.append(['device', config_pci])
 
 def configure_usb(opts, config_devs, vals):
-    for path in vals.usb:
-        config_usb = ['usb', ['path', path]]
+    for d in vals.usb:
+        path    = d.get('path')
+        backend = d.get('backend')
+        config_usb = ['usb']
+        config_usb.append(['path', path])
+        if backend:
+            config_usb.append(['backend', backend])
         config_devs.append(['device', config_usb])
 
 def configure_vtpm(opts, config_devs, vals):
@@ -578,6 +589,8 @@
         config.append(['backend', ['blkif']])
     if vals.netif:
         config.append(['backend', ['netif']])
+    if vals.usbif:
+        config.append(['backend', ['usbif']])
     if vals.tpmif:
         config.append(['backend', ['tpmif']])
     if vals.restart:
@@ -649,6 +662,22 @@
             d[k] = v
         vifs.append(d)
     vals.vif = vifs
+
+def preprocess_usb(opts, vals):
+    if not vals.usb: return
+    usb = []
+    for port in vals.usb:
+        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']:
+                opts.err('Invalid usb port specifier: ' + port)
+            d[k] = v
+        usb.append(d)
+    vals.usb = usb
 
 def preprocess_vtpm(opts, vals):
     if not vals.vtpm: return
@@ -770,9 +799,10 @@
     preprocess_ip(opts, vals)
     preprocess_nfs(opts, vals)
     preprocess_vnc(opts, vals)
+    preprocess_usb(opts, vals)
     preprocess_vtpm(opts, vals)
     preprocess_tpmif(opts, vals)
-         
+
 def make_domain(opts, config):
     """Create, build and start a domain.
 
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/Makefile
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/Makefile	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,9 @@
+obj-$(CONFIG_XEN_USBDEV_BACKEND) += usbback.o
+
+usbback-objs :=                \
+usbback_device.o               \
+usbback_driver_backend.o       \
+usbback_driver.o               \
+usbback_driver_port.o          \
+usbback_driver_port_resource.o \
+usbback_module.o
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,43 @@
+/*****************************************************************************/
+/* Implementation of the ASSERT macro                                        */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_ASSERT_H
+#define USBBACK_ASSERT_H
+
+#include <linux/kernel.h>
+
+static inline void assert_failed
+  ( const char * function, int line, const char * statement )
+{
+    printk
+    (
+        KERN_ERR "usbback assert failed: %s line %d, statement %s\n",
+        function,
+        line,
+        statement
+    );
+
+    BUG();
+}
+
+#define ASSERT( S ) \
+( ( S ) ? ( (void)0 ) : assert_failed( __PRETTY_FUNCTION__, __LINE__, #S ) )
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,401 @@
+/*****************************************************************************/
+/* A device object representing the low-level connection to a single         */
+/* front-end.                                                                */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on                                                                  */
+/*                                                                           */
+/* arch/xen/drivers/usbif/backend/control.c                                  */
+/* arch/xen/drivers/usbif/backend/interface.c                                */
+/* arch/xen/drivers/usbif/backend/main.c                                     */
+/* blkback/xenbus.c                                                          */
+/*                                                                           */
+/* original copyright notices follow...                                      */
+/*****************************************************************************/
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/control.c
+ * 
+ * Routines for interfacing with the control plane.
+ * 
+ * Copyright (c) 2004, Keir Fraser
+ */
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/interface.c
+ * 
+ * USB device interface management.
+ * 
+ * by Mark Williamson, Copyright (c) 2004
+ */
+
+/******************************************************************************
+ * arch/xen/drivers/blkif/backend/interface.c
+ * 
+ * Block-device interface management.
+ * 
+ * Copyright (c) 2004, Keir Fraser
+ */
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ * 
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson
+ * Copyright (c) 2004 Intel Research Cambridge
+ * Copyright (c) 2004, 2005 Mark Williamson
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+/*  Xenbus code for blkif backend
+    Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <asm-xen/xen-public/io/usbif.h>
+#include <asm-xen/xenbus.h>
+#include <asm-xen/xenidc.h>
+#include "usbback_assert.h"
+#include "usbback_device.h"
+#include "usbback_driver.h"
+#include "usbback_trace.h"
+
+struct usbback_device
+{
+    struct xenbus_device * dev;
+    void                 * drvdata;
+    long int               frontend_id;
+    char                 * frontend;
+    xenidc_endpoint        endpoint;
+};
+
+static inline struct usbback_device * usbback_device_endpoint_to
+  ( xenidc_endpoint * endpoint )
+{
+    trace();
+
+    return container_of( endpoint, struct usbback_device, endpoint );
+}
+
+void usbback_device_set_drvdata( struct usbback_device * device, void * data )
+{
+    trace();
+
+    device->drvdata = data;
+}
+
+void * usbback_device_get_drvdata( struct usbback_device * device )
+{
+    trace();
+
+    return device->drvdata;
+}
+
+static void usbback_device_endpoint_connect( xenidc_endpoint * endpoint )
+{
+    trace();
+
+    /* Transactions and messages received between connect and disconnect are */
+    /* processed normally.                                                   */
+    /* Between connect and completion of the disconnect callback we are      */
+    /* allowed to issue messages and transactions.  We don't actually need   */
+    /* to issue messages or transactions from the backend to the frontend.   */
+
+    usbback_driver_connect( usbback_device_endpoint_to( endpoint ) );
+}
+
+static void usbback_device_endpoint_disconnect
+  ( xenidc_endpoint * endpoint, xenidc_callback * callback )
+{
+    trace();
+
+    /* We must stop issuing messages and transactions and complete the       */
+    /* callback once all of the messages and transactions we are issuing     */
+    /* have completed or failed back to us.                                  */
+
+    /* After the disconnect, any messages or transactions we receive must be */
+    /* failed back and we must flush through any that are in progress.       */
+
+    usbback_driver_disconnect( usbback_device_endpoint_to( endpoint ) );
+
+    /* We can complete the callback immediately since we are not issuing any */
+    /* messages or transactions from the backend to the frontend.            */
+
+    xenidc_callback_success( callback );
+}
+
+static void usbback_device_endpoint_message
+  ( xenidc_endpoint * endpoint, xenidc_endpoint_message * message )
+{
+    trace();
+
+    usbback_driver_message_handler
+      ( usbback_device_endpoint_to( endpoint ), message );
+}
+
+static void usbback_device_endpoint_transaction
+  ( xenidc_endpoint * endpoint, xenidc_endpoint_transaction * transaction )
+{
+    trace();
+
+    usbback_driver_transaction_handler
+      ( usbback_device_endpoint_to( endpoint ), transaction );
+}
+
+static int usbback_device_init_or_exit
+  ( struct usbback_device * device, struct xenbus_device * dev, int exit )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        if( exit )
+        {
+           goto EXIT;
+        }
+
+        memset( device, 0, sizeof( *device ) );
+
+        device->dev = dev;
+
+        return_value = usbback_driver_probe_usbback_device( device );
+
+        if( return_value != 0 )
+        {
+            goto EXIT_NO_DRIVER;
+        }
+
+        device->frontend = NULL;
+
+        return_value = xenbus_gather
+        (
+            NULL, /* FIXME? */
+            dev->nodename,
+            "frontend-id", "%li", &device->frontend_id,
+            "frontend",   NULL, &device->frontend,
+            NULL
+        );
+
+        if( XENBUS_EXIST_ERR( return_value ) )
+        {
+            goto EXIT_NO_FRONTEND;
+        }
+
+        if( return_value < 0 )
+        {
+            xenbus_dev_error
+            (
+                dev,
+                return_value,
+                "reading %s/frontend",
+                dev->nodename
+            );
+
+            goto EXIT_NO_FRONTEND;
+        }
+
+        return_value = xenidc_endpoint_init
+        (
+            &device->endpoint,
+            usbback_device_endpoint_connect,
+            usbback_device_endpoint_message,
+            usbback_device_endpoint_transaction,
+            usbback_device_endpoint_disconnect,
+            USBIF_BE_INITIATOR_QUOTA,
+            USBIF_BE_INITIATOR_MAXIMUM_BYTE_COUNT,
+            USBIF_BE_TARGET_QUOTA,
+            USBIF_BE_TARGET_MAXIMUM_BYTE_COUNT
+        );
+
+        if( return_value != 0 )
+        {
+            goto EXIT_NO_ENDPOINT;
+        }
+
+        {
+            xenidc_address address;
+
+            xenidc_address_init
+            (
+                &address,
+                dev->nodename,
+                device->frontend,
+                device->frontend_id
+            );
+
+            xenidc_endpoint_create( &device->endpoint, address );
+        }
+
+        return 0;
+
+      EXIT:
+
+        xenidc_endpoint_destroy( &device->endpoint );
+
+        xenidc_endpoint_exit( &device->endpoint );
+
+      EXIT_NO_ENDPOINT:
+
+        kfree( device->frontend );
+
+      EXIT_NO_FRONTEND:
+
+        usbback_driver_remove_usbback_device( device );
+
+      EXIT_NO_DRIVER:
+
+        return return_value;
+    }
+}
+
+static int usbback_device_init
+  ( struct usbback_device * device, struct xenbus_device * dev )
+{
+    trace();
+
+    return usbback_device_init_or_exit( device, dev, 0 );
+}
+
+static void usbback_device_exit( struct usbback_device * device )
+{
+    trace();
+
+    (void)usbback_device_init_or_exit( device, NULL, 1 );
+}
+
+static int usbback_device_probe_or_remove
+  ( struct xenbus_device * dev, int remove )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        struct usbback_device * device;
+
+        if( remove )
+        {
+            goto REMOVE;
+        }
+
+        device = kmalloc( sizeof( *device ), GFP_KERNEL );
+
+        if( device == NULL )
+        {
+            xenbus_dev_error( dev, -ENOMEM, "allocating backend structure" );
+
+            return_value = -ENOMEM;
+
+            goto EXIT_NO_DEVICE;
+        }
+
+        dev->data = device;
+
+        return_value = usbback_device_init( device, dev );
+
+        if( return_value != 0 )
+        {
+            goto EXIT_INIT_FAILED;
+        }
+
+        return 0;
+
+      REMOVE:
+
+        device = dev->data;
+
+        usbback_device_exit( device );
+
+      EXIT_INIT_FAILED:
+
+        dev->data = NULL;
+
+        kfree( device );
+
+      EXIT_NO_DEVICE:
+
+        return return_value;
+    }
+}
+
+static int usbback_device_probe
+  ( struct xenbus_device * dev, const struct xenbus_device_id * id )
+{
+    trace();
+
+    return usbback_device_probe_or_remove( dev, 0 );
+}
+
+static int usbback_device_remove( struct xenbus_device * dev )
+{
+    trace();
+
+    return usbback_device_probe_or_remove( dev, 1 );
+}
+
+static struct xenbus_device_id usbback_device_ids[] =
+{
+    { "usb" },
+    { "" }
+};
+
+static struct xenbus_driver usbback_device_driver =
+{
+    .name   = "usb",
+    .owner  = THIS_MODULE,
+    .ids    = usbback_device_ids,
+    .probe  = usbback_device_probe,
+    .remove = usbback_device_remove,
+};
+
+int usbback_device_class_init( void )
+{
+    trace();
+
+    xenbus_register_backend( &usbback_device_driver );
+
+    return 0;
+}
+
+void usbback_device_class_exit( void )
+{
+    trace();
+
+    xenbus_unregister_driver( &usbback_device_driver );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,37 @@
+/*****************************************************************************/
+/* A device object representing the low-level connection to a single         */
+/* front-end.                                                                */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_DEVICE_H
+#define USBBACK_DEVICE_H
+
+extern int usbback_device_class_init( void );
+
+extern void usbback_device_class_exit( void );
+
+struct usbback_device;
+
+extern void usbback_device_set_drvdata
+  ( struct usbback_device * device, void * data );
+
+extern void * usbback_device_get_drvdata( struct usbback_device * device );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,249 @@
+/*****************************************************************************/
+/* Device driver which drives usbback_device devices.                        */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#include <linux/device.h>
+#include <linux/usb.h>
+#include "usbback_assert.h"
+#include "usbback_device.h"
+#include "usbback_driver.h"
+#include "usbback_driver_backend.h"
+#include "usbback_driver_port.h"
+#include "usbback_trace.h"
+
+static int usbback_driver_probe_usb
+  ( struct usb_interface * intf, const struct usb_device_id * id )
+{
+    trace();
+
+    return usbback_driver_port_probe_usb( intf );
+}
+
+static void usbback_driver_disconnect_usb( struct usb_interface * intf )
+{
+    trace();
+
+    usbback_driver_port_disconnect_usb( intf );
+}
+
+static int usbback_driver_probe_or_remove_usbback_device
+  ( struct usbback_device * device, int remove )
+{
+    trace();
+
+    {
+        struct usbback_driver_backend * backend;
+
+        int return_value = 0;
+
+        if( remove )
+        {
+            goto REMOVE;
+        }
+
+        backend = usbback_driver_backend_allocate( device );
+
+        if( backend == NULL )
+        {
+            return_value = -ENOMEM;
+
+            goto EXIT_NO_BACKEND;
+        }
+
+        usbback_device_set_drvdata( device, backend );
+
+        return 0;
+
+      REMOVE:
+
+        backend = usbback_device_get_drvdata( device );
+
+        usbback_driver_backend_shutdown( backend );
+
+        usbback_device_set_drvdata( device, NULL );
+
+      EXIT_NO_BACKEND:
+
+        return return_value;
+    }
+}
+
+int usbback_driver_probe_usbback_device( struct usbback_device * device )
+{
+    trace();
+
+    return usbback_driver_probe_or_remove_usbback_device( device, 0 );
+}
+
+void usbback_driver_connect( struct usbback_device * device )
+{
+    trace();
+
+    {
+        struct usbback_driver_backend * backend =
+          usbback_device_get_drvdata( device );
+
+        usbback_driver_backend_connect( backend );
+    }
+}
+
+void usbback_driver_message_handler
+  ( struct usbback_device * device, xenidc_endpoint_message * message )
+{
+    trace();
+
+    {
+        struct usbback_driver_backend * backend =
+          usbback_device_get_drvdata( device );
+
+        usbback_driver_backend_message_handler( backend, message );
+    }
+}
+
+void usbback_driver_transaction_handler
+  ( struct usbback_device * device, xenidc_endpoint_transaction * transaction )
+{
+    trace();
+
+    {
+        struct usbback_driver_backend * backend =
+          usbback_device_get_drvdata( device );
+
+        usbback_driver_backend_transaction_handler( backend, transaction );
+    }
+}
+
+void usbback_driver_disconnect( struct usbback_device * device )
+{
+    trace();
+
+    {
+        struct usbback_driver_backend * backend =
+          usbback_device_get_drvdata( device );
+
+        usbback_driver_backend_disconnect( backend );
+    }
+}
+
+void usbback_driver_claim_port
+  ( struct usbback_device * device, u32 port, char * path )
+{
+    trace();
+
+    {
+        struct usbback_driver_backend * backend =
+          usbback_device_get_drvdata( device );
+
+        usbback_driver_backend_claim_port( backend, port, path );
+    }
+}
+
+void usbback_driver_release_port
+  ( struct usbback_device * device, u32 port )
+{
+    trace();
+
+    {
+        struct usbback_driver_backend * backend =
+          usbback_device_get_drvdata( device );
+
+        usbback_driver_backend_release_port( backend, port );
+    }
+}
+
+void usbback_driver_remove_usbback_device( struct usbback_device * device )
+{
+    trace();
+
+    (void)usbback_driver_probe_or_remove_usbback_device( device, 1 );
+}
+
+static struct usb_device_id usbback_driver_usb_id_table[] =
+{
+    { .driver_info = 1 }, /* Matches all devices. */
+    {}
+};
+
+MODULE_DEVICE_TABLE( usb, usbback_driver_usb_id_table );
+
+struct usb_driver usbback_driver_usb_driver =
+{
+    .owner      = THIS_MODULE,
+    .name       = "usbback",
+    .probe      = usbback_driver_probe_usb,
+    .disconnect = usbback_driver_disconnect_usb,
+    .id_table   = usbback_driver_usb_id_table,
+};
+
+static int usbback_driver_init_or_exit( int exit )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        if( exit )
+        {
+            goto EXIT;
+        }
+
+        return_value = usbback_driver_port_class_init();
+
+        if( return_value != 0 )
+        {
+            goto EXIT_NO_PORT_CLASS;
+        }
+
+        return_value = usb_register( &usbback_driver_usb_driver );
+
+        if( return_value != 0 )
+        {
+            goto EXIT_NO_USB_REGISTER;
+        }
+
+        return 0;
+
+      EXIT:
+
+        usb_deregister( &usbback_driver_usb_driver );
+
+      EXIT_NO_USB_REGISTER:
+
+        usbback_driver_port_class_exit();
+
+      EXIT_NO_PORT_CLASS:
+
+        return return_value;
+    }
+}
+
+int usbback_driver_init( void )
+{
+    trace();
+
+    return usbback_driver_init_or_exit( 0 );
+}
+
+void usbback_driver_exit( void )
+{
+    trace();
+
+    (void)usbback_driver_init_or_exit( 1 );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,57 @@
+/*****************************************************************************/
+/* Device driver which drives usbback_device devices.                        */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_DRIVER_H
+#define USBBACK_DRIVER_H
+
+#include "asm-xen/xenidc.h"
+#include "usbback_device.h"
+
+extern int usbback_driver_init( void );
+
+extern int usbback_driver_probe_usbback_device
+  ( struct usbback_device * device );
+
+extern void usbback_driver_connect( struct usbback_device * device );
+
+extern void usbback_driver_message_handler
+  ( struct usbback_device * device, xenidc_endpoint_message * message );
+
+extern void usbback_driver_transaction_handler
+(
+    struct usbback_device       * device,
+    xenidc_endpoint_transaction * transaction
+);
+
+extern void usbback_driver_disconnect( struct usbback_device * device );
+
+extern void usbback_driver_claim_port
+  ( struct usbback_device * device, u32 port, char * path );
+
+extern void usbback_driver_release_port
+  ( struct usbback_device * device, u32 port );
+
+extern void usbback_driver_remove_usbback_device
+  ( struct usbback_device * device );
+
+extern void usbback_driver_exit( void );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,603 @@
+/*****************************************************************************/
+/* usbback_driver_backend is the representation in the driver of the         */
+/* back-end side of a single front-end to back-end connection.               */
+/* One of these objects is used by the usbback_driver to manage each         */
+/* usbback_device.                                                           */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on arch/xen/drivers/usbif/backend/main.c, original copyright notice */
+/* follows...                                                                */
+/*****************************************************************************/
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ * 
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson
+ * Copyright (c) 2004 Intel Research Cambridge
+ * Copyright (c) 2004, 2005 Mark Williamson
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+#include <asm-xen/xen-public/io/usbif.h>
+#include "usbback_assert.h"
+#include "usbback_device.h"
+#include "usbback_driver_backend.h"
+#include "usbback_driver_port.h"
+#include "usbback_trace.h"
+
+#define USBBACK_DRIVER_PORT_COUNT 7
+
+struct usbback_driver_backend
+{
+    struct usbback_device * device;
+    struct usbback_driver_port port[ USBBACK_DRIVER_PORT_COUNT ];
+};
+
+static int usbback_driver_backend_init_or_exit
+(
+    struct usbback_driver_backend * backend,
+    struct usbback_device         * device,
+    int                             exit
+)
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        if( exit )
+        {
+            goto EXIT;
+        }
+
+        memset( backend, 0, sizeof( *backend ) );
+
+        backend->device = device;
+
+        {
+            int i;
+
+            for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ )
+            {
+                return_value =
+                  usbback_driver_port_init( &backend->port[ i ], backend );
+
+                if( return_value != 0 )
+                {
+                    goto EXIT_NO_PORT;
+                }
+            }
+
+            return 0;
+
+          EXIT:
+
+            i = USBBACK_DRIVER_PORT_COUNT;
+
+          EXIT_NO_PORT:
+
+            i--;
+
+            for( ; i >= 0; i-- )
+            {
+                usbback_driver_port_shutdown( &backend->port[ i ] );
+            }
+        }
+
+        return return_value;
+    }
+}
+
+struct usbback_driver_backend * usbback_driver_backend_allocate
+  ( struct usbback_device * device )
+{
+    struct usbback_driver_backend * backend =
+      (struct usbback_driver_backend *)kmalloc
+        ( sizeof( struct usbback_driver_backend ), GFP_KERNEL );
+
+    if
+    (
+        ( backend != NULL )
+        &&
+        ( usbback_driver_backend_init_or_exit( backend, device, 0 ) != 0 )
+    )
+    {
+        kfree( backend );
+
+        backend = NULL;
+    }
+
+    return backend;
+}
+
+void usbback_driver_backend_connect( struct usbback_driver_backend * backend )
+{
+    trace();
+
+    {
+        int i;
+
+        for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ )
+        {
+            usbback_driver_port_connect( &backend->port[ i ] );
+        }
+    }
+}
+
+static void usbback_driver_backend_handle_probe
+(
+    struct usbback_driver_backend * backend,
+    xenidc_endpoint_transaction            * transaction
+);
+
+static void usbback_driver_backend_handle_reset
+(
+    struct usbback_driver_backend * backend,
+    xenidc_endpoint_transaction            * transaction
+);
+
+static void usbback_driver_backend_handle_io
+(
+    struct usbback_driver_backend * backend,
+    xenidc_endpoint_transaction            * transaction
+);
+
+void usbback_driver_backend_transaction_handler
+(
+    struct usbback_driver_backend * backend,
+    xenidc_endpoint_transaction   * transaction
+)
+{
+    /* trace(); */
+
+    usbif_transaction_parameters_header header;
+
+    if
+    (
+        xenidc_local_buffer_reference_copy_out
+        (
+            xenidc_endpoint_transaction_to_parameters_lbr( transaction ),
+            &header,
+            sizeof( header )
+        )
+        ==
+        sizeof( header )
+    )
+    {
+        switch( header.transaction_type )
+        {
+          case USBIF_TRANSACTION_TYPE_PROBE:
+            usbback_driver_backend_handle_probe( backend, transaction );
+            break;
+          case USBIF_TRANSACTION_TYPE_RESET:
+            usbback_driver_backend_handle_reset( backend, transaction );
+            break;
+          case USBIF_TRANSACTION_TYPE_IO:
+            usbback_driver_backend_handle_io( backend, transaction );
+            break;
+          default:
+            xenidc_endpoint_transaction_complete
+              ( transaction, XENIDC_ERROR_INVALID_PARAMETER );
+            break;
+        }
+    }
+    else
+    {
+        /* Parameters were underlength. */
+
+        xenidc_endpoint_transaction_complete
+          ( transaction, XENIDC_ERROR_INVALID_FORMAT );
+    }
+}
+
+static void usbback_driver_backend_handle_probe
+(
+    struct usbback_driver_backend * backend,
+    xenidc_endpoint_transaction   * transaction
+)
+{
+    /* trace(); */
+
+    usbif_probe_transaction_parameters parameters;
+
+    xenidc_error error;
+
+    if
+    (
+        xenidc_local_buffer_reference_copy_out
+        (
+            xenidc_endpoint_transaction_to_parameters_lbr( transaction ),
+            &parameters,
+            sizeof( parameters )
+        )
+        !=
+        sizeof( parameters )
+    )
+    {
+        error = XENIDC_ERROR_INVALID_FORMAT;
+
+        goto COMPLETE;
+    }
+
+    if
+    (
+        ( parameters.port <= 0 )
+        ||
+        ( parameters.port > USBBACK_DRIVER_PORT_COUNT )
+    )
+    {
+        error = XENIDC_ERROR_INVALID_PARAMETER;
+
+        goto COMPLETE;
+    }
+
+    {
+        usbif_probe_transaction_status status;
+
+        memset( &status, 0, sizeof( status ) );
+
+        status.result = usbback_driver_port_usbdev_is_connected
+          ( &backend->port[ parameters.port - 1 ] ) ?
+            USBIF_PROBE_RESULT_DEVICE_PRESENT :
+              USBIF_PROBE_RESULT_NO_DEVICE;
+
+        if
+        (
+            xenidc_local_buffer_reference_copy_in
+            (
+                xenidc_endpoint_transaction_to_status_lbr( transaction ),
+                &status,
+                sizeof( status )
+            )
+            !=
+            sizeof( status )
+        )
+        {
+            error = XENIDC_ERROR_INVALID_FORMAT;
+
+            goto COMPLETE;
+        }
+    }
+
+    error = XENIDC_ERROR_SUCCESS;
+
+  COMPLETE:
+
+    xenidc_endpoint_transaction_complete( transaction, error );
+}
+
+static void usbback_driver_backend_handle_reset
+(
+    struct usbback_driver_backend * backend,
+    xenidc_endpoint_transaction   * transaction
+)
+{
+    trace();
+
+    {
+        usbif_reset_transaction_parameters parameters;
+
+        xenidc_error error;
+
+        if
+        (
+            xenidc_local_buffer_reference_copy_out
+            (
+                xenidc_endpoint_transaction_to_parameters_lbr( transaction ),
+                &parameters,
+                sizeof( parameters )
+            )
+            !=
+            sizeof( parameters )
+        )
+        {
+            error = XENIDC_ERROR_INVALID_FORMAT;
+
+            goto COMPLETE;
+        }
+
+        if
+        (
+            ( parameters.port <= 0 )
+            ||
+            ( parameters.port > USBBACK_DRIVER_PORT_COUNT )
+        )
+        {
+            error = XENIDC_ERROR_INVALID_PARAMETER;
+
+            goto COMPLETE;
+        }
+
+        {
+            int result = usbback_driver_port_reset
+              ( &backend->port[ parameters.port - 1 ] );
+
+            if( result < 0 )
+            {
+                error = USBIF_XENIDC_ERROR_NO_DEVICE;
+
+                goto COMPLETE;
+            }
+
+            {
+                usbif_reset_transaction_status status;
+
+                memset( &status, 0, sizeof( status ) );
+
+                status.result = result;
+
+                if
+                (
+                    xenidc_local_buffer_reference_copy_in
+                    (
+                        xenidc_endpoint_transaction_to_status_lbr
+                          ( transaction ),
+                        &status,
+                        sizeof( status )
+                    )
+                    !=
+                    sizeof( status )
+                )
+                {
+                    error = XENIDC_ERROR_INVALID_FORMAT;
+
+                    goto COMPLETE;
+                }
+            }
+        }
+
+        error = XENIDC_ERROR_SUCCESS;
+
+  COMPLETE:
+
+        xenidc_endpoint_transaction_complete( transaction, error );
+    }
+}
+
+static struct usbback_driver_port *
+  usbback_driver_backend_find_port_by_guest_address
+(
+    struct usbback_driver_backend * backend,
+    unsigned long                   guest_address
+)
+{
+    trace();
+
+    {
+        int i;
+
+        for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ )
+        {
+            struct usbback_driver_port * port = &backend->port[ i ];
+
+            if
+            (
+                usbback_driver_port_match_guest_address( port, guest_address )
+            )
+            {
+                return port;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+static void usbback_driver_backend_handle_io
+(
+    struct usbback_driver_backend * backend,
+    xenidc_endpoint_transaction   * transaction
+)
+{
+    trace();
+
+    {
+        usbif_io_transaction_parameters_header header;
+
+        xenidc_error error;
+
+        if
+        (
+            xenidc_local_buffer_reference_copy_out
+            (
+                xenidc_endpoint_transaction_to_parameters_lbr( transaction ),
+                &header,
+                sizeof( header )
+            )
+            !=
+            sizeof( header )
+        )
+        {
+            error = XENIDC_ERROR_INVALID_FORMAT;
+
+            goto COMPLETE;
+        }
+
+        {
+            struct usbback_driver_port * port =
+              usbback_driver_backend_find_port_by_guest_address
+                ( backend, header.device_number );
+
+            if( port == NULL )
+            {
+                error = USBIF_XENIDC_ERROR_NO_DEVICE;
+
+                goto COMPLETE;
+            }
+
+            usbback_driver_port_handle_io( port, transaction );
+        }
+
+        return;
+
+      COMPLETE:
+
+        xenidc_endpoint_transaction_complete( transaction, error );
+    }
+}
+
+static void usbback_driver_backend_handle_unlink
+(
+    struct usbback_driver_backend * backend,
+    xenidc_endpoint_message       * message
+);
+
+void usbback_driver_backend_message_handler
+(
+    struct usbback_driver_backend * backend,
+    xenidc_endpoint_message       * message
+)
+{
+    trace();
+
+    {
+        usbif_message_header header;
+
+        if
+        (
+            xenidc_local_buffer_reference_copy_out
+            (
+                xenidc_endpoint_message_to_message_lbr( message ),
+                &header,
+                sizeof( header )
+            )
+            ==
+            sizeof( header )
+        )
+        {
+            switch( header.message_type )
+            {
+              case USBIF_MESSAGE_TYPE_UNLINK:
+                usbback_driver_backend_handle_unlink( backend, message );
+                break;
+            }
+        }
+
+        xenidc_callback_success
+          ( xenidc_endpoint_message_to_callback( message ) );
+    }
+}
+
+static void usbback_driver_backend_handle_unlink
+(
+    struct usbback_driver_backend * backend,
+    xenidc_endpoint_message       * message
+)
+{
+    trace();
+
+    {
+        usbif_unlink_message_body unlink;
+
+        if
+        (
+            xenidc_local_buffer_reference_copy_out
+            (
+                xenidc_endpoint_message_to_message_lbr( message ),
+                &unlink,
+                sizeof( unlink )
+            )
+            ==
+            sizeof( unlink )
+        )
+        {
+            int i;
+
+            for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ )
+            {
+                struct usbback_driver_port * port = &backend->port[ i ];
+
+                if
+                (
+                    usbback_driver_port_try_unlink
+                      ( port, unlink.unlink_id )
+                )
+                {
+                    break;
+                }
+            }
+        }
+    }
+}
+
+void usbback_driver_backend_disconnect
+  ( struct usbback_driver_backend * backend )
+{
+    trace();
+
+    {
+        int i;
+
+        for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ )
+        {
+            usbback_driver_port_disconnect( &backend->port[ i ] );
+        }
+    }
+}
+
+void usbback_driver_backend_claim_port
+  ( struct usbback_driver_backend * backend, u32 port, char * path )
+{
+    trace2( "port: %d, path: %s", port, path );
+
+    ASSERT
+    (
+        ( port > 0 )
+        &&
+        ( port <= USBBACK_DRIVER_PORT_COUNT )
+    );
+
+    usbback_driver_port_claim( &backend->port[ port - 1 ], path );
+
+    bus_rescan_devices( &usb_bus_type );
+}
+
+void usbback_driver_backend_release_port
+  ( struct usbback_driver_backend * backend, u32 port )
+{
+    trace1( "port: %d", port );
+
+    ASSERT
+    (
+        ( port > 0 )
+        &&
+        ( port <= USBBACK_DRIVER_PORT_COUNT )
+    );
+
+    usbback_driver_port_release( &backend->port[ port - 1 ] );
+
+    bus_rescan_devices( &usb_bus_type );
+}
+
+void usbback_driver_backend_shutdown
+  ( struct usbback_driver_backend * backend )
+{
+    trace();
+
+    (void)usbback_driver_backend_init_or_exit( backend, NULL, 1 );
+
+    kfree( backend );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,63 @@
+/*****************************************************************************/
+/* usbback_driver_backend is the representation in the driver of the         */
+/* back-end side of a single front-end to back-end connection.               */
+/* One of these objects is used by the usbback_driver to manage each         */
+/* usbback_device.                                                           */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_DRIVER_BACKEND_H
+#define USBBACK_DRIVER_BACKEND_H
+
+#include "asm-xen/xenidc.h"
+#include "usbback_device.h"
+
+struct usbback_driver_backend;
+
+extern struct usbback_driver_backend * usbback_driver_backend_allocate
+  ( struct usbback_device * device );
+
+extern void usbback_driver_backend_connect
+  ( struct usbback_driver_backend * backend );
+
+extern void usbback_driver_backend_transaction_handler
+(
+    struct usbback_driver_backend * backend,
+    xenidc_endpoint_transaction   * transaction
+);
+
+extern void usbback_driver_backend_message_handler
+(
+    struct usbback_driver_backend * backend,
+    xenidc_endpoint_message       * message
+);
+
+extern void usbback_driver_backend_disconnect
+  ( struct usbback_driver_backend * backend );
+
+extern void usbback_driver_backend_claim_port
+  ( struct usbback_driver_backend * backend, u32 port, char * path );
+
+extern void usbback_driver_backend_release_port
+  ( struct usbback_driver_backend * backend, u32 port );
+
+extern void usbback_driver_backend_shutdown
+  ( struct usbback_driver_backend * backend );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,1163 @@
+/*****************************************************************************/
+/* Object which manages a single USB device and handles all the IO           */
+/* transactions for that device by assigning usbback_driver_port_resources   */
+/* to process them.                                                          */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on arch/xen/drivers/usbif/backend/main.c, original copyright notice */
+/* follows...                                                                */
+/*****************************************************************************/
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ * 
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson
+ * Copyright (c) 2004 Intel Research Cambridge
+ * Copyright (c) 2004, 2005 Mark Williamson
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+#include <linux/rwsem.h>
+#include <asm-xen/xen-public/io/usbif.h>
+#include "usbback_assert.h"
+#include "usbback_driver_port.h"
+#include "usbback_trace.h"
+
+int usbback_driver_port_class_init( void )
+{
+    trace();
+
+    return usbback_driver_port_resource_class_init();
+}
+
+void usbback_driver_port_class_exit( void )
+{
+    trace();
+
+    usbback_driver_port_resource_class_exit();
+}
+
+extern struct usb_driver usbback_driver_usb_driver;
+
+static DECLARE_RWSEM( usbback_driver_port_list_sem );
+
+static LIST_HEAD( usbback_driver_port_list );
+
+typedef enum
+{
+    usbback_driver_port_stimulus_pc, /* Port claim                           */
+    usbback_driver_port_stimulus_pr, /* Port release                         */
+    usbback_driver_port_stimulus_up, /* USB probe                            */
+    usbback_driver_port_stimulus_ud, /* USB disconnect                       */
+    usbback_driver_port_stimulus_cn, /* endpoint connect                     */
+    usbback_driver_port_stimulus_dn, /* endpoint disconnect                  */
+    usbback_driver_port_stimulus_rq, /* Transaction queued/resource freed    */
+    usbback_driver_port_stimulus_sd, /* Shutdown                             */
+    usbback_driver_port_stimulus_ri, /* test_io transactions idle (reent)    */
+    usbback_driver_port_stimulus_rr, /* test_io transactions running (reent) */
+    usbback_driver_port_stimulus_rp, /* release performed                    */
+}
+usbback_driver_port_stimulus;
+
+static void usbback_driver_port_handle_stimulus
+(
+    struct usbback_driver_port   * port,
+    usbback_driver_port_stimulus   stimulus
+);
+
+static void usbback_driver_port_purge_io_1( void * data );
+
+static void usbback_driver_port_perform_release_1( void * data );
+
+int usbback_driver_port_init
+(
+    struct usbback_driver_port    * port,
+    struct usbback_driver_backend * backend
+)
+{
+    trace();
+
+    memset( port, 0, sizeof( *port ) );
+
+    port->backend = backend;
+
+    INIT_LIST_HEAD( &port->link );
+
+    spin_lock_init( &port->lock );
+
+    port->state = usbback_driver_port_state_i;
+
+    INIT_LIST_HEAD( &port->transaction_list );
+    INIT_LIST_HEAD( &port->purge_list );
+    INIT_LIST_HEAD( &port->free_resource_list );
+
+    {
+        int i;
+
+        for( i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++ )
+        {
+            struct usbback_driver_port_resource * resource =
+              &port->resources[ i ];
+
+            usbback_driver_port_resource_init( resource, port );
+
+            list_add( &resource->link, &port->free_resource_list );
+        }
+    }
+
+    xenidc_work_init
+      ( &port->purge_io_1_work, usbback_driver_port_purge_io_1, port );
+
+    xenidc_work_init
+    (
+        &port->perform_release_1_work,
+        usbback_driver_port_perform_release_1,
+        port
+    );
+
+    return 0;
+}
+
+void usbback_driver_port_claim
+  ( struct usbback_driver_port * port, char * path )
+{
+    trace();
+
+    down_write( &usbback_driver_port_list_sem );
+
+    strncpy( port->path, path, sizeof( port->path ) );
+
+    list_add_tail( &port->link, &usbback_driver_port_list );
+
+    spin_lock_irq( &port->lock );
+
+    usbback_driver_port_handle_stimulus
+      ( port, usbback_driver_port_stimulus_pc );
+
+    spin_unlock_irq( &port->lock );
+
+    up_write( &usbback_driver_port_list_sem );
+}
+
+void usbback_driver_port_release( struct usbback_driver_port * port )
+{
+    trace();
+
+    down_write( &usbback_driver_port_list_sem );
+
+    list_del_init( &port->link );
+
+    up_write( &usbback_driver_port_list_sem );
+
+    port->release = 0;
+
+    spin_lock_irq( &port->lock );
+
+    usbback_driver_port_handle_stimulus
+      ( port, usbback_driver_port_stimulus_pr );
+
+    spin_unlock_irq( &port->lock );
+
+    xenidc_work_until( port->release );
+}
+
+int usbback_driver_port_probe_usb( struct usb_interface * intf )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        struct usb_device * usbdev = interface_to_usbdev( intf );
+
+        struct usbback_driver_port * port = NULL;
+
+        printk
+          ( KERN_INFO "usbback: Probe for usb device %s\n", usbdev->devpath );
+
+        down_read( &usbback_driver_port_list_sem );
+
+        {
+            struct usbback_driver_port * cur = NULL;
+
+            list_for_each_entry( cur, &usbback_driver_port_list, link )
+            {
+                printk
+                (
+                    KERN_INFO
+                    "usbback: Testing against configured path %s:",
+                    cur->path
+                );
+
+                if
+                (
+                    strncmp( cur->path, usbdev->devpath, sizeof( cur->path ) )
+                    ==
+                    0
+                )
+                {
+                    printk( " matches.\n" );
+
+                    port = cur;
+
+                    break;
+                }
+                else
+                {
+                    printk( " doesn't match.\n" );
+                }
+            }
+        }
+
+        if( port == NULL )
+        {
+            printk( KERN_INFO "usbback: No match found.\n" );
+
+            return_value = -ENODEV;
+
+            goto EXIT_NO_PORT;
+        }
+
+        {
+            int i;
+
+            for( i = 0; i < usbdev->actconfig->desc.bNumInterfaces; i++ )
+            {
+                struct usb_interface * other_intf =
+                  usb_ifnum_to_if( usbdev, i );
+
+                if( other_intf != intf )
+                {
+                    if( usb_interface_claimed( other_intf ) )
+                    {
+                        printk
+                        (
+                            KERN_INFO
+                            "usbback: An interface of the matching device is "
+                            "already in use by another driver.\n"
+                        );
+
+                        return_value = -EBUSY;
+
+                        goto EXIT_INTERFACE_ALREADY_CLAIMED;
+                    }
+                }
+            }
+        }
+
+        {
+            int i;
+
+            for( i = 0; i < usbdev->actconfig->desc.bNumInterfaces; i++ )
+            {
+                struct usb_interface * other_intf =
+                  usb_ifnum_to_if( usbdev, i );
+
+                if( other_intf != intf )
+                {
+                    int error = usb_driver_claim_interface
+                      ( &usbback_driver_usb_driver, other_intf, port );
+
+                    /* We already checked all the interfaces were available. */
+
+                    ASSERT( error == 0 );
+                }
+            }
+        }
+
+        usbdev = usb_get_dev( usbdev );
+
+        usb_set_intfdata( intf, port );
+
+        spin_lock_irq( &port->lock );
+
+        port->usbdev_is_connected = 1;
+
+        port->usbdev = usbdev;
+
+        usbback_driver_port_handle_stimulus
+          ( port, usbback_driver_port_stimulus_up );
+
+        spin_unlock_irq( &port->lock );
+
+  EXIT_INTERFACE_ALREADY_CLAIMED:
+
+  EXIT_NO_PORT:
+
+        up_read( &usbback_driver_port_list_sem );
+
+        return return_value;
+    }
+}
+
+void usbback_driver_port_disconnect_usb( struct usb_interface * intf )
+{
+    trace();
+
+    {
+        struct usbback_driver_port * port = usb_get_intfdata( intf );
+
+        /* Protect against reentrant call when we release other interfaces. */
+
+        if( port != NULL )
+        {
+            ASSERT( port->usbdev_is_connected );
+
+            spin_lock_irq( &port->lock );
+
+            port->usbdev_is_connected = 0;
+
+            port->enabled = 0;
+
+            port->usb_disconnect = 0;
+
+            usbback_driver_port_handle_stimulus
+              ( port, usbback_driver_port_stimulus_ud );
+
+            spin_unlock_irq( &port->lock );
+
+            xenidc_work_until( port->usb_disconnect );
+
+            {
+                struct usb_device * usbdev = port->usbdev;
+
+                {
+                    int i;
+
+                    for
+                    (
+                        i = 0;
+                        i < usbdev->actconfig->desc.bNumInterfaces;
+                        i++
+                    )
+                    {
+                        struct usb_interface * other_intf =
+                          usb_ifnum_to_if( usbdev, i );
+
+                        if( other_intf != intf )
+                        {
+                            /* Protect against reentrant call when we        */
+                            /* release other interfaces.                     */
+
+                            usb_set_intfdata( other_intf, NULL );
+
+                            usb_driver_release_interface
+                              ( &usbback_driver_usb_driver, other_intf );
+                        }
+                    }
+                }
+
+                usb_set_intfdata( intf, NULL );
+
+                usb_put_dev( usbdev );
+            }
+        }
+    }
+}
+
+int usbback_driver_port_reset( struct usbback_driver_port * port )
+{
+    trace();
+
+    {
+        int status = -1;
+
+        spin_lock_irq( &port->lock );
+
+        port->guest_address = 0;
+
+        if( usbback_driver_port_usbdev_is_connected( port ) )
+        {
+            if( port->usbdev->speed == USB_SPEED_LOW )
+            {
+                status = USBIF_RESET_RESULT_LOW_SPEED;
+            }
+            else if( port->usbdev->speed == USB_SPEED_HIGH )
+            {
+                status = USBIF_RESET_RESULT_HIGH_SPEED;
+            }
+            else
+            {
+                status = USBIF_RESET_RESULT_FULL_SPEED;
+            }
+
+            port->enabled = 1;
+        }
+        else
+        {
+            port->enabled = 0;
+        }
+
+        spin_unlock_irq( &port->lock );
+
+        return status;
+    }
+}
+
+void usbback_driver_port_set_guest_address
+  ( struct usbback_driver_port * port, unsigned long guest_address )
+{
+    trace();
+
+    port->guest_address = guest_address;
+}
+
+int usbback_driver_port_match_guest_address
+  ( struct usbback_driver_port * port, unsigned long guest_address )
+{
+    trace();
+
+    return ( port->enabled && ( guest_address == port->guest_address ) );
+}
+
+void usbback_driver_port_connect( struct usbback_driver_port * port )
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &port->lock, flags );
+
+        usbback_driver_port_handle_stimulus
+          ( port, usbback_driver_port_stimulus_cn );
+
+        spin_unlock_irqrestore( &port->lock, flags );
+    }
+}
+
+void usbback_driver_port_handle_io
+(
+    struct usbback_driver_port  * port,
+    xenidc_endpoint_transaction * transaction
+)
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &port->lock, flags );
+
+        list_add_tail
+        (
+            xenidc_endpoint_transaction_to_link( transaction ),
+            &port->transaction_list
+        );
+
+        usbback_driver_port_handle_stimulus
+          ( port, usbback_driver_port_stimulus_rq );
+
+        spin_unlock_irqrestore( &port->lock, flags );
+    }
+}
+
+void usbback_driver_port_disconnect( struct usbback_driver_port * port )
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &port->lock, flags );
+
+        usbback_driver_port_handle_stimulus
+          ( port, usbback_driver_port_stimulus_dn );
+
+        spin_unlock_irqrestore( &port->lock, flags );
+    }
+}
+
+int usbback_driver_port_try_unlink
+  ( struct usbback_driver_port * port, int unlink_id )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        xenidc_endpoint_transaction * transaction = NULL;
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &port->lock, flags );
+
+        {
+            xenidc_endpoint_transaction * temp;
+
+            list_for_each_entry
+            (
+                temp,
+                &port->transaction_list,
+                XENIDC_ENDPOINT_TRANSACTION_LINK
+            )
+            {
+                usbif_io_transaction_parameters_header header;
+
+                if
+                (
+                    xenidc_local_buffer_reference_copy_out
+                    (
+                        xenidc_endpoint_transaction_to_parameters_lbr
+                          ( transaction ),
+                        &header,
+                        sizeof( header )
+                    )
+                    ==
+                    sizeof( header )
+                )
+                {
+                    if( header.unlink_id == unlink_id )
+                    {
+                        transaction = temp;
+
+                        list_del_init
+                        (
+                            xenidc_endpoint_transaction_to_link( transaction )
+                        );
+
+                        break;
+                    }
+                }
+            }
+        }
+
+        if( transaction == NULL )
+        {
+            int i;
+
+            for( i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++ )
+            {
+                struct usbback_driver_port_resource * resource =
+                  &port->resources[ i ];
+
+                if
+                (
+                    usbback_driver_port_resource_try_unlink
+                      ( resource, unlink_id )
+                )
+                {
+                    return_value = 1;
+
+                    break;
+                }
+            }
+        }
+
+        spin_unlock_irqrestore( &port->lock, flags );
+
+        if( transaction )
+        {
+            xenidc_endpoint_transaction_complete
+              ( transaction, USBIF_XENIDC_ERROR_UNLINKED );
+
+            return_value = 1;
+        }
+
+        return return_value;
+    }
+}
+
+void usbback_driver_port_shutdown( struct usbback_driver_port * port )
+{
+    trace();
+
+    down_write( &usbback_driver_port_list_sem );
+
+    list_del_init( &port->link );
+
+    up_write( &usbback_driver_port_list_sem );
+
+    port->shutdown = 0;
+
+    spin_lock_irq( &port->lock );
+
+    usbback_driver_port_handle_stimulus
+      ( port, usbback_driver_port_stimulus_sd );
+
+    spin_unlock_irq( &port->lock );
+
+    xenidc_work_until( port->shutdown );
+
+    flush_scheduled_work();
+}
+
+static void usbback_driver_port_invalid_stimulus
+  ( struct usbback_driver_port * port, usbback_driver_port_stimulus stimulus );
+
+static void usbback_driver_port_purge_io( struct usbback_driver_port * port );
+
+static void usbback_driver_port_test_io( struct usbback_driver_port * port );
+
+static void usbback_driver_port_kick_io( struct usbback_driver_port * port );
+
+static void usbback_driver_port_perform_release
+  ( struct usbback_driver_port * port );
+
+static void usbback_driver_port_complete_release
+  ( struct usbback_driver_port * port );
+
+static void usbback_driver_port_complete_usb_disconnect
+  ( struct usbback_driver_port * port );
+
+static void usbback_driver_port_complete_shutdown
+  ( struct usbback_driver_port * port );
+
+/* FIXME: update to add cn and dn */
+
+static void usbback_driver_port_handle_stimulus
+(
+    struct usbback_driver_port   * port,
+    usbback_driver_port_stimulus   stimulus
+)
+{
+    trace3
+    (
+        "port %p in state %d received stimulus %d",
+        port,
+        port->state,
+        stimulus
+    );
+
+    switch( port->state )
+    {
+      case usbback_driver_port_state_i:
+        /* Released     */
+        /* Disconnected */
+        /* Idle         */
+        switch( stimulus )
+        {
+          case usbback_driver_port_stimulus_pc:
+            port->state = usbback_driver_port_state_i_pc;
+            break;
+          case usbback_driver_port_stimulus_rq:
+            usbback_driver_port_purge_io( port );
+            break;
+          case usbback_driver_port_stimulus_sd:
+            usbback_driver_port_complete_shutdown( port );
+            break;
+          default:
+            usbback_driver_port_invalid_stimulus( port, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_state_i_pc:
+        /* Claimed      */
+        /* Disconnected */
+        /* Idle         */
+        switch( stimulus )
+        {
+          case usbback_driver_port_stimulus_pr:
+            port->state = usbback_driver_port_state_i;
+            usbback_driver_port_complete_release( port );
+            break;
+          case usbback_driver_port_stimulus_up:
+            port->state = usbback_driver_port_state_i_pc_up;
+            break;
+          case usbback_driver_port_stimulus_rq:
+            usbback_driver_port_purge_io( port );
+            break;
+          case usbback_driver_port_stimulus_sd:
+            port->state = usbback_driver_port_state_i;
+            usbback_driver_port_complete_shutdown( port );
+            break;
+          default:
+            usbback_driver_port_invalid_stimulus( port, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_state_i_pc_up:
+        /* Claimed       */
+        /* Probed        */
+        /* Maybe Running */
+        switch( stimulus )
+        {
+          case usbback_driver_port_stimulus_pr:
+            port->state = usbback_driver_port_state_i_pc_up_pr;
+            usbback_driver_port_purge_io( port );
+            usbback_driver_port_test_io( port );
+            break;
+          case usbback_driver_port_stimulus_ud:
+            port->state = usbback_driver_port_state_i_pc_up_ud;
+            usbback_driver_port_purge_io( port );
+            usbback_driver_port_test_io( port );
+            break;
+          case usbback_driver_port_stimulus_rq:
+            usbback_driver_port_kick_io( port );
+            break;
+          case usbback_driver_port_stimulus_sd:
+            port->state = usbback_driver_port_state_i_pc_up_sd;
+            usbback_driver_port_purge_io( port );
+            usbback_driver_port_test_io( port );
+            break;
+          default:
+            usbback_driver_port_invalid_stimulus( port, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_state_i_pc_up_pr:
+        /* Releasing       */
+        /* Probed          */
+        /* Testing/Running */
+        switch( stimulus )
+        {
+          case usbback_driver_port_stimulus_ud:
+            port->state = usbback_driver_port_state_i_pc_up_pr_ud;
+            break;
+          case usbback_driver_port_stimulus_rq:
+            usbback_driver_port_purge_io( port );
+            usbback_driver_port_test_io( port );
+            break;
+          case usbback_driver_port_stimulus_ri:
+            port->state = usbback_driver_port_state_i_pc_up_pr_ri;
+            usbback_driver_port_perform_release( port );
+            break;
+          case usbback_driver_port_stimulus_rr:
+            break;
+          default:
+            usbback_driver_port_invalid_stimulus( port, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_state_i_pc_up_ud:
+        /* Claimed           */
+        /* USB Disconnecting */
+        /* Testing/Running   */
+        switch( stimulus )
+        {
+          case usbback_driver_port_stimulus_pr:
+            port->state = usbback_driver_port_state_i_pc_up_pr_ud;
+            break;
+          case usbback_driver_port_stimulus_rq:
+            usbback_driver_port_purge_io( port );
+            usbback_driver_port_test_io( port );
+            break;
+          case usbback_driver_port_stimulus_sd:
+            port->state = usbback_driver_port_state_i_pc_up_ud_sd;
+            break;
+          case usbback_driver_port_stimulus_ri:
+            port->state = usbback_driver_port_state_i_pc;
+            usbback_driver_port_complete_usb_disconnect( port );
+            break;
+          case usbback_driver_port_stimulus_rr:
+            break;
+          default:
+            usbback_driver_port_invalid_stimulus( port, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_state_i_pc_up_sd:
+        /* Released        */
+        /* Probed          */
+        /* Shutting down   */
+        /* Testing/Running */
+        switch( stimulus )
+        {
+          case usbback_driver_port_stimulus_ud:
+            port->state = usbback_driver_port_state_i_pc_up_ud_sd;
+            break;
+          case usbback_driver_port_stimulus_rq:
+            usbback_driver_port_purge_io( port );
+            usbback_driver_port_test_io( port );
+            break;
+          case usbback_driver_port_stimulus_ri:
+            port->state = usbback_driver_port_state_i_pc_up_sd_ri;
+            usbback_driver_port_perform_release( port );
+            break;
+          case usbback_driver_port_stimulus_rr:
+            break;
+          default:
+            usbback_driver_port_invalid_stimulus( port, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_state_i_pc_up_pr_ud:
+        /* Releasing         */
+        /* USB Disconnecting */
+        /* Testing/Running   */
+        switch( stimulus )
+        {
+          case usbback_driver_port_stimulus_rq:
+            usbback_driver_port_purge_io( port );
+            usbback_driver_port_test_io( port );
+            break;
+          case usbback_driver_port_stimulus_ri:
+            port->state = usbback_driver_port_state_i_pc_up_pr_ud_ri;
+            usbback_driver_port_perform_release( port );
+            usbback_driver_port_complete_usb_disconnect( port );
+            break;
+          case usbback_driver_port_stimulus_rr:
+            break;
+          default:
+            usbback_driver_port_invalid_stimulus( port, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_state_i_pc_up_pr_ri:
+        /* Releasing          */
+        /* Probed             */
+        /* Idle               */
+        /* Performing Release */
+        switch( stimulus )
+        {
+          case usbback_driver_port_stimulus_ud:
+            port->state = usbback_driver_port_state_i_pc_up_pr_ud_ri;
+            usbback_driver_port_complete_usb_disconnect( port );
+            break;
+          case usbback_driver_port_stimulus_rq:
+            usbback_driver_port_purge_io( port );
+            break;
+          default:
+            usbback_driver_port_invalid_stimulus( port, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_state_i_pc_up_ud_sd:
+        /* Released          */
+        /* USB Disconnecting */
+        /* Shutting down     */
+        /* Testing/Running   */
+        switch( stimulus )
+        {
+          case usbback_driver_port_stimulus_rq:
+            usbback_driver_port_purge_io( port );
+            usbback_driver_port_test_io( port );
+            break;
+          case usbback_driver_port_stimulus_ri:
+            port->state = usbback_driver_port_state_i_pc_up_ud_sd_ri;
+            usbback_driver_port_perform_release( port );
+            usbback_driver_port_complete_usb_disconnect( port );
+            break;
+          case usbback_driver_port_stimulus_rr:
+            break;
+          default:
+            usbback_driver_port_invalid_stimulus( port, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_state_i_pc_up_sd_ri:
+        /* Released           */
+        /* Probed             */
+        /* Shutting down      */
+        /* Idle               */
+        /* Performing release */
+        switch( stimulus )
+        {
+          case usbback_driver_port_stimulus_ud:
+            port->state = usbback_driver_port_state_i_pc_up_ud_sd_ri;
+            usbback_driver_port_complete_usb_disconnect( port );
+            break;
+          case usbback_driver_port_stimulus_rq:
+            usbback_driver_port_purge_io( port );
+            break;
+          default:
+            usbback_driver_port_invalid_stimulus( port, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_state_i_pc_up_pr_ud_ri:
+        /* Releasing          */
+        /* Disconnected       */
+        /* Idle               */
+        /* Performing release */
+        switch( stimulus )
+        {
+          case usbback_driver_port_stimulus_rq:
+            usbback_driver_port_purge_io( port );
+            break;
+          case usbback_driver_port_stimulus_rp:
+            port->state = usbback_driver_port_state_i;
+            usbback_driver_port_complete_release( port );
+            break;
+          default:
+            usbback_driver_port_invalid_stimulus( port, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_state_i_pc_up_ud_sd_ri:
+        /* Released           */
+        /* Disconnected       */
+        /* Shutting down      */
+        /* Idle               */
+        /* Performing release */
+        switch( stimulus )
+        {
+          case usbback_driver_port_stimulus_rq:
+            usbback_driver_port_purge_io( port );
+            break;
+          case usbback_driver_port_stimulus_rp:
+            port->state = usbback_driver_port_state_i;
+            usbback_driver_port_complete_shutdown( port );
+            break;
+          default:
+            usbback_driver_port_invalid_stimulus( port, stimulus );
+            break;
+        }
+        break;
+      default:
+        usbback_driver_port_invalid_stimulus( port, stimulus );
+        break;
+    }
+}
+
+static void usbback_driver_port_invalid_stimulus
+  ( struct usbback_driver_port * port, usbback_driver_port_stimulus stimulus )
+{
+    trace();
+
+    printk
+    (
+        KERN_ERR "usbback: port %p in state %d"
+        "received invalid stimulus %d",
+        port,
+        port->state,
+        stimulus
+    );
+}
+
+static void usbback_driver_port_purge_io( struct usbback_driver_port * port )
+{
+    trace();
+
+    while( !list_empty( &port->transaction_list ) )
+    {
+        xenidc_endpoint_transaction * transaction = list_entry
+        (
+            port->transaction_list.next,
+            xenidc_endpoint_transaction,
+            XENIDC_ENDPOINT_TRANSACTION_LINK
+        );
+
+        list_del_init( xenidc_endpoint_transaction_to_link( transaction ) );
+
+        list_add_tail
+        (
+            xenidc_endpoint_transaction_to_link( transaction ),
+            &port->purge_list
+        );
+    }
+
+    {
+        int i;
+
+        for( i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++ )
+        {
+            struct usbback_driver_port_resource * resource =
+              &port->resources[ i ];
+
+            usbback_driver_port_resource_flush_transaction( resource );
+        }
+    }
+
+    (void)xenidc_work_schedule( &port->purge_io_1_work );
+}
+
+static void usbback_driver_port_purge_io_1( void * data )
+{
+    trace();
+
+    {
+        struct usbback_driver_port * port = (struct usbback_driver_port *)data;
+
+        spin_lock_irq( &port->lock );
+
+        while( !list_empty( &port->purge_list ) )
+        {
+            xenidc_endpoint_transaction * transaction = list_entry
+            (
+                port->purge_list.next,
+                xenidc_endpoint_transaction,
+                XENIDC_ENDPOINT_TRANSACTION_LINK
+            );
+
+            list_del_init
+              ( xenidc_endpoint_transaction_to_link( transaction ) );
+
+            spin_unlock_irq( &port->lock );
+
+            xenidc_endpoint_transaction_complete
+              ( transaction, USBIF_XENIDC_ERROR_UNLINKED );
+
+            spin_lock_irq( &port->lock );
+        }
+
+        spin_unlock_irq( &port->lock );
+    }
+}
+
+static void usbback_driver_port_test_io( struct usbback_driver_port * port )
+{
+    trace();
+
+    if( port->current_transactions == 0 )
+    {
+        usbback_driver_port_handle_stimulus
+          ( port, usbback_driver_port_stimulus_ri );
+    }
+    else
+    {
+        usbback_driver_port_handle_stimulus
+          ( port, usbback_driver_port_stimulus_rr );
+    }
+}
+
+static void usbback_driver_port_kick_io( struct usbback_driver_port * port )
+{
+    trace();
+
+    while
+    (
+        ( !list_empty( &port->transaction_list ) )
+        &&
+        ( !list_empty( &port->free_resource_list ) )
+    )
+    {
+        xenidc_endpoint_transaction * transaction = list_entry
+        (
+            port->transaction_list.next,
+            xenidc_endpoint_transaction,
+            XENIDC_ENDPOINT_TRANSACTION_LINK
+        );
+
+        struct usbback_driver_port_resource * resource = list_entry
+        (
+            port->free_resource_list.next,
+            struct usbback_driver_port_resource,
+            link
+        );
+
+        list_del_init( xenidc_endpoint_transaction_to_link( transaction ) );
+
+        list_del_init( &resource->link );
+
+        port->current_transactions++;
+
+        usbback_driver_port_resource_start_io( resource, transaction );
+    }
+}
+
+void usbback_driver_port_resource_completed_io
+(
+    struct usbback_driver_port          * port,
+    struct usbback_driver_port_resource * resource
+)
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &port->lock, flags );
+
+        list_add( &resource->link, &port->free_resource_list );
+
+        port->current_transactions--;
+
+        usbback_driver_port_handle_stimulus
+          ( port, usbback_driver_port_stimulus_rq );
+
+        spin_unlock_irqrestore( &port->lock, flags );
+    }
+}
+
+static void usbback_driver_port_perform_release
+  ( struct usbback_driver_port * port )
+{
+    trace();
+
+    usb_get_dev( port->usbdev );
+
+    {
+        int scheduled = xenidc_work_schedule( &port->perform_release_1_work );
+
+        ASSERT( scheduled );
+    }
+}
+
+static void usbback_driver_port_perform_release_1( void * data )
+{
+    trace();
+
+    {
+        struct usbback_driver_port * port = (struct usbback_driver_port *)data;
+
+        usb_lock_device( port->usbdev );
+
+        down_write( &usb_bus_type.subsys.rwsem );
+
+        if( port->usbdev_is_connected )
+        {
+            usb_driver_release_interface
+            (
+                &usbback_driver_usb_driver,
+                usb_ifnum_to_if( port->usbdev, 0 )
+            );
+        }
+
+        up_write( &usb_bus_type.subsys.rwsem );
+
+        usb_unlock_device( port->usbdev );
+
+        usb_put_dev( port->usbdev );
+
+        spin_lock_irq( &port->lock );
+
+        usbback_driver_port_handle_stimulus
+          ( port, usbback_driver_port_stimulus_rp );
+
+        spin_unlock_irq( &port->lock );
+    }
+}
+
+static void usbback_driver_port_complete_release
+  ( struct usbback_driver_port * port )
+{
+    trace();
+
+    port->release = 1;
+
+    xenidc_work_wake_up();
+}
+
+static void usbback_driver_port_complete_usb_disconnect
+  ( struct usbback_driver_port * port )
+{
+    trace();
+
+    port->usb_disconnect = 1;
+
+    xenidc_work_wake_up();
+}
+
+static void usbback_driver_port_complete_shutdown
+  ( struct usbback_driver_port * port )
+{
+    trace();
+
+    port->shutdown = 1;
+
+    xenidc_work_wake_up();
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,149 @@
+/*****************************************************************************/
+/* Object which manages a single USB device and handles all the              */
+/* io transactions for that device by assigning                              */
+/* usbback_driver_port_resources to process them.                            */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_DRIVER_PORT_H
+#define USBBACK_DRIVER_PORT_H
+
+#include <asm-xen/xenidc.h>
+#include <linux/usb.h>
+#include "usbback_assert.h"
+#include "usbback_driver_backend.h"
+#include "usbback_driver_port_resource.h"
+#include "usbback_trace.h"
+
+int usbback_driver_port_class_init( void );
+
+void usbback_driver_port_class_exit( void );
+
+int usbback_driver_port_init
+(
+    struct usbback_driver_port    * port,
+    struct usbback_driver_backend * backend
+);
+
+void usbback_driver_port_claim
+  ( struct usbback_driver_port * port, char * path );
+
+void usbback_driver_port_release
+  ( struct usbback_driver_port * port );
+
+int usbback_driver_port_probe_usb( struct usb_interface * intf );
+
+void usbback_driver_port_disconnect_usb( struct usb_interface * intf );
+
+/* On success, usbback_driver_port_reset returns */
+/* USBIF_RESET_RESULT_FULL/LOW/HIGH_SPEED */
+
+int usbback_driver_port_reset( struct usbback_driver_port * port );
+
+void usbback_driver_port_set_guest_address
+  ( struct usbback_driver_port * port, unsigned long guest_address );
+
+int usbback_driver_port_match_guest_address
+  ( struct usbback_driver_port * port, unsigned long guest_address );
+
+void usbback_driver_port_connect
+  ( struct usbback_driver_port * port );
+
+void usbback_driver_port_handle_io
+(
+    struct usbback_driver_port  * port,
+    xenidc_endpoint_transaction * transaction
+);
+
+void usbback_driver_port_disconnect
+  ( struct usbback_driver_port * port );
+
+int usbback_driver_port_try_unlink
+  ( struct usbback_driver_port * port, int unlink_id );
+
+void usbback_driver_port_shutdown( struct usbback_driver_port * port );
+
+typedef enum
+{
+    usbback_driver_port_state_i,
+    usbback_driver_port_state_i_pc,
+    usbback_driver_port_state_i_pc_up,
+    usbback_driver_port_state_i_pc_up_pr,
+    usbback_driver_port_state_i_pc_up_ud,
+    usbback_driver_port_state_i_pc_up_sd,
+    usbback_driver_port_state_i_pc_up_pr_ud,
+    usbback_driver_port_state_i_pc_up_pr_ri,
+    usbback_driver_port_state_i_pc_up_ud_sd,
+    usbback_driver_port_state_i_pc_up_sd_ri,
+    usbback_driver_port_state_i_pc_up_pr_ud_ri,
+    usbback_driver_port_state_i_pc_up_ud_sd_ri
+}
+usbback_driver_port_state;
+
+#define USBBACK_DRIVER_PORT_RESOURCE_COUNT 4
+
+struct usbback_driver_port
+{
+    struct usbback_driver_backend * backend;
+    struct list_head                link;
+    char                            path[ 16 ]; /* FIXME: Magic number. */
+    struct usb_device             * usbdev;
+    spinlock_t                      lock;
+    usbback_driver_port_state       state;
+    int                             usbdev_is_connected;
+    int                             enabled;
+    unsigned long                   guest_address;
+    struct list_head                transaction_list;
+    struct list_head                purge_list;
+    struct list_head                free_resource_list;
+    unsigned long                   current_transactions;
+    struct usbback_driver_port_resource resources
+      [ USBBACK_DRIVER_PORT_RESOURCE_COUNT ];
+    xenidc_work                     purge_io_1_work;
+    xenidc_work                     perform_release_1_work;
+    int                             release;
+    int                             usb_disconnect;
+    int                             shutdown;
+};
+
+static inline struct usb_device * usbback_driver_port_query_usbdev
+  ( struct usbback_driver_port * port )
+{
+    trace();
+
+    ASSERT( port->usbdev != NULL );
+
+    return port->usbdev;
+}
+
+static inline int usbback_driver_port_usbdev_is_connected
+  ( struct usbback_driver_port * port )
+{
+  /*    trace(); */
+
+    return port->usbdev_is_connected;
+}
+
+void usbback_driver_port_resource_completed_io
+(
+    struct usbback_driver_port          * port,
+    struct usbback_driver_port_resource * resource
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,1228 @@
+/*****************************************************************************/
+/* Resource which processes a usbback_transaction by translating it into  */
+/* an URB and submitting it to the USB stack.                                */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on arch/xen/drivers/usbif/backend/main.c, original copyright notice */
+/* follows...                                                                */
+/*****************************************************************************/
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ * 
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson
+ * Copyright (c) 2004 Intel Research Cambridge
+ * Copyright (c) 2004, 2005 Mark Williamson
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+#include <asm-xen/xen-public/io/usbif.h>
+#include "usbback_assert.h"
+#include "usbback_driver_port.h"
+#include "usbback_driver_port_resource.h"
+#include "usbback_trace.h"
+
+static XENIDC_CALLBACK_SERIALISER
+  ( usbback_driver_port_resource_submit_urb_serialiser );
+
+static xenidc_rbr_mapper_pool * usbback_driver_port_resource_rbr_mapper_pool;
+
+int usbback_driver_port_resource_class_init( void )
+{
+    trace();
+
+    usbback_driver_port_resource_rbr_mapper_pool =
+      xenidc_allocate_rbr_mapper_pool( USBIF_MAX_PAGES_PER_REQUEST );
+
+    return ( usbback_driver_port_resource_rbr_mapper_pool != NULL ) ?
+      0 : -ENOMEM;
+}
+
+void usbback_driver_port_resource_class_exit( void )
+{
+    trace();
+
+    xenidc_free_rbr_mapper_pool
+      ( usbback_driver_port_resource_rbr_mapper_pool );
+}
+
+typedef enum
+{
+    usbback_driver_port_resource_stimulus_st, /* Start IO          */
+    usbback_driver_port_resource_stimulus_tu, /* Try unlink        */
+    usbback_driver_port_resource_stimulus_ms, /* Map success       */
+    usbback_driver_port_resource_stimulus_mf, /* Map failure       */
+    usbback_driver_port_resource_stimulus_us, /* URB submitted     */
+    usbback_driver_port_resource_stimulus_un, /* URB not submitted */
+    usbback_driver_port_resource_stimulus_uc, /* URB completed     */
+    usbback_driver_port_resource_stimulus_ul, /* Unlink completed  */
+}
+usbback_driver_port_resource_stimulus;
+
+static void usbback_driver_port_resource_handle_stimulus
+(
+    struct usbback_driver_port_resource   * resource,
+    usbback_driver_port_resource_stimulus   stimulus
+);
+
+static void usbback_driver_port_resource_submit_urb_1
+  ( xenidc_callback * callback );
+
+static void usbback_driver_port_resource_unlink_urb_1( void * data );
+
+static void usbback_driver_port_resource_map_callback
+  ( xenidc_callback * callback );
+
+static void usbback_driver_port_resource_unmap_callback
+  ( xenidc_callback * callback );
+
+void usbback_driver_port_resource_init
+(
+    struct usbback_driver_port_resource * resource,
+    struct usbback_driver_port          * port
+)
+{
+    trace();
+
+    resource->port = port;
+
+    INIT_LIST_HEAD( &resource->link );
+
+    spin_lock_init( &resource->lock );
+
+    resource->state = usbback_driver_port_resource_state_i;
+
+    resource->transaction = NULL;
+
+    xenidc_map_rbr_request_element_init( &resource->request_element[ 0 ] );
+    xenidc_map_rbr_request_element_init( &resource->request_element[ 1 ] );
+
+    xenidc_reserve_and_map_rbr_request_init
+    (
+        &resource->reserve_and_map_rbr_request,
+        usbback_driver_port_resource_map_callback,
+        usbback_driver_port_resource_unmap_callback
+    );
+
+    resource->rbrs_mapped = 0;
+
+    xenidc_callback_init
+    (
+        &resource->submit_urb_1_callback,
+        usbback_driver_port_resource_submit_urb_1
+    );
+
+    xenidc_work_init
+    (
+        &resource->unlink_urb_1_work,
+        usbback_driver_port_resource_unlink_urb_1,
+        resource
+    );
+}
+
+void usbback_driver_port_resource_start_io
+(
+    struct usbback_driver_port_resource * resource,
+    xenidc_endpoint_transaction                  * transaction
+)
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &resource->lock, flags );
+
+        resource->transaction_error         = XENIDC_ERROR_SUCCESS;
+        resource->transaction_status_length = 0;
+
+        resource->transaction = transaction;
+
+        usbback_driver_port_resource_handle_stimulus
+          ( resource, usbback_driver_port_resource_stimulus_st );
+
+        spin_unlock_irqrestore( &resource->lock, flags );
+    }
+}
+
+int usbback_driver_port_resource_try_unlink
+  ( struct usbback_driver_port_resource * resource, int unlink_id )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &resource->lock, flags );
+
+        if( resource->transaction != NULL )
+        {
+            usbif_io_transaction_parameters_header header;
+
+            if
+            (
+                (
+                    xenidc_local_buffer_reference_copy_out
+                    (
+                        xenidc_endpoint_transaction_to_parameters_lbr
+                          ( resource->transaction ),
+                        &header,
+                        sizeof( header )
+                    )
+                    ==
+                    sizeof( header )
+                )
+                &&
+                ( header.unlink_id == unlink_id )
+            )
+            {
+                usbback_driver_port_resource_handle_stimulus
+                  ( resource, usbback_driver_port_resource_stimulus_tu );
+
+                return_value = 1;
+            }
+        }
+
+        spin_unlock_irqrestore( &resource->lock, flags );
+
+        return return_value;
+    }
+}
+
+void usbback_driver_port_resource_flush_transaction
+  ( struct usbback_driver_port_resource * resource )
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &resource->lock, flags );
+
+        if( resource->transaction != NULL )
+        {
+            usbback_driver_port_resource_handle_stimulus
+              ( resource, usbback_driver_port_resource_stimulus_tu );
+        }
+
+        spin_unlock_irqrestore( &resource->lock, flags );
+    }
+}
+
+static void usbback_driver_port_resource_invalid_stimulus
+(
+    struct usbback_driver_port_resource   * resource,
+    usbback_driver_port_resource_stimulus   stimulus
+);
+
+static void usbback_driver_port_resource_map_buffer
+  ( struct usbback_driver_port_resource * resource );
+
+static void usbback_driver_port_resource_abort_map
+  ( struct usbback_driver_port_resource * resource );
+
+static void usbback_driver_port_resource_submit_urb
+  ( struct usbback_driver_port_resource * resource );
+
+static void usbback_driver_port_resource_unlink_urb
+  ( struct usbback_driver_port_resource * resource );
+
+static void usbback_driver_port_resource_set_error
+  ( struct usbback_driver_port_resource * resource );
+
+static void usbback_driver_port_resource_complete
+  ( struct usbback_driver_port_resource * resource );
+
+static void usbback_driver_port_resource_handle_stimulus
+(
+    struct usbback_driver_port_resource   * resource,
+    usbback_driver_port_resource_stimulus   stimulus
+)
+{
+    trace3
+    (
+        "port resource %p in state %d received stimulus %d",
+        resource,
+        resource->state,
+        stimulus
+    );
+
+    switch( resource->state )
+    {
+      case usbback_driver_port_resource_state_i:
+        /* Idle */
+        switch( stimulus )
+        {
+          case usbback_driver_port_resource_stimulus_st:
+            resource->state = usbback_driver_port_resource_state_i_st;
+            usbback_driver_port_resource_map_buffer( resource );
+            break;
+          default:
+            usbback_driver_port_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_resource_state_i_st:
+        /* Handling request       */
+        /* map_buffer outstanding */
+        switch( stimulus )
+        {
+          case usbback_driver_port_resource_stimulus_tu:
+            resource->state = usbback_driver_port_resource_state_i_st_tu;
+            usbback_driver_port_resource_abort_map( resource );
+            break;
+          case usbback_driver_port_resource_stimulus_ms:
+            resource->state = usbback_driver_port_resource_state_i_st_ms;
+            usbback_driver_port_resource_submit_urb( resource );
+            break;
+          case usbback_driver_port_resource_stimulus_mf:
+            resource->state = usbback_driver_port_resource_state_i;
+            usbback_driver_port_resource_complete( resource );
+            break;
+          default:
+            usbback_driver_port_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_resource_state_i_st_tu:
+        /* Handling request       */
+        /* map_buffer outstanding */
+        /* unlinking              */
+        switch( stimulus )
+        {
+          case usbback_driver_port_resource_stimulus_tu:
+            break;
+          case usbback_driver_port_resource_stimulus_ms:
+            resource->state = usbback_driver_port_resource_state_i;
+            usbback_driver_port_resource_set_error( resource );
+            usbback_driver_port_resource_complete( resource );
+            break;
+          case usbback_driver_port_resource_stimulus_mf:
+            resource->state = usbback_driver_port_resource_state_i;
+            usbback_driver_port_resource_complete( resource );
+            break;
+          default:
+            usbback_driver_port_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_resource_state_i_st_ms:
+        /* Handling request       */
+        /* submit_urb outstanding */
+        switch( stimulus )
+        {
+          case usbback_driver_port_resource_stimulus_tu:
+            resource->state = usbback_driver_port_resource_state_i_st_ms_tu;
+            break;
+          case usbback_driver_port_resource_stimulus_us:
+            resource->state = usbback_driver_port_resource_state_i_st_ms_us;
+            break;
+          case usbback_driver_port_resource_stimulus_un:
+            resource->state = usbback_driver_port_resource_state_i;
+            usbback_driver_port_resource_complete( resource );
+            break;
+          case usbback_driver_port_resource_stimulus_uc:
+            resource->state = usbback_driver_port_resource_state_i_st_ms_uc;
+            break;
+          default:
+            usbback_driver_port_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_resource_state_i_st_ms_tu:
+        /* Handling request       */
+        /* submit_urb outstanding */
+        /* unlinking              */
+        switch( stimulus )
+        {
+          case usbback_driver_port_resource_stimulus_tu:
+            break;
+          case usbback_driver_port_resource_stimulus_us:
+            resource->state = usbback_driver_port_resource_state_i_st_ms_tu_us;
+            usbback_driver_port_resource_unlink_urb( resource );
+            break;
+          case usbback_driver_port_resource_stimulus_un:
+            resource->state = usbback_driver_port_resource_state_i;
+            usbback_driver_port_resource_complete( resource );
+            break;
+          case usbback_driver_port_resource_stimulus_uc:
+            resource->state = usbback_driver_port_resource_state_i_st_ms_uc;
+            break;
+          default:
+            usbback_driver_port_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_resource_state_i_st_ms_us:
+        /* Handling request */
+        /* URB submitted    */
+        switch( stimulus )
+        {
+          case usbback_driver_port_resource_stimulus_tu:
+            resource->state = usbback_driver_port_resource_state_i_st_ms_tu_us;
+            usbback_driver_port_resource_unlink_urb( resource );
+            break;
+          case usbback_driver_port_resource_stimulus_uc:
+            resource->state = usbback_driver_port_resource_state_i;
+            usbback_driver_port_resource_complete( resource );
+            break;
+          default:
+            usbback_driver_port_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_resource_state_i_st_ms_uc:
+        /* Handling request       */
+        /* submit_urb outstanding */
+        /* URB completed          */
+        switch( stimulus )
+        {
+          case usbback_driver_port_resource_stimulus_tu:
+            break;
+          case usbback_driver_port_resource_stimulus_us:
+            resource->state = usbback_driver_port_resource_state_i;
+            usbback_driver_port_resource_complete( resource );
+            break;
+          default:
+            usbback_driver_port_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_resource_state_i_st_ms_tu_us:
+        /* Handling request       */
+        /* URB submitted    */
+        /* unlink_urb outstanding */
+        switch( stimulus )
+        {
+          case usbback_driver_port_resource_stimulus_tu:
+            break;
+          case usbback_driver_port_resource_stimulus_uc:
+          case usbback_driver_port_resource_stimulus_ul:
+            resource->state =
+              usbback_driver_port_resource_state_i_st_ms_tu_us_uc;
+            break;
+          default:
+            usbback_driver_port_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      case usbback_driver_port_resource_state_i_st_ms_tu_us_uc:
+        /* Handling request                        */
+        /* URB submitted or unlink_urb outstanding */
+        switch( stimulus )
+        {
+          case usbback_driver_port_resource_stimulus_tu:
+            break;
+          case usbback_driver_port_resource_stimulus_uc:
+          case usbback_driver_port_resource_stimulus_ul:
+            resource->state = usbback_driver_port_resource_state_i;
+            usbback_driver_port_resource_complete( resource );
+            break;
+          default:
+            usbback_driver_port_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      default:
+        usbback_driver_port_resource_invalid_stimulus( resource, stimulus );
+        break;
+    }
+}
+
+static void usbback_driver_port_resource_invalid_stimulus
+(
+    struct usbback_driver_port_resource   * resource,
+    usbback_driver_port_resource_stimulus   stimulus
+)
+{
+    trace();
+
+    printk
+    (
+        KERN_ERR "usbback: port resource %p in state %d"
+        "received invalid stimulus %d",
+        resource,
+        resource->state,
+        stimulus
+    );
+}
+
+static void usbback_driver_port_resource_map_buffer
+  ( struct usbback_driver_port_resource * resource )
+{
+    trace();
+
+    {
+        usbif_io_transaction_parameters_header header;
+
+        if
+        (
+            xenidc_local_buffer_reference_copy_out
+            (
+                xenidc_endpoint_transaction_to_parameters_lbr
+                  ( resource->transaction ),
+                &header,
+                sizeof( header )
+            )
+            !=
+            sizeof( header )
+        )
+        {
+            goto FORMAT_ERROR;
+        }
+
+        xenidc_map_rbr_request_element_ensure_removed
+          ( &resource->request_element[ 0 ] );
+
+        xenidc_map_rbr_request_element_ensure_removed
+          ( &resource->request_element[ 1 ] );
+
+        xenidc_reserve_and_map_rbr_request_add_element
+        (
+            &resource->reserve_and_map_rbr_request,
+            &resource->request_element[ 0 ]
+        );
+
+        xenidc_map_rbr_request_element_set_rbr
+        (
+            &resource->request_element[ 0 ],
+            header.rbr
+        );
+
+        if
+        (
+            header.io_transaction_type
+            ==
+            USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS
+        )
+        {
+            usbif_isochronous_io_transaction_parameters parameters;
+
+            if
+            (
+                xenidc_local_buffer_reference_copy_out
+                (
+                    xenidc_endpoint_transaction_to_parameters_lbr
+                      ( resource->transaction ),
+                    &parameters,
+                    sizeof( parameters )
+                )
+                !=
+                sizeof( parameters )
+            )
+            {
+                goto FORMAT_ERROR;
+            }
+
+            xenidc_reserve_and_map_rbr_request_add_element
+            (
+                &resource->reserve_and_map_rbr_request,
+                &resource->request_element[ 1 ]
+            );
+
+            xenidc_map_rbr_request_element_set_rbr
+            (
+                &resource->request_element[ 1 ],
+                parameters.schedule_rbr
+            );
+        }
+
+        xenidc_rbr_mapper_pool_reserve_and_map_rbrs
+        (
+            usbback_driver_port_resource_rbr_mapper_pool,
+            &resource->reserve_and_map_rbr_request
+        );
+    }
+
+    return;
+
+  FORMAT_ERROR:
+
+    resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT;
+
+    usbback_driver_port_resource_handle_stimulus
+      ( resource, usbback_driver_port_resource_stimulus_mf );
+}
+
+static void usbback_driver_port_resource_abort_map
+  ( struct usbback_driver_port_resource * resource )
+{
+    trace();
+
+    xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs
+    (
+        usbback_driver_port_resource_rbr_mapper_pool,
+        &resource->reserve_and_map_rbr_request
+    );
+}
+
+static void usbback_driver_port_resource_map_callback
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_reserve_and_map_rbr_request * request =
+          xenidc_reserve_and_map_rbr_request_map_callback_to( callback );
+
+        struct usbback_driver_port_resource * resource = container_of
+        (
+            request,
+            struct usbback_driver_port_resource,
+            reserve_and_map_rbr_request
+        );
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &resource->lock, flags );
+
+            resource->transaction_error =
+              xenidc_callback_query_error( callback );
+
+            if
+            (
+                resource->transaction_error
+                ==
+                XENIDC_ERROR_SUCCESS
+            )
+            {
+                resource->rbrs_mapped = 1;
+
+                usbback_driver_port_resource_handle_stimulus
+                  ( resource, usbback_driver_port_resource_stimulus_ms );
+            }
+            else
+            {
+                usbback_driver_port_resource_handle_stimulus
+                  ( resource, usbback_driver_port_resource_stimulus_mf );
+            }
+
+            spin_unlock_irqrestore( &resource->lock, flags );
+        }
+    }
+}
+
+static void usbback_driver_port_resource_submit_urb
+  ( struct usbback_driver_port_resource * resource )
+{
+    trace();
+
+    xenidc_callback_serialiser_complete_callback
+    (
+        &usbback_driver_port_resource_submit_urb_serialiser,
+        &resource->submit_urb_1_callback,
+        0
+    );
+}
+
+static void usbback_driver_port_resource_end_io
+  ( struct urb * urb, struct pt_regs * regs );
+
+static int check_iso_schedule( struct urb * urb )
+{
+    int i;
+
+    unsigned long total_length = 0;
+
+    for( i = 0; i < urb->number_of_packets; i++ )
+    {
+        struct usb_iso_packet_descriptor * desc = &urb->iso_frame_desc[ i ];
+
+        total_length += desc->length;
+
+        if
+        (
+            ( desc->offset > urb->transfer_buffer_length )
+            ||
+            ( desc->length > ( urb->transfer_buffer_length - desc->offset ) )
+            ||
+            ( total_length > urb->transfer_buffer_length )
+        )
+        {
+            return -EINVAL;
+        }
+    }
+
+    return 0;
+}
+
+static void usbback_driver_port_resource_submit_urb_1
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        struct usbback_driver_port_resource * resource = container_of
+        (
+            callback,
+            struct usbback_driver_port_resource,
+            submit_urb_1_callback
+        );
+
+        usbif_io_transaction_parameters io_parameters;
+
+        {
+            xenidc_buffer_byte_count io_parameters_byte_count =
+              xenidc_local_buffer_reference_copy_out
+            (
+                xenidc_endpoint_transaction_to_parameters_lbr
+                  ( resource->transaction ),
+                &io_parameters,
+                sizeof( io_parameters )
+            );
+
+            if( io_parameters_byte_count < sizeof( io_parameters.header ) )
+            {
+                resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT;
+
+                goto FORMAT_ERROR;
+            }
+
+            if
+            (
+                io_parameters.header.io_transaction_type
+                >=
+                USBIF_IO_TRANSACTION_TYPE_LIMIT
+            )
+            {
+                resource->transaction_error = XENIDC_ERROR_INVALID_PARAMETER;
+
+                goto FORMAT_ERROR;
+            }
+
+            if
+            (
+                io_parameters_byte_count
+                <
+                usbif_io_parameters_byte_count
+                  [ io_parameters.header.io_transaction_type ]
+            )
+            {
+                resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT;
+
+                goto FORMAT_ERROR;
+            }
+        }
+
+        if
+        (
+            io_parameters.header.io_transaction_type
+            ==
+            USBIF_IO_TRANSACTION_TYPE_CONTROL
+        )
+        {
+            struct usb_ctrlrequest * ctrl =
+              (struct usb_ctrlrequest *)io_parameters.control.setup;
+
+            if
+            (
+                ctrl->bRequestType
+                ==
+                ( USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE )
+            )
+            {
+                if( ctrl->bRequest == USB_REQ_SET_ADDRESS )
+                {
+                    usbback_driver_port_set_guest_address
+                      ( resource->port, le16_to_cpu( ctrl->wValue ) );
+
+                    goto HANDLED_SPECIAL_CASE;
+                }
+                else if( ctrl->bRequest == USB_REQ_SET_CONFIGURATION )
+                {
+                    /* FIXME: what to do for set configuration? */
+
+                    goto HANDLED_SPECIAL_CASE;
+                }
+            }
+        }
+
+        {
+            struct urb * urb = resource->urb = usb_alloc_urb
+            (
+                (
+                    io_parameters.header.io_transaction_type
+                    ==
+                    USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS
+                )
+                ? io_parameters.isochronous.packet_count : 0,
+                GFP_KERNEL
+            );
+
+            static const unsigned int pipe_type
+              [ USBIF_IO_TRANSACTION_TYPE_LIMIT ] =
+            {
+                [ USBIF_IO_TRANSACTION_TYPE_CONTROL     ] = PIPE_CONTROL,
+                [ USBIF_IO_TRANSACTION_TYPE_BULK        ] = PIPE_BULK,
+                [ USBIF_IO_TRANSACTION_TYPE_INTERRUPT   ] = PIPE_INTERRUPT,
+                [ USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS ] = PIPE_ISOCHRONOUS
+            };
+
+            unsigned int pipe =
+            (
+                (
+                    (
+                        (
+                            io_parameters.header.direction
+                            ==
+                            USBIF_IO_TRANSACTION_DIRECTION_OUT
+                        )
+                        ? USB_DIR_OUT : USB_DIR_IN
+                    )
+                    << 7
+                )
+                |
+                (
+                    (unsigned int)usbback_driver_port_query_usbdev
+                      ( resource->port )->devnum
+                    <<
+                    8
+                )
+                |
+                ( (unsigned int)io_parameters.header.endpoint << 15 )
+                |
+                ( pipe_type[ io_parameters.header.io_transaction_type ] << 30 )
+            );
+
+            if( urb == NULL )
+            {
+                /* FIXME: better URB resource management should let us queue */
+                /* for an URB and ISO resources from a reserved pool which   */
+                /* would eliminate the possibility of failure at this point. */
+
+                resource->transaction_error =
+                  XENIDC_ERROR_IMPLEMENTATION_DEFICIENCY;
+
+                goto NO_URB;
+            }
+
+            if
+            (
+                io_parameters.header.io_transaction_type
+                ==
+                USBIF_IO_TRANSACTION_TYPE_CONTROL
+            )
+            {
+                memcpy
+                (
+                    resource->setup,
+                    io_parameters.control.setup,
+                    sizeof( resource->setup )
+                );
+
+                usb_fill_control_urb
+                (
+                    urb,
+                    usbback_driver_port_query_usbdev( resource->port ),
+                    pipe,
+                    resource->setup,
+                    resource->request_element[ 0 ].mapping,
+                    xenidc_remote_buffer_reference_query_byte_count
+                      ( &resource->request_element[ 0 ].rbr ),
+                    usbback_driver_port_resource_end_io,
+                    resource
+                );
+            }
+            else if
+            (
+                io_parameters.header.io_transaction_type
+                ==
+                USBIF_IO_TRANSACTION_TYPE_BULK
+            )
+            {
+                usb_fill_bulk_urb
+                (
+                    urb,
+                    usbback_driver_port_query_usbdev( resource->port ),
+                    pipe,
+                    resource->request_element[ 0 ].mapping,
+                    xenidc_remote_buffer_reference_query_byte_count
+                      ( &resource->request_element[ 0 ].rbr ),
+                    usbback_driver_port_resource_end_io,
+                    resource
+                );
+            }
+            else if
+            (
+                io_parameters.header.io_transaction_type
+                ==
+                USBIF_IO_TRANSACTION_TYPE_INTERRUPT
+            )
+            {
+                /* FIXME: hacking the interval like this is a bit unclean. */
+                /* should probably convert back to exponential form for    */
+                /* high speed transfers and then pass the value into       */
+                /* fill_int_urb.                                           */
+                usb_fill_int_urb
+                (
+                    urb,
+                    usbback_driver_port_query_usbdev( resource->port ),
+                    pipe,
+                    resource->request_element[ 0 ].mapping,
+                    xenidc_remote_buffer_reference_query_byte_count
+                      ( &resource->request_element[ 0 ].rbr ),
+                    usbback_driver_port_resource_end_io,
+                    resource,
+                    1 /* For the time being... */
+                );
+
+                /* ...now set the real value. */
+                urb->interval = io_parameters.interrupt.interval;
+            }
+            else
+            {
+                ASSERT
+                (
+                    io_parameters.header.io_transaction_type
+                    ==
+                    USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS
+                );
+
+                /* FIXME: where's usb_fill_isoc_urb ?!? */
+
+                spin_lock_init(&urb->lock);
+                urb->dev = usbback_driver_port_query_usbdev( resource->port );
+                urb->pipe = pipe;
+                urb->transfer_buffer = resource->request_element[ 0 ].mapping;
+                urb->transfer_buffer_length =
+                  xenidc_remote_buffer_reference_query_byte_count
+                    ( &resource->request_element[ 0 ].rbr );
+                urb->complete = usbback_driver_port_resource_end_io;
+                urb->context = resource;
+                urb->number_of_packets =
+                  io_parameters.isochronous.packet_count;
+                urb->interval = io_parameters.isochronous.interval;
+                urb->start_frame = 0;
+                urb->transfer_flags |= URB_ISO_ASAP;
+
+                if
+                (
+                    xenidc_remote_buffer_reference_query_byte_count
+                      ( &resource->request_element[ 1 ].rbr )
+                    <
+                    (
+                        io_parameters.isochronous.packet_count
+                        *
+                        sizeof( usbif_isochronous_io_schedule_element )
+                    )
+                )
+                {
+                    resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT;
+
+                    goto SCHEDULE_ERROR;
+                }
+
+                {
+                    usbif_isochronous_io_schedule_element * schedule_element =
+                      resource->request_element[ 1 ].mapping;
+
+                    usbif_isochronous_io_schedule_element aligned_element;
+
+                    int i;
+
+                    for
+                    (
+                        i = 0;
+                        i < io_parameters.isochronous.packet_count;
+                        i++
+                    )
+                    {
+                        memcpy
+                        (
+                            &aligned_element,
+                            schedule_element++,
+                            sizeof( aligned_element )
+                        );
+
+                        urb->iso_frame_desc[ i ].offset =
+                          aligned_element.offset;
+                        urb->iso_frame_desc[ i ].length =
+                          aligned_element.length;
+
+                        urb->iso_frame_desc[ i ].actual_length = 0;
+                        urb->iso_frame_desc[ i ].status        = 0;
+                    }
+                }
+
+                if( !check_iso_schedule( urb ) )
+                {
+                    resource->transaction_error =
+                      XENIDC_ERROR_INVALID_PARAMETER;
+
+                    goto SCHEDULE_ERROR;
+                }
+            }
+
+            /* On the backend, all unlinks are asynchronous. */
+
+            urb->transfer_flags |= URB_ASYNC_UNLINK;
+
+            if( io_parameters.header.flags & USBIF_IO_FLAGS_SHORT_NOT_OK )
+            {
+                urb->transfer_flags |= URB_SHORT_NOT_OK;
+            }
+            if( io_parameters.header.flags & USBIF_IO_FLAGS_ZERO_PACKET )
+            {
+                urb->transfer_flags |= URB_ZERO_PACKET;
+            }
+
+            if( usb_submit_urb( urb, GFP_KERNEL ) != 0 )
+            {
+                printk( KERN_WARNING "URB %p submission failed.\n", urb );
+
+                /* FIXME: non-specific failure return. */
+                resource->transaction_error = USBIF_XENIDC_ERROR_FAILURE;
+
+                goto URB_ERROR;
+            }
+
+            {
+                unsigned long flags;
+
+                spin_lock_irqsave( &resource->lock, flags );
+
+                usbback_driver_port_resource_handle_stimulus
+                  ( resource, usbback_driver_port_resource_stimulus_us );
+
+                spin_unlock_irqrestore( &resource->lock, flags );
+            }
+
+            return;
+
+          URB_ERROR:
+
+          SCHEDULE_ERROR:
+
+            usb_free_urb( urb );
+        }
+
+      NO_URB:
+
+      HANDLED_SPECIAL_CASE:
+
+      FORMAT_ERROR:
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &resource->lock, flags );
+
+            usbback_driver_port_resource_handle_stimulus
+              ( resource, usbback_driver_port_resource_stimulus_un );
+
+            spin_unlock_irqrestore( &resource->lock, flags );
+        }
+    }
+}
+
+static void usbback_driver_port_resource_end_io
+  ( struct urb * urb, struct pt_regs * regs )
+{
+    trace();
+
+    {
+        struct usbback_driver_port_resource * resource = urb->context;
+
+        if( urb->status != 0 )
+        {
+            printk
+              ( KERN_WARNING "URB %p failed. Status %d\n", urb, urb->status );
+
+            resource->transaction_error = USBIF_XENIDC_ERROR_FAILURE;
+        }
+
+        resource->transaction_status_length = urb->actual_length;
+
+        if( usb_pipetype( urb->pipe ) == PIPE_ISOCHRONOUS )
+        {
+            usbif_isochronous_io_schedule_element * schedule_element =
+              resource->request_element[ 1 ].mapping;
+
+            usbif_isochronous_io_schedule_element aligned_element;
+
+            int i;
+
+            for( i = 0; i < urb->number_of_packets; i++ )
+            {
+                aligned_element.length =
+                  urb->iso_frame_desc[ i ].actual_length;
+                aligned_element.error =
+                  ( urb->iso_frame_desc[ i ].status == 0 ) ?
+                    XENIDC_ERROR_SUCCESS : USBIF_XENIDC_ERROR_FAILURE;
+
+                memcpy
+                (
+                    schedule_element++,
+                    &aligned_element,
+                    sizeof( *schedule_element )
+                );
+            }
+        }
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &resource->lock, flags );
+
+            usbback_driver_port_resource_handle_stimulus
+              ( resource, usbback_driver_port_resource_stimulus_uc );
+
+            spin_unlock_irqrestore( &resource->lock, flags );
+        }
+    }
+
+    usb_free_urb( urb );
+}
+
+static void usbback_driver_port_resource_unlink_urb
+  ( struct usbback_driver_port_resource * resource )
+{
+    trace();
+
+    usb_get_urb( resource->urb );
+
+    {
+        int scheduled = xenidc_work_schedule( &resource->unlink_urb_1_work );
+
+        ASSERT( scheduled );
+    }
+}
+
+static void usbback_driver_port_resource_unlink_urb_1( void * data )
+{
+    trace();
+
+    {
+        struct usbback_driver_port_resource * resource =
+          (struct usbback_driver_port_resource *)data;
+
+        usb_unlink_urb( resource->urb );
+
+        usb_put_urb( resource->urb );
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &resource->lock, flags );
+
+            usbback_driver_port_resource_handle_stimulus
+              ( resource, usbback_driver_port_resource_stimulus_ul );
+
+            spin_unlock_irqrestore( &resource->lock, flags );
+        }
+    }
+}
+
+static void usbback_driver_port_resource_set_error
+  ( struct usbback_driver_port_resource * resource )
+{
+    trace();
+
+    resource->transaction_error = USBIF_XENIDC_ERROR_FAILURE;
+}
+
+static void usbback_driver_port_resource_complete
+  ( struct usbback_driver_port_resource * resource )
+{
+    trace();
+
+    resource->completing_transaction = resource->transaction;
+    resource->transaction = NULL;
+
+    if( resource->rbrs_mapped )
+    {
+        resource->rbrs_mapped = 0;
+
+        xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs
+        (
+            usbback_driver_port_resource_rbr_mapper_pool,
+            &resource->reserve_and_map_rbr_request
+        );
+    }
+    else
+    {
+        xenidc_callback_success
+        (
+            xenidc_reserve_and_map_rbr_request_to_unmap_callback
+              ( &resource->reserve_and_map_rbr_request )
+        );
+    }
+}
+
+static void usbback_driver_port_resource_unmap_callback
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_reserve_and_map_rbr_request * request =
+          xenidc_reserve_and_map_rbr_request_unmap_callback_to( callback );
+
+        struct usbback_driver_port_resource * resource = container_of
+        (
+            request,
+            struct usbback_driver_port_resource,
+            reserve_and_map_rbr_request
+        );
+
+        usbif_io_transaction_status status;
+
+        status.length = resource->transaction_status_length;
+
+        if
+        (
+            xenidc_local_buffer_reference_copy_in
+            (
+                xenidc_endpoint_transaction_to_status_lbr
+                  ( resource->completing_transaction ),
+                &status,
+                sizeof( status )
+            )
+            !=
+            sizeof( status )
+        )
+        {
+            resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT;
+        }
+
+        xenidc_endpoint_transaction_complete
+          ( resource->completing_transaction, resource->transaction_error );
+
+        usbback_driver_port_resource_completed_io( resource->port, resource );
+    }
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,87 @@
+/*****************************************************************************/
+/* Resource which processes an io transaction by translating it into an URB  */
+/* and submitting it to the USB stack.                                       */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_DRIVER_PORT_RESOURCE_H
+#define USBBACK_DRIVER_PORT_RESOURCE_H
+
+#include <asm-xen/xenidc.h>
+#include "usbback_device.h"
+
+int usbback_driver_port_resource_class_init( void );
+
+void usbback_driver_port_resource_class_exit( void );
+
+struct usbback_driver_port;
+struct usbback_driver_port_resource;
+
+void usbback_driver_port_resource_init
+(
+    struct usbback_driver_port_resource * resource,
+    struct usbback_driver_port          * port
+);
+
+void usbback_driver_port_resource_start_io
+(
+    struct usbback_driver_port_resource * resource,
+    xenidc_endpoint_transaction                  * transaction
+);
+
+int usbback_driver_port_resource_try_unlink
+  ( struct usbback_driver_port_resource * resource, int unlink_id );
+
+void usbback_driver_port_resource_flush_transaction
+  ( struct usbback_driver_port_resource * resource );
+
+typedef enum
+{
+    usbback_driver_port_resource_state_i,
+    usbback_driver_port_resource_state_i_st,
+    usbback_driver_port_resource_state_i_st_tu,
+    usbback_driver_port_resource_state_i_st_ms,
+    usbback_driver_port_resource_state_i_st_ms_tu,
+    usbback_driver_port_resource_state_i_st_ms_us,
+    usbback_driver_port_resource_state_i_st_ms_uc,
+    usbback_driver_port_resource_state_i_st_ms_tu_us,
+    usbback_driver_port_resource_state_i_st_ms_tu_us_uc
+}
+usbback_driver_port_resource_state;
+
+struct usbback_driver_port_resource
+{
+    struct usbback_driver_port         * port;
+    struct list_head                     link;
+    spinlock_t                           lock;
+    usbback_driver_port_resource_state   state;
+    xenidc_error                         transaction_error;
+    unsigned long                        transaction_status_length;
+    xenidc_endpoint_transaction        * transaction;
+    xenidc_endpoint_transaction        * completing_transaction;
+    xenidc_reserve_and_map_rbr_request   reserve_and_map_rbr_request;
+    xenidc_map_rbr_request_element       request_element[ 2 ];
+    int                                  rbrs_mapped;
+    struct urb                         * urb;
+    u8                                   setup[ 8 ];
+    xenidc_callback                      submit_urb_1_callback;
+    xenidc_work                          unlink_urb_1_work;
+};
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,83 @@
+/*****************************************************************************/
+/* Back-end module for Xen USB split driver.                                 */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbback_driver.h"
+#include "usbback_device.h"
+#include "usbback_trace.h"
+
+static int usbback_module_init_or_exit( int exit )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        if( exit )
+        {
+            goto EXIT;
+        }
+
+        if( ( return_value = usbback_driver_init() ) != 0 )
+        {
+            goto EXIT_NO_DRIVER;
+        }
+
+        if( ( return_value = usbback_device_class_init() ) != 0 )
+        {
+            goto EXIT_NO_DEVICE_CLASS;
+        }
+
+        return 0;
+
+      EXIT:
+
+        usbback_device_class_exit();
+
+      EXIT_NO_DEVICE_CLASS:
+
+        usbback_driver_exit();
+
+      EXIT_NO_DRIVER:
+
+        return return_value;
+    }
+}
+
+static int __init usbback_module_init( void )
+{
+    trace();
+
+    return usbback_module_init_or_exit( 0 );
+}
+
+static void __exit usbback_module_exit( void )
+{
+    trace();
+
+    (void)usbback_module_init_or_exit( 1 );
+}
+
+module_init( usbback_module_init );
+module_exit( usbback_module_exit );
+
+MODULE_LICENSE( "GPL" );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,54 @@
+/*****************************************************************************/
+/* Simple trace macros                                                       */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBBACK_TRACE_H
+#define USBBACK_TRACE_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_XEN_USBDEV_BACKEND_TRACE
+
+#define trace0( format ) \
+printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__ )
+
+#define trace1( format, a0 ) \
+printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__, a0 )
+
+#define trace2( format, a0, a1 ) \
+printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__, a0, a1 )
+
+#define trace3( format, a0, a1, a2 ) \
+printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__, a0, a1, a2 )
+
+#define trace() trace0( "" )
+
+#else
+
+#define trace0( format )
+#define trace1( format,a0 )
+#define trace2( format,a0, a1 )
+#define trace3( format,a0, a1, a2 )
+#define trace()
+
+#endif
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,7 @@
+obj-$(CONFIG_XEN_USBDEV_FRONTEND) += usbfront.o
+
+usbfront-objs :=  \
+usbfront_hcd_resource.o \
+usbfront_driver.o \
+usbfront_device.o \
+usbfront_module.o
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_assert.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_assert.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,44 @@
+/*****************************************************************************/
+/* An implementation of the ASSERT macro.                                    */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBFRONT_ASSERT_H
+#define USBFRONT_ASSERT_H
+
+#include <linux/kernel.h>
+
+static inline void assert_failed
+  ( const char * function, int line, const char * statement )
+{
+    printk
+    (
+        KERN_ERR "usbfront assert failed: %s line %d, statement %s\n",
+        function,
+        line,
+        statement
+    );
+
+    BUG();
+}
+
+#define ASSERT( S ) \
+( ( S ) ? ( (void)0 ) : assert_failed( __PRETTY_FUNCTION__, __LINE__, #S ) )
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,1314 @@
+/*****************************************************************************/
+/* usbfront_device is a device which represents a connection to a back-end.  */
+/* The intent was for it to have an interface like a hardware USB host       */
+/* controller device.                                                        */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on arch/xen/drivers/usbif/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@cl.cam.ac.uk> or
+ * <xen-devel@lists.sourceforge.net> 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@erdfelt.com>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (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@rustcorp.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/* FIXME: check all port numbering is one based */
+
+#include <asm-xen/xenbus.h>
+#include <asm-xen/xenidc.h>
+#include <asm-xen/xenidc_vaddress.h>
+#include "usbfront_assert.h"
+#include "usbfront_device.h"
+#include "usbfront_driver.h"
+#include "usbfront_trace.h"
+
+#define USBFRONT_DEVICE_PORT_COUNT 7
+
+typedef enum
+{
+    usbfront_device_state_i,
+    usbfront_device_state_i_cn,
+    usbfront_device_state_i_cn_dn,
+    usbfront_device_state_i_cn_ps,
+    usbfront_device_state_i_cn_pf,
+    usbfront_device_state_i_cn_dn_ps,
+    usbfront_device_state_i_cn_ps_dn,
+    usbfront_device_state_i_cn_ps_pc,
+    usbfront_device_state_i_cn_ps_dn_rc
+}
+usbfront_device_state;
+
+typedef enum
+{
+    usbfront_device_stimulus_cn, /* Endpoint connect.       */
+    usbfront_device_stimulus_dn, /* Endpoint disconnect.    */
+    usbfront_device_stimulus_ps, /* Probe driver success.   */
+    usbfront_device_stimulus_pf, /* Probe driver failure.   */
+    usbfront_device_stimulus_rc, /* Remove driver complete. */
+    usbfront_device_stimulus_pt, /* Polling tick.           */
+    usbfront_device_stimulus_pc  /* Probe complete.         */
+}
+usbfront_device_stimulus;
+
+struct usbfront_device;
+
+struct usbfront_device_probe_transaction
+{
+    xenidc_endpoint_transaction transaction;
+
+    union
+    {
+        struct
+        {
+            usbif_probe_transaction_parameters parameters;
+            usbif_probe_transaction_status     status;
+        }
+        probe;
+        struct
+        {
+            usbif_reset_transaction_parameters parameters;
+            usbif_reset_transaction_status     status;
+        }
+        reset;
+    };
+
+    struct usbfront_device * device;
+};
+
+struct usbfront_device
+{
+    struct xenbus_device * dev;
+    void                 * drvdata;
+    spinlock_t             lock;
+    usbfront_device_state  state;
+    long int               backend_id;
+    char                 * backend;
+    xenidc_endpoint        endpoint;
+    xenidc_callback      * endpoint_disconnect_callback;
+    int                    tick_count;
+    int                    port_probe_count;
+    struct usbfront_device_probe_transaction
+      probe_transaction[ USBFRONT_DEVICE_PORT_COUNT ];
+    struct usb_port_status port_status[ USBFRONT_DEVICE_PORT_COUNT ];
+    xenidc_work            probe_driver_1_work;
+    xenidc_work            remove_driver_1_work;
+};
+
+static void usbfront_device_handle_stimulus
+  ( struct usbfront_device * device, usbfront_device_stimulus stimulus );
+
+static inline struct usbfront_device * usbfront_device_endpoint_to
+  ( xenidc_endpoint * endpoint )
+{
+    trace();
+
+    return container_of( endpoint, struct usbfront_device, endpoint );
+}
+
+void usbfront_device_set_drvdata
+  ( struct usbfront_device * device, void * data )
+{
+    trace();
+
+    device->drvdata = data;
+}
+
+void * usbfront_device_get_drvdata( struct usbfront_device * device )
+{
+    trace();
+
+    return device->drvdata;
+}
+
+struct device * usbfront_device_to_dev( struct usbfront_device * device )
+{
+    trace();
+
+    return &device->dev->dev;
+}
+
+struct usbfront_device * usbfront_device_dev_to( struct device * dev )
+{
+    trace();
+
+    return to_xenbus_device( dev )->data;
+}
+
+int usbfront_device_query_port_count( struct usbfront_device * device )
+{
+    /* trace(); */
+
+    return USBFRONT_DEVICE_PORT_COUNT;
+}
+
+int usbfront_device_query_port_status_changed
+  ( struct usbfront_device * device, int port_number )
+{
+    /* trace(); */
+
+    ASSERT
+    (
+        ( port_number > 0 )
+        &&
+        ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+    );
+
+    {
+        int changed;
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &device->lock, flags );
+
+        if( ++device->tick_count == USBFRONT_DEVICE_PORT_COUNT )
+        {
+            device->tick_count = 0;
+
+            usbfront_device_handle_stimulus
+              ( device, usbfront_device_stimulus_pt );
+        }
+
+        changed = ( device->port_status[ port_number - 1 ].wPortChange != 0 );
+
+        spin_unlock_irqrestore( &device->lock, flags );
+
+        return changed;
+    }
+}
+
+struct usb_port_status usbfront_device_query_port_status
+  ( struct usbfront_device * device, int port_number )
+{
+    trace();
+
+    ASSERT
+    (
+        ( port_number > 0 )
+        &&
+        ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+    );
+
+    {
+        struct usb_port_status port_status;
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &device->lock, flags );
+
+        port_status = device->port_status[ port_number - 1 ];
+
+        spin_unlock_irqrestore( &device->lock, flags );
+
+        return port_status;
+    }
+}
+
+void usbfront_device_set_port_power
+  ( struct usbfront_device * device, int port_number )
+{
+    trace();
+
+    ASSERT
+    (
+        ( port_number > 0 )
+        &&
+        ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+    );
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &device->lock, flags );
+
+        device->port_status[ port_number - 1 ].wPortStatus |=
+          USB_PORT_STAT_POWER;
+
+        spin_unlock_irqrestore( &device->lock, flags );
+    }
+}
+
+void usbfront_device_set_port_reset
+  ( struct usbfront_device * device, int port_number )
+{
+    trace();
+
+    ASSERT
+    (
+        ( port_number > 0 )
+        &&
+        ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+    );
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &device->lock, flags );
+
+        device->port_status[ port_number - 1 ].wPortStatus |=
+          USB_PORT_STAT_RESET;
+        device->port_status[ port_number - 1 ].wPortStatus &=
+          ~USB_PORT_STAT_ENABLE;
+
+        usbfront_device_handle_stimulus( device, usbfront_device_stimulus_pt );
+
+        spin_unlock_irqrestore( &device->lock, flags );
+    }
+}
+
+void usbfront_device_clear_port_enable
+  ( struct usbfront_device * device, int port_number )
+{
+    trace();
+
+    ASSERT
+    (
+        ( port_number > 0 )
+        &&
+        ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+    );
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &device->lock, flags );
+
+        device->port_status[ port_number - 1 ].wPortStatus &=
+          ~USB_PORT_STAT_ENABLE;
+
+        spin_unlock_irqrestore( &device->lock, flags );
+    }
+}
+
+void usbfront_device_clear_port_connection_change
+  ( struct usbfront_device * device, int port_number )
+{
+    trace();
+
+    ASSERT
+    (
+        ( port_number > 0 )
+        &&
+        ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+    );
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &device->lock, flags );
+
+        device->port_status[ port_number - 1 ].wPortChange &=
+          ~USB_PORT_STAT_C_CONNECTION;
+
+        spin_unlock_irqrestore( &device->lock, flags );
+    }
+}
+
+void usbfront_device_clear_port_reset_change
+  ( struct usbfront_device * device, int port_number )
+{
+    trace();
+
+    ASSERT
+    (
+        ( port_number > 0 )
+        &&
+        ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+    );
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &device->lock, flags );
+
+        device->port_status[ port_number - 1 ].wPortChange &=
+          ~USB_PORT_STAT_C_RESET;
+
+        spin_unlock_irqrestore( &device->lock, flags );
+    }
+}
+
+void usbfront_device_submit_message
+  ( struct usbfront_device * device, xenidc_endpoint_message * message )
+{
+    trace();
+
+    xenidc_endpoint_submit_message( &device->endpoint, message );
+}
+
+void usbfront_device_submit_transaction
+  ( struct usbfront_device * device, xenidc_endpoint_transaction * transaction )
+{
+    trace();
+
+    xenidc_endpoint_submit_transaction( &device->endpoint, transaction );
+}
+
+static void usbfront_device_endpoint_connect( xenidc_endpoint * endpoint )
+{
+    trace();
+
+    /* Between connect and completion of the disconnect callback we are      */
+    /* allowed to issue messages and transactions.                           */
+
+    {
+        struct usbfront_device * device =
+          usbfront_device_endpoint_to( endpoint );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &device->lock, flags );
+
+        usbfront_device_handle_stimulus( device, usbfront_device_stimulus_cn );
+
+        spin_unlock_irqrestore( &device->lock, flags );
+    }
+}
+
+static void usbfront_device_endpoint_disconnect
+  ( xenidc_endpoint * endpoint, xenidc_callback * callback )
+{
+    trace();
+
+    /* We must stop issuing messages and transactions and complete the       */
+    /* callback once all of the messages and transactions we are issuing     */
+    /* have completed or failed back to us.                                  */
+
+    {
+        struct usbfront_device * device =
+          usbfront_device_endpoint_to( endpoint );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &device->lock, flags );
+
+        device->endpoint_disconnect_callback = callback;
+
+        usbfront_device_handle_stimulus( device, usbfront_device_stimulus_dn );
+
+        spin_unlock_irqrestore( &device->lock, flags );
+    }
+}
+
+static void usbfront_device_endpoint_message
+  ( xenidc_endpoint * endpoint, xenidc_endpoint_message * message )
+{
+    trace();
+
+    /* The protocol doesn't require any messages sent from BE to FE so we    */
+    /* just ignore anything sent to us.                                      */
+
+    xenidc_callback_success( xenidc_endpoint_message_to_callback( message ) );
+}
+
+static void usbfront_device_endpoint_transaction
+  ( xenidc_endpoint * endpoint, xenidc_endpoint_transaction * transaction )
+{
+    trace();
+
+    /* The protocol doesn't require any transactions sent from BE to FE so   */
+    /* we just ignore anything sent to us.                                   */
+
+    xenidc_endpoint_transaction_complete
+      ( transaction, XENIDC_ERROR_INVALID_PROTOCOL );
+}
+
+static void usbfront_device_probe_driver_1( void * data );
+static void usbfront_device_remove_driver_1( void * data );
+static void usbfront_device_probe_all_ports_1( xenidc_callback * callback );
+
+static int usbfront_device_init_or_exit
+  ( struct usbfront_device * device, struct xenbus_device * dev, int exit )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        if( exit )
+        {
+           goto EXIT;
+        }
+
+        memset( device, 0, sizeof( *device ) );
+
+        device->dev = dev;
+
+        spin_lock_init( &device->lock );
+
+        device->state = usbfront_device_state_i;
+
+        {
+            int i;
+
+            for( i = 0; i < USBFRONT_DEVICE_PORT_COUNT; i++ )
+            {
+                struct usbfront_device_probe_transaction * probe =
+                  &device->probe_transaction[ i ];
+
+                xenidc_endpoint_transaction_init
+                (
+                    &probe->transaction,
+                    usbfront_device_probe_all_ports_1
+                );
+
+                probe->device = device;
+            }
+        }
+
+        xenidc_work_init
+        (
+            &device->probe_driver_1_work,
+            usbfront_device_probe_driver_1,
+            device
+        );
+
+        xenidc_work_init
+        (
+            &device->remove_driver_1_work,
+            usbfront_device_remove_driver_1,
+            device
+        );
+
+        device->backend = NULL;
+
+        return_value = xenbus_gather
+        (
+            NULL, /* FIXME? */
+            dev->nodename,
+            "backend-id", "%li", &device->backend_id,
+            "backend",     NULL, &device->backend,
+            NULL
+        );
+
+        if( XENBUS_EXIST_ERR( return_value ) )
+        {
+            goto EXIT_NO_BACKEND;
+        }
+
+        if( return_value < 0 )
+        {
+            xenbus_dev_error
+            (
+                dev,
+                return_value,
+                "reading %s/backend",
+                dev->nodename
+            );
+
+            goto EXIT_NO_BACKEND;
+        }
+
+        return_value = xenidc_endpoint_init
+        (
+            &device->endpoint,
+            usbfront_device_endpoint_connect,
+            usbfront_device_endpoint_message,
+            usbfront_device_endpoint_transaction,
+            usbfront_device_endpoint_disconnect,
+            USBIF_FE_INITIATOR_QUOTA,
+            USBIF_FE_INITIATOR_MAXIMUM_BYTE_COUNT,
+            USBIF_FE_TARGET_QUOTA,
+            USBIF_FE_TARGET_MAXIMUM_BYTE_COUNT
+        );
+
+        if( return_value != 0 )
+        {
+            goto EXIT_NO_ENDPOINT;
+        }
+
+        {
+            xenidc_address address;
+
+            xenidc_address_init
+            (
+                &address,
+                dev->nodename,
+                device->backend,
+                device->backend_id
+            );
+
+            xenidc_endpoint_create( &device->endpoint, address );
+        }
+
+        return 0;
+
+      EXIT:
+
+        xenidc_endpoint_destroy( &device->endpoint );
+
+        xenidc_endpoint_exit( &device->endpoint );
+
+      EXIT_NO_ENDPOINT:
+
+        kfree( device->backend );
+
+      EXIT_NO_BACKEND:
+
+        return return_value;
+    }
+}
+
+static int usbfront_device_init
+  ( struct usbfront_device * device, struct xenbus_device * dev )
+{
+    trace();
+
+    return usbfront_device_init_or_exit( device, dev, 0 );
+}
+
+static void usbfront_device_exit( struct usbfront_device * device )
+{
+    trace();
+
+    (void)usbfront_device_init_or_exit( device, NULL, 1 );
+}
+
+static int usbfront_device_probe_or_remove
+  ( struct xenbus_device * dev, int remove )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        struct usbfront_device * device;
+
+        if( remove )
+        {
+            goto REMOVE;
+        }
+
+        device = kmalloc( sizeof( *device ), GFP_KERNEL );
+
+        if( device == NULL )
+        {
+            xenbus_dev_error( dev, -ENOMEM, "allocating backend structure" );
+
+            return_value = -ENOMEM;
+
+            goto EXIT_NO_DEVICE;
+        }
+
+        dev->data = device;
+
+        return_value = usbfront_device_init( device, dev );
+
+        if( return_value != 0 )
+        {
+            goto EXIT_INIT_FAILED;
+        }
+
+        return 0;
+
+      REMOVE:
+
+        device = dev->data;
+
+        usbfront_device_exit( device );
+
+      EXIT_INIT_FAILED:
+
+        dev->data = NULL;
+
+        kfree( device );
+
+      EXIT_NO_DEVICE:
+
+        return return_value;
+    }
+}
+
+static int usbfront_device_probe
+  ( struct xenbus_device * dev, const struct xenbus_device_id * id )
+{
+    trace();
+
+    return usbfront_device_probe_or_remove( dev, 0 );
+}
+
+static int usbfront_device_remove( struct xenbus_device * dev )
+{
+    trace();
+
+    return usbfront_device_probe_or_remove( dev, 1 );
+}
+
+static struct xenbus_device_id usbfront_device_ids[] =
+{
+    { "usb" },
+    { "" }
+};
+
+static struct xenbus_driver usbfront_device_driver =
+{
+    .name   = "usb",
+    .owner  = THIS_MODULE,
+    .ids    = usbfront_device_ids,
+    .probe  = usbfront_device_probe,
+    .remove = usbfront_device_remove,
+};
+
+int usbfront_device_class_init( void )
+{
+    trace();
+
+    return xenbus_register_driver( &usbfront_device_driver );
+}
+
+void usbfront_device_class_exit( void )
+{
+    trace();
+
+    xenbus_unregister_driver( &usbfront_device_driver );
+}
+
+static void usbfront_device_invalid_stimulus
+  ( struct usbfront_device * device, usbfront_device_stimulus stimulus );
+
+static void usbfront_device_probe_driver( struct usbfront_device * device );
+
+static void usbfront_device_remove_driver( struct usbfront_device * device );
+
+static void usbfront_device_probe_all_ports( struct usbfront_device * device );
+
+static void usbfront_device_disconnect_all_ports
+  ( struct usbfront_device * device );
+
+static void usbfront_device_complete_endpoint_disconnect
+  ( struct usbfront_device * device );
+
+static void usbfront_device_handle_stimulus
+  ( struct usbfront_device * device, usbfront_device_stimulus stimulus )
+{
+    switch( device->state )
+    {
+      case usbfront_device_state_i:
+        switch( stimulus )
+        {
+          case usbfront_device_stimulus_cn:
+            device->state = usbfront_device_state_i_cn;
+            usbfront_device_probe_driver( device );
+            break;
+          default:
+            usbfront_device_invalid_stimulus( device, stimulus );
+            break;
+        }
+      case usbfront_device_state_i_cn:
+        /* Probing driver. */
+        switch( stimulus )
+        {
+          case usbfront_device_stimulus_dn:
+            device->state = usbfront_device_state_i_cn_dn;
+            break;
+          case usbfront_device_stimulus_ps:
+            device->state = usbfront_device_state_i_cn_ps;
+            usbfront_device_probe_all_ports( device );
+            break;
+          case usbfront_device_stimulus_pf:
+            device->state = usbfront_device_state_i_cn_pf;
+            break;
+          case usbfront_device_stimulus_pt:
+            break;
+          default:
+            usbfront_device_invalid_stimulus( device, stimulus );
+            break;
+        }
+      case usbfront_device_state_i_cn_dn:
+        /* Probing driver.         */
+        /* Endpoint disconnecting. */
+        switch( stimulus )
+        {
+          case usbfront_device_stimulus_ps:
+            device->state = usbfront_device_state_i_cn_dn_ps;
+            usbfront_device_remove_driver( device );
+            break;
+          case usbfront_device_stimulus_pf:
+            device->state = usbfront_device_state_i;
+            usbfront_device_disconnect_all_ports( device );
+            usbfront_device_complete_endpoint_disconnect( device );
+            break;
+          case usbfront_device_stimulus_pt:
+            break;
+          default:
+            usbfront_device_invalid_stimulus( device, stimulus );
+            break;
+        }
+      case usbfront_device_state_i_cn_ps:
+        /* Driver Probed. */
+        /* Polling ports. */
+        switch( stimulus )
+        {
+          case usbfront_device_stimulus_dn:
+            device->state = usbfront_device_state_i_cn_ps_dn;
+            usbfront_device_remove_driver( device );
+            break;
+          case usbfront_device_stimulus_pt:
+            break;
+          case usbfront_device_stimulus_pc:
+            device->state = usbfront_device_state_i_cn_ps_pc;
+            break;
+          default:
+            usbfront_device_invalid_stimulus( device, stimulus );
+            break;
+        }
+      case usbfront_device_state_i_cn_pf:
+        /* Driver probe failed. */
+        switch( stimulus )
+        {
+          case usbfront_device_stimulus_dn:
+            device->state = usbfront_device_state_i;
+            usbfront_device_disconnect_all_ports( device );
+            usbfront_device_complete_endpoint_disconnect( device );
+            break;
+          default:
+            usbfront_device_invalid_stimulus( device, stimulus );
+            break;
+        }
+      case usbfront_device_state_i_cn_dn_ps:
+        /* Endpoint disconnecting. */
+        /* Removing driver.        */
+        switch( stimulus )
+        {
+          case usbfront_device_stimulus_rc:
+            device->state = usbfront_device_state_i;
+            usbfront_device_disconnect_all_ports( device );
+            usbfront_device_complete_endpoint_disconnect( device );
+            break;
+          case usbfront_device_stimulus_pt:
+            break;
+          default:
+            usbfront_device_invalid_stimulus( device, stimulus );
+            break;
+        }
+      case usbfront_device_state_i_cn_ps_dn:
+        /* Endpoint disconnecting. */
+        /* Removing driver.        */
+        /* Polling ports.          */
+        switch( stimulus )
+        {
+          case usbfront_device_stimulus_rc:
+            device->state = usbfront_device_state_i_cn_ps_dn_rc;
+            break;
+          case usbfront_device_stimulus_pt:
+            break;
+          case usbfront_device_stimulus_pc:
+            device->state = usbfront_device_state_i_cn_dn_ps;
+            break;
+          default:
+            usbfront_device_invalid_stimulus( device, stimulus );
+            break;
+        }
+      case usbfront_device_state_i_cn_ps_pc:
+        /* Driver Probed. */
+        switch( stimulus )
+        {
+          case usbfront_device_stimulus_dn:
+            device->state = usbfront_device_state_i_cn_dn_ps;
+            usbfront_device_remove_driver( device );
+            break;
+          case usbfront_device_stimulus_pt:
+            device->state = usbfront_device_state_i_cn_ps;
+            usbfront_device_probe_all_ports( device );
+            break;
+          default:
+            usbfront_device_invalid_stimulus( device, stimulus );
+            break;
+        }
+      case usbfront_device_state_i_cn_ps_dn_rc:
+        /* Endpoint disconnecting. */
+        /* Polling ports.          */
+        switch( stimulus )
+        {
+          case usbfront_device_stimulus_pc:
+            device->state = usbfront_device_state_i;
+            usbfront_device_disconnect_all_ports( device );
+            usbfront_device_complete_endpoint_disconnect( device );
+            break;
+          default:
+            usbfront_device_invalid_stimulus( device, stimulus );
+            break;
+        }
+      default:
+        usbfront_device_invalid_stimulus( device, stimulus );
+        break;
+    }
+}
+
+static void usbfront_device_invalid_stimulus
+  ( struct usbfront_device * device, usbfront_device_stimulus stimulus )
+{
+    trace();
+
+    printk
+    (
+        KERN_ERR "usbfront: device %p in state %d"
+        "received invalid stimulus %d",
+        device,
+        device->state,
+        stimulus
+    );
+}
+
+static void usbfront_device_probe_driver( struct usbfront_device * device )
+{
+    trace();
+
+    {
+        int scheduled = xenidc_work_schedule( &device->probe_driver_1_work );
+
+        ASSERT( scheduled );
+    }
+}
+
+static void usbfront_device_probe_driver_1( void * data )
+{
+    trace();
+
+    {
+        struct usbfront_device * device = (struct usbfront_device *)data;
+
+        usbfront_device_stimulus stimulus;
+
+        if( usbfront_driver_probe( device ) == 0 )
+        {
+            stimulus = usbfront_device_stimulus_ps;
+        }
+        else
+        {
+            stimulus = usbfront_device_stimulus_pf;
+        }
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &device->lock, flags );
+
+            usbfront_device_handle_stimulus( device, stimulus );
+
+            spin_unlock_irqrestore( &device->lock, flags ); 
+        }
+    }
+}
+
+static void usbfront_device_remove_driver( struct usbfront_device * device )
+{
+    trace();
+
+    {
+        int scheduled = xenidc_work_schedule( &device->remove_driver_1_work );
+
+        ASSERT( scheduled );
+    }
+}
+
+static void usbfront_device_remove_driver_1( void * data )
+{
+    trace();
+
+    {
+        struct usbfront_device * device = (struct usbfront_device *)data;
+
+        usbfront_driver_remove( device );
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &device->lock, flags );
+
+            usbfront_device_handle_stimulus
+              ( device, usbfront_device_stimulus_rc );
+
+            spin_unlock_irqrestore( &device->lock, flags ); 
+        }
+    }
+}
+
+static void usbfront_device_probe_all_ports( struct usbfront_device * device )
+{
+    device->port_probe_count = USBFRONT_DEVICE_PORT_COUNT;
+
+    {
+        int i;
+
+        for( i = 0; i < USBFRONT_DEVICE_PORT_COUNT; i++ )
+        {
+            struct usbfront_device_probe_transaction * probe =
+              &device->probe_transaction[ i ];
+
+            if
+            (
+                ( device->port_status[ i ].wPortStatus & USB_PORT_STAT_RESET )
+                !=
+                USB_PORT_STAT_RESET
+            )
+            {
+                xenidc_endpoint_transaction_set_parameters_lbr
+                (
+                    &probe->transaction,
+                    xenidc_vaddress_create_lbr
+                    (
+                        &probe->probe.parameters,
+                        sizeof( probe->probe.parameters )
+                    )
+                );
+
+                xenidc_endpoint_transaction_set_status_lbr
+                (
+                    &probe->transaction,
+                    xenidc_vaddress_create_lbr
+                    (
+                        &probe->probe.status,
+                        sizeof( probe->probe.status )
+                    )
+                );
+
+                memset
+                (
+                    &probe->probe.parameters,
+                    0,
+                    sizeof( probe->probe.parameters )
+                );
+
+                probe->probe.parameters.header.transaction_type =
+                  USBIF_TRANSACTION_TYPE_PROBE;
+
+                probe->probe.parameters.port = i + 1;
+
+                memset
+                  ( &probe->probe.status, 0, sizeof( probe->probe.status ) );
+            }
+            else
+            {
+                xenidc_endpoint_transaction_set_parameters_lbr
+                (
+                    &probe->transaction,
+                    xenidc_vaddress_create_lbr
+                    (
+                        &probe->reset.parameters,
+                        sizeof( probe->reset.parameters )
+                    )
+                );
+
+                xenidc_endpoint_transaction_set_status_lbr
+                (
+                    &probe->transaction,
+                    xenidc_vaddress_create_lbr
+                    (
+                        &probe->reset.status,
+                        sizeof( probe->reset.status )
+                    )
+                );
+
+                memset
+                (
+                    &probe->reset.parameters,
+                    0,
+                    sizeof( probe->reset.parameters )
+                );
+
+                probe->reset.parameters.header.transaction_type =
+                  USBIF_TRANSACTION_TYPE_RESET;
+
+                probe->reset.parameters.port = i + 1;
+
+                memset
+                  ( &probe->reset.status, 0, sizeof( probe->reset.status ) );
+            }
+
+            xenidc_endpoint_submit_transaction
+              ( &device->endpoint, &probe->transaction );
+        }
+    }
+}
+
+static void usbfront_device_probe_all_ports_1( xenidc_callback * callback )
+{
+    struct usbfront_device_probe_transaction * probe = container_of
+    (
+        xenidc_endpoint_transaction_callback_to( callback ),
+        struct usbfront_device_probe_transaction,
+        transaction
+    );
+
+    struct usbfront_device * device = probe->device;
+
+    unsigned long flags;
+
+    spin_lock_irqsave( &device->lock, flags );
+
+    if
+    (
+        probe->probe.parameters.header.transaction_type
+        ==
+        USBIF_TRANSACTION_TYPE_PROBE
+    )
+    {
+        int port_number = probe->probe.parameters.port;
+
+        if( xenidc_callback_query_error( callback ) == XENIDC_ERROR_SUCCESS )
+        {
+            struct usb_port_status * port_status =
+              &device->port_status[ port_number - 1 ];
+
+            if
+            (
+                probe->probe.status.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
+              ( probe->probe.status.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
+            {
+                trace3
+                (
+                    "device %p: unexpected result %d probing port %d",
+                    device,
+                    (int)probe->probe.status.result,
+                    port_number
+                );
+            }
+        }
+        else
+        {
+            trace3
+            (
+                "device %p: error %d probing port %d",
+                device,
+                usbif_error_map_to_local
+                  ( xenidc_callback_query_error( callback ) ),
+                port_number
+            );
+        }
+    }
+    else
+    {
+        int port_number = probe->reset.parameters.port;
+
+        struct usb_port_status * port_status =
+          &device->port_status[ port_number - 1 ];
+
+        if
+        (
+            ( xenidc_callback_query_error( callback ) == XENIDC_ERROR_SUCCESS )
+            &&
+            (
+                ( probe->reset.status.result == USBIF_RESET_RESULT_FULL_SPEED )
+                ||
+                ( probe->reset.status.result == USBIF_RESET_RESULT_LOW_SPEED )
+                ||
+                ( probe->reset.status.result == USBIF_RESET_RESULT_HIGH_SPEED )
+            )
+        )
+        {
+            if( probe->reset.status.result == USBIF_RESET_RESULT_LOW_SPEED )
+            {
+                port_status->wPortStatus |=  USB_PORT_STAT_LOW_SPEED;
+                port_status->wPortStatus &= ~USB_PORT_STAT_HIGH_SPEED;
+            }
+            else if
+              ( probe->reset.status.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
+            (
+                xenidc_callback_query_error( callback )
+                !=
+                XENIDC_ERROR_SUCCESS
+            )
+            {
+                printk
+                (
+                    KERN_ERR "usbfront: device %p: error %d resetting port %d",
+                    device,
+                    usbif_error_map_to_local
+                      ( xenidc_callback_query_error( callback ) ),
+                    port_number
+                );
+            }
+            else
+            {
+                trace3
+                (
+                    "device %p: unexpected result %d resetting port %d",
+                    device,
+                    (int)probe->reset.status.result,
+                    port_number
+                );
+            }
+
+            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 )
+    {
+        usbfront_device_handle_stimulus( device, usbfront_device_stimulus_pc );
+    }
+
+    spin_unlock_irqrestore( &device->lock, flags );
+}
+
+static void usbfront_device_disconnect_all_ports
+  ( struct usbfront_device * device )
+{
+    trace();
+
+    {
+        int i;
+
+        for( i = 0; i < USBFRONT_DEVICE_PORT_COUNT; i++ )
+        {
+            struct usb_port_status * port_status = &device->port_status[ i ];
+
+            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 usbfront_device_complete_endpoint_disconnect
+  ( struct usbfront_device * device )
+{
+    trace();
+
+    xenidc_callback_success( device->endpoint_disconnect_callback );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,85 @@
+/*****************************************************************************/
+/* usbfront_device is a device which represents a connection to a back-end.  */
+/* The intent was for it to have an interface like a hardware USB host       */
+/* controller device.                                                        */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBFRONT_DEVICE_H
+#define USBFRONT_DEVICE_H
+
+#include <linux/device.h>
+#include <linux/usb.h>
+#include "../../usb/core/hcd.h"
+#include <asm-xen/xen-public/io/usbif.h>
+
+extern int usbfront_device_class_init( void );
+
+extern void usbfront_device_class_exit( void );
+
+struct usbfront_device;
+
+void usbfront_device_set_drvdata
+  ( struct usbfront_device * device, void * data );
+
+void * usbfront_device_get_drvdata( struct usbfront_device * device );
+
+struct device * usbfront_device_to_dev
+  ( struct usbfront_device * device );
+
+struct usbfront_device * usbfront_device_dev_to( struct device * dev );
+
+int usbfront_device_query_port_count( struct usbfront_device * device );
+
+int usbfront_device_query_port_status_changed
+  ( struct usbfront_device * device, int port_number );
+
+struct usb_port_status usbfront_device_query_port_status
+  ( struct usbfront_device * device, int port_number );
+
+/* Used to turn on power to a port. */
+void usbfront_device_set_port_power
+  ( struct usbfront_device * device, int port_number );
+
+/* Used to reset a port. Completes asynchronously with notification via the  */
+/* port status.                                                              */
+void usbfront_device_set_port_reset
+  ( struct usbfront_device * device, int port_number );
+
+void usbfront_device_clear_port_enable
+  ( struct usbfront_device * device, int port_number );
+
+/* Used to ack a connection change */
+void usbfront_device_clear_port_connection_change
+  ( struct usbfront_device * device, int port_number );
+
+/* Used to ack a reset change */
+void usbfront_device_clear_port_reset_change
+  ( struct usbfront_device * device, int port_number );
+
+void usbfront_device_submit_message
+  ( struct usbfront_device * device, xenidc_endpoint_message * message );
+
+void usbfront_device_submit_transaction
+(
+    struct usbfront_device      * device,
+    xenidc_endpoint_transaction * transaction
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,880 @@
+/*****************************************************************************/
+/* A device driver for usbfront_device devices.                              */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* 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@cl.cam.ac.uk> or
+ * <xen-devel@lists.sourceforge.net> 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@erdfelt.com>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (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@rowland.harvard.edu>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
+ *
+ * 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 "usbfront_driver.h"
+#include "usbfront_hcd_resource.h"
+#include "usbfront_sll.h"
+#include "usbfront_trace.h"
+
+typedef enum
+{
+    usbfront_hcd_state_i
+}
+usbfront_hcd_state;
+
+typedef enum
+{
+    usbfront_hcd_stimulus_uq /* urb enqueue */
+}
+usbfront_hcd_stimulus;
+
+#define USBFRONT_HCD_RESOURCE_COUNT 16
+
+struct usbfront_hcd
+{
+    spinlock_t                   lock;
+    usbfront_hcd_state           state;
+    struct usbfront_sll          urb_sll;
+    struct list_head             free_resource_list;
+    struct usbfront_hcd_resource resources[ USBFRONT_HCD_RESOURCE_COUNT ];
+};
+
+static void usbfront_hcd_handle_stimulus
+  ( struct usbfront_hcd * uhcd, usbfront_hcd_stimulus stimulus );
+
+static struct usbfront_hcd * usbfront_hcd_hcd_to_uhcd( struct usb_hcd * hcd )
+{
+    return (struct usbfront_hcd *)( hcd->hcd_priv );
+}
+
+static struct usbfront_device *
+  usbfront_hcd_hcd_to_usbfront_device( struct usb_hcd * hcd )
+{
+    return usbfront_device_dev_to( hcd_to_bus( hcd )->controller );
+}
+
+void usbfront_hcd_resource_completed( xenidc_callback * callback );
+
+static int usbfront_hcd_start( struct usb_hcd * hcd )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd( hcd );
+
+        memset( uhcd, 0, sizeof( *uhcd ) );
+
+        spin_lock_init( &uhcd->lock );
+
+        uhcd->state = usbfront_hcd_state_i;
+
+        usbfront_sll_init( &uhcd->urb_sll );
+
+        INIT_LIST_HEAD( &uhcd->free_resource_list );
+
+        {
+            int i;
+
+            for( i = 0; i < USBFRONT_HCD_RESOURCE_COUNT; i++ )
+            {
+                struct usbfront_hcd_resource * resource =
+                  &uhcd->resources[ i ];
+
+                return_value = usbfront_hcd_resource_init
+                (
+                    resource,
+                    usbfront_hcd_hcd_to_usbfront_device( hcd ),
+                    i,
+                    usbfront_hcd_resource_completed
+                );
+
+                if( return_value != 0 )
+                {
+                    goto EXIT_NO_RESOURCE;
+                }
+
+                list_add
+                (
+                    usbfront_hcd_resource_to_link( resource ),
+                    &uhcd->free_resource_list
+                );
+            }
+        }
+
+        {
+            struct usb_device * root_hub_device =
+              usb_alloc_dev( NULL, &hcd->self, 0 );
+
+            if( root_hub_device == NULL )
+            {
+                return_value = -ENOMEM;
+
+                goto EXIT_NO_ROOT_HUB;
+            }
+
+            root_hub_device->speed = USB_SPEED_HIGH;
+
+            if
+            (
+                (
+                    return_value =
+                      usb_hcd_register_root_hub( root_hub_device, hcd )
+                )
+                !=
+                0
+            )
+            {
+                goto EXIT_NO_REGISTER;
+            }
+
+            return 0;
+
+      EXIT_NO_REGISTER:
+
+            usb_put_dev( root_hub_device );
+        }
+
+  EXIT_NO_ROOT_HUB:
+
+  EXIT_NO_RESOURCE:
+
+        while( !list_empty( &uhcd->free_resource_list ) )
+        {
+            struct usbfront_hcd_resource * resource = list_entry
+            (
+                uhcd->free_resource_list.next,
+                struct usbfront_hcd_resource,
+                USBFRONT_HCD_RESOURCE_LINK
+            );
+
+            list_del_init( usbfront_hcd_resource_to_link( resource ) );
+
+            usbfront_hcd_resource_exit( resource );
+        }
+
+        return return_value;
+    }
+}
+
+static void usbfront_hcd_stop( struct usb_hcd * hcd )
+{
+    trace();
+
+    {
+        struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd( hcd );
+
+        while( !list_empty( &uhcd->free_resource_list ) )
+        {
+            struct usbfront_hcd_resource * resource = list_entry
+            (
+                uhcd->free_resource_list.next,
+                struct usbfront_hcd_resource,
+                USBFRONT_HCD_RESOURCE_LINK
+            );
+
+            list_del_init( usbfront_hcd_resource_to_link( resource ) );
+
+            usbfront_hcd_resource_exit( resource );
+        }
+    }
+}
+
+static int usbfront_hcd_get_frame_number( struct usb_hcd * hcd )
+{
+    trace();
+
+    return 0;
+}
+
+static inline void usbfront_check_contiguous
+  ( unsigned long buffer, unsigned long length )
+{
+    if( length != 0 )
+    {
+        unsigned long offset;
+
+        for
+        (
+            offset = 0;
+            offset < ( length + ( buffer & ~PAGE_MASK ) );
+            offset += PAGE_SIZE
+        )
+        {
+            unsigned long maddress1 =
+              virt_to_machine( ( buffer & PAGE_MASK ) + offset );
+
+            unsigned long maddress2 =
+              virt_to_machine( buffer & PAGE_MASK ) + offset;
+
+            ASSERT( maddress1 == maddress2 );
+        }
+    }
+}
+
+static int usbfront_hcd_urb_enqueue
+(
+    struct usb_hcd           * hcd,
+    struct usb_host_endpoint * ep, /* FIXME: what's the intended use for ep? */
+    struct urb               * urb,
+    int                        mem_flags
+)
+{
+    trace();
+
+    usbfront_check_contiguous
+      ( (unsigned long)urb->transfer_buffer, urb->transfer_buffer_length );
+
+    {
+        struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd( hcd );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &uhcd->lock, flags );
+
+        usbfront_slk_init( (struct usbfront_slk *)&urb->hcpriv );
+
+        usbfront_sll_add_last
+          ( &uhcd->urb_sll, (struct usbfront_slk *)&urb->hcpriv );
+
+        usbfront_hcd_handle_stimulus( uhcd, usbfront_hcd_stimulus_uq );
+
+        spin_unlock_irqrestore( &uhcd->lock, flags );
+    }
+
+    return 0;
+}
+
+static int usbfront_hcd_urb_dequeue( struct usb_hcd * hcd, struct urb * urb )
+{
+    trace();
+
+    {
+        int dequeued;
+
+        {
+            struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd( hcd );
+
+            unsigned long flags;
+
+            spin_lock_irqsave( &uhcd->lock, flags );
+
+            dequeued = usbfront_sll_remove_slk
+              ( &uhcd->urb_sll, (struct usbfront_slk *)&urb->hcpriv );
+
+            spin_unlock_irqrestore( &uhcd->lock, flags );
+        }
+
+        if( dequeued )
+        {
+            urb->hcpriv = 0;
+
+            urb->actual_length = 0;
+
+            {
+                unsigned long flags;
+
+                local_irq_save( flags );
+
+                usb_hcd_giveback_urb( hcd, urb, 0 );
+
+                local_irq_restore( flags );
+            }
+        }
+        else
+        {
+            usbfront_hcd_resource_dequeue_urb( urb );
+        }
+    }
+
+    return 0;
+}
+
+static void usbfront_hcd_endpoint_disable
+  ( struct usb_hcd * hcd, struct usb_host_endpoint * ep )
+{
+    trace();
+}
+
+static int usbfront_hcd_hub_status_data( struct usb_hcd * hcd, char * buf )
+{
+    int changed = 0;
+
+    struct usbfront_device * device =
+      usbfront_hcd_hcd_to_usbfront_device( hcd );
+
+    int port_count = usbfront_device_query_port_count( device );
+
+    int byte_count =
+      ( 1 /* hub */ + port_count /* ports */ + 7 /* round up */ ) / 8;
+
+    memset( buf, 0, byte_count );
+
+    {
+        int i;
+
+        for( i = 0; i < port_count; i++ )
+        {
+            if( usbfront_device_query_port_status_changed( device, i ) )
+            {
+                buf[ ( i + 1 ) / 8 ] |= 1 << ( ( i + 1 ) % 8 );
+
+                changed = 1;
+            }
+        }
+    }
+
+    return changed ? byte_count : 0;
+}
+
+static int usbfront_hcd_hub_control
+(
+    struct usb_hcd * hcd,
+    u16              typeReq,
+    u16              wValue,
+    u16              wIndex,
+    char           * buf,
+    u16              wLength
+)
+{
+    trace();
+
+    {
+        struct usbfront_device * device =
+          usbfront_hcd_hcd_to_usbfront_device( hcd );
+
+        int return_value = 0;
+
+        switch( typeReq )
+        {
+          case GetHubStatus:
+
+            trace0( "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:
+
+            trace0( "GetPortStatus" );
+
+            if
+            (
+                ( wValue != 0 )
+                ||
+                ( wIndex > usbfront_device_query_port_count( device ) )
+                ||
+                ( wLength != 4 )
+            )
+            {
+                goto ERROR;
+            }
+
+            {
+                struct usb_port_status port_status =
+                  usbfront_device_query_port_status( device, wIndex - 1 );
+
+                memcpy( buf, &port_status, wLength );
+            }
+
+            break;
+
+          case GetHubDescriptor:
+
+            trace0( "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 ] = usbfront_device_query_port_count( device );
+
+                memcpy
+                (
+                    buf,
+                    &descriptor,
+                    min_t( size_t, sizeof( descriptor ), wLength )
+                );
+            }
+
+            break;
+
+          case SetPortFeature:
+
+            trace0( "SetPortFeature" );
+
+            if
+            (
+                (
+                    ( wIndex & 0x00FF )
+                    >
+                    usbfront_device_query_port_count( device )
+                )
+                ||
+                ( wLength != 0 )
+            )
+            {
+                goto ERROR;
+            }
+
+            switch( wValue )
+            {
+              case USB_PORT_FEAT_SUSPEND:
+                trace0( "USB_PORT_FEAT_SUSPEND" );
+                break;
+              case USB_PORT_FEAT_RESET:
+                trace0( "USB_PORT_FEAT_RESET" );
+                usbfront_device_set_port_reset( device, wIndex - 1 );
+                break;
+              case USB_PORT_FEAT_POWER:
+                trace0( "USB_PORT_FEAT_POWER" );
+                usbfront_device_set_port_power( device, wIndex - 1 );
+                break;
+              default:
+                trace1( "Unknown:%x", wValue );
+                goto ERROR;
+            }
+
+            break;
+
+          case ClearPortFeature:
+
+            trace0( "ClearPortFeature" );
+
+            if
+            (
+                (
+                    ( wIndex & 0x00FF )
+                    >
+                    usbfront_device_query_port_count( device )
+                )
+                ||
+                ( wLength != 0 )
+            )
+            {
+                goto ERROR;
+            }
+
+            switch( wValue )
+            {
+              case USB_PORT_FEAT_ENABLE:
+                trace0( "USB_PORT_FEAT_ENABLE" );
+                usbfront_device_clear_port_enable( device, wIndex - 1 );
+                break;
+              case USB_PORT_FEAT_SUSPEND:
+                trace0( "USB_PORT_FEAT_SUSPEND" );
+                break;
+              case USB_PORT_FEAT_POWER:
+                trace0( "USB_PORT_FEAT_POWER" );
+                break;
+              case USB_PORT_FEAT_INDICATOR:
+                trace0( "USB_PORT_FEAT_INDICATOR" );
+                break;
+              case USB_PORT_FEAT_C_CONNECTION:
+                trace0( "USB_PORT_C_CONNECTION" );
+                usbfront_device_clear_port_connection_change
+                  ( device, wIndex - 1 );
+                break;
+              case USB_PORT_FEAT_C_RESET:
+                trace0( "USB_PORT_C_RESET" );
+                usbfront_device_clear_port_reset_change( device, wIndex - 1 );
+                break;
+              case USB_PORT_FEAT_C_ENABLE:
+                trace0( "USB_PORT_C_ENABLE" );
+                break;
+              case USB_PORT_FEAT_C_SUSPEND:
+                trace0( "USB_PORT_C_SUSPEND" );
+                break;
+              case USB_PORT_FEAT_C_OVER_CURRENT:
+                trace0( "USB_PORT_C_OVER_CURRENT" );
+                break;
+              default:
+                trace1( "Unknown:%x", wValue );
+                goto ERROR;
+            }
+
+            break;
+
+          default:
+            trace1( "Unknown:%x", typeReq );
+          ERROR:
+            return_value = -EPIPE;
+        }
+
+        return return_value;
+    }
+}
+
+static int usbfront_hcd_start_port_reset
+  ( struct usb_hcd * hcd, unsigned port_num )
+{
+    trace();
+
+    return 0;
+}
+
+static struct hc_driver usbfront_hc_driver =
+{
+    .description      = "usbfront_hc_driver",
+    .product_desc     = "Xen USB Front-End Driver",
+    .hcd_priv_size    = sizeof( struct usbfront_hcd ),
+    /* .irq */
+    .flags            = HCD_USB2,
+    /* reset optional. */
+    .start            = usbfront_hcd_start,
+    /* suspend optional. */
+    /* resume optional. */
+    .stop             = usbfront_hcd_stop,
+    .get_frame_number = usbfront_hcd_get_frame_number,
+    .urb_enqueue      = usbfront_hcd_urb_enqueue,
+    .urb_dequeue      = usbfront_hcd_urb_dequeue,
+    .endpoint_disable = usbfront_hcd_endpoint_disable,
+    .hub_status_data  = usbfront_hcd_hub_status_data,
+    .hub_control      = usbfront_hcd_hub_control,
+    /* hub_suspend optional. */
+    /* hub_resume optional. */
+    .start_port_reset = usbfront_hcd_start_port_reset,
+};
+
+static void usbfront_hcd_invalid_stimulus
+  ( struct usbfront_hcd * uhcd, usbfront_hcd_stimulus stimulus );
+
+static void usbfront_hcd_kick_urbs( struct usbfront_hcd * uhcd );
+
+static void usbfront_hcd_handle_stimulus
+  ( struct usbfront_hcd * uhcd, usbfront_hcd_stimulus stimulus )
+{
+    trace3
+    (
+        "uhcd %p in state %d received stimulus %d",
+        uhcd,
+        uhcd->state,
+        stimulus
+    );
+
+    switch( uhcd->state )
+    {
+      case usbfront_hcd_state_i:
+        switch( stimulus )
+        {
+          case usbfront_hcd_stimulus_uq:
+            usbfront_hcd_kick_urbs( uhcd );
+            break;
+        }
+        break;
+      default:
+        usbfront_hcd_invalid_stimulus( uhcd, stimulus );
+        break;
+    }
+}
+
+static void usbfront_hcd_invalid_stimulus
+  ( struct usbfront_hcd * uhcd, usbfront_hcd_stimulus stimulus )
+{
+    trace();
+
+    printk
+    (
+        KERN_ERR "usbfront: hc_driver_uhcd %p in state %d"
+        "received invalid stimulus %d",
+        uhcd,
+        uhcd->state,
+        stimulus
+    );
+}
+
+static void usbfront_hcd_kick_urbs( struct usbfront_hcd * uhcd )
+{
+    trace();
+
+    while
+    (
+        !usbfront_sll_is_empty( &uhcd->urb_sll )
+        &&
+        !list_empty( &uhcd->free_resource_list )
+    )
+    {
+        trace0( "Starting URB" );
+
+        {
+            struct urb * urb = container_of
+            (
+                (void **)usbfront_sll_remove_first( &uhcd->urb_sll ),
+                struct urb,
+                hcpriv
+            );
+
+            struct usbfront_hcd_resource * resource = list_entry
+            (
+                uhcd->free_resource_list.next,
+                struct usbfront_hcd_resource,
+                USBFRONT_HCD_RESOURCE_LINK
+            );
+
+            list_del_init( usbfront_hcd_resource_to_link( resource ) );
+
+            usbfront_hcd_resource_start_urb( resource, urb );
+        }
+    }
+}
+
+void usbfront_hcd_resource_completed( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        struct usbfront_hcd_resource * resource =
+          usbfront_hcd_resource_callback_to( callback );
+
+        struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd
+        (
+            usbfront_device_get_drvdata
+              ( usbfront_hcd_resource_query_device( resource ) )
+        );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &uhcd->lock, flags );
+
+        list_add
+        (
+            usbfront_hcd_resource_to_link( resource ),
+            &uhcd->free_resource_list
+        );
+
+        usbfront_hcd_kick_urbs( uhcd );
+
+        spin_unlock_irqrestore( &uhcd->lock, flags );
+    }
+}
+
+static int usbfront_driver_probe_or_remove
+  ( struct usbfront_device * device, int remove )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        struct usb_hcd * hcd;
+
+        if( remove )
+        {
+            goto REMOVE;
+        }
+
+        if( usb_disabled() )
+        {
+            return_value = -ENODEV;
+
+            goto REMOVE_0;
+        }
+
+        if
+        (
+            (
+                hcd = usb_create_hcd
+                (
+                    &usbfront_hc_driver,
+                    usbfront_device_to_dev( device ),
+                    usbfront_device_to_dev( device )->bus_id
+                )
+            )
+            ==
+            NULL
+        )
+        {
+            return_value = -ENOMEM;
+
+            goto REMOVE_0;
+        }
+
+        usbfront_device_set_drvdata( device, hcd );
+
+        if( ( return_value = usb_add_hcd( hcd, 0, 0 ) ) != 0 )
+        {
+            goto REMOVE_1;
+        }
+
+        return 0;
+
+  REMOVE:
+
+        hcd = usbfront_device_get_drvdata( device );
+
+        usb_remove_hcd( hcd );
+
+      REMOVE_1:
+
+        usb_put_hcd( hcd );
+
+        usbfront_device_set_drvdata( device, NULL );
+
+      REMOVE_0:
+
+        return return_value;
+    }
+}
+
+int usbfront_driver_probe( struct usbfront_device * device )
+{
+    trace();
+
+    return usbfront_driver_probe_or_remove( device, 0 );
+}
+
+void usbfront_driver_remove( struct usbfront_device * device )
+{
+    trace();
+
+    usbfront_driver_probe_or_remove( device, 1 );
+}
+
+int usbfront_driver_class_init( void )
+{
+    trace();
+
+    return usbfront_hcd_resource_class_init();
+}
+
+void usbfront_driver_class_exit( void )
+{
+    trace();
+
+    usbfront_hcd_resource_class_exit();
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,35 @@
+/*****************************************************************************/
+/* A device driver for usbfront_device devices.                              */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBFRONT_DRIVER_H
+#define USBFRONT_DRIVER_H
+
+#include "usbfront_device.h"
+
+extern int usbfront_driver_class_init( void );
+
+extern void usbfront_driver_class_exit( void );
+
+extern int usbfront_driver_probe( struct usbfront_device * device );
+
+extern void usbfront_driver_remove( struct usbfront_device * device );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,945 @@
+/*****************************************************************************/
+/* A resource used by the usbfront host controller device driver to process  */
+/* an URB by translating the URB and optional unlink request into            */
+/* a transaction and corresponding optional unlink message for submission to */
+/* the back end.                                                             */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on arch/xen/drivers/usbif/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@cl.cam.ac.uk> or
+ * <xen-devel@lists.sourceforge.net> 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@erdfelt.com>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (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
+ */
+
+/* FIXME is URB serialisation maintained correctly? */
+
+#include <asm-xen/xenidc_vaddress.h>
+#include "usbfront_assert.h"
+#include "usbfront_driver.h"
+#include "usbfront_hcd_resource.h"
+#include "usbfront_trace.h"
+
+xenidc_rbr_provider_pool * usbfront_hcd_resource_rbr_provider_pool;
+
+int usbfront_hcd_resource_class_init( void )
+{
+    trace();
+
+    usbfront_hcd_resource_rbr_provider_pool =
+      xenidc_allocate_rbr_provider_pool( USBIF_MAX_PAGES_PER_REQUEST );
+
+    return ( usbfront_hcd_resource_rbr_provider_pool != NULL ) ? 0 : -ENOMEM;
+}
+
+void usbfront_hcd_resource_class_exit( void )
+{
+    trace();
+
+    xenidc_free_rbr_provider_pool( usbfront_hcd_resource_rbr_provider_pool );
+}
+
+typedef enum
+{
+    usbfront_hcd_resource_stimulus_st, /* Start URB */
+    usbfront_hcd_resource_stimulus_dq, /* Dequeue URB */
+    usbfront_hcd_resource_stimulus_cs, /* Create RBRs success */
+    usbfront_hcd_resource_stimulus_cf, /* Create RBRs failure */
+    usbfront_hcd_resource_stimulus_tc, /* Transaction complete */
+    usbfront_hcd_resource_stimulus_rc, /* Revoke RBRs complete */
+    usbfront_hcd_resource_stimulus_uc, /* Unlink complete */
+}
+usbfront_hcd_resource_stimulus;
+
+static void usbfront_hcd_resource_handle_stimulus
+(
+    struct usbfront_hcd_resource   * resource,
+    usbfront_hcd_resource_stimulus   stimulus
+);
+
+static void usbfront_hcd_resource_create_rbrs_1( xenidc_callback * callback );
+
+static void usbfront_hcd_resource_submit_transaction_1
+  ( xenidc_callback * callback );
+
+static void usbfront_hcd_resource_revoke_rbrs_1
+  ( xenidc_callback * callback );
+
+static void usbfront_hcd_resource_submit_unlink_1
+  ( xenidc_callback * callback );
+
+static void usbfront_hcd_resource_complete_1( void * context );
+
+static int usbfront_hcd_resource_init_or_exit
+(
+    struct usbfront_hcd_resource * resource,
+    struct usbfront_device       * device,
+    int                            index,
+    xenidc_callback_function     * callback,
+    int                            exit
+)
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        if( exit )
+        {
+            goto EXIT;
+        }
+
+        xenidc_callback_init( &resource->callback, callback );
+
+        resource->device = device;
+
+        resource->index = index;
+
+        resource->schedule = (usbif_isochronous_io_schedule_element *)
+          __get_free_page( GFP_KERNEL );
+
+        if( resource->schedule == NULL )
+        {
+            return_value = -ENOMEM;
+
+            goto EXIT_NO_SCHEDULE;
+        }
+
+        spin_lock_init( &resource->lock );
+
+        resource->state = usbfront_hcd_resource_state_i;
+
+        xenidc_create_rbr_request_element_init
+          ( &resource->rbr_request_element[ 0 ] );
+
+        xenidc_create_rbr_request_element_init
+          ( &resource->rbr_request_element[ 1 ] );
+
+        xenidc_reserve_and_create_rbr_request_init
+        (
+            &resource->rbr_request,
+            usbfront_hcd_resource_create_rbrs_1,
+            usbfront_hcd_resource_revoke_rbrs_1
+        );
+
+        xenidc_endpoint_transaction_init
+        (
+            &resource->io_transaction,
+            usbfront_hcd_resource_submit_transaction_1
+        );
+
+        xenidc_endpoint_transaction_set_parameters_lbr
+        (
+            &resource->io_transaction,
+            xenidc_vaddress_create_lbr
+            (
+                &resource->io_parameters,
+                sizeof( resource->io_parameters )
+            )
+        );
+
+        xenidc_endpoint_transaction_set_status_lbr
+        (
+            &resource->io_transaction,
+            xenidc_vaddress_create_lbr
+            (
+                &resource->io_status,
+                sizeof( resource->io_status )
+            )
+        );
+
+        xenidc_endpoint_message_init
+          ( &resource->unlink_message, usbfront_hcd_resource_submit_unlink_1 );
+
+        xenidc_endpoint_message_set_message_lbr
+        (
+            &resource->unlink_message,
+            xenidc_vaddress_create_lbr
+            (
+                &resource->unlink_message_body,
+                sizeof( resource->unlink_message_body )
+            )
+        );
+
+        xenidc_work_init
+        (
+            &resource->complete_1_work,
+            usbfront_hcd_resource_complete_1,
+            resource
+        );
+
+        return 0;
+
+      EXIT:
+
+        free_page( (unsigned long)resource->schedule );
+
+      EXIT_NO_SCHEDULE:
+
+        return return_value;
+    }
+}
+
+int usbfront_hcd_resource_init
+(
+    struct usbfront_hcd_resource * resource,
+    struct usbfront_device       * device,
+    int                            index,
+    xenidc_callback_function     * callback
+)
+{
+    trace();
+
+    return usbfront_hcd_resource_init_or_exit
+      ( resource, device, index, callback, 0 );
+}
+
+void usbfront_hcd_resource_exit( struct usbfront_hcd_resource * resource )
+{
+    trace();
+
+    usbfront_hcd_resource_init_or_exit( resource, NULL, 0, NULL, 1 );
+}
+
+void usbfront_hcd_resource_start_urb
+  ( struct usbfront_hcd_resource * resource, struct urb * urb )
+{
+    trace();
+
+    urb->hcpriv = resource;
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &resource->lock, flags );
+
+        resource->urb = urb;
+
+        usbfront_hcd_resource_handle_stimulus
+          ( resource, usbfront_hcd_resource_stimulus_st );
+
+        spin_unlock_irqrestore( &resource->lock, flags );
+    }
+}
+
+static DEFINE_RWLOCK( dequeue_lock );
+
+void usbfront_hcd_resource_dequeue_urb( struct urb * urb )
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        write_lock_irqsave( &dequeue_lock, flags );
+
+        if( urb->hcpriv != NULL )
+        {
+            struct usbfront_hcd_resource * resource =
+              (struct usbfront_hcd_resource *)urb->hcpriv;
+
+            unsigned long flags2;
+
+            spin_lock_irqsave( &resource->lock, flags2 );
+
+            usbfront_hcd_resource_handle_stimulus
+              ( resource, usbfront_hcd_resource_stimulus_dq );
+
+            spin_unlock_irqrestore( &resource->lock, flags2 );
+        }
+
+        write_unlock_irqrestore( &dequeue_lock, flags );
+    }
+}
+
+static void usbfront_hcd_resource_invalid_stimulus
+(
+    struct usbfront_hcd_resource   * resource,
+    usbfront_hcd_resource_stimulus   stimulus
+);
+
+static void usbfront_hcd_resource_create_rbrs
+  ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_abort_create_rbrs
+  ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_set_aborted_error
+  ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_submit_transaction
+  ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_revoke_rbrs
+  ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_submit_unlink
+  ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_complete
+  ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_handle_stimulus
+(
+    struct usbfront_hcd_resource   * resource,
+    usbfront_hcd_resource_stimulus   stimulus
+)
+{
+    trace();
+
+    switch( resource->state )
+    {
+      case usbfront_hcd_resource_state_i:
+        /* Initialised.                   */
+        /* Maybe completing previous URB. */
+        switch( stimulus )
+        {
+          case usbfront_hcd_resource_stimulus_st:
+            resource->state = usbfront_hcd_resource_state_i_st;
+            usbfront_hcd_resource_create_rbrs( resource );
+            break;
+          /* A dequeue is possible whilst we are making the complete         */
+          /* response after we have transitioned back to the i state.        */
+          case usbfront_hcd_resource_stimulus_dq:
+            break;
+          default:
+            usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+            break;
+        }
+        break;
+      case usbfront_hcd_resource_state_i_st:
+        /* Creating RBRs. */
+        switch( stimulus )
+        {
+          case usbfront_hcd_resource_stimulus_dq:
+            resource->state = usbfront_hcd_resource_state_i_st_dq;
+            usbfront_hcd_resource_abort_create_rbrs( resource );
+            break;
+          case usbfront_hcd_resource_stimulus_cs:
+            resource->state = usbfront_hcd_resource_state_i_st_cs;
+            usbfront_hcd_resource_submit_transaction( resource );
+            break;
+          case usbfront_hcd_resource_stimulus_cf:
+            resource->state = usbfront_hcd_resource_state_i;
+            usbfront_hcd_resource_complete( resource );
+            break;
+          default:
+            usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+            break;
+        }
+        break;
+      case usbfront_hcd_resource_state_i_st_dq:
+        /* Creating RBRs. */
+        /* Dequeue URB.   */
+        switch( stimulus )
+        {
+          case usbfront_hcd_resource_stimulus_dq:
+            break;
+          case usbfront_hcd_resource_stimulus_cs:
+            resource->state = usbfront_hcd_resource_state_i_st_dq_cs;
+            usbfront_hcd_resource_set_aborted_error( resource );
+            usbfront_hcd_resource_revoke_rbrs( resource );
+            break;
+          case usbfront_hcd_resource_stimulus_cf:
+            resource->state = usbfront_hcd_resource_state_i;
+            usbfront_hcd_resource_complete( resource );
+            break;
+          default:
+            usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+            break;
+        }
+        break;
+      case usbfront_hcd_resource_state_i_st_cs:
+        /* Transaction submitted. */
+        switch( stimulus )
+        {
+          case usbfront_hcd_resource_stimulus_dq:
+            resource->state = usbfront_hcd_resource_state_i_st_cs_dq;
+            usbfront_hcd_resource_submit_unlink( resource );
+            break;
+          case usbfront_hcd_resource_stimulus_tc:
+            resource->state = usbfront_hcd_resource_state_i_st_dq_cs;
+            usbfront_hcd_resource_revoke_rbrs( resource );
+            break;
+          default:
+            usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+            break;
+        }
+        break;
+      case usbfront_hcd_resource_state_i_st_dq_cs:
+        /* Revoking RBRs.     */
+        /* Maybe Dequeue URB. */
+        switch( stimulus )
+        {
+          case usbfront_hcd_resource_stimulus_dq:
+            break;
+          case usbfront_hcd_resource_stimulus_rc:
+            resource->state = usbfront_hcd_resource_state_i;
+            usbfront_hcd_resource_complete( resource );
+            break;
+          default:
+            usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+            break;
+        }
+        break;
+      case usbfront_hcd_resource_state_i_st_cs_dq:
+        /* Transaction submitted. */
+        /* Unlink submitted.      */
+        /* Dequeue URB.           */
+        switch( stimulus )
+        {
+          case usbfront_hcd_resource_stimulus_dq:
+            break;
+          case usbfront_hcd_resource_stimulus_tc:
+          case usbfront_hcd_resource_stimulus_uc:
+            resource->state = usbfront_hcd_resource_state_i_st_cs_dq_tc;
+            break;
+          default:
+            usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+            break;
+        }
+        break;
+      case usbfront_hcd_resource_state_i_st_cs_dq_tc:
+        /* Transaction submitted or Unlink submitted. */
+        /* Dequeue URB.                               */
+        switch( stimulus )
+        {
+          case usbfront_hcd_resource_stimulus_dq:
+            break;
+          case usbfront_hcd_resource_stimulus_tc:
+          case usbfront_hcd_resource_stimulus_uc:
+            resource->state = usbfront_hcd_resource_state_i_st_dq_cs;
+            usbfront_hcd_resource_revoke_rbrs( resource );
+            break;
+          default:
+            usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+            break;
+        }
+        break;
+      default:
+        usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+        break;
+    }
+}
+
+static void usbfront_hcd_resource_invalid_stimulus
+(
+    struct usbfront_hcd_resource   * resource,
+    usbfront_hcd_resource_stimulus   stimulus
+)
+{
+    trace();
+
+    printk
+    (
+        KERN_ERR "usbfront: hcd resource %p in state %d"
+        "received invalid stimulus %d",
+        resource,
+        resource->state,
+        stimulus
+    );
+}
+
+static void usbfront_hcd_resource_create_rbrs
+  ( struct usbfront_hcd_resource * resource )
+{
+    trace();
+
+    xenidc_create_rbr_request_element_ensure_removed
+      ( &resource->rbr_request_element[ 0 ] );
+
+    xenidc_create_rbr_request_element_ensure_removed
+      ( &resource->rbr_request_element[ 1 ] );
+
+    xenidc_create_rbr_request_element_set_lbr
+    (
+        &resource->rbr_request_element[ 0 ],
+        xenidc_vaddress_create_lbr
+        (
+            resource->urb->transfer_buffer,
+            resource->urb->transfer_buffer_length
+        )
+    );
+
+    xenidc_reserve_and_create_rbr_request_add_element
+    (
+        &resource->rbr_request,
+        &resource->rbr_request_element[ 0 ]
+    );
+
+    if( usb_pipetype( resource->urb->pipe ) == PIPE_ISOCHRONOUS )
+    {
+        if
+        (
+            resource->urb->number_of_packets
+            >
+            ( PAGE_SIZE / sizeof( usbif_isochronous_io_schedule_element ) )
+        )
+        {
+            goto SCHEDULE_TOO_BIG;
+        }
+
+        {
+            usbif_isochronous_io_schedule_element * element =
+              resource->schedule;
+
+            int i;
+
+            for( i = 0; i < resource->urb->number_of_packets; i++ )
+            {
+                memset( &element[ i ], 0, sizeof( element[ i ] ) );
+
+                element[ i ].offset =
+                  resource->urb->iso_frame_desc[ i ].offset;
+                element[ i ].length =
+                  resource->urb->iso_frame_desc[ i ].length;
+            }
+        }
+
+        xenidc_create_rbr_request_element_set_lbr
+        (
+            &resource->rbr_request_element[ 1 ],
+            xenidc_vaddress_create_lbr
+            (
+                resource->schedule,
+                sizeof( usbif_isochronous_io_schedule_element )
+                *
+                resource->urb->number_of_packets
+            )
+        );
+
+        xenidc_reserve_and_create_rbr_request_add_element
+        (
+            &resource->rbr_request,
+            &resource->rbr_request_element[ 1 ]
+        );
+    }
+
+    xenidc_rbr_provider_pool_reserve_and_create_rbrs
+    (
+        usbfront_hcd_resource_rbr_provider_pool,
+        &resource->rbr_request
+    );
+
+    return;
+
+  SCHEDULE_TOO_BIG:
+
+    xenidc_callback_complete
+    (
+        xenidc_reserve_and_create_rbr_request_to_create_callback
+          ( &resource->rbr_request ),
+        XENIDC_ERROR_TOO_BIG
+    );
+}
+
+static void usbfront_hcd_resource_create_rbrs_1( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        struct usbfront_hcd_resource * resource = container_of
+        (
+            xenidc_reserve_and_create_rbr_request_create_callback_to
+              ( callback ),
+            struct usbfront_hcd_resource,
+            rbr_request
+        );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &resource->lock, flags );
+
+        if( xenidc_callback_query_error( callback ) == XENIDC_ERROR_SUCCESS )
+        {
+            usbfront_hcd_resource_handle_stimulus
+              ( resource, usbfront_hcd_resource_stimulus_cs );
+        }
+        else
+        {
+            usbfront_hcd_resource_handle_stimulus
+              ( resource, usbfront_hcd_resource_stimulus_cf );
+        }
+
+        spin_unlock_irqrestore( &resource->lock, flags );
+    }
+}
+
+static void usbfront_hcd_resource_abort_create_rbrs
+  ( struct usbfront_hcd_resource * resource )
+{
+    trace();
+
+    xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs
+    (
+        usbfront_hcd_resource_rbr_provider_pool,
+        &resource->rbr_request
+    );
+}
+
+static void usbfront_hcd_resource_set_aborted_error
+  ( struct usbfront_hcd_resource * resource )
+{
+    trace();
+
+    xenidc_callback_set_error
+    (
+        xenidc_reserve_and_create_rbr_request_to_create_callback
+          ( &resource->rbr_request ),
+        XENIDC_ERROR_ABORTED
+    );
+}
+
+static void usbfront_hcd_resource_submit_transaction
+  ( struct usbfront_hcd_resource * resource )
+{
+    trace();
+
+    memset( &resource->io_parameters, 0, sizeof( resource->io_parameters ) );
+    memset( &resource->io_status, 0, sizeof( resource->io_status ) );
+
+    resource->io_parameters.header.header.transaction_type =
+      USBIF_TRANSACTION_TYPE_IO;
+
+    {
+        struct urb * urb = resource->urb;
+
+        resource->io_parameters.header.device_number =
+          usb_pipedevice( urb->pipe );
+
+        resource->io_parameters.header.endpoint =
+          usb_pipeendpoint( urb->pipe );
+
+        resource->io_parameters.header.direction = usb_pipein( urb->pipe ) ?
+          USBIF_IO_TRANSACTION_DIRECTION_IN :
+            USBIF_IO_TRANSACTION_DIRECTION_OUT;
+
+        resource->io_parameters.header.unlink_id = resource->index;
+
+        if( urb->transfer_flags & URB_SHORT_NOT_OK )
+        {
+            resource->io_parameters.header.flags |=
+              USBIF_IO_FLAGS_SHORT_NOT_OK;
+        }
+        if( urb->transfer_flags & URB_ZERO_PACKET )
+        {
+            resource->io_parameters.header.flags |=
+              USBIF_IO_FLAGS_ZERO_PACKET;
+        }
+
+        resource->io_parameters.header.rbr =
+          xenidc_create_rbr_request_element_query_rbr
+            ( &resource->rbr_request_element[ 0 ] );
+
+        if( usb_pipetype( urb->pipe ) == PIPE_CONTROL )
+        {
+            resource->io_parameters.header.io_transaction_type =
+              USBIF_IO_TRANSACTION_TYPE_CONTROL;
+
+            ASSERT( urb->setup_packet != NULL );
+
+            memcpy
+              ( resource->io_parameters.control.setup, urb->setup_packet, 8 );
+        }
+        else if( usb_pipetype( urb->pipe ) == PIPE_BULK )
+        {
+            resource->io_parameters.header.io_transaction_type =
+              USBIF_IO_TRANSACTION_TYPE_BULK;
+        }
+        else if( usb_pipetype( urb->pipe ) == PIPE_INTERRUPT )
+        {
+            resource->io_parameters.header.io_transaction_type =
+              USBIF_IO_TRANSACTION_TYPE_INTERRUPT;
+
+            resource->io_parameters.interrupt.interval = urb->interval;
+        }
+        else if( usb_pipetype( urb->pipe ) == PIPE_ISOCHRONOUS )
+        {
+            resource->io_parameters.header.io_transaction_type =
+              USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS;
+
+            resource->io_parameters.isochronous.interval = urb->interval;
+
+            resource->io_parameters.isochronous.schedule_rbr =
+              xenidc_create_rbr_request_element_query_rbr
+                ( &resource->rbr_request_element[ 1 ] );
+
+            resource->io_parameters.isochronous.packet_count =
+              urb->number_of_packets;
+        }
+    }
+
+    usbfront_device_submit_transaction
+      ( resource->device, &resource->io_transaction );
+}
+
+static void usbfront_hcd_resource_submit_transaction_1
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        struct usbfront_hcd_resource * resource = container_of
+        (
+            xenidc_endpoint_transaction_callback_to( callback ),
+            struct usbfront_hcd_resource,
+            io_transaction
+        );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &resource->lock, flags );
+
+        usbfront_hcd_resource_handle_stimulus
+          ( resource, usbfront_hcd_resource_stimulus_tc );
+
+        spin_unlock_irqrestore( &resource->lock, flags );
+    }
+}
+
+static void usbfront_hcd_resource_revoke_rbrs
+  ( struct usbfront_hcd_resource * resource )
+{
+    trace();
+
+    xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs
+    (
+        usbfront_hcd_resource_rbr_provider_pool,
+        &resource->rbr_request
+    );
+}
+
+static void usbfront_hcd_resource_revoke_rbrs_1
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        struct usbfront_hcd_resource * resource = container_of
+        (
+            xenidc_reserve_and_create_rbr_request_revoke_callback_to
+              ( callback ),
+            struct usbfront_hcd_resource,
+            rbr_request
+        );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &resource->lock, flags );
+
+        usbfront_hcd_resource_handle_stimulus
+          ( resource, usbfront_hcd_resource_stimulus_rc );
+
+        spin_unlock_irqrestore( &resource->lock, flags );
+    }
+}
+
+static void usbfront_hcd_resource_submit_unlink
+  ( struct usbfront_hcd_resource * resource )
+{
+    trace();
+
+    memset
+    (
+        &resource->unlink_message_body,
+        0,
+        sizeof( resource->unlink_message_body )
+    );
+
+    resource->unlink_message_body.header.message_type =
+      USBIF_MESSAGE_TYPE_UNLINK;
+
+    resource->unlink_message_body.unlink_id = resource->index;
+
+    usbfront_device_submit_message
+      ( resource->device, &resource->unlink_message );
+}
+
+static void usbfront_hcd_resource_submit_unlink_1( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        struct usbfront_hcd_resource * resource = container_of
+        (
+            xenidc_endpoint_message_callback_to( callback ),
+            struct usbfront_hcd_resource,
+            unlink_message
+        );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &resource->lock, flags );
+
+        usbfront_hcd_resource_handle_stimulus
+          ( resource, usbfront_hcd_resource_stimulus_uc );
+
+        spin_unlock_irqrestore( &resource->lock, flags );
+    }
+}
+
+static void usbfront_hcd_resource_complete
+  ( struct usbfront_hcd_resource * resource )
+{
+    trace();
+
+    {
+        int scheduled = xenidc_work_schedule( &resource->complete_1_work );
+
+        ASSERT( scheduled );
+    }
+}
+
+static void usbfront_hcd_resource_complete_1( void * context )
+{
+    trace();
+
+    {
+        struct usbfront_hcd_resource * resource =
+          (struct usbfront_hcd_resource *)context;
+
+        struct urb * urb = resource->urb;
+
+        xenidc_error error;
+
+        if
+        (
+            (
+                (
+                    error = xenidc_callback_query_error
+                    (
+                       xenidc_reserve_and_create_rbr_request_to_create_callback
+                          ( &resource->rbr_request )
+                    )
+                )
+                ==
+                XENIDC_ERROR_SUCCESS
+            )
+            &&
+            (
+                (
+                    error = xenidc_callback_query_error
+                    (
+                       xenidc_reserve_and_create_rbr_request_to_revoke_callback
+                          ( &resource->rbr_request )
+                    )
+                )
+                ==
+                XENIDC_ERROR_SUCCESS
+            )
+        )
+        {
+            urb->status        = usbif_error_map_to_local
+            (
+                xenidc_endpoint_transaction_query_error
+                  ( &resource->io_transaction )
+            );
+            urb->actual_length = resource->io_status.length;
+
+            if( usb_pipetype( urb->pipe ) == PIPE_ISOCHRONOUS )
+            {
+                int i;
+
+                for( i = 0; i < urb->number_of_packets; i++ )
+                {
+                    usbif_isochronous_io_schedule_element * schedule =
+                      &resource->schedule[ i ];
+
+                    urb->iso_frame_desc[ i ].actual_length = schedule->length;
+                    urb->iso_frame_desc[ i ].status        =
+                      usbif_error_map_to_local( schedule->error );
+                }
+
+                /* FIXME isoc error_count ?!? */
+            }
+        }
+        else
+        {
+            urb->status        = usbif_error_map_to_local( error );
+            urb->actual_length = 0;
+        }
+
+        {
+            unsigned long flags;
+
+            read_lock_irqsave( &dequeue_lock, flags );
+
+            urb->hcpriv = 0;
+
+            read_unlock_irqrestore( &dequeue_lock, flags );
+        }
+
+        {
+            unsigned long flags;
+
+            local_irq_save( flags );
+
+            usb_hcd_giveback_urb( /* FIXME hcd */ NULL, urb, NULL );
+
+            local_irq_restore( flags );
+        }
+
+        xenidc_callback_success( &resource->callback );
+    }
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,104 @@
+/*****************************************************************************/
+/* A resource used by the usbfront host controller device driver to process  */
+/* an URB by translating the URB and optional unlink request into            */
+/* a transaction and corresponding optional unlink message for submission to */
+/* the back end.                                                             */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBFRONT_HCD_RESOURCE_H
+#define USBFRONT_HCD_RESOURCE_H
+
+#include <asm/atomic.h>
+#include <linux/usb.h>
+#include <linux/list.h>
+#include "usbfront_device.h"
+
+int usbfront_hcd_resource_class_init( void );
+
+void usbfront_hcd_resource_class_exit( void );
+
+typedef enum
+{
+    usbfront_hcd_resource_state_i,
+    usbfront_hcd_resource_state_i_st,
+    usbfront_hcd_resource_state_i_st_dq,
+    usbfront_hcd_resource_state_i_st_cs,
+    usbfront_hcd_resource_state_i_st_dq_cs,
+    usbfront_hcd_resource_state_i_st_cs_dq,
+    usbfront_hcd_resource_state_i_st_cs_dq_tc
+}
+usbfront_hcd_resource_state;
+
+struct usbfront_hcd_resource
+{
+    xenidc_callback                         callback;
+    struct usbfront_device                * device;
+    int                                     index;
+    usbif_isochronous_io_schedule_element * schedule;
+    spinlock_t                              lock;
+    usbfront_hcd_resource_state             state;
+    struct urb                            * urb;
+    xenidc_create_rbr_request_element       rbr_request_element[ 2 ];
+    xenidc_reserve_and_create_rbr_request   rbr_request;
+    xenidc_endpoint_transaction             io_transaction;
+    usbif_io_transaction_parameters         io_parameters;
+    usbif_io_transaction_status             io_status;
+    xenidc_endpoint_message                 unlink_message;
+    usbif_unlink_message_body               unlink_message_body;
+    xenidc_work                             complete_1_work;
+};
+
+#define USBFRONT_HCD_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK
+
+static inline struct list_head * usbfront_hcd_resource_to_link
+  ( struct usbfront_hcd_resource * resource )
+{
+    return xenidc_callback_to_link( &resource->callback );
+}
+
+static inline struct usbfront_hcd_resource *
+  usbfront_hcd_resource_callback_to( xenidc_callback * callback )
+{
+    return container_of( callback, struct usbfront_hcd_resource, callback );
+}
+
+static inline struct usbfront_device * usbfront_hcd_resource_query_device
+  ( struct usbfront_hcd_resource * resource )
+{
+    return resource->device;
+}
+
+int usbfront_hcd_resource_init
+(
+    struct usbfront_hcd_resource * resource,
+    struct usbfront_device       * device,
+    int                            index,
+    xenidc_callback_function     * callback
+);
+
+void usbfront_hcd_resource_exit
+  ( struct usbfront_hcd_resource * resource );
+
+void usbfront_hcd_resource_start_urb
+  ( struct usbfront_hcd_resource * resource, struct urb * urb );
+
+void usbfront_hcd_resource_dequeue_urb( struct urb * urb );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_module.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_module.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,92 @@
+/*****************************************************************************/
+/* Front-end module for Xen USB split driver.                                */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbfront_device.h"
+#include "usbfront_driver.h"
+#include "usbfront_trace.h"
+
+static int usbfront_module_init_or_exit( int exit )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        if( usb_disabled() )
+        {
+            return_value = -ENODEV;
+
+            goto EXIT_NO_USB;
+        }
+
+        if( exit )
+        {
+            goto EXIT;
+        }
+
+        if( ( return_value = usbfront_driver_class_init() ) != 0 )
+        {
+            goto EXIT_NO_DRIVER_CLASS;
+        }
+
+        if( ( return_value = usbfront_device_class_init() ) != 0 )
+        {
+            goto EXIT_NO_DEVICE_CLASS;
+        }
+
+        return 0;
+
+      EXIT:
+
+        usbfront_device_class_exit();
+
+      EXIT_NO_DEVICE_CLASS:
+
+        usbfront_driver_class_exit();
+
+      EXIT_NO_DRIVER_CLASS:
+
+      EXIT_NO_USB:
+
+        return return_value;
+    }
+}
+
+static int __init usbfront_module_init( void )
+{
+    trace();
+
+    return usbfront_module_init_or_exit( 0 );
+}
+
+static void __exit usbfront_module_exit( void )
+{
+    trace();
+
+    (void)usbfront_module_init_or_exit( 1 );
+}
+
+module_init( usbfront_module_init );
+module_exit( usbfront_module_exit );
+
+MODULE_LICENSE( "GPL" );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_sll.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_sll.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,133 @@
+/*****************************************************************************/
+/* A singly linked list implementation                                       */
+/* 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 USBFRONT_SLL_H
+#define USBFRONT_SLL_H
+
+#include "usbfront_assert.h"
+
+struct usbfront_slk
+{
+    struct usbfront_slk * next;
+};
+
+struct usbfront_sll
+{
+    struct usbfront_slk * first;
+    struct usbfront_slk * last;
+};
+
+static inline void usbfront_slk_init( struct usbfront_slk * slk )
+{
+    slk->next = slk;
+}
+
+static inline int usbfront_slk_is_singular( struct usbfront_slk * slk )
+{
+    return ( slk->next == slk );
+}
+
+static inline void usbfront_sll_init( struct usbfront_sll * sll )
+{
+    sll->first = 0;
+}
+
+static inline int usbfront_sll_is_empty( struct usbfront_sll * sll )
+{
+    return ( sll->first == 0 );
+}
+
+static inline void usbfront_sll_add_last
+  ( struct usbfront_sll * sll, struct usbfront_slk * slk )
+{
+    ASSERT( usbfront_slk_is_singular( slk ) );
+
+    slk->next = 0;
+
+    if( sll->first != 0 )
+    {
+        sll->last->next = slk;
+    }
+    else
+    {
+        sll->first = slk;
+    }
+
+    sll->last = slk;
+}
+
+static inline struct usbfront_slk * usbfront_sll_remove_first
+  ( struct usbfront_sll * sll )
+{
+    struct usbfront_slk * slk = sll->first;
+
+    if( slk != 0 )
+    {
+        sll->first = slk->next;
+
+        slk->next = slk;
+    }
+
+    return slk;
+}
+
+/* Returns 1 if slk removed, 0 otherwise. */
+
+static inline int usbfront_sll_remove_slk
+  ( struct usbfront_sll * sll, struct usbfront_slk * slk )
+{
+    struct usbfront_slk * prev_slk = NULL;
+    struct usbfront_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 b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_trace.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_trace.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,53 @@
+/*****************************************************************************/
+/* Simple trace macros                                                       */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef USBFRONT_TRACE_H
+#define USBFRONT_TRACE_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_XEN_USBDEV_FRONTEND_TRACE
+
+#define trace0( format ) \
+printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__ )
+
+#define trace1( format, a0 ) \
+printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__, a0 )
+
+#define trace2( format, a0, a1 ) \
+printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__, a0, a1 )
+
+#define trace3( format, a0, a1, a2 ) \
+printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__, a0, a1, a2 )
+
+#define trace() trace0( "" )
+
+#else
+
+#define trace0( format )
+#define trace1( format,a0 )
+#define trace2( format,a0, a1 )
+#define trace3( format,a0, a1, a2 )
+#define trace()
+
+#endif
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,17 @@
+obj-y += xenidc.o
+
+xenidc-objs =
+xenidc-objs += xenidc_callback.o
+xenidc-objs += xenidc_concatenate.o
+xenidc-objs += xenidc_endpoint.o
+xenidc-objs += xenidc_gateway.o
+xenidc-objs += xenidc_gateway_initiator_resource.o
+xenidc-objs += xenidc_gateway_target_resource.o
+xenidc-objs += xenidc_gnttab_channel.o
+xenidc-objs += xenidc_local_buffer_reference.o
+xenidc-objs += xenidc_rbr_mapper_pool.o
+xenidc-objs += xenidc_rbr_provider_pool.o
+xenidc-objs += xenidc_vaddress.o
+xenidc-objs += xenidc_work.o
+xenidc-objs += xenidc_wrapping.o
+xenidc-objs += xenidc_xbgt_channel.o
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_callback.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_callback.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,61 @@
+/*****************************************************************************/
+/* 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                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#include "xenidc_callback.h"
+#include <linux/module.h>
+
+void xenidc_callback_serialiser_function( void * context )
+{
+    xenidc_callback_serialiser * serialiser =
+      (xenidc_callback_serialiser *)context;
+
+    unsigned long flags;
+
+    spin_lock_irqsave( &serialiser->lock, flags );
+
+    while
+    (
+        ( !list_empty( &serialiser->list ) )
+        &&
+        ( !serialiser->running )
+    )
+    {
+        xenidc_callback * callback =
+          xenidc_callback_link_to( serialiser->list.next );
+
+        list_del_init( xenidc_callback_to_link( callback ) );
+
+        serialiser->running = 1;
+
+        spin_unlock_irqrestore( &serialiser->lock, flags );
+
+        xenidc_callback_complete_synchronously( callback );
+
+        spin_lock_irqsave( &serialiser->lock, flags );
+
+        serialiser->running = 0;
+    }
+
+    spin_unlock_irqrestore( &serialiser->lock, flags );
+}
+
+EXPORT_SYMBOL( xenidc_callback_serialiser_function );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_channel_ring.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_channel_ring.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,44 @@
+/*****************************************************************************/
+/* Xen inter-domain communication channel ring structure definitions.        */
+/*                                                                           */
+/* 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 _XENIDC_CHANNEL_RING_H
+#define _XENIDC_CHANNEL_RING_H
+
+#include <asm-xen/xenidc.h>
+
+typedef struct xenidc_channel_ring_header_struct xenidc_channel_ring_header;
+
+struct xenidc_channel_ring_header_struct
+{
+    u16 this_ring_producer_offset;
+    u16 other_ring_consumer_offset;
+};
+
+typedef struct xenidc_channel_ring_element_header_struct
+  xenidc_channel_ring_element_header;
+
+struct xenidc_channel_ring_element_header_struct
+{
+    u16 length;
+    u8  reserved1[6];
+};
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_concatenate.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_concatenate.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,140 @@
+/*****************************************************************************/
+/* Xen inter-domain communication concatenate local buffer reference type.   */
+/*                                                                           */
+/* 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 <asm-xen/xenidc_concatenate.h>
+#include <linux/module.h>
+#include "xenidc_trace.h"
+
+static xenidc_buffer_type xenidc_concatenate_type;
+
+static xenidc_local_buffer_reference xenidc_concatenate_resolve
+(
+    xenidc_buffer_virtual_class   * class,
+    xenidc_local_buffer_reference * lbr
+)
+{
+    trace();
+
+    {
+        xenidc_local_buffer_reference resolved_lbr;
+
+        xenidc_concatenate_base * base = (xenidc_concatenate_base *)lbr->base;
+
+        if( lbr->byte_offset < base->head->byte_count )
+        {
+            resolved_lbr = *base->head;
+
+            xenidc_local_buffer_reference_subrange
+              ( &resolved_lbr, lbr->byte_offset, lbr->byte_count );
+        }
+        else
+        {
+            resolved_lbr = *base->tail;
+
+            xenidc_local_buffer_reference_subrange
+            (
+                &resolved_lbr,
+                lbr->byte_offset - base->head->byte_count,
+                lbr->byte_count
+            );
+        }
+
+        return resolved_lbr;
+    }
+}
+
+static void xenidc_concatenate_init( void )
+{
+    trace();
+
+    {
+        static DEFINE_RWLOCK( xenidc_concatenate_lock );
+
+        unsigned long flags;
+
+        read_lock_irqsave( &xenidc_concatenate_lock, flags );
+
+        {
+            static int initialised = 0;
+
+            if( !initialised )
+            {
+                read_unlock_irqrestore
+                  ( &xenidc_concatenate_lock, flags );
+
+                write_lock_irqsave
+                  ( &xenidc_concatenate_lock, flags );
+
+                if( !initialised )
+                {
+                    static xenidc_buffer_virtual_class
+                      xenidc_concatenate_virtual_class;
+
+                    xenidc_concatenate_type =
+                      xenidc_local_buffer_reference_register_buffer_virtual_class
+                    (
+                        &xenidc_concatenate_virtual_class,
+                        xenidc_concatenate_resolve,
+                        NULL
+                    );
+
+                    initialised = 1;
+                }
+
+                write_unlock_irqrestore
+                  ( &xenidc_concatenate_lock, flags );
+
+                read_lock_irqsave
+                  ( &xenidc_concatenate_lock, flags );
+            }
+        }
+
+        read_unlock_irqrestore( &xenidc_concatenate_lock, flags );
+    }
+}
+
+xenidc_local_buffer_reference xenidc_concatenate_create_lbr
+(
+    xenidc_concatenate_base       * base,
+    xenidc_local_buffer_reference * head,
+    xenidc_local_buffer_reference * tail
+)
+{
+    trace();
+
+    xenidc_concatenate_init();
+
+    base->head = head;
+    base->tail = tail;
+
+    {
+        xenidc_local_buffer_reference lbr;
+
+        lbr.type        = xenidc_concatenate_type;
+        lbr.base        = base;
+        lbr.byte_offset = 0;
+        lbr.byte_count  = head->byte_count + tail->byte_count;
+
+        return lbr;
+    }
+}
+
+EXPORT_SYMBOL( xenidc_concatenate_create_lbr );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,176 @@
+/*****************************************************************************/
+/* Xen inter-domain communication API, endpoint object.                      */
+/*                                                                           */
+/* 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 <asm-xen/xenidc_endpoint.h>
+#include <linux/module.h>
+#include "xenidc_trace.h"
+
+int xenidc_endpoint_init
+(
+    xenidc_endpoint * endpoint,
+
+    void ( * connect )( xenidc_endpoint * endpoint ),
+    void ( * handle_message )
+      ( xenidc_endpoint * endpoint, xenidc_endpoint_message * message ),
+    void ( * handle_transaction )
+    (
+        xenidc_endpoint * endpoint,
+        xenidc_endpoint_transaction * transaction
+    ),
+    void ( * disconnect )
+      ( xenidc_endpoint * endpoint, xenidc_callback * callback ),
+    u32                      initiator_quota,
+    xenidc_buffer_byte_count initiator_maximum_byte_count,
+    u32                      target_quota,
+    xenidc_buffer_byte_count target_maximum_byte_count
+)
+{
+    trace();
+
+    {
+        int return_value = xenidc_xbgt_channel_init( &endpoint->channel );
+
+        if( return_value != 0 )
+        {
+            goto EXIT_NO_CHANNEL;
+        }
+
+        return_value = xenidc_gateway_init
+        (
+            &endpoint->gateway,
+            xenidc_xbgt_channel_to_channel( &endpoint->channel ),
+            (void (*)( xenidc_gateway * ))connect,
+            (void (*)( xenidc_gateway *, xenidc_endpoint_message* ))
+              handle_message,
+            (void (*)( xenidc_gateway *, xenidc_endpoint_transaction *))
+              handle_transaction,
+            (void (*)( xenidc_gateway *, xenidc_callback *))disconnect,
+            initiator_quota,
+            initiator_maximum_byte_count,
+            target_quota,
+            target_maximum_byte_count
+        );
+
+        if( return_value != 0 )
+        {
+            goto EXIT_NO_GATEWAY;
+        }
+
+        return 0;
+
+      EXIT_NO_GATEWAY:
+
+        xenidc_xbgt_channel_exit( &endpoint->channel );
+
+      EXIT_NO_CHANNEL:
+
+        return return_value;
+    }
+}
+
+void xenidc_endpoint_create
+  ( xenidc_endpoint * endpoint, xenidc_address address )
+{
+    trace();
+
+    xenidc_xbgt_channel_connect
+    (
+        &endpoint->channel,
+        xenidc_address_query_local_domain( &address ),
+        xenidc_address_query_remote_domain( &address ),
+        xenidc_address_query_remote_domain_id( &address )
+    );
+}
+
+void xenidc_endpoint_submit_message
+  ( xenidc_endpoint * endpoint, xenidc_endpoint_message * message )
+{
+    trace();
+
+    xenidc_gateway_submit_message( &endpoint->gateway, message );
+}
+
+void xenidc_endpoint_submit_transaction
+  ( xenidc_endpoint * endpoint, xenidc_endpoint_transaction * transaction )
+{
+    trace();
+
+    xenidc_gateway_submit_transaction( &endpoint->gateway, transaction );
+}
+
+typedef struct xenidc_endpoint_callback_struct xenidc_endpoint_callback;
+
+struct xenidc_endpoint_callback_struct
+{
+    xenidc_callback callback;
+    int             destroyed;
+};
+
+static void xenidc_endpoint_destroy_1( xenidc_callback * callback );
+
+void xenidc_endpoint_destroy( xenidc_endpoint * endpoint )
+{
+    trace();
+
+    {
+        xenidc_endpoint_callback endpoint_callback;
+
+        xenidc_callback_init
+          ( &endpoint_callback.callback, xenidc_endpoint_destroy_1 );
+
+        endpoint_callback.destroyed = 0;
+
+        xenidc_xbgt_channel_disconnect
+          ( &endpoint->channel, &endpoint_callback.callback );
+
+        xenidc_work_until( endpoint_callback.destroyed );
+    }
+}
+
+static void xenidc_endpoint_destroy_1( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_endpoint_callback * endpoint_callback =
+          container_of( callback, xenidc_endpoint_callback, callback );
+
+        endpoint_callback->destroyed = 1;
+
+        xenidc_work_wake_up();
+    }
+}
+
+void xenidc_endpoint_exit( xenidc_endpoint * endpoint )
+{
+    trace();
+
+    xenidc_gateway_exit( &endpoint->gateway );
+
+    xenidc_xbgt_channel_exit( &endpoint->channel );
+}
+
+EXPORT_SYMBOL( xenidc_endpoint_init );
+EXPORT_SYMBOL( xenidc_endpoint_create );
+EXPORT_SYMBOL( xenidc_endpoint_submit_message );
+EXPORT_SYMBOL( xenidc_endpoint_submit_transaction );
+EXPORT_SYMBOL( xenidc_endpoint_destroy );
+EXPORT_SYMBOL( xenidc_endpoint_exit );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,1344 @@
+#include <asm-xen/xenidc_gateway.h>
+#include <asm-xen/xenidc_vaddress.h>
+#include <linux/vmalloc.h>
+#include "xenidc_gateway_initiator_resource.h"
+#include "xenidc_gateway_target_resource.h"
+#include "xenidc_trace.h"
+
+typedef enum
+{
+    xenidc_gateway_stimulus_mt, /* Message or transaction queued.            */
+    xenidc_gateway_stimulus_cc, /* Channel connect.                          */
+    xenidc_gateway_stimulus_cm, /* Channel message.                          */
+    xenidc_gateway_stimulus_cd, /* Channel disconnect.                       */
+    xenidc_gateway_stimulus_km, /* Kick messages and transactions completed. */
+    xenidc_gateway_stimulus_kc, /* Kick channel messages completed.          */
+    xenidc_gateway_stimulus_ic, /* Initiator resource completed.             */
+    xenidc_gateway_stimulus_ii, /* Initiator resources idle.                 */
+    xenidc_gateway_stimulus_tc, /* Target resource completed.                */
+    xenidc_gateway_stimulus_ti, /* Target resources idle.                    */
+    xenidc_gateway_stimulus_lc, /* Client connect completed.                 */
+    xenidc_gateway_stimulus_lg, /* Client disconnect called.                 */
+    xenidc_gateway_stimulus_ld, /* Client disconnect completed.              */
+}
+xenidc_gateway_stimulus;
+
+static void xenidc_gateway_handle_stimulus
+  ( xenidc_gateway * gateway, xenidc_gateway_stimulus stimulus );
+
+static void xenidc_gateway_channel_connect( void * context );
+
+static void xenidc_gateway_handle_channel_message
+  ( void * context, xenidc_channel_message * message );
+
+static void xenidc_gateway_channel_disconnect
+  ( void * context, xenidc_callback * callback );
+
+static int xenidc_gateway_init_or_exit( xenidc_gateway * gateway, int exit );
+
+int xenidc_gateway_init
+(
+    xenidc_gateway * gateway,
+    xenidc_channel * channel,
+    void         ( * connect )( xenidc_gateway * gateway ),
+    void         ( * handle_message )
+      ( xenidc_gateway * gateway, xenidc_gateway_message * message ),
+    void         ( * handle_transaction )
+      ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction ),
+    void         ( * disconnect )
+      ( xenidc_gateway * gateway, xenidc_callback * callback ),
+    u32                      initiator_quota,
+    xenidc_buffer_byte_count initiator_maximum_byte_count,
+    u32                      target_quota,
+    xenidc_buffer_byte_count target_maximum_byte_count
+)
+{
+    trace();
+
+    gateway->channel            = channel;
+    gateway->connect            = connect;
+    gateway->handle_message     = handle_message;
+    gateway->handle_transaction = handle_transaction;
+    gateway->disconnect         = disconnect;
+
+    gateway->initiator_quota           = initiator_quota;
+    gateway->target_quota              = target_quota;
+    gateway->target_maximum_byte_count = target_maximum_byte_count;
+
+    xenidc_channel_install_client
+    (
+        channel,
+        gateway,
+        xenidc_gateway_channel_connect,
+        xenidc_gateway_handle_channel_message,
+        xenidc_gateway_channel_disconnect
+    );
+
+    return xenidc_gateway_init_or_exit( gateway, 0 );
+}
+
+static void xenidc_gateway_kick_messages_and_transactions_1( void * data );
+
+static void xenidc_gateway_kick_messages_and_transactions_2
+  ( xenidc_callback * callback );
+
+static void xenidc_gateway_kick_channel_messages_1( void * data );
+
+static void xenidc_gateway_kick_channel_messages_2
+  ( xenidc_callback * callback );
+
+static void xenidc_gateway_connect_client_1( void * data );
+
+static void xenidc_gateway_disconnect_client_1( void * data );
+
+static void xenidc_gateway_disconnect_client_2( xenidc_callback * callback );
+
+static int xenidc_gateway_init_or_exit( xenidc_gateway * gateway, int exit )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        if( exit )
+        {
+            goto EXIT;
+        }
+
+        INIT_LIST_HEAD( &gateway->initiator_resource_list );
+
+        if( gateway->initiator_quota != 0 )
+        {
+            gateway->initiator_resources = vmalloc
+            (
+                sizeof( xenidc_gateway_initiator_resource )
+                *
+                gateway->initiator_quota
+            );
+
+            if( gateway->initiator_resources == NULL )
+            {
+                trace0( "failed to allocate initiator resources" );
+
+                return_value = -ENOMEM;
+
+                goto EXIT_NO_INITIATOR_RESOURCES;
+            }
+
+            {
+                u32 i;
+
+                for( i = 0; i < gateway->initiator_quota; i++ )
+                {
+                    xenidc_gateway_initiator_resource * resource =
+                      &gateway->initiator_resources[ i ];
+
+                    xenidc_gateway_initiator_resource_init
+                    (
+                        resource,
+                        gateway,
+                        xenidc_gateway_kick_messages_and_transactions_2,
+                        i
+                    );
+
+                    list_add_tail
+                    (
+                        xenidc_gateway_initiator_resource_to_link( resource ),
+                        &gateway->initiator_resource_list
+                    );
+                }
+            }
+        }
+
+        INIT_LIST_HEAD( &gateway->target_resource_list );
+
+        if( gateway->target_quota != 0 )
+        {
+            gateway->target_resources = vmalloc
+            (
+                (
+                    sizeof( xenidc_gateway_target_resource )
+                    *
+                    gateway->target_quota
+                )
+                +
+                (
+                    gateway->target_maximum_byte_count
+                    *
+                    gateway->target_quota
+                )
+            );
+
+            if( gateway->target_resources == NULL )
+            {
+                trace0( "failed to allocate target resources" );
+
+                return_value = -ENOMEM;
+
+                goto EXIT_NO_TARGET_RESOURCES;
+            }
+
+            {
+                xenidc_local_buffer_reference buffer_area =
+                  xenidc_vaddress_create_lbr
+                (
+                    &gateway->target_resources
+                      [ gateway->target_quota ],
+                    gateway->target_maximum_byte_count *
+                      gateway->target_quota
+                );
+
+                u32 i;
+
+                for( i = 0; i < gateway->target_quota; i++ )
+                {
+                    xenidc_gateway_target_resource * resource =
+                      &gateway->target_resources[ i ];
+
+                    xenidc_local_buffer_reference buffer = buffer_area;
+
+                    xenidc_local_buffer_reference_truncate
+                    (
+                        &buffer,
+                        gateway->target_maximum_byte_count
+                    );
+
+                    xenidc_gateway_target_resource_init
+                    (
+                        resource,
+                        gateway,
+                        xenidc_gateway_kick_channel_messages_2,
+                        buffer
+                    );
+
+                    list_add_tail
+                    (
+                        xenidc_gateway_target_resource_to_link( resource ),
+                        &gateway->target_resource_list
+                    );
+
+                    xenidc_local_buffer_reference_advance
+                    (
+                        &buffer_area,
+                        gateway->target_maximum_byte_count
+                    );
+                }
+            }
+        }
+
+        spin_lock_init( &gateway->lock );
+
+        gateway->state = xenidc_gateway_state_i;
+
+        INIT_LIST_HEAD( &gateway->message_and_transaction_list );
+        INIT_LIST_HEAD( &gateway->channel_message_list );
+
+        xenidc_work_init
+        (
+            &gateway->kick_messages_and_transactions_1_work,
+            xenidc_gateway_kick_messages_and_transactions_1,
+            gateway
+        );
+
+        xenidc_work_init
+        (
+            &gateway->kick_channel_messages_1_work,
+            xenidc_gateway_kick_channel_messages_1,
+            gateway
+        );
+
+        xenidc_work_init
+        (
+            &gateway->connect_client_1_work,
+            xenidc_gateway_connect_client_1,
+            gateway
+        );
+
+        xenidc_work_init
+        (
+            &gateway->disconnect_client_1_work,
+            xenidc_gateway_disconnect_client_1,
+            gateway
+        );
+
+        xenidc_callback_init
+        (
+            &gateway->disconnect_client_2_callback,
+            xenidc_gateway_disconnect_client_2
+        );
+
+        gateway->kick_messages_and_transactions_out = 0;
+        gateway->kick_channel_messages_out = 0;
+        gateway->initiator_resources_out = 0;
+        gateway->target_resources_out = 0;
+
+        return 0;
+
+      EXIT:
+
+        if( gateway->target_quota != 0 )
+        {
+            vfree( gateway->target_resources );
+        }
+
+      EXIT_NO_TARGET_RESOURCES:
+
+        if( gateway->initiator_quota != 0 )
+        {
+            vfree( gateway->initiator_resources );
+        }
+
+      EXIT_NO_INITIATOR_RESOURCES:
+
+        return return_value;
+    }
+}
+
+void xenidc_gateway_submit_message
+  ( xenidc_gateway * gateway, xenidc_gateway_message * message )
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &gateway->lock, flags );
+
+        list_add_tail
+        (
+            xenidc_gateway_message_to_link( message ),
+            &gateway->message_and_transaction_list
+        );
+
+        xenidc_gateway_handle_stimulus
+          ( gateway, xenidc_gateway_stimulus_mt );
+
+        spin_unlock_irqrestore( &gateway->lock, flags );
+    }
+}
+
+void xenidc_gateway_submit_transaction
+  ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction )
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &gateway->lock, flags );
+
+        list_add_tail
+        (
+            xenidc_gateway_transaction_to_link( transaction ),
+            &gateway->message_and_transaction_list
+        );
+
+        xenidc_gateway_handle_stimulus
+          ( gateway, xenidc_gateway_stimulus_mt );
+
+        spin_unlock_irqrestore( &gateway->lock, flags );
+    }
+}
+
+void xenidc_gateway_exit( xenidc_gateway * gateway )
+{
+    trace();
+
+    (void)xenidc_gateway_init_or_exit( gateway, 1 );
+}
+
+static void xenidc_gateway_channel_connect( void * context )
+{
+    trace();
+
+    {
+        xenidc_gateway * gateway = (xenidc_gateway *)context;
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &gateway->lock, flags );
+
+        xenidc_gateway_handle_stimulus
+          ( gateway, xenidc_gateway_stimulus_cc );
+
+        spin_unlock_irqrestore( &gateway->lock, flags );
+    }
+}
+
+static void xenidc_gateway_handle_channel_message
+  ( void * context, xenidc_channel_message * message )
+{
+    trace();
+
+    {
+        xenidc_gateway * gateway = (xenidc_gateway *)context;
+
+        xenidc_gateway_ring_element_header header;
+
+        if
+        (
+            xenidc_local_buffer_reference_copy_out
+              ( &message->message_lbr, &header, sizeof( header ) )
+            !=
+            sizeof( header )
+        )
+        {
+            goto PROTOCOL_ERROR;
+        }
+
+        if( header.type == XENIDC_GATEWAY_RING_ELEMENT_TYPE_STATUS )
+        {
+            xenidc_local_buffer_reference status_lbr = message->message_lbr;
+
+            xenidc_gateway_status_ring_element status_element;
+
+            if
+            (
+                xenidc_local_buffer_reference_copy_out
+                  ( &status_lbr, &status_element, sizeof( status_element ) )
+                !=
+                sizeof( status_element )
+            )
+            {
+                goto PROTOCOL_ERROR;
+            }
+
+            xenidc_local_buffer_reference_advance
+              ( &status_lbr, sizeof( status_element ) );
+
+            if( status_element.id >= gateway->initiator_quota )
+            {
+                goto PROTOCOL_ERROR;
+            }
+
+            {
+                xenidc_gateway_initiator_resource * resource =
+                  &gateway->initiator_resources[ status_element.id ];
+
+                if
+                (
+                    xenidc_gateway_initiator_resource_handle_status
+                      ( resource, status_element.error, status_lbr )
+                    !=
+                    0
+                )
+                {
+                    goto PROTOCOL_ERROR;
+                }
+            }
+
+            xenidc_callback_success
+              ( xenidc_channel_message_to_callback( message ) );
+        }
+        else
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &gateway->lock, flags );
+
+            list_add_tail
+            (
+                xenidc_channel_message_to_link( message ),
+                &gateway->channel_message_list
+            );
+
+            xenidc_gateway_handle_stimulus
+              ( gateway, xenidc_gateway_stimulus_cm );
+
+            spin_unlock_irqrestore( &gateway->lock, flags );
+        }
+    }
+
+    return;
+
+  PROTOCOL_ERROR:
+
+    xenidc_callback_complete
+    (
+        xenidc_channel_message_to_callback( message ),
+        XENIDC_ERROR_INVALID_PROTOCOL
+    );
+}
+
+static void xenidc_gateway_channel_disconnect
+  ( void * context, xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_gateway * gateway = (xenidc_gateway *)context;
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &gateway->lock, flags );
+
+        gateway->channel_disconnect_callback = callback;
+
+        xenidc_gateway_handle_stimulus
+          ( gateway, xenidc_gateway_stimulus_cd );
+
+        spin_unlock_irqrestore( &gateway->lock, flags );
+    }
+}
+
+void xenidc_gateway_submit_channel_message
+  ( xenidc_gateway * gateway, xenidc_channel_message * message )
+{
+    trace();
+
+    xenidc_channel_submit_message( gateway->channel, message );
+}
+
+void xenidc_gateway_submit_message_to_client
+  ( xenidc_gateway * gateway, xenidc_gateway_message * message )
+{
+    trace();
+
+    gateway->handle_message( gateway, message );
+}
+
+void xenidc_gateway_submit_transaction_to_client
+  ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction )
+{
+    trace();
+
+    gateway->handle_transaction( gateway, transaction );
+}
+
+static void xenidc_gateway_invalid_stimulus
+  ( xenidc_gateway * gateway, xenidc_gateway_stimulus stimulus );
+
+static void xenidc_gateway_kick_messages_and_transactions
+  ( xenidc_gateway * gateway );
+
+static void xenidc_gateway_fail_out_messages_and_transactions
+  ( xenidc_gateway * gateway );
+
+static void xenidc_gateway_kick_channel_messages( xenidc_gateway * gateway );
+
+static void xenidc_gateway_complete_channel_messages
+  ( xenidc_gateway * gateway );
+
+static void xenidc_gateway_connect_client( xenidc_gateway * gateway );
+
+static void xenidc_gateway_disconnect_client( xenidc_gateway * gateway );
+
+static void xenidc_gateway_abort_initiator_resources
+  ( xenidc_gateway * gateway );
+
+static void xenidc_gateway_test_initiator_resources
+  ( xenidc_gateway * gateway );
+
+static void xenidc_gateway_test_target_resources( xenidc_gateway * gateway );
+
+static void xenidc_gateway_complete_channel_disconnect
+  ( xenidc_gateway * gateway );
+
+static void xenidc_gateway_handle_stimulus
+  ( xenidc_gateway * gateway, xenidc_gateway_stimulus stimulus )
+{
+    trace3
+    (
+        "gateway %p in state %d received stimulus %d",
+        gateway,
+        gateway->state,
+        stimulus
+    );
+
+    switch( gateway->state )
+    {
+      case xenidc_gateway_state_i:
+        /* Channel disconnected.               */
+        /* Client disconnected.                */
+        /* No messages or transactions queued. */
+        /* No channel messages queued.         */
+        /* Initiator resources idle.           */
+        /* Target resources idle.              */
+        /* Not kicking m/t.                    */
+        /* Not kicking cm.                     */
+        switch( stimulus )
+        {
+          case xenidc_gateway_stimulus_cc:
+            gateway->state = xenidc_gateway_state_i_cc;
+            xenidc_gateway_connect_client( gateway );
+            break;
+          default:
+            xenidc_gateway_invalid_stimulus( gateway, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_state_i_cc:
+        /* Channel connected.                     */
+        /* Client connecting.                     */
+        /* Maybe messages or transactions queued. */
+        /* Maybe channel messages queued.         */
+        /* Initiator resources idle.              */
+        /* Target resources idle.                 */
+        /* Not kicking m/t.                       */
+        /* Not kicking cm.                        */
+        switch( stimulus )
+        {
+          case xenidc_gateway_stimulus_mt:
+          case xenidc_gateway_stimulus_cm:
+            break;
+          case xenidc_gateway_stimulus_cd:
+            gateway->state = xenidc_gateway_state_i_cc_cd;
+            xenidc_gateway_complete_channel_messages( gateway );
+            break;
+          case xenidc_gateway_stimulus_lc:
+            gateway->state = xenidc_gateway_state_i_cc_lc;
+            xenidc_gateway_kick_messages_and_transactions( gateway );
+            xenidc_gateway_kick_channel_messages( gateway );
+            break;
+          default:
+            xenidc_gateway_invalid_stimulus( gateway, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_state_i_cc_cd:
+        /* Channel disconnecting.                 */
+        /* Client connecting.                     */
+        /* Maybe messages or transactions queued. */
+        /* No channel messages queued.            */
+        /* Initiator resources idle.              */
+        /* Target resources idle.                 */
+        /* Not kicking m/t.                       */
+        /* Not kicking cm.                        */
+        switch( stimulus )
+        {
+          case xenidc_gateway_stimulus_mt:
+            break;
+          case xenidc_gateway_stimulus_lc:
+            gateway->state = xenidc_gateway_state_i_cc_cd_lc;
+            xenidc_gateway_disconnect_client( gateway );
+            break;
+          default:
+            xenidc_gateway_invalid_stimulus( gateway, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_state_i_cc_lc:
+        /* Channel connected.                     */
+        /* Client connected.                      */
+        /* Maybe messages or transactions queued. */
+        /* Maybe channel messages queued.         */
+        /* Maybe initiator resources busy.        */
+        /* Maybe target resources busy.           */
+        /* Maybe kicking m/t.                     */
+        /* Maybe kicking cm.                      */
+        switch( stimulus )
+        {
+          case xenidc_gateway_stimulus_mt:
+            xenidc_gateway_kick_messages_and_transactions( gateway );
+            break;
+          case xenidc_gateway_stimulus_cm:
+            xenidc_gateway_kick_channel_messages( gateway );
+            break;
+          case xenidc_gateway_stimulus_cd:
+            gateway->state = xenidc_gateway_state_i_cc_lc_cd;
+            xenidc_gateway_complete_channel_messages( gateway );
+            xenidc_gateway_kick_messages_and_transactions( gateway );
+            xenidc_gateway_kick_channel_messages( gateway );
+            break;
+          case xenidc_gateway_stimulus_km:
+          case xenidc_gateway_stimulus_kc:
+            break;
+          case xenidc_gateway_stimulus_ic:
+          case xenidc_gateway_stimulus_ii:
+            xenidc_gateway_kick_messages_and_transactions( gateway );
+            break;
+          case xenidc_gateway_stimulus_tc:
+          case xenidc_gateway_stimulus_ti:
+            xenidc_gateway_kick_channel_messages( gateway );
+            break;
+          default:
+            xenidc_gateway_invalid_stimulus( gateway, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_state_i_cc_lc_cd:
+        /* Channel disconnecting.                 */
+        /* Client connected.                      */
+        /* Maybe messages or transactions queued. */
+        /* No channel messages queued.            */
+        /* Maybe initiator resources busy.        */
+        /* Maybe target resources busy.           */
+        /* Kicking m/t.                           */
+        /* Kicking cm.                            */
+        switch( stimulus )
+        {
+          case xenidc_gateway_stimulus_mt:
+            break;
+          case xenidc_gateway_stimulus_km:
+          case xenidc_gateway_stimulus_kc:
+            gateway->state = xenidc_gateway_state_i_cc_lc_cd_km;
+            break;
+          case xenidc_gateway_stimulus_ic:
+          case xenidc_gateway_stimulus_ii:
+          case xenidc_gateway_stimulus_tc:
+          case xenidc_gateway_stimulus_ti:
+            break;
+          default:
+            xenidc_gateway_invalid_stimulus( gateway, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_state_i_cc_lc_cd_km:
+        /* Channel disconnecting.                 */
+        /* Client connected.                      */
+        /* Maybe messages or transactions queued. */
+        /* No channel messages queued.            */
+        /* Maybe initiator resources busy.        */
+        /* Maybe target resources busy.           */
+        /* One of kicking m/t or cm.              */
+        switch( stimulus )
+        {
+          case xenidc_gateway_stimulus_mt:
+            break;
+          case xenidc_gateway_stimulus_km:
+          case xenidc_gateway_stimulus_kc:
+            gateway->state = xenidc_gateway_state_i_cc_cd_lc;
+            xenidc_gateway_disconnect_client( gateway );
+            break;
+          case xenidc_gateway_stimulus_ic:
+          case xenidc_gateway_stimulus_ii:
+          case xenidc_gateway_stimulus_tc:
+          case xenidc_gateway_stimulus_ti:
+            break;
+          default:
+            xenidc_gateway_invalid_stimulus( gateway, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_state_i_cc_cd_lc:
+        /* Channel disconnecting.                 */
+        /* Calling client disconnect.             */
+        /* Maybe messages or transactions queued. */
+        /* No channel messages queued.            */
+        /* Maybe initiator resources busy.        */
+        /* Maybe target resources busy.           */
+        /* Not kicking m/t.                       */
+        /* Not kicking cm.                        */
+        switch( stimulus )
+        {
+          case xenidc_gateway_stimulus_mt:
+            break;
+          case xenidc_gateway_stimulus_ic:
+          case xenidc_gateway_stimulus_ii:
+          case xenidc_gateway_stimulus_tc:
+          case xenidc_gateway_stimulus_ti:
+            break;
+          case xenidc_gateway_stimulus_lg:
+            gateway->state = xenidc_gateway_state_i_cc_cd_lc_lg;
+            xenidc_gateway_fail_out_messages_and_transactions( gateway );
+            xenidc_gateway_abort_initiator_resources( gateway );
+            break;
+          case xenidc_gateway_stimulus_ld:
+            gateway->state = xenidc_gateway_state_i_cc_cd_lc_ld;
+            break;
+          default:
+            xenidc_gateway_invalid_stimulus( gateway, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_state_i_cc_cd_lc_lg:
+        /* Channel disconnecting.              */
+        /* Client disconnecting.               */
+        /* No messages or transactions queued. */
+        /* No channel messages queued.         */
+        /* Maybe initiator resources busy.     */
+        /* Maybe target resources busy.        */
+        /* Not kicking m/t.                    */
+        /* Not kicking cm.                     */
+        switch( stimulus )
+        {
+          case xenidc_gateway_stimulus_mt:
+            break;
+          case xenidc_gateway_stimulus_ic:
+          case xenidc_gateway_stimulus_ii:
+          case xenidc_gateway_stimulus_tc:
+          case xenidc_gateway_stimulus_ti:
+            break;
+          case xenidc_gateway_stimulus_ld:
+            gateway->state = xenidc_gateway_state_i_cc_cd_lc_lg_ld;
+            xenidc_gateway_test_target_resources( gateway );
+            break;
+          default:
+            xenidc_gateway_invalid_stimulus( gateway, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_state_i_cc_cd_lc_ld:
+        /* Channel disconnecting.                          */
+        /* Client disconnected but call still in progress. */
+        /* No messages or transactions queued.             */
+        /* No channel messages queued.                     */
+        /* Maybe initiator resources busy.                 */
+        /* Maybe target resources busy.                    */
+        /* Not kicking m/t.                                */
+        /* Not kicking cm.                                 */
+        switch( stimulus )
+        {
+          case xenidc_gateway_stimulus_ic:
+          case xenidc_gateway_stimulus_ii:
+          case xenidc_gateway_stimulus_tc:
+          case xenidc_gateway_stimulus_ti:
+            break;
+          case xenidc_gateway_stimulus_lg:
+            gateway->state = xenidc_gateway_state_i_cc_cd_lc_lg_ld;
+            xenidc_gateway_test_target_resources( gateway );
+            break;
+          default:
+            xenidc_gateway_invalid_stimulus( gateway, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_state_i_cc_cd_lc_lg_ld:
+        /* Channel disconnecting.                          */
+        /* Client disconnected.                            */
+        /* No messages or transactions queued.             */
+        /* No channel messages queued.                     */
+        /* Maybe initiator resources busy.                 */
+        /* Test target resources or target resources busy. */
+        /* Not kicking m/t.                                */
+        /* Not kicking cm.                                 */
+        switch( stimulus )
+        {
+          case xenidc_gateway_stimulus_ic:
+          case xenidc_gateway_stimulus_ii:
+          case xenidc_gateway_stimulus_tc:
+            break;
+          case xenidc_gateway_stimulus_ti:
+            gateway->state = xenidc_gateway_state_i_cc_cd_lc_lg_ld_ti;
+            xenidc_gateway_test_initiator_resources( gateway );
+            break;
+          default:
+            xenidc_gateway_invalid_stimulus( gateway, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_state_i_cc_cd_lc_lg_ld_ti:
+        /* Channel disconnecting.                                */
+        /* Client disconnected.                                  */
+        /* No messages or transactions queued.                   */
+        /* No channel messages queued.                           */
+        /* Test initiator resources or initiator resources busy. */
+        /* Target resources idle.                                */
+        /* Not kicking m/t.                                      */
+        /* Not kicking cm.                                       */
+        switch( stimulus )
+        {
+          case xenidc_gateway_stimulus_ic:
+            break;
+          case xenidc_gateway_stimulus_ii:
+            gateway->state = xenidc_gateway_state_i;
+            xenidc_gateway_complete_channel_disconnect( gateway );
+            break;
+          default:
+            xenidc_gateway_invalid_stimulus( gateway, stimulus );
+            break;
+        }
+        break;
+      default:
+        xenidc_gateway_invalid_stimulus( gateway, stimulus );
+        break;
+    }
+}
+
+static void xenidc_gateway_invalid_stimulus
+  ( xenidc_gateway * gateway, xenidc_gateway_stimulus stimulus )
+{
+    trace();
+
+    printk
+    (
+        KERN_ERR "xenidc: gateway %p in state %d"
+        "received invalid stimulus %d",
+        gateway,
+        gateway->state,
+        stimulus
+    );
+}
+
+static void xenidc_gateway_kick_messages_and_transactions
+  ( xenidc_gateway * gateway )
+{
+    trace();
+
+    if( !gateway->kick_messages_and_transactions_out )
+    {
+        gateway->kick_messages_and_transactions_out = 1;
+
+        (void)xenidc_work_schedule
+          ( &gateway->kick_messages_and_transactions_1_work );
+    }
+}
+
+static void xenidc_gateway_kick_messages_and_transactions_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_gateway * gateway = (xenidc_gateway *)data;
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &gateway->lock, flags );
+
+        gateway->kick_messages_and_transactions_out = 0;
+
+        while
+        (
+            ( !list_empty( &gateway->message_and_transaction_list ) )
+            &&
+            ( !list_empty( &gateway->initiator_resource_list ) )
+        )
+        {
+            xenidc_gateway_message_and_transaction_header * header = list_entry
+            (
+                gateway->message_and_transaction_list.next,
+                xenidc_gateway_message_and_transaction_header,
+                XENIDC_GATEWAY_MESSAGE_AND_TRANSACTION_HEADER_LINK
+            );
+
+            xenidc_gateway_initiator_resource * resource = list_entry
+            (
+                gateway->initiator_resource_list.next,
+                xenidc_gateway_initiator_resource,
+                XENIDC_GATEWAY_INITIATOR_RESOURCE_LINK
+            );
+
+            list_del_init
+            (
+                xenidc_gateway_message_and_transaction_header_to_link
+                  ( header )
+            );
+
+            list_del_init
+              ( xenidc_gateway_initiator_resource_to_link( resource ) );
+
+            gateway->initiator_resources_out++;
+
+            spin_unlock_irqrestore( &gateway->lock, flags );
+
+            xenidc_gateway_initiator_resource_start( resource, header );
+
+            spin_lock_irqsave( &gateway->lock, flags );
+        }
+
+        if( !gateway->kick_messages_and_transactions_out )
+        {
+            xenidc_gateway_handle_stimulus
+              ( gateway, xenidc_gateway_stimulus_km );
+        }
+
+        spin_unlock_irqrestore( &gateway->lock, flags );
+    }
+}
+
+static void xenidc_gateway_kick_messages_and_transactions_2
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_gateway_initiator_resource * resource =
+          xenidc_gateway_initiator_resource_callback_to( callback );
+
+        xenidc_gateway * gateway =
+          xenidc_gateway_initiator_resource_query_gateway( resource );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &gateway->lock, flags );
+
+        list_add_tail
+        (
+            xenidc_gateway_initiator_resource_to_link( resource ),
+            &gateway->initiator_resource_list
+        );
+
+        if( --gateway->initiator_resources_out != 0 )
+        {
+            xenidc_gateway_handle_stimulus
+              ( gateway, xenidc_gateway_stimulus_ic );
+        }
+        else
+        {
+            xenidc_gateway_handle_stimulus
+              ( gateway, xenidc_gateway_stimulus_ii );
+        }
+
+        spin_unlock_irqrestore( &gateway->lock, flags );
+    }
+}
+
+static void xenidc_gateway_fail_out_messages_and_transactions
+  ( xenidc_gateway * gateway )
+{
+    trace();
+
+    while( !list_empty( &gateway->message_and_transaction_list ) )
+    {
+        xenidc_gateway_message_and_transaction_header * header = list_entry
+        (
+            gateway->message_and_transaction_list.next,
+            xenidc_gateway_message_and_transaction_header,
+            XENIDC_GATEWAY_MESSAGE_AND_TRANSACTION_HEADER_LINK
+        );
+
+        list_del_init
+          ( xenidc_gateway_message_and_transaction_header_to_link( header ) );
+
+        xenidc_callback_complete
+        (
+            xenidc_gateway_message_and_transaction_header_to_callback
+              ( header ),
+            XENIDC_ERROR_DISCONNECT
+        );
+    }
+}
+
+static void xenidc_gateway_kick_channel_messages( xenidc_gateway * gateway )
+{
+    trace();
+
+    if( !gateway->kick_channel_messages_out )
+    {
+        gateway->kick_channel_messages_out = 1;
+
+        (void)xenidc_work_schedule( &gateway->kick_channel_messages_1_work );
+    }
+}
+
+static void xenidc_gateway_kick_channel_messages_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_gateway * gateway = (xenidc_gateway *)data;
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &gateway->lock, flags );
+
+        gateway->kick_channel_messages_out = 0;
+
+        while
+        (
+            ( !list_empty( &gateway->channel_message_list ) )
+            &&
+            ( !list_empty( &gateway->target_resource_list ) )
+        )
+        {
+            xenidc_channel_message * message = list_entry
+            (
+                gateway->channel_message_list.next,
+                xenidc_channel_message,
+                XENIDC_CHANNEL_MESSAGE_LINK
+            );
+
+            xenidc_gateway_target_resource * resource = list_entry
+            (
+                gateway->target_resource_list.next,
+                xenidc_gateway_target_resource,
+                XENIDC_GATEWAY_TARGET_RESOURCE_LINK
+            );
+
+            list_del_init( xenidc_channel_message_to_link( message ) );
+
+            {
+                xenidc_gateway_ring_element_header header;
+
+                if
+                (
+                    xenidc_local_buffer_reference_copy_out
+                      ( &message->message_lbr, &header, sizeof( header ) )
+                    !=
+                    sizeof( header )
+                )
+                {
+                    goto PROTOCOL_ERROR;
+                }
+
+                if( header.type == XENIDC_GATEWAY_RING_ELEMENT_TYPE_MESSAGE )
+                {
+                    xenidc_local_buffer_reference message_lbr =
+                      message->message_lbr;
+
+                    xenidc_local_buffer_reference_advance
+                    (
+                        &message_lbr,
+                        sizeof( xenidc_gateway_message_ring_element )
+                    );
+
+                    list_del_init
+                      ( xenidc_gateway_target_resource_to_link( resource ) );
+
+                    gateway->target_resources_out++;
+
+                    spin_unlock_irqrestore( &gateway->lock, flags );
+
+                    xenidc_gateway_target_resource_start_message
+                      ( resource, message_lbr );
+
+                    spin_lock_irqsave( &gateway->lock, flags );
+
+                    xenidc_callback_success
+                      ( xenidc_channel_message_to_callback( message ) );
+                }
+                else if
+                (
+                    header.type
+                    ==
+                    XENIDC_GATEWAY_RING_ELEMENT_TYPE_PARAMETERS
+                )
+                {
+                    xenidc_local_buffer_reference parameters_lbr =
+                      message->message_lbr;
+
+                    xenidc_gateway_parameters_ring_element parameters_element;
+
+                    if
+                    (
+                        xenidc_local_buffer_reference_copy_out
+                        (
+                            &parameters_lbr,
+                            &parameters_element,
+                            sizeof( parameters_element )
+                        )
+                        !=
+                        sizeof( parameters_element )
+                    )
+                    {
+                        goto PROTOCOL_ERROR;
+                    }
+
+                    xenidc_local_buffer_reference_advance
+                      ( &parameters_lbr, sizeof( parameters_element ) );
+
+                    list_del_init
+                      ( xenidc_gateway_target_resource_to_link( resource ) );
+
+                    gateway->target_resources_out++;
+
+                    spin_unlock_irqrestore( &gateway->lock, flags );
+
+                    xenidc_gateway_target_resource_start_transaction
+                    (
+                        resource,
+                        parameters_element.id,
+                        parameters_lbr,
+                        parameters_element.status_byte_count
+                    );
+
+                    spin_lock_irqsave( &gateway->lock, flags );
+
+                    xenidc_callback_success
+                      ( xenidc_channel_message_to_callback( message ) );
+                }
+                else
+                {
+                  PROTOCOL_ERROR:
+
+                    xenidc_callback_complete
+                    (
+                        xenidc_channel_message_to_callback( message ),
+                        XENIDC_ERROR_INVALID_PROTOCOL
+                    );
+                }
+            }
+        }
+
+        if( !gateway->kick_channel_messages_out )
+        {
+            xenidc_gateway_handle_stimulus
+              ( gateway, xenidc_gateway_stimulus_kc );
+        }
+
+        spin_unlock_irqrestore( &gateway->lock, flags );
+    }
+}
+
+static void xenidc_gateway_kick_channel_messages_2
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_gateway_target_resource * resource =
+          xenidc_gateway_target_resource_callback_to( callback );
+
+        xenidc_gateway * gateway =
+          xenidc_gateway_target_resource_query_gateway( resource );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &gateway->lock, flags );
+
+        list_add_tail
+        (
+            xenidc_gateway_target_resource_to_link( resource ),
+            &gateway->target_resource_list
+        );
+
+        if( --gateway->target_resources_out != 0 )
+        {
+            xenidc_gateway_handle_stimulus
+              ( gateway, xenidc_gateway_stimulus_tc );
+        }
+        else
+        {
+            xenidc_gateway_handle_stimulus
+              ( gateway, xenidc_gateway_stimulus_ti );
+        }
+
+        spin_unlock_irqrestore( &gateway->lock, flags );
+    }
+}
+
+static void xenidc_gateway_complete_channel_messages
+  ( xenidc_gateway * gateway )
+{
+    trace();
+
+    while( !list_empty( &gateway->channel_message_list ) )
+    {
+        xenidc_channel_message * message = list_entry
+        (
+            gateway->channel_message_list.next,
+            xenidc_channel_message,
+            XENIDC_CHANNEL_MESSAGE_LINK
+        );
+
+        list_del_init( xenidc_channel_message_to_link( message ) );
+
+        xenidc_callback_success
+          ( xenidc_channel_message_to_callback( message ) );
+    }
+}
+
+static void xenidc_gateway_connect_client( xenidc_gateway * gateway )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &gateway->connect_client_1_work );
+}
+
+static void xenidc_gateway_connect_client_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_gateway * gateway = (xenidc_gateway *)data;
+
+        gateway->connect( gateway );
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &gateway->lock, flags );
+
+            xenidc_gateway_handle_stimulus
+              ( gateway, xenidc_gateway_stimulus_lc );
+
+            spin_unlock_irqrestore( &gateway->lock, flags );
+        }
+    }
+}
+
+static void xenidc_gateway_disconnect_client( xenidc_gateway * gateway )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &gateway->disconnect_client_1_work );
+}
+
+static void xenidc_gateway_disconnect_client_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_gateway * gateway = (xenidc_gateway *)data;
+
+        gateway->disconnect( gateway, &gateway->disconnect_client_2_callback );
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &gateway->lock, flags );
+
+            xenidc_gateway_handle_stimulus
+              ( gateway, xenidc_gateway_stimulus_lg );
+
+            spin_unlock_irqrestore( &gateway->lock, flags );
+        }
+    }
+}
+
+static void xenidc_gateway_disconnect_client_2( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_gateway * gateway = container_of
+          ( callback, xenidc_gateway, disconnect_client_2_callback );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &gateway->lock, flags );
+
+        xenidc_gateway_handle_stimulus
+          ( gateway, xenidc_gateway_stimulus_ld );
+
+        spin_unlock_irqrestore( &gateway->lock, flags );
+    }
+}
+
+static void xenidc_gateway_abort_initiator_resources
+  ( xenidc_gateway * gateway )
+{
+    trace();
+
+    {
+        u32 i;
+
+        for( i = 0; i < gateway->initiator_quota; i++ )
+        {
+            xenidc_gateway_initiator_resource_abort
+              ( &gateway->initiator_resources[ i ] );
+        }
+    }
+}
+
+static void xenidc_gateway_test_initiator_resources
+  ( xenidc_gateway * gateway )
+{
+    trace();
+
+    if( gateway->initiator_resources_out == 0 )
+    {
+        xenidc_gateway_handle_stimulus
+          ( gateway, xenidc_gateway_stimulus_ii );
+    }
+}
+
+static void xenidc_gateway_test_target_resources
+  ( xenidc_gateway * gateway )
+{
+    trace();
+
+    if( gateway->target_resources_out == 0 )
+    {
+        xenidc_gateway_handle_stimulus
+          ( gateway, xenidc_gateway_stimulus_ti );
+    }
+}
+
+static void xenidc_gateway_complete_channel_disconnect
+  ( xenidc_gateway * gateway )
+{
+    trace();
+
+    xenidc_callback_success( gateway->channel_disconnect_callback );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,411 @@
+#include <asm-xen/xenidc_vaddress.h>
+#include "xenidc_gateway_initiator_resource.h"
+#include "xenidc_trace.h"
+
+extern void xenidc_gateway_submit_channel_message
+  ( xenidc_gateway * gateway, xenidc_channel_message * message );
+
+static void xenidc_gateway_initiator_resource_handle_stimulus
+(
+    xenidc_gateway_initiator_resource          * resource,
+    xenidc_gateway_initiator_resource_stimulus   stimulus
+);
+
+static void xenidc_gateway_initiator_resource_channel_message_callback
+  ( xenidc_callback * callback );
+
+void xenidc_gateway_initiator_resource_init
+(
+    xenidc_gateway_initiator_resource * resource,
+    xenidc_gateway                    * gateway,
+    xenidc_callback_function            callback,
+    int                                 id
+)
+{
+    trace();
+
+    xenidc_callback_init( &resource->callback, callback );
+
+    resource->gateway = gateway;
+
+    resource->id = id;
+
+    spin_lock_init( &resource->lock );
+
+    resource->state = xenidc_gateway_initiator_resource_state_i;
+
+    xenidc_callback_init
+    (
+        xenidc_channel_message_to_callback( &resource->channel_message ),
+        xenidc_gateway_initiator_resource_channel_message_callback
+    );
+}
+
+void xenidc_gateway_initiator_resource_start
+(
+    xenidc_gateway_initiator_resource             * resource,
+    xenidc_gateway_message_and_transaction_header * header
+)
+{
+    trace();
+
+    resource->header = header;
+
+    resource->error = XENIDC_ERROR_SUCCESS;
+
+    {
+        xenidc_gateway_initiator_resource_stimulus stimulus;
+
+        if( header->transaction_not_message )
+        {
+            xenidc_gateway_transaction * transaction =
+              xenidc_gateway_transaction_header_to( header );
+
+            resource->element_lbr = xenidc_vaddress_create_lbr
+            (
+                &resource->parameters_element,
+                sizeof( resource->parameters_element )
+            );
+
+            resource->channel_message.message_lbr =
+              xenidc_concatenate_create_lbr
+            (
+                &resource->base,
+                &resource->element_lbr,
+                &transaction->parameters_lbr
+            );
+
+            memset
+            (
+                &resource->parameters_element,
+                0,
+                sizeof( resource->parameters_element )
+            );
+
+            resource->parameters_element.header.type =
+              XENIDC_GATEWAY_RING_ELEMENT_TYPE_PARAMETERS;
+
+            resource->parameters_element.id = resource->id;
+
+            resource->parameters_element.status_byte_count =
+              xenidc_local_buffer_reference_query_byte_count
+                ( &transaction->status_lbr );
+
+            stimulus = xenidc_gateway_initiator_resource_stimulus_st;
+        }
+        else
+        {
+            xenidc_gateway_message * message =
+              xenidc_gateway_message_header_to( header );
+
+            resource->element_lbr = xenidc_vaddress_create_lbr
+            (
+                &resource->message_element,
+                sizeof( resource->message_element )
+            );
+
+            resource->channel_message.message_lbr =
+              xenidc_concatenate_create_lbr
+            (
+                &resource->base,
+                &resource->element_lbr,
+                &message->message_lbr
+            );
+
+            memset
+            (
+                &resource->message_element,
+                0,
+                sizeof( resource->message_element )
+            );
+
+            resource->parameters_element.header.type =
+              XENIDC_GATEWAY_RING_ELEMENT_TYPE_MESSAGE;
+
+            stimulus = xenidc_gateway_initiator_resource_stimulus_sm;
+        }
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &resource->lock, flags );
+
+            xenidc_gateway_initiator_resource_handle_stimulus
+              ( resource, stimulus );
+
+            spin_unlock_irqrestore( &resource->lock, flags );
+        }
+
+        xenidc_gateway_submit_channel_message
+          ( resource->gateway, &resource->channel_message );
+    }
+}
+
+void xenidc_gateway_initiator_resource_abort
+  ( xenidc_gateway_initiator_resource * resource )
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &resource->lock, flags );
+
+        xenidc_gateway_initiator_resource_handle_stimulus
+          ( resource, xenidc_gateway_initiator_resource_stimulus_ab );
+
+        spin_unlock_irqrestore( &resource->lock, flags );
+    }
+}
+
+static void xenidc_gateway_initiator_resource_channel_message_callback
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_gateway_initiator_resource * resource = container_of
+        (
+            callback,
+            xenidc_gateway_initiator_resource,
+            channel_message.callback
+        );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &resource->lock, flags );
+
+        xenidc_gateway_initiator_resource_handle_stimulus
+          ( resource, xenidc_gateway_initiator_resource_stimulus_sc );
+
+        spin_unlock_irqrestore( &resource->lock, flags );
+    }
+}
+
+int xenidc_gateway_initiator_resource_handle_status
+(
+    xenidc_gateway_initiator_resource * resource,
+    xenidc_error                        error,
+    xenidc_local_buffer_reference       status_lbr
+)
+{
+    trace();
+
+    {
+        int return_value = -1;
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &resource->lock, flags );
+
+        if
+        (
+            (
+                resource->state
+                ==
+                xenidc_gateway_initiator_resource_state_i_st
+            )
+            ||
+            (
+                resource->state
+                ==
+                xenidc_gateway_initiator_resource_state_i_st_sc
+            )
+        )
+        {
+            xenidc_gateway_transaction * transaction =
+              xenidc_gateway_transaction_header_to( resource->header );
+
+            if
+            (
+                xenidc_local_buffer_reference_query_byte_count( &status_lbr )
+                ==
+                xenidc_local_buffer_reference_query_byte_count
+                  ( &transaction->status_lbr )
+            )
+            {
+                xenidc_local_buffer_reference_copy
+                  ( &transaction->status_lbr, &status_lbr );
+
+                resource->error = error;
+
+                xenidc_gateway_initiator_resource_handle_stimulus
+                  ( resource, xenidc_gateway_initiator_resource_stimulus_ts );
+
+                return_value = 0;
+            }
+        }
+
+        spin_unlock_irqrestore( &resource->lock, flags );
+
+        return return_value;
+    }
+}
+
+static void xenidc_gateway_initiator_resource_invalid_stimulus
+(
+    xenidc_gateway_initiator_resource          * resource,
+    xenidc_gateway_initiator_resource_stimulus   stimulus
+);
+
+static void xenidc_gateway_initiator_resource_set_aborted
+  ( xenidc_gateway_initiator_resource * resource );
+
+static void xenidc_gateway_initiator_resource_complete
+  ( xenidc_gateway_initiator_resource * resource );
+
+static void xenidc_gateway_initiator_resource_handle_stimulus
+(
+    xenidc_gateway_initiator_resource          * resource,
+    xenidc_gateway_initiator_resource_stimulus   stimulus
+)
+{
+    trace3
+    (
+        "gateway initiator resource %p in state %d received stimulus %d",
+        resource,
+        resource->state,
+        stimulus
+    );
+
+    switch( resource->state )
+    {
+      case xenidc_gateway_initiator_resource_state_i:
+        switch( stimulus )
+        {
+          case xenidc_gateway_initiator_resource_stimulus_sm:
+            resource->state = xenidc_gateway_initiator_resource_state_i_sm;
+            break;
+          case xenidc_gateway_initiator_resource_stimulus_st:
+            resource->state = xenidc_gateway_initiator_resource_state_i_st;
+            break;
+          case xenidc_gateway_initiator_resource_stimulus_ab:
+            break;
+          default:
+            xenidc_gateway_initiator_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_initiator_resource_state_i_sm:
+        switch( stimulus )
+        {
+          case xenidc_gateway_initiator_resource_stimulus_ab:
+            break;
+          case xenidc_gateway_initiator_resource_stimulus_sc:
+            resource->state = xenidc_gateway_initiator_resource_state_i;
+            xenidc_gateway_initiator_resource_complete( resource );
+            break;
+          default:
+            xenidc_gateway_initiator_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_initiator_resource_state_i_st:
+        switch( stimulus )
+        {
+          case xenidc_gateway_initiator_resource_stimulus_ab:
+            resource->state = xenidc_gateway_initiator_resource_state_i_st_ab;
+            break;
+          case xenidc_gateway_initiator_resource_stimulus_sc:
+            resource->state = xenidc_gateway_initiator_resource_state_i_st_sc;
+            break;
+          case xenidc_gateway_initiator_resource_stimulus_ts:
+            resource->state = xenidc_gateway_initiator_resource_state_i_st_ts;
+            break;
+          default:
+            xenidc_gateway_initiator_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_initiator_resource_state_i_st_ab:
+        switch( stimulus )
+        {
+          case xenidc_gateway_initiator_resource_stimulus_sc:
+            resource->state = xenidc_gateway_initiator_resource_state_i;
+            xenidc_gateway_initiator_resource_set_aborted( resource );
+            xenidc_gateway_initiator_resource_complete( resource );
+            break;
+          default:
+            xenidc_gateway_initiator_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_initiator_resource_state_i_st_sc:
+        switch( stimulus )
+        {
+          case xenidc_gateway_initiator_resource_stimulus_ab:
+            resource->state = xenidc_gateway_initiator_resource_state_i;
+            xenidc_gateway_initiator_resource_set_aborted( resource );
+            xenidc_gateway_initiator_resource_complete( resource );
+            break;
+          case xenidc_gateway_initiator_resource_stimulus_ts:
+            resource->state = xenidc_gateway_initiator_resource_state_i;
+            xenidc_gateway_initiator_resource_complete( resource );
+            break;
+          default:
+            xenidc_gateway_initiator_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gateway_initiator_resource_state_i_st_ts:
+        switch( stimulus )
+        {
+          case xenidc_gateway_initiator_resource_stimulus_ab:
+            break;
+          case xenidc_gateway_initiator_resource_stimulus_sc:
+            resource->state = xenidc_gateway_initiator_resource_state_i;
+            xenidc_gateway_initiator_resource_complete( resource );
+            break;
+          default:
+            xenidc_gateway_initiator_resource_invalid_stimulus
+              ( resource, stimulus );
+            break;
+        }
+        break;
+      default:
+        xenidc_gateway_initiator_resource_invalid_stimulus
+          ( resource, stimulus );
+        break;
+    }
+}
+
+static void xenidc_gateway_initiator_resource_invalid_stimulus
+(
+    xenidc_gateway_initiator_resource          * resource,
+    xenidc_gateway_initiator_resource_stimulus   stimulus
+)
+{
+    trace();
+
+    printk
+    (
+        KERN_ERR "xenidc: gateway initiator resource %p in state %d"
+        "received invalid stimulus %d",
+        resource,
+        resource->state,
+        stimulus
+    );
+}
+
+static void xenidc_gateway_initiator_resource_set_aborted
+  ( xenidc_gateway_initiator_resource * resource )
+{
+    trace();
+
+    resource->error = XENIDC_ERROR_ABORTED;
+}
+
+static void xenidc_gateway_initiator_resource_complete
+  ( xenidc_gateway_initiator_resource * resource )
+{
+    trace();
+
+    xenidc_callback_complete( &resource->header->callback, resource->error );
+
+    xenidc_callback_success( &resource->callback );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,95 @@
+#ifndef _XENIDC_GATEWAY_INITIATOR_RESOURCE_H
+#define _XENIDC_GATEWAY_INITIATOR_RESOURCE_H
+
+#include <asm-xen/xenidc_concatenate.h>
+#include <asm-xen/xenidc_channel.h>
+#include <asm-xen/xenidc_gateway.h>
+#include "xenidc_gateway_ring.h"
+
+typedef enum
+{
+    xenidc_gateway_initiator_resource_state_i,
+    xenidc_gateway_initiator_resource_state_i_sm,
+    xenidc_gateway_initiator_resource_state_i_st,
+    xenidc_gateway_initiator_resource_state_i_st_ab,
+    xenidc_gateway_initiator_resource_state_i_st_sc,
+    xenidc_gateway_initiator_resource_state_i_st_ts
+}
+xenidc_gateway_initiator_resource_state;
+
+typedef enum
+{
+    xenidc_gateway_initiator_resource_stimulus_sm, /* Start message      */
+    xenidc_gateway_initiator_resource_stimulus_st, /* Start transaction  */
+    xenidc_gateway_initiator_resource_stimulus_ab, /* Abort              */
+    xenidc_gateway_initiator_resource_stimulus_sc, /* Send complete      */
+    xenidc_gateway_initiator_resource_stimulus_ts, /* Transaction status */
+}
+xenidc_gateway_initiator_resource_stimulus;
+
+struct xenidc_gateway_initiator_resource_struct
+{
+    xenidc_callback                                 callback;
+    xenidc_gateway                                * gateway;
+    int                                             id;
+    spinlock_t                                      lock;
+    xenidc_gateway_initiator_resource_state         state;
+    xenidc_gateway_message_and_transaction_header * header;
+    xenidc_error                                    error;
+    xenidc_channel_message                          channel_message;
+    xenidc_local_buffer_reference                   element_lbr;
+    xenidc_concatenate_base                         base;
+    union
+    {
+        xenidc_gateway_parameters_ring_element parameters_element;
+        xenidc_gateway_message_ring_element    message_element;
+    };
+};
+
+#define XENIDC_GATEWAY_INITIATOR_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK
+
+static inline struct list_head * xenidc_gateway_initiator_resource_to_link
+  ( xenidc_gateway_initiator_resource * resource )
+{
+    return &resource->XENIDC_GATEWAY_INITIATOR_RESOURCE_LINK;
+}
+
+static inline xenidc_gateway_initiator_resource *
+  xenidc_gateway_initiator_resource_callback_to( xenidc_callback * callback )
+{
+    return container_of
+      ( callback, xenidc_gateway_initiator_resource, callback );
+}
+
+static inline xenidc_gateway *
+  xenidc_gateway_initiator_resource_query_gateway
+    ( xenidc_gateway_initiator_resource* resource )
+{
+    return resource->gateway;
+}
+
+void xenidc_gateway_initiator_resource_init
+(
+    xenidc_gateway_initiator_resource * resource,
+    xenidc_gateway                    * gateway,
+    xenidc_callback_function            callback,
+    int                                 id
+);
+
+void xenidc_gateway_initiator_resource_start
+(
+    xenidc_gateway_initiator_resource             * resource,
+    xenidc_gateway_message_and_transaction_header * header
+);
+
+void xenidc_gateway_initiator_resource_abort
+  ( xenidc_gateway_initiator_resource * resource );
+
+int xenidc_gateway_initiator_resource_handle_status
+(
+    xenidc_gateway_initiator_resource * resource,
+    xenidc_error                        error,
+    xenidc_local_buffer_reference       status
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_ring.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_ring.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,69 @@
+/*****************************************************************************/
+/* Xen inter-domain communication gateway ring structure definitions.        */
+/*                                                                           */
+/* 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 _XENIDC_GATEWAY_RING_H
+#define _XENIDC_GATEWAY_RING_H
+
+#include <asm-xen/xenidc.h>
+
+typedef struct xenidc_gateway_ring_element_header_struct
+  xenidc_gateway_ring_element_header;
+
+struct xenidc_gateway_ring_element_header_struct
+{
+    u8 type;
+    u8 reserved[ 7 ];
+};
+
+#define XENIDC_GATEWAY_RING_ELEMENT_TYPE_MESSAGE    0
+#define XENIDC_GATEWAY_RING_ELEMENT_TYPE_PARAMETERS 1
+#define XENIDC_GATEWAY_RING_ELEMENT_TYPE_STATUS     2
+
+typedef struct xenidc_gateway_message_ring_element_struct
+  xenidc_gateway_message_ring_element;
+
+struct xenidc_gateway_message_ring_element_struct
+{
+    xenidc_gateway_ring_element_header header;
+};
+
+typedef struct xenidc_gateway_parameters_ring_element_struct
+  xenidc_gateway_parameters_ring_element;
+
+struct xenidc_gateway_parameters_ring_element_struct
+{
+    xenidc_gateway_ring_element_header header;
+    u32                                id;
+    u16                                status_byte_count;
+    u16                                reserved;
+};
+
+typedef struct xenidc_gateway_status_ring_element_struct
+  xenidc_gateway_status_ring_element;
+
+struct xenidc_gateway_status_ring_element_struct
+{
+    xenidc_gateway_ring_element_header header;
+    u32                                id;
+    xenidc_error                       error;
+};
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,193 @@
+#include <asm-xen/xenidc_vaddress.h>
+#include "xenidc_gateway_target_resource.h"
+#include "xenidc_trace.h"
+
+extern void xenidc_gateway_submit_channel_message
+  ( xenidc_gateway * gateway, xenidc_channel_message * message );
+
+extern void xenidc_gateway_submit_message_to_client
+  ( xenidc_gateway * gateway, xenidc_gateway_message * message );
+
+extern void xenidc_gateway_submit_transaction_to_client
+  ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction );
+
+static void xenidc_gateway_target_resource_channel_message_callback
+  ( xenidc_callback * callback );
+
+void xenidc_gateway_target_resource_init
+(
+    xenidc_gateway_target_resource * resource,
+    xenidc_gateway                 * gateway,
+    xenidc_callback_function         callback,
+    xenidc_local_buffer_reference    buffer
+)
+{
+    trace();
+
+    xenidc_callback_init( &resource->callback, callback );
+
+    resource->gateway = gateway;
+
+    resource->buffer = buffer;
+
+    xenidc_callback_init
+    (
+        xenidc_channel_message_to_callback( &resource->channel_message ),
+        xenidc_gateway_target_resource_channel_message_callback
+    );
+
+    resource->element_lbr = xenidc_vaddress_create_lbr
+      ( &resource->status_element, sizeof( resource->status_element ) );
+
+    memset( &resource->status_element, 0, sizeof( resource->status_element ) );
+
+    resource->status_element.header.type =
+      XENIDC_GATEWAY_RING_ELEMENT_TYPE_STATUS;
+}
+
+static void xenidc_gateway_target_resource_message_callback
+  ( xenidc_callback * callback );
+
+void xenidc_gateway_target_resource_start_message
+(
+    xenidc_gateway_target_resource * resource,
+    xenidc_local_buffer_reference    message_lbr
+)
+{
+    trace();
+
+    xenidc_gateway_message_init
+    (
+        &resource->message,
+        xenidc_gateway_target_resource_message_callback
+    );
+
+    {
+        xenidc_local_buffer_reference lbr = resource->buffer;
+
+        xenidc_local_buffer_reference_truncate
+        (
+            &lbr,
+            xenidc_local_buffer_reference_copy( &lbr, &message_lbr )
+        );
+
+	resource->message.message_lbr = lbr;
+    }
+
+    xenidc_gateway_submit_message_to_client
+      ( resource->gateway, &resource->message );
+}
+
+static void xenidc_gateway_target_resource_message_callback
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_gateway_target_resource * resource = container_of
+        (
+            xenidc_gateway_message_callback_to( callback ),
+            xenidc_gateway_target_resource,
+            message
+        );
+
+        xenidc_callback_success( &resource->callback );
+    }
+}
+
+static void xenidc_gateway_target_resource_transaction_callback
+  ( xenidc_callback * callback );
+
+void xenidc_gateway_target_resource_start_transaction
+(
+    xenidc_gateway_target_resource * resource,
+    u32                              id,
+    xenidc_local_buffer_reference    parameters_lbr,
+    xenidc_buffer_byte_count         status_byte_count
+)
+{
+    trace();
+
+    xenidc_gateway_transaction_init
+    (
+        &resource->transaction,
+        xenidc_gateway_target_resource_transaction_callback
+    );
+
+    {
+        xenidc_local_buffer_reference lbr = resource->buffer;
+
+        xenidc_local_buffer_reference_truncate
+        (
+            &lbr,
+            xenidc_local_buffer_reference_copy( &lbr, &parameters_lbr )
+        );
+
+	resource->transaction.parameters_lbr = lbr;
+    }
+
+    {
+        xenidc_local_buffer_reference lbr = resource->buffer;
+
+        xenidc_local_buffer_reference_subrange
+        (
+            &lbr,
+            xenidc_local_buffer_reference_query_byte_count( &parameters_lbr ),
+            status_byte_count
+        );
+
+        xenidc_local_buffer_reference_zero( &lbr );
+
+	resource->transaction.status_lbr = lbr;
+    }
+
+    resource->status_element.id = id;
+
+    xenidc_gateway_submit_transaction_to_client
+      ( resource->gateway, &resource->transaction );
+}
+
+static void xenidc_gateway_target_resource_transaction_callback
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_gateway_target_resource * resource = container_of
+        (
+            xenidc_gateway_transaction_callback_to( callback ),
+            xenidc_gateway_target_resource,
+            transaction
+        );
+
+        resource->status_element.error =
+          xenidc_callback_query_error( callback );
+
+        resource->channel_message.message_lbr = xenidc_concatenate_create_lbr
+        (
+            &resource->base,
+            &resource->element_lbr,
+            &resource->transaction.status_lbr
+        );
+
+        xenidc_gateway_submit_channel_message
+          ( resource->gateway, &resource->channel_message );
+    }
+}
+
+static void xenidc_gateway_target_resource_channel_message_callback
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_gateway_target_resource * resource = container_of
+        (
+            callback,
+            xenidc_gateway_target_resource,
+            channel_message.callback
+        );
+
+        xenidc_callback_success( &resource->callback );
+    }
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,68 @@
+#ifndef _XENIDC_GATEWAY_TARGET_RESOURCE_H
+#define _XENIDC_GATEWAY_TARGET_RESOURCE_H
+
+#include <asm-xen/xenidc_channel.h>
+#include <asm-xen/xenidc_concatenate.h>
+#include <asm-xen/xenidc_gateway.h>
+#include "xenidc_gateway_ring.h"
+
+struct xenidc_gateway_target_resource_struct
+{
+    xenidc_callback                    callback;
+    xenidc_gateway                   * gateway;
+    xenidc_local_buffer_reference      buffer;
+    union
+    {
+        xenidc_gateway_message         message;
+        xenidc_gateway_transaction     transaction;
+    };
+    xenidc_channel_message             channel_message;
+    xenidc_local_buffer_reference      element_lbr;
+    xenidc_concatenate_base            base;
+    xenidc_gateway_status_ring_element status_element;
+};
+
+#define XENIDC_GATEWAY_TARGET_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK
+
+static inline struct list_head * xenidc_gateway_target_resource_to_link
+  ( xenidc_gateway_target_resource * resource )
+{
+    return &resource->XENIDC_GATEWAY_TARGET_RESOURCE_LINK;
+}
+
+static inline xenidc_gateway_target_resource *
+  xenidc_gateway_target_resource_callback_to( xenidc_callback * callback )
+{
+    return container_of
+      ( callback, xenidc_gateway_target_resource, callback );
+}
+
+static inline xenidc_gateway * xenidc_gateway_target_resource_query_gateway
+  ( xenidc_gateway_target_resource* resource )
+{
+    return resource->gateway;
+}
+
+extern void xenidc_gateway_target_resource_init
+(
+    xenidc_gateway_target_resource * resource,
+    xenidc_gateway                 * gateway,
+    xenidc_callback_function         callback,
+    xenidc_local_buffer_reference    buffer
+);
+
+extern void xenidc_gateway_target_resource_start_message
+(
+    xenidc_gateway_target_resource * resource,
+    xenidc_local_buffer_reference    message_lbr
+);
+
+extern void xenidc_gateway_target_resource_start_transaction
+(
+    xenidc_gateway_target_resource * resource,
+    u32                              id,
+    xenidc_local_buffer_reference    parameters_lbr,
+    xenidc_buffer_byte_count         status_byte_count
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gnttab_channel.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gnttab_channel.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,1693 @@
+/*****************************************************************************/
+/* This is a class which implements a grant-tables based inter-domain        */
+/* message channel. The implementation of the bring-up and tear-down         */
+/* handshaking is left to a derived class.                                   */
+/* This class is used by xenidc_xbgt_channel (which implements bring-up and  */
+/* teardown using xenbus) which is in turn used to implement the             */
+/* xenidc_endpoint class.                                                    */
+/*                                                                           */
+/* 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 <asm-xen/driver_util.h>
+#include <asm-xen/evtchn.h>
+#include <asm-xen/xenidc_concatenate.h>
+#include <asm-xen/xenidc_gnttab_channel.h>
+#include <asm-xen/xenidc_vaddress.h>
+#include <asm-xen/xenidc_wrapping.h>
+#include <linux/interrupt.h>
+#include "xenidc_trace.h"
+#include "xenidc_channel_ring.h"
+
+static inline void xenidc_gnttab_channel_target_resource_init
+(
+    xenidc_gnttab_channel_target_resource * resource,
+    xenidc_gnttab_channel                 * channel,
+    xenidc_callback_function              * callback
+)
+{
+    trace();
+
+    xenidc_channel_message_init( &resource->message, callback );
+
+    resource->channel = channel;
+}
+
+static inline struct list_head * xenidc_gnttab_channel_target_resource_to_link
+  ( xenidc_gnttab_channel_target_resource * resource )
+{
+    trace();
+
+    return xenidc_channel_message_to_link( &resource->message );
+}
+
+static inline xenidc_channel_message *
+  xenidc_gnttab_channel_target_resource_to_message
+    ( xenidc_gnttab_channel_target_resource * resource )
+{
+    trace();
+
+    return &resource->message;
+}
+
+static inline xenidc_gnttab_channel_target_resource *
+  xenidc_gnttab_channel_target_resource_callback_to
+    ( xenidc_callback * callback )
+{
+    trace();
+
+    return container_of
+    (
+        xenidc_channel_message_callback_to( callback ),
+        xenidc_gnttab_channel_target_resource,
+        message
+    );
+}
+
+static inline xenidc_gnttab_channel *
+  xenidc_gnttab_channel_target_resource_query_channel
+    ( xenidc_gnttab_channel_target_resource * resource )
+{
+    trace();
+
+    return resource->channel;
+}
+
+typedef enum
+{
+    xenidc_gnttab_channel_stimulus_c1r, /* phase one connect request      */
+    xenidc_gnttab_channel_stimulus_c2r, /* phase two connect request      */
+    xenidc_gnttab_channel_stimulus_mqr, /* message queued                 */
+    xenidc_gnttab_channel_stimulus_d2r, /* phase two disconnect request   */
+    xenidc_gnttab_channel_stimulus_d1r, /* phase one disconnect request   */
+    xenidc_gnttab_channel_stimulus_sir, /* send interrupt                 */
+    xenidc_gnttab_channel_stimulus_rir, /* recv interrupt                 */
+    xenidc_gnttab_channel_stimulus_c1c, /* phase one connect completed    */
+    xenidc_gnttab_channel_stimulus_c2s, /* phase two connect successful   */
+    xenidc_gnttab_channel_stimulus_c2f, /* phase two connect failed       */
+    xenidc_gnttab_channel_stimulus_ccc, /* connect client completed       */
+    xenidc_gnttab_channel_stimulus_dcc, /* disconnect client completed    */
+    xenidc_gnttab_channel_stimulus_d2c, /* phase two disconnect completed */
+    xenidc_gnttab_channel_stimulus_d1c, /* phase one disconnect completed */
+    xenidc_gnttab_channel_stimulus_ksc, /* kick send ring completed       */
+    xenidc_gnttab_channel_stimulus_krc, /* kick recv ring completed       */
+    xenidc_gnttab_channel_stimulus_trc, /* target resource completed      */
+    xenidc_gnttab_channel_stimulus_tri  /* target resources idle          */
+}
+xenidc_gnttab_channel_stimulus;
+
+static void xenidc_gnttab_channel_handle_stimulus
+  ( xenidc_gnttab_channel * channel, xenidc_gnttab_channel_stimulus stimulus );
+
+static void xenidc_gnttab_channel_submit_message
+  ( xenidc_channel * base_channel, xenidc_channel_message * message );
+
+static int xenidc_gnttab_channel_init_or_exit
+  ( xenidc_gnttab_channel * channel, int exit );
+
+int xenidc_gnttab_channel_init
+(
+    xenidc_gnttab_channel * channel,
+    void ( * protocol_error )( xenidc_gnttab_channel * channel )
+)
+{
+    trace();
+
+    xenidc_channel_init
+      ( &channel->channel, xenidc_gnttab_channel_submit_message );
+
+    channel->protocol_error = protocol_error;
+
+    return xenidc_gnttab_channel_init_or_exit( channel, 0 );
+}
+
+static void xenidc_gnttab_channel_do_phase_one_connect_1( void * data );
+
+static void xenidc_gnttab_channel_do_phase_two_connect_1( void * data );
+
+static void xenidc_gnttab_channel_connect_client_1( void * data );
+
+static void xenidc_gnttab_channel_disconnect_client_1( void * data );
+
+static void xenidc_gnttab_channel_disconnect_client_2
+  ( xenidc_callback * callback );
+
+static void xenidc_gnttab_channel_do_phase_two_disconnect_1( void * data );
+
+static void xenidc_gnttab_channel_do_phase_one_disconnect_1( void * data );
+
+static void xenidc_gnttab_channel_kick_send_ring_1( void * data );
+
+static void xenidc_gnttab_channel_kick_recv_ring_1( void * data );
+
+static void xenidc_gnttab_channel_kick_recv_ring_2
+  ( xenidc_callback * callback );
+
+static int xenidc_gnttab_channel_init_or_exit
+  ( xenidc_gnttab_channel * channel, int exit )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        if( exit )
+        {
+            goto EXIT;
+        }
+
+        channel->send_irq_context = channel;
+        channel->recv_irq_context = channel;
+
+        channel->send_ring = (void *)__get_free_page( GFP_KERNEL );
+
+        if( channel->send_ring == NULL )
+        {
+            trace0( "failed to allocate send ring" );
+
+            return_value = -ENOMEM;
+
+            goto EXIT_NO_SEND_RING;
+        }
+
+        if
+        (
+            ( channel->recv_ring_area = alloc_vm_area( PAGE_SIZE ) )
+            ==
+            NULL
+        )
+        {
+            trace0( "failed to allocate receive ring area" );
+
+            return_value = -ENOMEM;
+
+            goto EXIT_NO_RING_AREA;
+        }
+
+        return_value =
+          gnttab_alloc_grant_references( 1, &channel->grant_ref_pool );
+
+        if( return_value != 0 )
+        {
+            trace0( "failed to allocate grant reference pool" );
+
+            goto EXIT_NO_GRANT_REF;
+        }
+
+        spin_lock_init( &channel->lock );
+
+        channel->state = xenidc_gnttab_channel_state_i;
+
+        INIT_LIST_HEAD( &channel->message_list );
+
+        xenidc_work_init
+        (
+            &channel->do_phase_one_connect_1_work,
+            xenidc_gnttab_channel_do_phase_one_connect_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->do_phase_two_connect_1_work,
+            xenidc_gnttab_channel_do_phase_two_connect_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->connect_client_1_work,
+            xenidc_gnttab_channel_connect_client_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->disconnect_client_1_work,
+            xenidc_gnttab_channel_disconnect_client_1,
+            channel
+        );
+
+        xenidc_callback_init
+        (
+            &channel->disconnect_client_2_callback,
+            xenidc_gnttab_channel_disconnect_client_2
+        );
+
+        xenidc_work_init
+        (
+            &channel->do_phase_two_disconnect_1_work,
+            xenidc_gnttab_channel_do_phase_two_disconnect_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->do_phase_one_disconnect_1_work,
+            xenidc_gnttab_channel_do_phase_one_disconnect_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->kick_send_ring_1_work,
+            xenidc_gnttab_channel_kick_send_ring_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->kick_recv_ring_1_work,
+            xenidc_gnttab_channel_kick_recv_ring_1,
+            channel
+        );
+
+        {
+            int i;
+
+            for( i = 0; i < XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT; i++ )
+            {
+                xenidc_gnttab_channel_target_resource * resource =
+                  &channel->target_resources[ i ];
+
+                xenidc_gnttab_channel_target_resource_init
+                (
+                    resource,
+                    channel,
+                    xenidc_gnttab_channel_kick_recv_ring_2
+                );
+
+                channel->target_resource_free[ i ] = 1;
+            }
+        }
+
+        channel->first_target_resource = 0;
+        channel->next_target_resource = 0;
+
+        channel->send_ring_kick_out = 0;
+        channel->recv_ring_kick_out = 0;
+
+        return 0;
+
+      EXIT:
+
+        gnttab_free_grant_references( channel->grant_ref_pool );
+
+      EXIT_NO_GRANT_REF:
+
+        free_vm_area( channel->recv_ring_area );
+
+      EXIT_NO_RING_AREA:
+
+        free_page( (unsigned long)channel->send_ring );
+
+      EXIT_NO_SEND_RING:
+
+        return return_value;
+    }
+}
+
+void xenidc_gnttab_channel_phase_one_connect
+(
+    xenidc_gnttab_channel                           * channel,
+    xenidc_gnttab_channel_phase_one_connect_request * request
+)
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        channel->current_callback = &request->callback;
+
+        xenidc_gnttab_channel_handle_stimulus
+          ( channel, xenidc_gnttab_channel_stimulus_c1r );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+void xenidc_gnttab_channel_reset_ring( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    channel->recv_ring_offset = 0;
+
+    memset( channel->send_ring, 0, PAGE_SIZE );
+}
+
+void xenidc_gnttab_channel_phase_two_connect
+(
+    xenidc_gnttab_channel                           * channel,
+    xenidc_gnttab_channel_phase_two_connect_request * request
+)
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        channel->current_callback = &request->callback;
+
+        xenidc_gnttab_channel_handle_stimulus
+          ( channel, xenidc_gnttab_channel_stimulus_c2r );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+static void xenidc_gnttab_channel_submit_message
+  ( xenidc_channel * base_channel, xenidc_channel_message * message )
+{
+    trace();
+
+    {
+        xenidc_gnttab_channel * channel =
+          xenidc_gnttab_channel_channel_to( base_channel );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        list_add_tail
+        (
+            xenidc_channel_message_to_link( message ),
+            &channel->message_list
+        );
+
+        xenidc_gnttab_channel_handle_stimulus
+          ( channel, xenidc_gnttab_channel_stimulus_mqr );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+void xenidc_gnttab_channel_phase_two_disconnect
+  ( xenidc_gnttab_channel * channel, xenidc_callback * callback )
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        channel->current_callback = callback;
+
+        xenidc_gnttab_channel_handle_stimulus
+          ( channel, xenidc_gnttab_channel_stimulus_d2r );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+void xenidc_gnttab_channel_phase_one_disconnect
+  ( xenidc_gnttab_channel * channel, xenidc_callback * callback )
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        channel->current_callback = callback;
+
+        xenidc_gnttab_channel_handle_stimulus
+          ( channel, xenidc_gnttab_channel_stimulus_d1r );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+void xenidc_gnttab_channel_exit( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    (void)xenidc_gnttab_channel_init_or_exit( channel, 1 );
+}
+
+static irqreturn_t xenidc_gnttab_channel_send_interrupt
+  ( int irq, void * context, struct pt_regs * ptregs )
+{
+    trace();
+
+    {
+        xenidc_gnttab_channel * channel = *(xenidc_gnttab_channel **)context;
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        xenidc_gnttab_channel_handle_stimulus
+          ( channel, xenidc_gnttab_channel_stimulus_sir );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+
+    return IRQ_HANDLED;
+}
+
+static irqreturn_t xenidc_gnttab_channel_recv_interrupt
+  ( int irq, void * context, struct pt_regs * ptregs )
+{
+    trace();
+
+    {
+        xenidc_gnttab_channel * channel = *(xenidc_gnttab_channel **)context;
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        xenidc_gnttab_channel_handle_stimulus
+          ( channel, xenidc_gnttab_channel_stimulus_rir );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+
+    return IRQ_HANDLED;
+}
+
+static void xenidc_gnttab_channel_invalid_stimulus
+  ( xenidc_gnttab_channel * channel, xenidc_gnttab_channel_stimulus stimulus );
+
+static void xenidc_gnttab_channel_do_phase_one_connect
+  ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_do_phase_two_connect
+  ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_connect_client
+  ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_disconnect_client
+  ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_do_phase_two_disconnect
+  ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_do_phase_one_disconnect
+  ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_kick_send_ring
+  ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_kick_recv_ring
+  ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_complete_current_callback
+  ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_fail_current_callback
+  ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_fail_out_messages
+  ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_test_target_resources
+  ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_handle_stimulus
+  ( xenidc_gnttab_channel * channel, xenidc_gnttab_channel_stimulus stimulus )
+{
+    trace3
+    (
+        "channel %p in state %d received stimulus %d",
+        channel,
+        channel->state,
+        stimulus
+    );
+
+    switch( channel->state )
+    {
+      case xenidc_gnttab_channel_state_i:
+        /* Interface disconnected. */
+        /* Client disconnected.    */
+        /* No messages queued.     */
+        /* Kick send idle.         */
+        /* Kick recv idle.         */
+        /* Target resources idle.  */
+        switch( stimulus )
+        {
+          case xenidc_gnttab_channel_stimulus_c1r:
+            channel->state = xenidc_gnttab_channel_state_i_c1r;
+            xenidc_gnttab_channel_do_phase_one_connect( channel );
+            break;
+          default:
+            xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gnttab_channel_state_i_c1r:
+        /* Interface phase one connecting.  */
+        /* Client disconnected.             */
+        /* No messages queued.              */
+        /* Kick send idle.                  */
+        /* Kick recv idle.                  */
+        /* Target resources idle.           */
+        /* do phase one connect in progress */
+        switch( stimulus )
+        {
+          case xenidc_gnttab_channel_stimulus_sir:
+            break;
+          case xenidc_gnttab_channel_stimulus_c1c:
+            channel->state = xenidc_gnttab_channel_state_i_c1r_c1c;
+            xenidc_gnttab_channel_complete_current_callback( channel );
+            break;
+          default:
+            xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gnttab_channel_state_i_c1r_c1c:
+        /* Interface phase one connected.   */
+        /* Client disconnected.             */
+        /* No messages queued.              */
+        /* Kick send idle.                  */
+        /* Kick recv idle.                  */
+        /* Target resources idle.           */
+        /* Phase one connected.             */
+        switch( stimulus )
+        {
+          case xenidc_gnttab_channel_stimulus_c2r:
+            channel->state = xenidc_gnttab_channel_state_i_c1r_c1c_c2r;
+            xenidc_gnttab_channel_do_phase_two_connect( channel );
+            break;
+          case xenidc_gnttab_channel_stimulus_d1r:
+            channel->state = xenidc_gnttab_channel_state_i_c1r_c1c_d1r;
+            xenidc_gnttab_channel_do_phase_one_disconnect( channel );
+            break;
+          case xenidc_gnttab_channel_stimulus_sir:
+            break;
+          default:
+            xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gnttab_channel_state_i_c1r_c1c_c2r:
+        /* Interface phase two connecting.  */
+        /* Client disconnected.             */
+        /* No messages queued.              */
+        /* Kick send idle.                  */
+        /* Kick recv idle.                  */
+        /* Target resources idle.           */
+        /* do phase two connect in progress */
+        switch( stimulus )
+        {
+          case xenidc_gnttab_channel_stimulus_sir:
+          case xenidc_gnttab_channel_stimulus_rir:
+            break;
+          case xenidc_gnttab_channel_stimulus_c2s:
+            channel->state = xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s;
+            xenidc_gnttab_channel_connect_client( channel );
+            break;
+          case xenidc_gnttab_channel_stimulus_c2f:
+            channel->state = xenidc_gnttab_channel_state_i_c1r_c1c;
+            xenidc_gnttab_channel_fail_current_callback( channel );
+            break;
+          default:
+            xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gnttab_channel_state_i_c1r_c1c_d1r:
+        /* Interface phase one disconnecting.  */
+        /* Client disconnected.                */
+        /* No messages queued.                 */
+        /* Kick send idle.                     */
+        /* Kick recv idle.                     */
+        /* Target resources idle.              */
+        /* do phase one disconnect in progress */
+        switch( stimulus )
+        {
+          case xenidc_gnttab_channel_stimulus_sir:
+            break;
+          case xenidc_gnttab_channel_stimulus_d1c:
+            channel->state = xenidc_gnttab_channel_state_i;
+            xenidc_gnttab_channel_complete_current_callback( channel );
+            break;
+          default:
+            xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s:
+        /* Interface phase two connecting. */
+        /* Client connecting.              */
+        /* Maybe messages queued.          */
+        /* Kick send idle.                 */
+        /* Kick recv idle.                 */
+        /* Target resources idle.          */
+        /* Phase two connected.            */
+        /* connect client in progress      */
+        switch( stimulus )
+        {
+          case xenidc_gnttab_channel_stimulus_mqr:
+          case xenidc_gnttab_channel_stimulus_sir:
+          case xenidc_gnttab_channel_stimulus_rir:
+            break;
+          case xenidc_gnttab_channel_stimulus_ccc:
+            channel->state = xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc;
+            xenidc_gnttab_channel_complete_current_callback( channel );
+            xenidc_gnttab_channel_kick_send_ring( channel );
+            xenidc_gnttab_channel_kick_recv_ring( channel );
+            break;
+          default:
+            xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc:
+        /* Interface phase two connected.  */
+        /* Client connected.               */
+        /* Maybe messages queued.          */
+        /* Maybe kick send in progress.    */
+        /* Maybe kick recv in progress.    */
+        /* Maybe target resources busy.    */
+        /* Phase two connected.            */
+        switch( stimulus )
+        {
+          case xenidc_gnttab_channel_stimulus_mqr:
+            xenidc_gnttab_channel_kick_send_ring( channel );
+            break;
+          case xenidc_gnttab_channel_stimulus_d2r:
+            channel->state =
+              xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r;
+            xenidc_gnttab_channel_kick_send_ring( channel );
+            xenidc_gnttab_channel_kick_recv_ring( channel );
+            break;
+          case xenidc_gnttab_channel_stimulus_sir:
+            xenidc_gnttab_channel_kick_send_ring( channel );
+            break;
+          case xenidc_gnttab_channel_stimulus_rir:
+            xenidc_gnttab_channel_kick_recv_ring( channel );
+            break;
+          case xenidc_gnttab_channel_stimulus_ksc:
+          case xenidc_gnttab_channel_stimulus_krc:
+            break;
+          case xenidc_gnttab_channel_stimulus_trc:
+          case xenidc_gnttab_channel_stimulus_tri:
+            xenidc_gnttab_channel_kick_recv_ring( channel );
+            break;
+          default:
+            xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r:
+        /* Interface phase two disconnecting. */
+        /* Client connected.                  */
+        /* Maybe messages queued.             */
+        /* Kick send in progress.             */
+        /* Kick recv in progress.             */
+        /* Maybe target resources busy.       */
+        /* Phase two connected.               */
+        switch( stimulus )
+        {
+          case xenidc_gnttab_channel_stimulus_mqr:
+          case xenidc_gnttab_channel_stimulus_sir:
+          case xenidc_gnttab_channel_stimulus_rir:
+            break;
+          case xenidc_gnttab_channel_stimulus_ksc:
+          case xenidc_gnttab_channel_stimulus_krc:
+            channel->state =
+              xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc;
+            break;
+          case xenidc_gnttab_channel_stimulus_trc:
+          case xenidc_gnttab_channel_stimulus_tri:
+            break;
+          default:
+            xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc:
+        /* Interface phase two disconnecting.  */
+        /* Client connected.                   */
+        /* Maybe messages queued.              */
+        /* One of kick send /recv in progress. */
+        /* Maybe target resources busy.        */
+        /* Phase two connected.                */
+        switch( stimulus )
+        {
+          case xenidc_gnttab_channel_stimulus_mqr:
+          case xenidc_gnttab_channel_stimulus_sir:
+          case xenidc_gnttab_channel_stimulus_rir:
+            break;
+          case xenidc_gnttab_channel_stimulus_ksc:
+          case xenidc_gnttab_channel_stimulus_krc:
+            channel->state =
+              xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc;
+            xenidc_gnttab_channel_disconnect_client( channel );
+            xenidc_gnttab_channel_fail_out_messages( channel );
+            break;
+          case xenidc_gnttab_channel_stimulus_trc:
+          case xenidc_gnttab_channel_stimulus_tri:
+            break;
+          default:
+            xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc:
+        /* Interface phase two disconnecting.  */
+        /* Client disconnecting.               */
+        /* No messages queued.                 */
+        /* Kick send /recv idle.               */
+        /* Maybe target resources busy.        */
+        /* Phase two connected.                */
+        switch( stimulus )
+        {
+          case xenidc_gnttab_channel_stimulus_mqr:
+            xenidc_gnttab_channel_fail_out_messages( channel );
+            break;
+          case xenidc_gnttab_channel_stimulus_sir:
+          case xenidc_gnttab_channel_stimulus_rir:
+            break;
+          case xenidc_gnttab_channel_stimulus_dcc:
+            channel->state =
+              xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc;
+            xenidc_gnttab_channel_test_target_resources( channel );
+            break;
+          case xenidc_gnttab_channel_stimulus_trc:
+          case xenidc_gnttab_channel_stimulus_tri:
+            break;
+          default:
+            xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc:
+        /* Interface phase two disconnecting.              */
+        /* Client disconnected.                            */
+        /* No messages queued.                             */
+        /* Kick send /recv idle.                           */
+        /* Testing target resources/ target resources busy */
+        /* Phase two connected.                            */
+        switch( stimulus )
+        {
+          case xenidc_gnttab_channel_stimulus_sir:
+          case xenidc_gnttab_channel_stimulus_rir:
+          case xenidc_gnttab_channel_stimulus_trc:
+            break;
+          case xenidc_gnttab_channel_stimulus_tri:
+            channel->state =
+              xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri;
+            xenidc_gnttab_channel_do_phase_two_disconnect( channel );
+            break;
+          default:
+            xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri:
+        /* Interface phase two disconnecting.              */
+        /* Client disconnected.                            */
+        /* No messages queued.                             */
+        /* Kick send /recv idle.                           */
+        /* Target resources idle.                          */
+        /* Phase two disconnecting.                        */
+        switch( stimulus )
+        {
+          case xenidc_gnttab_channel_stimulus_sir:
+          case xenidc_gnttab_channel_stimulus_rir:
+            break;
+          case xenidc_gnttab_channel_stimulus_d2c:
+            channel->state = xenidc_gnttab_channel_state_i_c1r_c1c;
+            xenidc_gnttab_channel_complete_current_callback( channel );
+            break;
+          default:
+            xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      default:
+        xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+        break;
+    }
+}
+
+static void xenidc_gnttab_channel_invalid_stimulus
+  ( xenidc_gnttab_channel * channel, xenidc_gnttab_channel_stimulus stimulus )
+{
+    trace();
+
+    printk
+    (
+        KERN_ERR "xenidc: channel %p in state %d"
+        "received invalid stimulus %d",
+        channel,
+        channel->state,
+        stimulus
+    );
+}
+
+static void xenidc_gnttab_channel_do_phase_one_connect
+  ( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &channel->do_phase_one_connect_1_work );
+}
+
+static void xenidc_gnttab_channel_do_phase_one_connect_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+        xenidc_gnttab_channel_phase_one_connect_request * request =
+          xenidc_gnttab_channel_phase_one_connect_request_callback_to
+            ( channel->current_callback );
+
+        {
+            evtchn_op_t op =
+            {
+                .cmd                 = EVTCHNOP_alloc_unbound,
+                .u.alloc_unbound.dom = request->remote_domain_id
+            };
+
+            BUG_ON( HYPERVISOR_event_channel_op( &op ) != 0 );
+
+            channel->send_event_channel = op.u.alloc_unbound.port;
+        }
+
+        {
+            int error = bind_evtchn_to_irqhandler
+            (
+                channel->send_event_channel,
+                xenidc_gnttab_channel_send_interrupt,
+                SA_SAMPLE_RANDOM,
+                "xenidc",
+                &channel->send_irq_context
+            );
+
+            BUG_ON( error < 0 );
+
+            channel->send_irq = error;
+        }
+
+        channel->send_ring_ref =
+          gnttab_claim_grant_reference( &channel->grant_ref_pool );
+
+        gnttab_grant_foreign_access_ref
+        (
+            channel->send_ring_ref,
+            request->remote_domain_id,
+            virt_to_mfn( channel->send_ring ),
+            1 /* readonly */
+        );
+
+        request->send_ring_ref      = channel->send_ring_ref;
+        request->send_event_channel = channel->send_event_channel;
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            xenidc_gnttab_channel_handle_stimulus
+              ( channel, xenidc_gnttab_channel_stimulus_c1c );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+    }
+}
+
+static void xenidc_gnttab_channel_do_phase_two_connect
+  ( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &channel->do_phase_two_connect_1_work );
+}
+
+static void xenidc_gnttab_channel_do_phase_two_connect_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+        xenidc_gnttab_channel_phase_two_connect_request * request =
+          xenidc_gnttab_channel_phase_two_connect_request_callback_to
+            ( channel->current_callback );
+
+        {
+            struct gnttab_map_grant_ref op =
+            {
+                .host_addr = (unsigned long)channel->recv_ring_area->addr,
+                .flags     = GNTMAP_host_map | GNTMAP_readonly,
+                .dom       = request->remote_domain_id,
+                .ref       = request->recv_ring_ref
+            };
+
+            lock_vm_area( channel->recv_ring_area );
+
+            BUG_ON
+              ( HYPERVISOR_grant_table_op( GNTTABOP_map_grant_ref, &op, 1 ) );
+
+            unlock_vm_area( channel->recv_ring_area );
+
+            if( op.handle < 0 )
+            {
+                trace0( "failed to map remote page" );
+
+                goto EXIT_NO_MAPPING;
+            }
+
+            channel->recv_ring_handle = op.handle;
+        }
+
+        {
+            evtchn_op_t op =
+            {
+                .cmd                            = EVTCHNOP_bind_interdomain,
+                .u.bind_interdomain.remote_dom  = request->remote_domain_id,
+                .u.bind_interdomain.remote_port = request->recv_event_channel
+            };
+
+            if( HYPERVISOR_event_channel_op( &op ) != 0 )
+            {
+                trace0( "failed to bind to remote event channel" );
+
+                goto EXIT_NO_BIND;
+            }
+
+            channel->recv_event_channel = op.u.bind_interdomain.local_port;
+        }
+
+        channel->recv_irq = bind_evtchn_to_irqhandler
+        (
+            channel->recv_event_channel,
+            xenidc_gnttab_channel_recv_interrupt,
+            0,
+            "xenidc",
+            &channel->recv_irq_context
+        );
+
+        if( channel->recv_irq < 0 )
+        {
+            trace0( "failed to bind remote irq" );
+
+            goto EXIT_NO_IRQ;
+        }
+
+        channel->recv_ring_lbr = xenidc_vaddress_create_lbr
+        (
+            (
+                (xenidc_channel_ring_header *)
+                  channel->recv_ring_area->addr
+            ) + 1,
+            PAGE_SIZE - sizeof( xenidc_channel_ring_header )
+        );
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            xenidc_gnttab_channel_handle_stimulus
+              ( channel, xenidc_gnttab_channel_stimulus_c2s );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+
+        return;
+
+      EXIT_NO_IRQ:
+
+        {
+            evtchn_op_t op =
+            {
+                .cmd          = EVTCHNOP_close,
+                .u.close.port = channel->recv_event_channel
+            };
+
+            BUG_ON( HYPERVISOR_event_channel_op( &op ) != 0 );
+        }
+
+      EXIT_NO_BIND:
+
+        {
+            struct gnttab_unmap_grant_ref op;
+
+            op.host_addr    = (unsigned long)channel->recv_ring_area->addr;
+            op.handle       = channel->recv_ring_handle;
+            op.dev_bus_addr = 0;
+
+            lock_vm_area( channel->recv_ring_area );
+
+            BUG_ON
+            (
+                HYPERVISOR_grant_table_op( GNTTABOP_unmap_grant_ref, &op, 1 )
+            );
+
+            unlock_vm_area( channel->recv_ring_area );
+        }
+
+      EXIT_NO_MAPPING:
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            xenidc_gnttab_channel_handle_stimulus
+              ( channel, xenidc_gnttab_channel_stimulus_c2f );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+    }
+}
+
+static void xenidc_gnttab_channel_connect_client
+  ( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &channel->connect_client_1_work );
+}
+
+static void xenidc_gnttab_channel_connect_client_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+        xenidc_channel_connect( &channel->channel );
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            xenidc_gnttab_channel_handle_stimulus
+              ( channel, xenidc_gnttab_channel_stimulus_ccc );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+    }
+}
+
+static void xenidc_gnttab_channel_disconnect_client
+  ( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &channel->disconnect_client_1_work );
+}
+
+static void xenidc_gnttab_channel_disconnect_client_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+        xenidc_channel_disconnect
+          ( &channel->channel, &channel->disconnect_client_2_callback );
+    }
+}
+
+static void xenidc_gnttab_channel_disconnect_client_2
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_gnttab_channel * channel = container_of
+          ( callback, xenidc_gnttab_channel, disconnect_client_2_callback );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        xenidc_gnttab_channel_handle_stimulus
+          ( channel, xenidc_gnttab_channel_stimulus_dcc );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+static void xenidc_gnttab_channel_do_phase_two_disconnect
+  ( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &channel->do_phase_two_disconnect_1_work );
+}
+
+static void xenidc_gnttab_channel_do_phase_two_disconnect_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+        unbind_evtchn_from_irqhandler
+          ( channel->recv_irq, &channel->recv_irq_context );
+
+        {
+            struct gnttab_unmap_grant_ref op;
+
+            op.host_addr    = (unsigned long)channel->recv_ring_area->addr;
+            op.handle       = channel->recv_ring_handle;
+            op.dev_bus_addr = 0;
+
+            lock_vm_area( channel->recv_ring_area );
+
+            BUG_ON
+            (
+                HYPERVISOR_grant_table_op( GNTTABOP_unmap_grant_ref, &op, 1 )
+            );
+
+            unlock_vm_area( channel->recv_ring_area );
+        }
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            xenidc_gnttab_channel_handle_stimulus
+              ( channel, xenidc_gnttab_channel_stimulus_d2c );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+    }
+}
+
+static void xenidc_gnttab_channel_do_phase_one_disconnect
+  ( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &channel->do_phase_one_disconnect_1_work );
+}
+
+static void xenidc_gnttab_channel_do_phase_one_disconnect_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+        gnttab_end_foreign_access_ref( channel->send_ring_ref, 1 );
+
+        /* FIXME: need to extend grant-tables API so we can wait for other */
+        /* side to stop referencing page.                                  */
+
+        gnttab_release_grant_reference
+          ( &channel->grant_ref_pool, channel->send_ring_ref );
+
+        unbind_evtchn_from_irqhandler
+          ( channel->send_irq, &channel->send_irq_context );
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            xenidc_gnttab_channel_handle_stimulus
+              ( channel, xenidc_gnttab_channel_stimulus_d1c );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+    }
+}
+
+static void xenidc_gnttab_channel_kick_send_ring
+  ( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    if( !channel->send_ring_kick_out )
+    {
+        channel->send_ring_kick_out = 1;
+
+        (void)xenidc_work_schedule( &channel->kick_send_ring_1_work );
+    }
+}
+
+static void xenidc_gnttab_channel_kick_send_ring_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+        int notify = 0;
+
+        xenidc_local_buffer_reference ring_lbr;
+        xenidc_local_buffer_reference wrapping_lbr;
+        xenidc_channel_message * message;
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        channel->send_ring_kick_out = 0;
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+
+        /* Create a reference to the send ring buffer. */
+
+        ring_lbr = xenidc_vaddress_create_lbr
+        (
+            ( (xenidc_channel_ring_header *)channel->send_ring ) + 1,
+            PAGE_SIZE - sizeof( xenidc_channel_ring_header )
+        );
+
+        /* Create a reference to the free space in the send ring buffer.     */
+        /* We use a wrapping reference to the above buffer so that we can    */
+        /* copy into the buffer and wrap automatically.                      */
+
+        wrapping_lbr = xenidc_wrapping_create_lbr
+        (
+            &ring_lbr,
+            ( (xenidc_channel_ring_header *)channel->send_ring )->
+              this_ring_producer_offset,
+            (
+                (xenidc_channel_ring_header *)
+                  channel->recv_ring_area->addr
+            )
+            ->other_ring_consumer_offset,
+            xenidc_wrapping_client_type_producer
+        );
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        while
+        (
+            ( !list_empty( &channel->message_list ) )
+            &&
+            (
+                xenidc_local_buffer_reference_query_byte_count( &wrapping_lbr )
+                >
+                (
+                    sizeof( xenidc_channel_ring_element_header )
+                    +
+                    xenidc_local_buffer_reference_query_byte_count
+                    (
+                        &
+                        (
+                            message = list_entry
+                            (
+                                channel->message_list.next,
+                                xenidc_channel_message,
+                                XENIDC_CHANNEL_MESSAGE_LINK
+                            )
+                        )
+                        ->message_lbr
+                    )
+                )
+            )
+        )
+        {
+            list_del_init( xenidc_channel_message_to_link( message ) );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+
+            {
+                xenidc_channel_ring_element_header header;
+                xenidc_local_buffer_reference      header_lbr;
+                xenidc_concatenate_base            base;
+                xenidc_local_buffer_reference      element_lbr;
+
+                memset( &header, 0, sizeof( header ) );
+
+                header.length = xenidc_local_buffer_reference_query_byte_count
+                  ( &message->message_lbr );
+
+                header_lbr =
+                  xenidc_vaddress_create_lbr( &header, sizeof( header ) );
+
+                element_lbr = xenidc_concatenate_create_lbr
+                  ( &base, &header_lbr, &message->message_lbr );
+
+                xenidc_local_buffer_reference_advance
+                (
+                    &wrapping_lbr,
+                    xenidc_local_buffer_reference_copy
+                      ( &wrapping_lbr, &element_lbr )
+                );
+            }
+
+            xenidc_callback_success
+              ( xenidc_channel_message_to_callback( message ) );
+
+            notify = 1;
+
+            spin_lock_irqsave( &channel->lock, flags );
+        }
+
+        channel->send_ring_kick_out = 0;
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+
+        if( notify )
+        {
+            wmb(); /* Ensure contents of ring written before offset updated. */
+
+            ( (xenidc_channel_ring_header *)channel->send_ring )->
+              this_ring_producer_offset =
+                xenidc_local_buffer_reference_query_byte_offset
+                  ( &wrapping_lbr );
+
+            notify_remote_via_irq( channel->send_irq );
+        }
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        if( !channel->send_ring_kick_out )
+        {
+            xenidc_gnttab_channel_handle_stimulus
+              ( channel, xenidc_gnttab_channel_stimulus_ksc );
+        }
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+static void xenidc_gnttab_channel_kick_recv_ring
+  ( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    if( !channel->recv_ring_kick_out )
+    {
+        channel->recv_ring_kick_out = 1;
+
+        (void)xenidc_work_schedule( &channel->kick_recv_ring_1_work );
+    }
+}
+
+static void xenidc_gnttab_channel_kick_recv_ring_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+        int error = 0;
+
+        xenidc_local_buffer_reference wrapping_lbr;
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        channel->recv_ring_kick_out = 0;
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+
+        /* Create a reference to the elements in the recv ring buffer.       */
+        /* We use a wrapping reference to the buffer so that we can copy out */
+        /* of the buffer and wrap automatically.                             */
+
+        wrapping_lbr = xenidc_wrapping_create_lbr
+        (
+            &channel->recv_ring_lbr,
+            channel->recv_ring_offset,
+            (
+                (xenidc_channel_ring_header *)
+                  channel->recv_ring_area->addr
+            )
+            ->this_ring_producer_offset,
+            xenidc_wrapping_client_type_consumer
+        );
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        rmb(); /* Ensure we see latest data for contents of wrapping buffer. */
+
+        while
+        (
+            channel->target_resource_free[ channel->next_target_resource ]
+            &&
+            (
+                xenidc_local_buffer_reference_query_byte_count( &wrapping_lbr )
+                !=
+                0
+            )
+        )
+        {
+            xenidc_local_buffer_reference element = wrapping_lbr;
+
+            xenidc_gnttab_channel_target_resource * resource =
+              &channel->target_resources[ channel->next_target_resource ];
+
+            {
+                xenidc_channel_ring_element_header header;
+
+                if
+                (
+                    (
+                        xenidc_local_buffer_reference_copy_out
+                          ( &wrapping_lbr, &header, sizeof( header ) )
+                        ==
+                        sizeof( header )
+                    )
+                    &&
+                    (
+                        xenidc_local_buffer_reference_subrange
+                          ( &element, sizeof( header ), header.length )
+                        ==
+                        header.length
+                    )
+                )
+                {
+                    xenidc_local_buffer_reference_advance
+                      ( &wrapping_lbr, sizeof( header ) + header.length );
+
+                    channel->target_resource_free
+                      [ channel->next_target_resource ] = 0;
+
+                    channel->target_resource_offset
+                      [ channel->next_target_resource ] =
+                        xenidc_local_buffer_reference_query_byte_offset
+                          ( &wrapping_lbr );
+                    if
+                    (
+                        ++channel->next_target_resource
+                        ==
+                        XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT
+                    )
+                    {
+                        channel->next_target_resource = 0;
+                    }
+                }
+                else
+                {
+                    error = 1;
+
+                    break;
+                }
+            }
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+
+            {
+                xenidc_channel_message * message =
+                  xenidc_gnttab_channel_target_resource_to_message( resource );
+
+                xenidc_channel_message_set_message_lbr( message, element );
+
+                xenidc_channel_handle_message( &channel->channel, message );
+            }
+
+            spin_lock_irqsave( &channel->lock, flags );
+        }
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+
+        channel->recv_ring_offset =
+          xenidc_local_buffer_reference_query_byte_offset( &wrapping_lbr );
+
+        if( error )
+        {
+            channel->protocol_error( channel );
+        }
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            if( !channel->recv_ring_kick_out )
+            {
+                xenidc_gnttab_channel_handle_stimulus
+                  ( channel, xenidc_gnttab_channel_stimulus_krc );
+            }
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+    }
+}
+
+static void xenidc_gnttab_channel_kick_recv_ring_2
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_gnttab_channel_target_resource * resource =
+          xenidc_gnttab_channel_target_resource_callback_to( callback );
+
+        xenidc_gnttab_channel * channel =
+          xenidc_gnttab_channel_target_resource_query_channel( resource );
+
+        int current_target_resource =
+        (
+            (
+                ( (unsigned long)resource )
+                -
+                ( (unsigned long)&channel->target_resources[ 0 ] )
+            )
+            /
+            sizeof( xenidc_gnttab_channel_target_resource )
+        );
+
+        if( xenidc_callback_query_error( callback ) != XENIDC_ERROR_SUCCESS )
+        {
+            channel->protocol_error( channel );
+        }
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            channel->target_resource_free[ current_target_resource ] = 1;
+
+            if( current_target_resource == channel->first_target_resource )
+            {
+                u16 offset;
+
+                do
+                {
+                    offset = channel->target_resource_offset
+                      [ channel->first_target_resource ];
+
+                    if
+                    (
+                        ++channel->first_target_resource
+                        ==
+                        XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT
+                    )
+                    {
+                        channel->first_target_resource = 0;
+                    }
+                }
+                while
+                (
+                    channel->target_resource_free
+                      [ channel->first_target_resource ]
+                    &&
+                    (
+                        channel->first_target_resource
+                        !=
+                        channel->next_target_resource
+                    )
+                );
+
+                mb(); /* Ensure reads complete before we free space. */
+
+                ( (xenidc_channel_ring_header *)channel->send_ring )->
+                  other_ring_consumer_offset = offset;
+
+                notify_remote_via_irq( channel->recv_irq );
+
+                if
+                (
+                    !channel->target_resource_free
+                      [ channel->first_target_resource ]
+                )
+                {
+                    xenidc_gnttab_channel_handle_stimulus
+                      ( channel, xenidc_gnttab_channel_stimulus_trc );
+                }
+                else
+                {
+                    xenidc_gnttab_channel_handle_stimulus
+                      ( channel, xenidc_gnttab_channel_stimulus_tri );
+                }
+            }
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+    }
+}
+
+static void xenidc_gnttab_channel_complete_current_callback
+  ( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    xenidc_callback_success( channel->current_callback );
+}
+
+static void xenidc_gnttab_channel_fail_current_callback
+  ( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    xenidc_callback_complete
+      ( channel->current_callback, XENIDC_ERROR_FAILURE );
+}
+
+static void xenidc_gnttab_channel_fail_out_messages
+  ( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    while( !list_empty( &channel->message_list ) )
+    {
+        xenidc_channel_message * message = list_entry
+        (
+            channel->message_list.next,
+            xenidc_channel_message,
+            XENIDC_CHANNEL_MESSAGE_LINK
+        );
+
+        list_del_init( xenidc_channel_message_to_link( message ) );
+
+        xenidc_callback_success
+          ( xenidc_channel_message_to_callback( message ) );
+    }
+}
+
+static void xenidc_gnttab_channel_test_target_resources
+  ( xenidc_gnttab_channel * channel )
+{
+    trace();
+
+    if( channel->target_resource_free[ channel->first_target_resource ] )
+    {
+        xenidc_gnttab_channel_handle_stimulus
+          ( channel, xenidc_gnttab_channel_stimulus_tri );
+    }
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gnttab_channel_enumeration.dot
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gnttab_channel_enumeration.dot	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,55 @@
+digraph enumeration {
+size="7,7"
+
+i[style=filled,fillcolor=green]
+i->i_c1r[label="c1r\ndo_phase_one_connect"]
+
+i_c1r[style=filled,fillcolor=green]
+i_c1r->i_c1r[label="sir"]
+i_c1r->i_c1r_c1c[label="c1c\ncomplete_current_callback"]
+
+i_c1r_c1c[style=filled,fillcolor=green]
+i_c1r_c1c->i_c1r_c1c_c2r[label="c2r\ndo_phase_two_connect"]
+i_c1r_c1c->i_c1r_c1c_d1r[label="d1r\ndo_phase_one_disconnect"]
+i_c1r_c1c->i_c1r_c1c[label="sir"]
+
+i_c1r_c1c_c2r[style=filled,fillcolor=green]
+i_c1r_c1c_c2r->i_c1r_c1c_c2r[label="sir/rir"]
+i_c1r_c1c_c2r->i_c1r_c1c_c2r_c2s[label="c2s\nconnect_client"]
+i_c1r_c1c_c2r->i_c1r_c1c[label="c2f\nfail_current_callback"]
+
+i_c1r_c1c_d1r[style=filled,fillcolor=orange]
+i_c1r_c1c_d1r->i_c1r_c1c_d1r[label="sir"]
+i_c1r_c1c_d1r->i[label="d1c\ncomplete_current_callback"]
+
+i_c1r_c1c_c2r_c2s[style=filled,fillcolor=green]
+i_c1r_c1c_c2r_c2s->i_c1r_c1c_c2r_c2s[label="mqr/sir/rir"]
+i_c1r_c1c_c2r_c2s->i_c1r_c1c_c2r_c2s_ccc[label="ccc\ncomplete_current_callback\nkick_send_ring\nkick_recv_ring"]
+
+i_c1r_c1c_c2r_c2s_ccc[style=filled,fillcolor=green]
+i_c1r_c1c_c2r_c2s_ccc->i_c1r_c1c_c2r_c2s_ccc[label="mqr/sir\nkick_send_ring"]
+i_c1r_c1c_c2r_c2s_ccc->i_c1r_c1c_c2r_c2s_ccc[label="rir/trc/tri\nkick_recv_ring"]
+i_c1r_c1c_c2r_c2s_ccc->i_c1r_c1c_c2r_c2s_ccc[label="ksc/krc/trb"]
+i_c1r_c1c_c2r_c2s_ccc->i_c1r_c1c_c2r_c2s_ccc_d2r[label="d2r\nkick_send_ring\nkick_recv_ring"]
+
+i_c1r_c1c_c2r_c2s_ccc_d2r[style=filled,fillcolor=orange]
+i_c1r_c1c_c2r_c2s_ccc_d2r->i_c1r_c1c_c2r_c2s_ccc_d2r[label="mqr/sir/rir/trb/trc/tri"]
+i_c1r_c1c_c2r_c2s_ccc_d2r->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc[label="ksc/krc"]
+
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc[style=filled,fillcolor=orange]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc[label="mqr/sir/rir/trb/trc/tri"]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc[label="ksc/krc\ndisconnect_client\nfail_out_messages"]
+
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc[style=filled,fillcolor=orange]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc[label="mqr\nfail_out_messages"]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc[label="sir/rir/trc/tri"]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc[label="dcc\ntest_target_resources"]
+
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc[style=filled,fillcolor=orange]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc[label="sir/rir/trc"]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri[label="tri\nphase_two_disconnect"]
+
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri[style=filled,fillcolor=orange]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri[label="sir/rir"]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri->i_c1r_c1c[label="d2c\ncomplete_current_callback"]
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_local_buffer_reference.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_local_buffer_reference.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,618 @@
+/*****************************************************************************/
+/* Xen inter-domain communication local buffer references.                   */
+/*                                                                           */
+/* 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 <asm-xen/xenidc.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include "xenidc_trace.h"
+
+#ifdef MIN
+#undef MIN
+#endif
+
+#define MIN( X, Y ) ( ( (X) < (Y) ) ? (X) : (Y) )
+
+#define XENIDC_BUFFER_HASH_COUNT 255
+
+static DEFINE_RWLOCK( xenidc_local_buffer_reference_lock );
+
+static struct list_head
+  xenidc_buffer_concrete_hash[ XENIDC_BUFFER_HASH_COUNT ];
+
+static struct list_head
+  xenidc_buffer_copy_hash[ XENIDC_BUFFER_HASH_COUNT ];
+
+static struct list_head
+  xenidc_buffer_virtual_hash[ XENIDC_BUFFER_HASH_COUNT ];
+
+static void xenidc_local_buffer_reference_init( void )
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        write_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+        {
+            static int initialised = 0;
+
+            if( !initialised )
+            {
+                int i;
+
+                for( i = 0; i < XENIDC_BUFFER_HASH_COUNT; i++ )
+                {
+                    INIT_LIST_HEAD( &xenidc_buffer_concrete_hash[ i ] );
+                    INIT_LIST_HEAD( &xenidc_buffer_copy_hash[ i ] );
+                    INIT_LIST_HEAD( &xenidc_buffer_virtual_hash[ i ] );
+                }
+
+                initialised = 1;
+            }
+        }
+
+        write_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+    }
+}
+
+static void xenidc_local_buffer_reference_default_zero
+(
+    xenidc_buffer_concrete_class  * class,
+    xenidc_local_buffer_reference * lbr
+)
+{
+    trace();
+
+    {
+        u8 buffer[ 64 ];
+
+        xenidc_local_buffer_reference temp_lbr = *lbr;
+
+        memset( buffer, 0, 64 );
+
+        do
+        {
+            xenidc_buffer_byte_count this_go = MIN( temp_lbr.byte_count, 64 );
+
+            class->copy_in_or_out( class, &temp_lbr, buffer, this_go, 0 );
+
+            xenidc_local_buffer_reference_advance( &temp_lbr, this_go );
+        }
+        while( temp_lbr.byte_count != 0 );
+    }
+}
+
+xenidc_buffer_type xenidc_local_buffer_reference_register_buffer_concrete_class
+(
+    xenidc_buffer_concrete_class * class,
+    void ( * copy_in_or_out )
+    (
+        xenidc_buffer_concrete_class  * class,
+        xenidc_local_buffer_reference * lbr,
+        void                          * buffer,
+        xenidc_buffer_byte_count        byte_count,
+        int                             out
+    ),
+    void ( * zero )
+    (
+        xenidc_buffer_concrete_class  * class,
+        xenidc_local_buffer_reference * lbr
+    )
+)
+{
+    trace();
+
+    xenidc_local_buffer_reference_init();
+
+    INIT_LIST_HEAD( &class->link );
+
+    class->copy_in_or_out = copy_in_or_out;
+    class->zero           = ( zero != NULL ) ?
+      zero : xenidc_local_buffer_reference_default_zero;
+
+    {
+        unsigned long flags;
+
+        write_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+        {
+            static xenidc_buffer_type type_index = 0;
+
+            class->type = ++type_index;
+        }
+
+        {
+            int i = ( class->type % XENIDC_BUFFER_HASH_COUNT );
+
+            list_add_tail( &class->link, &xenidc_buffer_concrete_hash[ i ] );
+        }
+
+        write_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+    }
+
+    return class->type;
+}
+
+static inline xenidc_buffer_concrete_class *
+  xenidc_local_buffer_reference_find_concrete_class( xenidc_buffer_type type )
+{
+    trace();
+
+    {
+        int i = type % XENIDC_BUFFER_HASH_COUNT;
+
+        xenidc_buffer_concrete_class * class;
+
+        unsigned long flags;
+
+        read_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+        list_for_each_entry( class, &xenidc_buffer_concrete_hash[ i ], link )
+        {
+            if( class->type == type )
+            {
+                read_unlock_irqrestore
+                  ( &xenidc_local_buffer_reference_lock, flags );
+
+                return class;
+            }
+        }
+
+        read_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+
+        BUG();
+
+        return NULL;
+    }
+}
+
+void xenidc_local_buffer_reference_register_buffer_copy_class
+(
+    xenidc_buffer_copy_class * class,
+    xenidc_buffer_type         target_type,
+    xenidc_buffer_type         source_type,
+    void ( * copy )
+    (
+        xenidc_buffer_copy_class      * class,
+        xenidc_local_buffer_reference * target,
+        xenidc_local_buffer_reference * source,
+        xenidc_buffer_byte_count        byte_count
+    )
+)
+{
+    trace();
+
+    INIT_LIST_HEAD( &class->link );
+
+    class->target_type = target_type;
+    class->source_type = source_type;
+    class->copy        = copy;
+
+    {
+        unsigned long flags;
+
+        write_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+        {
+            int i =
+            (
+                ( class->target_type << 16 | class->source_type )
+                %
+                XENIDC_BUFFER_HASH_COUNT
+            );
+
+            list_add_tail( &class->link, &xenidc_buffer_copy_hash[ i ] );
+        }
+
+        write_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+    }
+}
+
+static inline xenidc_buffer_copy_class *
+  xenidc_local_buffer_reference_find_copy_class
+    ( xenidc_buffer_type target_type, xenidc_buffer_type source_type )
+{
+    trace();
+
+    {
+        int i =
+          ( ( target_type << 16 | source_type ) % XENIDC_BUFFER_HASH_COUNT );
+
+        xenidc_buffer_copy_class * class;
+
+        unsigned long flags;
+
+        read_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+        list_for_each_entry( class, &xenidc_buffer_copy_hash[ i ], link )
+        {
+            if
+            (
+                ( class->target_type == target_type )
+                &&
+                ( class->source_type == source_type )
+            )
+            {
+                read_unlock_irqrestore
+                  ( &xenidc_local_buffer_reference_lock, flags );
+
+                return class;
+            }
+        }
+
+        read_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+
+        return NULL;
+    }
+}
+
+xenidc_buffer_type xenidc_local_buffer_reference_register_buffer_virtual_class
+(
+    xenidc_buffer_virtual_class * class,
+    xenidc_local_buffer_reference ( * resolve )
+    (
+        xenidc_buffer_virtual_class   * class,
+        xenidc_local_buffer_reference * lbr
+    ),
+    void ( * advance )
+    (
+        xenidc_buffer_virtual_class   * class,
+        xenidc_local_buffer_reference * lbr,
+        xenidc_buffer_byte_count        byte_count
+    )
+)
+{
+    trace();
+
+    xenidc_local_buffer_reference_init();
+
+    INIT_LIST_HEAD( &class->link );
+
+    class->resolve = resolve;
+    class->advance = advance;
+
+    {
+        unsigned long flags;
+
+        write_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+        {
+            static xenidc_buffer_type type_index = 0;
+
+            class->type =
+            (
+                ++type_index
+                |
+                XENIDC_LOCAL_BUFFER_REFERENCE_TYPE_FLAG_VIRTUAL
+                |
+                (
+                    ( advance != NULL )
+                    ? XENIDC_LOCAL_BUFFER_REFERENCE_TYPE_FLAG_VIRTUAL_ADVANCE
+                    : 0
+                )
+            );
+        }
+
+        {
+            int i = ( class->type % XENIDC_BUFFER_HASH_COUNT );
+
+            list_add_tail( &class->link, &xenidc_buffer_virtual_hash[ i ] );
+        }
+
+        write_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+    }
+
+    return class->type;
+}
+
+static inline xenidc_buffer_virtual_class *
+  xenidc_local_buffer_reference_find_virtual_class( xenidc_buffer_type type )
+{
+    trace();
+
+    {
+        int i = type % XENIDC_BUFFER_HASH_COUNT;
+
+        xenidc_buffer_virtual_class * class;
+
+        unsigned long flags;
+
+        read_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+        list_for_each_entry( class, &xenidc_buffer_virtual_hash[ i ], link )
+        {
+            if( class->type == type )
+            {
+                read_unlock_irqrestore
+                  ( &xenidc_local_buffer_reference_lock, flags );
+
+                return class;
+            }
+        }
+
+        read_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+
+        BUG();
+
+        return NULL;
+    }
+}
+
+static xenidc_local_buffer_reference xenidc_local_buffer_reference_resolve
+  ( xenidc_local_buffer_reference * lbr )
+{
+    trace();
+
+    {
+        xenidc_local_buffer_reference resolved_lbr = *lbr;
+
+        while( 1 )
+        {
+            if
+            (
+                (
+                    resolved_lbr.type
+                    &
+                    XENIDC_LOCAL_BUFFER_REFERENCE_TYPE_FLAG_VIRTUAL
+                )
+                ==
+                0
+            )
+            {
+                return resolved_lbr;
+            }
+            else
+            {
+                xenidc_buffer_virtual_class * class =
+                  xenidc_local_buffer_reference_find_virtual_class
+                    ( resolved_lbr.type );
+
+                resolved_lbr = class->resolve( class, &resolved_lbr );
+            }
+        }
+    }
+}
+
+xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_in_or_out
+(
+    xenidc_local_buffer_reference * lbr,
+    void                          * buffer,
+    xenidc_buffer_byte_count        buffer_byte_count,
+    int                             out
+)
+{
+    trace();
+
+    {
+        /* Total amount to copy is the smaller of the two buffers. */
+
+        xenidc_buffer_byte_count byte_count =
+          MIN( lbr->byte_count, buffer_byte_count );
+
+        xenidc_buffer_byte_count remainder_offset = 0;
+        xenidc_buffer_byte_count remainder_count  = byte_count;
+
+        xenidc_local_buffer_reference top_lbr = *lbr;
+
+        while( remainder_count != 0 )
+        {
+            /* top_lbr might be virtual so we resolve it to get a concrete   */
+            /* lbr for the first contiguous chunk of top_lbr.                */
+
+            xenidc_local_buffer_reference resolved_lbr =
+              xenidc_local_buffer_reference_resolve( &top_lbr );
+
+            /* resolved_lbr is guaranteed to be concrete so we can look up   */
+            /* its copy method.                                              */
+
+            xenidc_buffer_concrete_class * class =
+              xenidc_local_buffer_reference_find_concrete_class
+                ( resolved_lbr.type );
+
+            /* Amount to copy this go may be restricted by the size of the   */
+            /* resolved lbr.                                                 */
+
+            xenidc_buffer_byte_count this_go =
+              MIN( resolved_lbr.byte_count, remainder_count );
+
+            class->copy_in_or_out
+            (
+                class,
+                &resolved_lbr,
+                ( (char *)buffer ) + remainder_offset,
+                this_go,
+                out
+            );
+
+            remainder_offset += this_go;
+            remainder_count  -= this_go;
+
+            xenidc_local_buffer_reference_advance( &top_lbr, this_go );
+        }
+
+        return byte_count;
+    }
+}
+
+void xenidc_local_buffer_reference_zero( xenidc_local_buffer_reference * lbr )
+{
+    trace();
+
+    {
+        xenidc_local_buffer_reference top_lbr = *lbr;
+
+        while( top_lbr.byte_count != 0 )
+        {
+            /* top_lbr might be virtual so we resolve it to get a concrete   */
+            /* lbr for the first contiguous chunk of top_lbr.                */
+
+            xenidc_local_buffer_reference resolved_lbr =
+              xenidc_local_buffer_reference_resolve( &top_lbr );
+
+            xenidc_buffer_concrete_class * class =
+              xenidc_local_buffer_reference_find_concrete_class
+                ( resolved_lbr.type );
+
+            class->zero( class, &resolved_lbr );
+
+            xenidc_local_buffer_reference_advance
+              ( &top_lbr, resolved_lbr.byte_count );
+        }
+    }
+}
+
+xenidc_buffer_byte_count xenidc_local_buffer_reference_copy
+(
+    xenidc_local_buffer_reference * target,
+    xenidc_local_buffer_reference * source
+)
+{
+    trace();
+
+    {
+        /* Total amount to copy is the smaller of the two buffers. */
+
+        xenidc_buffer_byte_count byte_count =
+          MIN( target->byte_count, source->byte_count );
+
+        xenidc_local_buffer_reference top_target_lbr = *target;
+        xenidc_local_buffer_reference top_source_lbr = *source;
+
+        xenidc_buffer_byte_count remainder_count = byte_count;
+
+        while( remainder_count != 0 )
+        {
+            xenidc_local_buffer_reference resolved_target_lbr =
+              xenidc_local_buffer_reference_resolve( &top_target_lbr );
+
+            xenidc_local_buffer_reference resolved_source_lbr =
+              xenidc_local_buffer_reference_resolve( &top_source_lbr );
+
+            xenidc_buffer_byte_count this_go = MIN
+            (
+                resolved_target_lbr.byte_count,
+                resolved_source_lbr.byte_count
+            );
+
+            xenidc_buffer_copy_class * copy_class =
+              xenidc_local_buffer_reference_find_copy_class
+                ( resolved_target_lbr.type, resolved_source_lbr.type );
+
+            if( copy_class != NULL )
+            {
+                copy_class->copy
+                (
+                    copy_class,
+                    &resolved_target_lbr,
+                    &resolved_source_lbr,
+                    this_go
+                );
+            }
+            else
+            {
+                u8 buffer[ 64 ];
+
+                xenidc_buffer_concrete_class * target_concrete_class =
+                  xenidc_local_buffer_reference_find_concrete_class
+                    ( resolved_target_lbr.type );
+
+                xenidc_buffer_concrete_class * source_concrete_class =
+                  xenidc_local_buffer_reference_find_concrete_class
+                    ( resolved_source_lbr.type );
+
+                xenidc_local_buffer_reference temp_target =
+                  resolved_target_lbr;
+                xenidc_local_buffer_reference temp_source =
+                  resolved_source_lbr;
+
+                xenidc_buffer_byte_count nested_remainder_count = this_go;
+
+                do
+                {
+                    xenidc_buffer_byte_count nested_this_go =
+                      MIN( 64, nested_remainder_count );
+
+                    source_concrete_class->copy_in_or_out
+                    (
+                        source_concrete_class,
+                        &temp_source,
+                        buffer,
+                        nested_this_go,
+                        1
+                    );
+
+                    target_concrete_class->copy_in_or_out
+                    (
+                        target_concrete_class,
+                        &temp_target,
+                        buffer,
+                        nested_this_go,
+                        0
+                    );
+
+                    xenidc_local_buffer_reference_advance
+                      ( &temp_target, nested_this_go );
+
+                    xenidc_local_buffer_reference_advance
+                      ( &temp_source, nested_this_go );
+
+                    nested_remainder_count -= nested_this_go;
+                }
+                while( nested_remainder_count != 0 );
+            }
+
+            xenidc_local_buffer_reference_advance( &top_target_lbr, this_go );
+            xenidc_local_buffer_reference_advance( &top_source_lbr, this_go );
+
+            remainder_count -= this_go;            
+        }
+
+        return byte_count;
+    }
+}
+
+xenidc_buffer_byte_count xenidc_local_buffer_reference_virtual_advance
+  ( xenidc_local_buffer_reference * lbr, xenidc_buffer_byte_count byte_count )
+{
+    trace();
+
+    {
+        xenidc_buffer_byte_count actual_byte_count =
+          MIN( lbr->byte_count, byte_count );
+
+        xenidc_buffer_virtual_class * class =
+          xenidc_local_buffer_reference_find_virtual_class( lbr->type );
+
+        class->advance( class, lbr, actual_byte_count );
+
+        return actual_byte_count;
+    }
+}
+
+EXPORT_SYMBOL( xenidc_local_buffer_reference_register_buffer_concrete_class );
+EXPORT_SYMBOL( xenidc_local_buffer_reference_register_buffer_copy_class );
+EXPORT_SYMBOL( xenidc_local_buffer_reference_register_buffer_virtual_class );
+EXPORT_SYMBOL( xenidc_local_buffer_reference_copy_in_or_out );
+EXPORT_SYMBOL( xenidc_local_buffer_reference_zero );
+EXPORT_SYMBOL( xenidc_local_buffer_reference_copy );
+EXPORT_SYMBOL( xenidc_local_buffer_reference_virtual_advance );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_mapper_pool.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_mapper_pool.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,80 @@
+/*****************************************************************************/
+/* Xen remote buffer reference mapper pool.                                  */
+/*                                                                           */
+/* 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 <asm-xen/xenidc.h>
+#include <linux/module.h>
+#include "xenidc_trace.h"
+
+xenidc_rbr_mapper_pool * xenidc_allocate_rbr_mapper_pool
+  ( u32 anti_deadlock_page_count )
+{
+    trace();
+
+    /* FIXME */
+
+    return 1;
+}
+
+void xenidc_free_rbr_mapper_pool( xenidc_rbr_mapper_pool * pool )
+{
+    trace();
+
+    /* FIXME */
+}
+
+void xenidc_rbr_mapper_pool_reserve_and_map_rbrs
+(
+    xenidc_rbr_mapper_pool             * pool,
+    xenidc_reserve_and_map_rbr_request * request
+)
+{
+    trace();
+
+    /* FIXME */
+}
+
+void xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs
+(
+    xenidc_rbr_mapper_pool             * pool,
+    xenidc_reserve_and_map_rbr_request * request
+)
+{
+    trace();
+
+    /* FIXME */
+}
+
+void xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs
+(
+    xenidc_rbr_mapper_pool             * pool,
+    xenidc_reserve_and_map_rbr_request * request
+)
+{
+    trace();
+
+    /* FIXME */
+}
+
+EXPORT_SYMBOL( xenidc_allocate_rbr_mapper_pool );
+EXPORT_SYMBOL( xenidc_free_rbr_mapper_pool );
+EXPORT_SYMBOL( xenidc_rbr_mapper_pool_reserve_and_map_rbrs );
+EXPORT_SYMBOL( xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs );
+EXPORT_SYMBOL( xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_provider_pool.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_provider_pool.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,80 @@
+/*****************************************************************************/
+/* Xen remote buffer reference provider pool.                                */
+/*                                                                           */
+/* 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 <asm-xen/xenidc.h>
+#include <linux/module.h>
+#include "xenidc_trace.h"
+
+xenidc_rbr_provider_pool * xenidc_allocate_rbr_provider_pool
+  ( u32 anti_deadlock_page_count )
+{
+    trace();
+
+    /* FIXME */
+
+    return 1;
+}
+
+void xenidc_free_rbr_provider_pool( xenidc_rbr_provider_pool * pool )
+{
+    trace();
+
+    /* FIXME */
+}
+
+void xenidc_rbr_provider_pool_reserve_and_create_rbrs
+(
+    xenidc_rbr_provider_pool              * pool,
+    xenidc_reserve_and_create_rbr_request * request
+)
+{
+    trace();
+
+    /* FIXME */
+}
+
+void xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs
+(
+    xenidc_rbr_provider_pool              * pool,
+    xenidc_reserve_and_create_rbr_request * request
+)
+{
+    trace();
+
+    /* FIXME */
+}
+
+void xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs
+(
+    xenidc_rbr_provider_pool              * pool,
+    xenidc_reserve_and_create_rbr_request * request
+)
+{
+    trace();
+
+    /* FIXME */
+}
+
+EXPORT_SYMBOL( xenidc_allocate_rbr_provider_pool );
+EXPORT_SYMBOL( xenidc_free_rbr_provider_pool );
+EXPORT_SYMBOL( xenidc_rbr_provider_pool_reserve_and_create_rbrs );
+EXPORT_SYMBOL( xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs );
+EXPORT_SYMBOL( xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_trace.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_trace.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,54 @@
+/*****************************************************************************/
+/* Simple trace macros.                                                      */
+/*                                                                           */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation                      */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify it   */
+/* under the terms of the GNU General Public License as published by the     */
+/* Free Software Foundation; either version 2 of the License, or (at your    */
+/* option) any later version.                                                */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful, but       */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
+/* Public License for more details.                                          */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License along   */
+/* with this program; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                   */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef XENIDC_TRACE_H
+#define XENIDC_TRACE_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_XEN_IDC_TRACE
+
+#define trace0( format ) \
+printk( KERN_INFO "xenidc %s:" format "\n", __PRETTY_FUNCTION__ )
+
+#define trace1( format, a0 ) \
+printk( KERN_INFO "xenidc %s:" format "\n", __PRETTY_FUNCTION__, a0 )
+
+#define trace2( format, a0, a1 ) \
+printk( KERN_INFO "xenidc %s:" format "\n", __PRETTY_FUNCTION__, a0, a1 )
+
+#define trace3( format, a0, a1, a2 ) \
+printk( KERN_INFO "xenidc %s:" format "\n", __PRETTY_FUNCTION__, a0, a1, a2 )
+
+#define trace() trace0( "" )
+
+#else
+
+#define trace0( format )
+#define trace1( format,a0 )
+#define trace2( format,a0, a1 )
+#define trace3( format,a0, a1, a2 )
+#define trace()
+
+#endif
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_vaddress.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_vaddress.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,129 @@
+/*****************************************************************************/
+/* Xen inter-domain communication vaddress local buffer reference type.      */
+/*                                                                           */
+/* 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 <asm-xen/xenidc_vaddress.h>
+#include <linux/module.h>
+#include "xenidc_trace.h"
+
+static xenidc_buffer_type xenidc_vaddress_type;
+
+static void xenidc_vaddress_copy_in_or_out
+(
+    xenidc_buffer_concrete_class  * class,
+    xenidc_local_buffer_reference * lbr,
+    void                          * buffer,
+    xenidc_buffer_byte_count        byte_count,
+    int                             out
+)
+{
+    trace();
+
+    if( out )
+    {
+        memcpy( buffer, ( (char *)lbr->base ) + lbr->byte_offset, byte_count );
+    }
+    else
+    {
+        memcpy( ( (char *)lbr->base ) + lbr->byte_offset, buffer, byte_count );
+    }
+}
+
+static void xenidc_vaddress_zero
+(
+    xenidc_buffer_concrete_class  * class,
+    xenidc_local_buffer_reference * lbr
+)
+{
+    trace();
+
+    memset( ( (char *)lbr->base ) + lbr->byte_offset, 0, lbr->byte_count );
+}
+
+static void xenidc_vaddress_init( void )
+{
+    trace();
+
+    {
+        static DEFINE_RWLOCK( xenidc_vaddress_lock );
+
+        unsigned long flags;
+
+        read_lock_irqsave( &xenidc_vaddress_lock, flags );
+
+        {
+            static int initialised = 0;
+
+            if( !initialised )
+            {
+                read_unlock_irqrestore
+                  ( &xenidc_vaddress_lock, flags );
+
+                write_lock_irqsave
+                  ( &xenidc_vaddress_lock, flags );
+
+                if( !initialised )
+                {
+                    static xenidc_buffer_concrete_class
+                      xenidc_vaddress_concrete_class;
+
+                    xenidc_vaddress_type =
+                      xenidc_local_buffer_reference_register_buffer_concrete_class
+                    (
+                        &xenidc_vaddress_concrete_class,
+                        xenidc_vaddress_copy_in_or_out,
+                        xenidc_vaddress_zero
+                    );
+
+                    initialised = 1;
+                }
+
+                write_unlock_irqrestore
+                  ( &xenidc_vaddress_lock, flags );
+
+                read_lock_irqsave
+                  ( &xenidc_vaddress_lock, flags );
+            }
+        }
+
+        read_unlock_irqrestore( &xenidc_vaddress_lock, flags );
+    }
+}
+
+xenidc_local_buffer_reference xenidc_vaddress_create_lbr
+  ( void * address, xenidc_buffer_byte_count byte_count )
+{
+    trace();
+
+    xenidc_vaddress_init();
+
+    {
+        xenidc_local_buffer_reference lbr;
+
+        lbr.type        = xenidc_vaddress_type;
+        lbr.base        = address;
+        lbr.byte_offset = 0;
+        lbr.byte_count  = byte_count;
+
+        return lbr;
+    }
+}
+
+EXPORT_SYMBOL( xenidc_vaddress_create_lbr );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_work.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_work.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,110 @@
+/*****************************************************************************/
+/* Enhanced work queue service                                               */
+/* 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 "xenidc_work.h"
+
+DEFINE_SPINLOCK( xenidc_work_list_lock );
+
+LIST_HEAD( xenidc_work_list );
+
+static void xenidc_work_function( void * ignored );
+
+DECLARE_WORK( xenidc_work_work, xenidc_work_function, NULL );
+
+DECLARE_WAIT_QUEUE_HEAD( xenidc_work_waitqueue );
+
+LIST_HEAD( xenidc_work_condition );
+
+void xenidc_work_wake_up( void )
+{
+    unsigned long flags;
+
+    spin_lock_irqsave( &xenidc_work_list_lock, flags );
+
+    while( !list_empty( &xenidc_work_condition ) )
+    {
+        list_del_init( xenidc_work_condition.next );
+    }
+
+    spin_unlock_irqrestore( &xenidc_work_list_lock, flags );
+
+    wake_up( &xenidc_work_waitqueue );
+}
+
+int xenidc_work_schedule( xenidc_work * work )
+{
+    int scheduled = 0;
+
+    unsigned long flags;
+
+    spin_lock_irqsave( &xenidc_work_list_lock, flags );
+
+    if( list_empty( &work->link ) )
+    {
+        list_add_tail( &work->link, &xenidc_work_list );
+
+        scheduled = 1;
+    }
+
+    spin_unlock_irqrestore( &xenidc_work_list_lock, flags );
+
+    if( scheduled )
+    {
+        xenidc_work_wake_up();
+
+        schedule_work( &xenidc_work_work );
+    }
+
+    return scheduled;
+}
+
+static void xenidc_work_function( void * ignored )
+{
+    unsigned long flags;
+
+    spin_lock_irqsave( &xenidc_work_list_lock, flags );
+
+    while( !list_empty( &xenidc_work_list ) )
+    {
+        xenidc_work * work = list_entry
+        (
+            xenidc_work_list.next,
+            xenidc_work,
+            link
+        );
+
+        list_del_init( &work->link );
+
+        spin_unlock_irqrestore( &xenidc_work_list_lock, flags );
+
+        xenidc_work_perform_synchronously( work );
+
+        spin_lock_irqsave( &xenidc_work_list_lock, flags );
+    }
+
+    spin_unlock_irqrestore( &xenidc_work_list_lock, flags );
+}
+
+EXPORT_SYMBOL( xenidc_work_schedule );
+EXPORT_SYMBOL( xenidc_work_list );
+EXPORT_SYMBOL( xenidc_work_condition );
+EXPORT_SYMBOL( xenidc_work_waitqueue );
+EXPORT_SYMBOL( xenidc_work_wake_up );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_wrapping.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_wrapping.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,165 @@
+/*****************************************************************************/
+/* Xen inter-domain communication wrapping local buffer reference type.      */
+/*                                                                           */
+/* 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 <asm-xen/xenidc_wrapping.h>
+#include <linux/module.h>
+#include "xenidc_trace.h"
+
+#ifdef MIN
+#undef MIN
+#endif
+
+#define MIN( X, Y ) ( ( (X) < (Y) ) ? (X) : (Y) )
+
+static xenidc_buffer_type xenidc_wrapping_type;
+
+static xenidc_local_buffer_reference xenidc_wrapping_resolve
+(
+    xenidc_buffer_virtual_class   * class,
+    xenidc_local_buffer_reference * lbr
+)
+{
+    trace();
+
+    {
+        xenidc_local_buffer_reference resolved_lbr =
+        *(xenidc_local_buffer_reference *)lbr->base;
+
+        xenidc_local_buffer_reference_subrange
+        (
+            &resolved_lbr,
+            lbr->byte_offset,
+            MIN( lbr->byte_count, resolved_lbr.byte_count - lbr->byte_offset )
+        );
+
+        return resolved_lbr;
+    }
+}
+
+static void xenidc_wrapping_advance
+(
+    xenidc_buffer_virtual_class   * class,
+    xenidc_local_buffer_reference * lbr,
+    xenidc_buffer_byte_count        byte_count
+)
+{
+    trace();
+
+    lbr->byte_offset += byte_count;
+    lbr->byte_offset %=
+      ( (xenidc_local_buffer_reference *)lbr->base )->byte_count;
+    lbr->byte_count -= byte_count;
+}
+
+static void xenidc_wrapping_init( void )
+{
+    trace();
+
+    {
+        static DEFINE_RWLOCK( xenidc_wrapping_lock );
+
+        unsigned long flags;
+
+        read_lock_irqsave( &xenidc_wrapping_lock, flags );
+
+        {
+            static int initialised = 0;
+
+            if( !initialised )
+            {
+                read_unlock_irqrestore
+                  ( &xenidc_wrapping_lock, flags );
+
+                write_lock_irqsave
+                  ( &xenidc_wrapping_lock, flags );
+
+                if( !initialised )
+                {
+                    static xenidc_buffer_virtual_class
+                      xenidc_wrapping_virtual_class;
+
+                    xenidc_wrapping_type =
+                      xenidc_local_buffer_reference_register_buffer_virtual_class
+                    (
+                        &xenidc_wrapping_virtual_class,
+                        xenidc_wrapping_resolve,
+                        xenidc_wrapping_advance
+                    );
+
+                    initialised = 1;
+                }
+
+                write_unlock_irqrestore
+                  ( &xenidc_wrapping_lock, flags );
+
+                read_lock_irqsave
+                  ( &xenidc_wrapping_lock, flags );
+            }
+        }
+
+        read_unlock_irqrestore( &xenidc_wrapping_lock, flags );
+    }
+}
+
+xenidc_local_buffer_reference xenidc_wrapping_create_lbr
+(
+    xenidc_local_buffer_reference * underlying_buffer,
+    xenidc_buffer_byte_count        start_offset,
+    xenidc_buffer_byte_count        end_offset,
+    xenidc_wrapping_client_type     client_type
+)
+{
+    trace();
+
+    xenidc_wrapping_init();
+
+    {
+        xenidc_local_buffer_reference lbr;
+
+        lbr.type        = xenidc_wrapping_type;
+        lbr.base        = underlying_buffer;
+        lbr.byte_offset = start_offset;
+        lbr.byte_count  =
+        (
+            ( start_offset < end_offset )
+            ?
+            ( end_offset - start_offset )
+            :
+            (
+                ( start_offset > end_offset )
+                ?
+                ( end_offset + underlying_buffer->byte_count - start_offset )
+                :
+                (
+                    ( client_type == xenidc_wrapping_client_type_producer )
+                    ?
+                    underlying_buffer->byte_count
+                    :
+                    0
+                )
+            )
+        );
+
+        return lbr;
+    }
+}
+
+EXPORT_SYMBOL( xenidc_wrapping_create_lbr );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel.c
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel.c	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,1737 @@
+/*****************************************************************************/
+/* This is a class which uses a xenidc_gnttab_channel (grant-tables based    */
+/* message channel class) and xenbus to implement an interdomain message     */
+/* channel with grant-tables based message transfer and xenbus based         */
+/* bring-up and tear-down handshaking.                                       */
+/* This class is used in the implementation of the xenidc_endpoint class.    */
+/*                                                                           */
+/* 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                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* The state machine below makes the following assumptions:                  */
+/*                                                                           */
+/* 1) The store might contain some stale cruft from the last time our device */
+/* driver failed.  This is a handy assumption for testing new versions of    */
+/* the driver but isn't strictly necessary.                                  */
+/*                                                                           */
+/* 2) If the other side generates a protocol error on the inter-domain       */
+/* connection then we attempt to disconnect and reconnect.  An alternative   */
+/* behaviour would be to wait for our interface to be called to disconnect   */
+/* and then reconnect before retrying.                                       */
+/*                                                                           */
+/* 3) If we experience an internal failure (fail to register watch for       */
+/* example) then we attempt to disconnect and wait for our interface to be   */
+/* called to disconnect (by module unload for example) and reconnect before  */
+/* retrying.                                                                 */
+/*                                                                           */
+/* 4) Connection and disconnection of the channel is done in two phases: the */
+/* first phase makes the local resources available to the remote side, the   */
+/* second phase uses the resources of the remote side to complete the        */
+/* connection.                                                               */
+/*                                                                           */
+/* The key for the stimuli is as follows:                                    */
+/*                                                                           */
+/* cn: interface called to connect the channel when interface state is       */
+/* disconnected (for example on module load).                                */
+/*                                                                           */
+/* pe: protocol error detected when channel is in a state between phase two  */
+/* connected and the completion of the phase two disconnect callback.        */
+/*                                                                           */
+/* dn: interface called to disconnect the channel when the interface state   */
+/* is connected (for example on module unload).                              */
+/*                                                                           */
+/* ou: a synchronous stimulus from the response test_other_state which       */
+/* indicates that the other state is still unknown because the watch         */
+/* callback hasn't happened yet. Can only happen when making the response    */
+/* test_other_state.                                                         */
+/*                                                                           */
+/* od: other state is disconnected.  This is both a synchronous stimulus     */
+/* from test_other_state and an asynchronous stimulus from the watch         */
+/* function. Disconnected means that we can't read at least the other side's */
+/* ready node from the store.                                                */
+/*                                                                           */
+/* or: other state is ready. This is both a synchronous stimulus from        */
+/* test_other_state and an asynchronous stimulus from the watch function.    */
+/* Ready means that we can see the other side's ready node but not the       */
+/* ring-reference and event-channel information.                             */
+/*                                                                           */
+/* oc: other state is connected.  This is both a synchronous stimulus from   */
+/* test_other_state and an asynchronous stimulus from the watch function.    */
+/* Connected means that we found both the ready node and the connected       */
+/* information in the store.                                                 */
+/*                                                                           */
+/* If the values of the connected information change when the other side is  */
+/* connected then we generate the 'oc' stimulus again which forces a         */
+/* reconnect.                                                                */
+/*                                                                           */
+/* rs: An asynchronous response was successful (we only make one response at */
+/* a time so all asynchronous responses have the same completion stimuli).   */
+/*                                                                           */
+/* rf: An asynchronous response failed.  Only register_watch, clear_store,   */
+/* write_ready, write_connected, phase_two_connect can fail.  Only           */
+/* phase_two_connect has a good reason for failure: the other side might     */
+/* have passed bogus parameters; the other failures are poor API design and  */
+/* ought to be promoted to domain failures.                                  */
+/*                                                                           */
+/* The state machine responses are as follows:                               */
+/*                                                                           */
+/* test_other_state:  what state do we currently think the other side is in  */
+/* as reflected by the last watch event.  Synchronous (called with the lock  */
+/* held) completes with ou/od/or/oc.                                         */
+/*                                                                           */
+/* register_watch: register a watch on the other side.                       */
+/*                                                                           */
+/* unregister_watch: unregister the watch.                                   */
+/*                                                                           */
+/* clear_store: remove the ready node and connected information.             */
+/*                                                                           */
+/* write_ready: write the ready node to the store.                           */
+/*                                                                           */
+/* write_connected: write the connected information to the store.            */
+/*                                                                           */
+/* phase_one_connect: grant the remote side access to the local page etc.    */
+/*                                                                           */
+/* phase_two_connect: map the remote page etc.                               */
+/*                                                                           */
+/* phase_two_disconnect: unmap the remote page.                              */
+/*                                                                           */
+/* phase_one_disconnect: revoke the access of the remote side.               */
+/*                                                                           */
+/* complete_disconnect: When our interface is called to get us to disconnect */
+/* the channel we quiesce and disconnect and then call this to indicate we   */
+/* are done.                                                                 */
+/*                                                                           */
+/*****************************************************************************/
+
+#include <asm-xen/xenidc_xbgt_channel.h>
+#include <linux/err.h>
+#include "xenidc_trace.h"
+
+typedef enum
+{
+    xenidc_xbgt_channel_stimulus_cn, /* Connect:  disconnected               */
+    xenidc_xbgt_channel_stimulus_pe, /* Protocol error: ph2c->ph2dc inclusive*/
+    xenidc_xbgt_channel_stimulus_dn, /* Disconnect: connected                */
+    xenidc_xbgt_channel_stimulus_ou, /* Other unknown: test other state only */
+    xenidc_xbgt_channel_stimulus_od, /* Other disconnected: watch / test     */
+    xenidc_xbgt_channel_stimulus_or, /* Other ready: watch / test            */
+    xenidc_xbgt_channel_stimulus_oc, /* Other connected: watch / test        */
+    xenidc_xbgt_channel_stimulus_rs, /* Response successful: making response */
+    xenidc_xbgt_channel_stimulus_rf  /* Response failed: r. watch, tra, ph2c */
+}
+xenidc_xbgt_channel_stimulus;
+
+static void xenidc_xbgt_channel_handle_stimulus
+  ( xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus );
+
+static int xenidc_xbgt_channel_init_or_exit
+  ( xenidc_xbgt_channel * channel, int exit );
+
+int xenidc_xbgt_channel_init( xenidc_xbgt_channel * channel )
+{
+    return xenidc_xbgt_channel_init_or_exit( channel, 0 );
+}
+
+void xenidc_xbgt_channel_connect
+(
+    xenidc_xbgt_channel * channel,
+    char                * local_path,
+    char                * remote_path,
+    domid_t               remote_domain_id
+)
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        channel->local_path       = local_path;
+        channel->remote_path      = remote_path;
+        channel->remote_domain_id = remote_domain_id;
+
+        xenidc_xbgt_channel_handle_stimulus
+          ( channel, xenidc_xbgt_channel_stimulus_cn );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+static void xenidc_xbgt_channel_watch
+  ( struct xenbus_watch * watch, const char ** vec, unsigned int len )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel =
+          container_of( watch, xenidc_xbgt_channel, watch );
+
+        struct xenbus_transaction * transaction = xenbus_transaction_start();
+
+        if( IS_ERR( transaction ) )
+        {
+            trace0( "error starting transaction" );
+
+            goto DISCONNECTED;
+        }
+
+        {
+            unsigned int event_channel;
+            unsigned int ring_reference;
+            unsigned int ready;
+
+            int error = xenbus_gather
+            (
+                transaction,
+                watch->node,
+                "ready",          "%u", &ready,
+                "event-channel",  "%u", &event_channel,
+                "ring-reference", "%u", &ring_reference,
+                NULL
+            );
+
+            if( error == 0 )
+            {
+                unsigned long flags;
+
+                spin_lock_irqsave( &channel->lock, flags );
+
+                if
+                (
+                    (
+                        channel->other_state
+                        !=
+                        xenidc_xbgt_channel_other_state_connected
+                    )
+                    ||
+                    ( channel->ready_event_channel  != event_channel  )
+                    ||
+                    ( channel->ready_ring_reference != ring_reference )
+                )
+                {
+                    channel->other_state =
+                      xenidc_xbgt_channel_other_state_connected;
+
+                    channel->ready_event_channel  = event_channel;
+                    channel->ready_ring_reference = ring_reference;
+
+                    xenidc_xbgt_channel_handle_stimulus
+                      ( channel, xenidc_xbgt_channel_stimulus_oc );
+                }
+
+                spin_unlock_irqrestore( &channel->lock, flags );
+
+                xenbus_transaction_end( transaction, 1 /* abort */ );
+
+                return;
+            }
+        }
+
+        {
+            unsigned int ready;
+
+            int error = xenbus_gather
+            (
+                transaction,
+                watch->node,
+                "ready", "%u", &ready,
+                NULL
+            );
+
+            if( error == 0 )
+            {
+                unsigned long flags;
+
+                spin_lock_irqsave( &channel->lock, flags );
+
+                if
+                (
+                    (
+                        channel->other_state
+                        !=
+                        xenidc_xbgt_channel_other_state_ready
+                    )
+                )
+                {
+                    channel->other_state =
+                      xenidc_xbgt_channel_other_state_ready;
+
+                    xenidc_xbgt_channel_handle_stimulus
+                      ( channel, xenidc_xbgt_channel_stimulus_or );
+                }
+
+                spin_unlock_irqrestore( &channel->lock, flags );
+
+                xenbus_transaction_end( transaction, 1 /* abort */ );
+
+                return;
+            }
+        }
+
+        xenbus_transaction_end( transaction, 1 /* abort */ );
+
+      DISCONNECTED:
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            if
+            (
+                channel->other_state
+                !=
+                xenidc_xbgt_channel_other_state_disconnected
+            )
+            {
+                channel->other_state =
+                  xenidc_xbgt_channel_other_state_disconnected;
+
+                xenidc_xbgt_channel_handle_stimulus
+                  ( channel, xenidc_xbgt_channel_stimulus_od );
+            }
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+    }
+}
+
+static void xenidc_xbgt_channel_protocol_error
+  ( xenidc_gnttab_channel * gnttab_channel )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel =
+          xenidc_xbgt_channel_gnttab_channel_to( gnttab_channel );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        xenidc_xbgt_channel_handle_stimulus
+          ( channel, xenidc_xbgt_channel_stimulus_pe );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+void xenidc_xbgt_channel_disconnect
+  ( xenidc_xbgt_channel * channel, xenidc_callback * callback )
+{
+    trace();
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        channel->disconnect_callback = callback;
+
+        xenidc_xbgt_channel_handle_stimulus
+          ( channel, xenidc_xbgt_channel_stimulus_dn );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+void xenidc_xbgt_channel_exit( xenidc_xbgt_channel * channel )
+{
+    trace();
+
+    (void)xenidc_xbgt_channel_init_or_exit( channel, 1 );
+}
+
+static void xenidc_xbgt_channel_register_watch_1( void * data );
+static void xenidc_xbgt_channel_unregister_watch_1( void * data );
+static void xenidc_xbgt_channel_clear_store_1( void * data );
+static void xenidc_xbgt_channel_write_ready_1( void * data );
+static void xenidc_xbgt_channel_write_connected_1( void * data );
+static void xenidc_xbgt_channel_phase_one_connect_1( void * data );
+static void xenidc_xbgt_channel_phase_one_connect_2
+  ( xenidc_callback * callback );
+static void xenidc_xbgt_channel_phase_two_connect_1( void * data );
+static void xenidc_xbgt_channel_phase_two_connect_2
+  ( xenidc_callback * callback );
+static void xenidc_xbgt_channel_phase_two_disconnect_1( void * data );
+static void xenidc_xbgt_channel_phase_two_disconnect_2
+  ( xenidc_callback * callback );
+static void xenidc_xbgt_channel_phase_one_disconnect_1( void * data );
+static void xenidc_xbgt_channel_phase_one_disconnect_2
+  ( xenidc_callback * callback );
+
+static int xenidc_xbgt_channel_init_or_exit
+  ( xenidc_xbgt_channel * channel, int exit )
+{
+    trace();
+
+    {
+        int return_value = 0;
+
+        if( exit )
+        {
+            goto EXIT;
+        }
+
+        if
+        (
+            (
+                return_value = xenidc_gnttab_channel_init
+                  ( &channel->channel, xenidc_xbgt_channel_protocol_error )
+            )
+            !=
+            0
+        )
+        {
+            goto EXIT_NO_GNTTAB_CHANNEL;
+        }
+
+        xenidc_work_init
+        (
+            &channel->register_watch_1_work,
+            xenidc_xbgt_channel_register_watch_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->unregister_watch_1_work,
+            xenidc_xbgt_channel_unregister_watch_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->clear_store_1_work,
+            xenidc_xbgt_channel_clear_store_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->write_ready_1_work,
+            xenidc_xbgt_channel_write_ready_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->write_connected_1_work,
+            xenidc_xbgt_channel_write_connected_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->phase_one_connect_1_work,
+            xenidc_xbgt_channel_phase_one_connect_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->phase_two_connect_1_work,
+            xenidc_xbgt_channel_phase_two_connect_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->phase_two_disconnect_1_work,
+            xenidc_xbgt_channel_phase_two_disconnect_1,
+            channel
+        );
+
+        xenidc_work_init
+        (
+            &channel->phase_one_disconnect_1_work,
+            xenidc_xbgt_channel_phase_one_disconnect_1,
+            channel
+        );
+
+        xenidc_callback_init
+        (
+            &channel->phase_one_connect_request.callback,
+            xenidc_xbgt_channel_phase_one_connect_2
+        );
+
+        xenidc_callback_init
+        (
+            &channel->phase_two_connect_request.callback,
+            xenidc_xbgt_channel_phase_two_connect_2
+        );
+
+        xenidc_callback_init
+        (
+            &channel->phase_two_disconnect_callback,
+            xenidc_xbgt_channel_phase_two_disconnect_2
+        );
+
+        xenidc_callback_init
+        (
+            &channel->phase_one_disconnect_callback,
+            xenidc_xbgt_channel_phase_one_disconnect_2
+        );
+
+        return 0;
+
+      EXIT:
+
+        xenidc_gnttab_channel_exit( &channel->channel );
+
+      EXIT_NO_GNTTAB_CHANNEL:
+
+        return return_value;
+    }
+}
+
+static void xenidc_xbgt_channel_invalid_stimulus
+  ( xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus );
+
+static void xenidc_xbgt_channel_test_other_state
+  ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_register_watch
+  ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_unregister_watch
+  ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_clear_store
+  ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_write_ready
+  ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_write_connected
+  ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_phase_one_connect
+  ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_phase_two_connect
+  ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_phase_two_disconnect
+  ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_phase_one_disconnect
+  ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_complete_disconnect
+  ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_handle_stimulus
+  ( xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus )
+{
+    trace3
+    (
+        "xbgt channel %p in state %d received stimulus %d",
+        channel,
+        channel->state,
+        stimulus
+    );
+
+    switch( channel->state )
+    {
+      case xenidc_xbgt_channel_state_i:
+        /* Interface disconnected.      */
+        /* Gnttab channel disconnected. */
+        /* Local store unknown.         */
+        /* Watch not registered.        */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_cn:
+            channel->state = xenidc_xbgt_channel_state_i_cn;
+            xenidc_xbgt_channel_phase_one_connect( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn:
+        /* Interface connected.                 */
+        /* Gnttab channel phase one connecting. */
+        /* Local store unknown.                 */
+        /* Watch not registered.                */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state = xenidc_xbgt_channel_state_i_cn_dn;
+            break;
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs;
+            xenidc_xbgt_channel_register_watch( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_dn:
+        /* Interface disconnecting.            */
+        /* Gnttab channel phase one connecting */
+        /* Local store unknown.                */
+        /* Watch not registered.               */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs;
+            xenidc_xbgt_channel_clear_store( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs:
+        /* Interface connected.                                        */
+        /* Gnttab channel phase one connected and registering watch or */
+        /* Watch registered and gnttab channel phase two disconnecting */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_pe:
+            break;
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn;
+            break;
+          case xenidc_xbgt_channel_stimulus_od:
+          case xenidc_xbgt_channel_stimulus_or:
+          case xenidc_xbgt_channel_stimulus_oc:
+            break;
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs;
+            xenidc_xbgt_channel_clear_store( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_rf:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf;
+            xenidc_xbgt_channel_clear_store( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_dn_rs:
+        /* Interface disconnecting.           */
+        /* Gnttab channel phase one connected */
+        /* Clearing store.                    */
+        /* Watch not registered.              */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_rs:
+          case xenidc_xbgt_channel_stimulus_rf:
+            channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs_rs;
+            xenidc_xbgt_channel_phase_one_disconnect( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_dn:
+        /* Interface disconnecting.            */
+        /* Gnttab channel phase one connected. */
+        /* Local store unknown.                */
+        /* Registering watch.                  */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_od:
+          case xenidc_xbgt_channel_stimulus_or:
+          case xenidc_xbgt_channel_stimulus_oc:
+            break;
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+            xenidc_xbgt_channel_unregister_watch( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_rf:
+            channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs;
+            xenidc_xbgt_channel_clear_store( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rs:
+        /* Interface connected.                */
+        /* Gnttab channel phase one connected. */
+        /* Clearing Store.                     */
+        /* Watch Registered.                   */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+            break;
+          case xenidc_xbgt_channel_stimulus_od:
+          case xenidc_xbgt_channel_stimulus_or:
+          case xenidc_xbgt_channel_stimulus_oc:
+            break;
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rs;
+            xenidc_xbgt_channel_test_other_state( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_rf:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rf;
+            xenidc_xbgt_channel_unregister_watch( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rf:
+        /* Interface connected.                */
+        /* Gnttab channel phase one connected. */
+        /* Clearing store.                     */
+        /* Something failed.                   */
+        /* Watch not registered.               */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs;
+            break;
+          case xenidc_xbgt_channel_stimulus_rs:
+          case xenidc_xbgt_channel_stimulus_rf:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf_rs;
+            xenidc_xbgt_channel_phase_one_disconnect( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_dn_rs_rs:
+        /* Interface disconnecting.               */
+        /* Gnttab channel phase one disconnecting */
+        /* Attempted to clear store.              */
+        /* Watch not registered.                  */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state = xenidc_xbgt_channel_state_i;
+            xenidc_xbgt_channel_complete_disconnect( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_dn_rs:
+        /* Interface disconnecting.            */
+        /* Gnttab channel phase one connected. */
+        /* Local store unknown.                */
+        /* Unregistering watch.                */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_od:
+          case xenidc_xbgt_channel_stimulus_or:
+          case xenidc_xbgt_channel_stimulus_oc:
+            break;
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs;
+            xenidc_xbgt_channel_clear_store( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rs_dn:
+        /* Interface disconnecting.                                          */
+        /* Gnttab channel phase one connected unless ph2 disconnecting below.*/
+        /* Clearing Store / writing ready / writing connected / ...          */
+        /* ... ph2 disconnecting                                             */
+        /* Watch Registered.                                                 */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_pe:
+          case xenidc_xbgt_channel_stimulus_od:
+          case xenidc_xbgt_channel_stimulus_or:
+          case xenidc_xbgt_channel_stimulus_oc:
+            break;
+          case xenidc_xbgt_channel_stimulus_rs:
+          case xenidc_xbgt_channel_stimulus_rf:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+            xenidc_xbgt_channel_unregister_watch( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rs_rs:
+        /* Interface connected.                                */
+        /* Gnttab channel phase one connected.                 */
+        /* Store clear.                                        */
+        /* Watch Registered.                                   */
+        /* Testing other state / other state unknown/connected */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+            xenidc_xbgt_channel_unregister_watch( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_ou:
+            break;
+          case xenidc_xbgt_channel_stimulus_od:
+          case xenidc_xbgt_channel_stimulus_or:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od;
+            xenidc_xbgt_channel_write_ready( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_oc:
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rs_rf:
+        /* Interface connected.                */
+        /* Gnttab channel phase one connected. */
+        /* Unregistering watch.                */
+        /* Something failed.                   */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+            break;
+          case xenidc_xbgt_channel_stimulus_od:
+          case xenidc_xbgt_channel_stimulus_or:
+          case xenidc_xbgt_channel_stimulus_oc:
+            break;
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf;
+            xenidc_xbgt_channel_clear_store( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rf_rs:
+        /* Interface connected.                    */
+        /* Gnttab channel phase one disconnecting. */
+        /* Attempted to clear store.               */
+        /* Something failed.                       */
+        /* Watch not registered.                   */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs_rs;
+            break;
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs;
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od:
+        /* Interface connected.                                */
+        /* Gnttab channel phase one connected.                 */
+        /* Writing Ready.                                      */
+        /* Watch Registered.                                   */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+            break;
+          case xenidc_xbgt_channel_stimulus_od:
+          case xenidc_xbgt_channel_stimulus_or:
+          case xenidc_xbgt_channel_stimulus_oc:
+            break;
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs;
+            xenidc_xbgt_channel_test_other_state( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_rf:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rf;
+            xenidc_xbgt_channel_unregister_watch( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs:
+        /* Interface connected.                   */
+        /* Gnttab channel phase one disconnected. */
+        /* Attempted to clear store.              */
+        /* Something failed.                      */
+        /* Watch not registered.                  */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state = xenidc_xbgt_channel_state_i;
+            xenidc_xbgt_channel_complete_disconnect( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs:
+        /* Interface connected.                            */
+        /* Gnttab channel phase one connected.             */
+        /* Ready.                                          */
+        /* Watch registered.                               */
+        /* Testing other state or other state disconnected */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+            xenidc_xbgt_channel_unregister_watch( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_od:
+            break;
+          case xenidc_xbgt_channel_stimulus_or:
+          case xenidc_xbgt_channel_stimulus_oc:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or;
+            xenidc_xbgt_channel_write_connected( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or:
+        /* Interface connected.                            */
+        /* Gnttab channel phase one connected.             */
+        /* Writing Connected.                              */
+        /* Watch registered.                               */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+            break;
+          case xenidc_xbgt_channel_stimulus_od:
+          case xenidc_xbgt_channel_stimulus_or:
+          case xenidc_xbgt_channel_stimulus_oc:
+            break;
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state =
+              xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs;
+            xenidc_xbgt_channel_test_other_state( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_rf:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rf;
+            xenidc_xbgt_channel_unregister_watch( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs:
+        /* Interface connected.                            */
+        /* Gnttab channel phase one connected.             */
+        /* Connected.                                      */
+        /* Watch registered.                               */
+        /* Testing other state / other state ready.        */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state =
+              xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+            xenidc_xbgt_channel_unregister_watch( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_od:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs;
+            xenidc_xbgt_channel_clear_store( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_or:
+            break;
+          case xenidc_xbgt_channel_stimulus_oc:
+            channel->state =
+              xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc;
+            xenidc_xbgt_channel_phase_two_connect( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc:
+        /* Interface connected.                 */
+        /* Gnttab channel phase two connecting. */
+        /* Connected.                           */
+        /* Watch registered.                    */
+        /* Other side connected.                */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_pe:
+            /* Phase two disconnect then go around. */
+            channel->state =
+              xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe;
+            break;
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state =
+              xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn;
+            break;
+          case xenidc_xbgt_channel_stimulus_od:
+          case xenidc_xbgt_channel_stimulus_or:
+          case xenidc_xbgt_channel_stimulus_oc:
+            channel->state =
+              xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe;
+	    break;
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state =
+              xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs;
+            break;
+          case xenidc_xbgt_channel_stimulus_rf:
+            /* Maybe we picked up stale state from the store. Go around. */
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs;
+            xenidc_xbgt_channel_clear_store( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe:
+        /* Interface connected.                 */
+        /* Gnttab channel phase two connecting. */
+        /* Connected.                           */
+        /* Watch registered.                    */
+        /* Protocol error or glitch.            */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_pe:
+            break;
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state =
+              xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn;
+            break;
+          case xenidc_xbgt_channel_stimulus_od:
+          case xenidc_xbgt_channel_stimulus_or:
+          case xenidc_xbgt_channel_stimulus_oc:
+	    break;
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state =
+              xenidc_xbgt_channel_state_i_cn_rs;
+              xenidc_xbgt_channel_phase_two_disconnect( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_rf:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs;
+            xenidc_xbgt_channel_clear_store( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn:
+        /* Interface disconnecting.             */
+        /* Gnttab channel phase two connecting. */
+        /* Connected.                           */
+        /* Watch registered.                    */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_pe:
+          case xenidc_xbgt_channel_stimulus_od:
+          case xenidc_xbgt_channel_stimulus_or:
+          case xenidc_xbgt_channel_stimulus_oc:
+	    break;
+          case xenidc_xbgt_channel_stimulus_rs:
+            channel->state =
+              xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+              xenidc_xbgt_channel_phase_two_disconnect( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_rf:
+            channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+            xenidc_xbgt_channel_unregister_watch( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs:
+        /* Interface connected.                */
+        /* Gnttab channel phase two connected. */
+        /* Connected.                          */
+        /* Watch registered.                   */
+        /* Other side connected.               */
+        /* Totally happy.                      */
+        switch( stimulus )
+        {
+          case xenidc_xbgt_channel_stimulus_pe:
+            channel->state =
+              xenidc_xbgt_channel_state_i_cn_rs;
+              xenidc_xbgt_channel_phase_two_disconnect( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_dn:
+            channel->state =
+              xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+              xenidc_xbgt_channel_phase_two_disconnect( channel );
+            break;
+          case xenidc_xbgt_channel_stimulus_od:
+          case xenidc_xbgt_channel_stimulus_or:
+          case xenidc_xbgt_channel_stimulus_oc:
+            channel->state =
+              xenidc_xbgt_channel_state_i_cn_rs;
+              xenidc_xbgt_channel_phase_two_disconnect( channel );
+            break;
+          default:
+            xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+            break;
+        }
+        break;
+      default:
+        xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+        break;
+    }
+}
+
+static void xenidc_xbgt_channel_invalid_stimulus
+  ( xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus )
+{
+    trace();
+
+    printk
+    (
+        KERN_ERR "xenidc: xbgt channel %p in state %d"
+        "received invalid stimulus %d",
+        channel,
+        channel->state,
+        stimulus
+    );
+}
+
+static void xenidc_xbgt_channel_test_other_state
+  ( xenidc_xbgt_channel * channel )
+{
+    trace();
+
+    switch( channel->other_state )
+    {
+      case xenidc_xbgt_channel_other_state_unknown:
+        xenidc_xbgt_channel_handle_stimulus
+          ( channel, xenidc_xbgt_channel_stimulus_ou );
+        break;
+      case xenidc_xbgt_channel_other_state_disconnected:
+        xenidc_xbgt_channel_handle_stimulus
+          ( channel, xenidc_xbgt_channel_stimulus_od );
+        break;
+      case xenidc_xbgt_channel_other_state_ready:
+        xenidc_xbgt_channel_handle_stimulus
+          ( channel, xenidc_xbgt_channel_stimulus_or );
+        break;
+      case xenidc_xbgt_channel_other_state_connected:
+        xenidc_xbgt_channel_handle_stimulus
+          ( channel, xenidc_xbgt_channel_stimulus_oc );
+        break;
+    }
+}
+
+static void xenidc_xbgt_channel_register_watch
+  ( xenidc_xbgt_channel * channel )
+{
+    trace();
+
+    channel->other_state = xenidc_xbgt_channel_other_state_unknown;
+
+    (void)xenidc_work_schedule( &channel->register_watch_1_work );
+}
+
+static void xenidc_xbgt_channel_register_watch_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+        channel->watch.node     = channel->remote_path;
+        channel->watch.callback = xenidc_xbgt_channel_watch;
+
+        {
+            int return_value = register_xenbus_watch( &channel->watch );
+
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            if( return_value == 0 )
+            {
+                xenidc_xbgt_channel_handle_stimulus
+                  ( channel, xenidc_xbgt_channel_stimulus_rs );
+            }
+            else
+            {
+                xenidc_xbgt_channel_handle_stimulus
+                  ( channel, xenidc_xbgt_channel_stimulus_rf );
+            }
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+    }
+}
+
+static void xenidc_xbgt_channel_unregister_watch
+  ( xenidc_xbgt_channel * channel )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &channel->unregister_watch_1_work );
+}
+
+static void xenidc_xbgt_channel_unregister_watch_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+        unregister_xenbus_watch( &channel->watch );
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            xenidc_xbgt_channel_handle_stimulus
+              ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+    }
+}
+
+static void xenidc_xbgt_channel_clear_store( xenidc_xbgt_channel * channel )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &channel->clear_store_1_work );
+}
+
+static void xenidc_xbgt_channel_clear_store_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+        struct xenbus_transaction * transaction;
+
+      AGAIN:
+
+        transaction = xenbus_transaction_start();
+
+        if( IS_ERR( transaction ) )
+        {
+            trace0( "error starting transaction" );
+
+            goto ERROR;
+        }
+
+        {
+            int error =
+              xenbus_rm( transaction, channel->local_path, "ready" );
+
+            if( error )
+            {
+                trace0( "error removing ready field from store" );
+
+                goto ABORT_TRANSACTION;
+            }
+        }
+
+        {
+            int error =
+              xenbus_rm( transaction, channel->local_path, "event-channel" );
+
+            if( error )
+            {
+                trace0( "error removing event-channel field from store" );
+
+                goto ABORT_TRANSACTION;
+            }
+        }
+
+        {
+            int error =
+              xenbus_rm( transaction, channel->local_path, "ring-reference" );
+
+            if( error )
+            {
+                trace0( "error removing ring-reference field from store" );
+
+                goto ABORT_TRANSACTION;
+            }
+        }
+
+        {
+            int error = xenbus_transaction_end( transaction, 0 /* commit */ );
+
+            if( error != 0 )
+            {
+                if( error == -EAGAIN )
+                {
+                    goto AGAIN;
+                }
+                else
+                {
+                    trace0( "error committing transaction" );
+
+                    goto ERROR;
+                }
+            }
+        }
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            xenidc_xbgt_channel_handle_stimulus
+              ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+
+        return;
+
+      ABORT_TRANSACTION:
+
+        xenbus_transaction_end( transaction, 1 /* abort */ );
+
+      ERROR:
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            xenidc_xbgt_channel_handle_stimulus
+              ( channel, xenidc_xbgt_channel_stimulus_rf );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+    }
+}
+
+static void xenidc_xbgt_channel_write_ready( xenidc_xbgt_channel * channel )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &channel->write_ready_1_work );
+}
+
+static void xenidc_xbgt_channel_write_ready_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+        struct xenbus_transaction * transaction;
+
+      AGAIN:
+
+        transaction = xenbus_transaction_start();
+
+        if( IS_ERR( transaction ) )
+        {
+            trace0( "error starting transaction" );
+
+            goto ERROR;
+        }
+
+        {
+            int error = xenbus_write
+            (
+                transaction,
+                channel->local_path,
+                "ready",
+                "1"
+            );
+
+            if( error )
+            {
+                trace0( "error writing ready to store" );
+
+                goto ABORT_TRANSACTION;
+            }
+        }
+
+        {
+            int error = xenbus_transaction_end( transaction, 0 /* commit */ );
+
+            if( error != 0 )
+            {
+                if( error == -EAGAIN )
+                {
+                    goto AGAIN;
+                }
+                else
+                {
+                    trace0( "error committing transaction" );
+
+                    goto ERROR;
+                }
+            }
+        }
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            xenidc_xbgt_channel_handle_stimulus
+              ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+
+        return;
+
+      ABORT_TRANSACTION:
+
+        xenbus_transaction_end( transaction, 1 /* abort */ );
+
+      ERROR:
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            xenidc_xbgt_channel_handle_stimulus
+              ( channel, xenidc_xbgt_channel_stimulus_rf );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+    }
+}
+
+static void xenidc_xbgt_channel_write_connected
+  ( xenidc_xbgt_channel * channel )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &channel->write_connected_1_work );
+}
+
+static void xenidc_xbgt_channel_write_connected_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+        struct xenbus_transaction * transaction;
+
+        xenidc_gnttab_channel_reset_ring( &channel->channel );
+
+      AGAIN:
+
+        transaction = xenbus_transaction_start();
+
+        if( IS_ERR( transaction ) )
+        {
+            trace0( "error starting transaction" );
+
+            goto ERROR;
+        }
+
+        {
+            int error = xenbus_printf
+            (
+                transaction,
+                channel->local_path,
+                "ring-reference",
+                "%u",
+                channel->phase_one_connect_request.send_ring_ref
+            );
+
+            if( error )
+            {
+                trace0( "error writing ring-reference to store" );
+
+                goto ABORT_TRANSACTION;
+            }
+        }
+
+        {
+            int error = xenbus_printf
+            (
+                transaction,
+                channel->local_path,
+                "event-channel",
+                "%u",
+                channel->phase_one_connect_request.send_event_channel
+            );
+
+            if( error )
+            {
+                trace0( "error writing event-channel to store" );
+
+                goto ABORT_TRANSACTION;
+            }
+        }
+
+        {
+            int error = xenbus_transaction_end( transaction, 0 /* commit */ );
+
+            if( error != 0 )
+            {
+                if( error == -EAGAIN )
+                {
+                    goto AGAIN;
+                }
+                else
+                {
+                    trace0( "error committing transaction" );
+
+                    goto ERROR;
+                }
+            }
+        }
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            xenidc_xbgt_channel_handle_stimulus
+              ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+
+        return;
+
+      ABORT_TRANSACTION:
+
+        xenbus_transaction_end( transaction, 1 /* abort */ );
+
+      ERROR:
+
+        {
+            unsigned long flags;
+
+            spin_lock_irqsave( &channel->lock, flags );
+
+            xenidc_xbgt_channel_handle_stimulus
+              ( channel, xenidc_xbgt_channel_stimulus_rf );
+
+            spin_unlock_irqrestore( &channel->lock, flags );
+        }
+    }
+}
+
+static void xenidc_xbgt_channel_phase_one_connect
+  ( xenidc_xbgt_channel * channel )
+{
+    trace();
+
+    channel->phase_one_connect_request.remote_domain_id =
+      channel->remote_domain_id;
+
+    (void)xenidc_work_schedule( &channel->phase_one_connect_1_work );
+}
+
+static void xenidc_xbgt_channel_phase_one_connect_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+        xenidc_gnttab_channel_phase_one_connect
+          ( &channel->channel, &channel->phase_one_connect_request );
+    }
+}
+
+static void xenidc_xbgt_channel_phase_one_connect_2
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel = container_of
+        (
+            xenidc_gnttab_channel_phase_one_connect_request_callback_to
+              ( callback ),
+            xenidc_xbgt_channel,
+            phase_one_connect_request
+        );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        xenidc_xbgt_channel_handle_stimulus
+          ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+static void xenidc_xbgt_channel_phase_two_connect
+  ( xenidc_xbgt_channel * channel )
+{
+    trace();
+
+    channel->phase_two_connect_request.remote_domain_id   =
+      channel->remote_domain_id;
+    channel->phase_two_connect_request.recv_ring_ref      =
+      channel->ready_ring_reference;
+    channel->phase_two_connect_request.recv_event_channel =
+      channel->ready_event_channel;
+
+    (void)xenidc_work_schedule( &channel->phase_two_connect_1_work );
+}
+
+static void xenidc_xbgt_channel_phase_two_connect_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+        xenidc_gnttab_channel_phase_two_connect
+          ( &channel->channel, &channel->phase_two_connect_request );
+    }
+}
+
+static void xenidc_xbgt_channel_phase_two_connect_2
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel = container_of
+        (
+            xenidc_gnttab_channel_phase_two_connect_request_callback_to
+              ( callback ),
+            xenidc_xbgt_channel,
+            phase_two_connect_request
+        );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        if( xenidc_callback_query_error( callback ) == XENIDC_ERROR_SUCCESS )
+        {
+            xenidc_xbgt_channel_handle_stimulus
+              ( channel, xenidc_xbgt_channel_stimulus_rs );
+        }
+        else
+        {
+            xenidc_xbgt_channel_handle_stimulus
+              ( channel, xenidc_xbgt_channel_stimulus_rf );
+        }
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+static void xenidc_xbgt_channel_phase_two_disconnect
+  ( xenidc_xbgt_channel * channel )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &channel->phase_two_disconnect_1_work );
+}
+
+static void xenidc_xbgt_channel_phase_two_disconnect_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+        xenidc_gnttab_channel_phase_two_disconnect
+          ( &channel->channel, &channel->phase_two_disconnect_callback );
+    }
+}
+
+static void xenidc_xbgt_channel_phase_two_disconnect_2
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel = container_of
+          ( callback, xenidc_xbgt_channel, phase_two_disconnect_callback );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        xenidc_xbgt_channel_handle_stimulus
+          ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+static void xenidc_xbgt_channel_phase_one_disconnect
+  ( xenidc_xbgt_channel * channel )
+{
+    trace();
+
+    (void)xenidc_work_schedule( &channel->phase_one_disconnect_1_work );
+}
+
+static void xenidc_xbgt_channel_phase_one_disconnect_1( void * data )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+        xenidc_gnttab_channel_phase_one_disconnect
+          ( &channel->channel, &channel->phase_one_disconnect_callback );
+    }
+}
+
+static void xenidc_xbgt_channel_phase_one_disconnect_2
+  ( xenidc_callback * callback )
+{
+    trace();
+
+    {
+        xenidc_xbgt_channel * channel = container_of
+          ( callback, xenidc_xbgt_channel, phase_one_disconnect_callback );
+
+        unsigned long flags;
+
+        spin_lock_irqsave( &channel->lock, flags );
+
+        xenidc_xbgt_channel_handle_stimulus
+          ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+        spin_unlock_irqrestore( &channel->lock, flags );
+    }
+}
+
+static void xenidc_xbgt_channel_complete_disconnect
+  ( xenidc_xbgt_channel * channel )
+{
+    trace();
+
+    xenidc_callback_success( channel->disconnect_callback );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.dot
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.dot	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,109 @@
+digraph enumeration {
+size="7,7"
+
+i[style=filled,fillcolor=green]
+i->i_cn[label="cn\nphase_one_connect"];
+
+i_cn[style=filled,fillcolor=green]
+i_cn->i_cn_dn[label="dn"];
+i_cn->i_cn_rs[label="rs\nregister_watch"];
+
+i_cn_dn[style=filled,fillcolor=orange]
+i_cn_dn->i_cn_dn_rs[label="rs\nclear_store"];
+
+i_cn_rs[style=filled,fillcolor=green]
+i_cn_rs->i_cn_rs_dn[label="dn"];
+i_cn_rs->i_cn_rs[label="pe/od/or/oc"];
+i_cn_rs->i_cn_rs_rs[label="rs\nclear_store"];
+i_cn_rs->i_cn_rs_rf[label="rf\nclear_store"];
+
+i_cn_dn_rs[style=filled,fillcolor=orange]
+i_cn_dn_rs->i_cn_dn_rs_rs[label="rs/rf\nphase_one_disconnect"];
+
+i_cn_rs_dn[style=filled,fillcolor=orange]
+i_cn_rs_dn->i_cn_rs_dn[label="od/or/oc"];
+i_cn_rs_dn->i_cn_rs_dn_rs[label="rs\nunregister_watch"];
+i_cn_rs_dn->i_cn_dn_rs[label="rf\nclear_store"];
+
+i_cn_rs_rs[style=filled,fillcolor=green]
+i_cn_rs_rs->i_cn_rs_rs_dn[label="dn"];
+i_cn_rs_rs->i_cn_rs_rs[label="od/or/oc"];
+i_cn_rs_rs->i_cn_rs_rs_rs[label="rs\ntest_other_state"];
+i_cn_rs_rs->i_cn_rs_rs_rf[label="rf\nunregister_watch"];
+
+i_cn_rs_rf[style=filled,fillcolor=red]
+i_cn_rs_rf->i_cn_dn_rs[label="dn"];
+i_cn_rs_rf->i_cn_rs_rf_rs[label="rs/rf\nphase_one_disconnect"];
+
+i_cn_dn_rs_rs[style=filled,fillcolor=orange]
+i_cn_dn_rs_rs->i[label="rs\ncomplete_disconnect"];
+
+i_cn_rs_dn_rs[style=filled,fillcolor=orange]
+i_cn_rs_dn_rs->i_cn_rs_dn_rs[label="od/or/oc"];
+i_cn_rs_dn_rs->i_cn_dn_rs[label="rs\nclear_store"];
+
+i_cn_rs_rs_dn[style=filled,fillcolor=orange]
+i_cn_rs_rs_dn->i_cn_rs_rs_dn[label="od/or/oc"];
+i_cn_rs_rs_dn->i_cn_rs_dn_rs[label="rs/rf\nunregister_watch"];
+
+i_cn_rs_rs_rs[style=filled,fillcolor=green]
+i_cn_rs_rs_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"];
+i_cn_rs_rs_rs->i_cn_rs_rs_rs[label="ou/oc"];
+i_cn_rs_rs_rs->i_cn_rs_rs_rs_od[label="od/or\nwrite_ready"];
+
+i_cn_rs_rs_rf[style=filled,fillcolor=red]
+i_cn_rs_rs_rf->i_cn_rs_dn_rs[label="dn"];
+i_cn_rs_rs_rf->i_cn_rs_rs_rf[label="od/or/oc"];
+i_cn_rs_rs_rf->i_cn_rs_rf[label="rs\nclear_store"];
+
+i_cn_rs_rf_rs[style=filled,fillcolor=red]
+i_cn_rs_rf_rs->i_cn_dn_rs_rs[label="dn"];
+i_cn_rs_rf_rs->i_cn_rs_rf_rs_rs[label="rs"];
+
+i_cn_rs_rs_rs_od[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od->i_cn_rs_rs_dn[label="dn"];
+i_cn_rs_rs_rs_od->i_cn_rs_rs_rs_od[label="od/or/oc"];
+i_cn_rs_rs_rs_od->i_cn_rs_rs_rs_od_rs[label="rs\ntest_other_state"];
+i_cn_rs_rs_rs_od->i_cn_rs_rs_rf[label="rf\nunregister_watch"];
+
+i_cn_rs_rf_rs_rs[style=filled,fillcolor=red]
+i_cn_rs_rf_rs_rs->i[label="dn\ncomplete_disconnect"];
+
+i_cn_rs_rs_rs_od_rs[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"];
+i_cn_rs_rs_rs_od_rs->i_cn_rs_rs_rs_od_rs[label="od"];
+i_cn_rs_rs_rs_od_rs->i_cn_rs_rs_rs_od_rs_or[label="or/oc\nwrite_connected"];
+
+i_cn_rs_rs_rs_od_rs_or[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_dn[label="dn"];
+i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rs_od_rs_or[label="od/or/oc"];
+i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rs_od_rs_or_rs[label="rs\ntest_other_state"];
+i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rf[label="rf\nunregister_watch"];
+
+i_cn_rs_rs_rs_od_rs_or_rs[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"];
+i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs[label="od\nclear_store"];
+i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs_rs_od_rs_or_rs[label="or"];
+i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs_rs_od_rs_or_rs_oc[label="oc\nphase_two_connect"];
+
+i_cn_rs_rs_rs_od_rs_or_rs_oc[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[label="pe/od/or/oc"];
+i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="dn"];
+i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_rs[label="rs"];
+i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs[label="rf\nclear_store"];
+
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[style=filled,fillcolor=blue]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[label="pe/od/or/oc"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="dn"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs[label="rs\nphase_two_disconnect"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs[label="rf\nclear_store"]
+
+i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[style=filled,fillcolor=orange]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="pe/od/or/oc"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_rs_dn[label="rs\nphase_two_disconnect"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_dn_rs[label="rf\nunregister_watch"]
+
+i_cn_rs_rs_rs_od_rs_or_rs_oc_rs[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_rs->i_cn_rs[label="pe/od/or/oc\nphase_two_disconnect"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_rs->i_cn_rs_rs_dn[label="dn\nphase_two_disconnect"]
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,122 @@
+/*****************************************************************************/
+/* Xen inter-domain communication API.                                       */
+/*                                                                           */
+/* 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 __ASM_XEN_XENIDC_H__
+#define __ASM_XEN_XENIDC_H__
+
+/*****************************************************************************/
+/* RESOURCE MANAGEMENT                                                       */
+/*                                                                           */
+/* The bulk data transfer mechanism uses the following strategy for resource */
+/* management:                                                               */
+/*                                                                           */
+/* 1) Create an anti-deadlock resource pool.  This pool of resources is used */
+/* to guarantee that your subsystem can make progress independent of all     */
+/* other subsystems using the xenidc API.  The subsystem operations using    */
+/* the resource pool must be independent and the resource pool must contain  */
+/* enough resources to service the worst case individual operation.  This    */
+/* guarantees progress because, in the worst case, an operation can wait for */
+/* all other operations to complete (they are independent so they will       */
+/* complete eventually) at which time the resource pool will be replenished  */
+/* such that it contains enough resources to start the waiting operation.    */
+/*                                                                           */
+/* 2) Make a single atomic request to reserve and create/reserve and open    */
+/* all of the local/remote buffers required for the operation to proceed to  */
+/* completion.  This request is guaranteed to complete because it is atomic  */
+/* and so will eventually get a chance to acquire all the resources it needs */
+/* which by design will be less than the anti-deadlock reservation.          */
+/*                                                                           */
+/* 3) Dependent operations using independent anti-deadlock pools acquire     */
+/* resources from pools in a defined order.                                  */
+/*                                                                           */
+/* An alternative implementation could support an additional API for the     */
+/* following strategy which might be more convenient for some clients:       */
+/*                                                                           */
+/* 1) Create an anti-deadlock resource pool as above.                        */
+/*                                                                           */
+/* 2) Make a single atomic reservation to reserve all the resources required */
+/* for an operation to proceed to completion.  This request is guaranteed to */
+/* complete because it is atomic and so will eventually get a chance to      */
+/* acquire all the resources it needs which by design will be less than the  */
+/* anti-deadlock reservation.                                                */
+/*                                                                           */
+/* 3) Make an arbitrary number of create/open requests using the resources   */
+/* reserved in step 2.  These are guaranteed to complete because the         */
+/* resources reserved in step 2 are sufficient by design.                    */
+/*                                                                           */
+/* 4) Dependent operations using independent anti-deadlock pools acquire     */
+/* resources from pools in a defined order.                                  */
+/*                                                                           */
+/* The following strategies are examples which in general DO NOT WORK:       */
+/*                                                                           */
+/* First incorrect strategy:                                                 */
+/*                                                                           */
+/* 1) Have no anti-deadlock resource pool.                                   */
+/*                                                                           */
+/* This doesn't work because all the xenidc resources might be allocated to  */
+/* an operation that is dependent on your subsystem for completion.  A       */
+/* deadlock results where your subsystem is waiting on xenidc which is       */
+/* waiting on the client of your subsystem to free resources which is        */
+/* waiting on your subsystem.                                                */
+/*                                                                           */
+/* Second incorrect strategy:                                                */
+/*                                                                           */
+/* 1) Create an anti-deadlock resource pool.                                 */
+/*                                                                           */
+/* 2) Make an arbitrary number of non-atomic reserve_and_create and          */
+/* reserve_and_open requests for a single subsystem operation.               */
+/*                                                                           */
+/* In general, this doesn't work because your subsystem will be processing   */
+/* multiple operations concurrently which means that the anti-deadlock       */
+/* resources might get fully used by multiple concurrent operations in such  */
+/* a way that none of the operations have enough resources to proceed so     */
+/* they all end up waiting indefinitely on each other.                       */
+/*                                                                           */
+/* Third incorrect strategy:                                                 */
+/*                                                                           */
+/* 1) Create an anti-deadlock resource pool.                                 */
+/*                                                                           */
+/* 2) Use the same anti-deadlock pool for dependent operations.              */
+/*                                                                           */
+/* This doesn't work because an operation might acquire all the              */
+/* anti-deadlock reservation and then initiate a second operation.  The      */
+/* second operation goes to the same anti-deadlock pool and waits forever    */
+/* for the dependent operation to free the resources back.  The dependent    */
+/* operation never frees the resources because it is dependent on the second */
+/* operation.                                                                */
+/*                                                                           */
+/* Fourth incorrect strategy:                                                */
+/*                                                                           */
+/* 1) Create anti-deadlock resource pools for different dependent            */
+/* operations.                                                               */
+/*                                                                           */
+/* 2) Different operations acquire resources from the pools in different     */
+/* order.                                                                    */
+/*                                                                           */
+/* This doesn't work because of the potential for another cyclic deadlock.   */
+/*                                                                           */
+/*****************************************************************************/
+
+#include "xenidc_endpoint.h"
+#include "xenidc_rbr_provider_pool.h"
+#include "xenidc_rbr_mapper_pool.h"
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_address.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_address.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,60 @@
+/*****************************************************************************/
+/* Xen inter-domain communication address.                                   */
+/*                                                                           */
+/* 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 __ASM_XEN_XENIDC_ADDRESS_H__
+#define __ASM_XEN_XENIDC_ADDRESS_H__
+
+typedef struct xenidc_address_struct xenidc_address;
+
+struct xenidc_address_struct
+{
+    char * local;
+    char * remote;
+    int    remote_id;
+};
+
+static inline void xenidc_address_init
+  ( xenidc_address * address, char * local, char * remote, int remote_id )
+{
+    address->local     = local;
+    address->remote    = remote;
+    address->remote_id = remote_id;
+}
+
+static inline char * xenidc_address_query_local_domain
+  ( xenidc_address * address )
+{
+    return address->local;
+}
+
+static inline char * xenidc_address_query_remote_domain
+  ( xenidc_address * address )
+{
+    return address->remote;
+}
+
+static inline int xenidc_address_query_remote_domain_id
+  ( xenidc_address * address )
+{
+    return address->remote_id;
+}
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_callback.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_callback.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,166 @@
+/*****************************************************************************/
+/* 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 XENIDC_CALLBACK_H
+#define XENIDC_CALLBACK_H
+
+#include <linux/spinlock.h>
+#include "xenidc_error.h"
+#include "xenidc_work.h"
+
+/* Service parameter blocks contain callbacks for asynchronous completions.  */
+
+typedef struct xenidc_callback_struct xenidc_callback;
+
+struct xenidc_callback_struct
+{
+    xenidc_work  work;
+    xenidc_error error;
+};
+
+#define XENIDC_CALLBACK_LINK work.XENIDC_WORK_LINK
+
+/* Client of service initialises callback with its callback function.        */
+
+typedef void ( xenidc_callback_function )( xenidc_callback * callback );
+
+static inline void xenidc_callback_init
+  ( xenidc_callback * callback, xenidc_callback_function * function )
+{
+    xenidc_work_init( &callback->work, (void(*)(void*))function, callback );
+
+    callback->error = XENIDC_ERROR_SUCCESS;
+}
+
+/* Client may use link whilst it owns parameter block. Service may use link  */
+/* whilst it owns parameter block.  Link is reserved whilst callback is      */
+/* scheduled for completion.                                                 */
+
+static inline struct list_head * xenidc_callback_to_link
+  ( xenidc_callback * callback )
+{
+    return xenidc_work_to_link( &callback->work );
+}
+
+static inline xenidc_callback * xenidc_callback_link_to
+  ( struct list_head * link )
+{
+    return container_of
+      ( xenidc_work_link_to( link ), xenidc_callback, work );
+}
+
+/* Service which completes requests concurrently may call                    */
+/* xenidc_callback_complete or xenidc_callback_success to complete the       */
+/* callback.                                                                 */
+
+static inline void xenidc_callback_complete
+  ( xenidc_callback * callback, xenidc_error error )
+{
+    callback->error = error;
+
+    xenidc_work_schedule( &callback->work );
+}
+
+static inline void xenidc_callback_success
+  ( xenidc_callback * callback )
+{
+    xenidc_callback_complete( callback, 0 );
+}
+
+/* These functions used by serialiser below. */
+
+static inline void xenidc_callback_set_error
+  ( xenidc_callback * callback, xenidc_error error )
+{
+    callback->error = error;
+}
+
+static inline void xenidc_callback_complete_synchronously
+  ( xenidc_callback * callback )
+{
+    xenidc_work_perform_synchronously( &callback->work );
+}
+
+/* When callback completes, client may call xenidc_callback_query_error to   */
+/* get the error code.                                                       */
+
+static inline xenidc_error xenidc_callback_query_error
+  ( xenidc_callback * callback )
+{
+    return callback->error;
+}
+
+/* Services which must serialise completions to preserve submission order    */
+/* can use one of these.                                                     */
+
+typedef struct xenidc_callback_serialiser_struct xenidc_callback_serialiser;
+
+struct xenidc_callback_serialiser_struct
+{
+    spinlock_t       lock;
+    struct list_head list;
+    xenidc_work      work;
+    int              running;
+};
+
+void xenidc_callback_serialiser_function( void * context );
+
+#define XENIDC_CALLBACK_SERIALISER_INIT( name )                  \
+{                                                                \
+    SPIN_LOCK_UNLOCKED,                                          \
+    LIST_HEAD_INIT( name.list ),                                 \
+    XENIDC_WORK_INIT                                             \
+      ( name.work, xenidc_callback_serialiser_function, &name ), \
+    0                                                            \
+}
+
+#define XENIDC_CALLBACK_SERIALISER( name ) \
+xenidc_callback_serialiser name =          \
+  XENIDC_CALLBACK_SERIALISER_INIT( name )
+
+/* The service completes the callback to the serialiser which serialises the */
+/* completions to the client, performing them in submission order.           */
+
+static inline void xenidc_callback_serialiser_complete_callback
+(
+    xenidc_callback_serialiser * serialiser,
+    xenidc_callback            * callback,
+    xenidc_error                 error
+)
+{
+    xenidc_callback_set_error( callback, error );
+
+    {
+        unsigned long flags;
+
+        spin_lock_irqsave( &serialiser->lock, flags );
+
+        list_add_tail
+          ( xenidc_callback_to_link( callback ), &serialiser->list );
+
+        spin_unlock_irqrestore( &serialiser->lock, flags );
+    }
+
+    xenidc_work_schedule( &serialiser->work );
+}
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_channel.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_channel.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,146 @@
+/*****************************************************************************/
+/* Xen inter-domain communication channel abstract base class.               */
+/*                                                                           */
+/* 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 _XENIDC_CHANNEL_H
+#define _XENIDC_CHANNEL_H
+
+#include <asm-xen/xenidc_callback.h>
+#include <asm-xen/xenidc_local_buffer_reference.h>
+
+typedef struct xenidc_channel_message_struct xenidc_channel_message;
+
+struct xenidc_channel_message_struct
+{
+    xenidc_callback               callback;
+    xenidc_local_buffer_reference message_lbr;
+};
+
+#define XENIDC_CHANNEL_MESSAGE_LINK callback.XENIDC_CALLBACK_LINK
+
+static inline struct list_head * xenidc_channel_message_to_link
+  ( xenidc_channel_message * message )
+{
+    return &message->XENIDC_CHANNEL_MESSAGE_LINK;
+}
+
+static inline xenidc_callback * xenidc_channel_message_to_callback
+  ( xenidc_channel_message * message )
+{
+    return &message->callback;
+}
+
+static inline xenidc_channel_message * xenidc_channel_message_callback_to
+  ( xenidc_callback * callback )
+{
+    return container_of( callback, xenidc_channel_message, callback );
+}
+
+static inline void xenidc_channel_message_init
+  ( xenidc_channel_message * message, xenidc_callback_function * callback )
+{
+    xenidc_callback_init
+      ( xenidc_channel_message_to_callback( message ), callback );
+}
+
+static inline void xenidc_channel_message_set_message_lbr
+  ( xenidc_channel_message * message, xenidc_local_buffer_reference lbr )
+{
+    message->message_lbr = lbr;
+}
+
+typedef struct xenidc_channel_struct xenidc_channel;
+
+struct xenidc_channel_struct
+{
+    void ( * submit_message )
+      ( xenidc_channel * channel, xenidc_channel_message * message );
+    void * client_context;
+    void ( * connect )( void * client_context );
+    void ( * handle_message )
+      ( void * client_context, xenidc_channel_message * message );
+    void ( * disconnect )
+      ( void * client_context, xenidc_callback * callback );
+};
+
+/* Called by a derived class to initialise the base class. */
+
+static inline void xenidc_channel_init
+(
+    xenidc_channel * channel,
+    void ( * submit_message )
+      ( xenidc_channel * channel, xenidc_channel_message * message )
+)
+{
+    channel->submit_message = submit_message;
+}
+
+/* Called by a derived class to notify the client. */
+
+static inline void xenidc_channel_connect( xenidc_channel * channel )
+{
+    channel->connect( channel->client_context );
+}
+
+/* Called by a derived class to notify the client. */
+
+static inline void xenidc_channel_handle_message
+  ( xenidc_channel * channel, xenidc_channel_message * message )
+{
+    channel->handle_message( channel->client_context, message );
+}
+
+/* Called by a derived class to notify the client. */
+
+static inline void xenidc_channel_disconnect
+  ( xenidc_channel * channel, xenidc_callback * callback )
+{
+    channel->disconnect( channel->client_context, callback );
+}
+
+/* Called by the client class before derived class first calls connect. */
+
+static inline void xenidc_channel_install_client
+(
+    xenidc_channel * channel,
+    void   * client_context,
+    void ( * connect )( void * client_context ),
+    void ( * handle_message )
+      ( void * client_context, xenidc_channel_message * message ),
+    void ( * disconnect )
+      ( void * client_context, xenidc_callback * callback )
+)
+{
+    channel->client_context = client_context;
+    channel->connect        = connect;
+    channel->handle_message = handle_message;
+    channel->disconnect     = disconnect;
+}
+
+/* Called by the client class between connect and disconnect callback to     */
+/* submit a message.                                                         */
+
+static inline void xenidc_channel_submit_message
+  ( xenidc_channel * channel, xenidc_channel_message * message )
+{
+    channel->submit_message( channel, message );
+}
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_concatenate.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_concatenate.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,47 @@
+/*****************************************************************************/
+/* Support for concatenated local buffer references                          */
+/*                                                                           */
+/* 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 XENIDC_CONCATENATE_H
+#define XENIDC_CONCATENATE_H
+
+#include "xenidc.h"
+
+typedef struct xenidc_concatenate_base_struct xenidc_concatenate_base;
+
+struct xenidc_concatenate_base_struct
+{
+    xenidc_local_buffer_reference * head;
+    xenidc_local_buffer_reference * tail;
+};
+
+/* To create a concatenated lbr, you need a base resource which will persist */
+/* for the lifetime of the created lbr.  Pass a pointer to this resource and */
+/* pointers to the underlying lbrs to concatenate.  These must also persist  */
+/* for the lifetime of the created lbr.                                      */
+
+extern xenidc_local_buffer_reference xenidc_concatenate_create_lbr
+(
+    xenidc_concatenate_base       * base,
+    xenidc_local_buffer_reference * head,
+    xenidc_local_buffer_reference * tail
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_endpoint.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_endpoint.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,203 @@
+/*****************************************************************************/
+/* Xen inter-domain communication endpoint.                                  */
+/*                                                                           */
+/* 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 __ASM_XEN_XENIDC_ENDPOINT_H__
+#define __ASM_XEN_XENIDC_ENDPOINT_H__
+
+#include "xenidc_address.h"
+#include "xenidc_gateway.h"
+#include "xenidc_xbgt_channel.h"
+
+typedef struct xenidc_gateway_message_struct xenidc_endpoint_message;
+
+#define XENIDC_ENDPOINT_MESSAGE_LINK XENIDC_GATEWAY_MESSAGE_LINK
+
+static inline xenidc_callback * xenidc_endpoint_message_to_callback
+  ( xenidc_endpoint_message * message )
+{
+    return xenidc_gateway_message_to_callback( message );
+}
+
+static inline xenidc_endpoint_message * xenidc_endpoint_message_callback_to
+  ( xenidc_callback * callback )
+{
+    return xenidc_gateway_message_callback_to( callback );
+}
+
+static inline struct list_head * xenidc_endpoint_message_to_link
+  ( xenidc_endpoint_message * message )
+{
+    return xenidc_callback_to_link
+      ( xenidc_endpoint_message_to_callback( message ) );
+}
+
+static inline xenidc_endpoint_message * xenidc_endpoint_message_link_to
+  ( struct list_head * link )
+{
+    return xenidc_endpoint_message_callback_to
+      ( xenidc_callback_link_to( link ) );
+}
+
+static inline void xenidc_endpoint_message_init
+  ( xenidc_endpoint_message * message, xenidc_callback_function * callback )
+{
+    xenidc_gateway_message_init( message, callback );
+}
+
+static inline void xenidc_endpoint_message_set_message_lbr
+  ( xenidc_endpoint_message * message, xenidc_local_buffer_reference lbr )
+{
+    message->message_lbr = lbr;
+}
+
+static inline xenidc_local_buffer_reference *
+  xenidc_endpoint_message_to_message_lbr( xenidc_endpoint_message * message )
+{
+    return &message->message_lbr;
+}
+
+typedef struct xenidc_gateway_transaction_struct xenidc_endpoint_transaction;
+
+#define XENIDC_ENDPOINT_TRANSACTION_LINK XENIDC_GATEWAY_TRANSACTION_LINK
+
+static inline xenidc_callback * xenidc_endpoint_transaction_to_callback
+  ( xenidc_endpoint_transaction * transaction )
+{
+    return xenidc_gateway_transaction_to_callback( transaction );
+}
+
+static inline xenidc_endpoint_transaction *
+  xenidc_endpoint_transaction_callback_to( xenidc_callback * callback )
+{
+    return xenidc_gateway_transaction_callback_to( callback );
+}
+
+static inline struct list_head * xenidc_endpoint_transaction_to_link
+  ( xenidc_endpoint_transaction * transaction )
+{
+    return xenidc_callback_to_link
+      ( xenidc_endpoint_transaction_to_callback( transaction ) );
+}
+
+static inline xenidc_endpoint_transaction * xenidc_endpoint_transaction_link_to
+  ( struct list_head * link )
+{
+    return xenidc_endpoint_transaction_callback_to
+      ( xenidc_callback_link_to( link ) );
+}
+
+static inline void xenidc_endpoint_transaction_init
+(
+    xenidc_endpoint_transaction * transaction,
+    xenidc_callback_function    * callback
+)
+{
+    xenidc_gateway_transaction_init( transaction, callback );
+}
+
+static inline void xenidc_endpoint_transaction_set_parameters_lbr
+(
+    xenidc_endpoint_transaction * transaction,
+    xenidc_local_buffer_reference lbr
+)
+{
+    transaction->parameters_lbr = lbr;
+}
+
+static inline void xenidc_endpoint_transaction_set_status_lbr
+(
+    xenidc_endpoint_transaction * transaction,
+    xenidc_local_buffer_reference lbr
+)
+{
+    transaction->status_lbr = lbr;
+}
+
+static inline xenidc_local_buffer_reference *
+  xenidc_endpoint_transaction_to_parameters_lbr
+    ( xenidc_endpoint_transaction * transaction )
+{
+    return &transaction->parameters_lbr;
+}
+
+static inline xenidc_local_buffer_reference *
+  xenidc_endpoint_transaction_to_status_lbr
+    ( xenidc_endpoint_transaction * transaction )
+{
+    return &transaction->status_lbr;
+}
+
+static inline void xenidc_endpoint_transaction_complete
+  ( xenidc_endpoint_transaction * transaction, xenidc_error error )
+{
+    xenidc_callback_complete
+      ( xenidc_endpoint_transaction_to_callback( transaction ), error );
+}
+
+static inline xenidc_error xenidc_endpoint_transaction_query_error
+  ( xenidc_endpoint_transaction * transaction )
+{
+    return xenidc_callback_query_error
+      ( xenidc_endpoint_transaction_to_callback( transaction ) );
+}
+
+typedef struct xenidc_endpoint_struct xenidc_endpoint;
+
+struct xenidc_endpoint_struct
+{
+    xenidc_gateway      gateway;
+    xenidc_xbgt_channel channel;
+};
+
+extern int xenidc_endpoint_init
+(
+    xenidc_endpoint * endpoint,
+
+    void ( * connect )( xenidc_endpoint * endpoint ),
+    void ( * handle_message    )
+      ( xenidc_endpoint * endpoint, xenidc_endpoint_message * message ),
+    void ( * handle_transaction )
+    (
+        xenidc_endpoint * endpoint,
+        xenidc_endpoint_transaction * transaction
+    ),
+    void ( * disconnect )
+      ( xenidc_endpoint * endpoint, xenidc_callback * callback ),
+    u32                      initiator_quota,
+    xenidc_buffer_byte_count initiator_maximum_byte_count,
+    u32                      target_quota,
+    xenidc_buffer_byte_count target_maximum_byte_count
+);
+
+extern void xenidc_endpoint_create
+  ( xenidc_endpoint * endpoint, xenidc_address address );
+
+extern void xenidc_endpoint_submit_message
+  ( xenidc_endpoint * endpoint, xenidc_endpoint_message * message );
+
+extern void xenidc_endpoint_submit_transaction
+  ( xenidc_endpoint * endpoint, xenidc_endpoint_transaction * transaction );
+
+extern void xenidc_endpoint_destroy( xenidc_endpoint * endpoint );
+
+extern void xenidc_endpoint_exit( xenidc_endpoint * endpoint );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_error.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_error.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,56 @@
+#ifndef __ASM_XEN_XENIDC_ERROR_H__
+#define __ASM_XEN_XENIDC_ERROR_H__
+
+#include <asm/types.h>
+
+typedef u32 xenidc_error;
+
+/* The first few error numbers are reserved for success and transport errors */
+/* which are common to all IDC protocols.                                    */
+
+#define XENIDC_ERROR_SUCCESS                   ( (xenidc_error)0 )
+#define XENIDC_ERROR_ABORTED                   ( (xenidc_error)1 )
+#define XENIDC_ERROR_FAILURE                   ( (xenidc_error)2 )
+#define XENIDC_ERROR_DISCONNECT                ( (xenidc_error)3 )
+/* Initiator did everything right, target software needs to be fixed: */
+#define XENIDC_ERROR_IMPLEMENTATION_DEFICIENCY ( (xenidc_error)4 )
+/* Unexpected transaction/transaction in wrong sequence etc: */
+#define XENIDC_ERROR_INVALID_PROTOCOL          ( (xenidc_error)5 )
+/* Underlength parameters/status etc: */
+#define XENIDC_ERROR_INVALID_FORMAT            ( (xenidc_error)6 )
+/* Parameter value wrong: */
+#define XENIDC_ERROR_INVALID_PARAMETER         ( (xenidc_error)7 )
+/* Something about a request exceeded a hard-coded limit: */
+#define XENIDC_ERROR_TOO_BIG                   ( (xenidc_error)8 )
+
+static inline xenidc_error xenidc_error_map_local_to( int error )
+{
+    /* FIXME */
+    switch( error )
+    {
+      case 0:
+        return XENIDC_ERROR_SUCCESS;
+      default:
+        return XENIDC_ERROR_FAILURE;
+    }
+}
+
+static inline int xenidc_error_map_to_local( xenidc_error error )
+{
+    /* FIXME */
+    switch( error )
+    {
+      case XENIDC_ERROR_SUCCESS:
+        return 0;
+      default:
+        return -1;
+    }
+}
+
+/* Protocols can define their own set of protocol specific errors starting   */
+/* at this one.  The driver code on either side must translate between the   */
+/* local OS specific error codes and the protocol specific error codes.      */
+
+#define XENIDC_ERROR_PROTOCOL_SPECIFIC_FIRST ( (xenidc_error)256 )
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_gateway.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_gateway.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,253 @@
+/*****************************************************************************/
+/* Xen inter-domain communication gateway class. This class uses the message */
+/* channel service provided by a xenidc_channel to implement a gateway       */
+/* service which allows the client to send both messages and transactions    */
+/* (consisting of parameters and status) between domains.                    */
+/*                                                                           */
+/* 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 _XENIDC_GATEWAY_H
+#define _XENIDC_GATEWAY_H
+
+#include <asm-xen/xenidc_callback.h>
+#include <asm-xen/xenidc_channel.h>
+#include <asm-xen/xenidc_local_buffer_reference.h>
+
+typedef struct xenidc_gateway_initiator_resource_struct
+  xenidc_gateway_initiator_resource;
+
+typedef struct xenidc_gateway_target_resource_struct
+  xenidc_gateway_target_resource;
+
+typedef struct xenidc_gateway_message_and_transaction_header_struct
+  xenidc_gateway_message_and_transaction_header;
+
+struct xenidc_gateway_message_and_transaction_header_struct
+{
+    xenidc_callback callback;
+    int             transaction_not_message;
+};
+
+#define XENIDC_GATEWAY_MESSAGE_AND_TRANSACTION_HEADER_LINK \
+callback.XENIDC_CALLBACK_LINK
+
+static inline struct list_head *
+  xenidc_gateway_message_and_transaction_header_to_link
+    ( xenidc_gateway_message_and_transaction_header * header )
+{
+    return xenidc_callback_to_link( &header->callback );
+}
+
+static inline xenidc_callback *
+  xenidc_gateway_message_and_transaction_header_to_callback
+    ( xenidc_gateway_message_and_transaction_header * header )
+{
+    return &header->callback;
+}
+
+typedef struct xenidc_gateway_message_struct xenidc_gateway_message;
+
+struct xenidc_gateway_message_struct
+{
+    xenidc_gateway_message_and_transaction_header header;
+    xenidc_local_buffer_reference                 message_lbr;
+};
+
+static inline xenidc_callback * xenidc_gateway_message_to_callback
+  ( xenidc_gateway_message * message )
+{
+    return &message->header.callback;
+}
+
+static inline xenidc_gateway_message * xenidc_gateway_message_callback_to
+  ( xenidc_callback * callback )
+{
+    return container_of( callback, xenidc_gateway_message, header.callback );
+}
+
+static inline struct list_head * xenidc_gateway_message_to_link
+  ( xenidc_gateway_message * message )
+{
+    return xenidc_callback_to_link( &message->header.callback );
+}
+
+static inline xenidc_gateway_message * xenidc_gateway_message_link_to
+  ( struct list_head * link )
+{
+    return xenidc_gateway_message_callback_to
+      ( xenidc_callback_link_to( link ) );
+}
+
+static inline xenidc_gateway_message * xenidc_gateway_message_header_to
+  ( xenidc_gateway_message_and_transaction_header * header )
+{
+    return container_of( header, xenidc_gateway_message, header );
+}
+
+static inline void xenidc_gateway_message_init
+  ( xenidc_gateway_message * message, xenidc_callback_function * callback )
+{
+    xenidc_callback_init
+      ( xenidc_gateway_message_to_callback( message ), callback );
+
+    message->header.transaction_not_message = 0;
+}
+
+typedef struct xenidc_gateway_transaction_struct xenidc_gateway_transaction;
+
+struct xenidc_gateway_transaction_struct
+{
+    xenidc_gateway_message_and_transaction_header header;
+    xenidc_local_buffer_reference                 parameters_lbr;
+    xenidc_local_buffer_reference                 status_lbr;
+};
+
+#define XENIDC_GATEWAY_TRANSACTION_LINK header.callback.XENIDC_CALLBACK_LINK
+
+static inline xenidc_callback * xenidc_gateway_transaction_to_callback
+  ( xenidc_gateway_transaction * transaction )
+{
+    return &transaction->header.callback;
+}
+
+static inline xenidc_gateway_transaction *
+  xenidc_gateway_transaction_callback_to( xenidc_callback * callback )
+{
+    return container_of
+      ( callback, xenidc_gateway_transaction, header.callback );
+}
+
+static inline struct list_head * xenidc_gateway_transaction_to_link
+  ( xenidc_gateway_transaction * transaction )
+{
+    return xenidc_callback_to_link
+      ( xenidc_gateway_transaction_to_callback( transaction ) );
+}
+
+static inline xenidc_gateway_transaction * xenidc_gateway_transaction_link_to
+  ( struct list_head * link )
+{
+    return xenidc_gateway_transaction_callback_to
+      ( xenidc_callback_link_to( link ) );
+}
+
+static inline xenidc_gateway_transaction * xenidc_gateway_transaction_header_to
+  ( xenidc_gateway_message_and_transaction_header * header )
+{
+    return container_of( header, xenidc_gateway_transaction, header );
+}
+
+static inline void xenidc_gateway_transaction_init
+(
+    xenidc_gateway_transaction * transaction,
+    xenidc_callback_function   * callback
+)
+{
+    xenidc_callback_init
+      ( xenidc_gateway_transaction_to_callback( transaction ), callback );
+
+    transaction->header.transaction_not_message = 1;
+}
+
+typedef enum
+{
+    xenidc_gateway_state_i,
+    xenidc_gateway_state_i_cc,
+    xenidc_gateway_state_i_cc_cd,
+    xenidc_gateway_state_i_cc_lc,
+    xenidc_gateway_state_i_cc_cd_lc,
+    xenidc_gateway_state_i_cc_lc_cd,
+    xenidc_gateway_state_i_cc_lc_cd_km,
+    xenidc_gateway_state_i_cc_cd_lc_lg,
+    xenidc_gateway_state_i_cc_cd_lc_ld,
+    xenidc_gateway_state_i_cc_cd_lc_lg_ld,
+    xenidc_gateway_state_i_cc_cd_lc_lg_ld_ti
+}
+xenidc_gateway_state;
+
+typedef struct xenidc_gateway_struct xenidc_gateway;
+
+struct xenidc_gateway_struct
+{
+    xenidc_channel * channel;
+    void         ( * connect )( xenidc_gateway * gateway );
+    void         ( * handle_message )
+      ( xenidc_gateway * gateway, xenidc_gateway_message * message );
+    void         ( * handle_transaction )
+      ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction );
+    void         ( * disconnect )
+      ( xenidc_gateway * gateway, xenidc_callback * callback );
+
+    u32                      initiator_quota;
+    u32                      target_quota;
+    xenidc_buffer_byte_count target_maximum_byte_count;
+
+    struct list_head                    initiator_resource_list;
+    xenidc_gateway_initiator_resource * initiator_resources;
+
+    struct list_head                 target_resource_list;
+    xenidc_gateway_target_resource * target_resources;
+
+    spinlock_t lock;
+
+    xenidc_gateway_state state;
+
+    struct list_head message_and_transaction_list;
+    struct list_head channel_message_list;
+
+    xenidc_work     kick_messages_and_transactions_1_work;
+    xenidc_work     kick_channel_messages_1_work;
+    xenidc_work     connect_client_1_work;
+    xenidc_work     disconnect_client_1_work;
+    xenidc_callback disconnect_client_2_callback;
+
+    int kick_messages_and_transactions_out : 1;
+    int kick_channel_messages_out : 1;
+    u32 initiator_resources_out;
+    u32 target_resources_out;
+
+    xenidc_callback * channel_disconnect_callback;
+};
+
+extern int xenidc_gateway_init
+(
+    xenidc_gateway * gateway,
+    xenidc_channel * channel,
+    void         ( * connect    )( xenidc_gateway * gateway ),
+    void         ( * handle_message     )
+      ( xenidc_gateway * gateway, xenidc_gateway_message * message ),
+    void         ( * handle_transaction )
+      ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction ),
+    void         ( * disconnect )
+      ( xenidc_gateway * gateway, xenidc_callback * callback ),
+    u32                      initiator_quota,
+    xenidc_buffer_byte_count initiator_maximum_byte_count,
+    u32                      target_quota,
+    xenidc_buffer_byte_count target_maximum_byte_count
+);
+
+extern void xenidc_gateway_submit_message
+  ( xenidc_gateway * gateway, xenidc_gateway_message * message );
+
+extern void xenidc_gateway_submit_transaction
+  ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction );
+
+extern void xenidc_gateway_exit( xenidc_gateway * gateway );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_gnttab_channel.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_gnttab_channel.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,222 @@
+/*****************************************************************************/
+/* This is a class which implements a grant-tables based inter-domain        */
+/* message channel. The implementation of the bring-up and tear-down         */
+/* handshaking is left to a derived class.                                   */
+/* This class is used by xenidc_xbgt_channel (which implements bring-up and  */
+/* teardown using xenbus) which is in turn used to implement the             */
+/* xenidc_endpoint class.                                                    */
+/*                                                                           */
+/* 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 _XENIDC_GNTTAB_CHANNEL_H
+#define _XENIDC_GNTTAB_CHANNEL_H
+
+#include <asm-xen/gnttab.h>
+#include <asm-xen/xenidc_channel.h>
+
+typedef struct xenidc_gnttab_channel_struct xenidc_gnttab_channel;
+
+typedef struct xenidc_gnttab_channel_target_resource_struct
+  xenidc_gnttab_channel_target_resource;
+
+struct xenidc_gnttab_channel_target_resource_struct
+{
+    xenidc_channel_message   message;
+    xenidc_gnttab_channel  * channel;
+};
+
+#define XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_LINK \
+message.XENIDC_CHANNEL_MESSAGE_LINK
+
+typedef enum
+{
+    xenidc_gnttab_channel_state_i,
+    xenidc_gnttab_channel_state_i_c1r,
+    xenidc_gnttab_channel_state_i_c1r_c1c,
+    xenidc_gnttab_channel_state_i_c1r_c1c_c2r,
+    xenidc_gnttab_channel_state_i_c1r_c1c_d1r,
+    xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s,
+    xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc,
+    xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r,
+    xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc,
+    xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc,
+    xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc,
+    xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri
+}
+xenidc_gnttab_channel_state;
+
+#define XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT 16
+
+struct xenidc_gnttab_channel_struct
+{
+    xenidc_channel channel;
+    void ( * protocol_error )( xenidc_gnttab_channel * channel );
+
+    xenidc_gnttab_channel * send_irq_context;
+    xenidc_gnttab_channel * recv_irq_context;
+
+    void               * send_ring;
+    struct vm_struct   * recv_ring_area;
+    grant_ref_t          grant_ref_pool;
+
+    spinlock_t lock;
+
+    xenidc_gnttab_channel_state state;
+
+    struct list_head message_list;
+
+    xenidc_work     do_phase_one_connect_1_work;
+    xenidc_work     do_phase_two_connect_1_work;
+    xenidc_work     connect_client_1_work;
+    xenidc_work     disconnect_client_1_work;
+    xenidc_callback disconnect_client_2_callback;
+    xenidc_work     do_phase_two_disconnect_1_work;
+    xenidc_work     do_phase_one_disconnect_1_work;
+    xenidc_work     kick_send_ring_1_work;
+    xenidc_work     kick_recv_ring_1_work;
+
+    xenidc_gnttab_channel_target_resource target_resources
+      [ XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT ];
+    u8                                    target_resource_free
+      [ XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT ];
+    u16                                   target_resource_offset
+      [ XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT ];
+
+    int first_target_resource;
+    int next_target_resource;
+
+    int send_ring_kick_out : 1;
+    int recv_ring_kick_out : 1;
+
+    xenidc_callback * current_callback;
+
+    unsigned int send_event_channel;
+    grant_ref_t  send_ring_ref;
+    int          send_irq;
+
+    unsigned int                  recv_event_channel;
+    u16                           recv_ring_handle;
+    xenidc_local_buffer_reference recv_ring_lbr;
+    int                           recv_irq;
+    u16                           recv_ring_offset;
+};
+
+/* Cast to base class. */
+
+static inline xenidc_channel * xenidc_gnttab_channel_to_channel
+  ( xenidc_gnttab_channel * channel )
+{
+    return &channel->channel;
+}
+
+/* Cast from base class. */
+
+static inline xenidc_gnttab_channel * xenidc_gnttab_channel_channel_to
+  ( xenidc_channel * channel )
+{
+    return container_of( channel, xenidc_gnttab_channel, channel );
+}
+
+/* Called by derived class. */
+
+extern int xenidc_gnttab_channel_init
+(
+    xenidc_gnttab_channel * channel,
+    void ( * protocol_error )( xenidc_gnttab_channel * channel )
+);
+
+/* xenidc_gnttab_channel_phase_one_connect should never fail because we are  */
+/* supposed to have reserved all required resources during initialisation.   */
+/* Called by derived class.                                                  */
+
+typedef struct xenidc_gnttab_channel_phase_one_connect_request_struct
+  xenidc_gnttab_channel_phase_one_connect_request;
+
+struct xenidc_gnttab_channel_phase_one_connect_request_struct
+{
+    xenidc_callback callback;
+    domid_t         remote_domain_id;   /* IN  */
+    grant_ref_t     send_ring_ref;      /* OUT */
+    unsigned int    send_event_channel; /* OUT */
+};
+
+static inline xenidc_gnttab_channel_phase_one_connect_request *
+  xenidc_gnttab_channel_phase_one_connect_request_callback_to
+    ( xenidc_callback * callback )
+{
+    return container_of
+      ( callback, xenidc_gnttab_channel_phase_one_connect_request, callback );
+}
+
+extern void xenidc_gnttab_channel_phase_one_connect
+(
+    xenidc_gnttab_channel                           * channel,
+    xenidc_gnttab_channel_phase_one_connect_request * request
+);
+
+/* Called by derived class whilst phase one connected to reset the ring      */
+/* before (re)establishing the connection with the other side.               */
+
+extern void xenidc_gnttab_channel_reset_ring
+  ( xenidc_gnttab_channel * channel );
+
+/* xenidc_gnttab_channel_phase_two_connect should only fail if the remote    */
+/* domain provided incorrect parameters.                                     */
+/* Called by derived class.                                                  */
+
+typedef struct xenidc_gnttab_channel_phase_two_connect_request_struct
+  xenidc_gnttab_channel_phase_two_connect_request;
+
+struct xenidc_gnttab_channel_phase_two_connect_request_struct
+{
+    xenidc_callback callback;
+    domid_t         remote_domain_id;   /* IN */
+    grant_ref_t     recv_ring_ref;      /* IN */
+    unsigned int    recv_event_channel; /* IN */
+};
+
+static inline xenidc_gnttab_channel_phase_two_connect_request *
+  xenidc_gnttab_channel_phase_two_connect_request_callback_to
+    ( xenidc_callback * callback )
+{
+    return container_of
+      ( callback, xenidc_gnttab_channel_phase_two_connect_request, callback );
+}
+
+extern void xenidc_gnttab_channel_phase_two_connect
+(
+    xenidc_gnttab_channel                           * channel,
+    xenidc_gnttab_channel_phase_two_connect_request * request
+);
+
+/* Called by derived class. */
+
+extern void xenidc_gnttab_channel_phase_two_disconnect
+  ( xenidc_gnttab_channel * channel, xenidc_callback * callback );
+
+/* Called by derived class. */
+
+extern void xenidc_gnttab_channel_phase_one_disconnect
+  ( xenidc_gnttab_channel * channel, xenidc_callback * callback );
+
+/* Called by derived class. */
+
+extern void xenidc_gnttab_channel_exit( xenidc_gnttab_channel * channel );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_local_buffer_reference.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_local_buffer_reference.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,283 @@
+/*****************************************************************************/
+/* Xen inter-domain communication local buffer reference object.             */
+/*                                                                           */
+/* 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 __ASM_XEN_XENIDC_LOCAL_BUFFER_REFERENCE_H__
+#define __ASM_XEN_XENIDC_LOCAL_BUFFER_REFERENCE_H__
+
+#include <asm/types.h>
+#include "xenidc_callback.h"
+
+#define XENIDC_LOCAL_BUFFER_REFERENCE_TYPE_FLAG_VIRTUAL         0xC0000000
+#define XENIDC_LOCAL_BUFFER_REFERENCE_TYPE_FLAG_VIRTUAL_ADVANCE 0x80000000
+
+typedef u32 xenidc_buffer_type;
+
+typedef u32 xenidc_buffer_byte_count;
+
+typedef struct xenidc_local_buffer_reference_struct
+  xenidc_local_buffer_reference;
+
+struct xenidc_local_buffer_reference_struct
+{
+    xenidc_buffer_type         type;
+    void                     * base;
+    xenidc_buffer_byte_count   byte_offset;
+    xenidc_buffer_byte_count   byte_count;
+};
+
+static inline xenidc_buffer_byte_count
+  xenidc_local_buffer_reference_query_byte_offset
+    ( xenidc_local_buffer_reference * lbr )
+{
+    return lbr->byte_offset;
+}
+
+static inline xenidc_buffer_byte_count
+  xenidc_local_buffer_reference_query_byte_count
+    ( xenidc_local_buffer_reference * lbr )
+{
+    return lbr->byte_count;
+}
+
+typedef struct xenidc_buffer_concrete_class_struct
+  xenidc_buffer_concrete_class;
+
+struct xenidc_buffer_concrete_class_struct
+{
+    struct list_head   link;
+    xenidc_buffer_type type;
+    void ( * copy_in_or_out )
+    (
+        xenidc_buffer_concrete_class  * class,
+        xenidc_local_buffer_reference * lbr,
+        void                          * buffer,
+        xenidc_buffer_byte_count        byte_count,
+        int                             out
+    );
+    void ( * zero )
+    (
+        xenidc_buffer_concrete_class  * class,
+        xenidc_local_buffer_reference * lbr
+    );
+};
+
+extern xenidc_buffer_type
+  xenidc_local_buffer_reference_register_buffer_concrete_class
+(
+    xenidc_buffer_concrete_class * class,
+    void ( * copy_in_or_out )
+    (
+        xenidc_buffer_concrete_class  * class,
+        xenidc_local_buffer_reference * lbr,
+        void                          * buffer,
+        xenidc_buffer_byte_count        byte_count,
+        int                             out
+    ),
+    void ( * zero ) /* NULL for the inefficient default */
+    (
+        xenidc_buffer_concrete_class  * class,
+        xenidc_local_buffer_reference * lbr
+    )
+);
+
+typedef struct xenidc_buffer_copy_class_struct xenidc_buffer_copy_class;
+
+struct xenidc_buffer_copy_class_struct
+{
+    struct list_head   link;
+    xenidc_buffer_type target_type;
+    xenidc_buffer_type source_type;
+    void ( * copy )
+    (
+        xenidc_buffer_copy_class      * class,
+        xenidc_local_buffer_reference * target,
+        xenidc_local_buffer_reference * source,
+        xenidc_buffer_byte_count        byte_count
+    );
+};
+
+extern void xenidc_local_buffer_reference_register_buffer_copy_class
+(
+    xenidc_buffer_copy_class * class,
+    xenidc_buffer_type         target_type,
+    xenidc_buffer_type         source_type,
+    void ( * copy )
+    (
+        xenidc_buffer_copy_class      * class,
+        xenidc_local_buffer_reference * target,
+        xenidc_local_buffer_reference * source,
+        xenidc_buffer_byte_count        byte_count
+    )
+);
+
+typedef struct xenidc_buffer_virtual_class_struct xenidc_buffer_virtual_class;
+
+struct xenidc_buffer_virtual_class_struct
+{
+    struct list_head   link;
+    xenidc_buffer_type type;
+    xenidc_local_buffer_reference ( * resolve )
+    (
+        xenidc_buffer_virtual_class   * class,
+        xenidc_local_buffer_reference * lbr
+    );
+    void ( * advance )
+    (
+        xenidc_buffer_virtual_class   * class,
+        xenidc_local_buffer_reference * lbr,
+        xenidc_buffer_byte_count        byte_count
+    );
+};
+
+extern xenidc_buffer_type
+  xenidc_local_buffer_reference_register_buffer_virtual_class
+(
+    xenidc_buffer_virtual_class * class,
+    xenidc_local_buffer_reference ( * resolve )
+    (
+        xenidc_buffer_virtual_class   * class,
+        xenidc_local_buffer_reference * lbr
+    ),
+    void ( * advance ) /* NULL for the efficient default */
+    (
+        xenidc_buffer_virtual_class   * class,
+        xenidc_local_buffer_reference * lbr,
+        xenidc_buffer_byte_count        byte_count
+    )
+);
+
+/* Copy between an lbr and a buffer. Returns the number of bytes copied      */
+/* which is the minimum of the source and target byte_counts.                */
+
+extern xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_in_or_out
+(
+    xenidc_local_buffer_reference * lbr,
+    void                          * buffer,
+    xenidc_buffer_byte_count        buffer_byte_count,
+    int                             out
+);
+
+static inline xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_out
+(
+    xenidc_local_buffer_reference * lbr,
+    void                          * target,
+    xenidc_buffer_byte_count        target_byte_count
+)
+{
+    return xenidc_local_buffer_reference_copy_in_or_out
+      ( lbr, target, target_byte_count, 1 );
+}
+
+static inline xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_in
+(
+    xenidc_local_buffer_reference * lbr,
+    void                          * source,
+    xenidc_buffer_byte_count        source_byte_count
+)
+{
+    return xenidc_local_buffer_reference_copy_in_or_out
+      ( lbr, source, source_byte_count, 0 );
+}
+
+extern void xenidc_local_buffer_reference_zero
+  ( xenidc_local_buffer_reference * lbr );
+
+extern xenidc_buffer_byte_count xenidc_local_buffer_reference_copy
+(
+    xenidc_local_buffer_reference * target,
+    xenidc_local_buffer_reference * source
+);
+
+extern xenidc_buffer_byte_count xenidc_local_buffer_reference_virtual_advance
+  ( xenidc_local_buffer_reference * lbr, xenidc_buffer_byte_count byte_count );
+
+/* Advance increments the offset and decrements the length by the amount     */
+/* specified which is useful to advance the reference after having copied a  */
+/* chunk of data into the start of the buffer.                               */
+/* Advance returns the remaining length.                                     */
+
+static inline xenidc_buffer_byte_count xenidc_local_buffer_reference_advance
+  ( xenidc_local_buffer_reference * lbr, xenidc_buffer_byte_count byte_count )
+{
+    if
+    (
+        ( lbr->type & XENIDC_LOCAL_BUFFER_REFERENCE_TYPE_FLAG_VIRTUAL_ADVANCE )
+        ==
+        0
+    )
+    {
+        if( lbr->byte_count > byte_count )
+        {
+            lbr->byte_offset += byte_count;
+            lbr->byte_count  -= byte_count;
+        }
+        else
+        {
+            lbr->byte_offset += lbr->byte_count;
+            lbr->byte_count = 0;
+        }
+
+        return lbr->byte_count;
+    }
+    else
+    {
+        return
+          xenidc_local_buffer_reference_virtual_advance( lbr, byte_count );
+    }
+}
+
+/* Truncate reduces the length of the buffer which results in a reference to */
+/* the first byte_count bytes of the buffer (or the whole buffer, whichever  */
+/* is less).                                                                 */
+/* Truncate returns the resulting length of the buffer.                      */
+
+static inline xenidc_buffer_byte_count xenidc_local_buffer_reference_truncate
+(
+    xenidc_local_buffer_reference * lbr,
+    xenidc_buffer_byte_count        byte_count
+)
+{
+    if( lbr->byte_count > byte_count )
+    {
+        lbr->byte_count = byte_count;
+    }
+
+    return lbr->byte_count;
+}
+
+/* Subrange reduces the range of the buffer by advancing the start           */
+/* byte_offset bytes and reducing the length to the minimum of byte_count    */
+/* and the remaining length.  Subrange returns the resulting length of the   */
+/* buffer.                                                                   */
+
+static inline xenidc_buffer_byte_count xenidc_local_buffer_reference_subrange
+(
+    xenidc_local_buffer_reference * lbr,
+    xenidc_buffer_byte_count        byte_offset,
+    xenidc_buffer_byte_count        byte_count
+)
+{
+    (void)xenidc_local_buffer_reference_advance( lbr, byte_offset );
+
+    return xenidc_local_buffer_reference_truncate( lbr, byte_count );
+}
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_mapper_pool.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_mapper_pool.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,150 @@
+/*****************************************************************************/
+/* Xen inter-domain communication remote buffer reference mapper pool.       */
+/*                                                                           */
+/* TO MAP REMOTE BUFFERS INTO THE LOCAL ADDRESS SPACE.                       */
+/*                                                                           */
+/* 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 __ASM_XEN_XENIDC_RBR_MAPPER_POOL_H__
+#define __ASM_XEN_XENIDC_RBR_MAPPER_POOL_H__
+
+typedef struct xenidc_rbr_mapper_pool_struct xenidc_rbr_mapper_pool;
+
+/* xenidc_allocate_rbr_mapper_pool returns NULL if the pool cannot be        */
+/* allocated or the anti-deadlock reservation fails.                         */
+
+extern xenidc_rbr_mapper_pool * xenidc_allocate_rbr_mapper_pool
+  ( u32 anti_deadlock_page_count );
+
+extern void xenidc_free_rbr_mapper_pool( xenidc_rbr_mapper_pool * pool );
+
+typedef struct xenidc_map_rbr_request_element_struct
+  xenidc_map_rbr_request_element;
+
+struct xenidc_map_rbr_request_element_struct
+{
+    struct list_head                 link;
+    xenidc_remote_buffer_reference   rbr;
+    void                           * mapping;
+};
+
+static inline void xenidc_map_rbr_request_element_init
+  ( xenidc_map_rbr_request_element * element )
+{
+    memset( element, 0, sizeof( *element ) );
+
+    INIT_LIST_HEAD( &element->link );
+}
+
+static inline void xenidc_map_rbr_request_element_set_rbr
+(
+    xenidc_map_rbr_request_element * element,
+    xenidc_remote_buffer_reference   rbr
+)
+{
+    element->rbr = rbr;
+}
+
+static inline void xenidc_map_rbr_request_element_ensure_removed
+  ( xenidc_map_rbr_request_element * element )
+{
+    list_del_init( &element->link );
+}
+
+typedef struct xenidc_reserve_and_map_rbr_request_struct
+  xenidc_reserve_and_map_rbr_request;
+
+struct xenidc_reserve_and_map_rbr_request_struct
+{
+    xenidc_callback  map_callback;
+    xenidc_callback  unmap_callback;
+    struct list_head request_elements;
+};
+
+static inline xenidc_callback *
+  xenidc_reserve_and_map_rbr_request_to_map_callback
+    ( xenidc_reserve_and_map_rbr_request * request )
+{
+    return &request->map_callback;
+}
+
+static inline xenidc_reserve_and_map_rbr_request *
+  xenidc_reserve_and_map_rbr_request_map_callback_to
+    ( xenidc_callback * callback )
+{
+    return container_of
+      ( callback, xenidc_reserve_and_map_rbr_request, map_callback );
+}
+
+static inline xenidc_callback *
+  xenidc_reserve_and_map_rbr_request_to_unmap_callback
+    ( xenidc_reserve_and_map_rbr_request * request )
+{
+    return &request->unmap_callback;
+}
+
+static inline xenidc_reserve_and_map_rbr_request *
+  xenidc_reserve_and_map_rbr_request_unmap_callback_to
+    ( xenidc_callback * callback )
+{
+    return container_of
+      ( callback, xenidc_reserve_and_map_rbr_request, unmap_callback );
+}
+
+static inline void xenidc_reserve_and_map_rbr_request_init
+(
+    xenidc_reserve_and_map_rbr_request * request,
+    xenidc_callback_function           * map_callback,
+    xenidc_callback_function           * unmap_callback
+)
+{
+    xenidc_callback_init( &request->map_callback, map_callback );
+    xenidc_callback_init( &request->unmap_callback, unmap_callback );
+
+    INIT_LIST_HEAD( &request->request_elements );
+}
+
+static inline void xenidc_reserve_and_map_rbr_request_add_element
+(
+    xenidc_reserve_and_map_rbr_request * request,
+    xenidc_map_rbr_request_element     * element
+)
+{
+    list_add( &element->link, &request->request_elements );
+}
+
+extern void xenidc_rbr_mapper_pool_reserve_and_map_rbrs
+(
+    xenidc_rbr_mapper_pool             * pool,
+    xenidc_reserve_and_map_rbr_request * request
+);
+
+extern void xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs
+(
+    xenidc_rbr_mapper_pool             * pool,
+    xenidc_reserve_and_map_rbr_request * request
+);
+
+extern void xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs
+(
+    xenidc_rbr_mapper_pool             * pool,
+    xenidc_reserve_and_map_rbr_request * request
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_provider_pool.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_provider_pool.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,160 @@
+/*****************************************************************************/
+/* Xen inter-domain communication remote buffer reference provider pool.     */
+/*                                                                           */
+/* TO CREATE REMOTE BUFFER REFERENCES TO GRANT OTHER DOMAINS ACCESS TO LOCAL */
+/* BUFFERS.                                                                  */
+/*                                                                           */
+/* 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 __ASM_XEN_XENIDC_RBR_PROVIDER_POOL_H__
+#define __ASM_XEN_XENIDC_RBR_PROVIDER_POOL_H__
+
+#include "xenidc_remote_buffer_reference.h"
+
+typedef struct xenidc_rbr_provider_pool_struct xenidc_rbr_provider_pool;
+
+/* xenidc_allocate_rbr_provider_pool returns NULL if the pool cannot be      */
+/* allocated or the anti-deadlock reservation fails.                         */
+
+extern xenidc_rbr_provider_pool * xenidc_allocate_rbr_provider_pool
+  ( u32 anti_deadlock_page_count );
+
+extern void xenidc_free_rbr_provider_pool( xenidc_rbr_provider_pool * pool );
+
+typedef struct xenidc_create_rbr_request_element_struct
+  xenidc_create_rbr_request_element;
+
+struct xenidc_create_rbr_request_element_struct
+{
+    struct list_head               link;
+    xenidc_local_buffer_reference  lbr;
+    xenidc_remote_buffer_reference rbr;
+};
+
+static inline void xenidc_create_rbr_request_element_init
+  ( xenidc_create_rbr_request_element * element )
+{
+    memset( element, 0, sizeof( *element ) );
+
+    INIT_LIST_HEAD( &element->link );
+}
+
+static inline void xenidc_create_rbr_request_element_set_lbr
+(
+    xenidc_create_rbr_request_element * element,
+    xenidc_local_buffer_reference       lbr
+)
+{
+    element->lbr = lbr;
+}
+
+static inline xenidc_remote_buffer_reference
+  xenidc_create_rbr_request_element_query_rbr
+    ( xenidc_create_rbr_request_element * element )
+{
+    return element->rbr;
+}
+
+static inline void xenidc_create_rbr_request_element_ensure_removed
+  ( xenidc_create_rbr_request_element * element )
+{
+    list_del_init( &element->link );
+}
+
+typedef struct xenidc_reserve_and_create_rbr_request_struct
+  xenidc_reserve_and_create_rbr_request;
+
+struct xenidc_reserve_and_create_rbr_request_struct
+{
+    xenidc_callback  create_callback;
+    xenidc_callback  revoke_callback;
+    struct list_head request_elements;
+};
+
+static inline xenidc_callback *
+  xenidc_reserve_and_create_rbr_request_to_create_callback
+    ( xenidc_reserve_and_create_rbr_request * request )
+{
+    return &request->create_callback;
+}
+
+static inline xenidc_reserve_and_create_rbr_request *
+  xenidc_reserve_and_create_rbr_request_create_callback_to
+    ( xenidc_callback * callback )
+{
+    return container_of
+      ( callback, xenidc_reserve_and_create_rbr_request, create_callback );
+}
+
+static inline xenidc_callback *
+  xenidc_reserve_and_create_rbr_request_to_revoke_callback
+    ( xenidc_reserve_and_create_rbr_request * request )
+{
+    return &request->revoke_callback;
+}
+
+static inline xenidc_reserve_and_create_rbr_request *
+  xenidc_reserve_and_create_rbr_request_revoke_callback_to
+    ( xenidc_callback * callback )
+{
+    return container_of
+      ( callback, xenidc_reserve_and_create_rbr_request, revoke_callback );
+}
+
+static inline void xenidc_reserve_and_create_rbr_request_init
+(
+    xenidc_reserve_and_create_rbr_request * request,
+    xenidc_callback_function              * create_callback,
+    xenidc_callback_function              * revoke_callback
+)
+{
+    xenidc_callback_init( &request->create_callback, create_callback );
+    xenidc_callback_init( &request->revoke_callback, revoke_callback );
+
+    INIT_LIST_HEAD( &request->request_elements );
+}
+
+static inline void xenidc_reserve_and_create_rbr_request_add_element
+(
+    xenidc_reserve_and_create_rbr_request * request,
+    xenidc_create_rbr_request_element     * element
+)
+{
+    list_add( &element->link, &request->request_elements );
+}
+
+extern void xenidc_rbr_provider_pool_reserve_and_create_rbrs
+(
+    xenidc_rbr_provider_pool              * pool,
+    xenidc_reserve_and_create_rbr_request * request
+);
+
+extern void xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs
+(
+    xenidc_rbr_provider_pool              * pool,
+    xenidc_reserve_and_create_rbr_request * request
+);
+
+extern void xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs
+(
+    xenidc_rbr_provider_pool              * pool,
+    xenidc_reserve_and_create_rbr_request * request
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_remote_buffer_reference.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_remote_buffer_reference.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,42 @@
+/*****************************************************************************/
+/* Xen inter-domain communication remote buffer references.                  */
+/*                                                                           */
+/* 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 __ASM_XEN_XENIDC_REMOTE_BUFFER_REFERENCE_H__
+#define __ASM_XEN_XENIDC_REMOTE_BUFFER_REFERENCE_H__
+
+#include "xenidc_local_buffer_reference.h"
+
+typedef struct xenidc_remote_buffer_reference_struct
+  xenidc_remote_buffer_reference;
+
+struct xenidc_remote_buffer_reference_struct
+{
+    xenidc_buffer_byte_count byte_count;
+};
+
+static inline xenidc_buffer_byte_count
+  xenidc_remote_buffer_reference_query_byte_count
+    ( xenidc_remote_buffer_reference * rbr )
+{
+    return rbr->byte_count;
+}
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_vaddress.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_vaddress.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,30 @@
+/*****************************************************************************/
+/* Support for local buffer references of type vaddress.                     */
+/*                                                                           */
+/* 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 XENIDC_VADDRESS_H
+#define XENIDC_VADDRESS_H
+
+#include "xenidc.h"
+
+extern xenidc_local_buffer_reference xenidc_vaddress_create_lbr
+  ( void * address, xenidc_buffer_byte_count byte_count );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_work.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_work.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,160 @@
+/*****************************************************************************/
+/* Enhanced work queue service                                               */
+/* 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                   */
+/*                                                                           */
+/*****************************************************************************/
+
+/* This work queue service is a lot like the linux work queue service except */
+/* that it provides the interface xenidc_work_until which allows the client  */
+/* to wait for a condition to be met even when the client is executing on a  */
+/* work thread and the condition will only be satisfied by execution of      */
+/* another work item.                                                        */
+
+#ifndef XENIDC_WORK_H
+#define XENIDC_WORK_H
+
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+typedef struct xenidc_work_struct xenidc_work;
+
+struct xenidc_work_struct
+{
+    struct list_head link;
+    void ( * function )( void * context );
+    void   * context;
+};
+
+#define XENIDC_WORK_LINK link
+
+#define XENIDC_WORK_INIT( name, fn, ctx ) \
+{ LIST_HEAD_INIT( name.link ), fn, ctx }
+
+#define XENIDC_WORK( name, fn, ctx ) \
+xenidc_work name = XENIDC_WORK_INIT( name, fn, ctx )
+
+static inline void xenidc_work_init
+(
+    xenidc_work   * work,
+    void                ( * function )( void * context ),
+    void                  * context
+)
+{
+    INIT_LIST_HEAD( &work->link );
+
+    work->function = function;
+    work->context  = context;
+}
+
+static inline struct list_head * xenidc_work_to_link( xenidc_work * work )
+{
+    return &work->link;
+}
+
+static inline xenidc_work * xenidc_work_link_to( struct list_head * link )
+{
+    return container_of( link, xenidc_work, link );
+}
+
+/* Returns 1 if scheduled this time or 0 if already scheduled. */
+
+int xenidc_work_schedule( xenidc_work * work );
+
+static inline void xenidc_work_perform_synchronously( xenidc_work * work )
+{
+    work->function( work->context );
+}
+
+/* Don't use any of these, they're just exposed for the macro below. */
+
+extern spinlock_t xenidc_work_list_lock;
+
+extern struct list_head xenidc_work_list;
+
+extern wait_queue_head_t xenidc_work_waitqueue;
+
+extern struct list_head xenidc_work_condition;
+
+/* Wait for a condition to be met. This works whether or not you call it     */
+/* from a work item and works even when the condition will only be satisfied */
+/* by another work item.                                                     */
+
+#define xenidc_work_until( condition )                                  \
+do                                                                      \
+{                                                                       \
+    unsigned long flags;                                                \
+                                                                        \
+    spin_lock_irqsave( &xenidc_work_list_lock, flags );                 \
+                                                                        \
+    for( ; ; )                                                          \
+    {                                                                   \
+        while                                                           \
+        (                                                               \
+            ( !list_empty( &xenidc_work_list ) )                        \
+            &&                                                          \
+            ( !( condition ) )                                          \
+        )                                                               \
+        {                                                               \
+            xenidc_work * work = list_entry                             \
+            (                                                           \
+                xenidc_work_list.next,                                  \
+                xenidc_work,                                            \
+                link                                                    \
+            );                                                          \
+                                                                        \
+            list_del_init( &work->link );                               \
+                                                                        \
+            spin_unlock_irqrestore( &xenidc_work_list_lock, flags );    \
+                                                                        \
+            xenidc_work_perform_synchronously( work );                  \
+                                                                        \
+            spin_lock_irqsave( &xenidc_work_list_lock, flags );         \
+        }                                                               \
+                                                                        \
+        if( condition )                                                 \
+        {                                                               \
+            break;                                                      \
+        }                                                               \
+                                                                        \
+        {                                                               \
+            struct list_head link;                                      \
+                                                                        \
+            INIT_LIST_HEAD( &link );                                    \
+                                                                        \
+            list_add_tail( &link, &xenidc_work_condition );             \
+                                                                        \
+            spin_unlock_irqrestore( &xenidc_work_list_lock, flags );    \
+                                                                        \
+            wait_event( xenidc_work_waitqueue, list_empty( &link ) );   \
+                                                                        \
+            spin_lock_irqsave( &xenidc_work_list_lock, flags );         \
+        }                                                               \
+    }                                                                   \
+                                                                        \
+    spin_unlock_irqrestore( &xenidc_work_list_lock, flags );            \
+}                                                                       \
+while( 0 )
+
+/* When you satisfy a condition, you should call this to kick any threads    */
+/* waiting on the condition.                                                 */
+
+void xenidc_work_wake_up( void );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_wrapping.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_wrapping.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,48 @@
+/*****************************************************************************/
+/* Support for wrapping buffer local buffer references                       */
+/*                                                                           */
+/* 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 XENIDC_WRAPPING_H
+#define XENIDC_WRAPPING_H
+
+#include "xenidc.h"
+
+typedef enum
+{
+    xenidc_wrapping_client_type_producer,
+    xenidc_wrapping_client_type_consumer
+}
+xenidc_wrapping_client_type;
+
+/* Create a reference to a wrapping buffer. Pass the start offset and the    */
+/* end offset of the section of interest of the wrapping buffer. If the      */
+/* start and end offsets are the same then a producer will get a reference   */
+/* to the whole buffer to fill whereas a consumer will get a reference to a  */
+/* zero length buffer.                                                       */
+
+extern xenidc_local_buffer_reference xenidc_wrapping_create_lbr
+(
+    xenidc_local_buffer_reference * underlying_buffer,
+    xenidc_buffer_byte_count        start_offset,
+    xenidc_buffer_byte_count        end_offset,
+    xenidc_wrapping_client_type     client_type
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_xbgt_channel.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_xbgt_channel.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,142 @@
+/*****************************************************************************/
+/* This is a class which uses a xenidc_gnttab_channel (grant-tables based    */
+/* message channel class) and xenbus to implement an interdomain message     */
+/* channel with grant-tables based message transfer and xenbus based         */
+/* bring-up and tear-down handshaking.                                       */
+/* This class is used in the implementation of the xenidc_endpoint class.    */
+/*                                                                           */
+/* 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 _XENIDC_XBGT_CHANNEL_H
+#define _XENIDC_XBGT_CHANNEL_H
+
+#include <asm-xen/xenbus.h>
+#include <asm-xen/xenidc_gnttab_channel.h>
+
+typedef struct xenidc_xbgt_channel_struct xenidc_xbgt_channel;
+
+typedef enum
+{
+    xenidc_xbgt_channel_state_i,
+    xenidc_xbgt_channel_state_i_cn,
+    xenidc_xbgt_channel_state_i_cn_dn,
+    xenidc_xbgt_channel_state_i_cn_rs,
+    xenidc_xbgt_channel_state_i_cn_dn_rs,
+    xenidc_xbgt_channel_state_i_cn_rs_dn,
+    xenidc_xbgt_channel_state_i_cn_rs_rs,
+    xenidc_xbgt_channel_state_i_cn_rs_rf,
+    xenidc_xbgt_channel_state_i_cn_dn_rs_rs,
+    xenidc_xbgt_channel_state_i_cn_rs_dn_rs,
+    xenidc_xbgt_channel_state_i_cn_rs_rs_dn,
+    xenidc_xbgt_channel_state_i_cn_rs_rs_rs,
+    xenidc_xbgt_channel_state_i_cn_rs_rs_rf,
+    xenidc_xbgt_channel_state_i_cn_rs_rf_rs,
+    xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od,
+    xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs,
+    xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs,
+    xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or,
+    xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs,
+    xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc,
+    xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe,
+    xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn,
+    xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs
+}
+xenidc_xbgt_channel_state;
+
+typedef enum
+{
+    xenidc_xbgt_channel_other_state_unknown,
+    xenidc_xbgt_channel_other_state_disconnected,
+    xenidc_xbgt_channel_other_state_ready,
+    xenidc_xbgt_channel_other_state_connected
+}
+xenidc_xbgt_channel_other_state;
+
+struct xenidc_xbgt_channel_struct
+{
+    xenidc_gnttab_channel channel;
+
+    struct xenbus_watch watch;
+
+    spinlock_t lock;
+
+    xenidc_xbgt_channel_state       state;
+    xenidc_xbgt_channel_other_state other_state;
+
+    char    * local_path;
+    char    * remote_path;
+    domid_t   remote_domain_id;
+
+    xenidc_callback * disconnect_callback;
+
+    int ready_ring_reference;
+    int ready_event_channel;
+
+    xenidc_work register_watch_1_work;
+    xenidc_work unregister_watch_1_work;
+    xenidc_work clear_store_1_work;
+    xenidc_work write_ready_1_work;
+    xenidc_work write_connected_1_work;
+    xenidc_work phase_one_connect_1_work;
+    xenidc_work phase_two_connect_1_work;
+    xenidc_work phase_two_disconnect_1_work;
+    xenidc_work phase_one_disconnect_1_work;
+
+    xenidc_gnttab_channel_phase_one_connect_request phase_one_connect_request;
+    xenidc_gnttab_channel_phase_two_connect_request phase_two_connect_request;
+
+    xenidc_callback phase_two_disconnect_callback;
+    xenidc_callback phase_one_disconnect_callback;
+};
+
+static inline xenidc_channel * xenidc_xbgt_channel_to_channel
+  ( xenidc_xbgt_channel * channel )
+{
+    return xenidc_gnttab_channel_to_channel( &channel->channel );
+}
+
+static inline xenidc_xbgt_channel * xenidc_xbgt_channel_gnttab_channel_to
+  ( xenidc_gnttab_channel * gnttab_channel )
+{
+    return container_of( gnttab_channel, xenidc_xbgt_channel, channel );
+}
+
+static inline xenidc_xbgt_channel * xenidc_xbgt_channel_channel_to
+  ( xenidc_channel * channel )
+{
+    return xenidc_xbgt_channel_gnttab_channel_to
+      ( xenidc_gnttab_channel_channel_to( channel ) );
+}
+
+extern int xenidc_xbgt_channel_init( xenidc_xbgt_channel * channel );
+
+extern void xenidc_xbgt_channel_connect
+(
+    xenidc_xbgt_channel * channel,
+    char                * local_path,
+    char                * remote_path,
+    domid_t               remote_domain_id
+);
+
+extern void xenidc_xbgt_channel_disconnect
+  ( xenidc_xbgt_channel * channel, xenidc_callback * callback );
+
+extern void xenidc_xbgt_channel_exit( xenidc_xbgt_channel * channel );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 patches/linux-2.6.12/usb.patch
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/patches/linux-2.6.12/usb.patch	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,10 @@
+diff -Naur linux-2.6.12/drivers/usb/core/usb.c linux-2.6.12-usb/drivers/usb/core/usb.c
+--- linux-2.6.12/drivers/usb/core/usb.c	2005-06-17 20:48:29.000000000 +0100
++++ linux-2.6.12-usb/drivers/usb/core/usb.c	2005-09-28 13:01:29.000000000 +0100
+@@ -1561,4 +1561,6 @@
+ #endif
+ EXPORT_SYMBOL (usb_buffer_unmap_sg);
+ 
++EXPORT_SYMBOL (usb_bus_type);
++
+ MODULE_LICENSE("GPL");
diff -r b5903c9aeda5 -r e93b9c54edb3 xen/include/public/io/usbif.h
--- /dev/null	Sun Oct 30 09:45:49 2005
+++ b/xen/include/public/io/usbif.h	Sun Oct 30 16:03:34 2005
@@ -0,0 +1,357 @@
+/*****************************************************************************/
+/* FE->BE transactions for the USB split driver interface.                   */
+/*                                                                           */
+/* 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 __SHARED_USBIF_H__
+#define __SHARED_USBIF_H__
+
+#include <asm-xen/xenidc.h>
+
+/* USBIF_MAX_PAGES_PER_REQUEST is the maximum number of pages a request is   */
+/* allowed to require to construct the mapping in the back-end.              */
+
+#define USBIF_MAX_PAGES_PER_REQUEST 128
+
+/* All transactions have the same header which specifies the type of the     */
+/* transaction.                                                              */
+
+typedef struct usbif_transaction_parameters_header_struct
+  usbif_transaction_parameters_header;
+
+struct usbif_transaction_parameters_header_struct
+{
+    u8 transaction_type;
+    u8 reserved[ 7 ];
+};
+
+/* There are three types of transaction: */
+
+#define USBIF_TRANSACTION_TYPE_PROBE 0
+#define USBIF_TRANSACTION_TYPE_RESET 1
+#define USBIF_TRANSACTION_TYPE_IO    2
+
+/* The probe transaction is used to test whether a USB device is connected   */
+/* to a port.                                                                */
+/* Port numbers start at 1.                                                  */
+
+typedef struct usbif_probe_transaction_parameters_struct
+  usbif_probe_transaction_parameters;
+
+struct usbif_probe_transaction_parameters_struct
+{
+    usbif_transaction_parameters_header header;
+    u32                                 port;
+    u8                                  reserved[ 4 ];
+};
+
+typedef struct usbif_probe_transaction_status_struct
+  usbif_probe_transaction_status;
+
+struct usbif_probe_transaction_status_struct
+{
+    u8 result;
+    u8 reserved[ 7 ];
+};
+
+#define USBIF_PROBE_RESULT_NO_DEVICE      0
+#define USBIF_PROBE_RESULT_DEVICE_PRESENT 1
+
+/* The reset transaction is used to reset a port. On success, the speed the  */
+/* port is operating at after the reset is returned.                         */
+
+typedef struct usbif_reset_transaction_parameters_struct
+  usbif_reset_transaction_parameters;
+
+struct usbif_reset_transaction_parameters_struct
+{
+    usbif_transaction_parameters_header header;
+    u32                                 port;
+    u8                                  reserved[ 4 ];
+};
+
+/* On success, the reset returns status... */
+
+typedef struct usbif_reset_transaction_status_struct
+  usbif_reset_transaction_status;
+
+struct usbif_reset_transaction_status_struct
+{
+    u8 result;
+    u8 reserved[ 7 ];
+};
+
+#define USBIF_RESET_RESULT_FULL_SPEED 0
+#define USBIF_RESET_RESULT_LOW_SPEED  1
+#define USBIF_RESET_RESULT_HIGH_SPEED 2
+
+/* Aside from the usual transport errors, the reset transaction might fail   */
+/* if there is no device.                                                    */
+
+/* All IO transactions have a header which specifies the type of IO          */
+/* transaction and contains parameters common to all types of IO transaction.*/
+
+typedef struct usbif_io_transaction_parameters_header_struct
+  usbif_io_transaction_parameters_header;
+
+struct usbif_io_transaction_parameters_header_struct
+{
+    usbif_transaction_parameters_header header;
+    u8                                  io_transaction_type;
+    u8                                  device_number;
+    u8                                  endpoint;
+    u8                                  direction;
+    u32                                 unlink_id;
+    u32                                 flags;
+    u32                                 reserved;
+    xenidc_remote_buffer_reference      rbr;
+};
+
+#define USBIF_IO_TRANSACTION_TYPE_CONTROL     0
+#define USBIF_IO_TRANSACTION_TYPE_BULK        1
+#define USBIF_IO_TRANSACTION_TYPE_INTERRUPT   2
+#define USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS 3
+/* Not a transaction type. For array bounds: */
+#define USBIF_IO_TRANSACTION_TYPE_LIMIT 4
+
+#define USBIF_IO_TRANSACTION_DIRECTION_OUT 0
+#define USBIF_IO_TRANSACTION_DIRECTION_IN  1
+
+#define USBIF_IO_FLAGS_SHORT_NOT_OK 0x00000001
+#define USBIF_IO_FLAGS_ZERO_PACKET  0x00000002
+
+typedef struct usbif_control_io_transaction_parameters_struct
+  usbif_control_io_transaction_parameters;
+
+struct usbif_control_io_transaction_parameters_struct
+{
+    usbif_io_transaction_parameters_header header;
+    u8                                     setup[ 8 ];
+};
+
+typedef struct usbif_bulk_io_transaction_parameters_struct
+  usbif_bulk_io_transaction_parameters;
+
+struct usbif_bulk_io_transaction_parameters_struct
+{
+    usbif_io_transaction_parameters_header header;
+};
+
+typedef struct usbif_interrupt_io_transaction_parameters_struct
+  usbif_interrupt_io_transaction_parameters;
+
+struct usbif_interrupt_io_transaction_parameters_struct
+{
+    usbif_io_transaction_parameters_header header;
+    u32                                    interval;
+};
+
+typedef struct usbif_isochronous_io_transaction_parameters_struct
+  usbif_isochronous_io_transaction_parameters;
+
+struct usbif_isochronous_io_transaction_parameters_struct
+{
+    usbif_io_transaction_parameters_header header;
+    u32                                    interval;
+    xenidc_remote_buffer_reference         schedule_rbr;
+    u32                                    packet_count;
+};
+
+typedef struct usbif_isochronous_io_schedule_element_struct
+  usbif_isochronous_io_schedule_element;
+
+struct usbif_isochronous_io_schedule_element_struct
+{
+    xenidc_buffer_byte_count offset; /* IN offset into header's rbr */
+    xenidc_buffer_byte_count length; /* IN = expected, OUT = actual */
+    xenidc_error             error;  /* OUT for this packet. */
+};
+
+typedef struct usbif_io_transaction_status_struct
+  usbif_io_transaction_status;
+
+struct usbif_io_transaction_status_struct
+{
+    xenidc_buffer_byte_count length;
+};
+
+/* USBIF specific transaction error codes: */
+
+#define USBIF_XENIDC_ERROR_FAILURE  \
+  ( XENIDC_ERROR_PROTOCOL_SPECIFIC_FIRST + 0 )
+#define USBIF_XENIDC_ERROR_NO_DEVICE \
+  ( XENIDC_ERROR_PROTOCOL_SPECIFIC_FIRST + 1 )
+#define USBIF_XENIDC_ERROR_UNLINKED \
+  ( XENIDC_ERROR_PROTOCOL_SPECIFIC_FIRST + 2 )
+
+static inline xenidc_error usbif_error_map_local_to( int error )
+{
+    switch( error )
+    {
+      /* FIXME: handle USB specific error codes. */
+      default:
+        return xenidc_error_map_local_to( error );
+    }
+}
+
+static inline int usbif_error_map_to_local( xenidc_error error )
+{
+    switch( error )
+    {
+      /* FIXME: handle USB specific error codes. */
+      default:
+        return xenidc_error_map_to_local( error );
+    }
+}
+
+/* Lookup table for sizes of io parameters structures. */
+
+static const xenidc_buffer_byte_count usbif_io_parameters_byte_count
+  [ USBIF_IO_TRANSACTION_TYPE_LIMIT ] =
+{
+    [ USBIF_IO_TRANSACTION_TYPE_CONTROL ] =
+      sizeof( usbif_control_io_transaction_parameters ),
+    [ USBIF_IO_TRANSACTION_TYPE_BULK ] =
+      sizeof( usbif_bulk_io_transaction_parameters ),
+    [ USBIF_IO_TRANSACTION_TYPE_INTERRUPT ] =
+      sizeof( usbif_interrupt_io_transaction_parameters ),
+    [ USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS ] =
+      sizeof( usbif_isochronous_io_transaction_parameters )
+};
+
+typedef union
+{
+    usbif_io_transaction_parameters_header      header;
+    usbif_control_io_transaction_parameters     control;
+    usbif_bulk_io_transaction_parameters        bulk;
+    usbif_interrupt_io_transaction_parameters   interrupt;
+    usbif_isochronous_io_transaction_parameters isochronous;
+}
+usbif_io_transaction_parameters;
+
+typedef union usbif_max_transaction_union usbif_max_transaction;
+
+union usbif_max_transaction_union
+{
+    struct
+    {
+        usbif_probe_transaction_parameters parameters;
+        usbif_probe_transaction_status     status;
+    } probe;
+    struct
+    {
+        usbif_reset_transaction_parameters parameters;
+        usbif_reset_transaction_status     status;
+    } reset;
+    struct
+    {
+        usbif_control_io_transaction_parameters parameters;
+        usbif_io_transaction_status             status;
+    } control_io;
+    struct
+    {
+        usbif_bulk_io_transaction_parameters parameters;
+        usbif_io_transaction_status          status;
+    } bulk_io;
+    struct
+    {
+        usbif_interrupt_io_transaction_parameters parameters;
+        usbif_io_transaction_status               status;
+    } interrupt_io;
+    struct
+    {
+        usbif_isochronous_io_transaction_parameters parameters;
+        usbif_io_transaction_status                 status;
+    } isochronous_io;
+};
+
+/* All messages have the same header which specifies the type of the         */
+/* message.                                                                  */
+
+typedef struct usbif_message_header_struct usbif_message_header;
+
+struct usbif_message_header_struct
+{
+    u8 message_type;
+    u8 reserved[ 7 ];
+};
+
+/* There is only one type of message:                                        */
+
+#define USBIF_MESSAGE_TYPE_UNLINK 0
+
+/* The unlink message is sent to unlink an IO operation.  The backend will   */
+/* ensure it completes or is failed out as quickly as possible.              */
+/* This is a send and forget message: the client should wait for the         */
+/* completion of the IO transaction as normal.                               */
+
+typedef struct usbif_unlink_message_body_struct usbif_unlink_message_body;
+
+struct usbif_unlink_message_body_struct
+{
+    usbif_message_header header;
+    u32                  unlink_id;
+    u32                  reserved;
+};
+
+typedef union usbif_max_message_union usbif_max_message;
+
+union usbif_max_message_union
+{
+    usbif_unlink_message_body unlink;
+};
+
+typedef union usbif_max_transaction_or_message_union
+  usbif_max_transaction_or_message;
+
+union usbif_max_transaction_or_message_union
+{
+    usbif_max_transaction transaction;
+    usbif_max_message     message;
+};
+
+#define USBIF_BE_INITIATOR_QUOTA 0
+#define USBIF_BE_INITIATOR_MAXIMUM_BYTE_COUNT 0
+
+#define USBIF_BE_TARGET_QUOTA 32
+#define USBIF_BE_TARGET_MAXIMUM_BYTE_COUNT \
+( sizeof( usbif_max_transaction_or_message ) )
+
+#define USBIF_FE_INITIATOR_QUOTA USBIF_BE_TARGET_QUOTA
+#define USBIF_FE_INITIATOR_MAXIMUM_BYTE_COUNT \
+USBIF_BE_TARGET_MAXIMUM_BYTE_COUNT
+
+#define USBIF_FE_TARGET_QUOTA USBIF_BE_INITIATOR_QUOTA
+#define USBIF_FE_TARGET_MAXIMUM_BYTE_COUNT \
+USBIF_BE_INITIATOR_MAXIMUM_BYTE_COUNT
+
+#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] 10+ messages in thread

* Re: USB virt status
       [not found]     ` <200511050050.58120.mark.williamson@cl.cam.ac.uk>
@ 2005-11-05  2:21       ` Harry Butterworth
  2005-11-05  4:08         ` Nivedita Singhvi
  2005-11-05 12:32         ` Mark Williamson
  0 siblings, 2 replies; 10+ messages in thread
From: Harry Butterworth @ 2005-11-05  2:21 UTC (permalink / raw)
  To: Mark Williamson; +Cc: xen-devel

On Sat, 2005-11-05 at 00:50 +0000, Mark Williamson wrote:
> > Most of the difficulty is in working with xenstore, which is deeply
> > inconvenient as a tool for sequencing dependent operations.  That's what
> > resulted in the state machine I posted to the list as a ps file.  You
> > could probably hack this state machine into the existing drivers with
> > only a small amount of additional code but it will just make the drivers
> > even more ugly and incomprehensible than they are already.
> 
> Yes, right now I'm working with Xenstore too.  The updates I mentioned are 
> supposed to tackle this problem by providing a better API, automating the 
> channel setup state machine for the majority of users (i.e. all devices).  I 
> believe a some of this code is fully completed and awaiting push to the main 
> tree once it's been reviewed by a few people.

Really? I haven't seen any discussion about this on the list.  Or any
patches for review for that matter.  Another private Cambridge clique?

> 
> > The main reason for me to write the API was to have something concrete
> > to code the USB driver against whilst the Xen infrastructure was in
> > flux---previously the two changes to xend and the change to grant-tables
> > had caused me a huge amount of rework.  The API allowed me to complete
> > the driver whilst the infrastructure was stabilising.
> 
> Surely you still had to update the code just as often?  I guess having it 
> separated would at least ease the update burden.  I've rewritten my code 
> several times for the control plane also; it's tough working out-of-tree for 
> long periods based on the unstable tree.

No, after I stopped trying to sync up with the xenbus-of-the-week API I
just defined the API I wanted, coded my driver to it and it's only been
in the last few weeks that I've been implementing the API.  Thankfully
the xenbus and grant-table interfaces haven't changed enough to
completely break me since then. And, yes, you'll find it is much easier
to update the code when it isn't all munged together in one big lump.

> 
> > Rather than remove the xenidc stuff, I think it would be much more
> > useful to pick up the xenidc code for general use, base all new drivers
> > on it and eventually port the block and net drivers to it.  This would
> > allow you to change the infrastructure underneath all new drivers
> > relatively easily and I would expect it to save you a significant amount
> > of effort when implementing new drivers, when optimizing the code and,
> > in the future, if you extend the system over the network or do any fancy
> > page sharing.
> 
> I really would have liked to see a more abstract interface to communications, 
> such as the one you propose.  However, it is not going to happen for the 3.0 
> release and that's when the team promised the interfaces will be frozen.  If 
> it can't be compatible with the existing interfaces, that's going to make it 
> much less likely that anyone will update the existing drivers and then 
> maintain two separate interdomain interfaces for each.
> 
> I think the project is likely to follow the path of least resistance and go 
> with a "xenstore connection setup library" that replaces most of the 
> duplicate code but retain the old datapath API.  I get the impression this 
> decision has been taken already.

This doesn't seem to have been discussed on the list either.

> > When I've got the code up and working and have split the patch up into a
> > series of manageable chunks you should judge it on technical merit.  I
> > would expect that peer review will find ways to improve the
> > implementation and perhaps make it fit better with Xen but I'm confident
> > that the basic design is reasonable.
> 
> I agree, but regardless of the goals of the basic design it's going to be 
> harder to get a merge for a driver that implements its own complex 
> abstraction layer than for one which uses the Xen APIs directly.  I'd like to 
> have a nicer driver API but if that isn't accepted then we're probably better 
> with the drivers as small as possible.
> 
> It's an unfortunate situation; what you propose is a nice way of doing things 
> but doesn't appear to be gaining much traction yet.  If the USB driver is 
> going to be predicated on it I'd suggest having a clear plan about how you're 
> going to get the generic IDC code into the main tree - I'm not sure whether 
> rolling it in with the USB driver itself will be accepted.

Current plan: write good quality generic code which is reusable and
useful to other drivers.  Document and break patch down into manageable
chunks.  Get in to the tree on technical merit.

In any case, I can always change the implementation of the xenidc code
to base it on whatever API you provide.  This is what it was designed
for. So at least I won't have to rewrite the driver again.

> 
> Cheers,
> Mark
> 
-- 
Harry Butterworth <harry@hebutterworth.freeserve.co.uk>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Re: USB virt status
  2005-11-05  2:21       ` Harry Butterworth
@ 2005-11-05  4:08         ` Nivedita Singhvi
  2005-11-05 10:32           ` Keir Fraser
  2005-11-05 13:06           ` Mark Williamson
  2005-11-05 12:32         ` Mark Williamson
  1 sibling, 2 replies; 10+ messages in thread
From: Nivedita Singhvi @ 2005-11-05  4:08 UTC (permalink / raw)
  To: Harry Butterworth; +Cc: xen-devel, Mark Williamson

Harry Butterworth wrote:
> On Sat, 2005-11-05 at 00:50 +0000, Mark Williamson wrote:

>>Yes, right now I'm working with Xenstore too.  The updates I mentioned are 
>>supposed to tackle this problem by providing a better API, automating the 
>>channel setup state machine for the majority of users (i.e. all devices).  I 
>>believe a some of this code is fully completed and awaiting push to the main 
>>tree once it's been reviewed by a few people.

Hi Mark,

I didn't see the original email that Harry quoted, but could
you elaborate on that? Are you proposing a new API? Why only
a few people? Any reason not on the list?

Rusty had asked a question regarding what's in 3.0:
http://marc.theaimsgroup.com/?l=xen-devel&m=113038760216447&w=2

and I guess I'll second that..


>>I really would have liked to see a more abstract interface to communications, 
>>such as the one you propose.  However, it is not going to happen for the 3.0 
>>release and that's when the team promised the interfaces will be frozen.  If 
>>it can't be compatible with the existing interfaces, that's going to make it 
>>much less likely that anyone will update the existing drivers and then 
>>maintain two separate interdomain interfaces for each.
>>
>>I think the project is likely to follow the path of least resistance and go 
>>with a "xenstore connection setup library" that replaces most of the 
>>duplicate code but retain the old datapath API.  I get the impression this 
>>decision has been taken already.

Any reason for this to not be shared on xen-devel?

thanks,
Nivedita

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Re: USB virt status
  2005-11-05  4:08         ` Nivedita Singhvi
@ 2005-11-05 10:32           ` Keir Fraser
  2005-11-05 11:30             ` Harry Butterworth
  2005-11-05 18:00             ` Nivedita Singhvi
  2005-11-05 13:06           ` Mark Williamson
  1 sibling, 2 replies; 10+ messages in thread
From: Keir Fraser @ 2005-11-05 10:32 UTC (permalink / raw)
  To: Nivedita Singhvi; +Cc: Harry Butterworth, Mark Williamson, xen-devel


On 5 Nov 2005, at 04:08, Nivedita Singhvi wrote:

>>> I really would have liked to see a more abstract interface to 
>>> communications, such as the one you propose.  However, it is not 
>>> going to happen for the 3.0 release and that's when the team 
>>> promised the interfaces will be frozen.  If it can't be compatible 
>>> with the existing interfaces, that's going to make it much less 
>>> likely that anyone will update the existing drivers and then 
>>> maintain two separate interdomain interfaces for each.
>>>
>>> I think the project is likely to follow the path of least resistance 
>>> and go with a "xenstore connection setup library" that replaces most 
>>> of the duplicate code but retain the old datapath API.  I get the 
>>> impression this decision has been taken already.
>
> Any reason for this to not be shared on xen-devel?

All that's being done is the simplest possible bug fixing and 
refactoring to get stable drivers for a 3.0.0 release asap. xenidc is 
possibly a suitable alternative for future releases, after we have had 
time to look at it, integrate it with all the split drivers, and fix 
bug fallout. Given the size and complexity of the patch, I think it 
would be very high risk to commit to doing that in the next couple of 
weeks.

  -- Keir

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Re: USB virt status
  2005-11-05 10:32           ` Keir Fraser
@ 2005-11-05 11:30             ` Harry Butterworth
  2005-11-05 18:00             ` Nivedita Singhvi
  1 sibling, 0 replies; 10+ messages in thread
From: Harry Butterworth @ 2005-11-05 11:30 UTC (permalink / raw)
  To: Keir Fraser; +Cc: Nivedita Singhvi, xen-devel, Mark Williamson

On Sat, 2005-11-05 at 10:32 +0000, Keir Fraser wrote:

> All that's being done is the simplest possible bug fixing and 
> refactoring to get stable drivers for a 3.0.0 release asap. xenidc is 
> possibly a suitable alternative for future releases, after we have had 
> time to look at it, integrate it with all the split drivers, and fix 
> bug fallout. Given the size and complexity of the patch, I think it 
> would be very high risk to commit to doing that in the next couple of 
> weeks.

Good. This seems entirely reasonable to me.

So I'll release the USB driver against xenidc as an example and document
and break down the xenidc patch (and run it through a reformatter) so it
can be reviewed.

If you like xenidc you can keep it, if not I can factor out the code
later.  Easy come, easy go :-)

> 
>   -- Keir
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xensource.com
> http://lists.xensource.com/xen-devel
> 
-- 
Harry Butterworth <harry@hebutterworth.freeserve.co.uk>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: USB virt status
  2005-11-05  2:21       ` Harry Butterworth
  2005-11-05  4:08         ` Nivedita Singhvi
@ 2005-11-05 12:32         ` Mark Williamson
  1 sibling, 0 replies; 10+ messages in thread
From: Mark Williamson @ 2005-11-05 12:32 UTC (permalink / raw)
  To: Harry Butterworth; +Cc: xen-devel

> > Yes, right now I'm working with Xenstore too.  The updates I mentioned
> > are supposed to tackle this problem by providing a better API, automating
> > the channel setup state machine for the majority of users (i.e. all
> > devices).  I believe a some of this code is fully completed and awaiting
> > push to the main tree once it's been reviewed by a few people.
>
> Really? I haven't seen any discussion about this on the list.  Or any
> patches for review for that matter.  Another private Cambridge clique?

I believe I mentioned it to you in a previous e-mail.  But no, it hasn't been 
on the public list; I found out about it by chance and was trying to keep you 
informed.  It's not my place to publically announce other people's work 
unless it's relevant to an on-list discussion.  That said, it does seem like 
a logical next step to progress to.

> No, after I stopped trying to sync up with the xenbus-of-the-week API I
> just defined the API I wanted, coded my driver to it and it's only been
> in the last few weeks that I've been implementing the API.  Thankfully
> the xenbus and grant-table interfaces haven't changed enough to
> completely break me since then. And, yes, you'll find it is much easier
> to update the code when it isn't all munged together in one big lump.

I separated the control code from the data code within my driver, so I just 
have to rewrite that, rather than the entire driver.

> > I think the project is likely to follow the path of least resistance and
> > go with a "xenstore connection setup library" that replaces most of the
> > duplicate code but retain the old datapath API.  I get the impression
> > this decision has been taken already.
>
> This doesn't seem to have been discussed on the list either.

It's the same thing I mentioned above...

> Current plan: write good quality generic code which is reusable and
> useful to other drivers.  Document and break patch down into manageable
> chunks.  Get in to the tree on technical merit.

I'll look forward to future patches.

Cheers,
Mark

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Re: USB virt status
  2005-11-05  4:08         ` Nivedita Singhvi
  2005-11-05 10:32           ` Keir Fraser
@ 2005-11-05 13:06           ` Mark Williamson
  1 sibling, 0 replies; 10+ messages in thread
From: Mark Williamson @ 2005-11-05 13:06 UTC (permalink / raw)
  To: xen-devel; +Cc: Nivedita Singhvi, Harry Butterworth, Ewan Mellor

> I didn't see the original email that Harry quoted, but could
> you elaborate on that? Are you proposing a new API?

My understanding is that a new Xenbus "library" has been developed that'll 
automate the state machines involved in connecting a device channel.  This'll 
hopefully eliminate some of the "cut and paste" code that's in all the 
drivers.  The data-plane code and the actual Xenstore setup protocols will 
remain the same.

I believe the code exists (at least partially) but that's all I know.  I'm 
afraid it's not my area...  Somebody else may be more qualified to comment.

> Rusty had asked a question regarding what's in 3.0:
> http://marc.theaimsgroup.com/?l=xen-devel&m=113038760216447&w=2
>
> and I guess I'll second that..

There's a TODO list on the Wiki which should give some idea.  Beyond that, 
it's hard to know exactly.  I'm not directly working on the release code this 
time round.

> >>I think the project is likely to follow the path of least resistance and
> >> go with a "xenstore connection setup library" that replaces most of the
> >> duplicate code but retain the old datapath API.  I get the impression
> >> this decision has been taken already.
>
> Any reason for this to not be shared on xen-devel?

In case there's any confusion again, this "library" is the same code referred 
to above.  I didn't post on xen-devel because it was speculative, and 
intended to be shared in private discussion with Harry.

Cheers,
Mark

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Re: USB virt status
  2005-11-05 10:32           ` Keir Fraser
  2005-11-05 11:30             ` Harry Butterworth
@ 2005-11-05 18:00             ` Nivedita Singhvi
  1 sibling, 0 replies; 10+ messages in thread
From: Nivedita Singhvi @ 2005-11-05 18:00 UTC (permalink / raw)
  To: Keir Fraser; +Cc: Harry Butterworth, Mark Williamson, xen-devel

Keir Fraser wrote:

> All that's being done is the simplest possible bug fixing and 
> refactoring to get stable drivers for a 3.0.0 release asap. xenidc is 
> possibly a suitable alternative for future releases, after we have had 
> time to look at it, integrate it with all the split drivers, and fix bug 
> fallout. Given the size and complexity of the patch, I think it would be 
> very high risk to commit to doing that in the next couple of weeks.

Thanks for the clarification, Keir, good to know!

thanks,
Nivedita

^ permalink raw reply	[flat|nested] 10+ messages in thread

* USB virt status
@ 2005-11-11 19:37 harry
  0 siblings, 0 replies; 10+ messages in thread
From: harry @ 2005-11-11 19:37 UTC (permalink / raw)
  To: sanjay.kushwaha, mark.williamson, xen-devel

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

Here's the latest USB code.

I've spent a few days testing and fixing bugs and it's now possible to
create and mount a filesystem on a USB key in the FE using this code.

I'm in the middle of debugging a problem where dom0 reboots when
flushing a big file to the USB key.  I didn't manage to find a serial
cable for a serial console this evening so I don't have much to go on
yet.

Since last week I've hooked the claim port call into xenbus such that
the configured port is claimed when the device is probed.  At the moment
the code will generate a 7 port virtual USB hub in the FE for each
configured backend device.  It would probably be better to either put
multiple devices on each FE hub or have single port hubs in the front
end.  I think I prefer the latter approach.

The code doesn't currently support hot-reconfiguration of the mapping
between BE usb ports and FE domains but does support hot plug and unplug
of USB devices into configured ports.

I also fixed a few FIXMEs in the code including checking that port
numbering was consistently one-based and checking that URB serialisation
was maintained correctly.

Remaining work:

o - more testing, fix dom0 reboot issue ASAP.
o - reformat to kernel coding style
o - split patch up into manageable chunks for review and patch
submission
o - run the USB code by the usb mailing list
o - fix remaining FIXMEs in code, error codes in particular.
o - more comments and API documentation

If anyone is interested in trying this out the steps are as follows:

Apply the patch to a recent xen-unstable.
make world
Choose to build the usb frontend and backend drivers either as loadable
modules or in kernel (both seem to work equally well).
Do not enable tracing in the xenidc code or the usb FE or BE (there's
too much tracing).
Configure a usb device in a FE domain config script:

usb = ['path=1']

This means attach whatever device is in the BE USB port specified by the
path (i.e. port 1 in this case) to the FE domain. This will create a USB
HUB in the FE domain and whatever device is attached to the BE port will
get attached to port one of the FE hub.

Boot the FE domain.

Load the modules (unless compiled into the kernel).

Plug a USB device in.

You are supposed to be able to load and unload modules and plug/unplug USB
devices however you like but unloading the backend module sometimes hangs
when unregistering a watch.  I think this is likely to be the deadlock in
xenstore that Rusty described.

[-- Attachment #2: latest-usb-patch.gz --]
[-- Type: application/x-gzip, Size: 86554 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] 10+ messages in thread

* RE: USB virt status
@ 2005-11-11 23:23 Ian Pratt
  0 siblings, 0 replies; 10+ messages in thread
From: Ian Pratt @ 2005-11-11 23:23 UTC (permalink / raw)
  To: harry, sanjay.kushwaha, mark.williamson, xen-devel

 
> I've spent a few days testing and fixing bugs and it's now 
> possible to create and mount a filesystem on a USB key in the 
> FE using this code.

Excellent, sounds promising.  
 
> I'm in the middle of debugging a problem where dom0 reboots 
> when flushing a big file to the USB key.  I didn't manage to 
> find a serial cable for a serial console this evening so I 
> don't have much to go on yet.

You could try 'noreboot' and stick to a text mode.

It'll be good to get USB functionality back in the tree.

Thanks,
Ian

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2005-11-11 23:23 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-10-30 16:43 USB virt status Harry Butterworth
     [not found] ` <200511041725.11451.mark.williamson@cl.cam.ac.uk>
     [not found]   ` <1131130680.3019.87.camel@localhost.localdomain>
     [not found]     ` <200511050050.58120.mark.williamson@cl.cam.ac.uk>
2005-11-05  2:21       ` Harry Butterworth
2005-11-05  4:08         ` Nivedita Singhvi
2005-11-05 10:32           ` Keir Fraser
2005-11-05 11:30             ` Harry Butterworth
2005-11-05 18:00             ` Nivedita Singhvi
2005-11-05 13:06           ` Mark Williamson
2005-11-05 12:32         ` Mark Williamson
  -- strict thread matches above, loose matches on Subject: below --
2005-11-11 19:37 harry
2005-11-11 23:23 Ian Pratt

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.