VirtualBox

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

Last change on this file since 59875 was 59875, checked in by vboxsync, 9 years ago

VUSB: Move the thread for periodic frame procession down to the roothub. There we don't need to replicate the code to EHCI later and it has much better overview of the amount of active URBs to schedule when to process new frames

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