Mercurial > hg > ucis.core
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 } |