21
|
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 } |