VirtualBox

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

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

usb/win: close handle

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.8 KB
Line 
1/* $Id: VBoxUsbLib-win.cpp 37431 2011-06-14 09:32:05Z 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 LPSTR lpszName = NULL;
769 rc = usbLibDevStrDriverKeyGet(hHub, iPort, &lpszName);
770 if (RT_FAILURE(rc))
771 {
772 return rc;
773 }
774
775 Assert(lpszName);
776
777 PUSB_CONFIGURATION_DESCRIPTOR pCfgDr = NULL;
778 PVBOXUSB_STRING_DR_ENTRY pList = NULL;
779 rc = usbLibDevCfgDrGet(hHub, iPort, 0, &pCfgDr);
780 if (pCfgDr)
781 {
782 rc = usbLibDevStrDrEntryGetAll(hHub, iPort, &pConInfo->DeviceDescriptor, pCfgDr, &pList);
783#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
784 AssertRC(rc);
785#endif
786 }
787
788 PUSBDEVICE pDev = (PUSBDEVICE)RTMemAllocZ(sizeof (*pDev));
789 rc = usbLibDevPopulate(pDev, pConInfo, iPort, lpszName, lpcszHubName, pList);
790 AssertRC(rc);
791 if (RT_SUCCESS(rc))
792 {
793 pDev->pNext = *ppDevs;
794 *ppDevs = pDev;
795 ++*pcDevs;
796 }
797
798 if (pCfgDr)
799 usbLibDevCfgDrFree(pCfgDr);
800 if (lpszName)
801 usbLibDevStrFree(lpszName);
802 if (pList)
803 usbLibDevStrDrEntryFreeList(pList);
804
805 return VINF_SUCCESS;
806}
807
808static int usbLibDevGetHubDevices(LPCSTR lpszName, PUSBDEVICE *ppDevs, uint32_t *pcDevs)
809{
810 LPSTR lpszDevName = (LPSTR)RTMemAllocZ(strlen(lpszName) + sizeof("\\\\.\\"));
811 HANDLE hDev = INVALID_HANDLE_VALUE;
812 Assert(lpszDevName);
813 if (!lpszDevName)
814 {
815 AssertFailed();
816 return VERR_OUT_OF_RESOURCES;
817 }
818
819 int rc = VINF_SUCCESS;
820 strcpy(lpszDevName, "\\\\.\\");
821 strcpy(lpszDevName + sizeof("\\\\.\\") - sizeof (lpszDevName[0]), lpszName);
822 do
823 {
824 DWORD cbReturned = 0;
825 hDev = CreateFile(lpszDevName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
826 if (hDev == INVALID_HANDLE_VALUE)
827 {
828 AssertFailed();
829 break;
830 }
831
832 USB_NODE_INFORMATION NodeInfo;
833 memset(&NodeInfo, 0, sizeof (NodeInfo));
834 if (!DeviceIoControl(hDev, IOCTL_USB_GET_NODE_INFORMATION,
835 &NodeInfo, sizeof (NodeInfo),
836 &NodeInfo, sizeof (NodeInfo),
837 &cbReturned, NULL))
838 {
839 AssertFailed();
840 break;
841 }
842
843 for (ULONG i = 1; i <= NodeInfo.u.HubInformation.HubDescriptor.bNumberOfPorts; ++i)
844 {
845 usbLibDevGetHubPortDevices(hDev, lpszName, i, ppDevs, pcDevs);
846 }
847 } while (0);
848
849 if (hDev != INVALID_HANDLE_VALUE)
850 CloseHandle(hDev);
851
852 RTMemFree(lpszDevName);
853
854 return rc;
855}
856
857static int usbLibDevGetDevices(PUSBDEVICE *ppDevs, uint32_t *pcDevs)
858{
859 char CtlName[16];
860 int rc = VINF_SUCCESS;
861
862 for (int i = 0; i < 10; ++i)
863 {
864 sprintf(CtlName, "\\\\.\\HCD%d", i);
865 HANDLE hCtl = CreateFile(CtlName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
866 if (hCtl != INVALID_HANDLE_VALUE)
867 {
868 char* lpszName;
869 rc = usbLibDevStrRootHubNameGet(hCtl, &lpszName);
870 AssertRC(rc);
871 if (RT_SUCCESS(rc))
872 {
873 rc = usbLibDevGetHubDevices(lpszName, ppDevs, pcDevs);
874 AssertRC(rc);
875 usbLibDevStrFree(lpszName);
876 }
877 CloseHandle(hCtl);
878 if (RT_FAILURE(rc))
879 break;
880 }
881 }
882 return VINF_SUCCESS;
883}
884
885static PUSBSUP_GET_DEVICES usbLibMonGetDevRqAlloc(uint32_t cDevs, PDWORD pcbRq)
886{
887 DWORD cbRq = RT_OFFSETOF(USBSUP_GET_DEVICES, aDevices[cDevs]);
888 PUSBSUP_GET_DEVICES pRq = (PUSBSUP_GET_DEVICES)RTMemAllocZ(cbRq);
889 Assert(pRq);
890 if (!pRq)
891 return NULL;
892 pRq->cDevices = cDevs;
893 *pcbRq = cbRq;
894 return pRq;
895}
896
897static int usbLibMonDevicesCmp(PUSBDEVICE pDev, PVBOXUSB_DEV pDevInfo)
898{
899 int iDiff;
900 iDiff = strcmp(pDev->pszAddress, pDevInfo->szDriverRegName);
901 return iDiff;
902}
903
904static int usbLibMonDevicesUpdate(PVBOXUSBGLOBALSTATE pGlobal, PUSBDEVICE pDevs, uint32_t cDevs, PVBOXUSB_DEV pDevInfos, uint32_t cDevInfos)
905{
906 PUSBDEVICE pDevsHead = pDevs;
907 for (; pDevInfos; pDevInfos = pDevInfos->pNext)
908 {
909 for (pDevs = pDevsHead; pDevs; pDevs = pDevs->pNext)
910 {
911 if (usbLibMonDevicesCmp(pDevs, pDevInfos))
912 continue;
913
914 if (!pDevInfos->szDriverRegName[0])
915 {
916 AssertFailed();
917 break;
918 }
919
920 USBSUP_GETDEV Dev = {0};
921 HANDLE hDev = CreateFile(pDevInfos->szName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
922 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
923 if (hDev == INVALID_HANDLE_VALUE)
924 {
925 AssertFailed();
926 break;
927 }
928
929 DWORD cbReturned = 0;
930 if (!DeviceIoControl(hDev, SUPUSB_IOCTL_GET_DEVICE, &Dev, sizeof (Dev), &Dev, sizeof (Dev), &cbReturned, NULL))
931 {
932 DWORD winEr = GetLastError();
933 /* ERROR_DEVICE_NOT_CONNECTED -> device was removed just now */
934#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
935 AssertMsg(winEr == ERROR_DEVICE_NOT_CONNECTED, (__FUNCTION__": DeviceIoControl failed winEr (%d)\n", winEr));
936#endif
937 Log(("SUPUSB_IOCTL_GET_DEVICE: DeviceIoControl no longer connected\n"));
938 CloseHandle(hDev);
939 break;
940 }
941
942 /* we must not close the handle until we request for the device state from the monitor to ensure
943 * the device handle returned by the device driver does not disappear */
944 Assert(Dev.hDevice);
945 USBSUP_GETDEV_MON MonInfo;
946 HVBOXUSBDEVUSR hDevice = Dev.hDevice;
947 if (!DeviceIoControl(pGlobal->hMonitor, SUPUSBFLT_IOCTL_GET_DEVICE, &hDevice, sizeof (hDevice), &MonInfo, sizeof (MonInfo), &cbReturned, NULL))
948 {
949 DWORD winEr = GetLastError();
950 /* ERROR_DEVICE_NOT_CONNECTED -> device was removed just now */
951 AssertMsgFailed((__FUNCTION__": Monitor DeviceIoControl failed winEr (%d)\n", winEr));
952 Log(("SUPUSBFLT_IOCTL_GET_DEVICE: DeviceIoControl no longer connected\n"));
953 CloseHandle(hDev);
954 break;
955 }
956
957 CloseHandle(hDev);
958
959 /* success!! update device info */
960 /* ensure the state returned is valid */
961 Assert( MonInfo.enmState == USBDEVICESTATE_USED_BY_HOST
962 || MonInfo.enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
963 || MonInfo.enmState == USBDEVICESTATE_UNUSED
964 || MonInfo.enmState == USBDEVICESTATE_HELD_BY_PROXY
965 || MonInfo.enmState == USBDEVICESTATE_USED_BY_GUEST);
966 pDevs->enmState = MonInfo.enmState;
967 /* The following is not 100% accurate but we only care about high-speed vs. non-high-speed */
968 pDevs->enmSpeed = Dev.fHiSpeed ? USBDEVICESPEED_HIGH : USBDEVICESPEED_FULL;
969 if (pDevs->enmState != USBDEVICESTATE_USED_BY_HOST)
970 {
971 /* only set the interface name if device can be grabbed */
972 RTStrFree(pDevs->pszAltAddress);
973 pDevs->pszAltAddress = (char*)pDevs->pszAddress;
974 pDevs->pszAddress = RTStrDup(pDevInfos->szName);
975 }
976#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
977 else
978 {
979 /* dbg breakpoint */
980 Assert(0);
981 }
982#endif
983
984 /* we've found the device, break in any way */
985 break;
986 }
987 }
988
989 return VINF_SUCCESS;
990}
991
992static int usbLibGetDevices(PVBOXUSBGLOBALSTATE pGlobal, PUSBDEVICE *ppDevs, uint32_t *pcDevs)
993{
994 *ppDevs = NULL;
995 *pcDevs = 0;
996
997 int rc = usbLibDevGetDevices(ppDevs, pcDevs);
998 AssertRC(rc);
999 if (RT_SUCCESS(rc))
1000 {
1001 PVBOXUSB_DEV pDevInfos = NULL;
1002 uint32_t cDevInfos = 0;
1003 rc = usbLibVuGetDevices(&pDevInfos, &cDevInfos);
1004 AssertRC(rc);
1005 if (RT_SUCCESS(rc))
1006 {
1007 rc = usbLibMonDevicesUpdate(pGlobal, *ppDevs, *pcDevs, pDevInfos, cDevInfos);
1008 AssertRC(rc);
1009 usbLibVuFreeDevices(pDevInfos);
1010 }
1011
1012 return VINF_SUCCESS;
1013 }
1014 return rc;
1015}
1016
1017AssertCompile(INFINITE == RT_INDEFINITE_WAIT);
1018static int usbLibStateWaitChange(PVBOXUSBGLOBALSTATE pGlobal, RTMSINTERVAL cMillies)
1019{
1020 HANDLE ahEvents[] = {pGlobal->hNotifyEvent, pGlobal->hInterruptEvent};
1021 DWORD dwResult = WaitForMultipleObjects(RT_ELEMENTS(ahEvents), ahEvents,
1022 FALSE, /* BOOL bWaitAll */
1023 cMillies);
1024
1025 switch (dwResult)
1026 {
1027 case WAIT_OBJECT_0:
1028 return VINF_SUCCESS;
1029 case WAIT_OBJECT_0 + 1:
1030 return VERR_INTERRUPTED;
1031 case WAIT_TIMEOUT:
1032 return VERR_TIMEOUT;
1033 default:
1034 {
1035 DWORD winEr = GetLastError();
1036 AssertMsgFailed((__FUNCTION__": WaitForMultipleObjects failed, winEr (%d)\n", winEr));
1037 return VERR_GENERAL_FAILURE;
1038 }
1039 }
1040}
1041
1042AssertCompile(RT_INDEFINITE_WAIT == INFINITE);
1043AssertCompile(sizeof (RTMSINTERVAL) == sizeof (DWORD));
1044USBLIB_DECL(int) USBLibWaitChange(RTMSINTERVAL msWaitTimeout)
1045{
1046 return usbLibStateWaitChange(&g_VBoxUsbGlobal, msWaitTimeout);
1047}
1048
1049static int usbLibInterruptWaitChange(PVBOXUSBGLOBALSTATE pGlobal)
1050{
1051 BOOL bRc = SetEvent(pGlobal->hInterruptEvent);
1052 if (!bRc)
1053 {
1054 DWORD winEr = GetLastError();
1055 AssertMsgFailed((__FUNCTION__": SetEvent failed, winEr (%d)\n", winEr));
1056 return VERR_GENERAL_FAILURE;
1057 }
1058 return VINF_SUCCESS;
1059}
1060
1061USBLIB_DECL(int) USBLibInterruptWaitChange()
1062{
1063 return usbLibInterruptWaitChange(&g_VBoxUsbGlobal);
1064}
1065
1066/*
1067USBLIB_DECL(bool) USBLibHasPendingDeviceChanges(void)
1068{
1069 int rc = USBLibWaitChange(0);
1070 return rc == VINF_SUCCESS;
1071}
1072*/
1073
1074USBLIB_DECL(int) USBLibGetDevices(PUSBDEVICE *ppDevices, uint32_t *pcbNumDevices)
1075{
1076 Assert(g_VBoxUsbGlobal.hMonitor != INVALID_HANDLE_VALUE);
1077 return usbLibGetDevices(&g_VBoxUsbGlobal, ppDevices, pcbNumDevices);
1078}
1079
1080USBLIB_DECL(void *) USBLibAddFilter(PCUSBFILTER pFilter)
1081{
1082 USBSUP_FLTADDOUT FltAddRc;
1083 DWORD cbReturned = 0;
1084
1085 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
1086 {
1087#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1088 AssertFailed();
1089#endif
1090 return NULL;
1091 }
1092
1093 Log(("usblibInsertFilter: Manufacturer=%s Product=%s Serial=%s\n",
1094 USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
1095 USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
1096 USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
1097
1098 if (!DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_ADD_FILTER,
1099 (LPVOID)pFilter, sizeof(*pFilter),
1100 &FltAddRc, sizeof(FltAddRc),
1101 &cbReturned, NULL))
1102 {
1103 DWORD winEr = GetLastError();
1104 AssertMsgFailed(("DeviceIoControl failed with winEr (%d(\n", winEr));
1105 return NULL;
1106 }
1107
1108 if (RT_FAILURE(FltAddRc.rc))
1109 {
1110 AssertMsgFailed(("Adding filter failed with %d\n", FltAddRc.rc));
1111 return NULL;
1112 }
1113 return (void *)FltAddRc.uId;
1114}
1115
1116
1117USBLIB_DECL(void) USBLibRemoveFilter(void *pvId)
1118{
1119 uintptr_t uId;
1120 DWORD cbReturned = 0;
1121
1122 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
1123 {
1124#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1125 AssertFailed();
1126#endif
1127 return;
1128 }
1129
1130 Log(("usblibRemoveFilter %p\n", pvId));
1131
1132 uId = (uintptr_t)pvId;
1133 if (!DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_REMOVE_FILTER, &uId, sizeof(uId), NULL, 0,&cbReturned, NULL))
1134 AssertMsgFailed(("DeviceIoControl failed with LastError=%Rwa\n", GetLastError()));
1135}
1136
1137USBLIB_DECL(int) USBLibRunFilters()
1138{
1139 DWORD cbReturned = 0;
1140
1141 Assert(g_VBoxUsbGlobal.hMonitor != INVALID_HANDLE_VALUE);
1142
1143 if (!DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_RUN_FILTERS,
1144 NULL, 0,
1145 NULL, 0,
1146 &cbReturned, NULL))
1147 {
1148 DWORD winEr = GetLastError();
1149 AssertMsgFailed(("DeviceIoControl failed with winEr (%d(\n", winEr));
1150 return RTErrConvertFromWin32(winEr);
1151 }
1152
1153 return VINF_SUCCESS;
1154}
1155
1156
1157#ifdef VBOX_USB_USE_DEVICE_NOTIFICATION
1158
1159static VOID CALLBACK usbLibTimerCallback(
1160 __in PVOID lpParameter,
1161 __in BOOLEAN TimerOrWaitFired
1162 )
1163{
1164 SetEvent(g_VBoxUsbGlobal.hNotifyEvent);
1165}
1166
1167static void usbLibOnDeviceChange()
1168{
1169 /* we're getting series of events like that especially on device re-attach
1170 * (i.e. first for device detach and then for device attach)
1171 * unfortunately the event does not tell us what actually happened.
1172 * To avoid extra notifications, we delay the SetEvent via a timer
1173 * and update the timer if additional notification comes before the timer fires
1174 * */
1175 if (g_VBoxUsbGlobal.hTimer)
1176 {
1177 if (!DeleteTimerQueueTimer(g_VBoxUsbGlobal.hTimerQueue, g_VBoxUsbGlobal.hTimer, NULL))
1178 {
1179 DWORD winEr = GetLastError();
1180 AssertMsg(winEr == ERROR_IO_PENDING, (__FUNCTION__": DeleteTimerQueueTimer failed, winEr (%d)\n", winEr));
1181 }
1182 }
1183
1184 if (!CreateTimerQueueTimer(&g_VBoxUsbGlobal.hTimer, g_VBoxUsbGlobal.hTimerQueue,
1185 usbLibTimerCallback,
1186 NULL,
1187 500, /* ms*/
1188 0,
1189 WT_EXECUTEONLYONCE))
1190 {
1191 DWORD winEr = GetLastError();
1192 AssertMsgFailed((__FUNCTION__": CreateTimerQueueTimer failed, winEr (%d)\n", winEr));
1193
1194 /* call it directly */
1195 usbLibTimerCallback(NULL, FALSE);
1196 }
1197}
1198
1199static LRESULT CALLBACK usbLibWndProc(HWND hwnd,
1200 UINT uMsg,
1201 WPARAM wParam,
1202 LPARAM lParam
1203)
1204{
1205 switch (uMsg)
1206 {
1207 case WM_DEVICECHANGE:
1208 if (wParam == DBT_DEVNODES_CHANGED)
1209 {
1210 /* we notify change any device arivals/removals on the system
1211 * and let the client decide whether the usb change actually happened
1212 * so far this is more clean than reporting events from the Monitor
1213 * because monitor sees only PDO arrivals/removals,
1214 * and by the time PDO is created, device can not
1215 * be yet started and fully functional,
1216 * so usblib won't be able to pick it up
1217 * */
1218
1219 usbLibOnDeviceChange();
1220 }
1221 break;
1222 case WM_DESTROY:
1223 return 0;
1224 }
1225 return DefWindowProc (hwnd, uMsg, wParam, lParam);
1226}
1227
1228static LPCSTR g_VBoxUsbWndClassName = "VBoxUsbLibClass";
1229
1230static DWORD WINAPI usbLibMsgThreadProc(__in LPVOID lpParameter)
1231{
1232 HWND hwnd = 0;
1233 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle (NULL);
1234 bool bExit = false;
1235
1236 /* Register the Window Class. */
1237 WNDCLASS wc;
1238 wc.style = 0;
1239 wc.lpfnWndProc = usbLibWndProc;
1240 wc.cbClsExtra = 0;
1241 wc.cbWndExtra = sizeof(void *);
1242 wc.hInstance = hInstance;
1243 wc.hIcon = NULL;
1244 wc.hCursor = NULL;
1245 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
1246 wc.lpszMenuName = NULL;
1247 wc.lpszClassName = g_VBoxUsbWndClassName;
1248
1249 ATOM atomWindowClass = RegisterClass(&wc);
1250
1251 if (atomWindowClass != 0)
1252 {
1253 /* Create the window. */
1254 g_VBoxUsbGlobal.hWnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
1255 g_VBoxUsbWndClassName, g_VBoxUsbWndClassName,
1256 WS_POPUPWINDOW,
1257 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
1258 SetEvent(g_VBoxUsbGlobal.hNotifyEvent);
1259
1260 if (g_VBoxUsbGlobal.hWnd)
1261 {
1262 SetWindowPos(hwnd, HWND_TOPMOST, -200, -200, 0, 0,
1263 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
1264
1265 MSG msg;
1266 while (GetMessage(&msg, NULL, 0, 0))
1267 {
1268 TranslateMessage(&msg);
1269 DispatchMessage(&msg);
1270 }
1271
1272 DestroyWindow (hwnd);
1273
1274 bExit = true;
1275 }
1276
1277 UnregisterClass (g_VBoxUsbWndClassName, hInstance);
1278 }
1279
1280 if(bExit)
1281 {
1282 /* no need any accuracy here, in anyway the DHCP server usually gets terminated with TerminateProcess */
1283 exit(0);
1284 }
1285
1286 return 0;
1287}
1288#endif
1289
1290/**
1291 * Initialize the USB library
1292 *
1293 * @returns VBox status code.
1294 */
1295USBLIB_DECL(int) USBLibInit(void)
1296{
1297 int rc = VERR_GENERAL_FAILURE;
1298
1299 Log(("usbproxy: usbLibInit\n"));
1300
1301 memset(&g_VBoxUsbGlobal, 0, sizeof (g_VBoxUsbGlobal));
1302
1303 g_VBoxUsbGlobal.hMonitor = INVALID_HANDLE_VALUE;
1304
1305 g_VBoxUsbGlobal.hNotifyEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes */
1306 FALSE, /* BOOL bManualReset */
1307#ifndef VBOX_USB_USE_DEVICE_NOTIFICATION
1308 TRUE, /* BOOL bInitialState */
1309#else
1310 FALSE, /* set to false since it will be initially used for notification thread startup sync */
1311#endif
1312 NULL /* LPCTSTR lpName */);
1313 if (g_VBoxUsbGlobal.hNotifyEvent)
1314 {
1315 g_VBoxUsbGlobal.hInterruptEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes */
1316 FALSE, /* BOOL bManualReset */
1317 FALSE, /* BOOL bInitialState */
1318 NULL /* LPCTSTR lpName */);
1319 if (g_VBoxUsbGlobal.hInterruptEvent)
1320 {
1321 g_VBoxUsbGlobal.hMonitor = CreateFile(USBMON_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1322 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
1323
1324 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
1325 {
1326 HRESULT hr = VBoxDrvCfgSvcStart(USBMON_SERVICE_NAME_W);
1327 if (hr == S_OK)
1328 {
1329 g_VBoxUsbGlobal.hMonitor = CreateFile(USBMON_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
1330 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
1331 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
1332 {
1333 DWORD winEr = GetLastError();
1334 LogRel((__FUNCTION__": CreateFile failed winEr(%d)\n", winEr));
1335 rc = VERR_FILE_NOT_FOUND;
1336 }
1337 }
1338 }
1339
1340 if (g_VBoxUsbGlobal.hMonitor != INVALID_HANDLE_VALUE)
1341 {
1342 USBSUP_VERSION Version = {0};
1343 DWORD cbReturned = 0;
1344
1345 if (DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_GET_VERSION, NULL, 0, &Version, sizeof (Version), &cbReturned, NULL))
1346 {
1347 if (Version.u32Major == USBMON_MAJOR_VERSION || Version.u32Minor <= USBMON_MINOR_VERSION)
1348 {
1349#ifndef VBOX_USB_USE_DEVICE_NOTIFICATION
1350 USBSUP_SET_NOTIFY_EVENT SetEvent = {0};
1351 Assert(g_VBoxUsbGlobal.hNotifyEvent);
1352 SetEvent.u.hEvent = g_VBoxUsbGlobal.hNotifyEvent;
1353 if (DeviceIoControl(g_VBoxUsbGlobal.hMonitor, SUPUSBFLT_IOCTL_SET_NOTIFY_EVENT,
1354 &SetEvent, sizeof (SetEvent),
1355 &SetEvent, sizeof (SetEvent),
1356 &cbReturned, NULL))
1357 {
1358 rc = SetEvent.u.rc;
1359 AssertRC(rc);
1360 if (RT_SUCCESS(rc))
1361 return VINF_SUCCESS;
1362 else
1363 AssertMsgFailed((__FUNCTION__": SetEvent failed, rc (%d)\n", rc));
1364 }
1365 else
1366 {
1367 DWORD winEr = GetLastError();
1368 AssertMsgFailed((__FUNCTION__": SetEvent Ioctl failed, winEr (%d)\n", winEr));
1369 rc = VERR_VERSION_MISMATCH;
1370 }
1371#else
1372 g_VBoxUsbGlobal.hTimerQueue = CreateTimerQueue();
1373 if (g_VBoxUsbGlobal.hTimerQueue)
1374 {
1375 g_VBoxUsbGlobal.hThread = CreateThread(
1376 NULL, /*__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, */
1377 0, /*__in SIZE_T dwStackSize, */
1378 usbLibMsgThreadProc, /*__in LPTHREAD_START_ROUTINE lpStartAddress,*/
1379 NULL, /*__in_opt LPVOID lpParameter,*/
1380 0, /*__in DWORD dwCreationFlags,*/
1381 NULL /*__out_opt LPDWORD lpThreadId*/
1382 );
1383
1384 if(g_VBoxUsbGlobal.hThread)
1385 {
1386 DWORD dwResult = WaitForSingleObject(g_VBoxUsbGlobal.hNotifyEvent, INFINITE);
1387 Assert(dwResult == WAIT_OBJECT_0);
1388
1389 if (g_VBoxUsbGlobal.hWnd)
1390 {
1391 /* ensure the event is set so the first "wait change" request processes */
1392 SetEvent(g_VBoxUsbGlobal.hNotifyEvent);
1393 return VINF_SUCCESS;
1394 }
1395 dwResult = WaitForSingleObject(g_VBoxUsbGlobal.hThread, INFINITE);
1396 Assert(dwResult == WAIT_OBJECT_0);
1397 BOOL bRc = CloseHandle(g_VBoxUsbGlobal.hThread);
1398 if (!bRc)
1399 {
1400 DWORD winEr = GetLastError();
1401 AssertMsgFailed((__FUNCTION__": CloseHandle for hThread failed winEr(%d)\n", winEr));
1402 }
1403 }
1404 else
1405 {
1406 DWORD winEr = GetLastError();
1407 AssertMsgFailed((__FUNCTION__": CreateThread failed, winEr (%d)\n", winEr));
1408 rc = VERR_GENERAL_FAILURE;
1409 }
1410 }
1411 else
1412 {
1413 DWORD winEr = GetLastError();
1414 AssertMsgFailed((__FUNCTION__": CreateTimerQueue failed winEr(%d)\n", winEr));
1415 }
1416#endif
1417 }
1418 else
1419 {
1420 AssertMsgFailed((__FUNCTION__": Monitor driver version mismatch!!\n"));
1421 rc = VERR_VERSION_MISMATCH;
1422 }
1423 }
1424 else
1425 {
1426 DWORD winEr = GetLastError();
1427 AssertMsgFailed((__FUNCTION__": DeviceIoControl failed winEr(%d)\n", winEr));
1428 rc = VERR_VERSION_MISMATCH;
1429 }
1430
1431 CloseHandle(g_VBoxUsbGlobal.hMonitor);
1432 }
1433 else
1434 {
1435 LogRel((__FUNCTION__": USB Service not found\n"));
1436#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1437 AssertFailed();
1438#endif
1439 rc = VERR_FILE_NOT_FOUND;
1440 }
1441
1442 CloseHandle(g_VBoxUsbGlobal.hInterruptEvent);
1443 }
1444 else
1445 {
1446 DWORD winEr = GetLastError();
1447 AssertMsgFailed((__FUNCTION__": CreateEvent for InterruptEvent failed winEr(%d)\n", winEr));
1448 rc = VERR_GENERAL_FAILURE;
1449 }
1450
1451 CloseHandle(g_VBoxUsbGlobal.hNotifyEvent);
1452 }
1453 else
1454 {
1455 DWORD winEr = GetLastError();
1456 AssertMsgFailed((__FUNCTION__": CreateEvent for NotifyEvent failed winEr(%d)\n", winEr));
1457 rc = VERR_GENERAL_FAILURE;
1458 }
1459
1460 /* since main calls us even if USBLibInit fails,
1461 * we use hMonitor == INVALID_HANDLE_VALUE as a marker to indicate whether the lib is inited */
1462
1463 Assert(RT_FAILURE(rc));
1464 return rc;
1465}
1466
1467
1468/**
1469 * Terminate the USB library
1470 *
1471 * @returns VBox status code.
1472 */
1473USBLIB_DECL(int) USBLibTerm(void)
1474{
1475 if (g_VBoxUsbGlobal.hMonitor == INVALID_HANDLE_VALUE)
1476 {
1477#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1478 AssertFailed();
1479#endif
1480 return VINF_ALREADY_INITIALIZED;
1481 }
1482
1483 BOOL bRc;
1484#ifdef VBOX_USB_USE_DEVICE_NOTIFICATION
1485 bRc= PostMessage(g_VBoxUsbGlobal.hWnd, WM_QUIT, 0, 0);
1486 if (!bRc)
1487 {
1488 DWORD winEr = GetLastError();
1489 AssertMsgFailed((__FUNCTION__": PostMessage for hWnd failed winEr(%d)\n", winEr));
1490 }
1491
1492 DWORD dwResult = WaitForSingleObject(g_VBoxUsbGlobal.hThread, INFINITE);
1493 Assert(dwResult == WAIT_OBJECT_0);
1494 bRc = CloseHandle(g_VBoxUsbGlobal.hThread);
1495 if (!bRc)
1496 {
1497 DWORD winEr = GetLastError();
1498 AssertMsgFailed((__FUNCTION__": CloseHandle for hThread failed winEr(%d)\n", winEr));
1499 }
1500
1501 if (g_VBoxUsbGlobal.hTimer)
1502 {
1503 bRc = DeleteTimerQueueTimer(g_VBoxUsbGlobal.hTimerQueue, g_VBoxUsbGlobal.hTimer,
1504 INVALID_HANDLE_VALUE /* <-- to block until the timer is completed */
1505 );
1506 if (!bRc)
1507 {
1508 DWORD winEr = GetLastError();
1509 AssertMsgFailed((__FUNCTION__": DeleteTimerQueueEx failed winEr(%d)\n", winEr));
1510 }
1511 }
1512
1513 bRc = DeleteTimerQueueEx(g_VBoxUsbGlobal.hTimerQueue,
1514 INVALID_HANDLE_VALUE /* <-- to block until all timers are completed */
1515 );
1516 if (!bRc)
1517 {
1518 DWORD winEr = GetLastError();
1519 AssertMsgFailed((__FUNCTION__": DeleteTimerQueueEx failed winEr(%d)\n", winEr));
1520 }
1521#endif
1522
1523 bRc = CloseHandle(g_VBoxUsbGlobal.hMonitor);
1524 if (!bRc)
1525 {
1526 DWORD winEr = GetLastError();
1527 AssertMsgFailed((__FUNCTION__": CloseHandle for hMonitor failed winEr(%d)\n", winEr));
1528 }
1529
1530 bRc = CloseHandle(g_VBoxUsbGlobal.hInterruptEvent);
1531 if (!bRc)
1532 {
1533 DWORD winEr = GetLastError();
1534 AssertMsgFailed((__FUNCTION__": CloseHandle for hInterruptEvent failed winEr(%d)\n", winEr));
1535 }
1536
1537 bRc = CloseHandle(g_VBoxUsbGlobal.hNotifyEvent);
1538 if (!bRc)
1539 {
1540 DWORD winEr = GetLastError();
1541 AssertMsgFailed((__FUNCTION__": CloseHandle for hNotifyEvent failed winEr(%d)\n", winEr));
1542 }
1543
1544 return VINF_SUCCESS;
1545}
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