VirtualBox

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

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

usb: disable annoying assertions with ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS

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