[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH 03/14 v2] Add boilerplate Pdo
From: Owen Smith <owen.smith@xxxxxxxxxx> Enumerates a single static RawPdo. Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx> --- src/xencons/driver.c | 8 + src/xencons/driver.h | 12 +- src/xencons/fdo.c | 426 ++++++++- src/xencons/fdo.h | 43 + src/xencons/mutex.h | 82 ++ src/xencons/pdo.c | 1865 ++++++++++++++++++++++++++++++++++++++++ src/xencons/pdo.h | 113 +++ vs2015/xencons/xencons.vcxproj | 1 + vs2017/xencons/xencons.vcxproj | 1 + 9 files changed, 2541 insertions(+), 10 deletions(-) create mode 100755 src/xencons/mutex.h create mode 100755 src/xencons/pdo.c create mode 100755 src/xencons/pdo.h diff --git a/src/xencons/driver.c b/src/xencons/driver.c index 3121b99..5a4d1d3 100644 --- a/src/xencons/driver.c +++ b/src/xencons/driver.c @@ -36,6 +36,7 @@ #include "registry.h" #include "fdo.h" +#include "pdo.h" #include "driver.h" #include "dbg_print.h" #include "assert.h" @@ -208,6 +209,13 @@ Dispatch( status = FdoDispatch(Fdo, Irp); break; } + case PHYSICAL_DEVICE_OBJECT: + { + PXENCONS_PDO Pdo = Dx->Pdo; + + status = PdoDispatch(Pdo, Irp); + break; + } default: ASSERT(FALSE); break; diff --git a/src/xencons/driver.h b/src/xencons/driver.h index 4a2eb61..fb5ece0 100644 --- a/src/xencons/driver.h +++ b/src/xencons/driver.h @@ -50,12 +50,17 @@ DriverGetParametersKey( ); typedef struct _XENCONS_FDO XENCONS_FDO, *PXENCONS_FDO; +typedef struct _XENCONS_PDO XENCONS_PDO, *PXENCONS_PDO; #include "fdo.h" +#include "pdo.h" #define MAX_DEVICE_ID_LEN 200 #define MAX_GUID_STRING_LEN 39 +#pragma warning(push) +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union + typedef struct _XENCONS_DX { PDEVICE_OBJECT DeviceObject; DEVICE_OBJECT_TYPE Type; @@ -72,7 +77,12 @@ typedef struct _XENCONS_DX { LIST_ENTRY ListEntry; - PXENCONS_FDO Fdo; + union { + PXENCONS_FDO Fdo; + PXENCONS_PDO Pdo; + }; } XENCONS_DX, *PXENCONS_DX; +#pragma warning(pop) + #endif // _XENCONS_DRIVER_H diff --git a/src/xencons/fdo.c b/src/xencons/fdo.c index 0170ef6..1c5323c 100644 --- a/src/xencons/fdo.c +++ b/src/xencons/fdo.c @@ -47,6 +47,8 @@ #include "driver.h" #include "registry.h" #include "fdo.h" +#include "pdo.h" +#include "mutex.h" #include "console.h" #include "thread.h" #include "names.h" @@ -85,6 +87,9 @@ struct _XENCONS_FDO { CHAR VendorName[MAXNAMELEN]; + MUTEX Mutex; + ULONG References; + FDO_RESOURCE Resource[RESOURCE_COUNT]; PXENCONS_CONSOLE Console; @@ -210,6 +215,14 @@ __FdoGetPhysicalDeviceObject( return Fdo->PhysicalDeviceObject; } +PDEVICE_OBJECT +FdoGetPhysicalDeviceObject( + IN PXENCONS_FDO Fdo + ) +{ + return __FdoGetPhysicalDeviceObject(Fdo); +} + __drv_requiresIRQL(PASSIVE_LEVEL) static FORCEINLINE NTSTATUS __FdoAcquireLowerBusInterface( @@ -358,6 +371,14 @@ __FdoGetVendorName( return Fdo->VendorName; } +PCHAR +FdoGetVendorName( + IN PXENCONS_FDO Fdo + ) +{ + return __FdoGetVendorName(Fdo); +} + static FORCEINLINE VOID __FdoSetName( IN PXENCONS_FDO Fdo @@ -383,6 +404,99 @@ __FdoGetName( return Dx->Name; } +PCHAR +FdoGetName( + IN PXENCONS_FDO Fdo + ) +{ + return __FdoGetName(Fdo); +} + +__drv_functionClass(IO_COMPLETION_ROUTINE) +__drv_sameIRQL +static NTSTATUS +__FdoDelegateIrp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context + ) +{ + PKEVENT Event = Context; + + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(Irp); + + KeSetEvent(Event, IO_NO_INCREMENT, FALSE); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +FdoDelegateIrp( + IN PXENCONS_FDO Fdo, + IN PIRP Irp + ) +{ + PDEVICE_OBJECT DeviceObject; + PIO_STACK_LOCATION StackLocation; + PIRP SubIrp; + KEVENT Event; + PIO_STACK_LOCATION SubStackLocation; + NTSTATUS status; + + ASSERT3U(KeGetCurrentIrql(), == , PASSIVE_LEVEL); + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + + // Find the top of the FDO stack and hold a reference + DeviceObject = IoGetAttachedDeviceReference(Fdo->Dx->DeviceObject); + + // Get a new IRP for the FDO stack + SubIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + + status = STATUS_NO_MEMORY; + if (SubIrp == NULL) + goto done; + + // Copy in the information from the original IRP + SubStackLocation = IoGetNextIrpStackLocation(SubIrp); + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + RtlCopyMemory(SubStackLocation, StackLocation, + FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine)); + SubStackLocation->Control = 0; + + IoSetCompletionRoutine(SubIrp, + __FdoDelegateIrp, + &Event, + TRUE, + TRUE, + TRUE); + + // Default completion status + SubIrp->IoStatus.Status = Irp->IoStatus.Status; + + status = IoCallDriver(DeviceObject, SubIrp); + if (status == STATUS_PENDING) { + (VOID)KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + status = SubIrp->IoStatus.Status; + } else { + ASSERT3U(status, == , SubIrp->IoStatus.Status); + } + + IoFreeIrp(SubIrp); + +done: + ObDereferenceObject(DeviceObject); + + return status; +} + __drv_functionClass(IO_COMPLETION_ROUTINE) __drv_sameIRQL static NTSTATUS @@ -487,6 +601,99 @@ FdoParseResources( } } +NTSTATUS +FdoAddPhysicalDeviceObject( + IN PXENCONS_FDO Fdo, + IN PXENCONS_PDO Pdo + ) +{ + PDEVICE_OBJECT DeviceObject; + PXENCONS_DX Dx; + NTSTATUS status; + + DeviceObject = PdoGetDeviceObject(Pdo); + Dx = (PXENCONS_DX)DeviceObject->DeviceExtension; + ASSERT3U(Dx->Type, == , PHYSICAL_DEVICE_OBJECT); + + if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD3) + goto done; + + status = PdoResume(Pdo); + if (!NT_SUCCESS(status)) + goto fail1; + +done: + InsertTailList(&Fdo->Dx->ListEntry, &Dx->ListEntry); + ASSERT3U(Fdo->References, != , 0); + Fdo->References++; + + return STATUS_SUCCESS; + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + +VOID +FdoRemovePhysicalDeviceObject( + IN PXENCONS_FDO Fdo, + IN PXENCONS_PDO Pdo + ) +{ + PDEVICE_OBJECT DeviceObject; + PXENCONS_DX Dx; + + DeviceObject = PdoGetDeviceObject(Pdo); + Dx = (PXENCONS_DX)DeviceObject->DeviceExtension; + ASSERT3U(Dx->Type, == , PHYSICAL_DEVICE_OBJECT); + + if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD3) + goto done; + + PdoSuspend(Pdo); + +done: + RemoveEntryList(&Dx->ListEntry); + ASSERT3U(Fdo->References, != , 0); + --Fdo->References; +} + +static FORCEINLINE VOID +__FdoAcquireMutex( + IN PXENCONS_FDO Fdo + ) +{ + AcquireMutex(&Fdo->Mutex); +} + +VOID +FdoAcquireMutex( + IN PXENCONS_FDO Fdo + ) +{ + __FdoAcquireMutex(Fdo); +} + +static FORCEINLINE VOID +__FdoReleaseMutex( + IN PXENCONS_FDO Fdo + ) +{ + ReleaseMutex(&Fdo->Mutex); +} + +VOID +FdoReleaseMutex( + IN PXENCONS_FDO Fdo + ) +{ + __FdoReleaseMutex(Fdo); + + if (Fdo->References == 0) + FdoDestroy(Fdo); +} + static FORCEINLINE PANSI_STRING __FdoMultiSzToUpcaseAnsi( IN PCHAR Buffer @@ -831,9 +1038,9 @@ FdoD3ToD0( IN PXENCONS_FDO Fdo ) { - PXENCONS_DX Dx = Fdo->Dx; POWER_STATE PowerState; KIRQL Irql; + PLIST_ENTRY ListEntry; NTSTATUS status; ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL); @@ -873,11 +1080,27 @@ FdoD3ToD0( DevicePowerState, PowerState); + __FdoAcquireMutex(Fdo); + + for (ListEntry = Fdo->Dx->ListEntry.Flink; + ListEntry != &Fdo->Dx->ListEntry; + ListEntry = ListEntry->Flink) { + PXENCONS_DX Dx = CONTAINING_RECORD(ListEntry, XENCONS_DX, ListEntry); + PXENCONS_PDO Pdo = Dx->Pdo; + + ASSERT3U(Dx->Type, == , PHYSICAL_DEVICE_OBJECT); + + status = PdoResume(Pdo); + ASSERT(NT_SUCCESS(status)); + } + + __FdoReleaseMutex(Fdo); + status = ConsoleD3ToD0(Fdo->Console); ASSERT(NT_SUCCESS(status)); #pragma prefast(suppress:28123) - (VOID) IoSetDeviceInterfaceState(&Dx->Link, TRUE); + (VOID) IoSetDeviceInterfaceState(&Fdo->Dx->Link, TRUE); Trace("<====\n"); @@ -912,8 +1135,8 @@ FdoD0ToD3( IN PXENCONS_FDO Fdo ) { - PXENCONS_DX Dx = Fdo->Dx; POWER_STATE PowerState; + PLIST_ENTRY ListEntry; KIRQL Irql; ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL); @@ -922,10 +1145,29 @@ FdoD0ToD3( Trace("====>\n"); #pragma prefast(suppress:28123) - (VOID) IoSetDeviceInterfaceState(&Dx->Link, FALSE); + (VOID) IoSetDeviceInterfaceState(&Fdo->Dx->Link, FALSE); ConsoleD0ToD3(Fdo->Console); + __FdoAcquireMutex(Fdo); + + for (ListEntry = Fdo->Dx->ListEntry.Flink; + ListEntry != &Fdo->Dx->ListEntry; + ListEntry = ListEntry->Flink) { + PXENCONS_DX Dx = CONTAINING_RECORD(ListEntry, XENCONS_DX, ListEntry); + PXENCONS_PDO Pdo = Dx->Pdo; + + ASSERT3U(Dx->Type, == , PHYSICAL_DEVICE_OBJECT); + + if (PdoGetDevicePnpState(Pdo) == Deleted || + PdoIsMissing(Pdo)) + continue; + + PdoSuspend(Pdo); + } + + __FdoReleaseMutex(Fdo); + PowerState.DeviceState = PowerDeviceD3; PoSetPowerState(Fdo->Dx->DeviceObject, DevicePowerState, @@ -1117,10 +1359,27 @@ FdoSurpriseRemoval( IN PIRP Irp ) { + PLIST_ENTRY ListEntry; NTSTATUS status; __FdoSetDevicePnpState(Fdo, SurpriseRemovePending); + __FdoAcquireMutex(Fdo); + + for (ListEntry = Fdo->Dx->ListEntry.Flink; + ListEntry != &Fdo->Dx->ListEntry; + ListEntry = ListEntry->Flink) { + PXENCONS_DX Dx = CONTAINING_RECORD(ListEntry, XENCONS_DX, ListEntry); + PXENCONS_PDO Pdo = Dx->Pdo; + + ASSERT3U(Dx->Type, == , PHYSICAL_DEVICE_OBJECT); + + if (!PdoIsMissing(Pdo)) + PdoSetMissing(Pdo, "FDO surprise removed"); + } + + __FdoReleaseMutex(Fdo); + Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(Irp); @@ -1135,6 +1394,7 @@ FdoRemoveDevice( IN PIRP Irp ) { + PLIST_ENTRY ListEntry; NTSTATUS status; ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL); @@ -1142,6 +1402,30 @@ FdoRemoveDevice( if (__FdoGetPreviousDevicePnpState(Fdo) != Started) goto done; + __FdoAcquireMutex(Fdo); + + ListEntry = Fdo->Dx->ListEntry.Flink; + while (ListEntry != &Fdo->Dx->ListEntry) { + PLIST_ENTRY Flink = ListEntry->Flink; + PXENCONS_DX Dx = CONTAINING_RECORD(ListEntry, XENCONS_DX, ListEntry); + PXENCONS_PDO Pdo = Dx->Pdo; + + ASSERT3U(Dx->Type, == , PHYSICAL_DEVICE_OBJECT); + + if (!PdoIsMissing(Pdo)) + PdoSetMissing(Pdo, "FDO removed"); + + if (PdoGetDevicePnpState(Pdo) != SurpriseRemovePending) + PdoSetDevicePnpState(Pdo, Deleted); + + if (PdoGetDevicePnpState(Pdo) == Deleted) + PdoDestroy(Pdo); + + ListEntry = Flink; + } + + __FdoReleaseMutex(Fdo); + if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD0) FdoD0ToD3(Fdo); @@ -1157,7 +1441,13 @@ done: IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(Fdo->LowerDeviceObject, Irp); - FdoDestroy(Fdo); + __FdoAcquireMutex(Fdo); + ASSERT3U(Fdo->References, != , 0); + --Fdo->References; + __FdoReleaseMutex(Fdo); + + if (Fdo->References == 0) + FdoDestroy(Fdo); return status; } @@ -1169,16 +1459,110 @@ FdoQueryDeviceRelations( ) { PIO_STACK_LOCATION StackLocation; + ULONG Size; + PDEVICE_RELATIONS Relations; + ULONG Count; + PLIST_ENTRY ListEntry; NTSTATUS status; - ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL); + ASSERT3U(KeGetCurrentIrql(), == , PASSIVE_LEVEL); StackLocation = IoGetCurrentIrpStackLocation(Irp); status = Irp->IoStatus.Status; - IoSkipCurrentIrpStackLocation(Irp); - status = IoCallDriver(Fdo->LowerDeviceObject, Irp); + if (StackLocation->Parameters.QueryDeviceRelations.Type != BusRelations) { + IoSkipCurrentIrpStackLocation(Irp); + status = IoCallDriver(Fdo->LowerDeviceObject, Irp); + + goto done; + } + + __FdoAcquireMutex(Fdo); + + Count = 0; + for (ListEntry = Fdo->Dx->ListEntry.Flink; + ListEntry != &Fdo->Dx->ListEntry; + ListEntry = ListEntry->Flink) + Count++; + + Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + (sizeof(PDEVICE_OBJECT) * __max(Count, 1)); + + Relations = ExAllocatePoolWithTag(PagedPool, Size, FDO_POOL); + + status = STATUS_NO_MEMORY; + if (Relations == NULL) + goto fail1; + + RtlZeroMemory(Relations, Size); + + for (ListEntry = Fdo->Dx->ListEntry.Flink; + ListEntry != &Fdo->Dx->ListEntry; + ListEntry = ListEntry->Flink) { + PXENCONS_DX Dx = CONTAINING_RECORD(ListEntry, XENCONS_DX, ListEntry); + PXENCONS_PDO Pdo = Dx->Pdo; + + ASSERT3U(Dx->Type, == , PHYSICAL_DEVICE_OBJECT); + + if (PdoIsMissing(Pdo)) + continue; + + if (PdoGetDevicePnpState(Pdo) == Present) + PdoSetDevicePnpState(Pdo, Enumerated); + + ObReferenceObject(Dx->DeviceObject); + Relations->Objects[Relations->Count++] = Dx->DeviceObject; + } + + ASSERT3U(Relations->Count, <= , Count); + + Trace("%d PDO(s)\n", Relations->Count); + + __FdoReleaseMutex(Fdo); + + Irp->IoStatus.Information = (ULONG_PTR)Relations; + Irp->IoStatus.Status = STATUS_SUCCESS; + + status = FdoForwardIrpSynchronously(Fdo, Irp); + if (!NT_SUCCESS(status)) + goto fail2; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + __FdoAcquireMutex(Fdo); + + ListEntry = Fdo->Dx->ListEntry.Flink; + while (ListEntry != &Fdo->Dx->ListEntry) { + PXENCONS_DX Dx = CONTAINING_RECORD(ListEntry, XENCONS_DX, ListEntry); + PXENCONS_PDO Pdo = Dx->Pdo; + PLIST_ENTRY Next = ListEntry->Flink; + + ASSERT3U(Dx->Type, == , PHYSICAL_DEVICE_OBJECT); + + if (PdoGetDevicePnpState(Pdo) == Deleted && + PdoIsMissing(Pdo)) + PdoDestroy(Pdo); + + ListEntry = Next; + } + + __FdoReleaseMutex(Fdo); + +done: + return status; + +fail2: + Error("fail2\n"); + + __FdoAcquireMutex(Fdo); + +fail1: + Error("fail1 (%08x)\n", status); + + __FdoReleaseMutex(Fdo); + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } @@ -2469,13 +2853,33 @@ FdoCreate( Dx->Fdo = Fdo; + InitializeMutex(&Fdo->Mutex); + InitializeListHead(&Dx->ListEntry); + Fdo->References = 1; + Info("%p (%s)\n", FunctionDeviceObject, __FdoGetName(Fdo)); + status = PdoCreate(Fdo, NULL); + if (!NT_SUCCESS(status)) + goto fail13; + FunctionDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; return STATUS_SUCCESS; +fail13: + Error("fail13\n"); + + Dx->Fdo = Fdo; + + RtlZeroMemory(&Fdo->Mutex, sizeof(MUTEX)); + RtlZeroMemory(&Dx->ListEntry, sizeof(LIST_ENTRY)); + Fdo->References = 0; + + ConsoleDestroy(Fdo->Console); + Fdo->Console = NULL; + fail12: Error("fail12\n"); @@ -2561,7 +2965,9 @@ FdoDestroy( PXENCONS_DX Dx = Fdo->Dx; PDEVICE_OBJECT FunctionDeviceObject = Dx->DeviceObject; - ASSERT3U(__FdoGetDevicePnpState(Fdo), ==, Deleted); + ASSERT(IsListEmpty(&Dx->ListEntry)); + ASSERT3U(Fdo->References, == , 0); + ASSERT3U(__FdoGetDevicePnpState(Fdo), == , Deleted); Fdo->NotDisableable = FALSE; @@ -2569,6 +2975,8 @@ FdoDestroy( FunctionDeviceObject, __FdoGetName(Fdo)); + RtlZeroMemory(&Fdo->Mutex, sizeof(MUTEX)); + Dx->Fdo = NULL; ConsoleDestroy(Fdo->Console); diff --git a/src/xencons/fdo.h b/src/xencons/fdo.h index 19eaa42..f8ebaf3 100644 --- a/src/xencons/fdo.h +++ b/src/xencons/fdo.h @@ -40,6 +40,49 @@ #include "driver.h" +extern PCHAR +FdoGetVendorName( + IN PXENCONS_FDO Fdo + ); + +extern PCHAR +FdoGetName( + IN PXENCONS_FDO Fdo + ); + +extern NTSTATUS +FdoAddPhysicalDeviceObject( + IN PXENCONS_FDO Fdo, + IN PXENCONS_PDO Pdo + ); + +extern VOID +FdoRemovePhysicalDeviceObject( + IN PXENCONS_FDO Fdo, + IN PXENCONS_PDO Pdo + ); + +extern VOID +FdoAcquireMutex( + IN PXENCONS_FDO Fdo + ); + +extern VOID +FdoReleaseMutex( + IN PXENCONS_FDO Fdo + ); + +extern PDEVICE_OBJECT +FdoGetPhysicalDeviceObject( + IN PXENCONS_FDO Fdo + ); + +extern NTSTATUS +FdoDelegateIrp( + IN PXENCONS_FDO Fdo, + IN PIRP Irp + ); + extern NTSTATUS FdoDispatch( IN PXENCONS_FDO Fdo, diff --git a/src/xencons/mutex.h b/src/xencons/mutex.h new file mode 100755 index 0000000..904b21d --- /dev/null +++ b/src/xencons/mutex.h @@ -0,0 +1,82 @@ +/* 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 _XENCONS_MUTEX_H +#define _XENCONS_MUTEX_H + +#include <ntddk.h> + +#include "assert.h" + +typedef struct _MUTEX { + PKTHREAD Owner; + KEVENT Event; +} MUTEX, *PMUTEX; + +static FORCEINLINE VOID +InitializeMutex( + IN PMUTEX Mutex +) +{ + RtlZeroMemory(Mutex, sizeof(MUTEX)); + + KeInitializeEvent(&Mutex->Event, SynchronizationEvent, TRUE); +} + +static FORCEINLINE VOID +__drv_maxIRQL(PASSIVE_LEVEL) +AcquireMutex( + IN PMUTEX Mutex +) +{ + (VOID)KeWaitForSingleObject(&Mutex->Event, + Executive, + KernelMode, + FALSE, + NULL); + + ASSERT3P(Mutex->Owner, == , NULL); + Mutex->Owner = KeGetCurrentThread(); +} + +static FORCEINLINE VOID +__drv_maxIRQL(PASSIVE_LEVEL) +ReleaseMutex( + IN PMUTEX Mutex +) +{ + ASSERT3P(Mutex->Owner, == , KeGetCurrentThread()); + Mutex->Owner = NULL; + + KeSetEvent(&Mutex->Event, IO_NO_INCREMENT, FALSE); +} + +#endif // _XENCONS_MUTEX_H diff --git a/src/xencons/pdo.c b/src/xencons/pdo.c new file mode 100755 index 0000000..5e90844 --- /dev/null +++ b/src/xencons/pdo.c @@ -0,0 +1,1865 @@ +/* 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. +*/ + +#define INITGUID 1 + +#include <ntddk.h> +#include <wdmguid.h> +#include <ntstrsafe.h> +#include <stdlib.h> + +#include <suspend_interface.h> +#include <version.h> + +#include "driver.h" +#include "names.h" +#include "fdo.h" +#include "pdo.h" +#include "thread.h" +#include "dbg_print.h" +#include "assert.h" +#include "util.h" + +#define PDO_POOL 'ODP' + +#define MAXNAMELEN 128 +#define MAXTEXTLEN 1024 + +struct _XENCONS_PDO { + PXENCONS_DX Dx; + + PXENCONS_THREAD SystemPowerThread; + PIRP SystemPowerIrp; + PXENCONS_THREAD DevicePowerThread; + PIRP DevicePowerIrp; + + PXENCONS_FDO Fdo; + BOOLEAN Missing; + const CHAR *Reason; + LONG Eject; + + XENBUS_SUSPEND_INTERFACE SuspendInterface; + PXENBUS_SUSPEND_CALLBACK SuspendCallbackLate; +}; + +static FORCEINLINE PVOID +__PdoAllocate( + IN ULONG Length + ) +{ + return __AllocatePoolWithTag(NonPagedPool, Length, PDO_POOL); +} + +static FORCEINLINE VOID +__PdoFree( + IN PVOID Buffer + ) +{ + __FreePoolWithTag(Buffer, PDO_POOL); +} + +static FORCEINLINE VOID +__PdoSetDevicePnpState( + IN PXENCONS_PDO Pdo, + IN DEVICE_PNP_STATE State + ) +{ + PXENCONS_DX Dx = Pdo->Dx; + + // We can never transition out of the deleted state + ASSERT(Dx->DevicePnpState != Deleted || State == Deleted); + + Dx->PreviousDevicePnpState = Dx->DevicePnpState; + Dx->DevicePnpState = State; +} + +VOID +PdoSetDevicePnpState( + IN PXENCONS_PDO Pdo, + IN DEVICE_PNP_STATE State + ) +{ + __PdoSetDevicePnpState(Pdo, State); +} + +static FORCEINLINE VOID +__PdoRestoreDevicePnpState( + IN PXENCONS_PDO Pdo, + IN DEVICE_PNP_STATE State + ) +{ + PXENCONS_DX Dx = Pdo->Dx; + + if (Dx->DevicePnpState == State) + Dx->DevicePnpState = Dx->PreviousDevicePnpState; +} + +static FORCEINLINE DEVICE_PNP_STATE +__PdoGetDevicePnpState( + IN PXENCONS_PDO Pdo + ) +{ + PXENCONS_DX Dx = Pdo->Dx; + + return Dx->DevicePnpState; +} + +DEVICE_PNP_STATE +PdoGetDevicePnpState( + IN PXENCONS_PDO Pdo + ) +{ + return __PdoGetDevicePnpState(Pdo); +} + +static FORCEINLINE VOID +__PdoSetSystemPowerState( + IN PXENCONS_PDO Pdo, + IN SYSTEM_POWER_STATE State + ) +{ + PXENCONS_DX Dx = Pdo->Dx; + + Dx->SystemPowerState = State; +} + +static FORCEINLINE SYSTEM_POWER_STATE +__PdoGetSystemPowerState( + IN PXENCONS_PDO Pdo + ) +{ + PXENCONS_DX Dx = Pdo->Dx; + + return Dx->SystemPowerState; +} + +static FORCEINLINE VOID +__PdoSetDevicePowerState( + IN PXENCONS_PDO Pdo, + IN DEVICE_POWER_STATE State + ) +{ + PXENCONS_DX Dx = Pdo->Dx; + + Dx->DevicePowerState = State; +} + +static FORCEINLINE DEVICE_POWER_STATE +__PdoGetDevicePowerState( + IN PXENCONS_PDO Pdo + ) +{ + PXENCONS_DX Dx = Pdo->Dx; + + return Dx->DevicePowerState; +} + +static FORCEINLINE VOID +__PdoSetMissing( + IN PXENCONS_PDO Pdo, + IN const CHAR *Reason + ) +{ + Pdo->Reason = Reason; + Pdo->Missing = TRUE; +} + +VOID +PdoSetMissing( + IN PXENCONS_PDO Pdo, + IN const CHAR *Reason + ) +{ + __PdoSetMissing(Pdo, Reason); +} + +static FORCEINLINE BOOLEAN +__PdoIsMissing( + IN PXENCONS_PDO Pdo + ) +{ + return Pdo->Missing; +} + +BOOLEAN +PdoIsMissing( + IN PXENCONS_PDO Pdo + ) +{ + return __PdoIsMissing(Pdo); +} + +static FORCEINLINE PDEVICE_OBJECT +__PdoGetDeviceObject( + IN PXENCONS_PDO Pdo + ) +{ + PXENCONS_DX Dx = Pdo->Dx; + + return (Dx->DeviceObject); +} + +PDEVICE_OBJECT +PdoGetDeviceObject( + IN PXENCONS_PDO Pdo + ) +{ + return __PdoGetDeviceObject(Pdo); +} + +static FORCEINLINE PXENCONS_FDO +__PdoGetFdo( + IN PXENCONS_PDO Pdo + ) +{ + return Pdo->Fdo; +} + +PXENCONS_FDO +PdoGetFdo( + IN PXENCONS_PDO Pdo + ) +{ + return __PdoGetFdo(Pdo); +} + +static FORCEINLINE VOID +__PdoSetName( + IN PXENCONS_PDO Pdo, + IN PANSI_STRING Device + ) +{ + PXENCONS_DX Dx = Pdo->Dx; + NTSTATUS status; + + if (Device == NULL) + status = RtlStringCbPrintfA(Dx->Name, + MAX_DEVICE_ID_LEN, + "0"); + else + status = RtlStringCbPrintfA(Dx->Name, + MAX_DEVICE_ID_LEN, + "%Z", + Device); + ASSERT(NT_SUCCESS(status)); +} + +static FORCEINLINE PCHAR +__PdoGetName( + IN PXENCONS_PDO Pdo + ) +{ + PXENCONS_DX Dx = Pdo->Dx; + + return Dx->Name; +} + +static FORCEINLINE PCHAR +__PdoGetVendorName( + IN PXENCONS_PDO Pdo + ) +{ + return FdoGetVendorName(__PdoGetFdo(Pdo)); +} + +static FORCEINLINE BOOLEAN +__PdoSetEjectRequested( + IN PXENCONS_PDO Pdo + ) +{ + return (InterlockedBitTestAndSet(&Pdo->Eject, 0) == 0) ? TRUE : FALSE; +} + +VOID +PdoRequestEject( + IN PXENCONS_PDO Pdo + ) +{ + PXENCONS_DX Dx = Pdo->Dx; + PDEVICE_OBJECT PhysicalDeviceObject = Dx->DeviceObject; + PXENCONS_FDO Fdo = __PdoGetFdo(Pdo); + + if (!__PdoSetEjectRequested(Pdo)) + return; + + Info("%p (%s)\n", + PhysicalDeviceObject, + __PdoGetName(Pdo)); + + IoInvalidateDeviceRelations(FdoGetPhysicalDeviceObject(Fdo), + BusRelations); +} + +static FORCEINLINE BOOLEAN +__PdoClearEjectRequested( + IN PXENCONS_PDO Pdo + ) +{ + return (InterlockedBitTestAndReset(&Pdo->Eject, 0) != 0) ? TRUE : FALSE; +} + +static FORCEINLINE BOOLEAN +__PdoIsEjectRequested( + IN PXENCONS_PDO Pdo + ) +{ + KeMemoryBarrier(); + return (Pdo->Eject & 1) ? TRUE : FALSE; +} + +BOOLEAN +PdoIsEjectRequested( + IN PXENCONS_PDO Pdo + ) +{ + return __PdoIsEjectRequested(Pdo); +} + +static FORCEINLINE NTSTATUS +__PdoD3ToD0( + IN PXENCONS_PDO Pdo + ) +{ + POWER_STATE PowerState; + + Trace("(%s) ====>\n", __PdoGetName(Pdo)); + + ASSERT3U(KeGetCurrentIrql(), == , DISPATCH_LEVEL); + ASSERT3U(__PdoGetDevicePowerState(Pdo), == , PowerDeviceD3); + + __PdoSetDevicePowerState(Pdo, PowerDeviceD0); + + PowerState.DeviceState = PowerDeviceD0; + PoSetPowerState(__PdoGetDeviceObject(Pdo), + DevicePowerState, + PowerState); + + Trace("(%s) <====\n", __PdoGetName(Pdo)); + + return STATUS_SUCCESS; +} + +static FORCEINLINE VOID +__PdoD0ToD3( + IN PXENCONS_PDO Pdo + ) +{ + POWER_STATE PowerState; + + Trace("(%s) ====>\n", __PdoGetName(Pdo)); + + ASSERT3U(KeGetCurrentIrql(), == , DISPATCH_LEVEL); + ASSERT3U(__PdoGetDevicePowerState(Pdo), == , PowerDeviceD0); + + PowerState.DeviceState = PowerDeviceD3; + PoSetPowerState(__PdoGetDeviceObject(Pdo), + DevicePowerState, + PowerState); + + __PdoSetDevicePowerState(Pdo, PowerDeviceD3); + + Trace("(%s) <====\n", __PdoGetName(Pdo)); +} + +static DECLSPEC_NOINLINE VOID +PdoSuspendCallbackLate( + IN PVOID Argument + ) +{ + PXENCONS_PDO Pdo = Argument; + NTSTATUS status; + + __PdoD0ToD3(Pdo); + + status = __PdoD3ToD0(Pdo); + ASSERT(NT_SUCCESS(status)); +} + +// This function must not touch pageable code or data +static DECLSPEC_NOINLINE NTSTATUS +PdoD3ToD0( + IN PXENCONS_PDO Pdo + ) +{ + KIRQL Irql; + NTSTATUS status; + + Trace("(%s) ====>\n", __PdoGetName(Pdo)); + + ASSERT3U(KeGetCurrentIrql(), == , PASSIVE_LEVEL); + + KeRaiseIrql(DISPATCH_LEVEL, &Irql); + + status = XENBUS_SUSPEND(Acquire, &Pdo->SuspendInterface); + if (!NT_SUCCESS(status)) + goto fail1; + + status = __PdoD3ToD0(Pdo); + if (!NT_SUCCESS(status)) + goto fail2; + + status = XENBUS_SUSPEND(Register, + &Pdo->SuspendInterface, + SUSPEND_CALLBACK_LATE, + PdoSuspendCallbackLate, + Pdo, + &Pdo->SuspendCallbackLate); + if (!NT_SUCCESS(status)) + goto fail3; + + KeLowerIrql(Irql); + + Trace("(%s) <====\n", __PdoGetName(Pdo)); + + return STATUS_SUCCESS; + +fail3: + Error("fail3\n"); + + __PdoD0ToD3(Pdo); + +fail2: + Error("fail2\n"); + + XENBUS_SUSPEND(Release, &Pdo->SuspendInterface); + +fail1: + Error("fail1 (%08x)\n", status); + + KeLowerIrql(Irql); + + return status; +} + +// This function must not touch pageable code or data +static DECLSPEC_NOINLINE VOID +PdoD0ToD3( + IN PXENCONS_PDO Pdo + ) +{ + KIRQL Irql; + + Trace("(%s) ====>\n", __PdoGetName(Pdo)); + + ASSERT3U(KeGetCurrentIrql(), == , PASSIVE_LEVEL); + + KeRaiseIrql(DISPATCH_LEVEL, &Irql); + + XENBUS_SUSPEND(Deregister, + &Pdo->SuspendInterface, + Pdo->SuspendCallbackLate); + Pdo->SuspendCallbackLate = NULL; + + __PdoD0ToD3(Pdo); + + XENBUS_SUSPEND(Release, &Pdo->SuspendInterface); + + KeLowerIrql(Irql); + + Trace("(%s) <====\n", __PdoGetName(Pdo)); +} + +// This function must not touch pageable code or data +static DECLSPEC_NOINLINE VOID +PdoS4ToS3( + IN PXENCONS_PDO Pdo + ) +{ + Trace("(%s) ====>\n", __PdoGetName(Pdo)); + + ASSERT3U(KeGetCurrentIrql(), == , PASSIVE_LEVEL); + ASSERT3U(__PdoGetSystemPowerState(Pdo), == , PowerSystemHibernate); + + __PdoSetSystemPowerState(Pdo, PowerSystemSleeping3); + + Trace("(%s) <====\n", __PdoGetName(Pdo)); +} + +// This function must not touch pageable code or data +static DECLSPEC_NOINLINE VOID +PdoS3ToS4( + IN PXENCONS_PDO Pdo + ) +{ + Trace("(%s) ====>\n", __PdoGetName(Pdo)); + + ASSERT3U(KeGetCurrentIrql(), == , PASSIVE_LEVEL); + ASSERT3U(__PdoGetSystemPowerState(Pdo), == , PowerSystemSleeping3); + + __PdoSetSystemPowerState(Pdo, PowerSystemHibernate); + + Trace("(%s) <====\n", __PdoGetName(Pdo)); +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoStartDevice( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + NTSTATUS status; + + status = PdoD3ToD0(Pdo); + if (!NT_SUCCESS(status)) + goto fail1; + + __PdoSetDevicePnpState(Pdo, Started); + + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return STATUS_SUCCESS; + +fail1: + Error("fail1 (%08x)\n", status); + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoQueryStopDevice( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + NTSTATUS status; + + __PdoSetDevicePnpState(Pdo, StopPending); + status = STATUS_SUCCESS; + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoCancelStopDevice( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + NTSTATUS status; + + __PdoRestoreDevicePnpState(Pdo, StopPending); + status = STATUS_SUCCESS; + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoStopDevice( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + NTSTATUS status; + + if (__PdoGetDevicePowerState(Pdo) != PowerDeviceD0) + goto done; + + PdoD0ToD3(Pdo); + +done: + __PdoSetDevicePnpState(Pdo, Stopped); + status = STATUS_SUCCESS; + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoQueryRemoveDevice( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + NTSTATUS status; + + __PdoSetDevicePnpState(Pdo, RemovePending); + status = STATUS_SUCCESS; + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoCancelRemoveDevice( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + NTSTATUS status; + + if (__PdoClearEjectRequested(Pdo)) + Trace("(%s) Eject Failed\n", __PdoGetName(Pdo)); + + __PdoRestoreDevicePnpState(Pdo, RemovePending); + status = STATUS_SUCCESS; + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoSurpriseRemoval( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + NTSTATUS status; + + Warning("%s\n", __PdoGetName(Pdo)); + + __PdoSetDevicePnpState(Pdo, SurpriseRemovePending); + status = STATUS_SUCCESS; + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoRemoveDevice( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + PXENCONS_FDO Fdo = __PdoGetFdo(Pdo); + BOOLEAN NeedInvalidate; + NTSTATUS status; + + if (__PdoGetDevicePowerState(Pdo) != PowerDeviceD0) + goto done; + + PdoD0ToD3(Pdo); + +done: + NeedInvalidate = FALSE; + + FdoAcquireMutex(Fdo); + + if (__PdoIsMissing(Pdo)) { + DEVICE_PNP_STATE State = __PdoGetDevicePnpState(Pdo); + + __PdoSetDevicePnpState(Pdo, Deleted); + + if (State == SurpriseRemovePending) + PdoDestroy(Pdo); + else + NeedInvalidate = TRUE; + } else { + __PdoSetDevicePnpState(Pdo, Enumerated); + } + + FdoReleaseMutex(Fdo); + + if (NeedInvalidate) + IoInvalidateDeviceRelations(FdoGetPhysicalDeviceObject(Fdo), + BusRelations); + + status = STATUS_SUCCESS; + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoQueryDeviceRelations( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + PDEVICE_RELATIONS Relations; + NTSTATUS status; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + + status = Irp->IoStatus.Status; + + if (StackLocation->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) + goto done; + + Relations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), PDO_POOL); + + status = STATUS_NO_MEMORY; + if (Relations == NULL) + goto done; + + RtlZeroMemory(Relations, sizeof(DEVICE_RELATIONS)); + + Relations->Count = 1; + ObReferenceObject(__PdoGetDeviceObject(Pdo)); + Relations->Objects[0] = __PdoGetDeviceObject(Pdo); + + Irp->IoStatus.Information = (ULONG_PTR)Relations; + status = STATUS_SUCCESS; + +done: + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoQueryCapabilities( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + PDEVICE_CAPABILITIES Capabilities; + SYSTEM_POWER_STATE SystemPowerState; + NTSTATUS status; + + UNREFERENCED_PARAMETER(Pdo); + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + Capabilities = StackLocation->Parameters.DeviceCapabilities.Capabilities; + + status = STATUS_INVALID_PARAMETER; + if (Capabilities->Version != 1) + goto done; + + Capabilities->DeviceD1 = 0; + Capabilities->DeviceD2 = 0; + Capabilities->LockSupported = 0; + Capabilities->EjectSupported = 1; + Capabilities->Removable = 1; + Capabilities->DockDevice = 0; + Capabilities->UniqueID = 1; + Capabilities->SilentInstall = 1; + Capabilities->RawDeviceOK = 1; + Capabilities->SurpriseRemovalOK = 1; + Capabilities->HardwareDisabled = 0; + Capabilities->NoDisplayInUI = 0; + + Capabilities->Address = 0xffffffff; + Capabilities->UINumber = 0xffffffff; + + for (SystemPowerState = 0; SystemPowerState < PowerSystemMaximum; SystemPowerState++) { + switch (SystemPowerState) { + case PowerSystemUnspecified: + case PowerSystemSleeping1: + case PowerSystemSleeping2: + break; + + case PowerSystemWorking: + Capabilities->DeviceState[SystemPowerState] = PowerDeviceD0; + break; + + default: + Capabilities->DeviceState[SystemPowerState] = PowerDeviceD3; + break; + } + } + + Capabilities->SystemWake = PowerSystemUnspecified; + Capabilities->DeviceWake = PowerDeviceUnspecified; + Capabilities->D1Latency = 0; + Capabilities->D2Latency = 0; + Capabilities->D3Latency = 0; + + status = STATUS_SUCCESS; + +done: + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoQueryDeviceText( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + PWCHAR Buffer; + UNICODE_STRING Text; + NTSTATUS status; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + + switch (StackLocation->Parameters.QueryDeviceText.DeviceTextType) { + case DeviceTextDescription: + Trace("DeviceTextDescription\n"); + break; + + case DeviceTextLocationInformation: + Trace("DeviceTextLocationInformation\n"); + break; + + default: + Irp->IoStatus.Information = 0; + status = STATUS_NOT_SUPPORTED; + goto done; + } + + Buffer = ExAllocatePoolWithTag(PagedPool, MAXTEXTLEN, PDO_POOL); + + status = STATUS_NO_MEMORY; + if (Buffer == NULL) + goto done; + + RtlZeroMemory(Buffer, MAXTEXTLEN); + + Text.Buffer = Buffer; + Text.MaximumLength = MAXTEXTLEN; + Text.Length = 0; + + switch (StackLocation->Parameters.QueryDeviceText.DeviceTextType) { + case DeviceTextDescription: + status = RtlStringCbPrintfW(Buffer, + MAXTEXTLEN, + L"%hs PV Console #%hs", + PRODUCT_NAME_STR, + __PdoGetName(Pdo)); + ASSERT(NT_SUCCESS(status)); + + Buffer += wcslen(Buffer); + + break; + + case DeviceTextLocationInformation: + status = RtlStringCbPrintfW(Buffer, + MAXTEXTLEN, + L"%hs", + __PdoGetName(Pdo)); + ASSERT(NT_SUCCESS(status)); + + Buffer += wcslen(Buffer); + + break; + + default: + ASSERT(FALSE); + break; + } + + Text.Length = (USHORT)((ULONG_PTR)Buffer - (ULONG_PTR)Text.Buffer); + + ASSERT3U(KeGetCurrentIrql(), == , PASSIVE_LEVEL); + + Trace("%s: %wZ\n", __PdoGetName(Pdo), &Text); + + Irp->IoStatus.Information = (ULONG_PTR)Text.Buffer; + status = STATUS_SUCCESS; + +done: + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoReadConfig( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + UNREFERENCED_PARAMETER(Pdo); + + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return STATUS_NOT_SUPPORTED; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoWriteConfig( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + UNREFERENCED_PARAMETER(Pdo); + + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return STATUS_NOT_SUPPORTED; +} + +#define REGSTR_VAL_MAX_HCID_LEN 1024 + +static DECLSPEC_NOINLINE NTSTATUS +PdoQueryId( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + PWCHAR Buffer; + UNICODE_STRING Id; + ULONG Type; + NTSTATUS status; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + + switch (StackLocation->Parameters.QueryId.IdType) { + case BusQueryInstanceID: + Trace("BusQueryInstanceID\n"); + Id.MaximumLength = (USHORT)(strlen(__PdoGetName(Pdo)) + 1) * sizeof(WCHAR); + break; + + case BusQueryDeviceID: + Trace("BusQueryDeviceID\n"); + Id.MaximumLength = (MAX_DEVICE_ID_LEN - 2) * sizeof(WCHAR); + break; + + case BusQueryHardwareIDs: + Trace("BusQueryHardwareIDs\n"); + Id.MaximumLength = (USHORT)(MAX_DEVICE_ID_LEN * sizeof(WCHAR)); + break; + + case BusQueryCompatibleIDs: + Trace("BusQueryCompatibleIDs\n"); + Id.MaximumLength = (USHORT)(MAX_DEVICE_ID_LEN * sizeof(WCHAR)); + break; + + default: + Irp->IoStatus.Information = 0; + status = STATUS_NOT_SUPPORTED; + goto done; + } + + Buffer = ExAllocatePoolWithTag(PagedPool, Id.MaximumLength, PDO_POOL); + + status = STATUS_NO_MEMORY; + if (Buffer == NULL) + goto done; + + RtlZeroMemory(Buffer, Id.MaximumLength); + + Id.Buffer = Buffer; + Id.Length = 0; + + switch (StackLocation->Parameters.QueryId.IdType) { + case BusQueryInstanceID: + Type = REG_SZ; + + status = RtlStringCbPrintfW(Buffer, + Id.MaximumLength, + L"%hs", + __PdoGetName(Pdo)); + ASSERT(NT_SUCCESS(status)); + + Buffer += wcslen(Buffer); + + break; + + case BusQueryDeviceID: + Type = REG_SZ; + + status = RtlStringCbPrintfW(Buffer, + Id.MaximumLength, + L"XENCONS\\VEN_%hs&DEV_CONSOLE", + __PdoGetVendorName(Pdo)); + ASSERT(NT_SUCCESS(status)); + + Buffer += wcslen(Buffer); + + break; + + case BusQueryHardwareIDs: + case BusQueryCompatibleIDs: + { + ULONG Length; + + Type = REG_MULTI_SZ; + + Length = Id.MaximumLength; + + status = RtlStringCbPrintfW(Buffer, + Length, + L"XENCONS\\VEN_%hs&DEV_CONSOLE", + __PdoGetVendorName(Pdo)); + ASSERT(NT_SUCCESS(status)); + + Buffer += wcslen(Buffer); + Length -= (ULONG)(wcslen(Buffer) * sizeof(WCHAR)); + + Buffer++; + Length -= sizeof(WCHAR); + + status = RtlStringCbPrintfW(Buffer, + Length, + L"XENDEVICE"); + ASSERT(NT_SUCCESS(status)); + + Buffer += wcslen(Buffer); + Buffer++; + + ASSERT3U((ULONG_PTR)Buffer - (ULONG_PTR)Id.Buffer, <, + REGSTR_VAL_MAX_HCID_LEN); + break; + } + default: + Type = REG_NONE; + + ASSERT(FALSE); + break; + } + + ASSERT3U(KeGetCurrentIrql(), == , PASSIVE_LEVEL); + + Id.Length = (USHORT)((ULONG_PTR)Buffer - (ULONG_PTR)Id.Buffer); + Buffer = Id.Buffer; + + switch (Type) { + case REG_SZ: + Trace("- %ws\n", Buffer); + break; + + case REG_MULTI_SZ: + do { + Trace("- %ws\n", Buffer); + Buffer += wcslen(Buffer); + Buffer++; + } while (*Buffer != L'\0'); + break; + + default: + ASSERT(FALSE); + break; + } + + Irp->IoStatus.Information = (ULONG_PTR)Id.Buffer; + status = STATUS_SUCCESS; + +done: + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoQueryBusInformation( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + PPNP_BUS_INFORMATION Info; + NTSTATUS status; + + UNREFERENCED_PARAMETER(Pdo); + + Info = ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), PDO_POOL); + + status = STATUS_NO_MEMORY; + if (Info == NULL) + goto done; + + RtlZeroMemory(Info, sizeof(PNP_BUS_INFORMATION)); + + Info->BusTypeGuid = GUID_BUS_TYPE_INTERNAL; + Info->LegacyBusType = PNPBus; + Info->BusNumber = 0; + + Irp->IoStatus.Information = (ULONG_PTR)Info; + status = STATUS_SUCCESS; + +done: + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static NTSTATUS +PdoDelegateIrp( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + return FdoDelegateIrp(__PdoGetFdo(Pdo), Irp); +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoDeviceUsageNotification( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + NTSTATUS status; + + status = PdoDelegateIrp(Pdo, Irp); + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoEject( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + PXENCONS_FDO Fdo = __PdoGetFdo(Pdo); + NTSTATUS status; + + Trace("%s\n", __PdoGetName(Pdo)); + + FdoAcquireMutex(Fdo); + + __PdoSetDevicePnpState(Pdo, Deleted); + __PdoSetMissing(Pdo, "device ejected"); + + FdoReleaseMutex(Fdo); + + IoInvalidateDeviceRelations(FdoGetPhysicalDeviceObject(Fdo), + BusRelations); + + status = STATUS_SUCCESS; + + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoDispatchPnp( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + UCHAR MinorFunction; + NTSTATUS status; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + MinorFunction = StackLocation->MinorFunction; + + Trace("====> (%s) (%02x:%s)\n", + __PdoGetName(Pdo), + MinorFunction, + PnpMinorFunctionName(MinorFunction)); + + switch (StackLocation->MinorFunction) { + case IRP_MN_START_DEVICE: + status = PdoStartDevice(Pdo, Irp); + break; + + case IRP_MN_QUERY_STOP_DEVICE: + status = PdoQueryStopDevice(Pdo, Irp); + break; + + case IRP_MN_CANCEL_STOP_DEVICE: + status = PdoCancelStopDevice(Pdo, Irp); + break; + + case IRP_MN_STOP_DEVICE: + status = PdoStopDevice(Pdo, Irp); + break; + + case IRP_MN_QUERY_REMOVE_DEVICE: + status = PdoQueryRemoveDevice(Pdo, Irp); + break; + + case IRP_MN_CANCEL_REMOVE_DEVICE: + status = PdoCancelRemoveDevice(Pdo, Irp); + break; + + case IRP_MN_SURPRISE_REMOVAL: + status = PdoSurpriseRemoval(Pdo, Irp); + break; + + case IRP_MN_REMOVE_DEVICE: + status = PdoRemoveDevice(Pdo, Irp); + break; + + case IRP_MN_QUERY_DEVICE_RELATIONS: + status = PdoQueryDeviceRelations(Pdo, Irp); + break; + + case IRP_MN_QUERY_CAPABILITIES: + status = PdoQueryCapabilities(Pdo, Irp); + break; + + case IRP_MN_QUERY_DEVICE_TEXT: + status = PdoQueryDeviceText(Pdo, Irp); + break; + + case IRP_MN_READ_CONFIG: + status = PdoReadConfig(Pdo, Irp); + break; + + case IRP_MN_WRITE_CONFIG: + status = PdoWriteConfig(Pdo, Irp); + break; + + case IRP_MN_QUERY_ID: + status = PdoQueryId(Pdo, Irp); + break; + + case IRP_MN_QUERY_BUS_INFORMATION: + status = PdoQueryBusInformation(Pdo, Irp); + break; + + case IRP_MN_DEVICE_USAGE_NOTIFICATION: + status = PdoDeviceUsageNotification(Pdo, Irp); + break; + + case IRP_MN_EJECT: + status = PdoEject(Pdo, Irp); + break; + + default: + status = Irp->IoStatus.Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + break; + } + + Trace("<==== (%02x:%s)(%08x)\n", + MinorFunction, + PnpMinorFunctionName(MinorFunction), + status); + + return status; +} + +static FORCEINLINE NTSTATUS +__PdoSetDevicePower( + IN PXENCONS_PDO Pdo, + 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:%s)\n", + __PdoGetName(Pdo), + PowerDeviceStateName(DeviceState), + PowerActionName(PowerAction)); + + ASSERT3U(PowerAction, <, PowerActionShutdown); + + if (__PdoGetDevicePowerState(Pdo) > DeviceState) { + Trace("%s: POWERING UP: %s -> %s\n", + __PdoGetName(Pdo), + PowerDeviceStateName(__PdoGetDevicePowerState(Pdo)), + PowerDeviceStateName(DeviceState)); + + ASSERT3U(DeviceState, == , PowerDeviceD0); + status = PdoD3ToD0(Pdo); + ASSERT(NT_SUCCESS(status)); + } else if (__PdoGetDevicePowerState(Pdo) < DeviceState) { + Trace("%s: POWERING DOWN: %s -> %s\n", + __PdoGetName(Pdo), + PowerDeviceStateName(__PdoGetDevicePowerState(Pdo)), + PowerDeviceStateName(DeviceState)); + + ASSERT3U(DeviceState, == , PowerDeviceD3); + PdoD0ToD3(Pdo); + } + + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + Trace("<==== (%s:%s)\n", + PowerDeviceStateName(DeviceState), + PowerActionName(PowerAction)); + + return STATUS_SUCCESS; +} + +static NTSTATUS +PdoDevicePower( + IN PXENCONS_THREAD Self, + IN PVOID Context + ) +{ + PXENCONS_PDO Pdo = Context; + PKEVENT Event; + + Event = ThreadGetEvent(Self); + + for (;;) { + PIRP Irp; + + if (Pdo->DevicePowerIrp == NULL) { + (VOID)KeWaitForSingleObject(Event, + Executive, + KernelMode, + FALSE, + NULL); + KeClearEvent(Event); + } + + if (ThreadIsAlerted(Self)) + break; + + Irp = Pdo->DevicePowerIrp; + + if (Irp == NULL) + continue; + + Pdo->DevicePowerIrp = NULL; + KeMemoryBarrier(); + + (VOID)__PdoSetDevicePower(Pdo, Irp); + } + + return STATUS_SUCCESS; +} + +__drv_functionClass(REQUEST_POWER_COMPLETE) +__drv_sameIRQL +VOID +__PdoRequestSetDevicePower( + IN PDEVICE_OBJECT DeviceObject, + IN UCHAR MinorFunction, + IN POWER_STATE PowerState, + IN PVOID Context, + IN PIO_STATUS_BLOCK IoStatus + ) +{ + PKEVENT Event = Context; + + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(MinorFunction); + UNREFERENCED_PARAMETER(PowerState); + + ASSERT(NT_SUCCESS(IoStatus->Status)); + + KeSetEvent(Event, IO_NO_INCREMENT, FALSE); +} + +static VOID +PdoRequestSetDevicePower( + IN PXENCONS_PDO Pdo, + IN DEVICE_POWER_STATE DeviceState + ) +{ + POWER_STATE PowerState; + KEVENT Event; + NTSTATUS status; + + Trace("%s\n", PowerDeviceStateName(DeviceState)); + + ASSERT3U(KeGetCurrentIrql(), == , PASSIVE_LEVEL); + + PowerState.DeviceState = DeviceState; + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + status = PoRequestPowerIrp(__PdoGetDeviceObject(Pdo), + IRP_MN_SET_POWER, + PowerState, + __PdoRequestSetDevicePower, + &Event, + NULL); + ASSERT(NT_SUCCESS(status)); + + (VOID)KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); +} + +// Define a static SystemPower to DevicePower map +// This would normally be queried from the power policy owner, +// but since this Pdo is "raw", the Pdo is the power policy owner +static const DEVICE_POWER_STATE +DevicePowerStateMap[PowerSystemMaximum] = +{ + PowerDeviceUnspecified, // PowerSystemUnspecified + PowerDeviceD0, // PowerSystemWorking + PowerDeviceD3, // PowerSystemSleeping1 + PowerDeviceD3, // PowerSystemSleeping2 + PowerDeviceD3, // PowerSystemSleeping3 + PowerDeviceD3, // PowerSystemHibernate + PowerDeviceD3 // PowerSystemShutdown +}; + +static FORCEINLINE NTSTATUS +__PdoSetSystemPower( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + SYSTEM_POWER_STATE SystemState; + POWER_ACTION PowerAction; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + SystemState = StackLocation->Parameters.Power.State.SystemState; + PowerAction = StackLocation->Parameters.Power.ShutdownType; + + Trace("====> (%s) (%s:%s)\n", + __PdoGetName(Pdo), + PowerSystemStateName(SystemState), + PowerActionName(PowerAction)); + + ASSERT3U(PowerAction, <, PowerActionShutdown); + + if (__PdoGetSystemPowerState(Pdo) > SystemState) { + if (SystemState < PowerSystemHibernate && + __PdoGetSystemPowerState(Pdo) >= PowerSystemHibernate) { + __PdoSetSystemPowerState(Pdo, PowerSystemHibernate); + PdoS4ToS3(Pdo); + } + + Trace("%s: POWERING UP: %s -> %s\n", + __PdoGetName(Pdo), + PowerSystemStateName(__PdoGetSystemPowerState(Pdo)), + PowerSystemStateName(SystemState)); + + PdoRequestSetDevicePower(Pdo, DevicePowerStateMap[SystemState]); + } else if (__PdoGetSystemPowerState(Pdo) < SystemState) { + PdoRequestSetDevicePower(Pdo, DevicePowerStateMap[SystemState]); + + Trace("%s: POWERING DOWN: %s -> %s\n", + __PdoGetName(Pdo), + PowerSystemStateName(__PdoGetSystemPowerState(Pdo)), + PowerSystemStateName(SystemState)); + + if (SystemState >= PowerSystemHibernate && + __PdoGetSystemPowerState(Pdo) < PowerSystemHibernate) { + __PdoSetSystemPowerState(Pdo, PowerSystemSleeping3); + PdoS3ToS4(Pdo); + } + } + + __PdoSetSystemPowerState(Pdo, SystemState); + + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + Trace("<==== (%s:%s)\n", + PowerSystemStateName(SystemState), + PowerActionName(PowerAction)); + + return STATUS_SUCCESS; +} + +static NTSTATUS +PdoSystemPower( + IN PXENCONS_THREAD Self, + IN PVOID Context + ) +{ + PXENCONS_PDO Pdo = Context; + PKEVENT Event; + + Event = ThreadGetEvent(Self); + + for (;;) { + PIRP Irp; + + if (Pdo->SystemPowerIrp == NULL) { + (VOID)KeWaitForSingleObject(Event, + Executive, + KernelMode, + FALSE, + NULL); + KeClearEvent(Event); + } + + if (ThreadIsAlerted(Self)) + break; + + Irp = Pdo->SystemPowerIrp; + + if (Irp == NULL) + continue; + + Pdo->SystemPowerIrp = NULL; + KeMemoryBarrier(); + + (VOID)__PdoSetSystemPower(Pdo, Irp); + } + + return STATUS_SUCCESS; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoSetPower( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + POWER_STATE_TYPE PowerType; + POWER_ACTION PowerAction; + NTSTATUS status; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + PowerType = StackLocation->Parameters.Power.Type; + PowerAction = StackLocation->Parameters.Power.ShutdownType; + + if (PowerAction >= PowerActionShutdown) { + Irp->IoStatus.Status = STATUS_SUCCESS; + + status = Irp->IoStatus.Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + goto done; + } + + switch (PowerType) { + case DevicePowerState: + IoMarkIrpPending(Irp); + + ASSERT3P(Pdo->DevicePowerIrp, == , NULL); + Pdo->DevicePowerIrp = Irp; + KeMemoryBarrier(); + + ThreadWake(Pdo->DevicePowerThread); + + status = STATUS_PENDING; + break; + + case SystemPowerState: + IoMarkIrpPending(Irp); + + ASSERT3P(Pdo->SystemPowerIrp, == , NULL); + Pdo->SystemPowerIrp = Irp; + KeMemoryBarrier(); + + ThreadWake(Pdo->SystemPowerThread); + + status = STATUS_PENDING; + break; + + default: + status = Irp->IoStatus.Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + break; + } + +done: + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoQueryPower( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + NTSTATUS status; + + UNREFERENCED_PARAMETER(Pdo); + + Irp->IoStatus.Status = STATUS_SUCCESS; + + status = Irp->IoStatus.Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoDispatchPower( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + UCHAR MinorFunction; + NTSTATUS status; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + MinorFunction = StackLocation->MinorFunction; + + switch (StackLocation->MinorFunction) { + case IRP_MN_SET_POWER: + status = PdoSetPower(Pdo, Irp); + break; + + case IRP_MN_QUERY_POWER: + status = PdoQueryPower(Pdo, Irp); + break; + + default: + status = Irp->IoStatus.Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + break; + } + + return status; +} + +static DECLSPEC_NOINLINE NTSTATUS +PdoDispatchDefault( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + NTSTATUS status; + + UNREFERENCED_PARAMETER(Pdo); + + status = Irp->IoStatus.Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +NTSTATUS +PdoDispatch( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + NTSTATUS status; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + + switch (StackLocation->MajorFunction) { + case IRP_MJ_PNP: + status = PdoDispatchPnp(Pdo, Irp); + break; + + case IRP_MJ_POWER: + status = PdoDispatchPower(Pdo, Irp); + break; + + default: + status = PdoDispatchDefault(Pdo, Irp); + break; + } + + return status; +} + +NTSTATUS +PdoResume( + IN PXENCONS_PDO Pdo + ) +{ + Trace("(%s) ====>\n", __PdoGetName(Pdo)); + Trace("(%s) <====\n", __PdoGetName(Pdo)); + return STATUS_SUCCESS; +} + +VOID +PdoSuspend( + IN PXENCONS_PDO Pdo + ) +{ + Trace("(%s) ====>\n", __PdoGetName(Pdo)); + Trace("(%s) <====\n", __PdoGetName(Pdo)); +} + +NTSTATUS +PdoCreate( + IN PXENCONS_FDO Fdo, + IN PANSI_STRING Device + ) +{ + PDEVICE_OBJECT PhysicalDeviceObject; + PXENCONS_DX Dx; + PXENCONS_PDO Pdo; + NTSTATUS status; + +#pragma prefast(suppress:28197) // Possibly leaking memory 'PhysicalDeviceObject' + status = IoCreateDevice(DriverGetDriverObject(), + sizeof(XENCONS_DX), + NULL, + FILE_DEVICE_UNKNOWN, + FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME, + FALSE, + &PhysicalDeviceObject); + if (!NT_SUCCESS(status)) + goto fail1; + + Dx = (PXENCONS_DX)PhysicalDeviceObject->DeviceExtension; + RtlZeroMemory(Dx, sizeof(XENCONS_DX)); + + Dx->Type = PHYSICAL_DEVICE_OBJECT; + Dx->DeviceObject = PhysicalDeviceObject; + Dx->DevicePnpState = Present; + Dx->SystemPowerState = PowerSystemWorking; + Dx->DevicePowerState = PowerDeviceD3; + + Pdo = __PdoAllocate(sizeof(XENCONS_PDO)); + + status = STATUS_NO_MEMORY; + if (Pdo == NULL) + goto fail2; + + Pdo->Dx = Dx; + Pdo->Fdo = Fdo; + + status = ThreadCreate(PdoSystemPower, Pdo, &Pdo->SystemPowerThread); + if (!NT_SUCCESS(status)) + goto fail3; + + status = ThreadCreate(PdoDevicePower, Pdo, &Pdo->DevicePowerThread); + if (!NT_SUCCESS(status)) + goto fail4; + + __PdoSetName(Pdo, Device); + + FdoGetSuspendInterface(Fdo, &Pdo->SuspendInterface); + + Dx->Pdo = Pdo; + + status = FdoAddPhysicalDeviceObject(Fdo, Pdo); + if (!NT_SUCCESS(status)) + goto fail5; + + status = STATUS_UNSUCCESSFUL; + if (__PdoIsEjectRequested(Pdo)) + goto fail6; + + Info("%p (%s)\n", + PhysicalDeviceObject, + __PdoGetName(Pdo)); + + PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + return STATUS_SUCCESS; + +fail6: + Error("fail6\n"); + + FdoRemovePhysicalDeviceObject(Fdo, Pdo); + +fail5: + Error("fail5\n"); + + (VOID)__PdoClearEjectRequested(Pdo); + + Dx->Pdo = NULL; + + RtlZeroMemory(&Pdo->SuspendInterface, + sizeof(XENBUS_SUSPEND_INTERFACE)); + + ThreadAlert(Pdo->DevicePowerThread); + ThreadJoin(Pdo->DevicePowerThread); + Pdo->DevicePowerThread = NULL; + +fail4: + Error("fail4\n"); + + ThreadAlert(Pdo->SystemPowerThread); + ThreadJoin(Pdo->SystemPowerThread); + Pdo->SystemPowerThread = NULL; + +fail3: + Error("fail3\n"); + + Pdo->Fdo = NULL; + Pdo->Dx = NULL; + + ASSERT(IsZeroMemory(Pdo, sizeof(XENCONS_PDO))); + __PdoFree(Pdo); + +fail2: + Error("fail2\n"); + + IoDeleteDevice(PhysicalDeviceObject); + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + +VOID +PdoDestroy( + IN PXENCONS_PDO Pdo + ) +{ + PXENCONS_DX Dx = Pdo->Dx; + PDEVICE_OBJECT PhysicalDeviceObject = Dx->DeviceObject; + PXENCONS_FDO Fdo = __PdoGetFdo(Pdo); + + ASSERT3U(__PdoGetDevicePnpState(Pdo), == , Deleted); + + ASSERT(__PdoIsMissing(Pdo)); + Pdo->Missing = FALSE; + + Info("%p (%s) (%s)\n", + PhysicalDeviceObject, + __PdoGetName(Pdo), + Pdo->Reason); + + Pdo->Reason = NULL; + + FdoRemovePhysicalDeviceObject(Fdo, Pdo); + + (VOID)__PdoClearEjectRequested(Pdo); + + Dx->Pdo = NULL; + + RtlZeroMemory(&Pdo->SuspendInterface, + sizeof(XENBUS_SUSPEND_INTERFACE)); + + ThreadAlert(Pdo->DevicePowerThread); + ThreadJoin(Pdo->DevicePowerThread); + Pdo->DevicePowerThread = NULL; + + ThreadAlert(Pdo->SystemPowerThread); + ThreadJoin(Pdo->SystemPowerThread); + Pdo->SystemPowerThread = NULL; + + Pdo->Fdo = NULL; + Pdo->Dx = NULL; + + ASSERT(IsZeroMemory(Pdo, sizeof(XENCONS_PDO))); + __PdoFree(Pdo); + + IoDeleteDevice(PhysicalDeviceObject); +} + diff --git a/src/xencons/pdo.h b/src/xencons/pdo.h new file mode 100755 index 0000000..0605483 --- /dev/null +++ b/src/xencons/pdo.h @@ -0,0 +1,113 @@ +/* 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 _XENCONS_PDO_H +#define _XENCONS_PDO_H + +#include <ntddk.h> + +#include "driver.h" + +extern VOID +PdoSetDevicePnpState( + IN PXENCONS_PDO Pdo, + IN DEVICE_PNP_STATE State + ); + +extern DEVICE_PNP_STATE +PdoGetDevicePnpState( + IN PXENCONS_PDO Pdo + ); + +extern VOID +PdoSetMissing( + IN PXENCONS_PDO Pdo, + IN const CHAR *Reason + ); + +extern BOOLEAN +PdoIsMissing( + IN PXENCONS_PDO Pdo + ); + +extern VOID +PdoRequestEject( + IN PXENCONS_PDO Pdo + ); + +extern BOOLEAN +PdoIsEjectRequested( + IN PXENCONS_PDO Pdo + ); + +extern PCHAR +PdoGetName( + IN PXENCONS_PDO Pdo + ); + +extern PXENCONS_FDO +PdoGetFdo( + IN PXENCONS_PDO Pdo + ); + +extern PDEVICE_OBJECT +PdoGetDeviceObject( + IN PXENCONS_PDO Pdo + ); + +extern NTSTATUS +PdoCreate( + IN PXENCONS_FDO Fdo, + IN PANSI_STRING Device + ); + +extern NTSTATUS +PdoResume( + IN PXENCONS_PDO Pdo + ); + +extern VOID +PdoSuspend( + IN PXENCONS_PDO Pdo + ); + +extern VOID +PdoDestroy( + IN PXENCONS_PDO Pdo + ); + +extern NTSTATUS +PdoDispatch( + IN PXENCONS_PDO Pdo, + IN PIRP Irp + ); + +#endif // _XENCONS_PDO_H diff --git a/vs2015/xencons/xencons.vcxproj b/vs2015/xencons/xencons.vcxproj index 12f5b70..2e9d208 100644 --- a/vs2015/xencons/xencons.vcxproj +++ b/vs2015/xencons/xencons.vcxproj @@ -66,6 +66,7 @@ <ItemGroup> <ClCompile Include="../../src/xencons/driver.c" /> <ClCompile Include="../../src/xencons/fdo.c" /> + <ClCompile Include="../../src/xencons/pdo.c" /> <ClCompile Include="../../src/xencons/registry.c" /> <ClCompile Include="../../src/xencons/console.c" /> <ClCompile Include="../../src/xencons/stream.c" /> diff --git a/vs2017/xencons/xencons.vcxproj b/vs2017/xencons/xencons.vcxproj index 510acb6..6c67fe8 100644 --- a/vs2017/xencons/xencons.vcxproj +++ b/vs2017/xencons/xencons.vcxproj @@ -74,6 +74,7 @@ <ItemGroup> <ClCompile Include="../../src/xencons/driver.c" /> <ClCompile Include="../../src/xencons/fdo.c" /> + <ClCompile Include="../../src/xencons/pdo.c" /> <ClCompile Include="../../src/xencons/registry.c" /> <ClCompile Include="../../src/xencons/console.c" /> <ClCompile Include="../../src/xencons/stream.c" /> -- 2.8.3 _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |