qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [STABLE PULL] usb bugfixes
@ 2011-09-02 10:01 Gerd Hoffmann
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 1/7] usb-host: reapurb error report fix Gerd Hoffmann
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2011-09-02 10:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

  Hi,

These are the bugfixes for stable cherry-picked from
master's usb patch queue.

please pull,
  Gerd

The following changes since commit 76e4e1d23711750f777333654f13cf6baf8d01f1:

  Update version to 0.15.0 (2011-08-08 13:27:32 -0500)

are available in the git repository at:
  git://git.kraxel.org/qemu usb.25.stable

Gerd Hoffmann (7):
      usb-host: reapurb error report fix
      usb-host: fix halted endpoints
      usb-host: fix configuration tracking.
      usb-host: endpoint table fixup
      usb-ehci: handle siTDs
      usb: fix use after free
      usb: claim port at device initialization time.

 hw/usb-bus.c  |  110 +++++++++++++----------
 hw/usb-ehci.c |   65 +++++++++++---
 hw/usb-hub.c  |   12 +---
 hw/usb-ohci.c |    4 +-
 hw/usb-uhci.c |   11 ++-
 hw/usb.c      |   37 ++++----
 hw/usb.h      |    5 +-
 trace-events  |    7 ++
 usb-linux.c   |  273 +++++++++++++++++++++++++++------------------------------
 9 files changed, 282 insertions(+), 242 deletions(-)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 1/7] usb-host: reapurb error report fix
  2011-09-02 10:01 [Qemu-devel] [STABLE PULL] usb bugfixes Gerd Hoffmann
@ 2011-09-02 10:01 ` Gerd Hoffmann
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 2/7] usb-host: fix halted endpoints Gerd Hoffmann
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2011-09-02 10:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Don't report errors on devices which are in disconnected
and closing state.
(cherry picked from commit 3d09d54e57b92aaaba8d4e8c0d1c9901f1a56c7f)

Conflicts:

	usb-linux.c
---
 usb-linux.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/usb-linux.c b/usb-linux.c
index 53cc5fc..7d8a103 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -308,8 +308,10 @@ static void async_complete(void *opaque)
                 }
                 return;
             }
-            if (errno == ENODEV && !s->closing) {
-                do_disconnect(s);
+            if (errno == ENODEV) {
+                if (!s->closing) {
+                    do_disconnect(s);
+                }
                 return;
             }
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 2/7] usb-host: fix halted endpoints
  2011-09-02 10:01 [Qemu-devel] [STABLE PULL] usb bugfixes Gerd Hoffmann
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 1/7] usb-host: reapurb error report fix Gerd Hoffmann
@ 2011-09-02 10:01 ` Gerd Hoffmann
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 3/7] usb-host: fix configuration tracking Gerd Hoffmann
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2011-09-02 10:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Two fixes for the price of one ;)

First, reinitialize the endpoint table after device reset.
This is needed anyway as the reset might have switched interfaces.
It also clears the endpoint halted state.

Second the CLEAR_HALT ioctl wants a unsigned int passed in as
argument, not uint8_t.

This gets my usb sd card reader (sandisk micromate) going.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit a8b44be4da11ba57ab3219a55eecbc422663c9b3)
---
 usb-linux.c |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/usb-linux.c b/usb-linux.c
index 7d8a103..1d0ccf8 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -142,6 +142,7 @@ static int parse_filter(const char *spec, struct USBAutoFilter *f);
 static void usb_host_auto_check(void *unused);
 static int usb_host_read_file(char *line, size_t line_size,
                             const char *device_file, const char *device_name);
+static int usb_linux_update_endp_table(USBHostDevice *s);
 
 static struct endp_data *get_endp(USBHostDevice *s, int ep)
 {
@@ -509,6 +510,7 @@ static void usb_host_handle_reset(USBDevice *dev)
     ioctl(s->fd, USBDEVFS_RESET);
 
     usb_host_claim_interfaces(s, s->configuration);
+    usb_linux_update_endp_table(s);
 }
 
 static void usb_host_handle_destroy(USBDevice *dev)
@@ -520,8 +522,6 @@ static void usb_host_handle_destroy(USBDevice *dev)
     qemu_remove_exit_notifier(&s->exit);
 }
 
-static int usb_linux_update_endp_table(USBHostDevice *s);
-
 /* iso data is special, we need to keep enough urbs in flight to make sure
    that the controller never runs out of them, otherwise the device will
    likely suffer a buffer underrun / overrun. */
@@ -723,7 +723,8 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
     }
 
     if (is_halted(s, p->devep)) {
-        ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
+        unsigned int arg = ep;
+        ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
         if (ret < 0) {
             DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
                    ep, errno);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 3/7] usb-host: fix configuration tracking.
  2011-09-02 10:01 [Qemu-devel] [STABLE PULL] usb bugfixes Gerd Hoffmann
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 1/7] usb-host: reapurb error report fix Gerd Hoffmann
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 2/7] usb-host: fix halted endpoints Gerd Hoffmann
@ 2011-09-02 10:01 ` Gerd Hoffmann
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 4/7] usb-host: endpoint table fixup Gerd Hoffmann
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2011-09-02 10:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

It is perfectly fine to leave the usb device in unconfigured state
(USBHostDevice->configuration == 0).  Just do that and wait for the
guest to explicitly set a configuration.  This is closer to what real
hardware does and it also simplifies the device initialization.  There
is no need to figure how the device is configured on the host.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit b2d7c159824b5cf6af797e8bf52243fcbb42395a)
---
 usb-linux.c |   82 +++++++++++++---------------------------------------------
 1 files changed, 19 insertions(+), 63 deletions(-)

diff --git a/usb-linux.c b/usb-linux.c
index 1d0ccf8..74f1a0b 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -397,8 +397,11 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
     int interface, nb_interfaces;
     int ret, i;
 
-    if (configuration == 0) /* address state - ignore */
+    if (configuration == 0) { /* address state - ignore */
+        dev->ninterfaces   = 0;
+        dev->configuration = 0;
         return 1;
+    }
 
     DPRINTF("husb: claiming interfaces. config %d\n", configuration);
 
@@ -423,7 +426,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
 
         printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
 
-        if (configuration < 0 || configuration == dev->descr[i + 5]) {
+        if (configuration == dev->descr[i + 5]) {
             configuration = dev->descr[i + 5];
             break;
         }
@@ -509,7 +512,7 @@ static void usb_host_handle_reset(USBDevice *dev)
 
     ioctl(s->fd, USBDEVFS_RESET);
 
-    usb_host_claim_interfaces(s, s->configuration);
+    usb_host_claim_interfaces(s, 0);
     usb_linux_update_endp_table(s);
 }
 
@@ -810,6 +813,7 @@ static int usb_host_set_config(USBHostDevice *s, int config)
         return ctrl_error();
     }
     usb_host_claim_interfaces(s, config);
+    usb_linux_update_endp_table(s);
     return 0;
 }
 
@@ -913,51 +917,6 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
     return USB_RET_ASYNC;
 }
 
-static int usb_linux_get_configuration(USBHostDevice *s)
-{
-    uint8_t configuration;
-    struct usb_ctrltransfer ct;
-    int ret;
-
-    if (usb_fs_type == USB_FS_SYS) {
-        char device_name[32], line[1024];
-        int configuration;
-
-        sprintf(device_name, "%d-%s", s->bus_num, s->port);
-
-        if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
-                                device_name)) {
-            goto usbdevfs;
-        }
-        if (sscanf(line, "%d", &configuration) != 1) {
-            goto usbdevfs;
-        }
-        return configuration;
-    }
-
-usbdevfs:
-    ct.bRequestType = USB_DIR_IN;
-    ct.bRequest = USB_REQ_GET_CONFIGURATION;
-    ct.wValue = 0;
-    ct.wIndex = 0;
-    ct.wLength = 1;
-    ct.data = &configuration;
-    ct.timeout = 50;
-
-    ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
-    if (ret < 0) {
-        perror("usb_linux_get_configuration");
-        return -1;
-    }
-
-    /* in address state */
-    if (configuration == 0) {
-        return -1;
-    }
-
-    return configuration;
-}
-
 static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
     uint8_t configuration, uint8_t interface)
 {
@@ -1003,16 +962,16 @@ usbdevfs:
 static int usb_linux_update_endp_table(USBHostDevice *s)
 {
     uint8_t *descriptors;
-    uint8_t devep, type, configuration, alt_interface;
+    uint8_t devep, type, alt_interface;
     int interface, length, i;
 
     for (i = 0; i < MAX_ENDPOINTS; i++)
         s->endp_table[i].type = INVALID_EP_TYPE;
 
-    i = usb_linux_get_configuration(s);
-    if (i < 0)
-        return 1;
-    configuration = i;
+    if (s->configuration == 0) {
+        /* not configured yet -- leave all endpoints disabled */
+        return 0;
+    }
 
     /* get the desired configuration, interface, and endpoint descriptors
      * from device description */
@@ -1021,8 +980,9 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
     i = 0;
 
     if (descriptors[i + 1] != USB_DT_CONFIG ||
-        descriptors[i + 5] != configuration) {
-        DPRINTF("invalid descriptor data - configuration\n");
+        descriptors[i + 5] != s->configuration) {
+        fprintf(stderr, "invalid descriptor data - configuration %d\n",
+                s->configuration);
         return 1;
     }
     i += descriptors[i];
@@ -1036,7 +996,8 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
         }
 
         interface = descriptors[i + 2];
-        alt_interface = usb_linux_get_alt_setting(s, configuration, interface);
+        alt_interface = usb_linux_get_alt_setting(s, s->configuration,
+                                                  interface);
 
         /* the current interface descriptor is the active interface
          * and has endpoints */
@@ -1175,13 +1136,8 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
 #endif
 
 
-    /*
-     * Initial configuration is -1 which makes us claim first
-     * available config. We used to start with 1, which does not
-     * always work. I've seen devices where first config starts
-     * with 2.
-     */
-    if (!usb_host_claim_interfaces(dev, -1)) {
+    /* start unconfigured -- we'll wait for the guest to set a configuration */
+    if (!usb_host_claim_interfaces(dev, 0)) {
         goto fail;
     }
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 4/7] usb-host: endpoint table fixup
  2011-09-02 10:01 [Qemu-devel] [STABLE PULL] usb bugfixes Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 3/7] usb-host: fix configuration tracking Gerd Hoffmann
@ 2011-09-02 10:01 ` Gerd Hoffmann
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 5/7] usb-ehci: handle siTDs Gerd Hoffmann
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2011-09-02 10:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

USB Devices can have up to 15 IN and 15 OUT endpoints, not 15 endpoints
total.  Move from one array to two arrays (one IN, one OUT) to maintain
the endpoint state.
(cherry picked from commit 07d4920d2bca19c64827a226b0afdfe8c7f1e3f0)

Conflicts:

	usb-linux.c
---
 usb-linux.c |  178 +++++++++++++++++++++++++++++++++-------------------------
 1 files changed, 101 insertions(+), 77 deletions(-)

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

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 5/7] usb-ehci: handle siTDs
  2011-09-02 10:01 [Qemu-devel] [STABLE PULL] usb bugfixes Gerd Hoffmann
                   ` (3 preceding siblings ...)
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 4/7] usb-host: endpoint table fixup Gerd Hoffmann
@ 2011-09-02 10:01 ` Gerd Hoffmann
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 6/7] usb: fix use after free Gerd Hoffmann
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 7/7] usb: claim port at device initialization time Gerd Hoffmann
  6 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2011-09-02 10:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This patch adds code to do minimal siTD handling, which is basically
just following the next pointer.  This is good enougth to handle the
inactive siTDs used by FreeBSD.  Active siTDs are skipped too as we
don't have split transfer support in qemu, additionally a warning is
printed.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit c57f5348b0c95b46b98b9ddb48b059b29c178452)
---
 hw/usb-ehci.c |   43 ++++++++++++++++++++++++++++++++++++++++++-
 trace-events  |    1 +
 2 files changed, 43 insertions(+), 1 deletions(-)

diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index a4758f9..3ea4c72 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -148,6 +148,7 @@ typedef enum {
     EST_FETCHENTRY,
     EST_FETCHQH,
     EST_FETCHITD,
+    EST_FETCHSITD,
     EST_ADVANCEQUEUE,
     EST_FETCHQTD,
     EST_EXECUTE,
@@ -645,6 +646,13 @@ static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd)
                        get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR));
 }
 
+static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr,
+                            EHCIsitd *sitd)
+{
+    trace_usb_ehci_sitd(addr, sitd->next,
+                        (bool)(sitd->results & SITD_RESULTS_ACTIVE));
+}
+
 /* queue management */
 
 static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async)
@@ -1613,8 +1621,13 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)
         again = 1;
         break;
 
+    case NLPTR_TYPE_STITD:
+        ehci_set_state(ehci, async, EST_FETCHSITD);
+        again = 1;
+        break;
+
     default:
-        // TODO: handle siTD and FSTN types
+        /* TODO: handle FSTN type */
         fprintf(stderr, "FETCHENTRY: entry at %X is of type %d "
                 "which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
         return -1;
@@ -1730,6 +1743,30 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async)
     return 1;
 }
 
+static int ehci_state_fetchsitd(EHCIState *ehci, int async)
+{
+    uint32_t entry;
+    EHCIsitd sitd;
+
+    assert(!async);
+    entry = ehci_get_fetch_addr(ehci, async);
+
+    get_dwords(NLPTR_GET(entry), (uint32_t *)&sitd,
+               sizeof(EHCIsitd) >> 2);
+    ehci_trace_sitd(ehci, entry, &sitd);
+
+    if (!(sitd.results & SITD_RESULTS_ACTIVE)) {
+        /* siTD is not active, nothing to do */;
+    } else {
+        /* TODO: split transfers are not implemented */
+        fprintf(stderr, "WARNING: Skipping active siTD\n");
+    }
+
+    ehci_set_fetch_addr(ehci, async, sitd.next);
+    ehci_set_state(ehci, async, EST_FETCHENTRY);
+    return 1;
+}
+
 /* Section 4.10.2 - paragraph 3 */
 static int ehci_state_advqueue(EHCIQueue *q, int async)
 {
@@ -2005,6 +2042,10 @@ static void ehci_advance_state(EHCIState *ehci,
             again = ehci_state_fetchitd(ehci, async);
             break;
 
+        case EST_FETCHSITD:
+            again = ehci_state_fetchsitd(ehci, async);
+            break;
+
         case EST_ADVANCEQUEUE:
             again = ehci_state_advqueue(q, async);
             break;
diff --git a/trace-events b/trace-events
index 713f042..e6f8c37 100644
--- a/trace-events
+++ b/trace-events
@@ -223,6 +223,7 @@ disable usb_ehci_qtd_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t altnext
 disable usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ %08x - tbytes %d, cpage %d, cerr %d, pid %d"
 disable usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ %08x - ioc %d, active %d, halt %d, babble %d, xacterr %d"
 disable usb_ehci_itd(uint32_t addr, uint32_t nxt, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ %08x: next %08x - mplen %d, mult %d, ep %d, dev %d"
+disable usb_ehci_sitd(uint32_t addr, uint32_t nxt, uint32_t active) "ITD @ %08x: next %08x - active %d"
 disable usb_ehci_port_attach(uint32_t port, const char *device) "attach port #%d - %s"
 disable usb_ehci_port_detach(uint32_t port) "detach port #%d"
 disable usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 6/7] usb: fix use after free
  2011-09-02 10:01 [Qemu-devel] [STABLE PULL] usb bugfixes Gerd Hoffmann
                   ` (4 preceding siblings ...)
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 5/7] usb-ehci: handle siTDs Gerd Hoffmann
@ 2011-09-02 10:01 ` Gerd Hoffmann
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 7/7] usb: claim port at device initialization time Gerd Hoffmann
  6 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2011-09-02 10:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

The ->complete() callback might have released the USBPacket (uhci
actually does), so we must not touch it after the callback returns.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 722d89396b6ccb49cd9d3aafd991ae01c8a30744)
---
 hw/usb.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/hw/usb.c b/hw/usb.c
index 27a983c..b44e997 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -334,8 +334,8 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
 {
     /* Note: p->owner != dev is possible in case dev is a hub */
     assert(p->owner != NULL);
-    dev->port->ops->complete(dev->port, p);
     p->owner = NULL;
+    dev->port->ops->complete(dev->port, p);
 }
 
 /* Cancel an active packet.  The packed must have been deferred by
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 7/7] usb: claim port at device initialization time.
  2011-09-02 10:01 [Qemu-devel] [STABLE PULL] usb bugfixes Gerd Hoffmann
                   ` (5 preceding siblings ...)
  2011-09-02 10:01 ` [Qemu-devel] [PATCH 6/7] usb: fix use after free Gerd Hoffmann
@ 2011-09-02 10:01 ` Gerd Hoffmann
  6 siblings, 0 replies; 8+ messages in thread
From: Gerd Hoffmann @ 2011-09-02 10:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This patch makes qemu assign a port when creating the device, not when
attaching it.  For most usb devices this isn't a noticable difference
because they are in attached state all the time.

The change affects usb-host devices which live in detached state while
the real device is unplugged from the host.  They have a fixed port
assigned all the time now instead of getting grabbing one on attach and
releasing it at detach, i.e. they stop floating around at the usb bus.

The change also allows to simplify usb-hub.  It doesn't need the
handle_attach() callback any more to configure the downstream ports.
This can be done at device initialitation time now.  The changed
initialization order (first grab upstream port, then register downstream
ports) also fixes some icky corner cases.  For example it is not possible
any more to plug the hub into one of its own downstream ports.

The usb host adapters must care too.  USBPort->dev being non-NULL
doesn't imply any more the device is in attached state.  The host
adapters must additionally check the USBPort->dev->attached flag.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 763917c9b6d5a6126530d8e52324e653e594c521)
---
 hw/usb-bus.c  |  110 +++++++++++++++++++++++++++++++++------------------------
 hw/usb-ehci.c |   22 ++++++------
 hw/usb-hub.c  |   12 +------
 hw/usb-ohci.c |    4 +-
 hw/usb-uhci.c |   11 +++---
 hw/usb.c      |   35 ++++++++----------
 hw/usb.h      |    5 ++-
 trace-events  |    6 +++
 8 files changed, 110 insertions(+), 95 deletions(-)

diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index f1dd55e..d384426 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -3,6 +3,7 @@
 #include "qdev.h"
 #include "sysemu.h"
 #include "monitor.h"
+#include "trace.h"
 
 static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
 
@@ -73,9 +74,13 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
     dev->info = info;
     dev->auto_attach = 1;
     QLIST_INIT(&dev->strings);
-    rc = dev->info->init(dev);
-    if (rc == 0 && dev->auto_attach)
+    rc = usb_claim_port(dev);
+    if (rc == 0) {
+        rc = dev->info->init(dev);
+    }
+    if (rc == 0 && dev->auto_attach) {
         rc = usb_device_attach(dev);
+    }
     return rc;
 }
 
@@ -89,6 +94,9 @@ static int usb_qdev_exit(DeviceState *qdev)
     if (dev->info->handle_destroy) {
         dev->info->handle_destroy(dev);
     }
+    if (dev->port) {
+        usb_release_port(dev);
+    }
     return 0;
 }
 
@@ -205,21 +213,13 @@ void usb_unregister_port(USBBus *bus, USBPort *port)
     bus->nfree--;
 }
 
-static int do_attach(USBDevice *dev)
+int usb_claim_port(USBDevice *dev)
 {
     USBBus *bus = usb_bus_from_device(dev);
     USBPort *port;
 
-    if (dev->attached) {
-        error_report("Error: tried to attach usb device %s twice\n",
-                dev->product_desc);
-        return -1;
-    }
-    if (bus->nfree == 0) {
-        error_report("Error: tried to attach usb device %s to a bus with no free ports\n",
-                dev->product_desc);
-        return -1;
-    }
+    assert(dev->port == NULL);
+
     if (dev->port_path) {
         QTAILQ_FOREACH(port, &bus->free, next) {
             if (strcmp(port->path, dev->port_path) == 0) {
@@ -227,68 +227,86 @@ static int do_attach(USBDevice *dev)
             }
         }
         if (port == NULL) {
-            error_report("Error: usb port %s (bus %s) not found\n",
-                    dev->port_path, bus->qbus.name);
+            error_report("Error: usb port %s (bus %s) not found (in use?)\n",
+                         dev->port_path, bus->qbus.name);
             return -1;
         }
     } else {
+        if (bus->nfree == 1 && strcmp(dev->qdev.info->name, "usb-hub") != 0) {
+            /* Create a new hub and chain it on */
+            usb_create_simple(bus, "usb-hub");
+        }
+        if (bus->nfree == 0) {
+            error_report("Error: tried to attach usb device %s to a bus "
+                         "with no free ports\n", dev->product_desc);
+            return -1;
+        }
         port = QTAILQ_FIRST(&bus->free);
     }
-    if (!(port->speedmask & dev->speedmask)) {
-        error_report("Warning: speed mismatch trying to attach usb device %s to bus %s\n",
-                dev->product_desc, bus->qbus.name);
-        return -1;
-    }
+    trace_usb_port_claim(bus->busnr, port->path);
 
-    dev->attached++;
     QTAILQ_REMOVE(&bus->free, port, next);
     bus->nfree--;
 
-    usb_attach(port, dev);
+    dev->port = port;
+    port->dev = dev;
 
     QTAILQ_INSERT_TAIL(&bus->used, port, next);
     bus->nused++;
-
     return 0;
 }
 
-int usb_device_attach(USBDevice *dev)
+void usb_release_port(USBDevice *dev)
 {
     USBBus *bus = usb_bus_from_device(dev);
+    USBPort *port = dev->port;
 
-    if (bus->nfree == 1 && dev->port_path == NULL) {
-        /* Create a new hub and chain it on
-           (unless a physical port location is specified). */
-        usb_create_simple(bus, "usb-hub");
-    }
-    return do_attach(dev);
+    assert(port != NULL);
+    trace_usb_port_release(bus->busnr, port->path);
+
+    QTAILQ_REMOVE(&bus->used, port, next);
+    bus->nused--;
+
+    dev->port = NULL;
+    port->dev = NULL;
+
+    QTAILQ_INSERT_TAIL(&bus->free, port, next);
+    bus->nfree++;
 }
 
-int usb_device_detach(USBDevice *dev)
+int usb_device_attach(USBDevice *dev)
 {
     USBBus *bus = usb_bus_from_device(dev);
-    USBPort *port;
+    USBPort *port = dev->port;
 
-    if (!dev->attached) {
-        error_report("Error: tried to detach unattached usb device %s\n",
-                dev->product_desc);
+    assert(port != NULL);
+    assert(!dev->attached);
+    trace_usb_port_attach(bus->busnr, port->path);
+
+    if (!(port->speedmask & dev->speedmask)) {
+        error_report("Warning: speed mismatch trying to attach "
+                     "usb device %s to bus %s\n",
+                     dev->product_desc, bus->qbus.name);
         return -1;
     }
-    dev->attached--;
 
-    QTAILQ_FOREACH(port, &bus->used, next) {
-        if (port->dev == dev)
-            break;
-    }
-    assert(port != NULL);
+    dev->attached++;
+    usb_attach(port);
 
-    QTAILQ_REMOVE(&bus->used, port, next);
-    bus->nused--;
+    return 0;
+}
+
+int usb_device_detach(USBDevice *dev)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+    USBPort *port = dev->port;
 
-    usb_attach(port, NULL);
+    assert(port != NULL);
+    assert(dev->attached);
+    trace_usb_port_detach(bus->busnr, port->path);
 
-    QTAILQ_INSERT_TAIL(&bus->free, port, next);
-    bus->nfree++;
+    usb_detach(port);
+    dev->attached--;
     return 0;
 }
 
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 3ea4c72..5bb61bb 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -856,8 +856,8 @@ static void ehci_reset(void *opaque)
      */
     for(i = 0; i < NB_PORTS; i++) {
         devs[i] = s->ports[i].dev;
-        if (devs[i]) {
-            usb_attach(&s->ports[i], NULL);
+        if (devs[i] && devs[i]->attached) {
+            usb_detach(&s->ports[i]);
         }
     }
 
@@ -877,8 +877,8 @@ static void ehci_reset(void *opaque)
         } else {
             s->portsc[i] = PORTSC_PPOWER;
         }
-        if (devs[i]) {
-            usb_attach(&s->ports[i], devs[i]);
+        if (devs[i] && devs[i]->attached) {
+            usb_attach(&s->ports[i]);
         }
     }
     ehci_queues_rip_all(s);
@@ -944,15 +944,15 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
         return;
     }
 
-    if (dev) {
-        usb_attach(&s->ports[port], NULL);
+    if (dev && dev->attached) {
+        usb_detach(&s->ports[port]);
     }
 
     *portsc &= ~PORTSC_POWNER;
     *portsc |= owner;
 
-    if (dev) {
-        usb_attach(&s->ports[port], dev);
+    if (dev && dev->attached) {
+        usb_attach(&s->ports[port]);
     }
 }
 
@@ -976,8 +976,8 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
 
     if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
         trace_usb_ehci_port_reset(port, 0);
-        if (dev) {
-            usb_attach(&s->ports[port], dev);
+        if (dev && dev->attached) {
+            usb_attach(&s->ports[port]);
             usb_send_msg(dev, USB_MSG_RESET);
             *portsc &= ~PORTSC_CSC;
         }
@@ -986,7 +986,7 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
          *  Table 2.16 Set the enable bit(and enable bit change) to indicate
          *  to SW that this port has a high speed device attached
          */
-        if (dev && (dev->speedmask & USB_SPEED_MASK_HIGH)) {
+        if (dev && dev->attached && (dev->speedmask & USB_SPEED_MASK_HIGH)) {
             val |= PORTSC_PED;
         }
     }
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index b49a2fe..a7a80f0 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -213,16 +213,6 @@ static void usb_hub_complete(USBPort *port, USBPacket *packet)
     usb_packet_complete(&s->dev, packet);
 }
 
-static void usb_hub_handle_attach(USBDevice *dev)
-{
-    USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
-    int i;
-
-    for (i = 0; i < NUM_PORTS; i++) {
-        usb_port_location(&s->ports[i].port, dev->port, i+1);
-    }
-}
-
 static void usb_hub_handle_reset(USBDevice *dev)
 {
     /* XXX: do it */
@@ -497,6 +487,7 @@ static int usb_hub_initfn(USBDevice *dev)
         usb_register_port(usb_bus_from_device(dev),
                           &port->port, s, i, &usb_hub_port_ops,
                           USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+        usb_port_location(&port->port, dev->port, i+1);
         port->wPortStatus = PORT_STAT_POWER;
         port->wPortChange = 0;
     }
@@ -535,7 +526,6 @@ static struct USBDeviceInfo hub_info = {
     .usb_desc       = &desc_hub,
     .init           = usb_hub_initfn,
     .handle_packet  = usb_hub_handle_packet,
-    .handle_attach  = usb_hub_handle_attach,
     .handle_reset   = usb_hub_handle_reset,
     .handle_control = usb_hub_handle_control,
     .handle_data    = usb_hub_handle_data,
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 8491d59..4dd2c1e 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -448,8 +448,8 @@ static void ohci_reset(void *opaque)
       {
         port = &ohci->rhport[i];
         port->ctrl = 0;
-        if (port->port.dev) {
-            usb_attach(&port->port, port->port.dev);
+        if (port->port.dev && port->port.dev->attached) {
+            usb_attach(&port->port);
         }
       }
     if (ohci->async_td) {
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index da74c57..b2647b0 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -338,8 +338,8 @@ static void uhci_reset(void *opaque)
     for(i = 0; i < NB_PORTS; i++) {
         port = &s->ports[i];
         port->ctrl = 0x0080;
-        if (port->port.dev) {
-            usb_attach(&port->port, port->port.dev);
+        if (port->port.dev && port->port.dev->attached) {
+            usb_attach(&port->port);
         }
     }
 
@@ -444,7 +444,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
             for(i = 0; i < NB_PORTS; i++) {
                 port = &s->ports[i];
                 dev = port->port.dev;
-                if (dev) {
+                if (dev && dev->attached) {
                     usb_send_msg(dev, USB_MSG_RESET);
                 }
             }
@@ -484,7 +484,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
                 return;
             port = &s->ports[n];
             dev = port->port.dev;
-            if (dev) {
+            if (dev && dev->attached) {
                 /* port reset */
                 if ( (val & UHCI_PORT_RESET) &&
                      !(port->ctrl & UHCI_PORT_RESET) ) {
@@ -658,8 +658,9 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
         UHCIPort *port = &s->ports[i];
         USBDevice *dev = port->port.dev;
 
-        if (dev && (port->ctrl & UHCI_PORT_EN))
+        if (dev && dev->attached && (port->ctrl & UHCI_PORT_EN)) {
             ret = usb_handle_packet(dev, p);
+        }
     }
 
     DPRINTF("uhci: packet exit. ret %d len %d\n", ret, p->len);
diff --git a/hw/usb.c b/hw/usb.c
index b44e997..b89a609 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -26,26 +26,23 @@
 #include "qemu-common.h"
 #include "usb.h"
 
-void usb_attach(USBPort *port, USBDevice *dev)
+void usb_attach(USBPort *port)
 {
-    if (dev != NULL) {
-        /* attach */
-        if (port->dev) {
-            usb_attach(port, NULL);
-        }
-        dev->port = port;
-        port->dev = dev;
-        port->ops->attach(port);
-        usb_send_msg(dev, USB_MSG_ATTACH);
-    } else {
-        /* detach */
-        dev = port->dev;
-        assert(dev);
-        port->ops->detach(port);
-        usb_send_msg(dev, USB_MSG_DETACH);
-        dev->port = NULL;
-        port->dev = NULL;
-    }
+    USBDevice *dev = port->dev;
+
+    assert(dev != NULL);
+    assert(dev->attached);
+    port->ops->attach(port);
+    usb_send_msg(dev, USB_MSG_ATTACH);
+}
+
+void usb_detach(USBPort *port)
+{
+    USBDevice *dev = port->dev;
+
+    assert(dev != NULL);
+    port->ops->detach(port);
+    usb_send_msg(dev, USB_MSG_DETACH);
 }
 
 void usb_wakeup(USBDevice *dev)
diff --git a/hw/usb.h b/hw/usb.h
index ded2de2..dfe4449 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -295,7 +295,8 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p);
 void usb_packet_complete(USBDevice *dev, USBPacket *p);
 void usb_cancel_packet(USBPacket * p);
 
-void usb_attach(USBPort *port, USBDevice *dev);
+void usb_attach(USBPort *port);
+void usb_detach(USBPort *port);
 void usb_wakeup(USBDevice *dev);
 int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
 void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
@@ -372,6 +373,8 @@ int usb_register_companion(const char *masterbus, USBPort *ports[],
                            void *opaque, USBPortOps *ops, int speedmask);
 void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr);
 void usb_unregister_port(USBBus *bus, USBPort *port);
+int usb_claim_port(USBDevice *dev);
+void usb_release_port(USBDevice *dev);
 int usb_device_attach(USBDevice *dev);
 int usb_device_detach(USBDevice *dev);
 int usb_device_delete_addr(int busnr, int addr);
diff --git a/trace-events b/trace-events
index e6f8c37..201cb49 100644
--- a/trace-events
+++ b/trace-events
@@ -209,6 +209,12 @@ disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "g
 disable sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x"
 disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
 
+# hw/usb-bus.c
+usb_port_claim(int bus, const char *port) "bus %d, port %s"
+usb_port_attach(int bus, const char *port) "bus %d, port %s"
+usb_port_detach(int bus, const char *port) "bus %d, port %s"
+usb_port_release(int bus, const char *port) "bus %d, port %s"
+
 # hw/usb-ehci.c
 disable usb_ehci_reset(void) "=== RESET ==="
 disable usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2011-09-02 10:01 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-09-02 10:01 [Qemu-devel] [STABLE PULL] usb bugfixes Gerd Hoffmann
2011-09-02 10:01 ` [Qemu-devel] [PATCH 1/7] usb-host: reapurb error report fix Gerd Hoffmann
2011-09-02 10:01 ` [Qemu-devel] [PATCH 2/7] usb-host: fix halted endpoints Gerd Hoffmann
2011-09-02 10:01 ` [Qemu-devel] [PATCH 3/7] usb-host: fix configuration tracking Gerd Hoffmann
2011-09-02 10:01 ` [Qemu-devel] [PATCH 4/7] usb-host: endpoint table fixup Gerd Hoffmann
2011-09-02 10:01 ` [Qemu-devel] [PATCH 5/7] usb-ehci: handle siTDs Gerd Hoffmann
2011-09-02 10:01 ` [Qemu-devel] [PATCH 6/7] usb: fix use after free Gerd Hoffmann
2011-09-02 10:01 ` [Qemu-devel] [PATCH 7/7] usb: claim port at device initialization time Gerd Hoffmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).