Index: trunk/src/VBox/HostDrivers/VBoxUSB/win/mon/VBoxUsbMon.cpp
===================================================================
--- trunk/src/VBox/HostDrivers/VBoxUSB/win/mon/VBoxUsbMon.cpp	(revision 48042)
+++ trunk/src/VBox/HostDrivers/VBoxUSB/win/mon/VBoxUsbMon.cpp	(revision 48062)
@@ -62,8 +62,27 @@
 } VBOXUSBHUB_PNPHOOK_COMPLETION, *PVBOXUSBHUB_PNPHOOK_COMPLETION;
 
+/*
+ * Comment out VBOX_USB3PORT definition to disable hooking to multiple drivers (#6509)
+ */
+#define VBOX_USB3PORT
+
+#ifdef VBOX_USB3PORT
+#define VBOXUSBMON_MAXDRIVERS 3
+typedef struct VBOXUSB_PNPDRIVER
+{
+    PDRIVER_OBJECT     DriverObject;
+    VBOXUSBHUB_PNPHOOK UsbHubPnPHook;
+    PDRIVER_DISPATCH   pfnHookStub;
+} VBOXUSB_PNPDRIVER, *PVBOXUSB_PNPDRIVER;
+#endif /* !VBOX_USB3PORT */
+
 typedef struct VBOXUSBMONGLOBALS
 {
     PDEVICE_OBJECT pDevObj;
+#ifdef VBOX_USB3PORT
+    VBOXUSB_PNPDRIVER pDrivers[VBOXUSBMON_MAXDRIVERS];
+#else /* !VBOX_USB3PORT */
     VBOXUSBHUB_PNPHOOK UsbHubPnPHook;
+#endif /* !VBOX_USB3PORT */
     KEVENT OpenSynchEvent;
     IO_REMOVE_LOCK RmLock;
@@ -510,4 +529,5 @@
 {
     NTSTATUS Status = STATUS_UNSUCCESSFUL;
+#ifndef VBOX_USB3PORT
     UNICODE_STRING szStandardHubName;
     PDRIVER_OBJECT pDrvObj = NULL;
@@ -587,4 +607,41 @@
         }
     }
+#else /* VBOX_USB3PORT */
+    PWSTR szwHubList;
+    Status = IoGetDeviceInterfaces(&GUID_DEVINTERFACE_USB_HUB, NULL, 0, &szwHubList);
+    if (Status != STATUS_SUCCESS)
+    {
+        LOG(("IoGetDeviceInterfaces failed with %d\n", Status));
+        return;
+    }
+    if (szwHubList)
+    {
+        UNICODE_STRING  UnicodeName;
+        PDEVICE_OBJECT  pHubDevObj;
+        PFILE_OBJECT    pHubFileObj;
+        PWSTR           szwHubName = szwHubList;
+        while (*szwHubName != UNICODE_NULL)
+        {
+            RtlInitUnicodeString(&UnicodeName, szwHubName);
+            Status = IoGetDeviceObjectPointer(&UnicodeName, FILE_READ_DATA, &pHubFileObj, &pHubDevObj);
+            if (Status == STATUS_SUCCESS)
+            {
+                /** @todo Replace %S with something else as it does not work for PWSTR. */
+                LOG(("IoGetDeviceObjectPointer for %S returned %p %p", szwHubName, pHubDevObj, pHubFileObj));
+                if (!pfnWalker(pHubFileObj, pHubDevObj, pHubDevObj, pvWalker))
+                {
+                    LOG(("the walker said to stop"));
+                    ObDereferenceObject(pHubFileObj);
+                    break;
+                }
+
+                LOG(("going forward.."));
+                ObDereferenceObject(pHubFileObj);
+            }
+            szwHubName += wcslen(szwHubName) + 1;
+        }
+        ExFreePool(szwHubList);
+    }
+#endif /* VBOX_USB3PORT */
 }
 
@@ -997,5 +1054,10 @@
     NTSTATUS tmpStatus = pIrp->IoStatus.Status;
 #endif
-    NTSTATUS Status = VBoxUsbHookRequestComplete(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook, pDevObj, pIrp, pRequest);
+#ifdef VBOX_USB3PORT
+    PVBOXUSBHOOK_ENTRY pHook = pRequest->pHook;
+#else /* !VBOX_USB3PORT */
+    PVBOXUSBHOOK_ENTRY pHook = &g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook;
+#endif /* !VBOX_USB3PORT */
+    NTSTATUS Status = VBoxUsbHookRequestComplete(pHook, pDevObj, pIrp, pRequest);
     VBoxUsbMonMemFree(pRequest);
 #ifdef DEBUG_misha
@@ -1005,5 +1067,5 @@
     }
 #endif
-    VBoxUsbHookRelease(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook);
+    VBoxUsbHookRelease(pHook);
     return Status;
 }
@@ -1015,12 +1077,19 @@
  * @param   pIrp         Request packet.
  */
+#ifdef VBOX_USB3PORT
+static NTSTATUS vboxUsbMonPnPHook(IN PVBOXUSBHOOK_ENTRY pHook, IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
+#else /* !VBOX_USB3PORT */
 NTSTATUS _stdcall VBoxUsbMonPnPHook(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
-{
+#endif /* !VBOX_USB3PORT */
+{
+#ifndef VBOX_USB3PORT
+    PVBOXUSBHOOK_ENTRY pHook = &g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook;
+#endif /* !VBOX_USB3PORT */
     LOG(("==>PnP: Mn(%s), PDO(0x%p), IRP(0x%p), Status(0x%x)", vboxUsbDbgStrPnPMn(IoGetCurrentIrpStackLocation(pIrp)->MinorFunction), pDevObj, pIrp, pIrp->IoStatus.Status));
 
-    if(!VBoxUsbHookRetain(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook))
+    if(!VBoxUsbHookRetain(pHook))
     {
         WARN(("VBoxUsbHookRetain failed"));
-        return VBoxUsbHookRequestPassDownHookSkip(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook, pDevObj, pIrp);
+        return VBoxUsbHookRequestPassDownHookSkip(pHook, pDevObj, pIrp);
     }
 
@@ -1029,5 +1098,5 @@
     {
         WARN(("VBoxUsbMonMemAlloc failed"));
-        VBoxUsbHookRelease(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook);
+        VBoxUsbHookRelease(pHook);
         pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
         pIrp->IoStatus.Information = 0;
@@ -1036,10 +1105,10 @@
     }
 
-    NTSTATUS Status = VBoxUsbHookRequestPassDownHookCompletion(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook, pDevObj, pIrp, VBoxUsbPnPCompletion, &pCompletion->Rq);
+    NTSTATUS Status = VBoxUsbHookRequestPassDownHookCompletion(pHook, pDevObj, pIrp, VBoxUsbPnPCompletion, &pCompletion->Rq);
 #ifdef VBOX_USB_WITH_VERBOSE_LOGGING
     if (Status != STATUS_PENDING)
     {
         LOG(("Request completed, Status(0x%x)", Status));
-        VBoxUsbHookVerifyCompletion(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook, &pCompletion->Rq, pIrp);
+        VBoxUsbHookVerifyCompletion(pHook, &pCompletion->Rq, pIrp);
     }
     else
@@ -1051,4 +1120,77 @@
 }
 
+#ifdef VBOX_USB3PORT
+/**
+ * Device PnP hook stubs.
+ *
+ * @param   pDevObj     Device object.
+ * @param   pIrp         Request packet.
+ */
+#define VBOX_PNPHOOKSTUB(n) NTSTATUS _stdcall VBoxUsbMonPnPHook##n(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) \
+{ \
+    return vboxUsbMonPnPHook(&g_VBoxUsbMonGlobals.pDrivers[n].UsbHubPnPHook.Hook, pDevObj, pIrp); \
+}
+
+#define VBOX_PNPHOOKSTUB_INIT(n) g_VBoxUsbMonGlobals.pDrivers[n].pfnHookStub = VBoxUsbMonPnPHook##n
+
+VBOX_PNPHOOKSTUB(0)
+VBOX_PNPHOOKSTUB(1)
+VBOX_PNPHOOKSTUB(2)
+AssertCompile(VBOXUSBMON_MAXDRIVERS == 3);
+
+typedef struct VBOXUSBMONHOOKDRIVERWALKER
+{
+    PDRIVER_OBJECT pDrvObj;
+} VBOXUSBMONHOOKDRIVERWALKER, *PVBOXUSBMONHOOKDRIVERWALKER;
+
+static DECLCALLBACK(BOOLEAN) vboxUsbMonHookDrvObjWalker(PFILE_OBJECT pFile, PDEVICE_OBJECT pTopDo, PDEVICE_OBJECT pHubDo, PVOID pvContext)
+{
+    PDRIVER_OBJECT pDrvObj = pHubDo->DriverObject;
+
+    /* First we try to figure out if we are already hooked to this driver. */
+    for (int i = 0; i < VBOXUSBMON_MAXDRIVERS; i++)
+        if (pDrvObj == g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
+        {
+            LOG(("Found %p at pDrivers[%d]\n", pDrvObj, i));
+            /* We've already hooked to this one -- nothing to do. */
+            return TRUE;
+        }
+    /* We are not hooked yet, find an empty slot. */
+    for (int i = 0; i < VBOXUSBMON_MAXDRIVERS; i++)
+    {
+        if (!g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
+        {
+            /* Found an emtpy slot, use it. */
+            g_VBoxUsbMonGlobals.pDrivers[i].DriverObject = pDrvObj;
+            ObReferenceObject(pDrvObj);
+            LOG(("pDrivers[%d] = %p, installing the hook...\n", i, pDrvObj));
+            VBoxUsbHookInit(&g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook,
+                            pDrvObj,
+                            IRP_MJ_PNP,
+                            g_VBoxUsbMonGlobals.pDrivers[i].pfnHookStub);
+            VBoxUsbHookInstall(&g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook);
+            return TRUE; /* Must continue to find all drivers. */
+        }
+        if (pDrvObj == g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
+        {
+            LOG(("Found %p at pDrivers[%d]\n", pDrvObj, i));
+            /* We've already hooked to this one -- nothing to do. */
+            return TRUE;
+        }
+    }
+    /* No empty slots! No reason to continue. */
+    LOG(("No empty slots!\n"));
+    return FALSE;
+}
+
+/**
+ * Finds all USB drivers in the system and installs hooks if haven't done already.
+ */
+static NTSTATUS vboxUsbMonInstallAllHooks()
+{
+    vboxUsbMonHubDevWalk(vboxUsbMonHookDrvObjWalker, NULL, VBOXUSBMONHUBWALK_F_ALL);
+    return STATUS_SUCCESS;
+}
+#endif /* VBOX_USB3PORT */
 
 static NTSTATUS vboxUsbMonHookCheckInit()
@@ -1060,4 +1202,7 @@
         return STATUS_SUCCESS;
     }
+#ifdef VBOX_USB3PORT
+    return vboxUsbMonInstallAllHooks();
+#else /* !VBOX_USB3PORT */
     PDRIVER_OBJECT pDrvObj = vboxUsbMonHookFindHubDrvObj();
     if (pDrvObj)
@@ -1070,8 +1215,13 @@
     WARN(("hub drv obj not found, fail"));
     return STATUS_UNSUCCESSFUL;
+#endif /* !VBOX_USB3PORT */
 }
 
 static NTSTATUS vboxUsbMonHookInstall()
 {
+#ifdef VBOX_USB3PORT
+    /* Nothing to do here as we have already installed all hooks in vboxUsbMonHookCheckInit(). */
+    return STATUS_SUCCESS;
+#else /* !VBOX_USB3PORT */
 #ifdef VBOXUSBMON_DBG_NO_PNPHOOK
     return STATUS_SUCCESS;
@@ -1084,4 +1234,5 @@
     return VBoxUsbHookInstall(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook);
 #endif
+#endif /* !VBOX_USB3PORT */
 }
 
@@ -1091,4 +1242,33 @@
     return STATUS_SUCCESS;
 #else
+#ifdef VBOX_USB3PORT
+    NTSTATUS Status = STATUS_SUCCESS;
+    for (int i = 0; i < VBOXUSBMON_MAXDRIVERS; i++)
+    {
+        if (g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
+        {
+            Assert(g_VBoxUsbMonGlobals.pDrivers[i].DriverObject == g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook.pDrvObj);
+            LOG(("Unhooking from %p...\n", g_VBoxUsbMonGlobals.pDrivers[i].DriverObject));
+            Status = VBoxUsbHookUninstall(&g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook);
+            if (!NT_SUCCESS(Status))
+            {
+                /*
+                 * We failed to uninstall the hook, so we keep the reference to the driver
+                 * in order to prevent another driver re-using this slot because we are
+                 * going to mark this hook as fUninitFailed.
+                 */
+                //AssertMsgFailed(("usbhub pnp unhook failed, setting the fUninitFailed flag, the current value of fUninitFailed (%d)", g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed));
+                LOG(("usbhub pnp unhook failed, setting the fUninitFailed flag, the current value of fUninitFailed (%d)", g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.fUninitFailed));
+                g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.fUninitFailed = true;
+            }
+            else
+            {
+                /* The hook was removed successfully, now we can forget about this driver. */
+                ObDereferenceObject(g_VBoxUsbMonGlobals.pDrivers[i].DriverObject);
+                g_VBoxUsbMonGlobals.pDrivers[i].DriverObject = NULL;
+            }
+        }
+    }
+#else /* !VBOX_USB3PORT */
     NTSTATUS Status = VBoxUsbHookUninstall(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook);
     if (!NT_SUCCESS(Status))
@@ -1097,4 +1277,5 @@
         g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed = true;
     }
+#endif /* !VBOX_USB3PORT */
     return Status;
 #endif
@@ -1675,4 +1856,10 @@
 
     memset (&g_VBoxUsbMonGlobals, 0, sizeof (g_VBoxUsbMonGlobals));
+#ifdef VBOX_USB3PORT
+    VBOX_PNPHOOKSTUB_INIT(0);
+    VBOX_PNPHOOKSTUB_INIT(1);
+    VBOX_PNPHOOKSTUB_INIT(2);
+    AssertCompile(VBOXUSBMON_MAXDRIVERS == 3);
+#endif /* VBOX_USB3PORT */
     KeInitializeEvent(&g_VBoxUsbMonGlobals.OpenSynchEvent, SynchronizationEvent, TRUE /* signaled */);
     IoInitializeRemoveLock(&g_VBoxUsbMonGlobals.RmLock, VBOXUSBMON_MEMTAG, 1, 100);
