VirtualBox

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

Last change on this file since 99739 was 99739, checked in by vboxsync, 16 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

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