PNP Resource Management

Proper management of hardware resources is a cornerstone of the Windows Plug and Play (PnP) subsystem. PnP ensures that devices are detected, configured, and assigned resources (such as I/O port addresses, interrupt request lines (IRQs), and direct memory access (DMA) channels) without conflicts.

Key Concepts

Resource Types

The PnP manager handles several types of hardware resources:

Resource Allocation Process

When a device is detected, the PnP manager initiates a resource allocation process:

  1. The PnP enumerator for the bus (e.g., PCI, USB) identifies a new device.
  2. The PnP manager queries the device's driver for its resource requirements (often defined in the hardware's BIOS or configuration space). This information is typically returned in a Resource Requirements List (RRL).
  3. The PnP manager consults its database of currently allocated resources and requests from other devices.
  4. Resource arbitrators are invoked to determine a conflict-free assignment of resources from the RRL. This might involve negotiating with other drivers or modifying existing assignments.
  5. Once a valid set of resources is identified, the PnP manager assigns them to the device, storing the information in a Resource Settings List (RSL).
  6. The PnP manager then informs the device's driver of the assigned resources by sending a IRP_MN_START_DEVICE IRP. The driver uses this information to initialize and configure the device.

Driver's Role in Resource Management

Drivers play a crucial role in resource management:

Important: Drivers should never attempt to directly access or claim hardware resources without going through the PnP manager. This can lead to system instability and resource conflicts.

Example: Requesting Resources in a Driver

While the PnP manager handles the allocation, drivers provide the requirements. A common way to represent these requirements is using data structures like CM_PARTIAL_RESOURCE_DESCRIPTOR and building up a CM_RESOURCE_LIST.

C++ Snippet (Conceptual)
NTSTATUS AddDevice(
    _In_ PDRIVER_OBJECT DriverObject,
    _In_ PDEVICE_OBJECT PDO
)
{
    // ... (Create device object, etc.)

    PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION)PhysicalDeviceObject->DeviceExtension;

    // Report resource requirements (simplified)
    // This would involve querying registry or hardware for specific needs.
    // The PnP Manager's IoQueryDeviceResources would eventually be involved.
    devExt->IoResourceRequirementList.ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
    devExt->IoResourceRequirementList.AlternativeLists[0].Count = 1; // One alternative list
    devExt->IoResourceRequirementList.AlternativeLists[0].List[0].Type = CmResourceTypePort;
    devExt->IoResourceRequirementList.AlternativeLists[0].List[0].Start.LowPart = 0x300; // Example start port
    devExt->IoResourceRequirementList.AlternativeLists[0].List[0].Length = 8;     // Example length

    // ... more resource types like IRQ, DMA etc.

    // The PnP Manager will use this information during StartDevice.
    return STATUS_SUCCESS;
}

// During IRP_MN_START_DEVICE handler:
NTSTATUS StartDevice(
    _In_ PDEVICE_OBJECT DeviceObject,
    _In_ PIRP Irp
)
{
    PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
    PCM_RESOURCE_LIST allocatedResources = irpSp->Parameters.StartDevice.AllocatedResourcesTranslated;

    if (allocatedResources) {
        // Process the allocated resources
        for (ULONG i = 0; i < allocatedResources->List[0].PartialResourceList.Count; i++) {
            PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = &allocatedResources->List[0].PartialResourceList.PartialDescriptors[i];
            switch (resource->Type) {
                case CmResourceTypePort:
                    devExt->IoPortBase = resource->u.Port.Start.LowPart;
                    devExt->IoPortCount = resource->u.Port.Length;
                    break;
                case CmResourceTypeInterrupt:
                    // Configure interrupt
                    break;
                case CmResourceTypeDma:
                    // Configure DMA
                    break;
                case CmResourceTypeMemory:
                    // Map memory region
                    break;
                default:
                    break;
            }
        }
        // Initialize hardware with allocated resources
    }
    // ...
    return STATUS_SUCCESS;
}
                    

Dynamic Resource Rebalancing

Windows supports dynamic resource rebalancing, allowing the system to reassign resources to optimize their usage or accommodate newly added hardware. Drivers may receive IRP_MN_REBALANCE and IRP_MN_QUERY_REMOVE / IRP_MN_REMOVE_DEVICE IRPs to manage these changes.

Understanding the PnP IRPs related to resource management (IRP_MN_QUERY_RESOURCE_REQUIREMENTS, IRP_MN_FILTER_RESOURCE_REQUIREMENTS, IRP_MN_START_DEVICE, IRP_MN_REBALANCE) is crucial for developing robust PnP drivers.

Further Reading