VirtualBox

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

Last change on this file since 99196 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.3 KB
Line 
1/* $Id: VUSBUrb.cpp 98103 2023-01-17 14:15:46Z 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 * @return
475 */
476static void vusbMsgSubmitSynchronously(PVUSBURB pUrb, bool fSafeRequest)
477{
478 PVUSBDEV pDev = pUrb->pVUsb->pDev;
479 Assert(pDev);
480 PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
481 PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
482 PVUSBSETUP pSetup = pExtra->pMsg;
483 LogFlow(("%s: vusbMsgSubmitSynchronously: pDev=%p[%s]\n", pUrb->pszDesc, pDev, pDev->pUsbIns ? pDev->pUsbIns->pszName : ""));
484
485 uint8_t *pbData = (uint8_t *)pExtra->pMsg + sizeof(*pSetup);
486 uint32_t cbData = pSetup->wLength;
487 bool fOk = false;
488 if (!fSafeRequest)
489 fOk = vusbDevStandardRequest(pDev, pUrb->EndPt, pSetup, pbData, &cbData);
490 else
491 AssertMsgFailed(("oops\n"));
492
493 pUrb->enmState = VUSBURBSTATE_REAPED;
494 if (fOk)
495 {
496 pSetup->wLength = cbData;
497 pUrb->enmStatus = VUSBSTATUS_OK;
498 pExtra->fOk = true;
499 }
500 else
501 {
502 pUrb->enmStatus = VUSBSTATUS_STALL;
503 pExtra->fOk = false;
504 }
505 pExtra->cbLeft = cbData; /* used by IN only */
506
507 vusbCtrlCompletion(pUrb);
508 vusbUrbCompletionRh(pUrb);
509
510 /*
511 * 'Free' the message URB, i.e. put it back to the allocated state.
512 */
513 pExtra->Urb.enmState = VUSBURBSTATE_ALLOCATED;
514 pExtra->Urb.fCompleting = false;
515}
516
517/**
518 * Callback for dealing with device reset.
519 */
520void vusbMsgResetExtraData(PVUSBCTRLEXTRA pExtra)
521{
522 if (!pExtra)
523 return;
524 pExtra->enmStage = CTLSTAGE_SETUP;
525 if (pExtra->Urb.enmState != VUSBURBSTATE_CANCELLED)
526 {
527 pExtra->Urb.enmState = VUSBURBSTATE_ALLOCATED;
528 pExtra->Urb.fCompleting = false;
529 }
530}
531
532
533/**
534 * Callback to free a cancelled message URB.
535 *
536 * This is yet another place we're we have to performance acrobatics to
537 * deal with cancelled URBs. sigh.
538 *
539 * The deal here is that we never free message URBs since they are integrated
540 * into the message pipe state. But since cancel can leave URBs unreaped and in
541 * a state which require them not to be freed, we'll have to do two things.
542 * First, if a new message URB is processed we'll have to get a new message
543 * pipe state. Second, we cannot just free the damn state structure because
544 * that might lead to heap corruption since it might still be in-flight.
545 *
546 * The URB embedded into the message pipe control structure will start in an
547 * ALLOCATED state. When submitted it will be go to the IN-FLIGHT state. When
548 * reaped it will go from REAPED to ALLOCATED. When completed in the CANCELLED
549 * state it will remain in that state (as does normal URBs).
550 *
551 * If a new message urb comes up while it's in the CANCELLED state, we will
552 * orphan it and it will be freed here in vusbMsgFreeUrb. We indicate this
553 * by setting pVUsb->pvFreeCtx to NULL.
554 *
555 * If we have to free the message state structure because of device destruction,
556 * configuration changes, or similar, we will orphan the message pipe state in
557 * the same way by setting pVUsb->pvFreeCtx to NULL and let this function free it.
558 *
559 * @param pUrb
560 */
561static DECLCALLBACK(void) vusbMsgFreeUrb(PVUSBURB pUrb)
562{
563 vusbUrbAssert(pUrb);
564 PVUSBCTRLEXTRA pExtra = (PVUSBCTRLEXTRA)((uint8_t *)pUrb - RT_UOFFSETOF(VUSBCTRLEXTRA, Urb));
565 if ( pUrb->enmState == VUSBURBSTATE_CANCELLED
566 && !pUrb->pVUsb->pvFreeCtx)
567 {
568 LogFlow(("vusbMsgFreeUrb: Freeing orphan: %p (pUrb=%p)\n", pExtra, pUrb));
569 RTMemFree(pExtra);
570 }
571 else
572 {
573 Assert(pUrb->pVUsb->pvFreeCtx == &pExtra->Urb);
574 pUrb->enmState = VUSBURBSTATE_ALLOCATED;
575 pUrb->fCompleting = false;
576 }
577}
578
579/**
580 * Frees the extra state data associated with a message pipe.
581 *
582 * @param pExtra The data.
583 */
584void vusbMsgFreeExtraData(PVUSBCTRLEXTRA pExtra)
585{
586 if (!pExtra)
587 return;
588 if (pExtra->Urb.enmState != VUSBURBSTATE_CANCELLED)
589 {
590 pExtra->Urb.u32Magic = 0;
591 pExtra->Urb.enmState = VUSBURBSTATE_FREE;
592 if (pExtra->Urb.pszDesc)
593 RTStrFree(pExtra->Urb.pszDesc);
594 RTMemFree(pExtra);
595 }
596 else
597 pExtra->Urb.pVUsb->pvFreeCtx = NULL; /* see vusbMsgFreeUrb */
598}
599
600/**
601 * Allocates the extra state data required for a control pipe.
602 *
603 * @returns Pointer to the allocated and initialized state data.
604 * @returns NULL on out of memory condition.
605 * @param pUrb A URB we can copy default data from.
606 */
607static PVUSBCTRLEXTRA vusbMsgAllocExtraData(PVUSBURB pUrb)
608{
609/** @todo reuse these? */
610 PVUSBCTRLEXTRA pExtra;
611 /* The initial allocation tries to balance wasted memory versus the need to re-allocate
612 * the message data. Experience shows that an 8K initial allocation in practice never needs
613 * to be expanded but almost certainly wastes 4K or more memory.
614 */
615 const size_t cbMax = _2K + sizeof(VUSBSETUP);
616 pExtra = (PVUSBCTRLEXTRA)RTMemAllocZ(RT_UOFFSETOF_DYN(VUSBCTRLEXTRA, Urb.abData[cbMax]));
617 if (pExtra)
618 {
619 pExtra->enmStage = CTLSTAGE_SETUP;
620 //pExtra->fOk = false;
621 pExtra->pMsg = (PVUSBSETUP)pExtra->Urb.abData;
622 pExtra->pbCur = (uint8_t *)(pExtra->pMsg + 1);
623 //pExtra->cbLeft = 0;
624 pExtra->cbMax = cbMax;
625
626 //pExtra->Urb.Dev.pvProxyUrb = NULL;
627 pExtra->Urb.u32Magic = VUSBURB_MAGIC;
628 pExtra->Urb.enmState = VUSBURBSTATE_ALLOCATED;
629 pExtra->Urb.fCompleting = false;
630#ifdef LOG_ENABLED
631 RTStrAPrintf(&pExtra->Urb.pszDesc, "URB %p msg->%p", &pExtra->Urb, pUrb);
632#endif
633 pExtra->Urb.pVUsb = &pExtra->VUsbExtra;
634 //pExtra->Urb.pVUsb->pCtrlUrb = NULL;
635 //pExtra->Urb.pVUsb->pNext = NULL;
636 //pExtra->Urb.pVUsb->ppPrev = NULL;
637 pExtra->Urb.pVUsb->pUrb = &pExtra->Urb;
638 pExtra->Urb.pVUsb->pDev = pUrb->pVUsb->pDev;
639 pExtra->Urb.pVUsb->pfnFree = vusbMsgFreeUrb;
640 pExtra->Urb.pVUsb->pvFreeCtx = &pExtra->Urb;
641 //pExtra->Urb.Hci = {0};
642 //pExtra->Urb.Dev.pvProxyUrb = NULL;
643 pExtra->Urb.DstAddress = pUrb->DstAddress;
644 pExtra->Urb.EndPt = pUrb->EndPt;
645 pExtra->Urb.enmType = VUSBXFERTYPE_MSG;
646 pExtra->Urb.enmDir = VUSBDIRECTION_INVALID;
647 //pExtra->Urb.fShortNotOk = false;
648 pExtra->Urb.enmStatus = VUSBSTATUS_INVALID;
649 //pExtra->Urb.cbData = 0;
650 vusbUrbAssert(&pExtra->Urb);
651 }
652 return pExtra;
653}
654
655/**
656 * Sets up the message.
657 *
658 * The message is associated with the pipe, in what's currently called
659 * control pipe extra state data (pointed to by pPipe->pCtrl). If this
660 * is a OUT message, we will no go on collecting data URB. If it's a
661 * IN message, we'll send it and then queue any incoming data for the
662 * URBs collecting it.
663 *
664 * @returns Success indicator.
665 */
666static bool vusbMsgSetup(PVUSBPIPE pPipe, const void *pvBuf, uint32_t cbBuf)
667{
668 PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
669 const VUSBSETUP *pSetupIn = (PVUSBSETUP)pvBuf;
670
671 /*
672 * Validate length.
673 */
674 if (cbBuf < sizeof(VUSBSETUP))
675 {
676 LogFlow(("vusbMsgSetup: pPipe=%p cbBuf=%u < %u (failure) !!!\n",
677 pPipe, cbBuf, sizeof(VUSBSETUP)));
678 return false;
679 }
680
681 /*
682 * Check if we've got an cancelled message URB. Allocate a new one in that case.
683 */
684 if (pExtra->Urb.enmState == VUSBURBSTATE_CANCELLED)
685 {
686 void *pvNew = RTMemDup(pExtra, RT_UOFFSETOF_DYN(VUSBCTRLEXTRA, Urb.abData[pExtra->cbMax]));
687 if (!pvNew)
688 {
689 Log(("vusbMsgSetup: out of memory!!! cbReq=%zu\n", RT_UOFFSETOF_DYN(VUSBCTRLEXTRA, Urb.abData[pExtra->cbMax])));
690 return false;
691 }
692 pExtra->Urb.pVUsb->pvFreeCtx = NULL;
693 LogFlow(("vusbMsgSetup: Replacing canceled pExtra=%p with %p.\n", pExtra, pvNew));
694 pPipe->pCtrl = pExtra = (PVUSBCTRLEXTRA)pvNew;
695 pExtra->Urb.pVUsb = &pExtra->VUsbExtra;
696 pExtra->Urb.pVUsb->pUrb = &pExtra->Urb;
697 pExtra->pMsg = (PVUSBSETUP)pExtra->Urb.abData;
698 pExtra->Urb.enmState = VUSBURBSTATE_ALLOCATED;
699 pExtra->Urb.fCompleting = false;
700 }
701
702 /*
703 * Check that we've got sufficient space in the message URB.
704 */
705 if (pExtra->cbMax < cbBuf + pSetupIn->wLength)
706 {
707 uint32_t cbReq = RT_ALIGN_32(cbBuf + pSetupIn->wLength, 64);
708 PVUSBCTRLEXTRA pNew = (PVUSBCTRLEXTRA)RTMemRealloc(pExtra, RT_UOFFSETOF_DYN(VUSBCTRLEXTRA, Urb.abData[cbReq]));
709 if (!pNew)
710 {
711 Log(("vusbMsgSetup: out of memory!!! cbReq=%u %zu\n",
712 cbReq, RT_UOFFSETOF_DYN(VUSBCTRLEXTRA, Urb.abData[cbReq])));
713 return false;
714 }
715 if (pExtra != pNew)
716 {
717 LogFunc(("Reallocated %u -> %u\n", pExtra->cbMax, cbReq));
718 pNew->pMsg = (PVUSBSETUP)pNew->Urb.abData;
719 pExtra = pNew;
720 pPipe->pCtrl = pExtra;
721 pExtra->Urb.pVUsb = &pExtra->VUsbExtra;
722 pExtra->Urb.pVUsb->pUrb = &pExtra->Urb;
723 pExtra->Urb.pVUsb->pvFreeCtx = &pExtra->Urb;
724 }
725
726 pExtra->cbMax = cbReq;
727 }
728 Assert(pExtra->Urb.enmState == VUSBURBSTATE_ALLOCATED);
729
730 /*
731 * Copy the setup data and prepare for data.
732 */
733 PVUSBSETUP pSetup = pExtra->pMsg;
734 pExtra->fSubmitted = false;
735 pExtra->Urb.enmState = VUSBURBSTATE_IN_FLIGHT;
736 pExtra->pbCur = (uint8_t *)(pSetup + 1);
737 pSetup->bmRequestType = pSetupIn->bmRequestType;
738 pSetup->bRequest = pSetupIn->bRequest;
739 pSetup->wValue = RT_LE2H_U16(pSetupIn->wValue);
740 pSetup->wIndex = RT_LE2H_U16(pSetupIn->wIndex);
741 pSetup->wLength = RT_LE2H_U16(pSetupIn->wLength);
742
743 LogFlow(("vusbMsgSetup(%p,,%d): bmRequestType=%#04x bRequest=%#04x wValue=%#06x wIndex=%#06x wLength=0x%.4x\n",
744 pPipe, cbBuf, pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
745 return true;
746}
747
748/**
749 * Build the message URB from the given control URB and accompanying message
750 * pipe state which we grab from the device for the URB.
751 *
752 * @param pUrb The URB to submit.
753 * @param pSetup The setup packet for the message transfer.
754 * @param pExtra Pointer to the additional state requred for a control transfer.
755 * @param pPipe The message pipe state.
756 */
757static void vusbMsgDoTransfer(PVUSBURB pUrb, PVUSBSETUP pSetup, PVUSBCTRLEXTRA pExtra, PVUSBPIPE pPipe)
758{
759 RT_NOREF(pPipe);
760
761 /*
762 * Mark this transfer as sent (cleared at setup time).
763 */
764 Assert(!pExtra->fSubmitted);
765 pExtra->fSubmitted = true;
766
767 /*
768 * Do we have to do this synchronously?
769 */
770 bool fSafeRequest = vusbUrbIsRequestSafe(pSetup, pUrb);
771 if (!fSafeRequest)
772 {
773 vusbMsgSubmitSynchronously(pUrb, fSafeRequest);
774 return;
775 }
776
777 /*
778 * Do it asynchronously.
779 */
780 LogFlow(("%s: vusbMsgDoTransfer: ep=%d pMsgUrb=%p pPipe=%p stage=%s\n",
781 pUrb->pszDesc, pUrb->EndPt, &pExtra->Urb, pPipe, g_apszCtlStates[pExtra->enmStage]));
782 Assert(pExtra->Urb.enmType == VUSBXFERTYPE_MSG);
783 Assert(pExtra->Urb.EndPt == pUrb->EndPt);
784 pExtra->Urb.enmDir = (pSetup->bmRequestType & VUSB_DIR_TO_HOST) ? VUSBDIRECTION_IN : VUSBDIRECTION_OUT;
785 pExtra->Urb.cbData = pSetup->wLength + sizeof(*pSetup);
786 pExtra->Urb.pVUsb->pCtrlUrb = pUrb;
787 int rc = vusbUrbQueueAsyncRh(&pExtra->Urb);
788 if (RT_FAILURE(rc))
789 {
790 /*
791 * If we fail submitting it, will not retry but fail immediately.
792 *
793 * This keeps things simple. The host OS will have retried if
794 * it's a proxied device, and if it's a virtual one it really means
795 * it if it's failing a control message.
796 */
797 LogFlow(("%s: vusbMsgDoTransfer: failed submitting urb! failing it with %s (rc=%Rrc)!!!\n",
798 pUrb->pszDesc, rc == VERR_VUSB_DEVICE_NOT_ATTACHED ? "DNR" : "CRC", rc));
799 pExtra->Urb.enmStatus = rc == VERR_VUSB_DEVICE_NOT_ATTACHED ? VUSBSTATUS_DNR : VUSBSTATUS_CRC;
800 pExtra->Urb.enmState = VUSBURBSTATE_REAPED;
801 vusbMsgCompletion(&pExtra->Urb);
802 }
803}
804
805/**
806 * Fails a URB request with a pipe STALL error.
807 *
808 * @returns VINF_SUCCESS indicating that we've completed the URB.
809 * @param pUrb The URB in question.
810 */
811static int vusbMsgStall(PVUSBURB pUrb)
812{
813 PVUSBPIPE pPipe = &pUrb->pVUsb->pDev->aPipes[pUrb->EndPt];
814 PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
815 LogFlow(("%s: vusbMsgStall: pPipe=%p err=STALL stage %s->SETUP\n",
816 pUrb->pszDesc, pPipe, g_apszCtlStates[pExtra->enmStage]));
817
818 pExtra->pbCur = NULL;
819 pExtra->enmStage = CTLSTAGE_SETUP;
820 pUrb->enmState = VUSBURBSTATE_REAPED;
821 pUrb->enmStatus = VUSBSTATUS_STALL;
822 vusbUrbCompletionRh(pUrb);
823 return VINF_SUCCESS;
824}
825
826/**
827 * Submit a control message.
828 *
829 * Here we implement the USB defined traffic that occurs in message pipes
830 * (aka control endpoints). We want to provide a single function for device
831 * drivers so that they don't all have to reimplement the usb logic for
832 * themselves. This means we need to keep a little bit of state information
833 * because control transfers occur over multiple bus transactions. We may
834 * also need to buffer data over multiple data stages.
835 *
836 * @returns VBox status code.
837 * @param pUrb The URB to submit.
838 */
839static int vusbUrbSubmitCtrl(PVUSBURB pUrb)
840{
841#ifdef LOG_ENABLED
842 vusbUrbTrace(pUrb, "vusbUrbSubmitCtrl", false);
843#endif
844 PVUSBDEV pDev = pUrb->pVUsb->pDev;
845 PVUSBPIPE pPipe = &pDev->aPipes[pUrb->EndPt];
846
847 RTCritSectEnter(&pPipe->CritSectCtrl);
848 PVUSBCTRLEXTRA pExtra = pPipe->pCtrl;
849
850 if (!pExtra && !(pExtra = pPipe->pCtrl = vusbMsgAllocExtraData(pUrb)))
851 {
852 RTCritSectLeave(&pPipe->CritSectCtrl);
853 return VERR_VUSB_NO_URB_MEMORY;
854 }
855 PVUSBSETUP pSetup = pExtra->pMsg;
856
857 if (pPipe->async)
858 {
859 AssertMsgFailed(("%u\n", pPipe->async));
860 RTCritSectLeave(&pPipe->CritSectCtrl);
861 return VERR_GENERAL_FAILURE;
862 }
863
864 /*
865 * A setup packet always resets the transaction and the
866 * end of data transmission is signified by change in
867 * data direction.
868 */
869 if (pUrb->enmDir == VUSBDIRECTION_SETUP)
870 {
871 LogFlow(("%s: vusbUrbSubmitCtrl: pPipe=%p state %s->SETUP\n",
872 pUrb->pszDesc, pPipe, g_apszCtlStates[pExtra->enmStage]));
873 pExtra->enmStage = CTLSTAGE_SETUP;
874 }
875 else if ( pExtra->enmStage == CTLSTAGE_DATA
876 /* (the STATUS stage direction goes the other way) */
877 && !!(pSetup->bmRequestType & VUSB_DIR_TO_HOST) != (pUrb->enmDir == VUSBDIRECTION_IN))
878 {
879 LogFlow(("%s: vusbUrbSubmitCtrl: pPipe=%p state %s->STATUS\n",
880 pUrb->pszDesc, pPipe, g_apszCtlStates[pExtra->enmStage]));
881 pExtra->enmStage = CTLSTAGE_STATUS;
882 }
883
884 /*
885 * Act according to the current message stage.
886 */
887 switch (pExtra->enmStage)
888 {
889 case CTLSTAGE_SETUP:
890 /*
891 * When stall handshake is returned, all subsequent packets
892 * must generate stall until a setup packet arrives.
893 */
894 if (pUrb->enmDir != VUSBDIRECTION_SETUP)
895 {
896 Log(("%s: vusbUrbSubmitCtrl: Stall at setup stage (dir=%#x)!!\n", pUrb->pszDesc, pUrb->enmDir));
897 vusbMsgStall(pUrb);
898 break;
899 }
900
901 /* Store setup details, return DNR if corrupt */
902 if (!vusbMsgSetup(pPipe, pUrb->abData, pUrb->cbData))
903 {
904 pUrb->enmState = VUSBURBSTATE_REAPED;
905 pUrb->enmStatus = VUSBSTATUS_DNR;
906 vusbUrbCompletionRh(pUrb);
907 break;
908 }
909 if (pPipe->pCtrl != pExtra)
910 {
911 pExtra = pPipe->pCtrl;
912 pSetup = pExtra->pMsg;
913 }
914
915 /* pre-buffer our output if it's device-to-host */
916 if (pSetup->bmRequestType & VUSB_DIR_TO_HOST)
917 vusbMsgDoTransfer(pUrb, pSetup, pExtra, pPipe);
918 else if (pSetup->wLength)
919 {
920 LogFlow(("%s: vusbUrbSubmitCtrl: stage=SETUP - to dev: need data\n", pUrb->pszDesc));
921 pUrb->enmState = VUSBURBSTATE_REAPED;
922 vusbMsgSetupCompletion(pUrb);
923 vusbUrbCompletionRh(pUrb);
924 }
925 /*
926 * If there is no DATA stage, we must send it now since there are
927 * no requirement of a STATUS stage.
928 */
929 else
930 {
931 LogFlow(("%s: vusbUrbSubmitCtrl: stage=SETUP - to dev: sending\n", pUrb->pszDesc));
932 vusbMsgDoTransfer(pUrb, pSetup, pExtra, pPipe);
933 }
934 break;
935
936 case CTLSTAGE_DATA:
937 {
938 /*
939 * If a data stage exceeds the target buffer indicated in
940 * setup return stall, if data stage returns stall there
941 * will be no status stage.
942 */
943 uint8_t *pbData = (uint8_t *)(pExtra->pMsg + 1);
944 if ((uintptr_t)&pExtra->pbCur[pUrb->cbData] > (uintptr_t)&pbData[pSetup->wLength])
945 {
946 /* In the device -> host direction, the device never returns more data than
947 what was requested (wLength). So, we can just cap cbData. */
948 ssize_t const cbLeft = &pbData[pSetup->wLength] - pExtra->pbCur;
949 if (pSetup->bmRequestType & VUSB_DIR_TO_HOST)
950 {
951 LogFlow(("%s: vusbUrbSubmitCtrl: Adjusting DATA request: %d -> %d\n", pUrb->pszDesc, pUrb->cbData, cbLeft));
952 pUrb->cbData = cbLeft >= 0 ? (uint32_t)cbLeft : 0;
953 }
954 /* In the host -> direction it's undefined what happens if the host provides
955 more data than what wLength inidicated. However, in 2007, iPhone detection
956 via iTunes would issue wLength=0 but provide a data URB which we needed to
957 pass on to the device anyway, so we'll just quietly adjust wLength if it's
958 zero and get on with the work.
959
960 What confuses me (bird) here, though, is that we've already sent the SETUP
961 URB to the device when we received it, and all we end up doing is an
962 unnecessary memcpy and completing the URB, but never actually sending the
963 data to the device. So, I guess this stuff is still a little iffy.
964
965 Note! We currently won't be doing any resizing, as we've disabled resizing
966 in general.
967 P.S. We used to have a very strange (pUrb->cbData % pSetup->wLength) == 0
968 thing too that joined the pUrb->cbData adjusting above. */
969 else if ( pSetup->wLength == 0
970 && pUrb->cbData <= pExtra->cbMax)
971 {
972 Log(("%s: vusbUrbSubmitCtrl: pAdjusting wLength: %u -> %u (iPhone hack)\n",
973 pUrb->pszDesc, pSetup->wLength, pUrb->cbData));
974 pSetup->wLength = pUrb->cbData;
975 Assert(cbLeft >= (ssize_t)pUrb->cbData);
976 }
977 else
978 {
979 Log(("%s: vusbUrbSubmitCtrl: Stall at data stage!! wLength=%u cbData=%d cbMax=%d cbLeft=%dz\n",
980 pUrb->pszDesc, pSetup->wLength, pUrb->cbData, pExtra->cbMax, cbLeft));
981 vusbMsgStall(pUrb);
982 break;
983 }
984 }
985
986 if (pUrb->enmDir == VUSBDIRECTION_IN)
987 {
988 /* put data received from the device. */
989 const uint32_t cbRead = RT_MIN(pUrb->cbData, pExtra->cbLeft);
990 memcpy(pUrb->abData, pExtra->pbCur, cbRead);
991
992 /* advance */
993 pExtra->pbCur += cbRead;
994 if (pUrb->cbData == cbRead)
995 pExtra->cbLeft -= pUrb->cbData;
996 else
997 {
998 /* adjust the pUrb->cbData to reflect the number of bytes containing actual data. */
999 LogFlow(("%s: vusbUrbSubmitCtrl: adjusting last DATA pUrb->cbData, %d -> %d\n",
1000 pUrb->pszDesc, pUrb->cbData, pExtra->cbLeft));
1001 pUrb->cbData = cbRead;
1002 pExtra->cbLeft = 0;
1003 }
1004 }
1005 else
1006 {
1007 /* get data for sending when completed. */
1008 AssertStmt((ssize_t)pUrb->cbData <= pExtra->cbMax - (pExtra->pbCur - pbData), /* paranoia: checked above */
1009 pUrb->cbData = pExtra->cbMax - (uint32_t)RT_MIN(pExtra->pbCur - pbData, pExtra->cbMax));
1010 memcpy(pExtra->pbCur, pUrb->abData, pUrb->cbData);
1011
1012 /* advance */
1013 pExtra->pbCur += pUrb->cbData;
1014
1015 /*
1016 * If we've got the necessary data, we'll send it now since there are
1017 * no requirement of a STATUS stage.
1018 */
1019 if ( !pExtra->fSubmitted
1020 && pExtra->pbCur - pbData >= pSetup->wLength)
1021 {
1022 LogFlow(("%s: vusbUrbSubmitCtrl: stage=DATA - to dev: sending\n", pUrb->pszDesc));
1023 vusbMsgDoTransfer(pUrb, pSetup, pExtra, pPipe);
1024 break;
1025 }
1026 }
1027
1028 pUrb->enmState = VUSBURBSTATE_REAPED;
1029 vusbMsgDataCompletion(pUrb);
1030 vusbUrbCompletionRh(pUrb);
1031 break;
1032 }
1033
1034 case CTLSTAGE_STATUS:
1035 if ( (pSetup->bmRequestType & VUSB_DIR_TO_HOST)
1036 || pExtra->fSubmitted)
1037 {
1038 Assert(pExtra->fSubmitted);
1039 pUrb->enmState = VUSBURBSTATE_REAPED;
1040 vusbMsgStatusCompletion(pUrb);
1041 vusbUrbCompletionRh(pUrb);
1042 }
1043 else
1044 {
1045 LogFlow(("%s: vusbUrbSubmitCtrl: stage=STATUS - to dev: sending\n", pUrb->pszDesc));
1046 vusbMsgDoTransfer(pUrb, pSetup, pExtra, pPipe);
1047 }
1048 break;
1049 }
1050
1051 RTCritSectLeave(&pPipe->CritSectCtrl);
1052 return VINF_SUCCESS;
1053}
1054
1055
1056/**
1057 * Submit a interrupt URB.
1058 *
1059 * @returns VBox status code.
1060 * @param pUrb The URB to submit.
1061 */
1062static int vusbUrbSubmitInterrupt(PVUSBURB pUrb)
1063{
1064 LogFlow(("%s: vusbUrbSubmitInterrupt: (sync)\n", pUrb->pszDesc));
1065 return vusbUrbQueueAsyncRh(pUrb);
1066}
1067
1068
1069/**
1070 * Submit a bulk URB.
1071 *
1072 * @returns VBox status code.
1073 * @param pUrb The URB to submit.
1074 */
1075static int vusbUrbSubmitBulk(PVUSBURB pUrb)
1076{
1077 LogFlow(("%s: vusbUrbSubmitBulk: (async)\n", pUrb->pszDesc));
1078 return vusbUrbQueueAsyncRh(pUrb);
1079}
1080
1081
1082/**
1083 * Submit an isochronous URB.
1084 *
1085 * @returns VBox status code.
1086 * @param pUrb The URB to submit.
1087 */
1088static int vusbUrbSubmitIsochronous(PVUSBURB pUrb)
1089{
1090 LogFlow(("%s: vusbUrbSubmitIsochronous: (async)\n", pUrb->pszDesc));
1091 return vusbUrbQueueAsyncRh(pUrb);
1092}
1093
1094
1095/**
1096 * Fail a URB with a 'hard-error' sort of error.
1097 *
1098 * @return VINF_SUCCESS (the Urb status indicates the error).
1099 * @param pUrb The URB.
1100 */
1101int vusbUrbSubmitHardError(PVUSBURB pUrb)
1102{
1103 /* FIXME: Find out the correct return code from the spec */
1104 pUrb->enmState = VUSBURBSTATE_REAPED;
1105 pUrb->enmStatus = VUSBSTATUS_DNR;
1106 vusbUrbCompletionRh(pUrb);
1107 return VINF_SUCCESS;
1108}
1109
1110
1111/**
1112 * Submit a URB.
1113 */
1114int vusbUrbSubmit(PVUSBURB pUrb)
1115{
1116 vusbUrbAssert(pUrb);
1117 Assert(pUrb->enmState == VUSBURBSTATE_ALLOCATED);
1118 PVUSBDEV pDev = pUrb->pVUsb->pDev;
1119 PVUSBPIPE pPipe = NULL;
1120 Assert(pDev);
1121
1122 /*
1123 * Check that the device is in a valid state.
1124 */
1125 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
1126 if (enmState == VUSB_DEVICE_STATE_RESET)
1127 {
1128 LogRel(("VUSB: %s: power off ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
1129 pUrb->enmStatus = VUSBSTATUS_DNR;
1130 /* This will postpone the TDs until we're done with the resetting. */
1131 return VERR_VUSB_DEVICE_IS_RESETTING;
1132 }
1133
1134#ifdef LOG_ENABLED
1135 /* stamp it */
1136 pUrb->pVUsb->u64SubmitTS = RTTimeNanoTS();
1137#endif
1138
1139 /** @todo Check max packet size here too? */
1140
1141 /*
1142 * Validate the pipe.
1143 */
1144 if (pUrb->EndPt >= VUSB_PIPE_MAX)
1145 {
1146 Log(("%s: pDev=%p[%s]: SUBMIT: ep %i >= %i!!!\n", pUrb->pszDesc, pDev, pDev->pUsbIns->pszName, pUrb->EndPt, VUSB_PIPE_MAX));
1147 return vusbUrbSubmitHardError(pUrb);
1148 }
1149 PCVUSBDESCENDPOINTEX pEndPtDesc;
1150 switch (pUrb->enmDir)
1151 {
1152 case VUSBDIRECTION_IN:
1153 pEndPtDesc = pDev->aPipes[pUrb->EndPt].in;
1154 pPipe = &pDev->aPipes[pUrb->EndPt];
1155 break;
1156 case VUSBDIRECTION_SETUP:
1157 case VUSBDIRECTION_OUT:
1158 default:
1159 pEndPtDesc = pDev->aPipes[pUrb->EndPt].out;
1160 pPipe = &pDev->aPipes[pUrb->EndPt];
1161 break;
1162 }
1163 if (!pEndPtDesc)
1164 {
1165 Log(("%s: pDev=%p[%s]: SUBMIT: no endpoint!!! dir=%s e=%i\n",
1166 pUrb->pszDesc, pDev, pDev->pUsbIns->pszName, vusbUrbDirName(pUrb->enmDir), pUrb->EndPt));
1167 return vusbUrbSubmitHardError(pUrb);
1168 }
1169
1170 /*
1171 * Check for correct transfer types.
1172 * Our type codes are the same - what a coincidence.
1173 */
1174 if ((pEndPtDesc->Core.bmAttributes & 0x3) != pUrb->enmType)
1175 {
1176 /* Bulk and interrupt transfers are identical on the bus level (the only difference
1177 * is in how they are scheduled by the HCD/HC) and need an exemption.
1178 * Atheros AR9271 is a known offender; its configuration descriptors include
1179 * interrupt endpoints, but drivers (Win7/8, Linux kernel pre-3.05) treat them
1180 * as bulk endpoints.
1181 */
1182 if ( (pUrb->enmType == VUSBXFERTYPE_BULK && (pEndPtDesc->Core.bmAttributes & 0x3) == VUSBXFERTYPE_INTR)
1183 || (pUrb->enmType == VUSBXFERTYPE_INTR && (pEndPtDesc->Core.bmAttributes & 0x3) == VUSBXFERTYPE_BULK))
1184 {
1185 Log2(("%s: pDev=%p[%s]: SUBMIT: mixing bulk/interrupt transfers on DstAddress=%i ep=%i dir=%s\n",
1186 pUrb->pszDesc, pDev, pDev->pUsbIns->pszName,
1187 pUrb->DstAddress, pUrb->EndPt, vusbUrbDirName(pUrb->enmDir)));
1188 }
1189 else
1190 {
1191 Log(("%s: pDev=%p[%s]: SUBMIT: %s transfer requested for %#x endpoint on DstAddress=%i ep=%i dir=%s\n",
1192 pUrb->pszDesc, pDev, pDev->pUsbIns->pszName, vusbUrbTypeName(pUrb->enmType), pEndPtDesc->Core.bmAttributes,
1193 pUrb->DstAddress, pUrb->EndPt, vusbUrbDirName(pUrb->enmDir)));
1194 return vusbUrbSubmitHardError(pUrb);
1195 }
1196 }
1197
1198 /*
1199 * If there's a URB in the read-ahead buffer, use it.
1200 */
1201 int rc;
1202
1203 if (pDev->hSniffer)
1204 {
1205 rc = VUSBSnifferRecordEvent(pDev->hSniffer, pUrb, VUSBSNIFFEREVENT_SUBMIT);
1206 if (RT_FAILURE(rc))
1207 LogRel(("VUSB: Capturing URB submit event failed with %Rrc\n", rc));
1208 }
1209
1210 /*
1211 * Take action based on type.
1212 */
1213 pUrb->enmState = VUSBURBSTATE_IN_FLIGHT;
1214 switch (pUrb->enmType)
1215 {
1216 case VUSBXFERTYPE_CTRL:
1217 rc = vusbUrbSubmitCtrl(pUrb);
1218 break;
1219 case VUSBXFERTYPE_BULK:
1220 rc = vusbUrbSubmitBulk(pUrb);
1221 break;
1222 case VUSBXFERTYPE_INTR:
1223 rc = vusbUrbSubmitInterrupt(pUrb);
1224 break;
1225 case VUSBXFERTYPE_ISOC:
1226 rc = vusbUrbSubmitIsochronous(pUrb);
1227 break;
1228 default:
1229 AssertMsgFailed(("Unexpected pUrb type %d\n", pUrb->enmType));
1230 return vusbUrbSubmitHardError(pUrb);
1231 }
1232
1233 /*
1234 * The device was detached, so we fail everything.
1235 * (We should really detach and destroy the device, but we'll have to wait till Main reacts.)
1236 */
1237 if (rc == VERR_VUSB_DEVICE_NOT_ATTACHED)
1238 rc = vusbUrbSubmitHardError(pUrb);
1239 /*
1240 * We don't increment error count if async URBs are in flight, in
1241 * this case we just assume we need to throttle back, this also
1242 * makes sure we don't halt bulk endpoints at the wrong time.
1243 */
1244 else if ( RT_FAILURE(rc)
1245 && !ASMAtomicReadU32(&pDev->aPipes[pUrb->EndPt].async)
1246 /* && pUrb->enmType == VUSBXFERTYPE_BULK ?? */
1247 && !vusbUrbErrorRh(pUrb))
1248 {
1249 /* don't retry it anymore. */
1250 pUrb->enmState = VUSBURBSTATE_REAPED;
1251 pUrb->enmStatus = VUSBSTATUS_CRC;
1252 vusbUrbCompletionRh(pUrb);
1253 return VINF_SUCCESS;
1254 }
1255
1256 return rc;
1257}
1258
1259
1260/**
1261 * Reap in-flight URBs.
1262 *
1263 * @param pUrbLst Pointer to the head of the URB list.
1264 * @param cMillies Number of milliseconds to block in each reap operation.
1265 * Use 0 to not block at all.
1266 */
1267void vusbUrbDoReapAsync(PRTLISTANCHOR pUrbLst, RTMSINTERVAL cMillies)
1268{
1269 PVUSBURBVUSB pVUsbUrb = RTListGetFirst(pUrbLst, VUSBURBVUSBINT, NdLst);
1270 while (pVUsbUrb)
1271 {
1272 vusbUrbAssert(pVUsbUrb->pUrb);
1273 PVUSBURBVUSB pVUsbUrbNext = RTListGetNext(pUrbLst, pVUsbUrb, VUSBURBVUSBINT, NdLst);
1274 PVUSBDEV pDev = pVUsbUrb->pDev;
1275
1276 /* Don't touch resetting devices - paranoid safety precaution. */
1277 if (vusbDevGetState(pDev) != VUSB_DEVICE_STATE_RESET)
1278 {
1279 /*
1280 * Reap most URBs pending on a single device.
1281 */
1282 PVUSBURB pRipe;
1283
1284 /**
1285 * This is workaround for race(should be fixed) detach on one EMT thread and frame boundary timer on other
1286 * and leaked URBs (shouldn't be affected by leaked URBs).
1287 */
1288 Assert(pDev->pUsbIns);
1289 while ( pDev->pUsbIns
1290 && ((pRipe = pDev->pUsbIns->pReg->pfnUrbReap(pDev->pUsbIns, cMillies)) != NULL))
1291 {
1292 vusbUrbAssert(pRipe);
1293 if (pVUsbUrbNext && pRipe == pVUsbUrbNext->pUrb)
1294 pVUsbUrbNext = RTListGetNext(pUrbLst, pVUsbUrbNext, VUSBURBVUSBINT, NdLst);
1295 vusbUrbRipe(pRipe);
1296 }
1297 }
1298
1299 /* next */
1300 pVUsbUrb = pVUsbUrbNext;
1301 }
1302}
1303
1304/**
1305 * Reap URBs on a per device level.
1306 *
1307 * @returns nothing.
1308 * @param pDev The device instance to reap URBs for.
1309 * @param cMillies Number of milliseconds to block in each reap operation.
1310 * Use 0 to not block at all.
1311 */
1312void vusbUrbDoReapAsyncDev(PVUSBDEV pDev, RTMSINTERVAL cMillies)
1313{
1314 Assert(pDev->enmState != VUSB_DEVICE_STATE_RESET);
1315
1316 /*
1317 * Reap most URBs pending on a single device.
1318 */
1319 PVUSBURB pRipe;
1320
1321 /**
1322 * This is workaround for race(should be fixed) detach on one EMT thread and frame boundary timer on other
1323 * and leaked URBs (shouldn't be affected by leaked URBs).
1324 */
1325
1326 if (ASMAtomicXchgBool(&pDev->fWokenUp, false))
1327 return;
1328
1329 Assert(pDev->pUsbIns);
1330 while ( pDev->pUsbIns
1331 && ((pRipe = pDev->pUsbIns->pReg->pfnUrbReap(pDev->pUsbIns, cMillies)) != NULL))
1332 {
1333 vusbUrbAssert(pRipe);
1334 vusbUrbRipe(pRipe);
1335 if (ASMAtomicXchgBool(&pDev->fWokenUp, false))
1336 break;
1337 }
1338}
1339
1340/**
1341 * Completes the URB.
1342 */
1343static void vusbUrbCompletion(PVUSBURB pUrb)
1344{
1345 Assert(pUrb->pVUsb->pDev->aPipes);
1346 ASMAtomicDecU32(&pUrb->pVUsb->pDev->aPipes[pUrb->EndPt].async);
1347
1348 if (pUrb->enmState == VUSBURBSTATE_REAPED)
1349 vusbUrbUnlink(pUrb);
1350
1351 vusbUrbCompletionRh(pUrb);
1352}
1353
1354/**
1355 * The worker for vusbUrbCancel() which is executed on the I/O thread.
1356 *
1357 * @returns IPRT status code.
1358 * @param pUrb The URB to cancel.
1359 * @param enmMode The way the URB should be canceled.
1360 */
1361DECLHIDDEN(int) vusbUrbCancelWorker(PVUSBURB pUrb, CANCELMODE enmMode)
1362{
1363 vusbUrbAssert(pUrb);
1364#ifdef VBOX_WITH_STATISTICS
1365 PVUSBROOTHUB pRh = vusbDevGetRh(pUrb->pVUsb->pDev);
1366#endif
1367 if (pUrb->enmState == VUSBURBSTATE_IN_FLIGHT)
1368 {
1369 LogFlow(("%s: vusbUrbCancel: Canceling in-flight\n", pUrb->pszDesc));
1370 STAM_COUNTER_INC(&pRh->Total.StatUrbsCancelled);
1371 if (pUrb->enmType != VUSBXFERTYPE_MSG)
1372 {
1373 STAM_STATS({Assert(pUrb->enmType >= 0 && pUrb->enmType < (int)RT_ELEMENTS(pRh->aTypes));});
1374 STAM_COUNTER_INC(&pRh->aTypes[pUrb->enmType].StatUrbsCancelled);
1375 }
1376
1377 pUrb->enmState = VUSBURBSTATE_CANCELLED;
1378 PPDMUSBINS pUsbIns = pUrb->pVUsb->pDev->pUsbIns;
1379 pUsbIns->pReg->pfnUrbCancel(pUsbIns, pUrb);
1380 Assert(pUrb->enmState == VUSBURBSTATE_CANCELLED || pUrb->enmState == VUSBURBSTATE_REAPED);
1381
1382 pUrb->enmStatus = VUSBSTATUS_CRC;
1383 vusbUrbCompletion(pUrb);
1384 }
1385 else if (pUrb->enmState == VUSBURBSTATE_REAPED)
1386 {
1387 LogFlow(("%s: vusbUrbCancel: Canceling reaped urb\n", pUrb->pszDesc));
1388 STAM_COUNTER_INC(&pRh->Total.StatUrbsCancelled);
1389 if (pUrb->enmType != VUSBXFERTYPE_MSG)
1390 {
1391 STAM_STATS({Assert(pUrb->enmType >= 0 && pUrb->enmType < (int)RT_ELEMENTS(pRh->aTypes));});
1392 STAM_COUNTER_INC(&pRh->aTypes[pUrb->enmType].StatUrbsCancelled);
1393 }
1394
1395 pUrb->enmStatus = VUSBSTATUS_CRC;
1396 vusbUrbCompletion(pUrb);
1397 }
1398 else
1399 {
1400 AssertMsg(pUrb->enmState == VUSBURBSTATE_CANCELLED, ("Invalid state %d, pUrb=%p\n", pUrb->enmState, pUrb));
1401 switch (enmMode)
1402 {
1403 default:
1404 AssertMsgFailed(("Invalid cancel mode\n"));
1405 RT_FALL_THRU();
1406 case CANCELMODE_FAIL:
1407 pUrb->enmStatus = VUSBSTATUS_CRC;
1408 break;
1409 case CANCELMODE_UNDO:
1410 pUrb->enmStatus = VUSBSTATUS_UNDO;
1411 break;
1412
1413 }
1414 }
1415 return VINF_SUCCESS;
1416}
1417
1418/**
1419 * Cancels an URB with CRC failure.
1420 *
1421 * Cancelling an URB is a tricky thing. The USBProxy backend can not
1422 * all cancel it and we must keep the URB around until it's ripe and
1423 * can be reaped the normal way. However, we must complete the URB
1424 * now, before leaving this function. This is not nice. sigh.
1425 *
1426 * This function will cancel the URB if it's in-flight and complete
1427 * it. The device will in its pfnCancel method be given the chance to
1428 * say that the URB doesn't need reaping and should be unlinked.
1429 *
1430 * An URB which is in the cancel state after pfnCancel will remain in that
1431 * state and in the async list until its reaped. When it's finally reaped
1432 * it will be unlinked and freed without doing any completion.
1433 *
1434 * There are different modes of canceling an URB. When devices are being
1435 * disconnected etc., they will be completed with an error (CRC). However,
1436 * when the HC needs to temporarily halt communication with a device, the
1437 * URB/TD must be left alone if possible.
1438 *
1439 * @param pUrb The URB to cancel.
1440 * @param mode The way the URB should be canceled.
1441 */
1442void vusbUrbCancel(PVUSBURB pUrb, CANCELMODE mode)
1443{
1444 int rc = vusbDevIoThreadExecSync(pUrb->pVUsb->pDev, (PFNRT)vusbUrbCancelWorker, 2, pUrb, mode);
1445 AssertRC(rc);
1446}
1447
1448
1449/**
1450 * Async version of vusbUrbCancel() - doesn't wait for the cancelling to be complete.
1451 */
1452void vusbUrbCancelAsync(PVUSBURB pUrb, CANCELMODE mode)
1453{
1454 /* Don't try to cancel the URB when completion is in progress at the moment. */
1455 if (!ASMAtomicXchgBool(&pUrb->fCompleting, true))
1456 {
1457 int rc = vusbDevIoThreadExec(pUrb->pVUsb->pDev, 0 /* fFlags */, (PFNRT)vusbUrbCancelWorker, 2, pUrb, mode);
1458 AssertRC(rc);
1459 }
1460}
1461
1462
1463/**
1464 * Deals with a ripe URB (i.e. after reaping it).
1465 *
1466 * If an URB is in the reaped or in-flight state, we'll
1467 * complete it. If it's cancelled, we'll simply free it.
1468 * Any other states should never get here.
1469 *
1470 * @param pUrb The URB.
1471 */
1472void vusbUrbRipe(PVUSBURB pUrb)
1473{
1474 if ( pUrb->enmState == VUSBURBSTATE_IN_FLIGHT
1475 || pUrb->enmState == VUSBURBSTATE_REAPED)
1476 {
1477 pUrb->enmState = VUSBURBSTATE_REAPED;
1478 if (!ASMAtomicXchgBool(&pUrb->fCompleting, true))
1479 vusbUrbCompletion(pUrb);
1480 }
1481 else if (pUrb->enmState == VUSBURBSTATE_CANCELLED)
1482 {
1483 vusbUrbUnlink(pUrb);
1484 LogFlow(("%s: vusbUrbRipe: Freeing cancelled URB\n", pUrb->pszDesc));
1485 pUrb->pVUsb->pfnFree(pUrb);
1486 }
1487 else
1488 AssertMsgFailed(("Invalid URB state %d; %s\n", pUrb->enmState, pUrb->pszDesc));
1489}
1490
1491
1492/*
1493 * Local Variables:
1494 * mode: c
1495 * c-file-style: "bsd"
1496 * c-basic-offset: 4
1497 * tab-width: 4
1498 * indent-tabs-mode: s
1499 * End:
1500 */
1501
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