|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH 06/14] Enumerate ~/device/console for non-default consoles
From: Owen Smith <owen.smith@xxxxxxxxxx>
Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx>
---
src/xencons/driver.c | 6 +
src/xencons/driver.h | 12 +-
src/xencons/fdo.c | 721 +++++++++++++++-
src/xencons/fdo.h | 43 +
src/xencons/mutex.h | 82 ++
src/xencons/pdo.c | 1786 ++++++++++++++++++++++++++++++++++++++++
src/xencons/pdo.h | 114 +++
vs2015/xencons/xencons.vcxproj | 1 +
8 files changed, 2755 insertions(+), 10 deletions(-)
create mode 100644 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..beac030 100644
--- a/src/xencons/driver.c
+++ b/src/xencons/driver.c
@@ -202,6 +202,12 @@ Dispatch(
status = STATUS_NOT_SUPPORTED;
switch (Dx->Type) {
+ case PHYSICAL_DEVICE_OBJECT: {
+ PXENCONS_PDO Pdo = Dx->Pdo;
+
+ status = PdoDispatch(Pdo, Irp);
+ break;
+ }
case FUNCTION_DEVICE_OBJECT: {
PXENCONS_FDO Fdo = Dx->Fdo;
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 8e72dc6..5296c7f 100644
--- a/src/xencons/fdo.c
+++ b/src/xencons/fdo.c
@@ -49,6 +49,7 @@
#include "fdo.h"
#include "console.h"
#include "thread.h"
+#include "mutex.h"
#include "names.h"
#include "dbg_print.h"
#include "assert.h"
@@ -85,6 +86,12 @@ struct _XENCONS_FDO {
CHAR VendorName[MAXNAMELEN];
+ PXENCONS_THREAD ScanThread;
+ KEVENT ScanEvent;
+ PXENBUS_STORE_WATCH ScanWatch;
+ MUTEX Mutex;
+ ULONG References;
+
FDO_RESOURCE Resource[RESOURCE_COUNT];
PXENCONS_CONSOLE Console;
@@ -210,6 +217,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 +373,14 @@ __FdoGetVendorName(
return Fdo->VendorName;
}
+PCHAR
+FdoGetVendorName(
+ IN PXENCONS_FDO Fdo
+ )
+{
+ return __FdoGetVendorName(Fdo);
+}
+
static FORCEINLINE VOID
__FdoSetName(
IN PXENCONS_FDO Fdo
@@ -383,6 +406,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 +603,204 @@ 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;
+
+ if (Fdo->ScanThread)
+ ThreadWake(Fdo->ScanThread);
+}
+
+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 BOOLEAN
+__FdoEnumerate(
+ IN PXENCONS_FDO Fdo,
+ IN PANSI_STRING Devices
+ )
+{
+ BOOLEAN NeedInvalidate;
+ HANDLE ParametersKey;
+ ULONG Enumerate;
+ PLIST_ENTRY ListEntry;
+ ULONG Index;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ NeedInvalidate = FALSE;
+
+ ParametersKey = DriverGetParametersKey();
+
+ status = RegistryQueryDwordValue(ParametersKey,
+ "Enumerate",
+ &Enumerate);
+ if (!NT_SUCCESS(status))
+ Enumerate = 1;
+
+ if (Enumerate == 0)
+ goto done;
+
+ __FdoAcquireMutex(Fdo);
+
+ ListEntry = Fdo->Dx->ListEntry.Flink;
+ while (ListEntry != &Fdo->Dx->ListEntry) {
+ PLIST_ENTRY Next = ListEntry->Flink;
+ PXENCONS_DX Dx = CONTAINING_RECORD(ListEntry, XENCONS_DX,
ListEntry);
+ PXENCONS_PDO Pdo = Dx->Pdo;
+
+ if (PdoGetDevicePnpState(Pdo) != Deleted) {
+ PCHAR Name;
+ BOOLEAN Missing;
+
+ Name = PdoGetName(Pdo);
+ Missing = TRUE;
+
+ // If the PDO already exists and its name is in the device list
+ // then we don't want to remove it.
+ for (Index = 0; Devices[Index].Buffer != NULL; Index++) {
+ PANSI_STRING Device = &Devices[Index];
+
+ if (Device->Length == 0)
+ continue;
+
+ if (strcmp(Name, Device->Buffer) == 0) {
+ Missing = FALSE;
+ Device->Length = 0; // avoid duplication
+ break;
+ }
+ }
+
+ if (!PdoIsMissing(Pdo)) {
+ if (PdoIsEjectRequested(Pdo)) {
+ IoRequestDeviceEject(PdoGetDeviceObject(Pdo));
+ } else if (Missing) {
+ PdoSetMissing(Pdo, "device disappeared");
+
+ // If the PDO has not yet been enumerated then we can
+ // go ahead and mark it as deleted, otherwise we need
+ // to notify PnP manager and wait for the REMOVE_DEVICE
+ // IRP.
+ if (PdoGetDevicePnpState(Pdo) == Present) {
+ PdoSetDevicePnpState(Pdo, Deleted);
+ PdoDestroy(Pdo);
+ } else {
+ NeedInvalidate = TRUE;
+ }
+ }
+ }
+ }
+
+ ListEntry = Next;
+ }
+
+ // Walk the class list and create PDOs for any new device
+ for (Index = 0; Devices[Index].Buffer != NULL; Index++) {
+ PANSI_STRING Device = &Devices[Index];
+
+ if (Device->Length == 0)
+ continue;
+
+ status = PdoCreate(Fdo, Device);
+ if (NT_SUCCESS(status))
+ NeedInvalidate = TRUE;
+ }
+
+ __FdoReleaseMutex(Fdo);
+
+done:
+ Trace("<====\n");
+
+ return NeedInvalidate;
+}
+
static FORCEINLINE PANSI_STRING
__FdoMultiSzToUpcaseAnsi(
IN PCHAR Buffer
@@ -565,6 +879,126 @@ __FdoFreeAnsi(
__FdoFree(Ansi);
}
+
+static NTSTATUS
+FdoScan(
+ PXENCONS_THREAD Self,
+ PVOID Context
+ )
+{
+ PXENCONS_FDO Fdo = Context;
+ PKEVENT Event;
+ HANDLE ParametersKey;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ Event = ThreadGetEvent(Self);
+
+ ParametersKey = DriverGetParametersKey();
+
+ for (;;) {
+ PCHAR Buffer;
+ PANSI_STRING Devices;
+ PANSI_STRING UnsupportedDevices;
+ ULONG Index;
+ BOOLEAN NeedInvalidate;
+
+ Trace("waiting...\n");
+
+ (VOID)KeWaitForSingleObject(Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(Event);
+
+ if (ThreadIsAlerted(Self))
+ break;
+
+ // It is not safe to use interfaces before this point
+ if (__FdoGetDevicePnpState(Fdo) != Started) {
+ KeSetEvent(&Fdo->ScanEvent, IO_NO_INCREMENT, FALSE);
+ continue;
+ }
+
+ status = XENBUS_STORE(Directory,
+ &Fdo->StoreInterface,
+ NULL,
+ "device",
+ "console",
+ &Buffer);
+ if (NT_SUCCESS(status)) {
+ Devices = __FdoMultiSzToUpcaseAnsi(Buffer);
+
+ XENBUS_STORE(Free,
+ &Fdo->StoreInterface,
+ Buffer);
+ } else {
+ Devices = NULL;
+ }
+
+ if (Devices == NULL)
+ goto loop;
+
+ if (ParametersKey != NULL) {
+ status = RegistryQuerySzValue(ParametersKey,
+ "UnsupportedDevices",
+ NULL,
+ &UnsupportedDevices);
+ if (!NT_SUCCESS(status))
+ UnsupportedDevices = NULL;
+ } else {
+ UnsupportedDevices = NULL;
+ }
+
+ // NULL out anything in the Devices list that is in the
+ // UnsupportedDevices list
+ for (Index = 0; Devices[Index].Buffer != NULL; Index++) {
+ PANSI_STRING Device = &Devices[Index];
+ ULONG Entry;
+ BOOLEAN Supported;
+
+ Supported = TRUE;
+
+ for (Entry = 0;
+ UnsupportedDevices != NULL &&
UnsupportedDevices[Entry].Buffer != NULL;
+ Entry++) {
+ if (strncmp(Device->Buffer,
+ UnsupportedDevices[Entry].Buffer,
+ Device->Length) == 0) {
+ Supported = FALSE;
+ break;
+ }
+ }
+
+ if (!Supported)
+ Device->Length = 0;
+ }
+
+ if (UnsupportedDevices != NULL)
+ RegistryFreeSzValue(UnsupportedDevices);
+
+ NeedInvalidate = __FdoEnumerate(Fdo, Devices);
+
+ __FdoFreeAnsi(Devices);
+
+ if (NeedInvalidate) {
+ NeedInvalidate = FALSE;
+ IoInvalidateDeviceRelations(__FdoGetPhysicalDeviceObject(Fdo),
+ BusRelations);
+ }
+
+ loop:
+ KeSetEvent(&Fdo->ScanEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ KeSetEvent(&Fdo->ScanEvent, IO_NO_INCREMENT, FALSE);
+
+ Trace("<====\n");
+ return STATUS_SUCCESS;
+}
+
static FORCEINLINE BOOLEAN
__FdoMatchDistribution(
IN PXENCONS_FDO Fdo,
@@ -796,12 +1230,34 @@ __FdoD3ToD0(
if (!NT_SUCCESS(status))
goto fail1;
+ status = XENBUS_STORE(WatchAdd,
+ &Fdo->StoreInterface,
+ "device",
+ "console",
+ ThreadGetEvent(Fdo->ScanThread),
+ &Fdo->ScanWatch);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ (VOID)XENBUS_STORE(Printf,
+ &Fdo->StoreInterface,
+ NULL,
+ "feature/hotplug",
+ "console",
+ "%u",
+ TRUE);
+
(VOID) FdoSetDistribution(Fdo);
Trace("<====\n");
return STATUS_SUCCESS;
+fail2:
+ Error("fail2\n");
+
+ ConsoleDisable(Fdo->Console);
+
fail1:
Error("fail1 (%08x)\n", status);
@@ -819,6 +1275,17 @@ __FdoD0ToD3(
FdoClearDistribution(Fdo);
+ (VOID)XENBUS_STORE(Remove,
+ &Fdo->StoreInterface,
+ NULL,
+ "feature/hotplug",
+ "console");
+
+ (VOID)XENBUS_STORE(WatchRemove,
+ &Fdo->StoreInterface,
+ Fdo->ScanWatch);
+ Fdo->ScanWatch = NULL;
+
ConsoleDisable(Fdo->Console);
Trace("<====\n");
@@ -844,9 +1311,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);
@@ -886,8 +1353,24 @@ 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);
+
#pragma prefast(suppress:28123)
- (VOID) IoSetDeviceInterfaceState(&Dx->Link, TRUE);
+ (VOID) IoSetDeviceInterfaceState(&Fdo->Dx->Link, TRUE);
Trace("<====\n");
@@ -924,8 +1407,8 @@ FdoD0ToD3(
IN PXENCONS_FDO Fdo
)
{
- PXENCONS_DX Dx = Fdo->Dx;
POWER_STATE PowerState;
+ PLIST_ENTRY ListEntry;
KIRQL Irql;
ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
@@ -934,7 +1417,26 @@ FdoD0ToD3(
Trace("====>\n");
#pragma prefast(suppress:28123)
- (VOID) IoSetDeviceInterfaceState(&Dx->Link, FALSE);
+ (VOID) IoSetDeviceInterfaceState(&Fdo->Dx->Link, FALSE);
+
+ __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,
@@ -1004,20 +1506,36 @@ FdoStartDevice(
StackLocation->Parameters.StartDevice.AllocatedResources,
StackLocation->Parameters.StartDevice.AllocatedResourcesTranslated);
- status = FdoD3ToD0(Fdo);
+ KeInitializeEvent(&Fdo->ScanEvent, NotificationEvent, FALSE);
+
+ status = ThreadCreate(FdoScan, Fdo, &Fdo->ScanThread);
if (!NT_SUCCESS(status))
goto fail2;
+ status = FdoD3ToD0(Fdo);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
__FdoSetDevicePnpState(Fdo, Started);
+ ThreadWake(Fdo->ScanThread);
status = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
+fail3:
+ Error("fail3\n");
+
+ ThreadAlert(Fdo->ScanThread);
+ ThreadJoin(Fdo->ScanThread);
+ Fdo->ScanThread = NULL;
+
fail2:
Error("fail2\n");
+ RtlZeroMemory(&Fdo->ScanEvent, sizeof(KEVENT));
+
RtlZeroMemory(&Fdo->Resource, sizeof (FDO_RESOURCE) * RESOURCE_COUNT);
fail1:
@@ -1075,6 +1593,12 @@ FdoStopDevice(
if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD0)
FdoD0ToD3(Fdo);
+ ThreadAlert(Fdo->ScanThread);
+ ThreadJoin(Fdo->ScanThread);
+ Fdo->ScanThread = NULL;
+
+ RtlZeroMemory(&Fdo->ScanEvent, sizeof(KEVENT));
+
RtlZeroMemory(&Fdo->Resource, sizeof (FDO_RESOURCE) * RESOURCE_COUNT);
__FdoSetDevicePnpState(Fdo, Stopped);
@@ -1127,10 +1651,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);
@@ -1145,6 +1686,7 @@ FdoRemoveDevice(
IN PIRP Irp
)
{
+ PLIST_ENTRY ListEntry;
NTSTATUS status;
ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
@@ -1152,9 +1694,50 @@ FdoRemoveDevice(
if (__FdoGetPreviousDevicePnpState(Fdo) != Started)
goto done;
+ KeClearEvent(&Fdo->ScanEvent);
+ ThreadWake(Fdo->ScanThread);
+
+ Trace("waiting for scan thread\n");
+
+ (VOID)KeWaitForSingleObject(&Fdo->ScanEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ __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);
+ ThreadAlert(Fdo->ScanThread);
+ ThreadJoin(Fdo->ScanThread);
+ Fdo->ScanThread = NULL;
+
+ RtlZeroMemory(&Fdo->ScanEvent, sizeof(KEVENT));
+
RtlZeroMemory(&Fdo->Resource, sizeof (FDO_RESOURCE) * RESOURCE_COUNT);
done:
@@ -1167,7 +1750,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;
}
@@ -1179,16 +1768,121 @@ 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;
+ }
+
+ KeClearEvent(&Fdo->ScanEvent);
+ ThreadWake(Fdo->ScanThread);
+
+ Trace("waiting for scan thread\n");
+
+ (VOID)KeWaitForSingleObject(&Fdo->ScanEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ __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;
}
@@ -2566,6 +3260,11 @@ FdoCreate(
Dx->Fdo = Fdo;
+ InitializeMutex(&Fdo->Mutex);
+ InitializeListHead(&Dx->ListEntry);
+
+ Fdo->References = 1;
+
Info("%p (%s)\n",
FunctionDeviceObject,
__FdoGetName(Fdo));
@@ -2658,6 +3357,8 @@ FdoDestroy(
PXENCONS_DX Dx = Fdo->Dx;
PDEVICE_OBJECT FunctionDeviceObject = Dx->DeviceObject;
+ ASSERT(IsListEmpty(&Dx->ListEntry));
+ ASSERT3U(Fdo->References, == , 0);
ASSERT3U(__FdoGetDevicePnpState(Fdo), ==, Deleted);
Fdo->NotDisableable = FALSE;
@@ -2666,6 +3367,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..189c70f 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 100644
index 0000000..faf1a98
--- /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..7a9c1e6
--- /dev/null
+++ b/src/xencons/pdo.c
@@ -0,0 +1,1786 @@
+/* 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 "names.h"
+#include "fdo.h"
+#include "pdo.h"
+#include "driver.h"
+#include "registry.h"
+#include "thread.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+#include "version.h"
+
+#define PDO_POOL 'ODP'
+
+#define MAXNAMELEN 128
+
+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 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 Name
+ )
+{
+ PXENCONS_DX Dx = Pdo->Dx;
+ NTSTATUS status;
+
+ status = RtlStringCbPrintfA(Dx->Name,
+ MAX_DEVICE_ID_LEN,
+ "%Z",
+ Name);
+ ASSERT(NT_SUCCESS(status));
+}
+
+static FORCEINLINE PCHAR
+__PdoGetName(
+ IN PXENCONS_PDO Pdo
+ )
+{
+ PXENCONS_DX Dx = Pdo->Dx;
+
+ return Dx->Name;
+}
+
+PCHAR
+PdoGetName(
+ IN PXENCONS_PDO Pdo
+ )
+{
+ return __PdoGetName(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 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 PCHAR
+__PdoGetVendorName(
+ IN PXENCONS_PDO Pdo
+ )
+{
+ return FdoGetVendorName(__PdoGetFdo(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;
+
+ 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);
+
+ 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;
+
+ 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);
+}
+
+// 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))
+ // FrontendEjectFailed(__PdoGetFrontend(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;
+}
+
+#define MAXTEXTLEN 1024
+
+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",
+ FdoGetName(__PdoGetFdo(Pdo)),
+ __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_CONS",
+ __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_CONS",
+ __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(Pdo->Fdo, 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;
+}
+
+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));
+ } else if (__PdoGetSystemPowerState(Pdo) < 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
+ )
+{
+ UNREFERENCED_PARAMETER(Pdo);
+ return STATUS_SUCCESS;
+}
+
+VOID
+PdoSuspend(
+ IN PXENCONS_PDO Pdo
+ )
+{
+ UNREFERENCED_PARAMETER(Pdo);
+}
+
+NTSTATUS
+PdoCreate(
+ IN PXENCONS_FDO Fdo,
+ IN PANSI_STRING Name
+ )
+{
+ 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, Name);
+
+ 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_BUFFERED_IO;
+ 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..2164542
--- /dev/null
+++ b/src/xencons/pdo.h
@@ -0,0 +1,114 @@
+/* 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"
+#include "types.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 Name
+ );
+
+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" />
--
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 |