Files
Aaru/Aaru.Devices/Windows/Usb.cs

1088 lines
43 KiB
C#
Raw Normal View History

// /***************************************************************************
2020-02-27 12:31:25 +00:00
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : Usb.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Windows direct device access.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains code to access USB device information under Windows.
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General internal License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General internal License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
2022-12-03 16:07:10 +00:00
// Copyright © 2011-2023 Natalia Portillo
// Copyright © 2007 Fort Hood TX, herethen, Public Domain
// ****************************************************************************/
2017-12-19 19:33:46 +00:00
using System;
using System.Collections.Generic;
2017-12-21 14:30:38 +00:00
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
2017-12-19 19:33:46 +00:00
using System.Runtime.InteropServices;
using System.Text;
namespace Aaru.Devices.Windows;
2022-03-06 13:29:38 +00:00
// TODO: Even after cleaning, refactoring and xml-documenting, this code needs some love
/// <summary>Implements functions for getting and accessing information from the USB bus</summary>
[SuppressMessage("ReSharper", "UnusedMember.Local"), SuppressMessage("ReSharper", "UnusedType.Local")]
2022-03-07 07:36:44 +00:00
static partial class Usb
{
2022-03-06 13:29:38 +00:00
/// <summary>Return a list of USB Host Controllers</summary>
/// <returns>List of USB Host Controllers</returns>
static IEnumerable<UsbController> GetHostControllers()
{
List<UsbController> hostList = new List<UsbController>();
var hostGuid = new Guid(GUID_DEVINTERFACE_HUBCONTROLLER);
2022-03-06 13:29:38 +00:00
// We start at the "root" of the device tree and look for all
// devices that match the interface GUID of a Hub Controller
IntPtr h = SetupDiGetClassDevs(ref hostGuid, 0, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
2020-02-29 18:03:35 +00:00
2022-03-18 01:32:22 +00:00
if(h == _invalidHandleValue)
2022-03-06 13:29:38 +00:00
return new ReadOnlyCollection<UsbController>(hostList);
2022-03-06 13:29:38 +00:00
IntPtr ptrBuf = Marshal.AllocHGlobal(BUFFER_SIZE);
bool success;
int i = 0;
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
do
{
var host = new UsbController
{
2022-03-18 01:32:22 +00:00
_controllerIndex = i
2022-03-06 13:29:38 +00:00
};
2022-03-06 13:29:38 +00:00
// create a Device Interface Data structure
var dia = new SpDeviceInterfaceData();
dia.cbSize = Marshal.SizeOf(dia);
2022-03-06 13:29:38 +00:00
// start the enumeration
success = SetupDiEnumDeviceInterfaces(h, IntPtr.Zero, ref hostGuid, i, ref dia);
if(success)
{
// build a DevInfo Data structure
var da = new SpDevinfoData();
da.cbSize = Marshal.SizeOf(da);
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
// build a Device Interface Detail Data structure
var didd = new SpDeviceInterfaceDetailData
{
2022-03-06 13:29:38 +00:00
cbSize = 4 + Marshal.SystemDefaultCharSize
};
2022-03-06 13:29:38 +00:00
// trust me :)
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
// now we can get some more detailed information
int nRequiredSize = 0;
2022-11-15 00:20:20 +00:00
if(SetupDiGetDeviceInterfaceDetail(h, ref dia, ref didd, BUFFER_SIZE, ref nRequiredSize, ref da))
2022-03-06 13:29:38 +00:00
{
2022-03-18 01:32:22 +00:00
host._controllerDevicePath = didd.DevicePath;
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
// get the Device Description and DriverKeyName
int requiredSize = 0;
2022-03-06 13:29:38 +00:00
int regType = REG_SZ;
2022-03-07 07:36:44 +00:00
if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DEVICEDESC, ref regType, ptrBuf, BUFFER_SIZE,
ref requiredSize))
2022-03-18 01:32:22 +00:00
host._controllerDeviceDesc = Marshal.PtrToStringAuto(ptrBuf);
2022-03-06 13:29:38 +00:00
if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DRIVER, ref regType, ptrBuf, BUFFER_SIZE,
ref requiredSize))
2022-03-18 01:32:22 +00:00
host._controllerDriverKeyName = Marshal.PtrToStringAuto(ptrBuf);
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
hostList.Add(host);
}
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
i++;
} while(success);
2018-06-22 08:08:38 +01:00
2022-03-06 13:29:38 +00:00
Marshal.FreeHGlobal(ptrBuf);
SetupDiDestroyDeviceInfoList(h);
2018-06-22 08:08:38 +01:00
2022-03-06 13:29:38 +00:00
// convert it into a Collection
return new ReadOnlyCollection<UsbController>(hostList);
}
2022-03-06 13:29:38 +00:00
/// <summary>private function for finding a USB device's Description</summary>
/// <param name="driverKeyName">Device driver key name</param>
/// <returns>USB device description</returns>
static string GetDescriptionByKeyName(string driverKeyName)
{
string ans = "";
2022-03-06 13:29:38 +00:00
// Use the "enumerator form" of the SetupDiGetClassDevs API
// to generate a list of all USB devices
2022-11-15 00:20:20 +00:00
IntPtr h = SetupDiGetClassDevs(0, REGSTR_KEY_USB, IntPtr.Zero, DIGCF_PRESENT | DIGCF_ALLCLASSES);
2022-03-18 01:32:22 +00:00
if(h == _invalidHandleValue)
2022-03-06 13:29:38 +00:00
return ans;
2022-03-06 13:29:38 +00:00
IntPtr ptrBuf = Marshal.AllocHGlobal(BUFFER_SIZE);
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
bool success;
int i = 0;
2022-03-06 13:29:38 +00:00
do
{
// create a Device Interface Data structure
var da = new SpDevinfoData();
da.cbSize = Marshal.SizeOf(da);
2022-03-06 13:29:38 +00:00
// start the enumeration
success = SetupDiEnumDeviceInfo(h, i, ref da);
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
if(success)
{
int requiredSize = 0;
int regType = REG_SZ;
string keyName = "";
2022-03-06 13:29:38 +00:00
if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DRIVER, ref regType, ptrBuf, BUFFER_SIZE,
ref requiredSize))
keyName = Marshal.PtrToStringAuto(ptrBuf);
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
// is it a match?
if(keyName == driverKeyName)
{
2022-03-07 07:36:44 +00:00
if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DEVICEDESC, ref regType, ptrBuf, BUFFER_SIZE,
ref requiredSize))
2022-03-06 13:29:38 +00:00
ans = Marshal.PtrToStringAuto(ptrBuf);
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
i++;
} while(success);
2022-03-06 13:29:38 +00:00
Marshal.FreeHGlobal(ptrBuf);
SetupDiDestroyDeviceInfoList(h);
2022-03-06 13:29:38 +00:00
return ans;
}
2022-03-06 13:29:38 +00:00
/// <summary>private function for finding a USB device's Instance ID</summary>
/// <param name="driverKeyName">Device driver key name</param>
/// <returns>Device instance ID</returns>
static string GetInstanceIdByKeyName(string driverKeyName)
{
string ans = "";
2022-03-06 13:29:38 +00:00
// Use the "enumerator form" of the SetupDiGetClassDevs API
// to generate a list of all USB devices
2022-11-15 00:20:20 +00:00
IntPtr h = SetupDiGetClassDevs(0, REGSTR_KEY_USB, IntPtr.Zero, DIGCF_PRESENT | DIGCF_ALLCLASSES);
2020-02-29 18:03:35 +00:00
2022-03-18 01:32:22 +00:00
if(h == _invalidHandleValue)
2022-03-06 13:29:38 +00:00
return ans;
2022-03-06 13:29:38 +00:00
IntPtr ptrBuf = Marshal.AllocHGlobal(BUFFER_SIZE);
2022-03-06 13:29:38 +00:00
bool success;
int i = 0;
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
do
{
// create a Device Interface Data structure
var da = new SpDevinfoData();
da.cbSize = Marshal.SizeOf(da);
2022-03-06 13:29:38 +00:00
// start the enumeration
success = SetupDiEnumDeviceInfo(h, i, ref da);
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
if(success)
{
int requiredSize = 0;
2022-03-06 13:29:38 +00:00
int regType = REG_SZ;
string keyName = "";
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DRIVER, ref regType, ptrBuf, BUFFER_SIZE,
ref requiredSize))
keyName = Marshal.PtrToStringAuto(ptrBuf);
2022-03-06 13:29:38 +00:00
// is it a match?
if(keyName == driverKeyName)
{
2022-11-15 00:20:20 +00:00
var sb = new StringBuilder(BUFFER_SIZE);
SetupDiGetDeviceInstanceId(h, ref da, sb, BUFFER_SIZE, out requiredSize);
2022-03-06 13:29:38 +00:00
ans = sb.ToString();
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
break;
}
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
i++;
} while(success);
2022-03-06 13:29:38 +00:00
Marshal.FreeHGlobal(ptrBuf);
SetupDiDestroyDeviceInfoList(h);
2022-03-06 13:29:38 +00:00
return ans;
}
/// <summary>Represents a USB Host Controller</summary>
sealed class UsbController
{
2022-03-18 01:32:22 +00:00
internal string _controllerDriverKeyName, _controllerDevicePath, _controllerDeviceDesc;
internal int _controllerIndex;
2022-03-06 13:29:38 +00:00
/// <summary>A simple default constructor</summary>
internal UsbController()
{
2022-03-18 01:32:22 +00:00
_controllerIndex = 0;
_controllerDevicePath = "";
_controllerDeviceDesc = "";
_controllerDriverKeyName = "";
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
/// <summary>Return the index of the instance</summary>
2022-03-18 01:32:22 +00:00
internal int Index => _controllerIndex;
2022-03-06 13:29:38 +00:00
/// <summary>
/// Return the Device Path, such as "\\?\pci#ven_10de&amp;dev_005a&amp;subsys_815a1043&amp;rev_a2#3&267a616a&0&
/// 58#{3abf6f2d-71c4-462a-8a92-1e6861e6af27}"
/// </summary>
2022-03-18 01:32:22 +00:00
internal string DevicePath => _controllerDevicePath;
2022-03-06 13:29:38 +00:00
/// <summary>The DriverKeyName may be useful as a search key</summary>
2022-03-18 01:32:22 +00:00
internal string DriverKeyName => _controllerDriverKeyName;
2022-03-06 13:29:38 +00:00
/// <summary>Return the Friendly Name, such as "VIA USB Enhanced Host Controller"</summary>
2022-03-18 01:32:22 +00:00
internal string Name => _controllerDeviceDesc;
2022-03-06 13:29:38 +00:00
/// <summary>Return Root Hub for this Controller</summary>
internal UsbHub GetRootHub()
{
var root = new UsbHub
{
2022-03-18 01:32:22 +00:00
_hubIsRootHub = true,
_hubDeviceDesc = "Root Hub"
2022-03-06 13:29:38 +00:00
};
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
// Open a handle to the Host Controller
IntPtr h = CreateFile(_controllerDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0,
IntPtr.Zero);
2022-03-18 01:32:22 +00:00
if(h == _invalidHandleValue)
2022-03-06 13:29:38 +00:00
return root;
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
var hubName = new UsbRootHubName();
int nBytes = Marshal.SizeOf(hubName);
IntPtr ptrHubName = Marshal.AllocHGlobal(nBytes);
2022-03-06 13:29:38 +00:00
// get the Hub Name
if(DeviceIoControl(h, IOCTL_USB_GET_ROOT_HUB_NAME, ptrHubName, nBytes, ptrHubName, nBytes, out _,
IntPtr.Zero))
{
2022-03-17 00:46:26 +00:00
hubName = (UsbRootHubName)(Marshal.PtrToStructure(ptrHubName, typeof(UsbRootHubName)) ??
default(UsbRootHubName));
2022-03-18 01:32:22 +00:00
root._hubDevicePath = @"\\.\" + hubName.RootHubName;
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
// TODO: Get DriverKeyName for Root Hub
// Now let's open the Hub (based upon the HubName we got above)
IntPtr h2 = CreateFile(root._hubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0,
IntPtr.Zero);
2020-02-29 18:03:35 +00:00
2022-03-18 01:32:22 +00:00
if(h2 != _invalidHandleValue)
2022-03-06 13:29:38 +00:00
{
var nodeInfo = new UsbNodeInformation
{
2022-03-06 13:29:38 +00:00
NodeType = (int)UsbHubNode.UsbHub
};
2022-03-06 13:29:38 +00:00
nBytes = Marshal.SizeOf(nodeInfo);
IntPtr ptrNodeInfo = Marshal.AllocHGlobal(nBytes);
Marshal.StructureToPtr(nodeInfo, ptrNodeInfo, true);
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
// get the Hub Information
2022-03-07 07:36:44 +00:00
if(DeviceIoControl(h2, IOCTL_USB_GET_NODE_INFORMATION, ptrNodeInfo, nBytes, ptrNodeInfo, nBytes, out _,
IntPtr.Zero))
2022-03-06 13:29:38 +00:00
{
2022-03-18 01:32:22 +00:00
nodeInfo = (UsbNodeInformation)(Marshal.PtrToStructure(ptrNodeInfo, typeof(UsbNodeInformation)) ??
default(UsbNodeInformation));
2018-06-22 08:08:38 +01:00
2022-03-18 01:32:22 +00:00
root._hubIsBusPowered = Convert.ToBoolean(nodeInfo.HubInformation.HubIsBusPowered);
root._hubPortCount = nodeInfo.HubInformation.HubDescriptor.bNumberOfPorts;
}
2022-03-06 13:29:38 +00:00
Marshal.FreeHGlobal(ptrNodeInfo);
CloseHandle(h2);
}
2022-03-06 13:29:38 +00:00
Marshal.FreeHGlobal(ptrHubName);
CloseHandle(h);
return root;
}
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
/// <summary>The Hub class</summary>
internal class UsbHub
{
2022-03-18 01:32:22 +00:00
internal string _hubDriverKey, _hubDevicePath, _hubDeviceDesc;
internal bool _hubIsBusPowered, _hubIsRootHub;
internal string _hubManufacturer, _hubProduct, _hubSerialNumber, _hubInstanceId;
internal int _hubPortCount;
2022-03-06 13:29:38 +00:00
/// <summary>a simple default constructor</summary>
internal UsbHub()
{
2022-03-18 01:32:22 +00:00
_hubPortCount = 0;
_hubDevicePath = "";
_hubDeviceDesc = "";
_hubDriverKey = "";
_hubIsBusPowered = false;
_hubIsRootHub = false;
_hubManufacturer = "";
_hubProduct = "";
_hubSerialNumber = "";
_hubInstanceId = "";
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
/// <summary>return Port Count</summary>
2022-03-18 01:32:22 +00:00
internal int PortCount => _hubPortCount;
2022-03-06 13:29:38 +00:00
/// <summary>
/// return the Device Path, such as "\\?\pci#ven_10de&amp;dev_005a&amp;subsys_815a1043&amp;rev_a2#3&267a616a&0&
/// 58#{3abf6f2d-71c4-462a-8a92-1e6861e6af27}"
/// </summary>
2022-03-18 01:32:22 +00:00
internal string DevicePath => _hubDevicePath;
2022-03-06 13:29:38 +00:00
/// <summary>The DriverKey may be useful as a search key</summary>
2022-03-18 01:32:22 +00:00
internal string DriverKey => _hubDriverKey;
2022-03-06 13:29:38 +00:00
/// <summary>return the Friendly Name, such as "VIA USB Enhanced Host Controller"</summary>
2022-03-18 01:32:22 +00:00
internal string Name => _hubDeviceDesc;
2022-03-06 13:29:38 +00:00
/// <summary>the device path of this device</summary>
2022-03-18 01:32:22 +00:00
internal string InstanceId => _hubInstanceId;
2022-03-06 13:29:38 +00:00
/// <summary>is is this a self-powered hub?</summary>
2022-03-18 01:32:22 +00:00
internal bool IsBusPowered => _hubIsBusPowered;
2022-03-06 13:29:38 +00:00
/// <summary>is this a root hub?</summary>
2022-03-18 01:32:22 +00:00
internal bool IsRootHub => _hubIsRootHub;
2022-03-18 01:32:22 +00:00
internal string Manufacturer => _hubManufacturer;
2022-03-18 01:32:22 +00:00
internal string Product => _hubProduct;
2022-03-18 01:32:22 +00:00
internal string SerialNumber => _hubSerialNumber;
2022-03-06 13:29:38 +00:00
/// <summary>return a list of the down stream ports</summary>
/// <returns>List of downstream ports</returns>
internal IEnumerable<UsbPort> GetPorts()
{
List<UsbPort> portList = new List<UsbPort>();
2022-03-06 13:29:38 +00:00
// Open a handle to the Hub device
2022-03-18 01:32:22 +00:00
IntPtr h = CreateFile(_hubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0,
2022-03-06 13:29:38 +00:00
IntPtr.Zero);
2020-02-29 18:03:35 +00:00
2022-03-18 01:32:22 +00:00
if(h == _invalidHandleValue)
2022-03-06 13:29:38 +00:00
return new ReadOnlyCollection<UsbPort>(portList);
2022-03-06 13:29:38 +00:00
int nBytes = Marshal.SizeOf(typeof(UsbNodeConnectionInformationEx));
IntPtr ptrNodeConnection = Marshal.AllocHGlobal(nBytes);
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
// loop thru all of the ports on the hub
// BTW: Ports are numbered starting at 1
for(int i = 1; i <= _hubPortCount; i++)
2022-03-06 13:29:38 +00:00
{
var nodeConnection = new UsbNodeConnectionInformationEx
{
2022-03-06 13:29:38 +00:00
ConnectionIndex = i
};
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
Marshal.StructureToPtr(nodeConnection, ptrNodeConnection, true);
2022-03-06 13:29:38 +00:00
if(!DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, ptrNodeConnection, nBytes,
ptrNodeConnection, nBytes, out _, IntPtr.Zero))
continue;
2022-03-06 13:29:38 +00:00
nodeConnection =
2022-03-17 00:46:26 +00:00
(UsbNodeConnectionInformationEx)(Marshal.PtrToStructure(ptrNodeConnection,
typeof(UsbNodeConnectionInformationEx)) ??
default(UsbNodeConnectionInformationEx));
2022-03-06 13:29:38 +00:00
// load up the USBPort class
var port = new UsbPort
{
_portPortNumber = i,
_portHubDevicePath = _hubDevicePath,
_portStatus = ((UsbConnectionStatus)nodeConnection.ConnectionStatus).ToString(),
_portSpeed = ((UsbDeviceSpeed)nodeConnection.Speed).ToString(),
_portIsDeviceConnected =
nodeConnection.ConnectionStatus == (int)UsbConnectionStatus.DeviceConnected,
_portIsHub = Convert.ToBoolean(nodeConnection.DeviceIsHub),
_portDeviceDescriptor = nodeConnection.DeviceDescriptor
2022-03-06 13:29:38 +00:00
};
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
// add it to the list
portList.Add(port);
}
2022-03-06 13:29:38 +00:00
Marshal.FreeHGlobal(ptrNodeConnection);
CloseHandle(h);
// convert it into a Collection
return new ReadOnlyCollection<UsbPort>(portList);
}
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
/// <summary>Represents an USB port</summary>
internal class UsbPort
{
2022-03-18 01:32:22 +00:00
internal UsbDeviceDescriptor _portDeviceDescriptor;
internal bool _portIsHub, _portIsDeviceConnected;
internal int _portPortNumber;
internal string _portStatus, _portHubDevicePath, _portSpeed;
2022-03-06 13:29:38 +00:00
/// <summary>a simple default constructor</summary>
internal UsbPort()
{
2022-03-18 01:32:22 +00:00
_portPortNumber = 0;
_portStatus = "";
_portHubDevicePath = "";
_portSpeed = "";
_portIsHub = false;
_portIsDeviceConnected = false;
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
/// <summary>return Port Index of the Hub</summary>
2022-03-18 01:32:22 +00:00
internal int PortNumber => _portPortNumber;
2022-03-06 13:29:38 +00:00
/// <summary>return the Device Path of the Hub</summary>
2022-03-18 01:32:22 +00:00
internal string HubDevicePath => _portHubDevicePath;
2022-03-06 13:29:38 +00:00
/// <summary>the status (see USB_CONNECTION_STATUS above)</summary>
2022-03-18 01:32:22 +00:00
internal string Status => _portStatus;
2022-03-06 13:29:38 +00:00
/// <summary>the speed of the connection (see USB_DEVICE_SPEED above)</summary>
2022-03-18 01:32:22 +00:00
internal string Speed => _portSpeed;
2022-03-06 13:29:38 +00:00
/// <summary>is this a downstream external hub?</summary>
2022-03-18 01:32:22 +00:00
internal bool IsHub => _portIsHub;
2022-03-06 13:29:38 +00:00
/// <summary>is anybody home?</summary>
2022-03-18 01:32:22 +00:00
internal bool IsDeviceConnected => _portIsDeviceConnected;
2022-03-06 13:29:38 +00:00
/// <summary>return a down stream external hub</summary>
/// <returns>Downstream external hub</returns>
internal UsbDevice GetDevice()
{
2022-03-18 01:32:22 +00:00
if(!_portIsDeviceConnected)
2022-03-06 13:29:38 +00:00
return null;
2022-03-06 13:29:38 +00:00
// Copy over some values from the Port class
// Ya know, I've given some thought about making Device a derived class...
var device = new UsbDevice
{
2022-03-18 01:32:22 +00:00
_devicePortNumber = _portPortNumber,
_deviceHubDevicePath = _portHubDevicePath,
_deviceDescriptor = _portDeviceDescriptor
2022-03-06 13:29:38 +00:00
};
2022-03-06 13:29:38 +00:00
// Open a handle to the Hub device
2022-03-18 01:32:22 +00:00
IntPtr h = CreateFile(_portHubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0,
2022-03-06 13:29:38 +00:00
IntPtr.Zero);
2020-02-29 18:03:35 +00:00
2022-03-18 01:32:22 +00:00
if(h == _invalidHandleValue)
2022-03-06 13:29:38 +00:00
return device;
2022-03-06 13:29:38 +00:00
int nBytesReturned;
int nBytes = BUFFER_SIZE;
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
// We use this to zero fill a buffer
string nullString = new string((char)0, BUFFER_SIZE / Marshal.SystemDefaultCharSize);
2022-03-06 13:29:38 +00:00
// The iManufacturer, iProduct and iSerialNumber entries in the
// Device Descriptor are really just indexes. So, we have to
// request a String Descriptor to get the values for those strings.
2022-03-18 01:32:22 +00:00
if(_portDeviceDescriptor.iManufacturer > 0)
2022-03-06 13:29:38 +00:00
{
// build a request for string descriptor
var request = new UsbDescriptorRequest
{
2022-03-18 01:32:22 +00:00
ConnectionIndex = _portPortNumber,
2022-03-06 13:29:38 +00:00
SetupPacket =
{
2022-03-06 13:29:38 +00:00
// Language Code
wIndex = 0x409,
2022-03-18 01:32:22 +00:00
wValue = (short)((USB_STRING_DESCRIPTOR_TYPE << 8) + _portDeviceDescriptor.iManufacturer)
}
2022-03-06 13:29:38 +00:00
};
2018-06-22 08:08:38 +01:00
2022-03-06 13:29:38 +00:00
request.SetupPacket.wLength = (short)(nBytes - Marshal.SizeOf(request));
2018-06-22 08:08:38 +01:00
2022-03-06 13:29:38 +00:00
// Geez, I wish C# had a Marshal.MemSet() method
IntPtr ptrRequest = Marshal.StringToHGlobalAuto(nullString);
Marshal.StructureToPtr(request, ptrRequest, true);
2018-06-22 08:08:38 +01:00
2022-03-06 13:29:38 +00:00
// Use an IOCTL call to request the String Descriptor
if(DeviceIoControl(h, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ptrRequest, nBytes, ptrRequest,
nBytes, out nBytesReturned, IntPtr.Zero))
{
2022-03-06 13:29:38 +00:00
// The location of the string descriptor is immediately after
// the Request structure. Because this location is not "covered"
// by the structure allocation, we're forced to zero out this
// chunk of memory by using the StringToHGlobalAuto() hack above
var ptrStringDesc = IntPtr.Add(ptrRequest, Marshal.SizeOf(request));
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
var stringDesc =
2022-03-17 00:46:26 +00:00
(UsbStringDescriptor)(Marshal.PtrToStructure(ptrStringDesc, typeof(UsbStringDescriptor)) ??
default(UsbStringDescriptor));
2018-06-22 08:08:38 +01:00
2022-03-18 01:32:22 +00:00
device._deviceManufacturer = stringDesc.bString;
}
2022-03-06 13:29:38 +00:00
Marshal.FreeHGlobal(ptrRequest);
}
2022-03-18 01:32:22 +00:00
if(_portDeviceDescriptor.iProduct > 0)
2022-03-06 13:29:38 +00:00
{
// build a request for string descriptor
var request = new UsbDescriptorRequest
{
2022-03-18 01:32:22 +00:00
ConnectionIndex = _portPortNumber,
2020-07-20 04:34:16 +01:00
SetupPacket =
2020-02-29 18:03:35 +00:00
{
2022-03-06 13:29:38 +00:00
// Language Code
wIndex = 0x409,
2022-03-18 01:32:22 +00:00
wValue = (short)((USB_STRING_DESCRIPTOR_TYPE << 8) + _portDeviceDescriptor.iProduct)
2020-02-29 18:03:35 +00:00
}
};
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
request.SetupPacket.wLength = (short)(nBytes - Marshal.SizeOf(request));
2020-02-29 18:03:35 +00:00
// Geez, I wish C# had a Marshal.MemSet() method
2022-03-06 13:29:38 +00:00
IntPtr ptrRequest = Marshal.StringToHGlobalAuto(nullString);
Marshal.StructureToPtr(request, ptrRequest, true);
// Use an IOCTL call to request the String Descriptor
2022-03-06 13:29:38 +00:00
if(DeviceIoControl(h, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ptrRequest, nBytes, ptrRequest,
nBytes, out nBytesReturned, IntPtr.Zero))
{
2022-03-06 13:29:38 +00:00
// the location of the string descriptor is immediately after the Request structure
var ptrStringDesc = IntPtr.Add(ptrRequest, Marshal.SizeOf(request));
var stringDesc =
2022-03-17 00:46:26 +00:00
(UsbStringDescriptor)(Marshal.PtrToStructure(ptrStringDesc, typeof(UsbStringDescriptor)) ??
default(UsbStringDescriptor));
2022-03-06 13:29:38 +00:00
2022-03-18 01:32:22 +00:00
device._deviceProduct = stringDesc.bString;
}
2018-06-22 08:08:38 +01:00
2022-03-06 13:29:38 +00:00
Marshal.FreeHGlobal(ptrRequest);
}
2022-03-18 01:32:22 +00:00
if(_portDeviceDescriptor.iSerialNumber > 0)
2022-03-06 13:29:38 +00:00
{
// build a request for string descriptor
var request = new UsbDescriptorRequest
2020-02-29 18:03:35 +00:00
{
2022-03-18 01:32:22 +00:00
ConnectionIndex = _portPortNumber,
2022-03-06 13:29:38 +00:00
SetupPacket =
{
// Language Code
wIndex = 0x409,
2022-03-18 01:32:22 +00:00
wValue = (short)((USB_STRING_DESCRIPTOR_TYPE << 8) + _portDeviceDescriptor.iSerialNumber)
2022-03-06 13:29:38 +00:00
}
2020-02-29 18:03:35 +00:00
};
2022-03-06 13:29:38 +00:00
request.SetupPacket.wLength = (short)(nBytes - Marshal.SizeOf(request));
2022-03-06 13:29:38 +00:00
// Geez, I wish C# had a Marshal.MemSet() method
IntPtr ptrRequest = Marshal.StringToHGlobalAuto(nullString);
Marshal.StructureToPtr(request, ptrRequest, true);
// Use an IOCTL call to request the String Descriptor
if(DeviceIoControl(h, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ptrRequest, nBytes, ptrRequest,
nBytes, out nBytesReturned, IntPtr.Zero))
{
2022-03-06 13:29:38 +00:00
// the location of the string descriptor is immediately after the Request structure
var ptrStringDesc = IntPtr.Add(ptrRequest, Marshal.SizeOf(request));
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
var stringDesc =
2022-03-17 00:46:26 +00:00
(UsbStringDescriptor)(Marshal.PtrToStructure(ptrStringDesc, typeof(UsbStringDescriptor)) ??
default(UsbStringDescriptor));
2022-03-18 01:32:22 +00:00
device._deviceSerialNumber = stringDesc.bString;
}
2018-06-22 08:08:38 +01:00
2022-03-06 13:29:38 +00:00
Marshal.FreeHGlobal(ptrRequest);
}
2022-03-06 13:29:38 +00:00
// build a request for configuration descriptor
var dcrRequest = new UsbDescriptorRequest
{
2022-03-18 01:32:22 +00:00
ConnectionIndex = _portPortNumber,
2022-03-06 13:29:38 +00:00
SetupPacket =
{
wIndex = 0,
wValue = USB_CONFIGURATION_DESCRIPTOR_TYPE << 8
}
};
2022-03-06 13:29:38 +00:00
dcrRequest.SetupPacket.wLength = (short)(nBytes - Marshal.SizeOf(dcrRequest));
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
// Geez, I wish C# had a Marshal.MemSet() method
IntPtr dcrPtrRequest = Marshal.StringToHGlobalAuto(nullString);
Marshal.StructureToPtr(dcrRequest, dcrPtrRequest, true);
2018-06-22 08:08:38 +01:00
2022-03-06 13:29:38 +00:00
// Use an IOCTL call to request the String Descriptor
2022-03-07 07:36:44 +00:00
if(DeviceIoControl(h, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, dcrPtrRequest, nBytes, dcrPtrRequest,
nBytes, out nBytesReturned, IntPtr.Zero))
2022-03-06 13:29:38 +00:00
{
var ptrStringDesc = IntPtr.Add(dcrPtrRequest, Marshal.SizeOf(dcrRequest));
2022-03-18 01:32:22 +00:00
device._binaryDeviceDescriptors = new byte[nBytesReturned];
Marshal.Copy(ptrStringDesc, device._binaryDeviceDescriptors, 0, nBytesReturned);
2022-03-06 13:29:38 +00:00
}
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
Marshal.FreeHGlobal(dcrPtrRequest);
2022-03-06 13:29:38 +00:00
// Get the Driver Key Name (usefull in locating a device)
var driverKey = new UsbNodeConnectionDriverkeyName
{
2022-03-18 01:32:22 +00:00
ConnectionIndex = _portPortNumber
2022-03-06 13:29:38 +00:00
};
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
nBytes = Marshal.SizeOf(driverKey);
IntPtr ptrDriverKey = Marshal.AllocHGlobal(nBytes);
Marshal.StructureToPtr(driverKey, ptrDriverKey, true);
2022-03-06 13:29:38 +00:00
// Use an IOCTL call to request the Driver Key Name
if(DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, ptrDriverKey, nBytes, ptrDriverKey,
nBytes, out nBytesReturned, IntPtr.Zero))
{
2022-03-17 00:46:26 +00:00
driverKey = (UsbNodeConnectionDriverkeyName)(Marshal.PtrToStructure(ptrDriverKey,
typeof(UsbNodeConnectionDriverkeyName)) ??
default(UsbNodeConnectionDriverkeyName));
2020-02-29 18:03:35 +00:00
2022-03-18 01:32:22 +00:00
device._deviceDriverKey = driverKey.DriverKeyName;
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
// use the DriverKeyName to get the Device Description and Instance ID
2022-03-18 01:32:22 +00:00
device._deviceName = GetDescriptionByKeyName(device._deviceDriverKey);
device._deviceInstanceId = GetInstanceIdByKeyName(device._deviceDriverKey);
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
Marshal.FreeHGlobal(ptrDriverKey);
CloseHandle(h);
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
return device;
}
2018-06-22 08:08:38 +01:00
2022-03-06 13:29:38 +00:00
/// <summary>return a down stream external hub</summary>
/// <returns>Downstream external hub</returns>
internal UsbHub GetHub()
{
2022-03-18 01:32:22 +00:00
if(!_portIsHub)
2022-03-06 13:29:38 +00:00
return null;
2022-11-14 01:23:52 +00:00
var hub = new UsbHub
{
_hubIsRootHub = false,
_hubDeviceDesc = "External Hub"
};
2022-03-06 13:29:38 +00:00
// Open a handle to the Host Controller
IntPtr h = CreateFile(_portHubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0,
IntPtr.Zero);
2020-02-29 18:03:35 +00:00
2022-03-18 01:32:22 +00:00
if(h == _invalidHandleValue)
return hub;
2022-03-06 13:29:38 +00:00
// Get the DevicePath for downstream hub
var nodeName = new UsbNodeConnectionName
{
2022-03-18 01:32:22 +00:00
ConnectionIndex = _portPortNumber
2022-03-06 13:29:38 +00:00
};
int nBytes = Marshal.SizeOf(nodeName);
IntPtr ptrNodeName = Marshal.AllocHGlobal(nBytes);
Marshal.StructureToPtr(nodeName, ptrNodeName, true);
// Use an IOCTL call to request the Node Name
2022-03-07 07:36:44 +00:00
if(DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_NAME, ptrNodeName, nBytes, ptrNodeName, nBytes, out _,
IntPtr.Zero))
2022-03-06 13:29:38 +00:00
{
2022-03-17 00:46:26 +00:00
nodeName = (UsbNodeConnectionName)(Marshal.PtrToStructure(ptrNodeName, typeof(UsbNodeConnectionName)) ??
default(UsbNodeConnectionName));
2022-03-06 13:29:38 +00:00
2022-03-18 01:32:22 +00:00
hub._hubDevicePath = @"\\.\" + nodeName.NodeName;
}
2022-03-06 13:29:38 +00:00
// Now let's open the Hub (based upon the HubName we got above)
IntPtr h2 = CreateFile(hub._hubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0,
IntPtr.Zero);
2022-03-18 01:32:22 +00:00
if(h2 != _invalidHandleValue)
2022-03-06 13:29:38 +00:00
{
var nodeInfo = new UsbNodeInformation
{
NodeType = (int)UsbHubNode.UsbHub
};
2022-03-06 13:29:38 +00:00
nBytes = Marshal.SizeOf(nodeInfo);
IntPtr ptrNodeInfo = Marshal.AllocHGlobal(nBytes);
Marshal.StructureToPtr(nodeInfo, ptrNodeInfo, true);
2022-03-06 13:29:38 +00:00
// get the Hub Information
2022-03-07 07:36:44 +00:00
if(DeviceIoControl(h2, IOCTL_USB_GET_NODE_INFORMATION, ptrNodeInfo, nBytes, ptrNodeInfo, nBytes, out _,
IntPtr.Zero))
2022-03-06 13:29:38 +00:00
{
2022-03-17 00:46:26 +00:00
nodeInfo = (UsbNodeInformation)(Marshal.PtrToStructure(ptrNodeInfo, typeof(UsbNodeInformation)) ??
default(UsbNodeInformation));
2022-03-18 01:32:22 +00:00
hub._hubIsBusPowered = Convert.ToBoolean(nodeInfo.HubInformation.HubIsBusPowered);
hub._hubPortCount = nodeInfo.HubInformation.HubDescriptor.bNumberOfPorts;
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
Marshal.FreeHGlobal(ptrNodeInfo);
CloseHandle(h2);
}
2022-03-06 13:29:38 +00:00
// Fill in the missing Manufacture, Product, and SerialNumber values
// values by just creating a Device instance and copying the values
UsbDevice device = GetDevice();
2022-03-18 01:32:22 +00:00
hub._hubInstanceId = device._deviceInstanceId;
hub._hubManufacturer = device.Manufacturer;
hub._hubProduct = device.Product;
hub._hubSerialNumber = device.SerialNumber;
hub._hubDriverKey = device.DriverKey;
2022-03-06 13:29:38 +00:00
Marshal.FreeHGlobal(ptrNodeName);
CloseHandle(h);
2022-03-06 13:29:38 +00:00
return hub;
}
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
/// <summary>Represents an USB device</summary>
internal class UsbDevice
{
2022-03-18 01:32:22 +00:00
internal byte[] _binaryDeviceDescriptors;
internal UsbDeviceDescriptor _deviceDescriptor;
internal string _deviceDriverKey, _deviceHubDevicePath, _deviceInstanceId, _deviceName;
internal string _deviceManufacturer, _deviceProduct, _deviceSerialNumber;
internal int _devicePortNumber;
2022-03-06 13:29:38 +00:00
/// <summary>a simple default constructor</summary>
internal UsbDevice()
{
2022-03-18 01:32:22 +00:00
_devicePortNumber = 0;
_deviceHubDevicePath = "";
_deviceDriverKey = "";
_deviceManufacturer = "";
_deviceProduct = "Unknown USB Device";
_deviceSerialNumber = "";
_deviceName = "";
_deviceInstanceId = "";
_binaryDeviceDescriptors = null;
}
2022-03-06 13:29:38 +00:00
/// <summary>return Port Index of the Hub</summary>
2022-03-18 01:32:22 +00:00
internal int PortNumber => _devicePortNumber;
2022-03-06 13:29:38 +00:00
/// <summary>return the Device Path of the Hub (the parent device)</summary>
2022-03-18 01:32:22 +00:00
internal string HubDevicePath => _deviceHubDevicePath;
2022-03-06 13:29:38 +00:00
/// <summary>useful as a search key</summary>
2022-03-18 01:32:22 +00:00
internal string DriverKey => _deviceDriverKey;
2022-03-06 13:29:38 +00:00
/// <summary>the device path of this device</summary>
2022-03-18 01:32:22 +00:00
internal string InstanceId => _deviceInstanceId;
2022-03-06 13:29:38 +00:00
/// <summary>the friendly name</summary>
2022-03-18 01:32:22 +00:00
internal string Name => _deviceName;
2022-03-18 01:32:22 +00:00
internal string Manufacturer => _deviceManufacturer;
2022-03-18 01:32:22 +00:00
internal string Product => _deviceProduct;
2022-03-18 01:32:22 +00:00
internal string SerialNumber => _deviceSerialNumber;
2017-12-19 20:33:03 +00:00
2022-03-18 01:32:22 +00:00
internal byte[] BinaryDescriptors => _binaryDeviceDescriptors;
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
#region "API Region"
// ********************** Constants ************************
const int GENERIC_WRITE = 0x40000000;
const int FILE_SHARE_READ = 0x1;
const int FILE_SHARE_WRITE = 0x2;
const int OPEN_EXISTING = 0x3;
2022-03-18 01:32:22 +00:00
static readonly IntPtr _invalidHandleValue = new(-1);
2022-03-06 13:29:38 +00:00
const int IOCTL_GET_HCD_DRIVERKEY_NAME = 0x220424;
const int IOCTL_USB_GET_ROOT_HUB_NAME = 0x220408;
const int IOCTL_USB_GET_NODE_INFORMATION = 0x220408; // same as above... strange, eh?
const int IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX = 0x220448;
const int IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION = 0x220410;
const int IOCTL_USB_GET_NODE_CONNECTION_NAME = 0x220414;
const int IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME = 0x220420;
const int USB_DEVICE_DESCRIPTOR_TYPE = 0x1;
const int USB_CONFIGURATION_DESCRIPTOR_TYPE = 0x2;
const int USB_STRING_DESCRIPTOR_TYPE = 0x3;
const int BUFFER_SIZE = 2048;
const int MAXIMUM_USB_STRING_LENGTH = 255;
const string GUID_DEVINTERFACE_HUBCONTROLLER = "3abf6f2d-71c4-462a-8a92-1e6861e6af27";
const string REGSTR_KEY_USB = "USB";
const int DIGCF_PRESENT = 0x2;
const int DIGCF_ALLCLASSES = 0x4;
const int DIGCF_DEVICEINTERFACE = 0x10;
const int SPDRP_DRIVER = 0x9;
const int SPDRP_DEVICEDESC = 0x0;
const int REG_SZ = 1;
// ********************** Enumerations ************************
enum UsbHubNode
{
UsbHub, UsbMiParent
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
enum UsbConnectionStatus
{
NoDeviceConnected, DeviceConnected, DeviceFailedEnumeration,
DeviceGeneralFailure, DeviceCausedOvercurrent, DeviceNotEnoughPower,
DeviceNotEnoughBandwidth, DeviceHubNestedTooDeeply, DeviceInLegacyHub
2022-03-06 13:29:38 +00:00
}
2022-03-06 13:29:38 +00:00
enum UsbDeviceSpeed : byte
{
UsbLowSpeed, UsbFullSpeed, UsbHighSpeed
2022-03-06 13:29:38 +00:00
}
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
// ********************** Stuctures ************************
2022-03-06 13:29:38 +00:00
[StructLayout(LayoutKind.Sequential)]
struct SpDevinfoData
{
internal int cbSize;
internal readonly Guid ClassGuid;
internal readonly IntPtr DevInst;
internal readonly IntPtr Reserved;
}
2022-03-06 13:29:38 +00:00
[StructLayout(LayoutKind.Sequential)]
struct SpDeviceInterfaceData
{
internal int cbSize;
internal readonly Guid InterfaceClassGuid;
internal readonly int Flags;
internal readonly IntPtr Reserved;
}
2022-03-06 13:29:38 +00:00
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct SpDeviceInterfaceDetailData
{
internal int cbSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
internal readonly string DevicePath;
}
2022-03-06 13:29:38 +00:00
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct UsbHcdDriverkeyName
{
internal readonly int ActualLength;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
internal readonly string DriverKeyName;
}
2022-03-06 13:29:38 +00:00
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct UsbRootHubName
{
internal readonly int ActualLength;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
internal readonly string RootHubName;
}
2022-03-06 13:29:38 +00:00
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct UsbHubDescriptor
{
internal readonly byte bDescriptorLength;
internal readonly byte bDescriptorType;
internal readonly byte bNumberOfPorts;
internal readonly short wHubCharacteristics;
internal readonly byte bPowerOnToPowerGood;
internal readonly byte bHubControlCurrent;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
internal readonly byte[] bRemoveAndPowerMask;
}
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
[StructLayout(LayoutKind.Sequential)]
struct UsbHubInformation
{
internal readonly UsbHubDescriptor HubDescriptor;
internal readonly byte HubIsBusPowered;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
[StructLayout(LayoutKind.Sequential)]
struct UsbNodeInformation
{
internal int NodeType;
internal readonly UsbHubInformation HubInformation; // Yeah, I'm assuming we'll just use the first form
}
2022-03-06 13:29:38 +00:00
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct UsbNodeConnectionInformationEx
{
internal int ConnectionIndex;
internal readonly UsbDeviceDescriptor DeviceDescriptor;
internal readonly byte CurrentConfigurationValue;
internal readonly byte Speed;
internal readonly byte DeviceIsHub;
internal readonly short DeviceAddress;
internal readonly int NumberOfOpenPipes;
internal readonly int ConnectionStatus;
2022-03-06 13:29:38 +00:00
//internal IntPtr PipeList;
}
2022-03-06 13:29:38 +00:00
[StructLayout(LayoutKind.Sequential, Pack = 1), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
internal struct UsbDeviceDescriptor
{
internal byte bLength;
internal byte bDescriptorType;
internal short bcdUSB;
internal byte bDeviceClass;
internal byte bDeviceSubClass;
internal byte bDeviceProtocol;
internal byte bMaxPacketSize0;
internal short idVendor;
internal short idProduct;
internal short bcdDevice;
internal byte iManufacturer;
internal byte iProduct;
internal byte iSerialNumber;
internal byte bNumConfigurations;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct UsbStringDescriptor
{
internal readonly byte bLength;
internal readonly byte bDescriptorType;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAXIMUM_USB_STRING_LENGTH)]
internal readonly string bString;
}
[StructLayout(LayoutKind.Sequential)]
struct UsbSetupPacket
{
internal readonly byte bmRequest;
internal readonly byte bRequest;
internal short wValue;
internal short wIndex;
internal short wLength;
}
[StructLayout(LayoutKind.Sequential)]
struct UsbDescriptorRequest
{
internal int ConnectionIndex;
internal UsbSetupPacket SetupPacket;
//internal byte[] Data;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct UsbNodeConnectionName
{
internal int ConnectionIndex;
internal readonly int ActualLength;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
internal readonly string NodeName;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct UsbNodeConnectionDriverkeyName // Yes, this is the same as the structure above...
{
internal int ConnectionIndex;
internal readonly int ActualLength;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
internal readonly string DriverKeyName;
}
// ********************** API Definitions ************************
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
static extern IntPtr SetupDiGetClassDevs( // 1st form using a ClassGUID
ref Guid classGuid, int enumerator, IntPtr hwndParent, int flags);
[DllImport("setupapi.dll", CharSet = CharSet.Auto)] // 2nd form uses an Enumerator
static extern IntPtr SetupDiGetClassDevs(int classGuid, string enumerator, IntPtr hwndParent, int flags);
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool SetupDiEnumDeviceInterfaces(IntPtr deviceInfoSet, IntPtr deviceInfoData,
ref Guid interfaceClassGuid, int memberIndex,
ref SpDeviceInterfaceData deviceInterfaceData);
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr deviceInfoSet,
ref SpDeviceInterfaceData deviceInterfaceData,
ref SpDeviceInterfaceDetailData deviceInterfaceDetailData,
int deviceInterfaceDetailDataSize, ref int requiredSize,
ref SpDevinfoData deviceInfoData);
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool SetupDiGetDeviceRegistryProperty(IntPtr deviceInfoSet, ref SpDevinfoData deviceInfoData,
int iProperty, ref int propertyRegDataType,
IntPtr propertyBuffer, int propertyBufferSize,
ref int requiredSize);
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
2022-03-07 07:36:44 +00:00
static extern bool SetupDiEnumDeviceInfo(IntPtr deviceInfoSet, int memberIndex, ref SpDevinfoData deviceInfoData);
2022-03-06 13:29:38 +00:00
[DllImport("setupapi.dll", SetLastError = true)]
static extern bool SetupDiDestroyDeviceInfoList(IntPtr deviceInfoSet);
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool SetupDiGetDeviceInstanceId(IntPtr deviceInfoSet, ref SpDevinfoData deviceInfoData,
StringBuilder deviceInstanceId, int deviceInstanceIdSize,
out int requiredSize);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool DeviceIoControl(IntPtr hDevice, int dwIoControlCode, IntPtr lpInBuffer, int nInBufferSize,
IntPtr lpOutBuffer, int nOutBufferSize, out int lpBytesReturned,
IntPtr lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
2022-03-07 07:36:44 +00:00
IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes,
IntPtr hTemplateFile);
2022-03-06 13:29:38 +00:00
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CloseHandle(IntPtr hObject);
#endregion
2017-12-19 20:33:03 +00:00
}