VirtualBox

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

Last change on this file was 100517, checked in by vboxsync, 10 months ago

VUSB: Explicitly ignore any high bits of a USB address which is a 7-bit quantity (see bugref:10433).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.7 KB
Line 
1/* $Id: VUSBDevice.cpp 100517 2023-07-11 14:54:11Z 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 /*
518 * If wValue has any bits set beyond 0-6, throw them away.
519 */
520 if ((pSetup->wValue & VUSB_ADDRESS_MASK) != pSetup->wValue) {
521 LogRelMax(10, ("VUSB: %s: Warning: Ignoring high bits of requested address (wLength=0x%X), using only lower 7 bits.\n",
522 pDev->pUsbIns->pszName, pSetup->wValue));
523
524 pSetup->wValue &= VUSB_ADDRESS_MASK;
525 }
526
527 pDev->u8NewAddress = pSetup->wValue;
528 return true;
529}
530
531/**
532 * Standard device request: CLEAR_FEATURE
533 * @returns success indicator.
534 *
535 * @remark This is only called for VUSB_TO_ENDPOINT && ep == 0 && wValue == ENDPOINT_HALT.
536 * All other cases of CLEAR_FEATURE is handled in the normal async/sync manner.
537 */
538static bool vusbDevStdReqClearFeature(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
539{
540 RT_NOREF(pbBuf, pcbBuf);
541 switch (pSetup->bmRequestType & VUSB_RECIP_MASK)
542 {
543 case VUSB_TO_DEVICE:
544 Log(("vusb: ClearFeature: dev(%u): selector=%u\n", pSetup->wIndex, pSetup->wValue));
545 break;
546 case VUSB_TO_INTERFACE:
547 Log(("vusb: ClearFeature: iface(%u): selector=%u\n", pSetup->wIndex, pSetup->wValue));
548 break;
549 case VUSB_TO_ENDPOINT:
550 Log(("vusb: ClearFeature: ep(%u): selector=%u\n", pSetup->wIndex, pSetup->wValue));
551 if ( !EndPt /* Default control pipe only */
552 && pSetup->wValue == 0 /* ENDPOINT_HALT */
553 && pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint)
554 {
555 RTCritSectEnter(&pDev->pHub->CritSectDevices);
556 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint,
557 2, pDev->pUsbIns, pSetup->wIndex);
558 RTCritSectLeave(&pDev->pHub->CritSectDevices);
559 return RT_SUCCESS(rc);
560 }
561 break;
562 default:
563 AssertMsgFailed(("VUSB_TO_OTHER!\n"));
564 break;
565 }
566
567 AssertMsgFailed(("Invalid safe check !!!\n"));
568 return false;
569}
570
571/**
572 * Standard device request: SET_FEATURE
573 * @returns success indicator.
574 */
575static bool vusbDevStdReqSetFeature(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
576{
577 RT_NOREF(pDev, EndPt, pbBuf, pcbBuf);
578 switch (pSetup->bmRequestType & VUSB_RECIP_MASK)
579 {
580 case VUSB_TO_DEVICE:
581 Log(("vusb: SetFeature: dev(%u): selector=%u\n",
582 pSetup->wIndex, pSetup->wValue));
583 break;
584 case VUSB_TO_INTERFACE:
585 Log(("vusb: SetFeature: if(%u): selector=%u\n",
586 pSetup->wIndex, pSetup->wValue));
587 break;
588 case VUSB_TO_ENDPOINT:
589 Log(("vusb: SetFeature: ep(%u): selector=%u\n",
590 pSetup->wIndex, pSetup->wValue));
591 break;
592 default:
593 AssertMsgFailed(("VUSB_TO_OTHER!\n"));
594 return false;
595 }
596 AssertMsgFailed(("This stuff is bogus\n"));
597 return false;
598}
599
600static bool vusbDevStdReqGetStatus(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
601{
602 RT_NOREF(EndPt);
603 if (*pcbBuf != 2)
604 {
605 LogFlow(("vusbDevStdReqGetStatus: %s: buffer is too small! (%d)\n", pDev->pUsbIns->pszName, *pcbBuf));
606 return false;
607 }
608
609 uint16_t u16Status;
610 switch (pSetup->bmRequestType & VUSB_RECIP_MASK)
611 {
612 case VUSB_TO_DEVICE:
613 u16Status = pDev->u16Status;
614 LogFlow(("vusbDevStdReqGetStatus: %s: device status %#x (%d)\n", pDev->pUsbIns->pszName, u16Status, u16Status));
615 break;
616 case VUSB_TO_INTERFACE:
617 u16Status = 0;
618 LogFlow(("vusbDevStdReqGetStatus: %s: bogus interface status request!!\n", pDev->pUsbIns->pszName));
619 break;
620 case VUSB_TO_ENDPOINT:
621 u16Status = 0;
622 LogFlow(("vusbDevStdReqGetStatus: %s: bogus endpoint status request!!\n", pDev->pUsbIns->pszName));
623 break;
624 default:
625 AssertMsgFailed(("VUSB_TO_OTHER!\n"));
626 return false;
627 }
628
629 *(uint16_t *)pbBuf = u16Status;
630 return true;
631}
632
633
634/**
635 * Finds a cached string.
636 *
637 * @returns Pointer to the cached string if found. NULL if not.
638 * @param paLanguages The languages to search.
639 * @param cLanguages The number of languages in the table.
640 * @param idLang The language ID.
641 * @param iString The string index.
642 */
643static PCPDMUSBDESCCACHESTRING FindCachedString(PCPDMUSBDESCCACHELANG paLanguages, unsigned cLanguages,
644 uint16_t idLang, uint8_t iString)
645{
646 /** @todo binary lookups! */
647 unsigned iCurLang = cLanguages;
648 while (iCurLang-- > 0)
649 if (paLanguages[iCurLang].idLang == idLang)
650 {
651 PCPDMUSBDESCCACHESTRING paStrings = paLanguages[iCurLang].paStrings;
652 unsigned iCurStr = paLanguages[iCurLang].cStrings;
653 while (iCurStr-- > 0)
654 if (paStrings[iCurStr].idx == iString)
655 return &paStrings[iCurStr];
656 break;
657 }
658 return NULL;
659}
660
661
662/** Macro for copying descriptor data. */
663#define COPY_DATA(pbDst, cbLeft, pvSrc, cbSrc) \
664 do { \
665 uint32_t cbSrc_ = cbSrc; \
666 uint32_t cbCopy = RT_MIN(cbLeft, cbSrc_); \
667 if (cbCopy) \
668 memcpy(pbBuf, pvSrc, cbCopy); \
669 cbLeft -= cbCopy; \
670 if (!cbLeft) \
671 return; \
672 pbBuf += cbCopy; \
673 } while (0)
674
675/**
676 * Internal function for reading the language IDs.
677 */
678static void ReadCachedStringDesc(PCPDMUSBDESCCACHESTRING pString, uint8_t *pbBuf, uint32_t *pcbBuf)
679{
680 uint32_t cbLeft = *pcbBuf;
681
682 RTUTF16 wsz[128]; /* 128-1 => bLength=0xff */
683 PRTUTF16 pwsz = wsz;
684 size_t cwc;
685 int rc = RTStrToUtf16Ex(pString->psz, RT_ELEMENTS(wsz) - 1, &pwsz, RT_ELEMENTS(wsz), &cwc);
686 if (RT_FAILURE(rc))
687 {
688 AssertRC(rc);
689 wsz[0] = 'e';
690 wsz[1] = 'r';
691 wsz[2] = 'r';
692 cwc = 3;
693 }
694
695 VUSBDESCSTRING StringDesc;
696 StringDesc.bLength = (uint8_t)(sizeof(StringDesc) + cwc * sizeof(RTUTF16));
697 StringDesc.bDescriptorType = VUSB_DT_STRING;
698 COPY_DATA(pbBuf, cbLeft, &StringDesc, sizeof(StringDesc));
699 COPY_DATA(pbBuf, cbLeft, wsz, (uint32_t)cwc * sizeof(RTUTF16));
700
701 /* updated the size of the output buffer. */
702 *pcbBuf -= cbLeft;
703}
704
705
706/**
707 * Internal function for reading the language IDs.
708 */
709static void ReadCachedLangIdDesc(PCPDMUSBDESCCACHELANG paLanguages, unsigned cLanguages,
710 uint8_t *pbBuf, uint32_t *pcbBuf)
711{
712 uint32_t cbLeft = *pcbBuf;
713
714 VUSBDESCLANGID LangIdDesc;
715 size_t cbDesc = sizeof(LangIdDesc) + cLanguages * sizeof(paLanguages[0].idLang);
716 LangIdDesc.bLength = (uint8_t)RT_MIN(0xff, cbDesc);
717 LangIdDesc.bDescriptorType = VUSB_DT_STRING;
718 COPY_DATA(pbBuf, cbLeft, &LangIdDesc, sizeof(LangIdDesc));
719
720 unsigned iLanguage = cLanguages;
721 while (iLanguage-- > 0)
722 COPY_DATA(pbBuf, cbLeft, &paLanguages[iLanguage].idLang, sizeof(paLanguages[iLanguage].idLang));
723
724 /* updated the size of the output buffer. */
725 *pcbBuf -= cbLeft;
726}
727
728
729/**
730 * Internal function which performs a descriptor read on the cached descriptors.
731 */
732static void ReadCachedConfigDesc(PCVUSBDESCCONFIGEX pCfgDesc, uint8_t *pbBuf, uint32_t *pcbBuf)
733{
734 uint32_t cbLeft = *pcbBuf;
735
736 /*
737 * Make a copy of the config descriptor and calculate the wTotalLength field.
738 */
739 VUSBDESCCONFIG CfgDesc;
740 memcpy(&CfgDesc, pCfgDesc, VUSB_DT_CONFIG_MIN_LEN);
741 uint32_t cbTotal = 0;
742 cbTotal += pCfgDesc->Core.bLength;
743 cbTotal += pCfgDesc->cbClass;
744 for (unsigned i = 0; i < pCfgDesc->Core.bNumInterfaces; i++)
745 {
746 PCVUSBINTERFACE pIf = &pCfgDesc->paIfs[i];
747 for (uint32_t j = 0; j < pIf->cSettings; j++)
748 {
749 cbTotal += pIf->paSettings[j].cbIAD;
750 cbTotal += pIf->paSettings[j].Core.bLength;
751 cbTotal += pIf->paSettings[j].cbClass;
752 for (unsigned k = 0; k < pIf->paSettings[j].Core.bNumEndpoints; k++)
753 {
754 cbTotal += pIf->paSettings[j].paEndpoints[k].Core.bLength;
755 cbTotal += pIf->paSettings[j].paEndpoints[k].cbSsepc;
756 cbTotal += pIf->paSettings[j].paEndpoints[k].cbClass;
757 }
758 }
759 }
760 CfgDesc.wTotalLength = RT_H2LE_U16(cbTotal);
761
762 /*
763 * Copy the config descriptor
764 */
765 COPY_DATA(pbBuf, cbLeft, &CfgDesc, VUSB_DT_CONFIG_MIN_LEN);
766 COPY_DATA(pbBuf, cbLeft, pCfgDesc->pvMore, pCfgDesc->Core.bLength - VUSB_DT_CONFIG_MIN_LEN);
767 COPY_DATA(pbBuf, cbLeft, pCfgDesc->pvClass, pCfgDesc->cbClass);
768
769 /*
770 * Copy out all the interfaces for this configuration
771 */
772 for (unsigned i = 0; i < pCfgDesc->Core.bNumInterfaces; i++)
773 {
774 PCVUSBINTERFACE pIf = &pCfgDesc->paIfs[i];
775 for (uint32_t j = 0; j < pIf->cSettings; j++)
776 {
777 PCVUSBDESCINTERFACEEX pIfDesc = &pIf->paSettings[j];
778
779 COPY_DATA(pbBuf, cbLeft, pIfDesc->pIAD, pIfDesc->cbIAD);
780 COPY_DATA(pbBuf, cbLeft, pIfDesc, VUSB_DT_INTERFACE_MIN_LEN);
781 COPY_DATA(pbBuf, cbLeft, pIfDesc->pvMore, pIfDesc->Core.bLength - VUSB_DT_INTERFACE_MIN_LEN);
782 COPY_DATA(pbBuf, cbLeft, pIfDesc->pvClass, pIfDesc->cbClass);
783
784 /*
785 * Copy out all the endpoints for this interface
786 */
787 for (unsigned k = 0; k < pIfDesc->Core.bNumEndpoints; k++)
788 {
789 VUSBDESCENDPOINT EndPtDesc;
790 memcpy(&EndPtDesc, &pIfDesc->paEndpoints[k], VUSB_DT_ENDPOINT_MIN_LEN);
791 EndPtDesc.wMaxPacketSize = RT_H2LE_U16(EndPtDesc.wMaxPacketSize);
792
793 COPY_DATA(pbBuf, cbLeft, &EndPtDesc, VUSB_DT_ENDPOINT_MIN_LEN);
794 COPY_DATA(pbBuf, cbLeft, pIfDesc->paEndpoints[k].pvMore, EndPtDesc.bLength - VUSB_DT_ENDPOINT_MIN_LEN);
795 COPY_DATA(pbBuf, cbLeft, pIfDesc->paEndpoints[k].pvSsepc, pIfDesc->paEndpoints[k].cbSsepc);
796 COPY_DATA(pbBuf, cbLeft, pIfDesc->paEndpoints[k].pvClass, pIfDesc->paEndpoints[k].cbClass);
797 }
798 }
799 }
800
801 /* updated the size of the output buffer. */
802 *pcbBuf -= cbLeft;
803}
804
805/**
806 * Internal function which performs a descriptor read on the cached descriptors.
807 */
808static void ReadCachedDeviceDesc(PCVUSBDESCDEVICE pDevDesc, uint8_t *pbBuf, uint32_t *pcbBuf)
809{
810 uint32_t cbLeft = *pcbBuf;
811
812 /*
813 * Duplicate the device description and update some fields we keep in cpu type.
814 */
815 Assert(sizeof(VUSBDESCDEVICE) == 18);
816 VUSBDESCDEVICE DevDesc = *pDevDesc;
817 DevDesc.bcdUSB = RT_H2LE_U16(DevDesc.bcdUSB);
818 DevDesc.idVendor = RT_H2LE_U16(DevDesc.idVendor);
819 DevDesc.idProduct = RT_H2LE_U16(DevDesc.idProduct);
820 DevDesc.bcdDevice = RT_H2LE_U16(DevDesc.bcdDevice);
821
822 COPY_DATA(pbBuf, cbLeft, &DevDesc, sizeof(DevDesc));
823 COPY_DATA(pbBuf, cbLeft, pDevDesc + 1, pDevDesc->bLength - sizeof(DevDesc));
824
825 /* updated the size of the output buffer. */
826 *pcbBuf -= cbLeft;
827}
828
829#undef COPY_DATA
830
831/**
832 * Checks whether a descriptor read can be satisfied by reading from the
833 * descriptor cache or has to be passed to the device.
834 * If we have descriptors cached, it is generally safe to satisfy descriptor reads
835 * from the cache. As usual, there is broken USB software and hardware out there
836 * and guests might try to read a nonexistent desciptor (out of range index for
837 * string or configuration descriptor) and rely on it not failing.
838 * Since we cannot very well guess if such invalid requests should really succeed,
839 * and what exactly should happen if they do, we pass such requests to the device.
840 * If the descriptor was cached because it was edited, and the guest bypasses the
841 * edited cache by reading a descriptor with an invalid index, it is probably
842 * best to smash the USB device with a large hammer.
843 *
844 * See @bugref{10016}.
845 *
846 * @returns false if request must be passed to device.
847 */
848bool vusbDevIsDescriptorInCache(PVUSBDEV pDev, PCVUSBSETUP pSetup)
849{
850 unsigned int iIndex = (pSetup->wValue & 0xff);
851 Assert(pSetup->bRequest == VUSB_REQ_GET_DESCRIPTOR);
852
853 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) == VUSB_TO_DEVICE)
854 {
855 if (pDev->pDescCache->fUseCachedDescriptors)
856 {
857 switch (pSetup->wValue >> 8)
858 {
859 case VUSB_DT_DEVICE:
860 if (iIndex == 0)
861 return true;
862
863 LogRelMax(10, ("VUSB: %s: Warning: Reading device descriptor with non-zero index %u (wLength=%u), passing request to device\n",
864 pDev->pUsbIns->pszName, iIndex, pSetup->wLength));
865 break;
866
867 case VUSB_DT_CONFIG:
868 if (iIndex < pDev->pDescCache->pDevice->bNumConfigurations)
869 return true;
870
871 LogRelMax(10, ("VUSB: %s: Warning: Reading configuration descriptor invalid index %u (bNumConfigurations=%u, wLength=%u), passing request to device\n",
872 pDev->pUsbIns->pszName, iIndex, pDev->pDescCache->pDevice->bNumConfigurations, pSetup->wLength));
873 break;
874
875 case VUSB_DT_STRING:
876 if (pDev->pDescCache->fUseCachedStringsDescriptors)
877 {
878 if (pSetup->wIndex == 0) /* Language IDs. */
879 return true;
880
881 if (FindCachedString(pDev->pDescCache->paLanguages, pDev->pDescCache->cLanguages,
882 pSetup->wIndex, iIndex))
883 return true;
884 }
885 break;
886
887 default:
888 break;
889 }
890 Log(("VUSB: %s: Descriptor not cached: type=%u descidx=%u lang=%u len=%u, passing request to device\n",
891 pDev->pUsbIns->pszName, pSetup->wValue >> 8, iIndex, pSetup->wIndex, pSetup->wLength));
892 }
893 }
894 return false;
895}
896
897
898/**
899 * Standard device request: GET_DESCRIPTOR
900 * @returns success indicator.
901 */
902static bool vusbDevStdReqGetDescriptor(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, uint8_t *pbBuf, uint32_t *pcbBuf)
903{
904 RT_NOREF(EndPt);
905 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) == VUSB_TO_DEVICE)
906 {
907 switch (pSetup->wValue >> 8)
908 {
909 case VUSB_DT_DEVICE:
910 ReadCachedDeviceDesc(pDev->pDescCache->pDevice, pbBuf, pcbBuf);
911 LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of device descriptors\n", pDev->pUsbIns->pszName, *pcbBuf));
912 return true;
913
914 case VUSB_DT_CONFIG:
915 {
916 unsigned int iIndex = (pSetup->wValue & 0xff);
917 if (iIndex >= pDev->pDescCache->pDevice->bNumConfigurations)
918 {
919 LogFlow(("vusbDevStdReqGetDescriptor: %s: iIndex=%u >= bNumConfigurations=%d !!!\n",
920 pDev->pUsbIns->pszName, iIndex, pDev->pDescCache->pDevice->bNumConfigurations));
921 return false;
922 }
923 ReadCachedConfigDesc(&pDev->pDescCache->paConfigs[iIndex], pbBuf, pcbBuf);
924 LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of config descriptors\n", pDev->pUsbIns->pszName, *pcbBuf));
925 return true;
926 }
927
928 case VUSB_DT_STRING:
929 {
930 if (pSetup->wIndex == 0)
931 {
932 ReadCachedLangIdDesc(pDev->pDescCache->paLanguages, pDev->pDescCache->cLanguages, pbBuf, pcbBuf);
933 LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of language ID (string) descriptors\n", pDev->pUsbIns->pszName, *pcbBuf));
934 return true;
935 }
936 PCPDMUSBDESCCACHESTRING pString;
937 pString = FindCachedString(pDev->pDescCache->paLanguages, pDev->pDescCache->cLanguages,
938 pSetup->wIndex, pSetup->wValue & 0xff);
939 if (pString)
940 {
941 ReadCachedStringDesc(pString, pbBuf, pcbBuf);
942 LogFlow(("vusbDevStdReqGetDescriptor: %s: %u bytes of string descriptors \"%s\"\n",
943 pDev->pUsbIns->pszName, *pcbBuf, pString->psz));
944 return true;
945 }
946 break;
947 }
948
949 default:
950 break;
951 }
952 }
953 Log(("vusb: %s: warning: unknown descriptor: type=%u descidx=%u lang=%u len=%u!!!\n",
954 pDev->pUsbIns->pszName, pSetup->wValue >> 8, pSetup->wValue & 0xff, pSetup->wIndex, pSetup->wLength));
955 return false;
956}
957
958
959/**
960 * Service the standard USB requests.
961 *
962 * Devices may call this from controlmsg() if you want vusb core to handle your standard
963 * request, it's not necessary - you could handle them manually
964 *
965 * @param pDev The device.
966 * @param EndPoint The endpoint.
967 * @param pSetup Pointer to the setup request structure.
968 * @param pvBuf Buffer?
969 * @param pcbBuf ?
970 */
971bool vusbDevStandardRequest(PVUSBDEV pDev, int EndPoint, PVUSBSETUP pSetup, void *pvBuf, uint32_t *pcbBuf)
972{
973 static bool (* const s_apfnStdReq[VUSB_REQ_MAX])(PVUSBDEV, int, PVUSBSETUP, uint8_t *, uint32_t *) =
974 {
975 vusbDevStdReqGetStatus,
976 vusbDevStdReqClearFeature,
977 NULL,
978 vusbDevStdReqSetFeature,
979 NULL,
980 vusbDevStdReqSetAddress,
981 vusbDevStdReqGetDescriptor,
982 NULL,
983 vusbDevStdReqGetConfig,
984 vusbDevStdReqSetConfig,
985 vusbDevStdReqGetInterface,
986 vusbDevStdReqSetInterface,
987 NULL /* for iso */
988 };
989
990 /*
991 * Check that the device is in a valid state.
992 */
993 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
994 if (enmState == VUSB_DEVICE_STATE_RESET)
995 {
996 LogRel(("VUSB: %s: standard control message ignored, the device is resetting\n", pDev->pUsbIns->pszName));
997 return false;
998 }
999
1000 /*
1001 * Do the request if it's one we want to deal with.
1002 */
1003 if ( pSetup->bRequest >= VUSB_REQ_MAX
1004 || !s_apfnStdReq[pSetup->bRequest])
1005 {
1006 Log(("vusb: warning: standard req not implemented: message %u: val=%u idx=%u len=%u !!!\n",
1007 pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1008 return false;
1009 }
1010
1011 return s_apfnStdReq[pSetup->bRequest](pDev, EndPoint, pSetup, (uint8_t *)pvBuf, pcbBuf);
1012}
1013
1014
1015/**
1016 * Sets the address of a device.
1017 *
1018 * Called by status_completion() and vusbDevResetWorker().
1019 */
1020void vusbDevSetAddress(PVUSBDEV pDev, uint8_t u8Address)
1021{
1022 LogFlow(("vusbDevSetAddress: pDev=%p[%s]/%i u8Address=%#x\n",
1023 pDev, pDev->pUsbIns->pszName, pDev->i16Port, u8Address));
1024
1025 /*
1026 * Check that the device is in a valid state.
1027 */
1028 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
1029 VUSBDEV_ASSERT_VALID_STATE(enmState);
1030 if ( enmState == VUSB_DEVICE_STATE_ATTACHED
1031 || enmState == VUSB_DEVICE_STATE_DETACHED)
1032 {
1033 LogFlow(("vusbDevSetAddress: %s: fails because %d < POWERED\n", pDev->pUsbIns->pszName, pDev->enmState));
1034 return;
1035 }
1036 if (enmState == VUSB_DEVICE_STATE_RESET)
1037 {
1038 LogRel(("VUSB: %s: set address ignored, the device is resetting\n", pDev->pUsbIns->pszName));
1039 return;
1040 }
1041
1042 /* Paranoia. */
1043 Assert((u8Address & VUSB_ADDRESS_MASK) == u8Address);
1044 u8Address &= VUSB_ADDRESS_MASK;
1045
1046 /*
1047 * Ok, get on with it.
1048 */
1049 if (pDev->u8Address == u8Address)
1050 return;
1051
1052 /** @todo The following logic belongs to the roothub and should actually be in that file. */
1053 PVUSBROOTHUB pRh = vusbDevGetRh(pDev);
1054 AssertPtrReturnVoid(pRh);
1055
1056 RTCritSectEnter(&pRh->CritSectDevices);
1057
1058 /* Remove the device from the current address. */
1059 if (pDev->u8Address != VUSB_INVALID_ADDRESS)
1060 {
1061 Assert(pRh->apDevByAddr[pDev->u8Address] == pDev);
1062 pRh->apDevByAddr[pDev->u8Address] = NULL;
1063 }
1064
1065 if (u8Address == VUSB_DEFAULT_ADDRESS)
1066 {
1067 PVUSBDEV pDevDef = pRh->apDevByAddr[VUSB_DEFAULT_ADDRESS];
1068
1069 if (pDevDef)
1070 {
1071 pDevDef->u8Address = VUSB_INVALID_ADDRESS;
1072 pDevDef->u8NewAddress = VUSB_INVALID_ADDRESS;
1073 vusbDevSetStateCmp(pDevDef, VUSB_DEVICE_STATE_POWERED, VUSB_DEVICE_STATE_DEFAULT);
1074 Log(("2 DEFAULT ADDRS\n"));
1075 }
1076
1077 pRh->apDevByAddr[VUSB_DEFAULT_ADDRESS] = pDev;
1078 vusbDevSetState(pDev, VUSB_DEVICE_STATE_DEFAULT);
1079 }
1080 else
1081 {
1082 Assert(!pRh->apDevByAddr[u8Address]);
1083 pRh->apDevByAddr[u8Address] = pDev;
1084 vusbDevSetState(pDev, VUSB_DEVICE_STATE_ADDRESS);
1085 }
1086
1087 pDev->u8Address = u8Address;
1088 RTCritSectLeave(&pRh->CritSectDevices);
1089
1090 Log(("vusb: %p[%s]/%i: Assigned address %u\n",
1091 pDev, pDev->pUsbIns->pszName, pDev->i16Port, u8Address));
1092}
1093
1094
1095static DECLCALLBACK(int) vusbDevCancelAllUrbsWorker(PVUSBDEV pDev, bool fDetaching)
1096{
1097 /*
1098 * Iterate the URBs and cancel them.
1099 */
1100 PVUSBURBVUSB pVUsbUrb, pVUsbUrbNext;
1101 RTListForEachSafe(&pDev->LstAsyncUrbs, pVUsbUrb, pVUsbUrbNext, VUSBURBVUSBINT, NdLst)
1102 {
1103 PVUSBURB pUrb = pVUsbUrb->pUrb;
1104
1105 Assert(pUrb->pVUsb->pDev == pDev);
1106
1107 LogFlow(("%s: vusbDevCancelAllUrbs: CANCELING URB\n", pUrb->pszDesc));
1108 int rc = vusbUrbCancelWorker(pUrb, CANCELMODE_FAIL);
1109 AssertRC(rc);
1110 }
1111
1112 /*
1113 * Reap any URBs which became ripe during cancel now.
1114 */
1115 RTCritSectEnter(&pDev->CritSectAsyncUrbs);
1116 unsigned cReaped;
1117 do
1118 {
1119 cReaped = 0;
1120 pVUsbUrb = RTListGetFirst(&pDev->LstAsyncUrbs, VUSBURBVUSBINT, NdLst);
1121 while (pVUsbUrb)
1122 {
1123 PVUSBURBVUSB pNext = RTListGetNext(&pDev->LstAsyncUrbs, pVUsbUrb, VUSBURBVUSBINT, NdLst);
1124 PVUSBURB pUrb = pVUsbUrb->pUrb;
1125 Assert(pUrb->pVUsb->pDev == pDev);
1126
1127 PVUSBURB pRipe = NULL;
1128 if (pUrb->enmState == VUSBURBSTATE_REAPED)
1129 pRipe = pUrb;
1130 else if (pUrb->enmState == VUSBURBSTATE_CANCELLED)
1131#ifdef RT_OS_WINDOWS /** @todo Windows doesn't do cancelling, thus this kludge to prevent really bad
1132 * things from happening if we leave a pending URB behinds. */
1133 pRipe = pDev->pUsbIns->pReg->pfnUrbReap(pDev->pUsbIns, fDetaching ? 1500 : 0 /*ms*/);
1134#else
1135 pRipe = pDev->pUsbIns->pReg->pfnUrbReap(pDev->pUsbIns, fDetaching ? 10 : 0 /*ms*/);
1136#endif
1137 else
1138 AssertMsgFailed(("pUrb=%p enmState=%d\n", pUrb, pUrb->enmState));
1139 if (pRipe)
1140 {
1141 if ( pNext
1142 && pRipe == pNext->pUrb)
1143 pNext = RTListGetNext(&pDev->LstAsyncUrbs, pNext, VUSBURBVUSBINT, NdLst);
1144 vusbUrbRipe(pRipe);
1145 cReaped++;
1146 }
1147
1148 pVUsbUrb = pNext;
1149 }
1150 } while (cReaped > 0);
1151
1152 /*
1153 * If we're detaching, we'll have to orphan any leftover URBs.
1154 */
1155 if (fDetaching)
1156 {
1157 RTListForEachSafe(&pDev->LstAsyncUrbs, pVUsbUrb, pVUsbUrbNext, VUSBURBVUSBINT, NdLst)
1158 {
1159 PVUSBURB pUrb = pVUsbUrb->pUrb;
1160 Assert(pUrb->pVUsb->pDev == pDev);
1161
1162 AssertMsgFailed(("%s: Leaking left over URB! state=%d pDev=%p[%s]\n",
1163 pUrb->pszDesc, pUrb->enmState, pDev, pDev->pUsbIns->pszName));
1164 vusbUrbUnlink(pUrb);
1165 /* Unlink isn't enough, because boundary timer and detaching will try to reap it.
1166 * It was tested with MSD & iphone attachment to vSMP guest, if
1167 * it breaks anything, please add comment here, why we should unlink only.
1168 */
1169 pUrb->pVUsb->pfnFree(pUrb);
1170 }
1171 }
1172 RTCritSectLeave(&pDev->CritSectAsyncUrbs);
1173 return VINF_SUCCESS;
1174}
1175
1176/**
1177 * Cancels and completes (with CRC failure) all async URBs pending
1178 * on a device. This is typically done as part of a reset and
1179 * before detaching a device.
1180 *
1181 * @param pDev The VUSB device instance.
1182 * @param fDetaching If set, we will unconditionally unlink (and leak)
1183 * any URBs which isn't reaped.
1184 */
1185DECLHIDDEN(void) vusbDevCancelAllUrbs(PVUSBDEV pDev, bool fDetaching)
1186{
1187 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)vusbDevCancelAllUrbsWorker, 2, pDev, fDetaching);
1188 AssertRC(rc);
1189}
1190
1191
1192static DECLCALLBACK(int) vusbDevUrbIoThread(RTTHREAD hThread, void *pvUser)
1193{
1194 PVUSBDEV pDev = (PVUSBDEV)pvUser;
1195
1196 /* Notify the starter that we are up and running. */
1197 RTThreadUserSignal(hThread);
1198
1199 LogFlowFunc(("Entering work loop\n"));
1200
1201 while (!ASMAtomicReadBool(&pDev->fTerminate))
1202 {
1203 if (vusbDevGetState(pDev) != VUSB_DEVICE_STATE_RESET)
1204 vusbUrbDoReapAsyncDev(pDev, RT_INDEFINITE_WAIT);
1205
1206 /* Process any URBs waiting to be cancelled first. */
1207 int rc = RTReqQueueProcess(pDev->hReqQueueSync, 0); /* Don't wait if there is nothing to do. */
1208 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT); NOREF(rc);
1209 }
1210
1211 return VINF_SUCCESS;
1212}
1213
1214int vusbDevUrbIoThreadWakeup(PVUSBDEV pDev)
1215{
1216 ASMAtomicXchgBool(&pDev->fWokenUp, true);
1217 return pDev->pUsbIns->pReg->pfnWakeup(pDev->pUsbIns);
1218}
1219
1220/**
1221 * Create the URB I/O thread.
1222 *
1223 * @returns VBox status code.
1224 * @param pDev The VUSB device.
1225 */
1226int vusbDevUrbIoThreadCreate(PVUSBDEV pDev)
1227{
1228 int rc = VINF_SUCCESS;
1229
1230 ASMAtomicXchgBool(&pDev->fTerminate, false);
1231 rc = RTThreadCreateF(&pDev->hUrbIoThread, vusbDevUrbIoThread, pDev, 0, RTTHREADTYPE_IO,
1232 RTTHREADFLAGS_WAITABLE, "USBDevIo-%d", pDev->i16Port);
1233 if (RT_SUCCESS(rc))
1234 {
1235 /* Wait for it to become active. */
1236 rc = RTThreadUserWait(pDev->hUrbIoThread, RT_INDEFINITE_WAIT);
1237 }
1238
1239 return rc;
1240}
1241
1242/**
1243 * Destro the URB I/O thread.
1244 *
1245 * @returns VBox status code.
1246 * @param pDev The VUSB device.
1247 */
1248int vusbDevUrbIoThreadDestroy(PVUSBDEV pDev)
1249{
1250 int rc = VINF_SUCCESS;
1251 int rcThread = VINF_SUCCESS;
1252
1253 ASMAtomicXchgBool(&pDev->fTerminate, true);
1254 vusbDevUrbIoThreadWakeup(pDev);
1255
1256 rc = RTThreadWait(pDev->hUrbIoThread, RT_INDEFINITE_WAIT, &rcThread);
1257 if (RT_SUCCESS(rc))
1258 rc = rcThread;
1259
1260 pDev->hUrbIoThread = NIL_RTTHREAD;
1261
1262 return rc;
1263}
1264
1265
1266/**
1267 * Attaches a device to the given hub.
1268 *
1269 * @returns VBox status code.
1270 * @param pDev The device to attach.
1271 * @param pHub The roothub to attach to.
1272 */
1273int vusbDevAttach(PVUSBDEV pDev, PVUSBROOTHUB pHub)
1274{
1275 AssertMsg(pDev->enmState == VUSB_DEVICE_STATE_DETACHED, ("enmState=%d\n", pDev->enmState));
1276
1277 pDev->pHub = pHub;
1278 pDev->enmState = VUSB_DEVICE_STATE_ATTACHED;
1279
1280 /* noone else ever messes with the default pipe while we are attached */
1281 vusbDevMapEndpoint(pDev, &g_Endpoint0);
1282 vusbDevDoSelectConfig(pDev, &g_Config0);
1283
1284 /* Create I/O thread and attach to the hub. */
1285 int rc = vusbDevUrbIoThreadCreate(pDev);
1286 if (RT_FAILURE(rc))
1287 {
1288 pDev->pHub = NULL;
1289 pDev->enmState = VUSB_DEVICE_STATE_DETACHED;
1290 }
1291
1292 return rc;
1293}
1294
1295
1296/**
1297 * Detaches a device from the hub it's attached to.
1298 *
1299 * @returns VBox status code.
1300 * @param pDev The device to detach.
1301 *
1302 * @remark This can be called in any state but reset.
1303 */
1304int vusbDevDetach(PVUSBDEV pDev)
1305{
1306 LogFlow(("vusbDevDetach: pDev=%p[%s] enmState=%#x\n", pDev, pDev->pUsbIns->pszName, pDev->enmState));
1307 VUSBDEV_ASSERT_VALID_STATE(pDev->enmState);
1308 Assert(pDev->enmState != VUSB_DEVICE_STATE_RESET);
1309
1310 /*
1311 * Destroy I/O thread and request queue last because they might still be used
1312 * when cancelling URBs.
1313 */
1314 vusbDevUrbIoThreadDestroy(pDev);
1315
1316 vusbDevSetState(pDev, VUSB_DEVICE_STATE_DETACHED);
1317 pDev->pHub = NULL;
1318
1319 /* Remove the configuration */
1320 pDev->pCurCfgDesc = NULL;
1321 for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
1322 vusbDevResetPipeData(&pDev->aPipes[i]);
1323 return VINF_SUCCESS;
1324}
1325
1326
1327/**
1328 * Destroys a device, detaching it from the hub if necessary.
1329 *
1330 * @param pDev The device.
1331 * @thread any.
1332 */
1333void vusbDevDestroy(PVUSBDEV pDev)
1334{
1335 LogFlow(("vusbDevDestroy: pDev=%p[%s] enmState=%d\n", pDev, pDev->pUsbIns->pszName, pDev->enmState));
1336
1337 RTMemFree(pDev->paIfStates);
1338
1339 PDMUsbHlpTimerDestroy(pDev->pUsbIns, pDev->hResetTimer);
1340 pDev->hResetTimer = NIL_TMTIMERHANDLE;
1341
1342 for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
1343 {
1344 Assert(pDev->aPipes[i].pCtrl == NULL);
1345 RTCritSectDelete(&pDev->aPipes[i].CritSectCtrl);
1346 }
1347
1348 if (pDev->hSniffer != VUSBSNIFFER_NIL)
1349 VUSBSnifferDestroy(pDev->hSniffer);
1350
1351 vusbUrbPoolDestroy(&pDev->UrbPool);
1352
1353 int rc = RTReqQueueDestroy(pDev->hReqQueueSync);
1354 AssertRC(rc);
1355 pDev->hReqQueueSync = NIL_RTREQQUEUE;
1356
1357 RTCritSectDelete(&pDev->CritSectAsyncUrbs);
1358 /* Not using vusbDevSetState() deliberately here because it would assert on the state. */
1359 pDev->enmState = VUSB_DEVICE_STATE_DESTROYED;
1360 pDev->pUsbIns->pvVUsbDev2 = NULL;
1361 RTMemFree(pDev);
1362}
1363
1364
1365/* -=-=-=-=-=- VUSBIDEVICE methods -=-=-=-=-=- */
1366
1367
1368/**
1369 * The actual reset has been done, do completion on EMT.
1370 *
1371 * There are several things we have to do now, like set default
1372 * config and address, and cleanup the state of control pipes.
1373 *
1374 * It's possible that the device has a delayed destroy request
1375 * pending when we get here. This can happen for async resetting.
1376 * We deal with it here, since we're now executing on the EMT
1377 * thread and the destruction will be properly serialized now.
1378 *
1379 * @param pDev The device that is being reset.
1380 * @param rc The vusbDevResetWorker return code.
1381 * @param pfnDone The done callback specified by the caller of vusbDevReset().
1382 * @param pvUser The user argument for the callback.
1383 */
1384static void vusbDevResetDone(PVUSBDEV pDev, int rc, PFNVUSBRESETDONE pfnDone, void *pvUser)
1385{
1386 VUSBDEV_ASSERT_VALID_STATE(pDev->enmState);
1387 Assert(pDev->enmState == VUSB_DEVICE_STATE_RESET);
1388
1389 /*
1390 * Do control pipe cleanup regardless of state and result.
1391 */
1392 for (unsigned i = 0; i < VUSB_PIPE_MAX; i++)
1393 if (pDev->aPipes[i].pCtrl)
1394 vusbMsgResetExtraData(pDev->aPipes[i].pCtrl);
1395
1396 /*
1397 * Switch to the default state.
1398 */
1399 vusbDevSetState(pDev, VUSB_DEVICE_STATE_DEFAULT);
1400 pDev->u16Status = 0;
1401 vusbDevDoSelectConfig(pDev, &g_Config0);
1402 vusbDevSetAddress(pDev, VUSB_DEFAULT_ADDRESS);
1403 if (pfnDone)
1404 pfnDone(&pDev->IDevice, pDev->i16Port, rc, pvUser);
1405}
1406
1407
1408/**
1409 * @callback_method_impl{FNTMTIMERUSB,
1410 * Timer callback for doing reset completion.}
1411 */
1412static DECLCALLBACK(void) vusbDevResetDoneTimer(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, void *pvUser)
1413{
1414 PVUSBDEV pDev = (PVUSBDEV)pvUser;
1415 PVUSBRESETARGS pArgs = (PVUSBRESETARGS)pDev->pvArgs;
1416 Assert(pDev->pUsbIns == pUsbIns);
1417 RT_NOREF(pUsbIns, hTimer);
1418
1419 AssertPtr(pArgs);
1420
1421 /*
1422 * Reset-done processing and cleanup.
1423 */
1424 pDev->pvArgs = NULL;
1425 vusbDevResetDone(pDev, pArgs->rc, pArgs->pfnDone, pArgs->pvUser);
1426 RTMemFree(pArgs);
1427}
1428
1429
1430/**
1431 * Perform the actual reset.
1432 *
1433 * @thread EMT or a VUSB reset thread.
1434 */
1435static DECLCALLBACK(int) vusbDevResetWorker(PVUSBDEV pDev, bool fResetOnLinux, bool fUseTimer, PVUSBRESETARGS pArgs)
1436{
1437 uint64_t const uTimerDeadline = !fUseTimer ? 0
1438 : PDMUsbHlpTimerGet(pDev->pUsbIns, pDev->hResetTimer)
1439 + PDMUsbHlpTimerFromMilli(pDev->pUsbIns, pDev->hResetTimer, 10);
1440
1441 int rc = VINF_SUCCESS;
1442 if (pDev->pUsbIns->pReg->pfnUsbReset)
1443 rc = pDev->pUsbIns->pReg->pfnUsbReset(pDev->pUsbIns, fResetOnLinux);
1444
1445 if (pArgs)
1446 {
1447 pArgs->rc = rc;
1448 rc = VINF_SUCCESS;
1449 }
1450
1451 if (fUseTimer)
1452 {
1453 /*
1454 * We use a timer to communicate the result back to EMT.
1455 * This avoids suspend + poweroff issues, and it should give
1456 * us more accurate scheduling than making this thread sleep.
1457 */
1458 int rc2 = PDMUsbHlpTimerSet(pDev->pUsbIns, pDev->hResetTimer, uTimerDeadline);
1459 AssertReleaseRC(rc2);
1460 }
1461
1462 LogFlow(("vusbDevResetWorker: %s: returns %Rrc\n", pDev->pUsbIns->pszName, rc));
1463 return rc;
1464}
1465
1466
1467/**
1468 * Resets a device.
1469 *
1470 * Since a device reset shall take at least 10ms from the guest point of view,
1471 * it must be performed asynchronously. We create a thread which performs this
1472 * operation and ensures it will take at least 10ms.
1473 *
1474 * At times - like init - a synchronous reset is required, this can be done
1475 * by passing NULL for pfnDone.
1476 *
1477 * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state.
1478 * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful,
1479 * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed.
1480 *
1481 * @returns VBox status code.
1482 *
1483 * @param pDevice Pointer to the VUSB device interface.
1484 * @param fResetOnLinux Whether it's safe to reset the device(s) on a linux
1485 * host system. See discussion of logical reconnects elsewhere.
1486 * @param pfnDone Pointer to the completion routine. If NULL a synchronous
1487 * reset is preformed not respecting the 10ms.
1488 * @param pvUser Opaque user data to pass to the done callback.
1489 * @param pVM Pointer to the VM handle for performing the done function
1490 * on the EMT thread.
1491 * @thread EMT
1492 */
1493static DECLCALLBACK(int) vusbIDeviceReset(PVUSBIDEVICE pDevice, bool fResetOnLinux,
1494 PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
1495{
1496 RT_NOREF(pVM);
1497 PVUSBDEV pDev = (PVUSBDEV)pDevice;
1498 Assert(!pfnDone || pVM);
1499 LogFlow(("vusb: reset: [%s]/%i\n", pDev->pUsbIns->pszName, pDev->i16Port));
1500
1501 /*
1502 * Only one reset operation at a time.
1503 */
1504 const VUSBDEVICESTATE enmStateOld = vusbDevSetState(pDev, VUSB_DEVICE_STATE_RESET);
1505 if (enmStateOld == VUSB_DEVICE_STATE_RESET)
1506 {
1507 LogRel(("VUSB: %s: reset request is ignored, the device is already resetting!\n", pDev->pUsbIns->pszName));
1508 return VERR_VUSB_DEVICE_IS_RESETTING;
1509 }
1510
1511 /*
1512 * First, cancel all async URBs.
1513 */
1514 vusbDevCancelAllUrbs(pDev, false);
1515
1516 /* Async or sync? */
1517 if (pfnDone)
1518 {
1519 /*
1520 * Async fashion.
1521 */
1522 PVUSBRESETARGS pArgs = (PVUSBRESETARGS)RTMemTmpAlloc(sizeof(*pArgs));
1523 if (pArgs)
1524 {
1525 pArgs->pDev = pDev;
1526 pArgs->pfnDone = pfnDone;
1527 pArgs->pvUser = pvUser;
1528 pArgs->rc = VINF_SUCCESS;
1529 AssertPtrNull(pDev->pvArgs);
1530 pDev->pvArgs = pArgs;
1531 int rc = vusbDevIoThreadExec(pDev, 0 /* fFlags */, (PFNRT)vusbDevResetWorker, 4, pDev, fResetOnLinux, true, pArgs);
1532 if (RT_SUCCESS(rc))
1533 return rc;
1534
1535 RTMemTmpFree(pArgs);
1536 }
1537 /* fall back to sync on failure */
1538 }
1539
1540 /*
1541 * Sync fashion.
1542 */
1543 int rc = vusbDevResetWorker(pDev, fResetOnLinux, false, NULL);
1544 vusbDevResetDone(pDev, rc, pfnDone, pvUser);
1545 return rc;
1546}
1547
1548
1549/**
1550 * Powers on the device.
1551 *
1552 * @returns VBox status code.
1553 * @param pInterface Pointer to the device interface structure.
1554 */
1555static DECLCALLBACK(int) vusbIDevicePowerOn(PVUSBIDEVICE pInterface)
1556{
1557 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1558 LogFlow(("vusbDevPowerOn: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
1559
1560 /*
1561 * Check that the device is in a valid state.
1562 */
1563 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
1564 if (enmState == VUSB_DEVICE_STATE_DETACHED)
1565 {
1566 Log(("vusb: warning: attempt to power on detached device %p[%s]\n", pDev, pDev->pUsbIns->pszName));
1567 return VERR_VUSB_DEVICE_NOT_ATTACHED;
1568 }
1569 if (enmState == VUSB_DEVICE_STATE_RESET)
1570 {
1571 LogRel(("VUSB: %s: power on ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
1572 return VERR_VUSB_DEVICE_IS_RESETTING;
1573 }
1574
1575 /*
1576 * Do the job.
1577 */
1578 if (enmState == VUSB_DEVICE_STATE_ATTACHED)
1579 vusbDevSetState(pDev, VUSB_DEVICE_STATE_POWERED);
1580
1581 return VINF_SUCCESS;
1582}
1583
1584
1585/**
1586 * Powers off the device.
1587 *
1588 * @returns VBox status code.
1589 * @param pInterface Pointer to the device interface structure.
1590 */
1591static DECLCALLBACK(int) vusbIDevicePowerOff(PVUSBIDEVICE pInterface)
1592{
1593 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1594 LogFlow(("vusbDevPowerOff: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
1595
1596 /*
1597 * Check that the device is in a valid state.
1598 */
1599 const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
1600 if (enmState == VUSB_DEVICE_STATE_DETACHED)
1601 {
1602 Log(("vusb: warning: attempt to power off detached device %p[%s]\n", pDev, pDev->pUsbIns->pszName));
1603 return VERR_VUSB_DEVICE_NOT_ATTACHED;
1604 }
1605 if (enmState == VUSB_DEVICE_STATE_RESET)
1606 {
1607 LogRel(("VUSB: %s: power off ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
1608 return VERR_VUSB_DEVICE_IS_RESETTING;
1609 }
1610
1611 vusbDevSetState(pDev, VUSB_DEVICE_STATE_ATTACHED);
1612 return VINF_SUCCESS;
1613}
1614
1615
1616/**
1617 * Get the state of the device.
1618 *
1619 * @returns Device state.
1620 * @param pInterface Pointer to the device interface structure.
1621 */
1622static DECLCALLBACK(VUSBDEVICESTATE) vusbIDeviceGetState(PVUSBIDEVICE pInterface)
1623{
1624 return vusbDevGetState((PVUSBDEV)pInterface);
1625}
1626
1627
1628/**
1629 * @interface_method_impl{VUSBIDEVICE,pfnIsSavedStateSupported}
1630 */
1631static DECLCALLBACK(bool) vusbIDeviceIsSavedStateSupported(PVUSBIDEVICE pInterface)
1632{
1633 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1634 bool fSavedStateSupported = RT_BOOL(pDev->pUsbIns->pReg->fFlags & PDM_USBREG_SAVED_STATE_SUPPORTED);
1635
1636 LogFlowFunc(("pInterface=%p\n", pInterface));
1637
1638 LogFlowFunc(("returns %RTbool\n", fSavedStateSupported));
1639 return fSavedStateSupported;
1640}
1641
1642
1643/**
1644 * @interface_method_impl{VUSBIDEVICE,pfnGetState}
1645 */
1646static DECLCALLBACK(VUSBSPEED) vusbIDeviceGetSpeed(PVUSBIDEVICE pInterface)
1647{
1648 PVUSBDEV pDev = (PVUSBDEV)pInterface;
1649 VUSBSPEED enmSpeed = pDev->pUsbIns->enmSpeed;
1650
1651 LogFlowFunc(("pInterface=%p, returns %u\n", pInterface, enmSpeed));
1652 return enmSpeed;
1653}
1654
1655
1656/**
1657 * The maximum number of interfaces the device can have in all of it's configuration.
1658 *
1659 * @returns Number of interfaces.
1660 * @param pDev The device.
1661 */
1662size_t vusbDevMaxInterfaces(PVUSBDEV pDev)
1663{
1664 uint8_t cMax = 0;
1665 unsigned i = pDev->pDescCache->pDevice->bNumConfigurations;
1666 while (i-- > 0)
1667 {
1668 if (pDev->pDescCache->paConfigs[i].Core.bNumInterfaces > cMax)
1669 cMax = pDev->pDescCache->paConfigs[i].Core.bNumInterfaces;
1670 }
1671
1672 return cMax;
1673}
1674
1675
1676/**
1677 * Executes a given function on the I/O thread.
1678 *
1679 * @returns IPRT status code.
1680 * @param pDev The USB device instance data.
1681 * @param fFlags Combination of VUSB_DEV_IO_THREAD_EXEC_FLAGS_*
1682 * @param pfnFunction The function to execute.
1683 * @param cArgs Number of arguments to the function.
1684 * @param Args The parameter list.
1685 *
1686 * @remarks See remarks on RTReqQueueCallV
1687 */
1688DECLHIDDEN(int) vusbDevIoThreadExecV(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args)
1689{
1690 int rc = VINF_SUCCESS;
1691 PRTREQ hReq = NULL;
1692
1693 Assert(pDev->hUrbIoThread != NIL_RTTHREAD);
1694 if (RT_LIKELY(pDev->hUrbIoThread != NIL_RTTHREAD))
1695 {
1696 uint32_t fReqFlags = RTREQFLAGS_IPRT_STATUS;
1697
1698 if (!(fFlags & VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC))
1699 fReqFlags |= RTREQFLAGS_NO_WAIT;
1700
1701 rc = RTReqQueueCallV(pDev->hReqQueueSync, &hReq, 0 /* cMillies */, fReqFlags, pfnFunction, cArgs, Args);
1702 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1703
1704 /* In case we are called on the I/O thread just process the request. */
1705 if ( pDev->hUrbIoThread == RTThreadSelf()
1706 && (fFlags & VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC))
1707 {
1708 int rc2 = RTReqQueueProcess(pDev->hReqQueueSync, 0);
1709 Assert(RT_SUCCESS(rc2) || rc2 == VERR_TIMEOUT); NOREF(rc2);
1710 }
1711 else
1712 vusbDevUrbIoThreadWakeup(pDev);
1713
1714 if ( rc == VERR_TIMEOUT
1715 && (fFlags & VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC))
1716 {
1717 rc = RTReqWait(hReq, RT_INDEFINITE_WAIT);
1718 AssertRC(rc);
1719 }
1720 RTReqRelease(hReq);
1721 }
1722 else
1723 rc = VERR_INVALID_STATE;
1724
1725 return rc;
1726}
1727
1728
1729/**
1730 * Executes a given function on the I/O thread.
1731 *
1732 * @returns IPRT status code.
1733 * @param pDev The USB device instance data.
1734 * @param fFlags Combination of VUSB_DEV_IO_THREAD_EXEC_FLAGS_*
1735 * @param pfnFunction The function to execute.
1736 * @param cArgs Number of arguments to the function.
1737 * @param ... The parameter list.
1738 *
1739 * @remarks See remarks on RTReqQueueCallV
1740 */
1741DECLHIDDEN(int) vusbDevIoThreadExec(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, ...)
1742{
1743 int rc = VINF_SUCCESS;
1744 va_list va;
1745
1746 va_start(va, cArgs);
1747 rc = vusbDevIoThreadExecV(pDev, fFlags, pfnFunction, cArgs, va);
1748 va_end(va);
1749 return rc;
1750}
1751
1752
1753/**
1754 * Executes a given function synchronously on the I/O thread waiting for it to complete.
1755 *
1756 * @returns IPRT status code.
1757 * @param pDev The USB device instance data
1758 * @param pfnFunction The function to execute.
1759 * @param cArgs Number of arguments to the function.
1760 * @param ... The parameter list.
1761 *
1762 * @remarks See remarks on RTReqQueueCallV
1763 */
1764DECLHIDDEN(int) vusbDevIoThreadExecSync(PVUSBDEV pDev, PFNRT pfnFunction, unsigned cArgs, ...)
1765{
1766 int rc = VINF_SUCCESS;
1767 va_list va;
1768
1769 va_start(va, cArgs);
1770 rc = vusbDevIoThreadExecV(pDev, VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC, pfnFunction, cArgs, va);
1771 va_end(va);
1772 return rc;
1773}
1774
1775
1776/**
1777 * Initialize a new VUSB device.
1778 *
1779 * @returns VBox status code.
1780 * @param pDev The VUSB device to initialize.
1781 * @param pUsbIns Pointer to the PDM USB Device instance.
1782 * @param pszCaptureFilename Optional fileame to capture the traffic to.
1783 */
1784int vusbDevInit(PVUSBDEV pDev, PPDMUSBINS pUsbIns, const char *pszCaptureFilename)
1785{
1786 /*
1787 * Initialize the device data members.
1788 * (All that are Non-Zero at least.)
1789 */
1790 Assert(!pDev->IDevice.pfnReset);
1791 Assert(!pDev->IDevice.pfnPowerOn);
1792 Assert(!pDev->IDevice.pfnPowerOff);
1793 Assert(!pDev->IDevice.pfnGetState);
1794 Assert(!pDev->IDevice.pfnIsSavedStateSupported);
1795
1796 pDev->IDevice.pfnReset = vusbIDeviceReset;
1797 pDev->IDevice.pfnPowerOn = vusbIDevicePowerOn;
1798 pDev->IDevice.pfnPowerOff = vusbIDevicePowerOff;
1799 pDev->IDevice.pfnGetState = vusbIDeviceGetState;
1800 pDev->IDevice.pfnIsSavedStateSupported = vusbIDeviceIsSavedStateSupported;
1801 pDev->IDevice.pfnGetSpeed = vusbIDeviceGetSpeed;
1802 pDev->pUsbIns = pUsbIns;
1803 pDev->pHub = NULL;
1804 pDev->enmState = VUSB_DEVICE_STATE_DETACHED;
1805 pDev->cRefs = 1;
1806 pDev->u8Address = VUSB_INVALID_ADDRESS;
1807 pDev->u8NewAddress = VUSB_INVALID_ADDRESS;
1808 pDev->i16Port = -1;
1809 pDev->u16Status = 0;
1810 pDev->pDescCache = NULL;
1811 pDev->pCurCfgDesc = NULL;
1812 pDev->paIfStates = NULL;
1813 RTListInit(&pDev->LstAsyncUrbs);
1814 memset(&pDev->aPipes[0], 0, sizeof(pDev->aPipes));
1815 for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
1816 {
1817 int rc = RTCritSectInit(&pDev->aPipes[i].CritSectCtrl);
1818 AssertRCReturn(rc, rc);
1819 }
1820 pDev->hResetTimer = NIL_TMTIMERHANDLE;
1821 pDev->hSniffer = VUSBSNIFFER_NIL;
1822
1823 int rc = RTCritSectInit(&pDev->CritSectAsyncUrbs);
1824 AssertRCReturn(rc, rc);
1825
1826 /* Create the URB pool. */
1827 rc = vusbUrbPoolInit(&pDev->UrbPool);
1828 AssertRCReturn(rc, rc);
1829
1830 /* Setup request queue executing synchronous tasks on the I/O thread. */
1831 rc = RTReqQueueCreate(&pDev->hReqQueueSync);
1832 AssertRCReturn(rc, rc);
1833
1834 /*
1835 * Create the reset timer. Make sure the name is unique as we're generic code.
1836 */
1837 static uint32_t volatile s_iSeq;
1838 char szDesc[32];
1839 RTStrPrintf(szDesc, sizeof(szDesc), "VUSB Reset #%u", ASMAtomicIncU32(&s_iSeq));
1840 rc = PDMUsbHlpTimerCreate(pDev->pUsbIns, TMCLOCK_VIRTUAL, vusbDevResetDoneTimer, pDev, 0 /*fFlags*/,
1841 szDesc, &pDev->hResetTimer);
1842 AssertRCReturn(rc, rc);
1843
1844 if (pszCaptureFilename)
1845 {
1846 rc = VUSBSnifferCreate(&pDev->hSniffer, 0, pszCaptureFilename, NULL, NULL);
1847 AssertRCReturn(rc, rc);
1848 }
1849
1850 /*
1851 * Get the descriptor cache from the device. (shall cannot fail)
1852 */
1853 pDev->pDescCache = pUsbIns->pReg->pfnUsbGetDescriptorCache(pUsbIns);
1854 AssertPtr(pDev->pDescCache);
1855#ifdef VBOX_STRICT
1856 if (pDev->pDescCache->fUseCachedStringsDescriptors)
1857 {
1858 int32_t iPrevId = -1;
1859 for (unsigned iLang = 0; iLang < pDev->pDescCache->cLanguages; iLang++)
1860 {
1861 Assert((int32_t)pDev->pDescCache->paLanguages[iLang].idLang > iPrevId);
1862 iPrevId = pDev->pDescCache->paLanguages[iLang].idLang;
1863
1864 int32_t idxPrevStr = -1;
1865 PCPDMUSBDESCCACHESTRING paStrings = pDev->pDescCache->paLanguages[iLang].paStrings;
1866 unsigned cStrings = pDev->pDescCache->paLanguages[iLang].cStrings;
1867 for (unsigned iStr = 0; iStr < cStrings; iStr++)
1868 {
1869 Assert((int32_t)paStrings[iStr].idx > idxPrevStr);
1870 idxPrevStr = paStrings[iStr].idx;
1871 size_t cch = strlen(paStrings[iStr].psz);
1872 Assert(cch <= 127);
1873 }
1874 }
1875 }
1876#endif
1877
1878 /*
1879 * Allocate memory for the interface states.
1880 */
1881 size_t cbIface = vusbDevMaxInterfaces(pDev) * sizeof(*pDev->paIfStates);
1882 pDev->paIfStates = (PVUSBINTERFACESTATE)RTMemAllocZ(cbIface);
1883 AssertMsgReturn(pDev->paIfStates, ("RTMemAllocZ(%d) failed\n", cbIface), VERR_NO_MEMORY);
1884
1885 return VINF_SUCCESS;
1886}
1887
1888/*
1889 * Local Variables:
1890 * mode: c
1891 * c-file-style: "bsd"
1892 * c-basic-offset: 4
1893 * tab-width: 4
1894 * indent-tabs-mode: s
1895 * End:
1896 */
1897
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use