VirtualBox

Ignore:
Timestamp:
Sep 10, 2019 6:56:06 AM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
133222
Message:

USB/win: Continuing USB device enumeration rewrite.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/VBoxUSB/win/lib/VBoxUsbLib-win.cpp

    r80631 r80685  
    386386}
    387387
     388#ifndef VBOX_WITH_NEW_USB_ENUM
    388389static int usbLibDevStrDriverKeyGet(HANDLE hHub, ULONG iPort, LPSTR* plpszName)
    389390{
     
    431432    return rc;
    432433}
     434#endif
    433435
    434436static int usbLibDevStrHubNameGet(HANDLE hHub, ULONG iPort, LPSTR* plpszName)
     
    756758}
    757759
     760#ifndef VBOX_WITH_NEW_USB_ENUM
    758761static int usbLibDevGetHubDevices(LPCSTR lpszName, PUSBDEVICE *ppDevs, uint32_t *pcDevs);
    759762
     
    902905    return rc;
    903906}
     907#endif
    904908
    905909#ifdef VBOX_WITH_NEW_USB_ENUM
     
    918922    {
    919923        LogRelFunc(("Failed to query buffer size, error %ld\n", GetLastError()));
    920         AssertFailed();
    921924        return NULL;
    922925    }
     
    970973
    971974/* Given a hub's PnP device instance, find its device path (file name). */
    972 static LPCSTR usbLibGetHubPathFromDevInst(LPCSTR DevInst)
     975static LPCSTR usbLibGetHubPathFromInstanceID(LPCSTR InstanceID)
    973976{
    974977    HDEVINFO                            InfoSet;
    975     SP_DEVINFO_DATA                     DeviceData;
    976978    SP_DEVICE_INTERFACE_DATA            InterfaceData;
    977979    PSP_DEVICE_INTERFACE_DETAIL_DATA    DetailData;
     
    980982
    981983    /* Enumerate the DevInst's USB hub interface. */
    982     InfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_HUB, DevInst, NULL,
     984    InfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_HUB, InstanceID, NULL,
    983985                                  DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
    984986    if (InfoSet == INVALID_HANDLE_VALUE)
    985987    {
    986         LogRelFunc(("Failed to get interface, error %ld\n", GetLastError()));
     988        LogRelFunc(("Failed to get interface for InstID %se, error %ld\n", InstanceID, GetLastError()));
    987989        return NULL;
    988990    }
    989991
    990     memset(&DeviceData, 0, sizeof(DeviceData));
    991     DeviceData.cbSize = sizeof(DeviceData);
     992    memset(&InterfaceData, 0, sizeof(InterfaceData));
     993    InterfaceData.cbSize = sizeof(InterfaceData);
    992994    rc = SetupDiEnumDeviceInterfaces(InfoSet, 0, &GUID_DEVINTERFACE_USB_HUB, 0, &InterfaceData);
    993995    if (!rc)
    994996    {
    995         LogRelFunc(("Failed to get interface data, error %ld\n", GetLastError()));
     997        DWORD   dwErr = GetLastError();
     998
     999        /* The parent device might not be a hub; that is valid, ignore such errors. */
     1000        if (dwErr != ERROR_NO_MORE_ITEMS)
     1001            LogRelFunc(("Failed to get interface data for InstID %s, error %ld\n", InstanceID, dwErr));
    9961002        SetupDiDestroyDeviceInfoList(InfoSet);
    9971003        return NULL;
     
    10261032
    10271033    /* First get the parent DEVINST. */
    1028     cr = CM_Get_Parent( &ParentInst, DevInst, 0);
     1034    cr = CM_Get_Parent(&ParentInst, DevInst, 0);
    10291035    if (cr != CR_SUCCESS)
    10301036    {
     
    10581064}
    10591065
     1066/* Process a single USB device that's being enumerated and grab its hub-specific data. */
     1067static int usbLibDevGetDevice(LPCSTR lpcszHubFile, ULONG iPort, LPCSTR Location, PUSBDEVICE *ppDevs, uint32_t *pcDevs)
     1068{
     1069    HANDLE                                  HubDevice;
     1070    BYTE                                    abConBuf[sizeof(USB_NODE_CONNECTION_INFORMATION_EX)];
     1071    PUSB_NODE_CONNECTION_INFORMATION_EX     pConInfo = PUSB_NODE_CONNECTION_INFORMATION_EX(abConBuf);
     1072    int                                     rc = VINF_SUCCESS;
     1073    DWORD                                   cbReturned = 0;
     1074
     1075    /* Validate inputs. */
     1076    if ((iPort < 1) || (iPort > 255))
     1077    {
     1078        LogRelFunc(("Port index out of range (%u)\n", iPort));
     1079        return VERR_INVALID_PARAMETER;
     1080    }
     1081    if (!lpcszHubFile)
     1082    {
     1083        LogRelFunc(("Hub path is NULL!\n"));
     1084        return VERR_INVALID_PARAMETER;
     1085    }
     1086
     1087    /* Try opening the hub file so we can send IOCTLs to it. */
     1088    HubDevice = CreateFile(lpcszHubFile, GENERIC_WRITE, FILE_SHARE_WRITE,
     1089                           NULL, OPEN_EXISTING, 0, NULL);
     1090    if (HubDevice == INVALID_HANDLE_VALUE)
     1091    {
     1092        LogRelFunc(("Failed to open hub `%s', dwErr(%d)\n", lpcszHubFile, GetLastError()));
     1093        return VERR_FILE_NOT_FOUND;
     1094    }
     1095
     1096    /* The shenanigans with abConBuf are due to USB_NODE_CONNECTION_INFORMATION_EX
     1097     * containing a zero-sized array, triggering compiler warnings.
     1098     */
     1099    memset(pConInfo, 0, sizeof(abConBuf));
     1100    pConInfo->ConnectionIndex = iPort;
     1101
     1102    /* We expect that IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX is always available
     1103     * on any supported Windows version and hardware.
     1104     * NB: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 is Win8 and later only.
     1105     */
     1106    if (!DeviceIoControl(HubDevice, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
     1107                         pConInfo, sizeof(abConBuf), pConInfo, sizeof(abConBuf),
     1108                         &cbReturned, NULL))
     1109    {
     1110        DWORD dwErr = GetLastError(); NOREF(dwErr);
     1111        LogRel(("IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX failed with error %ld on hub %s, port %d\n", dwErr, lpcszHubFile, iPort));
     1112        AssertMsg(dwErr == ERROR_DEVICE_NOT_CONNECTED, (__FUNCTION__": DeviceIoControl failed dwErr (%d)\n", dwErr));
     1113        CloseHandle(HubDevice);
     1114        return VERR_GENERAL_FAILURE;
     1115    }
     1116
     1117    if (pConInfo->ConnectionStatus != DeviceConnected)
     1118    {
     1119        /* Ignore this, can't do anything with it. */
     1120        LogFunc(("Device is not connected, skipping.\n"));
     1121        CloseHandle(HubDevice);
     1122        return VINF_SUCCESS;
     1123    }
     1124
     1125    if (pConInfo->DeviceIsHub)
     1126    {
     1127        /* We're ignoring hubs, just skip this. */
     1128        LogFunc(("Device is a hub, skipping.\n"));
     1129        CloseHandle(HubDevice);
     1130        return VINF_SUCCESS;
     1131    }
     1132
     1133    PUSB_CONFIGURATION_DESCRIPTOR pCfgDr = NULL;
     1134    PVBOXUSB_STRING_DR_ENTRY pList = NULL;
     1135    rc = usbLibDevCfgDrGet(HubDevice, lpcszHubFile, iPort, 0, &pCfgDr);
     1136    if (pCfgDr)
     1137    {
     1138        rc = usbLibDevStrDrEntryGetAll(HubDevice, lpcszHubFile, iPort, &pConInfo->DeviceDescriptor, pCfgDr, &pList);
     1139#ifdef VBOX_WITH_ANNOYING_USB_ASSERTIONS
     1140        AssertRC(rc); // this can fail if device suspended
     1141#endif
     1142    }
     1143
     1144    /* At this point we're done with the hub device. */
     1145    CloseHandle(HubDevice);
     1146
     1147    PUSBDEVICE pDev = (PUSBDEVICE)RTMemAllocZ(sizeof (*pDev));
     1148    if (RT_LIKELY(pDev))
     1149    {
     1150        rc = usbLibDevPopulate(pDev, pConInfo, iPort, Location, lpcszHubFile, pList);
     1151        if (RT_SUCCESS(rc))
     1152        {
     1153            pDev->pNext = *ppDevs;
     1154            *ppDevs = pDev;
     1155            ++*pcDevs;
     1156        }
     1157        else
     1158            RTMemFree(pDev);
     1159    }
     1160    else
     1161        rc = VERR_NO_MEMORY;
     1162
     1163    if (pCfgDr)
     1164        usbLibDevCfgDrFree(pCfgDr);
     1165    if (pList)
     1166        usbLibDevStrDrEntryFreeList(pList);
     1167
     1168    return rc;
     1169}
     1170
     1171
    10601172/*
    10611173 * Enumerate the USB devices in the host system. Since we do not care about the hierarchical
    1062  * structure of root hubs, other hubs, and devices, we just use ask the USB PnP enumerator to
    1063  * give us all it has. This includes hubs (though not root hubs) which we filter out. It also
    1064  * includes USB devices with no driver, which is notably something we cannot get by enumerating
    1065  * via GUID_DEVINTERFACE_USB_DEVICE.
     1174 * structure of root hubs, other hubs, and devices, we just ask the USB PnP enumerator to
     1175 * give us all it has. This includes hubs (though not root hubs), as well as multiple child
     1176 * interfaces of multi-interface USB devices, which we filter out. It also includes USB
     1177 * devices with no driver, which is notably something we cannot get by enumerating via
     1178 * GUID_DEVINTERFACE_USB_DEVICE.
    10661179 *
    1067  * This approach also saves us some trouble relative to enumerating via hub IOCTLs and then
    1068  * hunting  through the PnP manager to find them. Instead, we look up the device's parent which
    1069  * is inevitably a hub, and that allows us to obtain USB-specific data (descriptors, speeds,
    1070  * etc.) when combined with the devices PnP "address" (USB port on parent hub).
     1180 * This approach also saves us some trouble relative to enumerating devices via hub IOCTLs and
     1181 * then hunting through the PnP manager to find them. Instead, we look up the device's parent
     1182 * which (for devices we're interested in) is always a hub, and that allows us to obtain
     1183 * USB-specific data (descriptors, speeds, etc.) when combined with the devices PnP "address"
     1184 * (USB port on parent hub).
    10711185 *
    10721186 * NB: Every USB device known to the Windows PnP Manager will have a device instance ID. Typically
     
    10771191 *
    10781192 * The location information should be a reliable way of identifying a device and does not change
    1079  * with driver installs, capturing, etc. It is only available on Windows Vista and later; earlier
    1080  * Windows version had no reliable way of cross-referencing the USB IOCTL and PnP Manager data.
     1193 * with driver installs, capturing, etc. USB device location information is only available on
     1194 * Windows Vista and later; earlier Windows version had no reliable way of cross-referencing the
     1195 * USB IOCTL and PnP Manager data.
    10811196 */
    10821197static int usbLibDevGetDevices(PUSBDEVICE *ppDevs, uint32_t *pcDevs)
     
    10841199    HDEVINFO            InfoSet;
    10851200    DWORD               DeviceIndex;
     1201    LPDWORD             Address;
    10861202    SP_DEVINFO_DATA     DeviceData;
    1087     LPSTR               ClassGUID;
     1203    LPCSTR              ParentInstID;
     1204    LPCSTR              HubPath = NULL;
     1205    LPCSTR              Location;
    10881206
    10891207    /* Ask for the USB PnP enumerator for all it has. */
     
    10971215    while (SetupDiEnumDeviceInfo(InfoSet, DeviceIndex, &DeviceData))
    10981216    {
    1099         /* Grab the class GUID. If it's a USB hub, we aren't interested. */
    1100         ClassGUID = (LPSTR)usbLibGetRegistryProperty(InfoSet, &DeviceData, SPDRP_CLASSGUID);
    1101         if (ClassGUID && strcmp(ClassGUID, "{36fc9e60-c465-11cf-8056-444553540000}"))
    1102         {
    1103             /* There is a class GUID and it's not a hub. Should be a USB device then. */
    1104             RTMemFree(ClassGUID);
    1105         }
     1217        /* Use the CM API to get the parent instance ID. */
     1218        ParentInstID = usbLibGetParentInstanceID(DeviceData.DevInst);
     1219
     1220        /* Now figure out the hub's file path fron the instance ID, if there is one. */
     1221        if (ParentInstID)
     1222            HubPath = usbLibGetHubPathFromInstanceID(ParentInstID);
     1223
     1224        /* If there's no hub interface on the parent, then this might be a child
     1225         * device of a multi-interface device. Either way, we're not interested.
     1226         */
     1227        if (HubPath)
     1228        {
     1229            /* The location information uniquely identifies the USB device, (hub/port). */
     1230            Location = (LPCSTR)usbLibGetRegistryProperty(InfoSet, &DeviceData, SPDRP_LOCATION_INFORMATION);
     1231
     1232            /* The device's PnP Manager "address" is the port number on the parent hub. */
     1233            Address = (LPDWORD)usbLibGetRegistryProperty(InfoSet, &DeviceData, SPDRP_ADDRESS);
     1234            if (Address && Location)
     1235            {
     1236                usbLibDevGetDevice(HubPath, *Address, Location, ppDevs, pcDevs);
     1237            }
     1238            RTMemFree((void *)HubPath);
     1239
     1240            if (Location)
     1241                RTMemFree((void *)Location);
     1242            if (Address)
     1243                RTMemFree((void *)Address);
     1244        }
     1245
     1246        /* Clean up after this device. */
     1247        if (ParentInstID)
     1248            RTMemFree((void *)ParentInstID);
    11061249
    11071250        ++DeviceIndex;
Note: See TracChangeset for help on using the changeset viewer.

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