Mercurial > hg > ucis.core
annotate USBLib/Communication/LibUsb0/LibUsbDevice.cs @ 46:053cc617af54
USBLib: added functions to clear USB endpoint halt state
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Sun, 30 Jun 2013 16:28:36 +0200 |
parents | dcfec2be27c9 |
children | 2d16447eff12 |
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 //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 } | |
46
053cc617af54
USBLib: added functions to clear USB endpoint halt state
Ivo Smits <Ivo@UCIS.nl>
parents:
21
diff
changeset
|
90 public override void BulkReset(byte endpoint) { |
053cc617af54
USBLib: added functions to clear USB endpoint halt state
Ivo Smits <Ivo@UCIS.nl>
parents:
21
diff
changeset
|
91 PipeReset(endpoint); |
053cc617af54
USBLib: added functions to clear USB endpoint halt state
Ivo Smits <Ivo@UCIS.nl>
parents:
21
diff
changeset
|
92 } |
21 | 93 public override int InterruptRead(byte endpoint, byte[] buffer, int offset, int length) { |
94 return PipeTransfer(endpoint, false, false, buffer, offset, length, 0); | |
95 } | |
96 public override int InterruptWrite(byte endpoint, byte[] buffer, int offset, int length) { | |
97 return PipeTransfer(endpoint, true, false, buffer, offset, length, 0); | |
98 } | |
46
053cc617af54
USBLib: added functions to clear USB endpoint halt state
Ivo Smits <Ivo@UCIS.nl>
parents:
21
diff
changeset
|
99 public override void InterruptReset(byte endpoint) { |
053cc617af54
USBLib: added functions to clear USB endpoint halt state
Ivo Smits <Ivo@UCIS.nl>
parents:
21
diff
changeset
|
100 PipeReset(endpoint); |
053cc617af54
USBLib: added functions to clear USB endpoint halt state
Ivo Smits <Ivo@UCIS.nl>
parents:
21
diff
changeset
|
101 } |
21 | 102 public unsafe override int ControlRead(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { |
103 if (buffer == null) buffer = new Byte[0]; | |
104 if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); | |
105 int code; | |
106 LibUsbRequest req = new LibUsbRequest(); | |
107 PrepareControlTransfer(requestType, request, value, index, length, ref req, out code); | |
108 int ret; | |
109 fixed (Byte* b = buffer) { | |
110 DeviceIoControl(DeviceHandle, code, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), length, out ret); | |
111 } | |
112 return ret; | |
113 } | |
114 public unsafe override int ControlWrite(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) { | |
115 Byte[] inbuffer = new Byte[length + LibUsbRequest.Size]; | |
116 if (length > 0) Buffer.BlockCopy(buffer, offset, inbuffer, LibUsbRequest.Size, length); | |
117 int code; | |
118 fixed (Byte* inbufferp = inbuffer) | |
119 PrepareControlTransfer(requestType, request, value, index, length, ref *((LibUsbRequest*)inbufferp), out code); | |
120 int ret; | |
121 DeviceIoControl(DeviceHandle, code, inbuffer, length + LibUsbRequest.Size, null, 0, out ret); | |
122 return length; | |
123 //ret -= LibUsbRequest.Size; | |
124 //if (ret <= 0) return 0; | |
125 //return ret; | |
126 } | |
127 void PrepareControlTransfer(UsbControlRequestType requestType, byte request, short value, short index, int length, ref LibUsbRequest req, out int code) { | |
128 code = LibUsbIoCtl.CONTROL_TRANSFER; | |
129 req.Timeout = UsbConstants.DEFAULT_TIMEOUT; | |
130 req.Control.RequestType = (Byte)requestType; | |
131 req.Control.Request = request; | |
132 req.Control.Value = (ushort)value; | |
133 req.Control.Index = (ushort)index; | |
134 req.Control.Length = (ushort)length; | |
135 switch ((UsbControlRequestType)((int)requestType & (0x03 << 5))) { | |
136 case UsbControlRequestType.TypeStandard: | |
137 switch ((UsbStandardRequest)request) { | |
138 case UsbStandardRequest.GetStatus: | |
139 req.Status.Recipient = (int)requestType & 0x1F; | |
140 req.Status.Index = index; | |
141 code = LibUsbIoCtl.GET_STATUS; | |
142 break; | |
143 case UsbStandardRequest.ClearFeature: | |
144 req.Feature.Recipient = (int)requestType & 0x1F; | |
145 req.Feature.ID = value; | |
146 req.Feature.Index = index; | |
147 code = LibUsbIoCtl.CLEAR_FEATURE; | |
148 break; | |
149 case UsbStandardRequest.SetFeature: | |
150 req.Feature.Recipient = (int)requestType & 0x1F; | |
151 req.Feature.ID = value; | |
152 req.Feature.Index = index; | |
153 code = LibUsbIoCtl.SET_FEATURE; | |
154 break; | |
155 case UsbStandardRequest.GetDescriptor: | |
156 req.Descriptor.Recipient = (int)requestType & 0x1F; | |
157 req.Descriptor.Type = (value >> 8) & 0xFF; | |
158 req.Descriptor.Index = value & 0xFF; | |
159 req.Descriptor.LangID = index; | |
160 code = LibUsbIoCtl.GET_DESCRIPTOR; | |
161 break; | |
162 case UsbStandardRequest.SetDescriptor: | |
163 req.Descriptor.Recipient = (int)requestType & 0x1F; | |
164 req.Descriptor.Type = (value >> 8) & 0xFF; | |
165 req.Descriptor.Index = value & 0xFF; | |
166 req.Descriptor.LangID = index; | |
167 code = LibUsbIoCtl.SET_DESCRIPTOR; | |
168 break; | |
169 case UsbStandardRequest.GetConfiguration: | |
170 code = LibUsbIoCtl.GET_CONFIGURATION; | |
171 break; | |
172 case UsbStandardRequest.SetConfiguration: | |
173 req.Config.ID = value; | |
174 code = LibUsbIoCtl.SET_CONFIGURATION; | |
175 break; | |
176 case UsbStandardRequest.GetInterface: | |
177 req.Iface.ID = index; | |
178 code = LibUsbIoCtl.GET_INTERFACE; | |
179 break; | |
180 case UsbStandardRequest.SetInterface: | |
181 req.Iface.ID = index; | |
182 req.Iface.AlternateID = value; | |
183 code = LibUsbIoCtl.SET_INTERFACE; | |
184 break; | |
185 default: | |
186 throw new ArgumentException(String.Format("Invalid request: 0x{0:X8}", request)); | |
187 } | |
188 break; | |
189 case UsbControlRequestType.TypeVendor: | |
190 case UsbControlRequestType.TypeClass: | |
191 req.Vendor.Type = ((byte)requestType >> 5) & 0x03; | |
192 req.Vendor.Recipient = (int)requestType & 0x1F; | |
193 req.Vendor.Request = (int)request; | |
194 req.Vendor.ID = value; | |
195 req.Vendor.Index = index; | |
196 code = ((byte)requestType & 0x80) != 0 ? LibUsbIoCtl.VENDOR_READ : LibUsbIoCtl.VENDOR_WRITE; | |
197 break; | |
198 case UsbControlRequestType.TypeReserved: | |
199 default: | |
200 throw new ArgumentException(String.Format("Invalid or unsupported request type: 0x{0:X8}", requestType)); | |
201 } | |
202 } | |
203 | |
204 unsafe int PipeTransfer(Byte epnum, Boolean write, Boolean isochronous, Byte[] buffer, int offset, int length, int packetsize) { | |
205 if (offset < 0 || length < 0 || offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length", "The specified offset and length exceed the buffer length"); | |
206 LibUsbRequest req = new LibUsbRequest(); | |
207 req.Endpoint.ID = epnum; | |
208 req.Endpoint.PacketSize = packetsize; | |
209 req.Timeout = UsbConstants.DEFAULT_TIMEOUT; | |
210 fixed (Byte* b = buffer) { | |
211 if (write) { | |
212 int cltCode = isochronous ? LibUsbIoCtl.ISOCHRONOUS_WRITE : LibUsbIoCtl.INTERRUPT_OR_BULK_WRITE; | |
213 int transfered = 0; | |
214 while (length > 0) { | |
215 int ret; | |
216 DeviceIoControl(DeviceHandle, cltCode, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), Math.Min(Int16.MaxValue, length), out ret); | |
217 if (ret <= 0) throw new System.IO.EndOfStreamException(); | |
218 length -= ret; | |
219 offset += ret; | |
220 transfered += ret; | |
221 } | |
222 return transfered; | |
223 } else { | |
224 int cltCode = isochronous ? LibUsbIoCtl.ISOCHRONOUS_READ : LibUsbIoCtl.INTERRUPT_OR_BULK_READ; | |
225 int ret; | |
226 DeviceIoControl(DeviceHandle, cltCode, ref req, LibUsbRequest.Size, (IntPtr)(b + offset), Math.Min(UInt16.MaxValue, length), out ret); | |
227 return ret; | |
228 } | |
229 } | |
230 } | |
231 public void PipeReset(byte pipeID) { | |
232 LibUsbRequest req = new LibUsbRequest(); | |
233 req.Endpoint.ID = pipeID; | |
234 req.Timeout = UsbConstants.DEFAULT_TIMEOUT; | |
235 int ret; | |
236 DeviceIoControl(DeviceHandle, LibUsbIoCtl.RESET_ENDPOINT, ref req, LibUsbRequest.Size, null, 0, out ret); | |
237 } | |
238 | |
239 private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, [In] ref LibUsbRequest InBuffer, int nInBufferSize, Byte[] OutBuffer, int nOutBufferSize, out int pBytesReturned) { | |
240 fixed (LibUsbRequest* InBufferPtr = &InBuffer) { | |
241 fixed (Byte* OutBufferPtr = OutBuffer) { | |
242 DeviceIoControl(hDevice, IoControlCode, (IntPtr)InBufferPtr, nInBufferSize, (IntPtr)OutBufferPtr, nOutBufferSize, out pBytesReturned); | |
243 } | |
244 } | |
245 } | |
246 private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, Byte[] InBuffer, int nInBufferSize, Byte[] OutBuffer, int nOutBufferSize, out int pBytesReturned) { | |
247 fixed (Byte* InBufferPtr = InBuffer, OutBufferPtr = OutBuffer) { | |
248 DeviceIoControl(hDevice, IoControlCode, (IntPtr)InBufferPtr, nInBufferSize, (IntPtr)OutBufferPtr, nOutBufferSize, out pBytesReturned); | |
249 } | |
250 } | |
251 private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, [In] ref LibUsbRequest InBuffer, int nInBufferSize, IntPtr OutBuffer, int nOutBufferSize, out int pBytesReturned) { | |
252 fixed (LibUsbRequest* InBufferPtr = &InBuffer) { | |
253 DeviceIoControl(hDevice, IoControlCode, (IntPtr)InBufferPtr, nInBufferSize, OutBuffer, nOutBufferSize, out pBytesReturned); | |
254 } | |
255 } | |
256 private unsafe void DeviceIoControl(SafeHandle hDevice, int IoControlCode, IntPtr InBuffer, int nInBufferSize, IntPtr OutBuffer, int nOutBufferSize, out int pBytesReturned) { | |
257 using (ManualResetEvent evt = new ManualResetEvent(false)) { | |
258 NativeOverlapped overlapped = new NativeOverlapped(); | |
259 overlapped.EventHandle = evt.SafeWaitHandle.DangerousGetHandle(); | |
260 if (Kernel32.DeviceIoControl(hDevice, IoControlCode, InBuffer, nInBufferSize, OutBuffer, nOutBufferSize, out pBytesReturned, &overlapped)) | |
261 return; | |
262 int err = Marshal.GetLastWin32Error(); | |
263 if (err != 997) throw new Win32Exception(err); | |
264 evt.WaitOne(); | |
265 if (!Kernel32.GetOverlappedResult(hDevice, &overlapped, out pBytesReturned, false)) | |
266 throw new Win32Exception(Marshal.GetLastWin32Error()); | |
267 } | |
268 } | |
269 } | |
270 } |