2017-12-19 03:50:57 +00:00
|
|
|
|
// /***************************************************************************
|
|
|
|
|
|
// The Disc Image Chef
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
//
|
|
|
|
|
|
// 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
|
2017-12-20 02:08:37 +00:00
|
|
|
|
// it under the terms of the GNU Lesser General internal License as
|
2017-12-19 03:50:57 +00:00
|
|
|
|
// 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
|
2017-12-20 02:08:37 +00:00
|
|
|
|
// Lesser General internal License for more details.
|
2017-12-19 03:50:57 +00:00
|
|
|
|
//
|
|
|
|
|
|
// 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/>.
|
|
|
|
|
|
//
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
// Copyright © 2011-2018 Natalia Portillo
|
|
|
|
|
|
// ****************************************************************************/
|
|
|
|
|
|
|
2017-12-19 19:33:46 +00:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
|
using System.Text;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
2017-12-20 02:08:37 +00:00
|
|
|
|
// Copyright "Fort Hood TX", internal domain, 2007
|
2017-12-06 19:30:03 +00:00
|
|
|
|
namespace DiscImageChef.Devices.Windows
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
partial class Usb
|
2017-12-06 19:30:03 +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;
|
|
|
|
|
|
const int INVALID_HANDLE_VALUE = -1;
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
2017-12-06 20:38:10 +00:00
|
|
|
|
const int USB_CONFIGURATION_DESCRIPTOR_TYPE = 0x2;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
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 ************************
|
|
|
|
|
|
|
|
|
|
|
|
//typedef enum _USB_HUB_NODE {
|
|
|
|
|
|
// UsbHub,
|
|
|
|
|
|
// UsbMIParent
|
|
|
|
|
|
//} USB_HUB_NODE;
|
|
|
|
|
|
enum USB_HUB_NODE
|
|
|
|
|
|
{
|
|
|
|
|
|
UsbHub,
|
|
|
|
|
|
UsbMIParent
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef enum _USB_CONNECTION_STATUS {
|
|
|
|
|
|
// NoDeviceConnected,
|
|
|
|
|
|
// DeviceConnected,
|
|
|
|
|
|
// DeviceFailedEnumeration,
|
|
|
|
|
|
// DeviceGeneralFailure,
|
|
|
|
|
|
// DeviceCausedOvercurrent,
|
|
|
|
|
|
// DeviceNotEnoughPower,
|
|
|
|
|
|
// DeviceNotEnoughBandwidth,
|
|
|
|
|
|
// DeviceHubNestedTooDeeply,
|
|
|
|
|
|
// DeviceInLegacyHub
|
|
|
|
|
|
//} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS;
|
|
|
|
|
|
enum USB_CONNECTION_STATUS
|
|
|
|
|
|
{
|
|
|
|
|
|
NoDeviceConnected,
|
|
|
|
|
|
DeviceConnected,
|
|
|
|
|
|
DeviceFailedEnumeration,
|
|
|
|
|
|
DeviceGeneralFailure,
|
|
|
|
|
|
DeviceCausedOvercurrent,
|
|
|
|
|
|
DeviceNotEnoughPower,
|
|
|
|
|
|
DeviceNotEnoughBandwidth,
|
|
|
|
|
|
DeviceHubNestedTooDeeply,
|
|
|
|
|
|
DeviceInLegacyHub
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef enum _USB_DEVICE_SPEED {
|
|
|
|
|
|
// UsbLowSpeed = 0,
|
|
|
|
|
|
// UsbFullSpeed,
|
|
|
|
|
|
// UsbHighSpeed
|
|
|
|
|
|
//} USB_DEVICE_SPEED;
|
|
|
|
|
|
enum USB_DEVICE_SPEED : byte
|
|
|
|
|
|
{
|
|
|
|
|
|
UsbLowSpeed,
|
|
|
|
|
|
UsbFullSpeed,
|
|
|
|
|
|
UsbHighSpeed
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ********************** Stuctures ************************
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _SP_DEVINFO_DATA {
|
|
|
|
|
|
// DWORD cbSize;
|
|
|
|
|
|
// GUID ClassGuid;
|
|
|
|
|
|
// DWORD DevInst;
|
|
|
|
|
|
// ULONG_PTR Reserved;
|
|
|
|
|
|
//} SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
|
|
|
|
struct SP_DEVINFO_DATA
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int cbSize;
|
|
|
|
|
|
internal Guid ClassGuid;
|
|
|
|
|
|
internal IntPtr DevInst;
|
|
|
|
|
|
internal IntPtr Reserved;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _SP_DEVICE_INTERFACE_DATA {
|
|
|
|
|
|
// DWORD cbSize;
|
|
|
|
|
|
// GUID InterfaceClassGuid;
|
|
|
|
|
|
// DWORD Flags;
|
|
|
|
|
|
// ULONG_PTR Reserved;
|
|
|
|
|
|
//} SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
|
|
|
|
struct SP_DEVICE_INTERFACE_DATA
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int cbSize;
|
|
|
|
|
|
internal Guid InterfaceClassGuid;
|
|
|
|
|
|
internal int Flags;
|
|
|
|
|
|
internal IntPtr Reserved;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA {
|
|
|
|
|
|
// DWORD cbSize;
|
|
|
|
|
|
// TCHAR DevicePath[ANYSIZE_ARRAY];
|
|
|
|
|
|
//} SP_DEVICE_INTERFACE_DETAIL_DATA, *PSP_DEVICE_INTERFACE_DETAIL_DATA;
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
|
|
|
|
|
struct SP_DEVICE_INTERFACE_DETAIL_DATA
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int cbSize;
|
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)] internal string DevicePath;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _USB_HCD_DRIVERKEY_NAME {
|
|
|
|
|
|
// ULONG ActualLength;
|
|
|
|
|
|
// WCHAR DriverKeyName[1];
|
|
|
|
|
|
//} USB_HCD_DRIVERKEY_NAME, *PUSB_HCD_DRIVERKEY_NAME;
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
|
|
|
|
|
struct USB_HCD_DRIVERKEY_NAME
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int ActualLength;
|
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)] internal string DriverKeyName;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _USB_ROOT_HUB_NAME {
|
|
|
|
|
|
// ULONG ActualLength;
|
|
|
|
|
|
// WCHAR RootHubName[1];
|
|
|
|
|
|
//} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME;
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
|
|
|
|
|
struct USB_ROOT_HUB_NAME
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int ActualLength;
|
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)] internal string RootHubName;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _USB_HUB_DESCRIPTOR {
|
|
|
|
|
|
// UCHAR bDescriptorLength;
|
|
|
|
|
|
// UCHAR bDescriptorType;
|
|
|
|
|
|
// UCHAR bNumberOfPorts;
|
|
|
|
|
|
// USHORT wHubCharacteristics;
|
|
|
|
|
|
// UCHAR bPowerOnToPowerGood;
|
|
|
|
|
|
// UCHAR bHubControlCurrent;
|
|
|
|
|
|
// UCHAR bRemoveAndPowerMask[64];
|
|
|
|
|
|
//} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR;
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
|
|
|
|
struct USB_HUB_DESCRIPTOR
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal byte bDescriptorLength;
|
|
|
|
|
|
internal byte bDescriptorType;
|
|
|
|
|
|
internal byte bNumberOfPorts;
|
|
|
|
|
|
internal short wHubCharacteristics;
|
|
|
|
|
|
internal byte bPowerOnToPowerGood;
|
|
|
|
|
|
internal byte bHubControlCurrent;
|
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] internal byte[] bRemoveAndPowerMask;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _USB_HUB_INFORMATION {
|
|
|
|
|
|
// USB_HUB_DESCRIPTOR HubDescriptor;
|
|
|
|
|
|
// BOOLEAN HubIsBusPowered;
|
|
|
|
|
|
//} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION;
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
|
|
|
|
struct USB_HUB_INFORMATION
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal USB_HUB_DESCRIPTOR HubDescriptor;
|
|
|
|
|
|
internal byte HubIsBusPowered;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _USB_NODE_INFORMATION {
|
|
|
|
|
|
// USB_HUB_NODE NodeType;
|
|
|
|
|
|
// union {
|
|
|
|
|
|
// USB_HUB_INFORMATION HubInformation;
|
|
|
|
|
|
// USB_MI_PARENT_INFORMATION MiParentInformation;
|
|
|
|
|
|
// } u;
|
|
|
|
|
|
//} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION;
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
|
|
|
|
struct USB_NODE_INFORMATION
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int NodeType;
|
|
|
|
|
|
internal USB_HUB_INFORMATION HubInformation; // Yeah, I'm assuming we'll just use the first form
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _USB_NODE_CONNECTION_INFORMATION_EX {
|
|
|
|
|
|
// ULONG ConnectionIndex;
|
|
|
|
|
|
// USB_DEVICE_DESCRIPTOR DeviceDescriptor;
|
|
|
|
|
|
// UCHAR CurrentConfigurationValue;
|
|
|
|
|
|
// UCHAR Speed;
|
|
|
|
|
|
// BOOLEAN DeviceIsHub;
|
|
|
|
|
|
// USHORT DeviceAddress;
|
|
|
|
|
|
// ULONG NumberOfOpenPipes;
|
|
|
|
|
|
// USB_CONNECTION_STATUS ConnectionStatus;
|
|
|
|
|
|
// USB_PIPE_INFO PipeList[0];
|
|
|
|
|
|
//} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX;
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
|
|
|
|
struct USB_NODE_CONNECTION_INFORMATION_EX
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int ConnectionIndex;
|
|
|
|
|
|
internal USB_DEVICE_DESCRIPTOR DeviceDescriptor;
|
|
|
|
|
|
internal byte CurrentConfigurationValue;
|
|
|
|
|
|
internal byte Speed;
|
|
|
|
|
|
internal byte DeviceIsHub;
|
|
|
|
|
|
internal short DeviceAddress;
|
|
|
|
|
|
internal int NumberOfOpenPipes;
|
|
|
|
|
|
|
|
|
|
|
|
internal int ConnectionStatus;
|
|
|
|
|
|
//internal IntPtr PipeList;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _USB_DEVICE_DESCRIPTOR {
|
|
|
|
|
|
// UCHAR bLength;
|
|
|
|
|
|
// UCHAR bDescriptorType;
|
|
|
|
|
|
// USHORT bcdUSB;
|
|
|
|
|
|
// UCHAR bDeviceClass;
|
|
|
|
|
|
// UCHAR bDeviceSubClass;
|
|
|
|
|
|
// UCHAR bDeviceProtocol;
|
|
|
|
|
|
// UCHAR bMaxPacketSize0;
|
|
|
|
|
|
// USHORT idVendor;
|
|
|
|
|
|
// USHORT idProduct;
|
|
|
|
|
|
// USHORT bcdDevice;
|
|
|
|
|
|
// UCHAR iManufacturer;
|
|
|
|
|
|
// UCHAR iProduct;
|
|
|
|
|
|
// UCHAR iSerialNumber;
|
|
|
|
|
|
// UCHAR bNumConfigurations;
|
|
|
|
|
|
//} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR ;
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
|
|
|
|
internal struct USB_DEVICE_DESCRIPTOR
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
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;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _USB_STRING_DESCRIPTOR {
|
|
|
|
|
|
// UCHAR bLength;
|
|
|
|
|
|
// UCHAR bDescriptorType;
|
|
|
|
|
|
// WCHAR bString[1];
|
|
|
|
|
|
//} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR;
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
|
|
|
|
|
struct USB_STRING_DESCRIPTOR
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal byte bLength;
|
|
|
|
|
|
internal byte bDescriptorType;
|
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAXIMUM_USB_STRING_LENGTH)] internal string bString;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _USB_DESCRIPTOR_REQUEST {
|
|
|
|
|
|
// ULONG ConnectionIndex;
|
|
|
|
|
|
// struct {
|
|
|
|
|
|
// UCHAR bmRequest;
|
|
|
|
|
|
// UCHAR bRequest;
|
|
|
|
|
|
// USHORT wValue;
|
|
|
|
|
|
// USHORT wIndex;
|
|
|
|
|
|
// USHORT wLength;
|
|
|
|
|
|
// } SetupPacket;
|
|
|
|
|
|
// UCHAR Data[0];
|
|
|
|
|
|
//} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
|
|
|
|
struct USB_SETUP_PACKET
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal byte bmRequest;
|
|
|
|
|
|
internal byte bRequest;
|
|
|
|
|
|
internal short wValue;
|
|
|
|
|
|
internal short wIndex;
|
|
|
|
|
|
internal short wLength;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
|
|
|
|
struct USB_DESCRIPTOR_REQUEST
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int ConnectionIndex;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal USB_SETUP_PACKET SetupPacket;
|
|
|
|
|
|
//internal byte[] Data;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _USB_NODE_CONNECTION_NAME {
|
|
|
|
|
|
// ULONG ConnectionIndex;
|
|
|
|
|
|
// ULONG ActualLength;
|
|
|
|
|
|
// WCHAR NodeName[1];
|
|
|
|
|
|
//} USB_NODE_CONNECTION_NAME, *PUSB_NODE_CONNECTION_NAME;
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
|
|
|
|
|
struct USB_NODE_CONNECTION_NAME
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int ConnectionIndex;
|
|
|
|
|
|
internal int ActualLength;
|
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)] internal string NodeName;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//typedef struct _USB_NODE_CONNECTION_DRIVERKEY_NAME {
|
|
|
|
|
|
// ULONG ConnectionIndex;
|
|
|
|
|
|
// ULONG ActualLength;
|
|
|
|
|
|
// WCHAR DriverKeyName[1];
|
|
|
|
|
|
//} USB_NODE_CONNECTION_DRIVERKEY_NAME, *PUSB_NODE_CONNECTION_DRIVERKEY_NAME;
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
|
|
|
|
|
struct USB_NODE_CONNECTION_DRIVERKEY_NAME // Yes, this is the same as the structure above...
|
|
|
|
|
|
{
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int ConnectionIndex;
|
|
|
|
|
|
internal int ActualLength;
|
|
|
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)] internal string DriverKeyName;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ********************** API Definitions ************************
|
|
|
|
|
|
|
|
|
|
|
|
//HDEVINFO SetupDiGetClassDevs(
|
|
|
|
|
|
// const GUID* ClassGuid,
|
|
|
|
|
|
// PCTSTR Enumerator,
|
|
|
|
|
|
// HWND hwndParent,
|
|
|
|
|
|
// DWORD Flags
|
|
|
|
|
|
//);
|
|
|
|
|
|
[DllImport("setupapi.dll", CharSet = CharSet.Auto)]
|
|
|
|
|
|
static extern IntPtr SetupDiGetClassDevs( // 1st form using a ClassGUID
|
2017-12-19 20:33:03 +00:00
|
|
|
|
ref Guid ClassGuid, int Enumerator, IntPtr hwndParent, int Flags);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
[DllImport("setupapi.dll", CharSet = CharSet.Auto)] // 2nd form uses an Enumerator
|
2017-12-19 20:33:03 +00:00
|
|
|
|
static extern IntPtr SetupDiGetClassDevs(int ClassGuid, string Enumerator, IntPtr hwndParent, int Flags);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
//BOOL SetupDiEnumDeviceInterfaces(
|
|
|
|
|
|
// HDEVINFO DeviceInfoSet,
|
|
|
|
|
|
// PSP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
|
// const GUID* InterfaceClassGuid,
|
|
|
|
|
|
// DWORD MemberIndex,
|
|
|
|
|
|
// PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
|
|
|
|
|
|
//);
|
|
|
|
|
|
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
2017-12-19 20:33:03 +00:00
|
|
|
|
static extern bool SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, IntPtr DeviceInfoData,
|
|
|
|
|
|
ref Guid InterfaceClassGuid, int MemberIndex,
|
|
|
|
|
|
ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
//BOOL SetupDiGetDeviceInterfaceDetail(
|
|
|
|
|
|
// HDEVINFO DeviceInfoSet,
|
|
|
|
|
|
// PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
|
|
|
|
|
|
// PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData,
|
|
|
|
|
|
// DWORD DeviceInterfaceDetailDataSize,
|
|
|
|
|
|
// PDWORD RequiredSize,
|
|
|
|
|
|
// PSP_DEVINFO_DATA DeviceInfoData
|
|
|
|
|
|
//);
|
|
|
|
|
|
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
2017-12-19 20:33:03 +00:00
|
|
|
|
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);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
//BOOL SetupDiGetDeviceRegistryProperty(
|
|
|
|
|
|
// HDEVINFO DeviceInfoSet,
|
|
|
|
|
|
// PSP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
|
// DWORD Property,
|
|
|
|
|
|
// PDWORD PropertyRegDataType,
|
|
|
|
|
|
// PBYTE PropertyBuffer,
|
|
|
|
|
|
// DWORD PropertyBufferSize,
|
|
|
|
|
|
// PDWORD RequiredSize
|
|
|
|
|
|
//);
|
|
|
|
|
|
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
2017-12-19 20:33:03 +00:00
|
|
|
|
static extern bool SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
|
int iProperty, ref int PropertyRegDataType,
|
|
|
|
|
|
IntPtr PropertyBuffer, int PropertyBufferSize,
|
|
|
|
|
|
ref int RequiredSize);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
//BOOL SetupDiEnumDeviceInfo(
|
|
|
|
|
|
// HDEVINFO DeviceInfoSet,
|
|
|
|
|
|
// DWORD MemberIndex,
|
|
|
|
|
|
// PSP_DEVINFO_DATA DeviceInfoData
|
|
|
|
|
|
//);
|
|
|
|
|
|
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
2017-12-19 20:33:03 +00:00
|
|
|
|
static extern bool SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, int MemberIndex,
|
|
|
|
|
|
ref SP_DEVINFO_DATA DeviceInfoData);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
//BOOL SetupDiDestroyDeviceInfoList(
|
|
|
|
|
|
// HDEVINFO DeviceInfoSet
|
|
|
|
|
|
//);
|
|
|
|
|
|
[DllImport("setupapi.dll", SetLastError = true)]
|
2017-12-19 20:33:03 +00:00
|
|
|
|
static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
//WINSETUPAPI BOOL WINAPI SetupDiGetDeviceInstanceId(
|
|
|
|
|
|
// IN HDEVINFO DeviceInfoSet,
|
|
|
|
|
|
// IN PSP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
|
// OUT PTSTR DeviceInstanceId,
|
|
|
|
|
|
// IN DWORD DeviceInstanceIdSize,
|
|
|
|
|
|
// OUT PDWORD RequiredSize OPTIONAL
|
|
|
|
|
|
//);
|
|
|
|
|
|
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
2017-12-19 20:33:03 +00:00
|
|
|
|
static extern bool SetupDiGetDeviceInstanceId(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData,
|
|
|
|
|
|
StringBuilder DeviceInstanceId, int DeviceInstanceIdSize,
|
|
|
|
|
|
out int RequiredSize);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
//BOOL DeviceIoControl(
|
|
|
|
|
|
// HANDLE hDevice,
|
|
|
|
|
|
// DWORD dwIoControlCode,
|
|
|
|
|
|
// LPVOID lpInBuffer,
|
|
|
|
|
|
// DWORD nInBufferSize,
|
|
|
|
|
|
// LPVOID lpOutBuffer,
|
|
|
|
|
|
// DWORD nOutBufferSize,
|
|
|
|
|
|
// LPDWORD lpBytesReturned,
|
|
|
|
|
|
// LPOVERLAPPED lpOverlapped
|
|
|
|
|
|
//);
|
|
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
2017-12-19 20:33:03 +00:00
|
|
|
|
static extern bool DeviceIoControl(IntPtr hDevice, int dwIoControlCode, IntPtr lpInBuffer, int nInBufferSize,
|
|
|
|
|
|
IntPtr lpOutBuffer, int nOutBufferSize, out int lpBytesReturned,
|
|
|
|
|
|
IntPtr lpOverlapped);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
//HANDLE CreateFile(
|
|
|
|
|
|
// LPCTSTR lpFileName,
|
|
|
|
|
|
// DWORD dwDesiredAccess,
|
|
|
|
|
|
// DWORD dwShareMode,
|
|
|
|
|
|
// LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
|
|
|
|
|
// DWORD dwCreationDisposition,
|
|
|
|
|
|
// DWORD dwFlagsAndAttributes,
|
|
|
|
|
|
// HANDLE hTemplateFile
|
|
|
|
|
|
//);
|
|
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
2017-12-19 20:33:03 +00:00
|
|
|
|
static extern IntPtr CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
|
|
|
|
|
|
IntPtr lpSecurityAttributes, int dwCreationDisposition,
|
|
|
|
|
|
int dwFlagsAndAttributes, IntPtr hTemplateFile);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
//BOOL CloseHandle(
|
|
|
|
|
|
// HANDLE hObject
|
|
|
|
|
|
//);
|
|
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
2017-12-19 20:33:03 +00:00
|
|
|
|
static extern bool CloseHandle(IntPtr hObject);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
// Return a list of USB Host Controllers
|
|
|
|
|
|
//
|
2017-12-20 02:08:37 +00:00
|
|
|
|
static internal System.Collections.ObjectModel.ReadOnlyCollection<USBController> GetHostControllers()
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
List<USBController> HostList = new List<USBController>();
|
|
|
|
|
|
Guid HostGUID = new Guid(GUID_DEVINTERFACE_HUBCONTROLLER);
|
|
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
if(h.ToInt32() != INVALID_HANDLE_VALUE)
|
|
|
|
|
|
{
|
|
|
|
|
|
IntPtr ptrBuf = Marshal.AllocHGlobal(BUFFER_SIZE);
|
|
|
|
|
|
bool Success;
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
do
|
|
|
|
|
|
{
|
|
|
|
|
|
USBController host = new USBController();
|
|
|
|
|
|
host.ControllerIndex = i;
|
|
|
|
|
|
|
|
|
|
|
|
// create a Device Interface Data structure
|
|
|
|
|
|
SP_DEVICE_INTERFACE_DATA dia = new SP_DEVICE_INTERFACE_DATA();
|
|
|
|
|
|
dia.cbSize = Marshal.SizeOf(dia);
|
|
|
|
|
|
|
|
|
|
|
|
// start the enumeration
|
|
|
|
|
|
Success = SetupDiEnumDeviceInterfaces(h, IntPtr.Zero, ref HostGUID, i, ref dia);
|
|
|
|
|
|
if(Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
// build a DevInfo Data structure
|
|
|
|
|
|
SP_DEVINFO_DATA da = new SP_DEVINFO_DATA();
|
|
|
|
|
|
da.cbSize = Marshal.SizeOf(da);
|
|
|
|
|
|
|
|
|
|
|
|
// build a Device Interface Detail Data structure
|
|
|
|
|
|
SP_DEVICE_INTERFACE_DETAIL_DATA didd = new SP_DEVICE_INTERFACE_DETAIL_DATA();
|
|
|
|
|
|
didd.cbSize = 4 + Marshal.SystemDefaultCharSize; // trust me :)
|
|
|
|
|
|
|
|
|
|
|
|
// now we can get some more detailed information
|
|
|
|
|
|
int nRequiredSize = 0;
|
|
|
|
|
|
int nBytes = BUFFER_SIZE;
|
|
|
|
|
|
if(SetupDiGetDeviceInterfaceDetail(h, ref dia, ref didd, nBytes, ref nRequiredSize, ref da))
|
|
|
|
|
|
{
|
|
|
|
|
|
host.ControllerDevicePath = didd.DevicePath;
|
|
|
|
|
|
|
|
|
|
|
|
// get the Device Description and DriverKeyName
|
|
|
|
|
|
int RequiredSize = 0;
|
|
|
|
|
|
int RegType = REG_SZ;
|
|
|
|
|
|
|
|
|
|
|
|
if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DEVICEDESC, ref RegType, ptrBuf,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
BUFFER_SIZE, ref RequiredSize))
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
host.ControllerDeviceDesc = Marshal.PtrToStringAuto(ptrBuf);
|
|
|
|
|
|
}
|
|
|
|
|
|
if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DRIVER, ref RegType, ptrBuf,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
BUFFER_SIZE, ref RequiredSize))
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
host.ControllerDriverKeyName = Marshal.PtrToStringAuto(ptrBuf);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
HostList.Add(host);
|
|
|
|
|
|
}
|
|
|
|
|
|
i++;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
while(Success);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
Marshal.FreeHGlobal(ptrBuf);
|
|
|
|
|
|
SetupDiDestroyDeviceInfoList(h);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// convert it into a Collection
|
|
|
|
|
|
return new System.Collections.ObjectModel.ReadOnlyCollection<USBController>(HostList);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
// The USB Host Controller Class
|
|
|
|
|
|
//
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal class USBController
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
internal int ControllerIndex;
|
|
|
|
|
|
internal string ControllerDriverKeyName, ControllerDevicePath, ControllerDeviceDesc;
|
|
|
|
|
|
|
|
|
|
|
|
// A simple default constructor
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal USBController()
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
ControllerIndex = 0;
|
|
|
|
|
|
ControllerDevicePath = "";
|
|
|
|
|
|
ControllerDeviceDesc = "";
|
|
|
|
|
|
ControllerDriverKeyName = "";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return the index of the instance
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int Index
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return ControllerIndex; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return the Device Path, such as "\\?\pci#ven_10de&dev_005a&subsys_815a1043&rev_a2#3&267a616a&0&58#{3abf6f2d-71c4-462a-8a92-1e6861e6af27}"
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string DevicePath
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return ControllerDevicePath; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// The DriverKeyName may be useful as a search key
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string DriverKeyName
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return ControllerDriverKeyName; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return the Friendly Name, such as "VIA USB Enhanced Host Controller"
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string Name
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return ControllerDeviceDesc; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return Root Hub for this Controller
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal USBHub GetRootHub()
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
IntPtr h, h2;
|
|
|
|
|
|
USBHub Root = new USBHub();
|
|
|
|
|
|
Root.HubIsRootHub = true;
|
|
|
|
|
|
Root.HubDeviceDesc = "Root Hub";
|
|
|
|
|
|
|
|
|
|
|
|
// Open a handle to the Host Controller
|
|
|
|
|
|
h = CreateFile(ControllerDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
IntPtr.Zero);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
if(h.ToInt32() != INVALID_HANDLE_VALUE)
|
|
|
|
|
|
{
|
|
|
|
|
|
int nBytesReturned;
|
|
|
|
|
|
USB_ROOT_HUB_NAME HubName = new USB_ROOT_HUB_NAME();
|
|
|
|
|
|
int nBytes = Marshal.SizeOf(HubName);
|
|
|
|
|
|
IntPtr ptrHubName = Marshal.AllocHGlobal(nBytes);
|
|
|
|
|
|
|
|
|
|
|
|
// get the Hub Name
|
|
|
|
|
|
if(DeviceIoControl(h, IOCTL_USB_GET_ROOT_HUB_NAME, ptrHubName, nBytes, ptrHubName, nBytes,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
out nBytesReturned, IntPtr.Zero))
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
HubName = (USB_ROOT_HUB_NAME)Marshal.PtrToStructure(ptrHubName, typeof(USB_ROOT_HUB_NAME));
|
|
|
|
|
|
Root.HubDevicePath = @"\\.\" + HubName.RootHubName;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: Get DriverKeyName for Root Hub
|
|
|
|
|
|
|
|
|
|
|
|
// Now let's open the Hub (based upon the HubName we got above)
|
|
|
|
|
|
h2 = CreateFile(Root.HubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
IntPtr.Zero);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
if(h2.ToInt32() != INVALID_HANDLE_VALUE)
|
|
|
|
|
|
{
|
|
|
|
|
|
USB_NODE_INFORMATION NodeInfo = new USB_NODE_INFORMATION();
|
|
|
|
|
|
NodeInfo.NodeType = (int)USB_HUB_NODE.UsbHub;
|
|
|
|
|
|
nBytes = Marshal.SizeOf(NodeInfo);
|
|
|
|
|
|
IntPtr ptrNodeInfo = Marshal.AllocHGlobal(nBytes);
|
|
|
|
|
|
Marshal.StructureToPtr(NodeInfo, ptrNodeInfo, true);
|
|
|
|
|
|
|
|
|
|
|
|
// get the Hub Information
|
|
|
|
|
|
if(DeviceIoControl(h2, IOCTL_USB_GET_NODE_INFORMATION, ptrNodeInfo, nBytes, ptrNodeInfo, nBytes,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
out nBytesReturned, IntPtr.Zero))
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
NodeInfo = (USB_NODE_INFORMATION)Marshal.PtrToStructure(ptrNodeInfo,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
typeof(USB_NODE_INFORMATION));
|
2017-12-06 19:30:03 +00:00
|
|
|
|
Root.HubIsBusPowered = Convert.ToBoolean(NodeInfo.HubInformation.HubIsBusPowered);
|
|
|
|
|
|
Root.HubPortCount = NodeInfo.HubInformation.HubDescriptor.bNumberOfPorts;
|
|
|
|
|
|
}
|
|
|
|
|
|
Marshal.FreeHGlobal(ptrNodeInfo);
|
|
|
|
|
|
CloseHandle(h2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Marshal.FreeHGlobal(ptrHubName);
|
|
|
|
|
|
CloseHandle(h);
|
|
|
|
|
|
}
|
|
|
|
|
|
return Root;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
// The Hub class
|
|
|
|
|
|
//
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal class USBHub
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
internal int HubPortCount;
|
|
|
|
|
|
internal string HubDriverKey, HubDevicePath, HubDeviceDesc;
|
|
|
|
|
|
internal string HubManufacturer, HubProduct, HubSerialNumber, HubInstanceID;
|
|
|
|
|
|
internal bool HubIsBusPowered, HubIsRootHub;
|
|
|
|
|
|
|
|
|
|
|
|
// a simple default constructor
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal USBHub()
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
HubPortCount = 0;
|
|
|
|
|
|
HubDevicePath = "";
|
|
|
|
|
|
HubDeviceDesc = "";
|
|
|
|
|
|
HubDriverKey = "";
|
|
|
|
|
|
HubIsBusPowered = false;
|
|
|
|
|
|
HubIsRootHub = false;
|
|
|
|
|
|
HubManufacturer = "";
|
|
|
|
|
|
HubProduct = "";
|
|
|
|
|
|
HubSerialNumber = "";
|
|
|
|
|
|
HubInstanceID = "";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// return Port Count
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int PortCount
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return HubPortCount; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// return the Device Path, such as "\\?\pci#ven_10de&dev_005a&subsys_815a1043&rev_a2#3&267a616a&0&58#{3abf6f2d-71c4-462a-8a92-1e6861e6af27}"
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string DevicePath
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return HubDevicePath; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// The DriverKey may be useful as a search key
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string DriverKey
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return HubDriverKey; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// return the Friendly Name, such as "VIA USB Enhanced Host Controller"
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string Name
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return HubDeviceDesc; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// the device path of this device
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string InstanceID
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return HubInstanceID; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// is is this a self-powered hub?
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal bool IsBusPowered
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return HubIsBusPowered; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// is this a root hub?
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal bool IsRootHub
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return HubIsRootHub; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string Manufacturer
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return HubManufacturer; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string Product
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return HubProduct; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string SerialNumber
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return HubSerialNumber; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// return a list of the down stream ports
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal System.Collections.ObjectModel.ReadOnlyCollection<USBPort> GetPorts()
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
List<USBPort> PortList = new List<USBPort>();
|
|
|
|
|
|
|
|
|
|
|
|
// Open a handle to the Hub device
|
|
|
|
|
|
IntPtr h = CreateFile(HubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
IntPtr.Zero);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
if(h.ToInt32() != INVALID_HANDLE_VALUE)
|
|
|
|
|
|
{
|
|
|
|
|
|
int nBytes = Marshal.SizeOf(typeof(USB_NODE_CONNECTION_INFORMATION_EX));
|
|
|
|
|
|
IntPtr ptrNodeConnection = Marshal.AllocHGlobal(nBytes);
|
|
|
|
|
|
|
|
|
|
|
|
// loop thru all of the ports on the hub
|
|
|
|
|
|
// BTW: Ports are numbered starting at 1
|
|
|
|
|
|
for(int i = 1; i <= HubPortCount; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
int nBytesReturned;
|
|
|
|
|
|
USB_NODE_CONNECTION_INFORMATION_EX NodeConnection = new USB_NODE_CONNECTION_INFORMATION_EX();
|
|
|
|
|
|
NodeConnection.ConnectionIndex = i;
|
|
|
|
|
|
Marshal.StructureToPtr(NodeConnection, ptrNodeConnection, true);
|
|
|
|
|
|
|
|
|
|
|
|
if(DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, ptrNodeConnection, nBytes,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
ptrNodeConnection, nBytes, out nBytesReturned, IntPtr.Zero))
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
NodeConnection =
|
|
|
|
|
|
(USB_NODE_CONNECTION_INFORMATION_EX)Marshal.PtrToStructure(ptrNodeConnection,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
typeof(
|
|
|
|
|
|
USB_NODE_CONNECTION_INFORMATION_EX
|
|
|
|
|
|
));
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
// load up the USBPort class
|
|
|
|
|
|
USBPort port = new USBPort();
|
|
|
|
|
|
port.PortPortNumber = i;
|
|
|
|
|
|
port.PortHubDevicePath = HubDevicePath;
|
|
|
|
|
|
USB_CONNECTION_STATUS Status = (USB_CONNECTION_STATUS)NodeConnection.ConnectionStatus;
|
|
|
|
|
|
port.PortStatus = Status.ToString();
|
|
|
|
|
|
USB_DEVICE_SPEED Speed = (USB_DEVICE_SPEED)NodeConnection.Speed;
|
|
|
|
|
|
port.PortSpeed = Speed.ToString();
|
|
|
|
|
|
port.PortIsDeviceConnected =
|
|
|
|
|
|
(NodeConnection.ConnectionStatus == (int)USB_CONNECTION_STATUS.DeviceConnected);
|
|
|
|
|
|
port.PortIsHub = Convert.ToBoolean(NodeConnection.DeviceIsHub);
|
|
|
|
|
|
port.PortDeviceDescriptor = NodeConnection.DeviceDescriptor;
|
|
|
|
|
|
|
|
|
|
|
|
// add it to the list
|
|
|
|
|
|
PortList.Add(port);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-06 19:30:03 +00:00
|
|
|
|
Marshal.FreeHGlobal(ptrNodeConnection);
|
|
|
|
|
|
CloseHandle(h);
|
|
|
|
|
|
}
|
|
|
|
|
|
// convert it into a Collection
|
|
|
|
|
|
return new System.Collections.ObjectModel.ReadOnlyCollection<USBPort>(PortList);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
// The Port Class
|
|
|
|
|
|
//
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal class USBPort
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
internal int PortPortNumber;
|
|
|
|
|
|
internal string PortStatus, PortHubDevicePath, PortSpeed;
|
|
|
|
|
|
internal bool PortIsHub, PortIsDeviceConnected;
|
|
|
|
|
|
internal USB_DEVICE_DESCRIPTOR PortDeviceDescriptor;
|
|
|
|
|
|
|
|
|
|
|
|
// a simple default constructor
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal USBPort()
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
PortPortNumber = 0;
|
|
|
|
|
|
PortStatus = "";
|
|
|
|
|
|
PortHubDevicePath = "";
|
|
|
|
|
|
PortSpeed = "";
|
|
|
|
|
|
PortIsHub = false;
|
|
|
|
|
|
PortIsDeviceConnected = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// return Port Index of the Hub
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int PortNumber
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return PortPortNumber; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// return the Device Path of the Hub
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string HubDevicePath
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return PortHubDevicePath; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// the status (see USB_CONNECTION_STATUS above)
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string Status
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return PortStatus; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// the speed of the connection (see USB_DEVICE_SPEED above)
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string Speed
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return PortSpeed; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// is this a downstream external hub?
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal bool IsHub
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return PortIsHub; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// is anybody home?
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal bool IsDeviceConnected
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return PortIsDeviceConnected; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// return a down stream external hub
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal USBDevice GetDevice()
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
2017-12-19 20:33:03 +00:00
|
|
|
|
if(!PortIsDeviceConnected) { return null; }
|
|
|
|
|
|
|
2017-12-06 19:30:03 +00:00
|
|
|
|
USBDevice Device = new USBDevice();
|
|
|
|
|
|
|
|
|
|
|
|
// Copy over some values from the Port class
|
|
|
|
|
|
// Ya know, I've given some thought about making Device a derived class...
|
|
|
|
|
|
Device.DevicePortNumber = PortPortNumber;
|
|
|
|
|
|
Device.DeviceHubDevicePath = PortHubDevicePath;
|
|
|
|
|
|
Device.DeviceDescriptor = PortDeviceDescriptor;
|
|
|
|
|
|
|
|
|
|
|
|
// Open a handle to the Hub device
|
|
|
|
|
|
IntPtr h = CreateFile(PortHubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
IntPtr.Zero);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
if(h.ToInt32() != INVALID_HANDLE_VALUE)
|
|
|
|
|
|
{
|
|
|
|
|
|
int nBytesReturned;
|
|
|
|
|
|
int nBytes = BUFFER_SIZE;
|
|
|
|
|
|
// We use this to zero fill a buffer
|
|
|
|
|
|
string NullString = new string((char)0, BUFFER_SIZE / Marshal.SystemDefaultCharSize);
|
|
|
|
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
|
|
|
|
if(PortDeviceDescriptor.iManufacturer > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// build a request for string descriptor
|
|
|
|
|
|
USB_DESCRIPTOR_REQUEST Request = new USB_DESCRIPTOR_REQUEST();
|
|
|
|
|
|
Request.ConnectionIndex = PortPortNumber;
|
|
|
|
|
|
Request.SetupPacket.wValue =
|
|
|
|
|
|
(short)((USB_STRING_DESCRIPTOR_TYPE << 8) + PortDeviceDescriptor.iManufacturer);
|
|
|
|
|
|
Request.SetupPacket.wLength = (short)(nBytes - Marshal.SizeOf(Request));
|
|
|
|
|
|
Request.SetupPacket.wIndex = 0x409; // Language Code
|
|
|
|
|
|
// 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,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
ptrRequest, nBytes, out nBytesReturned, IntPtr.Zero))
|
2017-12-06 19:30:03 +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
|
|
|
|
|
|
IntPtr ptrStringDesc = new IntPtr(ptrRequest.ToInt32() + Marshal.SizeOf(Request));
|
|
|
|
|
|
USB_STRING_DESCRIPTOR StringDesc =
|
|
|
|
|
|
(USB_STRING_DESCRIPTOR)Marshal.PtrToStructure(ptrStringDesc,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
typeof(USB_STRING_DESCRIPTOR));
|
2017-12-06 19:30:03 +00:00
|
|
|
|
Device.DeviceManufacturer = StringDesc.bString;
|
|
|
|
|
|
}
|
|
|
|
|
|
Marshal.FreeHGlobal(ptrRequest);
|
|
|
|
|
|
}
|
|
|
|
|
|
if(PortDeviceDescriptor.iProduct > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// build a request for string descriptor
|
|
|
|
|
|
USB_DESCRIPTOR_REQUEST Request = new USB_DESCRIPTOR_REQUEST();
|
|
|
|
|
|
Request.ConnectionIndex = PortPortNumber;
|
|
|
|
|
|
Request.SetupPacket.wValue =
|
|
|
|
|
|
(short)((USB_STRING_DESCRIPTOR_TYPE << 8) + PortDeviceDescriptor.iProduct);
|
|
|
|
|
|
Request.SetupPacket.wLength = (short)(nBytes - Marshal.SizeOf(Request));
|
|
|
|
|
|
Request.SetupPacket.wIndex = 0x409; // Language Code
|
|
|
|
|
|
// 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,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
ptrRequest, nBytes, out nBytesReturned, IntPtr.Zero))
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
// the location of the string descriptor is immediately after the Request structure
|
|
|
|
|
|
IntPtr ptrStringDesc = new IntPtr(ptrRequest.ToInt32() + Marshal.SizeOf(Request));
|
|
|
|
|
|
USB_STRING_DESCRIPTOR StringDesc =
|
|
|
|
|
|
(USB_STRING_DESCRIPTOR)Marshal.PtrToStructure(ptrStringDesc,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
typeof(USB_STRING_DESCRIPTOR));
|
2017-12-06 19:30:03 +00:00
|
|
|
|
Device.DeviceProduct = StringDesc.bString;
|
|
|
|
|
|
}
|
|
|
|
|
|
Marshal.FreeHGlobal(ptrRequest);
|
|
|
|
|
|
}
|
|
|
|
|
|
if(PortDeviceDescriptor.iSerialNumber > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// build a request for string descriptor
|
|
|
|
|
|
USB_DESCRIPTOR_REQUEST Request = new USB_DESCRIPTOR_REQUEST();
|
|
|
|
|
|
Request.ConnectionIndex = PortPortNumber;
|
|
|
|
|
|
Request.SetupPacket.wValue =
|
|
|
|
|
|
(short)((USB_STRING_DESCRIPTOR_TYPE << 8) + PortDeviceDescriptor.iSerialNumber);
|
|
|
|
|
|
Request.SetupPacket.wLength = (short)(nBytes - Marshal.SizeOf(Request));
|
|
|
|
|
|
Request.SetupPacket.wIndex = 0x409; // Language Code
|
|
|
|
|
|
// 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,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
ptrRequest, nBytes, out nBytesReturned, IntPtr.Zero))
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
// the location of the string descriptor is immediately after the Request structure
|
|
|
|
|
|
IntPtr ptrStringDesc = new IntPtr(ptrRequest.ToInt32() + Marshal.SizeOf(Request));
|
|
|
|
|
|
USB_STRING_DESCRIPTOR StringDesc =
|
|
|
|
|
|
(USB_STRING_DESCRIPTOR)Marshal.PtrToStructure(ptrStringDesc,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
typeof(USB_STRING_DESCRIPTOR));
|
2017-12-06 19:30:03 +00:00
|
|
|
|
Device.DeviceSerialNumber = StringDesc.bString;
|
|
|
|
|
|
}
|
|
|
|
|
|
Marshal.FreeHGlobal(ptrRequest);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-06 20:38:10 +00:00
|
|
|
|
// build a request for configuration descriptor
|
|
|
|
|
|
USB_DESCRIPTOR_REQUEST dcrRequest = new USB_DESCRIPTOR_REQUEST();
|
|
|
|
|
|
dcrRequest.ConnectionIndex = PortPortNumber;
|
|
|
|
|
|
dcrRequest.SetupPacket.wValue = (short)((USB_CONFIGURATION_DESCRIPTOR_TYPE << 8));
|
|
|
|
|
|
dcrRequest.SetupPacket.wLength = (short)(nBytes - Marshal.SizeOf(dcrRequest));
|
2017-12-19 20:33:03 +00:00
|
|
|
|
dcrRequest.SetupPacket.wIndex = 0;
|
2017-12-06 20:38:10 +00:00
|
|
|
|
// Geez, I wish C# had a Marshal.MemSet() method
|
|
|
|
|
|
IntPtr dcrPtrRequest = Marshal.StringToHGlobalAuto(NullString);
|
|
|
|
|
|
Marshal.StructureToPtr(dcrRequest, dcrPtrRequest, true);
|
|
|
|
|
|
|
|
|
|
|
|
// Use an IOCTL call to request the String Descriptor
|
|
|
|
|
|
if(DeviceIoControl(h, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, dcrPtrRequest, nBytes,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
dcrPtrRequest, nBytes, out nBytesReturned, IntPtr.Zero))
|
2017-12-06 20:38:10 +00:00
|
|
|
|
{
|
|
|
|
|
|
IntPtr ptrStringDesc = new IntPtr(dcrPtrRequest.ToInt32() + Marshal.SizeOf(dcrRequest));
|
|
|
|
|
|
Device.BinaryDeviceDescriptors = new byte[nBytesReturned];
|
|
|
|
|
|
Marshal.Copy(ptrStringDesc, Device.BinaryDeviceDescriptors, 0, nBytesReturned);
|
|
|
|
|
|
}
|
|
|
|
|
|
Marshal.FreeHGlobal(dcrPtrRequest);
|
|
|
|
|
|
|
2017-12-06 19:30:03 +00:00
|
|
|
|
// Get the Driver Key Name (usefull in locating a device)
|
|
|
|
|
|
USB_NODE_CONNECTION_DRIVERKEY_NAME DriverKey = new USB_NODE_CONNECTION_DRIVERKEY_NAME();
|
|
|
|
|
|
DriverKey.ConnectionIndex = PortPortNumber;
|
|
|
|
|
|
nBytes = Marshal.SizeOf(DriverKey);
|
|
|
|
|
|
IntPtr ptrDriverKey = Marshal.AllocHGlobal(nBytes);
|
|
|
|
|
|
Marshal.StructureToPtr(DriverKey, ptrDriverKey, true);
|
|
|
|
|
|
|
|
|
|
|
|
// Use an IOCTL call to request the Driver Key Name
|
|
|
|
|
|
if(DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, ptrDriverKey, nBytes,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
ptrDriverKey, nBytes, out nBytesReturned, IntPtr.Zero))
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
DriverKey = (USB_NODE_CONNECTION_DRIVERKEY_NAME)Marshal.PtrToStructure(ptrDriverKey,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
typeof(
|
|
|
|
|
|
USB_NODE_CONNECTION_DRIVERKEY_NAME
|
|
|
|
|
|
));
|
2017-12-06 19:30:03 +00:00
|
|
|
|
Device.DeviceDriverKey = DriverKey.DriverKeyName;
|
|
|
|
|
|
|
|
|
|
|
|
// use the DriverKeyName to get the Device Description and Instance ID
|
|
|
|
|
|
Device.DeviceName = GetDescriptionByKeyName(Device.DeviceDriverKey);
|
|
|
|
|
|
Device.DeviceInstanceID = GetInstanceIDByKeyName(Device.DeviceDriverKey);
|
|
|
|
|
|
}
|
|
|
|
|
|
Marshal.FreeHGlobal(ptrDriverKey);
|
|
|
|
|
|
CloseHandle(h);
|
|
|
|
|
|
}
|
|
|
|
|
|
return Device;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// return a down stream external hub
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal USBHub GetHub()
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
2017-12-19 20:33:03 +00:00
|
|
|
|
if(!PortIsHub) { return null; }
|
|
|
|
|
|
|
2017-12-06 19:30:03 +00:00
|
|
|
|
USBHub Hub = new USBHub();
|
|
|
|
|
|
IntPtr h, h2;
|
|
|
|
|
|
Hub.HubIsRootHub = false;
|
|
|
|
|
|
Hub.HubDeviceDesc = "External Hub";
|
|
|
|
|
|
|
|
|
|
|
|
// Open a handle to the Host Controller
|
|
|
|
|
|
h = CreateFile(PortHubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
IntPtr.Zero);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
if(h.ToInt32() != INVALID_HANDLE_VALUE)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Get the DevicePath for downstream hub
|
|
|
|
|
|
int nBytesReturned;
|
|
|
|
|
|
USB_NODE_CONNECTION_NAME NodeName = new USB_NODE_CONNECTION_NAME();
|
|
|
|
|
|
NodeName.ConnectionIndex = PortPortNumber;
|
|
|
|
|
|
int nBytes = Marshal.SizeOf(NodeName);
|
|
|
|
|
|
IntPtr ptrNodeName = Marshal.AllocHGlobal(nBytes);
|
|
|
|
|
|
Marshal.StructureToPtr(NodeName, ptrNodeName, true);
|
|
|
|
|
|
|
|
|
|
|
|
// Use an IOCTL call to request the Node Name
|
|
|
|
|
|
if(DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_NAME, ptrNodeName, nBytes, ptrNodeName, nBytes,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
out nBytesReturned, IntPtr.Zero))
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
NodeName = (USB_NODE_CONNECTION_NAME)Marshal.PtrToStructure(ptrNodeName,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
typeof(USB_NODE_CONNECTION_NAME));
|
2017-12-06 19:30:03 +00:00
|
|
|
|
Hub.HubDevicePath = @"\\.\" + NodeName.NodeName;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Now let's open the Hub (based upon the HubName we got above)
|
|
|
|
|
|
h2 = CreateFile(Hub.HubDevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
IntPtr.Zero);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
if(h2.ToInt32() != INVALID_HANDLE_VALUE)
|
|
|
|
|
|
{
|
|
|
|
|
|
USB_NODE_INFORMATION NodeInfo = new USB_NODE_INFORMATION();
|
|
|
|
|
|
NodeInfo.NodeType = (int)USB_HUB_NODE.UsbHub;
|
|
|
|
|
|
nBytes = Marshal.SizeOf(NodeInfo);
|
|
|
|
|
|
IntPtr ptrNodeInfo = Marshal.AllocHGlobal(nBytes);
|
|
|
|
|
|
Marshal.StructureToPtr(NodeInfo, ptrNodeInfo, true);
|
|
|
|
|
|
|
|
|
|
|
|
// get the Hub Information
|
|
|
|
|
|
if(DeviceIoControl(h2, IOCTL_USB_GET_NODE_INFORMATION, ptrNodeInfo, nBytes, ptrNodeInfo, nBytes,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
out nBytesReturned, IntPtr.Zero))
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
NodeInfo = (USB_NODE_INFORMATION)Marshal.PtrToStructure(ptrNodeInfo,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
typeof(USB_NODE_INFORMATION));
|
2017-12-06 19:30:03 +00:00
|
|
|
|
Hub.HubIsBusPowered = Convert.ToBoolean(NodeInfo.HubInformation.HubIsBusPowered);
|
|
|
|
|
|
Hub.HubPortCount = NodeInfo.HubInformation.HubDescriptor.bNumberOfPorts;
|
|
|
|
|
|
}
|
|
|
|
|
|
Marshal.FreeHGlobal(ptrNodeInfo);
|
|
|
|
|
|
CloseHandle(h2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Fill in the missing Manufacture, Product, and SerialNumber values
|
|
|
|
|
|
// values by just creating a Device instance and copying the values
|
|
|
|
|
|
USBDevice Device = GetDevice();
|
|
|
|
|
|
Hub.HubInstanceID = Device.DeviceInstanceID;
|
|
|
|
|
|
Hub.HubManufacturer = Device.Manufacturer;
|
|
|
|
|
|
Hub.HubProduct = Device.Product;
|
|
|
|
|
|
Hub.HubSerialNumber = Device.SerialNumber;
|
|
|
|
|
|
Hub.HubDriverKey = Device.DriverKey;
|
|
|
|
|
|
|
|
|
|
|
|
Marshal.FreeHGlobal(ptrNodeName);
|
|
|
|
|
|
CloseHandle(h);
|
|
|
|
|
|
}
|
|
|
|
|
|
return Hub;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
// The USB Device Class
|
|
|
|
|
|
//
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal class USBDevice
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
internal int DevicePortNumber;
|
|
|
|
|
|
internal string DeviceDriverKey, DeviceHubDevicePath, DeviceInstanceID, DeviceName;
|
|
|
|
|
|
internal string DeviceManufacturer, DeviceProduct, DeviceSerialNumber;
|
|
|
|
|
|
internal USB_DEVICE_DESCRIPTOR DeviceDescriptor;
|
2017-12-06 20:38:10 +00:00
|
|
|
|
internal byte[] BinaryDeviceDescriptors;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
// a simple default constructor
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal USBDevice()
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
DevicePortNumber = 0;
|
|
|
|
|
|
DeviceHubDevicePath = "";
|
|
|
|
|
|
DeviceDriverKey = "";
|
|
|
|
|
|
DeviceManufacturer = "";
|
|
|
|
|
|
DeviceProduct = "Unknown USB Device";
|
|
|
|
|
|
DeviceSerialNumber = "";
|
|
|
|
|
|
DeviceName = "";
|
|
|
|
|
|
DeviceInstanceID = "";
|
2017-12-06 20:38:10 +00:00
|
|
|
|
BinaryDeviceDescriptors = null;
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// return Port Index of the Hub
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal int PortNumber
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return DevicePortNumber; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// return the Device Path of the Hub (the parent device)
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string HubDevicePath
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return DeviceHubDevicePath; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// useful as a search key
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string DriverKey
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return DeviceDriverKey; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// the device path of this device
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string InstanceID
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return DeviceInstanceID; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// the friendly name
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string Name
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return DeviceName; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string Manufacturer
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return DeviceManufacturer; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string Product
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return DeviceProduct; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal string SerialNumber
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return DeviceSerialNumber; }
|
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-20 02:08:37 +00:00
|
|
|
|
internal byte[] BinaryDescriptors
|
2017-12-06 20:38:10 +00:00
|
|
|
|
{
|
|
|
|
|
|
get { return BinaryDeviceDescriptors; }
|
|
|
|
|
|
}
|
2017-12-06 19:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
// private function for finding a USB device's Description
|
|
|
|
|
|
//
|
|
|
|
|
|
static string GetDescriptionByKeyName(string DriverKeyName)
|
|
|
|
|
|
{
|
|
|
|
|
|
string ans = "";
|
|
|
|
|
|
string DevEnum = REGSTR_KEY_USB;
|
|
|
|
|
|
|
|
|
|
|
|
// Use the "enumerator form" of the SetupDiGetClassDevs API
|
|
|
|
|
|
// to generate a list of all USB devices
|
|
|
|
|
|
IntPtr h = SetupDiGetClassDevs(0, DevEnum, IntPtr.Zero, DIGCF_PRESENT | DIGCF_ALLCLASSES);
|
|
|
|
|
|
if(h.ToInt32() != INVALID_HANDLE_VALUE)
|
|
|
|
|
|
{
|
|
|
|
|
|
IntPtr ptrBuf = Marshal.AllocHGlobal(BUFFER_SIZE);
|
|
|
|
|
|
string KeyName;
|
|
|
|
|
|
|
|
|
|
|
|
bool Success;
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
do
|
|
|
|
|
|
{
|
|
|
|
|
|
// create a Device Interface Data structure
|
|
|
|
|
|
SP_DEVINFO_DATA da = new SP_DEVINFO_DATA();
|
|
|
|
|
|
da.cbSize = Marshal.SizeOf(da);
|
|
|
|
|
|
|
|
|
|
|
|
// start the enumeration
|
|
|
|
|
|
Success = SetupDiEnumDeviceInfo(h, i, ref da);
|
|
|
|
|
|
if(Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
int RequiredSize = 0;
|
|
|
|
|
|
int RegType = REG_SZ;
|
|
|
|
|
|
KeyName = "";
|
|
|
|
|
|
|
|
|
|
|
|
if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DRIVER, ref RegType, ptrBuf, BUFFER_SIZE,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
ref RequiredSize))
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
KeyName = Marshal.PtrToStringAuto(ptrBuf);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// is it a match?
|
|
|
|
|
|
if(KeyName == DriverKeyName)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DEVICEDESC, ref RegType, ptrBuf,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
BUFFER_SIZE, ref RequiredSize))
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
ans = Marshal.PtrToStringAuto(ptrBuf);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-06 19:30:03 +00:00
|
|
|
|
i++;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
while(Success);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
Marshal.FreeHGlobal(ptrBuf);
|
|
|
|
|
|
SetupDiDestroyDeviceInfoList(h);
|
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-06 19:30:03 +00:00
|
|
|
|
return ans;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
// private function for finding a USB device's Instance ID
|
|
|
|
|
|
//
|
|
|
|
|
|
static string GetInstanceIDByKeyName(string DriverKeyName)
|
|
|
|
|
|
{
|
|
|
|
|
|
string ans = "";
|
|
|
|
|
|
string DevEnum = REGSTR_KEY_USB;
|
|
|
|
|
|
|
|
|
|
|
|
// Use the "enumerator form" of the SetupDiGetClassDevs API
|
|
|
|
|
|
// to generate a list of all USB devices
|
|
|
|
|
|
IntPtr h = SetupDiGetClassDevs(0, DevEnum, IntPtr.Zero, DIGCF_PRESENT | DIGCF_ALLCLASSES);
|
|
|
|
|
|
if(h.ToInt32() != INVALID_HANDLE_VALUE)
|
|
|
|
|
|
{
|
|
|
|
|
|
IntPtr ptrBuf = Marshal.AllocHGlobal(BUFFER_SIZE);
|
|
|
|
|
|
string KeyName;
|
|
|
|
|
|
|
|
|
|
|
|
bool Success;
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
do
|
|
|
|
|
|
{
|
|
|
|
|
|
// create a Device Interface Data structure
|
|
|
|
|
|
SP_DEVINFO_DATA da = new SP_DEVINFO_DATA();
|
|
|
|
|
|
da.cbSize = Marshal.SizeOf(da);
|
|
|
|
|
|
|
|
|
|
|
|
// start the enumeration
|
|
|
|
|
|
Success = SetupDiEnumDeviceInfo(h, i, ref da);
|
|
|
|
|
|
if(Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
int RequiredSize = 0;
|
|
|
|
|
|
int RegType = REG_SZ;
|
|
|
|
|
|
|
|
|
|
|
|
KeyName = "";
|
|
|
|
|
|
if(SetupDiGetDeviceRegistryProperty(h, ref da, SPDRP_DRIVER, ref RegType, ptrBuf, BUFFER_SIZE,
|
2017-12-19 20:33:03 +00:00
|
|
|
|
ref RequiredSize))
|
2017-12-06 19:30:03 +00:00
|
|
|
|
{
|
|
|
|
|
|
KeyName = Marshal.PtrToStringAuto(ptrBuf);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// is it a match?
|
|
|
|
|
|
if(KeyName == DriverKeyName)
|
|
|
|
|
|
{
|
|
|
|
|
|
int nBytes = BUFFER_SIZE;
|
|
|
|
|
|
StringBuilder sb = new StringBuilder(nBytes);
|
|
|
|
|
|
SetupDiGetDeviceInstanceId(h, ref da, sb, nBytes, out RequiredSize);
|
|
|
|
|
|
ans = sb.ToString();
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-06 19:30:03 +00:00
|
|
|
|
i++;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
while(Success);
|
2017-12-06 19:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
Marshal.FreeHGlobal(ptrBuf);
|
|
|
|
|
|
SetupDiDestroyDeviceInfoList(h);
|
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2017-12-06 19:30:03 +00:00
|
|
|
|
return ans;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|