diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/arch/xen/Kconfig --- a/linux-2.6-xen-sparse/arch/xen/Kconfig Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/arch/xen/Kconfig Mon Nov 21 11:10:19 2005 @@ -77,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 n + 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" diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/Makefile Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Mon Nov 21 11:10:19 2005 @@ -12,6 +12,7 @@ obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/ obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/ obj-$(CONFIG_XEN_TPMDEV_BACKEND) += tpmback/ +obj-$(CONFIG_XEN_USBDEV_BACKEND) += usbback/ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/Makefile --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/Makefile Mon Nov 21 11:10:19 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 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h Mon Nov 21 11:10:19 2005 @@ -0,0 +1,38 @@ +/*****************************************************************************/ +/* 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 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c Mon Nov 21 11:10:19 2005 @@ -0,0 +1,450 @@ +/*****************************************************************************/ +/* 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 +#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; + char *path; + xenidc_address address; + 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; +} + +xenidc_address usbback_device_query_address(struct usbback_device * device) +{ + trace(); + + return device->address; +} + +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_endpoint_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. */ + + /* We don't issue any messages or transactions from the BE to the FE but */ + /* we hang onto the callback until we are internally quiesced. This */ + /* stops the endpoint from reconnecting whilst we are quiescing which */ + /* helps to keep the state machines a little bit simpler. */ + + usbback_driver_endpoint_disconnect + (usbback_device_endpoint_to(endpoint), callback); +} + +static void usbback_device_endpoint_message + (xenidc_endpoint * endpoint, xenidc_endpoint_message * message) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + usbback_driver_message_handler + (usbback_device_endpoint_to(endpoint), message); +} + +static void usbback_device_endpoint_transaction + (xenidc_endpoint * endpoint, xenidc_endpoint_transaction * transaction) { + /* trace(); */ + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + usbback_driver_transaction_handler + (usbback_device_endpoint_to(endpoint), transaction); +} + +static int __usbback_device_resume_or_suspend + (struct usbback_device *device, int suspend); + +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) { + trace0("Failed to probe driver."); + + goto EXIT_NO_DRIVER; + } + + { + struct xenbus_transaction *transaction = + xenbus_transaction_start(); + + if (IS_ERR(transaction)) { + trace0("Error starting transaction."); + + return_value = PTR_ERR(transaction); + + goto EXIT_NO_PATH; + } + + return_value = xenbus_gather + (transaction, + dev->nodename, "path", NULL, &device->path, NULL); + + (void)xenbus_transaction_end(transaction, 1); + } + + if (XENBUS_EXIST_ERR(return_value)) { + trace0("Frontend doesn't seem to exist."); + + goto EXIT_NO_PATH; + } + + if (return_value < 0) { + trace0("Failed to gather configuration parameters."); + + xenbus_dev_error + (dev, + return_value, "reading %s/path", dev->nodename); + + goto EXIT_NO_PATH; + } + + trace1("Gathered configuration: path:%s", device->path); + + return_value = xenidc_endpoint_init + (&device->endpoint, + usbback_device_endpoint_connect, + usbback_device_endpoint_message, + usbback_device_endpoint_transaction, + usbback_device_endpoint_disconnect, + USBIF_BE_INITIATOR_QUOTA, + USBIF_BE_INITIATOR_MAXIMUM_BYTE_COUNT, + USBIF_BE_TARGET_QUOTA, USBIF_BE_TARGET_MAXIMUM_BYTE_COUNT); + + if (return_value != 0) { + trace0 + ("Failed to initialise endpoint for frontend connection."); + + goto EXIT_NO_ENDPOINT; + } + + usbback_driver_claim_port(device, 1, device->path); + + return_value = __usbback_device_resume_or_suspend(device, 0); + + if (return_value != 0) { + goto EXIT_NO_RESUME; + } + + return 0; + + EXIT: + + (void)__usbback_device_resume_or_suspend(device, 1); + + EXIT_NO_RESUME: + + usbback_driver_release_port(device, 1); + + xenidc_endpoint_exit(&device->endpoint); + + EXIT_NO_ENDPOINT: + + kfree(device->path); + + EXIT_NO_PATH: + + 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 int __usbback_device_resume_or_suspend + (struct usbback_device *device, int suspend) { + trace(); + + { + int return_value = 0; + + if (suspend) { + goto SUSPEND; + } + + xenidc_address_init + (&device->address, + device->dev->nodename, + device->dev->otherend, device->dev->otherend_id); + + xenidc_endpoint_create(&device->endpoint, device->address); + + return 0; + + SUSPEND: + + xenidc_endpoint_destroy(&device->endpoint); + + return return_value; + } +} + +static int usbback_device_resume(struct xenbus_device *dev) +{ + trace(); + + { + struct usbback_device *device = dev->data; + + (void)__usbback_device_resume_or_suspend(device, 1); + + return __usbback_device_resume_or_suspend(device, 0); + } +} + +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, + .resume = usbback_device_resume, +}; + +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 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h Mon Nov 21 11:10:19 2005 @@ -0,0 +1,42 @@ +/*****************************************************************************/ +/* 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 + +#include + +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); + +extern xenidc_address usbback_device_query_address + (struct usbback_device *device); + +#endif diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c Mon Nov 21 11:10:19 2005 @@ -0,0 +1,240 @@ +/*****************************************************************************/ +/* 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_endpoint_connect(struct usbback_device *device) +{ + trace(); + + { + struct usbback_driver_backend *backend = + usbback_device_get_drvdata(device); + + usbback_driver_backend_endpoint_connect(backend); + } +} + +void usbback_driver_message_handler + (struct usbback_device *device, xenidc_endpoint_message * message) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + struct usbback_driver_backend *backend = + usbback_device_get_drvdata(device); + + usbback_driver_backend_message_handler(backend, message); + } +} + +void usbback_driver_transaction_handler + (struct usbback_device *device, xenidc_endpoint_transaction * transaction) { + /* trace(); */ + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + struct usbback_driver_backend *backend = + usbback_device_get_drvdata(device); + + usbback_driver_backend_transaction_handler(backend, + transaction); + } +} + +void usbback_driver_endpoint_disconnect + (struct usbback_device *device, xenidc_callback * callback) { + trace(); + + { + struct usbback_driver_backend *backend = + usbback_device_get_drvdata(device); + + usbback_driver_backend_endpoint_disconnect(backend, callback); + } +} + +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 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h Mon Nov 21 11:10:19 2005 @@ -0,0 +1,53 @@ +/*****************************************************************************/ +/* 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_endpoint_connect(struct usbback_device *device); + +extern void usbback_driver_message_handler + (struct usbback_device *device, xenidc_endpoint_message * message); + +extern void usbback_driver_transaction_handler + (struct usbback_device *device, xenidc_endpoint_transaction * transaction); + +extern void usbback_driver_endpoint_disconnect + (struct usbback_device *device, xenidc_callback * callback); + +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 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c Mon Nov 21 11:10:19 2005 @@ -0,0 +1,554 @@ +/*****************************************************************************/ +/* 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 + +typedef struct usbback_driver_backend_callback_struct + usbback_driver_backend_callback; + +struct usbback_driver_backend_callback_struct { + xenidc_callback callback; + struct usbback_driver_backend *backend; +}; + +struct usbback_driver_backend { + struct usbback_device *device; + spinlock_t lock; + xenidc_callback *endpoint_disconnect_callback; + int port_disconnect_callbacks_out; + usbback_driver_backend_callback port_disconnect_callback + [USBBACK_DRIVER_PORT_COUNT]; + struct usbback_driver_port port[USBBACK_DRIVER_PORT_COUNT]; +}; + +static void usbback_driver_backend_endpoint_disconnect_1 + (xenidc_callback * callback); + +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; + + spin_lock_init(&backend->lock); + + { + int i; + + for (i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++) { + xenidc_callback_init + (&backend->port_disconnect_callback[i]. + callback, + usbback_driver_backend_endpoint_disconnect_1); + + backend->port_disconnect_callback[i].backend = + backend; + } + } + + { + 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_endpoint_connect + (struct usbback_driver_backend *backend) { + trace(); + + { + int i; + + for (i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++) { + usbback_driver_port_endpoint_connect(&backend->port[i]); + } + } +} + +static void usbback_driver_backend_handle_probe + (struct usbback_driver_backend *backend, + xenidc_endpoint_transaction * transaction); + +static void usbback_driver_backend_handle_reset + (struct usbback_driver_backend *backend, + xenidc_endpoint_transaction * transaction); + +static void usbback_driver_backend_handle_io + (struct usbback_driver_backend *backend, + xenidc_endpoint_transaction * transaction); + +void usbback_driver_backend_transaction_handler + (struct usbback_driver_backend *backend, + xenidc_endpoint_transaction * transaction) { + /* trace(); */ + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + usbif_transaction_parameters_header header; + + if (xenidc_local_buffer_reference_copy_out + (xenidc_endpoint_transaction_to_parameters_lbr(transaction), + &header, sizeof(header) + ) + == sizeof(header) + ) { + switch (header.transaction_type) { + case USBIF_TRANSACTION_TYPE_PROBE: + usbback_driver_backend_handle_probe(backend, + transaction); + break; + case USBIF_TRANSACTION_TYPE_RESET: + usbback_driver_backend_handle_reset(backend, + transaction); + break; + case USBIF_TRANSACTION_TYPE_IO: + usbback_driver_backend_handle_io(backend, transaction); + break; + default: + xenidc_endpoint_transaction_complete + (transaction, XENIDC_ERROR_INVALID_PARAMETER); + break; + } + } else { + /* Parameters were underlength. */ + + xenidc_endpoint_transaction_complete + (transaction, XENIDC_ERROR_INVALID_PROTOCOL); + } +} + +static void usbback_driver_backend_handle_probe + (struct usbback_driver_backend *backend, + xenidc_endpoint_transaction * transaction) { + /* trace(); */ + + usbif_probe_transaction_parameters parameters; + + xenidc_error error; + + if (xenidc_local_buffer_reference_copy_out + (xenidc_endpoint_transaction_to_parameters_lbr(transaction), + ¶meters, sizeof(parameters) + ) + != sizeof(parameters) + ) { + error = XENIDC_ERROR_INVALID_PROTOCOL; + + goto COMPLETE; + } + + if ((parameters.port <= 0) + || (parameters.port > USBBACK_DRIVER_PORT_COUNT) + ) { + error = XENIDC_ERROR_INVALID_PARAMETER; + + goto COMPLETE; + } + + { + usbif_probe_transaction_status status; + + memset(&status, 0, sizeof(status)); + + status.result = usbback_driver_port_usbdev_is_connected + (&backend->port[parameters.port - 1]) ? + USBIF_PROBE_RESULT_DEVICE_PRESENT : + USBIF_PROBE_RESULT_NO_DEVICE; + + if (xenidc_local_buffer_reference_copy_in + (xenidc_endpoint_transaction_to_status_lbr(transaction), + &status, sizeof(status) + ) + != sizeof(status) + ) { + error = XENIDC_ERROR_INVALID_PROTOCOL; + + goto COMPLETE; + } + } + + error = XENIDC_ERROR_SUCCESS; + + COMPLETE: + + xenidc_endpoint_transaction_complete(transaction, error); +} + +static void usbback_driver_backend_handle_reset + (struct usbback_driver_backend *backend, + xenidc_endpoint_transaction * transaction) { + trace(); + + { + usbif_reset_transaction_parameters parameters; + + xenidc_error error; + + if (xenidc_local_buffer_reference_copy_out + (xenidc_endpoint_transaction_to_parameters_lbr(transaction), + ¶meters, sizeof(parameters) + ) + != sizeof(parameters) + ) { + error = XENIDC_ERROR_INVALID_PROTOCOL; + + goto COMPLETE; + } + + if ((parameters.port <= 0) + || (parameters.port > USBBACK_DRIVER_PORT_COUNT) + ) { + error = XENIDC_ERROR_INVALID_PARAMETER; + + goto COMPLETE; + } + + { + int result = usbback_driver_port_reset + (&backend->port[parameters.port - 1]); + + if (result < 0) { + error = USBIF_XENIDC_ERROR_NO_DEVICE; + + goto COMPLETE; + } + + { + usbif_reset_transaction_status status; + + memset(&status, 0, sizeof(status)); + + status.result = result; + + if (xenidc_local_buffer_reference_copy_in + (xenidc_endpoint_transaction_to_status_lbr + (transaction), &status, sizeof(status) + ) + != sizeof(status) + ) { + error = XENIDC_ERROR_INVALID_PROTOCOL; + + goto COMPLETE; + } + } + } + + error = XENIDC_ERROR_SUCCESS; + + COMPLETE: + + xenidc_endpoint_transaction_complete(transaction, error); + } +} + +static struct usbback_driver_port + *usbback_driver_backend_find_port_by_guest_address(struct + usbback_driver_backend + *backend, + unsigned long + guest_address) { + trace(); + + { + int i; + + for (i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++) { + struct usbback_driver_port *port = &backend->port[i]; + + if (usbback_driver_port_match_guest_address + (port, guest_address) + ) { + return port; + } + } + } + + return NULL; +} + +static void usbback_driver_backend_handle_io + (struct usbback_driver_backend *backend, + xenidc_endpoint_transaction * transaction) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + usbif_io_transaction_parameters_header header; + + xenidc_error error; + + if (xenidc_local_buffer_reference_copy_out + (xenidc_endpoint_transaction_to_parameters_lbr(transaction), + &header, sizeof(header) + ) + != sizeof(header) + ) { + error = XENIDC_ERROR_INVALID_PROTOCOL; + + goto COMPLETE; + } + + { + struct usbback_driver_port *port = + usbback_driver_backend_find_port_by_guest_address + (backend, header.device_number); + + if (port == NULL) { + error = USBIF_XENIDC_ERROR_NO_DEVICE; + + goto COMPLETE; + } + + usbback_driver_port_handle_io(port, transaction); + } + + return; + + COMPLETE: + + xenidc_endpoint_transaction_complete(transaction, error); + } +} + +static void usbback_driver_backend_handle_unlink + (struct usbback_driver_backend *backend, xenidc_endpoint_message * message); + +void usbback_driver_backend_message_handler + (struct usbback_driver_backend *backend, + xenidc_endpoint_message * message) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + usbif_message_header header; + + if (xenidc_local_buffer_reference_copy_out + (xenidc_endpoint_message_to_message_lbr(message), + &header, sizeof(header) + ) + == sizeof(header) + ) { + switch (header.message_type) { + case USBIF_MESSAGE_TYPE_UNLINK: + usbback_driver_backend_handle_unlink(backend, + message); + break; + } + } + + xenidc_callback_success + (xenidc_endpoint_message_to_callback(message)); + } +} + +static void usbback_driver_backend_handle_unlink + (struct usbback_driver_backend *backend, + xenidc_endpoint_message * message) { + trace(); + + { + usbif_unlink_message_body unlink; + + if (xenidc_local_buffer_reference_copy_out + (xenidc_endpoint_message_to_message_lbr(message), + &unlink, sizeof(unlink) + ) + == sizeof(unlink) + ) { + int i; + + for (i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++) { + struct usbback_driver_port *port = + &backend->port[i]; + + if (usbback_driver_port_try_unlink + (port, unlink.unlink_id) + ) { + break; + } + } + } + } +} + +void usbback_driver_backend_endpoint_disconnect + (struct usbback_driver_backend *backend, xenidc_callback * callback) { + trace(); + + backend->endpoint_disconnect_callback = callback; + + backend->port_disconnect_callbacks_out = USBBACK_DRIVER_PORT_COUNT; + + { + int i; + + for (i = 0; i < USBBACK_DRIVER_PORT_COUNT; i++) { + usbback_driver_port_endpoint_disconnect + (&backend->port[i], + &backend->port_disconnect_callback[i].callback); + } + } +} + +static void usbback_driver_backend_endpoint_disconnect_1 + (xenidc_callback * callback) { + trace(); + + { + struct usbback_driver_backend *backend = container_of + (callback, usbback_driver_backend_callback, + callback)->backend; + + spin_lock(&backend->lock); + + if (--backend->port_disconnect_callbacks_out == 0) { + xenidc_callback_success(backend-> + endpoint_disconnect_callback); + } + + spin_unlock(&backend->lock); + } +} + +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); +} + +struct usbback_device *usbback_driver_backend_query_device + (struct usbback_driver_backend *backend) { + trace(); + + return backend->device; +} diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h Mon Nov 21 11:10:19 2005 @@ -0,0 +1,61 @@ +/*****************************************************************************/ +/* 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_endpoint_connect + (struct usbback_driver_backend *backend); + +extern void usbback_driver_backend_transaction_handler + (struct usbback_driver_backend *backend, + xenidc_endpoint_transaction * transaction); + +extern void usbback_driver_backend_message_handler + (struct usbback_driver_backend *backend, xenidc_endpoint_message * message); + +extern void usbback_driver_backend_endpoint_disconnect + (struct usbback_driver_backend *backend, xenidc_callback * callback); + +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); + +extern struct usbback_device *usbback_driver_backend_query_device + (struct usbback_driver_backend *backend); + +#endif diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c Mon Nov 21 11:10:19 2005 @@ -0,0 +1,1369 @@ +/*****************************************************************************/ +/* 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_perform_release_1(void *data); + +static int usbback_driver_port_init_or_exit + (struct usbback_driver_port *port, int exit) { + trace(); + + { + int return_value = 0; + + if (exit) { + goto EXIT; + } + + 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->free_resource_list); + + { + int i; + + for (i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++) { + struct usbback_driver_port_resource *resource = + &port->resources[i]; + + return_value = + usbback_driver_port_resource_init(resource, + port); + + if (return_value != 0) { + goto EXIT_NO_RESOURCE; + } + + list_add(&resource->link, + &port->free_resource_list); + } + } + + xenidc_work_init + (&port->perform_release_1_work, + usbback_driver_port_perform_release_1, port); + + return 0; + + EXIT: + + EXIT_NO_RESOURCE: + + while (!list_empty(&port->free_resource_list)) { + struct usbback_driver_port_resource *resource = + list_entry(port->free_resource_list.next, + struct usbback_driver_port_resource, + link); + + list_del_init(&resource->link); + + usbback_driver_port_resource_exit(resource); + } + + return return_value; + } +} + +int usbback_driver_port_init + (struct usbback_driver_port *port, struct usbback_driver_backend *backend) { + trace(); + + memset(port, 0, sizeof(*port)); + + port->backend = backend; + + return usbback_driver_port_init_or_exit(port, 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_endpoint_connect(struct usbback_driver_port *port) +{ + trace(); + + { + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + usbback_driver_port_handle_stimulus + (port, usbback_driver_port_stimulus_cn); + + spin_unlock_irqrestore(&port->lock, flags); + } +} + +void usbback_driver_port_handle_io + (struct usbback_driver_port *port, + xenidc_endpoint_transaction * transaction) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + list_add_tail + (xenidc_endpoint_transaction_to_link(transaction), + &port->transaction_list); + + usbback_driver_port_handle_stimulus + (port, usbback_driver_port_stimulus_rq); + + spin_unlock_irqrestore(&port->lock, flags); + } +} + +void usbback_driver_port_endpoint_disconnect + (struct usbback_driver_port *port, xenidc_callback * callback) { + trace(); + + { + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + port->endpoint_disconnect_callback = callback; + + usbback_driver_port_handle_stimulus + (port, usbback_driver_port_stimulus_dn); + + spin_unlock_irqrestore(&port->lock, flags); + } +} + +int usbback_driver_port_try_unlink + (struct usbback_driver_port *port, int unlink_id) { + trace(); + + { + int return_value = 0; + + xenidc_endpoint_transaction *transaction = NULL; + + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + { + xenidc_endpoint_transaction *temp; + + list_for_each_entry + (temp, + &port->transaction_list, + XENIDC_ENDPOINT_TRANSACTION_LINK) { + usbif_io_transaction_parameters_header header; + + if (xenidc_local_buffer_reference_copy_out + (xenidc_endpoint_transaction_to_parameters_lbr + (transaction), &header, sizeof(header) + ) + == sizeof(header) + ) { + if (header.unlink_id == unlink_id) { + transaction = temp; + + list_del_init + (xenidc_endpoint_transaction_to_link + (transaction) + ); + + break; + } + } + } + } + + if (transaction == NULL) { + int i; + + for (i = 0; i < USBBACK_DRIVER_PORT_RESOURCE_COUNT; i++) { + struct usbback_driver_port_resource *resource = + &port->resources[i]; + + if (usbback_driver_port_resource_try_unlink + (resource, unlink_id) + ) { + return_value = 1; + + break; + } + } + } + + spin_unlock_irqrestore(&port->lock, flags); + + if (transaction) { + xenidc_endpoint_transaction_complete + (transaction, USBIF_XENIDC_ERROR_UNLINKED); + + return_value = 1; + } + + return return_value; + } +} + +void usbback_driver_port_shutdown(struct usbback_driver_port *port) +{ + trace(); + + down_write(&usbback_driver_port_list_sem); + + list_del_init(&port->link); + + up_write(&usbback_driver_port_list_sem); + + port->shutdown = 0; + + spin_lock_irq(&port->lock); + + usbback_driver_port_handle_stimulus + (port, usbback_driver_port_stimulus_sd); + + spin_unlock_irq(&port->lock); + + xenidc_work_until(port->shutdown); + + flush_scheduled_work(); + + (void)usbback_driver_port_init_or_exit(port, 1); +} + +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_endpoint_disconnect + (struct usbback_driver_port *port); + +static void usbback_driver_port_complete_shutdown + (struct usbback_driver_port *port); + +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: + /* No claimed port */ + /* USB disconnected */ + /* Endpoint disconnected */ + /* I/Os idle */ + /* Not performing release */ + /* Release not outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_pc: + port->state = usbback_driver_port_state_i_pc; + break; + case usbback_driver_port_stimulus_cn: + port->state = usbback_driver_port_state_i_cn; + break; + case usbback_driver_port_stimulus_sd: + port->state = usbback_driver_port_state_i_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 port */ + /* USB disconnected */ + /* Endpoint disconnected */ + /* I/Os idle */ + /* Not performing release */ + /* Release not outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + 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_cn: + port->state = usbback_driver_port_state_i_pc_cn; + break; + case usbback_driver_port_stimulus_sd: + port->state = usbback_driver_port_state_i_sd; + usbback_driver_port_complete_shutdown(port); + break; + default: + usbback_driver_port_invalid_stimulus(port, stimulus); + break; + } + break; + case usbback_driver_port_state_i_cn: + /* No claimed port */ + /* USB disconnected */ + /* Endpoint connected */ + /* I/Os idle */ + /* Not performing release */ + /* Release not outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_pc: + port->state = usbback_driver_port_state_i_pc_cn; + break; + case usbback_driver_port_stimulus_dn: + port->state = usbback_driver_port_state_i; + usbback_driver_port_complete_endpoint_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_sd: + /* Removed from port list. */ + /* USB disconnected */ + /* Endpoint disconnected */ + /* I/Os idle */ + /* Not performing release */ + /* Release not outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + /* Shutdown */ + switch (stimulus) { + default: + usbback_driver_port_invalid_stimulus(port, stimulus); + break; + } + break; + case usbback_driver_port_state_i_pc_up: + /* Claimed port */ + /* USB probed */ + /* Endpoint disconnected */ + /* I/Os idle */ + /* Not performing release */ + /* Release not outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_pr: + port->state = usbback_driver_port_state_i_pc_up_pr; + usbback_driver_port_perform_release(port); + break; + case usbback_driver_port_stimulus_ud: + port->state = usbback_driver_port_state_i_pc; + usbback_driver_port_complete_usb_disconnect(port); + break; + case usbback_driver_port_stimulus_cn: + port->state = usbback_driver_port_state_i_pc_up_cn; + break; + case usbback_driver_port_stimulus_sd: + port->state = usbback_driver_port_state_i_pc_up_sd; + usbback_driver_port_perform_release(port); + break; + default: + usbback_driver_port_invalid_stimulus(port, stimulus); + break; + } + break; + case usbback_driver_port_state_i_pc_cn: + /* Claimed port */ + /* USB disconnected */ + /* Endpoint connected */ + /* I/Os idle */ + /* Not performing release */ + /* Release not outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_pr: + port->state = usbback_driver_port_state_i_cn; + usbback_driver_port_complete_release(port); + break; + case usbback_driver_port_stimulus_up: + port->state = usbback_driver_port_state_i_pc_up_cn; + break; + case usbback_driver_port_stimulus_dn: + port->state = usbback_driver_port_state_i_pc; + usbback_driver_port_complete_endpoint_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: + /* Releasing port. */ + /* USB probed */ + /* Endpoint disconnected */ + /* I/Os idle */ + /* Performing release */ + /* Release outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_ud: + port->state = usbback_driver_port_state_i_pc_up_pr_ud; + usbback_driver_port_complete_usb_disconnect(port); + break; + case usbback_driver_port_stimulus_cn: + port->state = usbback_driver_port_state_i_pc_up_pr_cn; + break; + default: + usbback_driver_port_invalid_stimulus(port, stimulus); + break; + } + break; + case usbback_driver_port_state_i_pc_up_cn: + /* Claimed port */ + /* USB probed */ + /* Endpoint connected */ + /* Maybe I/Os in progress */ + /* Not performing release */ + /* Release not outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_pr: + port->state = usbback_driver_port_state_i_pc_up_cn_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_cn_ud; + usbback_driver_port_purge_io(port); + usbback_driver_port_test_io(port); + break; + case usbback_driver_port_stimulus_dn: + port->state = usbback_driver_port_state_i_pc_up_cn_dn; + 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; + default: + usbback_driver_port_invalid_stimulus(port, stimulus); + break; + } + break; + case usbback_driver_port_state_i_pc_up_sd: + /* Releasing port */ + /* USB probed */ + /* Endpoint disconnected */ + /* I/Os idle */ + /* Performing release */ + /* Release not outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_ud: + port->state = usbback_driver_port_state_i_pc_up_sd_ud; + usbback_driver_port_complete_usb_disconnect(port); + break; + default: + usbback_driver_port_invalid_stimulus(port, stimulus); + break; + } + break; + case usbback_driver_port_state_i_pc_up_pr_ud: + /* Releasing port. */ + /* USB disconnected */ + /* Endpoint disconnected */ + /* I/Os idle */ + /* Performing release */ + /* Release outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_cn: + port->state = + usbback_driver_port_state_i_pc_up_pr_ud_cn; + 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_pr_cn: + /* Releasing port. */ + /* USB probed */ + /* Endpoint connected */ + /* I/Os idle */ + /* Performing release */ + /* Release outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_ud: + port->state = + usbback_driver_port_state_i_pc_up_pr_ud_cn; + usbback_driver_port_complete_usb_disconnect(port); + break; + case usbback_driver_port_stimulus_dn: + port->state = usbback_driver_port_state_i_pc_up_pr; + usbback_driver_port_complete_endpoint_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_cn_pr: + /* Claimed port */ + /* USB probed */ + /* Endpoint connected */ + /* I/Os in progress/testing I/Os */ + /* Not performing release */ + /* Release outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_ud: + port->state = + usbback_driver_port_state_i_pc_up_cn_pr_ud; + break; + case usbback_driver_port_stimulus_dn: + port->state = + usbback_driver_port_state_i_pc_up_cn_pr_dn; + 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_cn; + 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_cn_ud: + /* Claimed port */ + /* USB disconnecting */ + /* Endpoint connected */ + /* I/Os in progress/testing I/Os */ + /* Not performing release */ + /* Release not outstanding */ + /* USB disconnect outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_pr: + port->state = + usbback_driver_port_state_i_pc_up_cn_pr_ud; + break; + case usbback_driver_port_stimulus_dn: + port->state = + usbback_driver_port_state_i_pc_up_cn_ud_dn; + 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_cn; + 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_cn_dn: + /* Claimed port */ + /* USB probed */ + /* Endpoint disconnecting */ + /* I/Os in progress/testing I/Os */ + /* Not performing release */ + /* Release not outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_pr: + port->state = + usbback_driver_port_state_i_pc_up_cn_pr_dn; + break; + case usbback_driver_port_stimulus_ud: + port->state = + usbback_driver_port_state_i_pc_up_cn_ud_dn; + 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; + usbback_driver_port_complete_endpoint_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_ud: + /* Releasing port */ + /* USB disconnected */ + /* Endpoint disconnected */ + /* I/Os idle */ + /* Performing release */ + /* Release not outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_rp: + port->state = usbback_driver_port_state_i_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_up_pr_ud_cn: + /* Releasing port. */ + /* USB disconnected */ + /* Endpoint connected */ + /* I/Os idle */ + /* Performing release */ + /* Release outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_dn: + port->state = usbback_driver_port_state_i_pc_up_pr_ud; + usbback_driver_port_complete_endpoint_disconnect(port); + break; + 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_cn; + 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_cn_pr_ud: + /* Claimed port */ + /* USB disconnecting */ + /* Endpoint connected */ + /* I/Os in progress/testing I/Os */ + /* Not performing release */ + /* Release outstanding */ + /* USB disconnect outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_dn: + port->state = + usbback_driver_port_state_i_pc_up_cn_pr_ud_dn; + 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_cn; + usbback_driver_port_complete_usb_disconnect(port); + usbback_driver_port_complete_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_cn_pr_dn: + /* Claimed port */ + /* USB probed */ + /* Endpoint disconnecting */ + /* I/Os in progress/testing I/Os */ + /* Not performing release */ + /* Release outstanding */ + /* USB disconnect not outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_ud: + port->state = + usbback_driver_port_state_i_pc_up_cn_pr_ud_dn; + 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; + usbback_driver_port_perform_release(port); + usbback_driver_port_complete_endpoint_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_cn_ud_dn: + /* Claimed port */ + /* USB disconnecting */ + /* Endpoint disconnecting */ + /* I/Os in progress/testing I/Os */ + /* Not performing release */ + /* Release not outstanding */ + /* USB disconnect outstanding */ + /* Endpoint disconnect not outstanding */ + /* Shutdown not outstanding */ + switch (stimulus) { + case usbback_driver_port_stimulus_pr: + port->state = + usbback_driver_port_state_i_pc_up_cn_pr_ud_dn; + 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; + usbback_driver_port_complete_usb_disconnect(port); + usbback_driver_port_complete_endpoint_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_cn_pr_ud_dn: + /* Claimed port */ + /* USB disconnecting */ + /* Endpoint disconnecting */ + /* I/Os in progress/testing I/Os */ + /* Not performing release */ + /* Release outstanding */ + /* USB disconnect outstanding */ + /* Endpoint disconnect outstanding */ + /* Shutdown not outstanding */ + 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; + usbback_driver_port_complete_usb_disconnect(port); + usbback_driver_port_complete_endpoint_disconnect(port); + usbback_driver_port_complete_release(port); + break; + case usbback_driver_port_stimulus_rr: + break; + default: + usbback_driver_port_invalid_stimulus(port, stimulus); + break; + } + break; + default: + usbback_driver_port_invalid_stimulus(port, stimulus); + break; + } +} + +static void usbback_driver_port_invalid_stimulus + (struct usbback_driver_port *port, usbback_driver_port_stimulus stimulus) { + trace(); + + printk + (KERN_ERR "usbback: port %p in state %d" + "received invalid stimulus %d", port, port->state, stimulus); +} + +static void usbback_driver_port_purge_io(struct usbback_driver_port *port) +{ + trace(); + + while (!list_empty(&port->transaction_list)) { + xenidc_endpoint_transaction *transaction = list_entry + (port->transaction_list.next, + xenidc_endpoint_transaction, + XENIDC_ENDPOINT_TRANSACTION_LINK); + + list_del_init(xenidc_endpoint_transaction_to_link(transaction)); + + xenidc_endpoint_transaction_complete + (transaction, USBIF_XENIDC_ERROR_UNLINKED); + } + + { + 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); + } + } +} + +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(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + while ((!list_empty(&port->transaction_list)) + && (!list_empty(&port->free_resource_list)) + ) { + xenidc_endpoint_transaction *transaction = list_entry + (port->transaction_list.next, + xenidc_endpoint_transaction, + XENIDC_ENDPOINT_TRANSACTION_LINK); + + struct usbback_driver_port_resource *resource = list_entry + (port->free_resource_list.next, + struct usbback_driver_port_resource, + link); + + list_del_init(xenidc_endpoint_transaction_to_link(transaction)); + + list_del_init(&resource->link); + + port->current_transactions++; + + usbback_driver_port_resource_start_io(resource, transaction); + } +} + +void usbback_driver_port_resource_completed_io + (struct usbback_driver_port *port, + struct usbback_driver_port_resource *resource) { + trace(); + + { + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + list_add(&resource->link, &port->free_resource_list); + + port->current_transactions--; + + usbback_driver_port_handle_stimulus + (port, usbback_driver_port_stimulus_rq); + + spin_unlock_irqrestore(&port->lock, flags); + } +} + +static void usbback_driver_port_perform_release + (struct usbback_driver_port *port) { + trace(); + + usb_get_dev(port->usbdev); + + { + int scheduled = + xenidc_work_schedule(&port->perform_release_1_work); + + ASSERT(scheduled); + } +} + +static void usbback_driver_port_perform_release_1(void *data) +{ + trace(); + + { + struct usbback_driver_port *port = + (struct usbback_driver_port *)data; + + usb_lock_device(port->usbdev); + + down_write(&usb_bus_type.subsys.rwsem); + + if (port->usbdev_is_connected) { + usb_driver_release_interface + (&usbback_driver_usb_driver, + usb_ifnum_to_if(port->usbdev, 0) + ); + } + + up_write(&usb_bus_type.subsys.rwsem); + + usb_unlock_device(port->usbdev); + + usb_put_dev(port->usbdev); + + spin_lock_irq(&port->lock); + + usbback_driver_port_handle_stimulus + (port, usbback_driver_port_stimulus_rp); + + spin_unlock_irq(&port->lock); + } +} + +static void usbback_driver_port_complete_release + (struct usbback_driver_port *port) { + trace(); + + port->release = 1; + + xenidc_work_wake_up(); +} + +static void usbback_driver_port_complete_usb_disconnect + (struct usbback_driver_port *port) { + trace(); + + port->usb_disconnect = 1; + + xenidc_work_wake_up(); +} + +static void usbback_driver_port_complete_endpoint_disconnect + (struct usbback_driver_port *port) { + trace(); + + xenidc_callback_success(port->endpoint_disconnect_callback); +} + +static void usbback_driver_port_complete_shutdown + (struct usbback_driver_port *port) { + trace(); + + port->shutdown = 1; + + xenidc_work_wake_up(); +} + +struct usbback_driver_backend *usbback_driver_port_query_backend + (struct usbback_driver_port *port) { + trace(); + + return port->backend; +} diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h Mon Nov 21 11:10:19 2005 @@ -0,0 +1,144 @@ +/*****************************************************************************/ +/* 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_endpoint_connect(struct usbback_driver_port *port); + +void usbback_driver_port_handle_io + (struct usbback_driver_port *port, + xenidc_endpoint_transaction * transaction); + +void usbback_driver_port_endpoint_disconnect + (struct usbback_driver_port *port, xenidc_callback * callback); + +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_cn, + usbback_driver_port_state_i_sd, + usbback_driver_port_state_i_pc_up, + usbback_driver_port_state_i_pc_cn, + usbback_driver_port_state_i_pc_up_pr, + usbback_driver_port_state_i_pc_up_cn, + 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_cn, + usbback_driver_port_state_i_pc_up_cn_pr, + usbback_driver_port_state_i_pc_up_cn_ud, + usbback_driver_port_state_i_pc_up_cn_dn, + usbback_driver_port_state_i_pc_up_sd_ud, + usbback_driver_port_state_i_pc_up_pr_ud_cn, + usbback_driver_port_state_i_pc_up_cn_pr_ud, + usbback_driver_port_state_i_pc_up_cn_pr_dn, + usbback_driver_port_state_i_pc_up_cn_ud_dn, + usbback_driver_port_state_i_pc_up_cn_pr_ud_dn +} 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 free_resource_list; + unsigned long current_transactions; + struct usbback_driver_port_resource resources + [USBBACK_DRIVER_PORT_RESOURCE_COUNT]; + xenidc_work perform_release_1_work; + xenidc_callback *endpoint_disconnect_callback; + 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); + +struct usbback_driver_backend *usbback_driver_port_query_backend + (struct usbback_driver_port *port); + +#endif diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c Mon Nov 21 11:10:19 2005 @@ -0,0 +1,1156 @@ +/*****************************************************************************/ +/* 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(); + + { + xenidc_buffer_resource_list sum = + xenidc_buffer_resource_list_null(); + + xenidc_buffer_resource_list bulk_list = + xenidc_grant_table_calculate_buffer_resource_list + (USBIF_MAX_BULK_BYTE_COUNT, USBIF_BULK_BYTE_ALIGNMENT); + + xenidc_buffer_resource_list schedule_list = + xenidc_grant_table_calculate_buffer_resource_list + (USBIF_MAX_SCHEDULE_BYTE_COUNT, + USBIF_SCHEDULE_BYTE_ALIGNMENT); + + xenidc_buffer_resource_list_plus_equals(&sum, &bulk_list); + xenidc_buffer_resource_list_plus_equals(&sum, &schedule_list); + + usbback_driver_port_resource_rbr_mapper_pool = + xenidc_allocate_rbr_mapper_pool(sum); + } + + 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); + +int 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); + + resource->urb = + usb_alloc_urb(USBIF_MAX_SCHEDULE_PACKET_COUNT, GFP_KERNEL); + + return (resource->urb != NULL) ? 0 : -ENOMEM; +} + +void usbback_driver_port_resource_exit + (struct usbback_driver_port_resource *resource) { + trace(); + + usb_free_urb(resource->urb); +} + +void usbback_driver_port_resource_start_io + (struct usbback_driver_port_resource *resource, + xenidc_endpoint_transaction * transaction) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + unsigned long flags; + + spin_lock_irqsave(&resource->lock, flags); + + resource->transaction_error = XENIDC_ERROR_SUCCESS; + resource->transaction_status_length = 0; + + resource->transaction = transaction; + + usbback_driver_port_resource_handle_stimulus + (resource, usbback_driver_port_resource_stimulus_st); + + spin_unlock_irqrestore(&resource->lock, flags); + } +} + +int usbback_driver_port_resource_try_unlink + (struct usbback_driver_port_resource *resource, int unlink_id) { + trace(); + + { + int return_value = 0; + + unsigned long flags; + + spin_lock_irqsave(&resource->lock, flags); + + if (resource->transaction != NULL) { + usbif_io_transaction_parameters_header header; + + if ((xenidc_local_buffer_reference_copy_out + (xenidc_endpoint_transaction_to_parameters_lbr + (resource->transaction), &header, sizeof(header) + ) + == sizeof(header) + ) + && (header.unlink_id == unlink_id) + ) { + usbback_driver_port_resource_handle_stimulus + (resource, + usbback_driver_port_resource_stimulus_tu); + + return_value = 1; + } + } + + spin_unlock_irqrestore(&resource->lock, flags); + + return return_value; + } +} + +void usbback_driver_port_resource_flush_transaction + (struct usbback_driver_port_resource *resource) { + trace(); + + { + unsigned long flags; + + spin_lock_irqsave(&resource->lock, flags); + + if (resource->transaction != NULL) { + usbback_driver_port_resource_handle_stimulus + (resource, + usbback_driver_port_resource_stimulus_tu); + } + + spin_unlock_irqrestore(&resource->lock, flags); + } +} + +static void usbback_driver_port_resource_invalid_stimulus + (struct usbback_driver_port_resource *resource, + usbback_driver_port_resource_stimulus stimulus); + +static void usbback_driver_port_resource_map_buffer + (struct usbback_driver_port_resource *resource); + +static void usbback_driver_port_resource_abort_map + (struct usbback_driver_port_resource *resource); + +static void usbback_driver_port_resource_submit_urb + (struct usbback_driver_port_resource *resource); + +static void usbback_driver_port_resource_unlink_urb + (struct usbback_driver_port_resource *resource); + +static void usbback_driver_port_resource_set_unlinked_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_unlinked_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(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + usbif_io_transaction_parameters_header header; + + if (xenidc_local_buffer_reference_copy_out + (xenidc_endpoint_transaction_to_parameters_lbr + (resource->transaction), &header, sizeof(header) + ) + != sizeof(header) + ) { + goto PROTOCOL_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, + (header.direction == USBIF_IO_TRANSACTION_DIRECTION_OUT) ? + XENIDC_MAP_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_READ : + XENIDC_MAP_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_WRITE); + + if (header.io_transaction_type + == USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS) { + usbif_isochronous_io_transaction_parameters parameters; + + if (xenidc_local_buffer_reference_copy_out + (xenidc_endpoint_transaction_to_parameters_lbr + (resource->transaction), + ¶meters, sizeof(parameters) + ) + != sizeof(parameters) + ) { + goto PROTOCOL_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_MAP_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_READ | + XENIDC_MAP_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_WRITE); + } + + xenidc_rbr_mapper_pool_reserve_and_map_rbrs + (usbback_driver_port_resource_rbr_mapper_pool, + &resource->reserve_and_map_rbr_request, + usbback_device_query_address + (usbback_driver_backend_query_device + (usbback_driver_port_query_backend(resource->port)) + ) + ); + } + + return; + + PROTOCOL_ERROR: + + resource->transaction_error = XENIDC_ERROR_INVALID_PROTOCOL; + + 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 + (&resource->reserve_and_map_rbr_request, + USBIF_XENIDC_ERROR_UNLINKED); +} + +static void usbback_driver_port_resource_map_callback + (xenidc_callback * callback) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + 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 { + trace0("failed to map FE buffer"); + + 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(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + xenidc_callback_serialiser_complete_callback + (&usbback_driver_port_resource_submit_urb_serialiser, + &resource->submit_urb_1_callback, XENIDC_ERROR_SUCCESS); +} + +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(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + struct usbback_driver_port_resource *resource = container_of + (callback, + struct usbback_driver_port_resource, + submit_urb_1_callback); + + usbif_io_transaction_parameters io_parameters; + + { + xenidc_buffer_byte_count io_parameters_byte_count = + xenidc_local_buffer_reference_copy_out + (xenidc_endpoint_transaction_to_parameters_lbr + (resource->transaction), + &io_parameters, + sizeof(io_parameters) + ); + + if (io_parameters_byte_count < + sizeof(io_parameters.header)) { + resource->transaction_error = + XENIDC_ERROR_INVALID_PROTOCOL; + + goto PROTOCOL_ERROR; + } + + if (io_parameters.header.io_transaction_type + >= USBIF_IO_TRANSACTION_TYPE_LIMIT) { + resource->transaction_error = + XENIDC_ERROR_INVALID_PARAMETER; + + goto PROTOCOL_ERROR; + } + + if (io_parameters_byte_count + < + usbif_io_parameters_byte_count + [io_parameters.header.io_transaction_type] + ) { + resource->transaction_error = + XENIDC_ERROR_INVALID_PROTOCOL; + + goto PROTOCOL_ERROR; + } + } + + trace1("io type:%d", + (int)io_parameters.header.io_transaction_type); + trace1("dev num:%d", (int)io_parameters.header.device_number); + trace1("endpoint:%d", (int)io_parameters.header.endpoint); + trace1("direction:%d", (int)io_parameters.header.direction); + trace1("unlink_id:%d", (int)io_parameters.header.unlink_id); + trace1("flags:%d", (int)io_parameters.header.flags); + trace1("rbr type:%d", (int)io_parameters.header.rbr.type); + trace1("rbr offset:%d", + (int)io_parameters.header.rbr.byte_offset); + trace1("rbr count:%d", + (int)io_parameters.header.rbr.byte_count); + + 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) { + trace1("Set address:%d", + (int)le16_to_cpu(ctrl->wValue)); + + 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; + + 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) + ? (unsigned int)USB_DIR_OUT : (unsigned int) + USB_DIR_IN) + | ((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) + ); + + trace1("pipe:%x", (int)pipe); + + 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); + + trace0("control URB"); + + trace1("setup[0]:%x", (int)resource->setup[0]); + trace1("setup[1]:%x", (int)resource->setup[1]); + trace1("setup[2]:%x", (int)resource->setup[2]); + trace1("setup[3]:%x", (int)resource->setup[3]); + trace1("setup[4]:%x", (int)resource->setup[4]); + trace1("setup[5]:%x", (int)resource->setup[5]); + trace1("setup[6]:%x", (int)resource->setup[6]); + trace1("setup[7]:%x", (int)resource->setup[7]); + + trace1 + ("mapping:%x", + (int)resource->request_element[0].mapping); + + trace1 + ("count:%x", + (int) + xenidc_remote_buffer_reference_query_byte_count + (&resource->request_element[0].rbr) + ); + } 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); + + trace0("bulk URB"); + } 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; + + trace0("interrupt URB"); + + trace1("interval:%d", + 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 (io_parameters.isochronous.packet_count + > USBIF_MAX_SCHEDULE_PACKET_COUNT) { + resource->transaction_error = + XENIDC_ERROR_TOO_BIG; + + goto SCHEDULE_ERROR; + } + + 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_PARAMETER; + + 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; + } + + trace0("isochronous URB"); + + trace1("interval:%d", + io_parameters.isochronous.interval); + + trace1("packet_count:%d", + io_parameters.isochronous.packet_count); + } + + /* 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; + } + + resource->transaction_error = + usbif_error_map_local_to(usb_submit_urb + (urb, GFP_KERNEL)); + + if (resource->transaction_error != XENIDC_ERROR_SUCCESS) { + printk(KERN_WARNING + "URB %p submission failed.\n", urb); + + 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: + + HANDLED_SPECIAL_CASE: + + PROTOCOL_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; + + resource->transaction_error = + usbif_error_map_local_to(urb->status); + + if (resource->transaction_error != XENIDC_ERROR_SUCCESS) { + printk + (KERN_WARNING "URB %p failed. Status %d\n", urb, + urb->status); + } + + 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 = + usbif_error_map_local_to(urb-> + iso_frame_desc[i]. + status); + + 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); + } + } +} + +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_unlinked_error + (struct usbback_driver_port_resource *resource) { + trace(); + + resource->transaction_error = USBIF_XENIDC_ERROR_UNLINKED; +} + +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 + (&resource->reserve_and_map_rbr_request); + } else { + xenidc_callback_success + (xenidc_reserve_and_map_rbr_request_to_unmap_callback + (&resource->reserve_and_map_rbr_request) + ); + } +} + +static void usbback_driver_port_resource_unmap_callback + (xenidc_callback * callback) { + trace(); + + { + xenidc_reserve_and_map_rbr_request *request = + xenidc_reserve_and_map_rbr_request_unmap_callback_to + (callback); + + struct usbback_driver_port_resource *resource = container_of + (request, + struct usbback_driver_port_resource, + reserve_and_map_rbr_request); + + usbif_io_transaction_status status; + + status.length = resource->transaction_status_length; + + if (xenidc_local_buffer_reference_copy_in + (xenidc_endpoint_transaction_to_status_lbr + (resource->completing_transaction), &status, sizeof(status) + ) + != sizeof(status) + ) { + resource->transaction_error = + XENIDC_ERROR_INVALID_PROTOCOL; + } + + xenidc_endpoint_transaction_complete + (resource->completing_transaction, + resource->transaction_error); + + usbback_driver_port_resource_completed_io(resource->port, + resource); + } +} diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h Mon Nov 21 11:10:19 2005 @@ -0,0 +1,83 @@ +/*****************************************************************************/ +/* 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; + +int usbback_driver_port_resource_init + (struct usbback_driver_port_resource *resource, + struct usbback_driver_port *port); + +void usbback_driver_port_resource_exit + (struct usbback_driver_port_resource *resource); + +void usbback_driver_port_resource_start_io + (struct usbback_driver_port_resource *resource, + xenidc_endpoint_transaction * transaction); + +int usbback_driver_port_resource_try_unlink + (struct usbback_driver_port_resource *resource, int unlink_id); + +void usbback_driver_port_resource_flush_transaction + (struct usbback_driver_port_resource *resource); + +typedef enum { + usbback_driver_port_resource_state_i, + usbback_driver_port_resource_state_i_st, + usbback_driver_port_resource_state_i_st_tu, + usbback_driver_port_resource_state_i_st_ms, + usbback_driver_port_resource_state_i_st_ms_tu, + usbback_driver_port_resource_state_i_st_ms_us, + usbback_driver_port_resource_state_i_st_ms_uc, + usbback_driver_port_resource_state_i_st_ms_tu_us, + usbback_driver_port_resource_state_i_st_ms_tu_us_uc +} usbback_driver_port_resource_state; + +struct usbback_driver_port_resource { + struct usbback_driver_port *port; + struct list_head link; + spinlock_t lock; + usbback_driver_port_resource_state state; + xenidc_error transaction_error; + unsigned long transaction_status_length; + xenidc_endpoint_transaction *transaction; + xenidc_endpoint_transaction *completing_transaction; + xenidc_reserve_and_map_rbr_request reserve_and_map_rbr_request; + xenidc_map_rbr_request_element request_element[2]; + int rbrs_mapped; + struct urb *urb; + u8 setup[8]; + xenidc_callback submit_urb_1_callback; + xenidc_work unlink_urb_1_work; +}; + +#endif diff -r 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c Mon Nov 21 11:10:19 2005 @@ -0,0 +1,80 @@ +/*****************************************************************************/ +/* 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 941c7dbc1353 -r 5a90f01cb37e linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h Mon Nov 21 11:10:19 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 941c7dbc1353 -r 5a90f01cb37e patches/linux-2.6.12/usb.patch --- /dev/null Mon Nov 21 11:09:54 2005 +++ b/patches/linux-2.6.12/usb.patch Mon Nov 21 11:10:19 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");