VirtualBox

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

Last change on this file since 28345 was 27901, checked in by vboxsync, 15 years ago

OSE header fixes

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