PnP notification on device interface change not received :(

Hi all,
I have a problem with notification on device interface change - it does not work for me at all :frowning: I spent last few days on this, read (probaly) all MS documentation and other sources, tried many posibilities and still canā€™t have it working. I fill that Iā€™m in the aā€¦, so I need any suggestion, ideas, something, pleaseā€¦
The main idea is exactly like described here: http://www.osronline.com/article.cfm^id=24.htm
Some facts:
Iā€™m creating two independent drivers (in the meaning: not belonging to the same driver stack), for Win10/11:

  • the ā€œmainā€ driver, which is the root enumerated software driver, exposing two interfaces: one for userspace communication (using IOCTLs), and the second one for inter-driver communcation (query interface);
  • the ā€œcardā€ driver, which is the driver for specific (custom) hardware (PCIe card), it doesnā€™t expose any interface, but registers ā€œitselfā€ as a subscriber for the PnP notifications about inter-driver communication interface state changes (an then communicates with ā€œmainā€ driver using this interface - but it is not important here).

So, in the ā€œmainā€ driver:

  • in the ā€œadd deviceā€ handler Iā€™m creating device, then Iā€™m creating the interface using WdfDeviceAddQueryInterface() (of course the dedicated unique GUID is used), and finally Iā€™m enabling this interface using WdfDeviceSetDeviceInterfaceState() with TRUE parameter;
  • in the ā€œdevice cleanupā€ event handler Iā€™m disabling this interface using WdfDeviceSetDeviceInterfaceState() with FALSE parameter (of course there are other things done too, but not important here).

And, in the ā€œcardā€ driver:

  • in the EvtDeviceSelfManagedIoInit handler Iā€™m registering subscription for notifications about interface state changed, using IoRegisterPlugPlayNotification() with parameters: EventCategoryDeviceInterfaceChange and PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, own callback function, and the same GUID as used in the ā€œmainā€ driver for creation and enabling/disabling the interface;
  • in the EvtDeviceSelfManagedIoCleanup handler Iā€™m unregistering subscription for these notifications using IoUnregisterPlugPlayNotificationEx();
  • of course the NotificationEntry pointer is saved on registering and used for unregistering.

All the above code executes without any problems (Iā€™ve logged entry/exit from all my functions/handlers, and all statuses not equal to STATUS_SUCCESS), all the flow paths are processed, event handlers are fired-up, butā€¦ unfortunately Iā€™m not receiving any notifications about interface arrival/romoval: my notification callback function is never fired-up :frowning:

As I understand the idea of such notifications, I should get the callback call on loading the ā€œmainā€ driver (so on creating the interface and enabling it), and the second call on unloading the ā€œmainā€ driver (so on disabling the interface).
Unfortunately, the callback is not called at all :frowning:

Do you have any ideas, suggestions, what I should check, or maybe Iā€™m totally wrong in my understanding of such notifications?
And the additional question: is there any tool for ā€œspyingā€ the PnP notifications sent by PnP Manager? Or is there any other way allowing to check that the PnP Manager can see the interface changes made by ā€œmainā€ driver, and sends the notifications to the ā€œcardā€ driver?

Regards,
Piotr

Oughā€¦ Probably found the reason: in the ā€œmainā€ driver Iā€™m creating interface in ā€œadd deviceā€ handler after creating the device (it is OK) and iā€™m enabling the interface in the same functionā€¦ so probably too early :frowning: So the interface is never enabled - am I right?
But: where it should be enabled???

I added interface enable/disable inside EvtDeviceD0Entry/EvtDeviceD0Exit handlers in the ā€œmainā€ driver. Andā€¦ it still doesnā€™t work :frowning: I can see (in my logs) that these handlers are executed (so the interface is enabled/disabled for sure), but the notification callback in the ā€œcardā€ driver (subscriber) is not fired-up still :(:frowning:

wdf will automatically manage device interface state on your behalf once you create the interface. See https://learn.microsoft.com/en-us/windows-hardware/drivers/wdf/using-device-interfaces#enabling-and-disabling-a-device-interface. So you donā€™t need to call set state() yourself. You need two guids though. One is the device interface created with WdfDeviceCreateDeviceInterface. The second is the query interface guid.

1 Like

Ok, so it seems that I can safely remove handling of the D0 transitions (it is used only for enabling/disabling the query interface).
Regarding to the interfaces: of course, Iā€™m using two different GUIDs - one for interface created with WdfDeviceCreateDeviceInterface, dedicated for communication with userspace (IOCTL), and the different one for the query interface. And, of course, this second GUID is used for registering for notifications in the second driver. So, it should work - but it doesnā€™t :frowning: How to investigate this issue? Iā€™ve no idea, really :frowning:

You need three GUIDs

  1. user mode device interface
  2. kernel mode device interface
  3. the query interface

query interface != device interface. there is no eventing (pub/sub) infrastructure for arrival and departure. Query interface is purely a v-table contract. Which device stack you ask query for the contract (querying for the interface) is separate from the contract itself.

In your scenario the card driver registers for device interface notifications for guid #2. When notified, it opens the interface (WdfIoTargetOpen) and then sends the query interface request (WdfIoTargetQueryForInterface).

You can choose to use one device interface (eliminate #2) to notify the card driver if you want. If the user mode application opens the main driver exclusively it makes sense to have separate device interfaces to advertise the user mode ā€œcontractā€ and the query interface contract

1 Like

Ok, I understand how to use the query interface (including INTERFACE structure and so on) - and, if I understand you correctly - I canā€™t register (in the second driver) any subscriptions for notifications related to the query interface, because it is not the ā€œrealā€ (whatever it means) interface? Am I right? If so, it seems that I didnā€™t fully understand this beforeā€¦
So, going forward, I have 2 options here:

  1. create additional ā€œfakeā€ (you called it ā€œkernel modeā€) interface in the ā€œmainā€ driver, acting only as the source of PnP notifications (arrival/removal),
    or
  2. use existing ā€œuser-modeā€ interface as the source of such notifications.
    Am I right?

correct. are you enforcing exclusive user mode handles? IOW are you calling WdfDeviceInitSetExclusive ? if so, the open from the kernel driver may fail if the user mode application already has an open handle. One choice would be to remove the WdfDeviceInitSetExclusive call and manage exclusive state yourself, restricting UserMode opens to exclusive and allowing KernelMode regardless of the UserMode open count.

1 Like

Ok, I implemented this using additional ā€œfakeā€ interface (as described in pt.1 in my previous post), andā€¦ it WORKS!!! @Doron_Holan , thank you very, very much!!! You made my day (or, more precisely, my night - because in Poland there is 02:18AM)! And especially thank you for showing me what I didnā€™t understand! If we ever meet, I have a great beer for you :slight_smile: BTW: I decided not to use the existing ā€œuser modeā€ interface because it can be temporary disabled in some situations (some things related to improper authorisation of the usermode app - customer/client expectations :slight_smile: ), and this should have no effect on the communication between drivers.
Thanks once more!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.