Mercurial > hg > ucis.core
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 +}