VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/win/USBProxyDevice-win.cpp@ 56292

Last change on this file since 56292 was 56292, checked in by vboxsync, 10 years ago

Devices: Updated (C) year.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.5 KB
Line 
1/* $Id: USBProxyDevice-win.cpp 56292 2015-06-09 14:20:46Z vboxsync $ */
2/** @file
3 * USBPROXY - USB proxy, Win32 backend
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
23#include <windows.h>
24
25#include <VBox/vmm/pdm.h>
26#include <VBox/err.h>
27#include <VBox/usb.h>
28#include <VBox/log.h>
29#include <iprt/assert.h>
30#include <iprt/alloc.h>
31#include <iprt/err.h>
32#include <iprt/string.h>
33#include <iprt/thread.h>
34#include <iprt/asm.h>
35#include "../USBProxyDevice.h"
36#include <VBox/usblib.h>
37
38
39/*******************************************************************************
40* Structures and Typedefs *
41*******************************************************************************/
42typedef struct _QUEUED_URB
43{
44 PVUSBURB urb;
45
46 USBSUP_URB urbwin;
47 OVERLAPPED overlapped;
48 DWORD cbReturned;
49 bool fCancelled;
50} QUEUED_URB, *PQUEUED_URB;
51
52typedef struct
53{
54 /* Critical section to protect this structure. */
55 RTCRITSECT CritSect;
56 HANDLE hDev;
57 uint8_t bInterfaceNumber;
58 bool fClaimed;
59 /** The allocated size of paHandles and paQueuedUrbs. */
60 unsigned cAllocatedUrbs;
61 /** The number of URBs in the array. */
62 unsigned cQueuedUrbs;
63 /** Array of pointers to the in-flight URB structures. */
64 PQUEUED_URB *paQueuedUrbs;
65 /** Array of handles, this is parallel to paQueuedUrbs. */
66 PHANDLE paHandles;
67 /* Event sempahore to wakeup the reaper thead. */
68 HANDLE hEventWakeup;
69 /** Number of queued URBs waiting to get into the handle list. */
70 unsigned cPendingUrbs;
71 /** Array of pending URBs. */
72 PQUEUED_URB aPendingUrbs[64];
73} PRIV_USBW32, *PPRIV_USBW32;
74
75/* All functions are returning 1 on success, 0 on error */
76
77/*******************************************************************************
78* Internal Functions *
79*******************************************************************************/
80static int usbProxyWinSetInterface(PUSBPROXYDEV p, int ifnum, int setting);
81
82/**
83 * Converts the given Windows error code to VBox handling unplugged devices.
84 *
85 * @returns VBox status code.
86 * @param pProxDev The USB proxy device instance.
87 * @param dwErr Windows error code.
88 */
89static int usbProxyWinHandleUnpluggedDevice(PUSBPROXYDEV pProxyDev, DWORD dwErr)
90{
91 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
92
93 if ( dwErr == ERROR_INVALID_HANDLE_STATE
94 || dwErr == ERROR_BAD_COMMAND)
95 {
96 Log(("usbproxy: device %x unplugged!!\n", pPriv->hDev));
97 pProxyDev->fDetached = true;
98 }
99 else
100 AssertMsgFailed(("lasterr=%d\n", dwErr));
101 return RTErrConvertFromWin32(dwErr);
102}
103
104/**
105 * Open a USB device and create a backend instance for it.
106 *
107 * @returns VBox status code.
108 */
109static DECLCALLBACK(int) usbProxyWinOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
110{
111 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
112
113 int rc = VINF_SUCCESS;
114 pPriv->cAllocatedUrbs = 32;
115 pPriv->paHandles = (PHANDLE)RTMemAllocZ(sizeof(pPriv->paHandles[0]) * pPriv->cAllocatedUrbs);
116 pPriv->paQueuedUrbs = (PQUEUED_URB *)RTMemAllocZ(sizeof(pPriv->paQueuedUrbs[0]) * pPriv->cAllocatedUrbs);
117 if ( pPriv->paQueuedUrbs
118 && pPriv->paHandles)
119 {
120 /*
121 * Open the device.
122 */
123 pPriv->hDev = CreateFile(pszAddress,
124 GENERIC_READ | GENERIC_WRITE,
125 FILE_SHARE_WRITE | FILE_SHARE_READ,
126 NULL, // no SECURITY_ATTRIBUTES structure
127 OPEN_EXISTING, // No special create flags
128 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, // overlapped IO
129 NULL); // No template file
130 if (pPriv->hDev != INVALID_HANDLE_VALUE)
131 {
132 Log(("usbProxyWinOpen: hDev=%p\n", pPriv->hDev));
133
134 /*
135 * Check the version
136 */
137 USBSUP_VERSION version = {0};
138 DWORD cbReturned = 0;
139 if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_GET_VERSION, NULL, 0, &version, sizeof(version), &cbReturned, NULL))
140 {
141 if (!( version.u32Major != USBDRV_MAJOR_VERSION
142 || version.u32Minor < USBDRV_MINOR_VERSION))
143 {
144 USBSUP_CLAIMDEV in;
145 in.bInterfaceNumber = 0;
146
147 cbReturned = 0;
148 if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_CLAIM_DEVICE, &in, sizeof(in), &in, sizeof(in), &cbReturned, NULL))
149 {
150 if (in.fClaimed)
151 {
152 pPriv->fClaimed = true;
153#if 0 /** @todo this needs to be enabled if windows chooses a default config. Test with the TrekStor GO Stick. */
154 pProxyDev->iActiveCfg = 1;
155 pProxyDev->cIgnoreSetConfigs = 1;
156#endif
157
158 rc = RTCritSectInit(&pPriv->CritSect);
159 AssertRC(rc);
160 pPriv->hEventWakeup = CreateEvent(NULL, FALSE, FALSE, NULL);
161 Assert(pPriv->hEventWakeup);
162
163 pPriv->paHandles[0] = pPriv->hEventWakeup;
164
165 return VINF_SUCCESS;
166 }
167
168 rc = VERR_GENERAL_FAILURE;
169 Log(("usbproxy: unable to claim device %x (%s)!!\n", pPriv->hDev, pszAddress));
170 }
171 }
172 else
173 {
174 rc = VERR_VERSION_MISMATCH;
175 Log(("usbproxy: Version mismatch: %d.%d != %d.%d (cur)\n",
176 version.u32Major, version.u32Minor, USBDRV_MAJOR_VERSION, USBDRV_MINOR_VERSION));
177 }
178 }
179
180 /* Convert last error if necessary */
181 if (RT_SUCCESS(rc))
182 {
183 DWORD dwErr = GetLastError();
184 Log(("usbproxy: last error %d\n", dwErr));
185 rc = RTErrConvertFromWin32(dwErr);
186 }
187
188 CloseHandle(pPriv->hDev);
189 pPriv->hDev = INVALID_HANDLE_VALUE;
190 }
191 else
192 {
193 Log(("usbproxy: FAILED to open '%s'! last error %d\n", pszAddress, GetLastError()));
194 rc = VERR_FILE_NOT_FOUND;
195 }
196 }
197 else
198 rc = VERR_NO_MEMORY;
199
200 RTMemFree(pPriv->paQueuedUrbs);
201 RTMemFree(pPriv->paHandles);
202 return rc;
203}
204
205/**
206 * Copy the device and free resources associated with the backend.
207 */
208static DECLCALLBACK(void) usbProxyWinClose(PUSBPROXYDEV pProxyDev)
209{
210 /* Here we just close the device and free up p->priv
211 * there is no need to do anything like cancel outstanding requests
212 * that will have been done already
213 */
214 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
215 Assert(pPriv);
216 if (!pPriv)
217 return;
218 Log(("usbProxyWinClose: %p\n", pPriv->hDev));
219
220 if (pPriv->hDev != INVALID_HANDLE_VALUE)
221 {
222 Assert(pPriv->fClaimed);
223
224 USBSUP_RELEASEDEV in;
225 DWORD cbReturned = 0;
226 in.bInterfaceNumber = pPriv->bInterfaceNumber;
227 if (!DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_RELEASE_DEVICE, &in, sizeof(in), NULL, 0, &cbReturned, NULL))
228 {
229 Log(("usbproxy: usbProxyWinClose: DeviceIoControl %#x failed with %#x!!\n", pPriv->hDev, GetLastError()));
230 }
231 if (!CloseHandle(pPriv->hDev))
232 AssertLogRelMsgFailed(("usbproxy: usbProxyWinClose: CloseHandle %#x failed with %#x!!\n", pPriv->hDev, GetLastError()));
233 pPriv->hDev = INVALID_HANDLE_VALUE;
234 }
235
236 CloseHandle(pPriv->hEventWakeup);
237 RTCritSectDelete(&pPriv->CritSect);
238
239 RTMemFree(pPriv->paQueuedUrbs);
240 RTMemFree(pPriv->paHandles);
241}
242
243
244static DECLCALLBACK(int) usbProxyWinReset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
245{
246 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
247 DWORD cbReturned;
248 int rc;
249
250 Assert(pPriv);
251
252 Log(("usbproxy: Reset %x\n", pPriv->hDev));
253
254 /* Here we just need to assert reset signalling on the USB device */
255 cbReturned = 0;
256 if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_RESET, NULL, 0, NULL, 0, &cbReturned, NULL))
257 {
258#if 0 /** @todo this needs to be enabled if windows chooses a default config. Test with the TrekStor GO Stick. */
259 pProxyDev->iActiveCfg = 1;
260 pProxyDev->cIgnoreSetConfigs = 2;
261#else
262 pProxyDev->iActiveCfg = -1;
263 pProxyDev->cIgnoreSetConfigs = 0;
264#endif
265 return VINF_SUCCESS;
266 }
267
268 rc = GetLastError();
269 if (rc == ERROR_DEVICE_REMOVED)
270 {
271 Log(("usbproxy: device %p unplugged!!\n", pPriv->hDev));
272 pProxyDev->fDetached = true;
273 }
274 return RTErrConvertFromWin32(rc);
275}
276
277static DECLCALLBACK(int) usbProxyWinSetConfig(PUSBPROXYDEV pProxyDev, int cfg)
278{
279 /* Send a SET_CONFIGURATION command to the device. We don't do this
280 * as a normal control message, because the OS might not want to
281 * be left out of the loop on such a thing.
282 *
283 * It would be OK to send a SET_CONFIGURATION control URB at this
284 * point but it has to be synchronous.
285 */
286 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
287 USBSUP_SET_CONFIG in;
288 DWORD cbReturned;
289
290 Assert(pPriv);
291
292 Log(("usbproxy: Set config of %p to %d\n", pPriv->hDev, cfg));
293 in.bConfigurationValue = cfg;
294
295 /* Here we just need to assert reset signalling on the USB device */
296 cbReturned = 0;
297 if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_SET_CONFIG, &in, sizeof(in), NULL, 0, &cbReturned, NULL))
298 return VINF_SUCCESS;
299
300 return usbProxyWinHandleUnpluggedDevice(pProxyDev, GetLastError());
301}
302
303static DECLCALLBACK(int) usbProxyWinClaimInterface(PUSBPROXYDEV pProxyDev, int ifnum)
304{
305 /* Called just before we use an interface. Needed on Linux to claim
306 * the interface from the OS, since even when proxying the host OS
307 * might want to allow other programs to use the unused interfaces.
308 * Not relevant for Windows.
309 */
310 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
311
312 pPriv->bInterfaceNumber = ifnum;
313
314 Assert(pPriv);
315 return VINF_SUCCESS;
316}
317
318static DECLCALLBACK(int) usbProxyWinReleaseInterface(PUSBPROXYDEV pProxyDev, int ifnum)
319{
320 /* The opposite of claim_interface. */
321 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
322
323 Assert(pPriv);
324 return VINF_SUCCESS;
325}
326
327static DECLCALLBACK(int) usbProxyWinSetInterface(PUSBPROXYDEV pProxyDev, int ifnum, int setting)
328{
329 /* Select an alternate setting for an interface, the same applies
330 * here as for set_config, you may convert this in to a control
331 * message if you want but it must be synchronous
332 */
333 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
334 USBSUP_SELECT_INTERFACE in;
335 DWORD cbReturned;
336
337 Assert(pPriv);
338
339 Log(("usbproxy: Select interface of %x to %d/%d\n", pPriv->hDev, ifnum, setting));
340 in.bInterfaceNumber = ifnum;
341 in.bAlternateSetting = setting;
342
343 /* Here we just need to assert reset signalling on the USB device */
344 cbReturned = 0;
345 if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_SELECT_INTERFACE, &in, sizeof(in), NULL, 0, &cbReturned, NULL))
346 return VINF_SUCCESS;
347
348 return usbProxyWinHandleUnpluggedDevice(pProxyDev, GetLastError());
349}
350
351/**
352 * Clears the halted endpoint 'ep'.
353 */
354static DECLCALLBACK(int) usbProxyWinClearHaltedEndPt(PUSBPROXYDEV pProxyDev, unsigned int ep)
355{
356 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
357 USBSUP_CLEAR_ENDPOINT in;
358 DWORD cbReturned;
359
360 Assert(pPriv);
361
362 Log(("usbproxy: Clear endpoint %d of %x\n", ep, pPriv->hDev));
363 in.bEndpoint = ep;
364
365 cbReturned = 0;
366 if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_CLEAR_ENDPOINT, &in, sizeof(in), NULL, 0, &cbReturned, NULL))
367 return VINF_SUCCESS;
368
369 return usbProxyWinHandleUnpluggedDevice(pProxyDev, GetLastError());
370}
371
372/**
373 * Aborts a pipe/endpoint (cancels all outstanding URBs on the endpoint).
374 */
375static int usbProxyWinAbortEndPt(PUSBPROXYDEV pProxyDev, unsigned int ep)
376{
377 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
378 USBSUP_CLEAR_ENDPOINT in;
379 DWORD cbReturned;
380 int rc;
381
382 Assert(pPriv);
383
384 Log(("usbproxy: Abort endpoint %d of %x\n", ep, pPriv->hDev));
385 in.bEndpoint = ep;
386
387 cbReturned = 0;
388 if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_ABORT_ENDPOINT, &in, sizeof(in), NULL, 0, &cbReturned, NULL))
389 return VINF_SUCCESS;
390
391 return usbProxyWinHandleUnpluggedDevice(pProxyDev, GetLastError());
392}
393
394/**
395 * @copydoc USBPROXYBACK::pfnUrbQueue
396 */
397static DECLCALLBACK(int) usbProxyWinUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
398{
399 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
400 Assert(pPriv);
401
402 /*
403 * Allocate and initialize a URB queue structure.
404 */
405 /** @todo pool these */
406 PQUEUED_URB pQUrbWin = (PQUEUED_URB)RTMemAllocZ(sizeof(QUEUED_URB));
407 if (!pQUrbWin)
408 return VERR_NO_MEMORY;
409
410 switch (pUrb->enmType)
411 {
412 case VUSBXFERTYPE_CTRL: pQUrbWin->urbwin.type = USBSUP_TRANSFER_TYPE_CTRL; break; /* you won't ever see these */
413 case VUSBXFERTYPE_ISOC: pQUrbWin->urbwin.type = USBSUP_TRANSFER_TYPE_ISOC;
414 pQUrbWin->urbwin.numIsoPkts = pUrb->cIsocPkts;
415 for (unsigned i = 0; i < pUrb->cIsocPkts; ++i)
416 {
417 pQUrbWin->urbwin.aIsoPkts[i].cb = pUrb->aIsocPkts[i].cb;
418 pQUrbWin->urbwin.aIsoPkts[i].off = pUrb->aIsocPkts[i].off;
419 pQUrbWin->urbwin.aIsoPkts[i].stat = USBSUP_XFER_OK;
420 }
421 break;
422 case VUSBXFERTYPE_BULK: pQUrbWin->urbwin.type = USBSUP_TRANSFER_TYPE_BULK; break;
423 case VUSBXFERTYPE_INTR: pQUrbWin->urbwin.type = USBSUP_TRANSFER_TYPE_INTR; break;
424 case VUSBXFERTYPE_MSG: pQUrbWin->urbwin.type = USBSUP_TRANSFER_TYPE_MSG; break;
425 default:
426 AssertMsgFailed(("Invalid type %d\n", pUrb->enmType));
427 return VERR_INVALID_PARAMETER;
428 }
429
430 switch (pUrb->enmDir)
431 {
432 case VUSBDIRECTION_SETUP:
433 AssertFailed();
434 pQUrbWin->urbwin.dir = USBSUP_DIRECTION_SETUP;
435 break;
436 case VUSBDIRECTION_IN:
437 pQUrbWin->urbwin.dir = USBSUP_DIRECTION_IN;
438 break;
439 case VUSBDIRECTION_OUT:
440 pQUrbWin->urbwin.dir = USBSUP_DIRECTION_OUT;
441 break;
442 default:
443 AssertMsgFailed(("Invalid direction %d\n", pUrb->enmDir));
444 return VERR_INVALID_PARAMETER;
445 }
446
447 Log(("usbproxy: Queue URB %p ep=%d cbData=%d abData=%p cIsocPkts=%d\n", pUrb, pUrb->EndPt, pUrb->cbData, pUrb->abData, pUrb->cIsocPkts));
448
449 pQUrbWin->urb = pUrb;
450 pQUrbWin->urbwin.ep = pUrb->EndPt;
451 pQUrbWin->urbwin.len = pUrb->cbData;
452 pQUrbWin->urbwin.buf = pUrb->abData;
453 pQUrbWin->urbwin.error = USBSUP_XFER_OK;
454 pQUrbWin->urbwin.flags = USBSUP_FLAG_NONE;
455 if (pUrb->enmDir == VUSBDIRECTION_IN && !pUrb->fShortNotOk)
456 pQUrbWin->urbwin.flags = USBSUP_FLAG_SHORT_OK;
457
458 int rc = VINF_SUCCESS;
459 pQUrbWin->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
460 if (pQUrbWin->overlapped.hEvent != INVALID_HANDLE_VALUE)
461 {
462 pUrb->Dev.pvPrivate = pQUrbWin;
463
464 if ( DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_SEND_URB,
465 &pQUrbWin->urbwin, sizeof(pQUrbWin->urbwin),
466 &pQUrbWin->urbwin, sizeof(pQUrbWin->urbwin),
467 &pQUrbWin->cbReturned, &pQUrbWin->overlapped)
468 || GetLastError() == ERROR_IO_PENDING)
469 {
470 /* insert into the queue */
471 RTCritSectEnter(&pPriv->CritSect);
472 unsigned j = pPriv->cPendingUrbs;
473 pPriv->aPendingUrbs[j] = pQUrbWin;
474 pPriv->cPendingUrbs++;
475 RTCritSectLeave(&pPriv->CritSect);
476 SetEvent(pPriv->hEventWakeup);
477 return VINF_SUCCESS;
478 }
479 else
480 {
481 DWORD dwErr = GetLastError();
482 if ( dwErr == ERROR_INVALID_HANDLE_STATE
483 || dwErr == ERROR_BAD_COMMAND)
484 {
485 Log(("usbproxy: device %p unplugged!!\n", pPriv->hDev));
486 pProxyDev->fDetached = true;
487 }
488 else
489 AssertMsgFailed(("dwErr=%X urbwin.error=%d (submit urb)\n", dwErr, pQUrbWin->urbwin.error));
490 rc = RTErrConvertFromWin32(dwErr);
491 CloseHandle(pQUrbWin->overlapped.hEvent);
492 pQUrbWin->overlapped.hEvent = INVALID_HANDLE_VALUE;
493 }
494 }
495#ifdef DEBUG_misha
496 else
497 {
498 AssertMsgFailed(("FAILED!!, hEvent(0x%p)\n", pQUrbWin->overlapped.hEvent));
499 rc = VERR_NO_MEMORY;
500 }
501#endif
502
503 Assert(pQUrbWin->overlapped.hEvent == INVALID_HANDLE_VALUE);
504 RTMemFree(pQUrbWin);
505 return rc;
506}
507
508/**
509 * Convert Windows proxy URB status to VUSB status.
510 *
511 * @returns VUSB status constant.
512 * @param win_status Windows USB proxy status constant.
513 */
514static VUSBSTATUS usbProxyWinStatusToVUsbStatus(USBSUP_ERROR win_status)
515{
516 VUSBSTATUS vusb_status;
517
518 switch (win_status)
519 {
520 case USBSUP_XFER_OK: vusb_status = VUSBSTATUS_OK; break;
521 case USBSUP_XFER_STALL: vusb_status = VUSBSTATUS_STALL; break;
522 case USBSUP_XFER_DNR: vusb_status = VUSBSTATUS_DNR; break;
523 case USBSUP_XFER_CRC: vusb_status = VUSBSTATUS_CRC; break;
524 case USBSUP_XFER_NAC: vusb_status = VUSBSTATUS_NOT_ACCESSED; break;
525 case USBSUP_XFER_UNDERRUN: vusb_status = VUSBSTATUS_DATA_UNDERRUN; break;
526 case USBSUP_XFER_OVERRUN: vusb_status = VUSBSTATUS_DATA_OVERRUN; break;
527 default:
528 AssertMsgFailed(("USB: Invalid error %d\n", win_status));
529 vusb_status = VUSBSTATUS_DNR;
530 break;
531 }
532 return vusb_status;
533}
534
535/**
536 * Reap URBs in-flight on a device.
537 *
538 * @returns Pointer to a completed URB.
539 * @returns NULL if no URB was completed.
540 * @param pProxyDev The device.
541 * @param cMillies Number of milliseconds to wait. Use 0 to not
542 * wait at all.
543 */
544static DECLCALLBACK(PVUSBURB) usbProxyWinUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
545{
546 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
547 AssertReturn(pPriv, NULL);
548
549 /*
550 * There are some unnecessary calls, just return immediately or
551 * WaitForMultipleObjects will fail.
552 */
553 if ( pPriv->cQueuedUrbs <= 0
554 && pPriv->cPendingUrbs == 0)
555 {
556 if ( cMillies != 0
557 && pPriv->cPendingUrbs == 0)
558 {
559 /* Wait for the wakeup call. */
560 DWORD cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies;
561 DWORD rc = WaitForMultipleObjects(1, &pPriv->hEventWakeup, FALSE, cMilliesWait);
562 }
563
564 return NULL;
565 }
566
567again:
568 /* Check for pending URBs. */
569 if (pPriv->cPendingUrbs)
570 {
571 RTCritSectEnter(&pPriv->CritSect);
572
573 /* Ensure we've got sufficient space in the arrays. */
574 if (pPriv->cQueuedUrbs + pPriv->cPendingUrbs + 1 > pPriv->cAllocatedUrbs)
575 {
576 unsigned cNewMax = pPriv->cAllocatedUrbs + pPriv->cPendingUrbs + 1;
577 void *pv = RTMemRealloc(pPriv->paHandles, sizeof(pPriv->paHandles[0]) * (cNewMax + 1)); /* One extra for the wakeup event. */
578 if (!pv)
579 {
580 AssertMsgFailed(("RTMemRealloc failed for paHandles[%d]", cNewMax));
581 //break;
582 }
583 pPriv->paHandles = (PHANDLE)pv;
584
585 pv = RTMemRealloc(pPriv->paQueuedUrbs, sizeof(pPriv->paQueuedUrbs[0]) * cNewMax);
586 if (!pv)
587 {
588 AssertMsgFailed(("RTMemRealloc failed for paQueuedUrbs[%d]", cNewMax));
589 //break;
590 }
591 pPriv->paQueuedUrbs = (PQUEUED_URB *)pv;
592 pPriv->cAllocatedUrbs = cNewMax;
593 }
594
595 /* Copy the pending URBs over. */
596 for (unsigned i = 0; i < pPriv->cPendingUrbs; i++)
597 {
598 pPriv->paHandles[pPriv->cQueuedUrbs + i] = pPriv->aPendingUrbs[i]->overlapped.hEvent;
599 pPriv->paQueuedUrbs[pPriv->cQueuedUrbs + i] = pPriv->aPendingUrbs[i];
600 }
601 pPriv->cQueuedUrbs += pPriv->cPendingUrbs;
602 pPriv->cPendingUrbs = 0;
603 pPriv->paHandles[pPriv->cQueuedUrbs] = pPriv->hEventWakeup;
604 pPriv->paHandles[pPriv->cQueuedUrbs + 1] = INVALID_HANDLE_VALUE;
605
606 RTCritSectLeave(&pPriv->CritSect);
607 }
608
609 /*
610 * Wait/poll.
611 *
612 * ASSUMPTIONS:
613 * 1. The usbProxyWinUrbReap can not be run concurrently with each other
614 * so racing the cQueuedUrbs access/modification can not occur.
615 * 2. The usbProxyWinUrbReap can not be run concurrently with
616 * usbProxyWinUrbQueue so they can not race the pPriv->paHandles
617 * access/realloc.
618 */
619 unsigned cQueuedUrbs = ASMAtomicReadU32((volatile uint32_t *)&pPriv->cQueuedUrbs);
620 DWORD cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies;
621 PVUSBURB pUrb = NULL;
622 DWORD rc = WaitForMultipleObjects(cQueuedUrbs + 1, pPriv->paHandles, FALSE, cMilliesWait);
623
624 /* If the wakeup event fired return immediately. */
625 if (rc == WAIT_OBJECT_0 + cQueuedUrbs)
626 {
627 if (pPriv->cPendingUrbs)
628 goto again;
629 return NULL;
630 }
631
632 if (rc >= WAIT_OBJECT_0 && rc < WAIT_OBJECT_0 + cQueuedUrbs)
633 {
634 RTCritSectEnter(&pPriv->CritSect);
635 unsigned iUrb = rc - WAIT_OBJECT_0;
636 PQUEUED_URB pQUrbWin = pPriv->paQueuedUrbs[iUrb];
637 pUrb = pQUrbWin->urb;
638
639 /*
640 * Remove it from the arrays.
641 */
642 cQueuedUrbs = --pPriv->cQueuedUrbs;
643 if (cQueuedUrbs != iUrb)
644 {
645 /* Move the array forward */
646 for (unsigned i=iUrb;i<cQueuedUrbs;i++)
647 {
648 pPriv->paHandles[i] = pPriv->paHandles[i+1];
649 pPriv->paQueuedUrbs[i] = pPriv->paQueuedUrbs[i+1];
650 }
651 }
652 pPriv->paHandles[cQueuedUrbs] = pPriv->hEventWakeup;
653 pPriv->paHandles[cQueuedUrbs + 1] = INVALID_HANDLE_VALUE;
654 pPriv->paQueuedUrbs[cQueuedUrbs] = NULL;
655 RTCritSectLeave(&pPriv->CritSect);
656 Assert(cQueuedUrbs == pPriv->cQueuedUrbs);
657
658 /*
659 * Update the urb.
660 */
661 pUrb->enmStatus = usbProxyWinStatusToVUsbStatus(pQUrbWin->urbwin.error);
662 pUrb->cbData = (uint32_t)pQUrbWin->urbwin.len;
663 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
664 {
665 for (unsigned i = 0; i < pUrb->cIsocPkts; ++i)
666 {
667 /* NB: Windows won't change the packet offsets, but the packets may
668 * be only partially filled or completely empty.
669 */
670 pUrb->aIsocPkts[i].enmStatus = usbProxyWinStatusToVUsbStatus(pQUrbWin->urbwin.aIsoPkts[i].stat);
671 pUrb->aIsocPkts[i].cb = pQUrbWin->urbwin.aIsoPkts[i].cb;
672 }
673 }
674 Log(("usbproxy: pUrb=%p (#%d) ep=%d cbData=%d status=%d cIsocPkts=%d ready\n",
675 pUrb, rc - WAIT_OBJECT_0, pQUrbWin->urb->EndPt, pQUrbWin->urb->cbData, pUrb->enmStatus, pUrb->cIsocPkts));
676
677 /* free the urb queuing structure */
678 if (pQUrbWin->overlapped.hEvent != INVALID_HANDLE_VALUE)
679 {
680 CloseHandle(pQUrbWin->overlapped.hEvent);
681 pQUrbWin->overlapped.hEvent = INVALID_HANDLE_VALUE;
682 }
683 RTMemFree(pQUrbWin);
684 }
685 else if ( rc == WAIT_FAILED
686 || (rc >= WAIT_ABANDONED_0 && rc < WAIT_ABANDONED_0 + cQueuedUrbs))
687 AssertMsgFailed(("USB: WaitForMultipleObjects %d objects failed with rc=%d and last error %d\n", cQueuedUrbs, rc, GetLastError()));
688
689 return pUrb;
690}
691
692
693/**
694 * Cancels an in-flight URB.
695 *
696 * The URB requires reaping, so we don't change its state.
697 *
698 * @remark There isn't a way to cancel a specific URB on Windows.
699 * on darwin. The interface only supports the aborting of
700 * all URBs pending on an endpoint. Luckily that is usually
701 * exactly what the guest wants to do.
702 */
703static DECLCALLBACK(int) usbProxyWinUrbCancel(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
704{
705 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
706 PQUEUED_URB pQUrbWin = (PQUEUED_URB)pUrb->Dev.pvPrivate;
707 USBSUP_CLEAR_ENDPOINT in;
708 DWORD cbReturned;
709
710 AssertPtrReturn(pQUrbWin, VERR_INVALID_PARAMETER);
711
712 in.bEndpoint = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? 0x80 : 0);
713 Log(("Cancel urb %p, endpoint %x\n", pUrb, in.bEndpoint));
714
715 cbReturned = 0;
716 if (DeviceIoControl(pPriv->hDev, SUPUSB_IOCTL_USB_ABORT_ENDPOINT, &in, sizeof(in), NULL, 0, &cbReturned, NULL))
717 return VINF_SUCCESS;
718
719 DWORD dwErr = GetLastError();
720 if ( dwErr == ERROR_INVALID_HANDLE_STATE
721 || dwErr == ERROR_BAD_COMMAND)
722 {
723 Log(("usbproxy: device %x unplugged!!\n", pPriv->hDev));
724 pProxyDev->fDetached = true;
725 return VINF_SUCCESS; /* Fake success and deal with the unplugged device elsewhere. */
726 }
727
728 AssertMsgFailed(("lastErr=%ld\n", dwErr));
729 return RTErrConvertFromWin32(dwErr);
730}
731
732static DECLCALLBACK(int) usbProxyWinWakeup(PUSBPROXYDEV pProxyDev)
733{
734 PPRIV_USBW32 pPriv = USBPROXYDEV_2_DATA(pProxyDev, PPRIV_USBW32);
735
736 SetEvent(pPriv->hEventWakeup);
737 return VINF_SUCCESS;
738}
739
740/**
741 * The Win32 USB Proxy Backend.
742 */
743extern const USBPROXYBACK g_USBProxyDeviceHost =
744{
745 /* pszName */
746 "host",
747 /* cbBackend */
748 sizeof(PRIV_USBW32),
749 usbProxyWinOpen,
750 NULL,
751 usbProxyWinClose,
752 usbProxyWinReset,
753 usbProxyWinSetConfig,
754 usbProxyWinClaimInterface,
755 usbProxyWinReleaseInterface,
756 usbProxyWinSetInterface,
757 usbProxyWinClearHaltedEndPt,
758 usbProxyWinUrbQueue,
759 usbProxyWinUrbCancel,
760 usbProxyWinUrbReap,
761 usbProxyWinWakeup,
762 0
763};
764
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette