VirtualBox

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

Last change on this file since 56772 was 56454, checked in by vboxsync, 10 years ago

Commit r100743 and r100913 to trunk which should improve pass through of USB sound devices

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