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