debuggers.hg
changeset 3501:3ced9b0f4dab
bitkeeper revision 1.1159.212.23 (41ee5e8fnbA6nB8wOl_As73BmvhklQ)
Support for USB virtualisation. Adds the USB frontend / backend, update build options,
make the control tools understand USB interfaces.
One extra file from vanilla Linux is imported (linux-2.4.28-xen-sparse/drivers/usb/hcd.c)
because small changes were required to make XenU domains build with a USB frontend. This
will not be required for the revised host controller infrastructure in Linux 2.6.
To use this, set "usb = " a list of USB ports in the domain config file. Ports are
specified as a path, e.g. '1' = the first USB port on the host, '1/2' is the second port
on the hub on the first host port, etc.
Should work for most mass storage and isochronous devices. May work for some HID devices
but these are not as intelligent and may have trouble supporting virtualisation.
Support for USB virtualisation. Adds the USB frontend / backend, update build options,
make the control tools understand USB interfaces.
One extra file from vanilla Linux is imported (linux-2.4.28-xen-sparse/drivers/usb/hcd.c)
because small changes were required to make XenU domains build with a USB frontend. This
will not be required for the revised host controller infrastructure in Linux 2.6.
To use this, set "usb = " a list of USB ports in the domain config file. Ports are
specified as a path, e.g. '1' = the first USB port on the host, '1/2' is the second port
on the hub on the first host port, etc.
Should work for most mass storage and isochronous devices. May work for some HID devices
but these are not as intelligent and may have trouble supporting virtualisation.
line diff
1.1 --- a/.rootkeys Wed Jan 19 08:53:39 2005 +0000 1.2 +++ b/.rootkeys Wed Jan 19 13:20:15 2005 +0000 1.3 @@ -63,6 +63,16 @@ 40420a6ebRqDjufoN1WSJvolEW2Wjw linux-2.4 1.4 4083dc16-Kd5y9psK_yk161sme5j5Q linux-2.4.28-xen-sparse/arch/xen/drivers/netif/Makefile 1.5 4083dc16UmHXxS9g_UFVnkUpN-oP2Q linux-2.4.28-xen-sparse/arch/xen/drivers/netif/backend/Makefile 1.6 405853f2wg7JXZJNltspMwOZJklxgw linux-2.4.28-xen-sparse/arch/xen/drivers/netif/frontend/Makefile 1.7 +41ee5e8b_2rt-qHzbDXtIoBzOli0EA linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/Makefile 1.8 +41ee5e8bUhF4tH7OoJaVbUxdXqneVw linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/Makefile 1.9 +41ee5e8bYDQkjRVKnFn5uFyy0KreCw linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/common.h 1.10 +41ee5e8bt7xeBUJqG5XJS-ofukdsgA linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/control.c 1.11 +41ee5e8bSs3BGC7yegM_ek2Tn0Ahvw linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/interface.c 1.12 +41ee5e8bglvqKvZSY5uJ5JGQejEwyQ linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/main.c 1.13 +41ee5e8bSPpxzhGO6TrY20TegW3cZg linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile 1.14 +41ee5e8ckZ9xVNvu9NHIZDK7JqApmQ linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/main.c 1.15 +41ee5e8ck9scpGirfqEZRARbGDyTXA linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/xhci.h 1.16 +41ee5e8c6mLxIx82KPsbpt_uts_vSA linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/usbif.h 1.17 3e5a4e65lWzkiPXsZdzPt2RNnJGG1g linux-2.4.28-xen-sparse/arch/xen/kernel/Makefile 1.18 3e5a4e65_hqfuxtGG8IUy6wRM86Ecg linux-2.4.28-xen-sparse/arch/xen/kernel/entry.S 1.19 3e5a4e65Hy_1iUvMTPsNqGNXd9uFpg linux-2.4.28-xen-sparse/arch/xen/kernel/head.S 1.20 @@ -87,6 +97,7 @@ 40d70c24-Dy2HUMrwSZagfXvAPnI4w linux-2.4 1.21 3f108aeaLcGDgQdFAANLTUEid0a05w linux-2.4.28-xen-sparse/drivers/char/mem.c 1.22 3e5a4e66rw65CxyolW9PKz4GG42RcA linux-2.4.28-xen-sparse/drivers/char/tty_io.c 1.23 40c9c0c1pPwYE3-4i-oI3ubUu7UgvQ linux-2.4.28-xen-sparse/drivers/scsi/aic7xxx/Makefile 1.24 +41ee5e8c__abdO50ZtQjPeSa5VN2dg linux-2.4.28-xen-sparse/drivers/usb/hcd.c 1.25 3e5a4e669uzIE54VwucPYtGwXLAbzA linux-2.4.28-xen-sparse/fs/exec.c 1.26 3e5a4e66wbeCpsJgVf_U8Jde-CNcsA linux-2.4.28-xen-sparse/include/asm-xen/bugs.h 1.27 3e5a4e66HdSkvIV6SJ1evG_xmTmXHA linux-2.4.28-xen-sparse/include/asm-xen/desc.h 1.28 @@ -680,6 +691,7 @@ 40c9c469-8mYEJJTAR6w_ClrJRAfwQ tools/pyt 1.29 40c9c4694eu5759Dehr4Uhakei0EMg tools/python/xen/xend/server/SrvNode.py 1.30 40c9c469TaZ83ypsrktmPSHLEZiP5w tools/python/xen/xend/server/SrvRoot.py 1.31 40c9c469W3sgDMbBJYQdz5wbQweL0Q tools/python/xen/xend/server/SrvServer.py 1.32 +41ee5e8cFlODpYxhBMZqo9ZgGtcHbg tools/python/xen/xend/server/SrvUsbif.py 1.33 40c9c469aq7oXrE1Ngqf3_lBqL0RoQ tools/python/xen/xend/server/SrvVnetDir.py 1.34 4108f181GtRoD1U9TBuJXMfBbGJwdQ tools/python/xen/xend/server/SrvXendLog.py 1.35 40c9c469Y_aimoOFfUZoS-4eV8gEKg tools/python/xen/xend/server/__init__.py 1.36 @@ -691,6 +703,7 @@ 40d83983OXjt-y3HjSCcuoPp9rzvmw tools/pyt 1.37 40c9c469yrm31i60pGKslTi2Zgpotg tools/python/xen/xend/server/messages.py 1.38 40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/python/xen/xend/server/netif.py 1.39 40c9c469ZqILEQ8x6yWy0_51jopiCg tools/python/xen/xend/server/params.py 1.40 +41ee5e8dq9NtihbL4nWKjuSLOhXPUg tools/python/xen/xend/server/usbif.py 1.41 40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py 1.42 4189125cL90jKSOcBJ3Vx4nWGiXXvA tools/python/xen/xend/util.py 1.43 40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py
2.1 --- a/linux-2.4.28-xen-sparse/arch/xen/Makefile Wed Jan 19 08:53:39 2005 +0000 2.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/Makefile Wed Jan 19 13:20:15 2005 +0000 2.3 @@ -61,6 +61,7 @@ SUBDIRS += arch/xen/drivers/console 2.4 SUBDIRS += arch/xen/drivers/evtchn 2.5 SUBDIRS += arch/xen/drivers/blkif 2.6 SUBDIRS += arch/xen/drivers/netif 2.7 +SUBDIRS += arch/xen/drivers/usbif 2.8 SUBDIRS += arch/xen/drivers/balloon 2.9 ifdef CONFIG_XEN_PRIVILEGED_GUEST 2.10 SUBDIRS += arch/xen/drivers/dom0 2.11 @@ -71,6 +72,7 @@ CORE_FILES += arch/xen/drivers/evtchn/dr 2.12 CORE_FILES += arch/xen/drivers/console/drv.o 2.13 DRIVERS += arch/xen/drivers/blkif/drv.o 2.14 DRIVERS += arch/xen/drivers/netif/drv.o 2.15 +DRIVERS += arch/xen/drivers/usbif/drv.o 2.16 ifdef CONFIG_XEN_PRIVILEGED_GUEST 2.17 CORE_FILES += arch/xen/drivers/dom0/drv.o 2.18 endif
3.1 --- a/linux-2.4.28-xen-sparse/arch/xen/config.in Wed Jan 19 08:53:39 2005 +0000 3.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/config.in Wed Jan 19 13:20:15 2005 +0000 3.3 @@ -16,14 +16,18 @@ mainmenu_option next_comment 3.4 comment 'Xen' 3.5 bool 'Support for privileged operations (domain 0)' CONFIG_XEN_PRIVILEGED_GUEST 3.6 bool 'Device-driver domain (physical device access)' CONFIG_XEN_PHYSDEV_ACCESS 3.7 +if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" ]; then 3.8 + bool 'USB-device backend driver' CONFIG_XEN_USB_BACKEND 3.9 +fi 3.10 bool 'Scrub memory before freeing it to Xen' CONFIG_XEN_SCRUB_PAGES 3.11 bool 'Network-device frontend driver' CONFIG_XEN_NETDEV_FRONTEND 3.12 bool 'Block-device frontend driver' CONFIG_XEN_BLKDEV_FRONTEND 3.13 +bool 'USB-device frontend driver' CONFIG_XEN_USB_FRONTEND 3.14 endmenu 3.15 # The IBM S/390 patch needs this. 3.16 define_bool CONFIG_NO_IDLE_HZ y 3.17 3.18 -if [ "$CONFIG_XEN_PHYSDEV_ACCESS" == "y" ]; then 3.19 +if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" ]; then 3.20 define_bool CONFIG_FOREIGN_PAGES y 3.21 else 3.22 define_bool CONFIG_FOREIGN_PAGES n 3.23 @@ -262,7 +266,7 @@ fi 3.24 3.25 source drivers/char/Config.in 3.26 3.27 -if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" ]; then 3.28 +if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" -o "$CONFIG_XEN_USB_FRONTEND" = "y" ]; then 3.29 source drivers/media/Config.in 3.30 fi 3.31 3.32 @@ -295,9 +299,16 @@ if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" 3.33 source drivers/sound/Config.in 3.34 fi 3.35 endmenu 3.36 +fi 3.37 3.38 +if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" -o "$CONFIG_XEN_USB_FRONTEND" = "y" ]; then 3.39 + if [ "$CONFIG_XEN_USB_FRONTEND" = "y" -o "$CONFIG_XEN_USB_BACKEND" = "y" ]; then 3.40 + define_bool CONFIG_USB y 3.41 + fi 3.42 source drivers/usb/Config.in 3.43 +fi 3.44 3.45 +if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" ]; then 3.46 source net/bluetooth/Config.in 3.47 fi 3.48
4.1 --- a/linux-2.4.28-xen-sparse/arch/xen/defconfig-xen0 Wed Jan 19 08:53:39 2005 +0000 4.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/defconfig-xen0 Wed Jan 19 13:20:15 2005 +0000 4.3 @@ -12,9 +12,11 @@ CONFIG_UID16=y 4.4 # 4.5 CONFIG_XEN_PRIVILEGED_GUEST=y 4.6 CONFIG_XEN_PHYSDEV_ACCESS=y 4.7 +# CONFIG_XEN_USB_BACKEND is not set 4.8 CONFIG_XEN_SCRUB_PAGES=y 4.9 CONFIG_XEN_NETDEV_FRONTEND=y 4.10 CONFIG_XEN_BLKDEV_FRONTEND=y 4.11 +# CONFIG_XEN_USB_FRONTEND is not set 4.12 CONFIG_NO_IDLE_HZ=y 4.13 CONFIG_FOREIGN_PAGES=y 4.14
5.1 --- a/linux-2.4.28-xen-sparse/arch/xen/defconfig-xenU Wed Jan 19 08:53:39 2005 +0000 5.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/defconfig-xenU Wed Jan 19 13:20:15 2005 +0000 5.3 @@ -15,6 +15,7 @@ CONFIG_UID16=y 5.4 CONFIG_XEN_SCRUB_PAGES=y 5.5 CONFIG_XEN_NETDEV_FRONTEND=y 5.6 CONFIG_XEN_BLKDEV_FRONTEND=y 5.7 +# CONFIG_XEN_USB_FRONTEND is not set 5.8 CONFIG_NO_IDLE_HZ=y 5.9 # CONFIG_FOREIGN_PAGES is not set 5.10 CONFIG_NETDEVICES=y
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/Makefile Wed Jan 19 13:20:15 2005 +0000 6.3 @@ -0,0 +1,10 @@ 6.4 + 6.5 +O_TARGET := drv.o 6.6 + 6.7 +subdir-$(CONFIG_XEN_USB_FRONTEND) += frontend 6.8 +obj-$(CONFIG_XEN_USB_FRONTEND) += frontend/drv.o 6.9 + 6.10 +subdir-$(CONFIG_XEN_USB_BACKEND) += backend 6.11 +obj-$(CONFIG_XEN_USB_BACKEND) += backend/drv.o 6.12 + 6.13 +include $(TOPDIR)/Rules.make
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/Makefile Wed Jan 19 13:20:15 2005 +0000 7.3 @@ -0,0 +1,3 @@ 7.4 +O_TARGET := drv.o 7.5 +obj-y := main.o interface.o control.o # vrh.o don't think I need this! 7.6 +include $(TOPDIR)/Rules.make
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/common.h Wed Jan 19 13:20:15 2005 +0000 8.3 @@ -0,0 +1,87 @@ 8.4 + 8.5 +#ifndef __USBIF__BACKEND__COMMON_H__ 8.6 +#define __USBIF__BACKEND__COMMON_H__ 8.7 + 8.8 +#include <linux/config.h> 8.9 +#include <linux/version.h> 8.10 +#include <linux/module.h> 8.11 +#include <linux/rbtree.h> 8.12 +#include <linux/interrupt.h> 8.13 +#include <linux/slab.h> 8.14 +#include <linux/blkdev.h> 8.15 +#include <asm/io.h> 8.16 +#include <asm/setup.h> 8.17 +#include <asm/pgalloc.h> 8.18 +#include <asm-xen/ctrl_if.h> 8.19 +#include <asm-xen/hypervisor.h> 8.20 + 8.21 +#include "../usbif.h" 8.22 + 8.23 +#if 0 8.24 +#define ASSERT(_p) \ 8.25 + if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \ 8.26 + __LINE__, __FILE__); *(int*)0=0; } 8.27 +#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \ 8.28 + __FILE__ , __LINE__ , ## _a ) 8.29 +#else 8.30 +#define ASSERT(_p) ((void)0) 8.31 +#define DPRINTK(_f, _a...) ((void)0) 8.32 +#endif 8.33 + 8.34 +typedef struct usbif_priv_st usbif_priv_t; 8.35 + 8.36 +struct usbif_priv_st { 8.37 + /* Unique identifier for this interface. */ 8.38 + domid_t domid; 8.39 + unsigned int handle; 8.40 + /* Physical parameters of the comms window. */ 8.41 + unsigned long shmem_frame; 8.42 + unsigned int evtchn; 8.43 + int irq; 8.44 + /* Comms information. */ 8.45 + usbif_t *usb_ring_base; /* ioremap()'ed ptr to shmem_frame. */ 8.46 + USBIF_RING_IDX usb_req_cons; /* Request consumer. */ 8.47 + USBIF_RING_IDX usb_resp_prod; /* Private version of resp. producer. */ 8.48 + /* Private fields. */ 8.49 + enum { DISCONNECTED, DISCONNECTING, CONNECTED } status; 8.50 + /* 8.51 + * DISCONNECT response is deferred until pending requests are ack'ed. 8.52 + * We therefore need to store the id from the original request. 8.53 + */ 8.54 + u8 disconnect_rspid; 8.55 + usbif_priv_t *hash_next; 8.56 + struct list_head usbif_list; 8.57 + spinlock_t usb_ring_lock; 8.58 + atomic_t refcnt; 8.59 + atomic_t work_scheduled; 8.60 + 8.61 + struct work_struct work; 8.62 +}; 8.63 + 8.64 +void usbif_create(usbif_be_create_t *create); 8.65 +void usbif_destroy(usbif_be_destroy_t *destroy); 8.66 +void usbif_connect(usbif_be_connect_t *connect); 8.67 +int usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id); 8.68 +void usbif_disconnect_complete(usbif_priv_t *up); 8.69 + 8.70 +void usbif_release_port(usbif_be_release_port_t *msg); 8.71 +int usbif_claim_port(usbif_be_claim_port_t *msg); 8.72 +void usbif_release_ports(usbif_priv_t *up); 8.73 + 8.74 +usbif_priv_t *usbif_find(domid_t domid); 8.75 +#define usbif_get(_b) (atomic_inc(&(_b)->refcnt)) 8.76 +#define usbif_put(_b) \ 8.77 + do { \ 8.78 + if ( atomic_dec_and_test(&(_b)->refcnt) ) \ 8.79 + usbif_disconnect_complete(_b); \ 8.80 + } while (0) 8.81 + 8.82 + 8.83 +void usbif_interface_init(void); 8.84 +void usbif_ctrlif_init(void); 8.85 + 8.86 +void usbif_deschedule(usbif_priv_t *usbif); 8.87 + 8.88 +irqreturn_t usbif_be_int(int irq, void *dev_id, struct pt_regs *regs); 8.89 + 8.90 +#endif /* __USBIF__BACKEND__COMMON_H__ */
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/control.c Wed Jan 19 13:20:15 2005 +0000 9.3 @@ -0,0 +1,77 @@ 9.4 +/****************************************************************************** 9.5 + * arch/xen/drivers/usbif/backend/control.c 9.6 + * 9.7 + * Routines for interfacing with the control plane. 9.8 + * 9.9 + * Copyright (c) 2004, Keir Fraser 9.10 + */ 9.11 + 9.12 +#include "common.h" 9.13 + 9.14 +static void usbif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id) 9.15 +{ 9.16 + DPRINTK("Received usbif backend message, subtype=%d\n", msg->subtype); 9.17 + 9.18 + switch ( msg->subtype ) 9.19 + { 9.20 + case CMSG_USBIF_BE_CREATE: 9.21 + if ( msg->length != sizeof(usbif_be_create_t) ) 9.22 + goto parse_error; 9.23 + usbif_create((usbif_be_create_t *)&msg->msg[0]); 9.24 + break; 9.25 + case CMSG_USBIF_BE_DESTROY: 9.26 + if ( msg->length != sizeof(usbif_be_destroy_t) ) 9.27 + goto parse_error; 9.28 + usbif_destroy((usbif_be_destroy_t *)&msg->msg[0]); 9.29 + break; 9.30 + case CMSG_USBIF_BE_CONNECT: 9.31 + if ( msg->length != sizeof(usbif_be_connect_t) ) 9.32 + goto parse_error; 9.33 + usbif_connect((usbif_be_connect_t *)&msg->msg[0]); 9.34 + break; 9.35 + case CMSG_USBIF_BE_DISCONNECT: 9.36 + if ( msg->length != sizeof(usbif_be_disconnect_t) ) 9.37 + goto parse_error; 9.38 + if ( !usbif_disconnect((usbif_be_disconnect_t *)&msg->msg[0],msg->id) ) 9.39 + return; /* Sending the response is deferred until later. */ 9.40 + break; 9.41 + case CMSG_USBIF_BE_CLAIM_PORT: 9.42 + if ( msg->length != sizeof(usbif_be_claim_port_t) ) 9.43 + goto parse_error; 9.44 + usbif_claim_port((usbif_be_claim_port_t *)&msg->msg[0]); 9.45 + break; 9.46 + case CMSG_USBIF_BE_RELEASE_PORT: 9.47 + if ( msg->length != sizeof(usbif_be_release_port_t) ) 9.48 + goto parse_error; 9.49 + usbif_release_port((usbif_be_release_port_t *)&msg->msg[0]); 9.50 + break; 9.51 + default: 9.52 + goto parse_error; 9.53 + } 9.54 + 9.55 + ctrl_if_send_response(msg); 9.56 + return; 9.57 + 9.58 + parse_error: 9.59 + DPRINTK("Parse error while reading message subtype %d, len %d\n", 9.60 + msg->subtype, msg->length); 9.61 + msg->length = 0; 9.62 + ctrl_if_send_response(msg); 9.63 +} 9.64 + 9.65 +void usbif_ctrlif_init(void) 9.66 +{ 9.67 + ctrl_msg_t cmsg; 9.68 + usbif_be_driver_status_changed_t st; 9.69 + 9.70 + (void)ctrl_if_register_receiver(CMSG_USBIF_BE, usbif_ctrlif_rx, 9.71 + CALLBACK_IN_BLOCKING_CONTEXT); 9.72 + 9.73 + /* Send a driver-UP notification to the domain controller. */ 9.74 + cmsg.type = CMSG_USBIF_BE; 9.75 + cmsg.subtype = CMSG_USBIF_BE_DRIVER_STATUS_CHANGED; 9.76 + cmsg.length = sizeof(usbif_be_driver_status_changed_t); 9.77 + st.status = USBIF_DRIVER_STATUS_UP; 9.78 + memcpy(cmsg.msg, &st, sizeof(st)); 9.79 + ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); 9.80 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/interface.c Wed Jan 19 13:20:15 2005 +0000 10.3 @@ -0,0 +1,248 @@ 10.4 +/****************************************************************************** 10.5 + * arch/xen/drivers/usbif/backend/interface.c 10.6 + * 10.7 + * USB device interface management. 10.8 + * 10.9 + * by Mark Williamson, Copyright (c) 2004 10.10 + */ 10.11 + 10.12 + 10.13 +/****************************************************************************** 10.14 + * arch/xen/drivers/blkif/backend/interface.c 10.15 + * 10.16 + * Block-device interface management. 10.17 + * 10.18 + * Copyright (c) 2004, Keir Fraser 10.19 + */ 10.20 + 10.21 +#include "common.h" 10.22 + 10.23 +#define USBIF_HASHSZ 1024 10.24 +#define USBIF_HASH(_d) (((int)(_d))&(USBIF_HASHSZ-1)) 10.25 + 10.26 +static kmem_cache_t *usbif_priv_cachep; 10.27 +static usbif_priv_t *usbif_priv_hash[USBIF_HASHSZ]; 10.28 + 10.29 +usbif_priv_t *usbif_find(domid_t domid) 10.30 +{ 10.31 + usbif_priv_t *up = usbif_priv_hash[USBIF_HASH(domid)]; 10.32 + while ( (up != NULL ) && ( up->domid != domid ) ) 10.33 + up = up->hash_next; 10.34 + return up; 10.35 +} 10.36 + 10.37 +static void __usbif_disconnect_complete(void *arg) 10.38 +{ 10.39 + usbif_priv_t *usbif = (usbif_priv_t *)arg; 10.40 + ctrl_msg_t cmsg; 10.41 + usbif_be_disconnect_t disc; 10.42 + 10.43 + /* 10.44 + * These can't be done in usbif_disconnect() because at that point there 10.45 + * may be outstanding requests at the device whose asynchronous responses 10.46 + * must still be notified to the remote driver. 10.47 + */ 10.48 + unbind_evtchn_from_irq(usbif->evtchn); 10.49 + vfree(usbif->usb_ring_base); 10.50 + 10.51 + /* Construct the deferred response message. */ 10.52 + cmsg.type = CMSG_USBIF_BE; 10.53 + cmsg.subtype = CMSG_USBIF_BE_DISCONNECT; 10.54 + cmsg.id = usbif->disconnect_rspid; 10.55 + cmsg.length = sizeof(usbif_be_disconnect_t); 10.56 + disc.domid = usbif->domid; 10.57 + disc.status = USBIF_BE_STATUS_OKAY; 10.58 + memcpy(cmsg.msg, &disc, sizeof(disc)); 10.59 + 10.60 + /* 10.61 + * Make sure message is constructed /before/ status change, because 10.62 + * after the status change the 'usbif' structure could be deallocated at 10.63 + * any time. Also make sure we send the response /after/ status change, 10.64 + * as otherwise a subsequent CONNECT request could spuriously fail if 10.65 + * another CPU doesn't see the status change yet. 10.66 + */ 10.67 + mb(); 10.68 + if ( usbif->status != DISCONNECTING ) 10.69 + BUG(); 10.70 + usbif->status = DISCONNECTED; 10.71 + mb(); 10.72 + 10.73 + /* Send the successful response. */ 10.74 + ctrl_if_send_response(&cmsg); 10.75 +} 10.76 + 10.77 +void usbif_disconnect_complete(usbif_priv_t *up) 10.78 +{ 10.79 + INIT_WORK(&up->work, __usbif_disconnect_complete, (void *)up); 10.80 + schedule_work(&up->work); 10.81 +} 10.82 + 10.83 +void usbif_create(usbif_be_create_t *create) 10.84 +{ 10.85 + domid_t domid = create->domid; 10.86 + usbif_priv_t **pup, *up; 10.87 + 10.88 + if ( (up = kmem_cache_alloc(usbif_priv_cachep, GFP_KERNEL)) == NULL ) 10.89 + { 10.90 + DPRINTK("Could not create usbif: out of memory\n"); 10.91 + create->status = USBIF_BE_STATUS_OUT_OF_MEMORY; 10.92 + return; 10.93 + } 10.94 + 10.95 + memset(up, 0, sizeof(*up)); 10.96 + up->domid = domid; 10.97 + up->status = DISCONNECTED; 10.98 + spin_lock_init(&up->usb_ring_lock); 10.99 + atomic_set(&up->refcnt, 0); 10.100 + 10.101 + pup = &usbif_priv_hash[USBIF_HASH(domid)]; 10.102 + while ( *pup != NULL ) 10.103 + { 10.104 + if ( (*pup)->domid == domid ) 10.105 + { 10.106 + create->status = USBIF_BE_STATUS_INTERFACE_EXISTS; 10.107 + kmem_cache_free(usbif_priv_cachep, up); 10.108 + return; 10.109 + } 10.110 + pup = &(*pup)->hash_next; 10.111 + } 10.112 + 10.113 + up->hash_next = *pup; 10.114 + *pup = up; 10.115 + 10.116 + create->status = USBIF_BE_STATUS_OKAY; 10.117 +} 10.118 + 10.119 +void usbif_destroy(usbif_be_destroy_t *destroy) 10.120 +{ 10.121 + domid_t domid = destroy->domid; 10.122 + usbif_priv_t **pup, *up; 10.123 + 10.124 + pup = &usbif_priv_hash[USBIF_HASH(domid)]; 10.125 + while ( (up = *pup) != NULL ) 10.126 + { 10.127 + if ( up->domid == domid ) 10.128 + { 10.129 + if ( up->status != DISCONNECTED ) 10.130 + goto still_connected; 10.131 + goto destroy; 10.132 + } 10.133 + pup = &up->hash_next; 10.134 + } 10.135 + 10.136 + destroy->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND; 10.137 + return; 10.138 + 10.139 + still_connected: 10.140 + destroy->status = USBIF_BE_STATUS_INTERFACE_CONNECTED; 10.141 + return; 10.142 + 10.143 + destroy: 10.144 + *pup = up->hash_next; 10.145 + usbif_release_ports(up); 10.146 + kmem_cache_free(usbif_priv_cachep, up); 10.147 + destroy->status = USBIF_BE_STATUS_OKAY; 10.148 +} 10.149 + 10.150 +void usbif_connect(usbif_be_connect_t *connect) 10.151 +{ 10.152 + domid_t domid = connect->domid; 10.153 + unsigned int evtchn = connect->evtchn; 10.154 + unsigned long shmem_frame = connect->shmem_frame; 10.155 + struct vm_struct *vma; 10.156 + pgprot_t prot; 10.157 + int error; 10.158 + usbif_priv_t *up; 10.159 + 10.160 + up = usbif_find(domid); 10.161 + if ( unlikely(up == NULL) ) 10.162 + { 10.163 + DPRINTK("usbif_connect attempted for non-existent usbif (%u)\n", 10.164 + connect->domid); 10.165 + connect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND; 10.166 + return; 10.167 + } 10.168 + 10.169 + if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL ) 10.170 + { 10.171 + connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY; 10.172 + return; 10.173 + } 10.174 + 10.175 + prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED); 10.176 + error = direct_remap_area_pages(&init_mm, VMALLOC_VMADDR(vma->addr), 10.177 + shmem_frame<<PAGE_SHIFT, PAGE_SIZE, 10.178 + prot, domid); 10.179 + if ( error != 0 ) 10.180 + { 10.181 + if ( error == -ENOMEM ) 10.182 + connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY; 10.183 + else if ( error == -EFAULT ) 10.184 + connect->status = USBIF_BE_STATUS_MAPPING_ERROR; 10.185 + else 10.186 + connect->status = USBIF_BE_STATUS_ERROR; 10.187 + vfree(vma->addr); 10.188 + return; 10.189 + } 10.190 + 10.191 + if ( up->status != DISCONNECTED ) 10.192 + { 10.193 + connect->status = USBIF_BE_STATUS_INTERFACE_CONNECTED; 10.194 + vfree(vma->addr); 10.195 + return; 10.196 + } 10.197 + 10.198 + up->evtchn = evtchn; 10.199 + up->irq = bind_evtchn_to_irq(evtchn); 10.200 + up->shmem_frame = shmem_frame; 10.201 + up->usb_ring_base = (usbif_t *)vma->addr; 10.202 + up->status = CONNECTED; 10.203 + usbif_get(up); 10.204 + 10.205 + request_irq(up->irq, usbif_be_int, 0, "usbif-backend", up); 10.206 + 10.207 + connect->status = USBIF_BE_STATUS_OKAY; 10.208 +} 10.209 + 10.210 +/* Remove URBs for this interface before destroying it. */ 10.211 +void usbif_deschedule(usbif_priv_t *up) 10.212 +{ 10.213 + remove_from_usbif_list(up); 10.214 +} 10.215 + 10.216 +int usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id) 10.217 +{ 10.218 + domid_t domid = disconnect->domid; 10.219 + usbif_priv_t *up; 10.220 + 10.221 + up = usbif_find(domid); 10.222 + if ( unlikely(up == NULL) ) 10.223 + { 10.224 + DPRINTK("usbif_disconnect attempted for non-existent usbif" 10.225 + " (%u)\n", disconnect->domid); 10.226 + disconnect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND; 10.227 + return 1; /* Caller will send response error message. */ 10.228 + } 10.229 + 10.230 + if ( up->status == CONNECTED ) 10.231 + { 10.232 + up->status = DISCONNECTING; 10.233 + up->disconnect_rspid = rsp_id; 10.234 + wmb(); /* Let other CPUs see the status change. */ 10.235 + free_irq(up->irq, up); 10.236 + usbif_deschedule(up); 10.237 + usbif_put(up); 10.238 + return 0; /* Caller should not send response message. */ 10.239 + } 10.240 + 10.241 + disconnect->status = USBIF_BE_STATUS_OKAY; 10.242 + return 1; 10.243 +} 10.244 + 10.245 +void __init usbif_interface_init(void) 10.246 +{ 10.247 + usbif_priv_cachep = kmem_cache_create("usbif_priv_cache", 10.248 + sizeof(usbif_priv_t), 10.249 + 0, 0, NULL, NULL); 10.250 + memset(usbif_priv_hash, 0, sizeof(usbif_priv_hash)); 10.251 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/main.c Wed Jan 19 13:20:15 2005 +0000 11.3 @@ -0,0 +1,1011 @@ 11.4 +/****************************************************************************** 11.5 + * arch/xen/drivers/usbif/backend/main.c 11.6 + * 11.7 + * Backend for the Xen virtual USB driver - provides an abstraction of a 11.8 + * USB host controller to the corresponding frontend driver. 11.9 + * 11.10 + * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge 11.11 + * 11.12 + * Based on arch/xen/drivers/blkif/backend/main.c 11.13 + * Copyright (c) 2003-2004, Keir Fraser & Steve Hand 11.14 + */ 11.15 + 11.16 +#include "common.h" 11.17 + 11.18 + 11.19 +#include <linux/list.h> 11.20 +#include <linux/usb.h> 11.21 +#include <linux/spinlock.h> 11.22 +#include <linux/module.h> 11.23 +#include <linux/tqueue.h> 11.24 + 11.25 +/* 11.26 + * This is rather arbitrary. 11.27 + */ 11.28 +#define MAX_PENDING_REQS 4 11.29 +#define BATCH_PER_DOMAIN 1 11.30 + 11.31 +static unsigned long mmap_vstart; 11.32 + 11.33 +/* Needs to be sufficiently large that we can map the (large) buffers 11.34 + * the USB mass storage driver wants. */ 11.35 +#define MMAP_PAGES_PER_REQUEST \ 11.36 + (128) 11.37 +#define MMAP_PAGES \ 11.38 + (MAX_PENDING_REQS * MMAP_PAGES_PER_REQUEST) 11.39 + 11.40 +#define MMAP_VADDR(_req,_seg) \ 11.41 + (mmap_vstart + \ 11.42 + ((_req) * MMAP_PAGES_PER_REQUEST * PAGE_SIZE) + \ 11.43 + ((_seg) * PAGE_SIZE)) 11.44 + 11.45 +#define MIN(x,y) ( ( x < y ) ? x : y ) 11.46 + 11.47 +static spinlock_t owned_ports_lock; 11.48 +LIST_HEAD(owned_ports); 11.49 + 11.50 +/* A list of these structures is used to track ownership of physical USB 11.51 + * ports. */ 11.52 +typedef struct 11.53 +{ 11.54 + usbif_priv_t *usbif_priv; 11.55 + char path[16]; 11.56 + int guest_port; 11.57 + int enabled; 11.58 + struct list_head list; 11.59 + unsigned long guest_address; /* The USB device address that has been 11.60 + * assigned by the guest. */ 11.61 + int dev_present; /* Is there a device present? */ 11.62 + struct usb_device * dev; 11.63 + unsigned long ifaces; /* What interfaces are present on this device? */ 11.64 +} owned_port_t; 11.65 + 11.66 + 11.67 +/* 11.68 + * Each outstanding request that we've passed to the lower device layers has a 11.69 + * 'pending_req' allocated to it. The request is complete, the specified 11.70 + * domain has a response queued for it, with the saved 'id' passed back. 11.71 + */ 11.72 +typedef struct { 11.73 + usbif_priv_t *usbif_priv; 11.74 + usbif_iso_t *iso_sched; 11.75 + unsigned long id; 11.76 + int nr_pages; 11.77 + unsigned short operation; 11.78 + int status; 11.79 +} pending_req_t; 11.80 + 11.81 +/* 11.82 + * We can't allocate pending_req's in order, since they may complete out of 11.83 + * order. We therefore maintain an allocation ring. This ring also indicates 11.84 + * when enough work has been passed down -- at that point the allocation ring 11.85 + * will be empty. 11.86 + */ 11.87 +static pending_req_t pending_reqs[MAX_PENDING_REQS]; 11.88 +static unsigned char pending_ring[MAX_PENDING_REQS]; 11.89 +static spinlock_t pend_prod_lock = SPIN_LOCK_UNLOCKED; 11.90 + 11.91 +/* NB. We use a different index type to differentiate from shared blk rings. */ 11.92 +typedef unsigned int PEND_RING_IDX; 11.93 +#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1)) 11.94 +static PEND_RING_IDX pending_prod, pending_cons; 11.95 +#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons) 11.96 + 11.97 +static int do_usb_io_op(usbif_priv_t *usbif, int max_to_do); 11.98 +static void make_response(usbif_priv_t *usbif, unsigned long id, 11.99 + unsigned short op, int st, int inband, 11.100 + unsigned long actual_length); 11.101 +static void dispatch_usb_probe(usbif_priv_t *up, unsigned long id, unsigned long port); 11.102 +static void dispatch_usb_io(usbif_priv_t *up, usbif_request_t *req); 11.103 +static void dispatch_usb_reset(usbif_priv_t *up, unsigned long portid); 11.104 +static owned_port_t *usbif_find_port(char *); 11.105 + 11.106 + 11.107 +void dump_port(owned_port_t *p) 11.108 +{ 11.109 + printk("owned_port_t @ %p\n", p); 11.110 + printk(" usbif_priv @ %p\n", p->usbif_priv); 11.111 + printk(" path: %s\n", p->path); 11.112 + printk(" guest_port: %d\n", p->guest_port); 11.113 + printk(" guest_address: %ld\n", p->guest_address); 11.114 + printk(" dev_present: %d\n", p->dev_present); 11.115 + printk(" dev @ %p\n", p->dev); 11.116 + printk(" ifaces: 0x%lx\n", p->ifaces); 11.117 +} 11.118 + 11.119 + 11.120 + 11.121 +static void fast_flush_area(int idx, int nr_pages) 11.122 +{ 11.123 + multicall_entry_t mcl[MMAP_PAGES_PER_REQUEST]; 11.124 + int i; 11.125 + 11.126 + for ( i = 0; i < nr_pages; i++ ) 11.127 + { 11.128 + mcl[i].op = __HYPERVISOR_update_va_mapping; 11.129 + mcl[i].args[0] = MMAP_VADDR(idx, i) >> PAGE_SHIFT; 11.130 + mcl[i].args[1] = 0; 11.131 + mcl[i].args[2] = 0; 11.132 + } 11.133 + 11.134 + mcl[nr_pages-1].args[2] = UVMF_FLUSH_TLB; 11.135 + if ( unlikely(HYPERVISOR_multicall(mcl, nr_pages) != 0) ) 11.136 + BUG(); 11.137 +} 11.138 + 11.139 + 11.140 +/****************************************************************** 11.141 + * USB INTERFACE SCHEDULER LIST MAINTENANCE 11.142 + */ 11.143 + 11.144 +static struct list_head usbio_schedule_list; 11.145 +static spinlock_t usbio_schedule_list_lock; 11.146 + 11.147 +static int __on_usbif_list(usbif_priv_t *up) 11.148 +{ 11.149 + return up->usbif_list.next != NULL; 11.150 +} 11.151 + 11.152 +void remove_from_usbif_list(usbif_priv_t *up) 11.153 +{ 11.154 + unsigned long flags; 11.155 + if ( !__on_usbif_list(up) ) return; 11.156 + spin_lock_irqsave(&usbio_schedule_list_lock, flags); 11.157 + if ( __on_usbif_list(up) ) 11.158 + { 11.159 + list_del(&up->usbif_list); 11.160 + up->usbif_list.next = NULL; 11.161 + usbif_put(up); 11.162 + } 11.163 + spin_unlock_irqrestore(&usbio_schedule_list_lock, flags); 11.164 +} 11.165 + 11.166 +static void add_to_usbif_list_tail(usbif_priv_t *up) 11.167 +{ 11.168 + unsigned long flags; 11.169 + if ( __on_usbif_list(up) ) return; 11.170 + spin_lock_irqsave(&usbio_schedule_list_lock, flags); 11.171 + if ( !__on_usbif_list(up) && (up->status == CONNECTED) ) 11.172 + { 11.173 + list_add_tail(&up->usbif_list, &usbio_schedule_list); 11.174 + usbif_get(up); 11.175 + } 11.176 + spin_unlock_irqrestore(&usbio_schedule_list_lock, flags); 11.177 +} 11.178 + 11.179 + 11.180 +/****************************************************************** 11.181 + * COMPLETION CALLBACK -- Called as urb->complete() 11.182 + */ 11.183 + 11.184 +static void maybe_trigger_usbio_schedule(void); 11.185 + 11.186 +static void __end_usb_io_op(struct urb *purb) 11.187 +{ 11.188 + unsigned long flags; 11.189 + pending_req_t *pending_req; 11.190 + int pending_idx; 11.191 + 11.192 + pending_req = purb->context; 11.193 + 11.194 +/* printk("Completed for id = %p to 0x%lx - 0x%lx\n", pending_req->id, */ 11.195 +/* virt_to_machine(purb->transfer_buffer), */ 11.196 +/* virt_to_machine(purb->transfer_buffer) */ 11.197 +/* + pending_req->nr_pages * PAGE_SIZE); */ 11.198 + 11.199 + pending_idx = pending_req - pending_reqs; 11.200 + 11.201 + ASSERT(purb->actual_length <= purb->transfer_buffer_length); 11.202 + ASSERT(purb->actual_length <= pending_req->nr_pages * PAGE_SIZE); 11.203 + 11.204 + /* An error fails the entire request. */ 11.205 + if ( purb->status ) 11.206 + { 11.207 + printk("URB @ %p failed. Status %d\n", purb, purb->status); 11.208 + } 11.209 + 11.210 + if ( usb_pipetype(purb->pipe) == 0 ) 11.211 + { 11.212 + int i; 11.213 + usbif_iso_t *sched = (usbif_iso_t *)MMAP_VADDR(pending_idx, pending_req->nr_pages - 1); 11.214 + 11.215 + ASSERT(sched == pending_req->sched); 11.216 + 11.217 + // printk("writing back schedule at %p\n", sched); 11.218 + 11.219 + /* If we're dealing with an iso pipe, we need to copy back the schedule. */ 11.220 + for ( i = 0; i < purb->number_of_packets; i++ ) 11.221 + { 11.222 + sched[i].length = purb->iso_frame_desc[i].actual_length; 11.223 + ASSERT(sched[i].buffer_offset == 11.224 + purb->iso_frame_desc[i].offset); 11.225 + sched[i].status = purb->iso_frame_desc[i].status; 11.226 + } 11.227 + } 11.228 + 11.229 + // printk("Flushing %d pages\n", pending_req->nr_pages); 11.230 + fast_flush_area(pending_req - pending_reqs, pending_req->nr_pages); 11.231 + 11.232 + kfree(purb->setup_packet); 11.233 + 11.234 + spin_lock_irqsave(&pending_req->usbif_priv->usb_ring_lock, flags); 11.235 + make_response(pending_req->usbif_priv, pending_req->id, 11.236 + pending_req->operation, pending_req->status, 0, purb->actual_length); 11.237 + spin_unlock_irqrestore(&pending_req->usbif_priv->usb_ring_lock, flags); 11.238 + usbif_put(pending_req->usbif_priv); 11.239 + 11.240 + usb_free_urb(purb); 11.241 + 11.242 + /* Free the pending request. */ 11.243 + spin_lock_irqsave(&pend_prod_lock, flags); 11.244 + pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; 11.245 + spin_unlock_irqrestore(&pend_prod_lock, flags); 11.246 + 11.247 + rmb(); 11.248 + 11.249 + /* Check for anything still waiting in the rings, having freed a request... */ 11.250 + maybe_trigger_usbio_schedule(); 11.251 +} 11.252 + 11.253 +/****************************************************************** 11.254 + * SCHEDULER FUNCTIONS 11.255 + */ 11.256 + 11.257 +static DECLARE_WAIT_QUEUE_HEAD(usbio_schedule_wait); 11.258 + 11.259 +static int usbio_schedule(void *arg) 11.260 +{ 11.261 + DECLARE_WAITQUEUE(wq, current); 11.262 + 11.263 + usbif_priv_t *up; 11.264 + struct list_head *ent; 11.265 + 11.266 + daemonize(); 11.267 + 11.268 + for ( ; ; ) 11.269 + { 11.270 + /* Wait for work to do. */ 11.271 + add_wait_queue(&usbio_schedule_wait, &wq); 11.272 + set_current_state(TASK_INTERRUPTIBLE); 11.273 + if ( (NR_PENDING_REQS == MAX_PENDING_REQS) || 11.274 + list_empty(&usbio_schedule_list) ) 11.275 + schedule(); 11.276 + __set_current_state(TASK_RUNNING); 11.277 + remove_wait_queue(&usbio_schedule_wait, &wq); 11.278 + 11.279 + /* Queue up a batch of requests. */ 11.280 + while ( (NR_PENDING_REQS < MAX_PENDING_REQS) && 11.281 + !list_empty(&usbio_schedule_list) ) 11.282 + { 11.283 + ent = usbio_schedule_list.next; 11.284 + up = list_entry(ent, usbif_priv_t, usbif_list); 11.285 + usbif_get(up); 11.286 + remove_from_usbif_list(up); 11.287 + if ( do_usb_io_op(up, BATCH_PER_DOMAIN) ) 11.288 + add_to_usbif_list_tail(up); 11.289 + usbif_put(up); 11.290 + } 11.291 + } 11.292 +} 11.293 + 11.294 +static void maybe_trigger_usbio_schedule(void) 11.295 +{ 11.296 + /* 11.297 + * Needed so that two processes, who together make the following predicate 11.298 + * true, don't both read stale values and evaluate the predicate 11.299 + * incorrectly. Incredibly unlikely to stall the scheduler on x86, but... 11.300 + */ 11.301 + smp_mb(); 11.302 + 11.303 + if ( !list_empty(&usbio_schedule_list) ) 11.304 + wake_up(&usbio_schedule_wait); 11.305 +} 11.306 + 11.307 + 11.308 +/****************************************************************************** 11.309 + * NOTIFICATION FROM GUEST OS. 11.310 + */ 11.311 + 11.312 +irqreturn_t usbif_be_int(int irq, void *dev_id, struct pt_regs *regs) 11.313 +{ 11.314 + usbif_priv_t *up = dev_id; 11.315 + 11.316 + smp_mb(); 11.317 + 11.318 + add_to_usbif_list_tail(up); 11.319 + 11.320 + /* Will in fact /always/ trigger an io schedule in this case. */ 11.321 + maybe_trigger_usbio_schedule(); 11.322 + 11.323 + return IRQ_HANDLED; 11.324 +} 11.325 + 11.326 + 11.327 + 11.328 +/****************************************************************** 11.329 + * DOWNWARD CALLS -- These interface with the usb-device layer proper. 11.330 + */ 11.331 + 11.332 +static int do_usb_io_op(usbif_priv_t *up, int max_to_do) 11.333 +{ 11.334 + usbif_t *usb_ring = up->usb_ring_base; 11.335 + usbif_request_t *req; 11.336 + USBIF_RING_IDX i, rp; 11.337 + int more_to_do = 0; 11.338 + unsigned long flags; 11.339 + 11.340 + spin_lock_irqsave(&up->usb_ring_lock, flags); 11.341 + 11.342 + rp = usb_ring->req_prod; 11.343 + rmb(); /* Ensure we see queued requests up to 'rp'. */ 11.344 + 11.345 + /* Take items off the comms ring, taking care not to overflow. */ 11.346 + for ( i = up->usb_req_cons; 11.347 + (i != rp) && ((i-up->usb_resp_prod) != USBIF_RING_SIZE); 11.348 + i++ ) 11.349 + { 11.350 + if ( (max_to_do-- == 0) || (NR_PENDING_REQS == MAX_PENDING_REQS) ) 11.351 + { 11.352 + more_to_do = 1; 11.353 + break; 11.354 + } 11.355 + 11.356 + req = &usb_ring->ring[MASK_USBIF_IDX(i)].req; 11.357 + 11.358 + switch ( req->operation ) 11.359 + { 11.360 + case USBIF_OP_PROBE: 11.361 + dispatch_usb_probe(up, req->id, req->port); 11.362 + break; 11.363 + 11.364 + case USBIF_OP_IO: 11.365 + /* Assemble an appropriate URB. */ 11.366 + dispatch_usb_io(up, req); 11.367 + break; 11.368 + 11.369 + case USBIF_OP_RESET: 11.370 + dispatch_usb_reset(up, req->port); 11.371 + break; 11.372 + 11.373 + default: 11.374 + DPRINTK("error: unknown USB io operation [%d]\n", 11.375 + req->operation); 11.376 + make_response(up, req->id, req->operation, -EINVAL, 0, 0); 11.377 + break; 11.378 + } 11.379 + } 11.380 + 11.381 + up->usb_req_cons = i; 11.382 + 11.383 + spin_unlock_irqrestore(&up->usb_ring_lock, flags); 11.384 + 11.385 + return more_to_do; 11.386 +} 11.387 + 11.388 +static owned_port_t *find_guest_port(usbif_priv_t *up, int port) 11.389 +{ 11.390 + unsigned long flags; 11.391 + struct list_head *l; 11.392 + 11.393 + spin_lock_irqsave(&owned_ports_lock, flags); 11.394 + list_for_each(l, &owned_ports) 11.395 + { 11.396 + owned_port_t *p = list_entry(l, owned_port_t, list); 11.397 + if(p->usbif_priv == up && p->guest_port == port) 11.398 + { 11.399 + spin_unlock_irqrestore(&owned_ports_lock, flags); 11.400 + return p; 11.401 + } 11.402 + } 11.403 + spin_unlock_irqrestore(&owned_ports_lock, flags); 11.404 + 11.405 + return NULL; 11.406 +} 11.407 + 11.408 +static void dispatch_usb_reset(usbif_priv_t *up, unsigned long portid) 11.409 +{ 11.410 + owned_port_t *port = find_guest_port(up, portid); 11.411 + int ret = 0; 11.412 + 11.413 + 11.414 + /* Allowing the guest to actually reset the device causes more problems 11.415 + * than it's worth. We just fake it out in software but we will do a real 11.416 + * reset when the interface is destroyed. */ 11.417 + 11.418 +#if 0 11.419 + printk("Reset port %d\n", portid); 11.420 + 11.421 + dump_port(port); 11.422 +#endif 11.423 + 11.424 + port->guest_address = 0; 11.425 + /* If there's an attached device then the port is now enabled. */ 11.426 + if ( port->dev_present ) 11.427 + port->enabled = 1; 11.428 + else 11.429 + port->enabled = 0; 11.430 + 11.431 + make_response(up, 0, USBIF_OP_RESET, ret, 0, 0); 11.432 +} 11.433 + 11.434 +static void dispatch_usb_probe(usbif_priv_t *up, unsigned long id, unsigned long portid) 11.435 +{ 11.436 + owned_port_t *port = find_guest_port(up, portid); 11.437 + int ret; 11.438 + 11.439 + if ( port != NULL ) 11.440 + ret = port->dev_present; 11.441 + else 11.442 + { 11.443 + ret = -EINVAL; 11.444 + printk("dispatch_usb_probe(): invalid port probe request (port %ld)\n", 11.445 + portid); 11.446 + } 11.447 + 11.448 + /* Probe result is sent back in-band. Probes don't have an associated id 11.449 + * right now... */ 11.450 + make_response(up, id, USBIF_OP_PROBE, ret, portid, 0); 11.451 +} 11.452 + 11.453 +owned_port_t *find_port_for_request(usbif_priv_t *up, usbif_request_t *req); 11.454 + 11.455 +static void dump_request(usbif_request_t *req) 11.456 +{ 11.457 + printk("id = 0x%lx\n", req->id); 11.458 + 11.459 + printk("devnum %d\n", req->devnum); 11.460 + printk("endpoint 0x%x\n", req->endpoint); 11.461 + printk("direction %d\n", req->direction); 11.462 + printk("speed %d\n", req->speed); 11.463 + printk("pipe_type 0x%x\n", req->pipe_type); 11.464 + printk("transfer_buffer 0x%lx\n", req->transfer_buffer); 11.465 + printk("length 0x%lx\n", req->length); 11.466 + printk("transfer_flags 0x%lx\n", req->transfer_flags); 11.467 + printk("setup = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", 11.468 + req->setup[0], req->setup[1], req->setup[2], req->setup[3], 11.469 + req->setup[4], req->setup[5], req->setup[6], req->setup[7]); 11.470 + printk("iso_schedule = 0x%lx\n", req->iso_schedule); 11.471 + printk("num_iso %ld\n", req->num_iso); 11.472 +} 11.473 + 11.474 +void dump_urb(struct urb *urb) 11.475 +{ 11.476 + printk("dumping urb @ %p\n", urb); 11.477 + 11.478 +#define DUMP_URB_FIELD(name, format) printk(" " # name " " format "\n", urb-> name) 11.479 + 11.480 + DUMP_URB_FIELD(pipe, "0x%x"); 11.481 + DUMP_URB_FIELD(status, "%d"); 11.482 + DUMP_URB_FIELD(transfer_flags, "0x%x"); 11.483 + DUMP_URB_FIELD(transfer_buffer, "%p"); 11.484 + DUMP_URB_FIELD(transfer_buffer_length, "%d"); 11.485 + DUMP_URB_FIELD(actual_length, "%d"); 11.486 +} 11.487 + 11.488 + 11.489 +static void dispatch_usb_io(usbif_priv_t *up, usbif_request_t *req) 11.490 +{ 11.491 + unsigned long buffer_mach; 11.492 + int i = 0, offset = 0, 11.493 + pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)]; 11.494 + pending_req_t *pending_req; 11.495 + unsigned long remap_prot; 11.496 + multicall_entry_t mcl[MMAP_PAGES_PER_REQUEST]; 11.497 + struct urb *purb = NULL; 11.498 + owned_port_t *port; 11.499 + unsigned char *setup; 11.500 + 11.501 +// dump_request(req); 11.502 + 11.503 + if ( NR_PENDING_REQS == MAX_PENDING_REQS ) 11.504 + { 11.505 + printk("usbback: Max requests already queued. Now giving up!\n"); 11.506 + 11.507 + return; 11.508 + } 11.509 + 11.510 + port = find_port_for_request(up, req); 11.511 + 11.512 + if(port == NULL) 11.513 + { 11.514 + printk("No such device! (%d)\n", req->devnum); 11.515 + dump_request(req); 11.516 + 11.517 + make_response(up, req->id, req->operation, -ENODEV, 0, 0); 11.518 + return; 11.519 + } 11.520 + 11.521 + setup = kmalloc(8, GFP_ATOMIC | GFP_NOIO); 11.522 + 11.523 + if ( setup == NULL ) 11.524 + goto no_mem; 11.525 + 11.526 + /* Copy request out for safety. */ 11.527 + memcpy(setup, req->setup, 8); 11.528 + 11.529 + if( setup[0] == 0x0 && setup[1] == 0x5) 11.530 + { 11.531 + /* To virtualise the USB address space, we need to intercept 11.532 + * set_address messages and emulate. From the USB specification: 11.533 + * bmRequestType = 0x0; 11.534 + * Brequest = SET_ADDRESS (i.e. 0x5) 11.535 + * wValue = device address 11.536 + * wIndex = 0 11.537 + * wLength = 0 11.538 + * data = None 11.539 + */ 11.540 + /* Store into the guest transfer buffer using cpu_to_le16 */ 11.541 + port->guest_address = le16_to_cpu(*(u16 *)(setup + 2)); 11.542 + /* Make a successful response. That was easy! */ 11.543 + 11.544 + make_response(up, req->id, req->operation, 0, 0, 0); 11.545 + 11.546 + kfree(setup); 11.547 + return; 11.548 + } 11.549 + else if ( setup[0] == 0x0 && setup[1] == 0x9 ) 11.550 + { 11.551 + /* The host kernel needs to know what device configuration is in use 11.552 + * because various error checks get confused otherwise. We just do 11.553 + * configuration settings here, under controlled conditions. 11.554 + */ 11.555 + usb_set_configuration(port->dev, setup[2]); 11.556 + 11.557 + make_response(up, req->id, req->operation, 0, 0, 0); 11.558 + 11.559 + kfree(setup); 11.560 + return; 11.561 + } 11.562 + 11.563 + else if ( setup[0] == 0x1 && setup[1] == 0xB ) 11.564 + { 11.565 + /* The host kernel needs to know what device interface is in use 11.566 + * because various error checks get confused otherwise. We just do 11.567 + * configuration settings here, under controlled conditions. 11.568 + */ 11.569 + usb_set_interface(port->dev, (setup[4] | setup[5] << 8), 11.570 + (setup[2] | setup[3] << 8) ); 11.571 + 11.572 + make_response(up, req->id, req->operation, 0, 0, 0); 11.573 + 11.574 + kfree(setup); 11.575 + return; 11.576 + } 11.577 + 11.578 + if ( ( req->transfer_buffer - (req->transfer_buffer & PAGE_MASK) 11.579 + + req->length ) 11.580 + > MMAP_PAGES_PER_REQUEST * PAGE_SIZE ) 11.581 + { 11.582 + printk("usbback: request of %d bytes too large, failing it\n", req->length); 11.583 + make_response(up, req->id, req->operation, -EINVAL, 0, 0); 11.584 + kfree(setup); 11.585 + return; 11.586 + } 11.587 + 11.588 + buffer_mach = req->transfer_buffer; 11.589 + 11.590 + if( buffer_mach == 0 ) 11.591 + goto no_remap; 11.592 + 11.593 + ASSERT((req->length >> PAGE_SHIFT) <= MMAP_PAGES_PER_REQUEST); 11.594 + ASSERT(buffer_mach); 11.595 + 11.596 + /* Always map writeable for now. */ 11.597 + remap_prot = _PAGE_PRESENT|_PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_RW; 11.598 + 11.599 + for ( i = 0, offset = 0; offset < req->length; 11.600 + i++, offset += PAGE_SIZE ) 11.601 + { 11.602 + // printk("length = %d, offset = %d, looping!\n", req->length, offset); 11.603 + 11.604 + mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain; 11.605 + mcl[i].args[0] = MMAP_VADDR(pending_idx, i) >> PAGE_SHIFT; 11.606 + mcl[i].args[1] = ((buffer_mach & PAGE_MASK) + offset) | remap_prot; 11.607 + mcl[i].args[2] = 0; 11.608 + mcl[i].args[3] = up->domid; 11.609 + 11.610 + phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] = 11.611 + FOREIGN_FRAME((buffer_mach + offset) >> PAGE_SHIFT); 11.612 + // printk("i = %d\n", i); 11.613 + 11.614 + ASSERT(virt_to_machine(MMAP_VADDR(pending_idx, i)) 11.615 + == buffer_mach + i << PAGE_SHIFT); 11.616 + } 11.617 + 11.618 + if ( req->pipe_type == 0 && req->num_iso > 0 ) /* Maybe schedule ISO... */ 11.619 + { 11.620 + // printk("for iso, i = %d\n", i); 11.621 + /* Map in ISO schedule, if necessary. */ 11.622 + mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain; 11.623 + mcl[i].args[0] = MMAP_VADDR(pending_idx, i) >> PAGE_SHIFT; 11.624 + mcl[i].args[1] = (req->iso_schedule & PAGE_MASK) | remap_prot; 11.625 + mcl[i].args[2] = 0; 11.626 + mcl[i].args[3] = up->domid; 11.627 + 11.628 + phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] = 11.629 + FOREIGN_FRAME(req->iso_schedule >> PAGE_SHIFT); 11.630 + 11.631 + // printk("Mapped iso at %p\n", MMAP_VADDR(pending_idx, i)); 11.632 + i++; 11.633 + } 11.634 + 11.635 + // printk("Well we got this far!\n"); 11.636 + 11.637 + if ( unlikely(HYPERVISOR_multicall(mcl, i) != 0) ) 11.638 + BUG(); 11.639 + 11.640 + { 11.641 + int j; 11.642 + for ( j = 0; j < i; j++ ) 11.643 + { 11.644 + if ( unlikely(mcl[j].args[5] != 0) ) 11.645 + { 11.646 + printk("invalid buffer %d -- could not remap it\n", j); 11.647 + fast_flush_area(pending_idx, i); 11.648 + printk("sending invalid descriptor\n"); 11.649 + goto bad_descriptor; 11.650 + } 11.651 + } 11.652 + } 11.653 + 11.654 + no_remap: 11.655 + 11.656 + ASSERT(i <= MMAP_PAGES_PER_REQUEST); 11.657 + ASSERT(i * PAGE_SIZE >= req->length); 11.658 + 11.659 + /* We have to do this because some things might complete out of order. */ 11.660 + pending_req = &pending_reqs[pending_idx]; 11.661 + pending_req->usbif_priv= up; 11.662 + pending_req->id = req->id; 11.663 + pending_req->operation = req->operation; 11.664 + pending_req->nr_pages = i; 11.665 + 11.666 + 11.667 + 11.668 + pending_cons++; 11.669 + 11.670 + usbif_get(up); 11.671 + 11.672 + /* Fill out an actual request for the USB layer. */ 11.673 + purb = usb_alloc_urb(req->num_iso); 11.674 + 11.675 + if ( purb == NULL ) 11.676 + goto no_mem; 11.677 + 11.678 + purb->dev = port->dev; 11.679 + purb->context = pending_req; 11.680 + purb->transfer_buffer = (void *)MMAP_VADDR(pending_idx, 0) + (buffer_mach & ~PAGE_MASK); 11.681 + if(buffer_mach == 0) 11.682 + purb->transfer_buffer = NULL; 11.683 + purb->complete = __end_usb_io_op; 11.684 + purb->transfer_buffer_length = req->length; 11.685 + purb->transfer_flags = req->transfer_flags; 11.686 + 11.687 +/* if ( req->transfer_flags != 0 ) */ 11.688 +/* dump_request(req); */ 11.689 + 11.690 + purb->pipe = 0; 11.691 + purb->pipe |= req->direction << 7; 11.692 + purb->pipe |= port->dev->devnum << 8; 11.693 + purb->pipe |= req->speed << 26; 11.694 + purb->pipe |= req->pipe_type << 30; 11.695 + purb->pipe |= req->endpoint << 15; 11.696 + 11.697 + purb->number_of_packets = req->num_iso; 11.698 + 11.699 + /* Make sure there's always some kind of timeout. */ 11.700 + purb->timeout = ( req->timeout > 0 ) ? (req->timeout * HZ) / 1000 11.701 + : 1000; 11.702 + 11.703 + purb->setup_packet = setup; 11.704 + 11.705 + if ( req->pipe_type == 0 ) /* ISO */ 11.706 + { 11.707 + int j; 11.708 + usbif_iso_t *iso_sched = (usbif_iso_t *)MMAP_VADDR(pending_idx, i - 1); 11.709 + 11.710 + // printk("Reading iso sched at %p\n", iso_sched); 11.711 + 11.712 + /* If we're dealing with an iso pipe, we need to copy in a schedule. */ 11.713 + for ( j = 0; j < req->num_iso; j++ ) 11.714 + { 11.715 + purb->iso_frame_desc[j].length = iso_sched[j].length; 11.716 + purb->iso_frame_desc[j].offset = iso_sched[j].buffer_offset; 11.717 + iso_sched[j].status = 0; 11.718 + } 11.719 + pending_req->iso_sched = iso_sched; 11.720 + } 11.721 + 11.722 + { 11.723 + int ret; 11.724 + ret = usb_submit_urb(purb); 11.725 + 11.726 + // dump_urb(purb); 11.727 + 11.728 + if ( ret != 0 ) 11.729 + goto bad_descriptor; /* XXX free pending here! */ 11.730 + } 11.731 + 11.732 + return; 11.733 + 11.734 + bad_descriptor: 11.735 + kfree ( setup ); 11.736 + if ( purb != NULL ) 11.737 + usb_free_urb(purb); 11.738 + make_response(up, req->id, req->operation, -EINVAL, 0, 0); 11.739 + return; 11.740 + 11.741 + no_mem: 11.742 + if ( setup != NULL ) 11.743 + kfree(setup); 11.744 + make_response(up, req->id, req->operation, -ENOMEM, 0, 0); 11.745 + return; 11.746 +} 11.747 + 11.748 + 11.749 + 11.750 +/****************************************************************** 11.751 + * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING 11.752 + */ 11.753 + 11.754 + 11.755 +static void make_response(usbif_priv_t *up, unsigned long id, 11.756 + unsigned short op, int st, int inband, 11.757 + unsigned long length) 11.758 +{ 11.759 + usbif_response_t *resp; 11.760 + unsigned long flags; 11.761 + 11.762 +#if 0 11.763 + printk("usbback: Sending response:\n"); 11.764 + printk(" id = 0x%x\n", id); 11.765 + printk(" op = %d\n", op); 11.766 + printk(" status = %d\n", st); 11.767 + printk(" data = %d\n", inband); 11.768 + printk(" length = %d\n", length); 11.769 +#endif 11.770 + 11.771 + /* Place on the response ring for the relevant domain. */ 11.772 + spin_lock_irqsave(&up->usb_ring_lock, flags); 11.773 + resp = &up->usb_ring_base-> 11.774 + ring[MASK_USBIF_IDX(up->usb_resp_prod)].resp; 11.775 + resp->id = id; 11.776 + resp->operation = op; 11.777 + resp->status = st; 11.778 + resp->data = inband; 11.779 + resp->length = length; 11.780 + wmb(); /* Ensure other side can see the response fields. */ 11.781 + up->usb_ring_base->resp_prod = ++up->usb_resp_prod; 11.782 + spin_unlock_irqrestore(&up->usb_ring_lock, flags); 11.783 + 11.784 + /* Kick the relevant domain. */ 11.785 + notify_via_evtchn(up->evtchn); 11.786 +} 11.787 + 11.788 +/** 11.789 + * usbif_claim_port - claim devices on a port on behalf of guest 11.790 + * 11.791 + * Once completed, this will ensure that any device attached to that 11.792 + * port is claimed by this driver for use by the guest. 11.793 + */ 11.794 +int usbif_claim_port(usbif_be_claim_port_t *msg) 11.795 +{ 11.796 + owned_port_t *o_p; 11.797 + 11.798 + /* Sanity... */ 11.799 + if ( usbif_find_port(msg->path) != NULL ) 11.800 + { 11.801 + printk("usbback: Attempted to claim USB port " 11.802 + "we already own!\n"); 11.803 + return -EINVAL; 11.804 + } 11.805 + 11.806 + spin_lock_irq(&owned_ports_lock); 11.807 + 11.808 + /* No need for a slab cache - this should be infrequent. */ 11.809 + o_p = kmalloc(sizeof(owned_port_t), GFP_KERNEL); 11.810 + 11.811 + o_p->enabled = 0; 11.812 + o_p->usbif_priv = usbif_find(msg->domid); 11.813 + o_p->guest_port = msg->usbif_port; 11.814 + o_p->dev_present = 0; 11.815 + o_p->guest_address = 0; /* Default address. */ 11.816 + 11.817 + strcpy(o_p->path, msg->path); 11.818 + 11.819 + list_add(&o_p->list, &owned_ports); 11.820 + 11.821 + printk("usbback: Claimed USB port (%s) for %d.%d\n", o_p->path, 11.822 + msg->domid, msg->usbif_port); 11.823 + 11.824 + spin_unlock_irq(&owned_ports_lock); 11.825 + 11.826 + /* Force a reprobe for unclaimed devices. */ 11.827 + usb_scan_devices(); 11.828 + 11.829 + return 0; 11.830 +} 11.831 + 11.832 +owned_port_t *find_port_for_request(usbif_priv_t *up, usbif_request_t *req) 11.833 +{ 11.834 + unsigned long flags; 11.835 + struct list_head *port; 11.836 + 11.837 + /* I'm assuming this is not called from IRQ context - correct? I think 11.838 + * it's probably only called in response to control messages or plug events 11.839 + * in the USB hub kernel thread, so should be OK. */ 11.840 + spin_lock_irqsave(&owned_ports_lock, flags); 11.841 + list_for_each(port, &owned_ports) 11.842 + { 11.843 + owned_port_t *p = list_entry(port, owned_port_t, list); 11.844 + if(p->usbif_priv == up && p->guest_address == req->devnum && p->enabled ) 11.845 + { 11.846 +#if 0 11.847 + printk("Found port for devnum %d\n", req->devnum); 11.848 + 11.849 + dump_port(p); 11.850 +#endif 11.851 + return p; 11.852 + } 11.853 + } 11.854 + spin_unlock_irqrestore(&owned_ports_lock, flags); 11.855 + 11.856 + return NULL; 11.857 +} 11.858 + 11.859 +owned_port_t *usbif_find_port(char *path) 11.860 +{ 11.861 + struct list_head *port; 11.862 + unsigned long flags; 11.863 + 11.864 + spin_lock_irqsave(&owned_ports_lock, flags); 11.865 + list_for_each(port, &owned_ports) 11.866 + { 11.867 + owned_port_t *p = list_entry(port, owned_port_t, list); 11.868 + if(!strcmp(path, p->path)) 11.869 + { 11.870 + spin_unlock_irqrestore(&owned_ports_lock, flags); 11.871 + return p; 11.872 + } 11.873 + } 11.874 + spin_unlock_irqrestore(&owned_ports_lock, flags); 11.875 + 11.876 + return NULL; 11.877 +} 11.878 + 11.879 + 11.880 +static void *probe(struct usb_device *dev, unsigned iface, 11.881 + const struct usb_device_id *id) 11.882 +{ 11.883 + owned_port_t *p; 11.884 + 11.885 + /* We don't care what the device is - if we own the port, we want it. We 11.886 + * don't deal with device-specifics in this driver, so we don't care what 11.887 + * the device actually is ;-) */ 11.888 + if ( ( p = usbif_find_port(dev->devpath) ) != NULL ) 11.889 + { 11.890 + printk("usbback: claimed device attached to owned port\n"); 11.891 + 11.892 + p->dev_present = 1; 11.893 + p->dev = dev; 11.894 + set_bit(iface, &p->ifaces); 11.895 + 11.896 + return p->usbif_priv; 11.897 + } 11.898 + else 11.899 + printk("usbback: hotplug for non-owned port (%s), ignoring\n", dev->devpath); 11.900 + 11.901 + 11.902 + return NULL; 11.903 +} 11.904 + 11.905 +static void disconnect(struct usb_device *dev, void *usbif) 11.906 +{ 11.907 + /* Note the device is removed so we can tell the guest when it probes. */ 11.908 + owned_port_t *port = usbif_find_port(dev->devpath); 11.909 + port->dev_present = 0; 11.910 + port->dev = NULL; 11.911 + port->ifaces = 0; 11.912 +} 11.913 + 11.914 + 11.915 +struct usb_driver driver = 11.916 +{ 11.917 + .owner = THIS_MODULE, 11.918 + .name = "Xen USB Backend", 11.919 + .probe = probe, 11.920 + .disconnect = disconnect, 11.921 + .id_table = NULL, 11.922 +}; 11.923 + 11.924 +/* __usbif_release_port - internal mechanics for releasing a port */ 11.925 +void __usbif_release_port(owned_port_t *p) 11.926 +{ 11.927 + int i; 11.928 + 11.929 + for ( i = 0; p->ifaces != 0; i++) 11.930 + if ( p->ifaces & 1 << i ) 11.931 + { 11.932 + usb_driver_release_interface(&driver, usb_ifnum_to_if(p->dev, i)); 11.933 + clear_bit(i, &p->ifaces); 11.934 + } 11.935 + list_del(&p->list); 11.936 + 11.937 + /* Reset the real device. We don't simulate disconnect / probe for other 11.938 + * drivers in this kernel because we assume the device is completely under 11.939 + * the control of ourselves (i.e. the guest!). This should ensure that the 11.940 + * device is in a sane state for the next customer ;-) */ 11.941 +/* if ( p->dev != NULL) */ 11.942 +/* usb_reset_device(p->dev); */ 11.943 + 11.944 + kfree(p); 11.945 +} 11.946 + 11.947 + 11.948 +/** 11.949 + * usbif_release_port - stop claiming devices on a port on behalf of guest 11.950 + */ 11.951 +void usbif_release_port(usbif_be_release_port_t *msg) 11.952 +{ 11.953 + owned_port_t *p; 11.954 + 11.955 + spin_lock_irq(&owned_ports_lock); 11.956 + p = usbif_find_port(msg->path); 11.957 + __usbif_release_port(p); 11.958 + spin_unlock_irq(&owned_ports_lock); 11.959 +} 11.960 + 11.961 +void usbif_release_ports(usbif_priv_t *up) 11.962 +{ 11.963 + struct list_head *port, *tmp; 11.964 + unsigned long flags; 11.965 + 11.966 + spin_lock_irqsave(&owned_ports_lock, flags); 11.967 + list_for_each_safe(port, tmp, &owned_ports) 11.968 + { 11.969 + owned_port_t *p = list_entry(port, owned_port_t, list); 11.970 + if ( p->usbif_priv == up ) 11.971 + __usbif_release_port(p); 11.972 + } 11.973 + spin_unlock_irqrestore(&owned_ports_lock, flags); 11.974 +} 11.975 + 11.976 +static int __init usbif_init(void) 11.977 +{ 11.978 + int i; 11.979 + 11.980 + if ( !(xen_start_info.flags & SIF_INITDOMAIN) && 11.981 + !(xen_start_info.flags & SIF_USB_BE_DOMAIN) ) 11.982 + return 0; 11.983 + 11.984 + INIT_LIST_HEAD(&owned_ports); 11.985 + 11.986 + usb_register(&driver); 11.987 + 11.988 + usbif_interface_init(); 11.989 + 11.990 + if ( (mmap_vstart = allocate_empty_lowmem_region(MMAP_PAGES)) == 0 ) 11.991 + BUG(); 11.992 + 11.993 + pending_cons = 0; 11.994 + pending_prod = MAX_PENDING_REQS; 11.995 + memset(pending_reqs, 0, sizeof(pending_reqs)); 11.996 + for ( i = 0; i < MAX_PENDING_REQS; i++ ) 11.997 + pending_ring[i] = i; 11.998 + 11.999 + spin_lock_init(&usbio_schedule_list_lock); 11.1000 + INIT_LIST_HEAD(&usbio_schedule_list); 11.1001 + 11.1002 + if ( kernel_thread(usbio_schedule, 0, CLONE_FS | CLONE_FILES) < 0 ) 11.1003 + BUG(); 11.1004 + 11.1005 + usbif_ctrlif_init(); 11.1006 + 11.1007 + spin_lock_init(&owned_ports_lock); 11.1008 + 11.1009 + printk("Xen USB Backend Initialised"); 11.1010 + 11.1011 + return 0; 11.1012 +} 11.1013 + 11.1014 +__initcall(usbif_init);
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile Wed Jan 19 13:20:15 2005 +0000 12.3 @@ -0,0 +1,3 @@ 12.4 +O_TARGET := drv.o 12.5 +obj-y := main.o 12.6 +include $(TOPDIR)/Rules.make
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/main.c Wed Jan 19 13:20:15 2005 +0000 13.3 @@ -0,0 +1,1720 @@ 13.4 +/* 13.5 + * Xen Virtual USB Frontend Driver 13.6 + * 13.7 + * This file contains the first version of the Xen virtual USB hub 13.8 + * that I've managed not to delete by mistake (3rd time lucky!). 13.9 + * 13.10 + * Based on Linux's uhci.c, original copyright notices are displayed 13.11 + * below. Portions also (c) 2004 Intel Research Cambridge 13.12 + * and (c) 2004 Mark Williamson 13.13 + * 13.14 + * Contact <mark.williamson@cl.cam.ac.uk> or 13.15 + * <xen-devel@lists.sourceforge.net> regarding this code. 13.16 + * 13.17 + * Still to be (maybe) implemented: 13.18 + * - multiple port 13.19 + * - multiple interfaces 13.20 + * - migration / backend restart support? 13.21 + * - unloading support 13.22 + * 13.23 + * Differences to a normal host controller: 13.24 + * - the backend does most of the mucky stuff so we don't have to do various 13.25 + * things that are necessary for a normal host controller (e.g. FSBR). 13.26 + * - we don't have any hardware, so status registers are simulated in software. 13.27 + */ 13.28 + 13.29 +/* 13.30 + * Universal Host Controller Interface driver for USB. 13.31 + * 13.32 + * Maintainer: Johannes Erdfelt <johannes@erdfelt.com> 13.33 + * 13.34 + * (C) Copyright 1999 Linus Torvalds 13.35 + * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com 13.36 + * (C) Copyright 1999 Randy Dunlap 13.37 + * (C) Copyright 1999 Georg Acher, acher@in.tum.de 13.38 + * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de 13.39 + * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch 13.40 + * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at 13.41 + * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface 13.42 + * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). 13.43 + * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) 13.44 + * 13.45 + * Intel documents this fairly well, and as far as I know there 13.46 + * are no royalties or anything like that, but even so there are 13.47 + * people who decided that they want to do the same thing in a 13.48 + * completely different way. 13.49 + * 13.50 + * WARNING! The USB documentation is downright evil. Most of it 13.51 + * is just crap, written by a committee. You're better off ignoring 13.52 + * most of it, the important stuff is: 13.53 + * - the low-level protocol (fairly simple but lots of small details) 13.54 + * - working around the horridness of the rest 13.55 + */ 13.56 + 13.57 +#include <linux/config.h> 13.58 +#include <linux/module.h> 13.59 +#include <linux/kernel.h> 13.60 +#include <linux/init.h> 13.61 +#include <linux/delay.h> 13.62 +#include <linux/ioport.h> 13.63 +#include <linux/sched.h> 13.64 +#include <linux/slab.h> 13.65 +#include <linux/smp_lock.h> 13.66 +#include <linux/errno.h> 13.67 +#include <linux/unistd.h> 13.68 +#include <linux/interrupt.h> 13.69 +#include <linux/spinlock.h> 13.70 +#ifdef CONFIG_USB_DEBUG 13.71 +#define DEBUG 13.72 +#else 13.73 +#undef DEBUG 13.74 +#endif 13.75 +#include <linux/usb.h> 13.76 + 13.77 +#include <asm/uaccess.h> 13.78 +#include <asm/irq.h> 13.79 +#include <asm/system.h> 13.80 + 13.81 +#include "xhci.h" 13.82 + 13.83 +#include <linux/pm.h> 13.84 + 13.85 +#include "../../../../../drivers/usb/hcd.h" 13.86 + 13.87 +#include "../usbif.h" 13.88 +#include <asm/ctrl_if.h> 13.89 +#include <asm/xen-public/io/domain_controller.h> 13.90 + 13.91 +/* 13.92 + * Version Information 13.93 + */ 13.94 +#define DRIVER_VERSION "v1.0" 13.95 +#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, Mark Williamson" 13.96 +#define DRIVER_DESC "Xen Virtual USB Host Controller Interface driver" 13.97 + 13.98 +/* 13.99 + * debug = 0, no debugging messages 13.100 + * debug = 1, dump failed URB's except for stalls 13.101 + * debug = 2, dump all failed URB's (including stalls) 13.102 + */ 13.103 +#ifdef DEBUG 13.104 +static int debug = 1; 13.105 +#else 13.106 +static int debug = 0; 13.107 +#endif 13.108 +MODULE_PARM(debug, "i"); 13.109 +MODULE_PARM_DESC(debug, "Debug level"); 13.110 +static char *errbuf; 13.111 +#define ERRBUF_LEN (PAGE_SIZE * 8) 13.112 + 13.113 +static kmem_cache_t *xhci_up_cachep; /* urb_priv */ 13.114 + 13.115 +static int rh_submit_urb(struct urb *urb); 13.116 +static int rh_unlink_urb(struct urb *urb); 13.117 +//static int xhci_get_current_frame_number(struct usb_device *dev); 13.118 +static int xhci_unlink_urb(struct urb *urb); 13.119 +static void xhci_unlink_generic(struct urb *urb); 13.120 +static void xhci_call_completion(struct urb *urb); 13.121 +static void xhci_drain_ring(void); 13.122 + 13.123 +#define MAX_URB_LOOP 2048 /* Maximum number of linked URB's */ 13.124 + 13.125 +struct xhci *xhci; 13.126 + 13.127 +enum { USBIF_STATE_CONNECTED = 2, 13.128 + USBIF_STATE_DISCONNECTED = 1, 13.129 + USBIF_STATE_CLOSED =0 13.130 +}; 13.131 + 13.132 +static int awaiting_reset = 0; 13.133 + 13.134 +/** 13.135 + * xhci_construct_isoc - add isochronous information to a request 13.136 + */ 13.137 +int xhci_construct_isoc(usbif_request_t *req, struct urb *urb) 13.138 +{ 13.139 + usbif_iso_t *schedule; 13.140 + int i; 13.141 + struct urb_priv *urb_priv = urb->hcpriv; 13.142 + 13.143 + req->num_iso = urb->number_of_packets; 13.144 + schedule = (usbif_iso_t *)__get_free_page(GFP_KERNEL); 13.145 + 13.146 + if ( schedule == NULL ) 13.147 + return -ENOMEM; 13.148 + 13.149 + for ( i = 0; i < req->num_iso; i++ ) 13.150 + { 13.151 + schedule[i].buffer_offset = urb->iso_frame_desc[i].offset; 13.152 + schedule[i].length = urb->iso_frame_desc[i].length; 13.153 + } 13.154 + 13.155 + urb_priv->schedule = schedule; 13.156 + req->iso_schedule = virt_to_machine(schedule); 13.157 + 13.158 + return 0; 13.159 +} 13.160 + 13.161 +#define USBIF_RING_FULL ((xhci->usbif->req_prod - xhci->usb_resp_cons) == USBIF_RING_SIZE) 13.162 + 13.163 +static void dump_urb(struct urb *urb) 13.164 +{ 13.165 + printk("dumping urb @ %p\n", urb); 13.166 + 13.167 + printk("hcpriv = %p\n", urb->hcpriv); 13.168 + printk("next = %p\n", urb->next); 13.169 + printk("dev = %p\n", urb->dev); 13.170 + printk("pipe = 0x%lx\n", urb->pipe); 13.171 + printk("status = %d\n", urb->status); 13.172 + printk("transfer_flags = 0x%lx\n", urb->transfer_flags); 13.173 + printk("transfer_buffer = %p\n", urb->transfer_buffer); 13.174 + printk("transfer_buffer_length = %d\n", urb->transfer_buffer_length); 13.175 + printk("actual_length = %d\n", urb->actual_length); 13.176 + printk("bandwidth = %d\n", urb->bandwidth); 13.177 + printk("setup_packet = %p\n", urb->setup_packet); 13.178 + if ( urb->setup_packet != NULL ) 13.179 + printk("setup = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", 13.180 + urb->setup_packet[0], urb->setup_packet[1], urb->setup_packet[2], urb->setup_packet[3], 13.181 + urb->setup_packet[4], urb->setup_packet[5], urb->setup_packet[6], urb->setup_packet[7]); 13.182 + printk("complete = %p\n", urb->complete); 13.183 + printk("interval = %d\n", urb->interval); 13.184 + 13.185 +} 13.186 + 13.187 + 13.188 +static int 13.189 +xhci_queue_req(struct urb *urb) 13.190 +{ 13.191 + usbif_request_t *req; 13.192 + usbif_t *usbif = xhci->usbif; 13.193 + 13.194 +#if 0 13.195 + printk("usbif = %p, req_prod = %d (@ 0x%lx), resp_prod = %d, resp_cons = %d\n", 13.196 + usbif, usbif->req_prod, virt_to_machine(&usbif->req_prod), 13.197 + usbif->resp_prod, xhci->usb_resp_cons); 13.198 +#endif 13.199 + 13.200 + 13.201 +/* printk("Usbif_priv %p, want IO at 0x%lx\n", urb->hcpriv, virt_to_machine(urb->transfer_buffer)); */ 13.202 + 13.203 + if ( USBIF_RING_FULL ) 13.204 + { 13.205 + printk("xhci_queue_req(): USB ring full, not queuing request\n"); 13.206 + return -ENOBUFS; 13.207 + } 13.208 + 13.209 + /* Stick something in the shared communications ring. */ 13.210 + req = &usbif->ring[MASK_USBIF_IDX(usbif->req_prod)].req; 13.211 + 13.212 + req->operation = USBIF_OP_IO; 13.213 + req->port = 0; /* We don't care what the port is. */ 13.214 + req->id = (unsigned long) urb->hcpriv; 13.215 + req->transfer_buffer = virt_to_machine(urb->transfer_buffer); 13.216 + req->devnum = usb_pipedevice(urb->pipe); 13.217 + req->direction = usb_pipein(urb->pipe); 13.218 + req->speed = usb_pipeslow(urb->pipe); 13.219 + req->pipe_type = usb_pipetype(urb->pipe); 13.220 + req->length = urb->transfer_buffer_length; 13.221 + req->transfer_flags = urb->transfer_flags; 13.222 + req->endpoint = usb_pipeendpoint(urb->pipe); 13.223 + req->speed = usb_pipeslow(urb->pipe); 13.224 + req->timeout = urb->timeout * (1000 / HZ); 13.225 + 13.226 + if ( usb_pipetype(urb->pipe) == 0 ) /* ISO */ 13.227 + { 13.228 + int ret = xhci_construct_isoc(req, urb); 13.229 + if ( ret != 0 ) 13.230 + return ret; 13.231 + } 13.232 + 13.233 + if(urb->setup_packet != NULL) 13.234 + memcpy(req->setup, urb->setup_packet, 8); 13.235 + else 13.236 + memset(req->setup, 0, 8); 13.237 + 13.238 + wmb(); 13.239 + 13.240 + usbif->req_prod++; 13.241 + 13.242 + notify_via_evtchn(xhci->evtchn); 13.243 + 13.244 + // dump_urb(urb); 13.245 + 13.246 + return -EINPROGRESS; 13.247 +} 13.248 + 13.249 +static inline usbif_request_t * 13.250 +xhci_queue_probe(usbif_vdev_t port) 13.251 +{ 13.252 + usbif_request_t *req; 13.253 + usbif_t *usbif = xhci->usbif; 13.254 + 13.255 +#if 0 13.256 + printk("queuing probe: req_prod = %d (@ 0x%lx), resp_prod = %d, resp_cons = %d\n", 13.257 + usbif->req_prod, virt_to_machine(&usbif->req_prod), 13.258 + usbif->resp_prod, xhci->usb_resp_cons); 13.259 +#endif 13.260 + 13.261 + if ( USBIF_RING_FULL ) 13.262 + { 13.263 + printk("xhci_queue_probe(): USB ring full, not queuing request\n"); 13.264 + return NULL; 13.265 + } 13.266 + 13.267 + /* Stick something in the shared communications ring. */ 13.268 + req = &usbif->ring[MASK_USBIF_IDX(usbif->req_prod)].req; 13.269 + 13.270 + req->operation = USBIF_OP_PROBE; 13.271 + req->port = port; 13.272 + req->id = 0; 13.273 + req->transfer_buffer = 0; 13.274 + req->devnum = 0; 13.275 + req->direction = 0; 13.276 + req->speed = 0; 13.277 + req->pipe_type = 0; 13.278 + req->length = 0; 13.279 + req->transfer_flags = 0; 13.280 + req->endpoint = 0; 13.281 + req->speed = 0; 13.282 + 13.283 + wmb(); 13.284 + 13.285 + usbif->req_prod++; 13.286 + 13.287 + notify_via_evtchn(xhci->evtchn); 13.288 + 13.289 + return req; 13.290 +} 13.291 + 13.292 +static int 13.293 +xhci_port_reset(usbif_vdev_t port) 13.294 +{ 13.295 + usbif_request_t *req; 13.296 + usbif_t *usbif = xhci->usbif; 13.297 + 13.298 + /* We only reset one port at a time, so we only need one variable per 13.299 + * hub. */ 13.300 + awaiting_reset = 1; 13.301 + 13.302 + /* Stick something in the shared communications ring. */ 13.303 + req = &usbif->ring[MASK_USBIF_IDX(usbif->req_prod)].req; 13.304 + 13.305 + req->operation = USBIF_OP_RESET; 13.306 + req->port = port; 13.307 + 13.308 + wmb(); 13.309 + 13.310 + usbif->req_prod++; 13.311 + 13.312 + notify_via_evtchn(xhci->evtchn); 13.313 + 13.314 + while ( awaiting_reset > 0 ) 13.315 + { 13.316 + mdelay(1); 13.317 + xhci_drain_ring(); 13.318 + } 13.319 + 13.320 + return awaiting_reset; 13.321 +} 13.322 + 13.323 +static void xhci_show_resp(usbif_response_t *r) 13.324 +{ 13.325 + printk("id=0x%lx, op=0x%x, data=0x%x, status=0x%x, length=0x%lx\n", 13.326 + r->id, r->operation, r->data, r->status, r->length); 13.327 +} 13.328 + 13.329 + 13.330 +/* 13.331 + * Only the USB core should call xhci_alloc_dev and xhci_free_dev 13.332 + */ 13.333 +static int xhci_alloc_dev(struct usb_device *dev) 13.334 +{ 13.335 + return 0; 13.336 +} 13.337 + 13.338 +static int xhci_free_dev(struct usb_device *dev) 13.339 +{ 13.340 + return 0; 13.341 +} 13.342 + 13.343 +static inline void xhci_add_complete(struct urb *urb) 13.344 +{ 13.345 + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; 13.346 + unsigned long flags; 13.347 + 13.348 + spin_lock_irqsave(&xhci->complete_list_lock, flags); 13.349 + list_add_tail(&urbp->complete_list, &xhci->complete_list); 13.350 + spin_unlock_irqrestore(&xhci->complete_list_lock, flags); 13.351 +} 13.352 + 13.353 +/* When this returns, the owner of the URB may free its 13.354 + * storage. 13.355 + * 13.356 + * We spin and wait for the URB to complete before returning. 13.357 + */ 13.358 +static void xhci_delete_urb(struct urb *urb) 13.359 +{ 13.360 + struct urb_priv *urbp; 13.361 + 13.362 + urbp = urb->hcpriv; 13.363 + 13.364 + /* If there's no urb_priv structure for this URB then it can't have 13.365 + * been submitted at all. */ 13.366 + if ( urbp == NULL ) 13.367 + return; 13.368 + 13.369 + /* For now we just spin until the URB completes. It shouldn't take too 13.370 + * long and we don't expect to have to do this very often. */ 13.371 + while ( urb->status == -EINPROGRESS ) 13.372 + { 13.373 + xhci_drain_ring(); 13.374 + mdelay(1); 13.375 + } 13.376 + 13.377 + /* Now we know that further transfers to the buffer won't 13.378 + * occur, so we can safely return. */ 13.379 +} 13.380 + 13.381 +static struct urb_priv *xhci_alloc_urb_priv(struct urb *urb) 13.382 +{ 13.383 + struct urb_priv *urbp; 13.384 + 13.385 + urbp = kmem_cache_alloc(xhci_up_cachep, SLAB_ATOMIC); 13.386 + if (!urbp) { 13.387 + err("xhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n"); 13.388 + return NULL; 13.389 + } 13.390 + 13.391 + memset((void *)urbp, 0, sizeof(*urbp)); 13.392 + 13.393 + urbp->inserttime = jiffies; 13.394 + urbp->urb = urb; 13.395 + urbp->dev = urb->dev; 13.396 + 13.397 + INIT_LIST_HEAD(&urbp->complete_list); 13.398 + 13.399 + urb->hcpriv = urbp; 13.400 + 13.401 + return urbp; 13.402 +} 13.403 + 13.404 +/* 13.405 + * MUST be called with urb->lock acquired 13.406 + */ 13.407 +/* When is this called? Do we need to stop the transfer (as we 13.408 + * currently do)? */ 13.409 +static void xhci_destroy_urb_priv(struct urb *urb) 13.410 +{ 13.411 + struct urb_priv *urbp; 13.412 + 13.413 + urbp = (struct urb_priv *)urb->hcpriv; 13.414 + if (!urbp) 13.415 + return; 13.416 + 13.417 + if (!list_empty(&urb->urb_list)) 13.418 + warn("xhci_destroy_urb_priv: urb %p still on xhci->urb_list or xhci->remove_list", urb); 13.419 + 13.420 + if (!list_empty(&urbp->complete_list)) 13.421 + warn("xhci_destroy_urb_priv: urb %p still on xhci->complete_list", urb); 13.422 + 13.423 + kmem_cache_free(xhci_up_cachep, urb->hcpriv); 13.424 + 13.425 + urb->hcpriv = NULL; 13.426 +} 13.427 + 13.428 +/** 13.429 + * Try to find URBs in progress on the same pipe to the same device. 13.430 + * 13.431 + * MUST be called with xhci->urb_list_lock acquired 13.432 + */ 13.433 +static struct urb *xhci_find_urb_ep(struct xhci *xhci, struct urb *urb) 13.434 +{ 13.435 + struct list_head *tmp, *head; 13.436 + 13.437 + /* We don't match Isoc transfers since they are special */ 13.438 + if (usb_pipeisoc(urb->pipe)) 13.439 + return NULL; 13.440 + 13.441 + head = &xhci->urb_list; 13.442 + tmp = head->next; 13.443 + while (tmp != head) { 13.444 + struct urb *u = list_entry(tmp, struct urb, urb_list); 13.445 + 13.446 + tmp = tmp->next; 13.447 + 13.448 + if (u->dev == urb->dev && u->pipe == urb->pipe && 13.449 + u->status == -EINPROGRESS) 13.450 + return u; 13.451 + } 13.452 + 13.453 + return NULL; 13.454 +} 13.455 + 13.456 +static int xhci_submit_urb(struct urb *urb) 13.457 +{ 13.458 + int ret = -EINVAL; 13.459 + unsigned long flags; 13.460 + struct urb *eurb; 13.461 + int bustime; 13.462 + 13.463 +#if 0 13.464 + printk("submitting urb @ %p for dev @ %p, devnum = %d path %s\n", 13.465 + urb, urb->dev, urb->dev->devnum, urb->dev->devpath); 13.466 +#endif 13.467 + 13.468 + if (!urb) 13.469 + return -EINVAL; 13.470 + 13.471 + if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) { 13.472 + warn("xhci_submit_urb: urb %p belongs to disconnected device or bus?", urb); 13.473 + return -ENODEV; 13.474 + } 13.475 + 13.476 + if ( urb->dev->devpath == NULL ) 13.477 + { 13.478 + printk("BARF!\n"); 13.479 + BUG(); 13.480 + } 13.481 + 13.482 + 13.483 + 13.484 + usb_inc_dev_use(urb->dev); 13.485 + 13.486 + spin_lock_irqsave(&xhci->urb_list_lock, flags); 13.487 + spin_lock(&urb->lock); 13.488 + 13.489 + if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET || 13.490 + urb->status == -ECONNABORTED) { 13.491 + dbg("xhci_submit_urb: urb not available to submit (status = %d)", urb->status); 13.492 + /* Since we can have problems on the out path */ 13.493 + spin_unlock(&urb->lock); 13.494 + spin_unlock_irqrestore(&xhci->urb_list_lock, flags); 13.495 + usb_dec_dev_use(urb->dev); 13.496 + 13.497 + return ret; 13.498 + } 13.499 + 13.500 + INIT_LIST_HEAD(&urb->urb_list); 13.501 + if (!xhci_alloc_urb_priv(urb)) { 13.502 + ret = -ENOMEM; 13.503 + 13.504 + goto out; 13.505 + } 13.506 + 13.507 + ( (struct urb_priv *)urb->hcpriv )->in_progress = 1; 13.508 + 13.509 + eurb = xhci_find_urb_ep(xhci, urb); 13.510 + if (eurb && !(urb->transfer_flags & USB_QUEUE_BULK)) { 13.511 + ret = -ENXIO; 13.512 + 13.513 + goto out; 13.514 + } 13.515 + 13.516 + /* Short circuit the virtual root hub */ 13.517 + if (urb->dev == xhci->rh.dev) { 13.518 + ret = rh_submit_urb(urb); 13.519 + 13.520 + goto out; 13.521 + } 13.522 + 13.523 + if ( usb_pipedevice(urb->pipe) == 1 ) 13.524 + printk("dev = %p, dev->path = %s, rh.dev = %p, rh.dev.devnum = %d rh.dev->path = %s!\n", 13.525 + urb->dev, urb->dev->devpath, xhci->rh.dev, xhci->rh.dev->devnum, xhci->rh.dev->devpath); 13.526 + 13.527 + switch (usb_pipetype(urb->pipe)) { 13.528 + case PIPE_CONTROL: 13.529 + ret = xhci_queue_req(urb); 13.530 + break; 13.531 + case PIPE_INTERRUPT: 13.532 + if (urb->bandwidth == 0) { /* not yet checked/allocated */ 13.533 + bustime = usb_check_bandwidth(urb->dev, urb); 13.534 + if (bustime < 0) 13.535 + ret = bustime; 13.536 + else { 13.537 + ret = xhci_queue_req(urb); 13.538 + if (ret == -EINPROGRESS) 13.539 + usb_claim_bandwidth(urb->dev, urb, bustime, 0); 13.540 + } 13.541 + } else /* bandwidth is already set */ 13.542 + ret = xhci_queue_req(urb); 13.543 + break; 13.544 + case PIPE_BULK: 13.545 + ret = xhci_queue_req(urb); 13.546 + break; 13.547 + case PIPE_ISOCHRONOUS: 13.548 + if (urb->bandwidth == 0) { /* not yet checked/allocated */ 13.549 + if (urb->number_of_packets <= 0) { 13.550 + ret = -EINVAL; 13.551 + break; 13.552 + } 13.553 + bustime = usb_check_bandwidth(urb->dev, urb); 13.554 + if (bustime < 0) { 13.555 + ret = bustime; 13.556 + break; 13.557 + } 13.558 + 13.559 + ret = xhci_queue_req(urb); 13.560 + if (ret == -EINPROGRESS) 13.561 + usb_claim_bandwidth(urb->dev, urb, bustime, 1); 13.562 + } else /* bandwidth is already set */ 13.563 + ret = xhci_queue_req(urb); 13.564 + break; 13.565 + } 13.566 + 13.567 +out: 13.568 + urb->status = ret; 13.569 + 13.570 + if (ret == -EINPROGRESS) { 13.571 + /* We use _tail to make find_urb_ep more efficient */ 13.572 + list_add_tail(&urb->urb_list, &xhci->urb_list); 13.573 + 13.574 + spin_unlock(&urb->lock); 13.575 + spin_unlock_irqrestore(&xhci->urb_list_lock, flags); 13.576 + 13.577 + return 0; 13.578 + } 13.579 + 13.580 + xhci_unlink_generic(urb); 13.581 + 13.582 + spin_unlock(&urb->lock); 13.583 + spin_unlock_irqrestore(&xhci->urb_list_lock, flags); 13.584 + 13.585 + /* Only call completion if it was successful */ 13.586 + if (!ret) 13.587 + xhci_call_completion(urb); 13.588 + 13.589 + return ret; 13.590 +} 13.591 + 13.592 +/* 13.593 + * Return the result of a transfer 13.594 + * 13.595 + * MUST be called with urb_list_lock acquired 13.596 + */ 13.597 +static void xhci_transfer_result(struct xhci *xhci, struct urb *urb) 13.598 +{ 13.599 + int ret = 0; 13.600 + unsigned long flags; 13.601 + struct urb_priv *urbp; 13.602 + 13.603 + /* The root hub is special */ 13.604 + if (urb->dev == xhci->rh.dev) 13.605 + return; 13.606 + 13.607 + spin_lock_irqsave(&urb->lock, flags); 13.608 + 13.609 + urbp = (struct urb_priv *)urb->hcpriv; 13.610 + 13.611 + if ( ( (struct urb_priv *)urb->hcpriv )->in_progress ) 13.612 + ret = -EINPROGRESS; 13.613 + 13.614 + if (urb->actual_length < urb->transfer_buffer_length) { 13.615 + if (urb->transfer_flags & USB_DISABLE_SPD) { 13.616 + ret = -EREMOTEIO; 13.617 + } 13.618 + } 13.619 + 13.620 + if (urb->status == -EPIPE) 13.621 + { 13.622 + ret = urb->status; 13.623 + /* endpoint has stalled - mark it halted */ 13.624 + usb_endpoint_halt(urb->dev, usb_pipeendpoint(urb->pipe), 13.625 + usb_pipeout(urb->pipe)); 13.626 + } 13.627 + 13.628 + if ((debug == 1 && ret != 0 && ret != -EPIPE) || 13.629 + (ret != 0 && debug > 1)) { 13.630 + /* Some debugging code */ 13.631 + dbg("xhci_result_interrupt/bulk() failed with status %x", 13.632 + status); 13.633 + } 13.634 + 13.635 + if (ret == -EINPROGRESS) 13.636 + goto out; 13.637 + 13.638 + switch (usb_pipetype(urb->pipe)) { 13.639 + case PIPE_CONTROL: 13.640 + case PIPE_BULK: 13.641 + case PIPE_ISOCHRONOUS: 13.642 + /* Release bandwidth for Interrupt or Isoc. transfers */ 13.643 + /* Spinlock needed ? */ 13.644 + if (urb->bandwidth) 13.645 + usb_release_bandwidth(urb->dev, urb, 1); 13.646 + xhci_unlink_generic(urb); 13.647 + break; 13.648 + case PIPE_INTERRUPT: 13.649 + /* Interrupts are an exception */ 13.650 + if (urb->interval) 13.651 + goto out_complete; 13.652 + 13.653 + /* Release bandwidth for Interrupt or Isoc. transfers */ 13.654 + /* Spinlock needed ? */ 13.655 + if (urb->bandwidth) 13.656 + usb_release_bandwidth(urb->dev, urb, 0); 13.657 + xhci_unlink_generic(urb); 13.658 + break; 13.659 + default: 13.660 + info("xhci_transfer_result: unknown pipe type %d for urb %p\n", 13.661 + usb_pipetype(urb->pipe), urb); 13.662 + } 13.663 + 13.664 + /* Remove it from xhci->urb_list */ 13.665 + list_del_init(&urb->urb_list); 13.666 + 13.667 +out_complete: 13.668 + xhci_add_complete(urb); 13.669 + 13.670 +out: 13.671 + spin_unlock_irqrestore(&urb->lock, flags); 13.672 +} 13.673 + 13.674 +/* 13.675 + * MUST be called with urb->lock acquired 13.676 + */ 13.677 +static void xhci_unlink_generic(struct urb *urb) 13.678 +{ 13.679 + struct urb_priv *urbp = urb->hcpriv; 13.680 + 13.681 + /* We can get called when urbp allocation fails, so check */ 13.682 + if (!urbp) 13.683 + return; 13.684 + 13.685 + /* ??? This function is now so minimal it doesn't do much. Do we really 13.686 + * need it? */ 13.687 + 13.688 + xhci_delete_urb(urb); 13.689 +} 13.690 + 13.691 +static int xhci_unlink_urb(struct urb *urb) 13.692 +{ 13.693 + unsigned long flags; 13.694 + struct urb_priv *urbp = urb->hcpriv; 13.695 + 13.696 + if (!urb) 13.697 + return -EINVAL; 13.698 + 13.699 + if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) 13.700 + return -ENODEV; 13.701 + 13.702 + spin_lock_irqsave(&xhci->urb_list_lock, flags); 13.703 + spin_lock(&urb->lock); 13.704 + 13.705 + /* Release bandwidth for Interrupt or Isoc. transfers */ 13.706 + /* Spinlock needed ? */ 13.707 + if (urb->bandwidth) { 13.708 + switch (usb_pipetype(urb->pipe)) { 13.709 + case PIPE_INTERRUPT: 13.710 + usb_release_bandwidth(urb->dev, urb, 0); 13.711 + break; 13.712 + case PIPE_ISOCHRONOUS: 13.713 + usb_release_bandwidth(urb->dev, urb, 1); 13.714 + break; 13.715 + default: 13.716 + break; 13.717 + } 13.718 + } 13.719 + 13.720 + if (urb->status != -EINPROGRESS) { 13.721 + spin_unlock(&urb->lock); 13.722 + spin_unlock_irqrestore(&xhci->urb_list_lock, flags); 13.723 + return 0; 13.724 + } 13.725 + 13.726 + list_del_init(&urb->urb_list); 13.727 + 13.728 + xhci_unlink_generic(urb); 13.729 + 13.730 + /* Short circuit the virtual root hub */ 13.731 + if (urb->dev == xhci->rh.dev) { 13.732 + rh_unlink_urb(urb); 13.733 + 13.734 + spin_unlock(&urb->lock); 13.735 + spin_unlock_irqrestore(&xhci->urb_list_lock, flags); 13.736 + 13.737 + xhci_call_completion(urb); 13.738 + } else { 13.739 + if (urb->transfer_flags & USB_ASYNC_UNLINK) { 13.740 + urbp->status = urb->status = -ECONNABORTED; 13.741 + 13.742 + spin_lock(&xhci->urb_remove_list_lock); 13.743 + 13.744 + list_add(&urb->urb_list, &xhci->urb_remove_list); 13.745 + 13.746 + spin_unlock(&xhci->urb_remove_list_lock); 13.747 + 13.748 + spin_unlock(&urb->lock); 13.749 + spin_unlock_irqrestore(&xhci->urb_list_lock, flags); 13.750 + 13.751 + } else { 13.752 + urb->status = -ENOENT; 13.753 + 13.754 + spin_unlock(&urb->lock); 13.755 + spin_unlock_irqrestore(&xhci->urb_list_lock, flags); 13.756 + 13.757 + if (in_interrupt()) { /* wait at least 1 frame */ 13.758 + static int errorcount = 10; 13.759 + 13.760 + if (errorcount--) 13.761 + dbg("xhci_unlink_urb called from interrupt for urb %p", urb); 13.762 + udelay(1000); 13.763 + } else 13.764 + schedule_timeout(1+1*HZ/1000); 13.765 + 13.766 + xhci_call_completion(urb); 13.767 + } 13.768 + } 13.769 + 13.770 + return 0; 13.771 +} 13.772 + 13.773 + 13.774 +struct usb_operations xhci_device_operations = { 13.775 + .allocate = xhci_alloc_dev, 13.776 + .deallocate = xhci_free_dev, 13.777 + /* It doesn't look like any drivers actually care what the frame number 13.778 + * is at the moment! If necessary, we could approximate the current 13.779 + * frame nubmer by passing it from the backend in response messages. */ 13.780 + .get_frame_number = NULL, 13.781 + .submit_urb = xhci_submit_urb, 13.782 + .unlink_urb = xhci_unlink_urb 13.783 +}; 13.784 + 13.785 +/* Virtual Root Hub */ 13.786 + 13.787 +static __u8 root_hub_dev_des[] = 13.788 +{ 13.789 + 0x12, /* __u8 bLength; */ 13.790 + 0x01, /* __u8 bDescriptorType; Device */ 13.791 + 0x00, /* __u16 bcdUSB; v1.0 */ 13.792 + 0x01, 13.793 + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 13.794 + 0x00, /* __u8 bDeviceSubClass; */ 13.795 + 0x00, /* __u8 bDeviceProtocol; */ 13.796 + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ 13.797 + 0x00, /* __u16 idVendor; */ 13.798 + 0x00, 13.799 + 0x00, /* __u16 idProduct; */ 13.800 + 0x00, 13.801 + 0x00, /* __u16 bcdDevice; */ 13.802 + 0x00, 13.803 + 0x00, /* __u8 iManufacturer; */ 13.804 + 0x02, /* __u8 iProduct; */ 13.805 + 0x01, /* __u8 iSerialNumber; */ 13.806 + 0x01 /* __u8 bNumConfigurations; */ 13.807 +}; 13.808 + 13.809 + 13.810 +/* Configuration descriptor */ 13.811 +static __u8 root_hub_config_des[] = 13.812 +{ 13.813 + 0x09, /* __u8 bLength; */ 13.814 + 0x02, /* __u8 bDescriptorType; Configuration */ 13.815 + 0x19, /* __u16 wTotalLength; */ 13.816 + 0x00, 13.817 + 0x01, /* __u8 bNumInterfaces; */ 13.818 + 0x01, /* __u8 bConfigurationValue; */ 13.819 + 0x00, /* __u8 iConfiguration; */ 13.820 + 0x40, /* __u8 bmAttributes; 13.821 + Bit 7: Bus-powered, 6: Self-powered, 13.822 + Bit 5 Remote-wakeup, 4..0: resvd */ 13.823 + 0x00, /* __u8 MaxPower; */ 13.824 + 13.825 + /* interface */ 13.826 + 0x09, /* __u8 if_bLength; */ 13.827 + 0x04, /* __u8 if_bDescriptorType; Interface */ 13.828 + 0x00, /* __u8 if_bInterfaceNumber; */ 13.829 + 0x00, /* __u8 if_bAlternateSetting; */ 13.830 + 0x01, /* __u8 if_bNumEndpoints; */ 13.831 + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ 13.832 + 0x00, /* __u8 if_bInterfaceSubClass; */ 13.833 + 0x00, /* __u8 if_bInterfaceProtocol; */ 13.834 + 0x00, /* __u8 if_iInterface; */ 13.835 + 13.836 + /* endpoint */ 13.837 + 0x07, /* __u8 ep_bLength; */ 13.838 + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 13.839 + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 13.840 + 0x03, /* __u8 ep_bmAttributes; Interrupt */ 13.841 + 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */ 13.842 + 0x00, 13.843 + 0xff /* __u8 ep_bInterval; 255 ms */ 13.844 +}; 13.845 + 13.846 +static __u8 root_hub_hub_des[] = 13.847 +{ 13.848 + 0x09, /* __u8 bLength; */ 13.849 + 0x29, /* __u8 bDescriptorType; Hub-descriptor */ 13.850 + 0x02, /* __u8 bNbrPorts; */ 13.851 + 0x00, /* __u16 wHubCharacteristics; */ 13.852 + 0x00, 13.853 + 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ 13.854 + 0x00, /* __u8 bHubContrCurrent; 0 mA */ 13.855 + 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ 13.856 + 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ 13.857 +}; 13.858 + 13.859 +/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */ 13.860 +static int rh_send_irq(struct urb *urb) 13.861 +{ 13.862 + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; 13.863 + xhci_port_t *ports = xhci->rh.ports; 13.864 + unsigned long flags; 13.865 + int i, len = 1; 13.866 + __u16 data = 0; 13.867 + 13.868 + spin_lock_irqsave(&urb->lock, flags); 13.869 + for (i = 0; i < xhci->rh.numports; i++) { 13.870 + /* MAW: No idea what the old code was doing here or why it worked. 13.871 + * This implementation sets a bit if anything at all has changed on the 13.872 + * port, as per USB spec 11.12 */ 13.873 + data |= (ports[i].cs_chg || ports[i].pe_chg ) 13.874 + ? (1 << (i + 1)) 13.875 + : 0; 13.876 + 13.877 + len = (i + 1) / 8 + 1; 13.878 + } 13.879 + 13.880 + *(__u16 *) urb->transfer_buffer = cpu_to_le16(data); 13.881 + urb->actual_length = len; 13.882 + urbp->status = 0; 13.883 + 13.884 + spin_unlock_irqrestore(&urb->lock, flags); 13.885 + 13.886 + if ((data > 0) && (xhci->rh.send != 0)) { 13.887 + dbg("root-hub INT complete: data: %x", data); 13.888 + xhci_call_completion(urb); 13.889 + } 13.890 + 13.891 + return 0; 13.892 +} 13.893 + 13.894 +/* Virtual Root Hub INTs are polled by this timer every "interval" ms */ 13.895 +static int rh_init_int_timer(struct urb *urb); 13.896 + 13.897 +static void rh_int_timer_do(unsigned long ptr) 13.898 +{ 13.899 + struct urb *urb = (struct urb *)ptr; 13.900 + struct list_head list, *tmp, *head; 13.901 + unsigned long flags; 13.902 + int i; 13.903 + 13.904 + for ( i = 0; i < xhci->rh.numports; i++) 13.905 + xhci_queue_probe(i); 13.906 + 13.907 + if (xhci->rh.send) 13.908 + rh_send_irq(urb); 13.909 + 13.910 + INIT_LIST_HEAD(&list); 13.911 + 13.912 + spin_lock_irqsave(&xhci->urb_list_lock, flags); 13.913 + head = &xhci->urb_list; 13.914 + tmp = head->next; 13.915 + while (tmp != head) { 13.916 + struct urb *u = list_entry(tmp, struct urb, urb_list); 13.917 + struct urb_priv *up = (struct urb_priv *)u->hcpriv; 13.918 + 13.919 + tmp = tmp->next; 13.920 + 13.921 + spin_lock(&u->lock); 13.922 + 13.923 + /* Check if the URB timed out */ 13.924 + if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) { 13.925 + list_del(&u->urb_list); 13.926 + list_add_tail(&u->urb_list, &list); 13.927 + } 13.928 + 13.929 + spin_unlock(&u->lock); 13.930 + } 13.931 + spin_unlock_irqrestore(&xhci->urb_list_lock, flags); 13.932 + 13.933 + head = &list; 13.934 + tmp = head->next; 13.935 + while (tmp != head) { 13.936 + struct urb *u = list_entry(tmp, struct urb, urb_list); 13.937 + 13.938 + tmp = tmp->next; 13.939 + 13.940 + u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED; 13.941 + xhci_unlink_urb(u); 13.942 + } 13.943 + 13.944 + rh_init_int_timer(urb); 13.945 +} 13.946 + 13.947 +/* Root Hub INTs are polled by this timer */ 13.948 +static int rh_init_int_timer(struct urb *urb) 13.949 +{ 13.950 + xhci->rh.interval = urb->interval; 13.951 + init_timer(&xhci->rh.rh_int_timer); 13.952 + xhci->rh.rh_int_timer.function = rh_int_timer_do; 13.953 + xhci->rh.rh_int_timer.data = (unsigned long)urb; 13.954 + xhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000; 13.955 + add_timer(&xhci->rh.rh_int_timer); 13.956 + 13.957 + return 0; 13.958 +} 13.959 + 13.960 +#define OK(x) len = (x); break 13.961 + 13.962 +/* Root Hub Control Pipe */ 13.963 +static int rh_submit_urb(struct urb *urb) 13.964 +{ 13.965 + unsigned int pipe = urb->pipe; 13.966 + struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet; 13.967 + void *data = urb->transfer_buffer; 13.968 + int leni = urb->transfer_buffer_length; 13.969 + int len = 0; 13.970 + xhci_port_t *status; 13.971 + int stat = 0; 13.972 + int i; 13.973 + int retstatus; 13.974 + unsigned long flags; 13.975 + 13.976 + __u16 cstatus; 13.977 + __u16 bmRType_bReq; 13.978 + __u16 wValue; 13.979 + __u16 wIndex; 13.980 + __u16 wLength; 13.981 + 13.982 + if (usb_pipetype(pipe) == PIPE_INTERRUPT) { 13.983 + xhci->rh.urb = urb; 13.984 + xhci->rh.send = 1; 13.985 + xhci->rh.interval = urb->interval; 13.986 + rh_init_int_timer(urb); 13.987 + 13.988 + return -EINPROGRESS; 13.989 + } 13.990 + 13.991 + bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8; 13.992 + wValue = le16_to_cpu(cmd->wValue); 13.993 + wIndex = le16_to_cpu(cmd->wIndex); 13.994 + wLength = le16_to_cpu(cmd->wLength); 13.995 + 13.996 + for (i = 0; i < 8; i++) 13.997 + xhci->rh.c_p_r[i] = 0; 13.998 + 13.999 + status = &xhci->rh.ports[wIndex - 1]; 13.1000 + 13.1001 + spin_lock_irqsave(&xhci->rh.port_state_lock, flags); 13.1002 + 13.1003 + switch (bmRType_bReq) { 13.1004 + /* Request Destination: 13.1005 + without flags: Device, 13.1006 + RH_INTERFACE: interface, 13.1007 + RH_ENDPOINT: endpoint, 13.1008 + RH_CLASS means HUB here, 13.1009 + RH_OTHER | RH_CLASS almost ever means HUB_PORT here 13.1010 + */ 13.1011 + 13.1012 + case RH_GET_STATUS: 13.1013 + *(__u16 *)data = cpu_to_le16(1); 13.1014 + OK(2); 13.1015 + case RH_GET_STATUS | RH_INTERFACE: 13.1016 + *(__u16 *)data = cpu_to_le16(0); 13.1017 + OK(2); 13.1018 + case RH_GET_STATUS | RH_ENDPOINT: 13.1019 + *(__u16 *)data = cpu_to_le16(0); 13.1020 + OK(2); 13.1021 + case RH_GET_STATUS | RH_CLASS: 13.1022 + *(__u32 *)data = cpu_to_le32(0); 13.1023 + OK(4); /* hub power */ 13.1024 + case RH_GET_STATUS | RH_OTHER | RH_CLASS: 13.1025 + cstatus = (status->cs_chg) | 13.1026 + (status->pe_chg << 1) | 13.1027 + (xhci->rh.c_p_r[wIndex - 1] << 4); 13.1028 + retstatus = (status->ccs) | 13.1029 + (status->pe << 1) | 13.1030 + (status->susp << 2) | 13.1031 + (status->pr << 8) | 13.1032 + (1 << 8) | /* power on */ 13.1033 + (status->lsda << 9); 13.1034 + *(__u16 *)data = cpu_to_le16(retstatus); 13.1035 + *(__u16 *)(data + 2) = cpu_to_le16(cstatus); 13.1036 + OK(4); 13.1037 + case RH_CLEAR_FEATURE | RH_ENDPOINT: 13.1038 + switch (wValue) { 13.1039 + case RH_ENDPOINT_STALL: 13.1040 + OK(0); 13.1041 + } 13.1042 + break; 13.1043 + case RH_CLEAR_FEATURE | RH_CLASS: 13.1044 + switch (wValue) { 13.1045 + case RH_C_HUB_OVER_CURRENT: 13.1046 + OK(0); /* hub power over current */ 13.1047 + } 13.1048 + break; 13.1049 + case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: 13.1050 + switch (wValue) { 13.1051 + case RH_PORT_ENABLE: 13.1052 + status->pe = 0; 13.1053 + OK(0); 13.1054 + case RH_PORT_SUSPEND: 13.1055 + status->susp = 0; 13.1056 + OK(0); 13.1057 + case RH_PORT_POWER: 13.1058 + OK(0); /* port power */ 13.1059 + case RH_C_PORT_CONNECTION: 13.1060 + status->cs_chg = 0; 13.1061 + OK(0); 13.1062 + case RH_C_PORT_ENABLE: 13.1063 + status->pe_chg = 0; 13.1064 + OK(0); 13.1065 + case RH_C_PORT_SUSPEND: 13.1066 + /*** WR_RH_PORTSTAT(RH_PS_PSSC); */ 13.1067 + OK(0); 13.1068 + case RH_C_PORT_OVER_CURRENT: 13.1069 + OK(0); /* port power over current */ 13.1070 + case RH_C_PORT_RESET: 13.1071 + xhci->rh.c_p_r[wIndex - 1] = 0; 13.1072 + OK(0); 13.1073 + } 13.1074 + break; 13.1075 + case RH_SET_FEATURE | RH_OTHER | RH_CLASS: 13.1076 + switch (wValue) { 13.1077 + case RH_PORT_SUSPEND: 13.1078 + status->susp = 1; 13.1079 + OK(0); 13.1080 + case RH_PORT_RESET: 13.1081 + { 13.1082 + int ret; 13.1083 + xhci->rh.c_p_r[wIndex - 1] = 1; 13.1084 + status->pr = 0; 13.1085 + status->pe = 1; 13.1086 + ret = xhci_port_reset(wIndex - 1); 13.1087 + /* XXX MAW: should probably cancel queued transfers during reset... *\/ */ 13.1088 + if ( ret == 0 ) { OK(0); } 13.1089 + else { return ret; } 13.1090 + } 13.1091 + break; 13.1092 + case RH_PORT_POWER: 13.1093 + OK(0); /* port power ** */ 13.1094 + case RH_PORT_ENABLE: 13.1095 + status->pe = 1; 13.1096 + OK(0); 13.1097 + } 13.1098 + break; 13.1099 + case RH_SET_ADDRESS: 13.1100 + printk("setting root hub device to %d\n", wValue); 13.1101 + xhci->rh.devnum = wValue; 13.1102 + OK(0); 13.1103 + case RH_GET_DESCRIPTOR: 13.1104 + switch ((wValue & 0xff00) >> 8) { 13.1105 + case 0x01: /* device descriptor */ 13.1106 + len = min_t(unsigned int, leni, 13.1107 + min_t(unsigned int, 13.1108 + sizeof(root_hub_dev_des), wLength)); 13.1109 + memcpy(data, root_hub_dev_des, len); 13.1110 + OK(len); 13.1111 + case 0x02: /* configuration descriptor */ 13.1112 + len = min_t(unsigned int, leni, 13.1113 + min_t(unsigned int, 13.1114 + sizeof(root_hub_config_des), wLength)); 13.1115 + memcpy (data, root_hub_config_des, len); 13.1116 + OK(len); 13.1117 + case 0x03: /* string descriptors */ 13.1118 + len = usb_root_hub_string (wValue & 0xff, 13.1119 + 0, "XHCI-alt", 13.1120 + data, wLength); 13.1121 + if (len > 0) { 13.1122 + OK(min_t(int, leni, len)); 13.1123 + } else 13.1124 + stat = -EPIPE; 13.1125 + } 13.1126 + break; 13.1127 + case RH_GET_DESCRIPTOR | RH_CLASS: 13.1128 + root_hub_hub_des[2] = xhci->rh.numports; 13.1129 + len = min_t(unsigned int, leni, 13.1130 + min_t(unsigned int, sizeof(root_hub_hub_des), wLength)); 13.1131 + memcpy(data, root_hub_hub_des, len); 13.1132 + OK(len); 13.1133 + case RH_GET_CONFIGURATION: 13.1134 + *(__u8 *)data = 0x01; 13.1135 + OK(1); 13.1136 + case RH_SET_CONFIGURATION: 13.1137 + OK(0); 13.1138 + case RH_GET_INTERFACE | RH_INTERFACE: 13.1139 + *(__u8 *)data = 0x00; 13.1140 + OK(1); 13.1141 + case RH_SET_INTERFACE | RH_INTERFACE: 13.1142 + OK(0); 13.1143 + default: 13.1144 + stat = -EPIPE; 13.1145 + } 13.1146 + 13.1147 + spin_unlock_irqrestore(&xhci->rh.port_state_lock, flags); 13.1148 + 13.1149 + urb->actual_length = len; 13.1150 + 13.1151 + return stat; 13.1152 +} 13.1153 + 13.1154 +/* 13.1155 + * MUST be called with urb->lock acquired 13.1156 + */ 13.1157 +static int rh_unlink_urb(struct urb *urb) 13.1158 +{ 13.1159 + if (xhci->rh.urb == urb) { 13.1160 + urb->status = -ENOENT; 13.1161 + xhci->rh.send = 0; 13.1162 + xhci->rh.urb = NULL; 13.1163 + del_timer(&xhci->rh.rh_int_timer); 13.1164 + } 13.1165 + return 0; 13.1166 +} 13.1167 + 13.1168 +static void xhci_call_completion(struct urb *urb) 13.1169 +{ 13.1170 + struct urb_priv *urbp; 13.1171 + struct usb_device *dev = urb->dev; 13.1172 + int is_ring = 0, killed, resubmit_interrupt, status; 13.1173 + struct urb *nurb; 13.1174 + unsigned long flags; 13.1175 + 13.1176 + spin_lock_irqsave(&urb->lock, flags); 13.1177 + 13.1178 + urbp = (struct urb_priv *)urb->hcpriv; 13.1179 + if (!urbp || !urb->dev) { 13.1180 + spin_unlock_irqrestore(&urb->lock, flags); 13.1181 + return; 13.1182 + } 13.1183 + 13.1184 + killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED || 13.1185 + urb->status == -ECONNRESET); 13.1186 + resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT && 13.1187 + urb->interval); 13.1188 + 13.1189 + nurb = urb->next; 13.1190 + if (nurb && !killed) { 13.1191 + int count = 0; 13.1192 + 13.1193 + while (nurb && nurb != urb && count < MAX_URB_LOOP) { 13.1194 + if (nurb->status == -ENOENT || 13.1195 + nurb->status == -ECONNABORTED || 13.1196 + nurb->status == -ECONNRESET) { 13.1197 + killed = 1; 13.1198 + break; 13.1199 + } 13.1200 + 13.1201 + nurb = nurb->next; 13.1202 + count++; 13.1203 + } 13.1204 + 13.1205 + if (count == MAX_URB_LOOP) 13.1206 + err("xhci_call_completion: too many linked URB's, loop? (first loop)"); 13.1207 + 13.1208 + /* Check to see if chain is a ring */ 13.1209 + is_ring = (nurb == urb); 13.1210 + } 13.1211 + 13.1212 + status = urbp->status; 13.1213 + if (!resubmit_interrupt || killed) 13.1214 + /* We don't need urb_priv anymore */ 13.1215 + xhci_destroy_urb_priv(urb); 13.1216 + 13.1217 + if (!killed) 13.1218 + urb->status = status; 13.1219 + 13.1220 + spin_unlock_irqrestore(&urb->lock, flags); 13.1221 + 13.1222 + if (urb->complete) 13.1223 + urb->complete(urb); 13.1224 + 13.1225 + if (resubmit_interrupt) 13.1226 + /* Recheck the status. The completion handler may have */ 13.1227 + /* unlinked the resubmitting interrupt URB */ 13.1228 + killed = (urb->status == -ENOENT || 13.1229 + urb->status == -ECONNABORTED || 13.1230 + urb->status == -ECONNRESET); 13.1231 + 13.1232 + if (resubmit_interrupt && !killed) { 13.1233 + if ( urb->dev != xhci->rh.dev ) 13.1234 + xhci_queue_req(urb); /* XXX What if this fails? */ 13.1235 + /* Don't need to resubmit URBs for the virtual root dev. */ 13.1236 + } else { 13.1237 + if (is_ring && !killed) { 13.1238 + urb->dev = dev; 13.1239 + xhci_submit_urb(urb); 13.1240 + } else { 13.1241 + /* We decrement the usage count after we're done */ 13.1242 + /* with everything */ 13.1243 + usb_dec_dev_use(dev); 13.1244 + } 13.1245 + } 13.1246 +} 13.1247 + 13.1248 +static void xhci_finish_completion(void) 13.1249 +{ 13.1250 + struct list_head *tmp, *head; 13.1251 + unsigned long flags; 13.1252 + 13.1253 + spin_lock_irqsave(&xhci->complete_list_lock, flags); 13.1254 + head = &xhci->complete_list; 13.1255 + tmp = head->next; 13.1256 + while (tmp != head) { 13.1257 + struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list); 13.1258 + struct urb *urb = urbp->urb; 13.1259 + 13.1260 + list_del_init(&urbp->complete_list); 13.1261 + spin_unlock_irqrestore(&xhci->complete_list_lock, flags); 13.1262 + 13.1263 + xhci_call_completion(urb); 13.1264 + 13.1265 + spin_lock_irqsave(&xhci->complete_list_lock, flags); 13.1266 + head = &xhci->complete_list; 13.1267 + tmp = head->next; 13.1268 + } 13.1269 + spin_unlock_irqrestore(&xhci->complete_list_lock, flags); 13.1270 +} 13.1271 + 13.1272 +void receive_usb_reset(usbif_response_t *resp) 13.1273 +{ 13.1274 + awaiting_reset = resp->status; 13.1275 + rmb(); 13.1276 + 13.1277 +} 13.1278 + 13.1279 +void receive_usb_probe(usbif_response_t *resp) 13.1280 +{ 13.1281 + spin_lock(&xhci->rh.port_state_lock); 13.1282 + 13.1283 + if ( resp->status > 0 ) 13.1284 + { 13.1285 + if ( resp->status == 1 ) 13.1286 + { 13.1287 +/* printk("hey hey, there's a device on port %d\n", resp->data); */ 13.1288 + 13.1289 + /* If theres a device there and there wasn't one before there must 13.1290 + * have been a connection status change. */ 13.1291 + if( xhci->rh.ports[resp->data].cs == 0 ) 13.1292 + { 13.1293 + xhci->rh.ports[resp->data].cs = 1; 13.1294 + xhci->rh.ports[resp->data].ccs = 1; 13.1295 + xhci->rh.ports[resp->data].cs_chg = 1; 13.1296 +/* printk("Look at device on port %d that wasn't there before\n", resp->data); */ 13.1297 + } 13.1298 + } 13.1299 + else 13.1300 + printk("receive_usb_probe(): unexpected status %d for port %d\n", 13.1301 + resp->status, resp->data); 13.1302 + } 13.1303 + else if ( resp->status < 0) 13.1304 + printk("receive_usb_probe(): got error status %d\n", resp->status); 13.1305 + 13.1306 + spin_unlock(&xhci->rh.port_state_lock); 13.1307 +} 13.1308 + 13.1309 +void receive_usb_io(usbif_response_t *resp) 13.1310 +{ 13.1311 + struct urb_priv *urbp = (struct urb_priv *)resp->id; 13.1312 + struct urb *urb = urbp->urb; 13.1313 + 13.1314 + urb->actual_length = resp->length; 13.1315 + urb->status = resp->status; 13.1316 + urbp->status = resp->status; 13.1317 + urbp->in_progress = 0; 13.1318 + 13.1319 + if( usb_pipetype(urb->pipe) == 0 ) /* ISO */ 13.1320 + { 13.1321 + int i; 13.1322 + 13.1323 + /* Copy ISO schedule results back in. */ 13.1324 + 13.1325 + for ( i = 0; i < urb->number_of_packets; i++ ) 13.1326 + { 13.1327 + urb->iso_frame_desc[i].status 13.1328 + = urbp->schedule[i].status; 13.1329 + urb->iso_frame_desc[i].actual_length 13.1330 + = urbp->schedule[i].length; 13.1331 + } 13.1332 + free_page((unsigned long)urbp->schedule); 13.1333 + } 13.1334 +} 13.1335 + 13.1336 +static void xhci_drain_ring(void) 13.1337 +{ 13.1338 + struct list_head *tmp, *head; 13.1339 + usbif_t *usb_ring = xhci->usbif; 13.1340 + usbif_response_t *resp; 13.1341 + USBIF_RING_IDX i, rp; 13.1342 + 13.1343 + /* Walk the ring here to get responses, updating URBs to show what 13.1344 + * completed. */ 13.1345 + 13.1346 + rp = usb_ring->resp_prod; 13.1347 + rmb(); /* Ensure we see queued requests up to 'rp'. */ 13.1348 + 13.1349 + /* Take items off the comms ring, taking care not to overflow. */ 13.1350 + for ( i = xhci->usb_resp_cons; 13.1351 + (i != rp) && ((i-usb_ring->req_prod) != USBIF_RING_SIZE); 13.1352 + i++ ) 13.1353 + { 13.1354 + resp = &usb_ring->ring[MASK_USBIF_IDX(i)].resp; 13.1355 + 13.1356 + /* May need to deal with batching and with putting a ceiling on 13.1357 + the number dispatched for performance and anti-dos reasons */ 13.1358 + 13.1359 +#if 0 13.1360 + printk("usbfront: Processing response:\n"); 13.1361 + printk(" id = 0x%x\n", resp->id); 13.1362 + printk(" op = %d\n", resp->operation); 13.1363 + printk(" status = %d\n", resp->status); 13.1364 + printk(" length = %d\n", resp->length); 13.1365 +#endif 13.1366 + 13.1367 + switch ( resp->operation ) 13.1368 + { 13.1369 + case USBIF_OP_PROBE: 13.1370 + receive_usb_probe(resp); 13.1371 + break; 13.1372 + 13.1373 + case USBIF_OP_IO: 13.1374 + receive_usb_io(resp); 13.1375 + break; 13.1376 + 13.1377 + case USBIF_OP_RESET: 13.1378 + receive_usb_reset(resp); 13.1379 + break; 13.1380 + 13.1381 + default: 13.1382 + printk("error: unknown USB io operation response [%d]\n", 13.1383 + usb_ring->ring[i].req.operation); 13.1384 + break; 13.1385 + } 13.1386 + } 13.1387 + 13.1388 + xhci->usb_resp_cons = i; 13.1389 + 13.1390 + /* Walk the list of pending URB's to see which ones completed and do 13.1391 + * callbacks, etc. */ 13.1392 + spin_lock(&xhci->urb_list_lock); 13.1393 + head = &xhci->urb_list; 13.1394 + tmp = head->next; 13.1395 + while (tmp != head) { 13.1396 + 13.1397 + struct urb *urb = list_entry(tmp, struct urb, urb_list); 13.1398 + 13.1399 + tmp = tmp->next; 13.1400 + 13.1401 + /* Checks the status and does all of the magic necessary */ 13.1402 + xhci_transfer_result(xhci, urb); 13.1403 + } 13.1404 + spin_unlock(&xhci->urb_list_lock); 13.1405 + 13.1406 + xhci_finish_completion(); 13.1407 +} 13.1408 + 13.1409 + 13.1410 +static void xhci_interrupt(int irq, void *__xhci, struct pt_regs *regs) 13.1411 +{ 13.1412 + xhci_drain_ring(); 13.1413 +} 13.1414 + 13.1415 +static void free_xhci(struct xhci *xhci) 13.1416 +{ 13.1417 + kfree(xhci); 13.1418 +} 13.1419 + 13.1420 +/* /\* */ 13.1421 +/* * De-allocate all resources.. */ 13.1422 +/* *\/ */ 13.1423 +/* static void release_xhci(struct xhci *xhci) */ 13.1424 +/* { */ 13.1425 +/* if (xhci->irq >= 0) { */ 13.1426 +/* free_irq(xhci->irq, xhci); */ 13.1427 +/* xhci->irq = -1; */ 13.1428 +/* } */ 13.1429 + 13.1430 +/* /\* Get the ring back from the backend domain. Then free it. Hmmmm. */ 13.1431 +/* * Lets ignore this for now - not particularly useful. *\/ */ 13.1432 + 13.1433 +/* free_xhci(xhci); */ 13.1434 +/* } */ 13.1435 + 13.1436 +/** 13.1437 + * Initialise a new virtual root hub for a new USB device channel. 13.1438 + */ 13.1439 +static int alloc_xhci(void) 13.1440 +{ 13.1441 + int retval; 13.1442 + struct usb_bus *bus; 13.1443 + 13.1444 + retval = -EBUSY; 13.1445 + 13.1446 + xhci = kmalloc(sizeof(*xhci), GFP_KERNEL); 13.1447 + if (!xhci) { 13.1448 + err("couldn't allocate xhci structure"); 13.1449 + retval = -ENOMEM; 13.1450 + goto err_alloc_xhci; 13.1451 + } 13.1452 + 13.1453 + /* Reset here so we don't get any interrupts from an old setup */ 13.1454 + /* or broken setup */ 13.1455 + // reset_hc(xhci); 13.1456 + 13.1457 + 13.1458 + xhci->state = USBIF_STATE_CLOSED; 13.1459 + xhci->is_suspended = 0; 13.1460 + 13.1461 + spin_lock_init(&xhci->urb_remove_list_lock); 13.1462 + INIT_LIST_HEAD(&xhci->urb_remove_list); 13.1463 + 13.1464 + spin_lock_init(&xhci->urb_list_lock); 13.1465 + INIT_LIST_HEAD(&xhci->urb_list); 13.1466 + 13.1467 + spin_lock_init(&xhci->complete_list_lock); 13.1468 + INIT_LIST_HEAD(&xhci->complete_list); 13.1469 + 13.1470 + spin_lock_init(&xhci->frame_list_lock); 13.1471 + 13.1472 + /* We need exactly one page (per XHCI specs), how convenient */ 13.1473 + /* We assume that one page is atleast 4k (1024 frames * 4 bytes) */ 13.1474 +#if PAGE_SIZE < (4 * 1024) 13.1475 +#error PAGE_SIZE is not atleast 4k 13.1476 +#endif 13.1477 + bus = usb_alloc_bus(&xhci_device_operations); 13.1478 + if (!bus) { 13.1479 + err("unable to allocate bus"); 13.1480 + goto err_alloc_bus; 13.1481 + } 13.1482 + 13.1483 + xhci->bus = bus; 13.1484 + bus->bus_name = "XHCI"; 13.1485 + bus->hcpriv = xhci; 13.1486 + 13.1487 + usb_register_bus(xhci->bus); 13.1488 + 13.1489 + /* Initialize the root hub */ 13.1490 + 13.1491 + xhci->rh.numports = 0; 13.1492 + 13.1493 + xhci->bus->root_hub = xhci->rh.dev = usb_alloc_dev(NULL, xhci->bus); 13.1494 + if (!xhci->rh.dev) { 13.1495 + err("unable to allocate root hub"); 13.1496 + goto err_alloc_root_hub; 13.1497 + } 13.1498 + 13.1499 + xhci->state = 0; 13.1500 + 13.1501 + return 0; 13.1502 + 13.1503 +/* 13.1504 + * error exits: 13.1505 + */ 13.1506 +err_start_root_hub: 13.1507 + free_irq(xhci->irq, xhci); 13.1508 + xhci->irq = -1; 13.1509 + 13.1510 +err_alloc_root_hub: 13.1511 + usb_free_bus(xhci->bus); 13.1512 + xhci->bus = NULL; 13.1513 + 13.1514 +err_alloc_bus: 13.1515 + free_xhci(xhci); 13.1516 + 13.1517 +err_alloc_xhci: 13.1518 + return retval; 13.1519 +} 13.1520 + 13.1521 +static void usbif_status_change(usbif_fe_interface_status_changed_t *status) 13.1522 +{ 13.1523 + ctrl_msg_t cmsg; 13.1524 + usbif_fe_interface_connect_t up; 13.1525 + long rc; 13.1526 + usbif_t *usbif; 13.1527 + 13.1528 + switch ( status->status ) 13.1529 + { 13.1530 + case USBIF_INTERFACE_STATUS_DESTROYED: 13.1531 + printk(KERN_WARNING "Unexpected usbif-DESTROYED message in state %d\n", 13.1532 + xhci->state); 13.1533 + break; 13.1534 + 13.1535 + case USBIF_INTERFACE_STATUS_DISCONNECTED: 13.1536 + if ( xhci->state != USBIF_STATE_CLOSED ) 13.1537 + { 13.1538 + printk(KERN_WARNING "Unexpected usbif-DISCONNECTED message" 13.1539 + " in state %d\n", xhci->state); 13.1540 + break; 13.1541 + /* Not bothering to do recovery here for now. Keep things 13.1542 + * simple. */ 13.1543 + } 13.1544 + 13.1545 + /* Move from CLOSED to DISCONNECTED state. */ 13.1546 + xhci->usbif = usbif = (usbif_t *)__get_free_page(GFP_KERNEL); 13.1547 + usbif->req_prod = usbif->resp_prod = 0; 13.1548 + xhci->state = USBIF_STATE_DISCONNECTED; 13.1549 + 13.1550 + /* Construct an interface-CONNECT message for the domain controller. */ 13.1551 + cmsg.type = CMSG_USBIF_FE; 13.1552 + cmsg.subtype = CMSG_USBIF_FE_INTERFACE_CONNECT; 13.1553 + cmsg.length = sizeof(usbif_fe_interface_connect_t); 13.1554 + up.shmem_frame = virt_to_machine(usbif) >> PAGE_SHIFT; 13.1555 + memcpy(cmsg.msg, &up, sizeof(up)); 13.1556 + 13.1557 + /* Tell the controller to bring up the interface. */ 13.1558 + ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); 13.1559 + break; 13.1560 + 13.1561 + case USBIF_INTERFACE_STATUS_CONNECTED: 13.1562 + if ( xhci->state == USBIF_STATE_CLOSED ) 13.1563 + { 13.1564 + printk(KERN_WARNING "Unexpected usbif-CONNECTED message" 13.1565 + " in state %d\n", xhci->state); 13.1566 + break; 13.1567 + } 13.1568 + 13.1569 + xhci->evtchn = status->evtchn; 13.1570 + xhci->irq = bind_evtchn_to_irq(xhci->evtchn); 13.1571 + xhci->bandwidth = status->bandwidth; 13.1572 + xhci->rh.numports = status->num_ports; 13.1573 + 13.1574 + xhci->rh.ports = kmalloc (sizeof(xhci_port_t) * xhci->rh.numports, GFP_KERNEL); 13.1575 + memset(xhci->rh.ports, 0, sizeof(xhci_port_t) * xhci->rh.numports); 13.1576 + 13.1577 + printk("rh.dev @ %p\n", xhci->rh.dev); 13.1578 + 13.1579 + usb_connect(xhci->rh.dev); 13.1580 + 13.1581 + if (usb_new_device(xhci->rh.dev) != 0) { 13.1582 + err("unable to start root hub"); 13.1583 + } 13.1584 + 13.1585 + /* Allocate the appropriate USB bandwidth here... Need to 13.1586 + * somehow know what the total available is thought to be so we 13.1587 + * can calculate the reservation correctly. */ 13.1588 + usb_claim_bandwidth(xhci->rh.dev, xhci->rh.urb, 13.1589 + 1000 - xhci->bandwidth, 0); 13.1590 + 13.1591 + if ( (rc = request_irq(xhci->irq, xhci_interrupt, 13.1592 + SA_SAMPLE_RANDOM, "usbif", xhci)) ) 13.1593 + printk(KERN_ALERT"usbfront request_irq failed (%ld)\n",rc); 13.1594 + 13.1595 + printk(KERN_INFO __FILE__ ": USB XHCI: SHM at %p (0x%lx), EVTCHN %d IRQ %d\n", 13.1596 + xhci->usbif, virt_to_machine(xhci->usbif), xhci->evtchn, xhci->irq); 13.1597 + 13.1598 + xhci->state = USBIF_STATE_CONNECTED; 13.1599 + 13.1600 + break; 13.1601 + 13.1602 + default: 13.1603 + printk(KERN_WARNING "Status change to unknown value %d\n", 13.1604 + status->status); 13.1605 + break; 13.1606 + } 13.1607 +} 13.1608 + 13.1609 + 13.1610 +static void usbif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id) 13.1611 +{ 13.1612 + switch ( msg->subtype ) 13.1613 + { 13.1614 + case CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED: 13.1615 + if ( msg->length != sizeof(usbif_fe_interface_status_changed_t) ) 13.1616 + goto parse_error; 13.1617 + usbif_status_change((usbif_fe_interface_status_changed_t *) 13.1618 + &msg->msg[0]); 13.1619 + break; 13.1620 + 13.1621 + /* New interface...? */ 13.1622 + default: 13.1623 + goto parse_error; 13.1624 + } 13.1625 + 13.1626 + ctrl_if_send_response(msg); 13.1627 + return; 13.1628 + 13.1629 + parse_error: 13.1630 + msg->length = 0; 13.1631 + ctrl_if_send_response(msg); 13.1632 +} 13.1633 + 13.1634 + 13.1635 +static int __init xhci_hcd_init(void) 13.1636 +{ 13.1637 + int retval = -ENOMEM, i; 13.1638 + usbif_fe_interface_status_changed_t st; 13.1639 + control_msg_t cmsg; 13.1640 + 13.1641 + if ( (xen_start_info.flags & SIF_INITDOMAIN) 13.1642 + || (xen_start_info.flags & SIF_USB_BE_DOMAIN) ) 13.1643 + return 0; 13.1644 + 13.1645 + info(DRIVER_DESC " " DRIVER_VERSION); 13.1646 + 13.1647 + if (debug) { 13.1648 + errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL); 13.1649 + if (!errbuf) 13.1650 + goto errbuf_failed; 13.1651 + } 13.1652 + 13.1653 + xhci_up_cachep = kmem_cache_create("xhci_urb_priv", 13.1654 + sizeof(struct urb_priv), 0, 0, NULL, NULL); 13.1655 + if (!xhci_up_cachep) 13.1656 + goto up_failed; 13.1657 + 13.1658 + /* Lazily avoid unloading issues for now. ;-)*/ 13.1659 + MOD_INC_USE_COUNT; 13.1660 + 13.1661 + /* Let the domain controller know we're here. For now we wait until 13.1662 + * connection, as for the block and net drivers. This is only strictly 13.1663 + * necessary if we're going to boot off a USB device. */ 13.1664 + printk(KERN_INFO "Initialising Xen virtual USB hub\n"); 13.1665 + 13.1666 + (void)ctrl_if_register_receiver(CMSG_USBIF_FE, usbif_ctrlif_rx, 13.1667 + CALLBACK_IN_BLOCKING_CONTEXT); 13.1668 + 13.1669 + alloc_xhci(); 13.1670 + 13.1671 + /* Send a driver-UP notification to the domain controller. */ 13.1672 + cmsg.type = CMSG_USBIF_FE; 13.1673 + cmsg.subtype = CMSG_USBIF_FE_DRIVER_STATUS_CHANGED; 13.1674 + cmsg.length = sizeof(usbif_fe_driver_status_changed_t); 13.1675 + st.status = USBIF_DRIVER_STATUS_UP; 13.1676 + memcpy(cmsg.msg, &st, sizeof(st)); 13.1677 + ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); 13.1678 + 13.1679 + /* 13.1680 + * We should read 'nr_interfaces' from response message and wait 13.1681 + * for notifications before proceeding. For now we assume that we 13.1682 + * will be notified of exactly one interface. 13.1683 + */ 13.1684 + for ( i=0; (xhci->state != USBIF_STATE_CONNECTED) && (i < 10*HZ); i++ ) 13.1685 + { 13.1686 + set_current_state(TASK_INTERRUPTIBLE); 13.1687 + schedule_timeout(1); 13.1688 + } 13.1689 + 13.1690 + if (xhci->state != USBIF_STATE_CONNECTED) 13.1691 + printk(KERN_INFO "Timeout connecting USB frontend driver!\n"); 13.1692 + 13.1693 + return 0; 13.1694 + 13.1695 +up_failed: 13.1696 + 13.1697 + if (errbuf) 13.1698 + kfree(errbuf); 13.1699 + 13.1700 +errbuf_failed: 13.1701 + 13.1702 + return retval; 13.1703 +} 13.1704 + 13.1705 +static void __exit xhci_hcd_cleanup(void) 13.1706 +{ 13.1707 + if (kmem_cache_destroy(xhci_up_cachep)) 13.1708 + printk(KERN_INFO "xhci: not all urb_priv's were freed\n"); 13.1709 + 13.1710 +// release_xhci(); do some calls here 13.1711 + 13.1712 + 13.1713 + if (errbuf) 13.1714 + kfree(errbuf); 13.1715 +} 13.1716 + 13.1717 +module_init(xhci_hcd_init); 13.1718 +module_exit(xhci_hcd_cleanup); 13.1719 + 13.1720 +MODULE_AUTHOR(DRIVER_AUTHOR); 13.1721 +MODULE_DESCRIPTION(DRIVER_DESC); 13.1722 +MODULE_LICENSE("GPL"); 13.1723 +
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/xhci.h Wed Jan 19 13:20:15 2005 +0000 14.3 @@ -0,0 +1,210 @@ 14.4 +#ifndef __LINUX_XHCI_H 14.5 +#define __LINUX_XHCI_H 14.6 + 14.7 +#include <linux/list.h> 14.8 +#include <linux/usb.h> 14.9 +#include "../usbif.h" 14.10 +#include <linux/spinlock.h> 14.11 + 14.12 +#define XHCI_NUMFRAMES 1024 /* in the frame list [array] */ 14.13 +#define XHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */ 14.14 +#define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */ 14.15 + 14.16 +/* In the absence of actual hardware state, we maintain the current known state 14.17 + * of the virtual hub ports in this data structure. 14.18 + */ 14.19 +typedef struct 14.20 +{ 14.21 + unsigned int cs :1; /* Connection status. do we really need this /and/ ccs? */ 14.22 + unsigned int cs_chg :1; /* Connection status change. */ 14.23 + unsigned int pe :1; /* Port enable. */ 14.24 + unsigned int pe_chg :1; /* Port enable change. */ 14.25 + unsigned int ccs :1; /* Current connect status. */ 14.26 + unsigned int susp :1; /* Suspended. */ 14.27 + unsigned int lsda :1; /* Low speed device attached. */ 14.28 + unsigned int pr :1; /* Port reset. */ 14.29 + 14.30 + /* Device info? */ 14.31 +} xhci_port_t; 14.32 + 14.33 +struct xhci_frame_list { 14.34 + __u32 frame[XHCI_NUMFRAMES]; 14.35 + 14.36 + void *frame_cpu[XHCI_NUMFRAMES]; 14.37 +}; 14.38 + 14.39 +struct urb_priv; 14.40 + 14.41 +#define xhci_status_bits(ctrl_sts) (ctrl_sts & 0xFE0000) 14.42 +#define xhci_actual_length(ctrl_sts) ((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ 14.43 + 14.44 +#define xhci_maxlen(token) ((token) >> 21) 14.45 +#define xhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */ 14.46 +#define xhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1) 14.47 +#define xhci_endpoint(token) (((token) >> 15) & 0xf) 14.48 +#define xhci_devaddr(token) (((token) >> 8) & 0x7f) 14.49 +#define xhci_devep(token) (((token) >> 8) & 0x7ff) 14.50 +#define xhci_packetid(token) ((token) & TD_TOKEN_PID_MASK) 14.51 +#define xhci_packetout(token) (xhci_packetid(token) != USB_PID_IN) 14.52 +#define xhci_packetin(token) (xhci_packetid(token) == USB_PID_IN) 14.53 + 14.54 +struct virt_root_hub { 14.55 + struct usb_device *dev; 14.56 + int devnum; /* Address of Root Hub endpoint */ 14.57 + struct urb *urb; 14.58 + void *int_addr; 14.59 + int send; 14.60 + int interval; 14.61 + int numports; 14.62 + int c_p_r[8]; 14.63 + struct timer_list rh_int_timer; 14.64 + spinlock_t port_state_lock; 14.65 + xhci_port_t *ports; /* */ 14.66 +}; 14.67 + 14.68 +/* 14.69 + * This describes the full xhci information. 14.70 + * 14.71 + * Note how the "proper" USB information is just 14.72 + * a subset of what the full implementation needs. 14.73 + */ 14.74 +struct xhci { 14.75 + 14.76 +#ifdef CONFIG_PROC_FS 14.77 + /* procfs */ 14.78 + int num; 14.79 + struct proc_dir_entry *proc_entry; 14.80 +#endif 14.81 + 14.82 + int evtchn; /* Interdom channel to backend */ 14.83 + int irq; /* Bound to evtchn */ 14.84 + int state; /* State of this USB interface */ 14.85 + unsigned long bandwidth; 14.86 + int handle; 14.87 + 14.88 + struct usb_bus *bus; 14.89 + 14.90 + spinlock_t frame_list_lock; 14.91 + struct xhci_frame_list *fl; /* P: xhci->frame_list_lock */ 14.92 + int is_suspended; 14.93 + 14.94 + /* Main list of URB's currently controlled by this HC */ 14.95 + spinlock_t urb_list_lock; 14.96 + struct list_head urb_list; /* P: xhci->urb_list_lock */ 14.97 + 14.98 + /* List of asynchronously unlinked URB's */ 14.99 + spinlock_t urb_remove_list_lock; 14.100 + struct list_head urb_remove_list; /* P: xhci->urb_remove_list_lock */ 14.101 + 14.102 + /* List of URB's awaiting completion callback */ 14.103 + spinlock_t complete_list_lock; 14.104 + struct list_head complete_list; /* P: xhci->complete_list_lock */ 14.105 + 14.106 + struct virt_root_hub rh; /* private data of the virtual root hub */ 14.107 + 14.108 + spinlock_t response_lock; 14.109 + 14.110 + usbif_t *usbif; 14.111 + int usb_resp_cons; 14.112 +}; 14.113 + 14.114 +struct urb_priv { 14.115 + struct urb *urb; 14.116 + usbif_iso_t *schedule; 14.117 + struct usb_device *dev; 14.118 + 14.119 + int in_progress : 1; /* QH was queued (not linked in) */ 14.120 + int short_control_packet : 1; /* If we get a short packet during */ 14.121 + /* a control transfer, retrigger */ 14.122 + /* the status phase */ 14.123 + 14.124 + int status; /* Final status */ 14.125 + 14.126 + unsigned long inserttime; /* In jiffies */ 14.127 + 14.128 + struct list_head queue_list; /* P: xhci->frame_list_lock */ 14.129 + struct list_head complete_list; /* P: xhci->complete_list_lock */ 14.130 +}; 14.131 + 14.132 +/* 14.133 + * Locking in xhci.c 14.134 + * 14.135 + * spinlocks are used extensively to protect the many lists and data 14.136 + * structures we have. It's not that pretty, but it's necessary. We 14.137 + * need to be done with all of the locks (except complete_list_lock) when 14.138 + * we call urb->complete. I've tried to make it simple enough so I don't 14.139 + * have to spend hours racking my brain trying to figure out if the 14.140 + * locking is safe. 14.141 + * 14.142 + * Here's the safe locking order to prevent deadlocks: 14.143 + * 14.144 + * #1 xhci->urb_list_lock 14.145 + * #2 urb->lock 14.146 + * #3 xhci->urb_remove_list_lock, xhci->frame_list_lock, 14.147 + * xhci->qh_remove_list_lock 14.148 + * #4 xhci->complete_list_lock 14.149 + * 14.150 + * If you're going to grab 2 or more locks at once, ALWAYS grab the lock 14.151 + * at the lowest level FIRST and NEVER grab locks at the same level at the 14.152 + * same time. 14.153 + * 14.154 + * So, if you need xhci->urb_list_lock, grab it before you grab urb->lock 14.155 + */ 14.156 + 14.157 +/* ------------------------------------------------------------------------- 14.158 + Virtual Root HUB 14.159 + ------------------------------------------------------------------------- */ 14.160 +/* destination of request */ 14.161 +#define RH_DEVICE 0x00 14.162 +#define RH_INTERFACE 0x01 14.163 +#define RH_ENDPOINT 0x02 14.164 +#define RH_OTHER 0x03 14.165 + 14.166 +#define RH_CLASS 0x20 14.167 +#define RH_VENDOR 0x40 14.168 + 14.169 +/* Requests: bRequest << 8 | bmRequestType */ 14.170 +#define RH_GET_STATUS 0x0080 14.171 +#define RH_CLEAR_FEATURE 0x0100 14.172 +#define RH_SET_FEATURE 0x0300 14.173 +#define RH_SET_ADDRESS 0x0500 14.174 +#define RH_GET_DESCRIPTOR 0x0680 14.175 +#define RH_SET_DESCRIPTOR 0x0700 14.176 +#define RH_GET_CONFIGURATION 0x0880 14.177 +#define RH_SET_CONFIGURATION 0x0900 14.178 +#define RH_GET_STATE 0x0280 14.179 +#define RH_GET_INTERFACE 0x0A80 14.180 +#define RH_SET_INTERFACE 0x0B00 14.181 +#define RH_SYNC_FRAME 0x0C80 14.182 +/* Our Vendor Specific Request */ 14.183 +#define RH_SET_EP 0x2000 14.184 + 14.185 +/* Hub port features */ 14.186 +#define RH_PORT_CONNECTION 0x00 14.187 +#define RH_PORT_ENABLE 0x01 14.188 +#define RH_PORT_SUSPEND 0x02 14.189 +#define RH_PORT_OVER_CURRENT 0x03 14.190 +#define RH_PORT_RESET 0x04 14.191 +#define RH_PORT_POWER 0x08 14.192 +#define RH_PORT_LOW_SPEED 0x09 14.193 +#define RH_C_PORT_CONNECTION 0x10 14.194 +#define RH_C_PORT_ENABLE 0x11 14.195 +#define RH_C_PORT_SUSPEND 0x12 14.196 +#define RH_C_PORT_OVER_CURRENT 0x13 14.197 +#define RH_C_PORT_RESET 0x14 14.198 + 14.199 +/* Hub features */ 14.200 +#define RH_C_HUB_LOCAL_POWER 0x00 14.201 +#define RH_C_HUB_OVER_CURRENT 0x01 14.202 +#define RH_DEVICE_REMOTE_WAKEUP 0x00 14.203 +#define RH_ENDPOINT_STALL 0x01 14.204 + 14.205 +/* Our Vendor Specific feature */ 14.206 +#define RH_REMOVE_EP 0x00 14.207 + 14.208 +#define RH_ACK 0x01 14.209 +#define RH_REQ_ERR -1 14.210 +#define RH_NACK 0x00 14.211 + 14.212 +#endif 14.213 +
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/usbif.h Wed Jan 19 13:20:15 2005 +0000 15.3 @@ -0,0 +1,111 @@ 15.4 +/****************************************************************************** 15.5 + * usbif.h 15.6 + * 15.7 + * Unified block-device I/O interface for Xen guest OSes. 15.8 + * 15.9 + * Copyright (c) 2003-2004, Keir Fraser 15.10 + */ 15.11 + 15.12 +#ifndef __SHARED_USBIF_H__ 15.13 +#define __SHARED_USBIF_H__ 15.14 + 15.15 +#define usbif_vdev_t u16 15.16 +#define usbif_sector_t u64 15.17 + 15.18 +#define USBIF_OP_IO 0 15.19 +#define USBIF_OP_PROBE 1 /* Is there a device on this port? */ 15.20 +#define USBIF_OP_RESET 2 /* Reset a virtual USB port. */ 15.21 + 15.22 +/* NB. Ring size must be small enough for sizeof(usbif_ring_t) <= PAGE_SIZE. */ 15.23 +#define USBIF_RING_SIZE 64 15.24 + 15.25 +/* XXX this does not want to be here! it really ought to be dynamic but it can 15.26 + * live here for now */ 15.27 +#define NUM_PORTS 1 15.28 + 15.29 +typedef struct { 15.30 + unsigned long id; /* 0: private guest value, echoed in resp */ 15.31 + u8 operation; /* 4: USBIF_OP_??? */ 15.32 + u8 __pad1; 15.33 + usbif_vdev_t port; /* 6 : guest virtual USB port */ 15.34 + unsigned long devnum :7; /* 8 : Device address, as seen by the guest.*/ 15.35 + unsigned long endpoint :4; /* Device endpoint. */ 15.36 + unsigned long direction :1; /* Pipe direction. */ 15.37 + unsigned long speed :1; /* Pipe speed. */ 15.38 + unsigned long pipe_type :2; /* Pipe type (iso, bulk, int, ctrl) */ 15.39 + unsigned long __pad2 :18; 15.40 + unsigned long transfer_buffer; /* 12: Machine address */ 15.41 + unsigned long length; /* 16: Buffer length */ 15.42 + unsigned long transfer_flags; /* 20: For now just pass Linux transfer 15.43 + * flags - this may change. */ 15.44 + unsigned char setup[8]; /* 22 Embed setup packets directly. */ 15.45 + unsigned long iso_schedule; /* 30 Machine address of transfer sched (iso 15.46 + * only) */ 15.47 + unsigned long num_iso; /* 34 : length of iso schedule */ 15.48 + unsigned long timeout; /* 38: timeout in ms */ 15.49 +} PACKED usbif_request_t; /* 42 */ 15.50 +/* Data we need to pass: 15.51 + * - Transparently handle short packets or complain at us? 15.52 + */ 15.53 + 15.54 +typedef struct { 15.55 + unsigned long id; /* 0: copied from request */ 15.56 + u8 operation; /* 4: copied from request */ 15.57 + u8 data; /* 5: Small chunk of in-band data */ 15.58 + s16 status; /* 6: USBIF_RSP_??? */ 15.59 + unsigned long transfer_mutex; /* Used for cancelling requests atomically. */ 15.60 + unsigned long length; /* 8: How much data we really got */ 15.61 +} PACKED usbif_response_t; 15.62 + 15.63 +#define USBIF_RSP_ERROR -1 /* non-specific 'error' */ 15.64 +#define USBIF_RSP_OKAY 0 /* non-specific 'okay' */ 15.65 + 15.66 +/* 15.67 + * We use a special capitalised type name because it is _essential_ that all 15.68 + * arithmetic on indexes is done on an integer type of the correct size. 15.69 + */ 15.70 +typedef u32 USBIF_RING_IDX; 15.71 + 15.72 +/* 15.73 + * Ring indexes are 'free running'. That is, they are not stored modulo the 15.74 + * size of the ring buffer. The following macro converts a free-running counter 15.75 + * into a value that can directly index a ring-buffer array. 15.76 + */ 15.77 +#define MASK_USBIF_IDX(_i) ((_i)&(USBIF_RING_SIZE-1)) 15.78 + 15.79 +typedef struct { 15.80 + USBIF_RING_IDX req_prod; /* 0: Request producer. Updated by front-end. */ 15.81 + USBIF_RING_IDX resp_prod; /* 4: Response producer. Updated by back-end. */ 15.82 + 15.83 + union { /* 8 */ 15.84 + usbif_request_t req; 15.85 + usbif_response_t resp; 15.86 + } PACKED ring[USBIF_RING_SIZE]; 15.87 +} PACKED usbif_t; 15.88 + 15.89 + 15.90 + 15.91 +/* 15.92 + * USBIF_OP_PROBE: 15.93 + * The request format for a probe request is constrained as follows: 15.94 + * @operation == USBIF_OP_PROBE 15.95 + * @nr_segments == size of probe buffer in pages 15.96 + * @device == unused (zero) 15.97 + * @id == any value (echoed in response message) 15.98 + * @sector_num == unused (zero) 15.99 + * @frame_and_sects == list of page-sized buffers. 15.100 + * (i.e., @first_sect == 0, @last_sect == 7). 15.101 + * 15.102 + * The response is a list of vdisk_t elements copied into the out-of-band 15.103 + * probe buffer. On success the response status field contains the number 15.104 + * of vdisk_t elements. 15.105 + */ 15.106 + 15.107 +typedef struct { 15.108 + unsigned long length; /* IN = expected, OUT = actual */ 15.109 + unsigned long buffer_offset; /* IN offset in buffer specified in main 15.110 + packet */ 15.111 + unsigned long status; /* OUT Status for this packet. */ 15.112 +} usbif_iso_t; 15.113 + 15.114 +#endif /* __SHARED_USBIF_H__ */
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/linux-2.4.28-xen-sparse/drivers/usb/hcd.c Wed Jan 19 13:20:15 2005 +0000 16.3 @@ -0,0 +1,1511 @@ 16.4 +/* 16.5 + * Copyright (c) 2001-2002 by David Brownell 16.6 + * 16.7 + * This program is free software; you can redistribute it and/or modify it 16.8 + * under the terms of the GNU General Public License as published by the 16.9 + * Free Software Foundation; either version 2 of the License, or (at your 16.10 + * option) any later version. 16.11 + * 16.12 + * This program is distributed in the hope that it will be useful, but 16.13 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16.14 + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16.15 + * for more details. 16.16 + * 16.17 + * You should have received a copy of the GNU General Public License 16.18 + * along with this program; if not, write to the Free Software Foundation, 16.19 + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 16.20 + */ 16.21 + 16.22 +#include <linux/config.h> 16.23 +#include <linux/module.h> 16.24 +#include <linux/pci.h> 16.25 +#include <linux/kernel.h> 16.26 +#include <linux/delay.h> 16.27 +#include <linux/ioport.h> 16.28 +#include <linux/sched.h> 16.29 +#include <linux/slab.h> 16.30 +#include <linux/smp_lock.h> 16.31 +#include <linux/errno.h> 16.32 +#include <linux/kmod.h> 16.33 +#include <linux/init.h> 16.34 +#include <linux/timer.h> 16.35 +#include <linux/list.h> 16.36 +#include <linux/interrupt.h> 16.37 +#include <linux/completion.h> 16.38 +#include <linux/uts.h> /* for UTS_SYSNAME */ 16.39 + 16.40 + 16.41 +#ifdef CONFIG_USB_DEBUG 16.42 + #define DEBUG 16.43 +#else 16.44 + #undef DEBUG 16.45 +#endif 16.46 + 16.47 +#include <linux/usb.h> 16.48 +#include "hcd.h" 16.49 + 16.50 +#include <asm/io.h> 16.51 +#include <asm/irq.h> 16.52 +#include <asm/system.h> 16.53 +#include <asm/unaligned.h> 16.54 + 16.55 + 16.56 +/*-------------------------------------------------------------------------*/ 16.57 + 16.58 +/* 16.59 + * USB Host Controller Driver framework 16.60 + * 16.61 + * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing 16.62 + * HCD-specific behaviors/bugs. Think of it as the "upper level" of 16.63 + * some drivers, where the "lower level" is hardware-specific. 16.64 + * 16.65 + * This does error checks, tracks devices and urbs, and delegates to a 16.66 + * "hc_driver" only for code (and data) that really needs to know about 16.67 + * hardware differences. That includes root hub registers, i/o queues, 16.68 + * and so on ... but as little else as possible. 16.69 + * 16.70 + * Shared code includes most of the "root hub" code (these are emulated, 16.71 + * though each HC's hardware works differently) and PCI glue, plus request 16.72 + * tracking overhead. The HCD code should only block on spinlocks or on 16.73 + * hardware handshaking; blocking on software events (such as other kernel 16.74 + * threads releasing resources, or completing actions) is all generic. 16.75 + * 16.76 + * Happens the USB 2.0 spec says this would be invisible inside the "USBD", 16.77 + * and includes mostly a "HCDI" (HCD Interface) along with some APIs used 16.78 + * only by the hub driver ... and that neither should be seen or used by 16.79 + * usb client device drivers. 16.80 + * 16.81 + * Contributors of ideas or unattributed patches include: David Brownell, 16.82 + * Roman Weissgaerber, Rory Bolt, ... 16.83 + * 16.84 + * HISTORY: 16.85 + * 2002-sept Merge some 2.5 updates so we can share hardware level HCD 16.86 + * code between the 2.4.20+ and 2.5 trees. 16.87 + * 2002-feb merge to 2.4.19 16.88 + * 2001-12-12 Initial patch version for Linux 2.5.1 kernel. 16.89 + */ 16.90 + 16.91 +/*-------------------------------------------------------------------------*/ 16.92 + 16.93 +/* host controllers we manage */ 16.94 +static LIST_HEAD (hcd_list); 16.95 + 16.96 +/* used when updating list of hcds */ 16.97 +static DECLARE_MUTEX (hcd_list_lock); 16.98 + 16.99 +/* used when updating hcd data */ 16.100 +static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; 16.101 + 16.102 +static struct usb_operations hcd_operations; 16.103 + 16.104 +/*-------------------------------------------------------------------------*/ 16.105 + 16.106 +/* 16.107 + * Sharable chunks of root hub code. 16.108 + */ 16.109 + 16.110 +/*-------------------------------------------------------------------------*/ 16.111 + 16.112 +#define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff) 16.113 +#define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff) 16.114 + 16.115 +/* usb 2.0 root hub device descriptor */ 16.116 +static const u8 usb2_rh_dev_descriptor [18] = { 16.117 + 0x12, /* __u8 bLength; */ 16.118 + 0x01, /* __u8 bDescriptorType; Device */ 16.119 + 0x00, 0x02, /* __u16 bcdUSB; v2.0 */ 16.120 + 16.121 + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 16.122 + 0x00, /* __u8 bDeviceSubClass; */ 16.123 + 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ 16.124 + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ 16.125 + 16.126 + 0x00, 0x00, /* __u16 idVendor; */ 16.127 + 0x00, 0x00, /* __u16 idProduct; */ 16.128 + KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ 16.129 + 16.130 + 0x03, /* __u8 iManufacturer; */ 16.131 + 0x02, /* __u8 iProduct; */ 16.132 + 0x01, /* __u8 iSerialNumber; */ 16.133 + 0x01 /* __u8 bNumConfigurations; */ 16.134 +}; 16.135 + 16.136 +/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */ 16.137 + 16.138 +/* usb 1.1 root hub device descriptor */ 16.139 +static const u8 usb11_rh_dev_descriptor [18] = { 16.140 + 0x12, /* __u8 bLength; */ 16.141 + 0x01, /* __u8 bDescriptorType; Device */ 16.142 + 0x10, 0x01, /* __u16 bcdUSB; v1.1 */ 16.143 + 16.144 + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 16.145 + 0x00, /* __u8 bDeviceSubClass; */ 16.146 + 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ 16.147 + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ 16.148 + 16.149 + 0x00, 0x00, /* __u16 idVendor; */ 16.150 + 0x00, 0x00, /* __u16 idProduct; */ 16.151 + KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ 16.152 + 16.153 + 0x03, /* __u8 iManufacturer; */ 16.154 + 0x02, /* __u8 iProduct; */ 16.155 + 0x01, /* __u8 iSerialNumber; */ 16.156 + 0x01 /* __u8 bNumConfigurations; */ 16.157 +}; 16.158 + 16.159 + 16.160 +/*-------------------------------------------------------------------------*/ 16.161 + 16.162 +/* Configuration descriptors for our root hubs */ 16.163 + 16.164 +static const u8 fs_rh_config_descriptor [] = { 16.165 + 16.166 + /* one configuration */ 16.167 + 0x09, /* __u8 bLength; */ 16.168 + 0x02, /* __u8 bDescriptorType; Configuration */ 16.169 + 0x19, 0x00, /* __u16 wTotalLength; */ 16.170 + 0x01, /* __u8 bNumInterfaces; (1) */ 16.171 + 0x01, /* __u8 bConfigurationValue; */ 16.172 + 0x00, /* __u8 iConfiguration; */ 16.173 + 0x40, /* __u8 bmAttributes; 16.174 + Bit 7: Bus-powered, 16.175 + 6: Self-powered, 16.176 + 5 Remote-wakwup, 16.177 + 4..0: resvd */ 16.178 + 0x00, /* __u8 MaxPower; */ 16.179 + 16.180 + /* USB 1.1: 16.181 + * USB 2.0, single TT organization (mandatory): 16.182 + * one interface, protocol 0 16.183 + * 16.184 + * USB 2.0, multiple TT organization (optional): 16.185 + * two interfaces, protocols 1 (like single TT) 16.186 + * and 2 (multiple TT mode) ... config is 16.187 + * sometimes settable 16.188 + * NOT IMPLEMENTED 16.189 + */ 16.190 + 16.191 + /* one interface */ 16.192 + 0x09, /* __u8 if_bLength; */ 16.193 + 0x04, /* __u8 if_bDescriptorType; Interface */ 16.194 + 0x00, /* __u8 if_bInterfaceNumber; */ 16.195 + 0x00, /* __u8 if_bAlternateSetting; */ 16.196 + 0x01, /* __u8 if_bNumEndpoints; */ 16.197 + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ 16.198 + 0x00, /* __u8 if_bInterfaceSubClass; */ 16.199 + 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 16.200 + 0x00, /* __u8 if_iInterface; */ 16.201 + 16.202 + /* one endpoint (status change endpoint) */ 16.203 + 0x07, /* __u8 ep_bLength; */ 16.204 + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 16.205 + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 16.206 + 0x03, /* __u8 ep_bmAttributes; Interrupt */ 16.207 + 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ 16.208 + 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */ 16.209 +}; 16.210 + 16.211 +static const u8 hs_rh_config_descriptor [] = { 16.212 + 16.213 + /* one configuration */ 16.214 + 0x09, /* __u8 bLength; */ 16.215 + 0x02, /* __u8 bDescriptorType; Configuration */ 16.216 + 0x19, 0x00, /* __u16 wTotalLength; */ 16.217 + 0x01, /* __u8 bNumInterfaces; (1) */ 16.218 + 0x01, /* __u8 bConfigurationValue; */ 16.219 + 0x00, /* __u8 iConfiguration; */ 16.220 + 0x40, /* __u8 bmAttributes; 16.221 + Bit 7: Bus-powered, 16.222 + 6: Self-powered, 16.223 + 5 Remote-wakwup, 16.224 + 4..0: resvd */ 16.225 + 0x00, /* __u8 MaxPower; */ 16.226 + 16.227 + /* USB 1.1: 16.228 + * USB 2.0, single TT organization (mandatory): 16.229 + * one interface, protocol 0 16.230 + * 16.231 + * USB 2.0, multiple TT organization (optional): 16.232 + * two interfaces, protocols 1 (like single TT) 16.233 + * and 2 (multiple TT mode) ... config is 16.234 + * sometimes settable 16.235 + * NOT IMPLEMENTED 16.236 + */ 16.237 + 16.238 + /* one interface */ 16.239 + 0x09, /* __u8 if_bLength; */ 16.240 + 0x04, /* __u8 if_bDescriptorType; Interface */ 16.241 + 0x00, /* __u8 if_bInterfaceNumber; */ 16.242 + 0x00, /* __u8 if_bAlternateSetting; */ 16.243 + 0x01, /* __u8 if_bNumEndpoints; */ 16.244 + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ 16.245 + 0x00, /* __u8 if_bInterfaceSubClass; */ 16.246 + 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 16.247 + 0x00, /* __u8 if_iInterface; */ 16.248 + 16.249 + /* one endpoint (status change endpoint) */ 16.250 + 0x07, /* __u8 ep_bLength; */ 16.251 + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 16.252 + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 16.253 + 0x03, /* __u8 ep_bmAttributes; Interrupt */ 16.254 + 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ 16.255 + 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */ 16.256 +}; 16.257 + 16.258 +/*-------------------------------------------------------------------------*/ 16.259 + 16.260 +/* 16.261 + * helper routine for returning string descriptors in UTF-16LE 16.262 + * input can actually be ISO-8859-1; ASCII is its 7-bit subset 16.263 + */ 16.264 +static int ascii2utf (char *s, u8 *utf, int utfmax) 16.265 +{ 16.266 + int retval; 16.267 + 16.268 + for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) { 16.269 + *utf++ = *s++; 16.270 + *utf++ = 0; 16.271 + } 16.272 + return retval; 16.273 +} 16.274 + 16.275 +/* 16.276 + * rh_string - provides manufacturer, product and serial strings for root hub 16.277 + * @id: the string ID number (1: serial number, 2: product, 3: vendor) 16.278 + * @pci_desc: PCI device descriptor for the relevant HC 16.279 + * @type: string describing our driver 16.280 + * @data: return packet in UTF-16 LE 16.281 + * @len: length of the return packet 16.282 + * 16.283 + * Produces either a manufacturer, product or serial number string for the 16.284 + * virtual root hub device. 16.285 + */ 16.286 +static int rh_string ( 16.287 + int id, 16.288 + struct usb_hcd *hcd, 16.289 + u8 *data, 16.290 + int len 16.291 +) { 16.292 + char buf [100]; 16.293 + 16.294 + // language ids 16.295 + if (id == 0) { 16.296 + *data++ = 4; *data++ = 3; /* 4 bytes string data */ 16.297 + *data++ = 0; *data++ = 0; /* some language id */ 16.298 + return 4; 16.299 + 16.300 + // serial number 16.301 + } else if (id == 1) { 16.302 + strcpy (buf, hcd->bus->bus_name); 16.303 + 16.304 + // product description 16.305 + } else if (id == 2) { 16.306 + strcpy (buf, hcd->product_desc); 16.307 + 16.308 + // id 3 == vendor description 16.309 + } else if (id == 3) { 16.310 + sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, 16.311 + hcd->description); 16.312 + 16.313 + // unsupported IDs --> "protocol stall" 16.314 + } else 16.315 + return 0; 16.316 + 16.317 + data [0] = 2 * (strlen (buf) + 1); 16.318 + data [1] = 3; /* type == string */ 16.319 + return 2 + ascii2utf (buf, data + 2, len - 2); 16.320 +} 16.321 + 16.322 + 16.323 +/* Root hub control transfers execute synchronously */ 16.324 +static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) 16.325 +{ 16.326 + struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet; 16.327 + u16 typeReq, wValue, wIndex, wLength; 16.328 + const u8 *bufp = 0; 16.329 + u8 *ubuf = urb->transfer_buffer; 16.330 + int len = 0; 16.331 + 16.332 + typeReq = (cmd->bRequestType << 8) | cmd->bRequest; 16.333 + wValue = le16_to_cpu (cmd->wValue); 16.334 + wIndex = le16_to_cpu (cmd->wIndex); 16.335 + wLength = le16_to_cpu (cmd->wLength); 16.336 + 16.337 + if (wLength > urb->transfer_buffer_length) 16.338 + goto error; 16.339 + 16.340 + /* set up for success */ 16.341 + urb->status = 0; 16.342 + urb->actual_length = wLength; 16.343 + switch (typeReq) { 16.344 + 16.345 + /* DEVICE REQUESTS */ 16.346 + 16.347 + case DeviceRequest | USB_REQ_GET_STATUS: 16.348 + // DEVICE_REMOTE_WAKEUP 16.349 + ubuf [0] = 1; // selfpowered 16.350 + ubuf [1] = 0; 16.351 + /* FALLTHROUGH */ 16.352 + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: 16.353 + case DeviceOutRequest | USB_REQ_SET_FEATURE: 16.354 + dbg ("no device features yet yet"); 16.355 + break; 16.356 + case DeviceRequest | USB_REQ_GET_CONFIGURATION: 16.357 + ubuf [0] = 1; 16.358 + /* FALLTHROUGH */ 16.359 + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: 16.360 + break; 16.361 + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: 16.362 + switch (wValue & 0xff00) { 16.363 + case USB_DT_DEVICE << 8: 16.364 + if (hcd->driver->flags & HCD_USB2) 16.365 + bufp = usb2_rh_dev_descriptor; 16.366 + else if (hcd->driver->flags & HCD_USB11) 16.367 + bufp = usb11_rh_dev_descriptor; 16.368 + else 16.369 + goto error; 16.370 + len = 18; 16.371 + break; 16.372 + case USB_DT_CONFIG << 8: 16.373 + if (hcd->driver->flags & HCD_USB2) { 16.374 + bufp = hs_rh_config_descriptor; 16.375 + len = sizeof hs_rh_config_descriptor; 16.376 + } else { 16.377 + bufp = fs_rh_config_descriptor; 16.378 + len = sizeof fs_rh_config_descriptor; 16.379 + } 16.380 + break; 16.381 + case USB_DT_STRING << 8: 16.382 + urb->actual_length = rh_string ( 16.383 + wValue & 0xff, hcd, 16.384 + ubuf, wLength); 16.385 + break; 16.386 + default: 16.387 + goto error; 16.388 + } 16.389 + break; 16.390 + case DeviceRequest | USB_REQ_GET_INTERFACE: 16.391 + ubuf [0] = 0; 16.392 + /* FALLTHROUGH */ 16.393 + case DeviceOutRequest | USB_REQ_SET_INTERFACE: 16.394 + break; 16.395 + case DeviceOutRequest | USB_REQ_SET_ADDRESS: 16.396 + // wValue == urb->dev->devaddr 16.397 + dbg ("%s root hub device address %d", 16.398 + hcd->bus->bus_name, wValue); 16.399 + break; 16.400 + 16.401 + /* INTERFACE REQUESTS (no defined feature/status flags) */ 16.402 + 16.403 + /* ENDPOINT REQUESTS */ 16.404 + 16.405 + case EndpointRequest | USB_REQ_GET_STATUS: 16.406 + // ENDPOINT_HALT flag 16.407 + ubuf [0] = 0; 16.408 + ubuf [1] = 0; 16.409 + /* FALLTHROUGH */ 16.410 + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: 16.411 + case EndpointOutRequest | USB_REQ_SET_FEATURE: 16.412 + dbg ("no endpoint features yet"); 16.413 + break; 16.414 + 16.415 + /* CLASS REQUESTS (and errors) */ 16.416 + 16.417 + default: 16.418 + /* non-generic request */ 16.419 + urb->status = hcd->driver->hub_control (hcd, 16.420 + typeReq, wValue, wIndex, 16.421 + ubuf, wLength); 16.422 + break; 16.423 +error: 16.424 + /* "protocol stall" on error */ 16.425 + urb->status = -EPIPE; 16.426 + dbg ("unsupported hub control message (maxchild %d)", 16.427 + urb->dev->maxchild); 16.428 + } 16.429 + if (urb->status) { 16.430 + urb->actual_length = 0; 16.431 + dbg ("CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d", 16.432 + typeReq, wValue, wIndex, wLength, urb->status); 16.433 + } 16.434 + if (bufp) { 16.435 + if (urb->transfer_buffer_length < len) 16.436 + len = urb->transfer_buffer_length; 16.437 + urb->actual_length = len; 16.438 + // always USB_DIR_IN, toward host 16.439 + memcpy (ubuf, bufp, len); 16.440 + } 16.441 + 16.442 + /* any errors get returned through the urb completion */ 16.443 + usb_hcd_giveback_urb (hcd, urb, 0); 16.444 + return 0; 16.445 +} 16.446 + 16.447 +/*-------------------------------------------------------------------------*/ 16.448 + 16.449 +/* 16.450 + * Root Hub interrupt transfers are synthesized with a timer. 16.451 + * Completions are called in_interrupt() but not in_irq(). 16.452 + */ 16.453 + 16.454 +static void rh_report_status (unsigned long ptr); 16.455 + 16.456 +static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) 16.457 +{ 16.458 + int len = 1 + (urb->dev->maxchild / 8); 16.459 + 16.460 + /* rh_timer protected by hcd_data_lock */ 16.461 + if (timer_pending (&hcd->rh_timer) 16.462 + || urb->status != -EINPROGRESS 16.463 + || !HCD_IS_RUNNING (hcd->state) 16.464 + || urb->transfer_buffer_length < len) { 16.465 + dbg ("not queuing status urb, stat %d", urb->status); 16.466 + return -EINVAL; 16.467 + } 16.468 + 16.469 + urb->hcpriv = hcd; /* nonzero to indicate it's queued */ 16.470 + init_timer (&hcd->rh_timer); 16.471 + hcd->rh_timer.function = rh_report_status; 16.472 + hcd->rh_timer.data = (unsigned long) urb; 16.473 + /* USB 2.0 spec says 256msec; this is close enough */ 16.474 + hcd->rh_timer.expires = jiffies + HZ/4; 16.475 + add_timer (&hcd->rh_timer); 16.476 + return 0; 16.477 +} 16.478 + 16.479 +/* timer callback */ 16.480 + 16.481 +static void rh_report_status (unsigned long ptr) 16.482 +{ 16.483 + struct urb *urb; 16.484 + struct usb_hcd *hcd; 16.485 + int length; 16.486 + unsigned long flags; 16.487 + 16.488 + urb = (struct urb *) ptr; 16.489 + spin_lock_irqsave (&urb->lock, flags); 16.490 + if (!urb->dev) { 16.491 + spin_unlock_irqrestore (&urb->lock, flags); 16.492 + return; 16.493 + } 16.494 + 16.495 + hcd = urb->dev->bus->hcpriv; 16.496 + if (urb->status == -EINPROGRESS) { 16.497 + if (HCD_IS_RUNNING (hcd->state)) { 16.498 + length = hcd->driver->hub_status_data (hcd, 16.499 + urb->transfer_buffer); 16.500 + spin_unlock_irqrestore (&urb->lock, flags); 16.501 + if (length > 0) { 16.502 + urb->actual_length = length; 16.503 + urb->status = 0; 16.504 + urb->complete (urb); 16.505 + } 16.506 + spin_lock_irqsave (&hcd_data_lock, flags); 16.507 + urb->status = -EINPROGRESS; 16.508 + if (HCD_IS_RUNNING (hcd->state) 16.509 + && rh_status_urb (hcd, urb) != 0) { 16.510 + /* another driver snuck in? */ 16.511 + dbg ("%s, can't resubmit roothub status urb?", 16.512 + hcd->bus->bus_name); 16.513 + spin_unlock_irqrestore (&hcd_data_lock, flags); 16.514 + BUG (); 16.515 + } 16.516 + spin_unlock_irqrestore (&hcd_data_lock, flags); 16.517 + } else 16.518 + spin_unlock_irqrestore (&urb->lock, flags); 16.519 + } else { 16.520 + /* this urb's been unlinked */ 16.521 + urb->hcpriv = 0; 16.522 + spin_unlock_irqrestore (&urb->lock, flags); 16.523 + 16.524 + usb_hcd_giveback_urb (hcd, urb, 0); 16.525 + } 16.526 +} 16.527 + 16.528 +/*-------------------------------------------------------------------------*/ 16.529 + 16.530 +static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) 16.531 +{ 16.532 + if (usb_pipeint (urb->pipe)) { 16.533 + int retval; 16.534 + unsigned long flags; 16.535 + 16.536 + spin_lock_irqsave (&hcd_data_lock, flags); 16.537 + retval = rh_status_urb (hcd, urb); 16.538 + spin_unlock_irqrestore (&hcd_data_lock, flags); 16.539 + return retval; 16.540 + } 16.541 + if (usb_pipecontrol (urb->pipe)) 16.542 + return rh_call_control (hcd, urb); 16.543 + else 16.544 + return -EINVAL; 16.545 +} 16.546 + 16.547 +/*-------------------------------------------------------------------------*/ 16.548 + 16.549 +static void rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb) 16.550 +{ 16.551 + unsigned long flags; 16.552 + 16.553 + spin_lock_irqsave (&hcd_data_lock, flags); 16.554 + del_timer_sync (&hcd->rh_timer); 16.555 + hcd->rh_timer.data = 0; 16.556 + spin_unlock_irqrestore (&hcd_data_lock, flags); 16.557 + 16.558 + /* we rely on RH callback code not unlinking its URB! */ 16.559 + usb_hcd_giveback_urb (hcd, urb, 0); 16.560 +} 16.561 + 16.562 +/*-------------------------------------------------------------------------*/ 16.563 + 16.564 +#ifdef CONFIG_PCI 16.565 + 16.566 +/* PCI-based HCs are normal, but custom bus glue should be ok */ 16.567 + 16.568 +static void hcd_irq (int irq, void *__hcd, struct pt_regs *r); 16.569 +static void hc_died (struct usb_hcd *hcd); 16.570 + 16.571 +/*-------------------------------------------------------------------------*/ 16.572 + 16.573 +/* configure so an HC device and id are always provided */ 16.574 +/* always called with process context; sleeping is OK */ 16.575 + 16.576 +/** 16.577 + * usb_hcd_pci_probe - initialize PCI-based HCDs 16.578 + * @dev: USB Host Controller being probed 16.579 + * @id: pci hotplug id connecting controller to HCD framework 16.580 + * Context: !in_interrupt() 16.581 + * 16.582 + * Allocates basic PCI resources for this USB host controller, and 16.583 + * then invokes the start() method for the HCD associated with it 16.584 + * through the hotplug entry's driver_data. 16.585 + * 16.586 + * Store this function in the HCD's struct pci_driver as probe(). 16.587 + */ 16.588 +int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) 16.589 +{ 16.590 + struct hc_driver *driver; 16.591 + unsigned long resource, len; 16.592 + void *base; 16.593 + struct usb_bus *bus; 16.594 + struct usb_hcd *hcd; 16.595 + int retval, region; 16.596 + char buf [8], *bufp = buf; 16.597 + 16.598 + if (!id || !(driver = (struct hc_driver *) id->driver_data)) 16.599 + return -EINVAL; 16.600 + 16.601 + if (pci_enable_device (dev) < 0) 16.602 + return -ENODEV; 16.603 + 16.604 + if (!dev->irq) { 16.605 + err ("Found HC with no IRQ. Check BIOS/PCI %s setup!", 16.606 + dev->slot_name); 16.607 + return -ENODEV; 16.608 + } 16.609 + 16.610 + if (driver->flags & HCD_MEMORY) { // EHCI, OHCI 16.611 + region = 0; 16.612 + resource = pci_resource_start (dev, 0); 16.613 + len = pci_resource_len (dev, 0); 16.614 + if (!request_mem_region (resource, len, driver->description)) { 16.615 + dbg ("controller already in use"); 16.616 + return -EBUSY; 16.617 + } 16.618 + base = ioremap_nocache (resource, len); 16.619 + if (base == NULL) { 16.620 + dbg ("error mapping memory"); 16.621 + retval = -EFAULT; 16.622 +clean_1: 16.623 + release_mem_region (resource, len); 16.624 + err ("init %s fail, %d", dev->slot_name, retval); 16.625 + return retval; 16.626 + } 16.627 + 16.628 + } else { // UHCI 16.629 + resource = len = 0; 16.630 + for (region = 0; region < PCI_ROM_RESOURCE; region++) { 16.631 + if (!(pci_resource_flags (dev, region) & IORESOURCE_IO)) 16.632 + continue; 16.633 + 16.634 + resource = pci_resource_start (dev, region); 16.635 + len = pci_resource_len (dev, region); 16.636 + if (request_region (resource, len, 16.637 + driver->description)) 16.638 + break; 16.639 + } 16.640 + if (region == PCI_ROM_RESOURCE) { 16.641 + dbg ("no i/o regions available"); 16.642 + return -EBUSY; 16.643 + } 16.644 + base = (void *) resource; 16.645 + } 16.646 + 16.647 + // driver->start(), later on, will transfer device from 16.648 + // control by SMM/BIOS to control by Linux (if needed) 16.649 + 16.650 + pci_set_master (dev); 16.651 + hcd = driver->hcd_alloc (); 16.652 + if (hcd == NULL){ 16.653 + dbg ("hcd alloc fail"); 16.654 + retval = -ENOMEM; 16.655 +clean_2: 16.656 + if (driver->flags & HCD_MEMORY) { 16.657 + iounmap (base); 16.658 + goto clean_1; 16.659 + } else { 16.660 + release_region (resource, len); 16.661 + err ("init %s fail, %d", dev->slot_name, retval); 16.662 + return retval; 16.663 + } 16.664 + } 16.665 + pci_set_drvdata(dev, hcd); 16.666 + hcd->driver = driver; 16.667 + hcd->description = driver->description; 16.668 + hcd->pdev = dev; 16.669 + printk (KERN_INFO "%s %s: %s\n", 16.670 + hcd->description, dev->slot_name, dev->name); 16.671 + 16.672 +#ifndef __sparc__ 16.673 + sprintf (buf, "%d", dev->irq); 16.674 +#else 16.675 + bufp = __irq_itoa(dev->irq); 16.676 +#endif 16.677 + if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd) 16.678 + != 0) { 16.679 + err ("request interrupt %s failed", bufp); 16.680 + retval = -EBUSY; 16.681 +clean_3: 16.682 + driver->hcd_free (hcd); 16.683 + goto clean_2; 16.684 + } 16.685 + hcd->irq = dev->irq; 16.686 + 16.687 + hcd->regs = base; 16.688 + hcd->region = region; 16.689 + printk (KERN_INFO "%s %s: irq %s, %s %p\n", 16.690 + hcd->description, dev->slot_name, bufp, 16.691 + (driver->flags & HCD_MEMORY) ? "pci mem" : "io base", 16.692 + base); 16.693 + 16.694 +// FIXME simpler: make "bus" be that data, not pointer to it. 16.695 +// (fixed in 2.5) 16.696 + bus = usb_alloc_bus (&hcd_operations); 16.697 + if (bus == NULL) { 16.698 + dbg ("usb_alloc_bus fail"); 16.699 + retval = -ENOMEM; 16.700 + free_irq (dev->irq, hcd); 16.701 + goto clean_3; 16.702 + } 16.703 + hcd->bus = bus; 16.704 + bus->bus_name = dev->slot_name; 16.705 + hcd->product_desc = dev->name; 16.706 + bus->hcpriv = (void *) hcd; 16.707 + 16.708 + INIT_LIST_HEAD (&hcd->dev_list); 16.709 + INIT_LIST_HEAD (&hcd->hcd_list); 16.710 + 16.711 + down (&hcd_list_lock); 16.712 + list_add (&hcd->hcd_list, &hcd_list); 16.713 + up (&hcd_list_lock); 16.714 + 16.715 + usb_register_bus (bus); 16.716 + 16.717 + if ((retval = driver->start (hcd)) < 0) 16.718 + usb_hcd_pci_remove (dev); 16.719 + 16.720 + return retval; 16.721 +} 16.722 +EXPORT_SYMBOL (usb_hcd_pci_probe); 16.723 + 16.724 + 16.725 +/* may be called without controller electrically present */ 16.726 +/* may be called with controller, bus, and devices active */ 16.727 + 16.728 +/** 16.729 + * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs 16.730 + * @dev: USB Host Controller being removed 16.731 + * Context: !in_interrupt() 16.732 + * 16.733 + * Reverses the effect of usb_hcd_pci_probe(), first invoking 16.734 + * the HCD's stop() method. It is always called from a thread 16.735 + * context, normally "rmmod", "apmd", or something similar. 16.736 + * 16.737 + * Store this function in the HCD's struct pci_driver as remove(). 16.738 + */ 16.739 +void usb_hcd_pci_remove (struct pci_dev *dev) 16.740 +{ 16.741 + struct usb_hcd *hcd; 16.742 + struct usb_device *hub; 16.743 + 16.744 + hcd = pci_get_drvdata(dev); 16.745 + if (!hcd) 16.746 + return; 16.747 + printk (KERN_INFO "%s %s: remove state %x\n", 16.748 + hcd->description, dev->slot_name, hcd->state); 16.749 + 16.750 + if (in_interrupt ()) BUG (); 16.751 + 16.752 + hub = hcd->bus->root_hub; 16.753 + hcd->state = USB_STATE_QUIESCING; 16.754 + 16.755 + dbg ("%s: roothub graceful disconnect", hcd->bus->bus_name); 16.756 + usb_disconnect (&hub); 16.757 + // usb_disconnect (&hcd->bus->root_hub); 16.758 + 16.759 + hcd->driver->stop (hcd); 16.760 + hcd->state = USB_STATE_HALT; 16.761 + 16.762 + free_irq (hcd->irq, hcd); 16.763 + if (hcd->driver->flags & HCD_MEMORY) { 16.764 + iounmap (hcd->regs); 16.765 + release_mem_region (pci_resource_start (dev, 0), 16.766 + pci_resource_len (dev, 0)); 16.767 + } else { 16.768 + release_region (pci_resource_start (dev, hcd->region), 16.769 + pci_resource_len (dev, hcd->region)); 16.770 + } 16.771 + 16.772 + down (&hcd_list_lock); 16.773 + list_del (&hcd->hcd_list); 16.774 + up (&hcd_list_lock); 16.775 + 16.776 + usb_deregister_bus (hcd->bus); 16.777 + usb_free_bus (hcd->bus); 16.778 + hcd->bus = NULL; 16.779 + 16.780 + hcd->driver->hcd_free (hcd); 16.781 +} 16.782 +EXPORT_SYMBOL (usb_hcd_pci_remove); 16.783 + 16.784 + 16.785 +#ifdef CONFIG_PM 16.786 + 16.787 +/* 16.788 + * Some "sleep" power levels imply updating struct usb_driver 16.789 + * to include a callback asking hcds to do their bit by checking 16.790 + * if all the drivers can suspend. Gets involved with remote wakeup. 16.791 + * 16.792 + * If there are pending urbs, then HCs will need to access memory, 16.793 + * causing extra power drain. New sleep()/wakeup() PM calls might 16.794 + * be needed, beyond PCI suspend()/resume(). The root hub timer 16.795 + * still be accessing memory though ... 16.796 + * 16.797 + * FIXME: USB should have some power budgeting support working with 16.798 + * all kinds of hubs. 16.799 + * 16.800 + * FIXME: This assumes only D0->D3 suspend and D3->D0 resume. 16.801 + * D1 and D2 states should do something, yes? 16.802 + * 16.803 + * FIXME: Should provide generic enable_wake(), calling pci_enable_wake() 16.804 + * for all supported states, so that USB remote wakeup can work for any 16.805 + * devices that support it (and are connected via powered hubs). 16.806 + * 16.807 + * FIXME: resume doesn't seem to work right any more... 16.808 + */ 16.809 + 16.810 + 16.811 +// 2.4 kernels have issued concurrent resumes (w/APM) 16.812 +// we defend against that error; PCI doesn't yet. 16.813 + 16.814 +/** 16.815 + * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD 16.816 + * @dev: USB Host Controller being suspended 16.817 + * 16.818 + * Store this function in the HCD's struct pci_driver as suspend(). 16.819 + */ 16.820 +int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) 16.821 +{ 16.822 + struct usb_hcd *hcd; 16.823 + int retval; 16.824 + 16.825 + hcd = pci_get_drvdata(dev); 16.826 + printk (KERN_INFO "%s %s: suspend to state %d\n", 16.827 + hcd->description, dev->slot_name, state); 16.828 + 16.829 + pci_save_state (dev, hcd->pci_state); 16.830 + 16.831 + // FIXME for all connected devices, leaf-to-root: 16.832 + // driver->suspend() 16.833 + // proposed "new 2.5 driver model" will automate that 16.834 + 16.835 + /* driver may want to disable DMA etc */ 16.836 + retval = hcd->driver->suspend (hcd, state); 16.837 + hcd->state = USB_STATE_SUSPENDED; 16.838 + 16.839 + pci_set_power_state (dev, state); 16.840 + return retval; 16.841 +} 16.842 +EXPORT_SYMBOL (usb_hcd_pci_suspend); 16.843 + 16.844 +/** 16.845 + * usb_hcd_pci_resume - power management resume of a PCI-based HCD 16.846 + * @dev: USB Host Controller being resumed 16.847 + * 16.848 + * Store this function in the HCD's struct pci_driver as resume(). 16.849 + */ 16.850 +int usb_hcd_pci_resume (struct pci_dev *dev) 16.851 +{ 16.852 + struct usb_hcd *hcd; 16.853 + int retval; 16.854 + 16.855 + hcd = pci_get_drvdata(dev); 16.856 + printk (KERN_INFO "%s %s: resume\n", 16.857 + hcd->description, dev->slot_name); 16.858 + 16.859 + /* guard against multiple resumes (APM bug?) */ 16.860 + atomic_inc (&hcd->resume_count); 16.861 + if (atomic_read (&hcd->resume_count) != 1) { 16.862 + err ("concurrent PCI resumes for %s", hcd->bus->bus_name); 16.863 + retval = 0; 16.864 + goto done; 16.865 + } 16.866 + 16.867 + retval = -EBUSY; 16.868 + if (hcd->state != USB_STATE_SUSPENDED) { 16.869 + dbg ("can't resume, not suspended!"); 16.870 + goto done; 16.871 + } 16.872 + hcd->state = USB_STATE_RESUMING; 16.873 + 16.874 + pci_set_power_state (dev, 0); 16.875 + pci_restore_state (dev, hcd->pci_state); 16.876 + 16.877 + retval = hcd->driver->resume (hcd); 16.878 + if (!HCD_IS_RUNNING (hcd->state)) { 16.879 + dbg ("resume %s failure, retval %d", 16.880 + hcd->bus->bus_name, retval); 16.881 + hc_died (hcd); 16.882 +// FIXME: recover, reset etc. 16.883 + } else { 16.884 + // FIXME for all connected devices, root-to-leaf: 16.885 + // driver->resume (); 16.886 + // proposed "new 2.5 driver model" will automate that 16.887 + } 16.888 + 16.889 +done: 16.890 + atomic_dec (&hcd->resume_count); 16.891 + return retval; 16.892 +} 16.893 +EXPORT_SYMBOL (usb_hcd_pci_resume); 16.894 + 16.895 +#endif /* CONFIG_PM */ 16.896 + 16.897 +#endif 16.898 + 16.899 +/*-------------------------------------------------------------------------*/ 16.900 + 16.901 +/* 16.902 + * Generic HC operations. 16.903 + */ 16.904 + 16.905 +/*-------------------------------------------------------------------------*/ 16.906 + 16.907 +/* called from khubd, or root hub init threads for hcd-private init */ 16.908 +static int hcd_alloc_dev (struct usb_device *udev) 16.909 +{ 16.910 + struct hcd_dev *dev; 16.911 + struct usb_hcd *hcd; 16.912 + unsigned long flags; 16.913 + 16.914 + if (!udev || udev->hcpriv) 16.915 + return -EINVAL; 16.916 + if (!udev->bus || !udev->bus->hcpriv) 16.917 + return -ENODEV; 16.918 + hcd = udev->bus->hcpriv; 16.919 + if (hcd->state == USB_STATE_QUIESCING) 16.920 + return -ENOLINK; 16.921 + 16.922 + dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL); 16.923 + if (dev == NULL) 16.924 + return -ENOMEM; 16.925 + memset (dev, 0, sizeof *dev); 16.926 + 16.927 + INIT_LIST_HEAD (&dev->dev_list); 16.928 + INIT_LIST_HEAD (&dev->urb_list); 16.929 + 16.930 + spin_lock_irqsave (&hcd_data_lock, flags); 16.931 + list_add (&dev->dev_list, &hcd->dev_list); 16.932 + // refcount is implicit 16.933 + udev->hcpriv = dev; 16.934 + spin_unlock_irqrestore (&hcd_data_lock, flags); 16.935 + 16.936 + return 0; 16.937 +} 16.938 + 16.939 +/*-------------------------------------------------------------------------*/ 16.940 + 16.941 +static void hcd_panic (void *_hcd) 16.942 +{ 16.943 + struct usb_hcd *hcd = _hcd; 16.944 + hcd->driver->stop (hcd); 16.945 +} 16.946 + 16.947 +static void hc_died (struct usb_hcd *hcd) 16.948 +{ 16.949 + struct list_head *devlist, *urblist; 16.950 + struct hcd_dev *dev; 16.951 + struct urb *urb; 16.952 + unsigned long flags; 16.953 + 16.954 + /* flag every pending urb as done */ 16.955 + spin_lock_irqsave (&hcd_data_lock, flags); 16.956 + list_for_each (devlist, &hcd->dev_list) { 16.957 + dev = list_entry (devlist, struct hcd_dev, dev_list); 16.958 + list_for_each (urblist, &dev->urb_list) { 16.959 + urb = list_entry (urblist, struct urb, urb_list); 16.960 + dbg ("shutdown %s urb %p pipe %x, current status %d", 16.961 + hcd->bus->bus_name, 16.962 + urb, urb->pipe, urb->status); 16.963 + if (urb->status == -EINPROGRESS) 16.964 + urb->status = -ESHUTDOWN; 16.965 + } 16.966 + } 16.967 + urb = (struct urb *) hcd->rh_timer.data; 16.968 + if (urb) 16.969 + urb->status = -ESHUTDOWN; 16.970 + spin_unlock_irqrestore (&hcd_data_lock, flags); 16.971 + 16.972 + if (urb) 16.973 + rh_status_dequeue (hcd, urb); 16.974 + 16.975 + /* hcd->stop() needs a task context */ 16.976 + INIT_TQUEUE (&hcd->work, hcd_panic, hcd); 16.977 + (void) schedule_task (&hcd->work); 16.978 +} 16.979 + 16.980 +/*-------------------------------------------------------------------------*/ 16.981 + 16.982 +static void urb_unlink (struct urb *urb) 16.983 +{ 16.984 + unsigned long flags; 16.985 + struct usb_device *dev; 16.986 + 16.987 + /* Release any periodic transfer bandwidth */ 16.988 + if (urb->bandwidth) 16.989 + usb_release_bandwidth (urb->dev, urb, 16.990 + usb_pipeisoc (urb->pipe)); 16.991 + 16.992 + /* clear all state linking urb to this dev (and hcd) */ 16.993 + 16.994 + spin_lock_irqsave (&hcd_data_lock, flags); 16.995 + list_del_init (&urb->urb_list); 16.996 + dev = urb->dev; 16.997 + urb->dev = NULL; 16.998 + usb_dec_dev_use (dev); 16.999 + spin_unlock_irqrestore (&hcd_data_lock, flags); 16.1000 +} 16.1001 + 16.1002 + 16.1003 +/* may be called in any context with a valid urb->dev usecount */ 16.1004 +/* caller surrenders "ownership" of urb */ 16.1005 + 16.1006 +static int hcd_submit_urb (struct urb *urb) 16.1007 +{ 16.1008 + int status; 16.1009 + struct usb_hcd *hcd; 16.1010 + struct hcd_dev *dev; 16.1011 + unsigned long flags; 16.1012 + int pipe, temp, max; 16.1013 + int mem_flags; 16.1014 + 16.1015 + if (!urb || urb->hcpriv || !urb->complete) 16.1016 + return -EINVAL; 16.1017 + 16.1018 + urb->status = -EINPROGRESS; 16.1019 + urb->actual_length = 0; 16.1020 + urb->bandwidth = 0; 16.1021 + INIT_LIST_HEAD (&urb->urb_list); 16.1022 + 16.1023 + if (!urb->dev || !urb->dev->bus || urb->dev->devnum <= 0) 16.1024 + return -ENODEV; 16.1025 + hcd = urb->dev->bus->hcpriv; 16.1026 + dev = urb->dev->hcpriv; 16.1027 + if (!hcd || !dev) 16.1028 + return -ENODEV; 16.1029 + 16.1030 + /* can't submit new urbs when quiescing, halted, ... */ 16.1031 + if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state)) 16.1032 + return -ESHUTDOWN; 16.1033 + pipe = urb->pipe; 16.1034 + temp = usb_pipetype (urb->pipe); 16.1035 + if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), 16.1036 + usb_pipeout (pipe))) 16.1037 + return -EPIPE; 16.1038 + 16.1039 + /* NOTE: 2.5 passes this value explicitly in submit() */ 16.1040 + mem_flags = GFP_ATOMIC; 16.1041 + 16.1042 + /* FIXME there should be a sharable lock protecting us against 16.1043 + * config/altsetting changes and disconnects, kicking in here. 16.1044 + */ 16.1045 + 16.1046 + /* Sanity check, so HCDs can rely on clean data */ 16.1047 + max = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)); 16.1048 + if (max <= 0) { 16.1049 + err ("bogus endpoint (bad maxpacket)"); 16.1050 + return -EINVAL; 16.1051 + } 16.1052 + 16.1053 + /* "high bandwidth" mode, 1-3 packets/uframe? */ 16.1054 + if (urb->dev->speed == USB_SPEED_HIGH) { 16.1055 + int mult; 16.1056 + switch (temp) { 16.1057 + case PIPE_ISOCHRONOUS: 16.1058 + case PIPE_INTERRUPT: 16.1059 + mult = 1 + ((max >> 11) & 0x03); 16.1060 + max &= 0x03ff; 16.1061 + max *= mult; 16.1062 + } 16.1063 + } 16.1064 + 16.1065 + /* periodic transfers limit size per frame/uframe */ 16.1066 + switch (temp) { 16.1067 + case PIPE_ISOCHRONOUS: { 16.1068 + int n, len; 16.1069 + 16.1070 + if (urb->number_of_packets <= 0) 16.1071 + return -EINVAL; 16.1072 + for (n = 0; n < urb->number_of_packets; n++) { 16.1073 + len = urb->iso_frame_desc [n].length; 16.1074 + if (len < 0 || len > max) 16.1075 + return -EINVAL; 16.1076 + } 16.1077 + 16.1078 + } 16.1079 + break; 16.1080 + case PIPE_INTERRUPT: 16.1081 + if (urb->transfer_buffer_length > max) 16.1082 + return -EINVAL; 16.1083 + } 16.1084 + 16.1085 + /* the I/O buffer must usually be mapped/unmapped */ 16.1086 + if (urb->transfer_buffer_length < 0) 16.1087 + return -EINVAL; 16.1088 + 16.1089 + if (urb->next) { 16.1090 + warn ("use explicit queuing not urb->next"); 16.1091 + return -EINVAL; 16.1092 + } 16.1093 + 16.1094 +#ifdef DEBUG 16.1095 + /* stuff that drivers shouldn't do, but which shouldn't 16.1096 + * cause problems in HCDs if they get it wrong. 16.1097 + */ 16.1098 + { 16.1099 + unsigned int orig_flags = urb->transfer_flags; 16.1100 + unsigned int allowed; 16.1101 + 16.1102 + /* enforce simple/standard policy */ 16.1103 + allowed = USB_ASYNC_UNLINK; // affects later unlinks 16.1104 + allowed |= USB_NO_FSBR; // only affects UHCI 16.1105 + switch (temp) { 16.1106 + case PIPE_CONTROL: 16.1107 + allowed |= USB_DISABLE_SPD; 16.1108 + break; 16.1109 + case PIPE_BULK: 16.1110 + allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK 16.1111 + | USB_ZERO_PACKET | URB_NO_INTERRUPT; 16.1112 + break; 16.1113 + case PIPE_INTERRUPT: 16.1114 + allowed |= USB_DISABLE_SPD; 16.1115 + break; 16.1116 + case PIPE_ISOCHRONOUS: 16.1117 + allowed |= USB_ISO_ASAP; 16.1118 + break; 16.1119 + } 16.1120 + urb->transfer_flags &= allowed; 16.1121 + 16.1122 + /* fail if submitter gave bogus flags */ 16.1123 + if (urb->transfer_flags != orig_flags) { 16.1124 + err ("BOGUS urb flags, %x --> %x", 16.1125 + orig_flags, urb->transfer_flags); 16.1126 + return -EINVAL; 16.1127 + } 16.1128 + } 16.1129 +#endif 16.1130 + /* 16.1131 + * Force periodic transfer intervals to be legal values that are 16.1132 + * a power of two (so HCDs don't need to). 16.1133 + * 16.1134 + * FIXME want bus->{intr,iso}_sched_horizon values here. Each HC 16.1135 + * supports different values... this uses EHCI/UHCI defaults (and 16.1136 + * EHCI can use smaller non-default values). 16.1137 + */ 16.1138 + switch (temp) { 16.1139 + case PIPE_ISOCHRONOUS: 16.1140 + case PIPE_INTERRUPT: 16.1141 + /* too small? */ 16.1142 + if (urb->interval <= 0) 16.1143 + return -EINVAL; 16.1144 + /* too big? */ 16.1145 + switch (urb->dev->speed) { 16.1146 + case USB_SPEED_HIGH: /* units are microframes */ 16.1147 + // NOTE usb handles 2^15 16.1148 + if (urb->interval > (1024 * 8)) 16.1149 + urb->interval = 1024 * 8; 16.1150 + temp = 1024 * 8; 16.1151 + break; 16.1152 + case USB_SPEED_FULL: /* units are frames/msec */ 16.1153 + case USB_SPEED_LOW: 16.1154 + if (temp == PIPE_INTERRUPT) { 16.1155 + if (urb->interval > 255) 16.1156 + return -EINVAL; 16.1157 + // NOTE ohci only handles up to 32 16.1158 + temp = 128; 16.1159 + } else { 16.1160 + if (urb->interval > 1024) 16.1161 + urb->interval = 1024; 16.1162 + // NOTE usb and ohci handle up to 2^15 16.1163 + temp = 1024; 16.1164 + } 16.1165 + break; 16.1166 + default: 16.1167 + return -EINVAL; 16.1168 + } 16.1169 + /* power of two? */ 16.1170 + while (temp > urb->interval) 16.1171 + temp >>= 1; 16.1172 + urb->interval = temp; 16.1173 + } 16.1174 + 16.1175 + 16.1176 + /* 16.1177 + * FIXME: make urb timeouts be generic, keeping the HCD cores 16.1178 + * as simple as possible. 16.1179 + */ 16.1180 + 16.1181 + // NOTE: a generic device/urb monitoring hook would go here. 16.1182 + // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb) 16.1183 + // It would catch submission paths for all urbs. 16.1184 + 16.1185 + /* 16.1186 + * Atomically queue the urb, first to our records, then to the HCD. 16.1187 + * Access to urb->status is controlled by urb->lock ... changes on 16.1188 + * i/o completion (normal or fault) or unlinking. 16.1189 + */ 16.1190 + 16.1191 + // FIXME: verify that quiescing hc works right (RH cleans up) 16.1192 + 16.1193 + spin_lock_irqsave (&hcd_data_lock, flags); 16.1194 + if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) { 16.1195 + usb_inc_dev_use (urb->dev); 16.1196 + list_add (&urb->urb_list, &dev->urb_list); 16.1197 + status = 0; 16.1198 + } else { 16.1199 + INIT_LIST_HEAD (&urb->urb_list); 16.1200 + status = -ESHUTDOWN; 16.1201 + } 16.1202 + spin_unlock_irqrestore (&hcd_data_lock, flags); 16.1203 + if (status) 16.1204 + return status; 16.1205 + 16.1206 + // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag 16.1207 + 16.1208 + /* For 2.4, don't map bounce buffer if it's a root hub operation. */ 16.1209 + if (urb->dev == hcd->bus->root_hub) { 16.1210 + status = rh_urb_enqueue (hcd, urb); 16.1211 + } else { 16.1212 +#ifdef CONFIG_PCI 16.1213 + if (usb_pipecontrol (urb->pipe)) 16.1214 + urb->setup_dma = pci_map_single ( 16.1215 + hcd->pdev, 16.1216 + urb->setup_packet, 16.1217 + sizeof (struct usb_ctrlrequest), 16.1218 + PCI_DMA_TODEVICE); 16.1219 + if (urb->transfer_buffer_length != 0) 16.1220 + urb->transfer_dma = pci_map_single ( 16.1221 + hcd->pdev, 16.1222 + urb->transfer_buffer, 16.1223 + urb->transfer_buffer_length, 16.1224 + usb_pipein (urb->pipe) 16.1225 + ? PCI_DMA_FROMDEVICE 16.1226 + : PCI_DMA_TODEVICE); 16.1227 +#endif /* CONFIG_PCI */ 16.1228 + status = hcd->driver->urb_enqueue (hcd, urb, mem_flags); 16.1229 + } 16.1230 + return status; 16.1231 +} 16.1232 + 16.1233 +/*-------------------------------------------------------------------------*/ 16.1234 + 16.1235 +/* called in any context */ 16.1236 +static int hcd_get_frame_number (struct usb_device *udev) 16.1237 +{ 16.1238 + struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv; 16.1239 + return hcd->driver->get_frame_number (hcd); 16.1240 +} 16.1241 + 16.1242 +/*-------------------------------------------------------------------------*/ 16.1243 + 16.1244 +struct completion_splice { // modified urb context: 16.1245 + /* did we complete? */ 16.1246 + struct completion done; 16.1247 + 16.1248 + /* original urb data */ 16.1249 + void (*complete)(struct urb *); 16.1250 + void *context; 16.1251 +}; 16.1252 + 16.1253 +static void unlink_complete (struct urb *urb) 16.1254 +{ 16.1255 + struct completion_splice *splice; 16.1256 + 16.1257 + splice = (struct completion_splice *) urb->context; 16.1258 + 16.1259 + /* issue original completion call */ 16.1260 + urb->complete = splice->complete; 16.1261 + urb->context = splice->context; 16.1262 + urb->complete (urb); 16.1263 + 16.1264 + /* then let the synchronous unlink call complete */ 16.1265 + complete (&splice->done); 16.1266 +} 16.1267 + 16.1268 +/* 16.1269 + * called in any context; note ASYNC_UNLINK restrictions 16.1270 + * 16.1271 + * caller guarantees urb won't be recycled till both unlink() 16.1272 + * and the urb's completion function return 16.1273 + */ 16.1274 +static int hcd_unlink_urb (struct urb *urb) 16.1275 +{ 16.1276 + struct hcd_dev *dev; 16.1277 + struct usb_hcd *hcd = 0; 16.1278 + unsigned long flags; 16.1279 + struct completion_splice splice; 16.1280 + int retval; 16.1281 + 16.1282 + if (!urb) 16.1283 + return -EINVAL; 16.1284 + 16.1285 + /* 16.1286 + * we contend for urb->status with the hcd core, 16.1287 + * which changes it while returning the urb. 16.1288 + * 16.1289 + * Caller guaranteed that the urb pointer hasn't been freed, and 16.1290 + * that it was submitted. But as a rule it can't know whether or 16.1291 + * not it's already been unlinked ... so we respect the reversed 16.1292 + * lock sequence needed for the usb_hcd_giveback_urb() code paths 16.1293 + * (urb lock, then hcd_data_lock) in case some other CPU is now 16.1294 + * unlinking it. 16.1295 + */ 16.1296 + spin_lock_irqsave (&urb->lock, flags); 16.1297 + spin_lock (&hcd_data_lock); 16.1298 + if (!urb->hcpriv || urb->transfer_flags & USB_TIMEOUT_KILLED) { 16.1299 + retval = -EINVAL; 16.1300 + goto done; 16.1301 + } 16.1302 + 16.1303 + if (!urb->dev || !urb->dev->bus) { 16.1304 + retval = -ENODEV; 16.1305 + goto done; 16.1306 + } 16.1307 + 16.1308 + /* giveback clears dev; non-null means it's linked at this level */ 16.1309 + dev = urb->dev->hcpriv; 16.1310 + hcd = urb->dev->bus->hcpriv; 16.1311 + if (!dev || !hcd) { 16.1312 + retval = -ENODEV; 16.1313 + goto done; 16.1314 + } 16.1315 + 16.1316 + /* Any status except -EINPROGRESS means the HCD has already started 16.1317 + * to return this URB to the driver. In that case, there's no 16.1318 + * more work for us to do. 16.1319 + * 16.1320 + * There's much magic because of "automagic resubmit" of interrupt 16.1321 + * transfers, stopped only by explicit unlinking. We won't issue 16.1322 + * an "it's unlinked" callback more than once, but device drivers 16.1323 + * can need to retry (SMP, -EAGAIN) an unlink request as well as 16.1324 + * fake out the "not yet completed" state (set -EINPROGRESS) if 16.1325 + * unlinking from complete(). Automagic eventually vanishes. 16.1326 + * 16.1327 + * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED 16.1328 + */ 16.1329 + if (urb->status != -EINPROGRESS) { 16.1330 + if (usb_pipetype (urb->pipe) == PIPE_INTERRUPT) 16.1331 + retval = -EAGAIN; 16.1332 + else 16.1333 + retval = -EBUSY; 16.1334 + goto done; 16.1335 + } 16.1336 + 16.1337 + /* maybe set up to block on completion notification */ 16.1338 + if ((urb->transfer_flags & USB_TIMEOUT_KILLED)) 16.1339 + urb->status = -ETIMEDOUT; 16.1340 + else if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) { 16.1341 + if (in_interrupt ()) { 16.1342 + dbg ("non-async unlink in_interrupt"); 16.1343 + retval = -EWOULDBLOCK; 16.1344 + goto done; 16.1345 + } 16.1346 + /* synchronous unlink: block till we see the completion */ 16.1347 + init_completion (&splice.done); 16.1348 + splice.complete = urb->complete; 16.1349 + splice.context = urb->context; 16.1350 + urb->complete = unlink_complete; 16.1351 + urb->context = &splice; 16.1352 + urb->status = -ENOENT; 16.1353 + } else { 16.1354 + /* asynchronous unlink */ 16.1355 + urb->status = -ECONNRESET; 16.1356 + } 16.1357 + spin_unlock (&hcd_data_lock); 16.1358 + spin_unlock_irqrestore (&urb->lock, flags); 16.1359 + 16.1360 + if (urb == (struct urb *) hcd->rh_timer.data) { 16.1361 + rh_status_dequeue (hcd, urb); 16.1362 + retval = 0; 16.1363 + } else { 16.1364 + retval = hcd->driver->urb_dequeue (hcd, urb); 16.1365 +// FIXME: if retval and we tried to splice, whoa!! 16.1366 +if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval); 16.1367 + } 16.1368 + 16.1369 + /* block till giveback, if needed */ 16.1370 + if (!(urb->transfer_flags & (USB_ASYNC_UNLINK|USB_TIMEOUT_KILLED)) 16.1371 + && HCD_IS_RUNNING (hcd->state) 16.1372 + && !retval) { 16.1373 + wait_for_completion (&splice.done); 16.1374 + } else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) { 16.1375 + return -EINPROGRESS; 16.1376 + } 16.1377 + goto bye; 16.1378 +done: 16.1379 + spin_unlock (&hcd_data_lock); 16.1380 + spin_unlock_irqrestore (&urb->lock, flags); 16.1381 +bye: 16.1382 + if (retval) 16.1383 + dbg ("%s: hcd_unlink_urb fail %d", 16.1384 + hcd ? hcd->bus->bus_name : "(no bus?)", 16.1385 + retval); 16.1386 + return retval; 16.1387 +} 16.1388 + 16.1389 +/*-------------------------------------------------------------------------*/ 16.1390 + 16.1391 +/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup */ 16.1392 + 16.1393 +// FIXME: likely best to have explicit per-setting (config+alt) 16.1394 +// setup primitives in the usbcore-to-hcd driver API, so nothing 16.1395 +// is implicit. kernel 2.5 needs a bunch of config cleanup... 16.1396 + 16.1397 +static int hcd_free_dev (struct usb_device *udev) 16.1398 +{ 16.1399 + struct hcd_dev *dev; 16.1400 + struct usb_hcd *hcd; 16.1401 + unsigned long flags; 16.1402 + 16.1403 + if (!udev || !udev->hcpriv) 16.1404 + return -EINVAL; 16.1405 + 16.1406 + if (!udev->bus || !udev->bus->hcpriv) 16.1407 + return -ENODEV; 16.1408 + 16.1409 + // should udev->devnum == -1 ?? 16.1410 + 16.1411 + dev = udev->hcpriv; 16.1412 + hcd = udev->bus->hcpriv; 16.1413 + 16.1414 + /* device driver problem with refcounts? */ 16.1415 + if (!list_empty (&dev->urb_list)) { 16.1416 + dbg ("free busy dev, %s devnum %d (bug!)", 16.1417 + hcd->bus->bus_name, udev->devnum); 16.1418 + return -EINVAL; 16.1419 + } 16.1420 + 16.1421 + hcd->driver->free_config (hcd, udev); 16.1422 + 16.1423 + spin_lock_irqsave (&hcd_data_lock, flags); 16.1424 + list_del (&dev->dev_list); 16.1425 + udev->hcpriv = NULL; 16.1426 + spin_unlock_irqrestore (&hcd_data_lock, flags); 16.1427 + 16.1428 + kfree (dev); 16.1429 + return 0; 16.1430 +} 16.1431 + 16.1432 +static struct usb_operations hcd_operations = { 16.1433 + allocate: hcd_alloc_dev, 16.1434 + get_frame_number: hcd_get_frame_number, 16.1435 + submit_urb: hcd_submit_urb, 16.1436 + unlink_urb: hcd_unlink_urb, 16.1437 + deallocate: hcd_free_dev, 16.1438 +}; 16.1439 + 16.1440 +/*-------------------------------------------------------------------------*/ 16.1441 + 16.1442 +static void hcd_irq (int irq, void *__hcd, struct pt_regs * r) 16.1443 +{ 16.1444 + struct usb_hcd *hcd = __hcd; 16.1445 + int start = hcd->state; 16.1446 + 16.1447 + if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */ 16.1448 + return; 16.1449 + 16.1450 + hcd->driver->irq (hcd, r); 16.1451 + if (hcd->state != start && hcd->state == USB_STATE_HALT) 16.1452 + hc_died (hcd); 16.1453 +} 16.1454 + 16.1455 +/*-------------------------------------------------------------------------*/ 16.1456 + 16.1457 +/** 16.1458 + * usb_hcd_giveback_urb - return URB from HCD to device driver 16.1459 + * @hcd: host controller returning the URB 16.1460 + * @urb: urb being returned to the USB device driver. 16.1461 + * @regs: saved hardware registers (ignored on 2.4 kernels) 16.1462 + * Context: in_interrupt() 16.1463 + * 16.1464 + * This hands the URB from HCD to its USB device driver, using its 16.1465 + * completion function. The HCD has freed all per-urb resources 16.1466 + * (and is done using urb->hcpriv). It also released all HCD locks; 16.1467 + * the device driver won't cause deadlocks if it resubmits this URB, 16.1468 + * and won't confuse things by modifying and resubmitting this one. 16.1469 + * Bandwidth and other resources will be deallocated. 16.1470 + * 16.1471 + * HCDs must not use this for periodic URBs that are still scheduled 16.1472 + * and will be reissued. They should just call their completion handlers 16.1473 + * until the urb is returned to the device driver by unlinking. 16.1474 + * 16.1475 + * NOTE that no urb->next processing is done, even for isochronous URBs. 16.1476 + * ISO streaming functionality can be achieved by having completion handlers 16.1477 + * re-queue URBs. Such explicit queuing doesn't discard error reports. 16.1478 + */ 16.1479 +void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) 16.1480 +{ 16.1481 + int is_root_hub_operation; 16.1482 + 16.1483 + /* Work this out here as urb_unlink clears urb->dev */ 16.1484 + is_root_hub_operation = (urb->dev == hcd->bus->root_hub); 16.1485 + 16.1486 + urb_unlink (urb); 16.1487 + 16.1488 + // NOTE: a generic device/urb monitoring hook would go here. 16.1489 + // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev) 16.1490 + // It would catch exit/unlink paths for all urbs, but non-exit 16.1491 + // completions for periodic urbs need hooks inside the HCD. 16.1492 + // hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev) 16.1493 + 16.1494 + // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag 16.1495 + 16.1496 +#ifdef CONFIG_PCI 16.1497 + /* For 2.4, don't unmap bounce buffer if it's a root hub operation. */ 16.1498 + if (usb_pipecontrol (urb->pipe) && !is_root_hub_operation) 16.1499 + pci_unmap_single (hcd->pdev, urb->setup_dma, 16.1500 + sizeof (struct usb_ctrlrequest), 16.1501 + PCI_DMA_TODEVICE); 16.1502 + 16.1503 + if ((urb->transfer_buffer_length != 0) && !is_root_hub_operation) 16.1504 + pci_unmap_single (hcd->pdev, urb->transfer_dma, 16.1505 + urb->transfer_buffer_length, 16.1506 + usb_pipein (urb->pipe) 16.1507 + ? PCI_DMA_FROMDEVICE 16.1508 + : PCI_DMA_TODEVICE); 16.1509 +#endif /* CONFIG_PCI */ 16.1510 + 16.1511 + /* pass ownership to the completion handler */ 16.1512 + urb->complete (urb); 16.1513 +} 16.1514 +EXPORT_SYMBOL (usb_hcd_giveback_urb);
17.1 --- a/tools/python/xen/lowlevel/xu/xu.c Wed Jan 19 08:53:39 2005 +0000 17.2 +++ b/tools/python/xen/lowlevel/xu/xu.c Wed Jan 19 13:20:15 2005 +0000 17.3 @@ -562,6 +562,24 @@ static PyTypeObject xu_notifier_type = { 17.4 PyDict_SetItemString(dict, #_field, obj); \ 17.5 } while ( 0 ) 17.6 17.7 +#define PSTR2CHAR(_struct, _field) \ 17.8 + do { \ 17.9 + PyObject *obj; \ 17.10 + if ( (obj = PyDict_GetItemString(payload, #_field)) != NULL ) \ 17.11 + { \ 17.12 + if ( PyString_Check(obj) ) \ 17.13 + { \ 17.14 + char *buffer = PyString_AsString(obj); \ 17.15 + \ 17.16 + strcpy(((_struct *)&xum->msg.msg[0])->_field, \ 17.17 + buffer); \ 17.18 + /* Should complain about length - think later */ \ 17.19 + dict_items_parsed++; \ 17.20 + } \ 17.21 + } \ 17.22 + xum->msg.length = sizeof(_struct); \ 17.23 + } while ( 0 ) 17.24 + 17.25 typedef struct { 17.26 PyObject_HEAD; 17.27 control_msg_t msg; 17.28 @@ -753,6 +771,52 @@ static PyObject *xu_message_get_payload( 17.29 case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS): 17.30 C2P(netif_be_driver_status_t, status, Int, Long); 17.31 return dict; 17.32 + case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED): 17.33 + C2P(usbif_fe_interface_status_changed_t, status, Int, Long); 17.34 + C2P(usbif_fe_interface_status_changed_t, evtchn, Int, Long); 17.35 + C2P(usbif_fe_interface_status_changed_t, domid, Int, Long); 17.36 + C2P(usbif_fe_interface_status_changed_t, bandwidth, Int, Long); 17.37 + C2P(usbif_fe_interface_status_changed_t, num_ports, Int, Long); 17.38 + return dict; 17.39 + case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_DRIVER_STATUS_CHANGED): 17.40 + C2P(usbif_fe_driver_status_changed_t, status, Int, Long); 17.41 + return dict; 17.42 + case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_CONNECT): 17.43 + C2P(usbif_fe_interface_connect_t, shmem_frame, Int, Long); 17.44 + return dict; 17.45 + case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_DISCONNECT): 17.46 + return dict; 17.47 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_CREATE): 17.48 + C2P(usbif_be_create_t, domid, Int, Long); 17.49 + C2P(usbif_be_create_t, status, Int, Long); 17.50 + return dict; 17.51 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_DESTROY): 17.52 + C2P(usbif_be_destroy_t, domid, Int, Long); 17.53 + C2P(usbif_be_destroy_t, status, Int, Long); 17.54 + return dict; 17.55 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_CONNECT): 17.56 + C2P(usbif_be_connect_t, domid, Int, Long); 17.57 + C2P(usbif_be_connect_t, shmem_frame, Int, Long); 17.58 + C2P(usbif_be_connect_t, evtchn, Int, Long); 17.59 + C2P(usbif_be_connect_t, bandwidth, Int, Long); 17.60 + C2P(usbif_be_connect_t, status, Int, Long); 17.61 + return dict; 17.62 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_DISCONNECT): 17.63 + C2P(usbif_be_disconnect_t, domid, Int, Long); 17.64 + C2P(usbif_be_disconnect_t, status, Int, Long); 17.65 + return dict; 17.66 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_DRIVER_STATUS_CHANGED): 17.67 + C2P(usbif_be_driver_status_changed_t, status, Int, Long); 17.68 + return dict; 17.69 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_CLAIM_PORT): 17.70 + C2P(usbif_be_claim_port_t, domid, Int, Long); 17.71 + C2P(usbif_be_claim_port_t, usbif_port, Int, Long); 17.72 + C2P(usbif_be_claim_port_t, status, Int, Long); 17.73 + C2P(usbif_be_claim_port_t, path, String, String); 17.74 + return dict; 17.75 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_RELEASE_PORT): 17.76 + C2P(usbif_be_release_port_t, path, String, String); 17.77 + return dict; 17.78 case TYPE(CMSG_MEM_REQUEST, CMSG_MEM_REQUEST_SET): 17.79 C2P(mem_request_t, target, Int, Long); 17.80 C2P(mem_request_t, status, Int, Long); 17.81 @@ -922,6 +986,53 @@ static PyObject *xu_message_new(PyObject 17.82 P2C(mem_request_t, target, u32); 17.83 P2C(mem_request_t, status, u32); 17.84 break; 17.85 + case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED): 17.86 + P2C(usbif_fe_interface_status_changed_t, status, u32); 17.87 + P2C(usbif_fe_interface_status_changed_t, evtchn, u16); 17.88 + P2C(usbif_fe_interface_status_changed_t, domid, domid_t); 17.89 + P2C(usbif_fe_interface_status_changed_t, bandwidth, u32); 17.90 + P2C(usbif_fe_interface_status_changed_t, num_ports, u32); 17.91 + break; 17.92 + case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_DRIVER_STATUS_CHANGED): 17.93 + P2C(usbif_fe_driver_status_changed_t, status, u32); 17.94 + break; 17.95 + case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_CONNECT): 17.96 + P2C(usbif_fe_interface_connect_t, shmem_frame, memory_t); 17.97 + break; 17.98 + case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_DISCONNECT): 17.99 + break; 17.100 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_CREATE): 17.101 + P2C(usbif_be_create_t, domid, domid_t); 17.102 + P2C(usbif_be_create_t, status, u32); 17.103 + break; 17.104 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_DESTROY): 17.105 + P2C(usbif_be_destroy_t, domid, domid_t); 17.106 + P2C(usbif_be_destroy_t, status, u32); 17.107 + break; 17.108 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_CONNECT): 17.109 + P2C(usbif_be_connect_t, domid, domid_t); 17.110 + P2C(usbif_be_connect_t, shmem_frame, memory_t); 17.111 + P2C(usbif_be_connect_t, evtchn, u32); 17.112 + P2C(usbif_be_connect_t, bandwidth, u32); 17.113 + P2C(usbif_be_connect_t, status, u32); 17.114 + break; 17.115 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_DISCONNECT): 17.116 + P2C(usbif_be_disconnect_t, domid, domid_t); 17.117 + P2C(usbif_be_disconnect_t, status, u32); 17.118 + break; 17.119 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_DRIVER_STATUS_CHANGED): 17.120 + P2C(usbif_be_driver_status_changed_t, status, u32); 17.121 + break; 17.122 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_CLAIM_PORT): 17.123 + P2C(usbif_be_claim_port_t, domid, domid_t); 17.124 + P2C(usbif_be_claim_port_t, usbif_port, u32); 17.125 + P2C(usbif_be_claim_port_t, status, u32); 17.126 + PSTR2CHAR(usbif_be_claim_port_t, path); 17.127 + printf("dict items parsed = %d", dict_items_parsed); 17.128 + break; 17.129 + case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_RELEASE_PORT): 17.130 + PSTR2CHAR(usbif_be_release_port_t, path); 17.131 + break; 17.132 } 17.133 17.134 if ( dict_items_parsed != PyDict_Size(payload) )
18.1 --- a/tools/python/xen/xend/XendDomainInfo.py Wed Jan 19 08:53:39 2005 +0000 18.2 +++ b/tools/python/xen/xend/XendDomainInfo.py Wed Jan 19 13:20:15 2005 +0000 18.3 @@ -658,6 +658,7 @@ class XendDomainInfo: 18.4 """ 18.5 self.release_vifs() 18.6 self.release_vbds() 18.7 + self.release_usbifs() 18.8 18.9 self.devices = {} 18.10 self.device_index = {} 18.11 @@ -682,6 +683,15 @@ class XendDomainInfo: 18.12 log.debug("Destroying vbds for domain %d", self.dom) 18.13 ctrl.destroy() 18.14 18.15 + def release_usbifs(self): 18.16 + """Release vm virtual USB devices (usbifs). 18.17 + """ 18.18 + if self.dom is None: return 18.19 + ctrl = xend.usbif_get(self.dom) 18.20 + if ctrl: 18.21 + log.debug("Destroying usbifs for domain %d", self.dom) 18.22 + ctrl.destroy() 18.23 + 18.24 def show(self): 18.25 """Print virtual machine info. 18.26 """ 18.27 @@ -994,6 +1004,8 @@ class XendDomainInfo: 18.28 self.blkif_backend = 1 18.29 elif name == 'netif': 18.30 self.netif_backend = 1 18.31 + elif name == 'usbif': 18.32 + self.usbif_backend = 1 18.33 else: 18.34 raise VmError('invalid backend type:' + str(name)) 18.35 18.36 @@ -1174,6 +1186,23 @@ def vm_dev_vif(vm, val, index, change=0) 18.37 defer.addCallback(cbok) 18.38 return defer 18.39 18.40 +def vm_dev_usb(vm, val, index): 18.41 + """Attach the relevant physical ports to the domains' USB interface. 18.42 + 18.43 + @param vm: virtual machine 18.44 + @param val: USB interface config 18.45 + @param index: USB interface index 18.46 + @return: deferred 18.47 + """ 18.48 + ctrl = xend.usbif_create(vm.dom, recreate=vm.recreate) 18.49 + log.debug("Creating USB interface dom=%d", vm.dom) 18.50 + defer = ctrl.attachDevice(val, recreate=vm.recreate) 18.51 + def cbok(path): 18.52 + vm.add_device('usb', val[1][1]) 18.53 + return path 18.54 + defer.addCallback(cbok) 18.55 + return defer 18.56 + 18.57 def vm_dev_vbd(vm, val, index, change=0): 18.58 """Create a virtual block device (vbd). 18.59 18.60 @@ -1278,6 +1307,7 @@ add_image_handler('vmx', vm_image_vmx) 18.61 add_device_handler('vif', vm_dev_vif) 18.62 add_device_handler('vbd', vm_dev_vbd) 18.63 add_device_handler('pci', vm_dev_pci) 18.64 +add_device_handler('usb', vm_dev_usb) 18.65 18.66 # Ignore the fields we already handle. 18.67 add_config_handler('name', vm_field_ignore)
19.1 --- a/tools/python/xen/xend/server/SrvDaemon.py Wed Jan 19 08:53:39 2005 +0000 19.2 +++ b/tools/python/xen/xend/server/SrvDaemon.py Wed Jan 19 13:20:15 2005 +0000 19.3 @@ -40,6 +40,7 @@ from xen.util.ip import _readline, _read 19.4 import channel 19.5 import blkif 19.6 import netif 19.7 +import usbif 19.8 import console 19.9 import domain 19.10 from params import * 19.11 @@ -261,6 +262,7 @@ class EventProtocol(protocol.Protocol): 19.12 val += self.daemon.consoles() 19.13 val += self.daemon.blkifs() 19.14 val += self.daemon.netifs() 19.15 + val += self.daemon.usbifs() 19.16 return val 19.17 19.18 def op_sys_subscribe(self, name, v): 19.19 @@ -617,6 +619,7 @@ class Daemon: 19.20 self.domainCF = domain.DomainControllerFactory() 19.21 self.blkifCF = blkif.BlkifControllerFactory() 19.22 self.netifCF = netif.NetifControllerFactory() 19.23 + self.usbifCF = usbif.UsbifControllerFactory() 19.24 self.consoleCF = console.ConsoleControllerFactory() 19.25 19.26 def listenEvent(self): 19.27 @@ -683,6 +686,15 @@ class Daemon: 19.28 def netif_get(self, dom): 19.29 return self.netifCF.getControllerByDom(dom) 19.30 19.31 + def usbif_create(self, dom, recreate=0): 19.32 + return self.usbifCF.getController(dom) 19.33 + 19.34 + def usbifs(self): 19.35 + return [ x.sxpr() for x in self.usbifCF.getControllers() ] 19.36 + 19.37 + def usbif_get(self, dom): 19.38 + return self.usbifCF.getControllerByDom(dom) 19.39 + 19.40 def console_create(self, dom, console_port=None): 19.41 """Create a console for a domain. 19.42 """
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/tools/python/xen/xend/server/SrvUsbif.py Wed Jan 19 13:20:15 2005 +0000 20.3 @@ -0,0 +1,249 @@ 20.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 20.5 + 20.6 +from twisted.protocols import http 20.7 + 20.8 +from xen.xend import sxp 20.9 +from xen.xend import XendDomain 20.10 +from xen.xend import XendConsole 20.11 +from xen.xend import PrettyPrint 20.12 +from xen.xend.Args import FormFn 20.13 + 20.14 +from SrvDir import SrvDir 20.15 + 20.16 +class SrvDomain(SrvDir): 20.17 + """Service managing a single domain. 20.18 + """ 20.19 + 20.20 + def __init__(self, dom): 20.21 + SrvDir.__init__(self) 20.22 + self.dom = dom 20.23 + self.xd = XendDomain.instance() 20.24 + self.xconsole = XendConsole.instance() 20.25 + 20.26 + def op_configure(self, op, req): 20.27 + """Configure an existing domain. 20.28 + Configure is unusual in that it requires a domain id, 20.29 + not a domain name. 20.30 + """ 20.31 + fn = FormFn(self.xd.domain_configure, 20.32 + [['dom', 'int'], 20.33 + ['config', 'sxpr']]) 20.34 + deferred = fn(req.args, {'dom': self.dom.dom}) 20.35 + deferred.addErrback(self._op_configure_err, req) 20.36 + return deferred 20.37 + 20.38 + def _op_configure_err(self, err, req): 20.39 + req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err)) 20.40 + return str(err) 20.41 + 20.42 + def op_unpause(self, op, req): 20.43 + val = self.xd.domain_unpause(self.dom.name) 20.44 + return val 20.45 + 20.46 + def op_pause(self, op, req): 20.47 + val = self.xd.domain_pause(self.dom.name) 20.48 + return val 20.49 + 20.50 + def op_shutdown(self, op, req): 20.51 + fn = FormFn(self.xd.domain_shutdown, 20.52 + [['dom', 'str'], 20.53 + ['reason', 'str']]) 20.54 + val = fn(req.args, {'dom': self.dom.id}) 20.55 + req.setResponseCode(http.ACCEPTED) 20.56 + req.setHeader("Location", "%s/.." % req.prePathURL()) 20.57 + return val 20.58 + 20.59 + def op_destroy(self, op, req): 20.60 + fn = FormFn(self.xd.domain_destroy, 20.61 + [['dom', 'str'], 20.62 + ['reason', 'str']]) 20.63 + val = fn(req.args, {'dom': self.dom.id}) 20.64 + req.setHeader("Location", "%s/.." % req.prePathURL()) 20.65 + return val 20.66 + 20.67 + def op_save(self, op, req): 20.68 + fn = FormFn(self.xd.domain_save, 20.69 + [['dom', 'str'], 20.70 + ['file', 'str']]) 20.71 + deferred = fn(req.args, {'dom': self.dom.id}) 20.72 + deferred.addCallback(self._op_save_cb, req) 20.73 + deferred.addErrback(self._op_save_err, req) 20.74 + return deferred 20.75 + 20.76 + def _op_save_cb(self, val, req): 20.77 + return 0 20.78 + 20.79 + def _op_save_err(self, err, req): 20.80 + req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err)) 20.81 + return str(err) 20.82 + 20.83 + def op_migrate(self, op, req): 20.84 + fn = FormFn(self.xd.domain_migrate, 20.85 + [['dom', 'str'], 20.86 + ['destination', 'str'], 20.87 + ['live', 'int']]) 20.88 + deferred = fn(req.args, {'dom': self.dom.id}) 20.89 + print 'op_migrate>', deferred 20.90 + deferred.addCallback(self._op_migrate_cb, req) 20.91 + deferred.addErrback(self._op_migrate_err, req) 20.92 + return deferred 20.93 + 20.94 + def _op_migrate_cb(self, info, req): 20.95 + print '_op_migrate_cb>', info, req 20.96 + #req.setResponseCode(http.ACCEPTED) 20.97 + host = info.dst_host 20.98 + port = info.dst_port 20.99 + dom = info.dst_dom 20.100 + url = "http://%s:%d/xend/domain/%d" % (host, port, dom) 20.101 + req.setHeader("Location", url) 20.102 + print '_op_migrate_cb> url=', url 20.103 + return url 20.104 + 20.105 + def _op_migrate_err(self, err, req): 20.106 + print '_op_migrate_err>', err, req 20.107 + req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err)) 20.108 + return str(err) 20.109 + 20.110 + def op_pincpu(self, op, req): 20.111 + fn = FormFn(self.xd.domain_pincpu, 20.112 + [['dom', 'str'], 20.113 + ['cpu', 'int']]) 20.114 + val = fn(req.args, {'dom': self.dom.id}) 20.115 + return val 20.116 + 20.117 + def op_cpu_bvt_set(self, op, req): 20.118 + fn = FormFn(self.xd.domain_cpu_bvt_set, 20.119 + [['dom', 'str'], 20.120 + ['mcuadv', 'int'], 20.121 + ['warpback', 'int'], 20.122 + ['warpvalue', 'int'], 20.123 + ['warpl', 'long'], 20.124 + ['warpu', 'long']]) 20.125 + val = fn(req.args, {'dom': self.dom.id}) 20.126 + return val 20.127 + 20.128 + def op_cpu_fbvt_set(self, op, req): 20.129 + fn = FormFn(self.xd.domain_cpu_fbvt_set, 20.130 + [['dom', 'str'], 20.131 + ['mcuadv', 'int'], 20.132 + ['warp', 'int'], 20.133 + ['warpl', 'int'], 20.134 + ['warpu', 'int']]) 20.135 + val = fn(req.args, {'dom': self.dom.id}) 20.136 + return val 20.137 + 20.138 + def op_cpu_atropos_set(self, op, req): 20.139 + fn = FormFn(self.xd.domain_cpu_atropos_set, 20.140 + [['dom', 'str'], 20.141 + ['period', 'int'], 20.142 + ['slice', 'int'], 20.143 + ['latency', 'int'], 20.144 + ['xtratime', 'int']]) 20.145 + val = fn(req.args, {'dom': self.dom.id}) 20.146 + return val 20.147 + 20.148 + def op_maxmem_set(self, op, req): 20.149 + fn = FormFn(self.xd.domain_maxmem_set, 20.150 + [['dom', 'str'], 20.151 + ['memory', 'int']]) 20.152 + val = fn(req.args, {'dom': self.dom.id}) 20.153 + return val 20.154 + 20.155 + def op_device_create(self, op, req): 20.156 + fn = FormFn(self.xd.domain_device_create, 20.157 + [['dom', 'str'], 20.158 + ['config', 'sxpr']]) 20.159 + d = fn(req.args, {'dom': self.dom.id}) 20.160 + return d 20.161 + 20.162 + def op_device_destroy(self, op, req): 20.163 + fn = FormFn(self.xd.domain_device_destroy, 20.164 + [['dom', 'str'], 20.165 + ['type', 'str'], 20.166 + ['idx', 'str']]) 20.167 + val = fn(req.args, {'dom': self.dom.id}) 20.168 + return val 20.169 + 20.170 + def op_vifs(self, op, req): 20.171 + devs = self.xd.domain_vif_ls(self.dom.id) 20.172 + return [ dev.sxpr() for dev in devs ] 20.173 + 20.174 + def op_vif(self, op, req): 20.175 + fn = FormFn(self.xd.domain_vif_get, 20.176 + [['dom', 'str'], 20.177 + ['vif', 'str']]) 20.178 + val = fn(req.args, {'dom': self.dom.id}) 20.179 + return val 20.180 + 20.181 + def op_vbds(self, op, req): 20.182 + devs = self.xd.domain_vbd_ls(self.dom.id) 20.183 + return [ dev.sxpr() for dev in devs ] 20.184 + 20.185 + def op_vbd(self, op, req): 20.186 + fn = FormFn(self.xd.domain_vbd_get, 20.187 + [['dom', 'str'], 20.188 + ['vbd', 'str']]) 20.189 + val = fn(req.args, {'dom': self.dom.id}) 20.190 + return val 20.191 + 20.192 + def render_POST(self, req): 20.193 + return self.perform(req) 20.194 + 20.195 + def render_GET(self, req): 20.196 + op = req.args.get('op') 20.197 + if op and op[0] in ['vifs', 'vif', 'vbds', 'vbd']: 20.198 + return self.perform(req) 20.199 + if self.use_sxp(req): 20.200 + req.setHeader("Content-Type", sxp.mime_type) 20.201 + sxp.show(self.dom.sxpr(), out=req) 20.202 + else: 20.203 + req.write('<html><head></head><body>') 20.204 + self.print_path(req) 20.205 + #self.ls() 20.206 + req.write('<p>%s</p>' % self.dom) 20.207 + if self.dom.console: 20.208 + cinfo = self.dom.console 20.209 + cid = str(cinfo.console_port) 20.210 + #todo: Local xref: need to know server prefix. 20.211 + req.write('<p><a href="/xend/console/%s">Console %s</a></p>' 20.212 + % (cid, cid)) 20.213 + req.write('<p><a href="%s">Connect to console</a></p>' 20.214 + % cinfo.uri()) 20.215 + if self.dom.config: 20.216 + req.write("<code><pre>") 20.217 + PrettyPrint.prettyprint(self.dom.config, out=req) 20.218 + req.write("</pre></code>") 20.219 + self.form(req) 20.220 + req.write('</body></html>') 20.221 + return '' 20.222 + 20.223 + def form(self, req): 20.224 + url = req.prePathURL() 20.225 + req.write('<form method="post" action="%s">' % url) 20.226 + req.write('<input type="submit" name="op" value="unpause">') 20.227 + req.write('<input type="submit" name="op" value="pause">') 20.228 + req.write('</form>') 20.229 + 20.230 + req.write('<form method="post" action="%s">' % url) 20.231 + req.write('<input type="submit" name="op" value="destroy">') 20.232 + req.write('<input type="radio" name="reason" value="halt" checked>Halt') 20.233 + req.write('<input type="radio" name="reason" value="reboot">Reboot') 20.234 + req.write('</form>') 20.235 + 20.236 + req.write('<form method="post" action="%s">' % url) 20.237 + req.write('<input type="submit" name="op" value="shutdown">') 20.238 + req.write('<input type="radio" name="reason" value="poweroff" checked>Poweroff') 20.239 + req.write('<input type="radio" name="reason" value="halt">Halt') 20.240 + req.write('<input type="radio" name="reason" value="reboot">Reboot') 20.241 + req.write('</form>') 20.242 + 20.243 + req.write('<form method="post" action="%s">' % url) 20.244 + req.write('<br><input type="submit" name="op" value="save">') 20.245 + req.write(' To file: <input type="text" name="file">') 20.246 + req.write('</form>') 20.247 + 20.248 + req.write('<form method="post" action="%s">' % url) 20.249 + req.write('<br><input type="submit" name="op" value="migrate">') 20.250 + req.write(' To host: <input type="text" name="destination">') 20.251 + req.write('<input type="checkbox" name="live" value="1">Live') 20.252 + req.write('</form>')
21.1 --- a/tools/python/xen/xend/server/messages.py Wed Jan 19 08:53:39 2005 +0000 21.2 +++ b/tools/python/xen/xend/server/messages.py Wed Jan 19 13:20:15 2005 +0000 21.3 @@ -189,6 +189,70 @@ netif_formats = { 21.4 msg_formats.update(netif_formats) 21.5 21.6 #============================================================================ 21.7 +# USB interface message types. 21.8 +#============================================================================ 21.9 + 21.10 +CMSG_USBIF_BE = 8 21.11 +CMSG_USBIF_FE = 9 21.12 + 21.13 +CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED = 0 21.14 + 21.15 +CMSG_USBIF_FE_DRIVER_STATUS_CHANGED = 32 21.16 +CMSG_USBIF_FE_INTERFACE_CONNECT = 33 21.17 +CMSG_USBIF_FE_INTERFACE_DISCONNECT = 34 21.18 + 21.19 +USBIF_DRIVER_STATUS_DOWN = 0 21.20 +USBIF_DRIVER_STATUS_UP = 1 21.21 + 21.22 +USBIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */ 21.23 +USBIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */ 21.24 +USBIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */ 21.25 + 21.26 +CMSG_USBIF_BE_CREATE = 0 21.27 +CMSG_USBIF_BE_DESTROY = 1 21.28 +CMSG_USBIF_BE_CONNECT = 2 21.29 + 21.30 +CMSG_USBIF_BE_DISCONNECT = 3 21.31 +CMSG_USBIF_BE_CLAIM_PORT = 4 21.32 +CMSG_USBIF_BE_RELEASE_PORT = 5 21.33 + 21.34 +CMSG_USBIF_BE_DRIVER_STATUS_CHANGED = 32 21.35 + 21.36 +USBIF_BE_STATUS_OKAY = 0 21.37 +USBIF_BE_STATUS_ERROR = 1 21.38 + 21.39 +USBIF_BE_STATUS_INTERFACE_EXISTS = 2 21.40 +USBIF_BE_STATUS_INTERFACE_NOT_FOUND = 3 21.41 +USBIF_BE_STATUS_INTERFACE_CONNECTED = 4 21.42 +USBIF_BE_STATUS_OUT_OF_MEMORY = 7 21.43 +USBIF_BE_STATUS_MAPPING_ERROR = 9 21.44 + 21.45 +usbif_formats = { 21.46 + 'usbif_be_create_t': 21.47 + (CMSG_USBIF_BE, CMSG_USBIF_BE_CREATE), 21.48 + 'usbif_be_destroy_t': 21.49 + (CMSG_USBIF_BE, CMSG_USBIF_BE_DESTROY), 21.50 + 'usbif_be_connect_t': 21.51 + (CMSG_USBIF_BE, CMSG_USBIF_BE_CONNECT), 21.52 + 'usbif_be_disconnect_t': 21.53 + (CMSG_USBIF_BE, CMSG_USBIF_BE_DISCONNECT), 21.54 + 'usbif_be_claim_port_t': 21.55 + (CMSG_USBIF_BE, CMSG_USBIF_BE_CLAIM_PORT), 21.56 + 'usbif_be_release_port_t': 21.57 + (CMSG_USBIF_BE, CMSG_USBIF_BE_RELEASE_PORT), 21.58 + 'usbif_fe_interface_status_changed_t': 21.59 + (CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED), 21.60 + 'usbif_fe_driver_status_changed_t': 21.61 + (CMSG_USBIF_FE, CMSG_USBIF_FE_DRIVER_STATUS_CHANGED), 21.62 + 'usbif_fe_interface_connect_t': 21.63 + (CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_CONNECT), 21.64 + 'usbif_fe_interface_disconnect_t': 21.65 + (CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_DISCONNECT) 21.66 + } 21.67 + 21.68 +msg_formats.update(usbif_formats) 21.69 + 21.70 +#============================================================================ 21.71 # Domain shutdown message types. 21.72 #============================================================================ 21.73
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 22.2 +++ b/tools/python/xen/xend/server/usbif.py Wed Jan 19 13:20:15 2005 +0000 22.3 @@ -0,0 +1,368 @@ 22.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 22.5 +# Copyright (C) 2004 Intel Research Cambridge 22.6 +# Copyright (C) 2004 Mark Williamson <mark.williamson@cl.cam.ac.uk> 22.7 +"""Support for virtual USB hubs. 22.8 +""" 22.9 + 22.10 +from twisted.internet import defer 22.11 +#defer.Deferred.debug = 1 22.12 + 22.13 +from xen.xend import sxp 22.14 +from xen.xend.XendLogging import log 22.15 +from xen.xend.XendError import XendError 22.16 + 22.17 +import channel 22.18 +import controller 22.19 +from messages import * 22.20 + 22.21 +class UsbifBackendController(controller.BackendController): 22.22 + """ Handler for the 'back-end' channel to a USB hub domain. 22.23 + Must be connected using connect() before it can be used. 22.24 + Do not create directly - use getBackend() on the UsbifController. 22.25 + """ 22.26 + 22.27 + def __init__(self, ctrl, dom): 22.28 + controller.BackendController.__init__(self, ctrl, dom) 22.29 + self.connected = 0 22.30 + self.evtchn = None 22.31 + self.addMethod(CMSG_USBIF_BE, 22.32 + CMSG_USBIF_BE_DRIVER_STATUS_CHANGED, 22.33 + self.recv_be_driver_status_changed) 22.34 + self.registerChannel() 22.35 + 22.36 + def __str__(self): 22.37 + return '<UsbifBackendController %d>' % (self.dom) 22.38 + 22.39 + def recv_be_driver_status_changed(self, msg, req): 22.40 + """Request handler for be_driver_status_changed messages. 22.41 + 22.42 + @param msg: message 22.43 + @type msg: xu message 22.44 + @param req: request flag (true if the msg is a request) 22.45 + @type req: bool 22.46 + """ 22.47 + val = unpackMsg('usbif_be_driver_status_changed_t', msg) 22.48 + status = val['status'] 22.49 + 22.50 +class UsbifBackendInterface(controller.BackendInterface): 22.51 + """Handler for the 'back-end' channel to a network device driver domain 22.52 + on behalf of a front-end domain. 22.53 + 22.54 + Each network device is handled separately, so we add no functionality 22.55 + here. 22.56 + """ 22.57 + def __init__(self, ctrl, dom): 22.58 + controller.BackendInterface.__init__(self, ctrl, dom, 0) 22.59 + self.connected = 0 22.60 + self.connecting = False 22.61 + 22.62 + def connect(self, recreate=0): 22.63 + """Connect the controller to the usbif control interface. 22.64 + 22.65 + @param recreate: true if after xend restart 22.66 + @return: deferred 22.67 + """ 22.68 + log.debug("Connecting usbif %s", str(self)) 22.69 + if recreate or self.connected or self.connecting: 22.70 + d = defer.succeed(self) 22.71 + else: 22.72 + self.connecting = True 22.73 + d = self.send_be_create() 22.74 + d.addCallback(self.respond_be_create) 22.75 + return d 22.76 + 22.77 + def send_be_create(self): 22.78 + d = defer.Deferred() 22.79 + msg = packMsg('usbif_be_create_t', 22.80 + { 'domid' : self.controller.dom }) 22.81 + self.writeRequest(msg, response=d) 22.82 + return d 22.83 + 22.84 + def respond_be_create(self, msg): 22.85 + val = unpackMsg('usbif_be_create_t', msg) 22.86 + log.debug('>UsbifBackendController>respond_be_create> %s', str(val)) 22.87 + self.connected = True 22.88 + return self 22.89 + 22.90 + def destroy(self): 22.91 + """Disconnect from the usbif control interface and destroy it. 22.92 + """ 22.93 + def cb_destroy(val): 22.94 + self.send_be_destroy() 22.95 + d = defer.Deferred() 22.96 + d.addCallback(cb_destroy) 22.97 + self.send_be_disconnect(response=d) 22.98 + 22.99 + def send_be_disconnect(self, response=None): 22.100 + log.debug('>UsbifBackendController>send_be_disconnect> %s', str(self)) 22.101 + msg = packMsg('usbif_be_disconnect_t', 22.102 + { 'domid' : self.controller.dom }) 22.103 + self.writeRequest(msg, response=response) 22.104 + 22.105 + def send_be_destroy(self, response=None): 22.106 + log.debug('>UsbifBackendController>send_be_destroy> %s', str(self)) 22.107 + msg = packMsg('usbif_be_destroy_t', 22.108 + { 'domid' : self.controller.dom }) 22.109 + self.writeRequest(msg, response=response) 22.110 + 22.111 + def send_be_claim_port(self, path): 22.112 + d=defer.Deferred() 22.113 + log.debug(">UsbifBackendController>send_be_claim_port> about to claim port %s" % path) 22.114 + def cb(blah): log.debug(">UsbifBackendController> Claim port completed") 22.115 + d.addCallback(cb) 22.116 + msg = packMsg('usbif_be_claim_port_t', 22.117 + { 'domid' : self.controller.dom, 22.118 + 'path' : path, 22.119 + 'usbif_port' : self.controller.devices[path], 22.120 + 'status' : 0}) 22.121 + self.writeRequest(msg, response=d) 22.122 + # No need to add any callbacks, since the guest polls its virtual ports 22.123 + # anyhow, somewhat like a UHCI controller ;-) 22.124 + return d 22.125 + 22.126 + def send_be_release_port(self, path): 22.127 + d=defer.Deferred() 22.128 + def cb(blah): log.debug(">UsbifBackendController> Release port completed") 22.129 + d.addCallback(cb) 22.130 + msg = packMsg('usbif_be_release_port_t', 22.131 + { 'domid' : self.controller.dom, 22.132 + 'path' : path }) 22.133 + self.writeRequest(msg, response) 22.134 + # No need to add any callbacks, since the guest polls its virtual ports 22.135 + # anyhow, somewhat like a UHCI controller ;-) 22.136 + 22.137 + def connectInterface(self, val): 22.138 + self.evtchn = channel.eventChannel(0, self.controller.dom) 22.139 + log.debug(">UsbifBackendController>connectInterface> connecting usbif to event channel %s ports=%d:%d", 22.140 + str(self), self.evtchn['port1'], self.evtchn['port2']) 22.141 + msg = packMsg('usbif_be_connect_t', 22.142 + { 'domid' : self.controller.dom, 22.143 + 'evtchn' : self.evtchn['port1'], 22.144 + 'shmem_frame' : val['shmem_frame'], 22.145 + 'bandwidth' : 500 # XXX fix bandwidth! 22.146 + }) 22.147 + d = defer.Deferred() 22.148 + d.addCallback(self.respond_be_connect) 22.149 + self.writeRequest(msg, response=d) 22.150 + 22.151 + def respond_be_connect(self, msg): 22.152 + """Response handler for a be_connect message. 22.153 + 22.154 + @param msg: message 22.155 + @type msg: xu message 22.156 + """ 22.157 + val = unpackMsg('usbif_be_connect_t', msg) 22.158 + log.debug('>UsbifBackendController>respond_be_connect> %s, %s', str(self), str(val)) 22.159 + d = defer.Deferred() 22.160 + def cb(blah): 22.161 + log.debug(">UsbifBackendController> Successfully connected USB interface for domain %d" % self.controller.dom) 22.162 + self.controller.claim_ports() 22.163 + d.addCallback(cb) 22.164 + self.send_fe_interface_status_changed(d) 22.165 + 22.166 + def send_fe_interface_status_changed(self, response=None): 22.167 + msg = packMsg('usbif_fe_interface_status_changed_t', 22.168 + { 'status' : USBIF_INTERFACE_STATUS_CONNECTED, 22.169 + 'domid' : 0, ## FIXME: should be domid of backend 22.170 + 'evtchn' : self.evtchn['port2'], 22.171 + 'bandwidth' : 500, 22.172 + 'num_ports' : len(self.controller.devices.keys())}) 22.173 + self.controller.writeRequest(msg, response=response) 22.174 + 22.175 + 22.176 +class UsbifControllerFactory(controller.SplitControllerFactory): 22.177 + """Factory for creating USB interface controllers. 22.178 + """ 22.179 + 22.180 + def __init__(self): 22.181 + controller.ControllerFactory.__init__(self) 22.182 + self.backendControllers = {} 22.183 + 22.184 + def createController(self, dom, recreate=0): 22.185 + """Create a USB device controller for a domain. 22.186 + 22.187 + @param dom: domain 22.188 + @type dom: int 22.189 + @param recreate: if true it's a recreate (after xend restart) 22.190 + @type recreate: bool 22.191 + @return: block device controller 22.192 + @rtype: UsbifController 22.193 + """ 22.194 + usbif = self.getControllerByDom(dom) 22.195 + if usbif is None: 22.196 + usbif = UsbifController(self, dom) 22.197 + self.addController(usbif) 22.198 + return usbif 22.199 + 22.200 + def getDomainDevices(self, dom): 22.201 + """Get the block devices for a domain. 22.202 + 22.203 + @param dom: domain 22.204 + @type dom: int 22.205 + @return: devices 22.206 + @rtype: [device] 22.207 + """ 22.208 + usbif = self.getControllerByDom(dom) 22.209 + return (usbif and usbif.getDevices()) or [] 22.210 + 22.211 + def getDomainDevice(self, dom, vdev): 22.212 + """Get a block device from a domain. 22.213 + 22.214 + @param dom: domain 22.215 + @type dom: int 22.216 + @param vdev: device index 22.217 + @type vdev: int 22.218 + @return: device 22.219 + @rtype: device 22.220 + """ 22.221 + usbif = self.getControllerByDom(dom) 22.222 + return (usbif and usbif.getDevice(vdev)) or None 22.223 + 22.224 + def createBackendInterface(self, ctrl, dom, handle): 22.225 + """Create a network device backend interface. 22.226 + 22.227 + @param ctrl: controller 22.228 + @param dom: backend domain 22.229 + @param handle: interface handle 22.230 + @return: backend interface 22.231 + """ 22.232 + return UsbifBackendInterface(ctrl, dom) 22.233 + 22.234 + def getBackendController(self, dom): 22.235 + """Get the backend controller for a domain, creating 22.236 + if necessary. 22.237 + 22.238 + @param dom: backend domain 22.239 + @return: backend controller 22.240 + """ 22.241 + b = self.getBackendControllerByDomain(dom) 22.242 + if b is None: 22.243 + b = self.createBackendController(dom) 22.244 + self.backendControllers[b.dom] = b 22.245 + return b 22.246 + 22.247 + def createBackendController(self, dom): 22.248 + return UsbifBackendController(self, dom) 22.249 + 22.250 +class UsbifController(controller.SplitController): 22.251 + """USB device interface controller. Handles all USB devices 22.252 + for a domain. 22.253 + """ 22.254 + 22.255 + def __init__(self, factory, dom): 22.256 + """Create a USB device controller. 22.257 + Do not call directly - use createController() on the factory instead. 22.258 + """ 22.259 + controller.SplitController.__init__(self, factory, dom) 22.260 + self.num_ports = 0 22.261 + self.devices = {} 22.262 + self.addMethod(CMSG_USBIF_FE, 22.263 + CMSG_USBIF_FE_DRIVER_STATUS_CHANGED, 22.264 + self.recv_fe_driver_status_changed) 22.265 + self.addMethod(CMSG_USBIF_FE, 22.266 + CMSG_USBIF_FE_INTERFACE_CONNECT, 22.267 + self.recv_fe_interface_connect) 22.268 + self.registerChannel() 22.269 + try: 22.270 + self.backendDomain = 0 #int(sxp.child_value(config, 'backend', '0')) TODO: configurable backends 22.271 + except: 22.272 + raise XendError('invalid backend domain') 22.273 + 22.274 + 22.275 + def sxpr(self): 22.276 + val = ['usbif', ['dom', self.dom]] 22.277 + return val 22.278 + 22.279 + def createBackend(self, dom, handle): 22.280 + return UsbifBackendController(self, dom, handle) 22.281 + 22.282 + def getDevices(self): 22.283 + return self.devices.values() 22.284 + 22.285 + def attachDevice(self, path, recreate=0): 22.286 + """Add privileges for a particular device to the domain. 22.287 + @param path: the Linux-style path to the device port 22.288 + """ 22.289 + self.devices[path[1][1]] = self.num_ports 22.290 + self.num_ports += 1 22.291 + log.debug(">UsbifController>attachDevice> device: %s, port: %d" % 22.292 + (str(path), self.num_ports ) ) 22.293 + 22.294 + backend =self.getBackendInterface(self.backendDomain) 22.295 + 22.296 + def cb(blah): 22.297 + log.debug(">UsbifController> Backend created") 22.298 + pass 22.299 + d = backend.connect() 22.300 + d.addCallback(cb) # Chaining the claim port operation 22.301 + return d 22.302 + 22.303 + 22.304 + def removeDevice(self, path): 22.305 + self.delDevice(path) 22.306 + backend = self.getBackendInterface(self.backendDomain) 22.307 + return backend.send_be_release_port(path) 22.308 + 22.309 + def delDevice(self, path): 22.310 + if path in self.devices: 22.311 + del self.devices[path] 22.312 + 22.313 + def attachPort(self, path, recreate=0): 22.314 + """Attach a device to the specified interface. 22.315 + On success the returned deferred will be called with the device. 22.316 + 22.317 + @return: deferred 22.318 + @rtype: Deferred 22.319 + """ 22.320 + return self.attachDevice(path) 22.321 + 22.322 + def destroy(self): 22.323 + """Destroy the controller and all devices. 22.324 + """ 22.325 + log.debug("Destroying usbif domain=%d", self.dom) 22.326 + self.destroyBackends() 22.327 + 22.328 + def destroyDevices(self): 22.329 + """Destroy all devices. 22.330 + """ 22.331 + for path in self.getDevices(): 22.332 + self.removeDevice(path) 22.333 + 22.334 + def destroyBackends(self): 22.335 + for backend in self.getBackendInterfaces(): 22.336 + backend.destroy() 22.337 + 22.338 + def recv_fe_driver_status_changed(self, msg, req): 22.339 + val = unpackMsg('usbif_fe_driver_status_changed_t', msg) 22.340 + log.debug('>UsbifController>recv_fe_driver_status_changed> %s', str(val)) 22.341 + # For each backend? 22.342 + msg = packMsg('usbif_fe_interface_status_changed_t', 22.343 + { 'status' : USBIF_INTERFACE_STATUS_DISCONNECTED, 22.344 + 'domid' : 0, ## FIXME: should be domid of backend 22.345 + 'evtchn' : 0 }) 22.346 + d = defer.Deferred() 22.347 + d.addCallback(self.disconnected_resp) 22.348 + self.writeRequest(msg) 22.349 + 22.350 + def disconnected_resp(self, msg): 22.351 + val = unpackMsg('usbif_fe_interface_status_changed_t', msg) 22.352 + if val['status'] != USBIF_INTERFACE_STATUS_DISCONNECTED: 22.353 + log.error(">UsbifController>disconnected_resp> unexpected status change") 22.354 + else: 22.355 + log.debug(">UsbifController>disconnected_resp> interface disconnected OK") 22.356 + 22.357 + def recv_fe_interface_connect(self, msg, req): 22.358 + val = unpackMsg('usbif_fe_interface_status_changed_t', msg) 22.359 + log.debug(">UsbifController>recv_fe_interface_connect> notifying backend") 22.360 + backend = self.getBackendInterfaceByHandle(0) 22.361 + if backend: 22.362 + d = backend.connectInterface(val) 22.363 + else: 22.364 + log.error('>UsbifController>recv_fe_interface_connect> unknown interface') 22.365 + 22.366 + def claim_ports(self): 22.367 + backend = self.getBackendInterfaceByHandle(0) 22.368 + for path in self.devices.keys(): 22.369 + log.debug(">UsbifController>claim_ports> claiming port... %s" % path) 22.370 + backend.send_be_claim_port(path) 22.371 +
23.1 --- a/tools/python/xen/xm/create.py Wed Jan 19 08:53:39 2005 +0000 23.2 +++ b/tools/python/xen/xm/create.py Wed Jan 19 13:20:15 2005 +0000 23.3 @@ -151,6 +151,11 @@ gopts.var('pci', val='BUS,DEV,FUNC', 23.4 For example '-pci c0,02,1a'. 23.5 The option may be repeated to add more than one pci device.""") 23.6 23.7 +gopts.var('usb', val='PATH', 23.8 + fn=append_value, default=[], 23.9 + use="""Add a physical USB port to a domain, as specified by the path 23.10 + to that port. This option may be repeated to add more than one port.""") 23.11 + 23.12 gopts.var('ipaddr', val="IPADDR", 23.13 fn=append_value, default=[], 23.14 use="Add an IP address to the domain.") 23.15 @@ -273,6 +278,11 @@ def configure_pci(config_devs, vals): 23.16 config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]] 23.17 config_devs.append(['device', config_pci]) 23.18 23.19 +def configure_usb(config_devs, vals): 23.20 + for path in vals.usb: 23.21 + config_usb = ['usb', ['path', path]] 23.22 + config_devs.append(['device', config_usb]) 23.23 + 23.24 def randomMAC(): 23.25 """Generate a random MAC address. 23.26 23.27 @@ -371,6 +381,7 @@ def make_config(vals): 23.28 configure_disks(config_devs, vals) 23.29 configure_pci(config_devs, vals) 23.30 configure_vifs(config_devs, vals) 23.31 + configure_usb(config_devs, vals) 23.32 configure_vmx(config_devs, vals) 23.33 config += config_devs 23.34 return config
24.1 --- a/xen/include/public/io/domain_controller.h Wed Jan 19 08:53:39 2005 +0000 24.2 +++ b/xen/include/public/io/domain_controller.h Wed Jan 19 13:20:15 2005 +0000 24.3 @@ -64,7 +64,8 @@ typedef struct { 24.4 #define CMSG_NETIF_FE 4 /* Network-device frontend */ 24.5 #define CMSG_SHUTDOWN 6 /* Shutdown messages */ 24.6 #define CMSG_MEM_REQUEST 7 /* Memory reservation reqs */ 24.7 - 24.8 +#define CMSG_USBIF_BE 8 /* USB controller backend */ 24.9 +#define CMSG_USBIF_FE 9 /* USB controller frontend */ 24.10 24.11 /****************************************************************************** 24.12 * CONSOLE DEFINITIONS 24.13 @@ -554,6 +555,208 @@ typedef struct { 24.14 } PACKED netif_be_driver_status_t; /* 4 bytes */ 24.15 24.16 24.17 + 24.18 +/****************************************************************************** 24.19 + * USB-INTERFACE FRONTEND DEFINITIONS 24.20 + */ 24.21 + 24.22 +/* Messages from domain controller to guest. */ 24.23 +#define CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED 0 24.24 + 24.25 +/* Messages from guest to domain controller. */ 24.26 +#define CMSG_USBIF_FE_DRIVER_STATUS_CHANGED 32 24.27 +#define CMSG_USBIF_FE_INTERFACE_CONNECT 33 24.28 +#define CMSG_USBIF_FE_INTERFACE_DISCONNECT 34 24.29 +/* 24.30 + * CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED: 24.31 + * Notify a guest about a status change on one of its block interfaces. 24.32 + * If the interface is DESTROYED or DOWN then the interface is disconnected: 24.33 + * 1. The shared-memory frame is available for reuse. 24.34 + * 2. Any unacknowledged messages pending on the interface were dropped. 24.35 + */ 24.36 +#define USBIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */ 24.37 +#define USBIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */ 24.38 +#define USBIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */ 24.39 +typedef struct { 24.40 + u32 status; /* 0 */ 24.41 + u16 evtchn; /* 4: (only if status == BLKIF_INTERFACE_STATUS_CONNECTED). */ 24.42 + domid_t domid; /* 6: status != BLKIF_INTERFACE_STATUS_DESTROYED */ 24.43 + u32 bandwidth; /* 8 */ 24.44 + u32 num_ports; /* 12 */ 24.45 +} PACKED usbif_fe_interface_status_changed_t; /* 12 bytes */ 24.46 + 24.47 +/* 24.48 + * CMSG_USBIF_FE_DRIVER_STATUS_CHANGED: 24.49 + * Notify the domain controller that the front-end driver is DOWN or UP. 24.50 + * When the driver goes DOWN then the controller will send no more 24.51 + * status-change notifications. 24.52 + * If the driver goes DOWN while interfaces are still UP, the domain 24.53 + * will automatically take the interfaces DOWN. 24.54 + * 24.55 + * NB. The controller should not send an INTERFACE_STATUS_CHANGED message 24.56 + * for interfaces that are active when it receives an UP notification. We 24.57 + * expect that the frontend driver will query those interfaces itself. 24.58 + */ 24.59 +#define USBIF_DRIVER_STATUS_DOWN 0 24.60 +#define USBIF_DRIVER_STATUS_UP 1 24.61 +typedef struct { 24.62 + /* IN */ 24.63 + u32 status; /* 0: USBIF_DRIVER_STATUS_??? */ 24.64 +} PACKED usbif_fe_driver_status_changed_t; /* 4 bytes */ 24.65 + 24.66 +/* 24.67 + * CMSG_USBIF_FE_INTERFACE_CONNECT: 24.68 + * If successful, the domain controller will acknowledge with a 24.69 + * STATUS_CONNECTED message. 24.70 + */ 24.71 +typedef struct { 24.72 + u32 __pad; 24.73 + memory_t shmem_frame; /* 8 */ 24.74 + MEMORY_PADDING; 24.75 +} PACKED usbif_fe_interface_connect_t; /* 16 bytes */ 24.76 + 24.77 +/* 24.78 + * CMSG_BLKIF_FE_INTERFACE_DISCONNECT: 24.79 + * If successful, the domain controller will acknowledge with a 24.80 + * STATUS_DISCONNECTED message. 24.81 + */ 24.82 +typedef struct {} PACKED usbif_fe_interface_disconnect_t; /* 4 bytes */ 24.83 + 24.84 + 24.85 +/****************************************************************************** 24.86 + * USB-INTERFACE BACKEND DEFINITIONS 24.87 + */ 24.88 + 24.89 +/* Messages from domain controller. */ 24.90 +#define CMSG_USBIF_BE_CREATE 0 /* Create a new block-device interface. */ 24.91 +#define CMSG_USBIF_BE_DESTROY 1 /* Destroy a block-device interface. */ 24.92 +#define CMSG_USBIF_BE_CONNECT 2 /* Connect i/f to remote driver. */ 24.93 +#define CMSG_USBIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */ 24.94 +#define CMSG_USBIF_BE_CLAIM_PORT 4 /* Claim host port for a domain. */ 24.95 +#define CMSG_USBIF_BE_RELEASE_PORT 5 /* Release host port. */ 24.96 +/* Messages to domain controller. */ 24.97 +#define CMSG_USBIF_BE_DRIVER_STATUS_CHANGED 32 24.98 + 24.99 +/* Non-specific 'okay' return. */ 24.100 +#define USBIF_BE_STATUS_OKAY 0 24.101 +/* Non-specific 'error' return. */ 24.102 +#define USBIF_BE_STATUS_ERROR 1 24.103 +/* The following are specific error returns. */ 24.104 +#define USBIF_BE_STATUS_INTERFACE_EXISTS 2 24.105 +#define USBIF_BE_STATUS_INTERFACE_NOT_FOUND 3 24.106 +#define USBIF_BE_STATUS_INTERFACE_CONNECTED 4 24.107 +#define USBIF_BE_STATUS_OUT_OF_MEMORY 7 24.108 +#define USBIF_BE_STATUS_MAPPING_ERROR 9 24.109 + 24.110 +/* This macro can be used to create an array of descriptive error strings. */ 24.111 +#define USBIF_BE_STATUS_ERRORS { \ 24.112 + "Okay", \ 24.113 + "Non-specific error", \ 24.114 + "Interface already exists", \ 24.115 + "Interface not found", \ 24.116 + "Interface is still connected", \ 24.117 + "Out of memory", \ 24.118 + "Could not map domain memory" } 24.119 + 24.120 +/* 24.121 + * CMSG_USBIF_BE_CREATE: 24.122 + * When the driver sends a successful response then the interface is fully 24.123 + * created. The controller will send a DOWN notification to the front-end 24.124 + * driver. 24.125 + */ 24.126 +typedef struct { 24.127 + /* IN */ 24.128 + domid_t domid; /* 0: Domain attached to new interface. */ 24.129 + u16 __pad; 24.130 + /* OUT */ 24.131 + u32 status; /* 8 */ 24.132 +} PACKED usbif_be_create_t; /* 12 bytes */ 24.133 + 24.134 +/* 24.135 + * CMSG_USBIF_BE_DESTROY: 24.136 + * When the driver sends a successful response then the interface is fully 24.137 + * torn down. The controller will send a DESTROYED notification to the 24.138 + * front-end driver. 24.139 + */ 24.140 +typedef struct { 24.141 + /* IN */ 24.142 + domid_t domid; /* 0: Identify interface to be destroyed. */ 24.143 + u16 __pad; 24.144 + /* OUT */ 24.145 + u32 status; /* 8 */ 24.146 +} PACKED usbif_be_destroy_t; /* 12 bytes */ 24.147 + 24.148 +/* 24.149 + * CMSG_USBIF_BE_CONNECT: 24.150 + * When the driver sends a successful response then the interface is fully 24.151 + * connected. The controller will send a CONNECTED notification to the 24.152 + * front-end driver. 24.153 + */ 24.154 +typedef struct { 24.155 + /* IN */ 24.156 + domid_t domid; /* 0: Domain attached to new interface. */ 24.157 + u16 __pad; 24.158 + memory_t shmem_frame; /* 8: Page cont. shared comms window. */ 24.159 + MEMORY_PADDING; 24.160 + u32 evtchn; /* 16: Event channel for notifications. */ 24.161 + u32 bandwidth; /* 20: Bandwidth allocated for isoch / int - us 24.162 + * per 1ms frame (ie between 0 and 900 or 800 24.163 + * depending on USB version). */ 24.164 + /* OUT */ 24.165 + u32 status; /* 24 */ 24.166 +} PACKED usbif_be_connect_t; /* 28 bytes */ 24.167 + 24.168 +/* 24.169 + * CMSG_USBIF_BE_DISCONNECT: 24.170 + * When the driver sends a successful response then the interface is fully 24.171 + * disconnected. The controller will send a DOWN notification to the front-end 24.172 + * driver. 24.173 + */ 24.174 +typedef struct { 24.175 + /* IN */ 24.176 + domid_t domid; /* 0: Domain attached to new interface. */ 24.177 + u16 __pad; 24.178 + /* OUT */ 24.179 + u32 status; /* 8 */ 24.180 +} PACKED usbif_be_disconnect_t; /* 12 bytes */ 24.181 + 24.182 +/* 24.183 + * CMSG_USBIF_BE_DRIVER_STATUS_CHANGED: 24.184 + * Notify the domain controller that the back-end driver is DOWN or UP. 24.185 + * If the driver goes DOWN while interfaces are still UP, the controller 24.186 + * will automatically send DOWN notifications. 24.187 + */ 24.188 +typedef struct { 24.189 + u32 status; /* 0: USBIF_DRIVER_STATUS_??? */ 24.190 +} PACKED usbif_be_driver_status_changed_t; /* 4 bytes */ 24.191 + 24.192 +#define USB_PATH_LEN 16 24.193 + 24.194 +/* 24.195 + * CMSG_USBIF_BE_CLAIM_PORT: 24.196 + * Instruct the backend driver to claim any device plugged into the specified 24.197 + * host port and to allow the specified domain to control that port. 24.198 + */ 24.199 +typedef struct 24.200 +{ 24.201 + /* IN */ 24.202 + domid_t domid; /* 0: which domain */ 24.203 + u32 usbif_port; /* 6: port on the virtual root hub */ 24.204 + u32 status; /* 10: status of operation */ 24.205 + char path[USB_PATH_LEN]; /* Currently specified in the Linux style - may need to be 24.206 + * converted to some OS-independent format at some stage. */ 24.207 +} PACKED usbif_be_claim_port_t; 24.208 + 24.209 +/* 24.210 + * CMSG_USBIF_BE_RELEASE_PORT: 24.211 + * Instruct the backend driver to release any device plugged into the specified 24.212 + * host port. 24.213 + */ 24.214 +typedef struct 24.215 +{ 24.216 + char path[USB_PATH_LEN]; 24.217 +} PACKED usbif_be_release_port_t; 24.218 + 24.219 /****************************************************************************** 24.220 * SHUTDOWN DEFINITIONS 24.221 */
25.1 --- a/xen/include/public/xen.h Wed Jan 19 08:53:39 2005 +0000 25.2 +++ b/xen/include/public/xen.h Wed Jan 19 13:20:15 2005 +0000 25.3 @@ -426,7 +426,7 @@ typedef struct { 25.4 #define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */ 25.5 #define SIF_BLK_BE_DOMAIN (1<<4) /* Is this a block backend domain? */ 25.6 #define SIF_NET_BE_DOMAIN (1<<5) /* Is this a net backend domain? */ 25.7 - 25.8 +#define SIF_USB_BE_DOMAIN (1<<6) /* Is this a usb backend domain? */ 25.9 /* For use in guest OSes. */ 25.10 extern shared_info_t *HYPERVISOR_shared_info; 25.11