How to correctly access IOCTL_USB_GET_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION?

Loberbom, PninaX 20 Reputation points
2025-05-07T20:57:05.45+00:00

Hello,

I am a developer working with IOCTL calls in Windows, and I am trying to understand the correct way to access IOCTL_USB_GET_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION.

Is there a difference between using kernel32.dll and kernelbase.dll when making this call? What is the recommended module to use when calling DeviceIoControl to issue this IOCTL?

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,480 questions
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 89,376 Reputation points
    2025-05-08T10:50:35.54+00:00

    I did this test (test in a Button Click) and I get 0 for speeds, but it seems normal as I'm on Windows 10 :

        public partial class Form1 : Form
        {
            [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
    
            public IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
    
            [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool CloseHandle(IntPtr hObject);
    
            [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);
    
            internal static uint CTL_CODE(uint deviceType, uint function, uint method, uint access)
            {
                return (deviceType << 16) | (access << 14) | (function << 2) | method;
            }
    
            public static uint FILE_DEVICE_UNKNOWN = 0x22;
            public static uint FILE_DEVICE_USB = FILE_DEVICE_UNKNOWN;
            public static uint USB_GET_NODE_INFORMATION = 258;
            public static uint USB_GET_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION  = 289;
    
            public static uint METHOD_BUFFERED = 0;
            public static uint METHOD_IN_DIRECT = 1;
            public static uint METHOD_OUT_DIRECT = 2;
            public static uint METHOD_NEITHER = 3;
    
            public static uint FILE_ANY_ACCESS = 0;
            public static uint FILE_SPECIAL_ACCESS = (FILE_ANY_ACCESS);
            public static uint FILE_READ_ACCESS = ( 0x0001 );    // file & pipe
            public static uint FILE_WRITE_ACCESS = ( 0x0002 );    // file & pipe
            public static uint IOCTL_USB_GET_NODE_INFORMATION => (uint)CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, 0, 0);
      
            public static uint IOCTL_USB_GET_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION =>
            CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS);
    
    
            [DllImport("Setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, IntPtr Enumerator, IntPtr hWndParent, int Flags);
    
            [DllImport("Setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, ref SP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData, int DeviceInterfaceDetailDataSize, ref int RequiredSize, ref SP_DEVINFO_DATA DeviceInfoData);
    
            [DllImport("Setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr Ptr, int DeviceInterfaceDetailDataSize, ref int RequiredSize, IntPtr PtrInfo);
    
            [DllImport("Setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, IntPtr DeviceInfoData, ref Guid InterfaceClassGuid, int MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
    
            [DllImport("Setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
            public static extern bool SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, uint Property,
                uint PropertyRegDataType, StringBuilder PropertyBuffer, uint PropertyBufferSize, IntPtr RequiredSize);
    
    
    #if WIN64
            public const int PACK_SIZE = 8;
    #else
            public const int PACK_SIZE = 1;
    #endif
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = PACK_SIZE)]
            public struct SP_DEVINFO_DATA
            {
                public int cbSize;
                public Guid ClassGuid;
                public int DevInst;
                public IntPtr Reserved;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct SP_DEVICE_INTERFACE_DATA
            {
                public int cbSize;
                public Guid InterfaceClassGuid;
                public int Flags;
                public IntPtr Reserved;
            }
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
            public struct SP_DEVICE_INTERFACE_DETAIL_DATA
            {
                public int cbSize;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
                public string DevicePath;
            }
    
            [DllImport("Setupapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
            public static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
    
            public const int DIGCF_PRESENT = 0x00000002;
            public const int DIGCF_DEVICEINTERFACE = 0x00000010;
            public const int ERROR_INSUFFICIENT_BUFFER = 122;
            public const int MAX_PATH = 260;
    
            public const int SPDRP_DEVICEDESC = (0x00000000);  // DeviceDesc (R/W)
            public const int SPDRP_FRIENDLYNAME = (0x0000000C); // FriendlyName (R/W)
            public const int SPDRP_LOCATION_INFORMATION = (0x0000000D);  // LocationInformation (R/W)
    
            Guid GUID_DEVINTERFACE_USB_HUB = new Guid("f18a0e88-c30c-11d0-8815-00a0c906bed8");
    
            public enum USB_HUB_NODE
            {
                UsbHub,
                UsbMIParent
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct USB_HUB_DESCRIPTOR
            {
                public byte bDescriptorLength;
                public byte bDescriptorType;
                public byte bNumberOfPorts;
                public short wHubCharacteristics;
                public byte bPowerOnToPowerGood;
                public byte bHubControlCurrent;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
                public byte[] DeviceRemovable;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct USB_HUB_INFORMATION
            {
                public USB_HUB_DESCRIPTOR HubDescriptor;
                [MarshalAs(UnmanagedType.Bool)]
                public bool HubIsBusPowered;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct USB_MI_PARENT_INFORMATION
            {
                public int NumberOfInterfaces;
            }
    
            [StructLayout(LayoutKind.Explicit)]
            public struct USB_NODE_INFORMATION
            {
                [FieldOffset(0)]
                public USB_HUB_NODE NodeType;
    
                [FieldOffset(4)]
                public USB_HUB_INFORMATION HubInformation;
    
                [FieldOffset(4)]
                public USB_MI_PARENT_INFORMATION MiParentInformation;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct USB_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION
            {
                public uint ConnectionIndex;
                public uint Length;
                public USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED RxSuperSpeedPlus;
                public uint RxLaneCount;
                public USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED TxSuperSpeedPlus;
                public uint TxLaneCount;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED
            {
                public uint Speed;
            }
    
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                Guid guid = GUID_DEVINTERFACE_USB_HUB;
                IntPtr hDeviceInfoSet = SetupDiGetClassDevs(ref guid, IntPtr.Zero, IntPtr.Zero, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
                if (hDeviceInfoSet != IntPtr.Zero)
                {
                    var did = new SP_DEVICE_INTERFACE_DATA() { cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA)) };
                    for (var nIndex = 0; SetupDiEnumDeviceInterfaces(hDeviceInfoSet, IntPtr.Zero, ref guid, nIndex, ref did); nIndex++)
                    {
                        int dwBytes = 0;
                        bool bRet = SetupDiGetDeviceInterfaceDetail(hDeviceInfoSet, ref did, IntPtr.Zero, 0, ref dwBytes, IntPtr.Zero);
                        if (!bRet && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
                        {
                            SP_DEVICE_INTERFACE_DETAIL_DATA didd = new SP_DEVICE_INTERFACE_DETAIL_DATA();
                            didd.cbSize = IntPtr.Size == 8 ? 8 : 6;
                            SP_DEVINFO_DATA dd = new SP_DEVINFO_DATA();
                            dd.cbSize = Marshal.SizeOf(dd);
                            bRet = SetupDiGetDeviceInterfaceDetail(hDeviceInfoSet, ref did, ref didd, dwBytes, ref dwBytes, ref dd);
                            if (bRet)
                            {
                                StringBuilder sbDeviceName = new StringBuilder(260);
                                bRet = SetupDiGetDeviceRegistryProperty(hDeviceInfoSet, ref dd, SPDRP_FRIENDLYNAME, 0, sbDeviceName, (uint)sbDeviceName.Capacity, IntPtr.Zero);
                                if (bRet)
                                {
                                    System.Diagnostics.Debug.WriteLine($"Device Name : {sbDeviceName.ToString()}");                               
                                }
                                else
                                {
                                    bRet = SetupDiGetDeviceRegistryProperty(hDeviceInfoSet, ref dd, SPDRP_DEVICEDESC, 0, sbDeviceName, (uint)sbDeviceName.Capacity, IntPtr.Zero);
                                    if (bRet)
                                    {
                                        System.Diagnostics.Debug.WriteLine($"Device Name (Description) : {sbDeviceName.ToString()}");                                    
                                    }
                                }
    
                                string sDevicePath = null;
                                sDevicePath = didd.DevicePath;                           
                                System.Diagnostics.Debug.WriteLine($"\tDevice Path : {sDevicePath}");
    
                                IntPtr hHub = CreateFile(sDevicePath, (uint)FileAccess.ReadWrite, (int)FileShare.ReadWrite, IntPtr.Zero, (int)FileMode.Open, 0, IntPtr.Zero);
                                if (hHub != INVALID_HANDLE_VALUE)
                                {
                                    USB_NODE_INFORMATION nodeInfo = new USB_NODE_INFORMATION();
                                    nodeInfo.NodeType = USB_HUB_NODE.UsbHub;
    
                                    int nNodeInfoSize = Marshal.SizeOf(typeof(USB_NODE_INFORMATION));
                                    IntPtr nodeInfoPtr = Marshal.AllocHGlobal(nNodeInfoSize);
                                    Marshal.StructureToPtr(nodeInfo, nodeInfoPtr, false);
    
                                    int nBytesReturned = 0;
                                    bool bResult = DeviceIoControl(hHub,
                                        IOCTL_USB_GET_NODE_INFORMATION,
                                        nodeInfoPtr,
                                        (uint)nNodeInfoSize,
                                        nodeInfoPtr,
                                        nNodeInfoSize,
                                        out nBytesReturned,
                                        IntPtr.Zero);
    
                                    if (bResult)
                                    {
                                        nodeInfo = Marshal.PtrToStructure<USB_NODE_INFORMATION>(nodeInfoPtr);
                                        for (uint port = 1; port <= nodeInfo.HubInformation.HubDescriptor.bNumberOfPorts; port++)
                                        {
                                            USB_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION ssInfo = new USB_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION();
                                            ssInfo.ConnectionIndex = port;
                                            int nSSSize = Marshal.SizeOf(ssInfo);
                                            IntPtr ssPtr = Marshal.AllocHGlobal(nSSSize);
                                            Marshal.StructureToPtr(ssInfo, ssPtr, false);
    
                                            if (DeviceIoControl(hHub, IOCTL_USB_GET_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION, ssPtr, (uint)nSSSize, ssPtr, nSSSize, out nBytesReturned, IntPtr.Zero))
                                            {
                                                ssInfo = Marshal.PtrToStructure<USB_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION>(ssPtr);
                                                System.Diagnostics.Debug.WriteLine($"\tPort {port}: Rx={ssInfo.RxSuperSpeedPlus.Speed}, Tx={ssInfo.TxSuperSpeedPlus.Speed}");
                                            }
                                            Marshal.FreeHGlobal(ssPtr);
                                        }
                                    }
                                    Marshal.FreeHGlobal(nodeInfoPtr);
                                    CloseHandle(hHub);
                                }
                            }
                        }
                    }
                    SetupDiDestroyDeviceInfoList(hDeviceInfoSet);
                }
            }
        }
    
    
    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.