Mercurial > hg > ucis.core
annotate USBLib/Communication/WinUsb/WinUsbDevice.cs @ 111:df53bdd49507 default tip
Merge
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Fri, 07 Nov 2014 18:37:39 +0100 |
parents | e811297f5aa4 |
children |
rev | line source |
---|---|
21 | 1 ???using System; |
2 using System.ComponentModel; | |
3 using System.Runtime.InteropServices; | |
4 using System.Security; | |
5 using Microsoft.Win32.SafeHandles; | |
68
e811297f5aa4
Updated USBLib: removed old LibUsbDotNet compatibility code and added new information helper classes
Ivo Smits <Ivo@UCIS.nl>
parents:
67
diff
changeset
|
6 using UCIS.USBLib.Descriptor; |
21 | 7 using UCIS.USBLib.Internal.Windows; |
8 | |
9 namespace UCIS.USBLib.Communication.WinUsb { | |
10 class SafeWinUsbInterfaceHandle : SafeHandleZeroOrMinusOneIsInvalid { | |
11 public SafeWinUsbInterfaceHandle() : base(true) { } | |
12 protected override bool ReleaseHandle() { | |
13 if (IsInvalid) return true; | |
14 bool bSuccess = WinUsbDevice.WinUsb_Free(handle); | |
15 handle = IntPtr.Zero; | |
16 return bSuccess; | |
17 } | |
18 } | |
19 [StructLayout(LayoutKind.Sequential, Pack = 1)] | |
20 struct UsbSetupPacket { | |
21 public byte RequestType; | |
22 public byte Request; | |
23 public short Value; | |
24 public short Index; | |
25 public short Length; | |
26 public UsbSetupPacket(byte requestType, byte request, short value, short index, short length) { | |
27 RequestType = requestType; | |
28 Request = request; | |
29 Value = value; | |
30 Index = index; | |
31 Length = length; | |
32 } | |
33 } | |
34 [SuppressUnmanagedCodeSecurity] | |
35 public class WinUsbDevice : UsbInterface, IUsbDevice { | |
36 const string WIN_USB_DLL = "winusb.dll"; | |
37 [DllImport(WIN_USB_DLL, SetLastError = true)] | |
38 static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle, out SafeWinUsbInterfaceHandle InterfaceHandle); | |
39 [DllImport(WIN_USB_DLL, SetLastError = true)] | |
40 internal static extern bool WinUsb_GetAssociatedInterface(SafeWinUsbInterfaceHandle InterfaceHandle, byte AssociatedInterfaceIndex, out SafeWinUsbInterfaceHandle AssociatedInterfaceHandle); | |
41 [DllImport(WIN_USB_DLL, SetLastError = true)] | |
42 internal static extern bool WinUsb_Free(IntPtr InterfaceHandle); | |
43 [DllImport(WIN_USB_DLL, SetLastError = true)] | |
44 private static extern bool WinUsb_AbortPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID); | |
45 [DllImport(WIN_USB_DLL, SetLastError = true)] | |
46 private static extern bool WinUsb_ControlTransfer(SafeWinUsbInterfaceHandle InterfaceHandle, UsbSetupPacket SetupPacket, IntPtr Buffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED); | |
47 [DllImport(WIN_USB_DLL, SetLastError = true)] | |
48 private static extern bool WinUsb_FlushPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID); | |
49 [DllImport(WIN_USB_DLL, SetLastError = true)] | |
50 private static extern bool WinUsb_GetDescriptor(SafeWinUsbInterfaceHandle InterfaceHandle, byte DescriptorType, byte Index, ushort LanguageID, IntPtr Buffer, int BufferLength, out int LengthTransferred); | |
51 [DllImport(WIN_USB_DLL, SetLastError = true)] | |
52 private static extern bool WinUsb_ReadPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, Byte[] Buffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED); | |
53 [DllImport(WIN_USB_DLL, SetLastError = true)] | |
54 private static extern bool WinUsb_ReadPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, IntPtr pBuffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED); | |
55 [DllImport(WIN_USB_DLL, SetLastError = true)] | |
56 private static extern bool WinUsb_ResetPipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID); | |
57 [DllImport(WIN_USB_DLL, SetLastError = true)] | |
58 private static extern bool WinUsb_WritePipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, Byte[] Buffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED); | |
59 [DllImport(WIN_USB_DLL, SetLastError = true)] | |
60 private static extern bool WinUsb_WritePipe(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, IntPtr pBuffer, int BufferLength, out int LengthTransferred, IntPtr pOVERLAPPED); | |
61 //[DllImport(WIN_USB_DLL, SetLastError = true)] | |
62 //private static extern bool WinUsb_SetPipePolicy(SafeWinUsbInterfaceHandle InterfaceHandle, byte PipeID, UInt32 PolicyType, UInt32 ValueLength, ref Byte Value); | |
63 SafeFileHandle DeviceHandle; | |
49
7e4dae99f919
USBLib: fix unhandled exception in WinUSB shutdown after failure to open device
Ivo Smits <Ivo@UCIS.nl>
parents:
46
diff
changeset
|
64 private SafeWinUsbInterfaceHandle[] InterfaceHandles = new SafeWinUsbInterfaceHandle[0]; |
21 | 65 private int[] EndpointToInterfaceIn = new int[0]; |
66 private int[] EndpointToInterfaceOut = new int[0]; | |
67 public IUsbDeviceRegistry Registry { get; private set; } | |
68 | |
69 public WinUsbDevice(String path, WinUsbRegistry registry) { | |
70 this.Registry = registry; | |
71 DeviceHandle = Kernel32.CreateFile(path, | |
72 NativeFileAccess.FILE_GENERIC_WRITE | NativeFileAccess.FILE_GENERIC_READ, | |
73 NativeFileShare.FILE_SHARE_WRITE | NativeFileShare.FILE_SHARE_READ, | |
74 IntPtr.Zero, | |
75 NativeFileMode.OPEN_EXISTING, | |
76 NativeFileFlag.FILE_ATTRIBUTE_NORMAL | NativeFileFlag.FILE_FLAG_OVERLAPPED, | |
77 IntPtr.Zero); | |
78 if (DeviceHandle.IsInvalid || DeviceHandle.IsClosed) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open device"); | |
79 SafeWinUsbInterfaceHandle InterfaceHandle; | |
80 if (!WinUsb_Initialize(DeviceHandle, out InterfaceHandle)) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not initialize WinUsb"); | |
81 if (InterfaceHandle.IsInvalid || InterfaceHandle.IsClosed) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open interface"); | |
82 InterfaceHandles = new SafeWinUsbInterfaceHandle[1] { InterfaceHandle }; | |
68
e811297f5aa4
Updated USBLib: removed old LibUsbDotNet compatibility code and added new information helper classes
Ivo Smits <Ivo@UCIS.nl>
parents:
67
diff
changeset
|
83 foreach (UsbInterfaceInfo ifinfo in UsbDeviceInfo.FromDevice(this).FindConfiguration(Configuration).Interfaces) { |
e811297f5aa4
Updated USBLib: removed old LibUsbDotNet compatibility code and added new information helper classes
Ivo Smits <Ivo@UCIS.nl>
parents:
67
diff
changeset
|
84 foreach (UsbEndpointDescriptor epinfo in ifinfo.Endpoints) { |
e811297f5aa4
Updated USBLib: removed old LibUsbDotNet compatibility code and added new information helper classes
Ivo Smits <Ivo@UCIS.nl>
parents:
67
diff
changeset
|
85 int epidx = epinfo.EndpointAddress & 0x7F; |
e811297f5aa4
Updated USBLib: removed old LibUsbDotNet compatibility code and added new information helper classes
Ivo Smits <Ivo@UCIS.nl>
parents:
67
diff
changeset
|
86 if ((epinfo.EndpointAddress & 0x80) != 0) { |
e811297f5aa4
Updated USBLib: removed old LibUsbDotNet compatibility code and added new information helper classes
Ivo Smits <Ivo@UCIS.nl>
parents:
67
diff
changeset
|
87 if (EndpointToInterfaceIn.Length <= epidx) Array.Resize(ref EndpointToInterfaceIn, epidx + 1); |
e811297f5aa4
Updated USBLib: removed old LibUsbDotNet compatibility code and added new information helper classes
Ivo Smits <Ivo@UCIS.nl>
parents:
67
diff
changeset
|
88 EndpointToInterfaceIn[epidx] = ifinfo.Descriptor.InterfaceNumber; |
e811297f5aa4
Updated USBLib: removed old LibUsbDotNet compatibility code and added new information helper classes
Ivo Smits <Ivo@UCIS.nl>
parents:
67
diff
changeset
|
89 } else { |
e811297f5aa4
Updated USBLib: removed old LibUsbDotNet compatibility code and added new information helper classes
Ivo Smits <Ivo@UCIS.nl>
parents:
67
diff
changeset
|
90 if (EndpointToInterfaceOut.Length <= epidx) Array.Resize(ref EndpointToInterfaceOut, epidx + 1); |
e811297f5aa4
Updated USBLib: removed old LibUsbDotNet compatibility code and added new information helper classes
Ivo Smits <Ivo@UCIS.nl>
parents:
67
diff
changeset
|
91 EndpointToInterfaceOut[epidx] = ifinfo.Descriptor.InterfaceNumber; |
21 | 92 } |
93 } | |
94 } | |
95 } | |
96 | |
97 public void ClaimInterface(int interfaceID) { | |
98 GetInterfaceHandle(interfaceID); | |
99 } | |
100 public void ReleaseInterface(int interfaceID) { | |
101 if (interfaceID == 0) return; | |
102 if (InterfaceHandles.Length < interfaceID || InterfaceHandles[interfaceID] == null) return; | |
103 InterfaceHandles[interfaceID].Close(); | |
104 InterfaceHandles[interfaceID] = null; | |
105 } | |
106 void IUsbDevice.ResetDevice() { | |
107 throw new NotSupportedException(); | |
108 } | |
109 private SafeWinUsbInterfaceHandle GetInterfaceHandle(int interfaceID) { | |
110 if (interfaceID == 0) return InterfaceHandles[0]; | |
111 if (interfaceID < 0 || interfaceID > 255) throw new ArgumentOutOfRangeException("interfaceID"); | |
112 if (InterfaceHandles.Length > interfaceID && InterfaceHandles[interfaceID] != null) return InterfaceHandles[interfaceID]; | |
113 SafeWinUsbInterfaceHandle ih; | |
114 if (!WinUsb_GetAssociatedInterface(InterfaceHandles[0], (Byte)(interfaceID - 1), out ih) || ih.IsInvalid || ih.IsClosed) | |
115 throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open interface"); | |
116 if (InterfaceHandles.Length <= interfaceID) Array.Resize(ref InterfaceHandles, interfaceID + 1); | |
117 InterfaceHandles[interfaceID] = ih; | |
118 return ih; | |
119 } | |
120 private SafeWinUsbInterfaceHandle GetInterfaceHandleForEndpoint(int epID) { | |
121 int epidx = epID & 0x7F; | |
122 if ((epID & 0x80) != 0) { | |
123 if (EndpointToInterfaceIn.Length <= epidx) throw new ArgumentOutOfRangeException("endpoint"); | |
124 return GetInterfaceHandle(EndpointToInterfaceIn[epidx]); | |
125 } else { | |
126 if (EndpointToInterfaceOut.Length <= epidx) throw new ArgumentOutOfRangeException("endpoint"); | |
127 return GetInterfaceHandle(EndpointToInterfaceOut[epidx]); | |
128 } | |
129 } | |
130 | |
131 public override void Close() { | |
49
7e4dae99f919
USBLib: fix unhandled exception in WinUSB shutdown after failure to open device
Ivo Smits <Ivo@UCIS.nl>
parents:
46
diff
changeset
|
132 foreach (SafeWinUsbInterfaceHandle ih in InterfaceHandles) if (ih != null) ih.Close(); |
21 | 133 InterfaceHandles = new SafeWinUsbInterfaceHandle[0]; |
134 if (DeviceHandle != null) DeviceHandle.Close(); | |
135 } | |
136 | |
137 public override Byte Configuration { | |
138 get { return base.Configuration; } | |
139 set { | |
140 if (value == base.Configuration) return; | |
141 throw new NotSupportedException(); | |
142 } | |
143 } | |
144 | |
67
2d16447eff12
Simplified USB communication code, added functions to abort pipe transfers
Ivo Smits <Ivo@UCIS.nl>
parents:
65
diff
changeset
|
145 public override unsafe int ControlTransfer(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { |
21 | 146 if (buffer == null) buffer = new Byte[0]; |
147 if (offset < 0 || length < 0 || length > short.MaxValue || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length"); | |
148 SafeWinUsbInterfaceHandle ih = InterfaceHandles[0]; | |
149 switch ((UsbControlRequestType)requestType & UsbControlRequestType.RecipMask) { | |
150 case UsbControlRequestType.RecipInterface: ih = GetInterfaceHandle(index & 0xff); break; | |
151 case UsbControlRequestType.RecipEndpoint: ih = GetInterfaceHandleForEndpoint(index & 0xff); break; | |
152 case UsbControlRequestType.RecipOther: break; | |
153 } | |
154 fixed (Byte* b = buffer) { | |
155 if (!WinUsb_ControlTransfer(ih, | |
67
2d16447eff12
Simplified USB communication code, added functions to abort pipe transfers
Ivo Smits <Ivo@UCIS.nl>
parents:
65
diff
changeset
|
156 new UsbSetupPacket((byte)requestType, request, value, index, (short)length), |
21 | 157 (IntPtr)(b + offset), length, out length, IntPtr.Zero)) |
158 throw new Win32Exception(Marshal.GetLastWin32Error(), "Control transfer failed"); | |
159 return length; | |
160 } | |
161 } | |
162 | |
163 public unsafe override int GetDescriptor(byte descriptorType, byte index, short langId, byte[] buffer, int offset, int length) { | |
36
c4a5dbe62513
USBLib: small fix in WinUSB backend bounds checking
Ivo Smits <Ivo@UCIS.nl>
parents:
21
diff
changeset
|
164 if (length > short.MaxValue || offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length"); |
21 | 165 fixed (Byte* b = buffer) { |
166 if (!WinUsb_GetDescriptor(InterfaceHandles[0], descriptorType, index, (ushort)langId, (IntPtr)(b + offset), length, out length)) | |
167 throw new Win32Exception(Marshal.GetLastWin32Error(), "Descriptor transfer failed"); | |
168 } | |
169 return length; | |
170 } | |
171 | |
67
2d16447eff12
Simplified USB communication code, added functions to abort pipe transfers
Ivo Smits <Ivo@UCIS.nl>
parents:
65
diff
changeset
|
172 public override unsafe int PipeTransfer(byte endpoint, byte[] buffer, int offset, int length) { |
21 | 173 if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); |
174 SafeWinUsbInterfaceHandle ih = GetInterfaceHandleForEndpoint(endpoint); | |
175 fixed (Byte* b = buffer) { | |
67
2d16447eff12
Simplified USB communication code, added functions to abort pipe transfers
Ivo Smits <Ivo@UCIS.nl>
parents:
65
diff
changeset
|
176 Boolean success; |
2d16447eff12
Simplified USB communication code, added functions to abort pipe transfers
Ivo Smits <Ivo@UCIS.nl>
parents:
65
diff
changeset
|
177 if ((endpoint & (Byte)UsbControlRequestType.EndpointMask) == (Byte)UsbControlRequestType.EndpointOut) |
2d16447eff12
Simplified USB communication code, added functions to abort pipe transfers
Ivo Smits <Ivo@UCIS.nl>
parents:
65
diff
changeset
|
178 success = WinUsb_WritePipe(ih, endpoint, (IntPtr)(b + offset), length, out length, IntPtr.Zero); |
2d16447eff12
Simplified USB communication code, added functions to abort pipe transfers
Ivo Smits <Ivo@UCIS.nl>
parents:
65
diff
changeset
|
179 else |
2d16447eff12
Simplified USB communication code, added functions to abort pipe transfers
Ivo Smits <Ivo@UCIS.nl>
parents:
65
diff
changeset
|
180 success = WinUsb_ReadPipe(ih, endpoint, (IntPtr)(b + offset), length, out length, IntPtr.Zero); |
2d16447eff12
Simplified USB communication code, added functions to abort pipe transfers
Ivo Smits <Ivo@UCIS.nl>
parents:
65
diff
changeset
|
181 if (!success) throw new Win32Exception(Marshal.GetLastWin32Error()); |
21 | 182 } |
183 return length; | |
184 } | |
185 | |
67
2d16447eff12
Simplified USB communication code, added functions to abort pipe transfers
Ivo Smits <Ivo@UCIS.nl>
parents:
65
diff
changeset
|
186 public override void PipeReset(byte endpoint) { |
46
053cc617af54
USBLib: added functions to clear USB endpoint halt state
Ivo Smits <Ivo@UCIS.nl>
parents:
36
diff
changeset
|
187 SafeWinUsbInterfaceHandle ih = GetInterfaceHandleForEndpoint(endpoint); |
053cc617af54
USBLib: added functions to clear USB endpoint halt state
Ivo Smits <Ivo@UCIS.nl>
parents:
36
diff
changeset
|
188 WinUsb_ResetPipe(ih, endpoint); |
053cc617af54
USBLib: added functions to clear USB endpoint halt state
Ivo Smits <Ivo@UCIS.nl>
parents:
36
diff
changeset
|
189 } |
67
2d16447eff12
Simplified USB communication code, added functions to abort pipe transfers
Ivo Smits <Ivo@UCIS.nl>
parents:
65
diff
changeset
|
190 public override void PipeAbort(byte endpoint) { |
2d16447eff12
Simplified USB communication code, added functions to abort pipe transfers
Ivo Smits <Ivo@UCIS.nl>
parents:
65
diff
changeset
|
191 SafeWinUsbInterfaceHandle ih = GetInterfaceHandleForEndpoint(endpoint); |
2d16447eff12
Simplified USB communication code, added functions to abort pipe transfers
Ivo Smits <Ivo@UCIS.nl>
parents:
65
diff
changeset
|
192 WinUsb_AbortPipe(ih, endpoint); |
46
053cc617af54
USBLib: added functions to clear USB endpoint halt state
Ivo Smits <Ivo@UCIS.nl>
parents:
36
diff
changeset
|
193 } |
21 | 194 } |
195 } |