VirtualBox

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

Last change on this file since 59010 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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