changeset 59:4e1a5dec786a

Merge USB updates
author Ivo Smits <Ivo@UCIS.nl>
date Wed, 09 Oct 2013 20:56:28 +0200
parents 7c15c12ef965 (current diff) fd63c453ff65 (diff)
children 3424fa5a12c9
files
diffstat 8 files changed, 705 insertions(+), 212 deletions(-) [+]
line wrap: on
line diff
--- a/UCIS.Core.csproj	Wed Oct 09 13:56:35 2013 +0200
+++ b/UCIS.Core.csproj	Wed Oct 09 20:56:28 2013 +0200
@@ -152,6 +152,7 @@
     <Compile Include="USBLib\Communication\USBIO\USBIODevice.cs" />
     <Compile Include="USBLib\Communication\USBIO\USBIORegistry.cs" />
     <Compile Include="USBLib\Communication\UsbPipeStream.cs" />
+    <Compile Include="USBLib\Communication\VBoxUSB.cs" />
     <Compile Include="USBLib\Communication\WindowsUsbDeviceRegistry.cs" />
     <Compile Include="USBLib\Communication\WinUsb\WinUsbDevice.cs" />
     <Compile Include="USBLib\Communication\WinUsb\WinUsbRegistry.cs" />
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBLib/Communication/VBoxUSB.cs	Wed Oct 09 20:56:28 2013 +0200
@@ -0,0 +1,463 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using Microsoft.Win32.SafeHandles;
+using UCIS.HWLib.Windows.Devices;
+using UCIS.USBLib.Communication;
+using UCIS.USBLib.Communication.WinUsb;
+using UCIS.USBLib.Internal.Windows;
+
+namespace UCIS.USBLib.Communication.VBoxUSB {
+	enum USBFILTERTYPE : int {
+		USBFILTERTYPE_INVALID = 0,
+		USBFILTERTYPE_FIRST,
+		USBFILTERTYPE_ONESHOT_IGNORE = USBFILTERTYPE_FIRST,
+		USBFILTERTYPE_ONESHOT_CAPTURE,
+		USBFILTERTYPE_IGNORE,
+		USBFILTERTYPE_CAPTURE,
+		USBFILTERTYPE_END,
+	}
+	enum USBFILTERMATCH : ushort {
+		USBFILTERMATCH_INVALID = 0,
+		USBFILTERMATCH_IGNORE,
+		USBFILTERMATCH_PRESENT,
+		USBFILTERMATCH_NUM_FIRST,
+		USBFILTERMATCH_NUM_EXACT = USBFILTERMATCH_NUM_FIRST,
+		USBFILTERMATCH_NUM_EXACT_NP,
+		USBFILTERMATCH_NUM_EXPRESSION,
+		USBFILTERMATCH_NUM_EXPRESSION_NP,
+		USBFILTERMATCH_NUM_LAST = USBFILTERMATCH_NUM_EXPRESSION_NP,
+		USBFILTERMATCH_STR_FIRST,
+		USBFILTERMATCH_STR_EXACT = USBFILTERMATCH_STR_FIRST,
+		USBFILTERMATCH_STR_EXACT_NP,
+		USBFILTERMATCH_STR_PATTERN,
+		USBFILTERMATCH_STR_PATTERN_NP,
+		USBFILTERMATCH_STR_LAST = USBFILTERMATCH_STR_PATTERN_NP,
+		USBFILTERMATCH_END = 11
+	}
+	enum USBFILTERIDX : int {
+		USBFILTERIDX_VENDOR_ID = 0,
+		USBFILTERIDX_PRODUCT_ID,
+		USBFILTERIDX_DEVICE_REV,
+		USBFILTERIDX_DEVICE_CLASS,
+		USBFILTERIDX_DEVICE_SUB_CLASS,
+		USBFILTERIDX_DEVICE_PROTOCOL,
+		USBFILTERIDX_BUS,
+		USBFILTERIDX_PORT,
+		USBFILTERIDX_MANUFACTURER_STR,
+		USBFILTERIDX_PRODUCT_STR,
+		USBFILTERIDX_SERIAL_NUMBER_STR,
+		USBFILTERIDX_END = 11
+	}
+	[StructLayout(LayoutKind.Sequential, Size = 4)]
+	struct USBFILTERFIELD {
+		public USBFILTERMATCH enmMatch;
+		public UInt16 u16Value;
+	}
+	[StructLayout(LayoutKind.Sequential)]
+	unsafe struct USBFILTER {
+		public UInt32 u32Magic;
+		public USBFILTERTYPE enmType;
+		public fixed UInt32 aFields[(int)USBFILTERIDX.USBFILTERIDX_END];
+		public UInt32 offCurEnd;
+		public fixed Byte achStrTab[256];
+
+		const UInt32 USBFILTER_MAGIC = 0x19670408;
+		public unsafe USBFILTER(USBFILTERTYPE enmType)
+			: this() {
+			u32Magic = USBFILTER_MAGIC;
+			this.enmType = enmType;
+			fixed (UInt32* aFieldsBytes = this.aFields) {
+				USBFILTERFIELD* aFields = (USBFILTERFIELD*)aFieldsBytes;
+				for (int i = 0; i < (int)USBFILTERIDX.USBFILTERIDX_END; i++)
+					aFields[i].enmMatch = USBFILTERMATCH.USBFILTERMATCH_IGNORE;
+			}
+		}
+		static Boolean IsNumericField(USBFILTERIDX enmFieldIdx) {
+			switch (enmFieldIdx) {
+				case USBFILTERIDX.USBFILTERIDX_VENDOR_ID:
+				case USBFILTERIDX.USBFILTERIDX_PRODUCT_ID:
+				case USBFILTERIDX.USBFILTERIDX_DEVICE_REV:
+				case USBFILTERIDX.USBFILTERIDX_DEVICE_CLASS:
+				case USBFILTERIDX.USBFILTERIDX_DEVICE_SUB_CLASS:
+				case USBFILTERIDX.USBFILTERIDX_DEVICE_PROTOCOL:
+				case USBFILTERIDX.USBFILTERIDX_BUS:
+				case USBFILTERIDX.USBFILTERIDX_PORT:
+					return true;
+				case USBFILTERIDX.USBFILTERIDX_MANUFACTURER_STR:
+				case USBFILTERIDX.USBFILTERIDX_PRODUCT_STR:
+				case USBFILTERIDX.USBFILTERIDX_SERIAL_NUMBER_STR:
+					return false;
+				default:
+					throw new ArgumentOutOfRangeException("enmFieldIdx");
+			}
+		}
+		static Boolean IsMethodUsingStringValue(USBFILTERMATCH enmMatchingMethod) {
+			switch (enmMatchingMethod) {
+				case USBFILTERMATCH.USBFILTERMATCH_NUM_EXPRESSION:
+				case USBFILTERMATCH.USBFILTERMATCH_NUM_EXPRESSION_NP:
+				case USBFILTERMATCH.USBFILTERMATCH_STR_EXACT:
+				case USBFILTERMATCH.USBFILTERMATCH_STR_EXACT_NP:
+				case USBFILTERMATCH.USBFILTERMATCH_STR_PATTERN:
+				case USBFILTERMATCH.USBFILTERMATCH_STR_PATTERN_NP:
+					return true;
+				case USBFILTERMATCH.USBFILTERMATCH_IGNORE:
+				case USBFILTERMATCH.USBFILTERMATCH_PRESENT:
+				case USBFILTERMATCH.USBFILTERMATCH_NUM_EXACT:
+				case USBFILTERMATCH.USBFILTERMATCH_NUM_EXACT_NP:
+					return false;
+				default:
+					throw new ArgumentOutOfRangeException("enmMatchingMethod");
+			}
+		}
+		static unsafe int strlen(byte* ptr) {
+			for (int length = 0; ; length++) if (ptr[length] != 0) return length;
+		}
+		static unsafe void memset(void* ptr, byte value, int count) {
+			for (int i = 0; i < count; i++) ((byte*)ptr)[i] = value;
+		}
+		static unsafe void memmove(void* dest, void* src, int count) {
+			if (dest > src) {
+				for (int i = count - 1; i >= 0; i--) ((byte*)dest)[i] = ((byte*)src)[i];
+			} else if (dest < src) {
+				for (int i = 0; i < count; i++) ((byte*)dest)[i] = ((byte*)src)[i];
+			}
+		}
+		public unsafe void SetString(USBFILTERIDX enmFieldIdx, Byte[] pszString) {
+			fixed (USBFILTER* pFilter = &this) {
+				USBFILTERFIELD* aFields = (USBFILTERFIELD*)pFilter->aFields;
+				if (IsMethodUsingStringValue((USBFILTERMATCH)aFields[(int)enmFieldIdx].enmMatch) && aFields[(int)enmFieldIdx].u16Value != 0) {
+					int off = aFields[(int)enmFieldIdx].u16Value;
+					aFields[(int)enmFieldIdx].u16Value = 0;     /* Assign it to the NULL string. */
+					int cchShift = strlen(&pFilter->achStrTab[off]) + 1;
+					int cchToMove = ((int)offCurEnd + 1) - (off + cchShift);
+					if (cchToMove > 0) {
+						memmove(&pFilter->achStrTab[off], &pFilter->achStrTab[off + cchShift], cchToMove);
+						for (int i = 0; i < (int)USBFILTERIDX.USBFILTERIDX_END; i++)
+							if (aFields[i].u16Value >= off && IsMethodUsingStringValue(aFields[i].enmMatch))
+								aFields[i].u16Value -= (ushort)cchShift;
+					}
+					offCurEnd -= (uint)cchShift;
+					memset(&pFilter->achStrTab[offCurEnd], 0, cchShift);
+				}
+				if (pszString.Length == 0) {
+					aFields[(int)enmFieldIdx].u16Value = 0;
+				} else {
+					int cch = pszString.Length;
+					if (this.offCurEnd + cch + 2 > 256) throw new IndexOutOfRangeException("Buffer overflow");
+					aFields[(int)enmFieldIdx].u16Value = (ushort)(this.offCurEnd + 1);
+					for (int i = 0; i < cch + 1; i++) pFilter->achStrTab[offCurEnd + 1 + i] = pszString[i];
+					offCurEnd += (uint)cch + 1;
+				}
+			}
+		}
+		unsafe void DeleteAnyStringValue(USBFILTERIDX enmFieldIdx) {
+			fixed (USBFILTER* pFilter = &this) {
+				USBFILTERFIELD* aFields = (USBFILTERFIELD*)pFilter->aFields;
+				if (IsMethodUsingStringValue((USBFILTERMATCH)aFields[(int)enmFieldIdx].enmMatch) && aFields[(int)enmFieldIdx].u16Value != 0)
+					SetString(enmFieldIdx, new Byte[0]);
+				else if (enmFieldIdx >= USBFILTERIDX.USBFILTERIDX_END)
+					throw new ArgumentOutOfRangeException("enmFieldIdx");
+			}
+		}
+		public unsafe void SetNumExact(USBFILTERIDX enmFieldIdx, UInt16 u16Value, bool fMustBePresent) {
+			if (!IsNumericField(enmFieldIdx)) throw new ArgumentOutOfRangeException("enmFieldIdx");
+			DeleteAnyStringValue(enmFieldIdx);
+			fixed (USBFILTER* pFilter = &this) {
+				USBFILTERFIELD* aFields = (USBFILTERFIELD*)pFilter->aFields;
+				aFields[(int)enmFieldIdx].u16Value = u16Value;
+				aFields[(int)enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH.USBFILTERMATCH_NUM_EXACT : USBFILTERMATCH.USBFILTERMATCH_NUM_EXACT_NP;
+			}
+		}
+	}
+	[StructLayout(LayoutKind.Sequential, Pack = 4)]
+	struct USBSUP_FLTADDOUT {
+		public IntPtr uId;
+		public int rc;
+	}
+	[StructLayout(LayoutKind.Sequential)]
+	struct USBSUP_VERSION {
+		public UInt32 u32Major;
+		public UInt32 u32Minor;
+	}
+	[StructLayout(LayoutKind.Sequential)]
+	struct USBSUP_CLAIMDEV {
+		public Byte bInterfaceNumber;
+		public Byte fClaimed;
+	}
+	[StructLayout(LayoutKind.Sequential)]
+	struct USBSUP_CLEAR_ENDPOINT {
+		public Byte bEndpoint;
+	}
+	[StructLayout(LayoutKind.Sequential)]
+	struct USBSUP_SET_CONFIG {
+		public Byte bConfigurationValue;
+	}
+	[StructLayout(LayoutKind.Sequential)]
+	struct USBSUP_SELECT_INTERFACE {
+		public Byte bInterfaceNumber;
+		public Byte bAlternateSetting;
+	}
+	enum USBSUP_TRANSFER_TYPE : int {
+		USBSUP_TRANSFER_TYPE_CTRL = 0,
+		USBSUP_TRANSFER_TYPE_ISOC = 1,
+		USBSUP_TRANSFER_TYPE_BULK = 2,
+		USBSUP_TRANSFER_TYPE_INTR = 3,
+		USBSUP_TRANSFER_TYPE_MSG = 4
+	}
+	enum USBSUP_DIRECTION : int {
+		USBSUP_DIRECTION_SETUP = 0,
+		USBSUP_DIRECTION_IN = 1,
+		USBSUP_DIRECTION_OUT = 2
+	}
+	enum USBSUP_XFER_FLAG : int {
+		USBSUP_FLAG_NONE = 0,
+		USBSUP_FLAG_SHORT_OK = 1
+	}
+	enum USBSUP_ERROR : int {
+		USBSUP_XFER_OK = 0,
+		USBSUP_XFER_STALL = 1,
+		USBSUP_XFER_DNR = 2,
+		USBSUP_XFER_CRC = 3,
+		USBSUP_XFER_NAC = 4,
+		USBSUP_XFER_UNDERRUN = 5,
+		USBSUP_XFER_OVERRUN = 6
+	}
+	[StructLayout(LayoutKind.Sequential, Pack = 4)]
+	unsafe struct USBSUP_URB {
+		public USBSUP_TRANSFER_TYPE type;
+		public UInt32 ep;
+		public USBSUP_DIRECTION dir;
+		public USBSUP_XFER_FLAG flags;
+		public USBSUP_ERROR error;
+		public UIntPtr len;
+		public void* buf;
+		public UInt32 numIsoPkts;
+		public fixed byte aIsoPkts[8 * 8];
+	}
+	class USBRegistry : WindowsUsbDeviceRegistry, IUsbDeviceRegistry {
+		public IUsbDevice Open() { return new VBoxUSB(this); }
+		public USBRegistry(DeviceNode devnode, String intf) : base(devnode, intf) { }
+	}
+
+	public class VBoxUSB : UsbInterface, IUsbDevice {
+		const int FILE_DEVICE_UNKNOWN = 0x00000022;
+		const int METHOD_BUFFERED = 0;
+		const int FILE_WRITE_ACCESS = 0x0002;
+		static int CTL_CODE(int DeviceType, int Function, int Method, int Access) { return (DeviceType << 16) | (Access << 14) | (Function << 2) | Method; }
+		static readonly int SUPUSBFLT_IOCTL_ADD_FILTER = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x611, METHOD_BUFFERED, FILE_WRITE_ACCESS);
+		static readonly int SUPUSBFLT_IOCTL_RUN_FILTERS = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x615, METHOD_BUFFERED, FILE_WRITE_ACCESS);
+		static readonly int SUPUSBFLT_IOCTL_REMOVE_FILTER = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x612, METHOD_BUFFERED, FILE_WRITE_ACCESS);
+		static readonly int SUPUSBFLT_IOCTL_GET_VERSION = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x610, METHOD_BUFFERED, FILE_WRITE_ACCESS);
+		static readonly int SUPUSB_IOCTL_GET_VERSION = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60F, METHOD_BUFFERED, FILE_WRITE_ACCESS);
+		static readonly int SUPUSB_IOCTL_USB_CLAIM_DEVICE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60B, METHOD_BUFFERED, FILE_WRITE_ACCESS);
+		static readonly int SUPUSB_IOCTL_USB_RELEASE_DEVICE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60C, METHOD_BUFFERED, FILE_WRITE_ACCESS);
+		static readonly int SUPUSB_IOCTL_USB_RESET = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x608, METHOD_BUFFERED, FILE_WRITE_ACCESS);
+		static readonly int SUPUSB_IOCTL_USB_CLEAR_ENDPOINT = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60E, METHOD_BUFFERED, FILE_WRITE_ACCESS);
+		static readonly int SUPUSB_IOCTL_USB_SET_CONFIG = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60A, METHOD_BUFFERED, FILE_WRITE_ACCESS);
+		static readonly int SUPUSB_IOCTL_USB_SELECT_INTERFACE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x609, METHOD_BUFFERED, FILE_WRITE_ACCESS);
+		static readonly int SUPUSB_IOCTL_SEND_URB = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x607, METHOD_BUFFERED, FILE_WRITE_ACCESS);
+
+		const UInt32 USBDRV_MAJOR_VERSION = 4;
+		const UInt32 USBDRV_MINOR_VERSION = 0;
+		const UInt32 USBMON_MAJOR_VERSION = 5;
+		const UInt32 USBMON_MINOR_VERSION = 0;
+
+		static SafeFileHandle hMonitor = null;
+		const String USBMON_DEVICE_NAME = "\\\\.\\VBoxUSBMon";
+
+		static unsafe void SyncIoControl(SafeHandle hDevice, int IoControlCode, void* InBuffer, int nInBufferSize, void* OutBuffer, int nOutBufferSize) {
+			Int32 pBytesReturned = 0;
+			if (!Kernel32.DeviceIoControl(hDevice, IoControlCode, InBuffer, nInBufferSize, OutBuffer, nOutBufferSize, out pBytesReturned, null))
+				throw new Win32Exception(Marshal.GetLastWin32Error());
+		}
+		
+		unsafe static void InitMonitor() {
+			if (hMonitor != null && !hMonitor.IsClosed && !hMonitor.IsInvalid) return;
+			hMonitor = Kernel32.CreateFile(USBMON_DEVICE_NAME, Kernel32.GENERIC_READ | Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_READ | Kernel32.FILE_SHARE_WRITE, IntPtr.Zero, Kernel32.OPEN_EXISTING, Kernel32.FILE_ATTRIBUTE_SYSTEM, IntPtr.Zero);
+			if (hMonitor.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error());
+			try {
+				USBSUP_VERSION Version = new USBSUP_VERSION();
+				SyncIoControl(hMonitor, SUPUSBFLT_IOCTL_GET_VERSION, null, 0, &Version, sizeof(USBSUP_VERSION));
+				if (Version.u32Major != USBMON_MAJOR_VERSION || Version.u32Minor < USBMON_MINOR_VERSION) throw new InvalidOperationException("Unsupported USBMON version");
+			} catch {
+				hMonitor.Close();
+			}
+		}
+
+		static unsafe IntPtr USBLibAddFilter(ref USBFILTER filter) {
+			USBSUP_FLTADDOUT FltAddRc;
+			fixed (USBFILTER* pFilter = &filter) SyncIoControl(hMonitor, SUPUSBFLT_IOCTL_ADD_FILTER, pFilter, sizeof(USBFILTER), &FltAddRc, sizeof(USBSUP_FLTADDOUT));
+			if (FltAddRc.rc != 0) throw new Exception(String.Format("rc={0}", FltAddRc.rc));
+			return FltAddRc.uId;
+		}
+		static unsafe void USBLibRemoveFilter(UIntPtr filterId) {
+			SyncIoControl(hMonitor, SUPUSBFLT_IOCTL_REMOVE_FILTER, &filterId, sizeof(UIntPtr), null, 0);
+		}
+		static unsafe void USBLibRunFilters() {
+			SyncIoControl(hMonitor, SUPUSBFLT_IOCTL_RUN_FILTERS, null, 0, null, 0);
+		}
+
+		static void initFilterFromDevice(ref USBFILTER aFilter, DeviceNode aDevice) {
+			int mVid, mPid, mRev, mMi;
+			WindowsUsbDeviceRegistry.DecodeDeviceIDs(aDevice, out mVid, out mPid, out mRev, out mMi);
+			if (mVid != -1) aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_VENDOR_ID, (ushort)mVid, true);
+			if (mPid != -1) aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_PRODUCT_ID, (ushort)mPid, true);
+			if (mRev != -1) {
+				int mRevBCD = (((mRev % 10) / 1) << 0) | (((mRev % 100) / 10) << 4) | (((mRev % 1000) / 100) << 8) | (((mRev % 10000) / 1000) << 12);
+				aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_DEVICE_REV, (ushort)mRevBCD, true);
+			}
+			//aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_DEVICE_CLASS, 0xff, true);
+			//aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_DEVICE_SUB_CLASS, 0x00, true);
+			//aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_DEVICE_PROTOCOL, 0x00, true);
+			//aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_PORT, 0, true);
+			//aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_BUS, 0, true);
+			//if (pDev->pszSerialNumber) aFilter.SetStringExact(USBFILTERIDX.USBFILTERIDX_SERIAL_NUMBER_STR, pDev->pszSerialNumber, true);
+			//if (pDev->pszProduct) aFilter.SetStringExact(USBFILTERIDX.USBFILTERIDX_PRODUCT_STR, pDev->pszProduct, true);
+			//if (pDev->pszManufacturer) aFilter.SetStringExact(USBFILTERIDX.USBFILTERIDX_MANUFACTURER_STR, pDev->pszManufacturer, true);
+		}
+
+		public unsafe static void Capture(DeviceNode aDevice) {
+			InitMonitor();
+			USBFILTER Filter = new USBFILTER(USBFILTERTYPE.USBFILTERTYPE_ONESHOT_CAPTURE);
+			initFilterFromDevice(ref Filter, aDevice);
+			IntPtr pvId = USBLibAddFilter(ref Filter);
+			if (pvId == IntPtr.Zero) throw new Exception("Add one-shot Filter failed");
+			//USBLibRunFilters();
+			aDevice.Reenumerate(0);
+		}
+		public unsafe static void Release(DeviceNode aDevice) {
+			InitMonitor();
+			USBFILTER Filter = new USBFILTER(USBFILTERTYPE.USBFILTERTYPE_ONESHOT_IGNORE);
+			initFilterFromDevice(ref Filter, aDevice);
+			IntPtr pvId = USBLibAddFilter(ref Filter);
+			if (pvId == IntPtr.Zero) throw new Exception("Add one-shot Filter failed");
+			//USBLibRunFilters();
+			aDevice.Reenumerate(0);
+		}
+		public static IUsbDeviceRegistry GetDeviceForDeviceNode(DeviceNode device) {
+			String[] intfpath = device.GetInterfaces(new Guid(0x873fdf, 0xCAFE, 0x80EE, 0xaa, 0x5e, 0x0, 0xc0, 0x4f, 0xb1, 0x72, 0xb));
+			if (intfpath == null || intfpath.Length == 0) return null;
+			return new USBRegistry(device, intfpath[0]);
+		}
+
+		SafeHandle hDev;
+		Byte bInterfaceNumber;
+
+		public IUsbDeviceRegistry Registry { get; private set; }
+
+		internal unsafe VBoxUSB(USBRegistry devreg) {
+			this.Registry = devreg;
+			hDev = Kernel32.CreateFile(devreg.DevicePath, Kernel32.GENERIC_READ | Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_WRITE | Kernel32.FILE_SHARE_READ, IntPtr.Zero, Kernel32.OPEN_EXISTING, Kernel32.FILE_ATTRIBUTE_SYSTEM | Kernel32.FILE_FLAG_OVERLAPPED, IntPtr.Zero);
+			if (hDev.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error());
+			try {
+				USBSUP_VERSION version = new USBSUP_VERSION();
+				SyncIoControl(hDev, SUPUSB_IOCTL_GET_VERSION, null, 0, &version, sizeof(USBSUP_VERSION));
+				if (version.u32Major != USBDRV_MAJOR_VERSION || version.u32Minor < USBDRV_MINOR_VERSION) throw new InvalidOperationException("Unsupported USBDRV version");
+				USBSUP_CLAIMDEV claim = new USBSUP_CLAIMDEV() { bInterfaceNumber = 0 };
+				SyncIoControl(hDev, SUPUSB_IOCTL_USB_CLAIM_DEVICE, &claim, sizeof(USBSUP_CLAIMDEV), &claim, sizeof(USBSUP_CLAIMDEV));
+				if (claim.fClaimed == 0) throw new InvalidOperationException("Claim failed");
+			} catch {
+				hDev.Close();
+				throw;
+			}
+		}
+		public unsafe override void Close() {
+			if (!hDev.IsInvalid && !hDev.IsClosed) {
+				USBSUP_CLAIMDEV release = new USBSUP_CLAIMDEV() { bInterfaceNumber = bInterfaceNumber };
+				SyncIoControl(hDev, SUPUSB_IOCTL_USB_RELEASE_DEVICE, &release, sizeof(USBSUP_CLAIMDEV), null, 0);
+			}
+			hDev.Close();
+		}
+
+		public unsafe override void BulkReset(byte endpoint) {
+			USBSUP_CLEAR_ENDPOINT inp = new USBSUP_CLEAR_ENDPOINT() { bEndpoint = endpoint };
+			SyncIoControl(hDev, SUPUSB_IOCTL_USB_CLEAR_ENDPOINT, &inp, sizeof(USBSUP_CLEAR_ENDPOINT), null, 0);
+		}
+		public override void InterruptReset(byte endpoint) {
+			BulkReset(endpoint);
+		}
+
+		public unsafe void ResetDevice() {
+			SyncIoControl(hDev, SUPUSB_IOCTL_USB_RESET, null, 0, null, 0);
+		}
+
+		public unsafe override byte Configuration {
+			get { return base.Configuration; }
+			set {
+				USBSUP_SET_CONFIG inp = new USBSUP_SET_CONFIG() { bConfigurationValue = value };
+				SyncIoControl(hDev, SUPUSB_IOCTL_USB_SET_CONFIG, &inp, sizeof(USBSUP_SET_CONFIG), null, 0);
+			}
+		}
+
+		private unsafe void HandleURB(USBSUP_URB* urb) {
+			using (ManualResetEvent evt = new ManualResetEvent(false)) {
+				NativeOverlapped overlapped = new NativeOverlapped();
+				overlapped.EventHandle = evt.SafeWaitHandle.DangerousGetHandle();
+				int size;
+				if (Kernel32.DeviceIoControl(hDev, SUPUSB_IOCTL_SEND_URB, urb, sizeof(USBSUP_URB), urb, sizeof(USBSUP_URB), out size, &overlapped))
+					return;
+				int err = Marshal.GetLastWin32Error();
+				if (err != 997) throw new Win32Exception(err);
+				evt.WaitOne();
+				if (!Kernel32.GetOverlappedResult(hDev, &overlapped, out size, false))
+					throw new Win32Exception(Marshal.GetLastWin32Error());
+			}
+		}
+
+		private unsafe int BlockTransfer(USBSUP_TRANSFER_TYPE type, USBSUP_DIRECTION dir, USBSUP_XFER_FLAG flags, UInt32 ep, Byte[] buffer, int offset, int length) {
+			fixed (Byte* ptr = buffer) {
+				USBSUP_URB urb = new USBSUP_URB();
+				urb.type = type;
+				urb.dir = dir;
+				urb.flags = flags;
+				urb.ep = ep;
+				urb.len = (UIntPtr)length;
+				urb.buf = ptr;
+				HandleURB(&urb);
+				return (int)urb.len;
+			}
+		}
+
+		public override int BulkWrite(byte endpoint, byte[] buffer, int offset, int length) {
+			return BlockTransfer(USBSUP_TRANSFER_TYPE.USBSUP_TRANSFER_TYPE_BULK, USBSUP_DIRECTION.USBSUP_DIRECTION_OUT, USBSUP_XFER_FLAG.USBSUP_FLAG_NONE, endpoint, buffer, offset, length);
+		}
+		public override int BulkRead(byte endpoint, byte[] buffer, int offset, int length) {
+			return BlockTransfer(USBSUP_TRANSFER_TYPE.USBSUP_TRANSFER_TYPE_BULK, USBSUP_DIRECTION.USBSUP_DIRECTION_IN, USBSUP_XFER_FLAG.USBSUP_FLAG_NONE, endpoint, buffer, offset, length);
+		}
+		public override int InterruptWrite(byte endpoint, byte[] buffer, int offset, int length) {
+			return BlockTransfer(USBSUP_TRANSFER_TYPE.USBSUP_TRANSFER_TYPE_INTR, USBSUP_DIRECTION.USBSUP_DIRECTION_OUT, USBSUP_XFER_FLAG.USBSUP_FLAG_NONE, endpoint, buffer, offset, length);
+		}
+		public override int InterruptRead(byte endpoint, byte[] buffer, int offset, int length) {
+			return BlockTransfer(USBSUP_TRANSFER_TYPE.USBSUP_TRANSFER_TYPE_INTR, USBSUP_DIRECTION.USBSUP_DIRECTION_IN, USBSUP_XFER_FLAG.USBSUP_FLAG_NONE, endpoint, buffer, offset, length);
+		}
+		private unsafe int ControlTransfer(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) {
+			Byte[] bigbuffer = new Byte[sizeof(UsbSetupPacket) + length];
+			Boolean isout = (requestType & UsbControlRequestType.EndpointMask) == UsbControlRequestType.EndpointOut;
+			if (isout && length > 0) Buffer.BlockCopy(buffer, offset, bigbuffer, sizeof(UsbSetupPacket), length);
+			fixed (Byte* ptr = bigbuffer) *(UsbSetupPacket*)ptr = new UsbSetupPacket((Byte)requestType, request, value, index, (short)length);
+			int dlen = BlockTransfer(USBSUP_TRANSFER_TYPE.USBSUP_TRANSFER_TYPE_MSG, isout ? USBSUP_DIRECTION.USBSUP_DIRECTION_OUT : USBSUP_DIRECTION.USBSUP_DIRECTION_IN, USBSUP_XFER_FLAG.USBSUP_FLAG_NONE, 0, bigbuffer, 0, bigbuffer.Length);
+			dlen -= sizeof(UsbSetupPacket);
+			if (dlen > length) dlen = length;
+			if (dlen < 0) dlen = 0;
+			if (!isout) Buffer.BlockCopy(bigbuffer, sizeof(UsbSetupPacket), buffer, offset, dlen);
+			return dlen;
+		}
+		public override int ControlWrite(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) {
+			return ControlTransfer(requestType, request, value, index, buffer, offset, length);
+		}
+		public override int ControlRead(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) {
+			return ControlTransfer(requestType, request, value, index, buffer, offset, length);
+		}
+
+		public void ClaimInterface(int interfaceID) {
+			bInterfaceNumber = (Byte)interfaceID;
+		}
+
+		public void ReleaseInterface(int interfaceID) {
+		}
+	}
+}
--- a/USBLib/Descriptor/UsbDescriptor.cs	Wed Oct 09 13:56:35 2013 +0200
+++ b/USBLib/Descriptor/UsbDescriptor.cs	Wed Oct 09 20:56:28 2013 +0200
@@ -33,6 +33,7 @@
 		public static String GetStringFromDevice(IUsbInterface device, byte index, short langId) {
 			Byte[] buff = new Byte[256];
 			int len = device.GetDescriptor((Byte)UsbDescriptorType.String, index, langId, buff, 0, buff.Length);
+			if (len == 0) return null;
 			return GetString(buff, 0, len);
 		}
 	}
@@ -199,5 +200,6 @@
 			if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer dimensions");
 			fixed (Byte* ptr = buffer) return *(UsbHubDescriptor*)(ptr + offset);
 		}
+		public static unsafe int Size { get { return sizeof(UsbHubDescriptor); } }
 	}
 }
--- a/USBLib/Internal/Windows/UsbApi.cs	Wed Oct 09 13:56:35 2013 +0200
+++ b/USBLib/Internal/Windows/UsbApi.cs	Wed Oct 09 20:56:28 2013 +0200
@@ -339,7 +339,7 @@
 		//public byte[] Data; //UCHAR  Data[0];
 	}
 
-	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
 	struct USB_NODE_CONNECTION_NAME {
 		public uint ConnectionIndex;
 		public uint ActualLength;
@@ -347,7 +347,7 @@
 		public string NodeName; //WCHAR  NodeName[1];
 	}
 
-	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
 	struct USB_NODE_CONNECTION_DRIVERKEY_NAME {
 		public uint ConnectionIndex;
 		public uint ActualLength;
--- a/USBLib/Internal/Windows/Win32Kernel.cs	Wed Oct 09 13:56:35 2013 +0200
+++ b/USBLib/Internal/Windows/Win32Kernel.cs	Wed Oct 09 20:56:28 2013 +0200
@@ -14,6 +14,8 @@
 
 		[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
 		unsafe internal static extern bool DeviceIoControl(SafeHandle hDevice, int IoControlCode, IntPtr InBuffer, int nInBufferSize, IntPtr OutBuffer, int nOutBufferSize, out int pBytesReturned, NativeOverlapped* Overlapped);
+		[DllImport("kernel32.dll", SetLastError = true)]
+		unsafe internal static extern bool DeviceIoControl(SafeHandle hDevice, int IoControlCode, void* InBuffer, int nInBufferSize, void* OutBuffer, int nOutBufferSize, out int pBytesReturned, NativeOverlapped* Overlapped);
 		[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
 		unsafe internal static extern bool GetOverlappedResult(SafeHandle hFile, NativeOverlapped* lpOverlapped, out int lpNumberOfBytesTransferred, Boolean bWait);
 
@@ -22,7 +24,7 @@
 		[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
 		public static extern bool DeviceIoControl(SafeHandle hDevice, int dwIoControlCode, [In] ref USB_NODE_INFORMATION lpInBuffer, int nInBufferSize, out USB_NODE_INFORMATION lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);
 		[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
-		public static extern bool DeviceIoControl(SafeHandle hDevice, int dwIoControlCode, [In] ref USB_DESCRIPTOR_REQUEST lpInBuffer, int nInBufferSize, IntPtr lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);
+		public static extern bool DeviceIoControl(SafeHandle hDevice, int dwIoControlCode, [In] ref USB_DESCRIPTOR_REQUEST lpInBuffer, int nInBufferSize, Byte[] lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);
 		[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
 		public static extern bool DeviceIoControl(SafeHandle hDevice, int dwIoControlCode, [In] ref USB_NODE_CONNECTION_DRIVERKEY_NAME lpInBuffer, int nInBufferSize, out USB_NODE_CONNECTION_DRIVERKEY_NAME lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);
 		[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
@@ -30,15 +32,18 @@
 		[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
 		public static extern bool DeviceIoControl(SafeHandle hDevice, int dwIoControlCode, [In] ref USB_NODE_CONNECTION_NAME lpInBuffer, int nInBufferSize, out USB_NODE_CONNECTION_NAME lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);
 
-		//public const uint GENERIC_READ = 0x80000000;
+		public const uint GENERIC_READ = 0x80000000;
 		public const uint GENERIC_WRITE = 0x40000000;
 		//public const uint GENERIC_EXECUTE = 0x20000000;
 		//public const uint GENERIC_ALL = 0x10000000;
-		//public const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
+		public const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
 
-		//public const int FILE_SHARE_READ = 0x1;
+		public const int FILE_SHARE_READ = 0x1;
 		public const int FILE_SHARE_WRITE = 0x2;
 		public const int OPEN_EXISTING = 0x3;
+
+		public const int FILE_ATTRIBUTE_SYSTEM = 0x00000004;
+		public const int FILE_FLAG_OVERLAPPED = 0x40000000;
 	}
 
 	[Flags]
--- a/USBLib/Windows/USB/UsbController.cs	Wed Oct 09 13:56:35 2013 +0200
+++ b/USBLib/Windows/USB/UsbController.cs	Wed Oct 09 20:56:28 2013 +0200
@@ -8,24 +8,22 @@
 	public class UsbController {
 		public String DevicePath { get; private set; }
 		public DeviceNode DeviceNode { get; private set; }
-		public String DeviceDescription { get; private set; }
-		public String DriverKey { get; private set; }
-		public UsbHub RootHub { get; private set; }
+		public String DeviceDescription {
+			get { return DeviceNode.GetPropertyString(SPDRP.DeviceDesc); }
+		}
+		public String DriverKey {
+			get { return DeviceNode.GetPropertyString(SPDRP.Driver); }
+		}
+		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);
+			}
+		}
 		internal UsbController(UsbBus parent, DeviceNode di, String devicePath) {
 			this.DeviceNode = di;
 			this.DevicePath = devicePath;
-			this.DeviceDescription = di.GetPropertyString(SPDRP.DeviceDesc);
-			this.DriverKey = di.GetPropertyString(SPDRP.Driver);
-
-			USB_ROOT_HUB_NAME rootHubName;
-			using (SafeFileHandle handel1 = Kernel32.CreateFile(DevicePath, Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_WRITE, IntPtr.Zero, Kernel32.OPEN_EXISTING, 0, IntPtr.Zero)) {
-				if (handel1.IsInvalid) throw new Exception("No port found!");
-				int nBytesReturned;
-				if (!Kernel32.DeviceIoControl(handel1, UsbApi.IOCTL_USB_GET_ROOT_HUB_NAME, IntPtr.Zero, 0, out rootHubName, Marshal.SizeOf(typeof(USB_ROOT_HUB_NAME)), out nBytesReturned, IntPtr.Zero))
-					throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
-			}
-			if (rootHubName.ActualLength <= 0) throw new Exception("rootHubName.ActualLength <= 0");
-			RootHub = new UsbHub(this, null, @"\\?\" + rootHubName.RootHubName);
 		}
 	}
-}
\ No newline at end of file
+}
--- a/USBLib/Windows/USB/UsbDevice.cs	Wed Oct 09 13:56:35 2013 +0200
+++ b/USBLib/Windows/USB/UsbDevice.cs	Wed Oct 09 20:56:28 2013 +0200
@@ -1,45 +1,120 @@
 using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.Runtime.InteropServices;
 using System.Text;
 using Microsoft.Win32.SafeHandles;
 using UCIS.HWLib.Windows.Devices;
+using UCIS.USBLib.Communication;
+using UCIS.USBLib.Descriptor;
 using UCIS.USBLib.Internal.Windows;
 
 namespace UCIS.HWLib.Windows.USB {
-	public class UsbDevice {
-		public UsbDevice Parent { get; protected set; }
-		internal USB_NODE_CONNECTION_INFORMATION_EX NodeConnectionInfo { get; set; }
-		internal USB_DEVICE_DESCRIPTOR DeviceDescriptor { get; private set; }
-		internal IList<USB_CONFIGURATION_DESCRIPTOR> ConfigurationDescriptor { get; private set; }
-		internal IList<USB_INTERFACE_DESCRIPTOR> InterfaceDescriptor { get; private set; }
-		internal IList<USB_ENDPOINT_DESCRIPTOR> EndpointDescriptor { get; private set; }
-		internal IList<HID_DESCRIPTOR> HdiDescriptor { get; private set; }
-		public string DevicePath { get; private set; }
-		public uint AdapterNumber { get; internal set; }
-		public string DriverKey { get; private set; }
+	public class UsbDevice : IUsbInterface {
+		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) {
+			int nBytes = Marshal.SizeOf(typeof(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;
+		}
+		internal 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;
+		}
+		internal 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.wValue = (ushort)((descriptorType << 8) + index);
+			request.SetupPacket.wIndex = (ushort)langId;
+			request.SetupPacket.wLength = (ushort)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;
+		}
+		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;
+		}
+		internal 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;
+		}
 
-		public virtual string DeviceDescription { get { return DeviceNode.GetPropertyString(CMRDP.DEVICEDESC); } }
-		public string DeviceID { get { return DeviceNode.DeviceID; } }
+		public UsbDevice Parent { get; protected set; }
+		public string DevicePath { get; private set; }
+		public uint AdapterNumber { get; private set; }
+		internal USB_NODE_CONNECTION_INFORMATION_EX NodeConnectionInfo { get; set; }
+		internal USB_DEVICE_DESCRIPTOR DeviceDescriptor { get { return NodeConnectionInfo.DeviceDescriptor; } }
+
+		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(); } }
+
+		SafeFileHandle OpenHandle() {
+			return OpenHandle(DevicePath);
+		}
 
-		public bool IsConnected { get; internal set; }
-		public bool IsHub { get; internal set; }
-		public string Status { get; internal set; }
-		public string Speed { get; internal set; }
+		public int NumConfigurations { get { return DeviceDescriptor == null ? 0 : DeviceDescriptor.bNumConfigurations; } }
+		public int VendorID { get { return DeviceDescriptor == null ? 0 : DeviceDescriptor.idVendor; } }
+		public int ProductID { get { return DeviceDescriptor == null ? 0 : DeviceDescriptor.idProduct; } }
 
-		public string Manufacturer { get; private set; }
-		public string SerialNumber { get; private set; }
-		public string Product { get; private set; }
+		private String GetStringSafe(Byte id) {
+			if (id == 0) return null;
+			String s = GetStringDescriptor(id);
+			if (s == null) return s;
+			return s.Trim(' ', '\0');
+		}
 
-		public int VendorID { get { return DeviceDescriptor.idVendor; } }
-		public int ProductID { get { return DeviceDescriptor.idProduct; } }
+		public string Manufacturer { get { return DeviceDescriptor == null ? null : GetStringSafe(DeviceDescriptor.iManufacturer); } }
+		public string Product { get { return DeviceDescriptor == null ? null : GetStringSafe(DeviceDescriptor.iProduct); } }
+		public string SerialNumber { get { return DeviceDescriptor == null ? null : GetStringSafe(DeviceDescriptor.iSerialNumber); } }
+		public virtual string DriverKey { get { using (SafeFileHandle handle = OpenHandle(DevicePath)) return UsbHub.GetNodeConnectionDriverKey(handle, AdapterNumber); } }
+
+		public virtual string DeviceDescription { get { return DeviceNode == null ? null : DeviceNode.GetPropertyString(CMRDP.DEVICEDESC); } }
+		public string DeviceID { get { return DeviceNode == null ? null : DeviceNode.DeviceID; } }
 
 		private DeviceNode mDeviceNode;
 		public DeviceNode DeviceNode {
 			get {
-				if (mDeviceNode == null && DriverKey != null) {
+				String dk = DriverKey;
+				if (mDeviceNode == null && dk != null) {
 					foreach (DeviceNode node in DeviceNode.GetDevices("USB")) {
-						if (DriverKey.Equals(node.DriverKey, StringComparison.InvariantCultureIgnoreCase)) {
+						if (dk.Equals(node.DriverKey, StringComparison.InvariantCultureIgnoreCase)) {
 							mDeviceNode = node;
 							break;
 						}
@@ -49,131 +124,84 @@
 			}
 		}
 
-		internal UsbDevice(UsbDevice parent, USB_DEVICE_DESCRIPTOR deviceDescriptor, uint adapterNumber)
-			: this(parent, deviceDescriptor, adapterNumber, null) { }
-		unsafe internal UsbDevice(UsbDevice parent, USB_DEVICE_DESCRIPTOR deviceDescriptor, uint adapterNumber, string devicePath) {
+		internal UsbDevice(UsbDevice parent, USB_NODE_CONNECTION_INFORMATION_EX nci, uint port, string devicePath) {
 			this.Parent = parent;
-			this.AdapterNumber = adapterNumber;
-			this.DeviceDescriptor = deviceDescriptor;
+			this.NodeConnectionInfo = nci;
 			this.DevicePath = devicePath;
-			ConfigurationDescriptor = new List<USB_CONFIGURATION_DESCRIPTOR>();
-			InterfaceDescriptor = new List<USB_INTERFACE_DESCRIPTOR>();
-			HdiDescriptor = new List<HID_DESCRIPTOR>();
-			EndpointDescriptor = new List<USB_ENDPOINT_DESCRIPTOR>();
+			this.AdapterNumber = port;
 			if (devicePath == null) return;
-
-			using (SafeFileHandle handel = Kernel32.CreateFile(devicePath, Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_WRITE, IntPtr.Zero, Kernel32.OPEN_EXISTING, 0, IntPtr.Zero)) {
-				if (handel.IsInvalid) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
-				int nBytesReturned;
-				int nBytes = UsbApi.MAX_BUFFER_SIZE;
-
-				USB_DESCRIPTOR_REQUEST Request1 = new USB_DESCRIPTOR_REQUEST();
-				Request1.ConnectionIndex = adapterNumber;// portCount;
-				Request1.SetupPacket.wValue = (ushort)((UsbApi.USB_CONFIGURATION_DESCRIPTOR_TYPE << 8));
-				Request1.SetupPacket.wLength = (ushort)(nBytes - Marshal.SizeOf(Request1));
-				Request1.SetupPacket.wIndex = 0; // 0x409; // Language Code
-
-				// Use an IOCTL call to request the String Descriptor
-				Byte[] buffer = new Byte[nBytes];
-				fixed (Byte* bufferptr = buffer) {
-					if (!Kernel32.DeviceIoControl(handel, UsbApi.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ref Request1, Marshal.SizeOf(typeof(USB_DESCRIPTOR_REQUEST)), (IntPtr)bufferptr, nBytes, out nBytesReturned, IntPtr.Zero)) {
-						int err = Marshal.GetLastWin32Error();
-						Console.WriteLine("IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION returned {0} {1}", err, (new System.ComponentModel.Win32Exception(err)).Message);
-						//SerialNumber = (new System.ComponentModel.Win32Exception(err)).Message;
-						if (err != 2 && err != 31 && err != 87) throw new System.ComponentModel.Win32Exception(err);
-					} else {
-						if (nBytesReturned > nBytes) throw new IndexOutOfRangeException("IOCtl returned too much data");
-						if (nBytesReturned < 0) throw new IndexOutOfRangeException("IOCtl returned insufficient data");
-						Byte* ptr = bufferptr + Marshal.SizeOf(Request1);
-						nBytesReturned -= Marshal.SizeOf(Request1);
-						if (nBytesReturned < 0) throw new IndexOutOfRangeException("IOCtl returned insufficient data");
+		}
 
-						int offset = 0;
-						while (offset < nBytesReturned) {
-							if (offset + Marshal.SizeOf(typeof(USB_DESCRIPTOR)) >= nBytesReturned) throw new IndexOutOfRangeException("Error in configuration descriptor");
-							USB_DESCRIPTOR* desc = (USB_DESCRIPTOR*)(ptr + offset);
-							offset += desc->bLength;
-							if (offset > nBytesReturned) throw new IndexOutOfRangeException("Error in configuration descriptor");
-							Console.WriteLine("Descriptor type {0} length {1}", desc->bDescriptorType, desc->bLength);
-							if (desc->bDescriptorType == USB_DESCRIPTOR_TYPE.ConfigurationDescriptorType) {
-								if (desc->bLength < 9) throw new IndexOutOfRangeException("Error in configuration descriptor");
-								USB_CONFIGURATION_DESCRIPTOR configurationDescriptor = *(USB_CONFIGURATION_DESCRIPTOR*)desc;
-								ConfigurationDescriptor.Add(configurationDescriptor);
-							} else if (desc->bDescriptorType == USB_DESCRIPTOR_TYPE.InterfaceDescriptorType) {
-								if (desc->bLength < 9) throw new IndexOutOfRangeException("Error in configuration descriptor");
-								USB_INTERFACE_DESCRIPTOR interfaceDescriptor = *(USB_INTERFACE_DESCRIPTOR*)desc;
-								InterfaceDescriptor.Add(interfaceDescriptor);
-							} else if (desc->bDescriptorType == USB_DESCRIPTOR_TYPE.EndpointDescriptorType) {
-								if (desc->bLength < 7) throw new IndexOutOfRangeException("Error in configuration descriptor");
-								USB_ENDPOINT_DESCRIPTOR endpointDescriptor1 = *(USB_ENDPOINT_DESCRIPTOR*)desc;
-								EndpointDescriptor.Add(endpointDescriptor1);
-							}
-						}
-					}
-					// 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 (DeviceDescriptor != null) {
-						if (DeviceDescriptor.iManufacturer > 0) Manufacturer = GetStringDescriptor(handel, DeviceDescriptor.iManufacturer);
-						if (DeviceDescriptor.iProduct > 0) Product = GetStringDescriptor(handel, DeviceDescriptor.iProduct);
-						if (DeviceDescriptor.iSerialNumber > 0) SerialNumber = GetStringDescriptor(handel, DeviceDescriptor.iSerialNumber);
-					}
-				}
-				// Get the Driver Key Name (usefull in locating a device)
-				USB_NODE_CONNECTION_DRIVERKEY_NAME DriverKeyStruct = new USB_NODE_CONNECTION_DRIVERKEY_NAME();
-				DriverKeyStruct.ConnectionIndex = adapterNumber;
-				// Use an IOCTL call to request the Driver Key Name
-				if (Kernel32.DeviceIoControl(handel, UsbApi.IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, ref DriverKeyStruct, Marshal.SizeOf(DriverKeyStruct), out DriverKeyStruct, Marshal.SizeOf(DriverKeyStruct), out nBytesReturned, IntPtr.Zero)) {
-					DriverKey = DriverKeyStruct.DriverKeyName;
-				}
-			}
+		private String GetStringDescriptor(Byte index) {
+			return UsbStringDescriptor.GetStringFromDevice(this, index, 0); //0x409
 		}
 
-		private unsafe String GetStringDescriptor(SafeFileHandle handel, Byte id) {
-			int nBytes = UsbApi.MAX_BUFFER_SIZE;
-			int nBytesReturned = 0;
-			Byte[] buffer = new Byte[nBytes];
-			fixed (Byte* bufferptr = buffer) {
-				// Build a request for string descriptor.
-				USB_DESCRIPTOR_REQUEST Request = new USB_DESCRIPTOR_REQUEST();
-				Request.ConnectionIndex = AdapterNumber;
-				Request.SetupPacket.wValue = (ushort)((UsbApi.USB_STRING_DESCRIPTOR_TYPE << 8) + id);
-				Request.SetupPacket.wLength = (ushort)(nBytes - Marshal.SizeOf(Request));
-				Request.SetupPacket.wIndex = 0x409; // The language code.
-				// Use an IOCTL call to request the string descriptor.
-				if (Kernel32.DeviceIoControl(handel, UsbApi.IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ref Request, Marshal.SizeOf(Request), (IntPtr)bufferptr, nBytes, out nBytesReturned, IntPtr.Zero)) {
-					if (nBytesReturned < nBytes) buffer[nBytesReturned] = 0;
-					if (nBytesReturned + 1 < nBytes) buffer[nBytesReturned + 1] = 0;
-					// 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
-					//*(UsbApi.USB_STRING_DESCRIPTOR*)(bufferptr + Marshal.SizeOf(Request));
-					USB_STRING_DESCRIPTOR StringDesc = (USB_STRING_DESCRIPTOR)Marshal.PtrToStructure((IntPtr)(bufferptr + Marshal.SizeOf(Request)), typeof(USB_STRING_DESCRIPTOR));
-					//return StringDesc.bString;
-					int len = Math.Min(nBytesReturned - Marshal.SizeOf(Request) - 2, StringDesc.bLength);
-					return Encoding.Unicode.GetString(buffer, 2 + Marshal.SizeOf(Request), len);
-				} else {
-					return null;
+		static UsbDevice GetUsbDevice(DeviceNode node, out Boolean isHostController) {
+			String[] hciinterface = node.GetInterfaces(UsbApi.GUID_DEVINTERFACE_USB_HOST_CONTROLLER);
+			if (hciinterface != null && hciinterface.Length > 0) {
+				isHostController = true;
+				return (new UsbController(null, node, hciinterface[0])).RootHub;
+			}
+			isHostController = false;
+			DeviceNode parent = node.GetParent();
+			Boolean isHostControllerA;
+			UsbDevice usbdev = GetUsbDevice(parent, out isHostControllerA);
+			if (isHostControllerA) return usbdev;
+			UsbHub usbhub = usbdev as UsbHub;
+			if (usbhub == null) return null;
+			String driverkey = node.DriverKey;
+			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);
+			/*
+
+			String[] hubinterface = node.GetInterfaces(UsbApi.GUID_DEVINTERFACE_USB_HUB);
+			if (hubinterface != null && hubinterface.Length > 0) {
+				USB_NODE_CONNECTION_INFORMATION_EX nodeConnection;
+				using (SafeFileHandle handle = OpenHandle(hubinterface[0])) {
+					if (!GetNodeConnectionInformation(handle, 0, out nodeConnection)) return null;
 				}
+				return new UsbHub(null, nodeConnection, hubinterface[0], false);
 			}
-		}
-
-		/*public static UsbDevice GetUsbDevice(DeviceNode node) {
-			String[] hubinterface = node.GetInterfaces(UsbApi.GUID_DEVINTERFACE_USB_HUB);
-			if (hubinterface != null && hubinterface.Length > 0) return new UsbHub(null, hubinterface[0], false);
 			String[] devinterface = node.GetInterfaces(UsbApi.GUID_DEVINTERFACE_USB_DEVICE);
-			if (devinterface == null || devinterface.Length == 0) throw new InvalidOperationException("Device is not an USB device");
+			if (devinterface == null || devinterface.Length == 0) return null;
 			DeviceNode parent = node.GetParent();
-			if (parent == null) throw new InvalidOperationException("Could not find parent hub device");
+			if (parent == null) return null;
 			UsbHub usbhub = GetUsbDevice(parent) as UsbHub;
-			if (usbhub == null) throw new InvalidOperationException("Could not find parent hub device");
+			if (usbhub == null) return null;
 			String driverkey = node.DriverKey;
 			foreach (UsbDevice usbdev in usbhub.Devices) {
 				if (driverkey.Equals(usbdev.DriverKey, StringComparison.InvariantCultureIgnoreCase)) return usbdev;
 			}
-			throw new InvalidOperationException("Could not find device on parent hub");
-			//return null;
-		}*/
+			return null;*/
+		}
+
+		#region IUsbInterface Members
+		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(); }
+		int IUsbInterface.InterruptWrite(byte endpoint, byte[] buffer, int offset, int length) { throw new NotImplementedException(); }
+		int IUsbInterface.InterruptRead(byte endpoint, byte[] buffer, int offset, int length) { throw new NotImplementedException(); }
+		void IUsbInterface.InterruptReset(byte endpoint) { throw new NotImplementedException(); }
+		int IUsbInterface.ControlWrite(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { throw new NotImplementedException(); }
+		int IUsbInterface.ControlRead(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { throw new NotImplementedException(); }
+		UsbPipeStream IUsbInterface.GetBulkStream(byte endpoint) { throw new NotImplementedException(); }
+		UsbPipeStream IUsbInterface.GetInterruptStream(byte endpoint) { throw new NotImplementedException(); }
+		void IDisposable.Dispose() { }
+		#endregion
 	}
-}
\ No newline at end of file
+	
+}
--- a/USBLib/Windows/USB/UsbHub.cs	Wed Oct 09 13:56:35 2013 +0200
+++ b/USBLib/Windows/USB/UsbHub.cs	Wed Oct 09 20:56:28 2013 +0200
@@ -3,74 +3,70 @@
 using System.Runtime.InteropServices;
 using Microsoft.Win32.SafeHandles;
 using UCIS.USBLib.Internal.Windows;
+using System.ComponentModel;
+using UCIS.USBLib.Communication;
 
 namespace UCIS.HWLib.Windows.USB {
 	public class UsbHub : UsbDevice {
-		public int PortCount { get; private set; }
-		public bool IsBusPowered { get; private set; }
 		public bool IsRootHub { get; private set; }
 		internal USB_NODE_INFORMATION NodeInformation { get; private set; }
-		private List<UsbDevice> devices = new List<UsbDevice>();
-		public IList<UsbDevice> Devices { get { return devices.AsReadOnly(); } }
+
+		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 UsbHub(UsbController parent, USB_DEVICE_DESCRIPTOR deviceDescriptor, string devicePath)
-			: this(null, deviceDescriptor, devicePath, true) { }
-		internal UsbHub(UsbDevice parent, USB_DEVICE_DESCRIPTOR deviceDescriptor, string devicePath, Boolean roothub)
-			: base(parent, deviceDescriptor, 0, devicePath) {
-			this.IsRootHub = roothub;
 
-			// TODO: Get the driver key name for the root hub.
-			// Now let's open the hub (based upon the hub name we got above).
-			using (SafeFileHandle handel2 = Kernel32.CreateFile(this.DevicePath, Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_WRITE, IntPtr.Zero, Kernel32.OPEN_EXISTING, 0, IntPtr.Zero)) {
-				if (handel2.IsInvalid) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
-				USB_NODE_INFORMATION NodeInfo = new USB_NODE_INFORMATION();
-				int nBytes = Marshal.SizeOf(typeof(USB_NODE_INFORMATION)); // Marshal.SizeOf(NodeInfo);
-				// Get the hub information.
-				int nBytesReturned = -1;
-				if (Kernel32.DeviceIoControl(handel2, UsbApi.IOCTL_USB_GET_NODE_INFORMATION, ref NodeInfo, nBytes, out NodeInfo, nBytes, out nBytesReturned, IntPtr.Zero)) {
-					this.NodeInformation = NodeInfo;
-					this.IsBusPowered = Convert.ToBoolean(NodeInfo.HubInformation.HubIsBusPowered);
-					this.PortCount = NodeInfo.HubInformation.HubDescriptor.bNumberOfPorts;
-				}
-
-				for (uint index = 1; index <= PortCount; index++) {
-					devices.Add(BuildDevice(this, index, this.DevicePath, handel2));
-				}
+		public override string DriverKey {
+			get {
+				if (Parent == null) return null;
+				using (SafeFileHandle handle = OpenHandle(Parent.DevicePath)) return UsbHub.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 static UsbDevice BuildDevice(UsbDevice parent, uint portCount, string devicePath, SafeFileHandle handel1) {
-			int nBytesReturned;
-			int nBytes = Marshal.SizeOf(typeof(USB_NODE_CONNECTION_INFORMATION_EX));
-			USB_NODE_CONNECTION_INFORMATION_EX nodeConnection = new USB_NODE_CONNECTION_INFORMATION_EX();
-			nodeConnection.ConnectionIndex = portCount;
+		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 UsbHub.GetDescriptor(handle, AdapterNumber, descriptorType, index, langId, buffer, offset, length);
+		}
+
 
-			//DateTime t = DateTime.Now;
-			if (!Kernel32.DeviceIoControl(handel1, UsbApi.IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, ref nodeConnection, nBytes, out nodeConnection, nBytes, out nBytesReturned, IntPtr.Zero))
-				throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
-			//Console.WriteLine("IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX took {0} ms (class={1})", DateTime.Now.Subtract(t).TotalMilliseconds, nodeConnection.DeviceDescriptor.bDeviceClass);
-			bool isConnected = (nodeConnection.ConnectionStatus == USB_CONNECTION_STATUS.DeviceConnected);
+		public IList<UsbDevice> Devices {
+			get {
+				List<UsbDevice> devices = new List<UsbDevice>();
+				using (SafeFileHandle handle = OpenHandle(DevicePath)) {
+					for (uint index = 1; index <= PortCount; index++) {
+						devices.Add(BuildDevice(this, index, this.DevicePath, handle));
+					}
+				}
+				return devices;
+			}
+		}
 
-			UsbDevice _Device = null;
-			if (!isConnected) {
-				_Device = new UsbDevice(parent, null, portCount);
+		internal static UsbDevice BuildDevice(UsbDevice parent, uint portCount, string devicePath) {
+			using (SafeFileHandle handle = OpenHandle(devicePath)) return BuildDevice(parent, portCount, devicePath, handle);
+		}
+		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.bDeviceClass == UsbDeviceClass.HubDevice) {
-				nBytes = Marshal.SizeOf(typeof(USB_NODE_CONNECTION_NAME));
-				USB_NODE_CONNECTION_NAME nameConnection = new USB_NODE_CONNECTION_NAME();
-				nameConnection.ConnectionIndex = portCount;
-				if (!Kernel32.DeviceIoControl(handel1, UsbApi.IOCTL_USB_GET_NODE_CONNECTION_NAME, ref nameConnection, nBytes, out nameConnection, nBytes, out nBytesReturned, IntPtr.Zero))
-					throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
-				_Device = new UsbHub(parent, nodeConnection.DeviceDescriptor, @"\\?\" + nameConnection.NodeName, false);
+				String nodeName = GetNodeConnectionName(handle, portCount);
+				device = new UsbHub(parent, nodeConnection, @"\\?\" + nodeName, portCount, false);
 			} else {
-				_Device = new UsbDevice(parent, nodeConnection.DeviceDescriptor, portCount, devicePath);
+				device = new UsbDevice(parent, nodeConnection, portCount, devicePath);
 			}
-			_Device.NodeConnectionInfo = nodeConnection;
-			_Device.AdapterNumber = _Device.NodeConnectionInfo.ConnectionIndex;
-			_Device.Status = ((USB_CONNECTION_STATUS)_Device.NodeConnectionInfo.ConnectionStatus).ToString();
-			_Device.Speed = ((USB_DEVICE_SPEED)_Device.NodeConnectionInfo.Speed).ToString();
-			_Device.IsConnected = isConnected;
-			_Device.IsHub = Convert.ToBoolean(_Device.NodeConnectionInfo.DeviceIsHub);
-			return _Device;
+			device.NodeConnectionInfo = nodeConnection;
+			return device;
 		}
 	}
-}
\ No newline at end of file
+}