USBPcap attaches as Upper Filter for all Root Hubs. It does so by adding UpperFilters entry for {36FC9E60-C465-11CF-8056-444553540000} class. Then in AddDevice function I retrieve the PDO and get list of hardware IDs. Then the list is checked for USB\ROOT_HUB and USB\ROOT_HUB20 entries. If it's in the list, the device is considered Root Hub, otherwise not. The source code for above function is available at github: https://github.com/desowin/usbpcap/blob/master/USBPcapDriver/USBPcapHelperFunctions.c#L725
This solution doesn't play nice with USB 3.0 Root Hubs. As there are many different drivers for USB 3.0 controllers floating around there is not standard USB\ROOT_HUB30 entry. Basically every driver has its own hardware ID. I would prefer to avoid making a list of hardware IDs for all root hubs out there.
I would like to know if there is any way to reliably determine whether device is root hub without relying solely on hardware ids.
I thought about checking if device has GUID_DEVINTERFACE_USB_HUB and its parent has GUID_DEVINTERFACE_USB_HOST_CONTROLLER, but I don't know how (and if) it can be done in kernel mode inside function called in AddDevice callback.
I solved this issue by generating list of non standard (by standard Hardware ID I mean USB\ROOT_HUB and USB\ROOT_HUB20) Hardware IDs in user-space application and storing it in registry. I enumerate all GUID_DEVINTERFACE_USB_HOST_CONTROLLER instances and assume that children are Root Hubs.
Driver checks if the Hardware ID is present in registry entry generated by user-space application. If it matches, it is considered a Root Hub.