diff USBLib/Communication/WinUsb/WinUsbDevice.cs @ 21:dcfec2be27c9

Added USBLib
author Ivo Smits <Ivo@UCIS.nl>
date Mon, 15 Apr 2013 01:04:59 +0200
parents
children c4a5dbe62513
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBLib/Communication/WinUsb/WinUsbDevice.cs	Mon Apr 15 01:04:59 2013 +0200
@@ -0,0 +1,216 @@
+using System;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using System.Security;
+using Microsoft.Win32.SafeHandles;
+using UCIS.USBLib.Internal.Windows;
+
+namespace UCIS.USBLib.Communication.WinUsb {
+	class SafeWinUsbInterfaceHandle : SafeHandleZeroOrMinusOneIsInvalid {
+		public SafeWinUsbInterfaceHandle() : base(true) { }
+		protected override bool ReleaseHandle() {
+			if (IsInvalid) return true;
+			bool bSuccess = WinUsbDevice.WinUsb_Free(handle);
+			handle = IntPtr.Zero;
+			return bSuccess;
+		}
+	}
+	[StructLayout(LayoutKind.Sequential, Pack = 1)]
+	struct UsbSetupPacket {
+		public byte RequestType;
+		public byte Request;
+		public short Value;
+		public short Index;
+		public short Length;
+		public UsbSetupPacket(byte requestType, byte request, short value, short index, short length) {
+			RequestType = requestType;
+			Request = request;
+			Value = value;
+			Index = index;
+			Length = length;
+		}
+	}
+	[SuppressUnmanagedCodeSecurity]
+	public class WinUsbDevice : UsbInterface, IUsbDevice {
+		const string WIN_USB_DLL = "winusb.dll";
+		[DllImport(WIN_USB_DLL, SetLastError = true)]
+		static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle, out SafeWinUsbInterfaceHandle InterfaceHandle);
+		[DllImport(WIN_USB_DLL, SetLastError = true)]
+		internal static extern bool WinUsb_GetAssociatedInterface(SafeWinUsbInterfaceHandle InterfaceHandle, byte AssociatedInterfaceIndex, out SafeWinUsbInterfaceHandle AssociatedInterfaceHandle);
+		[DllImport(WIN_USB_DLL, SetLastError = true)]
+		internal static extern bool WinUsb_Free(IntPtr InterfaceHandle);
+		[DllImport(WIN_USB_DLL, SetLastError = true)]
+		private static extern bool WinUsb_AbortPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID);
+		[DllImport(WIN_USB_DLL, SetLastError = true)]
+		private static extern bool WinUsb_ControlTransfer(SafeWinUsbInterfaceHandle InterfaceHandle, UsbSetupPacket SetupPacket, IntPtr Buffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED);
+		[DllImport(WIN_USB_DLL, SetLastError = true)]
+		private static extern bool WinUsb_FlushPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID);
+		[DllImport(WIN_USB_DLL, SetLastError = true)]
+		private static extern bool WinUsb_GetDescriptor(SafeWinUsbInterfaceHandle InterfaceHandle, byte DescriptorType, byte Index, ushort LanguageID, IntPtr Buffer, int BufferLength, out int LengthTransferred);
+		[DllImport(WIN_USB_DLL, SetLastError = true)]
+		private static extern bool WinUsb_ReadPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, Byte[] Buffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED);
+		[DllImport(WIN_USB_DLL, SetLastError = true)]
+		private static extern bool WinUsb_ReadPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, IntPtr pBuffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED);
+		[DllImport(WIN_USB_DLL, SetLastError = true)]
+		private static extern bool WinUsb_ResetPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID);
+		[DllImport(WIN_USB_DLL, SetLastError = true)]
+		private static extern bool WinUsb_WritePipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, Byte[] Buffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED);
+		[DllImport(WIN_USB_DLL, SetLastError = true)]
+		private static extern bool WinUsb_WritePipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, IntPtr pBuffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED);
+		//[DllImport(WIN_USB_DLL, SetLastError = true)]
+		//private static extern bool WinUsb_SetPipePolicy(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, UInt32 PolicyType, UInt32 ValueLength, ref Byte Value);
+		SafeFileHandle DeviceHandle;
+		private SafeWinUsbInterfaceHandle[] InterfaceHandles = null;
+		private int[] EndpointToInterfaceIn = new int[0];
+		private int[] EndpointToInterfaceOut = new int[0];
+		public IUsbDeviceRegistry Registry { get; private set; }
+
+		public WinUsbDevice(String path, WinUsbRegistry registry) {
+			this.Registry = registry;
+			DeviceHandle = Kernel32.CreateFile(path,
+				NativeFileAccess.FILE_GENERIC_WRITE | NativeFileAccess.FILE_GENERIC_READ,
+				NativeFileShare.FILE_SHARE_WRITE | NativeFileShare.FILE_SHARE_READ,
+				IntPtr.Zero,
+				NativeFileMode.OPEN_EXISTING,
+				NativeFileFlag.FILE_ATTRIBUTE_NORMAL | NativeFileFlag.FILE_FLAG_OVERLAPPED,
+				IntPtr.Zero);
+			if (DeviceHandle.IsInvalid || DeviceHandle.IsClosed) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open device");
+			SafeWinUsbInterfaceHandle InterfaceHandle;
+			if (!WinUsb_Initialize(DeviceHandle, out InterfaceHandle)) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not initialize WinUsb");
+			if (InterfaceHandle.IsInvalid || InterfaceHandle.IsClosed) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open interface");
+			InterfaceHandles = new SafeWinUsbInterfaceHandle[1] { InterfaceHandle };
+			foreach (LibUsbDotNet.Info.UsbConfigInfo ci in (new LibUsbDotNet.UsbDevice(this)).Configs) {
+				if (ci.Descriptor.ConfigID == Configuration) {
+					foreach (LibUsbDotNet.Info.UsbInterfaceInfo ifinfo in ci.InterfaceInfoList) {
+						foreach (LibUsbDotNet.Info.UsbEndpointInfo epinfo in ifinfo.EndpointInfoList) {
+							int epidx = epinfo.Descriptor.EndpointID & 0x7F;
+							if ((epinfo.Descriptor.EndpointID & 0x80) != 0) {
+								if (EndpointToInterfaceIn.Length <= epidx) Array.Resize(ref EndpointToInterfaceIn, epidx + 1);
+								EndpointToInterfaceIn[epidx] = ifinfo.Descriptor.InterfaceID;
+							} else {
+								if (EndpointToInterfaceOut.Length <= epidx) Array.Resize(ref EndpointToInterfaceOut, epidx + 1);
+								EndpointToInterfaceOut[epidx] = ifinfo.Descriptor.InterfaceID;
+							}
+						}
+					}
+				}
+			}
+		}
+
+		public void ClaimInterface(int interfaceID) {
+			GetInterfaceHandle(interfaceID);
+		}
+		public void ReleaseInterface(int interfaceID) {
+			if (interfaceID == 0) return;
+			if (InterfaceHandles.Length < interfaceID || InterfaceHandles[interfaceID] == null) return;
+			InterfaceHandles[interfaceID].Close();
+			InterfaceHandles[interfaceID] = null;
+		}
+		void IUsbDevice.ResetDevice() {
+			throw new NotSupportedException();
+		}
+		private SafeWinUsbInterfaceHandle GetInterfaceHandle(int interfaceID) {
+			if (interfaceID == 0) return InterfaceHandles[0];
+			if (interfaceID < 0 || interfaceID > 255) throw new ArgumentOutOfRangeException("interfaceID");
+			if (InterfaceHandles.Length > interfaceID && InterfaceHandles[interfaceID] != null) return InterfaceHandles[interfaceID];
+			SafeWinUsbInterfaceHandle ih;
+			if (!WinUsb_GetAssociatedInterface(InterfaceHandles[0], (Byte)(interfaceID - 1), out ih) || ih.IsInvalid || ih.IsClosed)
+				throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open interface");
+			if (InterfaceHandles.Length <= interfaceID) Array.Resize(ref InterfaceHandles, interfaceID + 1);
+			InterfaceHandles[interfaceID] = ih;
+			return ih;
+		}
+		private SafeWinUsbInterfaceHandle GetInterfaceHandleForEndpoint(int epID) {
+			int epidx = epID & 0x7F;
+			if ((epID & 0x80) != 0) {
+				if (EndpointToInterfaceIn.Length <= epidx) throw new ArgumentOutOfRangeException("endpoint");
+				return GetInterfaceHandle(EndpointToInterfaceIn[epidx]);
+			} else {
+				if (EndpointToInterfaceOut.Length <= epidx) throw new ArgumentOutOfRangeException("endpoint");
+				return GetInterfaceHandle(EndpointToInterfaceOut[epidx]);
+			}
+		}
+
+		public override void Close() {
+			foreach (SafeWinUsbInterfaceHandle ih in InterfaceHandles) ih.Close();
+			InterfaceHandles = new SafeWinUsbInterfaceHandle[0];
+			if (DeviceHandle != null) DeviceHandle.Close();
+		}
+
+		public override Byte Configuration {
+			get { return base.Configuration; }
+			set {
+				if (value == base.Configuration) return;
+				throw new NotSupportedException();
+			}
+		}
+
+		public unsafe int ControlTransfer(byte requestType, byte request, short value, short index, byte[] buffer, int offset, int length) {
+			if (buffer == null) buffer = new Byte[0];
+			if (offset < 0 || length < 0 || length > short.MaxValue || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length");
+			SafeWinUsbInterfaceHandle ih = InterfaceHandles[0];
+			switch ((UsbControlRequestType)requestType & UsbControlRequestType.RecipMask) {
+				case UsbControlRequestType.RecipInterface: ih = GetInterfaceHandle(index & 0xff); break;
+				case UsbControlRequestType.RecipEndpoint: ih = GetInterfaceHandleForEndpoint(index & 0xff); break;
+				case UsbControlRequestType.RecipOther: break;
+			}
+			fixed (Byte* b = buffer) {
+				if (!WinUsb_ControlTransfer(ih,
+					new UsbSetupPacket(requestType, request, value, index, (short)length),
+					(IntPtr)(b + offset), length, out length, IntPtr.Zero))
+					throw new Win32Exception(Marshal.GetLastWin32Error(), "Control transfer failed");
+				return length;
+			}
+		}
+
+		public override int ControlWrite(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) {
+			return ControlTransfer((byte)(requestType | UsbControlRequestType.EndpointOut), 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((byte)(requestType | UsbControlRequestType.EndpointIn), request, value, index, buffer, offset, length);
+		}
+
+		public unsafe override int GetDescriptor(byte descriptorType, byte index, short langId, byte[] buffer, int offset, int length) {
+			if (length > short.MaxValue || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length");
+			fixed (Byte* b = buffer) {
+				if (!WinUsb_GetDescriptor(InterfaceHandles[0], descriptorType, index, (ushort)langId, (IntPtr)(b + offset), length, out length))
+					throw new Win32Exception(Marshal.GetLastWin32Error(), "Descriptor transfer failed");
+			}
+			return length;
+		}
+
+		public unsafe int PipeWrite(byte endpoint, byte[] buffer, int offset, int length) {
+			if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length");
+			SafeWinUsbInterfaceHandle ih = GetInterfaceHandleForEndpoint(endpoint);
+			fixed (Byte* b = buffer) {
+				if (!WinUsb_WritePipe(ih, endpoint, (IntPtr)(b + offset), length, out length, IntPtr.Zero))
+						throw new Win32Exception(Marshal.GetLastWin32Error());
+			}
+			return length;
+		}
+
+		public unsafe int PipeRead(byte endpoint, byte[] buffer, int offset, int length) {
+			if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length");
+			SafeWinUsbInterfaceHandle ih = GetInterfaceHandleForEndpoint(endpoint);
+			fixed (Byte* b = buffer) {
+				if (!WinUsb_ReadPipe(ih, endpoint, (IntPtr)(b + offset), length, out length, IntPtr.Zero))
+					throw new Win32Exception(Marshal.GetLastWin32Error());
+			}
+			return length;
+		}
+
+		public override int BulkWrite(Byte endpoint, Byte[] buffer, int offset, int length) {
+			return PipeWrite(endpoint, buffer, offset, length);
+		}
+		public override int BulkRead(Byte endpoint, Byte[] buffer, int offset, int length) {
+			return PipeRead(endpoint, buffer, offset, length);
+		}
+		public override int InterruptWrite(Byte endpoint, Byte[] buffer, int offset, int length) {
+			return PipeWrite(endpoint, buffer, offset, length);
+		}
+		public override int InterruptRead(Byte endpoint, Byte[] buffer, int offset, int length) {
+			return PipeRead(endpoint, buffer, offset, length);
+		}
+	}
+}
\ No newline at end of file