VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/lib/VBoxUsbLib-win.cpp@ 82968

Last change on this file since 82968 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.8 KB
Line 
1/* $Id: VBoxUsbLib-win.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * VBox USB ring-3 Driver Interface library, Windows.
4 */
5
6/*
7 * Copyright (C) 2011-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
32#include <iprt/win/windows.h>
33
34#include <VBox/sup.h>
35#include <VBox/types.h>
36#include <VBox/err.h>
37#include <VBox/param.h>
38#include <iprt/path.h>
39#include <iprt/assert.h>
40#include <iprt/alloc.h>
41#include <iprt/string.h>
42#include <iprt/thread.h>
43#include <iprt/utf16.h>
44#include <VBox/log.h>
45#include <VBox/usblib.h>
46#include <VBox/usblib-win.h>
47#include <VBox/usb.h>
48#include <VBox/VBoxDrvCfg-win.h>
49#pragma warning (disable:4200) /* shuts up the empty array member warnings */
50#include <iprt/win/setupapi.h>
51#include <usbdi.h>
52#include <hidsdi.h>
53#include <Dbt.h>
54
55/* Defined in Windows 8 DDK (through usbdi.h) but we use Windows 7 DDK to build. */
56#define UsbSuperSpeed 3
57
58#ifdef VBOX_WITH_NEW_USB_ENUM
59# include <cfgmgr32.h>
60#endif
61
62
63/*********************************************************************************************************************************
64* Structures and Typedefs *
65*********************************************************************************************************************************/
66typedef struct _USB_INTERFACE_DESCRIPTOR2
67{
68 UCHAR bLength;
69 UCHAR bDescriptorType;
70 UCHAR bInterfaceNumber;
71 UCHAR bAlternateSetting;
72 UCHAR bNumEndpoints;
73 UCHAR bInterfaceClass;
74 UCHAR bInterfaceSubClass;
75 UCHAR bInterfaceProtocol;
76 UCHAR iInterface;
77 USHORT wNumClasses;
78} USB_INTERFACE_DESCRIPTOR2, *PUSB_INTERFACE_DESCRIPTOR2;
79
80typedef struct VBOXUSBGLOBALSTATE
81{
82 HANDLE hMonitor;
83 HANDLE hNotifyEvent;
84 HANDLE hInterruptEvent;
85 HANDLE hThread;
86 HWND hWnd;
87 HANDLE hTimerQueue;
88 HANDLE hTimer;
89} VBOXUSBGLOBALSTATE, *PVBOXUSBGLOBALSTATE;
90
91typedef struct VBOXUSB_STRING_DR_ENTRY
92{
93 struct VBOXUSB_STRING_DR_ENTRY *pNext;
94 UCHAR iDr;
95 USHORT idLang;
96 USB_STRING_DESCRIPTOR StrDr;
97} VBOXUSB_STRING_DR_ENTRY, *PVBOXUSB_STRING_DR_ENTRY;
98
99/**
100 * This represents VBoxUsb device instance
101 */
102typedef struct VBOXUSB_DEV
103{
104 struct VBOXUSB_DEV *pNext;
105 char szName[512];
106 char szDriverRegName[512];
107} VBOXUSB_DEV, *PVBOXUSB_DEV;
108
109
110/*********************************************************************************************************************************
111* Global Variables *
112*********************************************************************************************************************************/
113static VBOXUSBGLOBALSTATE g_VBoxUsbGlobal;
114
115
116static void usbLibVuFreeDevices(PVBOXUSB_DEV pDevInfos)
117{
118 while (pDevInfos)
119 {
120 PVBOXUSB_DEV pNext = pDevInfos->pNext;
121 RTMemFree(pDevInfos);
122 pDevInfos = pNext;
123 }
124}
125
126/* Check that a proxied device responds the way we expect it to. */
127static int usbLibVuDeviceValidate(PVBOXUSB_DEV pVuDev)
128{
129 HANDLE hOut = INVALID_HANDLE_VALUE;
130 DWORD dwErr;
131
132 hOut = CreateFile(pVuDev->szName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
133 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
134
135 if (hOut == INVALID_HANDLE_VALUE)
136 {
137 dwErr = GetLastError();
138 AssertFailed();
139 LogRelFunc(("Failed to open `%s' (dwErr=%u)!\n", pVuDev->szName, dwErr));
140 return VERR_GENERAL_FAILURE;
141 }
142
143 USBSUP_VERSION version = {0};
144 DWORD cbReturned = 0;
145 int rc = VERR_VERSION_MISMATCH;
146
147 do
148 {
149 if (!DeviceIoControl(hOut, SUPUSB_IOCTL_GET_VERSION, NULL, 0,&version, sizeof(version), &cbReturned, NULL))
150 {
151 dwErr = GetLastError();
152 AssertFailed();
153 LogRelFunc(("SUPUSB_IOCTL_GET_VERSION failed on `%s' (dwErr=%u)!\n", pVuDev->szName, dwErr));
154 break;
155 }
156
157 if ( version.u32Major != USBDRV_MAJOR_VERSION
158#if USBDRV_MINOR_VERSION != 0
159 || version.u32Minor < USBDRV_MINOR_VERSION
160#endif
161 )
162 {
163 AssertFailed();
164 LogRelFunc(("Invalid version %d:%d (%s) vs %d:%d (library)!\n", version.u32Major, version.u32Minor, pVuDev->szName, USBDRV_MAJOR_VERSION, USBDRV_MINOR_VERSION));
165 break;
166 }
167
168 if (!DeviceIoControl(hOut, SUPUSB_IOCTL_IS_OPERATIONAL, NULL, 0, NULL, NULL, &cbReturned, NULL))
169 {
170 dwErr = GetLastError();
171 AssertFailed();
172 LogRelFunc(("SUPUSB_IOCTL_IS_OPERATIONAL failed on `%s' (dwErr=%u)!\n", pVuDev->szName, dwErr));
173 break;
174 }
175
176 rc = VINF_SUCCESS;
177 } while (0);
178
179 CloseHandle(hOut);
180 return rc;
181}
182
183#ifndef VBOX_WITH_NEW_USB_ENUM
184static int usbLibVuDevicePopulate(PVBOXUSB_DEV pVuDev, HDEVINFO hDevInfo, PSP_DEVICE_INTERFACE_DATA pIfData)
185{
186 DWORD cbIfDetailData;
187 int rc = VINF_SUCCESS;
188
189 SetupDiGetDeviceInterfaceDetail(hDevInfo, pIfData,
190 NULL, /* OUT PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData */
191 0, /* IN DWORD DeviceInterfaceDetailDataSize */
192 &cbIfDetailData,
193 NULL
194 );
195 Assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
196
197 PSP_DEVICE_INTERFACE_DETAIL_DATA pIfDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)RTMemAllocZ(cbIfDetailData);
198 if (!pIfDetailData)
199 {
200 AssertMsgFailed(("RTMemAllocZ failed\n"));
201 return VERR_OUT_OF_RESOURCES;
202 }
203
204 DWORD cbDbgRequired;
205 SP_DEVINFO_DATA DevInfoData;
206 DevInfoData.cbSize = sizeof (DevInfoData);
207 /* the cbSize should contain the sizeof a fixed-size part according to the docs */
208 pIfDetailData->cbSize = sizeof (*pIfDetailData);
209 do
210 {
211 if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, pIfData,
212 pIfDetailData,
213 cbIfDetailData,
214 &cbDbgRequired,
215 &DevInfoData))
216 {
217 DWORD dwErr = GetLastError(); NOREF(dwErr);
218 AssertMsgFailed(("SetupDiGetDeviceInterfaceDetail, cbRequired (%d), was (%d), dwErr (%d)\n", cbDbgRequired, cbIfDetailData, dwErr));
219 rc = VERR_GENERAL_FAILURE;
220 break;
221 }
222
223 strncpy(pVuDev->szName, pIfDetailData->DevicePath, sizeof (pVuDev->szName));
224
225 if (!SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DevInfoData, SPDRP_DRIVER,
226 NULL, /* OUT PDWORD PropertyRegDataType */
227 (PBYTE)pVuDev->szDriverRegName,
228 sizeof (pVuDev->szDriverRegName),
229 &cbDbgRequired))
230 {
231 DWORD dwErr = GetLastError(); NOREF(dwErr);
232 AssertMsgFailed(("SetupDiGetDeviceRegistryPropertyA, cbRequired (%d), was (%d), dwErr (%d)\n", cbDbgRequired, sizeof (pVuDev->szDriverRegName), dwErr));
233 rc = VERR_GENERAL_FAILURE;
234 break;
235 }
236
237 rc = usbLibVuDeviceValidate(pVuDev);
238 LogRelFunc(("Found VBoxUSB on `%s' (rc=%d)\n", pVuDev->szName, rc));
239 AssertRC(rc);
240 } while (0);
241
242 RTMemFree(pIfDetailData);
243 return rc;
244}
245
246static int usbLibVuGetDevices(PVBOXUSB_DEV *ppVuDevs, uint32_t *pcVuDevs)
247{
248 *ppVuDevs = NULL;
249 *pcVuDevs = 0;
250
251 HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_CLASS_VBOXUSB,
252 NULL, /* IN PCTSTR Enumerator */
253 NULL, /* IN HWND hwndParent */
254 (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE) /* IN DWORD Flags */
255 );
256 if (hDevInfo == INVALID_HANDLE_VALUE)
257 {
258 DWORD dwErr = GetLastError(); NOREF(dwErr);
259 AssertMsgFailed(("SetupDiGetClassDevs, dwErr (%u)\n", dwErr));
260 return VERR_GENERAL_FAILURE;
261 }
262
263 for (int i = 0; ; ++i)
264 {
265 SP_DEVICE_INTERFACE_DATA IfData;
266 IfData.cbSize = sizeof (IfData);
267 if (!SetupDiEnumDeviceInterfaces(hDevInfo,
268 NULL, /* IN PSP_DEVINFO_DATA DeviceInfoData */
269 &GUID_CLASS_VBOXUSB, /* IN LPGUID InterfaceClassGuid */
270 i,
271 &IfData))
272 {
273 DWORD dwErr = GetLastError();
274 if (dwErr == ERROR_NO_MORE_ITEMS)
275 break;
276
277 AssertMsgFailed(("SetupDiEnumDeviceInterfaces, dwErr (%u), resuming\n", dwErr));
278 continue;
279 }
280
281 /* we've now got the IfData */
282 PVBOXUSB_DEV pVuDev = (PVBOXUSB_DEV)RTMemAllocZ(sizeof (*pVuDev));
283 if (!pVuDev)
284 {
285 AssertMsgFailed(("RTMemAllocZ failed, resuming\n"));
286 continue;
287 }
288
289 int rc = usbLibVuDevicePopulate(pVuDev, hDevInfo, &IfData);
290 if (!RT_SUCCESS(rc))
291 {
292 AssertMsgFailed(("usbLibVuDevicePopulate failed, rc (%d), resuming\n", rc));
293 continue;
294 }
295
296 pVuDev->pNext = *ppVuDevs;
297 *ppVuDevs = pVuDev;
298 ++*pcVuDevs;
299 }
300
301 SetupDiDestroyDeviceInfoList(hDevInfo);
302
303 return VINF_SUCCESS;
304}
305
306static int usbLibDevPopulate(PUSBDEVICE pDev, PUSB_NODE_CONNECTION_INFORMATION_EX pConInfo, ULONG iPort, LPCSTR lpszDrvKeyName, LPCSTR lpszHubName, PVBOXUSB_STRING_DR_ENTRY pDrList)
307{
308 pDev->bcdUSB = pConInfo->DeviceDescriptor.bcdUSB;
309 pDev->bDeviceClass = pConInfo->DeviceDescriptor.bDeviceClass;
310 pDev->bDeviceSubClass = pConInfo->DeviceDescriptor.bDeviceSubClass;
311 pDev->bDeviceProtocol = pConInfo->DeviceDescriptor.bDeviceProtocol;
312 pDev->idVendor = pConInfo->DeviceDescriptor.idVendor;
313 pDev->idProduct = pConInfo->DeviceDescriptor.idProduct;
314 pDev->bcdDevice = pConInfo->DeviceDescriptor.bcdDevice;
315 pDev->bBus = 0; /** @todo figure out bBus on windows... */
316 pDev->bPort = iPort;
317 /** @todo check which devices are used for primary input (keyboard & mouse) */
318 if (!lpszDrvKeyName || *lpszDrvKeyName == 0)
319 pDev->enmState = USBDEVICESTATE_UNUSED;
320 else
321 pDev->enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
322
323 /* Determine the speed the device is operating at. */
324 switch (pConInfo->Speed)
325 {
326 case UsbLowSpeed: pDev->enmSpeed = USBDEVICESPEED_LOW; break;
327 case UsbFullSpeed: pDev->enmSpeed = USBDEVICESPEED_FULL; break;
328 case UsbHighSpeed: pDev->enmSpeed = USBDEVICESPEED_HIGH; break;
329 default: /* If we don't know, most likely it's something new. */
330 case UsbSuperSpeed: pDev->enmSpeed = USBDEVICESPEED_SUPER; break;
331 }
332 /* Unfortunately USB_NODE_CONNECTION_INFORMATION_EX will not report UsbSuperSpeed, and
333 * it's not even defined in the Win7 DDK we use. So we go by the USB version, and
334 * luckily we know that USB3 must mean SuperSpeed. The USB3 spec guarantees this (9.6.1).
335 */
336 if (pDev->bcdUSB >= 0x0300)
337 pDev->enmSpeed = USBDEVICESPEED_SUPER;
338
339 int rc = RTStrAPrintf((char **)&pDev->pszAddress, "%s", lpszDrvKeyName);
340 if (rc < 0)
341 return VERR_NO_MEMORY;
342 pDev->pszBackend = RTStrDup("host");
343 if (!pDev->pszBackend)
344 {
345 RTStrFree((char *)pDev->pszAddress);
346 return VERR_NO_STR_MEMORY;
347 }
348 pDev->pszHubName = RTStrDup(lpszHubName);
349 pDev->bNumConfigurations = 0;
350 pDev->u64SerialHash = 0;
351
352 for (; pDrList; pDrList = pDrList->pNext)
353 {
354 char **ppszString = NULL;
355 if ( pConInfo->DeviceDescriptor.iManufacturer
356 && pDrList->iDr == pConInfo->DeviceDescriptor.iManufacturer)
357 ppszString = (char **)&pDev->pszManufacturer;
358 else if ( pConInfo->DeviceDescriptor.iProduct
359 && pDrList->iDr == pConInfo->DeviceDescriptor.iProduct)
360 ppszString = (char **)&pDev->pszProduct;
361 else if ( pConInfo->DeviceDescriptor.iSerialNumber
362 && pDrList->iDr == pConInfo->DeviceDescriptor.iSerialNumber)
363 ppszString = (char **)&pDev->pszSerialNumber;
364 if (ppszString)
365 {
366 rc = RTUtf16ToUtf8((PCRTUTF16)pDrList->StrDr.bString, ppszString);
367 if (RT_SUCCESS(rc))
368 {
369 Assert(*ppszString);
370 USBLibPurgeEncoding(*ppszString);
371
372 if (pDrList->iDr == pConInfo->DeviceDescriptor.iSerialNumber)
373 pDev->u64SerialHash = USBLibHashSerial(*ppszString);
374 }
375 else
376 {
377 AssertMsgFailed(("RTUtf16ToUtf8 failed, rc (%d), resuming\n", rc));
378 *ppszString = NULL;
379 }
380 }
381 }
382
383 return VINF_SUCCESS;
384}
385#else
386
387static PSP_DEVICE_INTERFACE_DETAIL_DATA usbLibGetDevDetail(HDEVINFO InfoSet, PSP_DEVICE_INTERFACE_DATA InterfaceData, PSP_DEVINFO_DATA DevInfoData);
388static void *usbLibGetRegistryProperty(HDEVINFO InfoSet, const PSP_DEVINFO_DATA DevData, DWORD Property);
389
390/* Populate the data for a single proxied USB device. */
391static int usbLibVUsbDevicePopulate(PVBOXUSB_DEV pVuDev, HDEVINFO InfoSet, PSP_DEVICE_INTERFACE_DATA InterfaceData)
392{
393 PSP_DEVICE_INTERFACE_DETAIL_DATA DetailData = NULL;
394 SP_DEVINFO_DATA DeviceData;
395 LPCSTR Location;
396 int rc = VINF_SUCCESS;
397
398 memset(&DeviceData, 0, sizeof(DeviceData));
399 DeviceData.cbSize = sizeof(DeviceData);
400 /* The interface detail includes the device path. */
401 DetailData = usbLibGetDevDetail(InfoSet, InterfaceData, &DeviceData);
402 if (DetailData)
403 {
404 strncpy(pVuDev->szName, DetailData->DevicePath, sizeof(pVuDev->szName));
405
406 /* The location is used as a unique identifier for cross-referencing the two lists. */
407 Location = (LPCSTR)usbLibGetRegistryProperty(InfoSet, &DeviceData, SPDRP_DRIVER);
408 if (Location)
409 {
410 strncpy(pVuDev->szDriverRegName, Location, sizeof(pVuDev->szDriverRegName));
411 rc = usbLibVuDeviceValidate(pVuDev);
412 LogRelFunc(("Found VBoxUSB on `%s' (rc=%d)\n", pVuDev->szName, rc));
413 AssertRC(rc);
414
415 RTMemFree((void *)Location);
416 }
417 else
418 {
419 /* Errors will be logged by usbLibGetRegistryProperty(). */
420 rc = VERR_GENERAL_FAILURE;
421 }
422
423 RTMemFree(DetailData);
424 }
425 else
426 {
427 /* Errors will be logged by usbLibGetDevDetail(). */
428 rc = VERR_GENERAL_FAILURE;
429 }
430
431
432 return rc;
433}
434
435/* Enumerate proxied USB devices (with VBoxUSB.sys loaded). */
436static int usbLibEnumVUsbDevices(PVBOXUSB_DEV *ppVuDevs, uint32_t *pcVuDevs)
437{
438 SP_DEVICE_INTERFACE_DATA InterfaceData;
439 HDEVINFO InfoSet;
440 DWORD DeviceIndex;
441 DWORD dwErr;
442
443 *ppVuDevs = NULL;
444 *pcVuDevs = 0;
445
446 /* Enumerate all present devices which support the GUID_CLASS_VBOXUSB interface. */
447 InfoSet = SetupDiGetClassDevs(&GUID_CLASS_VBOXUSB, NULL, NULL,
448 (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
449 if (InfoSet == INVALID_HANDLE_VALUE)
450 {
451 DWORD dwErr = GetLastError();
452 LogRelFunc(("SetupDiGetClassDevs for GUID_CLASS_VBOXUSB failed (dwErr=%u)\n", dwErr));
453 AssertFailed();
454 return VERR_GENERAL_FAILURE;
455 }
456
457 memset(&InterfaceData, 0, sizeof(InterfaceData));
458 InterfaceData.cbSize = sizeof(InterfaceData);
459 DeviceIndex = 0;
460
461 /* Loop over the enumerated list. */
462 while (SetupDiEnumDeviceInterfaces(InfoSet, NULL, &GUID_CLASS_VBOXUSB, DeviceIndex, &InterfaceData))
463 {
464 /* we've now got the IfData */
465 PVBOXUSB_DEV pVuDev = (PVBOXUSB_DEV)RTMemAllocZ(sizeof (*pVuDev));
466 if (!pVuDev)
467 {
468 AssertFailed();
469 LogRelFunc(("RTMemAllocZ failed\n"));
470 break;
471 }
472
473 int rc = usbLibVUsbDevicePopulate(pVuDev, InfoSet, &InterfaceData);
474 if (RT_SUCCESS(rc))
475 {
476 pVuDev->pNext = *ppVuDevs;
477 *ppVuDevs = pVuDev;
478 ++*pcVuDevs;
479 }
480 else /* Skip this device but continue enumerating. */
481 AssertMsgFailed(("usbLibVuDevicePopulate failed, rc=%d\n", rc));
482
483 memset(&InterfaceData, 0, sizeof(InterfaceData));
484 InterfaceData.cbSize = sizeof(InterfaceData);
485 ++DeviceIndex;
486 }
487
488 /* Paranoia. */
489 dwErr = GetLastError();
490 if (dwErr != ERROR_NO_MORE_ITEMS)
491 {
492 LogRelFunc(("SetupDiEnumDeviceInterfaces failed (dwErr=%u)\n", dwErr));
493 AssertFailed();
494 }
495
496 SetupDiDestroyDeviceInfoList(InfoSet);
497
498 return VINF_SUCCESS;
499}
500
501static uint16_t usbLibParseHexNumU16(LPCSTR *ppStr)
502{
503 const char *pStr = *ppStr;
504 char c;
505 uint16_t num = 0;
506 unsigned u;
507
508 for (int i = 0; i < 4; ++i)
509 {
510 if (!*pStr) /* Just in case the string is too short. */
511 break;
512
513 c = *pStr;
514 u = c >= 'A' ? c - 'A' + 10 : c - '0'; /* Hex digit to number. */
515 num |= u << (12 - 4 * i);
516 pStr++;
517 }
518 *ppStr = pStr;
519
520 return num;
521}
522
523static int usbLibDevPopulate(PUSBDEVICE pDev, PUSB_NODE_CONNECTION_INFORMATION_EX pConInfo, ULONG iPort, LPCSTR lpszLocation, LPCSTR lpszDrvKeyName, LPCSTR lpszHubName, PVBOXUSB_STRING_DR_ENTRY pDrList)
524{
525 pDev->bcdUSB = pConInfo->DeviceDescriptor.bcdUSB;
526 pDev->bDeviceClass = pConInfo->DeviceDescriptor.bDeviceClass;
527 pDev->bDeviceSubClass = pConInfo->DeviceDescriptor.bDeviceSubClass;
528 pDev->bDeviceProtocol = pConInfo->DeviceDescriptor.bDeviceProtocol;
529 pDev->idVendor = pConInfo->DeviceDescriptor.idVendor;
530 pDev->idProduct = pConInfo->DeviceDescriptor.idProduct;
531 pDev->bcdDevice = pConInfo->DeviceDescriptor.bcdDevice;
532 pDev->bBus = 0; /* The hub numbering is not very useful on Windows. Skip it. */
533 pDev->bPort = iPort;
534
535 /* The port path/location uniquely identifies the port. */
536 pDev->pszPortPath = RTStrDup(lpszLocation);
537 if (!pDev->pszPortPath)
538 return VERR_NO_STR_MEMORY;
539
540 /* If there is no DriverKey, the device is unused because there's no driver. */
541 if (!lpszDrvKeyName || *lpszDrvKeyName == 0)
542 pDev->enmState = USBDEVICESTATE_UNUSED;
543 else
544 pDev->enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
545
546 /* Determine the speed the device is operating at. */
547 switch (pConInfo->Speed)
548 {
549 case UsbLowSpeed: pDev->enmSpeed = USBDEVICESPEED_LOW; break;
550 case UsbFullSpeed: pDev->enmSpeed = USBDEVICESPEED_FULL; break;
551 case UsbHighSpeed: pDev->enmSpeed = USBDEVICESPEED_HIGH; break;
552 default: /* If we don't know, most likely it's something new. */
553 case UsbSuperSpeed: pDev->enmSpeed = USBDEVICESPEED_SUPER; break;
554 }
555 /* Unfortunately USB_NODE_CONNECTION_INFORMATION_EX will not report UsbSuperSpeed, and
556 * it's not even defined in the Win7 DDK we use. So we go by the USB version, and
557 * luckily we know that USB3 must mean SuperSpeed. The USB3 spec guarantees this (9.6.1).
558 */
559 if (pDev->bcdUSB >= 0x0300)
560 pDev->enmSpeed = USBDEVICESPEED_SUPER;
561
562 /* If there's no DriverKey, jam in an empty string to avoid NULL pointers. */
563 if (!lpszDrvKeyName)
564 pDev->pszAddress = RTStrDup("");
565 else
566 pDev->pszAddress = RTStrDup(lpszDrvKeyName);
567
568 pDev->pszBackend = RTStrDup("host");
569 if (!pDev->pszBackend)
570 {
571 RTStrFree((char *)pDev->pszAddress);
572 return VERR_NO_STR_MEMORY;
573 }
574 pDev->pszHubName = RTStrDup(lpszHubName);
575 pDev->bNumConfigurations = 0;
576 pDev->u64SerialHash = 0;
577
578 for (; pDrList; pDrList = pDrList->pNext)
579 {
580 char **ppszString = NULL;
581 if ( pConInfo->DeviceDescriptor.iManufacturer
582 && pDrList->iDr == pConInfo->DeviceDescriptor.iManufacturer)
583 ppszString = (char **)&pDev->pszManufacturer;
584 else if ( pConInfo->DeviceDescriptor.iProduct
585 && pDrList->iDr == pConInfo->DeviceDescriptor.iProduct)
586 ppszString = (char **)&pDev->pszProduct;
587 else if ( pConInfo->DeviceDescriptor.iSerialNumber
588 && pDrList->iDr == pConInfo->DeviceDescriptor.iSerialNumber)
589 ppszString = (char **)&pDev->pszSerialNumber;
590 if (ppszString)
591 {
592 int rc = RTUtf16ToUtf8((PCRTUTF16)pDrList->StrDr.bString, ppszString);
593 if (RT_SUCCESS(rc))
594 {
595 Assert(*ppszString);
596 USBLibPurgeEncoding(*ppszString);
597
598 if (pDrList->iDr == pConInfo->DeviceDescriptor.iSerialNumber)
599 pDev->u64SerialHash = USBLibHashSerial(*ppszString);
600 }
601 else
602 {
603 AssertMsgFailed(("RTUtf16ToUtf8 failed, rc (%d), resuming\n", rc));
604 *ppszString = NULL;
605 }
606 }
607 }
608
609 return VINF_SUCCESS;
610}
611#endif
612
613static void usbLibDevStrFree(LPSTR lpszName)
614{
615 RTStrFree(lpszName);
616}
617
618#ifndef VBOX_WITH_NEW_USB_ENUM
619static int usbLibDevStrDriverKeyGet(HANDLE hHub, ULONG iPort, LPSTR* plpszName)
620{
621 USB_NODE_CONNECTION_DRIVERKEY_NAME Name;
622 DWORD cbReturned = 0;
623 Name.ConnectionIndex = iPort;
624 *plpszName = NULL;
625 if (!DeviceIoControl(hHub, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, &Name, sizeof (Name), &Name, sizeof (Name), &cbReturned, NULL))
626 {
627#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
628 AssertMsgFailed(("DeviceIoControl 1 fail dwErr (%u)\n", GetLastError()));
629#endif
630 return VERR_GENERAL_FAILURE;
631 }
632
633 if (Name.ActualLength < sizeof (Name))
634 {
635 AssertFailed();
636 return VERR_OUT_OF_RESOURCES;
637 }
638
639 PUSB_NODE_CONNECTION_DRIVERKEY_NAME pName = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)RTMemAllocZ(Name.ActualLength);
640 if (!pName)
641 {
642 AssertFailed();
643 return VERR_OUT_OF_RESOURCES;
644 }
645
646 int rc = VINF_SUCCESS;
647 pName->ConnectionIndex = iPort;
648 if (DeviceIoControl(hHub, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, pName, Name.ActualLength, pName, Name.ActualLength, &cbReturned, NULL))
649 {
650 rc = RTUtf16ToUtf8Ex((PCRTUTF16)pName->DriverKeyName, pName->ActualLength / sizeof (WCHAR), plpszName, 0, NULL);
651 AssertRC(rc);
652 if (RT_SUCCESS(rc))
653 rc = VINF_SUCCESS;
654 }
655 else
656 {
657 DWORD dwErr = GetLastError(); NOREF(dwErr);
658 AssertMsgFailed(("DeviceIoControl 2 fail dwErr (%u)\n", dwErr));
659 rc = VERR_GENERAL_FAILURE;
660 }
661 RTMemFree(pName);
662 return rc;
663}
664#endif
665
666static int usbLibDevStrHubNameGet(HANDLE hHub, ULONG iPort, LPSTR* plpszName)
667{
668 USB_NODE_CONNECTION_NAME Name;
669 DWORD cbReturned = 0;
670 Name.ConnectionIndex = iPort;
671 *plpszName = NULL;
672 if (!DeviceIoControl(hHub, IOCTL_USB_GET_NODE_CONNECTION_NAME, &Name, sizeof (Name), &Name, sizeof (Name), &cbReturned, NULL))
673 {
674 AssertFailed();
675 return VERR_GENERAL_FAILURE;
676 }
677
678 if (Name.ActualLength < sizeof (Name))
679 {
680 AssertFailed();
681 return VERR_OUT_OF_RESOURCES;
682 }
683
684 PUSB_NODE_CONNECTION_NAME pName = (PUSB_NODE_CONNECTION_NAME)RTMemAllocZ(Name.ActualLength);
685 if (!pName)
686 {
687 AssertFailed();
688 return VERR_OUT_OF_RESOURCES;
689 }
690
691 int rc = VINF_SUCCESS;
692 pName->ConnectionIndex = iPort;
693 if (DeviceIoControl(hHub, IOCTL_USB_GET_NODE_CONNECTION_NAME, pName, Name.ActualLength, pName, Name.ActualLength, &cbReturned, NULL))
694 {
695 rc = RTUtf16ToUtf8Ex((PCRTUTF16)pName->NodeName, pName->ActualLength / sizeof (WCHAR), plpszName, 0, NULL);
696 AssertRC(rc);
697 if (RT_SUCCESS(rc))
698 rc = VINF_SUCCESS;
699 }
700 else
701 {
702 AssertFailed();
703 rc = VERR_GENERAL_FAILURE;
704 }
705 RTMemFree(pName);
706 return rc;
707}
708
709static int usbLibDevStrRootHubNameGet(HANDLE hCtl, LPSTR* plpszName)
710{
711 USB_ROOT_HUB_NAME HubName;
712 DWORD cbReturned = 0;
713 *plpszName = NULL;
714 if (!DeviceIoControl(hCtl, IOCTL_USB_GET_ROOT_HUB_NAME, NULL, 0, &HubName, sizeof (HubName), &cbReturned, NULL))
715 {
716 return VERR_GENERAL_FAILURE;
717 }
718 PUSB_ROOT_HUB_NAME pHubName = (PUSB_ROOT_HUB_NAME)RTMemAllocZ(HubName.ActualLength);
719 if (!pHubName)
720 return VERR_OUT_OF_RESOURCES;
721
722 int rc = VINF_SUCCESS;
723 if (DeviceIoControl(hCtl, IOCTL_USB_GET_ROOT_HUB_NAME, NULL, 0, pHubName, HubName.ActualLength, &cbReturned, NULL))
724 {
725 rc = RTUtf16ToUtf8Ex((PCRTUTF16)pHubName->RootHubName, pHubName->ActualLength / sizeof (WCHAR), plpszName, 0, NULL);
726 AssertRC(rc);
727 if (RT_SUCCESS(rc))
728 rc = VINF_SUCCESS;
729 }
730 else
731 {
732 rc = VERR_GENERAL_FAILURE;
733 }
734 RTMemFree(pHubName);
735 return rc;
736}
737
738static int usbLibDevCfgDrGet(HANDLE hHub, LPCSTR lpcszHubName, ULONG iPort, ULONG iDr, PUSB_CONFIGURATION_DESCRIPTOR *ppDr)
739{
740 *ppDr = NULL;
741
742 char Buf[sizeof (USB_DESCRIPTOR_REQUEST) + sizeof (USB_CONFIGURATION_DESCRIPTOR)];
743 memset(&Buf, 0, sizeof (Buf));
744
745 PUSB_DESCRIPTOR_REQUEST pCfgDrRq = (PUSB_DESCRIPTOR_REQUEST)Buf;
746 PUSB_CONFIGURATION_DESCRIPTOR pCfgDr = (PUSB_CONFIGURATION_DESCRIPTOR)(Buf + sizeof (*pCfgDrRq));
747
748 pCfgDrRq->ConnectionIndex = iPort;
749 pCfgDrRq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | iDr;
750 pCfgDrRq->SetupPacket.wLength = (USHORT)(sizeof (USB_CONFIGURATION_DESCRIPTOR));
751 DWORD cbReturned = 0;
752 if (!DeviceIoControl(hHub, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, pCfgDrRq, sizeof (Buf),
753 pCfgDrRq, sizeof (Buf),
754 &cbReturned, NULL))
755 {
756 DWORD dwErr = GetLastError();
757 LogRelFunc(("IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION #1 failed (dwErr=%u) on hub %s port %d\n", dwErr, lpcszHubName, iPort));
758#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
759 AssertFailed();
760#endif
761 return VERR_GENERAL_FAILURE;
762 }
763
764 if (sizeof (Buf) != cbReturned)
765 {
766 AssertFailed();
767 return VERR_GENERAL_FAILURE;
768 }
769
770 if (pCfgDr->wTotalLength < sizeof (USB_CONFIGURATION_DESCRIPTOR))
771 {
772 AssertFailed();
773 return VERR_GENERAL_FAILURE;
774 }
775
776 DWORD cbRq = sizeof (USB_DESCRIPTOR_REQUEST) + pCfgDr->wTotalLength;
777 PUSB_DESCRIPTOR_REQUEST pRq = (PUSB_DESCRIPTOR_REQUEST)RTMemAllocZ(cbRq);
778 Assert(pRq);
779 if (!pRq)
780 return VERR_OUT_OF_RESOURCES;
781
782 int rc = VERR_GENERAL_FAILURE;
783 do
784 {
785 PUSB_CONFIGURATION_DESCRIPTOR pDr = (PUSB_CONFIGURATION_DESCRIPTOR)(pRq + 1);
786 pRq->ConnectionIndex = iPort;
787 pRq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | iDr;
788 pRq->SetupPacket.wLength = (USHORT)(cbRq - sizeof (USB_DESCRIPTOR_REQUEST));
789 if (!DeviceIoControl(hHub, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, pRq, cbRq,
790 pRq, cbRq,
791 &cbReturned, NULL))
792 {
793 DWORD dwErr = GetLastError();
794 LogRelFunc(("IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION #2 failed (dwErr=%u) on hub %s port %d\n", dwErr, lpcszHubName, iPort));
795#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
796 AssertFailed();
797#endif
798 break;
799 }
800
801 if (cbRq != cbReturned)
802 {
803 AssertFailed();
804 break;
805 }
806
807 if (pDr->wTotalLength != cbRq - sizeof (USB_DESCRIPTOR_REQUEST))
808 {
809 AssertFailed();
810 break;
811 }
812
813 *ppDr = pDr;
814 return VINF_SUCCESS;
815 } while (0);
816
817 RTMemFree(pRq);
818 return rc;
819}
820
821static void usbLibDevCfgDrFree(PUSB_CONFIGURATION_DESCRIPTOR pDr)
822{
823 Assert(pDr);
824 PUSB_DESCRIPTOR_REQUEST pRq = ((PUSB_DESCRIPTOR_REQUEST)pDr)-1;
825 RTMemFree(pRq);
826}
827
828static int usbLibDevStrDrEntryGet(HANDLE hHub, LPCSTR lpcszHubName, ULONG iPort, ULONG iDr, USHORT idLang, PVBOXUSB_STRING_DR_ENTRY *ppList)
829{
830 char szBuf[sizeof (USB_DESCRIPTOR_REQUEST) + MAXIMUM_USB_STRING_LENGTH];
831 RT_ZERO(szBuf);
832
833 PUSB_DESCRIPTOR_REQUEST pRq = (PUSB_DESCRIPTOR_REQUEST)szBuf;
834 PUSB_STRING_DESCRIPTOR pDr = (PUSB_STRING_DESCRIPTOR)(szBuf + sizeof (*pRq));
835 RT_BZERO(pDr, sizeof(USB_STRING_DESCRIPTOR));
836
837 pRq->ConnectionIndex = iPort;
838 pRq->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) | iDr;
839 pRq->SetupPacket.wIndex = idLang;
840 pRq->SetupPacket.wLength = sizeof (szBuf) - sizeof (*pRq);
841
842 DWORD cbReturned = 0;
843 if (!DeviceIoControl(hHub, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, pRq, sizeof (szBuf),
844 pRq, sizeof(szBuf),
845 &cbReturned, NULL))
846 {
847 DWORD dwErr = GetLastError();
848 LogRel(("Getting USB descriptor (id %u) failed (dwErr=%u) on hub %s port %d\n", iDr, dwErr, lpcszHubName, iPort));
849 return RTErrConvertFromWin32(dwErr);
850 }
851
852 /* Wrong descriptor type at the requested port index? Bail out. */
853 if (pDr->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE)
854 return VERR_NOT_FOUND;
855
856 /* Some more sanity checks. */
857 if ( (cbReturned < sizeof (*pDr) + 2)
858 || (!!(pDr->bLength % 2))
859 || (pDr->bLength != cbReturned - sizeof(*pRq)))
860 {
861 AssertMsgFailed(("Sanity check failed for string descriptor: cbReturned=%RI32, cbDevReq=%zu, type=%RU8, len=%RU8, port=%RU32, index=%RU32, lang=%RU32\n",
862 cbReturned, sizeof(*pRq), pDr->bDescriptorType, pDr->bLength, iPort, iDr, idLang));
863 return VERR_INVALID_PARAMETER;
864 }
865
866 PVBOXUSB_STRING_DR_ENTRY pEntry =
867 (PVBOXUSB_STRING_DR_ENTRY)RTMemAllocZ(sizeof(VBOXUSB_STRING_DR_ENTRY) + pDr->bLength + 2);
868 AssertPtr(pEntry);
869 if (!pEntry)
870 return VERR_NO_MEMORY;
871
872 pEntry->pNext = *ppList;
873 pEntry->iDr = iDr;
874 pEntry->idLang = idLang;
875 memcpy(&pEntry->StrDr, pDr, pDr->bLength);
876
877 *ppList = pEntry;
878
879 return VINF_SUCCESS;
880}
881
882static void usbLibDevStrDrEntryFree(PVBOXUSB_STRING_DR_ENTRY pDr)
883{
884 RTMemFree(pDr);
885}
886
887static void usbLibDevStrDrEntryFreeList(PVBOXUSB_STRING_DR_ENTRY pDr)
888{
889 while (pDr)
890 {
891 PVBOXUSB_STRING_DR_ENTRY pNext = pDr->pNext;
892 usbLibDevStrDrEntryFree(pDr);
893 pDr = pNext;
894 }
895}
896
897static int usbLibDevStrDrEntryGetForLangs(HANDLE hHub, LPCSTR lpcszHubName, ULONG iPort, ULONG iDr, ULONG cIdLang, const USHORT *pIdLang, PVBOXUSB_STRING_DR_ENTRY *ppList)
898{
899 for (ULONG i = 0; i < cIdLang; ++i)
900 {
901 usbLibDevStrDrEntryGet(hHub, lpcszHubName, iPort, iDr, pIdLang[i], ppList);
902 }
903 return VINF_SUCCESS;
904}
905
906static int usbLibDevStrDrEntryGetAll(HANDLE hHub, LPCSTR lpcszHubName, ULONG iPort, PUSB_DEVICE_DESCRIPTOR pDevDr, PUSB_CONFIGURATION_DESCRIPTOR pCfgDr, PVBOXUSB_STRING_DR_ENTRY *ppList)
907{
908 /* Read string descriptor zero to determine what languages are available. */
909 int rc = usbLibDevStrDrEntryGet(hHub, lpcszHubName, iPort, 0, 0, ppList);
910 if (RT_FAILURE(rc))
911 return rc;
912
913 PUSB_STRING_DESCRIPTOR pLangStrDr = &(*ppList)->StrDr;
914 USHORT *pIdLang = pLangStrDr->bString;
915 ULONG cIdLang = (pLangStrDr->bLength - RT_OFFSETOF(USB_STRING_DESCRIPTOR, bString)) / sizeof (*pIdLang);
916
917 if (pDevDr->iManufacturer)
918 {
919 rc = usbLibDevStrDrEntryGetForLangs(hHub, lpcszHubName, iPort, pDevDr->iManufacturer, cIdLang, pIdLang, ppList);
920 AssertRC(rc);
921 }
922
923 if (pDevDr->iProduct)
924 {
925 rc = usbLibDevStrDrEntryGetForLangs(hHub, lpcszHubName, iPort, pDevDr->iProduct, cIdLang, pIdLang, ppList);
926 AssertRC(rc);
927 }
928
929 if (pDevDr->iSerialNumber)
930 {
931 rc = usbLibDevStrDrEntryGetForLangs(hHub, lpcszHubName, iPort, pDevDr->iSerialNumber, cIdLang, pIdLang, ppList);
932 AssertRC(rc);
933 }
934
935 PUCHAR pCur = (PUCHAR)pCfgDr;
936 PUCHAR pEnd = pCur + pCfgDr->wTotalLength;
937 while (pCur + sizeof (USB_COMMON_DESCRIPTOR) <= pEnd)
938 {
939 PUSB_COMMON_DESCRIPTOR pCmnDr = (PUSB_COMMON_DESCRIPTOR)pCur;
940 if (pCur + pCmnDr->bLength > pEnd)
941 {
942 AssertFailed();
943 break;
944 }
945
946 /* This is invalid but was seen with a TerraTec Aureon 7.1 USB sound card. */
947 if (!pCmnDr->bLength)
948 break;
949
950 switch (pCmnDr->bDescriptorType)
951 {
952 case USB_CONFIGURATION_DESCRIPTOR_TYPE:
953 {
954 if (pCmnDr->bLength != sizeof (USB_CONFIGURATION_DESCRIPTOR))
955 {
956 AssertFailed();
957 break;
958 }
959 PUSB_CONFIGURATION_DESCRIPTOR pCurCfgDr = (PUSB_CONFIGURATION_DESCRIPTOR)pCmnDr;
960 if (!pCurCfgDr->iConfiguration)
961 break;
962 rc = usbLibDevStrDrEntryGetForLangs(hHub, lpcszHubName, iPort, pCurCfgDr->iConfiguration, cIdLang, pIdLang, ppList);
963 AssertRC(rc);
964 break;
965 }
966 case USB_INTERFACE_DESCRIPTOR_TYPE:
967 {
968 if (pCmnDr->bLength != sizeof (USB_INTERFACE_DESCRIPTOR) && pCmnDr->bLength != sizeof (USB_INTERFACE_DESCRIPTOR2))
969 {
970 AssertFailed();
971 break;
972 }
973 PUSB_INTERFACE_DESCRIPTOR pCurIfDr = (PUSB_INTERFACE_DESCRIPTOR)pCmnDr;
974 if (!pCurIfDr->iInterface)
975 break;
976 rc = usbLibDevStrDrEntryGetForLangs(hHub, lpcszHubName, iPort, pCurIfDr->iInterface, cIdLang, pIdLang, ppList);
977 AssertRC(rc);
978 break;
979 }
980 default:
981 break;
982 }
983
984 pCur = pCur + pCmnDr->bLength;
985 }
986
987 return VINF_SUCCESS;
988}
989
990#ifndef VBOX_WITH_NEW_USB_ENUM
991static int usbLibDevGetHubDevices(LPCSTR lpszName, PUSBDEVICE *ppDevs, uint32_t *pcDevs);
992
993static int usbLibDevGetHubPortDevices(HANDLE hHub, LPCSTR lpcszHubName, ULONG iPort, PUSBDEVICE *ppDevs, uint32_t *pcDevs)
994{
995 int rc = VINF_SUCCESS;
996 char Buf[sizeof (USB_NODE_CONNECTION_INFORMATION_EX) + (sizeof (USB_PIPE_INFO) * 20)];
997 PUSB_NODE_CONNECTION_INFORMATION_EX pConInfo = (PUSB_NODE_CONNECTION_INFORMATION_EX)Buf;
998 //PUSB_PIPE_INFO paPipeInfo = (PUSB_PIPE_INFO)(Buf + sizeof (PUSB_NODE_CONNECTION_INFORMATION_EX));
999 DWORD cbReturned = 0;
1000 memset(&Buf, 0, sizeof (Buf));
1001 pConInfo->ConnectionIndex = iPort;
1002 if (!DeviceIoControl(hHub, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
1003 pConInfo, sizeof (Buf),
1004 pConInfo, sizeof (Buf),
1005 &cbReturned, NULL))
1006 {
1007 DWORD dwErr = GetLastError(); NOREF(dwErr);
1008 LogRel(("Getting USB connection information failed (dwErr=%u) on hub %s\n", dwErr, lpcszHubName));
1009 AssertMsg(dwErr == ERROR_DEVICE_NOT_CONNECTED, (__FUNCTION__": DeviceIoControl failed (dwErr=%u)\n", dwErr));
1010 return VERR_GENERAL_FAILURE;
1011 }
1012
1013 if (pConInfo->ConnectionStatus != DeviceConnected)
1014 {
1015 /* just ignore & return success */
1016 return VWRN_INVALID_HANDLE;
1017 }
1018
1019 if (pConInfo->DeviceIsHub)
1020 {
1021 LPSTR lpszChildHubName = NULL;
1022 rc = usbLibDevStrHubNameGet(hHub, iPort, &lpszChildHubName);
1023 AssertRC(rc);
1024 if (RT_SUCCESS(rc))
1025 {
1026 rc = usbLibDevGetHubDevices(lpszChildHubName, ppDevs, pcDevs);
1027 usbLibDevStrFree(lpszChildHubName);
1028 AssertRC(rc);
1029 return rc;
1030 }
1031 /* ignore this err */
1032 return VINF_SUCCESS;
1033 }
1034
1035 bool fFreeNameBuf = true;
1036 char nameEmptyBuf = '\0';
1037 LPSTR lpszName = NULL;
1038 rc = usbLibDevStrDriverKeyGet(hHub, iPort, &lpszName);
1039 Assert(!!lpszName == !!RT_SUCCESS(rc));
1040 if (!lpszName)
1041 {
1042 LogRelFunc(("No DriverKey on hub %s port %d\n", lpcszHubName, iPort));
1043 lpszName = &nameEmptyBuf;
1044 fFreeNameBuf = false;
1045 }
1046
1047 PUSB_CONFIGURATION_DESCRIPTOR pCfgDr = NULL;
1048 PVBOXUSB_STRING_DR_ENTRY pList = NULL;
1049 rc = usbLibDevCfgDrGet(hHub, lpcszHubName, iPort, 0, &pCfgDr);
1050 if (pCfgDr)
1051 {
1052 rc = usbLibDevStrDrEntryGetAll(hHub, lpcszHubName, iPort, &pConInfo->DeviceDescriptor, pCfgDr, &pList);
1053#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1054 AssertRC(rc); // this can fail if device suspended
1055#endif
1056 }
1057
1058 PUSBDEVICE pDev = (PUSBDEVICE)RTMemAllocZ(sizeof (*pDev));
1059 if (RT_LIKELY(pDev))
1060 {
1061 rc = usbLibDevPopulate(pDev, pConInfo, iPort, lpszName, lpcszHubName, pList);
1062 if (RT_SUCCESS(rc))
1063 {
1064 pDev->pNext = *ppDevs;
1065 *ppDevs = pDev;
1066 ++*pcDevs;
1067 }
1068 else
1069 RTMemFree(pDev);
1070 }
1071 else
1072 rc = VERR_NO_MEMORY;
1073
1074 if (pCfgDr)
1075 usbLibDevCfgDrFree(pCfgDr);
1076 if (fFreeNameBuf)
1077 {
1078 Assert(lpszName);
1079 usbLibDevStrFree(lpszName);
1080 }
1081 if (pList)
1082 usbLibDevStrDrEntryFreeList(pList);
1083
1084 return rc;
1085}
1086
1087static int usbLibDevGetHubDevices(LPCSTR lpszName, PUSBDEVICE *ppDevs, uint32_t *pcDevs)
1088{
1089 LPSTR lpszDevName = (LPSTR)RTMemAllocZ(strlen(lpszName) + sizeof("\\\\.\\"));
1090 HANDLE hDev = INVALID_HANDLE_VALUE;
1091 Assert(lpszDevName);
1092 if (!lpszDevName)
1093 {
1094 AssertFailed();
1095 return VERR_OUT_OF_RESOURCES;
1096 }
1097
1098 int rc = VINF_SUCCESS;
1099 strcpy(lpszDevName, "\\\\.\\");
1100 strcpy(lpszDevName + sizeof("\\\\.\\") - sizeof (lpszDevName[0]), lpszName);
1101 do
1102 {
1103 DWORD cbReturned = 0;
1104 hDev = CreateFile(lpszDevName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
1105 if (hDev == INVALID_HANDLE_VALUE)
1106 {
1107 AssertFailed();
1108 break;
1109 }
1110
1111 USB_NODE_INFORMATION NodeInfo;
1112 memset(&NodeInfo, 0, sizeof (NodeInfo));
1113 if (!DeviceIoControl(hDev, IOCTL_USB_GET_NODE_INFORMATION,
1114 &NodeInfo, sizeof (NodeInfo),
1115 &NodeInfo, sizeof (NodeInfo),
1116 &cbReturned, NULL))
1117 {
1118 LogRel(("Getting USB node information failed (dwErr=%u) on hub %s\n", GetLastError(), lpszName));
1119 AssertFailed();
1120 break;
1121 }
1122
1123 for (ULONG i = 1; i <= NodeInfo.u.HubInformation.HubDescriptor.bNumberOfPorts; ++i)
1124 {
1125 /* Just skip devices for which we failed to create the device structure. */
1126 usbLibDevGetHubPortDevices(hDev, lpszName, i, ppDevs, pcDevs);
1127 }
1128 } while (0);
1129
1130 if (hDev != INVALID_HANDLE_VALUE)
1131 CloseHandle(hDev);
1132
1133 RTMemFree(lpszDevName);
1134
1135 return rc;
1136}
1137#endif
1138
1139#ifdef VBOX_WITH_NEW_USB_ENUM
1140
1141/* Get a registry property for a device given its HDEVINFO + SP_DEVINFO_DATA. */
1142static void *usbLibGetRegistryProperty(HDEVINFO InfoSet, const PSP_DEVINFO_DATA DevData, DWORD Property)
1143{
1144 BOOL rc;
1145 DWORD dwReqLen;
1146 void *PropertyData;
1147
1148 /* How large a buffer do we need? */
1149 rc = SetupDiGetDeviceRegistryProperty(InfoSet, DevData, Property,
1150 NULL, NULL, 0, &dwReqLen);
1151 if (!rc && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
1152 {
1153 LogRelFunc(("Failed to query buffer size, error %ld\n", GetLastError()));
1154 return NULL;
1155 }
1156
1157 PropertyData = RTMemAlloc(dwReqLen);
1158 if (!PropertyData)
1159 return NULL;
1160
1161 /* Get the actual property data. */
1162 rc = SetupDiGetDeviceRegistryProperty(InfoSet, DevData, Property,
1163 NULL, (PBYTE)PropertyData, dwReqLen, &dwReqLen);
1164 if (!rc)
1165 {
1166 LogRelFunc(("Failed to get property data, error %ld\n", GetLastError()));
1167 RTMemFree(PropertyData);
1168 return NULL;
1169 }
1170 return PropertyData;
1171}
1172
1173/* Given a HDEVINFO and SP_DEVICE_INTERFACE_DATA, get the interface detail data and optionally device info data. */
1174static PSP_DEVICE_INTERFACE_DETAIL_DATA usbLibGetDevDetail(HDEVINFO InfoSet, PSP_DEVICE_INTERFACE_DATA InterfaceData, PSP_DEVINFO_DATA DevInfoData)
1175{
1176 BOOL rc;
1177 DWORD dwReqLen;
1178 PSP_DEVICE_INTERFACE_DETAIL_DATA DetailData;
1179
1180 rc = SetupDiGetDeviceInterfaceDetail(InfoSet, InterfaceData, NULL, 0, &dwReqLen, DevInfoData);
1181 if (!rc && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
1182 {
1183 LogRelFunc(("Failed to get interface detail size, error %ld\n", GetLastError()));
1184 return NULL;
1185 }
1186
1187 DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)RTMemAlloc(dwReqLen);
1188 if (!DetailData)
1189 return NULL;
1190
1191 memset(DetailData, 0, dwReqLen);
1192 DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
1193
1194 rc = SetupDiGetDeviceInterfaceDetail(InfoSet, InterfaceData, DetailData, dwReqLen, &dwReqLen, DevInfoData);
1195 if (!rc)
1196 {
1197 LogRelFunc(("Failed to get interface detail, error %ld\n", GetLastError()));
1198 RTMemFree(DetailData);
1199 }
1200
1201 return DetailData;
1202}
1203
1204/* Given a hub's PnP device instance, find its device path (file name). */
1205static LPCSTR usbLibGetHubPathFromInstanceID(LPCSTR InstanceID)
1206{
1207 HDEVINFO InfoSet;
1208 SP_DEVICE_INTERFACE_DATA InterfaceData;
1209 PSP_DEVICE_INTERFACE_DETAIL_DATA DetailData;
1210 BOOL rc;
1211 LPSTR DevicePath = NULL;
1212
1213 /* Enumerate the DevInst's USB hub interface. */
1214 InfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_HUB, InstanceID, NULL,
1215 DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
1216 if (InfoSet == INVALID_HANDLE_VALUE)
1217 {
1218 LogRelFunc(("Failed to get interface for InstID %se, error %ld\n", InstanceID, GetLastError()));
1219 return NULL;
1220 }
1221
1222 memset(&InterfaceData, 0, sizeof(InterfaceData));
1223 InterfaceData.cbSize = sizeof(InterfaceData);
1224 rc = SetupDiEnumDeviceInterfaces(InfoSet, 0, &GUID_DEVINTERFACE_USB_HUB, 0, &InterfaceData);
1225 if (!rc)
1226 {
1227 DWORD dwErr = GetLastError();
1228
1229 /* The parent device might not be a hub; that is valid, ignore such errors. */
1230 if (dwErr != ERROR_NO_MORE_ITEMS)
1231 LogRelFunc(("Failed to get interface data for InstID %s, error %ld\n", InstanceID, dwErr));
1232 SetupDiDestroyDeviceInfoList(InfoSet);
1233 return NULL;
1234 }
1235
1236 DetailData = usbLibGetDevDetail(InfoSet, &InterfaceData, NULL);
1237 if (!DetailData)
1238 {
1239 SetupDiDestroyDeviceInfoList(InfoSet);
1240 return NULL;
1241 }
1242
1243 /* Copy the device path out of the interface detail. */
1244 DevicePath = RTStrDup(DetailData->DevicePath);
1245 RTMemFree(DetailData);
1246 SetupDiDestroyDeviceInfoList(InfoSet);
1247
1248 return DevicePath;
1249}
1250
1251
1252/* Use the Configuration Manager (CM) to get a devices's parent given its DEVINST and
1253 * turn it into a PnP device instance ID string.
1254 */
1255static LPCSTR usbLibGetParentInstanceID(DEVINST DevInst)
1256{
1257 LPSTR InstanceID;
1258 DEVINST ParentInst;
1259 ULONG ulReqChars;
1260 ULONG ulReqBytes;
1261 CONFIGRET cr;
1262
1263 /* First get the parent DEVINST. */
1264 cr = CM_Get_Parent(&ParentInst, DevInst, 0);
1265 if (cr != CR_SUCCESS)
1266 {
1267 LogRelFunc(("Failed to get parent instance, error %ld\n", GetLastError()));
1268 return NULL;
1269 }
1270
1271 /* Then convert it to the instance ID string. */
1272 cr = CM_Get_Device_ID_Size(&ulReqChars, ParentInst, 0);
1273 if (cr != CR_SUCCESS)
1274 {
1275 LogRelFunc(("Failed to get device ID size (DevInst=%X), error %ld\n", DevInst, GetLastError()));
1276 return NULL;
1277 }
1278
1279 /* CM_Get_Device_ID_Size gives us the size in characters without terminating null. */
1280 ulReqBytes = (ulReqChars + 1) * sizeof(char);
1281 InstanceID = (LPSTR)RTMemAlloc(ulReqBytes);
1282 if (!InstanceID)
1283 return NULL;
1284
1285 cr = CM_Get_Device_ID(ParentInst, InstanceID, ulReqBytes, 0);
1286 if (cr != CR_SUCCESS)
1287 {
1288 LogRelFunc(("Failed to get device ID (DevInst=%X), error %ld\n", DevInst, GetLastError()));
1289 RTMemFree(InstanceID);
1290 return NULL;
1291 }
1292
1293 return InstanceID;
1294}
1295
1296/* Process a single USB device that's being enumerated and grab its hub-specific data. */
1297static int usbLibDevGetDevice(LPCSTR lpcszHubFile, ULONG iPort, LPCSTR lpcszLocation, LPCSTR lpcszDriverKey, PUSBDEVICE *ppDevs, uint32_t *pcDevs)
1298{
1299 HANDLE HubDevice;
1300 BYTE abConBuf[sizeof(USB_NODE_CONNECTION_INFORMATION_EX)];
1301 PUSB_NODE_CONNECTION_INFORMATION_EX pConInfo = PUSB_NODE_CONNECTION_INFORMATION_EX(abConBuf);
1302 int rc = VINF_SUCCESS;
1303 DWORD cbReturned = 0;
1304
1305 /* Validate inputs. */
1306 if ((iPort < 1) || (iPort > 255))
1307 {
1308 LogRelFunc(("Port index out of range (%u)\n", iPort));
1309 return VERR_INVALID_PARAMETER;
1310 }
1311 if (!lpcszHubFile)
1312 {
1313 LogRelFunc(("Hub path is NULL!\n"));
1314 return VERR_INVALID_PARAMETER;
1315 }
1316 if (!lpcszLocation)
1317 {
1318 LogRelFunc(("Location NULL!\n"));
1319 return VERR_INVALID_PARAMETER;
1320 }
1321
1322 /* Try opening the hub file so we can send IOCTLs to it. */
1323 HubDevice = CreateFile(lpcszHubFile, GENERIC_WRITE, FILE_SHARE_WRITE,
1324 NULL, OPEN_EXISTING, 0, NULL);
1325 if (HubDevice == INVALID_HANDLE_VALUE)
1326 {
1327 LogRelFunc(("Failed to open hub `%s' (dwErr=%u)\n", lpcszHubFile, GetLastError()));
1328 return VERR_FILE_NOT_FOUND;
1329 }
1330
1331 /* The shenanigans with abConBuf are due to USB_NODE_CONNECTION_INFORMATION_EX
1332 * containing a zero-sized array, triggering compiler warnings.
1333 */
1334 memset(pConInfo, 0, sizeof(abConBuf));
1335 pConInfo->ConnectionIndex = iPort;
1336
1337 /* We expect that IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX is always available
1338 * on any supported Windows version and hardware.
1339 * NB: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 is Win8 and later only.
1340 */
1341 if (!DeviceIoControl(HubDevice, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
1342 pConInfo, sizeof(abConBuf), pConInfo, sizeof(abConBuf),
1343 &cbReturned, NULL))
1344 {
1345 DWORD dwErr = GetLastError(); NOREF(dwErr);
1346 LogRel(("IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX failed (dwErr=%u) on hub %s, port %d\n", dwErr, lpcszHubFile, iPort));
1347 AssertMsg(dwErr == ERROR_DEVICE_NOT_CONNECTED, (__FUNCTION__": DeviceIoControl failed dwErr (%u)\n", dwErr));
1348 CloseHandle(HubDevice);
1349 return VERR_GENERAL_FAILURE;
1350 }
1351
1352 if (pConInfo->ConnectionStatus != DeviceConnected)
1353 {
1354 /* Ignore this, can't do anything with it. */
1355 LogFunc(("Device is not connected, skipping.\n"));
1356 CloseHandle(HubDevice);
1357 return VINF_SUCCESS;
1358 }
1359
1360 if (pConInfo->DeviceIsHub)
1361 {
1362 /* We're ignoring hubs, just skip this. */
1363 LogFunc(("Device is a hub, skipping.\n"));
1364 CloseHandle(HubDevice);
1365 return VINF_SUCCESS;
1366 }
1367
1368 PUSB_CONFIGURATION_DESCRIPTOR pCfgDr = NULL;
1369 PVBOXUSB_STRING_DR_ENTRY pList = NULL;
1370 rc = usbLibDevCfgDrGet(HubDevice, lpcszHubFile, iPort, 0, &pCfgDr);
1371 if (pCfgDr)
1372 {
1373 rc = usbLibDevStrDrEntryGetAll(HubDevice, lpcszHubFile, iPort, &pConInfo->DeviceDescriptor, pCfgDr, &pList);
1374#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1375 AssertRC(rc); // this can fail if device suspended
1376#endif
1377 }
1378
1379 /* At this point we're done with the hub device. */
1380 CloseHandle(HubDevice);
1381
1382 PUSBDEVICE pDev = (PUSBDEVICE)RTMemAllocZ(sizeof (*pDev));
1383 if (RT_LIKELY(pDev))
1384 {
1385 rc = usbLibDevPopulate(pDev, pConInfo, iPort, lpcszLocation, lpcszDriverKey, lpcszHubFile, pList);
1386 if (RT_SUCCESS(rc))
1387 {
1388 pDev->pNext = *ppDevs;
1389 *ppDevs = pDev;
1390 ++*pcDevs;
1391 }
1392 else
1393 RTMemFree(pDev);
1394 }
1395 else
1396 rc = VERR_NO_MEMORY;
1397
1398 if (pCfgDr)
1399 usbLibDevCfgDrFree(pCfgDr);
1400 if (pList)
1401 usbLibDevStrDrEntryFreeList(pList);
1402
1403 return rc;
1404}
1405
1406
1407/*
1408 * Enumerate the USB devices in the host system. Since we do not care about the hierarchical
1409 * structure of root hubs, other hubs, and devices, we just ask the USB PnP enumerator to
1410 * give us all it has. This includes hubs (though not root hubs), as well as multiple child
1411 * interfaces of multi-interface USB devices, which we filter out. It also includes USB
1412 * devices with no driver, which is notably something we cannot get by enumerating via
1413 * GUID_DEVINTERFACE_USB_DEVICE.
1414 *
1415 * This approach also saves us some trouble relative to enumerating devices via hub IOCTLs and
1416 * then hunting through the PnP manager to find them. Instead, we look up the device's parent
1417 * which (for devices we're interested in) is always a hub, and that allows us to obtain
1418 * USB-specific data (descriptors, speeds, etc.) when combined with the devices PnP "address"
1419 * (USB port on parent hub).
1420 *
1421 * NB: Every USB device known to the Windows PnP Manager will have a device instance ID. Typically
1422 * it also has a DriverKey but only if it has a driver installed. Hence we ignore the DriverKey, at
1423 * least prior to capturing (once VBoxUSB.sys is installed, a DriverKey must by definition be
1424 * present). Also note that the device instance ID changes for captured devices since we change
1425 * their USB VID/PID, though it is unique at any given point.
1426 *
1427 * The location information should be a reliable way of identifying a device and does not change
1428 * with driver installs, capturing, etc. USB device location information is only available on
1429 * Windows Vista and later; earlier Windows version had no reliable way of cross-referencing the
1430 * USB IOCTL and PnP Manager data.
1431 */
1432static int usbLibEnumDevices(PUSBDEVICE *ppDevs, uint32_t *pcDevs)
1433{
1434 HDEVINFO InfoSet;
1435 DWORD DeviceIndex;
1436 LPDWORD Address;
1437 SP_DEVINFO_DATA DeviceData;
1438 LPCSTR ParentInstID;
1439 LPCSTR HubPath = NULL;
1440 LPCSTR Location;
1441 LPCSTR DriverKey;
1442
1443 /* Ask the USB PnP enumerator for all it has. */
1444 InfoSet = SetupDiGetClassDevs(NULL, "USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
1445
1446 memset(&DeviceData, 0, sizeof(DeviceData));
1447 DeviceData.cbSize = sizeof(DeviceData);
1448 DeviceIndex = 0;
1449
1450 /* Enumerate everything in the info set. */
1451 while (SetupDiEnumDeviceInfo(InfoSet, DeviceIndex, &DeviceData))
1452 {
1453 /* Use the CM API to get the parent instance ID. */
1454 ParentInstID = usbLibGetParentInstanceID(DeviceData.DevInst);
1455
1456 /* Now figure out the hub's file path fron the instance ID, if there is one. */
1457 if (ParentInstID)
1458 HubPath = usbLibGetHubPathFromInstanceID(ParentInstID);
1459
1460 /* If there's no hub interface on the parent, then this might be a child
1461 * device of a multi-interface device. Either way, we're not interested.
1462 */
1463 if (HubPath)
1464 {
1465 /* The location information uniquely identifies the USB device, (hub/port). */
1466 Location = (LPCSTR)usbLibGetRegistryProperty(InfoSet, &DeviceData, SPDRP_LOCATION_PATHS);
1467
1468 /* The software key aka DriverKey. This will be NULL for devices with no driver
1469 * and allows us to distinguish between 'busy' (driver installed) and 'available'
1470 * (no driver) devices.
1471 */
1472 DriverKey = (LPCSTR)usbLibGetRegistryProperty(InfoSet, &DeviceData, SPDRP_DRIVER);
1473
1474 /* The device's PnP Manager "address" is the port number on the parent hub. */
1475 Address = (LPDWORD)usbLibGetRegistryProperty(InfoSet, &DeviceData, SPDRP_ADDRESS);
1476 if (Address && Location) /* NB: DriverKey may be NULL! */
1477 {
1478 usbLibDevGetDevice(HubPath, *Address, Location, DriverKey, ppDevs, pcDevs);
1479 }
1480 RTMemFree((void *)HubPath);
1481
1482 if (Location)
1483 RTMemFree((void *)Location);
1484 if (DriverKey)
1485 RTMemFree((void *)DriverKey);
1486 if (Address)
1487 RTMemFree((void *)Address);
1488 }
1489
1490 /* Clean up after this device. */
1491 if (ParentInstID)
1492 RTMemFree((void *)ParentInstID);
1493
1494 ++DeviceIndex;
1495 memset(&DeviceData, 0, sizeof(DeviceData));
1496 DeviceData.cbSize = sizeof(DeviceData);
1497 }
1498
1499 if (InfoSet)
1500 SetupDiDestroyDeviceInfoList(InfoSet);
1501
1502 return VINF_SUCCESS;
1503}
1504
1505#else
1506static int usbLibDevGetDevices(PUSBDEVICE *ppDevs, uint32_t *pcDevs)
1507{
1508 char CtlName[16];
1509 int rc = VINF_SUCCESS;
1510
1511 for (int i = 0; i < 10; ++i)
1512 {
1513 RTStrPrintf(CtlName, sizeof(CtlName), "\\\\.\\HCD%d", i);
1514 HANDLE hCtl = CreateFile(CtlName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
1515 if (hCtl != INVALID_HANDLE_VALUE)
1516 {
1517 char* lpszName;
1518 rc = usbLibDevStrRootHubNameGet(hCtl, &lpszName);
1519 AssertRC(rc);
1520 if (RT_SUCCESS(rc))
1521 {
1522 rc = usbLibDevGetHubDevices(lpszName, ppDevs, pcDevs);
1523 AssertRC(rc);
1524 usbLibDevStrFree(lpszName);
1525 }
1526 CloseHandle(hCtl);
1527 if (RT_FAILURE(rc))
1528 break;
1529 }
1530 }
1531 return VINF_SUCCESS;
1532}
1533#endif
1534
1535static int usbLibMonDevicesCmp(PUSBDEVICE pDev, PVBOXUSB_DEV pDevInfo)
1536{
1537 int iDiff;
1538 iDiff = strcmp(pDev->pszAddress, pDevInfo->szDriverRegName);
1539 return iDiff;
1540}
1541
1542static int usbLibMonDevicesUpdate(PVBOXUSBGLOBALSTATE pGlobal, PUSBDEVICE pDevs, PVBOXUSB_DEV pDevInfos)
1543{
1544
1545 PUSBDEVICE pDevsHead = pDevs;
1546 for (; pDevInfos; pDevInfos = pDevInfos->pNext)
1547 {
1548 for (pDevs = pDevsHead; pDevs; pDevs = pDevs->pNext)
1549 {
1550 if (usbLibMonDevicesCmp(pDevs, pDevInfos))
1551 continue;
1552
1553 if (!pDevInfos->szDriverRegName[0])
1554 {
1555 AssertFailed();
1556 break;
1557 }
1558
1559 USBSUP_GETDEV Dev = {0};
1560 HANDLE hDev = CreateFile(pDevInfos->szName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
1561 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
1562 if (hDev == INVALID_HANDLE_VALUE)
1563 {
1564 AssertFailed();
1565 break;
1566 }
1567
1568 DWORD cbReturned = 0;
1569 if (!DeviceIoControl(hDev, SUPUSB_IOCTL_GET_DEVICE, &Dev, sizeof (Dev), &Dev, sizeof (Dev), &cbReturned, NULL))
1570 {
1571 DWORD dwErr = GetLastError();
1572#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1573 /* ERROR_DEVICE_NOT_CONNECTED -> device was removed just now */
1574 AsserFailed();
1575#endif
1576 LogRelFunc(("SUPUSB_IOCTL_GET_DEVICE failed on '%s' (dwErr=%u)!\n", pDevInfos->szName, dwErr));
1577 CloseHandle(hDev);
1578 break;
1579 }
1580
1581 /* we must not close the handle until we request for the device state from the monitor to ensure
1582 * the device handle returned by the device driver does not disappear */
1583 Assert(Dev.hDevice);
1584 USBSUP_GETDEV_MON MonInfo;
1585 HVBOXUSBDEVUSR hDevice = Dev.hDevice;
1586 if (!DeviceIoControl(pGlobal->hMonitor, SUPUSBFLT_IOCTL_GET_DEVICE, &hDevice, sizeof (hDevice), &MonInfo, sizeof (MonInfo), &cbReturned, NULL))
1587 {
1588 DWORD dwErr = GetLastError();
1589 /* ERROR_DEVICE_NOT_CONNECTED -> device was removed just now */
1590 AssertFailed();
1591 LogRelFunc(("SUPUSBFLT_IOCTL_GET_DEVICE failed for '%s' (hDevice=%p, dwErr=%u)!\n", pDevInfos->szName, hDevice, dwErr));
1592 CloseHandle(hDev);
1593 break;
1594 }
1595
1596 CloseHandle(hDev);
1597
1598 /* success!! update device info */
1599 /* ensure the state returned is valid */
1600 Assert( MonInfo.enmState == USBDEVICESTATE_USED_BY_HOST
1601 || MonInfo.enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
1602 || MonInfo.enmState == USBDEVICESTATE_UNUSED
1603 || MonInfo.enmState == USBDEVICESTATE_HELD_BY_PROXY
1604 || MonInfo.enmState == USBDEVICESTATE_USED_BY_GUEST);
1605 pDevs->enmState = MonInfo.enmState;
1606
1607 if (pDevs->enmState != USBDEVICESTATE_USED_BY_HOST)
1608 {
1609 /* only set the interface name if device can be grabbed */
1610 RTStrFree(pDevs->pszAltAddress);
1611 pDevs->pszAltAddress = (char*)pDevs->pszAddress;
1612 pDevs->pszAddress = RTStrDup(pDevInfos->szName);
1613 }
1614#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1615 else
1616 {
1617 /* dbg breakpoint */
1618 AssertFailed();
1619 }
1620#endif
1621
1622 /* we've found the device, break in any way */
1623 break;
1624 }
1625 }
1626
1627 return VINF_SUCCESS;
1628}
1629
1630static int usbLibGetDevices(PVBOXUSBGLOBALSTATE pGlobal, PUSBDEVICE *ppDevs, uint32_t *pcDevs)
1631{
1632 *ppDevs = NULL;
1633 *pcDevs = 0;
1634
1635 LogRelFunc(("Starting USB device enumeration\n"));
1636#ifdef VBOX_WITH_NEW_USB_ENUM
1637 int rc = usbLibEnumDevices(ppDevs, pcDevs);
1638#else
1639 int rc = usbLibDevGetDevices(ppDevs, pcDevs);
1640#endif
1641 AssertRC(rc);
1642 if (RT_SUCCESS(rc))
1643 {
1644 PVBOXUSB_DEV pDevInfos = NULL;
1645 uint32_t cDevInfos = 0;
1646#ifdef VBOX_WITH_NEW_USB_ENUM
1647 rc = usbLibEnumVUsbDevices(&pDevInfos, &cDevInfos);
1648#else
1649 rc = usbLibVuGetDevices(&pDevInfos, &cDevInfos);
1650#endif
1651 AssertRC(rc);
1652 if (RT_SUCCESS(rc))
1653 {
1654 rc = usbLibMonDevicesUpdate(pGlobal, *ppDevs, pDevInfos);
1655 AssertRC(rc);
1656 usbLibVuFreeDevices(pDevInfos);
1657 }
1658
1659 LogRelFunc(("Found %u USB devices, %u captured\n", *pcDevs, cDevInfos));
1660 return VINF_SUCCESS;
1661 }
1662 return rc;
1663}
1664
1665AssertCompile(INFINITE == RT_INDEFINITE_WAIT);
1666static int usbLibStateWaitChange(PVBOXUSBGLOBALSTATE pGlobal, RTMSINTERVAL cMillies)
1667{
1668 HANDLE ahEvents[] = {pGlobal->hNotifyEvent, pGlobal->hInterruptEvent};
1669 DWORD dwResult = WaitForMultipleObjects(RT_ELEMENTS(ahEvents), ahEvents,
1670 FALSE, /* BOOL bWaitAll */
1671 cMillies);
1672
1673 switch (dwResult)
1674 {
1675 case WAIT_OBJECT_0:
1676 return VINF_SUCCESS;
1677 case WAIT_OBJECT_0 + 1:
1678 return VERR_INTERRUPTED;
1679 case WAIT_TIMEOUT:
1680 return VERR_TIMEOUT;
1681 default:
1682 {
1683 DWORD dwErr = GetLastError(); NOREF(dwErr);
1684 AssertMsgFailed(("WaitForMultipleObjects failed, dwErr (%u)\n", dwErr));
1685 return VERR_GENERAL_FAILURE;
1686 }
1687 }
1688}
1689
1690AssertCompile(RT_INDEFINITE_WAIT == INFINITE);
1691AssertCompile(sizeof (RTMSINTERVAL) == sizeof (DWORD));
1692USBLIB_DECL(int) USBLibWaitChange(RTMSINTERVAL msWaitTimeout)
1693{
1694 return usbLibStateWaitChange(&g_VBoxUsbGlobal, msWaitTimeout);
1695}
1696
1697static int usbLibInterruptWaitChange(PVBOXUSBGLOBALSTATE pGlobal)
1698{
1699 BOOL fRc = SetEvent(pGlobal->hInterruptEvent);
1700 if (!fRc)
1701 {
1702 DWORD dwErr = GetLastError(); NOREF(dwErr);
1703 AssertMsgFailed(("SetEvent failed, dwErr (%u)\n", dwErr));
1704 return VERR_GENERAL_FAILURE;
1705 }
1706 return VINF_SUCCESS;
1707}
1708
1709USBLIB_DECL(int) USBLibInterruptWaitChange(void)
1710{
1711 return usbLibInterruptWaitChange(&g_VBoxUsbGlobal);
1712}
1713
1714/*
1715USBLIB_DECL(bool) USBLibHasPendingDeviceChanges(void)
1716{
1717 int rc = USBLibWaitChange(0);
1718 return rc == VINF_SUCCESS;
1719}
1720*/
1721
1722USBLIB_DECL(int) USBLibGetDevices(PUSBDEVICE *ppDevices, uint32_t *pcbNumDevices)
1723{
1724 Assert(g_VBoxUsbGlobal.hMonitor != INVALID_HANDLE_VALUE);
1725 return usbLibGetDevices(&g_VBoxUsbGlobal, ppDevices, pcbNumDevices);
1726}
1727
1728USBLIB_DECL(void *) USBLibAddFilter(PCUSBFILTER pFilter)
1729{
1730 USBSUP_FLTADDOUT FltAddRc;
1731 DWORD cbReturned = 0;
1732
1733 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
1734 {
1735#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1736 AssertFailed();
1737#endif
1738 return NULL;
1739 }
1740
1741 Log(("usblibInsertFilter: Manufacturer=%s Product=%s Serial=%s\n",
1742 USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
1743 USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
1744 USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
1745
1746 if (!DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_ADD_FILTER,
1747 (LPVOID)pFilter, sizeof(*pFilter),
1748 &FltAddRc, sizeof(FltAddRc),
1749 &cbReturned, NULL))
1750 {
1751 DWORD dwErr = GetLastError();
1752 AssertFailed();
1753 LogRelFunc(("SUPUSBFLT_IOCTL_ADD_FILTER failed (dwErr=%u)!\n", dwErr));
1754 return NULL;
1755 }
1756
1757 if (RT_FAILURE(FltAddRc.rc))
1758 {
1759 AssertFailed();
1760 LogRelFunc(("Adding a USB filter failed with rc=%d!\n", FltAddRc.rc));
1761 return NULL;
1762 }
1763
1764 LogRel(("Added USB filter (ID=%u, type=%d) for device %04X:%04X rev %04X, c/s/p %02X/%02X/%02X, Manufacturer=`%s' Product=`%s' Serial=`%s'\n", FltAddRc.uId, USBFilterGetFilterType(pFilter),
1765 USBFilterGetNum(pFilter, USBFILTERIDX_VENDOR_ID), USBFilterGetNum(pFilter, USBFILTERIDX_PRODUCT_ID), USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_REV),
1766 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_CLASS), USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_SUB_CLASS), USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_PROTOCOL),
1767 USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
1768 USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
1769 USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
1770
1771 return (void *)FltAddRc.uId;
1772}
1773
1774
1775USBLIB_DECL(void) USBLibRemoveFilter(void *pvId)
1776{
1777 uintptr_t uId;
1778 DWORD cbReturned = 0;
1779
1780 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
1781 {
1782#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1783 AssertFailed();
1784#endif
1785 return;
1786 }
1787
1788 Log(("usblibRemoveFilter %p\n", pvId));
1789
1790 uId = (uintptr_t)pvId;
1791 if (!DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_REMOVE_FILTER, &uId, sizeof(uId), NULL, 0,&cbReturned, NULL))
1792 {
1793 DWORD dwErr = GetLastError();
1794 AssertFailed();
1795 LogRelFunc(("SUPUSBFLT_IOCTL_REMOVE_FILTER failed (dwErr=%u)!\n", dwErr));
1796 }
1797 else
1798 LogRel(("Removed USB filter ID=%u\n", uId));
1799}
1800
1801USBLIB_DECL(int) USBLibRunFilters(void)
1802{
1803 DWORD cbReturned = 0;
1804
1805 Assert(g_VBoxUsbGlobal.hMonitor != INVALID_HANDLE_VALUE);
1806
1807 if (!DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_RUN_FILTERS,
1808 NULL, 0,
1809 NULL, 0,
1810 &cbReturned, NULL))
1811 {
1812 DWORD dwErr = GetLastError();
1813 AssertFailed();
1814 LogRelFunc(("SUPUSBFLT_IOCTL_RUN_FILTERS failed (dwErr=%u)!\n", dwErr));
1815 return RTErrConvertFromWin32(dwErr);
1816 }
1817
1818 return VINF_SUCCESS;
1819}
1820
1821
1822static VOID CALLBACK usbLibTimerCallback(__in PVOID lpParameter, __in BOOLEAN TimerOrWaitFired)
1823{
1824 RT_NOREF2(lpParameter, TimerOrWaitFired);
1825 SetEvent(g_VBoxUsbGlobal.hNotifyEvent);
1826}
1827
1828static void usbLibOnDeviceChange(void)
1829{
1830 /* we're getting series of events like that especially on device re-attach
1831 * (i.e. first for device detach and then for device attach)
1832 * unfortunately the event does not tell us what actually happened.
1833 * To avoid extra notifications, we delay the SetEvent via a timer
1834 * and update the timer if additional notification comes before the timer fires
1835 * */
1836 if (g_VBoxUsbGlobal.hTimer)
1837 {
1838 if (!DeleteTimerQueueTimer(g_VBoxUsbGlobal.hTimerQueue, g_VBoxUsbGlobal.hTimer, NULL))
1839 {
1840 DWORD dwErr = GetLastError(); NOREF(dwErr);
1841 AssertMsg(dwErr == ERROR_IO_PENDING, ("DeleteTimerQueueTimer failed, dwErr (%u)\n", dwErr));
1842 }
1843 }
1844
1845 if (!CreateTimerQueueTimer(&g_VBoxUsbGlobal.hTimer, g_VBoxUsbGlobal.hTimerQueue,
1846 usbLibTimerCallback,
1847 NULL,
1848 500, /* ms*/
1849 0,
1850 WT_EXECUTEONLYONCE))
1851 {
1852 DWORD dwErr = GetLastError(); NOREF(dwErr);
1853 AssertMsgFailed(("CreateTimerQueueTimer failed, dwErr (%u)\n", dwErr));
1854
1855 /* call it directly */
1856 usbLibTimerCallback(NULL, FALSE);
1857 }
1858}
1859
1860static LRESULT CALLBACK usbLibWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1861{
1862 switch (uMsg)
1863 {
1864 case WM_DEVICECHANGE:
1865 if (wParam == DBT_DEVNODES_CHANGED)
1866 {
1867 /* we notify change any device arivals/removals on the system
1868 * and let the client decide whether the usb change actually happened
1869 * so far this is more clean than reporting events from the Monitor
1870 * because monitor sees only PDO arrivals/removals,
1871 * and by the time PDO is created, device can not
1872 * be yet started and fully functional,
1873 * so usblib won't be able to pick it up
1874 * */
1875
1876 usbLibOnDeviceChange();
1877 }
1878 break;
1879 case WM_DESTROY:
1880 {
1881 PostQuitMessage(0);
1882 return 0;
1883 }
1884 }
1885 return DefWindowProc (hwnd, uMsg, wParam, lParam);
1886}
1887
1888/** @todo r=bird: Use an IPRT thread? */
1889static DWORD WINAPI usbLibMsgThreadProc(__in LPVOID lpParameter)
1890{
1891 static LPCSTR s_szVBoxUsbWndClassName = "VBoxUsbLibClass";
1892 const HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
1893 RT_NOREF1(lpParameter);
1894
1895 Assert(g_VBoxUsbGlobal.hWnd == NULL);
1896 g_VBoxUsbGlobal.hWnd = NULL;
1897
1898 /*
1899 * Register the Window Class and create the hidden window.
1900 */
1901 WNDCLASS wc;
1902 wc.style = 0;
1903 wc.lpfnWndProc = usbLibWndProc;
1904 wc.cbClsExtra = 0;
1905 wc.cbWndExtra = sizeof(void *);
1906 wc.hInstance = hInstance;
1907 wc.hIcon = NULL;
1908 wc.hCursor = NULL;
1909 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
1910 wc.lpszMenuName = NULL;
1911 wc.lpszClassName = s_szVBoxUsbWndClassName;
1912 ATOM atomWindowClass = RegisterClass(&wc);
1913 if (atomWindowClass != 0)
1914 g_VBoxUsbGlobal.hWnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
1915 s_szVBoxUsbWndClassName, s_szVBoxUsbWndClassName,
1916 WS_POPUPWINDOW,
1917 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
1918 else
1919 AssertMsgFailed(("RegisterClass failed, last error %u\n", GetLastError()));
1920
1921 /*
1922 * Signal the creator thread.
1923 */
1924 ASMCompilerBarrier();
1925 SetEvent(g_VBoxUsbGlobal.hNotifyEvent);
1926
1927 if (g_VBoxUsbGlobal.hWnd)
1928 {
1929 /* Make sure it's really hidden. */
1930 SetWindowPos(g_VBoxUsbGlobal.hWnd, HWND_TOPMOST, -200, -200, 0, 0,
1931 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
1932
1933 /*
1934 * The message pump.
1935 */
1936 MSG msg;
1937 BOOL fRet;
1938 while ((fRet = GetMessage(&msg, NULL, 0, 0)) > 0)
1939 {
1940 TranslateMessage(&msg);
1941 DispatchMessage(&msg);
1942 }
1943 Assert(fRet >= 0);
1944 }
1945
1946 if (atomWindowClass != NULL)
1947 UnregisterClass(s_szVBoxUsbWndClassName, hInstance);
1948
1949 return 0;
1950}
1951
1952
1953/**
1954 * Initialize the USB library
1955 *
1956 * @returns VBox status code.
1957 */
1958USBLIB_DECL(int) USBLibInit(void)
1959{
1960 int rc = VERR_GENERAL_FAILURE;
1961
1962 Log(("usbproxy: usbLibInit\n"));
1963
1964 RT_ZERO(g_VBoxUsbGlobal);
1965 g_VBoxUsbGlobal.hMonitor = INVALID_HANDLE_VALUE;
1966
1967 /*
1968 * Create the notification and interrupt event before opening the device.
1969 */
1970 g_VBoxUsbGlobal.hNotifyEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes */
1971 FALSE, /* BOOL bManualReset */
1972 FALSE, /* set to false since it will be initially used for notification thread startup sync */
1973 NULL /* LPCTSTR lpName */);
1974 if (g_VBoxUsbGlobal.hNotifyEvent)
1975 {
1976 g_VBoxUsbGlobal.hInterruptEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes */
1977 FALSE, /* BOOL bManualReset */
1978 FALSE, /* BOOL bInitialState */
1979 NULL /* LPCTSTR lpName */);
1980 if (g_VBoxUsbGlobal.hInterruptEvent)
1981 {
1982 /*
1983 * Open the USB monitor device, starting if needed.
1984 */
1985 g_VBoxUsbGlobal.hMonitor = CreateFile(USBMON_DEVICE_NAME,
1986 GENERIC_READ | GENERIC_WRITE,
1987 FILE_SHARE_READ | FILE_SHARE_WRITE,
1988 NULL,
1989 OPEN_EXISTING,
1990 FILE_ATTRIBUTE_SYSTEM,
1991 NULL);
1992
1993 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
1994 {
1995 HRESULT hr = VBoxDrvCfgSvcStart(USBMON_SERVICE_NAME_W);
1996 if (hr == S_OK)
1997 {
1998 g_VBoxUsbGlobal.hMonitor = CreateFile(USBMON_DEVICE_NAME,
1999 GENERIC_READ | GENERIC_WRITE,
2000 FILE_SHARE_READ | FILE_SHARE_WRITE,
2001 NULL,
2002 OPEN_EXISTING,
2003 FILE_ATTRIBUTE_SYSTEM,
2004 NULL);
2005 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
2006 {
2007 DWORD dwErr = GetLastError();
2008 LogRelFunc(("CreateFile failed (dwErr=%u) for `%s'\n", dwErr, USBMON_DEVICE_NAME));
2009 rc = VERR_FILE_NOT_FOUND;
2010 }
2011 }
2012 }
2013
2014 if (g_VBoxUsbGlobal.hMonitor != INVALID_HANDLE_VALUE)
2015 {
2016 /*
2017 * Check the USB monitor version.
2018 *
2019 * Drivers are backwards compatible within the same major
2020 * number. We consider the minor version number this library
2021 * is compiled with to be the minimum required by the driver.
2022 * This is by reasoning that the library uses the full feature
2023 * set of the driver it's written for.
2024 */
2025 USBSUP_VERSION Version = {0};
2026 DWORD cbReturned = 0;
2027 if (DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_GET_VERSION,
2028 NULL, 0,
2029 &Version, sizeof (Version),
2030 &cbReturned, NULL))
2031 {
2032 if ( Version.u32Major == USBMON_MAJOR_VERSION
2033#if USBMON_MINOR_VERSION != 0
2034 && Version.u32Minor >= USBMON_MINOR_VERSION
2035#endif
2036 )
2037 {
2038 /*
2039 * We can not use USB Mon for reliable device add/remove tracking
2040 * since once USB Mon is notified about PDO creation and/or IRP_MN_START_DEVICE,
2041 * the function device driver may still do some initialization, which might result in
2042 * notifying too early.
2043 * Instead we use WM_DEVICECHANGE + DBT_DEVNODES_CHANGED to make Windows notify us about
2044 * device arivals/removals.
2045 * Since WM_DEVICECHANGE is a window message, create a dedicated thread to be used for WndProc and stuff.
2046 * The thread would create a window, track windows messages and call usbLibOnDeviceChange on WM_DEVICECHANGE arrival.
2047 * See comments in usbLibOnDeviceChange function for detail about using the timer queue.
2048 */
2049 g_VBoxUsbGlobal.hTimerQueue = CreateTimerQueue();
2050 if (g_VBoxUsbGlobal.hTimerQueue)
2051 {
2052 g_VBoxUsbGlobal.hThread = CreateThread(
2053 NULL, /*__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, */
2054 0, /*__in SIZE_T dwStackSize, */
2055 usbLibMsgThreadProc, /*__in LPTHREAD_START_ROUTINE lpStartAddress,*/
2056 NULL, /*__in_opt LPVOID lpParameter,*/
2057 0, /*__in DWORD dwCreationFlags,*/
2058 NULL /*__out_opt LPDWORD lpThreadId*/
2059 );
2060 if (g_VBoxUsbGlobal.hThread)
2061 {
2062 DWORD dwResult = WaitForSingleObject(g_VBoxUsbGlobal.hNotifyEvent, INFINITE);
2063 Assert(dwResult == WAIT_OBJECT_0);
2064 if (g_VBoxUsbGlobal.hWnd)
2065 {
2066 /*
2067 * We're DONE!
2068 *
2069 * Just ensure that the event is set so the
2070 * first "wait change" request is processed.
2071 */
2072 SetEvent(g_VBoxUsbGlobal.hNotifyEvent);
2073 return VINF_SUCCESS;
2074 }
2075
2076 dwResult = WaitForSingleObject(g_VBoxUsbGlobal.hThread, INFINITE);
2077 Assert(dwResult == WAIT_OBJECT_0);
2078 BOOL fRc = CloseHandle(g_VBoxUsbGlobal.hThread); NOREF(fRc);
2079 DWORD dwErr = GetLastError(); NOREF(dwErr);
2080 AssertMsg(fRc, ("CloseHandle for hThread failed (dwErr=%u)\n", dwErr));
2081 g_VBoxUsbGlobal.hThread = INVALID_HANDLE_VALUE;
2082 }
2083 else
2084 {
2085 DWORD dwErr = GetLastError(); NOREF(dwErr);
2086 AssertMsgFailed(("CreateThread failed, (dwErr=%u)\n", dwErr));
2087 rc = VERR_GENERAL_FAILURE;
2088 }
2089
2090 DeleteTimerQueueEx(g_VBoxUsbGlobal.hTimerQueue, INVALID_HANDLE_VALUE /* see term */);
2091 g_VBoxUsbGlobal.hTimerQueue = NULL;
2092 }
2093 else
2094 {
2095 DWORD dwErr = GetLastError(); NOREF(dwErr);
2096 AssertMsgFailed(("CreateTimerQueue failed (dwErr=%u)\n", dwErr));
2097 }
2098 }
2099 else
2100 {
2101 LogRelFunc(("USB Monitor driver version mismatch! driver=%u.%u library=%u.%u\n",
2102 Version.u32Major, Version.u32Minor, USBMON_MAJOR_VERSION, USBMON_MINOR_VERSION));
2103#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
2104 AssertFailed();
2105#endif
2106 rc = VERR_VERSION_MISMATCH;
2107 }
2108 }
2109 else
2110 {
2111 DWORD dwErr = GetLastError(); NOREF(dwErr);
2112 LogRelFunc(("SUPUSBFLT_IOCTL_GET_VERSION failed (dwErr=%u)\n", dwErr));
2113 AssertFailed();
2114 rc = VERR_VERSION_MISMATCH;
2115 }
2116
2117 CloseHandle(g_VBoxUsbGlobal.hMonitor);
2118 g_VBoxUsbGlobal.hMonitor = INVALID_HANDLE_VALUE;
2119 }
2120 else
2121 {
2122 LogRelFunc(("USB Service not found\n"));
2123#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
2124 AssertFailed();
2125#endif
2126 rc = VERR_FILE_NOT_FOUND;
2127 }
2128
2129 CloseHandle(g_VBoxUsbGlobal.hInterruptEvent);
2130 g_VBoxUsbGlobal.hInterruptEvent = NULL;
2131 }
2132 else
2133 {
2134 AssertMsgFailed(("CreateEvent for InterruptEvent failed (dwErr=%u)\n", GetLastError()));
2135 rc = VERR_GENERAL_FAILURE;
2136 }
2137
2138 CloseHandle(g_VBoxUsbGlobal.hNotifyEvent);
2139 g_VBoxUsbGlobal.hNotifyEvent = NULL;
2140 }
2141 else
2142 {
2143 AssertMsgFailed(("CreateEvent for NotifyEvent failed (dwErr=%u)\n", GetLastError()));
2144 rc = VERR_GENERAL_FAILURE;
2145 }
2146
2147 /* since main calls us even if USBLibInit fails,
2148 * we use hMonitor == INVALID_HANDLE_VALUE as a marker to indicate whether the lib is inited */
2149
2150 Assert(RT_FAILURE(rc));
2151 return rc;
2152}
2153
2154
2155/**
2156 * Terminate the USB library
2157 *
2158 * @returns VBox status code.
2159 */
2160USBLIB_DECL(int) USBLibTerm(void)
2161{
2162 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
2163 {
2164 Assert(g_VBoxUsbGlobal.hInterruptEvent == NULL);
2165 Assert(g_VBoxUsbGlobal.hNotifyEvent == NULL);
2166 return VINF_SUCCESS;
2167 }
2168
2169 BOOL fRc;
2170 fRc = PostMessage(g_VBoxUsbGlobal.hWnd, WM_CLOSE, 0, 0);
2171 AssertMsg(fRc, ("PostMessage for hWnd failed (dwErr=%u)\n", GetLastError()));
2172
2173 if (g_VBoxUsbGlobal.hThread != NULL)
2174 {
2175 DWORD dwResult = WaitForSingleObject(g_VBoxUsbGlobal.hThread, INFINITE);
2176 Assert(dwResult == WAIT_OBJECT_0); NOREF(dwResult);
2177 fRc = CloseHandle(g_VBoxUsbGlobal.hThread);
2178 AssertMsg(fRc, ("CloseHandle for hThread failed (dwErr=%u)\n", GetLastError()));
2179 }
2180
2181 if (g_VBoxUsbGlobal.hTimer)
2182 {
2183 fRc = DeleteTimerQueueTimer(g_VBoxUsbGlobal.hTimerQueue, g_VBoxUsbGlobal.hTimer,
2184 INVALID_HANDLE_VALUE); /* <-- to block until the timer is completed */
2185 AssertMsg(fRc, ("DeleteTimerQueueTimer failed (dwErr=%u)\n", GetLastError()));
2186 }
2187
2188 if (g_VBoxUsbGlobal.hTimerQueue)
2189 {
2190 fRc = DeleteTimerQueueEx(g_VBoxUsbGlobal.hTimerQueue,
2191 INVALID_HANDLE_VALUE); /* <-- to block until all timers are completed */
2192 AssertMsg(fRc, ("DeleteTimerQueueEx failed (dwErr=%u)\n", GetLastError()));
2193 }
2194
2195 fRc = CloseHandle(g_VBoxUsbGlobal.hMonitor);
2196 AssertMsg(fRc, ("CloseHandle for hMonitor failed (dwErr=%u)\n", GetLastError()));
2197 g_VBoxUsbGlobal.hMonitor = INVALID_HANDLE_VALUE;
2198
2199 fRc = CloseHandle(g_VBoxUsbGlobal.hInterruptEvent);
2200 AssertMsg(fRc, ("CloseHandle for hInterruptEvent failed (dwErr=%u)\n", GetLastError()));
2201 g_VBoxUsbGlobal.hInterruptEvent = NULL;
2202
2203 fRc = CloseHandle(g_VBoxUsbGlobal.hNotifyEvent);
2204 AssertMsg(fRc, ("CloseHandle for hNotifyEvent failed (dwErr=%u)\n", GetLastError()));
2205 g_VBoxUsbGlobal.hNotifyEvent = NULL;
2206
2207 return VINF_SUCCESS;
2208}
2209
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette