VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/USBLib-win.cpp@ 34261

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

typo

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 91.7 KB
Line 
1/* $Id: USBLib-win.cpp 34261 2010-11-22 18:14:53Z vboxsync $ */
2/** @file
3 * USBLIB - USB support library interface, Windows.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
23#include <windows.h>
24
25#include <VBox/sup.h>
26#include <VBox/types.h>
27#include <VBox/err.h>
28#include <VBox/param.h>
29#include <iprt/path.h>
30#include <iprt/assert.h>
31#include <iprt/alloc.h>
32#include <iprt/string.h>
33#include <iprt/thread.h>
34#include <VBox/log.h>
35#include <VBox/usblib.h>
36#include <VBox/usb.h>
37#include "../USBLibInternal.h"
38#include <stdio.h>
39#pragma warning (disable:4200) /* shuts up the empty array member warnings */
40#include <setupapi.h>
41#include <usbdi.h>
42#include <hidsdi.h>
43
44
45/*******************************************************************************
46* Global Variables *
47*******************************************************************************/
48/** Flags whether or not we started the service. */
49static bool g_fStartedService = false;
50static char completeDeviceName[256] = ""; //generated from the GUID registered by the driver itself
51
52typedef struct
53{
54 char szName[512];
55 char szDriverRegName[512];
56} USBDEV, *PUSBDEV;
57
58static PUSBDEV g_pUSBDev = NULL;
59static uint32_t g_cMaxDevices = 0;
60static uint32_t g_cUSBStateChange = 0;
61
62static HANDLE g_hUSBMonitor = INVALID_HANDLE_VALUE;
63
64
65/*******************************************************************************
66* Defined Constants And Macros *
67*******************************************************************************/
68/** @def VBOX_WITH_ANNOYING_USB_ASSERTIONS
69 * Enable this to get assertions on various failures.
70 */
71//#define VBOX_WITH_ANNOYING_USB_ASSERTIONS
72#ifdef DOXYGEN_RUNNING
73# define VBOX_WITH_ANNOYING_USB_ASSERTIONS
74#endif
75
76/*******************************************************************************
77* Internal Functions *
78*******************************************************************************/
79
80bool ValidateUSBDevice(char *pszName)
81{
82 HANDLE hOut = INVALID_HANDLE_VALUE;
83
84 hOut = CreateFile(pszName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
85 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
86
87 if (INVALID_HANDLE_VALUE == hOut)
88 {
89 Log(( "USB: FAILED to open %s\n", pszName));
90 goto failure;
91 }
92 else
93 {
94 /*
95 * Check the version
96 */
97 USBSUP_VERSION version = {0};
98 DWORD cbReturned = 0;
99
100 if (!DeviceIoControl(hOut, SUPUSB_IOCTL_GET_VERSION, NULL, 0,&version, sizeof(version), &cbReturned, NULL))
101 {
102 Log(("DeviceIoControl SUPUSB_IOCTL_GET_VERSION failed with rc=%d\n", GetLastError()));
103 goto failure;
104 }
105
106 if (version.u32Major != USBDRV_MAJOR_VERSION ||
107 version.u32Minor < USBDRV_MINOR_VERSION)
108 {
109 Log(("USB: Invalid version %d:%d vs %d:%d\n", version.u32Major, version.u32Minor, USBDRV_MAJOR_VERSION, USBDRV_MINOR_VERSION));
110 goto failure;
111 }
112 if (!DeviceIoControl(hOut, SUPUSB_IOCTL_IS_OPERATIONAL, NULL, 0, NULL, NULL, &cbReturned, NULL))
113 {
114 Log(("DeviceIoControl SUPUSB_IOCTL_IS_OPERATIONAL failed with rc=%d\n", GetLastError()));
115 goto failure;
116 }
117
118 }
119 CloseHandle(hOut);
120 return true;
121
122failure:
123 if (hOut != INVALID_HANDLE_VALUE)
124 CloseHandle(hOut);
125
126 return false;
127}
128
129bool OpenOneDevice (HDEVINFO HardwareDeviceInfo,
130 PSP_DEVICE_INTERFACE_DATA DeviceInfoData,
131 USBDEV *pUsbDev)
132{
133 PSP_DEVICE_INTERFACE_DETAIL_DATA functionClassDeviceData = NULL;
134 ULONG predictedLength = 0;
135 ULONG requiredLength = 0;
136 SP_DEVINFO_DATA devInfo;
137
138 //
139 // allocate a function class device data structure to receive the
140 // goods about this particular device.
141 //
142 SetupDiGetDeviceInterfaceDetail (
143 HardwareDeviceInfo,
144 DeviceInfoData,
145 NULL, // probing so no output buffer yet
146 0, // probing so output buffer length of zero
147 &requiredLength,
148 NULL); // not interested in the specific dev-node
149
150 predictedLength = requiredLength;
151
152 functionClassDeviceData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) RTMemAllocZ(predictedLength);
153 if(NULL == functionClassDeviceData)
154 {
155 return false;
156 }
157 functionClassDeviceData->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);
158
159 //
160 // Retrieve the information from Plug and Play.
161 //
162 devInfo.cbSize = sizeof(devInfo);
163 if (! SetupDiGetDeviceInterfaceDetail(HardwareDeviceInfo, DeviceInfoData,
164 functionClassDeviceData, predictedLength,
165 &requiredLength, &devInfo))
166 {
167 goto failure;
168 }
169
170 strcpy(pUsbDev->szName, functionClassDeviceData->DevicePath) ;
171 Log(( "USB: Attempting to open %s\n", pUsbDev->szName));
172
173 /* Query the registry path of the associated driver */
174 requiredLength = 0;
175 SetupDiGetDeviceRegistryProperty(HardwareDeviceInfo, &devInfo, SPDRP_DRIVER, NULL, NULL, 0, &requiredLength);
176 Assert(sizeof(pUsbDev->szDriverRegName) >= requiredLength);
177 if (requiredLength && sizeof(pUsbDev->szDriverRegName) >= requiredLength)
178 {
179 predictedLength = requiredLength;
180
181 if (!SetupDiGetDeviceRegistryProperty(HardwareDeviceInfo, &devInfo, SPDRP_DRIVER, NULL, (PBYTE)pUsbDev->szDriverRegName, predictedLength, &requiredLength))
182 goto failure;
183
184 Log(("USB: Driver name %s\n", pUsbDev->szDriverRegName));
185 }
186
187 bool rc = ValidateUSBDevice(functionClassDeviceData->DevicePath);
188 RTMemFree(functionClassDeviceData);
189
190 return rc;
191
192failure:
193 if (functionClassDeviceData)
194 RTMemFree(functionClassDeviceData);
195
196 return false;
197}
198
199bool OpenUsbDevices(LPGUID pGuid, uint32_t *pcNumDevices)
200{
201 HDEVINFO hardwareDeviceInfo;
202 SP_DEVICE_INTERFACE_DATA deviceInfoData;
203 USBDEV usbDev;
204
205 //
206 // Open a handle to the plug and play dev node.
207 // SetupDiGetClassDevs() returns a device information set that contains info on all
208 // installed devices of a specified class.
209 //
210 hardwareDeviceInfo = SetupDiGetClassDevs (
211 pGuid,
212 NULL, // Define no enumerator (global)
213 NULL, // Define no
214 (DIGCF_PRESENT | // Only Devices present
215 DIGCF_DEVICEINTERFACE)); // Function class devices.
216
217 deviceInfoData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
218
219 int j = 0, i = 0;
220
221 while (true)
222 {
223 // SetupDiEnumDeviceInterfaces() returns information about device interfaces
224 // exposed by one or more devices. Each call returns information about one interface;
225 // the routine can be called repeatedly to get information about several interfaces
226 // exposed by one or more devices.
227
228 Log(("OpenUsbDevices: SetupDiEnumDeviceInterfaces\n"));
229 if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo,
230 0, // We don't care about specific PDOs
231 pGuid,
232 i,
233 &deviceInfoData))
234 {
235 if (OpenOneDevice (hardwareDeviceInfo, &deviceInfoData, &usbDev) == true)
236 {
237 uint32_t z;
238 for (z = 0; z < g_cMaxDevices; z++)
239 {
240 if (g_pUSBDev[z].szName[0] == 0)
241 {
242 memcpy(&g_pUSBDev[z], &usbDev, sizeof(usbDev));
243 Log(("Captured device %s\n", g_pUSBDev[z].szName));
244 j++;
245 break;
246 }
247 }
248 AssertMsg(z < g_cMaxDevices, ("z=%d g_cMaxDevices=%d\n", z, g_cMaxDevices));
249 }
250 }
251 else
252 {
253 if (ERROR_NO_MORE_ITEMS == GetLastError())
254 {
255 Log(("OpenUsbDevices: No more items\n"));
256 break;
257 }
258 }
259 i++;
260 }
261
262 *pcNumDevices = j;
263
264 // SetupDiDestroyDeviceInfoList() destroys a device information set
265 // and frees all associated memory.
266
267 SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
268 return true;
269}
270
271/**
272 * Initialize the OS specific part of the library.
273 * On Win32 this involves:
274 * - registering the device driver
275 * - start device driver.
276 * - open driver.
277 *
278 * @returns VBox status code
279 */
280static int usblibEnumDevices(uint32_t cNumNewDevices, uint32_t *pcNumDevices)
281{
282 if (g_pUSBDev)
283 RTMemFree(g_pUSBDev);
284 g_pUSBDev = NULL;
285 g_cMaxDevices = 0;
286 *pcNumDevices = 0;
287
288 if (cNumNewDevices == 0)
289 return 0; /* nothing to do */
290
291 g_pUSBDev = (PUSBDEV)RTMemAllocZ(cNumNewDevices*sizeof(USBDEV));
292 if (!g_pUSBDev)
293 {
294 AssertFailed();
295 return VERR_NO_MEMORY;
296 }
297 g_cMaxDevices = cNumNewDevices;
298
299 if (OpenUsbDevices((LPGUID)&GUID_CLASS_VBOXUSB, pcNumDevices) == false)
300 {
301 AssertFailed();
302 return VERR_INTERNAL_ERROR;
303 }
304 AssertMsg(*pcNumDevices <= cNumNewDevices, ("cNumDevices = %d, cNumNewDevices = %d\n", *pcNumDevices, cNumNewDevices));
305 return VINF_SUCCESS;
306}
307
308/**
309 * Returns the nth USB device name
310 *
311 * @returns NULL on failure, otherwise the requested name
312 */
313char *usblibQueryDeviceName(uint32_t idxDev)
314{
315 int j=0;
316
317 Assert(idxDev < g_cMaxDevices);
318 for (uint32_t i=0; i<g_cMaxDevices; i++)
319 {
320 if (g_pUSBDev[i].szName[0])
321 {
322 if (j == idxDev)
323 return g_pUSBDev[i].szName;
324 j++;
325 }
326 }
327
328 Log(("USB: usblibQueryHandle returned -1; g_cMaxDevices = %d\n", g_cMaxDevices));
329 return NULL;
330}
331
332/**
333 * Returns the nth USB device registry path
334 *
335 * @returns NULL on failure, otherwise the requested name
336 */
337char *usblibQueryDeviceRegPath(uint32_t idxDev)
338{
339 int j=0;
340
341 Assert(idxDev < g_cMaxDevices);
342 for (uint32_t i=0; i<g_cMaxDevices; i++)
343 {
344 if (g_pUSBDev[i].szName[0])
345 {
346 if (j == idxDev)
347 return g_pUSBDev[i].szDriverRegName;
348 j++;
349 }
350 }
351
352 Log(("USB: usblibQueryHandle returned -1; g_cMaxDevices = %d\n", g_cMaxDevices));
353 return NULL;
354}
355
356/**
357 * Converts a supdrv error code to an nt status code.
358 *
359 * @returns corresponding SUPDRV_ERR_*.
360 * @param rc Win32 error code.
361 */
362static int suplibConvertWin32Err(int rc)
363{
364 /* Conversion program (link with ntdll.lib from ddk):
365 #define _WIN32_WINNT 0x0501
366 #include <windows.h>
367 #include <ntstatus.h>
368 #include <winternl.h>
369 #include <stdio.h>
370
371 int main()
372 {
373 #define CONVERT(a) printf(#a " %#x -> %d\n", a, RtlNtStatusToDosError((a)))
374 CONVERT(STATUS_SUCCESS);
375 CONVERT(STATUS_NOT_SUPPORTED);
376 CONVERT(STATUS_INVALID_PARAMETER);
377 CONVERT(STATUS_ACCESS_DENIED);
378 CONVERT(STATUS_INVALID_HANDLE);
379 CONVERT(STATUS_INVALID_ADDRESS);
380 CONVERT(STATUS_NOT_LOCKED);
381 CONVERT(STATUS_IMAGE_ALREADY_LOADED);
382 return 0;
383 }
384 */
385
386 switch (rc)
387 {
388 //case 0: return STATUS_SUCCESS;
389 case 0: return 0;
390 //case SUPDRV_ERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
391 case ERROR_NOT_SUPPORTED: return VERR_GENERAL_FAILURE;
392 //case SUPDRV_ERR_INVALID_PARAM: return STATUS_INVALID_PARAMETER;
393 case ERROR_INVALID_PARAMETER: return VERR_INVALID_PARAMETER;
394 //case SUPDRV_ERR_INVALID_MAGIC: return STATUS_ACCESS_DENIED;
395 case ERROR_ACCESS_DENIED: return VERR_INVALID_MAGIC;
396 //case SUPDRV_ERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
397 case ERROR_INVALID_HANDLE: return VERR_INVALID_HANDLE;
398 //case SUPDRV_ERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
399 case ERROR_UNEXP_NET_ERR: return VERR_INVALID_POINTER;
400 //case SUPDRV_ERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
401 case ERROR_NOT_LOCKED: return VERR_LOCK_FAILED;
402 //case SUPDRV_ERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
403 case ERROR_SERVICE_ALREADY_RUNNING: return VERR_ALREADY_LOADED;
404 }
405
406 return VERR_GENERAL_FAILURE;
407}
408
409
410
411//*****************************************************************************
412// D E F I N E S
413//*****************************************************************************
414
415#define NUM_HCS_TO_CHECK 10
416
417#include <cfgmgr32.h>
418#include "usbdesc.h"
419//
420// Structure used to build a linked list of String Descriptors
421// retrieved from a device.
422//
423
424typedef struct _STRING_DESCRIPTOR_NODE
425{
426 struct _STRING_DESCRIPTOR_NODE *Next;
427 UCHAR DescriptorIndex;
428 USHORT LanguageID;
429 USB_STRING_DESCRIPTOR StringDescriptor[0];
430} STRING_DESCRIPTOR_NODE, *PSTRING_DESCRIPTOR_NODE;
431
432//
433// Structures associated with TreeView items through the lParam. When an item
434// is selected, the lParam is retrieved and the structure it which it points
435// is used to display information in the edit control.
436//
437
438typedef struct
439{
440 PUSB_NODE_INFORMATION HubInfo; // NULL if not a HUB
441
442 PCHAR HubName; // NULL if not a HUB
443
444 PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo; // NULL if root HUB
445
446 PUSB_DESCRIPTOR_REQUEST ConfigDesc; // NULL if root HUB
447
448 PSTRING_DESCRIPTOR_NODE StringDescs;
449
450} USBDEVICEINFO, *PUSBDEVICEINFO;
451
452//*****************************************************************************
453// L O C A L F U N C T I O N P R O T O T Y P E S
454//*****************************************************************************
455
456VOID
457EnumerateHub (
458 PCHAR HubName,
459 PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo,
460 PUSB_DESCRIPTOR_REQUEST ConfigDesc,
461 PSTRING_DESCRIPTOR_NODE StringDescs,
462 PCHAR DeviceDesc
463);
464
465VOID
466EnumerateHubPorts (
467 HANDLE hHubDevice,
468 ULONG NumPorts,
469 const char *pszHubName
470);
471
472PCHAR GetRootHubName (
473 HANDLE HostController
474);
475
476PCHAR GetExternalHubName (
477 HANDLE Hub,
478 ULONG ConnectionIndex
479);
480
481PCHAR GetHCDDriverKeyName (
482 HANDLE HCD
483);
484
485PCHAR GetDriverKeyName (
486 HANDLE Hub,
487 ULONG ConnectionIndex
488);
489
490PUSB_DESCRIPTOR_REQUEST
491GetConfigDescriptor (
492 HANDLE hHubDevice,
493 ULONG ConnectionIndex,
494 UCHAR DescriptorIndex
495);
496
497BOOL
498AreThereStringDescriptors (
499 PUSB_DEVICE_DESCRIPTOR DeviceDesc,
500 PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc
501);
502
503PSTRING_DESCRIPTOR_NODE
504GetAllStringDescriptors (
505 HANDLE hHubDevice,
506 ULONG ConnectionIndex,
507 PUSB_DEVICE_DESCRIPTOR DeviceDesc,
508 PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc
509);
510
511PSTRING_DESCRIPTOR_NODE
512GetStringDescriptor (
513 HANDLE hHubDevice,
514 ULONG ConnectionIndex,
515 UCHAR DescriptorIndex,
516 USHORT LanguageID
517);
518
519PSTRING_DESCRIPTOR_NODE
520GetStringDescriptors (
521 HANDLE hHubDevice,
522 ULONG ConnectionIndex,
523 UCHAR DescriptorIndex,
524 ULONG NumLanguageIDs,
525 USHORT *LanguageIDs,
526 PSTRING_DESCRIPTOR_NODE StringDescNodeTail
527);
528
529PCHAR DriverNameToDeviceDesc (PCHAR DriverName);
530
531//*****************************************************************************
532// G L O B A L S P R I V A T E T O T H I S F I L E
533//*****************************************************************************
534
535PCHAR ConnectionStatuses[] =
536{
537 "NoDeviceConnected",
538 "DeviceConnected",
539 "DeviceFailedEnumeration",
540 "DeviceGeneralFailure",
541 "DeviceCausedOvercurrent",
542 "DeviceNotEnoughPower"
543};
544
545static ULONG TotalDevicesConnected;
546
547static BOOL gDoConfigDesc = TRUE;
548static int TotalHubs;
549static PUSBDEVICE *ppDeviceList = NULL;
550
551PCHAR ConnectionStatuses[];
552
553VOID AddLeaf(PUSBDEVICEINFO info, PCHAR pszLeafName, PCHAR pszDriverKeyName, const char *pszHubName, ULONG iHubPort)
554{
555 Log3(("usbproxy:AddLeaf: pszDriverKeyName=%s pszLeafName=%s pszHubName=%s iHubPort=%d\n", pszDriverKeyName, pszLeafName, pszHubName, iHubPort));
556 PUSBDEVICE pDevice = (PUSBDEVICE)RTMemAllocZ(sizeof(USBDEVICE));
557
558 if (pDevice)
559 {
560 Assert(info->ConnectionInfo);
561
562 if (info->ConnectionInfo)
563 {
564 PSTRING_DESCRIPTOR_NODE pStrDesc;
565 char **pString;
566
567 pDevice->bcdUSB = info->ConnectionInfo->DeviceDescriptor.bcdUSB;
568 pDevice->bDeviceClass = info->ConnectionInfo->DeviceDescriptor.bDeviceClass;
569 pDevice->bDeviceSubClass = info->ConnectionInfo->DeviceDescriptor.bDeviceSubClass;
570 pDevice->bDeviceProtocol = info->ConnectionInfo->DeviceDescriptor.bDeviceProtocol;
571 pDevice->idVendor = info->ConnectionInfo->DeviceDescriptor.idVendor;
572 pDevice->idProduct = info->ConnectionInfo->DeviceDescriptor.idProduct;
573 pDevice->bcdDevice = info->ConnectionInfo->DeviceDescriptor.bcdDevice;
574 pDevice->bBus = 0; /** @todo figure out bBus on windows... */
575 pDevice->bPort = iHubPort;
576 /** @todo check which devices are used for primary input (keyboard & mouse) */
577 if (!pszDriverKeyName || *pszDriverKeyName == 0)
578 pDevice->enmState = USBDEVICESTATE_UNUSED;
579 else
580 pDevice->enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
581 pDevice->enmSpeed = USBDEVICESPEED_UNKNOWN;
582
583 pDevice->pszAddress = RTStrDup(pszDriverKeyName);
584 pDevice->pszHubName = RTStrDup(pszHubName);
585 pDevice->bNumConfigurations = 0;
586 pDevice->u64SerialHash = 0;
587 pStrDesc = info->StringDescs;
588 while (pStrDesc)
589 {
590 pString = NULL;
591 if ( info->ConnectionInfo->DeviceDescriptor.iManufacturer
592 && pStrDesc->DescriptorIndex == info->ConnectionInfo->DeviceDescriptor.iManufacturer)
593 {
594 pString = (char **)&pDevice->pszManufacturer;
595 }
596 else
597 if ( info->ConnectionInfo->DeviceDescriptor.iProduct
598 && pStrDesc->DescriptorIndex == info->ConnectionInfo->DeviceDescriptor.iProduct)
599 {
600 pString = (char **)&pDevice->pszProduct;
601 }
602 else
603 if ( info->ConnectionInfo->DeviceDescriptor.iSerialNumber
604 && pStrDesc->DescriptorIndex == info->ConnectionInfo->DeviceDescriptor.iSerialNumber)
605 {
606 pString = (char **)&pDevice->pszSerialNumber;
607 }
608 if (pString)
609 {
610 char *pStringUTF8 = NULL;
611 RTUtf16ToUtf8((PCRTUTF16)&pStrDesc->StringDescriptor->bString[0], &pStringUTF8);
612 RTStrUtf8ToCurrentCP(pString, pStringUTF8);
613 RTStrFree(pStringUTF8);
614 if (pStrDesc->DescriptorIndex == info->ConnectionInfo->DeviceDescriptor.iSerialNumber)
615 {
616 pDevice->u64SerialHash = USBLibHashSerial(pDevice->pszSerialNumber);
617 }
618 }
619
620 pStrDesc = pStrDesc->Next;
621 }
622 if (*ppDeviceList == NULL)
623 {
624 pDevice->pNext = NULL;
625 *ppDeviceList = pDevice;
626 }
627 else
628 {
629 pDevice->pNext = *ppDeviceList;
630 *ppDeviceList = pDevice;
631 }
632 }
633 return;
634 }
635 AssertFailed();
636}
637
638//*****************************************************************************
639//
640// EnumerateHostController()
641//
642// hTreeParent - Handle of the TreeView item under which host controllers
643// should be added.
644//
645//*****************************************************************************
646
647VOID
648EnumerateHostController (
649 HANDLE hHCDev,
650 PCHAR leafName
651)
652{
653 PCHAR driverKeyName;
654 PCHAR deviceDesc;
655 PCHAR rootHubName;
656
657 driverKeyName = GetHCDDriverKeyName(hHCDev);
658
659 if (driverKeyName)
660 {
661 deviceDesc = DriverNameToDeviceDesc(driverKeyName);
662
663 if (deviceDesc)
664 {
665 leafName = deviceDesc;
666 }
667
668 RTMemFree(driverKeyName);
669 }
670
671 rootHubName = GetRootHubName(hHCDev);
672
673 if (rootHubName != NULL)
674 {
675 EnumerateHub(rootHubName,
676 NULL, // ConnectionInfo
677 NULL, // ConfigDesc
678 NULL, // StringDescs
679 "RootHub" // DeviceDesc
680 );
681 }
682}
683
684
685//*****************************************************************************
686//
687// EnumerateHostControllers()
688//
689// hTreeParent - Handle of the TreeView item under which host controllers
690// should be added.
691//
692//*****************************************************************************
693
694void usbLibEnumerateHostControllers(PUSBDEVICE *ppDevices, uint32_t *DevicesConnected)
695{
696 char HCName[16];
697 int HCNum;
698 HANDLE hHCDev;
699 PCHAR leafName;
700
701 TotalDevicesConnected = 0;
702 TotalHubs = 0;
703 ppDeviceList = ppDevices;
704
705 // Iterate over some Host Controller names and try to open them.
706 //
707 for (HCNum = 0; HCNum < NUM_HCS_TO_CHECK; HCNum++)
708 {
709 sprintf(HCName, "\\\\.\\HCD%d", HCNum);
710
711 hHCDev = CreateFile(HCName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
712
713 // If the handle is valid, then we've successfully opened a Host
714 // Controller. Display some info about the Host Controller itself,
715 // then enumerate the Root Hub attached to the Host Controller.
716 //
717 if (hHCDev != INVALID_HANDLE_VALUE)
718 {
719 leafName = HCName + sizeof("\\\\.\\") - sizeof("");
720
721 EnumerateHostController(hHCDev,
722 leafName);
723
724 CloseHandle(hHCDev);
725 }
726 }
727
728 ppDeviceList = NULL;
729 *DevicesConnected = TotalDevicesConnected - TotalHubs;
730}
731
732//*****************************************************************************
733//
734// EnumerateHub()
735//
736// hTreeParent - Handle of the TreeView item under which this hub should be
737// added.
738//
739// HubName - Name of this hub. This pointer is kept so the caller can neither
740// free nor reuse this memory.
741//
742// ConnectionInfo - NULL if this is a root hub, else this is the connection
743// info for an external hub. This pointer is kept so the caller can neither
744// free nor reuse this memory.
745//
746// ConfigDesc - NULL if this is a root hub, else this is the Configuration
747// Descriptor for an external hub. This pointer is kept so the caller can
748// neither free nor reuse this memory.
749//
750//*****************************************************************************
751
752VOID
753EnumerateHub (
754 PCHAR HubName,
755 PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo,
756 PUSB_DESCRIPTOR_REQUEST ConfigDesc,
757 PSTRING_DESCRIPTOR_NODE StringDescs,
758 PCHAR DeviceDesc
759)
760{
761 HANDLE hHubDevice;
762 PCHAR deviceName;
763 BOOL success;
764 ULONG nBytes;
765 PUSBDEVICEINFO info;
766 CHAR leafName[512]; // XXXXX how big does this have to be?
767
768 Log3(("usbproxy::EnumerateHub: HubName=%s\n", HubName));
769
770 // Initialize locals to not allocated state so the error cleanup routine
771 // only tries to cleanup things that were successfully allocated.
772 //
773 info = NULL;
774 hHubDevice = INVALID_HANDLE_VALUE;
775
776 // Allocate some space for a USBDEVICEINFO structure to hold the
777 // hub info, hub name, and connection info pointers. GPTR zero
778 // initializes the structure for us.
779 //
780 info = (PUSBDEVICEINFO) RTMemAllocZ(sizeof(USBDEVICEINFO));
781
782 if (info == NULL)
783 {
784 AssertFailed();
785 goto EnumerateHubError;
786 }
787
788 // Keep copies of the Hub Name, Connection Info, and Configuration
789 // Descriptor pointers
790 //
791 info->HubName = HubName;
792
793 info->ConnectionInfo = ConnectionInfo;
794
795 info->ConfigDesc = ConfigDesc;
796
797 info->StringDescs = StringDescs;
798
799
800 // Allocate some space for a USB_NODE_INFORMATION structure for this Hub,
801 //
802 info->HubInfo = (PUSB_NODE_INFORMATION)RTMemAllocZ(sizeof(USB_NODE_INFORMATION));
803
804 if (info->HubInfo == NULL)
805 {
806 AssertFailed();
807 goto EnumerateHubError;
808 }
809
810 // Allocate a temp buffer for the full hub device name.
811 //
812 deviceName = (PCHAR)RTMemAllocZ(strlen(HubName) + sizeof("\\\\.\\"));
813
814 if (deviceName == NULL)
815 {
816 AssertFailed();
817 goto EnumerateHubError;
818 }
819
820 // Create the full hub device name
821 //
822 strcpy(deviceName, "\\\\.\\");
823 strcpy(deviceName + sizeof("\\\\.\\") - 1, info->HubName);
824
825 // Try to hub the open device
826 //
827 hHubDevice = CreateFile(deviceName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
828
829 // Done with temp buffer for full hub device name
830 //
831 RTMemFree(deviceName);
832
833 if (hHubDevice == INVALID_HANDLE_VALUE)
834 {
835 AssertFailed();
836 goto EnumerateHubError;
837 }
838
839 //
840 // Now query USBHUB for the USB_NODE_INFORMATION structure for this hub.
841 // This will tell us the number of downstream ports to enumerate, among
842 // other things.
843 //
844 success = DeviceIoControl(hHubDevice,
845 IOCTL_USB_GET_NODE_INFORMATION,
846 info->HubInfo,
847 sizeof(USB_NODE_INFORMATION),
848 info->HubInfo,
849 sizeof(USB_NODE_INFORMATION),
850 &nBytes,
851 NULL);
852
853 if (!success)
854 {
855 AssertFailed();
856 goto EnumerateHubError;
857 }
858
859 // Build the leaf name from the port number and the device description
860 //
861 if (ConnectionInfo)
862 {
863 sprintf(leafName, "[Port%d] ", ConnectionInfo->ConnectionIndex);
864 strcat(leafName, ConnectionStatuses[ConnectionInfo->ConnectionStatus]);
865 strcat(leafName, " : ");
866 }
867 else
868 {
869 leafName[0] = 0;
870 }
871
872 if (DeviceDesc)
873 {
874
875 strcat(leafName, DeviceDesc);
876 }
877 else
878 {
879 strcat(leafName, info->HubName);
880 }
881
882 // Now recursively enumerate the ports of this hub.
883 //
884 EnumerateHubPorts(
885 hHubDevice,
886 info->HubInfo->u.HubInformation.HubDescriptor.bNumberOfPorts,
887 HubName
888 );
889
890
891 CloseHandle(hHubDevice);
892 return;
893
894EnumerateHubError:
895 //
896 // Clean up any stuff that got allocated
897 //
898
899 if (hHubDevice != INVALID_HANDLE_VALUE)
900 {
901 CloseHandle(hHubDevice);
902 hHubDevice = INVALID_HANDLE_VALUE;
903 }
904
905 if (info != NULL)
906 {
907 if (info->HubName != NULL)
908 {
909 RTMemFree(info->HubName);
910 info->HubName = NULL;
911 }
912
913 if (info->HubInfo != NULL)
914 {
915 RTMemFree(info->HubInfo);
916 info->HubInfo;
917 }
918
919 RTMemFree(info);
920 info = NULL;
921 }
922
923 if (ConnectionInfo)
924 {
925 RTMemFree(ConnectionInfo);
926 }
927
928 if (ConfigDesc)
929 {
930 RTMemFree(ConfigDesc);
931 }
932
933 if (StringDescs != NULL)
934 {
935 PSTRING_DESCRIPTOR_NODE Next;
936
937 do {
938
939 Next = StringDescs->Next;
940 RTMemFree(StringDescs);
941 StringDescs = Next;
942
943 } while (StringDescs != NULL);
944 }
945}
946
947//*****************************************************************************
948//
949// EnumerateHubPorts()
950//
951// hTreeParent - Handle of the TreeView item under which the hub port should
952// be added.
953//
954// hHubDevice - Handle of the hub device to enumerate.
955//
956// NumPorts - Number of ports on the hub.
957//
958//*****************************************************************************
959
960VOID
961EnumerateHubPorts (
962 HANDLE hHubDevice,
963 ULONG NumPorts,
964 const char *pszHubName
965)
966{
967 ULONG index;
968 BOOL success;
969
970 PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo;
971 PUSB_DESCRIPTOR_REQUEST configDesc;
972 PSTRING_DESCRIPTOR_NODE stringDescs;
973 PUSBDEVICEINFO info;
974
975 PCHAR pszDriverKeyName;
976 PCHAR deviceDesc;
977 CHAR leafName[512]; // XXXXX how big does this have to be?
978 CHAR szDriverKeyName[512];
979
980
981 // Loop over all ports of the hub.
982 //
983 // Port indices are 1 based, not 0 based.
984 //
985 for (index = 1; index <= NumPorts; index++)
986 {
987 ULONG nBytes;
988
989 // Allocate space to hold the connection info for this port.
990 // For now, allocate it big enough to hold info for 30 pipes.
991 //
992 // Endpoint numbers are 0-15. Endpoint number 0 is the standard
993 // control endpoint which is not explicitly listed in the Configuration
994 // Descriptor. There can be an IN endpoint and an OUT endpoint at
995 // endpoint numbers 1-15 so there can be a maximum of 30 endpoints
996 // per device configuration.
997 //
998 // Should probably size this dynamically at some point.
999 //
1000 nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) +
1001 sizeof(USB_PIPE_INFO) * 30;
1002
1003 connectionInfo = (PUSB_NODE_CONNECTION_INFORMATION_EX)RTMemAllocZ(nBytes);
1004
1005 if (connectionInfo == NULL)
1006 {
1007 AssertFailed();
1008 break;
1009 }
1010
1011 //
1012 // Now query USBHUB for the USB_NODE_CONNECTION_INFORMATION_EX structure
1013 // for this port. This will tell us if a device is attached to this
1014 // port, among other things.
1015 //
1016 connectionInfo->ConnectionIndex = index;
1017
1018 success = DeviceIoControl(hHubDevice,
1019 IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
1020 connectionInfo,
1021 nBytes,
1022 connectionInfo,
1023 nBytes,
1024 &nBytes,
1025 NULL);
1026
1027 if (!success)
1028 {
1029 RTMemFree(connectionInfo);
1030 continue;
1031 }
1032
1033 // Update the count of connected devices
1034 //
1035 if (connectionInfo->ConnectionStatus == DeviceConnected)
1036 {
1037 TotalDevicesConnected++;
1038 }
1039 else
1040 {
1041 RTMemFree(connectionInfo);
1042 continue;
1043 }
1044
1045 if (connectionInfo->DeviceIsHub)
1046 {
1047 TotalHubs++;
1048 }
1049
1050 // If there is a device connected, get the Device Description
1051 //
1052 deviceDesc = NULL;
1053 szDriverKeyName[0] = 0;
1054 if (connectionInfo->ConnectionStatus != NoDeviceConnected)
1055 {
1056 pszDriverKeyName = GetDriverKeyName(hHubDevice,
1057 index);
1058
1059 if (pszDriverKeyName)
1060 {
1061 Log(("Attached driver %s [port=%d]%s\n", pszDriverKeyName, index, connectionInfo->DeviceIsHub ? " DeviceIsHub" : ""));
1062 deviceDesc = DriverNameToDeviceDesc(pszDriverKeyName);
1063 Assert(strlen(pszDriverKeyName)+1 < sizeof(szDriverKeyName));
1064 if (strlen(pszDriverKeyName)+1 < sizeof(szDriverKeyName))
1065 strcpy(szDriverKeyName, pszDriverKeyName);
1066
1067 RTMemFree(pszDriverKeyName);
1068 }
1069 }
1070
1071 // If there is a device connected to the port, try to retrieve the
1072 // Configuration Descriptor from the device.
1073 //
1074 if (gDoConfigDesc &&
1075 connectionInfo->ConnectionStatus == DeviceConnected)
1076 {
1077 configDesc = GetConfigDescriptor(hHubDevice,
1078 index,
1079 0);
1080 }
1081 else
1082 {
1083 configDesc = NULL;
1084 }
1085
1086 if (configDesc != NULL &&
1087 AreThereStringDescriptors(&connectionInfo->DeviceDescriptor,
1088 (PUSB_CONFIGURATION_DESCRIPTOR)(configDesc+1)))
1089 {
1090 stringDescs = GetAllStringDescriptors(
1091 hHubDevice,
1092 index,
1093 &connectionInfo->DeviceDescriptor,
1094 (PUSB_CONFIGURATION_DESCRIPTOR)(configDesc+1));
1095 }
1096 else
1097 {
1098 stringDescs = NULL;
1099 }
1100
1101 // If the device connected to the port is an external hub, get the
1102 // name of the external hub and recursively enumerate it.
1103 //
1104 if (connectionInfo->DeviceIsHub)
1105 {
1106 PCHAR extHubName;
1107
1108 extHubName = GetExternalHubName(hHubDevice,
1109 index);
1110
1111 if (extHubName != NULL)
1112 {
1113 EnumerateHub(extHubName,
1114 connectionInfo,
1115 configDesc,
1116 stringDescs,
1117 deviceDesc);
1118
1119 // On to the next port
1120 //
1121 continue;
1122 }
1123 }
1124
1125 // Allocate some space for a USBDEVICEINFO structure to hold the
1126 // hub info, hub name, and connection info pointers. GPTR zero
1127 // initializes the structure for us.
1128 //
1129 info = (PUSBDEVICEINFO) RTMemAllocZ(sizeof(USBDEVICEINFO));
1130
1131 if (info == NULL)
1132 {
1133 AssertFailed();
1134 if (configDesc != NULL)
1135 {
1136 RTMemFree(configDesc);
1137 }
1138 RTMemFree(connectionInfo);
1139 break;
1140 }
1141
1142 info->ConnectionInfo = connectionInfo;
1143
1144 info->ConfigDesc = configDesc;
1145
1146 info->StringDescs = stringDescs;
1147
1148 sprintf(leafName, "[Port%d] ", index);
1149
1150 strcat(leafName, ConnectionStatuses[connectionInfo->ConnectionStatus]);
1151
1152 if (deviceDesc)
1153 {
1154 strcat(leafName, " : ");
1155 strcat(leafName, deviceDesc);
1156 }
1157
1158 AddLeaf(info, leafName, szDriverKeyName, pszHubName, index);
1159 }
1160}
1161
1162
1163//*****************************************************************************
1164//
1165// WideStrToMultiStr()
1166//
1167//*****************************************************************************
1168
1169PCHAR WideStrToMultiStr (PWCHAR WideStr)
1170{
1171 ULONG nBytes;
1172 PCHAR MultiStr;
1173
1174 // Get the length of the converted string
1175 //
1176 nBytes = WideCharToMultiByte(
1177 CP_ACP,
1178 0,
1179 WideStr,
1180 -1,
1181 NULL,
1182 0,
1183 NULL,
1184 NULL);
1185
1186 if (nBytes == 0)
1187 {
1188 return NULL;
1189 }
1190
1191 // Allocate space to hold the converted string
1192 //
1193 MultiStr = (PCHAR)RTMemAllocZ(nBytes);
1194
1195 if (MultiStr == NULL)
1196 {
1197 return NULL;
1198 }
1199
1200 // Convert the string
1201 //
1202 nBytes = WideCharToMultiByte(
1203 CP_ACP,
1204 0,
1205 WideStr,
1206 -1,
1207 MultiStr,
1208 nBytes,
1209 NULL,
1210 NULL);
1211
1212 if (nBytes == 0)
1213 {
1214 RTMemFree(MultiStr);
1215 return NULL;
1216 }
1217
1218 return MultiStr;
1219}
1220
1221
1222//*****************************************************************************
1223//
1224// GetRootHubName()
1225//
1226//*****************************************************************************
1227
1228PCHAR GetRootHubName (
1229 HANDLE HostController
1230)
1231{
1232 BOOL success;
1233 ULONG nBytes;
1234 USB_ROOT_HUB_NAME rootHubName;
1235 PUSB_ROOT_HUB_NAME rootHubNameW;
1236 PCHAR rootHubNameA;
1237
1238 rootHubNameW = NULL;
1239 rootHubNameA = NULL;
1240
1241 // Get the length of the name of the Root Hub attached to the
1242 // Host Controller
1243 //
1244 success = DeviceIoControl(HostController,
1245 IOCTL_USB_GET_ROOT_HUB_NAME,
1246 0,
1247 0,
1248 &rootHubName,
1249 sizeof(rootHubName),
1250 &nBytes,
1251 NULL);
1252
1253 if (!success)
1254 {
1255 AssertFailed();
1256 goto GetRootHubNameError;
1257 }
1258
1259 // Allocate space to hold the Root Hub name
1260 //
1261 nBytes = rootHubName.ActualLength;
1262
1263 rootHubNameW = (PUSB_ROOT_HUB_NAME)RTMemAllocZ(nBytes);
1264
1265 if (rootHubNameW == NULL)
1266 {
1267 AssertFailed();
1268 goto GetRootHubNameError;
1269 }
1270
1271 // Get the name of the Root Hub attached to the Host Controller
1272 //
1273 success = DeviceIoControl(HostController,
1274 IOCTL_USB_GET_ROOT_HUB_NAME,
1275 NULL,
1276 0,
1277 rootHubNameW,
1278 nBytes,
1279 &nBytes,
1280 NULL);
1281
1282 if (!success)
1283 {
1284 AssertFailed();
1285 goto GetRootHubNameError;
1286 }
1287
1288 // Convert the Root Hub name
1289 //
1290 rootHubNameA = WideStrToMultiStr(rootHubNameW->RootHubName);
1291
1292 // All done, free the uncoverted Root Hub name and return the
1293 // converted Root Hub name
1294 //
1295 RTMemFree(rootHubNameW);
1296
1297 return rootHubNameA;
1298
1299
1300GetRootHubNameError:
1301 // There was an error, free anything that was allocated
1302 //
1303 if (rootHubNameW != NULL)
1304 {
1305 RTMemFree(rootHubNameW);
1306 rootHubNameW = NULL;
1307 }
1308
1309 return NULL;
1310}
1311
1312
1313//*****************************************************************************
1314//
1315// GetExternalHubName()
1316//
1317//*****************************************************************************
1318
1319PCHAR GetExternalHubName (
1320 HANDLE Hub,
1321 ULONG ConnectionIndex
1322)
1323{
1324 BOOL success;
1325 ULONG nBytes;
1326 USB_NODE_CONNECTION_NAME extHubName;
1327 PUSB_NODE_CONNECTION_NAME extHubNameW;
1328 PCHAR extHubNameA;
1329
1330 extHubNameW = NULL;
1331 extHubNameA = NULL;
1332
1333 // Get the length of the name of the external hub attached to the
1334 // specified port.
1335 //
1336 extHubName.ConnectionIndex = ConnectionIndex;
1337
1338 success = DeviceIoControl(Hub,
1339 IOCTL_USB_GET_NODE_CONNECTION_NAME,
1340 &extHubName,
1341 sizeof(extHubName),
1342 &extHubName,
1343 sizeof(extHubName),
1344 &nBytes,
1345 NULL);
1346
1347 if (!success)
1348 {
1349 AssertFailed();
1350 goto GetExternalHubNameError;
1351 }
1352
1353 // Allocate space to hold the external hub name
1354 //
1355 nBytes = extHubName.ActualLength;
1356
1357 if (nBytes <= sizeof(extHubName))
1358 {
1359 AssertFailed();
1360 goto GetExternalHubNameError;
1361 }
1362
1363 extHubNameW = (PUSB_NODE_CONNECTION_NAME)RTMemAllocZ(nBytes);
1364
1365 if (extHubNameW == NULL)
1366 {
1367 AssertFailed();
1368 goto GetExternalHubNameError;
1369 }
1370
1371 // Get the name of the external hub attached to the specified port
1372 //
1373 extHubNameW->ConnectionIndex = ConnectionIndex;
1374
1375 success = DeviceIoControl(Hub,
1376 IOCTL_USB_GET_NODE_CONNECTION_NAME,
1377 extHubNameW,
1378 nBytes,
1379 extHubNameW,
1380 nBytes,
1381 &nBytes,
1382 NULL);
1383
1384 if (!success)
1385 {
1386 AssertFailed();
1387 goto GetExternalHubNameError;
1388 }
1389
1390 // Convert the External Hub name
1391 //
1392 extHubNameA = WideStrToMultiStr(extHubNameW->NodeName);
1393
1394 // All done, free the uncoverted external hub name and return the
1395 // converted external hub name
1396 //
1397 RTMemFree(extHubNameW);
1398
1399 return extHubNameA;
1400
1401
1402GetExternalHubNameError:
1403 // There was an error, free anything that was allocated
1404 //
1405 if (extHubNameW != NULL)
1406 {
1407 RTMemFree(extHubNameW);
1408 extHubNameW = NULL;
1409 }
1410
1411 return NULL;
1412}
1413
1414
1415//*****************************************************************************
1416//
1417// GetDriverKeyName()
1418//
1419//*****************************************************************************
1420
1421PCHAR GetDriverKeyName (
1422 HANDLE Hub,
1423 ULONG ConnectionIndex
1424)
1425{
1426 BOOL success;
1427 ULONG nBytes;
1428 USB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyName;
1429 PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyNameW;
1430 PCHAR driverKeyNameA;
1431
1432 driverKeyNameW = NULL;
1433 driverKeyNameA = NULL;
1434
1435 // Get the length of the name of the driver key of the device attached to
1436 // the specified port.
1437 //
1438 driverKeyName.ConnectionIndex = ConnectionIndex;
1439
1440 success = DeviceIoControl(Hub,
1441 IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
1442 &driverKeyName,
1443 sizeof(driverKeyName),
1444 &driverKeyName,
1445 sizeof(driverKeyName),
1446 &nBytes,
1447 NULL);
1448
1449 if (!success)
1450 {
1451 goto GetDriverKeyNameError;
1452 }
1453
1454 // Allocate space to hold the driver key name
1455 //
1456 nBytes = driverKeyName.ActualLength;
1457
1458 if (nBytes <= sizeof(driverKeyName))
1459 {
1460 AssertFailed();
1461 goto GetDriverKeyNameError;
1462 }
1463
1464 driverKeyNameW = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)RTMemAllocZ(nBytes);
1465
1466 if (driverKeyNameW == NULL)
1467 {
1468 AssertFailed();
1469 goto GetDriverKeyNameError;
1470 }
1471
1472 // Get the name of the driver key of the device attached to
1473 // the specified port.
1474 //
1475 driverKeyNameW->ConnectionIndex = ConnectionIndex;
1476
1477 success = DeviceIoControl(Hub,
1478 IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
1479 driverKeyNameW,
1480 nBytes,
1481 driverKeyNameW,
1482 nBytes,
1483 &nBytes,
1484 NULL);
1485
1486 if (!success)
1487 {
1488 AssertFailed();
1489 goto GetDriverKeyNameError;
1490 }
1491
1492 // Convert the driver key name
1493 //
1494 driverKeyNameA = WideStrToMultiStr(driverKeyNameW->DriverKeyName);
1495
1496 // All done, free the uncoverted driver key name and return the
1497 // converted driver key name
1498 //
1499 RTMemFree(driverKeyNameW);
1500
1501 return driverKeyNameA;
1502
1503
1504GetDriverKeyNameError:
1505 // There was an error, free anything that was allocated
1506 //
1507 if (driverKeyNameW != NULL)
1508 {
1509 RTMemFree(driverKeyNameW);
1510 driverKeyNameW = NULL;
1511 }
1512
1513 return NULL;
1514}
1515
1516
1517//*****************************************************************************
1518//
1519// GetHCDDriverKeyName()
1520//
1521//*****************************************************************************
1522
1523PCHAR GetHCDDriverKeyName (
1524 HANDLE HCD
1525)
1526{
1527 BOOL success;
1528 ULONG nBytes;
1529 USB_HCD_DRIVERKEY_NAME driverKeyName;
1530 PUSB_HCD_DRIVERKEY_NAME driverKeyNameW;
1531 PCHAR driverKeyNameA;
1532
1533 driverKeyNameW = NULL;
1534 driverKeyNameA = NULL;
1535
1536 // Get the length of the name of the driver key of the HCD
1537 //
1538 success = DeviceIoControl(HCD,
1539 IOCTL_GET_HCD_DRIVERKEY_NAME,
1540 &driverKeyName,
1541 sizeof(driverKeyName),
1542 &driverKeyName,
1543 sizeof(driverKeyName),
1544 &nBytes,
1545 NULL);
1546
1547 if (!success)
1548 {
1549 AssertFailed();
1550 goto GetHCDDriverKeyNameError;
1551 }
1552
1553 // Allocate space to hold the driver key name
1554 //
1555 nBytes = driverKeyName.ActualLength;
1556
1557 if (nBytes <= sizeof(driverKeyName))
1558 {
1559 AssertFailed();
1560 goto GetHCDDriverKeyNameError;
1561 }
1562
1563 driverKeyNameW = (PUSB_HCD_DRIVERKEY_NAME)RTMemAllocZ(nBytes);
1564
1565 if (driverKeyNameW == NULL)
1566 {
1567 AssertFailed();
1568 goto GetHCDDriverKeyNameError;
1569 }
1570
1571 // Get the name of the driver key of the device attached to
1572 // the specified port.
1573 //
1574 success = DeviceIoControl(HCD,
1575 IOCTL_GET_HCD_DRIVERKEY_NAME,
1576 driverKeyNameW,
1577 nBytes,
1578 driverKeyNameW,
1579 nBytes,
1580 &nBytes,
1581 NULL);
1582
1583 if (!success)
1584 {
1585 AssertFailed();
1586 goto GetHCDDriverKeyNameError;
1587 }
1588
1589 // Convert the driver key name
1590 //
1591 driverKeyNameA = WideStrToMultiStr(driverKeyNameW->DriverKeyName);
1592
1593 // All done, free the uncoverted driver key name and return the
1594 // converted driver key name
1595 //
1596 RTMemFree(driverKeyNameW);
1597
1598 return driverKeyNameA;
1599
1600
1601GetHCDDriverKeyNameError:
1602 // There was an error, free anything that was allocated
1603 //
1604 if (driverKeyNameW != NULL)
1605 {
1606 RTMemFree(driverKeyNameW);
1607 driverKeyNameW = NULL;
1608 }
1609
1610 return NULL;
1611}
1612
1613
1614//*****************************************************************************
1615//
1616// GetConfigDescriptor()
1617//
1618// hHubDevice - Handle of the hub device containing the port from which the
1619// Configuration Descriptor will be requested.
1620//
1621// ConnectionIndex - Identifies the port on the hub to which a device is
1622// attached from which the Configuration Descriptor will be requested.
1623//
1624// DescriptorIndex - Configuration Descriptor index, zero based.
1625//
1626//*****************************************************************************
1627
1628PUSB_DESCRIPTOR_REQUEST
1629GetConfigDescriptor (
1630 HANDLE hHubDevice,
1631 ULONG ConnectionIndex,
1632 UCHAR DescriptorIndex
1633)
1634{
1635 BOOL success;
1636 ULONG nBytes;
1637 ULONG nBytesReturned;
1638
1639 UCHAR configDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) +
1640 sizeof(USB_CONFIGURATION_DESCRIPTOR)];
1641
1642 PUSB_DESCRIPTOR_REQUEST configDescReq;
1643 PUSB_CONFIGURATION_DESCRIPTOR configDesc;
1644
1645
1646 // Request the Configuration Descriptor the first time using our
1647 // local buffer, which is just big enough for the Cofiguration
1648 // Descriptor itself.
1649 //
1650 nBytes = sizeof(configDescReqBuf);
1651
1652 configDescReq = (PUSB_DESCRIPTOR_REQUEST)configDescReqBuf;
1653 configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(configDescReq+1);
1654
1655 // Zero fill the entire request structure
1656 //
1657 memset(configDescReq, 0, nBytes);
1658
1659 // Indicate the port from which the descriptor will be requested
1660 //
1661 configDescReq->ConnectionIndex = ConnectionIndex;
1662
1663 //
1664 // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this
1665 // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.
1666 //
1667 // USBD will automatically initialize these fields:
1668 // bmRequest = 0x80
1669 // bRequest = 0x06
1670 //
1671 // We must initialize these fields:
1672 // wValue = Descriptor Type (high) and Descriptor Index (low byte)
1673 // wIndex = Zero (or Language ID for String Descriptors)
1674 // wLength = Length of descriptor buffer
1675 //
1676 configDescReq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8)
1677 | DescriptorIndex;
1678
1679 configDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));
1680
1681 // Now issue the get descriptor request.
1682 //
1683 success = DeviceIoControl(hHubDevice,
1684 IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
1685 configDescReq,
1686 nBytes,
1687 configDescReq,
1688 nBytes,
1689 &nBytesReturned,
1690 NULL);
1691
1692 if (!success)
1693 {
1694#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1695 AssertMsgFailed(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION failed with %d\n", GetLastError()));
1696#else
1697 LogRel(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION failed with %d\n", GetLastError()));
1698#endif
1699 return NULL;
1700 }
1701
1702 if (nBytes != nBytesReturned)
1703 {
1704 AssertFailed();
1705 return NULL;
1706 }
1707
1708 if (configDesc->wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))
1709 {
1710 AssertFailed();
1711 return NULL;
1712 }
1713
1714 // Now request the entire Configuration Descriptor using a dynamically
1715 // allocated buffer which is sized big enough to hold the entire descriptor
1716 //
1717 nBytes = sizeof(USB_DESCRIPTOR_REQUEST) + configDesc->wTotalLength;
1718
1719 configDescReq = (PUSB_DESCRIPTOR_REQUEST)RTMemAllocZ(nBytes);
1720
1721 if (configDescReq == NULL)
1722 {
1723 AssertFailed();
1724 return NULL;
1725 }
1726
1727 configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(configDescReq+1);
1728
1729 // Indicate the port from which the descriptor will be requested
1730 //
1731 configDescReq->ConnectionIndex = ConnectionIndex;
1732
1733 //
1734 // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this
1735 // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.
1736 //
1737 // USBD will automatically initialize these fields:
1738 // bmRequest = 0x80
1739 // bRequest = 0x06
1740 //
1741 // We must initialize these fields:
1742 // wValue = Descriptor Type (high) and Descriptor Index (low byte)
1743 // wIndex = Zero (or Language ID for String Descriptors)
1744 // wLength = Length of descriptor buffer
1745 //
1746 configDescReq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8)
1747 | DescriptorIndex;
1748
1749 configDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));
1750
1751 // Now issue the get descriptor request.
1752 //
1753 success = DeviceIoControl(hHubDevice,
1754 IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
1755 configDescReq,
1756 nBytes,
1757 configDescReq,
1758 nBytes,
1759 &nBytesReturned,
1760 NULL);
1761
1762 if (!success)
1763 {
1764#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1765 AssertMsgFailed(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION failed with %d\n", GetLastError()));
1766#else
1767 LogRel(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION failed with %d\n", GetLastError()));
1768#endif
1769 RTMemFree(configDescReq);
1770 return NULL;
1771 }
1772
1773 if (nBytes != nBytesReturned)
1774 {
1775#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1776 AssertMsgFailed(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION %d != %d\n", nBytes, nBytesReturned));
1777#else
1778 LogRel(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION %d != %d\n", nBytes, nBytesReturned));
1779#endif
1780 RTMemFree(configDescReq);
1781 return NULL;
1782 }
1783
1784 if (configDesc->wTotalLength != (nBytes - sizeof(USB_DESCRIPTOR_REQUEST)))
1785 {
1786#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
1787 AssertMsgFailed(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION %d != %d\n", configDesc->wTotalLength, (nBytes - sizeof(USB_DESCRIPTOR_REQUEST))));
1788#else
1789 LogRel(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION %d != %d\n", configDesc->wTotalLength, (nBytes - sizeof(USB_DESCRIPTOR_REQUEST)) ));
1790#endif
1791 RTMemFree(configDescReq);
1792 return NULL;
1793 }
1794
1795 return configDescReq;
1796}
1797
1798
1799//*****************************************************************************
1800//
1801// AreThereStringDescriptors()
1802//
1803// DeviceDesc - Device Descriptor for which String Descriptors should be
1804// checked.
1805//
1806// ConfigDesc - Configuration Descriptor (also containing Interface Descriptor)
1807// for which String Descriptors should be checked.
1808//
1809//*****************************************************************************
1810
1811BOOL
1812AreThereStringDescriptors (
1813 PUSB_DEVICE_DESCRIPTOR DeviceDesc,
1814 PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc
1815)
1816{
1817 PUCHAR descEnd;
1818 PUSB_COMMON_DESCRIPTOR commonDesc;
1819
1820 //
1821 // Check Device Descriptor strings
1822 //
1823
1824 if (DeviceDesc->iManufacturer ||
1825 DeviceDesc->iProduct ||
1826 DeviceDesc->iSerialNumber
1827 )
1828 {
1829 return TRUE;
1830 }
1831
1832
1833 //
1834 // Check the Configuration and Interface Descriptor strings
1835 //
1836
1837 descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength;
1838
1839 commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc;
1840
1841 while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&
1842 (PUCHAR)commonDesc + commonDesc->bLength <= descEnd)
1843 {
1844 switch (commonDesc->bDescriptorType)
1845 {
1846 case USB_CONFIGURATION_DESCRIPTOR_TYPE:
1847 if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR))
1848 {
1849 AssertFailed();
1850 break;
1851 }
1852 if (((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration)
1853 {
1854 return TRUE;
1855 }
1856 commonDesc = (PUSB_COMMON_DESCRIPTOR)((PUCHAR)commonDesc + commonDesc->bLength);
1857 continue;
1858
1859 case USB_INTERFACE_DESCRIPTOR_TYPE:
1860 if (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR) &&
1861 commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2))
1862 {
1863 AssertFailed();
1864 break;
1865 }
1866 if (((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface)
1867 {
1868 return TRUE;
1869 }
1870 commonDesc = (PUSB_COMMON_DESCRIPTOR)((PUCHAR)commonDesc + commonDesc->bLength);
1871 continue;
1872
1873 default:
1874 commonDesc = (PUSB_COMMON_DESCRIPTOR)((PUCHAR)commonDesc + commonDesc->bLength);
1875 continue;
1876 }
1877 break;
1878 }
1879
1880 return FALSE;
1881}
1882
1883
1884//*****************************************************************************
1885//
1886// GetAllStringDescriptors()
1887//
1888// hHubDevice - Handle of the hub device containing the port from which the
1889// String Descriptors will be requested.
1890//
1891// ConnectionIndex - Identifies the port on the hub to which a device is
1892// attached from which the String Descriptors will be requested.
1893//
1894// DeviceDesc - Device Descriptor for which String Descriptors should be
1895// requested.
1896//
1897// ConfigDesc - Configuration Descriptor (also containing Interface Descriptor)
1898// for which String Descriptors should be requested.
1899//
1900//*****************************************************************************
1901
1902PSTRING_DESCRIPTOR_NODE
1903GetAllStringDescriptors (
1904 HANDLE hHubDevice,
1905 ULONG ConnectionIndex,
1906 PUSB_DEVICE_DESCRIPTOR DeviceDesc,
1907 PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc
1908)
1909{
1910 PSTRING_DESCRIPTOR_NODE supportedLanguagesString;
1911 PSTRING_DESCRIPTOR_NODE stringDescNodeTail;
1912 ULONG numLanguageIDs;
1913 USHORT *languageIDs;
1914
1915 PUCHAR descEnd;
1916 PUSB_COMMON_DESCRIPTOR commonDesc;
1917
1918 //
1919 // Get the array of supported Language IDs, which is returned
1920 // in String Descriptor 0
1921 //
1922 supportedLanguagesString = GetStringDescriptor(hHubDevice,
1923 ConnectionIndex,
1924 0,
1925 0);
1926
1927 if (supportedLanguagesString == NULL)
1928 {
1929 return NULL;
1930 }
1931
1932 numLanguageIDs = (supportedLanguagesString->StringDescriptor->bLength - 2) / 2;
1933
1934 languageIDs = (PUSHORT)&supportedLanguagesString->StringDescriptor->bString[0];
1935
1936 stringDescNodeTail = supportedLanguagesString;
1937
1938 //
1939 // Get the Device Descriptor strings
1940 //
1941
1942 if (DeviceDesc->iManufacturer)
1943 {
1944 stringDescNodeTail = GetStringDescriptors(hHubDevice,
1945 ConnectionIndex,
1946 DeviceDesc->iManufacturer,
1947 numLanguageIDs,
1948 languageIDs,
1949 stringDescNodeTail);
1950 }
1951
1952 if (DeviceDesc->iProduct)
1953 {
1954 stringDescNodeTail = GetStringDescriptors(hHubDevice,
1955 ConnectionIndex,
1956 DeviceDesc->iProduct,
1957 numLanguageIDs,
1958 languageIDs,
1959 stringDescNodeTail);
1960 }
1961
1962 if (DeviceDesc->iSerialNumber)
1963 {
1964 stringDescNodeTail = GetStringDescriptors(hHubDevice,
1965 ConnectionIndex,
1966 DeviceDesc->iSerialNumber,
1967 numLanguageIDs,
1968 languageIDs,
1969 stringDescNodeTail);
1970 }
1971
1972
1973 //
1974 // Get the Configuration and Interface Descriptor strings
1975 //
1976
1977 descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength;
1978
1979 commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc;
1980
1981 while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&
1982 (PUCHAR)commonDesc + commonDesc->bLength <= descEnd)
1983 {
1984 switch (commonDesc->bDescriptorType)
1985 {
1986 case USB_CONFIGURATION_DESCRIPTOR_TYPE:
1987 if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR))
1988 {
1989 AssertFailed();
1990 break;
1991 }
1992 if (((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration)
1993 {
1994 stringDescNodeTail = GetStringDescriptors(
1995 hHubDevice,
1996 ConnectionIndex,
1997 ((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration,
1998 numLanguageIDs,
1999 languageIDs,
2000 stringDescNodeTail);
2001 }
2002 commonDesc = (PUSB_COMMON_DESCRIPTOR)((PUCHAR)commonDesc + commonDesc->bLength);
2003 continue;
2004
2005 case USB_INTERFACE_DESCRIPTOR_TYPE:
2006 if (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR) &&
2007 commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2))
2008 {
2009 AssertFailed();
2010 break;
2011 }
2012 if (((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface)
2013 {
2014 stringDescNodeTail = GetStringDescriptors(
2015 hHubDevice,
2016 ConnectionIndex,
2017 ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface,
2018 numLanguageIDs,
2019 languageIDs,
2020 stringDescNodeTail);
2021 }
2022 commonDesc = (PUSB_COMMON_DESCRIPTOR)((PUCHAR)commonDesc + commonDesc->bLength);
2023 continue;
2024
2025 default:
2026 commonDesc = (PUSB_COMMON_DESCRIPTOR)((PUCHAR)commonDesc + commonDesc->bLength);
2027 continue;
2028 }
2029 break;
2030 }
2031
2032 return supportedLanguagesString;
2033}
2034
2035
2036//*****************************************************************************
2037//
2038// GetStringDescriptor()
2039//
2040// hHubDevice - Handle of the hub device containing the port from which the
2041// String Descriptor will be requested.
2042//
2043// ConnectionIndex - Identifies the port on the hub to which a device is
2044// attached from which the String Descriptor will be requested.
2045//
2046// DescriptorIndex - String Descriptor index.
2047//
2048// LanguageID - Language in which the string should be requested.
2049//
2050//*****************************************************************************
2051
2052PSTRING_DESCRIPTOR_NODE
2053GetStringDescriptor (
2054 HANDLE hHubDevice,
2055 ULONG ConnectionIndex,
2056 UCHAR DescriptorIndex,
2057 USHORT LanguageID
2058)
2059{
2060 BOOL success;
2061 ULONG nBytes;
2062 ULONG nBytesReturned;
2063
2064 UCHAR stringDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) +
2065 MAXIMUM_USB_STRING_LENGTH];
2066
2067 PUSB_DESCRIPTOR_REQUEST stringDescReq;
2068 PUSB_STRING_DESCRIPTOR stringDesc;
2069 PSTRING_DESCRIPTOR_NODE stringDescNode;
2070
2071 nBytes = sizeof(stringDescReqBuf);
2072
2073 stringDescReq = (PUSB_DESCRIPTOR_REQUEST)stringDescReqBuf;
2074 stringDesc = (PUSB_STRING_DESCRIPTOR)(stringDescReq+1);
2075
2076 // Zero fill the entire request structure
2077 //
2078 memset(stringDescReq, 0, nBytes);
2079
2080 // Indicate the port from which the descriptor will be requested
2081 //
2082 stringDescReq->ConnectionIndex = ConnectionIndex;
2083
2084 //
2085 // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this
2086 // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.
2087 //
2088 // USBD will automatically initialize these fields:
2089 // bmRequest = 0x80
2090 // bRequest = 0x06
2091 //
2092 // We must initialize these fields:
2093 // wValue = Descriptor Type (high) and Descriptor Index (low byte)
2094 // wIndex = Zero (or Language ID for String Descriptors)
2095 // wLength = Length of descriptor buffer
2096 //
2097 stringDescReq->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8)
2098 | DescriptorIndex;
2099
2100 stringDescReq->SetupPacket.wIndex = LanguageID;
2101
2102 stringDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));
2103
2104 // Now issue the get descriptor request.
2105 //
2106 success = DeviceIoControl(hHubDevice,
2107 IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
2108 stringDescReq,
2109 nBytes,
2110 stringDescReq,
2111 nBytes,
2112 &nBytesReturned,
2113 NULL);
2114
2115 //
2116 // Do some sanity checks on the return from the get descriptor request.
2117 //
2118
2119 if (!success)
2120 {
2121#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
2122 AssertMsgFailed(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION failed with %d\n", GetLastError()));
2123#else
2124 LogRel(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION failed with %d\n", GetLastError()));
2125#endif
2126 return NULL;
2127 }
2128
2129 if (nBytesReturned < 2)
2130 {
2131 AssertFailed();
2132 return NULL;
2133 }
2134
2135 if (stringDesc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE)
2136 {
2137 AssertFailed();
2138 return NULL;
2139 }
2140
2141 if (stringDesc->bLength != nBytesReturned - sizeof(USB_DESCRIPTOR_REQUEST))
2142 {
2143 AssertFailed();
2144 return NULL;
2145 }
2146
2147 if (stringDesc->bLength % 2 != 0)
2148 {
2149 AssertFailed();
2150 return NULL;
2151 }
2152
2153 //
2154 // Looks good, allocate some (zero filled) space for the string descriptor
2155 // node and copy the string descriptor to it.
2156 //
2157
2158 stringDescNode = (PSTRING_DESCRIPTOR_NODE)RTMemAllocZ(sizeof(STRING_DESCRIPTOR_NODE) +
2159 stringDesc->bLength + 2);
2160
2161 if (stringDescNode == NULL)
2162 {
2163 AssertFailed();
2164 return NULL;
2165 }
2166
2167 stringDescNode->DescriptorIndex = DescriptorIndex;
2168 stringDescNode->LanguageID = LanguageID;
2169
2170 memcpy(stringDescNode->StringDescriptor,
2171 stringDesc,
2172 stringDesc->bLength);
2173
2174 return stringDescNode;
2175}
2176
2177
2178//*****************************************************************************
2179//
2180// GetStringDescriptors()
2181//
2182// hHubDevice - Handle of the hub device containing the port from which the
2183// String Descriptor will be requested.
2184//
2185// ConnectionIndex - Identifies the port on the hub to which a device is
2186// attached from which the String Descriptor will be requested.
2187//
2188// DescriptorIndex - String Descriptor index.
2189//
2190// NumLanguageIDs - Number of languages in which the string should be
2191// requested.
2192//
2193// LanguageIDs - Languages in which the string should be requested.
2194//
2195//*****************************************************************************
2196
2197PSTRING_DESCRIPTOR_NODE
2198GetStringDescriptors (
2199 HANDLE hHubDevice,
2200 ULONG ConnectionIndex,
2201 UCHAR DescriptorIndex,
2202 ULONG NumLanguageIDs,
2203 USHORT *LanguageIDs,
2204 PSTRING_DESCRIPTOR_NODE StringDescNodeTail
2205)
2206{
2207 ULONG i;
2208
2209 for (i = 0; i < NumLanguageIDs; i++)
2210 {
2211 StringDescNodeTail->Next = GetStringDescriptor(hHubDevice,
2212 ConnectionIndex,
2213 DescriptorIndex,
2214 *LanguageIDs);
2215
2216 if (StringDescNodeTail->Next)
2217 {
2218 StringDescNodeTail = StringDescNodeTail->Next;
2219 }
2220
2221 LanguageIDs++;
2222 }
2223
2224 return StringDescNodeTail;
2225}
2226
2227
2228//*****************************************************************************
2229//
2230// DriverNameToDeviceDesc()
2231//
2232// Returns the Device Description of the DevNode with the matching DriverName.
2233// Returns NULL if the matching DevNode is not found.
2234//
2235// The caller should copy the returned string buffer instead of just saving
2236// the pointer value. XXXXX Dynamically allocate return buffer?
2237//
2238//*****************************************************************************
2239CHAR buf[512]; // XXXXX How big does this have to be? Dynamically size it?
2240
2241PCHAR DriverNameToDeviceDesc (PCHAR DriverName)
2242{
2243 DEVINST devInst;
2244 DEVINST devInstNext;
2245 CONFIGRET cr;
2246 ULONG walkDone = 0;
2247 ULONG len;
2248
2249 // Get Root DevNode
2250 //
2251 cr = CM_Locate_DevNode(&devInst,
2252 NULL,
2253 0);
2254
2255 if (cr != CR_SUCCESS)
2256 {
2257 return NULL;
2258 }
2259
2260 // Do a depth first search for the DevNode with a matching
2261 // DriverName value
2262 //
2263 while (!walkDone)
2264 {
2265 // Get the DriverName value
2266 //
2267 len = sizeof(buf);
2268 cr = CM_Get_DevNode_Registry_Property(devInst,
2269 CM_DRP_DRIVER,
2270 NULL,
2271 buf,
2272 &len,
2273 0);
2274
2275 // If the DriverName value matches, return the DeviceDescription
2276 //
2277 if (cr == CR_SUCCESS && _stricmp(DriverName, buf) == 0)
2278 {
2279 len = sizeof(buf);
2280 cr = CM_Get_DevNode_Registry_Property(devInst,
2281 CM_DRP_DEVICEDESC,
2282 NULL,
2283 buf,
2284 &len,
2285 0);
2286
2287 if (cr == CR_SUCCESS)
2288 {
2289 return buf;
2290 }
2291 else
2292 {
2293 return NULL;
2294 }
2295 }
2296
2297 // This DevNode didn't match, go down a level to the first child.
2298 //
2299 cr = CM_Get_Child(&devInstNext,
2300 devInst,
2301 0);
2302
2303 if (cr == CR_SUCCESS)
2304 {
2305 devInst = devInstNext;
2306 continue;
2307 }
2308
2309 // Can't go down any further, go across to the next sibling. If
2310 // there are no more siblings, go back up until there is a sibling.
2311 // If we can't go up any further, we're back at the root and we're
2312 // done.
2313 //
2314 for (;;)
2315 {
2316 cr = CM_Get_Sibling(&devInstNext,
2317 devInst,
2318 0);
2319
2320 if (cr == CR_SUCCESS)
2321 {
2322 devInst = devInstNext;
2323 break;
2324 }
2325
2326 cr = CM_Get_Parent(&devInstNext,
2327 devInst,
2328 0);
2329
2330
2331 if (cr == CR_SUCCESS)
2332 {
2333 devInst = devInstNext;
2334 }
2335 else
2336 {
2337 walkDone = 1;
2338 break;
2339 }
2340 }
2341 }
2342
2343 return NULL;
2344}
2345
2346
2347/**
2348 * Attempts to start the service, creating it if necessary.
2349 *
2350 * @returns 0 on success.
2351 * @returns -1 on failure.
2352 * @param fRetry Indicates retry call.
2353 */
2354int usbMonStartService(void)
2355{
2356 /*
2357 * Check if the driver service is there.
2358 */
2359 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_QUERY_STATUS | SERVICE_START);
2360 if (hSMgr == NULL)
2361 {
2362 AssertMsgFailed(("couldn't open service manager in SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS mode!\n"));
2363 return -1;
2364 }
2365
2366 /*
2367 * Try open our service to check it's status.
2368 */
2369 SC_HANDLE hService = OpenService(hSMgr, USBMON_SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_START);
2370 if (!hService)
2371 return -1;
2372
2373 /*
2374 * Check if open and on demand create succeeded.
2375 */
2376 int rc = -1;
2377 if (hService)
2378 {
2379
2380 /*
2381 * Query service status to see if we need to start it or not.
2382 */
2383 SERVICE_STATUS Status;
2384 BOOL fRc = QueryServiceStatus(hService, &Status);
2385 Assert(fRc);
2386 if ( Status.dwCurrentState != SERVICE_RUNNING
2387 && Status.dwCurrentState != SERVICE_START_PENDING)
2388 {
2389 /*
2390 * Start it.
2391 */
2392 LogRel(("usbMonStartService -> start it\n"));
2393
2394 fRc = StartService(hService, 0, NULL);
2395 DWORD LastError = GetLastError(); NOREF(LastError);
2396 AssertMsg(fRc, ("StartService failed with LastError=%Rwa\n", LastError));
2397 if (fRc)
2398 g_fStartedService = true;
2399 }
2400
2401 /*
2402 * Wait for the service to finish starting.
2403 * We'll wait for 10 seconds then we'll give up.
2404 */
2405 QueryServiceStatus(hService, &Status);
2406 if (Status.dwCurrentState == SERVICE_START_PENDING)
2407 {
2408 int iWait;
2409 for (iWait = 100; iWait > 0 && Status.dwCurrentState == SERVICE_START_PENDING; iWait--)
2410 {
2411 Sleep(100);
2412 QueryServiceStatus(hService, &Status);
2413 }
2414 DWORD LastError = GetLastError(); NOREF(LastError);
2415 AssertMsg(Status.dwCurrentState != SERVICE_RUNNING,
2416 ("Failed to start. LastError=%Rwa iWait=%d status=%d\n",
2417 LastError, iWait, Status.dwCurrentState));
2418 }
2419
2420 if (Status.dwCurrentState == SERVICE_RUNNING)
2421 rc = 0;
2422
2423 /*
2424 * Close open handles.
2425 */
2426 CloseServiceHandle(hService);
2427 }
2428 else
2429 {
2430 DWORD LastError = GetLastError(); NOREF(LastError);
2431 AssertMsgFailed(("OpenService failed! LastError=%Rwa\n", LastError));
2432 }
2433 if (!CloseServiceHandle(hSMgr))
2434 AssertFailed();
2435
2436 return rc;
2437}
2438
2439/**
2440 * Stops a possibly running service.
2441 *
2442 * @returns 0 on success.
2443 * @returns -1 on failure.
2444 */
2445int usbMonStopService(void)
2446{
2447 LogRel(("usbMonStopService\n"));
2448 /*
2449 * Assume it didn't exist, so we'll create the service.
2450 */
2451 int rc = -1;
2452 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_STOP | SERVICE_QUERY_STATUS);
2453 DWORD LastError = GetLastError(); NOREF(LastError);
2454 AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed rc=%d\n", LastError));
2455 if (hSMgr)
2456 {
2457 SC_HANDLE hService = OpenService(hSMgr, USBMON_SERVICE_NAME, SERVICE_STOP | SERVICE_QUERY_STATUS);
2458 if (hService)
2459 {
2460 /*
2461 * Stop the service.
2462 */
2463 SERVICE_STATUS Status;
2464 QueryServiceStatus(hService, &Status);
2465 if (Status.dwCurrentState == SERVICE_STOPPED)
2466 rc = 0;
2467 else if (ControlService(hService, SERVICE_CONTROL_STOP, &Status))
2468 {
2469 int iWait = 100;
2470 while (Status.dwCurrentState == SERVICE_STOP_PENDING && iWait-- > 0)
2471 {
2472 Sleep(100);
2473 QueryServiceStatus(hService, &Status);
2474 }
2475 if (Status.dwCurrentState == SERVICE_STOPPED)
2476 rc = 0;
2477 else
2478 AssertMsgFailed(("Failed to stop service. status=%d\n", Status.dwCurrentState));
2479 }
2480 else
2481 {
2482 DWORD LastError = GetLastError(); NOREF(LastError);
2483 AssertMsgFailed(("ControlService failed with LastError=%Rwa. status=%d\n", LastError, Status.dwCurrentState));
2484 }
2485 CloseServiceHandle(hService);
2486 }
2487 else if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
2488 rc = 0;
2489 else
2490 {
2491 DWORD LastError = GetLastError(); NOREF(LastError);
2492 AssertMsgFailed(("OpenService failed LastError=%Rwa\n", LastError));
2493 }
2494 CloseServiceHandle(hSMgr);
2495 }
2496 return rc;
2497}
2498
2499
2500/**
2501 * Initialize the USB library
2502 *
2503 * @returns VBox status code.
2504 */
2505USBLIB_DECL(int) USBLibInit(void)
2506{
2507 int rc;
2508 USBSUP_VERSION version = {0};
2509 DWORD cbReturned;
2510
2511 Log(("usbproxy: usbLibInit\n"));
2512
2513 g_hUSBMonitor = CreateFile(USBMON_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
2514 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
2515
2516 if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
2517 {
2518 usbMonStartService();
2519
2520 g_hUSBMonitor = CreateFile(USBMON_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
2521 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
2522
2523 if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
2524 {
2525 /* AssertFailed(); */
2526 LogRel(("usbproxy: Unable to open monitor driver!! (rc=%d)\n", GetLastError()));
2527 rc = VERR_FILE_NOT_FOUND;
2528 goto failure;
2529 }
2530 }
2531
2532 /*
2533 * Check the version
2534 */
2535 cbReturned = 0;
2536 if (!DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_GET_VERSION, NULL, 0,&version, sizeof(version), &cbReturned, NULL))
2537 {
2538 LogRel(("usbproxy: Unable to query filter version!! (rc=%d)\n", GetLastError()));
2539 rc = VERR_VERSION_MISMATCH;
2540 goto failure;
2541 }
2542
2543 if (version.u32Major != USBMON_MAJOR_VERSION ||
2544 version.u32Minor < USBMON_MINOR_VERSION)
2545 {
2546 LogRel(("usbproxy: Filter driver version mismatch!!\n"));
2547 rc = VERR_VERSION_MISMATCH;
2548 goto failure;
2549 }
2550 return VINF_SUCCESS;
2551
2552failure:
2553 if (g_hUSBMonitor != INVALID_HANDLE_VALUE)
2554 {
2555 CloseHandle(g_hUSBMonitor);
2556 g_hUSBMonitor = INVALID_HANDLE_VALUE;
2557 }
2558 return rc;
2559}
2560
2561
2562/**
2563 * Terminate the USB library
2564 *
2565 * @returns VBox status code.
2566 */
2567USBLIB_DECL(int) USBLibTerm(void)
2568{
2569 if (g_hUSBMonitor != INVALID_HANDLE_VALUE)
2570 {
2571 CloseHandle(g_hUSBMonitor);
2572 g_hUSBMonitor = INVALID_HANDLE_VALUE;
2573 }
2574#if 0
2575 /*
2576 * If we started the service we might consider stopping it too.
2577 *
2578 * Since this won't work unless the process starting it is the
2579 * last user we might wanna skip this...
2580 */
2581 if (g_fStartedService)
2582 {
2583 usbMonStopService();
2584 g_fStartedService = false;
2585 }
2586#endif
2587
2588 return VINF_SUCCESS;
2589}
2590
2591/**
2592 * Capture specified USB device
2593 *
2594 * @returns VBox status code
2595 * @param usVendorId Vendor id
2596 * @param usProductId Product id
2597 * @param usRevision Revision
2598 */
2599USBLIB_DECL(int) USBLibCaptureDevice(uint16_t usVendorId, uint16_t usProductId, uint16_t usRevision)
2600{
2601 USBSUP_CAPTURE capture;
2602 DWORD cbReturned = 0;
2603
2604 Log(("usbLibCaptureDevice %x %x %x\n", usVendorId, usProductId, usRevision));
2605
2606 if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
2607 return VERR_NOT_SUPPORTED;
2608
2609 capture.usVendorId = usVendorId;
2610 capture.usProductId = usProductId;
2611 capture.usRevision = usRevision;
2612
2613 if (!DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_CAPTURE_DEVICE, &capture, sizeof(capture), NULL, 0, &cbReturned, NULL))
2614 {
2615 AssertMsgFailed(("DeviceIoControl failed with %d\n", GetLastError()));
2616 return RTErrConvertFromWin32(GetLastError());
2617 }
2618
2619 return VINF_SUCCESS;
2620}
2621
2622/**
2623 * Release specified USB device to the host.
2624 *
2625 * @returns VBox status code
2626 * @param usVendorId Vendor id
2627 * @param usProductId Product id
2628 * @param usRevision Revision
2629 */
2630USBLIB_DECL(int) USBLibReleaseDevice(uint16_t usVendorId, uint16_t usProductId, uint16_t usRevision)
2631{
2632 USBSUP_RELEASE release;
2633 DWORD cbReturned = 0;
2634
2635 Log(("usbLibReleaseDevice %x %x %x\n", usVendorId, usProductId, usRevision));
2636
2637 if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
2638 return VERR_NOT_SUPPORTED;
2639
2640 release.usVendorId = usVendorId;
2641 release.usProductId = usProductId;
2642 release.usRevision = usRevision;
2643
2644 if (!DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_RELEASE_DEVICE, &release, sizeof(release), NULL, 0, &cbReturned, NULL))
2645 {
2646 AssertMsgFailed(("DeviceIoControl failed with %d\n", GetLastError()));
2647 return RTErrConvertFromWin32(GetLastError());
2648 }
2649
2650 return VINF_SUCCESS;
2651}
2652
2653
2654USBLIB_DECL(void *) USBLibAddFilter(PCUSBFILTER pFilter)
2655{
2656 USBSUP_FLTADDOUT add_out;
2657 DWORD cbReturned = 0;
2658
2659 if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
2660 return NULL;
2661
2662 Log(("usblibInsertFilter: Manufacturer=%s Product=%s Serial=%s\n",
2663 USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
2664 USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
2665 USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
2666
2667 if (!DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_ADD_FILTER, (LPVOID)pFilter, sizeof(*pFilter), &add_out, sizeof(add_out), &cbReturned, NULL))
2668 {
2669 AssertMsgFailed(("DeviceIoControl failed with %d\n", GetLastError()));
2670 return NULL;
2671 }
2672 if (RT_FAILURE(add_out.rc))
2673 {
2674 AssertMsgFailed(("Adding filter failed with %d\n", add_out.rc));
2675 return NULL;
2676 }
2677 return (void *)add_out.uId;
2678}
2679
2680
2681USBLIB_DECL(void) USBLibRemoveFilter(void *pvId)
2682{
2683 uintptr_t uId;
2684 DWORD cbReturned = 0;
2685
2686 if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
2687 return;
2688
2689 Log(("usblibRemoveFilter %p\n", pvId));
2690
2691 uId = (uintptr_t)pvId;
2692 if (!DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_REMOVE_FILTER, &uId, sizeof(uId), NULL, 0,&cbReturned, NULL))
2693 AssertMsgFailed(("DeviceIoControl failed with %d\n", GetLastError()));
2694}
2695
2696
2697/**
2698 * Return all attached USB devices that are captured by the filter
2699 *
2700 * @returns VBox status code
2701 * @param ppDevices Receives pointer to list of devices
2702 * @param pcDevices Number of USB devices in the list
2703 */
2704USBLIB_DECL(int) USBLibGetDevices(PUSBDEVICE *ppDevices, uint32_t *pcDevices)
2705{
2706 USBSUP_GETNUMDEV numdev;
2707 PUSBDEVICE pDevice = NULL;
2708 Log(("usbLibGetDevices: enter\n"));
2709
2710 if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
2711 return VERR_NOT_SUPPORTED;
2712
2713 /* 1: Enumerate all usb devices attached to the host */
2714 PUSBDEVICE pHostDevices = NULL;
2715 uint32_t cHostDevices = 0;
2716 usbLibEnumerateHostControllers(&pHostDevices, &cHostDevices);
2717#ifdef LOG_ENABLED
2718 Log(("usbLibGetDevices: Detected %d host devices\n", cHostDevices));
2719 pDevice = pHostDevices;
2720 int iDevice = 0;
2721 while (pDevice)
2722 {
2723 iDevice++;
2724 Log(("Detected host device: #%d\n", iDevice));
2725 Log((" Vendor Id: 0x%04X\n", pDevice->idVendor));
2726 Log((" Product Id: 0x%04X\n", pDevice->idProduct));
2727 Log((" Revision: 0x%04X\n", pDevice->bcdDevice));
2728 Log((" Address: %s\n", pDevice->pszAddress));
2729 Log((" HubName: %s\n", pDevice->pszHubName));
2730 Log((" Port: %u\n", pDevice->bPort));
2731 Log((" Manufacturer: %s\n", pDevice->pszManufacturer));
2732 Log((" Product: %s\n", pDevice->pszProduct));
2733 if (pDevice->pszSerialNumber)
2734 Log((" Serial Nr.: %s\n", pDevice->pszSerialNumber));
2735
2736 switch(pDevice->enmState)
2737 {
2738 case USBDEVICESTATE_UNSUPPORTED:
2739 Log((" State USBDEVICESTATE_UNSUPPORTED\n"));
2740 break;
2741 case USBDEVICESTATE_USED_BY_HOST:
2742 Log((" State USBDEVICESTATE_USED_BY_HOST\n"));
2743 break;
2744 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
2745 Log((" State USBDEVICESTATE_USED_BY_HOST_CAPTURABLE\n"));
2746 break;
2747 case USBDEVICESTATE_UNUSED:
2748 Log((" State USBDEVICESTATE_UNUSED\n"));
2749 break;
2750 case USBDEVICESTATE_HELD_BY_PROXY:
2751 Log((" State USBDEVICESTATE_HELD_BY_PROXY\n"));
2752 break;
2753 case USBDEVICESTATE_USED_BY_GUEST:
2754 Log((" State USBDEVICESTATE_USED_BY_GUEST\n"));
2755 break;
2756 }
2757
2758 pDevice = pDevice->pNext;
2759 }
2760#endif
2761
2762 *ppDevices = 0;
2763 *pcDevices = 0;
2764
2765 /*
2766 * Get the return data.
2767 * Note that we might be called a bit too early here. Give windows time to register the new USB driver/device.
2768 * It's no problem to block here as we're in the async usb detection thread (not EMT)
2769 */
2770
2771 for (int i = 0; i < 100; i++)
2772 {
2773 /*
2774 * Get the number of USB devices.
2775 */
2776 DWORD cbReturned = 0;
2777 if (!DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_GET_NUM_DEVICES, NULL, 0, &numdev, sizeof(numdev), &cbReturned, NULL))
2778 {
2779 AssertMsgFailed(("DeviceIoControl failed with %d\n", GetLastError()));
2780 return RTErrConvertFromWin32(GetLastError());
2781 }
2782
2783 AssertMsg((int32_t)numdev.cUSBDevices >= 0, ("%d", numdev.cUSBDevices));
2784 if ((int32_t)numdev.cUSBDevices <= 0) /** @todo why does this return -1. Happened here when detaching a captured device which hadn't yet been opened by a VM process. */
2785 break;
2786
2787 Log(("Monitor detected %d captured devices\n", numdev.cUSBDevices));
2788
2789 usblibEnumDevices(numdev.cUSBDevices, pcDevices);
2790 Log(("usblibEnumDevices detected %d devices\n", *pcDevices));
2791
2792 if (numdev.cUSBDevices == *pcDevices)
2793 break;
2794 RTThreadSleep(100);
2795 }
2796 Assert(numdev.cUSBDevices == *pcDevices);
2797
2798 if ((int32_t)numdev.cUSBDevices <= 0 || *pcDevices == 0)
2799 {
2800 /* Only return the host devices */
2801 *ppDevices = pHostDevices;
2802 *pcDevices = cHostDevices;
2803 Log(("usbLibGetDevices: returns %d host device - no captured devices\n", cHostDevices));
2804 return VINF_SUCCESS;
2805 }
2806
2807 /* 2: Get all the USB devices that the filter has captured for us */
2808
2809 /* Get the required info for each captured device */
2810 PUSBDEVICE *ppCaptured = (PUSBDEVICE*)RTMemAllocZ(sizeof(PUSBDEVICE) * numDev.cUSBDevices);
2811 if (!ppCaptured)
2812 goto failure;
2813
2814 uint32_t cCaptured = 0;
2815 for (uint32_t i = 0; i < numdev.cUSBDevices; i++)
2816 {
2817 USBSUP_GETDEV dev = {0};
2818 HANDLE hDev;
2819
2820 char *pszDevname = usblibQueryDeviceName(i);
2821 hDev = CreateFile(pszDevname, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
2822 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
2823
2824 if (hDev != INVALID_HANDLE_VALUE)
2825 {
2826 DWORD cbReturned = 0;
2827 if (!DeviceIoControl(hDev, SUPUSB_IOCTL_GET_DEVICE, &dev, sizeof(dev), &dev, sizeof(dev), &cbReturned, NULL))
2828 {
2829 int iErr = GetLastError();
2830 /* ERROR_DEVICE_NOT_CONNECTED -> device was removed just now */
2831 AssertMsg(iErr == ERROR_DEVICE_NOT_CONNECTED, ("DeviceIoControl %d failed with %d\n", i, iErr));
2832 Log(("SUPUSB_IOCTL_GET_DEVICE: DeviceIoControl %d no longer connected\n", i));
2833 }
2834 else
2835 {
2836 pDevice = (PUSBDEVICE)RTMemAllocZ(sizeof(USBDEVICE));
2837 if (!pDevice)
2838 goto failure;
2839
2840 pDevice->idVendor = dev.vid;
2841 pDevice->idProduct = dev.did;
2842 pDevice->bcdDevice = dev.rev;
2843 pDevice->bBus = 0;
2844 pDevice->u64SerialHash = USBLibHashSerial(dev.serial_hash);
2845 pDevice->enmState = USBDEVICESTATE_HELD_BY_PROXY;
2846 pDevice->pszAddress = RTStrDup(pszDevname);
2847 /* The following is not 100% accurate but we only care about high-speed vs non-high-speed */
2848 pDevice->enmSpeed = dev.fHiSpeed ? USBDEVICESPEED_HIGH : USBDEVICESPEED_FULL;
2849 Log(("usbLibGetDevices: Detected device vid=%x did=%x rev=%x hispd=%d hash=%s hash=%RX64\n", dev.vid, dev.did, dev.rev, dev.fHiSpeed, dev.serial_hash, pDevice->u64SerialHash));
2850
2851 ppCaptured[i] = pDevice;
2852 cCaptured++;
2853 }
2854
2855 CloseHandle(hDev);
2856 }
2857 else
2858 AssertMsgFailed(("Unexpected failure to open %s. lasterr=%d\n", pszDevname, GetLastError()));
2859 }
2860
2861 if (!cCaptured)
2862 {
2863 /* Only return the host devices */
2864 *ppDevices = pHostDevices;
2865 *pcDevices = cHostDevices;
2866 Log(("usbLibGetDevices: returns %d host device - no captured devices after all\n", cHostDevices));
2867 return VINF_SUCCESS;
2868 }
2869
2870 /* 3: Go through the list of captured devices, lookup the corresponding device
2871 * in the list of host devices and update the information there. */
2872 Assert(pHostDevices);
2873 for (uint32_t i = 0; i < numdev.cUSBDevices; i++)
2874 {
2875 char *pszDeviceRegPath = usblibQueryDeviceRegPath(i);
2876 Assert(pszDeviceRegPath);
2877
2878 pDevice = pHostDevices;
2879 for (uint32_t j = 0; j < cHostDevices; j++)
2880 {
2881 if (pszDeviceRegPath)
2882 {
2883 if (!strcmp(pszDeviceRegPath, pDevice->pszAddress))
2884 {
2885 Log(("usbLibGetDevices: Duplicate device %s (%s)\n", pszDeviceRegPath, usblibQueryDeviceName(i)));
2886 break;
2887 }
2888 }
2889 pDevice = pDevice->pNext;
2890 }
2891
2892 if (j == cHostDevices)
2893 {
2894 Assert(!pDevice);
2895
2896 /* Probably in the process of being reattached */
2897 Log(("usbLibGetDevices: Captured device %s not found in host device list\n", usblibQueryDeviceRegPath(i)));
2898 /* do nothing */
2899 }
2900 else
2901 {
2902 Assert(pDevice);
2903
2904 pDevice->enmState = USBDEVICESTATE_HELD_BY_PROXY;
2905 if (ppCaptured[i])
2906 pDevice->enmSpeed = ppCaptured[i]->enmSpeed; // @todo: Is that right?
2907 RTStrFree(pDevice->pszAltAddress);
2908 pDevice->pszAltAddress = (char *)pDevice->pszAddress;
2909 pDevice->pszAddress = RTStrDup(usblibQueryDeviceName(i));
2910 }
2911 }
2912 *pcDevices = cHostDevices;
2913
2914 /* Free captured devices list */
2915 for (uint32_t i = 0; i < numdev.cUSBDevices; i++)
2916 {
2917 pDevice = ppCaptured[i];
2918 if (pDevice)
2919 {
2920 RTMemFree((void *)pDevice->pszAddress);
2921 RTStrFree(pDevice->pszAltAddress);
2922 RTStrFree(pDevice->pszHubName);
2923 RTMemFree((void *)pDevice->pszManufacturer);
2924 RTMemFree((void *)pDevice->pszProduct);
2925 RTMemFree((void *)pDevice->pszSerialNumber);
2926 RTMemFree(pDevice);
2927 }
2928 }
2929 RTMemFree(ppCaptured);
2930
2931 Log(("usbLibGetDevices: returns %d devices\n", *pcDevices));
2932#ifdef LOG_ENABLED
2933 pDevice = pHostDevices;
2934 iDevice = 0;
2935 while (pDevice)
2936 {
2937 iDevice++;
2938 Log(("Detected device: #%d\n", iDevice));
2939 Log((" Vendor Id: 0x%04X\n", pDevice->idVendor));
2940 Log((" Product Id: 0x%04X\n", pDevice->idProduct));
2941 Log((" Revision: 0x%04X\n", pDevice->bcdDevice));
2942 Log((" Address: %s\n", pDevice->pszAddress));
2943 Log((" AltAddress: %s\n", pDevice->pszAltAddress));
2944 Log((" HubName: %s\n", pDevice->pszHubName));
2945 Log((" Port: %u\n", pDevice->bPort));
2946 Log((" Manufacturer: %s\n", pDevice->pszManufacturer));
2947 Log((" Product: %s\n", pDevice->pszProduct));
2948 if (pDevice->pszSerialNumber)
2949 Log((" Serial Nr.: %s\n", pDevice->pszSerialNumber));
2950
2951 switch(pDevice->enmState)
2952 {
2953 case USBDEVICESTATE_UNSUPPORTED:
2954 Log((" State USBDEVICESTATE_UNSUPPORTED\n"));
2955 break;
2956 case USBDEVICESTATE_USED_BY_HOST:
2957 Log((" State USBDEVICESTATE_USED_BY_HOST\n"));
2958 break;
2959 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
2960 Log((" State USBDEVICESTATE_USED_BY_HOST_CAPTURABLE\n"));
2961 break;
2962 case USBDEVICESTATE_UNUSED:
2963 Log((" State USBDEVICESTATE_UNUSED\n"));
2964 break;
2965 case USBDEVICESTATE_HELD_BY_PROXY:
2966 Log((" State USBDEVICESTATE_HELD_BY_PROXY\n"));
2967 break;
2968 case USBDEVICESTATE_USED_BY_GUEST:
2969 Log((" State USBDEVICESTATE_USED_BY_GUEST\n"));
2970 break;
2971 }
2972 pDevice = pDevice->pNext;
2973 }
2974#endif
2975 *ppDevices = pHostDevices;
2976 return VINF_SUCCESS;
2977
2978failure:
2979 /* free host devices */
2980 pDevice = pHostDevices;
2981 pHostDevices = NULL;
2982 while (pDevice)
2983 {
2984 PUSBDEVICE pNext = pDevice->pNext;
2985
2986 RTMemFree((void *)pDevice->pszAddress);
2987 RTMemFree((void *)pDevice->pszManufacturer);
2988 RTMemFree((void *)pDevice->pszProduct);
2989 RTMemFree((void *)pDevice->pszSerialNumber);
2990 RTMemFree(pDevice);
2991
2992 pDevice = Next;
2993 }
2994
2995 /* free captured devices */
2996 for (uint32_t i = 0; i < numdev.cUSBDevices; i++)
2997 {
2998 pDevice = ppCaptured[i];
2999 if (pDevice)
3000 {
3001 RTMemFree((void *)pDevice->pszAddress);
3002 RTMemFree((void *)pDevice->pszManufacturer);
3003 RTMemFree((void *)pDevice->pszProduct);
3004 RTMemFree((void *)pDevice->pszSerialNumber);
3005 RTMemFree(pDevice);
3006 }
3007 }
3008 RTMemFree(ppCaptured);
3009
3010 *ppDevices = NULL;
3011 Log(("usbLibGetDevices: returns VERR_NO_MEMORY\n"));
3012 return VERR_NO_MEMORY;
3013}
3014
3015/**
3016 * Return all USB devices attached to the host
3017 *
3018 * @returns VBox status code
3019 * @param ppDevices Receives pointer to list of devices
3020 * @param pcDevices Number of USB devices in the list
3021 */
3022USBLIB_DECL(int) usbLibGetHostDevices(PUSBDEVICE *ppDevices, uint32_t *pcDevices)
3023{
3024 usbLibEnumerateHostControllers(ppDevices, pcDevices);
3025
3026 return VINF_SUCCESS;
3027}
3028
3029/**
3030 * Check for USB device arrivals or removals
3031 *
3032 * @returns boolean
3033 */
3034USBLIB_DECL(bool) USBLibHasPendingDeviceChanges(void)
3035{
3036 USBSUP_USB_CHANGE out;
3037 DWORD cbReturned;
3038
3039 if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
3040 return false;
3041 cbReturned = 0;
3042 if ( DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_USB_CHANGE, NULL, 0, &out, sizeof(out), &cbReturned, NULL)
3043 && out.cUSBStateChange != g_cUSBStateChange)
3044 {
3045 g_cUSBStateChange = out.cUSBStateChange;
3046 Log(("usbLibHasPendingDeviceChanges: Detected USB state change!!\n"));
3047 return true;
3048 }
3049 return false;
3050}
3051
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