VirtualBox

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

Last change on this file since 83617 was 83617, checked in by vboxsync, 5 years ago

VUSB: Avoid too large URBs (see bugref:9697).

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette