VirtualBox

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

Last change on this file was 103397, checked in by vboxsync, 4 months ago

Devices/VUSBUrb: Documented parfait false positive. bugref:3409

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

© 2023 Oracle
ContactPrivacy policyTerms of Use