ia64/linux-2.6.18-xen.hg

changeset 829:f799db0570f2

PVUSB: backend driver

Signed-off-by: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Mar 18 11:43:24 2009 +0000 (2009-03-18)
parents 8f996719f2ff
children cc27ca4b86c1
files drivers/xen/usbback/Makefile drivers/xen/usbback/interface.c drivers/xen/usbback/usbback.c drivers/xen/usbback/usbback.h drivers/xen/usbback/usbstub.c drivers/xen/usbback/xenbus.c
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/drivers/xen/usbback/Makefile	Wed Mar 18 11:43:24 2009 +0000
     1.3 @@ -0,0 +1,4 @@
     1.4 +obj-$(CONFIG_XEN_USB_BACKEND) := usbbk.o
     1.5 +
     1.6 +usbbk-y   := usbstub.o xenbus.o interface.o usbback.o
     1.7 +
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/drivers/xen/usbback/interface.c	Wed Mar 18 11:43:24 2009 +0000
     2.3 @@ -0,0 +1,208 @@
     2.4 +/*
     2.5 + * interface.c
     2.6 + *
     2.7 + * Xen USB backend interface management.
     2.8 + *
     2.9 + * Copyright (C) 2009, FUJITSU LABORATORIES LTD.
    2.10 + * Author: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
    2.11 + *
    2.12 + * This program is free software; you can redistribute it and/or modify
    2.13 + * it under the terms of the GNU General Public License as published by
    2.14 + * the Free Software Foundation; either version 2 of the License, or
    2.15 + * (at your option) any later version.
    2.16 + *
    2.17 + * This program is distributed in the hope that it will be useful,
    2.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.20 + * GNU General Public License for more details.
    2.21 + *
    2.22 + * You should have received a copy of the GNU General Public License
    2.23 + * along with this program; if not, see <http://www.gnu.org/licenses/>.
    2.24 + *
    2.25 + * or,
    2.26 + *
    2.27 + * When distributed separately from the Linux kernel or incorporated into
    2.28 + * other software packages, subject to the following license:
    2.29 + *
    2.30 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    2.31 + * of this software and associated documentation files (the "Software"), to
    2.32 + * deal in the Software without restriction, including without limitation the
    2.33 + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    2.34 + * sell copies of the Software, and to permit persons to whom the Software is
    2.35 + * furnished to do so, subject to the following conditions:
    2.36 + *
    2.37 + * The above copyright notice and this permission notice shall be included in
    2.38 + * all copies or substantial portions of the Software.
    2.39 + *
    2.40 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    2.41 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    2.42 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    2.43 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    2.44 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    2.45 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    2.46 + * DEALINGS IN THE SOFTWARE.
    2.47 + */
    2.48 +
    2.49 +#include "usbback.h"
    2.50 +
    2.51 +static LIST_HEAD(usbif_list);
    2.52 +static DEFINE_SPINLOCK(usbif_list_lock);
    2.53 +
    2.54 +usbif_t *find_usbif(int dom_id, int dev_id)
    2.55 +{
    2.56 +	usbif_t *usbif;
    2.57 +	int found = 0;
    2.58 +	unsigned long flags;
    2.59 +
    2.60 +	spin_lock_irqsave(&usbif_list_lock, flags);
    2.61 +	list_for_each_entry(usbif, &usbif_list, usbif_list) {
    2.62 +		if (usbif->domid == dom_id
    2.63 +			&& usbif->handle == dev_id) {
    2.64 +			found = 1;
    2.65 +			break;
    2.66 +		}
    2.67 +	}
    2.68 +	spin_unlock_irqrestore(&usbif_list_lock, flags);
    2.69 +
    2.70 +	if (found)
    2.71 +		return usbif;
    2.72 +
    2.73 +	return NULL;
    2.74 +}
    2.75 +
    2.76 +usbif_t *usbif_alloc(domid_t domid, unsigned int handle)
    2.77 +{
    2.78 +	usbif_t *usbif;
    2.79 +	unsigned long flags;
    2.80 +	int i;
    2.81 +
    2.82 +	usbif = kzalloc(sizeof(usbif_t), GFP_KERNEL);
    2.83 +	if (!usbif)
    2.84 +		return NULL;
    2.85 +
    2.86 +	usbif->domid = domid;
    2.87 +	usbif->handle = handle;
    2.88 +	spin_lock_init(&usbif->ring_lock);
    2.89 +	atomic_set(&usbif->refcnt, 0);
    2.90 +	init_waitqueue_head(&usbif->wq);
    2.91 +	init_waitqueue_head(&usbif->waiting_to_free);
    2.92 +	spin_lock_init(&usbif->plug_lock);
    2.93 +	INIT_LIST_HEAD(&usbif->plugged_devices);
    2.94 +	spin_lock_init(&usbif->addr_lock);
    2.95 +	for (i = 0; i < USB_DEV_ADDR_SIZE; i++) {
    2.96 +		usbif->addr_table[i] = NULL;
    2.97 +	}
    2.98 +
    2.99 +	spin_lock_irqsave(&usbif_list_lock, flags);
   2.100 +	list_add(&usbif->usbif_list, &usbif_list);
   2.101 +	spin_unlock_irqrestore(&usbif_list_lock, flags);
   2.102 +
   2.103 +	return usbif;
   2.104 +}
   2.105 +
   2.106 +static int map_frontend_page(usbif_t *usbif, unsigned long shared_page)
   2.107 +{
   2.108 +	struct gnttab_map_grant_ref op;
   2.109 +
   2.110 +	gnttab_set_map_op(&op, (unsigned long)usbif->ring_area->addr,
   2.111 +			  GNTMAP_host_map, shared_page, usbif->domid);
   2.112 +
   2.113 +	if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
   2.114 +		BUG();
   2.115 +
   2.116 +	if (op.status) {
   2.117 +		printk(KERN_ERR "grant table operation failure\n");
   2.118 +		return op.status;
   2.119 +	}
   2.120 +
   2.121 +	usbif->shmem_ref = shared_page;
   2.122 +	usbif->shmem_handle = op.handle;
   2.123 +
   2.124 +	return 0;
   2.125 +}
   2.126 +
   2.127 +static void unmap_frontend_page(usbif_t *usbif)
   2.128 +{
   2.129 +	struct gnttab_unmap_grant_ref op;
   2.130 +
   2.131 +	gnttab_set_unmap_op(&op, (unsigned long)usbif->ring_area->addr,
   2.132 +			    GNTMAP_host_map, usbif->shmem_handle);
   2.133 +
   2.134 +	if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
   2.135 +		BUG();
   2.136 +}
   2.137 +
   2.138 +int usbif_map(usbif_t *usbif, unsigned long shared_page, unsigned int evtchn)
   2.139 +{
   2.140 +	int err;
   2.141 +	usbif_sring_t *sring;
   2.142 +
   2.143 +	if (usbif->irq)
   2.144 +		return 0;
   2.145 +
   2.146 +	if ((usbif->ring_area = alloc_vm_area(PAGE_SIZE)) == NULL)
   2.147 +		return -ENOMEM;
   2.148 +
   2.149 +	err = map_frontend_page(usbif, shared_page);
   2.150 +	if (err) {
   2.151 +		free_vm_area(usbif->ring_area);
   2.152 +		return err;
   2.153 +	}
   2.154 +
   2.155 +	sring = (usbif_sring_t *) usbif->ring_area->addr;
   2.156 +	BACK_RING_INIT(&usbif->ring, sring, PAGE_SIZE);
   2.157 +
   2.158 +	err = bind_interdomain_evtchn_to_irqhandler(
   2.159 +			usbif->domid, evtchn, usbbk_be_int, 0, "usbif-backend", usbif);
   2.160 +	if (err < 0)
   2.161 +	{
   2.162 +		unmap_frontend_page(usbif);
   2.163 +		free_vm_area(usbif->ring_area);
   2.164 +		usbif->ring.sring = NULL;
   2.165 +		return err;
   2.166 +	}
   2.167 +	usbif->irq = err;
   2.168 +
   2.169 +	return 0;
   2.170 +}
   2.171 +
   2.172 +void usbif_disconnect(usbif_t *usbif)
   2.173 +{
   2.174 +	struct usbstub *stub, *tmp;
   2.175 +	unsigned long flags;
   2.176 +
   2.177 +	if (usbif->xenusbd) {
   2.178 +		kthread_stop(usbif->xenusbd);
   2.179 +		usbif->xenusbd = NULL;
   2.180 +	}
   2.181 +
   2.182 +	spin_lock_irqsave(&usbif->plug_lock, flags);
   2.183 +	list_for_each_entry_safe(stub, tmp, &usbif->plugged_devices, plugged_list) {
   2.184 +		usbbk_unlink_urbs(stub);
   2.185 +		detach_device_without_lock(usbif, stub);
   2.186 +	}
   2.187 +	spin_unlock_irqrestore(&usbif->plug_lock, flags);
   2.188 +
   2.189 +	wait_event(usbif->waiting_to_free, atomic_read(&usbif->refcnt) == 0);
   2.190 +
   2.191 +	if (usbif->irq) {
   2.192 +		unbind_from_irqhandler(usbif->irq, usbif);
   2.193 +		usbif->irq = 0;
   2.194 +	}
   2.195 +
   2.196 +	if (usbif->ring.sring) {
   2.197 +		unmap_frontend_page(usbif);
   2.198 +		free_vm_area(usbif->ring_area);
   2.199 +		usbif->ring.sring = NULL;
   2.200 +	}
   2.201 +}
   2.202 +
   2.203 +void usbif_free(usbif_t *usbif)
   2.204 +{
   2.205 +	unsigned long flags;
   2.206 +
   2.207 +	spin_lock_irqsave(&usbif_list_lock, flags);
   2.208 +	list_del(&usbif->usbif_list);
   2.209 +	spin_unlock_irqrestore(&usbif_list_lock, flags);
   2.210 +	kfree(usbif);
   2.211 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/drivers/xen/usbback/usbback.c	Wed Mar 18 11:43:24 2009 +0000
     3.3 @@ -0,0 +1,1075 @@
     3.4 +/*
     3.5 + * usbback.c
     3.6 + *
     3.7 + * Xen USB backend driver
     3.8 + *
     3.9 + * Copyright (C) 2009, FUJITSU LABORATORIES LTD.
    3.10 + * Author: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
    3.11 + *
    3.12 + * This program is free software; you can redistribute it and/or modify
    3.13 + * it under the terms of the GNU General Public License as published by
    3.14 + * the Free Software Foundation; either version 2 of the License, or
    3.15 + * (at your option) any later version.
    3.16 + *
    3.17 + * This program is distributed in the hope that it will be useful,
    3.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.20 + * GNU General Public License for more details.
    3.21 + *
    3.22 + * You should have received a copy of the GNU General Public License
    3.23 + * along with this program; if not, see <http://www.gnu.org/licenses/>.
    3.24 + *
    3.25 + * or,
    3.26 + *
    3.27 + * When distributed separately from the Linux kernel or incorporated into
    3.28 + * other software packages, subject to the following license:
    3.29 + *
    3.30 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    3.31 + * of this software and associated documentation files (the "Software"), to
    3.32 + * deal in the Software without restriction, including without limitation the
    3.33 + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    3.34 + * sell copies of the Software, and to permit persons to whom the Software is
    3.35 + * furnished to do so, subject to the following conditions:
    3.36 + *
    3.37 + * The above copyright notice and this permission notice shall be included in
    3.38 + * all copies or substantial portions of the Software.
    3.39 + *
    3.40 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    3.41 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    3.42 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    3.43 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    3.44 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    3.45 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    3.46 + * DEALINGS IN THE SOFTWARE.
    3.47 + */
    3.48 +
    3.49 +#include <linux/mm.h>
    3.50 +#include <xen/balloon.h>
    3.51 +#include "usbback.h"
    3.52 +
    3.53 +#if 0
    3.54 +#include "../../usb/core/hub.h"
    3.55 +#endif
    3.56 +
    3.57 +int usbif_reqs = USBIF_BACK_MAX_PENDING_REQS;
    3.58 +module_param_named(reqs, usbif_reqs, int, 0);
    3.59 +MODULE_PARM_DESC(reqs, "Number of usbback requests to allocate");
    3.60 +
    3.61 +struct pending_req_segment {
    3.62 +	uint16_t offset;
    3.63 +	uint16_t length;
    3.64 +};
    3.65 +
    3.66 +typedef struct {
    3.67 +	usbif_t *usbif;
    3.68 +
    3.69 +	uint16_t id; /* request id */
    3.70 +
    3.71 +	struct usbstub *stub;
    3.72 +	struct list_head urb_list;
    3.73 +
    3.74 +	/* urb */
    3.75 +	struct urb *urb;
    3.76 +	void *buffer;
    3.77 +	dma_addr_t transfer_dma;
    3.78 +	struct usb_ctrlrequest *setup;
    3.79 +	dma_addr_t setup_dma;
    3.80 +
    3.81 +	/* request segments */
    3.82 +	uint16_t nr_buffer_segs; /* number of urb->transfer_buffer segments */
    3.83 +	uint16_t nr_extra_segs; /* number of iso_frame_desc segments (ISO) */
    3.84 +	struct pending_req_segment *seg;
    3.85 +
    3.86 +	struct list_head free_list;
    3.87 +} pending_req_t;
    3.88 +
    3.89 +static pending_req_t *pending_reqs;
    3.90 +static struct list_head pending_free;
    3.91 +static DEFINE_SPINLOCK(pending_free_lock);
    3.92 +static DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
    3.93 +
    3.94 +#define USBBACK_INVALID_HANDLE (~0)
    3.95 +
    3.96 +static struct page **pending_pages;
    3.97 +static grant_handle_t *pending_grant_handles;
    3.98 +
    3.99 +static inline int vaddr_pagenr(pending_req_t *req, int seg)
   3.100 +{
   3.101 +	return (req - pending_reqs) * USBIF_MAX_SEGMENTS_PER_REQUEST + seg;
   3.102 +}
   3.103 +
   3.104 +static inline unsigned long vaddr(pending_req_t *req, int seg)
   3.105 +{
   3.106 +	unsigned long pfn = page_to_pfn(pending_pages[vaddr_pagenr(req, seg)]);
   3.107 +	return (unsigned long)pfn_to_kaddr(pfn);
   3.108 +}
   3.109 +
   3.110 +#define pending_handle(_req, _seg) \
   3.111 +	(pending_grant_handles[vaddr_pagenr(_req, _seg)])
   3.112 +
   3.113 +static pending_req_t* alloc_req(void)
   3.114 +{
   3.115 +	pending_req_t *req = NULL;
   3.116 +	unsigned long flags;
   3.117 +
   3.118 +	spin_lock_irqsave(&pending_free_lock, flags);
   3.119 +	if (!list_empty(&pending_free)) {
   3.120 +		req = list_entry(pending_free.next, pending_req_t, free_list);
   3.121 +		list_del(&req->free_list);
   3.122 +	}
   3.123 +	spin_unlock_irqrestore(&pending_free_lock, flags);
   3.124 +	return req;
   3.125 +}
   3.126 +
   3.127 +static void free_req(pending_req_t *req)
   3.128 +{
   3.129 +	unsigned long flags;
   3.130 +	int was_empty;
   3.131 +
   3.132 +	spin_lock_irqsave(&pending_free_lock, flags);
   3.133 +	was_empty = list_empty(&pending_free);
   3.134 +	list_add(&req->free_list, &pending_free);
   3.135 +	spin_unlock_irqrestore(&pending_free_lock, flags);
   3.136 +	if (was_empty)
   3.137 +		wake_up(&pending_free_wq);
   3.138 +}
   3.139 +
   3.140 +static inline void add_req_to_submitting_list(struct usbstub *stub, pending_req_t *pending_req)
   3.141 +{
   3.142 +	unsigned long flags;
   3.143 +
   3.144 +	spin_lock_irqsave(&stub->submitting_lock, flags);
   3.145 +	list_add_tail(&pending_req->urb_list, &stub->submitting_list);
   3.146 +	spin_unlock_irqrestore(&stub->submitting_lock, flags);
   3.147 +}
   3.148 +
   3.149 +static inline void remove_req_from_submitting_list(struct usbstub *stub, pending_req_t *pending_req)
   3.150 +{
   3.151 +	unsigned long flags;
   3.152 +
   3.153 +	spin_lock_irqsave(&stub->submitting_lock, flags);
   3.154 +	list_del_init(&pending_req->urb_list);
   3.155 +	spin_unlock_irqrestore(&stub->submitting_lock, flags);
   3.156 +}
   3.157 +
   3.158 +void usbbk_unlink_urbs(struct usbstub *stub)
   3.159 +{
   3.160 +	pending_req_t *req, *tmp;
   3.161 +	unsigned long flags;
   3.162 +
   3.163 +	spin_lock_irqsave(&stub->submitting_lock, flags);
   3.164 +	list_for_each_entry_safe(req, tmp, &stub->submitting_list, urb_list) {
   3.165 +		usb_unlink_urb(req->urb);
   3.166 +	}
   3.167 +	spin_unlock_irqrestore(&stub->submitting_lock, flags);
   3.168 +}
   3.169 +
   3.170 +static void fast_flush_area(pending_req_t *pending_req)
   3.171 +{
   3.172 +	struct gnttab_unmap_grant_ref unmap[USBIF_MAX_SEGMENTS_PER_REQUEST];
   3.173 +	unsigned int i, nr_segs, invcount = 0;
   3.174 +	grant_handle_t handle;
   3.175 +	int ret;
   3.176 +
   3.177 +	nr_segs = pending_req->nr_buffer_segs + pending_req->nr_extra_segs;
   3.178 +
   3.179 +	if (nr_segs) {
   3.180 +		for (i = 0; i < nr_segs; i++) {
   3.181 +			handle = pending_handle(pending_req, i);
   3.182 +			if (handle == USBBACK_INVALID_HANDLE)
   3.183 +				continue;
   3.184 +			gnttab_set_unmap_op(&unmap[invcount], vaddr(pending_req, i),
   3.185 +					    GNTMAP_host_map, handle);
   3.186 +			pending_handle(pending_req, i) = USBBACK_INVALID_HANDLE;
   3.187 +			invcount++;
   3.188 +		}
   3.189 +
   3.190 +		ret = HYPERVISOR_grant_table_op(
   3.191 +			GNTTABOP_unmap_grant_ref, unmap, invcount);
   3.192 +		BUG_ON(ret);
   3.193 +
   3.194 +		kfree(pending_req->seg);
   3.195 +	}
   3.196 +
   3.197 +	return;
   3.198 +}
   3.199 +
   3.200 +static void copy_buff_to_pages(void *buff, pending_req_t *pending_req,
   3.201 +		int start, int nr_pages)
   3.202 +{
   3.203 +	unsigned long copied = 0;
   3.204 +	int i;
   3.205 +
   3.206 +	for (i = start; i < start + nr_pages; i++) {
   3.207 +		memcpy((void *) vaddr(pending_req, i) + pending_req->seg[i].offset,
   3.208 +			buff + copied,
   3.209 +			pending_req->seg[i].length);
   3.210 +		copied += pending_req->seg[i].length;
   3.211 +	}
   3.212 +}
   3.213 +
   3.214 +static void copy_pages_to_buff(void *buff, pending_req_t *pending_req,
   3.215 +		int start, int nr_pages)
   3.216 +{
   3.217 +	unsigned long copied = 0;
   3.218 +	int i;
   3.219 +
   3.220 +	for (i = start; i < start + nr_pages; i++) {
   3.221 +		memcpy(buff + copied,
   3.222 +			(void *) vaddr(pending_req, i) + pending_req->seg[i].offset,
   3.223 +			pending_req->seg[i].length);
   3.224 +		copied += pending_req->seg[i].length;
   3.225 +	}
   3.226 +}
   3.227 +
   3.228 +static int usbbk_alloc_urb(usbif_request_t *req, pending_req_t *pending_req)
   3.229 +{
   3.230 +	int ret;
   3.231 +
   3.232 +	if (usb_pipeisoc(req->pipe))
   3.233 +		pending_req->urb = usb_alloc_urb(req->u.isoc.number_of_packets, GFP_KERNEL);
   3.234 +	else
   3.235 +		pending_req->urb = usb_alloc_urb(0, GFP_KERNEL);
   3.236 +	if (!pending_req->urb) {
   3.237 +		printk(KERN_ERR "usbback: can't alloc urb\n");
   3.238 +		ret = -ENOMEM;
   3.239 +		goto fail;
   3.240 +	}
   3.241 +
   3.242 +	if (req->buffer_length) {
   3.243 +		pending_req->buffer = usb_buffer_alloc(pending_req->stub->udev,
   3.244 +				req->buffer_length, GFP_KERNEL,
   3.245 +				&pending_req->transfer_dma);
   3.246 +		if (!pending_req->buffer) {
   3.247 +			printk(KERN_ERR "usbback: can't alloc urb buffer\n");
   3.248 +			ret = -ENOMEM;
   3.249 +			goto fail_free_urb;
   3.250 +		}
   3.251 +	}
   3.252 +
   3.253 +	if (usb_pipecontrol(req->pipe)) {
   3.254 +		pending_req->setup = usb_buffer_alloc(pending_req->stub->udev,
   3.255 +				sizeof(struct usb_ctrlrequest), GFP_KERNEL,
   3.256 +				&pending_req->setup_dma);
   3.257 +		if (!pending_req->setup) {
   3.258 +			printk(KERN_ERR "usbback: can't alloc usb_ctrlrequest\n");
   3.259 +			ret = -ENOMEM;
   3.260 +			goto fail_free_buffer;
   3.261 +		}
   3.262 +	}
   3.263 +
   3.264 +	return 0;
   3.265 +
   3.266 +fail_free_buffer:
   3.267 +	if (req->buffer_length)
   3.268 +		usb_buffer_free(pending_req->stub->udev, req->buffer_length,
   3.269 +				pending_req->buffer, pending_req->transfer_dma);
   3.270 +fail_free_urb:
   3.271 +	usb_free_urb(pending_req->urb);
   3.272 +fail:
   3.273 +	return ret;
   3.274 +}
   3.275 +
   3.276 +static void usbbk_free_urb(struct urb *urb)
   3.277 +{
   3.278 +	if (usb_pipecontrol(urb->pipe))
   3.279 +		usb_buffer_free(urb->dev, sizeof(struct usb_ctrlrequest),
   3.280 +				urb->setup_packet, urb->setup_dma);
   3.281 +	if (urb->transfer_buffer_length)
   3.282 +		usb_buffer_free(urb->dev, urb->transfer_buffer_length,
   3.283 +				urb->transfer_buffer, urb->transfer_dma);
   3.284 +	barrier();
   3.285 +	usb_free_urb(urb);
   3.286 +}
   3.287 +
   3.288 +static void usbbk_notify_work(usbif_t *usbif)
   3.289 +{
   3.290 +	usbif->waiting_reqs = 1;
   3.291 +	wake_up(&usbif->wq);
   3.292 +}
   3.293 +
   3.294 +irqreturn_t usbbk_be_int(int irq, void *dev_id, struct pt_regs *regs)
   3.295 +{
   3.296 +	usbbk_notify_work(dev_id);
   3.297 +	return IRQ_HANDLED;
   3.298 +}
   3.299 +
   3.300 +static void usbbk_do_response(pending_req_t *pending_req, int32_t status,
   3.301 +					int32_t actual_length, int32_t error_count, uint16_t start_frame)
   3.302 +{
   3.303 +	usbif_t *usbif = pending_req->usbif;
   3.304 +	usbif_response_t *ring_res;
   3.305 +	unsigned long flags;
   3.306 +	int notify;
   3.307 +
   3.308 +	spin_lock_irqsave(&usbif->ring_lock, flags);
   3.309 +	ring_res = RING_GET_RESPONSE(&usbif->ring, usbif->ring.rsp_prod_pvt);
   3.310 +	ring_res->id = pending_req->id;
   3.311 +	ring_res->status = status;
   3.312 +	ring_res->actual_length = actual_length;
   3.313 +	ring_res->error_count = error_count;
   3.314 +	ring_res->start_frame = start_frame;
   3.315 +	usbif->ring.rsp_prod_pvt++;
   3.316 +	barrier();
   3.317 +	RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->ring, notify);
   3.318 +	spin_unlock_irqrestore(&usbif->ring_lock, flags);
   3.319 +
   3.320 +	if (notify)
   3.321 +		notify_remote_via_irq(usbif->irq);
   3.322 +}
   3.323 +
   3.324 +static void usbbk_urb_complete(struct urb *urb, struct pt_regs *regs)
   3.325 +{
   3.326 +	pending_req_t *pending_req = (pending_req_t *)urb->context;
   3.327 +
   3.328 +	if (usb_pipein(urb->pipe) && urb->status == 0 && urb->actual_length > 0)
   3.329 +		copy_buff_to_pages(pending_req->buffer, pending_req,
   3.330 +					0, pending_req->nr_buffer_segs);
   3.331 +
   3.332 +	if (usb_pipeisoc(urb->pipe))
   3.333 +		copy_buff_to_pages(&urb->iso_frame_desc[0], pending_req,
   3.334 +					pending_req->nr_buffer_segs, pending_req->nr_extra_segs);
   3.335 +
   3.336 +	barrier();
   3.337 +
   3.338 +	fast_flush_area(pending_req);
   3.339 +
   3.340 +	usbbk_do_response(pending_req, urb->status, urb->actual_length,
   3.341 +					urb->error_count, urb->start_frame);
   3.342 +
   3.343 +	remove_req_from_submitting_list(pending_req->stub, pending_req);
   3.344 +
   3.345 +	barrier();
   3.346 +	usbbk_free_urb(urb);
   3.347 +	usbif_put(pending_req->usbif);
   3.348 +	free_req(pending_req);
   3.349 +}
   3.350 +
   3.351 +static int usbbk_gnttab_map(usbif_t *usbif,
   3.352 +			usbif_request_t *req, pending_req_t *pending_req)
   3.353 +{
   3.354 +	int i, ret;
   3.355 +	unsigned int nr_segs;
   3.356 +	uint32_t flags;
   3.357 +	struct gnttab_map_grant_ref map[USBIF_MAX_SEGMENTS_PER_REQUEST];
   3.358 +
   3.359 +	nr_segs = pending_req->nr_buffer_segs + pending_req->nr_extra_segs;
   3.360 +
   3.361 +	if (nr_segs > USBIF_MAX_SEGMENTS_PER_REQUEST) {
   3.362 +		printk(KERN_ERR "Bad number of segments in request\n");
   3.363 +		ret = -EINVAL;
   3.364 +		goto fail;
   3.365 +	}
   3.366 +
   3.367 +	if (nr_segs) {
   3.368 +		pending_req->seg = kmalloc(sizeof(struct pending_req_segment)
   3.369 +				* nr_segs, GFP_KERNEL);
   3.370 +		if (!pending_req->seg) {
   3.371 +			ret = -ENOMEM;
   3.372 +			goto fail;
   3.373 +		}
   3.374 +
   3.375 +		if (pending_req->nr_buffer_segs) {
   3.376 +			flags = GNTMAP_host_map;
   3.377 +			if (usb_pipeout(req->pipe))
   3.378 +				flags |= GNTMAP_readonly;
   3.379 +			for (i = 0; i < pending_req->nr_buffer_segs; i++)
   3.380 +				gnttab_set_map_op(&map[i], vaddr(
   3.381 +						pending_req, i), flags,
   3.382 +						req->seg[i].gref,
   3.383 +						usbif->domid);
   3.384 +		}
   3.385 +
   3.386 +		if (pending_req->nr_extra_segs) {
   3.387 +			flags = GNTMAP_host_map;
   3.388 +			for (i = req->nr_buffer_segs; i < nr_segs; i++)
   3.389 +				gnttab_set_map_op(&map[i], vaddr(
   3.390 +						pending_req, i), flags,
   3.391 +						req->seg[i].gref,
   3.392 +						usbif->domid);
   3.393 +		}
   3.394 +
   3.395 +		ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
   3.396 +					map, nr_segs);
   3.397 +		BUG_ON(ret);
   3.398 +
   3.399 +		for (i = 0; i < nr_segs; i++) {
   3.400 +			if (unlikely(map[i].status != 0)) {
   3.401 +				printk(KERN_ERR "usbback: invalid buffer -- could not remap it\n");
   3.402 +				map[i].handle = USBBACK_INVALID_HANDLE;
   3.403 +				ret |= 1;
   3.404 +			}
   3.405 +
   3.406 +			pending_handle(pending_req, i) = map[i].handle;
   3.407 +
   3.408 +			if (ret)
   3.409 +				continue;
   3.410 +
   3.411 +			set_phys_to_machine(__pa(vaddr(
   3.412 +				pending_req, i)) >> PAGE_SHIFT,
   3.413 +				FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
   3.414 +
   3.415 +			pending_req->seg[i].offset = req->seg[i].offset;
   3.416 +			pending_req->seg[i].length = req->seg[i].length;
   3.417 +
   3.418 +			barrier();
   3.419 +
   3.420 +			if (pending_req->seg[i].offset >= PAGE_SIZE ||
   3.421 +					pending_req->seg[i].length > PAGE_SIZE ||
   3.422 +					pending_req->seg[i].offset + pending_req->seg[i].length > PAGE_SIZE)
   3.423 +					ret |= 1;
   3.424 +		}
   3.425 +
   3.426 +		if (ret)
   3.427 +			goto fail_flush;
   3.428 +	}
   3.429 +
   3.430 +	return 0;
   3.431 +
   3.432 +fail_flush:
   3.433 +	fast_flush_area(pending_req);
   3.434 +	ret = -ENOMEM;
   3.435 +
   3.436 +fail:
   3.437 +	return ret;
   3.438 +}
   3.439 +
   3.440 +static void usbbk_init_urb(usbif_request_t *req, pending_req_t *pending_req)
   3.441 +{
   3.442 +	unsigned int pipe;
   3.443 +	struct usb_device *udev = pending_req->stub->udev;
   3.444 +	struct urb *urb = pending_req->urb;
   3.445 +
   3.446 +	switch (usb_pipetype(req->pipe)) {
   3.447 +	case PIPE_ISOCHRONOUS:
   3.448 +		if (usb_pipein(req->pipe))
   3.449 +			pipe = usb_rcvisocpipe(udev, usb_pipeendpoint(req->pipe));
   3.450 +		else
   3.451 +			pipe = usb_sndisocpipe(udev, usb_pipeendpoint(req->pipe));
   3.452 +
   3.453 +		urb->dev = udev;
   3.454 +		urb->pipe = pipe;
   3.455 +		urb->transfer_flags = req->transfer_flags;
   3.456 +		urb->transfer_flags |= URB_ISO_ASAP;
   3.457 +		urb->transfer_buffer = pending_req->buffer;
   3.458 +		urb->transfer_buffer_length = req->buffer_length;
   3.459 +		urb->complete = usbbk_urb_complete;
   3.460 +		urb->context = pending_req;
   3.461 +		urb->interval = req->u.isoc.interval;
   3.462 +		urb->start_frame = req->u.isoc.start_frame;
   3.463 +		urb->number_of_packets = req->u.isoc.number_of_packets;
   3.464 +
   3.465 +		break;
   3.466 +	case PIPE_INTERRUPT:
   3.467 +		if (usb_pipein(req->pipe))
   3.468 +			pipe = usb_rcvintpipe(udev, usb_pipeendpoint(req->pipe));
   3.469 +		else
   3.470 +			pipe = usb_sndintpipe(udev, usb_pipeendpoint(req->pipe));
   3.471 +
   3.472 +		usb_fill_int_urb(urb, udev, pipe,
   3.473 +				pending_req->buffer, req->buffer_length,
   3.474 +				usbbk_urb_complete,
   3.475 +				pending_req, req->u.intr.interval);
   3.476 +		urb->transfer_flags = req->transfer_flags;
   3.477 +
   3.478 +		break;
   3.479 +	case PIPE_CONTROL:
   3.480 +		if (usb_pipein(req->pipe))
   3.481 +			pipe = usb_rcvctrlpipe(udev, 0);
   3.482 +		else
   3.483 +			pipe = usb_sndctrlpipe(udev, 0);
   3.484 +
   3.485 +		usb_fill_control_urb(urb, udev, pipe,
   3.486 +				(unsigned char *) pending_req->setup,
   3.487 +				pending_req->buffer, req->buffer_length,
   3.488 +				usbbk_urb_complete, pending_req);
   3.489 +		memcpy(pending_req->setup, req->u.ctrl, 8);
   3.490 +		urb->setup_dma = pending_req->setup_dma;
   3.491 +		urb->transfer_flags = req->transfer_flags;
   3.492 +		urb->transfer_flags |= URB_NO_SETUP_DMA_MAP;
   3.493 +
   3.494 +		break;
   3.495 +	case PIPE_BULK:
   3.496 +		if (usb_pipein(req->pipe))
   3.497 +			pipe = usb_rcvbulkpipe(udev, usb_pipeendpoint(req->pipe));
   3.498 +		else
   3.499 +			pipe = usb_sndbulkpipe(udev, usb_pipeendpoint(req->pipe));
   3.500 +
   3.501 +		usb_fill_bulk_urb(urb, udev, pipe,
   3.502 +				pending_req->buffer, req->buffer_length,
   3.503 +				usbbk_urb_complete, pending_req);
   3.504 +		urb->transfer_flags = req->transfer_flags;
   3.505 +
   3.506 +		break;
   3.507 +	default:
   3.508 +		break;
   3.509 +	}
   3.510 +
   3.511 +	if (req->buffer_length) {
   3.512 +		urb->transfer_dma = pending_req->transfer_dma;
   3.513 +		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
   3.514 +	}
   3.515 +}
   3.516 +
   3.517 +struct set_interface_request {
   3.518 +	pending_req_t *pending_req;
   3.519 +	int interface;
   3.520 +	int alternate;
   3.521 +	struct work_struct work;
   3.522 +};
   3.523 +
   3.524 +static void usbbk_set_interface_work(void *data)
   3.525 +{
   3.526 +	struct set_interface_request *req = (struct set_interface_request *) data;
   3.527 +	pending_req_t *pending_req = req->pending_req;
   3.528 +	struct usb_device *udev = req->pending_req->stub->udev;
   3.529 +
   3.530 +	int ret;
   3.531 +
   3.532 +	usb_lock_device(udev);
   3.533 +	ret = usb_set_interface(udev, req->interface, req->alternate);
   3.534 +	usb_unlock_device(udev);
   3.535 +	usb_put_dev(udev);
   3.536 +
   3.537 +	usbbk_do_response(pending_req, ret, 0, 0, 0);
   3.538 +	usbif_put(pending_req->usbif);
   3.539 +	free_req(pending_req);
   3.540 +	kfree(req);
   3.541 +}
   3.542 +
   3.543 +static int usbbk_set_interface(pending_req_t *pending_req, int interface, int alternate)
   3.544 +{
   3.545 +	struct set_interface_request *req;
   3.546 +	struct usb_device *udev = pending_req->stub->udev;
   3.547 +
   3.548 +	req = kmalloc(sizeof(*req), GFP_KERNEL);
   3.549 +	if (!req)
   3.550 +		return -ENOMEM;
   3.551 +	req->pending_req = pending_req;
   3.552 +	req->interface = interface;
   3.553 +	req->alternate = alternate;
   3.554 +	INIT_WORK(&req->work, usbbk_set_interface_work, req);
   3.555 +	usb_get_dev(udev);
   3.556 +	schedule_work(&req->work);
   3.557 +	return 0;
   3.558 +}
   3.559 +
   3.560 +struct clear_halt_request {
   3.561 +	pending_req_t *pending_req;
   3.562 +	int pipe;
   3.563 +	struct work_struct work;
   3.564 +};
   3.565 +
   3.566 +static void usbbk_clear_halt_work(void *data)
   3.567 +{
   3.568 +	struct clear_halt_request *req = (struct clear_halt_request *) data;
   3.569 +	pending_req_t *pending_req = req->pending_req;
   3.570 +	struct usb_device *udev = req->pending_req->stub->udev;
   3.571 +	int ret;
   3.572 +
   3.573 +	usb_lock_device(udev);
   3.574 +	ret = usb_clear_halt(req->pending_req->stub->udev, req->pipe);
   3.575 +	usb_unlock_device(udev);
   3.576 +	usb_put_dev(udev);
   3.577 +
   3.578 +	usbbk_do_response(pending_req, ret, 0, 0, 0);
   3.579 +	usbif_put(pending_req->usbif);
   3.580 +	free_req(pending_req);
   3.581 +	kfree(req);
   3.582 +}
   3.583 +
   3.584 +static int usbbk_clear_halt(pending_req_t *pending_req, int pipe)
   3.585 +{
   3.586 +	struct clear_halt_request *req;
   3.587 +	struct usb_device *udev = pending_req->stub->udev;
   3.588 +
   3.589 +	req = kmalloc(sizeof(*req), GFP_KERNEL);
   3.590 +	if (!req)
   3.591 +		return -ENOMEM;
   3.592 +	req->pending_req = pending_req;
   3.593 +	req->pipe = pipe;
   3.594 +	INIT_WORK(&req->work, usbbk_clear_halt_work, req);
   3.595 +
   3.596 +	usb_get_dev(udev);
   3.597 +	schedule_work(&req->work);
   3.598 +	return 0;
   3.599 +}
   3.600 +
   3.601 +#if 0
   3.602 +struct port_reset_request {
   3.603 +	pending_req_t *pending_req;
   3.604 +	struct work_struct work;
   3.605 +};
   3.606 +
   3.607 +static void usbbk_port_reset_work(void *data)
   3.608 +{
   3.609 +	struct port_reset_request *req = (struct port_reset_request *) data;
   3.610 +	pending_req_t *pending_req = req->pending_req;
   3.611 +	struct usb_device *udev = pending_req->stub->udev;
   3.612 +	int ret, ret_lock;
   3.613 +
   3.614 +	ret = ret_lock = usb_lock_device_for_reset(udev, NULL);
   3.615 +	if (ret_lock >= 0) {
   3.616 +		ret = usb_reset_device(udev);
   3.617 +		if (ret_lock)
   3.618 +			usb_unlock_device(udev);
   3.619 +	}
   3.620 +	usb_put_dev(udev);
   3.621 +
   3.622 +	usbbk_do_response(pending_req, ret, 0, 0, 0);
   3.623 +	usbif_put(pending_req->usbif);
   3.624 +	free_req(pending_req);
   3.625 +	kfree(req);
   3.626 +}
   3.627 +
   3.628 +static int usbbk_port_reset(pending_req_t *pending_req)
   3.629 +{
   3.630 +	struct port_reset_request *req;
   3.631 +	struct usb_device *udev = pending_req->stub->udev;
   3.632 +
   3.633 +	req = kmalloc(sizeof(*req), GFP_KERNEL);
   3.634 +	if (!req)
   3.635 +		return -ENOMEM;
   3.636 +
   3.637 +	req->pending_req = pending_req;
   3.638 +	INIT_WORK(&req->work, usbbk_port_reset_work, req);
   3.639 +
   3.640 +	usb_get_dev(udev);
   3.641 +	schedule_work(&req->work);
   3.642 +	return 0;
   3.643 +}
   3.644 +#endif
   3.645 +
   3.646 +static void usbbk_set_address(usbif_t *usbif, struct usbstub *stub, int cur_addr, int new_addr)
   3.647 +{
   3.648 +	unsigned long flags;
   3.649 +
   3.650 +	spin_lock_irqsave(&usbif->addr_lock, flags);
   3.651 +	if (cur_addr)
   3.652 +		usbif->addr_table[cur_addr] = NULL;
   3.653 +	if (new_addr)
   3.654 +		usbif->addr_table[new_addr] = stub;
   3.655 +	stub->addr = new_addr;
   3.656 +	spin_unlock_irqrestore(&usbif->addr_lock, flags);
   3.657 +}
   3.658 +
   3.659 +struct usbstub *find_attached_device(usbif_t *usbif, int portnum)
   3.660 +{
   3.661 +	struct usbstub *stub;
   3.662 +	int found = 0;
   3.663 +	unsigned long flags;
   3.664 +
   3.665 +	spin_lock_irqsave(&usbif->plug_lock, flags);
   3.666 +	list_for_each_entry(stub, &usbif->plugged_devices, plugged_list) {
   3.667 +		if (stub->id->portnum == portnum) {
   3.668 +			found = 1;
   3.669 +			break;
   3.670 +		}
   3.671 +	}
   3.672 +	spin_unlock_irqrestore(&usbif->plug_lock, flags);
   3.673 +
   3.674 +	if (found)
   3.675 +		return stub;
   3.676 +
   3.677 +	return NULL;
   3.678 +}
   3.679 +
   3.680 +static int check_and_submit_special_ctrlreq(usbif_t *usbif, usbif_request_t *req, pending_req_t *pending_req)
   3.681 +{
   3.682 +	int devnum;
   3.683 +	struct usbstub *stub = NULL;
   3.684 +	struct usb_ctrlrequest *ctrl = (struct usb_ctrlrequest *) req->u.ctrl;
   3.685 +	int ret;
   3.686 +	int done = 0;
   3.687 +
   3.688 +	devnum = usb_pipedevice(req->pipe);
   3.689 +
   3.690 +	/*
   3.691 +	 * When the device is first connected or reseted, USB device has no address.
   3.692 +	 * In this initial state, following requests are send to device address (#0),
   3.693 +	 *
   3.694 +	 *  1. GET_DESCRIPTOR (with Descriptor Type is "DEVICE") is send,
   3.695 +	 *     and OS knows what device is connected to.
   3.696 +	 *
   3.697 +	 *  2. SET_ADDRESS is send, and then, device has its address.
   3.698 +	 *
   3.699 +	 * In the next step, SET_CONFIGURATION is send to addressed device, and then,
   3.700 +	 * the device is finally ready to use.
   3.701 +	 */
   3.702 +	if (unlikely(devnum == 0)) {
   3.703 +		stub = find_attached_device(usbif, usbif_pipeportnum(req->pipe));
   3.704 +		if (unlikely(!stub)) {
   3.705 +			ret = -ENODEV;
   3.706 +			goto fail_response;
   3.707 +		}
   3.708 +
   3.709 +		switch (ctrl->bRequest) {
   3.710 +		case USB_REQ_GET_DESCRIPTOR:
   3.711 +			/*
   3.712 +			 * GET_DESCRIPTOR request to device #0.
   3.713 +			 * through to normal urb transfer.
   3.714 +			 */
   3.715 +			pending_req->stub = stub;
   3.716 +			return 0;
   3.717 +			break;
   3.718 +		case USB_REQ_SET_ADDRESS:
   3.719 +			/*
   3.720 +			 * SET_ADDRESS request to device #0.
   3.721 +			 * add attached device to addr_table.
   3.722 +			 */
   3.723 +			{
   3.724 +				__u16 addr = le16_to_cpu(ctrl->wValue);
   3.725 +				usbbk_set_address(usbif, stub, 0, addr);
   3.726 +			}
   3.727 +			ret = 0;
   3.728 +			goto fail_response;
   3.729 +			break;
   3.730 +		default:
   3.731 +			ret = -EINVAL;
   3.732 +			goto fail_response;
   3.733 +		}
   3.734 +	} else {
   3.735 +		if (unlikely(!usbif->addr_table[devnum])) {
   3.736 +			ret = -ENODEV;
   3.737 +			goto fail_response;
   3.738 +		}
   3.739 +		pending_req->stub = usbif->addr_table[devnum];
   3.740 +	}
   3.741 +
   3.742 +	/*
   3.743 +	 * Check special request
   3.744 +	 */
   3.745 +	switch (ctrl->bRequest) {
   3.746 +	case USB_REQ_SET_ADDRESS:
   3.747 +		/*
   3.748 +		 * SET_ADDRESS request to addressed device.
   3.749 +		 * change addr or remove from addr_table.
   3.750 +		 */
   3.751 +		{
   3.752 +			__u16 addr = le16_to_cpu(ctrl->wValue);
   3.753 +			usbbk_set_address(usbif, stub, devnum, addr);
   3.754 +		}
   3.755 +		ret = 0;
   3.756 +		goto fail_response;
   3.757 +		break;
   3.758 +#if 0
   3.759 +	case USB_REQ_SET_CONFIGURATION:
   3.760 +		/*
   3.761 +		 * linux 2.6.27 or later version only!
   3.762 +		 */
   3.763 +		if (ctrl->RequestType == USB_RECIP_DEVICE) {
   3.764 +			__u16 config = le16_to_cpu(ctrl->wValue);
   3.765 +			usb_driver_set_configuration(pending_req->stub->udev, config);
   3.766 +			done = 1;
   3.767 +		}
   3.768 +		break;
   3.769 +#endif
   3.770 +	case USB_REQ_SET_INTERFACE:
   3.771 +		if (ctrl->bRequestType == USB_RECIP_INTERFACE) {
   3.772 +			__u16 alt = le16_to_cpu(ctrl->wValue);
   3.773 +			__u16 intf = le16_to_cpu(ctrl->wIndex);
   3.774 +			usbbk_set_interface(pending_req, intf, alt);
   3.775 +			done = 1;
   3.776 +		}
   3.777 +		break;
   3.778 +	case USB_REQ_CLEAR_FEATURE:
   3.779 +		if (ctrl->bRequestType == USB_RECIP_ENDPOINT
   3.780 +			&& ctrl->wValue == USB_ENDPOINT_HALT) {
   3.781 +			int pipe;
   3.782 +			int ep = le16_to_cpu(ctrl->wIndex) & 0x0f;
   3.783 +			int dir = le16_to_cpu(ctrl->wIndex)
   3.784 +					& USB_DIR_IN;
   3.785 +			if (dir)
   3.786 +				pipe = usb_rcvctrlpipe(pending_req->stub->udev, ep);
   3.787 +			else
   3.788 +				pipe = usb_sndctrlpipe(pending_req->stub->udev, ep);
   3.789 +			usbbk_clear_halt(pending_req, pipe);
   3.790 +			done = 1;
   3.791 +		}
   3.792 +		break;
   3.793 +#if 0 /* not tested yet */
   3.794 +	case USB_REQ_SET_FEATURE:
   3.795 +		if (ctrl->bRequestType == USB_RT_PORT) {
   3.796 +			__u16 feat = le16_to_cpu(ctrl->wValue);
   3.797 +			if (feat == USB_PORT_FEAT_RESET) {
   3.798 +				usbbk_port_reset(pending_req);
   3.799 +				done = 1;
   3.800 +			}
   3.801 +		}
   3.802 +		break;
   3.803 +#endif
   3.804 +	default:
   3.805 +		break;
   3.806 +	}
   3.807 +
   3.808 +	return done;
   3.809 +
   3.810 +fail_response:
   3.811 +	usbbk_do_response(pending_req, ret, 0, 0, 0);
   3.812 +	usbif_put(usbif);
   3.813 +	free_req(pending_req);
   3.814 +	return 1;
   3.815 +}
   3.816 +
   3.817 +static void dispatch_request_to_pending_reqs(usbif_t *usbif,
   3.818 +		usbif_request_t *req,
   3.819 +		pending_req_t *pending_req)
   3.820 +{
   3.821 +	int ret;
   3.822 +
   3.823 +	pending_req->id = req->id;
   3.824 +	pending_req->usbif = usbif;
   3.825 +
   3.826 +	barrier();
   3.827 +
   3.828 +	/*
   3.829 +	 * TODO:
   3.830 +	 * receive unlink request and cancel the urb in backend
   3.831 +	 */
   3.832 +#if 0
   3.833 +	if (unlikely(usb_pipeunlink(req->pipe))) {
   3.834 +
   3.835 +	}
   3.836 +#endif
   3.837 +
   3.838 +	usbif_get(usbif);
   3.839 +
   3.840 +	if (usb_pipecontrol(req->pipe)) {
   3.841 +		if (check_and_submit_special_ctrlreq(usbif, req, pending_req))
   3.842 +			return;
   3.843 +	} else {
   3.844 +		int devnum = usb_pipedevice(req->pipe);
   3.845 +		if (unlikely(!usbif->addr_table[devnum])) {
   3.846 +			ret = -ENODEV;
   3.847 +			goto fail_response;
   3.848 +		}
   3.849 +		pending_req->stub = usbif->addr_table[devnum];
   3.850 +	}
   3.851 +
   3.852 +	barrier();
   3.853 +
   3.854 +	ret = usbbk_alloc_urb(req, pending_req);
   3.855 +	if (ret) {
   3.856 +		ret = -ESHUTDOWN;
   3.857 +		goto fail_response;
   3.858 +	}
   3.859 +
   3.860 +	add_req_to_submitting_list(pending_req->stub, pending_req);
   3.861 +
   3.862 +	barrier();
   3.863 +
   3.864 +	usbbk_init_urb(req, pending_req);
   3.865 +
   3.866 +	barrier();
   3.867 +
   3.868 +	pending_req->nr_buffer_segs = req->nr_buffer_segs;
   3.869 +	if (usb_pipeisoc(req->pipe))
   3.870 +		pending_req->nr_extra_segs = req->u.isoc.nr_frame_desc_segs;
   3.871 +	else
   3.872 +		pending_req->nr_extra_segs = 0;
   3.873 +
   3.874 +	barrier();
   3.875 +
   3.876 +	ret = usbbk_gnttab_map(usbif, req, pending_req);
   3.877 +	if (ret) {
   3.878 +		printk(KERN_ERR "usbback: invalid buffer\n");
   3.879 +		ret = -ESHUTDOWN;
   3.880 +		goto fail_free_urb;
   3.881 +	}
   3.882 +
   3.883 +	barrier();
   3.884 +
   3.885 +	if (usb_pipeout(req->pipe) && req->buffer_length)
   3.886 +		copy_pages_to_buff(pending_req->buffer,
   3.887 +					pending_req,
   3.888 +					0,
   3.889 +					pending_req->nr_buffer_segs);
   3.890 +	if (usb_pipeisoc(req->pipe)) {
   3.891 +		copy_pages_to_buff(&pending_req->urb->iso_frame_desc[0],
   3.892 +			pending_req,
   3.893 +			pending_req->nr_buffer_segs,
   3.894 +			pending_req->nr_extra_segs);
   3.895 +	}
   3.896 +
   3.897 +	barrier();
   3.898 +
   3.899 +	ret = usb_submit_urb(pending_req->urb, GFP_KERNEL);
   3.900 +	if (ret) {
   3.901 +		printk(KERN_ERR "usbback: failed submitting urb, error %d\n", ret);
   3.902 +		ret = -ESHUTDOWN;
   3.903 +		goto fail_flush_area;
   3.904 +	}
   3.905 +	return;
   3.906 +
   3.907 +fail_flush_area:
   3.908 +	fast_flush_area(pending_req);
   3.909 +fail_free_urb:
   3.910 +	remove_req_from_submitting_list(pending_req->stub, pending_req);
   3.911 +	barrier();
   3.912 +	usbbk_free_urb(pending_req->urb);
   3.913 +fail_response:
   3.914 +	usbbk_do_response(pending_req, ret, 0, 0, 0);
   3.915 +	usbif_put(usbif);
   3.916 +	free_req(pending_req);
   3.917 +}
   3.918 +
   3.919 +static int usbbk_start_submit_urb(usbif_t *usbif)
   3.920 +{
   3.921 +	usbif_back_ring_t *usb_ring = &usbif->ring;
   3.922 +	usbif_request_t *ring_req;
   3.923 +	pending_req_t *pending_req;
   3.924 +	RING_IDX rc, rp;
   3.925 +	int more_to_do = 0;
   3.926 +
   3.927 +	rc = usb_ring->req_cons;
   3.928 +	rp = usb_ring->sring->req_prod;
   3.929 +	rmb();
   3.930 +
   3.931 +	while (rc != rp) {
   3.932 +		if (RING_REQUEST_CONS_OVERFLOW(usb_ring, rc)) {
   3.933 +			printk(KERN_WARNING "RING_REQUEST_CONS_OVERFLOW\n");
   3.934 +			break;
   3.935 +		}
   3.936 +
   3.937 +		pending_req = alloc_req();
   3.938 +		if (NULL == pending_req) {
   3.939 +			more_to_do = 1;
   3.940 +			break;
   3.941 +		}
   3.942 +
   3.943 +		ring_req = RING_GET_REQUEST(usb_ring, rc);
   3.944 +		usb_ring->req_cons = ++rc;
   3.945 +
   3.946 +		dispatch_request_to_pending_reqs(usbif, ring_req,
   3.947 +							pending_req);
   3.948 +	}
   3.949 +
   3.950 +	RING_FINAL_CHECK_FOR_REQUESTS(&usbif->ring, more_to_do);
   3.951 +
   3.952 +	cond_resched();
   3.953 +
   3.954 +	return more_to_do;
   3.955 +}
   3.956 +
   3.957 +int usbbk_schedule(void *arg)
   3.958 +{
   3.959 +        usbif_t *usbif = (usbif_t *)arg;
   3.960 +
   3.961 +        usbif_get(usbif);
   3.962 +
   3.963 +        while(!kthread_should_stop()) {
   3.964 +                wait_event_interruptible(
   3.965 +                                usbif->wq,
   3.966 +                                usbif->waiting_reqs || kthread_should_stop());
   3.967 +                wait_event_interruptible(
   3.968 +                                pending_free_wq,
   3.969 +                                !list_empty(&pending_free) || kthread_should_stop());
   3.970 +                usbif->waiting_reqs = 0;
   3.971 +                smp_mb();
   3.972 +
   3.973 +                if (usbbk_start_submit_urb(usbif))
   3.974 +                        usbif->waiting_reqs = 1;
   3.975 +        }
   3.976 +
   3.977 +        usbif->xenusbd = NULL;
   3.978 +        usbif_put(usbif);
   3.979 +
   3.980 +        return 0;
   3.981 +}
   3.982 +
   3.983 +/*
   3.984 + * attach the grabbed device to usbif.
   3.985 + */
   3.986 +void usbbk_plug_device(usbif_t *usbif, struct usbstub *stub)
   3.987 +{
   3.988 +	unsigned long flags;
   3.989 +
   3.990 +	spin_lock_irqsave(&usbif->plug_lock, flags);
   3.991 +	list_add(&stub->plugged_list, &usbif->plugged_devices);
   3.992 +	spin_unlock_irqrestore(&usbif->plug_lock, flags);
   3.993 +	stub->plugged = 1;
   3.994 +	stub->usbif = usbif;
   3.995 +}
   3.996 +
   3.997 +/*
   3.998 + * detach the grabbed device from usbif.
   3.999 + */
  3.1000 +void usbbk_unplug_device(usbif_t *usbif, struct usbstub *stub)
  3.1001 +{
  3.1002 +	unsigned long flags;
  3.1003 +
  3.1004 +	if (stub->addr)
  3.1005 +		usbbk_set_address(usbif, stub, stub->addr, 0);
  3.1006 +	spin_lock_irqsave(&usbif->plug_lock, flags);
  3.1007 +	list_del(&stub->plugged_list);
  3.1008 +	spin_unlock_irqrestore(&usbif->plug_lock, flags);
  3.1009 +	stub->plugged = 0;
  3.1010 +	stub->usbif = NULL;
  3.1011 +}
  3.1012 +
  3.1013 +void detach_device_without_lock(usbif_t *usbif, struct usbstub *stub)
  3.1014 +{
  3.1015 +	if (stub->addr)
  3.1016 +		usbbk_set_address(usbif, stub, stub->addr, 0);
  3.1017 +	list_del(&stub->plugged_list);
  3.1018 +	stub->plugged = 0;
  3.1019 +	stub->usbif = NULL;
  3.1020 +}
  3.1021 +
  3.1022 +static int __init usbback_init(void)
  3.1023 +{
  3.1024 +	int i, mmap_pages;
  3.1025 +
  3.1026 +	if (!is_running_on_xen())
  3.1027 +		return -ENODEV;
  3.1028 +
  3.1029 +	if (usbstub_init())
  3.1030 +		return -ENODEV;
  3.1031 +
  3.1032 +	mmap_pages = usbif_reqs * USBIF_MAX_SEGMENTS_PER_REQUEST;
  3.1033 +	pending_reqs = kmalloc(sizeof(pending_reqs[0]) *
  3.1034 +			usbif_reqs, GFP_KERNEL);
  3.1035 +	pending_grant_handles = kmalloc(sizeof(pending_grant_handles[0]) *
  3.1036 +			mmap_pages, GFP_KERNEL);
  3.1037 +	pending_pages = alloc_empty_pages_and_pagevec(mmap_pages);
  3.1038 +
  3.1039 +	if (!pending_reqs || !pending_grant_handles || !pending_pages)
  3.1040 +		goto out_of_memory;
  3.1041 +
  3.1042 +	for (i = 0; i < mmap_pages; i++)
  3.1043 +		pending_grant_handles[i] = USBBACK_INVALID_HANDLE;
  3.1044 +
  3.1045 +	memset(pending_reqs, 0, sizeof(pending_reqs));
  3.1046 +	INIT_LIST_HEAD(&pending_free);
  3.1047 +
  3.1048 +	for (i = 0; i < usbif_reqs; i++) {
  3.1049 +		list_add_tail(&pending_reqs[i].free_list, &pending_free);
  3.1050 +	}
  3.1051 +
  3.1052 +	usbback_xenbus_init();
  3.1053 +
  3.1054 +	return 0;
  3.1055 +
  3.1056 + out_of_memory:
  3.1057 +	 kfree(pending_reqs);
  3.1058 +	 kfree(pending_grant_handles);
  3.1059 +	 free_empty_pages_and_pagevec(pending_pages, mmap_pages);
  3.1060 +	 printk("%s: out of memory\n", __FUNCTION__);
  3.1061 +	 return -ENOMEM;
  3.1062 +}
  3.1063 +
  3.1064 +static void __exit usbback_exit(void)
  3.1065 +{
  3.1066 +	usbback_xenbus_exit();
  3.1067 +	usbstub_exit();
  3.1068 +	kfree(pending_reqs);
  3.1069 +	kfree(pending_grant_handles);
  3.1070 +	free_empty_pages_and_pagevec(pending_pages, usbif_reqs * USBIF_MAX_SEGMENTS_PER_REQUEST);
  3.1071 +}
  3.1072 +
  3.1073 +module_init(usbback_init);
  3.1074 +module_exit(usbback_exit);
  3.1075 +
  3.1076 +MODULE_AUTHOR("");
  3.1077 +MODULE_DESCRIPTION("Xen USB backend driver (usbback)");
  3.1078 +MODULE_LICENSE("Dual BSD/GPL");
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/drivers/xen/usbback/usbback.h	Wed Mar 18 11:43:24 2009 +0000
     4.3 @@ -0,0 +1,158 @@
     4.4 +/*
     4.5 + * usbback.h
     4.6 + *
     4.7 + * This file is part of Xen USB backend driver.
     4.8 + *
     4.9 + * Copyright (C) 2009, FUJITSU LABORATORIES LTD.
    4.10 + * Author: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
    4.11 + *
    4.12 + * This program is free software; you can redistribute it and/or modify
    4.13 + * it under the terms of the GNU General Public License as published by
    4.14 + * the Free Software Foundation; either version 2 of the License, or
    4.15 + * (at your option) any later version.
    4.16 + *
    4.17 + * This program is distributed in the hope that it will be useful,
    4.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.20 + * GNU General Public License for more details.
    4.21 + *
    4.22 + * You should have received a copy of the GNU General Public License
    4.23 + * along with this program; if not, see <http://www.gnu.org/licenses/>.
    4.24 + *
    4.25 + * or,
    4.26 + *
    4.27 + * When distributed separately from the Linux kernel or incorporated into
    4.28 + * other software packages, subject to the following license:
    4.29 + *
    4.30 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    4.31 + * of this software and associated documentation files (the "Software"), to
    4.32 + * deal in the Software without restriction, including without limitation the
    4.33 + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    4.34 + * sell copies of the Software, and to permit persons to whom the Software is
    4.35 + * furnished to do so, subject to the following conditions:
    4.36 + *
    4.37 + * The above copyright notice and this permission notice shall be included in
    4.38 + * all copies or substantial portions of the Software.
    4.39 + *
    4.40 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    4.41 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    4.42 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    4.43 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    4.44 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    4.45 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    4.46 + * DEALINGS IN THE SOFTWARE.
    4.47 + */
    4.48 +
    4.49 +#ifndef __XEN_USBBACK_H__
    4.50 +#define __XEN_USBBACK_H__
    4.51 +
    4.52 +#include <linux/module.h>
    4.53 +#include <linux/interrupt.h>
    4.54 +#include <linux/slab.h>
    4.55 +#include <linux/usb.h>
    4.56 +#include <linux/vmalloc.h>
    4.57 +#include <linux/kthread.h>
    4.58 +#include <linux/wait.h>
    4.59 +#include <linux/list.h>
    4.60 +#include <linux/kref.h>
    4.61 +#include <xen/evtchn.h>
    4.62 +#include <xen/gnttab.h>
    4.63 +#include <xen/driver_util.h>
    4.64 +#include <xen/interface/xen.h>
    4.65 +#include <xen/interface/io/usbif.h>
    4.66 +
    4.67 +struct usbstub;
    4.68 +
    4.69 +#define USB_DEV_ADDR_SIZE 128
    4.70 +
    4.71 +typedef struct usbif_st {
    4.72 +	domid_t           domid;
    4.73 +	unsigned int      handle;
    4.74 +	struct xenbus_device *xbdev;
    4.75 +	struct list_head usbif_list;
    4.76 +
    4.77 +	unsigned int      irq;
    4.78 +
    4.79 +	usbif_back_ring_t ring;
    4.80 +	struct vm_struct *ring_area;
    4.81 +
    4.82 +	spinlock_t ring_lock;
    4.83 +	atomic_t refcnt;
    4.84 +	grant_handle_t shmem_handle;
    4.85 +	grant_ref_t shmem_ref;
    4.86 +
    4.87 +	/* device address lookup table */
    4.88 +	spinlock_t addr_lock;
    4.89 +	struct usbstub *addr_table[USB_DEV_ADDR_SIZE];
    4.90 +
    4.91 +	/* plugged device list */
    4.92 +	unsigned plaggable:1;
    4.93 +	spinlock_t plug_lock;
    4.94 +	struct list_head plugged_devices;
    4.95 +
    4.96 +	/* request schedule */
    4.97 +	struct task_struct *xenusbd;
    4.98 +	unsigned int waiting_reqs;
    4.99 +	wait_queue_head_t waiting_to_free;
   4.100 +	wait_queue_head_t wq;
   4.101 +
   4.102 +} usbif_t;
   4.103 +
   4.104 +struct usbstub_id
   4.105 +{
   4.106 +	struct list_head id_list;
   4.107 +
   4.108 +	char bus_id[BUS_ID_SIZE];
   4.109 +	int dom_id;
   4.110 +	int dev_id;
   4.111 +	int portnum;
   4.112 +};
   4.113 +
   4.114 +struct usbstub
   4.115 +{
   4.116 +	struct usbstub_id *id;
   4.117 +	struct usb_device *udev;
   4.118 +	struct usb_interface *interface;
   4.119 +	usbif_t *usbif;
   4.120 +
   4.121 +	struct list_head grabbed_list;
   4.122 +
   4.123 +	unsigned plugged:1;
   4.124 +	struct list_head plugged_list;
   4.125 +
   4.126 +	int addr;
   4.127 +
   4.128 +	spinlock_t submitting_lock;
   4.129 +	struct list_head submitting_list;
   4.130 +};
   4.131 +
   4.132 +usbif_t *usbif_alloc(domid_t domid, unsigned int handle);
   4.133 +void usbif_disconnect(usbif_t *usbif);
   4.134 +void usbif_free(usbif_t *usbif);
   4.135 +int usbif_map(usbif_t *usbif, unsigned long shared_page, unsigned int evtchn);
   4.136 +
   4.137 +#define usbif_get(_b) (atomic_inc(&(_b)->refcnt))
   4.138 +#define usbif_put(_b) \
   4.139 +	do { \
   4.140 +		if (atomic_dec_and_test(&(_b)->refcnt)) \
   4.141 +		wake_up(&(_b)->waiting_to_free); \
   4.142 +	} while (0)
   4.143 +
   4.144 +void usbback_xenbus_init(void);
   4.145 +void usbback_xenbus_exit(void);
   4.146 +
   4.147 +irqreturn_t usbbk_be_int(int irq, void *dev_id, struct pt_regs *regs);
   4.148 +int usbbk_schedule(void *arg);
   4.149 +struct usbstub *find_attached_device(usbif_t *usbif, int port);
   4.150 +struct usbstub *find_grabbed_device(int dom_id, int dev_id, int port);
   4.151 +usbif_t *find_usbif(int dom_id, int dev_id);
   4.152 +void usbback_reconfigure(usbif_t *usbif);
   4.153 +void usbbk_plug_device(usbif_t *usbif, struct usbstub *stub);
   4.154 +void usbbk_unplug_device(usbif_t *usbif, struct usbstub *stub);
   4.155 +void detach_device_without_lock(usbif_t *usbif, struct usbstub *stub);
   4.156 +void usbbk_unlink_urbs(struct usbstub *stub);
   4.157 +
   4.158 +int usbstub_init(void);
   4.159 +void usbstub_exit(void);
   4.160 +
   4.161 +#endif /* __XEN_USBBACK_H__ */
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/drivers/xen/usbback/usbstub.c	Wed Mar 18 11:43:24 2009 +0000
     5.3 @@ -0,0 +1,447 @@
     5.4 +/*
     5.5 + * usbstub.c
     5.6 + *
     5.7 + * USB stub driver - grabbing and managing USB devices.
     5.8 + *
     5.9 + * Copyright (C) 2009, FUJITSU LABORATORIES LTD.
    5.10 + * Author: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
    5.11 + *
    5.12 + * This program is free software; you can redistribute it and/or modify
    5.13 + * it under the terms of the GNU General Public License as published by
    5.14 + * the Free Software Foundation; either version 2 of the License, or
    5.15 + * (at your option) any later version.
    5.16 + *
    5.17 + * This program is distributed in the hope that it will be useful,
    5.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.20 + * GNU General Public License for more details.
    5.21 + *
    5.22 + * You should have received a copy of the GNU General Public License
    5.23 + * along with this program; if not, see <http://www.gnu.org/licenses/>.
    5.24 + *
    5.25 + * or,
    5.26 + *
    5.27 + * When distributed separately from the Linux kernel or incorporated into
    5.28 + * other software packages, subject to the following license:
    5.29 + *
    5.30 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    5.31 + * of this software and associated documentation files (the "Software"), to
    5.32 + * deal in the Software without restriction, including without limitation the
    5.33 + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    5.34 + * sell copies of the Software, and to permit persons to whom the Software is
    5.35 + * furnished to do so, subject to the following conditions:
    5.36 + *
    5.37 + * The above copyright notice and this permission notice shall be included in
    5.38 + * all copies or substantial portions of the Software.
    5.39 + *
    5.40 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    5.41 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    5.42 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    5.43 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    5.44 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    5.45 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    5.46 + * DEALINGS IN THE SOFTWARE.
    5.47 + */
    5.48 +
    5.49 +#include "usbback.h"
    5.50 +
    5.51 +static LIST_HEAD(usbstub_ids);
    5.52 +static DEFINE_SPINLOCK(usbstub_ids_lock);
    5.53 +static LIST_HEAD(grabbed_devices);
    5.54 +static DEFINE_SPINLOCK(grabbed_devices_lock);
    5.55 +
    5.56 +struct usbstub *find_grabbed_device(int dom_id, int dev_id, int portnum)
    5.57 +{
    5.58 +	struct usbstub *stub;
    5.59 +	int found = 0;
    5.60 +	unsigned long flags;
    5.61 +
    5.62 +	spin_lock_irqsave(&grabbed_devices_lock, flags);
    5.63 +	list_for_each_entry(stub, &grabbed_devices, grabbed_list) {
    5.64 +		if (stub->id->dom_id == dom_id
    5.65 +				&& stub->id->dev_id == dev_id
    5.66 +				&& stub->id->portnum == portnum) {
    5.67 +			found = 1;
    5.68 +			break;
    5.69 +		}
    5.70 +	}
    5.71 +	spin_unlock_irqrestore(&grabbed_devices_lock, flags);
    5.72 +
    5.73 +	if (found)
    5.74 +		return stub;
    5.75 +
    5.76 +	return NULL;
    5.77 +}
    5.78 +
    5.79 +static struct usbstub *usbstub_alloc(struct usb_interface *interface,
    5.80 +						struct usbstub_id *stub_id)
    5.81 +{
    5.82 +	struct usbstub *stub;
    5.83 +
    5.84 +	stub = kzalloc(sizeof(*stub), GFP_KERNEL);
    5.85 +	if (!stub) {
    5.86 +		printk(KERN_ERR "no memory for alloc usbstub\n");
    5.87 +		return NULL;
    5.88 +	}
    5.89 +
    5.90 +	stub->udev = usb_get_dev(interface_to_usbdev(interface));
    5.91 +	stub->interface = interface;
    5.92 +	stub->id = stub_id;
    5.93 +	spin_lock_init(&stub->submitting_lock);
    5.94 +	INIT_LIST_HEAD(&stub->submitting_list);
    5.95 +
    5.96 +	return stub;
    5.97 +}
    5.98 +
    5.99 +static int usbstub_free(struct usbstub *stub)
   5.100 +{
   5.101 +	if (!stub)
   5.102 +		return -EINVAL;
   5.103 +
   5.104 +	usb_put_dev(stub->udev);
   5.105 +	stub->interface = NULL;
   5.106 +	stub->udev = NULL;
   5.107 +	stub->id = NULL;
   5.108 +	kfree(stub);
   5.109 +
   5.110 +	return 0;
   5.111 +}
   5.112 +
   5.113 +static int usbstub_match_one(struct usb_interface *interface,
   5.114 +		struct usbstub_id *stub_id)
   5.115 +{
   5.116 +	char *udev_busid = interface->dev.parent->bus_id;
   5.117 +
   5.118 +	if (!(strncmp(stub_id->bus_id, udev_busid, BUS_ID_SIZE))) {
   5.119 +		return 1;
   5.120 +	}
   5.121 +
   5.122 +	return 0;
   5.123 +}
   5.124 +
   5.125 +static struct usbstub_id *usbstub_match(struct usb_interface *interface)
   5.126 +{
   5.127 +	struct usb_device *udev = interface_to_usbdev(interface);
   5.128 +	struct usbstub_id *stub_id;
   5.129 +	unsigned long flags;
   5.130 +	int found = 0;
   5.131 +
   5.132 +	/* hub currently not supported, so skip. */
   5.133 +	if (udev->descriptor.bDeviceClass ==  USB_CLASS_HUB)
   5.134 +		return NULL;
   5.135 +
   5.136 +	spin_lock_irqsave(&usbstub_ids_lock, flags);
   5.137 +	list_for_each_entry(stub_id, &usbstub_ids, id_list) {
   5.138 +		if (usbstub_match_one(interface, stub_id)) {
   5.139 +			found = 1;
   5.140 +			break;
   5.141 +		}
   5.142 +	}
   5.143 +	spin_unlock_irqrestore(&usbstub_ids_lock, flags);
   5.144 +
   5.145 +	if (found)
   5.146 +		return stub_id;
   5.147 +
   5.148 +	return NULL;
   5.149 +}
   5.150 +
   5.151 +static void add_to_grabbed_devices(struct usbstub *stub)
   5.152 +{
   5.153 +	unsigned long flags;
   5.154 +
   5.155 +	spin_lock_irqsave(&grabbed_devices_lock, flags);
   5.156 +	list_add(&stub->grabbed_list, &grabbed_devices);
   5.157 +	spin_unlock_irqrestore(&grabbed_devices_lock, flags);
   5.158 +}
   5.159 +
   5.160 +static void remove_from_grabbed_devices(struct usbstub *stub)
   5.161 +{
   5.162 +	unsigned long flags;
   5.163 +
   5.164 +	spin_lock_irqsave(&grabbed_devices_lock, flags);
   5.165 +	list_del(&stub->grabbed_list);
   5.166 +	spin_unlock_irqrestore(&grabbed_devices_lock, flags);
   5.167 +}
   5.168 +
   5.169 +static int usbstub_probe(struct usb_interface *interface,
   5.170 +		const struct usb_device_id *id)
   5.171 +{
   5.172 +	struct usbstub_id *stub_id = NULL;
   5.173 +	struct usbstub *stub = NULL;
   5.174 +	usbif_t *usbif = NULL;
   5.175 +	int retval = 0;
   5.176 +
   5.177 +	if ((stub_id = usbstub_match(interface))) {
   5.178 +		stub = usbstub_alloc(interface, stub_id);
   5.179 +		if (!stub)
   5.180 +			return -ENOMEM;
   5.181 +
   5.182 +		usb_set_intfdata(interface, stub);
   5.183 +		add_to_grabbed_devices(stub);
   5.184 +		usbif = find_usbif(stub_id->dom_id, stub_id->dev_id);
   5.185 +		if (usbif) {
   5.186 +			usbbk_plug_device(usbif, stub);
   5.187 +			usbback_reconfigure(usbif);
   5.188 +		}
   5.189 +
   5.190 +	} else
   5.191 +		retval = -ENODEV;
   5.192 +
   5.193 +	return retval;
   5.194 +}
   5.195 +
   5.196 +static void usbstub_disconnect(struct usb_interface *interface)
   5.197 +{
   5.198 +	struct usbstub *stub
   5.199 +		= (struct usbstub *) usb_get_intfdata(interface);
   5.200 +
   5.201 +	usb_set_intfdata(interface, NULL);
   5.202 +
   5.203 +	if (!stub)
   5.204 +		return;
   5.205 +
   5.206 +	if (stub->usbif) {
   5.207 +		usbback_reconfigure(stub->usbif);
   5.208 +		usbbk_unplug_device(stub->usbif, stub);
   5.209 +	}
   5.210 +
   5.211 +	usbbk_unlink_urbs(stub);
   5.212 +
   5.213 +	remove_from_grabbed_devices(stub);
   5.214 +
   5.215 +	usbstub_free(stub);
   5.216 +
   5.217 +	return;
   5.218 +}
   5.219 +
   5.220 +static inline int str_to_vport(const char *buf,
   5.221 +					char *phys_bus,
   5.222 +					int *dom_id,
   5.223 +					int *dev_id,
   5.224 +					int *port)
   5.225 +{
   5.226 +	char *p;
   5.227 +	int len;
   5.228 +	int err;
   5.229 +
   5.230 +	/* no physical bus */
   5.231 +	if (!(p = strchr(buf, ':')))
   5.232 +		return -EINVAL;
   5.233 +
   5.234 +	len = p - buf;
   5.235 +
   5.236 +	/* bad physical bus */
   5.237 +	if (len + 1 > BUS_ID_SIZE)
   5.238 +		return -EINVAL;
   5.239 +
   5.240 +	strlcpy(phys_bus, buf, len + 1);
   5.241 +	err = sscanf(p + 1, "%d:%d:%d", dom_id, dev_id, port);
   5.242 +	if (err == 3)
   5.243 +		return 0;
   5.244 +	else
   5.245 +		return -EINVAL;
   5.246 +}
   5.247 +
   5.248 +static int usbstub_id_add(const char *bus_id,
   5.249 +					const int dom_id,
   5.250 +					const int dev_id,
   5.251 +					const int portnum)
   5.252 +{
   5.253 +	struct usbstub_id *stub_id;
   5.254 +	unsigned long flags;
   5.255 +
   5.256 +	stub_id = kzalloc(sizeof(*stub_id), GFP_KERNEL);
   5.257 +	if (!stub_id)
   5.258 +		return -ENOMEM;
   5.259 +
   5.260 +	stub_id->dom_id = dom_id;
   5.261 +	stub_id->dev_id = dev_id;
   5.262 +	stub_id->portnum = portnum;
   5.263 +
   5.264 +	strncpy(stub_id->bus_id, bus_id, BUS_ID_SIZE);
   5.265 +
   5.266 +	spin_lock_irqsave(&usbstub_ids_lock, flags);
   5.267 +	list_add(&stub_id->id_list, &usbstub_ids);
   5.268 +	spin_unlock_irqrestore(&usbstub_ids_lock, flags);
   5.269 +
   5.270 +	return 0;
   5.271 +}
   5.272 +
   5.273 +static int usbstub_id_remove(const char *phys_bus,
   5.274 +					const int dom_id,
   5.275 +					const int dev_id,
   5.276 +					const int portnum)
   5.277 +{
   5.278 +	struct usbstub_id *stub_id, *tmp;
   5.279 +	int err = -ENOENT;
   5.280 +	unsigned long flags;
   5.281 +
   5.282 +	spin_lock_irqsave(&usbstub_ids_lock, flags);
   5.283 +	list_for_each_entry_safe(stub_id, tmp, &usbstub_ids, id_list) {
   5.284 +		if (stub_id->dom_id == dom_id
   5.285 +				&& stub_id->dev_id == dev_id
   5.286 +				&& stub_id->portnum == portnum) {
   5.287 +			list_del(&stub_id->id_list);
   5.288 +			kfree(stub_id);
   5.289 +
   5.290 +			err = 0;
   5.291 +		}
   5.292 +	}
   5.293 +	spin_unlock_irqrestore(&usbstub_ids_lock, flags);
   5.294 +
   5.295 +	return err;
   5.296 +}
   5.297 +
   5.298 +static ssize_t usbstub_vport_add(struct device_driver *driver,
   5.299 +		const char *buf, size_t count)
   5.300 +{
   5.301 +	int err = 0;
   5.302 +
   5.303 +	char bus_id[BUS_ID_SIZE];
   5.304 +	int dom_id;
   5.305 +	int dev_id;
   5.306 +	int portnum;
   5.307 +
   5.308 +	err = str_to_vport(buf, &bus_id[0], &dom_id, &dev_id, &portnum);
   5.309 +	if (err)
   5.310 +		goto out;
   5.311 +
   5.312 +	err = usbstub_id_add(&bus_id[0], dom_id, dev_id, portnum);
   5.313 +
   5.314 +out:
   5.315 +	if (!err)
   5.316 +		err = count;
   5.317 +	return err;
   5.318 +}
   5.319 +
   5.320 +DRIVER_ATTR(new_vport, S_IWUSR, NULL, usbstub_vport_add);
   5.321 +
   5.322 +static ssize_t usbstub_vport_remove(struct device_driver *driver,
   5.323 +		const char *buf, size_t count)
   5.324 +{
   5.325 +	int err = 0;
   5.326 +
   5.327 +	char bus_id[BUS_ID_SIZE];
   5.328 +	int dom_id;
   5.329 +	int dev_id;
   5.330 +	int portnum;
   5.331 +
   5.332 +	err = str_to_vport(buf, &bus_id[0], &dom_id, &dev_id, &portnum);
   5.333 +	if (err)
   5.334 +		goto out;
   5.335 +
   5.336 +	err = usbstub_id_remove(&bus_id[0], dom_id, dev_id, portnum);
   5.337 +
   5.338 +out:
   5.339 +	if (!err)
   5.340 +		err = count;
   5.341 +	return err;
   5.342 +}
   5.343 +
   5.344 +DRIVER_ATTR(remove_vport, S_IWUSR, NULL, usbstub_vport_remove);
   5.345 +
   5.346 +static ssize_t usbstub_vport_show(struct device_driver *driver,
   5.347 +		char *buf)
   5.348 +{
   5.349 +	struct usbstub_id *stub_id;
   5.350 +	size_t count = 0;
   5.351 +	unsigned long flags;
   5.352 +
   5.353 +	spin_lock_irqsave(&usbstub_ids_lock, flags);
   5.354 +	list_for_each_entry(stub_id, &usbstub_ids, id_list) {
   5.355 +		if (count >= PAGE_SIZE)
   5.356 +			break;
   5.357 +		count += scnprintf((char *)buf + count, PAGE_SIZE - count,
   5.358 +				"%s:%d:%d:%d\n",
   5.359 +				&stub_id->bus_id[0],
   5.360 +				stub_id->dom_id,
   5.361 +				stub_id->dev_id,
   5.362 +				stub_id->portnum);
   5.363 +	}
   5.364 +	spin_unlock_irqrestore(&usbstub_ids_lock, flags);
   5.365 +
   5.366 +	return count;
   5.367 +}
   5.368 +
   5.369 +DRIVER_ATTR(vports, S_IRUSR, usbstub_vport_show, NULL);
   5.370 +
   5.371 +static ssize_t usbstub_devices_show(struct device_driver *driver,
   5.372 +		char *buf)
   5.373 +{
   5.374 +	struct usbstub *stub;
   5.375 +	size_t count = 0;
   5.376 +	unsigned long flags;
   5.377 +
   5.378 +	spin_lock_irqsave(&grabbed_devices_lock, flags);
   5.379 +	list_for_each_entry(stub, &grabbed_devices, grabbed_list) {
   5.380 +		if (count >= PAGE_SIZE)
   5.381 +			break;
   5.382 +
   5.383 +		count += scnprintf((char *)buf + count, PAGE_SIZE - count,
   5.384 +					"%u-%s:%u.%u\n",
   5.385 +					stub->udev->bus->busnum,
   5.386 +					stub->udev->devpath,
   5.387 +					stub->udev->config->desc.bConfigurationValue,
   5.388 +					stub->interface->cur_altsetting->desc.bInterfaceNumber);
   5.389 +
   5.390 +	}
   5.391 +	spin_unlock_irqrestore(&grabbed_devices_lock, flags);
   5.392 +
   5.393 +	return count;
   5.394 +}
   5.395 +
   5.396 +DRIVER_ATTR(grabbed_devices, S_IRUSR, usbstub_devices_show, NULL);
   5.397 +
   5.398 +/* table of devices that matches any usbdevice */
   5.399 +static struct usb_device_id usbstub_table[] = {
   5.400 +		{ .driver_info = 1 }, /* wildcard, see usb_match_id() */
   5.401 +		{ } /* Terminating entry */
   5.402 +};
   5.403 +MODULE_DEVICE_TABLE(usb, usbstub_table);
   5.404 +
   5.405 +static struct usb_driver usbback_usb_driver = {
   5.406 +		.name = "usbback",
   5.407 +		.probe = usbstub_probe,
   5.408 +		.disconnect = usbstub_disconnect,
   5.409 +		.id_table = usbstub_table,
   5.410 +};
   5.411 +
   5.412 +int __init usbstub_init(void)
   5.413 +{
   5.414 + 	int err;
   5.415 +
   5.416 +	err = usb_register(&usbback_usb_driver);
   5.417 +	if (err < 0)
   5.418 +		goto out;
   5.419 +	if (!err)
   5.420 +		err = driver_create_file(&usbback_usb_driver.driver,
   5.421 +				&driver_attr_new_vport);
   5.422 +	if (!err)
   5.423 +		err = driver_create_file(&usbback_usb_driver.driver,
   5.424 +				&driver_attr_remove_vport);
   5.425 +	if (!err)
   5.426 +		err = driver_create_file(&usbback_usb_driver.driver,
   5.427 +				&driver_attr_vports);
   5.428 +	if (!err)
   5.429 +		err = driver_create_file(&usbback_usb_driver.driver,
   5.430 +				&driver_attr_grabbed_devices);
   5.431 +	if (err)
   5.432 +		usbstub_exit();
   5.433 +
   5.434 +out:
   5.435 +	return err;
   5.436 +}
   5.437 +
   5.438 +void __exit usbstub_exit(void)
   5.439 +{
   5.440 +	driver_remove_file(&usbback_usb_driver.driver,
   5.441 +			&driver_attr_new_vport);
   5.442 +	driver_remove_file(&usbback_usb_driver.driver,
   5.443 +			&driver_attr_remove_vport);
   5.444 +	driver_remove_file(&usbback_usb_driver.driver,
   5.445 +				&driver_attr_vports);
   5.446 +	driver_remove_file(&usbback_usb_driver.driver,
   5.447 +				&driver_attr_grabbed_devices);
   5.448 +
   5.449 +	usb_deregister(&usbback_usb_driver);
   5.450 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/drivers/xen/usbback/xenbus.c	Wed Mar 18 11:43:24 2009 +0000
     6.3 @@ -0,0 +1,269 @@
     6.4 +/*
     6.5 + * xenbus.c
     6.6 + *
     6.7 + * Xenbus interface for USB backend driver.
     6.8 + *
     6.9 + * Copyright (C) 2009, FUJITSU LABORATORIES LTD.
    6.10 + * Author: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
    6.11 + *
    6.12 + * This program is free software; you can redistribute it and/or modify
    6.13 + * it under the terms of the GNU General Public License as published by
    6.14 + * the Free Software Foundation; either version 2 of the License, or
    6.15 + * (at your option) any later version.
    6.16 + *
    6.17 + * This program is distributed in the hope that it will be useful,
    6.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    6.20 + * GNU General Public License for more details.
    6.21 + *
    6.22 + * You should have received a copy of the GNU General Public License
    6.23 + * along with this program; if not, see <http://www.gnu.org/licenses/>.
    6.24 + *
    6.25 + * or,
    6.26 + *
    6.27 + * When distributed separately from the Linux kernel or incorporated into
    6.28 + * other software packages, subject to the following license:
    6.29 + *
    6.30 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    6.31 + * of this software and associated documentation files (the "Software"), to
    6.32 + * deal in the Software without restriction, including without limitation the
    6.33 + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    6.34 + * sell copies of the Software, and to permit persons to whom the Software is
    6.35 + * furnished to do so, subject to the following conditions:
    6.36 + *
    6.37 + * The above copyright notice and this permission notice shall be included in
    6.38 + * all copies or substantial portions of the Software.
    6.39 + *
    6.40 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    6.41 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    6.42 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    6.43 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    6.44 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    6.45 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    6.46 + * DEALINGS IN THE SOFTWARE.
    6.47 + */
    6.48 +
    6.49 +#include <xen/xenbus.h>
    6.50 +#include "usbback.h"
    6.51 +
    6.52 +static int start_xenusbd(usbif_t *usbif)
    6.53 +{
    6.54 +        int err = 0;
    6.55 +        char name[TASK_COMM_LEN];
    6.56 +
    6.57 +        snprintf(name, TASK_COMM_LEN, "usbback.%d.%d", usbif->domid, usbif->handle);
    6.58 +        usbif->xenusbd = kthread_run(usbbk_schedule, usbif, name);
    6.59 +        if (IS_ERR(usbif->xenusbd)) {
    6.60 +                err = PTR_ERR(usbif->xenusbd);
    6.61 +                usbif->xenusbd = NULL;
    6.62 +                xenbus_dev_error(usbif->xbdev, err, "start xenusbd");
    6.63 +        }
    6.64 +        return err;
    6.65 +}
    6.66 +
    6.67 +static int usbback_remove(struct xenbus_device *dev)
    6.68 +{
    6.69 +	usbif_t *usbif = dev->dev.driver_data;
    6.70 +
    6.71 +	if (usbif) {
    6.72 +		usbif_disconnect(usbif);
    6.73 +		usbif_free(usbif);;
    6.74 +	}
    6.75 +	dev->dev.driver_data = NULL;
    6.76 +
    6.77 +	return 0;
    6.78 +}
    6.79 +
    6.80 +static int usbback_probe(struct xenbus_device *dev,
    6.81 +			  const struct xenbus_device_id *id)
    6.82 +{
    6.83 +	usbif_t *usbif;
    6.84 +	unsigned int handle;
    6.85 +	int err;
    6.86 +
    6.87 +	if (usb_disabled())
    6.88 +		return -ENODEV;
    6.89 +
    6.90 +	handle = simple_strtoul(strrchr(dev->otherend,'/')+1, NULL, 0);
    6.91 +	usbif = usbif_alloc(dev->otherend_id, handle);
    6.92 +	if (!usbif) {
    6.93 +		xenbus_dev_fatal(dev, -ENOMEM, "allocating backend interface");
    6.94 +		return -ENOMEM;
    6.95 +	}
    6.96 +	usbif->xbdev = dev;
    6.97 +	dev->dev.driver_data = usbif;
    6.98 +
    6.99 +	err = xenbus_switch_state(dev, XenbusStateInitWait);
   6.100 +	if (err)
   6.101 +		goto fail;
   6.102 +
   6.103 +	return 0;
   6.104 +
   6.105 +fail:
   6.106 +	usbback_remove(dev);
   6.107 +	return err;
   6.108 +}
   6.109 +
   6.110 +static int connect_ring(usbif_t *usbif)
   6.111 +{
   6.112 +	struct xenbus_device *dev = usbif->xbdev;
   6.113 +	unsigned long ring_ref;
   6.114 +	unsigned int evtchn;
   6.115 +	int err;
   6.116 +
   6.117 +	err = xenbus_gather(XBT_NIL, dev->otherend,
   6.118 +			    "ring-ref", "%lu", &ring_ref,
   6.119 +			    "event-channel", "%u", &evtchn, NULL);
   6.120 +	if (err) {
   6.121 +		xenbus_dev_fatal(dev, err,
   6.122 +				 "reading %s/ring-ref and event-channel",
   6.123 +				 dev->otherend);
   6.124 +		return err;
   6.125 +	}
   6.126 +
   6.127 +	printk("usbback: ring-ref %ld, event-channel %d\n",
   6.128 +	       ring_ref, evtchn);
   6.129 +
   6.130 +	err = usbif_map(usbif, ring_ref, evtchn);
   6.131 +	if (err) {
   6.132 +		xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
   6.133 +				 ring_ref, evtchn);
   6.134 +		return err;
   6.135 +	}
   6.136 +
   6.137 +	return 0;
   6.138 +}
   6.139 +
   6.140 +void usbback_do_hotplug(usbif_t *usbif)
   6.141 +{
   6.142 +	struct xenbus_transaction xbt;
   6.143 +	struct xenbus_device *dev = usbif->xbdev;
   6.144 +	struct usbstub *stub = NULL;
   6.145 +	int err;
   6.146 +	char port_str[8];
   6.147 +	int i;
   6.148 +	int num_ports;
   6.149 +	int state;
   6.150 +
   6.151 +again:
   6.152 +		err = xenbus_transaction_start(&xbt);
   6.153 +		if (err) {
   6.154 +			xenbus_dev_fatal(dev, err, "starting transaction");
   6.155 +			return;
   6.156 +		}
   6.157 +
   6.158 +		err = xenbus_scanf(xbt, dev->nodename,
   6.159 +					"num-ports", "%d", &num_ports);
   6.160 +
   6.161 +		for (i = 1; i <= num_ports; i++) {
   6.162 +			stub = find_attached_device(usbif, i);
   6.163 +			if (stub)
   6.164 +				state = stub->udev->speed;
   6.165 +			else
   6.166 +				state = 0;
   6.167 +			sprintf(port_str, "port-%d", i);
   6.168 +			err = xenbus_printf(xbt, dev->nodename, port_str, "%d", state);
   6.169 +			if (err) {
   6.170 +				xenbus_dev_fatal(dev, err, "writing port-%d state", i);
   6.171 +				goto abort;
   6.172 +			}
   6.173 +		}
   6.174 +
   6.175 +		err = xenbus_transaction_end(xbt, 0);
   6.176 +		if (err == -EAGAIN)
   6.177 +			goto again;
   6.178 +		if (err)
   6.179 +			xenbus_dev_fatal(dev, err, "completing transaction");
   6.180 +
   6.181 +		return;
   6.182 +
   6.183 +abort:
   6.184 +		xenbus_transaction_end(xbt, 1);
   6.185 +}
   6.186 +
   6.187 +void usbback_reconfigure(usbif_t *usbif)
   6.188 +{
   6.189 +	struct xenbus_device *dev = usbif->xbdev;
   6.190 +
   6.191 +	if (dev->state == XenbusStateConnected)
   6.192 +		xenbus_switch_state(dev, XenbusStateReconfiguring);
   6.193 +}
   6.194 +
   6.195 +void frontend_changed(struct xenbus_device *dev,
   6.196 +				     enum xenbus_state frontend_state)
   6.197 +{
   6.198 +	usbif_t *usbif = dev->dev.driver_data;
   6.199 +	int err;
   6.200 +
   6.201 +	switch (frontend_state) {
   6.202 +	case XenbusStateInitialising:
   6.203 +		if (dev->state == XenbusStateClosed) {
   6.204 +			printk("%s: %s: prepare for reconnect\n",
   6.205 +			       __FUNCTION__, dev->nodename);
   6.206 +			xenbus_switch_state(dev, XenbusStateInitWait);
   6.207 +		}
   6.208 +		break;
   6.209 +
   6.210 +	case XenbusStateInitialised:
   6.211 +		err = connect_ring(usbif);
   6.212 +		if (err)
   6.213 +			break;
   6.214 +		start_xenusbd(usbif);
   6.215 +		usbback_do_hotplug(usbif);
   6.216 +		xenbus_switch_state(dev, XenbusStateConnected);
   6.217 +		break;
   6.218 +
   6.219 +	case XenbusStateConnected:
   6.220 +		if (dev->state == XenbusStateConnected)
   6.221 +			break;
   6.222 +		xenbus_switch_state(dev, XenbusStateConnected);
   6.223 +		break;
   6.224 +
   6.225 +	case XenbusStateClosing:
   6.226 +		usbif_disconnect(usbif);
   6.227 +		xenbus_switch_state(dev, XenbusStateClosing);
   6.228 +		break;
   6.229 +
   6.230 +	case XenbusStateClosed:
   6.231 +		xenbus_switch_state(dev, XenbusStateClosed);
   6.232 +		break;
   6.233 +
   6.234 +	case XenbusStateReconfiguring:
   6.235 +		usbback_do_hotplug(usbif);
   6.236 +		xenbus_switch_state(dev, XenbusStateReconfigured);
   6.237 +		break;
   6.238 +
   6.239 +	case XenbusStateUnknown:
   6.240 +		device_unregister(&dev->dev);
   6.241 +		break;
   6.242 +
   6.243 +	default:
   6.244 +		xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
   6.245 +				 frontend_state);
   6.246 +		break;
   6.247 +	}
   6.248 +}
   6.249 +
   6.250 +static const struct xenbus_device_id usbback_ids[] = {
   6.251 +	{ "vusb" },
   6.252 +	{ "" },
   6.253 +};
   6.254 +
   6.255 +static struct xenbus_driver usbback_driver = {
   6.256 +	.name = "vusb",
   6.257 +	.owner = THIS_MODULE,
   6.258 +	.ids = usbback_ids,
   6.259 +	.probe = usbback_probe,
   6.260 +	.otherend_changed = frontend_changed,
   6.261 +	.remove = usbback_remove,
   6.262 +};
   6.263 +
   6.264 +void usbback_xenbus_init(void)
   6.265 +{
   6.266 +	xenbus_register_backend(&usbback_driver);
   6.267 +}
   6.268 +
   6.269 +void usbback_xenbus_exit(void)
   6.270 +{
   6.271 +	xenbus_unregister_driver(&usbback_driver);
   6.272 +}