diff -r e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/arch/xen/Kconfig --- a/linux-2.6-xen-sparse/arch/xen/Kconfig Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/arch/xen/Kconfig Wed Nov 30 11:18:09 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 e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/drivers/xen/Makefile --- a/linux-2.6-xen-sparse/drivers/xen/Makefile Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Wed Nov 30 11:18:09 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 e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h --- a/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbback/usbback_trace.h Wed Nov 30 11:18:09 2005 @@ -29,7 +29,7 @@ #define trace_info(format, ...) \ printk(KERN_INFO "usbback %s: " format "\n", __FUNCTION__, ## __VA_ARGS__) -#define trace() trace_info( "" ) +#define trace() trace_info("") #else diff -r e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile --- /dev/null Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/Makefile Wed Nov 30 11:18:09 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 e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_assert.h --- /dev/null Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_assert.h Wed Nov 30 11:18:09 2005 @@ -0,0 +1,38 @@ +/*****************************************************************************/ +/* 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(__FUNCTION__, __LINE__, #S)) + +#endif diff -r e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.c --- /dev/null Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.c Wed Nov 30 11:18:09 2005 @@ -0,0 +1,969 @@ +/*****************************************************************************/ +/* 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 { + struct xenidc_endpoint_transaction transaction; + union { + struct { + struct usbif_probe_transaction_parameters parameters; + struct usbif_probe_transaction_status status; + } probe; + struct { + struct usbif_reset_transaction_parameters parameters; + struct usbif_reset_transaction_status status; + } reset; + }; + struct usbfront_device *device; +}; + +struct usbfront_device { + struct xenbus_device *dev; + void *drvdata; + int backend_id; + char *backend; + struct xenidc_address address; + spinlock_t lock; + usbfront_device_state state; + struct xenidc_endpoint endpoint; + struct 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]; + struct xenidc_work probe_driver_1_work; + struct 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(struct xenidc_endpoint *endpoint) +{ + trace_info("endpoint:%p", endpoint); + return container_of(endpoint, struct usbfront_device, endpoint); +} + +void usbfront_device_set_drvdata(struct usbfront_device *device, void *data) +{ + trace_info("device:%p,data:%p", device, data); + device->drvdata = data; +} + +void *usbfront_device_get_drvdata(struct usbfront_device *device) +{ + trace_info("device:%p", device); + return device->drvdata; +} + +struct device *usbfront_device_to_dev(struct usbfront_device *device) +{ + trace_info("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) +{ + return USBFRONT_DEVICE_PORT_COUNT; +} + +int usbfront_device_query_port_status_changed(struct usbfront_device *device, +int port_number) +{ + int changed; + unsigned long flags; + ASSERT((port_number > 0) && (port_number <= + USBFRONT_DEVICE_PORT_COUNT)); + 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) +{ + struct usb_port_status port_status; + unsigned long flags; + trace(); + ASSERT((port_number > 0) && (port_number <= + USBFRONT_DEVICE_PORT_COUNT)); + 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) +{ + unsigned long flags; + trace(); + ASSERT((port_number > 0) && (port_number <= + USBFRONT_DEVICE_PORT_COUNT)); + 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) +{ + unsigned long flags; + trace(); + ASSERT((port_number > 0) && (port_number <= + USBFRONT_DEVICE_PORT_COUNT)); + 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) +{ + unsigned long flags; + trace(); + + ASSERT((port_number > 0) && (port_number <= + USBFRONT_DEVICE_PORT_COUNT)); + 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) +{ + unsigned long flags; + trace(); + + ASSERT((port_number > 0) && (port_number <= + USBFRONT_DEVICE_PORT_COUNT)); + 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) +{ + unsigned long flags; + trace(); + ASSERT((port_number > 0) && (port_number <= + USBFRONT_DEVICE_PORT_COUNT)); + 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, +struct xenidc_endpoint_message *message) +{ + trace(); + xenidc_endpoint_submit_message(&device->endpoint, message); +} + +struct xenidc_address +usbfront_device_query_address(struct usbfront_device *device) +{ + trace(); + return device->address; +} + +void +usbfront_device_submit_transaction(struct usbfront_device *device, +struct xenidc_endpoint_transaction *transaction) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + trace(); + xenidc_endpoint_submit_transaction(&device->endpoint, transaction); +} + +static void usbfront_device_endpoint_connect(struct xenidc_endpoint *endpoint) +{ + struct usbfront_device *device = usbfront_device_endpoint_to(endpoint); + unsigned long flags; + trace_info("endpoint:%p", endpoint); + trace_info("device:%p", device); + /* Between connect and completion of the disconnect callback we are */ + /* allowed to issue messages and transactions. */ + 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(struct xenidc_endpoint *endpoint, +struct xenidc_callback *callback) +{ + struct usbfront_device *device = usbfront_device_endpoint_to(endpoint); + unsigned long flags; + 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. */ + 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(struct xenidc_endpoint *endpoint, +struct 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(struct xenidc_endpoint *endpoint, +struct 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(struct 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) +{ + int return_value = 0, i; + trace_info("%p", device); + if (exit) + goto exit_path; + memset(device, 0, sizeof(*device)); + device->dev = dev; + spin_lock_init(&device->lock); + device->state = usbfront_device_state_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_path: + (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) +{ + int return_value = 0; + struct usbfront_device *device; + trace(); + if (remove) + goto remove_path; + device = kmalloc(sizeof(*device), GFP_KERNEL); + if (device == NULL) { + xenbus_dev_error(dev, -ENOMEM,"allocating FE 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_path: + 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) +{ + int return_value = 0; + struct xenbus_transaction *transaction; + trace(); + if (suspend) + goto suspend_path; + transaction = xenbus_transaction_start(); + if (IS_ERR(transaction)) { + trace_info("Error starting transaction."); + return_value = PTR_ERR(transaction); + goto exit_no_transaction; + } + return_value = xenbus_gather(transaction, device->dev->nodename, + "backend-id", "%i", &device->backend_id, + "backend", NULL, &device->backend, NULL); + (void)xenbus_transaction_end(transaction, 1); + if (return_value < 0) { + trace_info("Failed to gather configuration parameters."); + goto exit_no_parameters; + } + trace_info("Configuration: backend-id:%d, backend:%s", + device->backend_id, device->backend); + xenidc_address_init(&device->address, device->dev->nodename, + device->backend, device->backend_id); + xenidc_endpoint_create(&device->endpoint, device->address); + return 0; + suspend_path: + xenidc_endpoint_destroy(&device->endpoint); + kfree(device->backend); + exit_no_parameters: + exit_no_transaction: + return return_value; +} + +static int usbfront_device_resume(struct xenbus_device *dev) +{ + struct usbfront_device *device = dev->data; + trace(); + (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) +{ + int scheduled; + trace(); + scheduled = xenidc_work_schedule(&device->probe_driver_1_work); + ASSERT(scheduled); +} + +static void usbfront_device_probe_driver_1(void *data) +{ + struct usbfront_device *device = (struct usbfront_device *)data; + usbfront_device_stimulus stimulus; + unsigned long flags; + trace(); + if (usbfront_driver_probe(device) == 0) { + stimulus = usbfront_device_stimulus_ps; + } else { + stimulus = usbfront_device_stimulus_pf; + } + 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) +{ + int scheduled; + trace(); + scheduled = xenidc_work_schedule(&device->remove_driver_1_work); + ASSERT(scheduled); +} + +static void usbfront_device_remove_driver_1(void *data) +{ + struct usbfront_device *device = (struct usbfront_device *)data; + unsigned long flags; + trace(); + usbfront_driver_remove(device); + 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) +{ + int i; + device->port_probe_count = USBFRONT_DEVICE_PORT_COUNT; + 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(struct 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 { + trace_info("device %p: unexpected result %d " + "probing port %d", device, + (int)probe->probe.status.result, + port_number); + } + } else { + trace_info("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 { + trace_info("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) +{ + int i; + trace(); + 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 e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.h --- /dev/null Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_device.h Wed Nov 30 11:18:09 2005 @@ -0,0 +1,92 @@ +/*****************************************************************************/ +/* 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 +#include "../../usb/core/hcd.h" + +int usbfront_device_class_init(void); + +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, +struct xenidc_endpoint_message *message); + +struct xenidc_address +usbfront_device_query_address(struct usbfront_device *device); + +void +usbfront_device_submit_transaction(struct usbfront_device *device, +struct xenidc_endpoint_transaction *transaction); + +#endif diff -r e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.c --- /dev/null Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.c Wed Nov 30 11:18:09 2005 @@ -0,0 +1,601 @@ +/*****************************************************************************/ +/* 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(struct xenidc_callback *callback); + +static int usbfront_hcd_start(struct usb_hcd *hcd) +{ + int return_value = 0; + struct usbfront_hcd *uhcd = usbfront_hcd_hcd_to_uhcd(hcd); + int i; + struct usb_device *root_hub_device; + trace(); + 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); + 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) { + trace_info("usbfront_hcd_resource_init failed"); + goto exit_no_resource; + } + list_add(usbfront_hcd_resource_to_link(resource), + &uhcd->free_resource_list); + } + root_hub_device = usb_alloc_dev(NULL, &hcd->self, 0); + if (root_hub_device == NULL) { + trace_info("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 */ + return_value = usb_hcd_register_root_hub(root_hub_device, hcd); + if (return_value != 0) { + trace_info("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) +{ + struct usbfront_hcd *uhcd = usbfront_hcd_hcd_to_uhcd(hcd); + trace(); + 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 int +usbfront_hcd_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, +struct urb *urb, int mem_flags) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + struct usbfront_hcd *uhcd = usbfront_hcd_hcd_to_uhcd(hcd); + unsigned long flags; + trace(); + 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) +{ + int dequeued; + struct usbfront_hcd *uhcd = usbfront_hcd_hcd_to_uhcd(hcd); + unsigned long flags; + trace(); + 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; + 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, i; + struct usbfront_device *device = usbfront_hcd_hcd_to_usbfront_device( + hcd); + int port_count = usbfront_device_query_port_count(device); + int byte_count = (1 + port_count /* ports */ + 7 /* round up */ ) / 8; + memset(buf, 0, byte_count); + 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) +{ + struct usbfront_device *device = usbfront_hcd_hcd_to_usbfront_device( + hcd); + int return_value = 0; + trace(); + switch (typeReq) { + case GetHubStatus: + trace_info("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: + trace_info("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: + trace_info("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: + trace_info("SetPortFeature"); + if (((wIndex & 0x00FF) > usbfront_device_query_port_count( + device)) || (wLength != 0)) + goto error; + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + trace_info("USB_PORT_FEAT_SUSPEND"); + break; + case USB_PORT_FEAT_RESET: + trace_info("USB_PORT_FEAT_RESET"); + usbfront_device_set_port_reset(device, wIndex); + break; + case USB_PORT_FEAT_POWER: + trace_info("USB_PORT_FEAT_POWER"); + usbfront_device_set_port_power(device, wIndex); + break; + default: + trace_info("Unknown:%x", wValue); + goto error; + } + break; + case ClearPortFeature: + trace_info("ClearPortFeature"); + if (((wIndex & 0x00FF) > usbfront_device_query_port_count( + device)) || (wLength != 0)) + goto error; + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + trace_info("USB_PORT_FEAT_ENABLE"); + usbfront_device_clear_port_enable(device, wIndex); + break; + case USB_PORT_FEAT_SUSPEND: + trace_info("USB_PORT_FEAT_SUSPEND"); + break; + case USB_PORT_FEAT_POWER: + trace_info("USB_PORT_FEAT_POWER"); + break; + case USB_PORT_FEAT_INDICATOR: + trace_info("USB_PORT_FEAT_INDICATOR"); + break; + case USB_PORT_FEAT_C_CONNECTION: + trace_info("USB_PORT_C_CONNECTION"); + usbfront_device_clear_port_connection_change(device, + wIndex); + break; + case USB_PORT_FEAT_C_RESET: + trace_info("USB_PORT_C_RESET"); + usbfront_device_clear_port_reset_change(device, + wIndex); + break; + case USB_PORT_FEAT_C_ENABLE: + trace_info("USB_PORT_C_ENABLE"); + break; + case USB_PORT_FEAT_C_SUSPEND: + trace_info("USB_PORT_C_SUSPEND"); + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + trace_info("USB_PORT_C_OVER_CURRENT"); + break; + default: + trace_info("Unknown:%x", wValue); + goto error; + } + break; + default: + trace_info("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) +{ + trace_info("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) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + trace(); + while (!usbfront_sll_is_empty(&uhcd->urb_sll) && + !list_empty(&uhcd->free_resource_list)) { + 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)); + trace_info("Starting URB"); + usbfront_hcd_resource_start_urb(resource, urb); + } +} + +void usbfront_hcd_resource_completed(struct xenidc_callback * callback) +{ + 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; + trace(); + 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) +{ + int return_value = 0; + struct usb_hcd *hcd; + trace(); + if (remove) + goto remove_path; + if (usb_disabled()) { + return_value = -ENODEV; + goto exit_no_usb; + } + if ((hcd = usb_create_hcd(&usbfront_hc_driver, + usbfront_device_to_dev(device), + usbfront_device_to_dev(device)->bus_id))== NULL) { + trace_info("usb_create_hcd failed"); + return_value = -ENOMEM; + goto exit_no_hcd; + } + usbfront_device_set_drvdata(device, hcd); + if ((return_value = usb_add_hcd(hcd, 0, 0)) != 0) { + trace_info("usb_add_hcd failed"); + goto exit_no_add; + } + return 0; + remove_path: + hcd = usbfront_device_get_drvdata(device); + usb_remove_hcd(hcd); + exit_no_add: + usb_put_hcd(hcd); + usbfront_device_set_drvdata(device, NULL); + exit_no_hcd: + exit_no_usb: + 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 e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.h --- /dev/null Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_driver.h Wed Nov 30 11:18:09 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" + +int usbfront_driver_class_init(void); + +void usbfront_driver_class_exit(void); + +int usbfront_driver_probe(struct usbfront_device *device); + +void usbfront_driver_remove(struct usbfront_device *device); + +#endif diff -r e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.c --- /dev/null Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.c Wed Nov 30 11:18:09 2005 @@ -0,0 +1,728 @@ +/*****************************************************************************/ +/* 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" + +struct xenidc_rbr_provider_pool *rbr_provider_pool; + +int usbfront_hcd_resource_class_init(void) +{ + struct xenidc_buffer_resource_list sum, bulk_list, schedule_list; + trace(); + sum = xenidc_buffer_resource_list_null(); + bulk_list = xenidc_vaddress_calculate_buffer_resource_list( + USBIF_MAX_BULK_BYTE_COUNT, + USBIF_BULK_BYTE_ALIGNMENT); + 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); + rbr_provider_pool = xenidc_allocate_rbr_provider_pool(sum); + return (rbr_provider_pool != NULL) ? 0 : -ENOMEM; +} + +void usbfront_hcd_resource_class_exit(void) +{ + trace(); + xenidc_free_rbr_provider_pool(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(struct xenidc_callback *callback); +static void +usbfront_hcd_resource_submit_transaction_1(struct xenidc_callback *callback); +static void +usbfront_hcd_resource_revoke_rbrs_1(struct xenidc_callback *callback); +static void +usbfront_hcd_resource_submit_unlink_1(struct 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) +{ + int return_value = 0; + trace(); + if (exit) + goto exit_path; + xenidc_callback_init(&resource->callback, callback); + resource->device = device; + resource->index = index; + resource->schedule = (struct 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_path: + 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) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + unsigned long flags; + trace(); + urb->hcpriv = resource; + 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) +{ + unsigned long flags; + trace(); + 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) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + trace(); + xenidc_create_rbr_request_element_ensure_removed( + &resource->rbr_request_element[0]); + xenidc_create_rbr_request_element_ensure_removed( + &resource->rbr_request_element[1]); + xenidc_create_rbr_request_element_set_lbr( + &resource->rbr_request_element[0], + xenidc_vaddress_create_lbr( + resource->urb->transfer_buffer, + resource->urb->transfer_buffer_length), + 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) { + struct usbif_isochronous_io_schedule_element *element; + int i; + if (resource->urb->number_of_packets > (PAGE_SIZE / + sizeof(struct + usbif_isochronous_io_schedule_element))) + goto schedule_too_big; + element = resource->schedule; + 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(struct + 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(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(struct xenidc_callback * callback) +{ + /* 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; + trace(); + 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) +{ + /* MUST MAINTAIN RELATIVE REQUEST ORDER ON THE SUBMISSION PATH */ + struct urb *urb = resource->urb; + trace(); + memset(&resource->io_parameters, 0, sizeof(resource->io_parameters)); + memset(&resource->io_status, 0, sizeof(resource->io_status)); + resource->io_parameters.header.header.transaction_type = + USBIF_TRANSACTION_TYPE_IO; + 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); + trace_info("control URB"); + trace_info("setup[0]:%x", + (int)resource->io_parameters.control.setup[0]); + trace_info("setup[1]:%x", + (int)resource->io_parameters.control.setup[1]); + trace_info("setup[2]:%x", + (int)resource->io_parameters.control.setup[2]); + trace_info("setup[3]:%x", + (int)resource->io_parameters.control.setup[3]); + trace_info("setup[4]:%x", + (int)resource->io_parameters.control.setup[4]); + trace_info("setup[5]:%x", + (int)resource->io_parameters.control.setup[5]); + trace_info("setup[6]:%x", + (int)resource->io_parameters.control.setup[6]); + trace_info("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; + trace_info("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; + trace_info("interrupt URB"); + trace_info("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; + trace_info("isochronous URB"); + trace_info("interval:%d", resource->io_parameters.isochronous. + interval); + trace_info("packet_count:%d", resource->io_parameters. + isochronous.packet_count); + } + + trace_info("io type:%d", (int)resource->io_parameters.header. + io_transaction_type); + trace_info("dev num:%d", (int)resource->io_parameters.header. + device_number); + trace_info("endpoint:%d", (int)resource->io_parameters.header. + endpoint); + trace_info("direction:%d", (int)resource->io_parameters.header. + direction); + trace_info("unlink_id:%d", (int)resource->io_parameters.header. + unlink_id); + trace_info("flags:%d", (int)resource->io_parameters.header.flags); + trace_info("rbr type:%d", (int)resource->io_parameters.header.rbr. + type); + trace_info("rbr offset:%d", (int)resource->io_parameters.header.rbr. + byte_offset); + trace_info("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(struct xenidc_callback *callback) +{ + struct usbfront_hcd_resource *resource = container_of( + xenidc_endpoint_transaction_callback_to(callback), + struct usbfront_hcd_resource, io_transaction); + unsigned long flags; + trace(); + 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(struct xenidc_callback *callback) +{ + 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; + trace(); + 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(struct xenidc_callback *callback) +{ + struct usbfront_hcd_resource *resource = container_of( + xenidc_endpoint_message_callback_to(callback), + struct usbfront_hcd_resource, unlink_message); + unsigned long flags; + trace(); + 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) +{ + int scheduled; + trace(); + scheduled = xenidc_work_schedule(&resource->complete_1_work); + ASSERT(scheduled); +} + +static void usbfront_hcd_resource_complete_1(void *context) +{ + struct usbfront_hcd_resource *resource = + (struct usbfront_hcd_resource *)context; + struct urb *urb = resource->urb; + xenidc_error error; + unsigned long flags; + trace(); + 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++) { + struct 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; + } + read_lock_irqsave(&dequeue_lock, flags); + urb->hcpriv = 0; + read_unlock_irqrestore(&dequeue_lock, 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 e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.h --- /dev/null Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_hcd_resource.h Wed Nov 30 11:18:09 2005 @@ -0,0 +1,98 @@ +/*****************************************************************************/ +/* 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 { + struct xenidc_callback callback; + struct usbfront_device *device; + int index; + struct usbif_isochronous_io_schedule_element *schedule; + spinlock_t lock; + usbfront_hcd_resource_state state; + struct urb *urb; + struct xenidc_create_rbr_request_element rbr_request_element[2]; + struct xenidc_reserve_and_create_rbr_request rbr_request; + struct xenidc_endpoint_transaction io_transaction; + union usbif_io_transaction_parameters io_parameters; + struct usbif_io_transaction_status io_status; + struct xenidc_endpoint_message unlink_message; + struct usbif_unlink_message_body unlink_message_body; + struct 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(struct 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 e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_module.c --- /dev/null Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_module.c Wed Nov 30 11:18:09 2005 @@ -0,0 +1,67 @@ +/*****************************************************************************/ +/* 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) +{ + int return_value = 0; + trace(); + if (usb_disabled()) { + return_value = -ENODEV; + goto exit_no_usb; + } + if (exit) + goto exit_path; + 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_path: + 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 e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_sll.h --- /dev/null Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_sll.h Wed Nov 30 11:18:09 2005 @@ -0,0 +1,106 @@ +/*****************************************************************************/ +/* 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 e95f0d5261d3 -r db396779c07b linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_trace.h --- /dev/null Wed Nov 30 11:05:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront_trace.h Wed Nov 30 11:18:09 2005 @@ -0,0 +1,41 @@ +/*****************************************************************************/ +/* Simple trace macros */ +/* */ +/* Copyright (c) 2005 Harry Butterworth IBM Corporation */ +/* */ +/* This program is free software; you can redistribute it and/or modify it */ +/* under the terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2 of the License, or (at your */ +/* option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License along */ +/* with this program; if not, write to the Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/*****************************************************************************/ + +#ifndef USBFRONT_TRACE_H +#define USBFRONT_TRACE_H + +#include +#include + +#ifdef CONFIG_XEN_USBDEV_FRONTEND_TRACE + +#define trace_info(format, ...) \ +printk(KERN_INFO "usbfront %s: " format "\n", __FUNCTION__, ## __VA_ARGS__) +#define trace() trace_info("") + +#else + +#define trace_info(format, ...) +#define trace() + +#endif + +#endif