VirtualBox

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

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

VUSB: Some structural cleanup (#4 Move the URB allocation from the roothub to the devices in order to optionally allocate the URBs by the device itself later on)

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