# 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
|