VirtualBox

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

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

usb arg2

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.5 KB
Line 
1/* $Id: VUSBDevice.cpp 52526 2014-08-29 09:51:53Z 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
219
220/**
221 * Worker that resets the pipe data on select config and detach.
222 *
223 * This leaves the critical section unmolested
224 *
225 * @param pPipe The pipe which data should be reset.
226 */
227static void vusbDevResetPipeData(PVUSBPIPE pPipe)
228{
229 vusbMsgFreeExtraData(pPipe->pCtrl);
230 pPipe->pCtrl = NULL;
231
232 if (pPipe->hReadAhead)
233 {
234 vusbReadAheadStop(pPipe->hReadAhead);
235 pPipe->hReadAhead = NULL;
236 }
237
238 RT_ZERO(pPipe->in);
239 RT_ZERO(pPipe->out);
240 pPipe->async = 0;
241}
242
243
244bool vusbDevDoSelectConfig(PVUSBDEV pDev, PCVUSBDESCCONFIGEX pCfgDesc)
245{
246 LogFlow(("vusbDevDoSelectConfig: pDev=%p[%s] pCfgDesc=%p:{.iConfiguration=%d}\n",
247 pDev, pDev->pUsbIns->pszName, pCfgDesc, pCfgDesc->Core.iConfiguration));
248
249 /*
250 * Clean up all pipes and interfaces.
251 */
252 unsigned i;
253 for (i = 0; i < VUSB_PIPE_MAX; i++)
254 if (i != VUSB_PIPE_DEFAULT)
255 vusbDevResetPipeData(&pDev->aPipes[i]);
256 memset(pDev->paIfStates, 0, pCfgDesc->Core.bNumInterfaces * sizeof(pDev->paIfStates[0]));
257
258 /*
259 * Map in the default setting for every interface.
260 */
261 for (i = 0; i < pCfgDesc->Core.bNumInterfaces; i++)
262 {
263 PCVUSBINTERFACE pIf;
264 struct vusb_interface_state *pIfState;
265
266 pIf = &pCfgDesc->paIfs[i];
267 pIfState = &pDev->paIfStates[i];
268 pIfState->pIf = pIf;
269
270 /*
271 * Find the 0 setting, if it is not present we just use
272 * the lowest numbered one.
273 */
274 for (uint32_t j = 0; j < pIf->cSettings; j++)
275 {
276 if ( !pIfState->pCurIfDesc
277 || pIf->paSettings[j].Core.bAlternateSetting < pIfState->pCurIfDesc->Core.bAlternateSetting)
278 pIfState->pCurIfDesc = &pIf->paSettings[j];
279 if (pIfState->pCurIfDesc->Core.bAlternateSetting == 0)
280 break;
281 }
282
283 if (pIfState->pCurIfDesc)
284 map_interface(pDev, pIfState->pCurIfDesc);
285 }
286
287 pDev->pCurCfgDesc = pCfgDesc;
288
289 if (pCfgDesc->Core.bmAttributes & 0x40)
290 pDev->u16Status |= (1 << VUSB_DEV_SELF_POWERED);
291 else
292 pDev->u16Status &= ~(1 << VUSB_DEV_SELF_POWERED);
293
294 return true;
295}
296
297/**
298 * Standard device request: SET_CONFIGURATION
299 * @returns success indicator.
300 */
301static bool vusbDevStdReqSetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
302{
303 unsigned iCfg = pSetup->wValue & 0xff;
304
305 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_DEVICE)
306 {
307 Log(("vusb: error: %s: SET_CONFIGURATION - invalid request (dir) !!!\n", pDev->pUsbIns->pszName, iCfg));
308 return false;
309 }
310
311 /*
312 * Check that the device is in a valid state.
313 * (The caller has already checked that it's not being reset.)
314 */
315 const VUSBDEVICESTATE enmState = pDev->enmState;
316 if (enmState == VUSB_DEVICE_STATE_DEFAULT)
317 {
318 LogFlow(("vusbDevStdReqSetConfig: %s: default dev state !!?\n", pDev->pUsbIns->pszName));
319 return false;
320 }
321
322 PCVUSBDESCCONFIGEX pNewCfgDesc = vusbDevFindCfgDesc(pDev, iCfg);
323 if (!pNewCfgDesc)
324 {
325 Log(("vusb: error: %s: config %i not found !!!\n", pDev->pUsbIns->pszName, iCfg));
326 return false;
327 }
328
329 if (iCfg == 0)
330 pDev->enmState = VUSB_DEVICE_STATE_ADDRESS;
331 else
332 pDev->enmState = VUSB_DEVICE_STATE_CONFIGURED;
333 if (pDev->pUsbIns->pReg->pfnUsbSetConfiguration)
334 {
335 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbSetConfiguration, 5,
336 pDev->pUsbIns, pNewCfgDesc->Core.bConfigurationValue,
337 pDev->pCurCfgDesc, pDev->paIfStates, pNewCfgDesc);
338 if (RT_FAILURE(rc))
339 {
340 Log(("vusb: error: %s: failed to set config %i (%Rrc) !!!\n", pDev->pUsbIns->pszName, iCfg, rc));
341 return false;
342 }
343 }
344 Log(("vusb: %p[%s]: SET_CONFIGURATION: Selected config %u\n", pDev, pDev->pUsbIns->pszName, iCfg));
345 return vusbDevDoSelectConfig(pDev, pNewCfgDesc);
346}
347
348
349/**
350 * Standard device request: GET_CONFIGURATION
351 * @returns success indicator.
352 */
353static bool vusbDevStdReqGetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
354{
355 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_DEVICE)
356 {
357 Log(("vusb: error: %s: GET_CONFIGURATION - invalid request (dir) !!!\n", pDev->pUsbIns->pszName));
358 return false;
359 }
360
361 /*
362 * Check that the device is in a valid state.
363 * (The caller has already checked that it's not being reset.)
364 */
365 const VUSBDEVICESTATE enmState = pDev->enmState;
366 if ( enmState != VUSB_DEVICE_STATE_CONFIGURED
367 && enmState != VUSB_DEVICE_STATE_ADDRESS)
368 {
369 LogFlow(("vusbDevStdReqGetConfig: error: %s: invalid device state %d!!!\n", pDev->pUsbIns->pszName, enmState));
370 return false;
371 }
372
373 if (*pcbBuf < 1)
374 {
375 LogFlow(("vusbDevStdReqGetConfig: %s: no space for data!\n", pDev->pUsbIns->pszName));
376 return true;
377 }
378
379 uint8_t iCfg;
380 if (pDev->enmState == VUSB_DEVICE_STATE_ADDRESS)
381 iCfg = 0;
382 else
383 iCfg = pDev->pCurCfgDesc->Core.bConfigurationValue;
384
385 *pbBuf = iCfg;
386 *pcbBuf = 1;
387 LogFlow(("vusbDevStdReqGetConfig: %s: returns iCfg=%d\n", pDev->pUsbIns->pszName, iCfg));
388 return true;
389}
390
391/**
392 * Standard device request: GET_INTERFACE
393 * @returns success indicator.
394 */
395static bool vusbDevStdReqGetInterface(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
396{
397 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_INTERFACE)
398 {
399 Log(("vusb: error: %s: GET_INTERFACE - invalid request (dir) !!!\n", pDev->pUsbIns->pszName));
400 return false;
401 }
402
403 /*
404 * Check that the device is in a valid state.
405 * (The caller has already checked that it's not being reset.)
406 */
407 const VUSBDEVICESTATE enmState = pDev->enmState;
408 if (enmState != VUSB_DEVICE_STATE_CONFIGURED)
409 {
410 LogFlow(("vusbDevStdReqGetInterface: error: %s: invalid device state %d!!!\n", pDev->pUsbIns->pszName, enmState));
411 return false;
412 }
413
414 if (*pcbBuf < 1)
415 {
416 LogFlow(("vusbDevStdReqGetInterface: %s: no space for data!\n", pDev->pUsbIns->pszName));
417 return true;
418 }
419
420 for (unsigned i = 0; i < pDev->pCurCfgDesc->Core.bNumInterfaces; i++)
421 {
422 PCVUSBDESCINTERFACEEX pIfDesc = pDev->paIfStates[i].pCurIfDesc;
423 if ( pIfDesc
424 && pSetup->wIndex == pIfDesc->Core.bInterfaceNumber)
425 {
426 *pbBuf = pIfDesc->Core.bAlternateSetting;
427 *pcbBuf = 1;
428 Log(("vusb: %s: GET_INTERFACE: %u.%u\n", pDev->pUsbIns->pszName, pIfDesc->Core.bInterfaceNumber, *pbBuf));
429 return true;
430 }
431 }
432
433 Log(("vusb: error: %s: GET_INTERFACE - unknown iface %u !!!\n", pDev->pUsbIns->pszName, pSetup->wIndex));
434 return false;
435}
436
437/**
438 * Standard device request: SET_INTERFACE
439 * @returns success indicator.
440 */
441static bool vusbDevStdReqSetInterface(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
442{
443 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_INTERFACE)
444 {
445 Log(("vusb: error: %s: SET_INTERFACE - invalid request (dir) !!!\n", pDev->pUsbIns->pszName));
446 return false;
447 }
448
449 /*
450 * Check that the device is in a valid state.
451 * (The caller has already checked that it's not being reset.)
452 */
453 const VUSBDEVICESTATE enmState = pDev->enmState;
454 if (enmState != VUSB_DEVICE_STATE_CONFIGURED)
455 {
456 LogFlow(("vusbDevStdReqSetInterface: error: %s: invalid device state %d !!!\n", pDev->pUsbIns->pszName, enmState));
457 return false;
458 }
459
460 /*
461 * Find the interface.
462 */
463 uint8_t iIf = pSetup->wIndex;
464 PVUSBINTERFACESTATE pIfState = vusbDevFindIfState(pDev, iIf);
465 if (!pIfState)
466 {
467 LogFlow(("vusbDevStdReqSetInterface: error: %s: couldn't find interface %u !!!\n", pDev->pUsbIns->pszName, iIf));
468 return false;
469 }
470 uint8_t iAlt = pSetup->wValue;
471 PCVUSBDESCINTERFACEEX pIfDesc = vusbDevFindAltIfDesc(pDev, pIfState, iAlt);
472 if (!pIfDesc)
473 {
474 LogFlow(("vusbDevStdReqSetInterface: error: %s: couldn't find alt interface %u.%u !!!\n", pDev->pUsbIns->pszName, iIf, iAlt));
475 return false;
476 }
477
478 if (pDev->pUsbIns->pReg->pfnUsbSetInterface)
479 {
480 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbSetInterface, 3, pDev->pUsbIns, iIf, iAlt);
481 if (RT_FAILURE(rc))
482 {
483 LogFlow(("vusbDevStdReqSetInterface: error: %s: couldn't find alt interface %u.%u (%Rrc)\n", pDev->pUsbIns->pszName, iIf, iAlt, rc));
484 return false;
485 }
486 }
487
488 for (unsigned i = 0; i < pIfState->pCurIfDesc->Core.bNumEndpoints; i++)
489 unmap_endpoint(pDev, &pIfState->pCurIfDesc->paEndpoints[i]);
490
491 Log(("vusb: SET_INTERFACE: Selected %u.%u\n", iIf, iAlt));
492
493 map_interface(pDev, pIfDesc);
494 pIfState->pCurIfDesc = pIfDesc;
495
496 return true;
497}
498
499/**
500 * Standard device request: SET_ADDRESS
501 * @returns success indicator.
502 */
503static bool vusbDevStdReqSetAddress(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
504{
505 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) != VUSB_TO_DEVICE)
506 {
507 Log(("vusb: error: %s: SET_ADDRESS - invalid request (dir) !!!\n", pDev->pUsbIns->pszName));
508 return false;
509 }
510
511 /*
512 * Check that the device is in a valid state.
513 * (The caller has already checked that it's not being reset.)
514 */
515 const VUSBDEVICESTATE enmState = pDev->enmState;
516 if ( enmState != VUSB_DEVICE_STATE_DEFAULT
517 && enmState != VUSB_DEVICE_STATE_ADDRESS)
518 {
519 LogFlow(("vusbDevStdReqSetAddress: error: %s: invalid device state %d !!!\n", pDev->pUsbIns->pszName, enmState));
520 return false;
521 }
522
523 pDev->u8NewAddress = pSetup->wValue;
524 return true;
525}
526
527/**
528 * Standard device request: CLEAR_FEATURE
529 * @returns success indicator.
530 *
531 * @remark This is only called for VUSB_TO_ENDPOINT && ep == 0 && wValue == ENDPOINT_HALT.
532 * All other cases of CLEAR_FEATURE is handled in the normal async/sync manner.
533 */
534static bool vusbDevStdReqClearFeature(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
535{
536 switch (pSetup->bmRequestType & VUSB_RECIP_MASK)
537 {
538 case VUSB_TO_DEVICE:
539 Log(("vusb: ClearFeature: dev(%u): selector=%u\n", pSetup->wIndex, pSetup->wValue));
540 break;
541 case VUSB_TO_INTERFACE:
542 Log(("vusb: ClearFeature: iface(%u): selector=%u\n", pSetup->wIndex, pSetup->wValue));
543 break;
544 case VUSB_TO_ENDPOINT:
545 Log(("vusb: ClearFeature: ep(%u): selector=%u\n", pSetup->wIndex, pSetup->wValue));
546 if ( !EndPt /* Default control pipe only */
547 && pSetup->wValue == 0 /* ENDPOINT_HALT */
548 && pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint)
549 {
550 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint,
551 2, pDev->pUsbIns, pSetup->wIndex);
552 return RT_SUCCESS(rc);
553 }
554 break;
555 default:
556 AssertMsgFailed(("VUSB_TO_OTHER!\n"));
557 break;
558 }
559
560 AssertMsgFailed(("Invalid safe check !!!\n"));
561 return false;
562}
563
564/**
565 * Standard device request: SET_FEATURE
566 * @returns success indicator.
567 */
568static bool vusbDevStdReqSetFeature(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
569{
570 switch (pSetup->bmRequestType & VUSB_RECIP_MASK)
571 {
572 case VUSB_TO_DEVICE:
573 Log(("vusb: SetFeature: dev(%u): selector=%u\n",
574 pSetup->wIndex, pSetup->wValue));
575 break;
576 case VUSB_TO_INTERFACE:
577 Log(("vusb: SetFeature: if(%u): selector=%u\n",
578 pSetup->wIndex, pSetup->wValue));
579 break;
580 case VUSB_TO_ENDPOINT:
581 Log(("vusb: SetFeature: ep(%u): selector=%u\n",
582 pSetup->wIndex, pSetup->wValue));
583 break;
584 default:
585 AssertMsgFailed(("VUSB_TO_OTHER!\n"));
586 return false;
587 }
588 AssertMsgFailed(("This stuff is bogus\n"));
589 return false;
590}
591
592static bool vusbDevStdReqGetStatus(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
593{
594 if (*pcbBuf != 2)
595 {
596 LogFlow(("vusbDevStdReqGetStatus: %s: buffer is too small! (%d)\n", pDev->pUsbIns->pszName, *pcbBuf));
597 return false;
598 }
599
600 uint16_t u16Status;
601 switch (pSetup->bmRequestType & VUSB_RECIP_MASK)
602 {
603 case VUSB_TO_DEVICE:
604 u16Status = pDev->u16Status;
605 LogFlow(("vusbDevStdReqGetStatus: %s: device status %#x (%d)\n", pDev->pUsbIns->pszName, u16Status, u16Status));
606 break;
607 case VUSB_TO_INTERFACE:
608 u16Status = 0;
609 LogFlow(("vusbDevStdReqGetStatus: %s: bogus interface status request!!\n", pDev->pUsbIns->pszName));
610 break;
611 case VUSB_TO_ENDPOINT:
612 u16Status = 0;
613 LogFlow(("vusbDevStdReqGetStatus: %s: bogus endpoint status request!!\n", pDev->pUsbIns->pszName));
614 break;
615 default:
616 AssertMsgFailed(("VUSB_TO_OTHER!\n"));
617 return false;
618 }
619
620 *(uint16_t *)pbBuf = u16Status;
621 return true;
622}
623
624
625/**
626 * Finds a cached string.
627 *
628 * @returns Pointer to the cached string if found. NULL if not.
629 * @param paLanguages The languages to search.
630 * @param cLanguages The number of languages in the table.
631 * @param idLang The language ID.
632 * @param iString The string index.
633 */
634static PCPDMUSBDESCCACHESTRING FindCachedString(PCPDMUSBDESCCACHELANG paLanguages, unsigned cLanguages,
635 uint16_t idLang, uint8_t iString)
636{
637 /** @todo binary lookups! */
638 unsigned iCurLang = cLanguages;
639 while (iCurLang-- > 0)
640 if (paLanguages[iCurLang].idLang == idLang)
641 {
642 PCPDMUSBDESCCACHESTRING paStrings = paLanguages[iCurLang].paStrings;
643 unsigned iCurStr = paLanguages[iCurLang].cStrings;
644 while (iCurStr-- > 0)
645 if (paStrings[iCurStr].idx == iString)
646 return &paStrings[iCurStr];
647 break;
648 }
649 return NULL;
650}
651
652
653/** Macro for copying descriptor data. */
654#define COPY_DATA(pbDst, cbLeft, pvSrc, cbSrc) \
655 do { \
656 uint32_t cbSrc_ = cbSrc; \
657 uint32_t cbCopy = RT_MIN(cbLeft, cbSrc_); \
658 memcpy(pbBuf, pvSrc, cbCopy); \
659 cbLeft -= cbCopy; \
660 if (!cbLeft) \
661 return; \
662 pbBuf += cbCopy; \
663 } while (0)
664
665/**
666 * Internal function for reading the language IDs.
667 */
668static void ReadCachedStringDesc(PCPDMUSBDESCCACHESTRING pString, uint8_t *pbBuf, uint32_t *pcbBuf)
669{
670 uint32_t cbLeft = *pcbBuf;
671
672 RTUTF16 wsz[128]; /* 128-1 => bLength=0xff */
673 PRTUTF16 pwsz = wsz;
674 size_t cwc;
675 int rc = RTStrToUtf16Ex(pString->psz, RT_ELEMENTS(wsz) - 1, &pwsz, RT_ELEMENTS(wsz), &cwc);
676 if (RT_FAILURE(rc))
677 {
678 AssertRC(rc);
679 wsz[0] = 'e';
680 wsz[1] = 'r';
681 wsz[2] = 'r';
682 cwc = 3;
683 }
684
685 VUSBDESCSTRING StringDesc;
686 StringDesc.bLength = (uint8_t)(sizeof(StringDesc) + cwc * sizeof(RTUTF16));
687 StringDesc.bDescriptorType = VUSB_DT_STRING;
688 COPY_DATA(pbBuf, cbLeft, &StringDesc, sizeof(StringDesc));
689 COPY_DATA(pbBuf, cbLeft, wsz, (uint32_t)cwc * sizeof(RTUTF16));
690
691 /* updated the size of the output buffer. */
692 *pcbBuf -= cbLeft;
693}
694
695
696/**
697 * Internal function for reading the language IDs.
698 */
699static void ReadCachedLangIdDesc(PCPDMUSBDESCCACHELANG paLanguages, unsigned cLanguages,
700 uint8_t *pbBuf, uint32_t *pcbBuf)
701{
702 uint32_t cbLeft = *pcbBuf;
703
704 VUSBDESCLANGID LangIdDesc;
705 size_t cbDesc = sizeof(LangIdDesc) + cLanguages * sizeof(paLanguages[0].idLang);
706 LangIdDesc.bLength = (uint8_t)RT_MIN(0xff, cbDesc);
707 LangIdDesc.bDescriptorType = VUSB_DT_STRING;
708 COPY_DATA(pbBuf, cbLeft, &LangIdDesc, sizeof(LangIdDesc));
709
710 unsigned iLanguage = cLanguages;
711 while (iLanguage-- > 0)
712 COPY_DATA(pbBuf, cbLeft, &paLanguages[iLanguage].idLang, sizeof(paLanguages[iLanguage].idLang));
713
714 /* updated the size of the output buffer. */
715 *pcbBuf -= cbLeft;
716}
717
718
719/**
720 * Internal function which performs a descriptor read on the cached descriptors.
721 */
722static void ReadCachedConfigDesc(PCVUSBDESCCONFIGEX pCfgDesc, uint8_t *pbBuf, uint32_t *pcbBuf)
723{
724 uint32_t cbLeft = *pcbBuf;
725
726/** @todo See @bugref{2693} */
727 /*
728 * Make a copy of the config descriptor and calculate the wTotalLength field.
729 */
730 VUSBDESCCONFIG CfgDesc;
731 memcpy(&CfgDesc, pCfgDesc, VUSB_DT_CONFIG_MIN_LEN);
732 uint32_t cbTotal = pCfgDesc->Core.bLength;
733 for (unsigned i = 0; i < pCfgDesc->Core.bNumInterfaces; i++)
734 {
735 PCVUSBINTERFACE pIf = &pCfgDesc->paIfs[i];
736 for (uint32_t j = 0; j < pIf->cSettings; j++)
737 {
738 cbTotal += pIf->paSettings[j].cbIAD;
739 cbTotal += pIf->paSettings[j].Core.bLength;
740 cbTotal += pIf->paSettings[j].cbClass;
741 for (unsigned k = 0; k < pIf->paSettings[j].Core.bNumEndpoints; k++)
742 {
743 cbTotal += pIf->paSettings[j].paEndpoints[k].Core.bLength;
744 cbTotal += pIf->paSettings[j].paEndpoints[k].cbClass;
745 }
746 }
747 }
748 CfgDesc.wTotalLength = RT_H2LE_U16(cbTotal);
749
750 /*
751 * Copy the config descriptor
752 */
753 COPY_DATA(pbBuf, cbLeft, &CfgDesc, VUSB_DT_CONFIG_MIN_LEN);
754 COPY_DATA(pbBuf, cbLeft, pCfgDesc->pvMore, pCfgDesc->Core.bLength - VUSB_DT_CONFIG_MIN_LEN);
755
756 /*
757 * Copy out all the interfaces for this configuration
758 */
759 for (unsigned i = 0; i < pCfgDesc->Core.bNumInterfaces; i++)
760 {
761 PCVUSBINTERFACE pIf = &pCfgDesc->paIfs[i];
762 for (uint32_t j = 0; j < pIf->cSettings; j++)
763 {
764 PCVUSBDESCINTERFACEEX pIfDesc = &pIf->paSettings[j];
765
766 COPY_DATA(pbBuf, cbLeft, pIfDesc->pIAD, pIfDesc->cbIAD);
767 COPY_DATA(pbBuf, cbLeft, pIfDesc, VUSB_DT_INTERFACE_MIN_LEN);
768 COPY_DATA(pbBuf, cbLeft, pIfDesc->pvMore, pIfDesc->Core.bLength - VUSB_DT_INTERFACE_MIN_LEN);
769 COPY_DATA(pbBuf, cbLeft, pIfDesc->pvClass, pIfDesc->cbClass);
770
771 /*
772 * Copy out all the endpoints for this interface
773 */
774 for (unsigned k = 0; k < pIfDesc->Core.bNumEndpoints; k++)
775 {
776 VUSBDESCENDPOINT EndPtDesc;
777 memcpy(&EndPtDesc, &pIfDesc->paEndpoints[k], VUSB_DT_ENDPOINT_MIN_LEN);
778 EndPtDesc.wMaxPacketSize = RT_H2LE_U16(EndPtDesc.wMaxPacketSize);
779
780 COPY_DATA(pbBuf, cbLeft, &EndPtDesc, VUSB_DT_ENDPOINT_MIN_LEN);
781 COPY_DATA(pbBuf, cbLeft, pIfDesc->paEndpoints[k].pvMore, EndPtDesc.bLength - VUSB_DT_ENDPOINT_MIN_LEN);
782 COPY_DATA(pbBuf, cbLeft, pIfDesc->paEndpoints[k].pvClass, pIfDesc->paEndpoints[k].cbClass);
783 }
784 }
785 }
786
787 /* updated the size of the output buffer. */
788 *pcbBuf -= cbLeft;
789}
790
791/**
792 * Internal function which performs a descriptor read on the cached descriptors.
793 */
794static void ReadCachedDeviceDesc(PCVUSBDESCDEVICE pDevDesc, uint8_t *pbBuf, uint32_t *pcbBuf)
795{
796 uint32_t cbLeft = *pcbBuf;
797
798 /*
799 * Duplicate the device description and update some fields we keep in cpu type.
800 */
801 Assert(sizeof(VUSBDESCDEVICE) == 18);
802 VUSBDESCDEVICE DevDesc = *pDevDesc;
803 DevDesc.bcdUSB = RT_H2LE_U16(DevDesc.bcdUSB);
804 DevDesc.idVendor = RT_H2LE_U16(DevDesc.idVendor);
805 DevDesc.idProduct = RT_H2LE_U16(DevDesc.idProduct);
806 DevDesc.bcdDevice = RT_H2LE_U16(DevDesc.bcdDevice);
807
808 COPY_DATA(pbBuf, cbLeft, &DevDesc, sizeof(DevDesc));
809 COPY_DATA(pbBuf, cbLeft, pDevDesc + 1, pDevDesc->bLength - sizeof(DevDesc));
810
811 /* updated the size of the output buffer. */
812 *pcbBuf -= cbLeft;
813}
814
815#undef COPY_DATA
816
817/**
818 * Standard device request: GET_DESCRIPTOR
819 * @returns success indicator.
820 * @remark not really used yet as we consider GET_DESCRIPTOR 'safe'.
821 */
822static bool vusbDevStdReqGetDescriptor(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
823{
824 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) == VUSB_TO_DEVICE)
825 {
826 switch (pSetup->wValue >> 8)
827 {
828 case VUSB_DT_DEVICE:
829 ReadCachedDeviceDesc(pDev->pDescCache->pDevice, pbBuf, pcbBuf);
830 LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of device descriptors\n", pDev->pUsbIns->pszName, *pcbBuf));
831 return true;
832
833 case VUSB_DT_CONFIG:
834 {
835 unsigned int iIndex = (pSetup->wValue & 0xff);
836 if (iIndex >= pDev->pDescCache->pDevice->bNumConfigurations)
837 {
838 LogFlow(("vusbDevStdReqGetDescriptor: %s: iIndex=%p >= bNumConfigurations=%d !!!\n",
839 pDev->pUsbIns->pszName, iIndex, pDev->pDescCache->pDevice->bNumConfigurations));
840 return false;
841 }
842 ReadCachedConfigDesc(&pDev->pDescCache->paConfigs[iIndex], pbBuf, pcbBuf);
843 LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of config descriptors\n", pDev->pUsbIns->pszName, *pcbBuf));
844 return true;
845 }
846
847 case VUSB_DT_STRING:
848 {
849 if (pSetup->wIndex == 0)
850 {
851 ReadCachedLangIdDesc(pDev->pDescCache->paLanguages, pDev->pDescCache->cLanguages, pbBuf, pcbBuf);
852 LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of language ID (string) descriptors\n", pDev->pUsbIns->pszName, *pcbBuf));
853 return true;
854 }
855 PCPDMUSBDESCCACHESTRING pString;
856 pString = FindCachedString(pDev->pDescCache->paLanguages, pDev->pDescCache->cLanguages,
857 pSetup->wIndex, pSetup->wValue & 0xff);
858 if (pString)
859 {
860 ReadCachedStringDesc(pString, pbBuf, pcbBuf);
861 LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of string descriptors \"%s\"\n",
862 pDev->pUsbIns->pszName, *pcbBuf, pString->psz));
863 return true;
864 }
865 break;
866 }
867
868 default:
869 break;
870 }
871 }
872 Log(("vusb: %s: warning: unknown descriptor: type=%u descidx=%u lang=%u len=%u!!!\n",
873 pDev->pUsbIns->pszName, pSetup->wValue >> 8, pSetup->wValue & 0xff, pSetup->wIndex, pSetup->wLength));
874 return false;
875}
876
877
878/**
879 * Service the standard USB requests.
880 *
881 * Devices may call this from controlmsg() if you want vusb core to handle your standard
882 * request, it's not necessary - you could handle them manually
883 *
884 * @param pDev The device.
885 * @param EndPoint The endpoint.
886 * @param pSetup Pointer to the setup request structure.
887 * @param pvBuf Buffer?
888 * @param pcbBuf ?
889 */
890bool vusbDevStandardRequest(PVUSBDEV pDev, int EndPoint, PVUSBSETUP pSetup, void *pvBuf, uint32_t *pcbBuf)
891{
892 static bool (* const s_apfnStdReq[VUSB_REQ_MAX])(PVUSBDEV, int, PVUSBSETUP, uint8_t *, uint32_t *) =
893 {
894 vusbDevStdReqGetStatus,
895 vusbDevStdReqClearFeature,
896 NULL,
897 vusbDevStdReqSetFeature,
898 NULL,
899 vusbDevStdReqSetAddress,
900 vusbDevStdReqGetDescriptor,
901 NULL,
902 vusbDevStdReqGetConfig,
903 vusbDevStdReqSetConfig,
904 vusbDevStdReqGetInterface,
905 vusbDevStdReqSetInterface,
906 NULL /* for iso */
907 };
908
909 /*
910 * Check that the device is in a valid state.
911 */
912 const VUSBDEVICESTATE enmState = pDev->enmState;
913 VUSBDEV_ASSERT_VALID_STATE(enmState);
914 if (enmState == VUSB_DEVICE_STATE_RESET)
915 {
916 LogRel(("VUSB: %s: standard control message ignored, the device is resetting\n", pDev->pUsbIns->pszName));
917 return false;
918 }
919
920 /*
921 * Do the request if it's one we want to deal with.
922 */
923 if ( pSetup->bRequest >= VUSB_REQ_MAX
924 || !s_apfnStdReq[pSetup->bRequest])
925 {
926 Log(("vusb: warning: standard req not implemented: message %u: val=%u idx=%u len=%u !!!\n",
927 pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
928 return false;
929 }
930
931 return s_apfnStdReq[pSetup->bRequest](pDev, EndPoint, pSetup, (uint8_t *)pvBuf, pcbBuf);
932}
933
934
935/**
936 * Add a device to the address hash
937 */
938static void vusbDevAddressHash(PVUSBDEV pDev)
939{
940 if (pDev->u8Address == VUSB_INVALID_ADDRESS)
941 return;
942 uint8_t u8Hash = vusbHashAddress(pDev->u8Address);
943 pDev->pNextHash = pDev->pHub->pRootHub->apAddrHash[u8Hash];
944 pDev->pHub->pRootHub->apAddrHash[u8Hash] = pDev;
945}
946
947/**
948 * Remove a device from the address hash
949 */
950static void vusbDevAddressUnHash(PVUSBDEV pDev)
951{
952 if (pDev->u8Address == VUSB_INVALID_ADDRESS)
953 return;
954
955 uint8_t u8Hash = vusbHashAddress(pDev->u8Address);
956 pDev->u8Address = VUSB_INVALID_ADDRESS;
957 pDev->u8NewAddress = VUSB_INVALID_ADDRESS;
958
959 PVUSBDEV pCur = pDev->pHub->pRootHub->apAddrHash[u8Hash];
960 if (pCur == pDev)
961 {
962 /* special case, we're at the head */
963 pDev->pHub->pRootHub->apAddrHash[u8Hash] = pDev->pNextHash;
964 pDev->pNextHash = NULL;
965 }
966 else
967 {
968 /* search the list */
969 PVUSBDEV pPrev;
970 for (pPrev = pCur, pCur = pCur->pNextHash;
971 pCur;
972 pPrev = pCur, pCur = pCur->pNextHash)
973 {
974 if (pCur == pDev)
975 {
976 pPrev->pNextHash = pCur->pNextHash;
977 pDev->pNextHash = NULL;
978 break;
979 }
980 }
981 }
982}
983
984/**
985 * Sets the address of a device.
986 *
987 * Called by status_completion() and vusbDevResetWorker().
988 */
989void vusbDevSetAddress(PVUSBDEV pDev, uint8_t u8Address)
990{
991 LogFlow(("vusbDevSetAddress: pDev=%p[%s]/%i u8Address=%#x\n",
992 pDev, pDev->pUsbIns->pszName, pDev->i16Port, u8Address));
993
994 /*
995 * Check that the device is in a valid state.
996 */
997 const VUSBDEVICESTATE enmState = pDev->enmState;
998 VUSBDEV_ASSERT_VALID_STATE(enmState);
999 if ( enmState == VUSB_DEVICE_STATE_ATTACHED
1000 || enmState == VUSB_DEVICE_STATE_DETACHED)
1001 {
1002 LogFlow(("vusbDevSetAddress: %s: fails because %d < POWERED\n", pDev->pUsbIns->pszName, pDev->enmState));
1003 return;
1004 }
1005 if (enmState == VUSB_DEVICE_STATE_RESET)
1006 {
1007 LogRel(("VUSB: %s: set address ignored, the device is resetting\n", pDev->pUsbIns->pszName));
1008 return;
1009 }
1010
1011 /*
1012 * Ok, get on with it.
1013 */
1014 if (pDev->u8Address == u8Address)
1015 return;
1016
1017 PVUSBROOTHUB pRh = vusbDevGetRh(pDev);
1018 AssertPtrReturnVoid(pRh);
1019 if (pDev->u8Address == VUSB_DEFAULT_ADDRESS)
1020 pRh->pDefaultAddress = NULL;
1021
1022 vusbDevAddressUnHash(pDev);
1023
1024 if (u8Address == VUSB_DEFAULT_ADDRESS)
1025 {
1026 if (pRh->pDefaultAddress != NULL)
1027 {
1028 vusbDevAddressUnHash(pRh->pDefaultAddress);
1029 pRh->pDefaultAddress->enmState = VUSB_DEVICE_STATE_POWERED;
1030 Log(("2 DEFAULT ADDRS\n"));
1031 }
1032
1033 pRh->pDefaultAddress = pDev;
1034 pDev->enmState = VUSB_DEVICE_STATE_DEFAULT;
1035 }
1036 else
1037 pDev->enmState = VUSB_DEVICE_STATE_ADDRESS;
1038
1039 pDev->u8Address = u8Address;
1040 vusbDevAddressHash(pDev);
1041
1042 Log(("vusb: %p[%s]/%i: Assigned address %u\n",
1043 pDev, pDev->pUsbIns->pszName, pDev->i16Port, u8Address));
1044}
1045
1046
1047static DECLCALLBACK(int) vusbDevCancelAllUrbsWorker(PVUSBDEV pDev, bool fDetaching)
1048{
1049 /*
1050 * Iterate the URBs and cancel them.
1051 */
1052 PVUSBURB pUrb = pDev->pAsyncUrbHead;
1053 while (pUrb)
1054 {
1055 PVUSBURB pNext = pUrb->VUsb.pNext;
1056
1057 Assert(pUrb->VUsb.pDev == pDev);
1058
1059 LogFlow(("%s: vusbDevCancelAllUrbs: CANCELING URB\n", pUrb->pszDesc));
1060 vusbUrbCancelWorker(pUrb, CANCELMODE_FAIL);
1061 pUrb = pNext;
1062 }
1063
1064 /*
1065 * Reap any URBs which became ripe during cancel now.
1066 */
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
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 (pDev->enmState != 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 pDev->enmState = 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 */
1265 if (pDev->enmState == VUSB_DEVICE_STATE_RESET)
1266 pDev->enmState = VUSB_DEVICE_STATE_DEFAULT; /* anything but 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 RTCritSectDelete(&pDev->CritSectAsyncUrbs);
1292 pDev->enmState = VUSB_DEVICE_STATE_DESTROYED;
1293}
1294
1295
1296/* -=-=-=-=-=- VUSBIDEVICE methods -=-=-=-=-=- */
1297
1298
1299/**
1300 * The actual reset has been done, do completion on EMT.
1301 *
1302 * There are several things we have to do now, like set default
1303 * config and address, and cleanup the state of control pipes.
1304 *
1305 * It's possible that the device has a delayed destroy request
1306 * pending when we get here. This can happen for async resetting.
1307 * We deal with it here, since we're now executing on the EMT
1308 * thread and the destruction will be properly serialized now.
1309 *
1310 * @param pDev The device that is being reset.
1311 * @param rc The vusbDevResetWorker return code.
1312 * @param pfnDone The done callback specified by the caller of vusbDevReset().
1313 * @param pvUser The user argument for the callback.
1314 */
1315static void vusbDevResetDone(PVUSBDEV pDev, int rc, PFNVUSBRESETDONE pfnDone, void *pvUser)
1316{
1317 VUSBDEV_ASSERT_VALID_STATE(pDev->enmState);
1318 Assert(pDev->enmState == VUSB_DEVICE_STATE_RESET);
1319
1320 /*
1321 * Do control pipe cleanup regardless of state and result.
1322 */
1323 for (unsigned i = 0; i < VUSB_PIPE_MAX; i++)
1324 if (pDev->aPipes[i].pCtrl)
1325 vusbMsgResetExtraData(pDev->aPipes[i].pCtrl);
1326
1327 /*
1328 * Switch to the default state.
1329 */
1330 pDev->enmState = VUSB_DEVICE_STATE_DEFAULT;
1331 pDev->u16Status = 0;
1332 vusbDevDoSelectConfig(pDev, &g_Config0);
1333 if (!vusbDevIsRh(pDev))
1334 vusbDevSetAddress(pDev, VUSB_DEFAULT_ADDRESS);
1335 if (pfnDone)
1336 pfnDone(&pDev->IDevice, rc, pvUser);
1337}
1338
1339
1340/**
1341 * Timer callback for doing reset completion.
1342 *
1343 * @param pUsbIns The USB device instance.
1344 * @param pTimer The timer instance.
1345 * @param pvUser The VUSB device data.
1346 * @thread EMT
1347 */
1348static DECLCALLBACK(void) vusbDevResetDoneTimer(PPDMUSBINS pUsbIns, PTMTIMER pTimer, void *pvUser)
1349{
1350 PVUSBDEV pDev = (PVUSBDEV)pvUser;
1351 PVUSBRESETARGS pArgs = (PVUSBRESETARGS)pDev->pvArgs;
1352 Assert(pDev->pUsbIns == pUsbIns);
1353
1354 /*
1355 * Reset-done processing and cleanup.
1356 */
1357 vusbDevResetDone(pDev, pArgs->rc, pArgs->pfnDone, pArgs->pvUser);
1358 pDev->pvArgs = NULL;
1359 RTMemFree(pArgs);
1360}
1361
1362
1363/**
1364 * Perform the actual reset.
1365 *
1366 * @thread EMT or a VUSB reset thread.
1367 */
1368static int vusbDevResetWorker(PVUSBDEV pDev, bool fResetOnLinux, bool fUseTimer, PVUSBRESETARGS pArgs)
1369{
1370 int rc = VINF_SUCCESS;
1371 uint64_t u64EndTS = TMTimerGet(pDev->pResetTimer) + TMTimerFromMilli(pDev->pResetTimer, 10);
1372
1373 if (pDev->pUsbIns->pReg->pfnUsbReset)
1374 rc = pDev->pUsbIns->pReg->pfnUsbReset(pDev->pUsbIns, fResetOnLinux);
1375
1376 if (fUseTimer)
1377 {
1378 /*
1379 * We use a timer to communicate the result back to EMT.
1380 * This avoids suspend + poweroff issues, and it should give
1381 * us more accurate scheduling than making this thread sleep.
1382 */
1383 int rc2 = TMTimerSet(pDev->pResetTimer, u64EndTS);
1384 AssertReleaseRC(rc2);
1385 }
1386
1387 if (pArgs)
1388 {
1389 pArgs->rc = rc;
1390 rc = VINF_SUCCESS;
1391 }
1392
1393 LogFlow(("vusbDevResetWorker: %s: returns %Rrc\n", pDev->pUsbIns->pszName, rc));
1394 return rc;
1395}
1396
1397
1398/**
1399 * Resets a device.
1400 *
1401 * Since a device reset shall take at least 10ms from the guest point of view,
1402 * it must be performed asynchronously. We create a thread which performs this
1403 * operation and ensures it will take at least 10ms.
1404 *
1405 * At times - like init - a synchronous reset is required, this can be done
1406 * by passing NULL for pfnDone.
1407 *
1408 * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state.
1409 * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful,
1410 * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed.
1411 *
1412 * @returns VBox status code.
1413 *
1414 * @param pDev Pointer to the VUSB device interface.
1415 * @param fResetOnLinux Whether it's safe to reset the device(s) on a linux
1416 * host system. See discussion of logical reconnects elsewhere.
1417 * @param pfnDone Pointer to the completion routine. If NULL a synchronous
1418 * reset is preformed not respecting the 10ms.
1419 * @param pVM Pointer to the VM handle for performing the done function
1420 * on the EMT thread.
1421 * @thread EMT
1422 */
1423DECLCALLBACK(int) vusbDevReset(PVUSBIDEVICE pDevice, bool fResetOnLinux, PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
1424{
1425 PVUSBDEV pDev = (PVUSBDEV)pDevice;
1426 Assert(!pfnDone || pVM);
1427 LogFlow(("vusb: reset: [%s]/%i\n", pDev->pUsbIns->pszName, pDev->i16Port));
1428
1429 /*
1430 * Only one reset operation at a time.
1431 */
1432 const VUSBDEVICESTATE enmState = pDev->enmState;
1433 VUSBDEV_ASSERT_VALID_STATE(enmState);
1434 if (enmState == VUSB_DEVICE_STATE_RESET)
1435 {
1436 LogRel(("VUSB: %s: reset request is ignored, the device is already resetting!\n", pDev->pUsbIns->pszName));
1437 return VERR_VUSB_DEVICE_IS_RESETTING;
1438 }
1439 pDev->enmState = VUSB_DEVICE_STATE_RESET;
1440
1441 /*
1442 * First, cancel all async URBs.
1443 */
1444 vusbDevCancelAllUrbs(pDev, false);
1445
1446 /* Async or sync? */
1447 if (pfnDone)
1448 {
1449 /*
1450 * Async fashion.
1451 */
1452 PVUSBRESETARGS pArgs = (PVUSBRESETARGS)RTMemTmpAlloc(sizeof(*pArgs));
1453 if (pArgs)
1454 {
1455 pArgs->pDev = pDev;
1456 pArgs->pfnDone = pfnDone;
1457 pArgs->pvUser = pvUser;
1458 pArgs->rc = VINF_SUCCESS;
1459 pDev->pvArgs = pArgs;
1460 int rc = vusbDevIoThreadExec(pDev, 0 /* fFlags */, (PFNRT)vusbDevResetWorker, 4, pDev, fResetOnLinux, true, pArgs);
1461 if (RT_SUCCESS(rc))
1462 return rc;
1463
1464 RTMemTmpFree(pArgs);
1465 }
1466 /* fall back to sync on failure */
1467 }
1468
1469 /*
1470 * Sync fashion.
1471 */
1472 int rc = vusbDevResetWorker(pDev, fResetOnLinux, false, NULL);
1473 vusbDevResetDone(pDev, rc, pfnDone, pvUser);
1474 return rc;
1475}
1476
1477
1478/**
1479 * Powers on the device.
1480 *
1481 * @returns VBox status code.
1482 * @param pInterface Pointer to the device interface structure.
1483 */
1484DECLCALLBACK(int) vusbDevPowerOn(PVUSBIDEVICE pInterface)
1485{
1486 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1487 LogFlow(("vusbDevPowerOn: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
1488
1489 /*
1490 * Check that the device is in a valid state.
1491 */
1492 const VUSBDEVICESTATE enmState = pDev->enmState;
1493 VUSBDEV_ASSERT_VALID_STATE(enmState);
1494 if (enmState == VUSB_DEVICE_STATE_DETACHED)
1495 {
1496 Log(("vusb: warning: attempt to power on detached device %p[%s]\n", pDev, pDev->pUsbIns->pszName));
1497 return VERR_VUSB_DEVICE_NOT_ATTACHED;
1498 }
1499 if (enmState == VUSB_DEVICE_STATE_RESET)
1500 {
1501 LogRel(("VUSB: %s: power on ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
1502 return VERR_VUSB_DEVICE_IS_RESETTING;
1503 }
1504
1505 /*
1506 * Do the job.
1507 */
1508 if (enmState == VUSB_DEVICE_STATE_ATTACHED)
1509 pDev->enmState = VUSB_DEVICE_STATE_POWERED;
1510
1511 return VINF_SUCCESS;
1512}
1513
1514
1515/**
1516 * Powers off the device.
1517 *
1518 * @returns VBox status code.
1519 * @param pInterface Pointer to the device interface structure.
1520 */
1521DECLCALLBACK(int) vusbDevPowerOff(PVUSBIDEVICE pInterface)
1522{
1523 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1524 LogFlow(("vusbDevPowerOff: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
1525
1526 /*
1527 * Check that the device is in a valid state.
1528 */
1529 const VUSBDEVICESTATE enmState = pDev->enmState;
1530 VUSBDEV_ASSERT_VALID_STATE(enmState);
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 pDev->enmState = VUSB_DEVICE_STATE_ATTACHED;
1553
1554 return VINF_SUCCESS;
1555}
1556
1557
1558/**
1559 * Get the state of the device.
1560 *
1561 * @returns Device state.
1562 * @param pInterface Pointer to the device interface structure.
1563 */
1564DECLCALLBACK(VUSBDEVICESTATE) vusbDevGetState(PVUSBIDEVICE pInterface)
1565{
1566 return ((PVUSBDEV)pInterface)->enmState;
1567}
1568
1569
1570/**
1571 * @interface_method_impl{VUSBIDEVICE,pfnIsEmulated}
1572 */
1573DECLCALLBACK(bool) vusbDevIsEmulated(PVUSBIDEVICE pInterface)
1574{
1575 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1576 bool fEmulated = !!(pDev->pUsbIns->pReg->fFlags & PDM_USBREG_EMULATED_DEVICE);
1577
1578 LogFlowFunc(("pInterface=%p\n", pInterface));
1579
1580 LogFlowFunc(("returns %RTbool\n", fEmulated));
1581 return fEmulated;
1582}
1583
1584
1585/**
1586 * The maximum number of interfaces the device can have in all of it's configuration.
1587 *
1588 * @returns Number of interfaces.
1589 * @param pDev The device.
1590 */
1591size_t vusbDevMaxInterfaces(PVUSBDEV pDev)
1592{
1593 uint8_t cMax = 0;
1594 unsigned i = pDev->pDescCache->pDevice->bNumConfigurations;
1595 while (i-- > 0)
1596 {
1597 if (pDev->pDescCache->paConfigs[i].Core.bNumInterfaces > cMax)
1598 cMax = pDev->pDescCache->paConfigs[i].Core.bNumInterfaces;
1599 }
1600
1601 return cMax;
1602}
1603
1604
1605/**
1606 * Executes a given function on the I/O thread.
1607 *
1608 * @returns IPRT status code.
1609 * @param pDev The USB device instance data.
1610 * @param fFlags Combination of VUSB_DEV_IO_THREAD_EXEC_FLAGS_*
1611 * @param pfnFunction The function to execute.
1612 * @param cArgs Number of arguments to the function.
1613 * @param Args The parameter list.
1614 *
1615 * @remarks See remarks on RTReqQueueCallV
1616 */
1617DECLHIDDEN(int) vusbDevIoThreadExecV(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args)
1618{
1619 int rc = VINF_SUCCESS;
1620 PRTREQ hReq = NULL;
1621
1622 Assert(pDev->hUrbIoThread != NIL_RTTHREAD);
1623 if (RT_LIKELY(pDev->hUrbIoThread != NIL_RTTHREAD))
1624 {
1625 uint32_t fReqFlags = RTREQFLAGS_IPRT_STATUS;
1626
1627 if (!(fFlags & VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC))
1628 fReqFlags |= RTREQFLAGS_NO_WAIT;
1629
1630 rc = RTReqQueueCallV(pDev->hReqQueueSync, &hReq, 0 /* cMillies */, fReqFlags, pfnFunction, cArgs, Args);
1631 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1632
1633 vusbDevUrbIoThreadWakeup(pDev);
1634 if ( rc == VERR_TIMEOUT
1635 && (fFlags & VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC))
1636 {
1637 rc = RTReqWait(hReq, RT_INDEFINITE_WAIT);
1638 AssertRC(rc);
1639 }
1640 RTReqRelease(hReq);
1641 }
1642 else
1643 rc = VERR_INVALID_STATE;
1644
1645 return rc;
1646}
1647
1648
1649/**
1650 * Executes a given function on the I/O thread.
1651 *
1652 * @returns IPRT status code.
1653 * @param pDev The USB device instance data.
1654 * @param fFlags Combination of VUSB_DEV_IO_THREAD_EXEC_FLAGS_*
1655 * @param pfnFunction The function to execute.
1656 * @param cArgs Number of arguments to the function.
1657 * @param ... The parameter list.
1658 *
1659 * @remarks See remarks on RTReqQueueCallV
1660 */
1661DECLHIDDEN(int) vusbDevIoThreadExec(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, ...)
1662{
1663 int rc = VINF_SUCCESS;
1664 va_list va;
1665
1666 va_start(va, cArgs);
1667 rc = vusbDevIoThreadExecV(pDev, fFlags, pfnFunction, cArgs, va);
1668 va_end(va);
1669 return rc;
1670}
1671
1672
1673/**
1674 * Executes a given function synchronously on the I/O thread waiting for it to complete.
1675 *
1676 * @returns IPRT status code.
1677 * @param pDev The USB device instance data
1678 * @param pfnFunction The function to execute.
1679 * @param cArgs Number of arguments to the function.
1680 * @param ... The parameter list.
1681 *
1682 * @remarks See remarks on RTReqQueueCallV
1683 */
1684DECLHIDDEN(int) vusbDevIoThreadExecSync(PVUSBDEV pDev, PFNRT pfnFunction, unsigned cArgs, ...)
1685{
1686 int rc = VINF_SUCCESS;
1687 va_list va;
1688
1689 va_start(va, cArgs);
1690 rc = vusbDevIoThreadExecV(pDev, VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC, pfnFunction, cArgs, va);
1691 va_end(va);
1692 return rc;
1693}
1694
1695
1696static DECLCALLBACK(int) vusbDevGetDescriptorCacheWorker(PPDMUSBINS pUsbIns, PCPDMUSBDESCCACHE *ppDescCache)
1697{
1698 *ppDescCache = pUsbIns->pReg->pfnUsbGetDescriptorCache(pUsbIns);
1699 return VINF_SUCCESS;
1700}
1701
1702/**
1703 * Initialize a new VUSB device.
1704 *
1705 * @returns VBox status code.
1706 * @param pDev The VUSB device to initialize.
1707 * @param pUsbIns Pointer to the PDM USB Device instance.
1708 */
1709int vusbDevInit(PVUSBDEV pDev, PPDMUSBINS pUsbIns)
1710{
1711 /*
1712 * Initialize the device data members.
1713 * (All that are Non-Zero at least.)
1714 */
1715 Assert(!pDev->IDevice.pfnReset);
1716 Assert(!pDev->IDevice.pfnPowerOn);
1717 Assert(!pDev->IDevice.pfnPowerOff);
1718 Assert(!pDev->IDevice.pfnGetState);
1719 Assert(!pDev->IDevice.pfnIsEmulated);
1720
1721 pDev->IDevice.pfnReset = vusbDevReset;
1722 pDev->IDevice.pfnPowerOn = vusbDevPowerOn;
1723 pDev->IDevice.pfnPowerOff = vusbDevPowerOff;
1724 pDev->IDevice.pfnGetState = vusbDevGetState;
1725 pDev->IDevice.pfnIsEmulated = vusbDevIsEmulated;
1726 pDev->pUsbIns = pUsbIns;
1727 pDev->pNext = NULL;
1728 pDev->pNextHash = NULL;
1729 pDev->pHub = NULL;
1730 pDev->enmState = VUSB_DEVICE_STATE_DETACHED;
1731 pDev->u8Address = VUSB_INVALID_ADDRESS;
1732 pDev->u8NewAddress = VUSB_INVALID_ADDRESS;
1733 pDev->i16Port = -1;
1734 pDev->u16Status = 0;
1735 pDev->pDescCache = NULL;
1736 pDev->pCurCfgDesc = NULL;
1737 pDev->paIfStates = NULL;
1738 memset(&pDev->aPipes[0], 0, sizeof(pDev->aPipes));
1739 for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
1740 {
1741 int rc = RTCritSectInit(&pDev->aPipes[i].CritSectCtrl);
1742 AssertRCReturn(rc, rc);
1743 }
1744 pDev->pResetTimer = NULL;
1745
1746 int rc = RTCritSectInit(&pDev->CritSectAsyncUrbs);
1747 AssertRCReturn(rc, rc);
1748
1749 /* Setup request queue executing synchronous tasks on the I/O thread. */
1750 rc = RTReqQueueCreate(&pDev->hReqQueueSync);
1751 AssertRCReturn(rc, rc);
1752
1753 /* Create I/O thread. */
1754 rc = vusbDevUrbIoThreadCreate(pDev);
1755 AssertRCReturn(rc, rc);
1756
1757 /*
1758 * Create the reset timer.
1759 */
1760 rc = PDMUsbHlpTMTimerCreate(pDev->pUsbIns, TMCLOCK_VIRTUAL, vusbDevResetDoneTimer, pDev, 0 /*fFlags*/,
1761 "USB Device Reset Timer", &pDev->pResetTimer);
1762 AssertRCReturn(rc, rc);
1763
1764 /*
1765 * Get the descriptor cache from the device. (shall cannot fail)
1766 */
1767 rc = vusbDevIoThreadExecSync(pDev, (PFNRT)vusbDevGetDescriptorCacheWorker, 2, pUsbIns, &pDev->pDescCache);
1768 AssertRC(rc);
1769 AssertPtr(pDev->pDescCache);
1770#ifdef VBOX_STRICT
1771 if (pDev->pDescCache->fUseCachedStringsDescriptors)
1772 {
1773 int32_t iPrevId = -1;
1774 for (unsigned iLang = 0; iLang < pDev->pDescCache->cLanguages; iLang++)
1775 {
1776 Assert((int32_t)pDev->pDescCache->paLanguages[iLang].idLang > iPrevId);
1777 iPrevId = pDev->pDescCache->paLanguages[iLang].idLang;
1778
1779 int32_t idxPrevStr = -1;
1780 PCPDMUSBDESCCACHESTRING paStrings = pDev->pDescCache->paLanguages[iLang].paStrings;
1781 unsigned cStrings = pDev->pDescCache->paLanguages[iLang].cStrings;
1782 for (unsigned iStr = 0; iStr < cStrings; iStr++)
1783 {
1784 Assert((int32_t)paStrings[iStr].idx > idxPrevStr);
1785 idxPrevStr = paStrings[iStr].idx;
1786 size_t cch = strlen(paStrings[iStr].psz);
1787 Assert(cch <= 127);
1788 }
1789 }
1790 }
1791#endif
1792
1793 /*
1794 * Allocate memory for the interface states.
1795 */
1796 size_t cbIface = vusbDevMaxInterfaces(pDev) * sizeof(*pDev->paIfStates);
1797 pDev->paIfStates = (PVUSBINTERFACESTATE)RTMemAllocZ(cbIface);
1798 AssertMsgReturn(pDev->paIfStates, ("RTMemAllocZ(%d) failed\n", cbIface), VERR_NO_MEMORY);
1799
1800 return VINF_SUCCESS;
1801}
1802
1803/*
1804 * Local Variables:
1805 * mode: c
1806 * c-file-style: "bsd"
1807 * c-basic-offset: 4
1808 * tab-width: 4
1809 * indent-tabs-mode: s
1810 * End:
1811 */
1812
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