VirtualBox

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

Last change on this file since 99739 was 99739, checked in by vboxsync, 13 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use