diff --git a/.gitignore b/.gitignore
index 4bebbc7..8c3b708 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ qemu-kvm-0.13.0-25fdf4a.tar.gz
 /qemu-kvm-0.15.0-fda1906.tar.gz
 /qemu-kvm-0.15.0-59fadcc.tar.gz
 /qemu-kvm-0.15.0-0af4922.tar.gz
+/qemu-kvm-0.15.0.tar.gz
diff --git a/0001-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch b/0001-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch
index 4786a30..5a7dc4c 100644
--- a/0001-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch
+++ b/0001-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch
@@ -1,7 +1,7 @@
->From a0ca79b6cb44fea156174f937c7398befe884048 Mon Sep 17 00:00:00 2001
+>From c0295cc7cc626a2d51de58ac0a9eeee94b6cc9d4 Mon Sep 17 00:00:00 2001
 From: Amit Shah <amit.shah@redhat.com>
 Date: Mon, 21 Mar 2011 21:57:47 +0100
-Subject: [PATCH 01/25] char: Split out tcp socket close code in a separate
+Subject: [PATCH 01/28] char: Split out tcp socket close code in a separate
  function
 
 Signed-off-by: Amit Shah <amit.shah@redhat.com>
diff --git a/0002-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch b/0002-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch
index 7793103..2f3bd6a 100644
--- a/0002-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch
+++ b/0002-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch
@@ -1,7 +1,7 @@
->From 7cda5b9b8b24b778751a402f2b5e6b7d716f1800 Mon Sep 17 00:00:00 2001
+>From 9e799828d3a805184687792254c379ba4887ec60 Mon Sep 17 00:00:00 2001
 From: Amit Shah <amit.shah@redhat.com>
 Date: Mon, 21 Mar 2011 20:31:45 +0100
-Subject: [PATCH 02/25] char: Add a QemuChrHandlers struct to initialise
+Subject: [PATCH 02/28] char: Add a QemuChrHandlers struct to initialise
  chardev handlers
 
 Instead of passing each handler in the qemu_add_handlers() function,
diff --git a/0003-iohandlers-Add-enable-disable_write_fd_handler-funct.patch b/0003-iohandlers-Add-enable-disable_write_fd_handler-funct.patch
index 53b1857..92d01aa 100644
--- a/0003-iohandlers-Add-enable-disable_write_fd_handler-funct.patch
+++ b/0003-iohandlers-Add-enable-disable_write_fd_handler-funct.patch
@@ -1,7 +1,7 @@
->From 28a0d9d78a886205765f513be2d522592b9ffd42 Mon Sep 17 00:00:00 2001
+>From c8cf564bc5c080540287ecd5bd944d85873755df Mon Sep 17 00:00:00 2001
 From: Amit Shah <amit.shah@redhat.com>
 Date: Mon, 21 Mar 2011 20:32:58 +0100
-Subject: [PATCH 03/25] iohandlers: Add enable/disable_write_fd_handler()
+Subject: [PATCH 03/28] iohandlers: Add enable/disable_write_fd_handler()
  functions
 
 These will be used to provide a cleaner API for the nonblocking case.
diff --git a/0004-char-Add-framework-for-a-write-unblocked-callback.patch b/0004-char-Add-framework-for-a-write-unblocked-callback.patch
index 2b4baa0..c4bd019 100644
--- a/0004-char-Add-framework-for-a-write-unblocked-callback.patch
+++ b/0004-char-Add-framework-for-a-write-unblocked-callback.patch
@@ -1,7 +1,7 @@
->From 7058d42cf3e2fab291bd4c42604ef510a46bebe0 Mon Sep 17 00:00:00 2001
+>From 3ad2ca8e46ba078e69254ca5886de89b30f823bb Mon Sep 17 00:00:00 2001
 From: Amit Shah <amit.shah@redhat.com>
 Date: Mon, 21 Mar 2011 21:41:42 +0100
-Subject: [PATCH 04/25] char: Add framework for a 'write unblocked' callback
+Subject: [PATCH 04/28] char: Add framework for a 'write unblocked' callback
 
 The char layer can let users know that the driver will block on further
 input.  For users interested in not blocking, they can assign a function
diff --git a/0005-char-Update-send_all-to-handle-nonblocking-chardev-w.patch b/0005-char-Update-send_all-to-handle-nonblocking-chardev-w.patch
index 0ca829d..383ba63 100644
--- a/0005-char-Update-send_all-to-handle-nonblocking-chardev-w.patch
+++ b/0005-char-Update-send_all-to-handle-nonblocking-chardev-w.patch
@@ -1,7 +1,7 @@
->From 92303bbcdb1a2877bce80e25836d47056060403d Mon Sep 17 00:00:00 2001
+>From a962453ed73a671f566cc94858dc21ab694cc85f Mon Sep 17 00:00:00 2001
 From: Amit Shah <amit.shah@redhat.com>
 Date: Mon, 21 Mar 2011 22:00:27 +0100
-Subject: [PATCH 05/25] char: Update send_all() to handle nonblocking chardev
+Subject: [PATCH 05/28] char: Update send_all() to handle nonblocking chardev
  write requests
 
 The send_all function is modified to return to the caller in case the
diff --git a/0006-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch b/0006-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch
index 897e36d..49bf64d 100644
--- a/0006-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch
+++ b/0006-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch
@@ -1,7 +1,7 @@
->From 569b1773afa2b30ec9c64cc71815d6c499cd02c0 Mon Sep 17 00:00:00 2001
+>From 5fc1c0fc4c8153ea927aa8580c78c484f966be64 Mon Sep 17 00:00:00 2001
 From: Amit Shah <amit.shah@redhat.com>
 Date: Mon, 21 Mar 2011 22:02:47 +0100
-Subject: [PATCH 06/25] char: Equip the unix/tcp backend to handle nonblocking
+Subject: [PATCH 06/28] char: Equip the unix/tcp backend to handle nonblocking
  writes#
 
 Now that the infrastructure is in place to return -EAGAIN to callers,
diff --git a/0007-char-Throttle-when-host-connection-is-down.patch b/0007-char-Throttle-when-host-connection-is-down.patch
index 99f0f5b..7a131d8 100644
--- a/0007-char-Throttle-when-host-connection-is-down.patch
+++ b/0007-char-Throttle-when-host-connection-is-down.patch
@@ -1,7 +1,7 @@
->From edcb78965b9cab18004c30721d46138000a2c810 Mon Sep 17 00:00:00 2001
+>From 5121e48706408e28c811e74d3e6da5b78aa9137d Mon Sep 17 00:00:00 2001
 From: Amit Shah <amit.shah@redhat.com>
 Date: Mon, 21 Mar 2011 22:05:10 +0100
-Subject: [PATCH 07/25] char: Throttle when host connection is down#
+Subject: [PATCH 07/28] char: Throttle when host connection is down#
 
 When the host-side connection goes down, throttle the virtio-serial bus
 and later unthrottle when a connection gets established.  This helps
diff --git a/0008-virtio-console-Enable-port-throttling-when-chardev-i.patch b/0008-virtio-console-Enable-port-throttling-when-chardev-i.patch
index 2b30604..740e25d 100644
--- a/0008-virtio-console-Enable-port-throttling-when-chardev-i.patch
+++ b/0008-virtio-console-Enable-port-throttling-when-chardev-i.patch
@@ -1,7 +1,7 @@
->From 06a1e88d3e4dc55e94da35928686571b56b8f7a4 Mon Sep 17 00:00:00 2001
+>From 8750ea70a68e74ca3ecea6149d1d5289cc77dae3 Mon Sep 17 00:00:00 2001
 From: Amit Shah <amit.shah@redhat.com>
 Date: Mon, 21 Mar 2011 22:06:41 +0100
-Subject: [PATCH 08/25] virtio-console: Enable port throttling when chardev is
+Subject: [PATCH 08/28] virtio-console: Enable port throttling when chardev is
  slow to consume data
 
 When a chardev indicates it can't accept more data, we tell the
diff --git a/0009-spice-qemu-char.c-add-throttling.patch b/0009-spice-qemu-char.c-add-throttling.patch
index 112adc8..17bebaa 100644
--- a/0009-spice-qemu-char.c-add-throttling.patch
+++ b/0009-spice-qemu-char.c-add-throttling.patch
@@ -1,7 +1,7 @@
->From faa8f1ed4cb40ce4699882a88650a42ca70f0b6b Mon Sep 17 00:00:00 2001
+>From a649fba41737329ae13a5b0b4f20798ddf97e2a2 Mon Sep 17 00:00:00 2001
 From: Alon Levy <alevy@redhat.com>
 Date: Tue, 22 Mar 2011 12:27:59 +0200
-Subject: [PATCH 09/25] spice-qemu-char.c: add throttling
+Subject: [PATCH 09/28] spice-qemu-char.c: add throttling
 
 BZ: 672191
 
diff --git a/0010-spice-qemu-char.c-remove-intermediate-buffer.patch b/0010-spice-qemu-char.c-remove-intermediate-buffer.patch
index 0396245..ca23ed9 100644
--- a/0010-spice-qemu-char.c-remove-intermediate-buffer.patch
+++ b/0010-spice-qemu-char.c-remove-intermediate-buffer.patch
@@ -1,7 +1,7 @@
->From b8af15fd71aa0d0eb0f7df053759eaa85176af46 Mon Sep 17 00:00:00 2001
+>From 63350d37305a8fc5b6a8fb2fbacfb8a6a91956fd Mon Sep 17 00:00:00 2001
 From: Alon Levy <alevy@redhat.com>
 Date: Tue, 22 Mar 2011 12:28:00 +0200
-Subject: [PATCH 10/25] spice-qemu-char.c: remove intermediate buffer
+Subject: [PATCH 10/28] spice-qemu-char.c: remove intermediate buffer
 
 BZ: 672191
 upstream: not submitted (explained below)
diff --git a/0011-usb-redir-Add-flow-control-support.patch b/0011-usb-redir-Add-flow-control-support.patch
index 838d679..ab8de4f 100644
--- a/0011-usb-redir-Add-flow-control-support.patch
+++ b/0011-usb-redir-Add-flow-control-support.patch
@@ -1,7 +1,7 @@
->From 267e2a453cab2966edd3cbef520351dd4880765c Mon Sep 17 00:00:00 2001
+>From e7903f889f3105efe7e3876925926e8e91919b0f Mon Sep 17 00:00:00 2001
 From: Hans de Goede <hdegoede@redhat.com>
 Date: Tue, 19 Jul 2011 10:56:19 +0200
-Subject: [PATCH 11/25] usb-redir: Add flow control support
+Subject: [PATCH 11/28] usb-redir: Add flow control support
 
 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
 ---
diff --git a/0012-spice-add-worker-wrapper-functions.patch b/0012-spice-add-worker-wrapper-functions.patch
new file mode 100644
index 0000000..a750ca6
--- /dev/null
+++ b/0012-spice-add-worker-wrapper-functions.patch
@@ -0,0 +1,323 @@
+>From 67d29af45ebb1539eaaa2bfb599350c790306111 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+Date: Fri, 17 Jun 2011 10:34:25 +0200
+Subject: [PATCH 12/28] spice: add worker wrapper functions.
+
+Add wrapper functions for all spice worker calls.
+
+Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
+---
+ hw/qxl-render.c    |    4 +-
+ hw/qxl.c           |   32 +++++++++---------
+ ui/spice-display.c |   95 ++++++++++++++++++++++++++++++++++++++++++++++++---
+ ui/spice-display.h |   22 ++++++++++++
+ 4 files changed, 129 insertions(+), 24 deletions(-)
+
+diff --git a/hw/qxl-render.c b/hw/qxl-render.c
+index 1316066..bef5f14 100644
+--- a/hw/qxl-render.c
++++ b/hw/qxl-render.c
+@@ -124,8 +124,8 @@ void qxl_render_update(PCIQXLDevice *qxl)
+     update.bottom = qxl->guest_primary.surface.height;
+ 
+     memset(dirty, 0, sizeof(dirty));
+-    qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update,
+-                                 dirty, ARRAY_SIZE(dirty), 1);
++    qemu_spice_update_area(&qxl->ssd, 0, &update,
++                           dirty, ARRAY_SIZE(dirty), 1);
+ 
+     for (i = 0; i < ARRAY_SIZE(dirty); i++) {
+         if (qemu_spice_rect_is_empty(dirty+i)) {
+diff --git a/hw/qxl.c b/hw/qxl.c
+index a6fb7f0..5deb776 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -684,8 +684,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
+     dprint(d, 1, "%s: start%s\n", __FUNCTION__,
+            loadvm ? " (loadvm)" : "");
+ 
+-    d->ssd.worker->reset_cursor(d->ssd.worker);
+-    d->ssd.worker->reset_image_cache(d->ssd.worker);
++    qemu_spice_reset_cursor(&d->ssd);
++    qemu_spice_reset_image_cache(&d->ssd);
+     qxl_reset_surfaces(d);
+     qxl_reset_memslots(d);
+ 
+@@ -790,7 +790,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
+            __FUNCTION__, memslot.slot_id,
+            memslot.virt_start, memslot.virt_end);
+ 
+-    d->ssd.worker->add_memslot(d->ssd.worker, &memslot);
++    qemu_spice_add_memslot(&d->ssd, &memslot);
+     d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
+     d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
+     d->guest_slots[slot_id].delta = delta;
+@@ -800,14 +800,14 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
+ static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
+ {
+     dprint(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id);
+-    d->ssd.worker->del_memslot(d->ssd.worker, MEMSLOT_GROUP_HOST, slot_id);
++    qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id);
+     d->guest_slots[slot_id].active = 0;
+ }
+ 
+ static void qxl_reset_memslots(PCIQXLDevice *d)
+ {
+     dprint(d, 1, "%s:\n", __FUNCTION__);
+-    d->ssd.worker->reset_memslots(d->ssd.worker);
++    qemu_spice_reset_memslots(&d->ssd);
+     memset(&d->guest_slots, 0, sizeof(d->guest_slots));
+ }
+ 
+@@ -815,7 +815,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
+ {
+     dprint(d, 1, "%s:\n", __FUNCTION__);
+     d->mode = QXL_MODE_UNDEFINED;
+-    d->ssd.worker->destroy_surfaces(d->ssd.worker);
++    qemu_spice_destroy_surfaces(&d->ssd);
+     memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
+ }
+ 
+@@ -869,7 +869,7 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
+ 
+     qxl->mode = QXL_MODE_NATIVE;
+     qxl->cmdflags = 0;
+-    qxl->ssd.worker->create_primary_surface(qxl->ssd.worker, 0, &surface);
++    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface);
+ 
+     /* for local rendering */
+     qxl_render_resize(qxl);
+@@ -884,7 +884,7 @@ static void qxl_destroy_primary(PCIQXLDevice *d)
+     dprint(d, 1, "%s\n", __FUNCTION__);
+ 
+     d->mode = QXL_MODE_UNDEFINED;
+-    d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0);
++    qemu_spice_destroy_primary_surface(&d->ssd, 0);
+ }
+ 
+ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
+@@ -956,15 +956,15 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+     case QXL_IO_UPDATE_AREA:
+     {
+         QXLRect update = d->ram->update_area;
+-        d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface,
+-                                   &update, NULL, 0, 0);
++        qemu_spice_update_area(&d->ssd, d->ram->update_surface,
++                               &update, NULL, 0, 0);
+         break;
+     }
+     case QXL_IO_NOTIFY_CMD:
+-        d->ssd.worker->wakeup(d->ssd.worker);
++        qemu_spice_wakeup(&d->ssd);
+         break;
+     case QXL_IO_NOTIFY_CURSOR:
+-        d->ssd.worker->wakeup(d->ssd.worker);
++        qemu_spice_wakeup(&d->ssd);
+         break;
+     case QXL_IO_UPDATE_IRQ:
+         qxl_set_irq(d);
+@@ -978,7 +978,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+             break;
+         }
+         d->oom_running = 1;
+-        d->ssd.worker->oom(d->ssd.worker);
++        qemu_spice_oom(&d->ssd);
+         d->oom_running = 0;
+         break;
+     case QXL_IO_SET_MODE:
+@@ -1016,10 +1016,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+         qxl_destroy_primary(d);
+         break;
+     case QXL_IO_DESTROY_SURFACE_WAIT:
+-        d->ssd.worker->destroy_surface_wait(d->ssd.worker, val);
++        qemu_spice_destroy_surface_wait(&d->ssd, val);
+         break;
+     case QXL_IO_DESTROY_ALL_SURFACES:
+-        d->ssd.worker->destroy_surfaces(d->ssd.worker);
++        qemu_spice_destroy_surfaces(&d->ssd);
+         break;
+     default:
+         fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
+@@ -1424,7 +1424,7 @@ static int qxl_post_load(void *opaque, int version)
+         cmds[out].cmd.type = QXL_CMD_CURSOR;
+         cmds[out].group_id = MEMSLOT_GROUP_GUEST;
+         out++;
+-        d->ssd.worker->loadvm_commands(d->ssd.worker, cmds, out);
++        qemu_spice_loadvm_commands(&d->ssd, cmds, out);
+         qemu_free(cmds);
+ 
+         break;
+diff --git a/ui/spice-display.c b/ui/spice-display.c
+index feeee73..1e6a38f 100644
+--- a/ui/spice-display.c
++++ b/ui/spice-display.c
+@@ -62,6 +62,89 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
+     dest->right = MAX(dest->right, r->right);
+ }
+ 
++
++void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id,
++                            struct QXLRect *area, struct QXLRect *dirty_rects,
++                            uint32_t num_dirty_rects,
++                            uint32_t clear_dirty_region)
++{
++    ssd->worker->update_area(ssd->worker, surface_id, area, dirty_rects,
++                             num_dirty_rects, clear_dirty_region);
++}
++
++void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot)
++{
++    ssd->worker->add_memslot(ssd->worker, memslot);
++}
++
++void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
++{
++    ssd->worker->del_memslot(ssd->worker, gid, sid);
++}
++
++void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
++                                       QXLDevSurfaceCreate *surface)
++{
++    ssd->worker->create_primary_surface(ssd->worker, id, surface);
++}
++
++void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id)
++{
++    ssd->worker->destroy_primary_surface(ssd->worker, id);
++}
++
++void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id)
++{
++    ssd->worker->destroy_surface_wait(ssd->worker, id);
++}
++
++void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd,
++                                struct QXLCommandExt *ext, uint32_t count)
++{
++    ssd->worker->loadvm_commands(ssd->worker, ext, count);
++}
++
++void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
++{
++    ssd->worker->wakeup(ssd->worker);
++}
++
++void qemu_spice_oom(SimpleSpiceDisplay *ssd)
++{
++    ssd->worker->oom(ssd->worker);
++}
++
++void qemu_spice_start(SimpleSpiceDisplay *ssd)
++{
++    ssd->worker->start(ssd->worker);
++}
++
++void qemu_spice_stop(SimpleSpiceDisplay *ssd)
++{
++    ssd->worker->stop(ssd->worker);
++}
++
++void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd)
++{
++    ssd->worker->reset_memslots(ssd->worker);
++}
++
++void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd)
++{
++    ssd->worker->destroy_surfaces(ssd->worker);
++}
++
++void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd)
++{
++    ssd->worker->reset_image_cache(ssd->worker);
++}
++
++void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd)
++{
++    ssd->worker->reset_cursor(ssd->worker);
++}
++
++
+ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
+ {
+     SimpleSpiceUpdate *update;
+@@ -161,7 +244,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
+     memset(&memslot, 0, sizeof(memslot));
+     memslot.slot_group_id = MEMSLOT_GROUP_HOST;
+     memslot.virt_end = ~0;
+-    ssd->worker->add_memslot(ssd->worker, &memslot);
++    qemu_spice_add_memslot(ssd, &memslot);
+ }
+ 
+ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
+@@ -181,14 +264,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
+     surface.mem        = (intptr_t)ssd->buf;
+     surface.group_id   = MEMSLOT_GROUP_HOST;
+ 
+-    ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
++    qemu_spice_create_primary_surface(ssd, 0, &surface);
+ }
+ 
+ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
+ {
+     dprint(1, "%s:\n", __FUNCTION__);
+ 
+-    ssd->worker->destroy_primary_surface(ssd->worker, 0);
++    qemu_spice_destroy_primary_surface(ssd, 0);
+ }
+ 
+ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
+@@ -196,9 +279,9 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
+     SimpleSpiceDisplay *ssd = opaque;
+ 
+     if (running) {
+-        ssd->worker->start(ssd->worker);
++        qemu_spice_start(ssd);
+     } else {
+-        ssd->worker->stop(ssd->worker);
++        qemu_spice_stop(ssd);
+     }
+     ssd->running = running;
+ }
+@@ -267,7 +350,7 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
+ 
+     if (ssd->notify) {
+         ssd->notify = 0;
+-        ssd->worker->wakeup(ssd->worker);
++        qemu_spice_wakeup(ssd);
+         dprint(2, "%s: notify\n", __FUNCTION__);
+     }
+ }
+diff --git a/ui/spice-display.h b/ui/spice-display.h
+index 2f95f68..5b06b11 100644
+--- a/ui/spice-display.h
++++ b/ui/spice-display.h
+@@ -80,3 +80,25 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+                                int x, int y, int w, int h);
+ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
+ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
++
++void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id,
++                            struct QXLRect *area, struct QXLRect *dirty_rects,
++                            uint32_t num_dirty_rects,
++                            uint32_t clear_dirty_region);
++void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot);
++void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid,
++                            uint32_t sid);
++void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
++                                       QXLDevSurfaceCreate *surface);
++void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id);
++void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id);
++void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd,
++                                struct QXLCommandExt *ext, uint32_t count);
++void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
++void qemu_spice_oom(SimpleSpiceDisplay *ssd);
++void qemu_spice_start(SimpleSpiceDisplay *ssd);
++void qemu_spice_stop(SimpleSpiceDisplay *ssd);
++void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd);
++void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd);
++void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd);
++void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd);
+-- 
+1.7.5.1
+
diff --git a/0012-usb-redir-Call-qemu_chr_guest_open-close.patch b/0012-usb-redir-Call-qemu_chr_guest_open-close.patch
deleted file mode 100644
index cddbe9d..0000000
--- a/0012-usb-redir-Call-qemu_chr_guest_open-close.patch
+++ /dev/null
@@ -1,37 +0,0 @@
->From eea72a6f70c7b4cf632c3637e12d4689ce6ff0f5 Mon Sep 17 00:00:00 2001
-From: Hans de Goede <hdegoede@redhat.com>
-Date: Thu, 21 Jul 2011 16:28:06 +0200
-Subject: [PATCH 12/25] usb-redir: Call qemu_chr_guest_open/close
-
-To let the chardev now we're ready start receiving data. This is necessary
-with the spicevmc chardev to get it registered with the spice-server.
-
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
----
- usb-redir.c |    3 +++
- 1 files changed, 3 insertions(+), 0 deletions(-)
-
-diff --git a/usb-redir.c b/usb-redir.c
-index 6932beb..d1aafda 100644
---- a/usb-redir.c
-+++ b/usb-redir.c
-@@ -840,6 +840,8 @@ static int usbredir_initfn(USBDevice *udev)
-     udev->auto_attach = 0;
- 
-     qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev);
-+    /* Let the other side know we are ready */
-+    qemu_chr_guest_open(dev->cs);
- 
-     return 0;
- }
-@@ -861,6 +863,7 @@ static void usbredir_handle_destroy(USBDevice *udev)
- {
-     USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
- 
-+    qemu_chr_guest_close(dev->cs);
-     qemu_chr_close(dev->cs);
-     /* Note must be done after qemu_chr_close, as that causes a close event */
-     qemu_bh_delete(dev->open_close_bh);
--- 
-1.7.5.1
-
diff --git a/0013-spice-add-qemu_spice_display_init_common.patch b/0013-spice-add-qemu_spice_display_init_common.patch
new file mode 100644
index 0000000..d40d24e
--- /dev/null
+++ b/0013-spice-add-qemu_spice_display_init_common.patch
@@ -0,0 +1,84 @@
+>From c28ee0e7c851fc58ac6ef8f5137fc35cc55b607c Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+Date: Fri, 17 Jun 2011 10:42:25 +0200
+Subject: [PATCH 13/28] spice: add qemu_spice_display_init_common
+
+Factor out SimpleSpiceDisplay initialization into
+qemu_spice_display_init_common() and call it from
+both qxl.c (for vga mode) and spice-display.c
+
+Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
+---
+ hw/qxl.c           |    7 +------
+ ui/spice-display.c |   17 +++++++++++------
+ ui/spice-display.h |    1 +
+ 3 files changed, 13 insertions(+), 12 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 5deb776..2127fa3 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -1315,12 +1315,7 @@ static int qxl_init_primary(PCIDevice *dev)
+ 
+     vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate,
+                                    qxl_hw_screen_dump, qxl_hw_text_update, qxl);
+-    qxl->ssd.ds = vga->ds;
+-    qemu_mutex_init(&qxl->ssd.lock);
+-    qxl->ssd.mouse_x = -1;
+-    qxl->ssd.mouse_y = -1;
+-    qxl->ssd.bufsize = (16 * 1024 * 1024);
+-    qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize);
++    qemu_spice_display_init_common(&qxl->ssd, vga->ds);
+ 
+     qxl0 = qxl;
+     register_displaychangelistener(vga->ds, &display_listener);
+diff --git a/ui/spice-display.c b/ui/spice-display.c
+index 1e6a38f..93e25bf 100644
+--- a/ui/spice-display.c
++++ b/ui/spice-display.c
+@@ -286,6 +286,16 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
+     ssd->running = running;
+ }
+ 
++void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds)
++{
++    ssd->ds = ds;
++    qemu_mutex_init(&ssd->lock);
++    ssd->mouse_x = -1;
++    ssd->mouse_y = -1;
++    ssd->bufsize = (16 * 1024 * 1024);
++    ssd->buf = qemu_malloc(ssd->bufsize);
++}
++
+ /* display listener callbacks */
+ 
+ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+@@ -499,12 +509,7 @@ static DisplayChangeListener display_listener = {
+ void qemu_spice_display_init(DisplayState *ds)
+ {
+     assert(sdpy.ds == NULL);
+-    sdpy.ds = ds;
+-    qemu_mutex_init(&sdpy.lock);
+-    sdpy.mouse_x = -1;
+-    sdpy.mouse_y = -1;
+-    sdpy.bufsize = (16 * 1024 * 1024);
+-    sdpy.buf = qemu_malloc(sdpy.bufsize);
++    qemu_spice_display_init_common(&sdpy, ds);
+     register_displaychangelistener(ds, &display_listener);
+ 
+     sdpy.qxl.base.sif = &dpy_interface.base;
+diff --git a/ui/spice-display.h b/ui/spice-display.h
+index 5b06b11..eb7a573 100644
+--- a/ui/spice-display.h
++++ b/ui/spice-display.h
+@@ -75,6 +75,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd);
+ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd);
+ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd);
+ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason);
++void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds);
+ 
+ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+                                int x, int y, int w, int h);
+-- 
+1.7.5.1
+
diff --git a/0013-spice-qemu-char-Generate-chardev-open-close-events.patch b/0013-spice-qemu-char-Generate-chardev-open-close-events.patch
deleted file mode 100644
index 87e0f45..0000000
--- a/0013-spice-qemu-char-Generate-chardev-open-close-events.patch
+++ /dev/null
@@ -1,90 +0,0 @@
->From c79ffc7e3357317bd81f2abefa4743eaf8101a4e Mon Sep 17 00:00:00 2001
-From: Hans de Goede <hdegoede@redhat.com>
-Date: Thu, 21 Jul 2011 15:36:40 +0200
-Subject: [PATCH 13/25] spice-qemu-char: Generate chardev open/close events
-
-Define a state callback and make that generate chardev open/close events when
-called by the spice-server.
-
-Note that for all but the newest spice-server versions (which have a fix for
-this) the code ignores these events for a spicevmc with a subtype of vdagent,
-this subtype specific knowledge is undesirable, but unavoidable for now, see:
-http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html
-
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
----
- spice-qemu-char.c |   46 +++++++++++++++++++++++++++++++++++++++++++++-
- 1 files changed, 45 insertions(+), 1 deletions(-)
-
-diff --git a/spice-qemu-char.c b/spice-qemu-char.c
-index 2b8aec4..1f4f1ec 100644
---- a/spice-qemu-char.c
-+++ b/spice-qemu-char.c
-@@ -89,11 +89,50 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
-     return bytes;
- }
- 
-+static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
-+{
-+    SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
-+    int event;
-+
-+#if SPICE_SERVER_VERSION < 0x000901
-+    /*
-+     * spice-server calls the state callback for the agent channel when the
-+     * spice client connects / disconnects. Given that not the client but
-+     * the server is doing the parsing of the messages this is wrong as the
-+     * server is still listening. Worse, this causes the parser in the server
-+     * to go out of sync, so we ignore state calls for subtype vdagent
-+     * spicevmc chardevs. For the full story see:
-+     * http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html
-+     */
-+    if (strcmp(sin->subtype, "vdagent") == 0) {
-+        return;
-+    }
-+#endif
-+
-+    if ((scd->chr->opened && connected) ||
-+        (!scd->chr->opened && !connected)) {
-+        return;
-+    }
-+
-+    if (connected) {
-+        scd->chr->opened = 1;
-+        event = CHR_EVENT_OPENED;
-+    } else {
-+        scd->chr->opened = 0;
-+        event = CHR_EVENT_CLOSED;
-+    }
-+
-+    if (scd->chr->chr_event) {
-+        scd->chr->chr_event(scd->chr->handler_opaque, event);
-+    }
-+}
-+
- static SpiceCharDeviceInterface vmc_interface = {
-     .base.type          = SPICE_INTERFACE_CHAR_DEVICE,
-     .base.description   = "spice virtual channel char device",
-     .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
-     .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
-+    .state              = vmc_state,
-     .write              = vmc_write,
-     .read               = vmc_read,
- };
-@@ -222,7 +261,12 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr)
-     chr->chr_guest_close = spice_chr_guest_close;
-     s->unblock_timer = qemu_new_timer_ms(vm_clock, spice_chr_unblock, s);
- 
--    qemu_chr_generic_open(chr);
-+#if SPICE_SERVER_VERSION < 0x000901
-+    /* See comment in vmc_state() */
-+    if (strcmp(subtype, "vdagent") == 0) {
-+        qemu_chr_generic_open(chr);
-+    }
-+#endif
- 
-     *_chr = chr;
-     return 0;
--- 
-1.7.5.1
-
diff --git a/0014-spice-add-worker-wrapper-functions.patch b/0014-spice-add-worker-wrapper-functions.patch
deleted file mode 100644
index 2fcb2d8..0000000
--- a/0014-spice-add-worker-wrapper-functions.patch
+++ /dev/null
@@ -1,323 +0,0 @@
->From e52026748bb0b6e29f7703cc9fe8f8d6f5f345f8 Mon Sep 17 00:00:00 2001
-From: Gerd Hoffmann <kraxel@redhat.com>
-Date: Fri, 17 Jun 2011 10:34:25 +0200
-Subject: [PATCH 14/25] spice: add worker wrapper functions.
-
-Add wrapper functions for all spice worker calls.
-
-Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
----
- hw/qxl-render.c    |    4 +-
- hw/qxl.c           |   32 +++++++++---------
- ui/spice-display.c |   95 ++++++++++++++++++++++++++++++++++++++++++++++++---
- ui/spice-display.h |   22 ++++++++++++
- 4 files changed, 129 insertions(+), 24 deletions(-)
-
-diff --git a/hw/qxl-render.c b/hw/qxl-render.c
-index 1316066..bef5f14 100644
---- a/hw/qxl-render.c
-+++ b/hw/qxl-render.c
-@@ -124,8 +124,8 @@ void qxl_render_update(PCIQXLDevice *qxl)
-     update.bottom = qxl->guest_primary.surface.height;
- 
-     memset(dirty, 0, sizeof(dirty));
--    qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update,
--                                 dirty, ARRAY_SIZE(dirty), 1);
-+    qemu_spice_update_area(&qxl->ssd, 0, &update,
-+                           dirty, ARRAY_SIZE(dirty), 1);
- 
-     for (i = 0; i < ARRAY_SIZE(dirty); i++) {
-         if (qemu_spice_rect_is_empty(dirty+i)) {
-diff --git a/hw/qxl.c b/hw/qxl.c
-index a6fb7f0..5deb776 100644
---- a/hw/qxl.c
-+++ b/hw/qxl.c
-@@ -684,8 +684,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
-     dprint(d, 1, "%s: start%s\n", __FUNCTION__,
-            loadvm ? " (loadvm)" : "");
- 
--    d->ssd.worker->reset_cursor(d->ssd.worker);
--    d->ssd.worker->reset_image_cache(d->ssd.worker);
-+    qemu_spice_reset_cursor(&d->ssd);
-+    qemu_spice_reset_image_cache(&d->ssd);
-     qxl_reset_surfaces(d);
-     qxl_reset_memslots(d);
- 
-@@ -790,7 +790,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
-            __FUNCTION__, memslot.slot_id,
-            memslot.virt_start, memslot.virt_end);
- 
--    d->ssd.worker->add_memslot(d->ssd.worker, &memslot);
-+    qemu_spice_add_memslot(&d->ssd, &memslot);
-     d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
-     d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
-     d->guest_slots[slot_id].delta = delta;
-@@ -800,14 +800,14 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
- static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
- {
-     dprint(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id);
--    d->ssd.worker->del_memslot(d->ssd.worker, MEMSLOT_GROUP_HOST, slot_id);
-+    qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id);
-     d->guest_slots[slot_id].active = 0;
- }
- 
- static void qxl_reset_memslots(PCIQXLDevice *d)
- {
-     dprint(d, 1, "%s:\n", __FUNCTION__);
--    d->ssd.worker->reset_memslots(d->ssd.worker);
-+    qemu_spice_reset_memslots(&d->ssd);
-     memset(&d->guest_slots, 0, sizeof(d->guest_slots));
- }
- 
-@@ -815,7 +815,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
- {
-     dprint(d, 1, "%s:\n", __FUNCTION__);
-     d->mode = QXL_MODE_UNDEFINED;
--    d->ssd.worker->destroy_surfaces(d->ssd.worker);
-+    qemu_spice_destroy_surfaces(&d->ssd);
-     memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
- }
- 
-@@ -869,7 +869,7 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
- 
-     qxl->mode = QXL_MODE_NATIVE;
-     qxl->cmdflags = 0;
--    qxl->ssd.worker->create_primary_surface(qxl->ssd.worker, 0, &surface);
-+    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface);
- 
-     /* for local rendering */
-     qxl_render_resize(qxl);
-@@ -884,7 +884,7 @@ static void qxl_destroy_primary(PCIQXLDevice *d)
-     dprint(d, 1, "%s\n", __FUNCTION__);
- 
-     d->mode = QXL_MODE_UNDEFINED;
--    d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0);
-+    qemu_spice_destroy_primary_surface(&d->ssd, 0);
- }
- 
- static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
-@@ -956,15 +956,15 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-     case QXL_IO_UPDATE_AREA:
-     {
-         QXLRect update = d->ram->update_area;
--        d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface,
--                                   &update, NULL, 0, 0);
-+        qemu_spice_update_area(&d->ssd, d->ram->update_surface,
-+                               &update, NULL, 0, 0);
-         break;
-     }
-     case QXL_IO_NOTIFY_CMD:
--        d->ssd.worker->wakeup(d->ssd.worker);
-+        qemu_spice_wakeup(&d->ssd);
-         break;
-     case QXL_IO_NOTIFY_CURSOR:
--        d->ssd.worker->wakeup(d->ssd.worker);
-+        qemu_spice_wakeup(&d->ssd);
-         break;
-     case QXL_IO_UPDATE_IRQ:
-         qxl_set_irq(d);
-@@ -978,7 +978,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-             break;
-         }
-         d->oom_running = 1;
--        d->ssd.worker->oom(d->ssd.worker);
-+        qemu_spice_oom(&d->ssd);
-         d->oom_running = 0;
-         break;
-     case QXL_IO_SET_MODE:
-@@ -1016,10 +1016,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-         qxl_destroy_primary(d);
-         break;
-     case QXL_IO_DESTROY_SURFACE_WAIT:
--        d->ssd.worker->destroy_surface_wait(d->ssd.worker, val);
-+        qemu_spice_destroy_surface_wait(&d->ssd, val);
-         break;
-     case QXL_IO_DESTROY_ALL_SURFACES:
--        d->ssd.worker->destroy_surfaces(d->ssd.worker);
-+        qemu_spice_destroy_surfaces(&d->ssd);
-         break;
-     default:
-         fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
-@@ -1424,7 +1424,7 @@ static int qxl_post_load(void *opaque, int version)
-         cmds[out].cmd.type = QXL_CMD_CURSOR;
-         cmds[out].group_id = MEMSLOT_GROUP_GUEST;
-         out++;
--        d->ssd.worker->loadvm_commands(d->ssd.worker, cmds, out);
-+        qemu_spice_loadvm_commands(&d->ssd, cmds, out);
-         qemu_free(cmds);
- 
-         break;
-diff --git a/ui/spice-display.c b/ui/spice-display.c
-index feeee73..1e6a38f 100644
---- a/ui/spice-display.c
-+++ b/ui/spice-display.c
-@@ -62,6 +62,89 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
-     dest->right = MAX(dest->right, r->right);
- }
- 
-+
-+void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id,
-+                            struct QXLRect *area, struct QXLRect *dirty_rects,
-+                            uint32_t num_dirty_rects,
-+                            uint32_t clear_dirty_region)
-+{
-+    ssd->worker->update_area(ssd->worker, surface_id, area, dirty_rects,
-+                             num_dirty_rects, clear_dirty_region);
-+}
-+
-+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot)
-+{
-+    ssd->worker->add_memslot(ssd->worker, memslot);
-+}
-+
-+void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
-+{
-+    ssd->worker->del_memslot(ssd->worker, gid, sid);
-+}
-+
-+void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
-+                                       QXLDevSurfaceCreate *surface)
-+{
-+    ssd->worker->create_primary_surface(ssd->worker, id, surface);
-+}
-+
-+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id)
-+{
-+    ssd->worker->destroy_primary_surface(ssd->worker, id);
-+}
-+
-+void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id)
-+{
-+    ssd->worker->destroy_surface_wait(ssd->worker, id);
-+}
-+
-+void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd,
-+                                struct QXLCommandExt *ext, uint32_t count)
-+{
-+    ssd->worker->loadvm_commands(ssd->worker, ext, count);
-+}
-+
-+void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
-+{
-+    ssd->worker->wakeup(ssd->worker);
-+}
-+
-+void qemu_spice_oom(SimpleSpiceDisplay *ssd)
-+{
-+    ssd->worker->oom(ssd->worker);
-+}
-+
-+void qemu_spice_start(SimpleSpiceDisplay *ssd)
-+{
-+    ssd->worker->start(ssd->worker);
-+}
-+
-+void qemu_spice_stop(SimpleSpiceDisplay *ssd)
-+{
-+    ssd->worker->stop(ssd->worker);
-+}
-+
-+void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd)
-+{
-+    ssd->worker->reset_memslots(ssd->worker);
-+}
-+
-+void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd)
-+{
-+    ssd->worker->destroy_surfaces(ssd->worker);
-+}
-+
-+void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd)
-+{
-+    ssd->worker->reset_image_cache(ssd->worker);
-+}
-+
-+void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd)
-+{
-+    ssd->worker->reset_cursor(ssd->worker);
-+}
-+
-+
- static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
- {
-     SimpleSpiceUpdate *update;
-@@ -161,7 +244,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
-     memset(&memslot, 0, sizeof(memslot));
-     memslot.slot_group_id = MEMSLOT_GROUP_HOST;
-     memslot.virt_end = ~0;
--    ssd->worker->add_memslot(ssd->worker, &memslot);
-+    qemu_spice_add_memslot(ssd, &memslot);
- }
- 
- void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
-@@ -181,14 +264,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
-     surface.mem        = (intptr_t)ssd->buf;
-     surface.group_id   = MEMSLOT_GROUP_HOST;
- 
--    ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
-+    qemu_spice_create_primary_surface(ssd, 0, &surface);
- }
- 
- void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
- {
-     dprint(1, "%s:\n", __FUNCTION__);
- 
--    ssd->worker->destroy_primary_surface(ssd->worker, 0);
-+    qemu_spice_destroy_primary_surface(ssd, 0);
- }
- 
- void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
-@@ -196,9 +279,9 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
-     SimpleSpiceDisplay *ssd = opaque;
- 
-     if (running) {
--        ssd->worker->start(ssd->worker);
-+        qemu_spice_start(ssd);
-     } else {
--        ssd->worker->stop(ssd->worker);
-+        qemu_spice_stop(ssd);
-     }
-     ssd->running = running;
- }
-@@ -267,7 +350,7 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
- 
-     if (ssd->notify) {
-         ssd->notify = 0;
--        ssd->worker->wakeup(ssd->worker);
-+        qemu_spice_wakeup(ssd);
-         dprint(2, "%s: notify\n", __FUNCTION__);
-     }
- }
-diff --git a/ui/spice-display.h b/ui/spice-display.h
-index 2f95f68..5b06b11 100644
---- a/ui/spice-display.h
-+++ b/ui/spice-display.h
-@@ -80,3 +80,25 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
-                                int x, int y, int w, int h);
- void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
- void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
-+
-+void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id,
-+                            struct QXLRect *area, struct QXLRect *dirty_rects,
-+                            uint32_t num_dirty_rects,
-+                            uint32_t clear_dirty_region);
-+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot);
-+void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid,
-+                            uint32_t sid);
-+void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
-+                                       QXLDevSurfaceCreate *surface);
-+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id);
-+void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id);
-+void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd,
-+                                struct QXLCommandExt *ext, uint32_t count);
-+void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
-+void qemu_spice_oom(SimpleSpiceDisplay *ssd);
-+void qemu_spice_start(SimpleSpiceDisplay *ssd);
-+void qemu_spice_stop(SimpleSpiceDisplay *ssd);
-+void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd);
-+void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd);
-+void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd);
-+void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd);
--- 
-1.7.5.1
-
diff --git a/0014-spice-qxl-move-worker-wrappers.patch b/0014-spice-qxl-move-worker-wrappers.patch
new file mode 100644
index 0000000..ef804d6
--- /dev/null
+++ b/0014-spice-qxl-move-worker-wrappers.patch
@@ -0,0 +1,294 @@
+>From 60257c766e7a39134a9db9f4d1111f2b9fea2f86 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+Date: Wed, 29 Jun 2011 10:07:52 +0200
+Subject: [PATCH 14/28] spice/qxl: move worker wrappers
+
+Move the wrapper functions which are used by qxl only to qxl.c.
+Rename them from qemu_spice_* to qxl_spice_*.  Also pass in a
+qxl state pointer instead of a SimpleSpiceDisplay pointer.
+
+Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
+---
+ hw/qxl-render.c    |    4 +-
+ hw/qxl.c           |   67 ++++++++++++++++++++++++++++++++++++++++++++-------
+ hw/qxl.h           |   13 ++++++++++
+ ui/spice-display.c |   46 -----------------------------------
+ ui/spice-display.h |   12 ---------
+ 5 files changed, 72 insertions(+), 70 deletions(-)
+
+diff --git a/hw/qxl-render.c b/hw/qxl-render.c
+index bef5f14..60b822d 100644
+--- a/hw/qxl-render.c
++++ b/hw/qxl-render.c
+@@ -124,8 +124,8 @@ void qxl_render_update(PCIQXLDevice *qxl)
+     update.bottom = qxl->guest_primary.surface.height;
+ 
+     memset(dirty, 0, sizeof(dirty));
+-    qemu_spice_update_area(&qxl->ssd, 0, &update,
+-                           dirty, ARRAY_SIZE(dirty), 1);
++    qxl_spice_update_area(qxl, 0, &update,
++                          dirty, ARRAY_SIZE(dirty), 1);
+ 
+     for (i = 0; i < ARRAY_SIZE(dirty); i++) {
+         if (qemu_spice_rect_is_empty(dirty+i)) {
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 2127fa3..803a364 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -125,6 +125,53 @@ static void qxl_reset_memslots(PCIQXLDevice *d);
+ static void qxl_reset_surfaces(PCIQXLDevice *d);
+ static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
+ 
++
++void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
++                           struct QXLRect *area, struct QXLRect *dirty_rects,
++                           uint32_t num_dirty_rects,
++                           uint32_t clear_dirty_region)
++{
++    qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, dirty_rects,
++                             num_dirty_rects, clear_dirty_region);
++}
++
++void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id)
++{
++    qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
++}
++
++void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
++                               uint32_t count)
++{
++    qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count);
++}
++
++void qxl_spice_oom(PCIQXLDevice *qxl)
++{
++    qxl->ssd.worker->oom(qxl->ssd.worker);
++}
++
++void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
++{
++    qxl->ssd.worker->reset_memslots(qxl->ssd.worker);
++}
++
++void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl)
++{
++    qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
++}
++
++void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
++{
++    qxl->ssd.worker->reset_image_cache(qxl->ssd.worker);
++}
++
++void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
++{
++    qxl->ssd.worker->reset_cursor(qxl->ssd.worker);
++}
++
++
+ static inline uint32_t msb_mask(uint32_t val)
+ {
+     uint32_t mask;
+@@ -684,8 +731,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
+     dprint(d, 1, "%s: start%s\n", __FUNCTION__,
+            loadvm ? " (loadvm)" : "");
+ 
+-    qemu_spice_reset_cursor(&d->ssd);
+-    qemu_spice_reset_image_cache(&d->ssd);
++    qxl_spice_reset_cursor(d);
++    qxl_spice_reset_image_cache(d);
+     qxl_reset_surfaces(d);
+     qxl_reset_memslots(d);
+ 
+@@ -807,7 +854,7 @@ static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
+ static void qxl_reset_memslots(PCIQXLDevice *d)
+ {
+     dprint(d, 1, "%s:\n", __FUNCTION__);
+-    qemu_spice_reset_memslots(&d->ssd);
++    qxl_spice_reset_memslots(d);
+     memset(&d->guest_slots, 0, sizeof(d->guest_slots));
+ }
+ 
+@@ -815,7 +862,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
+ {
+     dprint(d, 1, "%s:\n", __FUNCTION__);
+     d->mode = QXL_MODE_UNDEFINED;
+-    qemu_spice_destroy_surfaces(&d->ssd);
++    qxl_spice_destroy_surfaces(d);
+     memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
+ }
+ 
+@@ -956,8 +1003,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+     case QXL_IO_UPDATE_AREA:
+     {
+         QXLRect update = d->ram->update_area;
+-        qemu_spice_update_area(&d->ssd, d->ram->update_surface,
+-                               &update, NULL, 0, 0);
++        qxl_spice_update_area(d, d->ram->update_surface,
++                              &update, NULL, 0, 0);
+         break;
+     }
+     case QXL_IO_NOTIFY_CMD:
+@@ -978,7 +1025,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+             break;
+         }
+         d->oom_running = 1;
+-        qemu_spice_oom(&d->ssd);
++        qxl_spice_oom(d);
+         d->oom_running = 0;
+         break;
+     case QXL_IO_SET_MODE:
+@@ -1016,10 +1063,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+         qxl_destroy_primary(d);
+         break;
+     case QXL_IO_DESTROY_SURFACE_WAIT:
+-        qemu_spice_destroy_surface_wait(&d->ssd, val);
++        qxl_spice_destroy_surface_wait(d, val);
+         break;
+     case QXL_IO_DESTROY_ALL_SURFACES:
+-        qemu_spice_destroy_surfaces(&d->ssd);
++        qxl_spice_destroy_surfaces(d);
+         break;
+     default:
+         fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
+@@ -1419,7 +1466,7 @@ static int qxl_post_load(void *opaque, int version)
+         cmds[out].cmd.type = QXL_CMD_CURSOR;
+         cmds[out].group_id = MEMSLOT_GROUP_GUEST;
+         out++;
+-        qemu_spice_loadvm_commands(&d->ssd, cmds, out);
++        qxl_spice_loadvm_commands(d, cmds, out);
+         qemu_free(cmds);
+ 
+         break;
+diff --git a/hw/qxl.h b/hw/qxl.h
+index f6c450d..e62b9d0 100644
+--- a/hw/qxl.h
++++ b/hw/qxl.h
+@@ -98,6 +98,19 @@ typedef struct PCIQXLDevice {
+ /* qxl.c */
+ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
+ 
++void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
++                           struct QXLRect *area, struct QXLRect *dirty_rects,
++                           uint32_t num_dirty_rects,
++                           uint32_t clear_dirty_region);
++void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id);
++void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
++                               uint32_t count);
++void qxl_spice_oom(PCIQXLDevice *qxl);
++void qxl_spice_reset_memslots(PCIQXLDevice *qxl);
++void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl);
++void qxl_spice_reset_image_cache(PCIQXLDevice *qxl);
++void qxl_spice_reset_cursor(PCIQXLDevice *qxl);
++
+ /* qxl-logger.c */
+ void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
+ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
+diff --git a/ui/spice-display.c b/ui/spice-display.c
+index 93e25bf..af10ae8 100644
+--- a/ui/spice-display.c
++++ b/ui/spice-display.c
+@@ -63,15 +63,6 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
+ }
+ 
+ 
+-void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id,
+-                            struct QXLRect *area, struct QXLRect *dirty_rects,
+-                            uint32_t num_dirty_rects,
+-                            uint32_t clear_dirty_region)
+-{
+-    ssd->worker->update_area(ssd->worker, surface_id, area, dirty_rects,
+-                             num_dirty_rects, clear_dirty_region);
+-}
+-
+ void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot)
+ {
+     ssd->worker->add_memslot(ssd->worker, memslot);
+@@ -93,27 +84,11 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id)
+     ssd->worker->destroy_primary_surface(ssd->worker, id);
+ }
+ 
+-void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id)
+-{
+-    ssd->worker->destroy_surface_wait(ssd->worker, id);
+-}
+-
+-void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd,
+-                                struct QXLCommandExt *ext, uint32_t count)
+-{
+-    ssd->worker->loadvm_commands(ssd->worker, ext, count);
+-}
+-
+ void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
+ {
+     ssd->worker->wakeup(ssd->worker);
+ }
+ 
+-void qemu_spice_oom(SimpleSpiceDisplay *ssd)
+-{
+-    ssd->worker->oom(ssd->worker);
+-}
+-
+ void qemu_spice_start(SimpleSpiceDisplay *ssd)
+ {
+     ssd->worker->start(ssd->worker);
+@@ -124,27 +99,6 @@ void qemu_spice_stop(SimpleSpiceDisplay *ssd)
+     ssd->worker->stop(ssd->worker);
+ }
+ 
+-void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd)
+-{
+-    ssd->worker->reset_memslots(ssd->worker);
+-}
+-
+-void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd)
+-{
+-    ssd->worker->destroy_surfaces(ssd->worker);
+-}
+-
+-void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd)
+-{
+-    ssd->worker->reset_image_cache(ssd->worker);
+-}
+-
+-void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd)
+-{
+-    ssd->worker->reset_cursor(ssd->worker);
+-}
+-
+-
+ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
+ {
+     SimpleSpiceUpdate *update;
+diff --git a/ui/spice-display.h b/ui/spice-display.h
+index eb7a573..abe99c7 100644
+--- a/ui/spice-display.h
++++ b/ui/spice-display.h
+@@ -82,24 +82,12 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
+ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
+ 
+-void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id,
+-                            struct QXLRect *area, struct QXLRect *dirty_rects,
+-                            uint32_t num_dirty_rects,
+-                            uint32_t clear_dirty_region);
+ void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot);
+ void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid,
+                             uint32_t sid);
+ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
+                                        QXLDevSurfaceCreate *surface);
+ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id);
+-void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id);
+-void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd,
+-                                struct QXLCommandExt *ext, uint32_t count);
+ void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
+-void qemu_spice_oom(SimpleSpiceDisplay *ssd);
+ void qemu_spice_start(SimpleSpiceDisplay *ssd);
+ void qemu_spice_stop(SimpleSpiceDisplay *ssd);
+-void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd);
+-void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd);
+-void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd);
+-void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd);
+-- 
+1.7.5.1
+
diff --git a/0015-qxl-fix-surface-tracking-locking.patch b/0015-qxl-fix-surface-tracking-locking.patch
new file mode 100644
index 0000000..c5bd1ee
--- /dev/null
+++ b/0015-qxl-fix-surface-tracking-locking.patch
@@ -0,0 +1,92 @@
+>From b2b956cfda5fb144d9faa10b7c5894833feb7d30 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+Date: Wed, 29 Jun 2011 10:24:05 +0200
+Subject: [PATCH 15/28] qxl: fix surface tracking & locking
+
+Surface tracking needs proper locking since it is used from vcpu and spice
+worker threads, add it.  Also reset the surface counter when zapping all
+surfaces.
+
+Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
+---
+ hw/qxl.c |   13 ++++++++++++-
+ hw/qxl.h |    2 ++
+ 2 files changed, 14 insertions(+), 1 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 803a364..416bd48 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -137,7 +137,12 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+ 
+ void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id)
+ {
++    qemu_mutex_lock(&qxl->track_lock);
++    PANIC_ON(id >= NUM_SURFACES);
+     qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
++    qxl->guest_surfaces.cmds[id] = 0;
++    qxl->guest_surfaces.count--;
++    qemu_mutex_unlock(&qxl->track_lock);
+ }
+ 
+ void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
+@@ -158,7 +163,11 @@ void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
+ 
+ void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl)
+ {
++    qemu_mutex_lock(&qxl->track_lock);
+     qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
++    memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds));
++    qxl->guest_surfaces.count = 0;
++    qemu_mutex_unlock(&qxl->track_lock);
+ }
+ 
+ void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
+@@ -317,6 +326,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
+         QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+         uint32_t id = le32_to_cpu(cmd->surface_id);
+         PANIC_ON(id >= NUM_SURFACES);
++        qemu_mutex_lock(&qxl->track_lock);
+         if (cmd->type == QXL_SURFACE_CMD_CREATE) {
+             qxl->guest_surfaces.cmds[id] = ext->cmd.data;
+             qxl->guest_surfaces.count++;
+@@ -327,6 +337,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
+             qxl->guest_surfaces.cmds[id] = 0;
+             qxl->guest_surfaces.count--;
+         }
++        qemu_mutex_unlock(&qxl->track_lock);
+         break;
+     }
+     case QXL_CMD_CURSOR:
+@@ -863,7 +874,6 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
+     dprint(d, 1, "%s:\n", __FUNCTION__);
+     d->mode = QXL_MODE_UNDEFINED;
+     qxl_spice_destroy_surfaces(d);
+-    memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
+ }
+ 
+ /* called from spice server thread context only */
+@@ -1283,6 +1293,7 @@ static int qxl_init_common(PCIQXLDevice *qxl)
+     qxl->generation = 1;
+     qxl->num_memslots = NUM_MEMSLOTS;
+     qxl->num_surfaces = NUM_SURFACES;
++    qemu_mutex_init(&qxl->track_lock);
+ 
+     switch (qxl->revision) {
+     case 1: /* spice 0.4 -- qxl-1 */
+diff --git a/hw/qxl.h b/hw/qxl.h
+index e62b9d0..5d0e85e 100644
+--- a/hw/qxl.h
++++ b/hw/qxl.h
+@@ -55,6 +55,8 @@ typedef struct PCIQXLDevice {
+     } guest_surfaces;
+     QXLPHYSICAL        guest_cursor;
+ 
++    QemuMutex          track_lock;
++
+     /* thread signaling */
+     pthread_t          main;
+     int                pipe[2];
+-- 
+1.7.5.1
+
diff --git a/0015-spice-add-qemu_spice_display_init_common.patch b/0015-spice-add-qemu_spice_display_init_common.patch
deleted file mode 100644
index 23a1fe2..0000000
--- a/0015-spice-add-qemu_spice_display_init_common.patch
+++ /dev/null
@@ -1,84 +0,0 @@
->From 1de5cd33d8c1ffa35b5bcdf703d4b097284edda0 Mon Sep 17 00:00:00 2001
-From: Gerd Hoffmann <kraxel@redhat.com>
-Date: Fri, 17 Jun 2011 10:42:25 +0200
-Subject: [PATCH 15/25] spice: add qemu_spice_display_init_common
-
-Factor out SimpleSpiceDisplay initialization into
-qemu_spice_display_init_common() and call it from
-both qxl.c (for vga mode) and spice-display.c
-
-Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
----
- hw/qxl.c           |    7 +------
- ui/spice-display.c |   17 +++++++++++------
- ui/spice-display.h |    1 +
- 3 files changed, 13 insertions(+), 12 deletions(-)
-
-diff --git a/hw/qxl.c b/hw/qxl.c
-index 5deb776..2127fa3 100644
---- a/hw/qxl.c
-+++ b/hw/qxl.c
-@@ -1315,12 +1315,7 @@ static int qxl_init_primary(PCIDevice *dev)
- 
-     vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate,
-                                    qxl_hw_screen_dump, qxl_hw_text_update, qxl);
--    qxl->ssd.ds = vga->ds;
--    qemu_mutex_init(&qxl->ssd.lock);
--    qxl->ssd.mouse_x = -1;
--    qxl->ssd.mouse_y = -1;
--    qxl->ssd.bufsize = (16 * 1024 * 1024);
--    qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize);
-+    qemu_spice_display_init_common(&qxl->ssd, vga->ds);
- 
-     qxl0 = qxl;
-     register_displaychangelistener(vga->ds, &display_listener);
-diff --git a/ui/spice-display.c b/ui/spice-display.c
-index 1e6a38f..93e25bf 100644
---- a/ui/spice-display.c
-+++ b/ui/spice-display.c
-@@ -286,6 +286,16 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
-     ssd->running = running;
- }
- 
-+void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds)
-+{
-+    ssd->ds = ds;
-+    qemu_mutex_init(&ssd->lock);
-+    ssd->mouse_x = -1;
-+    ssd->mouse_y = -1;
-+    ssd->bufsize = (16 * 1024 * 1024);
-+    ssd->buf = qemu_malloc(ssd->bufsize);
-+}
-+
- /* display listener callbacks */
- 
- void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
-@@ -499,12 +509,7 @@ static DisplayChangeListener display_listener = {
- void qemu_spice_display_init(DisplayState *ds)
- {
-     assert(sdpy.ds == NULL);
--    sdpy.ds = ds;
--    qemu_mutex_init(&sdpy.lock);
--    sdpy.mouse_x = -1;
--    sdpy.mouse_y = -1;
--    sdpy.bufsize = (16 * 1024 * 1024);
--    sdpy.buf = qemu_malloc(sdpy.bufsize);
-+    qemu_spice_display_init_common(&sdpy, ds);
-     register_displaychangelistener(ds, &display_listener);
- 
-     sdpy.qxl.base.sif = &dpy_interface.base;
-diff --git a/ui/spice-display.h b/ui/spice-display.h
-index 5b06b11..eb7a573 100644
---- a/ui/spice-display.h
-+++ b/ui/spice-display.h
-@@ -75,6 +75,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd);
- void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd);
- void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd);
- void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason);
-+void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds);
- 
- void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
-                                int x, int y, int w, int h);
--- 
-1.7.5.1
-
diff --git a/0016-qxl-add-io_port_to_string.patch b/0016-qxl-add-io_port_to_string.patch
new file mode 100644
index 0000000..a47328c
--- /dev/null
+++ b/0016-qxl-add-io_port_to_string.patch
@@ -0,0 +1,71 @@
+>From 31c995f6ee18ff2e2b45dbdcf1d57f777d1e0ef9 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy@redhat.com>
+Date: Fri, 17 Jun 2011 14:42:09 +0200
+Subject: [PATCH 16/28] qxl: add io_port_to_string
+
+Signed-off-by: Alon Levy <alevy@redhat.com>
+---
+ hw/qxl.c |   40 +++++++++++++++++++++++++++++++++++++++-
+ 1 files changed, 39 insertions(+), 1 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 416bd48..6e66021 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -409,6 +409,43 @@ static const char *qxl_mode_to_string(int mode)
+     return "INVALID";
+ }
+ 
++static const char *io_port_to_string(uint32_t io_port)
++{
++    if (io_port >= QXL_IO_RANGE_SIZE) {
++        return "out of range";
++    }
++    static const char *io_port_to_string[QXL_IO_RANGE_SIZE + 1] = {
++        [QXL_IO_NOTIFY_CMD]             = "QXL_IO_NOTIFY_CMD",
++        [QXL_IO_NOTIFY_CURSOR]          = "QXL_IO_NOTIFY_CURSOR",
++        [QXL_IO_UPDATE_AREA]            = "QXL_IO_UPDATE_AREA",
++        [QXL_IO_UPDATE_IRQ]             = "QXL_IO_UPDATE_IRQ",
++        [QXL_IO_NOTIFY_OOM]             = "QXL_IO_NOTIFY_OOM",
++        [QXL_IO_RESET]                  = "QXL_IO_RESET",
++        [QXL_IO_SET_MODE]               = "QXL_IO_SET_MODE",
++        [QXL_IO_LOG]                    = "QXL_IO_LOG",
++        [QXL_IO_MEMSLOT_ADD]            = "QXL_IO_MEMSLOT_ADD",
++        [QXL_IO_MEMSLOT_DEL]            = "QXL_IO_MEMSLOT_DEL",
++        [QXL_IO_DETACH_PRIMARY]         = "QXL_IO_DETACH_PRIMARY",
++        [QXL_IO_ATTACH_PRIMARY]         = "QXL_IO_ATTACH_PRIMARY",
++        [QXL_IO_CREATE_PRIMARY]         = "QXL_IO_CREATE_PRIMARY",
++        [QXL_IO_DESTROY_PRIMARY]        = "QXL_IO_DESTROY_PRIMARY",
++        [QXL_IO_DESTROY_SURFACE_WAIT]   = "QXL_IO_DESTROY_SURFACE_WAIT",
++        [QXL_IO_DESTROY_ALL_SURFACES]   = "QXL_IO_DESTROY_ALL_SURFACES",
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++        [QXL_IO_UPDATE_AREA_ASYNC]      = "QXL_IO_UPDATE_AREA_ASYNC",
++        [QXL_IO_MEMSLOT_ADD_ASYNC]      = "QXL_IO_MEMSLOT_ADD_ASYNC",
++        [QXL_IO_CREATE_PRIMARY_ASYNC]   = "QXL_IO_CREATE_PRIMARY_ASYNC",
++        [QXL_IO_DESTROY_PRIMARY_ASYNC]  = "QXL_IO_DESTROY_PRIMARY_ASYNC",
++        [QXL_IO_DESTROY_SURFACE_ASYNC]  = "QXL_IO_DESTROY_SURFACE_ASYNC",
++        [QXL_IO_DESTROY_ALL_SURFACES_ASYNC]
++                                        = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
++        [QXL_IO_FLUSH_SURFACES_ASYNC]   = "QXL_IO_FLUSH_SURFACES_ASYNC",
++        [QXL_IO_FLUSH_RELEASE]          = "QXL_IO_FLUSH_RELEASE",
++#endif
++    };
++    return io_port_to_string[io_port];
++}
++
+ /* called from spice server thread context only */
+ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
+ {
+@@ -1005,7 +1042,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+     default:
+         if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT)
+             break;
+-        dprint(d, 1, "%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port);
++        dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n",
++            __func__, io_port, io_port_to_string(io_port));
+         return;
+     }
+ 
+-- 
+1.7.5.1
+
diff --git a/0016-spice-qxl-move-worker-wrappers.patch b/0016-spice-qxl-move-worker-wrappers.patch
deleted file mode 100644
index 55b7bf5..0000000
--- a/0016-spice-qxl-move-worker-wrappers.patch
+++ /dev/null
@@ -1,294 +0,0 @@
->From b1fef6eecf09404114ca016aa090cffa183d40f1 Mon Sep 17 00:00:00 2001
-From: Gerd Hoffmann <kraxel@redhat.com>
-Date: Wed, 29 Jun 2011 10:07:52 +0200
-Subject: [PATCH 16/25] spice/qxl: move worker wrappers
-
-Move the wrapper functions which are used by qxl only to qxl.c.
-Rename them from qemu_spice_* to qxl_spice_*.  Also pass in a
-qxl state pointer instead of a SimpleSpiceDisplay pointer.
-
-Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
----
- hw/qxl-render.c    |    4 +-
- hw/qxl.c           |   67 ++++++++++++++++++++++++++++++++++++++++++++-------
- hw/qxl.h           |   13 ++++++++++
- ui/spice-display.c |   46 -----------------------------------
- ui/spice-display.h |   12 ---------
- 5 files changed, 72 insertions(+), 70 deletions(-)
-
-diff --git a/hw/qxl-render.c b/hw/qxl-render.c
-index bef5f14..60b822d 100644
---- a/hw/qxl-render.c
-+++ b/hw/qxl-render.c
-@@ -124,8 +124,8 @@ void qxl_render_update(PCIQXLDevice *qxl)
-     update.bottom = qxl->guest_primary.surface.height;
- 
-     memset(dirty, 0, sizeof(dirty));
--    qemu_spice_update_area(&qxl->ssd, 0, &update,
--                           dirty, ARRAY_SIZE(dirty), 1);
-+    qxl_spice_update_area(qxl, 0, &update,
-+                          dirty, ARRAY_SIZE(dirty), 1);
- 
-     for (i = 0; i < ARRAY_SIZE(dirty); i++) {
-         if (qemu_spice_rect_is_empty(dirty+i)) {
-diff --git a/hw/qxl.c b/hw/qxl.c
-index 2127fa3..803a364 100644
---- a/hw/qxl.c
-+++ b/hw/qxl.c
-@@ -125,6 +125,53 @@ static void qxl_reset_memslots(PCIQXLDevice *d);
- static void qxl_reset_surfaces(PCIQXLDevice *d);
- static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
- 
-+
-+void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
-+                           struct QXLRect *area, struct QXLRect *dirty_rects,
-+                           uint32_t num_dirty_rects,
-+                           uint32_t clear_dirty_region)
-+{
-+    qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, dirty_rects,
-+                             num_dirty_rects, clear_dirty_region);
-+}
-+
-+void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id)
-+{
-+    qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
-+}
-+
-+void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
-+                               uint32_t count)
-+{
-+    qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count);
-+}
-+
-+void qxl_spice_oom(PCIQXLDevice *qxl)
-+{
-+    qxl->ssd.worker->oom(qxl->ssd.worker);
-+}
-+
-+void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
-+{
-+    qxl->ssd.worker->reset_memslots(qxl->ssd.worker);
-+}
-+
-+void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl)
-+{
-+    qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
-+}
-+
-+void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
-+{
-+    qxl->ssd.worker->reset_image_cache(qxl->ssd.worker);
-+}
-+
-+void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
-+{
-+    qxl->ssd.worker->reset_cursor(qxl->ssd.worker);
-+}
-+
-+
- static inline uint32_t msb_mask(uint32_t val)
- {
-     uint32_t mask;
-@@ -684,8 +731,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
-     dprint(d, 1, "%s: start%s\n", __FUNCTION__,
-            loadvm ? " (loadvm)" : "");
- 
--    qemu_spice_reset_cursor(&d->ssd);
--    qemu_spice_reset_image_cache(&d->ssd);
-+    qxl_spice_reset_cursor(d);
-+    qxl_spice_reset_image_cache(d);
-     qxl_reset_surfaces(d);
-     qxl_reset_memslots(d);
- 
-@@ -807,7 +854,7 @@ static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
- static void qxl_reset_memslots(PCIQXLDevice *d)
- {
-     dprint(d, 1, "%s:\n", __FUNCTION__);
--    qemu_spice_reset_memslots(&d->ssd);
-+    qxl_spice_reset_memslots(d);
-     memset(&d->guest_slots, 0, sizeof(d->guest_slots));
- }
- 
-@@ -815,7 +862,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
- {
-     dprint(d, 1, "%s:\n", __FUNCTION__);
-     d->mode = QXL_MODE_UNDEFINED;
--    qemu_spice_destroy_surfaces(&d->ssd);
-+    qxl_spice_destroy_surfaces(d);
-     memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
- }
- 
-@@ -956,8 +1003,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-     case QXL_IO_UPDATE_AREA:
-     {
-         QXLRect update = d->ram->update_area;
--        qemu_spice_update_area(&d->ssd, d->ram->update_surface,
--                               &update, NULL, 0, 0);
-+        qxl_spice_update_area(d, d->ram->update_surface,
-+                              &update, NULL, 0, 0);
-         break;
-     }
-     case QXL_IO_NOTIFY_CMD:
-@@ -978,7 +1025,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-             break;
-         }
-         d->oom_running = 1;
--        qemu_spice_oom(&d->ssd);
-+        qxl_spice_oom(d);
-         d->oom_running = 0;
-         break;
-     case QXL_IO_SET_MODE:
-@@ -1016,10 +1063,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-         qxl_destroy_primary(d);
-         break;
-     case QXL_IO_DESTROY_SURFACE_WAIT:
--        qemu_spice_destroy_surface_wait(&d->ssd, val);
-+        qxl_spice_destroy_surface_wait(d, val);
-         break;
-     case QXL_IO_DESTROY_ALL_SURFACES:
--        qemu_spice_destroy_surfaces(&d->ssd);
-+        qxl_spice_destroy_surfaces(d);
-         break;
-     default:
-         fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
-@@ -1419,7 +1466,7 @@ static int qxl_post_load(void *opaque, int version)
-         cmds[out].cmd.type = QXL_CMD_CURSOR;
-         cmds[out].group_id = MEMSLOT_GROUP_GUEST;
-         out++;
--        qemu_spice_loadvm_commands(&d->ssd, cmds, out);
-+        qxl_spice_loadvm_commands(d, cmds, out);
-         qemu_free(cmds);
- 
-         break;
-diff --git a/hw/qxl.h b/hw/qxl.h
-index f6c450d..e62b9d0 100644
---- a/hw/qxl.h
-+++ b/hw/qxl.h
-@@ -98,6 +98,19 @@ typedef struct PCIQXLDevice {
- /* qxl.c */
- void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
- 
-+void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
-+                           struct QXLRect *area, struct QXLRect *dirty_rects,
-+                           uint32_t num_dirty_rects,
-+                           uint32_t clear_dirty_region);
-+void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id);
-+void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
-+                               uint32_t count);
-+void qxl_spice_oom(PCIQXLDevice *qxl);
-+void qxl_spice_reset_memslots(PCIQXLDevice *qxl);
-+void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl);
-+void qxl_spice_reset_image_cache(PCIQXLDevice *qxl);
-+void qxl_spice_reset_cursor(PCIQXLDevice *qxl);
-+
- /* qxl-logger.c */
- void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
- void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
-diff --git a/ui/spice-display.c b/ui/spice-display.c
-index 93e25bf..af10ae8 100644
---- a/ui/spice-display.c
-+++ b/ui/spice-display.c
-@@ -63,15 +63,6 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
- }
- 
- 
--void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id,
--                            struct QXLRect *area, struct QXLRect *dirty_rects,
--                            uint32_t num_dirty_rects,
--                            uint32_t clear_dirty_region)
--{
--    ssd->worker->update_area(ssd->worker, surface_id, area, dirty_rects,
--                             num_dirty_rects, clear_dirty_region);
--}
--
- void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot)
- {
-     ssd->worker->add_memslot(ssd->worker, memslot);
-@@ -93,27 +84,11 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id)
-     ssd->worker->destroy_primary_surface(ssd->worker, id);
- }
- 
--void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id)
--{
--    ssd->worker->destroy_surface_wait(ssd->worker, id);
--}
--
--void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd,
--                                struct QXLCommandExt *ext, uint32_t count)
--{
--    ssd->worker->loadvm_commands(ssd->worker, ext, count);
--}
--
- void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
- {
-     ssd->worker->wakeup(ssd->worker);
- }
- 
--void qemu_spice_oom(SimpleSpiceDisplay *ssd)
--{
--    ssd->worker->oom(ssd->worker);
--}
--
- void qemu_spice_start(SimpleSpiceDisplay *ssd)
- {
-     ssd->worker->start(ssd->worker);
-@@ -124,27 +99,6 @@ void qemu_spice_stop(SimpleSpiceDisplay *ssd)
-     ssd->worker->stop(ssd->worker);
- }
- 
--void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd)
--{
--    ssd->worker->reset_memslots(ssd->worker);
--}
--
--void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd)
--{
--    ssd->worker->destroy_surfaces(ssd->worker);
--}
--
--void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd)
--{
--    ssd->worker->reset_image_cache(ssd->worker);
--}
--
--void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd)
--{
--    ssd->worker->reset_cursor(ssd->worker);
--}
--
--
- static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
- {
-     SimpleSpiceUpdate *update;
-diff --git a/ui/spice-display.h b/ui/spice-display.h
-index eb7a573..abe99c7 100644
---- a/ui/spice-display.h
-+++ b/ui/spice-display.h
-@@ -82,24 +82,12 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
- void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
- void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
- 
--void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id,
--                            struct QXLRect *area, struct QXLRect *dirty_rects,
--                            uint32_t num_dirty_rects,
--                            uint32_t clear_dirty_region);
- void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot);
- void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid,
-                             uint32_t sid);
- void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
-                                        QXLDevSurfaceCreate *surface);
- void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id);
--void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id);
--void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd,
--                                struct QXLCommandExt *ext, uint32_t count);
- void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
--void qemu_spice_oom(SimpleSpiceDisplay *ssd);
- void qemu_spice_start(SimpleSpiceDisplay *ssd);
- void qemu_spice_stop(SimpleSpiceDisplay *ssd);
--void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd);
--void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd);
--void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd);
--void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd);
--- 
-1.7.5.1
-
diff --git a/0017-qxl-error-handling-fixes-and-cleanups.patch b/0017-qxl-error-handling-fixes-and-cleanups.patch
new file mode 100644
index 0000000..39a81b7
--- /dev/null
+++ b/0017-qxl-error-handling-fixes-and-cleanups.patch
@@ -0,0 +1,110 @@
+>From 4b61f7ca2ed63deb1d35c17150b53a1661f395f7 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+Date: Thu, 30 Jun 2011 10:41:36 +0200
+Subject: [PATCH 17/28] qxl: error handling fixes and cleanups.
+
+Add qxl_guest_bug() function which is supposed to be called in case
+sanity checks of guest requests fail.  It raises an error IRQ and
+logs a message in case guest debugging is enabled.
+
+Make PANIC_ON() abort instead of exit.  That macro should be used
+for qemu bugs only, any guest-triggerable stuff should use the new
+qxl_guest_bug() function instead.
+
+Convert a few easy cases from PANIC_ON() to qxl_guest_bug() to
+show intended usage.
+
+Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
+---
+ hw/qxl.c |   34 ++++++++++++++++++++++++++++++----
+ hw/qxl.h |    3 ++-
+ 2 files changed, 32 insertions(+), 5 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 6e66021..28c8b5d 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -125,6 +125,16 @@ static void qxl_reset_memslots(PCIQXLDevice *d);
+ static void qxl_reset_surfaces(PCIQXLDevice *d);
+ static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
+ 
++void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg)
++{
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++    qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
++#endif
++    if (qxl->guestdebug) {
++        fprintf(stderr, "qxl-%d: guest bug: %s\n", qxl->id, msg);
++    }
++}
++
+ 
+ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+                            struct QXLRect *area, struct QXLRect *dirty_rects,
+@@ -1091,22 +1101,38 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+         qxl_hard_reset(d, 0);
+         break;
+     case QXL_IO_MEMSLOT_ADD:
+-        PANIC_ON(val >= NUM_MEMSLOTS);
+-        PANIC_ON(d->guest_slots[val].active);
++        if (val >= NUM_MEMSLOTS) {
++            qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: val out of range");
++            break;
++        }
++        if (d->guest_slots[val].active) {
++            qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: memory slot already active");
++            break;
++        }
+         d->guest_slots[val].slot = d->ram->mem_slot;
+         qxl_add_memslot(d, val, 0);
+         break;
+     case QXL_IO_MEMSLOT_DEL:
++        if (val >= NUM_MEMSLOTS) {
++            qxl_guest_bug(d, "QXL_IO_MEMSLOT_DEL: val out of range");
++            break;
++        }
+         qxl_del_memslot(d, val);
+         break;
+     case QXL_IO_CREATE_PRIMARY:
+-        PANIC_ON(val != 0);
++        if (val != 0) {
++            qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY: val != 0");
++            break;
++        }
+         dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n");
+         d->guest_primary.surface = d->ram->create_surface;
+         qxl_create_guest_primary(d, 0);
+         break;
+     case QXL_IO_DESTROY_PRIMARY:
+-        PANIC_ON(val != 0);
++        if (val != 0) {
++            qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY: val != 0");
++            break;
++        }
+         dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode));
+         qxl_destroy_primary(d);
+         break;
+diff --git a/hw/qxl.h b/hw/qxl.h
+index 5d0e85e..5db9aae 100644
+--- a/hw/qxl.h
++++ b/hw/qxl.h
+@@ -86,7 +86,7 @@ typedef struct PCIQXLDevice {
+ 
+ #define PANIC_ON(x) if ((x)) {                         \
+     printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \
+-    exit(-1);                                          \
++    abort();                                           \
+ }
+ 
+ #define dprint(_qxl, _level, _fmt, ...)                                 \
+@@ -99,6 +99,7 @@ typedef struct PCIQXLDevice {
+ 
+ /* qxl.c */
+ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
++void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg);
+ 
+ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+                            struct QXLRect *area, struct QXLRect *dirty_rects,
+-- 
+1.7.5.1
+
diff --git a/0017-qxl-fix-surface-tracking-locking.patch b/0017-qxl-fix-surface-tracking-locking.patch
deleted file mode 100644
index c525dc7..0000000
--- a/0017-qxl-fix-surface-tracking-locking.patch
+++ /dev/null
@@ -1,92 +0,0 @@
->From fc1bf5a4be15e71f87fd73f79356a5a1df5aa724 Mon Sep 17 00:00:00 2001
-From: Gerd Hoffmann <kraxel@redhat.com>
-Date: Wed, 29 Jun 2011 10:24:05 +0200
-Subject: [PATCH 17/25] qxl: fix surface tracking & locking
-
-Surface tracking needs proper locking since it is used from vcpu and spice
-worker threads, add it.  Also reset the surface counter when zapping all
-surfaces.
-
-Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
----
- hw/qxl.c |   13 ++++++++++++-
- hw/qxl.h |    2 ++
- 2 files changed, 14 insertions(+), 1 deletions(-)
-
-diff --git a/hw/qxl.c b/hw/qxl.c
-index 803a364..416bd48 100644
---- a/hw/qxl.c
-+++ b/hw/qxl.c
-@@ -137,7 +137,12 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
- 
- void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id)
- {
-+    qemu_mutex_lock(&qxl->track_lock);
-+    PANIC_ON(id >= NUM_SURFACES);
-     qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
-+    qxl->guest_surfaces.cmds[id] = 0;
-+    qxl->guest_surfaces.count--;
-+    qemu_mutex_unlock(&qxl->track_lock);
- }
- 
- void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
-@@ -158,7 +163,11 @@ void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
- 
- void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl)
- {
-+    qemu_mutex_lock(&qxl->track_lock);
-     qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
-+    memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds));
-+    qxl->guest_surfaces.count = 0;
-+    qemu_mutex_unlock(&qxl->track_lock);
- }
- 
- void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
-@@ -317,6 +326,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
-         QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
-         uint32_t id = le32_to_cpu(cmd->surface_id);
-         PANIC_ON(id >= NUM_SURFACES);
-+        qemu_mutex_lock(&qxl->track_lock);
-         if (cmd->type == QXL_SURFACE_CMD_CREATE) {
-             qxl->guest_surfaces.cmds[id] = ext->cmd.data;
-             qxl->guest_surfaces.count++;
-@@ -327,6 +337,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
-             qxl->guest_surfaces.cmds[id] = 0;
-             qxl->guest_surfaces.count--;
-         }
-+        qemu_mutex_unlock(&qxl->track_lock);
-         break;
-     }
-     case QXL_CMD_CURSOR:
-@@ -863,7 +874,6 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
-     dprint(d, 1, "%s:\n", __FUNCTION__);
-     d->mode = QXL_MODE_UNDEFINED;
-     qxl_spice_destroy_surfaces(d);
--    memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
- }
- 
- /* called from spice server thread context only */
-@@ -1283,6 +1293,7 @@ static int qxl_init_common(PCIQXLDevice *qxl)
-     qxl->generation = 1;
-     qxl->num_memslots = NUM_MEMSLOTS;
-     qxl->num_surfaces = NUM_SURFACES;
-+    qemu_mutex_init(&qxl->track_lock);
- 
-     switch (qxl->revision) {
-     case 1: /* spice 0.4 -- qxl-1 */
-diff --git a/hw/qxl.h b/hw/qxl.h
-index e62b9d0..5d0e85e 100644
---- a/hw/qxl.h
-+++ b/hw/qxl.h
-@@ -55,6 +55,8 @@ typedef struct PCIQXLDevice {
-     } guest_surfaces;
-     QXLPHYSICAL        guest_cursor;
- 
-+    QemuMutex          track_lock;
-+
-     /* thread signaling */
-     pthread_t          main;
-     int                pipe[2];
--- 
-1.7.5.1
-
diff --git a/0018-qxl-add-io_port_to_string.patch b/0018-qxl-add-io_port_to_string.patch
deleted file mode 100644
index 96a5238..0000000
--- a/0018-qxl-add-io_port_to_string.patch
+++ /dev/null
@@ -1,71 +0,0 @@
->From cb29c060e51d2afcd9ba6ed6a115442473381d5a Mon Sep 17 00:00:00 2001
-From: Alon Levy <alevy@redhat.com>
-Date: Fri, 17 Jun 2011 14:42:09 +0200
-Subject: [PATCH 18/25] qxl: add io_port_to_string
-
-Signed-off-by: Alon Levy <alevy@redhat.com>
----
- hw/qxl.c |   40 +++++++++++++++++++++++++++++++++++++++-
- 1 files changed, 39 insertions(+), 1 deletions(-)
-
-diff --git a/hw/qxl.c b/hw/qxl.c
-index 416bd48..6e66021 100644
---- a/hw/qxl.c
-+++ b/hw/qxl.c
-@@ -409,6 +409,43 @@ static const char *qxl_mode_to_string(int mode)
-     return "INVALID";
- }
- 
-+static const char *io_port_to_string(uint32_t io_port)
-+{
-+    if (io_port >= QXL_IO_RANGE_SIZE) {
-+        return "out of range";
-+    }
-+    static const char *io_port_to_string[QXL_IO_RANGE_SIZE + 1] = {
-+        [QXL_IO_NOTIFY_CMD]             = "QXL_IO_NOTIFY_CMD",
-+        [QXL_IO_NOTIFY_CURSOR]          = "QXL_IO_NOTIFY_CURSOR",
-+        [QXL_IO_UPDATE_AREA]            = "QXL_IO_UPDATE_AREA",
-+        [QXL_IO_UPDATE_IRQ]             = "QXL_IO_UPDATE_IRQ",
-+        [QXL_IO_NOTIFY_OOM]             = "QXL_IO_NOTIFY_OOM",
-+        [QXL_IO_RESET]                  = "QXL_IO_RESET",
-+        [QXL_IO_SET_MODE]               = "QXL_IO_SET_MODE",
-+        [QXL_IO_LOG]                    = "QXL_IO_LOG",
-+        [QXL_IO_MEMSLOT_ADD]            = "QXL_IO_MEMSLOT_ADD",
-+        [QXL_IO_MEMSLOT_DEL]            = "QXL_IO_MEMSLOT_DEL",
-+        [QXL_IO_DETACH_PRIMARY]         = "QXL_IO_DETACH_PRIMARY",
-+        [QXL_IO_ATTACH_PRIMARY]         = "QXL_IO_ATTACH_PRIMARY",
-+        [QXL_IO_CREATE_PRIMARY]         = "QXL_IO_CREATE_PRIMARY",
-+        [QXL_IO_DESTROY_PRIMARY]        = "QXL_IO_DESTROY_PRIMARY",
-+        [QXL_IO_DESTROY_SURFACE_WAIT]   = "QXL_IO_DESTROY_SURFACE_WAIT",
-+        [QXL_IO_DESTROY_ALL_SURFACES]   = "QXL_IO_DESTROY_ALL_SURFACES",
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+        [QXL_IO_UPDATE_AREA_ASYNC]      = "QXL_IO_UPDATE_AREA_ASYNC",
-+        [QXL_IO_MEMSLOT_ADD_ASYNC]      = "QXL_IO_MEMSLOT_ADD_ASYNC",
-+        [QXL_IO_CREATE_PRIMARY_ASYNC]   = "QXL_IO_CREATE_PRIMARY_ASYNC",
-+        [QXL_IO_DESTROY_PRIMARY_ASYNC]  = "QXL_IO_DESTROY_PRIMARY_ASYNC",
-+        [QXL_IO_DESTROY_SURFACE_ASYNC]  = "QXL_IO_DESTROY_SURFACE_ASYNC",
-+        [QXL_IO_DESTROY_ALL_SURFACES_ASYNC]
-+                                        = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
-+        [QXL_IO_FLUSH_SURFACES_ASYNC]   = "QXL_IO_FLUSH_SURFACES_ASYNC",
-+        [QXL_IO_FLUSH_RELEASE]          = "QXL_IO_FLUSH_RELEASE",
-+#endif
-+    };
-+    return io_port_to_string[io_port];
-+}
-+
- /* called from spice server thread context only */
- static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
- {
-@@ -1005,7 +1042,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-     default:
-         if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT)
-             break;
--        dprint(d, 1, "%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port);
-+        dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n",
-+            __func__, io_port, io_port_to_string(io_port));
-         return;
-     }
- 
--- 
-1.7.5.1
-
diff --git a/0018-qxl-make-qxl_guest_bug-take-variable-arguments.patch b/0018-qxl-make-qxl_guest_bug-take-variable-arguments.patch
new file mode 100644
index 0000000..b7b311f
--- /dev/null
+++ b/0018-qxl-make-qxl_guest_bug-take-variable-arguments.patch
@@ -0,0 +1,52 @@
+>From 5c0219c6cef769a5748705d489376ea618486a17 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy@redhat.com>
+Date: Wed, 6 Jul 2011 13:40:29 +0200
+Subject: [PATCH 18/28] qxl: make qxl_guest_bug take variable arguments
+
+Signed-off-by: Alon Levy <alevy@redhat.com>
+---
+ hw/qxl.c |    9 +++++++--
+ hw/qxl.h |    2 +-
+ 2 files changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 28c8b5d..c50eaf9 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -125,13 +125,18 @@ static void qxl_reset_memslots(PCIQXLDevice *d);
+ static void qxl_reset_surfaces(PCIQXLDevice *d);
+ static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
+ 
+-void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg)
++void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
+ {
+ #if SPICE_INTERFACE_QXL_MINOR >= 1
+     qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
+ #endif
+     if (qxl->guestdebug) {
+-        fprintf(stderr, "qxl-%d: guest bug: %s\n", qxl->id, msg);
++        va_list ap;
++        va_start(ap, msg);
++        fprintf(stderr, "qxl-%d: guest bug: ", qxl->id);
++        vfprintf(stderr, msg, ap);
++        fprintf(stderr, "\n");
++        va_end(ap);
+     }
+ }
+ 
+diff --git a/hw/qxl.h b/hw/qxl.h
+index 5db9aae..32ca5a0 100644
+--- a/hw/qxl.h
++++ b/hw/qxl.h
+@@ -99,7 +99,7 @@ typedef struct PCIQXLDevice {
+ 
+ /* qxl.c */
+ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
+-void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg);
++void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
+ 
+ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+                            struct QXLRect *area, struct QXLRect *dirty_rects,
+-- 
+1.7.5.1
+
diff --git a/0019-qxl-error-handling-fixes-and-cleanups.patch b/0019-qxl-error-handling-fixes-and-cleanups.patch
deleted file mode 100644
index c030308..0000000
--- a/0019-qxl-error-handling-fixes-and-cleanups.patch
+++ /dev/null
@@ -1,110 +0,0 @@
->From 9e85acc84ed9dbaed1bb7abe83e1b2fe61905706 Mon Sep 17 00:00:00 2001
-From: Gerd Hoffmann <kraxel@redhat.com>
-Date: Thu, 30 Jun 2011 10:41:36 +0200
-Subject: [PATCH 19/25] qxl: error handling fixes and cleanups.
-
-Add qxl_guest_bug() function which is supposed to be called in case
-sanity checks of guest requests fail.  It raises an error IRQ and
-logs a message in case guest debugging is enabled.
-
-Make PANIC_ON() abort instead of exit.  That macro should be used
-for qemu bugs only, any guest-triggerable stuff should use the new
-qxl_guest_bug() function instead.
-
-Convert a few easy cases from PANIC_ON() to qxl_guest_bug() to
-show intended usage.
-
-Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
----
- hw/qxl.c |   34 ++++++++++++++++++++++++++++++----
- hw/qxl.h |    3 ++-
- 2 files changed, 32 insertions(+), 5 deletions(-)
-
-diff --git a/hw/qxl.c b/hw/qxl.c
-index 6e66021..28c8b5d 100644
---- a/hw/qxl.c
-+++ b/hw/qxl.c
-@@ -125,6 +125,16 @@ static void qxl_reset_memslots(PCIQXLDevice *d);
- static void qxl_reset_surfaces(PCIQXLDevice *d);
- static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
- 
-+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg)
-+{
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+    qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
-+#endif
-+    if (qxl->guestdebug) {
-+        fprintf(stderr, "qxl-%d: guest bug: %s\n", qxl->id, msg);
-+    }
-+}
-+
- 
- void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
-                            struct QXLRect *area, struct QXLRect *dirty_rects,
-@@ -1091,22 +1101,38 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-         qxl_hard_reset(d, 0);
-         break;
-     case QXL_IO_MEMSLOT_ADD:
--        PANIC_ON(val >= NUM_MEMSLOTS);
--        PANIC_ON(d->guest_slots[val].active);
-+        if (val >= NUM_MEMSLOTS) {
-+            qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: val out of range");
-+            break;
-+        }
-+        if (d->guest_slots[val].active) {
-+            qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: memory slot already active");
-+            break;
-+        }
-         d->guest_slots[val].slot = d->ram->mem_slot;
-         qxl_add_memslot(d, val, 0);
-         break;
-     case QXL_IO_MEMSLOT_DEL:
-+        if (val >= NUM_MEMSLOTS) {
-+            qxl_guest_bug(d, "QXL_IO_MEMSLOT_DEL: val out of range");
-+            break;
-+        }
-         qxl_del_memslot(d, val);
-         break;
-     case QXL_IO_CREATE_PRIMARY:
--        PANIC_ON(val != 0);
-+        if (val != 0) {
-+            qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY: val != 0");
-+            break;
-+        }
-         dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n");
-         d->guest_primary.surface = d->ram->create_surface;
-         qxl_create_guest_primary(d, 0);
-         break;
-     case QXL_IO_DESTROY_PRIMARY:
--        PANIC_ON(val != 0);
-+        if (val != 0) {
-+            qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY: val != 0");
-+            break;
-+        }
-         dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode));
-         qxl_destroy_primary(d);
-         break;
-diff --git a/hw/qxl.h b/hw/qxl.h
-index 5d0e85e..5db9aae 100644
---- a/hw/qxl.h
-+++ b/hw/qxl.h
-@@ -86,7 +86,7 @@ typedef struct PCIQXLDevice {
- 
- #define PANIC_ON(x) if ((x)) {                         \
-     printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \
--    exit(-1);                                          \
-+    abort();                                           \
- }
- 
- #define dprint(_qxl, _level, _fmt, ...)                                 \
-@@ -99,6 +99,7 @@ typedef struct PCIQXLDevice {
- 
- /* qxl.c */
- void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
-+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg);
- 
- void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
-                            struct QXLRect *area, struct QXLRect *dirty_rects,
--- 
-1.7.5.1
-
diff --git a/0019-qxl-only-disallow-specific-io-s-in-vga-mode.patch b/0019-qxl-only-disallow-specific-io-s-in-vga-mode.patch
new file mode 100644
index 0000000..258a7c3
--- /dev/null
+++ b/0019-qxl-only-disallow-specific-io-s-in-vga-mode.patch
@@ -0,0 +1,31 @@
+>From e8f481961a5fd3ad92a55dbabcccf09b037d86c9 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy@redhat.com>
+Date: Wed, 29 Jun 2011 11:53:21 +0200
+Subject: [PATCH 19/28] qxl: only disallow specific io's in vga mode
+
+Since the driver is still in operation even after moving to UNDEFINED, i.e.
+by destroying primary in any way.
+
+Signed-off-by: Alon Levy <alevy@redhat.com>
+---
+ hw/qxl.c |    3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index c50eaf9..23e3240 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -1055,8 +1055,9 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+     case QXL_IO_LOG:
+         break;
+     default:
+-        if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT)
++        if (d->mode != QXL_MODE_VGA) {
+             break;
++        }
+         dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n",
+             __func__, io_port, io_port_to_string(io_port));
+         return;
+-- 
+1.7.5.1
+
diff --git a/0020-qxl-async-io-support-using-new-spice-api.patch b/0020-qxl-async-io-support-using-new-spice-api.patch
new file mode 100644
index 0000000..68ed72c
--- /dev/null
+++ b/0020-qxl-async-io-support-using-new-spice-api.patch
@@ -0,0 +1,659 @@
+>From a1950cb3afb36a78df3ac9a545d99baf7cc93ca2 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy@redhat.com>
+Date: Thu, 23 Jun 2011 20:02:18 +0200
+Subject: [PATCH 20/28] qxl: async io support using new spice api
+
+Some of the QXL port i/o commands are waiting for the spice server to
+complete certain actions.  Add async versions for these commands, so we
+don't block the vcpu while the spice server processses the command.
+Instead the qxl device will raise an IRQ when done.
+
+The async command processing relies on an added QXLInterface::async_complete
+and added QXLWorker::*_async additions, in spice server qxl >= 3.1
+
+Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
+Signed-off-by: Alon Levy     <alevy@redhat.com>
+---
+ hw/qxl-render.c    |    2 +-
+ hw/qxl.c           |  240 ++++++++++++++++++++++++++++++++++++++++++++--------
+ hw/qxl.h           |   16 +++-
+ ui/spice-display.c |   47 ++++++++--
+ ui/spice-display.h |   23 +++++-
+ 5 files changed, 274 insertions(+), 54 deletions(-)
+
+diff --git a/hw/qxl-render.c b/hw/qxl-render.c
+index 60b822d..643ff2d 100644
+--- a/hw/qxl-render.c
++++ b/hw/qxl-render.c
+@@ -125,7 +125,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
+ 
+     memset(dirty, 0, sizeof(dirty));
+     qxl_spice_update_area(qxl, 0, &update,
+-                          dirty, ARRAY_SIZE(dirty), 1);
++                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC);
+ 
+     for (i = 0; i < ARRAY_SIZE(dirty); i++) {
+         if (qemu_spice_rect_is_empty(dirty+i)) {
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 23e3240..d3109e4 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -120,7 +120,7 @@ static QXLMode qxl_modes[] = {
+ static PCIQXLDevice *qxl0;
+ 
+ static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
+-static void qxl_destroy_primary(PCIQXLDevice *d);
++static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async);
+ static void qxl_reset_memslots(PCIQXLDevice *d);
+ static void qxl_reset_surfaces(PCIQXLDevice *d);
+ static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
+@@ -144,22 +144,47 @@ void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
+ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+                            struct QXLRect *area, struct QXLRect *dirty_rects,
+                            uint32_t num_dirty_rects,
+-                           uint32_t clear_dirty_region)
++                           uint32_t clear_dirty_region,
++                           qxl_async_io async)
+ {
+-    qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, dirty_rects,
+-                             num_dirty_rects, clear_dirty_region);
++    if (async == QXL_SYNC) {
++        qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
++                        dirty_rects, num_dirty_rects, clear_dirty_region);
++    } else {
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++        spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area,
++                                    clear_dirty_region, 0);
++#else
++        abort();
++#endif
++    }
+ }
+ 
+-void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id)
++static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl,
++                                                    uint32_t id)
+ {
+     qemu_mutex_lock(&qxl->track_lock);
+-    PANIC_ON(id >= NUM_SURFACES);
+-    qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
+     qxl->guest_surfaces.cmds[id] = 0;
+     qxl->guest_surfaces.count--;
+     qemu_mutex_unlock(&qxl->track_lock);
+ }
+ 
++static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
++                                           qxl_async_io async)
++{
++    if (async) {
++#if SPICE_INTERFACE_QXL_MINOR < 1
++        abort();
++#else
++        spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id,
++                                        (uint64_t)id);
++#endif
++    } else {
++        qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
++        qxl_spice_destroy_surface_wait_complete(qxl, id);
++    }
++}
++
+ void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
+                                uint32_t count)
+ {
+@@ -176,15 +201,28 @@ void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
+     qxl->ssd.worker->reset_memslots(qxl->ssd.worker);
+ }
+ 
+-void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl)
++static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
+ {
+     qemu_mutex_lock(&qxl->track_lock);
+-    qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
+     memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds));
+     qxl->guest_surfaces.count = 0;
+     qemu_mutex_unlock(&qxl->track_lock);
+ }
+ 
++static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
++{
++    if (async) {
++#if SPICE_INTERFACE_QXL_MINOR < 1
++        abort();
++#else
++        spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0);
++#endif
++    } else {
++        qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
++        qxl_spice_destroy_surfaces_complete(qxl);
++    }
++}
++
+ void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
+ {
+     qxl->ssd.worker->reset_image_cache(qxl->ssd.worker);
+@@ -689,6 +727,38 @@ static int interface_flush_resources(QXLInstance *sin)
+     return ret;
+ }
+ 
++static void qxl_create_guest_primary_complete(PCIQXLDevice *d);
++
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++
++/* called from spice server thread context only */
++static void interface_async_complete(QXLInstance *sin, uint64_t cookie)
++{
++    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
++    uint32_t current_async;
++
++    qemu_mutex_lock(&qxl->async_lock);
++    current_async = qxl->current_async;
++    qxl->current_async = QXL_UNDEFINED_IO;
++    qemu_mutex_unlock(&qxl->async_lock);
++
++    dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie);
++    switch (current_async) {
++    case QXL_IO_CREATE_PRIMARY_ASYNC:
++        qxl_create_guest_primary_complete(qxl);
++        break;
++    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
++        qxl_spice_destroy_surfaces_complete(qxl);
++        break;
++    case QXL_IO_DESTROY_SURFACE_ASYNC:
++        qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie);
++        break;
++    }
++    qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
++}
++
++#endif
++
+ static const QXLInterface qxl_interface = {
+     .base.type               = SPICE_INTERFACE_QXL,
+     .base.description        = "qxl gpu",
+@@ -708,6 +778,9 @@ static const QXLInterface qxl_interface = {
+     .req_cursor_notification = interface_req_cursor_notification,
+     .notify_update           = interface_notify_update,
+     .flush_resources         = interface_flush_resources,
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++    .async_complete          = interface_async_complete,
++#endif
+ };
+ 
+ static void qxl_enter_vga_mode(PCIQXLDevice *d)
+@@ -727,7 +800,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d)
+         return;
+     }
+     dprint(d, 1, "%s\n", __FUNCTION__);
+-    qxl_destroy_primary(d);
++    qxl_destroy_primary(d, QXL_SYNC);
+ }
+ 
+ static void qxl_set_irq(PCIQXLDevice *d)
+@@ -824,13 +897,14 @@ static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+ 
+     if (qxl->mode != QXL_MODE_VGA) {
+         dprint(qxl, 1, "%s\n", __FUNCTION__);
+-        qxl_destroy_primary(qxl);
++        qxl_destroy_primary(qxl, QXL_SYNC);
+         qxl_soft_reset(qxl);
+     }
+     vga_ioport_write(opaque, addr, val);
+ }
+ 
+-static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
++static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
++                            qxl_async_io async)
+ {
+     static const int regions[] = {
+         QXL_RAM_RANGE_INDEX,
+@@ -900,7 +974,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
+            __FUNCTION__, memslot.slot_id,
+            memslot.virt_start, memslot.virt_end);
+ 
+-    qemu_spice_add_memslot(&d->ssd, &memslot);
++    qemu_spice_add_memslot(&d->ssd, &memslot, async);
+     d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
+     d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
+     d->guest_slots[slot_id].delta = delta;
+@@ -925,7 +999,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
+ {
+     dprint(d, 1, "%s:\n", __FUNCTION__);
+     d->mode = QXL_MODE_UNDEFINED;
+-    qxl_spice_destroy_surfaces(d);
++    qxl_spice_destroy_surfaces(d, QXL_SYNC);
+ }
+ 
+ /* called from spice server thread context only */
+@@ -950,7 +1024,14 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
+     }
+ }
+ 
+-static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
++static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl)
++{
++    /* for local rendering */
++    qxl_render_resize(qxl);
++}
++
++static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm,
++                                     qxl_async_io async)
+ {
+     QXLDevSurfaceCreate surface;
+     QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
+@@ -978,22 +1059,26 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
+ 
+     qxl->mode = QXL_MODE_NATIVE;
+     qxl->cmdflags = 0;
+-    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface);
++    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface, async);
+ 
+-    /* for local rendering */
+-    qxl_render_resize(qxl);
++    if (async == QXL_SYNC) {
++        qxl_create_guest_primary_complete(qxl);
++    }
+ }
+ 
+-static void qxl_destroy_primary(PCIQXLDevice *d)
++/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or
++ * done (in QXL_SYNC case), 0 otherwise. */
++static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
+ {
+     if (d->mode == QXL_MODE_UNDEFINED) {
+-        return;
++        return 0;
+     }
+ 
+     dprint(d, 1, "%s\n", __FUNCTION__);
+ 
+     d->mode = QXL_MODE_UNDEFINED;
+-    qemu_spice_destroy_primary_surface(&d->ssd, 0);
++    qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
++    return 1;
+ }
+ 
+ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
+@@ -1023,10 +1108,10 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
+     }
+ 
+     d->guest_slots[0].slot = slot;
+-    qxl_add_memslot(d, 0, devmem);
++    qxl_add_memslot(d, 0, devmem, QXL_SYNC);
+ 
+     d->guest_primary.surface = surface;
+-    qxl_create_guest_primary(d, 0);
++    qxl_create_guest_primary(d, 0, QXL_SYNC);
+ 
+     d->mode = QXL_MODE_COMPAT;
+     d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
+@@ -1044,6 +1129,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+ {
+     PCIQXLDevice *d = opaque;
+     uint32_t io_port = addr - d->io_base;
++    qxl_async_io async = QXL_SYNC;
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++    uint32_t orig_io_port = io_port;
++#endif
+ 
+     switch (io_port) {
+     case QXL_IO_RESET:
+@@ -1053,6 +1142,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+     case QXL_IO_CREATE_PRIMARY:
+     case QXL_IO_UPDATE_IRQ:
+     case QXL_IO_LOG:
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++    case QXL_IO_MEMSLOT_ADD_ASYNC:
++    case QXL_IO_CREATE_PRIMARY_ASYNC:
++#endif
+         break;
+     default:
+         if (d->mode != QXL_MODE_VGA) {
+@@ -1060,15 +1153,61 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+         }
+         dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n",
+             __func__, io_port, io_port_to_string(io_port));
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++        /* be nice to buggy guest drivers */
++        if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
++            io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
++            qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
++        }
++#endif
+         return;
+     }
+ 
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++    /* we change the io_port to avoid ifdeffery in the main switch */
++    orig_io_port = io_port;
++    switch (io_port) {
++    case QXL_IO_UPDATE_AREA_ASYNC:
++        io_port = QXL_IO_UPDATE_AREA;
++        goto async_common;
++    case QXL_IO_MEMSLOT_ADD_ASYNC:
++        io_port = QXL_IO_MEMSLOT_ADD;
++        goto async_common;
++    case QXL_IO_CREATE_PRIMARY_ASYNC:
++        io_port = QXL_IO_CREATE_PRIMARY;
++        goto async_common;
++    case QXL_IO_DESTROY_PRIMARY_ASYNC:
++        io_port = QXL_IO_DESTROY_PRIMARY;
++        goto async_common;
++    case QXL_IO_DESTROY_SURFACE_ASYNC:
++        io_port = QXL_IO_DESTROY_SURFACE_WAIT;
++        goto async_common;
++    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
++        io_port = QXL_IO_DESTROY_ALL_SURFACES;
++async_common:
++        async = QXL_ASYNC;
++        qemu_mutex_lock(&d->async_lock);
++        if (d->current_async != QXL_UNDEFINED_IO) {
++            qxl_guest_bug(d, "%d async started before last (%d) complete",
++                io_port, d->current_async);
++            qemu_mutex_unlock(&d->async_lock);
++            return;
++        }
++        d->current_async = orig_io_port;
++        qemu_mutex_unlock(&d->async_lock);
++        dprint(d, 2, "start async %d (%d)\n", io_port, val);
++        break;
++    default:
++        break;
++    }
++#endif
++
+     switch (io_port) {
+     case QXL_IO_UPDATE_AREA:
+     {
+         QXLRect update = d->ram->update_area;
+         qxl_spice_update_area(d, d->ram->update_surface,
+-                              &update, NULL, 0, 0);
++                              &update, NULL, 0, 0, async);
+         break;
+     }
+     case QXL_IO_NOTIFY_CMD:
+@@ -1116,7 +1255,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+             break;
+         }
+         d->guest_slots[val].slot = d->ram->mem_slot;
+-        qxl_add_memslot(d, val, 0);
++        qxl_add_memslot(d, val, 0, async);
+         break;
+     case QXL_IO_MEMSLOT_DEL:
+         if (val >= NUM_MEMSLOTS) {
+@@ -1127,31 +1266,56 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+         break;
+     case QXL_IO_CREATE_PRIMARY:
+         if (val != 0) {
+-            qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY: val != 0");
+-            break;
++            qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY (async=%d): val != 0",
++                          async);
++            goto cancel_async;
+         }
+-        dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n");
++        dprint(d, 1, "QXL_IO_CREATE_PRIMARY async=%d\n", async);
+         d->guest_primary.surface = d->ram->create_surface;
+-        qxl_create_guest_primary(d, 0);
++        qxl_create_guest_primary(d, 0, async);
+         break;
+     case QXL_IO_DESTROY_PRIMARY:
+         if (val != 0) {
+-            qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY: val != 0");
+-            break;
++            qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY (async=%d): val != 0",
++                          async);
++            goto cancel_async;
++        }
++        dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (async=%d) (%s)\n", async,
++               qxl_mode_to_string(d->mode));
++        if (!qxl_destroy_primary(d, async)) {
++            dprint(d, 1, "QXL_IO_DESTROY_PRIMARY_ASYNC in %s, ignored\n",
++                    qxl_mode_to_string(d->mode));
++            goto cancel_async;
+         }
+-        dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode));
+-        qxl_destroy_primary(d);
+         break;
+     case QXL_IO_DESTROY_SURFACE_WAIT:
+-        qxl_spice_destroy_surface_wait(d, val);
++        if (val >= NUM_SURFACES) {
++            qxl_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
++                             "%d >= NUM_SURFACES", async, val);
++            goto cancel_async;
++        }
++        qxl_spice_destroy_surface_wait(d, val, async);
+         break;
+     case QXL_IO_DESTROY_ALL_SURFACES:
+-        qxl_spice_destroy_surfaces(d);
++        d->mode = QXL_MODE_UNDEFINED;
++        qxl_spice_destroy_surfaces(d, async);
+         break;
+     default:
+         fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
+         abort();
+     }
++    return;
++cancel_async:
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++    if (async) {
++        qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
++        qemu_mutex_lock(&d->async_lock);
++        d->current_async = QXL_UNDEFINED_IO;
++        qemu_mutex_unlock(&d->async_lock);
++    }
++#else
++    return;
++#endif
+ }
+ 
+ static uint32_t ioport_read(void *opaque, uint32_t addr)
+@@ -1364,6 +1528,8 @@ static int qxl_init_common(PCIQXLDevice *qxl)
+     qxl->num_memslots = NUM_MEMSLOTS;
+     qxl->num_surfaces = NUM_SURFACES;
+     qemu_mutex_init(&qxl->track_lock);
++    qemu_mutex_init(&qxl->async_lock);
++    qxl->current_async = QXL_UNDEFINED_IO;
+ 
+     switch (qxl->revision) {
+     case 1: /* spice 0.4 -- qxl-1 */
+@@ -1528,9 +1694,9 @@ static int qxl_post_load(void *opaque, int version)
+             if (!d->guest_slots[i].active) {
+                 continue;
+             }
+-            qxl_add_memslot(d, i, 0);
++            qxl_add_memslot(d, i, 0, QXL_SYNC);
+         }
+-        qxl_create_guest_primary(d, 1);
++        qxl_create_guest_primary(d, 1, QXL_SYNC);
+ 
+         /* replay surface-create and cursor-set commands */
+         cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
+diff --git a/hw/qxl.h b/hw/qxl.h
+index 32ca5a0..1046205 100644
+--- a/hw/qxl.h
++++ b/hw/qxl.h
+@@ -15,6 +15,8 @@ enum qxl_mode {
+     QXL_MODE_NATIVE,
+ };
+ 
++#define QXL_UNDEFINED_IO UINT32_MAX
++
+ typedef struct PCIQXLDevice {
+     PCIDevice          pci;
+     SimpleSpiceDisplay ssd;
+@@ -30,6 +32,9 @@ typedef struct PCIQXLDevice {
+     int32_t            num_memslots;
+     int32_t            num_surfaces;
+ 
++    uint32_t           current_async;
++    QemuMutex          async_lock;
++
+     struct guest_slots {
+         QXLMemSlot     slot;
+         void           *ptr;
+@@ -104,13 +109,12 @@ void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
+ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+                            struct QXLRect *area, struct QXLRect *dirty_rects,
+                            uint32_t num_dirty_rects,
+-                           uint32_t clear_dirty_region);
+-void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id);
++                           uint32_t clear_dirty_region,
++                           qxl_async_io async);
+ void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
+                                uint32_t count);
+ void qxl_spice_oom(PCIQXLDevice *qxl);
+ void qxl_spice_reset_memslots(PCIQXLDevice *qxl);
+-void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl);
+ void qxl_spice_reset_image_cache(PCIQXLDevice *qxl);
+ void qxl_spice_reset_cursor(PCIQXLDevice *qxl);
+ 
+@@ -122,3 +126,9 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
+ void qxl_render_resize(PCIQXLDevice *qxl);
+ void qxl_render_update(PCIQXLDevice *qxl);
+ void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++void qxl_spice_update_area_async(PCIQXLDevice *qxl, uint32_t surface_id,
++                                 struct QXLRect *area,
++                                 uint32_t clear_dirty_region,
++                                 int is_vga);
++#endif
+diff --git a/ui/spice-display.c b/ui/spice-display.c
+index af10ae8..683d454 100644
+--- a/ui/spice-display.c
++++ b/ui/spice-display.c
+@@ -62,10 +62,18 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
+     dest->right = MAX(dest->right, r->right);
+ }
+ 
+-
+-void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot)
+-{
+-    ssd->worker->add_memslot(ssd->worker, memslot);
++void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
++                            qxl_async_io async)
++{
++    if (async != QXL_SYNC) {
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++        spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0);
++#else
++        abort();
++#endif
++    } else {
++        ssd->worker->add_memslot(ssd->worker, memslot);
++    }
+ }
+ 
+ void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
+@@ -74,14 +82,33 @@ void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
+ }
+ 
+ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
+-                                       QXLDevSurfaceCreate *surface)
+-{
+-    ssd->worker->create_primary_surface(ssd->worker, id, surface);
++                                       QXLDevSurfaceCreate *surface,
++                                       qxl_async_io async)
++{
++    if (async != QXL_SYNC) {
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++        spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0);
++#else
++        abort();
++#endif
++    } else {
++        ssd->worker->create_primary_surface(ssd->worker, id, surface);
++    }
+ }
+ 
+-void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id)
++
++void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
++                                        uint32_t id, qxl_async_io async)
+ {
+-    ssd->worker->destroy_primary_surface(ssd->worker, id);
++    if (async != QXL_SYNC) {
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++        spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0);
++#else
++        abort();
++#endif
++    } else {
++        ssd->worker->destroy_primary_surface(ssd->worker, id);
++    }
+ }
+ 
+ void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
+@@ -198,7 +225,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
+     memset(&memslot, 0, sizeof(memslot));
+     memslot.slot_group_id = MEMSLOT_GROUP_HOST;
+     memslot.virt_end = ~0;
+-    qemu_spice_add_memslot(ssd, &memslot);
++    qemu_spice_add_memslot(ssd, &memslot, QXL_SYNC);
+ }
+ 
+ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
+@@ -218,14 +245,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
+     surface.mem        = (intptr_t)ssd->buf;
+     surface.group_id   = MEMSLOT_GROUP_HOST;
+ 
+-    qemu_spice_create_primary_surface(ssd, 0, &surface);
++    qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC);
+ }
+ 
+ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
+ {
+     dprint(1, "%s:\n", __FUNCTION__);
+ 
+-    qemu_spice_destroy_primary_surface(ssd, 0);
++    qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC);
+ }
+ 
+ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
+diff --git a/ui/spice-display.h b/ui/spice-display.h
+index abe99c7..1388641 100644
+--- a/ui/spice-display.h
++++ b/ui/spice-display.h
+@@ -33,6 +33,20 @@
+ 
+ #define NUM_SURFACES 1024
+ 
++/*
++ * Internal enum to differenciate between options for
++ * io calls that have a sync (old) version and an _async (new)
++ * version:
++ *  QXL_SYNC: use the old version
++ *  QXL_ASYNC: use the new version and make sure there are no two
++ *   happening at the same time. This is used for guest initiated
++ *   calls
++ */
++typedef enum qxl_async_io {
++    QXL_SYNC,
++    QXL_ASYNC,
++} qxl_async_io;
++
+ typedef struct SimpleSpiceDisplay SimpleSpiceDisplay;
+ typedef struct SimpleSpiceUpdate SimpleSpiceUpdate;
+ 
+@@ -82,12 +96,15 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
+ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
+ 
+-void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot);
++void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
++                            qxl_async_io async);
+ void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid,
+                             uint32_t sid);
+ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
+-                                       QXLDevSurfaceCreate *surface);
+-void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id);
++                                       QXLDevSurfaceCreate *surface,
++                                       qxl_async_io async);
++void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
++                                        uint32_t id, qxl_async_io async);
+ void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
+ void qemu_spice_start(SimpleSpiceDisplay *ssd);
+ void qemu_spice_stop(SimpleSpiceDisplay *ssd);
+-- 
+1.7.5.1
+
diff --git a/0020-qxl-make-qxl_guest_bug-take-variable-arguments.patch b/0020-qxl-make-qxl_guest_bug-take-variable-arguments.patch
deleted file mode 100644
index e9f4866..0000000
--- a/0020-qxl-make-qxl_guest_bug-take-variable-arguments.patch
+++ /dev/null
@@ -1,52 +0,0 @@
->From beffb6d82668c7f8bcead447422529532cc0b4e7 Mon Sep 17 00:00:00 2001
-From: Alon Levy <alevy@redhat.com>
-Date: Wed, 6 Jul 2011 13:40:29 +0200
-Subject: [PATCH 20/25] qxl: make qxl_guest_bug take variable arguments
-
-Signed-off-by: Alon Levy <alevy@redhat.com>
----
- hw/qxl.c |    9 +++++++--
- hw/qxl.h |    2 +-
- 2 files changed, 8 insertions(+), 3 deletions(-)
-
-diff --git a/hw/qxl.c b/hw/qxl.c
-index 28c8b5d..c50eaf9 100644
---- a/hw/qxl.c
-+++ b/hw/qxl.c
-@@ -125,13 +125,18 @@ static void qxl_reset_memslots(PCIQXLDevice *d);
- static void qxl_reset_surfaces(PCIQXLDevice *d);
- static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
- 
--void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg)
-+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
- {
- #if SPICE_INTERFACE_QXL_MINOR >= 1
-     qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
- #endif
-     if (qxl->guestdebug) {
--        fprintf(stderr, "qxl-%d: guest bug: %s\n", qxl->id, msg);
-+        va_list ap;
-+        va_start(ap, msg);
-+        fprintf(stderr, "qxl-%d: guest bug: ", qxl->id);
-+        vfprintf(stderr, msg, ap);
-+        fprintf(stderr, "\n");
-+        va_end(ap);
-     }
- }
- 
-diff --git a/hw/qxl.h b/hw/qxl.h
-index 5db9aae..32ca5a0 100644
---- a/hw/qxl.h
-+++ b/hw/qxl.h
-@@ -99,7 +99,7 @@ typedef struct PCIQXLDevice {
- 
- /* qxl.c */
- void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
--void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg);
-+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
- 
- void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
-                            struct QXLRect *area, struct QXLRect *dirty_rects,
--- 
-1.7.5.1
-
diff --git a/0021-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch b/0021-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch
new file mode 100644
index 0000000..41b88a3
--- /dev/null
+++ b/0021-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch
@@ -0,0 +1,77 @@
+>From fed782e33714e6a44bca9a8c3ab8b017393e8089 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy@redhat.com>
+Date: Sun, 5 Jun 2011 11:01:48 +0300
+Subject: [PATCH 21/28] qxl: add QXL_IO_FLUSH_{SURFACES,RELEASE} for guest
+ S3&S4 support
+
+Add two new IOs.
+ QXL_IO_FLUSH_SURFACES - equivalent to update area for all surfaces, used
+  to reduce vmexits from NumSurfaces to 1 on guest S3, S4 and resolution change (windows
+  driver implementation is such that this is done on each of those occasions).
+ QXL_IO_FLUSH_RELEASE - used to ensure anything on last_release is put on the release ring
+  for the client to free.
+
+Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
+Signed-off-by: Alon Levy <alevy@redhat.com>
+---
+ hw/qxl.c |   30 ++++++++++++++++++++++++++++++
+ 1 files changed, 30 insertions(+), 0 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index d3109e4..847a9b8 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -185,6 +185,13 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
+     }
+ }
+ 
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl)
++{
++    spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0);
++}
++#endif
++
+ void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
+                                uint32_t count)
+ {
+@@ -1184,6 +1191,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+         goto async_common;
+     case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
+         io_port = QXL_IO_DESTROY_ALL_SURFACES;
++        goto async_common;
++    case QXL_IO_FLUSH_SURFACES_ASYNC:
+ async_common:
+         async = QXL_ASYNC;
+         qemu_mutex_lock(&d->async_lock);
+@@ -1296,6 +1305,27 @@ async_common:
+         }
+         qxl_spice_destroy_surface_wait(d, val, async);
+         break;
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++    case QXL_IO_FLUSH_RELEASE: {
++        QXLReleaseRing *ring = &d->ram->release_ring;
++        if (ring->prod - ring->cons + 1 == ring->num_items) {
++            fprintf(stderr,
++                "ERROR: no flush, full release ring [p%d,%dc]\n",
++                ring->prod, ring->cons);
++        }
++        qxl_push_free_res(d, 1 /* flush */);
++        dprint(d, 1, "QXL_IO_FLUSH_RELEASE exit (%s, s#=%d, res#=%d,%p)\n",
++            qxl_mode_to_string(d->mode), d->guest_surfaces.count,
++            d->num_free_res, d->last_release);
++        break;
++    }
++    case QXL_IO_FLUSH_SURFACES_ASYNC:
++        dprint(d, 1, "QXL_IO_FLUSH_SURFACES_ASYNC (%d) (%s, s#=%d, res#=%d)\n",
++               val, qxl_mode_to_string(d->mode), d->guest_surfaces.count,
++               d->num_free_res);
++        qxl_spice_flush_surfaces_async(d);
++        break;
++#endif
+     case QXL_IO_DESTROY_ALL_SURFACES:
+         d->mode = QXL_MODE_UNDEFINED;
+         qxl_spice_destroy_surfaces(d, async);
+-- 
+1.7.5.1
+
diff --git a/0021-qxl-only-disallow-specific-io-s-in-vga-mode.patch b/0021-qxl-only-disallow-specific-io-s-in-vga-mode.patch
deleted file mode 100644
index 3a1041b..0000000
--- a/0021-qxl-only-disallow-specific-io-s-in-vga-mode.patch
+++ /dev/null
@@ -1,31 +0,0 @@
->From 4eb9272a4185cf47a4a4e9cb59a95cfd9939e86c Mon Sep 17 00:00:00 2001
-From: Alon Levy <alevy@redhat.com>
-Date: Wed, 29 Jun 2011 11:53:21 +0200
-Subject: [PATCH 21/25] qxl: only disallow specific io's in vga mode
-
-Since the driver is still in operation even after moving to UNDEFINED, i.e.
-by destroying primary in any way.
-
-Signed-off-by: Alon Levy <alevy@redhat.com>
----
- hw/qxl.c |    3 ++-
- 1 files changed, 2 insertions(+), 1 deletions(-)
-
-diff --git a/hw/qxl.c b/hw/qxl.c
-index c50eaf9..23e3240 100644
---- a/hw/qxl.c
-+++ b/hw/qxl.c
-@@ -1055,8 +1055,9 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-     case QXL_IO_LOG:
-         break;
-     default:
--        if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT)
-+        if (d->mode != QXL_MODE_VGA) {
-             break;
-+        }
-         dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n",
-             __func__, io_port, io_port_to_string(io_port));
-         return;
--- 
-1.7.5.1
-
diff --git a/0022-qxl-async-io-support-using-new-spice-api.patch b/0022-qxl-async-io-support-using-new-spice-api.patch
deleted file mode 100644
index 74ca328..0000000
--- a/0022-qxl-async-io-support-using-new-spice-api.patch
+++ /dev/null
@@ -1,659 +0,0 @@
->From b25a2a169340f70b29d47d0598df1ac525a87bf9 Mon Sep 17 00:00:00 2001
-From: Alon Levy <alevy@redhat.com>
-Date: Thu, 23 Jun 2011 20:02:18 +0200
-Subject: [PATCH 22/25] qxl: async io support using new spice api
-
-Some of the QXL port i/o commands are waiting for the spice server to
-complete certain actions.  Add async versions for these commands, so we
-don't block the vcpu while the spice server processses the command.
-Instead the qxl device will raise an IRQ when done.
-
-The async command processing relies on an added QXLInterface::async_complete
-and added QXLWorker::*_async additions, in spice server qxl >= 3.1
-
-Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
-Signed-off-by: Alon Levy     <alevy@redhat.com>
----
- hw/qxl-render.c    |    2 +-
- hw/qxl.c           |  240 ++++++++++++++++++++++++++++++++++++++++++++--------
- hw/qxl.h           |   16 +++-
- ui/spice-display.c |   47 ++++++++--
- ui/spice-display.h |   23 +++++-
- 5 files changed, 274 insertions(+), 54 deletions(-)
-
-diff --git a/hw/qxl-render.c b/hw/qxl-render.c
-index 60b822d..643ff2d 100644
---- a/hw/qxl-render.c
-+++ b/hw/qxl-render.c
-@@ -125,7 +125,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
- 
-     memset(dirty, 0, sizeof(dirty));
-     qxl_spice_update_area(qxl, 0, &update,
--                          dirty, ARRAY_SIZE(dirty), 1);
-+                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC);
- 
-     for (i = 0; i < ARRAY_SIZE(dirty); i++) {
-         if (qemu_spice_rect_is_empty(dirty+i)) {
-diff --git a/hw/qxl.c b/hw/qxl.c
-index 23e3240..d3109e4 100644
---- a/hw/qxl.c
-+++ b/hw/qxl.c
-@@ -120,7 +120,7 @@ static QXLMode qxl_modes[] = {
- static PCIQXLDevice *qxl0;
- 
- static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
--static void qxl_destroy_primary(PCIQXLDevice *d);
-+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async);
- static void qxl_reset_memslots(PCIQXLDevice *d);
- static void qxl_reset_surfaces(PCIQXLDevice *d);
- static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
-@@ -144,22 +144,47 @@ void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
- void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
-                            struct QXLRect *area, struct QXLRect *dirty_rects,
-                            uint32_t num_dirty_rects,
--                           uint32_t clear_dirty_region)
-+                           uint32_t clear_dirty_region,
-+                           qxl_async_io async)
- {
--    qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, dirty_rects,
--                             num_dirty_rects, clear_dirty_region);
-+    if (async == QXL_SYNC) {
-+        qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
-+                        dirty_rects, num_dirty_rects, clear_dirty_region);
-+    } else {
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+        spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area,
-+                                    clear_dirty_region, 0);
-+#else
-+        abort();
-+#endif
-+    }
- }
- 
--void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id)
-+static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl,
-+                                                    uint32_t id)
- {
-     qemu_mutex_lock(&qxl->track_lock);
--    PANIC_ON(id >= NUM_SURFACES);
--    qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
-     qxl->guest_surfaces.cmds[id] = 0;
-     qxl->guest_surfaces.count--;
-     qemu_mutex_unlock(&qxl->track_lock);
- }
- 
-+static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
-+                                           qxl_async_io async)
-+{
-+    if (async) {
-+#if SPICE_INTERFACE_QXL_MINOR < 1
-+        abort();
-+#else
-+        spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id,
-+                                        (uint64_t)id);
-+#endif
-+    } else {
-+        qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
-+        qxl_spice_destroy_surface_wait_complete(qxl, id);
-+    }
-+}
-+
- void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
-                                uint32_t count)
- {
-@@ -176,15 +201,28 @@ void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
-     qxl->ssd.worker->reset_memslots(qxl->ssd.worker);
- }
- 
--void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl)
-+static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
- {
-     qemu_mutex_lock(&qxl->track_lock);
--    qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
-     memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds));
-     qxl->guest_surfaces.count = 0;
-     qemu_mutex_unlock(&qxl->track_lock);
- }
- 
-+static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
-+{
-+    if (async) {
-+#if SPICE_INTERFACE_QXL_MINOR < 1
-+        abort();
-+#else
-+        spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0);
-+#endif
-+    } else {
-+        qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
-+        qxl_spice_destroy_surfaces_complete(qxl);
-+    }
-+}
-+
- void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
- {
-     qxl->ssd.worker->reset_image_cache(qxl->ssd.worker);
-@@ -689,6 +727,38 @@ static int interface_flush_resources(QXLInstance *sin)
-     return ret;
- }
- 
-+static void qxl_create_guest_primary_complete(PCIQXLDevice *d);
-+
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+
-+/* called from spice server thread context only */
-+static void interface_async_complete(QXLInstance *sin, uint64_t cookie)
-+{
-+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-+    uint32_t current_async;
-+
-+    qemu_mutex_lock(&qxl->async_lock);
-+    current_async = qxl->current_async;
-+    qxl->current_async = QXL_UNDEFINED_IO;
-+    qemu_mutex_unlock(&qxl->async_lock);
-+
-+    dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie);
-+    switch (current_async) {
-+    case QXL_IO_CREATE_PRIMARY_ASYNC:
-+        qxl_create_guest_primary_complete(qxl);
-+        break;
-+    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
-+        qxl_spice_destroy_surfaces_complete(qxl);
-+        break;
-+    case QXL_IO_DESTROY_SURFACE_ASYNC:
-+        qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie);
-+        break;
-+    }
-+    qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
-+}
-+
-+#endif
-+
- static const QXLInterface qxl_interface = {
-     .base.type               = SPICE_INTERFACE_QXL,
-     .base.description        = "qxl gpu",
-@@ -708,6 +778,9 @@ static const QXLInterface qxl_interface = {
-     .req_cursor_notification = interface_req_cursor_notification,
-     .notify_update           = interface_notify_update,
-     .flush_resources         = interface_flush_resources,
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+    .async_complete          = interface_async_complete,
-+#endif
- };
- 
- static void qxl_enter_vga_mode(PCIQXLDevice *d)
-@@ -727,7 +800,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d)
-         return;
-     }
-     dprint(d, 1, "%s\n", __FUNCTION__);
--    qxl_destroy_primary(d);
-+    qxl_destroy_primary(d, QXL_SYNC);
- }
- 
- static void qxl_set_irq(PCIQXLDevice *d)
-@@ -824,13 +897,14 @@ static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
- 
-     if (qxl->mode != QXL_MODE_VGA) {
-         dprint(qxl, 1, "%s\n", __FUNCTION__);
--        qxl_destroy_primary(qxl);
-+        qxl_destroy_primary(qxl, QXL_SYNC);
-         qxl_soft_reset(qxl);
-     }
-     vga_ioport_write(opaque, addr, val);
- }
- 
--static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
-+static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
-+                            qxl_async_io async)
- {
-     static const int regions[] = {
-         QXL_RAM_RANGE_INDEX,
-@@ -900,7 +974,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
-            __FUNCTION__, memslot.slot_id,
-            memslot.virt_start, memslot.virt_end);
- 
--    qemu_spice_add_memslot(&d->ssd, &memslot);
-+    qemu_spice_add_memslot(&d->ssd, &memslot, async);
-     d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
-     d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
-     d->guest_slots[slot_id].delta = delta;
-@@ -925,7 +999,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
- {
-     dprint(d, 1, "%s:\n", __FUNCTION__);
-     d->mode = QXL_MODE_UNDEFINED;
--    qxl_spice_destroy_surfaces(d);
-+    qxl_spice_destroy_surfaces(d, QXL_SYNC);
- }
- 
- /* called from spice server thread context only */
-@@ -950,7 +1024,14 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
-     }
- }
- 
--static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
-+static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl)
-+{
-+    /* for local rendering */
-+    qxl_render_resize(qxl);
-+}
-+
-+static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm,
-+                                     qxl_async_io async)
- {
-     QXLDevSurfaceCreate surface;
-     QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
-@@ -978,22 +1059,26 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
- 
-     qxl->mode = QXL_MODE_NATIVE;
-     qxl->cmdflags = 0;
--    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface);
-+    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface, async);
- 
--    /* for local rendering */
--    qxl_render_resize(qxl);
-+    if (async == QXL_SYNC) {
-+        qxl_create_guest_primary_complete(qxl);
-+    }
- }
- 
--static void qxl_destroy_primary(PCIQXLDevice *d)
-+/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or
-+ * done (in QXL_SYNC case), 0 otherwise. */
-+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
- {
-     if (d->mode == QXL_MODE_UNDEFINED) {
--        return;
-+        return 0;
-     }
- 
-     dprint(d, 1, "%s\n", __FUNCTION__);
- 
-     d->mode = QXL_MODE_UNDEFINED;
--    qemu_spice_destroy_primary_surface(&d->ssd, 0);
-+    qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
-+    return 1;
- }
- 
- static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
-@@ -1023,10 +1108,10 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
-     }
- 
-     d->guest_slots[0].slot = slot;
--    qxl_add_memslot(d, 0, devmem);
-+    qxl_add_memslot(d, 0, devmem, QXL_SYNC);
- 
-     d->guest_primary.surface = surface;
--    qxl_create_guest_primary(d, 0);
-+    qxl_create_guest_primary(d, 0, QXL_SYNC);
- 
-     d->mode = QXL_MODE_COMPAT;
-     d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
-@@ -1044,6 +1129,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
- {
-     PCIQXLDevice *d = opaque;
-     uint32_t io_port = addr - d->io_base;
-+    qxl_async_io async = QXL_SYNC;
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+    uint32_t orig_io_port = io_port;
-+#endif
- 
-     switch (io_port) {
-     case QXL_IO_RESET:
-@@ -1053,6 +1142,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-     case QXL_IO_CREATE_PRIMARY:
-     case QXL_IO_UPDATE_IRQ:
-     case QXL_IO_LOG:
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+    case QXL_IO_MEMSLOT_ADD_ASYNC:
-+    case QXL_IO_CREATE_PRIMARY_ASYNC:
-+#endif
-         break;
-     default:
-         if (d->mode != QXL_MODE_VGA) {
-@@ -1060,15 +1153,61 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-         }
-         dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n",
-             __func__, io_port, io_port_to_string(io_port));
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+        /* be nice to buggy guest drivers */
-+        if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
-+            io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
-+            qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
-+        }
-+#endif
-         return;
-     }
- 
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+    /* we change the io_port to avoid ifdeffery in the main switch */
-+    orig_io_port = io_port;
-+    switch (io_port) {
-+    case QXL_IO_UPDATE_AREA_ASYNC:
-+        io_port = QXL_IO_UPDATE_AREA;
-+        goto async_common;
-+    case QXL_IO_MEMSLOT_ADD_ASYNC:
-+        io_port = QXL_IO_MEMSLOT_ADD;
-+        goto async_common;
-+    case QXL_IO_CREATE_PRIMARY_ASYNC:
-+        io_port = QXL_IO_CREATE_PRIMARY;
-+        goto async_common;
-+    case QXL_IO_DESTROY_PRIMARY_ASYNC:
-+        io_port = QXL_IO_DESTROY_PRIMARY;
-+        goto async_common;
-+    case QXL_IO_DESTROY_SURFACE_ASYNC:
-+        io_port = QXL_IO_DESTROY_SURFACE_WAIT;
-+        goto async_common;
-+    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
-+        io_port = QXL_IO_DESTROY_ALL_SURFACES;
-+async_common:
-+        async = QXL_ASYNC;
-+        qemu_mutex_lock(&d->async_lock);
-+        if (d->current_async != QXL_UNDEFINED_IO) {
-+            qxl_guest_bug(d, "%d async started before last (%d) complete",
-+                io_port, d->current_async);
-+            qemu_mutex_unlock(&d->async_lock);
-+            return;
-+        }
-+        d->current_async = orig_io_port;
-+        qemu_mutex_unlock(&d->async_lock);
-+        dprint(d, 2, "start async %d (%d)\n", io_port, val);
-+        break;
-+    default:
-+        break;
-+    }
-+#endif
-+
-     switch (io_port) {
-     case QXL_IO_UPDATE_AREA:
-     {
-         QXLRect update = d->ram->update_area;
-         qxl_spice_update_area(d, d->ram->update_surface,
--                              &update, NULL, 0, 0);
-+                              &update, NULL, 0, 0, async);
-         break;
-     }
-     case QXL_IO_NOTIFY_CMD:
-@@ -1116,7 +1255,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-             break;
-         }
-         d->guest_slots[val].slot = d->ram->mem_slot;
--        qxl_add_memslot(d, val, 0);
-+        qxl_add_memslot(d, val, 0, async);
-         break;
-     case QXL_IO_MEMSLOT_DEL:
-         if (val >= NUM_MEMSLOTS) {
-@@ -1127,31 +1266,56 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-         break;
-     case QXL_IO_CREATE_PRIMARY:
-         if (val != 0) {
--            qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY: val != 0");
--            break;
-+            qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY (async=%d): val != 0",
-+                          async);
-+            goto cancel_async;
-         }
--        dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n");
-+        dprint(d, 1, "QXL_IO_CREATE_PRIMARY async=%d\n", async);
-         d->guest_primary.surface = d->ram->create_surface;
--        qxl_create_guest_primary(d, 0);
-+        qxl_create_guest_primary(d, 0, async);
-         break;
-     case QXL_IO_DESTROY_PRIMARY:
-         if (val != 0) {
--            qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY: val != 0");
--            break;
-+            qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY (async=%d): val != 0",
-+                          async);
-+            goto cancel_async;
-+        }
-+        dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (async=%d) (%s)\n", async,
-+               qxl_mode_to_string(d->mode));
-+        if (!qxl_destroy_primary(d, async)) {
-+            dprint(d, 1, "QXL_IO_DESTROY_PRIMARY_ASYNC in %s, ignored\n",
-+                    qxl_mode_to_string(d->mode));
-+            goto cancel_async;
-         }
--        dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode));
--        qxl_destroy_primary(d);
-         break;
-     case QXL_IO_DESTROY_SURFACE_WAIT:
--        qxl_spice_destroy_surface_wait(d, val);
-+        if (val >= NUM_SURFACES) {
-+            qxl_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
-+                             "%d >= NUM_SURFACES", async, val);
-+            goto cancel_async;
-+        }
-+        qxl_spice_destroy_surface_wait(d, val, async);
-         break;
-     case QXL_IO_DESTROY_ALL_SURFACES:
--        qxl_spice_destroy_surfaces(d);
-+        d->mode = QXL_MODE_UNDEFINED;
-+        qxl_spice_destroy_surfaces(d, async);
-         break;
-     default:
-         fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
-         abort();
-     }
-+    return;
-+cancel_async:
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+    if (async) {
-+        qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
-+        qemu_mutex_lock(&d->async_lock);
-+        d->current_async = QXL_UNDEFINED_IO;
-+        qemu_mutex_unlock(&d->async_lock);
-+    }
-+#else
-+    return;
-+#endif
- }
- 
- static uint32_t ioport_read(void *opaque, uint32_t addr)
-@@ -1364,6 +1528,8 @@ static int qxl_init_common(PCIQXLDevice *qxl)
-     qxl->num_memslots = NUM_MEMSLOTS;
-     qxl->num_surfaces = NUM_SURFACES;
-     qemu_mutex_init(&qxl->track_lock);
-+    qemu_mutex_init(&qxl->async_lock);
-+    qxl->current_async = QXL_UNDEFINED_IO;
- 
-     switch (qxl->revision) {
-     case 1: /* spice 0.4 -- qxl-1 */
-@@ -1528,9 +1694,9 @@ static int qxl_post_load(void *opaque, int version)
-             if (!d->guest_slots[i].active) {
-                 continue;
-             }
--            qxl_add_memslot(d, i, 0);
-+            qxl_add_memslot(d, i, 0, QXL_SYNC);
-         }
--        qxl_create_guest_primary(d, 1);
-+        qxl_create_guest_primary(d, 1, QXL_SYNC);
- 
-         /* replay surface-create and cursor-set commands */
-         cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
-diff --git a/hw/qxl.h b/hw/qxl.h
-index 32ca5a0..1046205 100644
---- a/hw/qxl.h
-+++ b/hw/qxl.h
-@@ -15,6 +15,8 @@ enum qxl_mode {
-     QXL_MODE_NATIVE,
- };
- 
-+#define QXL_UNDEFINED_IO UINT32_MAX
-+
- typedef struct PCIQXLDevice {
-     PCIDevice          pci;
-     SimpleSpiceDisplay ssd;
-@@ -30,6 +32,9 @@ typedef struct PCIQXLDevice {
-     int32_t            num_memslots;
-     int32_t            num_surfaces;
- 
-+    uint32_t           current_async;
-+    QemuMutex          async_lock;
-+
-     struct guest_slots {
-         QXLMemSlot     slot;
-         void           *ptr;
-@@ -104,13 +109,12 @@ void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
- void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
-                            struct QXLRect *area, struct QXLRect *dirty_rects,
-                            uint32_t num_dirty_rects,
--                           uint32_t clear_dirty_region);
--void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id);
-+                           uint32_t clear_dirty_region,
-+                           qxl_async_io async);
- void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
-                                uint32_t count);
- void qxl_spice_oom(PCIQXLDevice *qxl);
- void qxl_spice_reset_memslots(PCIQXLDevice *qxl);
--void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl);
- void qxl_spice_reset_image_cache(PCIQXLDevice *qxl);
- void qxl_spice_reset_cursor(PCIQXLDevice *qxl);
- 
-@@ -122,3 +126,9 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
- void qxl_render_resize(PCIQXLDevice *qxl);
- void qxl_render_update(PCIQXLDevice *qxl);
- void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+void qxl_spice_update_area_async(PCIQXLDevice *qxl, uint32_t surface_id,
-+                                 struct QXLRect *area,
-+                                 uint32_t clear_dirty_region,
-+                                 int is_vga);
-+#endif
-diff --git a/ui/spice-display.c b/ui/spice-display.c
-index af10ae8..683d454 100644
---- a/ui/spice-display.c
-+++ b/ui/spice-display.c
-@@ -62,10 +62,18 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
-     dest->right = MAX(dest->right, r->right);
- }
- 
--
--void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot)
--{
--    ssd->worker->add_memslot(ssd->worker, memslot);
-+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
-+                            qxl_async_io async)
-+{
-+    if (async != QXL_SYNC) {
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+        spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0);
-+#else
-+        abort();
-+#endif
-+    } else {
-+        ssd->worker->add_memslot(ssd->worker, memslot);
-+    }
- }
- 
- void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
-@@ -74,14 +82,33 @@ void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
- }
- 
- void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
--                                       QXLDevSurfaceCreate *surface)
--{
--    ssd->worker->create_primary_surface(ssd->worker, id, surface);
-+                                       QXLDevSurfaceCreate *surface,
-+                                       qxl_async_io async)
-+{
-+    if (async != QXL_SYNC) {
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+        spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0);
-+#else
-+        abort();
-+#endif
-+    } else {
-+        ssd->worker->create_primary_surface(ssd->worker, id, surface);
-+    }
- }
- 
--void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id)
-+
-+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
-+                                        uint32_t id, qxl_async_io async)
- {
--    ssd->worker->destroy_primary_surface(ssd->worker, id);
-+    if (async != QXL_SYNC) {
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+        spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0);
-+#else
-+        abort();
-+#endif
-+    } else {
-+        ssd->worker->destroy_primary_surface(ssd->worker, id);
-+    }
- }
- 
- void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
-@@ -198,7 +225,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
-     memset(&memslot, 0, sizeof(memslot));
-     memslot.slot_group_id = MEMSLOT_GROUP_HOST;
-     memslot.virt_end = ~0;
--    qemu_spice_add_memslot(ssd, &memslot);
-+    qemu_spice_add_memslot(ssd, &memslot, QXL_SYNC);
- }
- 
- void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
-@@ -218,14 +245,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
-     surface.mem        = (intptr_t)ssd->buf;
-     surface.group_id   = MEMSLOT_GROUP_HOST;
- 
--    qemu_spice_create_primary_surface(ssd, 0, &surface);
-+    qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC);
- }
- 
- void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
- {
-     dprint(1, "%s:\n", __FUNCTION__);
- 
--    qemu_spice_destroy_primary_surface(ssd, 0);
-+    qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC);
- }
- 
- void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
-diff --git a/ui/spice-display.h b/ui/spice-display.h
-index abe99c7..1388641 100644
---- a/ui/spice-display.h
-+++ b/ui/spice-display.h
-@@ -33,6 +33,20 @@
- 
- #define NUM_SURFACES 1024
- 
-+/*
-+ * Internal enum to differenciate between options for
-+ * io calls that have a sync (old) version and an _async (new)
-+ * version:
-+ *  QXL_SYNC: use the old version
-+ *  QXL_ASYNC: use the new version and make sure there are no two
-+ *   happening at the same time. This is used for guest initiated
-+ *   calls
-+ */
-+typedef enum qxl_async_io {
-+    QXL_SYNC,
-+    QXL_ASYNC,
-+} qxl_async_io;
-+
- typedef struct SimpleSpiceDisplay SimpleSpiceDisplay;
- typedef struct SimpleSpiceUpdate SimpleSpiceUpdate;
- 
-@@ -82,12 +96,15 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
- void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
- void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
- 
--void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot);
-+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
-+                            qxl_async_io async);
- void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid,
-                             uint32_t sid);
- void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
--                                       QXLDevSurfaceCreate *surface);
--void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id);
-+                                       QXLDevSurfaceCreate *surface,
-+                                       qxl_async_io async);
-+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
-+                                        uint32_t id, qxl_async_io async);
- void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
- void qemu_spice_start(SimpleSpiceDisplay *ssd);
- void qemu_spice_stop(SimpleSpiceDisplay *ssd);
--- 
-1.7.5.1
-
diff --git a/0022-qxl-bump-pci-rev.patch b/0022-qxl-bump-pci-rev.patch
new file mode 100644
index 0000000..17ebfc1
--- /dev/null
+++ b/0022-qxl-bump-pci-rev.patch
@@ -0,0 +1,90 @@
+>From 81c99528614b45f2b8407418f7e2b5742559ac19 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+Date: Wed, 29 Jun 2011 15:51:24 +0200
+Subject: [PATCH 22/28] qxl: bump pci rev
+
+Inform guest drivers about the new features I/O commands we have
+now (async commands, S3 support) if building with newer spice, i.e.
+if SPICE_INTERFACE_QXL_MINOR >= 1.
+
+sneaked in some 81+ column line spliting.
+
+Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
+Signed-off-by: Alon Levy <alevy@redhat.com>
+---
+ hw/qxl.c |   25 ++++++++++++++++++-------
+ hw/qxl.h |    6 ++++++
+ 2 files changed, 24 insertions(+), 7 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 847a9b8..b684608 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -1566,9 +1566,14 @@ static int qxl_init_common(PCIQXLDevice *qxl)
+         pci_device_rev = QXL_REVISION_STABLE_V04;
+         break;
+     case 2: /* spice 0.6 -- qxl-2 */
+-    default:
+         pci_device_rev = QXL_REVISION_STABLE_V06;
+         break;
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++    case 3: /* qxl-3 */
++#endif
++    default:
++        pci_device_rev = QXL_DEFAULT_REVISION;
++        break;
+     }
+ 
+     pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
+@@ -1830,9 +1835,12 @@ static PCIDeviceInfo qxl_info_primary = {
+     .device_id    = QXL_DEVICE_ID_STABLE,
+     .class_id     = PCI_CLASS_DISPLAY_VGA,
+     .qdev.props = (Property[]) {
+-        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
+-        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
+-        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
++        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
++                           64 * 1024 * 1024),
++        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size,
++                           64 * 1024 * 1024),
++        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
++                           QXL_DEFAULT_REVISION),
+         DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
+         DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
+         DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
+@@ -1851,9 +1859,12 @@ static PCIDeviceInfo qxl_info_secondary = {
+     .device_id    = QXL_DEVICE_ID_STABLE,
+     .class_id     = PCI_CLASS_DISPLAY_OTHER,
+     .qdev.props = (Property[]) {
+-        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
+-        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
+-        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
++        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
++                           64 * 1024 * 1024),
++        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size,
++                           64 * 1024 * 1024),
++        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
++                           QXL_DEFAULT_REVISION),
+         DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
+         DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
+         DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
+diff --git a/hw/qxl.h b/hw/qxl.h
+index 1046205..4bcf7e1 100644
+--- a/hw/qxl.h
++++ b/hw/qxl.h
+@@ -102,6 +102,12 @@ typedef struct PCIQXLDevice {
+         }                                                               \
+     } while (0)
+ 
++#if SPICE_INTERFACE_QXL_MINOR >= 1
++#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10
++#else
++#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V06
++#endif
++
+ /* qxl.c */
+ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
+ void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
+-- 
+1.7.5.1
+
diff --git a/0023-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch b/0023-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch
deleted file mode 100644
index ab900ef..0000000
--- a/0023-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch
+++ /dev/null
@@ -1,77 +0,0 @@
->From b751be42f3da5666bd11d5a0acb20f225d9a4eb9 Mon Sep 17 00:00:00 2001
-From: Alon Levy <alevy@redhat.com>
-Date: Sun, 5 Jun 2011 11:01:48 +0300
-Subject: [PATCH 23/25] qxl: add QXL_IO_FLUSH_{SURFACES,RELEASE} for guest
- S3&S4 support
-
-Add two new IOs.
- QXL_IO_FLUSH_SURFACES - equivalent to update area for all surfaces, used
-  to reduce vmexits from NumSurfaces to 1 on guest S3, S4 and resolution change (windows
-  driver implementation is such that this is done on each of those occasions).
- QXL_IO_FLUSH_RELEASE - used to ensure anything on last_release is put on the release ring
-  for the client to free.
-
-Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
-Signed-off-by: Alon Levy <alevy@redhat.com>
----
- hw/qxl.c |   30 ++++++++++++++++++++++++++++++
- 1 files changed, 30 insertions(+), 0 deletions(-)
-
-diff --git a/hw/qxl.c b/hw/qxl.c
-index d3109e4..847a9b8 100644
---- a/hw/qxl.c
-+++ b/hw/qxl.c
-@@ -185,6 +185,13 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
-     }
- }
- 
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl)
-+{
-+    spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0);
-+}
-+#endif
-+
- void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
-                                uint32_t count)
- {
-@@ -1184,6 +1191,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
-         goto async_common;
-     case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
-         io_port = QXL_IO_DESTROY_ALL_SURFACES;
-+        goto async_common;
-+    case QXL_IO_FLUSH_SURFACES_ASYNC:
- async_common:
-         async = QXL_ASYNC;
-         qemu_mutex_lock(&d->async_lock);
-@@ -1296,6 +1305,27 @@ async_common:
-         }
-         qxl_spice_destroy_surface_wait(d, val, async);
-         break;
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+    case QXL_IO_FLUSH_RELEASE: {
-+        QXLReleaseRing *ring = &d->ram->release_ring;
-+        if (ring->prod - ring->cons + 1 == ring->num_items) {
-+            fprintf(stderr,
-+                "ERROR: no flush, full release ring [p%d,%dc]\n",
-+                ring->prod, ring->cons);
-+        }
-+        qxl_push_free_res(d, 1 /* flush */);
-+        dprint(d, 1, "QXL_IO_FLUSH_RELEASE exit (%s, s#=%d, res#=%d,%p)\n",
-+            qxl_mode_to_string(d->mode), d->guest_surfaces.count,
-+            d->num_free_res, d->last_release);
-+        break;
-+    }
-+    case QXL_IO_FLUSH_SURFACES_ASYNC:
-+        dprint(d, 1, "QXL_IO_FLUSH_SURFACES_ASYNC (%d) (%s, s#=%d, res#=%d)\n",
-+               val, qxl_mode_to_string(d->mode), d->guest_surfaces.count,
-+               d->num_free_res);
-+        qxl_spice_flush_surfaces_async(d);
-+        break;
-+#endif
-     case QXL_IO_DESTROY_ALL_SURFACES:
-         d->mode = QXL_MODE_UNDEFINED;
-         qxl_spice_destroy_surfaces(d, async);
--- 
-1.7.5.1
-
diff --git a/0023-virtio-serial-bus-replay-guest_open-on-migration.patch b/0023-virtio-serial-bus-replay-guest_open-on-migration.patch
new file mode 100644
index 0000000..5abb114
--- /dev/null
+++ b/0023-virtio-serial-bus-replay-guest_open-on-migration.patch
@@ -0,0 +1,50 @@
+>From ab57ac80b3e681a61ed34c84c36df673e6f9be33 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy@redhat.com>
+Date: Thu, 28 Jul 2011 15:08:48 +0300
+Subject: [PATCH 23/28] virtio-serial-bus: replay guest_open on migration
+
+When migrating a host with with a spice agent running the mouse becomes
+non operational after the migration. This is rhbz #725965.
+
+The problem is that after migration spice doesn't know the guest agent is open.
+Spice is just a char dev here. And a chardev cannot query it's device, the
+device has to let the chardev know when it is open. Right now after migration
+the chardev which is recreated is in it's default state, which assumes the
+guest is disconnected.
+
+Char devices carry no information across migration, but the virtio-serial does
+already carry the guest_connected state. This patch passes that bit to the
+chardev.
+
+Signed-off-by: Alon Levy <alevy@redhat.com>
+---
+ hw/virtio-serial-bus.c |    6 ++++++
+ 1 files changed, 6 insertions(+), 0 deletions(-)
+
+diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
+index c5eb931..4a6d932 100644
+--- a/hw/virtio-serial-bus.c
++++ b/hw/virtio-serial-bus.c
+@@ -618,6 +618,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
+     for (i = 0; i < nr_active_ports; i++) {
+         uint32_t id;
+         bool host_connected;
++        VirtIOSerialPortInfo *info;
+ 
+         id = qemu_get_be32(f);
+         port = find_port_by_id(s, id);
+@@ -626,6 +627,11 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
+         }
+ 
+         port->guest_connected = qemu_get_byte(f);
++        info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
++        if (port->guest_connected && info->guest_open) {
++            /* replay guest open */
++            info->guest_open(port);
++        }
+         host_connected = qemu_get_byte(f);
+         if (host_connected != port->host_connected) {
+             /*
+-- 
+1.7.5.1
+
diff --git a/0024-qemu-char-make-qemu_chr_event-public.patch b/0024-qemu-char-make-qemu_chr_event-public.patch
new file mode 100644
index 0000000..2294597
--- /dev/null
+++ b/0024-qemu-char-make-qemu_chr_event-public.patch
@@ -0,0 +1,42 @@
+>From c86147be45fe6cc38efa932f9587774d626a881b Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Thu, 11 Aug 2011 12:16:11 +0200
+Subject: [PATCH 24/28] qemu-char: make qemu_chr_event public
+
+Make qemu_chr_event public so that it can be used by chardev code
+which lives outside of qemu-char.c
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ qemu-char.c |    2 +-
+ qemu-char.h |    1 +
+ 2 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/qemu-char.c b/qemu-char.c
+index 8d39500..5d5a6d5 100644
+--- a/qemu-char.c
++++ b/qemu-char.c
+@@ -119,7 +119,7 @@ static void char_write_unblocked(void *opaque)
+     chr->chr_write_unblocked(chr->handler_opaque);
+ }
+ 
+-static void qemu_chr_event(CharDriverState *s, int event)
++void qemu_chr_event(CharDriverState *s, int event)
+ {
+     /* Keep track if the char device is open */
+     switch (event) {
+diff --git a/qemu-char.h b/qemu-char.h
+index 68e7b5b..77ad62d 100644
+--- a/qemu-char.h
++++ b/qemu-char.h
+@@ -107,6 +107,7 @@ int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg);
+ void qemu_chr_generic_open(CharDriverState *s);
+ int qemu_chr_can_read(CharDriverState *s);
+ void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len);
++void qemu_chr_event(CharDriverState *s, int event);
+ int qemu_chr_get_msgfd(CharDriverState *s);
+ void qemu_chr_accept_input(CharDriverState *s);
+ int qemu_chr_add_client(CharDriverState *s, int fd);
+-- 
+1.7.5.1
+
diff --git a/0024-qxl-bump-pci-rev.patch b/0024-qxl-bump-pci-rev.patch
deleted file mode 100644
index b301840..0000000
--- a/0024-qxl-bump-pci-rev.patch
+++ /dev/null
@@ -1,90 +0,0 @@
->From 37779d77dff7cb73d333a6440cadd1db0638516b Mon Sep 17 00:00:00 2001
-From: Gerd Hoffmann <kraxel@redhat.com>
-Date: Wed, 29 Jun 2011 15:51:24 +0200
-Subject: [PATCH 24/25] qxl: bump pci rev
-
-Inform guest drivers about the new features I/O commands we have
-now (async commands, S3 support) if building with newer spice, i.e.
-if SPICE_INTERFACE_QXL_MINOR >= 1.
-
-sneaked in some 81+ column line spliting.
-
-Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
-Signed-off-by: Alon Levy <alevy@redhat.com>
----
- hw/qxl.c |   25 ++++++++++++++++++-------
- hw/qxl.h |    6 ++++++
- 2 files changed, 24 insertions(+), 7 deletions(-)
-
-diff --git a/hw/qxl.c b/hw/qxl.c
-index 847a9b8..b684608 100644
---- a/hw/qxl.c
-+++ b/hw/qxl.c
-@@ -1566,9 +1566,14 @@ static int qxl_init_common(PCIQXLDevice *qxl)
-         pci_device_rev = QXL_REVISION_STABLE_V04;
-         break;
-     case 2: /* spice 0.6 -- qxl-2 */
--    default:
-         pci_device_rev = QXL_REVISION_STABLE_V06;
-         break;
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+    case 3: /* qxl-3 */
-+#endif
-+    default:
-+        pci_device_rev = QXL_DEFAULT_REVISION;
-+        break;
-     }
- 
-     pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
-@@ -1830,9 +1835,12 @@ static PCIDeviceInfo qxl_info_primary = {
-     .device_id    = QXL_DEVICE_ID_STABLE,
-     .class_id     = PCI_CLASS_DISPLAY_VGA,
-     .qdev.props = (Property[]) {
--        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
--        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
--        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
-+        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
-+                           64 * 1024 * 1024),
-+        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size,
-+                           64 * 1024 * 1024),
-+        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
-+                           QXL_DEFAULT_REVISION),
-         DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
-         DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
-         DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
-@@ -1851,9 +1859,12 @@ static PCIDeviceInfo qxl_info_secondary = {
-     .device_id    = QXL_DEVICE_ID_STABLE,
-     .class_id     = PCI_CLASS_DISPLAY_OTHER,
-     .qdev.props = (Property[]) {
--        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
--        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
--        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
-+        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
-+                           64 * 1024 * 1024),
-+        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size,
-+                           64 * 1024 * 1024),
-+        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
-+                           QXL_DEFAULT_REVISION),
-         DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
-         DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
-         DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
-diff --git a/hw/qxl.h b/hw/qxl.h
-index 1046205..4bcf7e1 100644
---- a/hw/qxl.h
-+++ b/hw/qxl.h
-@@ -102,6 +102,12 @@ typedef struct PCIQXLDevice {
-         }                                                               \
-     } while (0)
- 
-+#if SPICE_INTERFACE_QXL_MINOR >= 1
-+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10
-+#else
-+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V06
-+#endif
-+
- /* qxl.c */
- void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
- void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
--- 
-1.7.5.1
-
diff --git a/0025-spice-qemu-char-Generate-chardev-open-close-events.patch b/0025-spice-qemu-char-Generate-chardev-open-close-events.patch
new file mode 100644
index 0000000..7b4b41b
--- /dev/null
+++ b/0025-spice-qemu-char-Generate-chardev-open-close-events.patch
@@ -0,0 +1,79 @@
+>From d98187ff877341b5db5ca7f9d50b238d5936052b Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Thu, 21 Jul 2011 15:36:40 +0200
+Subject: [PATCH 25/28] spice-qemu-char: Generate chardev open/close events
+
+Define a state callback and make that generate chardev open/close events when
+called by the spice-server.
+
+Note that for all but the newest spice-server versions (which have a fix for
+this) the code ignores these events for a spicevmc with a subtype of vdagent,
+this subtype specific knowledge is undesirable, but unavoidable for now, see:
+http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ spice-qemu-char.c |   35 ++++++++++++++++++++++++++++++++++-
+ 1 files changed, 34 insertions(+), 1 deletions(-)
+
+diff --git a/spice-qemu-char.c b/spice-qemu-char.c
+index 2b8aec4..d55e74a 100644
+--- a/spice-qemu-char.c
++++ b/spice-qemu-char.c
+@@ -89,11 +89,39 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
+     return bytes;
+ }
+ 
++static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
++{
++    SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
++
++#if SPICE_SERVER_VERSION < 0x000901
++    /*
++     * spice-server calls the state callback for the agent channel when the
++     * spice client connects / disconnects. Given that not the client but
++     * the server is doing the parsing of the messages this is wrong as the
++     * server is still listening. Worse, this causes the parser in the server
++     * to go out of sync, so we ignore state calls for subtype vdagent
++     * spicevmc chardevs. For the full story see:
++     * http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html
++     */
++    if (strcmp(sin->subtype, "vdagent") == 0) {
++        return;
++    }
++#endif
++
++    if ((scd->chr->opened && connected) ||
++        (!scd->chr->opened && !connected)) {
++        return;
++    }
++
++    qemu_chr_event(scd->chr, connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED);
++}
++
+ static SpiceCharDeviceInterface vmc_interface = {
+     .base.type          = SPICE_INTERFACE_CHAR_DEVICE,
+     .base.description   = "spice virtual channel char device",
+     .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
+     .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
++    .state              = vmc_state,
+     .write              = vmc_write,
+     .read               = vmc_read,
+ };
+@@ -222,7 +250,12 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr)
+     chr->chr_guest_close = spice_chr_guest_close;
+     s->unblock_timer = qemu_new_timer_ms(vm_clock, spice_chr_unblock, s);
+ 
+-    qemu_chr_generic_open(chr);
++#if SPICE_SERVER_VERSION < 0x000901
++    /* See comment in vmc_state() */
++    if (strcmp(subtype, "vdagent") == 0) {
++        qemu_chr_generic_open(chr);
++    }
++#endif
+ 
+     *_chr = chr;
+     return 0;
+-- 
+1.7.5.1
+
diff --git a/0025-virtio-serial-bus-replay-guest_open-on-migration.patch b/0025-virtio-serial-bus-replay-guest_open-on-migration.patch
deleted file mode 100644
index 84f8a72..0000000
--- a/0025-virtio-serial-bus-replay-guest_open-on-migration.patch
+++ /dev/null
@@ -1,50 +0,0 @@
->From a1f7b1a638423f74a7a8e3e141f760777dcbd1ab Mon Sep 17 00:00:00 2001
-From: Alon Levy <alevy@redhat.com>
-Date: Thu, 28 Jul 2011 15:08:48 +0300
-Subject: [PATCH 25/25] virtio-serial-bus: replay guest_open on migration
-
-When migrating a host with with a spice agent running the mouse becomes
-non operational after the migration. This is rhbz #725965.
-
-The problem is that after migration spice doesn't know the guest agent is open.
-Spice is just a char dev here. And a chardev cannot query it's device, the
-device has to let the chardev know when it is open. Right now after migration
-the chardev which is recreated is in it's default state, which assumes the
-guest is disconnected.
-
-Char devices carry no information across migration, but the virtio-serial does
-already carry the guest_connected state. This patch passes that bit to the
-chardev.
-
-Signed-off-by: Alon Levy <alevy@redhat.com>
----
- hw/virtio-serial-bus.c |    6 ++++++
- 1 files changed, 6 insertions(+), 0 deletions(-)
-
-diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
-index c5eb931..4a6d932 100644
---- a/hw/virtio-serial-bus.c
-+++ b/hw/virtio-serial-bus.c
-@@ -618,6 +618,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
-     for (i = 0; i < nr_active_ports; i++) {
-         uint32_t id;
-         bool host_connected;
-+        VirtIOSerialPortInfo *info;
- 
-         id = qemu_get_be32(f);
-         port = find_port_by_id(s, id);
-@@ -626,6 +627,11 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
-         }
- 
-         port->guest_connected = qemu_get_byte(f);
-+        info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
-+        if (port->guest_connected && info->guest_open) {
-+            /* replay guest open */
-+            info->guest_open(port);
-+        }
-         host_connected = qemu_get_byte(f);
-         if (host_connected != port->host_connected) {
-             /*
--- 
-1.7.5.1
-
diff --git a/0026-usb-redir-Call-qemu_chr_guest_open-close.patch b/0026-usb-redir-Call-qemu_chr_guest_open-close.patch
new file mode 100644
index 0000000..8bb4dbf
--- /dev/null
+++ b/0026-usb-redir-Call-qemu_chr_guest_open-close.patch
@@ -0,0 +1,37 @@
+>From c8a865625b713ffc1cff6ff97fc3e4c01aeeb0f7 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Thu, 21 Jul 2011 16:28:06 +0200
+Subject: [PATCH 26/28] usb-redir: Call qemu_chr_guest_open/close
+
+To let the chardev now we're ready start receiving data. This is necessary
+with the spicevmc chardev to get it registered with the spice-server.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ usb-redir.c |    3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/usb-redir.c b/usb-redir.c
+index 6932beb..9ce2c8b 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -839,6 +839,8 @@ static int usbredir_initfn(USBDevice *udev)
+     /* We'll do the attach once we receive the speed from the usb-host */
+     udev->auto_attach = 0;
+ 
++    /* Let the other side know we are ready */
++    qemu_chr_guest_open(dev->cs);
+     qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev);
+ 
+     return 0;
+@@ -861,6 +863,7 @@ static void usbredir_handle_destroy(USBDevice *udev)
+ {
+     USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+ 
++    qemu_chr_guest_close(dev->cs);
+     qemu_chr_close(dev->cs);
+     /* Note must be done after qemu_chr_close, as that causes a close event */
+     qemu_bh_delete(dev->open_close_bh);
+-- 
+1.7.5.1
+
diff --git a/0027-usb-redir-Device-disconnect-re-connect-robustness-fi.patch b/0027-usb-redir-Device-disconnect-re-connect-robustness-fi.patch
new file mode 100644
index 0000000..baf9f81
--- /dev/null
+++ b/0027-usb-redir-Device-disconnect-re-connect-robustness-fi.patch
@@ -0,0 +1,88 @@
+>From a6fba82709859fc91e676ce53079eb250bb55750 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Thu, 4 Aug 2011 14:41:07 +0200
+Subject: [PATCH 27/28] usb-redir: Device disconnect + re-connect robustness
+ fixes
+
+These fixes mainly target the other side sending some (error status)
+packets after a disconnect packet. In some cases these would get queued
+up and then reported to the controller when a new device gets connected.
+
+* Fully reset device state on disconnect
+* Don't allow a connect message when already connected
+* Ignore iso and interrupt status messages when disconnected
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ usb-redir.c |   22 +++++++++++++++++++++-
+ 1 files changed, 21 insertions(+), 1 deletions(-)
+
+diff --git a/usb-redir.c b/usb-redir.c
+index 9ce2c8b..6d8f986 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -905,6 +905,11 @@ static void usbredir_device_connect(void *priv,
+ {
+     USBRedirDevice *dev = priv;
+ 
++    if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) {
++        ERROR("Received device connect while already connected\n");
++        return;
++    }
++
+     switch (device_connect->speed) {
+     case usb_redir_speed_low:
+         DPRINTF("attaching low speed device\n");
+@@ -933,19 +938,26 @@ static void usbredir_device_connect(void *priv,
+ static void usbredir_device_disconnect(void *priv)
+ {
+     USBRedirDevice *dev = priv;
++    int i;
+ 
+     /* Stop any pending attaches */
+     qemu_del_timer(dev->attach_timer);
+ 
+     if (dev->dev.attached) {
+         usb_device_detach(&dev->dev);
+-        usbredir_cleanup_device_queues(dev);
+         /*
+          * Delay next usb device attach to give the guest a chance to see
+          * see the detach / attach in case of quick close / open succession
+          */
+         dev->next_attach_time = qemu_get_clock_ms(vm_clock) + 200;
+     }
++
++    /* Reset state so that the next dev connected starts with a clean slate */
++    usbredir_cleanup_device_queues(dev);
++    memset(dev->endpoint, 0, sizeof(dev->endpoint));
++    for (i = 0; i < MAX_ENDPOINTS; i++) {
++        QTAILQ_INIT(&dev->endpoint[i].bufpq);
++    }
+ }
+ 
+ static void usbredir_interface_info(void *priv,
+@@ -1037,6 +1049,10 @@ static void usbredir_iso_stream_status(void *priv, uint32_t id,
+     DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status,
+             ep, id);
+ 
++    if (!dev->dev.attached) {
++        return;
++    }
++
+     dev->endpoint[EP2I(ep)].iso_error = iso_stream_status->status;
+     if (iso_stream_status->status == usb_redir_stall) {
+         DPRINTF("iso stream stopped by peer ep %02X\n", ep);
+@@ -1054,6 +1070,10 @@ static void usbredir_interrupt_receiving_status(void *priv, uint32_t id,
+     DPRINTF("interrupt recv status %d ep %02X id %u\n",
+             interrupt_receiving_status->status, ep, id);
+ 
++    if (!dev->dev.attached) {
++        return;
++    }
++
+     dev->endpoint[EP2I(ep)].interrupt_error =
+         interrupt_receiving_status->status;
+     if (interrupt_receiving_status->status == usb_redir_stall) {
+-- 
+1.7.5.1
+
diff --git a/0028-usb-redir-Don-t-try-to-write-to-the-chardev-after-a-.patch b/0028-usb-redir-Don-t-try-to-write-to-the-chardev-after-a-.patch
new file mode 100644
index 0000000..18e5064
--- /dev/null
+++ b/0028-usb-redir-Don-t-try-to-write-to-the-chardev-after-a-.patch
@@ -0,0 +1,32 @@
+>From 7e49ff036892fade86c7734118ee0c6da5cbad09 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Thu, 11 Aug 2011 12:11:16 +0200
+Subject: [PATCH 28/28] usb-redir: Don't try to write to the chardev after a
+ close event
+
+Sicne we handle close async in a bh, do_write and thus write can get
+called after receiving a close event. This patch adds a check to
+the usb-redir write callback to not do a qemu_chr_write on a closed
+chardev.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ usb-redir.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/usb-redir.c b/usb-redir.c
+index 6d8f986..732ddab 100644
+--- a/usb-redir.c
++++ b/usb-redir.c
+@@ -226,7 +226,7 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
+     USBRedirDevice *dev = priv;
+     int r;
+ 
+-    if (dev->cs->write_blocked) {
++    if (!dev->cs->opened || dev->cs->write_blocked) {
+         return 0;
+     }
+ 
+-- 
+1.7.5.1
+
diff --git a/qemu.spec b/qemu.spec
index 5896356..ec75e78 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -1,9 +1,7 @@
-%define githead 0af4922
-
 Summary: QEMU is a FAST! processor emulator
 Name: qemu
 Version: 0.15.0
-Release: 0.3.20110804%githead%{?dist}
+Release: 1%{?dist}
 # Epoch because we pushed a qemu-1.0 package
 Epoch: 2
 License: GPLv2+ and LGPLv2+ and BSD
@@ -19,11 +17,7 @@ URL: http://www.qemu.org/
 %define _smp_mflags %{nil}
 %endif
 
-# Source0: http://downloads.sourceforge.net/sourceforge/kvm/qemu-kvm-%{version}.tar.gz
-# The source for this package was pulled from upstream's git.  Use the
-# following commands to generate the tarball:
-# git archive --format=tar --prefix=qemu-kvm-0.15.0/ 0af4922 | gzip > qemu-kvm-0.15.0-0af4922.tar.gz
-Source0: qemu-kvm-%{version}-%{githead}.tar.gz
+Source0: http://downloads.sourceforge.net/sourceforge/kvm/qemu-kvm-%{version}.tar.gz
 
 Source1: qemu.init
 
@@ -52,23 +46,23 @@ Patch08: 0008-virtio-console-Enable-port-throttling-when-chardev-i.patch
 Patch09: 0009-spice-qemu-char.c-add-throttling.patch
 Patch10: 0010-spice-qemu-char.c-remove-intermediate-buffer.patch
 Patch11: 0011-usb-redir-Add-flow-control-support.patch
-Patch12: 0012-usb-redir-Call-qemu_chr_guest_open-close.patch
-Patch13: 0013-spice-qemu-char-Generate-chardev-open-close-events.patch
-Patch14: 0014-spice-add-worker-wrapper-functions.patch
-Patch15: 0015-spice-add-qemu_spice_display_init_common.patch
-Patch16: 0016-spice-qxl-move-worker-wrappers.patch
-Patch17: 0017-qxl-fix-surface-tracking-locking.patch
-Patch18: 0018-qxl-add-io_port_to_string.patch
-Patch19: 0019-qxl-error-handling-fixes-and-cleanups.patch
-Patch20: 0020-qxl-make-qxl_guest_bug-take-variable-arguments.patch
-Patch21: 0021-qxl-only-disallow-specific-io-s-in-vga-mode.patch
-Patch22: 0022-qxl-async-io-support-using-new-spice-api.patch
-Patch23: 0023-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch
-Patch24: 0024-qxl-bump-pci-rev.patch
-Patch25: 0025-virtio-serial-bus-replay-guest_open-on-migration.patch
-
-# Fix for default accelerator in non-KVM builds
-Patch100: qemu-kvm-default-accelerator.patch
+Patch12: 0012-spice-add-worker-wrapper-functions.patch
+Patch13: 0013-spice-add-qemu_spice_display_init_common.patch
+Patch14: 0014-spice-qxl-move-worker-wrappers.patch
+Patch15: 0015-qxl-fix-surface-tracking-locking.patch
+Patch16: 0016-qxl-add-io_port_to_string.patch
+Patch17: 0017-qxl-error-handling-fixes-and-cleanups.patch
+Patch18: 0018-qxl-make-qxl_guest_bug-take-variable-arguments.patch
+Patch19: 0019-qxl-only-disallow-specific-io-s-in-vga-mode.patch
+Patch20: 0020-qxl-async-io-support-using-new-spice-api.patch
+Patch21: 0021-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch
+Patch22: 0022-qxl-bump-pci-rev.patch
+Patch23: 0023-virtio-serial-bus-replay-guest_open-on-migration.patch
+Patch24: 0024-qemu-char-make-qemu_chr_event-public.patch
+Patch25: 0025-spice-qemu-char-Generate-chardev-open-close-events.patch
+Patch26: 0026-usb-redir-Call-qemu_chr_guest_open-close.patch
+Patch27: 0027-usb-redir-Device-disconnect-re-connect-robustness-fi.patch
+Patch28: 0028-usb-redir-Don-t-try-to-write-to-the-chardev-after-a-.patch
 
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 BuildRequires: SDL-devel zlib-devel which texi2html gnutls-devel cyrus-sasl-devel
@@ -267,8 +261,9 @@ such as kvm_stat.
 %patch23 -p1
 %patch24 -p1
 %patch25 -p1
-
-%patch100 -p1
+%patch26 -p1
+%patch27 -p1
+%patch28 -p1
 
 %build
 # By default we build everything, but allow x86 to build a minimal version
@@ -579,6 +574,9 @@ fi
 %{_mandir}/man1/qemu-img.1*
 
 %changelog
+* Sun Aug 14 2011 Justin M. Forbes <jforbes@redhat.com> - 2:0.15.0-1
+- Update to 0.15.0 stable release.
+
 * Thu Aug 04 2011 Justin M. Forbes <jforbes@redhat.com> - 2:0.15.0-0.3.201108040af4922
 - Update to 0.15.0-rc1 as we prepare for 0.15.0 release
 
diff --git a/sources b/sources
index 48c748a..250f8be 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-a6d16b7d6acfa94300586eda5e7c19a3  qemu-kvm-0.15.0-0af4922.tar.gz
+b45b0deebba4ce47dcaaab3807f6ed47  qemu-kvm-0.15.0.tar.gz