Windows下USB百科
+ -

Windows复位USB集线器HUB端口设备RestartUsbPort

2024-02-06 290 1

本人描述了如何在 Windows 下使用IOCTL_USB_HUB_CYCLE_PORT 重新启动USB端口。具体过程为:通过给定的设备实例ID在 Windows设备管理中查找USB 备、确定使用的 USB 端口号、获取其父设备(其 USB 集线器)、打开集线器并执行 IOCTL_USB_HUB_CYCLE_PORT 调用。

RestartUsbPort工具下载地址:https://www.usbzh.com/article/detail-1192.html

介绍

有时,USB 设备会停止按预期工作,重新插入它们会有所帮助。通过代码执行重新插入可能会很方便。
如果您想尝试重新启动 USB 端口是否有帮助,可以尝试使用UsbTreeView或RestartUsbPort工具来实现。
在Windows系统下,IOCTL_USB_HUB_CYCLE_PORT会重新启动 USB 端口,从而启动所连接设备的重新枚举。

  • 该功能在 XP 下可用,但通常仅适用于运行 Microsoft 标准驱动程序的集线器驱动。第三方驱动通常会返回ERROR_UNKNOWN_FUNCTION。
  • 在 Vista 和 Windows 7 下,Windows 标准驱动程序不再支持它,它总是失败并显示ERROR_NOT_SUPPORTED.
  • 从 Windows 8 开始,它再次可用,但与 XP 相比,需要管理员权限。如果没有管理员权限,它会像在 Vista 和 Win7 下一样失败,ERROR_NOT_SUPPORTED或者从 Win10 版本 1903 开始ERROR_GEN_FAILURE失败,这两种情况在这里都是相当误导的,因为这是一个权限问题。

代码实现

现将所有内容放在一个函数中,该函数使用USB设备的设备实例ID作为唯一参数。


bool CycleUsbDevice(char* pszUsbDeviceId)
{
    // Step 1: find the USB device in the device manager
    DEVINST DevInst = 0;
    if ( CR_SUCCESS != CM_Locate_DevNode(&DevInst, pszUsbDeviceId, 0) ) {
        return false; //----
    }

    // Step 2: Determine the USB port number. 
    // Since Vista it can be read reliably from the device location info:
    char szLocation[64] = "";
    DWORD dwType = 0;
    ULONG uLen = sizeof(szLocation);
    if ( CR_SUCCESS != CM_Get_DevNode_Registry_Property
       (DevInst, CM_DRP_LOCATION_INFORMATION, &dwType, szLocation, &uLen, 0) ) {
        return false; //----
    }

    //               0123456789
    // must be like "Port_#0004.Hub_#0014"
    if ( 0 != strncmp(szLocation, "Port_#", 6) ) {
        return false; //----
    }

    int PortNumber = atoi(szLocation + 6); // leading zeros are ok with atoi

    // Step 3: the USB hub is the parent device
    DEVINST DevInstHub = 0;
    if ( CR_SUCCESS != CM_Get_Parent(&DevInstHub, DevInst, 0) ) {
        return false; //----
    }

    // Step 4: scan all USB hubs for this DEVINST to get its DevicePath
    // which we need to open the hub
    char szHubDevPath[MAX_PATH] = "";

    const GUID* DevIfGuid = &GUID_DEVINTERFACE_USB_HUB;

    HDEVINFO hDevInfo = SetupDiGetClassDevs
             (DevIfGuid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);

    if ( INVALID_HANDLE_VALUE == hDevInfo ) {
        return false; //----
    }

    char DataBuf[1024];
    PSP_DEVICE_INTERFACE_DETAIL_DATA pDevIfDetailData = 
                         (PSP_DEVICE_INTERFACE_DETAIL_DATA)DataBuf;
    SP_DEVICE_INTERFACE_DATA         DevIfData   = { sizeof(SP_DEVICE_INTERFACE_DATA) };
    SP_DEVINFO_DATA                  DevInfoData = { sizeof(SP_DEVINFO_DATA) };
    DWORD                            dwSize;

    for ( DWORD dwIndex = 0; SetupDiEnumDeviceInterfaces
        (hDevInfo, NULL, DevIfGuid, dwIndex, &DevIfData); dwIndex++ ) {

        pDevIfDetailData->cbSize = 
            sizeof(*pDevIfDetailData); // yes, 5 (or 6 if UNICODE)

        dwSize = sizeof(DataBuf);

        if ( SetupDiGetDeviceInterfaceDetail(hDevInfo, 
             &DevIfData, pDevIfDetailData, dwSize, &dwSize, &DevInfoData) ) {
            if ( DevInfoData.DevInst == DevInstHub ) {
                // hub found, keep its DevicePath
                strcpy(szHubDevPath, pDevIfDetailData->DevicePath);
                break;
            }
        }
    }

    SetupDiDestroyDeviceInfoList(hDevInfo);

    if ( ! szHubDevPath[0] ) {
        return false; //----
    }

    // Step 5: open the hub
    HANDLE hHub = CreateFile(szHubDevPath, GENERIC_WRITE, 
                  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);

    if ( INVALID_HANDLE_VALUE == hHub ) {
        return false; //----
    }

    // Step 6: call IOCTL_USB_HUB_CYCLE_PORT
    typedef struct _USB_CYCLE_PORT_PARAMS {
        ULONG ConnectionIndex;
        ULONG StatusReturned;
    } USB_CYCLE_PORT_PARAMS, *PUSB_CYCLE_PORT_PARAMS;

    USB_CYCLE_PORT_PARAMS CyclePortParams  = { PortNumber, 0 }; // in and out

    DWORD dwBytes;
    int res = DeviceIoControl(hHub, IOCTL_USB_HUB_CYCLE_PORT,
                              &CyclePortParams, sizeof(CyclePortParams), 
                              &CyclePortParams, sizeof(CyclePortParams), 
                              &dwBytes, NULL);
    CloseHandle(hHub);

    return ( (0 != res) && (0 == CyclePortParams.StatusReturned) );
}

说明

  • 微软官方方档说明使用IOCTL_USB_HUB_CYCLE_PORT的函数DeviceIoControl的Output Buffer应为NULL ,但实际也是有的。
  • 重启的设备必须安装了USB驱动程序并且与设备必须存在。否则会出现错误 433 ( ERROR_NO_SUCH_DEVICE) 或自 Windows 10 21H2 起出现错误 50 ( ERROR_NOT_SUPPORTED)。Win11又返回的是 1167 ( ERROR_DEVICE_NOT_CONNECTED)。
翻译原文:https://www.codeproject.com/Articles/5363023/How-to-Restart-a-USB-Port

HID人机交互QQ群:564808376    UAC音频QQ群:218581009    UVC相机QQ群:331552032    BOT&UASP大容量存储QQ群:258159197    STC-USB单片机QQ群:315457461    USB技术交流QQ群2:580684376    USB技术交流QQ群:952873936   

0 篇笔记 写笔记

复位USB端口设备IOCTL_USB_HUB_CYCLE_PORT
在设备管理器中通过设备的实例ID查找到设备后,然后确定设备端口中,再根据设备端口号获取其父设备即USB集本器,打开集线器,发送IOCTL_USB_HUB_CYCLE_PORT 请求来复位集线器端口达到复位设备。IOCTL_USB_HUB_CYCLE_PORT在Vista和Windows 7下不支持......
Windows复位USB集线器HUB端口设备RestartUsbPort
本人描述了如何在 Windows 下使用IOCTL_USB_HUB_CYCLE_PORT 重新启动USB端口。具体过程为:通过给定的设备实例ID在 Windows设备管理中查找USB 备、确定使用的 USB 端口号、获取其父设备(其 USB 集线器)、打开集线器并执行 IOCTL_USB_HUB_C......
关注公众号
  • HID人机交互
  • Linux&USB
  • UAC音频
  • TYPE-C
  • USB规范
  • USB大容量存储
  • USB百科
  • USB周边
  • UVC摄像头
  • Windows系统USB
  • 音视频博客
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

    打开支付宝扫一扫,即可进行扫码打赏哦

    您的支持,是我们前进的动力!