diff -r 5a90f01cb37e -r 06d98ed0b6e5 linux-2.6-xen-sparse/arch/xen/Kconfig --- a/linux-2.6-xen-sparse/arch/xen/Kconfig Mon Nov 21 11:10:19 2005 +++ b/linux-2.6-xen-sparse/arch/xen/Kconfig Mon Nov 21 11:10:40 2005 @@ -159,6 +159,30 @@ are unsure; or if you experience network hangs when this option is enabled; then you must say N here. +config XEN_USBDEV_FRONTEND + tristate "USB-device frontend driver" + select USB + default m + help + The USB-device frontend driver allows the kernel to access USB + devices exported by a USB-device backend driver running in another + domain. + This is not required for USB device access in domain 0 or any domain + given exclusive control over a USB host controller device at the PCI + level. + Say Y or M if you want to use a USB-device backend driver to export a + USB device from another domain to the domain which will run this + kernel. + +config XEN_USBDEV_FRONTEND_TRACE + bool "USB-device frontend driver tracing" + depends on XEN_USBDEV_FRONTEND + default 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_BLKDEV_TAP bool "Block device tap driver" default n diff -r 5a90f01cb37e -r 06d98ed0b6e5 linux-2.6-xen-sparse/drivers/xen/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/Makefile Mon Nov 21 11:10:19 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Mon Nov 21 11:10:40 2005 @@ -17,4 +17,4 @@ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ obj-$(CONFIG_XEN_TPMDEV_FRONTEND) += tpmfront/ - +obj-$(CONFIG_XEN_USBDEV_FRONTEND) += usbfront/ diff -r 5a90f01cb37e -r 06d98ed0b6e5 linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile --- /dev/null Mon Nov 21 11:10:19 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile Mon Nov 21 11:10:40 2005 @@ -0,0 +1,7 @@ +obj-$(CONFIG_XEN_USBDEV_FRONTEND) += usbfront.o + +usbfront-objs := \ +usbfront_hcd_resource.o \ +usbfront_driver.o \ +usbfront_device.o \ +usbfront_module.o diff -r 5a90f01cb37e -r 06d98ed0b6e5 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_assert.h --- /dev/null Mon Nov 21 11:10:19 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_assert.h Mon Nov 21 11:10:40 2005 @@ -0,0 +1,39 @@ +/*****************************************************************************/ +/* An implementation of the ASSERT macro. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBFRONT_ASSERT_H +#define USBFRONT_ASSERT_H + +#include + +static inline void assert_failed + (const char *function, int line, const char *statement) { + printk + (KERN_ERR "usbfront assert failed: %s line %d, statement %s\n", + function, line, statement); + + BUG(); +} + +#define ASSERT( S ) \ +( ( S ) ? ( (void)0 ) : assert_failed( __PRETTY_FUNCTION__, __LINE__, #S ) ) + +#endif diff -r 5a90f01cb37e -r 06d98ed0b6e5 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.c --- /dev/null Mon Nov 21 11:10:19 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.c Mon Nov 21 11:10:40 2005 @@ -0,0 +1,1192 @@ +/*****************************************************************************/ +/* usbfront_device is a device which represents a connection to a back-end. */ +/* The intent was for it to have an interface like a hardware USB host */ +/* controller device. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Based on arch/xen/drivers/usbif/frontend/main.c, original copyright */ +/* notice follows... */ +/*****************************************************************************/ + +/* + * Xen Virtual USB Frontend Driver + * + * This file contains the first version of the Xen virtual USB hub + * that I've managed not to delete by mistake (3rd time lucky!). + * + * Based on Linux's uhci.c, original copyright notices are displayed + * below. Portions also (c) 2004 Intel Research Cambridge + * and (c) 2004, 2005 Mark Williamson + * + * Contact or + * regarding this code. + * + * Still to be (maybe) implemented: + * - migration / backend restart support? + * - support for building / using as a module + */ + +/* + * Universal Host Controller Interface driver for USB. + * + * Maintainer: Johannes Erdfelt + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx + * (C) Copyright 1999 Randy Dunlap + * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx + * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx + * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx + * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx + * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface + * support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx). + * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) + * + * Intel documents this fairly well, and as far as I know there + * are no royalties or anything like that, but even so there are + * people who decided that they want to do the same thing in a + * completely different way. + * + * WARNING! The USB documentation is downright evil. Most of it + * is just crap, written by a committee. You're better off ignoring + * most of it, the important stuff is: + * - the low-level protocol (fairly simple but lots of small details) + * - working around the horridness of the rest + */ + +/* Xenbus code for blkif backend + Copyright (C) 2005 Rusty Russell + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include "usbfront_assert.h" +#include "usbfront_device.h" +#include "usbfront_driver.h" +#include "usbfront_trace.h" + +#define USBFRONT_DEVICE_PORT_COUNT 7 + +typedef enum { + usbfront_device_state_i, + usbfront_device_state_i_cn, + usbfront_device_state_i_cn_dn, + usbfront_device_state_i_cn_ps, + usbfront_device_state_i_cn_pf, + usbfront_device_state_i_cn_dn_ps, + usbfront_device_state_i_cn_ps_dn, + usbfront_device_state_i_cn_ps_pc, + usbfront_device_state_i_cn_ps_dn_rc +} usbfront_device_state; + +typedef enum { + usbfront_device_stimulus_cn, /* Endpoint connect. */ + usbfront_device_stimulus_dn, /* Endpoint disconnect. */ + usbfront_device_stimulus_ps, /* Probe driver success. */ + usbfront_device_stimulus_pf, /* Probe driver failure. */ + usbfront_device_stimulus_rc, /* Remove driver complete. */ + usbfront_device_stimulus_pt, /* Polling tick. */ + usbfront_device_stimulus_pc /* Probe complete. */ +} usbfront_device_stimulus; + +struct usbfront_device; + +struct usbfront_device_probe_transaction { + xenidc_endpoint_transaction transaction; + + union { + struct { + usbif_probe_transaction_parameters parameters; + usbif_probe_transaction_status status; + } probe; + struct { + usbif_reset_transaction_parameters parameters; + usbif_reset_transaction_status status; + } reset; + }; + + struct usbfront_device *device; +}; + +struct usbfront_device { + struct xenbus_device *dev; + void *drvdata; + xenidc_address address; + spinlock_t lock; + usbfront_device_state state; + xenidc_endpoint endpoint; + xenidc_callback *endpoint_disconnect_callback; + int tick_count; + int port_probe_count; + struct usbfront_device_probe_transaction + probe_transaction[USBFRONT_DEVICE_PORT_COUNT]; + struct usb_port_status port_status[USBFRONT_DEVICE_PORT_COUNT]; + xenidc_work probe_driver_1_work; + xenidc_work remove_driver_1_work; +}; + +static void usbfront_device_handle_stimulus + (struct usbfront_device *device, usbfront_device_stimulus stimulus); + +static inline struct usbfront_device *usbfront_device_endpoint_to + (xenidc_endpoint * endpoint) { + trace1("endpoint:%p", endpoint); + + return container_of(endpoint, struct usbfront_device, endpoint); +} + +void usbfront_device_set_drvdata(struct usbfront_device *device, void *data) { + trace2("device:%p,data:%p", device, data); + + device->drvdata = data; +} + +void *usbfront_device_get_drvdata(struct usbfront_device *device) +{ + trace1("device:%p", device); + + return device->drvdata; +} + +struct device *usbfront_device_to_dev(struct usbfront_device *device) +{ + trace1("device:%p", device); + + return &device->dev->dev; +} + +struct usbfront_device *usbfront_device_dev_to(struct device *dev) +{ + return to_xenbus_device(dev)->data; +} + +int usbfront_device_query_port_count(struct usbfront_device *device) +{ + /* trace(); */ + + return USBFRONT_DEVICE_PORT_COUNT; +} + +int usbfront_device_query_port_status_changed + (struct usbfront_device *device, int port_number) { + /* trace(); */ + + ASSERT((port_number > 0) + && (port_number <= USBFRONT_DEVICE_PORT_COUNT) + ); + + { + int changed; + + unsigned long flags; + + spin_lock_irqsave(&device->lock, flags); + + if (++device->tick_count == USBFRONT_DEVICE_PORT_COUNT) { + device->tick_count = 0; + + usbfront_device_handle_stimulus + (device, usbfront_device_stimulus_pt); + } + + changed = + (device->port_status[port_number - 1].wPortChange != 0); + + spin_unlock_irqrestore(&device->lock, flags); + + return changed; + } +} + +struct usb_port_status usbfront_device_query_port_status + (struct usbfront_device *device, int port_number) { + trace(); + + ASSERT((port_number > 0) + && (port_number <= USBFRONT_DEVICE_PORT_COUNT) + ); + + { + struct usb_port_status port_status; + + unsigned long flags; + + spin_lock_irqsave(&device->lock, flags); + + port_status = device->port_status[port_number - 1]; + + spin_unlock_irqrestore(&device->lock, flags); + + return port_status; + } +} + +void usbfront_device_set_port_power + (struct usbfront_device *device, int port_number) { + trace(); + + ASSERT((port_number > 0) + && (port_number <= USBFRONT_DEVICE_PORT_COUNT) + ); + + { + unsigned long flags; + + spin_lock_irqsave(&device->lock, flags); + + device->port_status[port_number - 1].wPortStatus |= + USB_PORT_STAT_POWER; + + spin_unlock_irqrestore(&device->lock, flags); + } +} + +void usbfront_device_set_port_reset + (struct usbfront_device *device, int port_number) { + trace(); + + ASSERT((port_number > 0) + && (port_number <= USBFRONT_DEVICE_PORT_COUNT) + ); + + { + unsigned long flags; + + spin_lock_irqsave(&device->lock, flags); + + device->port_status[port_number - 1].wPortStatus |= + USB_PORT_STAT_RESET; + device->port_status[port_number - 1].wPortStatus &= + ~USB_PORT_STAT_ENABLE; + + usbfront_device_handle_stimulus(device, + usbfront_device_stimulus_pt); + + spin_unlock_irqrestore(&device->lock, flags); + } +} + +void usbfront_device_clear_port_enable + (struct usbfront_device *device, int port_number) { + trace(); + + ASSERT((port_number > 0) + && (port_number <= USBFRONT_DEVICE_PORT_COUNT) + ); + + { + unsigned long flags; + + spin_lock_irqsave(&device->lock, flags); + + device->port_status[port_number - 1].wPortStatus &= + ~USB_PORT_STAT_ENABLE; + + spin_unlock_irqrestore(&device->lock, flags); + } +} + +void usbfront_device_clear_port_connection_change + (struct usbfront_device *device, int port_number) { + trace(); + + ASSERT((port_number > 0) + && (port_number <= USBFRONT_DEVICE_PORT_COUNT) + ); + + { + unsigned long flags; + + spin_lock_irqsave(&device->lock, flags); + + device->port_status[port_number - 1].wPortChange &= + ~USB_PORT_STAT_C_CONNECTION; + + spin_unlock_irqrestore(&device->lock, flags); + } +} + +void usbfront_device_clear_port_reset_change + (struct usbfront_device *device, int port_number) { + trace(); + + ASSERT((port_number > 0) + && (port_number <= USBFRONT_DEVICE_PORT_COUNT) + ); + + { + unsigned long flags; + + spin_lock_irqsave(&device->lock, flags); + + device->port_status[port_number - 1].wPortChange &= + ~USB_PORT_STAT_C_RESET; + + spin_unlock_irqrestore(&device->lock, flags); + } +} + +void usbfront_device_submit_message + (struct usbfront_device *device, xenidc_endpoint_message * message) { + trace(); + + xenidc_endpoint_submit_message(&device->endpoint, message); +} + +xenidc_address usbfront_device_query_address(struct usbfront_device *device) +{ + trace(); + + return device->address; +} + +void usbfront_device_submit_transaction + (struct usbfront_device *device, xenidc_endpoint_transaction * transaction) +{ + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + xenidc_endpoint_submit_transaction(&device->endpoint, transaction); +} + +static void usbfront_device_endpoint_connect(xenidc_endpoint * endpoint) +{ + trace1("endpoint:%p", endpoint); + + /* Between connect and completion of the disconnect callback we are */ + /* allowed to issue messages and transactions. */ + + { + struct usbfront_device *device = + usbfront_device_endpoint_to(endpoint); + + unsigned long flags; + + trace1("device:%p", device); + + spin_lock_irqsave(&device->lock, flags); + + usbfront_device_handle_stimulus(device, + usbfront_device_stimulus_cn); + + spin_unlock_irqrestore(&device->lock, flags); + } +} + +static void usbfront_device_endpoint_disconnect + (xenidc_endpoint * endpoint, xenidc_callback * callback) { + trace(); + + /* We must stop issuing messages and transactions and complete the */ + /* callback once all of the messages and transactions we are issuing */ + /* have completed or failed back to us. */ + + { + struct usbfront_device *device = + usbfront_device_endpoint_to(endpoint); + + unsigned long flags; + + spin_lock_irqsave(&device->lock, flags); + + device->endpoint_disconnect_callback = callback; + + usbfront_device_handle_stimulus(device, + usbfront_device_stimulus_dn); + + spin_unlock_irqrestore(&device->lock, flags); + } +} + +static void usbfront_device_endpoint_message + (xenidc_endpoint * endpoint, xenidc_endpoint_message * message) { + trace(); + + /* The protocol doesn't require any messages sent from BE to FE so we */ + /* just ignore anything sent to us. */ + + xenidc_callback_success(xenidc_endpoint_message_to_callback(message)); +} + +static void usbfront_device_endpoint_transaction + (xenidc_endpoint * endpoint, xenidc_endpoint_transaction * transaction) { + trace(); + + /* The protocol doesn't require any transactions sent from BE to FE so */ + /* we just ignore anything sent to us. */ + + xenidc_endpoint_transaction_complete + (transaction, XENIDC_ERROR_INVALID_PROTOCOL); +} + +static void usbfront_device_probe_driver_1(void *data); +static void usbfront_device_remove_driver_1(void *data); +static void usbfront_device_probe_all_ports_1(xenidc_callback * callback); + +static int __usbfront_device_resume_or_suspend + (struct usbfront_device *device, int suspend); + +static int usbfront_device_init_or_exit + (struct usbfront_device *device, struct xenbus_device *dev, int exit) { + trace1("%p", device); + + { + int return_value = 0; + + if (exit) { + goto EXIT; + } + + memset(device, 0, sizeof(*device)); + + device->dev = dev; + + spin_lock_init(&device->lock); + + device->state = usbfront_device_state_i; + + { + int i; + + for (i = 0; i < USBFRONT_DEVICE_PORT_COUNT; i++) { + struct usbfront_device_probe_transaction *probe + = &device->probe_transaction[i]; + + xenidc_endpoint_transaction_init + (&probe->transaction, + usbfront_device_probe_all_ports_1); + + probe->device = device; + } + } + + xenidc_work_init + (&device->probe_driver_1_work, + usbfront_device_probe_driver_1, device); + + xenidc_work_init + (&device->remove_driver_1_work, + usbfront_device_remove_driver_1, device); + + return_value = xenidc_endpoint_init + (&device->endpoint, + usbfront_device_endpoint_connect, + usbfront_device_endpoint_message, + usbfront_device_endpoint_transaction, + usbfront_device_endpoint_disconnect, + USBIF_FE_INITIATOR_QUOTA, + USBIF_FE_INITIATOR_MAXIMUM_BYTE_COUNT, + USBIF_FE_TARGET_QUOTA, USBIF_FE_TARGET_MAXIMUM_BYTE_COUNT); + + if (return_value != 0) { + goto EXIT_NO_ENDPOINT; + } + + return_value = __usbfront_device_resume_or_suspend(device, 0); + + if (return_value != 0) { + goto EXIT_NO_RESUME; + } + + return 0; + + EXIT: + + (void)__usbfront_device_resume_or_suspend(device, 1); + + EXIT_NO_RESUME: + + xenidc_endpoint_exit(&device->endpoint); + + EXIT_NO_ENDPOINT: + + return return_value; + } +} + +static int usbfront_device_init + (struct usbfront_device *device, struct xenbus_device *dev) { + trace(); + + return usbfront_device_init_or_exit(device, dev, 0); +} + +static void usbfront_device_exit(struct usbfront_device *device) +{ + trace(); + + (void)usbfront_device_init_or_exit(device, NULL, 1); +} + +static int usbfront_device_probe_or_remove + (struct xenbus_device *dev, int remove) { + trace(); + + { + int return_value = 0; + + struct usbfront_device *device; + + if (remove) { + goto REMOVE; + } + + device = kmalloc(sizeof(*device), GFP_KERNEL); + + if (device == NULL) { + xenbus_dev_error(dev, -ENOMEM, + "allocating frontend structure"); + + return_value = -ENOMEM; + + goto EXIT_NO_DEVICE; + } + + dev->data = device; + + return_value = usbfront_device_init(device, dev); + + if (return_value != 0) { + goto EXIT_INIT_FAILED; + } + + return 0; + + REMOVE: + + device = dev->data; + + usbfront_device_exit(device); + + EXIT_INIT_FAILED: + + dev->data = NULL; + + kfree(device); + + EXIT_NO_DEVICE: + + return return_value; + } +} + +static int usbfront_device_probe + (struct xenbus_device *dev, const struct xenbus_device_id *id) { + trace(); + + return usbfront_device_probe_or_remove(dev, 0); +} + +static int usbfront_device_remove(struct xenbus_device *dev) +{ + trace(); + + return usbfront_device_probe_or_remove(dev, 1); +} + +static int __usbfront_device_resume_or_suspend + (struct usbfront_device *device, int suspend) { + trace(); + + { + int return_value = 0; + + if (suspend) { + goto SUSPEND; + } + + xenidc_address_init + (&device->address, + device->dev->nodename, + device->dev->otherend, device->dev->otherend_id); + + xenidc_endpoint_create(&device->endpoint, device->address); + + return 0; + + SUSPEND: + + xenidc_endpoint_destroy(&device->endpoint); + + return return_value; + } +} + +static int usbfront_device_resume(struct xenbus_device *dev) +{ + trace(); + + { + struct usbfront_device *device = dev->data; + + (void)__usbfront_device_resume_or_suspend(device, 1); + + return __usbfront_device_resume_or_suspend(device, 0); + } +} + +static struct xenbus_device_id usbfront_device_ids[] = { + {"usb"}, + {""} +}; + +static struct xenbus_driver usbfront_device_driver = { + .name = "usb", + .owner = THIS_MODULE, + .ids = usbfront_device_ids, + .probe = usbfront_device_probe, + .remove = usbfront_device_remove, + .resume = usbfront_device_resume +}; + +int usbfront_device_class_init(void) +{ + trace(); + + return xenbus_register_frontend(&usbfront_device_driver); +} + +void usbfront_device_class_exit(void) +{ + trace(); + + xenbus_unregister_driver(&usbfront_device_driver); +} + +static void usbfront_device_invalid_stimulus + (struct usbfront_device *device, usbfront_device_stimulus stimulus); + +static void usbfront_device_probe_driver(struct usbfront_device *device); + +static void usbfront_device_remove_driver(struct usbfront_device *device); + +static void usbfront_device_probe_all_ports(struct usbfront_device *device); + +static void usbfront_device_disconnect_all_ports + (struct usbfront_device *device); + +static void usbfront_device_complete_endpoint_disconnect + (struct usbfront_device *device); + +static void usbfront_device_handle_stimulus + (struct usbfront_device *device, usbfront_device_stimulus stimulus) { + switch (device->state) { + case usbfront_device_state_i: + switch (stimulus) { + case usbfront_device_stimulus_cn: + device->state = usbfront_device_state_i_cn; + usbfront_device_probe_driver(device); + break; + default: + usbfront_device_invalid_stimulus(device, stimulus); + break; + } + break; + case usbfront_device_state_i_cn: + /* Probing driver. */ + switch (stimulus) { + case usbfront_device_stimulus_dn: + device->state = usbfront_device_state_i_cn_dn; + break; + case usbfront_device_stimulus_ps: + device->state = usbfront_device_state_i_cn_ps; + usbfront_device_probe_all_ports(device); + break; + case usbfront_device_stimulus_pf: + device->state = usbfront_device_state_i_cn_pf; + break; + case usbfront_device_stimulus_pt: + break; + default: + usbfront_device_invalid_stimulus(device, stimulus); + break; + } + break; + case usbfront_device_state_i_cn_dn: + /* Probing driver. */ + /* Endpoint disconnecting. */ + switch (stimulus) { + case usbfront_device_stimulus_ps: + device->state = usbfront_device_state_i_cn_dn_ps; + usbfront_device_remove_driver(device); + break; + case usbfront_device_stimulus_pf: + device->state = usbfront_device_state_i; + usbfront_device_disconnect_all_ports(device); + usbfront_device_complete_endpoint_disconnect(device); + break; + case usbfront_device_stimulus_pt: + break; + default: + usbfront_device_invalid_stimulus(device, stimulus); + break; + } + break; + case usbfront_device_state_i_cn_ps: + /* Driver Probed. */ + /* Polling ports. */ + switch (stimulus) { + case usbfront_device_stimulus_dn: + device->state = usbfront_device_state_i_cn_ps_dn; + usbfront_device_remove_driver(device); + break; + case usbfront_device_stimulus_pt: + break; + case usbfront_device_stimulus_pc: + device->state = usbfront_device_state_i_cn_ps_pc; + break; + default: + usbfront_device_invalid_stimulus(device, stimulus); + break; + } + break; + case usbfront_device_state_i_cn_pf: + /* Driver probe failed. */ + switch (stimulus) { + case usbfront_device_stimulus_dn: + device->state = usbfront_device_state_i; + usbfront_device_disconnect_all_ports(device); + usbfront_device_complete_endpoint_disconnect(device); + break; + default: + usbfront_device_invalid_stimulus(device, stimulus); + break; + } + break; + case usbfront_device_state_i_cn_dn_ps: + /* Endpoint disconnecting. */ + /* Removing driver. */ + switch (stimulus) { + case usbfront_device_stimulus_rc: + device->state = usbfront_device_state_i; + usbfront_device_disconnect_all_ports(device); + usbfront_device_complete_endpoint_disconnect(device); + break; + case usbfront_device_stimulus_pt: + break; + default: + usbfront_device_invalid_stimulus(device, stimulus); + break; + } + break; + case usbfront_device_state_i_cn_ps_dn: + /* Endpoint disconnecting. */ + /* Removing driver. */ + /* Polling ports. */ + switch (stimulus) { + case usbfront_device_stimulus_rc: + device->state = usbfront_device_state_i_cn_ps_dn_rc; + break; + case usbfront_device_stimulus_pt: + break; + case usbfront_device_stimulus_pc: + device->state = usbfront_device_state_i_cn_dn_ps; + break; + default: + usbfront_device_invalid_stimulus(device, stimulus); + break; + } + break; + case usbfront_device_state_i_cn_ps_pc: + /* Driver Probed. */ + switch (stimulus) { + case usbfront_device_stimulus_dn: + device->state = usbfront_device_state_i_cn_dn_ps; + usbfront_device_remove_driver(device); + break; + case usbfront_device_stimulus_pt: + device->state = usbfront_device_state_i_cn_ps; + usbfront_device_probe_all_ports(device); + break; + default: + usbfront_device_invalid_stimulus(device, stimulus); + break; + } + break; + case usbfront_device_state_i_cn_ps_dn_rc: + /* Endpoint disconnecting. */ + /* Polling ports. */ + switch (stimulus) { + case usbfront_device_stimulus_pc: + device->state = usbfront_device_state_i; + usbfront_device_disconnect_all_ports(device); + usbfront_device_complete_endpoint_disconnect(device); + break; + default: + usbfront_device_invalid_stimulus(device, stimulus); + break; + } + break; + default: + usbfront_device_invalid_stimulus(device, stimulus); + break; + } +} + +static void usbfront_device_invalid_stimulus + (struct usbfront_device *device, usbfront_device_stimulus stimulus) { + trace(); + + printk + (KERN_ERR "usbfront: device %p in state %d " + "received invalid stimulus %d\n", device, device->state, stimulus); +} + +static void usbfront_device_probe_driver(struct usbfront_device *device) +{ + trace(); + + { + int scheduled = + xenidc_work_schedule(&device->probe_driver_1_work); + + ASSERT(scheduled); + } +} + +static void usbfront_device_probe_driver_1(void *data) +{ + trace(); + + { + struct usbfront_device *device = (struct usbfront_device *)data; + + usbfront_device_stimulus stimulus; + + if (usbfront_driver_probe(device) == 0) { + stimulus = usbfront_device_stimulus_ps; + } else { + stimulus = usbfront_device_stimulus_pf; + } + + { + unsigned long flags; + + spin_lock_irqsave(&device->lock, flags); + + usbfront_device_handle_stimulus(device, stimulus); + + spin_unlock_irqrestore(&device->lock, flags); + } + } +} + +static void usbfront_device_remove_driver(struct usbfront_device *device) +{ + trace(); + + { + int scheduled = + xenidc_work_schedule(&device->remove_driver_1_work); + + ASSERT(scheduled); + } +} + +static void usbfront_device_remove_driver_1(void *data) +{ + trace(); + + { + struct usbfront_device *device = (struct usbfront_device *)data; + + usbfront_driver_remove(device); + + { + unsigned long flags; + + spin_lock_irqsave(&device->lock, flags); + + usbfront_device_handle_stimulus + (device, usbfront_device_stimulus_rc); + + spin_unlock_irqrestore(&device->lock, flags); + } + } +} + +static void usbfront_device_probe_all_ports(struct usbfront_device *device) +{ + device->port_probe_count = USBFRONT_DEVICE_PORT_COUNT; + + { + int i; + + for (i = 0; i < USBFRONT_DEVICE_PORT_COUNT; i++) { + struct usbfront_device_probe_transaction *probe = + &device->probe_transaction[i]; + + if ((device->port_status[i]. + wPortStatus & USB_PORT_STAT_RESET) + != USB_PORT_STAT_RESET) { + xenidc_endpoint_transaction_set_parameters_lbr + (&probe->transaction, + xenidc_vaddress_create_lbr + (&probe->probe.parameters, + sizeof(probe->probe.parameters) + ) + ); + + xenidc_endpoint_transaction_set_status_lbr + (&probe->transaction, + xenidc_vaddress_create_lbr + (&probe->probe.status, + sizeof(probe->probe.status) + ) + ); + + memset + (&probe->probe.parameters, + 0, sizeof(probe->probe.parameters) + ); + + probe->probe.parameters.header. + transaction_type = + USBIF_TRANSACTION_TYPE_PROBE; + + probe->probe.parameters.port = i + 1; + + memset + (&probe->probe.status, 0, + sizeof(probe->probe.status)); + } else { + xenidc_endpoint_transaction_set_parameters_lbr + (&probe->transaction, + xenidc_vaddress_create_lbr + (&probe->reset.parameters, + sizeof(probe->reset.parameters) + ) + ); + + xenidc_endpoint_transaction_set_status_lbr + (&probe->transaction, + xenidc_vaddress_create_lbr + (&probe->reset.status, + sizeof(probe->reset.status) + ) + ); + + memset + (&probe->reset.parameters, + 0, sizeof(probe->reset.parameters) + ); + + probe->reset.parameters.header. + transaction_type = + USBIF_TRANSACTION_TYPE_RESET; + + probe->reset.parameters.port = i + 1; + + memset + (&probe->reset.status, 0, + sizeof(probe->reset.status)); + } + + xenidc_endpoint_submit_transaction + (&device->endpoint, &probe->transaction); + } + } +} + +static void usbfront_device_probe_all_ports_1(xenidc_callback * callback) +{ + struct usbfront_device_probe_transaction *probe = container_of + (xenidc_endpoint_transaction_callback_to(callback), + struct usbfront_device_probe_transaction, + transaction); + + struct usbfront_device *device = probe->device; + + unsigned long flags; + + spin_lock_irqsave(&device->lock, flags); + + if (probe->probe.parameters.header.transaction_type + == USBIF_TRANSACTION_TYPE_PROBE) { + int port_number = probe->probe.parameters.port; + + if (xenidc_callback_query_error(callback) == + XENIDC_ERROR_SUCCESS) { + struct usb_port_status *port_status = + &device->port_status[port_number - 1]; + + if (probe->probe.status.result + == USBIF_PROBE_RESULT_DEVICE_PRESENT) { + /* There is a device attached to the port. */ + + if ((port_status-> + wPortStatus & USB_PORT_STAT_CONNECTION) + != USB_PORT_STAT_CONNECTION) { + /* There wasn't a device attached to the port before. */ + + port_status->wPortStatus |= + USB_PORT_STAT_CONNECTION; + port_status->wPortChange |= + USB_PORT_STAT_C_CONNECTION; + } + } else if + (probe->probe.status.result == + USBIF_PROBE_RESULT_NO_DEVICE) { + /* There isn't a device attached to the port. */ + + if ((port_status-> + wPortStatus & USB_PORT_STAT_CONNECTION) + == USB_PORT_STAT_CONNECTION) { + /* There was a device attached to the port before. */ + + port_status->wPortStatus &= + ~USB_PORT_STAT_CONNECTION; + port_status->wPortChange |= + USB_PORT_STAT_C_CONNECTION; + } + } else { + trace3 + ("device %p: unexpected result %d probing port %d", + device, + (int)probe->probe.status.result, + port_number); + } + } else { + trace3 + ("device %p: error %d probing port %d", + device, + usbif_error_map_to_local + (xenidc_callback_query_error(callback)), + port_number); + } + } else { + int port_number = probe->reset.parameters.port; + + struct usb_port_status *port_status = + &device->port_status[port_number - 1]; + + if ((xenidc_callback_query_error(callback) == + XENIDC_ERROR_SUCCESS) + && + ((probe->reset.status.result == + USBIF_RESET_RESULT_FULL_SPEED) + || (probe->reset.status.result == + USBIF_RESET_RESULT_LOW_SPEED) + || (probe->reset.status.result == + USBIF_RESET_RESULT_HIGH_SPEED) + ) + ) { + if (probe->reset.status.result == + USBIF_RESET_RESULT_LOW_SPEED) { + port_status->wPortStatus |= + USB_PORT_STAT_LOW_SPEED; + port_status->wPortStatus &= + ~USB_PORT_STAT_HIGH_SPEED; + } else if (probe->reset.status.result == + USBIF_RESET_RESULT_HIGH_SPEED) { + port_status->wPortStatus &= + ~USB_PORT_STAT_LOW_SPEED; + port_status->wPortStatus |= + USB_PORT_STAT_HIGH_SPEED; + } else { + port_status->wPortStatus &= + ~USB_PORT_STAT_LOW_SPEED; + port_status->wPortStatus &= + ~USB_PORT_STAT_HIGH_SPEED; + } + + port_status->wPortStatus &= ~USB_PORT_STAT_RESET; + port_status->wPortStatus |= USB_PORT_STAT_ENABLE; + port_status->wPortChange |= USB_PORT_STAT_C_RESET; + } else { + if (xenidc_callback_query_error(callback) + != XENIDC_ERROR_SUCCESS) { + printk + (KERN_ERR + "usbfront: device %p: error %d resetting port %d", + device, + usbif_error_map_to_local + (xenidc_callback_query_error(callback)), + port_number); + } else { + trace3 + ("device %p: unexpected result %d resetting port %d", + device, + (int)probe->reset.status.result, + port_number); + } + + port_status->wPortStatus &= ~USB_PORT_STAT_LOW_SPEED; + port_status->wPortStatus &= ~USB_PORT_STAT_HIGH_SPEED; + + port_status->wPortStatus &= ~USB_PORT_STAT_RESET; + port_status->wPortChange |= USB_PORT_STAT_C_RESET; + } + } + + if (--device->port_probe_count == 0) { + usbfront_device_handle_stimulus(device, + usbfront_device_stimulus_pc); + } + + spin_unlock_irqrestore(&device->lock, flags); +} + +static void usbfront_device_disconnect_all_ports(struct usbfront_device *device) { + trace(); + + { + int i; + + for (i = 0; i < USBFRONT_DEVICE_PORT_COUNT; i++) { + struct usb_port_status *port_status = + &device->port_status[i]; + + if ((port_status-> + wPortStatus & USB_PORT_STAT_CONNECTION) + == USB_PORT_STAT_CONNECTION) { + /* There was a device attached to the port before. */ + + port_status->wPortStatus &= + ~USB_PORT_STAT_CONNECTION; + port_status->wPortChange |= + USB_PORT_STAT_C_CONNECTION; + } + } + } +} + +static void usbfront_device_complete_endpoint_disconnect + (struct usbfront_device *device) { + trace(); + + xenidc_callback_success(device->endpoint_disconnect_callback); +} diff -r 5a90f01cb37e -r 06d98ed0b6e5 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.h --- /dev/null Mon Nov 21 11:10:19 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.h Mon Nov 21 11:10:40 2005 @@ -0,0 +1,82 @@ +/*****************************************************************************/ +/* usbfront_device is a device which represents a connection to a back-end. */ +/* The intent was for it to have an interface like a hardware USB host */ +/* controller device. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBFRONT_DEVICE_H +#define USBFRONT_DEVICE_H + +#include +#include +#include "../../usb/core/hcd.h" +#include + +extern int usbfront_device_class_init(void); + +extern void usbfront_device_class_exit(void); + +struct usbfront_device; + +void usbfront_device_set_drvdata(struct usbfront_device *device, void *data); + +void *usbfront_device_get_drvdata(struct usbfront_device *device); + +struct device *usbfront_device_to_dev(struct usbfront_device *device); + +struct usbfront_device *usbfront_device_dev_to(struct device *dev); + +int usbfront_device_query_port_count(struct usbfront_device *device); + +int usbfront_device_query_port_status_changed + (struct usbfront_device *device, int port_number); + +struct usb_port_status usbfront_device_query_port_status + (struct usbfront_device *device, int port_number); + +/* Used to turn on power to a port. */ +void usbfront_device_set_port_power + (struct usbfront_device *device, int port_number); + +/* Used to reset a port. Completes asynchronously with notification via the */ +/* port status. */ +void usbfront_device_set_port_reset + (struct usbfront_device *device, int port_number); + +void usbfront_device_clear_port_enable + (struct usbfront_device *device, int port_number); + +/* Used to ack a connection change */ +void usbfront_device_clear_port_connection_change + (struct usbfront_device *device, int port_number); + +/* Used to ack a reset change */ +void usbfront_device_clear_port_reset_change + (struct usbfront_device *device, int port_number); + +void usbfront_device_submit_message + (struct usbfront_device *device, xenidc_endpoint_message * message); + +xenidc_address usbfront_device_query_address(struct usbfront_device *device); + +void usbfront_device_submit_transaction + (struct usbfront_device *device, xenidc_endpoint_transaction * transaction); + +#endif diff -r 5a90f01cb37e -r 06d98ed0b6e5 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.c --- /dev/null Mon Nov 21 11:10:19 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.c Mon Nov 21 11:10:40 2005 @@ -0,0 +1,812 @@ +/*****************************************************************************/ +/* A device driver for usbfront_device devices. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Based on */ +/* */ +/* arch/xen/drivers/usbif/frontend/main.c */ +/* pristine-linux-2.6.11/drivers/usb/host/uhci-hcd.c */ +/* pristine-linux-2.6.11/drivers/usb/core/hcd-pci.c */ +/* */ +/* original copyright notices follow... */ +/*****************************************************************************/ + +/* + * Xen Virtual USB Frontend Driver + * + * This file contains the first version of the Xen virtual USB hub + * that I've managed not to delete by mistake (3rd time lucky!). + * + * Based on Linux's uhci.c, original copyright notices are displayed + * below. Portions also (c) 2004 Intel Research Cambridge + * and (c) 2004, 2005 Mark Williamson + * + * Contact or + * regarding this code. + * + * Still to be (maybe) implemented: + * - migration / backend restart support? + * - support for building / using as a module + */ + +/* + * Universal Host Controller Interface driver for USB. + * + * Maintainer: Johannes Erdfelt + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx + * (C) Copyright 1999 Randy Dunlap + * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx + * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx + * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx + * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx + * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface + * support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx). + * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) + * + * Intel documents this fairly well, and as far as I know there + * are no royalties or anything like that, but even so there are + * people who decided that they want to do the same thing in a + * completely different way. + * + * WARNING! The USB documentation is downright evil. Most of it + * is just crap, written by a committee. You're better off ignoring + * most of it, the important stuff is: + * - the low-level protocol (fairly simple but lots of small details) + * - working around the horridness of the rest + */ + +/* + * Universal Host Controller Interface driver for USB. + * + * Maintainer: Alan Stern + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx + * (C) Copyright 1999 Randy Dunlap + * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx + * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx + * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx + * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx + * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface + * support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx). + * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) + * (C) Copyright 2004 Alan Stern, stern@xxxxxxxxxxxxxxxxxxx + * + * Intel documents this fairly well, and as far as I know there + * are no royalties or anything like that, but even so there are + * people who decided that they want to do the same thing in a + * completely different way. + * + * WARNING! The USB documentation is downright evil. Most of it + * is just crap, written by a committee. You're better off ignoring + * most of it, the important stuff is: + * - the low-level protocol (fairly simple but lots of small details) + * - working around the horridness of the rest + */ + +/* + * (C) Copyright David Brownell 2000-2002 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "usbfront_driver.h" +#include "usbfront_hcd_resource.h" +#include "usbfront_sll.h" +#include "usbfront_trace.h" + +typedef enum { + usbfront_hcd_state_i +} usbfront_hcd_state; + +typedef enum { + usbfront_hcd_stimulus_uq /* urb enqueue */ +} usbfront_hcd_stimulus; + +#define USBFRONT_HCD_RESOURCE_COUNT 16 + +struct usbfront_hcd { + u64 dma_mask; + spinlock_t lock; + usbfront_hcd_state state; + struct usbfront_sll urb_sll; + struct list_head free_resource_list; + struct usbfront_hcd_resource resources[USBFRONT_HCD_RESOURCE_COUNT]; +}; + +static void usbfront_hcd_handle_stimulus + (struct usbfront_hcd *uhcd, usbfront_hcd_stimulus stimulus); + +static struct usbfront_hcd *usbfront_hcd_hcd_to_uhcd(struct usb_hcd *hcd) +{ + return (struct usbfront_hcd *)(hcd->hcd_priv); +} + +static struct usbfront_device *usbfront_hcd_hcd_to_usbfront_device(struct + usb_hcd *hcd) +{ + return usbfront_device_dev_to(hcd_to_bus(hcd)->controller); +} + +void usbfront_hcd_resource_completed(xenidc_callback * callback); + +static int usbfront_hcd_start(struct usb_hcd *hcd) +{ + trace(); + + { + int return_value = 0; + + struct usbfront_hcd *uhcd = usbfront_hcd_hcd_to_uhcd(hcd); + + memset(uhcd, 0, sizeof(*uhcd)); +#if 0 + /* FIXME: This bit of dma_mask manipulation is to trick the USB hcd */ + /* code into giving us buffers allocated using dma_alloc_coherent. */ + /* Which is necessary to allow the BE to map them using */ + /* dma_map_single. This is unclean in so many different ways. */ + + uhcd->dma_mask = 0xffffffffffffffffULL; + + { + struct device *dev = usbfront_device_to_dev + (usbfront_hcd_hcd_to_usbfront_device(hcd)); + + dev->dma_mask = &uhcd->dma_mask; + + dev->coherent_dma_mask = uhcd->dma_mask; + } +#endif + spin_lock_init(&uhcd->lock); + + uhcd->state = usbfront_hcd_state_i; + + usbfront_sll_init(&uhcd->urb_sll); + + INIT_LIST_HEAD(&uhcd->free_resource_list); + + { + int i; + + for (i = 0; i < USBFRONT_HCD_RESOURCE_COUNT; i++) { + struct usbfront_hcd_resource *resource = + &uhcd->resources[i]; + + return_value = usbfront_hcd_resource_init + (resource, + usbfront_hcd_hcd_to_usbfront_device(hcd), + i, usbfront_hcd_resource_completed); + + if (return_value != 0) { + trace0 + ("usbfront_hcd_resource_init failed"); + + goto EXIT_NO_RESOURCE; + } + + list_add + (usbfront_hcd_resource_to_link(resource), + &uhcd->free_resource_list); + } + } + + { + struct usb_device *root_hub_device = + usb_alloc_dev(NULL, &hcd->self, 0); + + if (root_hub_device == NULL) { + trace0("usb_alloc_dev failed"); + + return_value = -ENOMEM; + + goto EXIT_NO_ROOT_HUB; + } + + root_hub_device->speed = USB_SPEED_HIGH; + + hcd->state = HC_STATE_RUNNING; /* FIXME: breaks encapsulation */ + + if ((return_value = + usb_hcd_register_root_hub(root_hub_device, hcd) + ) + != 0) { + trace0("usb_hcd_register_root_hub failed"); + + goto EXIT_NO_REGISTER; + } + + return 0; + + EXIT_NO_REGISTER: + + usb_put_dev(root_hub_device); + } + + EXIT_NO_ROOT_HUB: + + EXIT_NO_RESOURCE: + + while (!list_empty(&uhcd->free_resource_list)) { + struct usbfront_hcd_resource *resource = list_entry + (uhcd->free_resource_list.next, + struct usbfront_hcd_resource, + USBFRONT_HCD_RESOURCE_LINK); + + list_del_init(usbfront_hcd_resource_to_link(resource)); + + usbfront_hcd_resource_exit(resource); + } + + return return_value; + } +} + +static void usbfront_hcd_stop(struct usb_hcd *hcd) +{ + trace(); + + { + struct usbfront_hcd *uhcd = usbfront_hcd_hcd_to_uhcd(hcd); + + while (!list_empty(&uhcd->free_resource_list)) { + struct usbfront_hcd_resource *resource = list_entry + (uhcd->free_resource_list.next, + struct usbfront_hcd_resource, + USBFRONT_HCD_RESOURCE_LINK); + + list_del_init(usbfront_hcd_resource_to_link(resource)); + + usbfront_hcd_resource_exit(resource); + } + } +} + +static int usbfront_hcd_get_frame_number(struct usb_hcd *hcd) +{ + trace(); + + return 0; +} + +static inline void usbfront_check_contiguous + (unsigned long buffer, unsigned long length) { + if (length != 0) { + unsigned long offset; + + for (offset = 0; + offset < (length + (buffer & ~PAGE_MASK)); + offset += PAGE_SIZE) { + unsigned long maddress1 = + virt_to_machine((buffer & PAGE_MASK) + offset); + + unsigned long maddress2 = + virt_to_machine(buffer & PAGE_MASK) + offset; + + ASSERT(maddress1 == maddress2); + } + } +} + +static int usbfront_hcd_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, /* FIXME: what's the intended use for ep? */ + struct urb *urb, int mem_flags) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + usbfront_check_contiguous + ((unsigned long)urb->transfer_buffer, urb->transfer_buffer_length); + + { + struct usbfront_hcd *uhcd = usbfront_hcd_hcd_to_uhcd(hcd); + + unsigned long flags; + + spin_lock_irqsave(&uhcd->lock, flags); + + usbfront_slk_init((struct usbfront_slk *)&urb->hcpriv); + + usbfront_sll_add_last + (&uhcd->urb_sll, (struct usbfront_slk *)&urb->hcpriv); + + usbfront_hcd_handle_stimulus(uhcd, usbfront_hcd_stimulus_uq); + + spin_unlock_irqrestore(&uhcd->lock, flags); + } + + return 0; +} + +static int usbfront_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +{ + trace(); + + { + int dequeued; + + { + struct usbfront_hcd *uhcd = + usbfront_hcd_hcd_to_uhcd(hcd); + + unsigned long flags; + + spin_lock_irqsave(&uhcd->lock, flags); + + dequeued = usbfront_sll_remove_slk + (&uhcd->urb_sll, + (struct usbfront_slk *)&urb->hcpriv); + + spin_unlock_irqrestore(&uhcd->lock, flags); + } + + if (dequeued) { + urb->hcpriv = 0; + + urb->actual_length = 0; + + { + unsigned long flags; + + local_irq_save(flags); + + usb_hcd_giveback_urb(hcd, urb, 0); + + local_irq_restore(flags); + } + } else { + usbfront_hcd_resource_dequeue_urb(urb); + } + } + + return 0; +} + +static void usbfront_hcd_endpoint_disable + (struct usb_hcd *hcd, struct usb_host_endpoint *ep) { + trace(); +} + +static int usbfront_hcd_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + int changed = 0; + + struct usbfront_device *device = + usbfront_hcd_hcd_to_usbfront_device(hcd); + + int port_count = usbfront_device_query_port_count(device); + + int byte_count = + (1 /* hub */ + port_count /* ports */ + 7 /* round up */ ) / 8; + + memset(buf, 0, byte_count); + + { + int i; + + for (i = 1; i <= port_count; i++) { + if (usbfront_device_query_port_status_changed + (device, i)) { + buf[i / 8] |= 1 << (i % 8); + + changed = 1; + } + } + } + + return changed ? byte_count : 0; +} + +static int usbfront_hcd_hub_control + (struct usb_hcd *hcd, + u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { + trace(); + + { + struct usbfront_device *device = + usbfront_hcd_hcd_to_usbfront_device(hcd); + + int return_value = 0; + + switch (typeReq) { + case GetHubStatus: + + trace0("GetHubStatus"); + + if ((wValue != 0) || (wIndex != 0) || (wLength != 4)) { + goto ERROR; + } + + /* 2 bytes wHubStatus and 2 bytes wHubChange: */ + /* Local power supply good, no overcurrect condition */ + /* No changes. */ + + memset(buf, 0, wLength); + + break; + + case GetPortStatus: + + trace0("GetPortStatus"); + + if ((wValue != 0) + || + (wIndex > usbfront_device_query_port_count(device)) + || (wLength != 4) + ) { + goto ERROR; + } + + { + struct usb_port_status port_status = + usbfront_device_query_port_status(device, + wIndex); + + memcpy(buf, &port_status, wLength); + } + + break; + + case GetHubDescriptor: + + trace0("GetHubDescriptor"); + + { + /* bDescLength */ + /* bDescriptorType */ + /* bNbrPorts */ + /* wHubCharacteristics LSB */ + /* wHubCharacteristics MSB */ + /* bPwrOn2PwrGood */ + /* bHubContrCurrent */ + /* DeviceRemovable */ + /* PortPwrCtrlMask */ + + /* See table 11.23.2.1 of the USB 2.0 specification. */ + + char descriptor[] = + { 0x09, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0xFF }; + + descriptor[2] = + usbfront_device_query_port_count(device); + + memcpy + (buf, + &descriptor, + min_t(size_t, sizeof(descriptor), wLength) + ); + } + + break; + + case SetPortFeature: + + trace0("SetPortFeature"); + + if (((wIndex & 0x00FF) + > usbfront_device_query_port_count(device) + ) + || (wLength != 0) + ) { + goto ERROR; + } + + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + trace0("USB_PORT_FEAT_SUSPEND"); + break; + case USB_PORT_FEAT_RESET: + trace0("USB_PORT_FEAT_RESET"); + usbfront_device_set_port_reset(device, wIndex); + break; + case USB_PORT_FEAT_POWER: + trace0("USB_PORT_FEAT_POWER"); + usbfront_device_set_port_power(device, wIndex); + break; + default: + trace1("Unknown:%x", wValue); + goto ERROR; + } + + break; + + case ClearPortFeature: + + trace0("ClearPortFeature"); + + if (((wIndex & 0x00FF) + > usbfront_device_query_port_count(device) + ) + || (wLength != 0) + ) { + goto ERROR; + } + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + trace0("USB_PORT_FEAT_ENABLE"); + usbfront_device_clear_port_enable(device, + wIndex); + break; + case USB_PORT_FEAT_SUSPEND: + trace0("USB_PORT_FEAT_SUSPEND"); + break; + case USB_PORT_FEAT_POWER: + trace0("USB_PORT_FEAT_POWER"); + break; + case USB_PORT_FEAT_INDICATOR: + trace0("USB_PORT_FEAT_INDICATOR"); + break; + case USB_PORT_FEAT_C_CONNECTION: + trace0("USB_PORT_C_CONNECTION"); + usbfront_device_clear_port_connection_change + (device, wIndex); + break; + case USB_PORT_FEAT_C_RESET: + trace0("USB_PORT_C_RESET"); + usbfront_device_clear_port_reset_change(device, + wIndex); + break; + case USB_PORT_FEAT_C_ENABLE: + trace0("USB_PORT_C_ENABLE"); + break; + case USB_PORT_FEAT_C_SUSPEND: + trace0("USB_PORT_C_SUSPEND"); + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + trace0("USB_PORT_C_OVER_CURRENT"); + break; + default: + trace1("Unknown:%x", wValue); + goto ERROR; + } + + break; + + default: + trace1("Unknown:%x", typeReq); + ERROR: + return_value = -EPIPE; + } + + return return_value; + } +} + +static int usbfront_hcd_start_port_reset(struct usb_hcd *hcd, unsigned port_num) { + trace(); + + return 0; +} + +static struct hc_driver usbfront_hc_driver = { + .description = "usbfront_hc_driver", + .product_desc = "Xen USB Front-End Driver", + .hcd_priv_size = sizeof(struct usbfront_hcd), + /* .irq */ + .flags = HCD_USB2, + /* reset optional. */ + .start = usbfront_hcd_start, + /* suspend optional. */ + /* resume optional. */ + .stop = usbfront_hcd_stop, + .get_frame_number = usbfront_hcd_get_frame_number, + .urb_enqueue = usbfront_hcd_urb_enqueue, + .urb_dequeue = usbfront_hcd_urb_dequeue, + .endpoint_disable = usbfront_hcd_endpoint_disable, + .hub_status_data = usbfront_hcd_hub_status_data, + .hub_control = usbfront_hcd_hub_control, + /* hub_suspend optional. */ + /* hub_resume optional. */ + .start_port_reset = usbfront_hcd_start_port_reset, +}; + +static void usbfront_hcd_invalid_stimulus + (struct usbfront_hcd *uhcd, usbfront_hcd_stimulus stimulus); + +static void usbfront_hcd_kick_urbs(struct usbfront_hcd *uhcd); + +static void usbfront_hcd_handle_stimulus + (struct usbfront_hcd *uhcd, usbfront_hcd_stimulus stimulus) { + trace3 + ("uhcd %p in state %d received stimulus %d", + uhcd, uhcd->state, stimulus); + + switch (uhcd->state) { + case usbfront_hcd_state_i: + switch (stimulus) { + case usbfront_hcd_stimulus_uq: + usbfront_hcd_kick_urbs(uhcd); + break; + } + break; + default: + usbfront_hcd_invalid_stimulus(uhcd, stimulus); + break; + } +} + +static void usbfront_hcd_invalid_stimulus + (struct usbfront_hcd *uhcd, usbfront_hcd_stimulus stimulus) { + trace(); + + printk + (KERN_ERR "usbfront: hc_driver_uhcd %p in state %d" + "received invalid stimulus %d", uhcd, uhcd->state, stimulus); +} + +static void usbfront_hcd_kick_urbs(struct usbfront_hcd *uhcd) +{ + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + while (!usbfront_sll_is_empty(&uhcd->urb_sll) + && !list_empty(&uhcd->free_resource_list) + ) { + trace0("Starting URB"); + + { + struct urb *urb = container_of + ((void **)usbfront_sll_remove_first(&uhcd->urb_sll), + struct urb, + hcpriv); + + struct usbfront_hcd_resource *resource = list_entry + (uhcd->free_resource_list.next, + struct usbfront_hcd_resource, + USBFRONT_HCD_RESOURCE_LINK); + + list_del_init(usbfront_hcd_resource_to_link(resource)); + + usbfront_hcd_resource_start_urb(resource, urb); + } + } +} + +void usbfront_hcd_resource_completed(xenidc_callback * callback) +{ + trace(); + + { + struct usbfront_hcd_resource *resource = + usbfront_hcd_resource_callback_to(callback); + + struct usbfront_hcd *uhcd = usbfront_hcd_hcd_to_uhcd + (usbfront_device_get_drvdata + (usbfront_hcd_resource_query_device(resource)) + ); + + unsigned long flags; + + spin_lock_irqsave(&uhcd->lock, flags); + + list_add + (usbfront_hcd_resource_to_link(resource), + &uhcd->free_resource_list); + + usbfront_hcd_kick_urbs(uhcd); + + spin_unlock_irqrestore(&uhcd->lock, flags); + } +} + +static int usbfront_driver_probe_or_remove + (struct usbfront_device *device, int remove) { + trace(); + + { + int return_value = 0; + + struct usb_hcd *hcd; + + if (remove) { + goto REMOVE; + } + + if (usb_disabled()) { + return_value = -ENODEV; + + goto REMOVE_0; + } + + if ((hcd = usb_create_hcd + (&usbfront_hc_driver, + usbfront_device_to_dev(device), + usbfront_device_to_dev(device)->bus_id) + ) + == NULL) { + trace0("usb_create_hcd failed"); + + return_value = -ENOMEM; + + goto REMOVE_0; + } + + usbfront_device_set_drvdata(device, hcd); + + if ((return_value = usb_add_hcd(hcd, 0, 0)) != 0) { + trace0("usb_add_hcd failed"); + + goto REMOVE_1; + } + + return 0; + + REMOVE: + + hcd = usbfront_device_get_drvdata(device); + + usb_remove_hcd(hcd); + + REMOVE_1: + + usb_put_hcd(hcd); + + usbfront_device_set_drvdata(device, NULL); + + REMOVE_0: + + return return_value; + } +} + +int usbfront_driver_probe(struct usbfront_device *device) +{ + trace(); + + return usbfront_driver_probe_or_remove(device, 0); +} + +void usbfront_driver_remove(struct usbfront_device *device) +{ + trace(); + + usbfront_driver_probe_or_remove(device, 1); +} + +int usbfront_driver_class_init(void) +{ + trace(); + + return usbfront_hcd_resource_class_init(); +} + +void usbfront_driver_class_exit(void) +{ + trace(); + + usbfront_hcd_resource_class_exit(); +} diff -r 5a90f01cb37e -r 06d98ed0b6e5 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.h --- /dev/null Mon Nov 21 11:10:19 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.h Mon Nov 21 11:10:40 2005 @@ -0,0 +1,35 @@ +/*****************************************************************************/ +/* A device driver for usbfront_device devices. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBFRONT_DRIVER_H +#define USBFRONT_DRIVER_H + +#include "usbfront_device.h" + +extern int usbfront_driver_class_init(void); + +extern void usbfront_driver_class_exit(void); + +extern int usbfront_driver_probe(struct usbfront_device *device); + +extern void usbfront_driver_remove(struct usbfront_device *device); + +#endif diff -r 5a90f01cb37e -r 06d98ed0b6e5 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.c --- /dev/null Mon Nov 21 11:10:19 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.c Mon Nov 21 11:10:40 2005 @@ -0,0 +1,915 @@ +/*****************************************************************************/ +/* A resource used by the usbfront host controller device driver to process */ +/* an URB by translating the URB and optional unlink request into */ +/* a transaction and corresponding optional unlink message for submission to */ +/* the back end. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* Based on arch/xen/drivers/usbif/frontend/main.c, original copyright */ +/* notice follows... */ +/*****************************************************************************/ + +/* + * Xen Virtual USB Frontend Driver + * + * This file contains the first version of the Xen virtual USB hub + * that I've managed not to delete by mistake (3rd time lucky!). + * + * Based on Linux's uhci.c, original copyright notices are displayed + * below. Portions also (c) 2004 Intel Research Cambridge + * and (c) 2004, 2005 Mark Williamson + * + * Contact or + * regarding this code. + * + * Still to be (maybe) implemented: + * - migration / backend restart support? + * - support for building / using as a module + */ + +/* + * Universal Host Controller Interface driver for USB. + * + * Maintainer: Johannes Erdfelt + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@xxxxxxxxxxx + * (C) Copyright 1999 Randy Dunlap + * (C) Copyright 1999 Georg Acher, acher@xxxxxxxxx + * (C) Copyright 1999 Deti Fliegl, deti@xxxxxxxxx + * (C) Copyright 1999 Thomas Sailer, sailer@xxxxxxxxxxxxxx + * (C) Copyright 1999 Roman Weissgaerber, weissg@xxxxxxxxx + * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface + * support from usb-ohci.c by Adam Richter, adam@xxxxxxxxxxxxx). + * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) + * + * Intel documents this fairly well, and as far as I know there + * are no royalties or anything like that, but even so there are + * people who decided that they want to do the same thing in a + * completely different way. + * + * WARNING! The USB documentation is downright evil. Most of it + * is just crap, written by a committee. You're better off ignoring + * most of it, the important stuff is: + * - the low-level protocol (fairly simple but lots of small details) + * - working around the horridness of the rest + */ + +#include +#include "usbfront_assert.h" +#include "usbfront_driver.h" +#include "usbfront_hcd_resource.h" +#include "usbfront_trace.h" + +xenidc_rbr_provider_pool *usbfront_hcd_resource_rbr_provider_pool; + +int usbfront_hcd_resource_class_init(void) +{ + trace(); + + { + xenidc_buffer_resource_list sum = + xenidc_buffer_resource_list_null(); + + xenidc_buffer_resource_list bulk_list = + xenidc_vaddress_calculate_buffer_resource_list + (USBIF_MAX_BULK_BYTE_COUNT, USBIF_BULK_BYTE_ALIGNMENT); + + xenidc_buffer_resource_list schedule_list = + xenidc_vaddress_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); + + usbfront_hcd_resource_rbr_provider_pool = + xenidc_allocate_rbr_provider_pool(sum); + } + + return (usbfront_hcd_resource_rbr_provider_pool != NULL) ? 0 : -ENOMEM; +} + +void usbfront_hcd_resource_class_exit(void) +{ + trace(); + + xenidc_free_rbr_provider_pool(usbfront_hcd_resource_rbr_provider_pool); +} + +typedef enum { + usbfront_hcd_resource_stimulus_st, /* Start URB */ + usbfront_hcd_resource_stimulus_dq, /* Dequeue URB */ + usbfront_hcd_resource_stimulus_cs, /* Create RBRs success */ + usbfront_hcd_resource_stimulus_cf, /* Create RBRs failure */ + usbfront_hcd_resource_stimulus_tc, /* Transaction complete */ + usbfront_hcd_resource_stimulus_rc, /* Revoke RBRs complete */ + usbfront_hcd_resource_stimulus_uc, /* Unlink complete */ +} usbfront_hcd_resource_stimulus; + +static void usbfront_hcd_resource_handle_stimulus + (struct usbfront_hcd_resource *resource, + usbfront_hcd_resource_stimulus stimulus); + +static void usbfront_hcd_resource_create_rbrs_1(xenidc_callback * callback); + +static void usbfront_hcd_resource_submit_transaction_1 + (xenidc_callback * callback); + +static void usbfront_hcd_resource_revoke_rbrs_1(xenidc_callback * callback); + +static void usbfront_hcd_resource_submit_unlink_1(xenidc_callback * callback); + +static void usbfront_hcd_resource_complete_1(void *context); + +static int usbfront_hcd_resource_init_or_exit + (struct usbfront_hcd_resource *resource, + struct usbfront_device *device, + int index, xenidc_callback_function * callback, int exit) { + trace(); + + { + int return_value = 0; + + if (exit) { + goto EXIT; + } + + xenidc_callback_init(&resource->callback, callback); + + resource->device = device; + + resource->index = index; + + resource->schedule = (usbif_isochronous_io_schedule_element *) + __get_free_page(GFP_KERNEL); + + if (resource->schedule == NULL) { + return_value = -ENOMEM; + + goto EXIT_NO_SCHEDULE; + } + + spin_lock_init(&resource->lock); + + resource->state = usbfront_hcd_resource_state_i; + + xenidc_create_rbr_request_element_init + (&resource->rbr_request_element[0]); + + xenidc_create_rbr_request_element_init + (&resource->rbr_request_element[1]); + + xenidc_reserve_and_create_rbr_request_init + (&resource->rbr_request, + usbfront_hcd_resource_create_rbrs_1, + usbfront_hcd_resource_revoke_rbrs_1); + + xenidc_endpoint_transaction_init + (&resource->io_transaction, + usbfront_hcd_resource_submit_transaction_1); + + xenidc_endpoint_transaction_set_parameters_lbr + (&resource->io_transaction, + xenidc_vaddress_create_lbr + (&resource->io_parameters, sizeof(resource->io_parameters) + ) + ); + + xenidc_endpoint_transaction_set_status_lbr + (&resource->io_transaction, + xenidc_vaddress_create_lbr + (&resource->io_status, sizeof(resource->io_status) + ) + ); + + xenidc_endpoint_message_init + (&resource->unlink_message, + usbfront_hcd_resource_submit_unlink_1); + + xenidc_endpoint_message_set_message_lbr + (&resource->unlink_message, + xenidc_vaddress_create_lbr + (&resource->unlink_message_body, + sizeof(resource->unlink_message_body) + ) + ); + + xenidc_work_init + (&resource->complete_1_work, + usbfront_hcd_resource_complete_1, resource); + + return 0; + + EXIT: + + free_page((unsigned long)resource->schedule); + + EXIT_NO_SCHEDULE: + + return return_value; + } +} + +int usbfront_hcd_resource_init + (struct usbfront_hcd_resource *resource, + struct usbfront_device *device, + int index, xenidc_callback_function * callback) { + trace(); + + return usbfront_hcd_resource_init_or_exit + (resource, device, index, callback, 0); +} + +void usbfront_hcd_resource_exit(struct usbfront_hcd_resource *resource) +{ + trace(); + + usbfront_hcd_resource_init_or_exit(resource, NULL, 0, NULL, 1); +} + +void usbfront_hcd_resource_start_urb + (struct usbfront_hcd_resource *resource, struct urb *urb) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + urb->hcpriv = resource; + + { + unsigned long flags; + + spin_lock_irqsave(&resource->lock, flags); + + resource->urb = urb; + + usbfront_hcd_resource_handle_stimulus + (resource, usbfront_hcd_resource_stimulus_st); + + spin_unlock_irqrestore(&resource->lock, flags); + } +} + +static DEFINE_RWLOCK(dequeue_lock); + +void usbfront_hcd_resource_dequeue_urb(struct urb *urb) +{ + trace(); + + { + unsigned long flags; + + write_lock_irqsave(&dequeue_lock, flags); + + if (urb->hcpriv != NULL) { + struct usbfront_hcd_resource *resource = + (struct usbfront_hcd_resource *)urb->hcpriv; + + unsigned long flags2; + + spin_lock_irqsave(&resource->lock, flags2); + + usbfront_hcd_resource_handle_stimulus + (resource, usbfront_hcd_resource_stimulus_dq); + + spin_unlock_irqrestore(&resource->lock, flags2); + } + + write_unlock_irqrestore(&dequeue_lock, flags); + } +} + +static void usbfront_hcd_resource_invalid_stimulus + (struct usbfront_hcd_resource *resource, + usbfront_hcd_resource_stimulus stimulus); + +static void usbfront_hcd_resource_create_rbrs + (struct usbfront_hcd_resource *resource); + +static void usbfront_hcd_resource_abort_create_rbrs + (struct usbfront_hcd_resource *resource); + +static void usbfront_hcd_resource_set_unlinked_error + (struct usbfront_hcd_resource *resource); + +static void usbfront_hcd_resource_submit_transaction + (struct usbfront_hcd_resource *resource); + +static void usbfront_hcd_resource_revoke_rbrs + (struct usbfront_hcd_resource *resource); + +static void usbfront_hcd_resource_submit_unlink + (struct usbfront_hcd_resource *resource); + +static void usbfront_hcd_resource_complete + (struct usbfront_hcd_resource *resource); + +static void usbfront_hcd_resource_handle_stimulus + (struct usbfront_hcd_resource *resource, + usbfront_hcd_resource_stimulus stimulus) { + trace(); + + switch (resource->state) { + case usbfront_hcd_resource_state_i: + /* Initialised. */ + /* Maybe completing previous URB. */ + switch (stimulus) { + case usbfront_hcd_resource_stimulus_st: + resource->state = usbfront_hcd_resource_state_i_st; + usbfront_hcd_resource_create_rbrs(resource); + break; + /* A dequeue is possible whilst we are making the complete */ + /* response after we have transitioned back to the i state. */ + case usbfront_hcd_resource_stimulus_dq: + break; + default: + usbfront_hcd_resource_invalid_stimulus(resource, + stimulus); + break; + } + break; + case usbfront_hcd_resource_state_i_st: + /* Creating RBRs. */ + switch (stimulus) { + case usbfront_hcd_resource_stimulus_dq: + resource->state = usbfront_hcd_resource_state_i_st_dq; + usbfront_hcd_resource_abort_create_rbrs(resource); + break; + case usbfront_hcd_resource_stimulus_cs: + resource->state = usbfront_hcd_resource_state_i_st_cs; + usbfront_hcd_resource_submit_transaction(resource); + break; + case usbfront_hcd_resource_stimulus_cf: + resource->state = usbfront_hcd_resource_state_i; + usbfront_hcd_resource_complete(resource); + break; + default: + usbfront_hcd_resource_invalid_stimulus(resource, + stimulus); + break; + } + break; + case usbfront_hcd_resource_state_i_st_dq: + /* Creating RBRs. */ + /* Dequeue URB. */ + switch (stimulus) { + case usbfront_hcd_resource_stimulus_dq: + break; + case usbfront_hcd_resource_stimulus_cs: + resource->state = + usbfront_hcd_resource_state_i_st_dq_cs; + usbfront_hcd_resource_set_unlinked_error(resource); + usbfront_hcd_resource_revoke_rbrs(resource); + break; + case usbfront_hcd_resource_stimulus_cf: + resource->state = usbfront_hcd_resource_state_i; + usbfront_hcd_resource_complete(resource); + break; + default: + usbfront_hcd_resource_invalid_stimulus(resource, + stimulus); + break; + } + break; + case usbfront_hcd_resource_state_i_st_cs: + /* Transaction submitted. */ + switch (stimulus) { + case usbfront_hcd_resource_stimulus_dq: + resource->state = + usbfront_hcd_resource_state_i_st_cs_dq; + usbfront_hcd_resource_submit_unlink(resource); + break; + case usbfront_hcd_resource_stimulus_tc: + resource->state = + usbfront_hcd_resource_state_i_st_dq_cs; + usbfront_hcd_resource_revoke_rbrs(resource); + break; + default: + usbfront_hcd_resource_invalid_stimulus(resource, + stimulus); + break; + } + break; + case usbfront_hcd_resource_state_i_st_dq_cs: + /* Revoking RBRs. */ + /* Maybe Dequeue URB. */ + switch (stimulus) { + case usbfront_hcd_resource_stimulus_dq: + break; + case usbfront_hcd_resource_stimulus_rc: + resource->state = usbfront_hcd_resource_state_i; + usbfront_hcd_resource_complete(resource); + break; + default: + usbfront_hcd_resource_invalid_stimulus(resource, + stimulus); + break; + } + break; + case usbfront_hcd_resource_state_i_st_cs_dq: + /* Transaction submitted. */ + /* Unlink submitted. */ + /* Dequeue URB. */ + switch (stimulus) { + case usbfront_hcd_resource_stimulus_dq: + break; + case usbfront_hcd_resource_stimulus_tc: + case usbfront_hcd_resource_stimulus_uc: + resource->state = + usbfront_hcd_resource_state_i_st_cs_dq_tc; + break; + default: + usbfront_hcd_resource_invalid_stimulus(resource, + stimulus); + break; + } + break; + case usbfront_hcd_resource_state_i_st_cs_dq_tc: + /* Transaction submitted or Unlink submitted. */ + /* Dequeue URB. */ + switch (stimulus) { + case usbfront_hcd_resource_stimulus_dq: + break; + case usbfront_hcd_resource_stimulus_tc: + case usbfront_hcd_resource_stimulus_uc: + resource->state = + usbfront_hcd_resource_state_i_st_dq_cs; + usbfront_hcd_resource_revoke_rbrs(resource); + break; + default: + usbfront_hcd_resource_invalid_stimulus(resource, + stimulus); + break; + } + break; + default: + usbfront_hcd_resource_invalid_stimulus(resource, stimulus); + break; + } +} + +static void usbfront_hcd_resource_invalid_stimulus + (struct usbfront_hcd_resource *resource, + usbfront_hcd_resource_stimulus stimulus) { + trace(); + + printk + (KERN_ERR "usbfront: hcd resource %p in state %d" + "received invalid stimulus %d", + resource, resource->state, stimulus); +} + +static void usbfront_hcd_resource_create_rbrs + (struct usbfront_hcd_resource *resource) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + xenidc_create_rbr_request_element_ensure_removed + (&resource->rbr_request_element[0]); + + xenidc_create_rbr_request_element_ensure_removed + (&resource->rbr_request_element[1]); + + xenidc_create_rbr_request_element_set_lbr + (&resource->rbr_request_element[0], + xenidc_vaddress_create_lbr + (resource->urb->transfer_buffer, + resource->urb->transfer_buffer_length), + usb_pipein(resource->urb->pipe) ? + XENIDC_CREATE_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_WRITE : + XENIDC_CREATE_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_READ); + + xenidc_reserve_and_create_rbr_request_add_element + (&resource->rbr_request, &resource->rbr_request_element[0] + ); + + if (usb_pipetype(resource->urb->pipe) == PIPE_ISOCHRONOUS) { + if (resource->urb->number_of_packets + > + (PAGE_SIZE / sizeof(usbif_isochronous_io_schedule_element)) + ) { + goto SCHEDULE_TOO_BIG; + } + + { + usbif_isochronous_io_schedule_element *element = + resource->schedule; + + int i; + + for (i = 0; i < resource->urb->number_of_packets; i++) { + memset(&element[i], 0, sizeof(element[i])); + + element[i].offset = + resource->urb->iso_frame_desc[i].offset; + element[i].length = + resource->urb->iso_frame_desc[i].length; + } + } + + xenidc_create_rbr_request_element_set_lbr + (&resource->rbr_request_element[1], + xenidc_vaddress_create_lbr + (resource->schedule, + sizeof(usbif_isochronous_io_schedule_element) + * + resource->urb->number_of_packets), + XENIDC_CREATE_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_WRITE | + XENIDC_CREATE_RBR_REQUEST_ELEMENT_ACCESS_FLAGS_READ); + + xenidc_reserve_and_create_rbr_request_add_element + (&resource->rbr_request, &resource->rbr_request_element[1] + ); + } + + xenidc_rbr_provider_pool_reserve_and_create_rbrs + (usbfront_hcd_resource_rbr_provider_pool, + &resource->rbr_request, + usbfront_device_query_address(resource->device) + ); + + return; + + SCHEDULE_TOO_BIG: + + xenidc_callback_complete + (xenidc_reserve_and_create_rbr_request_to_create_callback + (&resource->rbr_request), XENIDC_ERROR_TOO_BIG); +} + +static void usbfront_hcd_resource_create_rbrs_1(xenidc_callback * callback) +{ + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + { + struct usbfront_hcd_resource *resource = container_of + (xenidc_reserve_and_create_rbr_request_create_callback_to + (callback), + struct usbfront_hcd_resource, + rbr_request); + + unsigned long flags; + + spin_lock_irqsave(&resource->lock, flags); + + if (xenidc_callback_query_error(callback) == + XENIDC_ERROR_SUCCESS) { + usbfront_hcd_resource_handle_stimulus(resource, + usbfront_hcd_resource_stimulus_cs); + } else { + usbfront_hcd_resource_handle_stimulus + (resource, usbfront_hcd_resource_stimulus_cf); + } + + spin_unlock_irqrestore(&resource->lock, flags); + } +} + +static void usbfront_hcd_resource_abort_create_rbrs + (struct usbfront_hcd_resource *resource) { + trace(); + + xenidc_rbr_provider_pool_abort_reserve_and_create_rbrs + (&resource->rbr_request, USBIF_XENIDC_ERROR_UNLINKED); +} + +static void usbfront_hcd_resource_set_unlinked_error + (struct usbfront_hcd_resource *resource) { + trace(); + + xenidc_callback_set_error + (xenidc_reserve_and_create_rbr_request_to_create_callback + (&resource->rbr_request), USBIF_XENIDC_ERROR_UNLINKED); +} + +static void usbfront_hcd_resource_submit_transaction + (struct usbfront_hcd_resource *resource) { + trace(); + + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + + memset(&resource->io_parameters, 0, sizeof(resource->io_parameters)); + memset(&resource->io_status, 0, sizeof(resource->io_status)); + + resource->io_parameters.header.header.transaction_type = + USBIF_TRANSACTION_TYPE_IO; + + { + struct urb *urb = resource->urb; + + resource->io_parameters.header.device_number = + usb_pipedevice(urb->pipe); + + resource->io_parameters.header.endpoint = + usb_pipeendpoint(urb->pipe); + + resource->io_parameters.header.direction = + usb_pipein(urb-> + pipe) ? USBIF_IO_TRANSACTION_DIRECTION_IN : + USBIF_IO_TRANSACTION_DIRECTION_OUT; + + resource->io_parameters.header.unlink_id = resource->index; + + if (urb->transfer_flags & URB_SHORT_NOT_OK) { + resource->io_parameters.header.flags |= + USBIF_IO_FLAGS_SHORT_NOT_OK; + } + if (urb->transfer_flags & URB_ZERO_PACKET) { + resource->io_parameters.header.flags |= + USBIF_IO_FLAGS_ZERO_PACKET; + } + + resource->io_parameters.header.rbr = + xenidc_create_rbr_request_element_query_rbr + (&resource->rbr_request_element[0]); + + if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { + resource->io_parameters.header.io_transaction_type = + USBIF_IO_TRANSACTION_TYPE_CONTROL; + + ASSERT(urb->setup_packet != NULL); + + memcpy + (resource->io_parameters.control.setup, + urb->setup_packet, 8); + + trace0("control URB"); + + trace1("setup[0]:%x", + (int)resource->io_parameters.control.setup[0]); + trace1("setup[1]:%x", + (int)resource->io_parameters.control.setup[1]); + trace1("setup[2]:%x", + (int)resource->io_parameters.control.setup[2]); + trace1("setup[3]:%x", + (int)resource->io_parameters.control.setup[3]); + trace1("setup[4]:%x", + (int)resource->io_parameters.control.setup[4]); + trace1("setup[5]:%x", + (int)resource->io_parameters.control.setup[5]); + trace1("setup[6]:%x", + (int)resource->io_parameters.control.setup[6]); + trace1("setup[7]:%x", + (int)resource->io_parameters.control.setup[7]); + } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { + resource->io_parameters.header.io_transaction_type = + USBIF_IO_TRANSACTION_TYPE_BULK; + + trace0("bulk URB"); + } else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { + resource->io_parameters.header.io_transaction_type = + USBIF_IO_TRANSACTION_TYPE_INTERRUPT; + + resource->io_parameters.interrupt.interval = + urb->interval; + + trace0("interrupt URB"); + + trace1("interval:%d", + resource->io_parameters.interrupt.interval); + } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + resource->io_parameters.header.io_transaction_type = + USBIF_IO_TRANSACTION_TYPE_ISOCHRONOUS; + + resource->io_parameters.isochronous.interval = + urb->interval; + + resource->io_parameters.isochronous.schedule_rbr = + xenidc_create_rbr_request_element_query_rbr + (&resource->rbr_request_element[1]); + + resource->io_parameters.isochronous.packet_count = + urb->number_of_packets; + + trace0("isochronous URB"); + + trace1("interval:%d", + resource->io_parameters.isochronous.interval); + + trace1 + ("packet_count:%d", + resource->io_parameters.isochronous.packet_count); + } + } + + trace1("io type:%d", + (int)resource->io_parameters.header.io_transaction_type); + trace1("dev num:%d", (int)resource->io_parameters.header.device_number); + trace1("endpoint:%d", (int)resource->io_parameters.header.endpoint); + trace1("direction:%d", (int)resource->io_parameters.header.direction); + trace1("unlink_id:%d", (int)resource->io_parameters.header.unlink_id); + trace1("flags:%d", (int)resource->io_parameters.header.flags); + trace1("rbr type:%d", (int)resource->io_parameters.header.rbr.type); + trace1("rbr offset:%d", + (int)resource->io_parameters.header.rbr.byte_offset); + trace1("rbr count:%d", + (int)resource->io_parameters.header.rbr.byte_count); + + usbfront_device_submit_transaction + (resource->device, &resource->io_transaction); +} + +static void usbfront_hcd_resource_submit_transaction_1 + (xenidc_callback * callback) { + trace(); + + { + struct usbfront_hcd_resource *resource = container_of + (xenidc_endpoint_transaction_callback_to(callback), + struct usbfront_hcd_resource, + io_transaction); + + unsigned long flags; + + spin_lock_irqsave(&resource->lock, flags); + + usbfront_hcd_resource_handle_stimulus + (resource, usbfront_hcd_resource_stimulus_tc); + + spin_unlock_irqrestore(&resource->lock, flags); + } +} + +static void usbfront_hcd_resource_revoke_rbrs + (struct usbfront_hcd_resource *resource) { + trace(); + + xenidc_rbr_provider_pool_revoke_and_unreserve_rbrs + (&resource->rbr_request); +} + +static void usbfront_hcd_resource_revoke_rbrs_1(xenidc_callback * callback) { + trace(); + + { + struct usbfront_hcd_resource *resource = container_of + (xenidc_reserve_and_create_rbr_request_revoke_callback_to + (callback), + struct usbfront_hcd_resource, + rbr_request); + + unsigned long flags; + + spin_lock_irqsave(&resource->lock, flags); + + usbfront_hcd_resource_handle_stimulus + (resource, usbfront_hcd_resource_stimulus_rc); + + spin_unlock_irqrestore(&resource->lock, flags); + } +} + +static void usbfront_hcd_resource_submit_unlink + (struct usbfront_hcd_resource *resource) { + trace(); + + memset + (&resource->unlink_message_body, + 0, sizeof(resource->unlink_message_body) + ); + + resource->unlink_message_body.header.message_type = + USBIF_MESSAGE_TYPE_UNLINK; + + resource->unlink_message_body.unlink_id = resource->index; + + usbfront_device_submit_message + (resource->device, &resource->unlink_message); +} + +static void usbfront_hcd_resource_submit_unlink_1(xenidc_callback * callback) +{ + trace(); + + { + struct usbfront_hcd_resource *resource = container_of + (xenidc_endpoint_message_callback_to(callback), + struct usbfront_hcd_resource, + unlink_message); + + unsigned long flags; + + spin_lock_irqsave(&resource->lock, flags); + + usbfront_hcd_resource_handle_stimulus + (resource, usbfront_hcd_resource_stimulus_uc); + + spin_unlock_irqrestore(&resource->lock, flags); + } +} + +static void usbfront_hcd_resource_complete + (struct usbfront_hcd_resource *resource) { + trace(); + + { + int scheduled = + xenidc_work_schedule(&resource->complete_1_work); + + ASSERT(scheduled); + } +} + +static void usbfront_hcd_resource_complete_1(void *context) +{ + trace(); + + { + struct usbfront_hcd_resource *resource = + (struct usbfront_hcd_resource *)context; + + struct urb *urb = resource->urb; + + xenidc_error error; + + if (((error = xenidc_callback_query_error + (xenidc_reserve_and_create_rbr_request_to_create_callback + (&resource->rbr_request) + ) + ) + == XENIDC_ERROR_SUCCESS) + && + ((error = xenidc_callback_query_error + (xenidc_reserve_and_create_rbr_request_to_revoke_callback + (&resource->rbr_request) + ) + ) + == XENIDC_ERROR_SUCCESS) + ) { + urb->status = usbif_error_map_to_local + (xenidc_endpoint_transaction_query_error + (&resource->io_transaction) + ); + urb->actual_length = resource->io_status.length; + + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + int i; + + urb->error_count = 0; + + for (i = 0; i < urb->number_of_packets; i++) { + usbif_isochronous_io_schedule_element + *schedule = &resource->schedule[i]; + + urb->iso_frame_desc[i].actual_length = + schedule->length; + urb->iso_frame_desc[i].status = + usbif_error_map_to_local(schedule-> + error); + + if (urb->iso_frame_desc[i].status != 0) { + urb->error_count++; + } + } + } + } else { + urb->status = usbif_error_map_to_local(error); + urb->actual_length = 0; + } + + { + unsigned long flags; + + read_lock_irqsave(&dequeue_lock, flags); + + urb->hcpriv = 0; + + read_unlock_irqrestore(&dequeue_lock, flags); + } + + { + unsigned long flags; + + local_irq_save(flags); + + usb_hcd_giveback_urb + (usbfront_device_get_drvdata(resource->device), urb, + NULL); + + local_irq_restore(flags); + } + + xenidc_callback_success(&resource->callback); + } +} diff -r 5a90f01cb37e -r 06d98ed0b6e5 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.h --- /dev/null Mon Nov 21 11:10:19 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.h Mon Nov 21 11:10:40 2005 @@ -0,0 +1,95 @@ +/*****************************************************************************/ +/* A resource used by the usbfront host controller device driver to process */ +/* an URB by translating the URB and optional unlink request into */ +/* a transaction and corresponding optional unlink message for submission to */ +/* the back end. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBFRONT_HCD_RESOURCE_H +#define USBFRONT_HCD_RESOURCE_H + +#include +#include +#include +#include "usbfront_device.h" + +int usbfront_hcd_resource_class_init(void); + +void usbfront_hcd_resource_class_exit(void); + +typedef enum { + usbfront_hcd_resource_state_i, + usbfront_hcd_resource_state_i_st, + usbfront_hcd_resource_state_i_st_dq, + usbfront_hcd_resource_state_i_st_cs, + usbfront_hcd_resource_state_i_st_dq_cs, + usbfront_hcd_resource_state_i_st_cs_dq, + usbfront_hcd_resource_state_i_st_cs_dq_tc +} usbfront_hcd_resource_state; + +struct usbfront_hcd_resource { + xenidc_callback callback; + struct usbfront_device *device; + int index; + usbif_isochronous_io_schedule_element *schedule; + spinlock_t lock; + usbfront_hcd_resource_state state; + struct urb *urb; + xenidc_create_rbr_request_element rbr_request_element[2]; + xenidc_reserve_and_create_rbr_request rbr_request; + xenidc_endpoint_transaction io_transaction; + usbif_io_transaction_parameters io_parameters; + usbif_io_transaction_status io_status; + xenidc_endpoint_message unlink_message; + usbif_unlink_message_body unlink_message_body; + xenidc_work complete_1_work; +}; + +#define USBFRONT_HCD_RESOURCE_LINK callback.XENIDC_CALLBACK_LINK + +static inline struct list_head *usbfront_hcd_resource_to_link + (struct usbfront_hcd_resource *resource) { + return xenidc_callback_to_link(&resource->callback); +} + +static inline struct usbfront_hcd_resource + *usbfront_hcd_resource_callback_to(xenidc_callback * callback) +{ + return container_of(callback, struct usbfront_hcd_resource, callback); +} + +static inline struct usbfront_device *usbfront_hcd_resource_query_device + (struct usbfront_hcd_resource *resource) { + return resource->device; +} + +int usbfront_hcd_resource_init + (struct usbfront_hcd_resource *resource, + struct usbfront_device *device, + int index, xenidc_callback_function * callback); + +void usbfront_hcd_resource_exit(struct usbfront_hcd_resource *resource); + +void usbfront_hcd_resource_start_urb + (struct usbfront_hcd_resource *resource, struct urb *urb); + +void usbfront_hcd_resource_dequeue_urb(struct urb *urb); + +#endif diff -r 5a90f01cb37e -r 06d98ed0b6e5 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_module.c --- /dev/null Mon Nov 21 11:10:19 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_module.c Mon Nov 21 11:10:40 2005 @@ -0,0 +1,88 @@ +/*****************************************************************************/ +/* Front-end module for Xen USB split driver. */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#include +#include +#include "usbfront_device.h" +#include "usbfront_driver.h" +#include "usbfront_trace.h" + +static int usbfront_module_init_or_exit(int exit) +{ + trace(); + + { + int return_value = 0; + + if (usb_disabled()) { + return_value = -ENODEV; + + goto EXIT_NO_USB; + } + + if (exit) { + goto EXIT; + } + + if ((return_value = usbfront_driver_class_init()) != 0) { + goto EXIT_NO_DRIVER_CLASS; + } + + if ((return_value = usbfront_device_class_init()) != 0) { + goto EXIT_NO_DEVICE_CLASS; + } + + return 0; + + EXIT: + + usbfront_device_class_exit(); + + EXIT_NO_DEVICE_CLASS: + + usbfront_driver_class_exit(); + + EXIT_NO_DRIVER_CLASS: + + EXIT_NO_USB: + + return return_value; + } +} + +static int __init usbfront_module_init(void) +{ + trace(); + + return usbfront_module_init_or_exit(0); +} + +static void __exit usbfront_module_exit(void) +{ + trace(); + + (void)usbfront_module_init_or_exit(1); +} + +module_init(usbfront_module_init); +module_exit(usbfront_module_exit); + +MODULE_LICENSE("GPL"); diff -r 5a90f01cb37e -r 06d98ed0b6e5 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_sll.h --- /dev/null Mon Nov 21 11:10:19 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_sll.h Mon Nov 21 11:10:40 2005 @@ -0,0 +1,116 @@ +/*****************************************************************************/ +/* A singly linked list implementation */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBFRONT_SLL_H +#define USBFRONT_SLL_H + +#include "usbfront_assert.h" + +struct usbfront_slk { + struct usbfront_slk *next; +}; + +struct usbfront_sll { + struct usbfront_slk *first; + struct usbfront_slk *last; +}; + +static inline void usbfront_slk_init(struct usbfront_slk *slk) +{ + slk->next = slk; +} + +static inline int usbfront_slk_is_singular(struct usbfront_slk *slk) +{ + return (slk->next == slk); +} + +static inline void usbfront_sll_init(struct usbfront_sll *sll) +{ + sll->first = 0; +} + +static inline int usbfront_sll_is_empty(struct usbfront_sll *sll) +{ + return (sll->first == 0); +} + +static inline void usbfront_sll_add_last + (struct usbfront_sll *sll, struct usbfront_slk *slk) { + ASSERT(usbfront_slk_is_singular(slk)); + + slk->next = 0; + + if (sll->first != 0) { + sll->last->next = slk; + } else { + sll->first = slk; + } + + sll->last = slk; +} + +static inline struct usbfront_slk *usbfront_sll_remove_first + (struct usbfront_sll *sll) { + struct usbfront_slk *slk = sll->first; + + if (slk != 0) { + sll->first = slk->next; + + slk->next = slk; + } + + return slk; +} + +/* Returns 1 if slk removed, 0 otherwise. */ + +static inline int usbfront_sll_remove_slk + (struct usbfront_sll *sll, struct usbfront_slk *slk) { + struct usbfront_slk *prev_slk = NULL; + struct usbfront_slk *next_slk = sll->first; + + while (next_slk != NULL) { + if (next_slk != slk) { + prev_slk = next_slk; + next_slk = next_slk->next; + } else { + next_slk = next_slk->next; + + if (prev_slk != NULL) { + prev_slk->next = next_slk; + } else { + sll->first = next_slk; + } + + if (next_slk == NULL) { + sll->last = prev_slk; + } + + slk->next = slk; + + return 1; + } + } + + return 0; +} + +#endif diff -r 5a90f01cb37e -r 06d98ed0b6e5 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_trace.h --- /dev/null Mon Nov 21 11:10:19 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_trace.h Mon Nov 21 11:10:40 2005 @@ -0,0 +1,53 @@ +/*****************************************************************************/ +/* Simple trace macros */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBFRONT_TRACE_H +#define USBFRONT_TRACE_H + +#include +#include + +#ifdef CONFIG_XEN_USBDEV_FRONTEND_TRACE + +#define trace0( format ) \ +printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__ ) + +#define trace1( format, a0 ) \ +printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__, a0 ) + +#define trace2( format, a0, a1 ) \ +printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__, a0, a1 ) + +#define trace3( format, a0, a1, a2 ) \ +printk( KERN_INFO "usbfront %s:" format "\n", __PRETTY_FUNCTION__, a0, a1, a2 ) + +#define trace() trace0( "" ) + +#else + +#define trace0( format ) +#define trace1( format,a0 ) +#define trace2( format,a0, a1 ) +#define trace3( format,a0, a1, a2 ) +#define trace() + +#endif + +#endif