Add support for (re-)initializing endpoints which belong to a specific
interface only.  Use this in usb-host when changing altsetting for an
interface, so other interfaces are not disturbed.

Signed-off-by: Gerd Hoffmann <kra...@redhat.com>
---
 hw/usb.h            |    2 +-
 hw/usb/bus.c        |    2 +-
 hw/usb/core.c       |   48 +++++++++++++++++++++++++++---------------------
 hw/usb/desc.c       |    2 +-
 hw/usb/host-linux.c |   16 ++++++++--------
 hw/usb/redirect.c   |    2 +-
 6 files changed, 39 insertions(+), 33 deletions(-)

diff --git a/hw/usb.h b/hw/usb.h
index a5623d3..b6d7052 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -362,7 +362,7 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p);
 void usb_packet_complete(USBDevice *dev, USBPacket *p);
 void usb_cancel_packet(USBPacket * p);
 
-void usb_ep_init(USBDevice *dev);
+void usb_ep_init(USBDevice *dev, int interface);
 void usb_ep_dump(USBDevice *dev);
 struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep);
 uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep);
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index b649360..ad1daaf 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -190,7 +190,7 @@ static int usb_qdev_init(DeviceState *qdev)
             usb_device_get_product_desc(dev));
     dev->auto_attach = 1;
     QLIST_INIT(&dev->strings);
-    usb_ep_init(dev);
+    usb_ep_init(dev, 0);
     rc = usb_claim_port(dev);
     if (rc != 0) {
         return rc;
diff --git a/hw/usb/core.c b/hw/usb/core.c
index 0e02da7..94c3c1a 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -550,31 +550,37 @@ void usb_packet_cleanup(USBPacket *p)
     qemu_iovec_destroy(&p->iov);
 }
 
-void usb_ep_init(USBDevice *dev)
+void usb_ep_init(USBDevice *dev, int interface)
 {
     int ep;
 
-    dev->ep_ctl.nr = 0;
-    dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL;
-    dev->ep_ctl.ifnum = 0;
-    dev->ep_ctl.dev = dev;
-    dev->ep_ctl.pipeline = false;
-    QTAILQ_INIT(&dev->ep_ctl.queue);
+    if (interface == 0) {
+        dev->ep_ctl.nr = 0;
+        dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL;
+        dev->ep_ctl.ifnum = 0;
+        dev->ep_ctl.dev = dev;
+        dev->ep_ctl.pipeline = false;
+        QTAILQ_INIT(&dev->ep_ctl.queue);
+    }
     for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
-        dev->ep_in[ep].nr = ep + 1;
-        dev->ep_out[ep].nr = ep + 1;
-        dev->ep_in[ep].pid = USB_TOKEN_IN;
-        dev->ep_out[ep].pid = USB_TOKEN_OUT;
-        dev->ep_in[ep].type = USB_ENDPOINT_XFER_INVALID;
-        dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID;
-        dev->ep_in[ep].ifnum = 0;
-        dev->ep_out[ep].ifnum = 0;
-        dev->ep_in[ep].dev = dev;
-        dev->ep_out[ep].dev = dev;
-        dev->ep_in[ep].pipeline = false;
-        dev->ep_out[ep].pipeline = false;
-        QTAILQ_INIT(&dev->ep_in[ep].queue);
-        QTAILQ_INIT(&dev->ep_out[ep].queue);
+        if (interface == 0 || interface == dev->ep_in[ep].ifnum) {
+            dev->ep_in[ep].nr = ep + 1;
+            dev->ep_in[ep].pid = USB_TOKEN_IN;
+            dev->ep_in[ep].type = USB_ENDPOINT_XFER_INVALID;
+            dev->ep_in[ep].ifnum = 0;
+            dev->ep_in[ep].dev = dev;
+            dev->ep_in[ep].pipeline = false;
+            QTAILQ_INIT(&dev->ep_in[ep].queue);
+        }
+        if (interface == 0 || interface == dev->ep_out[ep].ifnum) {
+            dev->ep_out[ep].nr = ep + 1;
+            dev->ep_out[ep].pid = USB_TOKEN_OUT;
+            dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID;
+            dev->ep_out[ep].ifnum = 0;
+            dev->ep_out[ep].dev = dev;
+            dev->ep_out[ep].pipeline = false;
+            QTAILQ_INIT(&dev->ep_out[ep].queue);
+        }
     }
 }
 
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 0a9d3c9..f010755 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -246,7 +246,7 @@ static void usb_desc_ep_init(USBDevice *dev)
     const USBDescIface *iface;
     int i, e, pid, ep;
 
-    usb_ep_init(dev);
+    usb_ep_init(dev, 0);
     for (i = 0; i < dev->ninterfaces; i++) {
         iface = dev->ifaces[i];
         if (iface == NULL) {
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 5479fb5..8e5d1be 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -135,7 +135,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 int usb_linux_update_endp_table(USBHostDevice *s, int ifnum);
 
 static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p)
 {
@@ -648,7 +648,7 @@ static void usb_host_handle_reset(USBDevice *dev)
     usb_host_do_reset(s);;
 
     usb_host_claim_interfaces(s, 0);
-    usb_linux_update_endp_table(s);
+    usb_linux_update_endp_table(s, 0);
 }
 
 static void usb_host_handle_destroy(USBDevice *dev)
@@ -988,7 +988,7 @@ again:
         return ctrl_error();
     }
     usb_host_claim_interfaces(s, config);
-    usb_linux_update_endp_table(s);
+    usb_linux_update_endp_table(s, 0);
     return 0;
 }
 
@@ -1024,7 +1024,7 @@ static int usb_host_set_interface(USBHostDevice *s, int 
iface, int alt)
     }
 
     s->dev.altsetting[iface] = alt;
-    usb_linux_update_endp_table(s);
+    usb_linux_update_endp_table(s, iface);
     return 0;
 }
 
@@ -1120,7 +1120,7 @@ static int usb_host_handle_control(USBDevice *dev, 
USBPacket *p,
 }
 
 /* returns 1 on problem encountered or 0 for success */
-static int usb_linux_update_endp_table(USBHostDevice *s)
+static int usb_linux_update_endp_table(USBHostDevice *s, int ifnum)
 {
     static const char *tname[] = {
         [USB_ENDPOINT_XFER_CONTROL] = "control",
@@ -1136,7 +1136,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
     USBDescriptor *d;
     bool active = false;
 
-    usb_ep_init(&s->dev);
+    usb_ep_init(&s->dev, ifnum);
 
     for (i = 0;; i += d->bLength) {
         if (i+2 >= s->descr_len) {
@@ -1239,7 +1239,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
     return 0;
 
 error:
-    usb_ep_init(&s->dev);
+    usb_ep_init(&s->dev, 0);
     return 1;
 }
 
@@ -1326,7 +1326,7 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
         goto fail;
     }
 
-    ret = usb_linux_update_endp_table(dev);
+    ret = usb_linux_update_endp_table(dev, 0);
     if (ret) {
         goto fail;
     }
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index d949f04..4afa9c2 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -1136,7 +1136,7 @@ static void usbredir_device_disconnect(void *priv)
     for (i = 0; i < MAX_ENDPOINTS; i++) {
         QTAILQ_INIT(&dev->endpoint[i].bufpq);
     }
-    usb_ep_init(&dev->dev);
+    usb_ep_init(&dev->dev, 0);
     dev->interface_info.interface_count = NO_INTERFACE_INFO;
     dev->dev.addr = 0;
     dev->dev.speed = 0;
-- 
1.7.1


Reply via email to