Пример #1
0
NTSTATUS
FilterAddDevice(
    __in PDRIVER_OBJECT DriverObject,
    __in PDEVICE_OBJECT PhysicalDeviceObject
    )
/*++

Routine Description:

    The Plug & Play subsystem is handing us a brand new PDO, for which we
    (by means of INF registration) have been asked to provide a driver.

    We need to determine if we need to be in the driver stack for the device.
    Create a function device object to attach to the stack
    Initialize that device object
    Return status success.

    Remember: We can NOT actually send ANY non pnp IRPS to the given driver
    stack, UNTIL we have received an IRP_MN_START_DEVICE.

Arguments:

    DeviceObject - pointer to a device object.

    PhysicalDeviceObject -  pointer to a device object created by the
                            underlying bus driver.

Return Value:

    NT status code.

--*/
{
    NTSTATUS                status = STATUS_SUCCESS;
    PDEVICE_OBJECT          deviceObject = NULL;
    PDEVICE_EXTENSION       deviceExtension;
    ULONG                   deviceType = FILE_DEVICE_UNKNOWN;

    PAGED_CODE ();


    //
    // IoIsWdmVersionAvailable(1, 0x20) returns TRUE on os after Windows 2000.
    //
    if (RtlIsNtDdiVersionAvailable(NTDDI_WINXP)) {
        //
        // Win2K system bugchecks if the filter attached to a storage device
        // doesn't specify the same DeviceType as the device it's attaching
        // to. This bugcheck happens in the filesystem when you disable
        // the devicestack whose top level deviceobject doesn't have a VPB.
        // To workaround we will get the toplevel object's DeviceType and
        // specify that in IoCreateDevice.
        //
        deviceObject = IoGetAttachedDeviceReference(PhysicalDeviceObject);
        deviceType = deviceObject->DeviceType;
        ObDereferenceObject(deviceObject);
    }

    //
    // Create a filter device object.
    //

    status = IoCreateDevice (DriverObject,
                             sizeof (DEVICE_EXTENSION),
                             NULL,  // No Name
                             deviceType,
                             FILE_DEVICE_SECURE_OPEN,
                             FALSE,
                             &deviceObject);


    if (!NT_SUCCESS (status)) {
        //
        // Returning failure here prevents the entire stack from functioning,
        // but most likely the rest of the stack will not be able to create
        // device objects either, so it is still OK.
        //
        return status;
    }

    DebugPrint (("AddDevice PDO (0x%p) FDO (0x%p)\n",
                    PhysicalDeviceObject, deviceObject));

    deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;

    deviceExtension->Common.Type = DEVICE_TYPE_FIDO;

    deviceExtension->NextLowerDriver = IoAttachDeviceToDeviceStack (
                                       deviceObject,
                                       PhysicalDeviceObject);
    //
    // Failure for attachment is an indication of a broken plug & play system.
    //

    if (NULL == deviceExtension->NextLowerDriver) {

        IoDeleteDevice(deviceObject);
        return STATUS_UNSUCCESSFUL;
    }

    deviceObject->Flags |= deviceExtension->NextLowerDriver->Flags &
                            (DO_BUFFERED_IO | DO_DIRECT_IO |
                            DO_POWER_PAGABLE );


    deviceObject->DeviceType = deviceExtension->NextLowerDriver->DeviceType;

    deviceObject->Characteristics =
                          deviceExtension->NextLowerDriver->Characteristics;

    deviceExtension->Self = deviceObject;

    //
    // Let us use remove lock to keep count of IRPs so that we don't 
    // deteach and delete our deviceobject until all pending I/Os in our
    // devstack are completed. Remlock is required to protect us from
    // various race conditions where our driver can get unloaded while we
    // are still running dispatch or completion code.
    //
    
    IoInitializeRemoveLock (&deviceExtension->RemoveLock , 
                            POOL_TAG,
                            1, // MaxLockedMinutes 
                            100); // HighWatermark, this parameter is 
                                // used only on checked build. Specifies 
                                // the maximum number of outstanding 
                                // acquisitions allowed on the lock
                                

    //
    // Set the initial state of the Filter DO
    //

    INITIALIZE_PNP_STATE(deviceExtension);

    DebugPrint(("AddDevice: %p to %p->%p \n", deviceObject,
                       deviceExtension->NextLowerDriver,
                       PhysicalDeviceObject));

    deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

    return STATUS_SUCCESS;

}
Пример #2
0
NTSTATUS
NTAPI
PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState, POWER_ACTION PowerAction)
{
    PDEVICE_OBJECT DeviceObject;
    PDEVICE_OBJECT Fdo;
    NTSTATUS Status;
    DEVICETREE_TRAVERSE_CONTEXT Context;
    POWER_STATE_TRAVERSE_CONTEXT PowerContext;
    
    Status = IopGetSystemPowerDeviceObject(&DeviceObject);
    if (!NT_SUCCESS(Status))
    {
        DPRINT1("No system power driver available\n");
        Fdo = NULL;
    }
    else
    {
        Fdo = IoGetAttachedDeviceReference(DeviceObject);
        if (Fdo == DeviceObject)
        {
            DPRINT("An FDO was not attached\n");
            return STATUS_UNSUCCESSFUL;
        }
    }
    
    /* Set up context */
    PowerContext.PowerAction = PowerAction;
    PowerContext.SystemPowerState = PowerState;
    PowerContext.PowerDevice = Fdo;
    
    /* Query for system power change */
    IopInitDeviceTreeTraverseContext(&Context,
                                     IopRootDeviceNode,
                                     PopQuerySystemPowerStateTraverse,
                                     &PowerContext);
    
    Status = IopTraverseDeviceTree(&Context);
    if (!NT_SUCCESS(Status))
    {
        DPRINT1("Query system power state failed; changing state anyway\n");
    }
    
    /* Set system power change */
    IopInitDeviceTreeTraverseContext(&Context,
                                     IopRootDeviceNode,
                                     PopSetSystemPowerStateTraverse,
                                     &PowerContext);
    
    IopTraverseDeviceTree(&Context);

    if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
    
    if (Fdo != NULL)
    {
        if (PowerAction != PowerActionShutdownReset)
            PopSendSetSystemPowerState(Fdo, PowerState, PowerAction);

        ObDereferenceObject(Fdo);
    }

    return Status;
}
Пример #3
0
/*
 * @implemented
 */
VOID
IssueUniqueIdChangeNotify(IN PDEVICE_EXTENSION DeviceExtension,
                          IN PUNICODE_STRING DeviceName,
                          IN PMOUNTDEV_UNIQUE_ID UniqueId)
{
    NTSTATUS Status;
    PVOID IrpBuffer = NULL;
    PFILE_OBJECT FileObject;
    PDEVICE_OBJECT DeviceObject;
    PUNIQUE_ID_WORK_ITEM WorkItem = NULL;

    /* Get the associated device object */
    Status = IoGetDeviceObjectPointer(DeviceName,
                                      FILE_READ_ATTRIBUTES,
                                      &FileObject,
                                      &DeviceObject);
    if (!NT_SUCCESS(Status))
    {
        return;
    }

    /* And then, get attached device */
    DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);

    ObDereferenceObject(FileObject);

    /* Allocate a work item */
    WorkItem = AllocatePool(sizeof(UNIQUE_ID_WORK_ITEM));
    if (!WorkItem)
    {
        ObDereferenceObject(DeviceObject);
        return;
    }

    WorkItem->Event = NULL;
    WorkItem->WorkItem = IoAllocateWorkItem(DeviceExtension->DeviceObject);
    if (!WorkItem->WorkItem)
    {
        ObDereferenceObject(DeviceObject);
        goto Cleanup;
    }

    WorkItem->DeviceExtension = DeviceExtension;
    WorkItem->StackSize = DeviceObject->StackSize;
    /* Already provide the IRP */
    WorkItem->Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);

    ObDereferenceObject(DeviceObject);

    if (!WorkItem->Irp)
    {
        goto Cleanup;
    }

    /* Ensure it has enough space */
    IrpBuffer = AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) + 1024);
    if (!IrpBuffer)
    {
        goto Cleanup;
    }

    WorkItem->DeviceName.Length = DeviceName->Length;
    WorkItem->DeviceName.MaximumLength = DeviceName->Length + sizeof(WCHAR);
    WorkItem->DeviceName.Buffer = AllocatePool(WorkItem->DeviceName.MaximumLength);
    if (!WorkItem->DeviceName.Buffer)
    {
        goto Cleanup;
    }

    RtlCopyMemory(WorkItem->DeviceName.Buffer, DeviceName->Buffer, DeviceName->Length);
    WorkItem->DeviceName.Buffer[DeviceName->Length / sizeof(WCHAR)] = UNICODE_NULL;

    WorkItem->IrpBuffer = IrpBuffer;
    WorkItem->IrpBufferLength = sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) + 1024;

    /* Add the worker in the list */
    KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
    InsertHeadList(&(DeviceExtension->UniqueIdWorkerItemListHead), &(WorkItem->UniqueIdWorkerItemListEntry));
    KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);

    /* And call the worker */
    IssueUniqueIdChangeNotifyWorker(WorkItem, UniqueId);

    return;

Cleanup:
    if (IrpBuffer)
    {
        FreePool(IrpBuffer);
    }

    if (WorkItem->Irp)
    {
        IoFreeIrp(WorkItem->Irp);
    }

    if (WorkItem->WorkItem)
    {
        IoFreeWorkItem(WorkItem->WorkItem);
    }

    if (WorkItem)
    {
        FreePool(WorkItem);
    }
}
Пример #4
0
NTSTATUS
Bus_GetDeviceCapabilities(
    __in  PDEVICE_OBJECT          DeviceObject,
    __in  PDEVICE_CAPABILITIES    DeviceCapabilities
    )
/*++

Routine Description:

    This routine sends the get capabilities irp to the given stack

Arguments:

    DeviceObject        A device object in the stack whose capabilities we want
    DeviceCapabilites   Where to store the answer

Return Value:

    NTSTATUS

--*/
{
    IO_STATUS_BLOCK     ioStatus;
    KEVENT              pnpEvent;
    NTSTATUS            status;
    PDEVICE_OBJECT      targetObject;
    PIO_STACK_LOCATION  irpStack;
    PIRP                pnpIrp;

    PAGED_CODE();

    //
    // Initialize the capabilities that we will send down
    //
    RtlZeroMemory( DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) );
    DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
    DeviceCapabilities->Version = 1;
    DeviceCapabilities->Address = -1;
    DeviceCapabilities->UINumber = -1;

    //
    // Initialize the event
    //
    KeInitializeEvent( &pnpEvent, NotificationEvent, FALSE );

    targetObject = IoGetAttachedDeviceReference( DeviceObject );

    //
    // Build an Irp
    //
    pnpIrp = IoBuildSynchronousFsdRequest(
        IRP_MJ_PNP,
        targetObject,
        NULL,
        0,
        NULL,
        &pnpEvent,
        &ioStatus
        );
    if (pnpIrp == NULL) {

        status = STATUS_INSUFFICIENT_RESOURCES;
        goto GetDeviceCapabilitiesExit;

    }

    //
    // Pnp Irps all begin life as STATUS_NOT_SUPPORTED;
    //
    pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;

    //
    // Get the top of stack
    //
    irpStack = IoGetNextIrpStackLocation( pnpIrp );

    //
    // Set the top of stack
    //
    RtlZeroMemory( irpStack, sizeof(IO_STACK_LOCATION ) );
    irpStack->MajorFunction = IRP_MJ_PNP;
    irpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
    irpStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;

    //
    // Call the driver
    //
    status = IoCallDriver( targetObject, pnpIrp );
    if (status == STATUS_PENDING) {

        //
        // Block until the irp comes back.
        // Important thing to note here is when you allocate
        // the memory for an event in the stack you must do a
        // KernelMode wait instead of UserMode to prevent
        // the stack from getting paged out.
        //

        KeWaitForSingleObject(
            &pnpEvent,
            Executive,
            KernelMode,
            FALSE,
            NULL
            );
        status = ioStatus.Status;

    }

GetDeviceCapabilitiesExit:
    //
    // Done with reference
    //
    ObDereferenceObject( targetObject );

    //
    // Done
    //
    return status;

}
Пример #5
0
/*
 * @implemented
 */
VOID
IssueUniqueIdChangeNotifyWorker(IN PUNIQUE_ID_WORK_ITEM WorkItem,
                                IN PMOUNTDEV_UNIQUE_ID UniqueId)
{
    PIRP Irp;
    NTSTATUS Status;
    PFILE_OBJECT FileObject;
    PIO_STACK_LOCATION Stack;
    PDEVICE_OBJECT DeviceObject;

    /* Get the device object */
    Status = IoGetDeviceObjectPointer(&(WorkItem->DeviceName),
                                      FILE_READ_ATTRIBUTES,
                                      &FileObject,
                                      &DeviceObject);
    if (!NT_SUCCESS(Status))
    {
        RemoveWorkItem(WorkItem);
        return;
    }

    /* And then, the attached device */
    DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);

    /* Initialize the IRP */
    Irp = WorkItem->Irp;
    IoInitializeIrp(Irp, IoSizeOfIrp(WorkItem->StackSize), (CCHAR)WorkItem->StackSize);

    if (InterlockedExchange((PLONG)&(WorkItem->Event), 0) != 0)
    {
        ObDereferenceObject(FileObject);
        ObDereferenceObject(DeviceObject);
        RemoveWorkItem(WorkItem);
        return;
    }

    Irp->AssociatedIrp.SystemBuffer = WorkItem->IrpBuffer;
    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
    RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, UniqueId, UniqueId->UniqueIdLength + sizeof(USHORT));

    Stack = IoGetNextIrpStackLocation(Irp);

    Stack->Parameters.DeviceIoControl.InputBufferLength = UniqueId->UniqueIdLength + sizeof(USHORT);
    Stack->Parameters.DeviceIoControl.OutputBufferLength = WorkItem->IrpBufferLength;
    Stack->Parameters.DeviceIoControl.Type3InputBuffer = 0;
    Stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY;
    Stack->MajorFunction = IRP_MJ_DEVICE_CONTROL;

    Status = IoSetCompletionRoutineEx(WorkItem->DeviceExtension->DeviceObject,
                                      Irp,
                                      UniqueIdChangeNotifyCompletion,
                                      WorkItem,
                                      TRUE, TRUE, TRUE);
    if (!NT_SUCCESS(Status))
    {
        ObDereferenceObject(FileObject);
        ObDereferenceObject(DeviceObject);
        RemoveWorkItem(WorkItem);
        return;
    }

    /* Call the driver */
    IoCallDriver(DeviceObject, Irp);
    ObDereferenceObject(FileObject);
    ObDereferenceObject(DeviceObject);
}
Пример #6
0
/*
 * @implemented
 */
VOID
MountMgrNotifyNameChange(IN PDEVICE_EXTENSION DeviceExtension,
                         IN PUNICODE_STRING DeviceName,
                         IN BOOLEAN ValidateVolume)
{
    PIRP Irp;
    KEVENT Event;
    NTSTATUS Status;
    PLIST_ENTRY NextEntry;
    PFILE_OBJECT FileObject;
    PIO_STACK_LOCATION Stack;
    PDEVICE_OBJECT DeviceObject;
    IO_STATUS_BLOCK IoStatusBlock;
    PDEVICE_RELATIONS DeviceRelations;
    PDEVICE_INFORMATION DeviceInformation;
    TARGET_DEVICE_CUSTOM_NOTIFICATION DeviceNotification;

    /* If we have to validate volume */
    if (ValidateVolume)
    {
        /* Then, ensure we can find the device */
        NextEntry = DeviceExtension->DeviceListHead.Flink;
        while (NextEntry != &(DeviceExtension->DeviceListHead))
        {
            DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
            if (RtlCompareUnicodeString(DeviceName, &(DeviceInformation->DeviceName), TRUE) == 0)
            {
                break;
            }
        }

        /* No need to notify for a PnP device or if we didn't find the device */
        if (NextEntry == &(DeviceExtension->DeviceListHead) ||
            !DeviceInformation->ManuallyRegistered)
        {
            return;
        }
    }

    /* Then, get device object */
    Status = IoGetDeviceObjectPointer(DeviceName,
                                      FILE_READ_ATTRIBUTES,
                                      &FileObject,
                                      &DeviceObject);
    if (!NT_SUCCESS(Status))
    {
        return;
    }

    DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);

    KeInitializeEvent(&Event, NotificationEvent, FALSE);

    /* Set up empty IRP (yes, yes!) */
    Irp = IoBuildDeviceIoControlRequest(0,
                                        DeviceObject,
                                        NULL,
                                        0,
                                        NULL,
                                        0,
                                        FALSE,
                                        &Event,
                                        &IoStatusBlock);
    if (!Irp)
    {
        ObDereferenceObject(DeviceObject);
        ObDereferenceObject(FileObject);
        return;
    }

    Stack = IoGetNextIrpStackLocation(Irp);

    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
    Irp->IoStatus.Information = 0;

    /* Properly set it, we want to query device relations */
    Stack->MajorFunction = IRP_MJ_PNP;
    Stack->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
    Stack->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
    Stack->FileObject = FileObject;

    /* And call driver */
    Status = IoCallDriver(DeviceObject, Irp);
    if (Status == STATUS_PENDING)
    {
        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
        Status = IoStatusBlock.Status;
    }

    ObDereferenceObject(DeviceObject);
    ObDereferenceObject(FileObject);

    if (!NT_SUCCESS(Status))
    {
        return;
    }

    /* Validate device return */
    DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
    if (DeviceRelations->Count < 1)
    {
        ExFreePool(DeviceRelations);
        return;
    }

    DeviceObject = DeviceRelations->Objects[0];
    ExFreePool(DeviceRelations);

    /* Set up real notification */
    DeviceNotification.Version = 1;
    DeviceNotification.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION);
    DeviceNotification.Event = GUID_IO_VOLUME_NAME_CHANGE;
    DeviceNotification.FileObject = NULL;
    DeviceNotification.NameBufferOffset = -1;

    /* And report */
    IoReportTargetDeviceChangeAsynchronous(DeviceObject,
                                           &DeviceNotification,
                                           NULL, NULL);

    ObDereferenceObject(DeviceObject);

    return;
}
Пример #7
0
static FORCEINLINE NTSTATUS
__DriverQueryId(
    IN  PDEVICE_OBJECT      PhysicalDeviceObject,
    IN  BUS_QUERY_ID_TYPE   IdType,
    OUT PVOID               *Information
    )
{
    PDEVICE_OBJECT          DeviceObject;
    PIRP                    Irp;
    KEVENT                  Event;
    PIO_STACK_LOCATION      StackLocation;
    NTSTATUS                status;

    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);

    DeviceObject = IoGetAttachedDeviceReference(PhysicalDeviceObject);

    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);

    status = STATUS_INSUFFICIENT_RESOURCES;
    if (Irp == NULL)
        goto fail1;

    StackLocation = IoGetNextIrpStackLocation(Irp);

    StackLocation->MajorFunction = IRP_MJ_PNP;
    StackLocation->MinorFunction = IRP_MN_QUERY_ID;
    StackLocation->Flags = 0;
    StackLocation->Parameters.QueryId.IdType = IdType;
    StackLocation->DeviceObject = DeviceObject;
    StackLocation->FileObject = NULL;

    KeInitializeEvent(&Event, NotificationEvent, FALSE);

    IoSetCompletionRoutine(Irp,
                           DriverQueryIdCompletion,
                           &Event,
                           TRUE,
                           TRUE,
                           TRUE);

    // Default completion status
    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;

    status = IoCallDriver(DeviceObject, Irp);
    if (status == STATUS_PENDING) {
        (VOID) KeWaitForSingleObject(&Event,
                                     Executive,
                                     KernelMode,
                                     FALSE,
                                     NULL);
        status = Irp->IoStatus.Status;
    } else {
        ASSERT3U(status, ==, Irp->IoStatus.Status);
    }

    if (!NT_SUCCESS(status))
        goto fail2;

    *Information = (PVOID)Irp->IoStatus.Information;

    IoFreeIrp(Irp);
    ObDereferenceObject(DeviceObject);

    return STATUS_SUCCESS;

fail2:
    Error("fail2\n");

    IoFreeIrp(Irp);

fail1:
    Error("fail1 (%08x)\n", status);

    ObDereferenceObject(DeviceObject);

    return status;
}
Пример #8
0
NTSTATUS
NTAPI
PciQueryForPciBusInterface(IN PPCI_FDO_EXTENSION FdoExtension)
{
    PDEVICE_OBJECT AttachedDevice;
    IO_STATUS_BLOCK IoStatusBlock;
    KEVENT Event;
    NTSTATUS Status;
    PIRP Irp;
    PIO_STACK_LOCATION IoStackLocation;
    PPCI_BUS_INTERFACE_STANDARD PciInterface;
    PAGED_CODE();
    ASSERT(PCI_IS_ROOT_FDO(FdoExtension));

    /* Allocate space for the inteface */
    PciInterface = ExAllocatePoolWithTag(NonPagedPool,
                                         sizeof(PCI_BUS_INTERFACE_STANDARD),
                                         PCI_POOL_TAG);
    if (!PciInterface) return STATUS_INSUFFICIENT_RESOURCES;

    /* Get the device the PDO is attached to, should be the Root (ACPI) */
    AttachedDevice = IoGetAttachedDeviceReference(FdoExtension->PhysicalDeviceObject);

    /* Build an IRP for this request */
    KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
    Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
                                       AttachedDevice,
                                       NULL,
                                       0,
                                       NULL,
                                       &Event,
                                       &IoStatusBlock);
    if (Irp)
    {
        /* Initialize the default PnP response */
        Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
        Irp->IoStatus.Information = 0;

        /* Make it a Query Interface IRP */
        IoStackLocation = IoGetNextIrpStackLocation(Irp);
        ASSERT(IoStackLocation->MajorFunction == IRP_MJ_PNP);
        IoStackLocation->MinorFunction = IRP_MN_QUERY_INTERFACE;
        IoStackLocation->Parameters.QueryInterface.InterfaceType = &GUID_PCI_BUS_INTERFACE_STANDARD;
        IoStackLocation->Parameters.QueryInterface.Size = sizeof(GUID_PCI_BUS_INTERFACE_STANDARD);
        IoStackLocation->Parameters.QueryInterface.Version = PCI_BUS_INTERFACE_STANDARD_VERSION;
        IoStackLocation->Parameters.QueryInterface.Interface = (PINTERFACE)PciInterface;
        IoStackLocation->Parameters.QueryInterface.InterfaceSpecificData = NULL;

        /* Send it to the root PDO */
        Status = IoCallDriver(AttachedDevice, Irp);
        if (Status == STATUS_PENDING)
        {
            /* Wait for completion */
            KeWaitForSingleObject(&Event,
                                  Executive,
                                  KernelMode,
                                  FALSE,
                                  NULL);
            Status = Irp->IoStatus.Status;
        }

        /* Check if an interface was returned */
        if (!NT_SUCCESS(Status))
        {
            /* No interface was returned by the root PDO */
            FdoExtension->PciBusInterface = NULL;
            ExFreePoolWithTag(PciInterface, 0);
        }
        else
        {
            /* An interface was returned, save it */
            FdoExtension->PciBusInterface = PciInterface;
        }

        /* Dereference the device object because we took a reference earlier */
        ObfDereferenceObject(AttachedDevice);
    }
    else
    {
        /* Failure path, dereference the device object and set failure code */
        if (AttachedDevice) ObfDereferenceObject(AttachedDevice);
        ExFreePoolWithTag(PciInterface, 0);
        Status = STATUS_INSUFFICIENT_RESOURCES;
    }

    /* Return status code to caller */
    return Status;
}
VOID
FxPkgPnp::QueryForD3ColdInterface(
    VOID
    )
{
    MxDeviceObject deviceObject;
    PDEVICE_OBJECT topOfStack;
    PDEVICE_OBJECT pdo;
    FxAutoIrp irp;
    NTSTATUS status;

    //
    // This function can be invoked multiple times, particularly if filters
    // send IRP_MN_QUERY_CAPABILITIES.  So bail out if the interface has already
    // been acquired.
    //

    if ((m_D3ColdInterface.InterfaceDereference != NULL) ||
        (m_D3ColdInterface.GetIdleWakeInfo != NULL) ||
        (m_D3ColdInterface.SetD3ColdSupport != NULL)) {
        return;
    }

    pdo = m_Device->GetPhysicalDevice();

    if (pdo == NULL) {
        return;
    }

    //
    // Get the top of stack device object, even though normal filters and the
    // FDO may not have been added to the stack yet to ensure that this
    // query-interface is seen by bus filters.  Specifically, in a PCI device
    // which is soldered to the motherboard, ACPI will be on the stack and it
    // needs to see this IRP.
    //
    topOfStack = IoGetAttachedDeviceReference(pdo);
    deviceObject.SetObject(topOfStack);
    if (deviceObject.GetObject() != NULL) {
        irp.SetIrp(FxIrp::AllocateIrp(deviceObject.GetStackSize()));
        if (irp.GetIrp() == NULL) {

            DoTraceLevelMessage(
                GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
                "Failed to allocate IRP to get D3COLD_SUPPORT_INTERFACE from !devobj %p", 
                pdo);
        } else {

            //
            // Initialize the Irp
            //
            irp.SetStatus(STATUS_NOT_SUPPORTED);

            irp.ClearNextStack();
            irp.SetMajorFunction(IRP_MJ_PNP);
            irp.SetMinorFunction(IRP_MN_QUERY_INTERFACE);
            irp.SetParameterQueryInterfaceType(&GUID_D3COLD_SUPPORT_INTERFACE);
            irp.SetParameterQueryInterfaceVersion(D3COLD_SUPPORT_INTERFACE_VERSION);
            irp.SetParameterQueryInterfaceSize(sizeof(m_D3ColdInterface));
            irp.SetParameterQueryInterfaceInterfaceSpecificData(NULL);
            irp.SetParameterQueryInterfaceInterface((PINTERFACE)&m_D3ColdInterface);

            status = irp.SendIrpSynchronously(deviceObject.GetObject());

            if (!NT_SUCCESS(status)) {
                DoTraceLevelMessage(
                    GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
                    "!devobj %p declined to supply D3COLD_SUPPORT_INTERFACE", 
                    pdo);

                RtlZeroMemory(&m_D3ColdInterface, sizeof(m_D3ColdInterface));
            }
        }
    }
    ObDereferenceObject(topOfStack);
}