VirtualBox

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

Last change on this file since 88956 was 87609, checked in by vboxsync, 4 years ago

VUSB: Removed redundant casts, fixed forgotten code (see bugref:9928)/

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