VirtualBox

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

Last change on this file since 99404 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

  • 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 98103 2023-01-17 14:15:46Z 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 * @returns nothing.
1168 * @param pDev The VUSB device instance.
1169 * @param fDetaching If set, we will unconditionally unlink (and leak)
1170 * any URBs which isn't reaped.
1171 */
1172DECLHIDDEN(void) vusbDevCancelAllUrbs(PVUSBDEV pDev, bool fDetaching)
1173{
1174 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)vusbDevCancelAllUrbsWorker, 2, pDev, fDetaching);
1175 AssertRC(rc);
1176}
1177
1178
1179static DECLCALLBACK(int) vusbDevUrbIoThread(RTTHREAD hThread, void *pvUser)
1180{
1181 PVUSBDEV pDev = (PVUSBDEV)pvUser;
1182
1183 /* Notify the starter that we are up and running. */
1184 RTThreadUserSignal(hThread);
1185
1186 LogFlowFunc(("Entering work loop\n"));
1187
1188 while (!ASMAtomicReadBool(&pDev->fTerminate))
1189 {
1190 if (vusbDevGetState(pDev) != VUSB_DEVICE_STATE_RESET)
1191 vusbUrbDoReapAsyncDev(pDev, RT_INDEFINITE_WAIT);
1192
1193 /* Process any URBs waiting to be cancelled first. */
1194 int rc = RTReqQueueProcess(pDev->hReqQueueSync, 0); /* Don't wait if there is nothing to do. */
1195 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT); NOREF(rc);
1196 }
1197
1198 return VINF_SUCCESS;
1199}
1200
1201int vusbDevUrbIoThreadWakeup(PVUSBDEV pDev)
1202{
1203 ASMAtomicXchgBool(&pDev->fWokenUp, true);
1204 return pDev->pUsbIns->pReg->pfnWakeup(pDev->pUsbIns);
1205}
1206
1207/**
1208 * Create the URB I/O thread.
1209 *
1210 * @returns VBox status code.
1211 * @param pDev The VUSB device.
1212 */
1213int vusbDevUrbIoThreadCreate(PVUSBDEV pDev)
1214{
1215 int rc = VINF_SUCCESS;
1216
1217 ASMAtomicXchgBool(&pDev->fTerminate, false);
1218 rc = RTThreadCreateF(&pDev->hUrbIoThread, vusbDevUrbIoThread, pDev, 0, RTTHREADTYPE_IO,
1219 RTTHREADFLAGS_WAITABLE, "USBDevIo-%d", pDev->i16Port);
1220 if (RT_SUCCESS(rc))
1221 {
1222 /* Wait for it to become active. */
1223 rc = RTThreadUserWait(pDev->hUrbIoThread, RT_INDEFINITE_WAIT);
1224 }
1225
1226 return rc;
1227}
1228
1229/**
1230 * Destro the URB I/O thread.
1231 *
1232 * @returns VBox status code.
1233 * @param pDev The VUSB device.
1234 */
1235int vusbDevUrbIoThreadDestroy(PVUSBDEV pDev)
1236{
1237 int rc = VINF_SUCCESS;
1238 int rcThread = VINF_SUCCESS;
1239
1240 ASMAtomicXchgBool(&pDev->fTerminate, true);
1241 vusbDevUrbIoThreadWakeup(pDev);
1242
1243 rc = RTThreadWait(pDev->hUrbIoThread, RT_INDEFINITE_WAIT, &rcThread);
1244 if (RT_SUCCESS(rc))
1245 rc = rcThread;
1246
1247 pDev->hUrbIoThread = NIL_RTTHREAD;
1248
1249 return rc;
1250}
1251
1252
1253/**
1254 * Attaches a device to the given hub.
1255 *
1256 * @returns VBox status code.
1257 * @param pDev The device to attach.
1258 * @param pHub The roothub to attach to.
1259 */
1260int vusbDevAttach(PVUSBDEV pDev, PVUSBROOTHUB pHub)
1261{
1262 AssertMsg(pDev->enmState == VUSB_DEVICE_STATE_DETACHED, ("enmState=%d\n", pDev->enmState));
1263
1264 pDev->pHub = pHub;
1265 pDev->enmState = VUSB_DEVICE_STATE_ATTACHED;
1266
1267 /* noone else ever messes with the default pipe while we are attached */
1268 vusbDevMapEndpoint(pDev, &g_Endpoint0);
1269 vusbDevDoSelectConfig(pDev, &g_Config0);
1270
1271 /* Create I/O thread and attach to the hub. */
1272 int rc = vusbDevUrbIoThreadCreate(pDev);
1273 if (RT_FAILURE(rc))
1274 {
1275 pDev->pHub = NULL;
1276 pDev->enmState = VUSB_DEVICE_STATE_DETACHED;
1277 }
1278
1279 return rc;
1280}
1281
1282
1283/**
1284 * Detaches a device from the hub it's attached to.
1285 *
1286 * @returns VBox status code.
1287 * @param pDev The device to detach.
1288 *
1289 * @remark This can be called in any state but reset.
1290 */
1291int vusbDevDetach(PVUSBDEV pDev)
1292{
1293 LogFlow(("vusbDevDetach: pDev=%p[%s] enmState=%#x\n", pDev, pDev->pUsbIns->pszName, pDev->enmState));
1294 VUSBDEV_ASSERT_VALID_STATE(pDev->enmState);
1295 Assert(pDev->enmState != VUSB_DEVICE_STATE_RESET);
1296
1297 /*
1298 * Destroy I/O thread and request queue last because they might still be used
1299 * when cancelling URBs.
1300 */
1301 vusbDevUrbIoThreadDestroy(pDev);
1302
1303 vusbDevSetState(pDev, VUSB_DEVICE_STATE_DETACHED);
1304 pDev->pHub = NULL;
1305
1306 /* Remove the configuration */
1307 pDev->pCurCfgDesc = NULL;
1308 for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
1309 vusbDevResetPipeData(&pDev->aPipes[i]);
1310 return VINF_SUCCESS;
1311}
1312
1313
1314/**
1315 * Destroys a device, detaching it from the hub if necessary.
1316 *
1317 * @param pDev The device.
1318 * @thread any.
1319 */
1320void vusbDevDestroy(PVUSBDEV pDev)
1321{
1322 LogFlow(("vusbDevDestroy: pDev=%p[%s] enmState=%d\n", pDev, pDev->pUsbIns->pszName, pDev->enmState));
1323
1324 RTMemFree(pDev->paIfStates);
1325
1326 PDMUsbHlpTimerDestroy(pDev->pUsbIns, pDev->hResetTimer);
1327 pDev->hResetTimer = NIL_TMTIMERHANDLE;
1328
1329 for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
1330 {
1331 Assert(pDev->aPipes[i].pCtrl == NULL);
1332 RTCritSectDelete(&pDev->aPipes[i].CritSectCtrl);
1333 }
1334
1335 if (pDev->hSniffer != VUSBSNIFFER_NIL)
1336 VUSBSnifferDestroy(pDev->hSniffer);
1337
1338 vusbUrbPoolDestroy(&pDev->UrbPool);
1339
1340 int rc = RTReqQueueDestroy(pDev->hReqQueueSync);
1341 AssertRC(rc);
1342 pDev->hReqQueueSync = NIL_RTREQQUEUE;
1343
1344 RTCritSectDelete(&pDev->CritSectAsyncUrbs);
1345 /* Not using vusbDevSetState() deliberately here because it would assert on the state. */
1346 pDev->enmState = VUSB_DEVICE_STATE_DESTROYED;
1347 pDev->pUsbIns->pvVUsbDev2 = NULL;
1348 RTMemFree(pDev);
1349}
1350
1351
1352/* -=-=-=-=-=- VUSBIDEVICE methods -=-=-=-=-=- */
1353
1354
1355/**
1356 * The actual reset has been done, do completion on EMT.
1357 *
1358 * There are several things we have to do now, like set default
1359 * config and address, and cleanup the state of control pipes.
1360 *
1361 * It's possible that the device has a delayed destroy request
1362 * pending when we get here. This can happen for async resetting.
1363 * We deal with it here, since we're now executing on the EMT
1364 * thread and the destruction will be properly serialized now.
1365 *
1366 * @param pDev The device that is being reset.
1367 * @param rc The vusbDevResetWorker return code.
1368 * @param pfnDone The done callback specified by the caller of vusbDevReset().
1369 * @param pvUser The user argument for the callback.
1370 */
1371static void vusbDevResetDone(PVUSBDEV pDev, int rc, PFNVUSBRESETDONE pfnDone, void *pvUser)
1372{
1373 VUSBDEV_ASSERT_VALID_STATE(pDev->enmState);
1374 Assert(pDev->enmState == VUSB_DEVICE_STATE_RESET);
1375
1376 /*
1377 * Do control pipe cleanup regardless of state and result.
1378 */
1379 for (unsigned i = 0; i < VUSB_PIPE_MAX; i++)
1380 if (pDev->aPipes[i].pCtrl)
1381 vusbMsgResetExtraData(pDev->aPipes[i].pCtrl);
1382
1383 /*
1384 * Switch to the default state.
1385 */
1386 vusbDevSetState(pDev, VUSB_DEVICE_STATE_DEFAULT);
1387 pDev->u16Status = 0;
1388 vusbDevDoSelectConfig(pDev, &g_Config0);
1389 vusbDevSetAddress(pDev, VUSB_DEFAULT_ADDRESS);
1390 if (pfnDone)
1391 pfnDone(&pDev->IDevice, pDev->i16Port, rc, pvUser);
1392}
1393
1394
1395/**
1396 * @callback_method_impl{FNTMTIMERUSB,
1397 * Timer callback for doing reset completion.}
1398 */
1399static DECLCALLBACK(void) vusbDevResetDoneTimer(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, void *pvUser)
1400{
1401 PVUSBDEV pDev = (PVUSBDEV)pvUser;
1402 PVUSBRESETARGS pArgs = (PVUSBRESETARGS)pDev->pvArgs;
1403 Assert(pDev->pUsbIns == pUsbIns);
1404 RT_NOREF(pUsbIns, hTimer);
1405
1406 AssertPtr(pArgs);
1407
1408 /*
1409 * Reset-done processing and cleanup.
1410 */
1411 pDev->pvArgs = NULL;
1412 vusbDevResetDone(pDev, pArgs->rc, pArgs->pfnDone, pArgs->pvUser);
1413 RTMemFree(pArgs);
1414}
1415
1416
1417/**
1418 * Perform the actual reset.
1419 *
1420 * @thread EMT or a VUSB reset thread.
1421 */
1422static DECLCALLBACK(int) vusbDevResetWorker(PVUSBDEV pDev, bool fResetOnLinux, bool fUseTimer, PVUSBRESETARGS pArgs)
1423{
1424 uint64_t const uTimerDeadline = !fUseTimer ? 0
1425 : PDMUsbHlpTimerGet(pDev->pUsbIns, pDev->hResetTimer)
1426 + PDMUsbHlpTimerFromMilli(pDev->pUsbIns, pDev->hResetTimer, 10);
1427
1428 int rc = VINF_SUCCESS;
1429 if (pDev->pUsbIns->pReg->pfnUsbReset)
1430 rc = pDev->pUsbIns->pReg->pfnUsbReset(pDev->pUsbIns, fResetOnLinux);
1431
1432 if (pArgs)
1433 {
1434 pArgs->rc = rc;
1435 rc = VINF_SUCCESS;
1436 }
1437
1438 if (fUseTimer)
1439 {
1440 /*
1441 * We use a timer to communicate the result back to EMT.
1442 * This avoids suspend + poweroff issues, and it should give
1443 * us more accurate scheduling than making this thread sleep.
1444 */
1445 int rc2 = PDMUsbHlpTimerSet(pDev->pUsbIns, pDev->hResetTimer, uTimerDeadline);
1446 AssertReleaseRC(rc2);
1447 }
1448
1449 LogFlow(("vusbDevResetWorker: %s: returns %Rrc\n", pDev->pUsbIns->pszName, rc));
1450 return rc;
1451}
1452
1453
1454/**
1455 * Resets a device.
1456 *
1457 * Since a device reset shall take at least 10ms from the guest point of view,
1458 * it must be performed asynchronously. We create a thread which performs this
1459 * operation and ensures it will take at least 10ms.
1460 *
1461 * At times - like init - a synchronous reset is required, this can be done
1462 * by passing NULL for pfnDone.
1463 *
1464 * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state.
1465 * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful,
1466 * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed.
1467 *
1468 * @returns VBox status code.
1469 *
1470 * @param pDevice Pointer to the VUSB device interface.
1471 * @param fResetOnLinux Whether it's safe to reset the device(s) on a linux
1472 * host system. See discussion of logical reconnects elsewhere.
1473 * @param pfnDone Pointer to the completion routine. If NULL a synchronous
1474 * reset is preformed not respecting the 10ms.
1475 * @param pvUser Opaque user data to pass to the done callback.
1476 * @param pVM Pointer to the VM handle for performing the done function
1477 * on the EMT thread.
1478 * @thread EMT
1479 */
1480static DECLCALLBACK(int) vusbIDeviceReset(PVUSBIDEVICE pDevice, bool fResetOnLinux,
1481 PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
1482{
1483 RT_NOREF(pVM);
1484 PVUSBDEV pDev = (PVUSBDEV)pDevice;
1485 Assert(!pfnDone || pVM);
1486 LogFlow(("vusb: reset: [%s]/%i\n", pDev->pUsbIns->pszName, pDev->i16Port));
1487
1488 /*
1489 * Only one reset operation at a time.
1490 */
1491 const VUSBDEVICESTATE enmStateOld = vusbDevSetState(pDev, VUSB_DEVICE_STATE_RESET);
1492 if (enmStateOld == VUSB_DEVICE_STATE_RESET)
1493 {
1494 LogRel(("VUSB: %s: reset request is ignored, the device is already resetting!\n", pDev->pUsbIns->pszName));
1495 return VERR_VUSB_DEVICE_IS_RESETTING;
1496 }
1497
1498 /*
1499 * First, cancel all async URBs.
1500 */
1501 vusbDevCancelAllUrbs(pDev, false);
1502
1503 /* Async or sync? */
1504 if (pfnDone)
1505 {
1506 /*
1507 * Async fashion.
1508 */
1509 PVUSBRESETARGS pArgs = (PVUSBRESETARGS)RTMemTmpAlloc(sizeof(*pArgs));
1510 if (pArgs)
1511 {
1512 pArgs->pDev = pDev;
1513 pArgs->pfnDone = pfnDone;
1514 pArgs->pvUser = pvUser;
1515 pArgs->rc = VINF_SUCCESS;
1516 AssertPtrNull(pDev->pvArgs);
1517 pDev->pvArgs = pArgs;
1518 int rc = vusbDevIoThreadExec(pDev, 0 /* fFlags */, (PFNRT)vusbDevResetWorker, 4, pDev, fResetOnLinux, true, pArgs);
1519 if (RT_SUCCESS(rc))
1520 return rc;
1521
1522 RTMemTmpFree(pArgs);
1523 }
1524 /* fall back to sync on failure */
1525 }
1526
1527 /*
1528 * Sync fashion.
1529 */
1530 int rc = vusbDevResetWorker(pDev, fResetOnLinux, false, NULL);
1531 vusbDevResetDone(pDev, rc, pfnDone, pvUser);
1532 return rc;
1533}
1534
1535
1536/**
1537 * Powers on the device.
1538 *
1539 * @returns VBox status code.
1540 * @param pInterface Pointer to the device interface structure.
1541 */
1542static DECLCALLBACK(int) vusbIDevicePowerOn(PVUSBIDEVICE pInterface)
1543{
1544 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1545 LogFlow(("vusbDevPowerOn: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
1546
1547 /*
1548 * Check that the device is in a valid state.
1549 */
1550 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
1551 if (enmState == VUSB_DEVICE_STATE_DETACHED)
1552 {
1553 Log(("vusb: warning: attempt to power on detached device %p[%s]\n", pDev, pDev->pUsbIns->pszName));
1554 return VERR_VUSB_DEVICE_NOT_ATTACHED;
1555 }
1556 if (enmState == VUSB_DEVICE_STATE_RESET)
1557 {
1558 LogRel(("VUSB: %s: power on ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
1559 return VERR_VUSB_DEVICE_IS_RESETTING;
1560 }
1561
1562 /*
1563 * Do the job.
1564 */
1565 if (enmState == VUSB_DEVICE_STATE_ATTACHED)
1566 vusbDevSetState(pDev, VUSB_DEVICE_STATE_POWERED);
1567
1568 return VINF_SUCCESS;
1569}
1570
1571
1572/**
1573 * Powers off the device.
1574 *
1575 * @returns VBox status code.
1576 * @param pInterface Pointer to the device interface structure.
1577 */
1578static DECLCALLBACK(int) vusbIDevicePowerOff(PVUSBIDEVICE pInterface)
1579{
1580 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1581 LogFlow(("vusbDevPowerOff: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
1582
1583 /*
1584 * Check that the device is in a valid state.
1585 */
1586 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
1587 if (enmState == VUSB_DEVICE_STATE_DETACHED)
1588 {
1589 Log(("vusb: warning: attempt to power off detached device %p[%s]\n", pDev, pDev->pUsbIns->pszName));
1590 return VERR_VUSB_DEVICE_NOT_ATTACHED;
1591 }
1592 if (enmState == VUSB_DEVICE_STATE_RESET)
1593 {
1594 LogRel(("VUSB: %s: power off ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
1595 return VERR_VUSB_DEVICE_IS_RESETTING;
1596 }
1597
1598 vusbDevSetState(pDev, VUSB_DEVICE_STATE_ATTACHED);
1599 return VINF_SUCCESS;
1600}
1601
1602
1603/**
1604 * Get the state of the device.
1605 *
1606 * @returns Device state.
1607 * @param pInterface Pointer to the device interface structure.
1608 */
1609static DECLCALLBACK(VUSBDEVICESTATE) vusbIDeviceGetState(PVUSBIDEVICE pInterface)
1610{
1611 return vusbDevGetState((PVUSBDEV)pInterface);
1612}
1613
1614
1615/**
1616 * @interface_method_impl{VUSBIDEVICE,pfnIsSavedStateSupported}
1617 */
1618static DECLCALLBACK(bool) vusbIDeviceIsSavedStateSupported(PVUSBIDEVICE pInterface)
1619{
1620 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1621 bool fSavedStateSupported = RT_BOOL(pDev->pUsbIns->pReg->fFlags & PDM_USBREG_SAVED_STATE_SUPPORTED);
1622
1623 LogFlowFunc(("pInterface=%p\n", pInterface));
1624
1625 LogFlowFunc(("returns %RTbool\n", fSavedStateSupported));
1626 return fSavedStateSupported;
1627}
1628
1629
1630/**
1631 * @interface_method_impl{VUSBIDEVICE,pfnGetState}
1632 */
1633static DECLCALLBACK(VUSBSPEED) vusbIDeviceGetSpeed(PVUSBIDEVICE pInterface)
1634{
1635 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1636 VUSBSPEED enmSpeed = pDev->pUsbIns->enmSpeed;
1637
1638 LogFlowFunc(("pInterface=%p, returns %u\n", pInterface, enmSpeed));
1639 return enmSpeed;
1640}
1641
1642
1643/**
1644 * The maximum number of interfaces the device can have in all of it's configuration.
1645 *
1646 * @returns Number of interfaces.
1647 * @param pDev The device.
1648 */
1649size_t vusbDevMaxInterfaces(PVUSBDEV pDev)
1650{
1651 uint8_t cMax = 0;
1652 unsigned i = pDev->pDescCache->pDevice->bNumConfigurations;
1653 while (i-- > 0)
1654 {
1655 if (pDev->pDescCache->paConfigs[i].Core.bNumInterfaces > cMax)
1656 cMax = pDev->pDescCache->paConfigs[i].Core.bNumInterfaces;
1657 }
1658
1659 return cMax;
1660}
1661
1662
1663/**
1664 * Executes a given function on the I/O thread.
1665 *
1666 * @returns IPRT status code.
1667 * @param pDev The USB device instance data.
1668 * @param fFlags Combination of VUSB_DEV_IO_THREAD_EXEC_FLAGS_*
1669 * @param pfnFunction The function to execute.
1670 * @param cArgs Number of arguments to the function.
1671 * @param Args The parameter list.
1672 *
1673 * @remarks See remarks on RTReqQueueCallV
1674 */
1675DECLHIDDEN(int) vusbDevIoThreadExecV(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args)
1676{
1677 int rc = VINF_SUCCESS;
1678 PRTREQ hReq = NULL;
1679
1680 Assert(pDev->hUrbIoThread != NIL_RTTHREAD);
1681 if (RT_LIKELY(pDev->hUrbIoThread != NIL_RTTHREAD))
1682 {
1683 uint32_t fReqFlags = RTREQFLAGS_IPRT_STATUS;
1684
1685 if (!(fFlags & VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC))
1686 fReqFlags |= RTREQFLAGS_NO_WAIT;
1687
1688 rc = RTReqQueueCallV(pDev->hReqQueueSync, &hReq, 0 /* cMillies */, fReqFlags, pfnFunction, cArgs, Args);
1689 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1690
1691 /* In case we are called on the I/O thread just process the request. */
1692 if ( pDev->hUrbIoThread == RTThreadSelf()
1693 && (fFlags & VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC))
1694 {
1695 int rc2 = RTReqQueueProcess(pDev->hReqQueueSync, 0);
1696 Assert(RT_SUCCESS(rc2) || rc2 == VERR_TIMEOUT); NOREF(rc2);
1697 }
1698 else
1699 vusbDevUrbIoThreadWakeup(pDev);
1700
1701 if ( rc == VERR_TIMEOUT
1702 && (fFlags & VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC))
1703 {
1704 rc = RTReqWait(hReq, RT_INDEFINITE_WAIT);
1705 AssertRC(rc);
1706 }
1707 RTReqRelease(hReq);
1708 }
1709 else
1710 rc = VERR_INVALID_STATE;
1711
1712 return rc;
1713}
1714
1715
1716/**
1717 * Executes a given function on the I/O thread.
1718 *
1719 * @returns IPRT status code.
1720 * @param pDev The USB device instance data.
1721 * @param fFlags Combination of VUSB_DEV_IO_THREAD_EXEC_FLAGS_*
1722 * @param pfnFunction The function to execute.
1723 * @param cArgs Number of arguments to the function.
1724 * @param ... The parameter list.
1725 *
1726 * @remarks See remarks on RTReqQueueCallV
1727 */
1728DECLHIDDEN(int) vusbDevIoThreadExec(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, ...)
1729{
1730 int rc = VINF_SUCCESS;
1731 va_list va;
1732
1733 va_start(va, cArgs);
1734 rc = vusbDevIoThreadExecV(pDev, fFlags, pfnFunction, cArgs, va);
1735 va_end(va);
1736 return rc;
1737}
1738
1739
1740/**
1741 * Executes a given function synchronously on the I/O thread waiting for it to complete.
1742 *
1743 * @returns IPRT status code.
1744 * @param pDev The USB device instance data
1745 * @param pfnFunction The function to execute.
1746 * @param cArgs Number of arguments to the function.
1747 * @param ... The parameter list.
1748 *
1749 * @remarks See remarks on RTReqQueueCallV
1750 */
1751DECLHIDDEN(int) vusbDevIoThreadExecSync(PVUSBDEV pDev, PFNRT pfnFunction, unsigned cArgs, ...)
1752{
1753 int rc = VINF_SUCCESS;
1754 va_list va;
1755
1756 va_start(va, cArgs);
1757 rc = vusbDevIoThreadExecV(pDev, VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC, pfnFunction, cArgs, va);
1758 va_end(va);
1759 return rc;
1760}
1761
1762
1763/**
1764 * Initialize a new VUSB device.
1765 *
1766 * @returns VBox status code.
1767 * @param pDev The VUSB device to initialize.
1768 * @param pUsbIns Pointer to the PDM USB Device instance.
1769 * @param pszCaptureFilename Optional fileame to capture the traffic to.
1770 */
1771int vusbDevInit(PVUSBDEV pDev, PPDMUSBINS pUsbIns, const char *pszCaptureFilename)
1772{
1773 /*
1774 * Initialize the device data members.
1775 * (All that are Non-Zero at least.)
1776 */
1777 Assert(!pDev->IDevice.pfnReset);
1778 Assert(!pDev->IDevice.pfnPowerOn);
1779 Assert(!pDev->IDevice.pfnPowerOff);
1780 Assert(!pDev->IDevice.pfnGetState);
1781 Assert(!pDev->IDevice.pfnIsSavedStateSupported);
1782
1783 pDev->IDevice.pfnReset = vusbIDeviceReset;
1784 pDev->IDevice.pfnPowerOn = vusbIDevicePowerOn;
1785 pDev->IDevice.pfnPowerOff = vusbIDevicePowerOff;
1786 pDev->IDevice.pfnGetState = vusbIDeviceGetState;
1787 pDev->IDevice.pfnIsSavedStateSupported = vusbIDeviceIsSavedStateSupported;
1788 pDev->IDevice.pfnGetSpeed = vusbIDeviceGetSpeed;
1789 pDev->pUsbIns = pUsbIns;
1790 pDev->pHub = NULL;
1791 pDev->enmState = VUSB_DEVICE_STATE_DETACHED;
1792 pDev->cRefs = 1;
1793 pDev->u8Address = VUSB_INVALID_ADDRESS;
1794 pDev->u8NewAddress = VUSB_INVALID_ADDRESS;
1795 pDev->i16Port = -1;
1796 pDev->u16Status = 0;
1797 pDev->pDescCache = NULL;
1798 pDev->pCurCfgDesc = NULL;
1799 pDev->paIfStates = NULL;
1800 RTListInit(&pDev->LstAsyncUrbs);
1801 memset(&pDev->aPipes[0], 0, sizeof(pDev->aPipes));
1802 for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
1803 {
1804 int rc = RTCritSectInit(&pDev->aPipes[i].CritSectCtrl);
1805 AssertRCReturn(rc, rc);
1806 }
1807 pDev->hResetTimer = NIL_TMTIMERHANDLE;
1808 pDev->hSniffer = VUSBSNIFFER_NIL;
1809
1810 int rc = RTCritSectInit(&pDev->CritSectAsyncUrbs);
1811 AssertRCReturn(rc, rc);
1812
1813 /* Create the URB pool. */
1814 rc = vusbUrbPoolInit(&pDev->UrbPool);
1815 AssertRCReturn(rc, rc);
1816
1817 /* Setup request queue executing synchronous tasks on the I/O thread. */
1818 rc = RTReqQueueCreate(&pDev->hReqQueueSync);
1819 AssertRCReturn(rc, rc);
1820
1821 /*
1822 * Create the reset timer. Make sure the name is unique as we're generic code.
1823 */
1824 static uint32_t volatile s_iSeq;
1825 char szDesc[32];
1826 RTStrPrintf(szDesc, sizeof(szDesc), "VUSB Reset #%u", ASMAtomicIncU32(&s_iSeq));
1827 rc = PDMUsbHlpTimerCreate(pDev->pUsbIns, TMCLOCK_VIRTUAL, vusbDevResetDoneTimer, pDev, 0 /*fFlags*/,
1828 szDesc, &pDev->hResetTimer);
1829 AssertRCReturn(rc, rc);
1830
1831 if (pszCaptureFilename)
1832 {
1833 rc = VUSBSnifferCreate(&pDev->hSniffer, 0, pszCaptureFilename, NULL, NULL);
1834 AssertRCReturn(rc, rc);
1835 }
1836
1837 /*
1838 * Get the descriptor cache from the device. (shall cannot fail)
1839 */
1840 pDev->pDescCache = pUsbIns->pReg->pfnUsbGetDescriptorCache(pUsbIns);
1841 AssertPtr(pDev->pDescCache);
1842#ifdef VBOX_STRICT
1843 if (pDev->pDescCache->fUseCachedStringsDescriptors)
1844 {
1845 int32_t iPrevId = -1;
1846 for (unsigned iLang = 0; iLang < pDev->pDescCache->cLanguages; iLang++)
1847 {
1848 Assert((int32_t)pDev->pDescCache->paLanguages[iLang].idLang > iPrevId);
1849 iPrevId = pDev->pDescCache->paLanguages[iLang].idLang;
1850
1851 int32_t idxPrevStr = -1;
1852 PCPDMUSBDESCCACHESTRING paStrings = pDev->pDescCache->paLanguages[iLang].paStrings;
1853 unsigned cStrings = pDev->pDescCache->paLanguages[iLang].cStrings;
1854 for (unsigned iStr = 0; iStr < cStrings; iStr++)
1855 {
1856 Assert((int32_t)paStrings[iStr].idx > idxPrevStr);
1857 idxPrevStr = paStrings[iStr].idx;
1858 size_t cch = strlen(paStrings[iStr].psz);
1859 Assert(cch <= 127);
1860 }
1861 }
1862 }
1863#endif
1864
1865 /*
1866 * Allocate memory for the interface states.
1867 */
1868 size_t cbIface = vusbDevMaxInterfaces(pDev) * sizeof(*pDev->paIfStates);
1869 pDev->paIfStates = (PVUSBINTERFACESTATE)RTMemAllocZ(cbIface);
1870 AssertMsgReturn(pDev->paIfStates, ("RTMemAllocZ(%d) failed\n", cbIface), VERR_NO_MEMORY);
1871
1872 return VINF_SUCCESS;
1873}
1874
1875/*
1876 * Local Variables:
1877 * mode: c
1878 * c-file-style: "bsd"
1879 * c-basic-offset: 4
1880 * tab-width: 4
1881 * indent-tabs-mode: s
1882 * End:
1883 */
1884
Note: See TracBrowser for help on using the repository browser.

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