VirtualBox

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

Last change on this file since 104591 was 104591, checked in by vboxsync, 7 months ago

Devices/USB/VUSBUrb.cpp: Remove unused variable, bugref:3409

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