VirtualBox

Changeset 80631 in vbox


Ignore:
Timestamp:
Sep 6, 2019 1:39:33 PM (5 years ago)
Author:
vboxsync
Message:

USB/win: Started rewriting USB enumeration.

File:
1 edited

Legend:

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

    r80480 r80631  
    5959#ifdef VBOX_USB_USE_DEVICE_NOTIFICATION
    6060# include <Dbt.h>
     61#endif
     62
     63#ifdef VBOX_WITH_NEW_USB_ENUM
     64# include <cfgmgr32.h>
    6165#endif
    6266
     
    899903}
    900904
     905#ifdef VBOX_WITH_NEW_USB_ENUM
     906
     907/* Get a registry property for a device given its HDEVINFO + SP_DEVINFO_DATA. */
     908static void *usbLibGetRegistryProperty(HDEVINFO InfoSet, const PSP_DEVINFO_DATA DevData, DWORD Property)
     909{
     910    BOOL    rc;
     911    DWORD   dwReqLen;
     912    void    *PropertyData;
     913
     914    /* How large a buffer do we need? */
     915    rc = SetupDiGetDeviceRegistryProperty(InfoSet, DevData, Property,
     916                                          NULL, NULL, 0, &dwReqLen);
     917    if (!rc && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
     918    {
     919        LogRelFunc(("Failed to query buffer size, error %ld\n", GetLastError()));
     920        AssertFailed();
     921        return NULL;
     922    }
     923
     924    PropertyData = RTMemAlloc(dwReqLen);
     925    if (!PropertyData)
     926        return NULL;
     927
     928    /* Get the actual property data. */
     929    rc = SetupDiGetDeviceRegistryProperty(InfoSet, DevData, Property,
     930                                          NULL, (PBYTE)PropertyData, dwReqLen, &dwReqLen);
     931    if (!rc)
     932    {
     933        LogRelFunc(("Failed to get property data, error %ld\n", GetLastError()));
     934        RTMemFree(PropertyData);
     935        return NULL;
     936    }
     937    return PropertyData;
     938}
     939
     940/* Given a HDEVINFO and SP_DEVICE_INTERFACE_DATA, get the interface detail data. */
     941static PSP_DEVICE_INTERFACE_DETAIL_DATA usbLibGetDevDetail(HDEVINFO InfoSet, PSP_DEVICE_INTERFACE_DATA InterfaceData)
     942{
     943    BOOL                                rc;
     944    DWORD                               dwReqLen;
     945    PSP_DEVICE_INTERFACE_DETAIL_DATA    DetailData;
     946
     947    rc = SetupDiGetDeviceInterfaceDetail(InfoSet, InterfaceData, NULL, 0, &dwReqLen, NULL);
     948    if (!rc && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
     949    {
     950        LogRelFunc(("Failed to get interface detail size, error %ld\n", GetLastError()));
     951        return NULL;
     952    }
     953
     954    DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)RTMemAlloc(dwReqLen);
     955    if (!DetailData)
     956        return NULL;
     957
     958    memset(DetailData, 0, dwReqLen);
     959    DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
     960
     961    rc = SetupDiGetDeviceInterfaceDetail(InfoSet, InterfaceData, DetailData, dwReqLen, &dwReqLen, NULL);
     962    if (!rc)
     963    {
     964        LogRelFunc(("Failed to get interface detail, error %ld\n", GetLastError()));
     965        RTMemFree(DetailData);
     966    }
     967
     968    return DetailData;
     969}
     970
     971/* Given a hub's PnP device instance, find its device path (file name). */
     972static LPCSTR usbLibGetHubPathFromDevInst(LPCSTR DevInst)
     973{
     974    HDEVINFO                            InfoSet;
     975    SP_DEVINFO_DATA                     DeviceData;
     976    SP_DEVICE_INTERFACE_DATA            InterfaceData;
     977    PSP_DEVICE_INTERFACE_DETAIL_DATA    DetailData;
     978    BOOL                                rc;
     979    LPSTR                               DevicePath = NULL;
     980
     981    /* Enumerate the DevInst's USB hub interface. */
     982    InfoSet = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_HUB, DevInst, NULL,
     983                                  DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
     984    if (InfoSet == INVALID_HANDLE_VALUE)
     985    {
     986        LogRelFunc(("Failed to get interface, error %ld\n", GetLastError()));
     987        return NULL;
     988    }
     989
     990    memset(&DeviceData, 0, sizeof(DeviceData));
     991    DeviceData.cbSize = sizeof(DeviceData);
     992    rc = SetupDiEnumDeviceInterfaces(InfoSet, 0, &GUID_DEVINTERFACE_USB_HUB, 0, &InterfaceData);
     993    if (!rc)
     994    {
     995        LogRelFunc(("Failed to get interface data, error %ld\n", GetLastError()));
     996        SetupDiDestroyDeviceInfoList(InfoSet);
     997        return NULL;
     998    }
     999
     1000    DetailData = usbLibGetDevDetail(InfoSet, &InterfaceData);
     1001    if (!DetailData)
     1002    {
     1003        SetupDiDestroyDeviceInfoList(InfoSet);
     1004        return NULL;
     1005    }
     1006
     1007    /* Copy the device path out of the interface detail. */
     1008    DevicePath = RTStrDup(DetailData->DevicePath);
     1009    RTMemFree(DetailData);
     1010    SetupDiDestroyDeviceInfoList(InfoSet);
     1011
     1012    return DevicePath;
     1013}
     1014
     1015
     1016/* Use the Configuration Manager (CM) to get a devices's parent given its DEVINST and
     1017 * turn it into a PnP device instance ID string.
     1018 */
     1019static LPCSTR usbLibGetParentInstanceID(DEVINST DevInst)
     1020{
     1021    LPSTR       InstanceID;
     1022    DEVINST     ParentInst;
     1023    ULONG       ulReqChars;
     1024    ULONG       ulReqBytes;
     1025    CONFIGRET   cr;
     1026
     1027    /* First get the parent DEVINST. */
     1028    cr = CM_Get_Parent( &ParentInst, DevInst, 0);
     1029    if (cr != CR_SUCCESS)
     1030    {
     1031        LogRelFunc(("Failed to get parent instance, error %ld\n", GetLastError()));
     1032        return NULL;
     1033    }
     1034
     1035    /* Then convert it to the instance ID string. */
     1036    cr = CM_Get_Device_ID_Size(&ulReqChars, ParentInst, 0);
     1037    if (cr != CR_SUCCESS)
     1038    {
     1039        LogRelFunc(("Failed to get device ID size, error %ld\n", GetLastError()));
     1040        return NULL;
     1041    }
     1042
     1043    /* CM_Get_Device_ID_Size gives us the size in characters without terminating null. */
     1044    ulReqBytes = (ulReqChars + 1) * sizeof(char);
     1045    InstanceID = (LPSTR)RTMemAlloc(ulReqBytes);
     1046    if (!InstanceID)
     1047        return NULL;
     1048
     1049    cr = CM_Get_Device_ID(ParentInst, InstanceID, ulReqBytes, 0);
     1050    if (cr != CR_SUCCESS)
     1051    {
     1052        LogRelFunc(("Failed to get device ID, error %ld\n", GetLastError()));
     1053        RTMemFree(InstanceID);
     1054        return NULL;
     1055    }
     1056
     1057    return InstanceID;
     1058}
     1059
     1060/*
     1061 * 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.
     1066 *
     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).
     1071 *
     1072 * NB: Every USB device known to the Windows PnP Manager will have a device instance ID. Typically
     1073 * it also has a DriverKey but only if it has a driver installed. Hence we ignore the DriverKey, at
     1074 * least prior to capturing (once VBoxUSB.sys is installed, a DriverKey must by definition be
     1075 * present). Also note that the device instance ID changes for captured devices since we change
     1076 * their USB VID/PID, though it is unique at any given point.
     1077 *
     1078 * 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.
     1081 */
     1082static int usbLibDevGetDevices(PUSBDEVICE *ppDevs, uint32_t *pcDevs)
     1083{
     1084    HDEVINFO            InfoSet;
     1085    DWORD               DeviceIndex;
     1086    SP_DEVINFO_DATA     DeviceData;
     1087    LPSTR               ClassGUID;
     1088
     1089    /* Ask for the USB PnP enumerator for all it has. */
     1090    InfoSet = SetupDiGetClassDevs(NULL, "USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
     1091
     1092    memset(&DeviceData, 0, sizeof(DeviceData));
     1093    DeviceData.cbSize = sizeof(DeviceData);
     1094    DeviceIndex = 0;
     1095
     1096    /* Enumerate everything in the info set. */
     1097    while (SetupDiEnumDeviceInfo(InfoSet, DeviceIndex, &DeviceData))
     1098    {
     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        }
     1106
     1107        ++DeviceIndex;
     1108        memset(&DeviceData, 0, sizeof(DeviceData));
     1109        DeviceData.cbSize = sizeof(DeviceData);
     1110    }
     1111
     1112    if (InfoSet)
     1113        SetupDiDestroyDeviceInfoList(InfoSet);
     1114
     1115    return VINF_SUCCESS;
     1116}
     1117
     1118#else
    9011119static int usbLibDevGetDevices(PUSBDEVICE *ppDevs, uint32_t *pcDevs)
    9021120{
     
    9261144    return VINF_SUCCESS;
    9271145}
     1146#endif
    9281147
    9291148static int usbLibMonDevicesCmp(PUSBDEVICE pDev, PVBOXUSB_DEV pDevInfo)
Note: See TracChangeset for help on using the changeset viewer.

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