changeset 63:309c705d7460

Updates and cleanup in Windows USB enumeration code
author Ivo Smits <Ivo@UCIS.nl>
date Sun, 13 Oct 2013 18:43:45 +0200
parents edc41c861d96
children 99ed461509fe
files USBLib/Internal/Windows/SetupApi.cs USBLib/Internal/Windows/UsbApi.cs USBLib/Windows/Devices/DeviceNode.cs USBLib/Windows/USB/UsbController.cs USBLib/Windows/USB/UsbDevice.cs USBLib/Windows/USB/UsbHub.cs
diffstat 6 files changed, 203 insertions(+), 191 deletions(-) [+]
line wrap: on
line diff
--- a/USBLib/Internal/Windows/SetupApi.cs	Sun Oct 13 02:47:08 2013 +0200
+++ b/USBLib/Internal/Windows/SetupApi.cs	Sun Oct 13 18:43:45 2013 +0200
@@ -412,5 +412,6 @@
 		LEGACYBUSTYPE = 0x00000015,
 		BUSNUMBER = 0x00000016,
 		ENUMERATOR_NAME = 0x00000017,
+		ADDRESS = 0x0000001D,
 	}
-}
\ No newline at end of file
+}
--- a/USBLib/Internal/Windows/UsbApi.cs	Sun Oct 13 02:47:08 2013 +0200
+++ b/USBLib/Internal/Windows/UsbApi.cs	Sun Oct 13 18:43:45 2013 +0200
@@ -27,8 +27,6 @@
 		public const int DICS_DISABLE = 0x00000002;
 	}
 
-	#region enumerations
-
 	enum UsbDeviceClass : byte {
 		UnspecifiedDevice = 0x00,
 		AudioInterface = 0x01,
@@ -54,12 +52,6 @@
 	enum HubCharacteristics : byte {
 		GangedPowerSwitching = 0x00,
 		IndividualPotPowerSwitching = 0x01,
-		// to do
-	}
-
-	enum USB_HUB_NODE {
-		UsbHub,
-		UsbMIParent
 	}
 
 	enum USB_CONNECTION_STATUS : int {
@@ -100,8 +92,6 @@
 		HighSpeed = 0x0400,
 		TestMode = 0x0800,
 		Indicator = 0x1000,
-		// these are the bits which cause the hub port state machine to keep moving 
-		//kHubPortStateChangeMask = kHubPortConnection | kHubPortEnabled | kHubPortSuspend | kHubPortOverCurrent | kHubPortBeingReset 
 	}
 
 	enum HubStatus : byte {
@@ -125,10 +115,6 @@
 		SetPowerOn = 1
 	}
 
-	#endregion
-
-	#region structures
-
 	[StructLayout(LayoutKind.Sequential)]
 	struct SP_CLASSINSTALL_HEADER {
 		public int cbSize;
@@ -143,18 +129,18 @@
 		public int HwProfile;
 	}
 
-	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
 	struct USB_HCD_DRIVERKEY_NAME {
-		public uint ActualLength;
+		public UInt32 ActualLength;
 		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = UsbApi.MAX_BUFFER_SIZE)]
-		public string DriverKeyName; //WCHAR DriverKeyName[1];
+		public String DriverKeyName;
 	}
 
-	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
 	struct USB_ROOT_HUB_NAME {
-		public uint ActualLength;
+		public UInt32 ActualLength;
 		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = UsbApi.MAX_BUFFER_SIZE)]
-		public string RootHubName; //WCHAR  RootHubName[1];
+		public String RootHubName;
 	}
 
 	[StructLayout(LayoutKind.Sequential, Pack = 1)]
@@ -177,9 +163,8 @@
 
 	[StructLayout(LayoutKind.Sequential)]
 	struct USB_NODE_INFORMATION {
-		//public int NodeType;
-		public USB_HUB_NODE NodeType;
-		public USB_HUB_INFORMATION HubInformation; // union { USB_HUB_INFORMATION  HubInformation; USB_MI_PARENT_INFORMATION  MiParentInformation; }
+		public int NodeType;
+		public USB_HUB_INFORMATION HubInformation;
 	}
 
 	[StructLayout(LayoutKind.Sequential, Pack = 1)]
@@ -225,7 +210,7 @@
 		public uint ConnectionIndex;
 		public uint ActualLength;
 		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = UsbApi.MAX_BUFFER_SIZE)]
-		public string NodeName; //WCHAR  NodeName[1];
+		public string NodeName;
 	}
 
 	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
@@ -233,7 +218,7 @@
 		public uint ConnectionIndex;
 		public uint ActualLength;
 		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = UsbApi.MAX_BUFFER_SIZE)]
-		public string DriverKeyName; //WCHAR  DriverKeyName[1];
+		public string DriverKeyName;
 	}
 
 	[StructLayout(LayoutKind.Sequential)]
@@ -242,5 +227,4 @@
 		public uint DeviceNumber;
 		public uint PartitionNumber;
 	}
-	#endregion
 }
--- a/USBLib/Windows/Devices/DeviceNode.cs	Sun Oct 13 02:47:08 2013 +0200
+++ b/USBLib/Windows/Devices/DeviceNode.cs	Sun Oct 13 18:43:45 2013 +0200
@@ -244,6 +244,7 @@
 		public String PhysicalDeviceObjectName { get { return GetPropertyString(CMRDP.PHYSICAL_DEVICE_OBJECT_NAME); } }
 		public Guid? BusTypeGuid { get { return SetupApi.GetAsGuid(GetProperty(CMRDP.BUSTYPEGUID)); } }
 		public Int32? BusNumber { get { return SetupApi.GetAsInt32(GetProperty(CMRDP.BUSNUMBER)); } }
+		public Int32? Address { get { return SetupApi.GetAsInt32(GetProperty(CMRDP.ADDRESS)); } }
 		public String EnumeratorName { get { return GetPropertyString(CMRDP.ENUMERATOR_NAME); } }
 
 		public String[] GetInterfaces(String classGuid) {
--- a/USBLib/Windows/USB/UsbController.cs	Sun Oct 13 02:47:08 2013 +0200
+++ b/USBLib/Windows/USB/UsbController.cs	Sun Oct 13 18:43:45 2013 +0200
@@ -1,21 +1,26 @@
 using System;
 using System.Collections.Generic;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
 using Microsoft.Win32.SafeHandles;
 using UCIS.HWLib.Windows.Devices;
 using UCIS.USBLib.Internal.Windows;
 
 namespace UCIS.HWLib.Windows.USB {
 	public class UsbController {
-		static readonly Guid IID_DEVINTERFACE_USB_HOST_CONTROLLER = new Guid(UsbApi.GUID_DEVINTERFACE_USB_HOST_CONTROLLER);
 		public String DevicePath { get; private set; }
 		public DeviceNode DeviceNode { get; private set; }
 		public String DeviceDescription { get { return DeviceNode.DeviceDescription; } }
 		public String DriverKey { get { return DeviceNode.DriverKey; } }
 		public UsbHub RootHub {
 			get {
-				String rootHubName;
-				using (SafeFileHandle handle = UsbHub.OpenHandle(DevicePath)) rootHubName = UsbHub.GetRootHubName(handle);
-				return new UsbHub(null, new USB_NODE_CONNECTION_INFORMATION_EX(), @"\\?\" + rootHubName, 0, true);
+				USB_ROOT_HUB_NAME rootHubName = new USB_ROOT_HUB_NAME();
+				int nBytesReturned;
+				using (SafeFileHandle handle = UsbHub.OpenHandle(DevicePath))
+					if (!Kernel32.DeviceIoControl(handle, UsbApi.IOCTL_USB_GET_ROOT_HUB_NAME, IntPtr.Zero, 0, out rootHubName, Marshal.SizeOf(rootHubName), out nBytesReturned, IntPtr.Zero))
+						throw new Win32Exception(Marshal.GetLastWin32Error());
+				if (rootHubName.ActualLength <= 0) return null;
+				return new UsbHub(null, @"\\?\" + rootHubName.RootHubName, 0);
 			}
 		}
 		private UsbController(DeviceNode di, String devicePath) {
@@ -23,7 +28,9 @@
 			this.DevicePath = devicePath;
 		}
 
+		static readonly Guid IID_DEVINTERFACE_USB_HOST_CONTROLLER = new Guid(UsbApi.GUID_DEVINTERFACE_USB_HOST_CONTROLLER);
 		public static UsbController GetControllerForDeviceNode(DeviceNode node) {
+			if (node == null) return null;
 			String[] interfaces = node.GetInterfaces(IID_DEVINTERFACE_USB_HOST_CONTROLLER);
 			if (interfaces == null || interfaces.Length == 0) return null;
 			return new UsbController(node, interfaces[0]);
--- a/USBLib/Windows/USB/UsbDevice.cs	Sun Oct 13 02:47:08 2013 +0200
+++ b/USBLib/Windows/USB/UsbDevice.cs	Sun Oct 13 18:43:45 2013 +0200
@@ -9,86 +9,41 @@
 
 namespace UCIS.HWLib.Windows.USB {
 	public class UsbDevice : IUsbDevice, IUsbInterface {
-		protected internal static SafeFileHandle OpenHandle(String path) {
-			SafeFileHandle handle = Kernel32.CreateFile(path, Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_WRITE, IntPtr.Zero, Kernel32.OPEN_EXISTING, 0, IntPtr.Zero);
-			if (handle.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error());
-			return handle;
-		}
-		internal static Boolean GetNodeInformation(SafeFileHandle handle, out USB_NODE_INFORMATION nodeInfo) {
-			nodeInfo = new USB_NODE_INFORMATION();
-			int nBytes = Marshal.SizeOf(typeof(USB_NODE_INFORMATION));
-			return Kernel32.DeviceIoControl(handle, UsbApi.IOCTL_USB_GET_NODE_INFORMATION, ref nodeInfo, nBytes, out nodeInfo, nBytes, out nBytes, IntPtr.Zero);
-		}
-		internal static Boolean GetNodeConnectionInformation(SafeFileHandle handle, UInt32 port, out USB_NODE_CONNECTION_INFORMATION_EX nodeConnection) {
+		internal static USB_NODE_CONNECTION_INFORMATION_EX GetNodeConnectionInformation(SafeFileHandle handle, UInt32 port) {
 			int nBytes = Marshal.SizeOf(typeof(USB_NODE_CONNECTION_INFORMATION_EX));
-			nodeConnection = new USB_NODE_CONNECTION_INFORMATION_EX();
+			USB_NODE_CONNECTION_INFORMATION_EX nodeConnection = new USB_NODE_CONNECTION_INFORMATION_EX();
 			nodeConnection.ConnectionIndex = port;
 			if (!Kernel32.DeviceIoControl(handle, UsbApi.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, ref nodeConnection, nBytes, out nodeConnection, nBytes, out nBytes, IntPtr.Zero))
 				throw new Win32Exception(Marshal.GetLastWin32Error());
-			return true;
-		}
-		protected static String GetNodeConnectionName(SafeFileHandle handle, UInt32 port) {
-			int nBytes = Marshal.SizeOf(typeof(USB_NODE_CONNECTION_NAME));
-			USB_NODE_CONNECTION_NAME nameConnection = new USB_NODE_CONNECTION_NAME();
-			nameConnection.ConnectionIndex = port;
-			if (!Kernel32.DeviceIoControl(handle, UsbApi.IOCTL_USB_GET_NODE_CONNECTION_NAME, ref nameConnection, nBytes, out nameConnection, nBytes, out nBytes, IntPtr.Zero))
-				throw new Win32Exception(Marshal.GetLastWin32Error());
-			return nameConnection.NodeName;
-		}
-		protected unsafe static int GetDescriptor(SafeFileHandle handle, UInt32 port, byte descriptorType, byte index, short langId, byte[] buffer, int offset, int length) {
-			int szRequest = Marshal.SizeOf(typeof(USB_DESCRIPTOR_REQUEST));
-			USB_DESCRIPTOR_REQUEST request = new USB_DESCRIPTOR_REQUEST();
-			request.ConnectionIndex = port;
-			request.SetupPacket.Value = (short)((descriptorType << 8) + index);
-			request.SetupPacket.Index = (short)langId;
-			request.SetupPacket.Length = (short)length;
-			int nBytes = length + szRequest;
-			Byte[] bigbuffer = new Byte[nBytes];
-			if (!Kernel32.DeviceIoControl(handle, UsbApi.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ref request, Marshal.SizeOf(typeof(USB_DESCRIPTOR_REQUEST)), bigbuffer, nBytes, out nBytes, IntPtr.Zero)) {
-				int err = Marshal.GetLastWin32Error();
-				if (err != 2 && err != 31 && err != 87) throw new Win32Exception(err);
-				return 0;
-			}
-			nBytes -= szRequest;
-			if (nBytes > length) nBytes = length;
-			if (nBytes < 0) return 0;
-			if (nBytes > 0) Buffer.BlockCopy(bigbuffer, szRequest, buffer, offset, nBytes);
-			return nBytes;
-		}
-		protected internal unsafe static String GetRootHubName(SafeFileHandle handle) {
-			USB_ROOT_HUB_NAME rootHubName = new USB_ROOT_HUB_NAME();
-			int nBytesReturned;
-			if (!Kernel32.DeviceIoControl(handle, UsbApi.IOCTL_USB_GET_ROOT_HUB_NAME, IntPtr.Zero, 0, out rootHubName, Marshal.SizeOf(rootHubName), out nBytesReturned, IntPtr.Zero))
-				throw new Win32Exception(Marshal.GetLastWin32Error());
-			if (rootHubName.ActualLength <= 0) return null;
-			return rootHubName.RootHubName;
-		}
-		protected unsafe static String GetNodeConnectionDriverKey(SafeFileHandle handle, UInt32 port) {
-			USB_NODE_CONNECTION_DRIVERKEY_NAME DriverKeyStruct = new USB_NODE_CONNECTION_DRIVERKEY_NAME();
-			int nBytes = Marshal.SizeOf(DriverKeyStruct);
-			DriverKeyStruct.ConnectionIndex = port;
-			if (!Kernel32.DeviceIoControl(handle, UsbApi.IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, ref DriverKeyStruct, nBytes, out DriverKeyStruct, nBytes, out nBytes, IntPtr.Zero))
-				return null;
-			return DriverKeyStruct.DriverKeyName;
+			return nodeConnection;
 		}
 
-		public UsbDevice Parent { get; protected set; }
-		public String DevicePath { get; private set; }
-		public UInt32 AdapterNumber { get; private set; }
-		internal USB_NODE_CONNECTION_INFORMATION_EX NodeConnectionInfo { get; set; }
-		public UsbDeviceDescriptor DeviceDescriptor { get { return NodeConnectionInfo.DeviceDescriptor; } }
+		private Boolean HasNodeConnectionInfo = false;
+		private USB_NODE_CONNECTION_INFORMATION_EX NodeConnectionInfo;
 
-		public bool IsHub { get { return NodeConnectionInfo.DeviceIsHub != 0; } }
-		public bool IsConnected { get { return NodeConnectionInfo.ConnectionStatus == USB_CONNECTION_STATUS.DeviceConnected; } }
-		public string Status { get { return NodeConnectionInfo.ConnectionStatus.ToString(); } }
-		public string Speed { get { return NodeConnectionInfo.Speed.ToString(); } }
-		public Byte CurrentConfigurationValue { get { return NodeConnectionInfo.CurrentConfigurationValue; } }
-		public UInt16 DeviceAddress { get { return NodeConnectionInfo.DeviceAddress; } }
-		public UInt32 NumberOfOpenPipes { get { return NodeConnectionInfo.NumberOfOpenPipes; } }
+		private void GetNodeConnectionInfo() {
+			if (HasNodeConnectionInfo) return;
+			if (Parent == null) {
+				HasNodeConnectionInfo = true;
+				return;
+			}
+			using (SafeFileHandle handle = Parent.OpenHandle()) NodeConnectionInfo = GetNodeConnectionInformation(handle, AdapterNumber);
+			HasNodeConnectionInfo = true;
+		}
+		internal void SetNodeConnectionInfo(USB_NODE_CONNECTION_INFORMATION_EX nci) {
+			NodeConnectionInfo = nci;
+			HasNodeConnectionInfo = true;
+		}
 
-		SafeFileHandle OpenHandle() {
-			return OpenHandle(DevicePath);
-		}
+		public UsbDeviceDescriptor DeviceDescriptor { get { GetNodeConnectionInfo(); return NodeConnectionInfo.DeviceDescriptor; } }
+
+		public bool IsHub { get { GetNodeConnectionInfo(); return NodeConnectionInfo.DeviceIsHub != 0; } }
+		public bool IsConnected { get { GetNodeConnectionInfo(); return NodeConnectionInfo.ConnectionStatus == USB_CONNECTION_STATUS.DeviceConnected; } }
+		public string Status { get { GetNodeConnectionInfo(); return NodeConnectionInfo.ConnectionStatus.ToString(); } }
+		public string Speed { get { GetNodeConnectionInfo(); return NodeConnectionInfo.Speed.ToString(); } }
+		public Byte CurrentConfigurationValue { get { GetNodeConnectionInfo(); return NodeConnectionInfo.CurrentConfigurationValue; } }
+		public UInt16 DeviceAddress { get { GetNodeConnectionInfo(); return NodeConnectionInfo.DeviceAddress; } }
+		public UInt32 NumberOfOpenPipes { get { GetNodeConnectionInfo(); return NodeConnectionInfo.NumberOfOpenPipes; } }
 
 		public int NumConfigurations { get { return DeviceDescriptor.NumConfigurations; } }
 		public int VendorID { get { return DeviceDescriptor.VendorID; } }
@@ -96,7 +51,7 @@
 
 		private String GetStringSafe(Byte id) {
 			if (id == 0) return null;
-			String s = GetStringDescriptor(id);
+			String s = GetString(id, 0);
 			if (s == null) return s;
 			return s.Trim(' ', '\0');
 		}
@@ -104,12 +59,27 @@
 		public string Manufacturer { get { return GetStringSafe(DeviceDescriptor.ManufacturerStringID); } }
 		public string Product { get { return GetStringSafe(DeviceDescriptor.ProductStringID); } }
 		public string SerialNumber { get { return GetStringSafe(DeviceDescriptor.SerialNumberStringID); } }
-		public virtual string DriverKey { get { using (SafeFileHandle handle = OpenHandle(DevicePath)) return UsbHub.GetNodeConnectionDriverKey(handle, AdapterNumber); } }
+		public String DriverKey {
+			get {
+				if (mParent != null) {
+					using (SafeFileHandle handle = mParent.OpenHandle()) {
+						USB_NODE_CONNECTION_DRIVERKEY_NAME DriverKeyStruct = new USB_NODE_CONNECTION_DRIVERKEY_NAME();
+						int nBytes = Marshal.SizeOf(DriverKeyStruct);
+						DriverKeyStruct.ConnectionIndex = AdapterNumber;
+						if (!Kernel32.DeviceIoControl(handle, UsbApi.IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, ref DriverKeyStruct, nBytes, out DriverKeyStruct, nBytes, out nBytes, IntPtr.Zero))
+							return null;
+						return DriverKeyStruct.DriverKeyName;
+					}
+				}
+				if (mDeviceNode != null) return mDeviceNode.DriverKey;
+				return null;
+			}
+		}
 
 		public virtual string DeviceDescription { get { return DeviceNode == null ? null : DeviceNode.DeviceDescription; } }
 		public string DeviceID { get { return DeviceNode == null ? null : DeviceNode.DeviceID; } }
 
-		private DeviceNode mDeviceNode;
+		protected DeviceNode mDeviceNode = null;
 		public DeviceNode DeviceNode {
 			get {
 				String dk = DriverKey;
@@ -124,57 +94,69 @@
 				return mDeviceNode;
 			}
 		}
+		protected UsbHub mParent = null;
+		private UInt32 mAdapterNumber = 0;
+		private UsbHub GetParent() {
+			if (mParent == null && mDeviceNode != null) {
+				mParent = UsbHub.GetHubForDeviceNode(mDeviceNode.GetParent());
+				if (mParent != null) {
+					UsbDevice self = mParent.FindChildForDeviceNode(mDeviceNode);
+					if (self != null) mAdapterNumber = self.AdapterNumber;
+				}
+			}
+			return mParent;
+		}
+		public UsbHub Parent { get { return GetParent(); } }
+		public UInt32 AdapterNumber { get { GetParent(); return mAdapterNumber; } }
 
-		internal UsbDevice(UsbDevice parent, USB_NODE_CONNECTION_INFORMATION_EX nci, uint port, string devicePath) {
-			this.Parent = parent;
-			this.NodeConnectionInfo = nci;
-			this.DevicePath = devicePath;
-			this.AdapterNumber = port;
-			if (devicePath == null) return;
+		internal UsbDevice(DeviceNode devnode, UsbHub parent, uint port) {
+			this.mDeviceNode = devnode;
+			this.mParent = parent;
+			this.mAdapterNumber = port;
 		}
 
-		private String GetStringDescriptor(Byte index) {
-			return UsbStringDescriptor.GetStringFromDevice(this, index, 0); //0x409
-		}
-
-		static UsbDevice GetUsbDevice(DeviceNode node, out Boolean isHostController) {
-			UsbController controller = UsbController.GetControllerForDeviceNode(node);
-			if (controller != null) {
-				isHostController = true;
-				return controller.RootHub;
-			}
-			isHostController = false;
+		public static UsbDevice GetUsbDevice(DeviceNode node) {
+			if (node == null) return null;
+			//UsbController controller = UsbController.GetControllerForDeviceNode(node);
+			//if (controller != null) return controller;
+			UsbHub hub = UsbHub.GetHubForDeviceNode(node);
+			if (hub != null) return hub;
 			DeviceNode parent = node.GetParent();
 			if (parent == null) return null;
-			Boolean isHostControllerA;
-			UsbDevice usbdev = GetUsbDevice(parent, out isHostControllerA);
-			if (isHostControllerA) return usbdev;
-			UsbHub usbhub = usbdev as UsbHub;
-			if (usbhub == null) {
-				if (parent.Service == "usbccgp") return usbdev;
-				return null;
-			}
-			String driverkey = node.DriverKey;
-			if (driverkey == null) return null;
-			foreach (UsbDevice child in usbhub.Devices) {
-				if (driverkey.Equals(child.DriverKey, StringComparison.InvariantCultureIgnoreCase)) return child;
-			}
-			return null;
-		}
-		public static UsbDevice GetUsbDevice(DeviceNode node) {
-			Boolean isHostController;
-			return GetUsbDevice(node, out isHostController);
+			if (parent.Service == "usbccgp") return GetUsbDevice(parent);
+			hub = UsbHub.GetHubForDeviceNode(parent);
+			if (hub == null) return null;
+			return hub.FindChildForDeviceNode(node);
 		}
 
-		#region IUsbInterface Members
+		#region IUsbInterface and IUsbDevice Members
+		public int GetDescriptor(byte descriptorType, byte index, short langId, byte[] buffer, int offset, int length) {
+			using (SafeFileHandle handle = Parent.OpenHandle()) {
+				int szRequest = Marshal.SizeOf(typeof(USB_DESCRIPTOR_REQUEST));
+				USB_DESCRIPTOR_REQUEST request = new USB_DESCRIPTOR_REQUEST();
+				request.ConnectionIndex = AdapterNumber;
+				request.SetupPacket.Value = (short)((descriptorType << 8) + index);
+				request.SetupPacket.Index = (short)langId;
+				request.SetupPacket.Length = (short)length;
+				int nBytes = length + szRequest;
+				Byte[] bigbuffer = new Byte[nBytes];
+				if (!Kernel32.DeviceIoControl(handle, UsbApi.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ref request, Marshal.SizeOf(typeof(USB_DESCRIPTOR_REQUEST)), bigbuffer, nBytes, out nBytes, IntPtr.Zero)) {
+					int err = Marshal.GetLastWin32Error();
+					if (err != 2 && err != 31 && err != 87) throw new Win32Exception(err);
+					return 0;
+				}
+				nBytes -= szRequest;
+				if (nBytes > length) nBytes = length;
+				if (nBytes < 0) return 0;
+				if (nBytes > 0) Buffer.BlockCopy(bigbuffer, szRequest, buffer, offset, nBytes);
+				return nBytes;
+			}
+		}
+		public String GetString(short langId, byte stringIndex) {
+			return UsbStringDescriptor.GetStringFromDevice(this, stringIndex, langId);
+		}
 		byte IUsbInterface.Configuration { get { throw new NotImplementedException(); } }
 		void IUsbInterface.Close() { }
-		public virtual int GetDescriptor(byte descriptorType, byte index, short langId, byte[] buffer, int offset, int length) {
-			using (SafeFileHandle handle = UsbHub.OpenHandle(DevicePath)) return UsbHub.GetDescriptor(handle, AdapterNumber, descriptorType, index, langId, buffer, offset, length);
-		}
-		string IUsbInterface.GetString(short langId, byte stringIndex) {
-			return UsbStringDescriptor.GetStringFromDevice(this, stringIndex, langId);
-		}
 		int IUsbInterface.BulkWrite(byte endpoint, byte[] buffer, int offset, int length) { throw new NotImplementedException(); }
 		int IUsbInterface.BulkRead(byte endpoint, byte[] buffer, int offset, int length) { throw new NotImplementedException(); }
 		void IUsbInterface.BulkReset(byte endpoint) { throw new NotImplementedException(); }
@@ -186,8 +168,6 @@
 		UsbPipeStream IUsbInterface.GetBulkStream(byte endpoint) { throw new NotImplementedException(); }
 		UsbPipeStream IUsbInterface.GetInterruptStream(byte endpoint) { throw new NotImplementedException(); }
 		void IDisposable.Dispose() { }
-		#endregion
-		#region IUsbDevice Members
 		byte IUsbDevice.Configuration { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } }
 		void IUsbDevice.ClaimInterface(int interfaceID) { }
 		void IUsbDevice.ReleaseInterface(int interfaceID) {	}
--- a/USBLib/Windows/USB/UsbHub.cs	Sun Oct 13 02:47:08 2013 +0200
+++ b/USBLib/Windows/USB/UsbHub.cs	Sun Oct 13 18:43:45 2013 +0200
@@ -3,69 +3,108 @@
 using System.ComponentModel;
 using System.Runtime.InteropServices;
 using Microsoft.Win32.SafeHandles;
+using UCIS.HWLib.Windows.Devices;
 using UCIS.USBLib.Internal.Windows;
 
 namespace UCIS.HWLib.Windows.USB {
 	public class UsbHub : UsbDevice {
-		public bool IsRootHub { get; private set; }
-		internal USB_NODE_INFORMATION NodeInformation { get; private set; }
-
-		public int PortCount { get { return NodeInformation.HubInformation.HubDescriptor.bNumberOfPorts; } }
-		public bool IsBusPowered { get { return NodeInformation.HubInformation.HubIsBusPowered; } }
-		public override string DeviceDescription { get { return IsRootHub ? "RootHub" : "Standard-USB-Hub"; } }
+		internal static SafeFileHandle OpenHandle(String path) {
+			SafeFileHandle handle = Kernel32.CreateFile(path, Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_WRITE, IntPtr.Zero, Kernel32.OPEN_EXISTING, 0, IntPtr.Zero);
+			if (handle.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error());
+			return handle;
+		}
 
-		public override string DriverKey {
-			get {
-				if (Parent == null) return null;
-				using (SafeFileHandle handle = OpenHandle(Parent.DevicePath)) return GetNodeConnectionDriverKey(handle, AdapterNumber);
-			}
-		}
-		
-		internal UsbHub(UsbDevice parent, USB_NODE_CONNECTION_INFORMATION_EX nci, string devicePath, uint port, Boolean roothub)
-			: base(parent, nci, port, devicePath) {
-			this.IsRootHub = roothub;
-			using (SafeFileHandle handle = OpenHandle(DevicePath)) {
-				USB_NODE_INFORMATION NodeInfo;
-				GetNodeInformation(handle, out NodeInfo);
-				this.NodeInformation = NodeInfo;
-			}
+		private Boolean HasNodeInformation = false;
+		private USB_NODE_INFORMATION NodeInformation;
+
+		private void GetNodeInformation() {
+			if (HasNodeInformation) return;
+			NodeInformation = new USB_NODE_INFORMATION();
+			int nBytes = Marshal.SizeOf(typeof(USB_NODE_INFORMATION));
+			using (SafeFileHandle handle = OpenHandle()) 
+				if (!Kernel32.DeviceIoControl(handle, UsbApi.IOCTL_USB_GET_NODE_INFORMATION, ref NodeInformation, nBytes, out NodeInformation, nBytes, out nBytes, IntPtr.Zero))
+					throw new Win32Exception(Marshal.GetLastWin32Error());
 		}
 
-		public override int GetDescriptor(byte descriptorType, byte index, short langId, byte[] buffer, int offset, int length) {
-			if (Parent == null) return 0;
-			using (SafeFileHandle handle = UsbHub.OpenHandle(Parent.DevicePath)) return GetDescriptor(handle, AdapterNumber, descriptorType, index, langId, buffer, offset, length);
+		public bool IsRootHub { get; private set; }
+		public int PortCount { get { GetNodeInformation(); return NodeInformation.HubInformation.HubDescriptor.bNumberOfPorts; } }
+		public bool IsBusPowered { get { GetNodeInformation(); return NodeInformation.HubInformation.HubIsBusPowered; } }
+		public override string DeviceDescription { get { return IsRootHub ? "Root hub" : base.DeviceDescription; } }
+
+		public String DevicePath { get; private set; }
+
+		internal UsbHub(UsbHub parent, string devicePath, uint port)
+			: base(null, parent, port) {
+			this.DevicePath = devicePath;
+			this.IsRootHub = (parent == null);
+			if (IsRootHub) SetNodeConnectionInfo(new USB_NODE_CONNECTION_INFORMATION_EX());
 		}
 
+		private UsbHub(DeviceNode devnode, string devicePath)
+			: base(devnode, null, 0) {
+			this.DevicePath = devicePath;
+			this.IsRootHub = false;
+		}
+
+		internal SafeFileHandle OpenHandle() {
+			return OpenHandle(DevicePath);
+		}
 
 		public IList<UsbDevice> Devices {
 			get {
-				List<UsbDevice> devices = new List<UsbDevice>();
-				using (SafeFileHandle handle = OpenHandle(DevicePath)) {
+				UsbDevice[] devices = new UsbDevice[PortCount];
+				using (SafeFileHandle handle = OpenHandle()) {
 					for (uint index = 1; index <= PortCount; index++) {
-						devices.Add(BuildDevice(this, index, this.DevicePath, handle));
+						USB_NODE_CONNECTION_INFORMATION_EX nodeConnection = GetNodeConnectionInformation(handle, index);
+						UsbDevice device;
+						if (nodeConnection.ConnectionStatus != USB_CONNECTION_STATUS.DeviceConnected) {
+							device = new UsbDevice(null, this, index);
+						} else if (nodeConnection.DeviceDescriptor.DeviceClass == (Byte)UsbDeviceClass.HubDevice) {
+							int nBytes = Marshal.SizeOf(typeof(USB_NODE_CONNECTION_NAME));
+							USB_NODE_CONNECTION_NAME nameConnection = new USB_NODE_CONNECTION_NAME();
+							nameConnection.ConnectionIndex = index;
+							if (!Kernel32.DeviceIoControl(handle, UsbApi.IOCTL_USB_GET_NODE_CONNECTION_NAME, ref nameConnection, nBytes, out nameConnection, nBytes, out nBytes, IntPtr.Zero))
+								throw new Win32Exception(Marshal.GetLastWin32Error());
+							device = new UsbHub(this, @"\\?\" + nameConnection.NodeName, index);
+						} else {
+							device = new UsbDevice(null, this, index);
+						}
+						device.SetNodeConnectionInfo(nodeConnection);
+						devices[index - 1] = device;
 					}
 				}
 				return devices;
 			}
 		}
 
-		internal static UsbDevice BuildDevice(UsbDevice parent, uint portCount, string devicePath) {
-			using (SafeFileHandle handle = OpenHandle(devicePath)) return BuildDevice(parent, portCount, devicePath, handle);
+		static readonly Guid IID_DEVINTERFACE_USB_HUB = new Guid(UsbApi.GUID_DEVINTERFACE_USB_HUB);
+		public static UsbHub GetHubForDeviceNode(DeviceNode node) {
+			if (node == null) return null;
+			String[] interfaces = node.GetInterfaces(IID_DEVINTERFACE_USB_HUB);
+			if (interfaces == null || interfaces.Length == 0) return null;
+			return new UsbHub(node, interfaces[0]);
 		}
-		internal static UsbDevice BuildDevice(UsbDevice parent, uint portCount, string devicePath, SafeFileHandle handle) {
-			USB_NODE_CONNECTION_INFORMATION_EX nodeConnection;
-			if (!GetNodeConnectionInformation(handle, portCount, out nodeConnection)) throw new Win32Exception(Marshal.GetLastWin32Error());
-			UsbDevice device = null;
-			if (nodeConnection.ConnectionStatus != USB_CONNECTION_STATUS.DeviceConnected) {
-				device = new UsbDevice(parent, nodeConnection, portCount, devicePath);
-			} else if (nodeConnection.DeviceDescriptor.DeviceClass == (Byte)UsbDeviceClass.HubDevice) {
-				String nodeName = GetNodeConnectionName(handle, portCount);
-				device = new UsbHub(parent, nodeConnection, @"\\?\" + nodeName, portCount, false);
+
+		public static IList<UsbHub> GetHubs() {
+			IList<UsbHub> devices = new List<UsbHub>();
+			foreach (DeviceNode dev in DeviceNode.GetDevices(IID_DEVINTERFACE_USB_HUB)) {
+				UsbHub hub = GetHubForDeviceNode(dev);
+				if (hub != null) devices.Add(hub);
+			}
+			return devices;
+		}
+
+		public UsbDevice FindChildForDeviceNode(DeviceNode node) {
+			String driverkey = node.DriverKey;
+			if (driverkey != null) {
+				foreach (UsbDevice child in Devices) if (driverkey.Equals(child.DriverKey, StringComparison.InvariantCultureIgnoreCase)) return child;
 			} else {
-				device = new UsbDevice(parent, nodeConnection, portCount, devicePath);
+				int? address = node.Address;
+				if (address == null || address.Value == 0) return null;
+				int port = address.Value;
+				foreach (UsbDevice child in Devices) if (port == child.AdapterNumber) return child;
 			}
-			device.NodeConnectionInfo = nodeConnection;
-			return device;
+			return null;
 		}
 	}
 }