[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] Remove defunct usb split driver code. It will get replaced with
# HG changeset patch # User kaf24@xxxxxxxxxxxxxxxxxxxx # Node ID ecc77b1c861209455e99f442a363e7a6333c05c9 # Parent d7c794130ac54f2d9e06e792361ba62fc92cfb4f Remove defunct usb split driver code. It will get replaced with a new working driver at some point. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> diff -r d7c794130ac5 -r ecc77b1c8612 linux-2.6-xen-sparse/drivers/xen/usbback/common.h --- a/linux-2.6-xen-sparse/drivers/xen/usbback/common.h Thu Sep 22 13:04:14 2005 +++ /dev/null Thu Sep 22 13:05:36 2005 @@ -1,84 +0,0 @@ - -#ifndef __USBIF__BACKEND__COMMON_H__ -#define __USBIF__BACKEND__COMMON_H__ - -#include <linux/config.h> -#include <linux/version.h> -#include <linux/module.h> -#include <linux/rbtree.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/blkdev.h> -#include <asm/io.h> -#include <asm/setup.h> -#include <asm/pgalloc.h> -#include <asm/hypervisor.h> -#include <asm-xen/driver_util.h> -#include <asm-xen/xen-public/io/usbif.h> - -#if 0 -#define ASSERT(_p) \ - if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \ - __LINE__, __FILE__); *(int*)0=0; } -#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \ - __FILE__ , __LINE__ , ## _a ) -#else -#define ASSERT(_p) ((void)0) -#define DPRINTK(_f, _a...) ((void)0) -#endif - -typedef struct usbif_priv_st usbif_priv_t; - -struct usbif_priv_st { - /* Unique identifier for this interface. */ - domid_t domid; - unsigned int handle; - /* Physical parameters of the comms window. */ - unsigned long shmem_frame; - unsigned int evtchn; - /* Comms Information */ - usbif_back_ring_t usb_ring; - struct vm_struct *usb_ring_area; - /* Private fields. */ - enum { DISCONNECTED, DISCONNECTING, CONNECTED } status; - /* - * DISCONNECT response is deferred until pending requests are ack'ed. - * We therefore need to store the id from the original request. - */ - u8 disconnect_rspid; - usbif_priv_t *hash_next; - struct list_head usbif_list; - spinlock_t usb_ring_lock; - atomic_t refcnt; - - struct work_struct work; -}; - -void usbif_create(usbif_be_create_t *create); -void usbif_destroy(usbif_be_destroy_t *destroy); -void usbif_connect(usbif_be_connect_t *connect); -int usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id); -void usbif_disconnect_complete(usbif_priv_t *up); - -void usbif_release_port(usbif_be_release_port_t *msg); -int usbif_claim_port(usbif_be_claim_port_t *msg); -void usbif_release_ports(usbif_priv_t *up); - -usbif_priv_t *usbif_find(domid_t domid); -#define usbif_get(_b) (atomic_inc(&(_b)->refcnt)) -#define usbif_put(_b) \ - do { \ - if ( atomic_dec_and_test(&(_b)->refcnt) ) \ - usbif_disconnect_complete(_b); \ - } while (0) - - -void usbif_interface_init(void); -void usbif_ctrlif_init(void); - -void usbif_deschedule(usbif_priv_t *up); -void remove_from_usbif_list(usbif_priv_t *up); - -irqreturn_t usbif_be_int(int irq, void *dev_id, struct pt_regs *regs); - -#endif /* __USBIF__BACKEND__COMMON_H__ */ diff -r d7c794130ac5 -r ecc77b1c8612 linux-2.6-xen-sparse/drivers/xen/usbback/control.c --- a/linux-2.6-xen-sparse/drivers/xen/usbback/control.c Thu Sep 22 13:04:14 2005 +++ /dev/null Thu Sep 22 13:05:36 2005 @@ -1,71 +0,0 @@ -/****************************************************************************** - * arch/xen/drivers/usbif/backend/control.c - * - * Routines for interfacing with the control plane. - * - * Copyright (c) 2004, Keir Fraser - */ - -#include "common.h" - -static void usbif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id) -{ - DPRINTK("Received usbif backend message, subtype=%d\n", msg->subtype); - - switch ( msg->subtype ) - { - case CMSG_USBIF_BE_CREATE: - usbif_create((usbif_be_create_t *)&msg->msg[0]); - break; - case CMSG_USBIF_BE_DESTROY: - usbif_destroy((usbif_be_destroy_t *)&msg->msg[0]); - break; - case CMSG_USBIF_BE_CONNECT: - usbif_connect((usbif_be_connect_t *)&msg->msg[0]); - break; - case CMSG_USBIF_BE_DISCONNECT: - if ( !usbif_disconnect((usbif_be_disconnect_t *)&msg->msg[0],msg->id) ) - return; /* Sending the response is deferred until later. */ - break; - case CMSG_USBIF_BE_CLAIM_PORT: - usbif_claim_port((usbif_be_claim_port_t *)&msg->msg[0]); - break; - case CMSG_USBIF_BE_RELEASE_PORT: - usbif_release_port((usbif_be_release_port_t *)&msg->msg[0]); - break; - default: - DPRINTK("Parse error while reading message subtype %d, len %d\n", - msg->subtype, msg->length); - msg->length = 0; - break; - } - - ctrl_if_send_response(msg); -} - -void usbif_ctrlif_init(void) -{ - ctrl_msg_t cmsg; - usbif_be_driver_status_changed_t st; - - (void)ctrl_if_register_receiver(CMSG_USBIF_BE, usbif_ctrlif_rx, - CALLBACK_IN_BLOCKING_CONTEXT); - - /* Send a driver-UP notification to the domain controller. */ - cmsg.type = CMSG_USBIF_BE; - cmsg.subtype = CMSG_USBIF_BE_DRIVER_STATUS_CHANGED; - cmsg.length = sizeof(usbif_be_driver_status_changed_t); - st.status = USBIF_DRIVER_STATUS_UP; - memcpy(cmsg.msg, &st, sizeof(st)); - ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); -} - -/* - * Local variables: - * c-file-style: "linux" - * indent-tabs-mode: t - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff -r d7c794130ac5 -r ecc77b1c8612 linux-2.6-xen-sparse/drivers/xen/usbback/interface.c --- a/linux-2.6-xen-sparse/drivers/xen/usbback/interface.c Thu Sep 22 13:04:14 2005 +++ /dev/null Thu Sep 22 13:05:36 2005 @@ -1,241 +0,0 @@ -/****************************************************************************** - * arch/xen/drivers/usbif/backend/interface.c - * - * USB device interface management. - * - * by Mark Williamson, Copyright (c) 2004 - */ - -#include "common.h" - -#define USBIF_HASHSZ 1024 -#define USBIF_HASH(_d) (((int)(_d))&(USBIF_HASHSZ-1)) - -static kmem_cache_t *usbif_priv_cachep; -static usbif_priv_t *usbif_priv_hash[USBIF_HASHSZ]; - -usbif_priv_t *usbif_find(domid_t domid) -{ - usbif_priv_t *up = usbif_priv_hash[USBIF_HASH(domid)]; - while ( (up != NULL ) && ( up->domid != domid ) ) - up = up->hash_next; - return up; -} - -static void __usbif_disconnect_complete(void *arg) -{ - usbif_priv_t *usbif = (usbif_priv_t *)arg; - ctrl_msg_t cmsg; - usbif_be_disconnect_t disc; - - /* - * These can't be done in usbif_disconnect() because at that point there - * may be outstanding requests at the device whose asynchronous responses - * must still be notified to the remote driver. - */ - free_vm_area(usbif->usb_ring_area); - - /* Construct the deferred response message. */ - cmsg.type = CMSG_USBIF_BE; - cmsg.subtype = CMSG_USBIF_BE_DISCONNECT; - cmsg.id = usbif->disconnect_rspid; - cmsg.length = sizeof(usbif_be_disconnect_t); - disc.domid = usbif->domid; - disc.status = USBIF_BE_STATUS_OKAY; - memcpy(cmsg.msg, &disc, sizeof(disc)); - - /* - * Make sure message is constructed /before/ status change, because - * after the status change the 'usbif' structure could be deallocated at - * any time. Also make sure we send the response /after/ status change, - * as otherwise a subsequent CONNECT request could spuriously fail if - * another CPU doesn't see the status change yet. - */ - mb(); - if ( usbif->status != DISCONNECTING ) - BUG(); - usbif->status = DISCONNECTED; - mb(); - - /* Send the successful response. */ - ctrl_if_send_response(&cmsg); -} - -void usbif_disconnect_complete(usbif_priv_t *up) -{ - INIT_WORK(&up->work, __usbif_disconnect_complete, (void *)up); - schedule_work(&up->work); -} - -void usbif_create(usbif_be_create_t *create) -{ - domid_t domid = create->domid; - usbif_priv_t **pup, *up; - - if ( (up = kmem_cache_alloc(usbif_priv_cachep, GFP_KERNEL)) == NULL ) - { - DPRINTK("Could not create usbif: out of memory\n"); - create->status = USBIF_BE_STATUS_OUT_OF_MEMORY; - return; - } - - memset(up, 0, sizeof(*up)); - up->domid = domid; - up->status = DISCONNECTED; - spin_lock_init(&up->usb_ring_lock); - atomic_set(&up->refcnt, 0); - - pup = &usbif_priv_hash[USBIF_HASH(domid)]; - while ( *pup != NULL ) - { - if ( (*pup)->domid == domid ) - { - create->status = USBIF_BE_STATUS_INTERFACE_EXISTS; - kmem_cache_free(usbif_priv_cachep, up); - return; - } - pup = &(*pup)->hash_next; - } - - up->hash_next = *pup; - *pup = up; - - create->status = USBIF_BE_STATUS_OKAY; -} - -void usbif_destroy(usbif_be_destroy_t *destroy) -{ - domid_t domid = destroy->domid; - usbif_priv_t **pup, *up; - - pup = &usbif_priv_hash[USBIF_HASH(domid)]; - while ( (up = *pup) != NULL ) - { - if ( up->domid == domid ) - { - if ( up->status != DISCONNECTED ) - goto still_connected; - goto destroy; - } - pup = &up->hash_next; - } - - destroy->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND; - return; - - still_connected: - destroy->status = USBIF_BE_STATUS_INTERFACE_CONNECTED; - return; - - destroy: - *pup = up->hash_next; - usbif_release_ports(up); - kmem_cache_free(usbif_priv_cachep, up); - destroy->status = USBIF_BE_STATUS_OKAY; -} - -void usbif_connect(usbif_be_connect_t *connect) -{ - domid_t domid = connect->domid; - unsigned int evtchn = connect->evtchn; - unsigned long shmem_frame = connect->shmem_frame; - pgprot_t prot; - int error; - usbif_priv_t *up; - usbif_sring_t *sring; - - up = usbif_find(domid); - if ( unlikely(up == NULL) ) - { - DPRINTK("usbif_connect attempted for non-existent usbif (%u)\n", - connect->domid); - connect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND; - return; - } - - if ( (up->usb_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL ) - { - connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY; - return; - } - - prot = __pgprot(_KERNPG_TABLE); - error = direct_remap_pfn_range(&init_mm, AREALLOC_AREADDR(area->addr), - shmem_frame, PAGE_SIZE, - prot, domid); - if ( error != 0 ) - { - if ( error == -ENOMEM ) - connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY; - else if ( error == -EFAULT ) - connect->status = USBIF_BE_STATUS_MAPPING_ERROR; - else - connect->status = USBIF_BE_STATUS_ERROR; - free_vm_area(up->usb_ring_area); - return; - } - - if ( up->status != DISCONNECTED ) - { - connect->status = USBIF_BE_STATUS_INTERFACE_CONNECTED; - free_vm_area(up->usb_ring_area); - return; - } - - sring = (usbif_sring_t *)area->addr; - SHARED_RING_INIT(sring); - BACK_RING_INIT(&up->usb_ring, sring, PAGE_SIZE); - - up->evtchn = evtchn; - up->shmem_frame = shmem_frame; - up->status = CONNECTED; - usbif_get(up); - - (void)bind_evtchn_to_irqhandler( - evtchn, usbif_be_int, 0, "usbif-backend", up); - - connect->status = USBIF_BE_STATUS_OKAY; -} - -/* Remove URBs for this interface before destroying it. */ -void usbif_deschedule(usbif_priv_t *up) -{ - remove_from_usbif_list(up); -} - -int usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id) -{ - domid_t domid = disconnect->domid; - usbif_priv_t *up; - - up = usbif_find(domid); - if ( unlikely(up == NULL) ) - { - DPRINTK("usbif_disconnect attempted for non-existent usbif" - " (%u)\n", disconnect->domid); - disconnect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND; - return 1; /* Caller will send response error message. */ - } - - if ( up->status == CONNECTED ) - { - up->status = DISCONNECTING; - up->disconnect_rspid = rsp_id; - wmb(); /* Let other CPUs see the status change. */ - unbind_evtchn_from_irqhandler(up->evtchn, up); - usbif_deschedule(up); - usbif_put(up); - return 0; /* Caller should not send response message. */ - } - - disconnect->status = USBIF_BE_STATUS_OKAY; - return 1; -} - -void __init usbif_interface_init(void) -{ - usbif_priv_cachep = kmem_cache_create("usbif_priv_cache", - sizeof(usbif_priv_t), - 0, 0, NULL, NULL); - memset(usbif_priv_hash, 0, sizeof(usbif_priv_hash)); -} diff -r d7c794130ac5 -r ecc77b1c8612 linux-2.6-xen-sparse/drivers/xen/usbback/usbback.c --- a/linux-2.6-xen-sparse/drivers/xen/usbback/usbback.c Thu Sep 22 13:04:14 2005 +++ /dev/null Thu Sep 22 13:05:36 2005 @@ -1,1068 +0,0 @@ -/****************************************************************************** - * arch/xen/drivers/usbif/backend/main.c - * - * Backend for the Xen virtual USB driver - provides an abstraction of a - * USB host controller to the corresponding frontend driver. - * - * by Mark Williamson - * Copyright (c) 2004 Intel Research Cambridge - * Copyright (c) 2004, 2005 Mark Williamson - * - * Based on arch/xen/drivers/blkif/backend/main.c - * Copyright (c) 2003-2004, Keir Fraser & Steve Hand - */ - -#include "common.h" - - -#include <linux/list.h> -#include <linux/usb.h> -#include <linux/spinlock.h> -#include <linux/module.h> -#include <linux/tqueue.h> - -/* - * This is rather arbitrary. - */ -#define MAX_PENDING_REQS 4 -#define BATCH_PER_DOMAIN 1 - -static unsigned long mmap_vstart; - -/* Needs to be sufficiently large that we can map the (large) buffers - * the USB mass storage driver wants. */ -#define MMAP_PAGES_PER_REQUEST \ - (128) -#define MMAP_PAGES \ - (MAX_PENDING_REQS * MMAP_PAGES_PER_REQUEST) - -#define MMAP_VADDR(_req,_seg) \ - (mmap_vstart + \ - ((_req) * MMAP_PAGES_PER_REQUEST * PAGE_SIZE) + \ - ((_seg) * PAGE_SIZE)) - - -static spinlock_t owned_ports_lock; -LIST_HEAD(owned_ports); - -/* A list of these structures is used to track ownership of physical USB - * ports. */ -typedef struct -{ - usbif_priv_t *usbif_priv; - char path[16]; - int guest_port; - int enabled; - struct list_head list; - unsigned long guest_address; /* The USB device address that has been - * assigned by the guest. */ - int dev_present; /* Is there a device present? */ - struct usb_device * dev; - unsigned long ifaces; /* What interfaces are present on this device? */ -} owned_port_t; - - -/* - * Each outstanding request that we've passed to the lower device layers has a - * 'pending_req' allocated to it. The request is complete, the specified - * domain has a response queued for it, with the saved 'id' passed back. - */ -typedef struct { - usbif_priv_t *usbif_priv; - unsigned long id; - int nr_pages; - unsigned short operation; - int status; -} pending_req_t; - -/* - * We can't allocate pending_req's in order, since they may complete out of - * order. We therefore maintain an allocation ring. This ring also indicates - * when enough work has been passed down -- at that point the allocation ring - * will be empty. - */ -static pending_req_t pending_reqs[MAX_PENDING_REQS]; -static unsigned char pending_ring[MAX_PENDING_REQS]; -static spinlock_t pend_prod_lock; - -/* NB. We use a different index type to differentiate from shared usb rings. */ -typedef unsigned int PEND_RING_IDX; -#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1)) -static PEND_RING_IDX pending_prod, pending_cons; -#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons) - -static int do_usb_io_op(usbif_priv_t *usbif, int max_to_do); -static void make_response(usbif_priv_t *usbif, unsigned long id, - unsigned short op, int st, int inband, - unsigned long actual_length); -static void dispatch_usb_probe(usbif_priv_t *up, unsigned long id, unsigned long port); -static void dispatch_usb_io(usbif_priv_t *up, usbif_request_t *req); -static void dispatch_usb_reset(usbif_priv_t *up, unsigned long portid); -static owned_port_t *usbif_find_port(char *); - -/****************************************************************** - * PRIVATE DEBUG FUNCTIONS - */ - -#undef DEBUG -#ifdef DEBUG - -static void dump_port(owned_port_t *p) -{ - printk(KERN_DEBUG "owned_port_t @ %p\n" - " usbif_priv @ %p\n" - " path: %s\n" - " guest_port: %d\n" - " guest_address: %ld\n" - " dev_present: %d\n" - " dev @ %p\n" - " ifaces: 0x%lx\n", - p, p->usbif_priv, p->path, p->guest_port, p->guest_address, - p->dev_present, p->dev, p->ifaces); -} - - -static void dump_request(usbif_request_t *req) -{ - printk(KERN_DEBUG "id = 0x%lx\n" - "devnum %d\n" - "endpoint 0x%x\n" - "direction %d\n" - "speed %d\n" - "pipe_type 0x%x\n" - "transfer_buffer 0x%lx\n" - "length 0x%lx\n" - "transfer_flags 0x%lx\n" - "setup = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }\n" - "iso_schedule = 0x%lx\n" - "num_iso %ld\n", - req->id, req->devnum, req->endpoint, req->direction, req->speed, - req->pipe_type, req->transfer_buffer, req->length, - req->transfer_flags, req->setup[0], req->setup[1], req->setup[2], - req->setup[3], req->setup[4], req->setup[5], req->setup[6], - req->setup[7], req->iso_schedule, req->num_iso); -} - -static void dump_urb(struct urb *urb) -{ - printk(KERN_DEBUG "dumping urb @ %p\n", urb); - -#define DUMP_URB_FIELD(name, format) \ - printk(KERN_DEBUG " " # name " " format "\n", urb-> name) - - DUMP_URB_FIELD(pipe, "0x%x"); - DUMP_URB_FIELD(status, "%d"); - DUMP_URB_FIELD(transfer_flags, "0x%x"); - DUMP_URB_FIELD(transfer_buffer, "%p"); - DUMP_URB_FIELD(transfer_buffer_length, "%d"); - DUMP_URB_FIELD(actual_length, "%d"); -} - -static void dump_response(usbif_response_t *resp) -{ - printk(KERN_DEBUG "usbback: Sending response:\n" - " id = 0x%x\n" - " op = %d\n" - " status = %d\n" - " data = %d\n" - " length = %d\n", - resp->id, resp->op, resp->status, resp->data, resp->length); -} - -#else /* DEBUG */ - -#define dump_port(blah) ((void)0) -#define dump_request(blah) ((void)0) -#define dump_urb(blah) ((void)0) -#define dump_response(blah) ((void)0) - -#endif /* DEBUG */ - -/****************************************************************** - * MEMORY MANAGEMENT - */ - -static void fast_flush_area(int idx, int nr_pages) -{ - multicall_entry_t mcl[MMAP_PAGES_PER_REQUEST]; - int i; - - for ( i = 0; i < nr_pages; i++ ) - { - MULTI_update_va_mapping(mcl+i, MMAP_VADDR(idx, i), - __pte(0), 0); - } - - mcl[nr_pages-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL; - if ( unlikely(HYPERVISOR_multicall(mcl, nr_pages) != 0) ) - BUG(); -} - - -/****************************************************************** - * USB INTERFACE SCHEDULER LIST MAINTENANCE - */ - -static struct list_head usbio_schedule_list; -static spinlock_t usbio_schedule_list_lock; - -static int __on_usbif_list(usbif_priv_t *up) -{ - return up->usbif_list.next != NULL; -} - -void remove_from_usbif_list(usbif_priv_t *up) -{ - unsigned long flags; - if ( !__on_usbif_list(up) ) return; - spin_lock_irqsave(&usbio_schedule_list_lock, flags); - if ( __on_usbif_list(up) ) - { - list_del(&up->usbif_list); - up->usbif_list.next = NULL; - usbif_put(up); - } - spin_unlock_irqrestore(&usbio_schedule_list_lock, flags); -} - -static void add_to_usbif_list_tail(usbif_priv_t *up) -{ - unsigned long flags; - if ( __on_usbif_list(up) ) return; - spin_lock_irqsave(&usbio_schedule_list_lock, flags); - if ( !__on_usbif_list(up) && (up->status == CONNECTED) ) - { - list_add_tail(&up->usbif_list, &usbio_schedule_list); - usbif_get(up); - } - spin_unlock_irqrestore(&usbio_schedule_list_lock, flags); -} - -void free_pending(int pending_idx) -{ - unsigned long flags; - - /* Free the pending request. */ - spin_lock_irqsave(&pend_prod_lock, flags); - pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; - spin_unlock_irqrestore(&pend_prod_lock, flags); -} - -/****************************************************************** - * COMPLETION CALLBACK -- Called as urb->complete() - */ - -static void maybe_trigger_usbio_schedule(void); - -static void __end_usb_io_op(struct urb *purb) -{ - pending_req_t *pending_req; - int pending_idx; - - pending_req = purb->context; - - pending_idx = pending_req - pending_reqs; - - ASSERT(purb->actual_length <= purb->transfer_buffer_length); - ASSERT(purb->actual_length <= pending_req->nr_pages * PAGE_SIZE); - - /* An error fails the entire request. */ - if ( purb->status ) - { - printk(KERN_WARNING "URB @ %p failed. Status %d\n", purb, purb->status); - } - - if ( usb_pipetype(purb->pipe) == 0 ) - { - int i; - usbif_iso_t *sched = (usbif_iso_t *)MMAP_VADDR(pending_idx, pending_req->nr_pages - 1); - - /* If we're dealing with an iso pipe, we need to copy back the schedule. */ - for ( i = 0; i < purb->number_of_packets; i++ ) - { - sched[i].length = purb->iso_frame_desc[i].actual_length; - ASSERT(sched[i].buffer_offset == - purb->iso_frame_desc[i].offset); - sched[i].status = purb->iso_frame_desc[i].status; - } - } - - fast_flush_area(pending_req - pending_reqs, pending_req->nr_pages); - - kfree(purb->setup_packet); - - make_response(pending_req->usbif_priv, pending_req->id, - pending_req->operation, pending_req->status, 0, purb->actual_length); - usbif_put(pending_req->usbif_priv); - - usb_free_urb(purb); - - free_pending(pending_idx); - - rmb(); - - /* Check for anything still waiting in the rings, having freed a request... */ - maybe_trigger_usbio_schedule(); -} - -/****************************************************************** - * SCHEDULER FUNCTIONS - */ - -static DECLARE_WAIT_QUEUE_HEAD(usbio_schedule_wait); - -static int usbio_schedule(void *arg) -{ - DECLARE_WAITQUEUE(wq, current); - - usbif_priv_t *up; - struct list_head *ent; - - daemonize(); - - for ( ; ; ) - { - /* Wait for work to do. */ - add_wait_queue(&usbio_schedule_wait, &wq); - set_current_state(TASK_INTERRUPTIBLE); - if ( (NR_PENDING_REQS == MAX_PENDING_REQS) || - list_empty(&usbio_schedule_list) ) - schedule(); - __set_current_state(TASK_RUNNING); - remove_wait_queue(&usbio_schedule_wait, &wq); - - /* Queue up a batch of requests. */ - while ( (NR_PENDING_REQS < MAX_PENDING_REQS) && - !list_empty(&usbio_schedule_list) ) - { - ent = usbio_schedule_list.next; - up = list_entry(ent, usbif_priv_t, usbif_list); - usbif_get(up); - remove_from_usbif_list(up); - if ( do_usb_io_op(up, BATCH_PER_DOMAIN) ) - add_to_usbif_list_tail(up); - usbif_put(up); - } - } -} - -static void maybe_trigger_usbio_schedule(void) -{ - /* - * Needed so that two processes, who together make the following predicate - * true, don't both read stale values and evaluate the predicate - * incorrectly. Incredibly unlikely to stall the scheduler on x86, but... - */ - smp_mb(); - - if ( !list_empty(&usbio_schedule_list) ) - wake_up(&usbio_schedule_wait); -} - - -/****************************************************************************** - * NOTIFICATION FROM GUEST OS. - */ - -irqreturn_t usbif_be_int(int irq, void *dev_id, struct pt_regs *regs) -{ - usbif_priv_t *up = dev_id; - - smp_mb(); - - add_to_usbif_list_tail(up); - - /* Will in fact /always/ trigger an io schedule in this case. */ - maybe_trigger_usbio_schedule(); - - return IRQ_HANDLED; -} - - - -/****************************************************************** - * DOWNWARD CALLS -- These interface with the usb-device layer proper. - */ - -static int do_usb_io_op(usbif_priv_t *up, int max_to_do) -{ - usbif_back_ring_t *usb_ring = &up->usb_ring; - usbif_request_t *req; - RING_IDX i, rp; - int more_to_do = 0; - - rp = usb_ring->sring->req_prod; - rmb(); /* Ensure we see queued requests up to 'rp'. */ - - /* Take items off the comms ring, taking care not to overflow. */ - for ( i = usb_ring->req_cons; - (i != rp) && !RING_REQUEST_CONS_OVERFLOW(usb_ring, i); - i++ ) - { - if ( (max_to_do-- == 0) || (NR_PENDING_REQS == MAX_PENDING_REQS) ) - { - more_to_do = 1; - break; - } - - req = RING_GET_REQUEST(usb_ring, i); - - switch ( req->operation ) - { - case USBIF_OP_PROBE: - dispatch_usb_probe(up, req->id, req->port); - break; - - case USBIF_OP_IO: - /* Assemble an appropriate URB. */ - dispatch_usb_io(up, req); - break; - - case USBIF_OP_RESET: - dispatch_usb_reset(up, req->port); - break; - - default: - DPRINTK("error: unknown USB io operation [%d]\n", - req->operation); - make_response(up, req->id, req->operation, -EINVAL, 0, 0); - break; - } - } - - usb_ring->req_cons = i; - - return more_to_do; -} - -static owned_port_t *find_guest_port(usbif_priv_t *up, int port) -{ - unsigned long flags; - struct list_head *l; - - spin_lock_irqsave(&owned_ports_lock, flags); - list_for_each(l, &owned_ports) - { - owned_port_t *p = list_entry(l, owned_port_t, list); - if(p->usbif_priv == up && p->guest_port == port) - { - spin_unlock_irqrestore(&owned_ports_lock, flags); - return p; - } - } - spin_unlock_irqrestore(&owned_ports_lock, flags); - - return NULL; -} - -static void dispatch_usb_reset(usbif_priv_t *up, unsigned long portid) -{ - owned_port_t *port = find_guest_port(up, portid); - int ret = 0; - - - /* Allowing the guest to actually reset the device causes more problems - * than it's worth. We just fake it out in software but we will do a real - * reset when the interface is destroyed. */ - - dump_port(port); - - port->guest_address = 0; - /* If there's an attached device then the port is now enabled. */ - if ( port->dev_present ) - port->enabled = 1; - else - port->enabled = 0; - - make_response(up, 0, USBIF_OP_RESET, ret, 0, 0); -} - -static void dispatch_usb_probe(usbif_priv_t *up, unsigned long id, unsigned long portid) -{ - owned_port_t *port = find_guest_port(up, portid); - int ret; - - if ( port != NULL ) - ret = port->dev_present; - else - { - ret = -EINVAL; - printk(KERN_INFO "dispatch_usb_probe(): invalid port probe request " - "(port %ld)\n", portid); - } - - /* Probe result is sent back in-band. Probes don't have an associated id - * right now... */ - make_response(up, id, USBIF_OP_PROBE, ret, portid, 0); -} - -/** - * check_iso_schedule - safety check the isochronous schedule for an URB - * @purb : the URB in question - */ -static int check_iso_schedule(struct urb *purb) -{ - int i; - unsigned long total_length = 0; - - for ( i = 0; i < purb->number_of_packets; i++ ) - { - struct usb_iso_packet_descriptor *desc = &purb->iso_frame_desc[i]; - - if ( desc->offset >= purb->transfer_buffer_length - || ( desc->offset + desc->length) > purb->transfer_buffer_length ) - return -EINVAL; - - total_length += desc->length; - - if ( total_length > purb->transfer_buffer_length ) - return -EINVAL; - } - - return 0; -} - -owned_port_t *find_port_for_request(usbif_priv_t *up, usbif_request_t *req); - -static void dispatch_usb_io(usbif_priv_t *up, usbif_request_t *req) -{ - unsigned long buffer_mach; - int i = 0, offset = 0, - pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)]; - pending_req_t *pending_req; - unsigned long remap_prot; - multicall_entry_t mcl[MMAP_PAGES_PER_REQUEST]; - struct urb *purb = NULL; - owned_port_t *port; - unsigned char *setup; - - dump_request(req); - - if ( NR_PENDING_REQS == MAX_PENDING_REQS ) - { - printk(KERN_WARNING "usbback: Max requests already queued. " - "Giving up!\n"); - - return; - } - - port = find_port_for_request(up, req); - - if ( port == NULL ) - { - printk(KERN_WARNING "No such device! (%d)\n", req->devnum); - dump_request(req); - - make_response(up, req->id, req->operation, -ENODEV, 0, 0); - return; - } - else if ( !port->dev_present ) - { - /* In normal operation, we'll only get here if a device is unplugged - * and the frontend hasn't noticed yet. */ - make_response(up, req->id, req->operation, -ENODEV, 0, 0); - return; - } - - - setup = kmalloc(8, GFP_KERNEL); - - if ( setup == NULL ) - goto no_mem; - - /* Copy request out for safety. */ - memcpy(setup, req->setup, 8); - - if( setup[0] == 0x0 && setup[1] == 0x5) - { - /* To virtualise the USB address space, we need to intercept - * set_address messages and emulate. From the USB specification: - * bmRequestType = 0x0; - * Brequest = SET_ADDRESS (i.e. 0x5) - * wValue = device address - * wIndex = 0 - * wLength = 0 - * data = None - */ - /* Store into the guest transfer buffer using cpu_to_le16 */ - port->guest_address = le16_to_cpu(*(u16 *)(setup + 2)); - /* Make a successful response. That was easy! */ - - make_response(up, req->id, req->operation, 0, 0, 0); - - kfree(setup); - return; - } - else if ( setup[0] == 0x0 && setup[1] == 0x9 ) - { - /* The host kernel needs to know what device configuration is in use - * because various error checks get confused otherwise. We just do - * configuration settings here, under controlled conditions. - */ - - /* Ignore configuration setting and hope that the host kernel - did it right. */ - /* usb_set_configuration(port->dev, setup[2]); */ - - make_response(up, req->id, req->operation, 0, 0, 0); - - kfree(setup); - return; - } - else if ( setup[0] == 0x1 && setup[1] == 0xB ) - { - /* The host kernel needs to know what device interface is in use - * because various error checks get confused otherwise. We just do - * configuration settings here, under controlled conditions. - */ - usb_set_interface(port->dev, (setup[4] | setup[5] << 8), - (setup[2] | setup[3] << 8) ); - - make_response(up, req->id, req->operation, 0, 0, 0); - - kfree(setup); - return; - } - - if ( ( req->transfer_buffer - (req->transfer_buffer & PAGE_MASK) - + req->length ) - > MMAP_PAGES_PER_REQUEST * PAGE_SIZE ) - { - printk(KERN_WARNING "usbback: request of %lu bytes too large\n", - req->length); - make_response(up, req->id, req->operation, -EINVAL, 0, 0); - kfree(setup); - return; - } - - buffer_mach = req->transfer_buffer; - - if( buffer_mach == 0 ) - goto no_remap; - - ASSERT((req->length >> PAGE_SHIFT) <= MMAP_PAGES_PER_REQUEST); - ASSERT(buffer_mach); - - /* Always map writeable for now. */ - remap_prot = _KERNPG_TABLE; - - for ( i = 0, offset = 0; offset < req->length; - i++, offset += PAGE_SIZE ) - { - MULTI_update_va_mapping_otherdomain( - mcl+i, MMAP_VADDR(pending_idx, i), - pfn_pte_ma((buffer_mach + offset) >> PAGE_SHIFT, remap_prot), - 0, up->domid); - - phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] = - FOREIGN_FRAME((buffer_mach + offset) >> PAGE_SHIFT); - - ASSERT(virt_to_mfn(MMAP_VADDR(pending_idx, i)) - == ((buffer_mach >> PAGE_SHIFT) + i)); - } - - if ( req->pipe_type == 0 && req->num_iso > 0 ) /* Maybe schedule ISO... */ - { - /* Map in ISO schedule, if necessary. */ - MULTI_update_va_mapping_otherdomain( - mcl+i, MMAP_VADDR(pending_idx, i), - pfn_pte_ma(req->iso_schedule >> PAGE_SHIFT, remap_prot), - 0, up->domid); - - phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] = - FOREIGN_FRAME(req->iso_schedule >> PAGE_SHIFT); - - i++; - } - - if ( unlikely(HYPERVISOR_multicall(mcl, i) != 0) ) - BUG(); - - { - int j; - for ( j = 0; j < i; j++ ) - { - if ( unlikely(mcl[j].result != 0) ) - { - printk(KERN_WARNING - "invalid buffer %d -- could not remap it\n", j); - fast_flush_area(pending_idx, i); - goto bad_descriptor; - } - } - } - - no_remap: - - ASSERT(i <= MMAP_PAGES_PER_REQUEST); - ASSERT(i * PAGE_SIZE >= req->length); - - /* We have to do this because some things might complete out of order. */ - pending_req = &pending_reqs[pending_idx]; - pending_req->usbif_priv= up; - pending_req->id = req->id; - pending_req->operation = req->operation; - pending_req->nr_pages = i; - - pending_cons++; - - usbif_get(up); - - /* Fill out an actual request for the USB layer. */ - purb = usb_alloc_urb(req->num_iso); - - if ( purb == NULL ) - { - usbif_put(up); - free_pending(pending_idx); - goto no_mem; - } - - purb->dev = port->dev; - purb->context = pending_req; - purb->transfer_buffer = - (void *)(MMAP_VADDR(pending_idx, 0) + (buffer_mach & ~PAGE_MASK)); - if(buffer_mach == 0) - purb->transfer_buffer = NULL; - purb->complete = __end_usb_io_op; - purb->transfer_buffer_length = req->length; - purb->transfer_flags = req->transfer_flags; - - purb->pipe = 0; - purb->pipe |= req->direction << 7; - purb->pipe |= port->dev->devnum << 8; - purb->pipe |= req->speed << 26; - purb->pipe |= req->pipe_type << 30; - purb->pipe |= req->endpoint << 15; - - purb->number_of_packets = req->num_iso; - - if ( purb->number_of_packets * sizeof(usbif_iso_t) > PAGE_SIZE ) - goto urb_error; - - /* Make sure there's always some kind of timeout. */ - purb->timeout = ( req->timeout > 0 ) ? (req->timeout * HZ) / 1000 - : 1000; - - purb->setup_packet = setup; - - if ( req->pipe_type == 0 ) /* ISO */ - { - int j; - usbif_iso_t *iso_sched = (usbif_iso_t *)MMAP_VADDR(pending_idx, i - 1); - - /* If we're dealing with an iso pipe, we need to copy in a schedule. */ - for ( j = 0; j < purb->number_of_packets; j++ ) - { - purb->iso_frame_desc[j].length = iso_sched[j].length; - purb->iso_frame_desc[j].offset = iso_sched[j].buffer_offset; - iso_sched[j].status = 0; - } - } - - if ( check_iso_schedule(purb) != 0 ) - goto urb_error; - - if ( usb_submit_urb(purb) != 0 ) - goto urb_error; - - return; - - urb_error: - dump_urb(purb); - usbif_put(up); - free_pending(pending_idx); - - bad_descriptor: - kfree ( setup ); - if ( purb != NULL ) - usb_free_urb(purb); - make_response(up, req->id, req->operation, -EINVAL, 0, 0); - return; - - no_mem: - if ( setup != NULL ) - kfree(setup); - make_response(up, req->id, req->operation, -ENOMEM, 0, 0); - return; -} - - - -/****************************************************************** - * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING - */ - - -static void make_response(usbif_priv_t *up, unsigned long id, - unsigned short op, int st, int inband, - unsigned long length) -{ - usbif_response_t *resp; - unsigned long flags; - usbif_back_ring_t *usb_ring = &up->usb_ring; - - /* Place on the response ring for the relevant domain. */ - spin_lock_irqsave(&up->usb_ring_lock, flags); - resp = RING_GET_RESPONSE(usb_ring, usb_ring->rsp_prod_pvt); - resp->id = id; - resp->operation = op; - resp->status = st; - resp->data = inband; - resp->length = length; - wmb(); /* Ensure other side can see the response fields. */ - - dump_response(resp); - - usb_ring->rsp_prod_pvt++; - RING_PUSH_RESPONSES(usb_ring); - spin_unlock_irqrestore(&up->usb_ring_lock, flags); - - /* Kick the relevant domain. */ - notify_via_evtchn(up->evtchn); -} - -/** - * usbif_claim_port - claim devices on a port on behalf of guest - * - * Once completed, this will ensure that any device attached to that - * port is claimed by this driver for use by the guest. - */ -int usbif_claim_port(usbif_be_claim_port_t *msg) -{ - owned_port_t *o_p; - - /* Sanity... */ - if ( usbif_find_port(msg->path) != NULL ) - { - printk(KERN_WARNING "usbback: Attempted to claim USB port " - "we already own!\n"); - return -EINVAL; - } - - /* No need for a slab cache - this should be infrequent. */ - o_p = kmalloc(sizeof(owned_port_t), GFP_KERNEL); - - if ( o_p == NULL ) - return -ENOMEM; - - o_p->enabled = 0; - o_p->usbif_priv = usbif_find(msg->domid); - o_p->guest_port = msg->usbif_port; - o_p->dev_present = 0; - o_p->guest_address = 0; /* Default address. */ - - strcpy(o_p->path, msg->path); - - spin_lock_irq(&owned_ports_lock); - - list_add(&o_p->list, &owned_ports); - - spin_unlock_irq(&owned_ports_lock); - - printk(KERN_INFO "usbback: Claimed USB port (%s) for %d.%d\n", o_p->path, - msg->domid, msg->usbif_port); - - /* Force a reprobe for unclaimed devices. */ - usb_scan_devices(); - - return 0; -} - -owned_port_t *find_port_for_request(usbif_priv_t *up, usbif_request_t *req) -{ - unsigned long flags; - struct list_head *port; - - /* I'm assuming this is not called from IRQ context - correct? I think - * it's probably only called in response to control messages or plug events - * in the USB hub kernel thread, so should be OK. */ - spin_lock_irqsave(&owned_ports_lock, flags); - list_for_each(port, &owned_ports) - { - owned_port_t *p = list_entry(port, owned_port_t, list); - if(p->usbif_priv == up && p->guest_address == req->devnum && p->enabled ) - { - dump_port(p); - - spin_unlock_irqrestore(&owned_ports_lock, flags); - return p; - } - } - spin_unlock_irqrestore(&owned_ports_lock, flags); - - return NULL; -} - -owned_port_t *__usbif_find_port(char *path) -{ - struct list_head *port; - - list_for_each(port, &owned_ports) - { - owned_port_t *p = list_entry(port, owned_port_t, list); - if(!strcmp(path, p->path)) - { - return p; - } - } - - return NULL; -} - -owned_port_t *usbif_find_port(char *path) -{ - owned_port_t *ret; - unsigned long flags; - - spin_lock_irqsave(&owned_ports_lock, flags); - ret = __usbif_find_port(path); - spin_unlock_irqrestore(&owned_ports_lock, flags); - - return ret; -} - - -static void *probe(struct usb_device *dev, unsigned iface, - const struct usb_device_id *id) -{ - owned_port_t *p; - - /* We don't care what the device is - if we own the port, we want it. We - * don't deal with device-specifics in this driver, so we don't care what - * the device actually is ;-) */ - if ( ( p = usbif_find_port(dev->devpath) ) != NULL ) - { - printk(KERN_INFO "usbback: claimed device attached to owned port\n"); - - p->dev_present = 1; - p->dev = dev; - set_bit(iface, &p->ifaces); - - return p->usbif_priv; - } - else - printk(KERN_INFO "usbback: hotplug for non-owned port (%s), ignoring\n", - dev->devpath); - - - return NULL; -} - -static void disconnect(struct usb_device *dev, void *usbif) -{ - /* Note the device is removed so we can tell the guest when it probes. */ - owned_port_t *port = usbif_find_port(dev->devpath); - port->dev_present = 0; - port->dev = NULL; - port->ifaces = 0; -} - - -struct usb_driver driver = -{ - .owner = THIS_MODULE, - .name = "Xen USB Backend", - .probe = probe, - .disconnect = disconnect, - .id_table = NULL, -}; - -/* __usbif_release_port - internal mechanics for releasing a port */ -void __usbif_release_port(owned_port_t *p) -{ - int i; - - for ( i = 0; p->ifaces != 0; i++) - if ( p->ifaces & 1 << i ) - { - usb_driver_release_interface(&driver, usb_ifnum_to_if(p->dev, i)); - clear_bit(i, &p->ifaces); - } - list_del(&p->list); - - /* Reset the real device. We don't simulate disconnect / probe for other - * drivers in this kernel because we assume the device is completely under - * the control of ourselves (i.e. the guest!). This should ensure that the - * device is in a sane state for the next customer ;-) */ - - /* MAW NB: we're not resetting the real device here. This looks perfectly - * valid to me but it causes memory corruption. We seem to get away with not - * resetting for now, although it'd be nice to have this tracked down. */ -/* if ( p->dev != NULL) */ -/* usb_reset_device(p->dev); */ - - kfree(p); -} - - -/** - * usbif_release_port - stop claiming devices on a port on behalf of guest - */ -void usbif_release_port(usbif_be_release_port_t *msg) -{ - owned_port_t *p; - - spin_lock_irq(&owned_ports_lock); - p = __usbif_find_port(msg->path); - __usbif_release_port(p); - spin_unlock_irq(&owned_ports_lock); -} - -void usbif_release_ports(usbif_priv_t *up) -{ - struct list_head *port, *tmp; - unsigned long flags; - - spin_lock_irqsave(&owned_ports_lock, flags); - list_for_each_safe(port, tmp, &owned_ports) - { - owned_port_t *p = list_entry(port, owned_port_t, list); - if ( p->usbif_priv == up ) - __usbif_release_port(p); - } - spin_unlock_irqrestore(&owned_ports_lock, flags); -} - -static int __init usbif_init(void) -{ - int i; - struct page *page; - - if ( !(xen_start_info->flags & SIF_INITDOMAIN) && - !(xen_start_info->flags & SIF_USB_BE_DOMAIN) ) - return 0; - - page = balloon_alloc_empty_page_range(MMAP_PAGES); - BUG_ON(page == NULL); - mmap_vstart = (unsigned long)pfn_to_kaddr(page_to_pfn(page)); - - pending_cons = 0; - pending_prod = MAX_PENDING_REQS; - memset(pending_reqs, 0, sizeof(pending_reqs)); - for ( i = 0; i < MAX_PENDING_REQS; i++ ) - pending_ring[i] = i; - - spin_lock_init(&pend_prod_lock); - - spin_lock_init(&owned_ports_lock); - INIT_LIST_HEAD(&owned_ports); - - spin_lock_init(&usbio_schedule_list_lock); - INIT_LIST_HEAD(&usbio_schedule_list); - - if ( kernel_thread(usbio_schedule, 0, CLONE_FS | CLONE_FILES) < 0 ) - BUG(); - - usbif_interface_init(); - - usbif_ctrlif_init(); - - usb_register(&driver); - - printk(KERN_INFO "Xen USB Backend Initialised"); - - return 0; -} - -__initcall(usbif_init); diff -r d7c794130ac5 -r ecc77b1c8612 linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront.c --- a/linux-2.6-xen-sparse/drivers/xen/usbfront/usbfront.c Thu Sep 22 13:04:14 2005 +++ /dev/null Thu Sep 22 13:05:36 2005 @@ -1,1735 +0,0 @@ -/* - * 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 <mark.williamson@xxxxxxxxxxxx> or - * <xen-devel@xxxxxxxxxxxxxxxxxxxxx> 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 <johannes@xxxxxxxxxxx> - * - * (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 <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/smp_lock.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#ifdef CONFIG_USB_DEBUG -#define DEBUG -#else -#undef DEBUG -#endif -#include <linux/usb.h> - -#include <asm/irq.h> -#include <asm/system.h> - -#include "xhci.h" - -#include "../../../../../drivers/usb/hcd.h" - -#include <asm-xen/xen-public/io/usbif.h> -#include <asm/xen-public/io/domain_controller.h> - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.0" -#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, " \ - "Randy Dunlap, Georg Acher, Deti Fliegl, " \ - "Thomas Sailer, Roman Weissgaerber, Mark Williamson" -#define DRIVER_DESC "Xen Virtual USB Host Controller Interface" - -/* - * debug = 0, no debugging messages - * debug = 1, dump failed URB's except for stalls - * debug = 2, dump all failed URB's (including stalls) - */ -#ifdef DEBUG -static int debug = 1; -#else -static int debug = 0; -#endif -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debug level"); -static char *errbuf; -#define ERRBUF_LEN (PAGE_SIZE * 8) - -static int rh_submit_urb(struct urb *urb); -static int rh_unlink_urb(struct urb *urb); -static int xhci_unlink_urb(struct urb *urb); -static void xhci_call_completion(struct urb *urb); -static void xhci_drain_ring(void); -static void xhci_transfer_result(struct xhci *xhci, struct urb *urb); -static void xhci_finish_completion(void); - -#define MAX_URB_LOOP 2048 /* Maximum number of linked URB's */ - -static kmem_cache_t *xhci_up_cachep; /* urb_priv cache */ -static struct xhci *xhci; /* XHCI structure for the interface */ - -/****************************************************************************** - * DEBUGGING - */ - -#ifdef DEBUG - -static void dump_urb(struct urb *urb) -{ - printk(KERN_DEBUG "dumping urb @ %p\n" - " hcpriv = %p\n" - " next = %p\n" - " dev = %p\n" - " pipe = 0x%lx\n" - " status = %d\n" - " transfer_flags = 0x%lx\n" - " transfer_buffer = %p\n" - " transfer_buffer_length = %d\n" - " actual_length = %d\n" - " bandwidth = %d\n" - " setup_packet = %p\n", - urb, urb->hcpriv, urb->next, urb->dev, urb->pipe, urb->status, - urb->transfer_flags, urb->transfer_buffer, - urb->transfer_buffer_length, urb->actual_length, urb->bandwidth, - urb->setup_packet); - if ( urb->setup_packet != NULL ) - printk(KERN_DEBUG - "setup = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }\n", - urb->setup_packet[0], urb->setup_packet[1], - urb->setup_packet[2], urb->setup_packet[3], - urb->setup_packet[4], urb->setup_packet[5], - urb->setup_packet[6], urb->setup_packet[7]); - printk(KERN_DEBUG "complete = %p\n" - "interval = %d\n", urb->complete, urb->interval); - -} - -static void xhci_show_resp(usbif_response_t *r) -{ - printk(KERN_DEBUG "dumping response @ %p\n" - " id=0x%lx\n" - " op=0x%x\n" - " data=0x%x\n" - " status=0x%x\n" - " length=0x%lx\n", - r->id, r->operation, r->data, r->status, r->length); -} - -#define DPRINK(...) printk(KERN_DEBUG __VA_ARGS__) - -#else /* DEBUG */ - -#define dump_urb(blah) ((void)0) -#define xhci_show_resp(blah) ((void)0) -#define DPRINTK(blah,...) ((void)0) - -#endif /* DEBUG */ - -/****************************************************************************** - * RING REQUEST HANDLING - */ - -#define RING_PLUGGED(_hc) ( RING_FULL(&_hc->usb_ring) || _hc->recovery ) - -/** - * xhci_construct_isoc - add isochronous information to a request - */ -static int xhci_construct_isoc(usbif_request_t *req, struct urb *urb) -{ - usbif_iso_t *schedule; - int i; - struct urb_priv *urb_priv = urb->hcpriv; - - req->num_iso = urb->number_of_packets; - schedule = (usbif_iso_t *)__get_free_page(GFP_KERNEL); - - if ( schedule == NULL ) - return -ENOMEM; - - for ( i = 0; i < req->num_iso; i++ ) - { - schedule[i].buffer_offset = urb->iso_frame_desc[i].offset; - schedule[i].length = urb->iso_frame_desc[i].length; - } - - urb_priv->schedule = schedule; - req->iso_schedule = virt_to_mfn(schedule) << PAGE_SHIFT; - - return 0; -} - -/** - * xhci_queue_req - construct and queue request for an URB - */ -static int xhci_queue_req(struct urb *urb) -{ - unsigned long flags; - usbif_request_t *req; - usbif_front_ring_t *usb_ring = &xhci->usb_ring; - -#if DEBUG - printk(KERN_DEBUG - "usbif = %p, req_prod = %d (@ 0x%lx), resp_prod = %d, resp_cons = %d\n", - usbif, usbif->req_prod, virt_to_mfn(&usbif->req_prod), - usbif->resp_prod, xhci->usb_resp_cons); -#endif - - spin_lock_irqsave(&xhci->ring_lock, flags); - - if ( RING_PLUGGED(xhci) ) - { - printk(KERN_WARNING - "xhci_queue_req(): USB ring plugged, not queuing request\n"); - spin_unlock_irqrestore(&xhci->ring_lock, flags); - return -ENOBUFS; - } - - /* Stick something in the shared communications ring. */ - req = RING_GET_REQUEST(usb_ring, usb_ring->req_prod_pvt); - - req->operation = USBIF_OP_IO; - req->port = 0; /* We don't care what the port is. */ - req->id = (unsigned long) urb->hcpriv; - req->transfer_buffer = virt_to_mfn(urb->transfer_buffer) << PAGE_SHIFT; - req->devnum = usb_pipedevice(urb->pipe); - req->direction = usb_pipein(urb->pipe); - req->speed = usb_pipeslow(urb->pipe); - req->pipe_type = usb_pipetype(urb->pipe); - req->length = urb->transfer_buffer_length; - req->transfer_flags = urb->transfer_flags; - req->endpoint = usb_pipeendpoint(urb->pipe); - req->speed = usb_pipeslow(urb->pipe); - req->timeout = urb->timeout * (1000 / HZ); - - if ( usb_pipetype(urb->pipe) == 0 ) /* ISO */ - { - int ret = xhci_construct_isoc(req, urb); - if ( ret != 0 ) - return ret; - } - - if(urb->setup_packet != NULL) - memcpy(req->setup, urb->setup_packet, 8); - else - memset(req->setup, 0, 8); - - usb_ring->req_prod_pvt++; - RING_PUSH_REQUESTS(usb_ring); - - spin_unlock_irqrestore(&xhci->ring_lock, flags); - - notify_via_evtchn(xhci->evtchn); - - DPRINTK("Queued request for an URB.\n"); - dump_urb(urb); - - return -EINPROGRESS; -} - -/** - * xhci_queue_probe - queue a probe request for a particular port - */ -static inline usbif_request_t *xhci_queue_probe(usbif_vdev_t port) -{ - usbif_request_t *req; - usbif_front_ring_t *usb_ring = &xhci->usb_ring; - -#if DEBUG - printk(KERN_DEBUG - "queuing probe: req_prod = %d (@ 0x%lx), resp_prod = %d, " - "resp_cons = %d\n", usbif->req_prod, - virt_to_mfn(&usbif->req_prod), - usbif->resp_prod, xhci->usb_resp_cons); -#endif - - /* This is always called from the timer interrupt. */ - spin_lock(&xhci->ring_lock); - - if ( RING_PLUGGED(xhci) ) - { - printk(KERN_WARNING - "xhci_queue_probe(): ring full, not queuing request\n"); - spin_unlock(&xhci->ring_lock); - return NULL; - } - - /* Stick something in the shared communications ring. */ - req = RING_GET_REQUEST(usb_ring, usb_ring->req_prod_pvt); - - memset(req, 0, sizeof(*req)); - - req->operation = USBIF_OP_PROBE; - req->port = port; - - usb_ring->req_prod_pvt++; - RING_PUSH_REQUESTS(usb_ring); - - spin_unlock(&xhci->ring_lock); - - notify_via_evtchn(xhci->evtchn); - - return req; -} - -/** - * xhci_port_reset - queue a reset request for a particular port - */ -static int xhci_port_reset(usbif_vdev_t port) -{ - usbif_request_t *req; - usbif_front_ring_t *usb_ring = &xhci->usb_ring; - - /* Only ever happens from process context (hub thread). */ - spin_lock_irq(&xhci->ring_lock); - - if ( RING_PLUGGED(xhci) ) - { - printk(KERN_WARNING - "xhci_port_reset(): ring plugged, not queuing request\n"); - spin_unlock_irq(&xhci->ring_lock); - return -ENOBUFS; - } - - /* We only reset one port at a time, so we only need one variable per - * hub. */ - xhci->awaiting_reset = 1; - - /* Stick something in the shared communications ring. */ - req = RING_GET_REQUEST(usb_ring, usb_ring->req_prod_pvt); - - memset(req, 0, sizeof(*req)); - - req->operation = USBIF_OP_RESET; - req->port = port; - - usb_ring->req_prod_pvt++; - RING_PUSH_REQUESTS(usb_ring); - - spin_unlock_irq(&xhci->ring_lock); - - notify_via_evtchn(xhci->evtchn); - - while ( xhci->awaiting_reset > 0 ) - { - mdelay(1); - xhci_drain_ring(); - } - - xhci->rh.ports[port].pe = 1; - xhci->rh.ports[port].pe_chg = 1; - - return xhci->awaiting_reset; -} - - -/****************************************************************************** - * RING RESPONSE HANDLING - */ - -static void receive_usb_reset(usbif_response_t *resp) -{ - xhci->awaiting_reset = resp->status; - rmb(); - -} - -static void receive_usb_probe(usbif_response_t *resp) -{ - spin_lock(&xhci->rh.port_state_lock); - - if ( resp->status >= 0 ) - { - if ( resp->status == 1 ) - { - /* If theres a device there and there wasn't one before there must - * have been a connection status change. */ - if( xhci->rh.ports[resp->data].cs == 0 ) - { - xhci->rh.ports[resp->data].cs = 1; - xhci->rh.ports[resp->data].cs_chg = 1; - } - } - else if ( resp->status == 0 ) - { - if(xhci->rh.ports[resp->data].cs == 1 ) - { - xhci->rh.ports[resp->data].cs = 0; - xhci->rh.ports[resp->data].cs_chg = 1; - xhci->rh.ports[resp->data].pe = 0; - /* According to USB Spec v2.0, 11.24.2.7.2.2, we don't need - * to set pe_chg since an error has not occurred. */ - } - } - else - printk(KERN_WARNING "receive_usb_probe(): unexpected status %d " - "for port %d\n", resp->status, resp->data); - } - else if ( resp->status < 0) - printk(KERN_WARNING "receive_usb_probe(): got error status %d\n", - resp->status); - - spin_unlock(&xhci->rh.port_state_lock); -} - -static void receive_usb_io(usbif_response_t *resp) -{ - struct urb_priv *urbp = (struct urb_priv *)resp->id; - struct urb *urb = urbp->urb; - - urb->actual_length = resp->length; - urbp->in_progress = 0; - - if( usb_pipetype(urb->pipe) == 0 ) /* ISO */ - { - int i; - - /* Copy ISO schedule results back in. */ - for ( i = 0; i < urb->number_of_packets; i++ ) - { - urb->iso_frame_desc[i].status - = urbp->schedule[i].status; - urb->iso_frame_desc[i].actual_length - = urbp->schedule[i].length; - } - free_page((unsigned long)urbp->schedule); - } - - /* Only set status if it's not been changed since submission. It might - * have been changed if the URB has been unlinked asynchronously, for - * instance. */ - if ( urb->status == -EINPROGRESS ) - urbp->status = urb->status = resp->status; -} - -/** - * xhci_drain_ring - drain responses from the ring, calling handlers - * - * This may be called from interrupt context when an event is received from the - * backend domain, or sometimes in process context whilst waiting for a port - * reset or URB completion. - */ -static void xhci_drain_ring(void) -{ - struct list_head *tmp, *head; - usbif_front_ring_t *usb_ring = &xhci->usb_ring; - usbif_response_t *resp; - RING_IDX i, rp; - - /* Walk the ring here to get responses, updating URBs to show what - * completed. */ - - rp = usb_ring->sring->rsp_prod; - rmb(); /* Ensure we see queued requests up to 'rp'. */ - - /* Take items off the comms ring, taking care not to overflow. */ - for ( i = usb_ring->rsp_cons; i != rp; i++ ) - { - resp = RING_GET_RESPONSE(usb_ring, i); - - /* May need to deal with batching and with putting a ceiling on - the number dispatched for performance and anti-dos reasons */ - - xhci_show_resp(resp); - - switch ( resp->operation ) - { - case USBIF_OP_PROBE: - receive_usb_probe(resp); - break; - - case USBIF_OP_IO: - receive_usb_io(resp); - break; - - case USBIF_OP_RESET: - receive_usb_reset(resp); - break; - - default: - printk(KERN_WARNING - "error: unknown USB io operation response [%d]\n", - resp->operation); - break; - } - } - - usb_ring->rsp_cons = i; - - /* Walk the list of pending URB's to see which ones completed and do - * callbacks, etc. */ - spin_lock(&xhci->urb_list_lock); - head = &xhci->urb_list; - tmp = head->next; - while (tmp != head) { - struct urb *urb = list_entry(tmp, struct urb, urb_list); - - tmp = tmp->next; - - /* Checks the status and does all of the magic necessary */ - xhci_transfer_result(xhci, urb); - } - spin_unlock(&xhci->urb_list_lock); - - xhci_finish_completion(); -} - - -static void xhci_interrupt(int irq, void *__xhci, struct pt_regs *regs) -{ - xhci_drain_ring(); -} - -/****************************************************************************** - * HOST CONTROLLER FUNCTIONALITY - */ - -/** - * no-op implementation of private device alloc / free routines - */ -static int xhci_do_nothing_dev(struct usb_device *dev) -{ - return 0; -} - -static inline void xhci_add_complete(struct urb *urb) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - unsigned long flags; - - spin_lock_irqsave(&xhci->complete_list_lock, flags); - list_add_tail(&urbp->complete_list, &xhci->complete_list); - spin_unlock_irqrestore(&xhci->complete_list_lock, flags); -} - -/* When this returns, the owner of the URB may free its - * storage. - * - * We spin and wait for the URB to complete before returning. - * - * Call with urb->lock acquired. - */ -static void xhci_delete_urb(struct urb *urb) -{ - struct urb_priv *urbp; - - urbp = urb->hcpriv; - - /* If there's no urb_priv structure for this URB then it can't have - * been submitted at all. */ - if ( urbp == NULL ) - return; - - /* For now we just spin until the URB completes. It shouldn't take too - * long and we don't expect to have to do this very often. */ - while ( urb->status == -EINPROGRESS ) - { - xhci_drain_ring(); - mdelay(1); - } - - /* Now we know that further transfers to the buffer won't - * occur, so we can safely return. */ -} - -static struct urb_priv *xhci_alloc_urb_priv(struct urb *urb) -{ - struct urb_priv *urbp; - - urbp = kmem_cache_alloc(xhci_up_cachep, SLAB_ATOMIC); - if (!urbp) { - err("xhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n"); - return NULL; - } - - memset((void *)urbp, 0, sizeof(*urbp)); - - urbp->inserttime = jiffies; - urbp->urb = urb; - urbp->dev = urb->dev; - - INIT_LIST_HEAD(&urbp->complete_list); - - urb->hcpriv = urbp; - - return urbp; -} - -/* - * MUST be called with urb->lock acquired - */ -/* When is this called? Do we need to stop the transfer (as we - * currently do)? */ -static void xhci_destroy_urb_priv(struct urb *urb) -{ - struct urb_priv *urbp; - - urbp = (struct urb_priv *)urb->hcpriv; - if (!urbp) - return; - - if (!list_empty(&urb->urb_list)) - warn("xhci_destroy_urb_priv: urb %p still on xhci->urb_list", urb); - - if (!list_empty(&urbp->complete_list)) - warn("xhci_destroy_urb_priv: urb %p still on xhci->complete_list", urb); - - kmem_cache_free(xhci_up_cachep, urb->hcpriv); - - urb->hcpriv = NULL; -} - -/** - * Try to find URBs in progress on the same pipe to the same device. - * - * MUST be called with xhci->urb_list_lock acquired - */ -static struct urb *xhci_find_urb_ep(struct xhci *xhci, struct urb *urb) -{ - struct list_head *tmp, *head; - - /* We don't match Isoc transfers since they are special */ - if (usb_pipeisoc(urb->pipe)) - return NULL; - - head = &xhci->urb_list; - tmp = head->next; - while (tmp != head) { - struct urb *u = list_entry(tmp, struct urb, urb_list); - - tmp = tmp->next; - - if (u->dev == urb->dev && u->pipe == urb->pipe && - u->status == -EINPROGRESS) - return u; - } - - return NULL; -} - -static int xhci_submit_urb(struct urb *urb) -{ - int ret = -EINVAL; - unsigned long flags; - struct urb *eurb; - int bustime; - - DPRINTK("URB submitted to XHCI driver.\n"); - dump_urb(urb); - - if (!urb) - return -EINVAL; - - if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) { - warn("xhci_submit_urb: urb %p belongs to disconnected device or bus?", urb); - return -ENODEV; - } - - if ( urb->dev->devpath == NULL ) - BUG(); - - usb_inc_dev_use(urb->dev); - - spin_lock_irqsave(&xhci->urb_list_lock, flags); - spin_lock(&urb->lock); - - if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET || - urb->status == -ECONNABORTED) { - dbg("xhci_submit_urb: urb not available to submit (status = %d)", urb->status); - /* Since we can have problems on the out path */ - spin_unlock(&urb->lock); - spin_unlock_irqrestore(&xhci->urb_list_lock, flags); - usb_dec_dev_use(urb->dev); - - return ret; - } - - INIT_LIST_HEAD(&urb->urb_list); - if (!xhci_alloc_urb_priv(urb)) { - ret = -ENOMEM; - - goto out; - } - - ( (struct urb_priv *)urb->hcpriv )->in_progress = 1; - - eurb = xhci_find_urb_ep(xhci, urb); - if (eurb && !(urb->transfer_flags & USB_QUEUE_BULK)) { - ret = -ENXIO; - - goto out; - } - - /* Short circuit the virtual root hub */ - if (urb->dev == xhci->rh.dev) { - ret = rh_submit_urb(urb); - - goto out; - } - - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - case PIPE_BULK: - ret = xhci_queue_req(urb); - break; - - case PIPE_INTERRUPT: - if (urb->bandwidth == 0) { /* not yet checked/allocated */ - bustime = usb_check_bandwidth(urb->dev, urb); - if (bustime < 0) - ret = bustime; - else { - ret = xhci_queue_req(urb); - if (ret == -EINPROGRESS) - usb_claim_bandwidth(urb->dev, urb, - bustime, 0); - } - } else /* bandwidth is already set */ - ret = xhci_queue_req(urb); - break; - - case PIPE_ISOCHRONOUS: - if (urb->bandwidth == 0) { /* not yet checked/allocated */ - if (urb->number_of_packets <= 0) { - ret = -EINVAL; - break; - } - bustime = usb_check_bandwidth(urb->dev, urb); - if (bustime < 0) { - ret = bustime; - break; - } - - ret = xhci_queue_req(urb); - if (ret == -EINPROGRESS) - usb_claim_bandwidth(urb->dev, urb, bustime, 1); - } else /* bandwidth is already set */ - ret = xhci_queue_req(urb); - break; - } -out: - urb->status = ret; - - if (ret == -EINPROGRESS) { - /* We use _tail to make find_urb_ep more efficient */ - list_add_tail(&urb->urb_list, &xhci->urb_list); - - spin_unlock(&urb->lock); - spin_unlock_irqrestore(&xhci->urb_list_lock, flags); - - return 0; - } - - xhci_delete_urb(urb); - - spin_unlock(&urb->lock); - spin_unlock_irqrestore(&xhci->urb_list_lock, flags); - - /* Only call completion if it was successful */ - if (!ret) - xhci_call_completion(urb); - - return ret; -} - -/* - * Return the result of a transfer - * - * MUST be called with urb_list_lock acquired - */ -static void xhci_transfer_result(struct xhci *xhci, struct urb *urb) -{ - int ret = 0; - unsigned long flags; - struct urb_priv *urbp; - - /* The root hub is special */ - if (urb->dev == xhci->rh.dev) - return; - - spin_lock_irqsave(&urb->lock, flags); - - urbp = (struct urb_priv *)urb->hcpriv; - - if ( ( (struct urb_priv *)urb->hcpriv )->in_progress ) - ret = -EINPROGRESS; - - if (urb->actual_length < urb->transfer_buffer_length) { - if (urb->transfer_flags & USB_DISABLE_SPD) { - ret = -EREMOTEIO; - } - } - - if (urb->status == -EPIPE) - { - ret = urb->status; - /* endpoint has stalled - mark it halted */ - usb_endpoint_halt(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)); - } - - if ((debug == 1 && ret != 0 && ret != -EPIPE) || - (ret != 0 && debug > 1)) { - /* Some debugging code */ - dbg("xhci_result_interrupt/bulk() failed with status %x", - status); - } - - if (ret == -EINPROGRESS) - goto out; - - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - case PIPE_BULK: - case PIPE_ISOCHRONOUS: - /* Release bandwidth for Interrupt or Isoc. transfers */ - /* Spinlock needed ? */ - if (urb->bandwidth) - usb_release_bandwidth(urb->dev, urb, 1); - xhci_delete_urb(urb); - break; - case PIPE_INTERRUPT: - /* Interrupts are an exception */ - if (urb->interval) - goto out_complete; - - /* Release bandwidth for Interrupt or Isoc. transfers */ - /* Spinlock needed ? */ - if (urb->bandwidth) - usb_release_bandwidth(urb->dev, urb, 0); - xhci_delete_urb(urb); - break; - default: - info("xhci_transfer_result: unknown pipe type %d for urb %p\n", - usb_pipetype(urb->pipe), urb); - } - - /* Remove it from xhci->urb_list */ - list_del_init(&urb->urb_list); - -out_complete: - xhci_add_complete(urb); - -out: - spin_unlock_irqrestore(&urb->lock, flags); -} - -static int xhci_unlink_urb(struct urb *urb) -{ - unsigned long flags; - struct urb_priv *urbp = urb->hcpriv; - - if (!urb) - return -EINVAL; - - if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) - return -ENODEV; - - spin_lock_irqsave(&xhci->urb_list_lock, flags); - spin_lock(&urb->lock); - - /* Release bandwidth for Interrupt or Isoc. transfers */ - /* Spinlock needed ? */ - if (urb->bandwidth) { - switch (usb_pipetype(urb->pipe)) { - case PIPE_INTERRUPT: - usb_release_bandwidth(urb->dev, urb, 0); - break; - case PIPE_ISOCHRONOUS: - usb_release_bandwidth(urb->dev, urb, 1); - break; - default: - break; - } - } - - if (urb->status != -EINPROGRESS) { - spin_unlock(&urb->lock); - spin_unlock_irqrestore(&xhci->urb_list_lock, flags); - return 0; - } - - list_del_init(&urb->urb_list); - - /* Short circuit the virtual root hub */ - if (urb->dev == xhci->rh.dev) { - rh_unlink_urb(urb); - - spin_unlock(&urb->lock); - spin_unlock_irqrestore(&xhci->urb_list_lock, flags); - - xhci_call_completion(urb); - } else { - if (urb->transfer_flags & USB_ASYNC_UNLINK) { - /* We currently don't currently attempt to cancel URBs - * that have been queued in the ring. We handle async - * unlinked URBs when they complete. */ - urbp->status = urb->status = -ECONNABORTED; - spin_unlock(&urb->lock); - spin_unlock_irqrestore(&xhci->urb_list_lock, flags); - } else { - urb->status = -ENOENT; - - spin_unlock(&urb->lock); - spin_unlock_irqrestore(&xhci->urb_list_lock, flags); - - if (in_interrupt()) { /* wait at least 1 frame */ - static int errorcount = 10; - - if (errorcount--) - dbg("xhci_unlink_urb called from interrupt for urb %p", urb); - udelay(1000); - } else - schedule_timeout(1+1*HZ/1000); - - xhci_delete_urb(urb); - - xhci_call_completion(urb); - } - } - - return 0; -} - -static void xhci_call_completion(struct urb *urb) -{ - struct urb_priv *urbp; - struct usb_device *dev = urb->dev; - int is_ring = 0, killed, resubmit_interrupt, status; - struct urb *nurb; - unsigned long flags; - - spin_lock_irqsave(&urb->lock, flags); - - urbp = (struct urb_priv *)urb->hcpriv; - if (!urbp || !urb->dev) { - spin_unlock_irqrestore(&urb->lock, flags); - return; - } - - killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED || - urb->status == -ECONNRESET); - resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT && - urb->interval); - - nurb = urb->next; - if (nurb && !killed) { - int count = 0; - - while (nurb && nurb != urb && count < MAX_URB_LOOP) { - if (nurb->status == -ENOENT || - nurb->status == -ECONNABORTED || - nurb->status == -ECONNRESET) { - killed = 1; - break; - } - - nurb = nurb->next; - count++; - } - - if (count == MAX_URB_LOOP) - err("xhci_call_completion: too many linked URB's, loop? (first loop)"); - - /* Check to see if chain is a ring */ - is_ring = (nurb == urb); - } - - status = urbp->status; - if (!resubmit_interrupt || killed) - /* We don't need urb_priv anymore */ - xhci_destroy_urb_priv(urb); - - if (!killed) - urb->status = status; - - spin_unlock_irqrestore(&urb->lock, flags); - - if (urb->complete) - urb->complete(urb); - - if (resubmit_interrupt) - /* Recheck the status. The completion handler may have */ - /* unlinked the resubmitting interrupt URB */ - killed = (urb->status == -ENOENT || - urb->status == -ECONNABORTED || - urb->status == -ECONNRESET); - - if (resubmit_interrupt && !killed) { - if ( urb->dev != xhci->rh.dev ) - xhci_queue_req(urb); /* XXX What if this fails? */ - /* Don't need to resubmit URBs for the virtual root dev. */ - } else { - if (is_ring && !killed) { - urb->dev = dev; - xhci_submit_urb(urb); - } else { - /* We decrement the usage count after we're done */ - /* with everything */ - usb_dec_dev_use(dev); - } - } -} - -static void xhci_finish_completion(void) -{ - struct list_head *tmp, *head; - unsigned long flags; - - spin_lock_irqsave(&xhci->complete_list_lock, flags); - head = &xhci->complete_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *urbp = list_entry(tmp, struct urb_priv, - complete_list); - struct urb *urb = urbp->urb; - - list_del_init(&urbp->complete_list); - spin_unlock_irqrestore(&xhci->complete_list_lock, flags); - - xhci_call_completion(urb); - - spin_lock_irqsave(&xhci->complete_list_lock, flags); - head = &xhci->complete_list; - tmp = head->next; - } - spin_unlock_irqrestore(&xhci->complete_list_lock, flags); -} - -static struct usb_operations xhci_device_operations = { - .allocate = xhci_do_nothing_dev, - .deallocate = xhci_do_nothing_dev, - /* It doesn't look like any drivers actually care what the frame number - * is at the moment! If necessary, we could approximate the current - * frame nubmer by passing it from the backend in response messages. */ - .get_frame_number = NULL, - .submit_urb = xhci_submit_urb, - .unlink_urb = xhci_unlink_urb -}; - -/****************************************************************************** - * VIRTUAL ROOT HUB EMULATION - */ - -static __u8 root_hub_dev_des[] = -{ - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x00, /* __u16 bcdUSB; v1.0 */ - 0x01, - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - 0x00, /* __u16 idVendor; */ - 0x00, - 0x00, /* __u16 idProduct; */ - 0x00, - 0x00, /* __u16 bcdDevice; */ - 0x00, - 0x00, /* __u8 iManufacturer; */ - 0x02, /* __u8 iProduct; */ - 0x01, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - - -/* Configuration descriptor */ -static __u8 root_hub_config_des[] = -{ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, /* __u16 wTotalLength; */ - 0x00, - 0x01, /* __u8 bNumInterfaces; */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, 6: Self-powered, - Bit 5 Remote-wakeup, 4..0: resvd */ - 0x00, /* __u8 MaxPower; */ - - /* interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; */ - 0x00, /* __u8 if_iInterface; */ - - /* endpoint */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */ - 0x00, - 0xff /* __u8 ep_bInterval; 255 ms */ -}; - -static __u8 root_hub_hub_des[] = -{ - 0x09, /* __u8 bLength; */ - 0x29, /* __u8 bDescriptorType; Hub-descriptor */ - 0x02, /* __u8 bNbrPorts; */ - 0x00, /* __u16 wHubCharacteristics; */ - 0x00, - 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ - 0x00, /* __u8 bHubContrCurrent; 0 mA */ - 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ - 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ -}; - -/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */ -static int rh_send_irq(struct urb *urb) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - xhci_port_t *ports = xhci->rh.ports; - unsigned long flags; - int i, len = 1; - __u16 data = 0; - - spin_lock_irqsave(&urb->lock, flags); - for (i = 0; i < xhci->rh.numports; i++) { - /* Set a bit if anything at all has changed on the port, as per - * USB spec 11.12 */ - data |= (ports[i].cs_chg || ports[i].pe_chg ) - ? (1 << (i + 1)) - : 0; - - len = (i + 1) / 8 + 1; - } - - *(__u16 *) urb->transfer_buffer = cpu_to_le16(data); - urb->actual_length = len; - urbp->status = 0; - - spin_unlock_irqrestore(&urb->lock, flags); - - if ((data > 0) && (xhci->rh.send != 0)) { - dbg("root-hub INT complete: data: %x", data); - xhci_call_completion(urb); - } - - return 0; -} - -/* Virtual Root Hub INTs are polled by this timer every "interval" ms */ -static int rh_init_int_timer(struct urb *urb); - -static void rh_int_timer_do(unsigned long ptr) -{ - struct urb *urb = (struct urb *)ptr; - struct list_head list, *tmp, *head; - unsigned long flags; - int i; - - for ( i = 0; i < xhci->rh.numports; i++) - xhci_queue_probe(i); - - if (xhci->rh.send) - rh_send_irq(urb); - - INIT_LIST_HEAD(&list); - - spin_lock_irqsave(&xhci->urb_list_lock, flags); - head = &xhci->urb_list; - tmp = head->next; - while (tmp != head) { - struct urb *u = list_entry(tmp, struct urb, urb_list); - struct urb_priv *up = (struct urb_priv *)u->hcpriv; - - tmp = tmp->next; - - spin_lock(&u->lock); - - /* Check if the URB timed out */ - if (u->timeout && time_after_eq(jiffies, - up->inserttime + u->timeout)) { - list_del(&u->urb_list); - list_add_tail(&u->urb_list, &list); - } - - spin_unlock(&u->lock); - } - spin_unlock_irqrestore(&xhci->urb_list_lock, flags); - - head = &list; - tmp = head->next; - while (tmp != head) { - struct urb *u = list_entry(tmp, struct urb, urb_list); - - tmp = tmp->next; - - u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED; - xhci_unlink_urb(u); - } - - rh_init_int_timer(urb); -} - -/* Root Hub INTs are polled by this timer */ -static int rh_init_int_timer(struct urb *urb) -{ - xhci->rh.interval = urb->interval; - init_timer(&xhci->rh.rh_int_timer); - xhci->rh.rh_int_timer.function = rh_int_timer_do; - xhci->rh.rh_int_timer.data = (unsigned long)urb; - xhci->rh.rh_int_timer.expires = jiffies - + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000; - add_timer(&xhci->rh.rh_int_timer); - - return 0; -} - -#define OK(x) len = (x); break - -/* Root Hub Control Pipe */ -static int rh_submit_urb(struct urb *urb) -{ - unsigned int pipe = urb->pipe; - struct usb_ctrlrequest *cmd = - (struct usb_ctrlrequest *)urb->setup_packet; - void *data = urb->transfer_buffer; - int leni = urb->transfer_buffer_length; - int len = 0; - xhci_port_t *status; - int stat = 0; - int i; - int retstatus; - unsigned long flags; - - __u16 cstatus; - __u16 bmRType_bReq; - __u16 wValue; - __u16 wIndex; - __u16 wLength; - - if (usb_pipetype(pipe) == PIPE_INTERRUPT) { - xhci->rh.urb = urb; - xhci->rh.send = 1; - xhci->rh.interval = urb->interval; - rh_init_int_timer(urb); - - return -EINPROGRESS; - } - - bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8; - wValue = le16_to_cpu(cmd->wValue); - wIndex = le16_to_cpu(cmd->wIndex); - wLength = le16_to_cpu(cmd->wLength); - - for (i = 0; i < 8; i++) - xhci->rh.c_p_r[i] = 0; - - status = &xhci->rh.ports[wIndex - 1]; - - spin_lock_irqsave(&xhci->rh.port_state_lock, flags); - - switch (bmRType_bReq) { - /* Request Destination: - without flags: Device, - RH_INTERFACE: interface, - RH_ENDPOINT: endpoint, - RH_CLASS means HUB here, - RH_OTHER | RH_CLASS almost ever means HUB_PORT here - */ - - case RH_GET_STATUS: - *(__u16 *)data = cpu_to_le16(1); - OK(2); - case RH_GET_STATUS | RH_INTERFACE: - *(__u16 *)data = cpu_to_le16(0); - OK(2); - case RH_GET_STATUS | RH_ENDPOINT: - *(__u16 *)data = cpu_to_le16(0); - OK(2); - case RH_GET_STATUS | RH_CLASS: - *(__u32 *)data = cpu_to_le32(0); - OK(4); /* hub power */ - case RH_GET_STATUS | RH_OTHER | RH_CLASS: - cstatus = (status->cs_chg) | - (status->pe_chg << 1) | - (xhci->rh.c_p_r[wIndex - 1] << 4); - retstatus = (status->cs) | - (status->pe << 1) | - (status->susp << 2) | - (1 << 8) | /* power on */ - (status->lsda << 9); - *(__u16 *)data = cpu_to_le16(retstatus); - *(__u16 *)(data + 2) = cpu_to_le16(cstatus); - OK(4); - case RH_CLEAR_FEATURE | RH_ENDPOINT: - switch (wValue) { - case RH_ENDPOINT_STALL: - OK(0); - } - break; - case RH_CLEAR_FEATURE | RH_CLASS: - switch (wValue) { - case RH_C_HUB_OVER_CURRENT: - OK(0); /* hub power over current */ - } - break; - case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: - switch (wValue) { - case RH_PORT_ENABLE: - status->pe = 0; - OK(0); - case RH_PORT_SUSPEND: - status->susp = 0; - OK(0); - case RH_PORT_POWER: - OK(0); /* port power */ - case RH_C_PORT_CONNECTION: - status->cs_chg = 0; - OK(0); - case RH_C_PORT_ENABLE: - status->pe_chg = 0; - OK(0); - case RH_C_PORT_SUSPEND: - /*** WR_RH_PORTSTAT(RH_PS_PSSC); */ - OK(0); - case RH_C_PORT_OVER_CURRENT: - OK(0); /* port power over current */ - case RH_C_PORT_RESET: - xhci->rh.c_p_r[wIndex - 1] = 0; - OK(0); - } - break; - case RH_SET_FEATURE | RH_OTHER | RH_CLASS: - switch (wValue) { - case RH_PORT_SUSPEND: - status->susp = 1; - OK(0); - case RH_PORT_RESET: - { - int ret; - xhci->rh.c_p_r[wIndex - 1] = 1; - status->pr = 0; - status->pe = 1; - ret = xhci_port_reset(wIndex - 1); - /* XXX MAW: should probably cancel queued transfers during reset... *\/ */ - if ( ret == 0 ) { OK(0); } - else { return ret; } - } - break; - case RH_PORT_POWER: - OK(0); /* port power ** */ - case RH_PORT_ENABLE: - status->pe = 1; - OK(0); - } - break; - case RH_SET_ADDRESS: - xhci->rh.devnum = wValue; - OK(0); - case RH_GET_DESCRIPTOR: - switch ((wValue & 0xff00) >> 8) { - case 0x01: /* device descriptor */ - len = min_t(unsigned int, leni, - min_t(unsigned int, - sizeof(root_hub_dev_des), wLength)); - memcpy(data, root_hub_dev_des, len); - OK(len); - case 0x02: /* configuration descriptor */ - len = min_t(unsigned int, leni, - min_t(unsigned int, - sizeof(root_hub_config_des), wLength)); - memcpy (data, root_hub_config_des, len); - OK(len); - case 0x03: /* string descriptors */ - len = usb_root_hub_string (wValue & 0xff, - 0, "XHCI-alt", - data, wLength); - if (len > 0) { - OK(min_t(int, leni, len)); - } else - stat = -EPIPE; - } - break; - case RH_GET_DESCRIPTOR | RH_CLASS: - root_hub_hub_des[2] = xhci->rh.numports; - len = min_t(unsigned int, leni, - min_t(unsigned int, sizeof(root_hub_hub_des), wLength)); - memcpy(data, root_hub_hub_des, len); - OK(len); - case RH_GET_CONFIGURATION: - *(__u8 *)data = 0x01; - OK(1); - case RH_SET_CONFIGURATION: - OK(0); - case RH_GET_INTERFACE | RH_INTERFACE: - *(__u8 *)data = 0x00; - OK(1); - case RH_SET_INTERFACE | RH_INTERFACE: - OK(0); - default: - stat = -EPIPE; - } - - spin_unlock_irqrestore(&xhci->rh.port_state_lock, flags); - - urb->actual_length = len; - - return stat; -} - -/* - * MUST be called with urb->lock acquired - */ -static int rh_unlink_urb(struct urb *urb) -{ - if (xhci->rh.urb == urb) { - urb->status = -ENOENT; - xhci->rh.send = 0; - xhci->rh.urb = NULL; - del_timer(&xhci->rh.rh_int_timer); - } - return 0; -} - -/****************************************************************************** - * CONTROL PLANE FUNCTIONALITY - */ - -/** - * alloc_xhci - initialise a new virtual root hub for a new USB device channel - */ -static int alloc_xhci(void) -{ - int retval; - struct usb_bus *bus; - - retval = -EBUSY; - - xhci = kmalloc(sizeof(*xhci), GFP_KERNEL); - if (!xhci) { - err("couldn't allocate xhci structure"); - retval = -ENOMEM; - goto err_alloc_xhci; - } - - xhci->state = USBIF_STATE_CLOSED; - - spin_lock_init(&xhci->urb_list_lock); - INIT_LIST_HEAD(&xhci->urb_list); - - spin_lock_init(&xhci->complete_list_lock); - INIT_LIST_HEAD(&xhci->complete_list); - - spin_lock_init(&xhci->frame_list_lock); - - bus = usb_alloc_bus(&xhci_device_operations); - - if (!bus) { - err("unable to allocate bus"); - goto err_alloc_bus; - } - - xhci->bus = bus; - bus->bus_name = "XHCI"; - bus->hcpriv = xhci; - - usb_register_bus(xhci->bus); - - /* Initialize the root hub */ - - xhci->rh.numports = 0; - - xhci->bus->root_hub = xhci->rh.dev = usb_alloc_dev(NULL, xhci->bus); - if (!xhci->rh.dev) { - err("unable to allocate root hub"); - goto err_alloc_root_hub; - } - - xhci->state = 0; - - return 0; - -/* - * error exits: - */ -err_alloc_root_hub: - usb_deregister_bus(xhci->bus); - usb_free_bus(xhci->bus); - xhci->bus = NULL; - -err_alloc_bus: - kfree(xhci); - -err_alloc_xhci: - return retval; -} - -/** - * usbif_status_change - deal with an incoming USB_INTERFACE_STATUS_ message - */ -static void usbif_status_change(usbif_fe_interface_status_changed_t *status) -{ - ctrl_msg_t cmsg; - usbif_fe_interface_connect_t up; - long rc; - usbif_sring_t *sring; - - switch ( status->status ) - { - case USBIF_INTERFACE_STATUS_DESTROYED: - printk(KERN_WARNING "Unexpected usbif-DESTROYED message in state %d\n", - xhci->state); - break; - - case USBIF_INTERFACE_STATUS_DISCONNECTED: - if ( xhci->state != USBIF_STATE_CLOSED ) - { - printk(KERN_WARNING "Unexpected usbif-DISCONNECTED message" - " in state %d\n", xhci->state); - break; - /* Not bothering to do recovery here for now. Keep things - * simple. */ - - spin_lock_irq(&xhci->ring_lock); - - /* Clean up resources. */ - free_page((unsigned long)xhci->usb_ring.sring); - unbind_evtchn_from_irqhandler(xhci->evtchn, xhci); - - /* Plug the ring. */ - xhci->recovery = 1; - wmb(); - - spin_unlock_irq(&xhci->ring_lock); - } - - /* Move from CLOSED to DISCONNECTED state. */ - sring = (usbif_sring_t *)__get_free_page(GFP_KERNEL); - SHARED_RING_INIT(sring); - FRONT_RING_INIT(&xhci->usb_ring, sring, PAGE_SIZE); - xhci->state = USBIF_STATE_DISCONNECTED; - - /* Construct an interface-CONNECT message for the domain controller. */ - cmsg.type = CMSG_USBIF_FE; - cmsg.subtype = CMSG_USBIF_FE_INTERFACE_CONNECT; - cmsg.length = sizeof(usbif_fe_interface_connect_t); - up.shmem_frame = virt_to_mfn(sring); - memcpy(cmsg.msg, &up, sizeof(up)); - - /* Tell the controller to bring up the interface. */ - ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); - break; - - case USBIF_INTERFACE_STATUS_CONNECTED: - if ( xhci->state == USBIF_STATE_CLOSED ) - { - printk(KERN_WARNING "Unexpected usbif-CONNECTED message" - " in state %d\n", xhci->state); - break; - } - - xhci->evtchn = status->evtchn; - xhci->bandwidth = status->bandwidth; - xhci->rh.numports = status->num_ports; - - xhci->rh.ports = kmalloc (sizeof(xhci_port_t) * xhci->rh.numports, GFP_KERNEL); - - if ( xhci->rh.ports == NULL ) - goto alloc_ports_nomem; - - memset(xhci->rh.ports, 0, sizeof(xhci_port_t) * xhci->rh.numports); - - usb_connect(xhci->rh.dev); - - if (usb_new_device(xhci->rh.dev) != 0) { - err("unable to start root hub"); - } - - /* Allocate the appropriate USB bandwidth here... Need to - * somehow know what the total available is thought to be so we - * can calculate the reservation correctly. */ - usb_claim_bandwidth(xhci->rh.dev, xhci->rh.urb, - 1000 - xhci->bandwidth, 0); - - if ( (rc = bind_evtchn_to_irqhandler(xhci->evtchn, xhci_interrupt, - SA_SAMPLE_RANDOM, "usbif", xhci)) ) - printk(KERN_ALERT"usbfront request_irq failed (%ld)\n",rc); - - DPRINTK(KERN_INFO __FILE__ - ": USB XHCI: SHM at %p (0x%lx), EVTCHN %d\n", - xhci->usb_ring.sring, virt_to_mfn(xhci->usbif), - xhci->evtchn); - - xhci->state = USBIF_STATE_CONNECTED; - - break; - - default: - printk(KERN_WARNING "Status change to unknown value %d\n", - status->status); - break; - } - - return; - - alloc_ports_nomem: - printk(KERN_WARNING "Failed to allocate port memory, XHCI failed to connect.\n"); - return; -} - -/** - * usbif_ctrlif_rx - demux control messages by subtype - */ -static void usbif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id) -{ - switch ( msg->subtype ) - { - case CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED: - usbif_status_change((usbif_fe_interface_status_changed_t *) - &msg->msg[0]); - break; - - /* New interface...? */ - default: - msg->length = 0; - break; - } - - ctrl_if_send_response(msg); -} - -static void send_driver_up(void) -{ - control_msg_t cmsg; - usbif_fe_interface_status_changed_t st; - - /* Send a driver-UP notification to the domain controller. */ - cmsg.type = CMSG_USBIF_FE; - cmsg.subtype = CMSG_USBIF_FE_DRIVER_STATUS_CHANGED; - cmsg.length = sizeof(usbif_fe_driver_status_changed_t); - st.status = USBIF_DRIVER_STATUS_UP; - memcpy(cmsg.msg, &st, sizeof(st)); - ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); -} - -void usbif_resume(void) -{ - int i; - - /* Fake disconnection on all virtual USB ports (suspending / migrating - * will destroy hard state associated will the USB devices anyhow). */ - /* No need to lock here. */ - for ( i = 0; i < xhci->rh.numports; i++ ) - { - xhci->rh.ports[i].cs = 0; - xhci->rh.ports[i].cs_chg = 1; - xhci->rh.ports[i].pe = 0; - } - - send_driver_up(); -} - -static int __init xhci_hcd_init(void) -{ - int retval = -ENOMEM, i; - - if ( (xen_start_info->flags & SIF_INITDOMAIN) || - (xen_start_info->flags & SIF_USB_BE_DOMAIN) ) - return 0; - - info(DRIVER_DESC " " DRIVER_VERSION); - - if (debug) { - errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL); - if (!errbuf) - goto errbuf_failed; - } - - xhci_up_cachep = kmem_cache_create("xhci_urb_priv", - sizeof(struct urb_priv), 0, 0, NULL, NULL); - if (!xhci_up_cachep) - goto up_failed; - - /* Let the domain controller know we're here. For now we wait until - * connection, as for the block and net drivers. This is only strictly - * necessary if we're going to boot off a USB device. */ - printk(KERN_INFO "Initialising Xen virtual USB hub\n"); - - (void)ctrl_if_register_receiver(CMSG_USBIF_FE, usbif_ctrlif_rx, - CALLBACK_IN_BLOCKING_CONTEXT); - - alloc_xhci(); - - send_driver_up(); - - /* - * We should read 'nr_interfaces' from response message and wait - * for notifications before proceeding. For now we assume that we - * will be notified of exactly one interface. - */ - for ( i=0; (xhci->state != USBIF_STATE_CONNECTED) && (i < 10*HZ); i++ ) - { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } - - if (xhci->state != USBIF_STATE_CONNECTED) - printk(KERN_WARNING "Timeout connecting USB frontend driver!\n"); - - return 0; - -up_failed: - if (errbuf) - kfree(errbuf); - -errbuf_failed: - return retval; -} - -module_init(xhci_hcd_init); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - diff -r d7c794130ac5 -r ecc77b1c8612 linux-2.6-xen-sparse/drivers/xen/usbfront/xhci.h --- a/linux-2.6-xen-sparse/drivers/xen/usbfront/xhci.h Thu Sep 22 13:04:14 2005 +++ /dev/null Thu Sep 22 13:05:36 2005 @@ -1,182 +0,0 @@ -/****************************************************************************** - * xhci.h - * - * Private definitions for the Xen Virtual USB Controller. Based on - * drivers/usb/host/uhci.h from Linux. Copyright for the imported content is - * retained by the original authors. - * - * Modifications are: - * Copyright (C) 2004 Intel Research Cambridge - * Copyright (C) 2004, 2005 Mark Williamson - */ - -#ifndef __LINUX_XHCI_H -#define __LINUX_XHCI_H - -#include <linux/list.h> -#include <linux/usb.h> -#include <asm-xen/xen-public/io/usbif.h> -#include <linux/spinlock.h> - -/* xhci_port_t - current known state of a virtual hub ports */ -typedef struct { - unsigned int cs :1; /* Connection status. */ - unsigned int cs_chg :1; /* Connection status change. */ - unsigned int pe :1; /* Port enable. */ - unsigned int pe_chg :1; /* Port enable change. */ - unsigned int susp :1; /* Suspended. */ - unsigned int lsda :1; /* Low speed device attached. */ - unsigned int pr :1; /* Port reset. */ -} xhci_port_t; - -/* struct virt_root_hub - state related to the virtual root hub */ -struct virt_root_hub { - struct usb_device *dev; - int devnum; /* Address of Root Hub endpoint */ - struct urb *urb; - void *int_addr; - int send; - int interval; - int numports; - int c_p_r[8]; - struct timer_list rh_int_timer; - spinlock_t port_state_lock; - xhci_port_t *ports; -}; - -/* struct xhci - contains the state associated with a single USB interface */ -struct xhci { - -#ifdef CONFIG_PROC_FS - /* procfs */ - int num; - struct proc_dir_entry *proc_entry; -#endif - - int evtchn; /* Interdom channel to backend */ - enum { - USBIF_STATE_CONNECTED = 2, - USBIF_STATE_DISCONNECTED = 1, - USBIF_STATE_CLOSED = 0 - } state; /* State of this USB interface */ - unsigned long recovery; /* boolean recovery in progress flag */ - - unsigned long bandwidth; - - struct usb_bus *bus; - - /* Main list of URB's currently controlled by this HC */ - spinlock_t urb_list_lock; - struct list_head urb_list; /* P: xhci->urb_list_lock */ - - /* List of URB's awaiting completion callback */ - spinlock_t complete_list_lock; - struct list_head complete_list; /* P: xhci->complete_list_lock */ - - struct virt_root_hub rh; /* private data of the virtual root hub */ - - spinlock_t ring_lock; - usbif_front_ring_t usb_ring; - - int awaiting_reset; -}; - -/* per-URB private data structure for the host controller */ -struct urb_priv { - struct urb *urb; - usbif_iso_t *schedule; - struct usb_device *dev; - - int in_progress : 1; /* QH was queued (not linked in) */ - int short_control_packet : 1; /* If we get a short packet during */ - /* a control transfer, retrigger */ - /* the status phase */ - - int status; /* Final status */ - - unsigned long inserttime; /* In jiffies */ - - struct list_head complete_list; /* P: xhci->complete_list_lock */ -}; - -/* - * Locking in xhci.c - * - * spinlocks are used extensively to protect the many lists and data - * structures we have. It's not that pretty, but it's necessary. We - * need to be done with all of the locks (except complete_list_lock) when - * we call urb->complete. I've tried to make it simple enough so I don't - * have to spend hours racking my brain trying to figure out if the - * locking is safe. - * - * Here's the safe locking order to prevent deadlocks: - * - * #1 xhci->urb_list_lock - * #2 urb->lock - * #3 xhci->urb_remove_list_lock - * #4 xhci->complete_list_lock - * - * If you're going to grab 2 or more locks at once, ALWAYS grab the lock - * at the lowest level FIRST and NEVER grab locks at the same level at the - * same time. - * - * So, if you need xhci->urb_list_lock, grab it before you grab urb->lock - */ - -/* ------------------------------------------------------------------------- - Virtual Root HUB - ------------------------------------------------------------------------- */ -/* destination of request */ -#define RH_DEVICE 0x00 -#define RH_INTERFACE 0x01 -#define RH_ENDPOINT 0x02 -#define RH_OTHER 0x03 - -#define RH_CLASS 0x20 -#define RH_VENDOR 0x40 - -/* Requests: bRequest << 8 | bmRequestType */ -#define RH_GET_STATUS 0x0080 -#define RH_CLEAR_FEATURE 0x0100 -#define RH_SET_FEATURE 0x0300 -#define RH_SET_ADDRESS 0x0500 -#define RH_GET_DESCRIPTOR 0x0680 -#define RH_SET_DESCRIPTOR 0x0700 -#define RH_GET_CONFIGURATION 0x0880 -#define RH_SET_CONFIGURATION 0x0900 -#define RH_GET_STATE 0x0280 -#define RH_GET_INTERFACE 0x0A80 -#define RH_SET_INTERFACE 0x0B00 -#define RH_SYNC_FRAME 0x0C80 -/* Our Vendor Specific Request */ -#define RH_SET_EP 0x2000 - -/* Hub port features */ -#define RH_PORT_CONNECTION 0x00 -#define RH_PORT_ENABLE 0x01 -#define RH_PORT_SUSPEND 0x02 -#define RH_PORT_OVER_CURRENT 0x03 -#define RH_PORT_RESET 0x04 -#define RH_PORT_POWER 0x08 -#define RH_PORT_LOW_SPEED 0x09 -#define RH_C_PORT_CONNECTION 0x10 -#define RH_C_PORT_ENABLE 0x11 -#define RH_C_PORT_SUSPEND 0x12 -#define RH_C_PORT_OVER_CURRENT 0x13 -#define RH_C_PORT_RESET 0x14 - -/* Hub features */ -#define RH_C_HUB_LOCAL_POWER 0x00 -#define RH_C_HUB_OVER_CURRENT 0x01 -#define RH_DEVICE_REMOTE_WAKEUP 0x00 -#define RH_ENDPOINT_STALL 0x01 - -/* Our Vendor Specific feature */ -#define RH_REMOVE_EP 0x00 - -#define RH_ACK 0x01 -#define RH_REQ_ERR -1 -#define RH_NACK 0x00 - -#endif - _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |