VirtualBox

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

Last change on this file since 43394 was 37359, checked in by vboxsync, 13 years ago

VUSB: Don't create the reset timer on the fly, it triggers lock order violations occasionally.

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