/*++

Copyright (c) Microsoft Corporation.  All rights reserved.

All rights reserved

Module Name:

    pnpdd.c

Abstract:

    This module implements new Plug-And-Play driver entries and IRPs.

Author:

    Shie-Lin Tzong (shielint) June-16-1995

Environment:

    Kernel mode only.

Revision History:

*/

#include "pnpmgrp.h"
#pragma hdrstop

#ifdef POOL_TAGGING
#undef ExAllocatePool
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'ddpP')
#endif

//
// Internal definitions and references
//

typedef struct _ROOT_ENUMERATOR_CONTEXT {
    NTSTATUS Status;
    PUNICODE_STRING KeyName;
    ULONG MaxDeviceCount;
    ULONG DeviceCount;
    PDEVICE_OBJECT *DeviceList;
} ROOT_ENUMERATOR_CONTEXT, *PROOT_ENUMERATOR_CONTEXT;

NTSTATUS
IopGetServiceType(
    IN PUNICODE_STRING KeyName,
    IN PULONG ServiceType
    );

BOOLEAN
IopInitializeDeviceInstanceKey(
    IN HANDLE KeyHandle,
    IN PUNICODE_STRING KeyName,
    IN OUT PVOID Context
    );

BOOLEAN
IopInitializeDeviceKey(
    IN HANDLE KeyHandle,
    IN PUNICODE_STRING KeyName,
    IN OUT PVOID Context
    );

BOOLEAN
IopIsFirmwareDisabled (
    IN PDEVICE_NODE DeviceNode
    );

VOID
IopPnPCompleteRequest(
    IN OUT PIRP Irp,
    IN NTSTATUS Status,
    IN ULONG_PTR Information
    );

NTSTATUS
IopTranslatorHandlerCm (
    IN PVOID Context,
    IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
    IN RESOURCE_TRANSLATION_DIRECTION Direction,
    IN ULONG AlternativesCount, OPTIONAL
    IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
    IN PDEVICE_OBJECT DeviceObject,
    OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
    );
NTSTATUS
IopTranslatorHandlerIo (
    IN PVOID Context,
    IN PIO_RESOURCE_DESCRIPTOR Source,
    IN PDEVICE_OBJECT DeviceObject,
    OUT PULONG TargetCount,
    OUT PIO_RESOURCE_DESCRIPTOR *Target
    );

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, IopGetRootDevices)
#pragma alloc_text(PAGE, IopGetServiceType)
#pragma alloc_text(PAGE, IopInitializeDeviceKey)
#pragma alloc_text(PAGE, IopInitializeDeviceInstanceKey)
#pragma alloc_text(PAGE, IopIsFirmwareDisabled)
#pragma alloc_text(PAGE, PipIsFirmwareMapperDevicePresent)
#pragma alloc_text(PAGE, IopPnPAddDevice)
#pragma alloc_text(PAGE, IopPnPDispatch)
#pragma alloc_text(PAGE, IopTranslatorHandlerCm)
#pragma alloc_text(PAGE, IopTranslatorHandlerIo)
#pragma alloc_text(PAGE, IopSystemControlDispatch)
#endif // ALLOC_PRAGMA

NTSTATUS
IopPnPAddDevice(
    IN PDRIVER_OBJECT DriverObject,
    IN PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:

    This routine handles AddDevice for an madeup PDO device.

Arguments:

    DriverObject - Pointer to our pseudo driver object.

    DeviceObject - Pointer to the device object for which this requestapplies.

Return Value:

    NT status.

--*/
{
    UNREFERENCED_PARAMETER( DriverObject );
    UNREFERENCED_PARAMETER( DeviceObject );

    PAGED_CODE();

#if DBG

    //
    // We should never get an AddDevice request.
    //

    DbgBreakPoint();

#endif

    return STATUS_SUCCESS;
}
//  PNPRES test

NTSTATUS
IopArbiterHandlerxx (
    IN PVOID Context,
    IN ARBITER_ACTION Action,
    IN OUT PARBITER_PARAMETERS Parameters
    )
{
    PLIST_ENTRY listHead, listEntry;
    PIO_RESOURCE_DESCRIPTOR ioDesc;
    PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc;
    PARBITER_LIST_ENTRY arbiterListEntry;

    UNREFERENCED_PARAMETER( Context );

    if (Action == ArbiterActionQueryArbitrate) {
        return STATUS_SUCCESS;
    }
    if (Parameters == NULL) {
        return STATUS_SUCCESS;
    }
    listHead = Parameters->Parameters.TestAllocation.ArbitrationList;
    if (IsListEmpty(listHead)) {
        return STATUS_SUCCESS;
    }
    listEntry = listHead->Flink;
    while (listEntry != listHead) {
      arbiterListEntry = (PARBITER_LIST_ENTRY)listEntry;
      cmDesc = arbiterListEntry->Assignment;
      ioDesc = arbiterListEntry->Alternatives;
      if (cmDesc == NULL || ioDesc == NULL) {
          return STATUS_SUCCESS;
      }
      cmDesc->Type = ioDesc->Type;
      cmDesc->ShareDisposition = ioDesc->ShareDisposition;
      cmDesc->Flags = ioDesc->Flags;
      if (ioDesc->Type == CmResourceTypePort) {
          cmDesc->u.Port.Start = ioDesc->u.Port.MinimumAddress;
          cmDesc->u.Port.Length = ioDesc->u.Port.Length;
      } else if (ioDesc->Type == CmResourceTypeInterrupt) {
          cmDesc->u.Interrupt.Level = ioDesc->u.Interrupt.MinimumVector;
          cmDesc->u.Interrupt.Vector = ioDesc->u.Interrupt.MinimumVector;
          cmDesc->u.Interrupt.Affinity = (ULONG) -1;
      } else if (ioDesc->Type == CmResourceTypeMemory) {
          cmDesc->u.Memory.Start = ioDesc->u.Memory.MinimumAddress;
          cmDesc->u.Memory.Length = ioDesc->u.Memory.Length;
      } else if (ioDesc->Type == CmResourceTypeDma) {
          cmDesc->u.Dma.Channel = ioDesc->u.Dma.MinimumChannel;
          cmDesc->u.Dma.Port = 0;
          cmDesc->u.Dma.Reserved1 = 0;
      }
      listEntry = listEntry->Flink;
    }
    return STATUS_SUCCESS;
}
NTSTATUS
IopTranslatorHandlerCm (
    IN PVOID Context,
    IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
    IN RESOURCE_TRANSLATION_DIRECTION Direction,
    IN ULONG AlternativesCount, OPTIONAL
    IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
    IN PDEVICE_OBJECT DeviceObject,
    OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
    )
{
    UNREFERENCED_PARAMETER( Context );
    UNREFERENCED_PARAMETER( Direction );
    UNREFERENCED_PARAMETER( AlternativesCount );
    UNREFERENCED_PARAMETER( Alternatives );
    UNREFERENCED_PARAMETER( DeviceObject );

    PAGED_CODE();

    *Target = *Source;
#if 0
    if (Direction == TranslateChildToParent) {
        if (Target->Type == CmResourceTypePort) {
            Target->u.Port.Start.LowPart += 0x10000;
        } else if (Target->Type == CmResourceTypeMemory) {
            Target->u.Memory.Start.LowPart += 0x100000;
        }
    } else {
        if (Target->Type == CmResourceTypePort) {
            Target->u.Port.Start.LowPart -= 0x10000;
        } else if (Target->Type == CmResourceTypeMemory) {
            Target->u.Memory.Start.LowPart -= 0x100000;
        }
    }
#endif
    return STATUS_SUCCESS;
}
NTSTATUS
IopTranslatorHandlerIo (
    IN PVOID Context,
    IN PIO_RESOURCE_DESCRIPTOR Source,
    IN PDEVICE_OBJECT DeviceObject,
    OUT PULONG TargetCount,
    OUT PIO_RESOURCE_DESCRIPTOR *Target
    )
{
    PIO_RESOURCE_DESCRIPTOR newDesc;

    UNREFERENCED_PARAMETER( Context );
    UNREFERENCED_PARAMETER( DeviceObject );

    PAGED_CODE();

    newDesc = (PIO_RESOURCE_DESCRIPTOR) ExAllocatePool(PagedPool, sizeof(IO_RESOURCE_DESCRIPTOR));
    if (newDesc == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    *TargetCount = 1;
    *newDesc = *Source;
#if 0
    if (newDesc->Type == CmResourceTypePort) {
        newDesc->u.Port.MinimumAddress.LowPart += 0x10000;
        newDesc->u.Port.MaximumAddress.LowPart += 0x10000;
    } else if (newDesc->Type == CmResourceTypeMemory) {
        newDesc->u.Memory.MinimumAddress.LowPart += 0x100000;
        newDesc->u.Memory.MaximumAddress.LowPart += 0x100000;
    }
#endif
    *Target = newDesc;
    return STATUS_SUCCESS;
}

NTSTATUS
IopPowerDispatch(
    IN PDEVICE_OBJECT DeviceObject,
    IN OUT PIRP Irp
    )
{
    PIO_STACK_LOCATION      IrpSp;
    PPOWER_SEQUENCE         PowerSequence;
    NTSTATUS                Status;


    UNREFERENCED_PARAMETER( DeviceObject );

    IrpSp = IoGetCurrentIrpStackLocation (Irp);
    Status = Irp->IoStatus.Status;

    switch (IrpSp->MinorFunction) {
        case IRP_MN_WAIT_WAKE:
            Status = STATUS_NOT_SUPPORTED;
            break;

        case IRP_MN_POWER_SEQUENCE:
            PowerSequence = IrpSp->Parameters.PowerSequence.PowerSequence;
            PowerSequence->SequenceD1 = PoPowerSequence;
            PowerSequence->SequenceD2 = PoPowerSequence;
            PowerSequence->SequenceD3 = PoPowerSequence;
            Status = STATUS_SUCCESS;
            break;

        case IRP_MN_QUERY_POWER:
            Status = STATUS_SUCCESS;
            break;

        case IRP_MN_SET_POWER:
            switch (IrpSp->Parameters.Power.Type) {
                case SystemPowerState:
                    Status = STATUS_SUCCESS;
                    break;

                case DevicePowerState:
                    //
                    // To be here the FDO must have passed the IRP on.
                    // We do not know how to turn the device off, but the
                    // FDO is prepaired for it work
                    //

                    Status = STATUS_SUCCESS;
                    break;

                default:
                    // Unkown power type
                    Status = STATUS_NOT_SUPPORTED;
                    break;
            }
            break;

        default:
            // Unkown power minor code
            Status = STATUS_NOT_SUPPORTED;
            break;
    }


    //
    // For lagecy devices that do not have drivers loaded, complete
    // power irps with success.
    //

    PoStartNextPowerIrp(Irp);
    if (Status != STATUS_NOT_SUPPORTED) {
       Irp->IoStatus.Status = Status;
    } else {
       Status = Irp->IoStatus.Status;
    }
    IoCompleteRequest( Irp, IO_NO_INCREMENT );
    return Status;
}

NTSTATUS
IopPnPDispatch(
    IN PDEVICE_OBJECT DeviceObject,
    IN OUT PIRP Irp
    )

/*++

Routine Description:

    This routine handles all IRP_MJ_PNP IRPs for madeup PDO device.

Arguments:

    DeviceObject - Pointer to the device object for which this IRP applies.

    Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.

Return Value:

    NT status.

--*/
{
    PIOPNP_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
    PIO_STACK_LOCATION irpSp;
    NTSTATUS status;
    PVOID information = NULL;
    ULONG length, uiNumber;
    PWCHAR id, wp;
    PDEVICE_NODE deviceNode;
    PARBITER_INTERFACE arbiterInterface;  // PNPRES test
    PTRANSLATOR_INTERFACE translatorInterface;  // PNPRES test

    PAGED_CODE();

    //
    // Get a pointer to our stack location and take appropriate action based
    // on the minor function.
    //

    irpSp = IoGetCurrentIrpStackLocation(Irp);
    switch (irpSp->MinorFunction){

    case IRP_MN_DEVICE_USAGE_NOTIFICATION:
    case IRP_MN_START_DEVICE:

        //
        // If we get a start device request for a PDO, we simply
        // return success.
        //

        status = STATUS_SUCCESS;
        break;

    case IRP_MN_CANCEL_STOP_DEVICE:

        //
        // As we fail all STOP's, this cancel is always successful, and we have
        // no work to do.
        //
        status = STATUS_SUCCESS;
        break;

    case IRP_MN_QUERY_STOP_DEVICE:
    case IRP_MN_STOP_DEVICE:

        //
        // We can not success the query stop.  We don't handle it.  because
        // we don't know how to stop a root enumerated device.
        //
        status = STATUS_UNSUCCESSFUL ;
        break;

    case IRP_MN_QUERY_RESOURCES:

        status = IopGetDeviceResourcesFromRegistry(
                         DeviceObject,
                         QUERY_RESOURCE_LIST,
                         REGISTRY_BOOT_CONFIG,
                         &information,
                         &length);
        if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
            status = STATUS_SUCCESS;
            information = NULL;
        }
        break;

    case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:

        status = IopGetDeviceResourcesFromRegistry(
                         DeviceObject,
                         QUERY_RESOURCE_REQUIREMENTS,
                         REGISTRY_BASIC_CONFIGVECTOR,
                         &information,
                         &length);
        if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
            status = STATUS_SUCCESS;
            information = NULL;
        }
        break;

    case IRP_MN_QUERY_REMOVE_DEVICE:
    case IRP_MN_REMOVE_DEVICE:
    case IRP_MN_CANCEL_REMOVE_DEVICE:

        //
        // For root enumerated devices we let the device objects stay.
        //
        status = STATUS_SUCCESS;
        break;

    case IRP_MN_QUERY_DEVICE_RELATIONS:

        if (DeviceObject == IopRootDeviceNode->PhysicalDeviceObject &&
            irpSp->Parameters.QueryDeviceRelations.Type == BusRelations) {
            status = IopGetRootDevices((PDEVICE_RELATIONS *)&information);
        } else {
            if (irpSp->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation) {
                PDEVICE_RELATIONS deviceRelations;

                deviceRelations = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
                if (deviceRelations == NULL) {
                    status = STATUS_INSUFFICIENT_RESOURCES;
                } else {
                    deviceRelations->Count = 1;
                    deviceRelations->Objects[0] = DeviceObject;
                    ObReferenceObject(DeviceObject);
                    information = (PVOID)deviceRelations;
                    status = STATUS_SUCCESS;
                }
            } else {
                information = (PVOID)Irp->IoStatus.Information;
                status = Irp->IoStatus.Status;
            }
        }
        break;

    case IRP_MN_QUERY_INTERFACE:
        status = Irp->IoStatus.Status;
        deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode;
        if (deviceNode == IopRootDeviceNode) {
            if ( IopCompareGuid((PVOID)irpSp->Parameters.QueryInterface.InterfaceType, (PVOID)&GUID_ARBITER_INTERFACE_STANDARD)) {
                status = STATUS_SUCCESS;
                arbiterInterface = (PARBITER_INTERFACE) irpSp->Parameters.QueryInterface.Interface;
                arbiterInterface->ArbiterHandler = ArbArbiterHandler;
                switch ((UCHAR)((ULONG_PTR)irpSp->Parameters.QueryInterface.InterfaceSpecificData)) {
                case CmResourceTypePort:
                    arbiterInterface->Context = (PVOID) &IopRootPortArbiter;
                    break;
                case CmResourceTypeMemory:
                    arbiterInterface->Context = (PVOID) &IopRootMemArbiter;
                    break;
                case CmResourceTypeInterrupt:
                    arbiterInterface->Context = (PVOID) &IopRootIrqArbiter;
                    break;
                case CmResourceTypeDma:
                    arbiterInterface->Context = (PVOID) &IopRootDmaArbiter;
                    break;
                case CmResourceTypeBusNumber:
                    arbiterInterface->Context = (PVOID) &IopRootBusNumberArbiter;
                    break;
                default:
                    status = STATUS_INVALID_PARAMETER;
                    break;
                }
            } else if ( IopCompareGuid((PVOID)irpSp->Parameters.QueryInterface.InterfaceType, (PVOID)&GUID_TRANSLATOR_INTERFACE_STANDARD)) {
                translatorInterface = (PTRANSLATOR_INTERFACE) irpSp->Parameters.QueryInterface.Interface;
                translatorInterface->TranslateResources = IopTranslatorHandlerCm;
                translatorInterface->TranslateResourceRequirements = IopTranslatorHandlerIo;
                status = STATUS_SUCCESS;
            }
        }
        break;

    case IRP_MN_QUERY_CAPABILITIES:

        {
            ULONG i;
            PDEVICE_POWER_STATE state;
            PDEVICE_CAPABILITIES deviceCapabilities;

            deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode;

            deviceCapabilities = irpSp->Parameters.DeviceCapabilities.Capabilities;
            deviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
            deviceCapabilities->Version = 1;

            deviceCapabilities->DeviceState[PowerSystemUnspecified]=PowerDeviceUnspecified;
            deviceCapabilities->DeviceState[PowerSystemWorking]=PowerDeviceD0;

            state = &deviceCapabilities->DeviceState[PowerSystemSleeping1];

            for (i = PowerSystemSleeping1; i < PowerSystemMaximum; i++) {

                //
                // Only supported state, currently, is off.
                //

                *state++ = PowerDeviceD3;
            }

            if(IopIsFirmwareDisabled(deviceNode)) {
                //
                // this device has been disabled by BIOS
                //
                deviceCapabilities->HardwareDisabled = TRUE;
            }
            if (deviceCapabilities->UINumber == (ULONG)-1) {
                //
                // Get the UI number from the registry.
                //
                length = sizeof(uiNumber);
                status = PiGetDeviceRegistryProperty(
                    DeviceObject,
                    REG_DWORD,
                    REGSTR_VALUE_UI_NUMBER,
                    NULL,
                    &uiNumber,
                    &length);
                if (NT_SUCCESS(status)) {

                    deviceCapabilities->UINumber = uiNumber;
                }
            }

            status = STATUS_SUCCESS;
        }
        break;

    case IRP_MN_QUERY_ID:
        if (DeviceObject != IopRootDeviceNode->PhysicalDeviceObject &&
            (!NT_SUCCESS(Irp->IoStatus.Status) || !Irp->IoStatus.Information)) {

            deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode;
            switch (irpSp->Parameters.QueryId.IdType) {

            case BusQueryInstanceID:
            case BusQueryDeviceID:

                id = (PWCHAR)ExAllocatePool(PagedPool, deviceNode->InstancePath.Length);
                if (id) {
                    ULONG separatorCount = 0;

                    RtlZeroMemory(id, deviceNode->InstancePath.Length);
                    information = id;
                    status = STATUS_SUCCESS;
                    wp = deviceNode->InstancePath.Buffer;
                    if (irpSp->Parameters.QueryId.IdType == BusQueryDeviceID) {
                        while(*wp) {
                            if (*wp == OBJ_NAME_PATH_SEPARATOR) {
                                separatorCount++;
                                if (separatorCount == 2) {
                                    break;
                                }
                            }
                            *id = *wp;
                            id++;
                            wp++;
                        }
                    } else {
                        while(*wp) {
                            if (*wp == OBJ_NAME_PATH_SEPARATOR) {
                                separatorCount++;
                                if (separatorCount == 2) {
                                    wp++;
                                    break;
                                }
                            }
                            wp++;
                        }
                        while (*wp) {
                            *id = *wp;
                            id++;
                            wp++;
                        }
                    }
                } else {
                    status = STATUS_INSUFFICIENT_RESOURCES;
                }
                break;

            case BusQueryCompatibleIDs:

                if((Irp->IoStatus.Status != STATUS_NOT_SUPPORTED) ||
                   (deviceExtension == NULL))  {

                    //
                    // Upper driver has given some sort of reply or this device
                    // object wasn't allocated to handle these requests.
                    //

                    status = Irp->IoStatus.Status;
                    break;
                }

                if(deviceExtension->CompatibleIdListSize != 0) {

                    id = ExAllocatePool(PagedPool,
                                        deviceExtension->CompatibleIdListSize);

                    if(id == NULL) {
                        status = STATUS_INSUFFICIENT_RESOURCES;
                        break;
                    }

                    RtlCopyMemory(id,
                                  deviceExtension->CompatibleIdList,
                                  deviceExtension->CompatibleIdListSize);

                    information = id;
                    status = STATUS_SUCCESS;
                    break;
                }

            default:

                information = (PVOID)Irp->IoStatus.Information;
                status = Irp->IoStatus.Status;
            }
        } else {
            information = (PVOID)Irp->IoStatus.Information;
            status = Irp->IoStatus.Status;
        }

        break;

    case IRP_MN_QUERY_DEVICE_TEXT:

        if (    irpSp->Parameters.QueryDeviceText.DeviceTextType == DeviceTextLocationInformation &&
                !Irp->IoStatus.Information) {
            //
            // Read and return the location in the registry.
            //
            length = 0;
            PiGetDeviceRegistryProperty(
                DeviceObject,
                REG_SZ,
                REGSTR_VALUE_LOCATION_INFORMATION,
                NULL,
                NULL,
                &length);
            if (length) {

                information = ExAllocatePool(PagedPool, length);
                if (information) {

                    status = PiGetDeviceRegistryProperty(
                        DeviceObject,
                        REG_SZ,
                        REGSTR_VALUE_LOCATION_INFORMATION,
                        NULL,
                        information,
                        &length);
                    if (!NT_SUCCESS(status)) {

                        ExFreePool(information);
                        information = NULL;
                    }
                } else {

                    status = STATUS_INSUFFICIENT_RESOURCES;
                }
            } else {

                status = STATUS_UNSUCCESSFUL;
            }
        } else {

            information = (PVOID)Irp->IoStatus.Information;
            status = Irp->IoStatus.Status;
        }
        break;

    default:

        information = (PVOID)Irp->IoStatus.Information;
        status = Irp->IoStatus.Status;
        break;
    }

    //
    // Complete the Irp and return.
    //

    IopPnPCompleteRequest(Irp, status, (ULONG_PTR)information);
    return status;
}

VOID
IopPnPCompleteRequest(
    IN OUT PIRP Irp,
    IN NTSTATUS Status,
    IN ULONG_PTR Information
    )

/*++

Routine Description:

    This routine completes PnP irps for our pseudo driver.

Arguments:

    Irp - Supplies a pointer to the irp to be completed.

    Status - completion status.

    Information - completion information to be passed back.

Return Value:

    None.

--*/

{

    //
    // Complete the IRP.  First update the status...
    //

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

    //
    // ... and complete it.
    //

    IoCompleteRequest(Irp, IO_NO_INCREMENT);
}

BOOLEAN
IopIsFirmwareDisabled (
    IN PDEVICE_NODE DeviceNode
    )

/*++

Routine Description:

    This routine determines if the devicenode has been disabled by firmware.

Arguments:

    DeviceNode - Supplies a pointer to the device node structure of the device.

Return Value:

    TRUE if disabled, otherwise FALSE

--*/
{
    NTSTATUS status;
    PDEVICE_OBJECT deviceObject = DeviceNode->PhysicalDeviceObject;
    HANDLE handle, handlex;
    UNICODE_STRING unicodeName;
    UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(ULONG)];
    PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
    ULONG buflen;
    BOOLEAN FirmwareDisabled = FALSE;

    PiLockPnpRegistry(FALSE);

    status = IopDeviceObjectToDeviceInstance(
                                    deviceObject,
                                    &handlex,
                                    KEY_ALL_ACCESS);
    if (NT_SUCCESS(status)) {

        //
        // Open the LogConfig key of the device instance.
        //

        PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_CONTROL);
        status = IopCreateRegistryKeyEx( &handle,
                                         handlex,
                                         &unicodeName,
                                         KEY_ALL_ACCESS,
                                         REG_OPTION_VOLATILE,
                                         NULL
                                         );
        ZwClose(handlex);
        if (NT_SUCCESS(status)) {

            PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_FIRMWAREDISABLED);
            value = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
            buflen = sizeof(buffer);
            status = ZwQueryValueKey(handle,
                                     &unicodeName,
                                     KeyValuePartialInformation,
                                     value,
                                     sizeof(buffer),
                                     &buflen
                                     );

            ZwClose(handle);

            //
            // We don't need to check the buffer was big enough because it starts
            // off that way and doesn't get any smaller!
            //

            if (NT_SUCCESS(status)
                && value->Type == REG_DWORD
                && value->DataLength == sizeof(ULONG)
                && (*(PULONG)(value->Data))!=0) {

                //
                // firmware disabled
                //
                FirmwareDisabled = TRUE;
            }
        }
    }
    PiUnlockPnpRegistry();
    return FirmwareDisabled;
}


NTSTATUS
IopGetRootDevices (
    PDEVICE_RELATIONS *DeviceRelations
    )

/*++

Routine Description:

    This routine scans through System\Enum\Root subtree to build a device node for
    each root device.

Arguments:

    DeviceRelations - supplies a variable to receive the returned DEVICE_RELATIONS structure.

Return Value:

    A NTSTATUS code.

--*/

{
    NTSTATUS status;
    HANDLE baseHandle;
    UNICODE_STRING workName, tmpName;
    PVOID buffer;
    ROOT_ENUMERATOR_CONTEXT context;
    ULONG i;
    PDEVICE_RELATIONS deviceRelations;

    PAGED_CODE();

    *DeviceRelations = NULL;
    buffer = ExAllocatePool(PagedPool, PNP_LARGE_SCRATCH_BUFFER_SIZE);
    if (!buffer) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    // Allocate a buffer to store the PDOs enumerated.
    // Note, the the buffer turns out to be not big enough, it will be reallocated dynamically.
    //

    context.DeviceList = (PDEVICE_OBJECT *) ExAllocatePool(PagedPool, PNP_SCRATCH_BUFFER_SIZE * 2);
    if (context.DeviceList) {
        context.MaxDeviceCount = (PNP_SCRATCH_BUFFER_SIZE * 2) / sizeof(PDEVICE_OBJECT);
        context.DeviceCount = 0;
    } else {
        ExFreePool(buffer);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    PiLockPnpRegistry(TRUE);

    //
    // Open System\CurrentControlSet\Enum\Root key and call worker routine to recursively
    // scan through the subkeys.
    //

    status = IopCreateRegistryKeyEx( &baseHandle,
                                     NULL,
                                     &CmRegistryMachineSystemCurrentControlSetEnumRootName,
                                     KEY_READ,
                                     REG_OPTION_NON_VOLATILE,
                                     NULL
                                     );

    if (NT_SUCCESS(status)) {

        workName.Buffer = (PWSTR)buffer;
        RtlFillMemory(buffer, PNP_LARGE_SCRATCH_BUFFER_SIZE, 0);
        workName.MaximumLength = PNP_LARGE_SCRATCH_BUFFER_SIZE;
        workName.Length = 0;

        //
        // only look at ROOT key
        //

        PiWstrToUnicodeString(&tmpName, REGSTR_KEY_ROOTENUM);
        RtlAppendStringToString((PSTRING)&workName, (PSTRING)&tmpName);

        //
        // Enumerate all subkeys under the System\CCS\Enum\Root.
        //

        context.Status = STATUS_SUCCESS;
        context.KeyName = &workName;

        status = PipApplyFunctionToSubKeys(baseHandle,
                                           NULL,
                                           KEY_ALL_ACCESS,
                                           FUNCTIONSUBKEY_FLAG_IGNORE_NON_CRITICAL_ERRORS,
                                           IopInitializeDeviceKey,
                                           &context
                                           );
        ZwClose(baseHandle);

        //
        // Build returned information from ROOT_ENUMERATOR_CONTEXT.
        //


        status = context.Status;
        if (NT_SUCCESS(status) && context.DeviceCount != 0) {
            deviceRelations = (PDEVICE_RELATIONS) ExAllocatePool(
                PagedPool,
                sizeof (DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * context.DeviceCount
                );
            if (deviceRelations == NULL) {
                status = STATUS_INSUFFICIENT_RESOURCES;
            } else {
                deviceRelations->Count = context.DeviceCount;
                RtlCopyMemory(deviceRelations->Objects,
                              context.DeviceList,
                              sizeof (PDEVICE_OBJECT) * context.DeviceCount);
                *DeviceRelations = deviceRelations;
            }
        }
        if (!NT_SUCCESS(status)) {

            //
            // If somehow the enumeration failed, we need to derefernece all the
            // device objects.
            //

            for (i = 0; i < context.DeviceCount; i++) {
                ObDereferenceObject(context.DeviceList[i]);
            }
        }
    }
    PiUnlockPnpRegistry();
    ExFreePool(buffer);
    ExFreePool(context.DeviceList);
    return status;
}

BOOLEAN
IopInitializeDeviceKey(
    IN HANDLE KeyHandle,
    IN PUNICODE_STRING KeyName,
    IN OUT PVOID Context
    )

/*++

Routine Description:

    This routine is a callback function for PipApplyFunctionToSubKeys.
    It is called for each subkey under HKLM\System\CCS\Enum\BusKey.

Arguments:

    KeyHandle - Supplies a handle to this key.

    KeyName - Supplies the name of this key.

    Context - points to the ROOT_ENUMERATOR_CONTEXT structure.

Returns:

    TRUE to continue the enumeration.
    FALSE to abort it.

--*/
{
    USHORT length;
    PWSTR p;
    PUNICODE_STRING unicodeName = ((PROOT_ENUMERATOR_CONTEXT)Context)->KeyName;

    length = unicodeName->Length;

    p = unicodeName->Buffer;
    if ( unicodeName->Length / sizeof(WCHAR) != 0) {
        p += unicodeName->Length / sizeof(WCHAR);
        *p = OBJ_NAME_PATH_SEPARATOR;
        unicodeName->Length += sizeof (WCHAR);
    }

    RtlAppendStringToString((PSTRING)unicodeName, (PSTRING)KeyName);

    //
    // Enumerate all subkeys under the current device key.
    //

    PipApplyFunctionToSubKeys(KeyHandle,
                              NULL,
                              KEY_ALL_ACCESS,
                              FUNCTIONSUBKEY_FLAG_IGNORE_NON_CRITICAL_ERRORS,
                              IopInitializeDeviceInstanceKey,
                              Context
                              );
    unicodeName->Length = length;

    return (BOOLEAN)NT_SUCCESS(((PROOT_ENUMERATOR_CONTEXT)Context)->Status);
}

BOOLEAN
IopInitializeDeviceInstanceKey(
    IN HANDLE KeyHandle,
    IN PUNICODE_STRING KeyName,
    IN OUT PVOID Context
    )

/*++

Routine Description:

    This routine is a callback function for PipApplyFunctionToSubKeys.
    It is called for each subkey under HKLM\System\Enum\Root\DeviceKey.

Arguments:

    KeyHandle - Supplies a handle to this key.

    KeyName - Supplies the name of this key.

    Context - points to the ROOT_ENUMERATOR_CONTEXT structure.

Returns:

    TRUE to continue the enumeration.
    FALSE to abort it.

--*/
{
    UNICODE_STRING unicodeName, serviceName;
    PKEY_VALUE_FULL_INFORMATION serviceKeyValueInfo;
    PKEY_VALUE_FULL_INFORMATION keyValueInformation;
    NTSTATUS status;
    BOOLEAN isDuplicate = FALSE;
    BOOLEAN configuredBySetup;
    ULONG deviceFlags, tmpValue1;
    ULONG legacy;
    USHORT savedLength;
    PUNICODE_STRING pUnicode;
    HANDLE handle;
    PDEVICE_OBJECT deviceObject;
    PDEVICE_NODE deviceNode = NULL;
    PROOT_ENUMERATOR_CONTEXT enumContext = (PROOT_ENUMERATOR_CONTEXT)Context;

    //
    // First off, check to see if this is a phantom device instance (i.e.,
    // registry key only).  If so, we want to totally ignore this key and
    // move on to the next one.
    //
    status = IopGetRegistryValue(KeyHandle,
                                 REGSTR_VAL_PHANTOM,
                                 &keyValueInformation);

    if (NT_SUCCESS(status)) {
        if ((keyValueInformation->Type == REG_DWORD) &&
            (keyValueInformation->DataLength >= sizeof(ULONG))) {
            tmpValue1 = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
        } else {
            tmpValue1 = 0;
        }

        ExFreePool(keyValueInformation);

        if (tmpValue1) {
            return TRUE;
        }
    }

    //
    // Since it is highly likely we are going to report another PDO make sure
    // there will be room in the buffer.
    //

    if (enumContext->DeviceCount == enumContext->MaxDeviceCount) {

        PDEVICE_OBJECT *tmpDeviceObjectList;
        ULONG tmpDeviceObjectListSize;

        //
        // We need to grow our PDO list buffer.
        //

        tmpDeviceObjectListSize = (enumContext->MaxDeviceCount * sizeof(PDEVICE_OBJECT))
                                        + (PNP_SCRATCH_BUFFER_SIZE * 2);

        tmpDeviceObjectList = ExAllocatePool(PagedPool, tmpDeviceObjectListSize);

        if (tmpDeviceObjectList) {

            RtlCopyMemory( tmpDeviceObjectList,
                           enumContext->DeviceList,
                           enumContext->DeviceCount * sizeof(PDEVICE_OBJECT)
                           );
            ExFreePool(enumContext->DeviceList);
            enumContext->DeviceList = tmpDeviceObjectList;
            enumContext->MaxDeviceCount = tmpDeviceObjectListSize / sizeof(PDEVICE_OBJECT);

        } else {

            //
            // We are out of memory.  There is no point going any further
            // since we don't have any place to report the PDOs anyways.
            //

            enumContext->Status = STATUS_INSUFFICIENT_RESOURCES;

            return FALSE;
        }
    }

    //
    // Combine Context->KeyName, i.e. the device name and KeyName (device instance name)
    // to form device instance path.
    //

    pUnicode = ((PROOT_ENUMERATOR_CONTEXT)Context)->KeyName;
    savedLength = pUnicode->Length;                  // Save WorkName
    if (pUnicode->Buffer[pUnicode->Length / sizeof(WCHAR) - 1] != OBJ_NAME_PATH_SEPARATOR) {
        pUnicode->Buffer[pUnicode->Length / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
        pUnicode->Length += 2;
    }

    RtlAppendStringToString((PSTRING)pUnicode, (PSTRING)KeyName);

    //
    // Check if the PDO for the device instance key exists already.  If no,
    // see if we need to create it.
    //

    deviceObject = IopDeviceObjectFromDeviceInstance(pUnicode);

    if (deviceObject != NULL) {

        enumContext->DeviceList[enumContext->DeviceCount] = deviceObject;
        enumContext->DeviceCount++;
        pUnicode->Length = savedLength;         // Restore WorkName
        return TRUE;
    }

    //
    // We don't have device object for it.
    // First check if this key was created by firmware mapper.  If yes, make sure
    // the device is still present.
    //

    if (!PipIsFirmwareMapperDevicePresent(KeyHandle)) {
        pUnicode->Length = savedLength;         // Restore WorkName
        return TRUE;
    }

    //
    // Get the "DuplicateOf" value entry to determine if the device instance
    // should be registered.  If the device instance is duplicate, We don't
    // add it to its service key's enum branch.
    //

    status = IopGetRegistryValue( KeyHandle,
                                  REGSTR_VALUE_DUPLICATEOF,
                                  &keyValueInformation
                                  );
    if (NT_SUCCESS(status)) {
        if (keyValueInformation->Type == REG_SZ &&
            keyValueInformation->DataLength > 0) {
            isDuplicate = TRUE;
        }

        ExFreePool(keyValueInformation);
    }

    //
    // Get the "Service=" value entry from KeyHandle
    //

    serviceKeyValueInfo = NULL;

    PiWstrToUnicodeString(&serviceName, NULL);

    status = IopGetRegistryValue ( KeyHandle,
                                   REGSTR_VALUE_SERVICE,
                                   &serviceKeyValueInfo
                                   );
    if (NT_SUCCESS(status)) {

        //
        // Append the new instance to its corresponding
        // Service\Name\Enum.
        //

        if (serviceKeyValueInfo->Type == REG_SZ &&
            serviceKeyValueInfo->DataLength != 0) {

            //
            // Set up ServiceKeyName unicode string
            //

            IopRegistryDataToUnicodeString(
                                &serviceName,
                                (PWSTR)KEY_VALUE_DATA(serviceKeyValueInfo),
                                serviceKeyValueInfo->DataLength
                                );
        }

        //
        // Do not Free serviceKeyValueInfo.  It contains Service Name.
        //

    }

    //
    // Register this device instance by constructing new value entry for
    // ServiceKeyName\Enum key.i.e., <Number> = <PathToSystemEnumBranch>
    // For the stuff under Root, we need to expose devnodes for everything
    // except those devices whose CsConfigFlags are set to CSCONFIGFLAG_DO_NOT_CREATE.
    //

    status = IopGetDeviceInstanceCsConfigFlags( pUnicode, &deviceFlags );

    if (NT_SUCCESS(status) && (deviceFlags & CSCONFIGFLAG_DO_NOT_CREATE)) {
        ExFreePool(serviceKeyValueInfo);
        pUnicode->Length = savedLength;         // Restore WorkName
        return TRUE;
    }

    //
    // Make sure this device instance is really a "device" by checking
    // the "Legacy" value name.
    //

    legacy = 0;
    status = IopGetRegistryValue( KeyHandle,
                                  REGSTR_VALUE_LEGACY,
                                  &keyValueInformation
                                  );
    if (NT_SUCCESS(status)) {

        //
        // If "Legacy=" exists ...
        //

        if (keyValueInformation->Type == REG_DWORD) {
            if (keyValueInformation->DataLength >= sizeof(ULONG)) {
                legacy = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
            }
        }
        ExFreePool(keyValueInformation);
    }

    if (legacy) {
        BOOLEAN doCreate = FALSE;

        //
        // Check if the the service for the device instance is a kernel mode
        // driver (even though it is a legacy device instance.) If yes, we will
        // create a PDO for it.
        //

        if (serviceName.Length) {
            status = IopGetServiceType(&serviceName, &tmpValue1);
            if (NT_SUCCESS(status) && tmpValue1 == SERVICE_KERNEL_DRIVER) {
                doCreate = TRUE;
            }
        }

        if (!doCreate)  {

            //
            // We are not creating PDO for the device instance.  In this case we
            // need to register the device ourself for legacy compatibility.
            //
            // Note we will register this device to its driver even it is a
            // duplicate.  It will be deregistered when the real enumerated
            // device shows up.  We need to do this because the driver which
            // controls the device may be a boot driver.
            //

            PpDeviceRegistration( pUnicode, TRUE, NULL );

            //
            // We did not create a PDO.  Release the service and ordinal names.
            //

            if (serviceKeyValueInfo) {
                ExFreePool(serviceKeyValueInfo);
            }

            pUnicode->Length = savedLength;         // Restore WorkName

            return TRUE;
        }
    }

    if (serviceKeyValueInfo) {
        ExFreePool(serviceKeyValueInfo);
    }

    //
    // Create madeup PDO and device node to represent the root device.
    //

    //
    // Madeup a name for the device object.
    //

    //
    // Create madeup PDO and device node to represent the root device.
    //

    status = IoCreateDevice( IoPnpDriverObject,
                             sizeof(IOPNP_DEVICE_EXTENSION),
                             NULL,
                             FILE_DEVICE_CONTROLLER,
                             FILE_AUTOGENERATED_DEVICE_NAME,
                             FALSE,
                             &deviceObject );

    if (NT_SUCCESS(status)) {

        deviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
        deviceObject->DeviceObjectExtension->ExtensionFlags |= DOE_START_PENDING;

        status = PipAllocateDeviceNode(deviceObject, &deviceNode);
        if (status != STATUS_SYSTEM_HIVE_TOO_LARGE && deviceNode) {

            //
            // Make a copy of the device instance path and save it in
            // device node.
            //

            if (PipConcatenateUnicodeStrings(   &deviceNode->InstancePath,
                                                pUnicode,
                                                NULL
                                                )) {
                PCM_RESOURCE_LIST cmResource;

                deviceNode->Flags = DNF_MADEUP | DNF_ENUMERATED;

                PipSetDevNodeState(deviceNode, DeviceNodeInitialized, NULL);

                PpDevNodeInsertIntoTree(IopRootDeviceNode, deviceNode);

                if (legacy) {

                    deviceNode->Flags |= DNF_LEGACY_DRIVER | DNF_NO_RESOURCE_REQUIRED;

                    PipSetDevNodeState( deviceNode, DeviceNodeStarted, NULL );

                } else {

                    //
                    // The device instance key exists.  We need to propagate the ConfigFlag
                    // to problem and StatusFlags
                    //

                    deviceFlags = 0;
                    status = IopGetRegistryValue(KeyHandle,
                                                    REGSTR_VALUE_CONFIG_FLAGS,
                                                    &keyValueInformation);
                    if (NT_SUCCESS(status)) {
                        if ((keyValueInformation->Type == REG_DWORD) &&
                            (keyValueInformation->DataLength >= sizeof(ULONG))) {
                            deviceFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
                        }
                        ExFreePool(keyValueInformation);
                        if (deviceFlags & CONFIGFLAG_REINSTALL) {
                            PipSetDevNodeProblem(deviceNode, CM_PROB_REINSTALL);
                        } else if (deviceFlags & CONFIGFLAG_PARTIAL_LOG_CONF) {
                            PipSetDevNodeProblem(deviceNode, CM_PROB_PARTIAL_LOG_CONF);
                        } else if (deviceFlags & CONFIGFLAG_FAILEDINSTALL) {
                            PipSetDevNodeProblem(deviceNode, CM_PROB_FAILED_INSTALL);
                        }

                    } else if (status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND) {
                        PipSetDevNodeProblem(deviceNode, CM_PROB_NOT_CONFIGURED);
                    }
                }

                if (isDuplicate) {
                    deviceNode->Flags |= DNF_DUPLICATE;
                }

                //
                // If the key say don't assign any resource, honor it...
                //

                PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_NO_RESOURCE_AT_INIT);
                status = IopGetRegistryValue( KeyHandle,
                                              unicodeName.Buffer,
                                              &keyValueInformation
                                              );

                if (NT_SUCCESS(status)) {
                    if (keyValueInformation->Type == REG_DWORD) {
                        if (keyValueInformation->DataLength >= sizeof(ULONG)) {
                            tmpValue1 = *(PULONG)KEY_VALUE_DATA(keyValueInformation);

                            if (tmpValue1 != 0) {
                                deviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
                            }
                        }
                    }
                    ExFreePool(keyValueInformation);
                }

                //
                // we need to set initial capabilities, like any other device
                // this will also handle hardware-disabled case
                //
                IopQueryAndSaveDeviceNodeCapabilities(deviceNode);

                if (IopDeviceNodeFlagsToCapabilities(deviceNode)->HardwareDisabled &&
                    !PipIsDevNodeProblem(deviceNode,CM_PROB_NOT_CONFIGURED)) {
                    //
                    // mark the node as hardware disabled, if no other problems
                    //

                    PipClearDevNodeProblem(deviceNode);
                    PipSetDevNodeProblem(deviceNode, CM_PROB_HARDWARE_DISABLED);
                    //
                    // Issue a PNP REMOVE_DEVICE Irp so when we query resources
                    // we have those required after boot
                    //
                    //status = IopRemoveDevice (deviceNode->PhysicalDeviceObject, IRP_MN_REMOVE_DEVICE);
                    //ASSERT(NT_SUCCESS(status));
                }

                //
                // Install service for critical devices.
                // however don't do it if we found HardwareDisabled to be set
                //
                if (PipDoesDevNodeHaveProblem(deviceNode) &&
                    !IopDeviceNodeFlagsToCapabilities(deviceNode)->HardwareDisabled) {
                    PipProcessCriticalDevice(deviceNode);
                }

                //
                // Set DNF_DISABLED flag if the device instance is disabled.
                //

                ASSERT(!PipDoesDevNodeHaveProblem(deviceNode) ||
                        PipIsDevNodeProblem(deviceNode, CM_PROB_NOT_CONFIGURED) ||
                        PipIsDevNodeProblem(deviceNode, CM_PROB_REINSTALL) ||
                        PipIsDevNodeProblem(deviceNode, CM_PROB_FAILED_INSTALL) ||
                        PipIsDevNodeProblem(deviceNode, CM_PROB_HARDWARE_DISABLED) ||
                        PipIsDevNodeProblem(deviceNode, CM_PROB_PARTIAL_LOG_CONF));

                if (!PipIsDevNodeProblem(deviceNode, CM_PROB_DISABLED) &&
                    !PipIsDevNodeProblem(deviceNode, CM_PROB_HARDWARE_DISABLED) &&
                    !IopIsDeviceInstanceEnabled(KeyHandle, &deviceNode->InstancePath, TRUE)) {

                    //
                    // Normally IopIsDeviceInstanceEnabled would set
                    // CM_PROB_DISABLED as a side effect (if necessary).  But it
                    // relies on the DeviceReference already being in the registry.
                    // We don't write it out till later so just set the problem
                    // now.

                    PipClearDevNodeProblem( deviceNode );
                    PipSetDevNodeProblem( deviceNode, CM_PROB_DISABLED );
                }

                status = IopNotifySetupDeviceArrival( deviceNode->PhysicalDeviceObject,
                                                      KeyHandle,
                                                      TRUE);

                configuredBySetup = (BOOLEAN)NT_SUCCESS(status);

                status = PpDeviceRegistration( &deviceNode->InstancePath,
                                               TRUE,
                                               &deviceNode->ServiceName
                                               );

                if (NT_SUCCESS(status) && configuredBySetup &&
                    PipIsDevNodeProblem(deviceNode, CM_PROB_NOT_CONFIGURED)) {

                    PipClearDevNodeProblem(deviceNode);
                }

                //
                // Add an entry into the table to set up a mapping between the DO
                // and the instance path.
                //

                status = IopMapDeviceObjectToDeviceInstance(deviceNode->PhysicalDeviceObject, &deviceNode->InstancePath);
                ASSERT(NT_SUCCESS(status));

                //
                // Add a reference for config magr
                //

                ObReferenceObject(deviceObject);

                //
                // Check if this device has BOOT config.  If yes, reserve them
                //

                cmResource = NULL;
                status = IopGetDeviceResourcesFromRegistry (
                                    deviceObject,
                                    QUERY_RESOURCE_LIST,
                                    REGISTRY_BOOT_CONFIG,
                                    &cmResource,
                                    &tmpValue1
                                    );

                if (NT_SUCCESS(status) && cmResource) {

                    //
                    // Still reserve boot config, even though the device is
                    // disabled.
                    //

                    status = (*IopAllocateBootResourcesRoutine)(
                                            ArbiterRequestPnpEnumerated,
                                            deviceNode->PhysicalDeviceObject,
                                            cmResource);
                    if (NT_SUCCESS(status)) {
                        deviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
                    }
                    ExFreePool(cmResource);
                }

                status = STATUS_SUCCESS;

                //
                // Add a reference for query device relations
                //

                ObReferenceObject(deviceObject);
            } else {
                IoDeleteDevice(deviceObject);
                deviceObject = NULL;
                status = STATUS_INSUFFICIENT_RESOURCES;
            }
        } else {

            IoDeleteDevice(deviceObject);
            deviceObject = NULL;
            status = STATUS_INSUFFICIENT_RESOURCES;
        }
    }

    pUnicode->Length = savedLength;                  // Restore WorkName

    //
    // If we enumerated a root device, add it to the device list
    //

    if (NT_SUCCESS(status)) {
        ASSERT(deviceObject != NULL);

        enumContext->DeviceList[enumContext->DeviceCount] = deviceObject;
        enumContext->DeviceCount++;

        return TRUE;
    } else {
        enumContext->Status = status;
        return FALSE;
    }
}

NTSTATUS
IopGetServiceType(
    IN PUNICODE_STRING KeyName,
    IN PULONG ServiceType
    )

/*++

Routine Description:

    This routine returns the controlling service's service type of the specified
    Device instance.

Arguments:

    KeyName - supplies a unicode string to specify the device instance.

    ServiceType - supplies a pointer to a variable to receive the service type.

Return Value:

    NTSTATUS code.

--*/

{
    NTSTATUS status;
    HANDLE handle;
    PKEY_VALUE_FULL_INFORMATION keyValueInformation;


    PAGED_CODE();

    *ServiceType = ~0ul;
    status = PipOpenServiceEnumKeys (
                             KeyName,
                             KEY_READ,
                             &handle,
                             NULL,
                             FALSE
                             );
    if (NT_SUCCESS(status)) {
        status = IopGetRegistryValue(handle, L"Type", &keyValueInformation);
        if (NT_SUCCESS(status)) {
            if (keyValueInformation->Type == REG_DWORD) {
                if (keyValueInformation->DataLength >= sizeof(ULONG)) {
                    *ServiceType = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
                }
            }
            ExFreePool(keyValueInformation);
        }
        ZwClose(handle);
    }
    return status;
}

BOOLEAN
PipIsFirmwareMapperDevicePresent (
    IN HANDLE KeyHandle
    )

/*++

Routine Description:

    This routine checks if the registry key is created by FirmwareMapper.
    If Yes, it further checks if the device for the key is present in this
    boot.

Parameters:

    KeyHandle - Specifies a handle to the registry key to be checked.

Return Value:

    A BOOLEAN vaStatus code that indicates whether or not the function was successful.

--*/
{
    NTSTATUS status;
    HANDLE handle;
    UNICODE_STRING unicodeName;
    PKEY_VALUE_FULL_INFORMATION keyValueInformation;
    ULONG tmp = 0;

    PAGED_CODE();

    //
    // First check to see if this device instance key is a firmware-created one
    //

    status = IopGetRegistryValue (KeyHandle,
                                  REGSTR_VAL_FIRMWAREIDENTIFIED,
                                  &keyValueInformation);
    if (NT_SUCCESS(status)) {
        if ((keyValueInformation->Type == REG_DWORD) &&
            (keyValueInformation->DataLength == sizeof(ULONG))) {

            tmp = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
        }
        ExFreePool(keyValueInformation);
    }
    if (tmp == 0) {
        return TRUE;
    }

    //
    // Make sure the device is present.
    //

    PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_CONTROL);
    status = IopOpenRegistryKeyEx( &handle,
                                   KeyHandle,
                                   &unicodeName,
                                   KEY_READ
                                   );
    if (!NT_SUCCESS(status)) {
        return FALSE;
    }

    status = IopGetRegistryValue (handle,
                                  REGSTR_VAL_FIRMWAREMEMBER,
                                  &keyValueInformation);
    ZwClose(handle);
    tmp = 0;

    if (NT_SUCCESS(status)) {
        if ((keyValueInformation->Type == REG_DWORD) &&
            (keyValueInformation->DataLength == sizeof(ULONG))) {

            tmp = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
        }
        ExFreePool(keyValueInformation);
    }
    if (!tmp) {
        return FALSE;
    } else {
        return TRUE;
    }
}


NTSTATUS
IopSystemControlDispatch(
    IN      PDEVICE_OBJECT  DeviceObject,
    IN OUT  PIRP            Irp
    )
{
    NTSTATUS status;

    PAGED_CODE();

    status = Irp->IoStatus.Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return status;
}