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; 8+ 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] 8+ messages in thread

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

Thread overview: 8+ 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

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.