* Re: USB virt
[not found] <200510241656.24936.mark.williamson@cl.cam.ac.uk>
@ 2005-10-24 16:40 ` harry
2005-10-25 23:21 ` Sean Dague
0 siblings, 1 reply; 4+ messages in thread
From: harry @ 2005-10-24 16:40 UTC (permalink / raw)
To: xen-devel, Mark Williamson
[-- Attachment #1: Type: text/plain, Size: 1660 bytes --]
I ported the FE and BE to a new interdomain communication interface and
the USB driver is mostly complete (the claim port interface needs to be
fixed up and there is a state machine which needs to be fixed).
I'm about halfway through the implementation of the interdomain
communication interface.
I defined a new interdomain communication interface because I wanted to
decouple the driver from changes in the underlying infrastructure so I
didn't have to rewrite it a fourth time for the next flavour of xenbus.
Also, I think the interdomain communication API I've written ought to be
generally useful and save a lot of code if people reuse it in other
drivers.
I've attached a patch of the current code. It compiles until it gets to
some undefined references for functions I've not implemented yet.
I'm currently working on the endpoint object. This is going to be
implemented in three layers: xenid_gnttab_channel, xenidc_xbgt_channel
and a third layer not yet complete. The current endpoint implementation
is crufty because I'm in the middle of factoring out the code into those
three layers.
Feedback on the code would be welcome.
Harry.
On Mon, 2005-10-24 at 16:56 +0100, Mark Williamson wrote:
> Hi Harry,
>
> Could you tell me what the status was on this? Is there any chance of getting
> a snapshot of the code online somewhere?
>
> Regarding the implementation, it sounds like you've done a good job making it
> work with lots of USB devices. I am curious as to why you're defining a new
> interdomain communications interface, though - XenBus is meant to be there
> for the forseeable future ... ?
>
> Thanks very much,
> Mark
>
[-- Attachment #2: latest-usb-patch --]
[-- Type: text/x-patch, Size: 588968 bytes --]
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/arch/xen/Kconfig
--- a/linux-2.6-xen-sparse/arch/xen/Kconfig Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/arch/xen/Kconfig Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 tools/python/xen/xend/server/usbif.py
--- a/tools/python/xen/xend/server/usbif.py Mon Oct 24 07:04:38 2005
+++ b/tools/python/xen/xend/server/usbif.py Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py Mon Oct 24 07:04:38 2005
+++ b/tools/python/xen/xm/create.py Mon Oct 24 15:04:49 2005
@@ -218,6 +218,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,
@@ -238,10 +242,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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/Makefile
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/Makefile Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,411 @@
+/*****************************************************************************/
+/* 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_local_buffer_reference message )
+{
+ trace();
+
+ usbback_driver_message_handler
+ ( usbback_device_endpoint_to( endpoint ), message );
+}
+
+static void usbback_device_endpoint_transaction
+ ( xenidc_endpoint * endpoint, xenidc_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_disconnect,
+ usbback_device_endpoint_message,
+ usbback_device_endpoint_transaction,
+ USBIF_BE_INITIATOR_MESSAGE_MAXIMUM_BYTE_COUNT,
+ USBIF_BE_INITIATOR_TRANSACTION_QUOTA,
+ USBIF_BE_INITIATOR_TRANSACTION_MAXIMUM_BYTE_COUNT,
+ USBIF_BE_TARGET_MESSAGE_MAXIMUM_BYTE_COUNT,
+ USBIF_BE_TARGET_TRANSACTION_QUOTA,
+ USBIF_BE_TARGET_TRANSACTION_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
+ );
+
+ return_value =
+ xenidc_endpoint_create( &device->endpoint, address );
+
+ if( return_value != 0 )
+ {
+ goto EXIT_NO_CREATE;
+ }
+ }
+
+ return 0;
+
+ EXIT:
+
+ xenidc_endpoint_destroy( &device->endpoint );
+
+ EXIT_NO_CREATE:
+
+ 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c Mon Oct 24 15:04:49 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_local_buffer_reference 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_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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h Mon Oct 24 15:04:49 2005
@@ -0,0 +1,54 @@
+/*****************************************************************************/
+/* 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_local_buffer_reference message );
+
+extern void usbback_driver_transaction_handler
+ ( struct usbback_device * device, xenidc_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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,587 @@
+/*****************************************************************************/
+/* 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_transaction * transaction
+);
+
+static void usbback_driver_backend_handle_reset
+(
+ struct usbback_driver_backend * backend,
+ xenidc_transaction * transaction
+);
+
+static void usbback_driver_backend_handle_io
+(
+ struct usbback_driver_backend * backend,
+ xenidc_transaction * transaction
+);
+
+void usbback_driver_backend_transaction_handler
+ ( struct usbback_driver_backend * backend, xenidc_transaction * transaction )
+{
+ /* trace(); */
+
+ usbif_transaction_parameters_header header;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ &transaction->parameters,
+ &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_transaction_complete
+ ( transaction, XENIDC_ERROR_INVALID_PARAMETER );
+ break;
+ }
+ }
+ else
+ {
+ /* Parameters were underlength. */
+
+ xenidc_transaction_complete
+ ( transaction, XENIDC_ERROR_INVALID_FORMAT );
+ }
+}
+
+static void usbback_driver_backend_handle_probe
+ ( struct usbback_driver_backend * backend, xenidc_transaction * transaction )
+{
+ /* trace(); */
+
+ usbif_probe_transaction_parameters parameters;
+
+ xenidc_error error;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ &transaction->parameters,
+ ¶meters,
+ 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
+ (
+ &transaction->status,
+ &status,
+ sizeof( status )
+ )
+ !=
+ sizeof( status )
+ )
+ {
+ error = XENIDC_ERROR_INVALID_FORMAT;
+
+ goto COMPLETE;
+ }
+ }
+
+ error = XENIDC_ERROR_SUCCESS;
+
+ COMPLETE:
+
+ xenidc_transaction_complete( transaction, error );
+}
+
+static void usbback_driver_backend_handle_reset
+ ( struct usbback_driver_backend * backend, xenidc_transaction * transaction )
+{
+ trace();
+
+ {
+ usbif_reset_transaction_parameters parameters;
+
+ xenidc_error error;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ &transaction->parameters,
+ ¶meters,
+ 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
+ (
+ &transaction->status,
+ &status,
+ sizeof( status )
+ )
+ !=
+ sizeof( status )
+ )
+ {
+ error = XENIDC_ERROR_INVALID_FORMAT;
+
+ goto COMPLETE;
+ }
+ }
+ }
+
+ error = XENIDC_ERROR_SUCCESS;
+
+ COMPLETE:
+
+ xenidc_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_transaction * transaction )
+{
+ trace();
+
+ {
+ usbif_io_transaction_parameters_header header;
+
+ xenidc_error error;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ &transaction->parameters,
+ &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_transaction_complete( transaction, error );
+ }
+}
+
+static void usbback_driver_backend_handle_unlink
+(
+ struct usbback_driver_backend * backend,
+ xenidc_local_buffer_reference message
+);
+
+void usbback_driver_backend_message_handler
+(
+ struct usbback_driver_backend * backend,
+ xenidc_local_buffer_reference message
+)
+{
+ trace();
+
+ {
+ usbif_message_header header;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ &message,
+ &header,
+ sizeof( header )
+ )
+ ==
+ sizeof( header )
+ )
+ {
+ switch( header.message_type )
+ {
+ case USBIF_MESSAGE_TYPE_UNLINK:
+ usbback_driver_backend_handle_unlink( backend, message );
+ break;
+ }
+ }
+ }
+}
+
+static void usbback_driver_backend_handle_unlink
+(
+ struct usbback_driver_backend * backend,
+ xenidc_local_buffer_reference message
+)
+{
+ trace();
+
+ {
+ usbif_unlink_message_body unlink;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ &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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h Mon Oct 24 15:04:49 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_transaction * transaction
+);
+
+extern void usbback_driver_backend_message_handler
+(
+ struct usbback_driver_backend * backend,
+ xenidc_local_buffer_reference 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,1149 @@
+/*****************************************************************************/
+/* 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_transaction * transaction )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &port->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_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_transaction * transaction = NULL;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &port->lock, flags );
+
+ {
+ xenidc_transaction * temp;
+
+ list_for_each_entry
+ ( temp, &port->transaction_list, XENIDC_TRANSACTION_LINK )
+ {
+ usbif_io_transaction_parameters_header header;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ &transaction->parameters,
+ &header,
+ sizeof( header )
+ )
+ ==
+ sizeof( header )
+ )
+ {
+ if( header.unlink_id == unlink_id )
+ {
+ transaction = temp;
+
+ list_del_init
+ ( xenidc_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_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_transaction * transaction = list_entry
+ (
+ port->transaction_list.next,
+ xenidc_transaction,
+ XENIDC_TRANSACTION_LINK
+ );
+
+ list_del_init( xenidc_transaction_to_link( transaction ) );
+
+ list_add_tail
+ ( xenidc_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_transaction * transaction = list_entry
+ (
+ port->purge_list.next,
+ xenidc_transaction,
+ XENIDC_TRANSACTION_LINK
+ );
+
+ list_del_init( xenidc_transaction_to_link( transaction ) );
+
+ spin_unlock_irq( &port->lock );
+
+ xenidc_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_transaction * transaction = list_entry
+ (
+ port->transaction_list.next,
+ xenidc_transaction,
+ XENIDC_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_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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h Mon Oct 24 15:04:49 2005
@@ -0,0 +1,146 @@
+/*****************************************************************************/
+/* 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_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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,1223 @@
+/*****************************************************************************/
+/* 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_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
+ (
+ &resource->transaction->parameters,
+ &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
+ (
+ &resource->transaction->parameters,
+ &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
+ (
+ &resource->transaction->parameters,
+ ¶meters,
+ 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
+ (
+ &resource->transaction->parameters,
+ &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
+ (
+ &resource->completing_transaction->status,
+ &status,
+ sizeof( status )
+ )
+ !=
+ sizeof( status )
+ )
+ {
+ resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT;
+ }
+
+ xenidc_transaction_complete
+ ( resource->completing_transaction, resource->transaction_error );
+
+ usbback_driver_port_resource_completed_io( resource->port, resource );
+ }
+}
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h Mon Oct 24 15:04:49 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_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_transaction * transaction;
+ xenidc_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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_assert.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_assert.h Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,1321 @@
+/*****************************************************************************/
+/* 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_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_message * message )
+{
+ trace();
+
+ xenidc_endpoint_submit_message( &device->endpoint, message );
+}
+
+void usbfront_device_submit_transaction
+ ( struct usbfront_device * device, xenidc_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_local_buffer_reference message )
+{
+ trace();
+
+ /* The protocol doesn't require any messages sent from BE to FE so we */
+ /* just ignore anything sent to us. */
+}
+
+static void usbfront_device_endpoint_transaction
+ ( xenidc_endpoint * endpoint, xenidc_transaction * transaction )
+{
+ trace();
+
+ /* The protocol doesn't require any transactions sent from BE to FE so */
+ /* we just ignore anything sent to us. */
+
+ xenidc_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_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_disconnect,
+ usbfront_device_endpoint_message,
+ usbfront_device_endpoint_transaction,
+ USBIF_FE_INITIATOR_MESSAGE_MAXIMUM_BYTE_COUNT,
+ USBIF_FE_INITIATOR_TRANSACTION_QUOTA,
+ USBIF_FE_INITIATOR_TRANSACTION_MAXIMUM_BYTE_COUNT,
+ USBIF_FE_TARGET_MESSAGE_MAXIMUM_BYTE_COUNT,
+ USBIF_FE_TARGET_TRANSACTION_QUOTA,
+ USBIF_FE_TARGET_TRANSACTION_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
+ );
+
+ return_value =
+ xenidc_endpoint_create( &device->endpoint, address );
+
+ if( return_value != 0 )
+ {
+ goto EXIT_NO_CREATE;
+ }
+ }
+
+ return 0;
+
+ EXIT:
+
+ xenidc_endpoint_destroy( &device->endpoint );
+
+ EXIT_NO_CREATE:
+
+ 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_transaction_set_parameters_lbr
+ (
+ &probe->transaction,
+ xenidc_vaddress_create_lbr
+ (
+ &probe->probe.parameters,
+ sizeof( probe->probe.parameters )
+ )
+ );
+
+ xenidc_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_transaction_set_parameters_lbr
+ (
+ &probe->transaction,
+ xenidc_vaddress_create_lbr
+ (
+ &probe->reset.parameters,
+ sizeof( probe->reset.parameters )
+ )
+ );
+
+ xenidc_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_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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.h Mon Oct 24 15:04:49 2005
@@ -0,0 +1,82 @@
+/*****************************************************************************/
+/* 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_message * message );
+
+void usbfront_device_submit_transaction
+ ( struct usbfront_device * device, xenidc_transaction * transaction );
+
+#endif
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.c Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.h Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,942 @@
+/*****************************************************************************/
+/* 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_transaction_init
+ (
+ &resource->io_transaction,
+ usbfront_hcd_resource_submit_transaction_1
+ );
+
+ xenidc_transaction_set_parameters_lbr
+ (
+ &resource->io_transaction,
+ xenidc_vaddress_create_lbr
+ (
+ &resource->io_parameters,
+ sizeof( resource->io_parameters )
+ )
+ );
+
+ xenidc_transaction_set_status_lbr
+ (
+ &resource->io_transaction,
+ xenidc_vaddress_create_lbr
+ (
+ &resource->io_status,
+ sizeof( resource->io_status )
+ )
+ );
+
+ xenidc_message_init
+ ( &resource->unlink_message, usbfront_hcd_resource_submit_unlink_1 );
+
+ xenidc_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_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_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_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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.h Mon Oct 24 15:04:49 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_transaction io_transaction;
+ usbif_io_transaction_parameters io_parameters;
+ usbif_io_transaction_status io_status;
+ xenidc_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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_module.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_module.c Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_sll.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_sll.h Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_trace.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_trace.h Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Mon Oct 24 15:04:49 2005
@@ -0,0 +1,13 @@
+obj-y += xenidc.o
+
+xenidc-objs =
+xenidc-objs += xenidc_callback.o
+xenidc-objs += xenidc_concatenate.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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_callback.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_callback.c Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_channel_ring.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_channel_ring.h Mon Oct 24 15:04:49 2005
@@ -0,0 +1,79 @@
+/*****************************************************************************/
+/* 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
+{
+ u8 type;
+ u8 reserved0;
+ u16 length;
+ u8 reserved1[4];
+};
+
+#define XENIDC_CHANNEL_RING_ELEMENT_TYPE_MESSAGE 0
+#define XENIDC_CHANNEL_RING_ELEMENT_TYPE_PARAMETERS 1
+#define XENIDC_CHANNEL_RING_ELEMENT_TYPE_STATUS 2
+
+typedef struct xenidc_channel_message_ring_element_struct
+ xenidc_channel_message_ring_element;
+
+struct xenidc_channel_message_ring_element_struct
+{
+ xenidc_channel_ring_element_header header;
+};
+
+typedef struct xenidc_channel_parameters_ring_element_struct
+ xenidc_channel_parameters_ring_element;
+
+struct xenidc_channel_parameters_ring_element_struct
+{
+ xenidc_channel_ring_element_header header;
+ u32 id;
+ u16 status_byte_count;
+ u16 reserved;
+};
+
+typedef struct xenidc_channel_status_ring_element_struct
+ xenidc_channel_status_ring_element;
+
+struct xenidc_channel_status_ring_element_struct
+{
+ xenidc_channel_ring_element_header header;
+ u32 id;
+ xenidc_error error;
+};
+
+#endif
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_concatenate.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_concatenate.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,46 @@
+/*****************************************************************************/
+/* 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"
+
+xenidc_local_buffer_reference xenidc_concatenate_create_lbr
+(
+ xenidc_concatenate_base * base,
+ xenidc_local_buffer_reference * head,
+ xenidc_local_buffer_reference * tail
+)
+{
+ trace();
+
+ /* FIXME */
+
+ {
+ xenidc_local_buffer_reference lbr;
+
+ memset( &lbr, 0, sizeof( lbr ) );
+
+ return lbr;
+ }
+}
+
+EXPORT_SYMBOL( xenidc_concatenate_create_lbr );
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,1164 @@
+/*****************************************************************************/
+/* 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 */
+/* */
+/*****************************************************************************/
+
+/******************************************************************************
+ * arch/xen/drivers/blkif/backend/interface.c
+ *
+ * Block-device interface management.
+ *
+ * Copyright (c) 2004, Keir Fraser
+ */
+
+/*****************************************************************************/
+/* xenidc_endpoint design notes: */
+/* */
+/* Two xenidc_endpoint instances, one in each of two domains connect */
+/* together to form a communication channel. The channel is symmetric apart */
+/* from the number of resources allocated for transactions and the */
+/* configured maximum size of transactions in each direction. */
+/* */
+/* Each endpoint allocates a page of memory and grants the other side */
+/* read-only access to it. Each page starts with a */
+/* xenidc_endpoint_ring_header structure and the remainder of the page is */
+/* used as a circular buffer for sending data from the granting side to the */
+/* read-only side. The xenidc_endpoint_ring_header contains the producer and */
+/* consumer offsets for the circular buffers. The producer offset in each */
+/* header is for the circular buffer in the same page as the header, the */
+/* consumer offset is for the circular buffer in the other header (so both */
+/* of the offsets written by an endpoint are in the page to which it has */
+/* write access and the offsets read by an endpoint are in the page to which */
+/* it has read-only access). */
+/* */
+/* The endpoints put three kinds of elements into the circular buffers: */
+/* message elements transfer messages; parameters elements transfer */
+/* transaction parameters and status elements transfer transaction status. */
+/* */
+/* There are two types of resources used to process messages and */
+/* transactions: initiator resources and target resources. Both types of */
+/* resource use xenidc_endpoint_send_request requests to transfer elements */
+/* using the circular buffer. */
+/* */
+/* Message processing is performed as follows: a message is queued and an */
+/* initiator resource is allocated to process it when one becomes available. */
+/* The initiator resource creates a xenidc_endpoint_send_request to send a */
+/* message element for the message. The xenidc_endpoint_send_request is */
+/* queued internally by the endpoint until there is space in the circular */
+/* buffer to copy in the element (a header and the body of the message). */
+/* When there is space in the buffer, the element is copied in and the other */
+/* endpoint is signalled. The other endpoint discovers the message element */
+/* in the buffer and submits the message data to the message handler */
+/* installed at initialisation. */
+/* The xenidc_endpoint_send_request completes to the initiator resource as */
+/* soon as the message element has been copied into the buffer at which time */
+/* the initiator resource completes and is returned to the free list. */
+/* */
+/* Transaction processing is performed as follows: a transaction is queued */
+/* and an initiator resource is allocated to process it when one becomes */
+/* available. The initiator resource creates a xenidc_endpoint_send_request */
+/* to send a parameters element for the transaction parameters. The */
+/* xenidc_endpoint_send_request is queued internally by the endpoint until */
+/* there is space in the circular buffer to copy in the element (a header */
+/* and the transaction parameters). When there is space in the buffer, the */
+/* element is copied in and the other endpoint is signalled. The other */
+/* endpoint discovers the parameters element and, if necessary, stalls until */
+/* a target resource becomes available. When one is available it is */
+/* allocated to process the transaction. The target resource creates a */
+/* xenidc_transaction by copying the parameters from the circular buffer */
+/* into a buffer of its own and zeroing a buffer to receive the transaction */
+/* status. The target resource submits the transaction to the endpoint */
+/* client's transaction handler. The client processes the transaction and */
+/* completes back to the target resource. The target resource creates a */
+/* xenidc_endpoint_send_request to send a status element for the transaction */
+/* back to the initiator. Once the target resource's */
+/* xenidc_endpoint_send_request completes, the target resource is itself */
+/* complete and is returned to the free list. */
+/* The initiator resource is called to handle the status element returned by */
+/* the target resource and copies the status from the circular buffer into */
+/* the transaction status buffer. The initiator resource's */
+/* xenidc_endpoint_send_request completes concurrently with the return of */
+/* status from the target and the initiator resource must wait for both to */
+/* happen in either order before completing the transaction and completing */
+/* itself back to the free list. */
+/* */
+/* Copying into and out of the circular buffer like this is the simplest way */
+/* to allow an arbitrary number of arbitrary sized transactions using a */
+/* finite number of shared pages. More importantly, it allows transactions */
+/* to overtake a stalled transaction which means that if a transaction hangs */
+/* indefinitely in the back end it won't block the system. This is */
+/* important for USB for example because some USB transactions hang for a */
+/* long time before being unlinked and we want the other USB devices to be */
+/* unaffected whilst this is going on. */
+/* */
+/* The endpoint code is structured as a state machine with inputs that */
+/* queue requests and generate stimuli, a core state machine that handles */
+/* stimuli, makes state transitions and generates responses and a set of */
+/* responses that initiate processes to manipulate the endpoint resources. */
+/* These processes also generate stimuli to signal significant conditions */
+/* (for example completion of a process). */
+/* */
+/*****************************************************************************/
+
+#include <asm/semaphore.h>
+#include <asm-xen/evtchn.h>
+#include <asm-xen/xenbus.h>
+#include <asm-xen/xenidc.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include "xenidc_trace.h"
+#include "xenidc_endpoint_initiator_resource.h"
+#include "xenidc_endpoint_target_resource.h"
+#include "xenidc_vaddress.h"
+#include "xenidc_wrapping.h"
+
+typedef enum
+{
+ xenidc_endpoint_stimulus_cr, /* Create */
+ xenidc_endpoint_stimulus_mt, /* Message or transaction enqueued */
+ xenidc_endpoint_stimulus_sr, /* Send request enqueued */
+ xenidc_endpoint_stimulus_dt, /* Destroy */
+ xenidc_endpoint_stimulus_cn, /* Connect from xenstore */
+ xenidc_endpoint_stimulus_xs, /* Xenstore transaction successful */
+ xenidc_endpoint_stimulus_xf, /* Xenstore transaction failed */
+ xenidc_endpoint_stimulus_es, /* Establish success */
+ xenidc_endpoint_stimulus_ef, /* Establish failed */
+ xenidc_endpoint_stimulus_si, /* Send interrupt */
+ xenidc_endpoint_stimulus_ri, /* Recv interrupt */
+ xenidc_endpoint_stimulus_sk, /* Kick send ring completed */
+ xenidc_endpoint_stimulus_rk, /* Kick recv ring completed */
+ xenidc_endpoint_stimulus_rp, /* Kick recv ring protocol error */
+}
+xenidc_endpoint_stimulus;
+
+static void xenidc_endpoint_handle_stimulus
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_stimulus stimulus );
+
+static void xenidc_endpoint_xenstore_connect_1( void * data );
+
+static void xenidc_endpoint_establish_connection_1( void * data );
+
+static void xenidc_endpoint_kick_messages_and_transactions_1( void * data );
+
+static void xenidc_endpoint_kick_messages_and_transactions_2
+ ( xenidc_callback * callback );
+
+static void xenidc_endpoint_kick_send_ring_1( void * data );
+
+static void xenidc_endpoint_kick_recv_ring_1( void * data );
+
+static void xenidc_endpoint_kick_recv_ring_2( xenidc_callback * callback );
+
+static int xenidc_endpoint_init_or_exit( xenidc_endpoint * endpoint, int exit )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ if( exit )
+ {
+ goto EXIT;
+ }
+
+ endpoint->send_irq_context = endpoint;
+ endpoint->recv_irq_context = endpoint;
+
+ INIT_LIST_HEAD( &endpoint->initiator_resource_list );
+
+ if( endpoint->initiator_transaction_quota != 0 )
+ {
+ endpoint->initiator_resources = vmalloc
+ (
+ sizeof( xenidc_endpoint_initiator_resource )
+ *
+ endpoint->initiator_transaction_quota
+ );
+
+ if( endpoint->initiator_resources == NULL )
+ {
+ trace0( "failed to allocate initiator resources" );
+
+ return_value = -ENOMEM;
+
+ goto EXIT_NO_INITIATOR_RESOURCES;
+ }
+
+ {
+ u32 i;
+
+ for( i = 0; i < endpoint->initiator_transaction_quota; i++ )
+ {
+ xenidc_endpoint_initiator_resource * resource =
+ &endpoint->initiator_resources[ i ];
+
+ xenidc_endpoint_initiator_resource_init
+ (
+ resource,
+ endpoint,
+ xenidc_endpoint_kick_messages_and_transactions_2,
+ i
+ );
+
+ list_add_tail
+ (
+ xenidc_endpoint_initiator_resource_to_link( resource ),
+ &endpoint->initiator_resource_list
+ );
+ }
+ }
+ }
+
+ INIT_LIST_HEAD( &endpoint->target_resource_list );
+
+ if( endpoint->target_transaction_quota != 0 )
+ {
+ endpoint->target_resources = vmalloc
+ (
+ (
+ sizeof( xenidc_endpoint_target_resource )
+ *
+ endpoint->target_transaction_quota
+ )
+ +
+ (
+ endpoint->target_transaction_maximum_byte_count
+ *
+ endpoint->target_transaction_quota
+ )
+ );
+
+ if( endpoint->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
+ (
+ &endpoint->target_resources
+ [ endpoint->target_transaction_quota ],
+ endpoint->target_transaction_maximum_byte_count *
+ endpoint->target_transaction_quota
+ );
+
+ u32 i;
+
+ for( i = 0; i < endpoint->target_transaction_quota; i++ )
+ {
+ xenidc_endpoint_target_resource * resource =
+ &endpoint->target_resources[ i ];
+
+ xenidc_local_buffer_reference buffer = buffer_area;
+
+ xenidc_local_buffer_reference_truncate
+ (
+ &buffer,
+ endpoint->target_transaction_maximum_byte_count
+ );
+
+ xenidc_endpoint_target_resource_init
+ (
+ resource,
+ endpoint,
+ xenidc_endpoint_kick_recv_ring_2,
+ buffer
+ );
+
+ list_add_tail
+ (
+ xenidc_endpoint_target_resource_to_link( resource ),
+ &endpoint->target_resource_list
+ );
+
+ xenidc_local_buffer_reference_advance
+ (
+ &buffer_area,
+ endpoint->target_transaction_maximum_byte_count
+ );
+ }
+ }
+ }
+
+ spin_lock_init( &endpoint->lock );
+
+ endpoint->state = xenidc_endpoint_state_i;
+
+ INIT_LIST_HEAD( &endpoint->message_and_transaction_list );
+ INIT_LIST_HEAD( &endpoint->send_request_list );
+
+ xenidc_work_init
+ (
+ &endpoint->xenstore_connect_1_work,
+ xenidc_endpoint_xenstore_connect_1,
+ endpoint
+ );
+
+ xenidc_work_init
+ (
+ &endpoint->establish_connection_1_work,
+ xenidc_endpoint_establish_connection_1,
+ endpoint
+ );
+
+ xenidc_work_init
+ (
+ &endpoint->kick_messages_and_transactions_1_work,
+ xenidc_endpoint_kick_messages_and_transactions_1,
+ endpoint
+ );
+
+ return 0;
+
+ EXIT:
+
+ if( endpoint->target_transaction_quota != 0 )
+ {
+ vfree( endpoint->target_resources );
+ }
+
+ EXIT_NO_TARGET_RESOURCES:
+
+ if( endpoint->initiator_transaction_quota != 0 )
+ {
+ vfree( endpoint->initiator_resources );
+ }
+
+ EXIT_NO_INITIATOR_RESOURCES:
+
+ return return_value;
+ }
+}
+
+int xenidc_endpoint_init
+(
+ xenidc_endpoint * endpoint,
+ void ( * connect )( xenidc_endpoint * endpoint ),
+ void ( * disconnect )
+ ( xenidc_endpoint * endpoint, xenidc_callback * callback ),
+ void ( * message )
+ ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference message ),
+ void ( * transaction )
+ ( xenidc_endpoint * endpoint, xenidc_transaction * transaction ),
+ xenidc_buffer_byte_count initiator_message_maximum_byte_count,
+ u32 initiator_transaction_quota,
+ xenidc_buffer_byte_count initiator_transaction_maximum_byte_count,
+ xenidc_buffer_byte_count target_message_maximum_byte_count,
+ u32 target_transaction_quota,
+ xenidc_buffer_byte_count target_transaction_maximum_byte_count
+)
+{
+ trace();
+
+ endpoint->connect = connect;
+ endpoint->disconnect = disconnect;
+ endpoint->message = message;
+ endpoint->transaction = transaction;
+
+ endpoint->initiator_transaction_quota = initiator_transaction_quota;
+ endpoint->target_transaction_quota = target_transaction_quota;
+ endpoint->target_transaction_maximum_byte_count =
+ target_transaction_maximum_byte_count;
+
+ return xenidc_endpoint_init_or_exit( endpoint, 0 );
+}
+
+static void xenidc_endpoint_watch
+ ( struct xenbus_watch * watch, const char ** vec, unsigned int len );
+
+static irqreturn_t xenidc_endpoint_send_interrupt
+ ( int irq, void * context, struct pt_regs * ptregs );
+
+static int xenidc_endpoint_create_or_destroy
+ ( xenidc_endpoint * endpoint, int destroy )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ if( destroy )
+ {
+ goto DESTROY;
+ }
+
+ endpoint->watch.node =
+ xenidc_address_query_remote_domain( &endpoint->address );
+ endpoint->watch.callback = xenidc_endpoint_watch;
+
+ return_value = register_xenbus_watch( &endpoint->watch );
+
+ if( return_value )
+ {
+ trace0( "register_xenbus_watch failed" );
+
+ goto EXIT_NO_WATCH;
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &endpoint->lock, flags );
+
+ xenidc_endpoint_handle_stimulus
+ ( endpoint, xenidc_endpoint_stimulus_cr );
+
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+ }
+
+ return 0;
+
+ DESTROY:
+
+ endpoint->destroyed = 0;
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &endpoint->lock, flags );
+
+ xenidc_endpoint_handle_stimulus
+ ( endpoint, xenidc_endpoint_stimulus_dt );
+
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+ }
+
+ /* FIXME xenidc_work_until( endpoint->destroyed ); */
+
+ gnttab_end_foreign_access_ref( endpoint->send_ring_ref, 0 );
+
+ gnttab_release_grant_reference
+ ( &endpoint->grant_ref_pool, endpoint->send_ring_ref );
+
+ unbind_evtchn_from_irqhandler
+ ( endpoint->send_irq, &endpoint->send_irq_context );
+
+ EXIT_NO_BIND:
+
+ /* FIXME: free event channel? */
+
+ EXIT_NO_EVENT_CHANNEL:
+
+ unregister_xenbus_watch( &endpoint->watch );
+
+ EXIT_NO_WATCH:
+
+ return return_value;
+ }
+}
+
+int xenidc_endpoint_create
+ ( xenidc_endpoint * endpoint, xenidc_address address )
+{
+ trace();
+
+ endpoint->address = address;
+
+ return xenidc_endpoint_create_or_destroy( endpoint, 0 );
+}
+
+static void xenidc_endpoint_watch
+ ( struct xenbus_watch * watch, const char ** vec, unsigned int len )
+{
+ trace();
+
+ {
+ xenidc_endpoint * endpoint =
+ container_of( watch, xenidc_endpoint, watch );
+
+ {
+ unsigned int event_channel;
+ unsigned int ring_ref;
+
+ int error = xenbus_gather
+ (
+ NULL, /* FIXME */
+ watch->node,
+ "event-channel", "%u", &event_channel,
+ "ring-ref", "%u", &ring_ref,
+ NULL
+ );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &endpoint->lock, flags );
+
+ if( error == 0 )
+ {
+ endpoint->recv_event_channel = event_channel;
+ endpoint->recv_ring_ref = ring_ref;
+
+ xenidc_endpoint_handle_stimulus
+ ( endpoint, xenidc_endpoint_stimulus_cn );
+ }
+
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+ }
+ }
+}
+
+
+void xenidc_endpoint_submit_message
+ ( xenidc_endpoint * endpoint, xenidc_message * message )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &endpoint->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_message_to_link( message ),
+ &endpoint->message_and_transaction_list
+ );
+
+ xenidc_endpoint_handle_stimulus
+ ( endpoint, xenidc_endpoint_stimulus_mt );
+
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+ }
+}
+
+void xenidc_endpoint_submit_transaction
+ ( xenidc_endpoint * endpoint, xenidc_transaction * transaction )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &endpoint->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_transaction_to_link( transaction ),
+ &endpoint->message_and_transaction_list
+ );
+
+ xenidc_endpoint_handle_stimulus
+ ( endpoint, xenidc_endpoint_stimulus_mt );
+
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+ }
+}
+
+void xenidc_endpoint_submit_send_request
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_send_request * request )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &endpoint->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_endpoint_send_request_to_link( request ),
+ &endpoint->send_request_list
+ );
+
+ xenidc_endpoint_handle_stimulus
+ ( endpoint, xenidc_endpoint_stimulus_sr );
+
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+ }
+}
+
+void xenidc_endpoint_destroy( xenidc_endpoint * endpoint )
+{
+ trace();
+
+ (void)xenidc_endpoint_create_or_destroy( endpoint, 1 );
+}
+
+void xenidc_endpoint_exit( xenidc_endpoint * endpoint )
+{
+ trace();
+
+ (void)xenidc_endpoint_init_or_exit( endpoint, 1 );
+}
+
+static void xenidc_endpoint_invalid_stimulus
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_stimulus stimulus );
+
+static void xenidc_endpoint_xenstore_connect( xenidc_endpoint * endpoint );
+
+static void xenidc_endpoint_establish_connection( xenidc_endpoint * endpoint );
+
+static void xenidc_endpoint_kick_messages_and_transactions
+ ( xenidc_endpoint * endpoint );
+
+static void xenidc_endpoint_kick_send_ring( xenidc_endpoint * endpoint );
+
+static void xenidc_endpoint_kick_recv_ring( xenidc_endpoint * endpoint );
+
+static void xenidc_endpoint_handle_stimulus
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_stimulus stimulus )
+{
+ trace3
+ (
+ "endpoint %p in state %d received stimulus %d",
+ endpoint,
+ endpoint->state,
+ stimulus
+ );
+
+ switch( endpoint->state )
+ {
+ case xenidc_endpoint_state_i:
+ /* Uncreated */
+ /* Offline */
+ switch( stimulus )
+ {
+ case xenidc_endpoint_stimulus_cr:
+ endpoint->state = xenidc_endpoint_state_i_cr;
+ xenidc_endpoint_xenstore_connect( endpoint );
+ break;
+ case xenidc_endpoint_stimulus_cn:
+ endpoint->state = xenidc_endpoint_state_i_cn;
+ break;
+ default:
+ xenidc_endpoint_invalid_stimulus( endpoint, stimulus );
+ break;
+ }
+ break;
+ case xenidc_endpoint_state_i_cr:
+ /* Creating */
+ /* Xenstore Connect */
+ /* Offline */
+ switch( stimulus )
+ {
+ case xenidc_endpoint_stimulus_cn:
+ endpoint->state = xenidc_endpoint_state_i_cr_cn;
+ break;
+ case xenidc_endpoint_stimulus_xs:
+ endpoint->state = xenidc_endpoint_state_i_cr_xs;
+ break;
+ default:
+ xenidc_endpoint_invalid_stimulus( endpoint, stimulus );
+ break;
+ }
+ break;
+ case xenidc_endpoint_state_i_cn:
+ /* Uncreated */
+ /* Offline */
+ /* Connect received */
+ switch( stimulus )
+ {
+ case xenidc_endpoint_stimulus_cr:
+ endpoint->state = xenidc_endpoint_state_i_cr_cn;
+ xenidc_endpoint_xenstore_connect( endpoint );
+ break;
+ case xenidc_endpoint_stimulus_cn:
+ break;
+ default:
+ xenidc_endpoint_invalid_stimulus( endpoint, stimulus );
+ break;
+ }
+ break;
+ case xenidc_endpoint_state_i_cr_cn:
+ /* Creating */
+ /* Xenstore Connect */
+ /* Offline */
+ /* Connect received */
+ switch( stimulus )
+ {
+ case xenidc_endpoint_stimulus_cn:
+ break;
+ case xenidc_endpoint_stimulus_xs:
+ endpoint->state = xenidc_endpoint_state_i_cr_cn_xs;
+ xenidc_endpoint_establish_connection( endpoint );
+ break;
+ default:
+ xenidc_endpoint_invalid_stimulus( endpoint, stimulus );
+ break;
+ }
+ break;
+ case xenidc_endpoint_state_i_cr_xs:
+ /* Creating */
+ /* Xenstore Connect completed */
+ /* Offline */
+ switch( stimulus )
+ {
+ case xenidc_endpoint_stimulus_cn:
+ endpoint->state = xenidc_endpoint_state_i_cr_cn_xs;
+ xenidc_endpoint_establish_connection( endpoint );
+ break;
+ default:
+ xenidc_endpoint_invalid_stimulus( endpoint, stimulus );
+ break;
+ }
+ break;
+ case xenidc_endpoint_state_i_cr_cn_xs:
+ /* Creating */
+ /* Xenstore Connect completed */
+ /* Establishing connection */
+ switch( stimulus )
+ {
+ case xenidc_endpoint_stimulus_cn:
+ break;
+ case xenidc_endpoint_stimulus_es:
+ endpoint->state = xenidc_endpoint_state_i_cr_cn_xs_es;
+ break;
+ default:
+ xenidc_endpoint_invalid_stimulus( endpoint, stimulus );
+ break;
+ }
+ break;
+ case xenidc_endpoint_state_i_cr_cn_xs_es:
+ /* Created */
+ /* Online */
+ switch( stimulus )
+ {
+ default:
+ xenidc_endpoint_invalid_stimulus( endpoint, stimulus );
+ break;
+ }
+ break;
+ default:
+ xenidc_endpoint_invalid_stimulus( endpoint, stimulus );
+ break;
+ }
+}
+
+static void xenidc_endpoint_invalid_stimulus
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_stimulus stimulus )
+{
+ trace();
+
+ printk
+ (
+ KERN_ERR "xenidc: endpoint %p in state %d"
+ "received invalid stimulus %d",
+ endpoint,
+ endpoint->state,
+ stimulus
+ );
+}
+
+static void xenidc_endpoint_xenstore_connect( xenidc_endpoint * endpoint )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &endpoint->xenstore_connect_1_work );
+}
+
+static void xenidc_endpoint_xenstore_connect_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_endpoint * endpoint = (xenidc_endpoint *)data;
+
+ memset( endpoint->send_ring, 0, PAGE_SIZE );
+
+ down( &xenbus_lock );
+
+ AGAIN:
+
+ {
+ int error = xenbus_transaction_start();
+
+ if( error )
+ {
+ trace0( "xenbus_transaction_start failed" );
+
+ goto EXIT_NO_TRANSACTION;
+ }
+ }
+
+ {
+ int error = xenbus_printf
+ (
+ xenidc_address_query_local_domain( &endpoint->address ),
+ "ring-ref",
+ "%u",
+ endpoint->send_ring_ref
+ );
+
+ if( error )
+ {
+ trace0( "xenbus_printf of ring-ref failed" );
+
+ goto ABORT_TRANSACTION;
+ }
+ }
+
+ {
+ int error = xenbus_printf
+ (
+ xenidc_address_query_local_domain( &endpoint->address ),
+ "event-channel",
+ "%u",
+ endpoint->send_event_channel
+ );
+
+ if( error )
+ {
+ trace0( "xenbus_printf of event-channel failed" );
+
+ ABORT_TRANSACTION:
+
+ xenbus_transaction_end( 1 );
+
+ goto EXIT_NO_TRANSACTION;
+ }
+ }
+
+ {
+ int error = xenbus_transaction_end( 0 );
+
+ if( error == -EAGAIN )
+ {
+ trace0( "EAGAIN on xenbus_transaction_end" );
+
+ goto AGAIN;
+ }
+
+ if( error )
+ {
+ trace0( "xenbus_transaction_end failed" );
+
+ goto EXIT_NO_TRANSACTION;
+ }
+ }
+
+ up( &xenbus_lock );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &endpoint->lock, flags );
+
+ xenidc_endpoint_handle_stimulus
+ ( endpoint, xenidc_endpoint_stimulus_xs );
+
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+ }
+
+ return;
+
+ EXIT_NO_TRANSACTION:
+
+ up( &xenbus_lock );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &endpoint->lock, flags );
+
+ xenidc_endpoint_handle_stimulus
+ ( endpoint, xenidc_endpoint_stimulus_xf );
+
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+ }
+ }
+}
+
+static void xenidc_endpoint_establish_connection( xenidc_endpoint * endpoint )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &endpoint->establish_connection_1_work );
+}
+
+static void xenidc_endpoint_establish_connection_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_endpoint * endpoint = (xenidc_endpoint *)data;
+ return;
+
+ }
+}
+
+static void xenidc_endpoint_kick_messages_and_transactions
+ ( xenidc_endpoint * endpoint )
+{
+ trace();
+
+ (void)xenidc_work_schedule
+ ( &endpoint->kick_messages_and_transactions_1_work );
+}
+
+static void xenidc_endpoint_kick_messages_and_transactions_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_endpoint * endpoint = (xenidc_endpoint *)data;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &endpoint->lock, flags );
+
+ while
+ (
+ ( !list_empty( &endpoint->message_and_transaction_list ) )
+ &&
+ ( !list_empty( &endpoint->initiator_resource_list ) )
+ )
+ {
+ xenidc_message_and_transaction_header * header = list_entry
+ (
+ endpoint->message_and_transaction_list.next,
+ xenidc_message_and_transaction_header,
+ XENIDC_MESSAGE_AND_TRANSACTION_HEADER_LINK
+ );
+
+ xenidc_endpoint_initiator_resource * resource = list_entry
+ (
+ endpoint->initiator_resource_list.next,
+ xenidc_endpoint_initiator_resource,
+ XENIDC_ENDPOINT_INITIATOR_RESOURCE_LINK
+ );
+
+ list_del_init
+ ( xenidc_message_and_transaction_header_to_link( header ) );
+
+ list_del_init
+ ( xenidc_endpoint_initiator_resource_to_link( resource ) );
+
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+
+ xenidc_endpoint_initiator_resource_start( resource, header );
+
+ spin_lock_irqsave( &endpoint->lock, flags );
+ }
+
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+ }
+}
+
+static void xenidc_endpoint_kick_messages_and_transactions_2
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_endpoint_initiator_resource * resource =
+ xenidc_endpoint_initiator_resource_callback_to( callback );
+
+ xenidc_endpoint * endpoint =
+ xenidc_endpoint_initiator_resource_query_endpoint( resource );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &endpoint->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_endpoint_initiator_resource_to_link( resource ),
+ &endpoint->initiator_resource_list
+ );
+
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+ }
+}
+
+
+static int xenidc_endpoint_handle_message_element
+ ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference element )
+{
+ trace();
+
+ xenidc_local_buffer_reference_advance
+ ( &element, sizeof( xenidc_endpoint_message_ring_element ) );
+
+ endpoint->message( endpoint, element );
+
+ return 0;
+}
+
+static int xenidc_endpoint_handle_parameters_element
+ ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference element )
+{
+ trace();
+
+ {
+ xenidc_endpoint_target_resource * resource;
+
+ xenidc_endpoint_parameters_ring_element parameters;
+
+ if
+ (
+ (
+ xenidc_local_buffer_reference_copy_out
+ ( &element, ¶meters, sizeof( parameters ) )
+ !=
+ sizeof( parameters )
+ )
+ ||
+ (
+ (
+ xenidc_local_buffer_reference_advance
+ (
+ &element,
+ sizeof( xenidc_endpoint_parameters_ring_element )
+ )
+ +
+ parameters.status_byte_count
+ )
+ >
+ endpoint->target_transaction_maximum_byte_count
+ )
+ )
+ {
+ return -1;
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &endpoint->lock, flags );
+
+ if( list_empty( &endpoint->target_resource_list ) )
+ {
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+
+ return 1;
+ }
+
+ resource = list_entry
+ (
+ endpoint->target_resource_list.next,
+ xenidc_endpoint_target_resource,
+ XENIDC_ENDPOINT_TARGET_RESOURCE_LINK
+ );
+
+ list_del_init
+ ( xenidc_endpoint_target_resource_to_link( resource ) );
+
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+ }
+
+ xenidc_endpoint_target_resource_start
+ ( resource, parameters.id, element, parameters.status_byte_count );
+ }
+
+ return 0;
+}
+
+static void xenidc_endpoint_kick_recv_ring_2( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_endpoint_target_resource * resource =
+ xenidc_endpoint_target_resource_callback_to( callback );
+
+ xenidc_endpoint * endpoint =
+ xenidc_endpoint_target_resource_query_endpoint( resource );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &endpoint->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_endpoint_target_resource_to_link( resource ),
+ &endpoint->target_resource_list
+ );
+
+ spin_unlock_irqrestore( &endpoint->lock, flags );
+ }
+}
+
+static inline xenidc_endpoint_initiator_resource *
+ xenidc_endpoint_find_initiator_resource_from_id
+ ( xenidc_endpoint * endpoint, u32 id )
+{
+ trace();
+
+ if( id < endpoint->initiator_transaction_quota )
+ {
+ return &endpoint->initiator_resources[ id ];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+static int xenidc_endpoint_handle_status_element
+ ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference element )
+{
+ trace();
+
+ {
+ xenidc_endpoint_status_ring_element status;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ ( &element, &status, sizeof( status ) )
+ !=
+ sizeof( status )
+ )
+ {
+ goto PROTOCOL_ERROR;
+ }
+
+ xenidc_local_buffer_reference_advance( &element, sizeof( status ) );
+
+ {
+ xenidc_endpoint_initiator_resource * resource =
+ xenidc_endpoint_find_initiator_resource_from_id
+ ( endpoint, status.id );
+
+ if( resource == NULL )
+ {
+ goto PROTOCOL_ERROR;
+ }
+
+ if
+ (
+ xenidc_endpoint_initiator_resource_handle_status
+ ( resource, status.error, element )
+ !=
+ 0
+ )
+ {
+ goto PROTOCOL_ERROR;
+ }
+ }
+ }
+
+ return 0;
+
+ PROTOCOL_ERROR:
+
+ return -1;
+}
+
+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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_initiator_resource.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_initiator_resource.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,410 @@
+#include <asm-xen/xenidc_vaddress.h>
+#include "xenidc_endpoint_initiator_resource.h"
+#include "xenidc_trace.h"
+
+static void xenidc_endpoint_initiator_resource_handle_stimulus
+(
+ xenidc_endpoint_initiator_resource * resource,
+ xenidc_endpoint_initiator_resource_stimulus stimulus
+);
+
+static void xenidc_endpoint_initiator_resource_send_request_callback
+ ( xenidc_callback * callback );
+
+void xenidc_endpoint_initiator_resource_init
+(
+ xenidc_endpoint_initiator_resource * resource,
+ xenidc_endpoint * endpoint,
+ xenidc_callback_function callback,
+ int id
+)
+{
+ trace();
+
+ xenidc_callback_init( &resource->callback, callback );
+
+ resource->endpoint = endpoint;
+
+ resource->id = id;
+
+ spin_lock_init( &resource->lock );
+
+ resource->state = xenidc_endpoint_initiator_resource_state_i;
+
+ xenidc_callback_init
+ (
+ xenidc_endpoint_send_request_to_callback( &resource->send_request ),
+ xenidc_endpoint_initiator_resource_send_request_callback
+ );
+}
+
+void xenidc_endpoint_initiator_resource_start
+(
+ xenidc_endpoint_initiator_resource * resource,
+ xenidc_message_and_transaction_header * header
+)
+{
+ trace();
+
+ resource->header = header;
+
+ resource->error = XENIDC_ERROR_SUCCESS;
+
+ {
+ xenidc_endpoint_initiator_resource_stimulus stimulus;
+
+ if( header->transaction_not_message )
+ {
+ xenidc_transaction * transaction =
+ xenidc_transaction_header_to( header );
+
+ resource->element = xenidc_vaddress_create_lbr
+ (
+ &resource->parameters_element,
+ sizeof( resource->parameters_element )
+ );
+
+ resource->send_request.buffer = xenidc_concatenate_create_lbr
+ (
+ &resource->base,
+ &resource->element,
+ &transaction->parameters
+ );
+
+ memset
+ (
+ &resource->parameters_element,
+ 0,
+ sizeof( resource->parameters_element )
+ );
+
+ resource->parameters_element.header.type =
+ XENIDC_ENDPOINT_RING_ELEMENT_TYPE_PARAMETERS;
+
+ resource->parameters_element.header.length =
+ xenidc_local_buffer_reference_query_byte_count
+ ( &resource->send_request.buffer );
+
+ resource->parameters_element.id =
+ resource->id;
+
+ resource->parameters_element.status_byte_count =
+ xenidc_local_buffer_reference_query_byte_count
+ ( &transaction->status );
+
+ stimulus = xenidc_endpoint_initiator_resource_stimulus_st;
+ }
+ else
+ {
+ xenidc_message * message = xenidc_message_header_to( header );
+
+ resource->element = xenidc_vaddress_create_lbr
+ (
+ &resource->message_element,
+ sizeof( resource->message_element )
+ );
+
+ resource->send_request.buffer = xenidc_concatenate_create_lbr
+ ( &resource->base, &resource->element, &message->message );
+
+ memset
+ (
+ &resource->message_element,
+ 0,
+ sizeof( resource->message_element )
+ );
+
+ resource->parameters_element.header.type =
+ XENIDC_ENDPOINT_RING_ELEMENT_TYPE_MESSAGE;
+
+ resource->parameters_element.header.length =
+ xenidc_local_buffer_reference_query_byte_count
+ ( &resource->send_request.buffer );
+
+ stimulus = xenidc_endpoint_initiator_resource_stimulus_sm;
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ xenidc_endpoint_initiator_resource_handle_stimulus
+ ( resource, stimulus );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+
+ xenidc_endpoint_submit_send_request
+ ( resource->endpoint, &resource->send_request );
+ }
+}
+
+void xenidc_endpoint_initiator_resource_abort
+ ( xenidc_endpoint_initiator_resource * resource )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ xenidc_endpoint_initiator_resource_handle_stimulus
+ ( resource, xenidc_endpoint_initiator_resource_stimulus_ab );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+}
+
+static void xenidc_endpoint_initiator_resource_send_request_callback
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_endpoint_initiator_resource * resource = container_of
+ (
+ callback,
+ xenidc_endpoint_initiator_resource,
+ send_request.callback
+ );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ xenidc_endpoint_initiator_resource_handle_stimulus
+ ( resource, xenidc_endpoint_initiator_resource_stimulus_sc );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+}
+
+int xenidc_endpoint_initiator_resource_handle_status
+(
+ xenidc_endpoint_initiator_resource * resource,
+ xenidc_error error,
+ xenidc_local_buffer_reference status
+)
+{
+ trace();
+
+ {
+ int return_value = -1;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ if
+ (
+ (
+ resource->state
+ ==
+ xenidc_endpoint_initiator_resource_state_i_st
+ )
+ ||
+ (
+ resource->state
+ ==
+ xenidc_endpoint_initiator_resource_state_i_st_sc
+ )
+ )
+ {
+ xenidc_transaction * transaction =
+ xenidc_transaction_header_to( resource->header );
+
+ if
+ (
+ xenidc_local_buffer_reference_query_byte_count( &status )
+ ==
+ xenidc_local_buffer_reference_query_byte_count
+ ( &transaction->status )
+ )
+ {
+ xenidc_local_buffer_reference_copy
+ ( &transaction->status, &status );
+
+ resource->error = error;
+
+ xenidc_endpoint_initiator_resource_handle_stimulus
+ ( resource, xenidc_endpoint_initiator_resource_stimulus_ts );
+
+ return_value = 0;
+ }
+ }
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+
+ return return_value;
+ }
+}
+
+static void xenidc_endpoint_initiator_resource_invalid_stimulus
+(
+ xenidc_endpoint_initiator_resource * resource,
+ xenidc_endpoint_initiator_resource_stimulus stimulus
+);
+
+static void xenidc_endpoint_initiator_resource_set_aborted
+ ( xenidc_endpoint_initiator_resource * resource );
+
+static void xenidc_endpoint_initiator_resource_complete
+ ( xenidc_endpoint_initiator_resource * resource );
+
+static void xenidc_endpoint_initiator_resource_handle_stimulus
+(
+ xenidc_endpoint_initiator_resource * resource,
+ xenidc_endpoint_initiator_resource_stimulus stimulus
+)
+{
+ trace3
+ (
+ "endpoint initiator resource %p in state %d received stimulus %d",
+ resource,
+ resource->state,
+ stimulus
+ );
+
+ switch( resource->state )
+ {
+ case xenidc_endpoint_initiator_resource_state_i:
+ switch( stimulus )
+ {
+ case xenidc_endpoint_initiator_resource_stimulus_sm:
+ resource->state = xenidc_endpoint_initiator_resource_state_i_sm;
+ break;
+ case xenidc_endpoint_initiator_resource_stimulus_st:
+ resource->state = xenidc_endpoint_initiator_resource_state_i_st;
+ break;
+ case xenidc_endpoint_initiator_resource_stimulus_ab:
+ break;
+ default:
+ xenidc_endpoint_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case xenidc_endpoint_initiator_resource_state_i_sm:
+ switch( stimulus )
+ {
+ case xenidc_endpoint_initiator_resource_stimulus_ab:
+ break;
+ case xenidc_endpoint_initiator_resource_stimulus_sc:
+ resource->state = xenidc_endpoint_initiator_resource_state_i;
+ xenidc_endpoint_initiator_resource_complete( resource );
+ break;
+ default:
+ xenidc_endpoint_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case xenidc_endpoint_initiator_resource_state_i_st:
+ switch( stimulus )
+ {
+ case xenidc_endpoint_initiator_resource_stimulus_ab:
+ resource->state = xenidc_endpoint_initiator_resource_state_i_st_ab;
+ break;
+ case xenidc_endpoint_initiator_resource_stimulus_sc:
+ resource->state = xenidc_endpoint_initiator_resource_state_i_st_sc;
+ break;
+ case xenidc_endpoint_initiator_resource_stimulus_ts:
+ resource->state = xenidc_endpoint_initiator_resource_state_i_st_ts;
+ break;
+ default:
+ xenidc_endpoint_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case xenidc_endpoint_initiator_resource_state_i_st_ab:
+ switch( stimulus )
+ {
+ case xenidc_endpoint_initiator_resource_stimulus_sc:
+ resource->state = xenidc_endpoint_initiator_resource_state_i;
+ xenidc_endpoint_initiator_resource_set_aborted( resource );
+ xenidc_endpoint_initiator_resource_complete( resource );
+ break;
+ default:
+ xenidc_endpoint_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case xenidc_endpoint_initiator_resource_state_i_st_sc:
+ switch( stimulus )
+ {
+ case xenidc_endpoint_initiator_resource_stimulus_ab:
+ resource->state = xenidc_endpoint_initiator_resource_state_i;
+ xenidc_endpoint_initiator_resource_set_aborted( resource );
+ xenidc_endpoint_initiator_resource_complete( resource );
+ break;
+ case xenidc_endpoint_initiator_resource_stimulus_ts:
+ resource->state = xenidc_endpoint_initiator_resource_state_i;
+ xenidc_endpoint_initiator_resource_complete( resource );
+ break;
+ default:
+ xenidc_endpoint_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case xenidc_endpoint_initiator_resource_state_i_st_ts:
+ switch( stimulus )
+ {
+ case xenidc_endpoint_initiator_resource_stimulus_ab:
+ break;
+ case xenidc_endpoint_initiator_resource_stimulus_sc:
+ resource->state = xenidc_endpoint_initiator_resource_state_i;
+ xenidc_endpoint_initiator_resource_complete( resource );
+ break;
+ default:
+ xenidc_endpoint_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ default:
+ xenidc_endpoint_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+}
+
+static void xenidc_endpoint_initiator_resource_invalid_stimulus
+(
+ xenidc_endpoint_initiator_resource * resource,
+ xenidc_endpoint_initiator_resource_stimulus stimulus
+)
+{
+ trace();
+
+ printk
+ (
+ KERN_ERR "xenidc: endpoint initiator resource %p in state %d"
+ "received invalid stimulus %d",
+ resource,
+ resource->state,
+ stimulus
+ );
+}
+
+static void xenidc_endpoint_initiator_resource_set_aborted
+ ( xenidc_endpoint_initiator_resource * resource )
+{
+ trace();
+
+ resource->error = XENIDC_ERROR_ABORTED;
+}
+
+static void xenidc_endpoint_initiator_resource_complete
+ ( xenidc_endpoint_initiator_resource * resource )
+{
+ trace();
+
+ xenidc_callback_complete( &resource->header->callback, resource->error );
+
+ xenidc_callback_success( &resource->callback );
+}
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_initiator_resource.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_initiator_resource.h Mon Oct 24 15:04:49 2005
@@ -0,0 +1,95 @@
+#ifndef _XENIDC_ENDPOINT_INITIATOR_RESOURCE_H
+#define _XENIDC_ENDPOINT_INITIATOR_RESOURCE_H
+
+#include <asm-xen/xenidc.h>
+#include <asm-xen/xenidc_concatenate.h>
+#include "xenidc_endpoint_ring.h"
+#include "xenidc_endpoint_send_request.h"
+
+typedef enum
+{
+ xenidc_endpoint_initiator_resource_state_i,
+ xenidc_endpoint_initiator_resource_state_i_sm,
+ xenidc_endpoint_initiator_resource_state_i_st,
+ xenidc_endpoint_initiator_resource_state_i_st_ab,
+ xenidc_endpoint_initiator_resource_state_i_st_sc,
+ xenidc_endpoint_initiator_resource_state_i_st_ts
+}
+xenidc_endpoint_initiator_resource_state;
+
+typedef enum
+{
+ xenidc_endpoint_initiator_resource_stimulus_sm, /* Start message */
+ xenidc_endpoint_initiator_resource_stimulus_st, /* Start transaction */
+ xenidc_endpoint_initiator_resource_stimulus_ab, /* Abort */
+ xenidc_endpoint_initiator_resource_stimulus_sc, /* Send complete */
+ xenidc_endpoint_initiator_resource_stimulus_ts, /* Transaction status */
+}
+xenidc_endpoint_initiator_resource_stimulus;
+
+struct xenidc_endpoint_initiator_resource_struct
+{
+ xenidc_callback callback;
+ xenidc_endpoint * endpoint;
+ int id;
+ spinlock_t lock;
+ xenidc_endpoint_initiator_resource_state state;
+ xenidc_message_and_transaction_header * header;
+ xenidc_error error;
+ xenidc_endpoint_send_request send_request;
+ xenidc_local_buffer_reference element;
+ xenidc_concatenate_base base;
+ union
+ {
+ xenidc_endpoint_parameters_ring_element parameters_element;
+ xenidc_endpoint_message_ring_element message_element;
+ };
+};
+
+#define XENIDC_ENDPOINT_INITIATOR_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK
+
+static inline struct list_head * xenidc_endpoint_initiator_resource_to_link
+ ( xenidc_endpoint_initiator_resource* resource )
+{
+ return &resource->XENIDC_ENDPOINT_INITIATOR_RESOURCE_LINK;
+}
+
+static inline xenidc_endpoint_initiator_resource *
+ xenidc_endpoint_initiator_resource_callback_to( xenidc_callback * callback )
+{
+ return container_of
+ ( callback, xenidc_endpoint_initiator_resource, callback );
+}
+
+static inline xenidc_endpoint *
+ xenidc_endpoint_initiator_resource_query_endpoint
+ ( xenidc_endpoint_initiator_resource* resource )
+{
+ return resource->endpoint;
+}
+
+void xenidc_endpoint_initiator_resource_init
+(
+ xenidc_endpoint_initiator_resource * resource,
+ xenidc_endpoint * endpoint,
+ xenidc_callback_function callback,
+ int id
+);
+
+void xenidc_endpoint_initiator_resource_start
+(
+ xenidc_endpoint_initiator_resource * resource,
+ xenidc_message_and_transaction_header * header
+);
+
+void xenidc_endpoint_initiator_resource_abort
+ ( xenidc_endpoint_initiator_resource * resource );
+
+int xenidc_endpoint_initiator_resource_handle_status
+(
+ xenidc_endpoint_initiator_resource * resource,
+ xenidc_error error,
+ xenidc_local_buffer_reference status
+);
+
+#endif
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_target_resource.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_target_resource.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,134 @@
+#include <asm-xen/xenidc_vaddress.h>
+#include "xenidc_endpoint_target_resource.h"
+#include "xenidc_trace.h"
+
+static void xenidc_endpoint_target_resource_transaction_callback
+ ( xenidc_callback * callback );
+
+static void xenidc_endpoint_target_resource_send_request_callback
+ ( xenidc_callback * callback );
+
+void xenidc_endpoint_target_resource_init
+(
+ xenidc_endpoint_target_resource * resource,
+ xenidc_endpoint * endpoint,
+ xenidc_callback_function callback,
+ xenidc_local_buffer_reference buffer
+)
+{
+ trace();
+
+ xenidc_callback_init( &resource->callback, callback );
+
+ resource->endpoint = endpoint;
+
+ resource->buffer = buffer;
+
+ xenidc_transaction_init
+ (
+ &resource->transaction,
+ xenidc_endpoint_target_resource_transaction_callback
+ );
+
+ xenidc_callback_init
+ (
+ xenidc_endpoint_send_request_to_callback( &resource->send_request ),
+ xenidc_endpoint_target_resource_send_request_callback
+ );
+
+ resource->element = xenidc_vaddress_create_lbr
+ ( &resource->status, sizeof( resource->status ) );
+
+ memset( &resource->status, 0, sizeof( resource->status ) );
+
+ resource->status.header.type = XENIDC_ENDPOINT_RING_ELEMENT_TYPE_STATUS;
+}
+
+void xenidc_endpoint_target_resource_start
+(
+ xenidc_endpoint_target_resource * resource,
+ u32 id,
+ xenidc_local_buffer_reference parameters,
+ xenidc_buffer_byte_count status_byte_count
+)
+{
+ trace();
+
+ resource->status.id = id;
+
+ {
+ xenidc_local_buffer_reference lbr = resource->buffer;
+
+ xenidc_local_buffer_reference_truncate
+ ( &lbr, xenidc_local_buffer_reference_copy( &lbr, ¶meters ) );
+
+ xenidc_transaction_set_parameters_lbr( &resource->transaction, lbr );
+ }
+
+ {
+ xenidc_local_buffer_reference lbr = resource->buffer;
+
+ xenidc_local_buffer_reference_advance
+ (
+ &lbr,
+ xenidc_local_buffer_reference_query_byte_count( ¶meters )
+ );
+
+ xenidc_local_buffer_reference_truncate( &lbr, status_byte_count );
+
+ xenidc_local_buffer_reference_zero( &lbr );
+
+ xenidc_transaction_set_status_lbr( &resource->transaction, lbr );
+ }
+
+ resource->endpoint->transaction
+ ( resource->endpoint, &resource->transaction );
+}
+
+static void xenidc_endpoint_target_resource_transaction_callback
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_endpoint_target_resource * resource = container_of
+ (
+ xenidc_transaction_callback_to( callback ),
+ xenidc_endpoint_target_resource,
+ transaction
+ );
+
+ resource->status.error = xenidc_callback_query_error( callback );
+
+ resource->send_request.buffer = xenidc_concatenate_create_lbr
+ (
+ &resource->base,
+ &resource->element,
+ &resource->transaction.status
+ );
+
+ resource->status.header.length =
+ xenidc_local_buffer_reference_query_byte_count
+ ( &resource->send_request.buffer );
+
+ xenidc_endpoint_submit_send_request
+ ( resource->endpoint, &resource->send_request );
+ }
+}
+
+static void xenidc_endpoint_target_resource_send_request_callback
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_endpoint_target_resource * resource = container_of
+ (
+ callback,
+ xenidc_endpoint_target_resource,
+ send_request.callback
+ );
+
+ xenidc_callback_success( &resource->callback );
+ }
+}
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_target_resource.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_target_resource.h Mon Oct 24 15:04:49 2005
@@ -0,0 +1,58 @@
+#ifndef _XENIDC_ENDPOINT_TARGET_RESOURCE_H
+#define _XENIDC_ENDPOINT_TARGET_RESOURCE_H
+
+#include <asm-xen/xenidc.h>
+#include <asm-xen/xenidc_concatenate.h>
+#include "xenidc_endpoint_ring.h"
+#include "xenidc_endpoint_send_request.h"
+
+struct xenidc_endpoint_target_resource_struct
+{
+ xenidc_callback callback;
+ xenidc_endpoint * endpoint;
+ xenidc_local_buffer_reference buffer;
+ xenidc_transaction transaction;
+ xenidc_endpoint_send_request send_request;
+ xenidc_local_buffer_reference element;
+ xenidc_concatenate_base base;
+ xenidc_endpoint_status_ring_element status;
+};
+
+#define XENIDC_ENDPOINT_TARGET_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK
+
+static inline struct list_head * xenidc_endpoint_target_resource_to_link
+ ( xenidc_endpoint_target_resource * resource )
+{
+ return &resource->XENIDC_ENDPOINT_TARGET_RESOURCE_LINK;
+}
+
+static inline xenidc_endpoint_target_resource *
+ xenidc_endpoint_target_resource_callback_to( xenidc_callback * callback )
+{
+ return container_of
+ ( callback, xenidc_endpoint_target_resource, callback );
+}
+
+static inline xenidc_endpoint * xenidc_endpoint_target_resource_query_endpoint
+ ( xenidc_endpoint_target_resource* resource )
+{
+ return resource->endpoint;
+}
+
+extern void xenidc_endpoint_target_resource_init
+(
+ xenidc_endpoint_target_resource * resource,
+ xenidc_endpoint * endpoint,
+ xenidc_callback_function callback,
+ xenidc_local_buffer_reference buffer
+);
+
+extern void xenidc_endpoint_target_resource_start
+(
+ xenidc_endpoint_target_resource * resource,
+ u32 id,
+ xenidc_local_buffer_reference parameters,
+ xenidc_buffer_byte_count status_byte_count
+);
+
+#endif
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gnttab_channel.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gnttab_channel.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,1297 @@
+/*****************************************************************************/
+/* Xen inter-domain communication channel 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_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_trb, /* target resources busy */
+ xenidc_gnttab_channel_stimulus_trc, /* target resource completed */
+ xenidc_gnttab_channel_stimulus_tri, /* target resources idle */
+ xenidc_gnttab_channel_stimulus_err /* protocol error */
+}
+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
+ );
+
+ INIT_LIST_HEAD( &channel->free_target_resource_list );
+
+ {
+ 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
+ );
+
+ list_add_tail
+ (
+ xenidc_gnttab_channel_target_resource_to_link( resource ),
+ &channel->free_target_resource_list
+ );
+ }
+ }
+
+ channel->target_resources_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_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_handle_stimulus
+ ( xenidc_gnttab_channel * channel, xenidc_gnttab_channel_stimulus stimulus )
+{
+ trace3
+ (
+ "channel %p in state %d received stimulus %d",
+ channel,
+ channel->state,
+ stimulus
+ );
+
+ /* FIXME: implement state machine */
+
+ switch( channel->state )
+ {
+ case xenidc_gnttab_channel_state_i:
+ switch( stimulus )
+ {
+ 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;
+ }
+
+ {
+ 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 make sure other side is no longer 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();
+
+ (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;
+
+ /* Create a reference to the send ring buffer. */
+
+ xenidc_local_buffer_reference ring_buffer_reference =
+ 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. */
+
+ xenidc_local_buffer_reference wrapping_lbr = xenidc_wrapping_create_lbr
+ (
+ &ring_buffer_reference,
+ ( (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
+ );
+
+ xenidc_channel_message * message;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ while
+ (
+ ( !list_empty( &channel->message_list ) )
+ &&
+ (
+ xenidc_local_buffer_reference_query_byte_count( &wrapping_lbr )
+ >
+ xenidc_local_buffer_reference_query_byte_count
+ (
+ &
+ (
+ message = list_entry
+ (
+ channel->message_list.next,
+ xenidc_channel_message,
+ XENIDC_CHANNEL_MESSAGE_LINK
+ )
+ )
+ ->lbr
+ )
+ )
+ )
+ {
+ list_del_init( xenidc_channel_message_to_link( message ) );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+
+ xenidc_local_buffer_reference_advance
+ (
+ &wrapping_lbr,
+ xenidc_local_buffer_reference_copy
+ ( &wrapping_lbr, &message->lbr )
+ );
+
+ xenidc_callback_success
+ ( xenidc_channel_message_to_callback( message ) );
+
+ notify = 1;
+
+ spin_lock_irqsave( &channel->lock, flags );
+ }
+
+ 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 );
+
+ 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();
+
+ (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 notify = 0;
+ int error = 0;
+
+ /* Create a reference to the recv ring buffer. */
+
+ xenidc_local_buffer_reference ring_buffer_reference =
+ xenidc_vaddress_create_lbr
+ (
+ (
+ (xenidc_channel_ring_header *)
+ channel->recv_ring_area->addr
+ ) + 1,
+ PAGE_SIZE - sizeof( xenidc_channel_ring_header )
+ );
+
+ /* Create a reference to the elements in the recv ring buffer. */
+ /* We use a wrapping reference to the above buffer so that we can */
+ /* copy out of the buffer and wrap automatically. */
+
+ xenidc_local_buffer_reference wrapping_lbr = xenidc_wrapping_create_lbr
+ (
+ &ring_buffer_reference,
+ ( (xenidc_channel_ring_header *)channel->send_ring )->
+ other_ring_consumer_offset,
+ (
+ (xenidc_channel_ring_header *)
+ channel->recv_ring_area->addr
+ )
+ ->this_ring_producer_offset,
+ xenidc_wrapping_client_type_consumer
+ );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ rmb(); /* Ensure we see latest data for contents of wrapping buffer. */
+
+ while
+ (
+ ( !list_empty( &channel->free_target_resource_list ) )
+ &&
+ (
+ xenidc_local_buffer_reference_query_byte_count( &wrapping_lbr )
+ !=
+ 0
+ )
+ )
+ {
+ xenidc_local_buffer_reference element = wrapping_lbr;
+
+ xenidc_gnttab_channel_target_resource * resource = list_entry
+ (
+ channel->free_target_resource_list.next,
+ xenidc_gnttab_channel_target_resource,
+ XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_LINK
+ );
+
+ {
+ xenidc_channel_ring_element_header header;
+
+ if
+ (
+ (
+ xenidc_local_buffer_reference_copy_out
+ ( &wrapping_lbr, &header, sizeof( header ) )
+ ==
+ sizeof( header )
+ )
+ &&
+ (
+ xenidc_local_buffer_reference_truncate
+ ( &element, header.length )
+ ==
+ header.length
+ )
+ )
+ {
+ list_del_init
+ (
+ xenidc_gnttab_channel_target_resource_to_link
+ ( resource )
+ );
+
+ if( channel->target_resources_out++ == 0 )
+ {
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_trb );
+ }
+ }
+ else
+ {
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_err );
+
+ error = 1;
+
+ break;
+ }
+
+ xenidc_local_buffer_reference_advance
+ ( &wrapping_lbr, header.length );
+ }
+
+ 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 );
+ }
+
+ notify = 1;
+
+ spin_lock_irqsave( &channel->lock, flags );
+ }
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+
+ if( notify )
+ {
+ mb(); /* Ensure reads complete before we free space. */
+
+ ( (xenidc_channel_ring_header *)channel->send_ring )->
+ other_ring_consumer_offset =
+ xenidc_local_buffer_reference_query_byte_offset
+ ( &wrapping_lbr );
+
+ notify_remote_via_irq( channel->recv_irq );
+ }
+
+ if( error )
+ {
+ channel->protocol_error( channel );
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ 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 error =
+ ( xenidc_callback_query_error( callback ) != XENIDC_ERROR_SUCCESS );
+
+ if( error )
+ {
+ channel->protocol_error( channel );
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_gnttab_channel_target_resource_to_link( resource ),
+ &channel->free_target_resource_list
+ );
+
+ if( error )
+ {
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_err );
+ }
+
+ if( --channel->target_resources_out != 0 )
+ {
+ 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 ) );
+ }
+}
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_local_buffer_reference.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_local_buffer_reference.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,55 @@
+/*****************************************************************************/
+/* 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/module.h>
+#include "xenidc_trace.h"
+
+xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_out
+(
+ xenidc_local_buffer_reference * buffer_reference,
+ void * target,
+ xenidc_buffer_byte_count target_byte_count
+)
+{
+ trace();
+
+ /* FIXME */
+
+ return 0;
+}
+
+xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_in
+(
+ xenidc_local_buffer_reference * buffer_reference,
+ void * source,
+ xenidc_buffer_byte_count source_byte_count
+)
+{
+ trace();
+
+ /* FIXME */
+
+ return 0;
+}
+
+EXPORT_SYMBOL( xenidc_local_buffer_reference_copy_out );
+EXPORT_SYMBOL( xenidc_local_buffer_reference_copy_in );
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_mapper_pool.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_mapper_pool.c Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_provider_pool.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_provider_pool.c Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_trace.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_trace.h Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_vaddress.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_vaddress.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,42 @@
+/*****************************************************************************/
+/* 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"
+
+xenidc_local_buffer_reference xenidc_vaddress_create_lbr
+ ( void * address, xenidc_buffer_byte_count byte_count )
+{
+ trace();
+
+ /* FIXME */
+
+ {
+ xenidc_local_buffer_reference lbr;
+
+ memset( &lbr, 0, sizeof( lbr ) );
+
+ return lbr;
+ }
+}
+
+EXPORT_SYMBOL( xenidc_vaddress_create_lbr );
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_work.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_work.c Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_wrapping.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_wrapping.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,47 @@
+/*****************************************************************************/
+/* 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"
+
+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();
+
+ /* FIXME */
+
+ {
+ xenidc_local_buffer_reference lbr;
+
+ memset( &lbr, 0, sizeof( lbr ) );
+
+ return lbr;
+ }
+}
+
+EXPORT_SYMBOL( xenidc_wrapping_create_lbr );
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel.c
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel.c Mon Oct 24 15:04:49 2005
@@ -0,0 +1,1732 @@
+/*****************************************************************************/
+/* Xen inter-domain communication channel implementation based on xenbus and */
+/* grant tables. */
+/* */
+/* 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 the 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;
+
+ 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.dot
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.dot Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.ps
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.ps Mon Oct 24 15:04:49 2005
@@ -0,0 +1,2497 @@
+%!PS-Adobe-2.0
+%%Creator: dot version 2.2.1 (Tue Apr 12 00:03:35 UTC 2005)
+%%For: (harry) harry,,,
+%%Title: enumeration
+%%Pages: (atend)
+%%BoundingBox: 35 35 541 513
+%%EndComments
+save
+%%BeginProlog
+/DotDict 200 dict def
+DotDict begin
+
+/setupLatin1 {
+mark
+/EncodingVector 256 array def
+ EncodingVector 0
+
+ISOLatin1Encoding 0 255 getinterval putinterval
+
+EncodingVector
+ dup 306 /AE
+ dup 301 /Aacute
+ dup 302 /Acircumflex
+ dup 304 /Adieresis
+ dup 300 /Agrave
+ dup 305 /Aring
+ dup 303 /Atilde
+ dup 307 /Ccedilla
+ dup 311 /Eacute
+ dup 312 /Ecircumflex
+ dup 313 /Edieresis
+ dup 310 /Egrave
+ dup 315 /Iacute
+ dup 316 /Icircumflex
+ dup 317 /Idieresis
+ dup 314 /Igrave
+ dup 334 /Udieresis
+ dup 335 /Yacute
+ dup 376 /thorn
+ dup 337 /germandbls
+ dup 341 /aacute
+ dup 342 /acircumflex
+ dup 344 /adieresis
+ dup 346 /ae
+ dup 340 /agrave
+ dup 345 /aring
+ dup 347 /ccedilla
+ dup 351 /eacute
+ dup 352 /ecircumflex
+ dup 353 /edieresis
+ dup 350 /egrave
+ dup 355 /iacute
+ dup 356 /icircumflex
+ dup 357 /idieresis
+ dup 354 /igrave
+ dup 360 /dcroat
+ dup 361 /ntilde
+ dup 363 /oacute
+ dup 364 /ocircumflex
+ dup 366 /odieresis
+ dup 362 /ograve
+ dup 365 /otilde
+ dup 370 /oslash
+ dup 372 /uacute
+ dup 373 /ucircumflex
+ dup 374 /udieresis
+ dup 371 /ugrave
+ dup 375 /yacute
+ dup 377 /ydieresis
+
+% Set up ISO Latin 1 character encoding
+/starnetISO {
+ dup dup findfont dup length dict begin
+ { 1 index /FID ne { def }{ pop pop } ifelse
+ } forall
+ /Encoding EncodingVector def
+ currentdict end definefont
+} def
+/Times-Roman starnetISO def
+/Times-Italic starnetISO def
+/Times-Bold starnetISO def
+/Times-BoldItalic starnetISO def
+/Helvetica starnetISO def
+/Helvetica-Oblique starnetISO def
+/Helvetica-Bold starnetISO def
+/Helvetica-BoldOblique starnetISO def
+/Courier starnetISO def
+/Courier-Oblique starnetISO def
+/Courier-Bold starnetISO def
+/Courier-BoldOblique starnetISO def
+cleartomark
+} bind def
+
+%%BeginResource: procset graphviz 0 0
+/coord-font-family /Times-Roman def
+/default-font-family /Times-Roman def
+/coordfont coord-font-family findfont 8 scalefont def
+
+/InvScaleFactor 1.0 def
+/set_scale {
+ dup 1 exch div /InvScaleFactor exch def
+ dup scale
+} bind def
+
+% styles
+/solid { [] 0 setdash } bind def
+/dashed { [9 InvScaleFactor mul dup ] 0 setdash } bind def
+/dotted { [1 InvScaleFactor mul 6 InvScaleFactor mul] 0 setdash } bind def
+/invis {/fill {newpath} def /stroke {newpath} def /show {pop newpath} def} bind def
+/bold { 2 setlinewidth } bind def
+/filled { } bind def
+/unfilled { } bind def
+/rounded { } bind def
+/diagonals { } bind def
+
+% hooks for setting color
+/nodecolor { sethsbcolor } bind def
+/edgecolor { sethsbcolor } bind def
+/graphcolor { sethsbcolor } bind def
+/nopcolor {pop pop pop} bind def
+
+/beginpage { % i j npages
+ /npages exch def
+ /j exch def
+ /i exch def
+ /str 10 string def
+ npages 1 gt {
+ gsave
+ coordfont setfont
+ 0 0 moveto
+ (\() show i str cvs show (,) show j str cvs show (\)) show
+ grestore
+ } if
+} bind def
+
+/set_font {
+ findfont exch
+ scalefont setfont
+} def
+
+% draw aligned label in bounding box aligned to current point
+/alignedtext { % width adj text
+ /text exch def
+ /adj exch def
+ /width exch def
+ gsave
+ width 0 gt {
+ text stringwidth pop adj mul 0 rmoveto
+ } if
+ [] 0 setdash
+ text show
+ grestore
+} def
+
+/boxprim { % xcorner ycorner xsize ysize
+ 4 2 roll
+ moveto
+ 2 copy
+ exch 0 rlineto
+ 0 exch rlineto
+ pop neg 0 rlineto
+ closepath
+} bind def
+
+/ellipse_path {
+ /ry exch def
+ /rx exch def
+ /y exch def
+ /x exch def
+ matrix currentmatrix
+ newpath
+ x y translate
+ rx ry scale
+ 0 0 1 0 360 arc
+ setmatrix
+} bind def
+
+/endpage { showpage } bind def
+/showpage { } def
+
+/layercolorseq
+ [ % layer color sequence - darkest to lightest
+ [0 0 0]
+ [.2 .8 .8]
+ [.4 .8 .8]
+ [.6 .8 .8]
+ [.8 .8 .8]
+ ]
+def
+
+/layerlen layercolorseq length def
+
+/setlayer {/maxlayer exch def /curlayer exch def
+ layercolorseq curlayer 1 sub layerlen mod get
+ aload pop sethsbcolor
+ /nodecolor {nopcolor} def
+ /edgecolor {nopcolor} def
+ /graphcolor {nopcolor} def
+} bind def
+
+/onlayer { curlayer ne {invis} if } def
+
+/onlayers {
+ /myupper exch def
+ /mylower exch def
+ curlayer mylower lt
+ curlayer myupper gt
+ or
+ {invis} if
+} def
+
+/curlayer 0 def
+
+%%EndResource
+%%EndProlog
+%%BeginSetup
+14 default-font-family set_font
+1 setmiterlimit
+% /arrowlength 10 def
+% /arrowwidth 5 def
+
+% make sure pdfmark is harmless for PS-interpreters other than Distiller
+/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse
+% make '<<' and '>>' safe on PS Level 1 devices
+/languagelevel where {pop languagelevel}{1} ifelse
+2 lt {
+ userdict (<<) cvn ([) cvn load put
+ userdict (>>) cvn ([) cvn load put
+} if
+
+%%EndSetup
+%%Page: 1 1
+%%PageBoundingBox: 36 36 541 513
+%%PageOrientation: Portrait
+gsave
+35 35 506 478 boxprim clip newpath
+36 36 translate
+0 0 1 beginpage
+0.2979 set_scale
+0 0 translate 0 rotate
+0.000 0.000 0.000 graphcolor
+14.00 /Times-Roman set_font
+
+% i
+gsave 10 dict begin
+filled
+0.333 1.000 1.000 nodecolor
+1441 1582 27 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+1441 1582 27 18 ellipse_path
+stroke
+gsave 10 dict begin
+1441 1577 moveto 5.0 -0.5 (i) alignedtext
+end grestore
+end grestore
+
+% i_cn
+gsave 10 dict begin
+filled
+0.333 1.000 1.000 nodecolor
+1283 1478 27 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+1283 1478 27 18 ellipse_path
+stroke
+gsave 10 dict begin
+1270 1473 moveto
+(i_cn)
+[3.84 6.96 6.24 6.96]
+xshow
+end grestore
+end grestore
+
+% i -> i_cn
+newpath 1415 1577 moveto
+1383 1570 1331 1558 1316 1546 curveto
+1304 1536 1296 1519 1290 1505 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1293 1504 moveto
+1287 1496 lineto
+1287 1507 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1293 1504 moveto
+1287 1496 lineto
+1287 1507 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1366 1533 moveto
+(cn)
+[6.24 6.96]
+xshow
+1317 1517 moveto
+(phase_one_connect)
+[6.96 6.96 6.24 5.52 6.24 6.96 6.96 6.96 6.24 6.96 6.24 6.96 6.96 6.96 6.24 6.24 3.84]
+xshow
+end grestore
+
+% i_cn_dn
+gsave 10 dict begin
+filled
+0.106 1.000 1.000 nodecolor
+1283 1320 36 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+1283 1320 36 18 ellipse_path
+stroke
+gsave 10 dict begin
+1259 1315 moveto
+(i_cn_dn)
+[3.84 6.96 6.24 6.96 6.96 6.96 6.96]
+xshow
+end grestore
+end grestore
+
+% i_cn -> i_cn_dn
+newpath 1283 1460 moveto
+1283 1432 1283 1381 1283 1348 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1287 1348 moveto
+1283 1338 lineto
+1280 1348 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1287 1348 moveto
+1283 1338 lineto
+1280 1348 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1282 1421 moveto
+(dn)
+[6.96 6.96]
+xshow
+end grestore
+
+% i_cn_rs
+gsave 10 dict begin
+filled
+0.333 1.000 1.000 nodecolor
+836 1374 34 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+836 1374 34 18 ellipse_path
+stroke
+gsave 10 dict begin
+814 1369 moveto
+(i_cn_rs)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52]
+xshow
+end grestore
+end grestore
+
+% i_cn -> i_cn_rs
+newpath 1257 1472 moveto
+1183 1455 968 1405 877 1383 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 877 1380 moveto
+867 1381 lineto
+876 1386 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 877 1380 moveto
+867 1381 lineto
+876 1386 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1161 1429 moveto
+(rs)
+[4.56 5.52]
+xshow
+1125 1413 moveto
+(register_watch)
+[4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96]
+xshow
+end grestore
+
+% i_cn_dn_rs
+gsave 10 dict begin
+filled
+0.106 1.000 1.000 nodecolor
+1179 122 45 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+1179 122 45 18 ellipse_path
+stroke
+gsave 10 dict begin
+1147 117 moveto
+(i_cn_dn_rs)
+[3.84 6.96 6.24 6.96 6.96 6.96 6.96 6.96 4.56 5.52]
+xshow
+end grestore
+end grestore
+
+% i_cn_dn -> i_cn_dn_rs
+newpath 1283 1302 moveto
+1283 1281 1283 1245 1283 1214 curveto
+1283 1214 1283 1214 1283 226 curveto
+1283 187 1247 158 1218 141 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1219 138 moveto
+1209 136 lineto
+1216 144 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1219 138 moveto
+1209 136 lineto
+1216 144 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1308 749 moveto
+(rs)
+[4.56 5.52]
+xshow
+1283 733 moveto
+(clear_store)
+[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24]
+xshow
+end grestore
+
+% i_cn_rs -> i_cn_rs
+newpath 860 1361 moveto
+874 1359 888 1363 888 1374 curveto
+888 1382 880 1387 870 1387 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 870 1384 moveto
+860 1387 lineto
+870 1391 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 870 1384 moveto
+860 1387 lineto
+870 1391 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+887 1369 moveto
+(pe/od/or/oc)
+[6.96 6.24 3.84 6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24]
+xshow
+end grestore
+
+% i_cn_rs_dn
+gsave 10 dict begin
+filled
+0.106 1.000 1.000 nodecolor
+1145 330 45 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+1145 330 45 18 ellipse_path
+stroke
+gsave 10 dict begin
+1113 325 moveto
+(i_cn_rs_dn)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 6.96 6.96]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs -> i_cn_rs_dn
+newpath 869 1370 moveto
+952 1359 1160 1326 1160 1266 curveto
+1160 1266 1160 1266 1160 902 curveto
+1160 752 1260 721 1234 574 curveto
+1219 491 1179 401 1158 357 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1161 356 moveto
+1154 348 lineto
+1155 359 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1161 356 moveto
+1154 348 lineto
+1155 359 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1165 845 moveto
+(dn)
+[6.96 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs
+gsave 10 dict begin
+filled
+0.333 1.000 1.000 nodecolor
+545 1266 43 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+545 1266 43 18 ellipse_path
+stroke
+gsave 10 dict begin
+515 1261 moveto
+(i_cn_rs_rs)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs -> i_cn_rs_rs
+newpath 808 1364 moveto
+757 1345 647 1304 587 1282 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 588 1278 moveto
+577 1278 lineto
+585 1285 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 588 1278 moveto
+577 1278 lineto
+585 1285 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+768 1323 moveto
+(rs)
+[4.56 5.52]
+xshow
+743 1307 moveto
+(clear_store)
+[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rf
+gsave 10 dict begin
+filled
+0.000 1.000 1.000 nodecolor
+1094 642 42 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+1094 642 42 18 ellipse_path
+stroke
+gsave 10 dict begin
+1064 637 moveto
+(i_cn_rs_rf)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 4.56]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs -> i_cn_rs_rf
+newpath 870 1372 moveto
+951 1368 1149 1355 1174 1338 curveto
+1201 1317 1203 1300 1203 1266 curveto
+1203 1266 1203 1266 1203 902 curveto
+1203 802 1241 758 1182 678 curveto
+1172 665 1158 657 1143 652 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1144 649 moveto
+1133 649 lineto
+1142 655 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1144 649 moveto
+1133 649 lineto
+1142 655 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1228 1009 moveto
+(rf)
+[4.56 4.56]
+xshow
+1203 993 moveto
+(clear_store)
+[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24]
+xshow
+end grestore
+
+% i_cn_dn_rs_rs
+gsave 10 dict begin
+filled
+0.106 1.000 1.000 nodecolor
+1354 18 53 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+1354 18 53 18 ellipse_path
+stroke
+gsave 10 dict begin
+1313 13 moveto
+(i_cn_dn_rs_rs)
+[3.84 6.96 6.24 6.96 6.96 6.96 6.96 6.96 4.56 5.52 6.96 4.56 5.52]
+xshow
+end grestore
+end grestore
+
+% i_cn_dn_rs -> i_cn_dn_rs_rs
+newpath 1183 104 moveto
+1188 88 1197 67 1213 54 curveto
+1226 43 1263 34 1296 28 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1297 31 moveto
+1306 26 lineto
+1296 25 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1297 31 moveto
+1306 26 lineto
+1296 25 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1263 73 moveto
+(rs/rf)
+[4.56 5.52 3.84 4.56 4.56]
+xshow
+1212 57 moveto
+(phase_one_disconnect)
+[6.96 6.96 6.24 5.52 6.24 6.96 6.96 6.96 6.24 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84]
+xshow
+end grestore
+
+% i_cn_rs_dn -> i_cn_dn_rs
+newpath 1148 312 moveto
+1154 275 1168 194 1174 150 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1177 150 moveto
+1176 140 lineto
+1171 149 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1177 150 moveto
+1176 140 lineto
+1171 149 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1188 229 moveto
+(rf)
+[4.56 4.56]
+xshow
+1163 213 moveto
+(clear_store)
+[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24]
+xshow
+end grestore
+
+% i_cn_rs_dn -> i_cn_rs_dn
+newpath 1176 317 moveto
+1193 315 1208 319 1208 330 curveto
+1208 339 1198 343 1186 343 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1186 340 moveto
+1176 343 lineto
+1186 347 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1186 340 moveto
+1176 343 lineto
+1186 347 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1207 325 moveto
+(od/or/oc)
+[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24]
+xshow
+end grestore
+
+% i_cn_rs_dn_rs
+gsave 10 dict begin
+filled
+0.106 1.000 1.000 nodecolor
+906 226 53 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+906 226 53 18 ellipse_path
+stroke
+gsave 10 dict begin
+865 221 moveto
+(i_cn_rs_dn_rs)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_dn -> i_cn_rs_dn_rs
+newpath 1115 316 moveto
+1100 310 1083 301 1067 294 curveto
+1037 280 1030 274 1001 262 curveto
+985 255 968 249 953 243 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 954 239 moveto
+943 239 lineto
+951 246 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 954 239 moveto
+943 239 lineto
+951 246 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1113 281 moveto
+(rs)
+[4.56 5.52]
+xshow
+1070 265 moveto
+(unregister_watch)
+[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs -> i_cn_rs_rs
+newpath 575 1253 moveto
+591 1251 606 1255 606 1266 curveto
+606 1275 597 1279 585 1279 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 585 1276 moveto
+575 1279 lineto
+585 1283 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 585 1276 moveto
+575 1279 lineto
+585 1283 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+606 1261 moveto
+(od/or/oc)
+[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_dn
+gsave 10 dict begin
+filled
+0.106 1.000 1.000 nodecolor
+600 330 53 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+600 330 53 18 ellipse_path
+stroke
+gsave 10 dict begin
+559 325 moveto
+(i_cn_rs_rs_dn)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_rs -> i_cn_rs_rs_dn
+newpath 502 1265 moveto
+498 1264 494 1264 493 1264 curveto
+425 1248 371 1232 371 1162 curveto
+371 1162 371 1162 371 1006 curveto
+371 770 43 825 43 590 curveto
+43 590 43 590 43 434 curveto
+43 338 370 357 465 350 curveto
+473 349 527 350 534 348 curveto
+538 346 540 344 542 342 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 545 344 moveto
+548 334 lineto
+539 340 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 545 344 moveto
+548 334 lineto
+539 340 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+240 793 moveto
+(dn)
+[6.96 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs
+gsave 10 dict begin
+filled
+0.333 1.000 1.000 nodecolor
+782 1162 51 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+782 1162 51 18 ellipse_path
+stroke
+gsave 10 dict begin
+743 1157 moveto
+(i_cn_rs_rs_rs)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_rs -> i_cn_rs_rs_rs
+newpath 575 1253 moveto
+617 1234 693 1201 741 1180 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 742 1183 moveto
+750 1176 lineto
+739 1177 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 742 1183 moveto
+750 1176 lineto
+739 1177 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+739 1217 moveto
+(rs)
+[4.56 5.52]
+xshow
+700 1201 moveto
+(test_other_state)
+[3.84 6.24 5.52 3.84 6.96 6.96 3.84 6.96 6.24 4.56 6.96 5.52 3.84 6.24 3.84 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_rf
+gsave 10 dict begin
+filled
+0.000 1.000 1.000 nodecolor
+936 746 51 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+936 746 51 18 ellipse_path
+stroke
+gsave 10 dict begin
+898 741 moveto
+(i_cn_rs_rs_rf)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 4.56]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_rs -> i_cn_rs_rs_rf
+newpath 588 1263 moveto
+708 1253 1047 1265 1047 1162 curveto
+1047 1162 1047 1162 1047 954 curveto
+1047 923 1046 914 1035 886 curveto
+1011 827 997 807 961 770 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 964 768 moveto
+954 763 lineto
+959 773 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 964 768 moveto
+954 763 lineto
+959 773 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1090 1009 moveto
+(rf)
+[4.56 4.56]
+xshow
+1047 993 moveto
+(unregister_watch)
+[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rf -> i_cn_dn_rs
+newpath 1088 624 moveto
+1071 571 1029 415 1091 312 curveto
+1099 297 1112 306 1123 294 curveto
+1161 244 1142 217 1162 158 curveto
+1163 155 1163 152 1164 149 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1167 149 moveto
+1165 139 lineto
+1161 149 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1167 149 moveto
+1165 139 lineto
+1161 149 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1065 377 moveto
+(dn)
+[6.96 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rf_rs
+gsave 10 dict begin
+filled
+0.000 1.000 1.000 nodecolor
+1362 538 51 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+1362 538 51 18 ellipse_path
+stroke
+gsave 10 dict begin
+1324 533 moveto
+(i_cn_rs_rf_rs)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 4.56 6.96 4.56 5.52]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_rf -> i_cn_rs_rf_rs
+newpath 1125 630 moveto
+1173 611 1264 576 1319 555 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1320 558 moveto
+1328 551 lineto
+1317 552 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1320 558 moveto
+1328 551 lineto
+1317 552 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1316 593 moveto
+(rs/rf)
+[4.56 5.52 3.84 4.56 4.56]
+xshow
+1265 577 moveto
+(phase_one_disconnect)
+[6.96 6.96 6.24 5.52 6.24 6.96 6.96 6.96 6.24 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84]
+xshow
+end grestore
+
+% i_cn_dn_rs_rs -> i
+newpath 1397 29 moveto
+1461 46 1574 83 1574 122 curveto
+1574 1478 1574 1478 1574 1478 curveto
+1574 1528 1515 1557 1476 1572 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1475 1569 moveto
+1466 1575 lineto
+1477 1575 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1475 1569 moveto
+1466 1575 lineto
+1477 1575 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1627 801 moveto
+(rs)
+[4.56 5.52]
+xshow
+1574 785 moveto
+(complete_disconnect)
+[6.24 6.96 10.8 6.96 3.84 6.24 3.84 6.24 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84]
+xshow
+end grestore
+
+% i_cn_rs_dn_rs -> i_cn_dn_rs
+newpath 936 211 moveto
+966 196 1013 174 1057 158 curveto
+1081 149 1109 141 1131 135 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1132 138 moveto
+1141 132 lineto
+1130 132 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1132 138 moveto
+1141 132 lineto
+1130 132 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1082 177 moveto
+(rs)
+[4.56 5.52]
+xshow
+1057 161 moveto
+(clear_store)
+[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24]
+xshow
+end grestore
+
+% i_cn_rs_dn_rs -> i_cn_rs_dn_rs
+newpath 943 213 moveto
+961 211 977 216 977 226 curveto
+977 234 967 239 953 239 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 953 236 moveto
+943 239 lineto
+953 243 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 953 236 moveto
+943 239 lineto
+953 243 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+976 221 moveto
+(od/or/oc)
+[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_dn -> i_cn_rs_dn_rs
+newpath 615 313 moveto
+631 297 655 274 681 262 curveto
+710 249 788 238 845 232 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 845 235 moveto
+855 231 lineto
+845 229 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 845 235 moveto
+855 231 lineto
+845 229 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+717 281 moveto
+(rs/rf)
+[4.56 5.52 3.84 4.56 4.56]
+xshow
+681 265 moveto
+(unregister_watch)
+[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_dn -> i_cn_rs_rs_dn
+newpath 637 317 moveto
+655 315 671 320 671 330 curveto
+671 338 661 343 647 343 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 647 340 moveto
+637 343 lineto
+647 347 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 647 340 moveto
+637 343 lineto
+647 347 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+671 325 moveto
+(od/or/oc)
+[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs -> i_cn_rs_dn_rs
+newpath 813 1148 moveto
+825 1141 840 1134 853 1126 curveto
+883 1106 892 1102 918 1076 curveto
+979 1013 1000 998 1035 918 curveto
+1062 854 1054 833 1061 764 curveto
+1064 725 1077 713 1062 678 curveto
+1057 667 1048 670 1043 660 curveto
+967 521 1016 464 976 312 curveto
+967 282 966 262 952 245 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 955 243 moveto
+945 238 lineto
+950 248 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 955 243 moveto
+945 238 lineto
+950 248 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1109 697 moveto
+(dn)
+[6.96 6.96]
+xshow
+1068 681 moveto
+(unregister_watch)
+[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs -> i_cn_rs_rs_rs
+newpath 817 1149 moveto
+835 1147 851 1151 851 1162 curveto
+851 1171 841 1175 827 1175 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 827 1172 moveto
+817 1175 lineto
+827 1179 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 827 1172 moveto
+817 1175 lineto
+827 1179 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+851 1157 moveto
+(ou/oc)
+[6.96 6.96 3.84 6.96 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od
+gsave 10 dict begin
+filled
+0.333 1.000 1.000 nodecolor
+782 1058 62 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+782 1058 62 18 ellipse_path
+stroke
+gsave 10 dict begin
+733 1053 moveto
+(i_cn_rs_rs_rs_od)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_rs_rs -> i_cn_rs_rs_rs_od
+newpath 782 1144 moveto
+782 1128 782 1105 782 1086 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 786 1086 moveto
+782 1076 lineto
+779 1086 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 786 1086 moveto
+782 1076 lineto
+779 1086 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+801 1113 moveto
+(od/or)
+[6.96 6.96 3.84 6.96 4.56]
+xshow
+782 1097 moveto
+(write_ready)
+[10.08 4.56 3.84 3.84 6.24 6.96 4.56 6.24 6.24 6.96 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rf -> i_cn_rs_rf
+newpath 956 729 moveto
+963 724 970 717 976 710 curveto
+986 697 982 688 996 678 curveto
+1010 666 1029 658 1046 653 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1047 656 moveto
+1056 650 lineto
+1045 650 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1047 656 moveto
+1056 650 lineto
+1045 650 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1021 697 moveto
+(rs)
+[4.56 5.52]
+xshow
+996 681 moveto
+(clear_store)
+[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_rf -> i_cn_rs_dn_rs
+newpath 943 728 moveto
+951 708 962 673 962 642 curveto
+962 642 962 642 962 330 curveto
+962 300 944 271 928 251 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 931 249 moveto
+922 243 lineto
+925 253 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 931 249 moveto
+922 243 lineto
+925 253 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+961 481 moveto
+(dn)
+[6.96 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rf -> i_cn_rs_rs_rf
+newpath 971 733 moveto
+989 731 1005 735 1005 746 curveto
+1005 755 995 759 981 759 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 981 756 moveto
+971 759 lineto
+981 763 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 981 756 moveto
+971 759 lineto
+981 763 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1004 741 moveto
+(od/or/oc)
+[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rf_rs -> i_cn_dn_rs_rs
+newpath 1360 520 moveto
+1357 499 1354 464 1354 434 curveto
+1354 434 1354 434 1354 122 curveto
+1354 96 1354 67 1354 46 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1358 46 moveto
+1354 36 lineto
+1351 46 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1358 46 moveto
+1354 36 lineto
+1351 46 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1353 273 moveto
+(dn)
+[6.96 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rf_rs_rs
+gsave 10 dict begin
+filled
+0.000 1.000 1.000 nodecolor
+1441 434 59 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+1441 434 59 18 ellipse_path
+stroke
+gsave 10 dict begin
+1394 429 moveto
+(i_cn_rs_rf_rs_rs)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 4.56 6.96 4.56 5.52 6.96 4.56 5.52]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_rf_rs -> i_cn_rs_rf_rs_rs
+newpath 1375 520 moveto
+1388 504 1407 479 1422 460 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1425 462 moveto
+1428 452 lineto
+1419 458 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1425 462 moveto
+1428 452 lineto
+1419 458 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1412 481 moveto
+(rs)
+[4.56 5.52]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od -> i_cn_rs_rs_dn
+newpath 762 1041 moveto
+728 1010 662 942 641 868 curveto
+637 852 632 845 641 832 curveto
+656 812 679 833 693 814 curveto
+740 753 718 546 713 470 curveto
+712 445 719 437 707 416 curveto
+692 388 662 365 639 350 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 640 347 moveto
+630 345 lineto
+637 353 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 640 347 moveto
+630 345 lineto
+637 353 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+724 689 moveto
+(dn)
+[6.96 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od -> i_cn_rs_rs_rf
+newpath 832 1047 moveto
+847 1042 863 1034 875 1022 curveto
+942 955 942 830 939 774 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 942 774 moveto
+938 764 lineto
+936 774 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 942 774 moveto
+938 764 lineto
+936 774 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+976 905 moveto
+(rf)
+[4.56 4.56]
+xshow
+933 889 moveto
+(unregister_watch)
+[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od -> i_cn_rs_rs_rs_od
+newpath 825 1045 moveto
+844 1043 862 1048 862 1058 curveto
+862 1066 850 1071 835 1071 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 835 1068 moveto
+825 1071 lineto
+835 1075 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 835 1068 moveto
+825 1071 lineto
+835 1075 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+861 1053 moveto
+(od/or/oc)
+[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs
+gsave 10 dict begin
+filled
+0.333 1.000 1.000 nodecolor
+782 954 70 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+782 954 70 18 ellipse_path
+stroke
+gsave 10 dict begin
+724 949 moveto
+(i_cn_rs_rs_rs_od_rs)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_rs_rs_od -> i_cn_rs_rs_rs_od_rs
+newpath 782 1040 moveto
+782 1024 782 1001 782 982 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 786 982 moveto
+782 972 lineto
+779 982 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 786 982 moveto
+782 972 lineto
+779 982 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+820 1009 moveto
+(rs)
+[4.56 5.52]
+xshow
+781 993 moveto
+(test_other_state)
+[3.84 6.24 5.52 3.84 6.96 6.96 3.84 6.96 6.24 4.56 6.96 5.52 3.84 6.24 3.84 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rf_rs_rs -> i
+newpath 1441 452 moveto
+1441 473 1441 508 1441 538 curveto
+1441 1478 1441 1478 1441 1478 curveto
+1441 1504 1441 1533 1441 1554 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 1438 1554 moveto
+1441 1564 lineto
+1445 1554 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 1438 1554 moveto
+1441 1564 lineto
+1445 1554 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+1492 1009 moveto
+(dn)
+[6.96 6.96]
+xshow
+1441 993 moveto
+(complete_disconnect)
+[6.24 6.96 10.8 6.96 3.84 6.24 3.84 6.24 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs -> i_cn_rs_dn_rs
+newpath 827 940 moveto
+839 935 852 927 861 918 curveto
+877 900 875 891 882 868 curveto
+892 831 904 818 891 782 curveto
+887 772 880 773 876 764 curveto
+846 699 856 676 850 606 curveto
+847 575 849 568 849 538 curveto
+849 538 849 538 849 330 curveto
+849 300 868 271 884 251 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 887 253 moveto
+890 243 lineto
+881 249 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 887 253 moveto
+890 243 lineto
+881 249 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+891 593 moveto
+(dn)
+[6.96 6.96]
+xshow
+850 577 moveto
+(unregister_watch)
+[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs -> i_cn_rs_rs_rs_od_rs
+newpath 829 941 moveto
+851 939 870 944 870 954 curveto
+870 962 856 967 839 967 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 839 964 moveto
+829 967 lineto
+839 971 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 839 964 moveto
+829 967 lineto
+839 971 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+869 949 moveto
+(od)
+[6.96 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or
+gsave 10 dict begin
+filled
+0.333 1.000 1.000 nodecolor
+729 850 79 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+729 850 79 18 ellipse_path
+stroke
+gsave 10 dict begin
+662 845 moveto
+(i_cn_rs_rs_rs_od_rs_or)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52 6.96 6.96 4.56]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_rs_rs_od_rs -> i_cn_rs_rs_rs_od_rs_or
+newpath 773 936 moveto
+764 920 752 896 743 877 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 746 875 moveto
+738 868 lineto
+740 878 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 746 875 moveto
+738 868 lineto
+740 878 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+796 905 moveto
+(or/oc)
+[6.96 4.56 3.84 6.96 6.24]
+xshow
+764 889 moveto
+(write_connected)
+[10.08 4.56 3.84 3.84 6.24 6.96 6.24 6.96 6.96 6.96 6.24 6.24 3.84 6.24 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or -> i_cn_rs_rs_dn
+newpath 736 832 moveto
+744 811 755 776 755 746 curveto
+755 746 755 746 755 434 curveto
+755 401 755 387 731 366 curveto
+720 355 688 347 658 340 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 658 337 moveto
+648 338 lineto
+657 343 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 658 337 moveto
+648 338 lineto
+657 343 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+755 585 moveto
+(dn)
+[6.96 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or -> i_cn_rs_rs_rf
+newpath 750 833 moveto
+769 817 799 796 827 782 curveto
+845 773 866 765 885 759 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 886 762 moveto
+895 756 lineto
+884 756 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 886 762 moveto
+895 756 lineto
+884 756 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+870 801 moveto
+(rf)
+[4.56 4.56]
+xshow
+827 785 moveto
+(unregister_watch)
+[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or -> i_cn_rs_rs_rs_od_rs_or
+newpath 782 837 moveto
+806 836 826 840 826 850 curveto
+826 859 811 863 792 863 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 792 860 moveto
+782 863 lineto
+792 867 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 792 860 moveto
+782 863 lineto
+792 867 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+825 845 moveto
+(od/or/oc)
+[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs
+gsave 10 dict begin
+filled
+0.333 1.000 1.000 nodecolor
+549 746 88 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+549 746 88 18 ellipse_path
+stroke
+gsave 10 dict begin
+474 741 moveto
+(i_cn_rs_rs_rs_od_rs_or_rs)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52 6.96 6.96 4.56 6.96 4.56 5.52]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or -> i_cn_rs_rs_rs_od_rs_or_rs
+newpath 692 834 moveto
+679 828 665 821 652 814 curveto
+628 800 602 783 582 769 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 584 766 moveto
+574 763 lineto
+580 772 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 584 766 moveto
+574 763 lineto
+580 772 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+697 801 moveto
+(rs)
+[4.56 5.52]
+xshow
+658 785 moveto
+(test_other_state)
+[3.84 6.24 5.52 3.84 6.96 6.96 3.84 6.96 6.24 4.56 6.96 5.52 3.84 6.24 3.84 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs -> i_cn_rs_rs
+newpath 548 764 moveto
+547 785 545 820 545 850 curveto
+545 1162 545 1162 545 1162 curveto
+545 1188 545 1217 545 1238 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 542 1238 moveto
+545 1248 lineto
+549 1238 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 542 1238 moveto
+545 1248 lineto
+549 1238 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+568 1009 moveto
+(od)
+[6.96 6.96]
+xshow
+545 993 moveto
+(clear_store)
+[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs -> i_cn_rs_dn_rs
+newpath 564 728 moveto
+568 722 573 716 577 710 curveto
+642 614 752 341 835 262 curveto
+843 254 851 249 861 244 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 863 247 moveto
+870 239 lineto
+860 241 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 863 247 moveto
+870 239 lineto
+860 241 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+746 489 moveto
+(dn)
+[6.96 6.96]
+xshow
+705 473 moveto
+(unregister_watch)
+[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs -> i_cn_rs_rs_rs_od_rs_or_rs
+newpath 608 733 moveto
+633 732 655 736 655 746 curveto
+655 755 639 759 618 759 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 618 756 moveto
+608 759 lineto
+618 763 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 618 756 moveto
+608 759 lineto
+618 763 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+655 741 moveto
+(or)
+[6.96 4.56]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc
+gsave 10 dict begin
+filled
+0.333 1.000 1.000 nodecolor
+419 642 98 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+419 642 98 18 ellipse_path
+stroke
+gsave 10 dict begin
+334 637 moveto
+(i_cn_rs_rs_rs_od_rs_or_rs_oc)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52 6.96 6.96 4.56 6.96 4.56 5.52 6.96 6.96 6.24]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs -> i_cn_rs_rs_rs_od_rs_or_rs_oc
+newpath 527 728 moveto
+506 711 473 685 449 666 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 451 663 moveto
+441 660 lineto
+447 669 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 451 663 moveto
+441 660 lineto
+447 669 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+553 697 moveto
+(oc)
+[6.96 6.24]
+xshow
+504 681 moveto
+(phase_two_connect)
+[6.96 6.96 6.24 5.52 6.24 6.96 3.84 10.08 6.96 6.96 6.24 6.96 6.96 6.96 6.24 6.24 3.84]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc -> i_cn_rs_rs
+newpath 422 660 moveto
+431 713 455 872 455 1006 curveto
+455 1162 455 1162 455 1162 curveto
+455 1198 485 1227 510 1245 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 509 1248 moveto
+519 1251 lineto
+513 1243 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 509 1248 moveto
+519 1251 lineto
+513 1243 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+480 957 moveto
+(rf)
+[4.56 4.56]
+xshow
+455 941 moveto
+(clear_store)
+[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc_pe
+gsave 10 dict begin
+filled
+0.667 1.000 1.000 nodecolor
+179 538 108 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+179 538 108 18 ellipse_path
+stroke
+gsave 10 dict begin
+83 533 moveto
+(i_cn_rs_rs_rs_od_rs_or_rs_oc_pe)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52 6.96 6.96 4.56 6.96 4.56 5.52 6.96 6.96 6.24 6.96 6.96 6.24]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc -> i_cn_rs_rs_rs_od_rs_or_rs_oc_pe
+newpath 364 627 moveto
+351 622 338 615 327 606 curveto
+315 595 321 584 307 574 curveto
+296 565 282 559 268 553 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 269 550 moveto
+258 550 lineto
+267 556 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 269 550 moveto
+258 550 lineto
+267 556 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+333 585 moveto
+(pe/od/or/oc)
+[6.96 6.24 3.84 6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc_dn
+gsave 10 dict begin
+filled
+0.106 1.000 1.000 nodecolor
+287 434 108 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+287 434 108 18 ellipse_path
+stroke
+gsave 10 dict begin
+191 429 moveto
+(i_cn_rs_rs_rs_od_rs_or_rs_oc_dn)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52 6.96 6.96 4.56 6.96 4.56 5.52 6.96 6.96 6.24 6.96 6.96 6.96]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc -> i_cn_rs_rs_rs_od_rs_or_rs_oc_dn
+newpath 416 624 moveto
+411 599 400 553 379 520 curveto
+363 496 340 473 320 458 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 322 455 moveto
+312 452 lineto
+318 461 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 322 455 moveto
+312 452 lineto
+318 461 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+400 533 moveto
+(dn)
+[6.96 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc_rs
+gsave 10 dict begin
+filled
+0.333 1.000 1.000 nodecolor
+545 538 106 18 ellipse_path
+fill
+0.000 0.000 0.000 nodecolor
+545 538 106 18 ellipse_path
+stroke
+gsave 10 dict begin
+451 533 moveto
+(i_cn_rs_rs_rs_od_rs_or_rs_oc_rs)
+[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52 6.96 6.96 4.56 6.96 4.56 5.52 6.96 6.96 6.24 6.96 4.56 5.52]
+xshow
+end grestore
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc -> i_cn_rs_rs_rs_od_rs_or_rs_oc_rs
+newpath 440 624 moveto
+460 607 492 581 515 563 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 518 565 moveto
+523 556 lineto
+513 560 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 518 565 moveto
+523 556 lineto
+513 560 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+501 585 moveto
+(rs)
+[4.56 5.52]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc_pe -> i_cn_rs
+newpath 170 556 moveto
+141 618 51 825 51 1006 curveto
+51 1266 51 1266 51 1266 curveto
+51 1370 172 1318 274 1338 curveto
+373 1356 678 1368 792 1373 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 792 1377 moveto
+802 1373 lineto
+792 1370 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 792 1377 moveto
+802 1373 lineto
+792 1370 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+114 957 moveto
+(rs)
+[4.56 5.52]
+xshow
+56 941 moveto
+(phase_two_disconnect)
+[6.96 6.96 6.24 5.52 6.24 6.96 3.84 10.08 6.96 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc_pe -> i_cn_rs_rs
+newpath 191 556 moveto
+217 596 280 694 323 782 curveto
+356 848 360 866 385 936 curveto
+397 966 409 973 409 1006 curveto
+409 1162 409 1162 409 1162 curveto
+409 1219 443 1239 493 1257 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 492 1261 moveto
+503 1261 lineto
+495 1254 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 492 1261 moveto
+503 1261 lineto
+495 1254 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+406 905 moveto
+(rf)
+[4.56 4.56]
+xshow
+381 889 moveto
+(clear_store)
+[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc_pe -> i_cn_rs_rs_rs_od_rs_or_rs_oc_pe
+newpath 251 525 moveto
+280 524 305 528 305 538 curveto
+305 547 286 551 261 551 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 261 548 moveto
+251 551 lineto
+261 555 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 261 548 moveto
+251 551 lineto
+261 555 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+305 533 moveto
+(pe/od/or/oc)
+[6.96 6.24 3.84 6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc_pe -> i_cn_rs_rs_rs_od_rs_or_rs_oc_dn
+newpath 198 520 moveto
+216 503 242 478 261 459 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 263 462 moveto
+268 452 lineto
+258 457 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 263 462 moveto
+268 452 lineto
+258 457 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+250 481 moveto
+(dn)
+[6.96 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc_dn -> i_cn_rs_dn_rs
+newpath 298 416 moveto
+308 401 323 380 339 366 curveto
+378 333 393 330 440 312 curveto
+609 245 660 245 843 228 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 843 231 moveto
+853 227 lineto
+843 225 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 843 231 moveto
+853 227 lineto
+843 225 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+483 333 moveto
+(rf)
+[4.56 4.56]
+xshow
+440 317 moveto
+(unregister_watch)
+[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc_dn -> i_cn_rs_rs_dn
+newpath 313 416 moveto
+338 401 376 379 411 366 curveto
+453 351 502 342 539 336 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 539 339 moveto
+549 335 lineto
+539 333 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 539 339 moveto
+549 335 lineto
+539 333 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+469 385 moveto
+(rs)
+[4.56 5.52]
+xshow
+411 369 moveto
+(phase_two_disconnect)
+[6.96 6.96 6.24 5.52 6.24 6.96 3.84 10.08 6.96 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc_dn -> i_cn_rs_rs_rs_od_rs_or_rs_oc_dn
+newpath 359 421 moveto
+388 420 413 424 413 434 curveto
+413 443 394 447 369 447 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 369 444 moveto
+359 447 lineto
+369 451 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 369 444 moveto
+359 447 lineto
+369 451 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+413 429 moveto
+(pe/od/or/oc)
+[6.96 6.24 3.84 6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc_rs -> i_cn_rs
+newpath 553 556 moveto
+567 590 591 666 553 710 curveto
+539 727 475 722 452 728 curveto
+376 746 339 726 282 782 curveto
+208 854 215 902 215 1006 curveto
+215 1266 215 1266 215 1266 curveto
+215 1325 651 1361 792 1371 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 792 1374 moveto
+802 1372 lineto
+792 1368 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 792 1374 moveto
+802 1372 lineto
+792 1368 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+247 957 moveto
+(pe/od/or/oc)
+[6.96 6.24 3.84 6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24]
+xshow
+216 941 moveto
+(phase_two_disconnect)
+[6.96 6.96 6.24 5.52 6.24 6.96 3.84 10.08 6.96 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84]
+xshow
+end grestore
+
+% i_cn_rs_rs_rs_od_rs_or_rs_oc_rs -> i_cn_rs_rs_dn
+newpath 549 520 moveto
+555 496 565 452 575 416 curveto
+581 396 587 375 592 358 curveto
+stroke
+gsave 10 dict begin
+solid
+1 setlinewidth
+0.000 0.000 0.000 edgecolor
+newpath 595 359 moveto
+595 348 lineto
+589 357 lineto
+closepath
+fill
+0.000 0.000 0.000 edgecolor
+newpath 595 359 moveto
+595 348 lineto
+589 357 lineto
+closepath
+stroke
+end grestore
+gsave 10 dict begin
+631 437 moveto
+(dn)
+[6.96 6.96]
+xshow
+575 421 moveto
+(phase_two_disconnect)
+[6.96 6.96 6.24 5.52 6.24 6.96 3.84 10.08 6.96 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84]
+xshow
+end grestore
+endpage
+showpage
+grestore
+%%PageTrailer
+%%EndPage: 1
+%%Trailer
+%%Pages: 1
+end
+restore
+%%EOF
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc.h Mon Oct 24 15:04:49 2005
@@ -0,0 +1,681 @@
+/*****************************************************************************/
+/* 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__
+
+#include <asm/types.h>
+#include <asm-xen/driver_util.h>
+#include "gnttab.h"
+#include "xenbus.h"
+#include "xenidc_callback.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;
+}
+
+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;
+}
+
+typedef struct xenidc_message_and_transaction_header_struct
+ xenidc_message_and_transaction_header;
+
+struct xenidc_message_and_transaction_header_struct
+{
+ xenidc_callback callback;
+ int transaction_not_message;
+};
+
+#define XENIDC_MESSAGE_AND_TRANSACTION_HEADER_LINK \
+callback.XENIDC_CALLBACK_LINK
+
+static inline struct list_head * xenidc_message_and_transaction_header_to_link
+ ( xenidc_message_and_transaction_header * header )
+{
+ return xenidc_callback_to_link( &header->callback );
+}
+
+typedef struct xenidc_message_struct xenidc_message;
+
+struct xenidc_message_struct
+{
+ xenidc_message_and_transaction_header header;
+ xenidc_local_buffer_reference message;
+};
+
+static inline xenidc_callback * xenidc_message_to_callback
+ ( xenidc_message * message )
+{
+ return &message->header.callback;
+}
+
+static inline xenidc_message * xenidc_message_callback_to
+ ( xenidc_callback * callback )
+{
+ return container_of( callback, xenidc_message, header.callback );
+}
+
+static inline struct list_head * xenidc_message_to_link
+ ( xenidc_message * message )
+{
+ return xenidc_callback_to_link( &message->header.callback );
+}
+
+static inline xenidc_message * xenidc_message_link_to
+ ( struct list_head * link )
+{
+ return xenidc_message_callback_to( xenidc_callback_link_to( link ) );
+}
+
+static inline xenidc_message * xenidc_message_header_to
+ ( xenidc_message_and_transaction_header * header )
+{
+ return container_of( header, xenidc_message, header );
+}
+
+static inline void xenidc_message_init
+ ( xenidc_message * message, xenidc_callback_function * callback )
+{
+ xenidc_callback_init( xenidc_message_to_callback( message ), callback );
+
+ message->header.transaction_not_message = 0;
+}
+
+static inline void xenidc_message_set_message_lbr
+ ( xenidc_message * message, xenidc_local_buffer_reference lbr )
+{
+ message->message = lbr;
+}
+
+typedef struct xenidc_transaction_struct xenidc_transaction;
+
+struct xenidc_transaction_struct
+{
+ xenidc_message_and_transaction_header header;
+ xenidc_local_buffer_reference parameters;
+ xenidc_local_buffer_reference status;
+};
+
+#define XENIDC_TRANSACTION_LINK header.callback.XENIDC_CALLBACK_LINK
+
+static inline xenidc_callback * xenidc_transaction_to_callback
+ ( xenidc_transaction * transaction )
+{
+ return &transaction->header.callback;
+}
+
+static inline xenidc_transaction * xenidc_transaction_callback_to
+ ( xenidc_callback * callback )
+{
+ return container_of( callback, xenidc_transaction, header.callback );
+}
+
+static inline struct list_head * xenidc_transaction_to_link
+ ( xenidc_transaction * transaction )
+{
+ return xenidc_callback_to_link
+ ( xenidc_transaction_to_callback( transaction ) );
+}
+
+static inline xenidc_transaction * xenidc_transaction_link_to
+ ( struct list_head * link )
+{
+ return xenidc_transaction_callback_to( xenidc_callback_link_to( link ) );
+}
+
+static inline xenidc_transaction * xenidc_transaction_header_to
+ ( xenidc_message_and_transaction_header * header )
+{
+ return container_of( header, xenidc_transaction, header );
+}
+
+static inline void xenidc_transaction_init
+ ( xenidc_transaction * transaction, xenidc_callback_function * callback )
+{
+ xenidc_callback_init
+ ( xenidc_transaction_to_callback( transaction ), callback );
+
+ transaction->header.transaction_not_message = 1;
+}
+
+static inline void xenidc_transaction_set_parameters_lbr
+ ( xenidc_transaction * transaction, xenidc_local_buffer_reference lbr )
+{
+ transaction->parameters = lbr;
+}
+
+static inline void xenidc_transaction_set_status_lbr
+ ( xenidc_transaction * transaction, xenidc_local_buffer_reference lbr )
+{
+ transaction->status = lbr;
+}
+
+static inline void xenidc_transaction_complete
+ ( xenidc_transaction * transaction, xenidc_error error )
+{
+ xenidc_callback_complete
+ ( xenidc_transaction_to_callback( transaction ), error );
+}
+
+static inline xenidc_error xenidc_transaction_query_error
+ ( xenidc_transaction * transaction )
+{
+ return xenidc_callback_query_error
+ ( xenidc_transaction_to_callback( transaction ) );
+}
+
+typedef enum
+{
+ xenidc_endpoint_state_i,
+ xenidc_endpoint_state_i_cr,
+ xenidc_endpoint_state_i_cn,
+ xenidc_endpoint_state_i_cr_cn,
+ xenidc_endpoint_state_i_cr_xs,
+ xenidc_endpoint_state_i_cr_cn_xs,
+ xenidc_endpoint_state_i_cr_cn_xs_es
+}
+xenidc_endpoint_state;
+
+typedef struct xenidc_endpoint_initiator_resource_struct
+ xenidc_endpoint_initiator_resource;
+
+typedef struct xenidc_endpoint_target_resource_struct
+ xenidc_endpoint_target_resource;
+
+typedef struct xenidc_endpoint_struct xenidc_endpoint;
+
+struct xenidc_endpoint_struct
+{
+ void ( * connect )( xenidc_endpoint * endpoint );
+ void ( * disconnect )
+ ( xenidc_endpoint * endpoint, xenidc_callback * callback );
+ void ( * message )
+ ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference message );
+ void ( * transaction )
+ ( xenidc_endpoint * endpoint, xenidc_transaction * transaction );
+
+ u32 initiator_transaction_quota;
+ u32 target_transaction_quota;
+ xenidc_buffer_byte_count target_transaction_maximum_byte_count;
+
+ xenidc_endpoint * send_irq_context;
+ xenidc_endpoint * recv_irq_context;
+
+ struct list_head initiator_resource_list;
+ xenidc_endpoint_initiator_resource * initiator_resources;
+
+ struct list_head target_resource_list;
+ xenidc_endpoint_target_resource * target_resources;
+
+ spinlock_t lock;
+ xenidc_endpoint_state state;
+ struct list_head message_and_transaction_list;
+ struct list_head send_request_list;
+ xenidc_work xenstore_connect_1_work;
+ xenidc_work establish_connection_1_work;
+ xenidc_work kick_messages_and_transactions_1_work;
+ xenidc_work kick_send_ring_1_work;
+ xenidc_work kick_recv_ring_1_work;
+ xenidc_address address;
+ struct xenbus_watch watch;
+ grant_ref_t send_ring_ref;
+ unsigned int send_event_channel;
+ int send_irq;
+ grant_ref_t recv_ring_ref;
+ unsigned int recv_event_channel;
+ u16 recv_ring_handle;
+ unsigned int recv_event_channel_bound;
+ int recv_irq;
+ int destroyed : 1;
+};
+
+/* Init blocks for resource allocation. */
+
+extern int xenidc_endpoint_init
+(
+ xenidc_endpoint * endpoint,
+
+ void ( * connect )( xenidc_endpoint * endpoint ),
+ void ( * disconnect )
+ ( xenidc_endpoint * endpoint, xenidc_callback * callback ),
+ void ( * message )
+ ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference message ),
+ void ( * transaction )
+ ( xenidc_endpoint * endpoint, xenidc_transaction * transaction ),
+ xenidc_buffer_byte_count initiator_message_maximum_byte_count,
+ u32 initiator_transaction_quota,
+ xenidc_buffer_byte_count initiator_transaction_maximum_byte_count,
+ xenidc_buffer_byte_count target_message_maximum_byte_count,
+ u32 target_transaction_quota,
+ xenidc_buffer_byte_count target_transaction_maximum_byte_count
+);
+
+int xenidc_endpoint_create
+ ( xenidc_endpoint * endpoint, xenidc_address address );
+
+extern void xenidc_endpoint_submit_message
+ ( xenidc_endpoint * endpoint, xenidc_message * message );
+
+extern void xenidc_endpoint_submit_transaction
+ ( xenidc_endpoint * endpoint, xenidc_transaction * transaction );
+
+/* Destroy blocks until disconnected */
+
+extern void xenidc_endpoint_destroy( xenidc_endpoint * endpoint );
+
+extern void xenidc_endpoint_exit( xenidc_endpoint * endpoint );
+
+/*****************************************************************************/
+/* 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. */
+/* */
+/*****************************************************************************/
+
+/* TO CREATE REMOTE BUFFER REFERENCES TO GRANT OTHER DOMAINS ACCESS TO LOCAL */
+/* BUFFERS. */
+
+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
+);
+
+/* TO MAP REMOTE BUFFERS INTO THE LOCAL ADDRESS SPACE. */
+
+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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_callback.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_callback.h Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_channel.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_channel.h Mon Oct 24 15:04:49 2005
@@ -0,0 +1,143 @@
+/*****************************************************************************/
+/* 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 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->lbr = lbr;
+}
+
+typedef struct xenidc_channel_struct xenidc_channel;
+
+struct xenidc_channel_struct
+{
+ void ( * submit_message )
+ ( xenidc_channel * channel, xenidc_channel_message * message );
+ void ( * connect )( xenidc_channel * channel );
+ void ( * handle_message )
+ ( xenidc_channel * channel, xenidc_channel_message * message );
+ void ( * disconnect )
+ ( xenidc_channel * channel, 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 );
+}
+
+/* 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, 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, callback );
+}
+
+/* Called by the client class before derived class first calls connect. */
+
+static inline void xenidc_channel_install_client
+(
+ xenidc_channel * channel,
+ void ( * connect )( xenidc_channel * channel ),
+ void ( * handle_message )
+ ( xenidc_channel * channel, xenidc_channel_message * message ),
+ void ( * disconnect )
+ ( xenidc_channel * channel, xenidc_callback * callback )
+)
+{
+ 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_concatenate.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_concatenate.h Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_error.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_error.h Mon Oct 24 15:04:49 2005
@@ -0,0 +1,55 @@
+#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 )
+/* Initiator did everything right, target software needs to be fixed: */
+#define XENIDC_ERROR_IMPLEMENTATION_DEFICIENCY ( (xenidc_error)3 )
+/* Unexpected transaction/transaction in wrong sequence etc: */
+#define XENIDC_ERROR_INVALID_PROTOCOL ( (xenidc_error)4 )
+/* Underlength parameters/status etc: */
+#define XENIDC_ERROR_INVALID_FORMAT ( (xenidc_error)5 )
+/* Parameter value wrong: */
+#define XENIDC_ERROR_INVALID_PARAMETER ( (xenidc_error)6 )
+/* Something about a request exceeded a hard-coded limit: */
+#define XENIDC_ERROR_TOO_BIG ( (xenidc_error)7 )
+
+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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_gnttab_channel.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_gnttab_channel.h Mon Oct 24 15:04:49 2005
@@ -0,0 +1,193 @@
+/*****************************************************************************/
+/* Xen inter-domain communication channel implementation based on grant */
+/* tables. */
+/* */
+/* 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;
+
+#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;
+
+ struct list_head free_target_resource_list;
+
+ xenidc_gnttab_channel_target_resource target_resources
+ [ XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT ];
+
+ int target_resources_out;
+
+ 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;
+ int recv_irq;
+};
+
+/* 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
+);
+
+/* 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_local_buffer_reference.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_local_buffer_reference.h Mon Oct 24 15:04:49 2005
@@ -0,0 +1,103 @@
+/*****************************************************************************/
+/* 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"
+
+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;
+}
+
+/* Copy out of a buffer into a target 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_out
+(
+ xenidc_local_buffer_reference * buffer_reference,
+ void * target,
+ xenidc_buffer_byte_count target_byte_count
+);
+
+extern xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_in
+(
+ xenidc_local_buffer_reference * buffer_reference,
+ void * source,
+ xenidc_buffer_byte_count source_byte_count
+);
+
+extern xenidc_buffer_byte_count xenidc_local_buffer_reference_copy
+(
+ xenidc_local_buffer_reference * target,
+ xenidc_local_buffer_reference * source
+);
+
+extern void xenidc_local_buffer_reference_zero
+ ( xenidc_local_buffer_reference * buffer_reference );
+
+/* 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. */
+
+extern xenidc_buffer_byte_count xenidc_local_buffer_reference_advance
+(
+ xenidc_local_buffer_reference * buffer_reference,
+ xenidc_buffer_byte_count 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). */
+
+extern xenidc_buffer_byte_count xenidc_local_buffer_reference_truncate
+(
+ xenidc_local_buffer_reference * buffer_reference,
+ xenidc_buffer_byte_count byte_count
+);
+
+#endif
diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_vaddress.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_vaddress.h Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_work.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_work.h Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_wrapping.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_wrapping.h Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_xbgt_channel.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_xbgt_channel.h Mon Oct 24 15:04:49 2005
@@ -0,0 +1,139 @@
+/*****************************************************************************/
+/* Xen inter-domain communication channel implementation based on xenbus and */
+/* grant tables. */
+/* */
+/* 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 1c62a4149b11 -r 5952173acc28 patches/linux-2.6.12/usb.patch
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/patches/linux-2.6.12/usb.patch Mon Oct 24 15:04:49 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 1c62a4149b11 -r 5952173acc28 xen/include/public/io/usbif.h
--- /dev/null Mon Oct 24 07:04:38 2005
+++ b/xen/include/public/io/usbif.h Mon Oct 24 15:04:49 2005
@@ -0,0 +1,350 @@
+/*****************************************************************************/
+/* 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;
+};
+
+#define USBIF_BE_INITIATOR_MESSAGE_MAXIMUM_BYTE_COUNT 0
+#define USBIF_BE_INITIATOR_TRANSACTION_QUOTA 0
+#define USBIF_BE_INITIATOR_TRANSACTION_MAXIMUM_BYTE_COUNT 0
+
+#define USBIF_BE_TARGET_MESSAGE_MAXIMUM_BYTE_COUNT \
+ ( sizeof( usbif_unlink_message_body ) )
+#define USBIF_BE_TARGET_TRANSACTION_QUOTA 32
+#define USBIF_BE_TARGET_TRANSACTION_MAXIMUM_BYTE_COUNT \
+( sizeof( usbif_max_transaction ) )
+
+#define USBIF_FE_INITIATOR_MESSAGE_MAXIMUM_BYTE_COUNT \
+USBIF_BE_TARGET_MESSAGE_MAXIMUM_BYTE_COUNT
+#define USBIF_FE_INITIATOR_TRANSACTION_QUOTA \
+USBIF_BE_TARGET_TRANSACTION_QUOTA
+#define USBIF_FE_INITIATOR_TRANSACTION_MAXIMUM_BYTE_COUNT \
+USBIF_BE_TARGET_TRANSACTION_MAXIMUM_BYTE_COUNT
+
+#define USBIF_FE_TARGET_MESSAGE_MAXIMUM_BYTE_COUNT \
+USBIF_BE_INITIATOR_MESSAGE_MAXIMUM_BYTE_COUNT
+#define USBIF_FE_TARGET_TRANSACTION_QUOTA \
+USBIF_BE_INITIATOR_TRANSACTION_QUOTA
+#define USBIF_FE_TARGET_TRANSACTION_MAXIMUM_BYTE_COUNT \
+USBIF_BE_INITIATOR_TRANSACTION_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] 4+ messages in thread
* Re: USB virt
2005-10-24 16:40 ` USB virt harry
@ 2005-10-25 23:21 ` Sean Dague
2005-10-26 2:05 ` Anthony Liguori
2005-10-26 9:09 ` harry
0 siblings, 2 replies; 4+ messages in thread
From: Sean Dague @ 2005-10-25 23:21 UTC (permalink / raw)
To: harry; +Cc: xen-devel, Mark Williamson
[-- Attachment #1.1: Type: text/plain, Size: 776 bytes --]
Wow, 18k lines of code so far.
Just out of curiosity, a friend pointed me to
http://heanet.dl.sourceforge.net/sourceforge/usbip/usbip-0.1-2.6.13.tar.gz
which he was looking at for trying to find a way to do usb on Xen 2.0.
Would an approach like this be worth looking at?
-Sean
--
__________________________________________________________________
Sean Dague Mid-Hudson Valley
sean at dague dot net Linux Users Group
http://dague.net http://mhvlug.org
There is no silver bullet. Plus, werewolves make better neighbors
than zombies, and they tend to keep the vampire population down.
__________________________________________________________________
[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]
[-- Attachment #2: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Re: USB virt
2005-10-25 23:21 ` Sean Dague
@ 2005-10-26 2:05 ` Anthony Liguori
2005-10-26 9:09 ` harry
1 sibling, 0 replies; 4+ messages in thread
From: Anthony Liguori @ 2005-10-26 2:05 UTC (permalink / raw)
To: Sean Dague; +Cc: harry, Mark Williamson, xen-devel
Sean Dague wrote:
>Wow, 18k lines of code so far.
>
>Just out of curiosity, a friend pointed me to
>http://heanet.dl.sourceforge.net/sourceforge/usbip/usbip-0.1-2.6.13.tar.gz
>which he was looking at for trying to find a way to do usb on Xen 2.0.
>
>Would an approach like this be worth looking at?
>
>
What an excellent idea. USB devices could keep working even after
domain migration too :-)
Regards,
Anthony Liguori
> -Sean
>
>
>
>------------------------------------------------------------------------
>
>_______________________________________________
>Xen-devel mailing list
>Xen-devel@lists.xensource.com
>http://lists.xensource.com/xen-devel
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Re: USB virt
2005-10-25 23:21 ` Sean Dague
2005-10-26 2:05 ` Anthony Liguori
@ 2005-10-26 9:09 ` harry
1 sibling, 0 replies; 4+ messages in thread
From: harry @ 2005-10-26 9:09 UTC (permalink / raw)
To: Sean Dague; +Cc: xen-devel, Mark Williamson
On Tue, 2005-10-25 at 19:21 -0400, Sean Dague wrote:
> Wow, 18k lines of code so far.
Actually, the USB driver is only 8k raw lines, most of which is
copyright comments. It's only 900 ";" of code which I think is pretty
small.
Some of the rest of the code is duplicated because I'm in the middle of
refactoring it.
The remainder of the rest of the code is the common code that is
generally required to turn Xenbus and grant-tables into a useful
inter-domain communication mechanism. This is the code that's currently
replicated in all the other drivers. The reason that this portion of
the code is bigger in my driver is because I'm coding a general solution
which a) will work for device driver domains with driver restarts and
loadable driver modules and b) is a service which can be used by new
drivers in the future to save them from having yet another copy of the
code.
>
> Just out of curiosity, a friend pointed me to
> http://heanet.dl.sourceforge.net/sourceforge/usbip/usbip-0.1-2.6.13.tar.gz
> which he was looking at for trying to find a way to do usb on Xen 2.0.
>
> Would an approach like this be worth looking at?
The API of the inter-domain communication mechanism that I wrote the USB
driver to is currently implemented using shared memory (grant-tables)
for efficiency but is compatible with a network transparent
implementation so could be extended to work through domain migration in
the future. Naturally, if you extended the implementation of my
interdomain communication API then any other drivers that had been
written to use it would also benefit from the new functionality.
The difference between what I have done and the above IP based solution
is that I have explicitly created a solution which can have an efficient
shared memory implementation in the normal case when domains are
resident on the same physical machine and my solution is intentionally
available to any other drivers that might choose to use it.
Thanks for your input. I think I'll continue with what I was doing for
the time being.
Harry.
>
> -Sean
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xensource.com
> http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2005-10-26 9:09 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <200510241656.24936.mark.williamson@cl.cam.ac.uk>
2005-10-24 16:40 ` USB virt harry
2005-10-25 23:21 ` Sean Dague
2005-10-26 2:05 ` Anthony Liguori
2005-10-26 9:09 ` harry
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.