VirtualBox

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

Last change on this file since 57064 was 56992, checked in by vboxsync, 9 years ago

Devices: Log & Assertion formatting fixes.

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

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