You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1735 lines
52 KiB
1735 lines
52 KiB
/*++
|
|
|
|
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
|
|
);
|
|
|
|
NTSTATUS
|
|
IopGetRootDevices (
|
|
PDEVICE_RELATIONS *DeviceRelations
|
|
);
|
|
|
|
#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;
|
|
}
|
|
|
|
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;
|
|
|
|
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;
|
|
*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;
|
|
}
|
|
} else if (context.DeviceCount == 0) {
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
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;
|
|
NTSTATUS status;
|
|
|
|
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.
|
|
//
|
|
|
|
status = PipApplyFunctionToSubKeys(
|
|
KeyHandle,
|
|
NULL,
|
|
KEY_ALL_ACCESS,
|
|
FUNCTIONSUBKEY_FLAG_IGNORE_NON_CRITICAL_ERRORS,
|
|
IopInitializeDeviceInstanceKey,
|
|
Context
|
|
);
|
|
unicodeName->Length = length;
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
((PROOT_ENUMERATOR_CONTEXT)Context)->Status = status;
|
|
}
|
|
|
|
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;
|
|
PDEVICE_OBJECT deviceObject;
|
|
PDEVICE_NODE deviceNode = NULL;
|
|
PROOT_ENUMERATOR_CONTEXT enumContext = (PROOT_ENUMERATOR_CONTEXT)Context;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
status = PipConcatenateUnicodeStrings( &deviceNode->InstancePath,
|
|
pUnicode,
|
|
NULL);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
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) {
|
|
PpCriticalProcessCriticalDevice(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;
|
|
}
|
|
} 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();
|
|
|
|
UNREFERENCED_PARAMETER (DeviceObject);
|
|
|
|
status = Irp->IoStatus.Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
|