[Spice-commits] 38 commits - display/driver.c display/mspace.c display/quic.c display/qxldd.h display/res.c display/res.h display/rop.c display/surface.c display/surface.h include/qxl_driver.h miniport/minimal_snprintf.c miniport/minimal_snprintf.h miniport/qxl.c miniport/qxl.h miniport/qxl.inf miniport/sources scripts/buildAll.bat scripts/clean.bat

Alon Levy alon at kemper.freedesktop.org
Sun Jul 31 07:24:27 PDT 2011


 display/driver.c            |  220 ++++++++++---
 display/mspace.c            |    6 
 display/quic.c              |    1 
 display/qxldd.h             |  118 ++++++-
 display/res.c               |  356 +++++++++++++++++-----
 display/res.h               |    7 
 display/rop.c               |   12 
 display/surface.c           |  301 +++++++++++++++---
 display/surface.h           |   32 +
 include/qxl_driver.h        |   13 
 miniport/minimal_snprintf.c |  708 ++++++++++++++++++++++++++++++++++++++++++++
 miniport/minimal_snprintf.h |    9 
 miniport/qxl.c              |  331 ++++++++++++++------
 miniport/qxl.h              |    3 
 miniport/qxl.inf            |    8 
 miniport/sources            |    3 
 scripts/buildAll.bat        |   75 ++++
 scripts/clean.bat           |    6 
 18 files changed, 1905 insertions(+), 304 deletions(-)

New commits:
commit 3969e0b891233c00839bdad592dd88f6ef160ff5
Author: Uri Lublin <uril at redhat.com>
Date:   Thu Jul 14 16:15:56 2011 +0300

    spice: qxl driver: support PnP surprise removal #721118
    
    This was (kind-of) cherry-picked from qspice (rhev-2.2) commit
    commit 1d467e6be87eedb3b0ad2723468fb5555192b9a2, that fixes
    rhbz #581514

diff --git a/display/res.c b/display/res.c
index 00f7f21..5d28184 100644
--- a/display/res.c
+++ b/display/res.c
@@ -224,6 +224,9 @@ static _inline void CursorCmdAddRes(PDev *pdev, QXLCursorCmd *cmd, Resource *res
     AddRes(pdev, output, res);
 }
 
+#define SUPPORT_SURPRISE_REMOVE
+
+
 /* Called with cursor_sem held */
 static void WaitForCursorRing(PDev* pdev)
 {
@@ -237,7 +240,7 @@ static void WaitForCursorRing(PDev* pdev)
         if (!wait) {
             break;
         }
-#ifdef DBG
+#ifdef SUPPORT_SURPRISE_REMOVE
         {
             LARGE_INTEGER timeout; // 1 => 100 nanoseconds
             timeout.QuadPart = -1 * (1000 * 1000 * 10); //negative  => relative // 1s
@@ -248,7 +251,7 @@ static void WaitForCursorRing(PDev* pdev)
         }
 #else
         WAIT_FOR_EVENT(pdev, pdev->cursor_event, NULL);
-#endif //DBG
+#endif //SUPPORT_SURPRISE_REMOVE
     }
 }
 
@@ -267,7 +270,7 @@ static void WaitForCmdRing(PDev* pdev)
         }
         DEBUG_PRINT((pdev, 9, "%s: 0x%lx\n", __FUNCTION__, pdev));
 
-#ifdef DBG
+#ifdef SUPPORT_SURPRISE_REMOVE
         {
             LARGE_INTEGER timeout; // 1 => 100 nanoseconds
             timeout.QuadPart = -1 * (1000 * 1000 * 10); //negative  => relative // 1s
@@ -278,7 +281,7 @@ static void WaitForCmdRing(PDev* pdev)
         }
 #else
         WAIT_FOR_EVENT(pdev, pdev->display_event, NULL);
-#endif //DBG
+#endif //SUPPORT_SURPRISE_REMOVE
     }
 }
 
commit 4029350783dcf61a9ffde552705674c9f91d6e39
Author: Uri Lublin <uril at redhat.com>
Date:   Thu Jun 30 16:18:42 2011 +0300

    qxl build: adding scripts directory and build/clean scripts

diff --git a/scripts/buildAll.bat b/scripts/buildAll.bat
new file mode 100644
index 0000000..24c81ea
--- /dev/null
+++ b/scripts/buildAll.bat
@@ -0,0 +1,75 @@
+REM Copyright Red Hat 2007-2011
+REM Authors: Yan Vugenfirer
+REM          Arnon Gilboa
+REM          Uri Lublin
+:
+: Set global parameters: 
+:
+
+: Use Windows 7 DDK
+if "%DDKVER%"=="" set DDKVER=7600.16385.0
+
+: By default DDK is installed under C:\WINDDK, but it can be installed in different location
+if "%DDKINSTALLROOT%"=="" set DDKINSTALLROOT=C:\WINDDK\
+set BUILDROOT=%DDKINSTALLROOT%%DDKVER%
+set X64ENV=x64
+if "%DDKVER%"=="6000" set X64ENV=amd64
+if "%BUILDCFG%"=="" set BUILDCFG=fre
+
+if not "%1"=="" goto parameters_here
+echo no parameters specified, exiting
+goto :eof
+:parameters_here
+
+:nextparam
+if "%1"=="" goto :eof
+goto %1
+:continue
+shift
+goto nextparam
+
+:fre
+set BUILDCFG=fre
+goto continue
+
+:chk
+set BUILDCFG=chk
+goto continue
+
+:Win7
+set BUILDENV=WIN7
+goto build_it
+
+:Win7_64
+set BUILDENV=%X64ENV% WIN7
+goto build_it
+
+:Vista
+set BUILDENV=Wlh
+goto build_it
+
+:Vista64
+set BUILDENV=%X64ENV% Wlh
+goto build_it
+
+:Win2003
+set BUILDENV=WNET
+goto build_it
+
+:Win200364
+set BUILDENV=%X64ENV% WNET
+goto build_it
+
+:XP
+set BUILDENV=WXP
+goto build_it
+
+:build_it
+set DDKBUILDENV=
+pushd %BUILDROOT%
+call %BUILDROOT%\bin\setenv.bat %BUILDROOT% %BUILDCFG% %BUILDENV%
+popd
+build -cZg
+
+goto continue
+
diff --git a/scripts/clean.bat b/scripts/clean.bat
new file mode 100644
index 0000000..acc3bc3
--- /dev/null
+++ b/scripts/clean.bat
@@ -0,0 +1,6 @@
+REM Copyright Red Hat 2009-2011
+REM Authors: Arnon Gilboa 
+:rmdir /S /Q Debug
+rmdir /S /Q Release
+for /d %%a in (obj*) do rd /s /q "%%a"
+del /F *.log *.wrn *.err
commit 3218f6cdb95a739b00b6ce4f6809141ebc44cdcf
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 16:49:32 2011 +0300

    display/driver: reimplement DrvAssertMode for Suspend+Hibernate (S3+S4) support
    
    our old code did a very minimal flow good for resolution change:
     DrvAssertMode False (disable)
      destroy primary surface
      delete vram memslot
     DrvAssertMode True (enable)
      create primary surface (destroyed on disable)
      create vram memslot
    
    Aside: Importantly the flow for resolution change involves two pdevs, so actually the
    enable call is not called, only:
     DrvAssertMode(PDEV#1, FALSE)
     DrvEnableSurface(PDEV#2)
    
    EnableSurface creates a primary surface, so the call to AssertMode must destroy it.
    
    This fails on suspend for many reasons, one of them being that we don't disable
    operations to any driver managed off screen surfaces, and the other is that
    after the qxl reset done via acpi S3 request by windows, we don't reinitialize
    the primary memslot (this is fixed by a previous commit).
    
    The correct (per example drivers from WinDDK, and per msdn) thing to do in
    DrvAssertMode is to not do any further interaction with the device. The
    simplest way to achieve that is to fail any operation. The GDI is designed such
    that it can work completely without any driver, so for any operation there is a
    fallback in case the driver returns a failure error code. A simplification is
    to use EngModifySurface to move a surface to GDI control and so not to get any
    further callback on it (except for the deletion callback when it is deleted).
    This is also done in the 3dlabs example driver.
    
    There is zero synchronization between the miniport, which knows about the power
    state, and the displayport, which knows about the pci device structure, command
    rings, resources.
    
    As a result the easiest and also consistent with the above requirements
    implementation for suspend to ram and to disk is to reset any server side state
    during DrvAssertMode(FALSE), copying all volatile (surface contents only atm)
    memory to guest ram (from there windows will copy it to disk for us if we are
    hibernating).
    
    So the new flow for DriveAssertMode is then:
    
    AssertModeDisable:
     1. set pdev->enable to False (all further operations will be punted)
     2. tell server to prepare for sleep, via new QXL_IO_UPDATE_MEM(QXL_UPDATE_MEM_RENDER_ALL):
      server updates all surfaces
      server destroys all surfaces. Since we never sent it a destroy command
       this doesn't trigger any guest side surface destruction, only a release of
       the creation command resources.
     3. release anything in the release ring.
     4. tell server to write it's current releasable items list (qxl->last_release)
     to the release_ring (we just made sure the release_ring is empty, and since we
     are not sending anything new to the worker and we already had it render
     anything outstanding it will not fill it) release the last resources (at this
     point there is nothing allocated on devram and vram - we verify that in debug
     mode with DUMP_MSPACE_VRAM and DUMP_MSPACE_DEVRAM).
     5. Destroy primary surface
     6. Delete vram memslot
    
    AssertModeEnable:
     1. Create primary surface
     2. create vram memslot
     3. copy surfaces from ram to vram, sending create commands which cause both
     create and surface image commands to be sent to the client.
    
    In suspend there is a single PDEV involved which does exactly those two calls,
    disable before sleep and enable after.
    
    For resolution change this work is excessive but correct. Since
    miniport:SetPowerState is called after DrvAssertMode during suspend (actually
    there is no defined order in the documentation), there is no way to distinguish
    between the two anyway.
    
    From: Alon Levy <alevy at redhat.com>
    From: Yonit Halperin <yhalperi at redhat.com>

diff --git a/display/driver.c b/display/driver.c
index 54913b8..00dd7ec 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -937,7 +937,11 @@ VOID DrvDisableSurface(DHPDEV in_pdev)
 
     DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
 
-    DisableQXLPrimarySurface(pdev, 1 /* hide mouse */);
+    // Don't destroy the primary - it's destroyed by destroy_all_surfaces
+    // at AssertModeDisable. Also, msdn specifically mentions DrvDisableSurface
+    // should not touch the hardware, that should be done just via DrvAssertMode
+    // (http://msdn.microsoft.com/en-us/library/ff556200%28VS.85%29.aspx)
+    pdev->surf_enable = FALSE;
     UnmapFB(pdev);
 
     if (pdev->surf) {
@@ -951,15 +955,56 @@ VOID DrvDisableSurface(DHPDEV in_pdev)
         pdev->mem_slots = NULL;
     }
 
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
 }
 
-BOOL DrvAssertMode(DHPDEV in_pdev, BOOL enable)
+static BOOL AssertModeDisable(PDev *pdev)
 {
-    PDev* pdev = (PDev*)in_pdev;
+    DEBUG_PRINT((pdev, 3, "%s entry\n", __FUNCTION__));
+    /* flush command ring and update all surfaces */
+    async_io(pdev, ASYNCABLE_FLUSH_SURFACES, 0);
+    async_io(pdev, ASYNCABLE_DESTROY_ALL_SURFACES, 0);
+    /* move all surfaces from device to system memory */
+    if (!MoveAllSurfacesToRam(pdev)) {
+        return FALSE;
+    }
+    /* Free release ring contents */
+    ReleaseCacheDeviceMemoryResources(pdev);
+    EmptyReleaseRing(pdev);
+    /* Get the last free list onto the release ring */
+    sync_io(pdev, pdev->flush_release_port, 0);
+    DEBUG_PRINT((pdev, 4, "%s after FLUSH_RELEASE\n", __FUNCTION__));
+    /* And release that. mspace allocators should be clean after. */
+    EmptyReleaseRing(pdev);
+    RemoveVRamSlot(pdev);
+    DebugCountAliveSurfaces(pdev);
+    DEBUG_PRINT((pdev, 4, "%s: [%d,%d] [%d,%d] [%d,%d] %lx\n", __FUNCTION__,
+        pdev->cmd_ring->prod, pdev->cmd_ring->cons,
+        pdev->cursor_ring->prod, pdev->cursor_ring->cons,
+        pdev->release_ring->prod, pdev->release_ring->cons,
+        pdev->Res->free_outputs));
+    DEBUG_PRINT((pdev, 4, "%s exit\n", __FUNCTION__));
+    return TRUE;
+}
 
-    DEBUG_PRINT((pdev, 1, "%s: 0x%lx %d\n", __FUNCTION__, pdev, enable));
+static void AssertModeEnable(PDev *pdev)
+{
+    InitResources(pdev);
+    InitDeviceMemoryResources(pdev);
+    DEBUG_PRINT((pdev, 3, "%s: [%d,%d] [%d,%d] [%d,%d] %lx\n", __FUNCTION__,
+        pdev->cmd_ring->prod, pdev->cmd_ring->cons,
+        pdev->cursor_ring->prod, pdev->cursor_ring->cons,
+        pdev->release_ring->prod, pdev->release_ring->cons,
+        pdev->Res->free_outputs));
+    EnableQXLPrimarySurface(pdev);
+    CreateVRamSlot(pdev);
+    DebugCountAliveSurfaces(pdev);
+    MoveAllSurfacesToVideoRam(pdev);
+    DebugCountAliveSurfaces(pdev);
+}
 
+BOOL DrvAssertModeOld(PDev *pdev, BOOL enable)
+{
     if (enable) {
         InitResources(pdev);
         EnableQXLPrimarySurface(pdev);
@@ -972,6 +1017,35 @@ BOOL DrvAssertMode(DHPDEV in_pdev, BOOL enable)
     return TRUE;
 }
 
+BOOL DrvAssertMode(DHPDEV in_pdev, BOOL enable)
+{
+    PDev* pdev = (PDev*)in_pdev;
+    BOOL ret = TRUE;
+
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx %d\n", __FUNCTION__, pdev, enable));
+    if (pdev->pci_revision < QXL_REVISION_STABLE_V10) {
+        return DrvAssertModeOld(pdev, enable);
+    }
+    /* new implementation that works correctly only with newer devices
+     * that implement QXL_IO_FLUSH_RELEASE */
+    if (pdev->enabled == enable) {
+        DEBUG_PRINT((pdev, 1, "%s: called twice with same argument (%d)\n", __FUNCTION__,
+            enable));
+        return TRUE;
+    }
+    pdev->enabled = enable;
+    if (enable) {
+        AssertModeEnable(pdev);
+    } else {
+        ret = AssertModeDisable(pdev);
+        if (!ret) {
+            pdev->enabled = !enable;
+        }
+    }
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit %d\n", __FUNCTION__, pdev, enable));
+    return ret;
+}
+
 ULONG DrvGetModes(HANDLE driver, ULONG dev_modes_size, DEVMODEW *dev_modes)
 {
     PVIDEO_MODE_INFORMATION video_modes;
diff --git a/display/surface.c b/display/surface.c
index 519d613..b40721d 100644
--- a/display/surface.c
+++ b/display/surface.c
@@ -136,11 +136,15 @@ static UINT8 *CreateSurfaceHelper(PDev *pdev, UINT32 surface_id,
 }
 
 static void SendSurfaceCreateCommand(PDev *pdev, UINT32 surface_id, SIZEL size,
-                                     UINT32 surface_format, INT32 stride, QXLPHYSICAL phys_mem)
+                                     UINT32 surface_format, INT32 stride, QXLPHYSICAL phys_mem,
+                                     int keep_data)
 {
     QXLSurfaceCmd *surface;
 
     surface = SurfaceCmd(pdev, QXL_SURFACE_CMD_CREATE, surface_id);
+    if (keep_data) {
+        surface->flags |= QXL_SURF_FLAG_KEEP_DATA;
+    }
     surface->u.surface_create.format = surface_format;
     surface->u.surface_create.width = size.cx;
     surface->u.surface_create.height = size.cy;
@@ -185,7 +189,7 @@ HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *ph
     }
 
     if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0) {
-        SendSurfaceCreateCommand(pdev, surface_id, size, surface_format, -stride, *phys_mem);
+        SendSurfaceCreateCommand(pdev, surface_id, size, surface_format, -stride, *phys_mem, 0);
     }
 
     return hbitmap;
@@ -269,7 +273,7 @@ BOOL MoveSurfaceToVideoRam(PDev *pdev, UINT32 surface_id)
     EngFreeMem(surface_info->copy);
     surface_info->copy = NULL;
     SendSurfaceCreateCommand(pdev, surface_id, surface_info->size, surface_format,
-                             -stride, phys_mem);
+                             -stride, phys_mem, 1);
     return TRUE;
 }
 
@@ -356,7 +360,9 @@ BOOL MoveAllSurfacesToRam(PDev *pdev)
                          __FUNCTION__, surface_id));
             phys_mem = SurfaceToPhysical(pdev, surface_info->draw_area.base_mem);
             SendSurfaceCreateCommand(pdev, surface_id, surf_obj->sizlBitmap,
-                                     surface_info->bitmap_format, -surf_obj->lDelta, phys_mem);
+                                     surface_info->bitmap_format, -surf_obj->lDelta, phys_mem,
+                                     /* the surface is still there, tell server not to erase */
+                                     1);
             return FALSE;
         }
         QXLDelSurface(pdev, surface_info->draw_area.base_mem, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
commit e3e2f20ea16b247208013baef06d86966c79724e
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 14:36:19 2011 +0300

    display/*: add PDev->enabled
    
    GDI will continue using any callback we registered even after a
    DrvAssertMode(FALSE). We are expected to move any surface we own to GDI handled
    and ignore any new requests to create a surface. This is called punting and we
    use PDev->enabled to indicate if this is required.
    
    A later patch will set PDev->enabled to FALSE on DrvAssertMode.

diff --git a/display/driver.c b/display/driver.c
index 6b12540..54913b8 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -516,6 +516,7 @@ DHPDEV DrvEnablePDEV(DEVMODEW *dev_mode, PWSTR ignore1, ULONG ignore2, HSURF *ig
     RtlCopyMemory(dev_caps, &gdi_info, dev_caps_size);
     RtlCopyMemory(in_dev_info, &dev_info, dev_inf_size);
 
+    pdev->enabled = TRUE; /* assume no operations before a DrvEnablePDEV. */
     DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
     return(DHPDEV)pdev;
 
@@ -1173,6 +1174,8 @@ BOOL APIENTRY DrvStrokePath(SURFOBJ *surf, PATHOBJ *path, CLIPOBJ *clip, XFORMOB
         return TRUE;
     }
 
+    PUNT_IF_DISABLED(pdev);
+
     CountCall(pdev, CALL_COUNTER_STROKE_PATH);
 
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
@@ -1265,6 +1268,8 @@ HBITMAP APIENTRY DrvCreateDeviceBitmap(DHPDEV dhpdev, SIZEL size, ULONG format)
         return 0;
     }
 
+    PUNT_IF_DISABLED(pdev);
+
     surface_id = GetFreeSurface(pdev);
     if (!surface_id) {
         goto out_error;
diff --git a/display/qxldd.h b/display/qxldd.h
index c9c2300..9b613c1 100644
--- a/display/qxldd.h
+++ b/display/qxldd.h
@@ -61,6 +61,14 @@
     EngDebugBreak();                                            \
 }
 
+#define PUNT_IF_DISABLED(pdev) \
+    do { \
+        if (!pdev->enabled) { \
+            DEBUG_PRINT((pdev, 0, "%s: punting\n", __FUNCTION__)); \
+            return FALSE; \
+        } \
+    } while (0)
+
 typedef enum {
     QXL_SUCCESS,
     QXL_FAILED,
@@ -345,6 +353,8 @@ typedef struct PDev {
     UINT32 n_surfaces;
     SurfaceInfo surface0_info;
 
+    UINT32 enabled; /* 1 between DrvAssertMode(TRUE) and DrvAssertMode(FALSE) */
+
     UCHAR  pci_revision;
 } PDev;
 
diff --git a/display/rop.c b/display/rop.c
index dce6e44..9fb3527 100644
--- a/display/rop.c
+++ b/display/rop.c
@@ -1265,6 +1265,8 @@ BOOL APIENTRY DrvBitBlt(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ *cli
         pdev = (PDev *)dest->dhpdev;
     }
 
+    PUNT_IF_DISABLED(pdev);
+
     CountCall(pdev, CALL_COUNTER_BIT_BLT);
 
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
@@ -1294,6 +1296,8 @@ BOOL APIENTRY DrvCopyBits(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip,
         pdev = (PDev *)dest->dhpdev;
     }
 
+    PUNT_IF_DISABLED(pdev);
+
     CountCall(pdev, CALL_COUNTER_BIT_BLT);
 
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
@@ -1461,6 +1465,8 @@ BOOL APIENTRY DrvStretchBltROP(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPO
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
     CountCall(pdev, CALL_COUNTER_STRETCH_BLT_ROP);
 
+    PUNT_IF_DISABLED(pdev);
+
     if ((res = _StretchBlt(pdev, dest, src, mask, clip, color_trans,
                            mode == HALFTONE ? color_adjust: NULL, brush_pos,
                            dest_rect, src_rect, mask_pos, mode, brush,rop4))) {
@@ -1494,6 +1500,8 @@ BOOL APIENTRY DrvStretchBlt(SURFOBJ *dest, SURFOBJ *src, SURFOBJ *mask, CLIPOBJ
 
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
     CountCall(pdev, CALL_COUNTER_STRETCH_BLT);
+    PUNT_IF_DISABLED(pdev);
+
     if ((res = _StretchBlt(pdev, dest, src, mask, clip, color_trans,
                            mode == HALFTONE ? color_adjust: NULL, NULL, dest_rect,
                            src_rect, mask_pos, mode, NULL, (mask) ? 0xccaa:  0xcccc))) {
@@ -1590,6 +1598,8 @@ BOOL APIENTRY DrvAlphaBlend(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLATEOBJ
     pdev = (PDev *)dest->dhpdev;
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
 
+    PUNT_IF_DISABLED(pdev);
+
     ASSERT(pdev, src_rect && src_rect->left < src_rect->right &&
            src_rect->top < src_rect->bottom);
     ASSERT(pdev, dest_rect && dest_rect->left < dest_rect->right &&
@@ -1688,6 +1698,8 @@ BOOL APIENTRY DrvTransparentBlt(SURFOBJ *dest, SURFOBJ *src, CLIPOBJ *clip, XLAT
 
     DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
 
+    PUNT_IF_DISABLED(pdev);
+
     ASSERT(pdev, src_rect && src_rect->left < src_rect->right &&
            src_rect->top < src_rect->bottom);
     ASSERT(pdev, dest_rect && dest_rect->left < dest_rect->right &&
commit 9cbe84d0843fff005d4f62b41878a8f51130998c
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 16:45:03 2011 +0300

    display/surface: add surfaces from/to ram
    
    Adds fields to SurfaceInfo to cache data previously only available
    via SurfaceArea::draw_area.
    
    Adds two functions to save and restore surfaces from ram:
    
    MoveAllSurfacesToVideoRam
     allocates and copies surfaces from vram to ram, and calls EngModifySurface
     with an empty hook list to make those surfaces completely managed by gdi and not
     us.
    
    MoveAllSurfacesToRam
     recreates surfaces on vram and calls EngModifySurface with QXL_SURFACE_HOOKS, and
     finally sends a QXL_SURFACE_CMD_CREATE with the valid data flag to make the server
     send a surface image message after the surface create message.
    
    Cc: Yonit Halperin <yhalperi at redhat.com>

diff --git a/display/driver.c b/display/driver.c
index d5f9d8c..6b12540 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -1300,7 +1300,9 @@ VOID APIENTRY DrvDeleteDeviceBitmap(DHSURF dhsurf)
 
     ASSERT(pdev, surface_id < pdev->n_surfaces);
 
-    DeleteDeviceBitmap(surface->u.pdev, surface_id, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+    DeleteDeviceBitmap(surface->u.pdev, surface_id,
+                       surface->copy ? DEVICE_BITMAP_ALLOCATION_TYPE_RAM
+                                     : DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
 }
 
 #ifdef CALL_TEST
diff --git a/display/qxldd.h b/display/qxldd.h
index 92d1ae8..c9c2300 100644
--- a/display/qxldd.h
+++ b/display/qxldd.h
@@ -187,7 +187,11 @@ typedef struct DrawArea {
 
 typedef struct SurfaceInfo SurfaceInfo;
 struct SurfaceInfo {
-    DrawArea draw_area;
+    DrawArea    draw_area;
+    HBITMAP     hbitmap;
+    SIZEL       size;
+    UINT8      *copy;
+    ULONG       bitmap_format;
     union {
         PDev *pdev;
         SurfaceInfo *next_free;
diff --git a/display/res.c b/display/res.c
index eda6663..00f7f21 100644
--- a/display/res.c
+++ b/display/res.c
@@ -771,8 +771,12 @@ void PushSurfaceCmd(PDev *pdev, QXLSurfaceCmd *surface_cmd)
     EngReleaseSemaphore(pdev->Res->cmd_sem);
 }
 
+QXLPHYSICAL SurfaceToPhysical(PDev *pdev, UINT8 *base_mem)
+{
+    return PA(pdev, base_mem, pdev->vram_mem_slot);
+}
 
-_inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, UINT32 *stride,
+_inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, INT32 *stride,
                               UINT8 **base_mem, QXLPHYSICAL *phys_mem, UINT8 allocation_type)
 {
     DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
@@ -794,7 +798,7 @@ _inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, UINT
         *stride = x * depth / 8;
         *stride = ALIGN(*stride, 4);
         *base_mem = __AllocMem(pdev, MSPACE_TYPE_VRAM, (*stride) * y, FALSE);
-        *phys_mem = PA(pdev, (PVOID)((UINT64)*base_mem), pdev->vram_mem_slot);
+        *phys_mem = SurfaceToPhysical(pdev, *base_mem);
         break;
     case DEVICE_BITMAP_ALLOCATION_TYPE_RAM:
         /* used only before suspend to sleep (DrvAssertMode(FALSE)) and then released
@@ -811,7 +815,7 @@ _inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, UINT
 }
 
 void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
-                   UINT32 *stride, UINT8 **base_mem, UINT8 allocation_type)
+                   INT32 *stride, UINT8 **base_mem, UINT8 allocation_type)
 {
     GetSurfaceMemory(pdev, x, y, depth, stride, base_mem, surface_phys, allocation_type);
 }
diff --git a/display/res.h b/display/res.h
index b38d5cf..1feadb0 100644
--- a/display/res.h
+++ b/display/res.h
@@ -31,8 +31,9 @@ void PushDrawable(PDev *pdev, QXLDrawable *drawable);
 QXLSurfaceCmd *SurfaceCmd(PDev *pdev, UINT8 type, UINT32 surface_id);
 void PushSurfaceCmd(PDev *pdev, QXLSurfaceCmd *surface_cmd);
 
+QXLPHYSICAL SurfaceToPhysical(PDev *pdev, UINT8 *base_mem);
 void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UINT32 depth,
-                   UINT32 *stride, UINT8 **base_mem, UINT8 allocation_type);
+                   INT32 *stride, UINT8 **base_mem, UINT8 allocation_type);
 void QXLGetDelSurface(PDev *pdev, QXLSurfaceCmd *surface, UINT32 surface_id, UINT8 allocation_type);
 void QXLDelSurface(PDev *pdev, UINT8 *base_mem, UINT8 allocation_type);
 BOOL QXLGetPath(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *path_phys, PATHOBJ *path);
diff --git a/display/surface.c b/display/surface.c
index 20fd950..519d613 100644
--- a/display/surface.c
+++ b/display/surface.c
@@ -82,69 +82,115 @@ static VOID FreeDrawArea(DrawArea *drawarea)
     }
 }
 
-HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem,
-                           UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type)
+static void BitmapFormatToDepthAndSurfaceFormat(ULONG format, UINT32 *depth, UINT32 *surface_format)
 {
-    UINT32 surface_format, depth;
-    HBITMAP surf;
-    UINT32 stride;
-
     switch (format) {
         case BMF_16BPP:
-            surface_format = SPICE_SURFACE_FMT_16_555;
-            depth = 16;
+            *surface_format = SPICE_SURFACE_FMT_16_555;
+            *depth = 16;
             break;
         case BMF_24BPP:
         case BMF_32BPP:
-            surface_format = SPICE_SURFACE_FMT_32_xRGB;
-            depth = 32;
+            *surface_format = SPICE_SURFACE_FMT_32_xRGB;
+            *depth = 32;
             break;
-        case BMF_8BPP:
         default:
-            return 0;
+            *depth = 0;
+            break;
     };
+}
+
+static UINT8 *CreateSurfaceHelper(PDev *pdev, UINT32 surface_id,
+                                  UINT32 cx, UINT32 cy, ULONG format,
+                                  UINT8 allocation_type,
+                                  INT32 *stride, UINT32 *surface_format,
+                                  QXLPHYSICAL *phys_mem)
+{
+    UINT32 depth;
+    SurfaceInfo *surface_info = GetSurfaceInfo(pdev, surface_id);
+    UINT8 *base_mem;
+    int size;
+
+    BitmapFormatToDepthAndSurfaceFormat(format, &depth, surface_format);
+    ASSERT(pdev, depth != 0);
+    ASSERT(pdev, stride);
+    QXLGetSurface(pdev, phys_mem, cx, cy, depth, stride, &base_mem, allocation_type);
+    DEBUG_PRINT((pdev, 3,
+        "%s: %d, pm %0lX, fmt %d, d %d, s (%d, %d) st %d\n",
+        __FUNCTION__, surface_id, (uint64_t)*phys_mem, *surface_format,
+        depth, cx, cy, *stride));
+    size = abs(*stride) * cy;
+    if (!base_mem) {
+        DEBUG_PRINT((pdev, 0, "%s: %p: %d: QXLGetSurface failed (%d bytes alloc)\n",
+            __FUNCTION__, pdev, surface_id, size));
+        return NULL;
+    }
+    if (!CreateDrawArea(pdev, base_mem, surface_info->bitmap_format, cx, cy, *stride, surface_id)) {
+        DEBUG_PRINT((pdev, 0, "%s: %p: CreateDrawArea failed (%d)\n",
+            __FUNCTION__, pdev, surface_id, size));
+        // TODO: Why did it fail? nothing in the MSDN
+        QXLDelSurface(pdev, base_mem, allocation_type);
+        return NULL;
+    }
+    return base_mem;
+}
+
+static void SendSurfaceCreateCommand(PDev *pdev, UINT32 surface_id, SIZEL size,
+                                     UINT32 surface_format, INT32 stride, QXLPHYSICAL phys_mem)
+{
+    QXLSurfaceCmd *surface;
+
+    surface = SurfaceCmd(pdev, QXL_SURFACE_CMD_CREATE, surface_id);
+    surface->u.surface_create.format = surface_format;
+    surface->u.surface_create.width = size.cx;
+    surface->u.surface_create.height = size.cy;
+    surface->u.surface_create.stride = stride;
+    surface->u.surface_create.data = phys_mem;
+    PushSurfaceCmd(pdev, surface);
+}
+
+HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem,
+                           UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type)
+{
+    UINT32 surface_format, depth;
+    HBITMAP hbitmap;
+    INT32 stride;
+    SurfaceInfo *surface_info;
 
-    if (!(surf = EngCreateDeviceBitmap((DHSURF)GetSurfaceInfo(pdev, surface_id), size, format))) {
+    DEBUG_PRINT((pdev, 9, "%s: %p: %d, (%dx%d), %d\n", __FUNCTION__, pdev, surface_id,
+                size.cx, size.cy, format));
+    surface_info = GetSurfaceInfo(pdev, surface_id);
+
+    if (!(hbitmap = EngCreateDeviceBitmap((DHSURF)surface_info, size, format))) {
         DEBUG_PRINT((pdev, 0, "%s: EngCreateDeviceBitmap failed, pdev 0x%lx, surface_id=%d\n",
                     __FUNCTION__, pdev, surface_id));
         goto out_error1;
     }
 
-    if (!EngAssociateSurface((HSURF)surf, pdev->eng, QXL_SURFACE_HOOKS)) {
+    if (!EngAssociateSurface((HSURF)hbitmap, pdev->eng, QXL_SURFACE_HOOKS)) {
         DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__));
         goto out_error2;
     }
-
-    GetSurfaceInfo(pdev, surface_id)->u.pdev = pdev;
-
-    QXLGetSurface(pdev, phys_mem, size.cx, size.cy, depth,
-                  &stride, base_mem, allocation_type);
-    if (!*base_mem) {
+    surface_info->u.pdev = pdev;
+    surface_info->hbitmap = hbitmap;
+    surface_info->copy = NULL;
+    surface_info->size = size;
+    surface_info->bitmap_format = format;
+    if ((*base_mem = CreateSurfaceHelper(pdev, surface_id, size.cx, size.cy, format,
+                                         allocation_type, &stride, &surface_format,
+                                         phys_mem)) == NULL) {
+        DEBUG_PRINT((pdev, 0, "%s: failed, pdev 0x%lx, surface_id=%d\n",
+                    __FUNCTION__, pdev, surface_id));
         goto out_error2;
     }
 
-    if (!CreateDrawArea(pdev, *base_mem, format, size.cx, size.cy, stride, surface_id)) {
-        goto out_error3;
-    }
-
     if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0) {
-        QXLSurfaceCmd *surface;
-
-        surface = SurfaceCmd(pdev, QXL_SURFACE_CMD_CREATE, surface_id);
-        surface->u.surface_create.format = surface_format;
-        surface->u.surface_create.width = size.cx;
-        surface->u.surface_create.height = size.cy;
-        surface->u.surface_create.stride = -(INT32)stride;
-        surface->u.surface_create.data = *phys_mem;
-        PushSurfaceCmd(pdev, surface);
+        SendSurfaceCreateCommand(pdev, surface_id, size, surface_format, -stride, *phys_mem);
     }
 
-    return surf;
-
-out_error3:
-    QXLDelSurface(pdev, *base_mem, allocation_type);
+    return hbitmap;
 out_error2:
-    EngDeleteSurface((HSURF)surf);
+    EngDeleteSurface((HSURF)hbitmap);
 out_error1:
     return 0;
 }
@@ -175,3 +221,147 @@ VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type)
         }
     }
 }
+
+static void CleanupSurfaceInfo(PDev *pdev, UINT32 surface_id, UINT8 allocation_type)
+{
+    SurfaceInfo *surface_info = GetSurfaceInfo(pdev, surface_id);
+
+    FreeDrawArea(&surface_info->draw_area);
+    if (surface_info->draw_area.base_mem != NULL) {
+        QXLDelSurface(pdev, surface_info->draw_area.base_mem, allocation_type);
+    }
+}
+
+BOOL MoveSurfaceToVideoRam(PDev *pdev, UINT32 surface_id)
+{
+    QXLSurfaceCmd *surface;
+    UINT32 surface_format;
+    UINT32 depth;
+    int count_used = 0;
+    int size;
+    INT32 stride = 0;
+    QXLPHYSICAL phys_mem;
+    SurfaceInfo *surface_info = GetSurfaceInfo(pdev, surface_id);
+    UINT32 cx = surface_info->size.cx;
+    UINT32 cy = surface_info->size.cy;
+    UINT8 *base_mem;
+
+    DEBUG_PRINT((pdev, 3, "%s: %d\n", __FUNCTION__, surface_id));
+    if ((base_mem = CreateSurfaceHelper(pdev, surface_id, cx, cy, surface_info->bitmap_format,
+                                        DEVICE_BITMAP_ALLOCATION_TYPE_VRAM,
+                                        &stride, &surface_format, &phys_mem)) == NULL) {
+        DEBUG_PRINT((pdev, 0, "%s: %p: %d: failed\n", __FUNCTION__, pdev, surface_id));
+        return FALSE;
+    }
+    size = abs(stride) * cy;
+    if (!EngModifySurface((HSURF)surface_info->hbitmap, pdev->eng, QXL_SURFACE_HOOKS,
+        MS_NOTSYSTEMMEMORY, (DHSURF)surface_info, NULL, 0, NULL)) {
+        DEBUG_PRINT((pdev, 0, "%s: %p: %d: EngModifySurface failed\n",
+            __FUNCTION__, pdev, surface_id));
+        CleanupSurfaceInfo(pdev, surface_id, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+        return FALSE;
+    }
+    DEBUG_PRINT((pdev, 3, "%s: stride = %d, phys_mem = %0lX, base_mem = %p\n",
+        __FUNCTION__, -stride, (uint64_t)phys_mem, base_mem));
+    DEBUG_PRINT((pdev, 3, "%s: copy %d bytes to %d\n", __FUNCTION__, size, surface_id));
+    // Everything allocated, nothing can fail (API wise) from this point
+    RtlCopyMemory(base_mem, surface_info->copy, size);
+    EngFreeMem(surface_info->copy);
+    surface_info->copy = NULL;
+    SendSurfaceCreateCommand(pdev, surface_id, surface_info->size, surface_format,
+                             -stride, phys_mem);
+    return TRUE;
+}
+
+/* when we return from S3 we need to resend all the surface creation commands.
+ * Actually moving the memory vram<->guest is not strictly neccessary since vram
+ * is not reset during the suspend, so contents are not lost */
+int MoveAllSurfacesToVideoRam(PDev *pdev)
+{
+    UINT32 surface_id;
+    SurfaceInfo *surface_info;
+
+    /* brute force implementation - alternative is to keep an updated used_surfaces list */
+    DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+
+    for (surface_id = 1 ; surface_id < pdev->n_surfaces ; ++surface_id) {
+        surface_info = GetSurfaceInfo(pdev, surface_id);
+        if (!surface_info->draw_area.base_mem) {
+            continue;
+        }
+        if (surface_info->u.pdev != pdev) {
+            DEBUG_PRINT((pdev, 3, "%s: %p: not our pdev (%p)\n", __FUNCTION__, pdev,
+                         surface_info->u.pdev));
+            continue;
+        }
+        if (surface_info->draw_area.surf_obj) {
+            DEBUG_PRINT((pdev, 3, "%s: surface_id = %d, surf_obj not empty\n", __FUNCTION__,
+                         surface_id));
+            continue;
+        }
+        if (surface_info->copy == NULL) {
+            DEBUG_PRINT((pdev, 3, "%s: %p: %d: no copy buffer, ignored\n", __FUNCTION__,
+                         pdev, surface_id));
+        }
+        if (!MoveSurfaceToVideoRam(pdev, surface_id)) {
+            /* Some of the surfaces have not been moved to video ram.
+             * they will remain managed by GDI. */
+            DEBUG_PRINT((pdev, 0, "%s: %p: %d: failed moving to vram\n", __FUNCTION__,
+                         pdev, surface_id));
+        }
+    }
+    return TRUE;
+}
+
+BOOL MoveAllSurfacesToRam(PDev *pdev)
+{
+    UINT32 surface_id;
+    SurfaceInfo *surface_info;
+    SURFOBJ *surf_obj;
+    UINT8 *copy;
+    UINT8 *line0;
+    int size;
+    QXLPHYSICAL phys_mem;
+
+    for (surface_id = 1 ; surface_id < pdev->n_surfaces ; ++surface_id) {
+        surface_info = GetSurfaceInfo(pdev, surface_id);
+        if (!surface_info->draw_area.base_mem) {
+            continue;
+        }
+        surf_obj = surface_info->draw_area.surf_obj;
+        if (!surf_obj) {
+            DEBUG_PRINT((pdev, 3, "%s: %d: no surfobj, not copying\n", __FUNCTION__, surface_id));
+            continue;
+        }
+        size = surf_obj->sizlBitmap.cy * abs(surf_obj->lDelta);
+        copy = EngAllocMem(0, size, ALLOC_TAG);
+        DEBUG_PRINT((pdev, 3, "%s: %d: copying #%d to %p (%d)\n", __FUNCTION__, surface_id, size,
+            copy, surf_obj->lDelta));
+        RtlCopyMemory(copy, surface_info->draw_area.base_mem, size);
+        surface_info->copy = copy;
+        line0 = surf_obj->lDelta > 0 ? copy : copy + abs(surf_obj->lDelta) *
+                (surf_obj->sizlBitmap.cy - 1);
+        if (!EngModifySurface((HSURF)surface_info->hbitmap,
+                      pdev->eng,
+                      0, /* from the example: used to monitor memory HOOK_COPYBITS | HOOK_BITBLT, */
+                      0,                    /* It's system-memory */
+                      (DHSURF)surface_info,
+                      line0,
+                      surf_obj->lDelta,
+                      NULL)) {
+            /* Send a create messsage for this surface - we previously did a destroy all. */
+            EngFreeMem(surface_info->copy);
+            surface_info->copy = NULL;
+            DEBUG_PRINT((pdev, 0, "%s: %d: EngModifySurface failed, sending create\n",
+                         __FUNCTION__, surface_id));
+            phys_mem = SurfaceToPhysical(pdev, surface_info->draw_area.base_mem);
+            SendSurfaceCreateCommand(pdev, surface_id, surf_obj->sizlBitmap,
+                                     surface_info->bitmap_format, -surf_obj->lDelta, phys_mem);
+            return FALSE;
+        }
+        QXLDelSurface(pdev, surface_info->draw_area.base_mem, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+        surface_info->draw_area.base_mem = copy;
+        FreeDrawArea(&surface_info->draw_area);
+    }
+    return TRUE;
+}
diff --git a/display/surface.h b/display/surface.h
index f723392..d770884 100644
--- a/display/surface.h
+++ b/display/surface.h
@@ -105,4 +105,7 @@ HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *ph
                            UINT8 **base_mem, UINT32 surface_id, UINT8 allocation_type);
 VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type);
 
+int MoveAllSurfacesToVideoRam(PDev *pdev);
+BOOL MoveAllSurfacesToRam(PDev *pdev);
+
 #endif
commit 6f7262628021333748e823a3b2219a7722fd405e
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 16:39:11 2011 +0300

    display/surface: add DEVICE_BITMAP_ALLOCATION_TYPE_RAM, cleanup surface alloc/free code paths
    
    This adds a third surface allocation type, allocation from guest memory using
    the windows ddk allocator.
    
    Not all code paths are used later - the creation is not done since
    copy-surfaces-to-ram allocates memory itself, and at the end we never allocate
    any surfaces when the device is disabled, we just punt the allocation to the
    gdi, but the code is still left in GetSurfaceMemory.
    
    Cc: Yonit Halperin <yhalperi at redhat.com>

diff --git a/display/driver.c b/display/driver.c
index c19fcaa..d5f9d8c 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -1290,9 +1290,15 @@ VOID APIENTRY DrvDeleteDeviceBitmap(DHSURF dhsurf)
 {
     UINT32 surface_id;
     SurfaceInfo *surface;
+    PDev *pdev;
 
     surface = (SurfaceInfo *)dhsurf;
     surface_id = GetSurfaceIdFromInfo(surface);
+    pdev = surface->u.pdev;
+
+    DEBUG_PRINT((pdev, 3, "%s: %p: %d\n", __FUNCTION__, pdev, surface_id));
+
+    ASSERT(pdev, surface_id < pdev->n_surfaces);
 
     DeleteDeviceBitmap(surface->u.pdev, surface_id, DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
 }
diff --git a/display/res.c b/display/res.c
index fb308ea..eda6663 100644
--- a/display/res.c
+++ b/display/res.c
@@ -790,13 +790,21 @@ _inline void GetSurfaceMemory(PDev *pdev, UINT32 x, UINT32 y, UINT32 depth, UINT
         *base_mem = AllocMem(pdev, MSPACE_TYPE_DEVRAM, (*stride) * y);
         *phys_mem = PA(pdev, *base_mem, pdev->main_mem_slot);
         break;
-    case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM: { 
+    case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM:
         *stride = x * depth / 8;
         *stride = ALIGN(*stride, 4);
         *base_mem = __AllocMem(pdev, MSPACE_TYPE_VRAM, (*stride) * y, FALSE);
         *phys_mem = PA(pdev, (PVOID)((UINT64)*base_mem), pdev->vram_mem_slot);
         break;
-    }
+    case DEVICE_BITMAP_ALLOCATION_TYPE_RAM:
+        /* used only before suspend to sleep (DrvAssertMode(FALSE)) and then released
+         * and copied back to VRAM */
+        *stride = x * depth / 8;
+        *stride = ALIGN(*stride, 4);
+        *base_mem = EngAllocMem(0 /* don't zero memory, will be copied over in a bit */,
+                                (*stride) * y, ALLOC_TAG);
+        *phys_mem = (QXLPHYSICAL)NULL; /* make sure no one uses it */
+        break;
     default:
         PANIC(pdev, "No allocation type");
     }
@@ -810,10 +818,18 @@ void QXLGetSurface(PDev *pdev, QXLPHYSICAL *surface_phys, UINT32 x, UINT32 y, UI
 
 void QXLDelSurface(PDev *pdev, UINT8 *base_mem, UINT8 allocation_type)
 {
-    if (allocation_type == DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM) {
+    switch (allocation_type) {
+    case DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM:
         FreeMem(pdev, MSPACE_TYPE_DEVRAM, base_mem);
-    }  else if (allocation_type == DEVICE_BITMAP_ALLOCATION_TYPE_VRAM) { // this wasn't there in the original code
-         FreeMem(pdev, MSPACE_TYPE_VRAM, base_mem);
+        break;
+    case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM:
+        FreeMem(pdev, MSPACE_TYPE_VRAM, base_mem);
+        break;
+    case DEVICE_BITMAP_ALLOCATION_TYPE_RAM:
+        EngFreeMem(base_mem);
+        break;
+    default:
+        PANIC(pdev, "bad allocation type");
     }
 }
 
@@ -829,18 +845,8 @@ static void FreeDelSurface(PDev *pdev, Resource *res)
     DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
 
     internal = (InternalDelSurface *)res->res;
-    switch (internal->allocation_type) {
-    case DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM:
-        FreeMem(pdev, MSPACE_TYPE_DEVRAM,
-                GetSurfaceInfo(pdev, internal->surface_id)->draw_area.base_mem);
-        break;
-    case DEVICE_BITMAP_ALLOCATION_TYPE_VRAM:
-        FreeMem(pdev, MSPACE_TYPE_VRAM,
-                GetSurfaceInfo(pdev, internal->surface_id)->draw_area.base_mem);
-        break;
-    default:
-        PANIC(pdev, "bad allocation type");
-    }
+    QXLDelSurface(pdev, GetSurfaceInfo(pdev, internal->surface_id)->draw_area.base_mem,
+        internal->allocation_type);
     FreeSurfaceInfo(pdev, internal->surface_id);
     FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
 
diff --git a/display/surface.c b/display/surface.c
index aabc31a..20fd950 100644
--- a/display/surface.c
+++ b/display/surface.c
@@ -159,10 +159,19 @@ VOID DeleteDeviceBitmap(PDev *pdev, UINT32 surface_id, UINT8 allocation_type)
 
     if (allocation_type != DEVICE_BITMAP_ALLOCATION_TYPE_SURF0 &&
         pdev->Res->surfaces_info[surface_id].draw_area.base_mem != NULL) {
-        QXLSurfaceCmd *surface;
 
-        surface = SurfaceCmd(pdev, QXL_SURFACE_CMD_DESTROY, surface_id);
-        QXLGetDelSurface(pdev, surface, surface_id, allocation_type);
-        PushSurfaceCmd(pdev, surface);
+        if (allocation_type == DEVICE_BITMAP_ALLOCATION_TYPE_RAM) {
+            /* server side this surface is already destroyed, just free it here */
+            ASSERT(pdev, pdev->Res->surfaces_info[surface_id].draw_area.base_mem ==
+                pdev->Res->surfaces_info[surface_id].copy);
+            QXLDelSurface(pdev, pdev->Res->surfaces_info[surface_id].draw_area.base_mem,
+                allocation_type);
+            FreeSurfaceInfo(pdev, surface_id);
+        } else {
+            QXLSurfaceCmd *surface_cmd;
+            surface_cmd = SurfaceCmd(pdev, QXL_SURFACE_CMD_DESTROY, surface_id);
+            QXLGetDelSurface(pdev, surface_cmd, surface_id, allocation_type);
+            PushSurfaceCmd(pdev, surface_cmd);
+        }
     }
 }
diff --git a/display/surface.h b/display/surface.h
index 0b7edb3..f723392 100644
--- a/display/surface.h
+++ b/display/surface.h
@@ -98,6 +98,7 @@ enum {
     DEVICE_BITMAP_ALLOCATION_TYPE_SURF0,
     DEVICE_BITMAP_ALLOCATION_TYPE_DEVRAM,
     DEVICE_BITMAP_ALLOCATION_TYPE_VRAM,
+    DEVICE_BITMAP_ALLOCATION_TYPE_RAM,
 };
 
 HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *phys_mem,
commit bc99aa0d84aea859d54404c3ccf085e3ef65901f
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 16:28:47 2011 +0300

    display/surface: FreeSurfaceInfo: ignore double frees
    
    Cc: Yonit Halperin <yhalperi at redhat.com>

diff --git a/display/surface.h b/display/surface.h
index e677610..0b7edb3 100644
--- a/display/surface.h
+++ b/display/surface.h
@@ -55,10 +55,16 @@ static _inline void FreeSurfaceInfo(PDev *pdev, UINT32 surface_id)
     if (surface_id == 0) {
         return;
     }
-
     EngAcquireSemaphore(pdev->Res->surface_sem);
 
+    DEBUG_PRINT((pdev, 9, "%s: %p: %d\n", __FUNCTION__, pdev, surface_id));
     surface = &pdev->Res->surfaces_info[surface_id];
+    if (surface->draw_area.base_mem == NULL) {
+        DEBUG_PRINT((pdev, 9, "%s: %p: %d: double free. safely ignored\n", __FUNCTION__,
+            pdev, surface_id));
+        EngReleaseSemaphore(pdev->Res->surface_sem);
+        return;
+    }
     surface->draw_area.base_mem = NULL; /* Mark as not used */
     surface->u.next_free = pdev->Res->free_surfaces;
     pdev->Res->free_surfaces = surface;
commit dad7879e8ff4bb06b46f5a7e535708b46f5d9466
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 16:28:10 2011 +0300

    display/surface: GetSurfaceId: return -1 if \!surf->dhsurf
    
    Cc: Yonit Halperin <yhalperi at redhat.com>

diff --git a/display/surface.h b/display/surface.h
index 00fd93c..e677610 100644
--- a/display/surface.h
+++ b/display/surface.h
@@ -41,6 +41,9 @@ static _inline UINT32 GetSurfaceId(SURFOBJ *surf)
 {
     SurfaceInfo *surface;
 
+    if (!surf || !surf->dhsurf) {
+        return (UINT32)-1;
+    }
     surface = (SurfaceInfo *)surf->dhsurf;
     return GetSurfaceIdFromInfo(surface);
 }
commit 0c8b82771d117749b2befedc1038d295e4850f5e
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 15:52:42 2011 +0300

    display/surface: add QXL_SURFACE_HOOKS define
    
    Cc: Yonit Halperin <yhalperi at redhat.com>

diff --git a/display/surface.c b/display/surface.c
index 61c898f..aabc31a 100644
--- a/display/surface.c
+++ b/display/surface.c
@@ -110,14 +110,7 @@ HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *ph
         goto out_error1;
     }
 
-    if (!EngAssociateSurface((HSURF)surf, pdev->eng,  HOOK_SYNCHRONIZE | HOOK_COPYBITS |
-                             HOOK_BITBLT | HOOK_TEXTOUT | HOOK_STROKEPATH | HOOK_STRETCHBLT |
-                             HOOK_STRETCHBLTROP | HOOK_TRANSPARENTBLT | HOOK_ALPHABLEND
-#ifdef CALL_TEST
-                             | HOOK_PLGBLT | HOOK_FILLPATH | HOOK_STROKEANDFILLPATH | HOOK_LINETO |
-                             HOOK_GRADIENTFILL 
-#endif
-                             )) {
+    if (!EngAssociateSurface((HSURF)surf, pdev->eng, QXL_SURFACE_HOOKS)) {
         DEBUG_PRINT((pdev, 0, "%s: EngAssociateSurface failed\n", __FUNCTION__));
         goto out_error2;
     }
diff --git a/display/surface.h b/display/surface.h
index 977fa91..00fd93c 100644
--- a/display/surface.h
+++ b/display/surface.h
@@ -3,6 +3,21 @@
 
 #include "qxldd.h"
 
+/* Hooks supported by our surfaces. */
+#ifdef CALL_TEST
+#define QXL_SURFACE_HOOKS_CALL_TEST \
+    (HOOK_PLGBLT | HOOK_FILLPATH | HOOK_STROKEANDFILLPATH | HOOK_LINETO |  \
+    HOOK_GRADIENTFILL)
+#else
+#define QXL_SURFACE_HOOKS_CALL_TEST (0)
+#endif
+
+#define QXL_SURFACE_HOOKS \
+    (HOOK_SYNCHRONIZE | HOOK_COPYBITS |                                 \
+    HOOK_BITBLT | HOOK_TEXTOUT | HOOK_STROKEPATH | HOOK_STRETCHBLT |    \
+    HOOK_STRETCHBLTROP | HOOK_TRANSPARENTBLT | HOOK_ALPHABLEND | QXL_SURFACE_HOOKS_CALL_TEST)
+
+
 static _inline UINT32 GetSurfaceIdFromInfo(SurfaceInfo *info)
 {
   PDev *pdev;
commit 8c5d8b39523e1a1da2c7b4902f8d6a8a8bc3aae9
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jun 15 22:43:39 2011 +0200

    display/res: add a debug print level 9

diff --git a/display/res.c b/display/res.c
index e184cf9..fb308ea 100644
--- a/display/res.c
+++ b/display/res.c
@@ -265,6 +265,8 @@ static void WaitForCmdRing(PDev* pdev)
         if (!wait) {
             break;
         }
+        DEBUG_PRINT((pdev, 9, "%s: 0x%lx\n", __FUNCTION__, pdev));
+
 #ifdef DBG
         {
             LARGE_INTEGER timeout; // 1 => 100 nanoseconds
commit b22e53cdc6886cc2fab37604a6950da34960e2b0
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jun 15 16:24:37 2011 +0200

    display/res: __AllocMem: verbose debugging (log_level 12)
    
    Cc: Yonit Halperin <yhalperi at redhat.com>

diff --git a/display/res.c b/display/res.c
index 96950c6..e184cf9 100644
--- a/display/res.c
+++ b/display/res.c
@@ -386,8 +386,15 @@ static void *__AllocMem(PDev* pdev, UINT32 mspace_type, size_t size, BOOL force)
     UINT8 *ptr;
 
     ASSERT(pdev, pdev && pdev->Res->mspaces[mspace_type]._mspace);
-    DEBUG_PRINT((pdev, 12, "%s: 0x%lx size %u\n", __FUNCTION__, pdev, size));
-
+    DEBUG_PRINT((pdev, 12, "%s: 0x%lx %p(%d) size %u\n", __FUNCTION__, pdev,
+        pdev->Res->mspaces[mspace_type]._mspace,
+        mspace_footprint(pdev->Res->mspaces[mspace_type]._mspace),
+        size));
+#ifdef DBG
+    if (pdev && pdev->log_level && *pdev->log_level > 11) {
+        mspace_malloc_stats(pdev->Res->mspaces[mspace_type]._mspace);
+    }
+#endif
     EngAcquireSemaphore(pdev->Res->malloc_sem);
 
     while (1) {
commit a48ad838e33a18097cc573134934860260985a05
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 15:45:40 2011 +0300

    display/res: add helpers for clearing device memory
    
    Refactors InitResources code called upon DrvEnableSurface so it can later be called
    from AssertModeEnable. Introduces three helpers:
    
    EmptyReleaseRing - no vmexit, goes over release ring and empties it all (as opposed to
    OOM behavior that empties 50 resources).
    InitDeviceMemoryResources - resets anything on the device memory (devram and vram pci bars).
    ReleaseCacheDeviceMemoryResources - helper for clearing the cache (which points to devram
    QXLImage's)
    
    Cc: Yonit Halperin <yhalperi at redhat.com>

diff --git a/display/res.c b/display/res.c
index 1a5e76e..96950c6 100644
--- a/display/res.c
+++ b/display/res.c
@@ -366,6 +366,19 @@ static void FlushReleaseRing(PDev *pdev)
     pdev->Res->free_outputs = output;
 }
 
+void EmptyReleaseRing(PDev *pdev)
+{
+    int count = 0;
+
+    EngAcquireSemaphore(pdev->Res->malloc_sem);
+    while (pdev->Res->free_outputs || !SPICE_RING_IS_EMPTY(pdev->release_ring)) {
+        FlushReleaseRing(pdev);
+        count++;
+    }
+    EngReleaseSemaphore(pdev->Res->malloc_sem);
+    DEBUG_PRINT((pdev, 3, "%s: complete after %d rounds\n", __FUNCTION__, count));
+}
+
 // todo: separate VRAM releases from DEVRAM releases
 #define AllocMem(pdev, mspace_type, size) __AllocMem(pdev, mspace_type, size, TRUE)
 static void *__AllocMem(PDev* pdev, UINT32 mspace_type, size_t size, BOOL force)
@@ -506,6 +519,44 @@ static void InitMspace(PDev *pdev, UINT32 mspace_type, UINT8 *start, size_t capa
     res->mspaces[mspace_type].mspace_end = start + capacity;
 }
 
+static void ResetCache(PDev *pdev)
+{
+    int i;
+
+    RtlZeroMemory(pdev->Res->image_key_lookup,
+                  sizeof(pdev->Res->image_key_lookup));
+    RtlZeroMemory(pdev->Res->cache_image_pool,
+                  sizeof(pdev->Res->cache_image_pool));
+    RingInit(&pdev->Res->cache_image_lru);
+    for (i = 0; i < IMAGE_POOL_SIZE; i++) {
+        RingAdd(pdev, &pdev->Res->cache_image_lru,
+                &pdev->Res->cache_image_pool[i].lru_link);
+    }
+
+    RtlZeroMemory(pdev->Res->image_cache, sizeof(pdev->Res->image_cache));
+    RtlZeroMemory(pdev->Res->cursor_cache, sizeof(pdev->Res->cursor_cache));
+    RingInit(&pdev->Res->cursors_lru);
+    pdev->Res->num_cursors = 0;
+    pdev->Res->last_cursor_id = 0;
+
+    RtlZeroMemory(pdev->Res->palette_cache, sizeof(pdev->Res->palette_cache));
+    RingInit(&pdev->Res->palette_lru);
+    pdev->Res->num_palettes = 0;
+}
+
+/* Init anything that resides on the device memory (pci vram and devram bars).
+ * NOTE: TODO better documentation of what is on the guest ram (saved during sleep)
+ * and what is on the pci device bars (bar 0 and 1, devram and vram)
+ */
+void InitDeviceMemoryResources(PDev *pdev)
+{
+    DEBUG_PRINT((pdev, 0, "%s: %d, %d\n", __FUNCTION__, pdev->num_io_pages * PAGE_SIZE,
+        pdev->fb_size));
+    InitMspace(pdev, MSPACE_TYPE_DEVRAM, pdev->io_pages_virt, pdev->num_io_pages * PAGE_SIZE);
+    InitMspace(pdev, MSPACE_TYPE_VRAM, pdev->fb, pdev->fb_size);
+    ResetCache(pdev);
+}
+
 static void InitRes(PDev *pdev)
 {
     UINT32 i;
@@ -555,30 +606,9 @@ static void InitRes(PDev *pdev)
         PANIC(pdev, "Res cache sem creation failed\n");
     }
 
-    InitMspace(pdev, MSPACE_TYPE_DEVRAM, pdev->io_pages_virt, pdev->num_io_pages * PAGE_SIZE);
-    InitMspace(pdev, MSPACE_TYPE_VRAM, pdev->fb, pdev->fb_size);
     pdev->Res->update_id = *pdev->dev_update_id;
+    InitDeviceMemoryResources(pdev);
 
-    RtlZeroMemory(pdev->Res->image_key_lookup,
-                  sizeof(pdev->Res->image_key_lookup));
-    RtlZeroMemory(pdev->Res->cache_image_pool,
-                  sizeof(pdev->Res->cache_image_pool));
-    RingInit(&pdev->Res->cache_image_lru);
-    for (i = 0; i < IMAGE_POOL_SIZE; i++) {
-        RingAdd(pdev, &pdev->Res->cache_image_lru,
-                &pdev->Res->cache_image_pool[i].lru_link);
-    }
-
-    RtlZeroMemory(pdev->Res->image_cache, sizeof(pdev->Res->image_cache));
-    RtlZeroMemory(pdev->Res->cursor_cache, sizeof(pdev->Res->cursor_cache));
-    RingInit(&pdev->Res->cursors_lru);
-    pdev->Res->num_cursors = 0;
-    pdev->Res->last_cursor_id = 0;
-
-    RtlZeroMemory(pdev->Res->palette_cache, sizeof(pdev->Res->palette_cache));
-    RingInit(&pdev->Res->palette_lru);
-    pdev->Res->num_palettes = 0;
-    
     pdev->Res->driver = pdev->driver;
 
     ONDBG(pdev->Res->num_outputs = 0);
@@ -1599,6 +1629,18 @@ static _inline InternalPalette *PaletteCacheGet(PDev *pdev, UINT32 unique)
     return NULL;
 }
 
+static void PaletteCacheClear(PDev *pdev)
+{
+    DEBUG_PRINT((pdev, 1, "%s\n", __FUNCTION__));
+    EngAcquireSemaphore(pdev->Res->palette_cache_sem);
+    while(pdev->Res->num_palettes) {
+        ASSERT(pdev, RingGetTail(pdev, &pdev->Res->palette_lru));
+        PaletteCacheRemove(pdev, CONTAINEROF(RingGetTail(pdev, &pdev->Res->palette_lru),
+                                             InternalPalette, lru_link));
+    }
+    EngReleaseSemaphore(pdev->Res->palette_cache_sem);
+}
+
 static _inline void PaletteCacheAdd(PDev *pdev, InternalPalette *palette)
 {
     int key;
@@ -2909,6 +2951,18 @@ static void CursorCacheRemove(PDev *pdev, InternalCursor *cursor)
 
 }
 
+static void CursorCacheClear(PDev *pdev)
+{
+    DEBUG_PRINT((pdev, 1, "%s\n", __FUNCTION__));
+    EngAcquireSemaphore(pdev->Res->cursor_cache_sem);
+    while (pdev->Res->num_cursors) {
+        ASSERT(pdev, RingGetTail(pdev, &pdev->Res->cursors_lru));
+        CursorCacheRemove(pdev, CONTAINEROF(RingGetTail(pdev, &pdev->Res->cursors_lru),
+                                            InternalCursor, lru_link));
+    }
+    EngReleaseSemaphore(pdev->Res->cursor_cache_sem);
+}
+
 static void CursorCacheAdd(PDev *pdev, InternalCursor *cursor)
 {
     int key;
@@ -3325,6 +3379,13 @@ BOOL GetTransparentCursor(PDev *pdev, QXLCursorCmd *cmd)
     return TRUE;
 }
 
+void ReleaseCacheDeviceMemoryResources(PDev *pdev)
+{
+    DEBUG_PRINT((pdev, 0, "%s \n", __FUNCTION__));
+    PaletteCacheClear(pdev);
+    CursorCacheClear(pdev);
+}
+
 static void quic_usr_error(QuicUsrContext *usr, const char *format, ...)
 {
     QuicData *quic_data = (QuicData *)usr;
diff --git a/display/res.h b/display/res.h
index 769c02d..b38d5cf 100644
--- a/display/res.h
+++ b/display/res.h
@@ -70,6 +70,9 @@ void ResDestroyGlobals();
 void CheckAndSetSSE2();
 #endif
 void ResetAllDevices();
+void EmptyReleaseRing(PDev *pdev);
+void InitDeviceMemoryResources(PDev *pdev);
+void ReleaseCacheDeviceMemoryResources(PDev *pdev);
 extern DevRes **global_res;
 
 #endif
commit 8707bb1b9e42df6f1c658c156250f33b8b488ba8
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Tue Jun 7 12:37:37 2011 +0300

    display/res: make (Cursor|Palette)CacheRemove always release the object
    
    even if it is not found in the cache (which is an error)

diff --git a/display/res.c b/display/res.c
index 5045b6f..1a5e76e 100644
--- a/display/res.c
+++ b/display/res.c
@@ -1544,6 +1544,7 @@ static _inline void ReleasePalette(PDev *pdev, InternalPalette *palette)
 static _inline void PaletteCacheRemove(PDev *pdev, InternalPalette *palette)
 {
     InternalPalette **internal;
+    BOOL found = FALSE;
 
     DEBUG_PRINT((pdev, 15, "%s\n", __FUNCTION__));
 
@@ -1553,15 +1554,22 @@ static _inline void PaletteCacheRemove(PDev *pdev, InternalPalette *palette)
     while (*internal) {
         if ((*internal)->palette.unique == palette->palette.unique) {
             *internal = palette->next;
-            RingRemove(pdev, &palette->lru_link);
-            ReleasePalette(pdev, palette);
-            pdev->Res->num_palettes--;
-            DEBUG_PRINT((pdev, 16, "%s: done\n", __FUNCTION__));
-            return;
+            found = TRUE;
+            break;
         }
         internal = &(*internal)->next;
     }
-    ASSERT(pdev, FALSE);
+
+    RingRemove(pdev, &palette->lru_link);
+    ReleasePalette(pdev, palette);
+    pdev->Res->num_palettes--;
+
+    if (!found) {
+        DEBUG_PRINT((pdev, 0, "%s: Error: palette 0x%x isn't in cache \n", __FUNCTION__, palette));
+        ASSERT(pdev, FALSE);
+    } else {
+        DEBUG_PRINT((pdev, 16, "%s: done\n", __FUNCTION__));
+    }
 }
 
 static _inline InternalPalette *PaletteCacheGet(PDev *pdev, UINT32 unique)
@@ -2869,29 +2877,36 @@ typedef struct InternalCursor {
 static void CursorCacheRemove(PDev *pdev, InternalCursor *cursor)
 {
     InternalCursor **internal;
+    BOOL found = FALSE;
 
     DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
 
-    if (!cursor->unique) {
-        DEBUG_PRINT((pdev, 1, "%s: cursor not unique\n", __FUNCTION__));
-        return;
-    }
+    ASSERT(pdev, cursor->unique);
     internal = &pdev->Res->cursor_cache[CURSOR_HASH_VAL(cursor->hsurf)];
 
     while (*internal) {
         if ((*internal)->hsurf == cursor->hsurf) {
             if ((*internal) == cursor) {
                 *internal = cursor->next;
-                RingRemove(pdev, &cursor->lru_link);
-                RELEASE_RES(pdev, (Resource *)((UINT8 *)cursor - sizeof(Resource)));
-                pdev->Res->num_cursors--;
-                return;
+                found = TRUE;
+                break;
             }
             DEBUG_PRINT((pdev, 0, "%s: unexpected\n", __FUNCTION__));
         }
         internal = &(*internal)->next;
     }
-    DEBUG_PRINT((pdev, 0, "%s: Error: should not reach this\n", __FUNCTION__));
+
+    RingRemove(pdev, &cursor->lru_link);
+    RELEASE_RES(pdev, (Resource *)((UINT8 *)cursor - sizeof(Resource)));
+    pdev->Res->num_cursors--;
+
+    if (!found) {
+        DEBUG_PRINT((pdev, 0, "%s: Error: cursor 0x%x isn't in cache \n", __FUNCTION__, cursor));
+        ASSERT(pdev, FALSE);
+    } else {
+        DEBUG_PRINT((pdev, 16, "%s: done\n", __FUNCTION__));
+    }
+
 }
 
 static void CursorCacheAdd(PDev *pdev, InternalCursor *cursor)
commit c2379198bd66c95f339faa1d039cfeea4a0957ab
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Tue Jun 7 12:37:24 2011 +0300

    display/res: substitute CursorCacheRemove false "break" with "return"

diff --git a/display/res.c b/display/res.c
index d8eb957..5045b6f 100644
--- a/display/res.c
+++ b/display/res.c
@@ -2885,7 +2885,7 @@ static void CursorCacheRemove(PDev *pdev, InternalCursor *cursor)
                 RingRemove(pdev, &cursor->lru_link);
                 RELEASE_RES(pdev, (Resource *)((UINT8 *)cursor - sizeof(Resource)));
                 pdev->Res->num_cursors--;
-                break;
+                return;
             }
             DEBUG_PRINT((pdev, 0, "%s: unexpected\n", __FUNCTION__));
         }
commit 57a61e403f7e132d8a35ccf046474cb044b50747
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 15:41:20 2011 +0300

    display/*: s/FreeSurface/FreeSurfaceInfo/

diff --git a/display/driver.c b/display/driver.c
index 134692f..c19fcaa 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -1281,7 +1281,7 @@ HBITMAP APIENTRY DrvCreateDeviceBitmap(DHPDEV dhpdev, SIZEL size, ULONG format)
 
     // to optimize the failure case
 out_error2:
-    FreeSurface(pdev, surface_id);
+    FreeSurfaceInfo(pdev, surface_id);
 out_error:
     return 0;
 }
diff --git a/display/res.c b/display/res.c
index e8bff43..d8eb957 100644
--- a/display/res.c
+++ b/display/res.c
@@ -802,7 +802,7 @@ static void FreeDelSurface(PDev *pdev, Resource *res)
     default:
         PANIC(pdev, "bad allocation type");
     }
-    FreeSurface(pdev, internal->surface_id);
+    FreeSurfaceInfo(pdev, internal->surface_id);
     FreeMem(pdev, MSPACE_TYPE_DEVRAM, res);
 
     DEBUG_PRINT((pdev, 13, "%s: done\n", __FUNCTION__));
diff --git a/display/surface.h b/display/surface.h
index 608696c..977fa91 100644
--- a/display/surface.h
+++ b/display/surface.h
@@ -30,7 +30,7 @@ static _inline UINT32 GetSurfaceId(SURFOBJ *surf)
     return GetSurfaceIdFromInfo(surface);
 }
 
-static _inline void FreeSurface(PDev *pdev, UINT32 surface_id)
+static _inline void FreeSurfaceInfo(PDev *pdev, UINT32 surface_id)
 {
     SurfaceInfo *surface;
 
commit b32e503e3a025d8b7d9c3f4a3e6d9bb14cfdfcaf
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Jun 20 12:29:34 2011 +0200

    display: add a few debug prints (level=3)

diff --git a/display/driver.c b/display/driver.c
index cc5559d..134692f 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -1269,6 +1269,7 @@ HBITMAP APIENTRY DrvCreateDeviceBitmap(DHPDEV dhpdev, SIZEL size, ULONG format)
     if (!surface_id) {
         goto out_error;
     }
+    DEBUG_PRINT((pdev, 3, "%s: %p: %d\n", __FUNCTION__, pdev, surface_id));
 
     hbitmap = CreateDeviceBitmap(pdev, size, pdev->bitmap_format, &phys_mem, &base_mem, surface_id,
                                  DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
diff --git a/display/res.c b/display/res.c
index cb578e6..e8bff43 100644
--- a/display/res.c
+++ b/display/res.c
@@ -604,6 +604,7 @@ void InitResources(PDev *pdev)
     UINT32 id;
     DevRes **new_global_res;
 
+    DEBUG_PRINT((pdev, 3, "%s: entry\n", __FUNCTION__));
     RtlZeroMemory(pdev->update_trace_items, sizeof(pdev->update_trace_items));
     RingInit(&pdev->update_trace);
     for (i = 0; i < NUM_UPDATE_TRACE_ITEMS; i++) {
@@ -631,10 +632,12 @@ void InitResources(PDev *pdev)
     if (global_res[id] == NULL) {
         global_res[id] = EngAllocMem(FL_ZERO_MEMORY, sizeof(DevRes), ALLOC_TAG);
         pdev->Res = global_res[id];
+        DEBUG_PRINT((pdev, 3, "%s: calling InitRes (id == %d)\n", __FUNCTION__, id));
         InitRes(pdev);
     } else {
         pdev->Res = global_res[id];
     }
+    DEBUG_PRINT((pdev, 3, "%s: exit\n", __FUNCTION__));
     EngReleaseSemaphore(res_sem);
 }
 
commit dfcf45445921e0901c539f581c23fd64e776e66f
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Jun 20 12:29:14 2011 +0200

    display/res: fix typo in debug print

diff --git a/display/res.c b/display/res.c
index 14e1979..cb578e6 100644
--- a/display/res.c
+++ b/display/res.c
@@ -669,7 +669,7 @@ QXLDrawable *Drawable(PDev *pdev, UINT8 type, RECTL *area, CLIPOBJ *clip, UINT32
     CopyRect(&drawable->bbox, area);
 
     if (!SetClip(pdev, clip, drawable)) {
-        DEBUG_PRINT((pdev, 0, "%s: set clip filed\n", __FUNCTION__));
+        DEBUG_PRINT((pdev, 0, "%s: set clip failed\n", __FUNCTION__));
         ReleaseOutput(pdev, drawable->release_info.id);
         drawable = NULL;
     }
commit c7c64c979d281ad696f162bc5d44f8c70990d9f4
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Jun 20 12:28:35 2011 +0200

    (mp+dd) whitespace cleanup

diff --git a/display/driver.c b/display/driver.c
index fcc98bc..cc5559d 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -694,7 +694,6 @@ static BOOLEAN CreateVRamSlot(PDev *pdev)
     return TRUE;
 }
 
-
 static BOOL PrepareHardware(PDev *pdev)
 {
     VIDEO_MEMORY video_mem;
diff --git a/display/res.c b/display/res.c
index 4e0ad6c..14e1979 100644
--- a/display/res.c
+++ b/display/res.c
@@ -319,7 +319,8 @@ static void WaitForReleaseRing(PDev* pdev)
         if (SPICE_RING_IS_EMPTY(pdev->release_ring)) {
 #ifdef DBG
             DEBUG_PRINT((pdev, 0, "%s: 0x%lx: timeout\n", __FUNCTION__, pdev));
-            DEBUG_PRINT((pdev, 0, "\tfree %d out %d path %d rect %d bits %d\n",
+            DEBUG_PRINT((pdev, 0,
+                "\tfree %d out %d path %d rect %d bits %d buf %d glyph %d cursor %d\n",
                          pdev->Res->num_free_pages,
                          pdev->Res->num_outputs,
                          pdev->Res->num_path_pages,
diff --git a/miniport/qxl.c b/miniport/qxl.c
index 43b8f53..4271104 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -1090,9 +1090,9 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             driver_info->num_mem_slot = dev_ext->rom->slots_end;
             driver_info->slot_gen_bits = dev_ext->rom->slot_gen_bits;
             driver_info->slot_id_bits = dev_ext->rom->slot_id_bits;
-	    driver_info->slots_generation = &dev_ext->rom->slot_generation;
-	    driver_info->ram_slot_start = &dev_ext->ram_header->mem_slot.mem_start;
-	    driver_info->ram_slot_end = &dev_ext->ram_header->mem_slot.mem_end;
+            driver_info->slots_generation = &dev_ext->rom->slot_generation;
+            driver_info->ram_slot_start = &dev_ext->ram_header->mem_slot.mem_start;
+            driver_info->ram_slot_end = &dev_ext->ram_header->mem_slot.mem_end;
             driver_info->main_mem_slot = dev_ext->mem_slots[driver_info->main_mem_slot_id];
 
 #if (WINVER < 0x0501)
commit 76f338fd7bb09c8da8a56b425a11d0d1408e5695
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 15:27:57 2011 +0300

    driver/res: add debugging prints of released resources types

diff --git a/display/res.c b/display/res.c
index d6b8f34..4e0ad6c 100644
--- a/display/res.c
+++ b/display/res.c
@@ -19,6 +19,9 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+#ifdef DBG
+#include <stdio.h>
+#endif
 #include <ddraw.h>
 #include <dxmini.h>
 #include "qxldd.h"
@@ -58,9 +61,33 @@ static _inline UINT64 VA(PDev *pdev, QXLPHYSICAL paddr, UINT8 slot_id)
 #define RELEASE_RES(pdev, res) if (!--(res)->refs) (res)->free(pdev, res);
 #define GET_RES(res) (++(res)->refs)
 
+/* Debug helpers - tag each resource with this enum */
+enum {
+    RESOURCE_TYPE_DRAWABLE = 1,
+    RESOURCE_TYPE_SURFACE,
+    RESOURCE_TYPE_PATH,
+    RESOURCE_TYPE_CLIP_RECTS,
+    RESOURCE_TYPE_QUIC_IMAGE,
+    RESOURCE_TYPE_BITMAP_IMAGE,
+    RESOURCE_TYPE_SURFACE_IMAGE,
+    RESOURCE_TYPE_SRING,
+    RESOURCE_TYPE_CURSOR,
+    RESOURCE_TYPE_BUF,
+    RESOURCE_TYPE_UPDATE,
+};
+
+#ifdef DBG
+#define RESOURCE_TYPE(res, val) do { res->type = val; } while (0)
+#else
+#define RESOURCE_TYPE(res, val)
+#endif
+
 typedef struct Resource Resource;
 struct Resource {
     UINT32 refs;
+#ifdef DBG
+    UINT32 type;
+#endif
     void (*free)(PDev *pdev, Resource *res);
     UINT8 res[0];
 };
@@ -90,12 +117,57 @@ static BOOL SetClip(PDev *pdev, CLIPOBJ *clip, QXLDrawable *drawable);
 
 typedef struct QXLOutput {
     UINT32 num_res;
+#ifdef DBG
+    UINT32 type;
+#endif
     Resource *resources[MAX_OUTPUT_RES];
     UINT8 data[0];
 } QXLOutput;
 
 static int have_sse2 = FALSE;
 
+#ifndef DBG
+static _inline void DebugShowOutput(PDev *pdev, QXLOutput* output)
+{
+}
+#else
+const char* resource_type_to_string(QXLOutput *output, UINT32 type)
+{
+    static char buf[1024];
+
+    switch (type) {
+    case 0: return "UNSET";
+    case RESOURCE_TYPE_DRAWABLE: return "drawable";
+    case RESOURCE_TYPE_SURFACE: {
+        QXLSurfaceCmd *surface_cmd = (QXLSurfaceCmd*)output->data;
+        _snprintf(buf, sizeof(buf) - 1, "surface %u", surface_cmd->surface_id);
+        return buf;
+    }
+    case RESOURCE_TYPE_PATH: return "path";
+    case RESOURCE_TYPE_CLIP_RECTS: return "clip_rects";
+    case RESOURCE_TYPE_QUIC_IMAGE: return "quic_image";
+    case RESOURCE_TYPE_BITMAP_IMAGE: return "bitmap_image";
+    case RESOURCE_TYPE_SURFACE_IMAGE: return "surface_image";
+    case RESOURCE_TYPE_SRING: return "sring";
+    case RESOURCE_TYPE_CURSOR: return "cursor";
+    case RESOURCE_TYPE_BUF: return "buf";
+    case RESOURCE_TYPE_UPDATE: return "update";
+    }
+    return "UNDEFINED";
+}
+
+static void DebugShowOutput(PDev *pdev, QXLOutput* output)
+{
+    UINT32 i;
+
+    DEBUG_PRINT((pdev, 11, "output: %s res %d\n", resource_type_to_string(output, output->type),
+                output->num_res));
+    for (i = 0 ; i < output->num_res ; ++i) {
+        DEBUG_PRINT((pdev, 11, "type %s\n", resource_type_to_string(output,
+            output->resources[i]->type)));
+    }
+}
+#endif
 
 UINT64 ReleaseOutput(PDev *pdev, UINT64 output_id)
 {
@@ -106,6 +178,7 @@ UINT64 ReleaseOutput(PDev *pdev, UINT64 output_id)
 
     ASSERT(pdev, output_id);
     DEBUG_PRINT((pdev, 9, "%s 0x%x\n", __FUNCTION__, output));
+    DebugShowOutput(pdev, output);
 
     for (now = output->resources, end = now + output->num_res; now < end; now++) {
         RELEASE_RES(pdev, *now);
@@ -570,6 +643,7 @@ static QXLDrawable *GetDrawable(PDev *pdev)
 
     output = (QXLOutput *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(QXLOutput) + sizeof(QXLDrawable));
     output->num_res = 0;
+    RESOURCE_TYPE(output, RESOURCE_TYPE_DRAWABLE);
     ((QXLDrawable *)output->data)->release_info.id = (UINT64)output;
     DEBUG_PRINT((pdev, 9, "%s 0x%x\n", __FUNCTION__, output));
     ONDBG(pdev->Res->num_outputs++); //todo: atomic
@@ -620,6 +694,7 @@ static QXLSurfaceCmd *GetSurfaceCmd(PDev *pdev)
 
     output = (QXLOutput *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(QXLOutput) + sizeof(QXLSurfaceCmd));
     output->num_res = 0;
+    RESOURCE_TYPE(output, RESOURCE_TYPE_SURFACE);
     ((QXLSurfaceCmd *)output->data)->release_info.id = (UINT64)output;
     DEBUG_PRINT((pdev, 9, "%s 0x%x\n", __FUNCTION__, output));
     ONDBG(pdev->Res->num_outputs++); //todo: atomic
@@ -744,6 +819,7 @@ void QXLGetDelSurface(PDev *pdev, QXLSurfaceCmd *surface, UINT32 surface_id, UIN
     
     surface_res->refs = 1;
     surface_res->free = FreeDelSurface;
+    RESOURCE_TYPE(surface_res, RESOURCE_TYPE_SURFACE);
 
     internal = (InternalDelSurface *)surface_res->res;
     internal->surface_id = surface_id;
@@ -874,6 +950,7 @@ static Resource *__GetPath(PDev *pdev, PATHOBJ *path)
     ONDBG(pdev->Res->num_path_pages++);
     res->refs = 1;
     res->free = FreePath;
+    RESOURCE_TYPE(res, RESOURCE_TYPE_PATH);
 
     qxl_path = (QXLPath *)res->res;
     qxl_path->data_size = 0;
@@ -946,6 +1023,7 @@ static Resource *GetClipRects(PDev *pdev, CLIPOBJ *clip)
     ONDBG(pdev->Res->num_rects_pages++);
     res->refs = 1;
     res->free = FreeClipRects;
+    RESOURCE_TYPE(res, RESOURCE_TYPE_CLIP_RECTS);
     rects = (QXLClipRects *)res->res;
     rects->num_rects = 0;
 
@@ -1006,6 +1084,7 @@ static BOOL SetClip(PDev *pdev, CLIPOBJ *clip, QXLDrawable *drawable)
                                          sizeof(QXLRect));
         rects_res->refs = 1;
         rects_res->free = FreeClipRects;
+        RESOURCE_TYPE(rects_res, RESOURCE_TYPE_CLIP_RECTS);
         rects = (QXLClipRects *)rects_res->res;
         rects->num_rects = 1;
         rects->chunk.data_size = sizeof(QXLRect);
@@ -1695,6 +1774,7 @@ static _inline Resource *GetQuicImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *color
     ONDBG(pdev->Res->num_bits_pages++);
     image_res->refs = 1;
     image_res->free = FreeQuicImage;
+    RESOURCE_TYPE(image_res, RESOURCE_TYPE_QUIC_IMAGE);
 
     internal = (InternalImage *)image_res->res;
     SetImageId(internal, cache_me, width, height, format, key);
@@ -1837,6 +1917,7 @@ static _inline Resource *GetBitmapImage(PDev *pdev, SURFOBJ *surf, XLATEOBJ *col
 
     image_res->refs = 1;
     image_res->free = FreeBitmapImage;
+    RESOURCE_TYPE(image_res, RESOURCE_TYPE_BITMAP_IMAGE);
 
     internal = (InternalImage *)image_res->res;
     SetImageId(internal, cache_me, width, height, format, key);
@@ -2147,6 +2228,7 @@ BOOL QXLGetBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phys, SU
         ONDBG(pdev->Res->num_bits_pages++);
         image_res->refs = 1;
         image_res->free = FreeSurfaceImage;
+        RESOURCE_TYPE(image_res, RESOURCE_TYPE_SURFACE_IMAGE);
 
         internal = (InternalImage *)image_res->res;
 
@@ -2313,6 +2395,7 @@ BOOL QXLGetAlphaBitmap(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *image_phy
         ONDBG(pdev->Res->num_bits_pages++);
         image_res->refs = 1;
         image_res->free = FreeSurfaceImage;
+        RESOURCE_TYPE(image_res, RESOURCE_TYPE_SURFACE_IMAGE);
 
         internal = (InternalImage *)image_res->res;
 
@@ -2477,6 +2560,7 @@ UINT8 *QXLGetBuf(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *buf_phys, UINT3
     ONDBG(pdev->Res->num_buf_pages++);
     buf_res->refs = 1;
     buf_res->free = FreeBuf;
+    RESOURCE_TYPE(buf_res, RESOURCE_TYPE_BUF);
 
     *buf_phys = PA(pdev, buf_res->res, pdev->main_mem_slot);
     DrawableAddRes(pdev, drawable, buf_res);
@@ -2494,6 +2578,7 @@ void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id)
     DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
 
     output = (QXLOutput *)AllocMem(pdev, sizeof(QXLOutput) + sizeof(QXLUpdateCmd));
+    RESOURCE_TYPE(output, RESOURCE_TYPE_UPDATE);
     output->num_res = 0;
     updat_cmd = (QXLUpdateCmd *)output->data;
     updat_cmd->release_info.id = (UINT64)output;
@@ -2663,6 +2748,7 @@ BOOL QXLGetStr(PDev *pdev, QXLDrawable *drawable, QXLPHYSICAL *str_phys, FONTOBJ
     ONDBG(pdev->Res->num_glyphs_pages++);
     str_res->refs = 1;
     str_res->free = FreeSring;
+    RESOURCE_TYPE(str_res, RESOURCE_TYPE_SRING);
 
     qxl_str = (QXLString *)str_res->res;
     qxl_str->data_size = 0;
@@ -2741,6 +2827,7 @@ QXLCursorCmd *CursorCmd(PDev *pdev)
 
     output = (QXLOutput *)AllocMem(pdev, MSPACE_TYPE_DEVRAM, sizeof(QXLOutput) + sizeof(QXLCursorCmd));
     output->num_res = 0;
+    RESOURCE_TYPE(output, RESOURCE_TYPE_CURSOR);
     cursor_cmd = (QXLCursorCmd *)output->data;
     cursor_cmd->release_info.id = (UINT64)output;
     ONDBG(pdev->Res->num_outputs++); //todo: atomic
@@ -2956,6 +3043,7 @@ static BOOL GetCursorCommon(PDev *pdev, QXLCursorCmd *cmd, LONG hot_x, LONG hot_
     ONDBG(pdev->Res->num_cursor_pages++);
     res->refs = 1;
     res->free = FreeCursor;
+    RESOURCE_TYPE(res, RESOURCE_TYPE_CURSOR);
 
     internal = (InternalCursor *)res->res;
     internal->hsurf = surf->hsurf;
@@ -3193,6 +3281,7 @@ BOOL GetTransparentCursor(PDev *pdev, QXLCursorCmd *cmd)
     ONDBG(pdev->Res->num_cursor_pages++);
     res->refs = 1;
     res->free = FreeCursor;
+    RESOURCE_TYPE(res, RESOURCE_TYPE_CURSOR);
 
     internal = (InternalCursor *)res->res;
     internal->hsurf = NULL;
commit a72eacc87f017a5489aea158011c85b6276bab7f
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 14:44:57 2011 +0300

    display/driver: DisableQXLPrimarySurface: add hide_mouse parameter (reused in DrvAssertModeDisable later)
    
    Cc: Yonit Halperin <yhalperi at redhat.com>

diff --git a/display/driver.c b/display/driver.c
index d1de1ef..fcc98bc 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -605,9 +605,11 @@ static VOID CreatePrimarySurface(PDev *pdev, UINT32 depth, UINT32 format,
     async_io(pdev, ASYNCABLE_CREATE_PRIMARY, 0);
 }
 
-static void DestroyPrimarySurface(PDev *pdev)
+static void DestroyPrimarySurface(PDev *pdev, int hide_mouse)
 {
-    HideMouse(pdev);
+    if (hide_mouse) {
+        HideMouse(pdev);
+    }
     async_io(pdev, ASYNCABLE_DESTROY_PRIMARY, 0);
 }
 
@@ -913,12 +915,12 @@ err:
     return NULL;
 }
 
-VOID DisableQXLPrimarySurface(PDev *pdev)
+VOID DisableQXLPrimarySurface(PDev *pdev, int hide_mouse)
 {
     DrawArea drawarea;
 
     if (pdev->surf_enable) {
-        DestroyPrimarySurface(pdev);
+        DestroyPrimarySurface(pdev, hide_mouse);
         pdev->surf_enable = FALSE;
     }
 }
@@ -935,8 +937,7 @@ VOID DrvDisableSurface(DHPDEV in_pdev)
 
     DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
 
-    DisableQXLPrimarySurface(pdev);
-
+    DisableQXLPrimarySurface(pdev, 1 /* hide mouse */);
     UnmapFB(pdev);
 
     if (pdev->surf) {
@@ -964,7 +965,7 @@ BOOL DrvAssertMode(DHPDEV in_pdev, BOOL enable)
         EnableQXLPrimarySurface(pdev);
         CreateVRamSlot(pdev);
     } else {
-        DisableQXLPrimarySurface(pdev);
+        DisableQXLPrimarySurface(pdev, 0);
         RemoveVRamSlot(pdev);
     }
     DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit %d\n", __FUNCTION__, pdev, enable));
commit b0f964447ef4be65a14f3b051f2fd0be87f19388
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 14:43:57 2011 +0300

    display/*: add debug helpers DUMP_VRAM_MSPACE and DUMP_DEVRAM_MSPACE
    
    changes the passed user pointer to mspace from NULL to a proper pdev, so
    it will be able to print using QXL_IO_LOG.

diff --git a/display/qxldd.h b/display/qxldd.h
index 36df21f..92d1ae8 100644
--- a/display/qxldd.h
+++ b/display/qxldd.h
@@ -461,4 +461,29 @@ static _inline void sync_io(PDev *pdev, PUCHAR port, UCHAR val)
     EngReleaseSemaphore(pdev->io_sem);
 }
 
+#ifdef DBG
+#define DUMP_VRAM_MSPACE(pdev) \
+    do { \
+        DEBUG_PRINT((pdev, 0, "%s: dumping mspace vram (%p, %p)\n", __FUNCTION__, pdev, global_res ? global_res[pdev->dev_id] : NULL)); \
+        if (pdev && global_res && global_res[pdev->dev_id]) {  \
+            mspace_malloc_stats(global_res[pdev->dev_id]->mspaces[MSPACE_TYPE_VRAM]._mspace); \
+        } else { \
+            DEBUG_PRINT((pdev, 0, "nothing\n")); \
+        }\
+    } while (0)
+
+#define DUMP_DEVRAM_MSPACE(pdev) \
+    do { \
+        DEBUG_PRINT((pdev, 0, "%s: dumping mspace devram (%p, %p)\n", __FUNCTION__, pdev, global_res ? global_res[pdev->dev_id] : NULL)); \
+        if (pdev && global_res && global_res[pdev->dev_id]) {  \
+            mspace_malloc_stats(global_res[pdev->dev_id]->mspaces[MSPACE_TYPE_DEVRAM]._mspace); \
+        } else { \
+            DEBUG_PRINT((pdev, 0, "nothing\n")); \
+        }\
+    } while (0)
+#else
+#define DUMP_VRAM_MSPACE
+#define DUMP_DEVRAM_MSPACE
+#endif
+
 #endif
diff --git a/display/res.c b/display/res.c
index abda771..d6b8f34 100644
--- a/display/res.c
+++ b/display/res.c
@@ -423,11 +423,13 @@ void InitGlobalRes()
     }
 }
 
-static void InitMspace(DevRes *res, UINT32 mspace_type, UINT8 *io_pages_virt, size_t capacity)
+static void InitMspace(PDev *pdev, UINT32 mspace_type, UINT8 *start, size_t capacity)
 {
-    res->mspaces[mspace_type]._mspace = create_mspace_with_base(io_pages_virt, capacity, 0, NULL);
-    res->mspaces[mspace_type].mspace_start = io_pages_virt;
-    res->mspaces[mspace_type].mspace_end = io_pages_virt + capacity;
+    DevRes *res = pdev->Res;
+
+    res->mspaces[mspace_type]._mspace = create_mspace_with_base(start, capacity, 0, pdev);
+    res->mspaces[mspace_type].mspace_start = start;
+    res->mspaces[mspace_type].mspace_end = start + capacity;
 }
 
 static void InitRes(PDev *pdev)
@@ -479,8 +481,8 @@ static void InitRes(PDev *pdev)
         PANIC(pdev, "Res cache sem creation failed\n");
     }
 
-    InitMspace(pdev->Res, MSPACE_TYPE_DEVRAM, pdev->io_pages_virt, pdev->num_io_pages * PAGE_SIZE);
-    InitMspace(pdev->Res, MSPACE_TYPE_VRAM, pdev->fb, pdev->fb_size);
+    InitMspace(pdev, MSPACE_TYPE_DEVRAM, pdev->io_pages_virt, pdev->num_io_pages * PAGE_SIZE);
+    InitMspace(pdev, MSPACE_TYPE_VRAM, pdev->fb, pdev->fb_size);
     pdev->Res->update_id = *pdev->dev_update_id;
 
     RtlZeroMemory(pdev->Res->image_key_lookup,
diff --git a/display/res.h b/display/res.h
index ae4ad14..769c02d 100644
--- a/display/res.h
+++ b/display/res.h
@@ -70,5 +70,6 @@ void ResDestroyGlobals();
 void CheckAndSetSSE2();
 #endif
 void ResetAllDevices();
+extern DevRes **global_res;
 
 #endif
commit f3774dbad9f6a9926de8d7834f86fb29e9caa906
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 14:07:40 2011 +0300

    display/driver: add DebugCountAliveSurfaces
    
    Disabled if no DBG, and uses loglevel == 1

diff --git a/display/driver.c b/display/driver.c
index 9705a3c..d1de1ef 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -528,11 +528,42 @@ err1:
     return NULL;
 }
 
+#ifdef DBG
+static void DebugCountAliveSurfaces(PDev *pdev)
+{
+    UINT32 i;
+    SurfaceInfo *surface_info;
+    int total = 0;
+    int of_pdev = 0;
+    int no_surf_obj = 0;
+
+    for (i = 0 ; i < pdev->n_surfaces; ++i) {
+        surface_info = GetSurfaceInfo(pdev, i);
+        if (surface_info->draw_area.base_mem != NULL) {
+            total++;
+            if (surface_info->u.pdev == pdev) {
+                of_pdev++;
+                if (surface_info->draw_area.surf_obj == NULL) {
+                    no_surf_obj++;
+                }
+            }
+        }
+    }
+    DEBUG_PRINT((pdev, 1, "%s: %p: %d / %d / %d (total,pdev,no_surf_obj)\n", __FUNCTION__, pdev,
+                total, of_pdev, no_surf_obj));
+}
+#else
+static void DebugCountAliveSurfaces(PDev *pdev)
+{
+}
+#endif
+
 VOID DrvDisablePDEV(DHPDEV in_pdev)
 {
     PDev* pdev = (PDev*)in_pdev;
 
     DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+    DebugCountAliveSurfaces(pdev);
     ResDestroy(pdev);
     DestroyPalette(pdev);
     EngFreeMem(pdev);
commit ca4bd8b1038ec863a50e57761eed3ca920b981a8
Author: Alon Levy <alevy at redhat.com>
Date:   Thu May 26 14:27:11 2011 +0300

    display/{driver,surface}: use pdev in some DEBUG_PRINTs

diff --git a/display/driver.c b/display/driver.c
index 24adb0b..9705a3c 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -532,7 +532,7 @@ VOID DrvDisablePDEV(DHPDEV in_pdev)
 {
     PDev* pdev = (PDev*)in_pdev;
 
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
     ResDestroy(pdev);
     DestroyPalette(pdev);
     EngFreeMem(pdev);
@@ -670,21 +670,21 @@ static BOOL PrepareHardware(PDev *pdev)
     QXLDriverInfo dev_info;
     QXLPHYSICAL high_bits;
 
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
 
     if (!SetHardwareMode(pdev)) {
-        DEBUG_PRINT((NULL, 0, "%s: set mode failed, 0x%lx\n", __FUNCTION__, pdev));
+        DEBUG_PRINT((pdev, 0, "%s: set mode failed, 0x%lx\n", __FUNCTION__, pdev));
         return FALSE;
     }
 
     if (EngDeviceIoControl( pdev->driver, IOCTL_QXL_GET_INFO, NULL,
                             0, &dev_info, sizeof(QXLDriverInfo), &length) ) {
-        DEBUG_PRINT((NULL, 0, "%s: get qxl info failed, 0x%lx\n", __FUNCTION__, pdev));
+        DEBUG_PRINT((pdev, 0, "%s: get qxl info failed, 0x%lx\n", __FUNCTION__, pdev));
         return FALSE;
     }
 
     if (dev_info.version != QXL_DRIVER_INFO_VERSION) {
-        DEBUG_PRINT((NULL, 0, "%s: get qxl info mismatch, 0x%lx\n", __FUNCTION__, pdev));
+        DEBUG_PRINT((pdev, 0, "%s: get qxl info mismatch, 0x%lx\n", __FUNCTION__, pdev));
         return FALSE;
     }
 
@@ -741,7 +741,7 @@ static BOOL PrepareHardware(PDev *pdev)
     pdev->mem_slots = EngAllocMem(FL_ZERO_MEMORY, sizeof(PMemSlot) * dev_info.num_mem_slot,
                                   ALLOC_TAG);
     if (!pdev->mem_slots) {
-        DEBUG_PRINT((NULL, 0, "%s: mem slots alloc failed, 0x%lx\n", __FUNCTION__, pdev));
+        DEBUG_PRINT((pdev, 0, "%s: mem slots alloc failed, 0x%lx\n", __FUNCTION__, pdev));
         return FALSE;
     }
 
@@ -760,10 +760,10 @@ static BOOL PrepareHardware(PDev *pdev)
     if (EngDeviceIoControl( pdev->driver, IOCTL_VIDEO_MAP_VIDEO_MEMORY, &video_mem,
                             sizeof(VIDEO_MEMORY), &video_mem_Info,
                             sizeof(video_mem_Info), &length) ) {
-        DEBUG_PRINT((NULL, 0, "%s: mapping failed, 0x%lx\n", __FUNCTION__, pdev));
+        DEBUG_PRINT((pdev, 0, "%s: mapping failed, 0x%lx\n", __FUNCTION__, pdev));
         return FALSE;
     }
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx vals 0x%lx %ul\n", __FUNCTION__, pdev,
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx vals 0x%lx %ul\n", __FUNCTION__, pdev,
                  video_mem_Info.FrameBufferBase, video_mem_Info.FrameBufferLength));
     pdev->fb = (BYTE*)video_mem_Info.FrameBufferBase;
     pdev->fb_size = video_mem_Info.FrameBufferLength;
@@ -843,9 +843,9 @@ HSURF DrvEnableSurface(DHPDEV in_pdev)
     QXLPHYSICAL phys_mem;
     UINT8 *base_mem;
 
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, in_pdev));
-
     pdev = (PDev*)in_pdev;
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, in_pdev));
+
     if (!PrepareHardware(pdev)) {
         return FALSE;
     }
@@ -853,12 +853,12 @@ HSURF DrvEnableSurface(DHPDEV in_pdev)
 
     if (!(surf = (HSURF)CreateDeviceBitmap(pdev, pdev->resolution, pdev->bitmap_format, &phys_mem,
                                            &base_mem, 0, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0))) {
-        DEBUG_PRINT((NULL, 0, "%s: create device surface failed, 0x%lx\n",
+        DEBUG_PRINT((pdev, 0, "%s: create device surface failed, 0x%lx\n",
                      __FUNCTION__, pdev));
         goto err;
     }
 
-    DEBUG_PRINT((NULL, 1, "%s: EngModifySurface(0x%lx, 0x%lx, 0, MS_NOTSYSTEMMEMORY, "
+    DEBUG_PRINT((pdev, 1, "%s: EngModifySurface(0x%lx, 0x%lx, 0, MS_NOTSYSTEMMEMORY, "
                  "0x%lx, 0x%lx, %lu, NULL)\n",
                  __FUNCTION__,
                  surf,
@@ -873,12 +873,12 @@ HSURF DrvEnableSurface(DHPDEV in_pdev)
 
     EnableQXLPrimarySurface(pdev);
 
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
     return surf;
 
 err:
     DrvDisableSurface((DHPDEV)pdev);
-    DEBUG_PRINT((NULL, 0, "%s: 0x%lx err\n", __FUNCTION__, pdev));
+    DEBUG_PRINT((pdev, 0, "%s: 0x%lx err\n", __FUNCTION__, pdev));
     return NULL;
 }
 
@@ -902,7 +902,7 @@ VOID DrvDisableSurface(DHPDEV in_pdev)
     PDev *pdev = (PDev*)in_pdev;
     DrawArea drawarea;
 
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
 
     DisableQXLPrimarySurface(pdev);
 
@@ -926,7 +926,8 @@ BOOL DrvAssertMode(DHPDEV in_pdev, BOOL enable)
 {
     PDev* pdev = (PDev*)in_pdev;
 
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx %d\n", __FUNCTION__, pdev, enable));
+
     if (enable) {
         InitResources(pdev);
         EnableQXLPrimarySurface(pdev);
@@ -935,7 +936,7 @@ BOOL DrvAssertMode(DHPDEV in_pdev, BOOL enable)
         DisableQXLPrimarySurface(pdev);
         RemoveVRamSlot(pdev);
     }
-    DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit TRUE\n", __FUNCTION__, pdev));
+    DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit %d\n", __FUNCTION__, pdev, enable));
     return TRUE;
 }
 
diff --git a/display/surface.c b/display/surface.c
index 4458bc6..61c898f 100644
--- a/display/surface.c
+++ b/display/surface.c
@@ -105,8 +105,8 @@ HBITMAP CreateDeviceBitmap(PDev *pdev, SIZEL size, ULONG format, QXLPHYSICAL *ph
     };
 
     if (!(surf = EngCreateDeviceBitmap((DHSURF)GetSurfaceInfo(pdev, surface_id), size, format))) {
-        DEBUG_PRINT((NULL, 0, "%s: create device surface failed, 0x%lx\n",
-                     __FUNCTION__, pdev));
+        DEBUG_PRINT((pdev, 0, "%s: EngCreateDeviceBitmap failed, pdev 0x%lx, surface_id=%d\n",
+                    __FUNCTION__, pdev, surface_id));
         goto out_error1;
     }
 
commit ee23f61e23ffdcc894f60c329b8f8a041c65df47
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jun 2 13:41:18 2011 +0300

    display/mspace: fix mspace_max_footprint and mspace_footprint

diff --git a/display/mspace.c b/display/mspace.c
index ec29fc6..d0ba123 100644
--- a/display/mspace.c
+++ b/display/mspace.c
@@ -2402,8 +2402,9 @@ size_t mspace_footprint(mspace msp) {
   mstate ms = (mstate)msp;
   if (ok_magic(ms)) {
     result = ms->footprint;
+  } else {
+    USAGE_ERROR_ACTION(ms,ms);
   }
-  USAGE_ERROR_ACTION(ms,ms);
   return result;
 }
 
@@ -2413,8 +2414,9 @@ size_t mspace_max_footprint(mspace msp) {
   mstate ms = (mstate)msp;
   if (ok_magic(ms)) {
     result = ms->max_footprint;
+  } else {
+    USAGE_ERROR_ACTION(ms,ms);
   }
-  USAGE_ERROR_ACTION(ms,ms);
   return result;
 }
 
commit 718a7be5503b9225a000d814b82a92058691b13b
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jun 15 16:02:39 2011 +0200

    miniport/qxl: raise loglevel for mode prints

diff --git a/miniport/qxl.c b/miniport/qxl.c
index e4b6804..43b8f53 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -428,7 +428,7 @@ VP_STATUS SetVideoModeInfo(QXLExtension *dev, PVIDEO_MODE_INFORMATION video_mode
 {
     ULONG color_bits;
     PAGED_CODE();
-    DEBUG_PRINT((dev, 0, "%s: x %u y %u bits %u stride %u orientation %u\n",
+    DEBUG_PRINT((dev, 5, "%s: x %u y %u bits %u stride %u orientation %u\n",
                  __FUNCTION__, qxl_mode->x_res, qxl_mode->y_res,
                  qxl_mode->bits, qxl_mode->stride, qxl_mode->orientation));
 
@@ -455,7 +455,7 @@ VP_STATUS SetVideoModeInfo(QXLExtension *dev, PVIDEO_MODE_INFORMATION video_mode
     video_mode->VideoMemoryBitmapWidth = qxl_mode->x_res;
     video_mode->VideoMemoryBitmapHeight = qxl_mode->y_res;
     video_mode->DriverSpecificAttributeFlags = qxl_mode->orientation;
-    DEBUG_PRINT((dev, 0, "%s OK\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 5, "%s OK\n", __FUNCTION__));
     return NO_ERROR;
 }
 
commit addc55ec77beb25a662c16190f804e5d060a19e1
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jun 15 16:18:08 2011 +0200

    miniport/qxl: SetVideoModeInfo: pass QXLExtension for debug prints

diff --git a/miniport/qxl.c b/miniport/qxl.c
index 800a3b0..e4b6804 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -420,11 +420,11 @@ VP_STATUS Prob(QXLExtension *dev, VIDEO_PORT_CONFIG_INFO *conf_info,
 }
 
 #if defined(ALLOC_PRAGMA)
-VP_STATUS SetVideoModeInfo(PVIDEO_MODE_INFORMATION video_mode, QXLMode *qxl_mode);
+VP_STATUS SetVideoModeInfo(QXLExtension *dev, PVIDEO_MODE_INFORMATION video_mode, QXLMode *qxl_mode);
 #pragma alloc_text(PAGE, SetVideoModeInfo)
 #endif
 
-VP_STATUS SetVideoModeInfo(PVIDEO_MODE_INFORMATION video_mode, QXLMode *qxl_mode)
+VP_STATUS SetVideoModeInfo(QXLExtension *dev, PVIDEO_MODE_INFORMATION video_mode, QXLMode *qxl_mode)
 {
     ULONG color_bits;
     PAGED_CODE();
@@ -530,7 +530,7 @@ VP_STATUS InitModes(QXLExtension *dev)
 #endif
     VideoPortZeroMemory(modes_info, sizeof(VIDEO_MODE_INFORMATION) * n_modes);
     for (i = 0; i < n_modes; i++) {
-        error = SetVideoModeInfo(&modes_info[i], &modes->modes[i]);
+        error = SetVideoModeInfo(dev, &modes_info[i], &modes->modes[i]);
         if (error != NO_ERROR) {
             VideoPortFreePool(dev, modes_info);
             DEBUG_PRINT((dev, 0, "%s: set video mode failed\n", __FUNCTION__));
commit d452c9494e6b0c15fcb137b06ce3bb946f7db85a
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Jun 6 12:24:20 2011 +0300

    miniport/qxl: disable DBG zap of video ram on map

diff --git a/miniport/qxl.c b/miniport/qxl.c
index 8340b72..800a3b0 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -1003,11 +1003,13 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             }
             mem_info->FrameBufferBase = mem_info->VideoRamBase;
             mem_info->FrameBufferLength = mem_info->VideoRamLength;
+#if 0
 #ifdef DBG
             DEBUG_PRINT((dev, 0, "%s: zap\n", __FUNCTION__));
             VideoPortZeroMemory(mem_info->VideoRamBase, mem_info->VideoRamLength);
             DEBUG_PRINT((dev, 0, "%s: zap done\n", __FUNCTION__));
 #endif
+#endif
         }
         break;
     case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY: {
commit 30321590878bb00368e4e1c7c7dbaa417dcd38c8
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jun 15 16:18:56 2011 +0200

    miniport: pass dev as first parameter of DEBUG_PRINT instead of 0

diff --git a/miniport/qxl.c b/miniport/qxl.c
index 4161282..8340b72 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -142,7 +142,7 @@ ULONG DriverEntry(PVOID context1, PVOID context2)
 
     PAGED_CODE();
 
-    DEBUG_PRINT((0, "%s: enter\n", __FUNCTION__));
+    DEBUG_PRINT((NULL, 0, "%s: enter\n", __FUNCTION__));
 
     VideoPortZeroMemory(&init_data, sizeof(VIDEO_HW_INITIALIZATION_DATA));
     init_data.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
@@ -159,11 +159,11 @@ ULONG DriverEntry(PVOID context1, PVOID context2)
     ret = VideoPortInitialize(context1, context2, &init_data, NULL);
 
     if (ret != NO_ERROR) {
-        DEBUG_PRINT((0, "%s: try W2K %u\n", __FUNCTION__, ret));
+        DEBUG_PRINT((NULL, 0, "%s: try W2K %u\n", __FUNCTION__, ret));
         init_data.HwInitDataSize = SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA;
         ret = VideoPortInitialize(context1, context2, &init_data, NULL);
     }
-    DEBUG_PRINT((0, "%s: exit %u\n", __FUNCTION__, ret));
+    DEBUG_PRINT((NULL, 0, "%s: exit %u\n", __FUNCTION__, ret));
     return ret;
 }
 
@@ -178,11 +178,11 @@ VP_STATUS InitIO(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
     PVOID io_base;
 
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
 
     if (range->RangeLength < QXL_IO_RANGE_SIZE
         || !range->RangeInIoSpace) {
-        DEBUG_PRINT((0, "%s: bad io range\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: bad io range\n", __FUNCTION__));
         return ERROR_INVALID_DATA;
     }
 
@@ -190,7 +190,7 @@ VP_STATUS InitIO(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
                                      range->RangeInIoSpace);
 
     if (!io_base) {
-        DEBUG_PRINT((0, "%s: get io base failed\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: get io base failed\n", __FUNCTION__));
         return ERROR_NOT_ENOUGH_MEMORY;
     }
 
@@ -216,40 +216,40 @@ VP_STATUS InitRom(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
     VP_STATUS error;
 
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
 
     if (rom_size < sizeof(QXLRom) || range->RangeInIoSpace) {
-        DEBUG_PRINT((0, "%s: bad rom range\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: bad rom range\n", __FUNCTION__));
         return ERROR_INVALID_DATA;
     }
     if ((error = VideoPortMapMemory(dev, range->RangeStart,
                                     &rom_size, &io_space,
                                     &rom)) != NO_ERROR ) {
-        DEBUG_PRINT((0, "%s: map rom filed\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: map rom filed\n", __FUNCTION__));
         return error;
     }
 
     if (rom_size < range->RangeLength) {
-        DEBUG_PRINT((0, "%s: short rom map\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: short rom map\n", __FUNCTION__));
         error = ERROR_NOT_ENOUGH_MEMORY;
         goto err;
     }
 
     if (((QXLRom*)rom)->magic != QXL_ROM_MAGIC) {
-        DEBUG_PRINT((0, "%s: bad rom magic\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: bad rom magic\n", __FUNCTION__));
         error = ERROR_INVALID_DATA;
         goto err;
     }
 
     dev->rom = rom;
     dev->rom_size = range->RangeLength;
-    DEBUG_PRINT((0, "%s OK: rom 0x%lx size %lu\n",
+    DEBUG_PRINT((dev, 0, "%s OK: rom 0x%lx size %lu\n",
                  __FUNCTION__, (ULONG)range->RangeStart.QuadPart, range->RangeLength));
     return NO_ERROR;
 
 err:
     VideoPortUnmapMemory(dev, rom, NULL);
-    DEBUG_PRINT((0, "%s ERR\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 0, "%s ERR\n", __FUNCTION__));
     return error;
 }
 
@@ -267,33 +267,33 @@ VP_STATUS InitRam(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
     VP_STATUS error;
 
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
 
     if (ram_size < sizeof(QXLRam) + dev->rom->ram_header_offset || range->RangeInIoSpace) {
-        DEBUG_PRINT((0, "%s: bad ram range\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: bad ram range\n", __FUNCTION__));
         return ERROR_INVALID_DATA;
     }
 
     if (ram_size < dev->rom->num_pages << PAGE_SHIFT) {
-        DEBUG_PRINT((0, "%s: bad ram size\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: bad ram size\n", __FUNCTION__));
         return ERROR_INVALID_DATA;
     }
 
     if ((error = VideoPortMapMemory(dev, range->RangeStart,
                                     &ram_size, &io_space,
                                     &ram)) != NO_ERROR ) {
-        DEBUG_PRINT((0, "%s: map ram filed\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: map ram filed\n", __FUNCTION__));
         return error;
     }
 
     if (ram_size < range->RangeLength) {
-        DEBUG_PRINT((0, "%s: short ram map\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: short ram map\n", __FUNCTION__));
         error = ERROR_NOT_ENOUGH_MEMORY;
         goto err;
     }
     ram_header = (QXLRam *)(ram + dev->rom->ram_header_offset);
     if (ram_header->magic != QXL_RAM_MAGIC) {
-        DEBUG_PRINT((0, "%s: bad ram magic\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: bad ram magic\n", __FUNCTION__));
         error = ERROR_INVALID_DATA;
         goto err;
     }
@@ -309,7 +309,7 @@ VP_STATUS InitRam(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
 
     err:
     VideoPortUnmapMemory(dev, ram, NULL);
-    DEBUG_PRINT((0, "%s ERR\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 0, "%s ERR\n", __FUNCTION__));
     return error;
 }
 
@@ -322,16 +322,16 @@ VP_STATUS InitVRAM(QXLExtension *dev, PVIDEO_ACCESS_RANGE range);
 VP_STATUS InitVRAM(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
 {
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
 
     if (range->RangeLength == 0 || range->RangeInIoSpace) {
-        DEBUG_PRINT((0, "%s: bad mem range\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: bad mem range\n", __FUNCTION__));
         return ERROR_INVALID_DATA;
     }
 
     dev->vram_physical = range->RangeStart;
     dev->vram_size = range->RangeLength;
-    DEBUG_PRINT((0, "%s: OK, vram 0x%lx size %lu\n",
+    DEBUG_PRINT((dev, 0, "%s: OK, vram 0x%lx size %lu\n",
                  __FUNCTION__, (ULONG)range->RangeStart.QuadPart, range->RangeLength));
     return NO_ERROR;
 }
@@ -350,7 +350,7 @@ VP_STATUS Prob(QXLExtension *dev, VIDEO_PORT_CONFIG_INFO *conf_info,
     VP_STATUS error;
 
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
 
     bus_data_size = VideoPortGetBusData(dev,
                                         PCIConfiguration,
@@ -360,25 +360,25 @@ VP_STATUS Prob(QXLExtension *dev, VIDEO_PORT_CONFIG_INFO *conf_info,
                                         sizeof(PCI_COMMON_CONFIG));
 
     if (bus_data_size != sizeof(PCI_COMMON_CONFIG)) {
-        DEBUG_PRINT((0,  "%s: GetBusData size %d expectes %d\n",
+        DEBUG_PRINT((dev, 0,  "%s: GetBusData size %d expectes %d\n",
                      __FUNCTION__, bus_data_size, sizeof(PCI_COMMON_CONFIG)));
         return ERROR_INVALID_PARAMETER;
     }
 
     if (pci_conf.VendorID != REDHAT_PCI_VENDOR_ID) {
-        DEBUG_PRINT((0,  "%s: bad vendor id 0x%x expectes 0x%x\n",
+        DEBUG_PRINT((dev, 0,  "%s: bad vendor id 0x%x expectes 0x%x\n",
                      __FUNCTION__, pci_conf.VendorID, REDHAT_PCI_VENDOR_ID));
         return ERROR_INVALID_PARAMETER;
     }
 
     if (pci_conf.DeviceID != QXL_DEVICE_ID_STABLE) {
-        DEBUG_PRINT((0,  "%s: bad vendor id 0x%x expectes 0x%x\n",
+        DEBUG_PRINT((dev, 0,  "%s: bad vendor id 0x%x expectes 0x%x\n",
                      __FUNCTION__, pci_conf.DeviceID, QXL_DEVICE_ID_STABLE));
         return ERROR_INVALID_PARAMETER;
     }
 
     if (pci_conf.RevisionID < QXL_REVISION_STABLE_V06) {
-        DEBUG_PRINT((0,  "%s: bad revision 0x%x expectes at least 0x%x\n",
+        DEBUG_PRINT((dev, 0,  "%s: bad revision 0x%x expectes at least 0x%x\n",
                      __FUNCTION__, pci_conf.RevisionID, QXL_REVISION_STABLE_V06));
         return ERROR_INVALID_PARAMETER;
     }
@@ -388,11 +388,11 @@ VP_STATUS Prob(QXLExtension *dev, VIDEO_PORT_CONFIG_INFO *conf_info,
     if ((error = VideoPortGetAccessRanges(dev, 0, NULL, n_ranges,
                                           ranges, NULL, NULL,
                                           NULL)) != NO_ERROR ) {
-        DEBUG_PRINT((0, "%s: get access ranges failed status %u\n", __FUNCTION__, error));
+        DEBUG_PRINT((dev, 0, "%s: get access ranges failed status %u\n", __FUNCTION__, error));
     }
 
     if (conf_info->BusInterruptLevel == 0 && conf_info->BusInterruptVector == 0) {
-        DEBUG_PRINT((0, "%s: no interrupt\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: no interrupt\n", __FUNCTION__));
         error = ERROR_INVALID_DATA;
     }
 
@@ -400,14 +400,14 @@ VP_STATUS Prob(QXLExtension *dev, VIDEO_PORT_CONFIG_INFO *conf_info,
     if (error == NO_ERROR) {
         int i;
 
-        DEBUG_PRINT((0, "%s: interrupt: vector %lu level %lu mode %s\n",
+        DEBUG_PRINT((dev, 0, "%s: interrupt: vector %lu level %lu mode %s\n",
                      __FUNCTION__,
                      conf_info->BusInterruptVector,
                      conf_info->BusInterruptLevel,
                      (conf_info->InterruptMode == LevelSensitive) ? "LevelSensitive" : "Latched"));
 
         for (i = 0; i < n_ranges; i++) {
-            DEBUG_PRINT((0, "%s: range %d start 0x%lx length %lu space %lu\n", __FUNCTION__, i,
+            DEBUG_PRINT((dev, 0, "%s: range %d start 0x%lx length %lu space %lu\n", __FUNCTION__, i,
                          (ULONG)ranges[i].RangeStart.QuadPart,
                          ranges[i].RangeLength,
                          (ULONG)ranges[i].RangeInIoSpace));
@@ -415,7 +415,7 @@ VP_STATUS Prob(QXLExtension *dev, VIDEO_PORT_CONFIG_INFO *conf_info,
     }
 #endif
 
-    DEBUG_PRINT((0, "%s exit %lu\n", __FUNCTION__, error));
+    DEBUG_PRINT((dev, 0, "%s exit %lu\n", __FUNCTION__, error));
     return error;
 }
 
@@ -428,7 +428,7 @@ VP_STATUS SetVideoModeInfo(PVIDEO_MODE_INFORMATION video_mode, QXLMode *qxl_mode
 {
     ULONG color_bits;
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s: x %u y %u bits %u stride %u orientation %u\n",
+    DEBUG_PRINT((dev, 0, "%s: x %u y %u bits %u stride %u orientation %u\n",
                  __FUNCTION__, qxl_mode->x_res, qxl_mode->y_res,
                  qxl_mode->bits, qxl_mode->stride, qxl_mode->orientation));
 
@@ -455,7 +455,7 @@ VP_STATUS SetVideoModeInfo(PVIDEO_MODE_INFORMATION video_mode, QXLMode *qxl_mode
     video_mode->VideoMemoryBitmapWidth = qxl_mode->x_res;
     video_mode->VideoMemoryBitmapHeight = qxl_mode->y_res;
     video_mode->DriverSpecificAttributeFlags = qxl_mode->orientation;
-    DEBUG_PRINT((0, "%s OK\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 0, "%s OK\n", __FUNCTION__));
     return NO_ERROR;
 }
 
@@ -485,7 +485,7 @@ VP_STATUS InitMemSlots(QXLExtension *dev)
     if (!(dev->mem_slots = VideoPortAllocatePool(dev, VpPagedPool,
                                                  dev->rom->slots_end * sizeof(MemSlot),
                                                  QXL_ALLOC_TAG))) {
-        DEBUG_PRINT((0, "%s: alloc mem failed\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: alloc mem failed\n", __FUNCTION__));
         return ERROR_NOT_ENOUGH_MEMORY;
     }
 #endif
@@ -504,13 +504,13 @@ VP_STATUS InitModes(QXLExtension *dev)
     VP_STATUS error;
 
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 0, "%s\n", __FUNCTION__));
     rom = dev->rom;
     modes = (QXLModes *)((UCHAR*)rom + rom->modes_offset);
     if (dev->rom_size < rom->modes_offset + sizeof(QXLModes) ||
         (n_modes = modes->n_modes) == 0 || dev->rom_size <
         rom->modes_offset + sizeof(QXLModes) + n_modes * sizeof(QXLMode)) {
-        DEBUG_PRINT((0, "%s: bad rom size\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: bad rom size\n", __FUNCTION__));
         return ERROR_INVALID_DATA;
     }
 
@@ -524,7 +524,7 @@ VP_STATUS InitModes(QXLExtension *dev)
     if (!(modes_info = VideoPortAllocatePool(dev, VpPagedPool,
                                              n_modes * sizeof(VIDEO_MODE_INFORMATION),
                                              QXL_ALLOC_TAG))) {
-        DEBUG_PRINT((0, "%s: alloc mem failed\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: alloc mem failed\n", __FUNCTION__));
         return ERROR_NOT_ENOUGH_MEMORY;
     }
 #endif
@@ -533,13 +533,13 @@ VP_STATUS InitModes(QXLExtension *dev)
         error = SetVideoModeInfo(&modes_info[i], &modes->modes[i]);
         if (error != NO_ERROR) {
             VideoPortFreePool(dev, modes_info);
-            DEBUG_PRINT((0, "%s: set video mode failed\n", __FUNCTION__));
+            DEBUG_PRINT((dev, 0, "%s: set video mode failed\n", __FUNCTION__));
             return error;
         }
     }
     dev->n_modes = n_modes;
     dev->modes = modes_info;
-    DEBUG_PRINT((0, "%s OK\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 0, "%s OK\n", __FUNCTION__));
     return NO_ERROR;
 }
 
@@ -604,45 +604,45 @@ VP_STATUS FindAdapter(PVOID dev_extension,
 
     PAGED_CODE();
 
-    DEBUG_PRINT((0, "%s: enter\n", __FUNCTION__));
+    DEBUG_PRINT((dev_ext, 0, "%s: enter\n", __FUNCTION__));
 
 #if (WINVER >= 0x0501)
     VideoPortZeroMemory(&sys_info, sizeof(VPOSVERSIONINFO));
     sys_info.Size = sizeof(VPOSVERSIONINFO);
     if ((status = VideoPortGetVersion(dev_ext, &sys_info)) != NO_ERROR ||
         sys_info.MajorVersion < 5 || (sys_info.MajorVersion == 5 && sys_info.MinorVersion < 1) ) {
-        DEBUG_PRINT((0, "%s: err not supported, status %lu major %lu minor %lu\n",
+        DEBUG_PRINT((dev_ext, 0, "%s: err not supported, status %lu major %lu minor %lu\n",
                      __FUNCTION__, status, sys_info.MajorVersion, sys_info.MinorVersion));
         return ERROR_NOT_SUPPORTED;
     }
 #endif
 
     if (conf_info->Length < sizeof(VIDEO_PORT_CONFIG_INFO)) {
-        DEBUG_PRINT((0, "%s: err configInfo size\n", __FUNCTION__));
+        DEBUG_PRINT((dev_ext, 0, "%s: err configInfo size\n", __FUNCTION__));
         return ERROR_INVALID_PARAMETER;
     }
 
     if (conf_info->AdapterInterfaceType != PCIBus) {
-        DEBUG_PRINT((0,  "%s: not a PCI device %d\n",
+        DEBUG_PRINT((dev_ext, 0,  "%s: not a PCI device %d\n",
                      __FUNCTION__, conf_info->AdapterInterfaceType));
         return ERROR_DEV_NOT_EXIST;
     }
 
     if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &display_event)) != NO_ERROR) {
-        DEBUG_PRINT((0,  "%s: create display event failed %lu\n",
+        DEBUG_PRINT((dev_ext, 0,  "%s: create display event failed %lu\n",
                      __FUNCTION__, status));
         return status;
     }
 
     if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &cursor_event)) != NO_ERROR) {
-        DEBUG_PRINT((0,  "%s: create cursor event failed %lu\n",
+        DEBUG_PRINT((dev_ext, 0,  "%s: create cursor event failed %lu\n",
                      __FUNCTION__, status));
         VideoPortDeleteEvent(dev_ext, display_event);
         return status;
     }
 
     if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &sleep_event)) != NO_ERROR) {
-        DEBUG_PRINT((0,  "%s: create sleep event failed %lu\n",
+        DEBUG_PRINT((dev_ext, 0,  "%s: create sleep event failed %lu\n",
                      __FUNCTION__, status));
         VideoPortDeleteEvent(dev_ext, display_event);
         VideoPortDeleteEvent(dev_ext, cursor_event);
@@ -650,7 +650,7 @@ VP_STATUS FindAdapter(PVOID dev_extension,
     }
 
     if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &io_cmd_event)) != NO_ERROR) {
-        DEBUG_PRINT((0,  "%s: create io_cmd event failed %lu\n",
+        DEBUG_PRINT((dev_ext, 0,  "%s: create io_cmd event failed %lu\n",
                      __FUNCTION__, status));
         VideoPortDeleteEvent(dev_ext, sleep_event);
         VideoPortDeleteEvent(dev_ext, display_event);
@@ -670,16 +670,16 @@ VP_STATUS FindAdapter(PVOID dev_extension,
         (status = InitVRAM(dev_ext, &ranges[QXL_VRAM_RANGE_INDEX])) != NO_ERROR ||
         (status = InitModes(dev_ext)) != NO_ERROR ||
         (status = InitMemSlots(dev_ext)) != NO_ERROR) {
-        DEBUG_PRINT((0,  "%s: findAdapter failed\n", __FUNCTION__));
+        DEBUG_PRINT((dev_ext, 0,  "%s: findAdapter failed\n", __FUNCTION__));
         DevExternsionCleanup(dev_ext);
     }
 
     if (VideoPortSetRegistryParameters(dev_extension, L"QxlDeviceID",
                                        &dev_ext->rom->id, sizeof(UINT32)) != NO_ERROR) {
-        DEBUG_PRINT((0, "%s: write QXL ID failed\n", __FUNCTION__));
+        DEBUG_PRINT((dev_ext, 0, "%s: write QXL ID failed\n", __FUNCTION__));
     }
 
-    DEBUG_PRINT((0, "%s: exit %lu\n", __FUNCTION__, status));
+    DEBUG_PRINT((dev_ext, 0, "%s: exit %lu\n", __FUNCTION__, status));
     return status;
 }
 
@@ -689,7 +689,7 @@ static BOOLEAN CreateMemSlots(QXLExtension *dev_ext)
     UINT8 slot_id = dev_ext->rom->slots_start;
 
     if (slot_id >= dev_ext->rom->slots_end) {
-        DEBUG_PRINT((0, "%s: start_memslot bigger than nmem_slot\n", __FUNCTION__));
+        DEBUG_PRINT((dev_ext, 0, "%s: start_memslot bigger than nmem_slot\n", __FUNCTION__));
         return FALSE;
     }
 
@@ -729,18 +729,18 @@ static void ResetDeviceWithoutIO(QXLExtension *dev_ext)
 void HWReset(QXLExtension *dev_ext)
 {
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+    DEBUG_PRINT((dev_ext, 0, "%s\n", __FUNCTION__));
     VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_RESET, 0);
     ResetDeviceWithoutIO(dev_ext);
-    DEBUG_PRINT((0, "%s: done\n", __FUNCTION__));
+    DEBUG_PRINT((dev_ext, 0, "%s: done\n", __FUNCTION__));
 }
 
 BOOLEAN Initialize(PVOID dev_ext)
 {
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s: enter\n", __FUNCTION__));
+    DEBUG_PRINT((dev_ext, 0, "%s: enter\n", __FUNCTION__));
     HWReset(dev_ext);
-    DEBUG_PRINT((0, "%s: done\n", __FUNCTION__));
+    DEBUG_PRINT((dev_ext, 0, "%s: done\n", __FUNCTION__));
     return TRUE;
 }
 
@@ -748,8 +748,9 @@ VP_STATUS GetPowerState(PVOID dev_extension,
                         ULONG hw_id,
                         PVIDEO_POWER_MANAGEMENT pm_stat)
 {
+    QXLExtension *dev = dev_extension;
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s: %lu\n", __FUNCTION__, pm_stat->PowerState));
+    DEBUG_PRINT((dev, 0, "%s: %lu\n", __FUNCTION__, pm_stat->PowerState));
 
     switch (hw_id) {
     case DISPLAY_ADAPTER_HW_ID:
@@ -760,14 +761,14 @@ VP_STATUS GetPowerState(PVOID dev_extension,
         case VideoPowerOff:
         case VideoPowerShutdown:
         case VideoPowerHibernate:
-            DEBUG_PRINT((0, "%s: OK\n", __FUNCTION__));
+            DEBUG_PRINT((dev, 0, "%s: OK\n", __FUNCTION__));
             return NO_ERROR;
         }
         break;
     default:
-        DEBUG_PRINT((0, "%s: unexpected hw_id %lu\n", __FUNCTION__, hw_id));
+        DEBUG_PRINT((dev, 0, "%s: unexpected hw_id %lu\n", __FUNCTION__, hw_id));
     }
-    DEBUG_PRINT((0, "%s: ERROR_DEVICE_REINITIALIZATION_NEEDED\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 0, "%s: ERROR_DEVICE_REINITIALIZATION_NEEDED\n", __FUNCTION__));
     return ERROR_DEVICE_REINITIALIZATION_NEEDED;
 }
 
@@ -795,7 +796,7 @@ VP_STATUS SetPowerState(PVOID dev_extension,
 {
     QXLExtension *dev_ext = dev_extension;
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s: %lu\n", __FUNCTION__, pm_stat->PowerState));
+    DEBUG_PRINT((dev_ext, 0, "%s (%d): %d: %lu\n", __FUNCTION__, dev_ext->rom->id, hw_id, pm_stat->PowerState));
 
     switch (hw_id) {
     case DISPLAY_ADAPTER_HW_ID:
@@ -817,12 +818,12 @@ VP_STATUS SetPowerState(PVOID dev_extension,
             DebugZeroDeviceMemory(dev_ext);
             break;
         default:
-            DEBUG_PRINT((0, "%s: unexpected power state\n", __FUNCTION__));
+            DEBUG_PRINT((dev_ext, 0, "%s: unexpected power state\n", __FUNCTION__));
             return ERROR_DEVICE_REINITIALIZATION_NEEDED;
         }
         break;
     default:
-        DEBUG_PRINT((0, "%s: unexpected hw_id %lu\n", __FUNCTION__, hw_id));
+        DEBUG_PRINT((dev_ext, 0, "%s: unexpected hw_id %lu\n", __FUNCTION__, hw_id));
         return ERROR_DEVICE_REINITIALIZATION_NEEDED;
     }
     return NO_ERROR;
@@ -835,15 +836,16 @@ VP_STATUS GetChildDescriptor(IN PVOID dev_extension,
                              OUT PULONG uid,
                              OUT PULONG unused)
 {
+    QXLExtension *dev = dev_extension;
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s: enter\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 0, "%s: enter\n", __FUNCTION__));
 
     switch (enum_info->ChildIndex) {
     case 0:
-        DEBUG_PRINT((0, "%s: ACPI id %u\n", __FUNCTION__, enum_info->ACPIHwId));
+        DEBUG_PRINT((dev, 0, "%s: ACPI id %u\n", __FUNCTION__, enum_info->ACPIHwId));
         return ERROR_NO_MORE_DEVICES;
     case 1:
-        DEBUG_PRINT((0, "%s: Monitor\n", __FUNCTION__));
+        DEBUG_PRINT((dev, 0, "%s: Monitor\n", __FUNCTION__));
         /*
         *pChildType = Monitor;
         todo: handle EDID
@@ -851,7 +853,7 @@ VP_STATUS GetChildDescriptor(IN PVOID dev_extension,
         */
         return ERROR_NO_MORE_DEVICES;
     }
-    DEBUG_PRINT((0, "%s: ERROR_NO_MORE_DEVICES\n", __FUNCTION__));
+    DEBUG_PRINT((dev, 0, "%s: ERROR_NO_MORE_DEVICES\n", __FUNCTION__));
     return ERROR_NO_MORE_DEVICES;
 }
 
@@ -868,19 +870,19 @@ PVIDEO_MODE_INFORMATION FindMode(QXLExtension *dev_ext, ULONG mode)
     VIDEO_MODE_INFORMATION *end;
 
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+    DEBUG_PRINT((dev_ext, 0, "%s\n", __FUNCTION__));
 
     inf = dev_ext->modes;
     end = inf + dev_ext->n_modes;
     for (; inf < end; inf++) {
         if (inf->ModeIndex == mode) {
-            DEBUG_PRINT((0, "%s: OK mode %lu res %lu-%lu orientation %lu\n", __FUNCTION__,
+            DEBUG_PRINT((dev_ext, 0, "%s: OK mode %lu res %lu-%lu orientation %lu\n", __FUNCTION__,
                          mode, inf->VisScreenWidth, inf->VisScreenHeight,
                          inf->DriverSpecificAttributeFlags ));
             return inf;
         }
     }
-    DEBUG_PRINT((0, "%s: mod info not found\n", __FUNCTION__));
+    DEBUG_PRINT((dev_ext, 0, "%s: mod info not found\n", __FUNCTION__));
     return NULL;
 }
 
@@ -890,11 +892,11 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
     VP_STATUS error;
 
     PAGED_CODE();
-    DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+    DEBUG_PRINT((dev_ext, 0, "%s\n", __FUNCTION__));
 
     switch (packet->IoControlCode) {
     case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
-        DEBUG_PRINT((0, "%s: IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES\n", __FUNCTION__));
+        DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES\n", __FUNCTION__));
         if (packet->OutputBufferLength < (packet->StatusBlock->Information =
                                           sizeof(VIDEO_NUM_MODES))) {
             error = ERROR_INSUFFICIENT_BUFFER;
@@ -909,7 +911,7 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             VIDEO_MODE_INFORMATION *end;
             VIDEO_MODE_INFORMATION *out;
 
-            DEBUG_PRINT((0, "%s: IOCTL_VIDEO_QUERY_AVAIL_MODES\n", __FUNCTION__));
+            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_QUERY_AVAIL_MODES\n", __FUNCTION__));
             if (packet->OutputBufferLength < (packet->StatusBlock->Information =
                                               dev_ext->n_modes * sizeof(VIDEO_MODE_INFORMATION))) {
                 error = ERROR_INSUFFICIENT_BUFFER;
@@ -925,7 +927,7 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
         break;
     case IOCTL_VIDEO_SET_CURRENT_MODE: {
             ULONG request_mode;
-            DEBUG_PRINT((0, "%s: IOCTL_VIDEO_SET_CURRENT_MODE\n", __FUNCTION__));
+            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_SET_CURRENT_MODE\n", __FUNCTION__));
             if (packet->InputBufferLength < sizeof(VIDEO_MODE)) {
                 error = ERROR_INSUFFICIENT_BUFFER;
                 goto err;
@@ -933,7 +935,7 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             request_mode = ((PVIDEO_MODE)packet->InputBuffer)->RequestedMode;
 
             dev_ext->current_mode = request_mode;
-            DEBUG_PRINT((0, "%s: mode %u\n", __FUNCTION__, request_mode));
+            DEBUG_PRINT((dev_ext, 0, "%s: mode %u\n", __FUNCTION__, request_mode));
             if (!IsValidMode(dev_ext, request_mode)) {
                 error = ERROR_INVALID_PARAMETER;
                 goto err;
@@ -943,7 +945,7 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
     case IOCTL_VIDEO_QUERY_CURRENT_MODE: {
             PVIDEO_MODE_INFORMATION inf;
 
-            DEBUG_PRINT((0, "%s: IOCTL_VIDEO_QUERY_CURRENT_MODE\n", __FUNCTION__));
+            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_QUERY_CURRENT_MODE\n", __FUNCTION__));
 
             if (packet->OutputBufferLength < (packet->StatusBlock->Information =
                                               sizeof(VIDEO_MODE_INFORMATION))) {
@@ -952,7 +954,7 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             }
 
             if ((inf = FindMode(dev_ext, dev_ext->current_mode)) == NULL) {
-                DEBUG_PRINT((0, "%s: mod info not found\n", __FUNCTION__));
+                DEBUG_PRINT((dev_ext, 0, "%s: mod info not found\n", __FUNCTION__));
                 error = ERROR_INVALID_DATA;
                 goto err;
             }
@@ -963,7 +965,7 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             PVIDEO_MEMORY_INFORMATION mem_info;
             ULONG fb_io_space;
 
-            DEBUG_PRINT((0, "%s: IOCTL_VIDEO_MAP_VIDEO_MEMORY\n", __FUNCTION__));
+            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_MAP_VIDEO_MEMORY\n", __FUNCTION__));
 
             if (packet->OutputBufferLength < (packet->StatusBlock->Information =
                                               sizeof(VIDEO_MEMORY_INFORMATION)) ||
@@ -982,17 +984,17 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             if ((error = VideoPortMapMemory(dev_ext, dev_ext->vram_physical,
                                             &mem_info->VideoRamLength,
                                             &fb_io_space, &mem_info->VideoRamBase)) != NO_ERROR) {
-                DEBUG_PRINT((0, "%s: map filed\n", __FUNCTION__));
+                DEBUG_PRINT((dev_ext, 0, "%s: map filed\n", __FUNCTION__));
                 goto err;
             }
             dev_ext->vram_start = mem_info->VideoRamBase;
-            DEBUG_PRINT((0, "%s: vram size %lu ret size %lu fb vaddr 0x%lx\n",
+            DEBUG_PRINT((dev_ext, 0, "%s: vram size %lu ret size %lu fb vaddr 0x%lx\n",
                          __FUNCTION__,
                          dev_ext->vram_size,
                          mem_info->VideoRamLength,
                          mem_info->VideoRamBase));
             if (mem_info->VideoRamLength < dev_ext->vram_size) {
-                DEBUG_PRINT((0, "%s: fb shrink\n", __FUNCTION__));
+                DEBUG_PRINT((dev_ext, 0, "%s: fb shrink\n", __FUNCTION__));
                 VideoPortUnmapMemory(dev_ext, mem_info->VideoRamBase, NULL);
                 mem_info->VideoRamBase = NULL;
                 mem_info->VideoRamLength = 0;
@@ -1002,16 +1004,16 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             mem_info->FrameBufferBase = mem_info->VideoRamBase;
             mem_info->FrameBufferLength = mem_info->VideoRamLength;
 #ifdef DBG
-            DEBUG_PRINT((0, "%s: zap\n", __FUNCTION__));
+            DEBUG_PRINT((dev, 0, "%s: zap\n", __FUNCTION__));
             VideoPortZeroMemory(mem_info->VideoRamBase, mem_info->VideoRamLength);
-            DEBUG_PRINT((0, "%s: zap done\n", __FUNCTION__));
+            DEBUG_PRINT((dev, 0, "%s: zap done\n", __FUNCTION__));
 #endif
         }
         break;
     case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY: {
             PVOID addr;
 
-            DEBUG_PRINT((0, "%s: IOCTL_VIDEO_UNMAP_VIDEO_MEMORY\n", __FUNCTION__));
+            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_UNMAP_VIDEO_MEMORY\n", __FUNCTION__));
 
             if (packet->InputBufferLength < sizeof(VIDEO_MEMORY)) {
                 error = ERROR_INSUFFICIENT_BUFFER;
@@ -1019,18 +1021,18 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             }
             addr = ((PVIDEO_MEMORY)(packet->InputBuffer))->RequestedVirtualAddress;
             if ((error = VideoPortUnmapMemory(dev_ext, addr, NULL)) != NO_ERROR) {
-                DEBUG_PRINT((0, "%s: unmap failed\n", __FUNCTION__));
+                DEBUG_PRINT((dev_ext, 0, "%s: unmap failed\n", __FUNCTION__));
             }
             dev_ext->vram_start = NULL;
         }
         break;
     case IOCTL_VIDEO_RESET_DEVICE:
-        DEBUG_PRINT((0, "%s: IOCTL_VIDEO_RESET_DEVICE\n", __FUNCTION__));
+        DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_VIDEO_RESET_DEVICE\n", __FUNCTION__));
         HWReset(dev_ext);
         break;
     case IOCTL_QXL_GET_INFO: {
             QXLDriverInfo *driver_info;
-            DEBUG_PRINT((0, "%s: IOCTL_QXL_GET_INFO\n", __FUNCTION__));
+            DEBUG_PRINT((dev_ext, 0, "%s: IOCTL_QXL_GET_INFO\n", __FUNCTION__));
 
             if (packet->OutputBufferLength < (packet->StatusBlock->Information =
                                               sizeof(QXLDriverInfo))) {
@@ -1111,17 +1113,17 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
         }
         break;
     default:
-        DEBUG_PRINT((0, "%s: invalid command 0x%lx\n", __FUNCTION__, packet->IoControlCode));
+        DEBUG_PRINT((dev_ext, 0, "%s: invalid command 0x%lx\n", __FUNCTION__, packet->IoControlCode));
         error = ERROR_INVALID_FUNCTION;
         goto err;
     }
     packet->StatusBlock->Status = NO_ERROR;
-    DEBUG_PRINT((0, "%s: OK\n", __FUNCTION__));
+    DEBUG_PRINT((dev_ext, 0, "%s: OK\n", __FUNCTION__));
     return TRUE;
 err:
     packet->StatusBlock->Information = 0;
     packet->StatusBlock->Status = error;
-    DEBUG_PRINT((0, "%s: ERR\n", __FUNCTION__));
+    DEBUG_PRINT((dev_ext, 0, "%s: ERR\n", __FUNCTION__));
     return TRUE;
 }
 
commit 533b2b7545de9b5bdc338ddb9de948447bd9a2df
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jun 15 22:59:48 2011 +0200

    miniport/qxl: add DebugZeroDeviceMemory and use in DBG for hibernate and
    
    We zero the memory explicitly for debugging purposes when going to sleep
    to ensure the return path doesn't rely on any initialization done before.
    
    SetPowerState slightly refactored in the process.

diff --git a/miniport/qxl.c b/miniport/qxl.c
index f3cbafa..4161282 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -771,10 +771,29 @@ VP_STATUS GetPowerState(PVOID dev_extension,
     return ERROR_DEVICE_REINITIALIZATION_NEEDED;
 }
 
+#ifdef DBG
+static void DebugZeroDeviceMemory(QXLExtension *dev_ext)
+{
+    // don't zero the memory if the ram_start and vram_start are not initialized (a
+    // device has been installed but the monitor is disabled)
+    if (dev_ext->ram_start == 0 || dev_ext->vram_start == 0) {
+        DEBUG_PRINT((dev_ext, 0, "%s: not zeroing memory (addresses not initialized)\n", __FUNCTION__));
+        return;
+    }
+    VideoPortZeroMemory(dev_ext->ram_start, dev_ext->ram_size);
+    VideoPortZeroMemory(dev_ext->vram_start, dev_ext->vram_size);
+}
+#else
+static _inline void DebugZeroDeviceMemory(QXLExtension *dev_ext)
+{
+}
+#endif
+
 VP_STATUS SetPowerState(PVOID dev_extension,
                         ULONG hw_id,
                         PVIDEO_POWER_MANAGEMENT pm_stat)
 {
+    QXLExtension *dev_ext = dev_extension;
     PAGED_CODE();
     DEBUG_PRINT((0, "%s: %lu\n", __FUNCTION__, pm_stat->PowerState));
 
@@ -785,19 +804,28 @@ VP_STATUS SetPowerState(PVOID dev_extension,
             ResetDeviceWithoutIO(dev_ext);
             break;
         case VideoPowerStandBy:
+            break;
         case VideoPowerSuspend:
+            break;
         case VideoPowerOff:
+            DebugZeroDeviceMemory(dev_ext);
+            break;
         case VideoPowerShutdown:
+            /* Important: you cannot call out to qxldd.dll here or you get a BSOD. */
+            break;
         case VideoPowerHibernate:
-            DEBUG_PRINT((0, "%s: OK\n", __FUNCTION__));
-            return NO_ERROR;
+            DebugZeroDeviceMemory(dev_ext);
+            break;
+        default:
+            DEBUG_PRINT((0, "%s: unexpected power state\n", __FUNCTION__));
+            return ERROR_DEVICE_REINITIALIZATION_NEEDED;
         }
         break;
     default:
         DEBUG_PRINT((0, "%s: unexpected hw_id %lu\n", __FUNCTION__, hw_id));
+        return ERROR_DEVICE_REINITIALIZATION_NEEDED;
     }
-    DEBUG_PRINT((0, "%s: ERROR_DEVICE_REINITIALIZATION_NEEDED\n", __FUNCTION__));
-    return ERROR_DEVICE_REINITIALIZATION_NEEDED;
+    return NO_ERROR;
 }
 
 VP_STATUS GetChildDescriptor(IN PVOID dev_extension,
commit fdad7aea6ed8c57f926bf4a4537a1cc7d8f8f659
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jun 15 22:59:22 2011 +0200

    miniport/qxl: implement SetPowerState:VideoPowerOn

diff --git a/miniport/qxl.c b/miniport/qxl.c
index 21c2c56..f3cbafa 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -718,13 +718,20 @@ void HWReset(QXLExtension *dev_ext);
 #pragma alloc_text(PAGE, HWReset)
 #endif
 
+/* called from HWReset or after returning from sleep from SetPowerState,
+ * when returning from sleep we don't want to do a redundant QXL_IO_RESET */
+static void ResetDeviceWithoutIO(QXLExtension *dev_ext)
+{
+    dev_ext->ram_header->int_mask = ~0;
+    CreateMemSlots(dev_ext);
+}
+
 void HWReset(QXLExtension *dev_ext)
 {
     PAGED_CODE();
     DEBUG_PRINT((0, "%s\n", __FUNCTION__));
     VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_RESET, 0);
-    dev_ext->ram_header->int_mask = ~0;
-    CreateMemSlots(dev_ext);
+    ResetDeviceWithoutIO(dev_ext);
     DEBUG_PRINT((0, "%s: done\n", __FUNCTION__));
 }
 
@@ -775,6 +782,8 @@ VP_STATUS SetPowerState(PVOID dev_extension,
     case DISPLAY_ADAPTER_HW_ID:
         switch (pm_stat->PowerState) {
         case VideoPowerOn:
+            ResetDeviceWithoutIO(dev_ext);
+            break;
         case VideoPowerStandBy:
         case VideoPowerSuspend:
         case VideoPowerOff:
commit 3fad0cb439bbf1f02f058dbd06cbedf291302d6d
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 13:53:34 2011 +0300

    miniport/qxl: store vram_start on video memory map for later debug usage

diff --git a/miniport/qxl.c b/miniport/qxl.c
index b0a3e8c..21c2c56 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -79,6 +79,7 @@ typedef struct QXLExtension {
 
     PHYSICAL_ADDRESS vram_physical;
     ULONG vram_size;
+    UINT8 *vram_start;
 
     ULONG current_mode;
     ULONG n_modes;
@@ -947,6 +948,7 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
                 DEBUG_PRINT((0, "%s: map filed\n", __FUNCTION__));
                 goto err;
             }
+            dev_ext->vram_start = mem_info->VideoRamBase;
             DEBUG_PRINT((0, "%s: vram size %lu ret size %lu fb vaddr 0x%lx\n",
                          __FUNCTION__,
                          dev_ext->vram_size,
@@ -982,6 +984,7 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             if ((error = VideoPortUnmapMemory(dev_ext, addr, NULL)) != NO_ERROR) {
                 DEBUG_PRINT((0, "%s: unmap failed\n", __FUNCTION__));
             }
+            dev_ext->vram_start = NULL;
         }
         break;
     case IOCTL_VIDEO_RESET_DEVICE:
commit dc715b7e14641504eeb1920f77456d15c5b1ae70
Author: Alon Levy <alevy at redhat.com>
Date:   Thu May 26 14:23:54 2011 +0300

    miniport/*: use QXL_IO_LOG with internal snprintf
    
    snprintf is Copyright Patrick Powell 1995 (with more changes, see miniport/minimal_snprintf.c
    starting comment).
    
    Implements a DebugPrint similar to the one in display, using QXL_IO_LOG with the buffer
    on the pci devram bar at ram->log_buf, and log_level taken from there as well (set by
    qemu via guestdebug parameter to the qxl device). Allows for easier debugging of the miniport.
    Compiled out for release (free) builds where DBG is not defined.

diff --git a/miniport/minimal_snprintf.c b/miniport/minimal_snprintf.c
new file mode 100644
index 0000000..40572c1
--- /dev/null
+++ b/miniport/minimal_snprintf.c
@@ -0,0 +1,708 @@
+/* $Id: snprintf.c,v 1.2 2003/12/10 01:35:10 lukem Exp $ */
+
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell at astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh.  This sort of thing is always nasty do deal with.  Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length.  This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ *  Brandon Long <blong at fiction.net> 9/15/96 for mutt 0.43
+ *  This was ugly.  It is still ugly.  I opted out of floating point
+ *  numbers, but the formatter understands just about everything
+ *  from the normal C string format, at least as far as I can tell from
+ *  the Solaris 2.5 printf(3S) man page.
+ *
+ *  Brandon Long <blong at fiction.net> 10/22/97 for mutt 0.87.1
+ *    Ok, added some minimal floating point support, which means this
+ *    probably requires libm on most operating systems.  Don't yet
+ *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
+ *    was pretty badly broken, it just wasn't being exercised in ways
+ *    which showed it, so that's been fixed.  Also, formated the code
+ *    to mutt conventions, and removed dead code left over from the
+ *    original.  Also, there is now a builtin-test, just compile with:
+ *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ *    and run snprintf for results.
+ *
+ *  Thomas Roessler <roessler at guug.de> 01/27/98 for mutt 0.89i
+ *    The PGP code was using unsigned hexadecimal formats.
+ *    Unfortunately, unsigned formats simply didn't work.
+ *
+ *  Michael Elkins <me at cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ *    The original code assumed that both snprintf() and vsnprintf() were
+ *    missing.  Some systems only have snprintf() but not vsnprintf(), so
+ *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ *  Andrew Tridgell (tridge at samba.org) Oct 1998
+ *    fixed handling of %.0f
+ *    added test for HAVE_LONG_DOUBLE
+ *
+ *  Luke Mewburn <lukem at NetBSD.org>, Thu Sep 30 23:28:21 EST 1999
+ *	cleaned up formatting, autoconf tests
+ *	added long long support
+ *
+ **************************************************************/
+
+#include "minimal_snprintf.h"
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+static _inline int isdigit(char c)
+{
+    return c >= '0' && c <= '9';
+}
+
+#if HAVE_LONG_LONG
+#define LLONG long long
+#else
+#define LLONG long
+#endif
+
+static void dopr(char *buffer, size_t maxlen, size_t *retlen,
+		    const char *format, va_list args);
+static void fmtstr(char *buffer, size_t * currlen, size_t maxlen,
+		    char *value, int min, int max, int flags);
+static void fmtint(char *buffer, size_t * currlen, size_t maxlen,
+		    LLONG value, int base, int min, int max, int flags);
+#ifdef SUPPORT_FLOAT
+#if HAVE_LONG_DOUBLE
+#define LDOUBLE long double
+#else
+#define LDOUBLE double
+#endif
+
+static void fmtfp(char *buffer, size_t * currlen, size_t maxlen,
+		    LDOUBLE fvalue, int min, int max, int flags);
+#endif
+static void dopr_outch(char *buffer, size_t * currlen, size_t maxlen, int c);
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT	0
+#define DP_S_FLAGS	1
+#define DP_S_MIN	2
+#define DP_S_DOT	3
+#define DP_S_MAX	4
+#define DP_S_MOD	5
+#define DP_S_CONV	6
+#define DP_S_DONE	7
+
+/* format flags - Bits */
+#define DP_F_MINUS	(1 << 0)
+#define DP_F_PLUS	(1 << 1)
+#define DP_F_SPACE	(1 << 2)
+#define DP_F_NUM	(1 << 3)
+#define DP_F_ZERO	(1 << 4)
+#define DP_F_UP		(1 << 5)
+#define DP_F_UNSIGNED	(1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT	1
+#define DP_C_LONG	2
+#ifdef SUPPORT_FLOAT
+#define DP_C_LDOUBLE	3
+#endif
+#define DP_C_LLONG	4
+
+#define char_to_int(p) (p - '0')
+
+static void
+dopr(char *buffer, size_t maxlen, size_t *retlen, const char *format,
+	va_list args)
+{
+	char	 ch;
+	LLONG	 value;
+#ifdef SUPPORT_FLOAT
+	LDOUBLE	 fvalue;
+#endif
+	char	*strvalue;
+	int	 min;
+	int	 max;
+	int	 state;
+	int	 flags;
+	int	 cflags;
+	size_t	 currlen;
+
+	state = DP_S_DEFAULT;
+	flags = currlen = cflags = min = 0;
+	max = -1;
+	ch = *format++;
+
+	while (state != DP_S_DONE) {
+		if ((ch == '\0') || (currlen >= maxlen))
+			state = DP_S_DONE;
+
+		switch (state) {
+		case DP_S_DEFAULT:
+			if (ch == '%')
+				state = DP_S_FLAGS;
+			else
+				dopr_outch(buffer, &currlen, maxlen, ch);
+			ch = *format++;
+			break;
+		case DP_S_FLAGS:
+			switch (ch) {
+			case '-':
+				flags |= DP_F_MINUS;
+				ch = *format++;
+				break;
+			case '+':
+				flags |= DP_F_PLUS;
+				ch = *format++;
+				break;
+			case ' ':
+				flags |= DP_F_SPACE;
+				ch = *format++;
+				break;
+			case '#':
+				flags |= DP_F_NUM;
+				ch = *format++;
+				break;
+			case '0':
+				flags |= DP_F_ZERO;
+				ch = *format++;
+				break;
+			default:
+				state = DP_S_MIN;
+				break;
+			}
+			break;
+		case DP_S_MIN:
+			if (isdigit((unsigned char) ch)) {
+				min = 10 * min + char_to_int(ch);
+				ch = *format++;
+			} else if (ch == '*') {
+				min = va_arg(args, int);
+				ch = *format++;
+				state = DP_S_DOT;
+			} else
+				state = DP_S_DOT;
+			break;
+		case DP_S_DOT:
+			if (ch == '.') {
+				state = DP_S_MAX;
+				ch = *format++;
+			} else
+				state = DP_S_MOD;
+			break;
+		case DP_S_MAX:
+			if (isdigit((unsigned char) ch)) {
+				if (max < 0)
+					max = 0;
+				max = 10 * max + char_to_int(ch);
+				ch = *format++;
+			} else if (ch == '*') {
+				max = va_arg(args, int);
+				ch = *format++;
+				state = DP_S_MOD;
+			} else
+				state = DP_S_MOD;
+			break;
+		case DP_S_MOD:
+			switch (ch) {
+			case 'h':
+				cflags = DP_C_SHORT;
+				ch = *format++;
+				break;
+			case 'l':
+				if (*format == 'l') {
+					cflags = DP_C_LLONG;
+					format++;
+				} else
+					cflags = DP_C_LONG;
+				ch = *format++;
+				break;
+			case 'q':
+				cflags = DP_C_LLONG;
+				ch = *format++;
+				break;
+#ifdef SUPPORT_FLOAT
+			case 'L':
+				cflags = DP_C_LDOUBLE;
+				ch = *format++;
+				break;
+#endif
+			default:
+				break;
+			}
+			state = DP_S_CONV;
+			break;
+		case DP_S_CONV:
+			switch (ch) {
+			case 'd':
+			case 'i':
+				switch (cflags) {
+				case DP_C_SHORT:
+					value = va_arg(args, int);
+					break;
+				case DP_C_LONG:
+					value = va_arg(args, long int);
+					break;
+				case DP_C_LLONG:
+					value = va_arg(args, LLONG);
+					break;
+				default:
+					value = va_arg(args, int);
+					break;
+				}
+				fmtint(buffer, &currlen, maxlen, value, 10,
+				    min, max, flags);
+				break;
+			case 'X':
+				flags |= DP_F_UP;
+				/* FALLTHROUGH */
+			case 'x':
+			case 'o':
+			case 'u':
+				flags |= DP_F_UNSIGNED;
+				switch (cflags) {
+				case DP_C_SHORT:
+					value = va_arg(args, unsigned int);
+					break;
+				case DP_C_LONG:
+					value = (LLONG) va_arg(args,
+					    unsigned long int);
+					break;
+				case DP_C_LLONG:
+					value = va_arg(args, unsigned LLONG);
+					break;
+				default:
+					value = (LLONG) va_arg(args,
+					    unsigned int);
+					break;
+				}
+				fmtint(buffer, &currlen, maxlen, value,
+				    ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
+				    min, max, flags);
+				break;
+#ifdef SUPPORT_FLOAT
+			case 'f':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, LDOUBLE);
+				else
+					fvalue = va_arg(args, double);
+				/* um, floating point? */
+				fmtfp(buffer, &currlen, maxlen, fvalue, min,
+				    max, flags);
+				break;
+			case 'E':
+				flags |= DP_F_UP;
+			case 'e':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, LDOUBLE);
+				else
+					fvalue = va_arg(args, double);
+				break;
+			case 'G':
+				flags |= DP_F_UP;
+			case 'g':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, LDOUBLE);
+				else
+					fvalue = va_arg(args, double);
+				break;
+#endif // SUPPORT_FLOAT
+			case 'c':
+				dopr_outch(buffer, &currlen, maxlen,
+				    va_arg(args, int));
+				break;
+			case 's':
+				strvalue = va_arg(args, char *);
+				if (max < 0)
+					max = maxlen;	/* ie, no max */
+				fmtstr(buffer, &currlen, maxlen, strvalue,
+				    min, max, flags);
+				break;
+			case 'p':
+				value = (long)va_arg(args, void *);
+				fmtint(buffer, &currlen, maxlen,
+				    value, 16, min, max, flags);
+				break;
+			case 'n':
+/* XXX */
+				if (cflags == DP_C_SHORT) {
+					short int *num;
+					num = va_arg(args, short int *);
+					*num = (short)currlen;
+				} else if (cflags == DP_C_LONG) { /* XXX */
+					long int *num;
+					num = va_arg(args, long int *);
+					*num = (long int) currlen;
+				} else if (cflags == DP_C_LLONG) { /* XXX */
+					LLONG *num;
+					num = va_arg(args, LLONG *);
+					*num = (LLONG) currlen;
+				} else {
+					int    *num;
+					num = va_arg(args, int *);
+					*num = currlen;
+				}
+				break;
+			case '%':
+				dopr_outch(buffer, &currlen, maxlen, ch);
+				break;
+			case 'w':
+				/* not supported yet, treat as next char */
+				ch = *format++;
+				break;
+			default:
+				/* Unknown, skip */
+				break;
+			}
+			ch = *format++;
+			state = DP_S_DEFAULT;
+			flags = cflags = min = 0;
+			max = -1;
+			break;
+		case DP_S_DONE:
+			break;
+		default:
+			/* hmm? */
+			break;	/* some picky compilers need this */
+		}
+	}
+	if (currlen >= maxlen - 1)
+		currlen = maxlen - 1;
+	buffer[currlen] = '\0';
+	*retlen = currlen;
+}
+
+static void
+fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value,
+	int min, int max, int flags)
+{
+	int	padlen, strln;	/* amount to pad */
+	int	cnt = 0;
+
+	if (value == 0) {
+		value = "<NULL>";
+	}
+	for (strln = 0; value[strln]; ++strln)
+		;	/* strlen */
+	padlen = min - strln;
+	if (padlen < 0)
+		padlen = 0;
+	if (flags & DP_F_MINUS)
+		padlen = -padlen;	/* Left Justify */
+
+	while ((padlen > 0) && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--padlen;
+		++cnt;
+	}
+	while (*value && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, *value++);
+		++cnt;
+	}
+	while ((padlen < 0) && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		++padlen;
+		++cnt;
+	}
+}
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void
+fmtint(char *buffer, size_t *currlen, size_t maxlen, LLONG value, int base,
+	int min, int max, int flags)
+{
+	int		signvalue = 0;
+	unsigned LLONG	uvalue;
+	char		convert[20];
+	int		place = 0;
+	int		spadlen = 0;	/* amount to space pad */
+	int		zpadlen = 0;	/* amount to zero pad */
+	int		caps = 0;
+
+	if (max < 0)
+		max = 0;
+
+	uvalue = value;
+
+	if (!(flags & DP_F_UNSIGNED)) {
+		if (value < 0) {
+			signvalue = '-';
+			uvalue = -value;
+		} else if (flags & DP_F_PLUS)	/* Do a sign (+/i) */
+			signvalue = '+';
+		else if (flags & DP_F_SPACE)
+			signvalue = ' ';
+	}
+	if (flags & DP_F_UP)
+		caps = 1;	/* Should characters be upper case? */
+
+	do {
+		convert[place++] =
+		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+		    [uvalue % (unsigned) base];
+		uvalue = (uvalue / (unsigned) base);
+	} while (uvalue && (place < 20));
+	if (place == 20)
+		place--;
+	convert[place] = 0;
+
+	zpadlen = max - place;
+	spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
+	if (zpadlen < 0)
+		zpadlen = 0;
+	if (spadlen < 0)
+		spadlen = 0;
+	if (flags & DP_F_ZERO) {
+		zpadlen = MAX(zpadlen, spadlen);
+		spadlen = 0;
+	}
+	if (flags & DP_F_MINUS)
+		spadlen = -spadlen;	/* Left Justifty */
+
+#ifdef DEBUG_SNPRINTF
+	printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+	    zpadlen, spadlen, min, max, place);
+#endif
+
+	/* Spaces */
+	while (spadlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--spadlen;
+	}
+
+	/* Sign */
+	if (signvalue)
+		dopr_outch(buffer, currlen, maxlen, signvalue);
+
+	/* Zeros */
+	if (zpadlen > 0) {
+		while (zpadlen > 0) {
+			dopr_outch(buffer, currlen, maxlen, '0');
+			--zpadlen;
+		}
+	}
+	/* Digits */
+	while (place > 0)
+		dopr_outch(buffer, currlen, maxlen, convert[--place]);
+
+	/* Left Justified spaces */
+	while (spadlen < 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		++spadlen;
+	}
+}
+
+#ifdef SUPPORT_FLOAT
+static LDOUBLE
+abs_val(LDOUBLE value)
+{
+	LDOUBLE	result = value;
+
+	if (value < 0)
+		result = -value;
+
+	return result;
+}
+
+static LDOUBLE
+pow10(int exp)
+{
+	LDOUBLE	result = 1;
+
+	while (exp) {
+		result *= 10;
+		exp--;
+	}
+
+	return result;
+}
+
+static long
+round(LDOUBLE value)
+{
+	long	intpart;
+
+	intpart = (long) value;
+	value = value - intpart;
+	if (value >= 0.5)
+		intpart++;
+
+	return intpart;
+}
+
+static void
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue,
+	int min, int max, int flags)
+{
+	int	signvalue = 0;
+	LDOUBLE	ufvalue;
+	char	iconvert[20];
+	char	fconvert[20];
+	int	iplace = 0;
+	int	fplace = 0;
+	int	padlen = 0;	/* amount to pad */
+	int	zpadlen = 0;
+	int	caps = 0;
+	long	intpart;
+	long	fracpart;
+
+	/* AIX manpage says the default is 0, but Solaris says the default is
+	 * 6, and sprintf on AIX defaults to 6 */
+	if (max < 0)
+		max = 6;
+
+	ufvalue = abs_val(fvalue);
+
+	if (fvalue < 0)
+		signvalue = '-';
+	else if (flags & DP_F_PLUS)	/* Do a sign (+/i) */
+		signvalue = '+';
+	else if (flags & DP_F_SPACE)
+		signvalue = ' ';
+
+#if 0
+	if (flags & DP_F_UP)
+		caps = 1;	/* Should characters be upper case? */
+#endif
+
+	intpart = (long) ufvalue;
+
+	/* Sorry, we only support 9 digits past the decimal because of our
+	 * conversion method */
+	if (max > 9)
+		max = 9;
+
+	/* We "cheat" by converting the fractional part to integer by
+	 * multiplying by a factor of 10 */
+	fracpart = round((pow10(max)) * (ufvalue - intpart));
+
+	if (fracpart >= pow10(max)) {
+		intpart++;
+		fracpart -= (long)pow10(max);
+	}
+#ifdef DEBUG_SNPRINTF
+	printf("fmtfp: %g %d.%d min=%d max=%d\n",
+	    (double) fvalue, intpart, fracpart, min, max);
+#endif
+
+	/* Convert integer part */
+	do {
+		iconvert[iplace++] =
+		    (caps ? "0123456789ABCDEF"
+			  : "0123456789abcdef")[intpart % 10];
+		intpart = (intpart / 10);
+	} while (intpart && (iplace < 20));
+	if (iplace == 20)
+		iplace--;
+	iconvert[iplace] = 0;
+
+	/* Convert fractional part */
+	do {
+		fconvert[fplace++] =
+		    (caps ? "0123456789ABCDEF"
+			  : "0123456789abcdef")[fracpart % 10];
+		fracpart = (fracpart / 10);
+	} while (fracpart && (fplace < 20));
+	if (fplace == 20)
+		fplace--;
+	fconvert[fplace] = 0;
+
+	/* -1 for decimal point, another -1 if we are printing a sign */
+	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
+	zpadlen = max - fplace;
+	if (zpadlen < 0)
+		zpadlen = 0;
+	if (padlen < 0)
+		padlen = 0;
+	if (flags & DP_F_MINUS)
+		padlen = -padlen;	/* Left Justifty */
+
+	if ((flags & DP_F_ZERO) && (padlen > 0)) {
+		if (signvalue) {
+			dopr_outch(buffer, currlen, maxlen, signvalue);
+			--padlen;
+			signvalue = 0;
+		}
+		while (padlen > 0) {
+			dopr_outch(buffer, currlen, maxlen, '0');
+			--padlen;
+		}
+	}
+	while (padlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--padlen;
+	}
+	if (signvalue)
+		dopr_outch(buffer, currlen, maxlen, signvalue);
+
+	while (iplace > 0)
+		dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
+
+
+#ifdef DEBUG_SNPRINTF
+	printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
+#endif
+
+	/*
+         * Decimal point.  This should probably use locale to find the correct
+         * char to print out.
+         */
+	if (max > 0) {
+		dopr_outch(buffer, currlen, maxlen, '.');
+
+		while (fplace > 0)
+			dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
+	}
+	while (zpadlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, '0');
+		--zpadlen;
+	}
+
+	while (padlen < 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		++padlen;
+	}
+}
+#endif // SUPPORT_FLOAT
+
+static void
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, int c)
+{
+	if (*currlen < maxlen)
+		buffer[(*currlen)++] = (char)c;
+}
+
+int
+vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+{
+	size_t retlen;
+
+	str[0] = 0;
+	dopr(str, count, &retlen, fmt, args);
+	return (retlen);
+}
+
+/* VARARGS3 */
+int
+snprintf(char *str, size_t count, const char *fmt, ...)
+{
+	va_list	 ap;
+	int	 rv;
+
+	va_start(ap, fmt);
+	rv = vsnprintf(str, count, fmt, ap);
+	va_end(ap);
+	return (rv);
+}
diff --git a/miniport/minimal_snprintf.h b/miniport/minimal_snprintf.h
new file mode 100644
index 0000000..e26f1da
--- /dev/null
+++ b/miniport/minimal_snprintf.h
@@ -0,0 +1,9 @@
+#ifndef MINIMAL_SNPRINTF_H
+#define MINIMAL_SNPRINTF_H
+
+#include <stdarg.h>
+
+int snprintf(char *str, size_t count, const char *fmt, ...);
+int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
+
+#endif // MINIMAL_SNPRINTF_H
diff --git a/miniport/qxl.c b/miniport/qxl.c
index f8621e9..b0a3e8c 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -24,6 +24,7 @@
 #if (WINVER < 0x0501)
 #include "wdmhelper.h"
 #endif
+#include "minimal_snprintf.h"
 
 VP_STATUS FindAdapter(PVOID dev_extension,
                       PVOID reserved,
@@ -90,10 +91,48 @@ typedef struct QXLExtension {
 
     MemSlot *mem_slots;
 
+    char *log_buf;
+    PUCHAR log_port;
 } QXLExtension;
 
 #define QXL_ALLOC_TAG '_lxq'
 
+#define DBG_LEVEL 10
+
+#define QXL_MINIPORT_DEBUG_PREFIX "qxlmp: "
+
+void DebugPrintV(char *log_buf, PUCHAR log_port, const char *message, const char *func, va_list ap)
+{
+    int n, n_strlen;
+
+    if (log_buf && log_port) {
+        /*
+         * TODO: use a shared semaphore with display code.
+         * In practice this is not a problem, since miniport runs either on ioctls (sync)
+         * or before display is brought up or when it is brought down.
+         * Also the worst that can happen is overwriting a message (not seen in practice).
+         */
+        snprintf(log_buf, QXL_LOG_BUF_SIZE, QXL_MINIPORT_DEBUG_PREFIX);
+        vsnprintf(log_buf + strlen(QXL_MINIPORT_DEBUG_PREFIX),
+                   QXL_LOG_BUF_SIZE - strlen(QXL_MINIPORT_DEBUG_PREFIX),
+                   message, ap);
+        VideoPortWritePortUchar(log_port, 0);
+    } else {
+        VideoDebugPrint((0, (PCHAR)message, ap));
+    }
+}
+
+void DebugPrint(QXLExtension *dev, UINT32 level, const char *message, const char *func, ...)
+{
+    va_list ap;
+
+    if (dev && dev->rom && level > dev->rom->log_level) {
+        return;
+    }
+    va_start(ap, message);
+    DebugPrintV(dev ? dev->log_buf : NULL, dev ? dev->log_port : 0, message, func, ap);
+    va_end(ap);
+}
 
 ULONG DriverEntry(PVOID context1, PVOID context2)
 {
@@ -156,8 +195,8 @@ VP_STATUS InitIO(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
 
     dev->io_base = io_base;
     dev->io_port = (PUCHAR)range->RangeStart.LowPart;
-
-    DEBUG_PRINT((0, "%s: OK, io 0x%x size %lu\n", __FUNCTION__,
+    dev->log_port = dev->io_port + QXL_IO_LOG;
+    DEBUG_PRINT((dev, 0, "%s: OK, io 0x%x size %lu\n", __FUNCTION__,
                  (ULONG)range->RangeStart.LowPart, range->RangeLength));
 
     return NO_ERROR;
@@ -262,7 +301,8 @@ VP_STATUS InitRam(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
     dev->ram_start = ram;
     dev->ram_header = ram_header;
     dev->ram_size = range->RangeLength;
-    DEBUG_PRINT((0, "%s OK: ram 0x%lx size %lu\n",
+    dev->log_buf = dev->ram_header->log_buf;
+    DEBUG_PRINT((dev, 0, "%s OK: ram 0x%lx size %lu\n",
                  __FUNCTION__, (ULONG)range->RangeStart.QuadPart, range->RangeLength));
     return NO_ERROR;
 
diff --git a/miniport/qxl.h b/miniport/qxl.h
index a65d590..c7df4b1 100644
--- a/miniport/qxl.h
+++ b/miniport/qxl.h
@@ -35,8 +35,7 @@ enum {
 #define PAGE_SIZE (1 << PAGE_SHIFT)
 
 #if DBG
-#define DEBUG_PRINT(arg) VideoDebugPrint(arg)
+#define DEBUG_PRINT(arg) DebugPrint arg
 #else
 #define DEBUG_PRINT(arg)
 #endif
-
diff --git a/miniport/sources b/miniport/sources
index 15b1c76..8d96e14 100644
--- a/miniport/sources
+++ b/miniport/sources
@@ -22,9 +22,8 @@ MSC_WARNING_LEVEL=$(MSC_WARNING_LEVEL) /WX
 INCLUDES=$(SPICE_COMMON_DIR); ..\include
 
 SOURCES=qxl.c      \
+		minimal_snprintf.c \
 		wdmhelper.c \
         qxl.rc
 
 MISCFILES=qxl.inf
-
-
commit f7bce1fbda7fcfb6a7cdc1fa96c3aef1c0fe527b
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jun 23 13:21:46 2011 +0200

    don't create a surface if vram mspace is unmapped

diff --git a/display/driver.c b/display/driver.c
index 22c33f1..24adb0b 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -1229,7 +1229,7 @@ HBITMAP APIENTRY DrvCreateDeviceBitmap(DHPDEV dhpdev, SIZEL size, ULONG format)
 
     pdev = (PDev *)dhpdev;
 
-    if (!pdev->vram_slot_initialized || pdev->bitmap_format != format) {
+    if (!pdev->vram_slot_initialized || pdev->bitmap_format != format || pdev->fb == 0) {
         return 0;
     }
 
commit a7605a001f4e22d8ec408c93939712060bc25d7a
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jun 23 13:47:36 2011 +0200

    qxl_driver.h: bump QXL_DRIVER_INFO_VERSION (added pci_revision, flush_* ports)

diff --git a/include/qxl_driver.h b/include/qxl_driver.h
index fff350d..af65916 100644
--- a/include/qxl_driver.h
+++ b/include/qxl_driver.h
@@ -36,7 +36,7 @@ enum {
 #define IOCTL_QXL_GET_INFO \
     CTL_CODE(FILE_DEVICE_VIDEO, QXL_GET_INFO_FUNC, METHOD_BUFFERED, FILE_ANY_ACCESS)
 
-#define QXL_DRIVER_INFO_VERSION 2
+#define QXL_DRIVER_INFO_VERSION 3
 
 typedef struct MemSlot {
     UINT8 generation;
commit bf4fa2558356fdb196d7c5e4818a6c849cdf68e3
Author: Alon Levy <alevy at redhat.com>
Date:   Sun Jun 5 15:25:48 2011 +0300

    miniport+display: export FLUSH_{SURFACES,RELEASE} ports for use by AssertModeEnable
    
    Revision 3 (V10) of the qxl device supports these added io ports which make sleep, resolution
    change and logout simpler to implement with less vmexits from pov of the driver.

diff --git a/display/driver.c b/display/driver.c
index d13c6bc..22c33f1 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -708,6 +708,8 @@ static BOOL PrepareHardware(PDev *pdev)
     pdev->asyncable[ASYNCABLE_DESTROY_SURFACE][SYNC] = dev_info.destroy_surface_wait_port;
     pdev->asyncable[ASYNCABLE_DESTROY_ALL_SURFACES][ASYNC] = dev_info.destroy_all_surfaces_async_port;
     pdev->asyncable[ASYNCABLE_DESTROY_ALL_SURFACES][SYNC] = dev_info.destroy_all_surfaces_port;
+    pdev->asyncable[ASYNCABLE_FLUSH_SURFACES][ASYNC] = dev_info.flush_surfaces_async_port;
+    pdev->asyncable[ASYNCABLE_FLUSH_SURFACES][SYNC] = NULL;
 
     pdev->display_event = dev_info.display_event;
     pdev->cursor_event = dev_info.cursor_event;
@@ -769,6 +771,8 @@ static BOOL PrepareHardware(PDev *pdev)
 
     pdev->memslot_del_port = dev_info.memslot_del_port;
 
+    pdev->flush_release_port = dev_info.flush_release_port;
+
     pdev->primary_memory_start = dev_info.surface0_area;
     pdev->primary_memory_size = dev_info.surface0_area_size;
 
diff --git a/display/qxldd.h b/display/qxldd.h
index fcfba29..36df21f 100644
--- a/display/qxldd.h
+++ b/display/qxldd.h
@@ -171,6 +171,7 @@ typedef enum {
     ASYNCABLE_DESTROY_PRIMARY,
     ASYNCABLE_DESTROY_SURFACE,
     ASYNCABLE_DESTROY_ALL_SURFACES,
+    ASYNCABLE_FLUSH_SURFACES,
 
     ASYNCABLE_COUNT
 } asyncable_t;
@@ -323,6 +324,7 @@ typedef struct PDev {
     PUCHAR asyncable[ASYNCABLE_COUNT][2];
     HSEMAPHORE io_sem;
     PUCHAR memslot_del_port;
+    PUCHAR flush_release_port;
 
     UINT8* primary_memory_start;
     UINT32 primary_memory_size;
diff --git a/include/qxl_driver.h b/include/qxl_driver.h
index bff417e..fff350d 100644
--- a/include/qxl_driver.h
+++ b/include/qxl_driver.h
@@ -60,6 +60,8 @@ typedef struct QXLDriverInfo {
     PUCHAR destroy_primary_async_port;
     PUCHAR destroy_surface_async_port;
     PUCHAR destroy_all_surfaces_async_port;
+    PUCHAR flush_surfaces_async_port;
+    PUCHAR flush_release_port;
     PEVENT display_event;
     PEVENT cursor_event;
     PEVENT sleep_event;
diff --git a/miniport/qxl.c b/miniport/qxl.c
index e3e515c..f8621e9 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -981,6 +981,8 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
                 dev_ext->io_port + QXL_IO_DESTROY_SURFACE_ASYNC;
             driver_info->destroy_all_surfaces_async_port =
                 dev_ext->io_port + QXL_IO_DESTROY_ALL_SURFACES_ASYNC;
+            driver_info->flush_surfaces_async_port = dev_ext->io_port + QXL_IO_FLUSH_SURFACES_ASYNC;
+            driver_info->flush_release_port = dev_ext->io_port + QXL_IO_FLUSH_RELEASE;
 
             driver_info->log_port = dev_ext->io_port + QXL_IO_LOG;
             driver_info->log_buf = dev_ext->ram_header->log_buf;
commit d1037d90b3d4ec38efce0da30da61d1e71d65d18
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jul 7 12:58:39 2011 +0200

    asynchronous io port support (introduced in revision 3 of qxl device)
    
    Fixes same issue in RHBZ#700134, but for a windows guest. Requires a revision 3
    pci device, that will be introduced with qemu patches. If the revision is 2 the
    old behavior is maintained, namely using the non asynchronous io ports.
    
    qxl revision 3 (QXL_REVISION_V10) gains support for async io operations for
    
     UPDATE_AREA
     CREATE_PRIMARY
     DESTROY_PRIMARY
     DESTROY_SURFACE_WAIT (not used currently, just exported)
     DESTROY_SURFACES
    
    use that if the revision is 3 or higher.
    
    Async io ports let qemu complete the io without blocking on spice, and issue an
    interrupt when the operation started by the io write is complete. This also means
    less time when the qemu global mutex is held.

diff --git a/display/driver.c b/display/driver.c
index 2c88cc5..d13c6bc 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -32,7 +32,6 @@
 #include "winddi.h"
 #include "devioctl.h"
 #include "ntddvdeo.h"
-#include "ioaccess.h"
 
 #include "qxldd.h"
 #include "utils.h"
@@ -112,7 +111,7 @@ void DebugPrintV(PDev *pdev, const char *message, va_list ap)
         _snprintf(pdev->log_buf, QXL_LOG_BUF_SIZE, QXLDD_DEBUG_PREFIX);
         _vsnprintf(pdev->log_buf + strlen(QXLDD_DEBUG_PREFIX),
                    QXL_LOG_BUF_SIZE - strlen(QXLDD_DEBUG_PREFIX), message, ap);
-        WRITE_PORT_UCHAR(pdev->log_port, 0);
+        sync_io(pdev, pdev->log_port, 0);
         EngReleaseSemaphore(pdev->Res->print_sem);
     } else {
         EngDebugPrint(QXLDD_DEBUG_PREFIX, (PCHAR)message, ap);
@@ -572,19 +571,19 @@ static VOID CreatePrimarySurface(PDev *pdev, UINT32 depth, UINT32 format,
     pdev->primary_surface_create->flags = 0;
     pdev->primary_surface_create->type = QXL_SURF_TYPE_PRIMARY;
 
-    WRITE_PORT_UCHAR(pdev->create_primary_port, 0);
+    async_io(pdev, ASYNCABLE_CREATE_PRIMARY, 0);
 }
 
 static void DestroyPrimarySurface(PDev *pdev)
 {
     HideMouse(pdev);
-    WRITE_PORT_UCHAR(pdev->destroy_primary_port, 0);
+    async_io(pdev, ASYNCABLE_DESTROY_PRIMARY, 0);
 }
 
 static void DestroyAllSurfaces(PDev *pdev)
 {
     HideMouse(pdev);
-    WRITE_PORT_UCHAR(pdev->destroy_all_surfaces_port, 0);
+    async_io(pdev, ASYNCABLE_DESTROY_ALL_SURFACES, 0);
 }
 
 BOOL SetHardwareMode(PDev *pdev)
@@ -622,7 +621,7 @@ static VOID UpdateMainSlot(PDev *pdev, MemSlot *slot)
 
 static void RemoveVRamSlot(PDev *pdev)
 {
-    WRITE_PORT_UCHAR(pdev->memslot_del_port, pdev->vram_mem_slot);
+    sync_io(pdev, pdev->memslot_del_port, pdev->vram_mem_slot);
     pdev->vram_slot_initialized = FALSE;
 }
 
@@ -642,7 +641,7 @@ static BOOLEAN CreateVRamSlot(PDev *pdev)
     *pdev->ram_slot_start = pdev->fb_phys;
     *pdev->ram_slot_end = pdev->fb_phys + pdev->fb_size;
 
-    WRITE_PORT_UCHAR(pdev->memslot_add_port, slot_id);
+    async_io(pdev, ASYNCABLE_MEMSLOT_ADD, slot_id);
 
     pdev->vram_mem_slot = slot_id;
 
@@ -696,9 +695,24 @@ static BOOL PrepareHardware(PDev *pdev)
     pdev->notify_cmd_port = dev_info.notify_cmd_port;
     pdev->notify_cursor_port = dev_info.notify_cursor_port;
     pdev->notify_oom_port = dev_info.notify_oom_port;
+
+    pdev->asyncable[ASYNCABLE_UPDATE_AREA][ASYNC] = dev_info.update_area_async_port;
+    pdev->asyncable[ASYNCABLE_UPDATE_AREA][SYNC] = dev_info.update_area_port;
+    pdev->asyncable[ASYNCABLE_MEMSLOT_ADD][ASYNC] = dev_info.memslot_add_async_port;
+    pdev->asyncable[ASYNCABLE_MEMSLOT_ADD][SYNC] = dev_info.memslot_add_port;
+    pdev->asyncable[ASYNCABLE_CREATE_PRIMARY][ASYNC] = dev_info.create_primary_async_port;
+    pdev->asyncable[ASYNCABLE_CREATE_PRIMARY][SYNC] = dev_info.create_primary_port;
+    pdev->asyncable[ASYNCABLE_DESTROY_PRIMARY][ASYNC] = dev_info.destroy_primary_async_port;
+    pdev->asyncable[ASYNCABLE_DESTROY_PRIMARY][SYNC] = dev_info.destroy_primary_port;
+    pdev->asyncable[ASYNCABLE_DESTROY_SURFACE][ASYNC] = dev_info.destroy_surface_async_port;
+    pdev->asyncable[ASYNCABLE_DESTROY_SURFACE][SYNC] = dev_info.destroy_surface_wait_port;
+    pdev->asyncable[ASYNCABLE_DESTROY_ALL_SURFACES][ASYNC] = dev_info.destroy_all_surfaces_async_port;
+    pdev->asyncable[ASYNCABLE_DESTROY_ALL_SURFACES][SYNC] = dev_info.destroy_all_surfaces_port;
+
     pdev->display_event = dev_info.display_event;
     pdev->cursor_event = dev_info.cursor_event;
     pdev->sleep_event = dev_info.sleep_event;
+    pdev->io_cmd_event = dev_info.io_cmd_event;
 #if (WINVER < 0x0501)
     pdev->WaitForEvent = dev_info.WaitForEvent;
 #endif
@@ -709,7 +723,6 @@ static BOOL PrepareHardware(PDev *pdev)
 
     pdev->dev_update_id = dev_info.update_id;
 
-    pdev->update_area_port = dev_info.update_area_port;
     pdev->update_area = dev_info.update_area;
     pdev->update_surface = dev_info.update_surface;
 
@@ -754,14 +767,8 @@ static BOOL PrepareHardware(PDev *pdev)
     pdev->fb_size = video_mem_Info.FrameBufferLength;
     pdev->fb_phys = dev_info.fb_phys;
 
-    pdev->destroy_surface_wait_port = dev_info.destroy_surface_wait_port;
-    pdev->destroy_all_surfaces_port = dev_info.destroy_all_surfaces_port;
-    pdev->memslot_add_port = dev_info.memslot_add_port;
     pdev->memslot_del_port = dev_info.memslot_del_port;
 
-    pdev->create_primary_port = dev_info.create_primary_port;
-    pdev->destroy_primary_port = dev_info.destroy_primary_port;
-
     pdev->primary_memory_start = dev_info.surface0_area;
     pdev->primary_memory_size = dev_info.surface0_area_size;
 
diff --git a/display/quic.c b/display/quic.c
index 5dc66d4..ee12fab 100644
--- a/display/quic.c
+++ b/display/quic.c
@@ -35,7 +35,6 @@
 #include "winddi.h"
 #include "devioctl.h"
 #include "ntddvdeo.h"
-#include "ioaccess.h"
 
 #include "qxldd.h"
 #include "utils.h"
diff --git a/display/qxldd.h b/display/qxldd.h
index fcfa752..fcfba29 100644
--- a/display/qxldd.h
+++ b/display/qxldd.h
@@ -30,6 +30,7 @@
 #include "windef.h"
 #include "wingdi.h"
 #include "winddi.h"
+#include "ioaccess.h"
 #include "qxl_driver.h"
 #include "mspace.h"
 #if (WINVER < 0x0501)
@@ -158,6 +159,23 @@ enum {
     NUM_MSPACES,
 };
 
+enum {
+    SYNC = 0,
+    ASYNC = 1
+};
+
+typedef enum {
+    ASYNCABLE_UPDATE_AREA = 0,
+    ASYNCABLE_MEMSLOT_ADD,
+    ASYNCABLE_CREATE_PRIMARY,
+    ASYNCABLE_DESTROY_PRIMARY,
+    ASYNCABLE_DESTROY_SURFACE,
+    ASYNCABLE_DESTROY_ALL_SURFACES,
+
+    ASYNCABLE_COUNT
+} asyncable_t;
+
+
 typedef struct PDev PDev;
 
 typedef struct DrawArea {
@@ -267,6 +285,7 @@ typedef struct PDev {
     PEVENT display_event;
     PEVENT cursor_event;
     PEVENT sleep_event;
+    PEVENT io_cmd_event;
 
     PUCHAR log_port;
     UINT8 *log_buf;
@@ -288,7 +307,6 @@ typedef struct PDev {
 
     UINT32 *dev_update_id;
 
-    PUCHAR update_area_port;
     QXLRect *update_area;
     UINT32 *update_surface;
 
@@ -302,12 +320,9 @@ typedef struct PDev {
     PQXLWaitForEvent WaitForEvent;
 #endif
 
-    PUCHAR create_primary_port;
-    PUCHAR destroy_primary_port;
-    PUCHAR destroy_surface_wait_port;
-    PUCHAR memslot_add_port;
+    PUCHAR asyncable[ASYNCABLE_COUNT][2];
+    HSEMAPHORE io_sem;
     PUCHAR memslot_del_port;
-    PUCHAR destroy_all_surfaces_port;
 
     UINT8* primary_memory_start;
     UINT32 primary_memory_size;
@@ -398,4 +413,50 @@ static _inline RingItem *RingGetTail(PDev *pdev, Ring *ring)
     return ret;
 }
 
+#if (WINVER < 0x0501)
+#define WAIT_FOR_EVENT(pdev, event, timeout) (pdev)->WaitForEvent(event, timeout)
+#else
+#define WAIT_FOR_EVENT(pdev, event, timeout) EngWaitForSingleObject(event, timeout)
+#endif
+
+/* Write to an ioport. For some operations we support a new port that returns
+ * immediatly, and completion is signaled by an interrupt that sets io_cmd_event.
+ * If the pci_revision is >= QXL_REVISION_STABLE_V10, we support it, else do
+ * a regular ioport write.
+ */
+static _inline void async_io(PDev *pdev, asyncable_t op, UCHAR val)
+{
+    if (pdev->pci_revision >= QXL_REVISION_STABLE_V10) {
+        EngAcquireSemaphore(pdev->io_sem);
+        WRITE_PORT_UCHAR(pdev->asyncable[op][ASYNC], val);
+        WAIT_FOR_EVENT(pdev, pdev->io_cmd_event, NULL);
+        EngReleaseSemaphore(pdev->io_sem);
+        DEBUG_PRINT((pdev, 3, "finished async %d\n", (int)op));
+    } else {
+        if (pdev->asyncable[op][SYNC] == NULL) {
+            DEBUG_PRINT((pdev, 0, "ERROR: trying calling sync io on NULL port %d\n", op));
+        } else {
+            EngAcquireSemaphore(pdev->io_sem);
+            WRITE_PORT_UCHAR(pdev->asyncable[op][SYNC], val);
+            EngReleaseSemaphore(pdev->io_sem);
+        }
+    }
+}
+
+/*
+ * Before the introduction of QXL_IO_*_ASYNC all io writes would return
+ * only when their function was complete. Since qemu would only allow
+ * a single outstanding io operation between all vcpu threads, they were
+ * also protected from simultaneous calls between different vcpus.
+ *
+ * With the introduction of _ASYNC we need to explicitly lock between different
+ * threads running on different vcpus, this is what this helper accomplishes.
+ */
+static _inline void sync_io(PDev *pdev, PUCHAR port, UCHAR val)
+{
+    EngAcquireSemaphore(pdev->io_sem);
+    WRITE_PORT_UCHAR(port, val);
+    EngReleaseSemaphore(pdev->io_sem);
+}
+
 #endif
diff --git a/display/res.c b/display/res.c
index c69b600..abda771 100644
--- a/display/res.c
+++ b/display/res.c
@@ -21,9 +21,9 @@
 
 #include <ddraw.h>
 #include <dxmini.h>
+#include "qxldd.h"
 #include "os_dep.h"
 #include "res.h"
-#include "ioaccess.h"
 #include "utils.h"
 #include "mspace.h"
 #include "quic.h"
@@ -33,12 +33,6 @@
 #include "devioctl.h"
 #include "ntddvdeo.h"
 
-#if (WINVER < 0x0501)
-#define WAIT_FOR_EVENT(pdev, event, timeout) (pdev)->WaitForEvent(event, timeout)
-#else
-#define WAIT_FOR_EVENT(pdev, event, timeout) EngWaitForSingleObject(event, timeout)
-#endif
-
 static _inline QXLPHYSICAL PA(PDev *pdev, PVOID virt, UINT8 slot_id)
 {
     PMemSlot *p_slot = &pdev->mem_slots[slot_id];
@@ -79,7 +73,7 @@ static BOOL SetClip(PDev *pdev, CLIPOBJ *clip, QXLDrawable *drawable);
     int notify;                                         \
     SPICE_RING_PUSH(pdev->cmd_ring, notify);            \
     if (notify) {                                       \
-        WRITE_PORT_UCHAR(pdev->notify_cmd_port, 0);     \
+        sync_io(pdev, pdev->notify_cmd_port, 0);     \
     }                                                   \
 } while (0);
 
@@ -87,7 +81,7 @@ static BOOL SetClip(PDev *pdev, CLIPOBJ *clip, QXLDrawable *drawable);
     int notify;                                         \
     SPICE_RING_PUSH(pdev->cursor_ring, notify);         \
     if (notify) {                                       \
-        WRITE_PORT_UCHAR(pdev->notify_cursor_port, 0);  \
+        sync_io(pdev, pdev->notify_cursor_port, 0);  \
     }                                                   \
 } while (0);
 
@@ -238,7 +232,7 @@ static void WaitForReleaseRing(PDev* pdev)
             if (!SPICE_RING_IS_EMPTY(pdev->release_ring)) {
                 break;
             }
-            WRITE_PORT_UCHAR(pdev->notify_oom_port, 0);
+            sync_io(pdev, pdev->notify_oom_port, 0);
         }
         SPICE_RING_CONS_WAIT(pdev->release_ring, wait);
 
@@ -263,7 +257,7 @@ static void WaitForReleaseRing(PDev* pdev)
                          pdev->Res->num_cursor_pages));
 #endif
             //oom
-            WRITE_PORT_UCHAR(pdev->notify_oom_port, 0);
+            sync_io(pdev, pdev->notify_oom_port, 0);
         }
     }
     DEBUG_PRINT((pdev, 16, "%s: 0x%lx, done\n", __FUNCTION__, pdev));
@@ -2538,7 +2532,7 @@ void UpdateArea(PDev *pdev, RECTL *area, UINT32 surface_id)
     DEBUG_PRINT((pdev, 12, "%s\n", __FUNCTION__));
     CopyRect(pdev->update_area, area);
     *pdev->update_surface = surface_id;
-    WRITE_PORT_UCHAR(pdev->update_area_port, 0);
+    async_io(pdev, ASYNCABLE_UPDATE_AREA, 0);
 }
 
 #endif
@@ -3273,6 +3267,13 @@ BOOL ResInit(PDev *pdev)
     }
     pdev->quic_data = usr_data;
     pdev->quic_data_sem = EngCreateSemaphore();
+    if (!pdev->quic_data_sem) {
+        PANIC(pdev, "quic_data_sem creation failed\n");
+    }
+    pdev->io_sem = EngCreateSemaphore();
+    if (!pdev->io_sem) {
+        PANIC(pdev, "io_sem creation failed\n");
+    }
 
     return TRUE;
 }
diff --git a/display/surface.c b/display/surface.c
index 0a93abf..4458bc6 100644
--- a/display/surface.c
+++ b/display/surface.c
@@ -32,7 +32,6 @@
 #include "winddi.h"
 #include "devioctl.h"
 #include "ntddvdeo.h"
-#include "ioaccess.h"
 
 #include "qxldd.h"
 #include "utils.h"
diff --git a/include/qxl_driver.h b/include/qxl_driver.h
index 9827a13..bff417e 100644
--- a/include/qxl_driver.h
+++ b/include/qxl_driver.h
@@ -54,9 +54,16 @@ typedef struct QXLDriverInfo {
     PUCHAR notify_cmd_port;
     PUCHAR notify_cursor_port;
     PUCHAR notify_oom_port;
+    PUCHAR update_area_async_port;
+    PUCHAR memslot_add_async_port;
+    PUCHAR create_primary_async_port;
+    PUCHAR destroy_primary_async_port;
+    PUCHAR destroy_surface_async_port;
+    PUCHAR destroy_all_surfaces_async_port;
     PEVENT display_event;
     PEVENT cursor_event;
     PEVENT sleep_event;
+    PEVENT io_cmd_event;
 
     UINT32 num_pages;
     void *io_pages_virt;
diff --git a/miniport/qxl.c b/miniport/qxl.c
index f3ee090..e3e515c 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -86,6 +86,7 @@ typedef struct QXLExtension {
     PEVENT display_event;
     PEVENT cursor_event;
     PEVENT sleep_event;
+    PEVENT io_cmd_event;
 
     MemSlot *mem_slots;
 
@@ -520,6 +521,10 @@ void DevExternsionCleanup(QXLExtension *dev)
         VideoPortDeleteEvent(dev, dev->display_event);
     }
 
+    if (dev->io_cmd_event) {
+        VideoPortDeleteEvent(dev, dev->io_cmd_event);
+    }
+
     if (dev->rom) {
         VideoPortUnmapMemory(dev, dev->rom, NULL);
     }
@@ -551,6 +556,7 @@ VP_STATUS FindAdapter(PVOID dev_extension,
     PEVENT display_event = NULL;
     PEVENT cursor_event = NULL;
     PEVENT sleep_event = NULL;
+    PEVENT io_cmd_event = NULL;
 #if (WINVER >= 0x0501)
     VPOSVERSIONINFO  sys_info;
 #endif
@@ -602,9 +608,19 @@ VP_STATUS FindAdapter(PVOID dev_extension,
         return status;
     }
 
+    if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &io_cmd_event)) != NO_ERROR) {
+        DEBUG_PRINT((0,  "%s: create io_cmd event failed %lu\n",
+                     __FUNCTION__, status));
+        VideoPortDeleteEvent(dev_ext, sleep_event);
+        VideoPortDeleteEvent(dev_ext, display_event);
+        VideoPortDeleteEvent(dev_ext, cursor_event);
+        return status;
+    }
+
     dev_ext->display_event = display_event;
     dev_ext->cursor_event = cursor_event;
     dev_ext->sleep_event = sleep_event;
+    dev_ext->io_cmd_event = io_cmd_event;
 
     if ((status = Prob(dev_ext, conf_info, ranges, QXL_PCI_RANGES)) != NO_ERROR ||
         (status = InitIO(dev_ext, &ranges[QXL_IO_RANGE_INDEX])) != NO_ERROR ||
@@ -948,12 +964,23 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
             driver_info->display_event = dev_ext->display_event;
             driver_info->cursor_event = dev_ext->cursor_event;
             driver_info->sleep_event = dev_ext->sleep_event;
+            driver_info->io_cmd_event = dev_ext->io_cmd_event;
             driver_info->cmd_ring = &dev_ext->ram_header->cmd_ring;
             driver_info->cursor_ring = &dev_ext->ram_header->cursor_ring;
             driver_info->release_ring = &dev_ext->ram_header->release_ring;
             driver_info->notify_cmd_port = dev_ext->io_port + QXL_IO_NOTIFY_CMD;
             driver_info->notify_cursor_port = dev_ext->io_port + QXL_IO_NOTIFY_CURSOR;
             driver_info->notify_oom_port = dev_ext->io_port + QXL_IO_NOTIFY_OOM;
+            driver_info->update_area_async_port = dev_ext->io_port + QXL_IO_UPDATE_AREA_ASYNC;
+            driver_info->memslot_add_async_port = dev_ext->io_port + QXL_IO_MEMSLOT_ADD_ASYNC;
+            driver_info->create_primary_async_port =
+                dev_ext->io_port + QXL_IO_CREATE_PRIMARY_ASYNC;
+            driver_info->destroy_primary_async_port =
+                dev_ext->io_port + QXL_IO_DESTROY_PRIMARY_ASYNC;
+            driver_info->destroy_surface_async_port =
+                dev_ext->io_port + QXL_IO_DESTROY_SURFACE_ASYNC;
+            driver_info->destroy_all_surfaces_async_port =
+                dev_ext->io_port + QXL_IO_DESTROY_ALL_SURFACES_ASYNC;
 
             driver_info->log_port = dev_ext->io_port + QXL_IO_LOG;
             driver_info->log_buf = dev_ext->ram_header->log_buf;
@@ -1023,9 +1050,13 @@ VOID InterruptCallback(PVOID dev_extension, PVOID Context)
 
     if (pending & QXL_INTERRUPT_DISPLAY) {
         VideoPortSetEvent(dev_ext, dev_ext->display_event);
-    } if (pending & QXL_INTERRUPT_CURSOR) {
+    }
+    if (pending & QXL_INTERRUPT_CURSOR) {
         VideoPortSetEvent(dev_ext, dev_ext->cursor_event);
     }
+    if (pending & QXL_INTERRUPT_IO_CMD) {
+        VideoPortSetEvent(dev_ext, dev_ext->io_cmd_event);
+    }
 
     dev_ext->ram_header->int_mask = ~0;
     VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_UPDATE_IRQ, 0);
commit 92b8b4ec837a803c8d5e366a4191b9c203cff18f
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jun 23 13:46:37 2011 +0200

    export pci revision from miniport to display

diff --git a/display/driver.c b/display/driver.c
index f82c744..2c88cc5 100644
--- a/display/driver.c
+++ b/display/driver.c
@@ -689,6 +689,7 @@ static BOOL PrepareHardware(PDev *pdev)
         return FALSE;
     }
 
+    pdev->pci_revision = dev_info.pci_revision;
     pdev->cmd_ring = dev_info.cmd_ring;
     pdev->cursor_ring = dev_info.cursor_ring;
     pdev->release_ring = dev_info.release_ring;
diff --git a/display/qxldd.h b/display/qxldd.h
index 0f90af1..fcfa752 100644
--- a/display/qxldd.h
+++ b/display/qxldd.h
@@ -323,6 +323,8 @@ typedef struct PDev {
 
     UINT32 n_surfaces;
     SurfaceInfo surface0_info;
+
+    UCHAR  pci_revision;
 } PDev;
 
 
diff --git a/include/qxl_driver.h b/include/qxl_driver.h
index b2e1c78..9827a13 100644
--- a/include/qxl_driver.h
+++ b/include/qxl_driver.h
@@ -96,6 +96,8 @@ typedef struct QXLDriverInfo {
     PUCHAR memslot_del_port;
     PUCHAR destroy_all_surfaces_port;
 
+    UCHAR  pci_revision;
+
     UINT32 dev_id;
 
     QXLSurfaceCreate *primary_surface_create;
diff --git a/miniport/qxl.c b/miniport/qxl.c
index 9d8ab36..f3ee090 100644
--- a/miniport/qxl.c
+++ b/miniport/qxl.c
@@ -66,6 +66,8 @@ typedef struct QXLExtension {
     PVOID io_base;
     PUCHAR io_port;
 
+    UCHAR pci_revision;
+
     QXLRom *rom;
     ULONG rom_size;
 
@@ -338,6 +340,7 @@ VP_STATUS Prob(QXLExtension *dev, VIDEO_PORT_CONFIG_INFO *conf_info,
                      __FUNCTION__, pci_conf.RevisionID, QXL_REVISION_STABLE_V06));
         return ERROR_INVALID_PARAMETER;
     }
+    dev->pci_revision = pci_conf.RevisionID;
 
     VideoPortZeroMemory(ranges, sizeof(VIDEO_ACCESS_RANGE) * n_ranges);
     if ((error = VideoPortGetAccessRanges(dev, 0, NULL, n_ranges,
@@ -941,6 +944,7 @@ BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
 
             driver_info = packet->OutputBuffer;
             driver_info->version = QXL_DRIVER_INFO_VERSION;
+            driver_info->pci_revision = dev_ext->pci_revision;
             driver_info->display_event = dev_ext->display_event;
             driver_info->cursor_event = dev_ext->cursor_event;
             driver_info->sleep_event = dev_ext->sleep_event;
commit 9e814a816892e21e7c79f2d9734082d3ce501a65
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jun 23 13:22:02 2011 +0200

    miniport/qxl.inf: support revision >= 2
    
    remove requirement of revision in qxl.inf, the Prob function will still
    error out if revision is 1.

diff --git a/miniport/qxl.inf b/miniport/qxl.inf
index bb7f582..d20778b 100644
--- a/miniport/qxl.inf
+++ b/miniport/qxl.inf
@@ -19,19 +19,19 @@ qxl.Display = 11	; system32
 
 ; WinXP x86 and up
 [q.NTx86]
-%RHAT% %QXL% = qxl, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4&REV_02
+%RHAT% %QXL% = qxl, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
 
 ; WinXP x64 and up
 [q.NTamd64]
-%RHAT% %QXL% = qxl, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4&REV_02
+%RHAT% %QXL% = qxl, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
 
 ; Vista x86 and up
 [q.NTx86.6.0]
-%RHAT% %QXL% = qxl_vista, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4&REV_02
+%RHAT% %QXL% = qxl_vista, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
 
 ; Vista x64 and up
 [q.NTamd64.6.0]
-%RHAT% %QXL% = qxl_vista, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4&REV_02
+%RHAT% %QXL% = qxl_vista, PCI\VEN_1b36&DEV_0100&SUBSYS_11001af4
 
 
 [ControlFlags]


More information about the Spice-commits mailing list