|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v2] Implement device power state transitions.
Implement device power state transition boilerplate so that xenhid can
release its interfaces before the system enters S3. Let hidclass handle
other power types.
Signed-off-by: Troy Crosley <troycrosley@xxxxxxxxx>
---
src/xenhid/fdo.c | 290 +++++++++++++++++++++++++++++++++--
src/xenhid/names.h | 278 +++++++++++++++++++++++++++++++++
src/xenhid/thread.c | 228 +++++++++++++++++++++++++++
src/xenhid/thread.h | 75 +++++++++
vs2015/xenhid/xenhid.vcxproj | 1 +
vs2017/xenhid/xenhid.vcxproj | 1 +
vs2019/xenhid/xenhid.vcxproj | 1 +
7 files changed, 862 insertions(+), 12 deletions(-)
create mode 100644 src/xenhid/names.h
create mode 100644 src/xenhid/thread.c
create mode 100644 src/xenhid/thread.h
diff --git a/src/xenhid/fdo.c b/src/xenhid/fdo.c
index 860c7bc..706fa33 100644
--- a/src/xenhid/fdo.c
+++ b/src/xenhid/fdo.c
@@ -41,10 +41,12 @@
#include <suspend_interface.h>
#include "fdo.h"
+#include "thread.h"
#include "driver.h"
#include "dbg_print.h"
#include "assert.h"
#include "util.h"
+#include "names.h"
#include "string.h"
#define MAXNAMELEN 128
@@ -52,6 +54,9 @@
struct _XENHID_FDO {
PDEVICE_OBJECT DeviceObject;
PDEVICE_OBJECT LowerDeviceObject;
+ PXENHID_THREAD DevicePowerThread;
+ PIRP DevicePowerIrp;
+ DEVICE_POWER_STATE DevicePowerState;
BOOLEAN Enabled;
XENHID_HID_INTERFACE HidInterface;
XENBUS_STORE_INTERFACE StoreInterface;
@@ -220,6 +225,23 @@ __FdoFree(
ExFreePoolWithTag(Buffer, FDO_POOL_TAG);
}
+static FORCEINLINE VOID
+__FdoSetDevicePowerState(
+ IN PXENHID_FDO Fdo,
+ IN DEVICE_POWER_STATE State
+)
+{
+ Fdo->DevicePowerState = State;
+}
+
+static FORCEINLINE DEVICE_POWER_STATE
+__FdoGetDevicePowerState(
+ IN PXENHID_FDO Fdo
+)
+{
+ return Fdo->DevicePowerState;
+}
+
static FORCEINLINE PANSI_STRING
__FdoMultiSzToUpcaseAnsi(
IN PCHAR Buffer
@@ -588,6 +610,8 @@ FdoD3ToD0(
{
NTSTATUS status;
+ ASSERT3U(__FdoGetDevicePowerState(Fdo), ==, PowerDeviceD3);
+
Trace("=====>\n");
if (Fdo->Enabled)
@@ -621,6 +645,7 @@ FdoD3ToD0(
Fdo->Enabled = TRUE;
done:
+ __FdoSetDevicePowerState(Fdo, PowerDeviceD0);
Trace("<=====\n");
return STATUS_SUCCESS;
@@ -659,6 +684,8 @@ FdoD0ToD3(
{
Trace("=====>\n");
+ __FdoSetDevicePowerState(Fdo, PowerDeviceD3);
+
if (!Fdo->Enabled)
goto done;
@@ -868,6 +895,222 @@ FdoDispatchPnp(
return status;
}
+static FORCEINLINE NTSTATUS
+__FdoSetDevicePowerUp(
+ IN PXENHID_FDO Fdo,
+ IN PIRP Irp
+)
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, < , __FdoGetDevicePowerState(Fdo));
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto done;
+
+ Info("%s -> %s\n",
+ PowerDeviceStateName(__FdoGetDevicePowerState(Fdo)),
+ PowerDeviceStateName(DeviceState));
+
+ ASSERT3U(DeviceState, ==, PowerDeviceD0);
+ status = FdoD3ToD0(Fdo);
+ ASSERT(NT_SUCCESS(status));
+
+done:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ Trace("<==== (%08x)\n", status);
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetDevicePowerDown(
+ IN PXENHID_FDO Fdo,
+ IN PIRP Irp
+)
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, > , __FdoGetDevicePowerState(Fdo));
+
+ Info("%s -> %s\n",
+ PowerDeviceStateName(__FdoGetDevicePowerState(Fdo)),
+ PowerDeviceStateName(DeviceState));
+
+ ASSERT3U(DeviceState, ==, PowerDeviceD3);
+
+ if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD0)
+ FdoD0ToD3(Fdo);
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetDevicePower(
+ IN PXENHID_FDO Fdo,
+ IN PIRP Irp
+)
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s:%s)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction));
+
+ ASSERT3U(PowerAction, < , PowerActionShutdown);
+
+ if (DeviceState == __FdoGetDevicePowerState(Fdo)) {
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ goto done;
+ }
+
+ status = (DeviceState < __FdoGetDevicePowerState(Fdo)) ?
+ __FdoSetDevicePowerUp(Fdo, Irp) :
+ __FdoSetDevicePowerDown(Fdo, Irp);
+
+done:
+ Trace("<==== (%s:%s)(%08x)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction),
+ status);
+ return status;
+}
+
+static NTSTATUS
+FdoDevicePower(
+ IN PXENHID_THREAD Self,
+ IN PVOID Context
+)
+{
+ PXENHID_FDO Fdo = (PXENHID_FDO)Context;
+ PKEVENT Event;
+
+ Event = ThreadGetEvent(Self);
+
+ for (;;) {
+ PIRP Irp;
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+
+ if (Fdo->DevicePowerIrp == NULL) {
+ (VOID)KeWaitForSingleObject(Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(Event);
+ }
+
+ if (ThreadIsAlerted(Self))
+ break;
+
+ Irp = Fdo->DevicePowerIrp;
+
+ if (Irp == NULL)
+ continue;
+
+ Fdo->DevicePowerIrp = NULL;
+ KeMemoryBarrier();
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ switch (StackLocation->MinorFunction) {
+ case IRP_MN_SET_POWER:
+ (VOID)__FdoSetDevicePower(Fdo, Irp);
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchPower(
+ IN PXENHID_FDO Fdo,
+ IN PIRP Irp
+)
+{
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+ POWER_STATE_TYPE PowerType;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ if (MinorFunction != IRP_MN_SET_POWER) {
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ goto done;
+ }
+
+ PowerType = StackLocation->Parameters.Power.Type;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ if (PowerAction >= PowerActionShutdown) {
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ goto done;
+ }
+
+ switch (PowerType) {
+ case DevicePowerState:
+ IoMarkIrpPending(Irp);
+
+ ASSERT3P(Fdo->DevicePowerIrp, ==, NULL);
+ Fdo->DevicePowerIrp = Irp;
+ KeMemoryBarrier();
+
+ ThreadWake(Fdo->DevicePowerThread);
+
+ status = STATUS_PENDING;
+ break;
+
+ case SystemPowerState:
+ default:
+ IoSkipCurrentIrpStackLocation(Irp);
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+ break;
+ }
+
+done:
+ return status;
+}
+
static DECLSPEC_NOINLINE NTSTATUS
FdoDispatchInternal(
IN PXENHID_FDO Fdo,
@@ -1031,6 +1274,10 @@ FdoDispatch(
status = FdoDispatchPnp(Fdo, Irp);
break;
+ case IRP_MJ_POWER:
+ status = FdoDispatchPower(Fdo, Irp);
+ break;
+
default:
status = FdoDispatchDefault(Fdo, Irp);
break;
@@ -1118,6 +1365,11 @@ FdoCreate(
Fdo->DeviceObject = DeviceObject;
Fdo->LowerDeviceObject = LowerDeviceObject;
+ Fdo->DevicePowerState = PowerDeviceD3;
+
+ status = ThreadCreate(FdoDevicePower, Fdo, &Fdo->DevicePowerThread);
+ if (!NT_SUCCESS(status))
+ goto fail1;
InitializeListHead(&Fdo->List);
KeInitializeSpinLock(&Fdo->Lock);
@@ -1130,7 +1382,7 @@ FdoCreate(
FdoCsqReleaseLock,
FdoCsqCompleteCanceledIrp);
if (!NT_SUCCESS(status))
- goto fail1;
+ goto fail2;
status = FdoQueryInterface(Fdo,
&GUID_XENBUS_SUSPEND_INTERFACE,
@@ -1138,7 +1390,7 @@ FdoCreate(
(PINTERFACE)&Fdo->SuspendInterface,
sizeof(XENBUS_SUSPEND_INTERFACE));
if (!NT_SUCCESS(status))
- goto fail2;
+ goto fail3;
status = FdoQueryInterface(Fdo,
&GUID_XENBUS_STORE_INTERFACE,
@@ -1146,7 +1398,7 @@ FdoCreate(
(PINTERFACE)&Fdo->StoreInterface,
sizeof(XENBUS_STORE_INTERFACE));
if (!NT_SUCCESS(status))
- goto fail3;
+ goto fail4;
status = FdoQueryInterface(Fdo,
&GUID_XENHID_HID_INTERFACE,
@@ -1154,34 +1406,41 @@ FdoCreate(
(PINTERFACE)&Fdo->HidInterface,
sizeof(XENHID_HID_INTERFACE));
if (!NT_SUCCESS(status))
- goto fail4;
+ goto fail5;
Trace("<=====\n");
return STATUS_SUCCESS;
-fail4:
- Error("fail4\n");
+fail5:
+ Error("fail5\n");
RtlZeroMemory(&Fdo->StoreInterface,
sizeof(XENBUS_STORE_INTERFACE));
-fail3:
- Error("fail3\n");
+fail4:
+ Error("fail4\n");
RtlZeroMemory(&Fdo->SuspendInterface,
sizeof(XENBUS_SUSPEND_INTERFACE));
-fail2:
- Error("fail2\n");
+fail3:
+ Error("fail3\n");
RtlZeroMemory(&Fdo->Queue, sizeof(IO_CSQ));
-fail1:
- Error("fail1 %08x\n", status);
+fail2:
+ Error("fail2 %08x\n", status);
+
+ ThreadAlert(Fdo->DevicePowerThread);
+ ThreadJoin(Fdo->DevicePowerThread);
+ Fdo->DevicePowerThread = NULL;
RtlZeroMemory(&Fdo->List, sizeof(LIST_ENTRY));
RtlZeroMemory(&Fdo->Lock, sizeof(KSPIN_LOCK));
+fail1:
+ Error("fail1 %08x\n", status);
+
Fdo->DeviceObject = NULL;
Fdo->LowerDeviceObject = NULL;
@@ -1202,6 +1461,13 @@ FdoDestroy(
sizeof(XENBUS_SUSPEND_INTERFACE));
RtlZeroMemory(&Fdo->StoreInterface,
sizeof(XENBUS_STORE_INTERFACE));
+
+ ThreadAlert(Fdo->DevicePowerThread);
+ ThreadJoin(Fdo->DevicePowerThread);
+ Fdo->DevicePowerThread = NULL;
+ Fdo->DevicePowerIrp = NULL;
+ Fdo->DevicePowerState = 0;
+
RtlZeroMemory(&Fdo->Queue, sizeof(IO_CSQ));
RtlZeroMemory(&Fdo->List, sizeof(LIST_ENTRY));
RtlZeroMemory(&Fdo->Lock, sizeof(KSPIN_LOCK));
diff --git a/src/xenhid/names.h b/src/xenhid/names.h
new file mode 100644
index 0000000..39e0716
--- /dev/null
+++ b/src/xenhid/names.h
@@ -0,0 +1,278 @@
+/* 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_NAMES_H_
+#define _XENHID_NAMES_H_
+
+#include <ntddk.h>
+
+#include "types.h"
+
+static FORCEINLINE const CHAR *
+PowerTypeName(
+ IN POWER_STATE_TYPE Type
+ )
+{
+#define _POWER_TYPE_NAME(_Type) \
+ case _Type: \
+ return #_Type;
+
+ switch (Type) {
+ _POWER_TYPE_NAME(SystemPowerState);
+ _POWER_TYPE_NAME(DevicePowerState);
+ default:
+ break;
+ }
+
+ return ("UNKNOWN");
+#undef _POWER_ACTION_NAME
+}
+
+static FORCEINLINE const CHAR *
+PowerSystemStateName(
+ IN SYSTEM_POWER_STATE State
+ )
+{
+#define _POWER_SYSTEM_STATE_NAME(_State) \
+ case PowerSystem ## _State: \
+ return #_State;
+
+ switch (State) {
+ _POWER_SYSTEM_STATE_NAME(Unspecified);
+ _POWER_SYSTEM_STATE_NAME(Working);
+ _POWER_SYSTEM_STATE_NAME(Sleeping1);
+ _POWER_SYSTEM_STATE_NAME(Sleeping2);
+ _POWER_SYSTEM_STATE_NAME(Sleeping3);
+ _POWER_SYSTEM_STATE_NAME(Hibernate);
+ _POWER_SYSTEM_STATE_NAME(Shutdown);
+ _POWER_SYSTEM_STATE_NAME(Maximum);
+ default:
+ break;
+ }
+
+ return ("UNKNOWN");
+#undef _POWER_SYSTEM_STATE_NAME
+}
+
+static FORCEINLINE const CHAR *
+PowerDeviceStateName(
+ IN DEVICE_POWER_STATE State
+ )
+{
+#define _POWER_DEVICE_STATE_NAME(_State) \
+ case PowerDevice ## _State: \
+ return #_State;
+
+ switch (State) {
+ _POWER_DEVICE_STATE_NAME(Unspecified);
+ _POWER_DEVICE_STATE_NAME(D0);
+ _POWER_DEVICE_STATE_NAME(D1);
+ _POWER_DEVICE_STATE_NAME(D2);
+ _POWER_DEVICE_STATE_NAME(D3);
+ _POWER_DEVICE_STATE_NAME(Maximum);
+ default:
+ break;
+ }
+
+ return ("UNKNOWN");
+#undef _POWER_DEVICE_STATE_NAME
+}
+
+static FORCEINLINE const CHAR *
+PowerActionName(
+ IN POWER_ACTION Type
+ )
+{
+#define _POWER_ACTION_NAME(_Type) \
+ case PowerAction ## _Type: \
+ return #_Type;
+
+ switch (Type) {
+ _POWER_ACTION_NAME(None);
+ _POWER_ACTION_NAME(Reserved);
+ _POWER_ACTION_NAME(Sleep);
+ _POWER_ACTION_NAME(Hibernate);
+ _POWER_ACTION_NAME(Shutdown);
+ _POWER_ACTION_NAME(ShutdownReset);
+ _POWER_ACTION_NAME(ShutdownOff);
+ _POWER_ACTION_NAME(WarmEject);
+ default:
+ break;
+ }
+
+ return ("UNKNOWN");
+#undef _POWER_ACTION_NAME
+}
+
+static FORCEINLINE const CHAR *
+PowerMinorFunctionName(
+ IN ULONG MinorFunction
+ )
+{
+#define _POWER_MINOR_FUNCTION_NAME(_Function) \
+ case IRP_MN_ ## _Function: \
+ return #_Function;
+
+ switch (MinorFunction) {
+ _POWER_MINOR_FUNCTION_NAME(WAIT_WAKE);
+ _POWER_MINOR_FUNCTION_NAME(POWER_SEQUENCE);
+ _POWER_MINOR_FUNCTION_NAME(SET_POWER);
+ _POWER_MINOR_FUNCTION_NAME(QUERY_POWER);
+
+ default:
+ return "UNKNOWN";
+ }
+
+#undef _POWER_MINOR_FUNCTION_NAME
+}
+
+static FORCEINLINE const CHAR *
+PnpDeviceStateName(
+ IN DEVICE_PNP_STATE State
+ )
+{
+#define _PNP_DEVICE_STATE_NAME(_State) \
+ case _State: \
+ return #_State;
+
+ switch (State) {
+ _PNP_DEVICE_STATE_NAME(Invalid);
+ _PNP_DEVICE_STATE_NAME(Added);
+ _PNP_DEVICE_STATE_NAME(Started);
+ _PNP_DEVICE_STATE_NAME(StopPending);
+ _PNP_DEVICE_STATE_NAME(Stopped);
+ _PNP_DEVICE_STATE_NAME(RemovePending);
+ _PNP_DEVICE_STATE_NAME(SurpriseRemovePending);
+ _PNP_DEVICE_STATE_NAME(Deleted);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _STATE_NAME
+}
+
+static FORCEINLINE const CHAR *
+PnpMinorFunctionName(
+ IN ULONG Function
+ )
+{
+#define _PNP_MINOR_FUNCTION_NAME(_Function) \
+ case IRP_MN_ ## _Function: \
+ return #_Function;
+
+ switch (Function) {
+ _PNP_MINOR_FUNCTION_NAME(START_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_REMOVE_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(REMOVE_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(CANCEL_REMOVE_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(STOP_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_STOP_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(CANCEL_STOP_DEVICE);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_DEVICE_RELATIONS);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_INTERFACE);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_CAPABILITIES);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_RESOURCES);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_RESOURCE_REQUIREMENTS);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_DEVICE_TEXT);
+ _PNP_MINOR_FUNCTION_NAME(FILTER_RESOURCE_REQUIREMENTS);
+ _PNP_MINOR_FUNCTION_NAME(READ_CONFIG);
+ _PNP_MINOR_FUNCTION_NAME(WRITE_CONFIG);
+ _PNP_MINOR_FUNCTION_NAME(EJECT);
+ _PNP_MINOR_FUNCTION_NAME(SET_LOCK);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_ID);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_PNP_DEVICE_STATE);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_BUS_INFORMATION);
+ _PNP_MINOR_FUNCTION_NAME(DEVICE_USAGE_NOTIFICATION);
+ _PNP_MINOR_FUNCTION_NAME(SURPRISE_REMOVAL);
+ _PNP_MINOR_FUNCTION_NAME(QUERY_LEGACY_BUS_INFORMATION);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _PNP_MINOR_FUNCTION_NAME
+}
+
+static FORCEINLINE const CHAR *
+PartialResourceDescriptorTypeName(
+ IN UCHAR Type
+ )
+{
+#define _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(_Type) \
+ case CmResourceType ## _Type: \
+ return #_Type;
+
+ switch (Type) {
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Null);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Port);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Interrupt);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Memory);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Dma);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(DeviceSpecific);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(BusNumber);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(MemoryLarge);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(ConfigData);
+ _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(DevicePrivate);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME
+}
+
+static FORCEINLINE const CHAR *
+DeviceUsageTypeName(
+ IN DEVICE_USAGE_NOTIFICATION_TYPE Type
+ )
+{
+#define _DEVICE_USAGE_TYPE_NAME(_Type) \
+ case DeviceUsageType ## _Type: \
+ return #_Type;
+
+ switch (Type) {
+ _DEVICE_USAGE_TYPE_NAME(Paging);
+ _DEVICE_USAGE_TYPE_NAME(Hibernation);
+ _DEVICE_USAGE_TYPE_NAME(DumpFile);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _DEVICE_USAGE_TYPE_NAME
+}
+
+#endif // _XENHID_NAMES_H_
diff --git a/src/xenhid/thread.c b/src/xenhid/thread.c
new file mode 100644
index 0000000..cdfb976
--- /dev/null
+++ b/src/xenhid/thread.c
@@ -0,0 +1,228 @@
+/* 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.
+ */
+
+#include <ntddk.h>
+
+#include "thread.h"
+#include "util.h"
+#include "dbg_print.h"
+#include "assert.h"
+
+#define THREAD_POOL 'ERHT'
+
+struct _XENHID_THREAD {
+ XENHID_THREAD_FUNCTION Function;
+ PVOID Context;
+ KEVENT Event;
+ BOOLEAN Alerted;
+ LONG References;
+ PKTHREAD Thread;
+};
+
+static FORCEINLINE PVOID
+__ThreadAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocatePoolWithTag(NonPagedPool, Length, THREAD_POOL);
+}
+
+static FORCEINLINE VOID
+__ThreadFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, THREAD_POOL);
+}
+
+static FORCEINLINE VOID
+__ThreadWake(
+ IN PXENHID_THREAD Thread
+ )
+{
+ KeSetEvent(&Thread->Event, IO_NO_INCREMENT, FALSE);
+}
+
+VOID
+ThreadWake(
+ IN PXENHID_THREAD Thread
+ )
+{
+ __ThreadWake(Thread);
+}
+
+static FORCEINLINE VOID
+__ThreadAlert(
+ IN PXENHID_THREAD Thread
+ )
+{
+ Thread->Alerted = TRUE;
+ __ThreadWake(Thread);
+}
+
+VOID
+ThreadAlert(
+ IN PXENHID_THREAD Thread
+ )
+{
+ __ThreadAlert(Thread);
+}
+
+KSTART_ROUTINE ThreadFunction;
+
+VOID
+ThreadFunction(
+ IN PVOID Argument
+ )
+{
+ PXENHID_THREAD Self = Argument;
+ NTSTATUS status;
+
+ status = Self->Function(Self, Self->Context);
+
+ if (InterlockedDecrement(&Self->References) == 0)
+ __ThreadFree(Self);
+
+ PsTerminateSystemThread(status);
+ // NOT REACHED
+}
+
+__drv_requiresIRQL(PASSIVE_LEVEL)
+NTSTATUS
+ThreadCreate(
+ IN XENHID_THREAD_FUNCTION Function,
+ IN PVOID Context,
+ OUT PXENHID_THREAD *Thread
+ )
+{
+ HANDLE Handle;
+ NTSTATUS status;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ (*Thread) = __ThreadAllocate(sizeof (XENHID_THREAD));
+
+ Warning("Create thread %p %p\n", Function, Thread);
+
+ status = STATUS_NO_MEMORY;
+ if (*Thread == NULL)
+ goto fail1;
+
+ (*Thread)->Function = Function;
+ (*Thread)->Context = Context;
+ (*Thread)->Alerted = FALSE;
+ (*Thread)->References = 2; // One for us, one for the thread function
+
+ KeInitializeEvent(&(*Thread)->Event, NotificationEvent, FALSE);
+
+ status = PsCreateSystemThread(&Handle,
+ STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
+ NULL,
+ NULL,
+ NULL,
+ ThreadFunction,
+ *Thread);
+ if (!NT_SUCCESS(status)) {
+ --(*Thread)->References; // Fake thread function termination
+ goto fail2;
+ }
+
+ status = ObReferenceObjectByHandle(Handle,
+ SYNCHRONIZE,
+ *PsThreadType,
+ KernelMode,
+ &(*Thread)->Thread,
+ NULL);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ ZwClose(Handle);
+
+ return STATUS_SUCCESS;
+
+fail3:
+ Error("fail3\n");
+
+ __ThreadAlert(*Thread);
+ ZwClose(Handle);
+
+fail2:
+ Error("fail2\n");
+
+ if (InterlockedDecrement(&(*Thread)->References) == 0)
+ __ThreadFree(*Thread);
+
+ *Thread = NULL;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+PKEVENT
+ThreadGetEvent(
+ IN PXENHID_THREAD Thread
+ )
+{
+ return &Thread->Event;
+}
+
+BOOLEAN
+ThreadIsAlerted(
+ IN PXENHID_THREAD Thread
+ )
+{
+ return Thread->Alerted;
+}
+
+VOID
+ThreadJoin(
+ IN PXENHID_THREAD Thread
+ )
+{
+ LONG References;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+ ASSERT3P(KeGetCurrentThread(), !=, Thread->Thread);
+
+ (VOID) KeWaitForSingleObject(Thread->Thread,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ References = InterlockedDecrement(&Thread->References);
+ ASSERT3U(References, ==, 0);
+
+ __ThreadFree(Thread);
+}
+
diff --git a/src/xenhid/thread.h b/src/xenhid/thread.h
new file mode 100644
index 0000000..30369c0
--- /dev/null
+++ b/src/xenhid/thread.h
@@ -0,0 +1,75 @@
+/* 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_THREAD_H
+#define _XENHID_THREAD_H
+
+#include <ntddk.h>
+
+typedef struct _XENHID_THREAD XENHID_THREAD, *PXENHID_THREAD;
+
+typedef NTSTATUS (*XENHID_THREAD_FUNCTION)(PXENHID_THREAD, PVOID);
+
+__drv_requiresIRQL(PASSIVE_LEVEL)
+extern NTSTATUS
+ThreadCreate(
+ IN XENHID_THREAD_FUNCTION Function,
+ IN PVOID Context,
+ OUT PXENHID_THREAD *Thread
+ );
+
+extern PKEVENT
+ThreadGetEvent(
+ IN PXENHID_THREAD Self
+ );
+
+extern BOOLEAN
+ThreadIsAlerted(
+ IN PXENHID_THREAD Self
+ );
+
+extern VOID
+ThreadWake(
+ IN PXENHID_THREAD Thread
+ );
+
+extern VOID
+ThreadAlert(
+ IN PXENHID_THREAD Thread
+ );
+
+extern VOID
+ThreadJoin(
+ IN PXENHID_THREAD Thread
+ );
+
+#endif // _XENHID_THREAD_H
+
diff --git a/vs2015/xenhid/xenhid.vcxproj b/vs2015/xenhid/xenhid.vcxproj
index 35ba30f..e15b581 100644
--- a/vs2015/xenhid/xenhid.vcxproj
+++ b/vs2015/xenhid/xenhid.vcxproj
@@ -53,6 +53,7 @@
<ItemGroup>
<ClCompile Include="../../src/xenhid/driver.c" />
<ClCompile Include="../../src/xenhid/fdo.c" />
+ <ClCompile Include="../../src/xenhid/thread.c" />
<ClCompile Include="../../src/xenhid/string.c" />
</ItemGroup>
<ItemGroup>
diff --git a/vs2017/xenhid/xenhid.vcxproj b/vs2017/xenhid/xenhid.vcxproj
index a113120..3ecd8d9 100644
--- a/vs2017/xenhid/xenhid.vcxproj
+++ b/vs2017/xenhid/xenhid.vcxproj
@@ -61,6 +61,7 @@
<ItemGroup>
<ClCompile Include="../../src/xenhid/driver.c" />
<ClCompile Include="../../src/xenhid/fdo.c" />
+ <ClCompile Include="../../src/xenhid/thread.c" />
<ClCompile Include="../../src/xenhid/string.c" />
</ItemGroup>
<ItemGroup>
diff --git a/vs2019/xenhid/xenhid.vcxproj b/vs2019/xenhid/xenhid.vcxproj
index 996df2c..4573a59 100644
--- a/vs2019/xenhid/xenhid.vcxproj
+++ b/vs2019/xenhid/xenhid.vcxproj
@@ -61,6 +61,7 @@
<ItemGroup>
<ClCompile Include="../../src/xenhid/driver.c" />
<ClCompile Include="../../src/xenhid/fdo.c" />
+ <ClCompile Include="../../src/xenhid/thread.c" />
<ClCompile Include="../../src/xenhid/string.c" />
</ItemGroup>
<ItemGroup>
--
2.20.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |