Created
July 18, 2024 01:19
-
-
Save nefarius/650f1ebde89e8ea7170a5c9ec4996ddf to your computer and use it in GitHub Desktop.
Utility function to power cycle/restart the hub port of a USB device identified by instance ID.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <SetupAPI.h> | |
#include <cfgmgr32.h> | |
#include <usbioctl.h> | |
_Must_inspect_result_ | |
_Success_(return == TRUE) | |
BOOL | |
USB_CyclePort( | |
_In_ PCWSTR InstanceId | |
); | |
_Use_decl_annotations_ | |
BOOL | |
USB_CyclePort( | |
_In_ PCWSTR InstanceId | |
) | |
{ | |
DEVINST usbDevice = 0; | |
BOOL result = FALSE; | |
DWORD win32Error = ERROR_NOT_FOUND; | |
PWSTR interfaceList = NULL; | |
HANDLE hubHandle = NULL; | |
CONFIGRET ret = CM_Locate_DevNodeW( | |
&usbDevice, | |
(PWSTR)InstanceId, | |
CM_LOCATE_DEVNODE_NORMAL | |
); | |
if (ret != CR_SUCCESS) | |
{ | |
win32Error = CM_MapCrToWin32Err(ret, ERROR_NOT_FOUND); | |
goto exit; | |
} | |
UINT32 connectionIndex = 0; | |
DEVPROPTYPE serviceType = 0; | |
WCHAR serviceName[MAX_PATH] = { 0 }; | |
ULONG serviceNameSize = MAX_PATH * sizeof(WCHAR); | |
BOOL hubFound = FALSE; | |
DEVPROPTYPE hubType = 0; | |
WCHAR hubInstanceId[MAX_PATH] = { 0 }; | |
ULONG hubInstanceIdSize = MAX_PATH * sizeof(WCHAR); | |
do | |
{ | |
// query service name | |
ret = CM_Get_DevNode_PropertyW( | |
usbDevice, | |
&DEVPKEY_Device_Service, | |
&serviceType, | |
// ReSharper disable once CppRedundantCastExpression | |
(PBYTE)serviceName, | |
&serviceNameSize, | |
0 | |
); | |
if (ret != CR_SUCCESS) | |
{ | |
win32Error = CM_MapCrToWin32Err(ret, ERROR_NOT_FOUND); | |
break; | |
} | |
hubFound = wstristr(serviceName, L"USBHUB") != NULL; | |
// not our hub, walk up to next parent | |
if (!hubFound) | |
{ | |
DEVPROPTYPE addressType = 0; | |
ULONG addressSize = sizeof(UINT32); | |
// query address/connection index name | |
ret = CM_Get_DevNode_PropertyW( | |
usbDevice, | |
&DEVPKEY_Device_Address, | |
&addressType, | |
(PBYTE)&connectionIndex, | |
&addressSize, | |
0 | |
); | |
if (ret != CR_SUCCESS) | |
{ | |
win32Error = CM_MapCrToWin32Err(ret, ERROR_NOT_FOUND); | |
break; | |
} | |
DEVPROPTYPE parentType = 0; | |
WCHAR parentInstanceId[MAX_PATH] = { 0 }; | |
ULONG parentInstanceIdSize = MAX_PATH * sizeof(WCHAR); | |
// query parent instance ID | |
ret = CM_Get_DevNode_PropertyW( | |
usbDevice, | |
&DEVPKEY_Device_Parent, | |
&parentType, | |
// ReSharper disable once CppRedundantCastExpression | |
(PBYTE)parentInstanceId, | |
&parentInstanceIdSize, | |
0 | |
); | |
if (ret != CR_SUCCESS) | |
{ | |
win32Error = CM_MapCrToWin32Err(ret, ERROR_NOT_FOUND); | |
break; | |
} | |
// replace current node with parent and repeat | |
ret = CM_Locate_DevNodeW( | |
&usbDevice, | |
parentInstanceId, | |
CM_LOCATE_DEVNODE_NORMAL | |
); | |
if (ret != CR_SUCCESS) | |
{ | |
win32Error = CM_MapCrToWin32Err(ret, ERROR_NOT_FOUND); | |
break; | |
} | |
} | |
else | |
{ | |
// query hub device instance ID | |
ret = CM_Get_DevNode_PropertyW( | |
usbDevice, | |
&DEVPKEY_Device_InstanceId, | |
&hubType, | |
// ReSharper disable once CppRedundantCastExpression | |
(PBYTE)hubInstanceId, | |
&hubInstanceIdSize, | |
0 | |
); | |
if (ret != CR_SUCCESS) | |
{ | |
win32Error = CM_MapCrToWin32Err(ret, ERROR_NOT_FOUND); | |
break; | |
} | |
} | |
} while (!hubFound); | |
if (hubFound) | |
{ | |
ULONG interfaceListCchSize = 0; | |
ret = CM_Get_Device_Interface_List_SizeW( | |
&interfaceListCchSize, | |
(LPGUID)&GUID_DEVINTERFACE_USB_HUB, | |
hubInstanceId, | |
CM_GET_DEVICE_INTERFACE_LIST_PRESENT | |
); | |
if (ret != CR_SUCCESS) | |
{ | |
win32Error = CM_MapCrToWin32Err(ret, ERROR_NOT_FOUND); | |
goto exit; | |
} | |
const ULONG interfaceListByteSize = interfaceListCchSize * sizeof(WCHAR); | |
interfaceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, interfaceListByteSize); | |
ret = CM_Get_Device_Interface_ListW( | |
(LPGUID)&GUID_DEVINTERFACE_USB_HUB, | |
hubInstanceId, | |
interfaceList, | |
interfaceListCchSize, | |
CM_GET_DEVICE_INTERFACE_LIST_PRESENT | |
); | |
if (ret != CR_SUCCESS) | |
{ | |
win32Error = CM_MapCrToWin32Err(ret, ERROR_NOT_FOUND); | |
goto exit; | |
} | |
// found hub interface, opening | |
hubHandle = CreateFileW( | |
interfaceList, | |
FILE_GENERIC_READ | FILE_GENERIC_WRITE, | |
FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, | |
OPEN_EXISTING, | |
FILE_ATTRIBUTE_NORMAL, | |
NULL | |
); | |
if (hubHandle == INVALID_HANDLE_VALUE) | |
{ | |
win32Error = GetLastError(); | |
goto exit; | |
} | |
USB_CYCLE_PORT_PARAMS cycleParams = { | |
connectionIndex, STATUS_SUCCESS | |
}; | |
const BOOL success = DeviceIoControl( | |
hubHandle, | |
IOCTL_USB_HUB_CYCLE_PORT, | |
&cycleParams, | |
sizeof(USB_CYCLE_PORT_PARAMS), | |
&cycleParams, | |
sizeof(USB_CYCLE_PORT_PARAMS), | |
NULL, | |
NULL | |
); | |
win32Error = GetLastError(); | |
result = success && cycleParams.StatusReturned == ERROR_SUCCESS; | |
} | |
exit: | |
if (hubHandle) | |
CloseHandle(hubHandle); | |
if (interfaceList) | |
HeapFree(GetProcessHeap(), 0, interfaceList); | |
SetLastError(win32Error); | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment