comparison USBLib/Communication/VBoxUSB.cs @ 57:b1efeada517e

Added VirtualBox USB driver backend for direct USB communication
author Ivo Smits <Ivo@UCIS.nl>
date Fri, 04 Oct 2013 13:22:21 +0200
parents
children 3424fa5a12c9
comparison
equal deleted inserted replaced
55:ec222fb577dd 57:b1efeada517e
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Runtime.InteropServices;
5 using System.Text;
6 using System.Threading;
7 using Microsoft.Win32.SafeHandles;
8 using UCIS.HWLib.Windows.Devices;
9 using UCIS.USBLib.Communication;
10 using UCIS.USBLib.Communication.WinUsb;
11 using UCIS.USBLib.Internal.Windows;
12
13 namespace UCIS.USBLib.Communication.VBoxUSB {
14 enum USBFILTERTYPE : int {
15 USBFILTERTYPE_INVALID = 0,
16 USBFILTERTYPE_FIRST,
17 USBFILTERTYPE_ONESHOT_IGNORE = USBFILTERTYPE_FIRST,
18 USBFILTERTYPE_ONESHOT_CAPTURE,
19 USBFILTERTYPE_IGNORE,
20 USBFILTERTYPE_CAPTURE,
21 USBFILTERTYPE_END,
22 }
23 enum USBFILTERMATCH : ushort {
24 USBFILTERMATCH_INVALID = 0,
25 USBFILTERMATCH_IGNORE,
26 USBFILTERMATCH_PRESENT,
27 USBFILTERMATCH_NUM_FIRST,
28 USBFILTERMATCH_NUM_EXACT = USBFILTERMATCH_NUM_FIRST,
29 USBFILTERMATCH_NUM_EXACT_NP,
30 USBFILTERMATCH_NUM_EXPRESSION,
31 USBFILTERMATCH_NUM_EXPRESSION_NP,
32 USBFILTERMATCH_NUM_LAST = USBFILTERMATCH_NUM_EXPRESSION_NP,
33 USBFILTERMATCH_STR_FIRST,
34 USBFILTERMATCH_STR_EXACT = USBFILTERMATCH_STR_FIRST,
35 USBFILTERMATCH_STR_EXACT_NP,
36 USBFILTERMATCH_STR_PATTERN,
37 USBFILTERMATCH_STR_PATTERN_NP,
38 USBFILTERMATCH_STR_LAST = USBFILTERMATCH_STR_PATTERN_NP,
39 USBFILTERMATCH_END = 11
40 }
41 enum USBFILTERIDX : int {
42 USBFILTERIDX_VENDOR_ID = 0,
43 USBFILTERIDX_PRODUCT_ID,
44 USBFILTERIDX_DEVICE_REV,
45 USBFILTERIDX_DEVICE_CLASS,
46 USBFILTERIDX_DEVICE_SUB_CLASS,
47 USBFILTERIDX_DEVICE_PROTOCOL,
48 USBFILTERIDX_BUS,
49 USBFILTERIDX_PORT,
50 USBFILTERIDX_MANUFACTURER_STR,
51 USBFILTERIDX_PRODUCT_STR,
52 USBFILTERIDX_SERIAL_NUMBER_STR,
53 USBFILTERIDX_END = 11
54 }
55 [StructLayout(LayoutKind.Sequential, Size = 4)]
56 struct USBFILTERFIELD {
57 public USBFILTERMATCH enmMatch;
58 public UInt16 u16Value;
59 }
60 [StructLayout(LayoutKind.Sequential)]
61 unsafe struct USBFILTER {
62 public UInt32 u32Magic;
63 public USBFILTERTYPE enmType;
64 public fixed UInt32 aFields[(int)USBFILTERIDX.USBFILTERIDX_END];
65 public UInt32 offCurEnd;
66 public fixed Byte achStrTab[256];
67
68 const UInt32 USBFILTER_MAGIC = 0x19670408;
69 public unsafe USBFILTER(USBFILTERTYPE enmType)
70 : this() {
71 u32Magic = USBFILTER_MAGIC;
72 this.enmType = enmType;
73 fixed (UInt32* aFieldsBytes = this.aFields) {
74 USBFILTERFIELD* aFields = (USBFILTERFIELD*)aFieldsBytes;
75 for (int i = 0; i < (int)USBFILTERIDX.USBFILTERIDX_END; i++)
76 aFields[i].enmMatch = USBFILTERMATCH.USBFILTERMATCH_IGNORE;
77 }
78 }
79 static Boolean IsNumericField(USBFILTERIDX enmFieldIdx) {
80 switch (enmFieldIdx) {
81 case USBFILTERIDX.USBFILTERIDX_VENDOR_ID:
82 case USBFILTERIDX.USBFILTERIDX_PRODUCT_ID:
83 case USBFILTERIDX.USBFILTERIDX_DEVICE_REV:
84 case USBFILTERIDX.USBFILTERIDX_DEVICE_CLASS:
85 case USBFILTERIDX.USBFILTERIDX_DEVICE_SUB_CLASS:
86 case USBFILTERIDX.USBFILTERIDX_DEVICE_PROTOCOL:
87 case USBFILTERIDX.USBFILTERIDX_BUS:
88 case USBFILTERIDX.USBFILTERIDX_PORT:
89 return true;
90 case USBFILTERIDX.USBFILTERIDX_MANUFACTURER_STR:
91 case USBFILTERIDX.USBFILTERIDX_PRODUCT_STR:
92 case USBFILTERIDX.USBFILTERIDX_SERIAL_NUMBER_STR:
93 return false;
94 default:
95 throw new ArgumentOutOfRangeException("enmFieldIdx");
96 }
97 }
98 static Boolean IsMethodUsingStringValue(USBFILTERMATCH enmMatchingMethod) {
99 switch (enmMatchingMethod) {
100 case USBFILTERMATCH.USBFILTERMATCH_NUM_EXPRESSION:
101 case USBFILTERMATCH.USBFILTERMATCH_NUM_EXPRESSION_NP:
102 case USBFILTERMATCH.USBFILTERMATCH_STR_EXACT:
103 case USBFILTERMATCH.USBFILTERMATCH_STR_EXACT_NP:
104 case USBFILTERMATCH.USBFILTERMATCH_STR_PATTERN:
105 case USBFILTERMATCH.USBFILTERMATCH_STR_PATTERN_NP:
106 return true;
107 case USBFILTERMATCH.USBFILTERMATCH_IGNORE:
108 case USBFILTERMATCH.USBFILTERMATCH_PRESENT:
109 case USBFILTERMATCH.USBFILTERMATCH_NUM_EXACT:
110 case USBFILTERMATCH.USBFILTERMATCH_NUM_EXACT_NP:
111 return false;
112 default:
113 throw new ArgumentOutOfRangeException("enmMatchingMethod");
114 }
115 }
116 static unsafe int strlen(byte* ptr) {
117 for (int length = 0; ; length++) if (ptr[length] != 0) return length;
118 }
119 static unsafe void memset(void* ptr, byte value, int count) {
120 for (int i = 0; i < count; i++) ((byte*)ptr)[i] = value;
121 }
122 static unsafe void memmove(void* dest, void* src, int count) {
123 if (dest > src) {
124 for (int i = count - 1; i >= 0; i--) ((byte*)dest)[i] = ((byte*)src)[i];
125 } else if (dest < src) {
126 for (int i = 0; i < count; i++) ((byte*)dest)[i] = ((byte*)src)[i];
127 }
128 }
129 public unsafe void SetString(USBFILTERIDX enmFieldIdx, Byte[] pszString) {
130 fixed (USBFILTER* pFilter = &this) {
131 USBFILTERFIELD* aFields = (USBFILTERFIELD*)pFilter->aFields;
132 if (IsMethodUsingStringValue((USBFILTERMATCH)aFields[(int)enmFieldIdx].enmMatch) && aFields[(int)enmFieldIdx].u16Value != 0) {
133 int off = aFields[(int)enmFieldIdx].u16Value;
134 aFields[(int)enmFieldIdx].u16Value = 0; /* Assign it to the NULL string. */
135 int cchShift = strlen(&pFilter->achStrTab[off]) + 1;
136 int cchToMove = ((int)offCurEnd + 1) - (off + cchShift);
137 if (cchToMove > 0) {
138 memmove(&pFilter->achStrTab[off], &pFilter->achStrTab[off + cchShift], cchToMove);
139 for (int i = 0; i < (int)USBFILTERIDX.USBFILTERIDX_END; i++)
140 if (aFields[i].u16Value >= off && IsMethodUsingStringValue(aFields[i].enmMatch))
141 aFields[i].u16Value -= (ushort)cchShift;
142 }
143 offCurEnd -= (uint)cchShift;
144 memset(&pFilter->achStrTab[offCurEnd], 0, cchShift);
145 }
146 if (pszString.Length == 0) {
147 aFields[(int)enmFieldIdx].u16Value = 0;
148 } else {
149 int cch = pszString.Length;
150 if (this.offCurEnd + cch + 2 > 256) throw new IndexOutOfRangeException("Buffer overflow");
151 aFields[(int)enmFieldIdx].u16Value = (ushort)(this.offCurEnd + 1);
152 for (int i = 0; i < cch + 1; i++) pFilter->achStrTab[offCurEnd + 1 + i] = pszString[i];
153 offCurEnd += (uint)cch + 1;
154 }
155 }
156 }
157 unsafe void DeleteAnyStringValue(USBFILTERIDX enmFieldIdx) {
158 fixed (USBFILTER* pFilter = &this) {
159 USBFILTERFIELD* aFields = (USBFILTERFIELD*)pFilter->aFields;
160 if (IsMethodUsingStringValue((USBFILTERMATCH)aFields[(int)enmFieldIdx].enmMatch) && aFields[(int)enmFieldIdx].u16Value != 0)
161 SetString(enmFieldIdx, new Byte[0]);
162 else if (enmFieldIdx >= USBFILTERIDX.USBFILTERIDX_END)
163 throw new ArgumentOutOfRangeException("enmFieldIdx");
164 }
165 }
166 public unsafe void SetNumExact(USBFILTERIDX enmFieldIdx, UInt16 u16Value, bool fMustBePresent) {
167 if (!IsNumericField(enmFieldIdx)) throw new ArgumentOutOfRangeException("enmFieldIdx");
168 DeleteAnyStringValue(enmFieldIdx);
169 fixed (USBFILTER* pFilter = &this) {
170 USBFILTERFIELD* aFields = (USBFILTERFIELD*)pFilter->aFields;
171 aFields[(int)enmFieldIdx].u16Value = u16Value;
172 aFields[(int)enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH.USBFILTERMATCH_NUM_EXACT : USBFILTERMATCH.USBFILTERMATCH_NUM_EXACT_NP;
173 }
174 }
175 }
176 [StructLayout(LayoutKind.Sequential, Pack = 4)]
177 struct USBSUP_FLTADDOUT {
178 public IntPtr uId;
179 public int rc;
180 }
181 [StructLayout(LayoutKind.Sequential)]
182 struct USBSUP_VERSION {
183 public UInt32 u32Major;
184 public UInt32 u32Minor;
185 }
186 [StructLayout(LayoutKind.Sequential)]
187 struct USBSUP_CLAIMDEV {
188 public Byte bInterfaceNumber;
189 public Byte fClaimed;
190 }
191 [StructLayout(LayoutKind.Sequential)]
192 struct USBSUP_CLEAR_ENDPOINT {
193 public Byte bEndpoint;
194 }
195 [StructLayout(LayoutKind.Sequential)]
196 struct USBSUP_SET_CONFIG {
197 public Byte bConfigurationValue;
198 }
199 [StructLayout(LayoutKind.Sequential)]
200 struct USBSUP_SELECT_INTERFACE {
201 public Byte bInterfaceNumber;
202 public Byte bAlternateSetting;
203 }
204 enum USBSUP_TRANSFER_TYPE : int {
205 USBSUP_TRANSFER_TYPE_CTRL = 0,
206 USBSUP_TRANSFER_TYPE_ISOC = 1,
207 USBSUP_TRANSFER_TYPE_BULK = 2,
208 USBSUP_TRANSFER_TYPE_INTR = 3,
209 USBSUP_TRANSFER_TYPE_MSG = 4
210 }
211 enum USBSUP_DIRECTION : int {
212 USBSUP_DIRECTION_SETUP = 0,
213 USBSUP_DIRECTION_IN = 1,
214 USBSUP_DIRECTION_OUT = 2
215 }
216 enum USBSUP_XFER_FLAG : int {
217 USBSUP_FLAG_NONE = 0,
218 USBSUP_FLAG_SHORT_OK = 1
219 }
220 enum USBSUP_ERROR : int {
221 USBSUP_XFER_OK = 0,
222 USBSUP_XFER_STALL = 1,
223 USBSUP_XFER_DNR = 2,
224 USBSUP_XFER_CRC = 3,
225 USBSUP_XFER_NAC = 4,
226 USBSUP_XFER_UNDERRUN = 5,
227 USBSUP_XFER_OVERRUN = 6
228 }
229 [StructLayout(LayoutKind.Sequential, Pack = 4)]
230 unsafe struct USBSUP_URB {
231 public USBSUP_TRANSFER_TYPE type;
232 public UInt32 ep;
233 public USBSUP_DIRECTION dir;
234 public USBSUP_XFER_FLAG flags;
235 public USBSUP_ERROR error;
236 public UIntPtr len;
237 public void* buf;
238 public UInt32 numIsoPkts;
239 public fixed byte aIsoPkts[8 * 8];
240 }
241 class USBRegistry : WindowsUsbDeviceRegistry, IUsbDeviceRegistry {
242 public IUsbDevice Open() { return new VBoxUSB(this); }
243 public USBRegistry(DeviceNode devnode, String intf) : base(devnode, intf) { }
244 }
245
246 public class VBoxUSB : UsbInterface, IUsbDevice {
247 const int FILE_DEVICE_UNKNOWN = 0x00000022;
248 const int METHOD_BUFFERED = 0;
249 const int FILE_WRITE_ACCESS = 0x0002;
250 static int CTL_CODE(int DeviceType, int Function, int Method, int Access) { return (DeviceType << 16) | (Access << 14) | (Function << 2) | Method; }
251 static readonly int SUPUSBFLT_IOCTL_ADD_FILTER = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x611, METHOD_BUFFERED, FILE_WRITE_ACCESS);
252 static readonly int SUPUSBFLT_IOCTL_RUN_FILTERS = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x615, METHOD_BUFFERED, FILE_WRITE_ACCESS);
253 static readonly int SUPUSBFLT_IOCTL_REMOVE_FILTER = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x612, METHOD_BUFFERED, FILE_WRITE_ACCESS);
254 static readonly int SUPUSBFLT_IOCTL_GET_VERSION = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x610, METHOD_BUFFERED, FILE_WRITE_ACCESS);
255 static readonly int SUPUSB_IOCTL_GET_VERSION = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60F, METHOD_BUFFERED, FILE_WRITE_ACCESS);
256 static readonly int SUPUSB_IOCTL_USB_CLAIM_DEVICE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60B, METHOD_BUFFERED, FILE_WRITE_ACCESS);
257 static readonly int SUPUSB_IOCTL_USB_RELEASE_DEVICE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60C, METHOD_BUFFERED, FILE_WRITE_ACCESS);
258 static readonly int SUPUSB_IOCTL_USB_RESET = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x608, METHOD_BUFFERED, FILE_WRITE_ACCESS);
259 static readonly int SUPUSB_IOCTL_USB_CLEAR_ENDPOINT = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60E, METHOD_BUFFERED, FILE_WRITE_ACCESS);
260 static readonly int SUPUSB_IOCTL_USB_SET_CONFIG = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60A, METHOD_BUFFERED, FILE_WRITE_ACCESS);
261 static readonly int SUPUSB_IOCTL_USB_SELECT_INTERFACE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x609, METHOD_BUFFERED, FILE_WRITE_ACCESS);
262 static readonly int SUPUSB_IOCTL_SEND_URB = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x607, METHOD_BUFFERED, FILE_WRITE_ACCESS);
263
264 const UInt32 USBDRV_MAJOR_VERSION = 4;
265 const UInt32 USBDRV_MINOR_VERSION = 0;
266 const UInt32 USBMON_MAJOR_VERSION = 5;
267 const UInt32 USBMON_MINOR_VERSION = 0;
268
269 static SafeFileHandle hMonitor = null;
270 const String USBMON_DEVICE_NAME = "\\\\.\\VBoxUSBMon";
271
272 static unsafe void SyncIoControl(SafeHandle hDevice, int IoControlCode, void* InBuffer, int nInBufferSize, void* OutBuffer, int nOutBufferSize) {
273 Int32 pBytesReturned = 0;
274 if (!Kernel32.DeviceIoControl(hDevice, IoControlCode, InBuffer, nInBufferSize, OutBuffer, nOutBufferSize, out pBytesReturned, null))
275 throw new Win32Exception(Marshal.GetLastWin32Error());
276 }
277
278 unsafe static void InitMonitor() {
279 if (hMonitor != null && !hMonitor.IsClosed && !hMonitor.IsInvalid) return;
280 hMonitor = Kernel32.CreateFile(USBMON_DEVICE_NAME, Kernel32.GENERIC_READ | Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_READ | Kernel32.FILE_SHARE_WRITE, IntPtr.Zero, Kernel32.OPEN_EXISTING, Kernel32.FILE_ATTRIBUTE_SYSTEM, IntPtr.Zero);
281 if (hMonitor.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error());
282 try {
283 USBSUP_VERSION Version = new USBSUP_VERSION();
284 SyncIoControl(hMonitor, SUPUSBFLT_IOCTL_GET_VERSION, null, 0, &Version, sizeof(USBSUP_VERSION));
285 if (Version.u32Major != USBMON_MAJOR_VERSION || Version.u32Minor < USBMON_MINOR_VERSION) throw new InvalidOperationException("Unsupported USBMON version");
286 } catch {
287 hMonitor.Close();
288 }
289 }
290
291 static unsafe IntPtr USBLibAddFilter(ref USBFILTER filter) {
292 USBSUP_FLTADDOUT FltAddRc;
293 fixed (USBFILTER* pFilter = &filter) SyncIoControl(hMonitor, SUPUSBFLT_IOCTL_ADD_FILTER, pFilter, sizeof(USBFILTER), &FltAddRc, sizeof(USBSUP_FLTADDOUT));
294 if (FltAddRc.rc != 0) throw new Exception(String.Format("rc={0}", FltAddRc.rc));
295 return FltAddRc.uId;
296 }
297 static unsafe void USBLibRemoveFilter(UIntPtr filterId) {
298 SyncIoControl(hMonitor, SUPUSBFLT_IOCTL_REMOVE_FILTER, &filterId, sizeof(UIntPtr), null, 0);
299 }
300 static unsafe void USBLibRunFilters() {
301 SyncIoControl(hMonitor, SUPUSBFLT_IOCTL_RUN_FILTERS, null, 0, null, 0);
302 }
303
304 static void initFilterFromDevice(ref USBFILTER aFilter, DeviceNode aDevice) {
305 int mVid, mPid, mRev, mMi;
306 WindowsUsbDeviceRegistry.DecodeDeviceIDs(aDevice, out mVid, out mPid, out mRev, out mMi);
307 if (mVid != -1) aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_VENDOR_ID, (ushort)mVid, true);
308 if (mPid != -1) aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_PRODUCT_ID, (ushort)mPid, true);
309 if (mRev != -1) {
310 int mRevBCD = (((mRev % 10) / 1) << 0) | (((mRev % 100) / 10) << 4) | (((mRev % 1000) / 100) << 8) | (((mRev % 10000) / 1000) << 12);
311 aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_DEVICE_REV, (ushort)mRevBCD, true);
312 }
313 //aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_DEVICE_CLASS, 0xff, true);
314 //aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_DEVICE_SUB_CLASS, 0x00, true);
315 //aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_DEVICE_PROTOCOL, 0x00, true);
316 //aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_PORT, 0, true);
317 //aFilter.SetNumExact(USBFILTERIDX.USBFILTERIDX_BUS, 0, true);
318 //if (pDev->pszSerialNumber) aFilter.SetStringExact(USBFILTERIDX.USBFILTERIDX_SERIAL_NUMBER_STR, pDev->pszSerialNumber, true);
319 //if (pDev->pszProduct) aFilter.SetStringExact(USBFILTERIDX.USBFILTERIDX_PRODUCT_STR, pDev->pszProduct, true);
320 //if (pDev->pszManufacturer) aFilter.SetStringExact(USBFILTERIDX.USBFILTERIDX_MANUFACTURER_STR, pDev->pszManufacturer, true);
321 }
322
323 public unsafe static void Capture(DeviceNode aDevice) {
324 InitMonitor();
325 USBFILTER Filter = new USBFILTER(USBFILTERTYPE.USBFILTERTYPE_ONESHOT_CAPTURE);
326 initFilterFromDevice(ref Filter, aDevice);
327 IntPtr pvId = USBLibAddFilter(ref Filter);
328 if (pvId == IntPtr.Zero) throw new Exception("Add one-shot Filter failed");
329 //USBLibRunFilters();
330 aDevice.Reenumerate(0);
331 }
332 public unsafe static void Release(DeviceNode aDevice) {
333 InitMonitor();
334 USBFILTER Filter = new USBFILTER(USBFILTERTYPE.USBFILTERTYPE_ONESHOT_IGNORE);
335 initFilterFromDevice(ref Filter, aDevice);
336 IntPtr pvId = USBLibAddFilter(ref Filter);
337 if (pvId == IntPtr.Zero) throw new Exception("Add one-shot Filter failed");
338 //USBLibRunFilters();
339 aDevice.Reenumerate(0);
340 }
341 public static IUsbDeviceRegistry GetDeviceForDeviceNode(DeviceNode device) {
342 String[] intfpath = device.GetInterfaces(new Guid(0x873fdf, 0xCAFE, 0x80EE, 0xaa, 0x5e, 0x0, 0xc0, 0x4f, 0xb1, 0x72, 0xb));
343 if (intfpath == null || intfpath.Length == 0) return null;
344 return new USBRegistry(device, intfpath[0]);
345 }
346
347 SafeHandle hDev;
348 Byte bInterfaceNumber;
349
350 public IUsbDeviceRegistry Registry { get; private set; }
351
352 internal unsafe VBoxUSB(USBRegistry devreg) {
353 this.Registry = devreg;
354 hDev = Kernel32.CreateFile(devreg.DevicePath, Kernel32.GENERIC_READ | Kernel32.GENERIC_WRITE, Kernel32.FILE_SHARE_WRITE | Kernel32.FILE_SHARE_READ, IntPtr.Zero, Kernel32.OPEN_EXISTING, Kernel32.FILE_ATTRIBUTE_SYSTEM | Kernel32.FILE_FLAG_OVERLAPPED, IntPtr.Zero);
355 if (hDev.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error());
356 try {
357 USBSUP_VERSION version = new USBSUP_VERSION();
358 SyncIoControl(hDev, SUPUSB_IOCTL_GET_VERSION, null, 0, &version, sizeof(USBSUP_VERSION));
359 if (version.u32Major != USBDRV_MAJOR_VERSION || version.u32Minor < USBDRV_MINOR_VERSION) throw new InvalidOperationException("Unsupported USBDRV version");
360 USBSUP_CLAIMDEV claim = new USBSUP_CLAIMDEV() { bInterfaceNumber = 0 };
361 SyncIoControl(hDev, SUPUSB_IOCTL_USB_CLAIM_DEVICE, &claim, sizeof(USBSUP_CLAIMDEV), &claim, sizeof(USBSUP_CLAIMDEV));
362 if (claim.fClaimed == 0) throw new InvalidOperationException("Claim failed");
363 } catch {
364 hDev.Close();
365 throw;
366 }
367 }
368 public unsafe override void Close() {
369 if (!hDev.IsInvalid && !hDev.IsClosed) {
370 USBSUP_CLAIMDEV release = new USBSUP_CLAIMDEV() { bInterfaceNumber = bInterfaceNumber };
371 SyncIoControl(hDev, SUPUSB_IOCTL_USB_RELEASE_DEVICE, &release, sizeof(USBSUP_CLAIMDEV), null, 0);
372 }
373 hDev.Close();
374 }
375
376 public unsafe override void BulkReset(byte endpoint) {
377 USBSUP_CLEAR_ENDPOINT inp = new USBSUP_CLEAR_ENDPOINT() { bEndpoint = endpoint };
378 SyncIoControl(hDev, SUPUSB_IOCTL_USB_CLEAR_ENDPOINT, &inp, sizeof(USBSUP_CLEAR_ENDPOINT), null, 0);
379 }
380 public override void InterruptReset(byte endpoint) {
381 BulkReset(endpoint);
382 }
383
384 public unsafe void ResetDevice() {
385 SyncIoControl(hDev, SUPUSB_IOCTL_USB_RESET, null, 0, null, 0);
386 }
387
388 public unsafe override byte Configuration {
389 get { return base.Configuration; }
390 set {
391 USBSUP_SET_CONFIG inp = new USBSUP_SET_CONFIG() { bConfigurationValue = value };
392 SyncIoControl(hDev, SUPUSB_IOCTL_USB_SET_CONFIG, &inp, sizeof(USBSUP_SET_CONFIG), null, 0);
393 }
394 }
395
396 private unsafe void HandleURB(USBSUP_URB* urb) {
397 using (ManualResetEvent evt = new ManualResetEvent(false)) {
398 NativeOverlapped overlapped = new NativeOverlapped();
399 overlapped.EventHandle = evt.SafeWaitHandle.DangerousGetHandle();
400 int size;
401 if (Kernel32.DeviceIoControl(hDev, SUPUSB_IOCTL_SEND_URB, urb, sizeof(USBSUP_URB), urb, sizeof(USBSUP_URB), out size, &overlapped))
402 return;
403 int err = Marshal.GetLastWin32Error();
404 if (err != 997) throw new Win32Exception(err);
405 evt.WaitOne();
406 if (!Kernel32.GetOverlappedResult(hDev, &overlapped, out size, false))
407 throw new Win32Exception(Marshal.GetLastWin32Error());
408 }
409 }
410
411 private unsafe int BlockTransfer(USBSUP_TRANSFER_TYPE type, USBSUP_DIRECTION dir, USBSUP_XFER_FLAG flags, UInt32 ep, Byte[] buffer, int offset, int length) {
412 fixed (Byte* ptr = buffer) {
413 USBSUP_URB urb = new USBSUP_URB();
414 urb.type = type;
415 urb.dir = dir;
416 urb.flags = flags;
417 urb.ep = ep;
418 urb.len = (UIntPtr)length;
419 urb.buf = ptr;
420 HandleURB(&urb);
421 return (int)urb.len;
422 }
423 }
424
425 public override int BulkWrite(byte endpoint, byte[] buffer, int offset, int length) {
426 return BlockTransfer(USBSUP_TRANSFER_TYPE.USBSUP_TRANSFER_TYPE_BULK, USBSUP_DIRECTION.USBSUP_DIRECTION_OUT, USBSUP_XFER_FLAG.USBSUP_FLAG_NONE, endpoint, buffer, offset, length);
427 }
428 public override int BulkRead(byte endpoint, byte[] buffer, int offset, int length) {
429 return BlockTransfer(USBSUP_TRANSFER_TYPE.USBSUP_TRANSFER_TYPE_BULK, USBSUP_DIRECTION.USBSUP_DIRECTION_IN, USBSUP_XFER_FLAG.USBSUP_FLAG_NONE, endpoint, buffer, offset, length);
430 }
431 public override int InterruptWrite(byte endpoint, byte[] buffer, int offset, int length) {
432 return BlockTransfer(USBSUP_TRANSFER_TYPE.USBSUP_TRANSFER_TYPE_INTR, USBSUP_DIRECTION.USBSUP_DIRECTION_OUT, USBSUP_XFER_FLAG.USBSUP_FLAG_NONE, endpoint, buffer, offset, length);
433 }
434 public override int InterruptRead(byte endpoint, byte[] buffer, int offset, int length) {
435 return BlockTransfer(USBSUP_TRANSFER_TYPE.USBSUP_TRANSFER_TYPE_INTR, USBSUP_DIRECTION.USBSUP_DIRECTION_IN, USBSUP_XFER_FLAG.USBSUP_FLAG_NONE, endpoint, buffer, offset, length);
436 }
437 private unsafe int ControlTransfer(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) {
438 Byte[] bigbuffer = new Byte[sizeof(UsbSetupPacket) + length];
439 Boolean isout = (requestType & UsbControlRequestType.EndpointMask) == UsbControlRequestType.EndpointOut;
440 if (isout && length > 0) Buffer.BlockCopy(buffer, offset, bigbuffer, sizeof(UsbSetupPacket), length);
441 fixed (Byte* ptr = bigbuffer) *(UsbSetupPacket*)ptr = new UsbSetupPacket((Byte)requestType, request, value, index, (short)length);
442 int dlen = BlockTransfer(USBSUP_TRANSFER_TYPE.USBSUP_TRANSFER_TYPE_MSG, isout ? USBSUP_DIRECTION.USBSUP_DIRECTION_OUT : USBSUP_DIRECTION.USBSUP_DIRECTION_IN, USBSUP_XFER_FLAG.USBSUP_FLAG_NONE, 0, bigbuffer, 0, bigbuffer.Length);
443 dlen -= sizeof(UsbSetupPacket);
444 if (dlen > length) dlen = length;
445 if (dlen < 0) dlen = 0;
446 if (!isout) Buffer.BlockCopy(bigbuffer, sizeof(UsbSetupPacket), buffer, offset, dlen);
447 return dlen;
448 }
449 public override int ControlWrite(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) {
450 return ControlTransfer(requestType, request, value, index, buffer, offset, length);
451 }
452 public override int ControlRead(UsbControlRequestType requestType, byte request, short value, short index, byte[] buffer, int offset, int length) {
453 return ControlTransfer(requestType, request, value, index, buffer, offset, length);
454 }
455
456 public void ClaimInterface(int interfaceID) {
457 bInterfaceNumber = (Byte)interfaceID;
458 }
459
460 public void ReleaseInterface(int interfaceID) {
461 }
462 }
463 }