#include <libusb.h>
#include "qapi/error.h"
-#include "qemu-common.h"
+#include "migration/vmstate.h"
#include "monitor/monitor.h"
#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
+#include "qemu/module.h"
+#include "sysemu/runstate.h"
#include "sysemu/sysemu.h"
#include "trace.h"
+#include "hw/qdev-properties.h"
#include "hw/usb.h"
/* ------------------------------------------------------------------------ */
uint32_t options;
uint32_t loglevel;
bool needs_autoscan;
+ bool allow_one_guest_reset;
+ bool allow_all_guest_resets;
+ bool suppress_remote_wake;
/* state */
QTAILQ_ENTRY(USBHostDevice) next;
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
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)) {
+ trace_usb_host_remote_wakeup_removed(s->bus_num, s->addr);
+ 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);
if (s->dh) {
usb_host_release_interfaces(s);
+ libusb_reset_device(s->dh);
usb_host_attach_kernel(s);
+ libusb_close(s->dh);
}
}
rc = libusb_kernel_driver_active(s->dh, i);
usb_host_libusb_error("libusb_kernel_driver_active", rc);
if (rc != 1) {
+ if (rc == 0) {
+ s->ifs[i].detached = true;
+ }
continue;
}
trace_usb_host_detach_kernel(s->bus_num, s->addr, i);
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) {
USBHostDevice *s = USB_HOST_DEVICE(udev);
int rc;
+ if (!s->allow_one_guest_reset && !s->allow_all_guest_resets) {
+ return;
+ }
+ if (!s->allow_all_guest_resets && udev->addr == 0) {
+ return;
+ }
+
trace_usb_host_reset(s->bus_num, s->addr);
rc = libusb_reset_device(s->dh);
DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0),
DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames, 32),
+ DEFINE_PROP_BOOL("guest-reset", USBHostDevice,
+ allow_one_guest_reset, true),
+ DEFINE_PROP_BOOL("guest-resets-all", USBHostDevice,
+ allow_all_guest_resets, false),
DEFINE_PROP_UINT32("loglevel", USBHostDevice, loglevel,
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(),
};
uc->alloc_streams = usb_host_alloc_streams;
uc->free_streams = usb_host_free_streams;
dc->vmsd = &vmstate_usb_host;
- dc->props = usb_host_dev_properties;
+ device_class_set_props(dc, usb_host_dev_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
}