VirtualBox

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

Last change on this file since 38280 was 38280, checked in by vboxsync, 14 years ago

annoying usb assertion

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 51.0 KB
Line 
1/* $Id: VBoxUsbLib-win.cpp 38280 2011-08-02 13:12:56Z vboxsync $ */
2/** @file
3 * VBox USB R3 Driver Interface library
4 */
5/*
6 * Copyright (C) 2011 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
17#include <windows.h>
18
19#include <VBox/sup.h>
20#include <VBox/types.h>
21#include <VBox/err.h>
22#include <VBox/param.h>
23#include <iprt/path.h>
24#include <iprt/assert.h>
25#include <iprt/alloc.h>
26#include <iprt/string.h>
27#include <iprt/thread.h>
28#include <VBox/log.h>
29#include <VBox/usblib.h>
30#include <VBox/usblib-win.h>
31#include <VBox/usb.h>
32#include <VBox/VBoxDrvCfg-win.h>
33#include <stdio.h>
34#pragma warning (disable:4200) /* shuts up the empty array member warnings */
35#include <setupapi.h>
36#include <usbdi.h>
37#include <hidsdi.h>
38
39#define VBOX_USB_USE_DEVICE_NOTIFICATION
40
41#ifdef VBOX_USB_USE_DEVICE_NOTIFICATION
42# include <Dbt.h>
43#endif
44
45typedef struct _USB_INTERFACE_DESCRIPTOR2 {
46 UCHAR bLength;
47 UCHAR bDescriptorType;
48 UCHAR bInterfaceNumber;
49 UCHAR bAlternateSetting;
50 UCHAR bNumEndpoints;
51 UCHAR bInterfaceClass;
52 UCHAR bInterfaceSubClass;
53 UCHAR bInterfaceProtocol;
54 UCHAR iInterface;
55 USHORT wNumClasses;
56} USB_INTERFACE_DESCRIPTOR2, *PUSB_INTERFACE_DESCRIPTOR2;
57
58typedef struct VBOXUSBGLOBALSTATE
59{
60 HANDLE hMonitor;
61 HANDLE hNotifyEvent;
62 HANDLE hInterruptEvent;
63#ifdef VBOX_USB_USE_DEVICE_NOTIFICATION
64 HANDLE hThread;
65 HWND hWnd;
66 HANDLE hTimerQueue;
67 HANDLE hTimer;
68#endif
69} VBOXUSBGLOBALSTATE, *PVBOXUSBGLOBALSTATE;
70
71static VBOXUSBGLOBALSTATE g_VBoxUsbGlobal;
72
73typedef struct VBOXUSB_STRING_DR_ENTRY
74{
75 struct VBOXUSB_STRING_DR_ENTRY *pNext;
76 UCHAR iDr;
77 USHORT idLang;
78 USB_STRING_DESCRIPTOR StrDr;
79} VBOXUSB_STRING_DR_ENTRY, *PVBOXUSB_STRING_DR_ENTRY;
80
81/* this represents VBoxUsb device instance */
82typedef struct VBOXUSB_DEV
83{
84 struct VBOXUSB_DEV *pNext;
85 char szName[512];
86 char szDriverRegName[512];
87} VBOXUSB_DEV, *PVBOXUSB_DEV;
88
89int usbLibVuDeviceValidate(PVBOXUSB_DEV pVuDev)
90{
91 HANDLE hOut = INVALID_HANDLE_VALUE;
92
93 hOut = CreateFile(pVuDev->szName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
94 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
95
96 if (hOut == INVALID_HANDLE_VALUE)
97 {
98 DWORD winEr = GetLastError();
99 AssertMsgFailed((__FUNCTION__": CreateFile FAILED to open %s, winEr (%d)\n", pVuDev->szName, winEr));
100 return VERR_GENERAL_FAILURE;
101 }
102
103 USBSUP_VERSION version = {0};
104 DWORD cbReturned = 0;
105 int rc = VERR_VERSION_MISMATCH;
106
107 do
108 {
109 if (!DeviceIoControl(hOut, SUPUSB_IOCTL_GET_VERSION, NULL, 0,&version, sizeof(version), &cbReturned, NULL))
110 {
111 AssertMsgFailed((__FUNCTION__": DeviceIoControl SUPUSB_IOCTL_GET_VERSION failed with LastError=%Rwa\n", GetLastError()));
112 break;
113 }
114
115 if (version.u32Major != USBDRV_MAJOR_VERSION
116 || version.u32Minor < USBDRV_MINOR_VERSION)
117 {
118 AssertMsgFailed((__FUNCTION__": Invalid version %d:%d vs %d:%d\n", version.u32Major, version.u32Minor, USBDRV_MAJOR_VERSION, USBDRV_MINOR_VERSION));
119 break;
120 }
121
122 if (!DeviceIoControl(hOut, SUPUSB_IOCTL_IS_OPERATIONAL, NULL, 0, NULL, NULL, &cbReturned, NULL))
123 {
124 AssertMsgFailed((__FUNCTION__": DeviceIoControl SUPUSB_IOCTL_IS_OPERATIONAL failed with LastError=%Rwa\n", GetLastError()));
125 break;
126 }
127
128 rc = VINF_SUCCESS;
129 } while (0);
130
131 CloseHandle(hOut);
132 return rc;
133}
134
135static int usbLibVuDevicePopulate(PVBOXUSB_DEV pVuDev, HDEVINFO hDevInfo, PSP_DEVICE_INTERFACE_DATA pIfData)
136{
137 DWORD cbIfDetailData;
138 int rc = VINF_SUCCESS;
139
140 SetupDiGetDeviceInterfaceDetail(hDevInfo, pIfData,
141 NULL, /* OUT PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData */
142 0, /* IN DWORD DeviceInterfaceDetailDataSize */
143 &cbIfDetailData,
144 NULL
145 );
146 Assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
147
148 PSP_DEVICE_INTERFACE_DETAIL_DATA pIfDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)RTMemAllocZ(cbIfDetailData);
149 if (!pIfDetailData)
150 {
151 AssertMsgFailed((__FUNCTION__": RTMemAllocZ failed\n"));
152 return VERR_OUT_OF_RESOURCES;
153 }
154
155 DWORD cbDbgRequired;
156 SP_DEVINFO_DATA DevInfoData;
157 DevInfoData.cbSize = sizeof (DevInfoData);
158 /* the cbSize should contain the sizeof a fixed-size part according to the docs */
159 pIfDetailData->cbSize = sizeof (*pIfDetailData);
160 do
161 {
162 if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, pIfData,
163 pIfDetailData,
164 cbIfDetailData,
165 &cbDbgRequired,
166 &DevInfoData))
167 {
168 DWORD winEr = GetLastError();
169 AssertMsgFailed((__FUNCTION__": SetupDiGetDeviceInterfaceDetail, cbRequired (%d), was (%d), winEr (%d)\n", cbDbgRequired, cbIfDetailData, winEr));
170 rc = VERR_GENERAL_FAILURE;
171 break;
172 }
173
174 strncpy(pVuDev->szName, pIfDetailData->DevicePath, sizeof (pVuDev->szName));
175
176 if (!SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DevInfoData, SPDRP_DRIVER,
177 NULL, /* OUT PDWORD PropertyRegDataType */
178 (PBYTE)pVuDev->szDriverRegName,
179 sizeof (pVuDev->szDriverRegName),
180 &cbDbgRequired))
181 {
182 DWORD winEr = GetLastError();
183 AssertMsgFailed((__FUNCTION__": SetupDiGetDeviceRegistryPropertyA, cbRequired (%d), was (%d), winEr (%d)\n", cbDbgRequired, sizeof (pVuDev->szDriverRegName), winEr));
184 rc = VERR_GENERAL_FAILURE;
185 break;
186 }
187
188 rc = usbLibVuDeviceValidate(pVuDev);
189 AssertRC(rc);
190 } while (0);
191
192 RTMemFree(pIfDetailData);
193 return rc;
194}
195
196static void usbLibVuFreeDevices(PVBOXUSB_DEV pDevInfos)
197{
198 while (pDevInfos)
199 {
200 PVBOXUSB_DEV pNext = pDevInfos->pNext;
201 RTMemFree(pDevInfos);
202 pDevInfos = pNext;
203 }
204}
205
206static int usbLibVuGetDevices(PVBOXUSB_DEV *ppVuDevs, uint32_t *pcVuDevs)
207{
208 *ppVuDevs = NULL;
209 *pcVuDevs = 0;
210
211 HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_CLASS_VBOXUSB,
212 NULL, /* IN PCTSTR Enumerator */
213 NULL, /* IN HWND hwndParent */
214 (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE) /* IN DWORD Flags */
215 );
216 if (hDevInfo == INVALID_HANDLE_VALUE)
217 {
218 DWORD winEr = GetLastError();
219 AssertMsgFailed((__FUNCTION__": SetupDiGetClassDevs, winEr (%d)\n", winEr));
220 return VERR_GENERAL_FAILURE;
221 }
222
223 for (int i = 0; ; ++i)
224 {
225 SP_DEVICE_INTERFACE_DATA IfData;
226 IfData.cbSize = sizeof (IfData);
227 if (!SetupDiEnumDeviceInterfaces(hDevInfo,
228 NULL, /* IN PSP_DEVINFO_DATA DeviceInfoData */
229 &GUID_CLASS_VBOXUSB, /* IN LPGUID InterfaceClassGuid */
230 i,
231 &IfData))
232 {
233 DWORD winEr = GetLastError();
234 if (winEr == ERROR_NO_MORE_ITEMS)
235 break;
236
237 AssertMsgFailed((__FUNCTION__": SetupDiEnumDeviceInterfaces, winEr (%d), resuming\n", winEr));
238 continue;
239 }
240
241 /* we've now got the IfData */
242 PVBOXUSB_DEV pVuDev = (PVBOXUSB_DEV)RTMemAllocZ(sizeof (*pVuDev));
243 if (!pVuDev)
244 {
245 AssertMsgFailed((__FUNCTION__": RTMemAllocZ failed, resuming\n"));
246 continue;
247 }
248
249 int rc = usbLibVuDevicePopulate(pVuDev, hDevInfo, &IfData);
250 if (!RT_SUCCESS(rc))
251 {
252 AssertMsgFailed((__FUNCTION__": usbLibVuDevicePopulate failed, rc (%d), resuming\n", rc));
253 continue;
254 }
255
256 pVuDev->pNext = *ppVuDevs;
257 *ppVuDevs = pVuDev;
258 ++*pcVuDevs;
259 }
260
261 SetupDiDestroyDeviceInfoList(hDevInfo);
262
263 return VINF_SUCCESS;
264}
265
266static void usbLibDevFree(PUSBDEVICE pDevice)
267{
268 RTStrFree((char*)pDevice->pszAddress);
269 RTStrFree((char*)pDevice->pszHubName);
270 if (pDevice->pszManufacturer)
271 RTStrFree((char*)pDevice->pszManufacturer);
272 if (pDevice->pszProduct)
273 RTStrFree((char*)pDevice->pszProduct);
274 if (pDevice->pszSerialNumber)
275 RTStrFree((char*)pDevice->pszSerialNumber);
276 RTMemFree(pDevice);
277}
278
279static void usbLibDevFreeList(PUSBDEVICE pDevice)
280{
281 while (pDevice)
282 {
283 PUSBDEVICE pNext = pDevice->pNext;
284 usbLibDevFree(pDevice);
285 pDevice = pNext;
286 }
287}
288
289static int usbLibDevPopulate(PUSBDEVICE pDev, PUSB_NODE_CONNECTION_INFORMATION_EX pConInfo, ULONG iPort, LPCSTR lpszDrvKeyName, LPCSTR lpszHubName, PVBOXUSB_STRING_DR_ENTRY pDrList)
290{
291 pDev->bcdUSB = pConInfo->DeviceDescriptor.bcdUSB;
292 pDev->bDeviceClass = pConInfo->DeviceDescriptor.bDeviceClass;
293 pDev->bDeviceSubClass = pConInfo->DeviceDescriptor.bDeviceSubClass;
294 pDev->bDeviceProtocol = pConInfo->DeviceDescriptor.bDeviceProtocol;
295 pDev->idVendor = pConInfo->DeviceDescriptor.idVendor;
296 pDev->idProduct = pConInfo->DeviceDescriptor.idProduct;
297 pDev->bcdDevice = pConInfo->DeviceDescriptor.bcdDevice;
298 pDev->bBus = 0; /** @todo figure out bBus on windows... */
299 pDev->bPort = iPort;
300 /** @todo check which devices are used for primary input (keyboard & mouse) */
301 if (!lpszDrvKeyName || *lpszDrvKeyName == 0)
302 pDev->enmState = USBDEVICESTATE_UNUSED;
303 else
304 pDev->enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
305 pDev->enmSpeed = USBDEVICESPEED_UNKNOWN;
306 pDev->pszAddress = RTStrDup(lpszDrvKeyName);
307 pDev->pszHubName = RTStrDup(lpszHubName);
308 pDev->bNumConfigurations = 0;
309 pDev->u64SerialHash = 0;
310
311 for (; pDrList; pDrList = pDrList->pNext)
312 {
313 LPSTR *lppszString = NULL;
314 if (pConInfo->DeviceDescriptor.iManufacturer && pDrList->iDr == pConInfo->DeviceDescriptor.iManufacturer)
315 {
316 lppszString = (LPSTR*)&pDev->pszManufacturer;
317 }
318 else if (pConInfo->DeviceDescriptor.iProduct && pDrList->iDr == pConInfo->DeviceDescriptor.iProduct)
319 {
320 lppszString = (LPSTR*)&pDev->pszProduct;
321 }
322 else if (pConInfo->DeviceDescriptor.iSerialNumber && pDrList->iDr == pConInfo->DeviceDescriptor.iSerialNumber)
323 {
324 lppszString = (LPSTR*)&pDev->pszSerialNumber;
325 }
326
327 if (lppszString)
328 {
329 char *pStringUTF8 = NULL;
330 RTUtf16ToUtf8((PCRTUTF16)pDrList->StrDr.bString, &pStringUTF8);
331 RTStrUtf8ToCurrentCP(lppszString, pStringUTF8);
332 RTStrFree(pStringUTF8);
333 if (pDrList->iDr == pConInfo->DeviceDescriptor.iSerialNumber)
334 {
335 pDev->u64SerialHash = USBLibHashSerial(pDev->pszSerialNumber);
336 }
337 }
338 }
339
340 return VINF_SUCCESS;
341}
342
343static void usbLibDevStrFree(LPSTR lpszName)
344{
345 RTStrFree(lpszName);
346}
347
348static int usbLibDevStrDriverKeyGet(HANDLE hHub, ULONG iPort, LPSTR* plpszName)
349{
350 USB_NODE_CONNECTION_DRIVERKEY_NAME Name;
351 DWORD cbReturned = 0;
352 Name.ConnectionIndex = iPort;
353 *plpszName = NULL;
354 if (!DeviceIoControl(hHub, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, &Name, sizeof (Name), &Name, sizeof (Name), &cbReturned, NULL))
355 {
356#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
357 DWORD winEr = GetLastError();
358 AssertMsgFailed((__FUNCTION__": DeviceIoControl 1 fail winEr (%d)\n", winEr));
359#endif
360 return VERR_GENERAL_FAILURE;
361 }
362
363 if (Name.ActualLength < sizeof (Name))
364 {
365 AssertFailed();
366 return VERR_OUT_OF_RESOURCES;
367 }
368
369 PUSB_NODE_CONNECTION_DRIVERKEY_NAME pName = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)RTMemAllocZ(Name.ActualLength);
370 if (!pName)
371 {
372 AssertFailed();
373 return VERR_OUT_OF_RESOURCES;
374 }
375
376 int rc = VINF_SUCCESS;
377 pName->ConnectionIndex = iPort;
378 if (DeviceIoControl(hHub, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, pName, Name.ActualLength, pName, Name.ActualLength, &cbReturned, NULL))
379 {
380 rc = RTUtf16ToUtf8Ex((PCRTUTF16)pName->DriverKeyName, pName->ActualLength, plpszName, 0, NULL);
381 AssertRC(rc);
382 if (RT_SUCCESS(rc))
383 rc = VINF_SUCCESS;
384 }
385 else
386 {
387 DWORD winEr = GetLastError();
388 AssertMsgFailed((__FUNCTION__": DeviceIoControl 2 fail winEr (%d)\n", winEr));
389 rc = VERR_GENERAL_FAILURE;
390 }
391 RTMemFree(pName);
392 return rc;
393}
394
395static int usbLibDevStrHubNameGet(HANDLE hHub, ULONG iPort, LPSTR* plpszName)
396{
397 USB_NODE_CONNECTION_NAME Name;
398 DWORD cbReturned = 0;
399 Name.ConnectionIndex = iPort;
400 *plpszName = NULL;
401 if (!DeviceIoControl(hHub, IOCTL_USB_GET_NODE_CONNECTION_NAME, &Name, sizeof (Name), &Name, sizeof (Name), &cbReturned, NULL))
402 {
403 AssertFailed();
404 return VERR_GENERAL_FAILURE;
405 }
406
407 if (Name.ActualLength < sizeof (Name))
408 {
409 AssertFailed();
410 return VERR_OUT_OF_RESOURCES;
411 }
412
413 PUSB_NODE_CONNECTION_NAME pName = (PUSB_NODE_CONNECTION_NAME)RTMemAllocZ(Name.ActualLength);
414 if (!pName)
415 {
416 AssertFailed();
417 return VERR_OUT_OF_RESOURCES;
418 }
419
420 int rc = VINF_SUCCESS;
421 pName->ConnectionIndex = iPort;
422 if (DeviceIoControl(hHub, IOCTL_USB_GET_NODE_CONNECTION_NAME, pName, Name.ActualLength, pName, Name.ActualLength, &cbReturned, NULL))
423 {
424 rc = RTUtf16ToUtf8Ex((PCRTUTF16)pName->NodeName, pName->ActualLength, plpszName, 0, NULL);
425 AssertRC(rc);
426 if (RT_SUCCESS(rc))
427 rc = VINF_SUCCESS;
428 }
429 else
430 {
431 AssertFailed();
432 rc = VERR_GENERAL_FAILURE;
433 }
434 RTMemFree(pName);
435 return rc;
436}
437
438static int usbLibDevStrRootHubNameGet(HANDLE hCtl, LPSTR* plpszName)
439{
440 USB_ROOT_HUB_NAME HubName;
441 DWORD cbReturned = 0;
442 *plpszName = NULL;
443 if (!DeviceIoControl(hCtl, IOCTL_USB_GET_ROOT_HUB_NAME, NULL, 0, &HubName, sizeof (HubName), &cbReturned, NULL))
444 {
445 return VERR_GENERAL_FAILURE;
446 }
447 PUSB_ROOT_HUB_NAME pHubName = (PUSB_ROOT_HUB_NAME)RTMemAllocZ(HubName.ActualLength);
448 if (!pHubName)
449 return VERR_OUT_OF_RESOURCES;
450
451 int rc = VINF_SUCCESS;
452 if (DeviceIoControl(hCtl, IOCTL_USB_GET_ROOT_HUB_NAME, NULL, 0, pHubName, HubName.ActualLength, &cbReturned, NULL))
453 {
454 rc = RTUtf16ToUtf8Ex((PCRTUTF16)pHubName->RootHubName, pHubName->ActualLength, plpszName, 0, NULL);
455 AssertRC(rc);
456 if (RT_SUCCESS(rc))
457 rc = VINF_SUCCESS;
458 }
459 else
460 {
461 rc = VERR_GENERAL_FAILURE;
462 }
463 RTMemFree(pHubName);
464 return rc;
465}
466
467static int usbLibDevCfgDrGet(HANDLE hHub, ULONG iPort, ULONG iDr, PUSB_CONFIGURATION_DESCRIPTOR *ppDr)
468{
469 *ppDr = NULL;
470
471 char Buf[sizeof (USB_DESCRIPTOR_REQUEST) + sizeof (USB_CONFIGURATION_DESCRIPTOR)];
472 memset(&Buf, 0, sizeof (Buf));
473
474 PUSB_DESCRIPTOR_REQUEST pCfgDrRq = (PUSB_DESCRIPTOR_REQUEST)Buf;
475 PUSB_CONFIGURATION_DESCRIPTOR pCfgDr = (PUSB_CONFIGURATION_DESCRIPTOR)(Buf + sizeof (*pCfgDrRq));
476
477 pCfgDrRq->ConnectionIndex = iPort;
478 pCfgDrRq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | iDr;
479 pCfgDrRq->SetupPacket.wLength = (USHORT)(sizeof (USB_CONFIGURATION_DESCRIPTOR));
480 DWORD cbReturned = 0;
481 if (!DeviceIoControl(hHub, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, pCfgDrRq, sizeof (Buf),
482 pCfgDrRq, sizeof (Buf),
483 &cbReturned, NULL))
484 {
485 DWORD winEr = GetLastError();
486 LogRel((__FUNCTION__": DeviceIoControl 1 fail winEr (%d)\n", winEr));
487#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
488 AssertFailed();
489#endif
490 return VERR_GENERAL_FAILURE;
491 }
492
493 if (sizeof (Buf) != cbReturned)
494 {
495 AssertFailed();
496 return VERR_GENERAL_FAILURE;
497 }
498
499 if (pCfgDr->wTotalLength < sizeof (USB_CONFIGURATION_DESCRIPTOR))
500 {
501 AssertFailed();
502 return VERR_GENERAL_FAILURE;
503 }
504
505 DWORD cbRq = sizeof (USB_DESCRIPTOR_REQUEST) + pCfgDr->wTotalLength;
506 PUSB_DESCRIPTOR_REQUEST pRq = (PUSB_DESCRIPTOR_REQUEST)RTMemAllocZ(cbRq);
507 Assert(pRq);
508 if (!pRq)
509 return VERR_OUT_OF_RESOURCES;
510
511 int rc = VERR_GENERAL_FAILURE;
512 do
513 {
514 PUSB_CONFIGURATION_DESCRIPTOR pDr = (PUSB_CONFIGURATION_DESCRIPTOR)(pRq + 1);
515 pRq->ConnectionIndex = iPort;
516 pRq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | iDr;
517 pRq->SetupPacket.wLength = (USHORT)(cbRq - sizeof (USB_DESCRIPTOR_REQUEST));
518 if (!DeviceIoControl(hHub, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, pRq, cbRq,
519 pRq, cbRq,
520 &cbReturned, NULL))
521 {
522 DWORD winEr = GetLastError();
523 LogRel((__FUNCTION__": DeviceIoControl 2 fail winEr (%d)\n", winEr));
524#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
525 AssertFailed();
526#endif
527 break;
528 }
529
530 if (cbRq != cbReturned)
531 {
532 AssertFailed();
533 break;
534 }
535
536 if (pDr->wTotalLength != cbRq - sizeof (USB_DESCRIPTOR_REQUEST))
537 {
538 AssertFailed();
539 break;
540 }
541
542 *ppDr = pDr;
543 return VINF_SUCCESS;
544 } while (0);
545
546 RTMemFree(pRq);
547 return rc;
548}
549
550static void usbLibDevCfgDrFree(PUSB_CONFIGURATION_DESCRIPTOR pDr)
551{
552 Assert(pDr);
553 PUSB_DESCRIPTOR_REQUEST pRq = ((PUSB_DESCRIPTOR_REQUEST)pDr)-1;
554 RTMemFree(pRq);
555}
556
557static int usbLibDevStrDrEntryGet(HANDLE hHub, ULONG iPort, ULONG iDr, USHORT idLang, PVBOXUSB_STRING_DR_ENTRY *ppList)
558{
559 char Buf[sizeof (USB_DESCRIPTOR_REQUEST) + MAXIMUM_USB_STRING_LENGTH];
560 PUSB_DESCRIPTOR_REQUEST pRq = (PUSB_DESCRIPTOR_REQUEST)Buf;
561 PUSB_STRING_DESCRIPTOR pDr = (PUSB_STRING_DESCRIPTOR)(Buf + sizeof (*pRq));
562 memset (&Buf, 0, sizeof (Buf));
563 pRq->ConnectionIndex = iPort;
564 pRq->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) | iDr;
565 pRq->SetupPacket.wIndex = idLang;
566 pRq->SetupPacket.wLength = sizeof (Buf) - sizeof (*pRq);
567 DWORD cbReturned = 0;
568 if (!DeviceIoControl(hHub, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, pRq, sizeof (Buf),
569 pRq, sizeof (Buf),
570 &cbReturned, NULL))
571 {
572 DWORD winEr = GetLastError();
573 LogRel((__FUNCTION__": DeviceIoControl 1 fail winEr (%d)\n", winEr));
574#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
575 AssertFailed();
576#endif
577 return VERR_GENERAL_FAILURE;
578 }
579
580 if (cbReturned < sizeof (*pDr) + 2)
581 {
582 AssertFailed();
583 return VERR_GENERAL_FAILURE;
584 }
585
586 if (!!(pDr->bLength % 2))
587 {
588 AssertFailed();
589 return VERR_GENERAL_FAILURE;
590 }
591
592 if (pDr->bLength != cbReturned - sizeof (*pRq))
593 {
594 AssertFailed();
595 return VERR_GENERAL_FAILURE;
596 }
597
598 if (pDr->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE)
599 {
600 AssertFailed();
601 return VERR_GENERAL_FAILURE;
602 }
603
604 PVBOXUSB_STRING_DR_ENTRY pEntry = (PVBOXUSB_STRING_DR_ENTRY)RTMemAllocZ(sizeof (*pEntry) + pDr->bLength + 2);
605 Assert(pEntry);
606 if (!pEntry)
607 {
608 return VERR_OUT_OF_RESOURCES;
609 }
610
611 pEntry->pNext = *ppList;
612 pEntry->iDr = iDr;
613 pEntry->idLang = idLang;
614 memcpy(&pEntry->StrDr, pDr, pDr->bLength);
615 *ppList = pEntry;
616 return VINF_SUCCESS;
617}
618
619static void usbLibDevStrDrEntryFree(PVBOXUSB_STRING_DR_ENTRY pDr)
620{
621 RTMemFree(pDr);
622}
623
624static void usbLibDevStrDrEntryFreeList(PVBOXUSB_STRING_DR_ENTRY pDr)
625{
626 while (pDr)
627 {
628 PVBOXUSB_STRING_DR_ENTRY pNext = pDr->pNext;
629 usbLibDevStrDrEntryFree(pDr);
630 pDr = pNext;
631 }
632}
633
634static int usbLibDevStrDrEntryGetForLangs(HANDLE hHub, ULONG iPort, ULONG iDr, ULONG cIdLang, const USHORT *pIdLang, PVBOXUSB_STRING_DR_ENTRY *ppList)
635{
636 for (ULONG i = 0; i < cIdLang; ++i)
637 {
638 usbLibDevStrDrEntryGet(hHub, iPort, iDr, pIdLang[i], ppList);
639 }
640 return VINF_SUCCESS;
641}
642
643static int usbLibDevStrDrEntryGetAll(HANDLE hHub, ULONG iPort, PUSB_DEVICE_DESCRIPTOR pDevDr, PUSB_CONFIGURATION_DESCRIPTOR pCfgDr, PVBOXUSB_STRING_DR_ENTRY *ppList)
644{
645 int rc = usbLibDevStrDrEntryGet(hHub, iPort, 0, 0, ppList);
646#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
647 AssertRC(rc);
648#endif
649 if (RT_FAILURE(rc))
650 return rc;
651
652 PUSB_STRING_DESCRIPTOR pLandStrDr = &(*ppList)->StrDr;
653 USHORT *pIdLang = pLandStrDr->bString;
654 ULONG cIdLang = (pLandStrDr->bLength - RT_OFFSETOF(USB_STRING_DESCRIPTOR, bString)) / sizeof (*pIdLang);
655
656 if (pDevDr->iManufacturer)
657 {
658 rc = usbLibDevStrDrEntryGetForLangs(hHub, iPort, pDevDr->iManufacturer, cIdLang, pIdLang, ppList);
659 AssertRC(rc);
660 }
661
662 if (pDevDr->iProduct)
663 {
664 rc = usbLibDevStrDrEntryGetForLangs(hHub, iPort, pDevDr->iProduct, cIdLang, pIdLang, ppList);
665 AssertRC(rc);
666 }
667
668 if (pDevDr->iSerialNumber)
669 {
670 rc = usbLibDevStrDrEntryGetForLangs(hHub, iPort, pDevDr->iSerialNumber, cIdLang, pIdLang, ppList);
671 AssertRC(rc);
672 }
673
674 PUCHAR pCur = (PUCHAR)pCfgDr;
675 PUCHAR pEnd = pCur + pCfgDr->wTotalLength;
676 while (pCur + sizeof (USB_COMMON_DESCRIPTOR) <= pEnd)
677 {
678 PUSB_COMMON_DESCRIPTOR pCmnDr = (PUSB_COMMON_DESCRIPTOR)pCur;
679 if (pCur + pCmnDr->bLength > pEnd)
680 {
681 AssertFailed();
682 break;
683 }
684
685 switch (pCmnDr->bDescriptorType)
686 {
687 case USB_CONFIGURATION_DESCRIPTOR_TYPE:
688 {
689 if (pCmnDr->bLength != sizeof (USB_CONFIGURATION_DESCRIPTOR))
690 {
691 AssertFailed();
692 break;
693 }
694 PUSB_CONFIGURATION_DESCRIPTOR pCurCfgDr = (PUSB_CONFIGURATION_DESCRIPTOR)pCmnDr;
695 if (!pCurCfgDr->iConfiguration)
696 break;
697 rc = usbLibDevStrDrEntryGetForLangs(hHub, iPort, pCurCfgDr->iConfiguration, cIdLang, pIdLang, ppList);
698 AssertRC(rc);
699 break;
700 }
701 case USB_INTERFACE_DESCRIPTOR_TYPE:
702 {
703 if (pCmnDr->bLength != sizeof (USB_INTERFACE_DESCRIPTOR) && pCmnDr->bLength != sizeof (USB_INTERFACE_DESCRIPTOR2))
704 {
705 AssertFailed();
706 break;
707 }
708 PUSB_INTERFACE_DESCRIPTOR pCurIfDr = (PUSB_INTERFACE_DESCRIPTOR)pCmnDr;
709 if (!pCurIfDr->iInterface)
710 break;
711 rc = usbLibDevStrDrEntryGetForLangs(hHub, iPort, pCurIfDr->iInterface, cIdLang, pIdLang, ppList);
712 AssertRC(rc);
713 break;
714 }
715 default:
716 break;
717 }
718
719 pCur = pCur + pCmnDr->bLength;
720 }
721
722 return VINF_SUCCESS;
723}
724
725static int usbLibDevGetHubDevices(LPCSTR lpszName, PUSBDEVICE *ppDevs, uint32_t *pcDevs);
726
727static int usbLibDevGetHubPortDevices(HANDLE hHub, LPCSTR lpcszHubName, ULONG iPort, PUSBDEVICE *ppDevs, uint32_t *pcDevs)
728{
729 int rc = VINF_SUCCESS;
730 char Buf[sizeof (USB_NODE_CONNECTION_INFORMATION_EX) + (sizeof (USB_PIPE_INFO) * 20)];
731 PUSB_NODE_CONNECTION_INFORMATION_EX pConInfo = (PUSB_NODE_CONNECTION_INFORMATION_EX)Buf;
732 PUSB_PIPE_INFO paPipeInfo = (PUSB_PIPE_INFO)(Buf + sizeof (PUSB_NODE_CONNECTION_INFORMATION_EX));
733 DWORD cbReturned = 0;
734 memset(&Buf, 0, sizeof (Buf));
735 pConInfo->ConnectionIndex = iPort;
736 if (!DeviceIoControl(hHub, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
737 pConInfo, sizeof (Buf),
738 pConInfo, sizeof (Buf),
739 &cbReturned, NULL))
740 {
741 DWORD winEr = GetLastError();
742 AssertMsg(winEr == ERROR_DEVICE_NOT_CONNECTED, (__FUNCTION__": DeviceIoControl failed winEr (%d)\n", winEr));
743 return VERR_GENERAL_FAILURE;
744 }
745
746 if (pConInfo->ConnectionStatus != DeviceConnected)
747 {
748 /* just ignore & return success */
749 return VWRN_INVALID_HANDLE;
750 }
751
752 if (pConInfo->DeviceIsHub)
753 {
754 LPSTR lpszHubName = NULL;
755 rc = usbLibDevStrHubNameGet(hHub, iPort, &lpszHubName);
756 AssertRC(rc);
757 if (RT_SUCCESS(rc))
758 {
759 rc = usbLibDevGetHubDevices(lpszHubName, ppDevs, pcDevs);
760 usbLibDevStrFree(lpszHubName);
761 AssertRC(rc);
762 return rc;
763 }
764 /* ignore this err */
765 return VINF_SUCCESS;
766 }
767
768 bool fFreeNameBuf = true;
769 char nameEmptyBuf = '\0';
770 LPSTR lpszName = NULL;
771 rc = usbLibDevStrDriverKeyGet(hHub, iPort, &lpszName);
772 Assert(!!lpszName == !!RT_SUCCESS(rc));
773 if (!lpszName)
774 {
775 lpszName = &nameEmptyBuf;
776 fFreeNameBuf = false;
777 }
778
779 PUSB_CONFIGURATION_DESCRIPTOR pCfgDr = NULL;
780 PVBOXUSB_STRING_DR_ENTRY pList = NULL;
781 rc = usbLibDevCfgDrGet(hHub, iPort, 0, &pCfgDr);
782 if (pCfgDr)
783 {
784 rc = usbLibDevStrDrEntryGetAll(hHub, iPort, &pConInfo->DeviceDescriptor, pCfgDr, &pList);
785#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
786 AssertRC(rc);
787#endif
788 }
789
790 PUSBDEVICE pDev = (PUSBDEVICE)RTMemAllocZ(sizeof (*pDev));
791 rc = usbLibDevPopulate(pDev, pConInfo, iPort, lpszName, lpcszHubName, pList);
792 AssertRC(rc);
793 if (RT_SUCCESS(rc))
794 {
795 pDev->pNext = *ppDevs;
796 *ppDevs = pDev;
797 ++*pcDevs;
798 }
799
800 if (pCfgDr)
801 usbLibDevCfgDrFree(pCfgDr);
802 if (fFreeNameBuf)
803 {
804 Assert(lpszName);
805 usbLibDevStrFree(lpszName);
806 }
807 if (pList)
808 usbLibDevStrDrEntryFreeList(pList);
809
810 return VINF_SUCCESS;
811}
812
813static int usbLibDevGetHubDevices(LPCSTR lpszName, PUSBDEVICE *ppDevs, uint32_t *pcDevs)
814{
815 LPSTR lpszDevName = (LPSTR)RTMemAllocZ(strlen(lpszName) + sizeof("\\\\.\\"));
816 HANDLE hDev = INVALID_HANDLE_VALUE;
817 Assert(lpszDevName);
818 if (!lpszDevName)
819 {
820 AssertFailed();
821 return VERR_OUT_OF_RESOURCES;
822 }
823
824 int rc = VINF_SUCCESS;
825 strcpy(lpszDevName, "\\\\.\\");
826 strcpy(lpszDevName + sizeof("\\\\.\\") - sizeof (lpszDevName[0]), lpszName);
827 do
828 {
829 DWORD cbReturned = 0;
830 hDev = CreateFile(lpszDevName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
831 if (hDev == INVALID_HANDLE_VALUE)
832 {
833 AssertFailed();
834 break;
835 }
836
837 USB_NODE_INFORMATION NodeInfo;
838 memset(&NodeInfo, 0, sizeof (NodeInfo));
839 if (!DeviceIoControl(hDev, IOCTL_USB_GET_NODE_INFORMATION,
840 &NodeInfo, sizeof (NodeInfo),
841 &NodeInfo, sizeof (NodeInfo),
842 &cbReturned, NULL))
843 {
844 AssertFailed();
845 break;
846 }
847
848 for (ULONG i = 1; i <= NodeInfo.u.HubInformation.HubDescriptor.bNumberOfPorts; ++i)
849 {
850 usbLibDevGetHubPortDevices(hDev, lpszName, i, ppDevs, pcDevs);
851 }
852 } while (0);
853
854 if (hDev != INVALID_HANDLE_VALUE)
855 CloseHandle(hDev);
856
857 RTMemFree(lpszDevName);
858
859 return rc;
860}
861
862static int usbLibDevGetDevices(PUSBDEVICE *ppDevs, uint32_t *pcDevs)
863{
864 char CtlName[16];
865 int rc = VINF_SUCCESS;
866
867 for (int i = 0; i < 10; ++i)
868 {
869 sprintf(CtlName, "\\\\.\\HCD%d", i);
870 HANDLE hCtl = CreateFile(CtlName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
871 if (hCtl != INVALID_HANDLE_VALUE)
872 {
873 char* lpszName;
874 rc = usbLibDevStrRootHubNameGet(hCtl, &lpszName);
875 AssertRC(rc);
876 if (RT_SUCCESS(rc))
877 {
878 rc = usbLibDevGetHubDevices(lpszName, ppDevs, pcDevs);
879 AssertRC(rc);
880 usbLibDevStrFree(lpszName);
881 }
882 CloseHandle(hCtl);
883 if (RT_FAILURE(rc))
884 break;
885 }
886 }
887 return VINF_SUCCESS;
888}
889
890static PUSBSUP_GET_DEVICES usbLibMonGetDevRqAlloc(uint32_t cDevs, PDWORD pcbRq)
891{
892 DWORD cbRq = RT_OFFSETOF(USBSUP_GET_DEVICES, aDevices[cDevs]);
893 PUSBSUP_GET_DEVICES pRq = (PUSBSUP_GET_DEVICES)RTMemAllocZ(cbRq);
894 Assert(pRq);
895 if (!pRq)
896 return NULL;
897 pRq->cDevices = cDevs;
898 *pcbRq = cbRq;
899 return pRq;
900}
901
902static int usbLibMonDevicesCmp(PUSBDEVICE pDev, PVBOXUSB_DEV pDevInfo)
903{
904 int iDiff;
905 iDiff = strcmp(pDev->pszAddress, pDevInfo->szDriverRegName);
906 return iDiff;
907}
908
909static int usbLibMonDevicesUpdate(PVBOXUSBGLOBALSTATE pGlobal, PUSBDEVICE pDevs, uint32_t cDevs, PVBOXUSB_DEV pDevInfos, uint32_t cDevInfos)
910{
911 PUSBDEVICE pDevsHead = pDevs;
912 for (; pDevInfos; pDevInfos = pDevInfos->pNext)
913 {
914 for (pDevs = pDevsHead; pDevs; pDevs = pDevs->pNext)
915 {
916 if (usbLibMonDevicesCmp(pDevs, pDevInfos))
917 continue;
918
919 if (!pDevInfos->szDriverRegName[0])
920 {
921 AssertFailed();
922 break;
923 }
924
925 USBSUP_GETDEV Dev = {0};
926 HANDLE hDev = CreateFile(pDevInfos->szName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
927 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
928 if (hDev == INVALID_HANDLE_VALUE)
929 {
930 AssertFailed();
931 break;
932 }
933
934 DWORD cbReturned = 0;
935 if (!DeviceIoControl(hDev, SUPUSB_IOCTL_GET_DEVICE, &Dev, sizeof (Dev), &Dev, sizeof (Dev), &cbReturned, NULL))
936 {
937 DWORD winEr = GetLastError();
938 /* ERROR_DEVICE_NOT_CONNECTED -> device was removed just now */
939#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
940 AssertMsg(winEr == ERROR_DEVICE_NOT_CONNECTED, (__FUNCTION__": DeviceIoControl failed winEr (%d)\n", winEr));
941#endif
942 Log(("SUPUSB_IOCTL_GET_DEVICE: DeviceIoControl no longer connected\n"));
943 CloseHandle(hDev);
944 break;
945 }
946
947 /* we must not close the handle until we request for the device state from the monitor to ensure
948 * the device handle returned by the device driver does not disappear */
949 Assert(Dev.hDevice);
950 USBSUP_GETDEV_MON MonInfo;
951 HVBOXUSBDEVUSR hDevice = Dev.hDevice;
952 if (!DeviceIoControl(pGlobal->hMonitor, SUPUSBFLT_IOCTL_GET_DEVICE, &hDevice, sizeof (hDevice), &MonInfo, sizeof (MonInfo), &cbReturned, NULL))
953 {
954 DWORD winEr = GetLastError();
955 /* ERROR_DEVICE_NOT_CONNECTED -> device was removed just now */
956 AssertMsgFailed((__FUNCTION__": Monitor DeviceIoControl failed winEr (%d)\n", winEr));
957 Log(("SUPUSBFLT_IOCTL_GET_DEVICE: DeviceIoControl no longer connected\n"));
958 CloseHandle(hDev);
959 break;
960 }
961
962 CloseHandle(hDev);
963
964 /* success!! update device info */
965 /* ensure the state returned is valid */
966 Assert( MonInfo.enmState == USBDEVICESTATE_USED_BY_HOST
967 || MonInfo.enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
968 || MonInfo.enmState == USBDEVICESTATE_UNUSED
969 || MonInfo.enmState == USBDEVICESTATE_HELD_BY_PROXY
970 || MonInfo.enmState == USBDEVICESTATE_USED_BY_GUEST);
971 pDevs->enmState = MonInfo.enmState;
972 /* The following is not 100% accurate but we only care about high-speed vs. non-high-speed */
973 pDevs->enmSpeed = Dev.fHiSpeed ? USBDEVICESPEED_HIGH : USBDEVICESPEED_FULL;
974 if (pDevs->enmState != USBDEVICESTATE_USED_BY_HOST)
975 {
976 /* only set the interface name if device can be grabbed */
977 RTStrFree(pDevs->pszAltAddress);
978 pDevs->pszAltAddress = (char*)pDevs->pszAddress;
979 pDevs->pszAddress = RTStrDup(pDevInfos->szName);
980 }
981#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
982 else
983 {
984 /* dbg breakpoint */
985 Assert(0);
986 }
987#endif
988
989 /* we've found the device, break in any way */
990 break;
991 }
992 }
993
994 return VINF_SUCCESS;
995}
996
997static int usbLibGetDevices(PVBOXUSBGLOBALSTATE pGlobal, PUSBDEVICE *ppDevs, uint32_t *pcDevs)
998{
999 *ppDevs = NULL;
1000 *pcDevs = 0;
1001
1002 int rc = usbLibDevGetDevices(ppDevs, pcDevs);
1003 AssertRC(rc);
1004 if (RT_SUCCESS(rc))
1005 {
1006 PVBOXUSB_DEV pDevInfos = NULL;
1007 uint32_t cDevInfos = 0;
1008 rc = usbLibVuGetDevices(&pDevInfos, &cDevInfos);
1009 AssertRC(rc);
1010 if (RT_SUCCESS(rc))
1011 {
1012 rc = usbLibMonDevicesUpdate(pGlobal, *ppDevs, *pcDevs, pDevInfos, cDevInfos);
1013 AssertRC(rc);
1014 usbLibVuFreeDevices(pDevInfos);
1015 }
1016
1017 return VINF_SUCCESS;
1018 }
1019 return rc;
1020}
1021
1022AssertCompile(INFINITE == RT_INDEFINITE_WAIT);
1023static int usbLibStateWaitChange(PVBOXUSBGLOBALSTATE pGlobal, RTMSINTERVAL cMillies)
1024{
1025 HANDLE ahEvents[] = {pGlobal->hNotifyEvent, pGlobal->hInterruptEvent};
1026 DWORD dwResult = WaitForMultipleObjects(RT_ELEMENTS(ahEvents), ahEvents,
1027 FALSE, /* BOOL bWaitAll */
1028 cMillies);
1029
1030 switch (dwResult)
1031 {
1032 case WAIT_OBJECT_0:
1033 return VINF_SUCCESS;
1034 case WAIT_OBJECT_0 + 1:
1035 return VERR_INTERRUPTED;
1036 case WAIT_TIMEOUT:
1037 return VERR_TIMEOUT;
1038 default:
1039 {
1040 DWORD winEr = GetLastError();
1041 AssertMsgFailed((__FUNCTION__": WaitForMultipleObjects failed, winEr (%d)\n", winEr));
1042 return VERR_GENERAL_FAILURE;
1043 }
1044 }
1045}
1046
1047AssertCompile(RT_INDEFINITE_WAIT == INFINITE);
1048AssertCompile(sizeof (RTMSINTERVAL) == sizeof (DWORD));
1049USBLIB_DECL(int) USBLibWaitChange(RTMSINTERVAL msWaitTimeout)
1050{
1051 return usbLibStateWaitChange(&g_VBoxUsbGlobal, msWaitTimeout);
1052}
1053
1054static int usbLibInterruptWaitChange(PVBOXUSBGLOBALSTATE pGlobal)
1055{
1056 BOOL bRc = SetEvent(pGlobal->hInterruptEvent);
1057 if (!bRc)
1058 {
1059 DWORD winEr = GetLastError();
1060 AssertMsgFailed((__FUNCTION__": SetEvent failed, winEr (%d)\n", winEr));
1061 return VERR_GENERAL_FAILURE;
1062 }
1063 return VINF_SUCCESS;
1064}
1065
1066USBLIB_DECL(int) USBLibInterruptWaitChange()
1067{
1068 return usbLibInterruptWaitChange(&g_VBoxUsbGlobal);
1069}
1070
1071/*
1072USBLIB_DECL(bool) USBLibHasPendingDeviceChanges(void)
1073{
1074 int rc = USBLibWaitChange(0);
1075 return rc == VINF_SUCCESS;
1076}
1077*/
1078
1079USBLIB_DECL(int) USBLibGetDevices(PUSBDEVICE *ppDevices, uint32_t *pcbNumDevices)
1080{
1081 Assert(g_VBoxUsbGlobal.hMonitor != INVALID_HANDLE_VALUE);
1082 return usbLibGetDevices(&g_VBoxUsbGlobal, ppDevices, pcbNumDevices);
1083}
1084
1085USBLIB_DECL(void *) USBLibAddFilter(PCUSBFILTER pFilter)
1086{
1087 USBSUP_FLTADDOUT FltAddRc;
1088 DWORD cbReturned = 0;
1089
1090 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
1091 {
1092#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1093 AssertFailed();
1094#endif
1095 return NULL;
1096 }
1097
1098 Log(("usblibInsertFilter: Manufacturer=%s Product=%s Serial=%s\n",
1099 USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
1100 USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
1101 USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
1102
1103 if (!DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_ADD_FILTER,
1104 (LPVOID)pFilter, sizeof(*pFilter),
1105 &FltAddRc, sizeof(FltAddRc),
1106 &cbReturned, NULL))
1107 {
1108 DWORD winEr = GetLastError();
1109 AssertMsgFailed(("DeviceIoControl failed with winEr (%d(\n", winEr));
1110 return NULL;
1111 }
1112
1113 if (RT_FAILURE(FltAddRc.rc))
1114 {
1115 AssertMsgFailed(("Adding filter failed with %d\n", FltAddRc.rc));
1116 return NULL;
1117 }
1118 return (void *)FltAddRc.uId;
1119}
1120
1121
1122USBLIB_DECL(void) USBLibRemoveFilter(void *pvId)
1123{
1124 uintptr_t uId;
1125 DWORD cbReturned = 0;
1126
1127 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
1128 {
1129#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1130 AssertFailed();
1131#endif
1132 return;
1133 }
1134
1135 Log(("usblibRemoveFilter %p\n", pvId));
1136
1137 uId = (uintptr_t)pvId;
1138 if (!DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_REMOVE_FILTER, &uId, sizeof(uId), NULL, 0,&cbReturned, NULL))
1139 AssertMsgFailed(("DeviceIoControl failed with LastError=%Rwa\n", GetLastError()));
1140}
1141
1142USBLIB_DECL(int) USBLibRunFilters()
1143{
1144 DWORD cbReturned = 0;
1145
1146 Assert(g_VBoxUsbGlobal.hMonitor != INVALID_HANDLE_VALUE);
1147
1148 if (!DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_RUN_FILTERS,
1149 NULL, 0,
1150 NULL, 0,
1151 &cbReturned, NULL))
1152 {
1153 DWORD winEr = GetLastError();
1154 AssertMsgFailed(("DeviceIoControl failed with winEr (%d(\n", winEr));
1155 return RTErrConvertFromWin32(winEr);
1156 }
1157
1158 return VINF_SUCCESS;
1159}
1160
1161
1162#ifdef VBOX_USB_USE_DEVICE_NOTIFICATION
1163
1164static VOID CALLBACK usbLibTimerCallback(
1165 __in PVOID lpParameter,
1166 __in BOOLEAN TimerOrWaitFired
1167 )
1168{
1169 SetEvent(g_VBoxUsbGlobal.hNotifyEvent);
1170}
1171
1172static void usbLibOnDeviceChange()
1173{
1174 /* we're getting series of events like that especially on device re-attach
1175 * (i.e. first for device detach and then for device attach)
1176 * unfortunately the event does not tell us what actually happened.
1177 * To avoid extra notifications, we delay the SetEvent via a timer
1178 * and update the timer if additional notification comes before the timer fires
1179 * */
1180 if (g_VBoxUsbGlobal.hTimer)
1181 {
1182 if (!DeleteTimerQueueTimer(g_VBoxUsbGlobal.hTimerQueue, g_VBoxUsbGlobal.hTimer, NULL))
1183 {
1184 DWORD winEr = GetLastError();
1185 AssertMsg(winEr == ERROR_IO_PENDING, (__FUNCTION__": DeleteTimerQueueTimer failed, winEr (%d)\n", winEr));
1186 }
1187 }
1188
1189 if (!CreateTimerQueueTimer(&g_VBoxUsbGlobal.hTimer, g_VBoxUsbGlobal.hTimerQueue,
1190 usbLibTimerCallback,
1191 NULL,
1192 500, /* ms*/
1193 0,
1194 WT_EXECUTEONLYONCE))
1195 {
1196 DWORD winEr = GetLastError();
1197 AssertMsgFailed((__FUNCTION__": CreateTimerQueueTimer failed, winEr (%d)\n", winEr));
1198
1199 /* call it directly */
1200 usbLibTimerCallback(NULL, FALSE);
1201 }
1202}
1203
1204static LRESULT CALLBACK usbLibWndProc(HWND hwnd,
1205 UINT uMsg,
1206 WPARAM wParam,
1207 LPARAM lParam
1208)
1209{
1210 switch (uMsg)
1211 {
1212 case WM_DEVICECHANGE:
1213 if (wParam == DBT_DEVNODES_CHANGED)
1214 {
1215 /* we notify change any device arivals/removals on the system
1216 * and let the client decide whether the usb change actually happened
1217 * so far this is more clean than reporting events from the Monitor
1218 * because monitor sees only PDO arrivals/removals,
1219 * and by the time PDO is created, device can not
1220 * be yet started and fully functional,
1221 * so usblib won't be able to pick it up
1222 * */
1223
1224 usbLibOnDeviceChange();
1225 }
1226 break;
1227 case WM_DESTROY:
1228 return 0;
1229 }
1230 return DefWindowProc (hwnd, uMsg, wParam, lParam);
1231}
1232
1233static LPCSTR g_VBoxUsbWndClassName = "VBoxUsbLibClass";
1234
1235static DWORD WINAPI usbLibMsgThreadProc(__in LPVOID lpParameter)
1236{
1237 HWND hwnd = 0;
1238 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle (NULL);
1239 bool bExit = false;
1240
1241 /* Register the Window Class. */
1242 WNDCLASS wc;
1243 wc.style = 0;
1244 wc.lpfnWndProc = usbLibWndProc;
1245 wc.cbClsExtra = 0;
1246 wc.cbWndExtra = sizeof(void *);
1247 wc.hInstance = hInstance;
1248 wc.hIcon = NULL;
1249 wc.hCursor = NULL;
1250 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
1251 wc.lpszMenuName = NULL;
1252 wc.lpszClassName = g_VBoxUsbWndClassName;
1253
1254 ATOM atomWindowClass = RegisterClass(&wc);
1255
1256 if (atomWindowClass != 0)
1257 {
1258 /* Create the window. */
1259 g_VBoxUsbGlobal.hWnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
1260 g_VBoxUsbWndClassName, g_VBoxUsbWndClassName,
1261 WS_POPUPWINDOW,
1262 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
1263 SetEvent(g_VBoxUsbGlobal.hNotifyEvent);
1264
1265 if (g_VBoxUsbGlobal.hWnd)
1266 {
1267 SetWindowPos(hwnd, HWND_TOPMOST, -200, -200, 0, 0,
1268 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
1269
1270 MSG msg;
1271 while (GetMessage(&msg, NULL, 0, 0))
1272 {
1273 TranslateMessage(&msg);
1274 DispatchMessage(&msg);
1275 }
1276
1277 DestroyWindow (hwnd);
1278
1279 bExit = true;
1280 }
1281
1282 UnregisterClass (g_VBoxUsbWndClassName, hInstance);
1283 }
1284
1285 if(bExit)
1286 {
1287 /* no need any accuracy here, in anyway the DHCP server usually gets terminated with TerminateProcess */
1288 exit(0);
1289 }
1290
1291 return 0;
1292}
1293#endif
1294
1295/**
1296 * Initialize the USB library
1297 *
1298 * @returns VBox status code.
1299 */
1300USBLIB_DECL(int) USBLibInit(void)
1301{
1302 int rc = VERR_GENERAL_FAILURE;
1303
1304 Log(("usbproxy: usbLibInit\n"));
1305
1306 memset(&g_VBoxUsbGlobal, 0, sizeof (g_VBoxUsbGlobal));
1307
1308 g_VBoxUsbGlobal.hMonitor = INVALID_HANDLE_VALUE;
1309
1310 g_VBoxUsbGlobal.hNotifyEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes */
1311 FALSE, /* BOOL bManualReset */
1312#ifndef VBOX_USB_USE_DEVICE_NOTIFICATION
1313 TRUE, /* BOOL bInitialState */
1314#else
1315 FALSE, /* set to false since it will be initially used for notification thread startup sync */
1316#endif
1317 NULL /* LPCTSTR lpName */);
1318 if (g_VBoxUsbGlobal.hNotifyEvent)
1319 {
1320 g_VBoxUsbGlobal.hInterruptEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes */
1321 FALSE, /* BOOL bManualReset */
1322 FALSE, /* BOOL bInitialState */
1323 NULL /* LPCTSTR lpName */);
1324 if (g_VBoxUsbGlobal.hInterruptEvent)
1325 {
1326 g_VBoxUsbGlobal.hMonitor = CreateFile(USBMON_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1327 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
1328
1329 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
1330 {
1331 HRESULT hr = VBoxDrvCfgSvcStart(USBMON_SERVICE_NAME_W);
1332 if (hr == S_OK)
1333 {
1334 g_VBoxUsbGlobal.hMonitor = CreateFile(USBMON_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
1335 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
1336 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
1337 {
1338 DWORD winEr = GetLastError();
1339 LogRel((__FUNCTION__": CreateFile failed winEr(%d)\n", winEr));
1340 rc = VERR_FILE_NOT_FOUND;
1341 }
1342 }
1343 }
1344
1345 if (g_VBoxUsbGlobal.hMonitor != INVALID_HANDLE_VALUE)
1346 {
1347 USBSUP_VERSION Version = {0};
1348 DWORD cbReturned = 0;
1349
1350 if (DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_GET_VERSION, NULL, 0, &Version, sizeof (Version), &cbReturned, NULL))
1351 {
1352 if (Version.u32Major == USBMON_MAJOR_VERSION || Version.u32Minor <= USBMON_MINOR_VERSION)
1353 {
1354#ifndef VBOX_USB_USE_DEVICE_NOTIFICATION
1355 USBSUP_SET_NOTIFY_EVENT SetEvent = {0};
1356 Assert(g_VBoxUsbGlobal.hNotifyEvent);
1357 SetEvent.u.hEvent = g_VBoxUsbGlobal.hNotifyEvent;
1358 if (DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_SET_NOTIFY_EVENT,
1359 &SetEvent, sizeof (SetEvent),
1360 &SetEvent, sizeof (SetEvent),
1361 &cbReturned, NULL))
1362 {
1363 rc = SetEvent.u.rc;
1364 AssertRC(rc);
1365 if (RT_SUCCESS(rc))
1366 return VINF_SUCCESS;
1367 else
1368 AssertMsgFailed((__FUNCTION__": SetEvent failed, rc (%d)\n", rc));
1369 }
1370 else
1371 {
1372 DWORD winEr = GetLastError();
1373 AssertMsgFailed((__FUNCTION__": SetEvent Ioctl failed, winEr (%d)\n", winEr));
1374 rc = VERR_VERSION_MISMATCH;
1375 }
1376#else
1377 g_VBoxUsbGlobal.hTimerQueue = CreateTimerQueue();
1378 if (g_VBoxUsbGlobal.hTimerQueue)
1379 {
1380 g_VBoxUsbGlobal.hThread = CreateThread(
1381 NULL, /*__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, */
1382 0, /*__in SIZE_T dwStackSize, */
1383 usbLibMsgThreadProc, /*__in LPTHREAD_START_ROUTINE lpStartAddress,*/
1384 NULL, /*__in_opt LPVOID lpParameter,*/
1385 0, /*__in DWORD dwCreationFlags,*/
1386 NULL /*__out_opt LPDWORD lpThreadId*/
1387 );
1388
1389 if(g_VBoxUsbGlobal.hThread)
1390 {
1391 DWORD dwResult = WaitForSingleObject(g_VBoxUsbGlobal.hNotifyEvent, INFINITE);
1392 Assert(dwResult == WAIT_OBJECT_0);
1393
1394 if (g_VBoxUsbGlobal.hWnd)
1395 {
1396 /* ensure the event is set so the first "wait change" request processes */
1397 SetEvent(g_VBoxUsbGlobal.hNotifyEvent);
1398 return VINF_SUCCESS;
1399 }
1400 dwResult = WaitForSingleObject(g_VBoxUsbGlobal.hThread, INFINITE);
1401 Assert(dwResult == WAIT_OBJECT_0);
1402 BOOL bRc = CloseHandle(g_VBoxUsbGlobal.hThread);
1403 if (!bRc)
1404 {
1405 DWORD winEr = GetLastError();
1406 AssertMsgFailed((__FUNCTION__": CloseHandle for hThread failed winEr(%d)\n", winEr));
1407 }
1408 }
1409 else
1410 {
1411 DWORD winEr = GetLastError();
1412 AssertMsgFailed((__FUNCTION__": CreateThread failed, winEr (%d)\n", winEr));
1413 rc = VERR_GENERAL_FAILURE;
1414 }
1415 }
1416 else
1417 {
1418 DWORD winEr = GetLastError();
1419 AssertMsgFailed((__FUNCTION__": CreateTimerQueue failed winEr(%d)\n", winEr));
1420 }
1421#endif
1422 }
1423 else
1424 {
1425 LogRel((__FUNCTION__": Monitor driver version mismatch!!\n"));
1426#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1427 AssertFailed();
1428#endif
1429 rc = VERR_VERSION_MISMATCH;
1430 }
1431 }
1432 else
1433 {
1434 DWORD winEr = GetLastError();
1435 AssertMsgFailed((__FUNCTION__": DeviceIoControl failed winEr(%d)\n", winEr));
1436 rc = VERR_VERSION_MISMATCH;
1437 }
1438
1439 CloseHandle(g_VBoxUsbGlobal.hMonitor);
1440 }
1441 else
1442 {
1443 LogRel((__FUNCTION__": USB Service not found\n"));
1444#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1445 AssertFailed();
1446#endif
1447 rc = VERR_FILE_NOT_FOUND;
1448 }
1449
1450 CloseHandle(g_VBoxUsbGlobal.hInterruptEvent);
1451 }
1452 else
1453 {
1454 DWORD winEr = GetLastError();
1455 AssertMsgFailed((__FUNCTION__": CreateEvent for InterruptEvent failed winEr(%d)\n", winEr));
1456 rc = VERR_GENERAL_FAILURE;
1457 }
1458
1459 CloseHandle(g_VBoxUsbGlobal.hNotifyEvent);
1460 }
1461 else
1462 {
1463 DWORD winEr = GetLastError();
1464 AssertMsgFailed((__FUNCTION__": CreateEvent for NotifyEvent failed winEr(%d)\n", winEr));
1465 rc = VERR_GENERAL_FAILURE;
1466 }
1467
1468 /* since main calls us even if USBLibInit fails,
1469 * we use hMonitor == INVALID_HANDLE_VALUE as a marker to indicate whether the lib is inited */
1470
1471 Assert(RT_FAILURE(rc));
1472 return rc;
1473}
1474
1475
1476/**
1477 * Terminate the USB library
1478 *
1479 * @returns VBox status code.
1480 */
1481USBLIB_DECL(int) USBLibTerm(void)
1482{
1483 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
1484 {
1485#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1486 AssertFailed();
1487#endif
1488 return VINF_ALREADY_INITIALIZED;
1489 }
1490
1491 BOOL bRc;
1492#ifdef VBOX_USB_USE_DEVICE_NOTIFICATION
1493 bRc= PostMessage(g_VBoxUsbGlobal.hWnd, WM_QUIT, 0, 0);
1494 if (!bRc)
1495 {
1496 DWORD winEr = GetLastError();
1497 AssertMsgFailed((__FUNCTION__": PostMessage for hWnd failed winEr(%d)\n", winEr));
1498 }
1499
1500 DWORD dwResult = WaitForSingleObject(g_VBoxUsbGlobal.hThread, INFINITE);
1501 Assert(dwResult == WAIT_OBJECT_0);
1502 bRc = CloseHandle(g_VBoxUsbGlobal.hThread);
1503 if (!bRc)
1504 {
1505 DWORD winEr = GetLastError();
1506 AssertMsgFailed((__FUNCTION__": CloseHandle for hThread failed winEr(%d)\n", winEr));
1507 }
1508
1509 if (g_VBoxUsbGlobal.hTimer)
1510 {
1511 bRc = DeleteTimerQueueTimer(g_VBoxUsbGlobal.hTimerQueue, g_VBoxUsbGlobal.hTimer,
1512 INVALID_HANDLE_VALUE /* <-- to block until the timer is completed */
1513 );
1514 if (!bRc)
1515 {
1516 DWORD winEr = GetLastError();
1517 AssertMsgFailed((__FUNCTION__": DeleteTimerQueueEx failed winEr(%d)\n", winEr));
1518 }
1519 }
1520
1521 bRc = DeleteTimerQueueEx(g_VBoxUsbGlobal.hTimerQueue,
1522 INVALID_HANDLE_VALUE /* <-- to block until all timers are completed */
1523 );
1524 if (!bRc)
1525 {
1526 DWORD winEr = GetLastError();
1527 AssertMsgFailed((__FUNCTION__": DeleteTimerQueueEx failed winEr(%d)\n", winEr));
1528 }
1529#endif
1530
1531 bRc = CloseHandle(g_VBoxUsbGlobal.hMonitor);
1532 if (!bRc)
1533 {
1534 DWORD winEr = GetLastError();
1535 AssertMsgFailed((__FUNCTION__": CloseHandle for hMonitor failed winEr(%d)\n", winEr));
1536 }
1537
1538 bRc = CloseHandle(g_VBoxUsbGlobal.hInterruptEvent);
1539 if (!bRc)
1540 {
1541 DWORD winEr = GetLastError();
1542 AssertMsgFailed((__FUNCTION__": CloseHandle for hInterruptEvent failed winEr(%d)\n", winEr));
1543 }
1544
1545 bRc = CloseHandle(g_VBoxUsbGlobal.hNotifyEvent);
1546 if (!bRc)
1547 {
1548 DWORD winEr = GetLastError();
1549 AssertMsgFailed((__FUNCTION__": CloseHandle for hNotifyEvent failed winEr(%d)\n", winEr));
1550 }
1551
1552 return VINF_SUCCESS;
1553}
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