From ac12683e3cae42e25c64e66113a8abfb497cc865 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 23 Jun 2011 12:41:24 -0300
Subject: [RHEL6 qemu-kvm PATCH 049/115] usb core: add migration support

RH-Author: Gerd Hoffmann <kraxel@redhat.com>
Message-id: <1308832951-8995-49-git-send-email-kraxel@redhat.com>
Patchwork-id: 27899
O-Subject: [RHEL-6.2 kvm PATCH 048/115] usb core: add migration support
Bugzilla: 561414 632299 645351 711354
RH-Acked-by: Hans de Goede <hdegoede@redhat.com>
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
RH-Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com>
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>

Yes, seriously.  There is no migration support at all for usb devices.
They loose state, especially the device address, and stop responding
because of that.  Oops.

Luckily there is so much broken usb hardware out there that the guest
usually just kicks the device hard (via port reset and
reinitialization), then continues without a hitch.  So we got away with
that in a surprising high number of cases.

The arrival of remote wakeup (which enables autosuspend support) changes
that picture though.  The usb devices also forget that it they are
supposed to wakeup, so they don't do that.  The host also doesn't notice
the device stopped working in case it suspended the device and thus
expects it waking up instead of polling it.  Result is that your mouse
is dead.

Lets start fixing that.  Add a vmstate struct for USBDevice.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit c1ecb40a6124b80f1e346e38a1975e82da6507ca)
---
 hw/hw.h      |   10 ++++++++++
 hw/usb-bus.c |   16 ++++++++++++++++
 hw/usb.h     |   10 +++++-----
 3 files changed, 31 insertions(+), 5 deletions(-)

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 hw/hw.h      |   10 ++++++++++
 hw/usb-bus.c |   16 ++++++++++++++++
 hw/usb.h     |   10 +++++-----
 3 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/hw/hw.h b/hw/hw.h
index ec8762d..1686176 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -584,6 +584,16 @@ extern const VMStateDescription vmstate_i2c_slave;
     .offset     = vmstate_offset_value(_state, _field, i2c_slave),   \
 }
 
+extern const VMStateDescription vmstate_usb_device;
+
+#define VMSTATE_USB_DEVICE(_field, _state) {                         \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(USBDevice),                                 \
+    .vmsd       = &vmstate_usb_device,                               \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, USBDevice),   \
+}
+
 #define vmstate_offset_macaddr(_state, _field)                       \
     vmstate_offset_array(_state, _field.a, uint8_t,                \
                          sizeof(typeof_field(_state, _field)))
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 0f1961d..a559b1d 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -23,6 +23,22 @@ static struct BusInfo usb_bus_info = {
 static int next_usb_bus = 0;
 static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
 
+const VMStateDescription vmstate_usb_device = {
+    .name = "USBDevice",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT8(addr, USBDevice),
+        VMSTATE_INT32(state, USBDevice),
+        VMSTATE_INT32(remote_wakeup, USBDevice),
+        VMSTATE_INT32(setup_state, USBDevice),
+        VMSTATE_INT32(setup_len, USBDevice),
+        VMSTATE_INT32(setup_index, USBDevice),
+        VMSTATE_UINT8_ARRAY(setup_buf, USBDevice, 8),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
 void usb_bus_new(USBBus *bus, DeviceState *host)
 {
     qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
diff --git a/hw/usb.h b/hw/usb.h
index a678571..74f4fae 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -161,13 +161,13 @@ struct USBDevice {
     int auto_attach;
     int attached;
 
-    int state;
+    int32_t state;
     uint8_t setup_buf[8];
     uint8_t data_buf[1024];
-    int remote_wakeup;
-    int setup_state;
-    int setup_len;
-    int setup_index;
+    int32_t remote_wakeup;
+    int32_t setup_state;
+    int32_t setup_len;
+    int32_t setup_index;
 
     QLIST_HEAD(, USBDescString) strings;
     const USBDescDevice *device;
-- 
1.7.3.2

