* USB virt status
@ 2005-10-30 16:43 Harry Butterworth
[not found] ` <200511041725.11451.mark.williamson@cl.cam.ac.uk>
0 siblings, 1 reply; 8+ messages in thread
From: Harry Butterworth @ 2005-10-30 16:43 UTC (permalink / raw)
To: xen-devel; +Cc: mark.williamson, sanjay.kushwaha
[-- Attachment #1: Type: text/plain, Size: 973 bytes --]
Here's the latest USB code. This patch is much less crufty than the one
I sent out a week ago since I just finished the refactoring which was
in-progress in the last patch.
In this patch, the inter-domain communication endpoint object
(xenidc_endpoint) is theoretically code-complete but is substantially
unexecuted so I wouldn't recommend trying to use it unless you want to
help test it.
FIXMEs in the patch indicate the work remaining to complete the USB
driver which include:
1) Implement the xenidc_rbr_provider_pool and the xenidc_rbr_mapper_pool
objects which are used to implement the bulk data transfer between the
FE and BE based on the grant-tables API.
2) Update the usbback_driver_port state machine to handle the cn and dn
stimuli.
3) Some minor bits and pieces here and there.
I also need to hook up the claim and release port interfaces to xenbus.
And of course, lots of testing.
Enjoy.
--
Harry Butterworth <harry@hebutterworth.freeserve.co.uk>
[-- Attachment #2: latest-usb-patch --]
[-- Type: text/x-patch, Size: 623232 bytes --]
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/arch/xen/Kconfig
--- a/linux-2.6-xen-sparse/arch/xen/Kconfig Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/arch/xen/Kconfig Sun Oct 30 16:03:34 2005
@@ -38,6 +38,14 @@
(e.g., hard drives, network cards). This allows you to configure
such devices and also includes some low-level support that is
otherwise not compiled into the kernel.
+
+config XEN_IDC_TRACE
+ bool "Inter-domain communication code tracing"
+ default y
+ help
+ This option causes the IDC code to output a continual trace of its
+ activity.
+ Say N here unless you are trying to debug this code.
config XEN_BLKDEV_BACKEND
bool "Block-device backend driver"
@@ -69,6 +77,29 @@
The network-device backend driver allows the kernel to export its
network devices to other guests via a high-performance shared-memory
interface.
+
+config XEN_USBDEV_BACKEND
+ tristate "USB-device backend driver"
+ depends on XEN_PHYSDEV_ACCESS
+ select USB
+ default m
+ help
+ The USB-device backend driver allows the kernel to export USB
+ devices to USB-device frontend drivers running in other domains.
+ This is not required for USB device access in domain 0 or any domain
+ given exclusive control over a USB host controller device at the PCI
+ level.
+ Say Y or M if you want to use this kernel to export a USB device to
+ another domain running a USB-device frontend driver.
+
+config XEN_USBDEV_BACKEND_TRACE
+ bool "USB-device backend driver tracing"
+ depends on XEN_USBDEV_BACKEND
+ default y
+ help
+ This option causes the driver to output a continual trace of its
+ activity.
+ Say N here unless you are trying to debug the driver.
config XEN_TPMDEV_FRONTEND
bool "TPM-device frontend driver"
@@ -128,6 +159,30 @@
are unsure; or if you experience network hangs when this option is
enabled; then you must say N here.
+config XEN_USBDEV_FRONTEND
+ tristate "USB-device frontend driver"
+ select USB
+ default m
+ help
+ The USB-device frontend driver allows the kernel to access USB
+ devices exported by a USB-device backend driver running in another
+ domain.
+ This is not required for USB device access in domain 0 or any domain
+ given exclusive control over a USB host controller device at the PCI
+ level.
+ Say Y or M if you want to use a USB-device backend driver to export a
+ USB device from another domain to the domain which will run this
+ kernel.
+
+config XEN_USBDEV_FRONTEND_TRACE
+ bool "USB-device frontend driver tracing"
+ depends on XEN_USBDEV_FRONTEND
+ default y
+ help
+ This option causes the driver to output a continual trace of its
+ activity.
+ Say N here unless you are trying to debug the driver.
+
config XEN_BLKDEV_TAP
bool "Block device tap driver"
default n
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Sun Oct 30 16:03:34 2005
@@ -1,4 +1,3 @@
-
obj-y += util.o
obj-y += console/
@@ -6,12 +5,14 @@
obj-y += balloon/
obj-y += privcmd/
obj-y += xenbus/
+obj-y += xenidc/
obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/
obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/
+obj-$(CONFIG_XEN_USBDEV_BACKEND) += usbback/
obj-$(CONFIG_XEN_TPMDEV_BACKEND) += tpmback/
obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/
obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/
+obj-$(CONFIG_XEN_USBDEV_FRONTEND) += usbfront/
obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/
obj-$(CONFIG_XEN_TPMDEV_FRONTEND) += tpmfront/
-
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Sun Oct 30 16:03:34 2005
@@ -264,6 +264,7 @@
{
return xenbus_register_driver_common(drv, &xenbus_backend);
}
+EXPORT_SYMBOL(xenbus_register_backend);
void xenbus_unregister_driver(struct xenbus_driver *drv)
{
diff -r b5903c9aeda5 -r e93b9c54edb3 tools/ioemu/target-i386-dm/Makefile
--- a/tools/ioemu/target-i386-dm/Makefile Sun Oct 30 09:45:49 2005
+++ b/tools/ioemu/target-i386-dm/Makefile Sun Oct 30 16:03:34 2005
@@ -188,7 +188,7 @@
#########################################################
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DAPIC_SUPPORT
-LIBS+=-lm -L../../libxc -lxenctrl
+LIBS+=-lm -L../../libxc -lxenctrl -lpthread
ifndef CONFIG_USER_ONLY
LIBS+=-lz
endif
diff -r b5903c9aeda5 -r e93b9c54edb3 tools/python/xen/xend/server/usbif.py
--- a/tools/python/xen/xend/server/usbif.py Sun Oct 30 09:45:49 2005
+++ b/tools/python/xen/xend/server/usbif.py Sun Oct 30 16:03:34 2005
@@ -22,8 +22,9 @@
"""Support for virtual USB hubs.
"""
+from xen.xend import sxp
+
from xen.xend.server.DevController import DevController
-
class UsbifController(DevController):
"""USB device interface controller. Handles all USB devices
@@ -35,8 +36,16 @@
"""
DevController.__init__(self, vm)
-
- def getDeviceDetails(self, _):
+ def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
- return (self.allocateDeviceID(), {}, {})
+ path = sxp.child_value(config, 'path')
+
+ devid = self.allocateDeviceID()
+
+ back = { 'path' : path,
+ 'handle' : "%i" % devid }
+
+ front = { 'handle' : "%i" % devid }
+
+ return (devid, back, front)
diff -r b5903c9aeda5 -r e93b9c54edb3 tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py Sun Oct 30 09:45:49 2005
+++ b/tools/python/xen/xm/create.py Sun Oct 30 16:03:34 2005
@@ -222,6 +222,10 @@
fn=set_bool, default=0,
use="Make the domain a network interface backend.")
+gopts.var('usbif', val='no|yes',
+ fn=set_bool, default=0,
+ use="Make the domain a USB device backend.")
+
gopts.var('tpmif', val='frontend=DOM',
fn=append_value, default=[],
use="""Make the domain a TPM interface backend. If frontend is given,
@@ -242,10 +246,12 @@
For example '-pci c0,02,1a'.
The option may be repeated to add more than one pci device.""")
-gopts.var('usb', val='PATH',
+gopts.var('usb', val="port=PORT,path=PATH,backend=DOM",
fn=append_value, default=[],
- use="""Add a physical USB port to a domain, as specified by the path
- to that port. This option may be repeated to add more than one port.""")
+ use="""Add a USB device, as specified by the path to that device in
+ the backend domain, to the specified virtual hub port of a domain.
+ If backend is not specified the default backend driver domain is
+ used. This option may be repeated to add more than one port.""")
gopts.var('ipaddr', val="IPADDR",
fn=append_value, default=[],
@@ -427,8 +433,13 @@
config_devs.append(['device', config_pci])
def configure_usb(opts, config_devs, vals):
- for path in vals.usb:
- config_usb = ['usb', ['path', path]]
+ for d in vals.usb:
+ path = d.get('path')
+ backend = d.get('backend')
+ config_usb = ['usb']
+ config_usb.append(['path', path])
+ if backend:
+ config_usb.append(['backend', backend])
config_devs.append(['device', config_usb])
def configure_vtpm(opts, config_devs, vals):
@@ -578,6 +589,8 @@
config.append(['backend', ['blkif']])
if vals.netif:
config.append(['backend', ['netif']])
+ if vals.usbif:
+ config.append(['backend', ['usbif']])
if vals.tpmif:
config.append(['backend', ['tpmif']])
if vals.restart:
@@ -649,6 +662,22 @@
d[k] = v
vifs.append(d)
vals.vif = vifs
+
+def preprocess_usb(opts, vals):
+ if not vals.usb: return
+ usb = []
+ for port in vals.usb:
+ d = {}
+ a = port.split(',')
+ for b in a:
+ (k, v) = b.strip().split('=', 1)
+ k = k.strip()
+ v = v.strip()
+ if k not in ['path', 'backend']:
+ opts.err('Invalid usb port specifier: ' + port)
+ d[k] = v
+ usb.append(d)
+ vals.usb = usb
def preprocess_vtpm(opts, vals):
if not vals.vtpm: return
@@ -770,9 +799,10 @@
preprocess_ip(opts, vals)
preprocess_nfs(opts, vals)
preprocess_vnc(opts, vals)
+ preprocess_usb(opts, vals)
preprocess_vtpm(opts, vals)
preprocess_tpmif(opts, vals)
-
+
def make_domain(opts, config):
"""Create, build and start a domain.
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/Makefile
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/Makefile Sun Oct 30 16:03:34 2005
@@ -0,0 +1,9 @@
+obj-$(CONFIG_XEN_USBDEV_BACKEND) += usbback.o
+
+usbback-objs := \
+usbback_device.o \
+usbback_driver_backend.o \
+usbback_driver.o \
+usbback_driver_port.o \
+usbback_driver_port_resource.o \
+usbback_module.o
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,43 @@
+/*****************************************************************************/
+/* Implementation of the ASSERT macro */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef USBBACK_ASSERT_H
+#define USBBACK_ASSERT_H
+
+#include <linux/kernel.h>
+
+static inline void assert_failed
+ ( const char * function, int line, const char * statement )
+{
+ printk
+ (
+ KERN_ERR "usbback assert failed: %s line %d, statement %s\n",
+ function,
+ line,
+ statement
+ );
+
+ BUG();
+}
+
+#define ASSERT( S ) \
+( ( S ) ? ( (void)0 ) : assert_failed( __PRETTY_FUNCTION__, __LINE__, #S ) )
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,401 @@
+/*****************************************************************************/
+/* A device object representing the low-level connection to a single */
+/* front-end. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on */
+/* */
+/* arch/xen/drivers/usbif/backend/control.c */
+/* arch/xen/drivers/usbif/backend/interface.c */
+/* arch/xen/drivers/usbif/backend/main.c */
+/* blkback/xenbus.c */
+/* */
+/* original copyright notices follow... */
+/*****************************************************************************/
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/control.c
+ *
+ * Routines for interfacing with the control plane.
+ *
+ * Copyright (c) 2004, Keir Fraser
+ */
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/interface.c
+ *
+ * USB device interface management.
+ *
+ * by Mark Williamson, Copyright (c) 2004
+ */
+
+/******************************************************************************
+ * arch/xen/drivers/blkif/backend/interface.c
+ *
+ * Block-device interface management.
+ *
+ * Copyright (c) 2004, Keir Fraser
+ */
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ *
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson
+ * Copyright (c) 2004 Intel Research Cambridge
+ * Copyright (c) 2004, 2005 Mark Williamson
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+/* Xenbus code for blkif backend
+ Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <asm-xen/xen-public/io/usbif.h>
+#include <asm-xen/xenbus.h>
+#include <asm-xen/xenidc.h>
+#include "usbback_assert.h"
+#include "usbback_device.h"
+#include "usbback_driver.h"
+#include "usbback_trace.h"
+
+struct usbback_device
+{
+ struct xenbus_device * dev;
+ void * drvdata;
+ long int frontend_id;
+ char * frontend;
+ xenidc_endpoint endpoint;
+};
+
+static inline struct usbback_device * usbback_device_endpoint_to
+ ( xenidc_endpoint * endpoint )
+{
+ trace();
+
+ return container_of( endpoint, struct usbback_device, endpoint );
+}
+
+void usbback_device_set_drvdata( struct usbback_device * device, void * data )
+{
+ trace();
+
+ device->drvdata = data;
+}
+
+void * usbback_device_get_drvdata( struct usbback_device * device )
+{
+ trace();
+
+ return device->drvdata;
+}
+
+static void usbback_device_endpoint_connect( xenidc_endpoint * endpoint )
+{
+ trace();
+
+ /* Transactions and messages received between connect and disconnect are */
+ /* processed normally. */
+ /* Between connect and completion of the disconnect callback we are */
+ /* allowed to issue messages and transactions. We don't actually need */
+ /* to issue messages or transactions from the backend to the frontend. */
+
+ usbback_driver_connect( usbback_device_endpoint_to( endpoint ) );
+}
+
+static void usbback_device_endpoint_disconnect
+ ( xenidc_endpoint * endpoint, xenidc_callback * callback )
+{
+ trace();
+
+ /* We must stop issuing messages and transactions and complete the */
+ /* callback once all of the messages and transactions we are issuing */
+ /* have completed or failed back to us. */
+
+ /* After the disconnect, any messages or transactions we receive must be */
+ /* failed back and we must flush through any that are in progress. */
+
+ usbback_driver_disconnect( usbback_device_endpoint_to( endpoint ) );
+
+ /* We can complete the callback immediately since we are not issuing any */
+ /* messages or transactions from the backend to the frontend. */
+
+ xenidc_callback_success( callback );
+}
+
+static void usbback_device_endpoint_message
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_message * message )
+{
+ trace();
+
+ usbback_driver_message_handler
+ ( usbback_device_endpoint_to( endpoint ), message );
+}
+
+static void usbback_device_endpoint_transaction
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_transaction * transaction )
+{
+ trace();
+
+ usbback_driver_transaction_handler
+ ( usbback_device_endpoint_to( endpoint ), transaction );
+}
+
+static int usbback_device_init_or_exit
+ ( struct usbback_device * device, struct xenbus_device * dev, int exit )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ if( exit )
+ {
+ goto EXIT;
+ }
+
+ memset( device, 0, sizeof( *device ) );
+
+ device->dev = dev;
+
+ return_value = usbback_driver_probe_usbback_device( device );
+
+ if( return_value != 0 )
+ {
+ goto EXIT_NO_DRIVER;
+ }
+
+ device->frontend = NULL;
+
+ return_value = xenbus_gather
+ (
+ NULL, /* FIXME? */
+ dev->nodename,
+ "frontend-id", "%li", &device->frontend_id,
+ "frontend", NULL, &device->frontend,
+ NULL
+ );
+
+ if( XENBUS_EXIST_ERR( return_value ) )
+ {
+ goto EXIT_NO_FRONTEND;
+ }
+
+ if( return_value < 0 )
+ {
+ xenbus_dev_error
+ (
+ dev,
+ return_value,
+ "reading %s/frontend",
+ dev->nodename
+ );
+
+ goto EXIT_NO_FRONTEND;
+ }
+
+ return_value = xenidc_endpoint_init
+ (
+ &device->endpoint,
+ usbback_device_endpoint_connect,
+ usbback_device_endpoint_message,
+ usbback_device_endpoint_transaction,
+ usbback_device_endpoint_disconnect,
+ USBIF_BE_INITIATOR_QUOTA,
+ USBIF_BE_INITIATOR_MAXIMUM_BYTE_COUNT,
+ USBIF_BE_TARGET_QUOTA,
+ USBIF_BE_TARGET_MAXIMUM_BYTE_COUNT
+ );
+
+ if( return_value != 0 )
+ {
+ goto EXIT_NO_ENDPOINT;
+ }
+
+ {
+ xenidc_address address;
+
+ xenidc_address_init
+ (
+ &address,
+ dev->nodename,
+ device->frontend,
+ device->frontend_id
+ );
+
+ xenidc_endpoint_create( &device->endpoint, address );
+ }
+
+ return 0;
+
+ EXIT:
+
+ xenidc_endpoint_destroy( &device->endpoint );
+
+ xenidc_endpoint_exit( &device->endpoint );
+
+ EXIT_NO_ENDPOINT:
+
+ kfree( device->frontend );
+
+ EXIT_NO_FRONTEND:
+
+ usbback_driver_remove_usbback_device( device );
+
+ EXIT_NO_DRIVER:
+
+ return return_value;
+ }
+}
+
+static int usbback_device_init
+ ( struct usbback_device * device, struct xenbus_device * dev )
+{
+ trace();
+
+ return usbback_device_init_or_exit( device, dev, 0 );
+}
+
+static void usbback_device_exit( struct usbback_device * device )
+{
+ trace();
+
+ (void)usbback_device_init_or_exit( device, NULL, 1 );
+}
+
+static int usbback_device_probe_or_remove
+ ( struct xenbus_device * dev, int remove )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ struct usbback_device * device;
+
+ if( remove )
+ {
+ goto REMOVE;
+ }
+
+ device = kmalloc( sizeof( *device ), GFP_KERNEL );
+
+ if( device == NULL )
+ {
+ xenbus_dev_error( dev, -ENOMEM, "allocating backend structure" );
+
+ return_value = -ENOMEM;
+
+ goto EXIT_NO_DEVICE;
+ }
+
+ dev->data = device;
+
+ return_value = usbback_device_init( device, dev );
+
+ if( return_value != 0 )
+ {
+ goto EXIT_INIT_FAILED;
+ }
+
+ return 0;
+
+ REMOVE:
+
+ device = dev->data;
+
+ usbback_device_exit( device );
+
+ EXIT_INIT_FAILED:
+
+ dev->data = NULL;
+
+ kfree( device );
+
+ EXIT_NO_DEVICE:
+
+ return return_value;
+ }
+}
+
+static int usbback_device_probe
+ ( struct xenbus_device * dev, const struct xenbus_device_id * id )
+{
+ trace();
+
+ return usbback_device_probe_or_remove( dev, 0 );
+}
+
+static int usbback_device_remove( struct xenbus_device * dev )
+{
+ trace();
+
+ return usbback_device_probe_or_remove( dev, 1 );
+}
+
+static struct xenbus_device_id usbback_device_ids[] =
+{
+ { "usb" },
+ { "" }
+};
+
+static struct xenbus_driver usbback_device_driver =
+{
+ .name = "usb",
+ .owner = THIS_MODULE,
+ .ids = usbback_device_ids,
+ .probe = usbback_device_probe,
+ .remove = usbback_device_remove,
+};
+
+int usbback_device_class_init( void )
+{
+ trace();
+
+ xenbus_register_backend( &usbback_device_driver );
+
+ return 0;
+}
+
+void usbback_device_class_exit( void )
+{
+ trace();
+
+ xenbus_unregister_driver( &usbback_device_driver );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,37 @@
+/*****************************************************************************/
+/* A device object representing the low-level connection to a single */
+/* front-end. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef USBBACK_DEVICE_H
+#define USBBACK_DEVICE_H
+
+extern int usbback_device_class_init( void );
+
+extern void usbback_device_class_exit( void );
+
+struct usbback_device;
+
+extern void usbback_device_set_drvdata
+ ( struct usbback_device * device, void * data );
+
+extern void * usbback_device_get_drvdata( struct usbback_device * device );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,249 @@
+/*****************************************************************************/
+/* Device driver which drives usbback_device devices. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#include <linux/device.h>
+#include <linux/usb.h>
+#include "usbback_assert.h"
+#include "usbback_device.h"
+#include "usbback_driver.h"
+#include "usbback_driver_backend.h"
+#include "usbback_driver_port.h"
+#include "usbback_trace.h"
+
+static int usbback_driver_probe_usb
+ ( struct usb_interface * intf, const struct usb_device_id * id )
+{
+ trace();
+
+ return usbback_driver_port_probe_usb( intf );
+}
+
+static void usbback_driver_disconnect_usb( struct usb_interface * intf )
+{
+ trace();
+
+ usbback_driver_port_disconnect_usb( intf );
+}
+
+static int usbback_driver_probe_or_remove_usbback_device
+ ( struct usbback_device * device, int remove )
+{
+ trace();
+
+ {
+ struct usbback_driver_backend * backend;
+
+ int return_value = 0;
+
+ if( remove )
+ {
+ goto REMOVE;
+ }
+
+ backend = usbback_driver_backend_allocate( device );
+
+ if( backend == NULL )
+ {
+ return_value = -ENOMEM;
+
+ goto EXIT_NO_BACKEND;
+ }
+
+ usbback_device_set_drvdata( device, backend );
+
+ return 0;
+
+ REMOVE:
+
+ backend = usbback_device_get_drvdata( device );
+
+ usbback_driver_backend_shutdown( backend );
+
+ usbback_device_set_drvdata( device, NULL );
+
+ EXIT_NO_BACKEND:
+
+ return return_value;
+ }
+}
+
+int usbback_driver_probe_usbback_device( struct usbback_device * device )
+{
+ trace();
+
+ return usbback_driver_probe_or_remove_usbback_device( device, 0 );
+}
+
+void usbback_driver_connect( struct usbback_device * device )
+{
+ trace();
+
+ {
+ struct usbback_driver_backend * backend =
+ usbback_device_get_drvdata( device );
+
+ usbback_driver_backend_connect( backend );
+ }
+}
+
+void usbback_driver_message_handler
+ ( struct usbback_device * device, xenidc_endpoint_message * message )
+{
+ trace();
+
+ {
+ struct usbback_driver_backend * backend =
+ usbback_device_get_drvdata( device );
+
+ usbback_driver_backend_message_handler( backend, message );
+ }
+}
+
+void usbback_driver_transaction_handler
+ ( struct usbback_device * device, xenidc_endpoint_transaction * transaction )
+{
+ trace();
+
+ {
+ struct usbback_driver_backend * backend =
+ usbback_device_get_drvdata( device );
+
+ usbback_driver_backend_transaction_handler( backend, transaction );
+ }
+}
+
+void usbback_driver_disconnect( struct usbback_device * device )
+{
+ trace();
+
+ {
+ struct usbback_driver_backend * backend =
+ usbback_device_get_drvdata( device );
+
+ usbback_driver_backend_disconnect( backend );
+ }
+}
+
+void usbback_driver_claim_port
+ ( struct usbback_device * device, u32 port, char * path )
+{
+ trace();
+
+ {
+ struct usbback_driver_backend * backend =
+ usbback_device_get_drvdata( device );
+
+ usbback_driver_backend_claim_port( backend, port, path );
+ }
+}
+
+void usbback_driver_release_port
+ ( struct usbback_device * device, u32 port )
+{
+ trace();
+
+ {
+ struct usbback_driver_backend * backend =
+ usbback_device_get_drvdata( device );
+
+ usbback_driver_backend_release_port( backend, port );
+ }
+}
+
+void usbback_driver_remove_usbback_device( struct usbback_device * device )
+{
+ trace();
+
+ (void)usbback_driver_probe_or_remove_usbback_device( device, 1 );
+}
+
+static struct usb_device_id usbback_driver_usb_id_table[] =
+{
+ { .driver_info = 1 }, /* Matches all devices. */
+ {}
+};
+
+MODULE_DEVICE_TABLE( usb, usbback_driver_usb_id_table );
+
+struct usb_driver usbback_driver_usb_driver =
+{
+ .owner = THIS_MODULE,
+ .name = "usbback",
+ .probe = usbback_driver_probe_usb,
+ .disconnect = usbback_driver_disconnect_usb,
+ .id_table = usbback_driver_usb_id_table,
+};
+
+static int usbback_driver_init_or_exit( int exit )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ if( exit )
+ {
+ goto EXIT;
+ }
+
+ return_value = usbback_driver_port_class_init();
+
+ if( return_value != 0 )
+ {
+ goto EXIT_NO_PORT_CLASS;
+ }
+
+ return_value = usb_register( &usbback_driver_usb_driver );
+
+ if( return_value != 0 )
+ {
+ goto EXIT_NO_USB_REGISTER;
+ }
+
+ return 0;
+
+ EXIT:
+
+ usb_deregister( &usbback_driver_usb_driver );
+
+ EXIT_NO_USB_REGISTER:
+
+ usbback_driver_port_class_exit();
+
+ EXIT_NO_PORT_CLASS:
+
+ return return_value;
+ }
+}
+
+int usbback_driver_init( void )
+{
+ trace();
+
+ return usbback_driver_init_or_exit( 0 );
+}
+
+void usbback_driver_exit( void )
+{
+ trace();
+
+ (void)usbback_driver_init_or_exit( 1 );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,57 @@
+/*****************************************************************************/
+/* Device driver which drives usbback_device devices. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef USBBACK_DRIVER_H
+#define USBBACK_DRIVER_H
+
+#include "asm-xen/xenidc.h"
+#include "usbback_device.h"
+
+extern int usbback_driver_init( void );
+
+extern int usbback_driver_probe_usbback_device
+ ( struct usbback_device * device );
+
+extern void usbback_driver_connect( struct usbback_device * device );
+
+extern void usbback_driver_message_handler
+ ( struct usbback_device * device, xenidc_endpoint_message * message );
+
+extern void usbback_driver_transaction_handler
+(
+ struct usbback_device * device,
+ xenidc_endpoint_transaction * transaction
+);
+
+extern void usbback_driver_disconnect( struct usbback_device * device );
+
+extern void usbback_driver_claim_port
+ ( struct usbback_device * device, u32 port, char * path );
+
+extern void usbback_driver_release_port
+ ( struct usbback_device * device, u32 port );
+
+extern void usbback_driver_remove_usbback_device
+ ( struct usbback_device * device );
+
+extern void usbback_driver_exit( void );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,603 @@
+/*****************************************************************************/
+/* usbback_driver_backend is the representation in the driver of the */
+/* back-end side of a single front-end to back-end connection. */
+/* One of these objects is used by the usbback_driver to manage each */
+/* usbback_device. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on arch/xen/drivers/usbif/backend/main.c, original copyright notice */
+/* follows... */
+/*****************************************************************************/
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ *
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson
+ * Copyright (c) 2004 Intel Research Cambridge
+ * Copyright (c) 2004, 2005 Mark Williamson
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+#include <asm-xen/xen-public/io/usbif.h>
+#include "usbback_assert.h"
+#include "usbback_device.h"
+#include "usbback_driver_backend.h"
+#include "usbback_driver_port.h"
+#include "usbback_trace.h"
+
+#define USBBACK_DRIVER_PORT_COUNT 7
+
+struct usbback_driver_backend
+{
+ struct usbback_device * device;
+ struct usbback_driver_port port[ USBBACK_DRIVER_PORT_COUNT ];
+};
+
+static int usbback_driver_backend_init_or_exit
+(
+ struct usbback_driver_backend * backend,
+ struct usbback_device * device,
+ int exit
+)
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ if( exit )
+ {
+ goto EXIT;
+ }
+
+ memset( backend, 0, sizeof( *backend ) );
+
+ backend->device = device;
+
+ {
+ int i;
+
+ for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ )
+ {
+ return_value =
+ usbback_driver_port_init( &backend->port[ i ], backend );
+
+ if( return_value != 0 )
+ {
+ goto EXIT_NO_PORT;
+ }
+ }
+
+ return 0;
+
+ EXIT:
+
+ i = USBBACK_DRIVER_PORT_COUNT;
+
+ EXIT_NO_PORT:
+
+ i--;
+
+ for( ; i >= 0; i-- )
+ {
+ usbback_driver_port_shutdown( &backend->port[ i ] );
+ }
+ }
+
+ return return_value;
+ }
+}
+
+struct usbback_driver_backend * usbback_driver_backend_allocate
+ ( struct usbback_device * device )
+{
+ struct usbback_driver_backend * backend =
+ (struct usbback_driver_backend *)kmalloc
+ ( sizeof( struct usbback_driver_backend ), GFP_KERNEL );
+
+ if
+ (
+ ( backend != NULL )
+ &&
+ ( usbback_driver_backend_init_or_exit( backend, device, 0 ) != 0 )
+ )
+ {
+ kfree( backend );
+
+ backend = NULL;
+ }
+
+ return backend;
+}
+
+void usbback_driver_backend_connect( struct usbback_driver_backend * backend )
+{
+ trace();
+
+ {
+ int i;
+
+ for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ )
+ {
+ usbback_driver_port_connect( &backend->port[ i ] );
+ }
+ }
+}
+
+static void usbback_driver_backend_handle_probe
+(
+ struct usbback_driver_backend * backend,
+ xenidc_endpoint_transaction * transaction
+);
+
+static void usbback_driver_backend_handle_reset
+(
+ struct usbback_driver_backend * backend,
+ xenidc_endpoint_transaction * transaction
+);
+
+static void usbback_driver_backend_handle_io
+(
+ struct usbback_driver_backend * backend,
+ xenidc_endpoint_transaction * transaction
+);
+
+void usbback_driver_backend_transaction_handler
+(
+ struct usbback_driver_backend * backend,
+ xenidc_endpoint_transaction * transaction
+)
+{
+ /* trace(); */
+
+ usbif_transaction_parameters_header header;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ xenidc_endpoint_transaction_to_parameters_lbr( transaction ),
+ &header,
+ sizeof( header )
+ )
+ ==
+ sizeof( header )
+ )
+ {
+ switch( header.transaction_type )
+ {
+ case USBIF_TRANSACTION_TYPE_PROBE:
+ usbback_driver_backend_handle_probe( backend, transaction );
+ break;
+ case USBIF_TRANSACTION_TYPE_RESET:
+ usbback_driver_backend_handle_reset( backend, transaction );
+ break;
+ case USBIF_TRANSACTION_TYPE_IO:
+ usbback_driver_backend_handle_io( backend, transaction );
+ break;
+ default:
+ xenidc_endpoint_transaction_complete
+ ( transaction, XENIDC_ERROR_INVALID_PARAMETER );
+ break;
+ }
+ }
+ else
+ {
+ /* Parameters were underlength. */
+
+ xenidc_endpoint_transaction_complete
+ ( transaction, XENIDC_ERROR_INVALID_FORMAT );
+ }
+}
+
+static void usbback_driver_backend_handle_probe
+(
+ struct usbback_driver_backend * backend,
+ xenidc_endpoint_transaction * transaction
+)
+{
+ /* trace(); */
+
+ usbif_probe_transaction_parameters parameters;
+
+ xenidc_error error;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ xenidc_endpoint_transaction_to_parameters_lbr( transaction ),
+ ¶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
+ (
+ xenidc_endpoint_transaction_to_status_lbr( transaction ),
+ &status,
+ sizeof( status )
+ )
+ !=
+ sizeof( status )
+ )
+ {
+ error = XENIDC_ERROR_INVALID_FORMAT;
+
+ goto COMPLETE;
+ }
+ }
+
+ error = XENIDC_ERROR_SUCCESS;
+
+ COMPLETE:
+
+ xenidc_endpoint_transaction_complete( transaction, error );
+}
+
+static void usbback_driver_backend_handle_reset
+(
+ struct usbback_driver_backend * backend,
+ xenidc_endpoint_transaction * transaction
+)
+{
+ trace();
+
+ {
+ usbif_reset_transaction_parameters parameters;
+
+ xenidc_error error;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ xenidc_endpoint_transaction_to_parameters_lbr( transaction ),
+ ¶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
+ (
+ xenidc_endpoint_transaction_to_status_lbr
+ ( transaction ),
+ &status,
+ sizeof( status )
+ )
+ !=
+ sizeof( status )
+ )
+ {
+ error = XENIDC_ERROR_INVALID_FORMAT;
+
+ goto COMPLETE;
+ }
+ }
+ }
+
+ error = XENIDC_ERROR_SUCCESS;
+
+ COMPLETE:
+
+ xenidc_endpoint_transaction_complete( transaction, error );
+ }
+}
+
+static struct usbback_driver_port *
+ usbback_driver_backend_find_port_by_guest_address
+(
+ struct usbback_driver_backend * backend,
+ unsigned long guest_address
+)
+{
+ trace();
+
+ {
+ int i;
+
+ for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ )
+ {
+ struct usbback_driver_port * port = &backend->port[ i ];
+
+ if
+ (
+ usbback_driver_port_match_guest_address( port, guest_address )
+ )
+ {
+ return port;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void usbback_driver_backend_handle_io
+(
+ struct usbback_driver_backend * backend,
+ xenidc_endpoint_transaction * transaction
+)
+{
+ trace();
+
+ {
+ usbif_io_transaction_parameters_header header;
+
+ xenidc_error error;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ xenidc_endpoint_transaction_to_parameters_lbr( transaction ),
+ &header,
+ sizeof( header )
+ )
+ !=
+ sizeof( header )
+ )
+ {
+ error = XENIDC_ERROR_INVALID_FORMAT;
+
+ goto COMPLETE;
+ }
+
+ {
+ struct usbback_driver_port * port =
+ usbback_driver_backend_find_port_by_guest_address
+ ( backend, header.device_number );
+
+ if( port == NULL )
+ {
+ error = USBIF_XENIDC_ERROR_NO_DEVICE;
+
+ goto COMPLETE;
+ }
+
+ usbback_driver_port_handle_io( port, transaction );
+ }
+
+ return;
+
+ COMPLETE:
+
+ xenidc_endpoint_transaction_complete( transaction, error );
+ }
+}
+
+static void usbback_driver_backend_handle_unlink
+(
+ struct usbback_driver_backend * backend,
+ xenidc_endpoint_message * message
+);
+
+void usbback_driver_backend_message_handler
+(
+ struct usbback_driver_backend * backend,
+ xenidc_endpoint_message * message
+)
+{
+ trace();
+
+ {
+ usbif_message_header header;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ xenidc_endpoint_message_to_message_lbr( message ),
+ &header,
+ sizeof( header )
+ )
+ ==
+ sizeof( header )
+ )
+ {
+ switch( header.message_type )
+ {
+ case USBIF_MESSAGE_TYPE_UNLINK:
+ usbback_driver_backend_handle_unlink( backend, message );
+ break;
+ }
+ }
+
+ xenidc_callback_success
+ ( xenidc_endpoint_message_to_callback( message ) );
+ }
+}
+
+static void usbback_driver_backend_handle_unlink
+(
+ struct usbback_driver_backend * backend,
+ xenidc_endpoint_message * message
+)
+{
+ trace();
+
+ {
+ usbif_unlink_message_body unlink;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ xenidc_endpoint_message_to_message_lbr( message ),
+ &unlink,
+ sizeof( unlink )
+ )
+ ==
+ sizeof( unlink )
+ )
+ {
+ int i;
+
+ for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ )
+ {
+ struct usbback_driver_port * port = &backend->port[ i ];
+
+ if
+ (
+ usbback_driver_port_try_unlink
+ ( port, unlink.unlink_id )
+ )
+ {
+ break;
+ }
+ }
+ }
+ }
+}
+
+void usbback_driver_backend_disconnect
+ ( struct usbback_driver_backend * backend )
+{
+ trace();
+
+ {
+ int i;
+
+ for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ )
+ {
+ usbback_driver_port_disconnect( &backend->port[ i ] );
+ }
+ }
+}
+
+void usbback_driver_backend_claim_port
+ ( struct usbback_driver_backend * backend, u32 port, char * path )
+{
+ trace2( "port: %d, path: %s", port, path );
+
+ ASSERT
+ (
+ ( port > 0 )
+ &&
+ ( port <= USBBACK_DRIVER_PORT_COUNT )
+ );
+
+ usbback_driver_port_claim( &backend->port[ port - 1 ], path );
+
+ bus_rescan_devices( &usb_bus_type );
+}
+
+void usbback_driver_backend_release_port
+ ( struct usbback_driver_backend * backend, u32 port )
+{
+ trace1( "port: %d", port );
+
+ ASSERT
+ (
+ ( port > 0 )
+ &&
+ ( port <= USBBACK_DRIVER_PORT_COUNT )
+ );
+
+ usbback_driver_port_release( &backend->port[ port - 1 ] );
+
+ bus_rescan_devices( &usb_bus_type );
+}
+
+void usbback_driver_backend_shutdown
+ ( struct usbback_driver_backend * backend )
+{
+ trace();
+
+ (void)usbback_driver_backend_init_or_exit( backend, NULL, 1 );
+
+ kfree( backend );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,63 @@
+/*****************************************************************************/
+/* usbback_driver_backend is the representation in the driver of the */
+/* back-end side of a single front-end to back-end connection. */
+/* One of these objects is used by the usbback_driver to manage each */
+/* usbback_device. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef USBBACK_DRIVER_BACKEND_H
+#define USBBACK_DRIVER_BACKEND_H
+
+#include "asm-xen/xenidc.h"
+#include "usbback_device.h"
+
+struct usbback_driver_backend;
+
+extern struct usbback_driver_backend * usbback_driver_backend_allocate
+ ( struct usbback_device * device );
+
+extern void usbback_driver_backend_connect
+ ( struct usbback_driver_backend * backend );
+
+extern void usbback_driver_backend_transaction_handler
+(
+ struct usbback_driver_backend * backend,
+ xenidc_endpoint_transaction * transaction
+);
+
+extern void usbback_driver_backend_message_handler
+(
+ struct usbback_driver_backend * backend,
+ xenidc_endpoint_message * message
+);
+
+extern void usbback_driver_backend_disconnect
+ ( struct usbback_driver_backend * backend );
+
+extern void usbback_driver_backend_claim_port
+ ( struct usbback_driver_backend * backend, u32 port, char * path );
+
+extern void usbback_driver_backend_release_port
+ ( struct usbback_driver_backend * backend, u32 port );
+
+extern void usbback_driver_backend_shutdown
+ ( struct usbback_driver_backend * backend );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,1163 @@
+/*****************************************************************************/
+/* Object which manages a single USB device and handles all the IO */
+/* transactions for that device by assigning usbback_driver_port_resources */
+/* to process them. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on arch/xen/drivers/usbif/backend/main.c, original copyright notice */
+/* follows... */
+/*****************************************************************************/
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ *
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson
+ * Copyright (c) 2004 Intel Research Cambridge
+ * Copyright (c) 2004, 2005 Mark Williamson
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+#include <linux/rwsem.h>
+#include <asm-xen/xen-public/io/usbif.h>
+#include "usbback_assert.h"
+#include "usbback_driver_port.h"
+#include "usbback_trace.h"
+
+int usbback_driver_port_class_init( void )
+{
+ trace();
+
+ return usbback_driver_port_resource_class_init();
+}
+
+void usbback_driver_port_class_exit( void )
+{
+ trace();
+
+ usbback_driver_port_resource_class_exit();
+}
+
+extern struct usb_driver usbback_driver_usb_driver;
+
+static DECLARE_RWSEM( usbback_driver_port_list_sem );
+
+static LIST_HEAD( usbback_driver_port_list );
+
+typedef enum
+{
+ usbback_driver_port_stimulus_pc, /* Port claim */
+ usbback_driver_port_stimulus_pr, /* Port release */
+ usbback_driver_port_stimulus_up, /* USB probe */
+ usbback_driver_port_stimulus_ud, /* USB disconnect */
+ usbback_driver_port_stimulus_cn, /* endpoint connect */
+ usbback_driver_port_stimulus_dn, /* endpoint disconnect */
+ usbback_driver_port_stimulus_rq, /* Transaction queued/resource freed */
+ usbback_driver_port_stimulus_sd, /* Shutdown */
+ usbback_driver_port_stimulus_ri, /* test_io transactions idle (reent) */
+ usbback_driver_port_stimulus_rr, /* test_io transactions running (reent) */
+ usbback_driver_port_stimulus_rp, /* release performed */
+}
+usbback_driver_port_stimulus;
+
+static void usbback_driver_port_handle_stimulus
+(
+ struct usbback_driver_port * port,
+ usbback_driver_port_stimulus stimulus
+);
+
+static void usbback_driver_port_purge_io_1( void * data );
+
+static void usbback_driver_port_perform_release_1( void * data );
+
+int usbback_driver_port_init
+(
+ struct usbback_driver_port * port,
+ struct usbback_driver_backend * backend
+)
+{
+ trace();
+
+ memset( port, 0, sizeof( *port ) );
+
+ port->backend = backend;
+
+ INIT_LIST_HEAD( &port->link );
+
+ spin_lock_init( &port->lock );
+
+ port->state = usbback_driver_port_state_i;
+
+ INIT_LIST_HEAD( &port->transaction_list );
+ INIT_LIST_HEAD( &port->purge_list );
+ INIT_LIST_HEAD( &port->free_resource_list );
+
+ {
+ int i;
+
+ for( i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++ )
+ {
+ struct usbback_driver_port_resource * resource =
+ &port->resources[ i ];
+
+ usbback_driver_port_resource_init( resource, port );
+
+ list_add( &resource->link, &port->free_resource_list );
+ }
+ }
+
+ xenidc_work_init
+ ( &port->purge_io_1_work, usbback_driver_port_purge_io_1, port );
+
+ xenidc_work_init
+ (
+ &port->perform_release_1_work,
+ usbback_driver_port_perform_release_1,
+ port
+ );
+
+ return 0;
+}
+
+void usbback_driver_port_claim
+ ( struct usbback_driver_port * port, char * path )
+{
+ trace();
+
+ down_write( &usbback_driver_port_list_sem );
+
+ strncpy( port->path, path, sizeof( port->path ) );
+
+ list_add_tail( &port->link, &usbback_driver_port_list );
+
+ spin_lock_irq( &port->lock );
+
+ usbback_driver_port_handle_stimulus
+ ( port, usbback_driver_port_stimulus_pc );
+
+ spin_unlock_irq( &port->lock );
+
+ up_write( &usbback_driver_port_list_sem );
+}
+
+void usbback_driver_port_release( struct usbback_driver_port * port )
+{
+ trace();
+
+ down_write( &usbback_driver_port_list_sem );
+
+ list_del_init( &port->link );
+
+ up_write( &usbback_driver_port_list_sem );
+
+ port->release = 0;
+
+ spin_lock_irq( &port->lock );
+
+ usbback_driver_port_handle_stimulus
+ ( port, usbback_driver_port_stimulus_pr );
+
+ spin_unlock_irq( &port->lock );
+
+ xenidc_work_until( port->release );
+}
+
+int usbback_driver_port_probe_usb( struct usb_interface * intf )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ struct usb_device * usbdev = interface_to_usbdev( intf );
+
+ struct usbback_driver_port * port = NULL;
+
+ printk
+ ( KERN_INFO "usbback: Probe for usb device %s\n", usbdev->devpath );
+
+ down_read( &usbback_driver_port_list_sem );
+
+ {
+ struct usbback_driver_port * cur = NULL;
+
+ list_for_each_entry( cur, &usbback_driver_port_list, link )
+ {
+ printk
+ (
+ KERN_INFO
+ "usbback: Testing against configured path %s:",
+ cur->path
+ );
+
+ if
+ (
+ strncmp( cur->path, usbdev->devpath, sizeof( cur->path ) )
+ ==
+ 0
+ )
+ {
+ printk( " matches.\n" );
+
+ port = cur;
+
+ break;
+ }
+ else
+ {
+ printk( " doesn't match.\n" );
+ }
+ }
+ }
+
+ if( port == NULL )
+ {
+ printk( KERN_INFO "usbback: No match found.\n" );
+
+ return_value = -ENODEV;
+
+ goto EXIT_NO_PORT;
+ }
+
+ {
+ int i;
+
+ for( i = 0; i < usbdev->actconfig->desc.bNumInterfaces; i++ )
+ {
+ struct usb_interface * other_intf =
+ usb_ifnum_to_if( usbdev, i );
+
+ if( other_intf != intf )
+ {
+ if( usb_interface_claimed( other_intf ) )
+ {
+ printk
+ (
+ KERN_INFO
+ "usbback: An interface of the matching device is "
+ "already in use by another driver.\n"
+ );
+
+ return_value = -EBUSY;
+
+ goto EXIT_INTERFACE_ALREADY_CLAIMED;
+ }
+ }
+ }
+ }
+
+ {
+ int i;
+
+ for( i = 0; i < usbdev->actconfig->desc.bNumInterfaces; i++ )
+ {
+ struct usb_interface * other_intf =
+ usb_ifnum_to_if( usbdev, i );
+
+ if( other_intf != intf )
+ {
+ int error = usb_driver_claim_interface
+ ( &usbback_driver_usb_driver, other_intf, port );
+
+ /* We already checked all the interfaces were available. */
+
+ ASSERT( error == 0 );
+ }
+ }
+ }
+
+ usbdev = usb_get_dev( usbdev );
+
+ usb_set_intfdata( intf, port );
+
+ spin_lock_irq( &port->lock );
+
+ port->usbdev_is_connected = 1;
+
+ port->usbdev = usbdev;
+
+ usbback_driver_port_handle_stimulus
+ ( port, usbback_driver_port_stimulus_up );
+
+ spin_unlock_irq( &port->lock );
+
+ EXIT_INTERFACE_ALREADY_CLAIMED:
+
+ EXIT_NO_PORT:
+
+ up_read( &usbback_driver_port_list_sem );
+
+ return return_value;
+ }
+}
+
+void usbback_driver_port_disconnect_usb( struct usb_interface * intf )
+{
+ trace();
+
+ {
+ struct usbback_driver_port * port = usb_get_intfdata( intf );
+
+ /* Protect against reentrant call when we release other interfaces. */
+
+ if( port != NULL )
+ {
+ ASSERT( port->usbdev_is_connected );
+
+ spin_lock_irq( &port->lock );
+
+ port->usbdev_is_connected = 0;
+
+ port->enabled = 0;
+
+ port->usb_disconnect = 0;
+
+ usbback_driver_port_handle_stimulus
+ ( port, usbback_driver_port_stimulus_ud );
+
+ spin_unlock_irq( &port->lock );
+
+ xenidc_work_until( port->usb_disconnect );
+
+ {
+ struct usb_device * usbdev = port->usbdev;
+
+ {
+ int i;
+
+ for
+ (
+ i = 0;
+ i < usbdev->actconfig->desc.bNumInterfaces;
+ i++
+ )
+ {
+ struct usb_interface * other_intf =
+ usb_ifnum_to_if( usbdev, i );
+
+ if( other_intf != intf )
+ {
+ /* Protect against reentrant call when we */
+ /* release other interfaces. */
+
+ usb_set_intfdata( other_intf, NULL );
+
+ usb_driver_release_interface
+ ( &usbback_driver_usb_driver, other_intf );
+ }
+ }
+ }
+
+ usb_set_intfdata( intf, NULL );
+
+ usb_put_dev( usbdev );
+ }
+ }
+ }
+}
+
+int usbback_driver_port_reset( struct usbback_driver_port * port )
+{
+ trace();
+
+ {
+ int status = -1;
+
+ spin_lock_irq( &port->lock );
+
+ port->guest_address = 0;
+
+ if( usbback_driver_port_usbdev_is_connected( port ) )
+ {
+ if( port->usbdev->speed == USB_SPEED_LOW )
+ {
+ status = USBIF_RESET_RESULT_LOW_SPEED;
+ }
+ else if( port->usbdev->speed == USB_SPEED_HIGH )
+ {
+ status = USBIF_RESET_RESULT_HIGH_SPEED;
+ }
+ else
+ {
+ status = USBIF_RESET_RESULT_FULL_SPEED;
+ }
+
+ port->enabled = 1;
+ }
+ else
+ {
+ port->enabled = 0;
+ }
+
+ spin_unlock_irq( &port->lock );
+
+ return status;
+ }
+}
+
+void usbback_driver_port_set_guest_address
+ ( struct usbback_driver_port * port, unsigned long guest_address )
+{
+ trace();
+
+ port->guest_address = guest_address;
+}
+
+int usbback_driver_port_match_guest_address
+ ( struct usbback_driver_port * port, unsigned long guest_address )
+{
+ trace();
+
+ return ( port->enabled && ( guest_address == port->guest_address ) );
+}
+
+void usbback_driver_port_connect( struct usbback_driver_port * port )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &port->lock, flags );
+
+ usbback_driver_port_handle_stimulus
+ ( port, usbback_driver_port_stimulus_cn );
+
+ spin_unlock_irqrestore( &port->lock, flags );
+ }
+}
+
+void usbback_driver_port_handle_io
+(
+ struct usbback_driver_port * port,
+ xenidc_endpoint_transaction * transaction
+)
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &port->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_endpoint_transaction_to_link( transaction ),
+ &port->transaction_list
+ );
+
+ usbback_driver_port_handle_stimulus
+ ( port, usbback_driver_port_stimulus_rq );
+
+ spin_unlock_irqrestore( &port->lock, flags );
+ }
+}
+
+void usbback_driver_port_disconnect( struct usbback_driver_port * port )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &port->lock, flags );
+
+ usbback_driver_port_handle_stimulus
+ ( port, usbback_driver_port_stimulus_dn );
+
+ spin_unlock_irqrestore( &port->lock, flags );
+ }
+}
+
+int usbback_driver_port_try_unlink
+ ( struct usbback_driver_port * port, int unlink_id )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ xenidc_endpoint_transaction * transaction = NULL;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &port->lock, flags );
+
+ {
+ xenidc_endpoint_transaction * temp;
+
+ list_for_each_entry
+ (
+ temp,
+ &port->transaction_list,
+ XENIDC_ENDPOINT_TRANSACTION_LINK
+ )
+ {
+ usbif_io_transaction_parameters_header header;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ xenidc_endpoint_transaction_to_parameters_lbr
+ ( transaction ),
+ &header,
+ sizeof( header )
+ )
+ ==
+ sizeof( header )
+ )
+ {
+ if( header.unlink_id == unlink_id )
+ {
+ transaction = temp;
+
+ list_del_init
+ (
+ xenidc_endpoint_transaction_to_link( transaction )
+ );
+
+ break;
+ }
+ }
+ }
+ }
+
+ if( transaction == NULL )
+ {
+ int i;
+
+ for( i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++ )
+ {
+ struct usbback_driver_port_resource * resource =
+ &port->resources[ i ];
+
+ if
+ (
+ usbback_driver_port_resource_try_unlink
+ ( resource, unlink_id )
+ )
+ {
+ return_value = 1;
+
+ break;
+ }
+ }
+ }
+
+ spin_unlock_irqrestore( &port->lock, flags );
+
+ if( transaction )
+ {
+ xenidc_endpoint_transaction_complete
+ ( transaction, USBIF_XENIDC_ERROR_UNLINKED );
+
+ return_value = 1;
+ }
+
+ return return_value;
+ }
+}
+
+void usbback_driver_port_shutdown( struct usbback_driver_port * port )
+{
+ trace();
+
+ down_write( &usbback_driver_port_list_sem );
+
+ list_del_init( &port->link );
+
+ up_write( &usbback_driver_port_list_sem );
+
+ port->shutdown = 0;
+
+ spin_lock_irq( &port->lock );
+
+ usbback_driver_port_handle_stimulus
+ ( port, usbback_driver_port_stimulus_sd );
+
+ spin_unlock_irq( &port->lock );
+
+ xenidc_work_until( port->shutdown );
+
+ flush_scheduled_work();
+}
+
+static void usbback_driver_port_invalid_stimulus
+ ( struct usbback_driver_port * port, usbback_driver_port_stimulus stimulus );
+
+static void usbback_driver_port_purge_io( struct usbback_driver_port * port );
+
+static void usbback_driver_port_test_io( struct usbback_driver_port * port );
+
+static void usbback_driver_port_kick_io( struct usbback_driver_port * port );
+
+static void usbback_driver_port_perform_release
+ ( struct usbback_driver_port * port );
+
+static void usbback_driver_port_complete_release
+ ( struct usbback_driver_port * port );
+
+static void usbback_driver_port_complete_usb_disconnect
+ ( struct usbback_driver_port * port );
+
+static void usbback_driver_port_complete_shutdown
+ ( struct usbback_driver_port * port );
+
+/* FIXME: update to add cn and dn */
+
+static void usbback_driver_port_handle_stimulus
+(
+ struct usbback_driver_port * port,
+ usbback_driver_port_stimulus stimulus
+)
+{
+ trace3
+ (
+ "port %p in state %d received stimulus %d",
+ port,
+ port->state,
+ stimulus
+ );
+
+ switch( port->state )
+ {
+ case usbback_driver_port_state_i:
+ /* Released */
+ /* Disconnected */
+ /* Idle */
+ switch( stimulus )
+ {
+ case usbback_driver_port_stimulus_pc:
+ port->state = usbback_driver_port_state_i_pc;
+ break;
+ case usbback_driver_port_stimulus_rq:
+ usbback_driver_port_purge_io( port );
+ break;
+ case usbback_driver_port_stimulus_sd:
+ usbback_driver_port_complete_shutdown( port );
+ break;
+ default:
+ usbback_driver_port_invalid_stimulus( port, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_state_i_pc:
+ /* Claimed */
+ /* Disconnected */
+ /* Idle */
+ switch( stimulus )
+ {
+ case usbback_driver_port_stimulus_pr:
+ port->state = usbback_driver_port_state_i;
+ usbback_driver_port_complete_release( port );
+ break;
+ case usbback_driver_port_stimulus_up:
+ port->state = usbback_driver_port_state_i_pc_up;
+ break;
+ case usbback_driver_port_stimulus_rq:
+ usbback_driver_port_purge_io( port );
+ break;
+ case usbback_driver_port_stimulus_sd:
+ port->state = usbback_driver_port_state_i;
+ usbback_driver_port_complete_shutdown( port );
+ break;
+ default:
+ usbback_driver_port_invalid_stimulus( port, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_state_i_pc_up:
+ /* Claimed */
+ /* Probed */
+ /* Maybe Running */
+ switch( stimulus )
+ {
+ case usbback_driver_port_stimulus_pr:
+ port->state = usbback_driver_port_state_i_pc_up_pr;
+ usbback_driver_port_purge_io( port );
+ usbback_driver_port_test_io( port );
+ break;
+ case usbback_driver_port_stimulus_ud:
+ port->state = usbback_driver_port_state_i_pc_up_ud;
+ usbback_driver_port_purge_io( port );
+ usbback_driver_port_test_io( port );
+ break;
+ case usbback_driver_port_stimulus_rq:
+ usbback_driver_port_kick_io( port );
+ break;
+ case usbback_driver_port_stimulus_sd:
+ port->state = usbback_driver_port_state_i_pc_up_sd;
+ usbback_driver_port_purge_io( port );
+ usbback_driver_port_test_io( port );
+ break;
+ default:
+ usbback_driver_port_invalid_stimulus( port, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_state_i_pc_up_pr:
+ /* Releasing */
+ /* Probed */
+ /* Testing/Running */
+ switch( stimulus )
+ {
+ case usbback_driver_port_stimulus_ud:
+ port->state = usbback_driver_port_state_i_pc_up_pr_ud;
+ break;
+ case usbback_driver_port_stimulus_rq:
+ usbback_driver_port_purge_io( port );
+ usbback_driver_port_test_io( port );
+ break;
+ case usbback_driver_port_stimulus_ri:
+ port->state = usbback_driver_port_state_i_pc_up_pr_ri;
+ usbback_driver_port_perform_release( port );
+ break;
+ case usbback_driver_port_stimulus_rr:
+ break;
+ default:
+ usbback_driver_port_invalid_stimulus( port, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_state_i_pc_up_ud:
+ /* Claimed */
+ /* USB Disconnecting */
+ /* Testing/Running */
+ switch( stimulus )
+ {
+ case usbback_driver_port_stimulus_pr:
+ port->state = usbback_driver_port_state_i_pc_up_pr_ud;
+ break;
+ case usbback_driver_port_stimulus_rq:
+ usbback_driver_port_purge_io( port );
+ usbback_driver_port_test_io( port );
+ break;
+ case usbback_driver_port_stimulus_sd:
+ port->state = usbback_driver_port_state_i_pc_up_ud_sd;
+ break;
+ case usbback_driver_port_stimulus_ri:
+ port->state = usbback_driver_port_state_i_pc;
+ usbback_driver_port_complete_usb_disconnect( port );
+ break;
+ case usbback_driver_port_stimulus_rr:
+ break;
+ default:
+ usbback_driver_port_invalid_stimulus( port, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_state_i_pc_up_sd:
+ /* Released */
+ /* Probed */
+ /* Shutting down */
+ /* Testing/Running */
+ switch( stimulus )
+ {
+ case usbback_driver_port_stimulus_ud:
+ port->state = usbback_driver_port_state_i_pc_up_ud_sd;
+ break;
+ case usbback_driver_port_stimulus_rq:
+ usbback_driver_port_purge_io( port );
+ usbback_driver_port_test_io( port );
+ break;
+ case usbback_driver_port_stimulus_ri:
+ port->state = usbback_driver_port_state_i_pc_up_sd_ri;
+ usbback_driver_port_perform_release( port );
+ break;
+ case usbback_driver_port_stimulus_rr:
+ break;
+ default:
+ usbback_driver_port_invalid_stimulus( port, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_state_i_pc_up_pr_ud:
+ /* Releasing */
+ /* USB Disconnecting */
+ /* Testing/Running */
+ switch( stimulus )
+ {
+ case usbback_driver_port_stimulus_rq:
+ usbback_driver_port_purge_io( port );
+ usbback_driver_port_test_io( port );
+ break;
+ case usbback_driver_port_stimulus_ri:
+ port->state = usbback_driver_port_state_i_pc_up_pr_ud_ri;
+ usbback_driver_port_perform_release( port );
+ usbback_driver_port_complete_usb_disconnect( port );
+ break;
+ case usbback_driver_port_stimulus_rr:
+ break;
+ default:
+ usbback_driver_port_invalid_stimulus( port, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_state_i_pc_up_pr_ri:
+ /* Releasing */
+ /* Probed */
+ /* Idle */
+ /* Performing Release */
+ switch( stimulus )
+ {
+ case usbback_driver_port_stimulus_ud:
+ port->state = usbback_driver_port_state_i_pc_up_pr_ud_ri;
+ usbback_driver_port_complete_usb_disconnect( port );
+ break;
+ case usbback_driver_port_stimulus_rq:
+ usbback_driver_port_purge_io( port );
+ break;
+ default:
+ usbback_driver_port_invalid_stimulus( port, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_state_i_pc_up_ud_sd:
+ /* Released */
+ /* USB Disconnecting */
+ /* Shutting down */
+ /* Testing/Running */
+ switch( stimulus )
+ {
+ case usbback_driver_port_stimulus_rq:
+ usbback_driver_port_purge_io( port );
+ usbback_driver_port_test_io( port );
+ break;
+ case usbback_driver_port_stimulus_ri:
+ port->state = usbback_driver_port_state_i_pc_up_ud_sd_ri;
+ usbback_driver_port_perform_release( port );
+ usbback_driver_port_complete_usb_disconnect( port );
+ break;
+ case usbback_driver_port_stimulus_rr:
+ break;
+ default:
+ usbback_driver_port_invalid_stimulus( port, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_state_i_pc_up_sd_ri:
+ /* Released */
+ /* Probed */
+ /* Shutting down */
+ /* Idle */
+ /* Performing release */
+ switch( stimulus )
+ {
+ case usbback_driver_port_stimulus_ud:
+ port->state = usbback_driver_port_state_i_pc_up_ud_sd_ri;
+ usbback_driver_port_complete_usb_disconnect( port );
+ break;
+ case usbback_driver_port_stimulus_rq:
+ usbback_driver_port_purge_io( port );
+ break;
+ default:
+ usbback_driver_port_invalid_stimulus( port, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_state_i_pc_up_pr_ud_ri:
+ /* Releasing */
+ /* Disconnected */
+ /* Idle */
+ /* Performing release */
+ switch( stimulus )
+ {
+ case usbback_driver_port_stimulus_rq:
+ usbback_driver_port_purge_io( port );
+ break;
+ case usbback_driver_port_stimulus_rp:
+ port->state = usbback_driver_port_state_i;
+ usbback_driver_port_complete_release( port );
+ break;
+ default:
+ usbback_driver_port_invalid_stimulus( port, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_state_i_pc_up_ud_sd_ri:
+ /* Released */
+ /* Disconnected */
+ /* Shutting down */
+ /* Idle */
+ /* Performing release */
+ switch( stimulus )
+ {
+ case usbback_driver_port_stimulus_rq:
+ usbback_driver_port_purge_io( port );
+ break;
+ case usbback_driver_port_stimulus_rp:
+ port->state = usbback_driver_port_state_i;
+ usbback_driver_port_complete_shutdown( port );
+ break;
+ default:
+ usbback_driver_port_invalid_stimulus( port, stimulus );
+ break;
+ }
+ break;
+ default:
+ usbback_driver_port_invalid_stimulus( port, stimulus );
+ break;
+ }
+}
+
+static void usbback_driver_port_invalid_stimulus
+ ( struct usbback_driver_port * port, usbback_driver_port_stimulus stimulus )
+{
+ trace();
+
+ printk
+ (
+ KERN_ERR "usbback: port %p in state %d"
+ "received invalid stimulus %d",
+ port,
+ port->state,
+ stimulus
+ );
+}
+
+static void usbback_driver_port_purge_io( struct usbback_driver_port * port )
+{
+ trace();
+
+ while( !list_empty( &port->transaction_list ) )
+ {
+ xenidc_endpoint_transaction * transaction = list_entry
+ (
+ port->transaction_list.next,
+ xenidc_endpoint_transaction,
+ XENIDC_ENDPOINT_TRANSACTION_LINK
+ );
+
+ list_del_init( xenidc_endpoint_transaction_to_link( transaction ) );
+
+ list_add_tail
+ (
+ xenidc_endpoint_transaction_to_link( transaction ),
+ &port->purge_list
+ );
+ }
+
+ {
+ int i;
+
+ for( i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++ )
+ {
+ struct usbback_driver_port_resource * resource =
+ &port->resources[ i ];
+
+ usbback_driver_port_resource_flush_transaction( resource );
+ }
+ }
+
+ (void)xenidc_work_schedule( &port->purge_io_1_work );
+}
+
+static void usbback_driver_port_purge_io_1( void * data )
+{
+ trace();
+
+ {
+ struct usbback_driver_port * port = (struct usbback_driver_port *)data;
+
+ spin_lock_irq( &port->lock );
+
+ while( !list_empty( &port->purge_list ) )
+ {
+ xenidc_endpoint_transaction * transaction = list_entry
+ (
+ port->purge_list.next,
+ xenidc_endpoint_transaction,
+ XENIDC_ENDPOINT_TRANSACTION_LINK
+ );
+
+ list_del_init
+ ( xenidc_endpoint_transaction_to_link( transaction ) );
+
+ spin_unlock_irq( &port->lock );
+
+ xenidc_endpoint_transaction_complete
+ ( transaction, USBIF_XENIDC_ERROR_UNLINKED );
+
+ spin_lock_irq( &port->lock );
+ }
+
+ spin_unlock_irq( &port->lock );
+ }
+}
+
+static void usbback_driver_port_test_io( struct usbback_driver_port * port )
+{
+ trace();
+
+ if( port->current_transactions == 0 )
+ {
+ usbback_driver_port_handle_stimulus
+ ( port, usbback_driver_port_stimulus_ri );
+ }
+ else
+ {
+ usbback_driver_port_handle_stimulus
+ ( port, usbback_driver_port_stimulus_rr );
+ }
+}
+
+static void usbback_driver_port_kick_io( struct usbback_driver_port * port )
+{
+ trace();
+
+ while
+ (
+ ( !list_empty( &port->transaction_list ) )
+ &&
+ ( !list_empty( &port->free_resource_list ) )
+ )
+ {
+ xenidc_endpoint_transaction * transaction = list_entry
+ (
+ port->transaction_list.next,
+ xenidc_endpoint_transaction,
+ XENIDC_ENDPOINT_TRANSACTION_LINK
+ );
+
+ struct usbback_driver_port_resource * resource = list_entry
+ (
+ port->free_resource_list.next,
+ struct usbback_driver_port_resource,
+ link
+ );
+
+ list_del_init( xenidc_endpoint_transaction_to_link( transaction ) );
+
+ list_del_init( &resource->link );
+
+ port->current_transactions++;
+
+ usbback_driver_port_resource_start_io( resource, transaction );
+ }
+}
+
+void usbback_driver_port_resource_completed_io
+(
+ struct usbback_driver_port * port,
+ struct usbback_driver_port_resource * resource
+)
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &port->lock, flags );
+
+ list_add( &resource->link, &port->free_resource_list );
+
+ port->current_transactions--;
+
+ usbback_driver_port_handle_stimulus
+ ( port, usbback_driver_port_stimulus_rq );
+
+ spin_unlock_irqrestore( &port->lock, flags );
+ }
+}
+
+static void usbback_driver_port_perform_release
+ ( struct usbback_driver_port * port )
+{
+ trace();
+
+ usb_get_dev( port->usbdev );
+
+ {
+ int scheduled = xenidc_work_schedule( &port->perform_release_1_work );
+
+ ASSERT( scheduled );
+ }
+}
+
+static void usbback_driver_port_perform_release_1( void * data )
+{
+ trace();
+
+ {
+ struct usbback_driver_port * port = (struct usbback_driver_port *)data;
+
+ usb_lock_device( port->usbdev );
+
+ down_write( &usb_bus_type.subsys.rwsem );
+
+ if( port->usbdev_is_connected )
+ {
+ usb_driver_release_interface
+ (
+ &usbback_driver_usb_driver,
+ usb_ifnum_to_if( port->usbdev, 0 )
+ );
+ }
+
+ up_write( &usb_bus_type.subsys.rwsem );
+
+ usb_unlock_device( port->usbdev );
+
+ usb_put_dev( port->usbdev );
+
+ spin_lock_irq( &port->lock );
+
+ usbback_driver_port_handle_stimulus
+ ( port, usbback_driver_port_stimulus_rp );
+
+ spin_unlock_irq( &port->lock );
+ }
+}
+
+static void usbback_driver_port_complete_release
+ ( struct usbback_driver_port * port )
+{
+ trace();
+
+ port->release = 1;
+
+ xenidc_work_wake_up();
+}
+
+static void usbback_driver_port_complete_usb_disconnect
+ ( struct usbback_driver_port * port )
+{
+ trace();
+
+ port->usb_disconnect = 1;
+
+ xenidc_work_wake_up();
+}
+
+static void usbback_driver_port_complete_shutdown
+ ( struct usbback_driver_port * port )
+{
+ trace();
+
+ port->shutdown = 1;
+
+ xenidc_work_wake_up();
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,149 @@
+/*****************************************************************************/
+/* Object which manages a single USB device and handles all the */
+/* io transactions for that device by assigning */
+/* usbback_driver_port_resources to process them. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef USBBACK_DRIVER_PORT_H
+#define USBBACK_DRIVER_PORT_H
+
+#include <asm-xen/xenidc.h>
+#include <linux/usb.h>
+#include "usbback_assert.h"
+#include "usbback_driver_backend.h"
+#include "usbback_driver_port_resource.h"
+#include "usbback_trace.h"
+
+int usbback_driver_port_class_init( void );
+
+void usbback_driver_port_class_exit( void );
+
+int usbback_driver_port_init
+(
+ struct usbback_driver_port * port,
+ struct usbback_driver_backend * backend
+);
+
+void usbback_driver_port_claim
+ ( struct usbback_driver_port * port, char * path );
+
+void usbback_driver_port_release
+ ( struct usbback_driver_port * port );
+
+int usbback_driver_port_probe_usb( struct usb_interface * intf );
+
+void usbback_driver_port_disconnect_usb( struct usb_interface * intf );
+
+/* On success, usbback_driver_port_reset returns */
+/* USBIF_RESET_RESULT_FULL/LOW/HIGH_SPEED */
+
+int usbback_driver_port_reset( struct usbback_driver_port * port );
+
+void usbback_driver_port_set_guest_address
+ ( struct usbback_driver_port * port, unsigned long guest_address );
+
+int usbback_driver_port_match_guest_address
+ ( struct usbback_driver_port * port, unsigned long guest_address );
+
+void usbback_driver_port_connect
+ ( struct usbback_driver_port * port );
+
+void usbback_driver_port_handle_io
+(
+ struct usbback_driver_port * port,
+ xenidc_endpoint_transaction * transaction
+);
+
+void usbback_driver_port_disconnect
+ ( struct usbback_driver_port * port );
+
+int usbback_driver_port_try_unlink
+ ( struct usbback_driver_port * port, int unlink_id );
+
+void usbback_driver_port_shutdown( struct usbback_driver_port * port );
+
+typedef enum
+{
+ usbback_driver_port_state_i,
+ usbback_driver_port_state_i_pc,
+ usbback_driver_port_state_i_pc_up,
+ usbback_driver_port_state_i_pc_up_pr,
+ usbback_driver_port_state_i_pc_up_ud,
+ usbback_driver_port_state_i_pc_up_sd,
+ usbback_driver_port_state_i_pc_up_pr_ud,
+ usbback_driver_port_state_i_pc_up_pr_ri,
+ usbback_driver_port_state_i_pc_up_ud_sd,
+ usbback_driver_port_state_i_pc_up_sd_ri,
+ usbback_driver_port_state_i_pc_up_pr_ud_ri,
+ usbback_driver_port_state_i_pc_up_ud_sd_ri
+}
+usbback_driver_port_state;
+
+#define USBBACK_DRIVER_PORT_RESOURCE_COUNT 4
+
+struct usbback_driver_port
+{
+ struct usbback_driver_backend * backend;
+ struct list_head link;
+ char path[ 16 ]; /* FIXME: Magic number. */
+ struct usb_device * usbdev;
+ spinlock_t lock;
+ usbback_driver_port_state state;
+ int usbdev_is_connected;
+ int enabled;
+ unsigned long guest_address;
+ struct list_head transaction_list;
+ struct list_head purge_list;
+ struct list_head free_resource_list;
+ unsigned long current_transactions;
+ struct usbback_driver_port_resource resources
+ [ USBBACK_DRIVER_PORT_RESOURCE_COUNT ];
+ xenidc_work purge_io_1_work;
+ xenidc_work perform_release_1_work;
+ int release;
+ int usb_disconnect;
+ int shutdown;
+};
+
+static inline struct usb_device * usbback_driver_port_query_usbdev
+ ( struct usbback_driver_port * port )
+{
+ trace();
+
+ ASSERT( port->usbdev != NULL );
+
+ return port->usbdev;
+}
+
+static inline int usbback_driver_port_usbdev_is_connected
+ ( struct usbback_driver_port * port )
+{
+ /* trace(); */
+
+ return port->usbdev_is_connected;
+}
+
+void usbback_driver_port_resource_completed_io
+(
+ struct usbback_driver_port * port,
+ struct usbback_driver_port_resource * resource
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,1228 @@
+/*****************************************************************************/
+/* Resource which processes a usbback_transaction by translating it into */
+/* an URB and submitting it to the USB stack. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on arch/xen/drivers/usbif/backend/main.c, original copyright notice */
+/* follows... */
+/*****************************************************************************/
+
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ *
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson
+ * Copyright (c) 2004 Intel Research Cambridge
+ * Copyright (c) 2004, 2005 Mark Williamson
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+#include <asm-xen/xen-public/io/usbif.h>
+#include "usbback_assert.h"
+#include "usbback_driver_port.h"
+#include "usbback_driver_port_resource.h"
+#include "usbback_trace.h"
+
+static XENIDC_CALLBACK_SERIALISER
+ ( usbback_driver_port_resource_submit_urb_serialiser );
+
+static xenidc_rbr_mapper_pool * usbback_driver_port_resource_rbr_mapper_pool;
+
+int usbback_driver_port_resource_class_init( void )
+{
+ trace();
+
+ usbback_driver_port_resource_rbr_mapper_pool =
+ xenidc_allocate_rbr_mapper_pool( USBIF_MAX_PAGES_PER_REQUEST );
+
+ return ( usbback_driver_port_resource_rbr_mapper_pool != NULL ) ?
+ 0 : -ENOMEM;
+}
+
+void usbback_driver_port_resource_class_exit( void )
+{
+ trace();
+
+ xenidc_free_rbr_mapper_pool
+ ( usbback_driver_port_resource_rbr_mapper_pool );
+}
+
+typedef enum
+{
+ usbback_driver_port_resource_stimulus_st, /* Start IO */
+ usbback_driver_port_resource_stimulus_tu, /* Try unlink */
+ usbback_driver_port_resource_stimulus_ms, /* Map success */
+ usbback_driver_port_resource_stimulus_mf, /* Map failure */
+ usbback_driver_port_resource_stimulus_us, /* URB submitted */
+ usbback_driver_port_resource_stimulus_un, /* URB not submitted */
+ usbback_driver_port_resource_stimulus_uc, /* URB completed */
+ usbback_driver_port_resource_stimulus_ul, /* Unlink completed */
+}
+usbback_driver_port_resource_stimulus;
+
+static void usbback_driver_port_resource_handle_stimulus
+(
+ struct usbback_driver_port_resource * resource,
+ usbback_driver_port_resource_stimulus stimulus
+);
+
+static void usbback_driver_port_resource_submit_urb_1
+ ( xenidc_callback * callback );
+
+static void usbback_driver_port_resource_unlink_urb_1( void * data );
+
+static void usbback_driver_port_resource_map_callback
+ ( xenidc_callback * callback );
+
+static void usbback_driver_port_resource_unmap_callback
+ ( xenidc_callback * callback );
+
+void usbback_driver_port_resource_init
+(
+ struct usbback_driver_port_resource * resource,
+ struct usbback_driver_port * port
+)
+{
+ trace();
+
+ resource->port = port;
+
+ INIT_LIST_HEAD( &resource->link );
+
+ spin_lock_init( &resource->lock );
+
+ resource->state = usbback_driver_port_resource_state_i;
+
+ resource->transaction = NULL;
+
+ xenidc_map_rbr_request_element_init( &resource->request_element[ 0 ] );
+ xenidc_map_rbr_request_element_init( &resource->request_element[ 1 ] );
+
+ xenidc_reserve_and_map_rbr_request_init
+ (
+ &resource->reserve_and_map_rbr_request,
+ usbback_driver_port_resource_map_callback,
+ usbback_driver_port_resource_unmap_callback
+ );
+
+ resource->rbrs_mapped = 0;
+
+ xenidc_callback_init
+ (
+ &resource->submit_urb_1_callback,
+ usbback_driver_port_resource_submit_urb_1
+ );
+
+ xenidc_work_init
+ (
+ &resource->unlink_urb_1_work,
+ usbback_driver_port_resource_unlink_urb_1,
+ resource
+ );
+}
+
+void usbback_driver_port_resource_start_io
+(
+ struct usbback_driver_port_resource * resource,
+ xenidc_endpoint_transaction * transaction
+)
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ resource->transaction_error = XENIDC_ERROR_SUCCESS;
+ resource->transaction_status_length = 0;
+
+ resource->transaction = transaction;
+
+ usbback_driver_port_resource_handle_stimulus
+ ( resource, usbback_driver_port_resource_stimulus_st );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+}
+
+int usbback_driver_port_resource_try_unlink
+ ( struct usbback_driver_port_resource * resource, int unlink_id )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ if( resource->transaction != NULL )
+ {
+ usbif_io_transaction_parameters_header header;
+
+ if
+ (
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ xenidc_endpoint_transaction_to_parameters_lbr
+ ( resource->transaction ),
+ &header,
+ sizeof( header )
+ )
+ ==
+ sizeof( header )
+ )
+ &&
+ ( header.unlink_id == unlink_id )
+ )
+ {
+ usbback_driver_port_resource_handle_stimulus
+ ( resource, usbback_driver_port_resource_stimulus_tu );
+
+ return_value = 1;
+ }
+ }
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+
+ return return_value;
+ }
+}
+
+void usbback_driver_port_resource_flush_transaction
+ ( struct usbback_driver_port_resource * resource )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ if( resource->transaction != NULL )
+ {
+ usbback_driver_port_resource_handle_stimulus
+ ( resource, usbback_driver_port_resource_stimulus_tu );
+ }
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+}
+
+static void usbback_driver_port_resource_invalid_stimulus
+(
+ struct usbback_driver_port_resource * resource,
+ usbback_driver_port_resource_stimulus stimulus
+);
+
+static void usbback_driver_port_resource_map_buffer
+ ( struct usbback_driver_port_resource * resource );
+
+static void usbback_driver_port_resource_abort_map
+ ( struct usbback_driver_port_resource * resource );
+
+static void usbback_driver_port_resource_submit_urb
+ ( struct usbback_driver_port_resource * resource );
+
+static void usbback_driver_port_resource_unlink_urb
+ ( struct usbback_driver_port_resource * resource );
+
+static void usbback_driver_port_resource_set_error
+ ( struct usbback_driver_port_resource * resource );
+
+static void usbback_driver_port_resource_complete
+ ( struct usbback_driver_port_resource * resource );
+
+static void usbback_driver_port_resource_handle_stimulus
+(
+ struct usbback_driver_port_resource * resource,
+ usbback_driver_port_resource_stimulus stimulus
+)
+{
+ trace3
+ (
+ "port resource %p in state %d received stimulus %d",
+ resource,
+ resource->state,
+ stimulus
+ );
+
+ switch( resource->state )
+ {
+ case usbback_driver_port_resource_state_i:
+ /* Idle */
+ switch( stimulus )
+ {
+ case usbback_driver_port_resource_stimulus_st:
+ resource->state = usbback_driver_port_resource_state_i_st;
+ usbback_driver_port_resource_map_buffer( resource );
+ break;
+ default:
+ usbback_driver_port_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_resource_state_i_st:
+ /* Handling request */
+ /* map_buffer outstanding */
+ switch( stimulus )
+ {
+ case usbback_driver_port_resource_stimulus_tu:
+ resource->state = usbback_driver_port_resource_state_i_st_tu;
+ usbback_driver_port_resource_abort_map( resource );
+ break;
+ case usbback_driver_port_resource_stimulus_ms:
+ resource->state = usbback_driver_port_resource_state_i_st_ms;
+ usbback_driver_port_resource_submit_urb( resource );
+ break;
+ case usbback_driver_port_resource_stimulus_mf:
+ resource->state = usbback_driver_port_resource_state_i;
+ usbback_driver_port_resource_complete( resource );
+ break;
+ default:
+ usbback_driver_port_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_resource_state_i_st_tu:
+ /* Handling request */
+ /* map_buffer outstanding */
+ /* unlinking */
+ switch( stimulus )
+ {
+ case usbback_driver_port_resource_stimulus_tu:
+ break;
+ case usbback_driver_port_resource_stimulus_ms:
+ resource->state = usbback_driver_port_resource_state_i;
+ usbback_driver_port_resource_set_error( resource );
+ usbback_driver_port_resource_complete( resource );
+ break;
+ case usbback_driver_port_resource_stimulus_mf:
+ resource->state = usbback_driver_port_resource_state_i;
+ usbback_driver_port_resource_complete( resource );
+ break;
+ default:
+ usbback_driver_port_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_resource_state_i_st_ms:
+ /* Handling request */
+ /* submit_urb outstanding */
+ switch( stimulus )
+ {
+ case usbback_driver_port_resource_stimulus_tu:
+ resource->state = usbback_driver_port_resource_state_i_st_ms_tu;
+ break;
+ case usbback_driver_port_resource_stimulus_us:
+ resource->state = usbback_driver_port_resource_state_i_st_ms_us;
+ break;
+ case usbback_driver_port_resource_stimulus_un:
+ resource->state = usbback_driver_port_resource_state_i;
+ usbback_driver_port_resource_complete( resource );
+ break;
+ case usbback_driver_port_resource_stimulus_uc:
+ resource->state = usbback_driver_port_resource_state_i_st_ms_uc;
+ break;
+ default:
+ usbback_driver_port_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_resource_state_i_st_ms_tu:
+ /* Handling request */
+ /* submit_urb outstanding */
+ /* unlinking */
+ switch( stimulus )
+ {
+ case usbback_driver_port_resource_stimulus_tu:
+ break;
+ case usbback_driver_port_resource_stimulus_us:
+ resource->state = usbback_driver_port_resource_state_i_st_ms_tu_us;
+ usbback_driver_port_resource_unlink_urb( resource );
+ break;
+ case usbback_driver_port_resource_stimulus_un:
+ resource->state = usbback_driver_port_resource_state_i;
+ usbback_driver_port_resource_complete( resource );
+ break;
+ case usbback_driver_port_resource_stimulus_uc:
+ resource->state = usbback_driver_port_resource_state_i_st_ms_uc;
+ break;
+ default:
+ usbback_driver_port_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_resource_state_i_st_ms_us:
+ /* Handling request */
+ /* URB submitted */
+ switch( stimulus )
+ {
+ case usbback_driver_port_resource_stimulus_tu:
+ resource->state = usbback_driver_port_resource_state_i_st_ms_tu_us;
+ usbback_driver_port_resource_unlink_urb( resource );
+ break;
+ case usbback_driver_port_resource_stimulus_uc:
+ resource->state = usbback_driver_port_resource_state_i;
+ usbback_driver_port_resource_complete( resource );
+ break;
+ default:
+ usbback_driver_port_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_resource_state_i_st_ms_uc:
+ /* Handling request */
+ /* submit_urb outstanding */
+ /* URB completed */
+ switch( stimulus )
+ {
+ case usbback_driver_port_resource_stimulus_tu:
+ break;
+ case usbback_driver_port_resource_stimulus_us:
+ resource->state = usbback_driver_port_resource_state_i;
+ usbback_driver_port_resource_complete( resource );
+ break;
+ default:
+ usbback_driver_port_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_resource_state_i_st_ms_tu_us:
+ /* Handling request */
+ /* URB submitted */
+ /* unlink_urb outstanding */
+ switch( stimulus )
+ {
+ case usbback_driver_port_resource_stimulus_tu:
+ break;
+ case usbback_driver_port_resource_stimulus_uc:
+ case usbback_driver_port_resource_stimulus_ul:
+ resource->state =
+ usbback_driver_port_resource_state_i_st_ms_tu_us_uc;
+ break;
+ default:
+ usbback_driver_port_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case usbback_driver_port_resource_state_i_st_ms_tu_us_uc:
+ /* Handling request */
+ /* URB submitted or unlink_urb outstanding */
+ switch( stimulus )
+ {
+ case usbback_driver_port_resource_stimulus_tu:
+ break;
+ case usbback_driver_port_resource_stimulus_uc:
+ case usbback_driver_port_resource_stimulus_ul:
+ resource->state = usbback_driver_port_resource_state_i;
+ usbback_driver_port_resource_complete( resource );
+ break;
+ default:
+ usbback_driver_port_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ default:
+ usbback_driver_port_resource_invalid_stimulus( resource, stimulus );
+ break;
+ }
+}
+
+static void usbback_driver_port_resource_invalid_stimulus
+(
+ struct usbback_driver_port_resource * resource,
+ usbback_driver_port_resource_stimulus stimulus
+)
+{
+ trace();
+
+ printk
+ (
+ KERN_ERR "usbback: port resource %p in state %d"
+ "received invalid stimulus %d",
+ resource,
+ resource->state,
+ stimulus
+ );
+}
+
+static void usbback_driver_port_resource_map_buffer
+ ( struct usbback_driver_port_resource * resource )
+{
+ trace();
+
+ {
+ usbif_io_transaction_parameters_header header;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ xenidc_endpoint_transaction_to_parameters_lbr
+ ( resource->transaction ),
+ &header,
+ sizeof( header )
+ )
+ !=
+ sizeof( header )
+ )
+ {
+ goto FORMAT_ERROR;
+ }
+
+ xenidc_map_rbr_request_element_ensure_removed
+ ( &resource->request_element[ 0 ] );
+
+ xenidc_map_rbr_request_element_ensure_removed
+ ( &resource->request_element[ 1 ] );
+
+ xenidc_reserve_and_map_rbr_request_add_element
+ (
+ &resource->reserve_and_map_rbr_request,
+ &resource->request_element[ 0 ]
+ );
+
+ xenidc_map_rbr_request_element_set_rbr
+ (
+ &resource->request_element[ 0 ],
+ header.rbr
+ );
+
+ if
+ (
+ header.io_transaction_type
+ ==
+ USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS
+ )
+ {
+ usbif_isochronous_io_transaction_parameters parameters;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ xenidc_endpoint_transaction_to_parameters_lbr
+ ( resource->transaction ),
+ ¶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
+ (
+ xenidc_endpoint_transaction_to_parameters_lbr
+ ( resource->transaction ),
+ &io_parameters,
+ sizeof( io_parameters )
+ );
+
+ if( io_parameters_byte_count < sizeof( io_parameters.header ) )
+ {
+ resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT;
+
+ goto FORMAT_ERROR;
+ }
+
+ if
+ (
+ io_parameters.header.io_transaction_type
+ >=
+ USBIF_IO_TRANSACTION_TYPE_LIMIT
+ )
+ {
+ resource->transaction_error = XENIDC_ERROR_INVALID_PARAMETER;
+
+ goto FORMAT_ERROR;
+ }
+
+ if
+ (
+ io_parameters_byte_count
+ <
+ usbif_io_parameters_byte_count
+ [ io_parameters.header.io_transaction_type ]
+ )
+ {
+ resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT;
+
+ goto FORMAT_ERROR;
+ }
+ }
+
+ if
+ (
+ io_parameters.header.io_transaction_type
+ ==
+ USBIF_IO_TRANSACTION_TYPE_CONTROL
+ )
+ {
+ struct usb_ctrlrequest * ctrl =
+ (struct usb_ctrlrequest *)io_parameters.control.setup;
+
+ if
+ (
+ ctrl->bRequestType
+ ==
+ ( USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE )
+ )
+ {
+ if( ctrl->bRequest == USB_REQ_SET_ADDRESS )
+ {
+ usbback_driver_port_set_guest_address
+ ( resource->port, le16_to_cpu( ctrl->wValue ) );
+
+ goto HANDLED_SPECIAL_CASE;
+ }
+ else if( ctrl->bRequest == USB_REQ_SET_CONFIGURATION )
+ {
+ /* FIXME: what to do for set configuration? */
+
+ goto HANDLED_SPECIAL_CASE;
+ }
+ }
+ }
+
+ {
+ struct urb * urb = resource->urb = usb_alloc_urb
+ (
+ (
+ io_parameters.header.io_transaction_type
+ ==
+ USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS
+ )
+ ? io_parameters.isochronous.packet_count : 0,
+ GFP_KERNEL
+ );
+
+ static const unsigned int pipe_type
+ [ USBIF_IO_TRANSACTION_TYPE_LIMIT ] =
+ {
+ [ USBIF_IO_TRANSACTION_TYPE_CONTROL ] = PIPE_CONTROL,
+ [ USBIF_IO_TRANSACTION_TYPE_BULK ] = PIPE_BULK,
+ [ USBIF_IO_TRANSACTION_TYPE_INTERRUPT ] = PIPE_INTERRUPT,
+ [ USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS ] = PIPE_ISOCHRONOUS
+ };
+
+ unsigned int pipe =
+ (
+ (
+ (
+ (
+ io_parameters.header.direction
+ ==
+ USBIF_IO_TRANSACTION_DIRECTION_OUT
+ )
+ ? USB_DIR_OUT : USB_DIR_IN
+ )
+ << 7
+ )
+ |
+ (
+ (unsigned int)usbback_driver_port_query_usbdev
+ ( resource->port )->devnum
+ <<
+ 8
+ )
+ |
+ ( (unsigned int)io_parameters.header.endpoint << 15 )
+ |
+ ( pipe_type[ io_parameters.header.io_transaction_type ] << 30 )
+ );
+
+ if( urb == NULL )
+ {
+ /* FIXME: better URB resource management should let us queue */
+ /* for an URB and ISO resources from a reserved pool which */
+ /* would eliminate the possibility of failure at this point. */
+
+ resource->transaction_error =
+ XENIDC_ERROR_IMPLEMENTATION_DEFICIENCY;
+
+ goto NO_URB;
+ }
+
+ if
+ (
+ io_parameters.header.io_transaction_type
+ ==
+ USBIF_IO_TRANSACTION_TYPE_CONTROL
+ )
+ {
+ memcpy
+ (
+ resource->setup,
+ io_parameters.control.setup,
+ sizeof( resource->setup )
+ );
+
+ usb_fill_control_urb
+ (
+ urb,
+ usbback_driver_port_query_usbdev( resource->port ),
+ pipe,
+ resource->setup,
+ resource->request_element[ 0 ].mapping,
+ xenidc_remote_buffer_reference_query_byte_count
+ ( &resource->request_element[ 0 ].rbr ),
+ usbback_driver_port_resource_end_io,
+ resource
+ );
+ }
+ else if
+ (
+ io_parameters.header.io_transaction_type
+ ==
+ USBIF_IO_TRANSACTION_TYPE_BULK
+ )
+ {
+ usb_fill_bulk_urb
+ (
+ urb,
+ usbback_driver_port_query_usbdev( resource->port ),
+ pipe,
+ resource->request_element[ 0 ].mapping,
+ xenidc_remote_buffer_reference_query_byte_count
+ ( &resource->request_element[ 0 ].rbr ),
+ usbback_driver_port_resource_end_io,
+ resource
+ );
+ }
+ else if
+ (
+ io_parameters.header.io_transaction_type
+ ==
+ USBIF_IO_TRANSACTION_TYPE_INTERRUPT
+ )
+ {
+ /* FIXME: hacking the interval like this is a bit unclean. */
+ /* should probably convert back to exponential form for */
+ /* high speed transfers and then pass the value into */
+ /* fill_int_urb. */
+ usb_fill_int_urb
+ (
+ urb,
+ usbback_driver_port_query_usbdev( resource->port ),
+ pipe,
+ resource->request_element[ 0 ].mapping,
+ xenidc_remote_buffer_reference_query_byte_count
+ ( &resource->request_element[ 0 ].rbr ),
+ usbback_driver_port_resource_end_io,
+ resource,
+ 1 /* For the time being... */
+ );
+
+ /* ...now set the real value. */
+ urb->interval = io_parameters.interrupt.interval;
+ }
+ else
+ {
+ ASSERT
+ (
+ io_parameters.header.io_transaction_type
+ ==
+ USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS
+ );
+
+ /* FIXME: where's usb_fill_isoc_urb ?!? */
+
+ spin_lock_init(&urb->lock);
+ urb->dev = usbback_driver_port_query_usbdev( resource->port );
+ urb->pipe = pipe;
+ urb->transfer_buffer = resource->request_element[ 0 ].mapping;
+ urb->transfer_buffer_length =
+ xenidc_remote_buffer_reference_query_byte_count
+ ( &resource->request_element[ 0 ].rbr );
+ urb->complete = usbback_driver_port_resource_end_io;
+ urb->context = resource;
+ urb->number_of_packets =
+ io_parameters.isochronous.packet_count;
+ urb->interval = io_parameters.isochronous.interval;
+ urb->start_frame = 0;
+ urb->transfer_flags |= URB_ISO_ASAP;
+
+ if
+ (
+ xenidc_remote_buffer_reference_query_byte_count
+ ( &resource->request_element[ 1 ].rbr )
+ <
+ (
+ io_parameters.isochronous.packet_count
+ *
+ sizeof( usbif_isochronous_io_schedule_element )
+ )
+ )
+ {
+ resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT;
+
+ goto SCHEDULE_ERROR;
+ }
+
+ {
+ usbif_isochronous_io_schedule_element * schedule_element =
+ resource->request_element[ 1 ].mapping;
+
+ usbif_isochronous_io_schedule_element aligned_element;
+
+ int i;
+
+ for
+ (
+ i = 0;
+ i < io_parameters.isochronous.packet_count;
+ i++
+ )
+ {
+ memcpy
+ (
+ &aligned_element,
+ schedule_element++,
+ sizeof( aligned_element )
+ );
+
+ urb->iso_frame_desc[ i ].offset =
+ aligned_element.offset;
+ urb->iso_frame_desc[ i ].length =
+ aligned_element.length;
+
+ urb->iso_frame_desc[ i ].actual_length = 0;
+ urb->iso_frame_desc[ i ].status = 0;
+ }
+ }
+
+ if( !check_iso_schedule( urb ) )
+ {
+ resource->transaction_error =
+ XENIDC_ERROR_INVALID_PARAMETER;
+
+ goto SCHEDULE_ERROR;
+ }
+ }
+
+ /* On the backend, all unlinks are asynchronous. */
+
+ urb->transfer_flags |= URB_ASYNC_UNLINK;
+
+ if( io_parameters.header.flags & USBIF_IO_FLAGS_SHORT_NOT_OK )
+ {
+ urb->transfer_flags |= URB_SHORT_NOT_OK;
+ }
+ if( io_parameters.header.flags & USBIF_IO_FLAGS_ZERO_PACKET )
+ {
+ urb->transfer_flags |= URB_ZERO_PACKET;
+ }
+
+ if( usb_submit_urb( urb, GFP_KERNEL ) != 0 )
+ {
+ printk( KERN_WARNING "URB %p submission failed.\n", urb );
+
+ /* FIXME: non-specific failure return. */
+ resource->transaction_error = USBIF_XENIDC_ERROR_FAILURE;
+
+ goto URB_ERROR;
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ usbback_driver_port_resource_handle_stimulus
+ ( resource, usbback_driver_port_resource_stimulus_us );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+
+ return;
+
+ URB_ERROR:
+
+ SCHEDULE_ERROR:
+
+ usb_free_urb( urb );
+ }
+
+ NO_URB:
+
+ HANDLED_SPECIAL_CASE:
+
+ FORMAT_ERROR:
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ usbback_driver_port_resource_handle_stimulus
+ ( resource, usbback_driver_port_resource_stimulus_un );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+ }
+}
+
+static void usbback_driver_port_resource_end_io
+ ( struct urb * urb, struct pt_regs * regs )
+{
+ trace();
+
+ {
+ struct usbback_driver_port_resource * resource = urb->context;
+
+ if( urb->status != 0 )
+ {
+ printk
+ ( KERN_WARNING "URB %p failed. Status %d\n", urb, urb->status );
+
+ resource->transaction_error = USBIF_XENIDC_ERROR_FAILURE;
+ }
+
+ resource->transaction_status_length = urb->actual_length;
+
+ if( usb_pipetype( urb->pipe ) == PIPE_ISOCHRONOUS )
+ {
+ usbif_isochronous_io_schedule_element * schedule_element =
+ resource->request_element[ 1 ].mapping;
+
+ usbif_isochronous_io_schedule_element aligned_element;
+
+ int i;
+
+ for( i = 0; i < urb->number_of_packets; i++ )
+ {
+ aligned_element.length =
+ urb->iso_frame_desc[ i ].actual_length;
+ aligned_element.error =
+ ( urb->iso_frame_desc[ i ].status == 0 ) ?
+ XENIDC_ERROR_SUCCESS : USBIF_XENIDC_ERROR_FAILURE;
+
+ memcpy
+ (
+ schedule_element++,
+ &aligned_element,
+ sizeof( *schedule_element )
+ );
+ }
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ usbback_driver_port_resource_handle_stimulus
+ ( resource, usbback_driver_port_resource_stimulus_uc );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+ }
+
+ usb_free_urb( urb );
+}
+
+static void usbback_driver_port_resource_unlink_urb
+ ( struct usbback_driver_port_resource * resource )
+{
+ trace();
+
+ usb_get_urb( resource->urb );
+
+ {
+ int scheduled = xenidc_work_schedule( &resource->unlink_urb_1_work );
+
+ ASSERT( scheduled );
+ }
+}
+
+static void usbback_driver_port_resource_unlink_urb_1( void * data )
+{
+ trace();
+
+ {
+ struct usbback_driver_port_resource * resource =
+ (struct usbback_driver_port_resource *)data;
+
+ usb_unlink_urb( resource->urb );
+
+ usb_put_urb( resource->urb );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ usbback_driver_port_resource_handle_stimulus
+ ( resource, usbback_driver_port_resource_stimulus_ul );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+ }
+}
+
+static void usbback_driver_port_resource_set_error
+ ( struct usbback_driver_port_resource * resource )
+{
+ trace();
+
+ resource->transaction_error = USBIF_XENIDC_ERROR_FAILURE;
+}
+
+static void usbback_driver_port_resource_complete
+ ( struct usbback_driver_port_resource * resource )
+{
+ trace();
+
+ resource->completing_transaction = resource->transaction;
+ resource->transaction = NULL;
+
+ if( resource->rbrs_mapped )
+ {
+ resource->rbrs_mapped = 0;
+
+ xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs
+ (
+ usbback_driver_port_resource_rbr_mapper_pool,
+ &resource->reserve_and_map_rbr_request
+ );
+ }
+ else
+ {
+ xenidc_callback_success
+ (
+ xenidc_reserve_and_map_rbr_request_to_unmap_callback
+ ( &resource->reserve_and_map_rbr_request )
+ );
+ }
+}
+
+static void usbback_driver_port_resource_unmap_callback
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_reserve_and_map_rbr_request * request =
+ xenidc_reserve_and_map_rbr_request_unmap_callback_to( callback );
+
+ struct usbback_driver_port_resource * resource = container_of
+ (
+ request,
+ struct usbback_driver_port_resource,
+ reserve_and_map_rbr_request
+ );
+
+ usbif_io_transaction_status status;
+
+ status.length = resource->transaction_status_length;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_in
+ (
+ xenidc_endpoint_transaction_to_status_lbr
+ ( resource->completing_transaction ),
+ &status,
+ sizeof( status )
+ )
+ !=
+ sizeof( status )
+ )
+ {
+ resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT;
+ }
+
+ xenidc_endpoint_transaction_complete
+ ( resource->completing_transaction, resource->transaction_error );
+
+ usbback_driver_port_resource_completed_io( resource->port, resource );
+ }
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,87 @@
+/*****************************************************************************/
+/* Resource which processes an io transaction by translating it into an URB */
+/* and submitting it to the USB stack. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef USBBACK_DRIVER_PORT_RESOURCE_H
+#define USBBACK_DRIVER_PORT_RESOURCE_H
+
+#include <asm-xen/xenidc.h>
+#include "usbback_device.h"
+
+int usbback_driver_port_resource_class_init( void );
+
+void usbback_driver_port_resource_class_exit( void );
+
+struct usbback_driver_port;
+struct usbback_driver_port_resource;
+
+void usbback_driver_port_resource_init
+(
+ struct usbback_driver_port_resource * resource,
+ struct usbback_driver_port * port
+);
+
+void usbback_driver_port_resource_start_io
+(
+ struct usbback_driver_port_resource * resource,
+ xenidc_endpoint_transaction * transaction
+);
+
+int usbback_driver_port_resource_try_unlink
+ ( struct usbback_driver_port_resource * resource, int unlink_id );
+
+void usbback_driver_port_resource_flush_transaction
+ ( struct usbback_driver_port_resource * resource );
+
+typedef enum
+{
+ usbback_driver_port_resource_state_i,
+ usbback_driver_port_resource_state_i_st,
+ usbback_driver_port_resource_state_i_st_tu,
+ usbback_driver_port_resource_state_i_st_ms,
+ usbback_driver_port_resource_state_i_st_ms_tu,
+ usbback_driver_port_resource_state_i_st_ms_us,
+ usbback_driver_port_resource_state_i_st_ms_uc,
+ usbback_driver_port_resource_state_i_st_ms_tu_us,
+ usbback_driver_port_resource_state_i_st_ms_tu_us_uc
+}
+usbback_driver_port_resource_state;
+
+struct usbback_driver_port_resource
+{
+ struct usbback_driver_port * port;
+ struct list_head link;
+ spinlock_t lock;
+ usbback_driver_port_resource_state state;
+ xenidc_error transaction_error;
+ unsigned long transaction_status_length;
+ xenidc_endpoint_transaction * transaction;
+ xenidc_endpoint_transaction * completing_transaction;
+ xenidc_reserve_and_map_rbr_request reserve_and_map_rbr_request;
+ xenidc_map_rbr_request_element request_element[ 2 ];
+ int rbrs_mapped;
+ struct urb * urb;
+ u8 setup[ 8 ];
+ xenidc_callback submit_urb_1_callback;
+ xenidc_work unlink_urb_1_work;
+};
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,83 @@
+/*****************************************************************************/
+/* Back-end module for Xen USB split driver. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbback_driver.h"
+#include "usbback_device.h"
+#include "usbback_trace.h"
+
+static int usbback_module_init_or_exit( int exit )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ if( exit )
+ {
+ goto EXIT;
+ }
+
+ if( ( return_value = usbback_driver_init() ) != 0 )
+ {
+ goto EXIT_NO_DRIVER;
+ }
+
+ if( ( return_value = usbback_device_class_init() ) != 0 )
+ {
+ goto EXIT_NO_DEVICE_CLASS;
+ }
+
+ return 0;
+
+ EXIT:
+
+ usbback_device_class_exit();
+
+ EXIT_NO_DEVICE_CLASS:
+
+ usbback_driver_exit();
+
+ EXIT_NO_DRIVER:
+
+ return return_value;
+ }
+}
+
+static int __init usbback_module_init( void )
+{
+ trace();
+
+ return usbback_module_init_or_exit( 0 );
+}
+
+static void __exit usbback_module_exit( void )
+{
+ trace();
+
+ (void)usbback_module_init_or_exit( 1 );
+}
+
+module_init( usbback_module_init );
+module_exit( usbback_module_exit );
+
+MODULE_LICENSE( "GPL" );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,54 @@
+/*****************************************************************************/
+/* Simple trace macros */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef USBBACK_TRACE_H
+#define USBBACK_TRACE_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_XEN_USBDEV_BACKEND_TRACE
+
+#define trace0( format ) \
+printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__ )
+
+#define trace1( format, a0 ) \
+printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__, a0 )
+
+#define trace2( format, a0, a1 ) \
+printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__, a0, a1 )
+
+#define trace3( format, a0, a1, a2 ) \
+printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__, a0, a1, a2 )
+
+#define trace() trace0( "" )
+
+#else
+
+#define trace0( format )
+#define trace1( format,a0 )
+#define trace2( format,a0, a1 )
+#define trace3( format,a0, a1, a2 )
+#define trace()
+
+#endif
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile Sun Oct 30 16:03:34 2005
@@ -0,0 +1,7 @@
+obj-$(CONFIG_XEN_USBDEV_FRONTEND) += usbfront.o
+
+usbfront-objs := \
+usbfront_hcd_resource.o \
+usbfront_driver.o \
+usbfront_device.o \
+usbfront_module.o
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_assert.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_assert.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,44 @@
+/*****************************************************************************/
+/* An implementation of the ASSERT macro. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef USBFRONT_ASSERT_H
+#define USBFRONT_ASSERT_H
+
+#include <linux/kernel.h>
+
+static inline void assert_failed
+ ( const char * function, int line, const char * statement )
+{
+ printk
+ (
+ KERN_ERR "usbfront assert failed: %s line %d, statement %s\n",
+ function,
+ line,
+ statement
+ );
+
+ BUG();
+}
+
+#define ASSERT( S ) \
+( ( S ) ? ( (void)0 ) : assert_failed( __PRETTY_FUNCTION__, __LINE__, #S ) )
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,1314 @@
+/*****************************************************************************/
+/* usbfront_device is a device which represents a connection to a back-end. */
+/* The intent was for it to have an interface like a hardware USB host */
+/* controller device. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on arch/xen/drivers/usbif/frontend/main.c, original copyright */
+/* notice follows... */
+/*****************************************************************************/
+
+/*
+ * Xen Virtual USB Frontend Driver
+ *
+ * This file contains the first version of the Xen virtual USB hub
+ * that I've managed not to delete by mistake (3rd time lucky!).
+ *
+ * Based on Linux's uhci.c, original copyright notices are displayed
+ * below. Portions also (c) 2004 Intel Research Cambridge
+ * and (c) 2004, 2005 Mark Williamson
+ *
+ * Contact <mark.williamson@cl.cam.ac.uk> or
+ * <xen-devel@lists.sourceforge.net> regarding this code.
+ *
+ * Still to be (maybe) implemented:
+ * - migration / backend restart support?
+ * - support for building / using as a module
+ */
+
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ * - the low-level protocol (fairly simple but lots of small details)
+ * - working around the horridness of the rest
+ */
+
+/* Xenbus code for blkif backend
+ Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/* FIXME: check all port numbering is one based */
+
+#include <asm-xen/xenbus.h>
+#include <asm-xen/xenidc.h>
+#include <asm-xen/xenidc_vaddress.h>
+#include "usbfront_assert.h"
+#include "usbfront_device.h"
+#include "usbfront_driver.h"
+#include "usbfront_trace.h"
+
+#define USBFRONT_DEVICE_PORT_COUNT 7
+
+typedef enum
+{
+ usbfront_device_state_i,
+ usbfront_device_state_i_cn,
+ usbfront_device_state_i_cn_dn,
+ usbfront_device_state_i_cn_ps,
+ usbfront_device_state_i_cn_pf,
+ usbfront_device_state_i_cn_dn_ps,
+ usbfront_device_state_i_cn_ps_dn,
+ usbfront_device_state_i_cn_ps_pc,
+ usbfront_device_state_i_cn_ps_dn_rc
+}
+usbfront_device_state;
+
+typedef enum
+{
+ usbfront_device_stimulus_cn, /* Endpoint connect. */
+ usbfront_device_stimulus_dn, /* Endpoint disconnect. */
+ usbfront_device_stimulus_ps, /* Probe driver success. */
+ usbfront_device_stimulus_pf, /* Probe driver failure. */
+ usbfront_device_stimulus_rc, /* Remove driver complete. */
+ usbfront_device_stimulus_pt, /* Polling tick. */
+ usbfront_device_stimulus_pc /* Probe complete. */
+}
+usbfront_device_stimulus;
+
+struct usbfront_device;
+
+struct usbfront_device_probe_transaction
+{
+ xenidc_endpoint_transaction transaction;
+
+ union
+ {
+ struct
+ {
+ usbif_probe_transaction_parameters parameters;
+ usbif_probe_transaction_status status;
+ }
+ probe;
+ struct
+ {
+ usbif_reset_transaction_parameters parameters;
+ usbif_reset_transaction_status status;
+ }
+ reset;
+ };
+
+ struct usbfront_device * device;
+};
+
+struct usbfront_device
+{
+ struct xenbus_device * dev;
+ void * drvdata;
+ spinlock_t lock;
+ usbfront_device_state state;
+ long int backend_id;
+ char * backend;
+ xenidc_endpoint endpoint;
+ xenidc_callback * endpoint_disconnect_callback;
+ int tick_count;
+ int port_probe_count;
+ struct usbfront_device_probe_transaction
+ probe_transaction[ USBFRONT_DEVICE_PORT_COUNT ];
+ struct usb_port_status port_status[ USBFRONT_DEVICE_PORT_COUNT ];
+ xenidc_work probe_driver_1_work;
+ xenidc_work remove_driver_1_work;
+};
+
+static void usbfront_device_handle_stimulus
+ ( struct usbfront_device * device, usbfront_device_stimulus stimulus );
+
+static inline struct usbfront_device * usbfront_device_endpoint_to
+ ( xenidc_endpoint * endpoint )
+{
+ trace();
+
+ return container_of( endpoint, struct usbfront_device, endpoint );
+}
+
+void usbfront_device_set_drvdata
+ ( struct usbfront_device * device, void * data )
+{
+ trace();
+
+ device->drvdata = data;
+}
+
+void * usbfront_device_get_drvdata( struct usbfront_device * device )
+{
+ trace();
+
+ return device->drvdata;
+}
+
+struct device * usbfront_device_to_dev( struct usbfront_device * device )
+{
+ trace();
+
+ return &device->dev->dev;
+}
+
+struct usbfront_device * usbfront_device_dev_to( struct device * dev )
+{
+ trace();
+
+ return to_xenbus_device( dev )->data;
+}
+
+int usbfront_device_query_port_count( struct usbfront_device * device )
+{
+ /* trace(); */
+
+ return USBFRONT_DEVICE_PORT_COUNT;
+}
+
+int usbfront_device_query_port_status_changed
+ ( struct usbfront_device * device, int port_number )
+{
+ /* trace(); */
+
+ ASSERT
+ (
+ ( port_number > 0 )
+ &&
+ ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+ );
+
+ {
+ int changed;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &device->lock, flags );
+
+ if( ++device->tick_count == USBFRONT_DEVICE_PORT_COUNT )
+ {
+ device->tick_count = 0;
+
+ usbfront_device_handle_stimulus
+ ( device, usbfront_device_stimulus_pt );
+ }
+
+ changed = ( device->port_status[ port_number - 1 ].wPortChange != 0 );
+
+ spin_unlock_irqrestore( &device->lock, flags );
+
+ return changed;
+ }
+}
+
+struct usb_port_status usbfront_device_query_port_status
+ ( struct usbfront_device * device, int port_number )
+{
+ trace();
+
+ ASSERT
+ (
+ ( port_number > 0 )
+ &&
+ ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+ );
+
+ {
+ struct usb_port_status port_status;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &device->lock, flags );
+
+ port_status = device->port_status[ port_number - 1 ];
+
+ spin_unlock_irqrestore( &device->lock, flags );
+
+ return port_status;
+ }
+}
+
+void usbfront_device_set_port_power
+ ( struct usbfront_device * device, int port_number )
+{
+ trace();
+
+ ASSERT
+ (
+ ( port_number > 0 )
+ &&
+ ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+ );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &device->lock, flags );
+
+ device->port_status[ port_number - 1 ].wPortStatus |=
+ USB_PORT_STAT_POWER;
+
+ spin_unlock_irqrestore( &device->lock, flags );
+ }
+}
+
+void usbfront_device_set_port_reset
+ ( struct usbfront_device * device, int port_number )
+{
+ trace();
+
+ ASSERT
+ (
+ ( port_number > 0 )
+ &&
+ ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+ );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &device->lock, flags );
+
+ device->port_status[ port_number - 1 ].wPortStatus |=
+ USB_PORT_STAT_RESET;
+ device->port_status[ port_number - 1 ].wPortStatus &=
+ ~USB_PORT_STAT_ENABLE;
+
+ usbfront_device_handle_stimulus( device, usbfront_device_stimulus_pt );
+
+ spin_unlock_irqrestore( &device->lock, flags );
+ }
+}
+
+void usbfront_device_clear_port_enable
+ ( struct usbfront_device * device, int port_number )
+{
+ trace();
+
+ ASSERT
+ (
+ ( port_number > 0 )
+ &&
+ ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+ );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &device->lock, flags );
+
+ device->port_status[ port_number - 1 ].wPortStatus &=
+ ~USB_PORT_STAT_ENABLE;
+
+ spin_unlock_irqrestore( &device->lock, flags );
+ }
+}
+
+void usbfront_device_clear_port_connection_change
+ ( struct usbfront_device * device, int port_number )
+{
+ trace();
+
+ ASSERT
+ (
+ ( port_number > 0 )
+ &&
+ ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+ );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &device->lock, flags );
+
+ device->port_status[ port_number - 1 ].wPortChange &=
+ ~USB_PORT_STAT_C_CONNECTION;
+
+ spin_unlock_irqrestore( &device->lock, flags );
+ }
+}
+
+void usbfront_device_clear_port_reset_change
+ ( struct usbfront_device * device, int port_number )
+{
+ trace();
+
+ ASSERT
+ (
+ ( port_number > 0 )
+ &&
+ ( port_number <= USBFRONT_DEVICE_PORT_COUNT )
+ );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &device->lock, flags );
+
+ device->port_status[ port_number - 1 ].wPortChange &=
+ ~USB_PORT_STAT_C_RESET;
+
+ spin_unlock_irqrestore( &device->lock, flags );
+ }
+}
+
+void usbfront_device_submit_message
+ ( struct usbfront_device * device, xenidc_endpoint_message * message )
+{
+ trace();
+
+ xenidc_endpoint_submit_message( &device->endpoint, message );
+}
+
+void usbfront_device_submit_transaction
+ ( struct usbfront_device * device, xenidc_endpoint_transaction * transaction )
+{
+ trace();
+
+ xenidc_endpoint_submit_transaction( &device->endpoint, transaction );
+}
+
+static void usbfront_device_endpoint_connect( xenidc_endpoint * endpoint )
+{
+ trace();
+
+ /* Between connect and completion of the disconnect callback we are */
+ /* allowed to issue messages and transactions. */
+
+ {
+ struct usbfront_device * device =
+ usbfront_device_endpoint_to( endpoint );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &device->lock, flags );
+
+ usbfront_device_handle_stimulus( device, usbfront_device_stimulus_cn );
+
+ spin_unlock_irqrestore( &device->lock, flags );
+ }
+}
+
+static void usbfront_device_endpoint_disconnect
+ ( xenidc_endpoint * endpoint, xenidc_callback * callback )
+{
+ trace();
+
+ /* We must stop issuing messages and transactions and complete the */
+ /* callback once all of the messages and transactions we are issuing */
+ /* have completed or failed back to us. */
+
+ {
+ struct usbfront_device * device =
+ usbfront_device_endpoint_to( endpoint );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &device->lock, flags );
+
+ device->endpoint_disconnect_callback = callback;
+
+ usbfront_device_handle_stimulus( device, usbfront_device_stimulus_dn );
+
+ spin_unlock_irqrestore( &device->lock, flags );
+ }
+}
+
+static void usbfront_device_endpoint_message
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_message * message )
+{
+ trace();
+
+ /* The protocol doesn't require any messages sent from BE to FE so we */
+ /* just ignore anything sent to us. */
+
+ xenidc_callback_success( xenidc_endpoint_message_to_callback( message ) );
+}
+
+static void usbfront_device_endpoint_transaction
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_transaction * transaction )
+{
+ trace();
+
+ /* The protocol doesn't require any transactions sent from BE to FE so */
+ /* we just ignore anything sent to us. */
+
+ xenidc_endpoint_transaction_complete
+ ( transaction, XENIDC_ERROR_INVALID_PROTOCOL );
+}
+
+static void usbfront_device_probe_driver_1( void * data );
+static void usbfront_device_remove_driver_1( void * data );
+static void usbfront_device_probe_all_ports_1( xenidc_callback * callback );
+
+static int usbfront_device_init_or_exit
+ ( struct usbfront_device * device, struct xenbus_device * dev, int exit )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ if( exit )
+ {
+ goto EXIT;
+ }
+
+ memset( device, 0, sizeof( *device ) );
+
+ device->dev = dev;
+
+ spin_lock_init( &device->lock );
+
+ device->state = usbfront_device_state_i;
+
+ {
+ int i;
+
+ for( i = 0; i < USBFRONT_DEVICE_PORT_COUNT; i++ )
+ {
+ struct usbfront_device_probe_transaction * probe =
+ &device->probe_transaction[ i ];
+
+ xenidc_endpoint_transaction_init
+ (
+ &probe->transaction,
+ usbfront_device_probe_all_ports_1
+ );
+
+ probe->device = device;
+ }
+ }
+
+ xenidc_work_init
+ (
+ &device->probe_driver_1_work,
+ usbfront_device_probe_driver_1,
+ device
+ );
+
+ xenidc_work_init
+ (
+ &device->remove_driver_1_work,
+ usbfront_device_remove_driver_1,
+ device
+ );
+
+ device->backend = NULL;
+
+ return_value = xenbus_gather
+ (
+ NULL, /* FIXME? */
+ dev->nodename,
+ "backend-id", "%li", &device->backend_id,
+ "backend", NULL, &device->backend,
+ NULL
+ );
+
+ if( XENBUS_EXIST_ERR( return_value ) )
+ {
+ goto EXIT_NO_BACKEND;
+ }
+
+ if( return_value < 0 )
+ {
+ xenbus_dev_error
+ (
+ dev,
+ return_value,
+ "reading %s/backend",
+ dev->nodename
+ );
+
+ goto EXIT_NO_BACKEND;
+ }
+
+ return_value = xenidc_endpoint_init
+ (
+ &device->endpoint,
+ usbfront_device_endpoint_connect,
+ usbfront_device_endpoint_message,
+ usbfront_device_endpoint_transaction,
+ usbfront_device_endpoint_disconnect,
+ USBIF_FE_INITIATOR_QUOTA,
+ USBIF_FE_INITIATOR_MAXIMUM_BYTE_COUNT,
+ USBIF_FE_TARGET_QUOTA,
+ USBIF_FE_TARGET_MAXIMUM_BYTE_COUNT
+ );
+
+ if( return_value != 0 )
+ {
+ goto EXIT_NO_ENDPOINT;
+ }
+
+ {
+ xenidc_address address;
+
+ xenidc_address_init
+ (
+ &address,
+ dev->nodename,
+ device->backend,
+ device->backend_id
+ );
+
+ xenidc_endpoint_create( &device->endpoint, address );
+ }
+
+ return 0;
+
+ EXIT:
+
+ xenidc_endpoint_destroy( &device->endpoint );
+
+ xenidc_endpoint_exit( &device->endpoint );
+
+ EXIT_NO_ENDPOINT:
+
+ kfree( device->backend );
+
+ EXIT_NO_BACKEND:
+
+ return return_value;
+ }
+}
+
+static int usbfront_device_init
+ ( struct usbfront_device * device, struct xenbus_device * dev )
+{
+ trace();
+
+ return usbfront_device_init_or_exit( device, dev, 0 );
+}
+
+static void usbfront_device_exit( struct usbfront_device * device )
+{
+ trace();
+
+ (void)usbfront_device_init_or_exit( device, NULL, 1 );
+}
+
+static int usbfront_device_probe_or_remove
+ ( struct xenbus_device * dev, int remove )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ struct usbfront_device * device;
+
+ if( remove )
+ {
+ goto REMOVE;
+ }
+
+ device = kmalloc( sizeof( *device ), GFP_KERNEL );
+
+ if( device == NULL )
+ {
+ xenbus_dev_error( dev, -ENOMEM, "allocating backend structure" );
+
+ return_value = -ENOMEM;
+
+ goto EXIT_NO_DEVICE;
+ }
+
+ dev->data = device;
+
+ return_value = usbfront_device_init( device, dev );
+
+ if( return_value != 0 )
+ {
+ goto EXIT_INIT_FAILED;
+ }
+
+ return 0;
+
+ REMOVE:
+
+ device = dev->data;
+
+ usbfront_device_exit( device );
+
+ EXIT_INIT_FAILED:
+
+ dev->data = NULL;
+
+ kfree( device );
+
+ EXIT_NO_DEVICE:
+
+ return return_value;
+ }
+}
+
+static int usbfront_device_probe
+ ( struct xenbus_device * dev, const struct xenbus_device_id * id )
+{
+ trace();
+
+ return usbfront_device_probe_or_remove( dev, 0 );
+}
+
+static int usbfront_device_remove( struct xenbus_device * dev )
+{
+ trace();
+
+ return usbfront_device_probe_or_remove( dev, 1 );
+}
+
+static struct xenbus_device_id usbfront_device_ids[] =
+{
+ { "usb" },
+ { "" }
+};
+
+static struct xenbus_driver usbfront_device_driver =
+{
+ .name = "usb",
+ .owner = THIS_MODULE,
+ .ids = usbfront_device_ids,
+ .probe = usbfront_device_probe,
+ .remove = usbfront_device_remove,
+};
+
+int usbfront_device_class_init( void )
+{
+ trace();
+
+ return xenbus_register_driver( &usbfront_device_driver );
+}
+
+void usbfront_device_class_exit( void )
+{
+ trace();
+
+ xenbus_unregister_driver( &usbfront_device_driver );
+}
+
+static void usbfront_device_invalid_stimulus
+ ( struct usbfront_device * device, usbfront_device_stimulus stimulus );
+
+static void usbfront_device_probe_driver( struct usbfront_device * device );
+
+static void usbfront_device_remove_driver( struct usbfront_device * device );
+
+static void usbfront_device_probe_all_ports( struct usbfront_device * device );
+
+static void usbfront_device_disconnect_all_ports
+ ( struct usbfront_device * device );
+
+static void usbfront_device_complete_endpoint_disconnect
+ ( struct usbfront_device * device );
+
+static void usbfront_device_handle_stimulus
+ ( struct usbfront_device * device, usbfront_device_stimulus stimulus )
+{
+ switch( device->state )
+ {
+ case usbfront_device_state_i:
+ switch( stimulus )
+ {
+ case usbfront_device_stimulus_cn:
+ device->state = usbfront_device_state_i_cn;
+ usbfront_device_probe_driver( device );
+ break;
+ default:
+ usbfront_device_invalid_stimulus( device, stimulus );
+ break;
+ }
+ case usbfront_device_state_i_cn:
+ /* Probing driver. */
+ switch( stimulus )
+ {
+ case usbfront_device_stimulus_dn:
+ device->state = usbfront_device_state_i_cn_dn;
+ break;
+ case usbfront_device_stimulus_ps:
+ device->state = usbfront_device_state_i_cn_ps;
+ usbfront_device_probe_all_ports( device );
+ break;
+ case usbfront_device_stimulus_pf:
+ device->state = usbfront_device_state_i_cn_pf;
+ break;
+ case usbfront_device_stimulus_pt:
+ break;
+ default:
+ usbfront_device_invalid_stimulus( device, stimulus );
+ break;
+ }
+ case usbfront_device_state_i_cn_dn:
+ /* Probing driver. */
+ /* Endpoint disconnecting. */
+ switch( stimulus )
+ {
+ case usbfront_device_stimulus_ps:
+ device->state = usbfront_device_state_i_cn_dn_ps;
+ usbfront_device_remove_driver( device );
+ break;
+ case usbfront_device_stimulus_pf:
+ device->state = usbfront_device_state_i;
+ usbfront_device_disconnect_all_ports( device );
+ usbfront_device_complete_endpoint_disconnect( device );
+ break;
+ case usbfront_device_stimulus_pt:
+ break;
+ default:
+ usbfront_device_invalid_stimulus( device, stimulus );
+ break;
+ }
+ case usbfront_device_state_i_cn_ps:
+ /* Driver Probed. */
+ /* Polling ports. */
+ switch( stimulus )
+ {
+ case usbfront_device_stimulus_dn:
+ device->state = usbfront_device_state_i_cn_ps_dn;
+ usbfront_device_remove_driver( device );
+ break;
+ case usbfront_device_stimulus_pt:
+ break;
+ case usbfront_device_stimulus_pc:
+ device->state = usbfront_device_state_i_cn_ps_pc;
+ break;
+ default:
+ usbfront_device_invalid_stimulus( device, stimulus );
+ break;
+ }
+ case usbfront_device_state_i_cn_pf:
+ /* Driver probe failed. */
+ switch( stimulus )
+ {
+ case usbfront_device_stimulus_dn:
+ device->state = usbfront_device_state_i;
+ usbfront_device_disconnect_all_ports( device );
+ usbfront_device_complete_endpoint_disconnect( device );
+ break;
+ default:
+ usbfront_device_invalid_stimulus( device, stimulus );
+ break;
+ }
+ case usbfront_device_state_i_cn_dn_ps:
+ /* Endpoint disconnecting. */
+ /* Removing driver. */
+ switch( stimulus )
+ {
+ case usbfront_device_stimulus_rc:
+ device->state = usbfront_device_state_i;
+ usbfront_device_disconnect_all_ports( device );
+ usbfront_device_complete_endpoint_disconnect( device );
+ break;
+ case usbfront_device_stimulus_pt:
+ break;
+ default:
+ usbfront_device_invalid_stimulus( device, stimulus );
+ break;
+ }
+ case usbfront_device_state_i_cn_ps_dn:
+ /* Endpoint disconnecting. */
+ /* Removing driver. */
+ /* Polling ports. */
+ switch( stimulus )
+ {
+ case usbfront_device_stimulus_rc:
+ device->state = usbfront_device_state_i_cn_ps_dn_rc;
+ break;
+ case usbfront_device_stimulus_pt:
+ break;
+ case usbfront_device_stimulus_pc:
+ device->state = usbfront_device_state_i_cn_dn_ps;
+ break;
+ default:
+ usbfront_device_invalid_stimulus( device, stimulus );
+ break;
+ }
+ case usbfront_device_state_i_cn_ps_pc:
+ /* Driver Probed. */
+ switch( stimulus )
+ {
+ case usbfront_device_stimulus_dn:
+ device->state = usbfront_device_state_i_cn_dn_ps;
+ usbfront_device_remove_driver( device );
+ break;
+ case usbfront_device_stimulus_pt:
+ device->state = usbfront_device_state_i_cn_ps;
+ usbfront_device_probe_all_ports( device );
+ break;
+ default:
+ usbfront_device_invalid_stimulus( device, stimulus );
+ break;
+ }
+ case usbfront_device_state_i_cn_ps_dn_rc:
+ /* Endpoint disconnecting. */
+ /* Polling ports. */
+ switch( stimulus )
+ {
+ case usbfront_device_stimulus_pc:
+ device->state = usbfront_device_state_i;
+ usbfront_device_disconnect_all_ports( device );
+ usbfront_device_complete_endpoint_disconnect( device );
+ break;
+ default:
+ usbfront_device_invalid_stimulus( device, stimulus );
+ break;
+ }
+ default:
+ usbfront_device_invalid_stimulus( device, stimulus );
+ break;
+ }
+}
+
+static void usbfront_device_invalid_stimulus
+ ( struct usbfront_device * device, usbfront_device_stimulus stimulus )
+{
+ trace();
+
+ printk
+ (
+ KERN_ERR "usbfront: device %p in state %d"
+ "received invalid stimulus %d",
+ device,
+ device->state,
+ stimulus
+ );
+}
+
+static void usbfront_device_probe_driver( struct usbfront_device * device )
+{
+ trace();
+
+ {
+ int scheduled = xenidc_work_schedule( &device->probe_driver_1_work );
+
+ ASSERT( scheduled );
+ }
+}
+
+static void usbfront_device_probe_driver_1( void * data )
+{
+ trace();
+
+ {
+ struct usbfront_device * device = (struct usbfront_device *)data;
+
+ usbfront_device_stimulus stimulus;
+
+ if( usbfront_driver_probe( device ) == 0 )
+ {
+ stimulus = usbfront_device_stimulus_ps;
+ }
+ else
+ {
+ stimulus = usbfront_device_stimulus_pf;
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &device->lock, flags );
+
+ usbfront_device_handle_stimulus( device, stimulus );
+
+ spin_unlock_irqrestore( &device->lock, flags );
+ }
+ }
+}
+
+static void usbfront_device_remove_driver( struct usbfront_device * device )
+{
+ trace();
+
+ {
+ int scheduled = xenidc_work_schedule( &device->remove_driver_1_work );
+
+ ASSERT( scheduled );
+ }
+}
+
+static void usbfront_device_remove_driver_1( void * data )
+{
+ trace();
+
+ {
+ struct usbfront_device * device = (struct usbfront_device *)data;
+
+ usbfront_driver_remove( device );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &device->lock, flags );
+
+ usbfront_device_handle_stimulus
+ ( device, usbfront_device_stimulus_rc );
+
+ spin_unlock_irqrestore( &device->lock, flags );
+ }
+ }
+}
+
+static void usbfront_device_probe_all_ports( struct usbfront_device * device )
+{
+ device->port_probe_count = USBFRONT_DEVICE_PORT_COUNT;
+
+ {
+ int i;
+
+ for( i = 0; i < USBFRONT_DEVICE_PORT_COUNT; i++ )
+ {
+ struct usbfront_device_probe_transaction * probe =
+ &device->probe_transaction[ i ];
+
+ if
+ (
+ ( device->port_status[ i ].wPortStatus & USB_PORT_STAT_RESET )
+ !=
+ USB_PORT_STAT_RESET
+ )
+ {
+ xenidc_endpoint_transaction_set_parameters_lbr
+ (
+ &probe->transaction,
+ xenidc_vaddress_create_lbr
+ (
+ &probe->probe.parameters,
+ sizeof( probe->probe.parameters )
+ )
+ );
+
+ xenidc_endpoint_transaction_set_status_lbr
+ (
+ &probe->transaction,
+ xenidc_vaddress_create_lbr
+ (
+ &probe->probe.status,
+ sizeof( probe->probe.status )
+ )
+ );
+
+ memset
+ (
+ &probe->probe.parameters,
+ 0,
+ sizeof( probe->probe.parameters )
+ );
+
+ probe->probe.parameters.header.transaction_type =
+ USBIF_TRANSACTION_TYPE_PROBE;
+
+ probe->probe.parameters.port = i + 1;
+
+ memset
+ ( &probe->probe.status, 0, sizeof( probe->probe.status ) );
+ }
+ else
+ {
+ xenidc_endpoint_transaction_set_parameters_lbr
+ (
+ &probe->transaction,
+ xenidc_vaddress_create_lbr
+ (
+ &probe->reset.parameters,
+ sizeof( probe->reset.parameters )
+ )
+ );
+
+ xenidc_endpoint_transaction_set_status_lbr
+ (
+ &probe->transaction,
+ xenidc_vaddress_create_lbr
+ (
+ &probe->reset.status,
+ sizeof( probe->reset.status )
+ )
+ );
+
+ memset
+ (
+ &probe->reset.parameters,
+ 0,
+ sizeof( probe->reset.parameters )
+ );
+
+ probe->reset.parameters.header.transaction_type =
+ USBIF_TRANSACTION_TYPE_RESET;
+
+ probe->reset.parameters.port = i + 1;
+
+ memset
+ ( &probe->reset.status, 0, sizeof( probe->reset.status ) );
+ }
+
+ xenidc_endpoint_submit_transaction
+ ( &device->endpoint, &probe->transaction );
+ }
+ }
+}
+
+static void usbfront_device_probe_all_ports_1( xenidc_callback * callback )
+{
+ struct usbfront_device_probe_transaction * probe = container_of
+ (
+ xenidc_endpoint_transaction_callback_to( callback ),
+ struct usbfront_device_probe_transaction,
+ transaction
+ );
+
+ struct usbfront_device * device = probe->device;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &device->lock, flags );
+
+ if
+ (
+ probe->probe.parameters.header.transaction_type
+ ==
+ USBIF_TRANSACTION_TYPE_PROBE
+ )
+ {
+ int port_number = probe->probe.parameters.port;
+
+ if( xenidc_callback_query_error( callback ) == XENIDC_ERROR_SUCCESS )
+ {
+ struct usb_port_status * port_status =
+ &device->port_status[ port_number - 1 ];
+
+ if
+ (
+ probe->probe.status.result
+ ==
+ USBIF_PROBE_RESULT_DEVICE_PRESENT
+ )
+ {
+ /* There is a device attached to the port. */
+
+ if
+ (
+ ( port_status->wPortStatus & USB_PORT_STAT_CONNECTION )
+ !=
+ USB_PORT_STAT_CONNECTION
+ )
+ {
+ /* There wasn't a device attached to the port before. */
+
+ port_status->wPortStatus |= USB_PORT_STAT_CONNECTION;
+ port_status->wPortChange |= USB_PORT_STAT_C_CONNECTION;
+ }
+ }
+ else if
+ ( probe->probe.status.result == USBIF_PROBE_RESULT_NO_DEVICE )
+ {
+ /* There isn't a device attached to the port. */
+
+ if
+ (
+ ( port_status->wPortStatus & USB_PORT_STAT_CONNECTION )
+ ==
+ USB_PORT_STAT_CONNECTION
+ )
+ {
+ /* There was a device attached to the port before. */
+
+ port_status->wPortStatus &= ~USB_PORT_STAT_CONNECTION;
+ port_status->wPortChange |= USB_PORT_STAT_C_CONNECTION;
+ }
+ }
+ else
+ {
+ trace3
+ (
+ "device %p: unexpected result %d probing port %d",
+ device,
+ (int)probe->probe.status.result,
+ port_number
+ );
+ }
+ }
+ else
+ {
+ trace3
+ (
+ "device %p: error %d probing port %d",
+ device,
+ usbif_error_map_to_local
+ ( xenidc_callback_query_error( callback ) ),
+ port_number
+ );
+ }
+ }
+ else
+ {
+ int port_number = probe->reset.parameters.port;
+
+ struct usb_port_status * port_status =
+ &device->port_status[ port_number - 1 ];
+
+ if
+ (
+ ( xenidc_callback_query_error( callback ) == XENIDC_ERROR_SUCCESS )
+ &&
+ (
+ ( probe->reset.status.result == USBIF_RESET_RESULT_FULL_SPEED )
+ ||
+ ( probe->reset.status.result == USBIF_RESET_RESULT_LOW_SPEED )
+ ||
+ ( probe->reset.status.result == USBIF_RESET_RESULT_HIGH_SPEED )
+ )
+ )
+ {
+ if( probe->reset.status.result == USBIF_RESET_RESULT_LOW_SPEED )
+ {
+ port_status->wPortStatus |= USB_PORT_STAT_LOW_SPEED;
+ port_status->wPortStatus &= ~USB_PORT_STAT_HIGH_SPEED;
+ }
+ else if
+ ( probe->reset.status.result == USBIF_RESET_RESULT_HIGH_SPEED )
+ {
+ port_status->wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
+ port_status->wPortStatus |= USB_PORT_STAT_HIGH_SPEED;
+ }
+ else
+ {
+ port_status->wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
+ port_status->wPortStatus &= ~USB_PORT_STAT_HIGH_SPEED;
+ }
+
+ port_status->wPortStatus &= ~USB_PORT_STAT_RESET;
+ port_status->wPortStatus |= USB_PORT_STAT_ENABLE;
+ port_status->wPortChange |= USB_PORT_STAT_C_RESET;
+ }
+ else
+ {
+ if
+ (
+ xenidc_callback_query_error( callback )
+ !=
+ XENIDC_ERROR_SUCCESS
+ )
+ {
+ printk
+ (
+ KERN_ERR "usbfront: device %p: error %d resetting port %d",
+ device,
+ usbif_error_map_to_local
+ ( xenidc_callback_query_error( callback ) ),
+ port_number
+ );
+ }
+ else
+ {
+ trace3
+ (
+ "device %p: unexpected result %d resetting port %d",
+ device,
+ (int)probe->reset.status.result,
+ port_number
+ );
+ }
+
+ port_status->wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
+ port_status->wPortStatus &= ~USB_PORT_STAT_HIGH_SPEED;
+
+ port_status->wPortStatus &= ~USB_PORT_STAT_RESET;
+ port_status->wPortChange |= USB_PORT_STAT_C_RESET;
+ }
+ }
+
+ if( --device->port_probe_count == 0 )
+ {
+ usbfront_device_handle_stimulus( device, usbfront_device_stimulus_pc );
+ }
+
+ spin_unlock_irqrestore( &device->lock, flags );
+}
+
+static void usbfront_device_disconnect_all_ports
+ ( struct usbfront_device * device )
+{
+ trace();
+
+ {
+ int i;
+
+ for( i = 0; i < USBFRONT_DEVICE_PORT_COUNT; i++ )
+ {
+ struct usb_port_status * port_status = &device->port_status[ i ];
+
+ if
+ (
+ ( port_status->wPortStatus & USB_PORT_STAT_CONNECTION )
+ ==
+ USB_PORT_STAT_CONNECTION
+ )
+ {
+ /* There was a device attached to the port before. */
+
+ port_status->wPortStatus &= ~USB_PORT_STAT_CONNECTION;
+ port_status->wPortChange |= USB_PORT_STAT_C_CONNECTION;
+ }
+ }
+ }
+}
+
+static void usbfront_device_complete_endpoint_disconnect
+ ( struct usbfront_device * device )
+{
+ trace();
+
+ xenidc_callback_success( device->endpoint_disconnect_callback );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,85 @@
+/*****************************************************************************/
+/* usbfront_device is a device which represents a connection to a back-end. */
+/* The intent was for it to have an interface like a hardware USB host */
+/* controller device. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef USBFRONT_DEVICE_H
+#define USBFRONT_DEVICE_H
+
+#include <linux/device.h>
+#include <linux/usb.h>
+#include "../../usb/core/hcd.h"
+#include <asm-xen/xen-public/io/usbif.h>
+
+extern int usbfront_device_class_init( void );
+
+extern void usbfront_device_class_exit( void );
+
+struct usbfront_device;
+
+void usbfront_device_set_drvdata
+ ( struct usbfront_device * device, void * data );
+
+void * usbfront_device_get_drvdata( struct usbfront_device * device );
+
+struct device * usbfront_device_to_dev
+ ( struct usbfront_device * device );
+
+struct usbfront_device * usbfront_device_dev_to( struct device * dev );
+
+int usbfront_device_query_port_count( struct usbfront_device * device );
+
+int usbfront_device_query_port_status_changed
+ ( struct usbfront_device * device, int port_number );
+
+struct usb_port_status usbfront_device_query_port_status
+ ( struct usbfront_device * device, int port_number );
+
+/* Used to turn on power to a port. */
+void usbfront_device_set_port_power
+ ( struct usbfront_device * device, int port_number );
+
+/* Used to reset a port. Completes asynchronously with notification via the */
+/* port status. */
+void usbfront_device_set_port_reset
+ ( struct usbfront_device * device, int port_number );
+
+void usbfront_device_clear_port_enable
+ ( struct usbfront_device * device, int port_number );
+
+/* Used to ack a connection change */
+void usbfront_device_clear_port_connection_change
+ ( struct usbfront_device * device, int port_number );
+
+/* Used to ack a reset change */
+void usbfront_device_clear_port_reset_change
+ ( struct usbfront_device * device, int port_number );
+
+void usbfront_device_submit_message
+ ( struct usbfront_device * device, xenidc_endpoint_message * message );
+
+void usbfront_device_submit_transaction
+(
+ struct usbfront_device * device,
+ xenidc_endpoint_transaction * transaction
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,880 @@
+/*****************************************************************************/
+/* A device driver for usbfront_device devices. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on */
+/* */
+/* arch/xen/drivers/usbif/frontend/main.c */
+/* pristine-linux-2.6.11/drivers/usb/host/uhci-hcd.c */
+/* pristine-linux-2.6.11/drivers/usb/core/hcd-pci.c */
+/* */
+/* original copyright notices follow... */
+/*****************************************************************************/
+
+/*
+ * Xen Virtual USB Frontend Driver
+ *
+ * This file contains the first version of the Xen virtual USB hub
+ * that I've managed not to delete by mistake (3rd time lucky!).
+ *
+ * Based on Linux's uhci.c, original copyright notices are displayed
+ * below. Portions also (c) 2004 Intel Research Cambridge
+ * and (c) 2004, 2005 Mark Williamson
+ *
+ * Contact <mark.williamson@cl.cam.ac.uk> or
+ * <xen-devel@lists.sourceforge.net> regarding this code.
+ *
+ * Still to be (maybe) implemented:
+ * - migration / backend restart support?
+ * - support for building / using as a module
+ */
+
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ * - the low-level protocol (fairly simple but lots of small details)
+ * - working around the horridness of the rest
+ */
+
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Alan Stern <stern@rowland.harvard.edu>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ * - the low-level protocol (fairly simple but lots of small details)
+ * - working around the horridness of the rest
+ */
+
+/*
+ * (C) Copyright David Brownell 2000-2002
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/device.h>
+#include "usbfront_driver.h"
+#include "usbfront_hcd_resource.h"
+#include "usbfront_sll.h"
+#include "usbfront_trace.h"
+
+typedef enum
+{
+ usbfront_hcd_state_i
+}
+usbfront_hcd_state;
+
+typedef enum
+{
+ usbfront_hcd_stimulus_uq /* urb enqueue */
+}
+usbfront_hcd_stimulus;
+
+#define USBFRONT_HCD_RESOURCE_COUNT 16
+
+struct usbfront_hcd
+{
+ spinlock_t lock;
+ usbfront_hcd_state state;
+ struct usbfront_sll urb_sll;
+ struct list_head free_resource_list;
+ struct usbfront_hcd_resource resources[ USBFRONT_HCD_RESOURCE_COUNT ];
+};
+
+static void usbfront_hcd_handle_stimulus
+ ( struct usbfront_hcd * uhcd, usbfront_hcd_stimulus stimulus );
+
+static struct usbfront_hcd * usbfront_hcd_hcd_to_uhcd( struct usb_hcd * hcd )
+{
+ return (struct usbfront_hcd *)( hcd->hcd_priv );
+}
+
+static struct usbfront_device *
+ usbfront_hcd_hcd_to_usbfront_device( struct usb_hcd * hcd )
+{
+ return usbfront_device_dev_to( hcd_to_bus( hcd )->controller );
+}
+
+void usbfront_hcd_resource_completed( xenidc_callback * callback );
+
+static int usbfront_hcd_start( struct usb_hcd * hcd )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd( hcd );
+
+ memset( uhcd, 0, sizeof( *uhcd ) );
+
+ spin_lock_init( &uhcd->lock );
+
+ uhcd->state = usbfront_hcd_state_i;
+
+ usbfront_sll_init( &uhcd->urb_sll );
+
+ INIT_LIST_HEAD( &uhcd->free_resource_list );
+
+ {
+ int i;
+
+ for( i = 0; i < USBFRONT_HCD_RESOURCE_COUNT; i++ )
+ {
+ struct usbfront_hcd_resource * resource =
+ &uhcd->resources[ i ];
+
+ return_value = usbfront_hcd_resource_init
+ (
+ resource,
+ usbfront_hcd_hcd_to_usbfront_device( hcd ),
+ i,
+ usbfront_hcd_resource_completed
+ );
+
+ if( return_value != 0 )
+ {
+ goto EXIT_NO_RESOURCE;
+ }
+
+ list_add
+ (
+ usbfront_hcd_resource_to_link( resource ),
+ &uhcd->free_resource_list
+ );
+ }
+ }
+
+ {
+ struct usb_device * root_hub_device =
+ usb_alloc_dev( NULL, &hcd->self, 0 );
+
+ if( root_hub_device == NULL )
+ {
+ return_value = -ENOMEM;
+
+ goto EXIT_NO_ROOT_HUB;
+ }
+
+ root_hub_device->speed = USB_SPEED_HIGH;
+
+ if
+ (
+ (
+ return_value =
+ usb_hcd_register_root_hub( root_hub_device, hcd )
+ )
+ !=
+ 0
+ )
+ {
+ goto EXIT_NO_REGISTER;
+ }
+
+ return 0;
+
+ EXIT_NO_REGISTER:
+
+ usb_put_dev( root_hub_device );
+ }
+
+ EXIT_NO_ROOT_HUB:
+
+ EXIT_NO_RESOURCE:
+
+ while( !list_empty( &uhcd->free_resource_list ) )
+ {
+ struct usbfront_hcd_resource * resource = list_entry
+ (
+ uhcd->free_resource_list.next,
+ struct usbfront_hcd_resource,
+ USBFRONT_HCD_RESOURCE_LINK
+ );
+
+ list_del_init( usbfront_hcd_resource_to_link( resource ) );
+
+ usbfront_hcd_resource_exit( resource );
+ }
+
+ return return_value;
+ }
+}
+
+static void usbfront_hcd_stop( struct usb_hcd * hcd )
+{
+ trace();
+
+ {
+ struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd( hcd );
+
+ while( !list_empty( &uhcd->free_resource_list ) )
+ {
+ struct usbfront_hcd_resource * resource = list_entry
+ (
+ uhcd->free_resource_list.next,
+ struct usbfront_hcd_resource,
+ USBFRONT_HCD_RESOURCE_LINK
+ );
+
+ list_del_init( usbfront_hcd_resource_to_link( resource ) );
+
+ usbfront_hcd_resource_exit( resource );
+ }
+ }
+}
+
+static int usbfront_hcd_get_frame_number( struct usb_hcd * hcd )
+{
+ trace();
+
+ return 0;
+}
+
+static inline void usbfront_check_contiguous
+ ( unsigned long buffer, unsigned long length )
+{
+ if( length != 0 )
+ {
+ unsigned long offset;
+
+ for
+ (
+ offset = 0;
+ offset < ( length + ( buffer & ~PAGE_MASK ) );
+ offset += PAGE_SIZE
+ )
+ {
+ unsigned long maddress1 =
+ virt_to_machine( ( buffer & PAGE_MASK ) + offset );
+
+ unsigned long maddress2 =
+ virt_to_machine( buffer & PAGE_MASK ) + offset;
+
+ ASSERT( maddress1 == maddress2 );
+ }
+ }
+}
+
+static int usbfront_hcd_urb_enqueue
+(
+ struct usb_hcd * hcd,
+ struct usb_host_endpoint * ep, /* FIXME: what's the intended use for ep? */
+ struct urb * urb,
+ int mem_flags
+)
+{
+ trace();
+
+ usbfront_check_contiguous
+ ( (unsigned long)urb->transfer_buffer, urb->transfer_buffer_length );
+
+ {
+ struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd( hcd );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &uhcd->lock, flags );
+
+ usbfront_slk_init( (struct usbfront_slk *)&urb->hcpriv );
+
+ usbfront_sll_add_last
+ ( &uhcd->urb_sll, (struct usbfront_slk *)&urb->hcpriv );
+
+ usbfront_hcd_handle_stimulus( uhcd, usbfront_hcd_stimulus_uq );
+
+ spin_unlock_irqrestore( &uhcd->lock, flags );
+ }
+
+ return 0;
+}
+
+static int usbfront_hcd_urb_dequeue( struct usb_hcd * hcd, struct urb * urb )
+{
+ trace();
+
+ {
+ int dequeued;
+
+ {
+ struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd( hcd );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &uhcd->lock, flags );
+
+ dequeued = usbfront_sll_remove_slk
+ ( &uhcd->urb_sll, (struct usbfront_slk *)&urb->hcpriv );
+
+ spin_unlock_irqrestore( &uhcd->lock, flags );
+ }
+
+ if( dequeued )
+ {
+ urb->hcpriv = 0;
+
+ urb->actual_length = 0;
+
+ {
+ unsigned long flags;
+
+ local_irq_save( flags );
+
+ usb_hcd_giveback_urb( hcd, urb, 0 );
+
+ local_irq_restore( flags );
+ }
+ }
+ else
+ {
+ usbfront_hcd_resource_dequeue_urb( urb );
+ }
+ }
+
+ return 0;
+}
+
+static void usbfront_hcd_endpoint_disable
+ ( struct usb_hcd * hcd, struct usb_host_endpoint * ep )
+{
+ trace();
+}
+
+static int usbfront_hcd_hub_status_data( struct usb_hcd * hcd, char * buf )
+{
+ int changed = 0;
+
+ struct usbfront_device * device =
+ usbfront_hcd_hcd_to_usbfront_device( hcd );
+
+ int port_count = usbfront_device_query_port_count( device );
+
+ int byte_count =
+ ( 1 /* hub */ + port_count /* ports */ + 7 /* round up */ ) / 8;
+
+ memset( buf, 0, byte_count );
+
+ {
+ int i;
+
+ for( i = 0; i < port_count; i++ )
+ {
+ if( usbfront_device_query_port_status_changed( device, i ) )
+ {
+ buf[ ( i + 1 ) / 8 ] |= 1 << ( ( i + 1 ) % 8 );
+
+ changed = 1;
+ }
+ }
+ }
+
+ return changed ? byte_count : 0;
+}
+
+static int usbfront_hcd_hub_control
+(
+ struct usb_hcd * hcd,
+ u16 typeReq,
+ u16 wValue,
+ u16 wIndex,
+ char * buf,
+ u16 wLength
+)
+{
+ trace();
+
+ {
+ struct usbfront_device * device =
+ usbfront_hcd_hcd_to_usbfront_device( hcd );
+
+ int return_value = 0;
+
+ switch( typeReq )
+ {
+ case GetHubStatus:
+
+ trace0( "GetHubStatus" );
+
+ if( ( wValue != 0 ) || ( wIndex != 0 ) || ( wLength != 4 ) )
+ {
+ goto ERROR;
+ }
+
+ /* 2 bytes wHubStatus and 2 bytes wHubChange: */
+ /* Local power supply good, no overcurrect condition */
+ /* No changes. */
+
+ memset( buf, 0, wLength );
+
+ break;
+
+ case GetPortStatus:
+
+ trace0( "GetPortStatus" );
+
+ if
+ (
+ ( wValue != 0 )
+ ||
+ ( wIndex > usbfront_device_query_port_count( device ) )
+ ||
+ ( wLength != 4 )
+ )
+ {
+ goto ERROR;
+ }
+
+ {
+ struct usb_port_status port_status =
+ usbfront_device_query_port_status( device, wIndex - 1 );
+
+ memcpy( buf, &port_status, wLength );
+ }
+
+ break;
+
+ case GetHubDescriptor:
+
+ trace0( "GetHubDescriptor" );
+
+ {
+ /* bDescLength */
+ /* bDescriptorType */
+ /* bNbrPorts */
+ /* wHubCharacteristics LSB */
+ /* wHubCharacteristics MSB */
+ /* bPwrOn2PwrGood */
+ /* bHubContrCurrent */
+ /* DeviceRemovable */
+ /* PortPwrCtrlMask */
+
+ /* See table 11.23.2.1 of the USB 2.0 specification. */
+
+ char descriptor[] =
+ { 0x09, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xFF };
+
+ descriptor[ 2 ] = usbfront_device_query_port_count( device );
+
+ memcpy
+ (
+ buf,
+ &descriptor,
+ min_t( size_t, sizeof( descriptor ), wLength )
+ );
+ }
+
+ break;
+
+ case SetPortFeature:
+
+ trace0( "SetPortFeature" );
+
+ if
+ (
+ (
+ ( wIndex & 0x00FF )
+ >
+ usbfront_device_query_port_count( device )
+ )
+ ||
+ ( wLength != 0 )
+ )
+ {
+ goto ERROR;
+ }
+
+ switch( wValue )
+ {
+ case USB_PORT_FEAT_SUSPEND:
+ trace0( "USB_PORT_FEAT_SUSPEND" );
+ break;
+ case USB_PORT_FEAT_RESET:
+ trace0( "USB_PORT_FEAT_RESET" );
+ usbfront_device_set_port_reset( device, wIndex - 1 );
+ break;
+ case USB_PORT_FEAT_POWER:
+ trace0( "USB_PORT_FEAT_POWER" );
+ usbfront_device_set_port_power( device, wIndex - 1 );
+ break;
+ default:
+ trace1( "Unknown:%x", wValue );
+ goto ERROR;
+ }
+
+ break;
+
+ case ClearPortFeature:
+
+ trace0( "ClearPortFeature" );
+
+ if
+ (
+ (
+ ( wIndex & 0x00FF )
+ >
+ usbfront_device_query_port_count( device )
+ )
+ ||
+ ( wLength != 0 )
+ )
+ {
+ goto ERROR;
+ }
+
+ switch( wValue )
+ {
+ case USB_PORT_FEAT_ENABLE:
+ trace0( "USB_PORT_FEAT_ENABLE" );
+ usbfront_device_clear_port_enable( device, wIndex - 1 );
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ trace0( "USB_PORT_FEAT_SUSPEND" );
+ break;
+ case USB_PORT_FEAT_POWER:
+ trace0( "USB_PORT_FEAT_POWER" );
+ break;
+ case USB_PORT_FEAT_INDICATOR:
+ trace0( "USB_PORT_FEAT_INDICATOR" );
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ trace0( "USB_PORT_C_CONNECTION" );
+ usbfront_device_clear_port_connection_change
+ ( device, wIndex - 1 );
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ trace0( "USB_PORT_C_RESET" );
+ usbfront_device_clear_port_reset_change( device, wIndex - 1 );
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ trace0( "USB_PORT_C_ENABLE" );
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ trace0( "USB_PORT_C_SUSPEND" );
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ trace0( "USB_PORT_C_OVER_CURRENT" );
+ break;
+ default:
+ trace1( "Unknown:%x", wValue );
+ goto ERROR;
+ }
+
+ break;
+
+ default:
+ trace1( "Unknown:%x", typeReq );
+ ERROR:
+ return_value = -EPIPE;
+ }
+
+ return return_value;
+ }
+}
+
+static int usbfront_hcd_start_port_reset
+ ( struct usb_hcd * hcd, unsigned port_num )
+{
+ trace();
+
+ return 0;
+}
+
+static struct hc_driver usbfront_hc_driver =
+{
+ .description = "usbfront_hc_driver",
+ .product_desc = "Xen USB Front-End Driver",
+ .hcd_priv_size = sizeof( struct usbfront_hcd ),
+ /* .irq */
+ .flags = HCD_USB2,
+ /* reset optional. */
+ .start = usbfront_hcd_start,
+ /* suspend optional. */
+ /* resume optional. */
+ .stop = usbfront_hcd_stop,
+ .get_frame_number = usbfront_hcd_get_frame_number,
+ .urb_enqueue = usbfront_hcd_urb_enqueue,
+ .urb_dequeue = usbfront_hcd_urb_dequeue,
+ .endpoint_disable = usbfront_hcd_endpoint_disable,
+ .hub_status_data = usbfront_hcd_hub_status_data,
+ .hub_control = usbfront_hcd_hub_control,
+ /* hub_suspend optional. */
+ /* hub_resume optional. */
+ .start_port_reset = usbfront_hcd_start_port_reset,
+};
+
+static void usbfront_hcd_invalid_stimulus
+ ( struct usbfront_hcd * uhcd, usbfront_hcd_stimulus stimulus );
+
+static void usbfront_hcd_kick_urbs( struct usbfront_hcd * uhcd );
+
+static void usbfront_hcd_handle_stimulus
+ ( struct usbfront_hcd * uhcd, usbfront_hcd_stimulus stimulus )
+{
+ trace3
+ (
+ "uhcd %p in state %d received stimulus %d",
+ uhcd,
+ uhcd->state,
+ stimulus
+ );
+
+ switch( uhcd->state )
+ {
+ case usbfront_hcd_state_i:
+ switch( stimulus )
+ {
+ case usbfront_hcd_stimulus_uq:
+ usbfront_hcd_kick_urbs( uhcd );
+ break;
+ }
+ break;
+ default:
+ usbfront_hcd_invalid_stimulus( uhcd, stimulus );
+ break;
+ }
+}
+
+static void usbfront_hcd_invalid_stimulus
+ ( struct usbfront_hcd * uhcd, usbfront_hcd_stimulus stimulus )
+{
+ trace();
+
+ printk
+ (
+ KERN_ERR "usbfront: hc_driver_uhcd %p in state %d"
+ "received invalid stimulus %d",
+ uhcd,
+ uhcd->state,
+ stimulus
+ );
+}
+
+static void usbfront_hcd_kick_urbs( struct usbfront_hcd * uhcd )
+{
+ trace();
+
+ while
+ (
+ !usbfront_sll_is_empty( &uhcd->urb_sll )
+ &&
+ !list_empty( &uhcd->free_resource_list )
+ )
+ {
+ trace0( "Starting URB" );
+
+ {
+ struct urb * urb = container_of
+ (
+ (void **)usbfront_sll_remove_first( &uhcd->urb_sll ),
+ struct urb,
+ hcpriv
+ );
+
+ struct usbfront_hcd_resource * resource = list_entry
+ (
+ uhcd->free_resource_list.next,
+ struct usbfront_hcd_resource,
+ USBFRONT_HCD_RESOURCE_LINK
+ );
+
+ list_del_init( usbfront_hcd_resource_to_link( resource ) );
+
+ usbfront_hcd_resource_start_urb( resource, urb );
+ }
+ }
+}
+
+void usbfront_hcd_resource_completed( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ struct usbfront_hcd_resource * resource =
+ usbfront_hcd_resource_callback_to( callback );
+
+ struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd
+ (
+ usbfront_device_get_drvdata
+ ( usbfront_hcd_resource_query_device( resource ) )
+ );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &uhcd->lock, flags );
+
+ list_add
+ (
+ usbfront_hcd_resource_to_link( resource ),
+ &uhcd->free_resource_list
+ );
+
+ usbfront_hcd_kick_urbs( uhcd );
+
+ spin_unlock_irqrestore( &uhcd->lock, flags );
+ }
+}
+
+static int usbfront_driver_probe_or_remove
+ ( struct usbfront_device * device, int remove )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ struct usb_hcd * hcd;
+
+ if( remove )
+ {
+ goto REMOVE;
+ }
+
+ if( usb_disabled() )
+ {
+ return_value = -ENODEV;
+
+ goto REMOVE_0;
+ }
+
+ if
+ (
+ (
+ hcd = usb_create_hcd
+ (
+ &usbfront_hc_driver,
+ usbfront_device_to_dev( device ),
+ usbfront_device_to_dev( device )->bus_id
+ )
+ )
+ ==
+ NULL
+ )
+ {
+ return_value = -ENOMEM;
+
+ goto REMOVE_0;
+ }
+
+ usbfront_device_set_drvdata( device, hcd );
+
+ if( ( return_value = usb_add_hcd( hcd, 0, 0 ) ) != 0 )
+ {
+ goto REMOVE_1;
+ }
+
+ return 0;
+
+ REMOVE:
+
+ hcd = usbfront_device_get_drvdata( device );
+
+ usb_remove_hcd( hcd );
+
+ REMOVE_1:
+
+ usb_put_hcd( hcd );
+
+ usbfront_device_set_drvdata( device, NULL );
+
+ REMOVE_0:
+
+ return return_value;
+ }
+}
+
+int usbfront_driver_probe( struct usbfront_device * device )
+{
+ trace();
+
+ return usbfront_driver_probe_or_remove( device, 0 );
+}
+
+void usbfront_driver_remove( struct usbfront_device * device )
+{
+ trace();
+
+ usbfront_driver_probe_or_remove( device, 1 );
+}
+
+int usbfront_driver_class_init( void )
+{
+ trace();
+
+ return usbfront_hcd_resource_class_init();
+}
+
+void usbfront_driver_class_exit( void )
+{
+ trace();
+
+ usbfront_hcd_resource_class_exit();
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,35 @@
+/*****************************************************************************/
+/* A device driver for usbfront_device devices. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef USBFRONT_DRIVER_H
+#define USBFRONT_DRIVER_H
+
+#include "usbfront_device.h"
+
+extern int usbfront_driver_class_init( void );
+
+extern void usbfront_driver_class_exit( void );
+
+extern int usbfront_driver_probe( struct usbfront_device * device );
+
+extern void usbfront_driver_remove( struct usbfront_device * device );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,945 @@
+/*****************************************************************************/
+/* A resource used by the usbfront host controller device driver to process */
+/* an URB by translating the URB and optional unlink request into */
+/* a transaction and corresponding optional unlink message for submission to */
+/* the back end. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on arch/xen/drivers/usbif/frontend/main.c, original copyright */
+/* notice follows... */
+/*****************************************************************************/
+
+/*
+ * Xen Virtual USB Frontend Driver
+ *
+ * This file contains the first version of the Xen virtual USB hub
+ * that I've managed not to delete by mistake (3rd time lucky!).
+ *
+ * Based on Linux's uhci.c, original copyright notices are displayed
+ * below. Portions also (c) 2004 Intel Research Cambridge
+ * and (c) 2004, 2005 Mark Williamson
+ *
+ * Contact <mark.williamson@cl.cam.ac.uk> or
+ * <xen-devel@lists.sourceforge.net> regarding this code.
+ *
+ * Still to be (maybe) implemented:
+ * - migration / backend restart support?
+ * - support for building / using as a module
+ */
+
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ * - the low-level protocol (fairly simple but lots of small details)
+ * - working around the horridness of the rest
+ */
+
+/* FIXME is URB serialisation maintained correctly? */
+
+#include <asm-xen/xenidc_vaddress.h>
+#include "usbfront_assert.h"
+#include "usbfront_driver.h"
+#include "usbfront_hcd_resource.h"
+#include "usbfront_trace.h"
+
+xenidc_rbr_provider_pool * usbfront_hcd_resource_rbr_provider_pool;
+
+int usbfront_hcd_resource_class_init( void )
+{
+ trace();
+
+ usbfront_hcd_resource_rbr_provider_pool =
+ xenidc_allocate_rbr_provider_pool( USBIF_MAX_PAGES_PER_REQUEST );
+
+ return ( usbfront_hcd_resource_rbr_provider_pool != NULL ) ? 0 : -ENOMEM;
+}
+
+void usbfront_hcd_resource_class_exit( void )
+{
+ trace();
+
+ xenidc_free_rbr_provider_pool( usbfront_hcd_resource_rbr_provider_pool );
+}
+
+typedef enum
+{
+ usbfront_hcd_resource_stimulus_st, /* Start URB */
+ usbfront_hcd_resource_stimulus_dq, /* Dequeue URB */
+ usbfront_hcd_resource_stimulus_cs, /* Create RBRs success */
+ usbfront_hcd_resource_stimulus_cf, /* Create RBRs failure */
+ usbfront_hcd_resource_stimulus_tc, /* Transaction complete */
+ usbfront_hcd_resource_stimulus_rc, /* Revoke RBRs complete */
+ usbfront_hcd_resource_stimulus_uc, /* Unlink complete */
+}
+usbfront_hcd_resource_stimulus;
+
+static void usbfront_hcd_resource_handle_stimulus
+(
+ struct usbfront_hcd_resource * resource,
+ usbfront_hcd_resource_stimulus stimulus
+);
+
+static void usbfront_hcd_resource_create_rbrs_1( xenidc_callback * callback );
+
+static void usbfront_hcd_resource_submit_transaction_1
+ ( xenidc_callback * callback );
+
+static void usbfront_hcd_resource_revoke_rbrs_1
+ ( xenidc_callback * callback );
+
+static void usbfront_hcd_resource_submit_unlink_1
+ ( xenidc_callback * callback );
+
+static void usbfront_hcd_resource_complete_1( void * context );
+
+static int usbfront_hcd_resource_init_or_exit
+(
+ struct usbfront_hcd_resource * resource,
+ struct usbfront_device * device,
+ int index,
+ xenidc_callback_function * callback,
+ int exit
+)
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ if( exit )
+ {
+ goto EXIT;
+ }
+
+ xenidc_callback_init( &resource->callback, callback );
+
+ resource->device = device;
+
+ resource->index = index;
+
+ resource->schedule = (usbif_isochronous_io_schedule_element *)
+ __get_free_page( GFP_KERNEL );
+
+ if( resource->schedule == NULL )
+ {
+ return_value = -ENOMEM;
+
+ goto EXIT_NO_SCHEDULE;
+ }
+
+ spin_lock_init( &resource->lock );
+
+ resource->state = usbfront_hcd_resource_state_i;
+
+ xenidc_create_rbr_request_element_init
+ ( &resource->rbr_request_element[ 0 ] );
+
+ xenidc_create_rbr_request_element_init
+ ( &resource->rbr_request_element[ 1 ] );
+
+ xenidc_reserve_and_create_rbr_request_init
+ (
+ &resource->rbr_request,
+ usbfront_hcd_resource_create_rbrs_1,
+ usbfront_hcd_resource_revoke_rbrs_1
+ );
+
+ xenidc_endpoint_transaction_init
+ (
+ &resource->io_transaction,
+ usbfront_hcd_resource_submit_transaction_1
+ );
+
+ xenidc_endpoint_transaction_set_parameters_lbr
+ (
+ &resource->io_transaction,
+ xenidc_vaddress_create_lbr
+ (
+ &resource->io_parameters,
+ sizeof( resource->io_parameters )
+ )
+ );
+
+ xenidc_endpoint_transaction_set_status_lbr
+ (
+ &resource->io_transaction,
+ xenidc_vaddress_create_lbr
+ (
+ &resource->io_status,
+ sizeof( resource->io_status )
+ )
+ );
+
+ xenidc_endpoint_message_init
+ ( &resource->unlink_message, usbfront_hcd_resource_submit_unlink_1 );
+
+ xenidc_endpoint_message_set_message_lbr
+ (
+ &resource->unlink_message,
+ xenidc_vaddress_create_lbr
+ (
+ &resource->unlink_message_body,
+ sizeof( resource->unlink_message_body )
+ )
+ );
+
+ xenidc_work_init
+ (
+ &resource->complete_1_work,
+ usbfront_hcd_resource_complete_1,
+ resource
+ );
+
+ return 0;
+
+ EXIT:
+
+ free_page( (unsigned long)resource->schedule );
+
+ EXIT_NO_SCHEDULE:
+
+ return return_value;
+ }
+}
+
+int usbfront_hcd_resource_init
+(
+ struct usbfront_hcd_resource * resource,
+ struct usbfront_device * device,
+ int index,
+ xenidc_callback_function * callback
+)
+{
+ trace();
+
+ return usbfront_hcd_resource_init_or_exit
+ ( resource, device, index, callback, 0 );
+}
+
+void usbfront_hcd_resource_exit( struct usbfront_hcd_resource * resource )
+{
+ trace();
+
+ usbfront_hcd_resource_init_or_exit( resource, NULL, 0, NULL, 1 );
+}
+
+void usbfront_hcd_resource_start_urb
+ ( struct usbfront_hcd_resource * resource, struct urb * urb )
+{
+ trace();
+
+ urb->hcpriv = resource;
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ resource->urb = urb;
+
+ usbfront_hcd_resource_handle_stimulus
+ ( resource, usbfront_hcd_resource_stimulus_st );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+}
+
+static DEFINE_RWLOCK( dequeue_lock );
+
+void usbfront_hcd_resource_dequeue_urb( struct urb * urb )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ write_lock_irqsave( &dequeue_lock, flags );
+
+ if( urb->hcpriv != NULL )
+ {
+ struct usbfront_hcd_resource * resource =
+ (struct usbfront_hcd_resource *)urb->hcpriv;
+
+ unsigned long flags2;
+
+ spin_lock_irqsave( &resource->lock, flags2 );
+
+ usbfront_hcd_resource_handle_stimulus
+ ( resource, usbfront_hcd_resource_stimulus_dq );
+
+ spin_unlock_irqrestore( &resource->lock, flags2 );
+ }
+
+ write_unlock_irqrestore( &dequeue_lock, flags );
+ }
+}
+
+static void usbfront_hcd_resource_invalid_stimulus
+(
+ struct usbfront_hcd_resource * resource,
+ usbfront_hcd_resource_stimulus stimulus
+);
+
+static void usbfront_hcd_resource_create_rbrs
+ ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_abort_create_rbrs
+ ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_set_aborted_error
+ ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_submit_transaction
+ ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_revoke_rbrs
+ ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_submit_unlink
+ ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_complete
+ ( struct usbfront_hcd_resource * resource );
+
+static void usbfront_hcd_resource_handle_stimulus
+(
+ struct usbfront_hcd_resource * resource,
+ usbfront_hcd_resource_stimulus stimulus
+)
+{
+ trace();
+
+ switch( resource->state )
+ {
+ case usbfront_hcd_resource_state_i:
+ /* Initialised. */
+ /* Maybe completing previous URB. */
+ switch( stimulus )
+ {
+ case usbfront_hcd_resource_stimulus_st:
+ resource->state = usbfront_hcd_resource_state_i_st;
+ usbfront_hcd_resource_create_rbrs( resource );
+ break;
+ /* A dequeue is possible whilst we are making the complete */
+ /* response after we have transitioned back to the i state. */
+ case usbfront_hcd_resource_stimulus_dq:
+ break;
+ default:
+ usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+ break;
+ }
+ break;
+ case usbfront_hcd_resource_state_i_st:
+ /* Creating RBRs. */
+ switch( stimulus )
+ {
+ case usbfront_hcd_resource_stimulus_dq:
+ resource->state = usbfront_hcd_resource_state_i_st_dq;
+ usbfront_hcd_resource_abort_create_rbrs( resource );
+ break;
+ case usbfront_hcd_resource_stimulus_cs:
+ resource->state = usbfront_hcd_resource_state_i_st_cs;
+ usbfront_hcd_resource_submit_transaction( resource );
+ break;
+ case usbfront_hcd_resource_stimulus_cf:
+ resource->state = usbfront_hcd_resource_state_i;
+ usbfront_hcd_resource_complete( resource );
+ break;
+ default:
+ usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+ break;
+ }
+ break;
+ case usbfront_hcd_resource_state_i_st_dq:
+ /* Creating RBRs. */
+ /* Dequeue URB. */
+ switch( stimulus )
+ {
+ case usbfront_hcd_resource_stimulus_dq:
+ break;
+ case usbfront_hcd_resource_stimulus_cs:
+ resource->state = usbfront_hcd_resource_state_i_st_dq_cs;
+ usbfront_hcd_resource_set_aborted_error( resource );
+ usbfront_hcd_resource_revoke_rbrs( resource );
+ break;
+ case usbfront_hcd_resource_stimulus_cf:
+ resource->state = usbfront_hcd_resource_state_i;
+ usbfront_hcd_resource_complete( resource );
+ break;
+ default:
+ usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+ break;
+ }
+ break;
+ case usbfront_hcd_resource_state_i_st_cs:
+ /* Transaction submitted. */
+ switch( stimulus )
+ {
+ case usbfront_hcd_resource_stimulus_dq:
+ resource->state = usbfront_hcd_resource_state_i_st_cs_dq;
+ usbfront_hcd_resource_submit_unlink( resource );
+ break;
+ case usbfront_hcd_resource_stimulus_tc:
+ resource->state = usbfront_hcd_resource_state_i_st_dq_cs;
+ usbfront_hcd_resource_revoke_rbrs( resource );
+ break;
+ default:
+ usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+ break;
+ }
+ break;
+ case usbfront_hcd_resource_state_i_st_dq_cs:
+ /* Revoking RBRs. */
+ /* Maybe Dequeue URB. */
+ switch( stimulus )
+ {
+ case usbfront_hcd_resource_stimulus_dq:
+ break;
+ case usbfront_hcd_resource_stimulus_rc:
+ resource->state = usbfront_hcd_resource_state_i;
+ usbfront_hcd_resource_complete( resource );
+ break;
+ default:
+ usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+ break;
+ }
+ break;
+ case usbfront_hcd_resource_state_i_st_cs_dq:
+ /* Transaction submitted. */
+ /* Unlink submitted. */
+ /* Dequeue URB. */
+ switch( stimulus )
+ {
+ case usbfront_hcd_resource_stimulus_dq:
+ break;
+ case usbfront_hcd_resource_stimulus_tc:
+ case usbfront_hcd_resource_stimulus_uc:
+ resource->state = usbfront_hcd_resource_state_i_st_cs_dq_tc;
+ break;
+ default:
+ usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+ break;
+ }
+ break;
+ case usbfront_hcd_resource_state_i_st_cs_dq_tc:
+ /* Transaction submitted or Unlink submitted. */
+ /* Dequeue URB. */
+ switch( stimulus )
+ {
+ case usbfront_hcd_resource_stimulus_dq:
+ break;
+ case usbfront_hcd_resource_stimulus_tc:
+ case usbfront_hcd_resource_stimulus_uc:
+ resource->state = usbfront_hcd_resource_state_i_st_dq_cs;
+ usbfront_hcd_resource_revoke_rbrs( resource );
+ break;
+ default:
+ usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+ break;
+ }
+ break;
+ default:
+ usbfront_hcd_resource_invalid_stimulus( resource, stimulus );
+ break;
+ }
+}
+
+static void usbfront_hcd_resource_invalid_stimulus
+(
+ struct usbfront_hcd_resource * resource,
+ usbfront_hcd_resource_stimulus stimulus
+)
+{
+ trace();
+
+ printk
+ (
+ KERN_ERR "usbfront: hcd resource %p in state %d"
+ "received invalid stimulus %d",
+ resource,
+ resource->state,
+ stimulus
+ );
+}
+
+static void usbfront_hcd_resource_create_rbrs
+ ( struct usbfront_hcd_resource * resource )
+{
+ trace();
+
+ xenidc_create_rbr_request_element_ensure_removed
+ ( &resource->rbr_request_element[ 0 ] );
+
+ xenidc_create_rbr_request_element_ensure_removed
+ ( &resource->rbr_request_element[ 1 ] );
+
+ xenidc_create_rbr_request_element_set_lbr
+ (
+ &resource->rbr_request_element[ 0 ],
+ xenidc_vaddress_create_lbr
+ (
+ resource->urb->transfer_buffer,
+ resource->urb->transfer_buffer_length
+ )
+ );
+
+ xenidc_reserve_and_create_rbr_request_add_element
+ (
+ &resource->rbr_request,
+ &resource->rbr_request_element[ 0 ]
+ );
+
+ if( usb_pipetype( resource->urb->pipe ) == PIPE_ISOCHRONOUS )
+ {
+ if
+ (
+ resource->urb->number_of_packets
+ >
+ ( PAGE_SIZE / sizeof( usbif_isochronous_io_schedule_element ) )
+ )
+ {
+ goto SCHEDULE_TOO_BIG;
+ }
+
+ {
+ usbif_isochronous_io_schedule_element * element =
+ resource->schedule;
+
+ int i;
+
+ for( i = 0; i < resource->urb->number_of_packets; i++ )
+ {
+ memset( &element[ i ], 0, sizeof( element[ i ] ) );
+
+ element[ i ].offset =
+ resource->urb->iso_frame_desc[ i ].offset;
+ element[ i ].length =
+ resource->urb->iso_frame_desc[ i ].length;
+ }
+ }
+
+ xenidc_create_rbr_request_element_set_lbr
+ (
+ &resource->rbr_request_element[ 1 ],
+ xenidc_vaddress_create_lbr
+ (
+ resource->schedule,
+ sizeof( usbif_isochronous_io_schedule_element )
+ *
+ resource->urb->number_of_packets
+ )
+ );
+
+ xenidc_reserve_and_create_rbr_request_add_element
+ (
+ &resource->rbr_request,
+ &resource->rbr_request_element[ 1 ]
+ );
+ }
+
+ xenidc_rbr_provider_pool_reserve_and_create_rbrs
+ (
+ usbfront_hcd_resource_rbr_provider_pool,
+ &resource->rbr_request
+ );
+
+ return;
+
+ SCHEDULE_TOO_BIG:
+
+ xenidc_callback_complete
+ (
+ xenidc_reserve_and_create_rbr_request_to_create_callback
+ ( &resource->rbr_request ),
+ XENIDC_ERROR_TOO_BIG
+ );
+}
+
+static void usbfront_hcd_resource_create_rbrs_1( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ struct usbfront_hcd_resource * resource = container_of
+ (
+ xenidc_reserve_and_create_rbr_request_create_callback_to
+ ( callback ),
+ struct usbfront_hcd_resource,
+ rbr_request
+ );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ if( xenidc_callback_query_error( callback ) == XENIDC_ERROR_SUCCESS )
+ {
+ usbfront_hcd_resource_handle_stimulus
+ ( resource, usbfront_hcd_resource_stimulus_cs );
+ }
+ else
+ {
+ usbfront_hcd_resource_handle_stimulus
+ ( resource, usbfront_hcd_resource_stimulus_cf );
+ }
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+}
+
+static void usbfront_hcd_resource_abort_create_rbrs
+ ( struct usbfront_hcd_resource * resource )
+{
+ trace();
+
+ xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs
+ (
+ usbfront_hcd_resource_rbr_provider_pool,
+ &resource->rbr_request
+ );
+}
+
+static void usbfront_hcd_resource_set_aborted_error
+ ( struct usbfront_hcd_resource * resource )
+{
+ trace();
+
+ xenidc_callback_set_error
+ (
+ xenidc_reserve_and_create_rbr_request_to_create_callback
+ ( &resource->rbr_request ),
+ XENIDC_ERROR_ABORTED
+ );
+}
+
+static void usbfront_hcd_resource_submit_transaction
+ ( struct usbfront_hcd_resource * resource )
+{
+ trace();
+
+ memset( &resource->io_parameters, 0, sizeof( resource->io_parameters ) );
+ memset( &resource->io_status, 0, sizeof( resource->io_status ) );
+
+ resource->io_parameters.header.header.transaction_type =
+ USBIF_TRANSACTION_TYPE_IO;
+
+ {
+ struct urb * urb = resource->urb;
+
+ resource->io_parameters.header.device_number =
+ usb_pipedevice( urb->pipe );
+
+ resource->io_parameters.header.endpoint =
+ usb_pipeendpoint( urb->pipe );
+
+ resource->io_parameters.header.direction = usb_pipein( urb->pipe ) ?
+ USBIF_IO_TRANSACTION_DIRECTION_IN :
+ USBIF_IO_TRANSACTION_DIRECTION_OUT;
+
+ resource->io_parameters.header.unlink_id = resource->index;
+
+ if( urb->transfer_flags & URB_SHORT_NOT_OK )
+ {
+ resource->io_parameters.header.flags |=
+ USBIF_IO_FLAGS_SHORT_NOT_OK;
+ }
+ if( urb->transfer_flags & URB_ZERO_PACKET )
+ {
+ resource->io_parameters.header.flags |=
+ USBIF_IO_FLAGS_ZERO_PACKET;
+ }
+
+ resource->io_parameters.header.rbr =
+ xenidc_create_rbr_request_element_query_rbr
+ ( &resource->rbr_request_element[ 0 ] );
+
+ if( usb_pipetype( urb->pipe ) == PIPE_CONTROL )
+ {
+ resource->io_parameters.header.io_transaction_type =
+ USBIF_IO_TRANSACTION_TYPE_CONTROL;
+
+ ASSERT( urb->setup_packet != NULL );
+
+ memcpy
+ ( resource->io_parameters.control.setup, urb->setup_packet, 8 );
+ }
+ else if( usb_pipetype( urb->pipe ) == PIPE_BULK )
+ {
+ resource->io_parameters.header.io_transaction_type =
+ USBIF_IO_TRANSACTION_TYPE_BULK;
+ }
+ else if( usb_pipetype( urb->pipe ) == PIPE_INTERRUPT )
+ {
+ resource->io_parameters.header.io_transaction_type =
+ USBIF_IO_TRANSACTION_TYPE_INTERRUPT;
+
+ resource->io_parameters.interrupt.interval = urb->interval;
+ }
+ else if( usb_pipetype( urb->pipe ) == PIPE_ISOCHRONOUS )
+ {
+ resource->io_parameters.header.io_transaction_type =
+ USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS;
+
+ resource->io_parameters.isochronous.interval = urb->interval;
+
+ resource->io_parameters.isochronous.schedule_rbr =
+ xenidc_create_rbr_request_element_query_rbr
+ ( &resource->rbr_request_element[ 1 ] );
+
+ resource->io_parameters.isochronous.packet_count =
+ urb->number_of_packets;
+ }
+ }
+
+ usbfront_device_submit_transaction
+ ( resource->device, &resource->io_transaction );
+}
+
+static void usbfront_hcd_resource_submit_transaction_1
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ struct usbfront_hcd_resource * resource = container_of
+ (
+ xenidc_endpoint_transaction_callback_to( callback ),
+ struct usbfront_hcd_resource,
+ io_transaction
+ );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ usbfront_hcd_resource_handle_stimulus
+ ( resource, usbfront_hcd_resource_stimulus_tc );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+}
+
+static void usbfront_hcd_resource_revoke_rbrs
+ ( struct usbfront_hcd_resource * resource )
+{
+ trace();
+
+ xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs
+ (
+ usbfront_hcd_resource_rbr_provider_pool,
+ &resource->rbr_request
+ );
+}
+
+static void usbfront_hcd_resource_revoke_rbrs_1
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ struct usbfront_hcd_resource * resource = container_of
+ (
+ xenidc_reserve_and_create_rbr_request_revoke_callback_to
+ ( callback ),
+ struct usbfront_hcd_resource,
+ rbr_request
+ );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ usbfront_hcd_resource_handle_stimulus
+ ( resource, usbfront_hcd_resource_stimulus_rc );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+}
+
+static void usbfront_hcd_resource_submit_unlink
+ ( struct usbfront_hcd_resource * resource )
+{
+ trace();
+
+ memset
+ (
+ &resource->unlink_message_body,
+ 0,
+ sizeof( resource->unlink_message_body )
+ );
+
+ resource->unlink_message_body.header.message_type =
+ USBIF_MESSAGE_TYPE_UNLINK;
+
+ resource->unlink_message_body.unlink_id = resource->index;
+
+ usbfront_device_submit_message
+ ( resource->device, &resource->unlink_message );
+}
+
+static void usbfront_hcd_resource_submit_unlink_1( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ struct usbfront_hcd_resource * resource = container_of
+ (
+ xenidc_endpoint_message_callback_to( callback ),
+ struct usbfront_hcd_resource,
+ unlink_message
+ );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ usbfront_hcd_resource_handle_stimulus
+ ( resource, usbfront_hcd_resource_stimulus_uc );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+}
+
+static void usbfront_hcd_resource_complete
+ ( struct usbfront_hcd_resource * resource )
+{
+ trace();
+
+ {
+ int scheduled = xenidc_work_schedule( &resource->complete_1_work );
+
+ ASSERT( scheduled );
+ }
+}
+
+static void usbfront_hcd_resource_complete_1( void * context )
+{
+ trace();
+
+ {
+ struct usbfront_hcd_resource * resource =
+ (struct usbfront_hcd_resource *)context;
+
+ struct urb * urb = resource->urb;
+
+ xenidc_error error;
+
+ if
+ (
+ (
+ (
+ error = xenidc_callback_query_error
+ (
+ xenidc_reserve_and_create_rbr_request_to_create_callback
+ ( &resource->rbr_request )
+ )
+ )
+ ==
+ XENIDC_ERROR_SUCCESS
+ )
+ &&
+ (
+ (
+ error = xenidc_callback_query_error
+ (
+ xenidc_reserve_and_create_rbr_request_to_revoke_callback
+ ( &resource->rbr_request )
+ )
+ )
+ ==
+ XENIDC_ERROR_SUCCESS
+ )
+ )
+ {
+ urb->status = usbif_error_map_to_local
+ (
+ xenidc_endpoint_transaction_query_error
+ ( &resource->io_transaction )
+ );
+ urb->actual_length = resource->io_status.length;
+
+ if( usb_pipetype( urb->pipe ) == PIPE_ISOCHRONOUS )
+ {
+ int i;
+
+ for( i = 0; i < urb->number_of_packets; i++ )
+ {
+ usbif_isochronous_io_schedule_element * schedule =
+ &resource->schedule[ i ];
+
+ urb->iso_frame_desc[ i ].actual_length = schedule->length;
+ urb->iso_frame_desc[ i ].status =
+ usbif_error_map_to_local( schedule->error );
+ }
+
+ /* FIXME isoc error_count ?!? */
+ }
+ }
+ else
+ {
+ urb->status = usbif_error_map_to_local( error );
+ urb->actual_length = 0;
+ }
+
+ {
+ unsigned long flags;
+
+ read_lock_irqsave( &dequeue_lock, flags );
+
+ urb->hcpriv = 0;
+
+ read_unlock_irqrestore( &dequeue_lock, flags );
+ }
+
+ {
+ unsigned long flags;
+
+ local_irq_save( flags );
+
+ usb_hcd_giveback_urb( /* FIXME hcd */ NULL, urb, NULL );
+
+ local_irq_restore( flags );
+ }
+
+ xenidc_callback_success( &resource->callback );
+ }
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,104 @@
+/*****************************************************************************/
+/* A resource used by the usbfront host controller device driver to process */
+/* an URB by translating the URB and optional unlink request into */
+/* a transaction and corresponding optional unlink message for submission to */
+/* the back end. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef USBFRONT_HCD_RESOURCE_H
+#define USBFRONT_HCD_RESOURCE_H
+
+#include <asm/atomic.h>
+#include <linux/usb.h>
+#include <linux/list.h>
+#include "usbfront_device.h"
+
+int usbfront_hcd_resource_class_init( void );
+
+void usbfront_hcd_resource_class_exit( void );
+
+typedef enum
+{
+ usbfront_hcd_resource_state_i,
+ usbfront_hcd_resource_state_i_st,
+ usbfront_hcd_resource_state_i_st_dq,
+ usbfront_hcd_resource_state_i_st_cs,
+ usbfront_hcd_resource_state_i_st_dq_cs,
+ usbfront_hcd_resource_state_i_st_cs_dq,
+ usbfront_hcd_resource_state_i_st_cs_dq_tc
+}
+usbfront_hcd_resource_state;
+
+struct usbfront_hcd_resource
+{
+ xenidc_callback callback;
+ struct usbfront_device * device;
+ int index;
+ usbif_isochronous_io_schedule_element * schedule;
+ spinlock_t lock;
+ usbfront_hcd_resource_state state;
+ struct urb * urb;
+ xenidc_create_rbr_request_element rbr_request_element[ 2 ];
+ xenidc_reserve_and_create_rbr_request rbr_request;
+ xenidc_endpoint_transaction io_transaction;
+ usbif_io_transaction_parameters io_parameters;
+ usbif_io_transaction_status io_status;
+ xenidc_endpoint_message unlink_message;
+ usbif_unlink_message_body unlink_message_body;
+ xenidc_work complete_1_work;
+};
+
+#define USBFRONT_HCD_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK
+
+static inline struct list_head * usbfront_hcd_resource_to_link
+ ( struct usbfront_hcd_resource * resource )
+{
+ return xenidc_callback_to_link( &resource->callback );
+}
+
+static inline struct usbfront_hcd_resource *
+ usbfront_hcd_resource_callback_to( xenidc_callback * callback )
+{
+ return container_of( callback, struct usbfront_hcd_resource, callback );
+}
+
+static inline struct usbfront_device * usbfront_hcd_resource_query_device
+ ( struct usbfront_hcd_resource * resource )
+{
+ return resource->device;
+}
+
+int usbfront_hcd_resource_init
+(
+ struct usbfront_hcd_resource * resource,
+ struct usbfront_device * device,
+ int index,
+ xenidc_callback_function * callback
+);
+
+void usbfront_hcd_resource_exit
+ ( struct usbfront_hcd_resource * resource );
+
+void usbfront_hcd_resource_start_urb
+ ( struct usbfront_hcd_resource * resource, struct urb * urb );
+
+void usbfront_hcd_resource_dequeue_urb( struct urb * urb );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_module.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_module.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,92 @@
+/*****************************************************************************/
+/* Front-end module for Xen USB split driver. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbfront_device.h"
+#include "usbfront_driver.h"
+#include "usbfront_trace.h"
+
+static int usbfront_module_init_or_exit( int exit )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ if( usb_disabled() )
+ {
+ return_value = -ENODEV;
+
+ goto EXIT_NO_USB;
+ }
+
+ if( exit )
+ {
+ goto EXIT;
+ }
+
+ if( ( return_value = usbfront_driver_class_init() ) != 0 )
+ {
+ goto EXIT_NO_DRIVER_CLASS;
+ }
+
+ if( ( return_value = usbfront_device_class_init() ) != 0 )
+ {
+ goto EXIT_NO_DEVICE_CLASS;
+ }
+
+ return 0;
+
+ EXIT:
+
+ usbfront_device_class_exit();
+
+ EXIT_NO_DEVICE_CLASS:
+
+ usbfront_driver_class_exit();
+
+ EXIT_NO_DRIVER_CLASS:
+
+ EXIT_NO_USB:
+
+ return return_value;
+ }
+}
+
+static int __init usbfront_module_init( void )
+{
+ trace();
+
+ return usbfront_module_init_or_exit( 0 );
+}
+
+static void __exit usbfront_module_exit( void )
+{
+ trace();
+
+ (void)usbfront_module_init_or_exit( 1 );
+}
+
+module_init( usbfront_module_init );
+module_exit( usbfront_module_exit );
+
+MODULE_LICENSE( "GPL" );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_sll.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_sll.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,133 @@
+/*****************************************************************************/
+/* A singly linked list implementation */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef USBFRONT_SLL_H
+#define USBFRONT_SLL_H
+
+#include "usbfront_assert.h"
+
+struct usbfront_slk
+{
+ struct usbfront_slk * next;
+};
+
+struct usbfront_sll
+{
+ struct usbfront_slk * first;
+ struct usbfront_slk * last;
+};
+
+static inline void usbfront_slk_init( struct usbfront_slk * slk )
+{
+ slk->next = slk;
+}
+
+static inline int usbfront_slk_is_singular( struct usbfront_slk * slk )
+{
+ return ( slk->next == slk );
+}
+
+static inline void usbfront_sll_init( struct usbfront_sll * sll )
+{
+ sll->first = 0;
+}
+
+static inline int usbfront_sll_is_empty( struct usbfront_sll * sll )
+{
+ return ( sll->first == 0 );
+}
+
+static inline void usbfront_sll_add_last
+ ( struct usbfront_sll * sll, struct usbfront_slk * slk )
+{
+ ASSERT( usbfront_slk_is_singular( slk ) );
+
+ slk->next = 0;
+
+ if( sll->first != 0 )
+ {
+ sll->last->next = slk;
+ }
+ else
+ {
+ sll->first = slk;
+ }
+
+ sll->last = slk;
+}
+
+static inline struct usbfront_slk * usbfront_sll_remove_first
+ ( struct usbfront_sll * sll )
+{
+ struct usbfront_slk * slk = sll->first;
+
+ if( slk != 0 )
+ {
+ sll->first = slk->next;
+
+ slk->next = slk;
+ }
+
+ return slk;
+}
+
+/* Returns 1 if slk removed, 0 otherwise. */
+
+static inline int usbfront_sll_remove_slk
+ ( struct usbfront_sll * sll, struct usbfront_slk * slk )
+{
+ struct usbfront_slk * prev_slk = NULL;
+ struct usbfront_slk * next_slk = sll->first;
+
+ while( next_slk != NULL )
+ {
+ if( next_slk != slk )
+ {
+ prev_slk = next_slk;
+ next_slk = next_slk->next;
+ }
+ else
+ {
+ next_slk = next_slk->next;
+
+ if( prev_slk != NULL )
+ {
+ prev_slk->next = next_slk;
+ }
+ else
+ {
+ sll->first = next_slk;
+ }
+
+ if( next_slk == NULL )
+ {
+ sll->last = prev_slk;
+ }
+
+ slk->next = slk;
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_trace.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_trace.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,53 @@
+/*****************************************************************************/
+/* Simple trace macros */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef USBFRONT_TRACE_H
+#define USBFRONT_TRACE_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_XEN_USBDEV_FRONTEND_TRACE
+
+#define trace0( format ) \
+printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__ )
+
+#define trace1( format, a0 ) \
+printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__, a0 )
+
+#define trace2( format, a0, a1 ) \
+printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__, a0, a1 )
+
+#define trace3( format, a0, a1, a2 ) \
+printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__, a0, a1, a2 )
+
+#define trace() trace0( "" )
+
+#else
+
+#define trace0( format )
+#define trace1( format,a0 )
+#define trace2( format,a0, a1 )
+#define trace3( format,a0, a1, a2 )
+#define trace()
+
+#endif
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Sun Oct 30 16:03:34 2005
@@ -0,0 +1,17 @@
+obj-y += xenidc.o
+
+xenidc-objs =
+xenidc-objs += xenidc_callback.o
+xenidc-objs += xenidc_concatenate.o
+xenidc-objs += xenidc_endpoint.o
+xenidc-objs += xenidc_gateway.o
+xenidc-objs += xenidc_gateway_initiator_resource.o
+xenidc-objs += xenidc_gateway_target_resource.o
+xenidc-objs += xenidc_gnttab_channel.o
+xenidc-objs += xenidc_local_buffer_reference.o
+xenidc-objs += xenidc_rbr_mapper_pool.o
+xenidc-objs += xenidc_rbr_provider_pool.o
+xenidc-objs += xenidc_vaddress.o
+xenidc-objs += xenidc_work.o
+xenidc-objs += xenidc_wrapping.o
+xenidc-objs += xenidc_xbgt_channel.o
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_callback.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_callback.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,61 @@
+/*****************************************************************************/
+/* A callback object for use in scheduling completion of asynchronous */
+/* requests. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#include "xenidc_callback.h"
+#include <linux/module.h>
+
+void xenidc_callback_serialiser_function( void * context )
+{
+ xenidc_callback_serialiser * serialiser =
+ (xenidc_callback_serialiser *)context;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &serialiser->lock, flags );
+
+ while
+ (
+ ( !list_empty( &serialiser->list ) )
+ &&
+ ( !serialiser->running )
+ )
+ {
+ xenidc_callback * callback =
+ xenidc_callback_link_to( serialiser->list.next );
+
+ list_del_init( xenidc_callback_to_link( callback ) );
+
+ serialiser->running = 1;
+
+ spin_unlock_irqrestore( &serialiser->lock, flags );
+
+ xenidc_callback_complete_synchronously( callback );
+
+ spin_lock_irqsave( &serialiser->lock, flags );
+
+ serialiser->running = 0;
+ }
+
+ spin_unlock_irqrestore( &serialiser->lock, flags );
+}
+
+EXPORT_SYMBOL( xenidc_callback_serialiser_function );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_channel_ring.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_channel_ring.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,44 @@
+/*****************************************************************************/
+/* Xen inter-domain communication channel ring structure definitions. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef _XENIDC_CHANNEL_RING_H
+#define _XENIDC_CHANNEL_RING_H
+
+#include <asm-xen/xenidc.h>
+
+typedef struct xenidc_channel_ring_header_struct xenidc_channel_ring_header;
+
+struct xenidc_channel_ring_header_struct
+{
+ u16 this_ring_producer_offset;
+ u16 other_ring_consumer_offset;
+};
+
+typedef struct xenidc_channel_ring_element_header_struct
+ xenidc_channel_ring_element_header;
+
+struct xenidc_channel_ring_element_header_struct
+{
+ u16 length;
+ u8 reserved1[6];
+};
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_concatenate.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_concatenate.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,140 @@
+/*****************************************************************************/
+/* Xen inter-domain communication concatenate local buffer reference type. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#include <asm-xen/xenidc_concatenate.h>
+#include <linux/module.h>
+#include "xenidc_trace.h"
+
+static xenidc_buffer_type xenidc_concatenate_type;
+
+static xenidc_local_buffer_reference xenidc_concatenate_resolve
+(
+ xenidc_buffer_virtual_class * class,
+ xenidc_local_buffer_reference * lbr
+)
+{
+ trace();
+
+ {
+ xenidc_local_buffer_reference resolved_lbr;
+
+ xenidc_concatenate_base * base = (xenidc_concatenate_base *)lbr->base;
+
+ if( lbr->byte_offset < base->head->byte_count )
+ {
+ resolved_lbr = *base->head;
+
+ xenidc_local_buffer_reference_subrange
+ ( &resolved_lbr, lbr->byte_offset, lbr->byte_count );
+ }
+ else
+ {
+ resolved_lbr = *base->tail;
+
+ xenidc_local_buffer_reference_subrange
+ (
+ &resolved_lbr,
+ lbr->byte_offset - base->head->byte_count,
+ lbr->byte_count
+ );
+ }
+
+ return resolved_lbr;
+ }
+}
+
+static void xenidc_concatenate_init( void )
+{
+ trace();
+
+ {
+ static DEFINE_RWLOCK( xenidc_concatenate_lock );
+
+ unsigned long flags;
+
+ read_lock_irqsave( &xenidc_concatenate_lock, flags );
+
+ {
+ static int initialised = 0;
+
+ if( !initialised )
+ {
+ read_unlock_irqrestore
+ ( &xenidc_concatenate_lock, flags );
+
+ write_lock_irqsave
+ ( &xenidc_concatenate_lock, flags );
+
+ if( !initialised )
+ {
+ static xenidc_buffer_virtual_class
+ xenidc_concatenate_virtual_class;
+
+ xenidc_concatenate_type =
+ xenidc_local_buffer_reference_register_buffer_virtual_class
+ (
+ &xenidc_concatenate_virtual_class,
+ xenidc_concatenate_resolve,
+ NULL
+ );
+
+ initialised = 1;
+ }
+
+ write_unlock_irqrestore
+ ( &xenidc_concatenate_lock, flags );
+
+ read_lock_irqsave
+ ( &xenidc_concatenate_lock, flags );
+ }
+ }
+
+ read_unlock_irqrestore( &xenidc_concatenate_lock, flags );
+ }
+}
+
+xenidc_local_buffer_reference xenidc_concatenate_create_lbr
+(
+ xenidc_concatenate_base * base,
+ xenidc_local_buffer_reference * head,
+ xenidc_local_buffer_reference * tail
+)
+{
+ trace();
+
+ xenidc_concatenate_init();
+
+ base->head = head;
+ base->tail = tail;
+
+ {
+ xenidc_local_buffer_reference lbr;
+
+ lbr.type = xenidc_concatenate_type;
+ lbr.base = base;
+ lbr.byte_offset = 0;
+ lbr.byte_count = head->byte_count + tail->byte_count;
+
+ return lbr;
+ }
+}
+
+EXPORT_SYMBOL( xenidc_concatenate_create_lbr );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,176 @@
+/*****************************************************************************/
+/* Xen inter-domain communication API, endpoint object. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#include <asm-xen/xenidc_endpoint.h>
+#include <linux/module.h>
+#include "xenidc_trace.h"
+
+int xenidc_endpoint_init
+(
+ xenidc_endpoint * endpoint,
+
+ void ( * connect )( xenidc_endpoint * endpoint ),
+ void ( * handle_message )
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_message * message ),
+ void ( * handle_transaction )
+ (
+ xenidc_endpoint * endpoint,
+ xenidc_endpoint_transaction * transaction
+ ),
+ void ( * disconnect )
+ ( xenidc_endpoint * endpoint, xenidc_callback * callback ),
+ u32 initiator_quota,
+ xenidc_buffer_byte_count initiator_maximum_byte_count,
+ u32 target_quota,
+ xenidc_buffer_byte_count target_maximum_byte_count
+)
+{
+ trace();
+
+ {
+ int return_value = xenidc_xbgt_channel_init( &endpoint->channel );
+
+ if( return_value != 0 )
+ {
+ goto EXIT_NO_CHANNEL;
+ }
+
+ return_value = xenidc_gateway_init
+ (
+ &endpoint->gateway,
+ xenidc_xbgt_channel_to_channel( &endpoint->channel ),
+ (void (*)( xenidc_gateway * ))connect,
+ (void (*)( xenidc_gateway *, xenidc_endpoint_message* ))
+ handle_message,
+ (void (*)( xenidc_gateway *, xenidc_endpoint_transaction *))
+ handle_transaction,
+ (void (*)( xenidc_gateway *, xenidc_callback *))disconnect,
+ initiator_quota,
+ initiator_maximum_byte_count,
+ target_quota,
+ target_maximum_byte_count
+ );
+
+ if( return_value != 0 )
+ {
+ goto EXIT_NO_GATEWAY;
+ }
+
+ return 0;
+
+ EXIT_NO_GATEWAY:
+
+ xenidc_xbgt_channel_exit( &endpoint->channel );
+
+ EXIT_NO_CHANNEL:
+
+ return return_value;
+ }
+}
+
+void xenidc_endpoint_create
+ ( xenidc_endpoint * endpoint, xenidc_address address )
+{
+ trace();
+
+ xenidc_xbgt_channel_connect
+ (
+ &endpoint->channel,
+ xenidc_address_query_local_domain( &address ),
+ xenidc_address_query_remote_domain( &address ),
+ xenidc_address_query_remote_domain_id( &address )
+ );
+}
+
+void xenidc_endpoint_submit_message
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_message * message )
+{
+ trace();
+
+ xenidc_gateway_submit_message( &endpoint->gateway, message );
+}
+
+void xenidc_endpoint_submit_transaction
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_transaction * transaction )
+{
+ trace();
+
+ xenidc_gateway_submit_transaction( &endpoint->gateway, transaction );
+}
+
+typedef struct xenidc_endpoint_callback_struct xenidc_endpoint_callback;
+
+struct xenidc_endpoint_callback_struct
+{
+ xenidc_callback callback;
+ int destroyed;
+};
+
+static void xenidc_endpoint_destroy_1( xenidc_callback * callback );
+
+void xenidc_endpoint_destroy( xenidc_endpoint * endpoint )
+{
+ trace();
+
+ {
+ xenidc_endpoint_callback endpoint_callback;
+
+ xenidc_callback_init
+ ( &endpoint_callback.callback, xenidc_endpoint_destroy_1 );
+
+ endpoint_callback.destroyed = 0;
+
+ xenidc_xbgt_channel_disconnect
+ ( &endpoint->channel, &endpoint_callback.callback );
+
+ xenidc_work_until( endpoint_callback.destroyed );
+ }
+}
+
+static void xenidc_endpoint_destroy_1( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_endpoint_callback * endpoint_callback =
+ container_of( callback, xenidc_endpoint_callback, callback );
+
+ endpoint_callback->destroyed = 1;
+
+ xenidc_work_wake_up();
+ }
+}
+
+void xenidc_endpoint_exit( xenidc_endpoint * endpoint )
+{
+ trace();
+
+ xenidc_gateway_exit( &endpoint->gateway );
+
+ xenidc_xbgt_channel_exit( &endpoint->channel );
+}
+
+EXPORT_SYMBOL( xenidc_endpoint_init );
+EXPORT_SYMBOL( xenidc_endpoint_create );
+EXPORT_SYMBOL( xenidc_endpoint_submit_message );
+EXPORT_SYMBOL( xenidc_endpoint_submit_transaction );
+EXPORT_SYMBOL( xenidc_endpoint_destroy );
+EXPORT_SYMBOL( xenidc_endpoint_exit );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,1344 @@
+#include <asm-xen/xenidc_gateway.h>
+#include <asm-xen/xenidc_vaddress.h>
+#include <linux/vmalloc.h>
+#include "xenidc_gateway_initiator_resource.h"
+#include "xenidc_gateway_target_resource.h"
+#include "xenidc_trace.h"
+
+typedef enum
+{
+ xenidc_gateway_stimulus_mt, /* Message or transaction queued. */
+ xenidc_gateway_stimulus_cc, /* Channel connect. */
+ xenidc_gateway_stimulus_cm, /* Channel message. */
+ xenidc_gateway_stimulus_cd, /* Channel disconnect. */
+ xenidc_gateway_stimulus_km, /* Kick messages and transactions completed. */
+ xenidc_gateway_stimulus_kc, /* Kick channel messages completed. */
+ xenidc_gateway_stimulus_ic, /* Initiator resource completed. */
+ xenidc_gateway_stimulus_ii, /* Initiator resources idle. */
+ xenidc_gateway_stimulus_tc, /* Target resource completed. */
+ xenidc_gateway_stimulus_ti, /* Target resources idle. */
+ xenidc_gateway_stimulus_lc, /* Client connect completed. */
+ xenidc_gateway_stimulus_lg, /* Client disconnect called. */
+ xenidc_gateway_stimulus_ld, /* Client disconnect completed. */
+}
+xenidc_gateway_stimulus;
+
+static void xenidc_gateway_handle_stimulus
+ ( xenidc_gateway * gateway, xenidc_gateway_stimulus stimulus );
+
+static void xenidc_gateway_channel_connect( void * context );
+
+static void xenidc_gateway_handle_channel_message
+ ( void * context, xenidc_channel_message * message );
+
+static void xenidc_gateway_channel_disconnect
+ ( void * context, xenidc_callback * callback );
+
+static int xenidc_gateway_init_or_exit( xenidc_gateway * gateway, int exit );
+
+int xenidc_gateway_init
+(
+ xenidc_gateway * gateway,
+ xenidc_channel * channel,
+ void ( * connect )( xenidc_gateway * gateway ),
+ void ( * handle_message )
+ ( xenidc_gateway * gateway, xenidc_gateway_message * message ),
+ void ( * handle_transaction )
+ ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction ),
+ void ( * disconnect )
+ ( xenidc_gateway * gateway, xenidc_callback * callback ),
+ u32 initiator_quota,
+ xenidc_buffer_byte_count initiator_maximum_byte_count,
+ u32 target_quota,
+ xenidc_buffer_byte_count target_maximum_byte_count
+)
+{
+ trace();
+
+ gateway->channel = channel;
+ gateway->connect = connect;
+ gateway->handle_message = handle_message;
+ gateway->handle_transaction = handle_transaction;
+ gateway->disconnect = disconnect;
+
+ gateway->initiator_quota = initiator_quota;
+ gateway->target_quota = target_quota;
+ gateway->target_maximum_byte_count = target_maximum_byte_count;
+
+ xenidc_channel_install_client
+ (
+ channel,
+ gateway,
+ xenidc_gateway_channel_connect,
+ xenidc_gateway_handle_channel_message,
+ xenidc_gateway_channel_disconnect
+ );
+
+ return xenidc_gateway_init_or_exit( gateway, 0 );
+}
+
+static void xenidc_gateway_kick_messages_and_transactions_1( void * data );
+
+static void xenidc_gateway_kick_messages_and_transactions_2
+ ( xenidc_callback * callback );
+
+static void xenidc_gateway_kick_channel_messages_1( void * data );
+
+static void xenidc_gateway_kick_channel_messages_2
+ ( xenidc_callback * callback );
+
+static void xenidc_gateway_connect_client_1( void * data );
+
+static void xenidc_gateway_disconnect_client_1( void * data );
+
+static void xenidc_gateway_disconnect_client_2( xenidc_callback * callback );
+
+static int xenidc_gateway_init_or_exit( xenidc_gateway * gateway, int exit )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ if( exit )
+ {
+ goto EXIT;
+ }
+
+ INIT_LIST_HEAD( &gateway->initiator_resource_list );
+
+ if( gateway->initiator_quota != 0 )
+ {
+ gateway->initiator_resources = vmalloc
+ (
+ sizeof( xenidc_gateway_initiator_resource )
+ *
+ gateway->initiator_quota
+ );
+
+ if( gateway->initiator_resources == NULL )
+ {
+ trace0( "failed to allocate initiator resources" );
+
+ return_value = -ENOMEM;
+
+ goto EXIT_NO_INITIATOR_RESOURCES;
+ }
+
+ {
+ u32 i;
+
+ for( i = 0; i < gateway->initiator_quota; i++ )
+ {
+ xenidc_gateway_initiator_resource * resource =
+ &gateway->initiator_resources[ i ];
+
+ xenidc_gateway_initiator_resource_init
+ (
+ resource,
+ gateway,
+ xenidc_gateway_kick_messages_and_transactions_2,
+ i
+ );
+
+ list_add_tail
+ (
+ xenidc_gateway_initiator_resource_to_link( resource ),
+ &gateway->initiator_resource_list
+ );
+ }
+ }
+ }
+
+ INIT_LIST_HEAD( &gateway->target_resource_list );
+
+ if( gateway->target_quota != 0 )
+ {
+ gateway->target_resources = vmalloc
+ (
+ (
+ sizeof( xenidc_gateway_target_resource )
+ *
+ gateway->target_quota
+ )
+ +
+ (
+ gateway->target_maximum_byte_count
+ *
+ gateway->target_quota
+ )
+ );
+
+ if( gateway->target_resources == NULL )
+ {
+ trace0( "failed to allocate target resources" );
+
+ return_value = -ENOMEM;
+
+ goto EXIT_NO_TARGET_RESOURCES;
+ }
+
+ {
+ xenidc_local_buffer_reference buffer_area =
+ xenidc_vaddress_create_lbr
+ (
+ &gateway->target_resources
+ [ gateway->target_quota ],
+ gateway->target_maximum_byte_count *
+ gateway->target_quota
+ );
+
+ u32 i;
+
+ for( i = 0; i < gateway->target_quota; i++ )
+ {
+ xenidc_gateway_target_resource * resource =
+ &gateway->target_resources[ i ];
+
+ xenidc_local_buffer_reference buffer = buffer_area;
+
+ xenidc_local_buffer_reference_truncate
+ (
+ &buffer,
+ gateway->target_maximum_byte_count
+ );
+
+ xenidc_gateway_target_resource_init
+ (
+ resource,
+ gateway,
+ xenidc_gateway_kick_channel_messages_2,
+ buffer
+ );
+
+ list_add_tail
+ (
+ xenidc_gateway_target_resource_to_link( resource ),
+ &gateway->target_resource_list
+ );
+
+ xenidc_local_buffer_reference_advance
+ (
+ &buffer_area,
+ gateway->target_maximum_byte_count
+ );
+ }
+ }
+ }
+
+ spin_lock_init( &gateway->lock );
+
+ gateway->state = xenidc_gateway_state_i;
+
+ INIT_LIST_HEAD( &gateway->message_and_transaction_list );
+ INIT_LIST_HEAD( &gateway->channel_message_list );
+
+ xenidc_work_init
+ (
+ &gateway->kick_messages_and_transactions_1_work,
+ xenidc_gateway_kick_messages_and_transactions_1,
+ gateway
+ );
+
+ xenidc_work_init
+ (
+ &gateway->kick_channel_messages_1_work,
+ xenidc_gateway_kick_channel_messages_1,
+ gateway
+ );
+
+ xenidc_work_init
+ (
+ &gateway->connect_client_1_work,
+ xenidc_gateway_connect_client_1,
+ gateway
+ );
+
+ xenidc_work_init
+ (
+ &gateway->disconnect_client_1_work,
+ xenidc_gateway_disconnect_client_1,
+ gateway
+ );
+
+ xenidc_callback_init
+ (
+ &gateway->disconnect_client_2_callback,
+ xenidc_gateway_disconnect_client_2
+ );
+
+ gateway->kick_messages_and_transactions_out = 0;
+ gateway->kick_channel_messages_out = 0;
+ gateway->initiator_resources_out = 0;
+ gateway->target_resources_out = 0;
+
+ return 0;
+
+ EXIT:
+
+ if( gateway->target_quota != 0 )
+ {
+ vfree( gateway->target_resources );
+ }
+
+ EXIT_NO_TARGET_RESOURCES:
+
+ if( gateway->initiator_quota != 0 )
+ {
+ vfree( gateway->initiator_resources );
+ }
+
+ EXIT_NO_INITIATOR_RESOURCES:
+
+ return return_value;
+ }
+}
+
+void xenidc_gateway_submit_message
+ ( xenidc_gateway * gateway, xenidc_gateway_message * message )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_gateway_message_to_link( message ),
+ &gateway->message_and_transaction_list
+ );
+
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_mt );
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+ }
+}
+
+void xenidc_gateway_submit_transaction
+ ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_gateway_transaction_to_link( transaction ),
+ &gateway->message_and_transaction_list
+ );
+
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_mt );
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+ }
+}
+
+void xenidc_gateway_exit( xenidc_gateway * gateway )
+{
+ trace();
+
+ (void)xenidc_gateway_init_or_exit( gateway, 1 );
+}
+
+static void xenidc_gateway_channel_connect( void * context )
+{
+ trace();
+
+ {
+ xenidc_gateway * gateway = (xenidc_gateway *)context;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_cc );
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+ }
+}
+
+static void xenidc_gateway_handle_channel_message
+ ( void * context, xenidc_channel_message * message )
+{
+ trace();
+
+ {
+ xenidc_gateway * gateway = (xenidc_gateway *)context;
+
+ xenidc_gateway_ring_element_header header;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ ( &message->message_lbr, &header, sizeof( header ) )
+ !=
+ sizeof( header )
+ )
+ {
+ goto PROTOCOL_ERROR;
+ }
+
+ if( header.type == XENIDC_GATEWAY_RING_ELEMENT_TYPE_STATUS )
+ {
+ xenidc_local_buffer_reference status_lbr = message->message_lbr;
+
+ xenidc_gateway_status_ring_element status_element;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ ( &status_lbr, &status_element, sizeof( status_element ) )
+ !=
+ sizeof( status_element )
+ )
+ {
+ goto PROTOCOL_ERROR;
+ }
+
+ xenidc_local_buffer_reference_advance
+ ( &status_lbr, sizeof( status_element ) );
+
+ if( status_element.id >= gateway->initiator_quota )
+ {
+ goto PROTOCOL_ERROR;
+ }
+
+ {
+ xenidc_gateway_initiator_resource * resource =
+ &gateway->initiator_resources[ status_element.id ];
+
+ if
+ (
+ xenidc_gateway_initiator_resource_handle_status
+ ( resource, status_element.error, status_lbr )
+ !=
+ 0
+ )
+ {
+ goto PROTOCOL_ERROR;
+ }
+ }
+
+ xenidc_callback_success
+ ( xenidc_channel_message_to_callback( message ) );
+ }
+ else
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_channel_message_to_link( message ),
+ &gateway->channel_message_list
+ );
+
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_cm );
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+ }
+ }
+
+ return;
+
+ PROTOCOL_ERROR:
+
+ xenidc_callback_complete
+ (
+ xenidc_channel_message_to_callback( message ),
+ XENIDC_ERROR_INVALID_PROTOCOL
+ );
+}
+
+static void xenidc_gateway_channel_disconnect
+ ( void * context, xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_gateway * gateway = (xenidc_gateway *)context;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ gateway->channel_disconnect_callback = callback;
+
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_cd );
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+ }
+}
+
+void xenidc_gateway_submit_channel_message
+ ( xenidc_gateway * gateway, xenidc_channel_message * message )
+{
+ trace();
+
+ xenidc_channel_submit_message( gateway->channel, message );
+}
+
+void xenidc_gateway_submit_message_to_client
+ ( xenidc_gateway * gateway, xenidc_gateway_message * message )
+{
+ trace();
+
+ gateway->handle_message( gateway, message );
+}
+
+void xenidc_gateway_submit_transaction_to_client
+ ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction )
+{
+ trace();
+
+ gateway->handle_transaction( gateway, transaction );
+}
+
+static void xenidc_gateway_invalid_stimulus
+ ( xenidc_gateway * gateway, xenidc_gateway_stimulus stimulus );
+
+static void xenidc_gateway_kick_messages_and_transactions
+ ( xenidc_gateway * gateway );
+
+static void xenidc_gateway_fail_out_messages_and_transactions
+ ( xenidc_gateway * gateway );
+
+static void xenidc_gateway_kick_channel_messages( xenidc_gateway * gateway );
+
+static void xenidc_gateway_complete_channel_messages
+ ( xenidc_gateway * gateway );
+
+static void xenidc_gateway_connect_client( xenidc_gateway * gateway );
+
+static void xenidc_gateway_disconnect_client( xenidc_gateway * gateway );
+
+static void xenidc_gateway_abort_initiator_resources
+ ( xenidc_gateway * gateway );
+
+static void xenidc_gateway_test_initiator_resources
+ ( xenidc_gateway * gateway );
+
+static void xenidc_gateway_test_target_resources( xenidc_gateway * gateway );
+
+static void xenidc_gateway_complete_channel_disconnect
+ ( xenidc_gateway * gateway );
+
+static void xenidc_gateway_handle_stimulus
+ ( xenidc_gateway * gateway, xenidc_gateway_stimulus stimulus )
+{
+ trace3
+ (
+ "gateway %p in state %d received stimulus %d",
+ gateway,
+ gateway->state,
+ stimulus
+ );
+
+ switch( gateway->state )
+ {
+ case xenidc_gateway_state_i:
+ /* Channel disconnected. */
+ /* Client disconnected. */
+ /* No messages or transactions queued. */
+ /* No channel messages queued. */
+ /* Initiator resources idle. */
+ /* Target resources idle. */
+ /* Not kicking m/t. */
+ /* Not kicking cm. */
+ switch( stimulus )
+ {
+ case xenidc_gateway_stimulus_cc:
+ gateway->state = xenidc_gateway_state_i_cc;
+ xenidc_gateway_connect_client( gateway );
+ break;
+ default:
+ xenidc_gateway_invalid_stimulus( gateway, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_state_i_cc:
+ /* Channel connected. */
+ /* Client connecting. */
+ /* Maybe messages or transactions queued. */
+ /* Maybe channel messages queued. */
+ /* Initiator resources idle. */
+ /* Target resources idle. */
+ /* Not kicking m/t. */
+ /* Not kicking cm. */
+ switch( stimulus )
+ {
+ case xenidc_gateway_stimulus_mt:
+ case xenidc_gateway_stimulus_cm:
+ break;
+ case xenidc_gateway_stimulus_cd:
+ gateway->state = xenidc_gateway_state_i_cc_cd;
+ xenidc_gateway_complete_channel_messages( gateway );
+ break;
+ case xenidc_gateway_stimulus_lc:
+ gateway->state = xenidc_gateway_state_i_cc_lc;
+ xenidc_gateway_kick_messages_and_transactions( gateway );
+ xenidc_gateway_kick_channel_messages( gateway );
+ break;
+ default:
+ xenidc_gateway_invalid_stimulus( gateway, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_state_i_cc_cd:
+ /* Channel disconnecting. */
+ /* Client connecting. */
+ /* Maybe messages or transactions queued. */
+ /* No channel messages queued. */
+ /* Initiator resources idle. */
+ /* Target resources idle. */
+ /* Not kicking m/t. */
+ /* Not kicking cm. */
+ switch( stimulus )
+ {
+ case xenidc_gateway_stimulus_mt:
+ break;
+ case xenidc_gateway_stimulus_lc:
+ gateway->state = xenidc_gateway_state_i_cc_cd_lc;
+ xenidc_gateway_disconnect_client( gateway );
+ break;
+ default:
+ xenidc_gateway_invalid_stimulus( gateway, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_state_i_cc_lc:
+ /* Channel connected. */
+ /* Client connected. */
+ /* Maybe messages or transactions queued. */
+ /* Maybe channel messages queued. */
+ /* Maybe initiator resources busy. */
+ /* Maybe target resources busy. */
+ /* Maybe kicking m/t. */
+ /* Maybe kicking cm. */
+ switch( stimulus )
+ {
+ case xenidc_gateway_stimulus_mt:
+ xenidc_gateway_kick_messages_and_transactions( gateway );
+ break;
+ case xenidc_gateway_stimulus_cm:
+ xenidc_gateway_kick_channel_messages( gateway );
+ break;
+ case xenidc_gateway_stimulus_cd:
+ gateway->state = xenidc_gateway_state_i_cc_lc_cd;
+ xenidc_gateway_complete_channel_messages( gateway );
+ xenidc_gateway_kick_messages_and_transactions( gateway );
+ xenidc_gateway_kick_channel_messages( gateway );
+ break;
+ case xenidc_gateway_stimulus_km:
+ case xenidc_gateway_stimulus_kc:
+ break;
+ case xenidc_gateway_stimulus_ic:
+ case xenidc_gateway_stimulus_ii:
+ xenidc_gateway_kick_messages_and_transactions( gateway );
+ break;
+ case xenidc_gateway_stimulus_tc:
+ case xenidc_gateway_stimulus_ti:
+ xenidc_gateway_kick_channel_messages( gateway );
+ break;
+ default:
+ xenidc_gateway_invalid_stimulus( gateway, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_state_i_cc_lc_cd:
+ /* Channel disconnecting. */
+ /* Client connected. */
+ /* Maybe messages or transactions queued. */
+ /* No channel messages queued. */
+ /* Maybe initiator resources busy. */
+ /* Maybe target resources busy. */
+ /* Kicking m/t. */
+ /* Kicking cm. */
+ switch( stimulus )
+ {
+ case xenidc_gateway_stimulus_mt:
+ break;
+ case xenidc_gateway_stimulus_km:
+ case xenidc_gateway_stimulus_kc:
+ gateway->state = xenidc_gateway_state_i_cc_lc_cd_km;
+ break;
+ case xenidc_gateway_stimulus_ic:
+ case xenidc_gateway_stimulus_ii:
+ case xenidc_gateway_stimulus_tc:
+ case xenidc_gateway_stimulus_ti:
+ break;
+ default:
+ xenidc_gateway_invalid_stimulus( gateway, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_state_i_cc_lc_cd_km:
+ /* Channel disconnecting. */
+ /* Client connected. */
+ /* Maybe messages or transactions queued. */
+ /* No channel messages queued. */
+ /* Maybe initiator resources busy. */
+ /* Maybe target resources busy. */
+ /* One of kicking m/t or cm. */
+ switch( stimulus )
+ {
+ case xenidc_gateway_stimulus_mt:
+ break;
+ case xenidc_gateway_stimulus_km:
+ case xenidc_gateway_stimulus_kc:
+ gateway->state = xenidc_gateway_state_i_cc_cd_lc;
+ xenidc_gateway_disconnect_client( gateway );
+ break;
+ case xenidc_gateway_stimulus_ic:
+ case xenidc_gateway_stimulus_ii:
+ case xenidc_gateway_stimulus_tc:
+ case xenidc_gateway_stimulus_ti:
+ break;
+ default:
+ xenidc_gateway_invalid_stimulus( gateway, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_state_i_cc_cd_lc:
+ /* Channel disconnecting. */
+ /* Calling client disconnect. */
+ /* Maybe messages or transactions queued. */
+ /* No channel messages queued. */
+ /* Maybe initiator resources busy. */
+ /* Maybe target resources busy. */
+ /* Not kicking m/t. */
+ /* Not kicking cm. */
+ switch( stimulus )
+ {
+ case xenidc_gateway_stimulus_mt:
+ break;
+ case xenidc_gateway_stimulus_ic:
+ case xenidc_gateway_stimulus_ii:
+ case xenidc_gateway_stimulus_tc:
+ case xenidc_gateway_stimulus_ti:
+ break;
+ case xenidc_gateway_stimulus_lg:
+ gateway->state = xenidc_gateway_state_i_cc_cd_lc_lg;
+ xenidc_gateway_fail_out_messages_and_transactions( gateway );
+ xenidc_gateway_abort_initiator_resources( gateway );
+ break;
+ case xenidc_gateway_stimulus_ld:
+ gateway->state = xenidc_gateway_state_i_cc_cd_lc_ld;
+ break;
+ default:
+ xenidc_gateway_invalid_stimulus( gateway, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_state_i_cc_cd_lc_lg:
+ /* Channel disconnecting. */
+ /* Client disconnecting. */
+ /* No messages or transactions queued. */
+ /* No channel messages queued. */
+ /* Maybe initiator resources busy. */
+ /* Maybe target resources busy. */
+ /* Not kicking m/t. */
+ /* Not kicking cm. */
+ switch( stimulus )
+ {
+ case xenidc_gateway_stimulus_mt:
+ break;
+ case xenidc_gateway_stimulus_ic:
+ case xenidc_gateway_stimulus_ii:
+ case xenidc_gateway_stimulus_tc:
+ case xenidc_gateway_stimulus_ti:
+ break;
+ case xenidc_gateway_stimulus_ld:
+ gateway->state = xenidc_gateway_state_i_cc_cd_lc_lg_ld;
+ xenidc_gateway_test_target_resources( gateway );
+ break;
+ default:
+ xenidc_gateway_invalid_stimulus( gateway, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_state_i_cc_cd_lc_ld:
+ /* Channel disconnecting. */
+ /* Client disconnected but call still in progress. */
+ /* No messages or transactions queued. */
+ /* No channel messages queued. */
+ /* Maybe initiator resources busy. */
+ /* Maybe target resources busy. */
+ /* Not kicking m/t. */
+ /* Not kicking cm. */
+ switch( stimulus )
+ {
+ case xenidc_gateway_stimulus_ic:
+ case xenidc_gateway_stimulus_ii:
+ case xenidc_gateway_stimulus_tc:
+ case xenidc_gateway_stimulus_ti:
+ break;
+ case xenidc_gateway_stimulus_lg:
+ gateway->state = xenidc_gateway_state_i_cc_cd_lc_lg_ld;
+ xenidc_gateway_test_target_resources( gateway );
+ break;
+ default:
+ xenidc_gateway_invalid_stimulus( gateway, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_state_i_cc_cd_lc_lg_ld:
+ /* Channel disconnecting. */
+ /* Client disconnected. */
+ /* No messages or transactions queued. */
+ /* No channel messages queued. */
+ /* Maybe initiator resources busy. */
+ /* Test target resources or target resources busy. */
+ /* Not kicking m/t. */
+ /* Not kicking cm. */
+ switch( stimulus )
+ {
+ case xenidc_gateway_stimulus_ic:
+ case xenidc_gateway_stimulus_ii:
+ case xenidc_gateway_stimulus_tc:
+ break;
+ case xenidc_gateway_stimulus_ti:
+ gateway->state = xenidc_gateway_state_i_cc_cd_lc_lg_ld_ti;
+ xenidc_gateway_test_initiator_resources( gateway );
+ break;
+ default:
+ xenidc_gateway_invalid_stimulus( gateway, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_state_i_cc_cd_lc_lg_ld_ti:
+ /* Channel disconnecting. */
+ /* Client disconnected. */
+ /* No messages or transactions queued. */
+ /* No channel messages queued. */
+ /* Test initiator resources or initiator resources busy. */
+ /* Target resources idle. */
+ /* Not kicking m/t. */
+ /* Not kicking cm. */
+ switch( stimulus )
+ {
+ case xenidc_gateway_stimulus_ic:
+ break;
+ case xenidc_gateway_stimulus_ii:
+ gateway->state = xenidc_gateway_state_i;
+ xenidc_gateway_complete_channel_disconnect( gateway );
+ break;
+ default:
+ xenidc_gateway_invalid_stimulus( gateway, stimulus );
+ break;
+ }
+ break;
+ default:
+ xenidc_gateway_invalid_stimulus( gateway, stimulus );
+ break;
+ }
+}
+
+static void xenidc_gateway_invalid_stimulus
+ ( xenidc_gateway * gateway, xenidc_gateway_stimulus stimulus )
+{
+ trace();
+
+ printk
+ (
+ KERN_ERR "xenidc: gateway %p in state %d"
+ "received invalid stimulus %d",
+ gateway,
+ gateway->state,
+ stimulus
+ );
+}
+
+static void xenidc_gateway_kick_messages_and_transactions
+ ( xenidc_gateway * gateway )
+{
+ trace();
+
+ if( !gateway->kick_messages_and_transactions_out )
+ {
+ gateway->kick_messages_and_transactions_out = 1;
+
+ (void)xenidc_work_schedule
+ ( &gateway->kick_messages_and_transactions_1_work );
+ }
+}
+
+static void xenidc_gateway_kick_messages_and_transactions_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_gateway * gateway = (xenidc_gateway *)data;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ gateway->kick_messages_and_transactions_out = 0;
+
+ while
+ (
+ ( !list_empty( &gateway->message_and_transaction_list ) )
+ &&
+ ( !list_empty( &gateway->initiator_resource_list ) )
+ )
+ {
+ xenidc_gateway_message_and_transaction_header * header = list_entry
+ (
+ gateway->message_and_transaction_list.next,
+ xenidc_gateway_message_and_transaction_header,
+ XENIDC_GATEWAY_MESSAGE_AND_TRANSACTION_HEADER_LINK
+ );
+
+ xenidc_gateway_initiator_resource * resource = list_entry
+ (
+ gateway->initiator_resource_list.next,
+ xenidc_gateway_initiator_resource,
+ XENIDC_GATEWAY_INITIATOR_RESOURCE_LINK
+ );
+
+ list_del_init
+ (
+ xenidc_gateway_message_and_transaction_header_to_link
+ ( header )
+ );
+
+ list_del_init
+ ( xenidc_gateway_initiator_resource_to_link( resource ) );
+
+ gateway->initiator_resources_out++;
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+
+ xenidc_gateway_initiator_resource_start( resource, header );
+
+ spin_lock_irqsave( &gateway->lock, flags );
+ }
+
+ if( !gateway->kick_messages_and_transactions_out )
+ {
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_km );
+ }
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+ }
+}
+
+static void xenidc_gateway_kick_messages_and_transactions_2
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_gateway_initiator_resource * resource =
+ xenidc_gateway_initiator_resource_callback_to( callback );
+
+ xenidc_gateway * gateway =
+ xenidc_gateway_initiator_resource_query_gateway( resource );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_gateway_initiator_resource_to_link( resource ),
+ &gateway->initiator_resource_list
+ );
+
+ if( --gateway->initiator_resources_out != 0 )
+ {
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_ic );
+ }
+ else
+ {
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_ii );
+ }
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+ }
+}
+
+static void xenidc_gateway_fail_out_messages_and_transactions
+ ( xenidc_gateway * gateway )
+{
+ trace();
+
+ while( !list_empty( &gateway->message_and_transaction_list ) )
+ {
+ xenidc_gateway_message_and_transaction_header * header = list_entry
+ (
+ gateway->message_and_transaction_list.next,
+ xenidc_gateway_message_and_transaction_header,
+ XENIDC_GATEWAY_MESSAGE_AND_TRANSACTION_HEADER_LINK
+ );
+
+ list_del_init
+ ( xenidc_gateway_message_and_transaction_header_to_link( header ) );
+
+ xenidc_callback_complete
+ (
+ xenidc_gateway_message_and_transaction_header_to_callback
+ ( header ),
+ XENIDC_ERROR_DISCONNECT
+ );
+ }
+}
+
+static void xenidc_gateway_kick_channel_messages( xenidc_gateway * gateway )
+{
+ trace();
+
+ if( !gateway->kick_channel_messages_out )
+ {
+ gateway->kick_channel_messages_out = 1;
+
+ (void)xenidc_work_schedule( &gateway->kick_channel_messages_1_work );
+ }
+}
+
+static void xenidc_gateway_kick_channel_messages_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_gateway * gateway = (xenidc_gateway *)data;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ gateway->kick_channel_messages_out = 0;
+
+ while
+ (
+ ( !list_empty( &gateway->channel_message_list ) )
+ &&
+ ( !list_empty( &gateway->target_resource_list ) )
+ )
+ {
+ xenidc_channel_message * message = list_entry
+ (
+ gateway->channel_message_list.next,
+ xenidc_channel_message,
+ XENIDC_CHANNEL_MESSAGE_LINK
+ );
+
+ xenidc_gateway_target_resource * resource = list_entry
+ (
+ gateway->target_resource_list.next,
+ xenidc_gateway_target_resource,
+ XENIDC_GATEWAY_TARGET_RESOURCE_LINK
+ );
+
+ list_del_init( xenidc_channel_message_to_link( message ) );
+
+ {
+ xenidc_gateway_ring_element_header header;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ ( &message->message_lbr, &header, sizeof( header ) )
+ !=
+ sizeof( header )
+ )
+ {
+ goto PROTOCOL_ERROR;
+ }
+
+ if( header.type == XENIDC_GATEWAY_RING_ELEMENT_TYPE_MESSAGE )
+ {
+ xenidc_local_buffer_reference message_lbr =
+ message->message_lbr;
+
+ xenidc_local_buffer_reference_advance
+ (
+ &message_lbr,
+ sizeof( xenidc_gateway_message_ring_element )
+ );
+
+ list_del_init
+ ( xenidc_gateway_target_resource_to_link( resource ) );
+
+ gateway->target_resources_out++;
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+
+ xenidc_gateway_target_resource_start_message
+ ( resource, message_lbr );
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ xenidc_callback_success
+ ( xenidc_channel_message_to_callback( message ) );
+ }
+ else if
+ (
+ header.type
+ ==
+ XENIDC_GATEWAY_RING_ELEMENT_TYPE_PARAMETERS
+ )
+ {
+ xenidc_local_buffer_reference parameters_lbr =
+ message->message_lbr;
+
+ xenidc_gateway_parameters_ring_element parameters_element;
+
+ if
+ (
+ xenidc_local_buffer_reference_copy_out
+ (
+ ¶meters_lbr,
+ ¶meters_element,
+ sizeof( parameters_element )
+ )
+ !=
+ sizeof( parameters_element )
+ )
+ {
+ goto PROTOCOL_ERROR;
+ }
+
+ xenidc_local_buffer_reference_advance
+ ( ¶meters_lbr, sizeof( parameters_element ) );
+
+ list_del_init
+ ( xenidc_gateway_target_resource_to_link( resource ) );
+
+ gateway->target_resources_out++;
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+
+ xenidc_gateway_target_resource_start_transaction
+ (
+ resource,
+ parameters_element.id,
+ parameters_lbr,
+ parameters_element.status_byte_count
+ );
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ xenidc_callback_success
+ ( xenidc_channel_message_to_callback( message ) );
+ }
+ else
+ {
+ PROTOCOL_ERROR:
+
+ xenidc_callback_complete
+ (
+ xenidc_channel_message_to_callback( message ),
+ XENIDC_ERROR_INVALID_PROTOCOL
+ );
+ }
+ }
+ }
+
+ if( !gateway->kick_channel_messages_out )
+ {
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_kc );
+ }
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+ }
+}
+
+static void xenidc_gateway_kick_channel_messages_2
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_gateway_target_resource * resource =
+ xenidc_gateway_target_resource_callback_to( callback );
+
+ xenidc_gateway * gateway =
+ xenidc_gateway_target_resource_query_gateway( resource );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_gateway_target_resource_to_link( resource ),
+ &gateway->target_resource_list
+ );
+
+ if( --gateway->target_resources_out != 0 )
+ {
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_tc );
+ }
+ else
+ {
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_ti );
+ }
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+ }
+}
+
+static void xenidc_gateway_complete_channel_messages
+ ( xenidc_gateway * gateway )
+{
+ trace();
+
+ while( !list_empty( &gateway->channel_message_list ) )
+ {
+ xenidc_channel_message * message = list_entry
+ (
+ gateway->channel_message_list.next,
+ xenidc_channel_message,
+ XENIDC_CHANNEL_MESSAGE_LINK
+ );
+
+ list_del_init( xenidc_channel_message_to_link( message ) );
+
+ xenidc_callback_success
+ ( xenidc_channel_message_to_callback( message ) );
+ }
+}
+
+static void xenidc_gateway_connect_client( xenidc_gateway * gateway )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &gateway->connect_client_1_work );
+}
+
+static void xenidc_gateway_connect_client_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_gateway * gateway = (xenidc_gateway *)data;
+
+ gateway->connect( gateway );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_lc );
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+ }
+ }
+}
+
+static void xenidc_gateway_disconnect_client( xenidc_gateway * gateway )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &gateway->disconnect_client_1_work );
+}
+
+static void xenidc_gateway_disconnect_client_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_gateway * gateway = (xenidc_gateway *)data;
+
+ gateway->disconnect( gateway, &gateway->disconnect_client_2_callback );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_lg );
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+ }
+ }
+}
+
+static void xenidc_gateway_disconnect_client_2( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_gateway * gateway = container_of
+ ( callback, xenidc_gateway, disconnect_client_2_callback );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &gateway->lock, flags );
+
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_ld );
+
+ spin_unlock_irqrestore( &gateway->lock, flags );
+ }
+}
+
+static void xenidc_gateway_abort_initiator_resources
+ ( xenidc_gateway * gateway )
+{
+ trace();
+
+ {
+ u32 i;
+
+ for( i = 0; i < gateway->initiator_quota; i++ )
+ {
+ xenidc_gateway_initiator_resource_abort
+ ( &gateway->initiator_resources[ i ] );
+ }
+ }
+}
+
+static void xenidc_gateway_test_initiator_resources
+ ( xenidc_gateway * gateway )
+{
+ trace();
+
+ if( gateway->initiator_resources_out == 0 )
+ {
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_ii );
+ }
+}
+
+static void xenidc_gateway_test_target_resources
+ ( xenidc_gateway * gateway )
+{
+ trace();
+
+ if( gateway->target_resources_out == 0 )
+ {
+ xenidc_gateway_handle_stimulus
+ ( gateway, xenidc_gateway_stimulus_ti );
+ }
+}
+
+static void xenidc_gateway_complete_channel_disconnect
+ ( xenidc_gateway * gateway )
+{
+ trace();
+
+ xenidc_callback_success( gateway->channel_disconnect_callback );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,411 @@
+#include <asm-xen/xenidc_vaddress.h>
+#include "xenidc_gateway_initiator_resource.h"
+#include "xenidc_trace.h"
+
+extern void xenidc_gateway_submit_channel_message
+ ( xenidc_gateway * gateway, xenidc_channel_message * message );
+
+static void xenidc_gateway_initiator_resource_handle_stimulus
+(
+ xenidc_gateway_initiator_resource * resource,
+ xenidc_gateway_initiator_resource_stimulus stimulus
+);
+
+static void xenidc_gateway_initiator_resource_channel_message_callback
+ ( xenidc_callback * callback );
+
+void xenidc_gateway_initiator_resource_init
+(
+ xenidc_gateway_initiator_resource * resource,
+ xenidc_gateway * gateway,
+ xenidc_callback_function callback,
+ int id
+)
+{
+ trace();
+
+ xenidc_callback_init( &resource->callback, callback );
+
+ resource->gateway = gateway;
+
+ resource->id = id;
+
+ spin_lock_init( &resource->lock );
+
+ resource->state = xenidc_gateway_initiator_resource_state_i;
+
+ xenidc_callback_init
+ (
+ xenidc_channel_message_to_callback( &resource->channel_message ),
+ xenidc_gateway_initiator_resource_channel_message_callback
+ );
+}
+
+void xenidc_gateway_initiator_resource_start
+(
+ xenidc_gateway_initiator_resource * resource,
+ xenidc_gateway_message_and_transaction_header * header
+)
+{
+ trace();
+
+ resource->header = header;
+
+ resource->error = XENIDC_ERROR_SUCCESS;
+
+ {
+ xenidc_gateway_initiator_resource_stimulus stimulus;
+
+ if( header->transaction_not_message )
+ {
+ xenidc_gateway_transaction * transaction =
+ xenidc_gateway_transaction_header_to( header );
+
+ resource->element_lbr = xenidc_vaddress_create_lbr
+ (
+ &resource->parameters_element,
+ sizeof( resource->parameters_element )
+ );
+
+ resource->channel_message.message_lbr =
+ xenidc_concatenate_create_lbr
+ (
+ &resource->base,
+ &resource->element_lbr,
+ &transaction->parameters_lbr
+ );
+
+ memset
+ (
+ &resource->parameters_element,
+ 0,
+ sizeof( resource->parameters_element )
+ );
+
+ resource->parameters_element.header.type =
+ XENIDC_GATEWAY_RING_ELEMENT_TYPE_PARAMETERS;
+
+ resource->parameters_element.id = resource->id;
+
+ resource->parameters_element.status_byte_count =
+ xenidc_local_buffer_reference_query_byte_count
+ ( &transaction->status_lbr );
+
+ stimulus = xenidc_gateway_initiator_resource_stimulus_st;
+ }
+ else
+ {
+ xenidc_gateway_message * message =
+ xenidc_gateway_message_header_to( header );
+
+ resource->element_lbr = xenidc_vaddress_create_lbr
+ (
+ &resource->message_element,
+ sizeof( resource->message_element )
+ );
+
+ resource->channel_message.message_lbr =
+ xenidc_concatenate_create_lbr
+ (
+ &resource->base,
+ &resource->element_lbr,
+ &message->message_lbr
+ );
+
+ memset
+ (
+ &resource->message_element,
+ 0,
+ sizeof( resource->message_element )
+ );
+
+ resource->parameters_element.header.type =
+ XENIDC_GATEWAY_RING_ELEMENT_TYPE_MESSAGE;
+
+ stimulus = xenidc_gateway_initiator_resource_stimulus_sm;
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ xenidc_gateway_initiator_resource_handle_stimulus
+ ( resource, stimulus );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+
+ xenidc_gateway_submit_channel_message
+ ( resource->gateway, &resource->channel_message );
+ }
+}
+
+void xenidc_gateway_initiator_resource_abort
+ ( xenidc_gateway_initiator_resource * resource )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ xenidc_gateway_initiator_resource_handle_stimulus
+ ( resource, xenidc_gateway_initiator_resource_stimulus_ab );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+}
+
+static void xenidc_gateway_initiator_resource_channel_message_callback
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_gateway_initiator_resource * resource = container_of
+ (
+ callback,
+ xenidc_gateway_initiator_resource,
+ channel_message.callback
+ );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ xenidc_gateway_initiator_resource_handle_stimulus
+ ( resource, xenidc_gateway_initiator_resource_stimulus_sc );
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+ }
+}
+
+int xenidc_gateway_initiator_resource_handle_status
+(
+ xenidc_gateway_initiator_resource * resource,
+ xenidc_error error,
+ xenidc_local_buffer_reference status_lbr
+)
+{
+ trace();
+
+ {
+ int return_value = -1;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &resource->lock, flags );
+
+ if
+ (
+ (
+ resource->state
+ ==
+ xenidc_gateway_initiator_resource_state_i_st
+ )
+ ||
+ (
+ resource->state
+ ==
+ xenidc_gateway_initiator_resource_state_i_st_sc
+ )
+ )
+ {
+ xenidc_gateway_transaction * transaction =
+ xenidc_gateway_transaction_header_to( resource->header );
+
+ if
+ (
+ xenidc_local_buffer_reference_query_byte_count( &status_lbr )
+ ==
+ xenidc_local_buffer_reference_query_byte_count
+ ( &transaction->status_lbr )
+ )
+ {
+ xenidc_local_buffer_reference_copy
+ ( &transaction->status_lbr, &status_lbr );
+
+ resource->error = error;
+
+ xenidc_gateway_initiator_resource_handle_stimulus
+ ( resource, xenidc_gateway_initiator_resource_stimulus_ts );
+
+ return_value = 0;
+ }
+ }
+
+ spin_unlock_irqrestore( &resource->lock, flags );
+
+ return return_value;
+ }
+}
+
+static void xenidc_gateway_initiator_resource_invalid_stimulus
+(
+ xenidc_gateway_initiator_resource * resource,
+ xenidc_gateway_initiator_resource_stimulus stimulus
+);
+
+static void xenidc_gateway_initiator_resource_set_aborted
+ ( xenidc_gateway_initiator_resource * resource );
+
+static void xenidc_gateway_initiator_resource_complete
+ ( xenidc_gateway_initiator_resource * resource );
+
+static void xenidc_gateway_initiator_resource_handle_stimulus
+(
+ xenidc_gateway_initiator_resource * resource,
+ xenidc_gateway_initiator_resource_stimulus stimulus
+)
+{
+ trace3
+ (
+ "gateway initiator resource %p in state %d received stimulus %d",
+ resource,
+ resource->state,
+ stimulus
+ );
+
+ switch( resource->state )
+ {
+ case xenidc_gateway_initiator_resource_state_i:
+ switch( stimulus )
+ {
+ case xenidc_gateway_initiator_resource_stimulus_sm:
+ resource->state = xenidc_gateway_initiator_resource_state_i_sm;
+ break;
+ case xenidc_gateway_initiator_resource_stimulus_st:
+ resource->state = xenidc_gateway_initiator_resource_state_i_st;
+ break;
+ case xenidc_gateway_initiator_resource_stimulus_ab:
+ break;
+ default:
+ xenidc_gateway_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_initiator_resource_state_i_sm:
+ switch( stimulus )
+ {
+ case xenidc_gateway_initiator_resource_stimulus_ab:
+ break;
+ case xenidc_gateway_initiator_resource_stimulus_sc:
+ resource->state = xenidc_gateway_initiator_resource_state_i;
+ xenidc_gateway_initiator_resource_complete( resource );
+ break;
+ default:
+ xenidc_gateway_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_initiator_resource_state_i_st:
+ switch( stimulus )
+ {
+ case xenidc_gateway_initiator_resource_stimulus_ab:
+ resource->state = xenidc_gateway_initiator_resource_state_i_st_ab;
+ break;
+ case xenidc_gateway_initiator_resource_stimulus_sc:
+ resource->state = xenidc_gateway_initiator_resource_state_i_st_sc;
+ break;
+ case xenidc_gateway_initiator_resource_stimulus_ts:
+ resource->state = xenidc_gateway_initiator_resource_state_i_st_ts;
+ break;
+ default:
+ xenidc_gateway_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_initiator_resource_state_i_st_ab:
+ switch( stimulus )
+ {
+ case xenidc_gateway_initiator_resource_stimulus_sc:
+ resource->state = xenidc_gateway_initiator_resource_state_i;
+ xenidc_gateway_initiator_resource_set_aborted( resource );
+ xenidc_gateway_initiator_resource_complete( resource );
+ break;
+ default:
+ xenidc_gateway_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_initiator_resource_state_i_st_sc:
+ switch( stimulus )
+ {
+ case xenidc_gateway_initiator_resource_stimulus_ab:
+ resource->state = xenidc_gateway_initiator_resource_state_i;
+ xenidc_gateway_initiator_resource_set_aborted( resource );
+ xenidc_gateway_initiator_resource_complete( resource );
+ break;
+ case xenidc_gateway_initiator_resource_stimulus_ts:
+ resource->state = xenidc_gateway_initiator_resource_state_i;
+ xenidc_gateway_initiator_resource_complete( resource );
+ break;
+ default:
+ xenidc_gateway_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gateway_initiator_resource_state_i_st_ts:
+ switch( stimulus )
+ {
+ case xenidc_gateway_initiator_resource_stimulus_ab:
+ break;
+ case xenidc_gateway_initiator_resource_stimulus_sc:
+ resource->state = xenidc_gateway_initiator_resource_state_i;
+ xenidc_gateway_initiator_resource_complete( resource );
+ break;
+ default:
+ xenidc_gateway_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+ break;
+ default:
+ xenidc_gateway_initiator_resource_invalid_stimulus
+ ( resource, stimulus );
+ break;
+ }
+}
+
+static void xenidc_gateway_initiator_resource_invalid_stimulus
+(
+ xenidc_gateway_initiator_resource * resource,
+ xenidc_gateway_initiator_resource_stimulus stimulus
+)
+{
+ trace();
+
+ printk
+ (
+ KERN_ERR "xenidc: gateway initiator resource %p in state %d"
+ "received invalid stimulus %d",
+ resource,
+ resource->state,
+ stimulus
+ );
+}
+
+static void xenidc_gateway_initiator_resource_set_aborted
+ ( xenidc_gateway_initiator_resource * resource )
+{
+ trace();
+
+ resource->error = XENIDC_ERROR_ABORTED;
+}
+
+static void xenidc_gateway_initiator_resource_complete
+ ( xenidc_gateway_initiator_resource * resource )
+{
+ trace();
+
+ xenidc_callback_complete( &resource->header->callback, resource->error );
+
+ xenidc_callback_success( &resource->callback );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_initiator_resource.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,95 @@
+#ifndef _XENIDC_GATEWAY_INITIATOR_RESOURCE_H
+#define _XENIDC_GATEWAY_INITIATOR_RESOURCE_H
+
+#include <asm-xen/xenidc_concatenate.h>
+#include <asm-xen/xenidc_channel.h>
+#include <asm-xen/xenidc_gateway.h>
+#include "xenidc_gateway_ring.h"
+
+typedef enum
+{
+ xenidc_gateway_initiator_resource_state_i,
+ xenidc_gateway_initiator_resource_state_i_sm,
+ xenidc_gateway_initiator_resource_state_i_st,
+ xenidc_gateway_initiator_resource_state_i_st_ab,
+ xenidc_gateway_initiator_resource_state_i_st_sc,
+ xenidc_gateway_initiator_resource_state_i_st_ts
+}
+xenidc_gateway_initiator_resource_state;
+
+typedef enum
+{
+ xenidc_gateway_initiator_resource_stimulus_sm, /* Start message */
+ xenidc_gateway_initiator_resource_stimulus_st, /* Start transaction */
+ xenidc_gateway_initiator_resource_stimulus_ab, /* Abort */
+ xenidc_gateway_initiator_resource_stimulus_sc, /* Send complete */
+ xenidc_gateway_initiator_resource_stimulus_ts, /* Transaction status */
+}
+xenidc_gateway_initiator_resource_stimulus;
+
+struct xenidc_gateway_initiator_resource_struct
+{
+ xenidc_callback callback;
+ xenidc_gateway * gateway;
+ int id;
+ spinlock_t lock;
+ xenidc_gateway_initiator_resource_state state;
+ xenidc_gateway_message_and_transaction_header * header;
+ xenidc_error error;
+ xenidc_channel_message channel_message;
+ xenidc_local_buffer_reference element_lbr;
+ xenidc_concatenate_base base;
+ union
+ {
+ xenidc_gateway_parameters_ring_element parameters_element;
+ xenidc_gateway_message_ring_element message_element;
+ };
+};
+
+#define XENIDC_GATEWAY_INITIATOR_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK
+
+static inline struct list_head * xenidc_gateway_initiator_resource_to_link
+ ( xenidc_gateway_initiator_resource * resource )
+{
+ return &resource->XENIDC_GATEWAY_INITIATOR_RESOURCE_LINK;
+}
+
+static inline xenidc_gateway_initiator_resource *
+ xenidc_gateway_initiator_resource_callback_to( xenidc_callback * callback )
+{
+ return container_of
+ ( callback, xenidc_gateway_initiator_resource, callback );
+}
+
+static inline xenidc_gateway *
+ xenidc_gateway_initiator_resource_query_gateway
+ ( xenidc_gateway_initiator_resource* resource )
+{
+ return resource->gateway;
+}
+
+void xenidc_gateway_initiator_resource_init
+(
+ xenidc_gateway_initiator_resource * resource,
+ xenidc_gateway * gateway,
+ xenidc_callback_function callback,
+ int id
+);
+
+void xenidc_gateway_initiator_resource_start
+(
+ xenidc_gateway_initiator_resource * resource,
+ xenidc_gateway_message_and_transaction_header * header
+);
+
+void xenidc_gateway_initiator_resource_abort
+ ( xenidc_gateway_initiator_resource * resource );
+
+int xenidc_gateway_initiator_resource_handle_status
+(
+ xenidc_gateway_initiator_resource * resource,
+ xenidc_error error,
+ xenidc_local_buffer_reference status
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_ring.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_ring.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,69 @@
+/*****************************************************************************/
+/* Xen inter-domain communication gateway ring structure definitions. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef _XENIDC_GATEWAY_RING_H
+#define _XENIDC_GATEWAY_RING_H
+
+#include <asm-xen/xenidc.h>
+
+typedef struct xenidc_gateway_ring_element_header_struct
+ xenidc_gateway_ring_element_header;
+
+struct xenidc_gateway_ring_element_header_struct
+{
+ u8 type;
+ u8 reserved[ 7 ];
+};
+
+#define XENIDC_GATEWAY_RING_ELEMENT_TYPE_MESSAGE 0
+#define XENIDC_GATEWAY_RING_ELEMENT_TYPE_PARAMETERS 1
+#define XENIDC_GATEWAY_RING_ELEMENT_TYPE_STATUS 2
+
+typedef struct xenidc_gateway_message_ring_element_struct
+ xenidc_gateway_message_ring_element;
+
+struct xenidc_gateway_message_ring_element_struct
+{
+ xenidc_gateway_ring_element_header header;
+};
+
+typedef struct xenidc_gateway_parameters_ring_element_struct
+ xenidc_gateway_parameters_ring_element;
+
+struct xenidc_gateway_parameters_ring_element_struct
+{
+ xenidc_gateway_ring_element_header header;
+ u32 id;
+ u16 status_byte_count;
+ u16 reserved;
+};
+
+typedef struct xenidc_gateway_status_ring_element_struct
+ xenidc_gateway_status_ring_element;
+
+struct xenidc_gateway_status_ring_element_struct
+{
+ xenidc_gateway_ring_element_header header;
+ u32 id;
+ xenidc_error error;
+};
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,193 @@
+#include <asm-xen/xenidc_vaddress.h>
+#include "xenidc_gateway_target_resource.h"
+#include "xenidc_trace.h"
+
+extern void xenidc_gateway_submit_channel_message
+ ( xenidc_gateway * gateway, xenidc_channel_message * message );
+
+extern void xenidc_gateway_submit_message_to_client
+ ( xenidc_gateway * gateway, xenidc_gateway_message * message );
+
+extern void xenidc_gateway_submit_transaction_to_client
+ ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction );
+
+static void xenidc_gateway_target_resource_channel_message_callback
+ ( xenidc_callback * callback );
+
+void xenidc_gateway_target_resource_init
+(
+ xenidc_gateway_target_resource * resource,
+ xenidc_gateway * gateway,
+ xenidc_callback_function callback,
+ xenidc_local_buffer_reference buffer
+)
+{
+ trace();
+
+ xenidc_callback_init( &resource->callback, callback );
+
+ resource->gateway = gateway;
+
+ resource->buffer = buffer;
+
+ xenidc_callback_init
+ (
+ xenidc_channel_message_to_callback( &resource->channel_message ),
+ xenidc_gateway_target_resource_channel_message_callback
+ );
+
+ resource->element_lbr = xenidc_vaddress_create_lbr
+ ( &resource->status_element, sizeof( resource->status_element ) );
+
+ memset( &resource->status_element, 0, sizeof( resource->status_element ) );
+
+ resource->status_element.header.type =
+ XENIDC_GATEWAY_RING_ELEMENT_TYPE_STATUS;
+}
+
+static void xenidc_gateway_target_resource_message_callback
+ ( xenidc_callback * callback );
+
+void xenidc_gateway_target_resource_start_message
+(
+ xenidc_gateway_target_resource * resource,
+ xenidc_local_buffer_reference message_lbr
+)
+{
+ trace();
+
+ xenidc_gateway_message_init
+ (
+ &resource->message,
+ xenidc_gateway_target_resource_message_callback
+ );
+
+ {
+ xenidc_local_buffer_reference lbr = resource->buffer;
+
+ xenidc_local_buffer_reference_truncate
+ (
+ &lbr,
+ xenidc_local_buffer_reference_copy( &lbr, &message_lbr )
+ );
+
+ resource->message.message_lbr = lbr;
+ }
+
+ xenidc_gateway_submit_message_to_client
+ ( resource->gateway, &resource->message );
+}
+
+static void xenidc_gateway_target_resource_message_callback
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_gateway_target_resource * resource = container_of
+ (
+ xenidc_gateway_message_callback_to( callback ),
+ xenidc_gateway_target_resource,
+ message
+ );
+
+ xenidc_callback_success( &resource->callback );
+ }
+}
+
+static void xenidc_gateway_target_resource_transaction_callback
+ ( xenidc_callback * callback );
+
+void xenidc_gateway_target_resource_start_transaction
+(
+ xenidc_gateway_target_resource * resource,
+ u32 id,
+ xenidc_local_buffer_reference parameters_lbr,
+ xenidc_buffer_byte_count status_byte_count
+)
+{
+ trace();
+
+ xenidc_gateway_transaction_init
+ (
+ &resource->transaction,
+ xenidc_gateway_target_resource_transaction_callback
+ );
+
+ {
+ xenidc_local_buffer_reference lbr = resource->buffer;
+
+ xenidc_local_buffer_reference_truncate
+ (
+ &lbr,
+ xenidc_local_buffer_reference_copy( &lbr, ¶meters_lbr )
+ );
+
+ resource->transaction.parameters_lbr = lbr;
+ }
+
+ {
+ xenidc_local_buffer_reference lbr = resource->buffer;
+
+ xenidc_local_buffer_reference_subrange
+ (
+ &lbr,
+ xenidc_local_buffer_reference_query_byte_count( ¶meters_lbr ),
+ status_byte_count
+ );
+
+ xenidc_local_buffer_reference_zero( &lbr );
+
+ resource->transaction.status_lbr = lbr;
+ }
+
+ resource->status_element.id = id;
+
+ xenidc_gateway_submit_transaction_to_client
+ ( resource->gateway, &resource->transaction );
+}
+
+static void xenidc_gateway_target_resource_transaction_callback
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_gateway_target_resource * resource = container_of
+ (
+ xenidc_gateway_transaction_callback_to( callback ),
+ xenidc_gateway_target_resource,
+ transaction
+ );
+
+ resource->status_element.error =
+ xenidc_callback_query_error( callback );
+
+ resource->channel_message.message_lbr = xenidc_concatenate_create_lbr
+ (
+ &resource->base,
+ &resource->element_lbr,
+ &resource->transaction.status_lbr
+ );
+
+ xenidc_gateway_submit_channel_message
+ ( resource->gateway, &resource->channel_message );
+ }
+}
+
+static void xenidc_gateway_target_resource_channel_message_callback
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_gateway_target_resource * resource = container_of
+ (
+ callback,
+ xenidc_gateway_target_resource,
+ channel_message.callback
+ );
+
+ xenidc_callback_success( &resource->callback );
+ }
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gateway_target_resource.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,68 @@
+#ifndef _XENIDC_GATEWAY_TARGET_RESOURCE_H
+#define _XENIDC_GATEWAY_TARGET_RESOURCE_H
+
+#include <asm-xen/xenidc_channel.h>
+#include <asm-xen/xenidc_concatenate.h>
+#include <asm-xen/xenidc_gateway.h>
+#include "xenidc_gateway_ring.h"
+
+struct xenidc_gateway_target_resource_struct
+{
+ xenidc_callback callback;
+ xenidc_gateway * gateway;
+ xenidc_local_buffer_reference buffer;
+ union
+ {
+ xenidc_gateway_message message;
+ xenidc_gateway_transaction transaction;
+ };
+ xenidc_channel_message channel_message;
+ xenidc_local_buffer_reference element_lbr;
+ xenidc_concatenate_base base;
+ xenidc_gateway_status_ring_element status_element;
+};
+
+#define XENIDC_GATEWAY_TARGET_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK
+
+static inline struct list_head * xenidc_gateway_target_resource_to_link
+ ( xenidc_gateway_target_resource * resource )
+{
+ return &resource->XENIDC_GATEWAY_TARGET_RESOURCE_LINK;
+}
+
+static inline xenidc_gateway_target_resource *
+ xenidc_gateway_target_resource_callback_to( xenidc_callback * callback )
+{
+ return container_of
+ ( callback, xenidc_gateway_target_resource, callback );
+}
+
+static inline xenidc_gateway * xenidc_gateway_target_resource_query_gateway
+ ( xenidc_gateway_target_resource* resource )
+{
+ return resource->gateway;
+}
+
+extern void xenidc_gateway_target_resource_init
+(
+ xenidc_gateway_target_resource * resource,
+ xenidc_gateway * gateway,
+ xenidc_callback_function callback,
+ xenidc_local_buffer_reference buffer
+);
+
+extern void xenidc_gateway_target_resource_start_message
+(
+ xenidc_gateway_target_resource * resource,
+ xenidc_local_buffer_reference message_lbr
+);
+
+extern void xenidc_gateway_target_resource_start_transaction
+(
+ xenidc_gateway_target_resource * resource,
+ u32 id,
+ xenidc_local_buffer_reference parameters_lbr,
+ xenidc_buffer_byte_count status_byte_count
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gnttab_channel.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gnttab_channel.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,1693 @@
+/*****************************************************************************/
+/* This is a class which implements a grant-tables based inter-domain */
+/* message channel. The implementation of the bring-up and tear-down */
+/* handshaking is left to a derived class. */
+/* This class is used by xenidc_xbgt_channel (which implements bring-up and */
+/* teardown using xenbus) which is in turn used to implement the */
+/* xenidc_endpoint class. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#include <asm-xen/driver_util.h>
+#include <asm-xen/evtchn.h>
+#include <asm-xen/xenidc_concatenate.h>
+#include <asm-xen/xenidc_gnttab_channel.h>
+#include <asm-xen/xenidc_vaddress.h>
+#include <asm-xen/xenidc_wrapping.h>
+#include <linux/interrupt.h>
+#include "xenidc_trace.h"
+#include "xenidc_channel_ring.h"
+
+static inline void xenidc_gnttab_channel_target_resource_init
+(
+ xenidc_gnttab_channel_target_resource * resource,
+ xenidc_gnttab_channel * channel,
+ xenidc_callback_function * callback
+)
+{
+ trace();
+
+ xenidc_channel_message_init( &resource->message, callback );
+
+ resource->channel = channel;
+}
+
+static inline struct list_head * xenidc_gnttab_channel_target_resource_to_link
+ ( xenidc_gnttab_channel_target_resource * resource )
+{
+ trace();
+
+ return xenidc_channel_message_to_link( &resource->message );
+}
+
+static inline xenidc_channel_message *
+ xenidc_gnttab_channel_target_resource_to_message
+ ( xenidc_gnttab_channel_target_resource * resource )
+{
+ trace();
+
+ return &resource->message;
+}
+
+static inline xenidc_gnttab_channel_target_resource *
+ xenidc_gnttab_channel_target_resource_callback_to
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ return container_of
+ (
+ xenidc_channel_message_callback_to( callback ),
+ xenidc_gnttab_channel_target_resource,
+ message
+ );
+}
+
+static inline xenidc_gnttab_channel *
+ xenidc_gnttab_channel_target_resource_query_channel
+ ( xenidc_gnttab_channel_target_resource * resource )
+{
+ trace();
+
+ return resource->channel;
+}
+
+typedef enum
+{
+ xenidc_gnttab_channel_stimulus_c1r, /* phase one connect request */
+ xenidc_gnttab_channel_stimulus_c2r, /* phase two connect request */
+ xenidc_gnttab_channel_stimulus_mqr, /* message queued */
+ xenidc_gnttab_channel_stimulus_d2r, /* phase two disconnect request */
+ xenidc_gnttab_channel_stimulus_d1r, /* phase one disconnect request */
+ xenidc_gnttab_channel_stimulus_sir, /* send interrupt */
+ xenidc_gnttab_channel_stimulus_rir, /* recv interrupt */
+ xenidc_gnttab_channel_stimulus_c1c, /* phase one connect completed */
+ xenidc_gnttab_channel_stimulus_c2s, /* phase two connect successful */
+ xenidc_gnttab_channel_stimulus_c2f, /* phase two connect failed */
+ xenidc_gnttab_channel_stimulus_ccc, /* connect client completed */
+ xenidc_gnttab_channel_stimulus_dcc, /* disconnect client completed */
+ xenidc_gnttab_channel_stimulus_d2c, /* phase two disconnect completed */
+ xenidc_gnttab_channel_stimulus_d1c, /* phase one disconnect completed */
+ xenidc_gnttab_channel_stimulus_ksc, /* kick send ring completed */
+ xenidc_gnttab_channel_stimulus_krc, /* kick recv ring completed */
+ xenidc_gnttab_channel_stimulus_trc, /* target resource completed */
+ xenidc_gnttab_channel_stimulus_tri /* target resources idle */
+}
+xenidc_gnttab_channel_stimulus;
+
+static void xenidc_gnttab_channel_handle_stimulus
+ ( xenidc_gnttab_channel * channel, xenidc_gnttab_channel_stimulus stimulus );
+
+static void xenidc_gnttab_channel_submit_message
+ ( xenidc_channel * base_channel, xenidc_channel_message * message );
+
+static int xenidc_gnttab_channel_init_or_exit
+ ( xenidc_gnttab_channel * channel, int exit );
+
+int xenidc_gnttab_channel_init
+(
+ xenidc_gnttab_channel * channel,
+ void ( * protocol_error )( xenidc_gnttab_channel * channel )
+)
+{
+ trace();
+
+ xenidc_channel_init
+ ( &channel->channel, xenidc_gnttab_channel_submit_message );
+
+ channel->protocol_error = protocol_error;
+
+ return xenidc_gnttab_channel_init_or_exit( channel, 0 );
+}
+
+static void xenidc_gnttab_channel_do_phase_one_connect_1( void * data );
+
+static void xenidc_gnttab_channel_do_phase_two_connect_1( void * data );
+
+static void xenidc_gnttab_channel_connect_client_1( void * data );
+
+static void xenidc_gnttab_channel_disconnect_client_1( void * data );
+
+static void xenidc_gnttab_channel_disconnect_client_2
+ ( xenidc_callback * callback );
+
+static void xenidc_gnttab_channel_do_phase_two_disconnect_1( void * data );
+
+static void xenidc_gnttab_channel_do_phase_one_disconnect_1( void * data );
+
+static void xenidc_gnttab_channel_kick_send_ring_1( void * data );
+
+static void xenidc_gnttab_channel_kick_recv_ring_1( void * data );
+
+static void xenidc_gnttab_channel_kick_recv_ring_2
+ ( xenidc_callback * callback );
+
+static int xenidc_gnttab_channel_init_or_exit
+ ( xenidc_gnttab_channel * channel, int exit )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ if( exit )
+ {
+ goto EXIT;
+ }
+
+ channel->send_irq_context = channel;
+ channel->recv_irq_context = channel;
+
+ channel->send_ring = (void *)__get_free_page( GFP_KERNEL );
+
+ if( channel->send_ring == NULL )
+ {
+ trace0( "failed to allocate send ring" );
+
+ return_value = -ENOMEM;
+
+ goto EXIT_NO_SEND_RING;
+ }
+
+ if
+ (
+ ( channel->recv_ring_area = alloc_vm_area( PAGE_SIZE ) )
+ ==
+ NULL
+ )
+ {
+ trace0( "failed to allocate receive ring area" );
+
+ return_value = -ENOMEM;
+
+ goto EXIT_NO_RING_AREA;
+ }
+
+ return_value =
+ gnttab_alloc_grant_references( 1, &channel->grant_ref_pool );
+
+ if( return_value != 0 )
+ {
+ trace0( "failed to allocate grant reference pool" );
+
+ goto EXIT_NO_GRANT_REF;
+ }
+
+ spin_lock_init( &channel->lock );
+
+ channel->state = xenidc_gnttab_channel_state_i;
+
+ INIT_LIST_HEAD( &channel->message_list );
+
+ xenidc_work_init
+ (
+ &channel->do_phase_one_connect_1_work,
+ xenidc_gnttab_channel_do_phase_one_connect_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->do_phase_two_connect_1_work,
+ xenidc_gnttab_channel_do_phase_two_connect_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->connect_client_1_work,
+ xenidc_gnttab_channel_connect_client_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->disconnect_client_1_work,
+ xenidc_gnttab_channel_disconnect_client_1,
+ channel
+ );
+
+ xenidc_callback_init
+ (
+ &channel->disconnect_client_2_callback,
+ xenidc_gnttab_channel_disconnect_client_2
+ );
+
+ xenidc_work_init
+ (
+ &channel->do_phase_two_disconnect_1_work,
+ xenidc_gnttab_channel_do_phase_two_disconnect_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->do_phase_one_disconnect_1_work,
+ xenidc_gnttab_channel_do_phase_one_disconnect_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->kick_send_ring_1_work,
+ xenidc_gnttab_channel_kick_send_ring_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->kick_recv_ring_1_work,
+ xenidc_gnttab_channel_kick_recv_ring_1,
+ channel
+ );
+
+ {
+ int i;
+
+ for( i = 0; i < XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT; i++ )
+ {
+ xenidc_gnttab_channel_target_resource * resource =
+ &channel->target_resources[ i ];
+
+ xenidc_gnttab_channel_target_resource_init
+ (
+ resource,
+ channel,
+ xenidc_gnttab_channel_kick_recv_ring_2
+ );
+
+ channel->target_resource_free[ i ] = 1;
+ }
+ }
+
+ channel->first_target_resource = 0;
+ channel->next_target_resource = 0;
+
+ channel->send_ring_kick_out = 0;
+ channel->recv_ring_kick_out = 0;
+
+ return 0;
+
+ EXIT:
+
+ gnttab_free_grant_references( channel->grant_ref_pool );
+
+ EXIT_NO_GRANT_REF:
+
+ free_vm_area( channel->recv_ring_area );
+
+ EXIT_NO_RING_AREA:
+
+ free_page( (unsigned long)channel->send_ring );
+
+ EXIT_NO_SEND_RING:
+
+ return return_value;
+ }
+}
+
+void xenidc_gnttab_channel_phase_one_connect
+(
+ xenidc_gnttab_channel * channel,
+ xenidc_gnttab_channel_phase_one_connect_request * request
+)
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ channel->current_callback = &request->callback;
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_c1r );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+void xenidc_gnttab_channel_reset_ring( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ channel->recv_ring_offset = 0;
+
+ memset( channel->send_ring, 0, PAGE_SIZE );
+}
+
+void xenidc_gnttab_channel_phase_two_connect
+(
+ xenidc_gnttab_channel * channel,
+ xenidc_gnttab_channel_phase_two_connect_request * request
+)
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ channel->current_callback = &request->callback;
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_c2r );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+static void xenidc_gnttab_channel_submit_message
+ ( xenidc_channel * base_channel, xenidc_channel_message * message )
+{
+ trace();
+
+ {
+ xenidc_gnttab_channel * channel =
+ xenidc_gnttab_channel_channel_to( base_channel );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ list_add_tail
+ (
+ xenidc_channel_message_to_link( message ),
+ &channel->message_list
+ );
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_mqr );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+void xenidc_gnttab_channel_phase_two_disconnect
+ ( xenidc_gnttab_channel * channel, xenidc_callback * callback )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ channel->current_callback = callback;
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_d2r );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+void xenidc_gnttab_channel_phase_one_disconnect
+ ( xenidc_gnttab_channel * channel, xenidc_callback * callback )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ channel->current_callback = callback;
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_d1r );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+void xenidc_gnttab_channel_exit( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ (void)xenidc_gnttab_channel_init_or_exit( channel, 1 );
+}
+
+static irqreturn_t xenidc_gnttab_channel_send_interrupt
+ ( int irq, void * context, struct pt_regs * ptregs )
+{
+ trace();
+
+ {
+ xenidc_gnttab_channel * channel = *(xenidc_gnttab_channel **)context;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_sir );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t xenidc_gnttab_channel_recv_interrupt
+ ( int irq, void * context, struct pt_regs * ptregs )
+{
+ trace();
+
+ {
+ xenidc_gnttab_channel * channel = *(xenidc_gnttab_channel **)context;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_rir );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void xenidc_gnttab_channel_invalid_stimulus
+ ( xenidc_gnttab_channel * channel, xenidc_gnttab_channel_stimulus stimulus );
+
+static void xenidc_gnttab_channel_do_phase_one_connect
+ ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_do_phase_two_connect
+ ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_connect_client
+ ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_disconnect_client
+ ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_do_phase_two_disconnect
+ ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_do_phase_one_disconnect
+ ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_kick_send_ring
+ ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_kick_recv_ring
+ ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_complete_current_callback
+ ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_fail_current_callback
+ ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_fail_out_messages
+ ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_test_target_resources
+ ( xenidc_gnttab_channel * channel );
+
+static void xenidc_gnttab_channel_handle_stimulus
+ ( xenidc_gnttab_channel * channel, xenidc_gnttab_channel_stimulus stimulus )
+{
+ trace3
+ (
+ "channel %p in state %d received stimulus %d",
+ channel,
+ channel->state,
+ stimulus
+ );
+
+ switch( channel->state )
+ {
+ case xenidc_gnttab_channel_state_i:
+ /* Interface disconnected. */
+ /* Client disconnected. */
+ /* No messages queued. */
+ /* Kick send idle. */
+ /* Kick recv idle. */
+ /* Target resources idle. */
+ switch( stimulus )
+ {
+ case xenidc_gnttab_channel_stimulus_c1r:
+ channel->state = xenidc_gnttab_channel_state_i_c1r;
+ xenidc_gnttab_channel_do_phase_one_connect( channel );
+ break;
+ default:
+ xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gnttab_channel_state_i_c1r:
+ /* Interface phase one connecting. */
+ /* Client disconnected. */
+ /* No messages queued. */
+ /* Kick send idle. */
+ /* Kick recv idle. */
+ /* Target resources idle. */
+ /* do phase one connect in progress */
+ switch( stimulus )
+ {
+ case xenidc_gnttab_channel_stimulus_sir:
+ break;
+ case xenidc_gnttab_channel_stimulus_c1c:
+ channel->state = xenidc_gnttab_channel_state_i_c1r_c1c;
+ xenidc_gnttab_channel_complete_current_callback( channel );
+ break;
+ default:
+ xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gnttab_channel_state_i_c1r_c1c:
+ /* Interface phase one connected. */
+ /* Client disconnected. */
+ /* No messages queued. */
+ /* Kick send idle. */
+ /* Kick recv idle. */
+ /* Target resources idle. */
+ /* Phase one connected. */
+ switch( stimulus )
+ {
+ case xenidc_gnttab_channel_stimulus_c2r:
+ channel->state = xenidc_gnttab_channel_state_i_c1r_c1c_c2r;
+ xenidc_gnttab_channel_do_phase_two_connect( channel );
+ break;
+ case xenidc_gnttab_channel_stimulus_d1r:
+ channel->state = xenidc_gnttab_channel_state_i_c1r_c1c_d1r;
+ xenidc_gnttab_channel_do_phase_one_disconnect( channel );
+ break;
+ case xenidc_gnttab_channel_stimulus_sir:
+ break;
+ default:
+ xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gnttab_channel_state_i_c1r_c1c_c2r:
+ /* Interface phase two connecting. */
+ /* Client disconnected. */
+ /* No messages queued. */
+ /* Kick send idle. */
+ /* Kick recv idle. */
+ /* Target resources idle. */
+ /* do phase two connect in progress */
+ switch( stimulus )
+ {
+ case xenidc_gnttab_channel_stimulus_sir:
+ case xenidc_gnttab_channel_stimulus_rir:
+ break;
+ case xenidc_gnttab_channel_stimulus_c2s:
+ channel->state = xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s;
+ xenidc_gnttab_channel_connect_client( channel );
+ break;
+ case xenidc_gnttab_channel_stimulus_c2f:
+ channel->state = xenidc_gnttab_channel_state_i_c1r_c1c;
+ xenidc_gnttab_channel_fail_current_callback( channel );
+ break;
+ default:
+ xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gnttab_channel_state_i_c1r_c1c_d1r:
+ /* Interface phase one disconnecting. */
+ /* Client disconnected. */
+ /* No messages queued. */
+ /* Kick send idle. */
+ /* Kick recv idle. */
+ /* Target resources idle. */
+ /* do phase one disconnect in progress */
+ switch( stimulus )
+ {
+ case xenidc_gnttab_channel_stimulus_sir:
+ break;
+ case xenidc_gnttab_channel_stimulus_d1c:
+ channel->state = xenidc_gnttab_channel_state_i;
+ xenidc_gnttab_channel_complete_current_callback( channel );
+ break;
+ default:
+ xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s:
+ /* Interface phase two connecting. */
+ /* Client connecting. */
+ /* Maybe messages queued. */
+ /* Kick send idle. */
+ /* Kick recv idle. */
+ /* Target resources idle. */
+ /* Phase two connected. */
+ /* connect client in progress */
+ switch( stimulus )
+ {
+ case xenidc_gnttab_channel_stimulus_mqr:
+ case xenidc_gnttab_channel_stimulus_sir:
+ case xenidc_gnttab_channel_stimulus_rir:
+ break;
+ case xenidc_gnttab_channel_stimulus_ccc:
+ channel->state = xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc;
+ xenidc_gnttab_channel_complete_current_callback( channel );
+ xenidc_gnttab_channel_kick_send_ring( channel );
+ xenidc_gnttab_channel_kick_recv_ring( channel );
+ break;
+ default:
+ xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc:
+ /* Interface phase two connected. */
+ /* Client connected. */
+ /* Maybe messages queued. */
+ /* Maybe kick send in progress. */
+ /* Maybe kick recv in progress. */
+ /* Maybe target resources busy. */
+ /* Phase two connected. */
+ switch( stimulus )
+ {
+ case xenidc_gnttab_channel_stimulus_mqr:
+ xenidc_gnttab_channel_kick_send_ring( channel );
+ break;
+ case xenidc_gnttab_channel_stimulus_d2r:
+ channel->state =
+ xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r;
+ xenidc_gnttab_channel_kick_send_ring( channel );
+ xenidc_gnttab_channel_kick_recv_ring( channel );
+ break;
+ case xenidc_gnttab_channel_stimulus_sir:
+ xenidc_gnttab_channel_kick_send_ring( channel );
+ break;
+ case xenidc_gnttab_channel_stimulus_rir:
+ xenidc_gnttab_channel_kick_recv_ring( channel );
+ break;
+ case xenidc_gnttab_channel_stimulus_ksc:
+ case xenidc_gnttab_channel_stimulus_krc:
+ break;
+ case xenidc_gnttab_channel_stimulus_trc:
+ case xenidc_gnttab_channel_stimulus_tri:
+ xenidc_gnttab_channel_kick_recv_ring( channel );
+ break;
+ default:
+ xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r:
+ /* Interface phase two disconnecting. */
+ /* Client connected. */
+ /* Maybe messages queued. */
+ /* Kick send in progress. */
+ /* Kick recv in progress. */
+ /* Maybe target resources busy. */
+ /* Phase two connected. */
+ switch( stimulus )
+ {
+ case xenidc_gnttab_channel_stimulus_mqr:
+ case xenidc_gnttab_channel_stimulus_sir:
+ case xenidc_gnttab_channel_stimulus_rir:
+ break;
+ case xenidc_gnttab_channel_stimulus_ksc:
+ case xenidc_gnttab_channel_stimulus_krc:
+ channel->state =
+ xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc;
+ break;
+ case xenidc_gnttab_channel_stimulus_trc:
+ case xenidc_gnttab_channel_stimulus_tri:
+ break;
+ default:
+ xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc:
+ /* Interface phase two disconnecting. */
+ /* Client connected. */
+ /* Maybe messages queued. */
+ /* One of kick send /recv in progress. */
+ /* Maybe target resources busy. */
+ /* Phase two connected. */
+ switch( stimulus )
+ {
+ case xenidc_gnttab_channel_stimulus_mqr:
+ case xenidc_gnttab_channel_stimulus_sir:
+ case xenidc_gnttab_channel_stimulus_rir:
+ break;
+ case xenidc_gnttab_channel_stimulus_ksc:
+ case xenidc_gnttab_channel_stimulus_krc:
+ channel->state =
+ xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc;
+ xenidc_gnttab_channel_disconnect_client( channel );
+ xenidc_gnttab_channel_fail_out_messages( channel );
+ break;
+ case xenidc_gnttab_channel_stimulus_trc:
+ case xenidc_gnttab_channel_stimulus_tri:
+ break;
+ default:
+ xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc:
+ /* Interface phase two disconnecting. */
+ /* Client disconnecting. */
+ /* No messages queued. */
+ /* Kick send /recv idle. */
+ /* Maybe target resources busy. */
+ /* Phase two connected. */
+ switch( stimulus )
+ {
+ case xenidc_gnttab_channel_stimulus_mqr:
+ xenidc_gnttab_channel_fail_out_messages( channel );
+ break;
+ case xenidc_gnttab_channel_stimulus_sir:
+ case xenidc_gnttab_channel_stimulus_rir:
+ break;
+ case xenidc_gnttab_channel_stimulus_dcc:
+ channel->state =
+ xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc;
+ xenidc_gnttab_channel_test_target_resources( channel );
+ break;
+ case xenidc_gnttab_channel_stimulus_trc:
+ case xenidc_gnttab_channel_stimulus_tri:
+ break;
+ default:
+ xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc:
+ /* Interface phase two disconnecting. */
+ /* Client disconnected. */
+ /* No messages queued. */
+ /* Kick send /recv idle. */
+ /* Testing target resources/ target resources busy */
+ /* Phase two connected. */
+ switch( stimulus )
+ {
+ case xenidc_gnttab_channel_stimulus_sir:
+ case xenidc_gnttab_channel_stimulus_rir:
+ case xenidc_gnttab_channel_stimulus_trc:
+ break;
+ case xenidc_gnttab_channel_stimulus_tri:
+ channel->state =
+ xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri;
+ xenidc_gnttab_channel_do_phase_two_disconnect( channel );
+ break;
+ default:
+ xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri:
+ /* Interface phase two disconnecting. */
+ /* Client disconnected. */
+ /* No messages queued. */
+ /* Kick send /recv idle. */
+ /* Target resources idle. */
+ /* Phase two disconnecting. */
+ switch( stimulus )
+ {
+ case xenidc_gnttab_channel_stimulus_sir:
+ case xenidc_gnttab_channel_stimulus_rir:
+ break;
+ case xenidc_gnttab_channel_stimulus_d2c:
+ channel->state = xenidc_gnttab_channel_state_i_c1r_c1c;
+ xenidc_gnttab_channel_complete_current_callback( channel );
+ break;
+ default:
+ xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ default:
+ xenidc_gnttab_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+}
+
+static void xenidc_gnttab_channel_invalid_stimulus
+ ( xenidc_gnttab_channel * channel, xenidc_gnttab_channel_stimulus stimulus )
+{
+ trace();
+
+ printk
+ (
+ KERN_ERR "xenidc: channel %p in state %d"
+ "received invalid stimulus %d",
+ channel,
+ channel->state,
+ stimulus
+ );
+}
+
+static void xenidc_gnttab_channel_do_phase_one_connect
+ ( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &channel->do_phase_one_connect_1_work );
+}
+
+static void xenidc_gnttab_channel_do_phase_one_connect_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+ xenidc_gnttab_channel_phase_one_connect_request * request =
+ xenidc_gnttab_channel_phase_one_connect_request_callback_to
+ ( channel->current_callback );
+
+ {
+ evtchn_op_t op =
+ {
+ .cmd = EVTCHNOP_alloc_unbound,
+ .u.alloc_unbound.dom = request->remote_domain_id
+ };
+
+ BUG_ON( HYPERVISOR_event_channel_op( &op ) != 0 );
+
+ channel->send_event_channel = op.u.alloc_unbound.port;
+ }
+
+ {
+ int error = bind_evtchn_to_irqhandler
+ (
+ channel->send_event_channel,
+ xenidc_gnttab_channel_send_interrupt,
+ SA_SAMPLE_RANDOM,
+ "xenidc",
+ &channel->send_irq_context
+ );
+
+ BUG_ON( error < 0 );
+
+ channel->send_irq = error;
+ }
+
+ channel->send_ring_ref =
+ gnttab_claim_grant_reference( &channel->grant_ref_pool );
+
+ gnttab_grant_foreign_access_ref
+ (
+ channel->send_ring_ref,
+ request->remote_domain_id,
+ virt_to_mfn( channel->send_ring ),
+ 1 /* readonly */
+ );
+
+ request->send_ring_ref = channel->send_ring_ref;
+ request->send_event_channel = channel->send_event_channel;
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_c1c );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+ }
+}
+
+static void xenidc_gnttab_channel_do_phase_two_connect
+ ( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &channel->do_phase_two_connect_1_work );
+}
+
+static void xenidc_gnttab_channel_do_phase_two_connect_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+ xenidc_gnttab_channel_phase_two_connect_request * request =
+ xenidc_gnttab_channel_phase_two_connect_request_callback_to
+ ( channel->current_callback );
+
+ {
+ struct gnttab_map_grant_ref op =
+ {
+ .host_addr = (unsigned long)channel->recv_ring_area->addr,
+ .flags = GNTMAP_host_map | GNTMAP_readonly,
+ .dom = request->remote_domain_id,
+ .ref = request->recv_ring_ref
+ };
+
+ lock_vm_area( channel->recv_ring_area );
+
+ BUG_ON
+ ( HYPERVISOR_grant_table_op( GNTTABOP_map_grant_ref, &op, 1 ) );
+
+ unlock_vm_area( channel->recv_ring_area );
+
+ if( op.handle < 0 )
+ {
+ trace0( "failed to map remote page" );
+
+ goto EXIT_NO_MAPPING;
+ }
+
+ channel->recv_ring_handle = op.handle;
+ }
+
+ {
+ evtchn_op_t op =
+ {
+ .cmd = EVTCHNOP_bind_interdomain,
+ .u.bind_interdomain.remote_dom = request->remote_domain_id,
+ .u.bind_interdomain.remote_port = request->recv_event_channel
+ };
+
+ if( HYPERVISOR_event_channel_op( &op ) != 0 )
+ {
+ trace0( "failed to bind to remote event channel" );
+
+ goto EXIT_NO_BIND;
+ }
+
+ channel->recv_event_channel = op.u.bind_interdomain.local_port;
+ }
+
+ channel->recv_irq = bind_evtchn_to_irqhandler
+ (
+ channel->recv_event_channel,
+ xenidc_gnttab_channel_recv_interrupt,
+ 0,
+ "xenidc",
+ &channel->recv_irq_context
+ );
+
+ if( channel->recv_irq < 0 )
+ {
+ trace0( "failed to bind remote irq" );
+
+ goto EXIT_NO_IRQ;
+ }
+
+ channel->recv_ring_lbr = xenidc_vaddress_create_lbr
+ (
+ (
+ (xenidc_channel_ring_header *)
+ channel->recv_ring_area->addr
+ ) + 1,
+ PAGE_SIZE - sizeof( xenidc_channel_ring_header )
+ );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_c2s );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+
+ return;
+
+ EXIT_NO_IRQ:
+
+ {
+ evtchn_op_t op =
+ {
+ .cmd = EVTCHNOP_close,
+ .u.close.port = channel->recv_event_channel
+ };
+
+ BUG_ON( HYPERVISOR_event_channel_op( &op ) != 0 );
+ }
+
+ EXIT_NO_BIND:
+
+ {
+ struct gnttab_unmap_grant_ref op;
+
+ op.host_addr = (unsigned long)channel->recv_ring_area->addr;
+ op.handle = channel->recv_ring_handle;
+ op.dev_bus_addr = 0;
+
+ lock_vm_area( channel->recv_ring_area );
+
+ BUG_ON
+ (
+ HYPERVISOR_grant_table_op( GNTTABOP_unmap_grant_ref, &op, 1 )
+ );
+
+ unlock_vm_area( channel->recv_ring_area );
+ }
+
+ EXIT_NO_MAPPING:
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_c2f );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+ }
+}
+
+static void xenidc_gnttab_channel_connect_client
+ ( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &channel->connect_client_1_work );
+}
+
+static void xenidc_gnttab_channel_connect_client_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+ xenidc_channel_connect( &channel->channel );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_ccc );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+ }
+}
+
+static void xenidc_gnttab_channel_disconnect_client
+ ( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &channel->disconnect_client_1_work );
+}
+
+static void xenidc_gnttab_channel_disconnect_client_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+ xenidc_channel_disconnect
+ ( &channel->channel, &channel->disconnect_client_2_callback );
+ }
+}
+
+static void xenidc_gnttab_channel_disconnect_client_2
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_gnttab_channel * channel = container_of
+ ( callback, xenidc_gnttab_channel, disconnect_client_2_callback );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_dcc );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+static void xenidc_gnttab_channel_do_phase_two_disconnect
+ ( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &channel->do_phase_two_disconnect_1_work );
+}
+
+static void xenidc_gnttab_channel_do_phase_two_disconnect_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+ unbind_evtchn_from_irqhandler
+ ( channel->recv_irq, &channel->recv_irq_context );
+
+ {
+ struct gnttab_unmap_grant_ref op;
+
+ op.host_addr = (unsigned long)channel->recv_ring_area->addr;
+ op.handle = channel->recv_ring_handle;
+ op.dev_bus_addr = 0;
+
+ lock_vm_area( channel->recv_ring_area );
+
+ BUG_ON
+ (
+ HYPERVISOR_grant_table_op( GNTTABOP_unmap_grant_ref, &op, 1 )
+ );
+
+ unlock_vm_area( channel->recv_ring_area );
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_d2c );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+ }
+}
+
+static void xenidc_gnttab_channel_do_phase_one_disconnect
+ ( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &channel->do_phase_one_disconnect_1_work );
+}
+
+static void xenidc_gnttab_channel_do_phase_one_disconnect_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+ gnttab_end_foreign_access_ref( channel->send_ring_ref, 1 );
+
+ /* FIXME: need to extend grant-tables API so we can wait for other */
+ /* side to stop referencing page. */
+
+ gnttab_release_grant_reference
+ ( &channel->grant_ref_pool, channel->send_ring_ref );
+
+ unbind_evtchn_from_irqhandler
+ ( channel->send_irq, &channel->send_irq_context );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_d1c );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+ }
+}
+
+static void xenidc_gnttab_channel_kick_send_ring
+ ( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ if( !channel->send_ring_kick_out )
+ {
+ channel->send_ring_kick_out = 1;
+
+ (void)xenidc_work_schedule( &channel->kick_send_ring_1_work );
+ }
+}
+
+static void xenidc_gnttab_channel_kick_send_ring_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+ int notify = 0;
+
+ xenidc_local_buffer_reference ring_lbr;
+ xenidc_local_buffer_reference wrapping_lbr;
+ xenidc_channel_message * message;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ channel->send_ring_kick_out = 0;
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+
+ /* Create a reference to the send ring buffer. */
+
+ ring_lbr = xenidc_vaddress_create_lbr
+ (
+ ( (xenidc_channel_ring_header *)channel->send_ring ) + 1,
+ PAGE_SIZE - sizeof( xenidc_channel_ring_header )
+ );
+
+ /* Create a reference to the free space in the send ring buffer. */
+ /* We use a wrapping reference to the above buffer so that we can */
+ /* copy into the buffer and wrap automatically. */
+
+ wrapping_lbr = xenidc_wrapping_create_lbr
+ (
+ &ring_lbr,
+ ( (xenidc_channel_ring_header *)channel->send_ring )->
+ this_ring_producer_offset,
+ (
+ (xenidc_channel_ring_header *)
+ channel->recv_ring_area->addr
+ )
+ ->other_ring_consumer_offset,
+ xenidc_wrapping_client_type_producer
+ );
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ while
+ (
+ ( !list_empty( &channel->message_list ) )
+ &&
+ (
+ xenidc_local_buffer_reference_query_byte_count( &wrapping_lbr )
+ >
+ (
+ sizeof( xenidc_channel_ring_element_header )
+ +
+ xenidc_local_buffer_reference_query_byte_count
+ (
+ &
+ (
+ message = list_entry
+ (
+ channel->message_list.next,
+ xenidc_channel_message,
+ XENIDC_CHANNEL_MESSAGE_LINK
+ )
+ )
+ ->message_lbr
+ )
+ )
+ )
+ )
+ {
+ list_del_init( xenidc_channel_message_to_link( message ) );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+
+ {
+ xenidc_channel_ring_element_header header;
+ xenidc_local_buffer_reference header_lbr;
+ xenidc_concatenate_base base;
+ xenidc_local_buffer_reference element_lbr;
+
+ memset( &header, 0, sizeof( header ) );
+
+ header.length = xenidc_local_buffer_reference_query_byte_count
+ ( &message->message_lbr );
+
+ header_lbr =
+ xenidc_vaddress_create_lbr( &header, sizeof( header ) );
+
+ element_lbr = xenidc_concatenate_create_lbr
+ ( &base, &header_lbr, &message->message_lbr );
+
+ xenidc_local_buffer_reference_advance
+ (
+ &wrapping_lbr,
+ xenidc_local_buffer_reference_copy
+ ( &wrapping_lbr, &element_lbr )
+ );
+ }
+
+ xenidc_callback_success
+ ( xenidc_channel_message_to_callback( message ) );
+
+ notify = 1;
+
+ spin_lock_irqsave( &channel->lock, flags );
+ }
+
+ channel->send_ring_kick_out = 0;
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+
+ if( notify )
+ {
+ wmb(); /* Ensure contents of ring written before offset updated. */
+
+ ( (xenidc_channel_ring_header *)channel->send_ring )->
+ this_ring_producer_offset =
+ xenidc_local_buffer_reference_query_byte_offset
+ ( &wrapping_lbr );
+
+ notify_remote_via_irq( channel->send_irq );
+ }
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ if( !channel->send_ring_kick_out )
+ {
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_ksc );
+ }
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+static void xenidc_gnttab_channel_kick_recv_ring
+ ( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ if( !channel->recv_ring_kick_out )
+ {
+ channel->recv_ring_kick_out = 1;
+
+ (void)xenidc_work_schedule( &channel->kick_recv_ring_1_work );
+ }
+}
+
+static void xenidc_gnttab_channel_kick_recv_ring_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data;
+
+ int error = 0;
+
+ xenidc_local_buffer_reference wrapping_lbr;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ channel->recv_ring_kick_out = 0;
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+
+ /* Create a reference to the elements in the recv ring buffer. */
+ /* We use a wrapping reference to the buffer so that we can copy out */
+ /* of the buffer and wrap automatically. */
+
+ wrapping_lbr = xenidc_wrapping_create_lbr
+ (
+ &channel->recv_ring_lbr,
+ channel->recv_ring_offset,
+ (
+ (xenidc_channel_ring_header *)
+ channel->recv_ring_area->addr
+ )
+ ->this_ring_producer_offset,
+ xenidc_wrapping_client_type_consumer
+ );
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ rmb(); /* Ensure we see latest data for contents of wrapping buffer. */
+
+ while
+ (
+ channel->target_resource_free[ channel->next_target_resource ]
+ &&
+ (
+ xenidc_local_buffer_reference_query_byte_count( &wrapping_lbr )
+ !=
+ 0
+ )
+ )
+ {
+ xenidc_local_buffer_reference element = wrapping_lbr;
+
+ xenidc_gnttab_channel_target_resource * resource =
+ &channel->target_resources[ channel->next_target_resource ];
+
+ {
+ xenidc_channel_ring_element_header header;
+
+ if
+ (
+ (
+ xenidc_local_buffer_reference_copy_out
+ ( &wrapping_lbr, &header, sizeof( header ) )
+ ==
+ sizeof( header )
+ )
+ &&
+ (
+ xenidc_local_buffer_reference_subrange
+ ( &element, sizeof( header ), header.length )
+ ==
+ header.length
+ )
+ )
+ {
+ xenidc_local_buffer_reference_advance
+ ( &wrapping_lbr, sizeof( header ) + header.length );
+
+ channel->target_resource_free
+ [ channel->next_target_resource ] = 0;
+
+ channel->target_resource_offset
+ [ channel->next_target_resource ] =
+ xenidc_local_buffer_reference_query_byte_offset
+ ( &wrapping_lbr );
+ if
+ (
+ ++channel->next_target_resource
+ ==
+ XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT
+ )
+ {
+ channel->next_target_resource = 0;
+ }
+ }
+ else
+ {
+ error = 1;
+
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+
+ {
+ xenidc_channel_message * message =
+ xenidc_gnttab_channel_target_resource_to_message( resource );
+
+ xenidc_channel_message_set_message_lbr( message, element );
+
+ xenidc_channel_handle_message( &channel->channel, message );
+ }
+
+ spin_lock_irqsave( &channel->lock, flags );
+ }
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+
+ channel->recv_ring_offset =
+ xenidc_local_buffer_reference_query_byte_offset( &wrapping_lbr );
+
+ if( error )
+ {
+ channel->protocol_error( channel );
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ if( !channel->recv_ring_kick_out )
+ {
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_krc );
+ }
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+ }
+}
+
+static void xenidc_gnttab_channel_kick_recv_ring_2
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_gnttab_channel_target_resource * resource =
+ xenidc_gnttab_channel_target_resource_callback_to( callback );
+
+ xenidc_gnttab_channel * channel =
+ xenidc_gnttab_channel_target_resource_query_channel( resource );
+
+ int current_target_resource =
+ (
+ (
+ ( (unsigned long)resource )
+ -
+ ( (unsigned long)&channel->target_resources[ 0 ] )
+ )
+ /
+ sizeof( xenidc_gnttab_channel_target_resource )
+ );
+
+ if( xenidc_callback_query_error( callback ) != XENIDC_ERROR_SUCCESS )
+ {
+ channel->protocol_error( channel );
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ channel->target_resource_free[ current_target_resource ] = 1;
+
+ if( current_target_resource == channel->first_target_resource )
+ {
+ u16 offset;
+
+ do
+ {
+ offset = channel->target_resource_offset
+ [ channel->first_target_resource ];
+
+ if
+ (
+ ++channel->first_target_resource
+ ==
+ XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT
+ )
+ {
+ channel->first_target_resource = 0;
+ }
+ }
+ while
+ (
+ channel->target_resource_free
+ [ channel->first_target_resource ]
+ &&
+ (
+ channel->first_target_resource
+ !=
+ channel->next_target_resource
+ )
+ );
+
+ mb(); /* Ensure reads complete before we free space. */
+
+ ( (xenidc_channel_ring_header *)channel->send_ring )->
+ other_ring_consumer_offset = offset;
+
+ notify_remote_via_irq( channel->recv_irq );
+
+ if
+ (
+ !channel->target_resource_free
+ [ channel->first_target_resource ]
+ )
+ {
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_trc );
+ }
+ else
+ {
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_tri );
+ }
+ }
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+ }
+}
+
+static void xenidc_gnttab_channel_complete_current_callback
+ ( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ xenidc_callback_success( channel->current_callback );
+}
+
+static void xenidc_gnttab_channel_fail_current_callback
+ ( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ xenidc_callback_complete
+ ( channel->current_callback, XENIDC_ERROR_FAILURE );
+}
+
+static void xenidc_gnttab_channel_fail_out_messages
+ ( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ while( !list_empty( &channel->message_list ) )
+ {
+ xenidc_channel_message * message = list_entry
+ (
+ channel->message_list.next,
+ xenidc_channel_message,
+ XENIDC_CHANNEL_MESSAGE_LINK
+ );
+
+ list_del_init( xenidc_channel_message_to_link( message ) );
+
+ xenidc_callback_success
+ ( xenidc_channel_message_to_callback( message ) );
+ }
+}
+
+static void xenidc_gnttab_channel_test_target_resources
+ ( xenidc_gnttab_channel * channel )
+{
+ trace();
+
+ if( channel->target_resource_free[ channel->first_target_resource ] )
+ {
+ xenidc_gnttab_channel_handle_stimulus
+ ( channel, xenidc_gnttab_channel_stimulus_tri );
+ }
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gnttab_channel_enumeration.dot
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gnttab_channel_enumeration.dot Sun Oct 30 16:03:34 2005
@@ -0,0 +1,55 @@
+digraph enumeration {
+size="7,7"
+
+i[style=filled,fillcolor=green]
+i->i_c1r[label="c1r\ndo_phase_one_connect"]
+
+i_c1r[style=filled,fillcolor=green]
+i_c1r->i_c1r[label="sir"]
+i_c1r->i_c1r_c1c[label="c1c\ncomplete_current_callback"]
+
+i_c1r_c1c[style=filled,fillcolor=green]
+i_c1r_c1c->i_c1r_c1c_c2r[label="c2r\ndo_phase_two_connect"]
+i_c1r_c1c->i_c1r_c1c_d1r[label="d1r\ndo_phase_one_disconnect"]
+i_c1r_c1c->i_c1r_c1c[label="sir"]
+
+i_c1r_c1c_c2r[style=filled,fillcolor=green]
+i_c1r_c1c_c2r->i_c1r_c1c_c2r[label="sir/rir"]
+i_c1r_c1c_c2r->i_c1r_c1c_c2r_c2s[label="c2s\nconnect_client"]
+i_c1r_c1c_c2r->i_c1r_c1c[label="c2f\nfail_current_callback"]
+
+i_c1r_c1c_d1r[style=filled,fillcolor=orange]
+i_c1r_c1c_d1r->i_c1r_c1c_d1r[label="sir"]
+i_c1r_c1c_d1r->i[label="d1c\ncomplete_current_callback"]
+
+i_c1r_c1c_c2r_c2s[style=filled,fillcolor=green]
+i_c1r_c1c_c2r_c2s->i_c1r_c1c_c2r_c2s[label="mqr/sir/rir"]
+i_c1r_c1c_c2r_c2s->i_c1r_c1c_c2r_c2s_ccc[label="ccc\ncomplete_current_callback\nkick_send_ring\nkick_recv_ring"]
+
+i_c1r_c1c_c2r_c2s_ccc[style=filled,fillcolor=green]
+i_c1r_c1c_c2r_c2s_ccc->i_c1r_c1c_c2r_c2s_ccc[label="mqr/sir\nkick_send_ring"]
+i_c1r_c1c_c2r_c2s_ccc->i_c1r_c1c_c2r_c2s_ccc[label="rir/trc/tri\nkick_recv_ring"]
+i_c1r_c1c_c2r_c2s_ccc->i_c1r_c1c_c2r_c2s_ccc[label="ksc/krc/trb"]
+i_c1r_c1c_c2r_c2s_ccc->i_c1r_c1c_c2r_c2s_ccc_d2r[label="d2r\nkick_send_ring\nkick_recv_ring"]
+
+i_c1r_c1c_c2r_c2s_ccc_d2r[style=filled,fillcolor=orange]
+i_c1r_c1c_c2r_c2s_ccc_d2r->i_c1r_c1c_c2r_c2s_ccc_d2r[label="mqr/sir/rir/trb/trc/tri"]
+i_c1r_c1c_c2r_c2s_ccc_d2r->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc[label="ksc/krc"]
+
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc[style=filled,fillcolor=orange]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc[label="mqr/sir/rir/trb/trc/tri"]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc[label="ksc/krc\ndisconnect_client\nfail_out_messages"]
+
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc[style=filled,fillcolor=orange]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc[label="mqr\nfail_out_messages"]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc[label="sir/rir/trc/tri"]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc[label="dcc\ntest_target_resources"]
+
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc[style=filled,fillcolor=orange]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc[label="sir/rir/trc"]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri[label="tri\nphase_two_disconnect"]
+
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri[style=filled,fillcolor=orange]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri->i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri[label="sir/rir"]
+i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri->i_c1r_c1c[label="d2c\ncomplete_current_callback"]
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_local_buffer_reference.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_local_buffer_reference.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,618 @@
+/*****************************************************************************/
+/* Xen inter-domain communication local buffer references. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#include <asm-xen/xenidc.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include "xenidc_trace.h"
+
+#ifdef MIN
+#undef MIN
+#endif
+
+#define MIN( X, Y ) ( ( (X) < (Y) ) ? (X) : (Y) )
+
+#define XENIDC_BUFFER_HASH_COUNT 255
+
+static DEFINE_RWLOCK( xenidc_local_buffer_reference_lock );
+
+static struct list_head
+ xenidc_buffer_concrete_hash[ XENIDC_BUFFER_HASH_COUNT ];
+
+static struct list_head
+ xenidc_buffer_copy_hash[ XENIDC_BUFFER_HASH_COUNT ];
+
+static struct list_head
+ xenidc_buffer_virtual_hash[ XENIDC_BUFFER_HASH_COUNT ];
+
+static void xenidc_local_buffer_reference_init( void )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ write_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+ {
+ static int initialised = 0;
+
+ if( !initialised )
+ {
+ int i;
+
+ for( i = 0; i < XENIDC_BUFFER_HASH_COUNT; i++ )
+ {
+ INIT_LIST_HEAD( &xenidc_buffer_concrete_hash[ i ] );
+ INIT_LIST_HEAD( &xenidc_buffer_copy_hash[ i ] );
+ INIT_LIST_HEAD( &xenidc_buffer_virtual_hash[ i ] );
+ }
+
+ initialised = 1;
+ }
+ }
+
+ write_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+ }
+}
+
+static void xenidc_local_buffer_reference_default_zero
+(
+ xenidc_buffer_concrete_class * class,
+ xenidc_local_buffer_reference * lbr
+)
+{
+ trace();
+
+ {
+ u8 buffer[ 64 ];
+
+ xenidc_local_buffer_reference temp_lbr = *lbr;
+
+ memset( buffer, 0, 64 );
+
+ do
+ {
+ xenidc_buffer_byte_count this_go = MIN( temp_lbr.byte_count, 64 );
+
+ class->copy_in_or_out( class, &temp_lbr, buffer, this_go, 0 );
+
+ xenidc_local_buffer_reference_advance( &temp_lbr, this_go );
+ }
+ while( temp_lbr.byte_count != 0 );
+ }
+}
+
+xenidc_buffer_type xenidc_local_buffer_reference_register_buffer_concrete_class
+(
+ xenidc_buffer_concrete_class * class,
+ void ( * copy_in_or_out )
+ (
+ xenidc_buffer_concrete_class * class,
+ xenidc_local_buffer_reference * lbr,
+ void * buffer,
+ xenidc_buffer_byte_count byte_count,
+ int out
+ ),
+ void ( * zero )
+ (
+ xenidc_buffer_concrete_class * class,
+ xenidc_local_buffer_reference * lbr
+ )
+)
+{
+ trace();
+
+ xenidc_local_buffer_reference_init();
+
+ INIT_LIST_HEAD( &class->link );
+
+ class->copy_in_or_out = copy_in_or_out;
+ class->zero = ( zero != NULL ) ?
+ zero : xenidc_local_buffer_reference_default_zero;
+
+ {
+ unsigned long flags;
+
+ write_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+ {
+ static xenidc_buffer_type type_index = 0;
+
+ class->type = ++type_index;
+ }
+
+ {
+ int i = ( class->type % XENIDC_BUFFER_HASH_COUNT );
+
+ list_add_tail( &class->link, &xenidc_buffer_concrete_hash[ i ] );
+ }
+
+ write_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+ }
+
+ return class->type;
+}
+
+static inline xenidc_buffer_concrete_class *
+ xenidc_local_buffer_reference_find_concrete_class( xenidc_buffer_type type )
+{
+ trace();
+
+ {
+ int i = type % XENIDC_BUFFER_HASH_COUNT;
+
+ xenidc_buffer_concrete_class * class;
+
+ unsigned long flags;
+
+ read_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+ list_for_each_entry( class, &xenidc_buffer_concrete_hash[ i ], link )
+ {
+ if( class->type == type )
+ {
+ read_unlock_irqrestore
+ ( &xenidc_local_buffer_reference_lock, flags );
+
+ return class;
+ }
+ }
+
+ read_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+
+ BUG();
+
+ return NULL;
+ }
+}
+
+void xenidc_local_buffer_reference_register_buffer_copy_class
+(
+ xenidc_buffer_copy_class * class,
+ xenidc_buffer_type target_type,
+ xenidc_buffer_type source_type,
+ void ( * copy )
+ (
+ xenidc_buffer_copy_class * class,
+ xenidc_local_buffer_reference * target,
+ xenidc_local_buffer_reference * source,
+ xenidc_buffer_byte_count byte_count
+ )
+)
+{
+ trace();
+
+ INIT_LIST_HEAD( &class->link );
+
+ class->target_type = target_type;
+ class->source_type = source_type;
+ class->copy = copy;
+
+ {
+ unsigned long flags;
+
+ write_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+ {
+ int i =
+ (
+ ( class->target_type << 16 | class->source_type )
+ %
+ XENIDC_BUFFER_HASH_COUNT
+ );
+
+ list_add_tail( &class->link, &xenidc_buffer_copy_hash[ i ] );
+ }
+
+ write_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+ }
+}
+
+static inline xenidc_buffer_copy_class *
+ xenidc_local_buffer_reference_find_copy_class
+ ( xenidc_buffer_type target_type, xenidc_buffer_type source_type )
+{
+ trace();
+
+ {
+ int i =
+ ( ( target_type << 16 | source_type ) % XENIDC_BUFFER_HASH_COUNT );
+
+ xenidc_buffer_copy_class * class;
+
+ unsigned long flags;
+
+ read_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+ list_for_each_entry( class, &xenidc_buffer_copy_hash[ i ], link )
+ {
+ if
+ (
+ ( class->target_type == target_type )
+ &&
+ ( class->source_type == source_type )
+ )
+ {
+ read_unlock_irqrestore
+ ( &xenidc_local_buffer_reference_lock, flags );
+
+ return class;
+ }
+ }
+
+ read_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+
+ return NULL;
+ }
+}
+
+xenidc_buffer_type xenidc_local_buffer_reference_register_buffer_virtual_class
+(
+ xenidc_buffer_virtual_class * class,
+ xenidc_local_buffer_reference ( * resolve )
+ (
+ xenidc_buffer_virtual_class * class,
+ xenidc_local_buffer_reference * lbr
+ ),
+ void ( * advance )
+ (
+ xenidc_buffer_virtual_class * class,
+ xenidc_local_buffer_reference * lbr,
+ xenidc_buffer_byte_count byte_count
+ )
+)
+{
+ trace();
+
+ xenidc_local_buffer_reference_init();
+
+ INIT_LIST_HEAD( &class->link );
+
+ class->resolve = resolve;
+ class->advance = advance;
+
+ {
+ unsigned long flags;
+
+ write_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+ {
+ static xenidc_buffer_type type_index = 0;
+
+ class->type =
+ (
+ ++type_index
+ |
+ XENIDC_LOCAL_BUFFER_REFERENCE_TYPE_FLAG_VIRTUAL
+ |
+ (
+ ( advance != NULL )
+ ? XENIDC_LOCAL_BUFFER_REFERENCE_TYPE_FLAG_VIRTUAL_ADVANCE
+ : 0
+ )
+ );
+ }
+
+ {
+ int i = ( class->type % XENIDC_BUFFER_HASH_COUNT );
+
+ list_add_tail( &class->link, &xenidc_buffer_virtual_hash[ i ] );
+ }
+
+ write_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+ }
+
+ return class->type;
+}
+
+static inline xenidc_buffer_virtual_class *
+ xenidc_local_buffer_reference_find_virtual_class( xenidc_buffer_type type )
+{
+ trace();
+
+ {
+ int i = type % XENIDC_BUFFER_HASH_COUNT;
+
+ xenidc_buffer_virtual_class * class;
+
+ unsigned long flags;
+
+ read_lock_irqsave( &xenidc_local_buffer_reference_lock, flags );
+
+ list_for_each_entry( class, &xenidc_buffer_virtual_hash[ i ], link )
+ {
+ if( class->type == type )
+ {
+ read_unlock_irqrestore
+ ( &xenidc_local_buffer_reference_lock, flags );
+
+ return class;
+ }
+ }
+
+ read_unlock_irqrestore( &xenidc_local_buffer_reference_lock, flags );
+
+ BUG();
+
+ return NULL;
+ }
+}
+
+static xenidc_local_buffer_reference xenidc_local_buffer_reference_resolve
+ ( xenidc_local_buffer_reference * lbr )
+{
+ trace();
+
+ {
+ xenidc_local_buffer_reference resolved_lbr = *lbr;
+
+ while( 1 )
+ {
+ if
+ (
+ (
+ resolved_lbr.type
+ &
+ XENIDC_LOCAL_BUFFER_REFERENCE_TYPE_FLAG_VIRTUAL
+ )
+ ==
+ 0
+ )
+ {
+ return resolved_lbr;
+ }
+ else
+ {
+ xenidc_buffer_virtual_class * class =
+ xenidc_local_buffer_reference_find_virtual_class
+ ( resolved_lbr.type );
+
+ resolved_lbr = class->resolve( class, &resolved_lbr );
+ }
+ }
+ }
+}
+
+xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_in_or_out
+(
+ xenidc_local_buffer_reference * lbr,
+ void * buffer,
+ xenidc_buffer_byte_count buffer_byte_count,
+ int out
+)
+{
+ trace();
+
+ {
+ /* Total amount to copy is the smaller of the two buffers. */
+
+ xenidc_buffer_byte_count byte_count =
+ MIN( lbr->byte_count, buffer_byte_count );
+
+ xenidc_buffer_byte_count remainder_offset = 0;
+ xenidc_buffer_byte_count remainder_count = byte_count;
+
+ xenidc_local_buffer_reference top_lbr = *lbr;
+
+ while( remainder_count != 0 )
+ {
+ /* top_lbr might be virtual so we resolve it to get a concrete */
+ /* lbr for the first contiguous chunk of top_lbr. */
+
+ xenidc_local_buffer_reference resolved_lbr =
+ xenidc_local_buffer_reference_resolve( &top_lbr );
+
+ /* resolved_lbr is guaranteed to be concrete so we can look up */
+ /* its copy method. */
+
+ xenidc_buffer_concrete_class * class =
+ xenidc_local_buffer_reference_find_concrete_class
+ ( resolved_lbr.type );
+
+ /* Amount to copy this go may be restricted by the size of the */
+ /* resolved lbr. */
+
+ xenidc_buffer_byte_count this_go =
+ MIN( resolved_lbr.byte_count, remainder_count );
+
+ class->copy_in_or_out
+ (
+ class,
+ &resolved_lbr,
+ ( (char *)buffer ) + remainder_offset,
+ this_go,
+ out
+ );
+
+ remainder_offset += this_go;
+ remainder_count -= this_go;
+
+ xenidc_local_buffer_reference_advance( &top_lbr, this_go );
+ }
+
+ return byte_count;
+ }
+}
+
+void xenidc_local_buffer_reference_zero( xenidc_local_buffer_reference * lbr )
+{
+ trace();
+
+ {
+ xenidc_local_buffer_reference top_lbr = *lbr;
+
+ while( top_lbr.byte_count != 0 )
+ {
+ /* top_lbr might be virtual so we resolve it to get a concrete */
+ /* lbr for the first contiguous chunk of top_lbr. */
+
+ xenidc_local_buffer_reference resolved_lbr =
+ xenidc_local_buffer_reference_resolve( &top_lbr );
+
+ xenidc_buffer_concrete_class * class =
+ xenidc_local_buffer_reference_find_concrete_class
+ ( resolved_lbr.type );
+
+ class->zero( class, &resolved_lbr );
+
+ xenidc_local_buffer_reference_advance
+ ( &top_lbr, resolved_lbr.byte_count );
+ }
+ }
+}
+
+xenidc_buffer_byte_count xenidc_local_buffer_reference_copy
+(
+ xenidc_local_buffer_reference * target,
+ xenidc_local_buffer_reference * source
+)
+{
+ trace();
+
+ {
+ /* Total amount to copy is the smaller of the two buffers. */
+
+ xenidc_buffer_byte_count byte_count =
+ MIN( target->byte_count, source->byte_count );
+
+ xenidc_local_buffer_reference top_target_lbr = *target;
+ xenidc_local_buffer_reference top_source_lbr = *source;
+
+ xenidc_buffer_byte_count remainder_count = byte_count;
+
+ while( remainder_count != 0 )
+ {
+ xenidc_local_buffer_reference resolved_target_lbr =
+ xenidc_local_buffer_reference_resolve( &top_target_lbr );
+
+ xenidc_local_buffer_reference resolved_source_lbr =
+ xenidc_local_buffer_reference_resolve( &top_source_lbr );
+
+ xenidc_buffer_byte_count this_go = MIN
+ (
+ resolved_target_lbr.byte_count,
+ resolved_source_lbr.byte_count
+ );
+
+ xenidc_buffer_copy_class * copy_class =
+ xenidc_local_buffer_reference_find_copy_class
+ ( resolved_target_lbr.type, resolved_source_lbr.type );
+
+ if( copy_class != NULL )
+ {
+ copy_class->copy
+ (
+ copy_class,
+ &resolved_target_lbr,
+ &resolved_source_lbr,
+ this_go
+ );
+ }
+ else
+ {
+ u8 buffer[ 64 ];
+
+ xenidc_buffer_concrete_class * target_concrete_class =
+ xenidc_local_buffer_reference_find_concrete_class
+ ( resolved_target_lbr.type );
+
+ xenidc_buffer_concrete_class * source_concrete_class =
+ xenidc_local_buffer_reference_find_concrete_class
+ ( resolved_source_lbr.type );
+
+ xenidc_local_buffer_reference temp_target =
+ resolved_target_lbr;
+ xenidc_local_buffer_reference temp_source =
+ resolved_source_lbr;
+
+ xenidc_buffer_byte_count nested_remainder_count = this_go;
+
+ do
+ {
+ xenidc_buffer_byte_count nested_this_go =
+ MIN( 64, nested_remainder_count );
+
+ source_concrete_class->copy_in_or_out
+ (
+ source_concrete_class,
+ &temp_source,
+ buffer,
+ nested_this_go,
+ 1
+ );
+
+ target_concrete_class->copy_in_or_out
+ (
+ target_concrete_class,
+ &temp_target,
+ buffer,
+ nested_this_go,
+ 0
+ );
+
+ xenidc_local_buffer_reference_advance
+ ( &temp_target, nested_this_go );
+
+ xenidc_local_buffer_reference_advance
+ ( &temp_source, nested_this_go );
+
+ nested_remainder_count -= nested_this_go;
+ }
+ while( nested_remainder_count != 0 );
+ }
+
+ xenidc_local_buffer_reference_advance( &top_target_lbr, this_go );
+ xenidc_local_buffer_reference_advance( &top_source_lbr, this_go );
+
+ remainder_count -= this_go;
+ }
+
+ return byte_count;
+ }
+}
+
+xenidc_buffer_byte_count xenidc_local_buffer_reference_virtual_advance
+ ( xenidc_local_buffer_reference * lbr, xenidc_buffer_byte_count byte_count )
+{
+ trace();
+
+ {
+ xenidc_buffer_byte_count actual_byte_count =
+ MIN( lbr->byte_count, byte_count );
+
+ xenidc_buffer_virtual_class * class =
+ xenidc_local_buffer_reference_find_virtual_class( lbr->type );
+
+ class->advance( class, lbr, actual_byte_count );
+
+ return actual_byte_count;
+ }
+}
+
+EXPORT_SYMBOL( xenidc_local_buffer_reference_register_buffer_concrete_class );
+EXPORT_SYMBOL( xenidc_local_buffer_reference_register_buffer_copy_class );
+EXPORT_SYMBOL( xenidc_local_buffer_reference_register_buffer_virtual_class );
+EXPORT_SYMBOL( xenidc_local_buffer_reference_copy_in_or_out );
+EXPORT_SYMBOL( xenidc_local_buffer_reference_zero );
+EXPORT_SYMBOL( xenidc_local_buffer_reference_copy );
+EXPORT_SYMBOL( xenidc_local_buffer_reference_virtual_advance );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_mapper_pool.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_mapper_pool.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,80 @@
+/*****************************************************************************/
+/* Xen remote buffer reference mapper pool. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#include <asm-xen/xenidc.h>
+#include <linux/module.h>
+#include "xenidc_trace.h"
+
+xenidc_rbr_mapper_pool * xenidc_allocate_rbr_mapper_pool
+ ( u32 anti_deadlock_page_count )
+{
+ trace();
+
+ /* FIXME */
+
+ return 1;
+}
+
+void xenidc_free_rbr_mapper_pool( xenidc_rbr_mapper_pool * pool )
+{
+ trace();
+
+ /* FIXME */
+}
+
+void xenidc_rbr_mapper_pool_reserve_and_map_rbrs
+(
+ xenidc_rbr_mapper_pool * pool,
+ xenidc_reserve_and_map_rbr_request * request
+)
+{
+ trace();
+
+ /* FIXME */
+}
+
+void xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs
+(
+ xenidc_rbr_mapper_pool * pool,
+ xenidc_reserve_and_map_rbr_request * request
+)
+{
+ trace();
+
+ /* FIXME */
+}
+
+void xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs
+(
+ xenidc_rbr_mapper_pool * pool,
+ xenidc_reserve_and_map_rbr_request * request
+)
+{
+ trace();
+
+ /* FIXME */
+}
+
+EXPORT_SYMBOL( xenidc_allocate_rbr_mapper_pool );
+EXPORT_SYMBOL( xenidc_free_rbr_mapper_pool );
+EXPORT_SYMBOL( xenidc_rbr_mapper_pool_reserve_and_map_rbrs );
+EXPORT_SYMBOL( xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs );
+EXPORT_SYMBOL( xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_provider_pool.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_provider_pool.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,80 @@
+/*****************************************************************************/
+/* Xen remote buffer reference provider pool. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#include <asm-xen/xenidc.h>
+#include <linux/module.h>
+#include "xenidc_trace.h"
+
+xenidc_rbr_provider_pool * xenidc_allocate_rbr_provider_pool
+ ( u32 anti_deadlock_page_count )
+{
+ trace();
+
+ /* FIXME */
+
+ return 1;
+}
+
+void xenidc_free_rbr_provider_pool( xenidc_rbr_provider_pool * pool )
+{
+ trace();
+
+ /* FIXME */
+}
+
+void xenidc_rbr_provider_pool_reserve_and_create_rbrs
+(
+ xenidc_rbr_provider_pool * pool,
+ xenidc_reserve_and_create_rbr_request * request
+)
+{
+ trace();
+
+ /* FIXME */
+}
+
+void xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs
+(
+ xenidc_rbr_provider_pool * pool,
+ xenidc_reserve_and_create_rbr_request * request
+)
+{
+ trace();
+
+ /* FIXME */
+}
+
+void xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs
+(
+ xenidc_rbr_provider_pool * pool,
+ xenidc_reserve_and_create_rbr_request * request
+)
+{
+ trace();
+
+ /* FIXME */
+}
+
+EXPORT_SYMBOL( xenidc_allocate_rbr_provider_pool );
+EXPORT_SYMBOL( xenidc_free_rbr_provider_pool );
+EXPORT_SYMBOL( xenidc_rbr_provider_pool_reserve_and_create_rbrs );
+EXPORT_SYMBOL( xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs );
+EXPORT_SYMBOL( xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_trace.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_trace.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,54 @@
+/*****************************************************************************/
+/* Simple trace macros. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef XENIDC_TRACE_H
+#define XENIDC_TRACE_H
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_XEN_IDC_TRACE
+
+#define trace0( format ) \
+printk( KERN_INFO "xenidc %s:" format "\n", __PRETTY_FUNCTION__ )
+
+#define trace1( format, a0 ) \
+printk( KERN_INFO "xenidc %s:" format "\n", __PRETTY_FUNCTION__, a0 )
+
+#define trace2( format, a0, a1 ) \
+printk( KERN_INFO "xenidc %s:" format "\n", __PRETTY_FUNCTION__, a0, a1 )
+
+#define trace3( format, a0, a1, a2 ) \
+printk( KERN_INFO "xenidc %s:" format "\n", __PRETTY_FUNCTION__, a0, a1, a2 )
+
+#define trace() trace0( "" )
+
+#else
+
+#define trace0( format )
+#define trace1( format,a0 )
+#define trace2( format,a0, a1 )
+#define trace3( format,a0, a1, a2 )
+#define trace()
+
+#endif
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_vaddress.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_vaddress.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,129 @@
+/*****************************************************************************/
+/* Xen inter-domain communication vaddress local buffer reference type. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#include <asm-xen/xenidc_vaddress.h>
+#include <linux/module.h>
+#include "xenidc_trace.h"
+
+static xenidc_buffer_type xenidc_vaddress_type;
+
+static void xenidc_vaddress_copy_in_or_out
+(
+ xenidc_buffer_concrete_class * class,
+ xenidc_local_buffer_reference * lbr,
+ void * buffer,
+ xenidc_buffer_byte_count byte_count,
+ int out
+)
+{
+ trace();
+
+ if( out )
+ {
+ memcpy( buffer, ( (char *)lbr->base ) + lbr->byte_offset, byte_count );
+ }
+ else
+ {
+ memcpy( ( (char *)lbr->base ) + lbr->byte_offset, buffer, byte_count );
+ }
+}
+
+static void xenidc_vaddress_zero
+(
+ xenidc_buffer_concrete_class * class,
+ xenidc_local_buffer_reference * lbr
+)
+{
+ trace();
+
+ memset( ( (char *)lbr->base ) + lbr->byte_offset, 0, lbr->byte_count );
+}
+
+static void xenidc_vaddress_init( void )
+{
+ trace();
+
+ {
+ static DEFINE_RWLOCK( xenidc_vaddress_lock );
+
+ unsigned long flags;
+
+ read_lock_irqsave( &xenidc_vaddress_lock, flags );
+
+ {
+ static int initialised = 0;
+
+ if( !initialised )
+ {
+ read_unlock_irqrestore
+ ( &xenidc_vaddress_lock, flags );
+
+ write_lock_irqsave
+ ( &xenidc_vaddress_lock, flags );
+
+ if( !initialised )
+ {
+ static xenidc_buffer_concrete_class
+ xenidc_vaddress_concrete_class;
+
+ xenidc_vaddress_type =
+ xenidc_local_buffer_reference_register_buffer_concrete_class
+ (
+ &xenidc_vaddress_concrete_class,
+ xenidc_vaddress_copy_in_or_out,
+ xenidc_vaddress_zero
+ );
+
+ initialised = 1;
+ }
+
+ write_unlock_irqrestore
+ ( &xenidc_vaddress_lock, flags );
+
+ read_lock_irqsave
+ ( &xenidc_vaddress_lock, flags );
+ }
+ }
+
+ read_unlock_irqrestore( &xenidc_vaddress_lock, flags );
+ }
+}
+
+xenidc_local_buffer_reference xenidc_vaddress_create_lbr
+ ( void * address, xenidc_buffer_byte_count byte_count )
+{
+ trace();
+
+ xenidc_vaddress_init();
+
+ {
+ xenidc_local_buffer_reference lbr;
+
+ lbr.type = xenidc_vaddress_type;
+ lbr.base = address;
+ lbr.byte_offset = 0;
+ lbr.byte_count = byte_count;
+
+ return lbr;
+ }
+}
+
+EXPORT_SYMBOL( xenidc_vaddress_create_lbr );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_work.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_work.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,110 @@
+/*****************************************************************************/
+/* Enhanced work queue service */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include "xenidc_work.h"
+
+DEFINE_SPINLOCK( xenidc_work_list_lock );
+
+LIST_HEAD( xenidc_work_list );
+
+static void xenidc_work_function( void * ignored );
+
+DECLARE_WORK( xenidc_work_work, xenidc_work_function, NULL );
+
+DECLARE_WAIT_QUEUE_HEAD( xenidc_work_waitqueue );
+
+LIST_HEAD( xenidc_work_condition );
+
+void xenidc_work_wake_up( void )
+{
+ unsigned long flags;
+
+ spin_lock_irqsave( &xenidc_work_list_lock, flags );
+
+ while( !list_empty( &xenidc_work_condition ) )
+ {
+ list_del_init( xenidc_work_condition.next );
+ }
+
+ spin_unlock_irqrestore( &xenidc_work_list_lock, flags );
+
+ wake_up( &xenidc_work_waitqueue );
+}
+
+int xenidc_work_schedule( xenidc_work * work )
+{
+ int scheduled = 0;
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &xenidc_work_list_lock, flags );
+
+ if( list_empty( &work->link ) )
+ {
+ list_add_tail( &work->link, &xenidc_work_list );
+
+ scheduled = 1;
+ }
+
+ spin_unlock_irqrestore( &xenidc_work_list_lock, flags );
+
+ if( scheduled )
+ {
+ xenidc_work_wake_up();
+
+ schedule_work( &xenidc_work_work );
+ }
+
+ return scheduled;
+}
+
+static void xenidc_work_function( void * ignored )
+{
+ unsigned long flags;
+
+ spin_lock_irqsave( &xenidc_work_list_lock, flags );
+
+ while( !list_empty( &xenidc_work_list ) )
+ {
+ xenidc_work * work = list_entry
+ (
+ xenidc_work_list.next,
+ xenidc_work,
+ link
+ );
+
+ list_del_init( &work->link );
+
+ spin_unlock_irqrestore( &xenidc_work_list_lock, flags );
+
+ xenidc_work_perform_synchronously( work );
+
+ spin_lock_irqsave( &xenidc_work_list_lock, flags );
+ }
+
+ spin_unlock_irqrestore( &xenidc_work_list_lock, flags );
+}
+
+EXPORT_SYMBOL( xenidc_work_schedule );
+EXPORT_SYMBOL( xenidc_work_list );
+EXPORT_SYMBOL( xenidc_work_condition );
+EXPORT_SYMBOL( xenidc_work_waitqueue );
+EXPORT_SYMBOL( xenidc_work_wake_up );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_wrapping.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_wrapping.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,165 @@
+/*****************************************************************************/
+/* Xen inter-domain communication wrapping local buffer reference type. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#include <asm-xen/xenidc_wrapping.h>
+#include <linux/module.h>
+#include "xenidc_trace.h"
+
+#ifdef MIN
+#undef MIN
+#endif
+
+#define MIN( X, Y ) ( ( (X) < (Y) ) ? (X) : (Y) )
+
+static xenidc_buffer_type xenidc_wrapping_type;
+
+static xenidc_local_buffer_reference xenidc_wrapping_resolve
+(
+ xenidc_buffer_virtual_class * class,
+ xenidc_local_buffer_reference * lbr
+)
+{
+ trace();
+
+ {
+ xenidc_local_buffer_reference resolved_lbr =
+ *(xenidc_local_buffer_reference *)lbr->base;
+
+ xenidc_local_buffer_reference_subrange
+ (
+ &resolved_lbr,
+ lbr->byte_offset,
+ MIN( lbr->byte_count, resolved_lbr.byte_count - lbr->byte_offset )
+ );
+
+ return resolved_lbr;
+ }
+}
+
+static void xenidc_wrapping_advance
+(
+ xenidc_buffer_virtual_class * class,
+ xenidc_local_buffer_reference * lbr,
+ xenidc_buffer_byte_count byte_count
+)
+{
+ trace();
+
+ lbr->byte_offset += byte_count;
+ lbr->byte_offset %=
+ ( (xenidc_local_buffer_reference *)lbr->base )->byte_count;
+ lbr->byte_count -= byte_count;
+}
+
+static void xenidc_wrapping_init( void )
+{
+ trace();
+
+ {
+ static DEFINE_RWLOCK( xenidc_wrapping_lock );
+
+ unsigned long flags;
+
+ read_lock_irqsave( &xenidc_wrapping_lock, flags );
+
+ {
+ static int initialised = 0;
+
+ if( !initialised )
+ {
+ read_unlock_irqrestore
+ ( &xenidc_wrapping_lock, flags );
+
+ write_lock_irqsave
+ ( &xenidc_wrapping_lock, flags );
+
+ if( !initialised )
+ {
+ static xenidc_buffer_virtual_class
+ xenidc_wrapping_virtual_class;
+
+ xenidc_wrapping_type =
+ xenidc_local_buffer_reference_register_buffer_virtual_class
+ (
+ &xenidc_wrapping_virtual_class,
+ xenidc_wrapping_resolve,
+ xenidc_wrapping_advance
+ );
+
+ initialised = 1;
+ }
+
+ write_unlock_irqrestore
+ ( &xenidc_wrapping_lock, flags );
+
+ read_lock_irqsave
+ ( &xenidc_wrapping_lock, flags );
+ }
+ }
+
+ read_unlock_irqrestore( &xenidc_wrapping_lock, flags );
+ }
+}
+
+xenidc_local_buffer_reference xenidc_wrapping_create_lbr
+(
+ xenidc_local_buffer_reference * underlying_buffer,
+ xenidc_buffer_byte_count start_offset,
+ xenidc_buffer_byte_count end_offset,
+ xenidc_wrapping_client_type client_type
+)
+{
+ trace();
+
+ xenidc_wrapping_init();
+
+ {
+ xenidc_local_buffer_reference lbr;
+
+ lbr.type = xenidc_wrapping_type;
+ lbr.base = underlying_buffer;
+ lbr.byte_offset = start_offset;
+ lbr.byte_count =
+ (
+ ( start_offset < end_offset )
+ ?
+ ( end_offset - start_offset )
+ :
+ (
+ ( start_offset > end_offset )
+ ?
+ ( end_offset + underlying_buffer->byte_count - start_offset )
+ :
+ (
+ ( client_type == xenidc_wrapping_client_type_producer )
+ ?
+ underlying_buffer->byte_count
+ :
+ 0
+ )
+ )
+ );
+
+ return lbr;
+ }
+}
+
+EXPORT_SYMBOL( xenidc_wrapping_create_lbr );
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel.c
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel.c Sun Oct 30 16:03:34 2005
@@ -0,0 +1,1737 @@
+/*****************************************************************************/
+/* This is a class which uses a xenidc_gnttab_channel (grant-tables based */
+/* message channel class) and xenbus to implement an interdomain message */
+/* channel with grant-tables based message transfer and xenbus based */
+/* bring-up and tear-down handshaking. */
+/* This class is used in the implementation of the xenidc_endpoint class. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* The state machine below makes the following assumptions: */
+/* */
+/* 1) The store might contain some stale cruft from the last time our device */
+/* driver failed. This is a handy assumption for testing new versions of */
+/* the driver but isn't strictly necessary. */
+/* */
+/* 2) If the other side generates a protocol error on the inter-domain */
+/* connection then we attempt to disconnect and reconnect. An alternative */
+/* behaviour would be to wait for our interface to be called to disconnect */
+/* and then reconnect before retrying. */
+/* */
+/* 3) If we experience an internal failure (fail to register watch for */
+/* example) then we attempt to disconnect and wait for our interface to be */
+/* called to disconnect (by module unload for example) and reconnect before */
+/* retrying. */
+/* */
+/* 4) Connection and disconnection of the channel is done in two phases: the */
+/* first phase makes the local resources available to the remote side, the */
+/* second phase uses the resources of the remote side to complete the */
+/* connection. */
+/* */
+/* The key for the stimuli is as follows: */
+/* */
+/* cn: interface called to connect the channel when interface state is */
+/* disconnected (for example on module load). */
+/* */
+/* pe: protocol error detected when channel is in a state between phase two */
+/* connected and the completion of the phase two disconnect callback. */
+/* */
+/* dn: interface called to disconnect the channel when the interface state */
+/* is connected (for example on module unload). */
+/* */
+/* ou: a synchronous stimulus from the response test_other_state which */
+/* indicates that the other state is still unknown because the watch */
+/* callback hasn't happened yet. Can only happen when making the response */
+/* test_other_state. */
+/* */
+/* od: other state is disconnected. This is both a synchronous stimulus */
+/* from test_other_state and an asynchronous stimulus from the watch */
+/* function. Disconnected means that we can't read at least the other side's */
+/* ready node from the store. */
+/* */
+/* or: other state is ready. This is both a synchronous stimulus from */
+/* test_other_state and an asynchronous stimulus from the watch function. */
+/* Ready means that we can see the other side's ready node but not the */
+/* ring-reference and event-channel information. */
+/* */
+/* oc: other state is connected. This is both a synchronous stimulus from */
+/* test_other_state and an asynchronous stimulus from the watch function. */
+/* Connected means that we found both the ready node and the connected */
+/* information in the store. */
+/* */
+/* If the values of the connected information change when the other side is */
+/* connected then we generate the 'oc' stimulus again which forces a */
+/* reconnect. */
+/* */
+/* rs: An asynchronous response was successful (we only make one response at */
+/* a time so all asynchronous responses have the same completion stimuli). */
+/* */
+/* rf: An asynchronous response failed. Only register_watch, clear_store, */
+/* write_ready, write_connected, phase_two_connect can fail. Only */
+/* phase_two_connect has a good reason for failure: the other side might */
+/* have passed bogus parameters; the other failures are poor API design and */
+/* ought to be promoted to domain failures. */
+/* */
+/* The state machine responses are as follows: */
+/* */
+/* test_other_state: what state do we currently think the other side is in */
+/* as reflected by the last watch event. Synchronous (called with the lock */
+/* held) completes with ou/od/or/oc. */
+/* */
+/* register_watch: register a watch on the other side. */
+/* */
+/* unregister_watch: unregister the watch. */
+/* */
+/* clear_store: remove the ready node and connected information. */
+/* */
+/* write_ready: write the ready node to the store. */
+/* */
+/* write_connected: write the connected information to the store. */
+/* */
+/* phase_one_connect: grant the remote side access to the local page etc. */
+/* */
+/* phase_two_connect: map the remote page etc. */
+/* */
+/* phase_two_disconnect: unmap the remote page. */
+/* */
+/* phase_one_disconnect: revoke the access of the remote side. */
+/* */
+/* complete_disconnect: When our interface is called to get us to disconnect */
+/* the channel we quiesce and disconnect and then call this to indicate we */
+/* are done. */
+/* */
+/*****************************************************************************/
+
+#include <asm-xen/xenidc_xbgt_channel.h>
+#include <linux/err.h>
+#include "xenidc_trace.h"
+
+typedef enum
+{
+ xenidc_xbgt_channel_stimulus_cn, /* Connect: disconnected */
+ xenidc_xbgt_channel_stimulus_pe, /* Protocol error: ph2c->ph2dc inclusive*/
+ xenidc_xbgt_channel_stimulus_dn, /* Disconnect: connected */
+ xenidc_xbgt_channel_stimulus_ou, /* Other unknown: test other state only */
+ xenidc_xbgt_channel_stimulus_od, /* Other disconnected: watch / test */
+ xenidc_xbgt_channel_stimulus_or, /* Other ready: watch / test */
+ xenidc_xbgt_channel_stimulus_oc, /* Other connected: watch / test */
+ xenidc_xbgt_channel_stimulus_rs, /* Response successful: making response */
+ xenidc_xbgt_channel_stimulus_rf /* Response failed: r. watch, tra, ph2c */
+}
+xenidc_xbgt_channel_stimulus;
+
+static void xenidc_xbgt_channel_handle_stimulus
+ ( xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus );
+
+static int xenidc_xbgt_channel_init_or_exit
+ ( xenidc_xbgt_channel * channel, int exit );
+
+int xenidc_xbgt_channel_init( xenidc_xbgt_channel * channel )
+{
+ return xenidc_xbgt_channel_init_or_exit( channel, 0 );
+}
+
+void xenidc_xbgt_channel_connect
+(
+ xenidc_xbgt_channel * channel,
+ char * local_path,
+ char * remote_path,
+ domid_t remote_domain_id
+)
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ channel->local_path = local_path;
+ channel->remote_path = remote_path;
+ channel->remote_domain_id = remote_domain_id;
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_cn );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+static void xenidc_xbgt_channel_watch
+ ( struct xenbus_watch * watch, const char ** vec, unsigned int len )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel =
+ container_of( watch, xenidc_xbgt_channel, watch );
+
+ struct xenbus_transaction * transaction = xenbus_transaction_start();
+
+ if( IS_ERR( transaction ) )
+ {
+ trace0( "error starting transaction" );
+
+ goto DISCONNECTED;
+ }
+
+ {
+ unsigned int event_channel;
+ unsigned int ring_reference;
+ unsigned int ready;
+
+ int error = xenbus_gather
+ (
+ transaction,
+ watch->node,
+ "ready", "%u", &ready,
+ "event-channel", "%u", &event_channel,
+ "ring-reference", "%u", &ring_reference,
+ NULL
+ );
+
+ if( error == 0 )
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ if
+ (
+ (
+ channel->other_state
+ !=
+ xenidc_xbgt_channel_other_state_connected
+ )
+ ||
+ ( channel->ready_event_channel != event_channel )
+ ||
+ ( channel->ready_ring_reference != ring_reference )
+ )
+ {
+ channel->other_state =
+ xenidc_xbgt_channel_other_state_connected;
+
+ channel->ready_event_channel = event_channel;
+ channel->ready_ring_reference = ring_reference;
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_oc );
+ }
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+
+ xenbus_transaction_end( transaction, 1 /* abort */ );
+
+ return;
+ }
+ }
+
+ {
+ unsigned int ready;
+
+ int error = xenbus_gather
+ (
+ transaction,
+ watch->node,
+ "ready", "%u", &ready,
+ NULL
+ );
+
+ if( error == 0 )
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ if
+ (
+ (
+ channel->other_state
+ !=
+ xenidc_xbgt_channel_other_state_ready
+ )
+ )
+ {
+ channel->other_state =
+ xenidc_xbgt_channel_other_state_ready;
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_or );
+ }
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+
+ xenbus_transaction_end( transaction, 1 /* abort */ );
+
+ return;
+ }
+ }
+
+ xenbus_transaction_end( transaction, 1 /* abort */ );
+
+ DISCONNECTED:
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ if
+ (
+ channel->other_state
+ !=
+ xenidc_xbgt_channel_other_state_disconnected
+ )
+ {
+ channel->other_state =
+ xenidc_xbgt_channel_other_state_disconnected;
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_od );
+ }
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+ }
+}
+
+static void xenidc_xbgt_channel_protocol_error
+ ( xenidc_gnttab_channel * gnttab_channel )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel =
+ xenidc_xbgt_channel_gnttab_channel_to( gnttab_channel );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_pe );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+void xenidc_xbgt_channel_disconnect
+ ( xenidc_xbgt_channel * channel, xenidc_callback * callback )
+{
+ trace();
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ channel->disconnect_callback = callback;
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_dn );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+void xenidc_xbgt_channel_exit( xenidc_xbgt_channel * channel )
+{
+ trace();
+
+ (void)xenidc_xbgt_channel_init_or_exit( channel, 1 );
+}
+
+static void xenidc_xbgt_channel_register_watch_1( void * data );
+static void xenidc_xbgt_channel_unregister_watch_1( void * data );
+static void xenidc_xbgt_channel_clear_store_1( void * data );
+static void xenidc_xbgt_channel_write_ready_1( void * data );
+static void xenidc_xbgt_channel_write_connected_1( void * data );
+static void xenidc_xbgt_channel_phase_one_connect_1( void * data );
+static void xenidc_xbgt_channel_phase_one_connect_2
+ ( xenidc_callback * callback );
+static void xenidc_xbgt_channel_phase_two_connect_1( void * data );
+static void xenidc_xbgt_channel_phase_two_connect_2
+ ( xenidc_callback * callback );
+static void xenidc_xbgt_channel_phase_two_disconnect_1( void * data );
+static void xenidc_xbgt_channel_phase_two_disconnect_2
+ ( xenidc_callback * callback );
+static void xenidc_xbgt_channel_phase_one_disconnect_1( void * data );
+static void xenidc_xbgt_channel_phase_one_disconnect_2
+ ( xenidc_callback * callback );
+
+static int xenidc_xbgt_channel_init_or_exit
+ ( xenidc_xbgt_channel * channel, int exit )
+{
+ trace();
+
+ {
+ int return_value = 0;
+
+ if( exit )
+ {
+ goto EXIT;
+ }
+
+ if
+ (
+ (
+ return_value = xenidc_gnttab_channel_init
+ ( &channel->channel, xenidc_xbgt_channel_protocol_error )
+ )
+ !=
+ 0
+ )
+ {
+ goto EXIT_NO_GNTTAB_CHANNEL;
+ }
+
+ xenidc_work_init
+ (
+ &channel->register_watch_1_work,
+ xenidc_xbgt_channel_register_watch_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->unregister_watch_1_work,
+ xenidc_xbgt_channel_unregister_watch_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->clear_store_1_work,
+ xenidc_xbgt_channel_clear_store_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->write_ready_1_work,
+ xenidc_xbgt_channel_write_ready_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->write_connected_1_work,
+ xenidc_xbgt_channel_write_connected_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->phase_one_connect_1_work,
+ xenidc_xbgt_channel_phase_one_connect_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->phase_two_connect_1_work,
+ xenidc_xbgt_channel_phase_two_connect_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->phase_two_disconnect_1_work,
+ xenidc_xbgt_channel_phase_two_disconnect_1,
+ channel
+ );
+
+ xenidc_work_init
+ (
+ &channel->phase_one_disconnect_1_work,
+ xenidc_xbgt_channel_phase_one_disconnect_1,
+ channel
+ );
+
+ xenidc_callback_init
+ (
+ &channel->phase_one_connect_request.callback,
+ xenidc_xbgt_channel_phase_one_connect_2
+ );
+
+ xenidc_callback_init
+ (
+ &channel->phase_two_connect_request.callback,
+ xenidc_xbgt_channel_phase_two_connect_2
+ );
+
+ xenidc_callback_init
+ (
+ &channel->phase_two_disconnect_callback,
+ xenidc_xbgt_channel_phase_two_disconnect_2
+ );
+
+ xenidc_callback_init
+ (
+ &channel->phase_one_disconnect_callback,
+ xenidc_xbgt_channel_phase_one_disconnect_2
+ );
+
+ return 0;
+
+ EXIT:
+
+ xenidc_gnttab_channel_exit( &channel->channel );
+
+ EXIT_NO_GNTTAB_CHANNEL:
+
+ return return_value;
+ }
+}
+
+static void xenidc_xbgt_channel_invalid_stimulus
+ ( xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus );
+
+static void xenidc_xbgt_channel_test_other_state
+ ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_register_watch
+ ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_unregister_watch
+ ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_clear_store
+ ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_write_ready
+ ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_write_connected
+ ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_phase_one_connect
+ ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_phase_two_connect
+ ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_phase_two_disconnect
+ ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_phase_one_disconnect
+ ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_complete_disconnect
+ ( xenidc_xbgt_channel * channel );
+
+static void xenidc_xbgt_channel_handle_stimulus
+ ( xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus )
+{
+ trace3
+ (
+ "xbgt channel %p in state %d received stimulus %d",
+ channel,
+ channel->state,
+ stimulus
+ );
+
+ switch( channel->state )
+ {
+ case xenidc_xbgt_channel_state_i:
+ /* Interface disconnected. */
+ /* Gnttab channel disconnected. */
+ /* Local store unknown. */
+ /* Watch not registered. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_cn:
+ channel->state = xenidc_xbgt_channel_state_i_cn;
+ xenidc_xbgt_channel_phase_one_connect( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn:
+ /* Interface connected. */
+ /* Gnttab channel phase one connecting. */
+ /* Local store unknown. */
+ /* Watch not registered. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i_cn_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs;
+ xenidc_xbgt_channel_register_watch( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_dn:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase one connecting */
+ /* Local store unknown. */
+ /* Watch not registered. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs;
+ xenidc_xbgt_channel_clear_store( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected and registering watch or */
+ /* Watch registered and gnttab channel phase two disconnecting */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_pe:
+ break;
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs;
+ xenidc_xbgt_channel_clear_store( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf;
+ xenidc_xbgt_channel_clear_store( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_dn_rs:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase one connected */
+ /* Clearing store. */
+ /* Watch not registered. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_rs:
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs_rs;
+ xenidc_xbgt_channel_phase_one_disconnect( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_dn:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase one connected. */
+ /* Local store unknown. */
+ /* Registering watch. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ xenidc_xbgt_channel_unregister_watch( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs;
+ xenidc_xbgt_channel_clear_store( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Clearing Store. */
+ /* Watch Registered. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rs;
+ xenidc_xbgt_channel_test_other_state( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rf;
+ xenidc_xbgt_channel_unregister_watch( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rf:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Clearing store. */
+ /* Something failed. */
+ /* Watch not registered. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs;
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf_rs;
+ xenidc_xbgt_channel_phase_one_disconnect( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_dn_rs_rs:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase one disconnecting */
+ /* Attempted to clear store. */
+ /* Watch not registered. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i;
+ xenidc_xbgt_channel_complete_disconnect( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_dn_rs:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase one connected. */
+ /* Local store unknown. */
+ /* Unregistering watch. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs;
+ xenidc_xbgt_channel_clear_store( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_dn:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase one connected unless ph2 disconnecting below.*/
+ /* Clearing Store / writing ready / writing connected / ... */
+ /* ... ph2 disconnecting */
+ /* Watch Registered. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_pe:
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ xenidc_xbgt_channel_unregister_watch( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Store clear. */
+ /* Watch Registered. */
+ /* Testing other state / other state unknown/connected */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ xenidc_xbgt_channel_unregister_watch( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_ou:
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od;
+ xenidc_xbgt_channel_write_ready( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rf:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Unregistering watch. */
+ /* Something failed. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf;
+ xenidc_xbgt_channel_clear_store( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rf_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one disconnecting. */
+ /* Attempted to clear store. */
+ /* Something failed. */
+ /* Watch not registered. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs_rs;
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs;
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Writing Ready. */
+ /* Watch Registered. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs;
+ xenidc_xbgt_channel_test_other_state( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rf;
+ xenidc_xbgt_channel_unregister_watch( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one disconnected. */
+ /* Attempted to clear store. */
+ /* Something failed. */
+ /* Watch not registered. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i;
+ xenidc_xbgt_channel_complete_disconnect( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Ready. */
+ /* Watch registered. */
+ /* Testing other state or other state disconnected */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ xenidc_xbgt_channel_unregister_watch( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ break;
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or;
+ xenidc_xbgt_channel_write_connected( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Writing Connected. */
+ /* Watch registered. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs;
+ xenidc_xbgt_channel_test_other_state( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rf;
+ xenidc_xbgt_channel_unregister_watch( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase one connected. */
+ /* Connected. */
+ /* Watch registered. */
+ /* Testing other state / other state ready. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ xenidc_xbgt_channel_unregister_watch( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs;
+ xenidc_xbgt_channel_clear_store( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_or:
+ break;
+ case xenidc_xbgt_channel_stimulus_oc:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc;
+ xenidc_xbgt_channel_phase_two_connect( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc:
+ /* Interface connected. */
+ /* Gnttab channel phase two connecting. */
+ /* Connected. */
+ /* Watch registered. */
+ /* Other side connected. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_pe:
+ /* Phase two disconnect then go around. */
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe;
+ break;
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe;
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs;
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ /* Maybe we picked up stale state from the store. Go around. */
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs;
+ xenidc_xbgt_channel_clear_store( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe:
+ /* Interface connected. */
+ /* Gnttab channel phase two connecting. */
+ /* Connected. */
+ /* Watch registered. */
+ /* Protocol error or glitch. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_pe:
+ break;
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn;
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs;
+ xenidc_xbgt_channel_phase_two_disconnect( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs;
+ xenidc_xbgt_channel_clear_store( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn:
+ /* Interface disconnecting. */
+ /* Gnttab channel phase two connecting. */
+ /* Connected. */
+ /* Watch registered. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_pe:
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ break;
+ case xenidc_xbgt_channel_stimulus_rs:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+ xenidc_xbgt_channel_phase_two_disconnect( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_rf:
+ channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs;
+ xenidc_xbgt_channel_unregister_watch( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs:
+ /* Interface connected. */
+ /* Gnttab channel phase two connected. */
+ /* Connected. */
+ /* Watch registered. */
+ /* Other side connected. */
+ /* Totally happy. */
+ switch( stimulus )
+ {
+ case xenidc_xbgt_channel_stimulus_pe:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs;
+ xenidc_xbgt_channel_phase_two_disconnect( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_dn:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs_rs_dn;
+ xenidc_xbgt_channel_phase_two_disconnect( channel );
+ break;
+ case xenidc_xbgt_channel_stimulus_od:
+ case xenidc_xbgt_channel_stimulus_or:
+ case xenidc_xbgt_channel_stimulus_oc:
+ channel->state =
+ xenidc_xbgt_channel_state_i_cn_rs;
+ xenidc_xbgt_channel_phase_two_disconnect( channel );
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+ break;
+ default:
+ xenidc_xbgt_channel_invalid_stimulus( channel, stimulus );
+ break;
+ }
+}
+
+static void xenidc_xbgt_channel_invalid_stimulus
+ ( xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus )
+{
+ trace();
+
+ printk
+ (
+ KERN_ERR "xenidc: xbgt channel %p in state %d"
+ "received invalid stimulus %d",
+ channel,
+ channel->state,
+ stimulus
+ );
+}
+
+static void xenidc_xbgt_channel_test_other_state
+ ( xenidc_xbgt_channel * channel )
+{
+ trace();
+
+ switch( channel->other_state )
+ {
+ case xenidc_xbgt_channel_other_state_unknown:
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_ou );
+ break;
+ case xenidc_xbgt_channel_other_state_disconnected:
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_od );
+ break;
+ case xenidc_xbgt_channel_other_state_ready:
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_or );
+ break;
+ case xenidc_xbgt_channel_other_state_connected:
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_oc );
+ break;
+ }
+}
+
+static void xenidc_xbgt_channel_register_watch
+ ( xenidc_xbgt_channel * channel )
+{
+ trace();
+
+ channel->other_state = xenidc_xbgt_channel_other_state_unknown;
+
+ (void)xenidc_work_schedule( &channel->register_watch_1_work );
+}
+
+static void xenidc_xbgt_channel_register_watch_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+ channel->watch.node = channel->remote_path;
+ channel->watch.callback = xenidc_xbgt_channel_watch;
+
+ {
+ int return_value = register_xenbus_watch( &channel->watch );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ if( return_value == 0 )
+ {
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rs );
+ }
+ else
+ {
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rf );
+ }
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+ }
+}
+
+static void xenidc_xbgt_channel_unregister_watch
+ ( xenidc_xbgt_channel * channel )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &channel->unregister_watch_1_work );
+}
+
+static void xenidc_xbgt_channel_unregister_watch_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+ unregister_xenbus_watch( &channel->watch );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+ }
+}
+
+static void xenidc_xbgt_channel_clear_store( xenidc_xbgt_channel * channel )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &channel->clear_store_1_work );
+}
+
+static void xenidc_xbgt_channel_clear_store_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+ struct xenbus_transaction * transaction;
+
+ AGAIN:
+
+ transaction = xenbus_transaction_start();
+
+ if( IS_ERR( transaction ) )
+ {
+ trace0( "error starting transaction" );
+
+ goto ERROR;
+ }
+
+ {
+ int error =
+ xenbus_rm( transaction, channel->local_path, "ready" );
+
+ if( error )
+ {
+ trace0( "error removing ready field from store" );
+
+ goto ABORT_TRANSACTION;
+ }
+ }
+
+ {
+ int error =
+ xenbus_rm( transaction, channel->local_path, "event-channel" );
+
+ if( error )
+ {
+ trace0( "error removing event-channel field from store" );
+
+ goto ABORT_TRANSACTION;
+ }
+ }
+
+ {
+ int error =
+ xenbus_rm( transaction, channel->local_path, "ring-reference" );
+
+ if( error )
+ {
+ trace0( "error removing ring-reference field from store" );
+
+ goto ABORT_TRANSACTION;
+ }
+ }
+
+ {
+ int error = xenbus_transaction_end( transaction, 0 /* commit */ );
+
+ if( error != 0 )
+ {
+ if( error == -EAGAIN )
+ {
+ goto AGAIN;
+ }
+ else
+ {
+ trace0( "error committing transaction" );
+
+ goto ERROR;
+ }
+ }
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+
+ return;
+
+ ABORT_TRANSACTION:
+
+ xenbus_transaction_end( transaction, 1 /* abort */ );
+
+ ERROR:
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rf );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+ }
+}
+
+static void xenidc_xbgt_channel_write_ready( xenidc_xbgt_channel * channel )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &channel->write_ready_1_work );
+}
+
+static void xenidc_xbgt_channel_write_ready_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+ struct xenbus_transaction * transaction;
+
+ AGAIN:
+
+ transaction = xenbus_transaction_start();
+
+ if( IS_ERR( transaction ) )
+ {
+ trace0( "error starting transaction" );
+
+ goto ERROR;
+ }
+
+ {
+ int error = xenbus_write
+ (
+ transaction,
+ channel->local_path,
+ "ready",
+ "1"
+ );
+
+ if( error )
+ {
+ trace0( "error writing ready to store" );
+
+ goto ABORT_TRANSACTION;
+ }
+ }
+
+ {
+ int error = xenbus_transaction_end( transaction, 0 /* commit */ );
+
+ if( error != 0 )
+ {
+ if( error == -EAGAIN )
+ {
+ goto AGAIN;
+ }
+ else
+ {
+ trace0( "error committing transaction" );
+
+ goto ERROR;
+ }
+ }
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+
+ return;
+
+ ABORT_TRANSACTION:
+
+ xenbus_transaction_end( transaction, 1 /* abort */ );
+
+ ERROR:
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rf );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+ }
+}
+
+static void xenidc_xbgt_channel_write_connected
+ ( xenidc_xbgt_channel * channel )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &channel->write_connected_1_work );
+}
+
+static void xenidc_xbgt_channel_write_connected_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+ struct xenbus_transaction * transaction;
+
+ xenidc_gnttab_channel_reset_ring( &channel->channel );
+
+ AGAIN:
+
+ transaction = xenbus_transaction_start();
+
+ if( IS_ERR( transaction ) )
+ {
+ trace0( "error starting transaction" );
+
+ goto ERROR;
+ }
+
+ {
+ int error = xenbus_printf
+ (
+ transaction,
+ channel->local_path,
+ "ring-reference",
+ "%u",
+ channel->phase_one_connect_request.send_ring_ref
+ );
+
+ if( error )
+ {
+ trace0( "error writing ring-reference to store" );
+
+ goto ABORT_TRANSACTION;
+ }
+ }
+
+ {
+ int error = xenbus_printf
+ (
+ transaction,
+ channel->local_path,
+ "event-channel",
+ "%u",
+ channel->phase_one_connect_request.send_event_channel
+ );
+
+ if( error )
+ {
+ trace0( "error writing event-channel to store" );
+
+ goto ABORT_TRANSACTION;
+ }
+ }
+
+ {
+ int error = xenbus_transaction_end( transaction, 0 /* commit */ );
+
+ if( error != 0 )
+ {
+ if( error == -EAGAIN )
+ {
+ goto AGAIN;
+ }
+ else
+ {
+ trace0( "error committing transaction" );
+
+ goto ERROR;
+ }
+ }
+ }
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+
+ return;
+
+ ABORT_TRANSACTION:
+
+ xenbus_transaction_end( transaction, 1 /* abort */ );
+
+ ERROR:
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rf );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+ }
+}
+
+static void xenidc_xbgt_channel_phase_one_connect
+ ( xenidc_xbgt_channel * channel )
+{
+ trace();
+
+ channel->phase_one_connect_request.remote_domain_id =
+ channel->remote_domain_id;
+
+ (void)xenidc_work_schedule( &channel->phase_one_connect_1_work );
+}
+
+static void xenidc_xbgt_channel_phase_one_connect_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+ xenidc_gnttab_channel_phase_one_connect
+ ( &channel->channel, &channel->phase_one_connect_request );
+ }
+}
+
+static void xenidc_xbgt_channel_phase_one_connect_2
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel = container_of
+ (
+ xenidc_gnttab_channel_phase_one_connect_request_callback_to
+ ( callback ),
+ xenidc_xbgt_channel,
+ phase_one_connect_request
+ );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+static void xenidc_xbgt_channel_phase_two_connect
+ ( xenidc_xbgt_channel * channel )
+{
+ trace();
+
+ channel->phase_two_connect_request.remote_domain_id =
+ channel->remote_domain_id;
+ channel->phase_two_connect_request.recv_ring_ref =
+ channel->ready_ring_reference;
+ channel->phase_two_connect_request.recv_event_channel =
+ channel->ready_event_channel;
+
+ (void)xenidc_work_schedule( &channel->phase_two_connect_1_work );
+}
+
+static void xenidc_xbgt_channel_phase_two_connect_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+ xenidc_gnttab_channel_phase_two_connect
+ ( &channel->channel, &channel->phase_two_connect_request );
+ }
+}
+
+static void xenidc_xbgt_channel_phase_two_connect_2
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel = container_of
+ (
+ xenidc_gnttab_channel_phase_two_connect_request_callback_to
+ ( callback ),
+ xenidc_xbgt_channel,
+ phase_two_connect_request
+ );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ if( xenidc_callback_query_error( callback ) == XENIDC_ERROR_SUCCESS )
+ {
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rs );
+ }
+ else
+ {
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rf );
+ }
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+static void xenidc_xbgt_channel_phase_two_disconnect
+ ( xenidc_xbgt_channel * channel )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &channel->phase_two_disconnect_1_work );
+}
+
+static void xenidc_xbgt_channel_phase_two_disconnect_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+ xenidc_gnttab_channel_phase_two_disconnect
+ ( &channel->channel, &channel->phase_two_disconnect_callback );
+ }
+}
+
+static void xenidc_xbgt_channel_phase_two_disconnect_2
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel = container_of
+ ( callback, xenidc_xbgt_channel, phase_two_disconnect_callback );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+static void xenidc_xbgt_channel_phase_one_disconnect
+ ( xenidc_xbgt_channel * channel )
+{
+ trace();
+
+ (void)xenidc_work_schedule( &channel->phase_one_disconnect_1_work );
+}
+
+static void xenidc_xbgt_channel_phase_one_disconnect_1( void * data )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data;
+
+ xenidc_gnttab_channel_phase_one_disconnect
+ ( &channel->channel, &channel->phase_one_disconnect_callback );
+ }
+}
+
+static void xenidc_xbgt_channel_phase_one_disconnect_2
+ ( xenidc_callback * callback )
+{
+ trace();
+
+ {
+ xenidc_xbgt_channel * channel = container_of
+ ( callback, xenidc_xbgt_channel, phase_one_disconnect_callback );
+
+ unsigned long flags;
+
+ spin_lock_irqsave( &channel->lock, flags );
+
+ xenidc_xbgt_channel_handle_stimulus
+ ( channel, xenidc_xbgt_channel_stimulus_rs );
+
+ spin_unlock_irqrestore( &channel->lock, flags );
+ }
+}
+
+static void xenidc_xbgt_channel_complete_disconnect
+ ( xenidc_xbgt_channel * channel )
+{
+ trace();
+
+ xenidc_callback_success( channel->disconnect_callback );
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.dot
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.dot Sun Oct 30 16:03:34 2005
@@ -0,0 +1,109 @@
+digraph enumeration {
+size="7,7"
+
+i[style=filled,fillcolor=green]
+i->i_cn[label="cn\nphase_one_connect"];
+
+i_cn[style=filled,fillcolor=green]
+i_cn->i_cn_dn[label="dn"];
+i_cn->i_cn_rs[label="rs\nregister_watch"];
+
+i_cn_dn[style=filled,fillcolor=orange]
+i_cn_dn->i_cn_dn_rs[label="rs\nclear_store"];
+
+i_cn_rs[style=filled,fillcolor=green]
+i_cn_rs->i_cn_rs_dn[label="dn"];
+i_cn_rs->i_cn_rs[label="pe/od/or/oc"];
+i_cn_rs->i_cn_rs_rs[label="rs\nclear_store"];
+i_cn_rs->i_cn_rs_rf[label="rf\nclear_store"];
+
+i_cn_dn_rs[style=filled,fillcolor=orange]
+i_cn_dn_rs->i_cn_dn_rs_rs[label="rs/rf\nphase_one_disconnect"];
+
+i_cn_rs_dn[style=filled,fillcolor=orange]
+i_cn_rs_dn->i_cn_rs_dn[label="od/or/oc"];
+i_cn_rs_dn->i_cn_rs_dn_rs[label="rs\nunregister_watch"];
+i_cn_rs_dn->i_cn_dn_rs[label="rf\nclear_store"];
+
+i_cn_rs_rs[style=filled,fillcolor=green]
+i_cn_rs_rs->i_cn_rs_rs_dn[label="dn"];
+i_cn_rs_rs->i_cn_rs_rs[label="od/or/oc"];
+i_cn_rs_rs->i_cn_rs_rs_rs[label="rs\ntest_other_state"];
+i_cn_rs_rs->i_cn_rs_rs_rf[label="rf\nunregister_watch"];
+
+i_cn_rs_rf[style=filled,fillcolor=red]
+i_cn_rs_rf->i_cn_dn_rs[label="dn"];
+i_cn_rs_rf->i_cn_rs_rf_rs[label="rs/rf\nphase_one_disconnect"];
+
+i_cn_dn_rs_rs[style=filled,fillcolor=orange]
+i_cn_dn_rs_rs->i[label="rs\ncomplete_disconnect"];
+
+i_cn_rs_dn_rs[style=filled,fillcolor=orange]
+i_cn_rs_dn_rs->i_cn_rs_dn_rs[label="od/or/oc"];
+i_cn_rs_dn_rs->i_cn_dn_rs[label="rs\nclear_store"];
+
+i_cn_rs_rs_dn[style=filled,fillcolor=orange]
+i_cn_rs_rs_dn->i_cn_rs_rs_dn[label="od/or/oc"];
+i_cn_rs_rs_dn->i_cn_rs_dn_rs[label="rs/rf\nunregister_watch"];
+
+i_cn_rs_rs_rs[style=filled,fillcolor=green]
+i_cn_rs_rs_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"];
+i_cn_rs_rs_rs->i_cn_rs_rs_rs[label="ou/oc"];
+i_cn_rs_rs_rs->i_cn_rs_rs_rs_od[label="od/or\nwrite_ready"];
+
+i_cn_rs_rs_rf[style=filled,fillcolor=red]
+i_cn_rs_rs_rf->i_cn_rs_dn_rs[label="dn"];
+i_cn_rs_rs_rf->i_cn_rs_rs_rf[label="od/or/oc"];
+i_cn_rs_rs_rf->i_cn_rs_rf[label="rs\nclear_store"];
+
+i_cn_rs_rf_rs[style=filled,fillcolor=red]
+i_cn_rs_rf_rs->i_cn_dn_rs_rs[label="dn"];
+i_cn_rs_rf_rs->i_cn_rs_rf_rs_rs[label="rs"];
+
+i_cn_rs_rs_rs_od[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od->i_cn_rs_rs_dn[label="dn"];
+i_cn_rs_rs_rs_od->i_cn_rs_rs_rs_od[label="od/or/oc"];
+i_cn_rs_rs_rs_od->i_cn_rs_rs_rs_od_rs[label="rs\ntest_other_state"];
+i_cn_rs_rs_rs_od->i_cn_rs_rs_rf[label="rf\nunregister_watch"];
+
+i_cn_rs_rf_rs_rs[style=filled,fillcolor=red]
+i_cn_rs_rf_rs_rs->i[label="dn\ncomplete_disconnect"];
+
+i_cn_rs_rs_rs_od_rs[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"];
+i_cn_rs_rs_rs_od_rs->i_cn_rs_rs_rs_od_rs[label="od"];
+i_cn_rs_rs_rs_od_rs->i_cn_rs_rs_rs_od_rs_or[label="or/oc\nwrite_connected"];
+
+i_cn_rs_rs_rs_od_rs_or[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_dn[label="dn"];
+i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rs_od_rs_or[label="od/or/oc"];
+i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rs_od_rs_or_rs[label="rs\ntest_other_state"];
+i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rf[label="rf\nunregister_watch"];
+
+i_cn_rs_rs_rs_od_rs_or_rs[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"];
+i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs[label="od\nclear_store"];
+i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs_rs_od_rs_or_rs[label="or"];
+i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs_rs_od_rs_or_rs_oc[label="oc\nphase_two_connect"];
+
+i_cn_rs_rs_rs_od_rs_or_rs_oc[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[label="pe/od/or/oc"];
+i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="dn"];
+i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_rs[label="rs"];
+i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs[label="rf\nclear_store"];
+
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[style=filled,fillcolor=blue]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[label="pe/od/or/oc"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="dn"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs[label="rs\nphase_two_disconnect"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs[label="rf\nclear_store"]
+
+i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[style=filled,fillcolor=orange]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="pe/od/or/oc"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_rs_dn[label="rs\nphase_two_disconnect"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_dn_rs[label="rf\nunregister_watch"]
+
+i_cn_rs_rs_rs_od_rs_or_rs_oc_rs[style=filled,fillcolor=green]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_rs->i_cn_rs[label="pe/od/or/oc\nphase_two_disconnect"]
+i_cn_rs_rs_rs_od_rs_or_rs_oc_rs->i_cn_rs_rs_dn[label="dn\nphase_two_disconnect"]
+}
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,122 @@
+/*****************************************************************************/
+/* Xen inter-domain communication API. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef __ASM_XEN_XENIDC_H__
+#define __ASM_XEN_XENIDC_H__
+
+/*****************************************************************************/
+/* RESOURCE MANAGEMENT */
+/* */
+/* The bulk data transfer mechanism uses the following strategy for resource */
+/* management: */
+/* */
+/* 1) Create an anti-deadlock resource pool. This pool of resources is used */
+/* to guarantee that your subsystem can make progress independent of all */
+/* other subsystems using the xenidc API. The subsystem operations using */
+/* the resource pool must be independent and the resource pool must contain */
+/* enough resources to service the worst case individual operation. This */
+/* guarantees progress because, in the worst case, an operation can wait for */
+/* all other operations to complete (they are independent so they will */
+/* complete eventually) at which time the resource pool will be replenished */
+/* such that it contains enough resources to start the waiting operation. */
+/* */
+/* 2) Make a single atomic request to reserve and create/reserve and open */
+/* all of the local/remote buffers required for the operation to proceed to */
+/* completion. This request is guaranteed to complete because it is atomic */
+/* and so will eventually get a chance to acquire all the resources it needs */
+/* which by design will be less than the anti-deadlock reservation. */
+/* */
+/* 3) Dependent operations using independent anti-deadlock pools acquire */
+/* resources from pools in a defined order. */
+/* */
+/* An alternative implementation could support an additional API for the */
+/* following strategy which might be more convenient for some clients: */
+/* */
+/* 1) Create an anti-deadlock resource pool as above. */
+/* */
+/* 2) Make a single atomic reservation to reserve all the resources required */
+/* for an operation to proceed to completion. This request is guaranteed to */
+/* complete because it is atomic and so will eventually get a chance to */
+/* acquire all the resources it needs which by design will be less than the */
+/* anti-deadlock reservation. */
+/* */
+/* 3) Make an arbitrary number of create/open requests using the resources */
+/* reserved in step 2. These are guaranteed to complete because the */
+/* resources reserved in step 2 are sufficient by design. */
+/* */
+/* 4) Dependent operations using independent anti-deadlock pools acquire */
+/* resources from pools in a defined order. */
+/* */
+/* The following strategies are examples which in general DO NOT WORK: */
+/* */
+/* First incorrect strategy: */
+/* */
+/* 1) Have no anti-deadlock resource pool. */
+/* */
+/* This doesn't work because all the xenidc resources might be allocated to */
+/* an operation that is dependent on your subsystem for completion. A */
+/* deadlock results where your subsystem is waiting on xenidc which is */
+/* waiting on the client of your subsystem to free resources which is */
+/* waiting on your subsystem. */
+/* */
+/* Second incorrect strategy: */
+/* */
+/* 1) Create an anti-deadlock resource pool. */
+/* */
+/* 2) Make an arbitrary number of non-atomic reserve_and_create and */
+/* reserve_and_open requests for a single subsystem operation. */
+/* */
+/* In general, this doesn't work because your subsystem will be processing */
+/* multiple operations concurrently which means that the anti-deadlock */
+/* resources might get fully used by multiple concurrent operations in such */
+/* a way that none of the operations have enough resources to proceed so */
+/* they all end up waiting indefinitely on each other. */
+/* */
+/* Third incorrect strategy: */
+/* */
+/* 1) Create an anti-deadlock resource pool. */
+/* */
+/* 2) Use the same anti-deadlock pool for dependent operations. */
+/* */
+/* This doesn't work because an operation might acquire all the */
+/* anti-deadlock reservation and then initiate a second operation. The */
+/* second operation goes to the same anti-deadlock pool and waits forever */
+/* for the dependent operation to free the resources back. The dependent */
+/* operation never frees the resources because it is dependent on the second */
+/* operation. */
+/* */
+/* Fourth incorrect strategy: */
+/* */
+/* 1) Create anti-deadlock resource pools for different dependent */
+/* operations. */
+/* */
+/* 2) Different operations acquire resources from the pools in different */
+/* order. */
+/* */
+/* This doesn't work because of the potential for another cyclic deadlock. */
+/* */
+/*****************************************************************************/
+
+#include "xenidc_endpoint.h"
+#include "xenidc_rbr_provider_pool.h"
+#include "xenidc_rbr_mapper_pool.h"
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_address.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_address.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,60 @@
+/*****************************************************************************/
+/* Xen inter-domain communication address. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef __ASM_XEN_XENIDC_ADDRESS_H__
+#define __ASM_XEN_XENIDC_ADDRESS_H__
+
+typedef struct xenidc_address_struct xenidc_address;
+
+struct xenidc_address_struct
+{
+ char * local;
+ char * remote;
+ int remote_id;
+};
+
+static inline void xenidc_address_init
+ ( xenidc_address * address, char * local, char * remote, int remote_id )
+{
+ address->local = local;
+ address->remote = remote;
+ address->remote_id = remote_id;
+}
+
+static inline char * xenidc_address_query_local_domain
+ ( xenidc_address * address )
+{
+ return address->local;
+}
+
+static inline char * xenidc_address_query_remote_domain
+ ( xenidc_address * address )
+{
+ return address->remote;
+}
+
+static inline int xenidc_address_query_remote_domain_id
+ ( xenidc_address * address )
+{
+ return address->remote_id;
+}
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_callback.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_callback.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,166 @@
+/*****************************************************************************/
+/* A callback object for use in scheduling completion of asynchronous */
+/* requests. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef XENIDC_CALLBACK_H
+#define XENIDC_CALLBACK_H
+
+#include <linux/spinlock.h>
+#include "xenidc_error.h"
+#include "xenidc_work.h"
+
+/* Service parameter blocks contain callbacks for asynchronous completions. */
+
+typedef struct xenidc_callback_struct xenidc_callback;
+
+struct xenidc_callback_struct
+{
+ xenidc_work work;
+ xenidc_error error;
+};
+
+#define XENIDC_CALLBACK_LINK work.XENIDC_WORK_LINK
+
+/* Client of service initialises callback with its callback function. */
+
+typedef void ( xenidc_callback_function )( xenidc_callback * callback );
+
+static inline void xenidc_callback_init
+ ( xenidc_callback * callback, xenidc_callback_function * function )
+{
+ xenidc_work_init( &callback->work, (void(*)(void*))function, callback );
+
+ callback->error = XENIDC_ERROR_SUCCESS;
+}
+
+/* Client may use link whilst it owns parameter block. Service may use link */
+/* whilst it owns parameter block. Link is reserved whilst callback is */
+/* scheduled for completion. */
+
+static inline struct list_head * xenidc_callback_to_link
+ ( xenidc_callback * callback )
+{
+ return xenidc_work_to_link( &callback->work );
+}
+
+static inline xenidc_callback * xenidc_callback_link_to
+ ( struct list_head * link )
+{
+ return container_of
+ ( xenidc_work_link_to( link ), xenidc_callback, work );
+}
+
+/* Service which completes requests concurrently may call */
+/* xenidc_callback_complete or xenidc_callback_success to complete the */
+/* callback. */
+
+static inline void xenidc_callback_complete
+ ( xenidc_callback * callback, xenidc_error error )
+{
+ callback->error = error;
+
+ xenidc_work_schedule( &callback->work );
+}
+
+static inline void xenidc_callback_success
+ ( xenidc_callback * callback )
+{
+ xenidc_callback_complete( callback, 0 );
+}
+
+/* These functions used by serialiser below. */
+
+static inline void xenidc_callback_set_error
+ ( xenidc_callback * callback, xenidc_error error )
+{
+ callback->error = error;
+}
+
+static inline void xenidc_callback_complete_synchronously
+ ( xenidc_callback * callback )
+{
+ xenidc_work_perform_synchronously( &callback->work );
+}
+
+/* When callback completes, client may call xenidc_callback_query_error to */
+/* get the error code. */
+
+static inline xenidc_error xenidc_callback_query_error
+ ( xenidc_callback * callback )
+{
+ return callback->error;
+}
+
+/* Services which must serialise completions to preserve submission order */
+/* can use one of these. */
+
+typedef struct xenidc_callback_serialiser_struct xenidc_callback_serialiser;
+
+struct xenidc_callback_serialiser_struct
+{
+ spinlock_t lock;
+ struct list_head list;
+ xenidc_work work;
+ int running;
+};
+
+void xenidc_callback_serialiser_function( void * context );
+
+#define XENIDC_CALLBACK_SERIALISER_INIT( name ) \
+{ \
+ SPIN_LOCK_UNLOCKED, \
+ LIST_HEAD_INIT( name.list ), \
+ XENIDC_WORK_INIT \
+ ( name.work, xenidc_callback_serialiser_function, &name ), \
+ 0 \
+}
+
+#define XENIDC_CALLBACK_SERIALISER( name ) \
+xenidc_callback_serialiser name = \
+ XENIDC_CALLBACK_SERIALISER_INIT( name )
+
+/* The service completes the callback to the serialiser which serialises the */
+/* completions to the client, performing them in submission order. */
+
+static inline void xenidc_callback_serialiser_complete_callback
+(
+ xenidc_callback_serialiser * serialiser,
+ xenidc_callback * callback,
+ xenidc_error error
+)
+{
+ xenidc_callback_set_error( callback, error );
+
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave( &serialiser->lock, flags );
+
+ list_add_tail
+ ( xenidc_callback_to_link( callback ), &serialiser->list );
+
+ spin_unlock_irqrestore( &serialiser->lock, flags );
+ }
+
+ xenidc_work_schedule( &serialiser->work );
+}
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_channel.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_channel.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,146 @@
+/*****************************************************************************/
+/* Xen inter-domain communication channel abstract base class. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef _XENIDC_CHANNEL_H
+#define _XENIDC_CHANNEL_H
+
+#include <asm-xen/xenidc_callback.h>
+#include <asm-xen/xenidc_local_buffer_reference.h>
+
+typedef struct xenidc_channel_message_struct xenidc_channel_message;
+
+struct xenidc_channel_message_struct
+{
+ xenidc_callback callback;
+ xenidc_local_buffer_reference message_lbr;
+};
+
+#define XENIDC_CHANNEL_MESSAGE_LINK callback.XENIDC_CALLBACK_LINK
+
+static inline struct list_head * xenidc_channel_message_to_link
+ ( xenidc_channel_message * message )
+{
+ return &message->XENIDC_CHANNEL_MESSAGE_LINK;
+}
+
+static inline xenidc_callback * xenidc_channel_message_to_callback
+ ( xenidc_channel_message * message )
+{
+ return &message->callback;
+}
+
+static inline xenidc_channel_message * xenidc_channel_message_callback_to
+ ( xenidc_callback * callback )
+{
+ return container_of( callback, xenidc_channel_message, callback );
+}
+
+static inline void xenidc_channel_message_init
+ ( xenidc_channel_message * message, xenidc_callback_function * callback )
+{
+ xenidc_callback_init
+ ( xenidc_channel_message_to_callback( message ), callback );
+}
+
+static inline void xenidc_channel_message_set_message_lbr
+ ( xenidc_channel_message * message, xenidc_local_buffer_reference lbr )
+{
+ message->message_lbr = lbr;
+}
+
+typedef struct xenidc_channel_struct xenidc_channel;
+
+struct xenidc_channel_struct
+{
+ void ( * submit_message )
+ ( xenidc_channel * channel, xenidc_channel_message * message );
+ void * client_context;
+ void ( * connect )( void * client_context );
+ void ( * handle_message )
+ ( void * client_context, xenidc_channel_message * message );
+ void ( * disconnect )
+ ( void * client_context, xenidc_callback * callback );
+};
+
+/* Called by a derived class to initialise the base class. */
+
+static inline void xenidc_channel_init
+(
+ xenidc_channel * channel,
+ void ( * submit_message )
+ ( xenidc_channel * channel, xenidc_channel_message * message )
+)
+{
+ channel->submit_message = submit_message;
+}
+
+/* Called by a derived class to notify the client. */
+
+static inline void xenidc_channel_connect( xenidc_channel * channel )
+{
+ channel->connect( channel->client_context );
+}
+
+/* Called by a derived class to notify the client. */
+
+static inline void xenidc_channel_handle_message
+ ( xenidc_channel * channel, xenidc_channel_message * message )
+{
+ channel->handle_message( channel->client_context, message );
+}
+
+/* Called by a derived class to notify the client. */
+
+static inline void xenidc_channel_disconnect
+ ( xenidc_channel * channel, xenidc_callback * callback )
+{
+ channel->disconnect( channel->client_context, callback );
+}
+
+/* Called by the client class before derived class first calls connect. */
+
+static inline void xenidc_channel_install_client
+(
+ xenidc_channel * channel,
+ void * client_context,
+ void ( * connect )( void * client_context ),
+ void ( * handle_message )
+ ( void * client_context, xenidc_channel_message * message ),
+ void ( * disconnect )
+ ( void * client_context, xenidc_callback * callback )
+)
+{
+ channel->client_context = client_context;
+ channel->connect = connect;
+ channel->handle_message = handle_message;
+ channel->disconnect = disconnect;
+}
+
+/* Called by the client class between connect and disconnect callback to */
+/* submit a message. */
+
+static inline void xenidc_channel_submit_message
+ ( xenidc_channel * channel, xenidc_channel_message * message )
+{
+ channel->submit_message( channel, message );
+}
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_concatenate.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_concatenate.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,47 @@
+/*****************************************************************************/
+/* Support for concatenated local buffer references */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef XENIDC_CONCATENATE_H
+#define XENIDC_CONCATENATE_H
+
+#include "xenidc.h"
+
+typedef struct xenidc_concatenate_base_struct xenidc_concatenate_base;
+
+struct xenidc_concatenate_base_struct
+{
+ xenidc_local_buffer_reference * head;
+ xenidc_local_buffer_reference * tail;
+};
+
+/* To create a concatenated lbr, you need a base resource which will persist */
+/* for the lifetime of the created lbr. Pass a pointer to this resource and */
+/* pointers to the underlying lbrs to concatenate. These must also persist */
+/* for the lifetime of the created lbr. */
+
+extern xenidc_local_buffer_reference xenidc_concatenate_create_lbr
+(
+ xenidc_concatenate_base * base,
+ xenidc_local_buffer_reference * head,
+ xenidc_local_buffer_reference * tail
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_endpoint.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_endpoint.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,203 @@
+/*****************************************************************************/
+/* Xen inter-domain communication endpoint. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef __ASM_XEN_XENIDC_ENDPOINT_H__
+#define __ASM_XEN_XENIDC_ENDPOINT_H__
+
+#include "xenidc_address.h"
+#include "xenidc_gateway.h"
+#include "xenidc_xbgt_channel.h"
+
+typedef struct xenidc_gateway_message_struct xenidc_endpoint_message;
+
+#define XENIDC_ENDPOINT_MESSAGE_LINK XENIDC_GATEWAY_MESSAGE_LINK
+
+static inline xenidc_callback * xenidc_endpoint_message_to_callback
+ ( xenidc_endpoint_message * message )
+{
+ return xenidc_gateway_message_to_callback( message );
+}
+
+static inline xenidc_endpoint_message * xenidc_endpoint_message_callback_to
+ ( xenidc_callback * callback )
+{
+ return xenidc_gateway_message_callback_to( callback );
+}
+
+static inline struct list_head * xenidc_endpoint_message_to_link
+ ( xenidc_endpoint_message * message )
+{
+ return xenidc_callback_to_link
+ ( xenidc_endpoint_message_to_callback( message ) );
+}
+
+static inline xenidc_endpoint_message * xenidc_endpoint_message_link_to
+ ( struct list_head * link )
+{
+ return xenidc_endpoint_message_callback_to
+ ( xenidc_callback_link_to( link ) );
+}
+
+static inline void xenidc_endpoint_message_init
+ ( xenidc_endpoint_message * message, xenidc_callback_function * callback )
+{
+ xenidc_gateway_message_init( message, callback );
+}
+
+static inline void xenidc_endpoint_message_set_message_lbr
+ ( xenidc_endpoint_message * message, xenidc_local_buffer_reference lbr )
+{
+ message->message_lbr = lbr;
+}
+
+static inline xenidc_local_buffer_reference *
+ xenidc_endpoint_message_to_message_lbr( xenidc_endpoint_message * message )
+{
+ return &message->message_lbr;
+}
+
+typedef struct xenidc_gateway_transaction_struct xenidc_endpoint_transaction;
+
+#define XENIDC_ENDPOINT_TRANSACTION_LINK XENIDC_GATEWAY_TRANSACTION_LINK
+
+static inline xenidc_callback * xenidc_endpoint_transaction_to_callback
+ ( xenidc_endpoint_transaction * transaction )
+{
+ return xenidc_gateway_transaction_to_callback( transaction );
+}
+
+static inline xenidc_endpoint_transaction *
+ xenidc_endpoint_transaction_callback_to( xenidc_callback * callback )
+{
+ return xenidc_gateway_transaction_callback_to( callback );
+}
+
+static inline struct list_head * xenidc_endpoint_transaction_to_link
+ ( xenidc_endpoint_transaction * transaction )
+{
+ return xenidc_callback_to_link
+ ( xenidc_endpoint_transaction_to_callback( transaction ) );
+}
+
+static inline xenidc_endpoint_transaction * xenidc_endpoint_transaction_link_to
+ ( struct list_head * link )
+{
+ return xenidc_endpoint_transaction_callback_to
+ ( xenidc_callback_link_to( link ) );
+}
+
+static inline void xenidc_endpoint_transaction_init
+(
+ xenidc_endpoint_transaction * transaction,
+ xenidc_callback_function * callback
+)
+{
+ xenidc_gateway_transaction_init( transaction, callback );
+}
+
+static inline void xenidc_endpoint_transaction_set_parameters_lbr
+(
+ xenidc_endpoint_transaction * transaction,
+ xenidc_local_buffer_reference lbr
+)
+{
+ transaction->parameters_lbr = lbr;
+}
+
+static inline void xenidc_endpoint_transaction_set_status_lbr
+(
+ xenidc_endpoint_transaction * transaction,
+ xenidc_local_buffer_reference lbr
+)
+{
+ transaction->status_lbr = lbr;
+}
+
+static inline xenidc_local_buffer_reference *
+ xenidc_endpoint_transaction_to_parameters_lbr
+ ( xenidc_endpoint_transaction * transaction )
+{
+ return &transaction->parameters_lbr;
+}
+
+static inline xenidc_local_buffer_reference *
+ xenidc_endpoint_transaction_to_status_lbr
+ ( xenidc_endpoint_transaction * transaction )
+{
+ return &transaction->status_lbr;
+}
+
+static inline void xenidc_endpoint_transaction_complete
+ ( xenidc_endpoint_transaction * transaction, xenidc_error error )
+{
+ xenidc_callback_complete
+ ( xenidc_endpoint_transaction_to_callback( transaction ), error );
+}
+
+static inline xenidc_error xenidc_endpoint_transaction_query_error
+ ( xenidc_endpoint_transaction * transaction )
+{
+ return xenidc_callback_query_error
+ ( xenidc_endpoint_transaction_to_callback( transaction ) );
+}
+
+typedef struct xenidc_endpoint_struct xenidc_endpoint;
+
+struct xenidc_endpoint_struct
+{
+ xenidc_gateway gateway;
+ xenidc_xbgt_channel channel;
+};
+
+extern int xenidc_endpoint_init
+(
+ xenidc_endpoint * endpoint,
+
+ void ( * connect )( xenidc_endpoint * endpoint ),
+ void ( * handle_message )
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_message * message ),
+ void ( * handle_transaction )
+ (
+ xenidc_endpoint * endpoint,
+ xenidc_endpoint_transaction * transaction
+ ),
+ void ( * disconnect )
+ ( xenidc_endpoint * endpoint, xenidc_callback * callback ),
+ u32 initiator_quota,
+ xenidc_buffer_byte_count initiator_maximum_byte_count,
+ u32 target_quota,
+ xenidc_buffer_byte_count target_maximum_byte_count
+);
+
+extern void xenidc_endpoint_create
+ ( xenidc_endpoint * endpoint, xenidc_address address );
+
+extern void xenidc_endpoint_submit_message
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_message * message );
+
+extern void xenidc_endpoint_submit_transaction
+ ( xenidc_endpoint * endpoint, xenidc_endpoint_transaction * transaction );
+
+extern void xenidc_endpoint_destroy( xenidc_endpoint * endpoint );
+
+extern void xenidc_endpoint_exit( xenidc_endpoint * endpoint );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_error.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_error.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,56 @@
+#ifndef __ASM_XEN_XENIDC_ERROR_H__
+#define __ASM_XEN_XENIDC_ERROR_H__
+
+#include <asm/types.h>
+
+typedef u32 xenidc_error;
+
+/* The first few error numbers are reserved for success and transport errors */
+/* which are common to all IDC protocols. */
+
+#define XENIDC_ERROR_SUCCESS ( (xenidc_error)0 )
+#define XENIDC_ERROR_ABORTED ( (xenidc_error)1 )
+#define XENIDC_ERROR_FAILURE ( (xenidc_error)2 )
+#define XENIDC_ERROR_DISCONNECT ( (xenidc_error)3 )
+/* Initiator did everything right, target software needs to be fixed: */
+#define XENIDC_ERROR_IMPLEMENTATION_DEFICIENCY ( (xenidc_error)4 )
+/* Unexpected transaction/transaction in wrong sequence etc: */
+#define XENIDC_ERROR_INVALID_PROTOCOL ( (xenidc_error)5 )
+/* Underlength parameters/status etc: */
+#define XENIDC_ERROR_INVALID_FORMAT ( (xenidc_error)6 )
+/* Parameter value wrong: */
+#define XENIDC_ERROR_INVALID_PARAMETER ( (xenidc_error)7 )
+/* Something about a request exceeded a hard-coded limit: */
+#define XENIDC_ERROR_TOO_BIG ( (xenidc_error)8 )
+
+static inline xenidc_error xenidc_error_map_local_to( int error )
+{
+ /* FIXME */
+ switch( error )
+ {
+ case 0:
+ return XENIDC_ERROR_SUCCESS;
+ default:
+ return XENIDC_ERROR_FAILURE;
+ }
+}
+
+static inline int xenidc_error_map_to_local( xenidc_error error )
+{
+ /* FIXME */
+ switch( error )
+ {
+ case XENIDC_ERROR_SUCCESS:
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+/* Protocols can define their own set of protocol specific errors starting */
+/* at this one. The driver code on either side must translate between the */
+/* local OS specific error codes and the protocol specific error codes. */
+
+#define XENIDC_ERROR_PROTOCOL_SPECIFIC_FIRST ( (xenidc_error)256 )
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_gateway.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_gateway.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,253 @@
+/*****************************************************************************/
+/* Xen inter-domain communication gateway class. This class uses the message */
+/* channel service provided by a xenidc_channel to implement a gateway */
+/* service which allows the client to send both messages and transactions */
+/* (consisting of parameters and status) between domains. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef _XENIDC_GATEWAY_H
+#define _XENIDC_GATEWAY_H
+
+#include <asm-xen/xenidc_callback.h>
+#include <asm-xen/xenidc_channel.h>
+#include <asm-xen/xenidc_local_buffer_reference.h>
+
+typedef struct xenidc_gateway_initiator_resource_struct
+ xenidc_gateway_initiator_resource;
+
+typedef struct xenidc_gateway_target_resource_struct
+ xenidc_gateway_target_resource;
+
+typedef struct xenidc_gateway_message_and_transaction_header_struct
+ xenidc_gateway_message_and_transaction_header;
+
+struct xenidc_gateway_message_and_transaction_header_struct
+{
+ xenidc_callback callback;
+ int transaction_not_message;
+};
+
+#define XENIDC_GATEWAY_MESSAGE_AND_TRANSACTION_HEADER_LINK \
+callback.XENIDC_CALLBACK_LINK
+
+static inline struct list_head *
+ xenidc_gateway_message_and_transaction_header_to_link
+ ( xenidc_gateway_message_and_transaction_header * header )
+{
+ return xenidc_callback_to_link( &header->callback );
+}
+
+static inline xenidc_callback *
+ xenidc_gateway_message_and_transaction_header_to_callback
+ ( xenidc_gateway_message_and_transaction_header * header )
+{
+ return &header->callback;
+}
+
+typedef struct xenidc_gateway_message_struct xenidc_gateway_message;
+
+struct xenidc_gateway_message_struct
+{
+ xenidc_gateway_message_and_transaction_header header;
+ xenidc_local_buffer_reference message_lbr;
+};
+
+static inline xenidc_callback * xenidc_gateway_message_to_callback
+ ( xenidc_gateway_message * message )
+{
+ return &message->header.callback;
+}
+
+static inline xenidc_gateway_message * xenidc_gateway_message_callback_to
+ ( xenidc_callback * callback )
+{
+ return container_of( callback, xenidc_gateway_message, header.callback );
+}
+
+static inline struct list_head * xenidc_gateway_message_to_link
+ ( xenidc_gateway_message * message )
+{
+ return xenidc_callback_to_link( &message->header.callback );
+}
+
+static inline xenidc_gateway_message * xenidc_gateway_message_link_to
+ ( struct list_head * link )
+{
+ return xenidc_gateway_message_callback_to
+ ( xenidc_callback_link_to( link ) );
+}
+
+static inline xenidc_gateway_message * xenidc_gateway_message_header_to
+ ( xenidc_gateway_message_and_transaction_header * header )
+{
+ return container_of( header, xenidc_gateway_message, header );
+}
+
+static inline void xenidc_gateway_message_init
+ ( xenidc_gateway_message * message, xenidc_callback_function * callback )
+{
+ xenidc_callback_init
+ ( xenidc_gateway_message_to_callback( message ), callback );
+
+ message->header.transaction_not_message = 0;
+}
+
+typedef struct xenidc_gateway_transaction_struct xenidc_gateway_transaction;
+
+struct xenidc_gateway_transaction_struct
+{
+ xenidc_gateway_message_and_transaction_header header;
+ xenidc_local_buffer_reference parameters_lbr;
+ xenidc_local_buffer_reference status_lbr;
+};
+
+#define XENIDC_GATEWAY_TRANSACTION_LINK header.callback.XENIDC_CALLBACK_LINK
+
+static inline xenidc_callback * xenidc_gateway_transaction_to_callback
+ ( xenidc_gateway_transaction * transaction )
+{
+ return &transaction->header.callback;
+}
+
+static inline xenidc_gateway_transaction *
+ xenidc_gateway_transaction_callback_to( xenidc_callback * callback )
+{
+ return container_of
+ ( callback, xenidc_gateway_transaction, header.callback );
+}
+
+static inline struct list_head * xenidc_gateway_transaction_to_link
+ ( xenidc_gateway_transaction * transaction )
+{
+ return xenidc_callback_to_link
+ ( xenidc_gateway_transaction_to_callback( transaction ) );
+}
+
+static inline xenidc_gateway_transaction * xenidc_gateway_transaction_link_to
+ ( struct list_head * link )
+{
+ return xenidc_gateway_transaction_callback_to
+ ( xenidc_callback_link_to( link ) );
+}
+
+static inline xenidc_gateway_transaction * xenidc_gateway_transaction_header_to
+ ( xenidc_gateway_message_and_transaction_header * header )
+{
+ return container_of( header, xenidc_gateway_transaction, header );
+}
+
+static inline void xenidc_gateway_transaction_init
+(
+ xenidc_gateway_transaction * transaction,
+ xenidc_callback_function * callback
+)
+{
+ xenidc_callback_init
+ ( xenidc_gateway_transaction_to_callback( transaction ), callback );
+
+ transaction->header.transaction_not_message = 1;
+}
+
+typedef enum
+{
+ xenidc_gateway_state_i,
+ xenidc_gateway_state_i_cc,
+ xenidc_gateway_state_i_cc_cd,
+ xenidc_gateway_state_i_cc_lc,
+ xenidc_gateway_state_i_cc_cd_lc,
+ xenidc_gateway_state_i_cc_lc_cd,
+ xenidc_gateway_state_i_cc_lc_cd_km,
+ xenidc_gateway_state_i_cc_cd_lc_lg,
+ xenidc_gateway_state_i_cc_cd_lc_ld,
+ xenidc_gateway_state_i_cc_cd_lc_lg_ld,
+ xenidc_gateway_state_i_cc_cd_lc_lg_ld_ti
+}
+xenidc_gateway_state;
+
+typedef struct xenidc_gateway_struct xenidc_gateway;
+
+struct xenidc_gateway_struct
+{
+ xenidc_channel * channel;
+ void ( * connect )( xenidc_gateway * gateway );
+ void ( * handle_message )
+ ( xenidc_gateway * gateway, xenidc_gateway_message * message );
+ void ( * handle_transaction )
+ ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction );
+ void ( * disconnect )
+ ( xenidc_gateway * gateway, xenidc_callback * callback );
+
+ u32 initiator_quota;
+ u32 target_quota;
+ xenidc_buffer_byte_count target_maximum_byte_count;
+
+ struct list_head initiator_resource_list;
+ xenidc_gateway_initiator_resource * initiator_resources;
+
+ struct list_head target_resource_list;
+ xenidc_gateway_target_resource * target_resources;
+
+ spinlock_t lock;
+
+ xenidc_gateway_state state;
+
+ struct list_head message_and_transaction_list;
+ struct list_head channel_message_list;
+
+ xenidc_work kick_messages_and_transactions_1_work;
+ xenidc_work kick_channel_messages_1_work;
+ xenidc_work connect_client_1_work;
+ xenidc_work disconnect_client_1_work;
+ xenidc_callback disconnect_client_2_callback;
+
+ int kick_messages_and_transactions_out : 1;
+ int kick_channel_messages_out : 1;
+ u32 initiator_resources_out;
+ u32 target_resources_out;
+
+ xenidc_callback * channel_disconnect_callback;
+};
+
+extern int xenidc_gateway_init
+(
+ xenidc_gateway * gateway,
+ xenidc_channel * channel,
+ void ( * connect )( xenidc_gateway * gateway ),
+ void ( * handle_message )
+ ( xenidc_gateway * gateway, xenidc_gateway_message * message ),
+ void ( * handle_transaction )
+ ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction ),
+ void ( * disconnect )
+ ( xenidc_gateway * gateway, xenidc_callback * callback ),
+ u32 initiator_quota,
+ xenidc_buffer_byte_count initiator_maximum_byte_count,
+ u32 target_quota,
+ xenidc_buffer_byte_count target_maximum_byte_count
+);
+
+extern void xenidc_gateway_submit_message
+ ( xenidc_gateway * gateway, xenidc_gateway_message * message );
+
+extern void xenidc_gateway_submit_transaction
+ ( xenidc_gateway * gateway, xenidc_gateway_transaction * transaction );
+
+extern void xenidc_gateway_exit( xenidc_gateway * gateway );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_gnttab_channel.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_gnttab_channel.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,222 @@
+/*****************************************************************************/
+/* This is a class which implements a grant-tables based inter-domain */
+/* message channel. The implementation of the bring-up and tear-down */
+/* handshaking is left to a derived class. */
+/* This class is used by xenidc_xbgt_channel (which implements bring-up and */
+/* teardown using xenbus) which is in turn used to implement the */
+/* xenidc_endpoint class. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef _XENIDC_GNTTAB_CHANNEL_H
+#define _XENIDC_GNTTAB_CHANNEL_H
+
+#include <asm-xen/gnttab.h>
+#include <asm-xen/xenidc_channel.h>
+
+typedef struct xenidc_gnttab_channel_struct xenidc_gnttab_channel;
+
+typedef struct xenidc_gnttab_channel_target_resource_struct
+ xenidc_gnttab_channel_target_resource;
+
+struct xenidc_gnttab_channel_target_resource_struct
+{
+ xenidc_channel_message message;
+ xenidc_gnttab_channel * channel;
+};
+
+#define XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_LINK \
+message.XENIDC_CHANNEL_MESSAGE_LINK
+
+typedef enum
+{
+ xenidc_gnttab_channel_state_i,
+ xenidc_gnttab_channel_state_i_c1r,
+ xenidc_gnttab_channel_state_i_c1r_c1c,
+ xenidc_gnttab_channel_state_i_c1r_c1c_c2r,
+ xenidc_gnttab_channel_state_i_c1r_c1c_d1r,
+ xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s,
+ xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc,
+ xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r,
+ xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc,
+ xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc,
+ xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc,
+ xenidc_gnttab_channel_state_i_c1r_c1c_c2r_c2s_ccc_d2r_ksc_krc_dcc_tri
+}
+xenidc_gnttab_channel_state;
+
+#define XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT 16
+
+struct xenidc_gnttab_channel_struct
+{
+ xenidc_channel channel;
+ void ( * protocol_error )( xenidc_gnttab_channel * channel );
+
+ xenidc_gnttab_channel * send_irq_context;
+ xenidc_gnttab_channel * recv_irq_context;
+
+ void * send_ring;
+ struct vm_struct * recv_ring_area;
+ grant_ref_t grant_ref_pool;
+
+ spinlock_t lock;
+
+ xenidc_gnttab_channel_state state;
+
+ struct list_head message_list;
+
+ xenidc_work do_phase_one_connect_1_work;
+ xenidc_work do_phase_two_connect_1_work;
+ xenidc_work connect_client_1_work;
+ xenidc_work disconnect_client_1_work;
+ xenidc_callback disconnect_client_2_callback;
+ xenidc_work do_phase_two_disconnect_1_work;
+ xenidc_work do_phase_one_disconnect_1_work;
+ xenidc_work kick_send_ring_1_work;
+ xenidc_work kick_recv_ring_1_work;
+
+ xenidc_gnttab_channel_target_resource target_resources
+ [ XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT ];
+ u8 target_resource_free
+ [ XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT ];
+ u16 target_resource_offset
+ [ XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT ];
+
+ int first_target_resource;
+ int next_target_resource;
+
+ int send_ring_kick_out : 1;
+ int recv_ring_kick_out : 1;
+
+ xenidc_callback * current_callback;
+
+ unsigned int send_event_channel;
+ grant_ref_t send_ring_ref;
+ int send_irq;
+
+ unsigned int recv_event_channel;
+ u16 recv_ring_handle;
+ xenidc_local_buffer_reference recv_ring_lbr;
+ int recv_irq;
+ u16 recv_ring_offset;
+};
+
+/* Cast to base class. */
+
+static inline xenidc_channel * xenidc_gnttab_channel_to_channel
+ ( xenidc_gnttab_channel * channel )
+{
+ return &channel->channel;
+}
+
+/* Cast from base class. */
+
+static inline xenidc_gnttab_channel * xenidc_gnttab_channel_channel_to
+ ( xenidc_channel * channel )
+{
+ return container_of( channel, xenidc_gnttab_channel, channel );
+}
+
+/* Called by derived class. */
+
+extern int xenidc_gnttab_channel_init
+(
+ xenidc_gnttab_channel * channel,
+ void ( * protocol_error )( xenidc_gnttab_channel * channel )
+);
+
+/* xenidc_gnttab_channel_phase_one_connect should never fail because we are */
+/* supposed to have reserved all required resources during initialisation. */
+/* Called by derived class. */
+
+typedef struct xenidc_gnttab_channel_phase_one_connect_request_struct
+ xenidc_gnttab_channel_phase_one_connect_request;
+
+struct xenidc_gnttab_channel_phase_one_connect_request_struct
+{
+ xenidc_callback callback;
+ domid_t remote_domain_id; /* IN */
+ grant_ref_t send_ring_ref; /* OUT */
+ unsigned int send_event_channel; /* OUT */
+};
+
+static inline xenidc_gnttab_channel_phase_one_connect_request *
+ xenidc_gnttab_channel_phase_one_connect_request_callback_to
+ ( xenidc_callback * callback )
+{
+ return container_of
+ ( callback, xenidc_gnttab_channel_phase_one_connect_request, callback );
+}
+
+extern void xenidc_gnttab_channel_phase_one_connect
+(
+ xenidc_gnttab_channel * channel,
+ xenidc_gnttab_channel_phase_one_connect_request * request
+);
+
+/* Called by derived class whilst phase one connected to reset the ring */
+/* before (re)establishing the connection with the other side. */
+
+extern void xenidc_gnttab_channel_reset_ring
+ ( xenidc_gnttab_channel * channel );
+
+/* xenidc_gnttab_channel_phase_two_connect should only fail if the remote */
+/* domain provided incorrect parameters. */
+/* Called by derived class. */
+
+typedef struct xenidc_gnttab_channel_phase_two_connect_request_struct
+ xenidc_gnttab_channel_phase_two_connect_request;
+
+struct xenidc_gnttab_channel_phase_two_connect_request_struct
+{
+ xenidc_callback callback;
+ domid_t remote_domain_id; /* IN */
+ grant_ref_t recv_ring_ref; /* IN */
+ unsigned int recv_event_channel; /* IN */
+};
+
+static inline xenidc_gnttab_channel_phase_two_connect_request *
+ xenidc_gnttab_channel_phase_two_connect_request_callback_to
+ ( xenidc_callback * callback )
+{
+ return container_of
+ ( callback, xenidc_gnttab_channel_phase_two_connect_request, callback );
+}
+
+extern void xenidc_gnttab_channel_phase_two_connect
+(
+ xenidc_gnttab_channel * channel,
+ xenidc_gnttab_channel_phase_two_connect_request * request
+);
+
+/* Called by derived class. */
+
+extern void xenidc_gnttab_channel_phase_two_disconnect
+ ( xenidc_gnttab_channel * channel, xenidc_callback * callback );
+
+/* Called by derived class. */
+
+extern void xenidc_gnttab_channel_phase_one_disconnect
+ ( xenidc_gnttab_channel * channel, xenidc_callback * callback );
+
+/* Called by derived class. */
+
+extern void xenidc_gnttab_channel_exit( xenidc_gnttab_channel * channel );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_local_buffer_reference.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_local_buffer_reference.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,283 @@
+/*****************************************************************************/
+/* Xen inter-domain communication local buffer reference object. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef __ASM_XEN_XENIDC_LOCAL_BUFFER_REFERENCE_H__
+#define __ASM_XEN_XENIDC_LOCAL_BUFFER_REFERENCE_H__
+
+#include <asm/types.h>
+#include "xenidc_callback.h"
+
+#define XENIDC_LOCAL_BUFFER_REFERENCE_TYPE_FLAG_VIRTUAL 0xC0000000
+#define XENIDC_LOCAL_BUFFER_REFERENCE_TYPE_FLAG_VIRTUAL_ADVANCE 0x80000000
+
+typedef u32 xenidc_buffer_type;
+
+typedef u32 xenidc_buffer_byte_count;
+
+typedef struct xenidc_local_buffer_reference_struct
+ xenidc_local_buffer_reference;
+
+struct xenidc_local_buffer_reference_struct
+{
+ xenidc_buffer_type type;
+ void * base;
+ xenidc_buffer_byte_count byte_offset;
+ xenidc_buffer_byte_count byte_count;
+};
+
+static inline xenidc_buffer_byte_count
+ xenidc_local_buffer_reference_query_byte_offset
+ ( xenidc_local_buffer_reference * lbr )
+{
+ return lbr->byte_offset;
+}
+
+static inline xenidc_buffer_byte_count
+ xenidc_local_buffer_reference_query_byte_count
+ ( xenidc_local_buffer_reference * lbr )
+{
+ return lbr->byte_count;
+}
+
+typedef struct xenidc_buffer_concrete_class_struct
+ xenidc_buffer_concrete_class;
+
+struct xenidc_buffer_concrete_class_struct
+{
+ struct list_head link;
+ xenidc_buffer_type type;
+ void ( * copy_in_or_out )
+ (
+ xenidc_buffer_concrete_class * class,
+ xenidc_local_buffer_reference * lbr,
+ void * buffer,
+ xenidc_buffer_byte_count byte_count,
+ int out
+ );
+ void ( * zero )
+ (
+ xenidc_buffer_concrete_class * class,
+ xenidc_local_buffer_reference * lbr
+ );
+};
+
+extern xenidc_buffer_type
+ xenidc_local_buffer_reference_register_buffer_concrete_class
+(
+ xenidc_buffer_concrete_class * class,
+ void ( * copy_in_or_out )
+ (
+ xenidc_buffer_concrete_class * class,
+ xenidc_local_buffer_reference * lbr,
+ void * buffer,
+ xenidc_buffer_byte_count byte_count,
+ int out
+ ),
+ void ( * zero ) /* NULL for the inefficient default */
+ (
+ xenidc_buffer_concrete_class * class,
+ xenidc_local_buffer_reference * lbr
+ )
+);
+
+typedef struct xenidc_buffer_copy_class_struct xenidc_buffer_copy_class;
+
+struct xenidc_buffer_copy_class_struct
+{
+ struct list_head link;
+ xenidc_buffer_type target_type;
+ xenidc_buffer_type source_type;
+ void ( * copy )
+ (
+ xenidc_buffer_copy_class * class,
+ xenidc_local_buffer_reference * target,
+ xenidc_local_buffer_reference * source,
+ xenidc_buffer_byte_count byte_count
+ );
+};
+
+extern void xenidc_local_buffer_reference_register_buffer_copy_class
+(
+ xenidc_buffer_copy_class * class,
+ xenidc_buffer_type target_type,
+ xenidc_buffer_type source_type,
+ void ( * copy )
+ (
+ xenidc_buffer_copy_class * class,
+ xenidc_local_buffer_reference * target,
+ xenidc_local_buffer_reference * source,
+ xenidc_buffer_byte_count byte_count
+ )
+);
+
+typedef struct xenidc_buffer_virtual_class_struct xenidc_buffer_virtual_class;
+
+struct xenidc_buffer_virtual_class_struct
+{
+ struct list_head link;
+ xenidc_buffer_type type;
+ xenidc_local_buffer_reference ( * resolve )
+ (
+ xenidc_buffer_virtual_class * class,
+ xenidc_local_buffer_reference * lbr
+ );
+ void ( * advance )
+ (
+ xenidc_buffer_virtual_class * class,
+ xenidc_local_buffer_reference * lbr,
+ xenidc_buffer_byte_count byte_count
+ );
+};
+
+extern xenidc_buffer_type
+ xenidc_local_buffer_reference_register_buffer_virtual_class
+(
+ xenidc_buffer_virtual_class * class,
+ xenidc_local_buffer_reference ( * resolve )
+ (
+ xenidc_buffer_virtual_class * class,
+ xenidc_local_buffer_reference * lbr
+ ),
+ void ( * advance ) /* NULL for the efficient default */
+ (
+ xenidc_buffer_virtual_class * class,
+ xenidc_local_buffer_reference * lbr,
+ xenidc_buffer_byte_count byte_count
+ )
+);
+
+/* Copy between an lbr and a buffer. Returns the number of bytes copied */
+/* which is the minimum of the source and target byte_counts. */
+
+extern xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_in_or_out
+(
+ xenidc_local_buffer_reference * lbr,
+ void * buffer,
+ xenidc_buffer_byte_count buffer_byte_count,
+ int out
+);
+
+static inline xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_out
+(
+ xenidc_local_buffer_reference * lbr,
+ void * target,
+ xenidc_buffer_byte_count target_byte_count
+)
+{
+ return xenidc_local_buffer_reference_copy_in_or_out
+ ( lbr, target, target_byte_count, 1 );
+}
+
+static inline xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_in
+(
+ xenidc_local_buffer_reference * lbr,
+ void * source,
+ xenidc_buffer_byte_count source_byte_count
+)
+{
+ return xenidc_local_buffer_reference_copy_in_or_out
+ ( lbr, source, source_byte_count, 0 );
+}
+
+extern void xenidc_local_buffer_reference_zero
+ ( xenidc_local_buffer_reference * lbr );
+
+extern xenidc_buffer_byte_count xenidc_local_buffer_reference_copy
+(
+ xenidc_local_buffer_reference * target,
+ xenidc_local_buffer_reference * source
+);
+
+extern xenidc_buffer_byte_count xenidc_local_buffer_reference_virtual_advance
+ ( xenidc_local_buffer_reference * lbr, xenidc_buffer_byte_count byte_count );
+
+/* Advance increments the offset and decrements the length by the amount */
+/* specified which is useful to advance the reference after having copied a */
+/* chunk of data into the start of the buffer. */
+/* Advance returns the remaining length. */
+
+static inline xenidc_buffer_byte_count xenidc_local_buffer_reference_advance
+ ( xenidc_local_buffer_reference * lbr, xenidc_buffer_byte_count byte_count )
+{
+ if
+ (
+ ( lbr->type & XENIDC_LOCAL_BUFFER_REFERENCE_TYPE_FLAG_VIRTUAL_ADVANCE )
+ ==
+ 0
+ )
+ {
+ if( lbr->byte_count > byte_count )
+ {
+ lbr->byte_offset += byte_count;
+ lbr->byte_count -= byte_count;
+ }
+ else
+ {
+ lbr->byte_offset += lbr->byte_count;
+ lbr->byte_count = 0;
+ }
+
+ return lbr->byte_count;
+ }
+ else
+ {
+ return
+ xenidc_local_buffer_reference_virtual_advance( lbr, byte_count );
+ }
+}
+
+/* Truncate reduces the length of the buffer which results in a reference to */
+/* the first byte_count bytes of the buffer (or the whole buffer, whichever */
+/* is less). */
+/* Truncate returns the resulting length of the buffer. */
+
+static inline xenidc_buffer_byte_count xenidc_local_buffer_reference_truncate
+(
+ xenidc_local_buffer_reference * lbr,
+ xenidc_buffer_byte_count byte_count
+)
+{
+ if( lbr->byte_count > byte_count )
+ {
+ lbr->byte_count = byte_count;
+ }
+
+ return lbr->byte_count;
+}
+
+/* Subrange reduces the range of the buffer by advancing the start */
+/* byte_offset bytes and reducing the length to the minimum of byte_count */
+/* and the remaining length. Subrange returns the resulting length of the */
+/* buffer. */
+
+static inline xenidc_buffer_byte_count xenidc_local_buffer_reference_subrange
+(
+ xenidc_local_buffer_reference * lbr,
+ xenidc_buffer_byte_count byte_offset,
+ xenidc_buffer_byte_count byte_count
+)
+{
+ (void)xenidc_local_buffer_reference_advance( lbr, byte_offset );
+
+ return xenidc_local_buffer_reference_truncate( lbr, byte_count );
+}
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_mapper_pool.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_mapper_pool.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,150 @@
+/*****************************************************************************/
+/* Xen inter-domain communication remote buffer reference mapper pool. */
+/* */
+/* TO MAP REMOTE BUFFERS INTO THE LOCAL ADDRESS SPACE. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef __ASM_XEN_XENIDC_RBR_MAPPER_POOL_H__
+#define __ASM_XEN_XENIDC_RBR_MAPPER_POOL_H__
+
+typedef struct xenidc_rbr_mapper_pool_struct xenidc_rbr_mapper_pool;
+
+/* xenidc_allocate_rbr_mapper_pool returns NULL if the pool cannot be */
+/* allocated or the anti-deadlock reservation fails. */
+
+extern xenidc_rbr_mapper_pool * xenidc_allocate_rbr_mapper_pool
+ ( u32 anti_deadlock_page_count );
+
+extern void xenidc_free_rbr_mapper_pool( xenidc_rbr_mapper_pool * pool );
+
+typedef struct xenidc_map_rbr_request_element_struct
+ xenidc_map_rbr_request_element;
+
+struct xenidc_map_rbr_request_element_struct
+{
+ struct list_head link;
+ xenidc_remote_buffer_reference rbr;
+ void * mapping;
+};
+
+static inline void xenidc_map_rbr_request_element_init
+ ( xenidc_map_rbr_request_element * element )
+{
+ memset( element, 0, sizeof( *element ) );
+
+ INIT_LIST_HEAD( &element->link );
+}
+
+static inline void xenidc_map_rbr_request_element_set_rbr
+(
+ xenidc_map_rbr_request_element * element,
+ xenidc_remote_buffer_reference rbr
+)
+{
+ element->rbr = rbr;
+}
+
+static inline void xenidc_map_rbr_request_element_ensure_removed
+ ( xenidc_map_rbr_request_element * element )
+{
+ list_del_init( &element->link );
+}
+
+typedef struct xenidc_reserve_and_map_rbr_request_struct
+ xenidc_reserve_and_map_rbr_request;
+
+struct xenidc_reserve_and_map_rbr_request_struct
+{
+ xenidc_callback map_callback;
+ xenidc_callback unmap_callback;
+ struct list_head request_elements;
+};
+
+static inline xenidc_callback *
+ xenidc_reserve_and_map_rbr_request_to_map_callback
+ ( xenidc_reserve_and_map_rbr_request * request )
+{
+ return &request->map_callback;
+}
+
+static inline xenidc_reserve_and_map_rbr_request *
+ xenidc_reserve_and_map_rbr_request_map_callback_to
+ ( xenidc_callback * callback )
+{
+ return container_of
+ ( callback, xenidc_reserve_and_map_rbr_request, map_callback );
+}
+
+static inline xenidc_callback *
+ xenidc_reserve_and_map_rbr_request_to_unmap_callback
+ ( xenidc_reserve_and_map_rbr_request * request )
+{
+ return &request->unmap_callback;
+}
+
+static inline xenidc_reserve_and_map_rbr_request *
+ xenidc_reserve_and_map_rbr_request_unmap_callback_to
+ ( xenidc_callback * callback )
+{
+ return container_of
+ ( callback, xenidc_reserve_and_map_rbr_request, unmap_callback );
+}
+
+static inline void xenidc_reserve_and_map_rbr_request_init
+(
+ xenidc_reserve_and_map_rbr_request * request,
+ xenidc_callback_function * map_callback,
+ xenidc_callback_function * unmap_callback
+)
+{
+ xenidc_callback_init( &request->map_callback, map_callback );
+ xenidc_callback_init( &request->unmap_callback, unmap_callback );
+
+ INIT_LIST_HEAD( &request->request_elements );
+}
+
+static inline void xenidc_reserve_and_map_rbr_request_add_element
+(
+ xenidc_reserve_and_map_rbr_request * request,
+ xenidc_map_rbr_request_element * element
+)
+{
+ list_add( &element->link, &request->request_elements );
+}
+
+extern void xenidc_rbr_mapper_pool_reserve_and_map_rbrs
+(
+ xenidc_rbr_mapper_pool * pool,
+ xenidc_reserve_and_map_rbr_request * request
+);
+
+extern void xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs
+(
+ xenidc_rbr_mapper_pool * pool,
+ xenidc_reserve_and_map_rbr_request * request
+);
+
+extern void xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs
+(
+ xenidc_rbr_mapper_pool * pool,
+ xenidc_reserve_and_map_rbr_request * request
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_provider_pool.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_rbr_provider_pool.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,160 @@
+/*****************************************************************************/
+/* Xen inter-domain communication remote buffer reference provider pool. */
+/* */
+/* TO CREATE REMOTE BUFFER REFERENCES TO GRANT OTHER DOMAINS ACCESS TO LOCAL */
+/* BUFFERS. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef __ASM_XEN_XENIDC_RBR_PROVIDER_POOL_H__
+#define __ASM_XEN_XENIDC_RBR_PROVIDER_POOL_H__
+
+#include "xenidc_remote_buffer_reference.h"
+
+typedef struct xenidc_rbr_provider_pool_struct xenidc_rbr_provider_pool;
+
+/* xenidc_allocate_rbr_provider_pool returns NULL if the pool cannot be */
+/* allocated or the anti-deadlock reservation fails. */
+
+extern xenidc_rbr_provider_pool * xenidc_allocate_rbr_provider_pool
+ ( u32 anti_deadlock_page_count );
+
+extern void xenidc_free_rbr_provider_pool( xenidc_rbr_provider_pool * pool );
+
+typedef struct xenidc_create_rbr_request_element_struct
+ xenidc_create_rbr_request_element;
+
+struct xenidc_create_rbr_request_element_struct
+{
+ struct list_head link;
+ xenidc_local_buffer_reference lbr;
+ xenidc_remote_buffer_reference rbr;
+};
+
+static inline void xenidc_create_rbr_request_element_init
+ ( xenidc_create_rbr_request_element * element )
+{
+ memset( element, 0, sizeof( *element ) );
+
+ INIT_LIST_HEAD( &element->link );
+}
+
+static inline void xenidc_create_rbr_request_element_set_lbr
+(
+ xenidc_create_rbr_request_element * element,
+ xenidc_local_buffer_reference lbr
+)
+{
+ element->lbr = lbr;
+}
+
+static inline xenidc_remote_buffer_reference
+ xenidc_create_rbr_request_element_query_rbr
+ ( xenidc_create_rbr_request_element * element )
+{
+ return element->rbr;
+}
+
+static inline void xenidc_create_rbr_request_element_ensure_removed
+ ( xenidc_create_rbr_request_element * element )
+{
+ list_del_init( &element->link );
+}
+
+typedef struct xenidc_reserve_and_create_rbr_request_struct
+ xenidc_reserve_and_create_rbr_request;
+
+struct xenidc_reserve_and_create_rbr_request_struct
+{
+ xenidc_callback create_callback;
+ xenidc_callback revoke_callback;
+ struct list_head request_elements;
+};
+
+static inline xenidc_callback *
+ xenidc_reserve_and_create_rbr_request_to_create_callback
+ ( xenidc_reserve_and_create_rbr_request * request )
+{
+ return &request->create_callback;
+}
+
+static inline xenidc_reserve_and_create_rbr_request *
+ xenidc_reserve_and_create_rbr_request_create_callback_to
+ ( xenidc_callback * callback )
+{
+ return container_of
+ ( callback, xenidc_reserve_and_create_rbr_request, create_callback );
+}
+
+static inline xenidc_callback *
+ xenidc_reserve_and_create_rbr_request_to_revoke_callback
+ ( xenidc_reserve_and_create_rbr_request * request )
+{
+ return &request->revoke_callback;
+}
+
+static inline xenidc_reserve_and_create_rbr_request *
+ xenidc_reserve_and_create_rbr_request_revoke_callback_to
+ ( xenidc_callback * callback )
+{
+ return container_of
+ ( callback, xenidc_reserve_and_create_rbr_request, revoke_callback );
+}
+
+static inline void xenidc_reserve_and_create_rbr_request_init
+(
+ xenidc_reserve_and_create_rbr_request * request,
+ xenidc_callback_function * create_callback,
+ xenidc_callback_function * revoke_callback
+)
+{
+ xenidc_callback_init( &request->create_callback, create_callback );
+ xenidc_callback_init( &request->revoke_callback, revoke_callback );
+
+ INIT_LIST_HEAD( &request->request_elements );
+}
+
+static inline void xenidc_reserve_and_create_rbr_request_add_element
+(
+ xenidc_reserve_and_create_rbr_request * request,
+ xenidc_create_rbr_request_element * element
+)
+{
+ list_add( &element->link, &request->request_elements );
+}
+
+extern void xenidc_rbr_provider_pool_reserve_and_create_rbrs
+(
+ xenidc_rbr_provider_pool * pool,
+ xenidc_reserve_and_create_rbr_request * request
+);
+
+extern void xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs
+(
+ xenidc_rbr_provider_pool * pool,
+ xenidc_reserve_and_create_rbr_request * request
+);
+
+extern void xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs
+(
+ xenidc_rbr_provider_pool * pool,
+ xenidc_reserve_and_create_rbr_request * request
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_remote_buffer_reference.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_remote_buffer_reference.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,42 @@
+/*****************************************************************************/
+/* Xen inter-domain communication remote buffer references. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef __ASM_XEN_XENIDC_REMOTE_BUFFER_REFERENCE_H__
+#define __ASM_XEN_XENIDC_REMOTE_BUFFER_REFERENCE_H__
+
+#include "xenidc_local_buffer_reference.h"
+
+typedef struct xenidc_remote_buffer_reference_struct
+ xenidc_remote_buffer_reference;
+
+struct xenidc_remote_buffer_reference_struct
+{
+ xenidc_buffer_byte_count byte_count;
+};
+
+static inline xenidc_buffer_byte_count
+ xenidc_remote_buffer_reference_query_byte_count
+ ( xenidc_remote_buffer_reference * rbr )
+{
+ return rbr->byte_count;
+}
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_vaddress.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_vaddress.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,30 @@
+/*****************************************************************************/
+/* Support for local buffer references of type vaddress. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef XENIDC_VADDRESS_H
+#define XENIDC_VADDRESS_H
+
+#include "xenidc.h"
+
+extern xenidc_local_buffer_reference xenidc_vaddress_create_lbr
+ ( void * address, xenidc_buffer_byte_count byte_count );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_work.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_work.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,160 @@
+/*****************************************************************************/
+/* Enhanced work queue service */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+/* This work queue service is a lot like the linux work queue service except */
+/* that it provides the interface xenidc_work_until which allows the client */
+/* to wait for a condition to be met even when the client is executing on a */
+/* work thread and the condition will only be satisfied by execution of */
+/* another work item. */
+
+#ifndef XENIDC_WORK_H
+#define XENIDC_WORK_H
+
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+typedef struct xenidc_work_struct xenidc_work;
+
+struct xenidc_work_struct
+{
+ struct list_head link;
+ void ( * function )( void * context );
+ void * context;
+};
+
+#define XENIDC_WORK_LINK link
+
+#define XENIDC_WORK_INIT( name, fn, ctx ) \
+{ LIST_HEAD_INIT( name.link ), fn, ctx }
+
+#define XENIDC_WORK( name, fn, ctx ) \
+xenidc_work name = XENIDC_WORK_INIT( name, fn, ctx )
+
+static inline void xenidc_work_init
+(
+ xenidc_work * work,
+ void ( * function )( void * context ),
+ void * context
+)
+{
+ INIT_LIST_HEAD( &work->link );
+
+ work->function = function;
+ work->context = context;
+}
+
+static inline struct list_head * xenidc_work_to_link( xenidc_work * work )
+{
+ return &work->link;
+}
+
+static inline xenidc_work * xenidc_work_link_to( struct list_head * link )
+{
+ return container_of( link, xenidc_work, link );
+}
+
+/* Returns 1 if scheduled this time or 0 if already scheduled. */
+
+int xenidc_work_schedule( xenidc_work * work );
+
+static inline void xenidc_work_perform_synchronously( xenidc_work * work )
+{
+ work->function( work->context );
+}
+
+/* Don't use any of these, they're just exposed for the macro below. */
+
+extern spinlock_t xenidc_work_list_lock;
+
+extern struct list_head xenidc_work_list;
+
+extern wait_queue_head_t xenidc_work_waitqueue;
+
+extern struct list_head xenidc_work_condition;
+
+/* Wait for a condition to be met. This works whether or not you call it */
+/* from a work item and works even when the condition will only be satisfied */
+/* by another work item. */
+
+#define xenidc_work_until( condition ) \
+do \
+{ \
+ unsigned long flags; \
+ \
+ spin_lock_irqsave( &xenidc_work_list_lock, flags ); \
+ \
+ for( ; ; ) \
+ { \
+ while \
+ ( \
+ ( !list_empty( &xenidc_work_list ) ) \
+ && \
+ ( !( condition ) ) \
+ ) \
+ { \
+ xenidc_work * work = list_entry \
+ ( \
+ xenidc_work_list.next, \
+ xenidc_work, \
+ link \
+ ); \
+ \
+ list_del_init( &work->link ); \
+ \
+ spin_unlock_irqrestore( &xenidc_work_list_lock, flags ); \
+ \
+ xenidc_work_perform_synchronously( work ); \
+ \
+ spin_lock_irqsave( &xenidc_work_list_lock, flags ); \
+ } \
+ \
+ if( condition ) \
+ { \
+ break; \
+ } \
+ \
+ { \
+ struct list_head link; \
+ \
+ INIT_LIST_HEAD( &link ); \
+ \
+ list_add_tail( &link, &xenidc_work_condition ); \
+ \
+ spin_unlock_irqrestore( &xenidc_work_list_lock, flags ); \
+ \
+ wait_event( xenidc_work_waitqueue, list_empty( &link ) ); \
+ \
+ spin_lock_irqsave( &xenidc_work_list_lock, flags ); \
+ } \
+ } \
+ \
+ spin_unlock_irqrestore( &xenidc_work_list_lock, flags ); \
+} \
+while( 0 )
+
+/* When you satisfy a condition, you should call this to kick any threads */
+/* waiting on the condition. */
+
+void xenidc_work_wake_up( void );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_wrapping.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_wrapping.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,48 @@
+/*****************************************************************************/
+/* Support for wrapping buffer local buffer references */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef XENIDC_WRAPPING_H
+#define XENIDC_WRAPPING_H
+
+#include "xenidc.h"
+
+typedef enum
+{
+ xenidc_wrapping_client_type_producer,
+ xenidc_wrapping_client_type_consumer
+}
+xenidc_wrapping_client_type;
+
+/* Create a reference to a wrapping buffer. Pass the start offset and the */
+/* end offset of the section of interest of the wrapping buffer. If the */
+/* start and end offsets are the same then a producer will get a reference */
+/* to the whole buffer to fill whereas a consumer will get a reference to a */
+/* zero length buffer. */
+
+extern xenidc_local_buffer_reference xenidc_wrapping_create_lbr
+(
+ xenidc_local_buffer_reference * underlying_buffer,
+ xenidc_buffer_byte_count start_offset,
+ xenidc_buffer_byte_count end_offset,
+ xenidc_wrapping_client_type client_type
+);
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 linux-2.6-xen-sparse/include/asm-xen/xenidc_xbgt_channel.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_xbgt_channel.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,142 @@
+/*****************************************************************************/
+/* This is a class which uses a xenidc_gnttab_channel (grant-tables based */
+/* message channel class) and xenbus to implement an interdomain message */
+/* channel with grant-tables based message transfer and xenbus based */
+/* bring-up and tear-down handshaking. */
+/* This class is used in the implementation of the xenidc_endpoint class. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+#ifndef _XENIDC_XBGT_CHANNEL_H
+#define _XENIDC_XBGT_CHANNEL_H
+
+#include <asm-xen/xenbus.h>
+#include <asm-xen/xenidc_gnttab_channel.h>
+
+typedef struct xenidc_xbgt_channel_struct xenidc_xbgt_channel;
+
+typedef enum
+{
+ xenidc_xbgt_channel_state_i,
+ xenidc_xbgt_channel_state_i_cn,
+ xenidc_xbgt_channel_state_i_cn_dn,
+ xenidc_xbgt_channel_state_i_cn_rs,
+ xenidc_xbgt_channel_state_i_cn_dn_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_dn,
+ xenidc_xbgt_channel_state_i_cn_rs_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rf,
+ xenidc_xbgt_channel_state_i_cn_dn_rs_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_dn_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_dn,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rf,
+ xenidc_xbgt_channel_state_i_cn_rs_rf_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od,
+ xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn,
+ xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs
+}
+xenidc_xbgt_channel_state;
+
+typedef enum
+{
+ xenidc_xbgt_channel_other_state_unknown,
+ xenidc_xbgt_channel_other_state_disconnected,
+ xenidc_xbgt_channel_other_state_ready,
+ xenidc_xbgt_channel_other_state_connected
+}
+xenidc_xbgt_channel_other_state;
+
+struct xenidc_xbgt_channel_struct
+{
+ xenidc_gnttab_channel channel;
+
+ struct xenbus_watch watch;
+
+ spinlock_t lock;
+
+ xenidc_xbgt_channel_state state;
+ xenidc_xbgt_channel_other_state other_state;
+
+ char * local_path;
+ char * remote_path;
+ domid_t remote_domain_id;
+
+ xenidc_callback * disconnect_callback;
+
+ int ready_ring_reference;
+ int ready_event_channel;
+
+ xenidc_work register_watch_1_work;
+ xenidc_work unregister_watch_1_work;
+ xenidc_work clear_store_1_work;
+ xenidc_work write_ready_1_work;
+ xenidc_work write_connected_1_work;
+ xenidc_work phase_one_connect_1_work;
+ xenidc_work phase_two_connect_1_work;
+ xenidc_work phase_two_disconnect_1_work;
+ xenidc_work phase_one_disconnect_1_work;
+
+ xenidc_gnttab_channel_phase_one_connect_request phase_one_connect_request;
+ xenidc_gnttab_channel_phase_two_connect_request phase_two_connect_request;
+
+ xenidc_callback phase_two_disconnect_callback;
+ xenidc_callback phase_one_disconnect_callback;
+};
+
+static inline xenidc_channel * xenidc_xbgt_channel_to_channel
+ ( xenidc_xbgt_channel * channel )
+{
+ return xenidc_gnttab_channel_to_channel( &channel->channel );
+}
+
+static inline xenidc_xbgt_channel * xenidc_xbgt_channel_gnttab_channel_to
+ ( xenidc_gnttab_channel * gnttab_channel )
+{
+ return container_of( gnttab_channel, xenidc_xbgt_channel, channel );
+}
+
+static inline xenidc_xbgt_channel * xenidc_xbgt_channel_channel_to
+ ( xenidc_channel * channel )
+{
+ return xenidc_xbgt_channel_gnttab_channel_to
+ ( xenidc_gnttab_channel_channel_to( channel ) );
+}
+
+extern int xenidc_xbgt_channel_init( xenidc_xbgt_channel * channel );
+
+extern void xenidc_xbgt_channel_connect
+(
+ xenidc_xbgt_channel * channel,
+ char * local_path,
+ char * remote_path,
+ domid_t remote_domain_id
+);
+
+extern void xenidc_xbgt_channel_disconnect
+ ( xenidc_xbgt_channel * channel, xenidc_callback * callback );
+
+extern void xenidc_xbgt_channel_exit( xenidc_xbgt_channel * channel );
+
+#endif
diff -r b5903c9aeda5 -r e93b9c54edb3 patches/linux-2.6.12/usb.patch
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/patches/linux-2.6.12/usb.patch Sun Oct 30 16:03:34 2005
@@ -0,0 +1,10 @@
+diff -Naur linux-2.6.12/drivers/usb/core/usb.c linux-2.6.12-usb/drivers/usb/core/usb.c
+--- linux-2.6.12/drivers/usb/core/usb.c 2005-06-17 20:48:29.000000000 +0100
++++ linux-2.6.12-usb/drivers/usb/core/usb.c 2005-09-28 13:01:29.000000000 +0100
+@@ -1561,4 +1561,6 @@
+ #endif
+ EXPORT_SYMBOL (usb_buffer_unmap_sg);
+
++EXPORT_SYMBOL (usb_bus_type);
++
+ MODULE_LICENSE("GPL");
diff -r b5903c9aeda5 -r e93b9c54edb3 xen/include/public/io/usbif.h
--- /dev/null Sun Oct 30 09:45:49 2005
+++ b/xen/include/public/io/usbif.h Sun Oct 30 16:03:34 2005
@@ -0,0 +1,357 @@
+/*****************************************************************************/
+/* FE->BE transactions for the USB split driver interface. */
+/* */
+/* Copyright (c) 2005 Harry Butterworth IBM Corporation */
+/* */
+/* This program is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2 of the License, or (at your */
+/* option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */
+/* Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License along */
+/* with this program; if not, write to the Free Software Foundation, Inc., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Based on the previous usbif.h by Mark Williamson and blkif.h, original */
+/* copyright notice follows... */
+/*****************************************************************************/
+
+/******************************************************************************
+ * usbif.h
+ *
+ * Unified block-device I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser
+ */
+
+#ifndef __SHARED_USBIF_H__
+#define __SHARED_USBIF_H__
+
+#include <asm-xen/xenidc.h>
+
+/* USBIF_MAX_PAGES_PER_REQUEST is the maximum number of pages a request is */
+/* allowed to require to construct the mapping in the back-end. */
+
+#define USBIF_MAX_PAGES_PER_REQUEST 128
+
+/* All transactions have the same header which specifies the type of the */
+/* transaction. */
+
+typedef struct usbif_transaction_parameters_header_struct
+ usbif_transaction_parameters_header;
+
+struct usbif_transaction_parameters_header_struct
+{
+ u8 transaction_type;
+ u8 reserved[ 7 ];
+};
+
+/* There are three types of transaction: */
+
+#define USBIF_TRANSACTION_TYPE_PROBE 0
+#define USBIF_TRANSACTION_TYPE_RESET 1
+#define USBIF_TRANSACTION_TYPE_IO 2
+
+/* The probe transaction is used to test whether a USB device is connected */
+/* to a port. */
+/* Port numbers start at 1. */
+
+typedef struct usbif_probe_transaction_parameters_struct
+ usbif_probe_transaction_parameters;
+
+struct usbif_probe_transaction_parameters_struct
+{
+ usbif_transaction_parameters_header header;
+ u32 port;
+ u8 reserved[ 4 ];
+};
+
+typedef struct usbif_probe_transaction_status_struct
+ usbif_probe_transaction_status;
+
+struct usbif_probe_transaction_status_struct
+{
+ u8 result;
+ u8 reserved[ 7 ];
+};
+
+#define USBIF_PROBE_RESULT_NO_DEVICE 0
+#define USBIF_PROBE_RESULT_DEVICE_PRESENT 1
+
+/* The reset transaction is used to reset a port. On success, the speed the */
+/* port is operating at after the reset is returned. */
+
+typedef struct usbif_reset_transaction_parameters_struct
+ usbif_reset_transaction_parameters;
+
+struct usbif_reset_transaction_parameters_struct
+{
+ usbif_transaction_parameters_header header;
+ u32 port;
+ u8 reserved[ 4 ];
+};
+
+/* On success, the reset returns status... */
+
+typedef struct usbif_reset_transaction_status_struct
+ usbif_reset_transaction_status;
+
+struct usbif_reset_transaction_status_struct
+{
+ u8 result;
+ u8 reserved[ 7 ];
+};
+
+#define USBIF_RESET_RESULT_FULL_SPEED 0
+#define USBIF_RESET_RESULT_LOW_SPEED 1
+#define USBIF_RESET_RESULT_HIGH_SPEED 2
+
+/* Aside from the usual transport errors, the reset transaction might fail */
+/* if there is no device. */
+
+/* All IO transactions have a header which specifies the type of IO */
+/* transaction and contains parameters common to all types of IO transaction.*/
+
+typedef struct usbif_io_transaction_parameters_header_struct
+ usbif_io_transaction_parameters_header;
+
+struct usbif_io_transaction_parameters_header_struct
+{
+ usbif_transaction_parameters_header header;
+ u8 io_transaction_type;
+ u8 device_number;
+ u8 endpoint;
+ u8 direction;
+ u32 unlink_id;
+ u32 flags;
+ u32 reserved;
+ xenidc_remote_buffer_reference rbr;
+};
+
+#define USBIF_IO_TRANSACTION_TYPE_CONTROL 0
+#define USBIF_IO_TRANSACTION_TYPE_BULK 1
+#define USBIF_IO_TRANSACTION_TYPE_INTERRUPT 2
+#define USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS 3
+/* Not a transaction type. For array bounds: */
+#define USBIF_IO_TRANSACTION_TYPE_LIMIT 4
+
+#define USBIF_IO_TRANSACTION_DIRECTION_OUT 0
+#define USBIF_IO_TRANSACTION_DIRECTION_IN 1
+
+#define USBIF_IO_FLAGS_SHORT_NOT_OK 0x00000001
+#define USBIF_IO_FLAGS_ZERO_PACKET 0x00000002
+
+typedef struct usbif_control_io_transaction_parameters_struct
+ usbif_control_io_transaction_parameters;
+
+struct usbif_control_io_transaction_parameters_struct
+{
+ usbif_io_transaction_parameters_header header;
+ u8 setup[ 8 ];
+};
+
+typedef struct usbif_bulk_io_transaction_parameters_struct
+ usbif_bulk_io_transaction_parameters;
+
+struct usbif_bulk_io_transaction_parameters_struct
+{
+ usbif_io_transaction_parameters_header header;
+};
+
+typedef struct usbif_interrupt_io_transaction_parameters_struct
+ usbif_interrupt_io_transaction_parameters;
+
+struct usbif_interrupt_io_transaction_parameters_struct
+{
+ usbif_io_transaction_parameters_header header;
+ u32 interval;
+};
+
+typedef struct usbif_isochronous_io_transaction_parameters_struct
+ usbif_isochronous_io_transaction_parameters;
+
+struct usbif_isochronous_io_transaction_parameters_struct
+{
+ usbif_io_transaction_parameters_header header;
+ u32 interval;
+ xenidc_remote_buffer_reference schedule_rbr;
+ u32 packet_count;
+};
+
+typedef struct usbif_isochronous_io_schedule_element_struct
+ usbif_isochronous_io_schedule_element;
+
+struct usbif_isochronous_io_schedule_element_struct
+{
+ xenidc_buffer_byte_count offset; /* IN offset into header's rbr */
+ xenidc_buffer_byte_count length; /* IN = expected, OUT = actual */
+ xenidc_error error; /* OUT for this packet. */
+};
+
+typedef struct usbif_io_transaction_status_struct
+ usbif_io_transaction_status;
+
+struct usbif_io_transaction_status_struct
+{
+ xenidc_buffer_byte_count length;
+};
+
+/* USBIF specific transaction error codes: */
+
+#define USBIF_XENIDC_ERROR_FAILURE \
+ ( XENIDC_ERROR_PROTOCOL_SPECIFIC_FIRST + 0 )
+#define USBIF_XENIDC_ERROR_NO_DEVICE \
+ ( XENIDC_ERROR_PROTOCOL_SPECIFIC_FIRST + 1 )
+#define USBIF_XENIDC_ERROR_UNLINKED \
+ ( XENIDC_ERROR_PROTOCOL_SPECIFIC_FIRST + 2 )
+
+static inline xenidc_error usbif_error_map_local_to( int error )
+{
+ switch( error )
+ {
+ /* FIXME: handle USB specific error codes. */
+ default:
+ return xenidc_error_map_local_to( error );
+ }
+}
+
+static inline int usbif_error_map_to_local( xenidc_error error )
+{
+ switch( error )
+ {
+ /* FIXME: handle USB specific error codes. */
+ default:
+ return xenidc_error_map_to_local( error );
+ }
+}
+
+/* Lookup table for sizes of io parameters structures. */
+
+static const xenidc_buffer_byte_count usbif_io_parameters_byte_count
+ [ USBIF_IO_TRANSACTION_TYPE_LIMIT ] =
+{
+ [ USBIF_IO_TRANSACTION_TYPE_CONTROL ] =
+ sizeof( usbif_control_io_transaction_parameters ),
+ [ USBIF_IO_TRANSACTION_TYPE_BULK ] =
+ sizeof( usbif_bulk_io_transaction_parameters ),
+ [ USBIF_IO_TRANSACTION_TYPE_INTERRUPT ] =
+ sizeof( usbif_interrupt_io_transaction_parameters ),
+ [ USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS ] =
+ sizeof( usbif_isochronous_io_transaction_parameters )
+};
+
+typedef union
+{
+ usbif_io_transaction_parameters_header header;
+ usbif_control_io_transaction_parameters control;
+ usbif_bulk_io_transaction_parameters bulk;
+ usbif_interrupt_io_transaction_parameters interrupt;
+ usbif_isochronous_io_transaction_parameters isochronous;
+}
+usbif_io_transaction_parameters;
+
+typedef union usbif_max_transaction_union usbif_max_transaction;
+
+union usbif_max_transaction_union
+{
+ struct
+ {
+ usbif_probe_transaction_parameters parameters;
+ usbif_probe_transaction_status status;
+ } probe;
+ struct
+ {
+ usbif_reset_transaction_parameters parameters;
+ usbif_reset_transaction_status status;
+ } reset;
+ struct
+ {
+ usbif_control_io_transaction_parameters parameters;
+ usbif_io_transaction_status status;
+ } control_io;
+ struct
+ {
+ usbif_bulk_io_transaction_parameters parameters;
+ usbif_io_transaction_status status;
+ } bulk_io;
+ struct
+ {
+ usbif_interrupt_io_transaction_parameters parameters;
+ usbif_io_transaction_status status;
+ } interrupt_io;
+ struct
+ {
+ usbif_isochronous_io_transaction_parameters parameters;
+ usbif_io_transaction_status status;
+ } isochronous_io;
+};
+
+/* All messages have the same header which specifies the type of the */
+/* message. */
+
+typedef struct usbif_message_header_struct usbif_message_header;
+
+struct usbif_message_header_struct
+{
+ u8 message_type;
+ u8 reserved[ 7 ];
+};
+
+/* There is only one type of message: */
+
+#define USBIF_MESSAGE_TYPE_UNLINK 0
+
+/* The unlink message is sent to unlink an IO operation. The backend will */
+/* ensure it completes or is failed out as quickly as possible. */
+/* This is a send and forget message: the client should wait for the */
+/* completion of the IO transaction as normal. */
+
+typedef struct usbif_unlink_message_body_struct usbif_unlink_message_body;
+
+struct usbif_unlink_message_body_struct
+{
+ usbif_message_header header;
+ u32 unlink_id;
+ u32 reserved;
+};
+
+typedef union usbif_max_message_union usbif_max_message;
+
+union usbif_max_message_union
+{
+ usbif_unlink_message_body unlink;
+};
+
+typedef union usbif_max_transaction_or_message_union
+ usbif_max_transaction_or_message;
+
+union usbif_max_transaction_or_message_union
+{
+ usbif_max_transaction transaction;
+ usbif_max_message message;
+};
+
+#define USBIF_BE_INITIATOR_QUOTA 0
+#define USBIF_BE_INITIATOR_MAXIMUM_BYTE_COUNT 0
+
+#define USBIF_BE_TARGET_QUOTA 32
+#define USBIF_BE_TARGET_MAXIMUM_BYTE_COUNT \
+( sizeof( usbif_max_transaction_or_message ) )
+
+#define USBIF_FE_INITIATOR_QUOTA USBIF_BE_TARGET_QUOTA
+#define USBIF_FE_INITIATOR_MAXIMUM_BYTE_COUNT \
+USBIF_BE_TARGET_MAXIMUM_BYTE_COUNT
+
+#define USBIF_FE_TARGET_QUOTA USBIF_BE_INITIATOR_QUOTA
+#define USBIF_FE_TARGET_MAXIMUM_BYTE_COUNT \
+USBIF_BE_INITIATOR_MAXIMUM_BYTE_COUNT
+
+#endif
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2005-11-05 18:00 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-10-30 16:43 USB virt status Harry Butterworth
[not found] ` <200511041725.11451.mark.williamson@cl.cam.ac.uk>
[not found] ` <1131130680.3019.87.camel@localhost.localdomain>
[not found] ` <200511050050.58120.mark.williamson@cl.cam.ac.uk>
2005-11-05 2:21 ` Harry Butterworth
2005-11-05 4:08 ` Nivedita Singhvi
2005-11-05 10:32 ` Keir Fraser
2005-11-05 11:30 ` Harry Butterworth
2005-11-05 18:00 ` Nivedita Singhvi
2005-11-05 13:06 ` Mark Williamson
2005-11-05 12:32 ` Mark Williamson
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.