NTSTATUS Bus_EvtDeviceListCreatePdo( WDFCHILDLIST DeviceList, PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, PWDFDEVICE_INIT ChildInit ) /*++ Routine Description: Called by the framework in response to Query-Device relation when a new PDO for a child device needs to be created. Arguments: DeviceList - Handle to the default WDFCHILDLIST created by the framework as part of FDO. IdentificationDescription - Decription of the new child device. ChildInit - It's a opaque structure used in collecting device settings and passed in as a parameter to CreateDevice. Return Value: NT Status code. --*/ { PPDO_IDENTIFICATION_DESCRIPTION pDesc; PAGED_CODE(); pDesc = CONTAINING_RECORD(IdentificationDescription, PDO_IDENTIFICATION_DESCRIPTION, Header); return Bus_CreatePdo(WdfChildListGetDevice(DeviceList), ChildInit, pDesc->HardwareIds, pDesc->SerialNo); }
NTSTATUS Bus_PlugInDevice( _In_ WDFDEVICE Device, _In_ PWCHAR HardwareIds, _In_ ULONG SerialNo ) /*++ Routine Description: The user application has told us that a new device on the bus has arrived. We therefore need to create a new PDO, initialize it, add it to the list of PDOs for this FDO bus, and then tell Plug and Play that all of this happened so that it will start sending prodding IRPs. --*/ { NTSTATUS status = STATUS_SUCCESS; BOOLEAN unique = TRUE; WDFDEVICE hChild; PPDO_DEVICE_DATA pdoData; PFDO_DEVICE_DATA deviceData; PAGED_CODE (); // // First make sure that we don't already have another device with the // same serial number. // Framework creates a collection of all the child devices we have // created so far. So acquire the handle to the collection and lock // it before walking the item. // deviceData = FdoGetData(Device); hChild = NULL; // // We need an additional lock to synchronize addition because // WdfFdoLockStaticChildListForIteration locks against anyone immediately // updating the static child list (the changes are put on a queue until the // list has been unlocked). This type of lock does not enforce our concept // of unique IDs on the bus (ie SerialNo). // // Without our additional lock, 2 threads could execute this function, both // find that the requested SerialNo is not in the list and attempt to add // it. If that were to occur, 2 PDOs would have the same unique SerialNo, // which is incorrect. // // We must use a passive level lock because you can only call WdfDeviceCreate // at PASSIVE_LEVEL. // WdfWaitLockAcquire(deviceData->ChildLock, NULL); WdfFdoLockStaticChildListForIteration(Device); while ((hChild = WdfFdoRetrieveNextStaticChild(Device, hChild, WdfRetrieveAddedChildren)) != NULL) { // // WdfFdoRetrieveNextStaticChild returns reported and to be reported // children (ie children who have been added but not yet reported to PNP). // // A surprise removed child will not be returned in this list. // pdoData = PdoGetData(hChild); // // It's okay to plug in another device with the same serial number // as long as the previous one is in a surprise-removed state. The // previous one would be in that state after the device has been // physically removed, if somebody has an handle open to it. // if (SerialNo == pdoData->SerialNo) { unique = FALSE; status = STATUS_INVALID_PARAMETER; break; } } if (unique) { // // Create a new child device. It is OK to create and add a child while // the list locked for enumeration. The enumeration lock applies only // to enumeration, not addition or removal. // status = Bus_CreatePdo(Device, HardwareIds, SerialNo); } WdfFdoUnlockStaticChildListFromIteration(Device); WdfWaitLockRelease(deviceData->ChildLock); return status; }