Plug and Play (PnP) in Windows Drivers
The Plug and Play (PnP) manager is a core component of the Windows operating system responsible for detecting and configuring hardware devices dynamically. For driver developers, understanding and correctly implementing PnP behavior is crucial for creating robust and user-friendly device drivers.
Core Concepts of PnP
The PnP manager orchestrates the process of enumerating devices, assigning resources, and loading appropriate drivers. This involves several key components:
- PnP Manager: The central component that manages the PnP process.
- Device Description: Information about hardware, typically provided by firmware or configuration data.
- Resources: System resources like I/O ports, memory addresses, and interrupts allocated to devices.
- Drivers: Software components that interact with hardware and PnP manager.
The PnP IRP Flow
Drivers communicate with the PnP manager primarily through I/O Request Packets (IRPs), specifically PnP IRPs. Key PnP IRPs include:
IRP_MJ_PNP: The main dispatch routine for all PnP operations.IRP_MN_START_DEVICE: Instructs the driver to prepare the device for use.IRP_MN_STOP_DEVICE: Instructs the driver to prepare the device for removal.IRP_MN_REMOVE_DEVICE: Instructs the driver to clean up resources and detach from the device.IRP_MN_QUERY_DEVICE_RELATIONS: Used to query relationships between devices (e.g., parent-child).
Example: Handling IRP_MN_START_DEVICE
When a device is ready to be started, the PnP manager sends an IRP_MN_START_DEVICE request to its driver. The driver's PnP dispatch routine must handle this IRP correctly:
NTSTATUS DriverPnpDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
// ...
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_SUCCESS;
switch (irpSp->MinorFunction) {
case IRP_MN_START_DEVICE:
status = HandleStartDevice(DeviceObject, Irp);
break;
// ... other minor functions
default:
status = Irp->IoStatus.Status;
break;
}
// ...
return status;
}
NTSTATUS HandleStartDevice(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
// Allocate resources, initialize hardware, etc.
// If successful:
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
Device Object and Driver Object
Each device managed by the PnP system has a corresponding Device Object (DEVICE_OBJECT), representing the instance of the device. Drivers are associated with devices through Driver Objects (DRIVER_OBJECT). Understanding the lifecycle and management of these objects is fundamental.
Best Practices
- Always pass PnP IRPs down to the next driver in the stack unless you explicitly need to handle them.
- Ensure proper resource management, freeing allocated resources when devices are removed or stopped.
- Handle all required PnP IRPs to ensure correct device behavior.
- Use the Windows Driver Kit (WDK) tools for debugging and testing PnP interactions.