[qemu] Add a whole bunch of USB bugfixes from upstream

Hans de Goede jwrdegoede at fedoraproject.org
Mon Mar 12 15:31:55 UTC 2012


commit 1b1995dd6760dc04df9535b784679d3c046d29bb
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Mon Mar 12 16:33:46 2012 +0100

    Add a whole bunch of USB bugfixes from upstream

 ...ear-the-portstatus-powner-bit-on-device-d.patch |   35 +++
 ...dd-the-posibility-to-filter-out-certain-d.patch |  263 ++++++++++++++++++++
 ...-usb-redir-Fix-printing-of-device-version.patch |   33 +++
 ...lways-clear-device-state-on-filter-reject.patch |   64 +++++
 ...et-the-usb-host-know-about-our-device-fil.patch |   93 +++++++
 ...imit-return-values-returned-by-iso-packet.patch |   42 +++
 ...eturn-USB_RET_NAK-when-we-ve-no-data-for-.patch |   33 +++
 ...ndle-ISO-packets-failing-with-an-error-ot.patch |   64 +++++
 ...ver-follow-table-entries-with-the-T-bit-s.patch |   61 +++++
 ...lit-our-qh-queue-into-async-and-periodic-.patch |  219 ++++++++++++++++
 ...ways-call-ehci_queues_rip_unused-for-peri.patch |   42 +++
 ...op-cached-qhs-when-the-doorbell-gets-rung.patch |  115 +++++++++
 ...p-the-queues-when-the-async-or-period-sch.patch |   44 ++++
 ...y-packet-completion-except-for-NAK-should.patch |   33 +++
 0133-usb-ehci-Fix-cerr-tracking.patch              |   72 ++++++
 0134-usb-ehci-Remove-dead-nakcnt-code.patch        |   78 ++++++
 ...usb-ehci-Fix-and-simplify-nakcnt-handling.patch |  120 +++++++++
 0136-usb-ehci-Remove-dead-isoch_pause-code.patch   |  114 +++++++++
 ...BABBLE-rather-then-NAK-when-we-receive-to.patch |   70 ++++++
 0138-usb-add-USB_RET_IOERROR.patch                 |  167 +++++++++++++
 0139-usb-ehci-fix-reset.patch                      |   40 +++
 0140-usb-ehci-sanity-check-iso-xfers.patch         |   42 +++
 qemu.spec                                          |   49 ++++-
 23 files changed, 1892 insertions(+), 1 deletions(-)
---
diff --git a/0119-usb-ehci-Clear-the-portstatus-powner-bit-on-device-d.patch b/0119-usb-ehci-Clear-the-portstatus-powner-bit-on-device-d.patch
new file mode 100644
index 0000000..cb41dc0
--- /dev/null
+++ b/0119-usb-ehci-Clear-the-portstatus-powner-bit-on-device-d.patch
@@ -0,0 +1,35 @@
+From 959f57d34f11daf0da6f73541243934f39dfb2b2 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Fri, 13 Jan 2012 14:26:26 +0100
+Subject: [PATCH 119/140] usb-ehci: Clear the portstatus powner bit on device
+ disconnect
+
+According to the EHCI spec port ownerhsip should revert to the EHCI controller
+on device disconnect. This fixes the problem of a port getting stuck on USB 1
+when using redirection and plugging in a USB 2 device after a USB 1 device
+has been redirected.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index a946e1d..69bcc4b 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -764,6 +764,11 @@ static void ehci_detach(USBPort *port)
+         USBPort *companion = s->companion_ports[port->index];
+         companion->ops->detach(companion);
+         companion->dev = NULL;
++        /*
++         * EHCI spec 4.2.2: "When a disconnect occurs... On the event,
++         * the port ownership is returned immediately to the EHCI controller."
++         */
++        *portsc &= ~PORTSC_POWNER;
+         return;
+     }
+ 
+-- 
+1.7.9.3
+
diff --git a/0120-usb-redir-Add-the-posibility-to-filter-out-certain-d.patch b/0120-usb-redir-Add-the-posibility-to-filter-out-certain-d.patch
new file mode 100644
index 0000000..c0d0e9f
--- /dev/null
+++ b/0120-usb-redir-Add-the-posibility-to-filter-out-certain-d.patch
@@ -0,0 +1,263 @@
+From bcc4748db3e991fbaa032fe9c0726288a8f1008d Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Thu, 12 Jan 2012 16:54:04 +0100
+Subject: [PATCH 120/140] usb-redir: Add the posibility to filter out certain
+ devices from redirecion
+
+This patch adds the posibility to filter out certain devices from redirecion.
+To use this pass the filter property to -device usb-redir.  The filter
+property takes a string consisting of filter rules, the format for a rule is:
+<class>:<vendor>:<product>:<version>:<allow>
+
+-1 can be used to allow any value for a field.
+
+Muliple rules can be concatonated using | as a separator. Note that if
+a device matches none of the passed in rules, redirecting it will not be
+allowed!
+
+Example:
+-device usb-redir,filter='-1:0x0781:0x5567:-1:0|0x08:-1:-1:-1:1'
+
+This example will deny the Sandisk Cruzer Blade being redirected, as it
+has a usb id of 0781:5567, it will allow any other usb mass storage devices,
+and it will deny any other devices (the default for devices not matching any
+of the rules.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ configure   |    2 +-
+ usb-redir.c |  115 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
+ 2 files changed, 106 insertions(+), 11 deletions(-)
+
+diff --git a/configure b/configure
+index 7ecf44e..c7e37df 100755
+--- a/configure
++++ b/configure
+@@ -2541,7 +2541,7 @@ fi
+ 
+ # check for usbredirparser for usb network redirection support
+ if test "$usb_redir" != "no" ; then
+-    if $pkg_config libusbredirparser >/dev/null 2>&1 ; then
++    if $pkg_config --atleast-version=0.3.3 libusbredirparser >/dev/null 2>&1 ; then
+         usb_redir="yes"
+         usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
+         usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
+diff --git a/usb-redir.c b/usb-redir.c
+index 6e92f14..85f40d6 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -34,6 +34,7 @@
+ #include <sys/ioctl.h>
+ #include <signal.h>
+ #include <usbredirparser.h>
++#include <usbredirfilter.h>
+ 
+ #include "hw/usb.h"
+ 
+@@ -72,6 +73,7 @@ struct USBRedirDevice {
+     /* Properties */
+     CharDriverState *cs;
+     uint8_t debug;
++    char *filter_str;
+     /* Data passed from chardev the fd_read cb to the usbredirparser read cb */
+     const uint8_t *read_buf;
+     int read_buf_size;
+@@ -84,6 +86,11 @@ struct USBRedirDevice {
+     struct endp_data endpoint[MAX_ENDPOINTS];
+     uint32_t packet_id;
+     QTAILQ_HEAD(, AsyncURB) asyncq;
++    /* Data for device filtering */
++    struct usb_redir_device_connect_header device_info;
++    struct usb_redir_interface_info_header interface_info;
++    struct usbredirfilter_rule *filter_rules;
++    int filter_rules_count;
+ };
+ 
+ struct AsyncURB {
+@@ -790,6 +797,7 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
+ static void usbredir_open_close_bh(void *opaque)
+ {
+     USBRedirDevice *dev = opaque;
++    uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
+ 
+     usbredir_device_disconnect(dev);
+ 
+@@ -820,7 +828,9 @@ static void usbredir_open_close_bh(void *opaque)
+         dev->parser->interrupt_packet_func = usbredir_interrupt_packet;
+         dev->read_buf = NULL;
+         dev->read_buf_size = 0;
+-        usbredirparser_init(dev->parser, VERSION, NULL, 0, 0);
++
++        usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
++        usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0);
+         usbredirparser_do_write(dev->parser);
+     }
+ }
+@@ -908,6 +918,17 @@ static int usbredir_initfn(USBDevice *udev)
+         return -1;
+     }
+ 
++    if (dev->filter_str) {
++        i = usbredirfilter_string_to_rules(dev->filter_str, ":", "|",
++                                           &dev->filter_rules,
++                                           &dev->filter_rules_count);
++        if (i) {
++            qerror_report(QERR_INVALID_PARAMETER_VALUE, "filter",
++                          "a usb device filter string");
++            return -1;
++        }
++    }
++
+     dev->open_close_bh = qemu_bh_new(usbredir_open_close_bh, dev);
+     dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev);
+ 
+@@ -956,6 +977,44 @@ static void usbredir_handle_destroy(USBDevice *udev)
+     if (dev->parser) {
+         usbredirparser_destroy(dev->parser);
+     }
++
++    free(dev->filter_rules);
++}
++
++static int usbredir_check_filter(USBRedirDevice *dev)
++{
++    if (dev->interface_info.interface_count == 0) {
++        ERROR("No interface info for device\n");
++        return -1;
++    }
++
++    if (dev->filter_rules) {
++        if (!usbredirparser_peer_has_cap(dev->parser,
++                                    usb_redir_cap_connect_device_version)) {
++            ERROR("Device filter specified and peer does not have the "
++                  "connect_device_version capability\n");
++            return -1;
++        }
++
++        if (usbredirfilter_check(
++                dev->filter_rules,
++                dev->filter_rules_count,
++                dev->device_info.device_class,
++                dev->device_info.device_subclass,
++                dev->device_info.device_protocol,
++                dev->interface_info.interface_class,
++                dev->interface_info.interface_subclass,
++                dev->interface_info.interface_protocol,
++                dev->interface_info.interface_count,
++                dev->device_info.vendor_id,
++                dev->device_info.product_id,
++                dev->device_info.device_version_bcd,
++                0) != 0) {
++            return -1;
++        }
++    }
++
++    return 0;
+ }
+ 
+ /*
+@@ -984,6 +1043,7 @@ static void usbredir_device_connect(void *priv,
+     struct usb_redir_device_connect_header *device_connect)
+ {
+     USBRedirDevice *dev = priv;
++    const char *speed;
+ 
+     if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) {
+         ERROR("Received device connect while already connected\n");
+@@ -992,26 +1052,48 @@ static void usbredir_device_connect(void *priv,
+ 
+     switch (device_connect->speed) {
+     case usb_redir_speed_low:
+-        DPRINTF("attaching low speed device\n");
++        speed = "low speed";
+         dev->dev.speed = USB_SPEED_LOW;
+         break;
+     case usb_redir_speed_full:
+-        DPRINTF("attaching full speed device\n");
++        speed = "full speed";
+         dev->dev.speed = USB_SPEED_FULL;
+         break;
+     case usb_redir_speed_high:
+-        DPRINTF("attaching high speed device\n");
++        speed = "high speed";
+         dev->dev.speed = USB_SPEED_HIGH;
+         break;
+     case usb_redir_speed_super:
+-        DPRINTF("attaching super speed device\n");
++        speed = "super speed";
+         dev->dev.speed = USB_SPEED_SUPER;
+         break;
+     default:
+-        DPRINTF("attaching unknown speed device, assuming full speed\n");
++        speed = "unknown speed";
+         dev->dev.speed = USB_SPEED_FULL;
+     }
++
++    if (usbredirparser_peer_has_cap(dev->parser,
++                                    usb_redir_cap_connect_device_version)) {
++        INFO("attaching %s device %04x:%04x version %d.%d class %02x\n",
++             speed, device_connect->vendor_id, device_connect->product_id,
++             device_connect->device_version_bcd >> 8,
++             device_connect->device_version_bcd & 0xff,
++             device_connect->device_class);
++    } else {
++        INFO("attaching %s device %04x:%04x class %02x\n", speed,
++             device_connect->vendor_id, device_connect->product_id,
++             device_connect->device_class);
++    }
++
+     dev->dev.speedmask = (1 << dev->dev.speed);
++    dev->device_info = *device_connect;
++
++    if (usbredir_check_filter(dev)) {
++        WARNING("Device %04x:%04x rejected by device filter, not attaching\n",
++                device_connect->vendor_id, device_connect->product_id);
++        return;
++    }
++
+     qemu_mod_timer(dev->attach_timer, dev->next_attach_time);
+ }
+ 
+@@ -1038,15 +1120,27 @@ static void usbredir_device_disconnect(void *priv)
+     for (i = 0; i < MAX_ENDPOINTS; i++) {
+         QTAILQ_INIT(&dev->endpoint[i].bufpq);
+     }
++    dev->interface_info.interface_count = 0;
+ }
+ 
+ static void usbredir_interface_info(void *priv,
+     struct usb_redir_interface_info_header *interface_info)
+ {
+-    /* The intention is to allow specifying acceptable interface classes
+-       for redirection on the cmdline and in the future verify this here,
+-       and disconnect (or never connect) the device if a not accepted
+-       interface class is detected */
++    USBRedirDevice *dev = priv;
++
++    dev->interface_info = *interface_info;
++
++    /*
++     * If we receive interface info after the device has already been
++     * connected (ie on a set_config), re-check the filter.
++     */
++    if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) {
++        if (usbredir_check_filter(dev)) {
++            ERROR("Device no longer matches filter after interface info "
++                  "change, disconnecting!\n");
++            usbredir_device_disconnect(dev);
++        }
++    }
+ }
+ 
+ static void usbredir_ep_info(void *priv,
+@@ -1356,6 +1450,7 @@ static struct USBDeviceInfo usbredir_dev_info = {
+     .qdev.props     = (Property[]) {
+         DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
+         DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
++        DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str),
+         DEFINE_PROP_END_OF_LIST(),
+     },
+ };
+-- 
+1.7.9.3
+
diff --git a/0121-usb-redir-Fix-printing-of-device-version.patch b/0121-usb-redir-Fix-printing-of-device-version.patch
new file mode 100644
index 0000000..854641c
--- /dev/null
+++ b/0121-usb-redir-Fix-printing-of-device-version.patch
@@ -0,0 +1,33 @@
+From 6c13e7b9448b10d966bb99c00c5120678ccd2a3f Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Sat, 18 Feb 2012 09:12:14 +0100
+Subject: [PATCH 121/140] usb-redir: Fix printing of device version
+
+The device version is in bcd format, which requires some special handling to
+print.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ usb-redir.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/usb-redir.c b/usb-redir.c
+index 85f40d6..9b804e9 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -1076,8 +1076,10 @@ static void usbredir_device_connect(void *priv,
+                                     usb_redir_cap_connect_device_version)) {
+         INFO("attaching %s device %04x:%04x version %d.%d class %02x\n",
+              speed, device_connect->vendor_id, device_connect->product_id,
+-             device_connect->device_version_bcd >> 8,
+-             device_connect->device_version_bcd & 0xff,
++             ((device_connect->device_version_bcd & 0xf000) >> 12) * 10 +
++             ((device_connect->device_version_bcd & 0x0f00) >>  8),
++             ((device_connect->device_version_bcd & 0x00f0) >>  4) * 10 +
++             ((device_connect->device_version_bcd & 0x000f) >>  0),
+              device_connect->device_class);
+     } else {
+         INFO("attaching %s device %04x:%04x class %02x\n", speed,
+-- 
+1.7.9.3
+
diff --git a/0122-usb-redir-Always-clear-device-state-on-filter-reject.patch b/0122-usb-redir-Always-clear-device-state-on-filter-reject.patch
new file mode 100644
index 0000000..66ccf68
--- /dev/null
+++ b/0122-usb-redir-Always-clear-device-state-on-filter-reject.patch
@@ -0,0 +1,64 @@
+From 49a01afb24b925de97074d093fb072bb7de470f9 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Sat, 18 Feb 2012 09:18:57 +0100
+Subject: [PATCH 122/140] usb-redir: Always clear device state on filter
+ reject
+
+Always call usbredir_device_disconnect() when usbredir_check_filter() fails
+to clean up all the device state (ie received endpoint info).
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ usb-redir.c |   11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/usb-redir.c b/usb-redir.c
+index 9b804e9..fe3b0a3 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -985,7 +985,7 @@ static int usbredir_check_filter(USBRedirDevice *dev)
+ {
+     if (dev->interface_info.interface_count == 0) {
+         ERROR("No interface info for device\n");
+-        return -1;
++        goto error;
+     }
+ 
+     if (dev->filter_rules) {
+@@ -993,7 +993,7 @@ static int usbredir_check_filter(USBRedirDevice *dev)
+                                     usb_redir_cap_connect_device_version)) {
+             ERROR("Device filter specified and peer does not have the "
+                   "connect_device_version capability\n");
+-            return -1;
++            goto error;
+         }
+ 
+         if (usbredirfilter_check(
+@@ -1010,11 +1010,15 @@ static int usbredir_check_filter(USBRedirDevice *dev)
+                 dev->device_info.product_id,
+                 dev->device_info.device_version_bcd,
+                 0) != 0) {
+-            return -1;
++            goto error;
+         }
+     }
+ 
+     return 0;
++
++error:
++    usbredir_device_disconnect(dev);
++    return -1;
+ }
+ 
+ /*
+@@ -1140,7 +1144,6 @@ static void usbredir_interface_info(void *priv,
+         if (usbredir_check_filter(dev)) {
+             ERROR("Device no longer matches filter after interface info "
+                   "change, disconnecting!\n");
+-            usbredir_device_disconnect(dev);
+         }
+     }
+ }
+-- 
+1.7.9.3
+
diff --git a/0123-usb-redir-Let-the-usb-host-know-about-our-device-fil.patch b/0123-usb-redir-Let-the-usb-host-know-about-our-device-fil.patch
new file mode 100644
index 0000000..9a166bf
--- /dev/null
+++ b/0123-usb-redir-Let-the-usb-host-know-about-our-device-fil.patch
@@ -0,0 +1,93 @@
+From f04315d9210f22e5d7317f1cfb3c076fb93b3c08 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Sun, 19 Feb 2012 09:58:03 +0100
+Subject: [PATCH 123/140] usb-redir: Let the usb-host know about our device
+ filtering
+
+libusbredirparser-0.3.4 adds 2 new packets which allows us to notify
+the usb-host:
+-about the usb device filter we have (if any), so that it knows not the even
+ try to redirect certain devices
+-when we reject a device based on filtering (in case it tries anyways)
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ configure   |    2 +-
+ usb-redir.c |   20 ++++++++++++++++++++
+ 2 files changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/configure b/configure
+index c7e37df..a4848a4 100755
+--- a/configure
++++ b/configure
+@@ -2541,7 +2541,7 @@ fi
+ 
+ # check for usbredirparser for usb network redirection support
+ if test "$usb_redir" != "no" ; then
+-    if $pkg_config --atleast-version=0.3.3 libusbredirparser >/dev/null 2>&1 ; then
++    if $pkg_config --atleast-version=0.3.4 libusbredirparser >/dev/null 2>&1 ; then
+         usb_redir="yes"
+         usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
+         usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
+diff --git a/usb-redir.c b/usb-redir.c
+index fe3b0a3..d10d8de 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -106,6 +106,7 @@ struct AsyncURB {
+     QTAILQ_ENTRY(AsyncURB)next;
+ };
+ 
++static void usbredir_hello(void *priv, struct usb_redir_hello_header *h);
+ static void usbredir_device_connect(void *priv,
+     struct usb_redir_device_connect_header *device_connect);
+ static void usbredir_device_disconnect(void *priv);
+@@ -812,6 +813,7 @@ static void usbredir_open_close_bh(void *opaque)
+         dev->parser->log_func = usbredir_log;
+         dev->parser->read_func = usbredir_read;
+         dev->parser->write_func = usbredir_write;
++        dev->parser->hello_func = usbredir_hello;
+         dev->parser->device_connect_func = usbredir_device_connect;
+         dev->parser->device_disconnect_func = usbredir_device_disconnect;
+         dev->parser->interface_info_func = usbredir_interface_info;
+@@ -830,6 +832,7 @@ static void usbredir_open_close_bh(void *opaque)
+         dev->read_buf_size = 0;
+ 
+         usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
++        usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
+         usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0);
+         usbredirparser_do_write(dev->parser);
+     }
+@@ -1018,6 +1021,10 @@ static int usbredir_check_filter(USBRedirDevice *dev)
+ 
+ error:
+     usbredir_device_disconnect(dev);
++    if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) {
++        usbredirparser_send_filter_reject(dev->parser);
++        usbredirparser_do_write(dev->parser);
++    }
+     return -1;
+ }
+ 
+@@ -1043,6 +1050,19 @@ static int usbredir_handle_status(USBRedirDevice *dev,
+     }
+ }
+ 
++static void usbredir_hello(void *priv, struct usb_redir_hello_header *h)
++{
++    USBRedirDevice *dev = priv;
++
++    /* Try to send the filter info now that we've the usb-host's caps */
++    if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter) &&
++            dev->filter_rules) {
++        usbredirparser_send_filter_filter(dev->parser, dev->filter_rules,
++                                          dev->filter_rules_count);
++        usbredirparser_do_write(dev->parser);
++    }
++}
++
+ static void usbredir_device_connect(void *priv,
+     struct usb_redir_device_connect_header *device_connect)
+ {
+-- 
+1.7.9.3
+
diff --git a/0124-usb-redir-Limit-return-values-returned-by-iso-packet.patch b/0124-usb-redir-Limit-return-values-returned-by-iso-packet.patch
new file mode 100644
index 0000000..d35ae08
--- /dev/null
+++ b/0124-usb-redir-Limit-return-values-returned-by-iso-packet.patch
@@ -0,0 +1,42 @@
+From 91338d1b4df14f7454d1b52200d2ae4eb957fa72 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Sun, 26 Feb 2012 15:28:51 +0100
+Subject: [PATCH 124/140] usb-redir: Limit return values returned by iso
+ packets
+
+The usbredir protocol uses a status of usb_redir_stall to indicate that
+an iso data stream has stopped (ie because the urbs failed on resubmit),
+but iso packets should never return a result of USB_RET_STALL, since iso
+endpoints cannot stall. So instead simply always return USB_RET_NAK on
+iso stream errors.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ usb-redir.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/usb-redir.c b/usb-redir.c
+index d10d8de..c76e55d 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -441,7 +441,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+             /* Check iso_error for stream errors, otherwise its an underrun */
+             status = dev->endpoint[EP2I(ep)].iso_error;
+             dev->endpoint[EP2I(ep)].iso_error = 0;
+-            return usbredir_handle_status(dev, status, 0);
++            return status ? USB_RET_NAK : 0;
+         }
+         DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep,
+                  isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size);
+@@ -449,7 +449,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+         status = isop->status;
+         if (status != usb_redir_success) {
+             bufp_free(dev, isop, ep);
+-            return usbredir_handle_status(dev, status, 0);
++            return USB_RET_NAK;
+         }
+ 
+         len = isop->len;
+-- 
+1.7.9.3
+
diff --git a/0125-usb-redir-Return-USB_RET_NAK-when-we-ve-no-data-for-.patch b/0125-usb-redir-Return-USB_RET_NAK-when-we-ve-no-data-for-.patch
new file mode 100644
index 0000000..516b431
--- /dev/null
+++ b/0125-usb-redir-Return-USB_RET_NAK-when-we-ve-no-data-for-.patch
@@ -0,0 +1,33 @@
+From ddb24b5063e3b4c90295bd4ddaab3bfc428ae79b Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Sun, 26 Feb 2012 15:51:50 +0100
+Subject: [PATCH 125/140] usb-redir: Return USB_RET_NAK when we've no data for
+ an interrupt endpoint
+
+We should return USB_RET_NAK, rather then a 0 sized packet, when we've no data
+for an interrupt IN endpoint.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ usb-redir.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/usb-redir.c b/usb-redir.c
+index c76e55d..629c87d 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -558,7 +558,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
+             /* Check interrupt_error for stream errors */
+             status = dev->endpoint[EP2I(ep)].interrupt_error;
+             dev->endpoint[EP2I(ep)].interrupt_error = 0;
+-            return usbredir_handle_status(dev, status, 0);
++            if (status) {
++                return usbredir_handle_status(dev, status, 0);
++            }
++            return USB_RET_NAK;
+         }
+         DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
+                 intp->status, intp->len);
+-- 
+1.7.9.3
+
diff --git a/0126-usb-ehci-Handle-ISO-packets-failing-with-an-error-ot.patch b/0126-usb-ehci-Handle-ISO-packets-failing-with-an-error-ot.patch
new file mode 100644
index 0000000..7c3c59d
--- /dev/null
+++ b/0126-usb-ehci-Handle-ISO-packets-failing-with-an-error-ot.patch
@@ -0,0 +1,64 @@
+From 7a3acb928b617b33605c779e7df05c2c896844b1 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Mon, 20 Feb 2012 16:27:47 +0100
+Subject: [PATCH 126/140] usb-ehci: Handle ISO packets failing with an error
+ other then NAK
+
+Before this patch the ehci code was not checking for any other errors other
+then USB_RET_NAK. This causes 2 problems:
+1) Other errors are not reported to the guest.
+2) When transactions with the ITD_XACT_IOC bit set completing with another
+   error would not result in USBSTS_INT getting set.
+
+I hit this problem when unplugging devices while iso data was streaming from
+the device to the guest. When this happens it takes a while for the guest to
+process the unplugging and remove ISO transactions from the ehci schedule, in
+the mean time these transactions would complete with a result of USB_RET_NODEV,
+which was not handled. This lead to the Linux guest's usb subsystem "hanging",
+that is it would no longer see new usb devices getting plugged in and running
+for example lsusb would lead to a stuck (D state) lsusb process. This patch
+fixes this.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |   22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index 69bcc4b..a6b6ae5 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -1512,11 +1512,27 @@ static int ehci_process_itd(EHCIState *ehci,
+                     /* IN */
+                     set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
+                 }
+-
+-                if (itd->transact[i] & ITD_XACT_IOC) {
+-                    ehci_record_interrupt(ehci, USBSTS_INT);
++            } else {
++                switch (ret) {
++                default:
++                    fprintf(stderr, "Unexpected iso usb result: %d\n", ret);
++                    /* Fall through */
++                case USB_RET_NODEV:
++                    /* 3.3.2: XACTERR is only allowed on IN transactions */
++                    if (dir) {
++                        itd->transact[i] |= ITD_XACT_XACTERR;
++                        ehci_record_interrupt(ehci, USBSTS_ERRINT);
++                    }
++                    break;
++                case USB_RET_BABBLE:
++                    itd->transact[i] |= ITD_XACT_BABBLE;
++                    ehci_record_interrupt(ehci, USBSTS_ERRINT);
++                    break;
+                 }
+             }
++            if (itd->transact[i] & ITD_XACT_IOC) {
++                ehci_record_interrupt(ehci, USBSTS_INT);
++            }
+             itd->transact[i] &= ~ITD_XACT_ACTIVE;
+         }
+     }
+-- 
+1.7.9.3
+
diff --git a/0127-usb-ehci-Never-follow-table-entries-with-the-T-bit-s.patch b/0127-usb-ehci-Never-follow-table-entries-with-the-T-bit-s.patch
new file mode 100644
index 0000000..e437048
--- /dev/null
+++ b/0127-usb-ehci-Never-follow-table-entries-with-the-T-bit-s.patch
@@ -0,0 +1,61 @@
+From 82e500c24a026323e0b8b869e227cc68b179fb11 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Mon, 27 Feb 2012 11:44:52 +0100
+Subject: [PATCH 127/140] usb-ehci: Never follow table entries with the T-bit
+ set
+
+Before this patch the T-bit was not checked in 2 places, while it should be.
+
+Once we properly check the T-bit everywhere we no longer need the weird
+entry < 0x1000 and entry > 0x1000 checks, so this patch removes them.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |   10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index a6b6ae5..37076a9 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -1596,8 +1596,7 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)
+     int again = 0;
+     uint32_t entry = ehci_get_fetch_addr(ehci, async);
+ 
+-    if (entry < 0x1000) {
+-        DPRINTF("fetchentry: entry invalid (0x%08x)\n", entry);
++    if (NLPTR_TBIT(entry)) {
+         ehci_set_state(ehci, async, EST_ACTIVE);
+         goto out;
+     }
+@@ -1705,7 +1704,8 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
+     if (q->qh.token & QTD_TOKEN_HALT) {
+         ehci_set_state(ehci, async, EST_HORIZONTALQH);
+ 
+-    } else if ((q->qh.token & QTD_TOKEN_ACTIVE) && (q->qh.current_qtd > 0x1000)) {
++    } else if ((q->qh.token & QTD_TOKEN_ACTIVE) &&
++               (NLPTR_TBIT(q->qh.current_qtd) == 0)) {
+         q->qtdaddr = q->qh.current_qtd;
+         ehci_set_state(ehci, async, EST_FETCHQTD);
+ 
+@@ -1784,7 +1784,6 @@ static int ehci_state_advqueue(EHCIQueue *q, int async)
+      * want data and alt-next qTD is valid
+      */
+     if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
+-        (q->qh.altnext_qtd > 0x1000) &&
+         (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) {
+         q->qtdaddr = q->qh.altnext_qtd;
+         ehci_set_state(q->ehci, async, EST_FETCHQTD);
+@@ -1792,8 +1791,7 @@ static int ehci_state_advqueue(EHCIQueue *q, int async)
+     /*
+      *  next qTD is valid
+      */
+-    } else if ((q->qh.next_qtd > 0x1000) &&
+-               (NLPTR_TBIT(q->qh.next_qtd) == 0)) {
++    } else if (NLPTR_TBIT(q->qh.next_qtd) == 0) {
+         q->qtdaddr = q->qh.next_qtd;
+         ehci_set_state(q->ehci, async, EST_FETCHQTD);
+ 
+-- 
+1.7.9.3
+
diff --git a/0128-usb-ehci-split-our-qh-queue-into-async-and-periodic-.patch b/0128-usb-ehci-split-our-qh-queue-into-async-and-periodic-.patch
new file mode 100644
index 0000000..6272c84
--- /dev/null
+++ b/0128-usb-ehci-split-our-qh-queue-into-async-and-periodic-.patch
@@ -0,0 +1,219 @@
+From 0f1e5b8d4f36de8b6b1301740226c9858b5a0318 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Tue, 28 Feb 2012 16:34:38 +0100
+Subject: [PATCH 128/140] usb-ehci: split our qh queue into async and periodic
+ queues
+
+qhs can be part of both the async and the periodic schedule, as is shown
+in later patches in this series it is useful to keep track of the qhs on
+a per schedule basis.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |   62 ++++++++++++++++++++++++++++++++++-----------------------
+ 1 file changed, 37 insertions(+), 25 deletions(-)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index 37076a9..980cce3 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -347,7 +347,6 @@ enum async_state {
+ struct EHCIQueue {
+     EHCIState *ehci;
+     QTAILQ_ENTRY(EHCIQueue) next;
+-    bool async_schedule;
+     uint32_t seen;
+     uint64_t ts;
+ 
+@@ -367,6 +366,8 @@ struct EHCIQueue {
+     int usb_status;
+ };
+ 
++typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
++
+ struct EHCIState {
+     PCIDevice dev;
+     USBBus bus;
+@@ -410,7 +411,8 @@ struct EHCIState {
+     USBPort ports[NB_PORTS];
+     USBPort *companion_ports[NB_PORTS];
+     uint32_t usbsts_pending;
+-    QTAILQ_HEAD(, EHCIQueue) queues;
++    EHCIQueueHead aqueues;
++    EHCIQueueHead pqueues;
+ 
+     uint32_t a_fetch_addr;   // which address to look at next
+     uint32_t p_fetch_addr;   // which address to look at next
+@@ -660,31 +662,34 @@ static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr,
+ 
+ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async)
+ {
++    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
+     EHCIQueue *q;
+ 
+     q = g_malloc0(sizeof(*q));
+     q->ehci = ehci;
+-    q->async_schedule = async;
+-    QTAILQ_INSERT_HEAD(&ehci->queues, q, next);
++    QTAILQ_INSERT_HEAD(head, q, next);
+     trace_usb_ehci_queue_action(q, "alloc");
+     return q;
+ }
+ 
+-static void ehci_free_queue(EHCIQueue *q)
++static void ehci_free_queue(EHCIQueue *q, int async)
+ {
++    EHCIQueueHead *head = async ? &q->ehci->aqueues : &q->ehci->pqueues;
+     trace_usb_ehci_queue_action(q, "free");
+     if (q->async == EHCI_ASYNC_INFLIGHT) {
+         usb_cancel_packet(&q->packet);
+     }
+-    QTAILQ_REMOVE(&q->ehci->queues, q, next);
++    QTAILQ_REMOVE(head, q, next);
+     g_free(q);
+ }
+ 
+-static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr)
++static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
++                                        int async)
+ {
++    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
+     EHCIQueue *q;
+ 
+-    QTAILQ_FOREACH(q, &ehci->queues, next) {
++    QTAILQ_FOREACH(q, head, next) {
+         if (addr == q->qhaddr) {
+             return q;
+         }
+@@ -692,11 +697,12 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr)
+     return NULL;
+ }
+ 
+-static void ehci_queues_rip_unused(EHCIState *ehci)
++static void ehci_queues_rip_unused(EHCIState *ehci, int async)
+ {
++    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
+     EHCIQueue *q, *tmp;
+ 
+-    QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
++    QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
+         if (q->seen) {
+             q->seen = 0;
+             q->ts = ehci->last_run_ns;
+@@ -706,28 +712,30 @@ static void ehci_queues_rip_unused(EHCIState *ehci)
+             /* allow 0.25 sec idle */
+             continue;
+         }
+-        ehci_free_queue(q);
++        ehci_free_queue(q, async);
+     }
+ }
+ 
+-static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev)
++static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async)
+ {
++    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
+     EHCIQueue *q, *tmp;
+ 
+-    QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
++    QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
+         if (q->packet.owner != dev) {
+             continue;
+         }
+-        ehci_free_queue(q);
++        ehci_free_queue(q, async);
+     }
+ }
+ 
+-static void ehci_queues_rip_all(EHCIState *ehci)
++static void ehci_queues_rip_all(EHCIState *ehci, int async)
+ {
++    EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
+     EHCIQueue *q, *tmp;
+ 
+-    QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
+-        ehci_free_queue(q);
++    QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
++        ehci_free_queue(q, async);
+     }
+ }
+ 
+@@ -772,7 +780,8 @@ static void ehci_detach(USBPort *port)
+         return;
+     }
+ 
+-    ehci_queues_rip_device(s, port->dev);
++    ehci_queues_rip_device(s, port->dev, 0);
++    ehci_queues_rip_device(s, port->dev, 1);
+ 
+     *portsc &= ~(PORTSC_CONNECT|PORTSC_PED);
+     *portsc |= PORTSC_CSC;
+@@ -792,7 +801,8 @@ static void ehci_child_detach(USBPort *port, USBDevice *child)
+         return;
+     }
+ 
+-    ehci_queues_rip_device(s, child);
++    ehci_queues_rip_device(s, child, 0);
++    ehci_queues_rip_device(s, child, 1);
+ }
+ 
+ static void ehci_wakeup(USBPort *port)
+@@ -890,7 +900,8 @@ static void ehci_reset(void *opaque)
+             usb_send_msg(devs[i], USB_MSG_RESET);
+         }
+     }
+-    ehci_queues_rip_all(s);
++    ehci_queues_rip_all(s, 0);
++    ehci_queues_rip_all(s, 1);
+ }
+ 
+ static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr)
+@@ -1554,7 +1565,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci,  int async)
+         ehci_set_usbsts(ehci, USBSTS_REC);
+     }
+ 
+-    ehci_queues_rip_unused(ehci);
++    ehci_queues_rip_unused(ehci, async);
+ 
+     /*  Find the head of the list (4.9.1.1) */
+     for(i = 0; i < MAX_QH; i++) {
+@@ -1641,7 +1652,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
+     int reload;
+ 
+     entry = ehci_get_fetch_addr(ehci, async);
+-    q = ehci_find_queue_by_qh(ehci, entry);
++    q = ehci_find_queue_by_qh(ehci, entry, async);
+     if (NULL == q) {
+         q = ehci_alloc_queue(ehci, async);
+     }
+@@ -2092,7 +2103,7 @@ static void ehci_advance_state(EHCIState *ehci,
+ 
+ static void ehci_advance_async_state(EHCIState *ehci)
+ {
+-    int async = 1;
++    const int async = 1;
+ 
+     switch(ehci_get_state(ehci, async)) {
+     case EST_INACTIVE:
+@@ -2149,7 +2160,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
+ {
+     uint32_t entry;
+     uint32_t list;
+-    int async = 0;
++    const int async = 0;
+ 
+     // 4.6
+ 
+@@ -2366,7 +2377,8 @@ static int usb_ehci_initfn(PCIDevice *dev)
+     }
+ 
+     s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s);
+-    QTAILQ_INIT(&s->queues);
++    QTAILQ_INIT(&s->aqueues);
++    QTAILQ_INIT(&s->pqueues);
+ 
+     qemu_register_reset(ehci_reset, s);
+ 
+-- 
+1.7.9.3
+
diff --git a/0129-usb-ehci-always-call-ehci_queues_rip_unused-for-peri.patch b/0129-usb-ehci-always-call-ehci_queues_rip_unused-for-peri.patch
new file mode 100644
index 0000000..6305ec4
--- /dev/null
+++ b/0129-usb-ehci-always-call-ehci_queues_rip_unused-for-peri.patch
@@ -0,0 +1,42 @@
+From 320063f7165c5a5f9ddd5a09a4663bc1a81f5bd6 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Fri, 2 Mar 2012 13:52:44 +0100
+Subject: [PATCH 129/140] usb-ehci: always call ehci_queues_rip_unused for
+ period queues
+
+Before this patch USB 2 devices with interrupt endpoints were not working
+properly. The problem is that to avoid loops we stop processing as soon
+as we encounter a queue-head (qh) we've already seen since qhs can be linked
+in a circular fashion, this is tracked by the seen flag in our qh struct.
+
+The resetting of the seen flag is done from ehci_queues_rip_unused which
+before this patch was only called when executing the statemachine for the
+async schedule.
+
+But packets for interrupt endpoints are part of the periodic schedule! So what
+would happen is that when there were no ctrl or bulk packets for a USB 2
+device with an interrupt endpoint, the async schedule would become non
+active, then ehci_queues_rip_unused would no longer get called and when
+processing the qhs for the interrupt endpoints from the periodic schedule
+their seen bit would still be 1 and they would be skipped.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index 980cce3..422afc8 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -2195,6 +2195,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
+         ehci_set_fetch_addr(ehci, async,entry);
+         ehci_set_state(ehci, async, EST_FETCHENTRY);
+         ehci_advance_state(ehci, async);
++        ehci_queues_rip_unused(ehci, async, 0);
+         break;
+ 
+     default:
+-- 
+1.7.9.3
+
diff --git a/0130-usb-ehci-Drop-cached-qhs-when-the-doorbell-gets-rung.patch b/0130-usb-ehci-Drop-cached-qhs-when-the-doorbell-gets-rung.patch
new file mode 100644
index 0000000..fa1b20d
--- /dev/null
+++ b/0130-usb-ehci-Drop-cached-qhs-when-the-doorbell-gets-rung.patch
@@ -0,0 +1,115 @@
+From 35562fb521547e081e732453a6395fc00d9ee9e4 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Thu, 1 Mar 2012 15:20:17 +0100
+Subject: [PATCH 130/140] usb-ehci: Drop cached qhs when the doorbell gets
+ rung
+
+The purpose of the IAAD bit / the doorbell is to make the ehci controller
+forget about cached qhs, this is mainly used when cancelling transactions,
+the qh is unlinked from the async schedule and then the doorbell gets rung,
+once the doorbell is acked by the controller the hcd knows that the qh is
+no longer in use and that it can do something else with the memory, such
+as re-use it for a new qh! But we keep our struct representing this qh around
+for circa 250 ms. This allows for a (mightily large) race window where the
+following could happen:
+-hcd submits a qh at address 0xdeadbeef
+-our ehci code sees the qh, sends a request to a usb-device, gets a result
+ of USB_RET_ASYNC, sets the async_state of the qh to EHCI_ASYNC_INFLIGHT
+-hcd unlinks the qh at address 0xdeadbeef
+-hcd rings the doorbell, wait for us to ack it
+-hcd re-uses the qh at address 0xdeadbeef
+-our ehci code sees the qh, looks in the async_queue, sees there already is
+ a qh at address 0xdeadbeef there with async_state of EHCI_ASYNC_INFLIGHT,
+ does nothing
+-the *original* (which the hcd thinks it has cancelled) transaction finishes
+-our ehci code sees the qh on yet another pass through the async list,
+ looks in the async_queue, sees there already is a qh at address 0xdeadbeef
+ there with async_state of EHCI_ASYNC_COMPLETED, and finished the transaction
+ with the results of the *original* transaction.
+
+Not good (tm), this patch fixes this race by removing all qhs which have not
+been seen during the last cycle through the async list immidiately when the
+doorbell is rung.
+
+Note this patch does not fix any actually observed problem, but upon
+reading of the EHCI spec it became apparent to me that the above race could
+happen and the usb-ehci behavior from before this patch is not good.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |   31 ++++++++++++++++---------------
+ 1 file changed, 16 insertions(+), 15 deletions(-)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index 422afc8..b8ba483 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -697,7 +697,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
+     return NULL;
+ }
+ 
+-static void ehci_queues_rip_unused(EHCIState *ehci, int async)
++static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush)
+ {
+     EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
+     EHCIQueue *q, *tmp;
+@@ -708,7 +708,7 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async)
+             q->ts = ehci->last_run_ns;
+             continue;
+         }
+-        if (ehci->last_run_ns < q->ts + 250000000) {
++        if (!flush && ehci->last_run_ns < q->ts + 250000000) {
+             /* allow 0.25 sec idle */
+             continue;
+         }
+@@ -1565,7 +1565,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci,  int async)
+         ehci_set_usbsts(ehci, USBSTS_REC);
+     }
+ 
+-    ehci_queues_rip_unused(ehci, async);
++    ehci_queues_rip_unused(ehci, async, 0);
+ 
+     /*  Find the head of the list (4.9.1.1) */
+     for(i = 0; i < MAX_QH; i++) {
+@@ -2121,18 +2121,7 @@ static void ehci_advance_async_state(EHCIState *ehci)
+             break;
+         }
+ 
+-        /* If the doorbell is set, the guest wants to make a change to the
+-         * schedule. The host controller needs to release cached data.
+-         * (section 4.8.2)
+-         */
+-        if (ehci->usbcmd & USBCMD_IAAD) {
+-            DPRINTF("ASYNC: doorbell request acknowledged\n");
+-            ehci->usbcmd &= ~USBCMD_IAAD;
+-            ehci_set_interrupt(ehci, USBSTS_IAA);
+-            break;
+-        }
+-
+-        /* make sure guest has acknowledged */
++        /* make sure guest has acknowledged the doorbell interrupt */
+         /* TO-DO: is this really needed? */
+         if (ehci->usbsts & USBSTS_IAA) {
+             DPRINTF("IAA status bit still set.\n");
+@@ -2146,6 +2135,18 @@ static void ehci_advance_async_state(EHCIState *ehci)
+ 
+         ehci_set_state(ehci, async, EST_WAITLISTHEAD);
+         ehci_advance_state(ehci, async);
++
++        /* If the doorbell is set, the guest wants to make a change to the
++         * schedule. The host controller needs to release cached data.
++         * (section 4.8.2)
++         */
++        if (ehci->usbcmd & USBCMD_IAAD) {
++            /* Remove all unseen qhs from the async qhs queue */
++            ehci_queues_rip_unused(ehci, async, 1);
++            DPRINTF("ASYNC: doorbell request acknowledged\n");
++            ehci->usbcmd &= ~USBCMD_IAAD;
++            ehci_set_interrupt(ehci, USBSTS_IAA);
++        }
+         break;
+ 
+     default:
+-- 
+1.7.9.3
+
diff --git a/0131-usb-ehci-Rip-the-queues-when-the-async-or-period-sch.patch b/0131-usb-ehci-Rip-the-queues-when-the-async-or-period-sch.patch
new file mode 100644
index 0000000..3f07ca0
--- /dev/null
+++ b/0131-usb-ehci-Rip-the-queues-when-the-async-or-period-sch.patch
@@ -0,0 +1,44 @@
+From cbb6384d32c4926822ba9216992253deef9ef3b5 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Fri, 2 Mar 2012 11:02:04 +0100
+Subject: [PATCH 131/140] usb-ehci: Rip the queues when the async or period
+ schedule is halted
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index b8ba483..11eded7 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -1054,7 +1054,8 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
+ 
+         if (!(val & USBCMD_RUNSTOP) && (s->usbcmd & USBCMD_RUNSTOP)) {
+             qemu_del_timer(s->frame_timer);
+-            // TODO - should finish out some stuff before setting halt
++            ehci_queues_rip_all(s, 0);
++            ehci_queues_rip_all(s, 1);
+             ehci_set_usbsts(s, USBSTS_HALT);
+         }
+ 
+@@ -2116,6 +2117,7 @@ static void ehci_advance_async_state(EHCIState *ehci)
+ 
+     case EST_ACTIVE:
+         if ( !(ehci->usbcmd & USBCMD_ASE)) {
++            ehci_queues_rip_all(ehci, async);
+             ehci_clear_usbsts(ehci, USBSTS_ASS);
+             ehci_set_state(ehci, async, EST_INACTIVE);
+             break;
+@@ -2176,6 +2178,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
+ 
+     case EST_ACTIVE:
+         if ( !(ehci->frindex & 7) && !(ehci->usbcmd & USBCMD_PSE)) {
++            ehci_queues_rip_all(ehci, async);
+             ehci_clear_usbsts(ehci, USBSTS_PSS);
+             ehci_set_state(ehci, async, EST_INACTIVE);
+             break;
+-- 
+1.7.9.3
+
diff --git a/0132-usb-ehci-Any-packet-completion-except-for-NAK-should.patch b/0132-usb-ehci-Any-packet-completion-except-for-NAK-should.patch
new file mode 100644
index 0000000..7107ed8
--- /dev/null
+++ b/0132-usb-ehci-Any-packet-completion-except-for-NAK-should.patch
@@ -0,0 +1,33 @@
+From 73a9969c47459ee208d6247999823f2a36ee51fe Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Thu, 1 Mar 2012 16:34:56 +0100
+Subject: [PATCH 132/140] usb-ehci: Any packet completion except for NAK
+ should set the interrupt
+
+As clearly stated in the 2.3.2 of the EHCI spec, any time USBERRINT get
+sets then if the td has its IOC bit set USBINT should be set as well.
+
+This means that for any status except for USB_RET_NAK we should set
+USBINT if the IOC bit is set.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index 11eded7..bc5f591 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -1338,7 +1338,7 @@ err:
+     q->qh.token ^= QTD_TOKEN_DTOGGLE;
+     q->qh.token &= ~QTD_TOKEN_ACTIVE;
+ 
+-    if ((q->usb_status >= 0) && (q->qh.token & QTD_TOKEN_IOC)) {
++    if ((q->usb_status != USB_RET_NAK) && (q->qh.token & QTD_TOKEN_IOC)) {
+         ehci_record_interrupt(q->ehci, USBSTS_INT);
+     }
+ }
+-- 
+1.7.9.3
+
diff --git a/0133-usb-ehci-Fix-cerr-tracking.patch b/0133-usb-ehci-Fix-cerr-tracking.patch
new file mode 100644
index 0000000..6ae9d8e
--- /dev/null
+++ b/0133-usb-ehci-Fix-cerr-tracking.patch
@@ -0,0 +1,72 @@
+From 6e6bfa88ae3867afd8258b43e3c05cba2585ee37 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Thu, 1 Mar 2012 21:43:56 +0100
+Subject: [PATCH 133/140] usb-ehci: Fix cerr tracking
+
+cerr should only be decremented on errors which cause XactErr to be set, and
+when that happens the failing transaction should be retried until cerr reaches
+0 and only then should USBSTS_ERRINT be set (and inactive cleared and
+USBSTS_INT set if requested).
+
+Since we don't have any hardware level errors (and in case of redirection
+the real hardware has already retried), re-trying makes no sense, so
+immediately set cerr to 0 on errors which set XactErr.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |   19 ++++++-------------
+ 1 file changed, 6 insertions(+), 13 deletions(-)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index bc5f591..a3d5c11 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -1269,7 +1269,7 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
+ 
+ static void ehci_execute_complete(EHCIQueue *q)
+ {
+-    int c_err, reload;
++    int reload;
+ 
+     assert(q->async != EHCI_ASYNC_INFLIGHT);
+     q->async = EHCI_ASYNC_NONE;
+@@ -1278,15 +1278,10 @@ static void ehci_execute_complete(EHCIQueue *q)
+             q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status);
+ 
+     if (q->usb_status < 0) {
+-err:
+-        /* TO-DO: put this is in a function that can be invoked below as well */
+-        c_err = get_field(q->qh.token, QTD_TOKEN_CERR);
+-        c_err--;
+-        set_field(&q->qh.token, c_err, QTD_TOKEN_CERR);
+-
+         switch(q->usb_status) {
+         case USB_RET_NODEV:
+             q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
++            set_field(&q->qh.token, 0, QTD_TOKEN_CERR);
+             ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
+             break;
+         case USB_RET_STALL:
+@@ -1314,15 +1309,13 @@ err:
+             assert(0);
+             break;
+         }
++    } else if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) {
++        q->usb_status = USB_RET_BABBLE;
++        q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
++        ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
+     } else {
+-        // DPRINTF("Short packet condition\n");
+         // TODO check 4.12 for splits
+ 
+-        if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) {
+-            q->usb_status = USB_RET_BABBLE;
+-            goto err;
+-        }
+-
+         if (q->tbytes && q->pid == USB_TOKEN_IN) {
+             q->tbytes -= q->usb_status;
+         } else {
+-- 
+1.7.9.3
+
diff --git a/0134-usb-ehci-Remove-dead-nakcnt-code.patch b/0134-usb-ehci-Remove-dead-nakcnt-code.patch
new file mode 100644
index 0000000..657ab26
--- /dev/null
+++ b/0134-usb-ehci-Remove-dead-nakcnt-code.patch
@@ -0,0 +1,78 @@
+From 6177c3610b6416a7200ae6c6985f01fccdbdc7e5 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Thu, 1 Mar 2012 23:11:13 +0100
+Subject: [PATCH 134/140] usb-ehci: Remove dead nakcnt code
+
+This patch removes 2 bits of dead nakcnt code:
+
+1) usb_ehci_execute calls ehci_qh_do_overlay which does:
+nakcnt = reload;
+and then has a block of code which is conditional on:
+if (reload && !nakcnt) {
+which ofcourse is never true now as nakcnt == reload.
+
+2) ehci_state_fetchqh does:
+nakcnt = reload;
+but before nakcnt is ever used ehci_state_fetchqh is always followed
+by a ehci_qh_do_overlay call which also does:
+nakcnt = reload;
+So doing this from ehci_state_fetchqh is redundant.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |   20 --------------------
+ 1 file changed, 20 deletions(-)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index a3d5c11..92cdf2a 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -1643,7 +1643,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
+ {
+     uint32_t entry;
+     EHCIQueue *q;
+-    int reload;
+ 
+     entry = ehci_get_fetch_addr(ehci, async);
+     q = ehci_find_queue_by_qh(ehci, entry, async);
+@@ -1701,11 +1700,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
+     }
+ #endif
+ 
+-    reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+-    if (reload) {
+-        set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
+-    }
+-
+     if (q->qh.token & QTD_TOKEN_HALT) {
+         ehci_set_state(ehci, async, EST_HORIZONTALQH);
+ 
+@@ -1865,25 +1859,11 @@ static void ehci_flush_qh(EHCIQueue *q)
+ static int ehci_state_execute(EHCIQueue *q, int async)
+ {
+     int again = 0;
+-    int reload, nakcnt;
+-    int smask;
+ 
+     if (ehci_qh_do_overlay(q) != 0) {
+         return -1;
+     }
+ 
+-    smask = get_field(q->qh.epcap, QH_EPCAP_SMASK);
+-
+-    if (!smask) {
+-        reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+-        nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
+-        if (reload && !nakcnt) {
+-            ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
+-            again = 1;
+-            goto out;
+-        }
+-    }
+-
+     // TODO verify enough time remains in the uframe as in 4.4.1.1
+     // TODO write back ptr to async list when done or out of time
+     // TODO Windows does not seem to ever set the MULT field
+-- 
+1.7.9.3
+
diff --git a/0135-usb-ehci-Fix-and-simplify-nakcnt-handling.patch b/0135-usb-ehci-Fix-and-simplify-nakcnt-handling.patch
new file mode 100644
index 0000000..351f9e4
--- /dev/null
+++ b/0135-usb-ehci-Fix-and-simplify-nakcnt-handling.patch
@@ -0,0 +1,120 @@
+From 2d9b6cb9bd00ede47635dc4db413f647143d5a1d Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Thu, 1 Mar 2012 23:55:11 +0100
+Subject: [PATCH 135/140] usb-ehci: Fix and simplify nakcnt handling
+
+The nakcnt code in ehci_execute_complete() marked transactions as finished
+when a packet completed with a result of USB_RET_NAK, but USB_RET_NAK
+means that the device cannot receive / send data at that time and that
+the transaction should be retried later, which is also what the usb-uhci
+and usb-ohci code does.
+
+Note that there already was some special code in place to handle this
+for interrupt endpoints in the form of doing a return from
+ehci_execute_complete() when reload == 0, but that for bulk transactions
+this was not handled correctly (where as for example the usb-ccid device does
+return USB_RET_NAK for bulk packets).
+
+Besides that the code in ehci_execute_complete() decrement nakcnt by 1
+on a packet result of USB_RET_NAK, but
+-since the transaction got marked as finished,
+ nakcnt would never be decremented again
+-there is no code checking for nakcnt becoming 0
+-there is no use in re-trying the transaction within the same usb frame /
+ usb-ehci frame-timer call, since the status of emulated devices won't change
+ as long as the usb-ehci frame-timer is running
+So we should simply set the nakcnt to 0 when we get a USB_RET_NAK, thus
+claiming that we've tried reload times (or as many times as possible if
+reload is 0).
+
+Besides the code in ehci_execute_complete() handling USB_RET_NAK there
+was also code handling it in ehci_state_executing(), which calls
+ehci_execute_complete(), and then does its own handling on top of the handling
+in ehci_execute_complete(), this code would decrement nakcnt *again* (if not
+already 0), or restore the reload value (which was never changed) on success.
+
+Since the double decrement was wrong to begin with, and is no longer needed
+now that we set nakcnt directly to 0 on USB_RET_NAK, and the restore of reload
+is not needed either, this patch simply removes all nakcnt handling from
+ehci_state_executing().
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |   32 ++++----------------------------
+ 1 file changed, 4 insertions(+), 28 deletions(-)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index 92cdf2a..aa6fae5 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -1269,8 +1269,6 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
+ 
+ static void ehci_execute_complete(EHCIQueue *q)
+ {
+-    int reload;
+-
+     assert(q->async != EHCI_ASYNC_INFLIGHT);
+     q->async = EHCI_ASYNC_NONE;
+ 
+@@ -1289,16 +1287,8 @@ static void ehci_execute_complete(EHCIQueue *q)
+             ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
+             break;
+         case USB_RET_NAK:
+-            /* 4.10.3 */
+-            reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+-            if ((q->pid == USB_TOKEN_IN) && reload) {
+-                int nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
+-                nakcnt--;
+-                set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+-            } else if (!reload) {
+-                return;
+-            }
+-            break;
++            set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT);
++            return; /* We're not done yet with this transaction */
+         case USB_RET_BABBLE:
+             q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
+             ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
+@@ -1331,7 +1321,7 @@ static void ehci_execute_complete(EHCIQueue *q)
+     q->qh.token ^= QTD_TOKEN_DTOGGLE;
+     q->qh.token &= ~QTD_TOKEN_ACTIVE;
+ 
+-    if ((q->usb_status != USB_RET_NAK) && (q->qh.token & QTD_TOKEN_IOC)) {
++    if (q->qh.token & QTD_TOKEN_IOC) {
+         ehci_record_interrupt(q->ehci, USBSTS_INT);
+     }
+ }
+@@ -1905,7 +1895,6 @@ out:
+ static int ehci_state_executing(EHCIQueue *q, int async)
+ {
+     int again = 0;
+-    int reload, nakcnt;
+ 
+     ehci_execute_complete(q);
+     if (q->usb_status == USB_RET_ASYNC) {
+@@ -1925,21 +1914,8 @@ static int ehci_state_executing(EHCIQueue *q, int async)
+         // counter decrements to 0
+     }
+ 
+-    reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+-    if (reload) {
+-        nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
+-        if (q->usb_status == USB_RET_NAK) {
+-            if (nakcnt) {
+-                nakcnt--;
+-            }
+-        } else {
+-            nakcnt = reload;
+-        }
+-        set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+-    }
+-
+     /* 4.10.5 */
+-    if ((q->usb_status == USB_RET_NAK) || (q->qh.token & QTD_TOKEN_ACTIVE)) {
++    if (q->usb_status == USB_RET_NAK) {
+         ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
+     } else {
+         ehci_set_state(q->ehci, async, EST_WRITEBACK);
+-- 
+1.7.9.3
+
diff --git a/0136-usb-ehci-Remove-dead-isoch_pause-code.patch b/0136-usb-ehci-Remove-dead-isoch_pause-code.patch
new file mode 100644
index 0000000..7d47913
--- /dev/null
+++ b/0136-usb-ehci-Remove-dead-isoch_pause-code.patch
@@ -0,0 +1,114 @@
+From 0e6cd6e6da3d0648204526e8ebd79047f48d009a Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Fri, 2 Mar 2012 00:36:50 +0100
+Subject: [PATCH 136/140] usb-ehci: Remove dead isoch_pause code
+
+I see no value in keeping this around, so lets delete it.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |   60 +++++++++++++++------------------------------------------
+ 1 file changed, 15 insertions(+), 45 deletions(-)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index aa6fae5..72c3f2a 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -419,7 +419,6 @@ struct EHCIState {
+ 
+     USBPacket ipacket;
+     QEMUSGList isgl;
+-    int isoch_pause;
+ 
+     uint64_t last_run_ns;
+ };
+@@ -886,7 +885,6 @@ static void ehci_reset(void *opaque)
+ 
+     s->astate = EST_INACTIVE;
+     s->pstate = EST_INACTIVE;
+-    s->isoch_pause = -1;
+     s->attach_poll_counter = 0;
+ 
+     for(i = 0; i < NB_PORTS; i++) {
+@@ -1468,46 +1466,7 @@ static int ehci_process_itd(EHCIState *ehci,
+             usb_packet_unmap(&ehci->ipacket);
+             qemu_sglist_destroy(&ehci->isgl);
+ 
+-#if 0
+-            /*  In isoch, there is no facility to indicate a NAK so let's
+-             *  instead just complete a zero-byte transaction.  Setting
+-             *  DBERR seems too draconian.
+-             */
+-
+-            if (ret == USB_RET_NAK) {
+-                if (ehci->isoch_pause > 0) {
+-                    DPRINTF("ISOCH: received a NAK but paused so returning\n");
+-                    ehci->isoch_pause--;
+-                    return 0;
+-                } else if (ehci->isoch_pause == -1) {
+-                    DPRINTF("ISOCH: recv NAK & isoch pause inactive, setting\n");
+-                    // Pause frindex for up to 50 msec waiting for data from
+-                    // remote
+-                    ehci->isoch_pause = 50;
+-                    return 0;
+-                } else {
+-                    DPRINTF("ISOCH: isoch pause timeout! return 0\n");
+-                    ret = 0;
+-                }
+-            } else {
+-                DPRINTF("ISOCH: received ACK, clearing pause\n");
+-                ehci->isoch_pause = -1;
+-            }
+-#else
+-            if (ret == USB_RET_NAK) {
+-                ret = 0;
+-            }
+-#endif
+-
+-            if (ret >= 0) {
+-                if (!dir) {
+-                    /* OUT */
+-                    set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH);
+-                } else {
+-                    /* IN */
+-                    set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
+-                }
+-            } else {
++            if (ret < 0) {
+                 switch (ret) {
+                 default:
+                     fprintf(stderr, "Unexpected iso usb result: %d\n", ret);
+@@ -1523,6 +1482,19 @@ static int ehci_process_itd(EHCIState *ehci,
+                     itd->transact[i] |= ITD_XACT_BABBLE;
+                     ehci_record_interrupt(ehci, USBSTS_ERRINT);
+                     break;
++                case USB_RET_NAK:
++                    /* no data for us, so do a zero-length transfer */
++                    ret = 0;
++                    break;
++                }
++            }
++            if (ret >= 0) {
++                if (!dir) {
++                    /* OUT */
++                    set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH);
++                } else {
++                    /* IN */
++                    set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
+                 }
+             }
+             if (itd->transact[i] & ITD_XACT_IOC) {
+@@ -2176,9 +2148,7 @@ static void ehci_frame_timer(void *opaque)
+ 
+     for (i = 0; i < frames; i++) {
+         if ( !(ehci->usbsts & USBSTS_HALT)) {
+-            if (ehci->isoch_pause <= 0) {
+-                ehci->frindex += 8;
+-            }
++            ehci->frindex += 8;
+ 
+             if (ehci->frindex > 0x00001fff) {
+                 ehci->frindex = 0;
+-- 
+1.7.9.3
+
diff --git a/0137-usb-return-BABBLE-rather-then-NAK-when-we-receive-to.patch b/0137-usb-return-BABBLE-rather-then-NAK-when-we-receive-to.patch
new file mode 100644
index 0000000..3743d5e
--- /dev/null
+++ b/0137-usb-return-BABBLE-rather-then-NAK-when-we-receive-to.patch
@@ -0,0 +1,70 @@
+From 9726556968aef62213b80bd4e351a4f7f721f941 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Thu, 1 Mar 2012 17:22:14 +0100
+Subject: [PATCH 137/140] usb: return BABBLE rather then NAK when we receive
+ too much data
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ usb-linux.c |    8 +++++++-
+ usb-redir.c |    4 ++--
+ 2 files changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/usb-linux.c b/usb-linux.c
+index ab4c693..b2d70f9 100644
+--- a/usb-linux.c
++++ b/usb-linux.c
+@@ -390,6 +390,10 @@ static void async_complete(void *opaque)
+                 p->result = USB_RET_STALL;
+                 break;
+ 
++            case -EOVERFLOW:
++                p->result = USB_RET_BABBLE;
++                break;
++
+             default:
+                 p->result = USB_RET_NAK;
+                 break;
+@@ -718,6 +722,8 @@ static int urb_status_to_usb_ret(int status)
+     switch (status) {
+     case -EPIPE:
+         return USB_RET_STALL;
++    case -EOVERFLOW:
++        return USB_RET_BABBLE;
+     default:
+         return USB_RET_NAK;
+     }
+@@ -755,7 +761,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
+             } else if (aurb[i].urb.iso_frame_desc[j].actual_length
+                        > p->iov.size) {
+                 printf("husb: received iso data is larger then packet\n");
+-                len = USB_RET_NAK;
++                len = USB_RET_BABBLE;
+             /* All good copy data over */
+             } else {
+                 len = aurb[i].urb.iso_frame_desc[j].actual_length;
+diff --git a/usb-redir.c b/usb-redir.c
+index 629c87d..61860ef 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -457,7 +457,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+             ERROR("received iso data is larger then packet ep %02X (%d > %d)\n",
+                   ep, len, (int)p->iov.size);
+             bufp_free(dev, isop, ep);
+-            return USB_RET_NAK;
++            return USB_RET_BABBLE;
+         }
+         usb_packet_copy(p, isop->data, len);
+         bufp_free(dev, isop, ep);
+@@ -576,7 +576,7 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
+         if (len > p->iov.size) {
+             ERROR("received int data is larger then packet ep %02X\n", ep);
+             bufp_free(dev, intp, ep);
+-            return USB_RET_NAK;
++            return USB_RET_BABBLE;
+         }
+         usb_packet_copy(p, intp->data, len);
+         bufp_free(dev, intp, ep);
+-- 
+1.7.9.3
+
diff --git a/0138-usb-add-USB_RET_IOERROR.patch b/0138-usb-add-USB_RET_IOERROR.patch
new file mode 100644
index 0000000..0ed82a7
--- /dev/null
+++ b/0138-usb-add-USB_RET_IOERROR.patch
@@ -0,0 +1,167 @@
+From 2a6bbdddc2aca6af038c42054c3d3a7b09e5ac3a Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Fri, 2 Mar 2012 00:26:23 +0100
+Subject: [PATCH 138/140] usb: add USB_RET_IOERROR
+
+We already have USB_RET_NAK, but that means that a device does not want
+to send/receive right now. But with host / network redirection we can
+actually have a transaction fail due to some io error, rather then ie
+the device just not having any data atm.
+
+This patch adds a new error code named USB_RET_IOERROR for this, and uses
+it were appropriate.
+
+Notes:
+-Currently all usb-controllers handle this the same as NODEV, but that
+ may change in the future, OHCI could indicate a CRC error instead for example.
+-This patch does not touch hw/usb-musb.c, that is because the code in there
+ handles STALL and NAK specially and has a if status < 0 generic catch all
+ for all other errors
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |    2 ++
+ hw/usb-ohci.c |    2 ++
+ hw/usb-uhci.c |    1 +
+ hw/usb.h      |   11 ++++++-----
+ usb-linux.c   |    4 ++--
+ usb-redir.c   |    9 ++++++---
+ 6 files changed, 19 insertions(+), 10 deletions(-)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index 72c3f2a..ba1b9da 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -1275,6 +1275,7 @@ static void ehci_execute_complete(EHCIQueue *q)
+ 
+     if (q->usb_status < 0) {
+         switch(q->usb_status) {
++        case USB_RET_IOERROR:
+         case USB_RET_NODEV:
+             q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
+             set_field(&q->qh.token, 0, QTD_TOKEN_CERR);
+@@ -1471,6 +1472,7 @@ static int ehci_process_itd(EHCIState *ehci,
+                 default:
+                     fprintf(stderr, "Unexpected iso usb result: %d\n", ret);
+                     /* Fall through */
++                case USB_RET_IOERROR:
+                 case USB_RET_NODEV:
+                     /* 3.3.2: XACTERR is only allowed on IN transactions */
+                     if (dir) {
+diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
+index c2981c5..d805497 100644
+--- a/hw/usb-ohci.c
++++ b/hw/usb-ohci.c
+@@ -828,6 +828,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
+                         OHCI_CC_DATAUNDERRUN);
+         } else {
+             switch (ret) {
++            case USB_RET_IOERROR:
+             case USB_RET_NODEV:
+                 OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
+                             OHCI_CC_DEVICENOTRESPONDING);
+@@ -1051,6 +1052,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
+             OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN);
+         } else {
+             switch (ret) {
++            case USB_RET_IOERROR:
+             case USB_RET_NODEV:
+                 OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING);
+             case USB_RET_NAK:
+diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
+index f9e3ea5..a994943 100644
+--- a/hw/usb-uhci.c
++++ b/hw/usb-uhci.c
+@@ -751,6 +751,7 @@ out:
+             break;
+ 	return 1;
+ 
++    case USB_RET_IOERROR:
+     case USB_RET_NODEV:
+     default:
+ 	break;
+diff --git a/hw/usb.h b/hw/usb.h
+index c6e1870..4010e12 100644
+--- a/hw/usb.h
++++ b/hw/usb.h
+@@ -41,11 +41,12 @@
+ #define USB_MSG_DETACH   0x101
+ #define USB_MSG_RESET    0x102
+ 
+-#define USB_RET_NODEV  (-1)
+-#define USB_RET_NAK    (-2)
+-#define USB_RET_STALL  (-3)
+-#define USB_RET_BABBLE (-4)
+-#define USB_RET_ASYNC  (-5)
++#define USB_RET_NODEV   (-1)
++#define USB_RET_NAK     (-2)
++#define USB_RET_STALL   (-3)
++#define USB_RET_BABBLE  (-4)
++#define USB_RET_IOERROR (-5)
++#define USB_RET_ASYNC   (-6)
+ 
+ #define USB_SPEED_LOW   0
+ #define USB_SPEED_FULL  1
+diff --git a/usb-linux.c b/usb-linux.c
+index b2d70f9..9f13d1e 100644
+--- a/usb-linux.c
++++ b/usb-linux.c
+@@ -395,7 +395,7 @@ static void async_complete(void *opaque)
+                 break;
+ 
+             default:
+-                p->result = USB_RET_NAK;
++                p->result = USB_RET_IOERROR;
+                 break;
+             }
+ 
+@@ -725,7 +725,7 @@ static int urb_status_to_usb_ret(int status)
+     case -EOVERFLOW:
+         return USB_RET_BABBLE;
+     default:
+-        return USB_RET_NAK;
++        return USB_RET_IOERROR;
+     }
+ }
+ 
+diff --git a/usb-redir.c b/usb-redir.c
+index 61860ef..f64443e 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -441,7 +441,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+             /* Check iso_error for stream errors, otherwise its an underrun */
+             status = dev->endpoint[EP2I(ep)].iso_error;
+             dev->endpoint[EP2I(ep)].iso_error = 0;
+-            return status ? USB_RET_NAK : 0;
++            return status ? USB_RET_IOERROR : 0;
+         }
+         DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep,
+                  isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size);
+@@ -449,7 +449,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
+         status = isop->status;
+         if (status != usb_redir_success) {
+             bufp_free(dev, isop, ep);
+-            return USB_RET_NAK;
++            return USB_RET_IOERROR;
+         }
+ 
+         len = isop->len;
+@@ -1045,11 +1045,14 @@ static int usbredir_handle_status(USBRedirDevice *dev,
+         return USB_RET_STALL;
+     case usb_redir_cancelled:
+         WARNING("returning cancelled packet to HC?\n");
++        return USB_RET_NAK;
+     case usb_redir_inval:
++        WARNING("got invalid param error from usb-host?\n");
++        return USB_RET_NAK;
+     case usb_redir_ioerror:
+     case usb_redir_timeout:
+     default:
+-        return USB_RET_NAK;
++        return USB_RET_IOERROR;
+     }
+ }
+ 
+-- 
+1.7.9.3
+
diff --git a/0139-usb-ehci-fix-reset.patch b/0139-usb-ehci-fix-reset.patch
new file mode 100644
index 0000000..d9e6ac1
--- /dev/null
+++ b/0139-usb-ehci-fix-reset.patch
@@ -0,0 +1,40 @@
+From 21946e621f14553b72cde7fae221ae390a427eac Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Thu, 23 Feb 2012 13:24:00 +0000
+Subject: [PATCH 139/140] usb-ehci: fix reset
+
+Two reset fixes:
+  * pick up s->usbcmd value after ehci_reset call to make sure it
+    keeps the reset value and doesn't get rubbish filled in when
+    val is written back to the mmio register array later on.
+  * make sure the frame timer is zapped on reset.
+
+Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
+---
+ hw/usb-ehci.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index ba1b9da..ad0f6e1 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -900,6 +900,7 @@ static void ehci_reset(void *opaque)
+     }
+     ehci_queues_rip_all(s, 0);
+     ehci_queues_rip_all(s, 1);
++    qemu_del_timer(s->frame_timer);
+ }
+ 
+ static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr)
+@@ -1059,7 +1060,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
+ 
+         if (val & USBCMD_HCRESET) {
+             ehci_reset(s);
+-            val &= ~USBCMD_HCRESET;
++            val = s->usbcmd;
+         }
+ 
+         /* not supporting dynamic frame list size at the moment */
+-- 
+1.7.9.3
+
diff --git a/0140-usb-ehci-sanity-check-iso-xfers.patch b/0140-usb-ehci-sanity-check-iso-xfers.patch
new file mode 100644
index 0000000..1305f51
--- /dev/null
+++ b/0140-usb-ehci-sanity-check-iso-xfers.patch
@@ -0,0 +1,42 @@
+From 985b7cfbd45960bb74a13ad8044765a8e35f2251 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Sun, 4 Mar 2012 12:41:11 +0100
+Subject: [PATCH 140/140] usb-ehci: sanity-check iso xfers
+
+This patch adds a sanity check to itd processing to make sure the
+endpoint addressed by the guest is actually an iso endpoint.  Also
+verify that usb drivers don't return USB_RET_ASYNC which is illegal for
+iso xfers.
+
+Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
+(Cherry picked from: aa0568ff2559d7717f4684af6a83d0bd1a125f56)
+
+[qemu-kvm-1.0: we don't track ep types on RHEL-6 like we do upstream, so we
+cannot check if an itd is pointing to a non iso ep in advance, but we do still
+need to make sure that we never handle an iso xfer async. So check if the
+device does want to handle it async, and if so cancel the xfer and treat it as
+a NAK, like upstream does when the ep type check fails.]
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ hw/usb-ehci.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
+index ad0f6e1..b5d7037 100644
+--- a/hw/usb-ehci.c
++++ b/hw/usb-ehci.c
+@@ -1485,6 +1485,10 @@ static int ehci_process_itd(EHCIState *ehci,
+                     itd->transact[i] |= ITD_XACT_BABBLE;
+                     ehci_record_interrupt(ehci, USBSTS_ERRINT);
+                     break;
++                case USB_RET_ASYNC:
++                    /* ISO endpoints are never ASYNC, not an iso endpoint? */
++                    usb_cancel_packet(&ehci->ipacket);
++                    /* Treat this as a NAK (fall through) */
+                 case USB_RET_NAK:
+                     /* no data for us, so do a zero-length transfer */
+                     ret = 0;
+-- 
+1.7.9.3
+
diff --git a/qemu.spec b/qemu.spec
index 6ffcbbc..ad235d1 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -1,7 +1,7 @@
 Summary: QEMU is a FAST! processor emulator
 Name: qemu
 Version: 1.0
-Release: 6%{?dist}
+Release: 7%{?dist}
 # Epoch because we pushed a qemu-1.0 package
 Epoch: 2
 License: GPLv2+ and LGPLv2+ and BSD
@@ -86,6 +86,28 @@ Patch115: 0115-spice-qemu-char.c-remove-intermediate-buffer.patch
 Patch116: 0116-usb-redir-Add-flow-control-support.patch
 Patch117: 0117-virtio-serial-bus-replay-guest_open-on-migration.patch
 Patch118: 0118-char-Disable-write-callback-if-throttled-chardev-is-.patch
+Patch119: 0119-usb-ehci-Clear-the-portstatus-powner-bit-on-device-d.patch
+Patch120: 0120-usb-redir-Add-the-posibility-to-filter-out-certain-d.patch
+Patch121: 0121-usb-redir-Fix-printing-of-device-version.patch
+Patch122: 0122-usb-redir-Always-clear-device-state-on-filter-reject.patch
+Patch123: 0123-usb-redir-Let-the-usb-host-know-about-our-device-fil.patch
+Patch124: 0124-usb-redir-Limit-return-values-returned-by-iso-packet.patch
+Patch125: 0125-usb-redir-Return-USB_RET_NAK-when-we-ve-no-data-for-.patch
+Patch126: 0126-usb-ehci-Handle-ISO-packets-failing-with-an-error-ot.patch
+Patch127: 0127-usb-ehci-Never-follow-table-entries-with-the-T-bit-s.patch
+Patch128: 0128-usb-ehci-split-our-qh-queue-into-async-and-periodic-.patch
+Patch129: 0129-usb-ehci-always-call-ehci_queues_rip_unused-for-peri.patch
+Patch130: 0130-usb-ehci-Drop-cached-qhs-when-the-doorbell-gets-rung.patch
+Patch131: 0131-usb-ehci-Rip-the-queues-when-the-async-or-period-sch.patch
+Patch132: 0132-usb-ehci-Any-packet-completion-except-for-NAK-should.patch
+Patch133: 0133-usb-ehci-Fix-cerr-tracking.patch
+Patch134: 0134-usb-ehci-Remove-dead-nakcnt-code.patch
+Patch135: 0135-usb-ehci-Fix-and-simplify-nakcnt-handling.patch
+Patch136: 0136-usb-ehci-Remove-dead-isoch_pause-code.patch
+Patch137: 0137-usb-return-BABBLE-rather-then-NAK-when-we-receive-to.patch
+Patch138: 0138-usb-add-USB_RET_IOERROR.patch
+Patch139: 0139-usb-ehci-fix-reset.patch
+Patch140: 0140-usb-ehci-sanity-check-iso-xfers.patch
 
 # General bug fixes
 Patch201: Fix_save-restore_of_in-kernel_i8259.patch
@@ -382,6 +404,28 @@ such as kvm_stat.
 %patch116 -p1
 %patch117 -p1
 %patch118 -p1
+%patch119 -p1
+%patch120 -p1
+%patch121 -p1
+%patch122 -p1
+%patch123 -p1
+%patch124 -p1
+%patch125 -p1
+%patch126 -p1
+%patch127 -p1
+%patch128 -p1
+%patch129 -p1
+%patch130 -p1
+%patch131 -p1
+%patch132 -p1
+%patch133 -p1
+%patch134 -p1
+%patch135 -p1
+%patch136 -p1
+%patch137 -p1
+%patch138 -p1
+%patch139 -p1
+%patch140 -p1
 
 %patch201 -p1
 
@@ -768,6 +812,9 @@ fi
 %{_mandir}/man1/qemu-img.1*
 
 %changelog
+* Fri Mar  9 2012 Hans de Goede <hdegoede at redhat.com> - 2:1.0-7
+- Add a whole bunch of USB bugfixes from upstream
+
 * Mon Feb 13 2012 Daniel P. Berrange <berrange at redhat.com> - 2:1.0-6
 - Add many more missing BRs for misc QEMU features
 - Enable running of test suite during build


More information about the scm-commits mailing list