diff -r 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/arch/xen/Kconfig --- a/linux-2.6-xen-sparse/arch/xen/Kconfig Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/arch/xen/Kconfig Wed Nov 30 11:05:57 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 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/Makefile Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Wed Nov 30 11:05:57 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 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/Makefile --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/Makefile Wed Nov 30 11:05:57 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 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_assert.h Wed Nov 30 11:05:57 2005 @@ -0,0 +1,36 @@ +/*****************************************************************************/ +/* 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(__FUNCTION__, __LINE__, #S)) + +#endif diff -r 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.c Wed Nov 30 11:05:57 2005 @@ -0,0 +1,363 @@ +/*****************************************************************************/ +/* 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; + int frontend_id; + char *frontend; + char *path; + struct xenidc_address address; + struct xenidc_endpoint endpoint; +}; + +static inline struct usbback_device * +usbback_device_endpoint_to(struct xenidc_endpoint *endpoint) +{ + 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) +{ + return device->drvdata; +} + +struct xenidc_address +usbback_device_query_address(struct usbback_device *device) +{ + trace(); + return device->address; +} + +static void usbback_device_endpoint_connect(struct 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(struct xenidc_endpoint *endpoint, +struct 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(struct xenidc_endpoint *endpoint, +struct xenidc_endpoint_message *message) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + trace(); + usbback_driver_message_handler(usbback_device_endpoint_to(endpoint), + message); +} + +static void usbback_device_endpoint_transaction( +struct xenidc_endpoint *endpoint, +struct xenidc_endpoint_transaction *transaction) +{ + /* 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) +{ + int return_value = 0; + trace(); + if (exit) + goto exit_path; + memset(device, 0, sizeof(*device)); + device->dev = dev; + return_value = usbback_driver_probe_usbback_device(device); + if (return_value != 0) { + trace_info("Failed to probe driver."); + goto exit_no_driver; + } + 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) { + trace_info("Failed to initialise endpoint for FE connection."); + goto exit_no_endpoint; + } + return_value = usbback_device_resume_or_suspend(device, 0); + if (return_value != 0) + goto exit_no_resume; + return 0; + exit_path: + (void)usbback_device_resume_or_suspend(device, 1); + exit_no_resume: + xenidc_endpoint_exit(&device->endpoint); + exit_no_endpoint: + 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) +{ + int return_value = 0; + struct usbback_device *device; + trace(); + if (remove) + goto remove_path; + 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_path: + 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) +{ + int return_value = 0; + struct xenbus_transaction *transaction; + trace(); + if (suspend) + goto suspend_path; + transaction = xenbus_transaction_start(); + if (IS_ERR(transaction)) { + trace_info("Error starting transaction."); + return_value = PTR_ERR(transaction); + goto exit_no_transaction; + } + return_value = xenbus_gather(transaction, device->dev->nodename, + "frontend-id", "%i", &device->frontend_id, + "frontend", NULL, &device->frontend, + "path", NULL, &device->path, NULL); + (void)xenbus_transaction_end(transaction, 1); + if (return_value < 0) { + trace_info("Failed to gather configuration parameters."); + goto exit_no_path; + } + trace_info("Configuration: frontend-id:%d, frontend:%s, path:%s", + device->frontend_id, device->frontend, device->path); + usbback_driver_claim_port(device, 1, device->path); + xenidc_address_init(&device->address, device->dev->nodename, + device->frontend, device->frontend_id); + xenidc_endpoint_create(&device->endpoint, device->address); + return 0; + suspend_path: + xenidc_endpoint_destroy(&device->endpoint); + usbback_driver_release_port(device, 1); + kfree(device->path); + kfree(device->frontend); + exit_no_path: + exit_no_transaction: + return return_value; +} + +static int usbback_device_resume(struct xenbus_device *dev) +{ + struct usbback_device *device = dev->data; + trace(); + (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 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_device.h Wed Nov 30 11:05:57 2005 @@ -0,0 +1,41 @@ +/*****************************************************************************/ +/* 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 + +int usbback_device_class_init(void); + +void usbback_device_class_exit(void); + +struct usbback_device; + +void usbback_device_set_drvdata(struct usbback_device *device, void *data); + +void *usbback_device_get_drvdata(struct usbback_device *device); + +struct xenidc_address usbback_device_query_address( +struct usbback_device *device); + +#endif diff -r 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.c Wed Nov 30 11:05:57 2005 @@ -0,0 +1,183 @@ +/*****************************************************************************/ +/* 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) +{ + struct usbback_driver_backend *backend; + int return_value = 0; + trace(); + if (remove) + goto remove_path; + 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_path: + 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) +{ + struct usbback_driver_backend *backend = usbback_device_get_drvdata( + device); + trace(); + usbback_driver_backend_endpoint_connect(backend); +} + +void +usbback_driver_message_handler(struct usbback_device *device, +struct xenidc_endpoint_message * message) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + struct usbback_driver_backend *backend = + usbback_device_get_drvdata(device); + trace(); + usbback_driver_backend_message_handler(backend, message); +} + +void +usbback_driver_transaction_handler(struct usbback_device *device, +struct xenidc_endpoint_transaction * transaction) +{ + /* 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, +struct xenidc_callback *callback) +{ + struct usbback_driver_backend *backend = usbback_device_get_drvdata( + device); + trace(); + usbback_driver_backend_endpoint_disconnect(backend, callback); +} + +void +usbback_driver_claim_port(struct usbback_device *device, u32 port, char *path) +{ + struct usbback_driver_backend *backend = usbback_device_get_drvdata( + device); + trace(); + usbback_driver_backend_claim_port(backend, port, path); +} + +void usbback_driver_release_port(struct usbback_device *device, u32 port) +{ + struct usbback_driver_backend *backend = usbback_device_get_drvdata( + device); + trace(); + 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) +{ + int return_value = 0; + trace(); + if (exit) + goto exit_path; + 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_path: + 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 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver.h Wed Nov 30 11:05:57 2005 @@ -0,0 +1,55 @@ +/*****************************************************************************/ +/* 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" + +int usbback_driver_init(void); + +int usbback_driver_probe_usbback_device(struct usbback_device *device); + +void usbback_driver_endpoint_connect(struct usbback_device *device); + +void +usbback_driver_message_handler(struct usbback_device *device, +struct xenidc_endpoint_message *message); + +void +usbback_driver_transaction_handler(struct usbback_device *device, +struct xenidc_endpoint_transaction *transaction); + +void +usbback_driver_endpoint_disconnect(struct usbback_device *device, +struct xenidc_callback *callback); + +void +usbback_driver_claim_port(struct usbback_device *device, u32 port, char *path); + +void usbback_driver_release_port(struct usbback_device *device, u32 port); + +void usbback_driver_remove_usbback_device(struct usbback_device *device); + +void usbback_driver_exit(void); + +#endif diff -r 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.c Wed Nov 30 11:05:57 2005 @@ -0,0 +1,390 @@ +/*****************************************************************************/ +/* usbback_driver_backend is the representation in the driver of the */ +/* back-end side of a single front-end to back-end connection. */ +/* One of these objects is used by the usbback_driver to manage each */ +/* usbback_device. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Based on arch/xen/drivers/usbif/backend/main.c, original copyright notice */ +/* follows... */ +/*****************************************************************************/ + +/****************************************************************************** + * arch/xen/drivers/usbif/backend/main.c + * + * Backend for the Xen virtual USB driver - provides an abstraction of a + * USB host controller to the corresponding frontend driver. + * + * by Mark Williamson + * Copyright (c) 2004 Intel Research Cambridge + * Copyright (c) 2004, 2005 Mark Williamson + * + * Based on arch/xen/drivers/blkif/backend/main.c + * Copyright (c) 2003-2004, Keir Fraser & Steve Hand + */ + +#include +#include "usbback_assert.h" +#include "usbback_device.h" +#include "usbback_driver_backend.h" +#include "usbback_driver_port.h" +#include "usbback_trace.h" + +#define USBBACK_DRIVER_PORT_COUNT 7 + +struct usbback_driver_backend_callback { + struct xenidc_callback callback; + struct usbback_driver_backend *backend; +}; + +struct usbback_driver_backend { + struct usbback_device *device; + spinlock_t lock; + struct xenidc_callback *endpoint_disconnect_callback; + int port_disconnect_callbacks_out; + struct 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(struct xenidc_callback *callback); + +static int usbback_driver_backend_init_or_exit( +struct usbback_driver_backend *backend, struct usbback_device *device, +int exit) +{ + int return_value = 0, i; + trace(); + if (exit) + goto exit_path; + memset(backend, 0, sizeof(*backend)); + backend->device = device; + spin_lock_init(&backend->lock); + 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; + } + 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_path: + 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) +{ + int i; + trace(); + 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, +struct xenidc_endpoint_transaction *transaction); + +static void +usbback_driver_backend_handle_reset(struct usbback_driver_backend *backend, +struct xenidc_endpoint_transaction *transaction); + +static void +usbback_driver_backend_handle_io(struct usbback_driver_backend *backend, +struct xenidc_endpoint_transaction *transaction); + +void +usbback_driver_backend_transaction_handler( +struct usbback_driver_backend *backend, +struct xenidc_endpoint_transaction *transaction) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + struct usbif_transaction_parameters_header header; + if (xenidc_lbr_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, +struct xenidc_endpoint_transaction *transaction) +{ + struct usbif_probe_transaction_parameters parameters; + struct usbif_probe_transaction_status status; + xenidc_error error; + if (xenidc_lbr_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; + } + 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_lbr_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, +struct xenidc_endpoint_transaction *transaction) +{ + struct usbif_reset_transaction_parameters parameters; + struct usbif_reset_transaction_status status; + xenidc_error error; + int result; + trace(); + if (xenidc_lbr_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; + } + result = usbback_driver_port_reset(&backend->port[parameters.port + - 1]); + if (result < 0) { + error = USBIF_XENIDC_ERROR_NO_DEVICE; + goto complete; + } + memset(&status, 0, sizeof(status)); + status.result = result; + if (xenidc_lbr_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) +{ + int i; + trace(); + 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, +struct xenidc_endpoint_transaction *transaction) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + struct usbif_io_transaction_parameters_header header; + xenidc_error error; + struct usbback_driver_port *port; + trace(); + if (xenidc_lbr_copy_out(xenidc_endpoint_transaction_to_parameters_lbr( + transaction), &header, sizeof(header)) != + sizeof(header)) { + error = XENIDC_ERROR_INVALID_PROTOCOL; + goto complete; + } + 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, +struct xenidc_endpoint_message *message); + +void +usbback_driver_backend_message_handler(struct usbback_driver_backend *backend, +struct xenidc_endpoint_message *message) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + struct usbif_message_header header; + trace(); + if (xenidc_lbr_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)); + /* FIXME: fail message to indicate protocol error if malformed. */ +} + +static void +usbback_driver_backend_handle_unlink(struct usbback_driver_backend *backend, +struct xenidc_endpoint_message *message) +{ + struct usbif_unlink_message_body unlink; + trace(); + if (xenidc_lbr_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, struct xenidc_callback *callback) +{ + int i; + trace(); + backend->endpoint_disconnect_callback = callback; + backend->port_disconnect_callbacks_out = USBBACK_DRIVER_PORT_COUNT; + 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(struct xenidc_callback *callback) +{ + struct usbback_driver_backend *backend = container_of(callback, + struct usbback_driver_backend_callback, callback)->backend; + trace(); + 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) +{ + trace_info("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) +{ + trace_info("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 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_backend.h Wed Nov 30 11:05:57 2005 @@ -0,0 +1,66 @@ +/*****************************************************************************/ +/* 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; + +struct usbback_driver_backend *usbback_driver_backend_allocate( +struct usbback_device *device); + +void +usbback_driver_backend_endpoint_connect( +struct usbback_driver_backend *backend); + +void usbback_driver_backend_transaction_handler( +struct usbback_driver_backend *backend, +struct xenidc_endpoint_transaction * transaction); + +void +usbback_driver_backend_message_handler(struct usbback_driver_backend *backend, +struct xenidc_endpoint_message * message); + +void +usbback_driver_backend_endpoint_disconnect( +struct usbback_driver_backend *backend, struct xenidc_callback *callback); + +void +usbback_driver_backend_claim_port(struct usbback_driver_backend *backend, +u32 port, char *path); + +void +usbback_driver_backend_release_port(struct usbback_driver_backend *backend, +u32 port); + +void +usbback_driver_backend_shutdown(struct usbback_driver_backend *backend); + +struct usbback_device * +usbback_driver_backend_query_device(struct usbback_driver_backend *backend); + +#endif diff -r 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.c Wed Nov 30 11:05:57 2005 @@ -0,0 +1,1134 @@ +/*****************************************************************************/ +/* 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, /* Tra queued/resource freed */ + usbback_driver_port_stimulus_sd, /* Shutdown */ + usbback_driver_port_stimulus_ri, /* test_io tras idle (reent) */ + usbback_driver_port_stimulus_rr, /* test_io tras 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) +{ + int return_value = 0, i; + trace(); + if (exit) + goto exit_path; + 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); + 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_path: + 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) +{ + int return_value = 0, i; + struct usb_device *usbdev = interface_to_usbdev(intf); + struct usbback_driver_port *port = NULL, *cur = NULL; + trace(); + printk(KERN_INFO "usbback: Probe for usb device %s\n", + usbdev->devpath); + down_read(&usbback_driver_port_list_sem); + list_for_each_entry(cur, &usbback_driver_port_list, link) { + printk(KERN_INFO "usbback: Testing 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; + } + 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; + } + } + } + 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 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) +{ + struct usbback_driver_port *port = usb_get_intfdata(intf); + trace(); + /* Protect against reentrant call when we release other interfaces. */ + if (port != NULL) { + struct usb_device *usbdev; + int i; + 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); + usbdev = port->usbdev; + 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) +{ + int status = -1; + trace(); + 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) +{ + unsigned long flags; + trace(); + 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, +struct xenidc_endpoint_transaction *transaction) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + unsigned long flags; + trace(); + 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, +struct xenidc_callback *callback) +{ + unsigned long flags; + trace(); + 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) +{ + int return_value = 0; + struct xenidc_endpoint_transaction *transaction = NULL, *temp; + unsigned long flags; + trace(); + spin_lock_irqsave(&port->lock, flags); + list_for_each_entry(temp, &port->transaction_list, + XENIDC_ENDPOINT_TRANSACTION_LINK) { + struct usbif_io_transaction_parameters_header header; + if (xenidc_lbr_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) +{ + trace_info("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) +{ + int i; + trace(); + while (!list_empty(&port->transaction_list)) { + struct xenidc_endpoint_transaction *transaction = list_entry( + port->transaction_list.next, + struct 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); + } + 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) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + trace(); + while (!list_empty(&port->transaction_list) && + !list_empty(&port->free_resource_list)) { + struct xenidc_endpoint_transaction *transaction = list_entry( + port->transaction_list.next, + struct 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) +{ + unsigned long flags; + trace(); + 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) +{ + int scheduled; + trace(); + usb_get_dev(port->usbdev); + scheduled = xenidc_work_schedule(&port->perform_release_1_work); + ASSERT(scheduled); +} + +static void usbback_driver_port_perform_release_1(void *data) +{ + struct usbback_driver_port *port = (struct usbback_driver_port *)data; + trace(); + 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 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port.h Wed Nov 30 11:05:57 2005 @@ -0,0 +1,146 @@ +/*****************************************************************************/ +/* Object which manages a single USB device and handles all the */ +/* io transactions for that device by assigning */ +/* usbback_driver_port_resources to process them. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBBACK_DRIVER_PORT_H +#define USBBACK_DRIVER_PORT_H + +#include +#include +#include "usbback_assert.h" +#include "usbback_driver_backend.h" +#include "usbback_driver_port_resource.h" +#include "usbback_trace.h" + +int usbback_driver_port_class_init(void); + +void usbback_driver_port_class_exit(void); + +int usbback_driver_port_init(struct usbback_driver_port *port, +struct usbback_driver_backend *backend); + +void usbback_driver_port_claim(struct usbback_driver_port *port, char *path); + +void usbback_driver_port_release(struct usbback_driver_port *port); + +int usbback_driver_port_probe_usb(struct usb_interface *intf); + +void usbback_driver_port_disconnect_usb(struct usb_interface *intf); + +/* On success, usbback_driver_port_reset returns */ +/* USBIF_RESET_RESULT_FULL/LOW/HIGH_SPEED */ + +int usbback_driver_port_reset(struct usbback_driver_port *port); + +void +usbback_driver_port_set_guest_address(struct usbback_driver_port *port, +unsigned long guest_address); + +int +usbback_driver_port_match_guest_address(struct usbback_driver_port *port, +unsigned long guest_address); + +void usbback_driver_port_endpoint_connect(struct usbback_driver_port *port); + +void +usbback_driver_port_handle_io(struct usbback_driver_port *port, +struct xenidc_endpoint_transaction *transaction); + +void +usbback_driver_port_endpoint_disconnect(struct usbback_driver_port *port, +struct 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]; + struct xenidc_work perform_release_1_work; + struct 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) +{ + 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 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.c Wed Nov 30 11:05:57 2005 @@ -0,0 +1,850 @@ +/*****************************************************************************/ +/* 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(submit_urb_serialiser); + +static struct xenidc_rbr_mapper_pool *rbr_mapper_pool; + +int usbback_driver_port_resource_class_init(void) +{ + struct xenidc_buffer_resource_list sum, bulk_list, schedule_list; + trace(); + sum = xenidc_buffer_resource_list_null(); + bulk_list = xenidc_grant_table_calculate_buffer_resource_list( + USBIF_MAX_BULK_BYTE_COUNT, USBIF_BULK_BYTE_ALIGNMENT); + 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); + rbr_mapper_pool = xenidc_allocate_rbr_mapper_pool(sum); + return (rbr_mapper_pool != NULL) ? 0 : -ENOMEM; +} + +void usbback_driver_port_resource_class_exit(void) +{ + trace(); + xenidc_free_rbr_mapper_pool(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(struct xenidc_callback * callback); + +static void usbback_driver_port_resource_unlink_urb_1(void *data); + +static void +usbback_driver_port_resource_map_callback(struct xenidc_callback * callback); + +static void +usbback_driver_port_resource_unmap_callback(struct 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, +struct xenidc_endpoint_transaction *transaction) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + unsigned long flags; + trace(); + 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) +{ + int return_value = 0; + unsigned long flags; + trace(); + spin_lock_irqsave(&resource->lock, flags); + if (resource->transaction != NULL) { + struct usbif_io_transaction_parameters_header header; + if ((xenidc_lbr_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) +{ + unsigned long flags; + trace(); + 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) +{ + trace_info("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) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + struct usbif_io_transaction_parameters_header header; + trace(); + if (xenidc_lbr_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) { + struct usbif_isochronous_io_transaction_parameters parameters; + if (xenidc_lbr_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(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(struct xenidc_callback * callback) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + struct 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; + trace(); + 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 { + trace_info("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) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + trace(); + xenidc_callback_serialiser_complete_callback(&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(struct xenidc_callback * callback) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + 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 + }; + struct usbback_driver_port_resource *resource = container_of(callback, + struct usbback_driver_port_resource, submit_urb_1_callback); + union usbif_io_transaction_parameters io_parameters; + xenidc_buffer_byte_count io_parameters_byte_count; + struct urb *urb = resource->urb; + struct usb_device * usbdev = usbback_driver_port_query_usbdev( + resource->port); + unsigned int pipe; + unsigned long flags; + trace(); + io_parameters_byte_count = xenidc_lbr_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; + } + trace_info("io type:%d", + (int)io_parameters.header.io_transaction_type); + trace_info("dev num:%d", (int)io_parameters.header.device_number); + trace_info("endpoint:%d", (int)io_parameters.header.endpoint); + trace_info("direction:%d", (int)io_parameters.header.direction); + trace_info("unlink_id:%d", (int)io_parameters.header.unlink_id); + trace_info("flags:%d", (int)io_parameters.header.flags); + trace_info("rbr type:%d", (int)io_parameters.header.rbr.type); + trace_info("rbr offset:%d", (int)io_parameters.header.rbr.byte_offset); + trace_info("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) { + trace_info("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; + } + } + } + if (io_parameters.header.direction == + USBIF_IO_TRANSACTION_DIRECTION_OUT) { + pipe = USB_DIR_OUT; + } else { + pipe = USB_DIR_IN; + } + pipe |= (unsigned int)usbdev->devnum << 8; + pipe |= (unsigned int)io_parameters.header.endpoint << 15; + pipe |= pipe_type[io_parameters.header.io_transaction_type] << 30; + trace_info("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, usbdev, pipe, resource->setup, + resource->request_element[0].mapping, + xenidc_rbr_query_byte_count(&resource-> + request_element[0].rbr), + usbback_driver_port_resource_end_io, resource); + trace_info("control URB"); + trace_info("setup[0]:%x", (int)resource->setup[0]); + trace_info("setup[1]:%x", (int)resource->setup[1]); + trace_info("setup[2]:%x", (int)resource->setup[2]); + trace_info("setup[3]:%x", (int)resource->setup[3]); + trace_info("setup[4]:%x", (int)resource->setup[4]); + trace_info("setup[5]:%x", (int)resource->setup[5]); + trace_info("setup[6]:%x", (int)resource->setup[6]); + trace_info("setup[7]:%x", (int)resource->setup[7]); + trace_info("mapping:%x", (int)resource->request_element[0]. + mapping); + trace_info("count:%x", (int)xenidc_rbr_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, usbdev, pipe, + resource->request_element[0].mapping, + xenidc_rbr_query_byte_count( + &resource->request_element[0].rbr), + usbback_driver_port_resource_end_io, + resource); + trace_info("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, usbdev, pipe, + resource->request_element[0].mapping, + xenidc_rbr_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; + trace_info("interrupt URB"); + trace_info("interval:%d", io_parameters.interrupt.interval); + } else { + struct usbif_isochronous_io_schedule_element *schedule_element; + struct usbif_isochronous_io_schedule_element aligned_element; + int i; + 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 = usbdev; + urb->pipe = pipe; + urb->transfer_buffer = resource->request_element[0].mapping; + urb->transfer_buffer_length = xenidc_rbr_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_rbr_query_byte_count(&resource->request_element[1]. + rbr) < (io_parameters.isochronous.packet_count + * sizeof(struct + usbif_isochronous_io_schedule_element))) { + resource->transaction_error = + XENIDC_ERROR_INVALID_PARAMETER; + goto schedule_error; + } + schedule_element = resource->request_element[1].mapping; + 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; + } + trace_info("isochronous URB"); + trace_info("interval:%d", io_parameters.isochronous.interval); + trace_info("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; + } + 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: + 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) +{ + struct usbback_driver_port_resource *resource = urb->context; + unsigned long flags; + trace(); + 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) { + struct usbif_isochronous_io_schedule_element *schedule_element + = resource->request_element[1].mapping; + struct 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)); + } + } + 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) +{ + int scheduled; + trace(); + usb_get_urb(resource->urb); + scheduled = xenidc_work_schedule(&resource->unlink_urb_1_work); + ASSERT(scheduled); +} + +static void +usbback_driver_port_resource_unlink_urb_1(void *data) +{ + struct usbback_driver_port_resource *resource = + (struct usbback_driver_port_resource *)data; + unsigned long flags; + trace(); + usb_unlink_urb(resource->urb); + usb_put_urb(resource->urb); + 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(struct xenidc_callback * callback) +{ + struct 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); + struct usbif_io_transaction_status status; + trace(); + status.length = resource->transaction_status_length; + if (xenidc_lbr_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 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_driver_port_resource.h Wed Nov 30 11:05:57 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, +struct 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; + struct xenidc_endpoint_transaction *transaction; + struct xenidc_endpoint_transaction *completing_transaction; + struct xenidc_reserve_and_map_rbr_request reserve_and_map_rbr_request; + struct xenidc_map_rbr_request_element request_element[2]; + int rbrs_mapped; + struct urb *urb; + u8 setup[8]; + struct xenidc_callback submit_urb_1_callback; + struct xenidc_work unlink_urb_1_work; +}; + +#endif diff -r 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_module.c Wed Nov 30 11:05:57 2005 @@ -0,0 +1,62 @@ +/*****************************************************************************/ +/* 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) +{ + int return_value = 0; + trace(); + if (exit) + goto exit_path; + 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_path: + 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 0dab7be3b83a -r e95f0d5261d3 linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h Wed Nov 30 11:05:57 2005 @@ -0,0 +1,41 @@ +/*****************************************************************************/ +/* 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 trace_info(format, ...) \ +printk(KERN_INFO "usbback %s: " format "\n", __FUNCTION__, ## __VA_ARGS__) +#define trace() trace_info( "" ) + +#else + +#define trace_info(format, ...) +#define trace() + +#endif + +#endif diff -r 0dab7be3b83a -r e95f0d5261d3 patches/linux-2.6.12/usb.patch --- /dev/null Tue Nov 29 17:11:59 2005 +++ b/patches/linux-2.6.12/usb.patch Wed Nov 30 11:05:57 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");