Skip to content

Instantly share code, notes, and snippets.

@nefarius
Created July 18, 2024 01:19
Show Gist options
  • Save nefarius/650f1ebde89e8ea7170a5c9ec4996ddf to your computer and use it in GitHub Desktop.
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.
#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