VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/VUSBDevice.cpp@ 65919

Last change on this file since 65919 was 64294, checked in by vboxsync, 8 years ago

VUSB: Doxygen fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 60.6 KB
Line 
1/* $Id: VUSBDevice.cpp 64294 2016-10-17 11:34:36Z vboxsync $ */
2/** @file
3 * Virtual USB - Device.
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 <VBox/log.h>
27#include <iprt/alloc.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 "VUSBInternal.h"
35
36#include "VUSBSniffer.h"
37
38
39/*********************************************************************************************************************************
40* Structures and Typedefs *
41*********************************************************************************************************************************/
42/**
43 * Argument package of vusbDevResetThread().
44 */
45typedef struct vusb_reset_args
46{
47 /** Pointer to the device which is being reset. */
48 PVUSBDEV pDev;
49 /** The reset return code. */
50 int rc;
51 /** Pointer to the completion callback. */
52 PFNVUSBRESETDONE pfnDone;
53 /** User argument to pfnDone. */
54 void *pvUser;
55} VUSBRESETARGS, *PVUSBRESETARGS;
56
57
58/*********************************************************************************************************************************
59* Global Variables *
60*********************************************************************************************************************************/
61/** Default message pipe. */
62const VUSBDESCENDPOINTEX g_Endpoint0 =
63{
64 {
65 /* .bLength = */ VUSB_DT_ENDPOINT_MIN_LEN,
66 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
67 /* .bEndpointAddress = */ 0,
68 /* .bmAttributes = */ 0,
69 /* .wMaxPacketSize = */ 64,
70 /* .bInterval = */ 0
71 },
72 NULL
73};
74
75/** Default configuration. */
76const VUSBDESCCONFIGEX g_Config0 =
77{
78 {
79 /* .bLength = */ VUSB_DT_CONFIG_MIN_LEN,
80 /* .bDescriptorType = */ VUSB_DT_CONFIG,
81 /* .WTotalLength = */ 0, /* (auto-calculated) */
82 /* .bNumInterfaces = */ 0,
83 /* .bConfigurationValue =*/ 0,
84 /* .iConfiguration = */ 0,
85 /* .bmAttributes = */ 0x80,
86 /* .MaxPower = */ 14
87 },
88 NULL,
89 NULL
90};
91
92
93
94static PCVUSBDESCCONFIGEX vusbDevFindCfgDesc(PVUSBDEV pDev, int iCfg)
95{
96 if (iCfg == 0)
97 return &g_Config0;
98
99 for (unsigned i = 0; i < pDev->pDescCache->pDevice->bNumConfigurations; i++)
100 if (pDev->pDescCache->paConfigs[i].Core.bConfigurationValue == iCfg)
101 return &pDev->pDescCache->paConfigs[i];
102 return NULL;
103}
104
105static PVUSBINTERFACESTATE vusbDevFindIfState(PVUSBDEV pDev, int iIf)
106{
107 for (unsigned i = 0; i < pDev->pCurCfgDesc->Core.bNumInterfaces; i++)
108 if (pDev->paIfStates[i].pIf->paSettings[0].Core.bInterfaceNumber == iIf)
109 return &pDev->paIfStates[i];
110 return NULL;
111}
112
113static PCVUSBDESCINTERFACEEX vusbDevFindAltIfDesc(PCVUSBINTERFACESTATE pIfState, int iAlt)
114{
115 for (uint32_t i = 0; i < pIfState->pIf->cSettings; i++)
116 if (pIfState->pIf->paSettings[i].Core.bAlternateSetting == iAlt)
117 return &pIfState->pIf->paSettings[i];
118 return NULL;
119}
120
121void vusbDevMapEndpoint(PVUSBDEV pDev, PCVUSBDESCENDPOINTEX pEndPtDesc)
122{
123 uint8_t i8Addr = pEndPtDesc->Core.bEndpointAddress & 0xF;
124 PVUSBPIPE pPipe = &pDev->aPipes[i8Addr];
125 LogFlow(("vusbDevMapEndpoint: pDev=%p[%s] pEndPtDesc=%p{.bEndpointAddress=%#x, .bmAttributes=%#x} p=%p stage %s->SETUP\n",
126 pDev, pDev->pUsbIns->pszName, pEndPtDesc, pEndPtDesc->Core.bEndpointAddress, pEndPtDesc->Core.bmAttributes,
127 pPipe, g_apszCtlStates[pPipe->pCtrl ? pPipe->pCtrl->enmStage : 3]));
128
129 if ((pEndPtDesc->Core.bmAttributes & 0x3) == 0)
130 {
131 Log(("vusb: map message pipe on address %u\n", i8Addr));
132 pPipe->in = pEndPtDesc;
133 pPipe->out = pEndPtDesc;
134 }
135 else if (pEndPtDesc->Core.bEndpointAddress & 0x80)
136 {
137 Log(("vusb: map input pipe on address %u\n", i8Addr));
138 pPipe->in = pEndPtDesc;
139 }
140 else
141 {
142 Log(("vusb: map output pipe on address %u\n", i8Addr));
143 pPipe->out = pEndPtDesc;
144
145#if 0
146 if ((pEndPtDesc->Core.bmAttributes & 0x03) == 1)
147 {
148 int rc = vusbBufferedPipeCreate(pDev, pPipe, VUSBDIRECTION_OUT, pDev->pUsbIns->enmSpeed,
149 32 /* cLatencyMs*/, &pPipe->hBuffer);
150 if (RT_SUCCESS(rc))
151 LogRel(("VUSB: Created a buffered pipe for isochronous output endpoint\n"));
152 else
153 LogRel(("VUSB: Failed to create a buffered pipe for isochronous output endpoint with rc=%Rrc\n", rc));
154 }
155#endif
156 }
157
158 if (pPipe->pCtrl)
159 {
160 vusbMsgFreeExtraData(pPipe->pCtrl);
161 pPipe->pCtrl = NULL;
162 }
163}
164
165static void unmap_endpoint(PVUSBDEV pDev, PCVUSBDESCENDPOINTEX pEndPtDesc)
166{
167 uint8_t EndPt = pEndPtDesc->Core.bEndpointAddress & 0xF;
168 PVUSBPIPE pPipe = &pDev->aPipes[EndPt];
169 LogFlow(("unmap_endpoint: pDev=%p[%s] pEndPtDesc=%p{.bEndpointAddress=%#x, .bmAttributes=%#x} p=%p stage %s->SETUP\n",
170 pDev, pDev->pUsbIns->pszName, pEndPtDesc, pEndPtDesc->Core.bEndpointAddress, pEndPtDesc->Core.bmAttributes,
171 pPipe, g_apszCtlStates[pPipe->pCtrl ? pPipe->pCtrl->enmStage : 3]));
172
173 if ((pEndPtDesc->Core.bmAttributes & 0x3) == 0)
174 {
175 Log(("vusb: unmap MSG pipe from address %u (%#x)\n", EndPt, pEndPtDesc->Core.bEndpointAddress));
176 pPipe->in = NULL;
177 pPipe->out = NULL;
178 }
179 else if (pEndPtDesc->Core.bEndpointAddress & 0x80)
180 {
181 Log(("vusb: unmap IN pipe from address %u (%#x)\n", EndPt, pEndPtDesc->Core.bEndpointAddress));
182 pPipe->in = NULL;
183
184 /* Terminate the pipe buffer if created. */
185 if (pPipe->hBuffer)
186 {
187 vusbBufferedPipeDestroy(pPipe->hBuffer);
188 pPipe->hBuffer = NULL;
189 }
190 }
191 else
192 {
193 Log(("vusb: unmap OUT pipe from address %u (%#x)\n", EndPt, pEndPtDesc->Core.bEndpointAddress));
194 pPipe->out = NULL;
195
196 /* Terminate the pipe buffer if created. */
197 if (pPipe->hBuffer)
198 {
199 vusbBufferedPipeDestroy(pPipe->hBuffer);
200 pPipe->hBuffer = NULL;
201 }
202 }
203
204 if (pPipe->pCtrl)
205 {
206 vusbMsgFreeExtraData(pPipe->pCtrl);
207 pPipe->pCtrl = NULL;
208 }
209}
210
211static void map_interface(PVUSBDEV pDev, PCVUSBDESCINTERFACEEX pIfDesc)
212{
213 LogFlow(("map_interface: pDev=%p[%s] pIfDesc=%p:{.iInterface=%d, .bAlternateSetting=%d}\n",
214 pDev, pDev->pUsbIns->pszName, pIfDesc, pIfDesc->Core.iInterface, pIfDesc->Core.bAlternateSetting));
215
216 for (unsigned i = 0; i < pIfDesc->Core.bNumEndpoints; i++)
217 {
218 if ((pIfDesc->paEndpoints[i].Core.bEndpointAddress & 0xF) == VUSB_PIPE_DEFAULT)
219 Log(("vusb: Endpoint 0x%x on interface %u.%u tried to override the default message pipe!!!\n",
220 pIfDesc->paEndpoints[i].Core.bEndpointAddress, pIfDesc->Core.bInterfaceNumber, pIfDesc->Core.bAlternateSetting));
221 else
222 vusbDevMapEndpoint(pDev, &pIfDesc->paEndpoints[i]);
223 }
224}
225
226
227/**
228 * Worker that resets the pipe data on select config and detach.
229 *
230 * This leaves the critical section unmolested
231 *
232 * @param pPipe The pipe which data should be reset.
233 */
234static void vusbDevResetPipeData(PVUSBPIPE pPipe)
235{
236 vusbMsgFreeExtraData(pPipe->pCtrl);
237 pPipe->pCtrl = NULL;
238
239 if (pPipe->hBuffer)
240 {
241 vusbBufferedPipeDestroy(pPipe->hBuffer);
242 pPipe->hBuffer = NULL;
243 }
244
245 RT_ZERO(pPipe->in);
246 RT_ZERO(pPipe->out);
247 pPipe->async = 0;
248}
249
250
251bool vusbDevDoSelectConfig(PVUSBDEV pDev, PCVUSBDESCCONFIGEX pCfgDesc)
252{
253 LogFlow(("vusbDevDoSelectConfig: pDev=%p[%s] pCfgDesc=%p:{.iConfiguration=%d}\n",
254 pDev, pDev->pUsbIns->pszName, pCfgDesc, pCfgDesc->Core.iConfiguration));
255
256 /*
257 * Clean up all pipes and interfaces.
258 */
259 unsigned i;
260 for (i = 0; i < VUSB_PIPE_MAX; i++)
261 if (i != VUSB_PIPE_DEFAULT)
262 vusbDevResetPipeData(&pDev->aPipes[i]);
263 memset(pDev->paIfStates, 0, pCfgDesc->Core.bNumInterfaces * sizeof(pDev->paIfStates[0]));
264
265 /*
266 * Map in the default setting for every interface.
267 */
268 for (i = 0; i < pCfgDesc->Core.bNumInterfaces; i++)
269 {
270 PCVUSBINTERFACE pIf;
271 struct vusb_interface_state *pIfState;
272
273 pIf = &pCfgDesc->paIfs[i];
274 pIfState = &pDev->paIfStates[i];
275 pIfState->pIf = pIf;
276
277 /*
278 * Find the 0 setting, if it is not present we just use
279 * the lowest numbered one.
280 */
281 for (uint32_t j = 0; j < pIf->cSettings; j++)
282 {
283 if ( !pIfState->pCurIfDesc
284 || pIf->paSettings[j].Core.bAlternateSetting < pIfState->pCurIfDesc->Core.bAlternateSetting)
285 pIfState->pCurIfDesc = &pIf->paSettings[j];
286 if (pIfState->pCurIfDesc->Core.bAlternateSetting == 0)
287 break;
288 }
289
290 if (pIfState->pCurIfDesc)
291 map_interface(pDev, pIfState->pCurIfDesc);
292 }
293
294 pDev->pCurCfgDesc = pCfgDesc;
295
296 if (pCfgDesc->Core.bmAttributes & 0x40)
297 pDev->u16Status |= (1 << VUSB_DEV_SELF_POWERED);
298 else
299 pDev->u16Status &= ~(1 << VUSB_DEV_SELF_POWERED);
300
301 return true;
302}
303
304/**
305 * Standard device request: SET_CONFIGURATION
306 * @returns success indicator.
307 */
308static bool vusbDevStdReqSetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
309{
310 RT_NOREF(EndPt, pbBuf, pcbBuf);
311 unsigned iCfg = pSetup->wValue & 0xff;
312
313 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_DEVICE)
314 {
315 Log(("vusb: error: %s: SET_CONFIGURATION - invalid request (dir) !!!\n", pDev->pUsbIns->pszName));
316 return false;
317 }
318
319 /*
320 * Check that the device is in a valid state.
321 * (The caller has already checked that it's not being reset.)
322 */
323 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
324 if (enmState == VUSB_DEVICE_STATE_DEFAULT)
325 {
326 LogFlow(("vusbDevStdReqSetConfig: %s: default dev state !!?\n", pDev->pUsbIns->pszName));
327 return false;
328 }
329
330 PCVUSBDESCCONFIGEX pNewCfgDesc = vusbDevFindCfgDesc(pDev, iCfg);
331 if (!pNewCfgDesc)
332 {
333 Log(("vusb: error: %s: config %i not found !!!\n", pDev->pUsbIns->pszName, iCfg));
334 return false;
335 }
336
337 if (iCfg == 0)
338 vusbDevSetState(pDev, VUSB_DEVICE_STATE_ADDRESS);
339 else
340 vusbDevSetState(pDev, VUSB_DEVICE_STATE_CONFIGURED);
341 if (pDev->pUsbIns->pReg->pfnUsbSetConfiguration)
342 {
343 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbSetConfiguration, 5,
344 pDev->pUsbIns, pNewCfgDesc->Core.bConfigurationValue,
345 pDev->pCurCfgDesc, pDev->paIfStates, pNewCfgDesc);
346 if (RT_FAILURE(rc))
347 {
348 Log(("vusb: error: %s: failed to set config %i (%Rrc) !!!\n", pDev->pUsbIns->pszName, iCfg, rc));
349 return false;
350 }
351 }
352 Log(("vusb: %p[%s]: SET_CONFIGURATION: Selected config %u\n", pDev, pDev->pUsbIns->pszName, iCfg));
353 return vusbDevDoSelectConfig(pDev, pNewCfgDesc);
354}
355
356
357/**
358 * Standard device request: GET_CONFIGURATION
359 * @returns success indicator.
360 */
361static bool vusbDevStdReqGetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
362{
363 RT_NOREF(EndPt);
364 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_DEVICE)
365 {
366 Log(("vusb: error: %s: GET_CONFIGURATION - invalid request (dir) !!!\n", pDev->pUsbIns->pszName));
367 return false;
368 }
369
370 /*
371 * Check that the device is in a valid state.
372 * (The caller has already checked that it's not being reset.)
373 */
374 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
375 if ( enmState != VUSB_DEVICE_STATE_CONFIGURED
376 && enmState != VUSB_DEVICE_STATE_ADDRESS)
377 {
378 LogFlow(("vusbDevStdReqGetConfig: error: %s: invalid device state %d!!!\n", pDev->pUsbIns->pszName, enmState));
379 return false;
380 }
381
382 if (*pcbBuf < 1)
383 {
384 LogFlow(("vusbDevStdReqGetConfig: %s: no space for data!\n", pDev->pUsbIns->pszName));
385 return true;
386 }
387
388 uint8_t iCfg;
389 if (enmState == VUSB_DEVICE_STATE_ADDRESS)
390 iCfg = 0;
391 else
392 iCfg = pDev->pCurCfgDesc->Core.bConfigurationValue;
393
394 *pbBuf = iCfg;
395 *pcbBuf = 1;
396 LogFlow(("vusbDevStdReqGetConfig: %s: returns iCfg=%d\n", pDev->pUsbIns->pszName, iCfg));
397 return true;
398}
399
400/**
401 * Standard device request: GET_INTERFACE
402 * @returns success indicator.
403 */
404static bool vusbDevStdReqGetInterface(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
405{
406 RT_NOREF(EndPt);
407 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_INTERFACE)
408 {
409 Log(("vusb: error: %s: GET_INTERFACE - invalid request (dir) !!!\n", pDev->pUsbIns->pszName));
410 return false;
411 }
412
413 /*
414 * Check that the device is in a valid state.
415 * (The caller has already checked that it's not being reset.)
416 */
417 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
418 if (enmState != VUSB_DEVICE_STATE_CONFIGURED)
419 {
420 LogFlow(("vusbDevStdReqGetInterface: error: %s: invalid device state %d!!!\n", pDev->pUsbIns->pszName, enmState));
421 return false;
422 }
423
424 if (*pcbBuf < 1)
425 {
426 LogFlow(("vusbDevStdReqGetInterface: %s: no space for data!\n", pDev->pUsbIns->pszName));
427 return true;
428 }
429
430 for (unsigned i = 0; i < pDev->pCurCfgDesc->Core.bNumInterfaces; i++)
431 {
432 PCVUSBDESCINTERFACEEX pIfDesc = pDev->paIfStates[i].pCurIfDesc;
433 if ( pIfDesc
434 && pSetup->wIndex == pIfDesc->Core.bInterfaceNumber)
435 {
436 *pbBuf = pIfDesc->Core.bAlternateSetting;
437 *pcbBuf = 1;
438 Log(("vusb: %s: GET_INTERFACE: %u.%u\n", pDev->pUsbIns->pszName, pIfDesc->Core.bInterfaceNumber, *pbBuf));
439 return true;
440 }
441 }
442
443 Log(("vusb: error: %s: GET_INTERFACE - unknown iface %u !!!\n", pDev->pUsbIns->pszName, pSetup->wIndex));
444 return false;
445}
446
447/**
448 * Standard device request: SET_INTERFACE
449 * @returns success indicator.
450 */
451static bool vusbDevStdReqSetInterface(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
452{
453 RT_NOREF(EndPt, pbBuf, pcbBuf);
454 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_INTERFACE)
455 {
456 Log(("vusb: error: %s: SET_INTERFACE - invalid request (dir) !!!\n", pDev->pUsbIns->pszName));
457 return false;
458 }
459
460 /*
461 * Check that the device is in a valid state.
462 * (The caller has already checked that it's not being reset.)
463 */
464 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
465 if (enmState != VUSB_DEVICE_STATE_CONFIGURED)
466 {
467 LogFlow(("vusbDevStdReqSetInterface: error: %s: invalid device state %d !!!\n", pDev->pUsbIns->pszName, enmState));
468 return false;
469 }
470
471 /*
472 * Find the interface.
473 */
474 uint8_t iIf = pSetup->wIndex;
475 PVUSBINTERFACESTATE pIfState = vusbDevFindIfState(pDev, iIf);
476 if (!pIfState)
477 {
478 LogFlow(("vusbDevStdReqSetInterface: error: %s: couldn't find interface %u !!!\n", pDev->pUsbIns->pszName, iIf));
479 return false;
480 }
481 uint8_t iAlt = pSetup->wValue;
482 PCVUSBDESCINTERFACEEX pIfDesc = vusbDevFindAltIfDesc(pIfState, iAlt);
483 if (!pIfDesc)
484 {
485 LogFlow(("vusbDevStdReqSetInterface: error: %s: couldn't find alt interface %u.%u !!!\n", pDev->pUsbIns->pszName, iIf, iAlt));
486 return false;
487 }
488
489 if (pDev->pUsbIns->pReg->pfnUsbSetInterface)
490 {
491 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbSetInterface, 3, pDev->pUsbIns, iIf, iAlt);
492 if (RT_FAILURE(rc))
493 {
494 LogFlow(("vusbDevStdReqSetInterface: error: %s: couldn't find alt interface %u.%u (%Rrc)\n", pDev->pUsbIns->pszName, iIf, iAlt, rc));
495 return false;
496 }
497 }
498
499 for (unsigned i = 0; i < pIfState->pCurIfDesc->Core.bNumEndpoints; i++)
500 unmap_endpoint(pDev, &pIfState->pCurIfDesc->paEndpoints[i]);
501
502 Log(("vusb: SET_INTERFACE: Selected %u.%u\n", iIf, iAlt));
503
504 map_interface(pDev, pIfDesc);
505 pIfState->pCurIfDesc = pIfDesc;
506
507 return true;
508}
509
510/**
511 * Standard device request: SET_ADDRESS
512 * @returns success indicator.
513 */
514static bool vusbDevStdReqSetAddress(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
515{
516 RT_NOREF(EndPt, pbBuf, pcbBuf);
517 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_DEVICE)
518 {
519 Log(("vusb: error: %s: SET_ADDRESS - invalid request (dir) !!!\n", pDev->pUsbIns->pszName));
520 return false;
521 }
522
523 /*
524 * Check that the device is in a valid state.
525 * (The caller has already checked that it's not being reset.)
526 */
527 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
528 if ( enmState != VUSB_DEVICE_STATE_DEFAULT
529 && enmState != VUSB_DEVICE_STATE_ADDRESS)
530 {
531 LogFlow(("vusbDevStdReqSetAddress: error: %s: invalid device state %d !!!\n", pDev->pUsbIns->pszName, enmState));
532 return false;
533 }
534
535 pDev->u8NewAddress = pSetup->wValue;
536 return true;
537}
538
539/**
540 * Standard device request: CLEAR_FEATURE
541 * @returns success indicator.
542 *
543 * @remark This is only called for VUSB_TO_ENDPOINT && ep == 0 && wValue == ENDPOINT_HALT.
544 * All other cases of CLEAR_FEATURE is handled in the normal async/sync manner.
545 */
546static bool vusbDevStdReqClearFeature(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
547{
548 RT_NOREF(pbBuf, pcbBuf);
549 switch (pSetup->bmRequestType & VUSB_RECIP_MASK)
550 {
551 case VUSB_TO_DEVICE:
552 Log(("vusb: ClearFeature: dev(%u): selector=%u\n", pSetup->wIndex, pSetup->wValue));
553 break;
554 case VUSB_TO_INTERFACE:
555 Log(("vusb: ClearFeature: iface(%u): selector=%u\n", pSetup->wIndex, pSetup->wValue));
556 break;
557 case VUSB_TO_ENDPOINT:
558 Log(("vusb: ClearFeature: ep(%u): selector=%u\n", pSetup->wIndex, pSetup->wValue));
559 if ( !EndPt /* Default control pipe only */
560 && pSetup->wValue == 0 /* ENDPOINT_HALT */
561 && pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint)
562 {
563 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint,
564 2, pDev->pUsbIns, pSetup->wIndex);
565 return RT_SUCCESS(rc);
566 }
567 break;
568 default:
569 AssertMsgFailed(("VUSB_TO_OTHER!\n"));
570 break;
571 }
572
573 AssertMsgFailed(("Invalid safe check !!!\n"));
574 return false;
575}
576
577/**
578 * Standard device request: SET_FEATURE
579 * @returns success indicator.
580 */
581static bool vusbDevStdReqSetFeature(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
582{
583 RT_NOREF(pDev, EndPt, pbBuf, pcbBuf);
584 switch (pSetup->bmRequestType & VUSB_RECIP_MASK)
585 {
586 case VUSB_TO_DEVICE:
587 Log(("vusb: SetFeature: dev(%u): selector=%u\n",
588 pSetup->wIndex, pSetup->wValue));
589 break;
590 case VUSB_TO_INTERFACE:
591 Log(("vusb: SetFeature: if(%u): selector=%u\n",
592 pSetup->wIndex, pSetup->wValue));
593 break;
594 case VUSB_TO_ENDPOINT:
595 Log(("vusb: SetFeature: ep(%u): selector=%u\n",
596 pSetup->wIndex, pSetup->wValue));
597 break;
598 default:
599 AssertMsgFailed(("VUSB_TO_OTHER!\n"));
600 return false;
601 }
602 AssertMsgFailed(("This stuff is bogus\n"));
603 return false;
604}
605
606static bool vusbDevStdReqGetStatus(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
607{
608 RT_NOREF(EndPt);
609 if (*pcbBuf != 2)
610 {
611 LogFlow(("vusbDevStdReqGetStatus: %s: buffer is too small! (%d)\n", pDev->pUsbIns->pszName, *pcbBuf));
612 return false;
613 }
614
615 uint16_t u16Status;
616 switch (pSetup->bmRequestType & VUSB_RECIP_MASK)
617 {
618 case VUSB_TO_DEVICE:
619 u16Status = pDev->u16Status;
620 LogFlow(("vusbDevStdReqGetStatus: %s: device status %#x (%d)\n", pDev->pUsbIns->pszName, u16Status, u16Status));
621 break;
622 case VUSB_TO_INTERFACE:
623 u16Status = 0;
624 LogFlow(("vusbDevStdReqGetStatus: %s: bogus interface status request!!\n", pDev->pUsbIns->pszName));
625 break;
626 case VUSB_TO_ENDPOINT:
627 u16Status = 0;
628 LogFlow(("vusbDevStdReqGetStatus: %s: bogus endpoint status request!!\n", pDev->pUsbIns->pszName));
629 break;
630 default:
631 AssertMsgFailed(("VUSB_TO_OTHER!\n"));
632 return false;
633 }
634
635 *(uint16_t *)pbBuf = u16Status;
636 return true;
637}
638
639
640/**
641 * Finds a cached string.
642 *
643 * @returns Pointer to the cached string if found. NULL if not.
644 * @param paLanguages The languages to search.
645 * @param cLanguages The number of languages in the table.
646 * @param idLang The language ID.
647 * @param iString The string index.
648 */
649static PCPDMUSBDESCCACHESTRING FindCachedString(PCPDMUSBDESCCACHELANG paLanguages, unsigned cLanguages,
650 uint16_t idLang, uint8_t iString)
651{
652 /** @todo binary lookups! */
653 unsigned iCurLang = cLanguages;
654 while (iCurLang-- > 0)
655 if (paLanguages[iCurLang].idLang == idLang)
656 {
657 PCPDMUSBDESCCACHESTRING paStrings = paLanguages[iCurLang].paStrings;
658 unsigned iCurStr = paLanguages[iCurLang].cStrings;
659 while (iCurStr-- > 0)
660 if (paStrings[iCurStr].idx == iString)
661 return &paStrings[iCurStr];
662 break;
663 }
664 return NULL;
665}
666
667
668/** Macro for copying descriptor data. */
669#define COPY_DATA(pbDst, cbLeft, pvSrc, cbSrc) \
670 do { \
671 uint32_t cbSrc_ = cbSrc; \
672 uint32_t cbCopy = RT_MIN(cbLeft, cbSrc_); \
673 if (cbCopy) \
674 memcpy(pbBuf, pvSrc, cbCopy); \
675 cbLeft -= cbCopy; \
676 if (!cbLeft) \
677 return; \
678 pbBuf += cbCopy; \
679 } while (0)
680
681/**
682 * Internal function for reading the language IDs.
683 */
684static void ReadCachedStringDesc(PCPDMUSBDESCCACHESTRING pString, uint8_t *pbBuf, uint32_t *pcbBuf)
685{
686 uint32_t cbLeft = *pcbBuf;
687
688 RTUTF16 wsz[128]; /* 128-1 => bLength=0xff */
689 PRTUTF16 pwsz = wsz;
690 size_t cwc;
691 int rc = RTStrToUtf16Ex(pString->psz, RT_ELEMENTS(wsz) - 1, &pwsz, RT_ELEMENTS(wsz), &cwc);
692 if (RT_FAILURE(rc))
693 {
694 AssertRC(rc);
695 wsz[0] = 'e';
696 wsz[1] = 'r';
697 wsz[2] = 'r';
698 cwc = 3;
699 }
700
701 VUSBDESCSTRING StringDesc;
702 StringDesc.bLength = (uint8_t)(sizeof(StringDesc) + cwc * sizeof(RTUTF16));
703 StringDesc.bDescriptorType = VUSB_DT_STRING;
704 COPY_DATA(pbBuf, cbLeft, &StringDesc, sizeof(StringDesc));
705 COPY_DATA(pbBuf, cbLeft, wsz, (uint32_t)cwc * sizeof(RTUTF16));
706
707 /* updated the size of the output buffer. */
708 *pcbBuf -= cbLeft;
709}
710
711
712/**
713 * Internal function for reading the language IDs.
714 */
715static void ReadCachedLangIdDesc(PCPDMUSBDESCCACHELANG paLanguages, unsigned cLanguages,
716 uint8_t *pbBuf, uint32_t *pcbBuf)
717{
718 uint32_t cbLeft = *pcbBuf;
719
720 VUSBDESCLANGID LangIdDesc;
721 size_t cbDesc = sizeof(LangIdDesc) + cLanguages * sizeof(paLanguages[0].idLang);
722 LangIdDesc.bLength = (uint8_t)RT_MIN(0xff, cbDesc);
723 LangIdDesc.bDescriptorType = VUSB_DT_STRING;
724 COPY_DATA(pbBuf, cbLeft, &LangIdDesc, sizeof(LangIdDesc));
725
726 unsigned iLanguage = cLanguages;
727 while (iLanguage-- > 0)
728 COPY_DATA(pbBuf, cbLeft, &paLanguages[iLanguage].idLang, sizeof(paLanguages[iLanguage].idLang));
729
730 /* updated the size of the output buffer. */
731 *pcbBuf -= cbLeft;
732}
733
734
735/**
736 * Internal function which performs a descriptor read on the cached descriptors.
737 */
738static void ReadCachedConfigDesc(PCVUSBDESCCONFIGEX pCfgDesc, uint8_t *pbBuf, uint32_t *pcbBuf)
739{
740 uint32_t cbLeft = *pcbBuf;
741
742/** @todo See @bugref{2693} */
743 /*
744 * Make a copy of the config descriptor and calculate the wTotalLength field.
745 */
746 VUSBDESCCONFIG CfgDesc;
747 memcpy(&CfgDesc, pCfgDesc, VUSB_DT_CONFIG_MIN_LEN);
748 uint32_t cbTotal = pCfgDesc->Core.bLength;
749 for (unsigned i = 0; i < pCfgDesc->Core.bNumInterfaces; i++)
750 {
751 PCVUSBINTERFACE pIf = &pCfgDesc->paIfs[i];
752 for (uint32_t j = 0; j < pIf->cSettings; j++)
753 {
754 cbTotal += pIf->paSettings[j].cbIAD;
755 cbTotal += pIf->paSettings[j].Core.bLength;
756 cbTotal += pIf->paSettings[j].cbClass;
757 for (unsigned k = 0; k < pIf->paSettings[j].Core.bNumEndpoints; k++)
758 {
759 cbTotal += pIf->paSettings[j].paEndpoints[k].Core.bLength;
760 cbTotal += pIf->paSettings[j].paEndpoints[k].cbSsepc;
761 cbTotal += pIf->paSettings[j].paEndpoints[k].cbClass;
762 }
763 }
764 }
765 CfgDesc.wTotalLength = RT_H2LE_U16(cbTotal);
766
767 /*
768 * Copy the config descriptor
769 */
770 COPY_DATA(pbBuf, cbLeft, &CfgDesc, VUSB_DT_CONFIG_MIN_LEN);
771 COPY_DATA(pbBuf, cbLeft, pCfgDesc->pvMore, pCfgDesc->Core.bLength - VUSB_DT_CONFIG_MIN_LEN);
772
773 /*
774 * Copy out all the interfaces for this configuration
775 */
776 for (unsigned i = 0; i < pCfgDesc->Core.bNumInterfaces; i++)
777 {
778 PCVUSBINTERFACE pIf = &pCfgDesc->paIfs[i];
779 for (uint32_t j = 0; j < pIf->cSettings; j++)
780 {
781 PCVUSBDESCINTERFACEEX pIfDesc = &pIf->paSettings[j];
782
783 COPY_DATA(pbBuf, cbLeft, pIfDesc->pIAD, pIfDesc->cbIAD);
784 COPY_DATA(pbBuf, cbLeft, pIfDesc, VUSB_DT_INTERFACE_MIN_LEN);
785 COPY_DATA(pbBuf, cbLeft, pIfDesc->pvMore, pIfDesc->Core.bLength - VUSB_DT_INTERFACE_MIN_LEN);
786 COPY_DATA(pbBuf, cbLeft, pIfDesc->pvClass, pIfDesc->cbClass);
787
788 /*
789 * Copy out all the endpoints for this interface
790 */
791 for (unsigned k = 0; k < pIfDesc->Core.bNumEndpoints; k++)
792 {
793 VUSBDESCENDPOINT EndPtDesc;
794 memcpy(&EndPtDesc, &pIfDesc->paEndpoints[k], VUSB_DT_ENDPOINT_MIN_LEN);
795 EndPtDesc.wMaxPacketSize = RT_H2LE_U16(EndPtDesc.wMaxPacketSize);
796
797 COPY_DATA(pbBuf, cbLeft, &EndPtDesc, VUSB_DT_ENDPOINT_MIN_LEN);
798 COPY_DATA(pbBuf, cbLeft, pIfDesc->paEndpoints[k].pvMore, EndPtDesc.bLength - VUSB_DT_ENDPOINT_MIN_LEN);
799 COPY_DATA(pbBuf, cbLeft, pIfDesc->paEndpoints[k].pvSsepc, pIfDesc->paEndpoints[k].cbSsepc);
800 COPY_DATA(pbBuf, cbLeft, pIfDesc->paEndpoints[k].pvClass, pIfDesc->paEndpoints[k].cbClass);
801 }
802 }
803 }
804
805 /* updated the size of the output buffer. */
806 *pcbBuf -= cbLeft;
807}
808
809/**
810 * Internal function which performs a descriptor read on the cached descriptors.
811 */
812static void ReadCachedDeviceDesc(PCVUSBDESCDEVICE pDevDesc, uint8_t *pbBuf, uint32_t *pcbBuf)
813{
814 uint32_t cbLeft = *pcbBuf;
815
816 /*
817 * Duplicate the device description and update some fields we keep in cpu type.
818 */
819 Assert(sizeof(VUSBDESCDEVICE) == 18);
820 VUSBDESCDEVICE DevDesc = *pDevDesc;
821 DevDesc.bcdUSB = RT_H2LE_U16(DevDesc.bcdUSB);
822 DevDesc.idVendor = RT_H2LE_U16(DevDesc.idVendor);
823 DevDesc.idProduct = RT_H2LE_U16(DevDesc.idProduct);
824 DevDesc.bcdDevice = RT_H2LE_U16(DevDesc.bcdDevice);
825
826 COPY_DATA(pbBuf, cbLeft, &DevDesc, sizeof(DevDesc));
827 COPY_DATA(pbBuf, cbLeft, pDevDesc + 1, pDevDesc->bLength - sizeof(DevDesc));
828
829 /* updated the size of the output buffer. */
830 *pcbBuf -= cbLeft;
831}
832
833#undef COPY_DATA
834
835/**
836 * Standard device request: GET_DESCRIPTOR
837 * @returns success indicator.
838 * @remark not really used yet as we consider GET_DESCRIPTOR 'safe'.
839 */
840static bool vusbDevStdReqGetDescriptor(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
841{
842 RT_NOREF(EndPt);
843 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) == VUSB_TO_DEVICE)
844 {
845 switch (pSetup->wValue >> 8)
846 {
847 case VUSB_DT_DEVICE:
848 ReadCachedDeviceDesc(pDev->pDescCache->pDevice, pbBuf, pcbBuf);
849 LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of device descriptors\n", pDev->pUsbIns->pszName, *pcbBuf));
850 return true;
851
852 case VUSB_DT_CONFIG:
853 {
854 unsigned int iIndex = (pSetup->wValue & 0xff);
855 if (iIndex >= pDev->pDescCache->pDevice->bNumConfigurations)
856 {
857 LogFlow(("vusbDevStdReqGetDescriptor: %s: iIndex=%p >= bNumConfigurations=%d !!!\n",
858 pDev->pUsbIns->pszName, iIndex, pDev->pDescCache->pDevice->bNumConfigurations));
859 return false;
860 }
861 ReadCachedConfigDesc(&pDev->pDescCache->paConfigs[iIndex], pbBuf, pcbBuf);
862 LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of config descriptors\n", pDev->pUsbIns->pszName, *pcbBuf));
863 return true;
864 }
865
866 case VUSB_DT_STRING:
867 {
868 if (pSetup->wIndex == 0)
869 {
870 ReadCachedLangIdDesc(pDev->pDescCache->paLanguages, pDev->pDescCache->cLanguages, pbBuf, pcbBuf);
871 LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of language ID (string) descriptors\n", pDev->pUsbIns->pszName, *pcbBuf));
872 return true;
873 }
874 PCPDMUSBDESCCACHESTRING pString;
875 pString = FindCachedString(pDev->pDescCache->paLanguages, pDev->pDescCache->cLanguages,
876 pSetup->wIndex, pSetup->wValue & 0xff);
877 if (pString)
878 {
879 ReadCachedStringDesc(pString, pbBuf, pcbBuf);
880 LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of string descriptors \"%s\"\n",
881 pDev->pUsbIns->pszName, *pcbBuf, pString->psz));
882 return true;
883 }
884 break;
885 }
886
887 default:
888 break;
889 }
890 }
891 Log(("vusb: %s: warning: unknown descriptor: type=%u descidx=%u lang=%u len=%u!!!\n",
892 pDev->pUsbIns->pszName, pSetup->wValue >> 8, pSetup->wValue & 0xff, pSetup->wIndex, pSetup->wLength));
893 return false;
894}
895
896
897/**
898 * Service the standard USB requests.
899 *
900 * Devices may call this from controlmsg() if you want vusb core to handle your standard
901 * request, it's not necessary - you could handle them manually
902 *
903 * @param pDev The device.
904 * @param EndPoint The endpoint.
905 * @param pSetup Pointer to the setup request structure.
906 * @param pvBuf Buffer?
907 * @param pcbBuf ?
908 */
909bool vusbDevStandardRequest(PVUSBDEV pDev, int EndPoint, PVUSBSETUP pSetup, void *pvBuf, uint32_t *pcbBuf)
910{
911 static bool (* const s_apfnStdReq[VUSB_REQ_MAX])(PVUSBDEV, int, PVUSBSETUP, uint8_t *, uint32_t *) =
912 {
913 vusbDevStdReqGetStatus,
914 vusbDevStdReqClearFeature,
915 NULL,
916 vusbDevStdReqSetFeature,
917 NULL,
918 vusbDevStdReqSetAddress,
919 vusbDevStdReqGetDescriptor,
920 NULL,
921 vusbDevStdReqGetConfig,
922 vusbDevStdReqSetConfig,
923 vusbDevStdReqGetInterface,
924 vusbDevStdReqSetInterface,
925 NULL /* for iso */
926 };
927
928 /*
929 * Check that the device is in a valid state.
930 */
931 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
932 if (enmState == VUSB_DEVICE_STATE_RESET)
933 {
934 LogRel(("VUSB: %s: standard control message ignored, the device is resetting\n", pDev->pUsbIns->pszName));
935 return false;
936 }
937
938 /*
939 * Do the request if it's one we want to deal with.
940 */
941 if ( pSetup->bRequest >= VUSB_REQ_MAX
942 || !s_apfnStdReq[pSetup->bRequest])
943 {
944 Log(("vusb: warning: standard req not implemented: message %u: val=%u idx=%u len=%u !!!\n",
945 pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
946 return false;
947 }
948
949 return s_apfnStdReq[pSetup->bRequest](pDev, EndPoint, pSetup, (uint8_t *)pvBuf, pcbBuf);
950}
951
952
953/**
954 * Add a device to the address hash
955 */
956static void vusbDevAddressHash(PVUSBDEV pDev)
957{
958 if (pDev->u8Address == VUSB_INVALID_ADDRESS)
959 return;
960 uint8_t u8Hash = vusbHashAddress(pDev->u8Address);
961 pDev->pNextHash = pDev->pHub->pRootHub->apAddrHash[u8Hash];
962 pDev->pHub->pRootHub->apAddrHash[u8Hash] = pDev;
963}
964
965/**
966 * Remove a device from the address hash
967 */
968static void vusbDevAddressUnHash(PVUSBDEV pDev)
969{
970 if (pDev->u8Address == VUSB_INVALID_ADDRESS)
971 return;
972
973 uint8_t u8Hash = vusbHashAddress(pDev->u8Address);
974 pDev->u8Address = VUSB_INVALID_ADDRESS;
975 pDev->u8NewAddress = VUSB_INVALID_ADDRESS;
976
977 RTCritSectEnter(&pDev->pHub->pRootHub->CritSectDevices);
978 PVUSBDEV pCur = pDev->pHub->pRootHub->apAddrHash[u8Hash];
979 if (pCur == pDev)
980 {
981 /* special case, we're at the head */
982 pDev->pHub->pRootHub->apAddrHash[u8Hash] = pDev->pNextHash;
983 pDev->pNextHash = NULL;
984 }
985 else
986 {
987 /* search the list */
988 PVUSBDEV pPrev;
989 for (pPrev = pCur, pCur = pCur->pNextHash;
990 pCur;
991 pPrev = pCur, pCur = pCur->pNextHash)
992 {
993 if (pCur == pDev)
994 {
995 pPrev->pNextHash = pCur->pNextHash;
996 pDev->pNextHash = NULL;
997 break;
998 }
999 }
1000 }
1001 RTCritSectLeave(&pDev->pHub->pRootHub->CritSectDevices);
1002}
1003
1004/**
1005 * Sets the address of a device.
1006 *
1007 * Called by status_completion() and vusbDevResetWorker().
1008 */
1009void vusbDevSetAddress(PVUSBDEV pDev, uint8_t u8Address)
1010{
1011 LogFlow(("vusbDevSetAddress: pDev=%p[%s]/%i u8Address=%#x\n",
1012 pDev, pDev->pUsbIns->pszName, pDev->i16Port, u8Address));
1013
1014 /*
1015 * Check that the device is in a valid state.
1016 */
1017 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
1018 VUSBDEV_ASSERT_VALID_STATE(enmState);
1019 if ( enmState == VUSB_DEVICE_STATE_ATTACHED
1020 || enmState == VUSB_DEVICE_STATE_DETACHED)
1021 {
1022 LogFlow(("vusbDevSetAddress: %s: fails because %d < POWERED\n", pDev->pUsbIns->pszName, pDev->enmState));
1023 return;
1024 }
1025 if (enmState == VUSB_DEVICE_STATE_RESET)
1026 {
1027 LogRel(("VUSB: %s: set address ignored, the device is resetting\n", pDev->pUsbIns->pszName));
1028 return;
1029 }
1030
1031 /*
1032 * Ok, get on with it.
1033 */
1034 if (pDev->u8Address == u8Address)
1035 return;
1036
1037 PVUSBROOTHUB pRh = vusbDevGetRh(pDev);
1038 AssertPtrReturnVoid(pRh);
1039 if (pDev->u8Address == VUSB_DEFAULT_ADDRESS)
1040 pRh->pDefaultAddress = NULL;
1041
1042 vusbDevAddressUnHash(pDev);
1043
1044 if (u8Address == VUSB_DEFAULT_ADDRESS)
1045 {
1046 if (pRh->pDefaultAddress != NULL)
1047 {
1048 vusbDevAddressUnHash(pRh->pDefaultAddress);
1049 vusbDevSetStateCmp(pRh->pDefaultAddress, VUSB_DEVICE_STATE_POWERED, VUSB_DEVICE_STATE_DEFAULT);
1050 Log(("2 DEFAULT ADDRS\n"));
1051 }
1052
1053 pRh->pDefaultAddress = pDev;
1054 vusbDevSetState(pDev, VUSB_DEVICE_STATE_DEFAULT);
1055 }
1056 else
1057 vusbDevSetState(pDev, VUSB_DEVICE_STATE_ADDRESS);
1058
1059 pDev->u8Address = u8Address;
1060 vusbDevAddressHash(pDev);
1061
1062 Log(("vusb: %p[%s]/%i: Assigned address %u\n",
1063 pDev, pDev->pUsbIns->pszName, pDev->i16Port, u8Address));
1064}
1065
1066
1067static DECLCALLBACK(int) vusbDevCancelAllUrbsWorker(PVUSBDEV pDev, bool fDetaching)
1068{
1069 /*
1070 * Iterate the URBs and cancel them.
1071 */
1072 PVUSBURBVUSB pVUsbUrb, pVUsbUrbNext;
1073 RTListForEachSafe(&pDev->LstAsyncUrbs, pVUsbUrb, pVUsbUrbNext, VUSBURBVUSBINT, NdLst)
1074 {
1075 PVUSBURB pUrb = pVUsbUrb->pUrb;
1076
1077 Assert(pUrb->pVUsb->pDev == pDev);
1078
1079 LogFlow(("%s: vusbDevCancelAllUrbs: CANCELING URB\n", pUrb->pszDesc));
1080 int rc = vusbUrbCancelWorker(pUrb, CANCELMODE_FAIL);
1081 AssertRC(rc);
1082 }
1083
1084 /*
1085 * Reap any URBs which became ripe during cancel now.
1086 */
1087 RTCritSectEnter(&pDev->CritSectAsyncUrbs);
1088 unsigned cReaped;
1089 do
1090 {
1091 cReaped = 0;
1092 pVUsbUrb = RTListGetFirst(&pDev->LstAsyncUrbs, VUSBURBVUSBINT, NdLst);
1093 while (pVUsbUrb)
1094 {
1095 PVUSBURBVUSB pNext = RTListGetNext(&pDev->LstAsyncUrbs, pVUsbUrb, VUSBURBVUSBINT, NdLst);
1096 PVUSBURB pUrb = pVUsbUrb->pUrb;
1097 Assert(pUrb->pVUsb->pDev == pDev);
1098
1099 PVUSBURB pRipe = NULL;
1100 if (pUrb->enmState == VUSBURBSTATE_REAPED)
1101 pRipe = pUrb;
1102 else if (pUrb->enmState == VUSBURBSTATE_CANCELLED)
1103#ifdef RT_OS_WINDOWS /** @todo Windows doesn't do cancelling, thus this kludge to prevent really bad
1104 * things from happening if we leave a pending URB behinds. */
1105 pRipe = pDev->pUsbIns->pReg->pfnUrbReap(pDev->pUsbIns, fDetaching ? 1500 : 0 /*ms*/);
1106#else
1107 pRipe = pDev->pUsbIns->pReg->pfnUrbReap(pDev->pUsbIns, fDetaching ? 10 : 0 /*ms*/);
1108#endif
1109 else
1110 AssertMsgFailed(("pUrb=%p enmState=%d\n", pUrb, pUrb->enmState));
1111 if (pRipe)
1112 {
1113 if ( pNext
1114 && pRipe == pNext->pUrb)
1115 pNext = RTListGetNext(&pDev->LstAsyncUrbs, pNext, VUSBURBVUSBINT, NdLst);
1116 vusbUrbRipe(pRipe);
1117 cReaped++;
1118 }
1119
1120 pVUsbUrb = pNext;
1121 }
1122 } while (cReaped > 0);
1123
1124 /*
1125 * If we're detaching, we'll have to orphan any leftover URBs.
1126 */
1127 if (fDetaching)
1128 {
1129 RTListForEachSafe(&pDev->LstAsyncUrbs, pVUsbUrb, pVUsbUrbNext, VUSBURBVUSBINT, NdLst)
1130 {
1131 PVUSBURB pUrb = pVUsbUrb->pUrb;
1132 Assert(pUrb->pVUsb->pDev == pDev);
1133
1134 AssertMsgFailed(("%s: Leaking left over URB! state=%d pDev=%p[%s]\n",
1135 pUrb->pszDesc, pUrb->enmState, pDev, pDev->pUsbIns->pszName));
1136 vusbUrbUnlink(pUrb);
1137 /* Unlink isn't enough, because boundary timer and detaching will try to reap it.
1138 * It was tested with MSD & iphone attachment to vSMP guest, if
1139 * it breaks anything, please add comment here, why we should unlink only.
1140 */
1141 pUrb->pVUsb->pfnFree(pUrb);
1142 }
1143 }
1144 RTCritSectLeave(&pDev->CritSectAsyncUrbs);
1145 return VINF_SUCCESS;
1146}
1147
1148/**
1149 * Cancels and completes (with CRC failure) all async URBs pending
1150 * on a device. This is typically done as part of a reset and
1151 * before detaching a device.
1152 *
1153 * @returns nothing.
1154 * @param pDev The VUSB device instance.
1155 * @param fDetaching If set, we will unconditionally unlink (and leak)
1156 * any URBs which isn't reaped.
1157 */
1158DECLHIDDEN(void) vusbDevCancelAllUrbs(PVUSBDEV pDev, bool fDetaching)
1159{
1160 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)vusbDevCancelAllUrbsWorker, 2, pDev, fDetaching);
1161 AssertRC(rc);
1162}
1163
1164
1165static DECLCALLBACK(int) vusbDevUrbIoThread(RTTHREAD hThread, void *pvUser)
1166{
1167 PVUSBDEV pDev = (PVUSBDEV)pvUser;
1168
1169 /* Notify the starter that we are up and running. */
1170 RTThreadUserSignal(hThread);
1171
1172 LogFlowFunc(("Entering work loop\n"));
1173
1174 while (!ASMAtomicReadBool(&pDev->fTerminate))
1175 {
1176 if (vusbDevGetState(pDev) != VUSB_DEVICE_STATE_RESET)
1177 vusbUrbDoReapAsyncDev(pDev, RT_INDEFINITE_WAIT);
1178
1179 /* Process any URBs waiting to be cancelled first. */
1180 int rc = RTReqQueueProcess(pDev->hReqQueueSync, 0); /* Don't wait if there is nothing to do. */
1181 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT); NOREF(rc);
1182 }
1183
1184 return VINF_SUCCESS;
1185}
1186
1187int vusbDevUrbIoThreadWakeup(PVUSBDEV pDev)
1188{
1189 ASMAtomicXchgBool(&pDev->fWokenUp, true);
1190 return pDev->pUsbIns->pReg->pfnWakeup(pDev->pUsbIns);
1191}
1192
1193/**
1194 * Create the URB I/O thread.
1195 *
1196 * @returns VBox status code.
1197 * @param pDev The VUSB device.
1198 */
1199int vusbDevUrbIoThreadCreate(PVUSBDEV pDev)
1200{
1201 int rc = VINF_SUCCESS;
1202
1203 ASMAtomicXchgBool(&pDev->fTerminate, false);
1204 rc = RTThreadCreateF(&pDev->hUrbIoThread, vusbDevUrbIoThread, pDev, 0, RTTHREADTYPE_IO,
1205 RTTHREADFLAGS_WAITABLE, "USBDevIo-%d", pDev->i16Port);
1206 if (RT_SUCCESS(rc))
1207 {
1208 /* Wait for it to become active. */
1209 rc = RTThreadUserWait(pDev->hUrbIoThread, RT_INDEFINITE_WAIT);
1210 }
1211
1212 return rc;
1213}
1214
1215/**
1216 * Destro the URB I/O thread.
1217 *
1218 * @returns VBox status code.
1219 * @param pDev The VUSB device.
1220 */
1221int vusbDevUrbIoThreadDestroy(PVUSBDEV pDev)
1222{
1223 int rc = VINF_SUCCESS;
1224 int rcThread = VINF_SUCCESS;
1225
1226 ASMAtomicXchgBool(&pDev->fTerminate, true);
1227 vusbDevUrbIoThreadWakeup(pDev);
1228
1229 rc = RTThreadWait(pDev->hUrbIoThread, RT_INDEFINITE_WAIT, &rcThread);
1230 if (RT_SUCCESS(rc))
1231 rc = rcThread;
1232
1233 pDev->hUrbIoThread = NIL_RTTHREAD;
1234
1235 return rc;
1236}
1237
1238
1239/**
1240 * Detaches a device from the hub it's attached to.
1241 *
1242 * @returns VBox status code.
1243 * @param pDev The device to detach.
1244 *
1245 * @remark This can be called in any state but reset.
1246 */
1247int vusbDevDetach(PVUSBDEV pDev)
1248{
1249 LogFlow(("vusbDevDetach: pDev=%p[%s] enmState=%#x\n", pDev, pDev->pUsbIns->pszName, pDev->enmState));
1250 VUSBDEV_ASSERT_VALID_STATE(pDev->enmState);
1251 Assert(pDev->enmState != VUSB_DEVICE_STATE_RESET);
1252
1253 vusbDevCancelAllUrbs(pDev, true);
1254 vusbDevAddressUnHash(pDev);
1255
1256 PVUSBROOTHUB pRh = vusbDevGetRh(pDev);
1257 if (!pRh)
1258 AssertMsgFailedReturn(("Not attached!\n"), VERR_VUSB_DEVICE_NOT_ATTACHED);
1259 if (pRh->pDefaultAddress == pDev)
1260 pRh->pDefaultAddress = NULL;
1261
1262 pDev->pHub->pOps->pfnDetach(pDev->pHub, pDev);
1263 pDev->i16Port = -1;
1264 vusbDevSetState(pDev, VUSB_DEVICE_STATE_DETACHED);
1265 pDev->pHub = NULL;
1266
1267 /* Remove the configuration */
1268 pDev->pCurCfgDesc = NULL;
1269 for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
1270 vusbDevResetPipeData(&pDev->aPipes[i]);
1271 return VINF_SUCCESS;
1272}
1273
1274
1275/**
1276 * Destroys a device, detaching it from the hub if necessary.
1277 *
1278 * @param pDev The device.
1279 * @thread any.
1280 */
1281void vusbDevDestroy(PVUSBDEV pDev)
1282{
1283 LogFlow(("vusbDevDestroy: pDev=%p[%s] enmState=%d\n", pDev, pDev->pUsbIns->pszName, pDev->enmState));
1284
1285 RTMemFree(pDev->paIfStates);
1286 TMR3TimerDestroy(pDev->pResetTimer);
1287 pDev->pResetTimer = NULL;
1288 for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
1289 {
1290 Assert(pDev->aPipes[i].pCtrl == NULL);
1291 RTCritSectDelete(&pDev->aPipes[i].CritSectCtrl);
1292 }
1293
1294 /*
1295 * Destroy I/O thread and request queue last because they might still be used
1296 * when cancelling URBs.
1297 */
1298 vusbDevUrbIoThreadDestroy(pDev);
1299
1300 int rc = RTReqQueueDestroy(pDev->hReqQueueSync);
1301 AssertRC(rc);
1302
1303 if (pDev->hSniffer != VUSBSNIFFER_NIL)
1304 VUSBSnifferDestroy(pDev->hSniffer);
1305
1306 vusbUrbPoolDestroy(&pDev->UrbPool);
1307
1308 RTCritSectDelete(&pDev->CritSectAsyncUrbs);
1309 /* Not using vusbDevSetState() deliberately here because it would assert on the state. */
1310 pDev->enmState = VUSB_DEVICE_STATE_DESTROYED;
1311 pDev->pUsbIns->pvVUsbDev2 = NULL;
1312 RTMemFree(pDev);
1313}
1314
1315
1316/* -=-=-=-=-=- VUSBIDEVICE methods -=-=-=-=-=- */
1317
1318
1319/**
1320 * The actual reset has been done, do completion on EMT.
1321 *
1322 * There are several things we have to do now, like set default
1323 * config and address, and cleanup the state of control pipes.
1324 *
1325 * It's possible that the device has a delayed destroy request
1326 * pending when we get here. This can happen for async resetting.
1327 * We deal with it here, since we're now executing on the EMT
1328 * thread and the destruction will be properly serialized now.
1329 *
1330 * @param pDev The device that is being reset.
1331 * @param rc The vusbDevResetWorker return code.
1332 * @param pfnDone The done callback specified by the caller of vusbDevReset().
1333 * @param pvUser The user argument for the callback.
1334 */
1335static void vusbDevResetDone(PVUSBDEV pDev, int rc, PFNVUSBRESETDONE pfnDone, void *pvUser)
1336{
1337 VUSBDEV_ASSERT_VALID_STATE(pDev->enmState);
1338 Assert(pDev->enmState == VUSB_DEVICE_STATE_RESET);
1339
1340 /*
1341 * Do control pipe cleanup regardless of state and result.
1342 */
1343 for (unsigned i = 0; i < VUSB_PIPE_MAX; i++)
1344 if (pDev->aPipes[i].pCtrl)
1345 vusbMsgResetExtraData(pDev->aPipes[i].pCtrl);
1346
1347 /*
1348 * Switch to the default state.
1349 */
1350 vusbDevSetState(pDev, VUSB_DEVICE_STATE_DEFAULT);
1351 pDev->u16Status = 0;
1352 vusbDevDoSelectConfig(pDev, &g_Config0);
1353 if (!vusbDevIsRh(pDev))
1354 vusbDevSetAddress(pDev, VUSB_DEFAULT_ADDRESS);
1355 if (pfnDone)
1356 pfnDone(&pDev->IDevice, rc, pvUser);
1357}
1358
1359
1360/**
1361 * Timer callback for doing reset completion.
1362 *
1363 * @param pUsbIns The USB device instance.
1364 * @param pTimer The timer instance.
1365 * @param pvUser The VUSB device data.
1366 * @thread EMT
1367 */
1368static DECLCALLBACK(void) vusbDevResetDoneTimer(PPDMUSBINS pUsbIns, PTMTIMER pTimer, void *pvUser)
1369{
1370 RT_NOREF(pUsbIns, pTimer);
1371 PVUSBDEV pDev = (PVUSBDEV)pvUser;
1372 PVUSBRESETARGS pArgs = (PVUSBRESETARGS)pDev->pvArgs;
1373 Assert(pDev->pUsbIns == pUsbIns);
1374
1375 AssertPtr(pArgs);
1376
1377 /*
1378 * Reset-done processing and cleanup.
1379 */
1380 pDev->pvArgs = NULL;
1381 vusbDevResetDone(pDev, pArgs->rc, pArgs->pfnDone, pArgs->pvUser);
1382 RTMemFree(pArgs);
1383}
1384
1385
1386/**
1387 * Perform the actual reset.
1388 *
1389 * @thread EMT or a VUSB reset thread.
1390 */
1391static int vusbDevResetWorker(PVUSBDEV pDev, bool fResetOnLinux, bool fUseTimer, PVUSBRESETARGS pArgs)
1392{
1393 int rc = VINF_SUCCESS;
1394 uint64_t u64EndTS = TMTimerGet(pDev->pResetTimer) + TMTimerFromMilli(pDev->pResetTimer, 10);
1395
1396 if (pDev->pUsbIns->pReg->pfnUsbReset)
1397 rc = pDev->pUsbIns->pReg->pfnUsbReset(pDev->pUsbIns, fResetOnLinux);
1398
1399 if (pArgs)
1400 {
1401 pArgs->rc = rc;
1402 rc = VINF_SUCCESS;
1403 }
1404
1405 if (fUseTimer)
1406 {
1407 /*
1408 * We use a timer to communicate the result back to EMT.
1409 * This avoids suspend + poweroff issues, and it should give
1410 * us more accurate scheduling than making this thread sleep.
1411 */
1412 int rc2 = TMTimerSet(pDev->pResetTimer, u64EndTS);
1413 AssertReleaseRC(rc2);
1414 }
1415
1416 LogFlow(("vusbDevResetWorker: %s: returns %Rrc\n", pDev->pUsbIns->pszName, rc));
1417 return rc;
1418}
1419
1420
1421/**
1422 * Resets a device.
1423 *
1424 * Since a device reset shall take at least 10ms from the guest point of view,
1425 * it must be performed asynchronously. We create a thread which performs this
1426 * operation and ensures it will take at least 10ms.
1427 *
1428 * At times - like init - a synchronous reset is required, this can be done
1429 * by passing NULL for pfnDone.
1430 *
1431 * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state.
1432 * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful,
1433 * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed.
1434 *
1435 * @returns VBox status code.
1436 *
1437 * @param pDevice Pointer to the VUSB device interface.
1438 * @param fResetOnLinux Whether it's safe to reset the device(s) on a linux
1439 * host system. See discussion of logical reconnects elsewhere.
1440 * @param pfnDone Pointer to the completion routine. If NULL a synchronous
1441 * reset is preformed not respecting the 10ms.
1442 * @param pvUser Opaque user data to pass to the done callback.
1443 * @param pVM Pointer to the VM handle for performing the done function
1444 * on the EMT thread.
1445 * @thread EMT
1446 */
1447static DECLCALLBACK(int) vusbIDeviceReset(PVUSBIDEVICE pDevice, bool fResetOnLinux,
1448 PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
1449{
1450 RT_NOREF(pVM);
1451 PVUSBDEV pDev = (PVUSBDEV)pDevice;
1452 Assert(!pfnDone || pVM);
1453 LogFlow(("vusb: reset: [%s]/%i\n", pDev->pUsbIns->pszName, pDev->i16Port));
1454
1455 /*
1456 * Only one reset operation at a time.
1457 */
1458 const VUSBDEVICESTATE enmStateOld = vusbDevSetState(pDev, VUSB_DEVICE_STATE_RESET);
1459 if (enmStateOld == VUSB_DEVICE_STATE_RESET)
1460 {
1461 LogRel(("VUSB: %s: reset request is ignored, the device is already resetting!\n", pDev->pUsbIns->pszName));
1462 return VERR_VUSB_DEVICE_IS_RESETTING;
1463 }
1464
1465 /*
1466 * First, cancel all async URBs.
1467 */
1468 vusbDevCancelAllUrbs(pDev, false);
1469
1470 /* Async or sync? */
1471 if (pfnDone)
1472 {
1473 /*
1474 * Async fashion.
1475 */
1476 PVUSBRESETARGS pArgs = (PVUSBRESETARGS)RTMemTmpAlloc(sizeof(*pArgs));
1477 if (pArgs)
1478 {
1479 pArgs->pDev = pDev;
1480 pArgs->pfnDone = pfnDone;
1481 pArgs->pvUser = pvUser;
1482 pArgs->rc = VINF_SUCCESS;
1483 AssertPtrNull(pDev->pvArgs);
1484 pDev->pvArgs = pArgs;
1485 int rc = vusbDevIoThreadExec(pDev, 0 /* fFlags */, (PFNRT)vusbDevResetWorker, 4, pDev, fResetOnLinux, true, pArgs);
1486 if (RT_SUCCESS(rc))
1487 return rc;
1488
1489 RTMemTmpFree(pArgs);
1490 }
1491 /* fall back to sync on failure */
1492 }
1493
1494 /*
1495 * Sync fashion.
1496 */
1497 int rc = vusbDevResetWorker(pDev, fResetOnLinux, false, NULL);
1498 vusbDevResetDone(pDev, rc, pfnDone, pvUser);
1499 return rc;
1500}
1501
1502
1503/**
1504 * Powers on the device.
1505 *
1506 * @returns VBox status code.
1507 * @param pInterface Pointer to the device interface structure.
1508 */
1509static DECLCALLBACK(int) vusbIDevicePowerOn(PVUSBIDEVICE pInterface)
1510{
1511 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1512 LogFlow(("vusbDevPowerOn: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
1513
1514 /*
1515 * Check that the device is in a valid state.
1516 */
1517 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
1518 if (enmState == VUSB_DEVICE_STATE_DETACHED)
1519 {
1520 Log(("vusb: warning: attempt to power on detached device %p[%s]\n", pDev, pDev->pUsbIns->pszName));
1521 return VERR_VUSB_DEVICE_NOT_ATTACHED;
1522 }
1523 if (enmState == VUSB_DEVICE_STATE_RESET)
1524 {
1525 LogRel(("VUSB: %s: power on ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
1526 return VERR_VUSB_DEVICE_IS_RESETTING;
1527 }
1528
1529 /*
1530 * Do the job.
1531 */
1532 if (enmState == VUSB_DEVICE_STATE_ATTACHED)
1533 vusbDevSetState(pDev, VUSB_DEVICE_STATE_POWERED);
1534
1535 return VINF_SUCCESS;
1536}
1537
1538
1539/**
1540 * Powers off the device.
1541 *
1542 * @returns VBox status code.
1543 * @param pInterface Pointer to the device interface structure.
1544 */
1545static DECLCALLBACK(int) vusbIDevicePowerOff(PVUSBIDEVICE pInterface)
1546{
1547 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1548 LogFlow(("vusbDevPowerOff: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
1549
1550 /*
1551 * Check that the device is in a valid state.
1552 */
1553 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
1554 if (enmState == VUSB_DEVICE_STATE_DETACHED)
1555 {
1556 Log(("vusb: warning: attempt to power off detached device %p[%s]\n", pDev, pDev->pUsbIns->pszName));
1557 return VERR_VUSB_DEVICE_NOT_ATTACHED;
1558 }
1559 if (enmState == VUSB_DEVICE_STATE_RESET)
1560 {
1561 LogRel(("VUSB: %s: power off ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
1562 return VERR_VUSB_DEVICE_IS_RESETTING;
1563 }
1564
1565 /*
1566 * If it's a root hub, we will have to cancel all URBs and reap them.
1567 */
1568 if (vusbDevIsRh(pDev))
1569 {
1570 PVUSBROOTHUB pRh = (PVUSBROOTHUB)pDev;
1571 VUSBIRhCancelAllUrbs(&pRh->IRhConnector);
1572 VUSBIRhReapAsyncUrbs(&pRh->IRhConnector, pInterface, 0);
1573 }
1574
1575 vusbDevSetState(pDev, VUSB_DEVICE_STATE_ATTACHED);
1576 return VINF_SUCCESS;
1577}
1578
1579
1580/**
1581 * Get the state of the device.
1582 *
1583 * @returns Device state.
1584 * @param pInterface Pointer to the device interface structure.
1585 */
1586static DECLCALLBACK(VUSBDEVICESTATE) vusbIDeviceGetState(PVUSBIDEVICE pInterface)
1587{
1588 return vusbDevGetState((PVUSBDEV)pInterface);
1589}
1590
1591
1592/**
1593 * @interface_method_impl{VUSBIDEVICE,pfnIsSavedStateSupported}
1594 */
1595static DECLCALLBACK(bool) vusbIDeviceIsSavedStateSupported(PVUSBIDEVICE pInterface)
1596{
1597 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1598 bool fSavedStateSupported = RT_BOOL(pDev->pUsbIns->pReg->fFlags & PDM_USBREG_SAVED_STATE_SUPPORTED);
1599
1600 LogFlowFunc(("pInterface=%p\n", pInterface));
1601
1602 LogFlowFunc(("returns %RTbool\n", fSavedStateSupported));
1603 return fSavedStateSupported;
1604}
1605
1606
1607/**
1608 * @interface_method_impl{VUSBIDEVICE,pfnGetState}
1609 */
1610static DECLCALLBACK(VUSBSPEED) vusbIDeviceGetSpeed(PVUSBIDEVICE pInterface)
1611{
1612 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1613 VUSBSPEED enmSpeed = pDev->pUsbIns->enmSpeed;
1614
1615 LogFlowFunc(("pInterface=%p, returns %u\n", pInterface, enmSpeed));
1616 return enmSpeed;
1617}
1618
1619
1620/**
1621 * The maximum number of interfaces the device can have in all of it's configuration.
1622 *
1623 * @returns Number of interfaces.
1624 * @param pDev The device.
1625 */
1626size_t vusbDevMaxInterfaces(PVUSBDEV pDev)
1627{
1628 uint8_t cMax = 0;
1629 unsigned i = pDev->pDescCache->pDevice->bNumConfigurations;
1630 while (i-- > 0)
1631 {
1632 if (pDev->pDescCache->paConfigs[i].Core.bNumInterfaces > cMax)
1633 cMax = pDev->pDescCache->paConfigs[i].Core.bNumInterfaces;
1634 }
1635
1636 return cMax;
1637}
1638
1639
1640/**
1641 * Executes a given function on the I/O thread.
1642 *
1643 * @returns IPRT status code.
1644 * @param pDev The USB device instance data.
1645 * @param fFlags Combination of VUSB_DEV_IO_THREAD_EXEC_FLAGS_*
1646 * @param pfnFunction The function to execute.
1647 * @param cArgs Number of arguments to the function.
1648 * @param Args The parameter list.
1649 *
1650 * @remarks See remarks on RTReqQueueCallV
1651 */
1652DECLHIDDEN(int) vusbDevIoThreadExecV(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args)
1653{
1654 int rc = VINF_SUCCESS;
1655 PRTREQ hReq = NULL;
1656
1657 Assert(pDev->hUrbIoThread != NIL_RTTHREAD);
1658 if (RT_LIKELY(pDev->hUrbIoThread != NIL_RTTHREAD))
1659 {
1660 uint32_t fReqFlags = RTREQFLAGS_IPRT_STATUS;
1661
1662 if (!(fFlags & VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC))
1663 fReqFlags |= RTREQFLAGS_NO_WAIT;
1664
1665 rc = RTReqQueueCallV(pDev->hReqQueueSync, &hReq, 0 /* cMillies */, fReqFlags, pfnFunction, cArgs, Args);
1666 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1667
1668 /* In case we are called on the I/O thread just process the request. */
1669 if ( pDev->hUrbIoThread == RTThreadSelf()
1670 && (fFlags & VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC))
1671 {
1672 int rc2 = RTReqQueueProcess(pDev->hReqQueueSync, 0);
1673 Assert(RT_SUCCESS(rc2) || rc2 == VERR_TIMEOUT); NOREF(rc2);
1674 }
1675 else
1676 vusbDevUrbIoThreadWakeup(pDev);
1677
1678 if ( rc == VERR_TIMEOUT
1679 && (fFlags & VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC))
1680 {
1681 rc = RTReqWait(hReq, RT_INDEFINITE_WAIT);
1682 AssertRC(rc);
1683 }
1684 RTReqRelease(hReq);
1685 }
1686 else
1687 rc = VERR_INVALID_STATE;
1688
1689 return rc;
1690}
1691
1692
1693/**
1694 * Executes a given function on the I/O thread.
1695 *
1696 * @returns IPRT status code.
1697 * @param pDev The USB device instance data.
1698 * @param fFlags Combination of VUSB_DEV_IO_THREAD_EXEC_FLAGS_*
1699 * @param pfnFunction The function to execute.
1700 * @param cArgs Number of arguments to the function.
1701 * @param ... The parameter list.
1702 *
1703 * @remarks See remarks on RTReqQueueCallV
1704 */
1705DECLHIDDEN(int) vusbDevIoThreadExec(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, ...)
1706{
1707 int rc = VINF_SUCCESS;
1708 va_list va;
1709
1710 va_start(va, cArgs);
1711 rc = vusbDevIoThreadExecV(pDev, fFlags, pfnFunction, cArgs, va);
1712 va_end(va);
1713 return rc;
1714}
1715
1716
1717/**
1718 * Executes a given function synchronously on the I/O thread waiting for it to complete.
1719 *
1720 * @returns IPRT status code.
1721 * @param pDev The USB device instance data
1722 * @param pfnFunction The function to execute.
1723 * @param cArgs Number of arguments to the function.
1724 * @param ... The parameter list.
1725 *
1726 * @remarks See remarks on RTReqQueueCallV
1727 */
1728DECLHIDDEN(int) vusbDevIoThreadExecSync(PVUSBDEV pDev, PFNRT pfnFunction, unsigned cArgs, ...)
1729{
1730 int rc = VINF_SUCCESS;
1731 va_list va;
1732
1733 va_start(va, cArgs);
1734 rc = vusbDevIoThreadExecV(pDev, VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC, pfnFunction, cArgs, va);
1735 va_end(va);
1736 return rc;
1737}
1738
1739
1740static DECLCALLBACK(int) vusbDevGetDescriptorCacheWorker(PPDMUSBINS pUsbIns, PCPDMUSBDESCCACHE *ppDescCache)
1741{
1742 *ppDescCache = pUsbIns->pReg->pfnUsbGetDescriptorCache(pUsbIns);
1743 return VINF_SUCCESS;
1744}
1745
1746/**
1747 * Initialize a new VUSB device.
1748 *
1749 * @returns VBox status code.
1750 * @param pDev The VUSB device to initialize.
1751 * @param pUsbIns Pointer to the PDM USB Device instance.
1752 * @param pszCaptureFilename Optional fileame to capture the traffic to.
1753 */
1754int vusbDevInit(PVUSBDEV pDev, PPDMUSBINS pUsbIns, const char *pszCaptureFilename)
1755{
1756 /*
1757 * Initialize the device data members.
1758 * (All that are Non-Zero at least.)
1759 */
1760 Assert(!pDev->IDevice.pfnReset);
1761 Assert(!pDev->IDevice.pfnPowerOn);
1762 Assert(!pDev->IDevice.pfnPowerOff);
1763 Assert(!pDev->IDevice.pfnGetState);
1764 Assert(!pDev->IDevice.pfnIsSavedStateSupported);
1765
1766 pDev->IDevice.pfnReset = vusbIDeviceReset;
1767 pDev->IDevice.pfnPowerOn = vusbIDevicePowerOn;
1768 pDev->IDevice.pfnPowerOff = vusbIDevicePowerOff;
1769 pDev->IDevice.pfnGetState = vusbIDeviceGetState;
1770 pDev->IDevice.pfnIsSavedStateSupported = vusbIDeviceIsSavedStateSupported;
1771 pDev->IDevice.pfnGetSpeed = vusbIDeviceGetSpeed;
1772 pDev->pUsbIns = pUsbIns;
1773 pDev->pNext = NULL;
1774 pDev->pNextHash = NULL;
1775 pDev->pHub = NULL;
1776 pDev->enmState = VUSB_DEVICE_STATE_DETACHED;
1777 pDev->cRefs = 1;
1778 pDev->u8Address = VUSB_INVALID_ADDRESS;
1779 pDev->u8NewAddress = VUSB_INVALID_ADDRESS;
1780 pDev->i16Port = -1;
1781 pDev->u16Status = 0;
1782 pDev->pDescCache = NULL;
1783 pDev->pCurCfgDesc = NULL;
1784 pDev->paIfStates = NULL;
1785 RTListInit(&pDev->LstAsyncUrbs);
1786 memset(&pDev->aPipes[0], 0, sizeof(pDev->aPipes));
1787 for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
1788 {
1789 int rc = RTCritSectInit(&pDev->aPipes[i].CritSectCtrl);
1790 AssertRCReturn(rc, rc);
1791 }
1792 pDev->pResetTimer = NULL;
1793 pDev->hSniffer = VUSBSNIFFER_NIL;
1794
1795 int rc = RTCritSectInit(&pDev->CritSectAsyncUrbs);
1796 AssertRCReturn(rc, rc);
1797
1798 /* Create the URB pool. */
1799 rc = vusbUrbPoolInit(&pDev->UrbPool);
1800 AssertRCReturn(rc, rc);
1801
1802 /* Setup request queue executing synchronous tasks on the I/O thread. */
1803 rc = RTReqQueueCreate(&pDev->hReqQueueSync);
1804 AssertRCReturn(rc, rc);
1805
1806 /* Create I/O thread. */
1807 rc = vusbDevUrbIoThreadCreate(pDev);
1808 AssertRCReturn(rc, rc);
1809
1810 /*
1811 * Create the reset timer.
1812 */
1813 rc = PDMUsbHlpTMTimerCreate(pDev->pUsbIns, TMCLOCK_VIRTUAL, vusbDevResetDoneTimer, pDev, 0 /*fFlags*/,
1814 "USB Device Reset Timer", &pDev->pResetTimer);
1815 AssertRCReturn(rc, rc);
1816
1817 if (pszCaptureFilename)
1818 {
1819 rc = VUSBSnifferCreate(&pDev->hSniffer, 0, pszCaptureFilename, NULL, NULL);
1820 AssertRCReturn(rc, rc);
1821 }
1822
1823 /*
1824 * Get the descriptor cache from the device. (shall cannot fail)
1825 */
1826 rc = vusbDevIoThreadExecSync(pDev, (PFNRT)vusbDevGetDescriptorCacheWorker, 2, pUsbIns, &pDev->pDescCache);
1827 AssertRC(rc);
1828 AssertPtr(pDev->pDescCache);
1829#ifdef VBOX_STRICT
1830 if (pDev->pDescCache->fUseCachedStringsDescriptors)
1831 {
1832 int32_t iPrevId = -1;
1833 for (unsigned iLang = 0; iLang < pDev->pDescCache->cLanguages; iLang++)
1834 {
1835 Assert((int32_t)pDev->pDescCache->paLanguages[iLang].idLang > iPrevId);
1836 iPrevId = pDev->pDescCache->paLanguages[iLang].idLang;
1837
1838 int32_t idxPrevStr = -1;
1839 PCPDMUSBDESCCACHESTRING paStrings = pDev->pDescCache->paLanguages[iLang].paStrings;
1840 unsigned cStrings = pDev->pDescCache->paLanguages[iLang].cStrings;
1841 for (unsigned iStr = 0; iStr < cStrings; iStr++)
1842 {
1843 Assert((int32_t)paStrings[iStr].idx > idxPrevStr);
1844 idxPrevStr = paStrings[iStr].idx;
1845 size_t cch = strlen(paStrings[iStr].psz);
1846 Assert(cch <= 127);
1847 }
1848 }
1849 }
1850#endif
1851
1852 /*
1853 * Allocate memory for the interface states.
1854 */
1855 size_t cbIface = vusbDevMaxInterfaces(pDev) * sizeof(*pDev->paIfStates);
1856 pDev->paIfStates = (PVUSBINTERFACESTATE)RTMemAllocZ(cbIface);
1857 AssertMsgReturn(pDev->paIfStates, ("RTMemAllocZ(%d) failed\n", cbIface), VERR_NO_MEMORY);
1858
1859 return VINF_SUCCESS;
1860}
1861
1862/*
1863 * Local Variables:
1864 * mode: c
1865 * c-file-style: "bsd"
1866 * c-basic-offset: 4
1867 * tab-width: 4
1868 * indent-tabs-mode: s
1869 * End:
1870 */
1871
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