|
|
/*++
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; }
|