Blame 0365-usb-redir-Add-support-for-migration.patch

Hans de Goede 393f81
From 0d733a1280bdaba402c6efbfae116408d7c81bb0 Mon Sep 17 00:00:00 2001
Hans de Goede c8dfc6
From: Hans de Goede <hdegoede@redhat.com>
Hans de Goede c8dfc6
Date: Wed, 5 Sep 2012 09:21:44 +0200
Hans de Goede 393f81
Subject: [PATCH 364/365] usb-redir: Add support for migration
Hans de Goede c8dfc6
Hans de Goede c8dfc6
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Hans de Goede c8dfc6
---
Hans de Goede 393f81
 hw/usb/redirect.c | 349 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
Hans de Goede 393f81
 1 file changed, 346 insertions(+), 3 deletions(-)
Hans de Goede c8dfc6
Hans de Goede c8dfc6
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
Hans de Goede 393f81
index d8568ae..812096e 100644
Hans de Goede c8dfc6
--- a/hw/usb/redirect.c
Hans de Goede c8dfc6
+++ b/hw/usb/redirect.c
Hans de Goede c8dfc6
@@ -65,8 +65,8 @@ struct endp_data {
Hans de Goede c8dfc6
     uint8_t bufpq_prefilled;
Hans de Goede c8dfc6
     uint8_t bufpq_dropping_packets;
Hans de Goede c8dfc6
     QTAILQ_HEAD(, buf_packet) bufpq;
Hans de Goede c8dfc6
-    int bufpq_size;
Hans de Goede c8dfc6
-    int bufpq_target_size;
Hans de Goede c8dfc6
+    int32_t bufpq_size;
Hans de Goede c8dfc6
+    int32_t bufpq_target_size;
Hans de Goede c8dfc6
 };
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
 struct PacketIdQueueEntry {
Hans de Goede c8dfc6
@@ -241,6 +241,11 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
Hans de Goede c8dfc6
         return 0;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
+    /* Don't send new data to the chardev until our state is fully synced */
Hans de Goede c8dfc6
+    if (!runstate_check(RUN_STATE_RUNNING)) {
Hans de Goede c8dfc6
+        return 0;
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
     r = qemu_chr_fe_write(dev->cs, data, count);
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     if (r < 0) {
Hans de Goede c8dfc6
@@ -868,6 +873,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev)
Hans de Goede c8dfc6
 {
Hans de Goede c8dfc6
     uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
Hans de Goede c8dfc6
     char version[32];
Hans de Goede c8dfc6
+    int flags = 0;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     /* Make sure any pending closes are handled (no-op if none pending) */
Hans de Goede c8dfc6
     usbredir_chardev_close_bh(dev);
Hans de Goede c8dfc6
@@ -903,7 +909,12 @@ static void usbredir_chardev_open(USBRedirDevice *dev)
Hans de Goede c8dfc6
     usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
Hans de Goede c8dfc6
     usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size);
Hans de Goede c8dfc6
     usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids);
Hans de Goede c8dfc6
-    usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0);
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    if (runstate_check(RUN_STATE_INMIGRATE)) {
Hans de Goede c8dfc6
+        flags |= usbredirparser_fl_no_hello;
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+    usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE,
Hans de Goede c8dfc6
+                        flags);
Hans de Goede c8dfc6
     usbredirparser_do_write(dev->parser);
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
@@ -949,6 +960,11 @@ static int usbredir_chardev_can_read(void *opaque)
Hans de Goede c8dfc6
         return 0;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
+    /* Don't read new data from the chardev until our state is fully synced */
Hans de Goede c8dfc6
+    if (!runstate_check(RUN_STATE_RUNNING)) {
Hans de Goede c8dfc6
+        return 0;
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
     /* usbredir_parser_do_read will consume *all* data we give it */
Hans de Goede c8dfc6
     return 1024 * 1024;
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
@@ -1004,6 +1020,15 @@ static const QemuChrHandlers usbredir_chr_handlers = {
Hans de Goede c8dfc6
  * init + destroy
Hans de Goede c8dfc6
  */
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
+static void usbredir_vm_state_change(void *priv, int running, RunState state)
Hans de Goede c8dfc6
+{
Hans de Goede c8dfc6
+    USBRedirDevice *dev = priv;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    if (state == RUN_STATE_RUNNING && dev->parser != NULL) {
Hans de Goede c8dfc6
+        usbredirparser_do_write(dev->parser); /* Flush any pending writes */
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+}
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
 static int usbredir_initfn(USBDevice *udev)
Hans de Goede c8dfc6
 {
Hans de Goede c8dfc6
     USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
Hans de Goede c8dfc6
@@ -1041,6 +1066,7 @@ static int usbredir_initfn(USBDevice *udev)
Hans de Goede c8dfc6
     qemu_chr_fe_open(dev->cs);
Hans de Goede c8dfc6
     qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev);
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
+    qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
Hans de Goede c8dfc6
     add_boot_device_path(dev->bootindex, &udev->qdev, NULL);
Hans de Goede c8dfc6
     return 0;
Hans de Goede c8dfc6
 }
Hans de Goede 393f81
@@ -1530,6 +1556,322 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
+/*
Hans de Goede c8dfc6
+ * Migration code
Hans de Goede c8dfc6
+ */
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+static void usbredir_pre_save(void *priv)
Hans de Goede c8dfc6
+{
Hans de Goede c8dfc6
+    USBRedirDevice *dev = priv;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    usbredir_fill_already_in_flight(dev);
Hans de Goede c8dfc6
+}
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+static int usbredir_post_load(void *priv, int version_id)
Hans de Goede c8dfc6
+{
Hans de Goede c8dfc6
+    USBRedirDevice *dev = priv;
Hans de Goede c8dfc6
+    struct USBEndpoint *usb_ep;
Hans de Goede c8dfc6
+    int i;
Hans de Goede c8dfc6
+
Hans de Goede 393f81
+    switch (dev->device_info.speed) {
Hans de Goede 393f81
+    case usb_redir_speed_low:
Hans de Goede 393f81
+        dev->dev.speed = USB_SPEED_LOW;
Hans de Goede 393f81
+        break;
Hans de Goede 393f81
+    case usb_redir_speed_full:
Hans de Goede 393f81
+        dev->dev.speed = USB_SPEED_FULL;
Hans de Goede 393f81
+        break;
Hans de Goede 393f81
+    case usb_redir_speed_high:
Hans de Goede 393f81
+        dev->dev.speed = USB_SPEED_HIGH;
Hans de Goede 393f81
+        break;
Hans de Goede 393f81
+    case usb_redir_speed_super:
Hans de Goede 393f81
+        dev->dev.speed = USB_SPEED_SUPER;
Hans de Goede 393f81
+        break;
Hans de Goede 393f81
+    default:
Hans de Goede 393f81
+        dev->dev.speed = USB_SPEED_FULL;
Hans de Goede 393f81
+    }
Hans de Goede 393f81
+    dev->dev.speedmask = (1 << dev->dev.speed);
Hans de Goede 393f81
+
Hans de Goede c8dfc6
+    for (i = 0; i < MAX_ENDPOINTS; i++) {
Hans de Goede c8dfc6
+        usb_ep = usb_ep_get(&dev->dev,
Hans de Goede c8dfc6
+                            (i & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT,
Hans de Goede c8dfc6
+                            i & 0x0f);
Hans de Goede c8dfc6
+        usb_ep->type = dev->endpoint[i].type;
Hans de Goede c8dfc6
+        usb_ep->ifnum = dev->endpoint[i].interface;
Hans de Goede c8dfc6
+        usb_ep->max_packet_size = dev->endpoint[i].max_packet_size;
Hans de Goede c8dfc6
+        if (dev->endpoint[i].type == usb_redir_type_bulk) {
Hans de Goede c8dfc6
+            usb_ep->pipeline = true;
Hans de Goede c8dfc6
+        }
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+    return 0;
Hans de Goede c8dfc6
+}
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+/* For usbredirparser migration */
Hans de Goede c8dfc6
+static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused)
Hans de Goede c8dfc6
+{
Hans de Goede c8dfc6
+    USBRedirDevice *dev = priv;
Hans de Goede c8dfc6
+    uint8_t *data;
Hans de Goede c8dfc6
+    int len;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    if (dev->parser == NULL) {
Hans de Goede c8dfc6
+        qemu_put_be32(f, 0);
Hans de Goede c8dfc6
+        return;
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    usbredirparser_serialize(dev->parser, &data, &len;;
Hans de Goede c8dfc6
+    qemu_oom_check(data);
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    qemu_put_be32(f, len);
Hans de Goede c8dfc6
+    qemu_put_buffer(f, data, len);
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    free(data);
Hans de Goede c8dfc6
+}
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused)
Hans de Goede c8dfc6
+{
Hans de Goede c8dfc6
+    USBRedirDevice *dev = priv;
Hans de Goede c8dfc6
+    uint8_t *data;
Hans de Goede c8dfc6
+    int len, ret;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    len = qemu_get_be32(f);
Hans de Goede c8dfc6
+    if (len == 0) {
Hans de Goede c8dfc6
+        return 0;
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    /*
Hans de Goede c8dfc6
+     * Our chardev should be open already at this point, otherwise
Hans de Goede c8dfc6
+     * the usbredir channel will be broken (ie spice without seamless)
Hans de Goede c8dfc6
+     */
Hans de Goede c8dfc6
+    if (dev->parser == NULL) {
Hans de Goede c8dfc6
+        ERROR("get_parser called with closed chardev, failing migration\n");
Hans de Goede c8dfc6
+        return -1;
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    data = g_malloc(len);
Hans de Goede c8dfc6
+    qemu_get_buffer(f, data, len);
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    ret = usbredirparser_unserialize(dev->parser, data, len);
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    g_free(data);
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    return ret;
Hans de Goede c8dfc6
+}
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+static const VMStateInfo usbredir_parser_vmstate_info = {
Hans de Goede c8dfc6
+    .name = "usb-redir-parser",
Hans de Goede c8dfc6
+    .put  = usbredir_put_parser,
Hans de Goede c8dfc6
+    .get  = usbredir_get_parser,
Hans de Goede c8dfc6
+};
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+/* For buffered packets (iso/irq) queue migration */
Hans de Goede c8dfc6
+static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused)
Hans de Goede c8dfc6
+{
Hans de Goede c8dfc6
+    struct endp_data *endp = priv;
Hans de Goede c8dfc6
+    struct buf_packet *bufp;
Hans de Goede c8dfc6
+    int remain = endp->bufpq_size;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    qemu_put_be32(f, endp->bufpq_size);
Hans de Goede c8dfc6
+    QTAILQ_FOREACH(bufp, &endp->bufpq, next) {
Hans de Goede c8dfc6
+        qemu_put_be32(f, bufp->len);
Hans de Goede c8dfc6
+        qemu_put_be32(f, bufp->status);
Hans de Goede c8dfc6
+        qemu_put_buffer(f, bufp->data, bufp->len);
Hans de Goede c8dfc6
+        remain--;
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+    assert(remain == 0);
Hans de Goede c8dfc6
+}
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused)
Hans de Goede c8dfc6
+{
Hans de Goede c8dfc6
+    struct endp_data *endp = priv;
Hans de Goede c8dfc6
+    struct buf_packet *bufp;
Hans de Goede c8dfc6
+    int i;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    endp->bufpq_size = qemu_get_be32(f);
Hans de Goede c8dfc6
+    for (i = 0; i < endp->bufpq_size; i++) {
Hans de Goede c8dfc6
+        bufp = g_malloc(sizeof(struct buf_packet));
Hans de Goede c8dfc6
+        bufp->len = qemu_get_be32(f);
Hans de Goede c8dfc6
+        bufp->status = qemu_get_be32(f);
Hans de Goede c8dfc6
+        bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */
Hans de Goede c8dfc6
+        qemu_get_buffer(f, bufp->data, bufp->len);
Hans de Goede c8dfc6
+        QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next);
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+    return 0;
Hans de Goede c8dfc6
+}
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+static const VMStateInfo usbredir_ep_bufpq_vmstate_info = {
Hans de Goede c8dfc6
+    .name = "usb-redir-bufpq",
Hans de Goede c8dfc6
+    .put  = usbredir_put_bufpq,
Hans de Goede c8dfc6
+    .get  = usbredir_get_bufpq,
Hans de Goede c8dfc6
+};
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+/* For endp_data migration */
Hans de Goede c8dfc6
+static const VMStateDescription usbredir_ep_vmstate = {
Hans de Goede c8dfc6
+    .name = "usb-redir-ep",
Hans de Goede c8dfc6
+    .version_id = 1,
Hans de Goede c8dfc6
+    .minimum_version_id = 1,
Hans de Goede c8dfc6
+    .fields = (VMStateField []) {
Hans de Goede c8dfc6
+        VMSTATE_UINT8(type, struct endp_data),
Hans de Goede c8dfc6
+        VMSTATE_UINT8(interval, struct endp_data),
Hans de Goede c8dfc6
+        VMSTATE_UINT8(interface, struct endp_data),
Hans de Goede c8dfc6
+        VMSTATE_UINT16(max_packet_size, struct endp_data),
Hans de Goede c8dfc6
+        VMSTATE_UINT8(iso_started, struct endp_data),
Hans de Goede c8dfc6
+        VMSTATE_UINT8(iso_error, struct endp_data),
Hans de Goede c8dfc6
+        VMSTATE_UINT8(interrupt_started, struct endp_data),
Hans de Goede c8dfc6
+        VMSTATE_UINT8(interrupt_error, struct endp_data),
Hans de Goede c8dfc6
+        VMSTATE_UINT8(bufpq_prefilled, struct endp_data),
Hans de Goede c8dfc6
+        VMSTATE_UINT8(bufpq_dropping_packets, struct endp_data),
Hans de Goede c8dfc6
+        {
Hans de Goede c8dfc6
+            .name         = "bufpq",
Hans de Goede c8dfc6
+            .version_id   = 0,
Hans de Goede c8dfc6
+            .field_exists = NULL,
Hans de Goede c8dfc6
+            .size         = 0,
Hans de Goede c8dfc6
+            .info         = &usbredir_ep_bufpq_vmstate_info,
Hans de Goede c8dfc6
+            .flags        = VMS_SINGLE,
Hans de Goede c8dfc6
+            .offset       = 0,
Hans de Goede c8dfc6
+        },
Hans de Goede c8dfc6
+        VMSTATE_INT32(bufpq_target_size, struct endp_data),
Hans de Goede c8dfc6
+        VMSTATE_END_OF_LIST()
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+};
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+/* For PacketIdQueue migration */
Hans de Goede c8dfc6
+static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused)
Hans de Goede c8dfc6
+{
Hans de Goede c8dfc6
+    struct PacketIdQueue *q = priv;
Hans de Goede c8dfc6
+    USBRedirDevice *dev = q->dev;
Hans de Goede c8dfc6
+    struct PacketIdQueueEntry *e;
Hans de Goede c8dfc6
+    int remain = q->size;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    DPRINTF("put_packet_id_q %s size %d\n", q->name, q->size);
Hans de Goede c8dfc6
+    qemu_put_be32(f, q->size);
Hans de Goede c8dfc6
+    QTAILQ_FOREACH(e, &q->head, next) {
Hans de Goede c8dfc6
+        qemu_put_be64(f, e->id);
Hans de Goede c8dfc6
+        remain--;
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+    assert(remain == 0);
Hans de Goede c8dfc6
+}
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused)
Hans de Goede c8dfc6
+{
Hans de Goede c8dfc6
+    struct PacketIdQueue *q = priv;
Hans de Goede c8dfc6
+    USBRedirDevice *dev = q->dev;
Hans de Goede c8dfc6
+    int i, size;
Hans de Goede c8dfc6
+    uint64_t id;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    size = qemu_get_be32(f);
Hans de Goede c8dfc6
+    DPRINTF("get_packet_id_q %s size %d\n", q->name, size);
Hans de Goede c8dfc6
+    for (i = 0; i < size; i++) {
Hans de Goede c8dfc6
+        id = qemu_get_be64(f);
Hans de Goede c8dfc6
+        packet_id_queue_add(q, id);
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+    assert(q->size == size);
Hans de Goede c8dfc6
+    return 0;
Hans de Goede c8dfc6
+}
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+static const VMStateInfo usbredir_ep_packet_id_q_vmstate_info = {
Hans de Goede c8dfc6
+    .name = "usb-redir-packet-id-q",
Hans de Goede c8dfc6
+    .put  = usbredir_put_packet_id_q,
Hans de Goede c8dfc6
+    .get  = usbredir_get_packet_id_q,
Hans de Goede c8dfc6
+};
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+static const VMStateDescription usbredir_ep_packet_id_queue_vmstate = {
Hans de Goede c8dfc6
+    .name = "usb-redir-packet-id-queue",
Hans de Goede c8dfc6
+    .version_id = 1,
Hans de Goede c8dfc6
+    .minimum_version_id = 1,
Hans de Goede c8dfc6
+    .fields = (VMStateField []) {
Hans de Goede c8dfc6
+        {
Hans de Goede c8dfc6
+            .name         = "queue",
Hans de Goede c8dfc6
+            .version_id   = 0,
Hans de Goede c8dfc6
+            .field_exists = NULL,
Hans de Goede c8dfc6
+            .size         = 0,
Hans de Goede c8dfc6
+            .info         = &usbredir_ep_packet_id_q_vmstate_info,
Hans de Goede c8dfc6
+            .flags        = VMS_SINGLE,
Hans de Goede c8dfc6
+            .offset       = 0,
Hans de Goede c8dfc6
+        },
Hans de Goede c8dfc6
+        VMSTATE_END_OF_LIST()
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+};
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+/* For usb_redir_device_connect_header migration */
Hans de Goede c8dfc6
+static const VMStateDescription usbredir_device_info_vmstate = {
Hans de Goede c8dfc6
+    .name = "usb-redir-device-info",
Hans de Goede c8dfc6
+    .version_id = 1,
Hans de Goede c8dfc6
+    .minimum_version_id = 1,
Hans de Goede c8dfc6
+    .fields = (VMStateField []) {
Hans de Goede c8dfc6
+        VMSTATE_UINT8(speed, struct usb_redir_device_connect_header),
Hans de Goede c8dfc6
+        VMSTATE_UINT8(device_class, struct usb_redir_device_connect_header),
Hans de Goede c8dfc6
+        VMSTATE_UINT8(device_subclass, struct usb_redir_device_connect_header),
Hans de Goede c8dfc6
+        VMSTATE_UINT8(device_protocol, struct usb_redir_device_connect_header),
Hans de Goede c8dfc6
+        VMSTATE_UINT16(vendor_id, struct usb_redir_device_connect_header),
Hans de Goede c8dfc6
+        VMSTATE_UINT16(product_id, struct usb_redir_device_connect_header),
Hans de Goede c8dfc6
+        VMSTATE_UINT16(device_version_bcd,
Hans de Goede c8dfc6
+                       struct usb_redir_device_connect_header),
Hans de Goede c8dfc6
+        VMSTATE_END_OF_LIST()
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+};
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+/* For usb_redir_interface_info_header migration */
Hans de Goede c8dfc6
+static const VMStateDescription usbredir_interface_info_vmstate = {
Hans de Goede c8dfc6
+    .name = "usb-redir-interface-info",
Hans de Goede c8dfc6
+    .version_id = 1,
Hans de Goede c8dfc6
+    .minimum_version_id = 1,
Hans de Goede c8dfc6
+    .fields = (VMStateField []) {
Hans de Goede c8dfc6
+        VMSTATE_UINT32(interface_count,
Hans de Goede c8dfc6
+                       struct usb_redir_interface_info_header),
Hans de Goede c8dfc6
+        VMSTATE_UINT8_ARRAY(interface,
Hans de Goede c8dfc6
+                            struct usb_redir_interface_info_header, 32),
Hans de Goede c8dfc6
+        VMSTATE_UINT8_ARRAY(interface_class,
Hans de Goede c8dfc6
+                            struct usb_redir_interface_info_header, 32),
Hans de Goede c8dfc6
+        VMSTATE_UINT8_ARRAY(interface_subclass,
Hans de Goede c8dfc6
+                            struct usb_redir_interface_info_header, 32),
Hans de Goede c8dfc6
+        VMSTATE_UINT8_ARRAY(interface_protocol,
Hans de Goede c8dfc6
+                            struct usb_redir_interface_info_header, 32),
Hans de Goede c8dfc6
+        VMSTATE_END_OF_LIST()
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+};
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+/* And finally the USBRedirDevice vmstate itself */
Hans de Goede c8dfc6
+static const VMStateDescription usbredir_vmstate = {
Hans de Goede c8dfc6
+    .name = "usb-redir",
Hans de Goede c8dfc6
+    .version_id = 1,
Hans de Goede c8dfc6
+    .minimum_version_id = 1,
Hans de Goede c8dfc6
+    .pre_save = usbredir_pre_save,
Hans de Goede c8dfc6
+    .post_load = usbredir_post_load,
Hans de Goede c8dfc6
+    .fields = (VMStateField []) {
Hans de Goede c8dfc6
+        VMSTATE_USB_DEVICE(dev, USBRedirDevice),
Hans de Goede c8dfc6
+        VMSTATE_TIMER(attach_timer, USBRedirDevice),
Hans de Goede c8dfc6
+        {
Hans de Goede c8dfc6
+            .name         = "parser",
Hans de Goede c8dfc6
+            .version_id   = 0,
Hans de Goede c8dfc6
+            .field_exists = NULL,
Hans de Goede c8dfc6
+            .size         = 0,
Hans de Goede c8dfc6
+            .info         = &usbredir_parser_vmstate_info,
Hans de Goede c8dfc6
+            .flags        = VMS_SINGLE,
Hans de Goede c8dfc6
+            .offset       = 0,
Hans de Goede c8dfc6
+        },
Hans de Goede c8dfc6
+        VMSTATE_STRUCT_ARRAY(endpoint, USBRedirDevice, MAX_ENDPOINTS, 1,
Hans de Goede c8dfc6
+                             usbredir_ep_vmstate, struct endp_data),
Hans de Goede c8dfc6
+        VMSTATE_STRUCT(cancelled, USBRedirDevice, 1,
Hans de Goede c8dfc6
+                       usbredir_ep_packet_id_queue_vmstate,
Hans de Goede c8dfc6
+                       struct PacketIdQueue),
Hans de Goede c8dfc6
+        VMSTATE_STRUCT(already_in_flight, USBRedirDevice, 1,
Hans de Goede c8dfc6
+                       usbredir_ep_packet_id_queue_vmstate,
Hans de Goede c8dfc6
+                       struct PacketIdQueue),
Hans de Goede c8dfc6
+        VMSTATE_STRUCT(device_info, USBRedirDevice, 1,
Hans de Goede c8dfc6
+                       usbredir_device_info_vmstate,
Hans de Goede c8dfc6
+                       struct usb_redir_device_connect_header),
Hans de Goede c8dfc6
+        VMSTATE_STRUCT(interface_info, USBRedirDevice, 1,
Hans de Goede c8dfc6
+                       usbredir_interface_info_vmstate,
Hans de Goede c8dfc6
+                       struct usb_redir_interface_info_header),
Hans de Goede c8dfc6
+        VMSTATE_END_OF_LIST()
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+};
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
 static Property usbredir_properties[] = {
Hans de Goede c8dfc6
     DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
Hans de Goede c8dfc6
     DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
Hans de Goede 393f81
@@ -1550,6 +1892,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data)
Hans de Goede c8dfc6
     uc->handle_reset   = usbredir_handle_reset;
Hans de Goede c8dfc6
     uc->handle_data    = usbredir_handle_data;
Hans de Goede c8dfc6
     uc->handle_control = usbredir_handle_control;
Hans de Goede c8dfc6
+    dc->vmsd           = &usbredir_vmstate;
Hans de Goede c8dfc6
     dc->props          = usbredir_properties;
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-- 
Hans de Goede c8dfc6
1.7.12
Hans de Goede c8dfc6