diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/arch/xen/Kconfig --- a/linux-2.6-xen-sparse/arch/xen/Kconfig Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/arch/xen/Kconfig Mon Oct 24 15:04:49 2005 @@ -38,6 +38,14 @@ (e.g., hard drives, network cards). This allows you to configure such devices and also includes some low-level support that is otherwise not compiled into the kernel. + +config XEN_IDC_TRACE + bool "Inter-domain communication code tracing" + default y + help + This option causes the IDC code to output a continual trace of its + activity. + Say N here unless you are trying to debug this code. config XEN_BLKDEV_BACKEND bool "Block-device backend driver" @@ -69,6 +77,29 @@ The network-device backend driver allows the kernel to export its network devices to other guests via a high-performance shared-memory interface. + +config XEN_USBDEV_BACKEND + tristate "USB-device backend driver" + depends on XEN_PHYSDEV_ACCESS + select USB + default m + help + The USB-device backend driver allows the kernel to export USB + devices to USB-device frontend drivers running in other domains. + This is not required for USB device access in domain 0 or any domain + given exclusive control over a USB host controller device at the PCI + level. + Say Y or M if you want to use this kernel to export a USB device to + another domain running a USB-device frontend driver. + +config XEN_USBDEV_BACKEND_TRACE + bool "USB-device backend driver tracing" + depends on XEN_USBDEV_BACKEND + default y + help + This option causes the driver to output a continual trace of its + activity. + Say N here unless you are trying to debug the driver. config XEN_TPMDEV_FRONTEND bool "TPM-device frontend driver" @@ -128,6 +159,30 @@ are unsure; or if you experience network hangs when this option is enabled; then you must say N here. +config XEN_USBDEV_FRONTEND + tristate "USB-device frontend driver" + select USB + default m + help + The USB-device frontend driver allows the kernel to access USB + devices exported by a USB-device backend driver running in another + domain. + This is not required for USB device access in domain 0 or any domain + given exclusive control over a USB host controller device at the PCI + level. + Say Y or M if you want to use a USB-device backend driver to export a + USB device from another domain to the domain which will run this + kernel. + +config XEN_USBDEV_FRONTEND_TRACE + bool "USB-device frontend driver tracing" + depends on XEN_USBDEV_FRONTEND + default y + help + This option causes the driver to output a continual trace of its + activity. + Say N here unless you are trying to debug the driver. + config XEN_BLKDEV_TAP bool "Block device tap driver" default n diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/Makefile Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Mon Oct 24 15:04:49 2005 @@ -1,4 +1,3 @@ - obj-y += util.o obj-y += console/ @@ -6,12 +5,14 @@ obj-y += balloon/ obj-y += privcmd/ obj-y += xenbus/ +obj-y += xenidc/ obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/ obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/ +obj-$(CONFIG_XEN_USBDEV_BACKEND) += usbback/ obj-$(CONFIG_XEN_TPMDEV_BACKEND) += tpmback/ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ +obj-$(CONFIG_XEN_USBDEV_FRONTEND) += usbfront/ obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ obj-$(CONFIG_XEN_TPMDEV_FRONTEND) += tpmfront/ - diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Mon Oct 24 15:04:49 2005 @@ -264,6 +264,7 @@ { return xenbus_register_driver_common(drv, &xenbus_backend); } +EXPORT_SYMBOL(xenbus_register_backend); void xenbus_unregister_driver(struct xenbus_driver *drv) { diff -r 1c62a4149b11 -r 5952173acc28 tools/python/xen/xend/server/usbif.py --- a/tools/python/xen/xend/server/usbif.py Mon Oct 24 07:04:38 2005 +++ b/tools/python/xen/xend/server/usbif.py Mon Oct 24 15:04:49 2005 @@ -22,8 +22,9 @@ """Support for virtual USB hubs. """ +from xen.xend import sxp + from xen.xend.server.DevController import DevController - class UsbifController(DevController): """USB device interface controller. Handles all USB devices @@ -35,8 +36,16 @@ """ DevController.__init__(self, vm) - - def getDeviceDetails(self, _): + def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" - return (self.allocateDeviceID(), {}, {}) + path = sxp.child_value(config, 'path') + + devid = self.allocateDeviceID() + + back = { 'path' : path, + 'handle' : "%i" % devid } + + front = { 'handle' : "%i" % devid } + + return (devid, back, front) diff -r 1c62a4149b11 -r 5952173acc28 tools/python/xen/xm/create.py --- a/tools/python/xen/xm/create.py Mon Oct 24 07:04:38 2005 +++ b/tools/python/xen/xm/create.py Mon Oct 24 15:04:49 2005 @@ -218,6 +218,10 @@ fn=set_bool, default=0, use="Make the domain a network interface backend.") +gopts.var('usbif', val='no|yes', + fn=set_bool, default=0, + use="Make the domain a USB device backend.") + gopts.var('tpmif', val='frontend=DOM', fn=append_value, default=[], use="""Make the domain a TPM interface backend. If frontend is given, @@ -238,10 +242,12 @@ For example '-pci c0,02,1a'. The option may be repeated to add more than one pci device.""") -gopts.var('usb', val='PATH', +gopts.var('usb', val="port=PORT,path=PATH,backend=DOM", fn=append_value, default=[], - use="""Add a physical USB port to a domain, as specified by the path - to that port. This option may be repeated to add more than one port.""") + use="""Add a USB device, as specified by the path to that device in + the backend domain, to the specified virtual hub port of a domain. + If backend is not specified the default backend driver domain is + used. This option may be repeated to add more than one port.""") gopts.var('ipaddr', val="IPADDR", fn=append_value, default=[], @@ -427,8 +433,13 @@ config_devs.append(['device', config_pci]) def configure_usb(opts, config_devs, vals): - for path in vals.usb: - config_usb = ['usb', ['path', path]] + for d in vals.usb: + path = d.get('path') + backend = d.get('backend') + config_usb = ['usb'] + config_usb.append(['path', path]) + if backend: + config_usb.append(['backend', backend]) config_devs.append(['device', config_usb]) def configure_vtpm(opts, config_devs, vals): @@ -578,6 +589,8 @@ config.append(['backend', ['blkif']]) if vals.netif: config.append(['backend', ['netif']]) + if vals.usbif: + config.append(['backend', ['usbif']]) if vals.tpmif: config.append(['backend', ['tpmif']]) if vals.restart: @@ -649,6 +662,22 @@ d[k] = v vifs.append(d) vals.vif = vifs + +def preprocess_usb(opts, vals): + if not vals.usb: return + usb = [] + for port in vals.usb: + d = {} + a = port.split(',') + for b in a: + (k, v) = b.strip().split('=', 1) + k = k.strip() + v = v.strip() + if k not in ['path', 'backend']: + opts.err('Invalid usb port specifier: ' + port) + d[k] = v + usb.append(d) + vals.usb = usb def preprocess_vtpm(opts, vals): if not vals.vtpm: return @@ -770,9 +799,10 @@ preprocess_ip(opts, vals) preprocess_nfs(opts, vals) preprocess_vnc(opts, vals) + preprocess_usb(opts, vals) preprocess_vtpm(opts, vals) preprocess_tpmif(opts, vals) - + def make_domain(opts, config): """Create, build and start a domain. diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/Makefile --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/Makefile Mon Oct 24 15:04:49 2005 @@ -0,0 +1,9 @@ +obj-$(CONFIG_XEN_USBDEV_BACKEND) += usbback.o + +usbback-objs := \ +usbback_device.o \ +usbback_driver_backend.o \ +usbback_driver.o \ +usbback_driver_port.o \ +usbback_driver_port_resource.o \ +usbback_module.o diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,43 @@ +/*****************************************************************************/ +/* Implementation of the ASSERT macro */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBBACK_ASSERT_H +#define USBBACK_ASSERT_H + +#include + +static inline void assert_failed + ( const char * function, int line, const char * statement ) +{ + printk + ( + KERN_ERR "usbback assert failed: %s line %d, statement %s\n", + function, + line, + statement + ); + + BUG(); +} + +#define ASSERT( S ) \ +( ( S ) ? ( (void)0 ) : assert_failed( __PRETTY_FUNCTION__, __LINE__, #S ) ) + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,411 @@ +/*****************************************************************************/ +/* A device object representing the low-level connection to a single */ +/* front-end. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Based on */ +/* */ +/* arch/xen/drivers/usbif/backend/control.c */ +/* arch/xen/drivers/usbif/backend/interface.c */ +/* arch/xen/drivers/usbif/backend/main.c */ +/* blkback/xenbus.c */ +/* */ +/* original copyright notices follow... */ +/*****************************************************************************/ + +/****************************************************************************** + * arch/xen/drivers/usbif/backend/control.c + * + * Routines for interfacing with the control plane. + * + * Copyright (c) 2004, Keir Fraser + */ + +/****************************************************************************** + * arch/xen/drivers/usbif/backend/interface.c + * + * USB device interface management. + * + * by Mark Williamson, Copyright (c) 2004 + */ + +/****************************************************************************** + * arch/xen/drivers/blkif/backend/interface.c + * + * Block-device interface management. + * + * Copyright (c) 2004, Keir Fraser + */ + +/****************************************************************************** + * arch/xen/drivers/usbif/backend/main.c + * + * Backend for the Xen virtual USB driver - provides an abstraction of a + * USB host controller to the corresponding frontend driver. + * + * by Mark Williamson + * Copyright (c) 2004 Intel Research Cambridge + * Copyright (c) 2004, 2005 Mark Williamson + * + * Based on arch/xen/drivers/blkif/backend/main.c + * Copyright (c) 2003-2004, Keir Fraser & Steve Hand + */ + +/* Xenbus code for blkif backend + Copyright (C) 2005 Rusty Russell + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 +#include +#include +#include "usbback_assert.h" +#include "usbback_device.h" +#include "usbback_driver.h" +#include "usbback_trace.h" + +struct usbback_device +{ + struct xenbus_device * dev; + void * drvdata; + long int frontend_id; + char * frontend; + xenidc_endpoint endpoint; +}; + +static inline struct usbback_device * usbback_device_endpoint_to + ( xenidc_endpoint * endpoint ) +{ + trace(); + + return container_of( endpoint, struct usbback_device, endpoint ); +} + +void usbback_device_set_drvdata( struct usbback_device * device, void * data ) +{ + trace(); + + device->drvdata = data; +} + +void * usbback_device_get_drvdata( struct usbback_device * device ) +{ + trace(); + + return device->drvdata; +} + +static void usbback_device_endpoint_connect( xenidc_endpoint * endpoint ) +{ + trace(); + + /* Transactions and messages received between connect and disconnect are */ + /* processed normally. */ + /* Between connect and completion of the disconnect callback we are */ + /* allowed to issue messages and transactions. We don't actually need */ + /* to issue messages or transactions from the backend to the frontend. */ + + usbback_driver_connect( usbback_device_endpoint_to( endpoint ) ); +} + +static void usbback_device_endpoint_disconnect + ( xenidc_endpoint * endpoint, xenidc_callback * callback ) +{ + trace(); + + /* We must stop issuing messages and transactions and complete the */ + /* callback once all of the messages and transactions we are issuing */ + /* have completed or failed back to us. */ + + /* After the disconnect, any messages or transactions we receive must be */ + /* failed back and we must flush through any that are in progress. */ + + usbback_driver_disconnect( usbback_device_endpoint_to( endpoint ) ); + + /* We can complete the callback immediately since we are not issuing any */ + /* messages or transactions from the backend to the frontend. */ + + xenidc_callback_success( callback ); +} + +static void usbback_device_endpoint_message + ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference message ) +{ + trace(); + + usbback_driver_message_handler + ( usbback_device_endpoint_to( endpoint ), message ); +} + +static void usbback_device_endpoint_transaction + ( xenidc_endpoint * endpoint, xenidc_transaction * transaction ) +{ + trace(); + + usbback_driver_transaction_handler + ( usbback_device_endpoint_to( endpoint ), transaction ); +} + +static int usbback_device_init_or_exit + ( struct usbback_device * device, struct xenbus_device * dev, int exit ) +{ + trace(); + + { + int return_value = 0; + + if( exit ) + { + goto EXIT; + } + + memset( device, 0, sizeof( *device ) ); + + device->dev = dev; + + return_value = usbback_driver_probe_usbback_device( device ); + + if( return_value != 0 ) + { + goto EXIT_NO_DRIVER; + } + + device->frontend = NULL; + + return_value = xenbus_gather + ( + NULL, /* FIXME? */ + dev->nodename, + "frontend-id", "%li", &device->frontend_id, + "frontend", NULL, &device->frontend, + NULL + ); + + if( XENBUS_EXIST_ERR( return_value ) ) + { + goto EXIT_NO_FRONTEND; + } + + if( return_value < 0 ) + { + xenbus_dev_error + ( + dev, + return_value, + "reading %s/frontend", + dev->nodename + ); + + goto EXIT_NO_FRONTEND; + } + + return_value = xenidc_endpoint_init + ( + &device->endpoint, + usbback_device_endpoint_connect, + usbback_device_endpoint_disconnect, + usbback_device_endpoint_message, + usbback_device_endpoint_transaction, + USBIF_BE_INITIATOR_MESSAGE_MAXIMUM_BYTE_COUNT, + USBIF_BE_INITIATOR_TRANSACTION_QUOTA, + USBIF_BE_INITIATOR_TRANSACTION_MAXIMUM_BYTE_COUNT, + USBIF_BE_TARGET_MESSAGE_MAXIMUM_BYTE_COUNT, + USBIF_BE_TARGET_TRANSACTION_QUOTA, + USBIF_BE_TARGET_TRANSACTION_MAXIMUM_BYTE_COUNT + ); + + if( return_value != 0 ) + { + goto EXIT_NO_ENDPOINT; + } + + { + xenidc_address address; + + xenidc_address_init + ( + &address, + dev->nodename, + device->frontend, + device->frontend_id + ); + + return_value = + xenidc_endpoint_create( &device->endpoint, address ); + + if( return_value != 0 ) + { + goto EXIT_NO_CREATE; + } + } + + return 0; + + EXIT: + + xenidc_endpoint_destroy( &device->endpoint ); + + EXIT_NO_CREATE: + + xenidc_endpoint_exit( &device->endpoint ); + + EXIT_NO_ENDPOINT: + + kfree( device->frontend ); + + EXIT_NO_FRONTEND: + + usbback_driver_remove_usbback_device( device ); + + EXIT_NO_DRIVER: + + return return_value; + } +} + +static int usbback_device_init + ( struct usbback_device * device, struct xenbus_device * dev ) +{ + trace(); + + return usbback_device_init_or_exit( device, dev, 0 ); +} + +static void usbback_device_exit( struct usbback_device * device ) +{ + trace(); + + (void)usbback_device_init_or_exit( device, NULL, 1 ); +} + +static int usbback_device_probe_or_remove + ( struct xenbus_device * dev, int remove ) +{ + trace(); + + { + int return_value = 0; + + struct usbback_device * device; + + if( remove ) + { + goto REMOVE; + } + + device = kmalloc( sizeof( *device ), GFP_KERNEL ); + + if( device == NULL ) + { + xenbus_dev_error( dev, -ENOMEM, "allocating backend structure" ); + + return_value = -ENOMEM; + + goto EXIT_NO_DEVICE; + } + + dev->data = device; + + return_value = usbback_device_init( device, dev ); + + if( return_value != 0 ) + { + goto EXIT_INIT_FAILED; + } + + return 0; + + REMOVE: + + device = dev->data; + + usbback_device_exit( device ); + + EXIT_INIT_FAILED: + + dev->data = NULL; + + kfree( device ); + + EXIT_NO_DEVICE: + + return return_value; + } +} + +static int usbback_device_probe + ( struct xenbus_device * dev, const struct xenbus_device_id * id ) +{ + trace(); + + return usbback_device_probe_or_remove( dev, 0 ); +} + +static int usbback_device_remove( struct xenbus_device * dev ) +{ + trace(); + + return usbback_device_probe_or_remove( dev, 1 ); +} + +static struct xenbus_device_id usbback_device_ids[] = +{ + { "usb" }, + { "" } +}; + +static struct xenbus_driver usbback_device_driver = +{ + .name = "usb", + .owner = THIS_MODULE, + .ids = usbback_device_ids, + .probe = usbback_device_probe, + .remove = usbback_device_remove, +}; + +int usbback_device_class_init( void ) +{ + trace(); + + xenbus_register_backend( &usbback_device_driver ); + + return 0; +} + +void usbback_device_class_exit( void ) +{ + trace(); + + xenbus_unregister_driver( &usbback_device_driver ); +} diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,37 @@ +/*****************************************************************************/ +/* A device object representing the low-level connection to a single */ +/* front-end. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBBACK_DEVICE_H +#define USBBACK_DEVICE_H + +extern int usbback_device_class_init( void ); + +extern void usbback_device_class_exit( void ); + +struct usbback_device; + +extern void usbback_device_set_drvdata + ( struct usbback_device * device, void * data ); + +extern void * usbback_device_get_drvdata( struct usbback_device * device ); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,249 @@ +/*****************************************************************************/ +/* Device driver which drives usbback_device devices. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include "usbback_assert.h" +#include "usbback_device.h" +#include "usbback_driver.h" +#include "usbback_driver_backend.h" +#include "usbback_driver_port.h" +#include "usbback_trace.h" + +static int usbback_driver_probe_usb + ( struct usb_interface * intf, const struct usb_device_id * id ) +{ + trace(); + + return usbback_driver_port_probe_usb( intf ); +} + +static void usbback_driver_disconnect_usb( struct usb_interface * intf ) +{ + trace(); + + usbback_driver_port_disconnect_usb( intf ); +} + +static int usbback_driver_probe_or_remove_usbback_device + ( struct usbback_device * device, int remove ) +{ + trace(); + + { + struct usbback_driver_backend * backend; + + int return_value = 0; + + if( remove ) + { + goto REMOVE; + } + + backend = usbback_driver_backend_allocate( device ); + + if( backend == NULL ) + { + return_value = -ENOMEM; + + goto EXIT_NO_BACKEND; + } + + usbback_device_set_drvdata( device, backend ); + + return 0; + + REMOVE: + + backend = usbback_device_get_drvdata( device ); + + usbback_driver_backend_shutdown( backend ); + + usbback_device_set_drvdata( device, NULL ); + + EXIT_NO_BACKEND: + + return return_value; + } +} + +int usbback_driver_probe_usbback_device( struct usbback_device * device ) +{ + trace(); + + return usbback_driver_probe_or_remove_usbback_device( device, 0 ); +} + +void usbback_driver_connect( struct usbback_device * device ) +{ + trace(); + + { + struct usbback_driver_backend * backend = + usbback_device_get_drvdata( device ); + + usbback_driver_backend_connect( backend ); + } +} + +void usbback_driver_message_handler + ( struct usbback_device * device, xenidc_local_buffer_reference message ) +{ + trace(); + + { + struct usbback_driver_backend * backend = + usbback_device_get_drvdata( device ); + + usbback_driver_backend_message_handler( backend, message ); + } +} + +void usbback_driver_transaction_handler + ( struct usbback_device * device, xenidc_transaction * transaction ) +{ + trace(); + + { + struct usbback_driver_backend * backend = + usbback_device_get_drvdata( device ); + + usbback_driver_backend_transaction_handler( backend, transaction ); + } +} + +void usbback_driver_disconnect( struct usbback_device * device ) +{ + trace(); + + { + struct usbback_driver_backend * backend = + usbback_device_get_drvdata( device ); + + usbback_driver_backend_disconnect( backend ); + } +} + +void usbback_driver_claim_port + ( struct usbback_device * device, u32 port, char * path ) +{ + trace(); + + { + struct usbback_driver_backend * backend = + usbback_device_get_drvdata( device ); + + usbback_driver_backend_claim_port( backend, port, path ); + } +} + +void usbback_driver_release_port + ( struct usbback_device * device, u32 port ) +{ + trace(); + + { + struct usbback_driver_backend * backend = + usbback_device_get_drvdata( device ); + + usbback_driver_backend_release_port( backend, port ); + } +} + +void usbback_driver_remove_usbback_device( struct usbback_device * device ) +{ + trace(); + + (void)usbback_driver_probe_or_remove_usbback_device( device, 1 ); +} + +static struct usb_device_id usbback_driver_usb_id_table[] = +{ + { .driver_info = 1 }, /* Matches all devices. */ + {} +}; + +MODULE_DEVICE_TABLE( usb, usbback_driver_usb_id_table ); + +struct usb_driver usbback_driver_usb_driver = +{ + .owner = THIS_MODULE, + .name = "usbback", + .probe = usbback_driver_probe_usb, + .disconnect = usbback_driver_disconnect_usb, + .id_table = usbback_driver_usb_id_table, +}; + +static int usbback_driver_init_or_exit( int exit ) +{ + trace(); + + { + int return_value = 0; + + if( exit ) + { + goto EXIT; + } + + return_value = usbback_driver_port_class_init(); + + if( return_value != 0 ) + { + goto EXIT_NO_PORT_CLASS; + } + + return_value = usb_register( &usbback_driver_usb_driver ); + + if( return_value != 0 ) + { + goto EXIT_NO_USB_REGISTER; + } + + return 0; + + EXIT: + + usb_deregister( &usbback_driver_usb_driver ); + + EXIT_NO_USB_REGISTER: + + usbback_driver_port_class_exit(); + + EXIT_NO_PORT_CLASS: + + return return_value; + } +} + +int usbback_driver_init( void ) +{ + trace(); + + return usbback_driver_init_or_exit( 0 ); +} + +void usbback_driver_exit( void ) +{ + trace(); + + (void)usbback_driver_init_or_exit( 1 ); +} diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,54 @@ +/*****************************************************************************/ +/* Device driver which drives usbback_device devices. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBBACK_DRIVER_H +#define USBBACK_DRIVER_H + +#include "asm-xen/xenidc.h" +#include "usbback_device.h" + +extern int usbback_driver_init( void ); + +extern int usbback_driver_probe_usbback_device + ( struct usbback_device * device ); + +extern void usbback_driver_connect( struct usbback_device * device ); + +extern void usbback_driver_message_handler + ( struct usbback_device * device, xenidc_local_buffer_reference message ); + +extern void usbback_driver_transaction_handler + ( struct usbback_device * device, xenidc_transaction * transaction ); + +extern void usbback_driver_disconnect( struct usbback_device * device ); + +extern void usbback_driver_claim_port + ( struct usbback_device * device, u32 port, char * path ); + +extern void usbback_driver_release_port + ( struct usbback_device * device, u32 port ); + +extern void usbback_driver_remove_usbback_device + ( struct usbback_device * device ); + +extern void usbback_driver_exit( void ); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,587 @@ +/*****************************************************************************/ +/* usbback_driver_backend is the representation in the driver of the */ +/* back-end side of a single front-end to back-end connection. */ +/* One of these objects is used by the usbback_driver to manage each */ +/* usbback_device. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Based on arch/xen/drivers/usbif/backend/main.c, original copyright notice */ +/* follows... */ +/*****************************************************************************/ + +/****************************************************************************** + * arch/xen/drivers/usbif/backend/main.c + * + * Backend for the Xen virtual USB driver - provides an abstraction of a + * USB host controller to the corresponding frontend driver. + * + * by Mark Williamson + * Copyright (c) 2004 Intel Research Cambridge + * Copyright (c) 2004, 2005 Mark Williamson + * + * Based on arch/xen/drivers/blkif/backend/main.c + * Copyright (c) 2003-2004, Keir Fraser & Steve Hand + */ + +#include +#include "usbback_assert.h" +#include "usbback_device.h" +#include "usbback_driver_backend.h" +#include "usbback_driver_port.h" +#include "usbback_trace.h" + +#define USBBACK_DRIVER_PORT_COUNT 7 + +struct usbback_driver_backend +{ + struct usbback_device * device; + struct usbback_driver_port port[ USBBACK_DRIVER_PORT_COUNT ]; +}; + +static int usbback_driver_backend_init_or_exit +( + struct usbback_driver_backend * backend, + struct usbback_device * device, + int exit +) +{ + trace(); + + { + int return_value = 0; + + if( exit ) + { + goto EXIT; + } + + memset( backend, 0, sizeof( *backend ) ); + + backend->device = device; + + { + int i; + + for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ ) + { + return_value = + usbback_driver_port_init( &backend->port[ i ], backend ); + + if( return_value != 0 ) + { + goto EXIT_NO_PORT; + } + } + + return 0; + + EXIT: + + i = USBBACK_DRIVER_PORT_COUNT; + + EXIT_NO_PORT: + + i--; + + for( ; i >= 0; i-- ) + { + usbback_driver_port_shutdown( &backend->port[ i ] ); + } + } + + return return_value; + } +} + +struct usbback_driver_backend * usbback_driver_backend_allocate + ( struct usbback_device * device ) +{ + struct usbback_driver_backend * backend = + (struct usbback_driver_backend *)kmalloc + ( sizeof( struct usbback_driver_backend ), GFP_KERNEL ); + + if + ( + ( backend != NULL ) + && + ( usbback_driver_backend_init_or_exit( backend, device, 0 ) != 0 ) + ) + { + kfree( backend ); + + backend = NULL; + } + + return backend; +} + +void usbback_driver_backend_connect( struct usbback_driver_backend * backend ) +{ + trace(); + + { + int i; + + for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ ) + { + usbback_driver_port_connect( &backend->port[ i ] ); + } + } +} + +static void usbback_driver_backend_handle_probe +( + struct usbback_driver_backend * backend, + xenidc_transaction * transaction +); + +static void usbback_driver_backend_handle_reset +( + struct usbback_driver_backend * backend, + xenidc_transaction * transaction +); + +static void usbback_driver_backend_handle_io +( + struct usbback_driver_backend * backend, + xenidc_transaction * transaction +); + +void usbback_driver_backend_transaction_handler + ( struct usbback_driver_backend * backend, xenidc_transaction * transaction ) +{ + /* trace(); */ + + usbif_transaction_parameters_header header; + + if + ( + xenidc_local_buffer_reference_copy_out + ( + &transaction->parameters, + &header, + sizeof( header ) + ) + == + sizeof( header ) + ) + { + switch( header.transaction_type ) + { + case USBIF_TRANSACTION_TYPE_PROBE: + usbback_driver_backend_handle_probe( backend, transaction ); + break; + case USBIF_TRANSACTION_TYPE_RESET: + usbback_driver_backend_handle_reset( backend, transaction ); + break; + case USBIF_TRANSACTION_TYPE_IO: + usbback_driver_backend_handle_io( backend, transaction ); + break; + default: + xenidc_transaction_complete + ( transaction, XENIDC_ERROR_INVALID_PARAMETER ); + break; + } + } + else + { + /* Parameters were underlength. */ + + xenidc_transaction_complete + ( transaction, XENIDC_ERROR_INVALID_FORMAT ); + } +} + +static void usbback_driver_backend_handle_probe + ( struct usbback_driver_backend * backend, xenidc_transaction * transaction ) +{ + /* trace(); */ + + usbif_probe_transaction_parameters parameters; + + xenidc_error error; + + if + ( + xenidc_local_buffer_reference_copy_out + ( + &transaction->parameters, + ¶meters, + sizeof( parameters ) + ) + != + sizeof( parameters ) + ) + { + error = XENIDC_ERROR_INVALID_FORMAT; + + goto COMPLETE; + } + + if + ( + ( parameters.port <= 0 ) + || + ( parameters.port > USBBACK_DRIVER_PORT_COUNT ) + ) + { + error = XENIDC_ERROR_INVALID_PARAMETER; + + goto COMPLETE; + } + + { + usbif_probe_transaction_status status; + + memset( &status, 0, sizeof( status ) ); + + status.result = usbback_driver_port_usbdev_is_connected + ( &backend->port[ parameters.port - 1 ] ) ? + USBIF_PROBE_RESULT_DEVICE_PRESENT : + USBIF_PROBE_RESULT_NO_DEVICE; + + if + ( + xenidc_local_buffer_reference_copy_in + ( + &transaction->status, + &status, + sizeof( status ) + ) + != + sizeof( status ) + ) + { + error = XENIDC_ERROR_INVALID_FORMAT; + + goto COMPLETE; + } + } + + error = XENIDC_ERROR_SUCCESS; + + COMPLETE: + + xenidc_transaction_complete( transaction, error ); +} + +static void usbback_driver_backend_handle_reset + ( struct usbback_driver_backend * backend, xenidc_transaction * transaction ) +{ + trace(); + + { + usbif_reset_transaction_parameters parameters; + + xenidc_error error; + + if + ( + xenidc_local_buffer_reference_copy_out + ( + &transaction->parameters, + ¶meters, + sizeof( parameters ) + ) + != + sizeof( parameters ) + ) + { + error = XENIDC_ERROR_INVALID_FORMAT; + + goto COMPLETE; + } + + if + ( + ( parameters.port <= 0 ) + || + ( parameters.port > USBBACK_DRIVER_PORT_COUNT ) + ) + { + error = XENIDC_ERROR_INVALID_PARAMETER; + + goto COMPLETE; + } + + { + int result = usbback_driver_port_reset + ( &backend->port[ parameters.port - 1 ] ); + + if( result < 0 ) + { + error = USBIF_XENIDC_ERROR_NO_DEVICE; + + goto COMPLETE; + } + + { + usbif_reset_transaction_status status; + + memset( &status, 0, sizeof( status ) ); + + status.result = result; + + if + ( + xenidc_local_buffer_reference_copy_in + ( + &transaction->status, + &status, + sizeof( status ) + ) + != + sizeof( status ) + ) + { + error = XENIDC_ERROR_INVALID_FORMAT; + + goto COMPLETE; + } + } + } + + error = XENIDC_ERROR_SUCCESS; + + COMPLETE: + + xenidc_transaction_complete( transaction, error ); + } +} + +static struct usbback_driver_port * + usbback_driver_backend_find_port_by_guest_address +( + struct usbback_driver_backend * backend, + unsigned long guest_address +) +{ + trace(); + + { + int i; + + for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ ) + { + struct usbback_driver_port * port = &backend->port[ i ]; + + if + ( + usbback_driver_port_match_guest_address( port, guest_address ) + ) + { + return port; + } + } + } + + return NULL; +} + +static void usbback_driver_backend_handle_io + ( struct usbback_driver_backend * backend, xenidc_transaction * transaction ) +{ + trace(); + + { + usbif_io_transaction_parameters_header header; + + xenidc_error error; + + if + ( + xenidc_local_buffer_reference_copy_out + ( + &transaction->parameters, + &header, + sizeof( header ) + ) + != + sizeof( header ) + ) + { + error = XENIDC_ERROR_INVALID_FORMAT; + + goto COMPLETE; + } + + { + struct usbback_driver_port * port = + usbback_driver_backend_find_port_by_guest_address + ( backend, header.device_number ); + + if( port == NULL ) + { + error = USBIF_XENIDC_ERROR_NO_DEVICE; + + goto COMPLETE; + } + + usbback_driver_port_handle_io( port, transaction ); + } + + return; + + COMPLETE: + + xenidc_transaction_complete( transaction, error ); + } +} + +static void usbback_driver_backend_handle_unlink +( + struct usbback_driver_backend * backend, + xenidc_local_buffer_reference message +); + +void usbback_driver_backend_message_handler +( + struct usbback_driver_backend * backend, + xenidc_local_buffer_reference message +) +{ + trace(); + + { + usbif_message_header header; + + if + ( + xenidc_local_buffer_reference_copy_out + ( + &message, + &header, + sizeof( header ) + ) + == + sizeof( header ) + ) + { + switch( header.message_type ) + { + case USBIF_MESSAGE_TYPE_UNLINK: + usbback_driver_backend_handle_unlink( backend, message ); + break; + } + } + } +} + +static void usbback_driver_backend_handle_unlink +( + struct usbback_driver_backend * backend, + xenidc_local_buffer_reference message +) +{ + trace(); + + { + usbif_unlink_message_body unlink; + + if + ( + xenidc_local_buffer_reference_copy_out + ( + &message, + &unlink, + sizeof( unlink ) + ) + == + sizeof( unlink ) + ) + { + int i; + + for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ ) + { + struct usbback_driver_port * port = &backend->port[ i ]; + + if + ( + usbback_driver_port_try_unlink + ( port, unlink.unlink_id ) + ) + { + break; + } + } + } + } +} + +void usbback_driver_backend_disconnect + ( struct usbback_driver_backend * backend ) +{ + trace(); + + { + int i; + + for( i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++ ) + { + usbback_driver_port_disconnect( &backend->port[ i ] ); + } + } +} + +void usbback_driver_backend_claim_port + ( struct usbback_driver_backend * backend, u32 port, char * path ) +{ + trace2( "port: %d, path: %s", port, path ); + + ASSERT + ( + ( port > 0 ) + && + ( port <= USBBACK_DRIVER_PORT_COUNT ) + ); + + usbback_driver_port_claim( &backend->port[ port - 1 ], path ); + + bus_rescan_devices( &usb_bus_type ); +} + +void usbback_driver_backend_release_port + ( struct usbback_driver_backend * backend, u32 port ) +{ + trace1( "port: %d", port ); + + ASSERT + ( + ( port > 0 ) + && + ( port <= USBBACK_DRIVER_PORT_COUNT ) + ); + + usbback_driver_port_release( &backend->port[ port - 1 ] ); + + bus_rescan_devices( &usb_bus_type ); +} + +void usbback_driver_backend_shutdown + ( struct usbback_driver_backend * backend ) +{ + trace(); + + (void)usbback_driver_backend_init_or_exit( backend, NULL, 1 ); + + kfree( backend ); +} diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,63 @@ +/*****************************************************************************/ +/* usbback_driver_backend is the representation in the driver of the */ +/* back-end side of a single front-end to back-end connection. */ +/* One of these objects is used by the usbback_driver to manage each */ +/* usbback_device. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBBACK_DRIVER_BACKEND_H +#define USBBACK_DRIVER_BACKEND_H + +#include "asm-xen/xenidc.h" +#include "usbback_device.h" + +struct usbback_driver_backend; + +extern struct usbback_driver_backend * usbback_driver_backend_allocate + ( struct usbback_device * device ); + +extern void usbback_driver_backend_connect + ( struct usbback_driver_backend * backend ); + +extern void usbback_driver_backend_transaction_handler +( + struct usbback_driver_backend * backend, + xenidc_transaction * transaction +); + +extern void usbback_driver_backend_message_handler +( + struct usbback_driver_backend * backend, + xenidc_local_buffer_reference message +); + +extern void usbback_driver_backend_disconnect + ( struct usbback_driver_backend * backend ); + +extern void usbback_driver_backend_claim_port + ( struct usbback_driver_backend * backend, u32 port, char * path ); + +extern void usbback_driver_backend_release_port + ( struct usbback_driver_backend * backend, u32 port ); + +extern void usbback_driver_backend_shutdown + ( struct usbback_driver_backend * backend ); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,1149 @@ +/*****************************************************************************/ +/* Object which manages a single USB device and handles all the IO */ +/* transactions for that device by assigning usbback_driver_port_resources */ +/* to process them. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Based on arch/xen/drivers/usbif/backend/main.c, original copyright notice */ +/* follows... */ +/*****************************************************************************/ + +/****************************************************************************** + * arch/xen/drivers/usbif/backend/main.c + * + * Backend for the Xen virtual USB driver - provides an abstraction of a + * USB host controller to the corresponding frontend driver. + * + * by Mark Williamson + * Copyright (c) 2004 Intel Research Cambridge + * Copyright (c) 2004, 2005 Mark Williamson + * + * Based on arch/xen/drivers/blkif/backend/main.c + * Copyright (c) 2003-2004, Keir Fraser & Steve Hand + */ + +#include +#include +#include "usbback_assert.h" +#include "usbback_driver_port.h" +#include "usbback_trace.h" + +int usbback_driver_port_class_init( void ) +{ + trace(); + + return usbback_driver_port_resource_class_init(); +} + +void usbback_driver_port_class_exit( void ) +{ + trace(); + + usbback_driver_port_resource_class_exit(); +} + +extern struct usb_driver usbback_driver_usb_driver; + +static DECLARE_RWSEM( usbback_driver_port_list_sem ); + +static LIST_HEAD( usbback_driver_port_list ); + +typedef enum +{ + usbback_driver_port_stimulus_pc, /* Port claim */ + usbback_driver_port_stimulus_pr, /* Port release */ + usbback_driver_port_stimulus_up, /* USB probe */ + usbback_driver_port_stimulus_ud, /* USB disconnect */ + usbback_driver_port_stimulus_cn, /* endpoint connect */ + usbback_driver_port_stimulus_dn, /* endpoint disconnect */ + usbback_driver_port_stimulus_rq, /* Transaction queued/resource freed */ + usbback_driver_port_stimulus_sd, /* Shutdown */ + usbback_driver_port_stimulus_ri, /* test_io transactions idle (reent) */ + usbback_driver_port_stimulus_rr, /* test_io transactions running (reent) */ + usbback_driver_port_stimulus_rp, /* release performed */ +} +usbback_driver_port_stimulus; + +static void usbback_driver_port_handle_stimulus +( + struct usbback_driver_port * port, + usbback_driver_port_stimulus stimulus +); + +static void usbback_driver_port_purge_io_1( void * data ); + +static void usbback_driver_port_perform_release_1( void * data ); + +int usbback_driver_port_init +( + struct usbback_driver_port * port, + struct usbback_driver_backend * backend +) +{ + trace(); + + memset( port, 0, sizeof( *port ) ); + + port->backend = backend; + + INIT_LIST_HEAD( &port->link ); + + spin_lock_init( &port->lock ); + + port->state = usbback_driver_port_state_i; + + INIT_LIST_HEAD( &port->transaction_list ); + INIT_LIST_HEAD( &port->purge_list ); + INIT_LIST_HEAD( &port->free_resource_list ); + + { + int i; + + for( i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++ ) + { + struct usbback_driver_port_resource * resource = + &port->resources[ i ]; + + usbback_driver_port_resource_init( resource, port ); + + list_add( &resource->link, &port->free_resource_list ); + } + } + + xenidc_work_init + ( &port->purge_io_1_work, usbback_driver_port_purge_io_1, port ); + + xenidc_work_init + ( + &port->perform_release_1_work, + usbback_driver_port_perform_release_1, + port + ); + + return 0; +} + +void usbback_driver_port_claim + ( struct usbback_driver_port * port, char * path ) +{ + trace(); + + down_write( &usbback_driver_port_list_sem ); + + strncpy( port->path, path, sizeof( port->path ) ); + + list_add_tail( &port->link, &usbback_driver_port_list ); + + spin_lock_irq( &port->lock ); + + usbback_driver_port_handle_stimulus + ( port, usbback_driver_port_stimulus_pc ); + + spin_unlock_irq( &port->lock ); + + up_write( &usbback_driver_port_list_sem ); +} + +void usbback_driver_port_release( struct usbback_driver_port * port ) +{ + trace(); + + down_write( &usbback_driver_port_list_sem ); + + list_del_init( &port->link ); + + up_write( &usbback_driver_port_list_sem ); + + port->release = 0; + + spin_lock_irq( &port->lock ); + + usbback_driver_port_handle_stimulus + ( port, usbback_driver_port_stimulus_pr ); + + spin_unlock_irq( &port->lock ); + + xenidc_work_until( port->release ); +} + +int usbback_driver_port_probe_usb( struct usb_interface * intf ) +{ + trace(); + + { + int return_value = 0; + + struct usb_device * usbdev = interface_to_usbdev( intf ); + + struct usbback_driver_port * port = NULL; + + printk + ( KERN_INFO "usbback: Probe for usb device %s\n", usbdev->devpath ); + + down_read( &usbback_driver_port_list_sem ); + + { + struct usbback_driver_port * cur = NULL; + + list_for_each_entry( cur, &usbback_driver_port_list, link ) + { + printk + ( + KERN_INFO + "usbback: Testing against configured path %s:", + cur->path + ); + + if + ( + strncmp( cur->path, usbdev->devpath, sizeof( cur->path ) ) + == + 0 + ) + { + printk( " matches.\n" ); + + port = cur; + + break; + } + else + { + printk( " doesn't match.\n" ); + } + } + } + + if( port == NULL ) + { + printk( KERN_INFO "usbback: No match found.\n" ); + + return_value = -ENODEV; + + goto EXIT_NO_PORT; + } + + { + int i; + + for( i = 0; i < usbdev->actconfig->desc.bNumInterfaces; i++ ) + { + struct usb_interface * other_intf = + usb_ifnum_to_if( usbdev, i ); + + if( other_intf != intf ) + { + if( usb_interface_claimed( other_intf ) ) + { + printk + ( + KERN_INFO + "usbback: An interface of the matching device is " + "already in use by another driver.\n" + ); + + return_value = -EBUSY; + + goto EXIT_INTERFACE_ALREADY_CLAIMED; + } + } + } + } + + { + int i; + + for( i = 0; i < usbdev->actconfig->desc.bNumInterfaces; i++ ) + { + struct usb_interface * other_intf = + usb_ifnum_to_if( usbdev, i ); + + if( other_intf != intf ) + { + int error = usb_driver_claim_interface + ( &usbback_driver_usb_driver, other_intf, port ); + + /* We already checked all the interfaces were available. */ + + ASSERT( error == 0 ); + } + } + } + + usbdev = usb_get_dev( usbdev ); + + usb_set_intfdata( intf, port ); + + spin_lock_irq( &port->lock ); + + port->usbdev_is_connected = 1; + + port->usbdev = usbdev; + + usbback_driver_port_handle_stimulus + ( port, usbback_driver_port_stimulus_up ); + + spin_unlock_irq( &port->lock ); + + EXIT_INTERFACE_ALREADY_CLAIMED: + + EXIT_NO_PORT: + + up_read( &usbback_driver_port_list_sem ); + + return return_value; + } +} + +void usbback_driver_port_disconnect_usb( struct usb_interface * intf ) +{ + trace(); + + { + struct usbback_driver_port * port = usb_get_intfdata( intf ); + + /* Protect against reentrant call when we release other interfaces. */ + + if( port != NULL ) + { + ASSERT( port->usbdev_is_connected ); + + spin_lock_irq( &port->lock ); + + port->usbdev_is_connected = 0; + + port->enabled = 0; + + port->usb_disconnect = 0; + + usbback_driver_port_handle_stimulus + ( port, usbback_driver_port_stimulus_ud ); + + spin_unlock_irq( &port->lock ); + + xenidc_work_until( port->usb_disconnect ); + + { + struct usb_device * usbdev = port->usbdev; + + { + int i; + + for + ( + i = 0; + i < usbdev->actconfig->desc.bNumInterfaces; + i++ + ) + { + struct usb_interface * other_intf = + usb_ifnum_to_if( usbdev, i ); + + if( other_intf != intf ) + { + /* Protect against reentrant call when we */ + /* release other interfaces. */ + + usb_set_intfdata( other_intf, NULL ); + + usb_driver_release_interface + ( &usbback_driver_usb_driver, other_intf ); + } + } + } + + usb_set_intfdata( intf, NULL ); + + usb_put_dev( usbdev ); + } + } + } +} + +int usbback_driver_port_reset( struct usbback_driver_port * port ) +{ + trace(); + + { + int status = -1; + + spin_lock_irq( &port->lock ); + + port->guest_address = 0; + + if( usbback_driver_port_usbdev_is_connected( port ) ) + { + if( port->usbdev->speed == USB_SPEED_LOW ) + { + status = USBIF_RESET_RESULT_LOW_SPEED; + } + else if( port->usbdev->speed == USB_SPEED_HIGH ) + { + status = USBIF_RESET_RESULT_HIGH_SPEED; + } + else + { + status = USBIF_RESET_RESULT_FULL_SPEED; + } + + port->enabled = 1; + } + else + { + port->enabled = 0; + } + + spin_unlock_irq( &port->lock ); + + return status; + } +} + +void usbback_driver_port_set_guest_address + ( struct usbback_driver_port * port, unsigned long guest_address ) +{ + trace(); + + port->guest_address = guest_address; +} + +int usbback_driver_port_match_guest_address + ( struct usbback_driver_port * port, unsigned long guest_address ) +{ + trace(); + + return ( port->enabled && ( guest_address == port->guest_address ) ); +} + +void usbback_driver_port_connect( struct usbback_driver_port * port ) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &port->lock, flags ); + + usbback_driver_port_handle_stimulus + ( port, usbback_driver_port_stimulus_cn ); + + spin_unlock_irqrestore( &port->lock, flags ); + } +} + +void usbback_driver_port_handle_io + ( struct usbback_driver_port * port, xenidc_transaction * transaction ) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &port->lock, flags ); + + list_add_tail + ( + xenidc_transaction_to_link( transaction ), + &port->transaction_list + ); + + usbback_driver_port_handle_stimulus + ( port, usbback_driver_port_stimulus_rq ); + + spin_unlock_irqrestore( &port->lock, flags ); + } +} + +void usbback_driver_port_disconnect( struct usbback_driver_port * port ) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &port->lock, flags ); + + usbback_driver_port_handle_stimulus + ( port, usbback_driver_port_stimulus_dn ); + + spin_unlock_irqrestore( &port->lock, flags ); + } +} + +int usbback_driver_port_try_unlink + ( struct usbback_driver_port * port, int unlink_id ) +{ + trace(); + + { + int return_value = 0; + + xenidc_transaction * transaction = NULL; + + unsigned long flags; + + spin_lock_irqsave( &port->lock, flags ); + + { + xenidc_transaction * temp; + + list_for_each_entry + ( temp, &port->transaction_list, XENIDC_TRANSACTION_LINK ) + { + usbif_io_transaction_parameters_header header; + + if + ( + xenidc_local_buffer_reference_copy_out + ( + &transaction->parameters, + &header, + sizeof( header ) + ) + == + sizeof( header ) + ) + { + if( header.unlink_id == unlink_id ) + { + transaction = temp; + + list_del_init + ( xenidc_transaction_to_link( transaction ) ); + + break; + } + } + } + } + + if( transaction == NULL ) + { + int i; + + for( i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++ ) + { + struct usbback_driver_port_resource * resource = + &port->resources[ i ]; + + if + ( + usbback_driver_port_resource_try_unlink + ( resource, unlink_id ) + ) + { + return_value = 1; + + break; + } + } + } + + spin_unlock_irqrestore( &port->lock, flags ); + + if( transaction ) + { + xenidc_transaction_complete + ( transaction, USBIF_XENIDC_ERROR_UNLINKED ); + + return_value = 1; + } + + return return_value; + } +} + +void usbback_driver_port_shutdown( struct usbback_driver_port * port ) +{ + trace(); + + down_write( &usbback_driver_port_list_sem ); + + list_del_init( &port->link ); + + up_write( &usbback_driver_port_list_sem ); + + port->shutdown = 0; + + spin_lock_irq( &port->lock ); + + usbback_driver_port_handle_stimulus + ( port, usbback_driver_port_stimulus_sd ); + + spin_unlock_irq( &port->lock ); + + xenidc_work_until( port->shutdown ); + + flush_scheduled_work(); +} + +static void usbback_driver_port_invalid_stimulus + ( struct usbback_driver_port * port, usbback_driver_port_stimulus stimulus ); + +static void usbback_driver_port_purge_io( struct usbback_driver_port * port ); + +static void usbback_driver_port_test_io( struct usbback_driver_port * port ); + +static void usbback_driver_port_kick_io( struct usbback_driver_port * port ); + +static void usbback_driver_port_perform_release + ( struct usbback_driver_port * port ); + +static void usbback_driver_port_complete_release + ( struct usbback_driver_port * port ); + +static void usbback_driver_port_complete_usb_disconnect + ( struct usbback_driver_port * port ); + +static void usbback_driver_port_complete_shutdown + ( struct usbback_driver_port * port ); + +/* FIXME: update to add cn and dn */ + +static void usbback_driver_port_handle_stimulus +( + struct usbback_driver_port * port, + usbback_driver_port_stimulus stimulus +) +{ + trace3 + ( + "port %p in state %d received stimulus %d", + port, + port->state, + stimulus + ); + + switch( port->state ) + { + case usbback_driver_port_state_i: + /* Released */ + /* Disconnected */ + /* Idle */ + switch( stimulus ) + { + case usbback_driver_port_stimulus_pc: + port->state = usbback_driver_port_state_i_pc; + break; + case usbback_driver_port_stimulus_rq: + usbback_driver_port_purge_io( port ); + break; + case usbback_driver_port_stimulus_sd: + usbback_driver_port_complete_shutdown( port ); + break; + default: + usbback_driver_port_invalid_stimulus( port, stimulus ); + break; + } + break; + case usbback_driver_port_state_i_pc: + /* Claimed */ + /* Disconnected */ + /* Idle */ + switch( stimulus ) + { + case usbback_driver_port_stimulus_pr: + port->state = usbback_driver_port_state_i; + usbback_driver_port_complete_release( port ); + break; + case usbback_driver_port_stimulus_up: + port->state = usbback_driver_port_state_i_pc_up; + break; + case usbback_driver_port_stimulus_rq: + usbback_driver_port_purge_io( port ); + break; + case usbback_driver_port_stimulus_sd: + port->state = usbback_driver_port_state_i; + usbback_driver_port_complete_shutdown( port ); + break; + default: + usbback_driver_port_invalid_stimulus( port, stimulus ); + break; + } + break; + case usbback_driver_port_state_i_pc_up: + /* Claimed */ + /* Probed */ + /* Maybe Running */ + switch( stimulus ) + { + case usbback_driver_port_stimulus_pr: + port->state = usbback_driver_port_state_i_pc_up_pr; + usbback_driver_port_purge_io( port ); + usbback_driver_port_test_io( port ); + break; + case usbback_driver_port_stimulus_ud: + port->state = usbback_driver_port_state_i_pc_up_ud; + usbback_driver_port_purge_io( port ); + usbback_driver_port_test_io( port ); + break; + case usbback_driver_port_stimulus_rq: + usbback_driver_port_kick_io( port ); + break; + case usbback_driver_port_stimulus_sd: + port->state = usbback_driver_port_state_i_pc_up_sd; + usbback_driver_port_purge_io( port ); + usbback_driver_port_test_io( port ); + break; + default: + usbback_driver_port_invalid_stimulus( port, stimulus ); + break; + } + break; + case usbback_driver_port_state_i_pc_up_pr: + /* Releasing */ + /* Probed */ + /* Testing/Running */ + switch( stimulus ) + { + case usbback_driver_port_stimulus_ud: + port->state = usbback_driver_port_state_i_pc_up_pr_ud; + break; + case usbback_driver_port_stimulus_rq: + usbback_driver_port_purge_io( port ); + usbback_driver_port_test_io( port ); + break; + case usbback_driver_port_stimulus_ri: + port->state = usbback_driver_port_state_i_pc_up_pr_ri; + usbback_driver_port_perform_release( port ); + break; + case usbback_driver_port_stimulus_rr: + break; + default: + usbback_driver_port_invalid_stimulus( port, stimulus ); + break; + } + break; + case usbback_driver_port_state_i_pc_up_ud: + /* Claimed */ + /* USB Disconnecting */ + /* Testing/Running */ + switch( stimulus ) + { + case usbback_driver_port_stimulus_pr: + port->state = usbback_driver_port_state_i_pc_up_pr_ud; + break; + case usbback_driver_port_stimulus_rq: + usbback_driver_port_purge_io( port ); + usbback_driver_port_test_io( port ); + break; + case usbback_driver_port_stimulus_sd: + port->state = usbback_driver_port_state_i_pc_up_ud_sd; + break; + case usbback_driver_port_stimulus_ri: + port->state = usbback_driver_port_state_i_pc; + usbback_driver_port_complete_usb_disconnect( port ); + break; + case usbback_driver_port_stimulus_rr: + break; + default: + usbback_driver_port_invalid_stimulus( port, stimulus ); + break; + } + break; + case usbback_driver_port_state_i_pc_up_sd: + /* Released */ + /* Probed */ + /* Shutting down */ + /* Testing/Running */ + switch( stimulus ) + { + case usbback_driver_port_stimulus_ud: + port->state = usbback_driver_port_state_i_pc_up_ud_sd; + break; + case usbback_driver_port_stimulus_rq: + usbback_driver_port_purge_io( port ); + usbback_driver_port_test_io( port ); + break; + case usbback_driver_port_stimulus_ri: + port->state = usbback_driver_port_state_i_pc_up_sd_ri; + usbback_driver_port_perform_release( port ); + break; + case usbback_driver_port_stimulus_rr: + break; + default: + usbback_driver_port_invalid_stimulus( port, stimulus ); + break; + } + break; + case usbback_driver_port_state_i_pc_up_pr_ud: + /* Releasing */ + /* USB Disconnecting */ + /* Testing/Running */ + switch( stimulus ) + { + case usbback_driver_port_stimulus_rq: + usbback_driver_port_purge_io( port ); + usbback_driver_port_test_io( port ); + break; + case usbback_driver_port_stimulus_ri: + port->state = usbback_driver_port_state_i_pc_up_pr_ud_ri; + usbback_driver_port_perform_release( port ); + usbback_driver_port_complete_usb_disconnect( port ); + break; + case usbback_driver_port_stimulus_rr: + break; + default: + usbback_driver_port_invalid_stimulus( port, stimulus ); + break; + } + break; + case usbback_driver_port_state_i_pc_up_pr_ri: + /* Releasing */ + /* Probed */ + /* Idle */ + /* Performing Release */ + switch( stimulus ) + { + case usbback_driver_port_stimulus_ud: + port->state = usbback_driver_port_state_i_pc_up_pr_ud_ri; + usbback_driver_port_complete_usb_disconnect( port ); + break; + case usbback_driver_port_stimulus_rq: + usbback_driver_port_purge_io( port ); + break; + default: + usbback_driver_port_invalid_stimulus( port, stimulus ); + break; + } + break; + case usbback_driver_port_state_i_pc_up_ud_sd: + /* Released */ + /* USB Disconnecting */ + /* Shutting down */ + /* Testing/Running */ + switch( stimulus ) + { + case usbback_driver_port_stimulus_rq: + usbback_driver_port_purge_io( port ); + usbback_driver_port_test_io( port ); + break; + case usbback_driver_port_stimulus_ri: + port->state = usbback_driver_port_state_i_pc_up_ud_sd_ri; + usbback_driver_port_perform_release( port ); + usbback_driver_port_complete_usb_disconnect( port ); + break; + case usbback_driver_port_stimulus_rr: + break; + default: + usbback_driver_port_invalid_stimulus( port, stimulus ); + break; + } + break; + case usbback_driver_port_state_i_pc_up_sd_ri: + /* Released */ + /* Probed */ + /* Shutting down */ + /* Idle */ + /* Performing release */ + switch( stimulus ) + { + case usbback_driver_port_stimulus_ud: + port->state = usbback_driver_port_state_i_pc_up_ud_sd_ri; + usbback_driver_port_complete_usb_disconnect( port ); + break; + case usbback_driver_port_stimulus_rq: + usbback_driver_port_purge_io( port ); + break; + default: + usbback_driver_port_invalid_stimulus( port, stimulus ); + break; + } + break; + case usbback_driver_port_state_i_pc_up_pr_ud_ri: + /* Releasing */ + /* Disconnected */ + /* Idle */ + /* Performing release */ + switch( stimulus ) + { + case usbback_driver_port_stimulus_rq: + usbback_driver_port_purge_io( port ); + break; + case usbback_driver_port_stimulus_rp: + port->state = usbback_driver_port_state_i; + usbback_driver_port_complete_release( port ); + break; + default: + usbback_driver_port_invalid_stimulus( port, stimulus ); + break; + } + break; + case usbback_driver_port_state_i_pc_up_ud_sd_ri: + /* Released */ + /* Disconnected */ + /* Shutting down */ + /* Idle */ + /* Performing release */ + switch( stimulus ) + { + case usbback_driver_port_stimulus_rq: + usbback_driver_port_purge_io( port ); + break; + case usbback_driver_port_stimulus_rp: + port->state = usbback_driver_port_state_i; + usbback_driver_port_complete_shutdown( port ); + break; + default: + usbback_driver_port_invalid_stimulus( port, stimulus ); + break; + } + break; + default: + usbback_driver_port_invalid_stimulus( port, stimulus ); + break; + } +} + +static void usbback_driver_port_invalid_stimulus + ( struct usbback_driver_port * port, usbback_driver_port_stimulus stimulus ) +{ + trace(); + + printk + ( + KERN_ERR "usbback: port %p in state %d" + "received invalid stimulus %d", + port, + port->state, + stimulus + ); +} + +static void usbback_driver_port_purge_io( struct usbback_driver_port * port ) +{ + trace(); + + while( !list_empty( &port->transaction_list ) ) + { + xenidc_transaction * transaction = list_entry + ( + port->transaction_list.next, + xenidc_transaction, + XENIDC_TRANSACTION_LINK + ); + + list_del_init( xenidc_transaction_to_link( transaction ) ); + + list_add_tail + ( xenidc_transaction_to_link( transaction ), &port->purge_list ); + } + + { + int i; + + for( i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++ ) + { + struct usbback_driver_port_resource * resource = + &port->resources[ i ]; + + usbback_driver_port_resource_flush_transaction( resource ); + } + } + + (void)xenidc_work_schedule( &port->purge_io_1_work ); +} + +static void usbback_driver_port_purge_io_1( void * data ) +{ + trace(); + + { + struct usbback_driver_port * port = (struct usbback_driver_port *)data; + + spin_lock_irq( &port->lock ); + + while( !list_empty( &port->purge_list ) ) + { + xenidc_transaction * transaction = list_entry + ( + port->purge_list.next, + xenidc_transaction, + XENIDC_TRANSACTION_LINK + ); + + list_del_init( xenidc_transaction_to_link( transaction ) ); + + spin_unlock_irq( &port->lock ); + + xenidc_transaction_complete + ( transaction, USBIF_XENIDC_ERROR_UNLINKED ); + + spin_lock_irq( &port->lock ); + } + + spin_unlock_irq( &port->lock ); + } +} + +static void usbback_driver_port_test_io( struct usbback_driver_port * port ) +{ + trace(); + + if( port->current_transactions == 0 ) + { + usbback_driver_port_handle_stimulus + ( port, usbback_driver_port_stimulus_ri ); + } + else + { + usbback_driver_port_handle_stimulus + ( port, usbback_driver_port_stimulus_rr ); + } +} + +static void usbback_driver_port_kick_io( struct usbback_driver_port * port ) +{ + trace(); + + while + ( + ( !list_empty( &port->transaction_list ) ) + && + ( !list_empty( &port->free_resource_list ) ) + ) + { + xenidc_transaction * transaction = list_entry + ( + port->transaction_list.next, + xenidc_transaction, + XENIDC_TRANSACTION_LINK + ); + + struct usbback_driver_port_resource * resource = list_entry + ( + port->free_resource_list.next, + struct usbback_driver_port_resource, + link + ); + + list_del_init( xenidc_transaction_to_link( transaction ) ); + + list_del_init( &resource->link ); + + port->current_transactions++; + + usbback_driver_port_resource_start_io( resource, transaction ); + } +} + +void usbback_driver_port_resource_completed_io +( + struct usbback_driver_port * port, + struct usbback_driver_port_resource * resource +) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &port->lock, flags ); + + list_add( &resource->link, &port->free_resource_list ); + + port->current_transactions--; + + usbback_driver_port_handle_stimulus + ( port, usbback_driver_port_stimulus_rq ); + + spin_unlock_irqrestore( &port->lock, flags ); + } +} + +static void usbback_driver_port_perform_release + ( struct usbback_driver_port * port ) +{ + trace(); + + usb_get_dev( port->usbdev ); + + { + int scheduled = xenidc_work_schedule( &port->perform_release_1_work ); + + ASSERT( scheduled ); + } +} + +static void usbback_driver_port_perform_release_1( void * data ) +{ + trace(); + + { + struct usbback_driver_port * port = (struct usbback_driver_port *)data; + + usb_lock_device( port->usbdev ); + + down_write( &usb_bus_type.subsys.rwsem ); + + if( port->usbdev_is_connected ) + { + usb_driver_release_interface + ( + &usbback_driver_usb_driver, + usb_ifnum_to_if( port->usbdev, 0 ) + ); + } + + up_write( &usb_bus_type.subsys.rwsem ); + + usb_unlock_device( port->usbdev ); + + usb_put_dev( port->usbdev ); + + spin_lock_irq( &port->lock ); + + usbback_driver_port_handle_stimulus + ( port, usbback_driver_port_stimulus_rp ); + + spin_unlock_irq( &port->lock ); + } +} + +static void usbback_driver_port_complete_release + ( struct usbback_driver_port * port ) +{ + trace(); + + port->release = 1; + + xenidc_work_wake_up(); +} + +static void usbback_driver_port_complete_usb_disconnect + ( struct usbback_driver_port * port ) +{ + trace(); + + port->usb_disconnect = 1; + + xenidc_work_wake_up(); +} + +static void usbback_driver_port_complete_shutdown + ( struct usbback_driver_port * port ) +{ + trace(); + + port->shutdown = 1; + + xenidc_work_wake_up(); +} diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,146 @@ +/*****************************************************************************/ +/* Object which manages a single USB device and handles all the */ +/* io transactions for that device by assigning */ +/* usbback_driver_port_resources to process them. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBBACK_DRIVER_PORT_H +#define USBBACK_DRIVER_PORT_H + +#include +#include +#include "usbback_assert.h" +#include "usbback_driver_backend.h" +#include "usbback_driver_port_resource.h" +#include "usbback_trace.h" + +int usbback_driver_port_class_init( void ); + +void usbback_driver_port_class_exit( void ); + +int usbback_driver_port_init +( + struct usbback_driver_port * port, + struct usbback_driver_backend * backend +); + +void usbback_driver_port_claim + ( struct usbback_driver_port * port, char * path ); + +void usbback_driver_port_release + ( struct usbback_driver_port * port ); + +int usbback_driver_port_probe_usb( struct usb_interface * intf ); + +void usbback_driver_port_disconnect_usb( struct usb_interface * intf ); + +/* On success, usbback_driver_port_reset returns */ +/* USBIF_RESET_RESULT_FULL/LOW/HIGH_SPEED */ + +int usbback_driver_port_reset( struct usbback_driver_port * port ); + +void usbback_driver_port_set_guest_address + ( struct usbback_driver_port * port, unsigned long guest_address ); + +int usbback_driver_port_match_guest_address + ( struct usbback_driver_port * port, unsigned long guest_address ); + +void usbback_driver_port_connect + ( struct usbback_driver_port * port ); + +void usbback_driver_port_handle_io + ( struct usbback_driver_port * port, xenidc_transaction * transaction ); + +void usbback_driver_port_disconnect + ( struct usbback_driver_port * port ); + +int usbback_driver_port_try_unlink + ( struct usbback_driver_port * port, int unlink_id ); + +void usbback_driver_port_shutdown( struct usbback_driver_port * port ); + +typedef enum +{ + usbback_driver_port_state_i, + usbback_driver_port_state_i_pc, + usbback_driver_port_state_i_pc_up, + usbback_driver_port_state_i_pc_up_pr, + usbback_driver_port_state_i_pc_up_ud, + usbback_driver_port_state_i_pc_up_sd, + usbback_driver_port_state_i_pc_up_pr_ud, + usbback_driver_port_state_i_pc_up_pr_ri, + usbback_driver_port_state_i_pc_up_ud_sd, + usbback_driver_port_state_i_pc_up_sd_ri, + usbback_driver_port_state_i_pc_up_pr_ud_ri, + usbback_driver_port_state_i_pc_up_ud_sd_ri +} +usbback_driver_port_state; + +#define USBBACK_DRIVER_PORT_RESOURCE_COUNT 4 + +struct usbback_driver_port +{ + struct usbback_driver_backend * backend; + struct list_head link; + char path[ 16 ]; /* FIXME: Magic number. */ + struct usb_device * usbdev; + spinlock_t lock; + usbback_driver_port_state state; + int usbdev_is_connected; + int enabled; + unsigned long guest_address; + struct list_head transaction_list; + struct list_head purge_list; + struct list_head free_resource_list; + unsigned long current_transactions; + struct usbback_driver_port_resource resources + [ USBBACK_DRIVER_PORT_RESOURCE_COUNT ]; + xenidc_work purge_io_1_work; + xenidc_work perform_release_1_work; + int release; + int usb_disconnect; + int shutdown; +}; + +static inline struct usb_device * usbback_driver_port_query_usbdev + ( struct usbback_driver_port * port ) +{ + trace(); + + ASSERT( port->usbdev != NULL ); + + return port->usbdev; +} + +static inline int usbback_driver_port_usbdev_is_connected + ( struct usbback_driver_port * port ) +{ + /* trace(); */ + + return port->usbdev_is_connected; +} + +void usbback_driver_port_resource_completed_io +( + struct usbback_driver_port * port, + struct usbback_driver_port_resource * resource +); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,1223 @@ +/*****************************************************************************/ +/* Resource which processes a usbback_transaction by translating it into */ +/* an URB and submitting it to the USB stack. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Based on arch/xen/drivers/usbif/backend/main.c, original copyright notice */ +/* follows... */ +/*****************************************************************************/ + +/****************************************************************************** + * arch/xen/drivers/usbif/backend/main.c + * + * Backend for the Xen virtual USB driver - provides an abstraction of a + * USB host controller to the corresponding frontend driver. + * + * by Mark Williamson + * Copyright (c) 2004 Intel Research Cambridge + * Copyright (c) 2004, 2005 Mark Williamson + * + * Based on arch/xen/drivers/blkif/backend/main.c + * Copyright (c) 2003-2004, Keir Fraser & Steve Hand + */ + +#include +#include "usbback_assert.h" +#include "usbback_driver_port.h" +#include "usbback_driver_port_resource.h" +#include "usbback_trace.h" + +static XENIDC_CALLBACK_SERIALISER + ( usbback_driver_port_resource_submit_urb_serialiser ); + +static xenidc_rbr_mapper_pool * usbback_driver_port_resource_rbr_mapper_pool; + +int usbback_driver_port_resource_class_init( void ) +{ + trace(); + + usbback_driver_port_resource_rbr_mapper_pool = + xenidc_allocate_rbr_mapper_pool( USBIF_MAX_PAGES_PER_REQUEST ); + + return ( usbback_driver_port_resource_rbr_mapper_pool != NULL ) ? + 0 : -ENOMEM; +} + +void usbback_driver_port_resource_class_exit( void ) +{ + trace(); + + xenidc_free_rbr_mapper_pool + ( usbback_driver_port_resource_rbr_mapper_pool ); +} + +typedef enum +{ + usbback_driver_port_resource_stimulus_st, /* Start IO */ + usbback_driver_port_resource_stimulus_tu, /* Try unlink */ + usbback_driver_port_resource_stimulus_ms, /* Map success */ + usbback_driver_port_resource_stimulus_mf, /* Map failure */ + usbback_driver_port_resource_stimulus_us, /* URB submitted */ + usbback_driver_port_resource_stimulus_un, /* URB not submitted */ + usbback_driver_port_resource_stimulus_uc, /* URB completed */ + usbback_driver_port_resource_stimulus_ul, /* Unlink completed */ +} +usbback_driver_port_resource_stimulus; + +static void usbback_driver_port_resource_handle_stimulus +( + struct usbback_driver_port_resource * resource, + usbback_driver_port_resource_stimulus stimulus +); + +static void usbback_driver_port_resource_submit_urb_1 + ( xenidc_callback * callback ); + +static void usbback_driver_port_resource_unlink_urb_1( void * data ); + +static void usbback_driver_port_resource_map_callback + ( xenidc_callback * callback ); + +static void usbback_driver_port_resource_unmap_callback + ( xenidc_callback * callback ); + +void usbback_driver_port_resource_init +( + struct usbback_driver_port_resource * resource, + struct usbback_driver_port * port +) +{ + trace(); + + resource->port = port; + + INIT_LIST_HEAD( &resource->link ); + + spin_lock_init( &resource->lock ); + + resource->state = usbback_driver_port_resource_state_i; + + resource->transaction = NULL; + + xenidc_map_rbr_request_element_init( &resource->request_element[ 0 ] ); + xenidc_map_rbr_request_element_init( &resource->request_element[ 1 ] ); + + xenidc_reserve_and_map_rbr_request_init + ( + &resource->reserve_and_map_rbr_request, + usbback_driver_port_resource_map_callback, + usbback_driver_port_resource_unmap_callback + ); + + resource->rbrs_mapped = 0; + + xenidc_callback_init + ( + &resource->submit_urb_1_callback, + usbback_driver_port_resource_submit_urb_1 + ); + + xenidc_work_init + ( + &resource->unlink_urb_1_work, + usbback_driver_port_resource_unlink_urb_1, + resource + ); +} + +void usbback_driver_port_resource_start_io +( + struct usbback_driver_port_resource * resource, + xenidc_transaction * transaction +) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + resource->transaction_error = XENIDC_ERROR_SUCCESS; + resource->transaction_status_length = 0; + + resource->transaction = transaction; + + usbback_driver_port_resource_handle_stimulus + ( resource, usbback_driver_port_resource_stimulus_st ); + + spin_unlock_irqrestore( &resource->lock, flags ); + } +} + +int usbback_driver_port_resource_try_unlink + ( struct usbback_driver_port_resource * resource, int unlink_id ) +{ + trace(); + + { + int return_value = 0; + + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + if( resource->transaction != NULL ) + { + usbif_io_transaction_parameters_header header; + + if + ( + ( + xenidc_local_buffer_reference_copy_out + ( + &resource->transaction->parameters, + &header, + sizeof( header ) + ) + == + sizeof( header ) + ) + && + ( header.unlink_id == unlink_id ) + ) + { + usbback_driver_port_resource_handle_stimulus + ( resource, usbback_driver_port_resource_stimulus_tu ); + + return_value = 1; + } + } + + spin_unlock_irqrestore( &resource->lock, flags ); + + return return_value; + } +} + +void usbback_driver_port_resource_flush_transaction + ( struct usbback_driver_port_resource * resource ) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + if( resource->transaction != NULL ) + { + usbback_driver_port_resource_handle_stimulus + ( resource, usbback_driver_port_resource_stimulus_tu ); + } + + spin_unlock_irqrestore( &resource->lock, flags ); + } +} + +static void usbback_driver_port_resource_invalid_stimulus +( + struct usbback_driver_port_resource * resource, + usbback_driver_port_resource_stimulus stimulus +); + +static void usbback_driver_port_resource_map_buffer + ( struct usbback_driver_port_resource * resource ); + +static void usbback_driver_port_resource_abort_map + ( struct usbback_driver_port_resource * resource ); + +static void usbback_driver_port_resource_submit_urb + ( struct usbback_driver_port_resource * resource ); + +static void usbback_driver_port_resource_unlink_urb + ( struct usbback_driver_port_resource * resource ); + +static void usbback_driver_port_resource_set_error + ( struct usbback_driver_port_resource * resource ); + +static void usbback_driver_port_resource_complete + ( struct usbback_driver_port_resource * resource ); + +static void usbback_driver_port_resource_handle_stimulus +( + struct usbback_driver_port_resource * resource, + usbback_driver_port_resource_stimulus stimulus +) +{ + trace3 + ( + "port resource %p in state %d received stimulus %d", + resource, + resource->state, + stimulus + ); + + switch( resource->state ) + { + case usbback_driver_port_resource_state_i: + /* Idle */ + switch( stimulus ) + { + case usbback_driver_port_resource_stimulus_st: + resource->state = usbback_driver_port_resource_state_i_st; + usbback_driver_port_resource_map_buffer( resource ); + break; + default: + usbback_driver_port_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + case usbback_driver_port_resource_state_i_st: + /* Handling request */ + /* map_buffer outstanding */ + switch( stimulus ) + { + case usbback_driver_port_resource_stimulus_tu: + resource->state = usbback_driver_port_resource_state_i_st_tu; + usbback_driver_port_resource_abort_map( resource ); + break; + case usbback_driver_port_resource_stimulus_ms: + resource->state = usbback_driver_port_resource_state_i_st_ms; + usbback_driver_port_resource_submit_urb( resource ); + break; + case usbback_driver_port_resource_stimulus_mf: + resource->state = usbback_driver_port_resource_state_i; + usbback_driver_port_resource_complete( resource ); + break; + default: + usbback_driver_port_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + case usbback_driver_port_resource_state_i_st_tu: + /* Handling request */ + /* map_buffer outstanding */ + /* unlinking */ + switch( stimulus ) + { + case usbback_driver_port_resource_stimulus_tu: + break; + case usbback_driver_port_resource_stimulus_ms: + resource->state = usbback_driver_port_resource_state_i; + usbback_driver_port_resource_set_error( resource ); + usbback_driver_port_resource_complete( resource ); + break; + case usbback_driver_port_resource_stimulus_mf: + resource->state = usbback_driver_port_resource_state_i; + usbback_driver_port_resource_complete( resource ); + break; + default: + usbback_driver_port_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + case usbback_driver_port_resource_state_i_st_ms: + /* Handling request */ + /* submit_urb outstanding */ + switch( stimulus ) + { + case usbback_driver_port_resource_stimulus_tu: + resource->state = usbback_driver_port_resource_state_i_st_ms_tu; + break; + case usbback_driver_port_resource_stimulus_us: + resource->state = usbback_driver_port_resource_state_i_st_ms_us; + break; + case usbback_driver_port_resource_stimulus_un: + resource->state = usbback_driver_port_resource_state_i; + usbback_driver_port_resource_complete( resource ); + break; + case usbback_driver_port_resource_stimulus_uc: + resource->state = usbback_driver_port_resource_state_i_st_ms_uc; + break; + default: + usbback_driver_port_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + case usbback_driver_port_resource_state_i_st_ms_tu: + /* Handling request */ + /* submit_urb outstanding */ + /* unlinking */ + switch( stimulus ) + { + case usbback_driver_port_resource_stimulus_tu: + break; + case usbback_driver_port_resource_stimulus_us: + resource->state = usbback_driver_port_resource_state_i_st_ms_tu_us; + usbback_driver_port_resource_unlink_urb( resource ); + break; + case usbback_driver_port_resource_stimulus_un: + resource->state = usbback_driver_port_resource_state_i; + usbback_driver_port_resource_complete( resource ); + break; + case usbback_driver_port_resource_stimulus_uc: + resource->state = usbback_driver_port_resource_state_i_st_ms_uc; + break; + default: + usbback_driver_port_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + case usbback_driver_port_resource_state_i_st_ms_us: + /* Handling request */ + /* URB submitted */ + switch( stimulus ) + { + case usbback_driver_port_resource_stimulus_tu: + resource->state = usbback_driver_port_resource_state_i_st_ms_tu_us; + usbback_driver_port_resource_unlink_urb( resource ); + break; + case usbback_driver_port_resource_stimulus_uc: + resource->state = usbback_driver_port_resource_state_i; + usbback_driver_port_resource_complete( resource ); + break; + default: + usbback_driver_port_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + case usbback_driver_port_resource_state_i_st_ms_uc: + /* Handling request */ + /* submit_urb outstanding */ + /* URB completed */ + switch( stimulus ) + { + case usbback_driver_port_resource_stimulus_tu: + break; + case usbback_driver_port_resource_stimulus_us: + resource->state = usbback_driver_port_resource_state_i; + usbback_driver_port_resource_complete( resource ); + break; + default: + usbback_driver_port_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + case usbback_driver_port_resource_state_i_st_ms_tu_us: + /* Handling request */ + /* URB submitted */ + /* unlink_urb outstanding */ + switch( stimulus ) + { + case usbback_driver_port_resource_stimulus_tu: + break; + case usbback_driver_port_resource_stimulus_uc: + case usbback_driver_port_resource_stimulus_ul: + resource->state = + usbback_driver_port_resource_state_i_st_ms_tu_us_uc; + break; + default: + usbback_driver_port_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + case usbback_driver_port_resource_state_i_st_ms_tu_us_uc: + /* Handling request */ + /* URB submitted or unlink_urb outstanding */ + switch( stimulus ) + { + case usbback_driver_port_resource_stimulus_tu: + break; + case usbback_driver_port_resource_stimulus_uc: + case usbback_driver_port_resource_stimulus_ul: + resource->state = usbback_driver_port_resource_state_i; + usbback_driver_port_resource_complete( resource ); + break; + default: + usbback_driver_port_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + default: + usbback_driver_port_resource_invalid_stimulus( resource, stimulus ); + break; + } +} + +static void usbback_driver_port_resource_invalid_stimulus +( + struct usbback_driver_port_resource * resource, + usbback_driver_port_resource_stimulus stimulus +) +{ + trace(); + + printk + ( + KERN_ERR "usbback: port resource %p in state %d" + "received invalid stimulus %d", + resource, + resource->state, + stimulus + ); +} + +static void usbback_driver_port_resource_map_buffer + ( struct usbback_driver_port_resource * resource ) +{ + trace(); + + { + usbif_io_transaction_parameters_header header; + + if + ( + xenidc_local_buffer_reference_copy_out + ( + &resource->transaction->parameters, + &header, + sizeof( header ) + ) + != + sizeof( header ) + ) + { + goto FORMAT_ERROR; + } + + xenidc_map_rbr_request_element_ensure_removed + ( &resource->request_element[ 0 ] ); + + xenidc_map_rbr_request_element_ensure_removed + ( &resource->request_element[ 1 ] ); + + xenidc_reserve_and_map_rbr_request_add_element + ( + &resource->reserve_and_map_rbr_request, + &resource->request_element[ 0 ] + ); + + xenidc_map_rbr_request_element_set_rbr + ( + &resource->request_element[ 0 ], + header.rbr + ); + + if + ( + header.io_transaction_type + == + USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS + ) + { + usbif_isochronous_io_transaction_parameters parameters; + + if + ( + xenidc_local_buffer_reference_copy_out + ( + &resource->transaction->parameters, + ¶meters, + sizeof( parameters ) + ) + != + sizeof( parameters ) + ) + { + goto FORMAT_ERROR; + } + + xenidc_reserve_and_map_rbr_request_add_element + ( + &resource->reserve_and_map_rbr_request, + &resource->request_element[ 1 ] + ); + + xenidc_map_rbr_request_element_set_rbr + ( + &resource->request_element[ 1 ], + parameters.schedule_rbr + ); + } + + xenidc_rbr_mapper_pool_reserve_and_map_rbrs + ( + usbback_driver_port_resource_rbr_mapper_pool, + &resource->reserve_and_map_rbr_request + ); + } + + return; + + FORMAT_ERROR: + + resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT; + + usbback_driver_port_resource_handle_stimulus + ( resource, usbback_driver_port_resource_stimulus_mf ); +} + +static void usbback_driver_port_resource_abort_map + ( struct usbback_driver_port_resource * resource ) +{ + trace(); + + xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs + ( + usbback_driver_port_resource_rbr_mapper_pool, + &resource->reserve_and_map_rbr_request + ); +} + +static void usbback_driver_port_resource_map_callback + ( xenidc_callback * callback ) +{ + trace(); + + { + xenidc_reserve_and_map_rbr_request * request = + xenidc_reserve_and_map_rbr_request_map_callback_to( callback ); + + struct usbback_driver_port_resource * resource = container_of + ( + request, + struct usbback_driver_port_resource, + reserve_and_map_rbr_request + ); + + { + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + resource->transaction_error = + xenidc_callback_query_error( callback ); + + if + ( + resource->transaction_error + == + XENIDC_ERROR_SUCCESS + ) + { + resource->rbrs_mapped = 1; + + usbback_driver_port_resource_handle_stimulus + ( resource, usbback_driver_port_resource_stimulus_ms ); + } + else + { + usbback_driver_port_resource_handle_stimulus + ( resource, usbback_driver_port_resource_stimulus_mf ); + } + + spin_unlock_irqrestore( &resource->lock, flags ); + } + } +} + +static void usbback_driver_port_resource_submit_urb + ( struct usbback_driver_port_resource * resource ) +{ + trace(); + + xenidc_callback_serialiser_complete_callback + ( + &usbback_driver_port_resource_submit_urb_serialiser, + &resource->submit_urb_1_callback, + 0 + ); +} + +static void usbback_driver_port_resource_end_io + ( struct urb * urb, struct pt_regs * regs ); + +static int check_iso_schedule( struct urb * urb ) +{ + int i; + + unsigned long total_length = 0; + + for( i = 0; i < urb->number_of_packets; i++ ) + { + struct usb_iso_packet_descriptor * desc = &urb->iso_frame_desc[ i ]; + + total_length += desc->length; + + if + ( + ( desc->offset > urb->transfer_buffer_length ) + || + ( desc->length > ( urb->transfer_buffer_length - desc->offset ) ) + || + ( total_length > urb->transfer_buffer_length ) + ) + { + return -EINVAL; + } + } + + return 0; +} + +static void usbback_driver_port_resource_submit_urb_1 + ( xenidc_callback * callback ) +{ + trace(); + + { + struct usbback_driver_port_resource * resource = container_of + ( + callback, + struct usbback_driver_port_resource, + submit_urb_1_callback + ); + + usbif_io_transaction_parameters io_parameters; + + { + xenidc_buffer_byte_count io_parameters_byte_count = + xenidc_local_buffer_reference_copy_out + ( + &resource->transaction->parameters, + &io_parameters, + sizeof( io_parameters ) + ); + + if( io_parameters_byte_count < sizeof( io_parameters.header ) ) + { + resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT; + + goto FORMAT_ERROR; + } + + if + ( + io_parameters.header.io_transaction_type + >= + USBIF_IO_TRANSACTION_TYPE_LIMIT + ) + { + resource->transaction_error = XENIDC_ERROR_INVALID_PARAMETER; + + goto FORMAT_ERROR; + } + + if + ( + io_parameters_byte_count + < + usbif_io_parameters_byte_count + [ io_parameters.header.io_transaction_type ] + ) + { + resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT; + + goto FORMAT_ERROR; + } + } + + if + ( + io_parameters.header.io_transaction_type + == + USBIF_IO_TRANSACTION_TYPE_CONTROL + ) + { + struct usb_ctrlrequest * ctrl = + (struct usb_ctrlrequest *)io_parameters.control.setup; + + if + ( + ctrl->bRequestType + == + ( USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE ) + ) + { + if( ctrl->bRequest == USB_REQ_SET_ADDRESS ) + { + usbback_driver_port_set_guest_address + ( resource->port, le16_to_cpu( ctrl->wValue ) ); + + goto HANDLED_SPECIAL_CASE; + } + else if( ctrl->bRequest == USB_REQ_SET_CONFIGURATION ) + { + /* FIXME: what to do for set configuration? */ + + goto HANDLED_SPECIAL_CASE; + } + } + } + + { + struct urb * urb = resource->urb = usb_alloc_urb + ( + ( + io_parameters.header.io_transaction_type + == + USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS + ) + ? io_parameters.isochronous.packet_count : 0, + GFP_KERNEL + ); + + static const unsigned int pipe_type + [ USBIF_IO_TRANSACTION_TYPE_LIMIT ] = + { + [ USBIF_IO_TRANSACTION_TYPE_CONTROL ] = PIPE_CONTROL, + [ USBIF_IO_TRANSACTION_TYPE_BULK ] = PIPE_BULK, + [ USBIF_IO_TRANSACTION_TYPE_INTERRUPT ] = PIPE_INTERRUPT, + [ USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS ] = PIPE_ISOCHRONOUS + }; + + unsigned int pipe = + ( + ( + ( + ( + io_parameters.header.direction + == + USBIF_IO_TRANSACTION_DIRECTION_OUT + ) + ? USB_DIR_OUT : USB_DIR_IN + ) + << 7 + ) + | + ( + (unsigned int)usbback_driver_port_query_usbdev + ( resource->port )->devnum + << + 8 + ) + | + ( (unsigned int)io_parameters.header.endpoint << 15 ) + | + ( pipe_type[ io_parameters.header.io_transaction_type ] << 30 ) + ); + + if( urb == NULL ) + { + /* FIXME: better URB resource management should let us queue */ + /* for an URB and ISO resources from a reserved pool which */ + /* would eliminate the possibility of failure at this point. */ + + resource->transaction_error = + XENIDC_ERROR_IMPLEMENTATION_DEFICIENCY; + + goto NO_URB; + } + + if + ( + io_parameters.header.io_transaction_type + == + USBIF_IO_TRANSACTION_TYPE_CONTROL + ) + { + memcpy + ( + resource->setup, + io_parameters.control.setup, + sizeof( resource->setup ) + ); + + usb_fill_control_urb + ( + urb, + usbback_driver_port_query_usbdev( resource->port ), + pipe, + resource->setup, + resource->request_element[ 0 ].mapping, + xenidc_remote_buffer_reference_query_byte_count + ( &resource->request_element[ 0 ].rbr ), + usbback_driver_port_resource_end_io, + resource + ); + } + else if + ( + io_parameters.header.io_transaction_type + == + USBIF_IO_TRANSACTION_TYPE_BULK + ) + { + usb_fill_bulk_urb + ( + urb, + usbback_driver_port_query_usbdev( resource->port ), + pipe, + resource->request_element[ 0 ].mapping, + xenidc_remote_buffer_reference_query_byte_count + ( &resource->request_element[ 0 ].rbr ), + usbback_driver_port_resource_end_io, + resource + ); + } + else if + ( + io_parameters.header.io_transaction_type + == + USBIF_IO_TRANSACTION_TYPE_INTERRUPT + ) + { + /* FIXME: hacking the interval like this is a bit unclean. */ + /* should probably convert back to exponential form for */ + /* high speed transfers and then pass the value into */ + /* fill_int_urb. */ + usb_fill_int_urb + ( + urb, + usbback_driver_port_query_usbdev( resource->port ), + pipe, + resource->request_element[ 0 ].mapping, + xenidc_remote_buffer_reference_query_byte_count + ( &resource->request_element[ 0 ].rbr ), + usbback_driver_port_resource_end_io, + resource, + 1 /* For the time being... */ + ); + + /* ...now set the real value. */ + urb->interval = io_parameters.interrupt.interval; + } + else + { + ASSERT + ( + io_parameters.header.io_transaction_type + == + USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS + ); + + /* FIXME: where's usb_fill_isoc_urb ?!? */ + + spin_lock_init(&urb->lock); + urb->dev = usbback_driver_port_query_usbdev( resource->port ); + urb->pipe = pipe; + urb->transfer_buffer = resource->request_element[ 0 ].mapping; + urb->transfer_buffer_length = + xenidc_remote_buffer_reference_query_byte_count + ( &resource->request_element[ 0 ].rbr ); + urb->complete = usbback_driver_port_resource_end_io; + urb->context = resource; + urb->number_of_packets = + io_parameters.isochronous.packet_count; + urb->interval = io_parameters.isochronous.interval; + urb->start_frame = 0; + urb->transfer_flags |= URB_ISO_ASAP; + + if + ( + xenidc_remote_buffer_reference_query_byte_count + ( &resource->request_element[ 1 ].rbr ) + < + ( + io_parameters.isochronous.packet_count + * + sizeof( usbif_isochronous_io_schedule_element ) + ) + ) + { + resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT; + + goto SCHEDULE_ERROR; + } + + { + usbif_isochronous_io_schedule_element * schedule_element = + resource->request_element[ 1 ].mapping; + + usbif_isochronous_io_schedule_element aligned_element; + + int i; + + for + ( + i = 0; + i < io_parameters.isochronous.packet_count; + i++ + ) + { + memcpy + ( + &aligned_element, + schedule_element++, + sizeof( aligned_element ) + ); + + urb->iso_frame_desc[ i ].offset = + aligned_element.offset; + urb->iso_frame_desc[ i ].length = + aligned_element.length; + + urb->iso_frame_desc[ i ].actual_length = 0; + urb->iso_frame_desc[ i ].status = 0; + } + } + + if( !check_iso_schedule( urb ) ) + { + resource->transaction_error = + XENIDC_ERROR_INVALID_PARAMETER; + + goto SCHEDULE_ERROR; + } + } + + /* On the backend, all unlinks are asynchronous. */ + + urb->transfer_flags |= URB_ASYNC_UNLINK; + + if( io_parameters.header.flags & USBIF_IO_FLAGS_SHORT_NOT_OK ) + { + urb->transfer_flags |= URB_SHORT_NOT_OK; + } + if( io_parameters.header.flags & USBIF_IO_FLAGS_ZERO_PACKET ) + { + urb->transfer_flags |= URB_ZERO_PACKET; + } + + if( usb_submit_urb( urb, GFP_KERNEL ) != 0 ) + { + printk( KERN_WARNING "URB %p submission failed.\n", urb ); + + /* FIXME: non-specific failure return. */ + resource->transaction_error = USBIF_XENIDC_ERROR_FAILURE; + + goto URB_ERROR; + } + + { + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + usbback_driver_port_resource_handle_stimulus + ( resource, usbback_driver_port_resource_stimulus_us ); + + spin_unlock_irqrestore( &resource->lock, flags ); + } + + return; + + URB_ERROR: + + SCHEDULE_ERROR: + + usb_free_urb( urb ); + } + + NO_URB: + + HANDLED_SPECIAL_CASE: + + FORMAT_ERROR: + + { + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + usbback_driver_port_resource_handle_stimulus + ( resource, usbback_driver_port_resource_stimulus_un ); + + spin_unlock_irqrestore( &resource->lock, flags ); + } + } +} + +static void usbback_driver_port_resource_end_io + ( struct urb * urb, struct pt_regs * regs ) +{ + trace(); + + { + struct usbback_driver_port_resource * resource = urb->context; + + if( urb->status != 0 ) + { + printk + ( KERN_WARNING "URB %p failed. Status %d\n", urb, urb->status ); + + resource->transaction_error = USBIF_XENIDC_ERROR_FAILURE; + } + + resource->transaction_status_length = urb->actual_length; + + if( usb_pipetype( urb->pipe ) == PIPE_ISOCHRONOUS ) + { + usbif_isochronous_io_schedule_element * schedule_element = + resource->request_element[ 1 ].mapping; + + usbif_isochronous_io_schedule_element aligned_element; + + int i; + + for( i = 0; i < urb->number_of_packets; i++ ) + { + aligned_element.length = + urb->iso_frame_desc[ i ].actual_length; + aligned_element.error = + ( urb->iso_frame_desc[ i ].status == 0 ) ? + XENIDC_ERROR_SUCCESS : USBIF_XENIDC_ERROR_FAILURE; + + memcpy + ( + schedule_element++, + &aligned_element, + sizeof( *schedule_element ) + ); + } + } + + { + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + usbback_driver_port_resource_handle_stimulus + ( resource, usbback_driver_port_resource_stimulus_uc ); + + spin_unlock_irqrestore( &resource->lock, flags ); + } + } + + usb_free_urb( urb ); +} + +static void usbback_driver_port_resource_unlink_urb + ( struct usbback_driver_port_resource * resource ) +{ + trace(); + + usb_get_urb( resource->urb ); + + { + int scheduled = xenidc_work_schedule( &resource->unlink_urb_1_work ); + + ASSERT( scheduled ); + } +} + +static void usbback_driver_port_resource_unlink_urb_1( void * data ) +{ + trace(); + + { + struct usbback_driver_port_resource * resource = + (struct usbback_driver_port_resource *)data; + + usb_unlink_urb( resource->urb ); + + usb_put_urb( resource->urb ); + + { + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + usbback_driver_port_resource_handle_stimulus + ( resource, usbback_driver_port_resource_stimulus_ul ); + + spin_unlock_irqrestore( &resource->lock, flags ); + } + } +} + +static void usbback_driver_port_resource_set_error + ( struct usbback_driver_port_resource * resource ) +{ + trace(); + + resource->transaction_error = USBIF_XENIDC_ERROR_FAILURE; +} + +static void usbback_driver_port_resource_complete + ( struct usbback_driver_port_resource * resource ) +{ + trace(); + + resource->completing_transaction = resource->transaction; + resource->transaction = NULL; + + if( resource->rbrs_mapped ) + { + resource->rbrs_mapped = 0; + + xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs + ( + usbback_driver_port_resource_rbr_mapper_pool, + &resource->reserve_and_map_rbr_request + ); + } + else + { + xenidc_callback_success + ( + xenidc_reserve_and_map_rbr_request_to_unmap_callback + ( &resource->reserve_and_map_rbr_request ) + ); + } +} + +static void usbback_driver_port_resource_unmap_callback + ( xenidc_callback * callback ) +{ + trace(); + + { + xenidc_reserve_and_map_rbr_request * request = + xenidc_reserve_and_map_rbr_request_unmap_callback_to( callback ); + + struct usbback_driver_port_resource * resource = container_of + ( + request, + struct usbback_driver_port_resource, + reserve_and_map_rbr_request + ); + + usbif_io_transaction_status status; + + status.length = resource->transaction_status_length; + + if + ( + xenidc_local_buffer_reference_copy_in + ( + &resource->completing_transaction->status, + &status, + sizeof( status ) + ) + != + sizeof( status ) + ) + { + resource->transaction_error = XENIDC_ERROR_INVALID_FORMAT; + } + + xenidc_transaction_complete + ( resource->completing_transaction, resource->transaction_error ); + + usbback_driver_port_resource_completed_io( resource->port, resource ); + } +} diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,87 @@ +/*****************************************************************************/ +/* Resource which processes an io transaction by translating it into an URB */ +/* and submitting it to the USB stack. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBBACK_DRIVER_PORT_RESOURCE_H +#define USBBACK_DRIVER_PORT_RESOURCE_H + +#include +#include "usbback_device.h" + +int usbback_driver_port_resource_class_init( void ); + +void usbback_driver_port_resource_class_exit( void ); + +struct usbback_driver_port; +struct usbback_driver_port_resource; + +void usbback_driver_port_resource_init +( + struct usbback_driver_port_resource * resource, + struct usbback_driver_port * port +); + +void usbback_driver_port_resource_start_io +( + struct usbback_driver_port_resource * resource, + xenidc_transaction * transaction +); + +int usbback_driver_port_resource_try_unlink + ( struct usbback_driver_port_resource * resource, int unlink_id ); + +void usbback_driver_port_resource_flush_transaction + ( struct usbback_driver_port_resource * resource ); + +typedef enum +{ + usbback_driver_port_resource_state_i, + usbback_driver_port_resource_state_i_st, + usbback_driver_port_resource_state_i_st_tu, + usbback_driver_port_resource_state_i_st_ms, + usbback_driver_port_resource_state_i_st_ms_tu, + usbback_driver_port_resource_state_i_st_ms_us, + usbback_driver_port_resource_state_i_st_ms_uc, + usbback_driver_port_resource_state_i_st_ms_tu_us, + usbback_driver_port_resource_state_i_st_ms_tu_us_uc +} +usbback_driver_port_resource_state; + +struct usbback_driver_port_resource +{ + struct usbback_driver_port * port; + struct list_head link; + spinlock_t lock; + usbback_driver_port_resource_state state; + xenidc_error transaction_error; + unsigned long transaction_status_length; + xenidc_transaction * transaction; + xenidc_transaction * completing_transaction; + xenidc_reserve_and_map_rbr_request reserve_and_map_rbr_request; + xenidc_map_rbr_request_element request_element[ 2 ]; + int rbrs_mapped; + struct urb * urb; + u8 setup[ 8 ]; + xenidc_callback submit_urb_1_callback; + xenidc_work unlink_urb_1_work; +}; + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,83 @@ +/*****************************************************************************/ +/* Back-end module for Xen USB split driver. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include "usbback_driver.h" +#include "usbback_device.h" +#include "usbback_trace.h" + +static int usbback_module_init_or_exit( int exit ) +{ + trace(); + + { + int return_value = 0; + + if( exit ) + { + goto EXIT; + } + + if( ( return_value = usbback_driver_init() ) != 0 ) + { + goto EXIT_NO_DRIVER; + } + + if( ( return_value = usbback_device_class_init() ) != 0 ) + { + goto EXIT_NO_DEVICE_CLASS; + } + + return 0; + + EXIT: + + usbback_device_class_exit(); + + EXIT_NO_DEVICE_CLASS: + + usbback_driver_exit(); + + EXIT_NO_DRIVER: + + return return_value; + } +} + +static int __init usbback_module_init( void ) +{ + trace(); + + return usbback_module_init_or_exit( 0 ); +} + +static void __exit usbback_module_exit( void ) +{ + trace(); + + (void)usbback_module_init_or_exit( 1 ); +} + +module_init( usbback_module_init ); +module_exit( usbback_module_exit ); + +MODULE_LICENSE( "GPL" ); diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,54 @@ +/*****************************************************************************/ +/* Simple trace macros */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBBACK_TRACE_H +#define USBBACK_TRACE_H + +#include +#include + +#ifdef CONFIG_XEN_USBDEV_BACKEND_TRACE + +#define trace0( format ) \ +printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__ ) + +#define trace1( format, a0 ) \ +printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__, a0 ) + +#define trace2( format, a0, a1 ) \ +printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__, a0, a1 ) + +#define trace3( format, a0, a1, a2 ) \ +printk( KERN_INFO "usbback %s:" format "\n", __PRETTY_FUNCTION__, a0, a1, a2 ) + +#define trace() trace0( "" ) + +#else + +#define trace0( format ) +#define trace1( format,a0 ) +#define trace2( format,a0, a1 ) +#define trace3( format,a0, a1, a2 ) +#define trace() + +#endif + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile Mon Oct 24 15:04:49 2005 @@ -0,0 +1,7 @@ +obj-$(CONFIG_XEN_USBDEV_FRONTEND) += usbfront.o + +usbfront-objs := \ +usbfront_hcd_resource.o \ +usbfront_driver.o \ +usbfront_device.o \ +usbfront_module.o diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_assert.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_assert.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,44 @@ +/*****************************************************************************/ +/* An implementation of the ASSERT macro. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBFRONT_ASSERT_H +#define USBFRONT_ASSERT_H + +#include + +static inline void assert_failed + ( const char * function, int line, const char * statement ) +{ + printk + ( + KERN_ERR "usbfront assert failed: %s line %d, statement %s\n", + function, + line, + statement + ); + + BUG(); +} + +#define ASSERT( S ) \ +( ( S ) ? ( (void)0 ) : assert_failed( __PRETTY_FUNCTION__, __LINE__, #S ) ) + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,1321 @@ +/*****************************************************************************/ +/* usbfront_device is a device which represents a connection to a back-end. */ +/* The intent was for it to have an interface like a hardware USB host */ +/* controller device. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Based on arch/xen/drivers/usbif/frontend/main.c, original copyright */ +/* notice follows... */ +/*****************************************************************************/ + +/* + * Xen Virtual USB Frontend Driver + * + * This file contains the first version of the Xen virtual USB hub + * that I've managed not to delete by mistake (3rd time lucky!). + * + * Based on Linux's uhci.c, original copyright notices are displayed + * below. Portions also (c) 2004 Intel Research Cambridge + * and (c) 2004, 2005 Mark Williamson + * + * Contact or + * 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 + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx + * (C) Copyright 1999 Randy Dunlap + * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx + * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx + * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx + * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx + * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface + * support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx). + * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) + * + * Intel documents this fairly well, and as far as I know there + * are no royalties or anything like that, but even so there are + * people who decided that they want to do the same thing in a + * completely different way. + * + * WARNING! The USB documentation is downright evil. Most of it + * is just crap, written by a committee. You're better off ignoring + * most of it, the important stuff is: + * - the low-level protocol (fairly simple but lots of small details) + * - working around the horridness of the rest + */ + +/* Xenbus code for blkif backend + Copyright (C) 2005 Rusty Russell + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public 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 +#include +#include +#include "usbfront_assert.h" +#include "usbfront_device.h" +#include "usbfront_driver.h" +#include "usbfront_trace.h" + +#define USBFRONT_DEVICE_PORT_COUNT 7 + +typedef enum +{ + usbfront_device_state_i, + usbfront_device_state_i_cn, + usbfront_device_state_i_cn_dn, + usbfront_device_state_i_cn_ps, + usbfront_device_state_i_cn_pf, + usbfront_device_state_i_cn_dn_ps, + usbfront_device_state_i_cn_ps_dn, + usbfront_device_state_i_cn_ps_pc, + usbfront_device_state_i_cn_ps_dn_rc +} +usbfront_device_state; + +typedef enum +{ + usbfront_device_stimulus_cn, /* Endpoint connect. */ + usbfront_device_stimulus_dn, /* Endpoint disconnect. */ + usbfront_device_stimulus_ps, /* Probe driver success. */ + usbfront_device_stimulus_pf, /* Probe driver failure. */ + usbfront_device_stimulus_rc, /* Remove driver complete. */ + usbfront_device_stimulus_pt, /* Polling tick. */ + usbfront_device_stimulus_pc /* Probe complete. */ +} +usbfront_device_stimulus; + +struct usbfront_device; + +struct usbfront_device_probe_transaction +{ + xenidc_transaction transaction; + + union + { + struct + { + usbif_probe_transaction_parameters parameters; + usbif_probe_transaction_status status; + } + probe; + struct + { + usbif_reset_transaction_parameters parameters; + usbif_reset_transaction_status status; + } + reset; + }; + + struct usbfront_device * device; +}; + +struct usbfront_device +{ + struct xenbus_device * dev; + void * drvdata; + spinlock_t lock; + usbfront_device_state state; + long int backend_id; + char * backend; + xenidc_endpoint endpoint; + xenidc_callback * endpoint_disconnect_callback; + int tick_count; + int port_probe_count; + struct usbfront_device_probe_transaction + probe_transaction[ USBFRONT_DEVICE_PORT_COUNT ]; + struct usb_port_status port_status[ USBFRONT_DEVICE_PORT_COUNT ]; + xenidc_work probe_driver_1_work; + xenidc_work remove_driver_1_work; +}; + +static void usbfront_device_handle_stimulus + ( struct usbfront_device * device, usbfront_device_stimulus stimulus ); + +static inline struct usbfront_device * usbfront_device_endpoint_to + ( xenidc_endpoint * endpoint ) +{ + trace(); + + return container_of( endpoint, struct usbfront_device, endpoint ); +} + +void usbfront_device_set_drvdata + ( struct usbfront_device * device, void * data ) +{ + trace(); + + device->drvdata = data; +} + +void * usbfront_device_get_drvdata( struct usbfront_device * device ) +{ + trace(); + + return device->drvdata; +} + +struct device * usbfront_device_to_dev( struct usbfront_device * device ) +{ + trace(); + + return &device->dev->dev; +} + +struct usbfront_device * usbfront_device_dev_to( struct device * dev ) +{ + trace(); + + return to_xenbus_device( dev )->data; +} + +int usbfront_device_query_port_count( struct usbfront_device * device ) +{ + /* trace(); */ + + return USBFRONT_DEVICE_PORT_COUNT; +} + +int usbfront_device_query_port_status_changed + ( struct usbfront_device * device, int port_number ) +{ + /* trace(); */ + + ASSERT + ( + ( port_number > 0 ) + && + ( port_number <= USBFRONT_DEVICE_PORT_COUNT ) + ); + + { + int changed; + + unsigned long flags; + + spin_lock_irqsave( &device->lock, flags ); + + if( ++device->tick_count == USBFRONT_DEVICE_PORT_COUNT ) + { + device->tick_count = 0; + + usbfront_device_handle_stimulus + ( device, usbfront_device_stimulus_pt ); + } + + changed = ( device->port_status[ port_number - 1 ].wPortChange != 0 ); + + spin_unlock_irqrestore( &device->lock, flags ); + + return changed; + } +} + +struct usb_port_status usbfront_device_query_port_status + ( struct usbfront_device * device, int port_number ) +{ + trace(); + + ASSERT + ( + ( port_number > 0 ) + && + ( port_number <= USBFRONT_DEVICE_PORT_COUNT ) + ); + + { + struct usb_port_status port_status; + + unsigned long flags; + + spin_lock_irqsave( &device->lock, flags ); + + port_status = device->port_status[ port_number - 1 ]; + + spin_unlock_irqrestore( &device->lock, flags ); + + return port_status; + } +} + +void usbfront_device_set_port_power + ( struct usbfront_device * device, int port_number ) +{ + trace(); + + ASSERT + ( + ( port_number > 0 ) + && + ( port_number <= USBFRONT_DEVICE_PORT_COUNT ) + ); + + { + unsigned long flags; + + spin_lock_irqsave( &device->lock, flags ); + + device->port_status[ port_number - 1 ].wPortStatus |= + USB_PORT_STAT_POWER; + + spin_unlock_irqrestore( &device->lock, flags ); + } +} + +void usbfront_device_set_port_reset + ( struct usbfront_device * device, int port_number ) +{ + trace(); + + ASSERT + ( + ( port_number > 0 ) + && + ( port_number <= USBFRONT_DEVICE_PORT_COUNT ) + ); + + { + unsigned long flags; + + spin_lock_irqsave( &device->lock, flags ); + + device->port_status[ port_number - 1 ].wPortStatus |= + USB_PORT_STAT_RESET; + device->port_status[ port_number - 1 ].wPortStatus &= + ~USB_PORT_STAT_ENABLE; + + usbfront_device_handle_stimulus( device, usbfront_device_stimulus_pt ); + + spin_unlock_irqrestore( &device->lock, flags ); + } +} + +void usbfront_device_clear_port_enable + ( struct usbfront_device * device, int port_number ) +{ + trace(); + + ASSERT + ( + ( port_number > 0 ) + && + ( port_number <= USBFRONT_DEVICE_PORT_COUNT ) + ); + + { + unsigned long flags; + + spin_lock_irqsave( &device->lock, flags ); + + device->port_status[ port_number - 1 ].wPortStatus &= + ~USB_PORT_STAT_ENABLE; + + spin_unlock_irqrestore( &device->lock, flags ); + } +} + +void usbfront_device_clear_port_connection_change + ( struct usbfront_device * device, int port_number ) +{ + trace(); + + ASSERT + ( + ( port_number > 0 ) + && + ( port_number <= USBFRONT_DEVICE_PORT_COUNT ) + ); + + { + unsigned long flags; + + spin_lock_irqsave( &device->lock, flags ); + + device->port_status[ port_number - 1 ].wPortChange &= + ~USB_PORT_STAT_C_CONNECTION; + + spin_unlock_irqrestore( &device->lock, flags ); + } +} + +void usbfront_device_clear_port_reset_change + ( struct usbfront_device * device, int port_number ) +{ + trace(); + + ASSERT + ( + ( port_number > 0 ) + && + ( port_number <= USBFRONT_DEVICE_PORT_COUNT ) + ); + + { + unsigned long flags; + + spin_lock_irqsave( &device->lock, flags ); + + device->port_status[ port_number - 1 ].wPortChange &= + ~USB_PORT_STAT_C_RESET; + + spin_unlock_irqrestore( &device->lock, flags ); + } +} + +void usbfront_device_submit_message + ( struct usbfront_device * device, xenidc_message * message ) +{ + trace(); + + xenidc_endpoint_submit_message( &device->endpoint, message ); +} + +void usbfront_device_submit_transaction + ( struct usbfront_device * device, xenidc_transaction * transaction ) +{ + trace(); + + xenidc_endpoint_submit_transaction( &device->endpoint, transaction ); +} + +static void usbfront_device_endpoint_connect( xenidc_endpoint * endpoint ) +{ + trace(); + + /* Between connect and completion of the disconnect callback we are */ + /* allowed to issue messages and transactions. */ + + { + struct usbfront_device * device = + usbfront_device_endpoint_to( endpoint ); + + unsigned long flags; + + spin_lock_irqsave( &device->lock, flags ); + + usbfront_device_handle_stimulus( device, usbfront_device_stimulus_cn ); + + spin_unlock_irqrestore( &device->lock, flags ); + } +} + +static void usbfront_device_endpoint_disconnect + ( xenidc_endpoint * endpoint, xenidc_callback * callback ) +{ + trace(); + + /* We must stop issuing messages and transactions and complete the */ + /* callback once all of the messages and transactions we are issuing */ + /* have completed or failed back to us. */ + + { + struct usbfront_device * device = + usbfront_device_endpoint_to( endpoint ); + + unsigned long flags; + + spin_lock_irqsave( &device->lock, flags ); + + device->endpoint_disconnect_callback = callback; + + usbfront_device_handle_stimulus( device, usbfront_device_stimulus_dn ); + + spin_unlock_irqrestore( &device->lock, flags ); + } +} + +static void usbfront_device_endpoint_message + ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference message ) +{ + trace(); + + /* The protocol doesn't require any messages sent from BE to FE so we */ + /* just ignore anything sent to us. */ +} + +static void usbfront_device_endpoint_transaction + ( xenidc_endpoint * endpoint, xenidc_transaction * transaction ) +{ + trace(); + + /* The protocol doesn't require any transactions sent from BE to FE so */ + /* we just ignore anything sent to us. */ + + xenidc_transaction_complete( transaction, XENIDC_ERROR_INVALID_PROTOCOL ); +} + +static void usbfront_device_probe_driver_1( void * data ); +static void usbfront_device_remove_driver_1( void * data ); +static void usbfront_device_probe_all_ports_1( xenidc_callback * callback ); + +static int usbfront_device_init_or_exit + ( struct usbfront_device * device, struct xenbus_device * dev, int exit ) +{ + trace(); + + { + int return_value = 0; + + if( exit ) + { + goto EXIT; + } + + memset( device, 0, sizeof( *device ) ); + + device->dev = dev; + + spin_lock_init( &device->lock ); + + device->state = usbfront_device_state_i; + + { + int i; + + for( i = 0; i < USBFRONT_DEVICE_PORT_COUNT; i++ ) + { + struct usbfront_device_probe_transaction * probe = + &device->probe_transaction[ i ]; + + xenidc_transaction_init + ( + &probe->transaction, + usbfront_device_probe_all_ports_1 + ); + + probe->device = device; + } + } + + xenidc_work_init + ( + &device->probe_driver_1_work, + usbfront_device_probe_driver_1, + device + ); + + xenidc_work_init + ( + &device->remove_driver_1_work, + usbfront_device_remove_driver_1, + device + ); + + device->backend = NULL; + + return_value = xenbus_gather + ( + NULL, /* FIXME? */ + dev->nodename, + "backend-id", "%li", &device->backend_id, + "backend", NULL, &device->backend, + NULL + ); + + if( XENBUS_EXIST_ERR( return_value ) ) + { + goto EXIT_NO_BACKEND; + } + + if( return_value < 0 ) + { + xenbus_dev_error + ( + dev, + return_value, + "reading %s/backend", + dev->nodename + ); + + goto EXIT_NO_BACKEND; + } + + return_value = xenidc_endpoint_init + ( + &device->endpoint, + usbfront_device_endpoint_connect, + usbfront_device_endpoint_disconnect, + usbfront_device_endpoint_message, + usbfront_device_endpoint_transaction, + USBIF_FE_INITIATOR_MESSAGE_MAXIMUM_BYTE_COUNT, + USBIF_FE_INITIATOR_TRANSACTION_QUOTA, + USBIF_FE_INITIATOR_TRANSACTION_MAXIMUM_BYTE_COUNT, + USBIF_FE_TARGET_MESSAGE_MAXIMUM_BYTE_COUNT, + USBIF_FE_TARGET_TRANSACTION_QUOTA, + USBIF_FE_TARGET_TRANSACTION_MAXIMUM_BYTE_COUNT + ); + + if( return_value != 0 ) + { + goto EXIT_NO_ENDPOINT; + } + + { + xenidc_address address; + + xenidc_address_init + ( + &address, + dev->nodename, + device->backend, + device->backend_id + ); + + return_value = + xenidc_endpoint_create( &device->endpoint, address ); + + if( return_value != 0 ) + { + goto EXIT_NO_CREATE; + } + } + + return 0; + + EXIT: + + xenidc_endpoint_destroy( &device->endpoint ); + + EXIT_NO_CREATE: + + xenidc_endpoint_exit( &device->endpoint ); + + EXIT_NO_ENDPOINT: + + kfree( device->backend ); + + EXIT_NO_BACKEND: + + return return_value; + } +} + +static int usbfront_device_init + ( struct usbfront_device * device, struct xenbus_device * dev ) +{ + trace(); + + return usbfront_device_init_or_exit( device, dev, 0 ); +} + +static void usbfront_device_exit( struct usbfront_device * device ) +{ + trace(); + + (void)usbfront_device_init_or_exit( device, NULL, 1 ); +} + +static int usbfront_device_probe_or_remove + ( struct xenbus_device * dev, int remove ) +{ + trace(); + + { + int return_value = 0; + + struct usbfront_device * device; + + if( remove ) + { + goto REMOVE; + } + + device = kmalloc( sizeof( *device ), GFP_KERNEL ); + + if( device == NULL ) + { + xenbus_dev_error( dev, -ENOMEM, "allocating backend structure" ); + + return_value = -ENOMEM; + + goto EXIT_NO_DEVICE; + } + + dev->data = device; + + return_value = usbfront_device_init( device, dev ); + + if( return_value != 0 ) + { + goto EXIT_INIT_FAILED; + } + + return 0; + + REMOVE: + + device = dev->data; + + usbfront_device_exit( device ); + + EXIT_INIT_FAILED: + + dev->data = NULL; + + kfree( device ); + + EXIT_NO_DEVICE: + + return return_value; + } +} + +static int usbfront_device_probe + ( struct xenbus_device * dev, const struct xenbus_device_id * id ) +{ + trace(); + + return usbfront_device_probe_or_remove( dev, 0 ); +} + +static int usbfront_device_remove( struct xenbus_device * dev ) +{ + trace(); + + return usbfront_device_probe_or_remove( dev, 1 ); +} + +static struct xenbus_device_id usbfront_device_ids[] = +{ + { "usb" }, + { "" } +}; + +static struct xenbus_driver usbfront_device_driver = +{ + .name = "usb", + .owner = THIS_MODULE, + .ids = usbfront_device_ids, + .probe = usbfront_device_probe, + .remove = usbfront_device_remove, +}; + +int usbfront_device_class_init( void ) +{ + trace(); + + return xenbus_register_driver( &usbfront_device_driver ); +} + +void usbfront_device_class_exit( void ) +{ + trace(); + + xenbus_unregister_driver( &usbfront_device_driver ); +} + +static void usbfront_device_invalid_stimulus + ( struct usbfront_device * device, usbfront_device_stimulus stimulus ); + +static void usbfront_device_probe_driver( struct usbfront_device * device ); + +static void usbfront_device_remove_driver( struct usbfront_device * device ); + +static void usbfront_device_probe_all_ports( struct usbfront_device * device ); + +static void usbfront_device_disconnect_all_ports + ( struct usbfront_device * device ); + +static void usbfront_device_complete_endpoint_disconnect + ( struct usbfront_device * device ); + +static void usbfront_device_handle_stimulus + ( struct usbfront_device * device, usbfront_device_stimulus stimulus ) +{ + switch( device->state ) + { + case usbfront_device_state_i: + switch( stimulus ) + { + case usbfront_device_stimulus_cn: + device->state = usbfront_device_state_i_cn; + usbfront_device_probe_driver( device ); + break; + default: + usbfront_device_invalid_stimulus( device, stimulus ); + break; + } + case usbfront_device_state_i_cn: + /* Probing driver. */ + switch( stimulus ) + { + case usbfront_device_stimulus_dn: + device->state = usbfront_device_state_i_cn_dn; + break; + case usbfront_device_stimulus_ps: + device->state = usbfront_device_state_i_cn_ps; + usbfront_device_probe_all_ports( device ); + break; + case usbfront_device_stimulus_pf: + device->state = usbfront_device_state_i_cn_pf; + break; + case usbfront_device_stimulus_pt: + break; + default: + usbfront_device_invalid_stimulus( device, stimulus ); + break; + } + case usbfront_device_state_i_cn_dn: + /* Probing driver. */ + /* Endpoint disconnecting. */ + switch( stimulus ) + { + case usbfront_device_stimulus_ps: + device->state = usbfront_device_state_i_cn_dn_ps; + usbfront_device_remove_driver( device ); + break; + case usbfront_device_stimulus_pf: + device->state = usbfront_device_state_i; + usbfront_device_disconnect_all_ports( device ); + usbfront_device_complete_endpoint_disconnect( device ); + break; + case usbfront_device_stimulus_pt: + break; + default: + usbfront_device_invalid_stimulus( device, stimulus ); + break; + } + case usbfront_device_state_i_cn_ps: + /* Driver Probed. */ + /* Polling ports. */ + switch( stimulus ) + { + case usbfront_device_stimulus_dn: + device->state = usbfront_device_state_i_cn_ps_dn; + usbfront_device_remove_driver( device ); + break; + case usbfront_device_stimulus_pt: + break; + case usbfront_device_stimulus_pc: + device->state = usbfront_device_state_i_cn_ps_pc; + break; + default: + usbfront_device_invalid_stimulus( device, stimulus ); + break; + } + case usbfront_device_state_i_cn_pf: + /* Driver probe failed. */ + switch( stimulus ) + { + case usbfront_device_stimulus_dn: + device->state = usbfront_device_state_i; + usbfront_device_disconnect_all_ports( device ); + usbfront_device_complete_endpoint_disconnect( device ); + break; + default: + usbfront_device_invalid_stimulus( device, stimulus ); + break; + } + case usbfront_device_state_i_cn_dn_ps: + /* Endpoint disconnecting. */ + /* Removing driver. */ + switch( stimulus ) + { + case usbfront_device_stimulus_rc: + device->state = usbfront_device_state_i; + usbfront_device_disconnect_all_ports( device ); + usbfront_device_complete_endpoint_disconnect( device ); + break; + case usbfront_device_stimulus_pt: + break; + default: + usbfront_device_invalid_stimulus( device, stimulus ); + break; + } + case usbfront_device_state_i_cn_ps_dn: + /* Endpoint disconnecting. */ + /* Removing driver. */ + /* Polling ports. */ + switch( stimulus ) + { + case usbfront_device_stimulus_rc: + device->state = usbfront_device_state_i_cn_ps_dn_rc; + break; + case usbfront_device_stimulus_pt: + break; + case usbfront_device_stimulus_pc: + device->state = usbfront_device_state_i_cn_dn_ps; + break; + default: + usbfront_device_invalid_stimulus( device, stimulus ); + break; + } + case usbfront_device_state_i_cn_ps_pc: + /* Driver Probed. */ + switch( stimulus ) + { + case usbfront_device_stimulus_dn: + device->state = usbfront_device_state_i_cn_dn_ps; + usbfront_device_remove_driver( device ); + break; + case usbfront_device_stimulus_pt: + device->state = usbfront_device_state_i_cn_ps; + usbfront_device_probe_all_ports( device ); + break; + default: + usbfront_device_invalid_stimulus( device, stimulus ); + break; + } + case usbfront_device_state_i_cn_ps_dn_rc: + /* Endpoint disconnecting. */ + /* Polling ports. */ + switch( stimulus ) + { + case usbfront_device_stimulus_pc: + device->state = usbfront_device_state_i; + usbfront_device_disconnect_all_ports( device ); + usbfront_device_complete_endpoint_disconnect( device ); + break; + default: + usbfront_device_invalid_stimulus( device, stimulus ); + break; + } + default: + usbfront_device_invalid_stimulus( device, stimulus ); + break; + } +} + +static void usbfront_device_invalid_stimulus + ( struct usbfront_device * device, usbfront_device_stimulus stimulus ) +{ + trace(); + + printk + ( + KERN_ERR "usbfront: device %p in state %d" + "received invalid stimulus %d", + device, + device->state, + stimulus + ); +} + +static void usbfront_device_probe_driver( struct usbfront_device * device ) +{ + trace(); + + { + int scheduled = xenidc_work_schedule( &device->probe_driver_1_work ); + + ASSERT( scheduled ); + } +} + +static void usbfront_device_probe_driver_1( void * data ) +{ + trace(); + + { + struct usbfront_device * device = (struct usbfront_device *)data; + + usbfront_device_stimulus stimulus; + + if( usbfront_driver_probe( device ) == 0 ) + { + stimulus = usbfront_device_stimulus_ps; + } + else + { + stimulus = usbfront_device_stimulus_pf; + } + + { + unsigned long flags; + + spin_lock_irqsave( &device->lock, flags ); + + usbfront_device_handle_stimulus( device, stimulus ); + + spin_unlock_irqrestore( &device->lock, flags ); + } + } +} + +static void usbfront_device_remove_driver( struct usbfront_device * device ) +{ + trace(); + + { + int scheduled = xenidc_work_schedule( &device->remove_driver_1_work ); + + ASSERT( scheduled ); + } +} + +static void usbfront_device_remove_driver_1( void * data ) +{ + trace(); + + { + struct usbfront_device * device = (struct usbfront_device *)data; + + usbfront_driver_remove( device ); + + { + unsigned long flags; + + spin_lock_irqsave( &device->lock, flags ); + + usbfront_device_handle_stimulus + ( device, usbfront_device_stimulus_rc ); + + spin_unlock_irqrestore( &device->lock, flags ); + } + } +} + +static void usbfront_device_probe_all_ports( struct usbfront_device * device ) +{ + device->port_probe_count = USBFRONT_DEVICE_PORT_COUNT; + + { + int i; + + for( i = 0; i < USBFRONT_DEVICE_PORT_COUNT; i++ ) + { + struct usbfront_device_probe_transaction * probe = + &device->probe_transaction[ i ]; + + if + ( + ( device->port_status[ i ].wPortStatus & USB_PORT_STAT_RESET ) + != + USB_PORT_STAT_RESET + ) + { + xenidc_transaction_set_parameters_lbr + ( + &probe->transaction, + xenidc_vaddress_create_lbr + ( + &probe->probe.parameters, + sizeof( probe->probe.parameters ) + ) + ); + + xenidc_transaction_set_status_lbr + ( + &probe->transaction, + xenidc_vaddress_create_lbr + ( + &probe->probe.status, + sizeof( probe->probe.status ) + ) + ); + + memset + ( + &probe->probe.parameters, + 0, + sizeof( probe->probe.parameters ) + ); + + probe->probe.parameters.header.transaction_type = + USBIF_TRANSACTION_TYPE_PROBE; + + probe->probe.parameters.port = i + 1; + + memset + ( &probe->probe.status, 0, sizeof( probe->probe.status ) ); + } + else + { + xenidc_transaction_set_parameters_lbr + ( + &probe->transaction, + xenidc_vaddress_create_lbr + ( + &probe->reset.parameters, + sizeof( probe->reset.parameters ) + ) + ); + + xenidc_transaction_set_status_lbr + ( + &probe->transaction, + xenidc_vaddress_create_lbr + ( + &probe->reset.status, + sizeof( probe->reset.status ) + ) + ); + + memset + ( + &probe->reset.parameters, + 0, + sizeof( probe->reset.parameters ) + ); + + probe->reset.parameters.header.transaction_type = + USBIF_TRANSACTION_TYPE_RESET; + + probe->reset.parameters.port = i + 1; + + memset + ( &probe->reset.status, 0, sizeof( probe->reset.status ) ); + } + + xenidc_endpoint_submit_transaction + ( &device->endpoint, &probe->transaction ); + } + } +} + +static void usbfront_device_probe_all_ports_1( xenidc_callback * callback ) +{ + struct usbfront_device_probe_transaction * probe = container_of + ( + xenidc_transaction_callback_to( callback ), + struct usbfront_device_probe_transaction, + transaction + ); + + struct usbfront_device * device = probe->device; + + unsigned long flags; + + spin_lock_irqsave( &device->lock, flags ); + + if + ( + probe->probe.parameters.header.transaction_type + == + USBIF_TRANSACTION_TYPE_PROBE + ) + { + int port_number = probe->probe.parameters.port; + + if( xenidc_callback_query_error( callback ) == XENIDC_ERROR_SUCCESS ) + { + struct usb_port_status * port_status = + &device->port_status[ port_number - 1 ]; + + if + ( + probe->probe.status.result + == + USBIF_PROBE_RESULT_DEVICE_PRESENT + ) + { + /* There is a device attached to the port. */ + + if + ( + ( port_status->wPortStatus & USB_PORT_STAT_CONNECTION ) + != + USB_PORT_STAT_CONNECTION + ) + { + /* There wasn't a device attached to the port before. */ + + port_status->wPortStatus |= USB_PORT_STAT_CONNECTION; + port_status->wPortChange |= USB_PORT_STAT_C_CONNECTION; + } + } + else if + ( probe->probe.status.result == USBIF_PROBE_RESULT_NO_DEVICE ) + { + /* There isn't a device attached to the port. */ + + if + ( + ( port_status->wPortStatus & USB_PORT_STAT_CONNECTION ) + == + USB_PORT_STAT_CONNECTION + ) + { + /* There was a device attached to the port before. */ + + port_status->wPortStatus &= ~USB_PORT_STAT_CONNECTION; + port_status->wPortChange |= USB_PORT_STAT_C_CONNECTION; + } + } + else + { + trace3 + ( + "device %p: unexpected result %d probing port %d", + device, + (int)probe->probe.status.result, + port_number + ); + } + } + else + { + trace3 + ( + "device %p: error %d probing port %d", + device, + usbif_error_map_to_local + ( xenidc_callback_query_error( callback ) ), + port_number + ); + } + } + else + { + int port_number = probe->reset.parameters.port; + + struct usb_port_status * port_status = + &device->port_status[ port_number - 1 ]; + + if + ( + ( xenidc_callback_query_error( callback ) == XENIDC_ERROR_SUCCESS ) + && + ( + ( probe->reset.status.result == USBIF_RESET_RESULT_FULL_SPEED ) + || + ( probe->reset.status.result == USBIF_RESET_RESULT_LOW_SPEED ) + || + ( probe->reset.status.result == USBIF_RESET_RESULT_HIGH_SPEED ) + ) + ) + { + if( probe->reset.status.result == USBIF_RESET_RESULT_LOW_SPEED ) + { + port_status->wPortStatus |= USB_PORT_STAT_LOW_SPEED; + port_status->wPortStatus &= ~USB_PORT_STAT_HIGH_SPEED; + } + else if + ( probe->reset.status.result == USBIF_RESET_RESULT_HIGH_SPEED ) + { + port_status->wPortStatus &= ~USB_PORT_STAT_LOW_SPEED; + port_status->wPortStatus |= USB_PORT_STAT_HIGH_SPEED; + } + else + { + port_status->wPortStatus &= ~USB_PORT_STAT_LOW_SPEED; + port_status->wPortStatus &= ~USB_PORT_STAT_HIGH_SPEED; + } + + port_status->wPortStatus &= ~USB_PORT_STAT_RESET; + port_status->wPortStatus |= USB_PORT_STAT_ENABLE; + port_status->wPortChange |= USB_PORT_STAT_C_RESET; + } + else + { + if + ( + xenidc_callback_query_error( callback ) + != + XENIDC_ERROR_SUCCESS + ) + { + printk + ( + KERN_ERR "usbfront: device %p: error %d resetting port %d", + device, + usbif_error_map_to_local + ( xenidc_callback_query_error( callback ) ), + port_number + ); + } + else + { + trace3 + ( + "device %p: unexpected result %d resetting port %d", + device, + (int)probe->reset.status.result, + port_number + ); + } + + port_status->wPortStatus &= ~USB_PORT_STAT_LOW_SPEED; + port_status->wPortStatus &= ~USB_PORT_STAT_HIGH_SPEED; + + port_status->wPortStatus &= ~USB_PORT_STAT_RESET; + port_status->wPortChange |= USB_PORT_STAT_C_RESET; + } + } + + if( --device->port_probe_count == 0 ) + { + usbfront_device_handle_stimulus( device, usbfront_device_stimulus_pc ); + } + + spin_unlock_irqrestore( &device->lock, flags ); +} + +static void usbfront_device_disconnect_all_ports + ( struct usbfront_device * device ) +{ + trace(); + + { + int i; + + for( i = 0; i < USBFRONT_DEVICE_PORT_COUNT; i++ ) + { + struct usb_port_status * port_status = &device->port_status[ i ]; + + if + ( + ( port_status->wPortStatus & USB_PORT_STAT_CONNECTION ) + == + USB_PORT_STAT_CONNECTION + ) + { + /* There was a device attached to the port before. */ + + port_status->wPortStatus &= ~USB_PORT_STAT_CONNECTION; + port_status->wPortChange |= USB_PORT_STAT_C_CONNECTION; + } + } + } +} + +static void usbfront_device_complete_endpoint_disconnect + ( struct usbfront_device * device ) +{ + trace(); + + xenidc_callback_success( device->endpoint_disconnect_callback ); +} diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,82 @@ +/*****************************************************************************/ +/* usbfront_device is a device which represents a connection to a back-end. */ +/* The intent was for it to have an interface like a hardware USB host */ +/* controller device. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBFRONT_DEVICE_H +#define USBFRONT_DEVICE_H + +#include +#include +#include "../../usb/core/hcd.h" +#include + +extern int usbfront_device_class_init( void ); + +extern void usbfront_device_class_exit( void ); + +struct usbfront_device; + +void usbfront_device_set_drvdata + ( struct usbfront_device * device, void * data ); + +void * usbfront_device_get_drvdata( struct usbfront_device * device ); + +struct device * usbfront_device_to_dev + ( struct usbfront_device * device ); + +struct usbfront_device * usbfront_device_dev_to( struct device * dev ); + +int usbfront_device_query_port_count( struct usbfront_device * device ); + +int usbfront_device_query_port_status_changed + ( struct usbfront_device * device, int port_number ); + +struct usb_port_status usbfront_device_query_port_status + ( struct usbfront_device * device, int port_number ); + +/* Used to turn on power to a port. */ +void usbfront_device_set_port_power + ( struct usbfront_device * device, int port_number ); + +/* Used to reset a port. Completes asynchronously with notification via the */ +/* port status. */ +void usbfront_device_set_port_reset + ( struct usbfront_device * device, int port_number ); + +void usbfront_device_clear_port_enable + ( struct usbfront_device * device, int port_number ); + +/* Used to ack a connection change */ +void usbfront_device_clear_port_connection_change + ( struct usbfront_device * device, int port_number ); + +/* Used to ack a reset change */ +void usbfront_device_clear_port_reset_change + ( struct usbfront_device * device, int port_number ); + +void usbfront_device_submit_message + ( struct usbfront_device * device, xenidc_message * message ); + +void usbfront_device_submit_transaction + ( struct usbfront_device * device, xenidc_transaction * transaction ); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,880 @@ +/*****************************************************************************/ +/* A device driver for usbfront_device devices. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Based on */ +/* */ +/* arch/xen/drivers/usbif/frontend/main.c */ +/* pristine-linux-2.6.11/drivers/usb/host/uhci-hcd.c */ +/* pristine-linux-2.6.11/drivers/usb/core/hcd-pci.c */ +/* */ +/* original copyright notices follow... */ +/*****************************************************************************/ + +/* + * Xen Virtual USB Frontend Driver + * + * This file contains the first version of the Xen virtual USB hub + * that I've managed not to delete by mistake (3rd time lucky!). + * + * Based on Linux's uhci.c, original copyright notices are displayed + * below. Portions also (c) 2004 Intel Research Cambridge + * and (c) 2004, 2005 Mark Williamson + * + * Contact or + * 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 + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx + * (C) Copyright 1999 Randy Dunlap + * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx + * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx + * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx + * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx + * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface + * support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx). + * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) + * + * Intel documents this fairly well, and as far as I know there + * are no royalties or anything like that, but even so there are + * people who decided that they want to do the same thing in a + * completely different way. + * + * WARNING! The USB documentation is downright evil. Most of it + * is just crap, written by a committee. You're better off ignoring + * most of it, the important stuff is: + * - the low-level protocol (fairly simple but lots of small details) + * - working around the horridness of the rest + */ + +/* + * Universal Host Controller Interface driver for USB. + * + * Maintainer: Alan Stern + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx + * (C) Copyright 1999 Randy Dunlap + * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx + * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx + * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx + * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx + * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface + * support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx). + * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) + * (C) Copyright 2004 Alan Stern, stern@xxxxxxxxxxxxxxxxxxx + * + * Intel documents this fairly well, and as far as I know there + * are no royalties or anything like that, but even so there are + * people who decided that they want to do the same thing in a + * completely different way. + * + * WARNING! The USB documentation is downright evil. Most of it + * is just crap, written by a committee. You're better off ignoring + * most of it, the important stuff is: + * - the low-level protocol (fairly simple but lots of small details) + * - working around the horridness of the rest + */ + +/* + * (C) Copyright David Brownell 2000-2002 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "usbfront_driver.h" +#include "usbfront_hcd_resource.h" +#include "usbfront_sll.h" +#include "usbfront_trace.h" + +typedef enum +{ + usbfront_hcd_state_i +} +usbfront_hcd_state; + +typedef enum +{ + usbfront_hcd_stimulus_uq /* urb enqueue */ +} +usbfront_hcd_stimulus; + +#define USBFRONT_HCD_RESOURCE_COUNT 16 + +struct usbfront_hcd +{ + spinlock_t lock; + usbfront_hcd_state state; + struct usbfront_sll urb_sll; + struct list_head free_resource_list; + struct usbfront_hcd_resource resources[ USBFRONT_HCD_RESOURCE_COUNT ]; +}; + +static void usbfront_hcd_handle_stimulus + ( struct usbfront_hcd * uhcd, usbfront_hcd_stimulus stimulus ); + +static struct usbfront_hcd * usbfront_hcd_hcd_to_uhcd( struct usb_hcd * hcd ) +{ + return (struct usbfront_hcd *)( hcd->hcd_priv ); +} + +static struct usbfront_device * + usbfront_hcd_hcd_to_usbfront_device( struct usb_hcd * hcd ) +{ + return usbfront_device_dev_to( hcd_to_bus( hcd )->controller ); +} + +void usbfront_hcd_resource_completed( xenidc_callback * callback ); + +static int usbfront_hcd_start( struct usb_hcd * hcd ) +{ + trace(); + + { + int return_value = 0; + + struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd( hcd ); + + memset( uhcd, 0, sizeof( *uhcd ) ); + + spin_lock_init( &uhcd->lock ); + + uhcd->state = usbfront_hcd_state_i; + + usbfront_sll_init( &uhcd->urb_sll ); + + INIT_LIST_HEAD( &uhcd->free_resource_list ); + + { + int i; + + for( i = 0; i < USBFRONT_HCD_RESOURCE_COUNT; i++ ) + { + struct usbfront_hcd_resource * resource = + &uhcd->resources[ i ]; + + return_value = usbfront_hcd_resource_init + ( + resource, + usbfront_hcd_hcd_to_usbfront_device( hcd ), + i, + usbfront_hcd_resource_completed + ); + + if( return_value != 0 ) + { + goto EXIT_NO_RESOURCE; + } + + list_add + ( + usbfront_hcd_resource_to_link( resource ), + &uhcd->free_resource_list + ); + } + } + + { + struct usb_device * root_hub_device = + usb_alloc_dev( NULL, &hcd->self, 0 ); + + if( root_hub_device == NULL ) + { + return_value = -ENOMEM; + + goto EXIT_NO_ROOT_HUB; + } + + root_hub_device->speed = USB_SPEED_HIGH; + + if + ( + ( + return_value = + usb_hcd_register_root_hub( root_hub_device, hcd ) + ) + != + 0 + ) + { + goto EXIT_NO_REGISTER; + } + + return 0; + + EXIT_NO_REGISTER: + + usb_put_dev( root_hub_device ); + } + + EXIT_NO_ROOT_HUB: + + EXIT_NO_RESOURCE: + + while( !list_empty( &uhcd->free_resource_list ) ) + { + struct usbfront_hcd_resource * resource = list_entry + ( + uhcd->free_resource_list.next, + struct usbfront_hcd_resource, + USBFRONT_HCD_RESOURCE_LINK + ); + + list_del_init( usbfront_hcd_resource_to_link( resource ) ); + + usbfront_hcd_resource_exit( resource ); + } + + return return_value; + } +} + +static void usbfront_hcd_stop( struct usb_hcd * hcd ) +{ + trace(); + + { + struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd( hcd ); + + while( !list_empty( &uhcd->free_resource_list ) ) + { + struct usbfront_hcd_resource * resource = list_entry + ( + uhcd->free_resource_list.next, + struct usbfront_hcd_resource, + USBFRONT_HCD_RESOURCE_LINK + ); + + list_del_init( usbfront_hcd_resource_to_link( resource ) ); + + usbfront_hcd_resource_exit( resource ); + } + } +} + +static int usbfront_hcd_get_frame_number( struct usb_hcd * hcd ) +{ + trace(); + + return 0; +} + +static inline void usbfront_check_contiguous + ( unsigned long buffer, unsigned long length ) +{ + if( length != 0 ) + { + unsigned long offset; + + for + ( + offset = 0; + offset < ( length + ( buffer & ~PAGE_MASK ) ); + offset += PAGE_SIZE + ) + { + unsigned long maddress1 = + virt_to_machine( ( buffer & PAGE_MASK ) + offset ); + + unsigned long maddress2 = + virt_to_machine( buffer & PAGE_MASK ) + offset; + + ASSERT( maddress1 == maddress2 ); + } + } +} + +static int usbfront_hcd_urb_enqueue +( + struct usb_hcd * hcd, + struct usb_host_endpoint * ep, /* FIXME: what's the intended use for ep? */ + struct urb * urb, + int mem_flags +) +{ + trace(); + + usbfront_check_contiguous + ( (unsigned long)urb->transfer_buffer, urb->transfer_buffer_length ); + + { + struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd( hcd ); + + unsigned long flags; + + spin_lock_irqsave( &uhcd->lock, flags ); + + usbfront_slk_init( (struct usbfront_slk *)&urb->hcpriv ); + + usbfront_sll_add_last + ( &uhcd->urb_sll, (struct usbfront_slk *)&urb->hcpriv ); + + usbfront_hcd_handle_stimulus( uhcd, usbfront_hcd_stimulus_uq ); + + spin_unlock_irqrestore( &uhcd->lock, flags ); + } + + return 0; +} + +static int usbfront_hcd_urb_dequeue( struct usb_hcd * hcd, struct urb * urb ) +{ + trace(); + + { + int dequeued; + + { + struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd( hcd ); + + unsigned long flags; + + spin_lock_irqsave( &uhcd->lock, flags ); + + dequeued = usbfront_sll_remove_slk + ( &uhcd->urb_sll, (struct usbfront_slk *)&urb->hcpriv ); + + spin_unlock_irqrestore( &uhcd->lock, flags ); + } + + if( dequeued ) + { + urb->hcpriv = 0; + + urb->actual_length = 0; + + { + unsigned long flags; + + local_irq_save( flags ); + + usb_hcd_giveback_urb( hcd, urb, 0 ); + + local_irq_restore( flags ); + } + } + else + { + usbfront_hcd_resource_dequeue_urb( urb ); + } + } + + return 0; +} + +static void usbfront_hcd_endpoint_disable + ( struct usb_hcd * hcd, struct usb_host_endpoint * ep ) +{ + trace(); +} + +static int usbfront_hcd_hub_status_data( struct usb_hcd * hcd, char * buf ) +{ + int changed = 0; + + struct usbfront_device * device = + usbfront_hcd_hcd_to_usbfront_device( hcd ); + + int port_count = usbfront_device_query_port_count( device ); + + int byte_count = + ( 1 /* hub */ + port_count /* ports */ + 7 /* round up */ ) / 8; + + memset( buf, 0, byte_count ); + + { + int i; + + for( i = 0; i < port_count; i++ ) + { + if( usbfront_device_query_port_status_changed( device, i ) ) + { + buf[ ( i + 1 ) / 8 ] |= 1 << ( ( i + 1 ) % 8 ); + + changed = 1; + } + } + } + + return changed ? byte_count : 0; +} + +static int usbfront_hcd_hub_control +( + struct usb_hcd * hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char * buf, + u16 wLength +) +{ + trace(); + + { + struct usbfront_device * device = + usbfront_hcd_hcd_to_usbfront_device( hcd ); + + int return_value = 0; + + switch( typeReq ) + { + case GetHubStatus: + + trace0( "GetHubStatus" ); + + if( ( wValue != 0 ) || ( wIndex != 0 ) || ( wLength != 4 ) ) + { + goto ERROR; + } + + /* 2 bytes wHubStatus and 2 bytes wHubChange: */ + /* Local power supply good, no overcurrect condition */ + /* No changes. */ + + memset( buf, 0, wLength ); + + break; + + case GetPortStatus: + + trace0( "GetPortStatus" ); + + if + ( + ( wValue != 0 ) + || + ( wIndex > usbfront_device_query_port_count( device ) ) + || + ( wLength != 4 ) + ) + { + goto ERROR; + } + + { + struct usb_port_status port_status = + usbfront_device_query_port_status( device, wIndex - 1 ); + + memcpy( buf, &port_status, wLength ); + } + + break; + + case GetHubDescriptor: + + trace0( "GetHubDescriptor" ); + + { + /* bDescLength */ + /* bDescriptorType */ + /* bNbrPorts */ + /* wHubCharacteristics LSB */ + /* wHubCharacteristics MSB */ + /* bPwrOn2PwrGood */ + /* bHubContrCurrent */ + /* DeviceRemovable */ + /* PortPwrCtrlMask */ + + /* See table 11.23.2.1 of the USB 2.0 specification. */ + + char descriptor[] = + { 0x09, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xFF }; + + descriptor[ 2 ] = usbfront_device_query_port_count( device ); + + memcpy + ( + buf, + &descriptor, + min_t( size_t, sizeof( descriptor ), wLength ) + ); + } + + break; + + case SetPortFeature: + + trace0( "SetPortFeature" ); + + if + ( + ( + ( wIndex & 0x00FF ) + > + usbfront_device_query_port_count( device ) + ) + || + ( wLength != 0 ) + ) + { + goto ERROR; + } + + switch( wValue ) + { + case USB_PORT_FEAT_SUSPEND: + trace0( "USB_PORT_FEAT_SUSPEND" ); + break; + case USB_PORT_FEAT_RESET: + trace0( "USB_PORT_FEAT_RESET" ); + usbfront_device_set_port_reset( device, wIndex - 1 ); + break; + case USB_PORT_FEAT_POWER: + trace0( "USB_PORT_FEAT_POWER" ); + usbfront_device_set_port_power( device, wIndex - 1 ); + break; + default: + trace1( "Unknown:%x", wValue ); + goto ERROR; + } + + break; + + case ClearPortFeature: + + trace0( "ClearPortFeature" ); + + if + ( + ( + ( wIndex & 0x00FF ) + > + usbfront_device_query_port_count( device ) + ) + || + ( wLength != 0 ) + ) + { + goto ERROR; + } + + switch( wValue ) + { + case USB_PORT_FEAT_ENABLE: + trace0( "USB_PORT_FEAT_ENABLE" ); + usbfront_device_clear_port_enable( device, wIndex - 1 ); + break; + case USB_PORT_FEAT_SUSPEND: + trace0( "USB_PORT_FEAT_SUSPEND" ); + break; + case USB_PORT_FEAT_POWER: + trace0( "USB_PORT_FEAT_POWER" ); + break; + case USB_PORT_FEAT_INDICATOR: + trace0( "USB_PORT_FEAT_INDICATOR" ); + break; + case USB_PORT_FEAT_C_CONNECTION: + trace0( "USB_PORT_C_CONNECTION" ); + usbfront_device_clear_port_connection_change + ( device, wIndex - 1 ); + break; + case USB_PORT_FEAT_C_RESET: + trace0( "USB_PORT_C_RESET" ); + usbfront_device_clear_port_reset_change( device, wIndex - 1 ); + break; + case USB_PORT_FEAT_C_ENABLE: + trace0( "USB_PORT_C_ENABLE" ); + break; + case USB_PORT_FEAT_C_SUSPEND: + trace0( "USB_PORT_C_SUSPEND" ); + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + trace0( "USB_PORT_C_OVER_CURRENT" ); + break; + default: + trace1( "Unknown:%x", wValue ); + goto ERROR; + } + + break; + + default: + trace1( "Unknown:%x", typeReq ); + ERROR: + return_value = -EPIPE; + } + + return return_value; + } +} + +static int usbfront_hcd_start_port_reset + ( struct usb_hcd * hcd, unsigned port_num ) +{ + trace(); + + return 0; +} + +static struct hc_driver usbfront_hc_driver = +{ + .description = "usbfront_hc_driver", + .product_desc = "Xen USB Front-End Driver", + .hcd_priv_size = sizeof( struct usbfront_hcd ), + /* .irq */ + .flags = HCD_USB2, + /* reset optional. */ + .start = usbfront_hcd_start, + /* suspend optional. */ + /* resume optional. */ + .stop = usbfront_hcd_stop, + .get_frame_number = usbfront_hcd_get_frame_number, + .urb_enqueue = usbfront_hcd_urb_enqueue, + .urb_dequeue = usbfront_hcd_urb_dequeue, + .endpoint_disable = usbfront_hcd_endpoint_disable, + .hub_status_data = usbfront_hcd_hub_status_data, + .hub_control = usbfront_hcd_hub_control, + /* hub_suspend optional. */ + /* hub_resume optional. */ + .start_port_reset = usbfront_hcd_start_port_reset, +}; + +static void usbfront_hcd_invalid_stimulus + ( struct usbfront_hcd * uhcd, usbfront_hcd_stimulus stimulus ); + +static void usbfront_hcd_kick_urbs( struct usbfront_hcd * uhcd ); + +static void usbfront_hcd_handle_stimulus + ( struct usbfront_hcd * uhcd, usbfront_hcd_stimulus stimulus ) +{ + trace3 + ( + "uhcd %p in state %d received stimulus %d", + uhcd, + uhcd->state, + stimulus + ); + + switch( uhcd->state ) + { + case usbfront_hcd_state_i: + switch( stimulus ) + { + case usbfront_hcd_stimulus_uq: + usbfront_hcd_kick_urbs( uhcd ); + break; + } + break; + default: + usbfront_hcd_invalid_stimulus( uhcd, stimulus ); + break; + } +} + +static void usbfront_hcd_invalid_stimulus + ( struct usbfront_hcd * uhcd, usbfront_hcd_stimulus stimulus ) +{ + trace(); + + printk + ( + KERN_ERR "usbfront: hc_driver_uhcd %p in state %d" + "received invalid stimulus %d", + uhcd, + uhcd->state, + stimulus + ); +} + +static void usbfront_hcd_kick_urbs( struct usbfront_hcd * uhcd ) +{ + trace(); + + while + ( + !usbfront_sll_is_empty( &uhcd->urb_sll ) + && + !list_empty( &uhcd->free_resource_list ) + ) + { + trace0( "Starting URB" ); + + { + struct urb * urb = container_of + ( + (void **)usbfront_sll_remove_first( &uhcd->urb_sll ), + struct urb, + hcpriv + ); + + struct usbfront_hcd_resource * resource = list_entry + ( + uhcd->free_resource_list.next, + struct usbfront_hcd_resource, + USBFRONT_HCD_RESOURCE_LINK + ); + + list_del_init( usbfront_hcd_resource_to_link( resource ) ); + + usbfront_hcd_resource_start_urb( resource, urb ); + } + } +} + +void usbfront_hcd_resource_completed( xenidc_callback * callback ) +{ + trace(); + + { + struct usbfront_hcd_resource * resource = + usbfront_hcd_resource_callback_to( callback ); + + struct usbfront_hcd * uhcd = usbfront_hcd_hcd_to_uhcd + ( + usbfront_device_get_drvdata + ( usbfront_hcd_resource_query_device( resource ) ) + ); + + unsigned long flags; + + spin_lock_irqsave( &uhcd->lock, flags ); + + list_add + ( + usbfront_hcd_resource_to_link( resource ), + &uhcd->free_resource_list + ); + + usbfront_hcd_kick_urbs( uhcd ); + + spin_unlock_irqrestore( &uhcd->lock, flags ); + } +} + +static int usbfront_driver_probe_or_remove + ( struct usbfront_device * device, int remove ) +{ + trace(); + + { + int return_value = 0; + + struct usb_hcd * hcd; + + if( remove ) + { + goto REMOVE; + } + + if( usb_disabled() ) + { + return_value = -ENODEV; + + goto REMOVE_0; + } + + if + ( + ( + hcd = usb_create_hcd + ( + &usbfront_hc_driver, + usbfront_device_to_dev( device ), + usbfront_device_to_dev( device )->bus_id + ) + ) + == + NULL + ) + { + return_value = -ENOMEM; + + goto REMOVE_0; + } + + usbfront_device_set_drvdata( device, hcd ); + + if( ( return_value = usb_add_hcd( hcd, 0, 0 ) ) != 0 ) + { + goto REMOVE_1; + } + + return 0; + + REMOVE: + + hcd = usbfront_device_get_drvdata( device ); + + usb_remove_hcd( hcd ); + + REMOVE_1: + + usb_put_hcd( hcd ); + + usbfront_device_set_drvdata( device, NULL ); + + REMOVE_0: + + return return_value; + } +} + +int usbfront_driver_probe( struct usbfront_device * device ) +{ + trace(); + + return usbfront_driver_probe_or_remove( device, 0 ); +} + +void usbfront_driver_remove( struct usbfront_device * device ) +{ + trace(); + + usbfront_driver_probe_or_remove( device, 1 ); +} + +int usbfront_driver_class_init( void ) +{ + trace(); + + return usbfront_hcd_resource_class_init(); +} + +void usbfront_driver_class_exit( void ) +{ + trace(); + + usbfront_hcd_resource_class_exit(); +} diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,35 @@ +/*****************************************************************************/ +/* A device driver for usbfront_device devices. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBFRONT_DRIVER_H +#define USBFRONT_DRIVER_H + +#include "usbfront_device.h" + +extern int usbfront_driver_class_init( void ); + +extern void usbfront_driver_class_exit( void ); + +extern int usbfront_driver_probe( struct usbfront_device * device ); + +extern void usbfront_driver_remove( struct usbfront_device * device ); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,942 @@ +/*****************************************************************************/ +/* A resource used by the usbfront host controller device driver to process */ +/* an URB by translating the URB and optional unlink request into */ +/* a transaction and corresponding optional unlink message for submission to */ +/* the back end. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Based on arch/xen/drivers/usbif/frontend/main.c, original copyright */ +/* notice follows... */ +/*****************************************************************************/ + +/* + * Xen Virtual USB Frontend Driver + * + * This file contains the first version of the Xen virtual USB hub + * that I've managed not to delete by mistake (3rd time lucky!). + * + * Based on Linux's uhci.c, original copyright notices are displayed + * below. Portions also (c) 2004 Intel Research Cambridge + * and (c) 2004, 2005 Mark Williamson + * + * Contact or + * 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 + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx + * (C) Copyright 1999 Randy Dunlap + * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx + * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx + * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx + * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx + * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface + * support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx). + * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) + * + * Intel documents this fairly well, and as far as I know there + * are no royalties or anything like that, but even so there are + * people who decided that they want to do the same thing in a + * completely different way. + * + * WARNING! The USB documentation is downright evil. Most of it + * is just crap, written by a committee. You're better off ignoring + * most of it, the important stuff is: + * - the low-level protocol (fairly simple but lots of small details) + * - working around the horridness of the rest + */ + +/* FIXME is URB serialisation maintained correctly? */ + +#include +#include "usbfront_assert.h" +#include "usbfront_driver.h" +#include "usbfront_hcd_resource.h" +#include "usbfront_trace.h" + +xenidc_rbr_provider_pool * usbfront_hcd_resource_rbr_provider_pool; + +int usbfront_hcd_resource_class_init( void ) +{ + trace(); + + usbfront_hcd_resource_rbr_provider_pool = + xenidc_allocate_rbr_provider_pool( USBIF_MAX_PAGES_PER_REQUEST ); + + return ( usbfront_hcd_resource_rbr_provider_pool != NULL ) ? 0 : -ENOMEM; +} + +void usbfront_hcd_resource_class_exit( void ) +{ + trace(); + + xenidc_free_rbr_provider_pool( usbfront_hcd_resource_rbr_provider_pool ); +} + +typedef enum +{ + usbfront_hcd_resource_stimulus_st, /* Start URB */ + usbfront_hcd_resource_stimulus_dq, /* Dequeue URB */ + usbfront_hcd_resource_stimulus_cs, /* Create RBRs success */ + usbfront_hcd_resource_stimulus_cf, /* Create RBRs failure */ + usbfront_hcd_resource_stimulus_tc, /* Transaction complete */ + usbfront_hcd_resource_stimulus_rc, /* Revoke RBRs complete */ + usbfront_hcd_resource_stimulus_uc, /* Unlink complete */ +} +usbfront_hcd_resource_stimulus; + +static void usbfront_hcd_resource_handle_stimulus +( + struct usbfront_hcd_resource * resource, + usbfront_hcd_resource_stimulus stimulus +); + +static void usbfront_hcd_resource_create_rbrs_1( xenidc_callback * callback ); + +static void usbfront_hcd_resource_submit_transaction_1 + ( xenidc_callback * callback ); + +static void usbfront_hcd_resource_revoke_rbrs_1 + ( xenidc_callback * callback ); + +static void usbfront_hcd_resource_submit_unlink_1 + ( xenidc_callback * callback ); + +static void usbfront_hcd_resource_complete_1( void * context ); + +static int usbfront_hcd_resource_init_or_exit +( + struct usbfront_hcd_resource * resource, + struct usbfront_device * device, + int index, + xenidc_callback_function * callback, + int exit +) +{ + trace(); + + { + int return_value = 0; + + if( exit ) + { + goto EXIT; + } + + xenidc_callback_init( &resource->callback, callback ); + + resource->device = device; + + resource->index = index; + + resource->schedule = (usbif_isochronous_io_schedule_element *) + __get_free_page( GFP_KERNEL ); + + if( resource->schedule == NULL ) + { + return_value = -ENOMEM; + + goto EXIT_NO_SCHEDULE; + } + + spin_lock_init( &resource->lock ); + + resource->state = usbfront_hcd_resource_state_i; + + xenidc_create_rbr_request_element_init + ( &resource->rbr_request_element[ 0 ] ); + + xenidc_create_rbr_request_element_init + ( &resource->rbr_request_element[ 1 ] ); + + xenidc_reserve_and_create_rbr_request_init + ( + &resource->rbr_request, + usbfront_hcd_resource_create_rbrs_1, + usbfront_hcd_resource_revoke_rbrs_1 + ); + + xenidc_transaction_init + ( + &resource->io_transaction, + usbfront_hcd_resource_submit_transaction_1 + ); + + xenidc_transaction_set_parameters_lbr + ( + &resource->io_transaction, + xenidc_vaddress_create_lbr + ( + &resource->io_parameters, + sizeof( resource->io_parameters ) + ) + ); + + xenidc_transaction_set_status_lbr + ( + &resource->io_transaction, + xenidc_vaddress_create_lbr + ( + &resource->io_status, + sizeof( resource->io_status ) + ) + ); + + xenidc_message_init + ( &resource->unlink_message, usbfront_hcd_resource_submit_unlink_1 ); + + xenidc_message_set_message_lbr + ( + &resource->unlink_message, + xenidc_vaddress_create_lbr + ( + &resource->unlink_message_body, + sizeof( resource->unlink_message_body ) + ) + ); + + xenidc_work_init + ( + &resource->complete_1_work, + usbfront_hcd_resource_complete_1, + resource + ); + + return 0; + + EXIT: + + free_page( (unsigned long)resource->schedule ); + + EXIT_NO_SCHEDULE: + + return return_value; + } +} + +int usbfront_hcd_resource_init +( + struct usbfront_hcd_resource * resource, + struct usbfront_device * device, + int index, + xenidc_callback_function * callback +) +{ + trace(); + + return usbfront_hcd_resource_init_or_exit + ( resource, device, index, callback, 0 ); +} + +void usbfront_hcd_resource_exit( struct usbfront_hcd_resource * resource ) +{ + trace(); + + usbfront_hcd_resource_init_or_exit( resource, NULL, 0, NULL, 1 ); +} + +void usbfront_hcd_resource_start_urb + ( struct usbfront_hcd_resource * resource, struct urb * urb ) +{ + trace(); + + urb->hcpriv = resource; + + { + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + resource->urb = urb; + + usbfront_hcd_resource_handle_stimulus + ( resource, usbfront_hcd_resource_stimulus_st ); + + spin_unlock_irqrestore( &resource->lock, flags ); + } +} + +static DEFINE_RWLOCK( dequeue_lock ); + +void usbfront_hcd_resource_dequeue_urb( struct urb * urb ) +{ + trace(); + + { + unsigned long flags; + + write_lock_irqsave( &dequeue_lock, flags ); + + if( urb->hcpriv != NULL ) + { + struct usbfront_hcd_resource * resource = + (struct usbfront_hcd_resource *)urb->hcpriv; + + unsigned long flags2; + + spin_lock_irqsave( &resource->lock, flags2 ); + + usbfront_hcd_resource_handle_stimulus + ( resource, usbfront_hcd_resource_stimulus_dq ); + + spin_unlock_irqrestore( &resource->lock, flags2 ); + } + + write_unlock_irqrestore( &dequeue_lock, flags ); + } +} + +static void usbfront_hcd_resource_invalid_stimulus +( + struct usbfront_hcd_resource * resource, + usbfront_hcd_resource_stimulus stimulus +); + +static void usbfront_hcd_resource_create_rbrs + ( struct usbfront_hcd_resource * resource ); + +static void usbfront_hcd_resource_abort_create_rbrs + ( struct usbfront_hcd_resource * resource ); + +static void usbfront_hcd_resource_set_aborted_error + ( struct usbfront_hcd_resource * resource ); + +static void usbfront_hcd_resource_submit_transaction + ( struct usbfront_hcd_resource * resource ); + +static void usbfront_hcd_resource_revoke_rbrs + ( struct usbfront_hcd_resource * resource ); + +static void usbfront_hcd_resource_submit_unlink + ( struct usbfront_hcd_resource * resource ); + +static void usbfront_hcd_resource_complete + ( struct usbfront_hcd_resource * resource ); + +static void usbfront_hcd_resource_handle_stimulus +( + struct usbfront_hcd_resource * resource, + usbfront_hcd_resource_stimulus stimulus +) +{ + trace(); + + switch( resource->state ) + { + case usbfront_hcd_resource_state_i: + /* Initialised. */ + /* Maybe completing previous URB. */ + switch( stimulus ) + { + case usbfront_hcd_resource_stimulus_st: + resource->state = usbfront_hcd_resource_state_i_st; + usbfront_hcd_resource_create_rbrs( resource ); + break; + /* A dequeue is possible whilst we are making the complete */ + /* response after we have transitioned back to the i state. */ + case usbfront_hcd_resource_stimulus_dq: + break; + default: + usbfront_hcd_resource_invalid_stimulus( resource, stimulus ); + break; + } + break; + case usbfront_hcd_resource_state_i_st: + /* Creating RBRs. */ + switch( stimulus ) + { + case usbfront_hcd_resource_stimulus_dq: + resource->state = usbfront_hcd_resource_state_i_st_dq; + usbfront_hcd_resource_abort_create_rbrs( resource ); + break; + case usbfront_hcd_resource_stimulus_cs: + resource->state = usbfront_hcd_resource_state_i_st_cs; + usbfront_hcd_resource_submit_transaction( resource ); + break; + case usbfront_hcd_resource_stimulus_cf: + resource->state = usbfront_hcd_resource_state_i; + usbfront_hcd_resource_complete( resource ); + break; + default: + usbfront_hcd_resource_invalid_stimulus( resource, stimulus ); + break; + } + break; + case usbfront_hcd_resource_state_i_st_dq: + /* Creating RBRs. */ + /* Dequeue URB. */ + switch( stimulus ) + { + case usbfront_hcd_resource_stimulus_dq: + break; + case usbfront_hcd_resource_stimulus_cs: + resource->state = usbfront_hcd_resource_state_i_st_dq_cs; + usbfront_hcd_resource_set_aborted_error( resource ); + usbfront_hcd_resource_revoke_rbrs( resource ); + break; + case usbfront_hcd_resource_stimulus_cf: + resource->state = usbfront_hcd_resource_state_i; + usbfront_hcd_resource_complete( resource ); + break; + default: + usbfront_hcd_resource_invalid_stimulus( resource, stimulus ); + break; + } + break; + case usbfront_hcd_resource_state_i_st_cs: + /* Transaction submitted. */ + switch( stimulus ) + { + case usbfront_hcd_resource_stimulus_dq: + resource->state = usbfront_hcd_resource_state_i_st_cs_dq; + usbfront_hcd_resource_submit_unlink( resource ); + break; + case usbfront_hcd_resource_stimulus_tc: + resource->state = usbfront_hcd_resource_state_i_st_dq_cs; + usbfront_hcd_resource_revoke_rbrs( resource ); + break; + default: + usbfront_hcd_resource_invalid_stimulus( resource, stimulus ); + break; + } + break; + case usbfront_hcd_resource_state_i_st_dq_cs: + /* Revoking RBRs. */ + /* Maybe Dequeue URB. */ + switch( stimulus ) + { + case usbfront_hcd_resource_stimulus_dq: + break; + case usbfront_hcd_resource_stimulus_rc: + resource->state = usbfront_hcd_resource_state_i; + usbfront_hcd_resource_complete( resource ); + break; + default: + usbfront_hcd_resource_invalid_stimulus( resource, stimulus ); + break; + } + break; + case usbfront_hcd_resource_state_i_st_cs_dq: + /* Transaction submitted. */ + /* Unlink submitted. */ + /* Dequeue URB. */ + switch( stimulus ) + { + case usbfront_hcd_resource_stimulus_dq: + break; + case usbfront_hcd_resource_stimulus_tc: + case usbfront_hcd_resource_stimulus_uc: + resource->state = usbfront_hcd_resource_state_i_st_cs_dq_tc; + break; + default: + usbfront_hcd_resource_invalid_stimulus( resource, stimulus ); + break; + } + break; + case usbfront_hcd_resource_state_i_st_cs_dq_tc: + /* Transaction submitted or Unlink submitted. */ + /* Dequeue URB. */ + switch( stimulus ) + { + case usbfront_hcd_resource_stimulus_dq: + break; + case usbfront_hcd_resource_stimulus_tc: + case usbfront_hcd_resource_stimulus_uc: + resource->state = usbfront_hcd_resource_state_i_st_dq_cs; + usbfront_hcd_resource_revoke_rbrs( resource ); + break; + default: + usbfront_hcd_resource_invalid_stimulus( resource, stimulus ); + break; + } + break; + default: + usbfront_hcd_resource_invalid_stimulus( resource, stimulus ); + break; + } +} + +static void usbfront_hcd_resource_invalid_stimulus +( + struct usbfront_hcd_resource * resource, + usbfront_hcd_resource_stimulus stimulus +) +{ + trace(); + + printk + ( + KERN_ERR "usbfront: hcd resource %p in state %d" + "received invalid stimulus %d", + resource, + resource->state, + stimulus + ); +} + +static void usbfront_hcd_resource_create_rbrs + ( struct usbfront_hcd_resource * resource ) +{ + trace(); + + xenidc_create_rbr_request_element_ensure_removed + ( &resource->rbr_request_element[ 0 ] ); + + xenidc_create_rbr_request_element_ensure_removed + ( &resource->rbr_request_element[ 1 ] ); + + xenidc_create_rbr_request_element_set_lbr + ( + &resource->rbr_request_element[ 0 ], + xenidc_vaddress_create_lbr + ( + resource->urb->transfer_buffer, + resource->urb->transfer_buffer_length + ) + ); + + xenidc_reserve_and_create_rbr_request_add_element + ( + &resource->rbr_request, + &resource->rbr_request_element[ 0 ] + ); + + if( usb_pipetype( resource->urb->pipe ) == PIPE_ISOCHRONOUS ) + { + if + ( + resource->urb->number_of_packets + > + ( PAGE_SIZE / sizeof( usbif_isochronous_io_schedule_element ) ) + ) + { + goto SCHEDULE_TOO_BIG; + } + + { + usbif_isochronous_io_schedule_element * element = + resource->schedule; + + int i; + + for( i = 0; i < resource->urb->number_of_packets; i++ ) + { + memset( &element[ i ], 0, sizeof( element[ i ] ) ); + + element[ i ].offset = + resource->urb->iso_frame_desc[ i ].offset; + element[ i ].length = + resource->urb->iso_frame_desc[ i ].length; + } + } + + xenidc_create_rbr_request_element_set_lbr + ( + &resource->rbr_request_element[ 1 ], + xenidc_vaddress_create_lbr + ( + resource->schedule, + sizeof( usbif_isochronous_io_schedule_element ) + * + resource->urb->number_of_packets + ) + ); + + xenidc_reserve_and_create_rbr_request_add_element + ( + &resource->rbr_request, + &resource->rbr_request_element[ 1 ] + ); + } + + xenidc_rbr_provider_pool_reserve_and_create_rbrs + ( + usbfront_hcd_resource_rbr_provider_pool, + &resource->rbr_request + ); + + return; + + SCHEDULE_TOO_BIG: + + xenidc_callback_complete + ( + xenidc_reserve_and_create_rbr_request_to_create_callback + ( &resource->rbr_request ), + XENIDC_ERROR_TOO_BIG + ); +} + +static void usbfront_hcd_resource_create_rbrs_1( xenidc_callback * callback ) +{ + trace(); + + { + struct usbfront_hcd_resource * resource = container_of + ( + xenidc_reserve_and_create_rbr_request_create_callback_to + ( callback ), + struct usbfront_hcd_resource, + rbr_request + ); + + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + if( xenidc_callback_query_error( callback ) == XENIDC_ERROR_SUCCESS ) + { + usbfront_hcd_resource_handle_stimulus + ( resource, usbfront_hcd_resource_stimulus_cs ); + } + else + { + usbfront_hcd_resource_handle_stimulus + ( resource, usbfront_hcd_resource_stimulus_cf ); + } + + spin_unlock_irqrestore( &resource->lock, flags ); + } +} + +static void usbfront_hcd_resource_abort_create_rbrs + ( struct usbfront_hcd_resource * resource ) +{ + trace(); + + xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs + ( + usbfront_hcd_resource_rbr_provider_pool, + &resource->rbr_request + ); +} + +static void usbfront_hcd_resource_set_aborted_error + ( struct usbfront_hcd_resource * resource ) +{ + trace(); + + xenidc_callback_set_error + ( + xenidc_reserve_and_create_rbr_request_to_create_callback + ( &resource->rbr_request ), + XENIDC_ERROR_ABORTED + ); +} + +static void usbfront_hcd_resource_submit_transaction + ( struct usbfront_hcd_resource * resource ) +{ + trace(); + + memset( &resource->io_parameters, 0, sizeof( resource->io_parameters ) ); + memset( &resource->io_status, 0, sizeof( resource->io_status ) ); + + resource->io_parameters.header.header.transaction_type = + USBIF_TRANSACTION_TYPE_IO; + + { + struct urb * urb = resource->urb; + + resource->io_parameters.header.device_number = + usb_pipedevice( urb->pipe ); + + resource->io_parameters.header.endpoint = + usb_pipeendpoint( urb->pipe ); + + resource->io_parameters.header.direction = usb_pipein( urb->pipe ) ? + USBIF_IO_TRANSACTION_DIRECTION_IN : + USBIF_IO_TRANSACTION_DIRECTION_OUT; + + resource->io_parameters.header.unlink_id = resource->index; + + if( urb->transfer_flags & URB_SHORT_NOT_OK ) + { + resource->io_parameters.header.flags |= + USBIF_IO_FLAGS_SHORT_NOT_OK; + } + if( urb->transfer_flags & URB_ZERO_PACKET ) + { + resource->io_parameters.header.flags |= + USBIF_IO_FLAGS_ZERO_PACKET; + } + + resource->io_parameters.header.rbr = + xenidc_create_rbr_request_element_query_rbr + ( &resource->rbr_request_element[ 0 ] ); + + if( usb_pipetype( urb->pipe ) == PIPE_CONTROL ) + { + resource->io_parameters.header.io_transaction_type = + USBIF_IO_TRANSACTION_TYPE_CONTROL; + + ASSERT( urb->setup_packet != NULL ); + + memcpy + ( resource->io_parameters.control.setup, urb->setup_packet, 8 ); + } + else if( usb_pipetype( urb->pipe ) == PIPE_BULK ) + { + resource->io_parameters.header.io_transaction_type = + USBIF_IO_TRANSACTION_TYPE_BULK; + } + else if( usb_pipetype( urb->pipe ) == PIPE_INTERRUPT ) + { + resource->io_parameters.header.io_transaction_type = + USBIF_IO_TRANSACTION_TYPE_INTERRUPT; + + resource->io_parameters.interrupt.interval = urb->interval; + } + else if( usb_pipetype( urb->pipe ) == PIPE_ISOCHRONOUS ) + { + resource->io_parameters.header.io_transaction_type = + USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS; + + resource->io_parameters.isochronous.interval = urb->interval; + + resource->io_parameters.isochronous.schedule_rbr = + xenidc_create_rbr_request_element_query_rbr + ( &resource->rbr_request_element[ 1 ] ); + + resource->io_parameters.isochronous.packet_count = + urb->number_of_packets; + } + } + + usbfront_device_submit_transaction + ( resource->device, &resource->io_transaction ); +} + +static void usbfront_hcd_resource_submit_transaction_1 + ( xenidc_callback * callback ) +{ + trace(); + + { + struct usbfront_hcd_resource * resource = container_of + ( + xenidc_transaction_callback_to( callback ), + struct usbfront_hcd_resource, + io_transaction + ); + + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + usbfront_hcd_resource_handle_stimulus + ( resource, usbfront_hcd_resource_stimulus_tc ); + + spin_unlock_irqrestore( &resource->lock, flags ); + } +} + +static void usbfront_hcd_resource_revoke_rbrs + ( struct usbfront_hcd_resource * resource ) +{ + trace(); + + xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs + ( + usbfront_hcd_resource_rbr_provider_pool, + &resource->rbr_request + ); +} + +static void usbfront_hcd_resource_revoke_rbrs_1 + ( xenidc_callback * callback ) +{ + trace(); + + { + struct usbfront_hcd_resource * resource = container_of + ( + xenidc_reserve_and_create_rbr_request_revoke_callback_to + ( callback ), + struct usbfront_hcd_resource, + rbr_request + ); + + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + usbfront_hcd_resource_handle_stimulus + ( resource, usbfront_hcd_resource_stimulus_rc ); + + spin_unlock_irqrestore( &resource->lock, flags ); + } +} + +static void usbfront_hcd_resource_submit_unlink + ( struct usbfront_hcd_resource * resource ) +{ + trace(); + + memset + ( + &resource->unlink_message_body, + 0, + sizeof( resource->unlink_message_body ) + ); + + resource->unlink_message_body.header.message_type = + USBIF_MESSAGE_TYPE_UNLINK; + + resource->unlink_message_body.unlink_id = resource->index; + + usbfront_device_submit_message + ( resource->device, &resource->unlink_message ); +} + +static void usbfront_hcd_resource_submit_unlink_1( xenidc_callback * callback ) +{ + trace(); + + { + struct usbfront_hcd_resource * resource = container_of + ( + xenidc_message_callback_to( callback ), + struct usbfront_hcd_resource, + unlink_message + ); + + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + usbfront_hcd_resource_handle_stimulus + ( resource, usbfront_hcd_resource_stimulus_uc ); + + spin_unlock_irqrestore( &resource->lock, flags ); + } +} + +static void usbfront_hcd_resource_complete + ( struct usbfront_hcd_resource * resource ) +{ + trace(); + + { + int scheduled = xenidc_work_schedule( &resource->complete_1_work ); + + ASSERT( scheduled ); + } +} + +static void usbfront_hcd_resource_complete_1( void * context ) +{ + trace(); + + { + struct usbfront_hcd_resource * resource = + (struct usbfront_hcd_resource *)context; + + struct urb * urb = resource->urb; + + xenidc_error error; + + if + ( + ( + ( + error = xenidc_callback_query_error + ( + xenidc_reserve_and_create_rbr_request_to_create_callback + ( &resource->rbr_request ) + ) + ) + == + XENIDC_ERROR_SUCCESS + ) + && + ( + ( + error = xenidc_callback_query_error + ( + xenidc_reserve_and_create_rbr_request_to_revoke_callback + ( &resource->rbr_request ) + ) + ) + == + XENIDC_ERROR_SUCCESS + ) + ) + { + urb->status = usbif_error_map_to_local + ( xenidc_transaction_query_error( &resource->io_transaction ) ); + urb->actual_length = resource->io_status.length; + + if( usb_pipetype( urb->pipe ) == PIPE_ISOCHRONOUS ) + { + int i; + + for( i = 0; i < urb->number_of_packets; i++ ) + { + usbif_isochronous_io_schedule_element * schedule = + &resource->schedule[ i ]; + + urb->iso_frame_desc[ i ].actual_length = schedule->length; + urb->iso_frame_desc[ i ].status = + usbif_error_map_to_local( schedule->error ); + } + + /* FIXME isoc error_count ?!? */ + } + } + else + { + urb->status = usbif_error_map_to_local( error ); + urb->actual_length = 0; + } + + { + unsigned long flags; + + read_lock_irqsave( &dequeue_lock, flags ); + + urb->hcpriv = 0; + + read_unlock_irqrestore( &dequeue_lock, flags ); + } + + { + unsigned long flags; + + local_irq_save( flags ); + + usb_hcd_giveback_urb( /* FIXME hcd */ NULL, urb, NULL ); + + local_irq_restore( flags ); + } + + xenidc_callback_success( &resource->callback ); + } +} diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,104 @@ +/*****************************************************************************/ +/* A resource used by the usbfront host controller device driver to process */ +/* an URB by translating the URB and optional unlink request into */ +/* a transaction and corresponding optional unlink message for submission to */ +/* the back end. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBFRONT_HCD_RESOURCE_H +#define USBFRONT_HCD_RESOURCE_H + +#include +#include +#include +#include "usbfront_device.h" + +int usbfront_hcd_resource_class_init( void ); + +void usbfront_hcd_resource_class_exit( void ); + +typedef enum +{ + usbfront_hcd_resource_state_i, + usbfront_hcd_resource_state_i_st, + usbfront_hcd_resource_state_i_st_dq, + usbfront_hcd_resource_state_i_st_cs, + usbfront_hcd_resource_state_i_st_dq_cs, + usbfront_hcd_resource_state_i_st_cs_dq, + usbfront_hcd_resource_state_i_st_cs_dq_tc +} +usbfront_hcd_resource_state; + +struct usbfront_hcd_resource +{ + xenidc_callback callback; + struct usbfront_device * device; + int index; + usbif_isochronous_io_schedule_element * schedule; + spinlock_t lock; + usbfront_hcd_resource_state state; + struct urb * urb; + xenidc_create_rbr_request_element rbr_request_element[ 2 ]; + xenidc_reserve_and_create_rbr_request rbr_request; + xenidc_transaction io_transaction; + usbif_io_transaction_parameters io_parameters; + usbif_io_transaction_status io_status; + xenidc_message unlink_message; + usbif_unlink_message_body unlink_message_body; + xenidc_work complete_1_work; +}; + +#define USBFRONT_HCD_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK + +static inline struct list_head * usbfront_hcd_resource_to_link + ( struct usbfront_hcd_resource * resource ) +{ + return xenidc_callback_to_link( &resource->callback ); +} + +static inline struct usbfront_hcd_resource * + usbfront_hcd_resource_callback_to( xenidc_callback * callback ) +{ + return container_of( callback, struct usbfront_hcd_resource, callback ); +} + +static inline struct usbfront_device * usbfront_hcd_resource_query_device + ( struct usbfront_hcd_resource * resource ) +{ + return resource->device; +} + +int usbfront_hcd_resource_init +( + struct usbfront_hcd_resource * resource, + struct usbfront_device * device, + int index, + xenidc_callback_function * callback +); + +void usbfront_hcd_resource_exit + ( struct usbfront_hcd_resource * resource ); + +void usbfront_hcd_resource_start_urb + ( struct usbfront_hcd_resource * resource, struct urb * urb ); + +void usbfront_hcd_resource_dequeue_urb( struct urb * urb ); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_module.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_module.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,92 @@ +/*****************************************************************************/ +/* Front-end module for Xen USB split driver. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include "usbfront_device.h" +#include "usbfront_driver.h" +#include "usbfront_trace.h" + +static int usbfront_module_init_or_exit( int exit ) +{ + trace(); + + { + int return_value = 0; + + if( usb_disabled() ) + { + return_value = -ENODEV; + + goto EXIT_NO_USB; + } + + if( exit ) + { + goto EXIT; + } + + if( ( return_value = usbfront_driver_class_init() ) != 0 ) + { + goto EXIT_NO_DRIVER_CLASS; + } + + if( ( return_value = usbfront_device_class_init() ) != 0 ) + { + goto EXIT_NO_DEVICE_CLASS; + } + + return 0; + + EXIT: + + usbfront_device_class_exit(); + + EXIT_NO_DEVICE_CLASS: + + usbfront_driver_class_exit(); + + EXIT_NO_DRIVER_CLASS: + + EXIT_NO_USB: + + return return_value; + } +} + +static int __init usbfront_module_init( void ) +{ + trace(); + + return usbfront_module_init_or_exit( 0 ); +} + +static void __exit usbfront_module_exit( void ) +{ + trace(); + + (void)usbfront_module_init_or_exit( 1 ); +} + +module_init( usbfront_module_init ); +module_exit( usbfront_module_exit ); + +MODULE_LICENSE( "GPL" ); diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_sll.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_sll.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,133 @@ +/*****************************************************************************/ +/* A singly linked list implementation */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBFRONT_SLL_H +#define USBFRONT_SLL_H + +#include "usbfront_assert.h" + +struct usbfront_slk +{ + struct usbfront_slk * next; +}; + +struct usbfront_sll +{ + struct usbfront_slk * first; + struct usbfront_slk * last; +}; + +static inline void usbfront_slk_init( struct usbfront_slk * slk ) +{ + slk->next = slk; +} + +static inline int usbfront_slk_is_singular( struct usbfront_slk * slk ) +{ + return ( slk->next == slk ); +} + +static inline void usbfront_sll_init( struct usbfront_sll * sll ) +{ + sll->first = 0; +} + +static inline int usbfront_sll_is_empty( struct usbfront_sll * sll ) +{ + return ( sll->first == 0 ); +} + +static inline void usbfront_sll_add_last + ( struct usbfront_sll * sll, struct usbfront_slk * slk ) +{ + ASSERT( usbfront_slk_is_singular( slk ) ); + + slk->next = 0; + + if( sll->first != 0 ) + { + sll->last->next = slk; + } + else + { + sll->first = slk; + } + + sll->last = slk; +} + +static inline struct usbfront_slk * usbfront_sll_remove_first + ( struct usbfront_sll * sll ) +{ + struct usbfront_slk * slk = sll->first; + + if( slk != 0 ) + { + sll->first = slk->next; + + slk->next = slk; + } + + return slk; +} + +/* Returns 1 if slk removed, 0 otherwise. */ + +static inline int usbfront_sll_remove_slk + ( struct usbfront_sll * sll, struct usbfront_slk * slk ) +{ + struct usbfront_slk * prev_slk = NULL; + struct usbfront_slk * next_slk = sll->first; + + while( next_slk != NULL ) + { + if( next_slk != slk ) + { + prev_slk = next_slk; + next_slk = next_slk->next; + } + else + { + next_slk = next_slk->next; + + if( prev_slk != NULL ) + { + prev_slk->next = next_slk; + } + else + { + sll->first = next_slk; + } + + if( next_slk == NULL ) + { + sll->last = prev_slk; + } + + slk->next = slk; + + return 1; + } + } + + return 0; +} + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_trace.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_trace.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,53 @@ +/*****************************************************************************/ +/* Simple trace macros */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBFRONT_TRACE_H +#define USBFRONT_TRACE_H + +#include +#include + +#ifdef CONFIG_XEN_USBDEV_FRONTEND_TRACE + +#define trace0( format ) \ +printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__ ) + +#define trace1( format, a0 ) \ +printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__, a0 ) + +#define trace2( format, a0, a1 ) \ +printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__, a0, a1 ) + +#define trace3( format, a0, a1, a2 ) \ +printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__, a0, a1, a2 ) + +#define trace() trace0( "" ) + +#else + +#define trace0( format ) +#define trace1( format,a0 ) +#define trace2( format,a0, a1 ) +#define trace3( format,a0, a1, a2 ) +#define trace() + +#endif + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/Makefile Mon Oct 24 15:04:49 2005 @@ -0,0 +1,13 @@ +obj-y += xenidc.o + +xenidc-objs = +xenidc-objs += xenidc_callback.o +xenidc-objs += xenidc_concatenate.o +xenidc-objs += xenidc_gnttab_channel.o +xenidc-objs += xenidc_local_buffer_reference.o +xenidc-objs += xenidc_rbr_mapper_pool.o +xenidc-objs += xenidc_rbr_provider_pool.o +xenidc-objs += xenidc_vaddress.o +xenidc-objs += xenidc_work.o +xenidc-objs += xenidc_wrapping.o +xenidc-objs += xenidc_xbgt_channel.o diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_callback.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_callback.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,61 @@ +/*****************************************************************************/ +/* A callback object for use in scheduling completion of asynchronous */ +/* requests. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include "xenidc_callback.h" +#include + +void xenidc_callback_serialiser_function( void * context ) +{ + xenidc_callback_serialiser * serialiser = + (xenidc_callback_serialiser *)context; + + unsigned long flags; + + spin_lock_irqsave( &serialiser->lock, flags ); + + while + ( + ( !list_empty( &serialiser->list ) ) + && + ( !serialiser->running ) + ) + { + xenidc_callback * callback = + xenidc_callback_link_to( serialiser->list.next ); + + list_del_init( xenidc_callback_to_link( callback ) ); + + serialiser->running = 1; + + spin_unlock_irqrestore( &serialiser->lock, flags ); + + xenidc_callback_complete_synchronously( callback ); + + spin_lock_irqsave( &serialiser->lock, flags ); + + serialiser->running = 0; + } + + spin_unlock_irqrestore( &serialiser->lock, flags ); +} + +EXPORT_SYMBOL( xenidc_callback_serialiser_function ); diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_channel_ring.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_channel_ring.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,79 @@ +/*****************************************************************************/ +/* Xen inter-domain communication channel ring structure definitions. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef _XENIDC_CHANNEL_RING_H +#define _XENIDC_CHANNEL_RING_H + +#include + +typedef struct xenidc_channel_ring_header_struct xenidc_channel_ring_header; + +struct xenidc_channel_ring_header_struct +{ + u16 this_ring_producer_offset; + u16 other_ring_consumer_offset; +}; + +typedef struct xenidc_channel_ring_element_header_struct + xenidc_channel_ring_element_header; + +struct xenidc_channel_ring_element_header_struct +{ + u8 type; + u8 reserved0; + u16 length; + u8 reserved1[4]; +}; + +#define XENIDC_CHANNEL_RING_ELEMENT_TYPE_MESSAGE 0 +#define XENIDC_CHANNEL_RING_ELEMENT_TYPE_PARAMETERS 1 +#define XENIDC_CHANNEL_RING_ELEMENT_TYPE_STATUS 2 + +typedef struct xenidc_channel_message_ring_element_struct + xenidc_channel_message_ring_element; + +struct xenidc_channel_message_ring_element_struct +{ + xenidc_channel_ring_element_header header; +}; + +typedef struct xenidc_channel_parameters_ring_element_struct + xenidc_channel_parameters_ring_element; + +struct xenidc_channel_parameters_ring_element_struct +{ + xenidc_channel_ring_element_header header; + u32 id; + u16 status_byte_count; + u16 reserved; +}; + +typedef struct xenidc_channel_status_ring_element_struct + xenidc_channel_status_ring_element; + +struct xenidc_channel_status_ring_element_struct +{ + xenidc_channel_ring_element_header header; + u32 id; + xenidc_error error; +}; + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_concatenate.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_concatenate.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,46 @@ +/*****************************************************************************/ +/* Xen inter-domain communication concatenate local buffer reference type. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include "xenidc_trace.h" + +xenidc_local_buffer_reference xenidc_concatenate_create_lbr +( + xenidc_concatenate_base * base, + xenidc_local_buffer_reference * head, + xenidc_local_buffer_reference * tail +) +{ + trace(); + + /* FIXME */ + + { + xenidc_local_buffer_reference lbr; + + memset( &lbr, 0, sizeof( lbr ) ); + + return lbr; + } +} + +EXPORT_SYMBOL( xenidc_concatenate_create_lbr ); diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,1164 @@ +/*****************************************************************************/ +/* Xen inter-domain communication API, endpoint object. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/****************************************************************************** + * arch/xen/drivers/blkif/backend/interface.c + * + * Block-device interface management. + * + * Copyright (c) 2004, Keir Fraser + */ + +/*****************************************************************************/ +/* xenidc_endpoint design notes: */ +/* */ +/* Two xenidc_endpoint instances, one in each of two domains connect */ +/* together to form a communication channel. The channel is symmetric apart */ +/* from the number of resources allocated for transactions and the */ +/* configured maximum size of transactions in each direction. */ +/* */ +/* Each endpoint allocates a page of memory and grants the other side */ +/* read-only access to it. Each page starts with a */ +/* xenidc_endpoint_ring_header structure and the remainder of the page is */ +/* used as a circular buffer for sending data from the granting side to the */ +/* read-only side. The xenidc_endpoint_ring_header contains the producer and */ +/* consumer offsets for the circular buffers. The producer offset in each */ +/* header is for the circular buffer in the same page as the header, the */ +/* consumer offset is for the circular buffer in the other header (so both */ +/* of the offsets written by an endpoint are in the page to which it has */ +/* write access and the offsets read by an endpoint are in the page to which */ +/* it has read-only access). */ +/* */ +/* The endpoints put three kinds of elements into the circular buffers: */ +/* message elements transfer messages; parameters elements transfer */ +/* transaction parameters and status elements transfer transaction status. */ +/* */ +/* There are two types of resources used to process messages and */ +/* transactions: initiator resources and target resources. Both types of */ +/* resource use xenidc_endpoint_send_request requests to transfer elements */ +/* using the circular buffer. */ +/* */ +/* Message processing is performed as follows: a message is queued and an */ +/* initiator resource is allocated to process it when one becomes available. */ +/* The initiator resource creates a xenidc_endpoint_send_request to send a */ +/* message element for the message. The xenidc_endpoint_send_request is */ +/* queued internally by the endpoint until there is space in the circular */ +/* buffer to copy in the element (a header and the body of the message). */ +/* When there is space in the buffer, the element is copied in and the other */ +/* endpoint is signalled. The other endpoint discovers the message element */ +/* in the buffer and submits the message data to the message handler */ +/* installed at initialisation. */ +/* The xenidc_endpoint_send_request completes to the initiator resource as */ +/* soon as the message element has been copied into the buffer at which time */ +/* the initiator resource completes and is returned to the free list. */ +/* */ +/* Transaction processing is performed as follows: a transaction is queued */ +/* and an initiator resource is allocated to process it when one becomes */ +/* available. The initiator resource creates a xenidc_endpoint_send_request */ +/* to send a parameters element for the transaction parameters. The */ +/* xenidc_endpoint_send_request is queued internally by the endpoint until */ +/* there is space in the circular buffer to copy in the element (a header */ +/* and the transaction parameters). When there is space in the buffer, the */ +/* element is copied in and the other endpoint is signalled. The other */ +/* endpoint discovers the parameters element and, if necessary, stalls until */ +/* a target resource becomes available. When one is available it is */ +/* allocated to process the transaction. The target resource creates a */ +/* xenidc_transaction by copying the parameters from the circular buffer */ +/* into a buffer of its own and zeroing a buffer to receive the transaction */ +/* status. The target resource submits the transaction to the endpoint */ +/* client's transaction handler. The client processes the transaction and */ +/* completes back to the target resource. The target resource creates a */ +/* xenidc_endpoint_send_request to send a status element for the transaction */ +/* back to the initiator. Once the target resource's */ +/* xenidc_endpoint_send_request completes, the target resource is itself */ +/* complete and is returned to the free list. */ +/* The initiator resource is called to handle the status element returned by */ +/* the target resource and copies the status from the circular buffer into */ +/* the transaction status buffer. The initiator resource's */ +/* xenidc_endpoint_send_request completes concurrently with the return of */ +/* status from the target and the initiator resource must wait for both to */ +/* happen in either order before completing the transaction and completing */ +/* itself back to the free list. */ +/* */ +/* Copying into and out of the circular buffer like this is the simplest way */ +/* to allow an arbitrary number of arbitrary sized transactions using a */ +/* finite number of shared pages. More importantly, it allows transactions */ +/* to overtake a stalled transaction which means that if a transaction hangs */ +/* indefinitely in the back end it won't block the system. This is */ +/* important for USB for example because some USB transactions hang for a */ +/* long time before being unlinked and we want the other USB devices to be */ +/* unaffected whilst this is going on. */ +/* */ +/* The endpoint code is structured as a state machine with inputs that */ +/* queue requests and generate stimuli, a core state machine that handles */ +/* stimuli, makes state transitions and generates responses and a set of */ +/* responses that initiate processes to manipulate the endpoint resources. */ +/* These processes also generate stimuli to signal significant conditions */ +/* (for example completion of a process). */ +/* */ +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "xenidc_trace.h" +#include "xenidc_endpoint_initiator_resource.h" +#include "xenidc_endpoint_target_resource.h" +#include "xenidc_vaddress.h" +#include "xenidc_wrapping.h" + +typedef enum +{ + xenidc_endpoint_stimulus_cr, /* Create */ + xenidc_endpoint_stimulus_mt, /* Message or transaction enqueued */ + xenidc_endpoint_stimulus_sr, /* Send request enqueued */ + xenidc_endpoint_stimulus_dt, /* Destroy */ + xenidc_endpoint_stimulus_cn, /* Connect from xenstore */ + xenidc_endpoint_stimulus_xs, /* Xenstore transaction successful */ + xenidc_endpoint_stimulus_xf, /* Xenstore transaction failed */ + xenidc_endpoint_stimulus_es, /* Establish success */ + xenidc_endpoint_stimulus_ef, /* Establish failed */ + xenidc_endpoint_stimulus_si, /* Send interrupt */ + xenidc_endpoint_stimulus_ri, /* Recv interrupt */ + xenidc_endpoint_stimulus_sk, /* Kick send ring completed */ + xenidc_endpoint_stimulus_rk, /* Kick recv ring completed */ + xenidc_endpoint_stimulus_rp, /* Kick recv ring protocol error */ +} +xenidc_endpoint_stimulus; + +static void xenidc_endpoint_handle_stimulus + ( xenidc_endpoint * endpoint, xenidc_endpoint_stimulus stimulus ); + +static void xenidc_endpoint_xenstore_connect_1( void * data ); + +static void xenidc_endpoint_establish_connection_1( void * data ); + +static void xenidc_endpoint_kick_messages_and_transactions_1( void * data ); + +static void xenidc_endpoint_kick_messages_and_transactions_2 + ( xenidc_callback * callback ); + +static void xenidc_endpoint_kick_send_ring_1( void * data ); + +static void xenidc_endpoint_kick_recv_ring_1( void * data ); + +static void xenidc_endpoint_kick_recv_ring_2( xenidc_callback * callback ); + +static int xenidc_endpoint_init_or_exit( xenidc_endpoint * endpoint, int exit ) +{ + trace(); + + { + int return_value = 0; + + if( exit ) + { + goto EXIT; + } + + endpoint->send_irq_context = endpoint; + endpoint->recv_irq_context = endpoint; + + INIT_LIST_HEAD( &endpoint->initiator_resource_list ); + + if( endpoint->initiator_transaction_quota != 0 ) + { + endpoint->initiator_resources = vmalloc + ( + sizeof( xenidc_endpoint_initiator_resource ) + * + endpoint->initiator_transaction_quota + ); + + if( endpoint->initiator_resources == NULL ) + { + trace0( "failed to allocate initiator resources" ); + + return_value = -ENOMEM; + + goto EXIT_NO_INITIATOR_RESOURCES; + } + + { + u32 i; + + for( i = 0; i < endpoint->initiator_transaction_quota; i++ ) + { + xenidc_endpoint_initiator_resource * resource = + &endpoint->initiator_resources[ i ]; + + xenidc_endpoint_initiator_resource_init + ( + resource, + endpoint, + xenidc_endpoint_kick_messages_and_transactions_2, + i + ); + + list_add_tail + ( + xenidc_endpoint_initiator_resource_to_link( resource ), + &endpoint->initiator_resource_list + ); + } + } + } + + INIT_LIST_HEAD( &endpoint->target_resource_list ); + + if( endpoint->target_transaction_quota != 0 ) + { + endpoint->target_resources = vmalloc + ( + ( + sizeof( xenidc_endpoint_target_resource ) + * + endpoint->target_transaction_quota + ) + + + ( + endpoint->target_transaction_maximum_byte_count + * + endpoint->target_transaction_quota + ) + ); + + if( endpoint->target_resources == NULL ) + { + trace0( "failed to allocate target resources" ); + + return_value = -ENOMEM; + + goto EXIT_NO_TARGET_RESOURCES; + } + + { + xenidc_local_buffer_reference buffer_area = + xenidc_vaddress_create_lbr + ( + &endpoint->target_resources + [ endpoint->target_transaction_quota ], + endpoint->target_transaction_maximum_byte_count * + endpoint->target_transaction_quota + ); + + u32 i; + + for( i = 0; i < endpoint->target_transaction_quota; i++ ) + { + xenidc_endpoint_target_resource * resource = + &endpoint->target_resources[ i ]; + + xenidc_local_buffer_reference buffer = buffer_area; + + xenidc_local_buffer_reference_truncate + ( + &buffer, + endpoint->target_transaction_maximum_byte_count + ); + + xenidc_endpoint_target_resource_init + ( + resource, + endpoint, + xenidc_endpoint_kick_recv_ring_2, + buffer + ); + + list_add_tail + ( + xenidc_endpoint_target_resource_to_link( resource ), + &endpoint->target_resource_list + ); + + xenidc_local_buffer_reference_advance + ( + &buffer_area, + endpoint->target_transaction_maximum_byte_count + ); + } + } + } + + spin_lock_init( &endpoint->lock ); + + endpoint->state = xenidc_endpoint_state_i; + + INIT_LIST_HEAD( &endpoint->message_and_transaction_list ); + INIT_LIST_HEAD( &endpoint->send_request_list ); + + xenidc_work_init + ( + &endpoint->xenstore_connect_1_work, + xenidc_endpoint_xenstore_connect_1, + endpoint + ); + + xenidc_work_init + ( + &endpoint->establish_connection_1_work, + xenidc_endpoint_establish_connection_1, + endpoint + ); + + xenidc_work_init + ( + &endpoint->kick_messages_and_transactions_1_work, + xenidc_endpoint_kick_messages_and_transactions_1, + endpoint + ); + + return 0; + + EXIT: + + if( endpoint->target_transaction_quota != 0 ) + { + vfree( endpoint->target_resources ); + } + + EXIT_NO_TARGET_RESOURCES: + + if( endpoint->initiator_transaction_quota != 0 ) + { + vfree( endpoint->initiator_resources ); + } + + EXIT_NO_INITIATOR_RESOURCES: + + return return_value; + } +} + +int xenidc_endpoint_init +( + xenidc_endpoint * endpoint, + void ( * connect )( xenidc_endpoint * endpoint ), + void ( * disconnect ) + ( xenidc_endpoint * endpoint, xenidc_callback * callback ), + void ( * message ) + ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference message ), + void ( * transaction ) + ( xenidc_endpoint * endpoint, xenidc_transaction * transaction ), + xenidc_buffer_byte_count initiator_message_maximum_byte_count, + u32 initiator_transaction_quota, + xenidc_buffer_byte_count initiator_transaction_maximum_byte_count, + xenidc_buffer_byte_count target_message_maximum_byte_count, + u32 target_transaction_quota, + xenidc_buffer_byte_count target_transaction_maximum_byte_count +) +{ + trace(); + + endpoint->connect = connect; + endpoint->disconnect = disconnect; + endpoint->message = message; + endpoint->transaction = transaction; + + endpoint->initiator_transaction_quota = initiator_transaction_quota; + endpoint->target_transaction_quota = target_transaction_quota; + endpoint->target_transaction_maximum_byte_count = + target_transaction_maximum_byte_count; + + return xenidc_endpoint_init_or_exit( endpoint, 0 ); +} + +static void xenidc_endpoint_watch + ( struct xenbus_watch * watch, const char ** vec, unsigned int len ); + +static irqreturn_t xenidc_endpoint_send_interrupt + ( int irq, void * context, struct pt_regs * ptregs ); + +static int xenidc_endpoint_create_or_destroy + ( xenidc_endpoint * endpoint, int destroy ) +{ + trace(); + + { + int return_value = 0; + + if( destroy ) + { + goto DESTROY; + } + + endpoint->watch.node = + xenidc_address_query_remote_domain( &endpoint->address ); + endpoint->watch.callback = xenidc_endpoint_watch; + + return_value = register_xenbus_watch( &endpoint->watch ); + + if( return_value ) + { + trace0( "register_xenbus_watch failed" ); + + goto EXIT_NO_WATCH; + } + + { + unsigned long flags; + + spin_lock_irqsave( &endpoint->lock, flags ); + + xenidc_endpoint_handle_stimulus + ( endpoint, xenidc_endpoint_stimulus_cr ); + + spin_unlock_irqrestore( &endpoint->lock, flags ); + } + + return 0; + + DESTROY: + + endpoint->destroyed = 0; + + { + unsigned long flags; + + spin_lock_irqsave( &endpoint->lock, flags ); + + xenidc_endpoint_handle_stimulus + ( endpoint, xenidc_endpoint_stimulus_dt ); + + spin_unlock_irqrestore( &endpoint->lock, flags ); + } + + /* FIXME xenidc_work_until( endpoint->destroyed ); */ + + gnttab_end_foreign_access_ref( endpoint->send_ring_ref, 0 ); + + gnttab_release_grant_reference + ( &endpoint->grant_ref_pool, endpoint->send_ring_ref ); + + unbind_evtchn_from_irqhandler + ( endpoint->send_irq, &endpoint->send_irq_context ); + + EXIT_NO_BIND: + + /* FIXME: free event channel? */ + + EXIT_NO_EVENT_CHANNEL: + + unregister_xenbus_watch( &endpoint->watch ); + + EXIT_NO_WATCH: + + return return_value; + } +} + +int xenidc_endpoint_create + ( xenidc_endpoint * endpoint, xenidc_address address ) +{ + trace(); + + endpoint->address = address; + + return xenidc_endpoint_create_or_destroy( endpoint, 0 ); +} + +static void xenidc_endpoint_watch + ( struct xenbus_watch * watch, const char ** vec, unsigned int len ) +{ + trace(); + + { + xenidc_endpoint * endpoint = + container_of( watch, xenidc_endpoint, watch ); + + { + unsigned int event_channel; + unsigned int ring_ref; + + int error = xenbus_gather + ( + NULL, /* FIXME */ + watch->node, + "event-channel", "%u", &event_channel, + "ring-ref", "%u", &ring_ref, + NULL + ); + + unsigned long flags; + + spin_lock_irqsave( &endpoint->lock, flags ); + + if( error == 0 ) + { + endpoint->recv_event_channel = event_channel; + endpoint->recv_ring_ref = ring_ref; + + xenidc_endpoint_handle_stimulus + ( endpoint, xenidc_endpoint_stimulus_cn ); + } + + spin_unlock_irqrestore( &endpoint->lock, flags ); + } + } +} + + +void xenidc_endpoint_submit_message + ( xenidc_endpoint * endpoint, xenidc_message * message ) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &endpoint->lock, flags ); + + list_add_tail + ( + xenidc_message_to_link( message ), + &endpoint->message_and_transaction_list + ); + + xenidc_endpoint_handle_stimulus + ( endpoint, xenidc_endpoint_stimulus_mt ); + + spin_unlock_irqrestore( &endpoint->lock, flags ); + } +} + +void xenidc_endpoint_submit_transaction + ( xenidc_endpoint * endpoint, xenidc_transaction * transaction ) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &endpoint->lock, flags ); + + list_add_tail + ( + xenidc_transaction_to_link( transaction ), + &endpoint->message_and_transaction_list + ); + + xenidc_endpoint_handle_stimulus + ( endpoint, xenidc_endpoint_stimulus_mt ); + + spin_unlock_irqrestore( &endpoint->lock, flags ); + } +} + +void xenidc_endpoint_submit_send_request + ( xenidc_endpoint * endpoint, xenidc_endpoint_send_request * request ) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &endpoint->lock, flags ); + + list_add_tail + ( + xenidc_endpoint_send_request_to_link( request ), + &endpoint->send_request_list + ); + + xenidc_endpoint_handle_stimulus + ( endpoint, xenidc_endpoint_stimulus_sr ); + + spin_unlock_irqrestore( &endpoint->lock, flags ); + } +} + +void xenidc_endpoint_destroy( xenidc_endpoint * endpoint ) +{ + trace(); + + (void)xenidc_endpoint_create_or_destroy( endpoint, 1 ); +} + +void xenidc_endpoint_exit( xenidc_endpoint * endpoint ) +{ + trace(); + + (void)xenidc_endpoint_init_or_exit( endpoint, 1 ); +} + +static void xenidc_endpoint_invalid_stimulus + ( xenidc_endpoint * endpoint, xenidc_endpoint_stimulus stimulus ); + +static void xenidc_endpoint_xenstore_connect( xenidc_endpoint * endpoint ); + +static void xenidc_endpoint_establish_connection( xenidc_endpoint * endpoint ); + +static void xenidc_endpoint_kick_messages_and_transactions + ( xenidc_endpoint * endpoint ); + +static void xenidc_endpoint_kick_send_ring( xenidc_endpoint * endpoint ); + +static void xenidc_endpoint_kick_recv_ring( xenidc_endpoint * endpoint ); + +static void xenidc_endpoint_handle_stimulus + ( xenidc_endpoint * endpoint, xenidc_endpoint_stimulus stimulus ) +{ + trace3 + ( + "endpoint %p in state %d received stimulus %d", + endpoint, + endpoint->state, + stimulus + ); + + switch( endpoint->state ) + { + case xenidc_endpoint_state_i: + /* Uncreated */ + /* Offline */ + switch( stimulus ) + { + case xenidc_endpoint_stimulus_cr: + endpoint->state = xenidc_endpoint_state_i_cr; + xenidc_endpoint_xenstore_connect( endpoint ); + break; + case xenidc_endpoint_stimulus_cn: + endpoint->state = xenidc_endpoint_state_i_cn; + break; + default: + xenidc_endpoint_invalid_stimulus( endpoint, stimulus ); + break; + } + break; + case xenidc_endpoint_state_i_cr: + /* Creating */ + /* Xenstore Connect */ + /* Offline */ + switch( stimulus ) + { + case xenidc_endpoint_stimulus_cn: + endpoint->state = xenidc_endpoint_state_i_cr_cn; + break; + case xenidc_endpoint_stimulus_xs: + endpoint->state = xenidc_endpoint_state_i_cr_xs; + break; + default: + xenidc_endpoint_invalid_stimulus( endpoint, stimulus ); + break; + } + break; + case xenidc_endpoint_state_i_cn: + /* Uncreated */ + /* Offline */ + /* Connect received */ + switch( stimulus ) + { + case xenidc_endpoint_stimulus_cr: + endpoint->state = xenidc_endpoint_state_i_cr_cn; + xenidc_endpoint_xenstore_connect( endpoint ); + break; + case xenidc_endpoint_stimulus_cn: + break; + default: + xenidc_endpoint_invalid_stimulus( endpoint, stimulus ); + break; + } + break; + case xenidc_endpoint_state_i_cr_cn: + /* Creating */ + /* Xenstore Connect */ + /* Offline */ + /* Connect received */ + switch( stimulus ) + { + case xenidc_endpoint_stimulus_cn: + break; + case xenidc_endpoint_stimulus_xs: + endpoint->state = xenidc_endpoint_state_i_cr_cn_xs; + xenidc_endpoint_establish_connection( endpoint ); + break; + default: + xenidc_endpoint_invalid_stimulus( endpoint, stimulus ); + break; + } + break; + case xenidc_endpoint_state_i_cr_xs: + /* Creating */ + /* Xenstore Connect completed */ + /* Offline */ + switch( stimulus ) + { + case xenidc_endpoint_stimulus_cn: + endpoint->state = xenidc_endpoint_state_i_cr_cn_xs; + xenidc_endpoint_establish_connection( endpoint ); + break; + default: + xenidc_endpoint_invalid_stimulus( endpoint, stimulus ); + break; + } + break; + case xenidc_endpoint_state_i_cr_cn_xs: + /* Creating */ + /* Xenstore Connect completed */ + /* Establishing connection */ + switch( stimulus ) + { + case xenidc_endpoint_stimulus_cn: + break; + case xenidc_endpoint_stimulus_es: + endpoint->state = xenidc_endpoint_state_i_cr_cn_xs_es; + break; + default: + xenidc_endpoint_invalid_stimulus( endpoint, stimulus ); + break; + } + break; + case xenidc_endpoint_state_i_cr_cn_xs_es: + /* Created */ + /* Online */ + switch( stimulus ) + { + default: + xenidc_endpoint_invalid_stimulus( endpoint, stimulus ); + break; + } + break; + default: + xenidc_endpoint_invalid_stimulus( endpoint, stimulus ); + break; + } +} + +static void xenidc_endpoint_invalid_stimulus + ( xenidc_endpoint * endpoint, xenidc_endpoint_stimulus stimulus ) +{ + trace(); + + printk + ( + KERN_ERR "xenidc: endpoint %p in state %d" + "received invalid stimulus %d", + endpoint, + endpoint->state, + stimulus + ); +} + +static void xenidc_endpoint_xenstore_connect( xenidc_endpoint * endpoint ) +{ + trace(); + + (void)xenidc_work_schedule( &endpoint->xenstore_connect_1_work ); +} + +static void xenidc_endpoint_xenstore_connect_1( void * data ) +{ + trace(); + + { + xenidc_endpoint * endpoint = (xenidc_endpoint *)data; + + memset( endpoint->send_ring, 0, PAGE_SIZE ); + + down( &xenbus_lock ); + + AGAIN: + + { + int error = xenbus_transaction_start(); + + if( error ) + { + trace0( "xenbus_transaction_start failed" ); + + goto EXIT_NO_TRANSACTION; + } + } + + { + int error = xenbus_printf + ( + xenidc_address_query_local_domain( &endpoint->address ), + "ring-ref", + "%u", + endpoint->send_ring_ref + ); + + if( error ) + { + trace0( "xenbus_printf of ring-ref failed" ); + + goto ABORT_TRANSACTION; + } + } + + { + int error = xenbus_printf + ( + xenidc_address_query_local_domain( &endpoint->address ), + "event-channel", + "%u", + endpoint->send_event_channel + ); + + if( error ) + { + trace0( "xenbus_printf of event-channel failed" ); + + ABORT_TRANSACTION: + + xenbus_transaction_end( 1 ); + + goto EXIT_NO_TRANSACTION; + } + } + + { + int error = xenbus_transaction_end( 0 ); + + if( error == -EAGAIN ) + { + trace0( "EAGAIN on xenbus_transaction_end" ); + + goto AGAIN; + } + + if( error ) + { + trace0( "xenbus_transaction_end failed" ); + + goto EXIT_NO_TRANSACTION; + } + } + + up( &xenbus_lock ); + + { + unsigned long flags; + + spin_lock_irqsave( &endpoint->lock, flags ); + + xenidc_endpoint_handle_stimulus + ( endpoint, xenidc_endpoint_stimulus_xs ); + + spin_unlock_irqrestore( &endpoint->lock, flags ); + } + + return; + + EXIT_NO_TRANSACTION: + + up( &xenbus_lock ); + + { + unsigned long flags; + + spin_lock_irqsave( &endpoint->lock, flags ); + + xenidc_endpoint_handle_stimulus + ( endpoint, xenidc_endpoint_stimulus_xf ); + + spin_unlock_irqrestore( &endpoint->lock, flags ); + } + } +} + +static void xenidc_endpoint_establish_connection( xenidc_endpoint * endpoint ) +{ + trace(); + + (void)xenidc_work_schedule( &endpoint->establish_connection_1_work ); +} + +static void xenidc_endpoint_establish_connection_1( void * data ) +{ + trace(); + + { + xenidc_endpoint * endpoint = (xenidc_endpoint *)data; + return; + + } +} + +static void xenidc_endpoint_kick_messages_and_transactions + ( xenidc_endpoint * endpoint ) +{ + trace(); + + (void)xenidc_work_schedule + ( &endpoint->kick_messages_and_transactions_1_work ); +} + +static void xenidc_endpoint_kick_messages_and_transactions_1( void * data ) +{ + trace(); + + { + xenidc_endpoint * endpoint = (xenidc_endpoint *)data; + + unsigned long flags; + + spin_lock_irqsave( &endpoint->lock, flags ); + + while + ( + ( !list_empty( &endpoint->message_and_transaction_list ) ) + && + ( !list_empty( &endpoint->initiator_resource_list ) ) + ) + { + xenidc_message_and_transaction_header * header = list_entry + ( + endpoint->message_and_transaction_list.next, + xenidc_message_and_transaction_header, + XENIDC_MESSAGE_AND_TRANSACTION_HEADER_LINK + ); + + xenidc_endpoint_initiator_resource * resource = list_entry + ( + endpoint->initiator_resource_list.next, + xenidc_endpoint_initiator_resource, + XENIDC_ENDPOINT_INITIATOR_RESOURCE_LINK + ); + + list_del_init + ( xenidc_message_and_transaction_header_to_link( header ) ); + + list_del_init + ( xenidc_endpoint_initiator_resource_to_link( resource ) ); + + spin_unlock_irqrestore( &endpoint->lock, flags ); + + xenidc_endpoint_initiator_resource_start( resource, header ); + + spin_lock_irqsave( &endpoint->lock, flags ); + } + + spin_unlock_irqrestore( &endpoint->lock, flags ); + } +} + +static void xenidc_endpoint_kick_messages_and_transactions_2 + ( xenidc_callback * callback ) +{ + trace(); + + { + xenidc_endpoint_initiator_resource * resource = + xenidc_endpoint_initiator_resource_callback_to( callback ); + + xenidc_endpoint * endpoint = + xenidc_endpoint_initiator_resource_query_endpoint( resource ); + + unsigned long flags; + + spin_lock_irqsave( &endpoint->lock, flags ); + + list_add_tail + ( + xenidc_endpoint_initiator_resource_to_link( resource ), + &endpoint->initiator_resource_list + ); + + spin_unlock_irqrestore( &endpoint->lock, flags ); + } +} + + +static int xenidc_endpoint_handle_message_element + ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference element ) +{ + trace(); + + xenidc_local_buffer_reference_advance + ( &element, sizeof( xenidc_endpoint_message_ring_element ) ); + + endpoint->message( endpoint, element ); + + return 0; +} + +static int xenidc_endpoint_handle_parameters_element + ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference element ) +{ + trace(); + + { + xenidc_endpoint_target_resource * resource; + + xenidc_endpoint_parameters_ring_element parameters; + + if + ( + ( + xenidc_local_buffer_reference_copy_out + ( &element, ¶meters, sizeof( parameters ) ) + != + sizeof( parameters ) + ) + || + ( + ( + xenidc_local_buffer_reference_advance + ( + &element, + sizeof( xenidc_endpoint_parameters_ring_element ) + ) + + + parameters.status_byte_count + ) + > + endpoint->target_transaction_maximum_byte_count + ) + ) + { + return -1; + } + + { + unsigned long flags; + + spin_lock_irqsave( &endpoint->lock, flags ); + + if( list_empty( &endpoint->target_resource_list ) ) + { + spin_unlock_irqrestore( &endpoint->lock, flags ); + + return 1; + } + + resource = list_entry + ( + endpoint->target_resource_list.next, + xenidc_endpoint_target_resource, + XENIDC_ENDPOINT_TARGET_RESOURCE_LINK + ); + + list_del_init + ( xenidc_endpoint_target_resource_to_link( resource ) ); + + spin_unlock_irqrestore( &endpoint->lock, flags ); + } + + xenidc_endpoint_target_resource_start + ( resource, parameters.id, element, parameters.status_byte_count ); + } + + return 0; +} + +static void xenidc_endpoint_kick_recv_ring_2( xenidc_callback * callback ) +{ + trace(); + + { + xenidc_endpoint_target_resource * resource = + xenidc_endpoint_target_resource_callback_to( callback ); + + xenidc_endpoint * endpoint = + xenidc_endpoint_target_resource_query_endpoint( resource ); + + unsigned long flags; + + spin_lock_irqsave( &endpoint->lock, flags ); + + list_add_tail + ( + xenidc_endpoint_target_resource_to_link( resource ), + &endpoint->target_resource_list + ); + + spin_unlock_irqrestore( &endpoint->lock, flags ); + } +} + +static inline xenidc_endpoint_initiator_resource * + xenidc_endpoint_find_initiator_resource_from_id + ( xenidc_endpoint * endpoint, u32 id ) +{ + trace(); + + if( id < endpoint->initiator_transaction_quota ) + { + return &endpoint->initiator_resources[ id ]; + } + else + { + return NULL; + } +} + +static int xenidc_endpoint_handle_status_element + ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference element ) +{ + trace(); + + { + xenidc_endpoint_status_ring_element status; + + if + ( + xenidc_local_buffer_reference_copy_out + ( &element, &status, sizeof( status ) ) + != + sizeof( status ) + ) + { + goto PROTOCOL_ERROR; + } + + xenidc_local_buffer_reference_advance( &element, sizeof( status ) ); + + { + xenidc_endpoint_initiator_resource * resource = + xenidc_endpoint_find_initiator_resource_from_id + ( endpoint, status.id ); + + if( resource == NULL ) + { + goto PROTOCOL_ERROR; + } + + if + ( + xenidc_endpoint_initiator_resource_handle_status + ( resource, status.error, element ) + != + 0 + ) + { + goto PROTOCOL_ERROR; + } + } + } + + return 0; + + PROTOCOL_ERROR: + + return -1; +} + +EXPORT_SYMBOL( xenidc_endpoint_init ); +EXPORT_SYMBOL( xenidc_endpoint_create ); +EXPORT_SYMBOL( xenidc_endpoint_submit_message ); +EXPORT_SYMBOL( xenidc_endpoint_submit_transaction ); +EXPORT_SYMBOL( xenidc_endpoint_destroy ); +EXPORT_SYMBOL( xenidc_endpoint_exit ); diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_initiator_resource.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_initiator_resource.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,410 @@ +#include +#include "xenidc_endpoint_initiator_resource.h" +#include "xenidc_trace.h" + +static void xenidc_endpoint_initiator_resource_handle_stimulus +( + xenidc_endpoint_initiator_resource * resource, + xenidc_endpoint_initiator_resource_stimulus stimulus +); + +static void xenidc_endpoint_initiator_resource_send_request_callback + ( xenidc_callback * callback ); + +void xenidc_endpoint_initiator_resource_init +( + xenidc_endpoint_initiator_resource * resource, + xenidc_endpoint * endpoint, + xenidc_callback_function callback, + int id +) +{ + trace(); + + xenidc_callback_init( &resource->callback, callback ); + + resource->endpoint = endpoint; + + resource->id = id; + + spin_lock_init( &resource->lock ); + + resource->state = xenidc_endpoint_initiator_resource_state_i; + + xenidc_callback_init + ( + xenidc_endpoint_send_request_to_callback( &resource->send_request ), + xenidc_endpoint_initiator_resource_send_request_callback + ); +} + +void xenidc_endpoint_initiator_resource_start +( + xenidc_endpoint_initiator_resource * resource, + xenidc_message_and_transaction_header * header +) +{ + trace(); + + resource->header = header; + + resource->error = XENIDC_ERROR_SUCCESS; + + { + xenidc_endpoint_initiator_resource_stimulus stimulus; + + if( header->transaction_not_message ) + { + xenidc_transaction * transaction = + xenidc_transaction_header_to( header ); + + resource->element = xenidc_vaddress_create_lbr + ( + &resource->parameters_element, + sizeof( resource->parameters_element ) + ); + + resource->send_request.buffer = xenidc_concatenate_create_lbr + ( + &resource->base, + &resource->element, + &transaction->parameters + ); + + memset + ( + &resource->parameters_element, + 0, + sizeof( resource->parameters_element ) + ); + + resource->parameters_element.header.type = + XENIDC_ENDPOINT_RING_ELEMENT_TYPE_PARAMETERS; + + resource->parameters_element.header.length = + xenidc_local_buffer_reference_query_byte_count + ( &resource->send_request.buffer ); + + resource->parameters_element.id = + resource->id; + + resource->parameters_element.status_byte_count = + xenidc_local_buffer_reference_query_byte_count + ( &transaction->status ); + + stimulus = xenidc_endpoint_initiator_resource_stimulus_st; + } + else + { + xenidc_message * message = xenidc_message_header_to( header ); + + resource->element = xenidc_vaddress_create_lbr + ( + &resource->message_element, + sizeof( resource->message_element ) + ); + + resource->send_request.buffer = xenidc_concatenate_create_lbr + ( &resource->base, &resource->element, &message->message ); + + memset + ( + &resource->message_element, + 0, + sizeof( resource->message_element ) + ); + + resource->parameters_element.header.type = + XENIDC_ENDPOINT_RING_ELEMENT_TYPE_MESSAGE; + + resource->parameters_element.header.length = + xenidc_local_buffer_reference_query_byte_count + ( &resource->send_request.buffer ); + + stimulus = xenidc_endpoint_initiator_resource_stimulus_sm; + } + + { + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + xenidc_endpoint_initiator_resource_handle_stimulus + ( resource, stimulus ); + + spin_unlock_irqrestore( &resource->lock, flags ); + } + + xenidc_endpoint_submit_send_request + ( resource->endpoint, &resource->send_request ); + } +} + +void xenidc_endpoint_initiator_resource_abort + ( xenidc_endpoint_initiator_resource * resource ) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + xenidc_endpoint_initiator_resource_handle_stimulus + ( resource, xenidc_endpoint_initiator_resource_stimulus_ab ); + + spin_unlock_irqrestore( &resource->lock, flags ); + } +} + +static void xenidc_endpoint_initiator_resource_send_request_callback + ( xenidc_callback * callback ) +{ + trace(); + + { + xenidc_endpoint_initiator_resource * resource = container_of + ( + callback, + xenidc_endpoint_initiator_resource, + send_request.callback + ); + + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + xenidc_endpoint_initiator_resource_handle_stimulus + ( resource, xenidc_endpoint_initiator_resource_stimulus_sc ); + + spin_unlock_irqrestore( &resource->lock, flags ); + } +} + +int xenidc_endpoint_initiator_resource_handle_status +( + xenidc_endpoint_initiator_resource * resource, + xenidc_error error, + xenidc_local_buffer_reference status +) +{ + trace(); + + { + int return_value = -1; + + unsigned long flags; + + spin_lock_irqsave( &resource->lock, flags ); + + if + ( + ( + resource->state + == + xenidc_endpoint_initiator_resource_state_i_st + ) + || + ( + resource->state + == + xenidc_endpoint_initiator_resource_state_i_st_sc + ) + ) + { + xenidc_transaction * transaction = + xenidc_transaction_header_to( resource->header ); + + if + ( + xenidc_local_buffer_reference_query_byte_count( &status ) + == + xenidc_local_buffer_reference_query_byte_count + ( &transaction->status ) + ) + { + xenidc_local_buffer_reference_copy + ( &transaction->status, &status ); + + resource->error = error; + + xenidc_endpoint_initiator_resource_handle_stimulus + ( resource, xenidc_endpoint_initiator_resource_stimulus_ts ); + + return_value = 0; + } + } + + spin_unlock_irqrestore( &resource->lock, flags ); + + return return_value; + } +} + +static void xenidc_endpoint_initiator_resource_invalid_stimulus +( + xenidc_endpoint_initiator_resource * resource, + xenidc_endpoint_initiator_resource_stimulus stimulus +); + +static void xenidc_endpoint_initiator_resource_set_aborted + ( xenidc_endpoint_initiator_resource * resource ); + +static void xenidc_endpoint_initiator_resource_complete + ( xenidc_endpoint_initiator_resource * resource ); + +static void xenidc_endpoint_initiator_resource_handle_stimulus +( + xenidc_endpoint_initiator_resource * resource, + xenidc_endpoint_initiator_resource_stimulus stimulus +) +{ + trace3 + ( + "endpoint initiator resource %p in state %d received stimulus %d", + resource, + resource->state, + stimulus + ); + + switch( resource->state ) + { + case xenidc_endpoint_initiator_resource_state_i: + switch( stimulus ) + { + case xenidc_endpoint_initiator_resource_stimulus_sm: + resource->state = xenidc_endpoint_initiator_resource_state_i_sm; + break; + case xenidc_endpoint_initiator_resource_stimulus_st: + resource->state = xenidc_endpoint_initiator_resource_state_i_st; + break; + case xenidc_endpoint_initiator_resource_stimulus_ab: + break; + default: + xenidc_endpoint_initiator_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + case xenidc_endpoint_initiator_resource_state_i_sm: + switch( stimulus ) + { + case xenidc_endpoint_initiator_resource_stimulus_ab: + break; + case xenidc_endpoint_initiator_resource_stimulus_sc: + resource->state = xenidc_endpoint_initiator_resource_state_i; + xenidc_endpoint_initiator_resource_complete( resource ); + break; + default: + xenidc_endpoint_initiator_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + case xenidc_endpoint_initiator_resource_state_i_st: + switch( stimulus ) + { + case xenidc_endpoint_initiator_resource_stimulus_ab: + resource->state = xenidc_endpoint_initiator_resource_state_i_st_ab; + break; + case xenidc_endpoint_initiator_resource_stimulus_sc: + resource->state = xenidc_endpoint_initiator_resource_state_i_st_sc; + break; + case xenidc_endpoint_initiator_resource_stimulus_ts: + resource->state = xenidc_endpoint_initiator_resource_state_i_st_ts; + break; + default: + xenidc_endpoint_initiator_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + case xenidc_endpoint_initiator_resource_state_i_st_ab: + switch( stimulus ) + { + case xenidc_endpoint_initiator_resource_stimulus_sc: + resource->state = xenidc_endpoint_initiator_resource_state_i; + xenidc_endpoint_initiator_resource_set_aborted( resource ); + xenidc_endpoint_initiator_resource_complete( resource ); + break; + default: + xenidc_endpoint_initiator_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + case xenidc_endpoint_initiator_resource_state_i_st_sc: + switch( stimulus ) + { + case xenidc_endpoint_initiator_resource_stimulus_ab: + resource->state = xenidc_endpoint_initiator_resource_state_i; + xenidc_endpoint_initiator_resource_set_aborted( resource ); + xenidc_endpoint_initiator_resource_complete( resource ); + break; + case xenidc_endpoint_initiator_resource_stimulus_ts: + resource->state = xenidc_endpoint_initiator_resource_state_i; + xenidc_endpoint_initiator_resource_complete( resource ); + break; + default: + xenidc_endpoint_initiator_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + case xenidc_endpoint_initiator_resource_state_i_st_ts: + switch( stimulus ) + { + case xenidc_endpoint_initiator_resource_stimulus_ab: + break; + case xenidc_endpoint_initiator_resource_stimulus_sc: + resource->state = xenidc_endpoint_initiator_resource_state_i; + xenidc_endpoint_initiator_resource_complete( resource ); + break; + default: + xenidc_endpoint_initiator_resource_invalid_stimulus + ( resource, stimulus ); + break; + } + break; + default: + xenidc_endpoint_initiator_resource_invalid_stimulus + ( resource, stimulus ); + break; + } +} + +static void xenidc_endpoint_initiator_resource_invalid_stimulus +( + xenidc_endpoint_initiator_resource * resource, + xenidc_endpoint_initiator_resource_stimulus stimulus +) +{ + trace(); + + printk + ( + KERN_ERR "xenidc: endpoint initiator resource %p in state %d" + "received invalid stimulus %d", + resource, + resource->state, + stimulus + ); +} + +static void xenidc_endpoint_initiator_resource_set_aborted + ( xenidc_endpoint_initiator_resource * resource ) +{ + trace(); + + resource->error = XENIDC_ERROR_ABORTED; +} + +static void xenidc_endpoint_initiator_resource_complete + ( xenidc_endpoint_initiator_resource * resource ) +{ + trace(); + + xenidc_callback_complete( &resource->header->callback, resource->error ); + + xenidc_callback_success( &resource->callback ); +} diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_initiator_resource.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_initiator_resource.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,95 @@ +#ifndef _XENIDC_ENDPOINT_INITIATOR_RESOURCE_H +#define _XENIDC_ENDPOINT_INITIATOR_RESOURCE_H + +#include +#include +#include "xenidc_endpoint_ring.h" +#include "xenidc_endpoint_send_request.h" + +typedef enum +{ + xenidc_endpoint_initiator_resource_state_i, + xenidc_endpoint_initiator_resource_state_i_sm, + xenidc_endpoint_initiator_resource_state_i_st, + xenidc_endpoint_initiator_resource_state_i_st_ab, + xenidc_endpoint_initiator_resource_state_i_st_sc, + xenidc_endpoint_initiator_resource_state_i_st_ts +} +xenidc_endpoint_initiator_resource_state; + +typedef enum +{ + xenidc_endpoint_initiator_resource_stimulus_sm, /* Start message */ + xenidc_endpoint_initiator_resource_stimulus_st, /* Start transaction */ + xenidc_endpoint_initiator_resource_stimulus_ab, /* Abort */ + xenidc_endpoint_initiator_resource_stimulus_sc, /* Send complete */ + xenidc_endpoint_initiator_resource_stimulus_ts, /* Transaction status */ +} +xenidc_endpoint_initiator_resource_stimulus; + +struct xenidc_endpoint_initiator_resource_struct +{ + xenidc_callback callback; + xenidc_endpoint * endpoint; + int id; + spinlock_t lock; + xenidc_endpoint_initiator_resource_state state; + xenidc_message_and_transaction_header * header; + xenidc_error error; + xenidc_endpoint_send_request send_request; + xenidc_local_buffer_reference element; + xenidc_concatenate_base base; + union + { + xenidc_endpoint_parameters_ring_element parameters_element; + xenidc_endpoint_message_ring_element message_element; + }; +}; + +#define XENIDC_ENDPOINT_INITIATOR_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK + +static inline struct list_head * xenidc_endpoint_initiator_resource_to_link + ( xenidc_endpoint_initiator_resource* resource ) +{ + return &resource->XENIDC_ENDPOINT_INITIATOR_RESOURCE_LINK; +} + +static inline xenidc_endpoint_initiator_resource * + xenidc_endpoint_initiator_resource_callback_to( xenidc_callback * callback ) +{ + return container_of + ( callback, xenidc_endpoint_initiator_resource, callback ); +} + +static inline xenidc_endpoint * + xenidc_endpoint_initiator_resource_query_endpoint + ( xenidc_endpoint_initiator_resource* resource ) +{ + return resource->endpoint; +} + +void xenidc_endpoint_initiator_resource_init +( + xenidc_endpoint_initiator_resource * resource, + xenidc_endpoint * endpoint, + xenidc_callback_function callback, + int id +); + +void xenidc_endpoint_initiator_resource_start +( + xenidc_endpoint_initiator_resource * resource, + xenidc_message_and_transaction_header * header +); + +void xenidc_endpoint_initiator_resource_abort + ( xenidc_endpoint_initiator_resource * resource ); + +int xenidc_endpoint_initiator_resource_handle_status +( + xenidc_endpoint_initiator_resource * resource, + xenidc_error error, + xenidc_local_buffer_reference status +); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_target_resource.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_target_resource.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,134 @@ +#include +#include "xenidc_endpoint_target_resource.h" +#include "xenidc_trace.h" + +static void xenidc_endpoint_target_resource_transaction_callback + ( xenidc_callback * callback ); + +static void xenidc_endpoint_target_resource_send_request_callback + ( xenidc_callback * callback ); + +void xenidc_endpoint_target_resource_init +( + xenidc_endpoint_target_resource * resource, + xenidc_endpoint * endpoint, + xenidc_callback_function callback, + xenidc_local_buffer_reference buffer +) +{ + trace(); + + xenidc_callback_init( &resource->callback, callback ); + + resource->endpoint = endpoint; + + resource->buffer = buffer; + + xenidc_transaction_init + ( + &resource->transaction, + xenidc_endpoint_target_resource_transaction_callback + ); + + xenidc_callback_init + ( + xenidc_endpoint_send_request_to_callback( &resource->send_request ), + xenidc_endpoint_target_resource_send_request_callback + ); + + resource->element = xenidc_vaddress_create_lbr + ( &resource->status, sizeof( resource->status ) ); + + memset( &resource->status, 0, sizeof( resource->status ) ); + + resource->status.header.type = XENIDC_ENDPOINT_RING_ELEMENT_TYPE_STATUS; +} + +void xenidc_endpoint_target_resource_start +( + xenidc_endpoint_target_resource * resource, + u32 id, + xenidc_local_buffer_reference parameters, + xenidc_buffer_byte_count status_byte_count +) +{ + trace(); + + resource->status.id = id; + + { + xenidc_local_buffer_reference lbr = resource->buffer; + + xenidc_local_buffer_reference_truncate + ( &lbr, xenidc_local_buffer_reference_copy( &lbr, ¶meters ) ); + + xenidc_transaction_set_parameters_lbr( &resource->transaction, lbr ); + } + + { + xenidc_local_buffer_reference lbr = resource->buffer; + + xenidc_local_buffer_reference_advance + ( + &lbr, + xenidc_local_buffer_reference_query_byte_count( ¶meters ) + ); + + xenidc_local_buffer_reference_truncate( &lbr, status_byte_count ); + + xenidc_local_buffer_reference_zero( &lbr ); + + xenidc_transaction_set_status_lbr( &resource->transaction, lbr ); + } + + resource->endpoint->transaction + ( resource->endpoint, &resource->transaction ); +} + +static void xenidc_endpoint_target_resource_transaction_callback + ( xenidc_callback * callback ) +{ + trace(); + + { + xenidc_endpoint_target_resource * resource = container_of + ( + xenidc_transaction_callback_to( callback ), + xenidc_endpoint_target_resource, + transaction + ); + + resource->status.error = xenidc_callback_query_error( callback ); + + resource->send_request.buffer = xenidc_concatenate_create_lbr + ( + &resource->base, + &resource->element, + &resource->transaction.status + ); + + resource->status.header.length = + xenidc_local_buffer_reference_query_byte_count + ( &resource->send_request.buffer ); + + xenidc_endpoint_submit_send_request + ( resource->endpoint, &resource->send_request ); + } +} + +static void xenidc_endpoint_target_resource_send_request_callback + ( xenidc_callback * callback ) +{ + trace(); + + { + xenidc_endpoint_target_resource * resource = container_of + ( + callback, + xenidc_endpoint_target_resource, + send_request.callback + ); + + xenidc_callback_success( &resource->callback ); + } +} diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_target_resource.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_endpoint_target_resource.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,58 @@ +#ifndef _XENIDC_ENDPOINT_TARGET_RESOURCE_H +#define _XENIDC_ENDPOINT_TARGET_RESOURCE_H + +#include +#include +#include "xenidc_endpoint_ring.h" +#include "xenidc_endpoint_send_request.h" + +struct xenidc_endpoint_target_resource_struct +{ + xenidc_callback callback; + xenidc_endpoint * endpoint; + xenidc_local_buffer_reference buffer; + xenidc_transaction transaction; + xenidc_endpoint_send_request send_request; + xenidc_local_buffer_reference element; + xenidc_concatenate_base base; + xenidc_endpoint_status_ring_element status; +}; + +#define XENIDC_ENDPOINT_TARGET_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK + +static inline struct list_head * xenidc_endpoint_target_resource_to_link + ( xenidc_endpoint_target_resource * resource ) +{ + return &resource->XENIDC_ENDPOINT_TARGET_RESOURCE_LINK; +} + +static inline xenidc_endpoint_target_resource * + xenidc_endpoint_target_resource_callback_to( xenidc_callback * callback ) +{ + return container_of + ( callback, xenidc_endpoint_target_resource, callback ); +} + +static inline xenidc_endpoint * xenidc_endpoint_target_resource_query_endpoint + ( xenidc_endpoint_target_resource* resource ) +{ + return resource->endpoint; +} + +extern void xenidc_endpoint_target_resource_init +( + xenidc_endpoint_target_resource * resource, + xenidc_endpoint * endpoint, + xenidc_callback_function callback, + xenidc_local_buffer_reference buffer +); + +extern void xenidc_endpoint_target_resource_start +( + xenidc_endpoint_target_resource * resource, + u32 id, + xenidc_local_buffer_reference parameters, + xenidc_buffer_byte_count status_byte_count +); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gnttab_channel.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_gnttab_channel.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,1297 @@ +/*****************************************************************************/ +/* Xen inter-domain communication channel class. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "xenidc_trace.h" +#include "xenidc_channel_ring.h" + +static inline void xenidc_gnttab_channel_target_resource_init +( + xenidc_gnttab_channel_target_resource * resource, + xenidc_gnttab_channel * channel, + xenidc_callback_function * callback +) +{ + trace(); + + xenidc_channel_message_init( &resource->message, callback ); + + resource->channel = channel; +} + +static inline struct list_head * xenidc_gnttab_channel_target_resource_to_link + ( xenidc_gnttab_channel_target_resource * resource ) +{ + trace(); + + return xenidc_channel_message_to_link( &resource->message ); +} + +static inline xenidc_channel_message * + xenidc_gnttab_channel_target_resource_to_message + ( xenidc_gnttab_channel_target_resource * resource ) +{ + trace(); + + return &resource->message; +} + +static inline xenidc_gnttab_channel_target_resource * + xenidc_gnttab_channel_target_resource_callback_to + ( xenidc_callback * callback ) +{ + trace(); + + return container_of + ( + xenidc_channel_message_callback_to( callback ), + xenidc_gnttab_channel_target_resource, + message + ); +} + +static inline xenidc_gnttab_channel * + xenidc_gnttab_channel_target_resource_query_channel + ( xenidc_gnttab_channel_target_resource * resource ) +{ + trace(); + + return resource->channel; +} + +typedef enum +{ + xenidc_gnttab_channel_stimulus_c1r, /* phase one connect request */ + xenidc_gnttab_channel_stimulus_c2r, /* phase two connect request */ + xenidc_gnttab_channel_stimulus_mqr, /* message queued */ + xenidc_gnttab_channel_stimulus_d2r, /* phase two disconnect request */ + xenidc_gnttab_channel_stimulus_d1r, /* phase one disconnect request */ + xenidc_gnttab_channel_stimulus_sir, /* send interrupt */ + xenidc_gnttab_channel_stimulus_rir, /* recv interrupt */ + xenidc_gnttab_channel_stimulus_c1c, /* phase one connect completed */ + xenidc_gnttab_channel_stimulus_c2s, /* phase two connect successful */ + xenidc_gnttab_channel_stimulus_c2f, /* phase two connect failed */ + xenidc_gnttab_channel_stimulus_ccc, /* connect client completed */ + xenidc_gnttab_channel_stimulus_dcc, /* disconnect client completed */ + xenidc_gnttab_channel_stimulus_d2c, /* phase two disconnect completed */ + xenidc_gnttab_channel_stimulus_d1c, /* phase one disconnect completed */ + xenidc_gnttab_channel_stimulus_ksc, /* kick send ring completed */ + xenidc_gnttab_channel_stimulus_krc, /* kick recv ring completed */ + xenidc_gnttab_channel_stimulus_trb, /* target resources busy */ + xenidc_gnttab_channel_stimulus_trc, /* target resource completed */ + xenidc_gnttab_channel_stimulus_tri, /* target resources idle */ + xenidc_gnttab_channel_stimulus_err /* protocol error */ +} +xenidc_gnttab_channel_stimulus; + +static void xenidc_gnttab_channel_handle_stimulus + ( xenidc_gnttab_channel * channel, xenidc_gnttab_channel_stimulus stimulus ); + +static void xenidc_gnttab_channel_submit_message + ( xenidc_channel * base_channel, xenidc_channel_message * message ); + +static int xenidc_gnttab_channel_init_or_exit + ( xenidc_gnttab_channel * channel, int exit ); + +int xenidc_gnttab_channel_init +( + xenidc_gnttab_channel * channel, + void ( * protocol_error )( xenidc_gnttab_channel * channel ) +) +{ + trace(); + + xenidc_channel_init + ( &channel->channel, xenidc_gnttab_channel_submit_message ); + + channel->protocol_error = protocol_error; + + return xenidc_gnttab_channel_init_or_exit( channel, 0 ); +} + +static void xenidc_gnttab_channel_do_phase_one_connect_1( void * data ); + +static void xenidc_gnttab_channel_do_phase_two_connect_1( void * data ); + +static void xenidc_gnttab_channel_connect_client_1( void * data ); + +static void xenidc_gnttab_channel_disconnect_client_1( void * data ); + +static void xenidc_gnttab_channel_disconnect_client_2 + ( xenidc_callback * callback ); + +static void xenidc_gnttab_channel_do_phase_two_disconnect_1( void * data ); + +static void xenidc_gnttab_channel_do_phase_one_disconnect_1( void * data ); + +static void xenidc_gnttab_channel_kick_send_ring_1( void * data ); + +static void xenidc_gnttab_channel_kick_recv_ring_1( void * data ); + +static void xenidc_gnttab_channel_kick_recv_ring_2 + ( xenidc_callback * callback ); + +static int xenidc_gnttab_channel_init_or_exit + ( xenidc_gnttab_channel * channel, int exit ) +{ + trace(); + + { + int return_value = 0; + + if( exit ) + { + goto EXIT; + } + + channel->send_irq_context = channel; + channel->recv_irq_context = channel; + + channel->send_ring = (void *)__get_free_page( GFP_KERNEL ); + + if( channel->send_ring == NULL ) + { + trace0( "failed to allocate send ring" ); + + return_value = -ENOMEM; + + goto EXIT_NO_SEND_RING; + } + + if + ( + ( channel->recv_ring_area = alloc_vm_area( PAGE_SIZE ) ) + == + NULL + ) + { + trace0( "failed to allocate receive ring area" ); + + return_value = -ENOMEM; + + goto EXIT_NO_RING_AREA; + } + + return_value = + gnttab_alloc_grant_references( 1, &channel->grant_ref_pool ); + + if( return_value != 0 ) + { + trace0( "failed to allocate grant reference pool" ); + + goto EXIT_NO_GRANT_REF; + } + + spin_lock_init( &channel->lock ); + + channel->state = xenidc_gnttab_channel_state_i; + + INIT_LIST_HEAD( &channel->message_list ); + + xenidc_work_init + ( + &channel->do_phase_one_connect_1_work, + xenidc_gnttab_channel_do_phase_one_connect_1, + channel + ); + + xenidc_work_init + ( + &channel->do_phase_two_connect_1_work, + xenidc_gnttab_channel_do_phase_two_connect_1, + channel + ); + + xenidc_work_init + ( + &channel->connect_client_1_work, + xenidc_gnttab_channel_connect_client_1, + channel + ); + + xenidc_work_init + ( + &channel->disconnect_client_1_work, + xenidc_gnttab_channel_disconnect_client_1, + channel + ); + + xenidc_callback_init + ( + &channel->disconnect_client_2_callback, + xenidc_gnttab_channel_disconnect_client_2 + ); + + xenidc_work_init + ( + &channel->do_phase_two_disconnect_1_work, + xenidc_gnttab_channel_do_phase_two_disconnect_1, + channel + ); + + xenidc_work_init + ( + &channel->do_phase_one_disconnect_1_work, + xenidc_gnttab_channel_do_phase_one_disconnect_1, + channel + ); + + xenidc_work_init + ( + &channel->kick_send_ring_1_work, + xenidc_gnttab_channel_kick_send_ring_1, + channel + ); + + xenidc_work_init + ( + &channel->kick_recv_ring_1_work, + xenidc_gnttab_channel_kick_recv_ring_1, + channel + ); + + INIT_LIST_HEAD( &channel->free_target_resource_list ); + + { + int i; + + for( i = 0; i < XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT; i++ ) + { + xenidc_gnttab_channel_target_resource * resource = + &channel->target_resources[ i ]; + + xenidc_gnttab_channel_target_resource_init + ( + resource, + channel, + xenidc_gnttab_channel_kick_recv_ring_2 + ); + + list_add_tail + ( + xenidc_gnttab_channel_target_resource_to_link( resource ), + &channel->free_target_resource_list + ); + } + } + + channel->target_resources_out = 0; + + return 0; + + EXIT: + + gnttab_free_grant_references( channel->grant_ref_pool ); + + EXIT_NO_GRANT_REF: + + free_vm_area( channel->recv_ring_area ); + + EXIT_NO_RING_AREA: + + free_page( (unsigned long)channel->send_ring ); + + EXIT_NO_SEND_RING: + + return return_value; + } +} + +void xenidc_gnttab_channel_phase_one_connect +( + xenidc_gnttab_channel * channel, + xenidc_gnttab_channel_phase_one_connect_request * request +) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + channel->current_callback = &request->callback; + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_c1r ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +void xenidc_gnttab_channel_phase_two_connect +( + xenidc_gnttab_channel * channel, + xenidc_gnttab_channel_phase_two_connect_request * request +) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + channel->current_callback = &request->callback; + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_c2r ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +static void xenidc_gnttab_channel_submit_message + ( xenidc_channel * base_channel, xenidc_channel_message * message ) +{ + trace(); + + { + xenidc_gnttab_channel * channel = + xenidc_gnttab_channel_channel_to( base_channel ); + + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + list_add_tail + ( + xenidc_channel_message_to_link( message ), + &channel->message_list + ); + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_mqr ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +void xenidc_gnttab_channel_phase_two_disconnect + ( xenidc_gnttab_channel * channel, xenidc_callback * callback ) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + channel->current_callback = callback; + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_d2r ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +void xenidc_gnttab_channel_phase_one_disconnect + ( xenidc_gnttab_channel * channel, xenidc_callback * callback ) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + channel->current_callback = callback; + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_d1r ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +void xenidc_gnttab_channel_exit( xenidc_gnttab_channel * channel ) +{ + trace(); + + (void)xenidc_gnttab_channel_init_or_exit( channel, 1 ); +} + +static irqreturn_t xenidc_gnttab_channel_send_interrupt + ( int irq, void * context, struct pt_regs * ptregs ) +{ + trace(); + + { + xenidc_gnttab_channel * channel = *(xenidc_gnttab_channel **)context; + + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_sir ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + + return IRQ_HANDLED; +} + +static irqreturn_t xenidc_gnttab_channel_recv_interrupt + ( int irq, void * context, struct pt_regs * ptregs ) +{ + trace(); + + { + xenidc_gnttab_channel * channel = *(xenidc_gnttab_channel **)context; + + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_rir ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + + return IRQ_HANDLED; +} + +static void xenidc_gnttab_channel_invalid_stimulus + ( xenidc_gnttab_channel * channel, xenidc_gnttab_channel_stimulus stimulus ); + +static void xenidc_gnttab_channel_do_phase_one_connect + ( xenidc_gnttab_channel * channel ); + +static void xenidc_gnttab_channel_do_phase_two_connect + ( xenidc_gnttab_channel * channel ); + +static void xenidc_gnttab_channel_connect_client + ( xenidc_gnttab_channel * channel ); + +static void xenidc_gnttab_channel_disconnect_client + ( xenidc_gnttab_channel * channel ); + +static void xenidc_gnttab_channel_do_phase_two_disconnect + ( xenidc_gnttab_channel * channel ); + +static void xenidc_gnttab_channel_do_phase_one_disconnect + ( xenidc_gnttab_channel * channel ); + +static void xenidc_gnttab_channel_kick_send_ring + ( xenidc_gnttab_channel * channel ); + +static void xenidc_gnttab_channel_kick_recv_ring + ( xenidc_gnttab_channel * channel ); + +static void xenidc_gnttab_channel_complete_current_callback + ( xenidc_gnttab_channel * channel ); + +static void xenidc_gnttab_channel_fail_current_callback + ( xenidc_gnttab_channel * channel ); + +static void xenidc_gnttab_channel_fail_out_messages + ( xenidc_gnttab_channel * channel ); + +static void xenidc_gnttab_channel_handle_stimulus + ( xenidc_gnttab_channel * channel, xenidc_gnttab_channel_stimulus stimulus ) +{ + trace3 + ( + "channel %p in state %d received stimulus %d", + channel, + channel->state, + stimulus + ); + + /* FIXME: implement state machine */ + + switch( channel->state ) + { + case xenidc_gnttab_channel_state_i: + switch( stimulus ) + { + default: + xenidc_gnttab_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + default: + xenidc_gnttab_channel_invalid_stimulus( channel, stimulus ); + break; + } +} + +static void xenidc_gnttab_channel_invalid_stimulus + ( xenidc_gnttab_channel * channel, xenidc_gnttab_channel_stimulus stimulus ) +{ + trace(); + + printk + ( + KERN_ERR "xenidc: channel %p in state %d" + "received invalid stimulus %d", + channel, + channel->state, + stimulus + ); +} + +static void xenidc_gnttab_channel_do_phase_one_connect + ( xenidc_gnttab_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->do_phase_one_connect_1_work ); +} + +static void xenidc_gnttab_channel_do_phase_one_connect_1( void * data ) +{ + trace(); + + { + xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data; + + xenidc_gnttab_channel_phase_one_connect_request * request = + xenidc_gnttab_channel_phase_one_connect_request_callback_to + ( channel->current_callback ); + + { + evtchn_op_t op = + { + .cmd = EVTCHNOP_alloc_unbound, + .u.alloc_unbound.dom = request->remote_domain_id + }; + + BUG_ON( HYPERVISOR_event_channel_op( &op ) != 0 ); + + channel->send_event_channel = op.u.alloc_unbound.port; + } + + { + int error = bind_evtchn_to_irqhandler + ( + channel->send_event_channel, + xenidc_gnttab_channel_send_interrupt, + SA_SAMPLE_RANDOM, + "xenidc", + &channel->send_irq_context + ); + + BUG_ON( error < 0 ); + + channel->send_irq = error; + } + + channel->send_ring_ref = + gnttab_claim_grant_reference( &channel->grant_ref_pool ); + + gnttab_grant_foreign_access_ref + ( + channel->send_ring_ref, + request->remote_domain_id, + virt_to_mfn( channel->send_ring ), + 1 /* readonly */ + ); + + request->send_ring_ref = channel->send_ring_ref; + request->send_event_channel = channel->send_event_channel; + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_c1c ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + } +} + +static void xenidc_gnttab_channel_do_phase_two_connect + ( xenidc_gnttab_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->do_phase_two_connect_1_work ); +} + +static void xenidc_gnttab_channel_do_phase_two_connect_1( void * data ) +{ + trace(); + + { + xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data; + + xenidc_gnttab_channel_phase_two_connect_request * request = + xenidc_gnttab_channel_phase_two_connect_request_callback_to + ( channel->current_callback ); + + { + struct gnttab_map_grant_ref op = + { + .host_addr = (unsigned long)channel->recv_ring_area->addr, + .flags = GNTMAP_host_map | GNTMAP_readonly, + .dom = request->remote_domain_id, + .ref = request->recv_ring_ref + }; + + lock_vm_area( channel->recv_ring_area ); + + BUG_ON + ( HYPERVISOR_grant_table_op( GNTTABOP_map_grant_ref, &op, 1 ) ); + + unlock_vm_area( channel->recv_ring_area ); + + if( op.handle < 0 ) + { + trace0( "failed to map remote page" ); + + goto EXIT_NO_MAPPING; + } + + channel->recv_ring_handle = op.handle; + } + + { + evtchn_op_t op = + { + .cmd = EVTCHNOP_bind_interdomain, + .u.bind_interdomain.remote_dom = request->remote_domain_id, + .u.bind_interdomain.remote_port = request->recv_event_channel + }; + + if( HYPERVISOR_event_channel_op( &op ) != 0 ) + { + trace0( "failed to bind to remote event channel" ); + + goto EXIT_NO_BIND; + } + + channel->recv_event_channel = op.u.bind_interdomain.local_port; + } + + channel->recv_irq = bind_evtchn_to_irqhandler + ( + channel->recv_event_channel, + xenidc_gnttab_channel_recv_interrupt, + 0, + "xenidc", + &channel->recv_irq_context + ); + + if( channel->recv_irq < 0 ) + { + trace0( "failed to bind remote irq" ); + + goto EXIT_NO_IRQ; + } + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_c2s ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + + return; + + EXIT_NO_IRQ: + + { + evtchn_op_t op = + { + .cmd = EVTCHNOP_close, + .u.close.port = channel->recv_event_channel + }; + + BUG_ON( HYPERVISOR_event_channel_op( &op ) != 0 ); + } + + EXIT_NO_BIND: + + { + struct gnttab_unmap_grant_ref op; + + op.host_addr = (unsigned long)channel->recv_ring_area->addr; + op.handle = channel->recv_ring_handle; + op.dev_bus_addr = 0; + + lock_vm_area( channel->recv_ring_area ); + + BUG_ON + ( + HYPERVISOR_grant_table_op( GNTTABOP_unmap_grant_ref, &op, 1 ) + ); + + unlock_vm_area( channel->recv_ring_area ); + } + + EXIT_NO_MAPPING: + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_c2f ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + } +} + +static void xenidc_gnttab_channel_connect_client + ( xenidc_gnttab_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->connect_client_1_work ); +} + +static void xenidc_gnttab_channel_connect_client_1( void * data ) +{ + trace(); + + { + xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data; + + xenidc_channel_connect( &channel->channel ); + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_ccc ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + } +} + +static void xenidc_gnttab_channel_disconnect_client + ( xenidc_gnttab_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->disconnect_client_1_work ); +} + +static void xenidc_gnttab_channel_disconnect_client_1( void * data ) +{ + trace(); + + { + xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data; + + xenidc_channel_disconnect + ( &channel->channel, &channel->disconnect_client_2_callback ); + } +} + +static void xenidc_gnttab_channel_disconnect_client_2 + ( xenidc_callback * callback ) +{ + trace(); + + { + xenidc_gnttab_channel * channel = container_of + ( callback, xenidc_gnttab_channel, disconnect_client_2_callback ); + + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_dcc ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +static void xenidc_gnttab_channel_do_phase_two_disconnect + ( xenidc_gnttab_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->do_phase_two_disconnect_1_work ); +} + +static void xenidc_gnttab_channel_do_phase_two_disconnect_1( void * data ) +{ + trace(); + + { + xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data; + + unbind_evtchn_from_irqhandler + ( channel->recv_irq, &channel->recv_irq_context ); + + { + struct gnttab_unmap_grant_ref op; + + op.host_addr = (unsigned long)channel->recv_ring_area->addr; + op.handle = channel->recv_ring_handle; + op.dev_bus_addr = 0; + + lock_vm_area( channel->recv_ring_area ); + + BUG_ON + ( + HYPERVISOR_grant_table_op( GNTTABOP_unmap_grant_ref, &op, 1 ) + ); + + unlock_vm_area( channel->recv_ring_area ); + } + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_d2c ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + } +} + +static void xenidc_gnttab_channel_do_phase_one_disconnect + ( xenidc_gnttab_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->do_phase_one_disconnect_1_work ); +} + +static void xenidc_gnttab_channel_do_phase_one_disconnect_1( void * data ) +{ + trace(); + + { + xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data; + + gnttab_end_foreign_access_ref( channel->send_ring_ref, 1 ); + + /* FIXME: need to make sure other side is no longer referencing page.*/ + + gnttab_release_grant_reference + ( &channel->grant_ref_pool, channel->send_ring_ref ); + + unbind_evtchn_from_irqhandler + ( channel->send_irq, &channel->send_irq_context ); + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_d1c ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + } +} + +static void xenidc_gnttab_channel_kick_send_ring + ( xenidc_gnttab_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->kick_send_ring_1_work ); +} + +static void xenidc_gnttab_channel_kick_send_ring_1( void * data ) +{ + trace(); + + { + xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data; + + int notify = 0; + + /* Create a reference to the send ring buffer. */ + + xenidc_local_buffer_reference ring_buffer_reference = + xenidc_vaddress_create_lbr + ( + ( (xenidc_channel_ring_header *)channel->send_ring ) + 1, + PAGE_SIZE - sizeof( xenidc_channel_ring_header ) + ); + + /* Create a reference to the free space in the send ring buffer. */ + /* We use a wrapping reference to the above buffer so that we can */ + /* copy into the buffer and wrap automatically. */ + + xenidc_local_buffer_reference wrapping_lbr = xenidc_wrapping_create_lbr + ( + &ring_buffer_reference, + ( (xenidc_channel_ring_header *)channel->send_ring )-> + this_ring_producer_offset, + ( + (xenidc_channel_ring_header *) + channel->recv_ring_area->addr + ) + ->other_ring_consumer_offset, + xenidc_wrapping_client_type_producer + ); + + xenidc_channel_message * message; + + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + while + ( + ( !list_empty( &channel->message_list ) ) + && + ( + xenidc_local_buffer_reference_query_byte_count( &wrapping_lbr ) + > + xenidc_local_buffer_reference_query_byte_count + ( + & + ( + message = list_entry + ( + channel->message_list.next, + xenidc_channel_message, + XENIDC_CHANNEL_MESSAGE_LINK + ) + ) + ->lbr + ) + ) + ) + { + list_del_init( xenidc_channel_message_to_link( message ) ); + + spin_unlock_irqrestore( &channel->lock, flags ); + + xenidc_local_buffer_reference_advance + ( + &wrapping_lbr, + xenidc_local_buffer_reference_copy + ( &wrapping_lbr, &message->lbr ) + ); + + xenidc_callback_success + ( xenidc_channel_message_to_callback( message ) ); + + notify = 1; + + spin_lock_irqsave( &channel->lock, flags ); + } + + spin_unlock_irqrestore( &channel->lock, flags ); + + if( notify ) + { + wmb(); /* Ensure contents of ring written before offset updated. */ + + ( (xenidc_channel_ring_header *)channel->send_ring )-> + this_ring_producer_offset = + xenidc_local_buffer_reference_query_byte_offset + ( &wrapping_lbr ); + + notify_remote_via_irq( channel->send_irq ); + } + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_ksc ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +static void xenidc_gnttab_channel_kick_recv_ring + ( xenidc_gnttab_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->kick_recv_ring_1_work ); +} + +static void xenidc_gnttab_channel_kick_recv_ring_1( void * data ) +{ + trace(); + + { + xenidc_gnttab_channel * channel = (xenidc_gnttab_channel *)data; + + int notify = 0; + int error = 0; + + /* Create a reference to the recv ring buffer. */ + + xenidc_local_buffer_reference ring_buffer_reference = + xenidc_vaddress_create_lbr + ( + ( + (xenidc_channel_ring_header *) + channel->recv_ring_area->addr + ) + 1, + PAGE_SIZE - sizeof( xenidc_channel_ring_header ) + ); + + /* Create a reference to the elements in the recv ring buffer. */ + /* We use a wrapping reference to the above buffer so that we can */ + /* copy out of the buffer and wrap automatically. */ + + xenidc_local_buffer_reference wrapping_lbr = xenidc_wrapping_create_lbr + ( + &ring_buffer_reference, + ( (xenidc_channel_ring_header *)channel->send_ring )-> + other_ring_consumer_offset, + ( + (xenidc_channel_ring_header *) + channel->recv_ring_area->addr + ) + ->this_ring_producer_offset, + xenidc_wrapping_client_type_consumer + ); + + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + rmb(); /* Ensure we see latest data for contents of wrapping buffer. */ + + while + ( + ( !list_empty( &channel->free_target_resource_list ) ) + && + ( + xenidc_local_buffer_reference_query_byte_count( &wrapping_lbr ) + != + 0 + ) + ) + { + xenidc_local_buffer_reference element = wrapping_lbr; + + xenidc_gnttab_channel_target_resource * resource = list_entry + ( + channel->free_target_resource_list.next, + xenidc_gnttab_channel_target_resource, + XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_LINK + ); + + { + xenidc_channel_ring_element_header header; + + if + ( + ( + xenidc_local_buffer_reference_copy_out + ( &wrapping_lbr, &header, sizeof( header ) ) + == + sizeof( header ) + ) + && + ( + xenidc_local_buffer_reference_truncate + ( &element, header.length ) + == + header.length + ) + ) + { + list_del_init + ( + xenidc_gnttab_channel_target_resource_to_link + ( resource ) + ); + + if( channel->target_resources_out++ == 0 ) + { + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_trb ); + } + } + else + { + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_err ); + + error = 1; + + break; + } + + xenidc_local_buffer_reference_advance + ( &wrapping_lbr, header.length ); + } + + spin_unlock_irqrestore( &channel->lock, flags ); + + { + xenidc_channel_message * message = + xenidc_gnttab_channel_target_resource_to_message( resource ); + + xenidc_channel_message_set_message_lbr( message, element ); + + xenidc_channel_handle_message( &channel->channel, message ); + } + + notify = 1; + + spin_lock_irqsave( &channel->lock, flags ); + } + + spin_unlock_irqrestore( &channel->lock, flags ); + + if( notify ) + { + mb(); /* Ensure reads complete before we free space. */ + + ( (xenidc_channel_ring_header *)channel->send_ring )-> + other_ring_consumer_offset = + xenidc_local_buffer_reference_query_byte_offset + ( &wrapping_lbr ); + + notify_remote_via_irq( channel->recv_irq ); + } + + if( error ) + { + channel->protocol_error( channel ); + } + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_krc ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + } +} + +static void xenidc_gnttab_channel_kick_recv_ring_2 + ( xenidc_callback * callback ) +{ + trace(); + + { + xenidc_gnttab_channel_target_resource * resource = + xenidc_gnttab_channel_target_resource_callback_to( callback ); + + xenidc_gnttab_channel * channel = + xenidc_gnttab_channel_target_resource_query_channel( resource ); + + int error = + ( xenidc_callback_query_error( callback ) != XENIDC_ERROR_SUCCESS ); + + if( error ) + { + channel->protocol_error( channel ); + } + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + list_add_tail + ( + xenidc_gnttab_channel_target_resource_to_link( resource ), + &channel->free_target_resource_list + ); + + if( error ) + { + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_err ); + } + + if( --channel->target_resources_out != 0 ) + { + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_trc ); + } + else + { + xenidc_gnttab_channel_handle_stimulus + ( channel, xenidc_gnttab_channel_stimulus_tri ); + } + + spin_unlock_irqrestore( &channel->lock, flags ); + } + } +} + +static void xenidc_gnttab_channel_complete_current_callback + ( xenidc_gnttab_channel * channel ) +{ + trace(); + + xenidc_callback_success( channel->current_callback ); +} + +static void xenidc_gnttab_channel_fail_current_callback + ( xenidc_gnttab_channel * channel ) +{ + trace(); + + xenidc_callback_complete + ( channel->current_callback, XENIDC_ERROR_FAILURE ); +} + +static void xenidc_gnttab_channel_fail_out_messages + ( xenidc_gnttab_channel * channel ) +{ + trace(); + + while( !list_empty( &channel->message_list ) ) + { + xenidc_channel_message * message = list_entry + ( + channel->message_list.next, + xenidc_channel_message, + XENIDC_CHANNEL_MESSAGE_LINK + ); + + list_del_init( xenidc_channel_message_to_link( message ) ); + + xenidc_callback_success + ( xenidc_channel_message_to_callback( message ) ); + } +} diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_local_buffer_reference.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_local_buffer_reference.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,55 @@ +/*****************************************************************************/ +/* Xen inter-domain communication local buffer references. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include "xenidc_trace.h" + +xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_out +( + xenidc_local_buffer_reference * buffer_reference, + void * target, + xenidc_buffer_byte_count target_byte_count +) +{ + trace(); + + /* FIXME */ + + return 0; +} + +xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_in +( + xenidc_local_buffer_reference * buffer_reference, + void * source, + xenidc_buffer_byte_count source_byte_count +) +{ + trace(); + + /* FIXME */ + + return 0; +} + +EXPORT_SYMBOL( xenidc_local_buffer_reference_copy_out ); +EXPORT_SYMBOL( xenidc_local_buffer_reference_copy_in ); diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_mapper_pool.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_mapper_pool.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,80 @@ +/*****************************************************************************/ +/* Xen remote buffer reference mapper pool. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include "xenidc_trace.h" + +xenidc_rbr_mapper_pool * xenidc_allocate_rbr_mapper_pool + ( u32 anti_deadlock_page_count ) +{ + trace(); + + /* FIXME */ + + return 1; +} + +void xenidc_free_rbr_mapper_pool( xenidc_rbr_mapper_pool * pool ) +{ + trace(); + + /* FIXME */ +} + +void xenidc_rbr_mapper_pool_reserve_and_map_rbrs +( + xenidc_rbr_mapper_pool * pool, + xenidc_reserve_and_map_rbr_request * request +) +{ + trace(); + + /* FIXME */ +} + +void xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs +( + xenidc_rbr_mapper_pool * pool, + xenidc_reserve_and_map_rbr_request * request +) +{ + trace(); + + /* FIXME */ +} + +void xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs +( + xenidc_rbr_mapper_pool * pool, + xenidc_reserve_and_map_rbr_request * request +) +{ + trace(); + + /* FIXME */ +} + +EXPORT_SYMBOL( xenidc_allocate_rbr_mapper_pool ); +EXPORT_SYMBOL( xenidc_free_rbr_mapper_pool ); +EXPORT_SYMBOL( xenidc_rbr_mapper_pool_reserve_and_map_rbrs ); +EXPORT_SYMBOL( xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs ); +EXPORT_SYMBOL( xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs ); diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_provider_pool.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_rbr_provider_pool.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,80 @@ +/*****************************************************************************/ +/* Xen remote buffer reference provider pool. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include "xenidc_trace.h" + +xenidc_rbr_provider_pool * xenidc_allocate_rbr_provider_pool + ( u32 anti_deadlock_page_count ) +{ + trace(); + + /* FIXME */ + + return 1; +} + +void xenidc_free_rbr_provider_pool( xenidc_rbr_provider_pool * pool ) +{ + trace(); + + /* FIXME */ +} + +void xenidc_rbr_provider_pool_reserve_and_create_rbrs +( + xenidc_rbr_provider_pool * pool, + xenidc_reserve_and_create_rbr_request * request +) +{ + trace(); + + /* FIXME */ +} + +void xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs +( + xenidc_rbr_provider_pool * pool, + xenidc_reserve_and_create_rbr_request * request +) +{ + trace(); + + /* FIXME */ +} + +void xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs +( + xenidc_rbr_provider_pool * pool, + xenidc_reserve_and_create_rbr_request * request +) +{ + trace(); + + /* FIXME */ +} + +EXPORT_SYMBOL( xenidc_allocate_rbr_provider_pool ); +EXPORT_SYMBOL( xenidc_free_rbr_provider_pool ); +EXPORT_SYMBOL( xenidc_rbr_provider_pool_reserve_and_create_rbrs ); +EXPORT_SYMBOL( xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs ); +EXPORT_SYMBOL( xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs ); diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_trace.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_trace.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,54 @@ +/*****************************************************************************/ +/* Simple trace macros. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef XENIDC_TRACE_H +#define XENIDC_TRACE_H + +#include +#include + +#ifdef CONFIG_XEN_IDC_TRACE + +#define trace0( format ) \ +printk( KERN_INFO "xenidc %s:" format "\n", __PRETTY_FUNCTION__ ) + +#define trace1( format, a0 ) \ +printk( KERN_INFO "xenidc %s:" format "\n", __PRETTY_FUNCTION__, a0 ) + +#define trace2( format, a0, a1 ) \ +printk( KERN_INFO "xenidc %s:" format "\n", __PRETTY_FUNCTION__, a0, a1 ) + +#define trace3( format, a0, a1, a2 ) \ +printk( KERN_INFO "xenidc %s:" format "\n", __PRETTY_FUNCTION__, a0, a1, a2 ) + +#define trace() trace0( "" ) + +#else + +#define trace0( format ) +#define trace1( format,a0 ) +#define trace2( format,a0, a1 ) +#define trace3( format,a0, a1, a2 ) +#define trace() + +#endif + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_vaddress.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_vaddress.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,42 @@ +/*****************************************************************************/ +/* Xen inter-domain communication vaddress local buffer reference type. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include "xenidc_trace.h" + +xenidc_local_buffer_reference xenidc_vaddress_create_lbr + ( void * address, xenidc_buffer_byte_count byte_count ) +{ + trace(); + + /* FIXME */ + + { + xenidc_local_buffer_reference lbr; + + memset( &lbr, 0, sizeof( lbr ) ); + + return lbr; + } +} + +EXPORT_SYMBOL( xenidc_vaddress_create_lbr ); diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_work.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_work.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,110 @@ +/*****************************************************************************/ +/* Enhanced work queue service */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include "xenidc_work.h" + +DEFINE_SPINLOCK( xenidc_work_list_lock ); + +LIST_HEAD( xenidc_work_list ); + +static void xenidc_work_function( void * ignored ); + +DECLARE_WORK( xenidc_work_work, xenidc_work_function, NULL ); + +DECLARE_WAIT_QUEUE_HEAD( xenidc_work_waitqueue ); + +LIST_HEAD( xenidc_work_condition ); + +void xenidc_work_wake_up( void ) +{ + unsigned long flags; + + spin_lock_irqsave( &xenidc_work_list_lock, flags ); + + while( !list_empty( &xenidc_work_condition ) ) + { + list_del_init( xenidc_work_condition.next ); + } + + spin_unlock_irqrestore( &xenidc_work_list_lock, flags ); + + wake_up( &xenidc_work_waitqueue ); +} + +int xenidc_work_schedule( xenidc_work * work ) +{ + int scheduled = 0; + + unsigned long flags; + + spin_lock_irqsave( &xenidc_work_list_lock, flags ); + + if( list_empty( &work->link ) ) + { + list_add_tail( &work->link, &xenidc_work_list ); + + scheduled = 1; + } + + spin_unlock_irqrestore( &xenidc_work_list_lock, flags ); + + if( scheduled ) + { + xenidc_work_wake_up(); + + schedule_work( &xenidc_work_work ); + } + + return scheduled; +} + +static void xenidc_work_function( void * ignored ) +{ + unsigned long flags; + + spin_lock_irqsave( &xenidc_work_list_lock, flags ); + + while( !list_empty( &xenidc_work_list ) ) + { + xenidc_work * work = list_entry + ( + xenidc_work_list.next, + xenidc_work, + link + ); + + list_del_init( &work->link ); + + spin_unlock_irqrestore( &xenidc_work_list_lock, flags ); + + xenidc_work_perform_synchronously( work ); + + spin_lock_irqsave( &xenidc_work_list_lock, flags ); + } + + spin_unlock_irqrestore( &xenidc_work_list_lock, flags ); +} + +EXPORT_SYMBOL( xenidc_work_schedule ); +EXPORT_SYMBOL( xenidc_work_list ); +EXPORT_SYMBOL( xenidc_work_condition ); +EXPORT_SYMBOL( xenidc_work_waitqueue ); +EXPORT_SYMBOL( xenidc_work_wake_up ); diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_wrapping.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_wrapping.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,47 @@ +/*****************************************************************************/ +/* Xen inter-domain communication wrapping local buffer reference type. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include "xenidc_trace.h" + +xenidc_local_buffer_reference xenidc_wrapping_create_lbr +( + xenidc_local_buffer_reference * underlying_buffer, + xenidc_buffer_byte_count start_offset, + xenidc_buffer_byte_count end_offset, + xenidc_wrapping_client_type client_type +) +{ + trace(); + + /* FIXME */ + + { + xenidc_local_buffer_reference lbr; + + memset( &lbr, 0, sizeof( lbr ) ); + + return lbr; + } +} + +EXPORT_SYMBOL( xenidc_wrapping_create_lbr ); diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel.c --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel.c Mon Oct 24 15:04:49 2005 @@ -0,0 +1,1732 @@ +/*****************************************************************************/ +/* Xen inter-domain communication channel implementation based on xenbus and */ +/* grant tables. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* The state machine below makes the following assumptions: */ +/* */ +/* 1) The store might contain some stale cruft from the last time our device */ +/* driver failed. This is a handy assumption for testing new versions of */ +/* the driver but isn't strictly necessary. */ +/* */ +/* 2) If the other side generates a protocol error on the inter-domain */ +/* connection then we attempt to disconnect and reconnect. An alternative */ +/* behaviour would be to wait for our interface to be called to disconnect */ +/* and then reconnect before retrying. */ +/* */ +/* 3) If we experience an internal failure (fail to register watch for */ +/* example) then we attempt to disconnect and wait for our interface to be */ +/* called to disconnect (by module unload for example) and reconnect before */ +/* retrying. */ +/* */ +/* 4) Connection and disconnection of the channel is done in two phases: the */ +/* first phase makes the local resources available to the remote side, the */ +/* second phase uses the resources of the remote side to complete the */ +/* connection. */ +/* */ +/* The key for the stimuli is as follows: */ +/* */ +/* cn: interface called to connect the channel when interface state is */ +/* disconnected (for example on module load). */ +/* */ +/* pe: protocol error detected when channel is in a state between phase two */ +/* connected and the completion of the phase two disconnect callback. */ +/* */ +/* dn: interface called to disconnect the channel when the interface state */ +/* is connected (for example on module unload). */ +/* */ +/* ou: a synchronous stimulus from the response test_other_state which */ +/* indicates that the other state is still unknown because the watch */ +/* callback hasn't happened yet. Can only happen when making the response */ +/* test_other_state. */ +/* */ +/* od: other state is disconnected. This is both a synchronous stimulus */ +/* from test_other_state and an asynchronous stimulus from the watch */ +/* function. Disconnected means that we can't read the at least the other */ +/* side's ready node from the store. */ +/* */ +/* or: other state is ready. This is both a synchronous stimulus from */ +/* test_other_state and an asynchronous stimulus from the watch function. */ +/* Ready means that we can see the other side's ready node but not the */ +/* ring-reference and event-channel information. */ +/* */ +/* oc: other state is connected. This is both a synchronous stimulus from */ +/* test_other_state and an asynchronous stimulus from the watch function. */ +/* Connected means that we found both the ready node and the connected */ +/* information in the store. */ +/* */ +/* If the values of the connected information change when the other side is */ +/* connected then we generate the 'oc' stimulus again which forces a */ +/* reconnect. */ +/* */ +/* rs: An asynchronous response was successful (we only make one response at */ +/* a time so all asynchronous responses have the same completion stimuli). */ +/* */ +/* rf: An asynchronous response failed. Only register_watch, clear_store, */ +/* write_ready, write_connected, phase_two_connect can fail. Only */ +/* phase_two_connect has a good reason for failure: the other side might */ +/* have passed bogus parameters; the other failures are poor API design and */ +/* ought to be promoted to domain failures. */ +/* */ +/* The state machine responses are as follows: */ +/* */ +/* test_other_state: what state do we currently think the other side is in */ +/* as reflected by the last watch event. Synchronous (called with the lock */ +/* held) completes with ou/od/or/oc. */ +/* */ +/* register_watch: register a watch on the other side. */ +/* */ +/* unregister_watch: unregister the watch. */ +/* */ +/* clear_store: remove the ready node and connected information. */ +/* */ +/* write_ready: write the ready node to the store. */ +/* */ +/* write_connected: write the connected information to the store. */ +/* */ +/* phase_one_connect: grant the remote side access to the local page etc. */ +/* */ +/* phase_two_connect: map the remote page etc. */ +/* */ +/* phase_two_disconnect: unmap the remote page. */ +/* */ +/* phase_one_disconnect: revoke the access of the remote side. */ +/* */ +/* complete_disconnect: When our interface is called to get us to disconnect */ +/* the channel we quiesce and disconnect and then call this to indicate we */ +/* are done. */ +/* */ +/*****************************************************************************/ + +#include +#include +#include "xenidc_trace.h" + +typedef enum +{ + xenidc_xbgt_channel_stimulus_cn, /* Connect: disconnected */ + xenidc_xbgt_channel_stimulus_pe, /* Protocol error: ph2c->ph2dc inclusive*/ + xenidc_xbgt_channel_stimulus_dn, /* Disconnect: connected */ + xenidc_xbgt_channel_stimulus_ou, /* Other unknown: test other state only */ + xenidc_xbgt_channel_stimulus_od, /* Other disconnected: watch / test */ + xenidc_xbgt_channel_stimulus_or, /* Other ready: watch / test */ + xenidc_xbgt_channel_stimulus_oc, /* Other connected: watch / test */ + xenidc_xbgt_channel_stimulus_rs, /* Response successful: making response */ + xenidc_xbgt_channel_stimulus_rf /* Response failed: r. watch, tra, ph2c */ +} +xenidc_xbgt_channel_stimulus; + +static void xenidc_xbgt_channel_handle_stimulus + ( xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus ); + +static int xenidc_xbgt_channel_init_or_exit + ( xenidc_xbgt_channel * channel, int exit ); + +int xenidc_xbgt_channel_init( xenidc_xbgt_channel * channel ) +{ + return xenidc_xbgt_channel_init_or_exit( channel, 0 ); +} + +void xenidc_xbgt_channel_connect +( + xenidc_xbgt_channel * channel, + char * local_path, + char * remote_path, + domid_t remote_domain_id +) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + channel->local_path = local_path; + channel->remote_path = remote_path; + channel->remote_domain_id = remote_domain_id; + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_cn ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +static void xenidc_xbgt_channel_watch + ( struct xenbus_watch * watch, const char ** vec, unsigned int len ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = + container_of( watch, xenidc_xbgt_channel, watch ); + + struct xenbus_transaction * transaction = xenbus_transaction_start(); + + if( IS_ERR( transaction ) ) + { + trace0( "error starting transaction" ); + + goto DISCONNECTED; + } + + { + unsigned int event_channel; + unsigned int ring_reference; + unsigned int ready; + + int error = xenbus_gather + ( + transaction, + watch->node, + "ready", "%u", &ready, + "event-channel", "%u", &event_channel, + "ring-reference", "%u", &ring_reference, + NULL + ); + + if( error == 0 ) + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + if + ( + ( + channel->other_state + != + xenidc_xbgt_channel_other_state_connected + ) + || + ( channel->ready_event_channel != event_channel ) + || + ( channel->ready_ring_reference != ring_reference ) + ) + { + channel->other_state = + xenidc_xbgt_channel_other_state_connected; + + channel->ready_event_channel = event_channel; + channel->ready_ring_reference = ring_reference; + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_oc ); + } + + spin_unlock_irqrestore( &channel->lock, flags ); + + xenbus_transaction_end( transaction, 1 /* abort */ ); + + return; + } + } + + { + unsigned int ready; + + int error = xenbus_gather + ( + transaction, + watch->node, + "ready", "%u", &ready, + NULL + ); + + if( error == 0 ) + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + if + ( + ( + channel->other_state + != + xenidc_xbgt_channel_other_state_ready + ) + ) + { + channel->other_state = + xenidc_xbgt_channel_other_state_ready; + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_or ); + } + + spin_unlock_irqrestore( &channel->lock, flags ); + + xenbus_transaction_end( transaction, 1 /* abort */ ); + + return; + } + } + + xenbus_transaction_end( transaction, 1 /* abort */ ); + + DISCONNECTED: + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + if + ( + channel->other_state + != + xenidc_xbgt_channel_other_state_disconnected + ) + { + channel->other_state = + xenidc_xbgt_channel_other_state_disconnected; + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_od ); + } + + spin_unlock_irqrestore( &channel->lock, flags ); + } + } +} + +static void xenidc_xbgt_channel_protocol_error + ( xenidc_gnttab_channel * gnttab_channel ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = + xenidc_xbgt_channel_gnttab_channel_to( gnttab_channel ); + + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_pe ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +void xenidc_xbgt_channel_disconnect + ( xenidc_xbgt_channel * channel, xenidc_callback * callback ) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + channel->disconnect_callback = callback; + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_dn ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +void xenidc_xbgt_channel_exit( xenidc_xbgt_channel * channel ) +{ + trace(); + + (void)xenidc_xbgt_channel_init_or_exit( channel, 1 ); +} + +static void xenidc_xbgt_channel_register_watch_1( void * data ); +static void xenidc_xbgt_channel_unregister_watch_1( void * data ); +static void xenidc_xbgt_channel_clear_store_1( void * data ); +static void xenidc_xbgt_channel_write_ready_1( void * data ); +static void xenidc_xbgt_channel_write_connected_1( void * data ); +static void xenidc_xbgt_channel_phase_one_connect_1( void * data ); +static void xenidc_xbgt_channel_phase_one_connect_2 + ( xenidc_callback * callback ); +static void xenidc_xbgt_channel_phase_two_connect_1( void * data ); +static void xenidc_xbgt_channel_phase_two_connect_2 + ( xenidc_callback * callback ); +static void xenidc_xbgt_channel_phase_two_disconnect_1( void * data ); +static void xenidc_xbgt_channel_phase_two_disconnect_2 + ( xenidc_callback * callback ); +static void xenidc_xbgt_channel_phase_one_disconnect_1( void * data ); +static void xenidc_xbgt_channel_phase_one_disconnect_2 + ( xenidc_callback * callback ); + +static int xenidc_xbgt_channel_init_or_exit + ( xenidc_xbgt_channel * channel, int exit ) +{ + trace(); + + { + int return_value = 0; + + if( exit ) + { + goto EXIT; + } + + if + ( + ( + return_value = xenidc_gnttab_channel_init + ( &channel->channel, xenidc_xbgt_channel_protocol_error ) + ) + != + 0 + ) + { + goto EXIT_NO_GNTTAB_CHANNEL; + } + + xenidc_work_init + ( + &channel->register_watch_1_work, + xenidc_xbgt_channel_register_watch_1, + channel + ); + + xenidc_work_init + ( + &channel->unregister_watch_1_work, + xenidc_xbgt_channel_unregister_watch_1, + channel + ); + + xenidc_work_init + ( + &channel->clear_store_1_work, + xenidc_xbgt_channel_clear_store_1, + channel + ); + + xenidc_work_init + ( + &channel->write_ready_1_work, + xenidc_xbgt_channel_write_ready_1, + channel + ); + + xenidc_work_init + ( + &channel->write_connected_1_work, + xenidc_xbgt_channel_write_connected_1, + channel + ); + + xenidc_work_init + ( + &channel->phase_one_connect_1_work, + xenidc_xbgt_channel_phase_one_connect_1, + channel + ); + + xenidc_work_init + ( + &channel->phase_two_connect_1_work, + xenidc_xbgt_channel_phase_two_connect_1, + channel + ); + + xenidc_work_init + ( + &channel->phase_two_disconnect_1_work, + xenidc_xbgt_channel_phase_two_disconnect_1, + channel + ); + + xenidc_work_init + ( + &channel->phase_one_disconnect_1_work, + xenidc_xbgt_channel_phase_one_disconnect_1, + channel + ); + + xenidc_callback_init + ( + &channel->phase_one_connect_request.callback, + xenidc_xbgt_channel_phase_one_connect_2 + ); + + xenidc_callback_init + ( + &channel->phase_two_connect_request.callback, + xenidc_xbgt_channel_phase_two_connect_2 + ); + + xenidc_callback_init + ( + &channel->phase_two_disconnect_callback, + xenidc_xbgt_channel_phase_two_disconnect_2 + ); + + xenidc_callback_init + ( + &channel->phase_one_disconnect_callback, + xenidc_xbgt_channel_phase_one_disconnect_2 + ); + + return 0; + + EXIT: + + xenidc_gnttab_channel_exit( &channel->channel ); + + EXIT_NO_GNTTAB_CHANNEL: + + return return_value; + } +} + +static void xenidc_xbgt_channel_invalid_stimulus + ( xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus ); + +static void xenidc_xbgt_channel_test_other_state + ( xenidc_xbgt_channel * channel ); + +static void xenidc_xbgt_channel_register_watch + ( xenidc_xbgt_channel * channel ); + +static void xenidc_xbgt_channel_unregister_watch + ( xenidc_xbgt_channel * channel ); + +static void xenidc_xbgt_channel_clear_store + ( xenidc_xbgt_channel * channel ); + +static void xenidc_xbgt_channel_write_ready + ( xenidc_xbgt_channel * channel ); + +static void xenidc_xbgt_channel_write_connected + ( xenidc_xbgt_channel * channel ); + +static void xenidc_xbgt_channel_phase_one_connect + ( xenidc_xbgt_channel * channel ); + +static void xenidc_xbgt_channel_phase_two_connect + ( xenidc_xbgt_channel * channel ); + +static void xenidc_xbgt_channel_phase_two_disconnect + ( xenidc_xbgt_channel * channel ); + +static void xenidc_xbgt_channel_phase_one_disconnect + ( xenidc_xbgt_channel * channel ); + +static void xenidc_xbgt_channel_complete_disconnect + ( xenidc_xbgt_channel * channel ); + +static void xenidc_xbgt_channel_handle_stimulus + ( xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus ) +{ + trace3 + ( + "xbgt channel %p in state %d received stimulus %d", + channel, + channel->state, + stimulus + ); + + switch( channel->state ) + { + case xenidc_xbgt_channel_state_i: + /* Interface disconnected. */ + /* Gnttab channel disconnected. */ + /* Local store unknown. */ + /* Watch not registered. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_cn: + channel->state = xenidc_xbgt_channel_state_i_cn; + xenidc_xbgt_channel_phase_one_connect( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn: + /* Interface connected. */ + /* Gnttab channel phase one connecting. */ + /* Local store unknown. */ + /* Watch not registered. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i_cn_dn; + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_rs; + xenidc_xbgt_channel_register_watch( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_dn: + /* Interface disconnecting. */ + /* Gnttab channel phase one connecting */ + /* Local store unknown. */ + /* Watch not registered. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs; + xenidc_xbgt_channel_clear_store( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs: + /* Interface connected. */ + /* Gnttab channel phase one connected and registering watch or */ + /* Watch registered and gnttab channel phase two disconnecting */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_pe: + break; + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs; + xenidc_xbgt_channel_clear_store( channel ); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf; + xenidc_xbgt_channel_clear_store( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_dn_rs: + /* Interface disconnecting. */ + /* Gnttab channel phase one connected */ + /* Clearing store. */ + /* Watch not registered. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_rs: + case xenidc_xbgt_channel_stimulus_rf: + channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs_rs; + xenidc_xbgt_channel_phase_one_disconnect( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_dn: + /* Interface disconnecting. */ + /* Gnttab channel phase one connected. */ + /* Local store unknown. */ + /* Registering watch. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + xenidc_xbgt_channel_unregister_watch( channel ); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs; + xenidc_xbgt_channel_clear_store( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Clearing Store. */ + /* Watch Registered. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_dn; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rs; + xenidc_xbgt_channel_test_other_state( channel ); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rf; + xenidc_xbgt_channel_unregister_watch( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rf: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Clearing store. */ + /* Something failed. */ + /* Watch not registered. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs; + break; + case xenidc_xbgt_channel_stimulus_rs: + case xenidc_xbgt_channel_stimulus_rf: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf_rs; + xenidc_xbgt_channel_phase_one_disconnect( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_dn_rs_rs: + /* Interface disconnecting. */ + /* Gnttab channel phase one disconnecting */ + /* Attempted to clear store. */ + /* Watch not registered. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i; + xenidc_xbgt_channel_complete_disconnect( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_dn_rs: + /* Interface disconnecting. */ + /* Gnttab channel phase one connected. */ + /* Local store unknown. */ + /* Unregistering watch. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs; + xenidc_xbgt_channel_clear_store( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_dn: + /* Interface disconnecting. */ + /* Gnttab channel phase one connected unless ph2 disconnecting below.*/ + /* Clearing Store / writing ready / writing connected / ... */ + /* ... ph2 disconnecting */ + /* Watch Registered. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_pe: + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + case xenidc_xbgt_channel_stimulus_rf: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + xenidc_xbgt_channel_unregister_watch( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Store clear. */ + /* Watch Registered. */ + /* Testing other state / other state unknown/connected */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + xenidc_xbgt_channel_unregister_watch( channel ); + break; + case xenidc_xbgt_channel_stimulus_ou: + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od; + xenidc_xbgt_channel_write_ready( channel ); + break; + case xenidc_xbgt_channel_stimulus_oc: + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rf: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Unregistering watch. */ + /* Something failed. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf; + xenidc_xbgt_channel_clear_store( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rf_rs: + /* Interface connected. */ + /* Gnttab channel phase one disconnecting. */ + /* Attempted to clear store. */ + /* Something failed. */ + /* Watch not registered. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i_cn_dn_rs_rs; + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs; + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Writing Ready. */ + /* Watch Registered. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_dn; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs; + xenidc_xbgt_channel_test_other_state( channel ); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rf; + xenidc_xbgt_channel_unregister_watch( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs: + /* Interface connected. */ + /* Gnttab channel phase one disconnected. */ + /* Attempted to clear store. */ + /* Something failed. */ + /* Watch not registered. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i; + xenidc_xbgt_channel_complete_disconnect( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Ready. */ + /* Watch registered. */ + /* Testing other state or other state disconnected */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + xenidc_xbgt_channel_unregister_watch( channel ); + break; + case xenidc_xbgt_channel_stimulus_od: + break; + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or; + xenidc_xbgt_channel_write_connected( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Writing Connected. */ + /* Watch registered. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_dn; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs; + xenidc_xbgt_channel_test_other_state( channel ); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs_rf; + xenidc_xbgt_channel_unregister_watch( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs: + /* Interface connected. */ + /* Gnttab channel phase one connected. */ + /* Connected. */ + /* Watch registered. */ + /* Testing other state / other state ready. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + xenidc_xbgt_channel_unregister_watch( channel ); + break; + case xenidc_xbgt_channel_stimulus_od: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs; + xenidc_xbgt_channel_clear_store( channel ); + break; + case xenidc_xbgt_channel_stimulus_or: + break; + case xenidc_xbgt_channel_stimulus_oc: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc; + xenidc_xbgt_channel_phase_two_connect( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc: + /* Interface connected. */ + /* Gnttab channel phase two connecting. */ + /* Connected. */ + /* Watch registered. */ + /* Other side connected. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_pe: + /* Phase two disconnect then go around. */ + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe; + break; + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe; + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs; + break; + case xenidc_xbgt_channel_stimulus_rf: + /* Maybe we picked up stale state from the store. Go around. */ + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs; + xenidc_xbgt_channel_clear_store( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe: + /* Interface connected. */ + /* Gnttab channel phase two connecting. */ + /* Connected. */ + /* Watch registered. */ + /* Protocol error or glitch. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_pe: + break; + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn; + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs; + xenidc_xbgt_channel_phase_two_disconnect( channel ); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_rs; + xenidc_xbgt_channel_clear_store( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn: + /* Interface disconnecting. */ + /* Gnttab channel phase two connecting. */ + /* Connected. */ + /* Watch registered. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_pe: + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + break; + case xenidc_xbgt_channel_stimulus_rs: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_dn; + xenidc_xbgt_channel_phase_two_disconnect( channel ); + break; + case xenidc_xbgt_channel_stimulus_rf: + channel->state = xenidc_xbgt_channel_state_i_cn_rs_dn_rs; + xenidc_xbgt_channel_unregister_watch( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + case xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs: + /* Interface connected. */ + /* Gnttab channel phase two connected. */ + /* Connected. */ + /* Watch registered. */ + /* Other side connected. */ + /* Totally happy. */ + switch( stimulus ) + { + case xenidc_xbgt_channel_stimulus_pe: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs; + xenidc_xbgt_channel_phase_two_disconnect( channel ); + break; + case xenidc_xbgt_channel_stimulus_dn: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs_rs_dn; + xenidc_xbgt_channel_phase_two_disconnect( channel ); + break; + case xenidc_xbgt_channel_stimulus_od: + case xenidc_xbgt_channel_stimulus_or: + case xenidc_xbgt_channel_stimulus_oc: + channel->state = + xenidc_xbgt_channel_state_i_cn_rs; + xenidc_xbgt_channel_phase_two_disconnect( channel ); + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } + break; + default: + xenidc_xbgt_channel_invalid_stimulus( channel, stimulus ); + break; + } +} + +static void xenidc_xbgt_channel_invalid_stimulus + ( xenidc_xbgt_channel * channel, xenidc_xbgt_channel_stimulus stimulus ) +{ + trace(); + + printk + ( + KERN_ERR "xenidc: xbgt channel %p in state %d" + "received invalid stimulus %d", + channel, + channel->state, + stimulus + ); +} + +static void xenidc_xbgt_channel_test_other_state + ( xenidc_xbgt_channel * channel ) +{ + trace(); + + switch( channel->other_state ) + { + case xenidc_xbgt_channel_other_state_unknown: + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_ou ); + break; + case xenidc_xbgt_channel_other_state_disconnected: + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_od ); + break; + case xenidc_xbgt_channel_other_state_ready: + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_or ); + break; + case xenidc_xbgt_channel_other_state_connected: + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_oc ); + break; + } +} + +static void xenidc_xbgt_channel_register_watch + ( xenidc_xbgt_channel * channel ) +{ + trace(); + + channel->other_state = xenidc_xbgt_channel_other_state_unknown; + + (void)xenidc_work_schedule( &channel->register_watch_1_work ); +} + +static void xenidc_xbgt_channel_register_watch_1( void * data ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data; + + channel->watch.node = channel->remote_path; + channel->watch.callback = xenidc_xbgt_channel_watch; + + { + int return_value = register_xenbus_watch( &channel->watch ); + + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + if( return_value == 0 ) + { + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rs ); + } + else + { + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rf ); + } + + spin_unlock_irqrestore( &channel->lock, flags ); + } + } +} + +static void xenidc_xbgt_channel_unregister_watch + ( xenidc_xbgt_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->unregister_watch_1_work ); +} + +static void xenidc_xbgt_channel_unregister_watch_1( void * data ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data; + + unregister_xenbus_watch( &channel->watch ); + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rs ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + } +} + +static void xenidc_xbgt_channel_clear_store( xenidc_xbgt_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->clear_store_1_work ); +} + +static void xenidc_xbgt_channel_clear_store_1( void * data ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data; + + struct xenbus_transaction * transaction; + + AGAIN: + + transaction = xenbus_transaction_start(); + + if( IS_ERR( transaction ) ) + { + trace0( "error starting transaction" ); + + goto ERROR; + } + + { + int error = + xenbus_rm( transaction, channel->local_path, "ready" ); + + if( error ) + { + trace0( "error removing ready field from store" ); + + goto ABORT_TRANSACTION; + } + } + + { + int error = + xenbus_rm( transaction, channel->local_path, "event-channel" ); + + if( error ) + { + trace0( "error removing event-channel field from store" ); + + goto ABORT_TRANSACTION; + } + } + + { + int error = + xenbus_rm( transaction, channel->local_path, "ring-reference" ); + + if( error ) + { + trace0( "error removing ring-reference field from store" ); + + goto ABORT_TRANSACTION; + } + } + + { + int error = xenbus_transaction_end( transaction, 0 /* commit */ ); + + if( error != 0 ) + { + if( error == -EAGAIN ) + { + goto AGAIN; + } + else + { + trace0( "error committing transaction" ); + + goto ERROR; + } + } + } + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rs ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + + return; + + ABORT_TRANSACTION: + + xenbus_transaction_end( transaction, 1 /* abort */ ); + + ERROR: + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rf ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + } +} + +static void xenidc_xbgt_channel_write_ready( xenidc_xbgt_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->write_ready_1_work ); +} + +static void xenidc_xbgt_channel_write_ready_1( void * data ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data; + + struct xenbus_transaction * transaction; + + AGAIN: + + transaction = xenbus_transaction_start(); + + if( IS_ERR( transaction ) ) + { + trace0( "error starting transaction" ); + + goto ERROR; + } + + { + int error = xenbus_write + ( + transaction, + channel->local_path, + "ready", + "1" + ); + + if( error ) + { + trace0( "error writing ready to store" ); + + goto ABORT_TRANSACTION; + } + } + + { + int error = xenbus_transaction_end( transaction, 0 /* commit */ ); + + if( error != 0 ) + { + if( error == -EAGAIN ) + { + goto AGAIN; + } + else + { + trace0( "error committing transaction" ); + + goto ERROR; + } + } + } + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rs ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + + return; + + ABORT_TRANSACTION: + + xenbus_transaction_end( transaction, 1 /* abort */ ); + + ERROR: + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rf ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + } +} + +static void xenidc_xbgt_channel_write_connected + ( xenidc_xbgt_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->write_connected_1_work ); +} + +static void xenidc_xbgt_channel_write_connected_1( void * data ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data; + + struct xenbus_transaction * transaction; + + AGAIN: + + transaction = xenbus_transaction_start(); + + if( IS_ERR( transaction ) ) + { + trace0( "error starting transaction" ); + + goto ERROR; + } + + { + int error = xenbus_printf + ( + transaction, + channel->local_path, + "ring-reference", + "%u", + channel->phase_one_connect_request.send_ring_ref + ); + + if( error ) + { + trace0( "error writing ring-reference to store" ); + + goto ABORT_TRANSACTION; + } + } + + { + int error = xenbus_printf + ( + transaction, + channel->local_path, + "event-channel", + "%u", + channel->phase_one_connect_request.send_event_channel + ); + + if( error ) + { + trace0( "error writing event-channel to store" ); + + goto ABORT_TRANSACTION; + } + } + + { + int error = xenbus_transaction_end( transaction, 0 /* commit */ ); + + if( error != 0 ) + { + if( error == -EAGAIN ) + { + goto AGAIN; + } + else + { + trace0( "error committing transaction" ); + + goto ERROR; + } + } + } + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rs ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + + return; + + ABORT_TRANSACTION: + + xenbus_transaction_end( transaction, 1 /* abort */ ); + + ERROR: + + { + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rf ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } + } +} + +static void xenidc_xbgt_channel_phase_one_connect + ( xenidc_xbgt_channel * channel ) +{ + trace(); + + channel->phase_one_connect_request.remote_domain_id = + channel->remote_domain_id; + + (void)xenidc_work_schedule( &channel->phase_one_connect_1_work ); +} + +static void xenidc_xbgt_channel_phase_one_connect_1( void * data ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data; + + xenidc_gnttab_channel_phase_one_connect + ( &channel->channel, &channel->phase_one_connect_request ); + } +} + +static void xenidc_xbgt_channel_phase_one_connect_2 + ( xenidc_callback * callback ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = container_of + ( + xenidc_gnttab_channel_phase_one_connect_request_callback_to + ( callback ), + xenidc_xbgt_channel, + phase_one_connect_request + ); + + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rs ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +static void xenidc_xbgt_channel_phase_two_connect + ( xenidc_xbgt_channel * channel ) +{ + trace(); + + channel->phase_two_connect_request.remote_domain_id = + channel->remote_domain_id; + channel->phase_two_connect_request.recv_ring_ref = + channel->ready_ring_reference; + channel->phase_two_connect_request.recv_event_channel = + channel->ready_event_channel; + + (void)xenidc_work_schedule( &channel->phase_two_connect_1_work ); +} + +static void xenidc_xbgt_channel_phase_two_connect_1( void * data ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data; + + xenidc_gnttab_channel_phase_two_connect + ( &channel->channel, &channel->phase_two_connect_request ); + } +} + +static void xenidc_xbgt_channel_phase_two_connect_2 + ( xenidc_callback * callback ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = container_of + ( + xenidc_gnttab_channel_phase_two_connect_request_callback_to + ( callback ), + xenidc_xbgt_channel, + phase_two_connect_request + ); + + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + if( xenidc_callback_query_error( callback ) == XENIDC_ERROR_SUCCESS ) + { + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rs ); + } + else + { + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rf ); + } + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +static void xenidc_xbgt_channel_phase_two_disconnect + ( xenidc_xbgt_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->phase_two_disconnect_1_work ); +} + +static void xenidc_xbgt_channel_phase_two_disconnect_1( void * data ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data; + + xenidc_gnttab_channel_phase_two_disconnect + ( &channel->channel, &channel->phase_two_disconnect_callback ); + } +} + +static void xenidc_xbgt_channel_phase_two_disconnect_2 + ( xenidc_callback * callback ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = container_of + ( callback, xenidc_xbgt_channel, phase_two_disconnect_callback ); + + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rs ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +static void xenidc_xbgt_channel_phase_one_disconnect + ( xenidc_xbgt_channel * channel ) +{ + trace(); + + (void)xenidc_work_schedule( &channel->phase_one_disconnect_1_work ); +} + +static void xenidc_xbgt_channel_phase_one_disconnect_1( void * data ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = (xenidc_xbgt_channel *)data; + + xenidc_gnttab_channel_phase_one_disconnect + ( &channel->channel, &channel->phase_one_disconnect_callback ); + } +} + +static void xenidc_xbgt_channel_phase_one_disconnect_2 + ( xenidc_callback * callback ) +{ + trace(); + + { + xenidc_xbgt_channel * channel = container_of + ( callback, xenidc_xbgt_channel, phase_one_disconnect_callback ); + + unsigned long flags; + + spin_lock_irqsave( &channel->lock, flags ); + + xenidc_xbgt_channel_handle_stimulus + ( channel, xenidc_xbgt_channel_stimulus_rs ); + + spin_unlock_irqrestore( &channel->lock, flags ); + } +} + +static void xenidc_xbgt_channel_complete_disconnect + ( xenidc_xbgt_channel * channel ) +{ + trace(); + + xenidc_callback_success( channel->disconnect_callback ); +} diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.dot --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.dot Mon Oct 24 15:04:49 2005 @@ -0,0 +1,109 @@ +digraph enumeration { +size="7,7" + +i[style=filled,fillcolor=green] +i->i_cn[label="cn\nphase_one_connect"]; + +i_cn[style=filled,fillcolor=green] +i_cn->i_cn_dn[label="dn"]; +i_cn->i_cn_rs[label="rs\nregister_watch"]; + +i_cn_dn[style=filled,fillcolor=orange] +i_cn_dn->i_cn_dn_rs[label="rs\nclear_store"]; + +i_cn_rs[style=filled,fillcolor=green] +i_cn_rs->i_cn_rs_dn[label="dn"]; +i_cn_rs->i_cn_rs[label="pe/od/or/oc"]; +i_cn_rs->i_cn_rs_rs[label="rs\nclear_store"]; +i_cn_rs->i_cn_rs_rf[label="rf\nclear_store"]; + +i_cn_dn_rs[style=filled,fillcolor=orange] +i_cn_dn_rs->i_cn_dn_rs_rs[label="rs/rf\nphase_one_disconnect"]; + +i_cn_rs_dn[style=filled,fillcolor=orange] +i_cn_rs_dn->i_cn_rs_dn[label="od/or/oc"]; +i_cn_rs_dn->i_cn_rs_dn_rs[label="rs\nunregister_watch"]; +i_cn_rs_dn->i_cn_dn_rs[label="rf\nclear_store"]; + +i_cn_rs_rs[style=filled,fillcolor=green] +i_cn_rs_rs->i_cn_rs_rs_dn[label="dn"]; +i_cn_rs_rs->i_cn_rs_rs[label="od/or/oc"]; +i_cn_rs_rs->i_cn_rs_rs_rs[label="rs\ntest_other_state"]; +i_cn_rs_rs->i_cn_rs_rs_rf[label="rf\nunregister_watch"]; + +i_cn_rs_rf[style=filled,fillcolor=red] +i_cn_rs_rf->i_cn_dn_rs[label="dn"]; +i_cn_rs_rf->i_cn_rs_rf_rs[label="rs/rf\nphase_one_disconnect"]; + +i_cn_dn_rs_rs[style=filled,fillcolor=orange] +i_cn_dn_rs_rs->i[label="rs\ncomplete_disconnect"]; + +i_cn_rs_dn_rs[style=filled,fillcolor=orange] +i_cn_rs_dn_rs->i_cn_rs_dn_rs[label="od/or/oc"]; +i_cn_rs_dn_rs->i_cn_dn_rs[label="rs\nclear_store"]; + +i_cn_rs_rs_dn[style=filled,fillcolor=orange] +i_cn_rs_rs_dn->i_cn_rs_rs_dn[label="od/or/oc"]; +i_cn_rs_rs_dn->i_cn_rs_dn_rs[label="rs/rf\nunregister_watch"]; + +i_cn_rs_rs_rs[style=filled,fillcolor=green] +i_cn_rs_rs_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"]; +i_cn_rs_rs_rs->i_cn_rs_rs_rs[label="ou/oc"]; +i_cn_rs_rs_rs->i_cn_rs_rs_rs_od[label="od/or\nwrite_ready"]; + +i_cn_rs_rs_rf[style=filled,fillcolor=red] +i_cn_rs_rs_rf->i_cn_rs_dn_rs[label="dn"]; +i_cn_rs_rs_rf->i_cn_rs_rs_rf[label="od/or/oc"]; +i_cn_rs_rs_rf->i_cn_rs_rf[label="rs\nclear_store"]; + +i_cn_rs_rf_rs[style=filled,fillcolor=red] +i_cn_rs_rf_rs->i_cn_dn_rs_rs[label="dn"]; +i_cn_rs_rf_rs->i_cn_rs_rf_rs_rs[label="rs"]; + +i_cn_rs_rs_rs_od[style=filled,fillcolor=green] +i_cn_rs_rs_rs_od->i_cn_rs_rs_dn[label="dn"]; +i_cn_rs_rs_rs_od->i_cn_rs_rs_rs_od[label="od/or/oc"]; +i_cn_rs_rs_rs_od->i_cn_rs_rs_rs_od_rs[label="rs\ntest_other_state"]; +i_cn_rs_rs_rs_od->i_cn_rs_rs_rf[label="rf\nunregister_watch"]; + +i_cn_rs_rf_rs_rs[style=filled,fillcolor=red] +i_cn_rs_rf_rs_rs->i[label="dn\ncomplete_disconnect"]; + +i_cn_rs_rs_rs_od_rs[style=filled,fillcolor=green] +i_cn_rs_rs_rs_od_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"]; +i_cn_rs_rs_rs_od_rs->i_cn_rs_rs_rs_od_rs[label="od"]; +i_cn_rs_rs_rs_od_rs->i_cn_rs_rs_rs_od_rs_or[label="or/oc\nwrite_connected"]; + +i_cn_rs_rs_rs_od_rs_or[style=filled,fillcolor=green] +i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_dn[label="dn"]; +i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rs_od_rs_or[label="od/or/oc"]; +i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rs_od_rs_or_rs[label="rs\ntest_other_state"]; +i_cn_rs_rs_rs_od_rs_or->i_cn_rs_rs_rf[label="rf\nunregister_watch"]; + +i_cn_rs_rs_rs_od_rs_or_rs[style=filled,fillcolor=green] +i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_dn_rs[label="dn\nunregister_watch"]; +i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs[label="od\nclear_store"]; +i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs_rs_od_rs_or_rs[label="or"]; +i_cn_rs_rs_rs_od_rs_or_rs->i_cn_rs_rs_rs_od_rs_or_rs_oc[label="oc\nphase_two_connect"]; + +i_cn_rs_rs_rs_od_rs_or_rs_oc[style=filled,fillcolor=green] +i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[label="pe/od/or/oc"]; +i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="dn"]; +i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs_rs_od_rs_or_rs_oc_rs[label="rs"]; +i_cn_rs_rs_rs_od_rs_or_rs_oc->i_cn_rs_rs[label="rf\nclear_store"]; + +i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[style=filled,fillcolor=blue] +i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs_rs_od_rs_or_rs_oc_pe[label="pe/od/or/oc"] +i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="dn"] +i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs[label="rs\nphase_two_disconnect"] +i_cn_rs_rs_rs_od_rs_or_rs_oc_pe->i_cn_rs_rs[label="rf\nclear_store"] + +i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[style=filled,fillcolor=orange] +i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_rs_rs_od_rs_or_rs_oc_dn[label="pe/od/or/oc"] +i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_rs_dn[label="rs\nphase_two_disconnect"] +i_cn_rs_rs_rs_od_rs_or_rs_oc_dn->i_cn_rs_dn_rs[label="rf\nunregister_watch"] + +i_cn_rs_rs_rs_od_rs_or_rs_oc_rs[style=filled,fillcolor=green] +i_cn_rs_rs_rs_od_rs_or_rs_oc_rs->i_cn_rs[label="pe/od/or/oc\nphase_two_disconnect"] +i_cn_rs_rs_rs_od_rs_or_rs_oc_rs->i_cn_rs_rs_dn[label="dn\nphase_two_disconnect"] +} diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.ps --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenidc/xenidc_xbgt_channel_enumeration.ps Mon Oct 24 15:04:49 2005 @@ -0,0 +1,2497 @@ +%!PS-Adobe-2.0 +%%Creator: dot version 2.2.1 (Tue Apr 12 00:03:35 UTC 2005) +%%For: (harry) harry,,, +%%Title: enumeration +%%Pages: (atend) +%%BoundingBox: 35 35 541 513 +%%EndComments +save +%%BeginProlog +/DotDict 200 dict def +DotDict begin + +/setupLatin1 { +mark +/EncodingVector 256 array def + EncodingVector 0 + +ISOLatin1Encoding 0 255 getinterval putinterval + +EncodingVector + dup 306 /AE + dup 301 /Aacute + dup 302 /Acircumflex + dup 304 /Adieresis + dup 300 /Agrave + dup 305 /Aring + dup 303 /Atilde + dup 307 /Ccedilla + dup 311 /Eacute + dup 312 /Ecircumflex + dup 313 /Edieresis + dup 310 /Egrave + dup 315 /Iacute + dup 316 /Icircumflex + dup 317 /Idieresis + dup 314 /Igrave + dup 334 /Udieresis + dup 335 /Yacute + dup 376 /thorn + dup 337 /germandbls + dup 341 /aacute + dup 342 /acircumflex + dup 344 /adieresis + dup 346 /ae + dup 340 /agrave + dup 345 /aring + dup 347 /ccedilla + dup 351 /eacute + dup 352 /ecircumflex + dup 353 /edieresis + dup 350 /egrave + dup 355 /iacute + dup 356 /icircumflex + dup 357 /idieresis + dup 354 /igrave + dup 360 /dcroat + dup 361 /ntilde + dup 363 /oacute + dup 364 /ocircumflex + dup 366 /odieresis + dup 362 /ograve + dup 365 /otilde + dup 370 /oslash + dup 372 /uacute + dup 373 /ucircumflex + dup 374 /udieresis + dup 371 /ugrave + dup 375 /yacute + dup 377 /ydieresis + +% Set up ISO Latin 1 character encoding +/starnetISO { + dup dup findfont dup length dict begin + { 1 index /FID ne { def }{ pop pop } ifelse + } forall + /Encoding EncodingVector def + currentdict end definefont +} def +/Times-Roman starnetISO def +/Times-Italic starnetISO def +/Times-Bold starnetISO def +/Times-BoldItalic starnetISO def +/Helvetica starnetISO def +/Helvetica-Oblique starnetISO def +/Helvetica-Bold starnetISO def +/Helvetica-BoldOblique starnetISO def +/Courier starnetISO def +/Courier-Oblique starnetISO def +/Courier-Bold starnetISO def +/Courier-BoldOblique starnetISO def +cleartomark +} bind def + +%%BeginResource: procset graphviz 0 0 +/coord-font-family /Times-Roman def +/default-font-family /Times-Roman def +/coordfont coord-font-family findfont 8 scalefont def + +/InvScaleFactor 1.0 def +/set_scale { + dup 1 exch div /InvScaleFactor exch def + dup scale +} bind def + +% styles +/solid { [] 0 setdash } bind def +/dashed { [9 InvScaleFactor mul dup ] 0 setdash } bind def +/dotted { [1 InvScaleFactor mul 6 InvScaleFactor mul] 0 setdash } bind def +/invis {/fill {newpath} def /stroke {newpath} def /show {pop newpath} def} bind def +/bold { 2 setlinewidth } bind def +/filled { } bind def +/unfilled { } bind def +/rounded { } bind def +/diagonals { } bind def + +% hooks for setting color +/nodecolor { sethsbcolor } bind def +/edgecolor { sethsbcolor } bind def +/graphcolor { sethsbcolor } bind def +/nopcolor {pop pop pop} bind def + +/beginpage { % i j npages + /npages exch def + /j exch def + /i exch def + /str 10 string def + npages 1 gt { + gsave + coordfont setfont + 0 0 moveto + (\() show i str cvs show (,) show j str cvs show (\)) show + grestore + } if +} bind def + +/set_font { + findfont exch + scalefont setfont +} def + +% draw aligned label in bounding box aligned to current point +/alignedtext { % width adj text + /text exch def + /adj exch def + /width exch def + gsave + width 0 gt { + text stringwidth pop adj mul 0 rmoveto + } if + [] 0 setdash + text show + grestore +} def + +/boxprim { % xcorner ycorner xsize ysize + 4 2 roll + moveto + 2 copy + exch 0 rlineto + 0 exch rlineto + pop neg 0 rlineto + closepath +} bind def + +/ellipse_path { + /ry exch def + /rx exch def + /y exch def + /x exch def + matrix currentmatrix + newpath + x y translate + rx ry scale + 0 0 1 0 360 arc + setmatrix +} bind def + +/endpage { showpage } bind def +/showpage { } def + +/layercolorseq + [ % layer color sequence - darkest to lightest + [0 0 0] + [.2 .8 .8] + [.4 .8 .8] + [.6 .8 .8] + [.8 .8 .8] + ] +def + +/layerlen layercolorseq length def + +/setlayer {/maxlayer exch def /curlayer exch def + layercolorseq curlayer 1 sub layerlen mod get + aload pop sethsbcolor + /nodecolor {nopcolor} def + /edgecolor {nopcolor} def + /graphcolor {nopcolor} def +} bind def + +/onlayer { curlayer ne {invis} if } def + +/onlayers { + /myupper exch def + /mylower exch def + curlayer mylower lt + curlayer myupper gt + or + {invis} if +} def + +/curlayer 0 def + +%%EndResource +%%EndProlog +%%BeginSetup +14 default-font-family set_font +1 setmiterlimit +% /arrowlength 10 def +% /arrowwidth 5 def + +% make sure pdfmark is harmless for PS-interpreters other than Distiller +/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse +% make '<<' and '>>' safe on PS Level 1 devices +/languagelevel where {pop languagelevel}{1} ifelse +2 lt { + userdict (<<) cvn ([) cvn load put + userdict (>>) cvn ([) cvn load put +} if + +%%EndSetup +%%Page: 1 1 +%%PageBoundingBox: 36 36 541 513 +%%PageOrientation: Portrait +gsave +35 35 506 478 boxprim clip newpath +36 36 translate +0 0 1 beginpage +0.2979 set_scale +0 0 translate 0 rotate +0.000 0.000 0.000 graphcolor +14.00 /Times-Roman set_font + +% i +gsave 10 dict begin +filled +0.333 1.000 1.000 nodecolor +1441 1582 27 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +1441 1582 27 18 ellipse_path +stroke +gsave 10 dict begin +1441 1577 moveto 5.0 -0.5 (i) alignedtext +end grestore +end grestore + +% i_cn +gsave 10 dict begin +filled +0.333 1.000 1.000 nodecolor +1283 1478 27 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +1283 1478 27 18 ellipse_path +stroke +gsave 10 dict begin +1270 1473 moveto +(i_cn) +[3.84 6.96 6.24 6.96] +xshow +end grestore +end grestore + +% i -> i_cn +newpath 1415 1577 moveto +1383 1570 1331 1558 1316 1546 curveto +1304 1536 1296 1519 1290 1505 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1293 1504 moveto +1287 1496 lineto +1287 1507 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1293 1504 moveto +1287 1496 lineto +1287 1507 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1366 1533 moveto +(cn) +[6.24 6.96] +xshow +1317 1517 moveto +(phase_one_connect) +[6.96 6.96 6.24 5.52 6.24 6.96 6.96 6.96 6.24 6.96 6.24 6.96 6.96 6.96 6.24 6.24 3.84] +xshow +end grestore + +% i_cn_dn +gsave 10 dict begin +filled +0.106 1.000 1.000 nodecolor +1283 1320 36 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +1283 1320 36 18 ellipse_path +stroke +gsave 10 dict begin +1259 1315 moveto +(i_cn_dn) +[3.84 6.96 6.24 6.96 6.96 6.96 6.96] +xshow +end grestore +end grestore + +% i_cn -> i_cn_dn +newpath 1283 1460 moveto +1283 1432 1283 1381 1283 1348 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1287 1348 moveto +1283 1338 lineto +1280 1348 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1287 1348 moveto +1283 1338 lineto +1280 1348 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1282 1421 moveto +(dn) +[6.96 6.96] +xshow +end grestore + +% i_cn_rs +gsave 10 dict begin +filled +0.333 1.000 1.000 nodecolor +836 1374 34 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +836 1374 34 18 ellipse_path +stroke +gsave 10 dict begin +814 1369 moveto +(i_cn_rs) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52] +xshow +end grestore +end grestore + +% i_cn -> i_cn_rs +newpath 1257 1472 moveto +1183 1455 968 1405 877 1383 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 877 1380 moveto +867 1381 lineto +876 1386 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 877 1380 moveto +867 1381 lineto +876 1386 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1161 1429 moveto +(rs) +[4.56 5.52] +xshow +1125 1413 moveto +(register_watch) +[4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96] +xshow +end grestore + +% i_cn_dn_rs +gsave 10 dict begin +filled +0.106 1.000 1.000 nodecolor +1179 122 45 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +1179 122 45 18 ellipse_path +stroke +gsave 10 dict begin +1147 117 moveto +(i_cn_dn_rs) +[3.84 6.96 6.24 6.96 6.96 6.96 6.96 6.96 4.56 5.52] +xshow +end grestore +end grestore + +% i_cn_dn -> i_cn_dn_rs +newpath 1283 1302 moveto +1283 1281 1283 1245 1283 1214 curveto +1283 1214 1283 1214 1283 226 curveto +1283 187 1247 158 1218 141 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1219 138 moveto +1209 136 lineto +1216 144 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1219 138 moveto +1209 136 lineto +1216 144 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1308 749 moveto +(rs) +[4.56 5.52] +xshow +1283 733 moveto +(clear_store) +[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24] +xshow +end grestore + +% i_cn_rs -> i_cn_rs +newpath 860 1361 moveto +874 1359 888 1363 888 1374 curveto +888 1382 880 1387 870 1387 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 870 1384 moveto +860 1387 lineto +870 1391 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 870 1384 moveto +860 1387 lineto +870 1391 lineto +closepath +stroke +end grestore +gsave 10 dict begin +887 1369 moveto +(pe/od/or/oc) +[6.96 6.24 3.84 6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24] +xshow +end grestore + +% i_cn_rs_dn +gsave 10 dict begin +filled +0.106 1.000 1.000 nodecolor +1145 330 45 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +1145 330 45 18 ellipse_path +stroke +gsave 10 dict begin +1113 325 moveto +(i_cn_rs_dn) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 6.96 6.96] +xshow +end grestore +end grestore + +% i_cn_rs -> i_cn_rs_dn +newpath 869 1370 moveto +952 1359 1160 1326 1160 1266 curveto +1160 1266 1160 1266 1160 902 curveto +1160 752 1260 721 1234 574 curveto +1219 491 1179 401 1158 357 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1161 356 moveto +1154 348 lineto +1155 359 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1161 356 moveto +1154 348 lineto +1155 359 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1165 845 moveto +(dn) +[6.96 6.96] +xshow +end grestore + +% i_cn_rs_rs +gsave 10 dict begin +filled +0.333 1.000 1.000 nodecolor +545 1266 43 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +545 1266 43 18 ellipse_path +stroke +gsave 10 dict begin +515 1261 moveto +(i_cn_rs_rs) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52] +xshow +end grestore +end grestore + +% i_cn_rs -> i_cn_rs_rs +newpath 808 1364 moveto +757 1345 647 1304 587 1282 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 588 1278 moveto +577 1278 lineto +585 1285 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 588 1278 moveto +577 1278 lineto +585 1285 lineto +closepath +stroke +end grestore +gsave 10 dict begin +768 1323 moveto +(rs) +[4.56 5.52] +xshow +743 1307 moveto +(clear_store) +[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24] +xshow +end grestore + +% i_cn_rs_rf +gsave 10 dict begin +filled +0.000 1.000 1.000 nodecolor +1094 642 42 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +1094 642 42 18 ellipse_path +stroke +gsave 10 dict begin +1064 637 moveto +(i_cn_rs_rf) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 4.56] +xshow +end grestore +end grestore + +% i_cn_rs -> i_cn_rs_rf +newpath 870 1372 moveto +951 1368 1149 1355 1174 1338 curveto +1201 1317 1203 1300 1203 1266 curveto +1203 1266 1203 1266 1203 902 curveto +1203 802 1241 758 1182 678 curveto +1172 665 1158 657 1143 652 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1144 649 moveto +1133 649 lineto +1142 655 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1144 649 moveto +1133 649 lineto +1142 655 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1228 1009 moveto +(rf) +[4.56 4.56] +xshow +1203 993 moveto +(clear_store) +[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24] +xshow +end grestore + +% i_cn_dn_rs_rs +gsave 10 dict begin +filled +0.106 1.000 1.000 nodecolor +1354 18 53 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +1354 18 53 18 ellipse_path +stroke +gsave 10 dict begin +1313 13 moveto +(i_cn_dn_rs_rs) +[3.84 6.96 6.24 6.96 6.96 6.96 6.96 6.96 4.56 5.52 6.96 4.56 5.52] +xshow +end grestore +end grestore + +% i_cn_dn_rs -> i_cn_dn_rs_rs +newpath 1183 104 moveto +1188 88 1197 67 1213 54 curveto +1226 43 1263 34 1296 28 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1297 31 moveto +1306 26 lineto +1296 25 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1297 31 moveto +1306 26 lineto +1296 25 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1263 73 moveto +(rs/rf) +[4.56 5.52 3.84 4.56 4.56] +xshow +1212 57 moveto +(phase_one_disconnect) +[6.96 6.96 6.24 5.52 6.24 6.96 6.96 6.96 6.24 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84] +xshow +end grestore + +% i_cn_rs_dn -> i_cn_dn_rs +newpath 1148 312 moveto +1154 275 1168 194 1174 150 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1177 150 moveto +1176 140 lineto +1171 149 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1177 150 moveto +1176 140 lineto +1171 149 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1188 229 moveto +(rf) +[4.56 4.56] +xshow +1163 213 moveto +(clear_store) +[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24] +xshow +end grestore + +% i_cn_rs_dn -> i_cn_rs_dn +newpath 1176 317 moveto +1193 315 1208 319 1208 330 curveto +1208 339 1198 343 1186 343 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1186 340 moveto +1176 343 lineto +1186 347 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1186 340 moveto +1176 343 lineto +1186 347 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1207 325 moveto +(od/or/oc) +[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24] +xshow +end grestore + +% i_cn_rs_dn_rs +gsave 10 dict begin +filled +0.106 1.000 1.000 nodecolor +906 226 53 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +906 226 53 18 ellipse_path +stroke +gsave 10 dict begin +865 221 moveto +(i_cn_rs_dn_rs) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52] +xshow +end grestore +end grestore + +% i_cn_rs_dn -> i_cn_rs_dn_rs +newpath 1115 316 moveto +1100 310 1083 301 1067 294 curveto +1037 280 1030 274 1001 262 curveto +985 255 968 249 953 243 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 954 239 moveto +943 239 lineto +951 246 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 954 239 moveto +943 239 lineto +951 246 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1113 281 moveto +(rs) +[4.56 5.52] +xshow +1070 265 moveto +(unregister_watch) +[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96] +xshow +end grestore + +% i_cn_rs_rs -> i_cn_rs_rs +newpath 575 1253 moveto +591 1251 606 1255 606 1266 curveto +606 1275 597 1279 585 1279 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 585 1276 moveto +575 1279 lineto +585 1283 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 585 1276 moveto +575 1279 lineto +585 1283 lineto +closepath +stroke +end grestore +gsave 10 dict begin +606 1261 moveto +(od/or/oc) +[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24] +xshow +end grestore + +% i_cn_rs_rs_dn +gsave 10 dict begin +filled +0.106 1.000 1.000 nodecolor +600 330 53 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +600 330 53 18 ellipse_path +stroke +gsave 10 dict begin +559 325 moveto +(i_cn_rs_rs_dn) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96] +xshow +end grestore +end grestore + +% i_cn_rs_rs -> i_cn_rs_rs_dn +newpath 502 1265 moveto +498 1264 494 1264 493 1264 curveto +425 1248 371 1232 371 1162 curveto +371 1162 371 1162 371 1006 curveto +371 770 43 825 43 590 curveto +43 590 43 590 43 434 curveto +43 338 370 357 465 350 curveto +473 349 527 350 534 348 curveto +538 346 540 344 542 342 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 545 344 moveto +548 334 lineto +539 340 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 545 344 moveto +548 334 lineto +539 340 lineto +closepath +stroke +end grestore +gsave 10 dict begin +240 793 moveto +(dn) +[6.96 6.96] +xshow +end grestore + +% i_cn_rs_rs_rs +gsave 10 dict begin +filled +0.333 1.000 1.000 nodecolor +782 1162 51 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +782 1162 51 18 ellipse_path +stroke +gsave 10 dict begin +743 1157 moveto +(i_cn_rs_rs_rs) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52] +xshow +end grestore +end grestore + +% i_cn_rs_rs -> i_cn_rs_rs_rs +newpath 575 1253 moveto +617 1234 693 1201 741 1180 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 742 1183 moveto +750 1176 lineto +739 1177 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 742 1183 moveto +750 1176 lineto +739 1177 lineto +closepath +stroke +end grestore +gsave 10 dict begin +739 1217 moveto +(rs) +[4.56 5.52] +xshow +700 1201 moveto +(test_other_state) +[3.84 6.24 5.52 3.84 6.96 6.96 3.84 6.96 6.24 4.56 6.96 5.52 3.84 6.24 3.84 6.24] +xshow +end grestore + +% i_cn_rs_rs_rf +gsave 10 dict begin +filled +0.000 1.000 1.000 nodecolor +936 746 51 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +936 746 51 18 ellipse_path +stroke +gsave 10 dict begin +898 741 moveto +(i_cn_rs_rs_rf) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 4.56] +xshow +end grestore +end grestore + +% i_cn_rs_rs -> i_cn_rs_rs_rf +newpath 588 1263 moveto +708 1253 1047 1265 1047 1162 curveto +1047 1162 1047 1162 1047 954 curveto +1047 923 1046 914 1035 886 curveto +1011 827 997 807 961 770 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 964 768 moveto +954 763 lineto +959 773 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 964 768 moveto +954 763 lineto +959 773 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1090 1009 moveto +(rf) +[4.56 4.56] +xshow +1047 993 moveto +(unregister_watch) +[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96] +xshow +end grestore + +% i_cn_rs_rf -> i_cn_dn_rs +newpath 1088 624 moveto +1071 571 1029 415 1091 312 curveto +1099 297 1112 306 1123 294 curveto +1161 244 1142 217 1162 158 curveto +1163 155 1163 152 1164 149 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1167 149 moveto +1165 139 lineto +1161 149 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1167 149 moveto +1165 139 lineto +1161 149 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1065 377 moveto +(dn) +[6.96 6.96] +xshow +end grestore + +% i_cn_rs_rf_rs +gsave 10 dict begin +filled +0.000 1.000 1.000 nodecolor +1362 538 51 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +1362 538 51 18 ellipse_path +stroke +gsave 10 dict begin +1324 533 moveto +(i_cn_rs_rf_rs) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 4.56 6.96 4.56 5.52] +xshow +end grestore +end grestore + +% i_cn_rs_rf -> i_cn_rs_rf_rs +newpath 1125 630 moveto +1173 611 1264 576 1319 555 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1320 558 moveto +1328 551 lineto +1317 552 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1320 558 moveto +1328 551 lineto +1317 552 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1316 593 moveto +(rs/rf) +[4.56 5.52 3.84 4.56 4.56] +xshow +1265 577 moveto +(phase_one_disconnect) +[6.96 6.96 6.24 5.52 6.24 6.96 6.96 6.96 6.24 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84] +xshow +end grestore + +% i_cn_dn_rs_rs -> i +newpath 1397 29 moveto +1461 46 1574 83 1574 122 curveto +1574 1478 1574 1478 1574 1478 curveto +1574 1528 1515 1557 1476 1572 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1475 1569 moveto +1466 1575 lineto +1477 1575 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1475 1569 moveto +1466 1575 lineto +1477 1575 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1627 801 moveto +(rs) +[4.56 5.52] +xshow +1574 785 moveto +(complete_disconnect) +[6.24 6.96 10.8 6.96 3.84 6.24 3.84 6.24 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84] +xshow +end grestore + +% i_cn_rs_dn_rs -> i_cn_dn_rs +newpath 936 211 moveto +966 196 1013 174 1057 158 curveto +1081 149 1109 141 1131 135 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1132 138 moveto +1141 132 lineto +1130 132 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1132 138 moveto +1141 132 lineto +1130 132 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1082 177 moveto +(rs) +[4.56 5.52] +xshow +1057 161 moveto +(clear_store) +[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24] +xshow +end grestore + +% i_cn_rs_dn_rs -> i_cn_rs_dn_rs +newpath 943 213 moveto +961 211 977 216 977 226 curveto +977 234 967 239 953 239 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 953 236 moveto +943 239 lineto +953 243 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 953 236 moveto +943 239 lineto +953 243 lineto +closepath +stroke +end grestore +gsave 10 dict begin +976 221 moveto +(od/or/oc) +[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24] +xshow +end grestore + +% i_cn_rs_rs_dn -> i_cn_rs_dn_rs +newpath 615 313 moveto +631 297 655 274 681 262 curveto +710 249 788 238 845 232 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 845 235 moveto +855 231 lineto +845 229 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 845 235 moveto +855 231 lineto +845 229 lineto +closepath +stroke +end grestore +gsave 10 dict begin +717 281 moveto +(rs/rf) +[4.56 5.52 3.84 4.56 4.56] +xshow +681 265 moveto +(unregister_watch) +[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96] +xshow +end grestore + +% i_cn_rs_rs_dn -> i_cn_rs_rs_dn +newpath 637 317 moveto +655 315 671 320 671 330 curveto +671 338 661 343 647 343 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 647 340 moveto +637 343 lineto +647 347 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 647 340 moveto +637 343 lineto +647 347 lineto +closepath +stroke +end grestore +gsave 10 dict begin +671 325 moveto +(od/or/oc) +[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24] +xshow +end grestore + +% i_cn_rs_rs_rs -> i_cn_rs_dn_rs +newpath 813 1148 moveto +825 1141 840 1134 853 1126 curveto +883 1106 892 1102 918 1076 curveto +979 1013 1000 998 1035 918 curveto +1062 854 1054 833 1061 764 curveto +1064 725 1077 713 1062 678 curveto +1057 667 1048 670 1043 660 curveto +967 521 1016 464 976 312 curveto +967 282 966 262 952 245 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 955 243 moveto +945 238 lineto +950 248 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 955 243 moveto +945 238 lineto +950 248 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1109 697 moveto +(dn) +[6.96 6.96] +xshow +1068 681 moveto +(unregister_watch) +[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96] +xshow +end grestore + +% i_cn_rs_rs_rs -> i_cn_rs_rs_rs +newpath 817 1149 moveto +835 1147 851 1151 851 1162 curveto +851 1171 841 1175 827 1175 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 827 1172 moveto +817 1175 lineto +827 1179 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 827 1172 moveto +817 1175 lineto +827 1179 lineto +closepath +stroke +end grestore +gsave 10 dict begin +851 1157 moveto +(ou/oc) +[6.96 6.96 3.84 6.96 6.24] +xshow +end grestore + +% i_cn_rs_rs_rs_od +gsave 10 dict begin +filled +0.333 1.000 1.000 nodecolor +782 1058 62 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +782 1058 62 18 ellipse_path +stroke +gsave 10 dict begin +733 1053 moveto +(i_cn_rs_rs_rs_od) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96] +xshow +end grestore +end grestore + +% i_cn_rs_rs_rs -> i_cn_rs_rs_rs_od +newpath 782 1144 moveto +782 1128 782 1105 782 1086 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 786 1086 moveto +782 1076 lineto +779 1086 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 786 1086 moveto +782 1076 lineto +779 1086 lineto +closepath +stroke +end grestore +gsave 10 dict begin +801 1113 moveto +(od/or) +[6.96 6.96 3.84 6.96 4.56] +xshow +782 1097 moveto +(write_ready) +[10.08 4.56 3.84 3.84 6.24 6.96 4.56 6.24 6.24 6.96 6.96] +xshow +end grestore + +% i_cn_rs_rs_rf -> i_cn_rs_rf +newpath 956 729 moveto +963 724 970 717 976 710 curveto +986 697 982 688 996 678 curveto +1010 666 1029 658 1046 653 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1047 656 moveto +1056 650 lineto +1045 650 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1047 656 moveto +1056 650 lineto +1045 650 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1021 697 moveto +(rs) +[4.56 5.52] +xshow +996 681 moveto +(clear_store) +[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24] +xshow +end grestore + +% i_cn_rs_rs_rf -> i_cn_rs_dn_rs +newpath 943 728 moveto +951 708 962 673 962 642 curveto +962 642 962 642 962 330 curveto +962 300 944 271 928 251 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 931 249 moveto +922 243 lineto +925 253 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 931 249 moveto +922 243 lineto +925 253 lineto +closepath +stroke +end grestore +gsave 10 dict begin +961 481 moveto +(dn) +[6.96 6.96] +xshow +end grestore + +% i_cn_rs_rs_rf -> i_cn_rs_rs_rf +newpath 971 733 moveto +989 731 1005 735 1005 746 curveto +1005 755 995 759 981 759 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 981 756 moveto +971 759 lineto +981 763 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 981 756 moveto +971 759 lineto +981 763 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1004 741 moveto +(od/or/oc) +[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24] +xshow +end grestore + +% i_cn_rs_rf_rs -> i_cn_dn_rs_rs +newpath 1360 520 moveto +1357 499 1354 464 1354 434 curveto +1354 434 1354 434 1354 122 curveto +1354 96 1354 67 1354 46 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1358 46 moveto +1354 36 lineto +1351 46 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1358 46 moveto +1354 36 lineto +1351 46 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1353 273 moveto +(dn) +[6.96 6.96] +xshow +end grestore + +% i_cn_rs_rf_rs_rs +gsave 10 dict begin +filled +0.000 1.000 1.000 nodecolor +1441 434 59 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +1441 434 59 18 ellipse_path +stroke +gsave 10 dict begin +1394 429 moveto +(i_cn_rs_rf_rs_rs) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 4.56 6.96 4.56 5.52 6.96 4.56 5.52] +xshow +end grestore +end grestore + +% i_cn_rs_rf_rs -> i_cn_rs_rf_rs_rs +newpath 1375 520 moveto +1388 504 1407 479 1422 460 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1425 462 moveto +1428 452 lineto +1419 458 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1425 462 moveto +1428 452 lineto +1419 458 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1412 481 moveto +(rs) +[4.56 5.52] +xshow +end grestore + +% i_cn_rs_rs_rs_od -> i_cn_rs_rs_dn +newpath 762 1041 moveto +728 1010 662 942 641 868 curveto +637 852 632 845 641 832 curveto +656 812 679 833 693 814 curveto +740 753 718 546 713 470 curveto +712 445 719 437 707 416 curveto +692 388 662 365 639 350 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 640 347 moveto +630 345 lineto +637 353 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 640 347 moveto +630 345 lineto +637 353 lineto +closepath +stroke +end grestore +gsave 10 dict begin +724 689 moveto +(dn) +[6.96 6.96] +xshow +end grestore + +% i_cn_rs_rs_rs_od -> i_cn_rs_rs_rf +newpath 832 1047 moveto +847 1042 863 1034 875 1022 curveto +942 955 942 830 939 774 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 942 774 moveto +938 764 lineto +936 774 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 942 774 moveto +938 764 lineto +936 774 lineto +closepath +stroke +end grestore +gsave 10 dict begin +976 905 moveto +(rf) +[4.56 4.56] +xshow +933 889 moveto +(unregister_watch) +[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96] +xshow +end grestore + +% i_cn_rs_rs_rs_od -> i_cn_rs_rs_rs_od +newpath 825 1045 moveto +844 1043 862 1048 862 1058 curveto +862 1066 850 1071 835 1071 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 835 1068 moveto +825 1071 lineto +835 1075 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 835 1068 moveto +825 1071 lineto +835 1075 lineto +closepath +stroke +end grestore +gsave 10 dict begin +861 1053 moveto +(od/or/oc) +[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs +gsave 10 dict begin +filled +0.333 1.000 1.000 nodecolor +782 954 70 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +782 954 70 18 ellipse_path +stroke +gsave 10 dict begin +724 949 moveto +(i_cn_rs_rs_rs_od_rs) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52] +xshow +end grestore +end grestore + +% i_cn_rs_rs_rs_od -> i_cn_rs_rs_rs_od_rs +newpath 782 1040 moveto +782 1024 782 1001 782 982 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 786 982 moveto +782 972 lineto +779 982 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 786 982 moveto +782 972 lineto +779 982 lineto +closepath +stroke +end grestore +gsave 10 dict begin +820 1009 moveto +(rs) +[4.56 5.52] +xshow +781 993 moveto +(test_other_state) +[3.84 6.24 5.52 3.84 6.96 6.96 3.84 6.96 6.24 4.56 6.96 5.52 3.84 6.24 3.84 6.24] +xshow +end grestore + +% i_cn_rs_rf_rs_rs -> i +newpath 1441 452 moveto +1441 473 1441 508 1441 538 curveto +1441 1478 1441 1478 1441 1478 curveto +1441 1504 1441 1533 1441 1554 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 1438 1554 moveto +1441 1564 lineto +1445 1554 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 1438 1554 moveto +1441 1564 lineto +1445 1554 lineto +closepath +stroke +end grestore +gsave 10 dict begin +1492 1009 moveto +(dn) +[6.96 6.96] +xshow +1441 993 moveto +(complete_disconnect) +[6.24 6.96 10.8 6.96 3.84 6.24 3.84 6.24 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs -> i_cn_rs_dn_rs +newpath 827 940 moveto +839 935 852 927 861 918 curveto +877 900 875 891 882 868 curveto +892 831 904 818 891 782 curveto +887 772 880 773 876 764 curveto +846 699 856 676 850 606 curveto +847 575 849 568 849 538 curveto +849 538 849 538 849 330 curveto +849 300 868 271 884 251 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 887 253 moveto +890 243 lineto +881 249 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 887 253 moveto +890 243 lineto +881 249 lineto +closepath +stroke +end grestore +gsave 10 dict begin +891 593 moveto +(dn) +[6.96 6.96] +xshow +850 577 moveto +(unregister_watch) +[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs -> i_cn_rs_rs_rs_od_rs +newpath 829 941 moveto +851 939 870 944 870 954 curveto +870 962 856 967 839 967 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 839 964 moveto +829 967 lineto +839 971 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 839 964 moveto +829 967 lineto +839 971 lineto +closepath +stroke +end grestore +gsave 10 dict begin +869 949 moveto +(od) +[6.96 6.96] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or +gsave 10 dict begin +filled +0.333 1.000 1.000 nodecolor +729 850 79 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +729 850 79 18 ellipse_path +stroke +gsave 10 dict begin +662 845 moveto +(i_cn_rs_rs_rs_od_rs_or) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52 6.96 6.96 4.56] +xshow +end grestore +end grestore + +% i_cn_rs_rs_rs_od_rs -> i_cn_rs_rs_rs_od_rs_or +newpath 773 936 moveto +764 920 752 896 743 877 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 746 875 moveto +738 868 lineto +740 878 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 746 875 moveto +738 868 lineto +740 878 lineto +closepath +stroke +end grestore +gsave 10 dict begin +796 905 moveto +(or/oc) +[6.96 4.56 3.84 6.96 6.24] +xshow +764 889 moveto +(write_connected) +[10.08 4.56 3.84 3.84 6.24 6.96 6.24 6.96 6.96 6.96 6.24 6.24 3.84 6.24 6.96] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or -> i_cn_rs_rs_dn +newpath 736 832 moveto +744 811 755 776 755 746 curveto +755 746 755 746 755 434 curveto +755 401 755 387 731 366 curveto +720 355 688 347 658 340 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 658 337 moveto +648 338 lineto +657 343 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 658 337 moveto +648 338 lineto +657 343 lineto +closepath +stroke +end grestore +gsave 10 dict begin +755 585 moveto +(dn) +[6.96 6.96] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or -> i_cn_rs_rs_rf +newpath 750 833 moveto +769 817 799 796 827 782 curveto +845 773 866 765 885 759 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 886 762 moveto +895 756 lineto +884 756 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 886 762 moveto +895 756 lineto +884 756 lineto +closepath +stroke +end grestore +gsave 10 dict begin +870 801 moveto +(rf) +[4.56 4.56] +xshow +827 785 moveto +(unregister_watch) +[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or -> i_cn_rs_rs_rs_od_rs_or +newpath 782 837 moveto +806 836 826 840 826 850 curveto +826 859 811 863 792 863 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 792 860 moveto +782 863 lineto +792 867 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 792 860 moveto +782 863 lineto +792 867 lineto +closepath +stroke +end grestore +gsave 10 dict begin +825 845 moveto +(od/or/oc) +[6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs +gsave 10 dict begin +filled +0.333 1.000 1.000 nodecolor +549 746 88 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +549 746 88 18 ellipse_path +stroke +gsave 10 dict begin +474 741 moveto +(i_cn_rs_rs_rs_od_rs_or_rs) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52 6.96 6.96 4.56 6.96 4.56 5.52] +xshow +end grestore +end grestore + +% i_cn_rs_rs_rs_od_rs_or -> i_cn_rs_rs_rs_od_rs_or_rs +newpath 692 834 moveto +679 828 665 821 652 814 curveto +628 800 602 783 582 769 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 584 766 moveto +574 763 lineto +580 772 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 584 766 moveto +574 763 lineto +580 772 lineto +closepath +stroke +end grestore +gsave 10 dict begin +697 801 moveto +(rs) +[4.56 5.52] +xshow +658 785 moveto +(test_other_state) +[3.84 6.24 5.52 3.84 6.96 6.96 3.84 6.96 6.24 4.56 6.96 5.52 3.84 6.24 3.84 6.24] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs -> i_cn_rs_rs +newpath 548 764 moveto +547 785 545 820 545 850 curveto +545 1162 545 1162 545 1162 curveto +545 1188 545 1217 545 1238 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 542 1238 moveto +545 1248 lineto +549 1238 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 542 1238 moveto +545 1248 lineto +549 1238 lineto +closepath +stroke +end grestore +gsave 10 dict begin +568 1009 moveto +(od) +[6.96 6.96] +xshow +545 993 moveto +(clear_store) +[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs -> i_cn_rs_dn_rs +newpath 564 728 moveto +568 722 573 716 577 710 curveto +642 614 752 341 835 262 curveto +843 254 851 249 861 244 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 863 247 moveto +870 239 lineto +860 241 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 863 247 moveto +870 239 lineto +860 241 lineto +closepath +stroke +end grestore +gsave 10 dict begin +746 489 moveto +(dn) +[6.96 6.96] +xshow +705 473 moveto +(unregister_watch) +[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs -> i_cn_rs_rs_rs_od_rs_or_rs +newpath 608 733 moveto +633 732 655 736 655 746 curveto +655 755 639 759 618 759 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 618 756 moveto +608 759 lineto +618 763 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 618 756 moveto +608 759 lineto +618 763 lineto +closepath +stroke +end grestore +gsave 10 dict begin +655 741 moveto +(or) +[6.96 4.56] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc +gsave 10 dict begin +filled +0.333 1.000 1.000 nodecolor +419 642 98 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +419 642 98 18 ellipse_path +stroke +gsave 10 dict begin +334 637 moveto +(i_cn_rs_rs_rs_od_rs_or_rs_oc) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52 6.96 6.96 4.56 6.96 4.56 5.52 6.96 6.96 6.24] +xshow +end grestore +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs -> i_cn_rs_rs_rs_od_rs_or_rs_oc +newpath 527 728 moveto +506 711 473 685 449 666 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 451 663 moveto +441 660 lineto +447 669 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 451 663 moveto +441 660 lineto +447 669 lineto +closepath +stroke +end grestore +gsave 10 dict begin +553 697 moveto +(oc) +[6.96 6.24] +xshow +504 681 moveto +(phase_two_connect) +[6.96 6.96 6.24 5.52 6.24 6.96 3.84 10.08 6.96 6.96 6.24 6.96 6.96 6.96 6.24 6.24 3.84] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc -> i_cn_rs_rs +newpath 422 660 moveto +431 713 455 872 455 1006 curveto +455 1162 455 1162 455 1162 curveto +455 1198 485 1227 510 1245 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 509 1248 moveto +519 1251 lineto +513 1243 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 509 1248 moveto +519 1251 lineto +513 1243 lineto +closepath +stroke +end grestore +gsave 10 dict begin +480 957 moveto +(rf) +[4.56 4.56] +xshow +455 941 moveto +(clear_store) +[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc_pe +gsave 10 dict begin +filled +0.667 1.000 1.000 nodecolor +179 538 108 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +179 538 108 18 ellipse_path +stroke +gsave 10 dict begin +83 533 moveto +(i_cn_rs_rs_rs_od_rs_or_rs_oc_pe) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52 6.96 6.96 4.56 6.96 4.56 5.52 6.96 6.96 6.24 6.96 6.96 6.24] +xshow +end grestore +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc -> i_cn_rs_rs_rs_od_rs_or_rs_oc_pe +newpath 364 627 moveto +351 622 338 615 327 606 curveto +315 595 321 584 307 574 curveto +296 565 282 559 268 553 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 269 550 moveto +258 550 lineto +267 556 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 269 550 moveto +258 550 lineto +267 556 lineto +closepath +stroke +end grestore +gsave 10 dict begin +333 585 moveto +(pe/od/or/oc) +[6.96 6.24 3.84 6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc_dn +gsave 10 dict begin +filled +0.106 1.000 1.000 nodecolor +287 434 108 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +287 434 108 18 ellipse_path +stroke +gsave 10 dict begin +191 429 moveto +(i_cn_rs_rs_rs_od_rs_or_rs_oc_dn) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52 6.96 6.96 4.56 6.96 4.56 5.52 6.96 6.96 6.24 6.96 6.96 6.96] +xshow +end grestore +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc -> i_cn_rs_rs_rs_od_rs_or_rs_oc_dn +newpath 416 624 moveto +411 599 400 553 379 520 curveto +363 496 340 473 320 458 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 322 455 moveto +312 452 lineto +318 461 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 322 455 moveto +312 452 lineto +318 461 lineto +closepath +stroke +end grestore +gsave 10 dict begin +400 533 moveto +(dn) +[6.96 6.96] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc_rs +gsave 10 dict begin +filled +0.333 1.000 1.000 nodecolor +545 538 106 18 ellipse_path +fill +0.000 0.000 0.000 nodecolor +545 538 106 18 ellipse_path +stroke +gsave 10 dict begin +451 533 moveto +(i_cn_rs_rs_rs_od_rs_or_rs_oc_rs) +[3.84 6.96 6.24 6.96 6.96 4.56 5.52 6.96 4.56 5.52 6.96 4.56 5.52 6.96 6.96 6.96 6.96 4.56 5.52 6.96 6.96 4.56 6.96 4.56 5.52 6.96 6.96 6.24 6.96 4.56 5.52] +xshow +end grestore +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc -> i_cn_rs_rs_rs_od_rs_or_rs_oc_rs +newpath 440 624 moveto +460 607 492 581 515 563 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 518 565 moveto +523 556 lineto +513 560 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 518 565 moveto +523 556 lineto +513 560 lineto +closepath +stroke +end grestore +gsave 10 dict begin +501 585 moveto +(rs) +[4.56 5.52] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc_pe -> i_cn_rs +newpath 170 556 moveto +141 618 51 825 51 1006 curveto +51 1266 51 1266 51 1266 curveto +51 1370 172 1318 274 1338 curveto +373 1356 678 1368 792 1373 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 792 1377 moveto +802 1373 lineto +792 1370 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 792 1377 moveto +802 1373 lineto +792 1370 lineto +closepath +stroke +end grestore +gsave 10 dict begin +114 957 moveto +(rs) +[4.56 5.52] +xshow +56 941 moveto +(phase_two_disconnect) +[6.96 6.96 6.24 5.52 6.24 6.96 3.84 10.08 6.96 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc_pe -> i_cn_rs_rs +newpath 191 556 moveto +217 596 280 694 323 782 curveto +356 848 360 866 385 936 curveto +397 966 409 973 409 1006 curveto +409 1162 409 1162 409 1162 curveto +409 1219 443 1239 493 1257 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 492 1261 moveto +503 1261 lineto +495 1254 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 492 1261 moveto +503 1261 lineto +495 1254 lineto +closepath +stroke +end grestore +gsave 10 dict begin +406 905 moveto +(rf) +[4.56 4.56] +xshow +381 889 moveto +(clear_store) +[6.24 3.84 6.24 6.24 4.56 6.96 5.52 3.84 6.96 4.56 6.24] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc_pe -> i_cn_rs_rs_rs_od_rs_or_rs_oc_pe +newpath 251 525 moveto +280 524 305 528 305 538 curveto +305 547 286 551 261 551 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 261 548 moveto +251 551 lineto +261 555 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 261 548 moveto +251 551 lineto +261 555 lineto +closepath +stroke +end grestore +gsave 10 dict begin +305 533 moveto +(pe/od/or/oc) +[6.96 6.24 3.84 6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc_pe -> i_cn_rs_rs_rs_od_rs_or_rs_oc_dn +newpath 198 520 moveto +216 503 242 478 261 459 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 263 462 moveto +268 452 lineto +258 457 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 263 462 moveto +268 452 lineto +258 457 lineto +closepath +stroke +end grestore +gsave 10 dict begin +250 481 moveto +(dn) +[6.96 6.96] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc_dn -> i_cn_rs_dn_rs +newpath 298 416 moveto +308 401 323 380 339 366 curveto +378 333 393 330 440 312 curveto +609 245 660 245 843 228 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 843 231 moveto +853 227 lineto +843 225 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 843 231 moveto +853 227 lineto +843 225 lineto +closepath +stroke +end grestore +gsave 10 dict begin +483 333 moveto +(rf) +[4.56 4.56] +xshow +440 317 moveto +(unregister_watch) +[6.96 6.96 4.56 6.24 6.96 3.84 5.52 3.84 6.24 4.56 6.96 10.08 6.24 3.84 6.24 6.96] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc_dn -> i_cn_rs_rs_dn +newpath 313 416 moveto +338 401 376 379 411 366 curveto +453 351 502 342 539 336 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 539 339 moveto +549 335 lineto +539 333 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 539 339 moveto +549 335 lineto +539 333 lineto +closepath +stroke +end grestore +gsave 10 dict begin +469 385 moveto +(rs) +[4.56 5.52] +xshow +411 369 moveto +(phase_two_disconnect) +[6.96 6.96 6.24 5.52 6.24 6.96 3.84 10.08 6.96 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc_dn -> i_cn_rs_rs_rs_od_rs_or_rs_oc_dn +newpath 359 421 moveto +388 420 413 424 413 434 curveto +413 443 394 447 369 447 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 369 444 moveto +359 447 lineto +369 451 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 369 444 moveto +359 447 lineto +369 451 lineto +closepath +stroke +end grestore +gsave 10 dict begin +413 429 moveto +(pe/od/or/oc) +[6.96 6.24 3.84 6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc_rs -> i_cn_rs +newpath 553 556 moveto +567 590 591 666 553 710 curveto +539 727 475 722 452 728 curveto +376 746 339 726 282 782 curveto +208 854 215 902 215 1006 curveto +215 1266 215 1266 215 1266 curveto +215 1325 651 1361 792 1371 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 792 1374 moveto +802 1372 lineto +792 1368 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 792 1374 moveto +802 1372 lineto +792 1368 lineto +closepath +stroke +end grestore +gsave 10 dict begin +247 957 moveto +(pe/od/or/oc) +[6.96 6.24 3.84 6.96 6.96 3.84 6.96 4.56 3.84 6.96 6.24] +xshow +216 941 moveto +(phase_two_disconnect) +[6.96 6.96 6.24 5.52 6.24 6.96 3.84 10.08 6.96 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84] +xshow +end grestore + +% i_cn_rs_rs_rs_od_rs_or_rs_oc_rs -> i_cn_rs_rs_dn +newpath 549 520 moveto +555 496 565 452 575 416 curveto +581 396 587 375 592 358 curveto +stroke +gsave 10 dict begin +solid +1 setlinewidth +0.000 0.000 0.000 edgecolor +newpath 595 359 moveto +595 348 lineto +589 357 lineto +closepath +fill +0.000 0.000 0.000 edgecolor +newpath 595 359 moveto +595 348 lineto +589 357 lineto +closepath +stroke +end grestore +gsave 10 dict begin +631 437 moveto +(dn) +[6.96 6.96] +xshow +575 421 moveto +(phase_two_disconnect) +[6.96 6.96 6.24 5.52 6.24 6.96 3.84 10.08 6.96 6.96 6.96 3.84 5.52 6.24 6.96 6.96 6.96 6.24 6.24 3.84] +xshow +end grestore +endpage +showpage +grestore +%%PageTrailer +%%EndPage: 1 +%%Trailer +%%Pages: 1 +end +restore +%%EOF diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,681 @@ +/*****************************************************************************/ +/* Xen inter-domain communication API. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef __ASM_XEN_XENIDC_H__ +#define __ASM_XEN_XENIDC_H__ + +#include +#include +#include "gnttab.h" +#include "xenbus.h" +#include "xenidc_callback.h" +#include "xenidc_local_buffer_reference.h" + +typedef struct xenidc_remote_buffer_reference_struct + xenidc_remote_buffer_reference; + +struct xenidc_remote_buffer_reference_struct +{ + xenidc_buffer_byte_count byte_count; +}; + +static inline xenidc_buffer_byte_count + xenidc_remote_buffer_reference_query_byte_count + ( xenidc_remote_buffer_reference * rbr ) +{ + return rbr->byte_count; +} + +typedef struct xenidc_address_struct xenidc_address; + +struct xenidc_address_struct +{ + char * local; + char * remote; + int remote_id; +}; + +static inline void xenidc_address_init + ( xenidc_address * address, char * local, char * remote, int remote_id ) +{ + address->local = local; + address->remote = remote; + address->remote_id = remote_id; +} + +static inline char * xenidc_address_query_local_domain + ( xenidc_address * address ) +{ + return address->local; +} + +static inline char * xenidc_address_query_remote_domain + ( xenidc_address * address ) +{ + return address->remote; +} + +static inline int xenidc_address_query_remote_domain_id + ( xenidc_address * address ) +{ + return address->remote_id; +} + +typedef struct xenidc_message_and_transaction_header_struct + xenidc_message_and_transaction_header; + +struct xenidc_message_and_transaction_header_struct +{ + xenidc_callback callback; + int transaction_not_message; +}; + +#define XENIDC_MESSAGE_AND_TRANSACTION_HEADER_LINK \ +callback.XENIDC_CALLBACK_LINK + +static inline struct list_head * xenidc_message_and_transaction_header_to_link + ( xenidc_message_and_transaction_header * header ) +{ + return xenidc_callback_to_link( &header->callback ); +} + +typedef struct xenidc_message_struct xenidc_message; + +struct xenidc_message_struct +{ + xenidc_message_and_transaction_header header; + xenidc_local_buffer_reference message; +}; + +static inline xenidc_callback * xenidc_message_to_callback + ( xenidc_message * message ) +{ + return &message->header.callback; +} + +static inline xenidc_message * xenidc_message_callback_to + ( xenidc_callback * callback ) +{ + return container_of( callback, xenidc_message, header.callback ); +} + +static inline struct list_head * xenidc_message_to_link + ( xenidc_message * message ) +{ + return xenidc_callback_to_link( &message->header.callback ); +} + +static inline xenidc_message * xenidc_message_link_to + ( struct list_head * link ) +{ + return xenidc_message_callback_to( xenidc_callback_link_to( link ) ); +} + +static inline xenidc_message * xenidc_message_header_to + ( xenidc_message_and_transaction_header * header ) +{ + return container_of( header, xenidc_message, header ); +} + +static inline void xenidc_message_init + ( xenidc_message * message, xenidc_callback_function * callback ) +{ + xenidc_callback_init( xenidc_message_to_callback( message ), callback ); + + message->header.transaction_not_message = 0; +} + +static inline void xenidc_message_set_message_lbr + ( xenidc_message * message, xenidc_local_buffer_reference lbr ) +{ + message->message = lbr; +} + +typedef struct xenidc_transaction_struct xenidc_transaction; + +struct xenidc_transaction_struct +{ + xenidc_message_and_transaction_header header; + xenidc_local_buffer_reference parameters; + xenidc_local_buffer_reference status; +}; + +#define XENIDC_TRANSACTION_LINK header.callback.XENIDC_CALLBACK_LINK + +static inline xenidc_callback * xenidc_transaction_to_callback + ( xenidc_transaction * transaction ) +{ + return &transaction->header.callback; +} + +static inline xenidc_transaction * xenidc_transaction_callback_to + ( xenidc_callback * callback ) +{ + return container_of( callback, xenidc_transaction, header.callback ); +} + +static inline struct list_head * xenidc_transaction_to_link + ( xenidc_transaction * transaction ) +{ + return xenidc_callback_to_link + ( xenidc_transaction_to_callback( transaction ) ); +} + +static inline xenidc_transaction * xenidc_transaction_link_to + ( struct list_head * link ) +{ + return xenidc_transaction_callback_to( xenidc_callback_link_to( link ) ); +} + +static inline xenidc_transaction * xenidc_transaction_header_to + ( xenidc_message_and_transaction_header * header ) +{ + return container_of( header, xenidc_transaction, header ); +} + +static inline void xenidc_transaction_init + ( xenidc_transaction * transaction, xenidc_callback_function * callback ) +{ + xenidc_callback_init + ( xenidc_transaction_to_callback( transaction ), callback ); + + transaction->header.transaction_not_message = 1; +} + +static inline void xenidc_transaction_set_parameters_lbr + ( xenidc_transaction * transaction, xenidc_local_buffer_reference lbr ) +{ + transaction->parameters = lbr; +} + +static inline void xenidc_transaction_set_status_lbr + ( xenidc_transaction * transaction, xenidc_local_buffer_reference lbr ) +{ + transaction->status = lbr; +} + +static inline void xenidc_transaction_complete + ( xenidc_transaction * transaction, xenidc_error error ) +{ + xenidc_callback_complete + ( xenidc_transaction_to_callback( transaction ), error ); +} + +static inline xenidc_error xenidc_transaction_query_error + ( xenidc_transaction * transaction ) +{ + return xenidc_callback_query_error + ( xenidc_transaction_to_callback( transaction ) ); +} + +typedef enum +{ + xenidc_endpoint_state_i, + xenidc_endpoint_state_i_cr, + xenidc_endpoint_state_i_cn, + xenidc_endpoint_state_i_cr_cn, + xenidc_endpoint_state_i_cr_xs, + xenidc_endpoint_state_i_cr_cn_xs, + xenidc_endpoint_state_i_cr_cn_xs_es +} +xenidc_endpoint_state; + +typedef struct xenidc_endpoint_initiator_resource_struct + xenidc_endpoint_initiator_resource; + +typedef struct xenidc_endpoint_target_resource_struct + xenidc_endpoint_target_resource; + +typedef struct xenidc_endpoint_struct xenidc_endpoint; + +struct xenidc_endpoint_struct +{ + void ( * connect )( xenidc_endpoint * endpoint ); + void ( * disconnect ) + ( xenidc_endpoint * endpoint, xenidc_callback * callback ); + void ( * message ) + ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference message ); + void ( * transaction ) + ( xenidc_endpoint * endpoint, xenidc_transaction * transaction ); + + u32 initiator_transaction_quota; + u32 target_transaction_quota; + xenidc_buffer_byte_count target_transaction_maximum_byte_count; + + xenidc_endpoint * send_irq_context; + xenidc_endpoint * recv_irq_context; + + struct list_head initiator_resource_list; + xenidc_endpoint_initiator_resource * initiator_resources; + + struct list_head target_resource_list; + xenidc_endpoint_target_resource * target_resources; + + spinlock_t lock; + xenidc_endpoint_state state; + struct list_head message_and_transaction_list; + struct list_head send_request_list; + xenidc_work xenstore_connect_1_work; + xenidc_work establish_connection_1_work; + xenidc_work kick_messages_and_transactions_1_work; + xenidc_work kick_send_ring_1_work; + xenidc_work kick_recv_ring_1_work; + xenidc_address address; + struct xenbus_watch watch; + grant_ref_t send_ring_ref; + unsigned int send_event_channel; + int send_irq; + grant_ref_t recv_ring_ref; + unsigned int recv_event_channel; + u16 recv_ring_handle; + unsigned int recv_event_channel_bound; + int recv_irq; + int destroyed : 1; +}; + +/* Init blocks for resource allocation. */ + +extern int xenidc_endpoint_init +( + xenidc_endpoint * endpoint, + + void ( * connect )( xenidc_endpoint * endpoint ), + void ( * disconnect ) + ( xenidc_endpoint * endpoint, xenidc_callback * callback ), + void ( * message ) + ( xenidc_endpoint * endpoint, xenidc_local_buffer_reference message ), + void ( * transaction ) + ( xenidc_endpoint * endpoint, xenidc_transaction * transaction ), + xenidc_buffer_byte_count initiator_message_maximum_byte_count, + u32 initiator_transaction_quota, + xenidc_buffer_byte_count initiator_transaction_maximum_byte_count, + xenidc_buffer_byte_count target_message_maximum_byte_count, + u32 target_transaction_quota, + xenidc_buffer_byte_count target_transaction_maximum_byte_count +); + +int xenidc_endpoint_create + ( xenidc_endpoint * endpoint, xenidc_address address ); + +extern void xenidc_endpoint_submit_message + ( xenidc_endpoint * endpoint, xenidc_message * message ); + +extern void xenidc_endpoint_submit_transaction + ( xenidc_endpoint * endpoint, xenidc_transaction * transaction ); + +/* Destroy blocks until disconnected */ + +extern void xenidc_endpoint_destroy( xenidc_endpoint * endpoint ); + +extern void xenidc_endpoint_exit( xenidc_endpoint * endpoint ); + +/*****************************************************************************/ +/* RESOURCE MANAGEMENT */ +/* */ +/* The bulk data transfer mechanism uses the following strategy for resource */ +/* management: */ +/* */ +/* 1) Create an anti-deadlock resource pool. This pool of resources is used */ +/* to guarantee that your subsystem can make progress independent of all */ +/* other subsystems using the xenidc API. The subsystem operations using */ +/* the resource pool must be independent and the resource pool must contain */ +/* enough resources to service the worst case individual operation. This */ +/* guarantees progress because, in the worst case, an operation can wait for */ +/* all other operations to complete (they are independent so they will */ +/* complete eventually) at which time the resource pool will be replenished */ +/* such that it contains enough resources to start the waiting operation. */ +/* */ +/* 2) Make a single atomic request to reserve and create/reserve and open */ +/* all of the local/remote buffers required for the operation to proceed to */ +/* completion. This request is guaranteed to complete because it is atomic */ +/* and so will eventually get a chance to acquire all the resources it needs */ +/* which by design will be less than the anti-deadlock reservation. */ +/* */ +/* 3) Dependent operations using independent anti-deadlock pools acquire */ +/* resources from pools in a defined order. */ +/* */ +/* An alternative implementation could support an additional API for the */ +/* following strategy which might be more convenient for some clients: */ +/* */ +/* 1) Create an anti-deadlock resource pool as above. */ +/* */ +/* 2) Make a single atomic reservation to reserve all the resources required */ +/* for an operation to proceed to completion. This request is guaranteed to */ +/* complete because it is atomic and so will eventually get a chance to */ +/* acquire all the resources it needs which by design will be less than the */ +/* anti-deadlock reservation. */ +/* */ +/* 3) Make an arbitrary number of create/open requests using the resources */ +/* reserved in step 2. These are guaranteed to complete because the */ +/* resources reserved in step 2 are sufficient by design. */ +/* */ +/* 4) Dependent operations using independent anti-deadlock pools acquire */ +/* resources from pools in a defined order. */ +/* */ +/* The following strategies are examples which in general DO NOT WORK: */ +/* */ +/* First incorrect strategy: */ +/* */ +/* 1) Have no anti-deadlock resource pool. */ +/* */ +/* This doesn't work because all the xenidc resources might be allocated to */ +/* an operation that is dependent on your subsystem for completion. A */ +/* deadlock results where your subsystem is waiting on xenidc which is */ +/* waiting on the client of your subsystem to free resources which is */ +/* waiting on your subsystem. */ +/* */ +/* Second incorrect strategy: */ +/* */ +/* 1) Create an anti-deadlock resource pool. */ +/* */ +/* 2) Make an arbitrary number of non-atomic reserve_and_create and */ +/* reserve_and_open requests for a single subsystem operation. */ +/* */ +/* In general, this doesn't work because your subsystem will be processing */ +/* multiple operations concurrently which means that the anti-deadlock */ +/* resources might get fully used by multiple concurrent operations in such */ +/* a way that none of the operations have enough resources to proceed so */ +/* they all end up waiting indefinitely on each other. */ +/* */ +/* Third incorrect strategy: */ +/* */ +/* 1) Create an anti-deadlock resource pool. */ +/* */ +/* 2) Use the same anti-deadlock pool for dependent operations. */ +/* */ +/* This doesn't work because an operation might acquire all the */ +/* anti-deadlock reservation and then initiate a second operation. The */ +/* second operation goes to the same anti-deadlock pool and waits forever */ +/* for the dependent operation to free the resources back. The dependent */ +/* operation never frees the resources because it is dependent on the second */ +/* operation. */ +/* */ +/* Fourth incorrect strategy: */ +/* */ +/* 1) Create anti-deadlock resource pools for different dependent */ +/* operations. */ +/* */ +/* 2) Different operations acquire resources from the pools in different */ +/* order. */ +/* */ +/* This doesn't work because of the potential for another cyclic deadlock. */ +/* */ +/*****************************************************************************/ + +/* TO CREATE REMOTE BUFFER REFERENCES TO GRANT OTHER DOMAINS ACCESS TO LOCAL */ +/* BUFFERS. */ + +typedef struct xenidc_rbr_provider_pool_struct xenidc_rbr_provider_pool; + +/* xenidc_allocate_rbr_provider_pool returns NULL if the pool cannot be */ +/* allocated or the anti-deadlock reservation fails. */ + +extern xenidc_rbr_provider_pool * xenidc_allocate_rbr_provider_pool + ( u32 anti_deadlock_page_count ); + +extern void xenidc_free_rbr_provider_pool( xenidc_rbr_provider_pool * pool ); + +typedef struct xenidc_create_rbr_request_element_struct + xenidc_create_rbr_request_element; + +struct xenidc_create_rbr_request_element_struct +{ + struct list_head link; + xenidc_local_buffer_reference lbr; + xenidc_remote_buffer_reference rbr; +}; + +static inline void xenidc_create_rbr_request_element_init + ( xenidc_create_rbr_request_element * element ) +{ + memset( element, 0, sizeof( *element ) ); + + INIT_LIST_HEAD( &element->link ); +} + +static inline void xenidc_create_rbr_request_element_set_lbr +( + xenidc_create_rbr_request_element * element, + xenidc_local_buffer_reference lbr +) +{ + element->lbr = lbr; +} + +static inline xenidc_remote_buffer_reference + xenidc_create_rbr_request_element_query_rbr + ( xenidc_create_rbr_request_element * element ) +{ + return element->rbr; +} + +static inline void xenidc_create_rbr_request_element_ensure_removed + ( xenidc_create_rbr_request_element * element ) +{ + list_del_init( &element->link ); +} + +typedef struct xenidc_reserve_and_create_rbr_request_struct + xenidc_reserve_and_create_rbr_request; + +struct xenidc_reserve_and_create_rbr_request_struct +{ + xenidc_callback create_callback; + xenidc_callback revoke_callback; + struct list_head request_elements; +}; + +static inline xenidc_callback * + xenidc_reserve_and_create_rbr_request_to_create_callback + ( xenidc_reserve_and_create_rbr_request * request ) +{ + return &request->create_callback; +} + +static inline xenidc_reserve_and_create_rbr_request * + xenidc_reserve_and_create_rbr_request_create_callback_to + ( xenidc_callback * callback ) +{ + return container_of + ( callback, xenidc_reserve_and_create_rbr_request, create_callback ); +} + +static inline xenidc_callback * + xenidc_reserve_and_create_rbr_request_to_revoke_callback + ( xenidc_reserve_and_create_rbr_request * request ) +{ + return &request->revoke_callback; +} + +static inline xenidc_reserve_and_create_rbr_request * + xenidc_reserve_and_create_rbr_request_revoke_callback_to + ( xenidc_callback * callback ) +{ + return container_of + ( callback, xenidc_reserve_and_create_rbr_request, revoke_callback ); +} + +static inline void xenidc_reserve_and_create_rbr_request_init +( + xenidc_reserve_and_create_rbr_request * request, + xenidc_callback_function * create_callback, + xenidc_callback_function * revoke_callback +) +{ + xenidc_callback_init( &request->create_callback, create_callback ); + xenidc_callback_init( &request->revoke_callback, revoke_callback ); + + INIT_LIST_HEAD( &request->request_elements ); +} + +static inline void xenidc_reserve_and_create_rbr_request_add_element +( + xenidc_reserve_and_create_rbr_request * request, + xenidc_create_rbr_request_element * element +) +{ + list_add( &element->link, &request->request_elements ); +} + +extern void xenidc_rbr_provider_pool_reserve_and_create_rbrs +( + xenidc_rbr_provider_pool * pool, + xenidc_reserve_and_create_rbr_request * request +); + +extern void xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs +( + xenidc_rbr_provider_pool * pool, + xenidc_reserve_and_create_rbr_request * request +); + +extern void xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs +( + xenidc_rbr_provider_pool * pool, + xenidc_reserve_and_create_rbr_request * request +); + +/* TO MAP REMOTE BUFFERS INTO THE LOCAL ADDRESS SPACE. */ + +typedef struct xenidc_rbr_mapper_pool_struct xenidc_rbr_mapper_pool; + +/* xenidc_allocate_rbr_mapper_pool returns NULL if the pool cannot be */ +/* allocated or the anti-deadlock reservation fails. */ + +extern xenidc_rbr_mapper_pool * xenidc_allocate_rbr_mapper_pool + ( u32 anti_deadlock_page_count ); + +extern void xenidc_free_rbr_mapper_pool( xenidc_rbr_mapper_pool * pool ); + +typedef struct xenidc_map_rbr_request_element_struct + xenidc_map_rbr_request_element; + +struct xenidc_map_rbr_request_element_struct +{ + struct list_head link; + xenidc_remote_buffer_reference rbr; + void * mapping; +}; + +static inline void xenidc_map_rbr_request_element_init + ( xenidc_map_rbr_request_element * element ) +{ + memset( element, 0, sizeof( *element ) ); + + INIT_LIST_HEAD( &element->link ); +} + +static inline void xenidc_map_rbr_request_element_set_rbr +( + xenidc_map_rbr_request_element * element, + xenidc_remote_buffer_reference rbr +) +{ + element->rbr = rbr; +} + +static inline void xenidc_map_rbr_request_element_ensure_removed + ( xenidc_map_rbr_request_element * element ) +{ + list_del_init( &element->link ); +} + +typedef struct xenidc_reserve_and_map_rbr_request_struct + xenidc_reserve_and_map_rbr_request; + +struct xenidc_reserve_and_map_rbr_request_struct +{ + xenidc_callback map_callback; + xenidc_callback unmap_callback; + struct list_head request_elements; +}; + +static inline xenidc_callback * + xenidc_reserve_and_map_rbr_request_to_map_callback + ( xenidc_reserve_and_map_rbr_request * request ) +{ + return &request->map_callback; +} + +static inline xenidc_reserve_and_map_rbr_request * + xenidc_reserve_and_map_rbr_request_map_callback_to + ( xenidc_callback * callback ) +{ + return container_of + ( callback, xenidc_reserve_and_map_rbr_request, map_callback ); +} + +static inline xenidc_callback * + xenidc_reserve_and_map_rbr_request_to_unmap_callback + ( xenidc_reserve_and_map_rbr_request * request ) +{ + return &request->unmap_callback; +} + +static inline xenidc_reserve_and_map_rbr_request * + xenidc_reserve_and_map_rbr_request_unmap_callback_to + ( xenidc_callback * callback ) +{ + return container_of + ( callback, xenidc_reserve_and_map_rbr_request, unmap_callback ); +} + +static inline void xenidc_reserve_and_map_rbr_request_init +( + xenidc_reserve_and_map_rbr_request * request, + xenidc_callback_function * map_callback, + xenidc_callback_function * unmap_callback +) +{ + xenidc_callback_init( &request->map_callback, map_callback ); + xenidc_callback_init( &request->unmap_callback, unmap_callback ); + + INIT_LIST_HEAD( &request->request_elements ); +} + +static inline void xenidc_reserve_and_map_rbr_request_add_element +( + xenidc_reserve_and_map_rbr_request * request, + xenidc_map_rbr_request_element * element +) +{ + list_add( &element->link, &request->request_elements ); +} + +extern void xenidc_rbr_mapper_pool_reserve_and_map_rbrs +( + xenidc_rbr_mapper_pool * pool, + xenidc_reserve_and_map_rbr_request * request +); + +extern void xenidc_rbr_mapper_pool_abort_reserve_and_map_rbrs +( + xenidc_rbr_mapper_pool * pool, + xenidc_reserve_and_map_rbr_request * request +); + +extern void xenidc_rbr_mapper_pool_unmap_and_unreserve_rbrs +( + xenidc_rbr_mapper_pool * pool, + xenidc_reserve_and_map_rbr_request * request +); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_callback.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_callback.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,166 @@ +/*****************************************************************************/ +/* A callback object for use in scheduling completion of asynchronous */ +/* requests. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef XENIDC_CALLBACK_H +#define XENIDC_CALLBACK_H + +#include +#include "xenidc_error.h" +#include "xenidc_work.h" + +/* Service parameter blocks contain callbacks for asynchronous completions. */ + +typedef struct xenidc_callback_struct xenidc_callback; + +struct xenidc_callback_struct +{ + xenidc_work work; + xenidc_error error; +}; + +#define XENIDC_CALLBACK_LINK work.XENIDC_WORK_LINK + +/* Client of service initialises callback with its callback function. */ + +typedef void ( xenidc_callback_function )( xenidc_callback * callback ); + +static inline void xenidc_callback_init + ( xenidc_callback * callback, xenidc_callback_function * function ) +{ + xenidc_work_init( &callback->work, (void(*)(void*))function, callback ); + + callback->error = XENIDC_ERROR_SUCCESS; +} + +/* Client may use link whilst it owns parameter block. Service may use link */ +/* whilst it owns parameter block. Link is reserved whilst callback is */ +/* scheduled for completion. */ + +static inline struct list_head * xenidc_callback_to_link + ( xenidc_callback * callback ) +{ + return xenidc_work_to_link( &callback->work ); +} + +static inline xenidc_callback * xenidc_callback_link_to + ( struct list_head * link ) +{ + return container_of + ( xenidc_work_link_to( link ), xenidc_callback, work ); +} + +/* Service which completes requests concurrently may call */ +/* xenidc_callback_complete or xenidc_callback_success to complete the */ +/* callback. */ + +static inline void xenidc_callback_complete + ( xenidc_callback * callback, xenidc_error error ) +{ + callback->error = error; + + xenidc_work_schedule( &callback->work ); +} + +static inline void xenidc_callback_success + ( xenidc_callback * callback ) +{ + xenidc_callback_complete( callback, 0 ); +} + +/* These functions used by serialiser below. */ + +static inline void xenidc_callback_set_error + ( xenidc_callback * callback, xenidc_error error ) +{ + callback->error = error; +} + +static inline void xenidc_callback_complete_synchronously + ( xenidc_callback * callback ) +{ + xenidc_work_perform_synchronously( &callback->work ); +} + +/* When callback completes, client may call xenidc_callback_query_error to */ +/* get the error code. */ + +static inline xenidc_error xenidc_callback_query_error + ( xenidc_callback * callback ) +{ + return callback->error; +} + +/* Services which must serialise completions to preserve submission order */ +/* can use one of these. */ + +typedef struct xenidc_callback_serialiser_struct xenidc_callback_serialiser; + +struct xenidc_callback_serialiser_struct +{ + spinlock_t lock; + struct list_head list; + xenidc_work work; + int running; +}; + +void xenidc_callback_serialiser_function( void * context ); + +#define XENIDC_CALLBACK_SERIALISER_INIT( name ) \ +{ \ + SPIN_LOCK_UNLOCKED, \ + LIST_HEAD_INIT( name.list ), \ + XENIDC_WORK_INIT \ + ( name.work, xenidc_callback_serialiser_function, &name ), \ + 0 \ +} + +#define XENIDC_CALLBACK_SERIALISER( name ) \ +xenidc_callback_serialiser name = \ + XENIDC_CALLBACK_SERIALISER_INIT( name ) + +/* The service completes the callback to the serialiser which serialises the */ +/* completions to the client, performing them in submission order. */ + +static inline void xenidc_callback_serialiser_complete_callback +( + xenidc_callback_serialiser * serialiser, + xenidc_callback * callback, + xenidc_error error +) +{ + xenidc_callback_set_error( callback, error ); + + { + unsigned long flags; + + spin_lock_irqsave( &serialiser->lock, flags ); + + list_add_tail + ( xenidc_callback_to_link( callback ), &serialiser->list ); + + spin_unlock_irqrestore( &serialiser->lock, flags ); + } + + xenidc_work_schedule( &serialiser->work ); +} + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_channel.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_channel.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,143 @@ +/*****************************************************************************/ +/* Xen inter-domain communication channel abstract base class. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef _XENIDC_CHANNEL_H +#define _XENIDC_CHANNEL_H + +#include +#include + +typedef struct xenidc_channel_message_struct xenidc_channel_message; + +struct xenidc_channel_message_struct +{ + xenidc_callback callback; + xenidc_local_buffer_reference lbr; +}; + +#define XENIDC_CHANNEL_MESSAGE_LINK callback.XENIDC_CALLBACK_LINK + +static inline struct list_head * xenidc_channel_message_to_link + ( xenidc_channel_message * message ) +{ + return &message->XENIDC_CHANNEL_MESSAGE_LINK; +} + +static inline xenidc_callback * xenidc_channel_message_to_callback + ( xenidc_channel_message * message ) +{ + return &message->callback; +} + +static inline xenidc_channel_message * xenidc_channel_message_callback_to + ( xenidc_callback * callback ) +{ + return container_of( callback, xenidc_channel_message, callback ); +} + +static inline void xenidc_channel_message_init + ( xenidc_channel_message * message, xenidc_callback_function * callback ) +{ + xenidc_callback_init + ( xenidc_channel_message_to_callback( message ), callback ); +} + +static inline void xenidc_channel_message_set_message_lbr + ( xenidc_channel_message * message, xenidc_local_buffer_reference lbr ) +{ + message->lbr = lbr; +} + +typedef struct xenidc_channel_struct xenidc_channel; + +struct xenidc_channel_struct +{ + void ( * submit_message ) + ( xenidc_channel * channel, xenidc_channel_message * message ); + void ( * connect )( xenidc_channel * channel ); + void ( * handle_message ) + ( xenidc_channel * channel, xenidc_channel_message * message ); + void ( * disconnect ) + ( xenidc_channel * channel, xenidc_callback * callback ); +}; + +/* Called by a derived class to initialise the base class. */ + +static inline void xenidc_channel_init +( + xenidc_channel * channel, + void ( * submit_message ) + ( xenidc_channel * channel, xenidc_channel_message * message ) +) +{ + channel->submit_message = submit_message; +} + +/* Called by a derived class to notify the client. */ + +static inline void xenidc_channel_connect( xenidc_channel * channel ) +{ + channel->connect( channel ); +} + +/* Called by a derived class to notify the client. */ + +static inline void xenidc_channel_handle_message + ( xenidc_channel * channel, xenidc_channel_message * message ) +{ + channel->handle_message( channel, message ); +} + +/* Called by a derived class to notify the client. */ + +static inline void xenidc_channel_disconnect + ( xenidc_channel * channel, xenidc_callback * callback ) +{ + channel->disconnect( channel, callback ); +} + +/* Called by the client class before derived class first calls connect. */ + +static inline void xenidc_channel_install_client +( + xenidc_channel * channel, + void ( * connect )( xenidc_channel * channel ), + void ( * handle_message ) + ( xenidc_channel * channel, xenidc_channel_message * message ), + void ( * disconnect ) + ( xenidc_channel * channel, xenidc_callback * callback ) +) +{ + channel->connect = connect; + channel->handle_message = handle_message; + channel->disconnect = disconnect; +} + +/* Called by the client class between connect and disconnect callback to */ +/* submit a message. */ + +static inline void xenidc_channel_submit_message + ( xenidc_channel * channel, xenidc_channel_message * message ) +{ + channel->submit_message( channel, message ); +} + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_concatenate.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_concatenate.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,47 @@ +/*****************************************************************************/ +/* Support for concatenated local buffer references */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef XENIDC_CONCATENATE_H +#define XENIDC_CONCATENATE_H + +#include "xenidc.h" + +typedef struct xenidc_concatenate_base_struct xenidc_concatenate_base; + +struct xenidc_concatenate_base_struct +{ + xenidc_local_buffer_reference * head; + xenidc_local_buffer_reference * tail; +}; + +/* To create a concatenated lbr, you need a base resource which will persist */ +/* for the lifetime of the created lbr. Pass a pointer to this resource and */ +/* pointers to the underlying lbrs to concatenate. These must also persist */ +/* for the lifetime of the created lbr. */ + +extern xenidc_local_buffer_reference xenidc_concatenate_create_lbr +( + xenidc_concatenate_base * base, + xenidc_local_buffer_reference * head, + xenidc_local_buffer_reference * tail +); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_error.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_error.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,55 @@ +#ifndef __ASM_XEN_XENIDC_ERROR_H__ +#define __ASM_XEN_XENIDC_ERROR_H__ + +#include + +typedef u32 xenidc_error; + +/* The first few error numbers are reserved for success and transport errors */ +/* which are common to all IDC protocols. */ + +#define XENIDC_ERROR_SUCCESS ( (xenidc_error)0 ) +#define XENIDC_ERROR_ABORTED ( (xenidc_error)1 ) +#define XENIDC_ERROR_FAILURE ( (xenidc_error)2 ) +/* Initiator did everything right, target software needs to be fixed: */ +#define XENIDC_ERROR_IMPLEMENTATION_DEFICIENCY ( (xenidc_error)3 ) +/* Unexpected transaction/transaction in wrong sequence etc: */ +#define XENIDC_ERROR_INVALID_PROTOCOL ( (xenidc_error)4 ) +/* Underlength parameters/status etc: */ +#define XENIDC_ERROR_INVALID_FORMAT ( (xenidc_error)5 ) +/* Parameter value wrong: */ +#define XENIDC_ERROR_INVALID_PARAMETER ( (xenidc_error)6 ) +/* Something about a request exceeded a hard-coded limit: */ +#define XENIDC_ERROR_TOO_BIG ( (xenidc_error)7 ) + +static inline xenidc_error xenidc_error_map_local_to( int error ) +{ + /* FIXME */ + switch( error ) + { + case 0: + return XENIDC_ERROR_SUCCESS; + default: + return XENIDC_ERROR_FAILURE; + } +} + +static inline int xenidc_error_map_to_local( xenidc_error error ) +{ + /* FIXME */ + switch( error ) + { + case XENIDC_ERROR_SUCCESS: + return 0; + default: + return -1; + } +} + +/* Protocols can define their own set of protocol specific errors starting */ +/* at this one. The driver code on either side must translate between the */ +/* local OS specific error codes and the protocol specific error codes. */ + +#define XENIDC_ERROR_PROTOCOL_SPECIFIC_FIRST ( (xenidc_error)256 ) + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_gnttab_channel.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_gnttab_channel.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,193 @@ +/*****************************************************************************/ +/* Xen inter-domain communication channel implementation based on grant */ +/* tables. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef _XENIDC_GNTTAB_CHANNEL_H +#define _XENIDC_GNTTAB_CHANNEL_H + +#include +#include + +typedef struct xenidc_gnttab_channel_struct xenidc_gnttab_channel; + +typedef struct xenidc_gnttab_channel_target_resource_struct + xenidc_gnttab_channel_target_resource; + +struct xenidc_gnttab_channel_target_resource_struct +{ + xenidc_channel_message message; + xenidc_gnttab_channel * channel; +}; + +#define XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_LINK \ +message.XENIDC_CHANNEL_MESSAGE_LINK + +typedef enum +{ + xenidc_gnttab_channel_state_i +} +xenidc_gnttab_channel_state; + +#define XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT 16 + +struct xenidc_gnttab_channel_struct +{ + xenidc_channel channel; + void ( * protocol_error )( xenidc_gnttab_channel * channel ); + + xenidc_gnttab_channel * send_irq_context; + xenidc_gnttab_channel * recv_irq_context; + + void * send_ring; + struct vm_struct * recv_ring_area; + grant_ref_t grant_ref_pool; + + spinlock_t lock; + + xenidc_gnttab_channel_state state; + + struct list_head message_list; + + xenidc_work do_phase_one_connect_1_work; + xenidc_work do_phase_two_connect_1_work; + xenidc_work connect_client_1_work; + xenidc_work disconnect_client_1_work; + xenidc_callback disconnect_client_2_callback; + xenidc_work do_phase_two_disconnect_1_work; + xenidc_work do_phase_one_disconnect_1_work; + xenidc_work kick_send_ring_1_work; + xenidc_work kick_recv_ring_1_work; + + struct list_head free_target_resource_list; + + xenidc_gnttab_channel_target_resource target_resources + [ XENIDC_GNTTAB_CHANNEL_TARGET_RESOURCE_COUNT ]; + + int target_resources_out; + + xenidc_callback * current_callback; + + unsigned int send_event_channel; + grant_ref_t send_ring_ref; + int send_irq; + + unsigned int recv_event_channel; + u16 recv_ring_handle; + int recv_irq; +}; + +/* Cast to base class. */ + +static inline xenidc_channel * xenidc_gnttab_channel_to_channel + ( xenidc_gnttab_channel * channel ) +{ + return &channel->channel; +} + +/* Cast from base class. */ + +static inline xenidc_gnttab_channel * xenidc_gnttab_channel_channel_to + ( xenidc_channel * channel ) +{ + return container_of( channel, xenidc_gnttab_channel, channel ); +} + +/* Called by derived class. */ + +extern int xenidc_gnttab_channel_init +( + xenidc_gnttab_channel * channel, + void ( * protocol_error )( xenidc_gnttab_channel * channel ) +); + +/* xenidc_gnttab_channel_phase_one_connect should never fail because we are */ +/* supposed to have reserved all required resources during initialisation. */ +/* Called by derived class. */ + +typedef struct xenidc_gnttab_channel_phase_one_connect_request_struct + xenidc_gnttab_channel_phase_one_connect_request; + +struct xenidc_gnttab_channel_phase_one_connect_request_struct +{ + xenidc_callback callback; + domid_t remote_domain_id; /* IN */ + grant_ref_t send_ring_ref; /* OUT */ + unsigned int send_event_channel; /* OUT */ +}; + +static inline xenidc_gnttab_channel_phase_one_connect_request * + xenidc_gnttab_channel_phase_one_connect_request_callback_to + ( xenidc_callback * callback ) +{ + return container_of + ( callback, xenidc_gnttab_channel_phase_one_connect_request, callback ); +} + +extern void xenidc_gnttab_channel_phase_one_connect +( + xenidc_gnttab_channel * channel, + xenidc_gnttab_channel_phase_one_connect_request * request +); + +/* xenidc_gnttab_channel_phase_two_connect should only fail if the remote */ +/* domain provided incorrect parameters. */ +/* Called by derived class. */ + +typedef struct xenidc_gnttab_channel_phase_two_connect_request_struct + xenidc_gnttab_channel_phase_two_connect_request; + +struct xenidc_gnttab_channel_phase_two_connect_request_struct +{ + xenidc_callback callback; + domid_t remote_domain_id; /* IN */ + grant_ref_t recv_ring_ref; /* IN */ + unsigned int recv_event_channel; /* IN */ +}; + +static inline xenidc_gnttab_channel_phase_two_connect_request * + xenidc_gnttab_channel_phase_two_connect_request_callback_to + ( xenidc_callback * callback ) +{ + return container_of + ( callback, xenidc_gnttab_channel_phase_two_connect_request, callback ); +} + +extern void xenidc_gnttab_channel_phase_two_connect +( + xenidc_gnttab_channel * channel, + xenidc_gnttab_channel_phase_two_connect_request * request +); + +/* Called by derived class. */ + +extern void xenidc_gnttab_channel_phase_two_disconnect + ( xenidc_gnttab_channel * channel, xenidc_callback * callback ); + +/* Called by derived class. */ + +extern void xenidc_gnttab_channel_phase_one_disconnect + ( xenidc_gnttab_channel * channel, xenidc_callback * callback ); + +/* Called by derived class. */ + +extern void xenidc_gnttab_channel_exit( xenidc_gnttab_channel * channel ); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_local_buffer_reference.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_local_buffer_reference.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,103 @@ +/*****************************************************************************/ +/* Xen inter-domain communication local buffer reference object. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef __ASM_XEN_XENIDC_LOCAL_BUFFER_REFERENCE_H__ +#define __ASM_XEN_XENIDC_LOCAL_BUFFER_REFERENCE_H__ + +#include +#include "xenidc_callback.h" + +typedef u32 xenidc_buffer_type; + +typedef u32 xenidc_buffer_byte_count; + +typedef struct xenidc_local_buffer_reference_struct + xenidc_local_buffer_reference; + +struct xenidc_local_buffer_reference_struct +{ + xenidc_buffer_type type; + void * base; + xenidc_buffer_byte_count byte_offset; + xenidc_buffer_byte_count byte_count; +}; + +static inline xenidc_buffer_byte_count + xenidc_local_buffer_reference_query_byte_offset + ( xenidc_local_buffer_reference * lbr ) +{ + return lbr->byte_offset; +} + +static inline xenidc_buffer_byte_count + xenidc_local_buffer_reference_query_byte_count + ( xenidc_local_buffer_reference * lbr ) +{ + return lbr->byte_count; +} + +/* Copy out of a buffer into a target buffer. Returns the number of bytes */ +/* copied which is the minimum of the source and target byte_counts. */ + +extern xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_out +( + xenidc_local_buffer_reference * buffer_reference, + void * target, + xenidc_buffer_byte_count target_byte_count +); + +extern xenidc_buffer_byte_count xenidc_local_buffer_reference_copy_in +( + xenidc_local_buffer_reference * buffer_reference, + void * source, + xenidc_buffer_byte_count source_byte_count +); + +extern xenidc_buffer_byte_count xenidc_local_buffer_reference_copy +( + xenidc_local_buffer_reference * target, + xenidc_local_buffer_reference * source +); + +extern void xenidc_local_buffer_reference_zero + ( xenidc_local_buffer_reference * buffer_reference ); + +/* Advance increments the offset and decrements the length by the amount */ +/* specified which is useful to advance the reference after having copied a */ +/* chunk of data into the start of the buffer. */ + +extern xenidc_buffer_byte_count xenidc_local_buffer_reference_advance +( + xenidc_local_buffer_reference * buffer_reference, + xenidc_buffer_byte_count byte_count +); + +/* Truncate reduces the length of the buffer which results in a reference to */ +/* the first byte_count bytes of the buffer (or the whole buffer, whichever */ +/* is less). */ + +extern xenidc_buffer_byte_count xenidc_local_buffer_reference_truncate +( + xenidc_local_buffer_reference * buffer_reference, + xenidc_buffer_byte_count byte_count +); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_vaddress.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_vaddress.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,30 @@ +/*****************************************************************************/ +/* Support for local buffer references of type vaddress. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef XENIDC_VADDRESS_H +#define XENIDC_VADDRESS_H + +#include "xenidc.h" + +extern xenidc_local_buffer_reference xenidc_vaddress_create_lbr + ( void * address, xenidc_buffer_byte_count byte_count ); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_work.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_work.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,160 @@ +/*****************************************************************************/ +/* Enhanced work queue service */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/* This work queue service is a lot like the linux work queue service except */ +/* that it provides the interface xenidc_work_until which allows the client */ +/* to wait for a condition to be met even when the client is executing on a */ +/* work thread and the condition will only be satisfied by execution of */ +/* another work item. */ + +#ifndef XENIDC_WORK_H +#define XENIDC_WORK_H + +#include +#include +#include +#include +#include + +typedef struct xenidc_work_struct xenidc_work; + +struct xenidc_work_struct +{ + struct list_head link; + void ( * function )( void * context ); + void * context; +}; + +#define XENIDC_WORK_LINK link + +#define XENIDC_WORK_INIT( name, fn, ctx ) \ +{ LIST_HEAD_INIT( name.link ), fn, ctx } + +#define XENIDC_WORK( name, fn, ctx ) \ +xenidc_work name = XENIDC_WORK_INIT( name, fn, ctx ) + +static inline void xenidc_work_init +( + xenidc_work * work, + void ( * function )( void * context ), + void * context +) +{ + INIT_LIST_HEAD( &work->link ); + + work->function = function; + work->context = context; +} + +static inline struct list_head * xenidc_work_to_link( xenidc_work * work ) +{ + return &work->link; +} + +static inline xenidc_work * xenidc_work_link_to( struct list_head * link ) +{ + return container_of( link, xenidc_work, link ); +} + +/* Returns 1 if scheduled this time or 0 if already scheduled. */ + +int xenidc_work_schedule( xenidc_work * work ); + +static inline void xenidc_work_perform_synchronously( xenidc_work * work ) +{ + work->function( work->context ); +} + +/* Don't use any of these, they're just exposed for the macro below. */ + +extern spinlock_t xenidc_work_list_lock; + +extern struct list_head xenidc_work_list; + +extern wait_queue_head_t xenidc_work_waitqueue; + +extern struct list_head xenidc_work_condition; + +/* Wait for a condition to be met. This works whether or not you call it */ +/* from a work item and works even when the condition will only be satisfied */ +/* by another work item. */ + +#define xenidc_work_until( condition ) \ +do \ +{ \ + unsigned long flags; \ + \ + spin_lock_irqsave( &xenidc_work_list_lock, flags ); \ + \ + for( ; ; ) \ + { \ + while \ + ( \ + ( !list_empty( &xenidc_work_list ) ) \ + && \ + ( !( condition ) ) \ + ) \ + { \ + xenidc_work * work = list_entry \ + ( \ + xenidc_work_list.next, \ + xenidc_work, \ + link \ + ); \ + \ + list_del_init( &work->link ); \ + \ + spin_unlock_irqrestore( &xenidc_work_list_lock, flags ); \ + \ + xenidc_work_perform_synchronously( work ); \ + \ + spin_lock_irqsave( &xenidc_work_list_lock, flags ); \ + } \ + \ + if( condition ) \ + { \ + break; \ + } \ + \ + { \ + struct list_head link; \ + \ + INIT_LIST_HEAD( &link ); \ + \ + list_add_tail( &link, &xenidc_work_condition ); \ + \ + spin_unlock_irqrestore( &xenidc_work_list_lock, flags ); \ + \ + wait_event( xenidc_work_waitqueue, list_empty( &link ) ); \ + \ + spin_lock_irqsave( &xenidc_work_list_lock, flags ); \ + } \ + } \ + \ + spin_unlock_irqrestore( &xenidc_work_list_lock, flags ); \ +} \ +while( 0 ) + +/* When you satisfy a condition, you should call this to kick any threads */ +/* waiting on the condition. */ + +void xenidc_work_wake_up( void ); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_wrapping.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_wrapping.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,48 @@ +/*****************************************************************************/ +/* Support for wrapping buffer local buffer references */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef XENIDC_WRAPPING_H +#define XENIDC_WRAPPING_H + +#include "xenidc.h" + +typedef enum +{ + xenidc_wrapping_client_type_producer, + xenidc_wrapping_client_type_consumer +} +xenidc_wrapping_client_type; + +/* Create a reference to a wrapping buffer. Pass the start offset and the */ +/* end offset of the section of interest of the wrapping buffer. If the */ +/* start and end offsets are the same then a producer will get a reference */ +/* to the whole buffer to fill whereas a consumer will get a reference to a */ +/* zero length buffer. */ + +extern xenidc_local_buffer_reference xenidc_wrapping_create_lbr +( + xenidc_local_buffer_reference * underlying_buffer, + xenidc_buffer_byte_count start_offset, + xenidc_buffer_byte_count end_offset, + xenidc_wrapping_client_type client_type +); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 linux-2.6-xen-sparse/include/asm-xen/xenidc_xbgt_channel.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenidc_xbgt_channel.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,139 @@ +/*****************************************************************************/ +/* Xen inter-domain communication channel implementation based on xenbus and */ +/* grant tables. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef _XENIDC_XBGT_CHANNEL_H +#define _XENIDC_XBGT_CHANNEL_H + +#include +#include + +typedef struct xenidc_xbgt_channel_struct xenidc_xbgt_channel; + +typedef enum +{ + xenidc_xbgt_channel_state_i, + xenidc_xbgt_channel_state_i_cn, + xenidc_xbgt_channel_state_i_cn_dn, + xenidc_xbgt_channel_state_i_cn_rs, + xenidc_xbgt_channel_state_i_cn_dn_rs, + xenidc_xbgt_channel_state_i_cn_rs_dn, + xenidc_xbgt_channel_state_i_cn_rs_rs, + xenidc_xbgt_channel_state_i_cn_rs_rf, + xenidc_xbgt_channel_state_i_cn_dn_rs_rs, + xenidc_xbgt_channel_state_i_cn_rs_dn_rs, + xenidc_xbgt_channel_state_i_cn_rs_rs_dn, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs, + xenidc_xbgt_channel_state_i_cn_rs_rs_rf, + xenidc_xbgt_channel_state_i_cn_rs_rf_rs, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od, + xenidc_xbgt_channel_state_i_cn_rs_rf_rs_rs, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_pe, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_dn, + xenidc_xbgt_channel_state_i_cn_rs_rs_rs_od_rs_or_rs_oc_rs +} +xenidc_xbgt_channel_state; + +typedef enum +{ + xenidc_xbgt_channel_other_state_unknown, + xenidc_xbgt_channel_other_state_disconnected, + xenidc_xbgt_channel_other_state_ready, + xenidc_xbgt_channel_other_state_connected +} +xenidc_xbgt_channel_other_state; + +struct xenidc_xbgt_channel_struct +{ + xenidc_gnttab_channel channel; + + struct xenbus_watch watch; + + spinlock_t lock; + + xenidc_xbgt_channel_state state; + xenidc_xbgt_channel_other_state other_state; + + char * local_path; + char * remote_path; + domid_t remote_domain_id; + + xenidc_callback * disconnect_callback; + + int ready_ring_reference; + int ready_event_channel; + + xenidc_work register_watch_1_work; + xenidc_work unregister_watch_1_work; + xenidc_work clear_store_1_work; + xenidc_work write_ready_1_work; + xenidc_work write_connected_1_work; + xenidc_work phase_one_connect_1_work; + xenidc_work phase_two_connect_1_work; + xenidc_work phase_two_disconnect_1_work; + xenidc_work phase_one_disconnect_1_work; + + xenidc_gnttab_channel_phase_one_connect_request phase_one_connect_request; + xenidc_gnttab_channel_phase_two_connect_request phase_two_connect_request; + + xenidc_callback phase_two_disconnect_callback; + xenidc_callback phase_one_disconnect_callback; +}; + +static inline xenidc_channel * xenidc_xbgt_channel_to_channel + ( xenidc_xbgt_channel * channel ) +{ + return xenidc_gnttab_channel_to_channel( &channel->channel ); +} + +static inline xenidc_xbgt_channel * xenidc_xbgt_channel_gnttab_channel_to + ( xenidc_gnttab_channel * gnttab_channel ) +{ + return container_of( gnttab_channel, xenidc_xbgt_channel, channel ); +} + +static inline xenidc_xbgt_channel * xenidc_xbgt_channel_channel_to + ( xenidc_channel * channel ) +{ + return xenidc_xbgt_channel_gnttab_channel_to + ( xenidc_gnttab_channel_channel_to( channel ) ); +} + +extern int xenidc_xbgt_channel_init( xenidc_xbgt_channel * channel ); + +extern void xenidc_xbgt_channel_connect +( + xenidc_xbgt_channel * channel, + char * local_path, + char * remote_path, + domid_t remote_domain_id +); + +extern void xenidc_xbgt_channel_disconnect + ( xenidc_xbgt_channel * channel, xenidc_callback * callback ); + +extern void xenidc_xbgt_channel_exit( xenidc_xbgt_channel * channel ); + +#endif diff -r 1c62a4149b11 -r 5952173acc28 patches/linux-2.6.12/usb.patch --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/patches/linux-2.6.12/usb.patch Mon Oct 24 15:04:49 2005 @@ -0,0 +1,10 @@ +diff -Naur linux-2.6.12/drivers/usb/core/usb.c linux-2.6.12-usb/drivers/usb/core/usb.c +--- linux-2.6.12/drivers/usb/core/usb.c 2005-06-17 20:48:29.000000000 +0100 ++++ linux-2.6.12-usb/drivers/usb/core/usb.c 2005-09-28 13:01:29.000000000 +0100 +@@ -1561,4 +1561,6 @@ + #endif + EXPORT_SYMBOL (usb_buffer_unmap_sg); + ++EXPORT_SYMBOL (usb_bus_type); ++ + MODULE_LICENSE("GPL"); diff -r 1c62a4149b11 -r 5952173acc28 xen/include/public/io/usbif.h --- /dev/null Mon Oct 24 07:04:38 2005 +++ b/xen/include/public/io/usbif.h Mon Oct 24 15:04:49 2005 @@ -0,0 +1,350 @@ +/*****************************************************************************/ +/* FE->BE transactions for the USB split driver interface. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Based on the previous usbif.h by Mark Williamson and blkif.h, original */ +/* copyright notice follows... */ +/*****************************************************************************/ + +/****************************************************************************** + * usbif.h + * + * Unified block-device I/O interface for Xen guest OSes. + * + * Copyright (c) 2003-2004, Keir Fraser + */ + +#ifndef __SHARED_USBIF_H__ +#define __SHARED_USBIF_H__ + +#include + +/* USBIF_MAX_PAGES_PER_REQUEST is the maximum number of pages a request is */ +/* allowed to require to construct the mapping in the back-end. */ + +#define USBIF_MAX_PAGES_PER_REQUEST 128 + +/* All transactions have the same header which specifies the type of the */ +/* transaction. */ + +typedef struct usbif_transaction_parameters_header_struct + usbif_transaction_parameters_header; + +struct usbif_transaction_parameters_header_struct +{ + u8 transaction_type; + u8 reserved[ 7 ]; +}; + +/* There are three types of transaction: */ + +#define USBIF_TRANSACTION_TYPE_PROBE 0 +#define USBIF_TRANSACTION_TYPE_RESET 1 +#define USBIF_TRANSACTION_TYPE_IO 2 + +/* The probe transaction is used to test whether a USB device is connected */ +/* to a port. */ +/* Port numbers start at 1. */ + +typedef struct usbif_probe_transaction_parameters_struct + usbif_probe_transaction_parameters; + +struct usbif_probe_transaction_parameters_struct +{ + usbif_transaction_parameters_header header; + u32 port; + u8 reserved[ 4 ]; +}; + +typedef struct usbif_probe_transaction_status_struct + usbif_probe_transaction_status; + +struct usbif_probe_transaction_status_struct +{ + u8 result; + u8 reserved[ 7 ]; +}; + +#define USBIF_PROBE_RESULT_NO_DEVICE 0 +#define USBIF_PROBE_RESULT_DEVICE_PRESENT 1 + +/* The reset transaction is used to reset a port. On success, the speed the */ +/* port is operating at after the reset is returned. */ + +typedef struct usbif_reset_transaction_parameters_struct + usbif_reset_transaction_parameters; + +struct usbif_reset_transaction_parameters_struct +{ + usbif_transaction_parameters_header header; + u32 port; + u8 reserved[ 4 ]; +}; + +/* On success, the reset returns status... */ + +typedef struct usbif_reset_transaction_status_struct + usbif_reset_transaction_status; + +struct usbif_reset_transaction_status_struct +{ + u8 result; + u8 reserved[ 7 ]; +}; + +#define USBIF_RESET_RESULT_FULL_SPEED 0 +#define USBIF_RESET_RESULT_LOW_SPEED 1 +#define USBIF_RESET_RESULT_HIGH_SPEED 2 + +/* Aside from the usual transport errors, the reset transaction might fail */ +/* if there is no device. */ + +/* All IO transactions have a header which specifies the type of IO */ +/* transaction and contains parameters common to all types of IO transaction.*/ + +typedef struct usbif_io_transaction_parameters_header_struct + usbif_io_transaction_parameters_header; + +struct usbif_io_transaction_parameters_header_struct +{ + usbif_transaction_parameters_header header; + u8 io_transaction_type; + u8 device_number; + u8 endpoint; + u8 direction; + u32 unlink_id; + u32 flags; + u32 reserved; + xenidc_remote_buffer_reference rbr; +}; + +#define USBIF_IO_TRANSACTION_TYPE_CONTROL 0 +#define USBIF_IO_TRANSACTION_TYPE_BULK 1 +#define USBIF_IO_TRANSACTION_TYPE_INTERRUPT 2 +#define USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS 3 +/* Not a transaction type. For array bounds: */ +#define USBIF_IO_TRANSACTION_TYPE_LIMIT 4 + +#define USBIF_IO_TRANSACTION_DIRECTION_OUT 0 +#define USBIF_IO_TRANSACTION_DIRECTION_IN 1 + +#define USBIF_IO_FLAGS_SHORT_NOT_OK 0x00000001 +#define USBIF_IO_FLAGS_ZERO_PACKET 0x00000002 + +typedef struct usbif_control_io_transaction_parameters_struct + usbif_control_io_transaction_parameters; + +struct usbif_control_io_transaction_parameters_struct +{ + usbif_io_transaction_parameters_header header; + u8 setup[ 8 ]; +}; + +typedef struct usbif_bulk_io_transaction_parameters_struct + usbif_bulk_io_transaction_parameters; + +struct usbif_bulk_io_transaction_parameters_struct +{ + usbif_io_transaction_parameters_header header; +}; + +typedef struct usbif_interrupt_io_transaction_parameters_struct + usbif_interrupt_io_transaction_parameters; + +struct usbif_interrupt_io_transaction_parameters_struct +{ + usbif_io_transaction_parameters_header header; + u32 interval; +}; + +typedef struct usbif_isochronous_io_transaction_parameters_struct + usbif_isochronous_io_transaction_parameters; + +struct usbif_isochronous_io_transaction_parameters_struct +{ + usbif_io_transaction_parameters_header header; + u32 interval; + xenidc_remote_buffer_reference schedule_rbr; + u32 packet_count; +}; + +typedef struct usbif_isochronous_io_schedule_element_struct + usbif_isochronous_io_schedule_element; + +struct usbif_isochronous_io_schedule_element_struct +{ + xenidc_buffer_byte_count offset; /* IN offset into header's rbr */ + xenidc_buffer_byte_count length; /* IN = expected, OUT = actual */ + xenidc_error error; /* OUT for this packet. */ +}; + +typedef struct usbif_io_transaction_status_struct + usbif_io_transaction_status; + +struct usbif_io_transaction_status_struct +{ + xenidc_buffer_byte_count length; +}; + +/* USBIF specific transaction error codes: */ + +#define USBIF_XENIDC_ERROR_FAILURE \ + ( XENIDC_ERROR_PROTOCOL_SPECIFIC_FIRST + 0 ) +#define USBIF_XENIDC_ERROR_NO_DEVICE \ + ( XENIDC_ERROR_PROTOCOL_SPECIFIC_FIRST + 1 ) +#define USBIF_XENIDC_ERROR_UNLINKED \ + ( XENIDC_ERROR_PROTOCOL_SPECIFIC_FIRST + 2 ) + +static inline xenidc_error usbif_error_map_local_to( int error ) +{ + switch( error ) + { + /* FIXME: handle USB specific error codes. */ + default: + return xenidc_error_map_local_to( error ); + } +} + +static inline int usbif_error_map_to_local( xenidc_error error ) +{ + switch( error ) + { + /* FIXME: handle USB specific error codes. */ + default: + return xenidc_error_map_to_local( error ); + } +} + +/* Lookup table for sizes of io parameters structures. */ + +static const xenidc_buffer_byte_count usbif_io_parameters_byte_count + [ USBIF_IO_TRANSACTION_TYPE_LIMIT ] = +{ + [ USBIF_IO_TRANSACTION_TYPE_CONTROL ] = + sizeof( usbif_control_io_transaction_parameters ), + [ USBIF_IO_TRANSACTION_TYPE_BULK ] = + sizeof( usbif_bulk_io_transaction_parameters ), + [ USBIF_IO_TRANSACTION_TYPE_INTERRUPT ] = + sizeof( usbif_interrupt_io_transaction_parameters ), + [ USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS ] = + sizeof( usbif_isochronous_io_transaction_parameters ) +}; + +typedef union +{ + usbif_io_transaction_parameters_header header; + usbif_control_io_transaction_parameters control; + usbif_bulk_io_transaction_parameters bulk; + usbif_interrupt_io_transaction_parameters interrupt; + usbif_isochronous_io_transaction_parameters isochronous; +} +usbif_io_transaction_parameters; + +typedef union usbif_max_transaction_union usbif_max_transaction; + +union usbif_max_transaction_union +{ + struct + { + usbif_probe_transaction_parameters parameters; + usbif_probe_transaction_status status; + } probe; + struct + { + usbif_reset_transaction_parameters parameters; + usbif_reset_transaction_status status; + } reset; + struct + { + usbif_control_io_transaction_parameters parameters; + usbif_io_transaction_status status; + } control_io; + struct + { + usbif_bulk_io_transaction_parameters parameters; + usbif_io_transaction_status status; + } bulk_io; + struct + { + usbif_interrupt_io_transaction_parameters parameters; + usbif_io_transaction_status status; + } interrupt_io; + struct + { + usbif_isochronous_io_transaction_parameters parameters; + usbif_io_transaction_status status; + } isochronous_io; +}; + +/* All messages have the same header which specifies the type of the */ +/* message. */ + +typedef struct usbif_message_header_struct usbif_message_header; + +struct usbif_message_header_struct +{ + u8 message_type; + u8 reserved[ 7 ]; +}; + +/* There is only one type of message: */ + +#define USBIF_MESSAGE_TYPE_UNLINK 0 + +/* The unlink message is sent to unlink an IO operation. The backend will */ +/* ensure it completes or is failed out as quickly as possible. */ +/* This is a send and forget message: the client should wait for the */ +/* completion of the IO transaction as normal. */ + +typedef struct usbif_unlink_message_body_struct usbif_unlink_message_body; + +struct usbif_unlink_message_body_struct +{ + usbif_message_header header; + u32 unlink_id; + u32 reserved; +}; + +#define USBIF_BE_INITIATOR_MESSAGE_MAXIMUM_BYTE_COUNT 0 +#define USBIF_BE_INITIATOR_TRANSACTION_QUOTA 0 +#define USBIF_BE_INITIATOR_TRANSACTION_MAXIMUM_BYTE_COUNT 0 + +#define USBIF_BE_TARGET_MESSAGE_MAXIMUM_BYTE_COUNT \ + ( sizeof( usbif_unlink_message_body ) ) +#define USBIF_BE_TARGET_TRANSACTION_QUOTA 32 +#define USBIF_BE_TARGET_TRANSACTION_MAXIMUM_BYTE_COUNT \ +( sizeof( usbif_max_transaction ) ) + +#define USBIF_FE_INITIATOR_MESSAGE_MAXIMUM_BYTE_COUNT \ +USBIF_BE_TARGET_MESSAGE_MAXIMUM_BYTE_COUNT +#define USBIF_FE_INITIATOR_TRANSACTION_QUOTA \ +USBIF_BE_TARGET_TRANSACTION_QUOTA +#define USBIF_FE_INITIATOR_TRANSACTION_MAXIMUM_BYTE_COUNT \ +USBIF_BE_TARGET_TRANSACTION_MAXIMUM_BYTE_COUNT + +#define USBIF_FE_TARGET_MESSAGE_MAXIMUM_BYTE_COUNT \ +USBIF_BE_INITIATOR_MESSAGE_MAXIMUM_BYTE_COUNT +#define USBIF_FE_TARGET_TRANSACTION_QUOTA \ +USBIF_BE_INITIATOR_TRANSACTION_QUOTA +#define USBIF_FE_TARGET_TRANSACTION_MAXIMUM_BYTE_COUNT \ +USBIF_BE_INITIATOR_TRANSACTION_MAXIMUM_BYTE_COUNT + +#endif