Mercurial > hg > ucis.core
comparison USBLib/Communication/LibUsb0/LibUsbDevice.cs @ 21:dcfec2be27c9
Added USBLib
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Mon, 15 Apr 2013 01:04:59 +0200 |
parents | |
children | 053cc617af54 |
comparison
equal
deleted
inserted
replaced
20:c873e3dd73fe | 21:dcfec2be27c9 |
---|---|
1 using System; | |
2 using System.ComponentModel; | |
3 using System.Runtime.InteropServices; | |
4 using System.Threading; | |
5 using Microsoft.Win32.SafeHandles; | |
6 using UCIS.USBLib.Internal.Windows; | |
7 | |
8 namespace UCIS.USBLib.Communication.LibUsb { | |
9 public class LibUsb0Device : UsbInterface, IUsbDevice { | |
10 //private readonly List<int> mClaimedInterfaces = new List<int>(); | |
11 public string DeviceFilename { get; private set; } | |
12 public IUsbDeviceRegistry Registry { get; private set; } | |
13 private SafeFileHandle DeviceHandle; | |
14 | |
15 public LibUsb0Device(String path, LibUsb0Registry registry) { | |
16 DeviceFilename = path; | |
17 this.Registry = registry; | |
18 DeviceHandle = Kernel32.CreateFile(DeviceFilename, | |
19 NativeFileAccess.SPECIAL, | |
20 NativeFileShare.NONE, | |
21 IntPtr.Zero, | |
22 NativeFileMode.OPEN_EXISTING, | |
23 NativeFileFlag.FILE_FLAG_OVERLAPPED, | |
24 IntPtr.Zero); | |
25 if (DeviceHandle.IsInvalid || DeviceHandle.IsClosed) throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not open device"); | |
26 } | |
27 public override void Close() { | |
28 if (DeviceHandle != null) DeviceHandle.Close(); | |
29 } | |
30 | |
31 public override Byte Configuration { | |
32 get { return base.Configuration; } | |
33 set { | |
34 ControlWrite( | |
35 UsbControlRequestType.EndpointOut | UsbControlRequestType.TypeStandard | UsbControlRequestType.RecipDevice, | |
36 (byte)UsbStandardRequest.SetConfiguration, | |
37 value, | |
38 0, null, 0, 0); | |
39 } | |
40 } | |
41 | |
42 public void ClaimInterface(int interfaceID) { | |
43 LibUsbRequest req = new LibUsbRequest(); | |
44 req.Iface.ID = interfaceID; | |
45 req.Timeout = UsbConstants.DEFAULT_TIMEOUT; | |
46 int ret; | |
47 DeviceIoControl(DeviceHandle, LibUsbIoCtl.CLAIM_INTERFACE, ref req, LibUsbRequest.Size, null, 0, out ret); | |
48 } | |
49 public void ReleaseInterface(int interfaceID) { | |
50 LibUsbRequest req = new LibUsbRequest(); | |
51 req.Iface.ID = interfaceID; | |
52 req.Timeout = UsbConstants.DEFAULT_TIMEOUT; | |
53 int ret; | |
54 DeviceIoControl(DeviceHandle, LibUsbIoCtl.RELEASE_INTERFACE, ref req, LibUsbRequest.Size, null, 0, out ret); | |
55 } | |
56 public void SetAltInterface(int interfaceID, int alternateID) { | |
57 LibUsbRequest req = new LibUsbRequest(); | |
58 req.Iface.ID = interfaceID; | |
59 req.Iface.AlternateID = alternateID; | |
60 req.Timeout = UsbConstants.DEFAULT_TIMEOUT; | |
61 int ret; | |
62 DeviceIoControl(DeviceHandle, LibUsbIoCtl.SET_INTERFACE, ref req, LibUsbRequest.Size, null, 0, out ret); | |
63 } | |
64 public void ResetDevice() { | |
65 LibUsbRequest req = new LibUsbRequest(); | |
66 req.Timeout = UsbConstants.DEFAULT_TIMEOUT; | |
67 int ret; | |
68 DeviceIoControl(DeviceHandle, LibUsbIoCtl.RESET_DEVICE, ref req, LibUsbRequest.Size, null, 0, out ret); | |
69 } | |
70 public unsafe override int GetDescriptor(byte descriptorType, byte index, short langId, byte[] buffer, int offset, int length) { | |
71 if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); | |
72 LibUsbRequest req = new LibUsbRequest(); | |
73 req.Descriptor.Index = index; | |
74 req.Descriptor.LangID = langId; | |
75 req.Descriptor.Recipient = (byte)UsbEndpointDirection.EndpointIn & 0x1F; | |
76 req.Descriptor.Type = descriptorType; | |
77 req.Timeout = UsbConstants.DEFAULT_TIMEOUT; | |
78 int ret; | |
79 fixed (Byte* b = buffer) { | |
80 DeviceIoControl(DeviceHandle, LibUsbIoCtl.GET_DESCRIPTOR, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), length, out ret); | |
81 } | |
82 return ret; | |
83 } | |
84 public override int BulkRead(byte endpoint, byte[] buffer, int offset, int length) { | |
85 return PipeTransfer(endpoint, false, false, buffer, offset, length, 0); | |
86 } | |
87 public override int BulkWrite(byte endpoint, byte[] buffer, int offset, int length) { | |
88 return PipeTransfer(endpoint, true, false, buffer, offset, length, 0); | |
89 } | |
90 public override int InterruptRead(byte endpoint, byte[] buffer, int offset, int length) { | |
91 return PipeTransfer(endpoint, false, false, buffer, offset, length, 0); | |
92 } | |
93 public override int InterruptWrite(byte endpoint, byte[] buffer, int offset, int length) { | |
94 return PipeTransfer(endpoint, true, false, buffer, offset, length, 0); | |
95 } | |
96 public unsafe override int ControlRead(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { | |
97 if (buffer == null) buffer = new Byte[0]; | |
98 if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); | |
99 int code; | |
100 LibUsbRequest req = new LibUsbRequest(); | |
101 PrepareControlTransfer(requestType, request, value, index, length, ref req, out code); | |
102 int ret; | |
103 fixed (Byte* b = buffer) { | |
104 DeviceIoControl(DeviceHandle, code, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), length, out ret); | |
105 } | |
106 return ret; | |
107 } | |
108 public unsafe override int ControlWrite(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { | |
109 Byte[] inbuffer = new Byte[length + LibUsbRequest.Size]; | |
110 if (length > 0) Buffer.BlockCopy(buffer, offset, inbuffer, LibUsbRequest.Size, length); | |
111 int code; | |
112 fixed (Byte* inbufferp = inbuffer) | |
113 PrepareControlTransfer(requestType, request, value, index, length, ref *((LibUsbRequest*)inbufferp), out code); | |
114 int ret; | |
115 DeviceIoControl(DeviceHandle, code, inbuffer, length + LibUsbRequest.Size, null, 0, out ret); | |
116 return length; | |
117 //ret -= LibUsbRequest.Size; | |
118 //if (ret <= 0) return 0; | |
119 //return ret; | |
120 } | |
121 void PrepareControlTransfer(UsbControlRequestType requestType, byte request, short value, short index, int length, ref LibUsbRequest req, out int code) { | |
122 code = LibUsbIoCtl.CONTROL_TRANSFER; | |
123 req.Timeout = UsbConstants.DEFAULT_TIMEOUT; | |
124 req.Control.RequestType = (Byte)requestType; | |
125 req.Control.Request = request; | |
126 req.Control.Value = (ushort)value; | |
127 req.Control.Index = (ushort)index; | |
128 req.Control.Length = (ushort)length; | |
129 switch ((UsbControlRequestType)((int)requestType & (0x03 << 5))) { | |
130 case UsbControlRequestType.TypeStandard: | |
131 switch ((UsbStandardRequest)request) { | |
132 case UsbStandardRequest.GetStatus: | |
133 req.Status.Recipient = (int)requestType & 0x1F; | |
134 req.Status.Index = index; | |
135 code = LibUsbIoCtl.GET_STATUS; | |
136 break; | |
137 case UsbStandardRequest.ClearFeature: | |
138 req.Feature.Recipient = (int)requestType & 0x1F; | |
139 req.Feature.ID = value; | |
140 req.Feature.Index = index; | |
141 code = LibUsbIoCtl.CLEAR_FEATURE; | |
142 break; | |
143 case UsbStandardRequest.SetFeature: | |
144 req.Feature.Recipient = (int)requestType & 0x1F; | |
145 req.Feature.ID = value; | |
146 req.Feature.Index = index; | |
147 code = LibUsbIoCtl.SET_FEATURE; | |
148 break; | |
149 case UsbStandardRequest.GetDescriptor: | |
150 req.Descriptor.Recipient = (int)requestType & 0x1F; | |
151 req.Descriptor.Type = (value >> 8) & 0xFF; | |
152 req.Descriptor.Index = value & 0xFF; | |
153 req.Descriptor.LangID = index; | |
154 code = LibUsbIoCtl.GET_DESCRIPTOR; | |
155 break; | |
156 case UsbStandardRequest.SetDescriptor: | |
157 req.Descriptor.Recipient = (int)requestType & 0x1F; | |
158 req.Descriptor.Type = (value >> 8) & 0xFF; | |
159 req.Descriptor.Index = value & 0xFF; | |
160 req.Descriptor.LangID = index; | |
161 code = LibUsbIoCtl.SET_DESCRIPTOR; | |
162 break; | |
163 case UsbStandardRequest.GetConfiguration: | |
164 code = LibUsbIoCtl.GET_CONFIGURATION; | |
165 break; | |
166 case UsbStandardRequest.SetConfiguration: | |
167 req.Config.ID = value; | |
168 code = LibUsbIoCtl.SET_CONFIGURATION; | |
169 break; | |
170 case UsbStandardRequest.GetInterface: | |
171 req.Iface.ID = index; | |
172 code = LibUsbIoCtl.GET_INTERFACE; | |
173 break; | |
174 case UsbStandardRequest.SetInterface: | |
175 req.Iface.ID = index; | |
176 req.Iface.AlternateID = value; | |
177 code = LibUsbIoCtl.SET_INTERFACE; | |
178 break; | |
179 default: | |
180 throw new ArgumentException(String.Format("Invalid request: 0x{0:X8}", request)); | |
181 } | |
182 break; | |
183 case UsbControlRequestType.TypeVendor: | |
184 case UsbControlRequestType.TypeClass: | |
185 req.Vendor.Type = ((byte)requestType >> 5) & 0x03; | |
186 req.Vendor.Recipient = (int)requestType & 0x1F; | |
187 req.Vendor.Request = (int)request; | |
188 req.Vendor.ID = value; | |
189 req.Vendor.Index = index; | |
190 code = ((byte)requestType & 0x80) != 0 ? LibUsbIoCtl.VENDOR_READ : LibUsbIoCtl.VENDOR_WRITE; | |
191 break; | |
192 case UsbControlRequestType.TypeReserved: | |
193 default: | |
194 throw new ArgumentException(String.Format("Invalid or unsupported request type: 0x{0:X8}", requestType)); | |
195 } | |
196 } | |
197 | |
198 unsafe int PipeTransfer(Byte epnum, Boolean write, Boolean isochronous, Byte[] buffer, int offset, int length, int packetsize) { | |
199 if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); | |
200 LibUsbRequest req = new LibUsbRequest(); | |
201 req.Endpoint.ID = epnum; | |
202 req.Endpoint.PacketSize = packetsize; | |
203 req.Timeout = UsbConstants.DEFAULT_TIMEOUT; | |
204 fixed (Byte* b = buffer) { | |
205 if (write) { | |
206 int cltCode = isochronous ? LibUsbIoCtl.ISOCHRONOUS_WRITE : LibUsbIoCtl.INTERRUPT_OR_BULK_WRITE; | |
207 int transfered = 0; | |
208 while (length > 0) { | |
209 int ret; | |
210 DeviceIoControl(DeviceHandle, cltCode, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), Math.Min(Int16.MaxValue, length), out ret); | |
211 if (ret <= 0) throw new System.IO.EndOfStreamException(); | |
212 length -= ret; | |
213 offset += ret; | |
214 transfered += ret; | |
215 } | |
216 return transfered; | |
217 } else { | |
218 int cltCode = isochronous ? LibUsbIoCtl.ISOCHRONOUS_READ : LibUsbIoCtl.INTERRUPT_OR_BULK_READ; | |
219 int ret; | |
220 DeviceIoControl(DeviceHandle, cltCode, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), Math.Min(UInt16.MaxValue, length), out ret); | |
221 return ret; | |
222 } | |
223 } | |
224 } | |
225 public void PipeReset(byte pipeID) { | |
226 LibUsbRequest req = new LibUsbRequest(); | |
227 req.Endpoint.ID = pipeID; | |
228 req.Timeout = UsbConstants.DEFAULT_TIMEOUT; | |
229 int ret; | |
230 DeviceIoControl(DeviceHandle, LibUsbIoCtl.RESET_ENDPOINT, ref req, LibUsbRequest.Size, null, 0, out ret); | |
231 } | |
232 | |
233 private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, [In] ref LibUsbRequest InBuffer, int nInBufferSize, Byte[] OutBuffer, int nOutBufferSize, out int pBytesReturned) { | |
234 fixed (LibUsbRequest* InBufferPtr = &InBuffer) { | |
235 fixed (Byte* OutBufferPtr = OutBuffer) { | |
236 DeviceIoControl(hDevice, IoControlCode, (IntPtr)InBufferPtr, nInBufferSize, (IntPtr)OutBufferPtr, nOutBufferSize, out pBytesReturned); | |
237 } | |
238 } | |
239 } | |
240 private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, Byte[] InBuffer, int nInBufferSize, Byte[] OutBuffer, int nOutBufferSize, out int pBytesReturned) { | |
241 fixed (Byte* InBufferPtr = InBuffer, OutBufferPtr = OutBuffer) { | |
242 DeviceIoControl(hDevice, IoControlCode, (IntPtr)InBufferPtr, nInBufferSize, (IntPtr)OutBufferPtr, nOutBufferSize, out pBytesReturned); | |
243 } | |
244 } | |
245 private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, [In] ref LibUsbRequest InBuffer, int nInBufferSize, IntPtr OutBuffer, int nOutBufferSize, out int pBytesReturned) { | |
246 fixed (LibUsbRequest* InBufferPtr = &InBuffer) { | |
247 DeviceIoControl(hDevice, IoControlCode, (IntPtr)InBufferPtr, nInBufferSize, OutBuffer, nOutBufferSize, out pBytesReturned); | |
248 } | |
249 } | |
250 private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, IntPtr InBuffer, int nInBufferSize, IntPtr OutBuffer, int nOutBufferSize, out int pBytesReturned) { | |
251 using (ManualResetEvent evt = new ManualResetEvent(false)) { | |
252 NativeOverlapped overlapped = new NativeOverlapped(); | |
253 overlapped.EventHandle = evt.SafeWaitHandle.DangerousGetHandle(); | |
254 if (Kernel32.DeviceIoControl(hDevice, IoControlCode, InBuffer, nInBufferSize, OutBuffer, nOutBufferSize, out pBytesReturned, &overlapped)) | |
255 return; | |
256 int err = Marshal.GetLastWin32Error(); | |
257 if (err != 997) throw new Win32Exception(err); | |
258 evt.WaitOne(); | |
259 if (!Kernel32.GetOverlappedResult(hDevice, &overlapped, out pBytesReturned, false)) | |
260 throw new Win32Exception(Marshal.GetLastWin32Error()); | |
261 } | |
262 } | |
263 } | |
264 } |