Windows2000/private/ntos/io/pnpdd.c

2062 lines
58 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
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.
*/
#include "iop.h"
#pragma hdrstop
#ifdef POOL_TAGGING
#undef ExAllocatePool
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'ddpP')
#endif
// Internal definitions and references
typedef struct _DEVICE_LIST_CONTEXT {
ULONG DeviceCount;
BOOLEAN Reallocation;
PDEVICE_OBJECT DeviceList[1];
} DEVICE_LIST_CONTEXT, *PDEVICE_LIST_CONTEXT;
BOOLEAN
IopAddDevicesToBootDriverWorker(
IN HANDLE DeviceInstanceHandle,
IN PUNICODE_STRING DeviceInstancePath,
IN OUT PVOID Context
);
NTSTATUS
IopProcessAddDevicesWorker (
IN PDEVICE_NODE DeviceNode,
IN PVOID Context
);
NTSTATUS
IopProcessAssignResourcesWorker (
IN PDEVICE_NODE DeviceNode,
IN PVOID Context
);
VOID
IopPnPCompleteRequest(
IN OUT PIRP Irp,
IN NTSTATUS Status,
IN ULONG_PTR Information
);
NTSTATUS
IopGetDriverDeviceList (
IN PDRIVER_OBJECT DriverObject,
OUT PDEVICE_LIST_CONTEXT *DeviceList
);
BOOLEAN
IopGetDriverDeviceListWorker(
IN HANDLE DeviceInstanceHandle,
IN PUNICODE_STRING DeviceInstancePath,
IN OUT PVOID Context
);
NTSTATUS
IopAssignResourcesToDevices (
IN ULONG DeviceCount,
IN PIOP_RESOURCE_REQUEST RequestTable,
IN BOOLEAN BootConfigsOK
);
BOOLEAN
IopIsFirmwareDisabled (
IN PDEVICE_NODE DeviceNode
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, IopAddDevicesToBootDriver)
#pragma alloc_text(INIT, IopAddDevicesToBootDriverWorker)
//#pragma alloc_text(INIT, IopReportResourcesForAllChildren)
#pragma alloc_text(PAGE, IopReleaseDeviceResources)
#pragma alloc_text(PAGE, IopPnPAddDevice)
#pragma alloc_text(PAGE, IopPnPDispatch)
#pragma alloc_text(INIT, IopProcessAddDevices)
#pragma alloc_text(INIT, IopProcessAddDevicesWorker)
#pragma alloc_text(PAGE, IopProcessAssignResources)
#pragma alloc_text(PAGE, IopProcessAssignResourcesWorker)
#pragma alloc_text(PAGE, IopGetDriverDeviceList)
#pragma alloc_text(PAGE, IopGetDriverDeviceListWorker)
#pragma alloc_text(PAGE, IopNewDevice)
#pragma alloc_text(PAGE, IopStartDriverDevices)
#pragma alloc_text(PAGE, IopAssignResourcesToDevices)
#pragma alloc_text(PAGE, IopWriteAllocatedResourcesToRegistry)
#pragma alloc_text(PAGE, IopIsFirmwareDisabled)
#endif
NTSTATUS
IopAddDevicesToBootDriver (
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
This functions is used by Pnp manager to inform a boot device driver of
all the devices it can possibly control. This routine is for boot
drivers only.
Parameters:
DriverObject - Supplies a driver object to receive its boot devices.
Return Value:
NTSTATUS code.
*/
{
NTSTATUS status;
// For each device instance in the driver's service/enum key, we will
// invoke the driver's AddDevice routine and perform enumeration on
// the device.
// Note, we don't acquire registry lock before calling IopApplyFunction
// routine. We know this code is for boot driver initialization. No
// one else would access the registry Enum key at this time and most
// important we need the registry lock in other down level routines.
status = IopApplyFunctionToServiceInstances(
NULL,
&DriverObject->DriverExtension->ServiceKeyName,
KEY_ALL_ACCESS,
TRUE,
IopAddDevicesToBootDriverWorker,
DriverObject,
NULL
);
return status;
}
BOOLEAN
IopAddDevicesToBootDriverWorker(
IN HANDLE DeviceInstanceHandle,
IN PUNICODE_STRING DeviceInstancePath,
IN OUT PVOID Context
)
/*++
Routine Description:
This routine is a callback function for IopApplyFunctionToServiceInstances.
It is called for each device instance key referenced by a service instance
value under the specified service's volatile Enum subkey. The purpose of this
routine is to invoke the AddDevice() entry of a boot driver with the device
object.
Note this routine is also used for the devices controlled by a legacy driver.
If the specified device instance is controlled by a legacy driver this routine
sets the device node flags.
Arguments:
DeviceInstanceHandle - Supplies a handle to the registry path (relative to
HKLM\CCS\System\Enum) to this device instance.
DeviceInstancePath - Supplies the registry path (relative to HKLM\CCS\System\Enum)
to this device instance.
Context - Supplies a pointer to a DRIVER_OBJECT structure.
Return Value:
TRUE to continue the enumeration.
FALSE to abort it.
*/
{
NTSTATUS status;
// PDRIVER_OBJECT driverObject = (PDRIVER_OBJECT)Context;
PDEVICE_OBJECT physicalDevice;
PDEVICE_NODE deviceNode;
ULONG length;
BOOLEAN conflict;
PCM_RESOURCE_LIST cmResource;
ADD_CONTEXT addContext;
// Reference the physical device object associated with the device instance.
physicalDevice = IopDeviceObjectFromDeviceInstance(DeviceInstanceHandle,
DeviceInstancePath);
if (!physicalDevice) {
return TRUE;
}
deviceNode = (PDEVICE_NODE)physicalDevice->DeviceObjectExtension->DeviceNode;
ASSERT(deviceNode && (deviceNode->PhysicalDeviceObject == physicalDevice));
// If the device has been added (or failed) skip it.
if (!OK_TO_ADD_DEVICE(deviceNode)) {
goto exit;
}
// If we know the device is a duplicate of another device which
// has been enumerated at this point. we will skip this device.
if ((deviceNode->Flags & DNF_DUPLICATE) && (deviceNode->DuplicatePDO)) {
goto exit;
}
// Invoke driver's AddDevice Entry for the device.
// Since the driver has already been loaded, we generate a fake
// context to make sure that group order won't get in the way of
// adding the drivers.
addContext.GroupsToStart = 0xffff;
addContext.GroupToStartNext = 0;
addContext.DriverStartType = SERVICE_BOOT_START;
IopCallDriverAddDevice(deviceNode, FALSE, &addContext);
exit:
ObDereferenceObject(physicalDevice);
return TRUE;
}
NTSTATUS
IopReleaseDeviceResources (
IN PDEVICE_NODE DeviceNode,
IN BOOLEAN ReserveResources
)
/*++
Routine Description:
This routine releases the resources assigned to a device.
Arguments:
DeviceObject - supplies a pointer to a device whose resources are to be released.
ReserveResources - indicates whether we need to re-query and reserve BOOT config for DeviceObject.
Return Value:
NTSTATUS code.
*/
{
BOOLEAN conflict;
NTSTATUS status= STATUS_SUCCESS;
PCM_RESOURCE_LIST cmResource;
ULONG cmLength;
PAGED_CODE();
if (DeviceNode->ResourceList || (DeviceNode->Flags & DNF_BOOT_CONFIG_RESERVED)) {
cmResource = NULL;
cmLength = 0;
// If needed, re-query for BOOT configs. We need to do this BEFORE we
// release the BOOT config (otherwise ROOT devices cannot report BOOT
// config).
if (ReserveResources && !(DeviceNode->Flags & DNF_MADEUP)) {
// First query for new BOOT config (order important for ROOT devices).
status = IopQueryDeviceResources ( DeviceNode->PhysicalDeviceObject,
QUERY_RESOURCE_LIST,
&cmResource,
&cmLength);
if (!NT_SUCCESS(status)) {
cmResource = NULL;
cmLength = 0;
}
}
// Release resources for this device.
status = IopLegacyResourceAllocation( ArbiterRequestUndefined,
IoPnpDriverObject,
DeviceNode->PhysicalDeviceObject,
NULL,
NULL);
if (NT_SUCCESS(status)) {
IopResourcesReleased = TRUE; // Signal there are resources available.
// If needed, re-query and reserve current BOOT config for this device.
// We always rereserve the boot config (ie DNF_MADEUP root enumerated
// and IoReportDetected) devices in IopLegacyResourceAllocation.
if (ReserveResources && !(DeviceNode->Flags & DNF_MADEUP)) {
UNICODE_STRING unicodeName;
HANDLE logConfHandle;
HANDLE handle;
ASSERT(DeviceNode->BootResources == NULL);
status = IopDeviceObjectToDeviceInstance(DeviceNode->PhysicalDeviceObject, &handle, KEY_ALL_ACCESS);
logConfHandle = NULL;
if (NT_SUCCESS(status)) {
PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
status = IopCreateRegistryKeyEx( &logConfHandle,
handle,
&unicodeName,
KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE,
NULL);
if (!NT_SUCCESS(status)) {
logConfHandle = NULL;
}
}
if (logConfHandle) {
PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_BOOTCONFIG);
KeEnterCriticalRegion();
ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE);
if (cmResource) {
ZwSetValueKey( logConfHandle,
&unicodeName,
TITLE_INDEX_VALUE,
REG_RESOURCE_LIST,
cmResource,
cmLength);
} else {
ZwDeleteValueKey(logConfHandle, &unicodeName);
}
ExReleaseResource(&PpRegistryDeviceResource);
KeLeaveCriticalRegion();
ZwClose(logConfHandle);
}
// Reserve any remaining BOOT config.
if (cmResource) {
DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
DeviceNode->BootResources = cmResource;
// This device consumes BOOT resources. Reserve its boot resources
(*IopReserveResourcesRoutine)( ArbiterRequestPnpEnumerated,
DeviceNode->PhysicalDeviceObject,
cmResource);
}
}
}
}
return status;
}
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.
*/
{
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;
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
)
{
*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;
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;
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 stays.
// So, they will be marked as deleted but still show up in the tree.
//IoDeleteDevice(DeviceObject);
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:
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;
}
status = Irp->IoStatus.Status;
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;
}
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;
#if 0
case IRP_MN_QUERY_BUS_INFORMATION:
deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode;
if (deviceNode == IopRootDeviceNode) {
PPNP_BUS_INFORMATION busInfo;
busInfo = (PPNP_BUS_INFORMATION) ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION));
if (busInfo) {
busInfo->LegacyBusType = PnpDefaultInterfaceType;
busInfo->BusNumber = 0;
if (PnpDefaultInterfaceType == Isa) {
busInfo->BusTypeGuid = GUID_BUS_TYPE_ISAPNP; // BUGBUG
} else if (PnpDefaultInterfaceType == Eisa) {
busInfo->BusTypeGuid = GUID_BUS_TYPE_EISA;
} else { // Microchannel
busInfo->BusTypeGuid = GUID_BUS_TYPE_MCA;
}
information = busInfo;
status = STATUS_SUCCESS;
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
information = NULL;
}
break;
}
#endif
// Otherwise, let it fall through the default path.
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.
*/
{
KIRQL oldIrql;
// Complete the IRP. First update the status...
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = Information;
// ... and complete it.
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
USHORT
IopProcessAddDevices (
IN PDEVICE_NODE DeviceNode,
IN USHORT StartOrder,
IN ULONG DriverStartType
)
/*++
Routine Description:
This functions is used by Pnp manager to load driver and perform AddDevice for
all the devices under DeviceNode subtree. This routine is used at boot time
to process devices which were not processed during boot driver initialization.
Note, caller must acquire the enumeration mutex of the DeviceNode before calling
this routine.
Parameters:
DeviceNode - Specifies the device node whose subtree is to be checked for StartDevice.
StartOrder - The group orders to start.
Return Value:
TRUE - if any new device is successfully added to its driver.
*/
{
PDEVICE_NODE deviceNode, nextDeviceNode;
USHORT returnValue = NO_MORE_GROUP;
ADD_CONTEXT context;
context.GroupsToStart = StartOrder;
context.GroupToStartNext = NO_MORE_GROUP;
context.DriverStartType = DriverStartType;
// Traverse the device node subtree to perform AddDevice call.
if (DeviceNode != IopRootDeviceNode) {
IopAcquireEnumerationLock(DeviceNode);
}
deviceNode = DeviceNode->Child;
while (deviceNode) {
// We need to remember the 'next' device node. If the deviceNode is a madeup device
// it may be deleted while processing the IopProcessAddDeviceWorker.
nextDeviceNode = deviceNode->Sibling;
IopProcessAddDevicesWorker(deviceNode, &context);
deviceNode = nextDeviceNode;
}
if (DeviceNode != IopRootDeviceNode) {
IopReleaseEnumerationLock(DeviceNode);
}
return context.GroupToStartNext;
}
NTSTATUS
IopProcessAddDevicesWorker (
IN PDEVICE_NODE DeviceNode,
IN PVOID Context
)
/*++
Routine Description:
This function checks if the driver for the DeviceNode is present and loads
the driver if necessary.
Arguments:
DeviceNode - Supplies a pointer to the device node which is to be added.
Context - Supplies a pointer to a BOOLEAN value to indicate if the specified device
is successfully added to its driver.
Return Value:
NTSTATUS code.
*/
{
PADD_CONTEXT addContext = (PADD_CONTEXT)Context;
if (DeviceNode->Flags & DNF_ADDED) {
// If the device has been added, move to its children.
// Acquire enumeration mutex to make sure its children won't change by
// someone else. Note, the current device node is protected by its parent's
// Enumeration mutex and it won't disappear either.
IopAcquireEnumerationLock(DeviceNode);
// Recursively mark all of our children deleted.
IopForAllChildDeviceNodes(DeviceNode, IopProcessAddDevicesWorker, Context);
// Release the enumeration mutex of the device node.
IopReleaseEnumerationLock(DeviceNode);
} else if (OK_TO_ADD_DEVICE(DeviceNode)) {
// If this device is not added (not because of failure), load its controlling
// driver and invoke the driver's AddDevice entry.
IopCallDriverAddDevice(DeviceNode, TRUE, addContext);
}
return STATUS_SUCCESS;
}
BOOLEAN
IopProcessAssignResources (
IN PDEVICE_NODE DeviceNode,
IN BOOLEAN Reallocation,
IN BOOLEAN BootConfigsOK
)
/*++
Routine Description:
This functions is used by Pnp manager to allocate resources for the devices
which have been successfully added to their drivers and waiting to be started.
Note, the caller must acquire the enumeration mutex before calling this routine.
Parameters:
DeviceNode - specifies the device node whose subtree is to be checked for AssignRes.
Reallocation - specifies if we are assigning resources for DNF_INSUFFICIENT_RESOURCES
devices.
BootConfigsOK - Indicates that it is OK to assign BOOT configs.
Return Value:
TRUE - if more devices need resources. This means we did not assign resources for all
the devices. caller must call this routine again.
*/
{
PDEVICE_NODE deviceNode;
PDEVICE_LIST_CONTEXT context;
BOOLEAN again = FALSE;
ULONG count, i;
PIOP_RESOURCE_REQUEST requestTable;
PAGED_CODE();
// Allocate and init memory for resource context
context = (PDEVICE_LIST_CONTEXT) ExAllocatePool(PagedPool, sizeof(DEVICE_LIST_CONTEXT) + sizeof(PDEVICE_OBJECT) * IopNumberDeviceNodes);
if (!context) {
return again;
}
context->DeviceCount = 0;
context->Reallocation = Reallocation;
// Parse the device node subtree to determine which devices need resources
IopAcquireEnumerationLock(DeviceNode);
deviceNode = DeviceNode->Child;
while (deviceNode) {
IopProcessAssignResourcesWorker(deviceNode, context);
deviceNode = deviceNode->Sibling;
}
IopReleaseEnumerationLock(DeviceNode);
count = context->DeviceCount;
if (count == 0) {
ExFreePool(context);
return again;
}
// Need to assign resources to devices. Build the resource request table and call
// resource assignment routine.
requestTable = (PIOP_RESOURCE_REQUEST) ExAllocatePool(PagedPool, sizeof(IOP_RESOURCE_REQUEST) * count);
if (requestTable) {
for (i = 0; i < count; i++) {
requestTable[i].Priority = 0;
requestTable[i].PhysicalDevice = context->DeviceList[i];
}
// Assign resources
ExAcquireResourceShared(&IopDeviceTreeLock, TRUE);
IopAssignResourcesToDevices(count, requestTable, BootConfigsOK);
// Check the results
for (i = 0; i < count; i++) {
deviceNode = (PDEVICE_NODE)
requestTable[i].PhysicalDevice->DeviceObjectExtension->DeviceNode;
if (NT_SUCCESS(requestTable[i].Status)) {
if (requestTable[i].ResourceAssignment) {
if (!(deviceNode->Flags & DNF_RESOURCE_REPORTED)) {
deviceNode->Flags |= DNF_RESOURCE_ASSIGNED;
}
//deviceNode->Flags &= ~DNF_INSUFFICIENT_RESOURCES;
deviceNode->ResourceList = requestTable[i].ResourceAssignment;
deviceNode->ResourceListTranslated = requestTable[i].TranslatedResourceAssignment;
} else {
deviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
}
} else if (requestTable[i].Status == STATUS_RETRY) {
again = TRUE;
} else if (requestTable[i].Status == STATUS_DEVICE_CONFIGURATION_ERROR) {
IopSetDevNodeProblem(deviceNode, CM_PROB_NO_SOFTCONFIG);
} else if (requestTable[i].Status == STATUS_PNP_BAD_MPS_TABLE) {
IopSetDevNodeProblem(deviceNode, CM_PROB_BIOS_TABLE);
} else if (requestTable[i].Status == STATUS_PNP_TRANSLATION_FAILED) {
IopSetDevNodeProblem(deviceNode, CM_PROB_TRANSLATION_FAILED);
} else if (requestTable[i].Status == STATUS_PNP_IRQ_TRANSLATION_FAILED) {
IopSetDevNodeProblem(deviceNode, CM_PROB_IRQ_TRANSLATION_FAILED);
} else {
IopSetDevNodeProblem(deviceNode, CM_PROB_NORMAL_CONFLICT);
}
// IopProcessAssignReourcesWork marks the device nodes as DNF_ASSIGNING_RESOURCES
// We need to clear it to indicate the assigment is done.
deviceNode->Flags &= ~DNF_ASSIGNING_RESOURCES;
}
ExReleaseResource(&IopDeviceTreeLock);
ExFreePool(requestTable);
}
ExFreePool(context);
return again;
}
NTSTATUS
IopProcessAssignResourcesWorker (
IN PDEVICE_NODE DeviceNode,
IN PVOID Context
)
/*++
Routine Description:
This functions searches the DeviceNode subtree to locate all the device objects
which have been successfully added to their drivers and waiting for resources to
be started.
Parameters:
DeviceNode - specifies the device node whose subtree is to be checked for AssignRes.
Context - specifies a pointer to a structure to pass resource assignment information.
Return Value:
TRUE.
*/
{
PDEVICE_LIST_CONTEXT resourceContext = (PDEVICE_LIST_CONTEXT) Context;
PAGED_CODE();
// If the device node/object has not been add, skip it.
if (!(DeviceNode->Flags & DNF_ADDED)) {
return STATUS_SUCCESS;
}
if (resourceContext->Reallocation &&
( IopIsDevNodeProblem(DeviceNode, CM_PROB_NORMAL_CONFLICT) ||
IopIsDevNodeProblem(DeviceNode, CM_PROB_TRANSLATION_FAILED) ||
IopIsDevNodeProblem(DeviceNode, CM_PROB_IRQ_TRANSLATION_FAILED))) {
IopClearDevNodeProblem(DeviceNode);
}
// If the device object has not been started and has no resources yet.
// Append it to our list.
if ( !(DeviceNode->Flags & DNF_START_PHASE) &&
!(DeviceNode->Flags & DNF_ASSIGN_RESOURCE_PHASE)) {
resourceContext->DeviceList[resourceContext->DeviceCount] =
DeviceNode->PhysicalDeviceObject;
DeviceNode->Flags |= DNF_ASSIGNING_RESOURCES;
resourceContext->DeviceCount++;
} else {
// Acquire enumeration mutex to make sure its children won't change by
// someone else. Note, the current device node is protected by its parent's
// Enumeration mutex and it won't disappear either.
IopAcquireEnumerationLock(DeviceNode);
// Recursively mark all of our children deleted.
IopForAllChildDeviceNodes(DeviceNode, IopProcessAssignResourcesWorker, Context);
// Release the enumeration mutex of the device node.
IopReleaseEnumerationLock(DeviceNode);
}
return STATUS_SUCCESS;
}
NTSTATUS
IopGetDriverDeviceList (
IN PDRIVER_OBJECT DriverObject,
OUT PDEVICE_LIST_CONTEXT *DeviceList
)
/*++
Routine Description:
This functions is used by Pnp manager to inform a device driver of
all the devices it can possibly control. See IopStartDriverDevices().
Parameters:
DriverObject - Supplies a driver object to receive its boot devices.
DeviceList - Specifies a pointer to a variable to receive the list of device
objects controlled by the driver.
Return Value:
NTSTATUS code.
*/
{
NTSTATUS status;
HANDLE enumHandle;
ULONG count = 0;
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
PDEVICE_LIST_CONTEXT deviceList;
PAGED_CODE();
*DeviceList = NULL;
KeEnterCriticalRegion();
ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE);
// Open System\CurrentControlSet\Services
status = IopOpenServiceEnumKeys (
&DriverObject->DriverExtension->ServiceKeyName,
KEY_READ,
NULL,
&enumHandle,
FALSE
);
if (!NT_SUCCESS(status)) {
goto exit;
}
// Read value of Count if present. If it is not present, a value of
// zero will be returned.
status = IopGetRegistryValue(enumHandle, REGSTR_VALUE_COUNT, &keyValueInformation);
ZwClose(enumHandle);
if (NT_SUCCESS(status)) {
if (keyValueInformation->DataLength != 0) {
count = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
}
ExFreePool(keyValueInformation);
}
if (count == 0) {
goto exit;
}
deviceList = (PDEVICE_LIST_CONTEXT) ExAllocatePool(PagedPool, sizeof(DEVICE_LIST_CONTEXT) + sizeof(PDEVICE_OBJECT) * count * 2);
if (!deviceList) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
deviceList->DeviceCount = 0;
// For each device instance in the driver's service/enum key, we will
// invoke the our worker routine to collect its corresponding device object.
status = IopApplyFunctionToServiceInstances(
NULL,
&DriverObject->DriverExtension->ServiceKeyName,
KEY_ALL_ACCESS,
TRUE,
IopGetDriverDeviceListWorker,
deviceList,
NULL
);
*DeviceList = deviceList;
exit:
ExReleaseResource(&PpRegistryDeviceResource);
KeLeaveCriticalRegion();
return status;
}
BOOLEAN
IopGetDriverDeviceListWorker(
IN HANDLE DeviceInstanceHandle,
IN PUNICODE_STRING DeviceInstancePath,
IN OUT PVOID Context
)
/*++
Routine Description:
This routine is a callback function for IopApplyFunctionToServiceInstances.
It is called for each device instance key referenced by a service instance
value under the specified service's volatile Enum subkey. The purpose of this
routine is to generate a device list controlled by the same driver.
Arguments:
DeviceInstanceHandle - Supplies a handle to the registry path (relative to
HKLM\CCS\System\Enum) to this device instance.
DeviceInstancePath - Supplies the registry path (relative to HKLM\CCS\System\Enum)
to this device instance.
Context - Supplies a pointer to a PDEVICE_LIST_CONTEXT structure.
Return Value:
TRUE to continue the enumeration.
FALSE to abort it.
*/
{
PDEVICE_LIST_CONTEXT deviceList = (PDEVICE_LIST_CONTEXT)Context;
PDEVICE_OBJECT physicalDevice;
PDEVICE_NODE deviceNode;
PAGED_CODE();
// Reference the physical device object associated with the device instance.
physicalDevice = IopDeviceObjectFromDeviceInstance(DeviceInstanceHandle,
DeviceInstancePath);
if (!physicalDevice) {
return TRUE;
}
deviceNode = (PDEVICE_NODE)physicalDevice->DeviceObjectExtension->DeviceNode;
// Make sure the device instance is not disabled.
if (IopDoesDevNodeHaveProblem(deviceNode)) {
goto exit;
} else if (!IopIsDeviceInstanceEnabled(DeviceInstanceHandle, DeviceInstancePath, TRUE)) {
goto exit;
}
// If we know the device is a duplicate of another enumerated device and it
// has been enumerated at this point. we will skip this device.
if ((deviceNode->Flags & DNF_DUPLICATE) && (deviceNode->DuplicatePDO)) {
goto exit;
}
deviceList->DeviceList[deviceList->DeviceCount] = physicalDevice;
deviceList->DeviceCount++;
return TRUE;
exit:
ObDereferenceObject(physicalDevice);
return TRUE;
}
VOID
IopNewDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This routine handles user-mode initiated starts of devices.
Parameters:
DeviceObject - PDO.
ReturnValue:
None.
*/
{
PDEVICE_NODE deviceNode, parent;
IOP_RESOURCE_REQUEST requestTable;
NTSTATUS status;
BOOLEAN newDevice;
START_CONTEXT startContext;
ADD_CONTEXT addContext;
PAGED_CODE();
deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode;
// Make sure the device is not started
if (deviceNode->Flags & DNF_ADDED) {
goto exit;
}
// Need enumeration on IoReportDetectedDevice
if (!(deviceNode->Flags & DNF_NEED_QUERY_IDS)) {
// Invoke the driver's AddDevice() entry and enumerate the device.
addContext.GroupsToStart = 0xffff;
addContext.GroupToStartNext = 0xffff;
addContext.DriverStartType = SERVICE_DEMAND_START;
status = IopCallDriverAddDevice(deviceNode, TRUE, &addContext);
if (!NT_SUCCESS(status) || (deviceNode->Flags & DNF_LEGACY_DRIVER)) {
goto exit;
} else if (deviceNode->Flags & DNF_NEED_QUERY_IDS) {
// The driver may perform IoReportDetectedDevice
goto enumerate;
}
// Assign resource to the device
requestTable.PhysicalDevice = DeviceObject;
requestTable.Priority = 0;
IopAssignResourcesToDevices(1, &requestTable, TRUE);
if (NT_SUCCESS(requestTable.Status)) {
if (requestTable.ResourceAssignment) {
if (!(deviceNode->Flags & DNF_RESOURCE_REPORTED)) {
deviceNode->Flags |= DNF_RESOURCE_ASSIGNED;
}
// deviceNode->Flags &= ~DNF_INSUFFICIENT_RESOURCES;
deviceNode->ResourceList = requestTable.ResourceAssignment;
deviceNode->ResourceListTranslated = requestTable.TranslatedResourceAssignment;
} else {
deviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
}
} else if (requestTable.Status == STATUS_DEVICE_CONFIGURATION_ERROR) {
IopSetDevNodeProblem(deviceNode, CM_PROB_NO_SOFTCONFIG);
goto exit;
} else if (requestTable.Status == STATUS_PNP_BAD_MPS_TABLE) {
IopSetDevNodeProblem(deviceNode, CM_PROB_BIOS_TABLE);
goto exit;
} else if (requestTable.Status == STATUS_PNP_TRANSLATION_FAILED) {
IopSetDevNodeProblem(deviceNode, CM_PROB_TRANSLATION_FAILED);
goto exit;
} else if (requestTable.Status == STATUS_PNP_IRQ_TRANSLATION_FAILED) {
IopSetDevNodeProblem(deviceNode, CM_PROB_IRQ_TRANSLATION_FAILED);
goto exit;
} else {
IopSetDevNodeProblem(deviceNode, CM_PROB_NORMAL_CONFLICT);
goto exit;
}
}
enumerate:
// Start and enumerate the device
startContext.LoadDriver = TRUE;
startContext.NewDevice = FALSE;
startContext.AddContext.GroupsToStart = NO_MORE_GROUP;
startContext.AddContext.GroupToStartNext = NO_MORE_GROUP;
startContext.AddContext.DriverStartType = SERVICE_DEMAND_START;
IopStartAndEnumerateDevice(deviceNode, &startContext);
newDevice = startContext.NewDevice;
while (newDevice) {
startContext.NewDevice = FALSE;
// Process the whole device tree to assign resources to those devices who
// have been successfully added to their drivers.
newDevice = IopProcessAssignResources(deviceNode, FALSE, TRUE);
// Process the whole device tree to start those devices who have been allocated
// resources and waiting to be started.
// Note, the IopProcessStartDevices routine may enumerate new devices.
IopProcessStartDevices(deviceNode, &startContext);
newDevice |= startContext.NewDevice;
}
exit:
;
}
NTSTATUS
IopStartDriverDevices(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
This routine is used by IopLoadDriver to add/start the devices controlled by
the newly loaded driver.
Arguments:
DriverObject - specifies the driver object which is being started thru
IopLoadDriver after the boot drivers and system drivers init
phase.
Return Value:
NTSTATUS code.
*/
{
ULONG count, i;
PDEVICE_LIST_CONTEXT deviceList;
PDEVICE_NODE deviceNode;
NTSTATUS status = STATUS_SUCCESS;
PDRIVER_ADD_DEVICE addDeviceRoutine;
PAGED_CODE();
if (!PnPInitialized) {
// If this function is called at PnP Init time, we don't start the devices
// for the specified driver. The device add/start is handled by pnp based
// on the device enumeration.
return status;
}
addDeviceRoutine = DriverObject->DriverExtension->AddDevice;
if (addDeviceRoutine == NULL) {
ASSERT(addDeviceRoutine);
return status;
}
IopGetDriverDeviceList(DriverObject, &deviceList);
count = deviceList ? deviceList->DeviceCount : 0;
if (count == 0) {
if (deviceList != NULL) {
ExFreePool(deviceList);
}
return STATUS_PLUGPLAY_NO_DEVICE;
}
// For each device int the list queue an IopNewDeviceEvent if the device is reported by driver
for (i = 0; i < count; i++) {
deviceNode = (PDEVICE_NODE)deviceList->DeviceList[i]->DeviceObjectExtension->DeviceNode;
if (!deviceNode || !(deviceNode->Flags & DNF_NEED_QUERY_IDS) ) {
ObDereferenceObject(deviceList->DeviceList[i]);
continue;
}
IopRequestDeviceAction(deviceList->DeviceList[i], StartDevice, NULL, NULL);
}
ExFreePool(deviceList);
return status;
}
// The following routines should be removed once the real
// Resource Assign code is done.
NTSTATUS
IopAssignResourcesToDevices (
IN ULONG DeviceCount,
IN OUT PIOP_RESOURCE_REQUEST RequestTable,
IN BOOLEAN BootConfigsOK
)
/*++
Routine Description:
This routine takes an input array of IOP_RESOURCE_REQUEST structures, and
allocates resource for the physical device object specified in
the structure. The allocated resources are automatically recorded
in the registry.
Arguments:
DeviceCount - Supplies the number of device objects whom we need to
allocate resource to. That is the number of entries
in the RequestTable.
RequestTable - Supplies an array of IOP_RESOURCE_REQUEST structures which
contains the Physical device object to allocate resource to.
Upon entry, the ResourceAssignment pointer is NULL and on
return the allocated resource is returned via the this pointer.
BootConfigsOK - Allow assignment of BOOT configs.
Return Value:
The status returned is the final completion status of the operation.
NOTE:
If NTSTATUS_SUCCESS is returned, the resource allocation for *all* the devices
specified is succeeded. Otherwise, one or more are failed and caller must
examine the ResourceAssignment pointer in each IOP_RESOURCE_REQUEST structure to
determine which devices failed and which succeeded.
*/
{
NTSTATUS status;
ULONG i;
PAGED_CODE();
ASSERT(DeviceCount != 0);
for (i = 0; i < DeviceCount; i++) {
// Initialize table entry.
RequestTable[i].ResourceAssignment = NULL;
RequestTable[i].Status = 0;
RequestTable[i].Flags = 0;
RequestTable[i].AllocationType = ArbiterRequestPnpEnumerated;
if (((PDEVICE_NODE)(RequestTable[i].PhysicalDevice->DeviceObjectExtension->DeviceNode))->Flags & DNF_MADEUP) {
ULONG reportedDevice = 0;
HANDLE hInstance;
status = IopDeviceObjectToDeviceInstance(RequestTable[i].PhysicalDevice, &hInstance, KEY_READ);
if (NT_SUCCESS(status)) {
ULONG resultSize = 0;
UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
UNICODE_STRING unicodeString;
PiWstrToUnicodeString(&unicodeString, REGSTR_VALUE_DEVICE_REPORTED);
status = ZwQueryValueKey( hInstance,
&unicodeString,
KeyValuePartialInformation,
(PVOID)buffer,
sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG),
&resultSize);
if (NT_SUCCESS(status)) {
reportedDevice = *(PULONG)(((PKEY_VALUE_PARTIAL_INFORMATION)buffer)->Data);
}
ZwClose(hInstance);
}
// Change the AllocationType for reported devices.
if (reportedDevice) {
RequestTable[i].AllocationType = ArbiterRequestLegacyReported;
}
}
RequestTable[i].ResourceRequirements = NULL;
}
// Allocate memory to build a IOP_ASSIGN table to call IopAllocateResources()
status = IopAllocateResources(&DeviceCount, &RequestTable, FALSE, BootConfigsOK);
return status;
}
NTSTATUS
IopWriteAllocatedResourcesToRegistry (
PDEVICE_NODE DeviceNode,
PCM_RESOURCE_LIST CmResourceList,
ULONG Length
)
/*++
Routine Description:
This routine writes allocated resources for a device to its control key of device
instance path key.
Arguments:
DeviceNode - Supplies a pointer to the device node structure of the device.
CmResourceList - Supplies a pointer to the device's allocated CM resource list.
Length - Supplies the length of the CmResourceList.
Return Value:
The status returned is the final completion status of the operation.
*/
{
NTSTATUS status;
PDEVICE_OBJECT deviceObject = DeviceNode->PhysicalDeviceObject;
HANDLE handle, handlex;
UNICODE_STRING unicodeName;
KeEnterCriticalRegion();
ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE);
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)) {
RtlInitUnicodeString(&unicodeName, REGSTR_VALUE_ALLOC_CONFIG);
if (CmResourceList) {
status = ZwSetValueKey(
handle,
&unicodeName,
TITLE_INDEX_VALUE,
REG_RESOURCE_LIST,
CmResourceList,
Length
);
} else {
status = ZwDeleteValueKey(handle, &unicodeName);
}
ZwClose(handle);
}
}
ExReleaseResource(&PpRegistryDeviceResource);
KeLeaveCriticalRegion();
return status;
}
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;
KeEnterCriticalRegion();
ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE);
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)) {
RtlInitUnicodeString(&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) {
FirmwareDisabled = TRUE;// firmware disabled
}
}
}
ExReleaseResource(&PpRegistryDeviceResource);
KeLeaveCriticalRegion();
return FirmwareDisabled;
}