VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/VUSBUrb.cpp@ 91942

Last change on this file since 91942 was 90049, checked in by vboxsync, 3 years ago

VUSB: If a descriptor read can't be satisfied from cache, pass it through to device rather than returning an error (stall). Fixes a problem with buggy drivers for Logitech C930e from Windows Update (see bugref:10059).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 51.9 KB
Line 
1/* $Id: VUSBUrb.cpp 90049 2021-07-06 10:23:26Z vboxsync $ */
2/** @file
3 * Virtual USB - URBs.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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_VUSB
23#include <VBox/vmm/pdm.h>
24#include <VBox/vmm/vmapi.h>
25#include <VBox/err.h>
26#include <iprt/alloc.h>
27#include <VBox/log.h>
28#include <iprt/time.h>
29#include <iprt/thread.h>
30#include <iprt/semaphore.h>
31#include <iprt/string.h>
32#include <iprt/assert.h>
33#include <iprt/asm.h>
34#include <iprt/env.h>
35#include "VUSBInternal.h"
36
37
38
39/*********************************************************************************************************************************
40* Global Variables *
41*********************************************************************************************************************************/
42/** Strings for the CTLSTAGE enum values. */
43const char * const g_apszCtlStates[4] =
44{
45 "SETUP",
46 "DATA",
47 "STATUS",
48 "N/A"
49};
50
51
52/*********************************************************************************************************************************
53* Internal Functions *
54*********************************************************************************************************************************/
55
56
57/**
58 * Complete a SETUP stage URB.
59 *
60 * This is used both for dev2host and host2dev kind of transfers.
61 * It is used by both the sync and async control paths.
62 */
63static void vusbMsgSetupCompletion(PVUSBURB pUrb)
64{
65 PVUSBDEV pDev = pUrb->pVUsb->pDev;
66 PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
67 PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
68 PVUSBSETUP pSetup = pExtra->pMsg;
69
70 LogFlow(("%s: vusbMsgSetupCompletion: cbData=%d wLength=%#x cbLeft=%d pPipe=%p stage %s->DATA\n",
71 pUrb->pszDesc, pUrb->cbData, pSetup->wLength, pExtra->cbLeft, pPipe, g_apszCtlStates[pExtra->enmStage])); NOREF(pSetup);
72 pExtra->enmStage = CTLSTAGE_DATA;
73 pUrb->enmStatus = VUSBSTATUS_OK;
74}
75
76/**
77 * Complete a DATA stage URB.
78 *
79 * This is used both for dev2host and host2dev kind of transfers.
80 * It is used by both the sync and async control paths.
81 */
82static void vusbMsgDataCompletion(PVUSBURB pUrb)
83{
84 PVUSBDEV pDev = pUrb->pVUsb->pDev;
85 PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
86 PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
87 PVUSBSETUP pSetup = pExtra->pMsg;
88
89 LogFlow(("%s: vusbMsgDataCompletion: cbData=%d wLength=%#x cbLeft=%d pPipe=%p stage DATA\n",
90 pUrb->pszDesc, pUrb->cbData, pSetup->wLength, pExtra->cbLeft, pPipe)); NOREF(pSetup);
91
92 pUrb->enmStatus = VUSBSTATUS_OK;
93}
94
95/**
96 * Complete a STATUS stage URB.
97 *
98 * This is used both for dev2host and host2dev kind of transfers.
99 * It is used by both the sync and async control paths.
100 */
101static void vusbMsgStatusCompletion(PVUSBURB pUrb)
102{
103 PVUSBDEV pDev = pUrb->pVUsb->pDev;
104 PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
105 PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
106
107 if (pExtra->fOk)
108 {
109 /*
110 * vusbDevStdReqSetAddress requests are deferred.
111 */
112 if (pDev->u8NewAddress != VUSB_INVALID_ADDRESS)
113 {
114 vusbDevSetAddress(pDev, pDev->u8NewAddress);
115 pDev->u8NewAddress = VUSB_INVALID_ADDRESS;
116 }
117
118 LogFlow(("%s: vusbMsgStatusCompletion: pDev=%p[%s] pPipe=%p err=OK stage %s->SETUP\n",
119 pUrb->pszDesc, pDev, pDev->pUsbIns->pszName, pPipe, g_apszCtlStates[pExtra->enmStage]));
120 pUrb->enmStatus = VUSBSTATUS_OK;
121 }
122 else
123 {
124 LogFlow(("%s: vusbMsgStatusCompletion: pDev=%p[%s] pPipe=%p err=STALL stage %s->SETUP\n",
125 pUrb->pszDesc, pDev, pDev->pUsbIns->pszName, pPipe, g_apszCtlStates[pExtra->enmStage]));
126 pUrb->enmStatus = VUSBSTATUS_STALL;
127 }
128
129 /*
130 * Done with this message sequence.
131 */
132 pExtra->pbCur = NULL;
133 pExtra->enmStage = CTLSTAGE_SETUP;
134}
135
136/**
137 * This is a worker function for vusbMsgCompletion and
138 * vusbMsgSubmitSynchronously used to complete the original URB.
139 *
140 * @param pUrb The URB originating from the HCI.
141 */
142static void vusbCtrlCompletion(PVUSBURB pUrb)
143{
144 PVUSBDEV pDev = pUrb->pVUsb->pDev;
145 PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
146 PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
147 LogFlow(("%s: vusbCtrlCompletion: pDev=%p[%s]\n", pUrb->pszDesc, pDev, pDev->pUsbIns->pszName));
148
149 switch (pExtra->enmStage)
150 {
151 case CTLSTAGE_SETUP:
152 vusbMsgSetupCompletion(pUrb);
153 break;
154 case CTLSTAGE_DATA:
155 vusbMsgDataCompletion(pUrb);
156 break;
157 case CTLSTAGE_STATUS:
158 vusbMsgStatusCompletion(pUrb);
159 break;
160 }
161}
162
163/**
164 * Called from vusbUrbCompletionRh when it encounters a
165 * message type URB.
166 *
167 * @param pUrb The URB within the control pipe extra state data.
168 */
169static void vusbMsgCompletion(PVUSBURB pUrb)
170{
171 PVUSBDEV pDev = pUrb->pVUsb->pDev;
172 PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
173
174 RTCritSectEnter(&pPipe->CritSectCtrl);
175 PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
176
177#ifdef LOG_ENABLED
178 LogFlow(("%s: vusbMsgCompletion: pDev=%p[%s]\n", pUrb->pszDesc, pDev, pDev->pUsbIns->pszName));
179 vusbUrbTrace(pUrb, "vusbMsgCompletion", true);
180#endif
181 Assert(&pExtra->Urb == pUrb);
182
183
184 if (pUrb->enmStatus == VUSBSTATUS_OK)
185 pExtra->fOk = true;
186 else
187 pExtra->fOk = false;
188 pExtra->cbLeft = pUrb->cbData - sizeof(VUSBSETUP);
189
190 /*
191 * Complete the original URB.
192 */
193 PVUSBURB pCtrlUrb = pUrb->pVUsb->pCtrlUrb;
194 pCtrlUrb->enmState = VUSBURBSTATE_REAPED;
195 vusbCtrlCompletion(pCtrlUrb);
196
197 /*
198 * 'Free' the message URB, i.e. put it back to the allocated state.
199 */
200 Assert( pUrb->enmState == VUSBURBSTATE_REAPED
201 || pUrb->enmState == VUSBURBSTATE_CANCELLED);
202 if (pUrb->enmState != VUSBURBSTATE_CANCELLED)
203 {
204 pUrb->enmState = VUSBURBSTATE_ALLOCATED;
205 pUrb->fCompleting = false;
206 }
207 RTCritSectLeave(&pPipe->CritSectCtrl);
208
209 /* Complete the original control URB on the root hub now. */
210 vusbUrbCompletionRh(pCtrlUrb);
211}
212
213/**
214 * Deal with URB errors, talking thru the RH to the HCI.
215 *
216 * @returns true if it could be retried.
217 * @returns false if it should be completed with failure.
218 * @param pUrb The URB in question.
219 */
220int vusbUrbErrorRh(PVUSBURB pUrb)
221{
222 PVUSBDEV pDev = pUrb->pVUsb->pDev;
223 PVUSBROOTHUB pRh = vusbDevGetRh(pDev);
224 AssertPtrReturn(pRh, VERR_VUSB_DEVICE_NOT_ATTACHED);
225 LogFlow(("%s: vusbUrbErrorRh: pDev=%p[%s] rh=%p\n", pUrb->pszDesc, pDev, pDev->pUsbIns ? pDev->pUsbIns->pszName : "", pRh));
226 return pRh->pIRhPort->pfnXferError(pRh->pIRhPort, pUrb);
227}
228
229/**
230 * Does URB completion on roothub level.
231 *
232 * @param pUrb The URB to complete.
233 */
234void vusbUrbCompletionRh(PVUSBURB pUrb)
235{
236 LogFlow(("%s: vusbUrbCompletionRh: type=%s status=%s\n",
237 pUrb->pszDesc, vusbUrbTypeName(pUrb->enmType), vusbUrbStatusName(pUrb->enmStatus)));
238 AssertMsg( pUrb->enmState == VUSBURBSTATE_REAPED
239 || pUrb->enmState == VUSBURBSTATE_CANCELLED, ("%d\n", pUrb->enmState));
240
241 if ( pUrb->pVUsb->pDev
242 && pUrb->pVUsb->pDev->hSniffer)
243 {
244 int rc = VUSBSnifferRecordEvent(pUrb->pVUsb->pDev->hSniffer, pUrb,
245 pUrb->enmStatus == VUSBSTATUS_OK
246 ? VUSBSNIFFEREVENT_COMPLETE
247 : VUSBSNIFFEREVENT_ERROR_COMPLETE);
248 if (RT_FAILURE(rc))
249 LogRel(("VUSB: Capturing URB completion event failed with %Rrc\n", rc));
250 }
251
252 PVUSBROOTHUB pRh = vusbDevGetRh(pUrb->pVUsb->pDev);
253 AssertPtrReturnVoid(pRh);
254
255 /* If there is a sniffer on the roothub record the completed URB there too. */
256 if (pRh->hSniffer != VUSBSNIFFER_NIL)
257 {
258 int rc = VUSBSnifferRecordEvent(pRh->hSniffer, pUrb,
259 pUrb->enmStatus == VUSBSTATUS_OK
260 ? VUSBSNIFFEREVENT_COMPLETE
261 : VUSBSNIFFEREVENT_ERROR_COMPLETE);
262 if (RT_FAILURE(rc))
263 LogRel(("VUSB: Capturing URB completion event on the root hub failed with %Rrc\n", rc));
264 }
265
266#ifdef VBOX_WITH_STATISTICS
267 /*
268 * Total and per-type submit statistics.
269 */
270 if (pUrb->enmType != VUSBXFERTYPE_MSG)
271 {
272 Assert(pUrb->enmType >= 0 && pUrb->enmType < (int)RT_ELEMENTS(pRh->aTypes));
273
274 if ( pUrb->enmStatus == VUSBSTATUS_OK
275 || pUrb->enmStatus == VUSBSTATUS_DATA_UNDERRUN
276 || pUrb->enmStatus == VUSBSTATUS_DATA_OVERRUN)
277 {
278 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
279 {
280 for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
281 {
282 const unsigned cb = pUrb->aIsocPkts[i].cb;
283 if (cb)
284 {
285 STAM_COUNTER_ADD(&pRh->Total.StatActBytes, cb);
286 STAM_COUNTER_ADD(&pRh->aTypes[VUSBXFERTYPE_ISOC].StatActBytes, cb);
287 STAM_COUNTER_ADD(&pRh->aStatIsocDetails[i].Bytes, cb);
288 if (pUrb->enmDir == VUSBDIRECTION_IN)
289 {
290 STAM_COUNTER_ADD(&pRh->Total.StatActReadBytes, cb);
291 STAM_COUNTER_ADD(&pRh->aTypes[VUSBXFERTYPE_ISOC].StatActReadBytes, cb);
292 }
293 else
294 {
295 STAM_COUNTER_ADD(&pRh->Total.StatActWriteBytes, cb);
296 STAM_COUNTER_ADD(&pRh->aTypes[VUSBXFERTYPE_ISOC].StatActWriteBytes, cb);
297 }
298 STAM_COUNTER_INC(&pRh->StatIsocActPkts);
299 STAM_COUNTER_INC(&pRh->StatIsocActReadPkts);
300 }
301 STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].Pkts);
302 switch (pUrb->aIsocPkts[i].enmStatus)
303 {
304 case VUSBSTATUS_OK:
305 if (cb) STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].Ok);
306 else STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].Ok0); break;
307 case VUSBSTATUS_DATA_UNDERRUN:
308 if (cb) STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].DataUnderrun);
309 else STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].DataUnderrun0); break;
310 case VUSBSTATUS_DATA_OVERRUN: STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].DataOverrun); break;
311 case VUSBSTATUS_NOT_ACCESSED: STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].NotAccessed); break;
312 default: STAM_COUNTER_INC(&pRh->aStatIsocDetails[i].Misc); break;
313 }
314 }
315 }
316 else
317 {
318 STAM_COUNTER_ADD(&pRh->Total.StatActBytes, pUrb->cbData);
319 STAM_COUNTER_ADD(&pRh->aTypes[pUrb->enmType].StatActBytes, pUrb->cbData);
320 if (pUrb->enmDir == VUSBDIRECTION_IN)
321 {
322 STAM_COUNTER_ADD(&pRh->Total.StatActReadBytes, pUrb->cbData);
323 STAM_COUNTER_ADD(&pRh->aTypes[pUrb->enmType].StatActReadBytes, pUrb->cbData);
324 }
325 else
326 {
327 STAM_COUNTER_ADD(&pRh->Total.StatActWriteBytes, pUrb->cbData);
328 STAM_COUNTER_ADD(&pRh->aTypes[pUrb->enmType].StatActWriteBytes, pUrb->cbData);
329 }
330 }
331 }
332 else
333 {
334 /* (Note. this also counts the cancelled packets) */
335 STAM_COUNTER_INC(&pRh->Total.StatUrbsFailed);
336 STAM_COUNTER_INC(&pRh->aTypes[pUrb->enmType].StatUrbsFailed);
337 }
338 }
339#endif /* VBOX_WITH_STATISTICS */
340
341 /*
342 * Msg transfers are special virtual transfers associated with
343 * vusb, not the roothub
344 */
345 switch (pUrb->enmType)
346 {
347 case VUSBXFERTYPE_MSG:
348 vusbMsgCompletion(pUrb);
349 return;
350 case VUSBXFERTYPE_ISOC:
351 /* Don't bother with error callback for isochronous URBs. */
352 break;
353
354#if 1 /** @todo r=bird: OHCI say ''If the Transfer Descriptor is being
355 * retired because of an error, the Host Controller must update
356 * the Halt bit of the Endpoint Descriptor.''
357 *
358 * So, I'll subject all transfertypes to the same halt stuff now. It could
359 * just happen to fix the logitech disconnect trap in win2k.
360 */
361 default:
362#endif
363 case VUSBXFERTYPE_BULK:
364 if (pUrb->enmStatus != VUSBSTATUS_OK)
365 vusbUrbErrorRh(pUrb);
366 break;
367 }
368#ifdef LOG_ENABLED
369 vusbUrbTrace(pUrb, "vusbUrbCompletionRh", true);
370#endif
371
372 pRh->pIRhPort->pfnXferCompletion(pRh->pIRhPort, pUrb);
373 if (pUrb->enmState == VUSBURBSTATE_REAPED)
374 {
375 LogFlow(("%s: vusbUrbCompletionRh: Freeing URB\n", pUrb->pszDesc));
376 pUrb->pVUsb->pfnFree(pUrb);
377 }
378
379 vusbRhR3ProcessFrame(pRh, true /* fCallback */);
380}
381
382
383/**
384 * Certain control requests must not ever be forwarded to the device because
385 * they are required by the vusb core in order to maintain the vusb internal
386 * data structures.
387 */
388DECLINLINE(bool) vusbUrbIsRequestSafe(PCVUSBSETUP pSetup, PVUSBURB pUrb)
389{
390 if ((pSetup->bmRequestType & VUSB_REQ_MASK) != VUSB_REQ_STANDARD)
391 return true;
392
393 switch (pSetup->bRequest)
394 {
395 case VUSB_REQ_CLEAR_FEATURE:
396 return pUrb->EndPt != 0 /* not default control pipe */
397 || pSetup->wValue != 0 /* not ENDPOINT_HALT */
398 || !pUrb->pVUsb->pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint; /* not special need for backend */
399 case VUSB_REQ_SET_ADDRESS:
400 case VUSB_REQ_SET_CONFIGURATION:
401 case VUSB_REQ_GET_CONFIGURATION:
402 case VUSB_REQ_SET_INTERFACE:
403 case VUSB_REQ_GET_INTERFACE:
404 return false;
405
406 /*
407 * If the device wishes it, we'll use the cached device and
408 * configuration descriptors. (We return false when we want to use the
409 * cache. Yeah, it's a bit weird to read.)
410 */
411 case VUSB_REQ_GET_DESCRIPTOR:
412 return !vusbDevIsDescriptorInCache(pUrb->pVUsb->pDev, pSetup);
413
414 default:
415 return true;
416 }
417}
418
419
420/**
421 * Queues an URB for asynchronous transfer.
422 * A list of asynchronous URBs is kept by the roothub.
423 *
424 * @returns VBox status code (from pfnUrbQueue).
425 * @param pUrb The URB.
426 */
427int vusbUrbQueueAsyncRh(PVUSBURB pUrb)
428{
429#ifdef LOG_ENABLED
430 vusbUrbTrace(pUrb, "vusbUrbQueueAsyncRh", false);
431#endif
432
433 /* Immediately return in case of error.
434 * XXX There is still a race: The Rh might vanish after this point! */
435 PVUSBDEV pDev = pUrb->pVUsb->pDev;
436 PVUSBROOTHUB pRh = vusbDevGetRh(pDev);
437 if (!pRh)
438 {
439 Log(("vusbUrbQueueAsyncRh returning VERR_OBJECT_DESTROYED\n"));
440 return VERR_OBJECT_DESTROYED;
441 }
442
443 RTCritSectEnter(&pDev->CritSectAsyncUrbs);
444 int rc = pDev->pUsbIns->pReg->pfnUrbQueue(pDev->pUsbIns, pUrb);
445 if (RT_FAILURE(rc))
446 {
447 LogFlow(("%s: vusbUrbQueueAsyncRh: returns %Rrc (queue_urb)\n", pUrb->pszDesc, rc));
448 RTCritSectLeave(&pDev->CritSectAsyncUrbs);
449 return rc;
450 }
451
452 ASMAtomicIncU32(&pDev->aPipes[pUrb->EndPt].async);
453
454 /* Queue the Urb on the roothub */
455 RTListAppend(&pDev->LstAsyncUrbs, &pUrb->pVUsb->NdLst);
456 RTCritSectLeave(&pDev->CritSectAsyncUrbs);
457
458 return VINF_SUCCESS;
459}
460
461
462/**
463 * Send a control message *synchronously*.
464 * @return
465 */
466static void vusbMsgSubmitSynchronously(PVUSBURB pUrb, bool fSafeRequest)
467{
468 PVUSBDEV pDev = pUrb->pVUsb->pDev;
469 Assert(pDev);
470 PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
471 PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
472 PVUSBSETUP pSetup = pExtra->pMsg;
473 LogFlow(("%s: vusbMsgSubmitSynchronously: pDev=%p[%s]\n", pUrb->pszDesc, pDev, pDev->pUsbIns ? pDev->pUsbIns->pszName : ""));
474
475 uint8_t *pbData = (uint8_t *)pExtra->pMsg + sizeof(*pSetup);
476 uint32_t cbData = pSetup->wLength;
477 bool fOk = false;
478 if (!fSafeRequest)
479 fOk = vusbDevStandardRequest(pDev, pUrb->EndPt, pSetup, pbData, &cbData);
480 else
481 AssertMsgFailed(("oops\n"));
482
483 pUrb->enmState = VUSBURBSTATE_REAPED;
484 if (fOk)
485 {
486 pSetup->wLength = cbData;
487 pUrb->enmStatus = VUSBSTATUS_OK;
488 pExtra->fOk = true;
489 }
490 else
491 {
492 pUrb->enmStatus = VUSBSTATUS_STALL;
493 pExtra->fOk = false;
494 }
495 pExtra->cbLeft = cbData; /* used by IN only */
496
497 vusbCtrlCompletion(pUrb);
498 vusbUrbCompletionRh(pUrb);
499
500 /*
501 * 'Free' the message URB, i.e. put it back to the allocated state.
502 */
503 pExtra->Urb.enmState = VUSBURBSTATE_ALLOCATED;
504 pExtra->Urb.fCompleting = false;
505}
506
507/**
508 * Callback for dealing with device reset.
509 */
510void vusbMsgResetExtraData(PVUSBCTRLEXTRA pExtra)
511{
512 if (!pExtra)
513 return;
514 pExtra->enmStage = CTLSTAGE_SETUP;
515 if (pExtra->Urb.enmState != VUSBURBSTATE_CANCELLED)
516 {
517 pExtra->Urb.enmState = VUSBURBSTATE_ALLOCATED;
518 pExtra->Urb.fCompleting = false;
519 }
520}
521
522
523/**
524 * Callback to free a cancelled message URB.
525 *
526 * This is yet another place we're we have to performance acrobatics to
527 * deal with cancelled URBs. sigh.
528 *
529 * The deal here is that we never free message URBs since they are integrated
530 * into the message pipe state. But since cancel can leave URBs unreaped and in
531 * a state which require them not to be freed, we'll have to do two things.
532 * First, if a new message URB is processed we'll have to get a new message
533 * pipe state. Second, we cannot just free the damn state structure because
534 * that might lead to heap corruption since it might still be in-flight.
535 *
536 * The URB embedded into the message pipe control structure will start in an
537 * ALLOCATED state. When submitted it will be go to the IN-FLIGHT state. When
538 * reaped it will go from REAPED to ALLOCATED. When completed in the CANCELLED
539 * state it will remain in that state (as does normal URBs).
540 *
541 * If a new message urb comes up while it's in the CANCELLED state, we will
542 * orphan it and it will be freed here in vusbMsgFreeUrb. We indicate this
543 * by setting pVUsb->pvFreeCtx to NULL.
544 *
545 * If we have to free the message state structure because of device destruction,
546 * configuration changes, or similar, we will orphan the message pipe state in
547 * the same way by setting pVUsb->pvFreeCtx to NULL and let this function free it.
548 *
549 * @param pUrb
550 */
551static DECLCALLBACK(void) vusbMsgFreeUrb(PVUSBURB pUrb)
552{
553 vusbUrbAssert(pUrb);
554 PVUSBCTRLEXTRA pExtra = (PVUSBCTRLEXTRA)((uint8_t *)pUrb - RT_UOFFSETOF(VUSBCTRLEXTRA, Urb));
555 if ( pUrb->enmState == VUSBURBSTATE_CANCELLED
556 && !pUrb->pVUsb->pvFreeCtx)
557 {
558 LogFlow(("vusbMsgFreeUrb: Freeing orphan: %p (pUrb=%p)\n", pExtra, pUrb));
559 RTMemFree(pExtra);
560 }
561 else
562 {
563 Assert(pUrb->pVUsb->pvFreeCtx == &pExtra->Urb);
564 pUrb->enmState = VUSBURBSTATE_ALLOCATED;
565 pUrb->fCompleting = false;
566 }
567}
568
569/**
570 * Frees the extra state data associated with a message pipe.
571 *
572 * @param pExtra The data.
573 */
574void vusbMsgFreeExtraData(PVUSBCTRLEXTRA pExtra)
575{
576 if (!pExtra)
577 return;
578 if (pExtra->Urb.enmState != VUSBURBSTATE_CANCELLED)
579 {
580 pExtra->Urb.u32Magic = 0;
581 pExtra->Urb.enmState = VUSBURBSTATE_FREE;
582 if (pExtra->Urb.pszDesc)
583 RTStrFree(pExtra->Urb.pszDesc);
584 RTMemFree(pExtra);
585 }
586 else
587 pExtra->Urb.pVUsb->pvFreeCtx = NULL; /* see vusbMsgFreeUrb */
588}
589
590/**
591 * Allocates the extra state data required for a control pipe.
592 *
593 * @returns Pointer to the allocated and initialized state data.
594 * @returns NULL on out of memory condition.
595 * @param pUrb A URB we can copy default data from.
596 */
597static PVUSBCTRLEXTRA vusbMsgAllocExtraData(PVUSBURB pUrb)
598{
599/** @todo reuse these? */
600 PVUSBCTRLEXTRA pExtra;
601 /* The initial allocation tries to balance wasted memory versus the need to re-allocate
602 * the message data. Experience shows that an 8K initial allocation in practice never needs
603 * to be expanded but almost certainly wastes 4K or more memory.
604 */
605 const size_t cbMax = _2K + sizeof(VUSBSETUP);
606 pExtra = (PVUSBCTRLEXTRA)RTMemAllocZ(RT_UOFFSETOF_DYN(VUSBCTRLEXTRA, Urb.abData[cbMax]));
607 if (pExtra)
608 {
609 pExtra->enmStage = CTLSTAGE_SETUP;
610 //pExtra->fOk = false;
611 pExtra->pMsg = (PVUSBSETUP)pExtra->Urb.abData;
612 pExtra->pbCur = (uint8_t *)(pExtra->pMsg + 1);
613 //pExtra->cbLeft = 0;
614 pExtra->cbMax = cbMax;
615
616 //pExtra->Urb.Dev.pvProxyUrb = NULL;
617 pExtra->Urb.u32Magic = VUSBURB_MAGIC;
618 pExtra->Urb.enmState = VUSBURBSTATE_ALLOCATED;
619 pExtra->Urb.fCompleting = false;
620#ifdef LOG_ENABLED
621 RTStrAPrintf(&pExtra->Urb.pszDesc, "URB %p msg->%p", &pExtra->Urb, pUrb);
622#endif
623 pExtra->Urb.pVUsb = &pExtra->VUsbExtra;
624 //pExtra->Urb.pVUsb->pCtrlUrb = NULL;
625 //pExtra->Urb.pVUsb->pNext = NULL;
626 //pExtra->Urb.pVUsb->ppPrev = NULL;
627 pExtra->Urb.pVUsb->pUrb = &pExtra->Urb;
628 pExtra->Urb.pVUsb->pDev = pUrb->pVUsb->pDev;
629 pExtra->Urb.pVUsb->pfnFree = vusbMsgFreeUrb;
630 pExtra->Urb.pVUsb->pvFreeCtx = &pExtra->Urb;
631 //pExtra->Urb.Hci = {0};
632 //pExtra->Urb.Dev.pvProxyUrb = NULL;
633 pExtra->Urb.DstAddress = pUrb->DstAddress;
634 pExtra->Urb.EndPt = pUrb->EndPt;
635 pExtra->Urb.enmType = VUSBXFERTYPE_MSG;
636 pExtra->Urb.enmDir = VUSBDIRECTION_INVALID;
637 //pExtra->Urb.fShortNotOk = false;
638 pExtra->Urb.enmStatus = VUSBSTATUS_INVALID;
639 //pExtra->Urb.cbData = 0;
640 vusbUrbAssert(&pExtra->Urb);
641 }
642 return pExtra;
643}
644
645/**
646 * Sets up the message.
647 *
648 * The message is associated with the pipe, in what's currently called
649 * control pipe extra state data (pointed to by pPipe->pCtrl). If this
650 * is a OUT message, we will no go on collecting data URB. If it's a
651 * IN message, we'll send it and then queue any incoming data for the
652 * URBs collecting it.
653 *
654 * @returns Success indicator.
655 */
656static bool vusbMsgSetup(PVUSBPIPE pPipe, const void *pvBuf, uint32_t cbBuf)
657{
658 PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
659 const VUSBSETUP *pSetupIn = (PVUSBSETUP)pvBuf;
660
661 /*
662 * Validate length.
663 */
664 if (cbBuf < sizeof(VUSBSETUP))
665 {
666 LogFlow(("vusbMsgSetup: pPipe=%p cbBuf=%u < %u (failure) !!!\n",
667 pPipe, cbBuf, sizeof(VUSBSETUP)));
668 return false;
669 }
670
671 /*
672 * Check if we've got an cancelled message URB. Allocate a new one in that case.
673 */
674 if (pExtra->Urb.enmState == VUSBURBSTATE_CANCELLED)
675 {
676 void *pvNew = RTMemDup(pExtra, RT_UOFFSETOF_DYN(VUSBCTRLEXTRA, Urb.abData[pExtra->cbMax]));
677 if (!pvNew)
678 {
679 Log(("vusbMsgSetup: out of memory!!! cbReq=%zu\n", RT_UOFFSETOF_DYN(VUSBCTRLEXTRA, Urb.abData[pExtra->cbMax])));
680 return false;
681 }
682 pExtra->Urb.pVUsb->pvFreeCtx = NULL;
683 LogFlow(("vusbMsgSetup: Replacing canceled pExtra=%p with %p.\n", pExtra, pvNew));
684 pPipe->pCtrl = pExtra = (PVUSBCTRLEXTRA)pvNew;
685 pExtra->Urb.pVUsb = &pExtra->VUsbExtra;
686 pExtra->Urb.pVUsb->pUrb = &pExtra->Urb;
687 pExtra->pMsg = (PVUSBSETUP)pExtra->Urb.abData;
688 pExtra->Urb.enmState = VUSBURBSTATE_ALLOCATED;
689 pExtra->Urb.fCompleting = false;
690 }
691
692 /*
693 * Check that we've got sufficient space in the message URB.
694 */
695 if (pExtra->cbMax < cbBuf + pSetupIn->wLength)
696 {
697 uint32_t cbReq = RT_ALIGN_32(cbBuf + pSetupIn->wLength, 64);
698 PVUSBCTRLEXTRA pNew = (PVUSBCTRLEXTRA)RTMemRealloc(pExtra, RT_UOFFSETOF_DYN(VUSBCTRLEXTRA, Urb.abData[cbReq]));
699 if (!pNew)
700 {
701 Log(("vusbMsgSetup: out of memory!!! cbReq=%u %zu\n",
702 cbReq, RT_UOFFSETOF_DYN(VUSBCTRLEXTRA, Urb.abData[cbReq])));
703 return false;
704 }
705 if (pExtra != pNew)
706 {
707 LogFunc(("Reallocated %u -> %u\n", pExtra->cbMax, cbReq));
708 pNew->pMsg = (PVUSBSETUP)pNew->Urb.abData;
709 pExtra = pNew;
710 pPipe->pCtrl = pExtra;
711 pExtra->Urb.pVUsb = &pExtra->VUsbExtra;
712 pExtra->Urb.pVUsb->pUrb = &pExtra->Urb;
713 pExtra->Urb.pVUsb->pvFreeCtx = &pExtra->Urb;
714 }
715
716 pExtra->cbMax = cbReq;
717 }
718 Assert(pExtra->Urb.enmState == VUSBURBSTATE_ALLOCATED);
719
720 /*
721 * Copy the setup data and prepare for data.
722 */
723 PVUSBSETUP pSetup = pExtra->pMsg;
724 pExtra->fSubmitted = false;
725 pExtra->Urb.enmState = VUSBURBSTATE_IN_FLIGHT;
726 pExtra->pbCur = (uint8_t *)(pSetup + 1);
727 pSetup->bmRequestType = pSetupIn->bmRequestType;
728 pSetup->bRequest = pSetupIn->bRequest;
729 pSetup->wValue = RT_LE2H_U16(pSetupIn->wValue);
730 pSetup->wIndex = RT_LE2H_U16(pSetupIn->wIndex);
731 pSetup->wLength = RT_LE2H_U16(pSetupIn->wLength);
732
733 LogFlow(("vusbMsgSetup(%p,,%d): bmRequestType=%#04x bRequest=%#04x wValue=%#06x wIndex=%#06x wLength=0x%.4x\n",
734 pPipe, cbBuf, pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
735 return true;
736}
737
738/**
739 * Build the message URB from the given control URB and accompanying message
740 * pipe state which we grab from the device for the URB.
741 *
742 * @param pUrb The URB to submit.
743 * @param pSetup The setup packet for the message transfer.
744 * @param pExtra Pointer to the additional state requred for a control transfer.
745 * @param pPipe The message pipe state.
746 */
747static void vusbMsgDoTransfer(PVUSBURB pUrb, PVUSBSETUP pSetup, PVUSBCTRLEXTRA pExtra, PVUSBPIPE pPipe)
748{
749 RT_NOREF(pPipe);
750
751 /*
752 * Mark this transfer as sent (cleared at setup time).
753 */
754 Assert(!pExtra->fSubmitted);
755 pExtra->fSubmitted = true;
756
757 /*
758 * Do we have to do this synchronously?
759 */
760 bool fSafeRequest = vusbUrbIsRequestSafe(pSetup, pUrb);
761 if (!fSafeRequest)
762 {
763 vusbMsgSubmitSynchronously(pUrb, fSafeRequest);
764 return;
765 }
766
767 /*
768 * Do it asynchronously.
769 */
770 LogFlow(("%s: vusbMsgDoTransfer: ep=%d pMsgUrb=%p pPipe=%p stage=%s\n",
771 pUrb->pszDesc, pUrb->EndPt, &pExtra->Urb, pPipe, g_apszCtlStates[pExtra->enmStage]));
772 Assert(pExtra->Urb.enmType == VUSBXFERTYPE_MSG);
773 Assert(pExtra->Urb.EndPt == pUrb->EndPt);
774 pExtra->Urb.enmDir = (pSetup->bmRequestType & VUSB_DIR_TO_HOST) ? VUSBDIRECTION_IN : VUSBDIRECTION_OUT;
775 pExtra->Urb.cbData = pSetup->wLength + sizeof(*pSetup);
776 pExtra->Urb.pVUsb->pCtrlUrb = pUrb;
777 int rc = vusbUrbQueueAsyncRh(&pExtra->Urb);
778 if (RT_FAILURE(rc))
779 {
780 /*
781 * If we fail submitting it, will not retry but fail immediately.
782 *
783 * This keeps things simple. The host OS will have retried if
784 * it's a proxied device, and if it's a virtual one it really means
785 * it if it's failing a control message.
786 */
787 LogFlow(("%s: vusbMsgDoTransfer: failed submitting urb! failing it with %s (rc=%Rrc)!!!\n",
788 pUrb->pszDesc, rc == VERR_VUSB_DEVICE_NOT_ATTACHED ? "DNR" : "CRC", rc));
789 pExtra->Urb.enmStatus = rc == VERR_VUSB_DEVICE_NOT_ATTACHED ? VUSBSTATUS_DNR : VUSBSTATUS_CRC;
790 pExtra->Urb.enmState = VUSBURBSTATE_REAPED;
791 vusbMsgCompletion(&pExtra->Urb);
792 }
793}
794
795/**
796 * Fails a URB request with a pipe STALL error.
797 *
798 * @returns VINF_SUCCESS indicating that we've completed the URB.
799 * @param pUrb The URB in question.
800 */
801static int vusbMsgStall(PVUSBURB pUrb)
802{
803 PVUSBPIPE pPipe = &pUrb->pVUsb->pDev->aPipes[pUrb->EndPt];
804 PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
805 LogFlow(("%s: vusbMsgStall: pPipe=%p err=STALL stage %s->SETUP\n",
806 pUrb->pszDesc, pPipe, g_apszCtlStates[pExtra->enmStage]));
807
808 pExtra->pbCur = NULL;
809 pExtra->enmStage = CTLSTAGE_SETUP;
810 pUrb->enmState = VUSBURBSTATE_REAPED;
811 pUrb->enmStatus = VUSBSTATUS_STALL;
812 vusbUrbCompletionRh(pUrb);
813 return VINF_SUCCESS;
814}
815
816/**
817 * Submit a control message.
818 *
819 * Here we implement the USB defined traffic that occurs in message pipes
820 * (aka control endpoints). We want to provide a single function for device
821 * drivers so that they don't all have to reimplement the usb logic for
822 * themselves. This means we need to keep a little bit of state information
823 * because control transfers occur over multiple bus transactions. We may
824 * also need to buffer data over multiple data stages.
825 *
826 * @returns VBox status code.
827 * @param pUrb The URB to submit.
828 */
829static int vusbUrbSubmitCtrl(PVUSBURB pUrb)
830{
831#ifdef LOG_ENABLED
832 vusbUrbTrace(pUrb, "vusbUrbSubmitCtrl", false);
833#endif
834 PVUSBDEV pDev = pUrb->pVUsb->pDev;
835 PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
836
837 RTCritSectEnter(&pPipe->CritSectCtrl);
838 PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
839
840 if (!pExtra && !(pExtra = pPipe->pCtrl = vusbMsgAllocExtraData(pUrb)))
841 {
842 RTCritSectLeave(&pPipe->CritSectCtrl);
843 return VERR_VUSB_NO_URB_MEMORY;
844 }
845 PVUSBSETUP pSetup = pExtra->pMsg;
846
847 if (pPipe->async)
848 {
849 AssertMsgFailed(("%u\n", pPipe->async));
850 RTCritSectLeave(&pPipe->CritSectCtrl);
851 return VERR_GENERAL_FAILURE;
852 }
853
854 /*
855 * A setup packet always resets the transaction and the
856 * end of data transmission is signified by change in
857 * data direction.
858 */
859 if (pUrb->enmDir == VUSBDIRECTION_SETUP)
860 {
861 LogFlow(("%s: vusbUrbSubmitCtrl: pPipe=%p state %s->SETUP\n",
862 pUrb->pszDesc, pPipe, g_apszCtlStates[pExtra->enmStage]));
863 pExtra->enmStage = CTLSTAGE_SETUP;
864 }
865 else if ( pExtra->enmStage == CTLSTAGE_DATA
866 /* (the STATUS stage direction goes the other way) */
867 && !!(pSetup->bmRequestType & VUSB_DIR_TO_HOST) != (pUrb->enmDir == VUSBDIRECTION_IN))
868 {
869 LogFlow(("%s: vusbUrbSubmitCtrl: pPipe=%p state %s->STATUS\n",
870 pUrb->pszDesc, pPipe, g_apszCtlStates[pExtra->enmStage]));
871 pExtra->enmStage = CTLSTAGE_STATUS;
872 }
873
874 /*
875 * Act according to the current message stage.
876 */
877 switch (pExtra->enmStage)
878 {
879 case CTLSTAGE_SETUP:
880 /*
881 * When stall handshake is returned, all subsequent packets
882 * must generate stall until a setup packet arrives.
883 */
884 if (pUrb->enmDir != VUSBDIRECTION_SETUP)
885 {
886 Log(("%s: vusbUrbSubmitCtrl: Stall at setup stage (dir=%#x)!!\n", pUrb->pszDesc, pUrb->enmDir));
887 vusbMsgStall(pUrb);
888 break;
889 }
890
891 /* Store setup details, return DNR if corrupt */
892 if (!vusbMsgSetup(pPipe, pUrb->abData, pUrb->cbData))
893 {
894 pUrb->enmState = VUSBURBSTATE_REAPED;
895 pUrb->enmStatus = VUSBSTATUS_DNR;
896 vusbUrbCompletionRh(pUrb);
897 break;
898 }
899 if (pPipe->pCtrl != pExtra)
900 {
901 pExtra = pPipe->pCtrl;
902 pSetup = pExtra->pMsg;
903 }
904
905 /* pre-buffer our output if it's device-to-host */
906 if (pSetup->bmRequestType & VUSB_DIR_TO_HOST)
907 vusbMsgDoTransfer(pUrb, pSetup, pExtra, pPipe);
908 else if (pSetup->wLength)
909 {
910 LogFlow(("%s: vusbUrbSubmitCtrl: stage=SETUP - to dev: need data\n", pUrb->pszDesc));
911 pUrb->enmState = VUSBURBSTATE_REAPED;
912 vusbMsgSetupCompletion(pUrb);
913 vusbUrbCompletionRh(pUrb);
914 }
915 /*
916 * If there is no DATA stage, we must send it now since there are
917 * no requirement of a STATUS stage.
918 */
919 else
920 {
921 LogFlow(("%s: vusbUrbSubmitCtrl: stage=SETUP - to dev: sending\n", pUrb->pszDesc));
922 vusbMsgDoTransfer(pUrb, pSetup, pExtra, pPipe);
923 }
924 break;
925
926 case CTLSTAGE_DATA:
927 {
928 /*
929 * If a data stage exceeds the target buffer indicated in
930 * setup return stall, if data stage returns stall there
931 * will be no status stage.
932 */
933 uint8_t *pbData = (uint8_t *)(pExtra->pMsg + 1);
934 if ((uintptr_t)&pExtra->pbCur[pUrb->cbData] > (uintptr_t)&pbData[pSetup->wLength])
935 {
936 /* In the device -> host direction, the device never returns more data than
937 what was requested (wLength). So, we can just cap cbData. */
938 ssize_t const cbLeft = &pbData[pSetup->wLength] - pExtra->pbCur;
939 if (pSetup->bmRequestType & VUSB_DIR_TO_HOST)
940 {
941 LogFlow(("%s: vusbUrbSubmitCtrl: Adjusting DATA request: %d -> %d\n", pUrb->pszDesc, pUrb->cbData, cbLeft));
942 pUrb->cbData = cbLeft >= 0 ? (uint32_t)cbLeft : 0;
943 }
944 /* In the host -> direction it's undefined what happens if the host provides
945 more data than what wLength inidicated. However, in 2007, iPhone detection
946 via iTunes would issue wLength=0 but provide a data URB which we needed to
947 pass on to the device anyway, so we'll just quietly adjust wLength if it's
948 zero and get on with the work.
949
950 What confuses me (bird) here, though, is that we've already sent the SETUP
951 URB to the device when we received it, and all we end up doing is an
952 unnecessary memcpy and completing the URB, but never actually sending the
953 data to the device. So, I guess this stuff is still a little iffy.
954
955 Note! We currently won't be doing any resizing, as we've disabled resizing
956 in general.
957 P.S. We used to have a very strange (pUrb->cbData % pSetup->wLength) == 0
958 thing too that joined the pUrb->cbData adjusting above. */
959 else if ( pSetup->wLength == 0
960 && pUrb->cbData <= pExtra->cbMax)
961 {
962 Log(("%s: vusbUrbSubmitCtrl: pAdjusting wLength: %u -> %u (iPhone hack)\n",
963 pUrb->pszDesc, pSetup->wLength, pUrb->cbData));
964 pSetup->wLength = pUrb->cbData;
965 Assert(cbLeft >= (ssize_t)pUrb->cbData);
966 }
967 else
968 {
969 Log(("%s: vusbUrbSubmitCtrl: Stall at data stage!! wLength=%u cbData=%d cbMax=%d cbLeft=%dz\n",
970 pUrb->pszDesc, pSetup->wLength, pUrb->cbData, pExtra->cbMax, cbLeft));
971 vusbMsgStall(pUrb);
972 break;
973 }
974 }
975
976 if (pUrb->enmDir == VUSBDIRECTION_IN)
977 {
978 /* put data received from the device. */
979 const uint32_t cbRead = RT_MIN(pUrb->cbData, pExtra->cbLeft);
980 memcpy(pUrb->abData, pExtra->pbCur, cbRead);
981
982 /* advance */
983 pExtra->pbCur += cbRead;
984 if (pUrb->cbData == cbRead)
985 pExtra->cbLeft -= pUrb->cbData;
986 else
987 {
988 /* adjust the pUrb->cbData to reflect the number of bytes containing actual data. */
989 LogFlow(("%s: vusbUrbSubmitCtrl: adjusting last DATA pUrb->cbData, %d -> %d\n",
990 pUrb->pszDesc, pUrb->cbData, pExtra->cbLeft));
991 pUrb->cbData = cbRead;
992 pExtra->cbLeft = 0;
993 }
994 }
995 else
996 {
997 /* get data for sending when completed. */
998 AssertStmt((ssize_t)pUrb->cbData <= pExtra->cbMax - (pExtra->pbCur - pbData), /* paranoia: checked above */
999 pUrb->cbData = pExtra->cbMax - (uint32_t)RT_MIN(pExtra->pbCur - pbData, pExtra->cbMax));
1000 memcpy(pExtra->pbCur, pUrb->abData, pUrb->cbData);
1001
1002 /* advance */
1003 pExtra->pbCur += pUrb->cbData;
1004
1005 /*
1006 * If we've got the necessary data, we'll send it now since there are
1007 * no requirement of a STATUS stage.
1008 */
1009 if ( !pExtra->fSubmitted
1010 && pExtra->pbCur - pbData >= pSetup->wLength)
1011 {
1012 LogFlow(("%s: vusbUrbSubmitCtrl: stage=DATA - to dev: sending\n", pUrb->pszDesc));
1013 vusbMsgDoTransfer(pUrb, pSetup, pExtra, pPipe);
1014 break;
1015 }
1016 }
1017
1018 pUrb->enmState = VUSBURBSTATE_REAPED;
1019 vusbMsgDataCompletion(pUrb);
1020 vusbUrbCompletionRh(pUrb);
1021 break;
1022 }
1023
1024 case CTLSTAGE_STATUS:
1025 if ( (pSetup->bmRequestType & VUSB_DIR_TO_HOST)
1026 || pExtra->fSubmitted)
1027 {
1028 Assert(pExtra->fSubmitted);
1029 pUrb->enmState = VUSBURBSTATE_REAPED;
1030 vusbMsgStatusCompletion(pUrb);
1031 vusbUrbCompletionRh(pUrb);
1032 }
1033 else
1034 {
1035 LogFlow(("%s: vusbUrbSubmitCtrl: stage=STATUS - to dev: sending\n", pUrb->pszDesc));
1036 vusbMsgDoTransfer(pUrb, pSetup, pExtra, pPipe);
1037 }
1038 break;
1039 }
1040
1041 RTCritSectLeave(&pPipe->CritSectCtrl);
1042 return VINF_SUCCESS;
1043}
1044
1045
1046/**
1047 * Submit a interrupt URB.
1048 *
1049 * @returns VBox status code.
1050 * @param pUrb The URB to submit.
1051 */
1052static int vusbUrbSubmitInterrupt(PVUSBURB pUrb)
1053{
1054 LogFlow(("%s: vusbUrbSubmitInterrupt: (sync)\n", pUrb->pszDesc));
1055 return vusbUrbQueueAsyncRh(pUrb);
1056}
1057
1058
1059/**
1060 * Submit a bulk URB.
1061 *
1062 * @returns VBox status code.
1063 * @param pUrb The URB to submit.
1064 */
1065static int vusbUrbSubmitBulk(PVUSBURB pUrb)
1066{
1067 LogFlow(("%s: vusbUrbSubmitBulk: (async)\n", pUrb->pszDesc));
1068 return vusbUrbQueueAsyncRh(pUrb);
1069}
1070
1071
1072/**
1073 * Submit an isochronous URB.
1074 *
1075 * @returns VBox status code.
1076 * @param pUrb The URB to submit.
1077 */
1078static int vusbUrbSubmitIsochronous(PVUSBURB pUrb)
1079{
1080 LogFlow(("%s: vusbUrbSubmitIsochronous: (async)\n", pUrb->pszDesc));
1081 return vusbUrbQueueAsyncRh(pUrb);
1082}
1083
1084
1085/**
1086 * Fail a URB with a 'hard-error' sort of error.
1087 *
1088 * @return VINF_SUCCESS (the Urb status indicates the error).
1089 * @param pUrb The URB.
1090 */
1091int vusbUrbSubmitHardError(PVUSBURB pUrb)
1092{
1093 /* FIXME: Find out the correct return code from the spec */
1094 pUrb->enmState = VUSBURBSTATE_REAPED;
1095 pUrb->enmStatus = VUSBSTATUS_DNR;
1096 vusbUrbCompletionRh(pUrb);
1097 return VINF_SUCCESS;
1098}
1099
1100
1101/**
1102 * Submit a URB.
1103 */
1104int vusbUrbSubmit(PVUSBURB pUrb)
1105{
1106 vusbUrbAssert(pUrb);
1107 Assert(pUrb->enmState == VUSBURBSTATE_ALLOCATED);
1108 PVUSBDEV pDev = pUrb->pVUsb->pDev;
1109 PVUSBPIPE pPipe = NULL;
1110 Assert(pDev);
1111
1112 /*
1113 * Check that the device is in a valid state.
1114 */
1115 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
1116 if (enmState == VUSB_DEVICE_STATE_RESET)
1117 {
1118 LogRel(("VUSB: %s: power off ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
1119 pUrb->enmStatus = VUSBSTATUS_DNR;
1120 /* This will postpone the TDs until we're done with the resetting. */
1121 return VERR_VUSB_DEVICE_IS_RESETTING;
1122 }
1123
1124#ifdef LOG_ENABLED
1125 /* stamp it */
1126 pUrb->pVUsb->u64SubmitTS = RTTimeNanoTS();
1127#endif
1128
1129 /** @todo Check max packet size here too? */
1130
1131 /*
1132 * Validate the pipe.
1133 */
1134 if (pUrb->EndPt >= VUSB_PIPE_MAX)
1135 {
1136 Log(("%s: pDev=%p[%s]: SUBMIT: ep %i >= %i!!!\n", pUrb->pszDesc, pDev, pDev->pUsbIns->pszName, pUrb->EndPt, VUSB_PIPE_MAX));
1137 return vusbUrbSubmitHardError(pUrb);
1138 }
1139 PCVUSBDESCENDPOINTEX pEndPtDesc;
1140 switch (pUrb->enmDir)
1141 {
1142 case VUSBDIRECTION_IN:
1143 pEndPtDesc = pDev->aPipes[pUrb->EndPt].in;
1144 pPipe = &pDev->aPipes[pUrb->EndPt];
1145 break;
1146 case VUSBDIRECTION_SETUP:
1147 case VUSBDIRECTION_OUT:
1148 default:
1149 pEndPtDesc = pDev->aPipes[pUrb->EndPt].out;
1150 pPipe = &pDev->aPipes[pUrb->EndPt];
1151 break;
1152 }
1153 if (!pEndPtDesc)
1154 {
1155 Log(("%s: pDev=%p[%s]: SUBMIT: no endpoint!!! dir=%s e=%i\n",
1156 pUrb->pszDesc, pDev, pDev->pUsbIns->pszName, vusbUrbDirName(pUrb->enmDir), pUrb->EndPt));
1157 return vusbUrbSubmitHardError(pUrb);
1158 }
1159
1160 /*
1161 * Check for correct transfer types.
1162 * Our type codes are the same - what a coincidence.
1163 */
1164 if ((pEndPtDesc->Core.bmAttributes & 0x3) != pUrb->enmType)
1165 {
1166 /* Bulk and interrupt transfers are identical on the bus level (the only difference
1167 * is in how they are scheduled by the HCD/HC) and need an exemption.
1168 * Atheros AR9271 is a known offender; its configuration descriptors include
1169 * interrupt endpoints, but drivers (Win7/8, Linux kernel pre-3.05) treat them
1170 * as bulk endpoints.
1171 */
1172 if ( (pUrb->enmType == VUSBXFERTYPE_BULK && (pEndPtDesc->Core.bmAttributes & 0x3) == VUSBXFERTYPE_INTR)
1173 || (pUrb->enmType == VUSBXFERTYPE_INTR && (pEndPtDesc->Core.bmAttributes & 0x3) == VUSBXFERTYPE_BULK))
1174 {
1175 Log2(("%s: pDev=%p[%s]: SUBMIT: mixing bulk/interrupt transfers on DstAddress=%i ep=%i dir=%s\n",
1176 pUrb->pszDesc, pDev, pDev->pUsbIns->pszName,
1177 pUrb->DstAddress, pUrb->EndPt, vusbUrbDirName(pUrb->enmDir)));
1178 }
1179 else
1180 {
1181 Log(("%s: pDev=%p[%s]: SUBMIT: %s transfer requested for %#x endpoint on DstAddress=%i ep=%i dir=%s\n",
1182 pUrb->pszDesc, pDev, pDev->pUsbIns->pszName, vusbUrbTypeName(pUrb->enmType), pEndPtDesc->Core.bmAttributes,
1183 pUrb->DstAddress, pUrb->EndPt, vusbUrbDirName(pUrb->enmDir)));
1184 return vusbUrbSubmitHardError(pUrb);
1185 }
1186 }
1187
1188 /*
1189 * If there's a URB in the read-ahead buffer, use it.
1190 */
1191 int rc;
1192
1193 if (pDev->hSniffer)
1194 {
1195 rc = VUSBSnifferRecordEvent(pDev->hSniffer, pUrb, VUSBSNIFFEREVENT_SUBMIT);
1196 if (RT_FAILURE(rc))
1197 LogRel(("VUSB: Capturing URB submit event failed with %Rrc\n", rc));
1198 }
1199
1200 /*
1201 * Take action based on type.
1202 */
1203 pUrb->enmState = VUSBURBSTATE_IN_FLIGHT;
1204 switch (pUrb->enmType)
1205 {
1206 case VUSBXFERTYPE_CTRL:
1207 rc = vusbUrbSubmitCtrl(pUrb);
1208 break;
1209 case VUSBXFERTYPE_BULK:
1210 rc = vusbUrbSubmitBulk(pUrb);
1211 break;
1212 case VUSBXFERTYPE_INTR:
1213 rc = vusbUrbSubmitInterrupt(pUrb);
1214 break;
1215 case VUSBXFERTYPE_ISOC:
1216 rc = vusbUrbSubmitIsochronous(pUrb);
1217 break;
1218 default:
1219 AssertMsgFailed(("Unexpected pUrb type %d\n", pUrb->enmType));
1220 return vusbUrbSubmitHardError(pUrb);
1221 }
1222
1223 /*
1224 * The device was detached, so we fail everything.
1225 * (We should really detach and destroy the device, but we'll have to wait till Main reacts.)
1226 */
1227 if (rc == VERR_VUSB_DEVICE_NOT_ATTACHED)
1228 rc = vusbUrbSubmitHardError(pUrb);
1229 /*
1230 * We don't increment error count if async URBs are in flight, in
1231 * this case we just assume we need to throttle back, this also
1232 * makes sure we don't halt bulk endpoints at the wrong time.
1233 */
1234 else if ( RT_FAILURE(rc)
1235 && !ASMAtomicReadU32(&pDev->aPipes[pUrb->EndPt].async)
1236 /* && pUrb->enmType == VUSBXFERTYPE_BULK ?? */
1237 && !vusbUrbErrorRh(pUrb))
1238 {
1239 /* don't retry it anymore. */
1240 pUrb->enmState = VUSBURBSTATE_REAPED;
1241 pUrb->enmStatus = VUSBSTATUS_CRC;
1242 vusbUrbCompletionRh(pUrb);
1243 return VINF_SUCCESS;
1244 }
1245
1246 return rc;
1247}
1248
1249
1250/**
1251 * Reap in-flight URBs.
1252 *
1253 * @param pUrbLst Pointer to the head of the URB list.
1254 * @param cMillies Number of milliseconds to block in each reap operation.
1255 * Use 0 to not block at all.
1256 */
1257void vusbUrbDoReapAsync(PRTLISTANCHOR pUrbLst, RTMSINTERVAL cMillies)
1258{
1259 PVUSBURBVUSB pVUsbUrb = RTListGetFirst(pUrbLst, VUSBURBVUSBINT, NdLst);
1260 while (pVUsbUrb)
1261 {
1262 vusbUrbAssert(pVUsbUrb->pUrb);
1263 PVUSBURBVUSB pVUsbUrbNext = RTListGetNext(pUrbLst, pVUsbUrb, VUSBURBVUSBINT, NdLst);
1264 PVUSBDEV pDev = pVUsbUrb->pDev;
1265
1266 /* Don't touch resetting devices - paranoid safety precaution. */
1267 if (vusbDevGetState(pDev) != VUSB_DEVICE_STATE_RESET)
1268 {
1269 /*
1270 * Reap most URBs pending on a single device.
1271 */
1272 PVUSBURB pRipe;
1273
1274 /**
1275 * This is workaround for race(should be fixed) detach on one EMT thread and frame boundary timer on other
1276 * and leaked URBs (shouldn't be affected by leaked URBs).
1277 */
1278 Assert(pDev->pUsbIns);
1279 while ( pDev->pUsbIns
1280 && ((pRipe = pDev->pUsbIns->pReg->pfnUrbReap(pDev->pUsbIns, cMillies)) != NULL))
1281 {
1282 vusbUrbAssert(pRipe);
1283 if (pVUsbUrbNext && pRipe == pVUsbUrbNext->pUrb)
1284 pVUsbUrbNext = RTListGetNext(pUrbLst, pVUsbUrbNext, VUSBURBVUSBINT, NdLst);
1285 vusbUrbRipe(pRipe);
1286 }
1287 }
1288
1289 /* next */
1290 pVUsbUrb = pVUsbUrbNext;
1291 }
1292}
1293
1294/**
1295 * Reap URBs on a per device level.
1296 *
1297 * @returns nothing.
1298 * @param pDev The device instance to reap URBs for.
1299 * @param cMillies Number of milliseconds to block in each reap operation.
1300 * Use 0 to not block at all.
1301 */
1302void vusbUrbDoReapAsyncDev(PVUSBDEV pDev, RTMSINTERVAL cMillies)
1303{
1304 Assert(pDev->enmState != VUSB_DEVICE_STATE_RESET);
1305
1306 /*
1307 * Reap most URBs pending on a single device.
1308 */
1309 PVUSBURB pRipe;
1310
1311 /**
1312 * This is workaround for race(should be fixed) detach on one EMT thread and frame boundary timer on other
1313 * and leaked URBs (shouldn't be affected by leaked URBs).
1314 */
1315
1316 if (ASMAtomicXchgBool(&pDev->fWokenUp, false))
1317 return;
1318
1319 Assert(pDev->pUsbIns);
1320 while ( pDev->pUsbIns
1321 && ((pRipe = pDev->pUsbIns->pReg->pfnUrbReap(pDev->pUsbIns, cMillies)) != NULL))
1322 {
1323 vusbUrbAssert(pRipe);
1324 vusbUrbRipe(pRipe);
1325 if (ASMAtomicXchgBool(&pDev->fWokenUp, false))
1326 break;
1327 }
1328}
1329
1330/**
1331 * Completes the URB.
1332 */
1333static void vusbUrbCompletion(PVUSBURB pUrb)
1334{
1335 Assert(pUrb->pVUsb->pDev->aPipes);
1336 ASMAtomicDecU32(&pUrb->pVUsb->pDev->aPipes[pUrb->EndPt].async);
1337
1338 if (pUrb->enmState == VUSBURBSTATE_REAPED)
1339 vusbUrbUnlink(pUrb);
1340
1341 vusbUrbCompletionRh(pUrb);
1342}
1343
1344/**
1345 * The worker for vusbUrbCancel() which is executed on the I/O thread.
1346 *
1347 * @returns IPRT status code.
1348 * @param pUrb The URB to cancel.
1349 * @param enmMode The way the URB should be canceled.
1350 */
1351DECLHIDDEN(int) vusbUrbCancelWorker(PVUSBURB pUrb, CANCELMODE enmMode)
1352{
1353 vusbUrbAssert(pUrb);
1354#ifdef VBOX_WITH_STATISTICS
1355 PVUSBROOTHUB pRh = vusbDevGetRh(pUrb->pVUsb->pDev);
1356#endif
1357 if (pUrb->enmState == VUSBURBSTATE_IN_FLIGHT)
1358 {
1359 LogFlow(("%s: vusbUrbCancel: Canceling in-flight\n", pUrb->pszDesc));
1360 STAM_COUNTER_INC(&pRh->Total.StatUrbsCancelled);
1361 if (pUrb->enmType != VUSBXFERTYPE_MSG)
1362 {
1363 STAM_STATS({Assert(pUrb->enmType >= 0 && pUrb->enmType < (int)RT_ELEMENTS(pRh->aTypes));});
1364 STAM_COUNTER_INC(&pRh->aTypes[pUrb->enmType].StatUrbsCancelled);
1365 }
1366
1367 pUrb->enmState = VUSBURBSTATE_CANCELLED;
1368 PPDMUSBINS pUsbIns = pUrb->pVUsb->pDev->pUsbIns;
1369 pUsbIns->pReg->pfnUrbCancel(pUsbIns, pUrb);
1370 Assert(pUrb->enmState == VUSBURBSTATE_CANCELLED || pUrb->enmState == VUSBURBSTATE_REAPED);
1371
1372 pUrb->enmStatus = VUSBSTATUS_CRC;
1373 vusbUrbCompletion(pUrb);
1374 }
1375 else if (pUrb->enmState == VUSBURBSTATE_REAPED)
1376 {
1377 LogFlow(("%s: vusbUrbCancel: Canceling reaped urb\n", pUrb->pszDesc));
1378 STAM_COUNTER_INC(&pRh->Total.StatUrbsCancelled);
1379 if (pUrb->enmType != VUSBXFERTYPE_MSG)
1380 {
1381 STAM_STATS({Assert(pUrb->enmType >= 0 && pUrb->enmType < (int)RT_ELEMENTS(pRh->aTypes));});
1382 STAM_COUNTER_INC(&pRh->aTypes[pUrb->enmType].StatUrbsCancelled);
1383 }
1384
1385 pUrb->enmStatus = VUSBSTATUS_CRC;
1386 vusbUrbCompletion(pUrb);
1387 }
1388 else
1389 {
1390 AssertMsg(pUrb->enmState == VUSBURBSTATE_CANCELLED, ("Invalid state %d, pUrb=%p\n", pUrb->enmState, pUrb));
1391 switch (enmMode)
1392 {
1393 default:
1394 AssertMsgFailed(("Invalid cancel mode\n"));
1395 RT_FALL_THRU();
1396 case CANCELMODE_FAIL:
1397 pUrb->enmStatus = VUSBSTATUS_CRC;
1398 break;
1399 case CANCELMODE_UNDO:
1400 pUrb->enmStatus = VUSBSTATUS_UNDO;
1401 break;
1402
1403 }
1404 }
1405 return VINF_SUCCESS;
1406}
1407
1408/**
1409 * Cancels an URB with CRC failure.
1410 *
1411 * Cancelling an URB is a tricky thing. The USBProxy backend can not
1412 * all cancel it and we must keep the URB around until it's ripe and
1413 * can be reaped the normal way. However, we must complete the URB
1414 * now, before leaving this function. This is not nice. sigh.
1415 *
1416 * This function will cancel the URB if it's in-flight and complete
1417 * it. The device will in its pfnCancel method be given the chance to
1418 * say that the URB doesn't need reaping and should be unlinked.
1419 *
1420 * An URB which is in the cancel state after pfnCancel will remain in that
1421 * state and in the async list until its reaped. When it's finally reaped
1422 * it will be unlinked and freed without doing any completion.
1423 *
1424 * There are different modes of canceling an URB. When devices are being
1425 * disconnected etc., they will be completed with an error (CRC). However,
1426 * when the HC needs to temporarily halt communication with a device, the
1427 * URB/TD must be left alone if possible.
1428 *
1429 * @param pUrb The URB to cancel.
1430 * @param mode The way the URB should be canceled.
1431 */
1432void vusbUrbCancel(PVUSBURB pUrb, CANCELMODE mode)
1433{
1434 int rc = vusbDevIoThreadExecSync(pUrb->pVUsb->pDev, (PFNRT)vusbUrbCancelWorker, 2, pUrb, mode);
1435 AssertRC(rc);
1436}
1437
1438
1439/**
1440 * Async version of vusbUrbCancel() - doesn't wait for the cancelling to be complete.
1441 */
1442void vusbUrbCancelAsync(PVUSBURB pUrb, CANCELMODE mode)
1443{
1444 /* Don't try to cancel the URB when completion is in progress at the moment. */
1445 if (!ASMAtomicXchgBool(&pUrb->fCompleting, true))
1446 {
1447 int rc = vusbDevIoThreadExec(pUrb->pVUsb->pDev, 0 /* fFlags */, (PFNRT)vusbUrbCancelWorker, 2, pUrb, mode);
1448 AssertRC(rc);
1449 }
1450}
1451
1452
1453/**
1454 * Deals with a ripe URB (i.e. after reaping it).
1455 *
1456 * If an URB is in the reaped or in-flight state, we'll
1457 * complete it. If it's cancelled, we'll simply free it.
1458 * Any other states should never get here.
1459 *
1460 * @param pUrb The URB.
1461 */
1462void vusbUrbRipe(PVUSBURB pUrb)
1463{
1464 if ( pUrb->enmState == VUSBURBSTATE_IN_FLIGHT
1465 || pUrb->enmState == VUSBURBSTATE_REAPED)
1466 {
1467 pUrb->enmState = VUSBURBSTATE_REAPED;
1468 if (!ASMAtomicXchgBool(&pUrb->fCompleting, true))
1469 vusbUrbCompletion(pUrb);
1470 }
1471 else if (pUrb->enmState == VUSBURBSTATE_CANCELLED)
1472 {
1473 vusbUrbUnlink(pUrb);
1474 LogFlow(("%s: vusbUrbRipe: Freeing cancelled URB\n", pUrb->pszDesc));
1475 pUrb->pVUsb->pfnFree(pUrb);
1476 }
1477 else
1478 AssertMsgFailed(("Invalid URB state %d; %s\n", pUrb->enmState, pUrb->pszDesc));
1479}
1480
1481
1482/*
1483 * Local Variables:
1484 * mode: c
1485 * c-file-style: "bsd"
1486 * c-basic-offset: 4
1487 * tab-width: 4
1488 * indent-tabs-mode: s
1489 * End:
1490 */
1491
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