VirtualBox

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

Last change on this file since 33000 was 32010, checked in by vboxsync, 14 years ago

VUSB: Added a way to cancel URBs without failing the transfer.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use