Patchwork [1/4] usb: split packet result into actual_length + status

login
register
mail settings
Submitter Hans de Goede
Date Oct. 18, 2012, 2:05 p.m.
Message ID <1350569156-2565-2-git-send-email-hdegoede@redhat.com>
Download mbox | patch
Permalink /patch/192328/
State New
Headers show

Comments

Hans de Goede - Oct. 18, 2012, 2:05 p.m.
Since with the ehci and xhci controllers a single packet can be larger
then maxpacketsize, it is possible for the result of a single packet
to be both having transferred some data as well as the transfer to have
an error.

An example would be an input transfer from a bulk endpoint successfully
receiving 1 or more maxpacketsize packets from the device, followed
by a packet signalling halt.

This patch unfortunately is somewhat invasive, since makeing the qemu
usb core deal with this requires changes everywhere. This patch only
prepares the usb core for this, all the hcd / device changes are done
in such a way that there are no functional changes.

This patch has been tested with uhci and ehci hcds, together with usb-audio,
usb-hid and usb-storage devices, as well as with usb-redir redirection
with a wide variety of real devices.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 hw/usb.h                      |  4 +-
 hw/usb/combined-packet.c      | 23 ++++++++----
 hw/usb/core.c                 | 85 +++++++++++++++++++++++--------------------
 hw/usb/desc.c                 | 26 ++++++++-----
 hw/usb/desc.h                 |  3 +-
 hw/usb/dev-audio.c            |  7 +++-
 hw/usb/dev-bluetooth.c        | 10 ++---
 hw/usb/dev-hid.c              | 30 +++++++--------
 hw/usb/dev-hub.c              | 23 +++++++-----
 hw/usb/dev-network.c          | 70 +++++++++++++++++------------------
 hw/usb/dev-serial.c           | 12 +++---
 hw/usb/dev-smartcard-reader.c | 31 ++++++++--------
 hw/usb/dev-storage.c          | 32 ++++++----------
 hw/usb/dev-uas.c              | 18 ++++-----
 hw/usb/dev-wacom.c            | 22 +++++------
 hw/usb/hcd-ehci.c             | 10 ++++-
 hw/usb/hcd-musb.c             |  8 ++--
 hw/usb/hcd-ohci.c             | 10 ++++-
 hw/usb/hcd-uhci.c             | 34 ++++++++---------
 hw/usb/hcd-xhci.c             | 10 ++---
 hw/usb/host-bsd.c             | 12 +++---
 hw/usb/host-linux.c           | 42 ++++++++++-----------
 hw/usb/redirect.c             | 74 ++++++++++++++++++++-----------------
 23 files changed, 312 insertions(+), 284 deletions(-)
Gerd Hoffmann - Oct. 19, 2012, 9 a.m.
Hi,

> This patch unfortunately is somewhat invasive, since makeing the qemu
> usb core deal with this requires changes everywhere. This patch only
> prepares the usb core for this, all the hcd / device changes are done
> in such a way that there are no functional changes.

/me likes it.

When touching this _anyway_:  How about making usb_handle_packet and
->handle_data callbacks return void (or bool for completed/async) and
expect drivers to fill the fields in USBPacket instead?  That would kill
a little annonying difference in sync/async packet handling.

Adding a usb_packet_result(packet, length, status) helper function would
probably useful too.

cheers,
  Gerd
Hans de Goede - Oct. 19, 2012, 10:21 a.m.
Hi,

On 10/19/2012 11:00 AM, Gerd Hoffmann wrote:
>    Hi,
>
>> This patch unfortunately is somewhat invasive, since makeing the qemu
>> usb core deal with this requires changes everywhere. This patch only
>> prepares the usb core for this, all the hcd / device changes are done
>> in such a way that there are no functional changes.
>
> /me likes it.
>
> When touching this _anyway_:  How about making usb_handle_packet and
> ->handle_data callbacks return void (or bool for completed/async) and
> expect drivers to fill the fields in USBPacket instead?  That would kill
> a little annonying difference in sync/async packet handling.
>
> Adding a usb_packet_result(packet, length, status) helper function would
> probably useful too.

Both sound reasonable, I'll take a shot at adding these changes when I've
send the (hopefully) final version of the input pipelining series. I'm off
Monday, so I likely won't give this a shot before next Tuesday.

Regards,

Hans
Hans de Goede - Oct. 31, 2012, 1:01 p.m.
Hi,

On 10/19/2012 11:00 AM, Gerd Hoffmann wrote:
>    Hi,
>
>> This patch unfortunately is somewhat invasive, since makeing the qemu
>> usb core deal with this requires changes everywhere. This patch only
>> prepares the usb core for this, all the hcd / device changes are done
>> in such a way that there are no functional changes.
>
> /me likes it.
>
> When touching this _anyway_:  How about making usb_handle_packet and
> ->handle_data callbacks return void (or bool for completed/async) and
> expect drivers to fill the fields in USBPacket instead?  That would kill
> a little annonying difference in sync/async packet handling.

Ok, I've redone the patchset making usb_handle_packet and
the device's handle_control and handle_data methods return void, to
make the sync/async packet handling more alike.

This turned out to be quite a bit of work! But is all done now,
and it has been thoroughly tested (although with a subset
of all supported / emulated qemu usb devices, see the
commit message).

Regards,

Hans

Patch

diff --git a/hw/usb.h b/hw/usb.h
index 3c8ba01..7b7a988 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -38,6 +38,7 @@ 
 #define USB_TOKEN_IN    0x69 /* device -> host */
 #define USB_TOKEN_OUT   0xe1 /* host -> device */
 
+#define USB_RET_SUCCESS           (0)
 #define USB_RET_NODEV             (-1)
 #define USB_RET_NAK               (-2)
 #define USB_RET_STALL             (-3)
@@ -362,7 +363,8 @@  struct USBPacket {
     uint64_t parameter; /* control transfers */
     bool short_not_ok;
     bool int_req;
-    int result; /* transfer length or USB_RET_* status code */
+    int status; /* USB_RET_* status code */
+    int actual_length; /* Number of bytes actually transfered */
     /* Internal use by the USB layer.  */
     USBPacketState state;
     USBCombinedPacket *combined;
diff --git a/hw/usb/combined-packet.c b/hw/usb/combined-packet.c
index ab23ade..f725d50 100644
--- a/hw/usb/combined-packet.c
+++ b/hw/usb/combined-packet.c
@@ -46,7 +46,7 @@  void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p)
     USBEndpoint *ep = p->ep;
     USBPacket *next;
     enum { completing, complete, leftover };
-    int result, state = completing;
+    int status, actual_length, state = completing;
     bool short_not_ok;
 
     if (combined == NULL) {
@@ -56,27 +56,34 @@  void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p)
 
     assert(combined->first == p && p == QTAILQ_FIRST(&combined->packets));
 
-    result = combined->first->result;
+    status = combined->first->status;
+    actual_length = combined->first->actual_length;
     short_not_ok = QTAILQ_LAST(&combined->packets, packets_head)->short_not_ok;
 
     QTAILQ_FOREACH_SAFE(p, &combined->packets, combined_entry, next) {
         if (state == completing) {
             /* Distribute data over uncombined packets */
-            if (result >= p->iov.size) {
-                p->result = p->iov.size;
+            if (actual_length >= p->iov.size) {
+                p->actual_length = p->iov.size;
             } else {
                 /* Send short or error packet to complete the transfer */
-                p->result = result;
+                p->actual_length = actual_length;
                 state = complete;
             }
+            /* Report status on the last packet */
+            if (state == complete || next == NULL) {
+                p->status = status;
+            } else {
+                p->status = USB_RET_SUCCESS;
+            }
             p->short_not_ok = short_not_ok;
             usb_combined_packet_remove(combined, p);
             usb_packet_complete_one(dev, p);
-            result -= p->result;
+            actual_length -= p->actual_length;
         } else {
             /* Remove any leftover packets from the queue */
             state = leftover;
-            p->result = USB_RET_REMOVE_FROM_QUEUE;
+            p->status = USB_RET_REMOVE_FROM_QUEUE;
             dev->port->ops->complete(dev->port, p);
         }
     }
@@ -129,7 +136,7 @@  void usb_ep_combine_input_packets(USBEndpoint *ep)
     QTAILQ_FOREACH_SAFE(p, &ep->queue, queue, next) {
         /* Empty the queue on a halt */
         if (ep->halted) {
-            p->result = USB_RET_REMOVE_FROM_QUEUE;
+            p->status = USB_RET_REMOVE_FROM_QUEUE;
             port->ops->complete(port, p);
             continue;
         }
diff --git a/hw/usb/core.c b/hw/usb/core.c
index 99b9fdb..34a65af 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -100,14 +100,14 @@  void usb_wakeup(USBEndpoint *ep)
 static int do_token_setup(USBDevice *s, USBPacket *p)
 {
     int request, value, index;
-    int ret = 0;
+    int ret = USB_RET_SUCCESS;
 
     if (p->iov.size != 8) {
         return USB_RET_STALL;
     }
 
     usb_packet_copy(p, s->setup_buf, p->iov.size);
-    p->result = 0;
+    p->actual_length = 0;
     s->setup_len   = (s->setup_buf[7] << 8) | s->setup_buf[6];
     s->setup_index = 0;
 
@@ -122,11 +122,13 @@  static int do_token_setup(USBDevice *s, USBPacket *p)
              s->setup_state = SETUP_STATE_SETUP;
              return USB_RET_ASYNC;
         }
-        if (ret < 0)
+        if (ret != USB_RET_SUCCESS) {
             return ret;
+        }
 
-        if (ret < s->setup_len)
-            s->setup_len = ret;
+        if (p->actual_length < s->setup_len) {
+            s->setup_len = p->actual_length;
+        }
         s->setup_state = SETUP_STATE_DATA;
     } else {
         if (s->setup_len > sizeof(s->data_buf)) {
@@ -141,13 +143,14 @@  static int do_token_setup(USBDevice *s, USBPacket *p)
             s->setup_state = SETUP_STATE_DATA;
     }
 
+    p->actual_length = 8;
     return ret;
 }
 
 static int do_token_in(USBDevice *s, USBPacket *p)
 {
     int request, value, index;
-    int ret = 0;
+    int ret;
 
     assert(p->ep->nr == 0);
 
@@ -164,13 +167,12 @@  static int do_token_in(USBDevice *s, USBPacket *p)
                 return USB_RET_ASYNC;
             }
             s->setup_state = SETUP_STATE_IDLE;
-            if (ret > 0)
-                return 0;
+            p->actual_length = 0;
             return ret;
         }
 
         /* return 0 byte */
-        return 0;
+        return USB_RET_SUCCESS;
 
     case SETUP_STATE_DATA:
         if (s->setup_buf[0] & USB_DIR_IN) {
@@ -182,7 +184,7 @@  static int do_token_in(USBDevice *s, USBPacket *p)
             s->setup_index += len;
             if (s->setup_index >= s->setup_len)
                 s->setup_state = SETUP_STATE_ACK;
-            return len;
+            return USB_RET_SUCCESS;
         }
 
         s->setup_state = SETUP_STATE_IDLE;
@@ -205,7 +207,7 @@  static int do_token_out(USBDevice *s, USBPacket *p)
         } else {
             /* ignore additional output */
         }
-        return 0;
+        return USB_RET_SUCCESS;
 
     case SETUP_STATE_DATA:
         if (!(s->setup_buf[0] & USB_DIR_IN)) {
@@ -217,7 +219,7 @@  static int do_token_out(USBDevice *s, USBPacket *p)
             s->setup_index += len;
             if (s->setup_index >= s->setup_len)
                 s->setup_state = SETUP_STATE_ACK;
-            return len;
+            return USB_RET_SUCCESS;
         }
 
         s->setup_state = SETUP_STATE_IDLE;
@@ -231,7 +233,7 @@  static int do_token_out(USBDevice *s, USBPacket *p)
 static int do_parameter(USBDevice *s, USBPacket *p)
 {
     int request, value, index;
-    int i, ret = 0;
+    int i, ret;
 
     for (i = 0; i < 8; i++) {
         s->setup_buf[i] = p->parameter >> (i*8);
@@ -258,14 +260,15 @@  static int do_parameter(USBDevice *s, USBPacket *p)
 
     ret = usb_device_handle_control(s, p, request, value, index,
                                     s->setup_len, s->data_buf);
-    if (ret < 0) {
-        return ret;
+    if (ret == USB_RET_ASYNC) {
+        return USB_RET_ASYNC;
     }
 
-    if (ret < s->setup_len) {
-        s->setup_len = ret;
+    if (p->actual_length < s->setup_len) {
+        s->setup_len = p->actual_length;
     }
     if (p->pid == USB_TOKEN_IN) {
+        p->actual_length = 0;
         usb_packet_copy(p, s->data_buf, s->setup_len);
     }
 
@@ -278,30 +281,30 @@  static int do_parameter(USBDevice *s, USBPacket *p)
    usb_packet_complete to complete their async control packets. */
 void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
 {
-    if (p->result < 0) {
+    if (p->status < 0) {
         s->setup_state = SETUP_STATE_IDLE;
     }
 
     switch (s->setup_state) {
     case SETUP_STATE_SETUP:
-        if (p->result < s->setup_len) {
-            s->setup_len = p->result;
+        if (p->actual_length < s->setup_len) {
+            s->setup_len = p->actual_length;
         }
         s->setup_state = SETUP_STATE_DATA;
-        p->result = 8;
+        p->actual_length = 8;
         break;
 
     case SETUP_STATE_ACK:
         s->setup_state = SETUP_STATE_IDLE;
-        p->result = 0;
+        p->actual_length = 0;
         break;
 
     case SETUP_STATE_PARAM:
-        if (p->result < s->setup_len) {
-            s->setup_len = p->result;
+        if (p->actual_length < s->setup_len) {
+            s->setup_len = p->actual_length;
         }
         if (p->pid == USB_TOKEN_IN) {
-            p->result = 0;
+            p->actual_length = 0;
             usb_packet_copy(p, s->data_buf, s->setup_len);
         }
         break;
@@ -404,7 +407,7 @@  int usb_handle_packet(USBDevice *dev, USBPacket *p)
              */
             assert(!p->ep->pipeline || QTAILQ_EMPTY(&p->ep->queue));
             if (ret != USB_RET_NAK) {
-                p->result = ret;
+                p->status = ret;
                 usb_packet_set_state(p, USB_PACKET_COMPLETE);
             }
         }
@@ -421,9 +424,10 @@  void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
     USBEndpoint *ep = p->ep;
 
     assert(QTAILQ_FIRST(&ep->queue) == p);
-    assert(p->result != USB_RET_ASYNC && p->result != USB_RET_NAK);
+    assert(p->status != USB_RET_ASYNC && p->status != USB_RET_NAK);
 
-    if (p->result < 0 || (p->short_not_ok && (p->result < p->iov.size))) {
+    if (p->status != USB_RET_SUCCESS ||
+            (p->short_not_ok && (p->actual_length < p->iov.size))) {
         ep->halted = true;
     }
     usb_packet_set_state(p, USB_PACKET_COMPLETE);
@@ -446,7 +450,7 @@  void usb_packet_complete(USBDevice *dev, USBPacket *p)
         p = QTAILQ_FIRST(&ep->queue);
         if (ep->halted) {
             /* Empty the queue on a halt */
-            p->result = USB_RET_REMOVE_FROM_QUEUE;
+            p->status = USB_RET_REMOVE_FROM_QUEUE;
             dev->port->ops->complete(dev->port, p);
             continue;
         }
@@ -459,7 +463,7 @@  void usb_packet_complete(USBDevice *dev, USBPacket *p)
             usb_packet_set_state(p, USB_PACKET_ASYNC);
             break;
         }
-        p->result = ret;
+        p->status = ret;
         usb_packet_complete_one(ep->dev, p);
     }
 }
@@ -540,7 +544,8 @@  void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id,
     p->id = id;
     p->pid = pid;
     p->ep = ep;
-    p->result = 0;
+    p->status = USB_RET_SUCCESS;
+    p->actual_length = 0;
     p->parameter = 0;
     p->short_not_ok = short_not_ok;
     p->int_req = int_req;
@@ -556,31 +561,31 @@  void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
 
 void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
 {
-    assert(p->result >= 0);
-    assert(p->result + bytes <= p->iov.size);
+    assert(p->actual_length >= 0);
+    assert(p->actual_length + bytes <= p->iov.size);
     switch (p->pid) {
     case USB_TOKEN_SETUP:
     case USB_TOKEN_OUT:
-        iov_to_buf(p->iov.iov, p->iov.niov, p->result, ptr, bytes);
+        iov_to_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes);
         break;
     case USB_TOKEN_IN:
-        iov_from_buf(p->iov.iov, p->iov.niov, p->result, ptr, bytes);
+        iov_from_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes);
         break;
     default:
         fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
         abort();
     }
-    p->result += bytes;
+    p->actual_length += bytes;
 }
 
 void usb_packet_skip(USBPacket *p, size_t bytes)
 {
-    assert(p->result >= 0);
-    assert(p->result + bytes <= p->iov.size);
+    assert(p->actual_length >= 0);
+    assert(p->actual_length + bytes <= p->iov.size);
     if (p->pid == USB_TOKEN_IN) {
-        iov_memset(p->iov.iov, p->iov.niov, p->result, 0, bytes);
+        iov_memset(p->iov.iov, p->iov.niov, p->actual_length, 0, bytes);
     }
-    p->result += bytes;
+    p->actual_length += bytes;
 }
 
 void usb_packet_cleanup(USBPacket *p)
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 1f12eae..b22a8e8 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -434,7 +434,7 @@  static int usb_desc_set_interface(USBDevice *dev, int index, int value)
     if (old != value) {
         usb_device_set_interface(dev, index, old, value);
     }
-    return 0;
+    return USB_RET_SUCCESS;
 }
 
 static int usb_desc_set_config(USBDevice *dev, int value)
@@ -467,7 +467,7 @@  static int usb_desc_set_config(USBDevice *dev, int value)
         dev->ifaces[i] = NULL;
     }
 
-    return 0;
+    return USB_RET_SUCCESS;
 }
 
 static void usb_desc_setdefaults(USBDevice *dev)
@@ -626,7 +626,8 @@  int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
     return pos;
 }
 
-int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len)
+int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
+                            int value, uint8_t *dest, size_t len)
 {
     const USBDesc *desc = usb_device_get_usb_desc(dev);
     const USBDescDevice *other_dev;
@@ -696,6 +697,8 @@  int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
             ret = len;
         }
         memcpy(dest, buf, ret);
+        p->actual_length = ret;
+        ret = USB_RET_SUCCESS;
     }
     return ret;
 }
@@ -711,11 +714,11 @@  int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
     case DeviceOutRequest | USB_REQ_SET_ADDRESS:
         dev->addr = value;
         trace_usb_set_addr(dev->addr);
-        ret = 0;
+        ret = USB_RET_SUCCESS;
         break;
 
     case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
-        ret = usb_desc_get_descriptor(dev, value, data, length);
+        ret = usb_desc_get_descriptor(dev, p, value, data, length);
         break;
 
     case DeviceRequest | USB_REQ_GET_CONFIGURATION:
@@ -724,7 +727,8 @@  int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
          * the non zero value of bConfigurationValue.
          */
         data[0] = dev->config ? dev->config->bConfigurationValue : 0;
-        ret = 1;
+        p->actual_length = 1;
+        ret = USB_RET_SUCCESS;
         break;
     case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
         ret = usb_desc_set_config(dev, value);
@@ -749,20 +753,21 @@  int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
             data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP;
         }
         data[1] = 0x00;
-        ret = 2;
+        p->actual_length = 2;
+        ret = USB_RET_SUCCESS;
         break;
     }
     case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
         if (value == USB_DEVICE_REMOTE_WAKEUP) {
             dev->remote_wakeup = 0;
-            ret = 0;
+            ret = USB_RET_SUCCESS;
         }
         trace_usb_clear_device_feature(dev->addr, value, ret);
         break;
     case DeviceOutRequest | USB_REQ_SET_FEATURE:
         if (value == USB_DEVICE_REMOTE_WAKEUP) {
             dev->remote_wakeup = 1;
-            ret = 0;
+            ret = USB_RET_SUCCESS;
         }
         trace_usb_set_device_feature(dev->addr, value, ret);
         break;
@@ -772,7 +777,8 @@  int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
             break;
         }
         data[0] = dev->altsetting[index];
-        ret = 1;
+        p->actual_length = 1;
+        ret = USB_RET_SUCCESS;
         break;
     case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
         ret = usb_desc_set_interface(dev, index, value);
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index 68bb570..ddd3e74 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -216,7 +216,8 @@  void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str);
 void usb_desc_create_serial(USBDevice *dev);
 const char *usb_desc_get_string(USBDevice *dev, uint8_t index);
 int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len);
-int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len);
+int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
+        int value, uint8_t *dest, size_t len);
 int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
         int request, int value, int index, int length, uint8_t *data);
 
diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c
index 2594c78..16771ab 100644
--- a/hw/usb/dev-audio.c
+++ b/hw/usb/dev-audio.c
@@ -517,7 +517,7 @@  static int usb_audio_handle_control(USBDevice *dev, USBPacket *p,
     }
 
     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
-    if (ret >= 0) {
+    if (ret == USB_RET_SUCCESS) {
         return ret;
     }
 
@@ -534,6 +534,8 @@  static int usb_audio_handle_control(USBDevice *dev, USBPacket *p,
             }
             goto fail;
         }
+        p->actual_length = ret;
+        ret = USB_RET_SUCCESS;
         break;
 
     case ClassInterfaceOutRequest | CR_SET_CUR:
@@ -548,6 +550,7 @@  static int usb_audio_handle_control(USBDevice *dev, USBPacket *p,
             }
             goto fail;
         }
+        ret = USB_RET_SUCCESS;
         break;
 
     default:
@@ -597,7 +600,7 @@  static int usb_audio_handle_dataout(USBAudioState *s, USBPacket *p)
                 p->iov.size - rc);
     }
 
-    return 0;
+    return USB_RET_SUCCESS;
 }
 
 static int usb_audio_handle_data(USBDevice *dev, USBPacket *p)
diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c
index 55bc191..dadfc66 100644
--- a/hw/usb/dev-bluetooth.c
+++ b/hw/usb/dev-bluetooth.c
@@ -311,7 +311,7 @@  static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
         fifo->dsize = DFIFO_LEN_MASK + 1;
     }
 
-    return len;
+    return USB_RET_SUCCESS;
 }
 
 static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s,
@@ -370,7 +370,7 @@  static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
     int ret;
 
     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
-    if (ret >= 0) {
+    if (ret == USB_RET_SUCCESS) {
         switch (request) {
         case DeviceRequest | USB_REQ_GET_CONFIGURATION:
             s->config = 0;
@@ -385,13 +385,13 @@  static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
         return ret;
     }
 
-    ret = 0;
+    ret = USB_RET_SUCCESS;
     switch (request) {
     case InterfaceRequest | USB_REQ_GET_STATUS:
     case EndpointRequest | USB_REQ_GET_STATUS:
         data[0] = 0x00;
         data[1] = 0x00;
-        ret = 2;
+        p->actual_length = 2;
         break;
     case InterfaceOutRequest | USB_REQ_CLEAR_FEATURE:
     case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
@@ -416,7 +416,7 @@  static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
 static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
 {
     struct USBBtState *s = (struct USBBtState *) dev->opaque;
-    int ret = 0;
+    int ret = USB_RET_SUCCESS;
 
     if (!s->config)
         goto fail;
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index b3dcd23..c7f2dcf 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -379,11 +379,11 @@  static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
     int ret;
 
     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
-    if (ret >= 0) {
+    if (ret == USB_RET_SUCCESS) {
         return ret;
     }
 
-    ret = 0;
+    ret = USB_RET_SUCCESS;
     switch (request) {
         /* hid specific requests */
     case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
@@ -392,15 +392,15 @@  static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
             if (hs->kind == HID_MOUSE) {
 		memcpy(data, qemu_mouse_hid_report_descriptor,
 		       sizeof(qemu_mouse_hid_report_descriptor));
-		ret = sizeof(qemu_mouse_hid_report_descriptor);
+                p->actual_length = sizeof(qemu_mouse_hid_report_descriptor);
             } else if (hs->kind == HID_TABLET) {
                 memcpy(data, qemu_tablet_hid_report_descriptor,
 		       sizeof(qemu_tablet_hid_report_descriptor));
-		ret = sizeof(qemu_tablet_hid_report_descriptor);
+                p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
             } else if (hs->kind == HID_KEYBOARD) {
                 memcpy(data, qemu_keyboard_hid_report_descriptor,
                        sizeof(qemu_keyboard_hid_report_descriptor));
-                ret = sizeof(qemu_keyboard_hid_report_descriptor);
+                p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor);
             }
             break;
         default:
@@ -409,14 +409,14 @@  static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
         break;
     case GET_REPORT:
         if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
-            ret = hid_pointer_poll(hs, data, length);
+            p->actual_length = hid_pointer_poll(hs, data, length);
         } else if (hs->kind == HID_KEYBOARD) {
-            ret = hid_keyboard_poll(hs, data, length);
+            p->actual_length = hid_keyboard_poll(hs, data, length);
         }
         break;
     case SET_REPORT:
         if (hs->kind == HID_KEYBOARD) {
-            ret = hid_keyboard_write(hs, data, length);
+            p->actual_length = hid_keyboard_write(hs, data, length);
         } else {
             goto fail;
         }
@@ -425,19 +425,18 @@  static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
         if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
             goto fail;
         }
-        ret = 1;
         data[0] = hs->protocol;
+        p->actual_length = 1;
         break;
     case SET_PROTOCOL:
         if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
             goto fail;
         }
-        ret = 0;
         hs->protocol = value;
         break;
     case GET_IDLE:
-        ret = 1;
         data[0] = hs->idle;
+        p->actual_length = 1;
         break;
     case SET_IDLE:
         hs->idle = (uint8_t) (value >> 8);
@@ -445,7 +444,6 @@  static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
         if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
             hid_pointer_activate(hs);
         }
-        ret = 0;
         break;
     default:
     fail:
@@ -460,7 +458,7 @@  static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
     HIDState *hs = &us->hid;
     uint8_t buf[p->iov.size];
-    int ret = 0;
+    int len = 0, ret = USB_RET_SUCCESS;
 
     switch (p->pid) {
     case USB_TOKEN_IN:
@@ -475,11 +473,11 @@  static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
             }
             hid_set_next_idle(hs, curtime);
             if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
-                ret = hid_pointer_poll(hs, buf, p->iov.size);
+                len = hid_pointer_poll(hs, buf, p->iov.size);
             } else if (hs->kind == HID_KEYBOARD) {
-                ret = hid_keyboard_poll(hs, buf, p->iov.size);
+                len = hid_keyboard_poll(hs, buf, p->iov.size);
             }
-            usb_packet_copy(p, buf, ret);
+            usb_packet_copy(p, buf, len);
         } else {
             goto fail;
         }
diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 8fd30df..eb2ce60 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -297,7 +297,7 @@  static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
     trace_usb_hub_control(s->dev.addr, request, value, index, length);
 
     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
-    if (ret >= 0) {
+    if (ret == USB_RET_SUCCESS) {
         return ret;
     }
 
@@ -306,7 +306,7 @@  static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
         if (value == 0 && index != 0x81) { /* clear ep halt */
             goto fail;
         }
-        ret = 0;
+        ret = USB_RET_SUCCESS;
         break;
         /* usb specific requests */
     case GetHubStatus:
@@ -314,7 +314,8 @@  static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
         data[1] = 0;
         data[2] = 0;
         data[3] = 0;
-        ret = 4;
+        p->actual_length = 4;
+        ret = USB_RET_SUCCESS;
         break;
     case GetPortStatus:
         {
@@ -331,16 +332,17 @@  static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
             data[1] = port->wPortStatus >> 8;
             data[2] = port->wPortChange;
             data[3] = port->wPortChange >> 8;
-            ret = 4;
+            p->actual_length = 4;
+            ret = USB_RET_SUCCESS;
         }
         break;
     case SetHubFeature:
     case ClearHubFeature:
         if (value == 0 || value == 1) {
+            ret = USB_RET_SUCCESS;
         } else {
             goto fail;
         }
-        ret = 0;
         break;
     case SetPortFeature:
         {
@@ -373,7 +375,7 @@  static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
             default:
                 goto fail;
             }
-            ret = 0;
+            ret = USB_RET_SUCCESS;
         }
         break;
     case ClearPortFeature:
@@ -413,7 +415,7 @@  static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
             default:
                 goto fail;
             }
-            ret = 0;
+            ret = USB_RET_SUCCESS;
         }
         break;
     case GetHubDescriptor:
@@ -437,8 +439,9 @@  static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
                 var_hub_size++;
             }
 
-            ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
-            data[0] = ret;
+            p->actual_length = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
+            data[0] = p->actual_length;
+            ret = USB_RET_SUCCESS;
             break;
         }
     default:
@@ -478,7 +481,7 @@  static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
                     buf[i] = status >> (8 * i);
                 }
                 usb_packet_copy(p, buf, n);
-                ret = n;
+                ret = USB_RET_SUCCESS;
             } else {
                 ret = USB_RET_NAK; /* usb11 11.13.1 */
             }
diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
index c84892c..7fa5452 100644
--- a/hw/usb/dev-network.c
+++ b/hw/usb/dev-network.c
@@ -889,7 +889,7 @@  static int rndis_init_response(USBNetState *s, rndis_init_msg_type *buf)
     resp->PacketAlignmentFactor = cpu_to_le32(0);
     resp->AFListOffset = cpu_to_le32(0);
     resp->AFListSize = cpu_to_le32(0);
-    return 0;
+    return USB_RET_SUCCESS;
 }
 
 static int rndis_query_response(USBNetState *s,
@@ -925,7 +925,7 @@  static int rndis_query_response(USBNetState *s,
         resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
         resp->InformationBufferLength = cpu_to_le32(0);
         resp->InformationBufferOffset = cpu_to_le32(0);
-        return 0;
+        return USB_RET_SUCCESS;
     }
 
     resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
@@ -934,7 +934,7 @@  static int rndis_query_response(USBNetState *s,
     resp->InformationBufferLength = cpu_to_le32(infobuflen);
     memcpy(resp + 1, infobuf, infobuflen);
 
-    return 0;
+    return USB_RET_SUCCESS;
 }
 
 static int rndis_set_response(USBNetState *s,
@@ -961,11 +961,11 @@  static int rndis_set_response(USBNetState *s,
     if (ret < 0) {
         /* OID not supported */
         resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
-        return 0;
+        return USB_RET_SUCCESS;
     }
     resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
 
-    return 0;
+    return USB_RET_SUCCESS;
 }
 
 static int rndis_reset_response(USBNetState *s, rndis_reset_msg_type *buf)
@@ -981,7 +981,7 @@  static int rndis_reset_response(USBNetState *s, rndis_reset_msg_type *buf)
     resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
     resp->AddressingReset = cpu_to_le32(1); /* reset information */
 
-    return 0;
+    return USB_RET_SUCCESS;
 }
 
 static int rndis_keepalive_response(USBNetState *s,
@@ -998,7 +998,7 @@  static int rndis_keepalive_response(USBNetState *s,
     resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
     resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
 
-    return 0;
+    return USB_RET_SUCCESS;
 }
 
 static int rndis_parse(USBNetState *s, uint8_t *data, int length)
@@ -1015,7 +1015,7 @@  static int rndis_parse(USBNetState *s, uint8_t *data, int length)
 
     case RNDIS_HALT_MSG:
         s->rndis_state = RNDIS_UNINITIALIZED;
-        return 0;
+        return USB_RET_SUCCESS;
 
     case RNDIS_QUERY_MSG:
         return rndis_query_response(s, (rndis_query_msg_type *) data, length);
@@ -1047,11 +1047,11 @@  static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
     int ret;
 
     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
-    if (ret >= 0) {
+    if (ret == USB_RET_SUCCESS) {
         return ret;
     }
 
-    ret = 0;
+    ret = USB_RET_SUCCESS;
     switch(request) {
     case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND:
         if (!is_rndis(s) || value || index != 0) {
@@ -1076,16 +1076,16 @@  static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
         if (!is_rndis(s) || value || index != 0) {
             goto fail;
         }
-        ret = rndis_get_response(s, data);
-        if (!ret) {
+        p->actual_length = rndis_get_response(s, data);
+        if (p->actual_length == 0) {
             data[0] = 0;
-            ret = 1;
+            p->actual_length = 1;
         }
 #ifdef TRAFFIC_DEBUG
         {
             unsigned int i;
             fprintf(stderr, "GET_ENCAPSULATED_RESPONSE:");
-            for (i = 0; i < ret; i++) {
+            for (i = 0; i < p->actual_length; i++) {
                 if (!(i & 15))
                     fprintf(stderr, "\n%04x:", i);
                 fprintf(stderr, " %02x", data[i]);
@@ -1109,7 +1109,7 @@  static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
 static int usb_net_handle_statusin(USBNetState *s, USBPacket *p)
 {
     le32 buf[2];
-    int ret = 8;
+    int ret = USB_RET_SUCCESS;
 
     if (p->iov.size < 8) {
         return USB_RET_STALL;
@@ -1132,40 +1132,37 @@  static int usb_net_handle_statusin(USBNetState *s, USBPacket *p)
 
 static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
 {
-    int ret = USB_RET_NAK;
+    int len;
 
     if (s->in_ptr > s->in_len) {
         s->in_ptr = s->in_len = 0;
-        ret = USB_RET_NAK;
-        return ret;
+        return USB_RET_NAK;
     }
     if (!s->in_len) {
-        ret = USB_RET_NAK;
-        return ret;
+        return USB_RET_NAK;
     }
-    ret = s->in_len - s->in_ptr;
-    if (ret > p->iov.size) {
-        ret = p->iov.size;
+    len = s->in_len - s->in_ptr;
+    if (len > p->iov.size) {
+        len = p->iov.size;
     }
-    usb_packet_copy(p, &s->in_buf[s->in_ptr], ret);
-    s->in_ptr += ret;
+    usb_packet_copy(p, &s->in_buf[s->in_ptr], len);
+    s->in_ptr += len;
     if (s->in_ptr >= s->in_len &&
-                    (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
+                    (is_rndis(s) || (s->in_len & (64 - 1)) || !len)) {
         /* no short packet necessary */
         s->in_ptr = s->in_len = 0;
     }
 
 #ifdef TRAFFIC_DEBUG
-    fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, ret);
-    iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret);
+    fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, len);
+    iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", len);
 #endif
 
-    return ret;
+    return USB_RET_SUCCESS;
 }
 
 static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
 {
-    int ret = p->iov.size;
     int sz = sizeof(s->out_buf) - s->out_ptr;
     struct rndis_packet_msg_type *msg =
             (struct rndis_packet_msg_type *) s->out_buf;
@@ -1176,21 +1173,22 @@  static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
     iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->iov.size);
 #endif
 
-    if (sz > ret)
-        sz = ret;
+    if (sz > p->iov.size) {
+        sz = p->iov.size;
+    }
     usb_packet_copy(p, &s->out_buf[s->out_ptr], sz);
     s->out_ptr += sz;
 
     if (!is_rndis(s)) {
-        if (ret < 64) {
+        if (p->iov.size < 64) {
             qemu_send_packet(&s->nic->nc, s->out_buf, s->out_ptr);
             s->out_ptr = 0;
         }
-        return ret;
+        return USB_RET_SUCCESS;
     }
     len = le32_to_cpu(msg->MessageLength);
     if (s->out_ptr < 8 || s->out_ptr < len)
-        return ret;
+        return USB_RET_SUCCESS;
     if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
         uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
         uint32_t size = le32_to_cpu(msg->DataLength);
@@ -1200,7 +1198,7 @@  static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
     s->out_ptr -= len;
     memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
 
-    return ret;
+    return USB_RET_SUCCESS;
 }
 
 static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index 0ddfab6..c44e5a9 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -227,14 +227,13 @@  static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
 
     DPRINTF("got control %x, value %x\n",request, value);
     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
-    if (ret >= 0) {
+    if (ret == USB_RET_SUCCESS) {
         return ret;
     }
 
-    ret = 0;
+    ret = USB_RET_SUCCESS;
     switch (request) {
     case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
-        ret = 0;
         break;
 
         /* Class specific requests.  */
@@ -323,7 +322,7 @@  static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
     case DeviceInVendor | FTDI_GET_MDM_ST:
         data[0] = usb_get_modem_lines(s) | 1;
         data[1] = 0;
-        ret = 2;
+        p->actual_length = 2;
         break;
     case DeviceOutVendor | FTDI_SET_EVENT_CHR:
         /* TODO: handle it */
@@ -338,7 +337,7 @@  static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
         break;
     case DeviceInVendor | FTDI_GET_LATENCY:
         data[0] = s->latency;
-        ret = 1;
+        p->actual_length = 1;
         break;
     default:
     fail:
@@ -366,6 +365,7 @@  static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
             iov = p->iov.iov + i;
             qemu_chr_fe_write(s->cs, iov->iov_base, iov->iov_len);
         }
+        p->actual_length = p->iov.size;
         break;
 
     case USB_TOKEN_IN:
@@ -384,7 +384,6 @@  static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
             s->event_trigger &= ~FTDI_BI;
             header[1] = FTDI_BI;
             usb_packet_copy(p, header, 2);
-            ret = 2;
             break;
         } else {
             header[1] = 0;
@@ -404,7 +403,6 @@  static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
             usb_packet_copy(p, s->recv_buf, len - first_len);
         s->recv_used -= len;
         s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
-        ret = len + 2;
         break;
 
     default:
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 1ea0791..86c8b3f 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -639,11 +639,11 @@  static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
                                int value, int index, int length, uint8_t *data)
 {
     USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
-    int ret = 0;
+    int ret;
 
     DPRINTF(s, 1, "got control %x, value %x\n", request, value);
     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
-    if (ret >= 0) {
+    if (ret == USB_RET_SUCCESS) {
         return ret;
     }
 
@@ -890,7 +890,7 @@  static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
         DPRINTF(s, D_VERBOSE,
             "usb-ccid: bulk_in: expecting more packets (%zd/%d)\n",
             p->iov.size, ccid_header->dwLength);
-        return 0;
+        return USB_RET_SUCCESS;
     }
     if (s->bulk_out_pos < 10) {
         DPRINTF(s, 1,
@@ -949,45 +949,45 @@  static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
         }
     }
     s->bulk_out_pos = 0;
-    return 0;
+    return USB_RET_SUCCESS;
 }
 
 static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
 {
-    int ret = 0;
+    int len = 0;
 
     assert(p->iov.size > 0);
     ccid_bulk_in_get(s);
     if (s->current_bulk_in != NULL) {
-        ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
+        len = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
                   p->iov.size);
         usb_packet_copy(p, s->current_bulk_in->data +
-                        s->current_bulk_in->pos, ret);
-        s->current_bulk_in->pos += ret;
+                        s->current_bulk_in->pos, len);
+        s->current_bulk_in->pos += len;
         if (s->current_bulk_in->pos == s->current_bulk_in->len) {
             ccid_bulk_in_release(s);
         }
     } else {
         /* return when device has no data - usb 2.0 spec Table 8-4 */
-        ret = USB_RET_NAK;
+        return USB_RET_NAK;
     }
-    if (ret > 0) {
+    if (len) {
         DPRINTF(s, D_MORE_INFO,
                 "%s: %zd/%d req/act to guest (BULK_IN)\n",
-                __func__, p->iov.size, ret);
+                __func__, p->iov.size, len);
     }
-    if (ret != USB_RET_NAK && ret < p->iov.size) {
+    if (len < p->iov.size) {
         DPRINTF(s, 1,
                 "%s: returning short (EREMOTEIO) %d < %zd\n",
-                __func__, ret, p->iov.size);
+                __func__, len, p->iov.size);
     }
-    return ret;
+    return USB_RET_SUCCESS;
 }
 
 static int ccid_handle_data(USBDevice *dev, USBPacket *p)
 {
     USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
-    int ret = 0;
+    int ret = USB_RET_SUCCESS;
     uint8_t buf[2];
 
     switch (p->pid) {
@@ -1010,7 +1010,6 @@  static int ccid_handle_data(USBDevice *dev, USBPacket *p)
                 buf[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
                 buf[1] = s->bmSlotICCState;
                 usb_packet_copy(p, buf, 2);
-                ret = 2;
                 s->notify_slot_change = false;
                 s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK;
                 DPRINTF(s, D_INFO,
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index e732191..70dae03 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -215,7 +215,7 @@  static const USBDesc desc = {
 static void usb_msd_copy_data(MSDState *s, USBPacket *p)
 {
     uint32_t len;
-    len = p->iov.size - p->result;
+    len = p->iov.size - p->actual_length;
     if (len > s->scsi_len)
         len = s->scsi_len;
     usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len);
@@ -263,7 +263,7 @@  static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
     if (p) {
         usb_msd_copy_data(s, p);
         p = s->packet;
-        if (p && p->result == p->iov.size) {
+        if (p && p->actual_length == p->iov.size) {
             usb_msd_packet_complete(s);
         }
     }
@@ -292,7 +292,7 @@  static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r
             s->mode = USB_MSDM_CBW;
         } else {
             if (s->data_len) {
-                int len = (p->iov.size - p->result);
+                int len = (p->iov.size - p->actual_length);
                 usb_packet_skip(p, len);
                 s->data_len -= len;
             }
@@ -330,7 +330,7 @@  static void usb_msd_handle_reset(USBDevice *dev)
     assert(s->req == NULL);
 
     if (s->packet) {
-        s->packet->result = USB_RET_STALL;
+        s->packet->status = USB_RET_STALL;
         usb_msd_packet_complete(s);
     }
 
@@ -344,24 +344,22 @@  static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
     int ret;
 
     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
-    if (ret >= 0) {
+    if (ret == USB_RET_SUCCESS) {
         return ret;
     }
 
-    ret = 0;
+    ret = USB_RET_SUCCESS;
     switch (request) {
     case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
-        ret = 0;
         break;
         /* Class specific requests.  */
     case ClassInterfaceOutRequest | MassStorageReset:
         /* Reset state ready for the next CBW.  */
         s->mode = USB_MSDM_CBW;
-        ret = 0;
         break;
     case ClassInterfaceRequest | GetMaxLun:
         data[0] = 0;
-        ret = 1;
+        p->actual_length = 1;
         break;
     default:
         ret = USB_RET_STALL;
@@ -386,7 +384,7 @@  static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
 {
     MSDState *s = (MSDState *)dev;
     uint32_t tag;
-    int ret = 0;
+    int ret = USB_RET_SUCCESS;
     struct usb_msd_cbw cbw;
     uint8_t devep = p->ep->nr;
 
@@ -433,7 +431,6 @@  static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
             if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
                 scsi_req_continue(s->req);
             }
-            ret = p->result;
             break;
 
         case USB_MSDM_DATAOUT:
@@ -446,7 +443,7 @@  static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
                 usb_msd_copy_data(s, p);
             }
             if (le32_to_cpu(s->csw.residue)) {
-                int len = p->iov.size - p->result;
+                int len = p->iov.size - p->actual_length;
                 if (len) {
                     usb_packet_skip(p, len);
                     s->data_len -= len;
@@ -455,12 +452,10 @@  static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
                     }
                 }
             }
-            if (p->result < p->iov.size) {
+            if (p->actual_length < p->iov.size) {
                 DPRINTF("Deferring packet %p [wait data-out]\n", p);
                 s->packet = p;
                 ret = USB_RET_ASYNC;
-            } else {
-                ret = p->result;
             }
             break;
 
@@ -497,7 +492,6 @@  static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
             } else {
                 usb_msd_send_status(s, p);
                 s->mode = USB_MSDM_CBW;
-                ret = 13;
             }
             break;
 
@@ -508,7 +502,7 @@  static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
                 usb_msd_copy_data(s, p);
             }
             if (le32_to_cpu(s->csw.residue)) {
-                int len = p->iov.size - p->result;
+                int len = p->iov.size - p->actual_length;
                 if (len) {
                     usb_packet_skip(p, len);
                     s->data_len -= len;
@@ -517,12 +511,10 @@  static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
                     }
                 }
             }
-            if (p->result < p->iov.size) {
+            if (p->actual_length < p->iov.size) {
                 DPRINTF("Deferring packet %p [wait data-in]\n", p);
                 s->packet = p;
                 ret = USB_RET_ASYNC;
-            } else {
-                ret = p->result;
             }
             break;
 
diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
index 5a0057a..8014c2b 100644
--- a/hw/usb/dev-uas.c
+++ b/hw/usb/dev-uas.c
@@ -256,7 +256,6 @@  static void usb_uas_send_status_bh(void *opaque)
 
     uas->status = NULL;
     usb_packet_copy(p, &st->status, st->length);
-    p->result = st->length;
     QTAILQ_REMOVE(&uas->results, st, next);
     g_free(st);
 
@@ -357,16 +356,16 @@  static void usb_uas_copy_data(UASRequest *req)
     uint32_t length;
 
     length = MIN(req->buf_size - req->buf_off,
-                 req->data->iov.size - req->data->result);
+                 req->data->iov.size - req->data->actual_length);
     trace_usb_uas_xfer_data(req->uas->dev.addr, req->tag, length,
-                            req->data->result, req->data->iov.size,
+                            req->data->actual_length, req->data->iov.size,
                             req->buf_off, req->buf_size);
     usb_packet_copy(req->data, scsi_req_get_buf(req->req) + req->buf_off,
                     length);
     req->buf_off += length;
     req->data_off += length;
 
-    if (req->data->result == req->data->iov.size) {
+    if (req->data->actual_length == req->data->iov.size) {
         usb_uas_complete_data_packet(req);
     }
     if (req->buf_size && req->buf_off == req->buf_size) {
@@ -510,7 +509,7 @@  static int usb_uas_handle_control(USBDevice *dev, USBPacket *p,
     int ret;
 
     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
-    if (ret >= 0) {
+    if (ret == USB_RET_SUCCESS) {
         return ret;
     }
     fprintf(stderr, "%s: unhandled control request\n", __func__);
@@ -649,7 +648,7 @@  static int usb_uas_handle_data(USBDevice *dev, USBPacket *p)
     uas_ui ui;
     UASStatus *st;
     UASRequest *req;
-    int length, ret = 0;
+    int length, ret = USB_RET_SUCCESS;
 
     switch (p->ep->nr) {
     case UAS_PIPE_ID_COMMAND:
@@ -658,15 +657,14 @@  static int usb_uas_handle_data(USBDevice *dev, USBPacket *p)
         switch (ui.hdr.id) {
         case UAS_UI_COMMAND:
             usb_uas_command(uas, &ui);
-            ret = length;
             break;
         case UAS_UI_TASK_MGMT:
             usb_uas_task(uas, &ui);
-            ret = length;
             break;
         default:
             fprintf(stderr, "%s: unknown command ui: id 0x%x\n",
                     __func__, ui.hdr.id);
+            p->actual_length = 0;
             ret = USB_RET_STALL;
             break;
         }
@@ -680,7 +678,6 @@  static int usb_uas_handle_data(USBDevice *dev, USBPacket *p)
             break;
         }
         usb_packet_copy(p, &st->status, st->length);
-        ret = st->length;
         QTAILQ_REMOVE(&uas->results, st, next);
         g_free(st);
         break;
@@ -695,9 +692,8 @@  static int usb_uas_handle_data(USBDevice *dev, USBPacket *p)
         scsi_req_ref(req->req);
         req->data = p;
         usb_uas_copy_data(req);
-        if (p->result == p->iov.size || req->complete) {
+        if (p->actual_length == p->iov.size || req->complete) {
             req->data = NULL;
-            ret = p->result;
         } else {
             req->data_async = true;
             ret = USB_RET_ASYNC;
diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c
index ed9a5ee..3945948 100644
--- a/hw/usb/dev-wacom.c
+++ b/hw/usb/dev-wacom.c
@@ -257,11 +257,11 @@  static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
     int ret;
 
     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
-    if (ret >= 0) {
+    if (ret == USB_RET_SUCCESS) {
         return ret;
     }
 
-    ret = 0;
+    ret = USB_RET_SUCCESS;
     switch (request) {
     case WACOM_SET_REPORT:
         if (s->mouse_grabbed) {
@@ -269,27 +269,25 @@  static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
             s->mouse_grabbed = 0;
         }
         s->mode = data[0];
-        ret = 0;
         break;
     case WACOM_GET_REPORT:
         data[0] = 0;
         data[1] = s->mode;
-        ret = 2;
+        p->actual_length = 2;
         break;
     /* USB HID requests */
     case HID_GET_REPORT:
         if (s->mode == WACOM_MODE_HID)
-            ret = usb_mouse_poll(s, data, length);
+            p->actual_length = usb_mouse_poll(s, data, length);
         else if (s->mode == WACOM_MODE_WACOM)
-            ret = usb_wacom_poll(s, data, length);
+            p->actual_length = usb_wacom_poll(s, data, length);
         break;
     case HID_GET_IDLE:
-        ret = 1;
         data[0] = s->idle;
+        p->actual_length = 1;
         break;
     case HID_SET_IDLE:
         s->idle = (uint8_t) (value >> 8);
-        ret = 0;
         break;
     default:
         ret = USB_RET_STALL;
@@ -302,7 +300,7 @@  static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
 {
     USBWacomState *s = (USBWacomState *) dev;
     uint8_t buf[p->iov.size];
-    int ret = 0;
+    int len = 0, ret = USB_RET_SUCCESS;
 
     switch (p->pid) {
     case USB_TOKEN_IN:
@@ -311,10 +309,10 @@  static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
                 return USB_RET_NAK;
             s->changed = 0;
             if (s->mode == WACOM_MODE_HID)
-                ret = usb_mouse_poll(s, buf, p->iov.size);
+                len = usb_mouse_poll(s, buf, p->iov.size);
             else if (s->mode == WACOM_MODE_WACOM)
-                ret = usb_wacom_poll(s, buf, p->iov.size);
-            usb_packet_copy(p, buf, ret);
+                len = usb_wacom_poll(s, buf, p->iov.size);
+            usb_packet_copy(p, buf, len);
             break;
         }
         /* Fall through.  */
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 18cf097..3e74372 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1458,7 +1458,7 @@  static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
     p = container_of(packet, EHCIPacket, packet);
     assert(p->async == EHCI_ASYNC_INFLIGHT);
 
-    if (packet->result == USB_RET_REMOVE_FROM_QUEUE) {
+    if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
         trace_usb_ehci_packet_action(p->queue, p, "remove");
         ehci_free_packet(p);
         return;
@@ -1466,7 +1466,7 @@  static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
 
     trace_usb_ehci_packet_action(p->queue, p, "wakeup");
     p->async = EHCI_ASYNC_FINISHED;
-    p->usb_status = packet->result;
+    p->usb_status = packet->status ? packet->status : packet->actual_length;
 
     if (p->queue->async) {
         qemu_bh_schedule(p->queue->ehci->async_bh);
@@ -1599,6 +1599,9 @@  static int ehci_execute(EHCIPacket *p, const char *action)
 
     trace_usb_ehci_packet_action(p->queue, p, action);
     ret = usb_handle_packet(p->queue->dev, &p->packet);
+    if (ret == USB_RET_SUCCESS) {
+        ret = p->packet.actual_length;
+    }
     DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd endp %x ret %d\n",
             q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
             q->packet.iov.size, endp, ret);
@@ -1667,6 +1670,9 @@  static int ehci_process_itd(EHCIState *ehci,
                 usb_packet_map(&ehci->ipacket, &ehci->isgl);
                 ret = usb_handle_packet(dev, &ehci->ipacket);
                 assert(ret != USB_RET_ASYNC);
+                if (ret == USB_RET_SUCCESS) {
+                    ret = ehci->ipacket.actual_length;
+                }
                 usb_packet_unmap(&ehci->ipacket, &ehci->isgl);
             } else {
                 DPRINTF("ISOCH: attempt to addess non-iso endpoint\n");
diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c
index a6105d3..02cfa18 100644
--- a/hw/usb/hcd-musb.c
+++ b/hw/usb/hcd-musb.c
@@ -633,6 +633,9 @@  static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
     ep->packey[dir].dir = dir;
 
     ret = usb_handle_packet(dev, &ep->packey[dir].p);
+    if (ret == USB_RET_SUCCESS) {
+        ret = ep->packey[dir].p.actual_length;
+    }
 
     if (ret == USB_RET_ASYNC) {
         usb_device_flush_ep_queue(dev, uep);
@@ -754,7 +757,6 @@  static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
 
     if (ep->status[1] == USB_RET_STALL) {
         ep->status[1] = 0;
-        packey->result = 0;
 
         ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
         if (!epnum)
@@ -793,14 +795,12 @@  static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
     /* TODO: check len for over/underruns of an OUT packet?  */
     /* TODO: perhaps make use of e->ext_size[1] here.  */
 
-    packey->result = ep->status[1];
-
     if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
         ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
         if (!epnum)
             ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
 
-        ep->rxcount = packey->result; /* XXX: MIN(packey->len, ep->maxp[1]); */
+        ep->rxcount = ep->status[1]; /* XXX: MIN(packey->len, ep->maxp[1]); */
         /* In DMA mode: assert DMA request for this EP */
     }
 
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index 4c77600..94a5c01 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -808,7 +808,7 @@  static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
     }
 
     if (completion) {
-        ret = ohci->usb_packet.result;
+        ret = ohci->usb_packet.status;
     } else {
         bool int_req = relative_frame_number == frame_count &&
                        OHCI_BM(iso_td.flags, TD_DI) == 0;
@@ -822,6 +822,9 @@  static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
             return 1;
         }
     }
+    if (ret == USB_RET_SUCCESS) {
+        ret = ohci->usb_packet.actual_length;
+    }
 
 #ifdef DEBUG_ISOCH
     printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d\n",
@@ -997,7 +1000,7 @@  static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
     }
 #endif
     if (completion) {
-        ret = ohci->usb_packet.result;
+        ret = ohci->usb_packet.status;
         ohci->async_td = 0;
         ohci->async_complete = 0;
     } else {
@@ -1027,6 +1030,9 @@  static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
             return 1;
         }
     }
+    if (ret == USB_RET_SUCCESS) {
+        ret = ohci->usb_packet.actual_length;
+    }
     if (ret >= 0) {
         if (dir == OHCI_TD_DIR_IN) {
             ohci_copy_td(ohci, &td, ohci->usb_buf, ret,
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 4a1ea6b..65b63d3 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -705,21 +705,20 @@  static void uhci_process_frame(UHCIState *s);
 */
 static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask)
 {
-    int len = 0, max_len, err, ret;
+    int len = 0, max_len, err;
     uint8_t pid;
 
     max_len = ((td->token >> 21) + 1) & 0x7ff;
     pid = td->token & 0xff;
 
-    ret = async->packet.result;
-
     if (td->ctrl & TD_CTRL_IOS)
         td->ctrl &= ~TD_CTRL_ACTIVE;
 
-    if (ret < 0)
+    if (async->packet.status != USB_RET_SUCCESS) {
         goto out;
+    }
 
-    len = async->packet.result;
+    len = async->packet.actual_length;
     td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
 
     /* The NAK bit may have been set by a previous frame, so clear it
@@ -744,7 +743,7 @@  static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
     return TD_RESULT_COMPLETE;
 
 out:
-    switch(ret) {
+    switch (async->packet.status) {
     case USB_RET_STALL:
         td->ctrl |= TD_CTRL_STALL;
         td->ctrl &= ~TD_CTRL_ACTIVE;
@@ -806,7 +805,7 @@  static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
                           struct USBEndpoint **ep_ret)
 {
     UHCIAsync *async;
-    int len = 0, max_len;
+    int ret, max_len;
     uint8_t pid;
     bool spd;
     USBDevice *dev;
@@ -868,13 +867,14 @@  static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
     switch(pid) {
     case USB_TOKEN_OUT:
     case USB_TOKEN_SETUP:
-        len = usb_handle_packet(dev, &async->packet);
-        if (len >= 0)
-            len = max_len;
+        ret = usb_handle_packet(dev, &async->packet);
+        if (ret == USB_RET_SUCCESS) {
+            async->packet.actual_length = max_len;
+        }
         break;
 
     case USB_TOKEN_IN:
-        len = usb_handle_packet(dev, &async->packet);
+        ret = usb_handle_packet(dev, &async->packet);
         break;
 
     default:
@@ -885,19 +885,19 @@  static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
         uhci_update_irq(s);
         return TD_RESULT_STOP_FRAME;
     }
- 
-    if (len == USB_RET_ASYNC) {
+
+    if (ret == USB_RET_ASYNC) {
         uhci_async_link(async);
         return TD_RESULT_ASYNC_START;
     }
 
-    async->packet.result = len;
+    async->packet.status = ret;
 
 done:
-    len = uhci_complete_td(s, td, async, int_mask);
+    ret = uhci_complete_td(s, td, async, int_mask);
     usb_packet_unmap(&async->packet, &async->sgl);
     uhci_async_free(async);
-    return len;
+    return ret;
 }
 
 static void uhci_async_complete(USBPort *port, USBPacket *packet)
@@ -905,7 +905,7 @@  static void uhci_async_complete(USBPort *port, USBPacket *packet)
     UHCIAsync *async = container_of(packet, UHCIAsync, packet);
     UHCIState *s = async->queue->uhci;
 
-    if (packet->result == USB_RET_REMOVE_FROM_QUEUE) {
+    if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
         uhci_async_unlink(async);
         uhci_async_cancel(async);
         return;
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 21c3386..ffba6de 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -1356,7 +1356,7 @@  static void xhci_xfer_report(XHCITransfer *xfer)
     XHCIState *xhci = xfer->xhci;
     int i;
 
-    left = xfer->packet.result < 0 ? 0 : xfer->packet.result;
+    left = xfer->packet.status ? 0 : xfer->packet.actual_length;
 
     for (i = 0; i < xfer->trb_count; i++) {
         XHCITRB *trb = &xfer->trbs[i];
@@ -1491,8 +1491,8 @@  static int xhci_complete_packet(XHCITransfer *xfer, int ret)
         xhci_xfer_unmap(xfer);
     }
 
-    if (ret >= 0) {
-        trace_usb_xhci_xfer_success(xfer, ret);
+    if (ret == USB_RET_SUCCESS) {
+        trace_usb_xhci_xfer_success(xfer, xfer->packet.actual_length);
         xfer->status = CC_SUCCESS;
         xhci_xfer_report(xfer);
         return 0;
@@ -2840,11 +2840,11 @@  static void xhci_complete(USBPort *port, USBPacket *packet)
 {
     XHCITransfer *xfer = container_of(packet, XHCITransfer, packet);
 
-    if (packet->result == USB_RET_REMOVE_FROM_QUEUE) {
+    if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
         xhci_ep_nuke_one_xfer(xfer);
         return;
     }
-    xhci_complete_packet(xfer, packet->result);
+    xhci_complete_packet(xfer, packet->status);
     xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid);
 }
 
diff --git a/hw/usb/host-bsd.c b/hw/usb/host-bsd.c
index ec26266..3968f30 100644
--- a/hw/usb/host-bsd.c
+++ b/hw/usb/host-bsd.c
@@ -139,7 +139,7 @@  static int usb_host_handle_control(USBDevice *dev,
 
         /* specific SET_ADDRESS support */
         dev->addr = value;
-        return 0;
+        return USB_RET_SUCCESS;
     } else if ((request >> 8) == UT_WRITE_DEVICE &&
                (request & 0xff) == UR_SET_CONFIG) {
 
@@ -154,7 +154,7 @@  static int usb_host_handle_control(USBDevice *dev,
             return USB_RET_STALL;
         }
 
-        return 0;
+        return USB_RET_SUCCESS;
     } else if ((request >> 8) == UT_WRITE_INTERFACE &&
                (request & 0xff) == UR_SET_INTERFACE) {
 
@@ -171,7 +171,7 @@  static int usb_host_handle_control(USBDevice *dev,
             return USB_RET_STALL;
         }
 
-        return 0;
+        return USB_RET_SUCCESS;
     } else {
         req.ucr_request.bmRequestType = request >> 8;
         req.ucr_request.bRequest = request & 0xff;
@@ -203,7 +203,8 @@  static int usb_host_handle_control(USBDevice *dev,
 #endif
             return USB_RET_NAK; // STALL
         } else {
-            return req.ucr_actlen;
+            p->actual_length = req.ucr_actlen;
+            return USB_RET_SUCCESS;
         }
     }
 }
@@ -272,7 +273,8 @@  static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
             return USB_RET_STALL;
         }
     } else {
-        return ret;
+        p->actual_length = ret;
+        return USB_RET_SUCCESS;
     }
 }
 
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 3a258b4..9857292 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -366,28 +366,29 @@  static void async_complete(void *opaque)
         if (p) {
             switch (aurb->urb.status) {
             case 0:
-                p->result += aurb->urb.actual_length;
+                p->actual_length = aurb->urb.actual_length;
+                p->status = USB_RET_SUCCESS;
                 break;
 
             case -EPIPE:
                 set_halt(s, p->pid, p->ep->nr);
-                p->result = USB_RET_STALL;
+                p->status = USB_RET_STALL;
                 break;
 
             case -EOVERFLOW:
-                p->result = USB_RET_BABBLE;
+                p->status = USB_RET_BABBLE;
                 break;
 
             default:
-                p->result = USB_RET_IOERROR;
+                p->status = USB_RET_IOERROR;
                 break;
             }
 
             if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
-                trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result);
+                trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status);
                 usb_generic_async_ctrl_complete(&s->dev, p);
             } else if (!aurb->more) {
-                trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result);
+                trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status);
                 usb_packet_complete(&s->dev, p);
             }
         }
@@ -748,7 +749,7 @@  static int urb_status_to_usb_ret(int status)
 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;
+    int i, j, max_packet_size, offset, len, ret = USB_RET_SUCCESS;
     uint8_t *buf;
 
     max_packet_size = p->ep->max_packet_size;
@@ -766,18 +767,18 @@  static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
         if (in) {
             /* Check urb status  */
             if (aurb[i].urb.status) {
-                len = urb_status_to_usb_ret(aurb[i].urb.status);
+                ret = urb_status_to_usb_ret(aurb[i].urb.status);
                 /* Move to the next urb */
                 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
             /* Check frame status */
             } else if (aurb[i].urb.iso_frame_desc[j].status) {
-                len = urb_status_to_usb_ret(
+                ret = urb_status_to_usb_ret(
                                         aurb[i].urb.iso_frame_desc[j].status);
             /* Check the frame fits */
             } 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_BABBLE;
+                ret = USB_RET_BABBLE;
             /* All good copy data over */
             } else {
                 len = aurb[i].urb.iso_frame_desc[j].actual_length;
@@ -823,17 +824,16 @@  static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
         /* (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) {
-                ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
-                if (ret < 0) {
+                if (ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]) < 0) {
                     perror("USBDEVFS_SUBMITURB");
-                    if (!in || len == 0) {
+                    if (!in || ret == USB_RET_SUCCESS) {
                         switch(errno) {
                         case ETIMEDOUT:
-                            len = USB_RET_NAK;
+                            ret = USB_RET_NAK;
                             break;
                         case EPIPE:
                         default:
-                            len = USB_RET_STALL;
+                            ret = USB_RET_STALL;
                         }
                     }
                     break;
@@ -844,7 +844,7 @@  static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
         }
     }
 
-    return len;
+    return ret;
 }
 
 static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
@@ -959,7 +959,7 @@  static int usb_host_set_address(USBHostDevice *s, int addr)
 {
     trace_usb_host_set_address(s->bus_num, s->addr, addr);
     s->dev.addr = addr;
-    return 0;
+    return USB_RET_SUCCESS;
 }
 
 static int usb_host_set_config(USBHostDevice *s, int config)
@@ -991,7 +991,7 @@  again:
     }
     usb_host_claim_interfaces(s, config);
     usb_linux_update_endp_table(s);
-    return 0;
+    return USB_RET_SUCCESS;
 }
 
 static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
@@ -1027,7 +1027,7 @@  static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
 
     s->dev.altsetting[iface] = alt;
     usb_linux_update_endp_table(s);
-    return 0;
+    return USB_RET_SUCCESS;
 }
 
 static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
@@ -1068,12 +1068,12 @@  static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
             ioctl(s->fd, USBDEVFS_CLEAR_HALT, &index);
             clear_halt(s, pid, index & 0x0f);
             trace_usb_host_req_emulated(s->bus_num, s->addr, p, 0);
-            return 0;
+            return USB_RET_SUCCESS;
         }
     }
 
     /* The rest are asynchronous */
-    assert(p && p->result == 0);
+    assert(p && p->status == USB_RET_SUCCESS);
 
     if (length > sizeof(dev->data_buf)) {
         fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 2c5377c..040582c 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -141,8 +141,8 @@  static void usbredir_interrupt_packet(void *priv, uint64_t id,
     struct usb_redir_interrupt_packet_header *interrupt_header,
     uint8_t *data, int data_len);
 
-static int usbredir_handle_status(USBRedirDevice *dev,
-                                       int status, int actual_len);
+static int usbredir_handle_status(USBRedirDevice *dev, USBPacket *p,
+    int status);
 
 #define VERSION "qemu usb-redir guest " QEMU_VERSION
 
@@ -506,7 +506,7 @@  static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
                 !dev->endpoint[EP2I(ep)].bufpq_prefilled) {
             if (dev->endpoint[EP2I(ep)].bufpq_size <
                     dev->endpoint[EP2I(ep)].bufpq_target_size) {
-                return usbredir_handle_status(dev, 0, 0);
+                return USB_RET_SUCCESS;
             }
             dev->endpoint[EP2I(ep)].bufpq_prefilled = 1;
         }
@@ -540,7 +540,7 @@  static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
         }
         usb_packet_copy(p, isop->data, len);
         bufp_free(dev, isop, ep);
-        return len;
+        return USB_RET_SUCCESS;
     } else {
         /* If the stream was not started because of a pending error don't
            send the packet to the usb-host */
@@ -560,7 +560,7 @@  static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
         dev->endpoint[EP2I(ep)].iso_error = 0;
         DPRINTF2("iso-token-out ep %02X status %d len %zd\n", ep, status,
                  p->iov.size);
-        return usbredir_handle_status(dev, status, p->iov.size);
+        return usbredir_handle_status(dev, p, status);
     }
 }
 
@@ -649,7 +649,7 @@  static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
             status = dev->endpoint[EP2I(ep)].interrupt_error;
             dev->endpoint[EP2I(ep)].interrupt_error = 0;
             if (status) {
-                return usbredir_handle_status(dev, status, 0);
+                return usbredir_handle_status(dev, p, status);
             }
             return USB_RET_NAK;
         }
@@ -659,7 +659,7 @@  static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
         status = intp->status;
         if (status != usb_redir_success) {
             bufp_free(dev, intp, ep);
-            return usbredir_handle_status(dev, status, 0);
+            return usbredir_handle_status(dev, p, status);
         }
 
         len = intp->len;
@@ -670,7 +670,7 @@  static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
         }
         usb_packet_copy(p, intp->data, len);
         bufp_free(dev, intp, ep);
-        return len;
+        return USB_RET_SUCCESS;
     } else {
         /* Output interrupt endpoint, normal async operation */
         struct usb_redir_interrupt_packet_header interrupt_packet;
@@ -1184,30 +1184,39 @@  error:
  * usbredirparser packet complete callbacks
  */
 
-static int usbredir_handle_status(USBRedirDevice *dev,
-                                       int status, int actual_len)
+static int usbredir_handle_status(USBRedirDevice *dev, USBPacket *p,
+    int status)
 {
+    int ret;
+
     switch (status) {
     case usb_redir_success:
-        return actual_len;
+        ret = USB_RET_SUCCESS;
+        break;
     case usb_redir_stall:
-        return USB_RET_STALL;
+        ret = USB_RET_STALL;
+        break;
     case usb_redir_cancelled:
         /*
          * When the usbredir-host unredirects a device, it will report a status
          * of cancelled for all pending packets, followed by a disconnect msg.
          */
-        return USB_RET_IOERROR;
+        ret = USB_RET_IOERROR;
+        break;
     case usb_redir_inval:
         WARNING("got invalid param error from usb-host?\n");
-        return USB_RET_IOERROR;
+        ret = USB_RET_IOERROR;
+        break;
     case usb_redir_babble:
-        return USB_RET_BABBLE;
+        ret = USB_RET_BABBLE;
+        break;
     case usb_redir_ioerror:
     case usb_redir_timeout:
     default:
-        return USB_RET_IOERROR;
+        ret = USB_RET_IOERROR;
     }
+    p->status = ret;
+    return ret;
 }
 
 static void usbredir_hello(void *priv, struct usb_redir_hello_header *h)
@@ -1437,7 +1446,6 @@  static void usbredir_configuration_status(void *priv, uint64_t id,
 {
     USBRedirDevice *dev = priv;
     USBPacket *p;
-    int len = 0;
 
     DPRINTF("set config status %d config %d id %"PRIu64"\n",
             config_status->status, config_status->configuration, id);
@@ -1446,9 +1454,9 @@  static void usbredir_configuration_status(void *priv, uint64_t id,
     if (p) {
         if (dev->dev.setup_buf[0] & USB_DIR_IN) {
             dev->dev.data_buf[0] = config_status->configuration;
-            len = 1;
+            p->actual_length = 1;
         }
-        p->result = usbredir_handle_status(dev, config_status->status, len);
+        usbredir_handle_status(dev, p, config_status->status);
         usb_generic_async_ctrl_complete(&dev->dev, p);
     }
 }
@@ -1458,7 +1466,6 @@  static void usbredir_alt_setting_status(void *priv, uint64_t id,
 {
     USBRedirDevice *dev = priv;
     USBPacket *p;
-    int len = 0;
 
     DPRINTF("alt status %d intf %d alt %d id: %"PRIu64"\n",
             alt_setting_status->status, alt_setting_status->interface,
@@ -1468,10 +1475,9 @@  static void usbredir_alt_setting_status(void *priv, uint64_t id,
     if (p) {
         if (dev->dev.setup_buf[0] & USB_DIR_IN) {
             dev->dev.data_buf[0] = alt_setting_status->alt;
-            len = 1;
+            p->actual_length = 1;
         }
-        p->result =
-            usbredir_handle_status(dev, alt_setting_status->status, len);
+        usbredir_handle_status(dev, p, alt_setting_status->status);
         usb_generic_async_ctrl_complete(&dev->dev, p);
     }
 }
@@ -1547,18 +1553,19 @@  static void usbredir_control_packet(void *priv, uint64_t id,
 
     p = usbredir_find_packet_by_id(dev, 0, id);
     if (p) {
-        len = usbredir_handle_status(dev, control_packet->status, len);
-        if (len > 0) {
+        usbredir_handle_status(dev, p, control_packet->status);
+        if (p->status == USB_RET_SUCCESS) {
             usbredir_log_data(dev, "ctrl data in:", data, data_len);
             if (data_len <= sizeof(dev->dev.data_buf)) {
                 memcpy(dev->dev.data_buf, data, data_len);
             } else {
                 ERROR("ctrl buffer too small (%d > %zu)\n",
                       data_len, sizeof(dev->dev.data_buf));
-                len = USB_RET_STALL;
+                p->status = USB_RET_STALL;
+                len = 0;
             }
         }
-        p->result = len;
+        p->actual_length = len;
         usb_generic_async_ctrl_complete(&dev->dev, p);
     }
     free(data);
@@ -1579,8 +1586,8 @@  static void usbredir_bulk_packet(void *priv, uint64_t id,
     p = usbredir_find_packet_by_id(dev, ep, id);
     if (p) {
         size_t size = (p->combined) ? p->combined->iov.size : p->iov.size;
-        len = usbredir_handle_status(dev, bulk_packet->status, len);
-        if (len > 0) {
+        usbredir_handle_status(dev, p, bulk_packet->status);
+        if (p->status == USB_RET_SUCCESS) {
             usbredir_log_data(dev, "bulk data in:", data, data_len);
             if (data_len <= size) {
                 if (p->combined) {
@@ -1592,10 +1599,11 @@  static void usbredir_bulk_packet(void *priv, uint64_t id,
             } else {
                 ERROR("bulk got more data then requested (%d > %zd)\n",
                       data_len, p->iov.size);
-                len = USB_RET_BABBLE;
+                p->status = USB_RET_BABBLE;
+                len = 0;
             }
         }
-        p->result = len;
+        p->actual_length = len;
         if (p->pid == USB_TOKEN_IN && p->ep->pipeline) {
             usb_combined_input_packet_complete(&dev->dev, p);
         } else {
@@ -1661,8 +1669,8 @@  static void usbredir_interrupt_packet(void *priv, uint64_t id,
 
         USBPacket *p = usbredir_find_packet_by_id(dev, ep, id);
         if (p) {
-            p->result = usbredir_handle_status(dev,
-                                               interrupt_packet->status, len);
+            usbredir_handle_status(dev, p, interrupt_packet->status);
+            p->actual_length = len;
             usb_packet_complete(&dev->dev, p);
         }
     }