VirtualBox

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

最後變更 在這個檔案從32010是 31890,由 vboxsync 提交於 15 年 前

OSE header fixes

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

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