Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 3160499aacb81f6735941eb4c372d87a > files > 11

kvm-83-164.el5_5.30.src.rpm

From 52f3dde83b45d9e4e84dc68d5c62b96bfd8c70cc Mon Sep 17 00:00:00 2001
From: Yaniv Kamay <yaniv@qumranet.com>
Date: Sun, 21 Dec 2008 13:32:08 +0200
Subject: [PATCH 10/54] qxl: add qxl device + support libspice

[ehabkost: use pkgconfig to probe for spice]

RH-Type: improvement(qxl)
RH-Upstream-status: pending
---
 qemu/Makefile               |    5 +
 qemu/Makefile.target        |   13 +
 qemu/configure              |   52 ++++-
 qemu/console.h              |    1 +
 qemu/hw/pc.c                |   13 +
 qemu/hw/pc.h                |   18 ++
 qemu/hw/ps2.c               |  217 ++++++++++++++++++-
 qemu/hw/qxl.c               |  508 ++++++++++++++++++++++++++++++-------------
 qemu/hw/qxl_interface.h     |   54 +++--
 qemu/hw/qxl_native_worker.c |  151 +++++++++++++
 qemu/hw/usb-hid.c           |   96 ++++++++-
 qemu/hw/vga.c               |   17 ++
 qemu/interface.c            |  232 ++++++++++++++++++++
 qemu/interface.h            |   12 +
 qemu/monitor.c              |  210 ++++++++++++++++--
 qemu/vl.c                   |   99 ++++++++-
 16 files changed, 1488 insertions(+), 210 deletions(-)
 create mode 100644 qemu/hw/qxl_native_worker.c
 create mode 100644 qemu/interface.c
 create mode 100644 qemu/interface.h

diff --git a/qemu/Makefile b/qemu/Makefile
index 8293bf9..f277379 100644
--- a/qemu/Makefile
+++ b/qemu/Makefile
@@ -151,6 +151,11 @@ ifdef CONFIG_COCOA
 OBJS+=cocoa.o
 endif
 
+ifdef CONFIG_SPICE
+CFLAGS+=$(SPICE_CFLAGS)
+LIBS+=$(SPICE_LIBS)
+endif
+
 ifdef CONFIG_SLIRP
 CPPFLAGS+=-I$(SRC_PATH)/slirp
 SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \
diff --git a/qemu/Makefile.target b/qemu/Makefile.target
index 5cf1dda..806fdb5 100644
--- a/qemu/Makefile.target
+++ b/qemu/Makefile.target
@@ -231,6 +231,11 @@ LIBOBJS+=qemu-kvm-helper.o
 endif
 endif
 
+ifeq ($(CONFIG_SPICE),yes)
+CFLAGS+=$(SPICE_CFLAGS)
+LIBS+=$(SPICE_LIBS)
+endif
+
 LIBOBJS+= op_helper.o
 
 ifneq ($(TARGET_ARCH), ia64)
@@ -710,6 +715,14 @@ OBJS+= extboot.o
 # virtio support
 OBJS+= virtio.o virtio-blk.o virtio-balloon.o
 OBJS += virtio-net.o
+
+ifeq ($(CONFIG_QXL),yes)
+OBJS+=qxl.o qxl_native_worker.o 
+endif
+ifeq ($(CONFIG_SPICE),yes)
+OBJS+=interface.o
+endif
+
 ifeq ($(USE_KVM_PIT), 1)
 OBJS+= i8254-kvm.o
 endif
diff --git a/qemu/configure b/qemu/configure
index f405b86..3276832 100755
--- a/qemu/configure
+++ b/qemu/configure
@@ -184,6 +184,8 @@ fdt="yes"
 signalfd="no"
 eventfd="no"
 cpu_emulation="yes"
+qxl="yes"
+spice="no"
 
 # OS specific
 if check_define __linux__ ; then
@@ -391,6 +393,10 @@ for opt do
   ;;
   --disable-vde) vde="no"
   ;;
+  --disable-qxl) qxl="no"
+  ;;
+  --enable-spice) spice="yes"
+  ;;
   --disable-kqemu) kqemu="no"
   ;;
   --disable-brlapi) brlapi="no"
@@ -569,6 +575,8 @@ echo "  --disable-aio            disable AIO support"
 echo "  --disable-blobs          disable installing provided firmware blobs"
 echo "  --kerneldir=PATH         look for kernel includes in PATH"
 echo "  --disable-cpu-emulation  disables use of qemu cpu emulation code"
+echo "  --disable-qxl            disable qxl"
+echo "  --enable-spice           use spice"
 echo ""
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
@@ -1140,6 +1148,26 @@ if [ -x "`which texi2html 2>/dev/null`" ] && \
 fi
 
 ##########################################
+# spice probe
+if test "$spice" = "yes" ; then
+  `pkg-config spice` || spice="no"
+fi
+if test "$spice" = "yes" ; then
+  cat > $TMPC << EOF
+#include <spice.h>
+int main(void) { CoreInterface ci; spice_init(&ci); return 0; }
+EOF
+  spice_cflags=`pkg-config --cflags spice`
+  spice_libs=`pkg-config --libs spice`
+  if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $spice_cflags $TMPC \
+      $spice_libs > /dev/null 2> /dev/null ; then
+    :
+  else
+    spice="no"
+  fi
+fi
+
+##########################################
 # Do we need librt
 cat > $TMPC <<EOF
 #include <signal.h>
@@ -1233,9 +1261,8 @@ echo "uname -r          $uname_release"
 echo "NPTL support      $nptl"
 echo "vde support       $vde"
 echo "AIO support       $aio"
-echo "Install blobs     $blobs"
-echo "KVM support       $kvm"
-echo "fdt support       $fdt"
+echo "QXL               $qxl"
+echo "Spice             $spice"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -1543,6 +1570,23 @@ if test "$eventfd" = "yes" ; then
   echo "#define CONFIG_eventfd 1" >> $config_h
 fi
 
+if test "$qxl" = "yes" ; then
+  echo "CONFIG_QXL=yes" >> $config_mak
+  echo "#define CONFIG_QXL 1" >> $config_h
+fi
+
+if test "$spice" = "yes" ; then
+  if test "$qxl" = "no" ; then
+    echo "ERROR: Spice requires QXL device"
+    exit 1;
+  fi
+
+  echo "CONFIG_SPICE=yes" >> $config_mak
+  echo "SPICE_CFLAGS=$spice_cflags" >> $config_mak
+  echo "SPICE_LIBS=$spice_libs" >> $config_mak
+  echo "#define CONFIG_SPICE 1" >> $config_h
+fi
+
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
   echo "#define O_LARGEFILE 0" >> $config_h
@@ -1623,7 +1667,7 @@ case "$target" in
 esac
 
 if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
-        -a "$sdl" = "no" -a "$cocoa" = "no" ; then
+        -a "$sdl" = "no" -a "$cocoa" = "no" -a "$qxl" = "no" ; then
     echo "ERROR: QEMU requires SDL or Cocoa for graphical output"
     echo "To build QEMU without graphical output configure with --disable-gfx-check"
     echo "Note that this will disable all output from the virtual graphics card"
diff --git a/qemu/console.h b/qemu/console.h
index 6ee40cc..791d32a 100644
--- a/qemu/console.h
+++ b/qemu/console.h
@@ -191,6 +191,7 @@ extern uint8_t _translate_keycode(const int key);
 /* FIXME: term_printf et al should probably go elsewhere so everything
    does not need to include console.h  */
 /* monitor.c */
+void init_monitor_commands();
 void monitor_init(CharDriverState *hd, int show_banner);
 void term_puts(const char *str);
 void term_vprintf(const char *fmt, va_list ap);
diff --git a/qemu/hw/pc.c b/qemu/hw/pc.c
index 3038cd3..51f78e1 100644
--- a/qemu/hw/pc.c
+++ b/qemu/hw/pc.c
@@ -1006,6 +1006,19 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
             isa_cirrus_vga_init(ds, phys_ram_base + vga_ram_addr,
                                 vga_ram_addr, vga_ram_size);
         }
+#ifdef CONFIG_QXL
+    } else if (using_qxl) {
+        if (!pci_enabled) {
+            fprintf(stderr, "%s: can't use qxl without pci\n", __FUNCTION__);
+            exit(-1);
+        }
+        isa_vga_init(ds, phys_ram_base + vga_ram_addr,
+                         vga_ram_addr, vga_ram_size);
+        for (i = 0; i < num_qxl_device; i++) {
+            ram_addr_t qxl_ram = qemu_ram_alloc(QXL_MEM_SIZE);
+            qxl_init(pci_bus, phys_ram_base + qxl_ram, qxl_ram, QXL_MEM_SIZE);
+        }
+#endif
     } else if (vmsvga_enabled) {
         if (pci_enabled)
             pci_vmsvga_init(pci_bus, ds, phys_ram_base + vga_ram_addr,
diff --git a/qemu/hw/pc.h b/qemu/hw/pc.h
index e9ddd4d..a4aede5 100644
--- a/qemu/hw/pc.h
+++ b/qemu/hw/pc.h
@@ -158,6 +158,24 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
 void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
                          ram_addr_t vga_ram_offset, int vga_ram_size);
 
+/*qxl.c*/
+#ifdef CONFIG_QXL
+
+#define QXL_MEM_SIZE (1024 * 1024 * (32 + 9))
+#define QXL_MAX_MONITORS 4
+
+extern int using_qxl;
+extern int num_qxl_device;
+
+void qxl_init(PCIBus *bus, uint8_t *vram,
+              unsigned long vram_offset,
+              uint32_t vram_size);
+void qxl_init_display(DisplayState *ds);
+int qxl_vga_touch(void);
+void qxl_do_set_log_level(int log_level);
+
+#endif
+
 /* ide.c */
 void isa_ide_init(int iobase, int iobase2, qemu_irq irq,
                   BlockDriverState *hd0, BlockDriverState *hd1);
diff --git a/qemu/hw/ps2.c b/qemu/hw/ps2.c
index 054b92f..405b9c3 100644
--- a/qemu/hw/ps2.c
+++ b/qemu/hw/ps2.c
@@ -24,6 +24,9 @@
 #include "hw.h"
 #include "ps2.h"
 #include "console.h"
+#ifdef CONFIG_SPICE
+#include "interface.h"
+#endif
 
 /* debug PC keyboard */
 //#define DEBUG_KBD
@@ -92,6 +95,7 @@ typedef struct {
        not the keyboard controller.  */
     int translate;
     int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
+    uint8_t leds; //bit 0 scroll lock, bit 1 num lock and bit 2 caps lock
 } PS2KbdState;
 
 typedef struct {
@@ -181,10 +185,101 @@ uint32_t ps2_read_data(void *opaque)
     return val;
 }
 
+#ifdef CONFIG_SPICE
+
+typedef struct KBDLedNotifier KBDLedNotifier;
+struct KBDLedNotifier {
+    void *opaque;
+    keyborad_leads_notifier_t proc;
+    int refs;
+    KBDLedNotifier *next;
+};
+
+static KBDLedNotifier *kbd_leds_notifiers = NULL;
+
+static KBDLedNotifier *register_leds_notifier(keyborad_leads_notifier_t proc, void *opaque)
+{
+    KBDLedNotifier *notifier;
+
+    if (!proc) {
+        return NULL;
+    }
+
+    if (!(notifier = (KBDLedNotifier *)malloc(sizeof(*notifier)))) {
+        printf("%s: malloc failed\n", __FUNCTION__);
+        exit(-1);
+    }
+    notifier->opaque = opaque;
+    notifier->proc = proc;
+    notifier->refs = 1;
+    notifier->next = kbd_leds_notifiers;
+    kbd_leds_notifiers = notifier;
+    return notifier;
+}
+
+static void hold_led_notifier(KBDLedNotifier* notifier)
+{
+    notifier->refs++;
+}
+
+static void releas_led_notifier(KBDLedNotifier* notifier)
+{
+    if (--notifier->refs) {
+        return;
+    }
+    KBDLedNotifier **now = &kbd_leds_notifiers;
+
+    while (*now != notifier) {
+        now = &(*now)->next;
+    }
+    *now = notifier->next;
+    free(notifier);
+}
+
+static void unregister_leds_notifier(KBDLedNotifier *notifier)
+{
+    KBDLedNotifier **now = &kbd_leds_notifiers;
+    for (;;) {
+        if (*now == notifier) {
+            notifier->proc = NULL;
+            releas_led_notifier(notifier);
+            return;
+        }
+        now = &(*now)->next;
+    }
+}
+
+static void on_leds_change(uint8_t leds)
+{
+    KBDLedNotifier *notifier = kbd_leds_notifiers;
+    KBDLedNotifier *temp;
+
+    while (notifier) {
+        hold_led_notifier(notifier);
+        notifier->proc(notifier->opaque, leds);
+        temp = notifier;
+        notifier = notifier->next;
+        releas_led_notifier(temp);
+    }
+}
+#endif
+
+static void ps2_set_keyboard_leds(PS2KbdState *s, uint8_t new_val)
+{
+    if (new_val == s->leds) {
+        return;
+    }
+    s->leds = new_val;
+#ifdef CONFIG_SPICE
+    on_leds_change(new_val);
+#endif
+}
+
 static void ps2_reset_keyboard(PS2KbdState *s)
 {
     s->scan_enabled = 1;
     s->scancode_set = 2;
+    ps2_set_keyboard_leds(s, 0);
 }
 
 void ps2_write_keyboard(void *opaque, int val)
@@ -259,6 +354,7 @@ void ps2_write_keyboard(void *opaque, int val)
         s->common.write_cmd = -1;
         break;
     case KBD_CMD_SET_LEDS:
+        ps2_set_keyboard_leds(s, val);
         ps2_queue(&s->common, KBD_REPLY_ACK);
         s->common.write_cmd = -1;
         break;
@@ -497,6 +593,7 @@ static void ps2_reset(void *opaque)
     q->rptr = 0;
     q->wptr = 0;
     q->count = 0;
+    s->update_irq(s->update_arg, 0);
 }
 
 static void ps2_common_save (QEMUFile *f, PS2State *s)
@@ -525,6 +622,7 @@ static void ps2_kbd_save(QEMUFile* f, void* opaque)
     qemu_put_be32(f, s->scan_enabled);
     qemu_put_be32(f, s->translate);
     qemu_put_be32(f, s->scancode_set);
+    qemu_put_byte(f, s->leds);
 }
 
 static void ps2_mouse_save(QEMUFile* f, void* opaque)
@@ -548,16 +646,21 @@ static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id)
 {
     PS2KbdState *s = (PS2KbdState*)opaque;
 
-    if (version_id != 2 && version_id != 3)
+    if (version_id < 2 || version_id > 4)
         return -EINVAL;
 
     ps2_common_load (f, &s->common);
     s->scan_enabled=qemu_get_be32(f);
     s->translate=qemu_get_be32(f);
-    if (version_id == 3)
+    if (version_id >= 3)
         s->scancode_set=qemu_get_be32(f);
     else
         s->scancode_set=2;
+    if (version_id >= 4) {
+        ps2_set_keyboard_leds(s, qemu_get_byte(f));
+    } else {
+        ps2_set_keyboard_leds(s, 0);
+    }
     return 0;
 }
 
@@ -582,6 +685,108 @@ static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id)
     return 0;
 }
 
+#ifdef CONFIG_SPICE
+
+typedef struct KbdInterface {
+    KeyboardInterface vd_interface;
+    PS2KbdState *keyboard_state;
+} KbdInterface;
+
+static void interface_push_scan_freg(KeyboardInterface *keyboard, uint8_t frag)
+{
+    KbdInterface *interface = (KbdInterface *)keyboard;
+    ps2_put_keycode(interface->keyboard_state, frag);
+}
+
+static uint8_t interface_get_leds(KeyboardInterface *keyboard)
+{
+    KbdInterface *interface = (KbdInterface *)keyboard;
+    return interface->keyboard_state->leds;
+}
+
+static VDObjectRef interface_register_leds_notifier(KeyboardInterface *keyboard,
+                                                     keyborad_leads_notifier_t notifier,
+                                                     void *opaque)
+{
+    if (!notifier) {
+        return 0;
+    }
+    return (VDObjectRef)register_leds_notifier(notifier, opaque);
+}
+
+static void interface_unregister_leds_notifier(KeyboardInterface *keyboard, VDObjectRef notifier)
+{
+    if (!notifier) {
+        return;
+    }
+    unregister_leds_notifier((KBDLedNotifier *)notifier);
+}
+
+static void regitser_keyboard(PS2KbdState *s)
+{
+    KbdInterface *interface = (KbdInterface *)qemu_mallocz(sizeof(*interface));
+    static int keyboard_interface_id = 0;
+
+    if (!interface) {
+        printf("%s: malloc failed\n", __FUNCTION__);
+        exit(-1);
+    }
+    interface->vd_interface.base.base_vertion = VM_INTERFACE_VERTION;
+    interface->vd_interface.base.type = VD_INTERFACE_KEYBOARD;
+    interface->vd_interface.base.id = ++keyboard_interface_id;
+    interface->vd_interface.base.description = "ps2 keyboard";
+    interface->vd_interface.base.major_vertion = VD_INTERFACE_KEYBOARD_MAJOR;
+    interface->vd_interface.base.minor_vertion = VD_INTERFACE_KEYBOARD_MINOR;
+    interface->vd_interface.push_scan_freg = interface_push_scan_freg;
+    interface->vd_interface.get_leds = interface_get_leds;
+    interface->vd_interface.register_leds_notifier = interface_register_leds_notifier;
+    interface->vd_interface.unregister_leds_notifayer = interface_unregister_leds_notifier;
+    interface->keyboard_state = s;
+    add_interface(&interface->vd_interface.base);
+}
+
+typedef struct PS2MouseInterface {
+    MouseInterface vd_interface;
+    PS2MouseState *mouse_state;
+} PS2MouseInterface;
+
+static void interface_moution(MouseInterface* mouse, int dx, int dy, int dz,
+                              uint32_t buttons_state)
+{
+    PS2MouseInterface *interface = (PS2MouseInterface *)mouse;
+    ps2_mouse_event(interface->mouse_state, dx, dy, dz, buttons_state);
+}
+
+static void interface_buttons(MouseInterface* mouse, uint32_t buttons_state)
+{
+    PS2MouseInterface *interface = (PS2MouseInterface *)mouse;
+    ps2_mouse_event(interface->mouse_state, 0, 0, 0, buttons_state);
+}
+
+static void regitser_mouse(PS2MouseState *s)
+{
+    PS2MouseInterface *interface = (PS2MouseInterface *)qemu_mallocz(sizeof(*interface));
+    static int mouse_interface_id = 0;
+    if (!interface) {
+        printf("%s: malloc failed\n", __FUNCTION__);
+        exit(-1);
+    }
+    interface->vd_interface.base.base_vertion = VM_INTERFACE_VERTION;
+    interface->vd_interface.base.type = VD_INTERFACE_MOUSE;
+    interface->vd_interface.base.id = mouse_interface_id++;
+    interface->vd_interface.base.description = "ps2 mouse";
+    interface->vd_interface.base.major_vertion = VD_INTERFACE_MOUSE_MAJOR;
+    interface->vd_interface.base.minor_vertion = VD_INTERFACE_MOUSE_MINOR;
+
+    interface->vd_interface.moution = interface_moution;
+    interface->vd_interface.buttons = interface_buttons;
+
+    interface->mouse_state = s;
+    add_interface(&interface->vd_interface.base);
+}
+
+#endif
+
 void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
 {
     PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
@@ -590,9 +795,12 @@ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
     s->common.update_arg = update_arg;
     s->scancode_set = 2;
     ps2_reset(&s->common);
-    register_savevm("ps2kbd", 0, 3, ps2_kbd_save, ps2_kbd_load, s);
+    register_savevm("ps2kbd", 0, 4, ps2_kbd_save, ps2_kbd_load, s);
     qemu_add_kbd_event_handler(ps2_put_keycode, s);
     qemu_register_reset(ps2_reset, &s->common);
+#ifdef CONFIG_SPICE
+    regitser_keyboard(s);
+#endif
     return s;
 }
 
@@ -606,5 +814,8 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
     register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s);
     qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
     qemu_register_reset(ps2_reset, &s->common);
+#ifdef CONFIG_SPICE
+    regitser_mouse(s);
+#endif
     return s;
 }
diff --git a/qemu/hw/qxl.c b/qemu/hw/qxl.c
index e37def9..9ce2072 100644
--- a/qemu/hw/qxl.c
+++ b/qemu/hw/qxl.c
@@ -2,35 +2,31 @@
 #include <signal.h>
 
 #include "qemu-common.h"
-#include "hw.h"
-#include "pc.h"
-#include "pci.h"
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "hw/pci.h"
 #include "console.h"
-#include "vga_int.h"
+#include "hw/vga_int.h"
 #include "qemu-timer.h"
 #include "sysemu.h"
 
 #include "qxl_dev.h"
-#include "qxl_interface.h"
-
-#include "qemu-kvm.h"
-
-#define KVM_MEM_ALIAS_QXL_RAM 0
-#define KVM_MEM_ALIAS_QXL_VRAM 1
-#define KVM_MEM_ALIAS_QXL_ROM 2
 
+#ifdef CONFIG_SPICE    
+#include "interface.h"
+#endif
+#include "qxl_interface.h"
 
 //#define QXL_IO_MEM
 
 #define QXL_RAM_SIZE (32 * 1024 * 1024)
-#define QXL_DEFAULT_COMPRESSION_LEVEL 2
+#define QXL_DEFAULT_COMPRESSION_LEVEL 0
 #define QXL_SHARED_VGA_MODE FALSE
 #define QXL_SAVE_VERSION 3
 
-
-#define ASSERT(x) if (!(x)) { 					\
+#define ASSERT(x) if (!(x)) {                               \
 	printf("%s: ASSERT %s failed\n", __FUNCTION__, #x); 	\
-	exit(-1);						\
+	exit(-1);                                               \
 }
 
 #undef ALIGN
@@ -99,7 +95,6 @@ typedef struct QXLState {
 #endif
     int num_free_res;
     QXLReleaseInfo *last_release;
-    QXLWorkerRef worker;
     void *worker_data;
     int worker_data_size;
     int mode;
@@ -108,7 +103,20 @@ typedef struct QXLState {
     int running;
 } QXLState;
 
-typedef struct PCIQXLDevice {
+typedef struct PCIQXLDevice PCIQXLDevice;
+
+#ifdef CONFIG_SPICE
+typedef struct QXLModeNotifier QXLModeNotifier;
+struct QXLModeNotifier {
+    void *opaque;
+    qxl_mode_change_notifier_t proc;
+    PCIQXLDevice *d;
+    int refs;
+    QXLModeNotifier *next;
+};
+#endif
+
+struct PCIQXLDevice {
     PCIDevice pci_dev;
     QXLState state;
     int id;
@@ -116,11 +124,14 @@ typedef struct PCIQXLDevice {
     struct PCIQXLDevice *dev_next;
     struct PCIQXLDevice *vga_next;
     int pipe_fd[2];
-} PCIQXLDevice;
+    QXLWorker* worker;
+#ifdef CONFIG_SPICE
+    QXLModeNotifier *mode_notifiers;
+#endif
+};
 
 static PCIQXLDevice *dev_list = NULL;
 static pthread_t main_thread;
-static int compression_level = QXL_DEFAULT_COMPRESSION_LEVEL;
 
 #define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9" 
 
@@ -180,8 +191,6 @@ static void qxl_reset_state(PCIQXLDevice *d);
 
 static QXLVga qxl_vga;
 
-static QXLModeChangeNotifier qxl_mode_change_notifier = NULL;
-
 inline void atomic_or(uint32_t *var, uint32_t add)
 {
    __asm__ __volatile__ ("lock; orl %1, %0" : "+m" (*var) : "r" (add) : "memory");
@@ -239,18 +248,7 @@ void qxl_update_irq()
     }
 }
 
-void qxl_set_compression_level(int new_compression_level)
-{
-    PCIQXLDevice *d = dev_list;
-
-    compression_level = new_compression_level;
-    while (d) {
-        d->state.rom->compression_level = compression_level;
-        d = d->dev_next;
-    }
-}
-
-void do_set_qxl_log_level(int log_level)
+void qxl_do_set_log_level(int log_level)
 {
     PCIQXLDevice *d = dev_list;
     while (d) {
@@ -272,7 +270,9 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
     } else {
         //dummy write in order to wake up the main thread
         //to update the irq line
-        write(d->pipe_fd[1], d, 1);
+        if (write(d->pipe_fd[1], d, 1) != 1) {
+            printf("%s: write to pipe failed\n", __FUNCTION__);
+        }
     }
 }
 
@@ -287,9 +287,8 @@ static void set_dreaw_area(PCIQXLDevice *d, QXLDevInfo *info)
     info->draw_area.heigth = info->y_res;
 }
 
-void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info)
+static void _qxl_get_info(PCIQXLDevice *d, QXLDevInfo *info)
 {
-    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
     QXLState *state = &d->state;
     QXLMode *mode;
 
@@ -297,6 +296,7 @@ void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info)
         info->x_res = qxl_vga.ds->width;
         info->y_res = qxl_vga.ds->height;
         info->bits = qxl_vga.ds->depth;
+        info->use_hardware_cursor = FALSE;
 
         info->phys_start = 0;
         info->phys_end = ~info->phys_start;
@@ -310,6 +310,7 @@ void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info)
     info->x_res = mode->x_res;
     info->y_res = mode->y_res;
     info->bits = mode->bits;
+    info->use_hardware_cursor = TRUE;
 
     info->phys_start = (unsigned long)state->ram_start + state->rom->pages_offset;
     info->phys_end = (unsigned long)state->ram_start + state->ram_size;
@@ -322,9 +323,8 @@ static QXLCommandRing *qxl_active_ring(PCIQXLDevice *d)
     return (d->state.mode == QXL_MODE_VGA) ? &d->state.vga_ring : &d->state.ram->cmd_ring;
 }
 
-int qxl_get_command(QXLDevRef dev_ref, QXLCommand *cmd)
+static int _qxl_get_command(PCIQXLDevice *d, QXLCommand *cmd)
 {
-    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
     QXLCommandRing *ring = qxl_active_ring(d);
     int notify;
 
@@ -339,16 +339,14 @@ int qxl_get_command(QXLDevRef dev_ref, QXLCommand *cmd)
     return TRUE;
 }
 
-int qxl_has_command(QXLDevRef dev_ref)
+static int _qxl_has_command(PCIQXLDevice *d)
 {
-    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
     QXLCommandRing *ring = qxl_active_ring(d);
     return !RING_IS_EMPTY(ring);
 }
 
-int qxl_get_cursor_command(QXLDevRef dev_ref, QXLCommand *cmd)
+static int _qxl_get_cursor_command(PCIQXLDevice *d, QXLCommand *cmd)
 {
-    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
     QXLCursorRing *ring;
     int notify;
 
@@ -369,24 +367,20 @@ int qxl_get_cursor_command(QXLDevRef dev_ref, QXLCommand *cmd)
     return 1;
 }
 
-const Rect *qxl_get_update_area(QXLDevRef dev_ref)
+static const Rect *_qxl_get_update_area(PCIQXLDevice *d)
 {
-    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
     return &d->state.ram->update_area;
 }
 
-int qxl_req_cmd_notification(QXLDevRef dev_ref)
+static int _qxl_req_cmd_notification(PCIQXLDevice *d)
 {
-    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
     int wait;
-
     RING_CONS_WAIT(qxl_active_ring(d), wait);
     return wait;
 }
 
-int qxl_req_cursor_notification(QXLDevRef dev_ref)
+static int _qxl_req_cursor_notification(PCIQXLDevice *d)
 {
-    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
     int wait;
 
     if (d->state.mode == QXL_MODE_VGA) {
@@ -419,9 +413,8 @@ static inline void qxl_push_free_res(PCIQXLDevice *d)
     }
 }
 
-void qxl_release_resource(QXLDevRef dev_ref, QXLReleaseInfo *release_info)
+static void _qxl_release_resource(PCIQXLDevice *d, QXLReleaseInfo *release_info)
 {
-    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
     UINT64 id = release_info->id;
     QXLState *state = &d->state;
     QXLReleaseRing *ring;
@@ -448,9 +441,8 @@ void qxl_release_resource(QXLDevRef dev_ref, QXLReleaseInfo *release_info)
     qxl_push_free_res(d);
 }
 
-void qxl_set_save_data(QXLDevRef dev_ref, void *data, int size)
+static void _qxl_set_save_data(PCIQXLDevice *d, void *data, int size)
 {
-    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
     QXLState *state = &d->state;
 
     free(state->worker_data);
@@ -458,20 +450,15 @@ void qxl_set_save_data(QXLDevRef dev_ref, void *data, int size)
     state->worker_data_size = size;
 }
 
-void *qxl_get_save_data(QXLDevRef dev_ref)
+static void *_qxl_get_save_data(PCIQXLDevice *d)
 {
-    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
     QXLState *state = &d->state;
-
     return state->worker_data;
-
 }
 
-int qxl_flush_resources(QXLDevRef dev_ref)
+static int _qxl_flush_resources(PCIQXLDevice *d)
 {
-    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
     int ret;
-
     if (d->state.mode == QXL_MODE_VGA) {
         return 0;
     }
@@ -482,10 +469,8 @@ int qxl_flush_resources(QXLDevRef dev_ref)
     return ret;
 }
 
-void qxl_notify_update(QXLDevRef dev_ref, uint32_t update_id)
+static void _qxl_notify_update(PCIQXLDevice *d, uint32_t update_id)
 {
-    PCIQXLDevice *d = (PCIQXLDevice *)dev_ref;
-
     if (d->state.mode == QXL_MODE_VGA) {
         return;
     }
@@ -501,7 +486,7 @@ static void qxl_detach(PCIQXLDevice *d)
         return;
     }
 
-    qxl_worker_detach(d->state.worker);
+    d->worker->detach(d->worker);
     if (d->state.mode != QXL_MODE_VGA) {
         RING_INIT(&d->state.ram->cmd_ring);
         RING_INIT(&d->state.ram->cursor_ring);
@@ -523,44 +508,42 @@ static void qxl_detach(PCIQXLDevice *d)
     }
 }
 
-static void qxl_notify_mode_change()
+#ifdef CONFIG_SPICE
+
+static void hold_mode_notifier(QXLModeNotifier* notifier)
 {
-    PCIQXLDevice *d = dev_list;
-    int qxl_mode_native_counter = 0;
-    int mode = 0;
+    notifier->refs++;
+}
 
-    if (!qxl_mode_change_notifier){
-        return;
-    }
-    if (qxl_vga.active_clients > 0) {
-        qxl_mode_change_notifier(FALSE, 0, 0);
+static void release_mode_notifier(QXLModeNotifier* notifier)
+{
+    if (--notifier->refs) {
         return;
     }
-    while (d && qxl_mode_native_counter < 2) {
-        if (d->state.mode == QXL_MODE_NATIVE && ++qxl_mode_native_counter == 1) {
-            mode = d->state.rom->mode;
-        }
-        d = d->dev_next;
-    }
-    if (qxl_mode_native_counter == 1) {
-        qxl_mode_change_notifier(TRUE, qxl_modes[mode].x_res, qxl_modes[mode].y_res);
-    } else {
-        qxl_mode_change_notifier(FALSE, 0, 0);
+    QXLModeNotifier **now = &notifier->d->mode_notifiers;
+    while (*now != notifier) {
+        now = &(*now)->next;
     }
+    *now = notifier->next;
+    free(notifier);
 }
 
-void qxl_register_mode_change(QXLModeChangeNotifier notifier){
-    qxl_mode_change_notifier = notifier;
-    qxl_notify_mode_change();
-}
+#endif
 
-void qxl_set_mm_time(uint32_t stamp)
+static void qxl_notify_mode_change(PCIQXLDevice *d)
 {
-    PCIQXLDevice *d = dev_list;
-    while (d) {
-        d->state.rom->mm_clock = stamp;
-        d = d->dev_next;
+#ifdef CONFIG_SPICE
+    QXLModeNotifier *now = d->mode_notifiers;
+    QXLModeNotifier *tmp;
+
+    while (now) {
+        hold_mode_notifier(now);
+        now->proc(now->opaque);
+        tmp = now;
+        now = now->next;
+        release_mode_notifier(tmp);
     }
+#endif
 }
 
 static void qxl_set_mode(PCIQXLDevice *d, uint32_t mode)
@@ -579,15 +562,8 @@ static void qxl_set_mode(PCIQXLDevice *d, uint32_t mode)
     d->state.rom->mode = mode;
     memset(d->state.vram, 0, d->state.vram_size);
     d->state.mode = QXL_MODE_NATIVE;
-    qxl_notify_mode_change();
-    qxl_worker_attach(d->state.worker);
-}
-
-void *vga_context = NULL;
-
-void qxl_set_vga_context(void *context)
-{
-    vga_context = context;
+    qxl_notify_mode_change(d);
+    d->worker->attach(d->worker);
 }
 
 static void qxl_add_vga_client()
@@ -610,9 +586,8 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d)
     printf("%u: %s\n", d->id, __FUNCTION__);
     d->state.rom->mode = ~0;
     d->state.mode = QXL_MODE_VGA;
-    qxl_notify_mode_change();
+    qxl_notify_mode_change(d);
     qxl_add_vga_client();
-    vga_on_qxl_enter_vga(vga_context);
 }
 
 /* reset the state (assuming the worker is detached) */
@@ -645,10 +620,10 @@ static void qxl_reset(PCIQXLDevice *d)
     qxl_reset_state(d);
     if (QXL_SHARED_VGA_MODE || !d->id) {
         qxl_enter_vga_mode(d);
-        qxl_worker_attach(d->state.worker);
+        d->worker->attach(d->worker);
     } else {
         d->state.mode = QXL_MODE_UNDEFINED;
-        qxl_notify_mode_change();
+        qxl_notify_mode_change(d);
     }
 }
 
@@ -665,13 +640,13 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
     }
     switch (io_port) {
     case QXL_IO_UPDATE_AREA:
-        qxl_worker_update_area(d->state.worker);
+        d->worker->update_area(d->worker);
         break;
     case QXL_IO_NOTIFY_CMD:
-        qxl_worker_wakeup(d->state.worker);
+        d->worker->wakeup(d->worker);
         break;
     case QXL_IO_NOTIFY_CURSOR:
-        qxl_worker_wakeup(d->state.worker);
+        d->worker->wakeup(d->worker);
         break;
     case QXL_IO_UPDATE_IRQ:
         qemu_set_irq(d->pci_dev.irq[0], irq_level(d));
@@ -685,7 +660,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
         if (!RING_IS_EMPTY(&d->state.ram->release_ring)) {
             break;
         }
-        qxl_worker_oom(d->state.worker);
+        d->worker->oom(d->worker);
         break;
     case QXL_IO_LOG:
         printf("%u: %s", d->id, d->state.ram->log_buf);
@@ -732,13 +707,6 @@ static void rom_map(PCIDevice *d, int region_num,
     ASSERT(size ==  s->rom_size);
 
     cpu_register_physical_memory(addr, size, s->rom_offset | IO_MEM_ROM);
-    if (kvm_enabled() && kvm_create_memory_alias(kvm_context,
-                                               addr,
-                                               size,
-                                               s->rom_offset)) {
-        printf("%s: create memory alias failed\n", __FUNCTION__);
-        exit(-1);
-    }
 }
 
 static void ram_map(PCIDevice *d, int region_num,
@@ -754,13 +722,6 @@ static void ram_map(PCIDevice *d, int region_num,
     ASSERT((size & ~TARGET_PAGE_MASK) == 0);
     s->ram_phys_addr = addr;
     cpu_register_physical_memory(addr, size, s->ram_offset | IO_MEM_RAM);
-    if (kvm_enabled() && kvm_create_memory_alias(kvm_context,
-                                               addr,
-                                               size,
-                                               s->ram_offset)) {
-        printf("%s: create memory alias failed\n", __FUNCTION__);
-        exit(-1);
-    }
 }
 
 static void vram_map(PCIDevice *d, int region_num,
@@ -779,13 +740,6 @@ static void vram_map(PCIDevice *d, int region_num,
 #else
     cpu_register_physical_memory(addr, size, s->vram_offset | IO_MEM_RAM);
 #endif
-    if (kvm_enabled() && kvm_create_memory_alias(kvm_context,
-                                               addr,
-                                               size,
-                                               s->vram_offset)) {
-        printf("%s: create memory alias failed\n", __FUNCTION__);
-        exit(-1);
-    }
 }
 
 
@@ -852,7 +806,7 @@ static uint32_t init_qxl_rom(PCIQXLDevice *d, uint8_t *buf, uint32_t vram_size,
     rom->mode = 0;
     rom->modes_offset = sizeof(QXLRom);
     rom->draw_area_size =qxl_max_x_res() * sizeof(uint32_t) * qxl_max_y_res();
-    rom->compression_level = compression_level;
+    rom->compression_level = QXL_DEFAULT_COMPRESSION_LEVEL;
     rom->log_level = 0;
 
     *max_fb = 0;
@@ -968,7 +922,7 @@ static void qxl_display_update(struct DisplayState *ds, int x, int y, int w, int
             cmd->data = (PHYSICAL)drawable;
             RING_PUSH(ring, notify);
             if (notify) {
-                qxl_worker_wakeup(client->state.worker);
+                client->worker->wakeup(client->worker);
             }
         }
         client = client->vga_next;
@@ -1040,7 +994,6 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d)
     printf("%s\n", __FUNCTION__);
     qxl_remove_vga_client();
     d->state.mode = QXL_MODE_UNDEFINED;
-    vga_on_qxl_exit_vga(vga_context);
 }
 
 int qxl_vga_touch(void)
@@ -1063,7 +1016,7 @@ static void qxl_save(QEMUFile* f, void* opaque)
     QXLState*     s=&d->state;
     uint32_t      last_release_offset;
 
-    qxl_worker_save(d->state.worker);
+    d->worker->save(d->worker);
     pci_device_save(&d->pci_dev, f);
 
     qemu_put_be32(f, s->rom->mode);
@@ -1105,7 +1058,7 @@ static int qxl_load(QEMUFile* f,void* opaque,int version_id)
     }
 
     if (d->state.mode != QXL_MODE_UNDEFINED) {
-        qxl_worker_detach(d->state.worker);
+        d->worker->detach(d->worker);
     }
 
     if (s->mode == QXL_MODE_VGA) {
@@ -1149,10 +1102,10 @@ static int qxl_load(QEMUFile* f,void* opaque,int version_id)
         qxl_add_vga_client();
     }
     if (s->mode != QXL_MODE_UNDEFINED) {
-        qxl_worker_attach(d->state.worker);
-        qxl_worker_load(d->state.worker);
+        d->worker->attach(d->worker);
+        d->worker->load(d->worker);
     }
-    qxl_notify_mode_change();
+    qxl_notify_mode_change(d);
     return 0;
 }
 
@@ -1183,14 +1136,14 @@ static void qxl_vm_change_state_handler(void *opaque, int running)
     if (running) {
         d->state.running = TRUE;
         qemu_set_fd_handler(d->pipe_fd[0], qxl_pipe_read, NULL, d);
-        qxl_worker_start(d->state.worker);
+        d->worker->start(d->worker);
         qemu_set_irq(d->pci_dev.irq[0], irq_level(d));
         if (qxl_vga.active_clients) {
             qemu_mod_timer(qxl_vga.timer, qemu_get_clock(rt_clock));
         }
     } else {
         qemu_del_timer(qxl_vga.timer);
-        qxl_worker_stop(d->state.worker);
+        d->worker->stop(d->worker);
         qemu_set_fd_handler(d->pipe_fd[0], NULL, NULL, d);
         d->state.running = FALSE;
     }
@@ -1215,7 +1168,259 @@ static void reset_handler(void *opaque)
     }
 }
 
-static int channel_id = 0;
+void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info)
+{
+    _qxl_get_info((PCIQXLDevice *)dev_ref, info);
+}
+
+int qxl_get_command(QXLDevRef dev_ref, struct QXLCommand *cmd)
+{
+    return _qxl_get_command((PCIQXLDevice *)dev_ref, cmd);
+}
+
+void qxl_release_resource(QXLDevRef dev_ref, union QXLReleaseInfo *release_info)
+{
+    _qxl_release_resource((PCIQXLDevice *)dev_ref, release_info);
+}
+
+void qxl_notify_update(QXLDevRef dev_ref, uint32_t update_id)
+{
+    _qxl_notify_update((PCIQXLDevice *)dev_ref, update_id);
+}
+
+int qxl_req_cmd_notification(QXLDevRef dev_ref)
+{
+    return _qxl_req_cmd_notification((PCIQXLDevice *)dev_ref);
+}
+
+int qxl_get_cursor_command(QXLDevRef dev_ref, struct QXLCommand *cmd)
+{
+    return _qxl_get_cursor_command((PCIQXLDevice *)dev_ref, cmd);
+}
+
+int qxl_req_cursor_notification(QXLDevRef dev_ref)
+{
+    return _qxl_req_cursor_notification((PCIQXLDevice *)dev_ref);
+}
+
+int qxl_has_command(QXLDevRef dev_ref)
+{
+    return _qxl_has_command((PCIQXLDevice *)dev_ref);
+}
+
+const Rect *qxl_get_update_area(QXLDevRef dev_ref)
+{
+    return _qxl_get_update_area((PCIQXLDevice *)dev_ref);
+}
+
+int qxl_flush_resources(QXLDevRef dev_ref)
+{
+    return _qxl_flush_resources((PCIQXLDevice *)dev_ref);
+}
+
+void qxl_set_save_data(QXLDevRef dev_ref, void *data, int size)
+{
+    _qxl_set_save_data((PCIQXLDevice *)dev_ref, data, size);
+}
+
+void *qxl_get_save_data(QXLDevRef dev_ref)
+{
+    return _qxl_get_save_data((PCIQXLDevice *)dev_ref);
+}
+
+#ifdef CONFIG_SPICE
+
+typedef struct Interface {
+    QXLInterface vd_interface;
+    PCIQXLDevice *d;
+} Interface;
+
+static void interface_attache_worker(QXLInterface *qxl, QXLWorker *qxl_worker)
+{
+    Interface *interface = (Interface *)qxl;
+    if (interface->d->worker) {
+        printf("%s: has worker\n", __FUNCTION__);
+        exit(-1);
+    }
+    interface->d->worker = qxl_worker;
+}
+
+void interface_set_compression_level(QXLInterface *qxl, int level)
+{
+    PCIQXLDevice *d = ((Interface *)qxl)->d;
+    d->state.rom->compression_level = level;
+}
+
+void interface_set_mm_time(QXLInterface *qxl, uint32_t mm_time)
+{
+    PCIQXLDevice *d = ((Interface *)qxl)->d;
+    d->state.rom->mm_clock = mm_time;
+}
+
+static QXLModeNotifier *register_mode_notifier(PCIQXLDevice *d, qxl_mode_change_notifier_t proc,
+                                               void *opaque)
+{
+    QXLModeNotifier *notifier;
+
+    if (!proc) {
+        return NULL;
+    }
+
+    if (!(notifier = (QXLModeNotifier *)malloc(sizeof(*notifier)))) {
+        printf("%s: malloc failed\n", __FUNCTION__);
+        exit(-1);
+    }
+    notifier->opaque = opaque;
+    notifier->proc = proc;
+    notifier->refs = 1;
+    notifier->next = d->mode_notifiers;
+    d->mode_notifiers = notifier;
+    return notifier;
+}
+
+static void unregister_mode_notifier(PCIQXLDevice *d, QXLModeNotifier *notifier)
+{
+    QXLModeNotifier **now = &d->mode_notifiers;
+    for (;;) {
+        if (*now == notifier) {
+            notifier->proc = NULL;
+            release_mode_notifier(notifier);
+            return;
+        }
+        now = &(*now)->next;
+    }
+}
+
+static VDObjectRef interface_register_mode_change(QXLInterface *qxl, qxl_mode_change_notifier_t notifier, void *opaque)
+{
+    PCIQXLDevice *d = ((Interface *)qxl)->d;
+
+    if (!notifier) {
+        return 0;
+    }
+    return (VDObjectRef)register_mode_notifier(d, notifier, opaque);
+}
+
+static void interface_unregister_mode_change(QXLInterface *qxl, VDObjectRef notifier)
+{
+    PCIQXLDevice *d = ((Interface *)qxl)->d;
+    if (!notifier) {
+        return;
+    }
+    unregister_mode_notifier(d, (QXLModeNotifier *)notifier);
+}
+
+static void interface_get_info(QXLInterface *qxl, QXLDevInfo *info)
+{
+    _qxl_get_info(((Interface *)qxl)->d, info);
+}
+
+static int interface_get_command(QXLInterface *qxl, struct QXLCommand *cmd)
+{
+    return _qxl_get_command(((Interface *)qxl)->d, cmd);
+}
+
+static int interface_req_cmd_notification(QXLInterface *qxl)
+{
+    return _qxl_req_cmd_notification(((Interface *)qxl)->d);
+}
+
+static int interface_has_command(QXLInterface *qxl)
+{
+    return _qxl_has_command(((Interface *)qxl)->d);
+}
+
+static void interface_release_resource(QXLInterface *qxl, union QXLReleaseInfo *release_info)
+{
+    _qxl_release_resource(((Interface *)qxl)->d, release_info);
+}
+
+static int interface_get_cursor_command(QXLInterface *qxl, struct QXLCommand *cmd)
+{
+    return _qxl_get_cursor_command(((Interface *)qxl)->d, cmd);
+}
+
+static int interface_req_cursor_notification(QXLInterface *qxl)
+{
+    return _qxl_req_cursor_notification(((Interface *)qxl)->d);
+}
+
+static const struct Rect *interface_get_update_area(QXLInterface *qxl)
+{
+    return _qxl_get_update_area(((Interface *)qxl)->d);
+}
+
+static void interface_notify_update(QXLInterface *qxl, uint32_t update_id)
+{
+    _qxl_notify_update(((Interface *)qxl)->d, update_id);
+}
+
+static void interface_set_save_data(QXLInterface *qxl, void *data, int size)
+{
+    _qxl_set_save_data(((Interface *)qxl)->d, data, size);
+}
+
+static void *interface_get_save_data(QXLInterface *qxl)
+{
+    return _qxl_get_save_data(((Interface *)qxl)->d);
+}
+
+static int interface_flush_resources(QXLInterface *qxl)
+{
+    return _qxl_flush_resources(((Interface *)qxl)->d);
+}
+
+static void regitser_interface(PCIQXLDevice *d)
+{
+    Interface *interface = (Interface *)qemu_mallocz(sizeof(*interface));
+
+    if (!interface) {
+        printf("%s: malloc failed\n", __FUNCTION__);
+        exit(-1);
+    }
+    interface->vd_interface.base.base_vertion = VM_INTERFACE_VERTION;
+    interface->vd_interface.base.type = VD_INTERFACE_QXL;
+    interface->vd_interface.base.id = d->id;
+    interface->vd_interface.base.description = "QXL GPU";
+    interface->vd_interface.base.major_vertion = VD_INTERFACE_QXL_MAJOR;
+    interface->vd_interface.base.minor_vertion = VD_INTERFACE_QXL_MINOR;
+
+    interface->vd_interface.pci_vendor = QUMRANET_PCI_VENDOR_ID;
+    interface->vd_interface.pci_id = QXL_DEVICE_ID;
+    interface->vd_interface.pci_revision = QXL_REVISION;
+
+    interface->vd_interface.attache_worker = interface_attache_worker;
+    interface->vd_interface.set_compression_level = interface_set_compression_level;
+    interface->vd_interface.set_mm_time = interface_set_mm_time;
+    interface->vd_interface.register_mode_change = interface_register_mode_change;
+    interface->vd_interface.unregister_mode_change = interface_unregister_mode_change;
+
+    interface->vd_interface.get_info = interface_get_info;
+    interface->vd_interface.get_command = interface_get_command;
+    interface->vd_interface.req_cmd_notification = interface_req_cmd_notification;
+    interface->vd_interface.has_command = interface_has_command;
+    interface->vd_interface.release_resource = interface_release_resource;
+    interface->vd_interface.get_cursor_command = interface_get_cursor_command;
+    interface->vd_interface.req_cursor_notification = interface_req_cursor_notification;
+    interface->vd_interface.get_update_area = interface_get_update_area;
+    interface->vd_interface.notify_update = interface_notify_update;
+    interface->vd_interface.set_save_data = interface_set_save_data;
+    interface->vd_interface.get_save_data = interface_get_save_data;
+    interface->vd_interface.flush_resources = interface_flush_resources;
+
+    interface->d = d;
+    add_interface(&interface->vd_interface.base);
+}
+
+#endif
+
+static void creat_native_worker(PCIQXLDevice *d, int id)
+{
+    d->worker = qxl_interface_create_worker((QXLDevRef)d, id);
+    ASSERT(d->worker);
+}
+
+static int device_id = 0;
 
 void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, 
               uint32_t vram_size)
@@ -1229,13 +1434,13 @@ void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset,
                                            sizeof(PCIQXLDevice), -1, NULL,
                                            NULL);
 
-    d->id = channel_id;
+    d->id = device_id;
     d->state.mode = QXL_MODE_UNDEFINED;
-    if (!channel_id) {
+    if (!device_id) {
         qxl_init_modes();
     }
 
-    register_savevm(QXL_DEV_NAME, channel_id, QXL_SAVE_VERSION, qxl_save, qxl_load, d);
+    register_savevm(QXL_DEV_NAME, device_id, QXL_SAVE_VERSION, qxl_save, qxl_load, d);
     qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, d);
 
     pci_conf = (PCIConf *)d->pci_dev.config;
@@ -1309,19 +1514,26 @@ void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset,
 #else
     pci_register_io_region(&d->pci_dev, QXL_VRAM_RANGE_INDEX, d->state.vram_size,
                            PCI_ADDRESS_SPACE_MEM_PREFETCH, vram_map);
-#endif
-    d->state.worker = qxl_worker_init((QXLDevRef) d, channel_id++);
+#endif    
     d->dev_next = dev_list;
     dev_list = d;
     d->vga_next = qxl_vga.clients;
     qxl_vga.clients = d;
     main_thread = pthread_self();
     qxl_reset_state(d);
+    init_pipe_signaling(d);
+    
+#ifdef CONFIG_SPICE
+    regitser_interface(d);
+#endif
+    if (!d->worker) {
+        creat_native_worker(d, device_id);
+    }
     if (QXL_SHARED_VGA_MODE || !d->id) {
         qxl_enter_vga_mode(d);
-        qxl_worker_attach(d->state.worker);
+        d->worker->attach(d->worker);
     } 
-    init_pipe_signaling(d);
     qemu_register_reset(reset_handler, d);
+    device_id++;
 }
 
diff --git a/qemu/hw/qxl_interface.h b/qemu/hw/qxl_interface.h
index 19ee2f9..15ee9c2 100644
--- a/qemu/hw/qxl_interface.h
+++ b/qemu/hw/qxl_interface.h
@@ -3,11 +3,13 @@
 
 #include <stdint.h>
 
-union QXLReleaseInfo;
-struct QXLCommand;
+#include "qxl_dev.h"
 
-typedef unsigned long QXLWorkerRef;
-typedef unsigned long QXLDevRef;
+#ifdef CONFIG_SPICE
+
+#include "vd_interface.h"
+
+#else
 
 typedef struct DrawArea{
     uint8_t *buf;
@@ -22,39 +24,43 @@ typedef struct QXLDevInfo {
     long phys_delta;
     unsigned long phys_start;
     unsigned long phys_end;
-
     uint32_t x_res;
     uint32_t y_res;
+    int use_hardware_cursor;
     uint32_t bits;
-
     DrawArea draw_area;
-
 } QXLDevInfo;
 
+typedef struct QXLWorker QXLWorker;
+struct QXLWorker {
+    void (*attach)(QXLWorker *worker);
+    void (*detach)(QXLWorker *worker);
+    void (*wakeup)(QXLWorker *worker);
+    void (*oom)(QXLWorker *worker);
+    void (*save)(QXLWorker *worker);
+    void (*load)(QXLWorker *worker);
+    void (*start)(QXLWorker *worker);
+    void (*stop)(QXLWorker *worker);
+    void (*update_area)(QXLWorker *worker);
+};
+#endif
+
+typedef unsigned long QXLDevRef;
+
 void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info);
-int qxl_get_command(QXLDevRef dev_ref, struct QXLCommand *cmd);
-int qxl_has_command(QXLDevRef dev_ref);
-int qxl_get_cursor_command(QXLDevRef dev_ref, struct QXLCommand *cmd);
-const struct Rect *qxl_get_update_area(QXLDevRef dev_ref);
+int qxl_get_command(QXLDevRef dev_ref, QXLCommand *cmd);
+void qxl_release_resource(QXLDevRef dev_ref, QXLReleaseInfo *release_info);
+void qxl_notify_update(QXLDevRef dev_ref, uint32_t update_id);
 int qxl_req_cmd_notification(QXLDevRef dev_ref);
+int qxl_get_cursor_command(QXLDevRef dev_ref, QXLCommand *cmd);
 int qxl_req_cursor_notification(QXLDevRef dev_ref);
-void qxl_release_resource(QXLDevRef dev_ref, union QXLReleaseInfo *release_info);
+int qxl_has_command(QXLDevRef dev_ref);
+const Rect *qxl_get_update_area(QXLDevRef dev_ref);
 int qxl_flush_resources(QXLDevRef dev_ref);
-void qxl_notify_update(QXLDevRef dev_ref, uint32_t update_id);
 void qxl_set_save_data(QXLDevRef dev_ref, void *data, int size);
 void *qxl_get_save_data(QXLDevRef dev_ref);
 
-
-QXLWorkerRef qxl_worker_init(QXLDevRef dev_ref, int channel_id);
-void qxl_worker_attach(QXLWorkerRef worker_ref);
-void qxl_worker_detach(QXLWorkerRef worker_ref);
-void qxl_worker_wakeup(QXLWorkerRef worker_ref);
-void qxl_worker_oom(QXLWorkerRef worker_ref);
-void qxl_worker_save(QXLWorkerRef worker_ref);
-void qxl_worker_load(QXLWorkerRef worker_ref);
-void qxl_worker_start(QXLWorkerRef worker_ref);
-void qxl_worker_stop(QXLWorkerRef worker_ref);
-void qxl_worker_update_area(QXLWorkerRef worker_ref);
+QXLWorker *qxl_interface_create_worker(QXLDevRef dev, int id);
 
 #endif
 
diff --git a/qemu/hw/qxl_native_worker.c b/qemu/hw/qxl_native_worker.c
new file mode 100644
index 0000000..91eefb1
--- /dev/null
+++ b/qemu/hw/qxl_native_worker.c
@@ -0,0 +1,151 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "qemu-common.h"
+
+#include "qxl_interface.h"
+#include "qxl_dev.h"
+
+#define qxl_error(format, ...) {                                 \
+    printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ );   \
+    exit(-1);                                                    \
+}
+
+#define qxl_printf(format, ...) \
+    printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ )
+
+typedef struct QxlDispatcher {
+    QXLWorker base;
+    int id;
+    QXLDevRef dev_ref;
+    QXLDevInfo dev_info;
+} QxlDispatcher;
+
+static void native_qxl_worker_wakeup(QXLWorker *worker)
+{
+    QxlDispatcher *dispatcher = (QxlDispatcher *)worker;
+    QXLCommand cmd;
+
+    qxl_printf("");
+
+    for (;;) {
+        if (qxl_get_command(dispatcher->dev_ref, &cmd)) {
+            switch (cmd.type) {
+            case QXL_CMD_DRAW: {
+                QXLDrawable *draw_cmd = (QXLDrawable *)(cmd.data + dispatcher->dev_info.phys_delta);   
+                qxl_release_resource(dispatcher->dev_ref, &draw_cmd->release_info);
+                break;
+            }
+            case QXL_CMD_UPDATE: {
+                QXLUpdateCmd *update_cmd = (QXLUpdateCmd *)(cmd.data + dispatcher->dev_info.phys_delta);
+                qxl_notify_update(dispatcher->dev_ref, update_cmd->update_id);
+                qxl_release_resource(dispatcher->dev_ref, &update_cmd->release_info);
+                break;
+            }
+            case QXL_CMD_MESSAGE: {
+                QXLMessage *message = (QXLMessage *)(cmd.data + dispatcher->dev_info.phys_delta);
+                qxl_printf("MESSAGE: %s", message->data);
+                qxl_release_resource(dispatcher->dev_ref, &message->release_info);
+                break;
+            }
+            default:
+                qxl_error("bad command type");
+            }
+            continue;
+        }
+        if (qxl_req_cmd_notification(dispatcher->dev_ref)) {
+            break;
+        }
+    }
+    for (;;) {
+        if (qxl_get_cursor_command(dispatcher->dev_ref, &cmd)) {
+            switch (cmd.type) {
+            case QXL_CMD_CURSOR: {
+                QXLCursorCmd *cursor_cmd = (QXLCursorCmd *)(cmd.data + dispatcher->dev_info.phys_delta);
+                qxl_release_resource(dispatcher->dev_ref, &cursor_cmd->release_info);
+                break;
+            }
+             default:
+                qxl_error("bad command type");
+            }
+            continue;
+        }
+        if (qxl_req_cursor_notification(dispatcher->dev_ref)) {
+            break;
+        }
+    }
+}
+
+static void native_qxl_worker_attach(QXLWorker *worker)
+{
+    QxlDispatcher *dispatcher = (QxlDispatcher *)worker;
+
+    qxl_printf("");
+
+    qxl_get_info(dispatcher->dev_ref, &dispatcher->dev_info);
+    native_qxl_worker_wakeup(worker);
+}
+
+static void native_qxl_worker_detach(QXLWorker *worker)
+{
+    qxl_printf("");
+    native_qxl_worker_wakeup(worker);
+}
+
+static void native_qxl_worker_update_area(QXLWorker *worker)
+{
+    qxl_printf("");
+    native_qxl_worker_wakeup(worker);
+}
+
+static void native_qxl_worker_oom(QXLWorker *worker)
+{
+    qxl_printf("");
+    native_qxl_worker_wakeup(worker);
+}
+
+static void native_qxl_worker_start(QXLWorker *worker)
+{
+    qxl_printf("");
+}
+
+static void native_qxl_worker_stop(QXLWorker *worker)
+{
+    qxl_printf("");
+}
+
+static void native_qxl_worker_save(QXLWorker *worker)
+{
+    qxl_printf("");
+}
+
+static void native_qxl_worker_load(QXLWorker *worker)
+{
+    qxl_printf("");
+}
+
+QXLWorker *qxl_interface_create_worker(QXLDevRef dev_ref, int device_id)
+{
+    QxlDispatcher *dispatcher;
+
+    if (!(dispatcher = malloc(sizeof(QxlDispatcher)))) {
+        qxl_error("malloc failed");
+    }
+    memset(dispatcher, 0, sizeof(*dispatcher));
+    dispatcher->id = device_id;
+    dispatcher->dev_ref = dev_ref;
+
+    dispatcher->base.attach = native_qxl_worker_attach;
+    dispatcher->base.detach = native_qxl_worker_detach;
+    dispatcher->base.wakeup = native_qxl_worker_wakeup;
+    dispatcher->base.oom = native_qxl_worker_oom;
+    dispatcher->base.save = native_qxl_worker_save;
+    dispatcher->base.load = native_qxl_worker_load;
+    dispatcher->base.start = native_qxl_worker_start;
+    dispatcher->base.stop = native_qxl_worker_stop;
+    dispatcher->base.update_area = native_qxl_worker_update_area;
+
+    return &dispatcher->base;
+}
+
diff --git a/qemu/hw/usb-hid.c b/qemu/hw/usb-hid.c
index 76fdce6..b23de50 100644
--- a/qemu/hw/usb-hid.c
+++ b/qemu/hw/usb-hid.c
@@ -26,6 +26,10 @@
 #include "console.h"
 #include "usb.h"
 
+#ifdef CONFIG_SPICE
+#include "interface.h"
+#endif
+
 /* HID interface requests */
 #define GET_REPORT   0xa101
 #define GET_IDLE     0xa102
@@ -47,6 +51,11 @@ typedef struct USBMouseState {
     int dx, dy, dz, buttons_state;
     int x, y;
     int mouse_grabbed;
+#ifdef CONFIG_SPICE
+    TabletInterface interface;
+    int logical_width;
+    int logical_height;
+#endif
     QEMUPutMouseEntry *eh_entry;
 } USBMouseState;
 
@@ -510,9 +519,9 @@ static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len)
     USBMouseState *s = &hs->ptr;
 
     if (!s->mouse_grabbed) {
-	s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, hs,
+        s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, hs,
                                                   0, "QEMU USB Mouse");
-	s->mouse_grabbed = 1;
+        s->mouse_grabbed = 1;
     }
 
     dx = int_clamp(s->dx, -127, 127);
@@ -546,15 +555,77 @@ static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len)
     return l;
 }
 
+
+#ifdef CONFIG_SPICE
+
+static void interface_set_logical_size(TabletInterface* interface, int width, int height)
+{
+   USBHIDState *hs = container_of(interface, USBHIDState, ptr.interface);
+   hs->ptr.logical_width = width;
+   hs->ptr.logical_height = height;
+}
+
+static void interface_position(TabletInterface *interface, int x, int y,
+                               uint32_t buttons_state)
+{
+    USBHIDState *hs = container_of(interface, USBHIDState, ptr.interface);
+
+    x = (x + 1) * 0x7FFF / (hs->ptr.logical_width + 1 /*why + 1*/);
+    y = (y + 1) * 0x7FFF / (hs->ptr.logical_height + 1 /*why + 1*/);
+    usb_tablet_event(hs, x, y, 0, buttons_state);
+}
+
+
+static void interface_wheel(TabletInterface *interface, int wheel,
+                            uint32_t buttons_state)
+{
+    USBHIDState *hs = container_of(interface, USBHIDState, ptr.interface);
+    usb_tablet_event(hs, hs->ptr.x, hs->ptr.y, wheel, buttons_state);
+}
+
+static void interface_buttons(TabletInterface *interface,
+                              uint32_t buttons_state)
+{
+    USBHIDState *hs = container_of(interface, USBHIDState, ptr.interface);
+    usb_tablet_event(hs, hs->ptr.x, hs->ptr.y, 0, buttons_state);
+}
+
+static void regitser_tablet(USBMouseState *s)
+{
+    TabletInterface *interface = &s->interface;
+    static int tablet_interface_id = 0;
+    
+    interface->base.base_vertion = VM_INTERFACE_VERTION;
+    interface->base.type = VD_INTERFACE_TABLET;
+    interface->base.id = ++tablet_interface_id;
+    interface->base.description = "usb tablet";
+    interface->base.major_vertion = VD_INTERFACE_TABLET_MAJOR;
+    interface->base.minor_vertion = VD_INTERFACE_TABLET_MINOR;
+
+
+    interface->set_logical_size = interface_set_logical_size;
+    interface->position = interface_position;
+    interface->wheel = interface_wheel;
+    interface->buttons = interface_buttons;
+
+    add_interface(&interface->base);
+}
+
+
+#endif
+
 static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, int len)
 {
     int dz, b, l;
     USBMouseState *s = &hs->ptr;
 
     if (!s->mouse_grabbed) {
-	s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, hs,
+        s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, hs,
                                                   1, "QEMU USB Tablet");
-	s->mouse_grabbed = 1;
+        s->mouse_grabbed = 1;
+#ifdef CONFIG_SPICE
+        regitser_tablet(s);
+#endif 
     }
 
     dz = int_clamp(s->dz, -127, 127);
@@ -840,12 +911,25 @@ static void usb_hid_handle_destroy(USBDevice *dev)
 {
     USBHIDState *s = (USBHIDState *)dev;
 
-    if (s->kind != USB_KEYBOARD)
+    if (s->kind != USB_KEYBOARD && s->ptr.mouse_grabbed)
         qemu_remove_mouse_event_handler(s->ptr.eh_entry);
     /* TODO: else */
     qemu_free(s);
 }
 
+
+static void usb_tablet_handle_destroy(USBDevice *dev)
+{
+    USBHIDState *s = (USBHIDState *)dev;
+    if (s->ptr.mouse_grabbed) {
+#ifdef CONFIG_SPICE
+        remove_interface(&s->ptr.interface.base);
+#endif
+        qemu_remove_mouse_event_handler(s->ptr.eh_entry);
+    }
+    qemu_free(s);
+}
+
 USBDevice *usb_tablet_init(void)
 {
     USBHIDState *s;
@@ -859,7 +943,7 @@ USBDevice *usb_tablet_init(void)
     s->dev.handle_reset = usb_mouse_handle_reset;
     s->dev.handle_control = usb_hid_handle_control;
     s->dev.handle_data = usb_hid_handle_data;
-    s->dev.handle_destroy = usb_hid_handle_destroy;
+    s->dev.handle_destroy = usb_tablet_handle_destroy;
     s->kind = USB_TABLET;
     /* Force poll routine to be run and grab input the first time.  */
     s->changed = 1;
diff --git a/qemu/hw/vga.c b/qemu/hw/vga.c
index 3cde818..f1eb2bb 100644
--- a/qemu/hw/vga.c
+++ b/qemu/hw/vga.c
@@ -151,6 +151,7 @@ static uint16_t expand2[256];
 static uint8_t expand4to8[16];
 
 static void vga_screen_dump(void *opaque, const char *filename);
+static void vga_invalidate_display(void *opaque);
 
 static void vga_dumb_update_retrace_info(VGAState *s)
 {
@@ -389,6 +390,12 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
 #endif
 
+#ifdef CONFIG_QXL
+    if(using_qxl && qxl_vga_touch()) {
+        vga_invalidate_display(opaque);
+    }
+#endif
+
     switch(addr) {
     case 0x3c0:
         if (s->ar_flip_flop == 0) {
@@ -564,6 +571,12 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
 {
     VGAState *s = opaque;
 
+#ifdef CONFIG_QXL
+    if(using_qxl && qxl_vga_touch()) {
+        vga_invalidate_display(opaque);
+    }
+#endif
+
     if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
 #ifdef DEBUG_BOCHS_VBE
         printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
@@ -2587,6 +2600,10 @@ int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
     /* XXX: use optimized standard vga accesses */
     cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
                                  vga_ram_size, vga_ram_offset);
+    if (kvm_enabled()) {
+        kvm_qemu_log_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, vga_ram_size, 1);
+    }
+    s->map_addr = VBE_DISPI_LFB_PHYSICAL_ADDRESS;
 #endif
     return 0;
 }
diff --git a/qemu/interface.c b/qemu/interface.c
new file mode 100644
index 0000000..847573f
--- /dev/null
+++ b/qemu/interface.c
@@ -0,0 +1,232 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "interface.h"
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "console.h"
+
+typedef struct InterfacesNotifier InterfacesNotifier;
+
+struct InterfacesNotifier {
+    vd_interface_change_notifier_t notifier;
+    void *opaque;
+    int refs;
+    InterfacesNotifier *next;
+};
+
+InterfacesNotifier *notifiers = NULL;
+
+typedef struct VDInterfaceLink VDInterfaceLink;
+
+struct VDInterfaceLink {
+    VDInterface *interface;
+    VDInterfaceLink *next;
+};
+
+VDInterfaceLink* interfaces = NULL;
+
+static void hold_notifier(InterfacesNotifier* notifier)
+{
+    notifier->refs++;
+}
+
+static void releas_notifier(InterfacesNotifier* notifier)
+{
+    if (--notifier->refs) {
+        return;
+    }
+    InterfacesNotifier **now = &notifiers;
+
+    while (*now != notifier) {
+        now = &(*now)->next;
+    }
+    *now = notifier->next;
+    free(notifier);
+}
+
+static void run_notifiers(VDInterface *interface, VDInterfaceChangeType type)
+{
+    InterfacesNotifier *now;
+    InterfacesNotifier *prev;
+
+    now = notifiers;
+    while (now) {
+        hold_notifier(now);
+        if (now->notifier) {
+            now->notifier(now->opaque, interface, type);
+        }
+        prev = now;
+        now = now->next;
+        releas_notifier(prev);
+    }
+}
+
+void add_interface(VDInterface *interface)
+{
+    VDInterfaceLink *holder;
+
+    if (!interface) {
+        return;
+    }
+
+    if (!(holder = malloc(sizeof(*holder)))) {
+        printf("%s: malloc failed\n", __FUNCTION__);
+        exit(-1);
+    }
+    memset(holder, 0, sizeof(*holder));
+    holder->interface = interface;
+    holder->next = interfaces;
+    interfaces = holder;
+    run_notifiers(interface, VD_INTERFACE_ADDING);
+}
+
+void remove_interface(VDInterface *interface)
+{
+    VDInterfaceLink **now;
+
+    if (!interface) {
+        return;
+    }
+    now = &interfaces;
+    while (*now) {
+        if ((*now)->interface == interface) {
+            VDInterfaceLink *found = *now;
+            *now = found->next;
+            free(found);
+            run_notifiers(interface, VD_INTERFACE_REMOVING);
+            return;
+        }
+        now = &(*now)->next;
+    }
+    printf("%s: not found\n", __FUNCTION__);
+}
+
+static VDInterface *firest_valid_interface(VDInterfaceLink* interface_holder)
+{
+    while (interface_holder) {
+        if (interface_holder->interface) {
+            return interface_holder->interface;
+        }
+        interface_holder = interface_holder->next;
+    }
+    return NULL;
+}
+
+static VDInterface *core_next(CoreInterface *core, VDInterface *prev)
+{
+    VDInterfaceLink* now;
+
+    if (!interfaces) {
+        return NULL;
+    }
+
+    if (!prev) {
+        return firest_valid_interface(interfaces);
+    }
+
+    now = interfaces;
+    while (now->next) {
+        if (now->interface == prev) {
+            return firest_valid_interface(now->next);
+        }
+    }
+    return NULL;
+}
+
+static void core_unregister_change_notifiers(CoreInterface *core, VDObjectRef notifier)
+{
+    InterfacesNotifier *to_remove = (InterfacesNotifier *)notifier;
+    InterfacesNotifier *now;
+
+    if (!to_remove) {
+        return;
+    }
+    now = notifiers;
+    while (now) {
+        if (now == to_remove && now->notifier) {
+            now->notifier = NULL;
+            releas_notifier(now);
+            return;
+        }
+        now = now->next;
+    }
+    printf("%s: not found\n", __FUNCTION__);
+}
+
+static VDObjectRef core_register_change_notifiers(CoreInterface *core, void *opaque,
+                                    vd_interface_change_notifier_t notifier)
+{
+    InterfacesNotifier *_notifie;
+
+    if (!notifier) {
+        printf("%s: invalid args\n", __FUNCTION__);
+        return 0;
+    }
+
+    _notifie = malloc(sizeof(*_notifie));
+    if (!_notifie) {
+        printf("%s: malloc failed\n", __FUNCTION__);
+        exit(-1);
+    }
+    memset(_notifie, 0, sizeof(*_notifie));
+    _notifie->refs = 1;
+    _notifie->opaque = opaque;
+    _notifie->notifier = notifier;
+    _notifie->next = notifiers;
+    notifiers = _notifie;
+
+    return (VDObjectRef)_notifie;
+}
+
+static VDObjectRef core_create_timer(CoreInterface *core, timer_callback_t callback, void *opaue)
+{
+    return (VDObjectRef)qemu_new_timer(rt_clock, callback, opaue);
+}
+
+static void core_arm_timer(CoreInterface *core, VDObjectRef timer, uint32_t ms)
+{
+    qemu_mod_timer((QEMUTimer *)timer, qemu_get_clock(rt_clock) + ms);
+}
+
+static void core_disarm_timer(CoreInterface *core, VDObjectRef timer)
+{
+    qemu_del_timer((QEMUTimer *)timer);
+}
+
+static void core_destroy_timer(CoreInterface *core, VDObjectRef timer)
+{
+    qemu_del_timer((QEMUTimer *)timer);
+    qemu_free_timer((QEMUTimer *)timer);
+}
+
+static int core_set_file_handlers(CoreInterface *core, int fd,
+                              void (*on_read)(void *),
+                              void (*on_write)(void *),
+                              void *opaque)
+{
+    return qemu_set_fd_handler(fd, on_read, on_write, opaque);
+}
+
+static void core_term_printf(CoreInterface *core, const char* format, ...)
+{
+    va_list ap;
+
+    va_start(ap, format);
+    term_vprintf(format, ap);
+    va_end(ap);
+}
+
+CoreInterface core_interface = {
+    {VM_INTERFACE_VERTION, VD_INTERFACE_CORE, 0, "qwnu core services", VD_INTERFACE_CORE_MAJOR, VD_INTERFACE_CORE_MINOR},
+    core_next,
+    core_register_change_notifiers,
+    core_unregister_change_notifiers,
+    core_create_timer,
+    core_arm_timer,
+    core_disarm_timer,
+    core_destroy_timer,
+    core_set_file_handlers,
+    core_term_printf,
+};
diff --git a/qemu/interface.h b/qemu/interface.h
new file mode 100644
index 0000000..aa01926
--- /dev/null
+++ b/qemu/interface.h
@@ -0,0 +1,12 @@
+#ifndef _H_INTERFACE
+#define _H_INTERFACE
+
+#include "vd_interface.h"
+
+void add_interface(VDInterface *interface);
+void remove_interface(VDInterface *interface);
+
+extern CoreInterface core_interface;
+
+#endif
+
diff --git a/qemu/monitor.c b/qemu/monitor.c
index 1bc46f4..6cfa0fa 100644
--- a/qemu/monitor.c
+++ b/qemu/monitor.c
@@ -42,6 +42,11 @@
 
 #include "qemu-kvm.h"
 
+#ifdef CONFIG_SPICE
+#include "vd_interface.h"
+#include "interface.h"
+#endif
+
 //#define DEBUG
 //#define DEBUG_COMPLETION
 
@@ -59,20 +64,24 @@
  *
  */
 
-typedef struct term_cmd_t {
+
+typedef struct term_cmd_t term_cmd_t;
+struct term_cmd_t {
     const char *name;
     const char *args_type;
     void *handler;
     const char *params;
     const char *help;
-} term_cmd_t;
+    term_cmd_t* next; 
+};
 
 #define MAX_MON 4
 static CharDriverState *monitor_hd[MAX_MON];
 static int hide_banner;
 
-static const term_cmd_t term_cmds[];
-static const term_cmd_t info_cmds[];
+
+static term_cmd_t *action_commands = NULL;
+static term_cmd_t *info_commands = NULL;
 
 static uint8_t term_outbuf[1024];
 static int term_outbuf_index;
@@ -182,20 +191,22 @@ static int compare_cmd(const char *name, const char *list)
 
 static void help_cmd1(const term_cmd_t *cmds, const char *prefix, const char *name)
 {
-    const term_cmd_t *cmd;
+    const term_cmd_t *cmd = cmds;
 
-    for(cmd = cmds; cmd->name != NULL; cmd++) {
-        if (!name || !strcmp(name, cmd->name))
+    while (cmd) {
+        if (!name || !strcmp(name, cmd->name)) {
             term_printf("%s%s %s -- %s\n", prefix, cmd->name, cmd->params, cmd->help);
+        }
+        cmd = cmd->next;
     }
 }
 
 static void help_cmd(const char *name)
 {
     if (name && !strcmp(name, "info")) {
-        help_cmd1(info_cmds, "info ", NULL);
+        help_cmd1(info_commands, "info ", NULL);
     } else {
-        help_cmd1(term_cmds, "", name);
+        help_cmd1(action_commands, "", name);
         if (name && !strcmp(name, "log")) {
             const CPULogItem *item;
             term_printf("Log items (comma separated):\n");
@@ -231,9 +242,12 @@ static void do_info(const char *item)
 
     if (!item)
         goto help;
-    for(cmd = info_cmds; cmd->name != NULL; cmd++) {
-        if (compare_cmd(item, cmd->name))
+    cmd = info_commands;
+    while (cmd) {
+        if (compare_cmd(item, cmd->name)) {
             goto found;
+        }
+        cmd = cmd->next;
     }
  help:
     help_cmd("info");
@@ -1456,7 +1470,7 @@ static void do_info_balloon(void)
         term_printf("balloon: actual=%d\n", (int)(actual >> 20));
 }
 
-static const term_cmd_t term_cmds[] = {
+static term_cmd_t term_cmds[] = {
     { "help|?", "s?", do_help,
       "[cmd]", "show the help" },
     { "commit", "s", do_commit,
@@ -1554,10 +1568,13 @@ static const term_cmd_t term_cmds[] = {
     { "pci_add", "iss", device_hot_add, "bus nic|storage|host [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]... [host=02:00.0[,name=string][,dma=none]", "hot-add PCI device" },
     { "pci_del", "ii", device_hot_remove, "bus slot-number", "hot remove PCI device" },
 #endif
+#ifdef CONFIG_QXL
+    { "set_qxl_log_level", "i", qxl_do_set_log_level, "", "set qxl log level" },
+#endif
     { NULL, NULL, },
 };
 
-static const term_cmd_t info_cmds[] = {
+static term_cmd_t info_cmds[] = {
     { "version", "", do_info_version,
       "", "show the version of qemu" },
     { "network", "", do_info_network,
@@ -2315,10 +2332,13 @@ static void monitor_handle_command(const char *cmdline)
     cmdname[len] = '\0';
 
     /* find the command */
-    for(cmd = term_cmds; cmd->name != NULL; cmd++) {
-        if (compare_cmd(cmdname, cmd->name))
+    cmd = action_commands;
+    while (cmd) {
+        if (compare_cmd(cmdname, cmd->name)) {
             goto found;
-    }
+        }
+        cmd = cmd->next;
+    } 
     term_printf("unknown command: '%s'\n", cmdname);
     return;
  found:
@@ -2708,6 +2728,126 @@ static void parse_cmdline(const char *cmdline,
     *pnb_args = nb_args;
 }
 
+#ifdef CONFIG_SPICE
+
+static term_cmd_t* add_command_common(const char *module_name,
+                                      const char *name,
+                                      const char *args_type,
+                                      void *handler,
+                                      const char *params,
+                                      const char *help,
+                                      term_cmd_t** command_list)
+{
+    const char *seperator = ".";
+    term_cmd_t *cmd;
+    char *pos ;
+
+    int malloc_size = sizeof(*cmd) + strlen(module_name) + strlen(seperator) + strlen(name) +
+                       strlen(args_type) + strlen(params) + strlen(help) +  4 /*str term*/;
+
+    if (!(cmd = malloc(malloc_size))) {
+        printf("%s: malloc failed\n", __FUNCTION__);
+        exit(-1);
+    }
+
+    pos = (char *)(cmd + 1);
+    strcpy(pos, module_name);
+    strcat(pos, seperator);
+    strcat(pos, name);
+    cmd->name = pos;
+    pos += strlen(pos) + 1;
+
+    strcpy(pos, args_type);
+    cmd->args_type = pos;
+    pos += strlen(pos) + 1;
+
+    strcpy(pos, params);
+    cmd->params = pos;
+    pos += strlen(pos) + 1;
+
+    strcpy(pos, help);
+    cmd->help = pos;
+
+    cmd->handler = handler;
+    cmd->next = NULL;
+    while (*command_list) {
+        command_list = &(*command_list)->next;
+    }
+    *command_list = cmd;
+    return cmd;
+}
+
+static VDObjectRef monitor_add_action_command(QTermInterface *term, const char *module_name,
+                                      const char *name,
+                                      const char *args_type,
+                                      void *handler,
+                                      const char *params,
+                                      const char *help)
+{
+    if (!module_name || !name || !args_type || !handler || !params || !help) {
+        return INVALID_VD_OBJECT_REF;
+    }
+
+    return (VDObjectRef)add_command_common(module_name, name, args_type, handler, params, help, &action_commands);
+}
+
+static VDObjectRef monitor_add_info_command(QTermInterface *term, const char *module_name,
+                                      const char *name,
+                                      void *handler,
+                                      const char *help)
+{
+    if (!module_name || !name || !handler || !help) {
+        return INVALID_VD_OBJECT_REF;
+    }
+
+    return (VDObjectRef)add_command_common(module_name, name, "", handler, "", help, &info_commands);
+}
+
+static void remove_command(term_cmd_t *command, term_cmd_t** command_list)
+{
+    while (*command_list) {
+        if (*command_list == command) {
+            *command_list = command->next;
+            free(command);
+            return;
+        }
+        command_list = &(*command_list)->next;
+    }
+}
+
+static void monitor_remove_action(QTermInterface *term, VDObjectRef command_ref)
+{
+    remove_command((term_cmd_t *)command_ref, &action_commands);
+}
+
+static void monitor_remove_info(QTermInterface *term, VDObjectRef command_ref)
+{
+    remove_command((term_cmd_t *)command_ref, &info_commands);
+}
+
+static void regitser_interface()
+{
+    QTermInterface *interface = (QTermInterface *)qemu_mallocz(sizeof(*interface));
+
+    if (!interface) {
+        printf("%s: malloc failed\n", __FUNCTION__);
+        exit(-1);
+    }
+    interface->base.base_vertion = VM_INTERFACE_VERTION;
+    interface->base.type = VD_INTERFACE_QTERM;
+    interface->base.id = 0;
+    interface->base.description = "qemue terminal";
+    interface->base.major_vertion = VD_INTERFACE_QTERM_MAJOR;
+    interface->base.minor_vertion = VD_INTERFACE_QTERM_MINOR;
+    interface->add_action_command_handler = monitor_add_action_command;
+    interface->remove_action_command_handler = monitor_remove_action;
+    interface->add_info_command_handler = monitor_add_info_command;
+    interface->remove_info_command_handler = monitor_remove_info;
+    add_interface(&interface->base);
+}
+
+#endif
+
 void readline_find_completion(const char *cmdline)
 {
     const char *cmdname;
@@ -2739,14 +2879,19 @@ void readline_find_completion(const char *cmdline)
         else
             cmdname = args[0];
         completion_index = strlen(cmdname);
-        for(cmd = term_cmds; cmd->name != NULL; cmd++) {
+        cmd = action_commands;
+        while (cmd) {
             cmd_completion(cmdname, cmd->name);
+            cmd = cmd->next;
         }
     } else {
         /* find the command */
-        for(cmd = term_cmds; cmd->name != NULL; cmd++) {
-            if (compare_cmd(args[0], cmd->name))
-                goto found;
+        cmd = action_commands;
+        while (cmd) {
+            if (compare_cmd(args[0], cmd->name)) {
+                 goto found;
+            }
+            cmd = cmd->next;
         }
         return;
     found:
@@ -2774,8 +2919,10 @@ void readline_find_completion(const char *cmdline)
             /* XXX: more generic ? */
             if (!strcmp(cmd->name, "info")) {
                 completion_index = strlen(str);
-                for(cmd = info_cmds; cmd->name != NULL; cmd++) {
+                cmd = info_commands;
+                while (cmd) {
                     cmd_completion(str, cmd->name);
+                    cmd = cmd->next;
                 }
             } else if (!strcmp(cmd->name, "sendkey")) {
                 completion_index = strlen(str);
@@ -2843,10 +2990,29 @@ static void term_event(void *opaque, int event)
     monitor_start_input();
 }
 
-static int is_first_init = 1;
+static void init_commands(term_cmd_t *init_array, term_cmd_t **pos)
+{
+    term_cmd_t *now = init_array;
+    while (now->name) {
+        now->next = NULL;
+        *pos = now;
+        pos = &now->next;
+        now++;
+    }
+}
+
+void init_monitor_commands()
+{
+    init_commands(term_cmds, &action_commands);
+    init_commands(info_cmds, &info_commands);
+#ifdef CONFIG_SPICE
+    regitser_interface();
+#endif
+}
 
 void monitor_init(CharDriverState *hd, int show_banner)
 {
+    static int is_first_init = 1;
     int i;
 
     if (is_first_init) {
diff --git a/qemu/vl.c b/qemu/vl.c
index 7a36870..1034240 100644
--- a/qemu/vl.c
+++ b/qemu/vl.c
@@ -153,6 +153,11 @@
 
 #include "qemu-kvm.h"
 
+#ifdef CONFIG_SPICE
+#include "spice.h"
+#include "interface.h" 
+#endif
+
 //#define DEBUG_UNUSED_IOPORT
 //#define DEBUG_IOPORT
 //#define DEBUG_NET
@@ -263,6 +268,16 @@ static int64_t qemu_icount_bias;
 static QEMUTimer *icount_rt_timer;
 static QEMUTimer *icount_vm_timer;
 
+#ifdef CONFIG_QXL
+int using_qxl = 0;
+int num_qxl_device = 0;
+#endif
+
+#ifdef CONFIG_SPICE
+int using_spice = 0;
+const char *spice_args = NULL;
+#endif
+
 uint8_t qemu_uuid[16];
 
 /* KVM runs the main loop in a separate thread.  If we update one of the lists
@@ -4007,6 +4022,13 @@ static void help(int exitcode)
 #endif
            "-name string    set the name of the guest\n"
            "-uuid %%08x-%%04x-%%04x-%%04x-%%012x specify machine UUID\n"
+#ifdef CONFIG_QXL
+           "-qxl <num>      use qxl display device\n"
+#endif
+#ifdef CONFIG_SPICE
+           "-spice <args>   use spice\n"
+           "-spice-help     show spice usage\n"
+#endif
            "\n"
            "Network options:\n"
            "-net nic[,vlan=n][,macaddr=addr][,model=type][,name=str]\n"
@@ -4246,6 +4268,13 @@ enum {
     QEMU_OPTION_tdf,
     QEMU_OPTION_kvm_shadow_memory,
     QEMU_OPTION_mempath,
+#ifdef CONFIG_QXL
+    QEMU_OPTION_qxl,
+#endif
+#ifdef CONFIG_SPICE
+    QEMU_OPTION_spice,
+    QEMU_OPTION_spice_help,
+#endif
 };
 
 typedef struct QEMUOption {
@@ -4381,6 +4410,13 @@ static const QEMUOption qemu_options[] = {
     { "icount", HAS_ARG, QEMU_OPTION_icount },
     { "incoming", HAS_ARG, QEMU_OPTION_incoming },
     { "mem-path", HAS_ARG, QEMU_OPTION_mempath },
+#ifdef CONFIG_QXL
+    { "qxl", HAS_ARG, QEMU_OPTION_qxl },
+#endif
+#ifdef CONFIG_SPICE
+    { "spice", HAS_ARG, QEMU_OPTION_spice },
+    { "spice-help", 0, QEMU_OPTION_spice_help },
+#endif
     { NULL },
 };
 
@@ -4635,7 +4671,6 @@ void qemu_get_launch_info(int *argc, char ***argv, int *opt_daemonize, const cha
     *opt_incoming = incoming;
 }
 
-
 static int gethugepagesize(void)
 {
     int ret, fd;
@@ -4815,7 +4850,7 @@ int main(int argc, char **argv, char **envp)
         }
     }
 #endif
-
+    init_monitor_commands();
     register_machines();
     machine = first_machine;
     cpu_model = NULL;
@@ -5316,6 +5351,37 @@ int main(int argc, char **argv, char **envp)
                 break;
 #endif
 #endif
+#ifdef CONFIG_QXL
+            case QEMU_OPTION_qxl: {
+                int devices = strtol(optarg, NULL, 0);
+                if (devices < 0 || devices > QXL_MAX_MONITORS ) {
+                    fprintf(stderr, "qemu: invalid number of qxl devices, use 0 to %d\n",
+                            QXL_MAX_MONITORS);
+                    exit(-1);
+                }
+                num_qxl_device = devices;
+                using_qxl = (num_qxl_device > 0) ? 1 : 0;
+                break;
+            }
+#endif
+#ifdef CONFIG_SPICE
+            case QEMU_OPTION_spice:
+                using_spice = 1;
+                if (!spice_parse_args(optarg)) {
+                    fprintf(stderr, "qemu: spice parse args failed\n");
+                    exit(1);
+                }
+                break;
+            case QEMU_OPTION_spice_help: {
+                const char **spice_line = spice_usage_str;
+                printf("\nSpice options\n");
+                for (; *spice_line; spice_line++) {
+                    printf("    %s\n", *spice_line);
+                }
+                exit(0);
+                break;
+            }
+#endif
             case QEMU_OPTION_usb:
                 usb_enabled = 1;
                 break;
@@ -5465,6 +5531,13 @@ int main(int argc, char **argv, char **envp)
         }
     }
 
+#ifdef CONFIG_QXL
+    if(using_qxl) {
+        cirrus_vga_enabled = 0;
+        vmsvga_enabled = 0;
+    }
+#endif
+
 #if defined(CONFIG_KVM) && defined(USE_KQEMU)
     if (kvm_allowed && kqemu_allowed) {
         fprintf(stderr,
@@ -5672,6 +5745,12 @@ int main(int argc, char **argv, char **envp)
         phys_ram_size += ram_size;
     }
 
+#ifdef CONFIG_QXL
+    if (using_qxl) {
+        phys_ram_size += num_qxl_device * QXL_MEM_SIZE;
+    }
+#endif
+
     /* Initialize kvm */
 #if defined(TARGET_I386) || defined(TARGET_X86_64)
 #define KVM_EXTRA_PAGES 3
@@ -5732,6 +5811,10 @@ int main(int argc, char **argv, char **envp)
         }
         /* nearly nothing to do */
         dumb_display_init(ds);
+#ifdef CONFIG_QXL
+    } else if (using_qxl) {
+        qxl_init_display(ds); 
+#endif
     } else if (vnc_display != NULL) {
         vnc_display_init(ds);
         if (vnc_display_open(ds, vnc_display) < 0)
@@ -5812,8 +5895,14 @@ int main(int argc, char **argv, char **envp)
         }
     }
 
+#ifdef CONFIG_SPICE
+    if(using_spice) {
+        spice_init(&core_interface);
+    }
+#endif
+
     if (kvm_enabled())
-	kvm_init_ap();
+        kvm_init_ap();
 
 #ifdef KVM_UPSTREAM
     if (kvm_enabled()) {
@@ -5853,7 +5942,11 @@ int main(int argc, char **argv, char **envp)
         }
     }
 
+#ifdef CONFIG_QXL
+    if(!using_qxl && display_state.dpy_refresh) {
+#else
     if (display_state.dpy_refresh) {
+#endif
         display_state.gui_timer = qemu_new_timer(rt_clock, gui_update, &display_state);
         qemu_mod_timer(display_state.gui_timer, qemu_get_clock(rt_clock));
     }
-- 
1.6.1