VirtualBox

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

Last change on this file since 91881 was 90049, checked in by vboxsync, 3 years ago

VUSB: If a descriptor read can't be satisfied from cache, pass it through to device rather than returning an error (stall). Fixes a problem with buggy drivers for Logitech C930e from Windows Update (see bugref:10059).

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