|
|
5544c1 |
From a056ffda5a57d7169268e49a3e42c7d79c8f7c48 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
|
|
|
5544c1 |
Subject: [PATCH] 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
|
|
|
5544c1 |
index 6eb3c6d..b7387b6 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 {
|
|
|
5544c1 |
@@ -243,6 +243,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) {
|
|
|
5544c1 |
@@ -870,6 +875,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);
|
|
|
5544c1 |
@@ -902,7 +908,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);
|
|
|
5544c1 |
- 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 |
+ }
|
|
|
5544c1 |
+ 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 |
|
|
|
5544c1 |
@@ -948,6 +959,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 |
}
|
|
|
5544c1 |
@@ -999,6 +1015,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);
|
|
|
5544c1 |
@@ -1036,6 +1061,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 |
}
|
|
|
5544c1 |
@@ -1525,6 +1551,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),
|
|
|
5544c1 |
@@ -1545,6 +1887,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 |
--
|
|
|
5544c1 |
1.7.12.1
|
|
Hans de Goede |
c8dfc6 |
|