diff mbox series

[1/2] usb-host: remove 'remote wakeup' flag from configuration descriptor

Message ID 20191202123430.7125-2-yuri.benditovich@daynix.com (mailing list archive)
State New, archived
Headers show
Series Remove 'remote wakeup' flag from USB config descriptor | expand

Commit Message

Yuri Benditovich Dec. 2, 2019, 12:34 p.m. UTC
If the redirected device has this capability, Windows guest may
place the device into D2 and expect it to wake when the device
becomes active, but this will never happen. For example, when
internal Bluetooth adapter is redirected, keyboards and mice
connected to it do not work. Current commit removes this
capability (starting from machine 4.2)
Set 'usb-host.suppress-remote-wake' property to 'off' to keep
'remote wake' as is or to 'on' to remove 'remote wake' on
4.1 or earlier.

Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
---
 hw/core/machine.c    |  1 +
 hw/usb/host-libusb.c | 18 ++++++++++++++++++
 hw/usb/trace-events  |  1 +
 3 files changed, 20 insertions(+)

Comments

Gerd Hoffmann Dec. 3, 2019, 10:48 a.m. UTC | #1
Hi,

> +        /* If this is GET_DESCRIPTOR request for configuration descriptor,
> +         * remove 'remote wakeup' flag from it to prevent idle power down
> +         * in Windows guest */

scripts/checkpatch.pl complains about that, please fix (and also the
other checkpatch warnings).

> +        if (s->suppress_remote_wake &&
> +            udev->setup_buf[0] == USB_DIR_IN &&
> +            udev->setup_buf[1] == USB_REQ_GET_DESCRIPTOR &&
> +            udev->setup_buf[3] == USB_DT_CONFIG && udev->setup_buf[2] == 0 &&
> +            xfer->actual_length > offsetof(struct libusb_config_descriptor, bmAttributes) &&
> +            (conf->bmAttributes & USB_CFG_ATT_WAKEUP)) {
> +                struct libusb_device_descriptor desc;
> +                libusb_get_device_descriptor(s->dev, &desc);
> +                trace_usb_host_remote_wakeup_removed(desc.idVendor, desc.idProduct);

Please use s->bus_num and s->addr to identify the device, like all the
other trace points do.  I don't think there is a need to log
desc.idVendor and desc.idProduct here.


Otherwise the patch looks fine.

cheers,
  Gerd
diff mbox series

Patch

diff --git a/hw/core/machine.c b/hw/core/machine.c
index 1689ad3bf8..8c0eaad091 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -29,6 +29,7 @@ 
 
 GlobalProperty hw_compat_4_1[] = {
     { "virtio-pci", "x-pcie-flr-init", "off" },
+    { "usb-host", "suppress-remote-wake", "off" },
 };
 const size_t hw_compat_4_1_len = G_N_ELEMENTS(hw_compat_4_1);
 
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index fcf48c0193..77c2720ec6 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -88,6 +88,7 @@  struct USBHostDevice {
     bool                             needs_autoscan;
     bool                             allow_one_guest_reset;
     bool                             allow_all_guest_resets;
+    bool                             suppress_remote_wake;
 
     /* state */
     QTAILQ_ENTRY(USBHostDevice)      next;
@@ -386,6 +387,8 @@  static void LIBUSB_CALL usb_host_req_complete_ctrl(struct libusb_transfer *xfer)
     r->p->status = status_map[xfer->status];
     r->p->actual_length = xfer->actual_length;
     if (r->in && xfer->actual_length) {
+        USBDevice *udev = USB_DEVICE(s);
+        struct libusb_config_descriptor *conf = (void *)r->cbuf;
         memcpy(r->cbuf, r->buffer + 8, xfer->actual_length);
 
         /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
@@ -394,6 +397,20 @@  static void LIBUSB_CALL usb_host_req_complete_ctrl(struct libusb_transfer *xfer)
             r->cbuf[7] == 9) {
             r->cbuf[7] = 64;
         }
+        /* If this is GET_DESCRIPTOR request for configuration descriptor,
+         * remove 'remote wakeup' flag from it to prevent idle power down
+         * in Windows guest */
+        if (s->suppress_remote_wake &&
+            udev->setup_buf[0] == USB_DIR_IN &&
+            udev->setup_buf[1] == USB_REQ_GET_DESCRIPTOR &&
+            udev->setup_buf[3] == USB_DT_CONFIG && udev->setup_buf[2] == 0 &&
+            xfer->actual_length > offsetof(struct libusb_config_descriptor, bmAttributes) &&
+            (conf->bmAttributes & USB_CFG_ATT_WAKEUP)) {
+                struct libusb_device_descriptor desc;
+                libusb_get_device_descriptor(s->dev, &desc);
+                trace_usb_host_remote_wakeup_removed(desc.idVendor, desc.idProduct);
+                conf->bmAttributes &= ~USB_CFG_ATT_WAKEUP;
+        }
     }
     trace_usb_host_req_complete(s->bus_num, s->addr, r->p,
                                 r->p->status, r->p->actual_length);
@@ -1596,6 +1613,7 @@  static Property usb_host_dev_properties[] = {
                        LIBUSB_LOG_LEVEL_WARNING),
     DEFINE_PROP_BIT("pipeline",    USBHostDevice, options,
                     USB_HOST_OPT_PIPELINE, true),
+    DEFINE_PROP_BOOL("suppress-remote-wake", USBHostDevice, suppress_remote_wake, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/usb/trace-events b/hw/usb/trace-events
index 2d3713351c..6f87b5262a 100644
--- a/hw/usb/trace-events
+++ b/hw/usb/trace-events
@@ -266,3 +266,4 @@  usb_host_parse_config(int bus, int addr, int value, int active) "dev %d:%d, valu
 usb_host_parse_interface(int bus, int addr, int num, int alt, int active) "dev %d:%d, num %d, alt %d, active %d"
 usb_host_parse_endpoint(int bus, int addr, int ep, const char *dir, const char *type, int active) "dev %d:%d, ep %d, %s, %s, active %d"
 usb_host_parse_error(int bus, int addr, const char *errmsg) "dev %d:%d, msg %s"
+usb_host_remote_wakeup_removed(uint16_t vid, uint16_t pid) "dev %04x:%04x"