[pve-devel] r6561 - in pve-qemu-kvm/trunk: . debian debian/patches

svn-commits at proxmox.com svn-commits at proxmox.com
Fri Oct 14 16:34:48 CEST 2011


Author: dietmar
Date: 2011-10-14 16:34:48 +0200 (Fri, 14 Oct 2011)
New Revision: 6561

Added:
   pve-qemu-kvm/trunk/debian/patches/0001-usb-host-reapurb-error-report-fix.patch
   pve-qemu-kvm/trunk/debian/patches/0002-usb-host-fix-halted-endpoints.patch
   pve-qemu-kvm/trunk/debian/patches/0003-usb-host-fix-configuration-tracking.patch
   pve-qemu-kvm/trunk/debian/patches/0004-usb-host-endpoint-table-fixup.patch
   pve-qemu-kvm/trunk/debian/patches/0005-usb-ehci-handle-siTDs.patch
   pve-qemu-kvm/trunk/debian/patches/0006-usb-fix-use-after-free.patch
   pve-qemu-kvm/trunk/debian/patches/0007-usb-claim-port-at-device-initialization-time.patch
Modified:
   pve-qemu-kvm/trunk/Makefile
   pve-qemu-kvm/trunk/debian/changelog
   pve-qemu-kvm/trunk/debian/patches/series
Log:
add usb fixes


Modified: pve-qemu-kvm/trunk/Makefile
===================================================================
--- pve-qemu-kvm/trunk/Makefile	2011-10-12 04:32:05 UTC (rev 6560)
+++ pve-qemu-kvm/trunk/Makefile	2011-10-14 14:34:48 UTC (rev 6561)
@@ -1,8 +1,8 @@
-RELEASE=1.8
+RELEASE=1.9
 
 # also update debian/changelog
 KVMVER=0.15.0
-KVMPKGREL=1
+KVMPKGREL=2
 
 KVMPACKAGE=pve-qemu-kvm
 KVMDIR=qemu-kvm

Modified: pve-qemu-kvm/trunk/debian/changelog
===================================================================
--- pve-qemu-kvm/trunk/debian/changelog	2011-10-12 04:32:05 UTC (rev 6560)
+++ pve-qemu-kvm/trunk/debian/changelog	2011-10-14 14:34:48 UTC (rev 6561)
@@ -1,3 +1,9 @@
+pve-qemu-kvm (0.15.0-2) unstable; urgency=low
+
+  * include usb fixes 
+
+ -- Proxmox Support Team <support at proxmox.com>  Fri, 14 Oct 2011 16:30:56 +0200
+
 pve-qemu-kvm (0.15.0-1) unstable; urgency=low
 
   * update to upstream 0.15.0

Added: pve-qemu-kvm/trunk/debian/patches/0001-usb-host-reapurb-error-report-fix.patch
===================================================================
--- pve-qemu-kvm/trunk/debian/patches/0001-usb-host-reapurb-error-report-fix.patch	                        (rev 0)
+++ pve-qemu-kvm/trunk/debian/patches/0001-usb-host-reapurb-error-report-fix.patch	2011-10-14 14:34:48 UTC (rev 6561)
@@ -0,0 +1,36 @@
+From 21d7691889fc7da34b20a73b7ee870d15b49267d Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Fri, 2 Sep 2011 11:32:27 +0200
+Subject: [PATCH] usb-host: reapurb error report fix
+
+Don't report errors on devices which are in disconnected
+and closing state.
+(cherry picked from commit 3d09d54e57b92aaaba8d4e8c0d1c9901f1a56c7f)
+
+Conflicts:
+
+	usb-linux.c
+---
+ usb-linux.c |    6 ++++--
+ 1 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/usb-linux.c b/usb-linux.c
+index 53cc5fc..7d8a103 100644
+--- a/usb-linux.c
++++ b/usb-linux.c
+@@ -308,8 +308,10 @@ static void async_complete(void *opaque)
+                 }
+                 return;
+             }
+-            if (errno == ENODEV && !s->closing) {
+-                do_disconnect(s);
++            if (errno == ENODEV) {
++                if (!s->closing) {
++                    do_disconnect(s);
++                }
+                 return;
+             }
+ 
+-- 
+1.5.6.5
+

Added: pve-qemu-kvm/trunk/debian/patches/0002-usb-host-fix-halted-endpoints.patch
===================================================================
--- pve-qemu-kvm/trunk/debian/patches/0002-usb-host-fix-halted-endpoints.patch	                        (rev 0)
+++ pve-qemu-kvm/trunk/debian/patches/0002-usb-host-fix-halted-endpoints.patch	2011-10-14 14:34:48 UTC (rev 6561)
@@ -0,0 +1,64 @@
+From c166f8dbb0db59eab6735e54dc2568e90c181d21 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 24 Aug 2011 10:55:40 +0200
+Subject: [PATCH] usb-host: fix halted endpoints
+
+Two fixes for the price of one ;)
+
+First, reinitialize the endpoint table after device reset.
+This is needed anyway as the reset might have switched interfaces.
+It also clears the endpoint halted state.
+
+Second the CLEAR_HALT ioctl wants a unsigned int passed in as
+argument, not uint8_t.
+
+This gets my usb sd card reader (sandisk micromate) going.
+
+Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
+(cherry picked from commit a8b44be4da11ba57ab3219a55eecbc422663c9b3)
+---
+ usb-linux.c |    7 ++++---
+ 1 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/usb-linux.c b/usb-linux.c
+index 7d8a103..1d0ccf8 100644
+--- a/usb-linux.c
++++ b/usb-linux.c
+@@ -142,6 +142,7 @@ static int parse_filter(const char *spec, struct USBAutoFilter *f);
+ static void usb_host_auto_check(void *unused);
+ static int usb_host_read_file(char *line, size_t line_size,
+                             const char *device_file, const char *device_name);
++static int usb_linux_update_endp_table(USBHostDevice *s);
+ 
+ static struct endp_data *get_endp(USBHostDevice *s, int ep)
+ {
+@@ -509,6 +510,7 @@ static void usb_host_handle_reset(USBDevice *dev)
+     ioctl(s->fd, USBDEVFS_RESET);
+ 
+     usb_host_claim_interfaces(s, s->configuration);
++    usb_linux_update_endp_table(s);
+ }
+ 
+ static void usb_host_handle_destroy(USBDevice *dev)
+@@ -520,8 +522,6 @@ static void usb_host_handle_destroy(USBDevice *dev)
+     qemu_remove_exit_notifier(&s->exit);
+ }
+ 
+-static int usb_linux_update_endp_table(USBHostDevice *s);
+-
+ /* iso data is special, we need to keep enough urbs in flight to make sure
+    that the controller never runs out of them, otherwise the device will
+    likely suffer a buffer underrun / overrun. */
+@@ -723,7 +723,8 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
+     }
+ 
+     if (is_halted(s, p->devep)) {
+-        ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
++        unsigned int arg = ep;
++        ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
+         if (ret < 0) {
+             DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
+                    ep, errno);
+-- 
+1.5.6.5
+

Added: pve-qemu-kvm/trunk/debian/patches/0003-usb-host-fix-configuration-tracking.patch
===================================================================
--- pve-qemu-kvm/trunk/debian/patches/0003-usb-host-fix-configuration-tracking.patch	                        (rev 0)
+++ pve-qemu-kvm/trunk/debian/patches/0003-usb-host-fix-configuration-tracking.patch	2011-10-14 14:34:48 UTC (rev 6561)
@@ -0,0 +1,175 @@
+From 154875f43c2188620f48ec70d713e545e493da35 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Wed, 24 Aug 2011 14:45:07 +0200
+Subject: [PATCH] usb-host: fix configuration tracking.
+
+It is perfectly fine to leave the usb device in unconfigured state
+(USBHostDevice->configuration == 0).  Just do that and wait for the
+guest to explicitly set a configuration.  This is closer to what real
+hardware does and it also simplifies the device initialization.  There
+is no need to figure how the device is configured on the host.
+
+Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
+(cherry picked from commit b2d7c159824b5cf6af797e8bf52243fcbb42395a)
+---
+ usb-linux.c |   82 +++++++++++++---------------------------------------------
+ 1 files changed, 19 insertions(+), 63 deletions(-)
+
+diff --git a/usb-linux.c b/usb-linux.c
+index 1d0ccf8..74f1a0b 100644
+--- a/usb-linux.c
++++ b/usb-linux.c
+@@ -397,8 +397,11 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
+     int interface, nb_interfaces;
+     int ret, i;
+ 
+-    if (configuration == 0) /* address state - ignore */
++    if (configuration == 0) { /* address state - ignore */
++        dev->ninterfaces   = 0;
++        dev->configuration = 0;
+         return 1;
++    }
+ 
+     DPRINTF("husb: claiming interfaces. config %d\n", configuration);
+ 
+@@ -423,7 +426,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
+ 
+         printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
+ 
+-        if (configuration < 0 || configuration == dev->descr[i + 5]) {
++        if (configuration == dev->descr[i + 5]) {
+             configuration = dev->descr[i + 5];
+             break;
+         }
+@@ -509,7 +512,7 @@ static void usb_host_handle_reset(USBDevice *dev)
+ 
+     ioctl(s->fd, USBDEVFS_RESET);
+ 
+-    usb_host_claim_interfaces(s, s->configuration);
++    usb_host_claim_interfaces(s, 0);
+     usb_linux_update_endp_table(s);
+ }
+ 
+@@ -810,6 +813,7 @@ static int usb_host_set_config(USBHostDevice *s, int config)
+         return ctrl_error();
+     }
+     usb_host_claim_interfaces(s, config);
++    usb_linux_update_endp_table(s);
+     return 0;
+ }
+ 
+@@ -913,51 +917,6 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
+     return USB_RET_ASYNC;
+ }
+ 
+-static int usb_linux_get_configuration(USBHostDevice *s)
+-{
+-    uint8_t configuration;
+-    struct usb_ctrltransfer ct;
+-    int ret;
+-
+-    if (usb_fs_type == USB_FS_SYS) {
+-        char device_name[32], line[1024];
+-        int configuration;
+-
+-        sprintf(device_name, "%d-%s", s->bus_num, s->port);
+-
+-        if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
+-                                device_name)) {
+-            goto usbdevfs;
+-        }
+-        if (sscanf(line, "%d", &configuration) != 1) {
+-            goto usbdevfs;
+-        }
+-        return configuration;
+-    }
+-
+-usbdevfs:
+-    ct.bRequestType = USB_DIR_IN;
+-    ct.bRequest = USB_REQ_GET_CONFIGURATION;
+-    ct.wValue = 0;
+-    ct.wIndex = 0;
+-    ct.wLength = 1;
+-    ct.data = &configuration;
+-    ct.timeout = 50;
+-
+-    ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
+-    if (ret < 0) {
+-        perror("usb_linux_get_configuration");
+-        return -1;
+-    }
+-
+-    /* in address state */
+-    if (configuration == 0) {
+-        return -1;
+-    }
+-
+-    return configuration;
+-}
+-
+ static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
+     uint8_t configuration, uint8_t interface)
+ {
+@@ -1003,16 +962,16 @@ usbdevfs:
+ static int usb_linux_update_endp_table(USBHostDevice *s)
+ {
+     uint8_t *descriptors;
+-    uint8_t devep, type, configuration, alt_interface;
++    uint8_t devep, type, alt_interface;
+     int interface, length, i;
+ 
+     for (i = 0; i < MAX_ENDPOINTS; i++)
+         s->endp_table[i].type = INVALID_EP_TYPE;
+ 
+-    i = usb_linux_get_configuration(s);
+-    if (i < 0)
+-        return 1;
+-    configuration = i;
++    if (s->configuration == 0) {
++        /* not configured yet -- leave all endpoints disabled */
++        return 0;
++    }
+ 
+     /* get the desired configuration, interface, and endpoint descriptors
+      * from device description */
+@@ -1021,8 +980,9 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
+     i = 0;
+ 
+     if (descriptors[i + 1] != USB_DT_CONFIG ||
+-        descriptors[i + 5] != configuration) {
+-        DPRINTF("invalid descriptor data - configuration\n");
++        descriptors[i + 5] != s->configuration) {
++        fprintf(stderr, "invalid descriptor data - configuration %d\n",
++                s->configuration);
+         return 1;
+     }
+     i += descriptors[i];
+@@ -1036,7 +996,8 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
+         }
+ 
+         interface = descriptors[i + 2];
+-        alt_interface = usb_linux_get_alt_setting(s, configuration, interface);
++        alt_interface = usb_linux_get_alt_setting(s, s->configuration,
++                                                  interface);
+ 
+         /* the current interface descriptor is the active interface
+          * and has endpoints */
+@@ -1175,13 +1136,8 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
+ #endif
+ 
+ 
+-    /*
+-     * Initial configuration is -1 which makes us claim first
+-     * available config. We used to start with 1, which does not
+-     * always work. I've seen devices where first config starts
+-     * with 2.
+-     */
+-    if (!usb_host_claim_interfaces(dev, -1)) {
++    /* start unconfigured -- we'll wait for the guest to set a configuration */
++    if (!usb_host_claim_interfaces(dev, 0)) {
+         goto fail;
+     }
+ 
+-- 
+1.5.6.5
+

Added: pve-qemu-kvm/trunk/debian/patches/0004-usb-host-endpoint-table-fixup.patch
===================================================================
--- pve-qemu-kvm/trunk/debian/patches/0004-usb-host-endpoint-table-fixup.patch	                        (rev 0)
+++ pve-qemu-kvm/trunk/debian/patches/0004-usb-host-endpoint-table-fixup.patch	2011-10-14 14:34:48 UTC (rev 6561)
@@ -0,0 +1,450 @@
+From aec30fcfcf41918e52eeb987a61d04e8345a62b9 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Fri, 2 Sep 2011 11:37:51 +0200
+Subject: [PATCH] usb-host: endpoint table fixup
+
+USB Devices can have up to 15 IN and 15 OUT endpoints, not 15 endpoints
+total.  Move from one array to two arrays (one IN, one OUT) to maintain
+the endpoint state.
+(cherry picked from commit 07d4920d2bca19c64827a226b0afdfe8c7f1e3f0)
+
+Conflicts:
+
+	usb-linux.c
+---
+ usb-linux.c |  178 +++++++++++++++++++++++++++++++++-------------------------
+ 1 files changed, 101 insertions(+), 77 deletions(-)
+
+diff --git a/usb-linux.c b/usb-linux.c
+index 74f1a0b..c1c2349 100644
+--- a/usb-linux.c
++++ b/usb-linux.c
+@@ -123,7 +123,8 @@ typedef struct USBHostDevice {
+     uint32_t  iso_urb_count;
+     Notifier  exit;
+ 
+-    struct endp_data endp_table[MAX_ENDPOINTS];
++    struct endp_data ep_in[MAX_ENDPOINTS];
++    struct endp_data ep_out[MAX_ENDPOINTS];
+     QLIST_HEAD(, AsyncURB) aurbs;
+ 
+     /* Host side address */
+@@ -144,94 +145,101 @@ static int usb_host_read_file(char *line, size_t line_size,
+                             const char *device_file, const char *device_name);
+ static int usb_linux_update_endp_table(USBHostDevice *s);
+ 
+-static struct endp_data *get_endp(USBHostDevice *s, int ep)
++static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep)
+ {
+-    return s->endp_table + ep - 1;
++    struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out;
++    assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
++    assert(ep > 0 && ep <= MAX_ENDPOINTS);
++    return eps + ep - 1;
+ }
+ 
+-static int is_isoc(USBHostDevice *s, int ep)
++static int is_isoc(USBHostDevice *s, int pid, int ep)
+ {
+-    return get_endp(s, ep)->type == USBDEVFS_URB_TYPE_ISO;
++    return get_endp(s, pid, ep)->type == USBDEVFS_URB_TYPE_ISO;
+ }
+ 
+-static int is_valid(USBHostDevice *s, int ep)
++static int is_valid(USBHostDevice *s, int pid, int ep)
+ {
+-    return get_endp(s, ep)->type != INVALID_EP_TYPE;
++    return get_endp(s, pid, ep)->type != INVALID_EP_TYPE;
+ }
+ 
+-static int is_halted(USBHostDevice *s, int ep)
++static int is_halted(USBHostDevice *s, int pid, int ep)
+ {
+-    return get_endp(s, ep)->halted;
++    return get_endp(s, pid, ep)->halted;
+ }
+ 
+-static void clear_halt(USBHostDevice *s, int ep)
++static void clear_halt(USBHostDevice *s, int pid, int ep)
+ {
+-    get_endp(s, ep)->halted = 0;
++    get_endp(s, pid, ep)->halted = 0;
+ }
+ 
+-static void set_halt(USBHostDevice *s, int ep)
++static void set_halt(USBHostDevice *s, int pid, int ep)
+ {
+-    get_endp(s, ep)->halted = 1;
++    if (ep != 0) {
++        get_endp(s, pid, ep)->halted = 1;
++    }
+ }
+ 
+-static int is_iso_started(USBHostDevice *s, int ep)
++static int is_iso_started(USBHostDevice *s, int pid, int ep)
+ {
+-    return get_endp(s, ep)->iso_started;
++    return get_endp(s, pid, ep)->iso_started;
+ }
+ 
+-static void clear_iso_started(USBHostDevice *s, int ep)
++static void clear_iso_started(USBHostDevice *s, int pid, int ep)
+ {
+-    get_endp(s, ep)->iso_started = 0;
++    get_endp(s, pid, ep)->iso_started = 0;
+ }
+ 
+-static void set_iso_started(USBHostDevice *s, int ep)
++static void set_iso_started(USBHostDevice *s, int pid, int ep)
+ {
+-    struct endp_data *e = get_endp(s, ep);
++    struct endp_data *e = get_endp(s, pid, ep);
++
+     if (!e->iso_started) {
+         e->iso_started = 1;
+         e->inflight = 0;
+     }
+ }
+ 
+-static int change_iso_inflight(USBHostDevice *s, int ep, int value)
++static int change_iso_inflight(USBHostDevice *s, int pid, int ep, int value)
+ {
+-    struct endp_data *e = get_endp(s, ep);
++    struct endp_data *e = get_endp(s, pid, ep);
+ 
+     e->inflight += value;
+     return e->inflight;
+ }
+ 
+-static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb)
++static void set_iso_urb(USBHostDevice *s, int pid, int ep, AsyncURB *iso_urb)
+ {
+-    get_endp(s, ep)->iso_urb = iso_urb;
++    get_endp(s, pid, ep)->iso_urb = iso_urb;
+ }
+ 
+-static AsyncURB *get_iso_urb(USBHostDevice *s, int ep)
++static AsyncURB *get_iso_urb(USBHostDevice *s, int pid, int ep)
+ {
+-    return get_endp(s, ep)->iso_urb;
++    return get_endp(s, pid, ep)->iso_urb;
+ }
+ 
+-static void set_iso_urb_idx(USBHostDevice *s, int ep, int i)
++static void set_iso_urb_idx(USBHostDevice *s, int pid, int ep, int i)
+ {
+-    get_endp(s, ep)->iso_urb_idx = i;
++    get_endp(s, pid, ep)->iso_urb_idx = i;
+ }
+ 
+-static int get_iso_urb_idx(USBHostDevice *s, int ep)
++static int get_iso_urb_idx(USBHostDevice *s, int pid, int ep)
+ {
+-    return get_endp(s, ep)->iso_urb_idx;
++    return get_endp(s, pid, ep)->iso_urb_idx;
+ }
+ 
+-static void set_iso_buffer_used(USBHostDevice *s, int ep, int i)
++static void set_iso_buffer_used(USBHostDevice *s, int pid, int ep, int i)
+ {
+-    get_endp(s, ep)->iso_buffer_used = i;
++    get_endp(s, pid, ep)->iso_buffer_used = i;
+ }
+ 
+-static int get_iso_buffer_used(USBHostDevice *s, int ep)
++static int get_iso_buffer_used(USBHostDevice *s, int pid, int ep)
+ {
+-    return get_endp(s, ep)->iso_buffer_used;
++    return get_endp(s, pid, ep)->iso_buffer_used;
+ }
+ 
+-static void set_max_packet_size(USBHostDevice *s, int ep, uint8_t *descriptor)
++static void set_max_packet_size(USBHostDevice *s, int pid, int ep,
++                                uint8_t *descriptor)
+ {
+     int raw = descriptor[4] + (descriptor[5] << 8);
+     int size, microframes;
+@@ -242,12 +250,12 @@ static void set_max_packet_size(USBHostDevice *s, int ep, uint8_t *descriptor)
+     case 2:  microframes = 3; break;
+     default: microframes = 1; break;
+     }
+-    get_endp(s, ep)->max_packet_size = size * microframes;
++    get_endp(s, pid, ep)->max_packet_size = size * microframes;
+ }
+ 
+-static int get_max_packet_size(USBHostDevice *s, int ep)
++static int get_max_packet_size(USBHostDevice *s, int pid, int ep)
+ {
+-    return get_endp(s, ep)->max_packet_size;
++    return get_endp(s, pid, ep)->max_packet_size;
+ }
+ 
+ /*
+@@ -327,13 +335,16 @@ static void async_complete(void *opaque)
+            anything else (it is handled further in usb_host_handle_iso_data) */
+         if (aurb->iso_frame_idx == -1) {
+             int inflight;
++            int pid = (aurb->urb.endpoint & USB_DIR_IN) ?
++                USB_TOKEN_IN : USB_TOKEN_OUT;
++            int ep = aurb->urb.endpoint & 0xf;
+             if (aurb->urb.status == -EPIPE) {
+-                set_halt(s, aurb->urb.endpoint & 0xf);
++                set_halt(s, pid, ep);
+             }
+             aurb->iso_frame_idx = 0;
+             urbs++;
+-            inflight = change_iso_inflight(s, aurb->urb.endpoint & 0xf, -1);
+-            if (inflight == 0 && is_iso_started(s, aurb->urb.endpoint & 0xf)) {
++            inflight = change_iso_inflight(s, pid, ep, -1);
++            if (inflight == 0 && is_iso_started(s, pid, ep)) {
+                 fprintf(stderr, "husb: out of buffers for iso stream\n");
+             }
+             continue;
+@@ -348,7 +359,7 @@ static void async_complete(void *opaque)
+                 break;
+ 
+             case -EPIPE:
+-                set_halt(s, p->devep);
++                set_halt(s, p->pid, p->devep);
+                 p->len = USB_RET_STALL;
+                 break;
+ 
+@@ -528,10 +539,10 @@ static void usb_host_handle_destroy(USBDevice *dev)
+ /* iso data is special, we need to keep enough urbs in flight to make sure
+    that the controller never runs out of them, otherwise the device will
+    likely suffer a buffer underrun / overrun. */
+-static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)
++static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
+ {
+     AsyncURB *aurb;
+-    int i, j, len = get_max_packet_size(s, ep);
++    int i, j, len = get_max_packet_size(s, pid, ep);
+ 
+     aurb = qemu_mallocz(s->iso_urb_count * sizeof(*aurb));
+     for (i = 0; i < s->iso_urb_count; i++) {
+@@ -543,23 +554,23 @@ static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)
+         aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
+         for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
+             aurb[i].urb.iso_frame_desc[j].length = len;
+-        if (in) {
++        if (pid == USB_TOKEN_IN) {
+             aurb[i].urb.endpoint |= 0x80;
+             /* Mark as fully consumed (idle) */
+             aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
+         }
+     }
+-    set_iso_urb(s, ep, aurb);
++    set_iso_urb(s, pid, ep, aurb);
+ 
+     return aurb;
+ }
+ 
+-static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
++static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep)
+ {
+     AsyncURB *aurb;
+     int i, ret, killed = 0, free = 1;
+ 
+-    aurb = get_iso_urb(s, ep);
++    aurb = get_iso_urb(s, pid, ep);
+     if (!aurb) {
+         return;
+     }
+@@ -590,9 +601,9 @@ static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
+         qemu_free(aurb);
+     else
+         printf("husb: leaking iso urbs because of discard failure\n");
+-    set_iso_urb(s, ep, NULL);
+-    set_iso_urb_idx(s, ep, 0);
+-    clear_iso_started(s, ep);
++    set_iso_urb(s, pid, ep, NULL);
++    set_iso_urb_idx(s, pid, ep, 0);
++    clear_iso_started(s, pid, ep);
+ }
+ 
+ static int urb_status_to_usb_ret(int status)
+@@ -610,16 +621,16 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
+     AsyncURB *aurb;
+     int i, j, ret, max_packet_size, offset, len = 0;
+ 
+-    max_packet_size = get_max_packet_size(s, p->devep);
++    max_packet_size = get_max_packet_size(s, p->pid, p->devep);
+     if (max_packet_size == 0)
+         return USB_RET_NAK;
+ 
+-    aurb = get_iso_urb(s, p->devep);
++    aurb = get_iso_urb(s, p->pid, p->devep);
+     if (!aurb) {
+-        aurb = usb_host_alloc_iso(s, p->devep, in);
++        aurb = usb_host_alloc_iso(s, p->pid, p->devep);
+     }
+ 
+-    i = get_iso_urb_idx(s, p->devep);
++    i = get_iso_urb_idx(s, p->pid, p->devep);
+     j = aurb[i].iso_frame_idx;
+     if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
+         if (in) {
+@@ -646,7 +657,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
+             }
+         } else {
+             len = p->len;
+-            offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->devep);
++            offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->devep);
+ 
+             /* Check the frame fits */
+             if (len > max_packet_size) {
+@@ -658,27 +669,27 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
+             memcpy(aurb[i].urb.buffer + offset, p->data, len);
+             aurb[i].urb.iso_frame_desc[j].length = len;
+             offset += len;
+-            set_iso_buffer_used(s, p->devep, offset);
++            set_iso_buffer_used(s, p->pid, p->devep, offset);
+ 
+             /* Start the stream once we have buffered enough data */
+-            if (!is_iso_started(s, p->devep) && i == 1 && j == 8) {
+-                set_iso_started(s, p->devep);
++            if (!is_iso_started(s, p->pid, p->devep) && i == 1 && j == 8) {
++                set_iso_started(s, p->pid, p->devep);
+             }
+         }
+         aurb[i].iso_frame_idx++;
+         if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
+             i = (i + 1) % s->iso_urb_count;
+-            set_iso_urb_idx(s, p->devep, i);
++            set_iso_urb_idx(s, p->pid, p->devep, i);
+         }
+     } else {
+         if (in) {
+-            set_iso_started(s, p->devep);
++            set_iso_started(s, p->pid, p->devep);
+         } else {
+             DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
+         }
+     }
+ 
+-    if (is_iso_started(s, p->devep)) {
++    if (is_iso_started(s, p->pid, p->devep)) {
+         /* (Re)-submit all fully consumed / filled urbs */
+         for (i = 0; i < s->iso_urb_count; i++) {
+             if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
+@@ -698,7 +709,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
+                     break;
+                 }
+                 aurb[i].iso_frame_idx = -1;
+-                change_iso_inflight(s, p->devep, +1);
++                change_iso_inflight(s, p->pid, p->devep, 1);
+             }
+         }
+     }
+@@ -715,7 +726,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
+     uint8_t *pbuf;
+     uint8_t ep;
+ 
+-    if (!is_valid(s, p->devep)) {
++    if (!is_valid(s, p->pid, p->devep)) {
+         return USB_RET_NAK;
+     }
+ 
+@@ -725,7 +736,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
+         ep = p->devep;
+     }
+ 
+-    if (is_halted(s, p->devep)) {
++    if (is_halted(s, p->pid, p->devep)) {
+         unsigned int arg = ep;
+         ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
+         if (ret < 0) {
+@@ -733,10 +744,10 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
+                    ep, errno);
+             return USB_RET_NAK;
+         }
+-        clear_halt(s, p->devep);
++        clear_halt(s, p->pid, p->devep);
+     }
+ 
+-    if (is_isoc(s, p->devep)) {
++    if (is_isoc(s, p->pid, p->devep)) {
+         return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
+     }
+ 
+@@ -823,8 +834,11 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
+     int i, ret;
+ 
+     for (i = 1; i <= MAX_ENDPOINTS; i++) {
+-        if (is_isoc(s, i)) {
+-            usb_host_stop_n_free_iso(s, i);
++        if (is_isoc(s, USB_TOKEN_IN, i)) {
++            usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i);
++        }
++        if (is_isoc(s, USB_TOKEN_OUT, i)) {
++            usb_host_stop_n_free_iso(s, USB_TOKEN_OUT, i);
+         }
+     }
+ 
+@@ -963,10 +977,13 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
+ {
+     uint8_t *descriptors;
+     uint8_t devep, type, alt_interface;
+-    int interface, length, i;
++    int interface, length, i, ep, pid;
++    struct endp_data *epd;
+ 
+-    for (i = 0; i < MAX_ENDPOINTS; i++)
+-        s->endp_table[i].type = INVALID_EP_TYPE;
++    for (i = 0; i < MAX_ENDPOINTS; i++) {
++        s->ep_in[i].type = INVALID_EP_TYPE;
++        s->ep_out[i].type = INVALID_EP_TYPE;
++    }
+ 
+     if (s->configuration == 0) {
+         /* not configured yet -- leave all endpoints disabled */
+@@ -1020,7 +1037,9 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
+             }
+ 
+             devep = descriptors[i + 2];
+-            if ((devep & 0x0f) == 0) {
++            pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
++            ep = devep & 0xf;
++            if (ep == 0) {
+                 fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
+                 return 1;
+             }
+@@ -1031,7 +1050,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
+                 break;
+             case 0x01:
+                 type = USBDEVFS_URB_TYPE_ISO;
+-                set_max_packet_size(s, (devep & 0xf), descriptors + i);
++                set_max_packet_size(s, pid, ep, descriptors + i);
+                 break;
+             case 0x02:
+                 type = USBDEVFS_URB_TYPE_BULK;
+@@ -1043,8 +1062,10 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
+                 DPRINTF("usb_host: malformed endpoint type\n");
+                 type = USBDEVFS_URB_TYPE_BULK;
+             }
+-            s->endp_table[(devep & 0xf) - 1].type = type;
+-            s->endp_table[(devep & 0xf) - 1].halted = 0;
++            epd = get_endp(s, pid, ep);
++            assert(epd->type == INVALID_EP_TYPE);
++            epd->type = type;
++            epd->halted = 0;
+ 
+             i += descriptors[i];
+         }
+@@ -1206,8 +1227,11 @@ static int usb_host_close(USBHostDevice *dev)
+     qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
+     dev->closing = 1;
+     for (i = 1; i <= MAX_ENDPOINTS; i++) {
+-        if (is_isoc(dev, i)) {
+-            usb_host_stop_n_free_iso(dev, i);
++        if (is_isoc(dev, USB_TOKEN_IN, i)) {
++            usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i);
++        }
++        if (is_isoc(dev, USB_TOKEN_OUT, i)) {
++            usb_host_stop_n_free_iso(dev, USB_TOKEN_OUT, i);
+         }
+     }
+     async_complete(dev);
+-- 
+1.5.6.5
+

Added: pve-qemu-kvm/trunk/debian/patches/0005-usb-ehci-handle-siTDs.patch
===================================================================
--- pve-qemu-kvm/trunk/debian/patches/0005-usb-ehci-handle-siTDs.patch	                        (rev 0)
+++ pve-qemu-kvm/trunk/debian/patches/0005-usb-ehci-handle-siTDs.patch	2011-10-14 14:34:48 UTC (rev 6561)
@@ -0,0 +1,116 @@
+From 7e6bb4c98ea2f2edfb6df901ea2f83fcada94a8f Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Fri, 26 Aug 2011 14:13:48 +0200
+Subject: [PATCH] usb-ehci: handle siTDs
+
+This patch adds code to do minimal siTD handling, which is basically
+just following the next pointer.  This is good enougth to handle the
+inactive siTDs used by FreeBSD.  Active siTDs are skipped too as we
+don't have split transfer support in qemu, additionally a warning is
+printed.
+
+Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
+(cherry picked from commit c57f5348b0c95b46b98b9ddb48b059b29c178452)
+---
+ hw/usb-ehci.c |   43 ++++++++++++++++++++++++++++++++++++++++++-
+ trace-events  |    1 +
+ 2 files changed, 43 insertions(+), 1 deletions(-)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index a4758f9..3ea4c72 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -148,6 +148,7 @@ typedef enum {
+     EST_FETCHENTRY,
+     EST_FETCHQH,
+     EST_FETCHITD,
++    EST_FETCHSITD,
+     EST_ADVANCEQUEUE,
+     EST_FETCHQTD,
+     EST_EXECUTE,
+@@ -645,6 +646,13 @@ static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd)
+                        get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR));
+ }
+ 
++static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr,
++                            EHCIsitd *sitd)
++{
++    trace_usb_ehci_sitd(addr, sitd->next,
++                        (bool)(sitd->results & SITD_RESULTS_ACTIVE));
++}
++
+ /* queue management */
+ 
+ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async)
+@@ -1613,8 +1621,13 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)
+         again = 1;
+         break;
+ 
++    case NLPTR_TYPE_STITD:
++        ehci_set_state(ehci, async, EST_FETCHSITD);
++        again = 1;
++        break;
++
+     default:
+-        // TODO: handle siTD and FSTN types
++        /* TODO: handle FSTN type */
+         fprintf(stderr, "FETCHENTRY: entry at %X is of type %d "
+                 "which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
+         return -1;
+@@ -1730,6 +1743,30 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async)
+     return 1;
+ }
+ 
++static int ehci_state_fetchsitd(EHCIState *ehci, int async)
++{
++    uint32_t entry;
++    EHCIsitd sitd;
++
++    assert(!async);
++    entry = ehci_get_fetch_addr(ehci, async);
++
++    get_dwords(NLPTR_GET(entry), (uint32_t *)&sitd,
++               sizeof(EHCIsitd) >> 2);
++    ehci_trace_sitd(ehci, entry, &sitd);
++
++    if (!(sitd.results & SITD_RESULTS_ACTIVE)) {
++        /* siTD is not active, nothing to do */;
++    } else {
++        /* TODO: split transfers are not implemented */
++        fprintf(stderr, "WARNING: Skipping active siTD\n");
++    }
++
++    ehci_set_fetch_addr(ehci, async, sitd.next);
++    ehci_set_state(ehci, async, EST_FETCHENTRY);
++    return 1;
++}
++
+ /* Section 4.10.2 - paragraph 3 */
+ static int ehci_state_advqueue(EHCIQueue *q, int async)
+ {
+@@ -2005,6 +2042,10 @@ static void ehci_advance_state(EHCIState *ehci,
+             again = ehci_state_fetchitd(ehci, async);
+             break;
+ 
++        case EST_FETCHSITD:
++            again = ehci_state_fetchsitd(ehci, async);
++            break;
++
+         case EST_ADVANCEQUEUE:
+             again = ehci_state_advqueue(q, async);
+             break;
+diff --git a/trace-events b/trace-events
+index 713f042..e6f8c37 100644
+--- a/trace-events
++++ b/trace-events
+@@ -223,6 +223,7 @@ disable usb_ehci_qtd_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t altnext
+ disable usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ %08x - tbytes %d, cpage %d, cerr %d, pid %d"
+ disable usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ %08x - ioc %d, active %d, halt %d, babble %d, xacterr %d"
+ disable usb_ehci_itd(uint32_t addr, uint32_t nxt, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ %08x: next %08x - mplen %d, mult %d, ep %d, dev %d"
++disable usb_ehci_sitd(uint32_t addr, uint32_t nxt, uint32_t active) "ITD @ %08x: next %08x - active %d"
+ disable usb_ehci_port_attach(uint32_t port, const char *device) "attach port #%d - %s"
+ disable usb_ehci_port_detach(uint32_t port) "detach port #%d"
+ disable usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
+-- 
+1.5.6.5
+

Added: pve-qemu-kvm/trunk/debian/patches/0006-usb-fix-use-after-free.patch
===================================================================
--- pve-qemu-kvm/trunk/debian/patches/0006-usb-fix-use-after-free.patch	                        (rev 0)
+++ pve-qemu-kvm/trunk/debian/patches/0006-usb-fix-use-after-free.patch	2011-10-14 14:34:48 UTC (rev 6561)
@@ -0,0 +1,31 @@
+From d3ffc953b3e5cacec22c34c6361e95d6ffcfc8ad Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 25 Aug 2011 16:43:15 +0200
+Subject: [PATCH] usb: fix use after free
+
+The ->complete() callback might have released the USBPacket (uhci
+actually does), so we must not touch it after the callback returns.
+
+Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
+(cherry picked from commit 722d89396b6ccb49cd9d3aafd991ae01c8a30744)
+---
+ hw/usb.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/hw/usb.c b/hw/usb.c
+index 27a983c..b44e997 100644
+--- a/hw/usb.c
++++ b/hw/usb.c
+@@ -334,8 +334,8 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
+ {
+     /* Note: p->owner != dev is possible in case dev is a hub */
+     assert(p->owner != NULL);
+-    dev->port->ops->complete(dev->port, p);
+     p->owner = NULL;
++    dev->port->ops->complete(dev->port, p);
+ }
+ 
+ /* Cancel an active packet.  The packed must have been deferred by
+-- 
+1.5.6.5
+

Added: pve-qemu-kvm/trunk/debian/patches/0007-usb-claim-port-at-device-initialization-time.patch
===================================================================
--- pve-qemu-kvm/trunk/debian/patches/0007-usb-claim-port-at-device-initialization-time.patch	                        (rev 0)
+++ pve-qemu-kvm/trunk/debian/patches/0007-usb-claim-port-at-device-initialization-time.patch	2011-10-14 14:34:48 UTC (rev 6561)
@@ -0,0 +1,473 @@
+From 08cc8c6ea3736d2303d2f720eb9bc1168a2adab5 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 1 Sep 2011 13:56:37 +0200
+Subject: [PATCH] usb: claim port at device initialization time.
+
+This patch makes qemu assign a port when creating the device, not when
+attaching it.  For most usb devices this isn't a noticable difference
+because they are in attached state all the time.
+
+The change affects usb-host devices which live in detached state while
+the real device is unplugged from the host.  They have a fixed port
+assigned all the time now instead of getting grabbing one on attach and
+releasing it at detach, i.e. they stop floating around at the usb bus.
+
+The change also allows to simplify usb-hub.  It doesn't need the
+handle_attach() callback any more to configure the downstream ports.
+This can be done at device initialitation time now.  The changed
+initialization order (first grab upstream port, then register downstream
+ports) also fixes some icky corner cases.  For example it is not possible
+any more to plug the hub into one of its own downstream ports.
+
+The usb host adapters must care too.  USBPort->dev being non-NULL
+doesn't imply any more the device is in attached state.  The host
+adapters must additionally check the USBPort->dev->attached flag.
+
+Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
+(cherry picked from commit 763917c9b6d5a6126530d8e52324e653e594c521)
+---
+ hw/usb-bus.c  |  110 +++++++++++++++++++++++++++++++++------------------------
+ hw/usb-ehci.c |   22 ++++++------
+ hw/usb-hub.c  |   12 +------
+ hw/usb-ohci.c |    4 +-
+ hw/usb-uhci.c |   11 +++---
+ hw/usb.c      |   35 ++++++++----------
+ hw/usb.h      |    5 ++-
+ trace-events  |    6 +++
+ 8 files changed, 110 insertions(+), 95 deletions(-)
+
+diff --git a/hw/usb-bus.c b/hw/usb-bus.c
+index f1dd55e..d384426 100644
+--- a/hw/usb-bus.c
++++ b/hw/usb-bus.c
+@@ -3,6 +3,7 @@
+ #include "qdev.h"
+ #include "sysemu.h"
+ #include "monitor.h"
++#include "trace.h"
+ 
+ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
+ 
+@@ -73,9 +74,13 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
+     dev->info = info;
+     dev->auto_attach = 1;
+     QLIST_INIT(&dev->strings);
+-    rc = dev->info->init(dev);
+-    if (rc == 0 && dev->auto_attach)
++    rc = usb_claim_port(dev);
++    if (rc == 0) {
++        rc = dev->info->init(dev);
++    }
++    if (rc == 0 && dev->auto_attach) {
+         rc = usb_device_attach(dev);
++    }
+     return rc;
+ }
+ 
+@@ -89,6 +94,9 @@ static int usb_qdev_exit(DeviceState *qdev)
+     if (dev->info->handle_destroy) {
+         dev->info->handle_destroy(dev);
+     }
++    if (dev->port) {
++        usb_release_port(dev);
++    }
+     return 0;
+ }
+ 
+@@ -205,21 +213,13 @@ void usb_unregister_port(USBBus *bus, USBPort *port)
+     bus->nfree--;
+ }
+ 
+-static int do_attach(USBDevice *dev)
++int usb_claim_port(USBDevice *dev)
+ {
+     USBBus *bus = usb_bus_from_device(dev);
+     USBPort *port;
+ 
+-    if (dev->attached) {
+-        error_report("Error: tried to attach usb device %s twice\n",
+-                dev->product_desc);
+-        return -1;
+-    }
+-    if (bus->nfree == 0) {
+-        error_report("Error: tried to attach usb device %s to a bus with no free ports\n",
+-                dev->product_desc);
+-        return -1;
+-    }
++    assert(dev->port == NULL);
++
+     if (dev->port_path) {
+         QTAILQ_FOREACH(port, &bus->free, next) {
+             if (strcmp(port->path, dev->port_path) == 0) {
+@@ -227,68 +227,86 @@ static int do_attach(USBDevice *dev)
+             }
+         }
+         if (port == NULL) {
+-            error_report("Error: usb port %s (bus %s) not found\n",
+-                    dev->port_path, bus->qbus.name);
++            error_report("Error: usb port %s (bus %s) not found (in use?)\n",
++                         dev->port_path, bus->qbus.name);
+             return -1;
+         }
+     } else {
++        if (bus->nfree == 1 && strcmp(dev->qdev.info->name, "usb-hub") != 0) {
++            /* Create a new hub and chain it on */
++            usb_create_simple(bus, "usb-hub");
++        }
++        if (bus->nfree == 0) {
++            error_report("Error: tried to attach usb device %s to a bus "
++                         "with no free ports\n", dev->product_desc);
++            return -1;
++        }
+         port = QTAILQ_FIRST(&bus->free);
+     }
+-    if (!(port->speedmask & dev->speedmask)) {
+-        error_report("Warning: speed mismatch trying to attach usb device %s to bus %s\n",
+-                dev->product_desc, bus->qbus.name);
+-        return -1;
+-    }
++    trace_usb_port_claim(bus->busnr, port->path);
+ 
+-    dev->attached++;
+     QTAILQ_REMOVE(&bus->free, port, next);
+     bus->nfree--;
+ 
+-    usb_attach(port, dev);
++    dev->port = port;
++    port->dev = dev;
+ 
+     QTAILQ_INSERT_TAIL(&bus->used, port, next);
+     bus->nused++;
+-
+     return 0;
+ }
+ 
+-int usb_device_attach(USBDevice *dev)
++void usb_release_port(USBDevice *dev)
+ {
+     USBBus *bus = usb_bus_from_device(dev);
++    USBPort *port = dev->port;
+ 
+-    if (bus->nfree == 1 && dev->port_path == NULL) {
+-        /* Create a new hub and chain it on
+-           (unless a physical port location is specified). */
+-        usb_create_simple(bus, "usb-hub");
+-    }
+-    return do_attach(dev);
++    assert(port != NULL);
++    trace_usb_port_release(bus->busnr, port->path);
++
++    QTAILQ_REMOVE(&bus->used, port, next);
++    bus->nused--;
++
++    dev->port = NULL;
++    port->dev = NULL;
++
++    QTAILQ_INSERT_TAIL(&bus->free, port, next);
++    bus->nfree++;
+ }
+ 
+-int usb_device_detach(USBDevice *dev)
++int usb_device_attach(USBDevice *dev)
+ {
+     USBBus *bus = usb_bus_from_device(dev);
+-    USBPort *port;
++    USBPort *port = dev->port;
+ 
+-    if (!dev->attached) {
+-        error_report("Error: tried to detach unattached usb device %s\n",
+-                dev->product_desc);
++    assert(port != NULL);
++    assert(!dev->attached);
++    trace_usb_port_attach(bus->busnr, port->path);
++
++    if (!(port->speedmask & dev->speedmask)) {
++        error_report("Warning: speed mismatch trying to attach "
++                     "usb device %s to bus %s\n",
++                     dev->product_desc, bus->qbus.name);
+         return -1;
+     }
+-    dev->attached--;
+ 
+-    QTAILQ_FOREACH(port, &bus->used, next) {
+-        if (port->dev == dev)
+-            break;
+-    }
+-    assert(port != NULL);
++    dev->attached++;
++    usb_attach(port);
+ 
+-    QTAILQ_REMOVE(&bus->used, port, next);
+-    bus->nused--;
++    return 0;
++}
++
++int usb_device_detach(USBDevice *dev)
++{
++    USBBus *bus = usb_bus_from_device(dev);
++    USBPort *port = dev->port;
+ 
+-    usb_attach(port, NULL);
++    assert(port != NULL);
++    assert(dev->attached);
++    trace_usb_port_detach(bus->busnr, port->path);
+ 
+-    QTAILQ_INSERT_TAIL(&bus->free, port, next);
+-    bus->nfree++;
++    usb_detach(port);
++    dev->attached--;
+     return 0;
+ }
+ 
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index 3ea4c72..5bb61bb 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -856,8 +856,8 @@ static void ehci_reset(void *opaque)
+      */
+     for(i = 0; i < NB_PORTS; i++) {
+         devs[i] = s->ports[i].dev;
+-        if (devs[i]) {
+-            usb_attach(&s->ports[i], NULL);
++        if (devs[i] && devs[i]->attached) {
++            usb_detach(&s->ports[i]);
+         }
+     }
+ 
+@@ -877,8 +877,8 @@ static void ehci_reset(void *opaque)
+         } else {
+             s->portsc[i] = PORTSC_PPOWER;
+         }
+-        if (devs[i]) {
+-            usb_attach(&s->ports[i], devs[i]);
++        if (devs[i] && devs[i]->attached) {
++            usb_attach(&s->ports[i]);
+         }
+     }
+     ehci_queues_rip_all(s);
+@@ -944,15 +944,15 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
+         return;
+     }
+ 
+-    if (dev) {
+-        usb_attach(&s->ports[port], NULL);
++    if (dev && dev->attached) {
++        usb_detach(&s->ports[port]);
+     }
+ 
+     *portsc &= ~PORTSC_POWNER;
+     *portsc |= owner;
+ 
+-    if (dev) {
+-        usb_attach(&s->ports[port], dev);
++    if (dev && dev->attached) {
++        usb_attach(&s->ports[port]);
+     }
+ }
+ 
+@@ -976,8 +976,8 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
+ 
+     if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
+         trace_usb_ehci_port_reset(port, 0);
+-        if (dev) {
+-            usb_attach(&s->ports[port], dev);
++        if (dev && dev->attached) {
++            usb_attach(&s->ports[port]);
+             usb_send_msg(dev, USB_MSG_RESET);
+             *portsc &= ~PORTSC_CSC;
+         }
+@@ -986,7 +986,7 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
+          *  Table 2.16 Set the enable bit(and enable bit change) to indicate
+          *  to SW that this port has a high speed device attached
+          */
+-        if (dev && (dev->speedmask & USB_SPEED_MASK_HIGH)) {
++        if (dev && dev->attached && (dev->speedmask & USB_SPEED_MASK_HIGH)) {
+             val |= PORTSC_PED;
+         }
+     }
+diff --git a/hw/usb-hub.c b/hw/usb-hub.c
+index b49a2fe..a7a80f0 100644
+--- a/hw/usb-hub.c
++++ b/hw/usb-hub.c
+@@ -213,16 +213,6 @@ static void usb_hub_complete(USBPort *port, USBPacket *packet)
+     usb_packet_complete(&s->dev, packet);
+ }
+ 
+-static void usb_hub_handle_attach(USBDevice *dev)
+-{
+-    USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
+-    int i;
+-
+-    for (i = 0; i < NUM_PORTS; i++) {
+-        usb_port_location(&s->ports[i].port, dev->port, i+1);
+-    }
+-}
+-
+ static void usb_hub_handle_reset(USBDevice *dev)
+ {
+     /* XXX: do it */
+@@ -497,6 +487,7 @@ static int usb_hub_initfn(USBDevice *dev)
+         usb_register_port(usb_bus_from_device(dev),
+                           &port->port, s, i, &usb_hub_port_ops,
+                           USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
++        usb_port_location(&port->port, dev->port, i+1);
+         port->wPortStatus = PORT_STAT_POWER;
+         port->wPortChange = 0;
+     }
+@@ -535,7 +526,6 @@ static struct USBDeviceInfo hub_info = {
+     .usb_desc       = &desc_hub,
+     .init           = usb_hub_initfn,
+     .handle_packet  = usb_hub_handle_packet,
+-    .handle_attach  = usb_hub_handle_attach,
+     .handle_reset   = usb_hub_handle_reset,
+     .handle_control = usb_hub_handle_control,
+     .handle_data    = usb_hub_handle_data,
+diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
+index 8491d59..4dd2c1e 100644
+--- a/hw/usb-ohci.c
++++ b/hw/usb-ohci.c
+@@ -448,8 +448,8 @@ static void ohci_reset(void *opaque)
+       {
+         port = &ohci->rhport[i];
+         port->ctrl = 0;
+-        if (port->port.dev) {
+-            usb_attach(&port->port, port->port.dev);
++        if (port->port.dev && port->port.dev->attached) {
++            usb_attach(&port->port);
+         }
+       }
+     if (ohci->async_td) {
+diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
+index da74c57..b2647b0 100644
+--- a/hw/usb-uhci.c
++++ b/hw/usb-uhci.c
+@@ -338,8 +338,8 @@ static void uhci_reset(void *opaque)
+     for(i = 0; i < NB_PORTS; i++) {
+         port = &s->ports[i];
+         port->ctrl = 0x0080;
+-        if (port->port.dev) {
+-            usb_attach(&port->port, port->port.dev);
++        if (port->port.dev && port->port.dev->attached) {
++            usb_attach(&port->port);
+         }
+     }
+ 
+@@ -444,7 +444,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+             for(i = 0; i < NB_PORTS; i++) {
+                 port = &s->ports[i];
+                 dev = port->port.dev;
+-                if (dev) {
++                if (dev && dev->attached) {
+                     usb_send_msg(dev, USB_MSG_RESET);
+                 }
+             }
+@@ -484,7 +484,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+                 return;
+             port = &s->ports[n];
+             dev = port->port.dev;
+-            if (dev) {
++            if (dev && dev->attached) {
+                 /* port reset */
+                 if ( (val & UHCI_PORT_RESET) &&
+                      !(port->ctrl & UHCI_PORT_RESET) ) {
+@@ -658,8 +658,9 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
+         UHCIPort *port = &s->ports[i];
+         USBDevice *dev = port->port.dev;
+ 
+-        if (dev && (port->ctrl & UHCI_PORT_EN))
++        if (dev && dev->attached && (port->ctrl & UHCI_PORT_EN)) {
+             ret = usb_handle_packet(dev, p);
++        }
+     }
+ 
+     DPRINTF("uhci: packet exit. ret %d len %d\n", ret, p->len);
+diff --git a/hw/usb.c b/hw/usb.c
+index b44e997..b89a609 100644
+--- a/hw/usb.c
++++ b/hw/usb.c
+@@ -26,26 +26,23 @@
+ #include "qemu-common.h"
+ #include "usb.h"
+ 
+-void usb_attach(USBPort *port, USBDevice *dev)
++void usb_attach(USBPort *port)
+ {
+-    if (dev != NULL) {
+-        /* attach */
+-        if (port->dev) {
+-            usb_attach(port, NULL);
+-        }
+-        dev->port = port;
+-        port->dev = dev;
+-        port->ops->attach(port);
+-        usb_send_msg(dev, USB_MSG_ATTACH);
+-    } else {
+-        /* detach */
+-        dev = port->dev;
+-        assert(dev);
+-        port->ops->detach(port);
+-        usb_send_msg(dev, USB_MSG_DETACH);
+-        dev->port = NULL;
+-        port->dev = NULL;
+-    }
++    USBDevice *dev = port->dev;
++
++    assert(dev != NULL);
++    assert(dev->attached);
++    port->ops->attach(port);
++    usb_send_msg(dev, USB_MSG_ATTACH);
++}
++
++void usb_detach(USBPort *port)
++{
++    USBDevice *dev = port->dev;
++
++    assert(dev != NULL);
++    port->ops->detach(port);
++    usb_send_msg(dev, USB_MSG_DETACH);
+ }
+ 
+ void usb_wakeup(USBDevice *dev)
+diff --git a/hw/usb.h b/hw/usb.h
+index ded2de2..dfe4449 100644
+--- a/hw/usb.h
++++ b/hw/usb.h
+@@ -295,7 +295,8 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p);
+ void usb_packet_complete(USBDevice *dev, USBPacket *p);
+ void usb_cancel_packet(USBPacket * p);
+ 
+-void usb_attach(USBPort *port, USBDevice *dev);
++void usb_attach(USBPort *port);
++void usb_detach(USBPort *port);
+ void usb_wakeup(USBDevice *dev);
+ int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
+ void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
+@@ -372,6 +373,8 @@ int usb_register_companion(const char *masterbus, USBPort *ports[],
+                            void *opaque, USBPortOps *ops, int speedmask);
+ void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr);
+ void usb_unregister_port(USBBus *bus, USBPort *port);
++int usb_claim_port(USBDevice *dev);
++void usb_release_port(USBDevice *dev);
+ int usb_device_attach(USBDevice *dev);
+ int usb_device_detach(USBDevice *dev);
+ int usb_device_delete_addr(int busnr, int addr);
+diff --git a/trace-events b/trace-events
+index e6f8c37..201cb49 100644
+--- a/trace-events
++++ b/trace-events
+@@ -209,6 +209,12 @@ disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "g
+ disable sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x"
+ disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
+ 
++# hw/usb-bus.c
++usb_port_claim(int bus, const char *port) "bus %d, port %s"
++usb_port_attach(int bus, const char *port) "bus %d, port %s"
++usb_port_detach(int bus, const char *port) "bus %d, port %s"
++usb_port_release(int bus, const char *port) "bus %d, port %s"
++
+ # hw/usb-ehci.c
+ disable usb_ehci_reset(void) "=== RESET ==="
+ disable usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
+-- 
+1.5.6.5
+

Modified: pve-qemu-kvm/trunk/debian/patches/series
===================================================================
--- pve-qemu-kvm/trunk/debian/patches/series	2011-10-12 04:32:05 UTC (rev 6560)
+++ pve-qemu-kvm/trunk/debian/patches/series	2011-10-14 14:34:48 UTC (rev 6561)
@@ -8,3 +8,10 @@
 use-local-linux-kvm-h.diff
 fr-ca-keymap-corrections.diff
 msix-eventfd-fix.patch
+0001-usb-host-reapurb-error-report-fix.patch 
+0002-usb-host-fix-halted-endpoints.patch
+0003-usb-host-fix-configuration-tracking.patch
+0004-usb-host-endpoint-table-fixup.patch
+0005-usb-ehci-handle-siTDs.patch
+0006-usb-fix-use-after-free.patch
+0007-usb-claim-port-at-device-initialization-time.patch




More information about the pve-devel mailing list