VirtualBox

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

Last change on this file since 52517 was 52517, checked in by vboxsync, 11 years ago

Devices/USB: Fix crash on Linux hosts, a hang when disconnecting a USB device while there is a transfer active and crash upon VM termination if a device with isochronous input endpoints was attached to the VM

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette