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 }