VirtualBox

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

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

*: scm cleanup run.

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