Index: /trunk/src/VBox/ValidationKit/utils/usb/Makefile.kmk
===================================================================
--- /trunk/src/VBox/ValidationKit/utils/usb/Makefile.kmk	(revision 60516)
+++ /trunk/src/VBox/ValidationKit/utils/usb/Makefile.kmk	(revision 60517)
@@ -52,4 +52,6 @@
 	UsbTestServiceProtocol.cpp \
 	UsbTestServiceTcp.cpp
+UsbTestService_SOURCES.linux = \
+	UsbTestServicePlatform-linux.cpp
 
 $(evalcall def_vbox_validationkit_process_python_sources)
Index: /trunk/src/VBox/ValidationKit/utils/usb/UsbTestService.cpp
===================================================================
--- /trunk/src/VBox/ValidationKit/utils/usb/UsbTestService.cpp	(revision 60516)
+++ /trunk/src/VBox/ValidationKit/utils/usb/UsbTestService.cpp	(revision 60517)
@@ -58,4 +58,5 @@
 #include "UsbTestServiceInternal.h"
 #include "UsbTestServiceGadget.h"
+#include "UsbTestServicePlatform.h"
 
 
@@ -1045,42 +1046,46 @@
     if (RT_SUCCESS(rc))
     {
-        rc = RTCritSectInit(&g_CritSectClients);
+        rc = utsPlatformInit();
         if (RT_SUCCESS(rc))
         {
-            rc = RTPipeCreate(&g_hPipeR, &g_hPipeW, 0);
+            rc = RTCritSectInit(&g_CritSectClients);
             if (RT_SUCCESS(rc))
             {
-                /* Spin off the thread serving connections. */
-                rc = RTThreadCreate(&g_hThreadServing, utsClientWorker, NULL, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
-                                    "USBTSTSRV");
+                rc = RTPipeCreate(&g_hPipeR, &g_hPipeW, 0);
                 if (RT_SUCCESS(rc))
-                    return VINF_SUCCESS;
+                {
+                    /* Spin off the thread serving connections. */
+                    rc = RTThreadCreate(&g_hThreadServing, utsClientWorker, NULL, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
+                                        "USBTSTSRV");
+                    if (RT_SUCCESS(rc))
+                        return VINF_SUCCESS;
+                    else
+                        RTMsgError("Creating the client worker thread failed with %Rrc\n", rc);
+
+                    RTPipeClose(g_hPipeR);
+                    RTPipeClose(g_hPipeW);
+                }
                 else
-                    RTMsgError("Creating the client worker thread failed with %Rrc\n", rc);
-
-                RTPipeClose(g_hPipeR);
-                RTPipeClose(g_hPipeW);
+                    RTMsgError("Creating communications pipe failed with %Rrc\n", rc);
+
+                RTCritSectDelete(&g_CritSectClients);
             }
             else
-                RTMsgError("Creating communications pipe failed with %Rrc\n", rc);
-
-            RTCritSectDelete(&g_CritSectClients);
+                RTMsgError("Creating global critical section failed with %Rrc\n", rc);
+
+            utsConfigAstDestroy(g_pCfgAst);
         }
         else
-            RTMsgError("Creating global critical section failed with %Rrc\n", rc);
-
-        utsConfigAstDestroy(g_pCfgAst);
-    }
-    else
-    {
-        if (RTErrInfoIsSet(pErrInfo))
         {
-            RTMsgError("Failed to parse config with detailed error: %s (%Rrc)\n",
-                       pErrInfo->pszMsg, pErrInfo->rc);
-            RTErrInfoFree(pErrInfo);
+            if (RTErrInfoIsSet(pErrInfo))
+            {
+                RTMsgError("Failed to parse config with detailed error: %s (%Rrc)\n",
+                           pErrInfo->pszMsg, pErrInfo->rc);
+                RTErrInfoFree(pErrInfo);
+            }
+            else
+                RTMsgError("Faield to parse config with unknown error (%Rrc)\n", rc);
+            return rc;
         }
-        else
-            RTMsgError("Faield to parse config with unknown error (%Rrc)\n", rc);
-        return rc;
     }
 
@@ -1425,4 +1430,6 @@
     g_pTransport->pfnTerm();
 
+    utsPlatformTerm();
+
     return rcExit;
 }
Index: /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadget.cpp
===================================================================
--- /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadget.cpp	(revision 60516)
+++ /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadget.cpp	(revision 60517)
@@ -107,5 +107,10 @@
             rc = pClassIf->pfnInit((PUTSGADGETCLASSINT)&pThis->abClassInst[0], paCfg);
             if (RT_SUCCESS(rc))
-                *phGadget = pThis;
+            {
+                /* Connect the gadget to the host. */
+                rc = utsGadgetHostGadgetConnect(pThis->hGadgetHost, pThis);
+                if (RT_SUCCESS(rc))
+                    *phGadget = pThis;
+            }
             else
                 RTMemFree(pThis);
@@ -145,10 +150,32 @@
 
 
+DECLHIDDEN(uint32_t) utsGadgetGetBusId(UTSGADGET hGadget)
+{
+    PUTSGADGETINT pThis = hGadget;
+
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    return pThis->pClassIf->pfnGetBusId((PUTSGADGETCLASSINT)&pThis->abClassInst[0]);
+}
+
+
+DECLHIDDEN(uint32_t) utsGadgetGetDevId(UTSGADGET hGadget)
+{
+    PUTSGADGETINT pThis = hGadget;
+
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    return 1; /** @todo: Current assumption which is true on Linux with dummy_hcd. */
+}
+
+
 DECLHIDDEN(int) utsGadgetConnect(UTSGADGET hGadget)
 {
     PUTSGADGETINT pThis = hGadget;
 
-    AssertPtrReturn(pThis, 0);
-    return VERR_NOT_IMPLEMENTED;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    int rc = pThis->pClassIf->pfnConnect((PUTSGADGETCLASSINT)&pThis->abClassInst[0]);
+    if (RT_SUCCESS(rc))
+        rc = utsGadgetHostGadgetConnect(pThis->hGadgetHost, hGadget);
+
+    return rc;
 }
 
@@ -158,6 +185,10 @@
     PUTSGADGETINT pThis = hGadget;
 
-    AssertPtrReturn(pThis, 0);
-    return VERR_NOT_IMPLEMENTED;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    int rc = utsGadgetHostGadgetDisconnect(pThis->hGadgetHost, hGadget);
+    if (RT_SUCCESS(rc))
+        rc = pThis->pClassIf->pfnDisconnect((PUTSGADGETCLASSINT)&pThis->abClassInst[0]);
+
+    return rc;
 }
 
Index: /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadget.h
===================================================================
--- /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadget.h	(revision 60516)
+++ /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadget.h	(revision 60517)
@@ -401,5 +401,5 @@
  * @param   paCfg             Additional configuration parameters - optional.
  *                            The array must be terminated with a NULL entry.
- * @param   phGadgetHost      Where to store the handle to the gadget host on success.              
+ * @param   phGadgetHost      Where to store the handle to the gadget host on success.
  */
 DECLHIDDEN(int) utsGadgetHostCreate(UTSGADGETHOSTTYPE enmType, PCUTSGADGETCFGITEM paCfg,
@@ -430,4 +430,22 @@
  */
 DECLHIDDEN(PCUTSGADGETCFGITEM) utsGadgetHostGetCfg(UTSGADGETHOST hGadgetHost);
+
+/**
+ * Connects the given gadget to the host.
+ *
+ * @returns IPRT status code.
+ * @param   hGadgetHost       The gadget host handle.
+ * @param   hGadget           The gadget handle.
+ */
+DECLHIDDEN(int) utsGadgetHostGadgetConnect(UTSGADGETHOST hGadgetHost, UTSGADGET hGadget);
+
+/**
+ * Disconnects the given gadget from the host.
+ *
+ * @returns IPRT status code.
+ * @param   hGadgetHost       The gadget host handle.
+ * @param   hGadget           The gadget handle.
+ */
+DECLHIDDEN(int) utsGadgetHostGadgetDisconnect(UTSGADGETHOST hGadgetHost, UTSGADGET hGadget);
 
 /**
@@ -477,4 +495,20 @@
 
 /**
+ * Returns the bus ID the gadget is on.
+ *
+ * @returns Bus ID of the gadget.
+ * @param   hGadget           The gadget handle.
+ */
+DECLHIDDEN(uint32_t) utsGadgetGetBusId(UTSGADGET hGadget);
+
+/**
+ * Returns the device ID of the gagdet.
+ *
+ * @returns Device ID of the gadget.
+ * @param   hGadget           The gadget handle.
+ */
+DECLHIDDEN(uint32_t) utsGadgetGetDevId(UTSGADGET hGadget);
+
+/**
  * Mark the gadget as connected to the host. Depending
  * on the host type it will be appear as physically attached
Index: /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetClassTest.cpp
===================================================================
--- /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetClassTest.cpp	(revision 60516)
+++ /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetClassTest.cpp	(revision 60517)
@@ -37,4 +37,5 @@
 
 #include "UsbTestServiceGadgetInternal.h"
+#include "UsbTestServicePlatform.h"
 
 /*********************************************************************************************************************************
@@ -253,4 +254,12 @@
     /* Finally delete the gadget template. */
     utsGadgetClassTestDirRemove(pClass->pszGadgetPath);
+
+    /* Release the UDC. */
+    if (pClass->pszUdc)
+    {
+        rc = utsPlatformLnxReleaseUDC(pClass->pszUdc);
+        AssertRC(rc);
+        RTStrFree(pClass->pszUdc);
+    }
 }
 
@@ -343,7 +352,12 @@
 
                 /* Finally enable the gadget by attaching it to a UDC. */
-                /** @todo: Figure out a free UDC dynamically. */
-                if (RT_SUCCESS(rc))
-                    rc = RTLinuxSysFsWriteStrFile("dummy_udc.0", 0, NULL, "%s/UDC", pClass->pszGadgetPath);
+                if (RT_SUCCESS(rc))
+                {
+                    pClass->pszUdc = NULL;
+
+                    rc = utsPlatformLnxAcquireUDC(&pClass->pszUdc, &pClass->uBusId);
+                    if (RT_SUCCESS(rc))
+                        rc = RTLinuxSysFsWriteStrFile(pClass->pszUdc, 0, NULL, "%s/UDC", pClass->pszGadgetPath);
+                }
             }
 
@@ -378,4 +392,30 @@
 
 
+/**
+ * @interface_method_impl{UTSGADGETCLASS,pfnGetBusId}
+ */
+static DECLCALLBACK(uint32_t) utsGadgetClassTestGetBusId(PUTSGADGETCLASSINT pClass)
+{
+    return pClass->uBusId;
+}
+
+
+/**
+ * @interface_method_impl{UTSGADGETCLASS,pfnConnect}
+ */
+static DECLCALLBACK(int) utsGadgetClassTestConnect(PUTSGADGETCLASSINT pClass)
+{
+    return RTLinuxSysFsWriteStrFile("connect", 0, NULL, "/sys/class/udc/%s/soft_connect", pClass->pszUdc);
+}
+
+
+/**
+ * @interface_method_impl{UTSGADGETCLASS,pfnDisconnect}
+ */
+static DECLCALLBACK(int) utsGadgetClassTestDisconnect(PUTSGADGETCLASSINT pClass)
+{
+    return RTLinuxSysFsWriteStrFile("disconnect", 0, NULL, "/sys/class/udc/%s/soft_connect", pClass->pszUdc);}
+
+
 
 /**
@@ -393,5 +433,11 @@
     utsGadgetClassTestInit,
     /** pfnTerm */
-    utsGadgetClassTestTerm
+    utsGadgetClassTestTerm,
+    /** pfnGetBusId */
+    utsGadgetClassTestGetBusId,
+    /** pfnConnect */
+    utsGadgetClassTestConnect,
+    /** pfnDisconnect. */
+    utsGadgetClassTestDisconnect
 };
 
Index: /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetHost.cpp
===================================================================
--- /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetHost.cpp	(revision 60516)
+++ /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetHost.cpp	(revision 60517)
@@ -142,2 +142,20 @@
 }
 
+
+DECLHIDDEN(int) utsGadgetHostGadgetConnect(UTSGADGETHOST hGadgetHost, UTSGADGET hGadget)
+{
+    PUTSGADGETHOSTINT pThis = hGadgetHost;
+
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    return pThis->pHstIf->pfnGadgetConnect((PUTSGADGETHOSTTYPEINT)&pThis->abIfInst[0], hGadget);
+}
+
+
+DECLHIDDEN(int) utsGadgetHostGadgetDisconnect(UTSGADGETHOST hGadgetHost, UTSGADGET hGadget)
+{
+    PUTSGADGETHOSTINT pThis = hGadgetHost;
+
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    return pThis->pHstIf->pfnGadgetDisconnect((PUTSGADGETHOSTTYPEINT)&pThis->abIfInst[0], hGadget);
+}
+
Index: /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetHostUsbIp.cpp
===================================================================
--- /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetHostUsbIp.cpp	(revision 60516)
+++ /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetHostUsbIp.cpp	(revision 60517)
@@ -34,4 +34,5 @@
 
 #include "UsbTestServiceGadgetHostInternal.h"
+#include "UsbTestServicePlatform.h"
 
 /*********************************************************************************************************************************
@@ -57,23 +58,39 @@
 
 /**
- * Load a kernel module on a Linux host.
+ * Worker for binding/unbinding the given gadget from the USB/IP server.
  *
  * @returns IPRT status code.
- * @param   pszModule    The module to load.
- */
-static int utsGadgetHostUsbIpLoadModule(const char *pszModule)
-{
-    RTPROCESS hProcModprobe = NIL_RTPROCESS;
-    const char *apszArgv[3];
-
-    apszArgv[0] = "modprobe";
-    apszArgv[1] = pszModule;
-    apszArgv[2] = NULL;
-
-    int rc = RTProcCreate("modprobe", apszArgv, RTENV_DEFAULT, RTPROC_FLAGS_SEARCH_PATH, &hProcModprobe);
+ * @param   pThis             The gadget host instance.
+ * @param   hGadget           The gadget handle.
+ * @param   fBind             Flag whether to do a bind or unbind.
+ */
+static int usbGadgetHostUsbIpBindUnbind(PUTSGADGETHOSTTYPEINT pThis, UTSGADGET hGadget, bool fBind)
+{
+    uint32_t uBusId, uDevId;
+    char aszBus[32];
+
+    uBusId = utsGadgetGetBusId(hGadget);
+    uDevId = utsGadgetGetDevId(hGadget);
+
+    /* Create the busid argument string. */
+    size_t cbRet = RTStrPrintf(&aszBus[0], RT_ELEMENTS(aszBus), "%u-%u", uBusId, uDevId);
+    if (cbRet == RT_ELEMENTS(aszBus))
+        return VERR_BUFFER_OVERFLOW;
+
+    /* Bind to the USB/IP server. */
+    RTPROCESS hProcUsbIp = NIL_RTPROCESS;
+    const char *apszArgv[5];
+
+    apszArgv[0] = "usbip";
+    apszArgv[1] = fBind ? "bind" : "unbind";
+    apszArgv[2] = "-b";
+    apszArgv[3] = &aszBus[0];
+    apszArgv[4] = NULL;
+
+    int rc = RTProcCreate("usbip", apszArgv, RTENV_DEFAULT, RTPROC_FLAGS_SEARCH_PATH, &hProcUsbIp);
     if (RT_SUCCESS(rc))
     {
         RTPROCSTATUS ProcSts;
-        rc = RTProcWait(hProcModprobe, RTPROCWAIT_FLAGS_BLOCK, &ProcSts);
+        rc = RTProcWait(hProcUsbIp, RTPROCWAIT_FLAGS_BLOCK, &ProcSts);
         if (RT_SUCCESS(rc))
         {
@@ -88,5 +105,4 @@
 }
 
-
 /**
  * @interface_method_impl{UTSGADGETHOSTIF,pfnInit}
@@ -103,44 +119,40 @@
     {
         /* Make sure the kernel drivers are loaded. */
-        rc = utsGadgetHostUsbIpLoadModule("usbip-core");
+        rc = utsPlatformModuleLoad("usbip-core", NULL, 0);
         if (RT_SUCCESS(rc))
         {
-            rc = utsGadgetHostUsbIpLoadModule("usbip-host");
+            rc = utsPlatformModuleLoad("usbip-host", NULL, 0);
             if (RT_SUCCESS(rc))
             {
-                rc = utsGadgetHostUsbIpLoadModule("libcomposite");
+                char aszPort[10];
+                char aszPidFile[64];
+                const char *apszArgv[6];
+
+                RTStrPrintf(aszPort, RT_ELEMENTS(aszPort), "%u", uPort);
+                RTStrPrintf(aszPidFile, RT_ELEMENTS(aszPidFile), "/var/run/usbipd-%u.pid", uPort);
+                /* Start the USB/IP server process. */
+                apszArgv[0] = "usbipd";
+                apszArgv[1] = "--tcp-port";
+                apszArgv[2] = aszPort;
+                apszArgv[3] = "--pid";
+                apszArgv[4] = aszPidFile;
+                apszArgv[5] = NULL;
+                rc = RTProcCreate("usbipd", apszArgv, RTENV_DEFAULT, RTPROC_FLAGS_SEARCH_PATH, &pIf->hProcUsbIp);
                 if (RT_SUCCESS(rc))
                 {
-                    char aszPort[10];
-                    char aszPidFile[64];
-                    const char *apszArgv[6];
-
-                    RTStrPrintf(aszPort, RT_ELEMENTS(aszPort), "%u", uPort);
-                    RTStrPrintf(aszPidFile, RT_ELEMENTS(aszPidFile), "/var/run/usbipd-%u.pid", uPort);
-                    /* Start the USB/IP server process. */
-                    apszArgv[0] = "usbipd";
-                    apszArgv[1] = "--tcp-port";
-                    apszArgv[2] = aszPort;
-                    apszArgv[3] = "--pid";
-                    apszArgv[4] = aszPidFile;
-                    apszArgv[5] = NULL;
-                    rc = RTProcCreate("usbipd", apszArgv, RTENV_DEFAULT, RTPROC_FLAGS_SEARCH_PATH, &pIf->hProcUsbIp);
-                    if (RT_SUCCESS(rc))
+                    /* Wait for a bit to make sure the server started up successfully. */
+                    uint64_t tsStart = RTTimeMilliTS();
+                    do
                     {
-                        /* Wait for a bit to make sure the server started up successfully. */
-                        uint64_t tsStart = RTTimeMilliTS();
-                        do
+                        RTPROCSTATUS ProcSts;
+                        rc = RTProcWait(pIf->hProcUsbIp, RTPROCWAIT_FLAGS_NOBLOCK, &ProcSts);
+                        if (rc != VERR_PROCESS_RUNNING)
                         {
-                            RTPROCSTATUS ProcSts;
-                            rc = RTProcWait(pIf->hProcUsbIp, RTPROCWAIT_FLAGS_NOBLOCK, &ProcSts);
-                            if (rc != VERR_PROCESS_RUNNING)
-                            {
-                                rc = VERR_INVALID_HANDLE;
-                                break;
-                            }
-                            RTThreadSleep(1);
-                            rc = VINF_SUCCESS;
-                        } while (RTTimeMilliTS() - tsStart < 2 * 1000); /* 2 seconds. */
-                    }
+                            rc = VERR_INVALID_HANDLE;
+                            break;
+                        }
+                        RTThreadSleep(1);
+                        rc = VINF_SUCCESS;
+                    } while (RTTimeMilliTS() - tsStart < 2 * 1000); /* 2 seconds. */
                 }
             }
@@ -190,5 +202,5 @@
 static DECLCALLBACK(int) utsGadgetHostUsbIpGadgetConnect(PUTSGADGETHOSTTYPEINT pIf, UTSGADGET hGadget)
 {
-   return VINF_SUCCESS;
+    return usbGadgetHostUsbIpBindUnbind(pIf, hGadget, true /* fBind */);
 }
 
@@ -199,5 +211,5 @@
 static DECLCALLBACK(int) utsGadgetHostUsbIpGadgetDisconnect(PUTSGADGETHOSTTYPEINT pIf, UTSGADGET hGadget)
 {
-    return VINF_SUCCESS;
+    return usbGadgetHostUsbIpBindUnbind(pIf, hGadget, false /* fBind */);
 }
 
Index: /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetInternal.h
===================================================================
--- /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetInternal.h	(revision 60516)
+++ /trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetInternal.h	(revision 60517)
@@ -69,4 +69,28 @@
     DECLR3CALLBACKMEMBER(void, pfnTerm, (PUTSGADGETCLASSINT pClass));
 
+    /**
+     * Returns the bus ID of the class instance.
+     *
+     * @returns Bus ID.
+     * @param   pClass        The interface specific instance data.
+     */
+    DECLR3CALLBACKMEMBER(uint32_t, pfnGetBusId, (PUTSGADGETCLASSINT pClass));
+
+    /**
+     * Connects the gadget.
+     *
+     * @returns IPRT status code.
+     * @param   pClass        The interface specific instance data.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnConnect, (PUTSGADGETCLASSINT pClass));
+
+    /**
+     * Disconnect the gadget.
+     *
+     * @returns IPRT status code.
+     * @param   pClass        The interface specific instance data.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnDisconnect, (PUTSGADGETCLASSINT pClass));
+
 } UTSGADGETCLASSIF;
 /** Pointer to a gadget class callback table. */
