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.
508 lines
15 KiB
508 lines
15 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
pnpstart.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
|
|
|
|
typedef struct _DEVICE_LIST_CONTEXT {
|
|
ULONG DeviceCount;
|
|
BOOLEAN Reallocation;
|
|
PDEVICE_OBJECT DeviceList[1];
|
|
} DEVICE_LIST_CONTEXT, *PDEVICE_LIST_CONTEXT;
|
|
|
|
NTSTATUS
|
|
IopAssignResourcesToDevices (
|
|
IN ULONG DeviceCount,
|
|
IN PIOP_RESOURCE_REQUEST RequestTable,
|
|
IN BOOLEAN DoBootConfigs,
|
|
OUT PBOOLEAN RebalancePerformed
|
|
);
|
|
|
|
NTSTATUS
|
|
IopGetDriverDeviceList(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
OUT PDEVICE_LIST_CONTEXT *DeviceList
|
|
);
|
|
|
|
NTSTATUS
|
|
IopProcessAssignResourcesWorker(
|
|
IN PDEVICE_NODE DeviceNode,
|
|
IN PVOID Context
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, IopAssignResourcesToDevices)
|
|
#pragma alloc_text(PAGE, IopProcessAssignResources)
|
|
#pragma alloc_text(PAGE, IopProcessAssignResourcesWorker)
|
|
#pragma alloc_text(PAGE, IopWriteAllocatedResourcesToRegistry)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
|
|
|
|
//
|
|
// 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 DoBootConfigs,
|
|
OUT PBOOLEAN RebalancePerformed
|
|
)
|
|
/*++
|
|
|
|
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.
|
|
|
|
DoBootConfigs - 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.
|
|
//
|
|
if (PpCallerInitializesRequestTable == TRUE) {
|
|
|
|
RequestTable[i].Position = i;
|
|
}
|
|
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,
|
|
DoBootConfigs,
|
|
RebalancePerformed);
|
|
return status;
|
|
}
|
|
|
|
BOOLEAN
|
|
IopProcessAssignResources(
|
|
IN PDEVICE_NODE DeviceNode,
|
|
IN BOOLEAN Reallocation,
|
|
OUT BOOLEAN *RebalancePerformed
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function attempts to assign resources to device under the subtree on
|
|
which AddDevice has been performed. Prior to the completion of all Boot Bus
|
|
Extenders in the system, this routine attempts allocation first so that devices
|
|
with no requirements and no boot config get processed. If there are no such devices,
|
|
then it attempts to allocate resources for devices with boot config. If there are no
|
|
devices with boot config, then other devices (requirements but no boot config)
|
|
get processed. During later part of boot, it attempts allocation only once
|
|
(since we should have already reserved all the boot configs).
|
|
|
|
Parameters:
|
|
|
|
DeviceNode - specifies the root of the subtree under which resources will be
|
|
allocated.
|
|
|
|
Reallocation - if TRUE, we will attempt allocation for devices with resource conflict
|
|
problem in addition to other devices.
|
|
|
|
RebalancePerformed - recieves whether a rebalance was successfully comp[eted.
|
|
|
|
Return Value:
|
|
|
|
TRUE if resources got assigned to any device, otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_NODE deviceNode;
|
|
PDEVICE_LIST_CONTEXT context;
|
|
BOOLEAN resourcesAssigned, tryAgain;
|
|
ULONG count, i, attempt, maxAttempts;
|
|
PIOP_RESOURCE_REQUEST requestTable;
|
|
|
|
PAGED_CODE();
|
|
|
|
resourcesAssigned = FALSE;
|
|
tryAgain = TRUE;
|
|
maxAttempts = (IopBootConfigsReserved)? 1 : 2;
|
|
for (attempt = 0; !resourcesAssigned && tryAgain && attempt < maxAttempts; attempt++) {
|
|
|
|
tryAgain = FALSE;
|
|
|
|
//
|
|
// Allocate and init memory for resource context
|
|
//
|
|
context = (PDEVICE_LIST_CONTEXT) ExAllocatePool(
|
|
PagedPool,
|
|
sizeof(DEVICE_LIST_CONTEXT) +
|
|
sizeof(PDEVICE_OBJECT) * IopNumberDeviceNodes
|
|
);
|
|
if (!context) {
|
|
|
|
return FALSE;
|
|
}
|
|
context->DeviceCount = 0;
|
|
context->Reallocation = Reallocation;
|
|
|
|
//
|
|
// Parse the device node subtree to determine which devices need resources
|
|
//
|
|
IopProcessAssignResourcesWorker(DeviceNode, context);
|
|
count = context->DeviceCount;
|
|
if (count == 0) {
|
|
|
|
ExFreePool(context);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// 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
|
|
//
|
|
IopAssignResourcesToDevices(
|
|
count,
|
|
requestTable,
|
|
(attempt == 0) ? IopBootConfigsReserved : TRUE,
|
|
RebalancePerformed
|
|
);
|
|
|
|
//
|
|
// 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) {
|
|
|
|
deviceNode->ResourceList = requestTable[i].ResourceAssignment;
|
|
deviceNode->ResourceListTranslated = requestTable[i].TranslatedResourceAssignment;
|
|
} else {
|
|
|
|
deviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
|
|
}
|
|
PipSetDevNodeState(deviceNode, DeviceNodeResourcesAssigned, NULL);
|
|
deviceNode->UserFlags &= ~DNUF_NEED_RESTART;
|
|
resourcesAssigned = TRUE;
|
|
} else {
|
|
|
|
switch (requestTable[i].Status) {
|
|
|
|
case STATUS_RETRY:
|
|
|
|
tryAgain = TRUE;
|
|
break;
|
|
|
|
case STATUS_DEVICE_CONFIGURATION_ERROR:
|
|
|
|
PipSetDevNodeProblem(deviceNode, CM_PROB_NO_SOFTCONFIG);
|
|
break;
|
|
|
|
case STATUS_PNP_BAD_MPS_TABLE:
|
|
|
|
PipSetDevNodeProblem(deviceNode, CM_PROB_BIOS_TABLE);
|
|
break;
|
|
|
|
case STATUS_PNP_TRANSLATION_FAILED:
|
|
|
|
PipSetDevNodeProblem(deviceNode, CM_PROB_TRANSLATION_FAILED);
|
|
break;
|
|
|
|
case STATUS_PNP_IRQ_TRANSLATION_FAILED:
|
|
|
|
PipSetDevNodeProblem(deviceNode, CM_PROB_IRQ_TRANSLATION_FAILED);
|
|
break;
|
|
|
|
case STATUS_RESOURCE_TYPE_NOT_FOUND:
|
|
|
|
PipSetDevNodeProblem(deviceNode, CM_PROB_UNKNOWN_RESOURCE);
|
|
break;
|
|
|
|
default:
|
|
|
|
PipSetDevNodeProblem(deviceNode, CM_PROB_NORMAL_CONFLICT);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
ExFreePool(requestTable);
|
|
}
|
|
ExFreePool(context);
|
|
}
|
|
|
|
return resourcesAssigned;
|
|
}
|
|
|
|
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 (resourceContext->Reallocation &&
|
|
(PipIsDevNodeProblem(DeviceNode, CM_PROB_NORMAL_CONFLICT) ||
|
|
PipIsDevNodeProblem(DeviceNode, CM_PROB_TRANSLATION_FAILED) ||
|
|
PipIsDevNodeProblem(DeviceNode, CM_PROB_IRQ_TRANSLATION_FAILED))) {
|
|
|
|
PipClearDevNodeProblem(DeviceNode);
|
|
}
|
|
|
|
if (!PipDoesDevNodeHaveProblem(DeviceNode)) {
|
|
|
|
//
|
|
// If the device object has not been started and has no resources yet.
|
|
// Append it to our list.
|
|
//
|
|
|
|
if (DeviceNode->State == DeviceNodeDriversAdded) {
|
|
|
|
resourceContext->DeviceList[resourceContext->DeviceCount] =
|
|
DeviceNode->PhysicalDeviceObject;
|
|
|
|
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.
|
|
//
|
|
|
|
//
|
|
// Recursively mark all of our children deleted.
|
|
//
|
|
|
|
PipForAllChildDeviceNodes(DeviceNode, IopProcessAssignResourcesWorker, Context);
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
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;
|
|
|
|
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_VALUE_ALLOC_CONFIG);
|
|
if (CmResourceList) {
|
|
status = ZwSetValueKey(
|
|
handle,
|
|
&unicodeName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_RESOURCE_LIST,
|
|
CmResourceList,
|
|
Length
|
|
);
|
|
} else {
|
|
status = ZwDeleteValueKey(handle, &unicodeName);
|
|
}
|
|
ZwClose(handle);
|
|
}
|
|
}
|
|
PiUnlockPnpRegistry();
|
|
return status;
|
|
}
|