[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[win-pv-devel] [PATCH] Report version details to XenStore


  • To: <win-pv-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Owen Smith <owen.smith@xxxxxxxxxx>
  • Date: Mon, 3 Jun 2019 11:35:28 +0100
  • Authentication-results: esa6.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none; spf=None smtp.pra=owen.smith@xxxxxxxxxx; spf=Pass smtp.mailfrom=owen.smith@xxxxxxxxxx; spf=None smtp.helo=postmaster@xxxxxxxxxxxxxxxxxxxxxxxxxx
  • Cc: Owen Smith <owen.smith@xxxxxxxxxx>
  • Delivery-date: Mon, 03 Jun 2019 10:36:05 +0000
  • Ironport-sdr: q2+y6vv60TYkkI2Ec00JFcdaOgOTqxpEoLgYSfakX6ezxIal6qa+AAhZyDt9LJIjnUsLMX4zmQ 4lmkuMTVMyl+tYL2SCfYwPIiHKKwIjIcrmyFZoUuKjjRjxZvb40Y6km7px7YSOlZ637b6HXcjA QVmBnmaq9dqmqhhUHwUSFEX45NmpV66oz6w7Wi/Q/Jo5BkyGengHqCgAR2a+omnM78z9pLSWad hSapngNtSUMgGnF2mThIax1sz/927IKXRHxcMzqyglQbC2L9RoIiTGwy4Blz0A6iRJCIY/zLlk Bi0=
  • List-id: Developer list for the Windows PV Drivers subproject <win-pv-devel.lists.xenproject.org>

Requires adding the XENBUS_STORE and XENBUS_SUSPEND interface to add the
version details, and deal with re-adding after a suspend/resume.

Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx>
---
 include/revision.h           |  11 +-
 include/store_interface.h    | 348 +++++++++++++++++++++++++++++
 include/suspend_interface.h  | 177 +++++++++++++++
 src/coinst/coinst.c          |   2 +-
 src/xenhid.inf               |   6 +-
 src/xenhid/fdo.c             | 510 +++++++++++++++++++++++++++++++++++++++++--
 src/xenhid/string.c          | 467 +++++++++++++++++++++++++++++++++++++++
 src/xenhid/string.h          |  51 +++++
 vs2015/xenhid/xenhid.vcxproj |   1 +
 vs2017/xenhid/xenhid.vcxproj |   1 +
 10 files changed, 1547 insertions(+), 27 deletions(-)
 create mode 100644 include/store_interface.h
 create mode 100644 include/suspend_interface.h
 create mode 100644 src/xenhid/string.c
 create mode 100644 src/xenhid/string.h

diff --git a/include/revision.h b/include/revision.h
index b30aee7..d81a16a 100644
--- a/include/revision.h
+++ b/include/revision.h
@@ -34,12 +34,13 @@
 
 // Key:
 // H  - XENHID_HID_INTERFACE
+// ST - XENBUS_STORE_INTERFACE
+// SU - XENBUS_SUSPEND_INTERFACE
 
 //                    REVISION   H
-#define DEFINE_REVISION_TABLE           \
-    DEFINE_REVISION(0x0800000B,  1),    \
-    DEFINE_REVISION(0x0800000C,  1),    \
-    DEFINE_REVISION(0x0800000D,  1),    \
-    DEFINE_REVISION(0x09000000,  1)
+#define DEFINE_REVISION_TABLE               \
+    DEFINE_REVISION(0x09000000,  1, 0, 0),  \
+    DEFINE_REVISION(0x09000001,  1, 1, 1),  \
+    DEFINE_REVISION(0x09000002,  1, 2, 1)
 
 #endif  // _REVISION_H
diff --git a/include/store_interface.h b/include/store_interface.h
new file mode 100644
index 0000000..52f1a1d
--- /dev/null
+++ b/include/store_interface.h
@@ -0,0 +1,348 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, 
+ * with or without modification, are permitted provided 
+ * that the following conditions are met:
+ * 
+ * *   Redistributions of source code must retain the above 
+ *     copyright notice, this list of conditions and the 
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above 
+ *     copyright notice, this list of conditions and the 
+ *     following disclaimer in the documentation and/or other 
+ *     materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
+ * SUCH DAMAGE.
+ */
+
+/*! \file store_interface.h
+    \brief XENBUS STORE Interface
+
+    This interface provides access to XenStore
+*/
+
+#ifndef _XENBUS_STORE_INTERFACE_H
+#define _XENBUS_STORE_INTERFACE_H
+
+#ifndef _WINDLL
+
+/*! \typedef XENBUS_STORE_TRANSACTION
+    \brief XenStore transaction handle
+*/
+typedef struct _XENBUS_STORE_TRANSACTION    XENBUS_STORE_TRANSACTION, 
*PXENBUS_STORE_TRANSACTION;
+
+/*! \typedef XENBUS_STORE_WATCH
+    \brief XenStore watch handle
+*/
+typedef struct _XENBUS_STORE_WATCH          XENBUS_STORE_WATCH, 
*PXENBUS_STORE_WATCH;
+
+/*! \typedef XENBUS_STORE_PERMISSION_MASK
+    \brief Bitmask of XenStore key permissions
+*/
+typedef enum _XENBUS_STORE_PERMISSION_MASK {
+    XENBUS_STORE_PERM_NONE = 0,
+    XENBUS_STORE_PERM_READ = 1,
+    XENBUS_STORE_PERM_WRITE = 2,
+} XENBUS_STORE_PERMISSION_MASK;
+
+/*! \typedef XENBUS_STORE_PERMISSION
+    \brief XenStore key permissions entry for a single domain
+*/
+typedef struct _XENBUS_STORE_PERMISSION {
+    USHORT                          Domain;
+    XENBUS_STORE_PERMISSION_MASK    Mask;
+} XENBUS_STORE_PERMISSION, *PXENBUS_STORE_PERMISSION;
+
+/*! \typedef XENBUS_STORE_ACQUIRE
+    \brief Acquire a reference to the STORE interface
+
+    \param Interface The interface header
+*/  
+typedef NTSTATUS
+(*XENBUS_STORE_ACQUIRE)(
+    IN  PINTERFACE  Interface
+    );
+
+/*! \typedef XENBUS_STORE_RELEASE
+    \brief Release a reference to the STORE interface
+
+    \param Interface The interface header
+*/  
+typedef VOID
+(*XENBUS_STORE_RELEASE)(
+    IN  PINTERFACE  Interface
+    );
+
+/*! \typedef XENBUS_STORE_FREE
+    \brief Free a memory buffer allocated by the STORE interface
+
+    \param Interface The interface header
+    \param Buffer Pointer to the memory buffer
+*/  
+typedef VOID
+(*XENBUS_STORE_FREE)(
+    IN  PINTERFACE  Interface,
+    IN  PCHAR       Buffer
+    );
+
+/*! \typedef XENBUS_STORE_READ
+    \brief Read a value from XenStore
+
+    \param Interface The interface header
+    \param Transaction The transaction handle (NULL if this read is not
+    part of a transaction)
+    \param Prefix An optional prefix for the \a Node
+    \param Node The concatenation of the \a Prefix and this value specifies
+    the XenStore key to read
+    \param A pointer to a pointer that will be initialized with a memory
+    buffer containing the value read
+
+    The \a Buffer should be freed using \a XENBUS_STORE_FREE
+*/  
+typedef NTSTATUS
+(*XENBUS_STORE_READ)(
+    IN  PINTERFACE                  Interface,
+    IN  PXENBUS_STORE_TRANSACTION   Transaction OPTIONAL,
+    IN  PCHAR                       Prefix OPTIONAL,
+    IN  PCHAR                       Node,
+    OUT PCHAR                       *Buffer
+    );
+
+/*! \typedef XENBUS_STORE_PRINTF
+    \brief Write a value to XenStore
+
+    \param Interface The interface header
+    \param Transaction The transaction handle (NULL if this write is not
+    part of a transaction)
+    \param Prefix An optional prefix for the \a Node
+    \param Node The concatenation of the \a Prefix and this value specifies
+    the XenStore key to write
+    \param Format A format specifier
+    \param ... Additional parameters required by \a Format
+
+    If the \a Node does not exist then it is created
+*/  
+typedef NTSTATUS
+(*XENBUS_STORE_PRINTF)(
+    IN  PINTERFACE                  Interface,
+    IN  PXENBUS_STORE_TRANSACTION   Transaction OPTIONAL,
+    IN  PCHAR                       Prefix OPTIONAL,
+    IN  PCHAR                       Node,
+    IN  const CHAR                  *Format,
+    ...
+    );
+
+/*! \typedef XENBUS_STORE_REMOVE
+    \brief Remove a key from XenStore
+
+    \param Interface The interface header
+    \param Transaction The transaction handle (NULL if this removal is not
+    part of a transaction)
+    \param Prefix An optional prefix for the \a Node
+    \param Node The concatenation of the \a Prefix and this value specifies
+    the XenStore key to remove
+*/  
+typedef NTSTATUS
+(*XENBUS_STORE_REMOVE)(
+    IN  PINTERFACE                  Interface,
+    IN  PXENBUS_STORE_TRANSACTION   Transaction OPTIONAL,
+    IN  PCHAR                       Prefix OPTIONAL,
+    IN  PCHAR                       Node
+    );
+
+/*! \typedef XENBUS_STORE_DIRECTORY
+    \brief Enumerate all immediate child keys of a XenStore key
+
+    \param Interface The interface header
+    \param Transaction The transaction handle (NULL if this removal is not
+    part of a transaction)
+    \param Prefix An optional prefix for the \a Node
+    \param Node The concatenation of the \a Prefix and this value specifies
+    the XenStore key to enumerate
+    \param A pointer to a pointer that will be initialized with a memory
+    buffer containing a NUL separated list of key names
+
+    The \a Buffer should be freed using \a XENBUS_STORE_FREE
+*/  
+typedef NTSTATUS
+(*XENBUS_STORE_DIRECTORY)(
+    IN  PINTERFACE                  Interface,
+    IN  PXENBUS_STORE_TRANSACTION   Transaction OPTIONAL,
+    IN  PCHAR                       Prefix OPTIONAL,
+    IN  PCHAR                       Node,
+    OUT PCHAR                       *Buffer
+    );
+
+/*! \typedef XENBUS_STORE_TRANSACTION_START
+    \brief Start a XenStore transaction
+
+    \param Interface The interface header
+    \param Transaction Pointer to a transaction handle to be initialized
+*/  
+typedef NTSTATUS
+(*XENBUS_STORE_TRANSACTION_START)(
+    IN  PINTERFACE                  Interface,
+    OUT PXENBUS_STORE_TRANSACTION   *Transaction
+    );
+
+/*! \typedef XENBUS_STORE_TRANSACTION_END
+    \brief End a XenStore transaction
+
+    \param Interface The interface header
+    \param Transaction The transaction handle
+    \param Commit Set to TRUE if actions performed within the transaction 
should
+    be made visible, or FALSE if they should not be
+
+    If \a Commit is TRUE and the transaction to found to clash then
+    STATUS_RETRY will be returned
+*/  
+typedef NTSTATUS
+(*XENBUS_STORE_TRANSACTION_END)(
+    IN  PINTERFACE                  Interface,
+    IN  PXENBUS_STORE_TRANSACTION   Transaction,
+    IN  BOOLEAN                     Commit
+    );
+
+/*! \typedef XENBUS_STORE_WATCH_ADD
+    \brief Add a XenStore watch
+
+    \param Interface The interface header
+    \param Prefix An optional prefix for the \a Node
+    \param Node The concatenation of the \a Prefix and this value specifies
+    the XenStore key to watch
+    \param Event A pointer to an event object to be signalled when the
+    watch fires
+    \param Watch A pointer to a watch handle to be initialized
+*/  
+typedef NTSTATUS
+(*XENBUS_STORE_WATCH_ADD)(
+    IN  PINTERFACE          Interface,
+    IN  PCHAR               Prefix OPTIONAL,
+    IN  PCHAR               Node,
+    IN  PKEVENT             Event,
+    OUT PXENBUS_STORE_WATCH *Watch
+    );
+
+/*! \typedef XENBUS_STORE_WATCH_REMOVE
+    \brief Remove a XenStore watch
+
+    \param Interface The interface header
+    \param Watch The watch handle
+*/  
+typedef NTSTATUS
+(*XENBUS_STORE_WATCH_REMOVE)(
+    IN  PINTERFACE          Interface,
+    IN  PXENBUS_STORE_WATCH Watch
+    );
+
+/*! \typedef XENBUS_STORE_POLL
+    \brief Poll for XenStore activity
+
+    \param Interface The interface header
+
+    If it is necessary to spin at DISPATCH_LEVEL waiting for XenStore
+    activity then this will block the normal STORE interface DPC so this
+    method must be regularly invoked during the spin loop to check for
+    XenStore activity
+*/  
+typedef VOID
+(*XENBUS_STORE_POLL)(
+    IN  PINTERFACE  Interface
+    );
+
+/*! \typedef XENBUS_STORE_PERMISSIONS_SET
+    \brief Set permissions for a XenStore key
+
+    \param Interface The interface header
+    \param Transaction The transaction handle (NULL if this is not
+    part of a transaction)
+    \param Prefix An optional prefix for the \a Node
+    \param Node The concatenation of the \a Prefix and this value specifies
+    the XenStore key to set permissions of
+    \param Permissions An array of permissions to set
+    \param NumberPermissions Number of elements in the \a Permissions array
+*/
+typedef NTSTATUS
+(*XENBUS_STORE_PERMISSIONS_SET)(
+    IN  PINTERFACE                  Interface,
+    IN  PXENBUS_STORE_TRANSACTION   Transaction OPTIONAL,
+    IN  PCHAR                       Prefix OPTIONAL,
+    IN  PCHAR                       Node,
+    IN  PXENBUS_STORE_PERMISSION    Permissions,
+    IN  ULONG                       NumberPermissions
+    );
+
+// {86824C3B-D34E-4753-B281-2F1E3AD214D7}
+DEFINE_GUID(GUID_XENBUS_STORE_INTERFACE, 
+0x86824c3b, 0xd34e, 0x4753, 0xb2, 0x81, 0x2f, 0x1e, 0x3a, 0xd2, 0x14, 0xd7);
+
+/*! \struct _XENBUS_STORE_INTERFACE_V1
+    \brief STORE interface version 1
+    \ingroup interfaces
+*/
+struct _XENBUS_STORE_INTERFACE_V1 {
+    INTERFACE                       Interface;
+    XENBUS_STORE_ACQUIRE            StoreAcquire;
+    XENBUS_STORE_RELEASE            StoreRelease;
+    XENBUS_STORE_FREE               StoreFree;
+    XENBUS_STORE_READ               StoreRead;
+    XENBUS_STORE_PRINTF             StorePrintf;
+    XENBUS_STORE_REMOVE             StoreRemove;
+    XENBUS_STORE_DIRECTORY          StoreDirectory;
+    XENBUS_STORE_TRANSACTION_START  StoreTransactionStart;
+    XENBUS_STORE_TRANSACTION_END    StoreTransactionEnd;
+    XENBUS_STORE_WATCH_ADD          StoreWatchAdd;
+    XENBUS_STORE_WATCH_REMOVE       StoreWatchRemove;
+    XENBUS_STORE_POLL               StorePoll;
+};
+
+/*! \struct _XENBUS_STORE_INTERFACE_V2
+    \brief STORE interface version 2
+    \ingroup interfaces
+*/
+struct _XENBUS_STORE_INTERFACE_V2 {
+    INTERFACE                       Interface;
+    XENBUS_STORE_ACQUIRE            StoreAcquire;
+    XENBUS_STORE_RELEASE            StoreRelease;
+    XENBUS_STORE_FREE               StoreFree;
+    XENBUS_STORE_READ               StoreRead;
+    XENBUS_STORE_PRINTF             StorePrintf;
+    XENBUS_STORE_PERMISSIONS_SET    StorePermissionsSet;
+    XENBUS_STORE_REMOVE             StoreRemove;
+    XENBUS_STORE_DIRECTORY          StoreDirectory;
+    XENBUS_STORE_TRANSACTION_START  StoreTransactionStart;
+    XENBUS_STORE_TRANSACTION_END    StoreTransactionEnd;
+    XENBUS_STORE_WATCH_ADD          StoreWatchAdd;
+    XENBUS_STORE_WATCH_REMOVE       StoreWatchRemove;
+    XENBUS_STORE_POLL               StorePoll;
+};
+
+typedef struct _XENBUS_STORE_INTERFACE_V2 XENBUS_STORE_INTERFACE, 
*PXENBUS_STORE_INTERFACE;
+
+/*! \def XENBUS_STORE
+    \brief Macro at assist in method invocation
+*/
+#define XENBUS_STORE(_Method, _Interface, ...)    \
+    (_Interface)->Store ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+
+#endif  // _WINDLL
+
+#define XENBUS_STORE_INTERFACE_VERSION_MIN  1
+#define XENBUS_STORE_INTERFACE_VERSION_MAX  2
+
+#endif  // _XENBUS_STORE_INTERFACE_H
+
diff --git a/include/suspend_interface.h b/include/suspend_interface.h
new file mode 100644
index 0000000..cbe11ab
--- /dev/null
+++ b/include/suspend_interface.h
@@ -0,0 +1,177 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, 
+ * with or without modification, are permitted provided 
+ * that the following conditions are met:
+ * 
+ * *   Redistributions of source code must retain the above 
+ *     copyright notice, this list of conditions and the 
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above 
+ *     copyright notice, this list of conditions and the 
+ *     following disclaimer in the documentation and/or other 
+ *     materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
+ * SUCH DAMAGE.
+ */
+
+/*! \file suspend_interface.h
+    \brief XENBUS SUSPEND Interface
+
+    This interface provides primitives to handle VM suspend/resume
+*/
+
+#ifndef _XENBUS_SUSPEND_INTERFACE_H
+#define _XENBUS_SUSPEND_INTERFACE_H
+
+#ifndef _WINDLL
+
+/*! \enum _XENBUS_SUSPEND_CALLBACK_TYPE
+    \brief Suspend callback type to be registered
+*/
+typedef enum _XENBUS_SUSPEND_CALLBACK_TYPE {
+    SUSPEND_CALLBACK_TYPE_INVALID = 0,
+    SUSPEND_CALLBACK_EARLY,             /*!< Early */
+    SUSPEND_CALLBACK_LATE               /*!< Late */
+} XENBUS_SUSPEND_CALLBACK_TYPE, *PXENBUS_SUSPEND_CALLBACK_TYPE;
+
+/*! \typedef XENBUS_SUSPEND_CALLBACK
+    \brief Suspend callback handle
+*/  
+typedef struct _XENBUS_SUSPEND_CALLBACK   XENBUS_SUSPEND_CALLBACK, 
*PXENBUS_SUSPEND_CALLBACK;
+
+/*! \typedef XENBUS_SUSPEND_ACQUIRE
+    \brief Acquire a reference to the SUSPEND interface
+
+    \param Interface The interface header
+*/  
+typedef NTSTATUS
+(*XENBUS_SUSPEND_ACQUIRE)(
+    IN  PINTERFACE  Interface
+    );
+
+/*! \typedef XENBUS_SUSPEND_RELEASE
+    \brief Release a reference to the SUSPEND interface
+
+    \param Interface The interface header
+*/  
+typedef VOID
+(*XENBUS_SUSPEND_RELEASE)(
+    IN  PINTERFACE  Interface
+    );
+
+/*! \typedef XENBUS_SUSPEND_FUNCTION
+    \brief Suspend callback function
+
+    \param Argument Context \a Argument supplied to \a XENBUS_SUSPEND_REGISTER
+
+    Suspend callback functions are always invoked on one vCPU with all other
+    vCPUs corralled at the same IRQL as the callback. \a Early callback
+    functions are always invoked with IRQL == HIGH_LEVEL and \a Late callback
+    functions are always invoked with IRQL == DISPATCH_LEVEL
+*/  
+typedef VOID
+(*XENBUS_SUSPEND_FUNCTION)(
+    IN  PVOID   Argument
+    );
+
+/*! \typedef XENBUS_SUSPEND_REGISTER
+    \brief Register a suspend callback function
+
+    \param Interface The interface header
+    \param Type The type of callback function to register
+    \param Function The callback function
+    \param Argument An optional context argument passed to the callback
+    \param Callback A pointer to a callback handle to be initialized
+*/  
+typedef NTSTATUS
+(*XENBUS_SUSPEND_REGISTER)(
+    IN  PINTERFACE                      Interface,
+    IN  XENBUS_SUSPEND_CALLBACK_TYPE    Type,
+    IN  XENBUS_SUSPEND_FUNCTION         Function,
+    IN  PVOID                           Argument OPTIONAL,
+    OUT PXENBUS_SUSPEND_CALLBACK        *Callback
+    );
+
+/*! \typedef XENBUS_SUSPEND_DEREGISTER
+    \brief Deregister a suspend callback function
+
+    \param Interface The interface header
+    \param Callback The callback handle
+*/
+typedef VOID
+(*XENBUS_SUSPEND_DEREGISTER)(
+    IN  PINTERFACE                  Interface,
+    IN  PXENBUS_SUSPEND_CALLBACK    Callback
+    );
+
+/*! \typedef XENBUS_SUSPEND_TRIGGER
+    \brief Trigger a VM suspend
+
+    \param Interface The interface header
+
+    This method must always be invoked with IRQL == PASSIVE_LEVEL
+*/
+typedef NTSTATUS
+(*XENBUS_SUSPEND_TRIGGER)(
+    IN  PINTERFACE  Interface
+    );
+
+/*! \typedef XENBUS_SUSPEND_GET_COUNT
+    \brief Get the number of VM suspends that have occurred since boot
+
+    \param Interface The interface header
+    \return The number of VM suspends
+*/
+typedef ULONG
+(*XENBUS_SUSPEND_GET_COUNT)(
+    IN  PINTERFACE  Interface
+    );
+
+// {0554F2AF-B510-4C71-AC03-1C503E394238}
+DEFINE_GUID(GUID_XENBUS_SUSPEND_INTERFACE,
+0x554f2af, 0xb510, 0x4c71, 0xac, 0x3, 0x1c, 0x50, 0x3e, 0x39, 0x42, 0x38);
+
+/*! \struct _XENBUS_SUSPEND_INTERFACE_V1
+    \brief SUSPEND interface version 1
+    \ingroup interfaces
+*/
+struct _XENBUS_SUSPEND_INTERFACE_V1 {
+    INTERFACE                   Interface;
+    XENBUS_SUSPEND_ACQUIRE      Acquire;
+    XENBUS_SUSPEND_RELEASE      Release;
+    XENBUS_SUSPEND_REGISTER     Register;
+    XENBUS_SUSPEND_DEREGISTER   Deregister;
+    XENBUS_SUSPEND_TRIGGER      Trigger;
+    XENBUS_SUSPEND_GET_COUNT    GetCount;
+};
+
+typedef struct _XENBUS_SUSPEND_INTERFACE_V1 XENBUS_SUSPEND_INTERFACE, 
*PXENBUS_SUSPEND_INTERFACE;
+
+/*! \def XENBUS_SUSPEND
+    \brief Macro at assist in method invocation
+*/
+#define XENBUS_SUSPEND(_Method, _Interface, ...)    \
+    (_Interface)-> ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+
+#endif  // _WINDLL
+
+#define XENBUS_SUSPEND_INTERFACE_VERSION_MIN    1
+#define XENBUS_SUSPEND_INTERFACE_VERSION_MAX    1
+
+#endif  // _XENBUS_SUSPEND_INTERFACE_H
+
diff --git a/src/coinst/coinst.c b/src/coinst/coinst.c
index b3368c9..56e566b 100644
--- a/src/coinst/coinst.c
+++ b/src/coinst/coinst.c
@@ -677,7 +677,7 @@ fail1:
     return FALSE;
 }
 
-#define DEFINE_REVISION(_N, _H) \
+#define DEFINE_REVISION(_N, _H, _ST, _SU) \
     (_N)
 
 static DWORD    DeviceRevision[] = {
diff --git a/src/xenhid.inf b/src/xenhid.inf
index d440876..e1f0e28 100644
--- a/src/xenhid.inf
+++ b/src/xenhid.inf
@@ -59,9 +59,9 @@ 
xenhid_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dll
 ; DisplayName          Section         DeviceID
 ; -----------          -------         --------
 
-%XenHidName%           =XenHid_Inst,   
XENVKBD\VEN_@VENDOR_PREFIX@@VENDOR_DEVICE_ID@&DEV_HID&REV_09000000
-%XenHidName%           =XenHid_Inst,   
XENVKBD\VEN_@VENDOR_PREFIX@0001&DEV_HID&REV_09000000
-%XenHidName%           =XenHid_Inst,   
XENVKBD\VEN_@VENDOR_PREFIX@0002&DEV_HID&REV_09000000
+%XenHidName%           =XenHid_Inst,   
XENVKBD\VEN_@VENDOR_PREFIX@@VENDOR_DEVICE_ID@&DEV_HID&REV_09000001
+%XenHidName%           =XenHid_Inst,   
XENVKBD\VEN_@VENDOR_PREFIX@0001&DEV_HID&REV_09000001
+%XenHidName%           =XenHid_Inst,   
XENVKBD\VEN_@VENDOR_PREFIX@0002&DEV_HID&REV_09000001
 
 [XenHid_Inst] 
 CopyFiles=XenHid_Copyfiles
diff --git a/src/xenhid/fdo.c b/src/xenhid/fdo.c
index f70d71a..c897185 100644
--- a/src/xenhid/fdo.c
+++ b/src/xenhid/fdo.c
@@ -34,25 +34,36 @@
 #include <procgrp.h>
 #include <ntstrsafe.h>
 #include <hidport.h>
+#include <version.h>
 
 #include <hid_interface.h>
+#include <store_interface.h>
+#include <suspend_interface.h>
 
 #include "fdo.h"
 #include "driver.h"
 #include "dbg_print.h"
 #include "assert.h"
 #include "util.h"
+#include "string.h"
+
+#define MAXNAMELEN  128
 
 struct _XENHID_FDO {
-    PDEVICE_OBJECT          DeviceObject;
-    PDEVICE_OBJECT          LowerDeviceObject;
-    BOOLEAN                 Enabled;
-    XENHID_HID_INTERFACE    HidInterface;
-    IO_CSQ                  Queue;
-    KSPIN_LOCK              Lock;
-    LIST_ENTRY              List;
+    PDEVICE_OBJECT              DeviceObject;
+    PDEVICE_OBJECT              LowerDeviceObject;
+    BOOLEAN                     Enabled;
+    XENHID_HID_INTERFACE        HidInterface;
+    XENBUS_STORE_INTERFACE      StoreInterface;
+    XENBUS_SUSPEND_INTERFACE    SuspendInterface;
+    PXENBUS_SUSPEND_CALLBACK    SuspendCallback;
+    IO_CSQ                      Queue;
+    KSPIN_LOCK                  Lock;
+    LIST_ENTRY                  List;
 };
 
+#define FDO_POOL_TAG 'ODF'
+
 ULONG
 FdoGetSize(
     VOID
@@ -186,6 +197,390 @@ done:
     return Completed;
 }
 
+
+static FORCEINLINE PVOID
+__FdoAllocate(
+    IN  ULONG   Length
+    )
+{
+    PVOID       Buffer;
+    
+    Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, FDO_POOL_TAG);
+    if (Buffer)
+        RtlZeroMemory(Buffer, Length);
+
+    return Buffer;
+}
+
+static FORCEINLINE VOID
+__FdoFree(
+    IN  PVOID   Buffer
+    )
+{
+    ExFreePoolWithTag(Buffer, FDO_POOL_TAG);
+}
+
+static FORCEINLINE PANSI_STRING
+__FdoMultiSzToUpcaseAnsi(
+    IN  PCHAR       Buffer
+)
+{
+    PANSI_STRING    Ansi;
+    LONG            Index;
+    LONG            Count;
+    NTSTATUS        status;
+
+    Index = 0;
+    Count = 0;
+    for (;;) {
+        if (Buffer[Index] == '\0') {
+            Count++;
+            Index++;
+
+            // Check for double NUL
+            if (Buffer[Index] == '\0')
+                break;
+        }
+        else {
+            Buffer[Index] = __toupper(Buffer[Index]);
+            Index++;
+        }
+    }
+
+    Ansi = __FdoAllocate(sizeof(ANSI_STRING) * (Count + 1));
+
+    status = STATUS_NO_MEMORY;
+    if (Ansi == NULL)
+        goto fail1;
+
+    for (Index = 0; Index < Count; Index++) {
+        ULONG   Length;
+
+        Length = (ULONG)strlen(Buffer);
+        Ansi[Index].MaximumLength = (USHORT)(Length + 1);
+        Ansi[Index].Buffer = __FdoAllocate(Ansi[Index].MaximumLength);
+
+        status = STATUS_NO_MEMORY;
+        if (Ansi[Index].Buffer == NULL)
+            goto fail2;
+
+        RtlCopyMemory(Ansi[Index].Buffer, Buffer, Length);
+        Ansi[Index].Length = (USHORT)Length;
+
+        Buffer += Length + 1;
+    }
+
+    return Ansi;
+
+fail2:
+    Error("fail2\n");
+
+    while (--Index >= 0)
+        __FdoFree(Ansi[Index].Buffer);
+
+    __FdoFree(Ansi);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return NULL;
+}
+
+static FORCEINLINE VOID
+__FdoFreeAnsi(
+    IN  PANSI_STRING    Ansi
+    )
+{
+    ULONG               Index;
+
+    for (Index = 0; Ansi[Index].Buffer != NULL; Index++)
+        __FdoFree(Ansi[Index].Buffer);
+
+    __FdoFree(Ansi);
+}
+
+static FORCEINLINE BOOLEAN
+__FdoMatchDistribution(
+    IN  PXENHID_FDO     Fdo,
+    IN  PCHAR           Buffer
+)
+{
+    PCHAR               Vendor;
+    PCHAR               Product;
+    PCHAR               Context;
+    const CHAR          *Text;
+    BOOLEAN             Match;
+    ULONG               Index;
+    NTSTATUS            status;
+
+    UNREFERENCED_PARAMETER(Fdo);
+
+    status = STATUS_INVALID_PARAMETER;
+
+    Vendor = __strtok_r(Buffer, " ", &Context);
+    if (Vendor == NULL)
+        goto fail1;
+
+    Product = __strtok_r(NULL, " ", &Context);
+    if (Product == NULL)
+        goto fail2;
+
+    Match = TRUE;
+
+    Text = VENDOR_NAME_STR;
+
+    for (Index = 0; Text[Index] != 0; Index++) {
+        if (!isalnum((UCHAR)Text[Index])) {
+            if (Vendor[Index] != '_') {
+                Match = FALSE;
+                break;
+            }
+        } else {
+            if (Vendor[Index] != Text[Index]) {
+                Match = FALSE;
+                break;
+            }
+        }
+    }
+
+    Text = "XENHID";
+
+    if (_stricmp(Product, Text) != 0)
+        Match = FALSE;
+
+    return Match;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return FALSE;
+}
+
+#define MAXIMUM_INDEX   255
+
+static FORCEINLINE NTSTATUS
+__FdoSetDistribution(
+    IN  PXENHID_FDO     Fdo
+    )
+{
+    ULONG               Index;
+    CHAR                Distribution[MAXNAMELEN];
+    CHAR                Vendor[MAXNAMELEN];
+    STRING              String;
+    const CHAR          *Product;
+    NTSTATUS            status;
+
+    Trace("====>\n");
+
+    Index = 0;
+    while (Index <= MAXIMUM_INDEX) {
+        PCHAR   Buffer;
+
+        String.Buffer = Distribution;
+        String.MaximumLength = sizeof(Distribution);
+        String.Length = 0;
+
+        status = StringPrintf(&String,
+                              "%u",
+                              Index);
+        ASSERT(NT_SUCCESS(status));
+
+        status = XENBUS_STORE(Read,
+                              &Fdo->StoreInterface,
+                              NULL,
+                              "drivers",
+                              Distribution,
+                              &Buffer);
+        if (!NT_SUCCESS(status)) {
+            if (status == STATUS_OBJECT_NAME_NOT_FOUND)
+                goto update;
+
+            goto fail1;
+        }
+
+        XENBUS_STORE(Free,
+            &Fdo->StoreInterface,
+            Buffer);
+
+        Index++;
+    }
+
+    status = STATUS_UNSUCCESSFUL;
+    goto fail2;
+
+update:
+    String.Buffer = Vendor;
+    String.MaximumLength = sizeof(Vendor);
+    String.Length = 0;
+
+    status = StringPrintf(&String,
+                          "%s",
+                          VENDOR_NAME_STR);
+    ASSERT(NT_SUCCESS(status));
+
+    for (Index = 0; Vendor[Index] != '\0'; Index++)
+        if (!isalnum((UCHAR)Vendor[Index]))
+            Vendor[Index] = '_';
+
+    Product = "XENHID";
+
+#if DBG
+#define ATTRIBUTES   "(DEBUG)"
+#else
+#define ATTRIBUTES   ""
+#endif
+
+    (VOID)XENBUS_STORE(Printf,
+                       &Fdo->StoreInterface,
+                       NULL,
+                       "drivers",
+                       Distribution,
+                       "%s %s %u.%u.%u.%u %s",
+                       Vendor,
+                       Product,
+                       MAJOR_VERSION,
+                       MINOR_VERSION,
+                       MICRO_VERSION,
+                       BUILD_NUMBER,
+                       ATTRIBUTES
+    );
+
+#undef  ATTRIBUTES
+
+    Trace("<====\n");
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+static FORCEINLINE VOID
+__FdoClearDistribution(
+    IN  PXENHID_FDO     Fdo
+    )
+{
+    PCHAR               Buffer;
+    PANSI_STRING        Distributions;
+    ULONG               Index;
+    NTSTATUS            status;
+
+    Trace("====>\n");
+
+    status = XENBUS_STORE(Directory,
+                          &Fdo->StoreInterface,
+                          NULL,
+                          NULL,
+                          "drivers",
+                          &Buffer);
+    if (NT_SUCCESS(status)) {
+        Distributions = __FdoMultiSzToUpcaseAnsi(Buffer);
+
+        XENBUS_STORE(Free,
+                     &Fdo->StoreInterface,
+                     Buffer);
+    } else {
+        Distributions = NULL;
+    }
+
+    if (Distributions == NULL)
+        goto done;
+
+    for (Index = 0; Distributions[Index].Buffer != NULL; Index++) {
+        PANSI_STRING    Distribution = &Distributions[Index];
+
+        status = XENBUS_STORE(Read,
+                              &Fdo->StoreInterface,
+                              NULL,
+                              "drivers",
+                              Distribution->Buffer,
+                              &Buffer);
+        if (!NT_SUCCESS(status))
+            continue;
+
+        if (__FdoMatchDistribution(Fdo, Buffer))
+            (VOID)XENBUS_STORE(Remove,
+                               &Fdo->StoreInterface,
+                               NULL,
+                               "drivers",
+                               Distribution->Buffer);
+
+        XENBUS_STORE(Free,
+                     &Fdo->StoreInterface,
+                     Buffer);
+    }
+
+    __FdoFreeAnsi(Distributions);
+
+done:
+    Trace("<====\n");
+}
+
+static DECLSPEC_NOINLINE VOID
+FdoSuspendCallback(
+    IN  PVOID       Argument
+    )
+{
+    PXENHID_FDO     Fdo = Argument;
+
+    (VOID)__FdoSetDistribution(Fdo);
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoSetDistribution(
+    IN  PXENHID_FDO Fdo
+    )
+{
+    NTSTATUS            status;
+
+    Trace("====>\n");
+
+    (VOID)__FdoSetDistribution(Fdo);
+
+    status = XENBUS_SUSPEND(Register,
+                            &Fdo->SuspendInterface,
+                            SUSPEND_CALLBACK_LATE,
+                            FdoSuspendCallback,
+                            Fdo,
+                            &Fdo->SuspendCallback);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    Trace("<====\n");
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    __FdoClearDistribution(Fdo);
+
+    return status;
+}
+
+static DECLSPEC_NOINLINE VOID
+FdoClearDistribution(
+    IN  PXENHID_FDO Fdo
+    )
+{
+    Trace("====>\n");
+
+    XENBUS_SUSPEND(Deregister,
+                   &Fdo->SuspendInterface,
+                   Fdo->SuspendCallback);
+    Fdo->SuspendCallback = NULL;
+
+    __FdoClearDistribution(Fdo);
+
+    Trace("<====\n");
+}
+
 static DECLSPEC_NOINLINE NTSTATUS
 FdoD3ToD0(
     IN  PXENHID_FDO Fdo
@@ -198,29 +593,60 @@ FdoD3ToD0(
     if (Fdo->Enabled)
         goto done;
 
+    status = XENBUS_STORE(Acquire,
+                          &Fdo->StoreInterface);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    status = XENBUS_SUSPEND(Acquire,
+                            &Fdo->SuspendInterface);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = FdoSetDistribution(Fdo);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
     status = XENHID_HID(Acquire,
                         &Fdo->HidInterface);
     if (!NT_SUCCESS(status))
-        goto fail1;
+        goto fail4;
 
     status = XENHID_HID(Enable,
                         &Fdo->HidInterface,
                         FdoHidCallback,
                         Fdo);
     if (!NT_SUCCESS(status))
-        goto fail2;
+        goto fail5;
 
     Fdo->Enabled = TRUE;
 done:
     Trace("<=====\n");
     return STATUS_SUCCESS;
 
-fail2:
-    Error("fail2\n");
+fail5:
+    Error("fail5\n");
 
     XENHID_HID(Release,
                &Fdo->HidInterface);
 
+fail4:
+    Error("fail4\n");
+
+    FdoClearDistribution(Fdo);
+
+fail3:
+    Error("fail3\n");
+
+    XENBUS_SUSPEND(Release,
+                   &Fdo->SuspendInterface);
+
+fail2:
+    Error("fail2\n");
+
+    XENBUS_STORE(Release,
+                 &Fdo->StoreInterface);
+
 fail1:
     Error("fail1 %08x\n", status);
     return status;
@@ -242,6 +668,14 @@ FdoD0ToD3(
     XENHID_HID(Release,
                &Fdo->HidInterface);
 
+    FdoClearDistribution(Fdo);
+
+    XENBUS_SUSPEND(Release,
+                   &Fdo->SuspendInterface);
+
+    XENBUS_STORE(Release,
+                 &Fdo->StoreInterface);
+
     Fdo->Enabled = FALSE;
 done:
     Trace("<=====\n");
@@ -606,8 +1040,12 @@ FdoDispatch(
 }
 
 static FORCEINLINE NTSTATUS
-FdoQueryHidInterface(
-    IN  PXENHID_FDO     Fdo
+FdoQueryInterface(
+    IN  PXENHID_FDO     Fdo,
+    IN  const GUID      *Guid,
+    IN  ULONG           Version,
+    OUT PINTERFACE      Interface,
+    IN  ULONG           Size
     )
 {
     KEVENT              Event;
@@ -637,10 +1075,10 @@ FdoQueryHidInterface(
     StackLocation = IoGetNextIrpStackLocation(Irp);
     StackLocation->MinorFunction = IRP_MN_QUERY_INTERFACE;
 
-    StackLocation->Parameters.QueryInterface.InterfaceType = 
&GUID_XENHID_HID_INTERFACE;
-    StackLocation->Parameters.QueryInterface.Size = sizeof 
(XENHID_HID_INTERFACE);
-    StackLocation->Parameters.QueryInterface.Version = 
XENHID_HID_INTERFACE_VERSION_MAX;
-    StackLocation->Parameters.QueryInterface.Interface = 
(PINTERFACE)&Fdo->HidInterface;
+    StackLocation->Parameters.QueryInterface.InterfaceType = Guid;
+    StackLocation->Parameters.QueryInterface.Size = (USHORT)Size;
+    StackLocation->Parameters.QueryInterface.Version = (USHORT)Version;
+    StackLocation->Parameters.QueryInterface.Interface = Interface;
 
     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
 
@@ -694,13 +1132,45 @@ FdoCreate(
     if (!NT_SUCCESS(status))
         goto fail1;
 
-    status = FdoQueryHidInterface(Fdo);
+    status = FdoQueryInterface(Fdo,
+                               &GUID_XENBUS_SUSPEND_INTERFACE,
+                               XENBUS_SUSPEND_INTERFACE_VERSION_MAX,
+                               (PINTERFACE)&Fdo->SuspendInterface,
+                               sizeof(XENBUS_SUSPEND_INTERFACE));
     if (!NT_SUCCESS(status))
         goto fail2;
 
+    status = FdoQueryInterface(Fdo,
+                               &GUID_XENBUS_STORE_INTERFACE,
+                               XENBUS_STORE_INTERFACE_VERSION_MAX,
+                               (PINTERFACE)&Fdo->StoreInterface,
+                               sizeof(XENBUS_STORE_INTERFACE));
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    status = FdoQueryInterface(Fdo,
+                               &GUID_XENHID_HID_INTERFACE,
+                               XENHID_HID_INTERFACE_VERSION_MAX,
+                               (PINTERFACE)&Fdo->HidInterface,
+                               sizeof(XENHID_HID_INTERFACE));
+    if (!NT_SUCCESS(status))
+        goto fail4;
+
     Trace("<=====\n");
     return STATUS_SUCCESS;
 
+fail4:
+    Error("fail4\n");
+
+    RtlZeroMemory(&Fdo->StoreInterface,
+                  sizeof(XENBUS_STORE_INTERFACE));
+
+fail3:
+    Error("fail3\n");
+
+    RtlZeroMemory(&Fdo->SuspendInterface,
+                  sizeof(XENBUS_SUSPEND_INTERFACE));
+
 fail2:
     Error("fail2\n");
 
@@ -728,6 +1198,10 @@ FdoDestroy(
 
     RtlZeroMemory(&Fdo->HidInterface,
                   sizeof(XENHID_HID_INTERFACE));
+    RtlZeroMemory(&Fdo->SuspendInterface,
+                  sizeof(XENBUS_SUSPEND_INTERFACE));
+    RtlZeroMemory(&Fdo->StoreInterface,
+                  sizeof(XENBUS_STORE_INTERFACE));
     RtlZeroMemory(&Fdo->Queue, sizeof(IO_CSQ));
     RtlZeroMemory(&Fdo->List, sizeof(LIST_ENTRY));
     RtlZeroMemory(&Fdo->Lock, sizeof(KSPIN_LOCK));
diff --git a/src/xenhid/string.c b/src/xenhid/string.c
new file mode 100644
index 0000000..7d2f1e3
--- /dev/null
+++ b/src/xenhid/string.c
@@ -0,0 +1,467 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma warning(disable:4152)   // nonstandard extension, function/data 
pointer conversion in expression
+
+#include <ntddk.h>
+
+#include "string.h"
+#include "dbg_print.h"
+#include "assert.h"
+
+static FORCEINLINE NTSTATUS
+__StringPut(
+    IN  PSTRING String,
+    IN  CHAR    Character
+    )
+{
+    if (String->Length >= String->MaximumLength - 1)
+        return STATUS_BUFFER_OVERFLOW;
+
+    String->Buffer[String->Length++] = Character;
+    return STATUS_SUCCESS;
+}
+
+static PCHAR
+FormatNumber(
+    IN  PCHAR       Buffer,
+    IN  ULONGLONG   Value,
+    IN  UCHAR       Base,
+    IN  BOOLEAN     UpperCase
+    )
+{
+    ULONGLONG       Next = Value / Base;
+
+    if (Next != 0)
+        Buffer = FormatNumber(Buffer, Next, Base, UpperCase);
+
+    Value %= Base;
+
+    if (Value < 10)
+        *Buffer++ = '0' + (CHAR)Value;
+    else
+        *Buffer++ = ((UpperCase) ? 'A' : 'a') + (CHAR)(Value - 10);
+
+    *Buffer = '\0';
+
+    return Buffer;
+}
+
+#define FORMAT_NUMBER(_Arguments, _Type, _Character, _Buffer)                  
             \
+        do {                                                                   
             \
+            U ## _Type  _Value = va_arg((_Arguments), U ## _Type);             
             \
+            BOOLEAN     _UpperCase = FALSE;                                    
             \
+            UCHAR       _Base = 0;                                             
             \
+            ULONG       _Index = 0;                                            
             \
+                                                                               
             \
+            if ((_Character) == 'd' && (_Type)_Value < 0) {                    
             \
+                _Value = -((_Type)_Value);                                     
             \
+                (_Buffer)[_Index++] = '-';                                     
             \
+            }                                                                  
             \
+                                                                               
             \
+            switch (_Character) {                                              
             \
+            case 'o':                                                          
             \
+                _Base = 8;                                                     
             \
+                break;                                                         
             \
+                                                                               
             \
+            case 'd':                                                          
             \
+            case 'u':                                                          
             \
+                _Base = 10;                                                    
             \
+                break;                                                         
             \
+                                                                               
             \
+            case 'p':                                                          
             \
+            case 'X':                                                          
             \
+                _UpperCase = TRUE;                                             
             \
+                /* FALLTHRU */                                                 
             \
+                                                                               
             \
+            case 'x':                                                          
             \
+                _Base = 16;                                                    
             \
+                break;                                                         
             \
+            }                                                                  
             \
+                                                                               
             \
+            (VOID) FormatNumber(&(_Buffer)[_Index], (ULONGLONG)_Value, _Base, 
_UpperCase);  \
+        } while (FALSE)
+
+static NTSTATUS
+StringWriteBuffer(
+    IN  PSTRING         String,
+    IN  const CHAR      *Format,
+    IN  va_list         Arguments
+    )
+{
+    CHAR                Character;
+    NTSTATUS            status;
+
+    status = STATUS_SUCCESS;
+
+    while ((Character = *Format++) != '\0') {
+        UCHAR   Pad = 0;
+        UCHAR   Long = 0;
+        BOOLEAN Wide = FALSE;
+        BOOLEAN ZeroPrefix = FALSE;
+        BOOLEAN OppositeJustification = FALSE;
+
+        if (Character != '%') {
+            status = __StringPut(String, Character);
+            if (!NT_SUCCESS(status))
+                goto done;
+
+            continue;
+        }
+
+        Character = *Format++;
+        ASSERT(Character != '\0');
+
+        if (Character == '-') {
+            OppositeJustification = TRUE;
+            Character = *Format++;
+            ASSERT(Character != '\0');
+        }
+
+        if (isdigit((unsigned char)Character)) {
+            ZeroPrefix = (Character == '0') ? TRUE : FALSE;
+
+            while (isdigit((unsigned char)Character)) {
+                Pad = (Pad * 10) + (Character - '0');
+                Character = *Format++;
+                ASSERT(Character != '\0');
+            }
+        }
+
+        while (Character == 'l') {
+            Long++;
+            Character = *Format++;
+            ASSERT(Character == 'd' ||
+                   Character == 'u' ||
+                   Character == 'o' ||
+                   Character == 'x' ||
+                   Character == 'X' ||
+                   Character == 'l');
+        }
+        ASSERT3U(Long, <=, 2);
+
+        while (Character == 'w') {
+            Wide = TRUE;
+            Character = *Format++;
+            ASSERT(Character == 'c' ||
+                   Character == 's' ||
+                   Character == 'Z');
+        }
+
+        switch (Character) {
+        case 'c': {
+            if (Wide) {
+                WCHAR   Value;
+                Value = va_arg(Arguments, WCHAR);
+
+                status = __StringPut(String, (CHAR)Value);
+                if (!NT_SUCCESS(status))
+                    goto done;
+            } else {
+                CHAR    Value;
+
+                Value = va_arg(Arguments, CHAR);
+
+                status = __StringPut(String, Value);
+                if (!NT_SUCCESS(status))
+                    goto done;
+            }
+            break;
+        }
+        case 'p':
+            ZeroPrefix = TRUE;
+            Pad = sizeof (ULONG_PTR) * 2;
+            Long = sizeof (ULONG_PTR) / sizeof (ULONG);
+            /* FALLTHRU */
+
+        case 'd':
+        case 'u':
+        case 'o':
+        case 'x':
+        case 'X': {
+            CHAR    Buffer[23]; // Enough for 8 bytes in octal plus the NUL 
terminator
+            ULONG   Length;
+            ULONG   Index;
+
+            if (Long == 2)
+                FORMAT_NUMBER(Arguments, LONGLONG, Character, Buffer);
+            else
+                FORMAT_NUMBER(Arguments, LONG, Character, Buffer);
+
+            Length = (ULONG)strlen(Buffer);
+            if (!OppositeJustification) {
+                while (Pad > Length) {
+                    status = __StringPut(String, (ZeroPrefix) ? '0' : ' ');
+                    if (!NT_SUCCESS(status))
+                        goto done;
+
+                    --Pad;
+                }
+            }
+
+            for (Index = 0; Index < Length; Index++) {
+                status = __StringPut(String, Buffer[Index]);
+                if (!NT_SUCCESS(status))
+                    goto done;
+            }
+
+            if (OppositeJustification) {
+                while (Pad > Length) {
+                    status = __StringPut(String, ' ');
+                    if (!NT_SUCCESS(status))
+                        goto done;
+
+                    --Pad;
+                }
+            }
+
+            break;
+        }
+        case 's': {
+            if (Wide) {
+                PWCHAR  Value = va_arg(Arguments, PWCHAR);
+                ULONG   Length;
+                ULONG   Index;
+
+                if (Value == NULL)
+                    Value = L"(null)";
+
+                Length = (ULONG)wcslen(Value);
+
+                if (OppositeJustification) {
+                    while (Pad > Length) {
+                        status = __StringPut(String, ' ');
+                        if (!NT_SUCCESS(status))
+                            goto done;
+
+                        --Pad;
+                    }
+                }
+
+                for (Index = 0; Index < Length; Index++) {
+                    status = __StringPut(String, (CHAR)Value[Index]);
+                    if (!NT_SUCCESS(status))
+                        goto done;
+                }
+
+                if (!OppositeJustification) {
+                    while (Pad > Length) {
+                        status = __StringPut(String, ' ');
+                        if (!NT_SUCCESS(status))
+                            goto done;
+
+                        --Pad;
+                    }
+                }
+            } else {
+                PCHAR   Value = va_arg(Arguments, PCHAR);
+                ULONG   Length;
+                ULONG   Index;
+
+                if (Value == NULL)
+                    Value = "(null)";
+
+                Length = (ULONG)strlen(Value);
+
+                if (OppositeJustification) {
+                    while (Pad > Length) {
+                        status = __StringPut(String, ' ');
+                        if (!NT_SUCCESS(status))
+                            goto done;
+
+                        --Pad;
+                    }
+                }
+
+                for (Index = 0; Index < Length; Index++) {
+                    status = __StringPut(String, Value[Index]);
+                    if (!NT_SUCCESS(status))
+                        goto done;
+                }
+
+                if (!OppositeJustification) {
+                    while (Pad > Length) {
+                        status = __StringPut(String, ' ');
+                        if (!NT_SUCCESS(status))
+                            goto done;
+
+                        --Pad;
+                    }
+                }
+            }
+
+            break;
+        }
+        case 'Z': {
+            if (Wide) {
+                PUNICODE_STRING Value = va_arg(Arguments, PUNICODE_STRING);
+                PWCHAR          Buffer;
+                ULONG           Length;
+                ULONG           Index;
+
+                if (Value == NULL) {
+                    Buffer = L"(null)";
+                    Length = sizeof ("(null)") - 1;
+                } else {
+                    Buffer = Value->Buffer;
+                    Length = Value->Length / sizeof (WCHAR);
+                }
+
+                if (OppositeJustification) {
+                    while (Pad > Length) {
+                        status = __StringPut(String, ' ');
+                        if (!NT_SUCCESS(status))
+                            goto done;
+
+                        --Pad;
+                    }
+                }
+
+                for (Index = 0; Index < Length; Index++) {
+                    status = __StringPut(String, (CHAR)Buffer[Index]);
+                    if (!NT_SUCCESS(status))
+                        goto done;
+                }
+
+                if (!OppositeJustification) {
+                    while (Pad > Length) {
+                        status = __StringPut(String, ' ');
+                        if (!NT_SUCCESS(status))
+                            goto done;
+
+                        --Pad;
+                    }
+                }
+            } else {
+                PANSI_STRING Value = va_arg(Arguments, PANSI_STRING);
+                PCHAR        Buffer;
+                ULONG        Length;
+                ULONG        Index;
+
+                if (Value == NULL) {
+                    Buffer = "(null)";
+                    Length = sizeof ("(null)") - 1;
+                } else {
+                    Buffer = Value->Buffer;
+                    Length = Value->Length / sizeof (CHAR);
+                }
+
+                if (OppositeJustification) {
+                    while (Pad > Length) {
+                        status = __StringPut(String, ' ');
+                        if (!NT_SUCCESS(status))
+                            goto done;
+
+                        --Pad;
+                    }
+                }
+
+                for (Index = 0; Index < Length; Index++) {
+                    status = __StringPut(String, Buffer[Index]);
+                    if (!NT_SUCCESS(status))
+                        goto done;
+                }
+
+                if (!OppositeJustification) {
+                    while (Pad > Length) {
+                        status = __StringPut(String, ' ');
+                        if (!NT_SUCCESS(status))
+                            goto done;
+
+                        --Pad;
+                    }
+                }
+            }
+
+            break;
+        }
+        default:
+            status = __StringPut(String, Character);
+            if (!NT_SUCCESS(status))
+                goto done;
+
+            break;
+        }
+    }
+
+done:
+    return status;
+}
+
+NTSTATUS
+StringVPrintf(
+    IN  PSTRING     String,
+    IN  const CHAR  *Format,
+    IN  va_list     Arguments
+    )
+{
+    NTSTATUS        status;
+
+    status = StringWriteBuffer(String,
+                               Format,
+                               Arguments);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    status = __StringPut(String, '\0');
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    // Length should not include the NUL terminator
+    --String->Length;
+
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+NTSTATUS
+StringPrintf(
+    IN  PSTRING     String,
+    IN  const CHAR  *Format,
+    ...
+    )
+{
+    va_list         Arguments;
+    NTSTATUS        status;
+
+    va_start(Arguments, Format);
+    status = StringVPrintf(String, Format, Arguments);
+    va_end(Arguments);
+
+    return status;
+}
diff --git a/src/xenhid/string.h b/src/xenhid/string.h
new file mode 100644
index 0000000..389239e
--- /dev/null
+++ b/src/xenhid/string.h
@@ -0,0 +1,51 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XENHID_STRING_H
+#define _XENHID_STRING_H
+
+#include <ntddk.h>
+
+extern NTSTATUS
+StringVPrintf(
+    IN  PSTRING     String,
+    IN  const CHAR  *Format,
+    IN  va_list     Arguments
+    );
+
+extern NTSTATUS
+StringPrintf(
+    IN  PSTRING     String,
+    IN  const CHAR  *Format,
+    ...
+    );
+
+#endif  // _XENHID_STRING_H
diff --git a/vs2015/xenhid/xenhid.vcxproj b/vs2015/xenhid/xenhid.vcxproj
index 3c2e27d..b0a84ea 100644
--- a/vs2015/xenhid/xenhid.vcxproj
+++ b/vs2015/xenhid/xenhid.vcxproj
@@ -66,6 +66,7 @@
   <ItemGroup>
     <ClCompile Include="../../src/xenhid/driver.c" />
     <ClCompile Include="../../src/xenhid/fdo.c" />
+    <ClCompile Include="../../src/xenhid/string.c" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\..\src\xenhid\xenhid.rc" />
diff --git a/vs2017/xenhid/xenhid.vcxproj b/vs2017/xenhid/xenhid.vcxproj
index 0872aa4..9c3d2b6 100644
--- a/vs2017/xenhid/xenhid.vcxproj
+++ b/vs2017/xenhid/xenhid.vcxproj
@@ -74,6 +74,7 @@
   <ItemGroup>
     <ClCompile Include="../../src/xenhid/driver.c" />
     <ClCompile Include="../../src/xenhid/fdo.c" />
+    <ClCompile Include="../../src/xenhid/string.c" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\..\src\xenhid\xenhid.rc" />
-- 
2.16.2.windows.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/win-pv-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.