qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 0/9] Usb 20190529 patches
@ 2019-05-29  6:28 Gerd Hoffmann
  2019-05-29  6:28 ` [Qemu-devel] [PULL 1/9] usb: call reset handler before updating state Gerd Hoffmann
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2019-05-29  6:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Eduardo Habkost, Gerd Hoffmann

The following changes since commit da35f7f1eeff9f249a9597400fc514c83fd3a0f8:

  virtio-gpu: add sanity check (2019-05-28 08:14:44 +0200)

are available in the Git repository at:

  git://git.kraxel.org/qemu tags/usb-20190529-pull-request

for you to fetch changes up to 442bac16a6cd708a9f87adb0a263f9d833f03ed5:

  usb-tablet: fix serial compat property (2019-05-29 07:10:02 +0200)

----------------------------------------------------------------
usb-hub: port count config option, emulate power switching, cleanups.
usb-tablet, usb-host: bugfixes.

----------------------------------------------------------------

Gerd Hoffmann (9):
  usb: call reset handler before updating state
  usb-host: skip reset for untouched devices
  usb-host: avoid libusb_set_configuration calls
  usb-hub: tweak feature names
  usb-hub: make number of ports runtime-configurable
  usb-hub: add helpers to update port state
  usb-hub: add usb_hub_port_update()
  usb-hub: emulate per port power switching
  usb-tablet: fix serial compat property

 hw/core/machine.c    |   2 +-
 hw/usb/core.c        |   2 +-
 hw/usb/dev-hub.c     | 221 ++++++++++++++++++++++++++++++-------------
 hw/usb/host-libusb.c |  21 ++--
 4 files changed, 169 insertions(+), 77 deletions(-)

-- 
2.18.1



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

* [Qemu-devel] [PULL 1/9] usb: call reset handler before updating state
  2019-05-29  6:28 [Qemu-devel] [PULL 0/9] Usb 20190529 patches Gerd Hoffmann
@ 2019-05-29  6:28 ` Gerd Hoffmann
  2019-05-29  6:28 ` [Qemu-devel] [PULL 2/9] usb-host: skip reset for untouched devices Gerd Hoffmann
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2019-05-29  6:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Eduardo Habkost, Gerd Hoffmann

That way the device reset handler can see what
the before-reset state of the device is.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20190522094702.17619-2-kraxel@redhat.com
---
 hw/usb/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/usb/core.c b/hw/usb/core.c
index 8fbd9c7d573b..3ab48a16074b 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -87,10 +87,10 @@ void usb_device_reset(USBDevice *dev)
     if (dev == NULL || !dev->attached) {
         return;
     }
+    usb_device_handle_reset(dev);
     dev->remote_wakeup = 0;
     dev->addr = 0;
     dev->state = USB_STATE_DEFAULT;
-    usb_device_handle_reset(dev);
 }
 
 void usb_wakeup(USBEndpoint *ep, unsigned int stream)
-- 
2.18.1



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

* [Qemu-devel] [PULL 2/9] usb-host: skip reset for untouched devices
  2019-05-29  6:28 [Qemu-devel] [PULL 0/9] Usb 20190529 patches Gerd Hoffmann
  2019-05-29  6:28 ` [Qemu-devel] [PULL 1/9] usb: call reset handler before updating state Gerd Hoffmann
@ 2019-05-29  6:28 ` Gerd Hoffmann
  2019-05-29  6:28 ` [Qemu-devel] [PULL 3/9] usb-host: avoid libusb_set_configuration calls Gerd Hoffmann
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2019-05-29  6:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Eduardo Habkost, Gerd Hoffmann

If the guest didn't talk to the device yet, skip the reset.
Without this usb-host devices get resetted a number of times
at boot time for no good reason.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20190522094702.17619-3-kraxel@redhat.com
---
 hw/usb/host-libusb.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index 67b7465915f5..4e9a45a5d26f 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -1459,6 +1459,9 @@ static void usb_host_handle_reset(USBDevice *udev)
     if (!s->allow_guest_reset) {
         return;
     }
+    if (udev->addr == 0) {
+        return;
+    }
 
     trace_usb_host_reset(s->bus_num, s->addr);
 
-- 
2.18.1



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

* [Qemu-devel] [PULL 3/9] usb-host: avoid libusb_set_configuration calls
  2019-05-29  6:28 [Qemu-devel] [PULL 0/9] Usb 20190529 patches Gerd Hoffmann
  2019-05-29  6:28 ` [Qemu-devel] [PULL 1/9] usb: call reset handler before updating state Gerd Hoffmann
  2019-05-29  6:28 ` [Qemu-devel] [PULL 2/9] usb-host: skip reset for untouched devices Gerd Hoffmann
@ 2019-05-29  6:28 ` Gerd Hoffmann
  2019-05-29  6:28 ` [Qemu-devel] [PULL 4/9] usb-hub: tweak feature names Gerd Hoffmann
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2019-05-29  6:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Eduardo Habkost, Gerd Hoffmann

Seems some devices become confused when we call
libusb_set_configuration().  So before calling the function check
whenever the device has multiple configurations in the first place, and
in case it hasn't (which is the case for the majority of devices) simply
skip the call as it will have no effect anyway.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20190522094702.17619-4-kraxel@redhat.com
---
 hw/usb/host-libusb.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index 4e9a45a5d26f..4f765d7f9a2f 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -1225,19 +1225,21 @@ static void usb_host_set_address(USBHostDevice *s, int addr)
 
 static void usb_host_set_config(USBHostDevice *s, int config, USBPacket *p)
 {
-    int rc;
+    int rc = 0;
 
     trace_usb_host_set_config(s->bus_num, s->addr, config);
 
     usb_host_release_interfaces(s);
-    rc = libusb_set_configuration(s->dh, config);
-    if (rc != 0) {
-        usb_host_libusb_error("libusb_set_configuration", rc);
-        p->status = USB_RET_STALL;
-        if (rc == LIBUSB_ERROR_NO_DEVICE) {
-            usb_host_nodev(s);
+    if (s->ddesc.bNumConfigurations != 1) {
+        rc = libusb_set_configuration(s->dh, config);
+        if (rc != 0) {
+            usb_host_libusb_error("libusb_set_configuration", rc);
+            p->status = USB_RET_STALL;
+            if (rc == LIBUSB_ERROR_NO_DEVICE) {
+                usb_host_nodev(s);
+            }
+            return;
         }
-        return;
     }
     p->status = usb_host_claim_interfaces(s, config);
     if (p->status != USB_RET_SUCCESS) {
-- 
2.18.1



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

* [Qemu-devel] [PULL 4/9] usb-hub: tweak feature names
  2019-05-29  6:28 [Qemu-devel] [PULL 0/9] Usb 20190529 patches Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2019-05-29  6:28 ` [Qemu-devel] [PULL 3/9] usb-host: avoid libusb_set_configuration calls Gerd Hoffmann
@ 2019-05-29  6:28 ` Gerd Hoffmann
  2019-05-29  6:28 ` [Qemu-devel] [PULL 5/9] usb-hub: make number of ports runtime-configurable Gerd Hoffmann
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2019-05-29  6:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Eduardo Habkost, Gerd Hoffmann

Add dashes, so they don't look like two separate things when printed.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20190524070310.4952-2-kraxel@redhat.com
---
 hw/usb/dev-hub.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 7e9339b8a83d..9b04b6a6ec2d 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -287,11 +287,11 @@ static const char *feature_name(int feature)
         [PORT_POWER]         = "power",
         [PORT_LOWSPEED]      = "lowspeed",
         [PORT_HIGHSPEED]     = "highspeed",
-        [PORT_C_CONNECTION]  = "change connection",
-        [PORT_C_ENABLE]      = "change enable",
-        [PORT_C_SUSPEND]     = "change suspend",
-        [PORT_C_OVERCURRENT] = "change overcurrent",
-        [PORT_C_RESET]       = "change reset",
+        [PORT_C_CONNECTION]  = "change-connection",
+        [PORT_C_ENABLE]      = "change-enable",
+        [PORT_C_SUSPEND]     = "change-suspend",
+        [PORT_C_OVERCURRENT] = "change-overcurrent",
+        [PORT_C_RESET]       = "change-reset",
         [PORT_TEST]          = "test",
         [PORT_INDICATOR]     = "indicator",
     };
-- 
2.18.1



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

* [Qemu-devel] [PULL 5/9] usb-hub: make number of ports runtime-configurable
  2019-05-29  6:28 [Qemu-devel] [PULL 0/9] Usb 20190529 patches Gerd Hoffmann
                   ` (3 preceding siblings ...)
  2019-05-29  6:28 ` [Qemu-devel] [PULL 4/9] usb-hub: tweak feature names Gerd Hoffmann
@ 2019-05-29  6:28 ` Gerd Hoffmann
  2019-05-29  6:28 ` [Qemu-devel] [PULL 6/9] usb-hub: add helpers to update port state Gerd Hoffmann
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2019-05-29  6:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Eduardo Habkost, Gerd Hoffmann

Add num_ports property which allows configure the number of downstream
ports.  Valid range is 1-8, default is 8.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20190524070310.4952-3-kraxel@redhat.com
---
 hw/usb/dev-hub.c | 45 +++++++++++++++++++++++++++++----------------
 1 file changed, 29 insertions(+), 16 deletions(-)

diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 9b04b6a6ec2d..4f700c8f92b5 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -29,7 +29,7 @@
 #include "desc.h"
 #include "qemu/error-report.h"
 
-#define NUM_PORTS 8
+#define MAX_PORTS 8
 
 typedef struct USBHubPort {
     USBPort port;
@@ -40,7 +40,8 @@ typedef struct USBHubPort {
 typedef struct USBHubState {
     USBDevice dev;
     USBEndpoint *intr;
-    USBHubPort ports[NUM_PORTS];
+    uint32_t num_ports;
+    USBHubPort ports[MAX_PORTS];
 } USBHubState;
 
 #define TYPE_USB_HUB "usb-hub"
@@ -109,7 +110,7 @@ static const USBDescIface desc_iface_hub = {
         {
             .bEndpointAddress      = USB_DIR_IN | 0x01,
             .bmAttributes          = USB_ENDPOINT_XFER_INT,
-            .wMaxPacketSize        = 1 + DIV_ROUND_UP(NUM_PORTS, 8),
+            .wMaxPacketSize        = 1 + DIV_ROUND_UP(MAX_PORTS, 8),
             .bInterval             = 0xff,
         },
     }
@@ -242,7 +243,7 @@ static USBDevice *usb_hub_find_device(USBDevice *dev, uint8_t addr)
     USBDevice *downstream;
     int i;
 
-    for (i = 0; i < NUM_PORTS; i++) {
+    for (i = 0; i < s->num_ports; i++) {
         port = &s->ports[i];
         if (!(port->wPortStatus & PORT_STAT_ENABLE)) {
             continue;
@@ -262,7 +263,7 @@ static void usb_hub_handle_reset(USBDevice *dev)
     int i;
 
     trace_usb_hub_reset(s->dev.addr);
-    for (i = 0; i < NUM_PORTS; i++) {
+    for (i = 0; i < s->num_ports; i++) {
         port = s->ports + i;
         port->wPortStatus = PORT_STAT_POWER;
         port->wPortChange = 0;
@@ -332,7 +333,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
         {
             unsigned int n = index - 1;
             USBHubPort *port;
-            if (n >= NUM_PORTS) {
+            if (n >= s->num_ports) {
                 goto fail;
             }
             port = &s->ports[n];
@@ -361,7 +362,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
             trace_usb_hub_set_port_feature(s->dev.addr, index,
                                            feature_name(value));
 
-            if (n >= NUM_PORTS) {
+            if (n >= s->num_ports) {
                 goto fail;
             }
             port = &s->ports[n];
@@ -394,7 +395,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
             trace_usb_hub_clear_port_feature(s->dev.addr, index,
                                              feature_name(value));
 
-            if (n >= NUM_PORTS) {
+            if (n >= s->num_ports) {
                 goto fail;
             }
             port = &s->ports[n];
@@ -443,17 +444,17 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
             unsigned int n, limit, var_hub_size = 0;
             memcpy(data, qemu_hub_hub_descriptor,
                    sizeof(qemu_hub_hub_descriptor));
-            data[2] = NUM_PORTS;
+            data[2] = s->num_ports;
 
             /* fill DeviceRemovable bits */
-            limit = DIV_ROUND_UP(NUM_PORTS + 1, 8) + 7;
+            limit = DIV_ROUND_UP(s->num_ports + 1, 8) + 7;
             for (n = 7; n < limit; n++) {
                 data[n] = 0x00;
                 var_hub_size++;
             }
 
             /* fill PortPwrCtrlMask bits */
-            limit = limit + DIV_ROUND_UP(NUM_PORTS, 8);
+            limit = limit + DIV_ROUND_UP(s->num_ports, 8);
             for (;n < limit; n++) {
                 data[n] = 0xff;
                 var_hub_size++;
@@ -481,7 +482,7 @@ static void usb_hub_handle_data(USBDevice *dev, USBPacket *p)
             unsigned int status;
             uint8_t buf[4];
             int i, n;
-            n = DIV_ROUND_UP(NUM_PORTS + 1, 8);
+            n = DIV_ROUND_UP(s->num_ports + 1, 8);
             if (p->iov.size == 1) { /* FreeBSD workaround */
                 n = 1;
             } else if (n > p->iov.size) {
@@ -489,7 +490,7 @@ static void usb_hub_handle_data(USBDevice *dev, USBPacket *p)
                 return;
             }
             status = 0;
-            for(i = 0; i < NUM_PORTS; i++) {
+            for (i = 0; i < s->num_ports; i++) {
                 port = &s->ports[i];
                 if (port->wPortChange)
                     status |= (1 << (i + 1));
@@ -520,7 +521,7 @@ static void usb_hub_unrealize(USBDevice *dev, Error **errp)
     USBHubState *s = (USBHubState *)dev;
     int i;
 
-    for (i = 0; i < NUM_PORTS; i++) {
+    for (i = 0; i < s->num_ports; i++) {
         usb_unregister_port(usb_bus_from_device(dev),
                             &s->ports[i].port);
     }
@@ -540,6 +541,12 @@ static void usb_hub_realize(USBDevice *dev, Error **errp)
     USBHubPort *port;
     int i;
 
+    if (s->num_ports < 1 || s->num_ports > MAX_PORTS) {
+        error_setg(errp, "num_ports (%d) out of range (1..%d)",
+                   s->num_ports, MAX_PORTS);
+        return;
+    }
+
     if (dev->port->hubcount == 5) {
         error_setg(errp, "usb hub chain too deep");
         return;
@@ -548,7 +555,7 @@ static void usb_hub_realize(USBDevice *dev, Error **errp)
     usb_desc_create_serial(dev);
     usb_desc_init(dev);
     s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
-    for (i = 0; i < NUM_PORTS; i++) {
+    for (i = 0; i < s->num_ports; i++) {
         port = &s->ports[i];
         usb_register_port(usb_bus_from_device(dev),
                           &port->port, s, i, &usb_hub_port_ops,
@@ -575,12 +582,17 @@ static const VMStateDescription vmstate_usb_hub = {
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
         VMSTATE_USB_DEVICE(dev, USBHubState),
-        VMSTATE_STRUCT_ARRAY(ports, USBHubState, NUM_PORTS, 0,
+        VMSTATE_STRUCT_ARRAY(ports, USBHubState, MAX_PORTS, 0,
                              vmstate_usb_hub_port, USBHubPort),
         VMSTATE_END_OF_LIST()
     }
 };
 
+static Property usb_hub_properties[] = {
+    DEFINE_PROP_UINT32("ports", USBHubState, num_ports, 8),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static void usb_hub_class_initfn(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -597,6 +609,7 @@ static void usb_hub_class_initfn(ObjectClass *klass, void *data)
     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
     dc->fw_name = "hub";
     dc->vmsd = &vmstate_usb_hub;
+    dc->props = usb_hub_properties;
 }
 
 static const TypeInfo hub_info = {
-- 
2.18.1



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

* [Qemu-devel] [PULL 6/9] usb-hub: add helpers to update port state
  2019-05-29  6:28 [Qemu-devel] [PULL 0/9] Usb 20190529 patches Gerd Hoffmann
                   ` (4 preceding siblings ...)
  2019-05-29  6:28 ` [Qemu-devel] [PULL 5/9] usb-hub: make number of ports runtime-configurable Gerd Hoffmann
@ 2019-05-29  6:28 ` Gerd Hoffmann
  2019-05-29  6:28 ` [Qemu-devel] [PULL 7/9] usb-hub: add usb_hub_port_update() Gerd Hoffmann
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2019-05-29  6:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Eduardo Habkost, Gerd Hoffmann

Add usb_hub_port_set() and usb_hub_port_clear() helpers which care about
updating the change bits (port->wPortChange) properly, so we don't need
to have that logic sprinkled all over the place ;)

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20190524070310.4952-4-kraxel@redhat.com
---
 hw/usb/dev-hub.c | 84 ++++++++++++++++++++++++++----------------------
 1 file changed, 45 insertions(+), 39 deletions(-)

diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 4f700c8f92b5..1cc92a5f9abe 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -159,18 +159,46 @@ static const uint8_t qemu_hub_hub_descriptor[] =
         /* DeviceRemovable and PortPwrCtrlMask patched in later */
 };
 
+static bool usb_hub_port_change(USBHubPort *port, uint16_t status)
+{
+    bool notify = false;
+
+    if (status & 0x1f) {
+        port->wPortChange |= status;
+        notify = true;
+    }
+    return notify;
+}
+
+static bool usb_hub_port_set(USBHubPort *port, uint16_t status)
+{
+    if (port->wPortStatus & status) {
+        return false;
+    }
+    port->wPortStatus |= status;
+    return usb_hub_port_change(port, status);
+}
+
+static bool usb_hub_port_clear(USBHubPort *port, uint16_t status)
+{
+    if (!(port->wPortStatus & status)) {
+        return false;
+    }
+    port->wPortStatus &= ~status;
+    return usb_hub_port_change(port, status);
+}
+
 static void usb_hub_attach(USBPort *port1)
 {
     USBHubState *s = port1->opaque;
     USBHubPort *port = &s->ports[port1->index];
 
     trace_usb_hub_attach(s->dev.addr, port1->index + 1);
-    port->wPortStatus |= PORT_STAT_CONNECTION;
-    port->wPortChange |= PORT_STAT_C_CONNECTION;
+    usb_hub_port_set(port, PORT_STAT_CONNECTION);
     if (port->port.dev->speed == USB_SPEED_LOW) {
-        port->wPortStatus |= PORT_STAT_LOW_SPEED;
+        usb_hub_port_set(port, PORT_STAT_LOW_SPEED);
     } else {
-        port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
+        usb_hub_port_clear(port, PORT_STAT_LOW_SPEED);
     }
     usb_wakeup(s->intr, 0);
 }
@@ -186,16 +214,9 @@ static void usb_hub_detach(USBPort *port1)
     /* Let upstream know the device on this port is gone */
     s->dev.port->ops->child_detach(s->dev.port, port1->dev);
 
-    port->wPortStatus &= ~PORT_STAT_CONNECTION;
-    port->wPortChange |= PORT_STAT_C_CONNECTION;
-    if (port->wPortStatus & PORT_STAT_ENABLE) {
-        port->wPortStatus &= ~PORT_STAT_ENABLE;
-        port->wPortChange |= PORT_STAT_C_ENABLE;
-    }
-    if (port->wPortStatus & PORT_STAT_SUSPEND) {
-        port->wPortStatus &= ~PORT_STAT_SUSPEND;
-        port->wPortChange |= PORT_STAT_C_SUSPEND;
-    }
+    usb_hub_port_clear(port, PORT_STAT_CONNECTION);
+    usb_hub_port_clear(port, PORT_STAT_ENABLE);
+    usb_hub_port_clear(port, PORT_STAT_SUSPEND);
     usb_wakeup(s->intr, 0);
 }
 
@@ -212,9 +233,7 @@ static void usb_hub_wakeup(USBPort *port1)
     USBHubState *s = port1->opaque;
     USBHubPort *port = &s->ports[port1->index];
 
-    if (port->wPortStatus & PORT_STAT_SUSPEND) {
-        port->wPortStatus &= ~PORT_STAT_SUSPEND;
-        port->wPortChange |= PORT_STAT_C_SUSPEND;
+    if (usb_hub_port_clear(port, PORT_STAT_SUSPEND)) {
         usb_wakeup(s->intr, 0);
     }
 }
@@ -265,13 +284,13 @@ static void usb_hub_handle_reset(USBDevice *dev)
     trace_usb_hub_reset(s->dev.addr);
     for (i = 0; i < s->num_ports; i++) {
         port = s->ports + i;
-        port->wPortStatus = PORT_STAT_POWER;
+        port->wPortStatus = 0;
         port->wPortChange = 0;
+        usb_hub_port_set(port, PORT_STAT_POWER);
         if (port->port.dev && port->port.dev->attached) {
-            port->wPortStatus |= PORT_STAT_CONNECTION;
-            port->wPortChange |= PORT_STAT_C_CONNECTION;
+            usb_hub_port_set(port, PORT_STAT_CONNECTION);
             if (port->port.dev->speed == USB_SPEED_LOW) {
-                port->wPortStatus |= PORT_STAT_LOW_SPEED;
+                usb_hub_port_set(port, PORT_STAT_LOW_SPEED);
             }
         }
     }
@@ -372,13 +391,13 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
                 port->wPortStatus |= PORT_STAT_SUSPEND;
                 break;
             case PORT_RESET:
+                usb_hub_port_set(port, PORT_STAT_RESET);
+                usb_hub_port_clear(port, PORT_STAT_RESET);
                 if (dev && dev->attached) {
                     usb_device_reset(dev);
-                    port->wPortChange |= PORT_STAT_C_RESET;
-                    /* set enable bit */
-                    port->wPortStatus |= PORT_STAT_ENABLE;
-                    usb_wakeup(s->intr, 0);
+                    usb_hub_port_set(port, PORT_STAT_ENABLE);
                 }
+                usb_wakeup(s->intr, 0);
                 break;
             case PORT_POWER:
                 break;
@@ -407,20 +426,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
                 port->wPortChange &= ~PORT_STAT_C_ENABLE;
                 break;
             case PORT_SUSPEND:
-                if (port->wPortStatus & PORT_STAT_SUSPEND) {
-                    port->wPortStatus &= ~PORT_STAT_SUSPEND;
-
-                    /*
-                     * USB Spec rev2.0 11.24.2.7.2.3 C_PORT_SUSPEND
-                     * "This bit is set on the following transitions:
-                     *  - On transition from the Resuming state to the
-                     *    SendEOP [sic] state"
-                     *
-                     * Note that this includes both remote wake-up and
-                     * explicit ClearPortFeature(PORT_SUSPEND).
-                     */
-                    port->wPortChange |= PORT_STAT_C_SUSPEND;
-                }
+                usb_hub_port_clear(port, PORT_STAT_SUSPEND);
                 break;
             case PORT_C_SUSPEND:
                 port->wPortChange &= ~PORT_STAT_C_SUSPEND;
-- 
2.18.1



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

* [Qemu-devel] [PULL 7/9] usb-hub: add usb_hub_port_update()
  2019-05-29  6:28 [Qemu-devel] [PULL 0/9] Usb 20190529 patches Gerd Hoffmann
                   ` (5 preceding siblings ...)
  2019-05-29  6:28 ` [Qemu-devel] [PULL 6/9] usb-hub: add helpers to update port state Gerd Hoffmann
@ 2019-05-29  6:28 ` Gerd Hoffmann
  2019-05-29  6:28 ` [Qemu-devel] [PULL 8/9] usb-hub: emulate per port power switching Gerd Hoffmann
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2019-05-29  6:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Eduardo Habkost, Gerd Hoffmann

Helper function to update port status bits which depends on the
connected device.  We need the same logic for device attach and
port reset, so factor it out.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20190524070310.4952-5-kraxel@redhat.com
---
 hw/usb/dev-hub.c | 29 +++++++++++++++++------------
 1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 1cc92a5f9abe..29f4d6723e26 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -188,18 +188,28 @@ static bool usb_hub_port_clear(USBHubPort *port, uint16_t status)
     return usb_hub_port_change(port, status);
 }
 
+static bool usb_hub_port_update(USBHubPort *port)
+{
+    bool notify = false;
+
+    if (port->port.dev && port->port.dev->attached) {
+        notify = usb_hub_port_set(port, PORT_STAT_CONNECTION);
+        if (port->port.dev->speed == USB_SPEED_LOW) {
+            usb_hub_port_set(port, PORT_STAT_LOW_SPEED);
+        } else {
+            usb_hub_port_clear(port, PORT_STAT_LOW_SPEED);
+        }
+    }
+    return notify;
+}
+
 static void usb_hub_attach(USBPort *port1)
 {
     USBHubState *s = port1->opaque;
     USBHubPort *port = &s->ports[port1->index];
 
     trace_usb_hub_attach(s->dev.addr, port1->index + 1);
-    usb_hub_port_set(port, PORT_STAT_CONNECTION);
-    if (port->port.dev->speed == USB_SPEED_LOW) {
-        usb_hub_port_set(port, PORT_STAT_LOW_SPEED);
-    } else {
-        usb_hub_port_clear(port, PORT_STAT_LOW_SPEED);
-    }
+    usb_hub_port_update(port);
     usb_wakeup(s->intr, 0);
 }
 
@@ -287,12 +297,7 @@ static void usb_hub_handle_reset(USBDevice *dev)
         port->wPortStatus = 0;
         port->wPortChange = 0;
         usb_hub_port_set(port, PORT_STAT_POWER);
-        if (port->port.dev && port->port.dev->attached) {
-            usb_hub_port_set(port, PORT_STAT_CONNECTION);
-            if (port->port.dev->speed == USB_SPEED_LOW) {
-                usb_hub_port_set(port, PORT_STAT_LOW_SPEED);
-            }
-        }
+        usb_hub_port_update(port);
     }
 }
 
-- 
2.18.1



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

* [Qemu-devel] [PULL 8/9] usb-hub: emulate per port power switching
  2019-05-29  6:28 [Qemu-devel] [PULL 0/9] Usb 20190529 patches Gerd Hoffmann
                   ` (6 preceding siblings ...)
  2019-05-29  6:28 ` [Qemu-devel] [PULL 7/9] usb-hub: add usb_hub_port_update() Gerd Hoffmann
@ 2019-05-29  6:28 ` Gerd Hoffmann
  2019-05-29  6:28 ` [Qemu-devel] [PULL 9/9] usb-tablet: fix serial compat property Gerd Hoffmann
  2019-05-30 14:07 ` [Qemu-devel] [PULL 0/9] Usb 20190529 patches Peter Maydell
  9 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2019-05-29  6:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Eduardo Habkost, Gerd Hoffmann

Add support for per port power switching.
Virtual power of course ;)

Use port-power=on property to enable this.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20190524070310.4952-6-kraxel@redhat.com
---
 hw/usb/dev-hub.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index 29f4d6723e26..2b64d6ef0349 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -24,6 +24,7 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "qemu-common.h"
+#include "qemu/timer.h"
 #include "trace.h"
 #include "hw/usb.h"
 #include "desc.h"
@@ -41,6 +42,8 @@ typedef struct USBHubState {
     USBDevice dev;
     USBEndpoint *intr;
     uint32_t num_ports;
+    bool port_power;
+    QEMUTimer *port_timer;
     USBHubPort ports[MAX_PORTS];
 } USBHubState;
 
@@ -203,6 +206,20 @@ static bool usb_hub_port_update(USBHubPort *port)
     return notify;
 }
 
+static void usb_hub_port_update_timer(void *opaque)
+{
+    USBHubState *s = opaque;
+    bool notify = false;
+    int i;
+
+    for (i = 0; i < s->num_ports; i++) {
+        notify |= usb_hub_port_update(&s->ports[i]);
+    }
+    if (notify) {
+        usb_wakeup(s->intr, 0);
+    }
+}
+
 static void usb_hub_attach(USBPort *port1)
 {
     USBHubState *s = port1->opaque;
@@ -405,6 +422,11 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
                 usb_wakeup(s->intr, 0);
                 break;
             case PORT_POWER:
+                if (s->port_power) {
+                    int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+                    usb_hub_port_set(port, PORT_STAT_POWER);
+                    timer_mod(s->port_timer, now + 5000000); /* 5 ms */
+                }
                 break;
             default:
                 goto fail;
@@ -445,6 +467,14 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
             case PORT_C_RESET:
                 port->wPortChange &= ~PORT_STAT_C_RESET;
                 break;
+            case PORT_POWER:
+                if (s->port_power) {
+                    usb_hub_port_clear(port, PORT_STAT_POWER);
+                    usb_hub_port_clear(port, PORT_STAT_CONNECTION);
+                    usb_hub_port_clear(port, PORT_STAT_ENABLE);
+                    usb_hub_port_clear(port, PORT_STAT_SUSPEND);
+                    port->wPortChange = 0;
+                }
             default:
                 goto fail;
             }
@@ -457,6 +487,11 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p,
                    sizeof(qemu_hub_hub_descriptor));
             data[2] = s->num_ports;
 
+            if (s->port_power) {
+                data[3] &= ~0x03;
+                data[3] |= 0x01;
+            }
+
             /* fill DeviceRemovable bits */
             limit = DIV_ROUND_UP(s->num_ports + 1, 8) + 7;
             for (n = 7; n < limit; n++) {
@@ -536,6 +571,9 @@ static void usb_hub_unrealize(USBDevice *dev, Error **errp)
         usb_unregister_port(usb_bus_from_device(dev),
                             &s->ports[i].port);
     }
+
+    timer_del(s->port_timer);
+    timer_free(s->port_timer);
 }
 
 static USBPortOps usb_hub_port_ops = {
@@ -565,6 +603,8 @@ static void usb_hub_realize(USBDevice *dev, Error **errp)
 
     usb_desc_create_serial(dev);
     usb_desc_init(dev);
+    s->port_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                 usb_hub_port_update_timer, s);
     s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
     for (i = 0; i < s->num_ports; i++) {
         port = &s->ports[i];
@@ -587,6 +627,24 @@ static const VMStateDescription vmstate_usb_hub_port = {
     }
 };
 
+static bool usb_hub_port_timer_needed(void *opaque)
+{
+    USBHubState *s = opaque;
+
+    return s->port_power;
+}
+
+static const VMStateDescription vmstate_usb_hub_port_timer = {
+    .name = "usb-hub/port-timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = usb_hub_port_timer_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_TIMER_PTR(port_timer, USBHubState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
 static const VMStateDescription vmstate_usb_hub = {
     .name = "usb-hub",
     .version_id = 1,
@@ -596,11 +654,16 @@ static const VMStateDescription vmstate_usb_hub = {
         VMSTATE_STRUCT_ARRAY(ports, USBHubState, MAX_PORTS, 0,
                              vmstate_usb_hub_port, USBHubPort),
         VMSTATE_END_OF_LIST()
+    },
+    .subsections = (const VMStateDescription * []) {
+        &vmstate_usb_hub_port_timer,
+        NULL
     }
 };
 
 static Property usb_hub_properties[] = {
     DEFINE_PROP_UINT32("ports", USBHubState, num_ports, 8),
+    DEFINE_PROP_BOOL("port-power", USBHubState, port_power, false),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-- 
2.18.1



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

* [Qemu-devel] [PULL 9/9] usb-tablet: fix serial compat property
  2019-05-29  6:28 [Qemu-devel] [PULL 0/9] Usb 20190529 patches Gerd Hoffmann
                   ` (7 preceding siblings ...)
  2019-05-29  6:28 ` [Qemu-devel] [PULL 8/9] usb-hub: emulate per port power switching Gerd Hoffmann
@ 2019-05-29  6:28 ` Gerd Hoffmann
  2019-05-30 14:07 ` [Qemu-devel] [PULL 0/9] Usb 20190529 patches Peter Maydell
  9 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2019-05-29  6:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Eduardo Habkost, Gerd Hoffmann

s/kbd/tablet/, fixes cut+paste bug.

Cc: qemu-stable@nongnu.org
Reported-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20190520081805.15019-1-kraxel@redhat.com
---
 hw/core/machine.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/core/machine.c b/hw/core/machine.c
index 934c1bcceb46..16ba66743441 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -36,7 +36,7 @@ GlobalProperty hw_compat_3_1[] = {
     { "tpm-tis", "ppi", "false" },
     { "usb-kbd", "serial", "42" },
     { "usb-mouse", "serial", "42" },
-    { "usb-kbd", "serial", "42" },
+    { "usb-tablet", "serial", "42" },
     { "virtio-blk-device", "discard", "false" },
     { "virtio-blk-device", "write-zeroes", "false" },
 };
-- 
2.18.1



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

* Re: [Qemu-devel] [PULL 0/9] Usb 20190529 patches
  2019-05-29  6:28 [Qemu-devel] [PULL 0/9] Usb 20190529 patches Gerd Hoffmann
                   ` (8 preceding siblings ...)
  2019-05-29  6:28 ` [Qemu-devel] [PULL 9/9] usb-tablet: fix serial compat property Gerd Hoffmann
@ 2019-05-30 14:07 ` Peter Maydell
  9 siblings, 0 replies; 11+ messages in thread
From: Peter Maydell @ 2019-05-30 14:07 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: QEMU Developers, Eduardo Habkost

On Wed, 29 May 2019 at 07:33, Gerd Hoffmann <kraxel@redhat.com> wrote:
>
> The following changes since commit da35f7f1eeff9f249a9597400fc514c83fd3a0f8:
>
>   virtio-gpu: add sanity check (2019-05-28 08:14:44 +0200)
>
> are available in the Git repository at:
>
>   git://git.kraxel.org/qemu tags/usb-20190529-pull-request
>
> for you to fetch changes up to 442bac16a6cd708a9f87adb0a263f9d833f03ed5:
>
>   usb-tablet: fix serial compat property (2019-05-29 07:10:02 +0200)
>
> ----------------------------------------------------------------
> usb-hub: port count config option, emulate power switching, cleanups.
> usb-tablet, usb-host: bugfixes.
>
> ----------------------------------------------------------------
>


Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/4.1
for any user-visible changes.

-- PMM


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

end of thread, other threads:[~2019-05-30 14:09 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-29  6:28 [Qemu-devel] [PULL 0/9] Usb 20190529 patches Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 1/9] usb: call reset handler before updating state Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 2/9] usb-host: skip reset for untouched devices Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 3/9] usb-host: avoid libusb_set_configuration calls Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 4/9] usb-hub: tweak feature names Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 5/9] usb-hub: make number of ports runtime-configurable Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 6/9] usb-hub: add helpers to update port state Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 7/9] usb-hub: add usb_hub_port_update() Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 8/9] usb-hub: emulate per port power switching Gerd Hoffmann
2019-05-29  6:28 ` [Qemu-devel] [PULL 9/9] usb-tablet: fix serial compat property Gerd Hoffmann
2019-05-30 14:07 ` [Qemu-devel] [PULL 0/9] Usb 20190529 patches Peter Maydell

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).