// 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)
+// REVISION H ST SU
+#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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
return FALSE;
}
-#define DEFINE_REVISION(_N, _H) \
+#define DEFINE_REVISION(_N, _H, _ST, _SU) \
(_N)
static DWORD DeviceRevision[] = {
; 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
#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
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
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;
XENHID_HID(Release,
&Fdo->HidInterface);
+ FdoClearDistribution(Fdo);
+
+ XENBUS_SUSPEND(Release,
+ &Fdo->SuspendInterface);
+
+ XENBUS_STORE(Release,
+ &Fdo->StoreInterface);
+
Fdo->Enabled = FALSE;
done:
Trace("<=====\n");
}
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;
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;
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");
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));
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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
<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" />
<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" />