kmdf dynamic vs static childlist question

I have a kmdf root-enumerated driver that manages a dynamic WDFCHILDLIST. When an actual hw (USB) device is connected, a PDO is created and added to the dynamic list, using a device+instanceId based on the usb VID+PID of the device + a count to discriminate between identical vid+pid combinations. When one of our USB devices arrives WdfChildListAddOrUpdateChildDescriptionAsPresent() is called using the instance data mentioned above. When the device is removed WdfChildListRequestChildEject() is called passing device+InstanceID for that device. The child PDOs expose a CompatibleId that another custom driver is loaded against. This all works very well and reliably until…
Unplugging and replugging the SAME device too close together in time causes this bugcheck:


*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

PNP_DETECTED_FATAL_ERROR (ca)
PnP encountered a severe error, either as a result of a problem in a driver or
a problem in PnP itself.  The first argument describes the nature of the
problem, the second argument is the address of the PDO.  The other arguments
vary depending on argument 1.
Arguments:
Arg1: 0000000000000001, Duplicate PDO
	A specific instance of a driver has enumerated multiple PDOs with
	identical device id and unique ids.
Arg2: ffffe70cd557d2c0, Newly reported PDO.
Arg3: ffffe70cdbf3a9f0, PDO of which it is a duplicate.
Arg4: 0000000000000000

I have verified that the wdfchildlist does indeed contain both PDOs:

Dumping WDFCHILDLIST 0x000018f32c4c4fd8

Owning !wdfdevice 0x000018f32ae1dfd8
ID description size 0x28

State:

List is unlocked, changes will be applied immediately
No scans or enumerations are active on the list

Descriptions:

PDO !wdfdevice 0x000018f32ab17378, ID description 0xffffe70cdb28ada8
+Device WDM !devobj 0xffffe70cdbf3a9f0, WDF pnp state WdfDevStatePnpStarted (0x119)
+Device found in last scan

PDO !wdfdevice 0x000018f326b466c8, ID description 0xffffe70cdb28b168
+Device WDM !devobj 0xffffe70cdb38d9f0, WDF pnp state WdfDevStatePnpStarted (0x119)
+Device found in last scan

PDO !wdfdevice 0x000018f32c7bf998, ID description 0xffffe70cdbfdd3a8
+Device WDM !devobj 0xffffe70cd557d2c0, WDF pnp state WdfDevStatePnpInit (0x105)
+Device found in last scan

No pending insertions are in the list.

Things I’ve tried / observations:
Making EVERY PDO’s device+InstanceId unique (autoincrementing global id) “fixes” the problem, but the custom driver that loads against the PDO is an audio portcls driver for which the auidoi endpoint builder seems to use bus info from the PDO to create a unique set of MMDevice subkeys for each occurrence it sees. With a device exposing many filters the MMdevices subkeys can get large very quickly which slows down the audio endpoint builder and makes for an annoying user experience.
I’ve tried setting the WDF_DEVICE_PNP_CAPABILITIES->UniqueId to WdfTrue, WdfFalse and use Default - no visible difference.

Implementing the ChildEvtDescriptionCompare() allows me to know wether there is a duplicate in the list at add time, but Im not sure what to do.

My Question:
A brute force approach to programmatically wait and poll the WDFCHILDLIST until the old PDO has actually been removed seems like a kludge and seems problematic, i.e. how long do I wait? Wait if I timeout?

Could I use a static list with a preset size of say 4 devices, and maybe change the state of the PDO (not actually creating / destroying it, using WdfPdoMarkMissing() and or WdfDeviceSetDeviceState()), to request that the driver load or unload, understanding, of course the requirements for said driver to actually unload?

I apologize if these are naive questions, and I don’t mind experimenting, I’d just like to get any thoughts on the current approach or possible alternatives.

Thanks as always!

You should not need to poll. Is there a reason you are not using WdfChildListUpdateChildDescriptionAsMissing to mark the child as missing? By using WdfChildListUpdateChildDescriptionAsMissing, the child list will track state for you if you report the PDO as present after you have marked the PDO as missing and before it has been removed by pnp. Eject doesn’t mark the PDO as missing immediately, rather it tears down the stack and then asks the bus driver if the PDO is still present. Lots more work and state management. d

Magic! Thanks Doron!! (thats fixed it)

sure, let’s call in magic :wink: