VirtualBox

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

Last change on this file since 27798 was 26972, checked in by vboxsync, 15 years ago

fixed accident in r58267

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