comparison 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
comparison
equal deleted inserted replaced
20:c873e3dd73fe 21:dcfec2be27c9
1 using System;
2 using System.ComponentModel;
3 using System.Runtime.InteropServices;
4 using System.Security;
5 using Microsoft.Win32.SafeHandles;
6 using UCIS.USBLib.Internal.Windows;
7
8 namespace UCIS.USBLib.Communication.WinUsb {
9 class SafeWinUsbInterfaceHandle : SafeHandleZeroOrMinusOneIsInvalid {
10 public SafeWinUsbInterfaceHandle() : base(true) { }
11 protected override bool ReleaseHandle() {
12 if (IsInvalid) return true;
13 bool bSuccess = WinUsbDevice.WinUsb_Free(handle);
14 handle = IntPtr.Zero;
15 return bSuccess;
16 }
17 }
18 [StructLayout(LayoutKind.Sequential, Pack = 1)]
19 struct UsbSetupPacket {
20 public byte RequestType;
21 public byte Request;
22 public short Value;
23 public short Index;
24 public short Length;
25 public UsbSetupPacket(byte requestType, byte request, short value, short index, short length) {
26 RequestType = requestType;
27 Request = request;
28 Value = value;
29 Index = index;
30 Length = length;
31 }
32 }
33 [SuppressUnmanagedCodeSecurity]
34 public class WinUsbDevice : UsbInterface, IUsbDevice {
35 const string WIN_USB_DLL = "winusb.dll";
36 [DllImport(WIN_USB_DLL, SetLastError = true)]
37 static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle, out SafeWinUsbInterfaceHandle InterfaceHandle);
38 [DllImport(WIN_USB_DLL, SetLastError = true)]
39 internal static extern bool WinUsb_GetAssociatedInterface(SafeWinUsbInterfaceHandle InterfaceHandle, byte AssociatedInterfaceIndex, out SafeWinUsbInterfaceHandle AssociatedInterfaceHandle);
40 [DllImport(WIN_USB_DLL, SetLastError = true)]
41 internal static extern bool WinUsb_Free(IntPtr InterfaceHandle);
42 [DllImport(WIN_USB_DLL, SetLastError = true)]
43 private static extern bool WinUsb_AbortPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID);
44 [DllImport(WIN_USB_DLL, SetLastError = true)]
45 private static extern bool WinUsb_ControlTransfer(SafeWinUsbInterfaceHandle InterfaceHandle, UsbSetupPacket SetupPacket, IntPtr Buffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED);
46 [DllImport(WIN_USB_DLL, SetLastError = true)]
47 private static extern bool WinUsb_FlushPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID);
48 [DllImport(WIN_USB_DLL, SetLastError = true)]
49 private static extern bool WinUsb_GetDescriptor(SafeWinUsbInterfaceHandle InterfaceHandle, byte DescriptorType, byte Index, ushort LanguageID, IntPtr Buffer, int BufferLength, out int LengthTransferred);
50 [DllImport(WIN_USB_DLL, SetLastError = true)]
51 private static extern bool WinUsb_ReadPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, Byte[] Buffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED);
52 [DllImport(WIN_USB_DLL, SetLastError = true)]
53 private static extern bool WinUsb_ReadPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, IntPtr pBuffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED);
54 [DllImport(WIN_USB_DLL, SetLastError = true)]
55 private static extern bool WinUsb_ResetPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID);
56 [DllImport(WIN_USB_DLL, SetLastError = true)]
57 private static extern bool WinUsb_WritePipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, Byte[] Buffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED);
58 [DllImport(WIN_USB_DLL, SetLastError = true)]
59 private static extern bool WinUsb_WritePipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, IntPtr pBuffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED);
60 //[DllImport(WIN_USB_DLL, SetLastError = true)]
61 //private static extern bool WinUsb_SetPipePolicy(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, UInt32 PolicyType, UInt32 ValueLength, ref Byte Value);
62 SafeFileHandle DeviceHandle;
63 private SafeWinUsbInterfaceHandle[] InterfaceHandles = null;
64 private int[] EndpointToInterfaceIn = new int[0];
65 private int[] EndpointToInterfaceOut = new int[0];
66 public IUsbDeviceRegistry Registry { get; private set; }
67
68 public WinUsbDevice(String path, WinUsbRegistry registry) {
69 this.Registry = registry;
70 DeviceHandle = Kernel32.CreateFile(path,
71 NativeFileAccess.FILE_GENERIC_WRITE | NativeFileAccess.FILE_GENERIC_READ,
72 NativeFileShare.FILE_SHARE_WRITE | NativeFileShare.FILE_SHARE_READ,
73 IntPtr.Zero,
74 NativeFileMode.OPEN_EXISTING,
75 NativeFileFlag.FILE_ATTRIBUTE_NORMAL | NativeFileFlag.FILE_FLAG_OVERLAPPED,
76 IntPtr.Zero);
77 if (DeviceHandle.IsInvalid || DeviceHandle.IsClosed) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open device");
78 SafeWinUsbInterfaceHandle InterfaceHandle;
79 if (!WinUsb_Initialize(DeviceHandle, out InterfaceHandle)) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not initialize WinUsb");
80 if (InterfaceHandle.IsInvalid || InterfaceHandle.IsClosed) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open interface");
81 InterfaceHandles = new SafeWinUsbInterfaceHandle[1] { InterfaceHandle };
82 foreach (LibUsbDotNet.Info.UsbConfigInfo ci in (new LibUsbDotNet.UsbDevice(this)).Configs) {
83 if (ci.Descriptor.ConfigID == Configuration) {
84 foreach (LibUsbDotNet.Info.UsbInterfaceInfo ifinfo in ci.InterfaceInfoList) {
85 foreach (LibUsbDotNet.Info.UsbEndpointInfo epinfo in ifinfo.EndpointInfoList) {
86 int epidx = epinfo.Descriptor.EndpointID & 0x7F;
87 if ((epinfo.Descriptor.EndpointID & 0x80) != 0) {
88 if (EndpointToInterfaceIn.Length <= epidx) Array.Resize(ref EndpointToInterfaceIn, epidx + 1);
89 EndpointToInterfaceIn[epidx] = ifinfo.Descriptor.InterfaceID;
90 } else {
91 if (EndpointToInterfaceOut.Length <= epidx) Array.Resize(ref EndpointToInterfaceOut, epidx + 1);
92 EndpointToInterfaceOut[epidx] = ifinfo.Descriptor.InterfaceID;
93 }
94 }
95 }
96 }
97 }
98 }
99
100 public void ClaimInterface(int interfaceID) {
101 GetInterfaceHandle(interfaceID);
102 }
103 public void ReleaseInterface(int interfaceID) {
104 if (interfaceID == 0) return;
105 if (InterfaceHandles.Length < interfaceID || InterfaceHandles[interfaceID] == null) return;
106 InterfaceHandles[interfaceID].Close();
107 InterfaceHandles[interfaceID] = null;
108 }
109 void IUsbDevice.ResetDevice() {
110 throw new NotSupportedException();
111 }
112 private SafeWinUsbInterfaceHandle GetInterfaceHandle(int interfaceID) {
113 if (interfaceID == 0) return InterfaceHandles[0];
114 if (interfaceID < 0 || interfaceID > 255) throw new ArgumentOutOfRangeException("interfaceID");
115 if (InterfaceHandles.Length > interfaceID && InterfaceHandles[interfaceID] != null) return InterfaceHandles[interfaceID];
116 SafeWinUsbInterfaceHandle ih;
117 if (!WinUsb_GetAssociatedInterface(InterfaceHandles[0], (Byte)(interfaceID - 1), out ih) || ih.IsInvalid || ih.IsClosed)
118 throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open interface");
119 if (InterfaceHandles.Length <= interfaceID) Array.Resize(ref InterfaceHandles, interfaceID + 1);
120 InterfaceHandles[interfaceID] = ih;
121 return ih;
122 }
123 private SafeWinUsbInterfaceHandle GetInterfaceHandleForEndpoint(int epID) {
124 int epidx = epID & 0x7F;
125 if ((epID & 0x80) != 0) {
126 if (EndpointToInterfaceIn.Length <= epidx) throw new ArgumentOutOfRangeException("endpoint");
127 return GetInterfaceHandle(EndpointToInterfaceIn[epidx]);
128 } else {
129 if (EndpointToInterfaceOut.Length <= epidx) throw new ArgumentOutOfRangeException("endpoint");
130 return GetInterfaceHandle(EndpointToInterfaceOut[epidx]);
131 }
132 }
133
134 public override void Close() {
135 foreach (SafeWinUsbInterfaceHandle ih in InterfaceHandles) ih.Close();
136 InterfaceHandles = new SafeWinUsbInterfaceHandle[0];
137 if (DeviceHandle != null) DeviceHandle.Close();
138 }
139
140 public override Byte Configuration {
141 get { return base.Configuration; }
142 set {
143 if (value == base.Configuration) return;
144 throw new NotSupportedException();
145 }
146 }
147
148 public unsafe int ControlTransfer(byte requestType, byte request, short value, short index, byte[] buffer, int offset, int length) {
149 if (buffer == null) buffer = new Byte[0];
150 if (offset < 0 || length < 0 || length > short.MaxValue || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length");
151 SafeWinUsbInterfaceHandle ih = InterfaceHandles[0];
152 switch ((UsbControlRequestType)requestType & UsbControlRequestType.RecipMask) {
153 case UsbControlRequestType.RecipInterface: ih = GetInterfaceHandle(index & 0xff); break;
154 case UsbControlRequestType.RecipEndpoint: ih = GetInterfaceHandleForEndpoint(index & 0xff); break;
155 case UsbControlRequestType.RecipOther: break;
156 }
157 fixed (Byte* b = buffer) {
158 if (!WinUsb_ControlTransfer(ih,
159 new UsbSetupPacket(requestType, request, value, index, (short)length),
160 (IntPtr)(b + offset), length, out length, IntPtr.Zero))
161 throw new Win32Exception(Marshal.GetLastWin32Error(), "Control transfer failed");
162 return length;
163 }
164 }
165
166 public override int ControlWrite(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) {
167 return ControlTransfer((byte)(requestType | UsbControlRequestType.EndpointOut), request, value, index, buffer, offset, length);
168 }
169
170 public override int ControlRead(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) {
171 return ControlTransfer((byte)(requestType | UsbControlRequestType.EndpointIn), request, value, index, buffer, offset, length);
172 }
173
174 public unsafe override int GetDescriptor(byte descriptorType, byte index, short langId, byte[] buffer, int offset, int length) {
175 if (length > short.MaxValue || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length");
176 fixed (Byte* b = buffer) {
177 if (!WinUsb_GetDescriptor(InterfaceHandles[0], descriptorType, index, (ushort)langId, (IntPtr)(b + offset), length, out length))
178 throw new Win32Exception(Marshal.GetLastWin32Error(), "Descriptor transfer failed");
179 }
180 return length;
181 }
182
183 public unsafe int PipeWrite(byte endpoint, byte[] buffer, int offset, int length) {
184 if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length");
185 SafeWinUsbInterfaceHandle ih = GetInterfaceHandleForEndpoint(endpoint);
186 fixed (Byte* b = buffer) {
187 if (!WinUsb_WritePipe(ih, endpoint, (IntPtr)(b + offset), length, out length, IntPtr.Zero))
188 throw new Win32Exception(Marshal.GetLastWin32Error());
189 }
190 return length;
191 }
192
193 public unsafe int PipeRead(byte endpoint, byte[] buffer, int offset, int length) {
194 if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length");
195 SafeWinUsbInterfaceHandle ih = GetInterfaceHandleForEndpoint(endpoint);
196 fixed (Byte* b = buffer) {
197 if (!WinUsb_ReadPipe(ih, endpoint, (IntPtr)(b + offset), length, out length, IntPtr.Zero))
198 throw new Win32Exception(Marshal.GetLastWin32Error());
199 }
200 return length;
201 }
202
203 public override int BulkWrite(Byte endpoint, Byte[] buffer, int offset, int length) {
204 return PipeWrite(endpoint, buffer, offset, length);
205 }
206 public override int BulkRead(Byte endpoint, Byte[] buffer, int offset, int length) {
207 return PipeRead(endpoint, buffer, offset, length);
208 }
209 public override int InterruptWrite(Byte endpoint, Byte[] buffer, int offset, int length) {
210 return PipeWrite(endpoint, buffer, offset, length);
211 }
212 public override int InterruptRead(Byte endpoint, Byte[] buffer, int offset, int length) {
213 return PipeRead(endpoint, buffer, offset, length);
214 }
215 }
216 }