How PnP Works in ReactOS
Where do baby PDOs come from?
Something, probably a bus driver, creates a PDO using data gathered when enumerating devices. This PDO will initially just implement functionality provided by the bus driver, such as power and enumeration service.
Each PDO created this way has a DeviceID and likely a BaseConfigVector with it. The DeviceID is used by the PnP manager to look up the associated service (more on this later) and the BaseConfigVector is an image of a CM_RESOURCE_LIST. The CM_RESOURCE_LIST contains the actual physical location of the enumerated hardware from the CPU's perspective.
The PDO itself is created as in PnpRootCreateDevice (ntoskrnl/io/pnproot.c). This is a normal device object, with the extras tacked on in the DeviceExtension. Each bus does this.
Ok what happens next
Well we have the PDO which knows the power state of the device, but it isn't connected to anything useful yet.
To bring up the device, NtPlugPlayControl is called from umpnpmgr after the device is discovered (IoRegisterPlugPlayNotification knows how to register for notification), and it in turn eventually calls IopLoadServiceModule if the indicated driver (which is ferreted out by umpnpmgr and entered in the registry) is not running.
So umpnpmgr ...
- discovers that a new PDO exists by receiving a notification
- searches the .infs for a matching DeviceID and enters the indicated information into the registry
- then asks the kernel to initialize the device (possibly calling IopLoadServiceModule along the way)
- at this point, the kernel is starting the device and has the DRIVER_OBJECT associated with the service that will run it
- It sends the DRIVER_OBJECT (there is no DEVICE_OBJECT associated with the driver at this point) an IRP_MJ_PNP:IRP_MN_ADD_DEVICE irp with the indicated PDO as an argument
- The driver consumes the config data
- Does IoAttachDeviceToDeviceStack
- Does IoCreateDevice with a name, creating the device's actual personality and well known name
- Now, we have a new device!