VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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