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

Re: [win-pv-devel] [PATCH 03/14 v2] Add boilerplate Pdo



> -----Original Message-----
> From: win-pv-devel [mailto:win-pv-devel-bounces@xxxxxxxxxxxxxxxxxxxx] On
> Behalf Of owen.smith@xxxxxxxxxx
> Sent: 23 February 2018 14:22
> To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
> Cc: Owen Smith <owen.smith@xxxxxxxxxx>
> Subject: [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>

Acked-by: Paul Durrant <paul.durrant@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
_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/win-pv-devel

 


Rackspace

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