VirtualBox

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

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

VUSB: Some structural cleanup (#7 Move the debug log trace related bits into a separate file)

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