VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/USBProxyDevice.cpp@ 35753

Last change on this file since 35753 was 35353, checked in by vboxsync, 14 years ago

Move the misc files the in src/VBox/Devices/ directory into a build/ subdirectory, changing their names to match the target module.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.7 KB
Line 
1/* $Id: USBProxyDevice.cpp 35353 2010-12-27 17:25:52Z vboxsync $ */
2/** @file
3 * USBProxy - USB device proxy.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
23#include <VBox/usb.h>
24#include <VBox/usbfilter.h>
25#include <VBox/vmm/pdm.h>
26#include <VBox/err.h>
27#include <iprt/alloc.h>
28#include <iprt/string.h>
29#include <VBox/log.h>
30#include <iprt/assert.h>
31#include "USBProxyDevice.h"
32#include "VUSBInternal.h"
33#include "VBoxDD.h"
34
35
36/*******************************************************************************
37* Global Variables *
38*******************************************************************************/
39/** A dummy name used early during the construction phase to avoid log crashes. */
40static char g_szDummyName[] = "proxy xxxx:yyyy";
41
42
43
44/* Synchronously obtain a standard USB descriptor for a device, used in order
45 * to grab configuration descriptors when we first add the device
46 */
47static void *GetStdDescSync(PUSBPROXYDEV pProxyDev, uint8_t iDescType, uint8_t iIdx, uint16_t LangId, uint16_t cbHint)
48{
49 LogFlow(("GetStdDescSync: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
50 for (;;)
51 {
52 /*
53 * Setup a MSG URB, queue and reap it.
54 */
55 VUSBURB Urb;
56 AssertCompile(RT_SIZEOFMEMB(VUSBURB, abData) >= _4K);
57 Urb.u32Magic = VUSBURB_MAGIC;
58 Urb.enmState = VUSBURBSTATE_IN_FLIGHT;
59 Urb.pszDesc = (char*)"URB sync";
60 memset(&Urb.VUsb, 0, sizeof(Urb.VUsb));
61 memset(&Urb.Hci, 0, sizeof(Urb.Hci));
62 Urb.Dev.pvPrivate = NULL;
63 Urb.Dev.pNext = NULL;
64 Urb.pUsbIns = pProxyDev->pUsbIns;
65 Urb.DstAddress = 0;
66 Urb.EndPt = 0;
67 Urb.enmType = VUSBXFERTYPE_MSG;
68 Urb.enmDir = VUSBDIRECTION_IN;
69 Urb.fShortNotOk = false;
70 Urb.enmStatus = VUSBSTATUS_INVALID;
71 cbHint = RT_MIN(cbHint, sizeof(Urb.abData) - sizeof(VUSBSETUP));
72 Urb.cbData = cbHint + sizeof(VUSBSETUP);
73
74 PVUSBSETUP pSetup = (PVUSBSETUP)Urb.abData;
75 pSetup->bmRequestType = VUSB_DIR_TO_HOST | VUSB_REQ_STANDARD | VUSB_TO_DEVICE;
76 pSetup->bRequest = VUSB_REQ_GET_DESCRIPTOR;
77 pSetup->wValue = (iDescType << 8) | iIdx;
78 pSetup->wIndex = LangId;
79 pSetup->wLength = cbHint;
80
81 if (!pProxyDev->pOps->pfnUrbQueue(&Urb))
82 break;
83
84 /* Don't wait forever, it's just a simple request that should
85 return immediately. Since we're executing in the EMT thread
86 it's important not to get stuck here. (Some of the builtin
87 iMac devices may not refuse respond for instance.) */
88 PVUSBURB pUrbReaped = pProxyDev->pOps->pfnUrbReap(pProxyDev, 10000 /* ms */);
89 if (!pUrbReaped)
90 {
91 pProxyDev->pOps->pfnUrbCancel(&Urb);
92 pUrbReaped = pProxyDev->pOps->pfnUrbReap(pProxyDev, RT_INDEFINITE_WAIT);
93 }
94 if (pUrbReaped != &Urb)
95 {
96 Log(("GetStdDescSync: pfnUrbReap failed, pUrbReaped=%p\n", pUrbReaped));
97 break;
98 }
99
100 if (Urb.enmStatus != VUSBSTATUS_OK)
101 {
102 Log(("GetStdDescSync: Urb.enmStatus=%d\n", Urb.enmStatus));
103 break;
104 }
105
106 /*
107 * Check the length, config descriptors have total_length field
108 */
109 uint8_t *pbDesc = (uint8_t *)(pSetup + 1);
110 uint32_t cbDesc;
111 if (iDescType == VUSB_DT_CONFIG)
112 {
113 if (Urb.cbData < sizeof(VUSBSETUP) + 4)
114 {
115 Log(("GetStdDescSync: Urb.cbData=%#x (min 4)\n", Urb.cbData));
116 break;
117 }
118 cbDesc = RT_LE2H_U16(((uint16_t *)pbDesc)[1]);
119 }
120 else
121 {
122 if (Urb.cbData < sizeof(VUSBSETUP) + 1)
123 {
124 Log(("GetStdDescSync: Urb.cbData=%#x (min 1)\n", Urb.cbData));
125 break;
126 }
127 cbDesc = ((uint8_t *)pbDesc)[0];
128 }
129
130 Log(("GetStdDescSync: got Urb.cbData=%u, cbDesc=%u cbHint=%u\n", Urb.cbData, cbDesc, cbHint));
131
132 if ( Urb.cbData == cbHint + sizeof(VUSBSETUP)
133 && cbDesc > Urb.cbData - sizeof(VUSBSETUP))
134 {
135 cbHint = cbDesc;
136 if (cbHint > sizeof(Urb.abData))
137 {
138 AssertMsgFailed(("cbHint=%u\n", cbHint));
139 break;
140 }
141 continue;
142 }
143 Assert(cbDesc <= Urb.cbData - sizeof(VUSBSETUP));
144#ifdef LOG_ENABLED
145 vusbUrbTrace(&Urb, "GetStdDescSync", true);
146#endif
147
148 /*
149 * Fine, we got everything return a heap duplicate of the descriptor.
150 */
151 return RTMemDup(pbDesc, cbDesc);
152 }
153 return NULL;
154}
155
156/**
157 * Frees a descriptor returned by GetStdDescSync().
158 */
159static void free_desc(void *pvDesc)
160{
161 RTMemFree(pvDesc);
162}
163
164/**
165 * Get and a device descriptor and byteswap it appropriately.
166 */
167static bool usbProxyGetDeviceDesc(PUSBPROXYDEV pProxyDev, PVUSBDESCDEVICE pOut)
168{
169 /*
170 * Get the descriptor from the device.
171 */
172 PVUSBDESCDEVICE pIn = (PVUSBDESCDEVICE)GetStdDescSync(pProxyDev, VUSB_DT_DEVICE, 0, 0, VUSB_DT_DEVICE_MIN_LEN);
173 if (!pIn)
174 {
175 Log(("usbProxyGetDeviceDesc: pProxyDev=%s: GetStdDescSync failed\n", pProxyDev->pUsbIns->pszName));
176 return false;
177 }
178 if (pIn->bLength < VUSB_DT_DEVICE_MIN_LEN)
179 {
180 Log(("usb-proxy: pProxyDev=%s: Corrupted device descriptor. bLength=%d\n", pProxyDev->pUsbIns->pszName, pIn->bLength));
181 return false;
182 }
183
184 /*
185 * Convert it.
186 */
187 pOut->bLength = VUSB_DT_DEVICE_MIN_LEN;
188 pOut->bDescriptorType = VUSB_DT_DEVICE;
189 pOut->bcdUSB = RT_LE2H_U16(pIn->bcdUSB);
190 pOut->bDeviceClass = pIn->bDeviceClass;
191 pOut->bDeviceSubClass = pIn->bDeviceSubClass;
192 pOut->bDeviceProtocol = pIn->bDeviceProtocol;
193 pOut->bMaxPacketSize0 = pIn->bMaxPacketSize0;
194 pOut->idVendor = RT_LE2H_U16(pIn->idVendor);
195 pOut->idProduct = RT_LE2H_U16(pIn->idProduct);
196 pOut->bcdDevice = RT_LE2H_U16(pIn->bcdDevice);
197 pOut->iManufacturer = pIn->iManufacturer;
198 pOut->iProduct = pIn->iProduct;
199 pOut->iSerialNumber = pIn->iSerialNumber;
200 pOut->bNumConfigurations = pIn->bNumConfigurations;
201
202 free_desc(pIn);
203 return true;
204}
205
206/**
207 * Count the numbers and types of each kind of descriptor that we need to
208 * copy out of the config descriptor
209 */
210struct desc_counts
211{
212 size_t num_ed, num_id, num_if;
213 /** bitmap (128 bits) */
214 uint32_t idmap[4];
215};
216
217static int count_descriptors(struct desc_counts *cnt, uint8_t *buf, size_t len)
218{
219 PVUSBDESCCONFIG cfg;
220 uint8_t *tmp, *end;
221 uint32_t i, x;
222
223 memset(cnt, 0, sizeof(*cnt));
224
225 end = buf + len;
226
227 cfg = (PVUSBDESCCONFIG)buf;
228 if ( cfg->bLength < VUSB_DT_CONFIG_MIN_LEN )
229 return 0;
230 if ( cfg->bLength > len )
231 return 0;
232
233 for (tmp = buf + cfg->bLength; ((tmp + 1) < end) && *tmp; tmp += *tmp)
234 {
235 uint8_t type;
236 uint32_t ifnum;
237 PVUSBDESCINTERFACE id;
238 PVUSBDESCENDPOINT ed;
239
240 type = *(tmp + 1);
241
242 switch ( type ) {
243 case VUSB_DT_INTERFACE:
244 id = (PVUSBDESCINTERFACE)tmp;
245 if ( id->bLength < VUSB_DT_INTERFACE_MIN_LEN )
246 return 0;
247 cnt->num_id++;
248 ifnum = id->bInterfaceNumber;
249 cnt->idmap[ifnum >> 6] |= (1 << (ifnum & 0x1f));
250 break;
251 case VUSB_DT_ENDPOINT:
252 ed = (PVUSBDESCENDPOINT)tmp;
253 if ( ed->bLength < VUSB_DT_ENDPOINT_MIN_LEN )
254 return 0;
255 cnt->num_ed++;
256 break;
257 default:
258 break;
259 }
260 }
261
262 /* count interfaces */
263 for(i=0; i < RT_ELEMENTS(cnt->idmap); i++)
264 for(x=1; x; x<<=1)
265 if ( cnt->idmap[i] & x )
266 cnt->num_if++;
267
268 return 1;
269}
270
271/* Setup a vusb_interface structure given some preallocated structures
272 * to use, (we counted them already)
273 */
274static int copy_interface(PVUSBINTERFACE pIf, uint8_t ifnum,
275 PVUSBDESCINTERFACEEX *id, PVUSBDESCENDPOINTEX *ed,
276 uint8_t *buf, size_t len)
277{
278 PVUSBDESCINTERFACEEX cur_if = NULL;
279 uint32_t altmap[4] = {0,};
280 uint8_t *tmp, *end = buf + len;
281 uint8_t alt;
282 int state;
283 size_t num_ep = 0;
284
285 buf += *(uint8_t *)buf;
286
287 pIf->cSettings = 0;
288 pIf->paSettings = NULL;
289
290 for (tmp = buf, state = 0; ((tmp + 1) < end) && *tmp; tmp += *tmp)
291 {
292 uint8_t type;
293 PVUSBDESCINTERFACE ifd;
294 PVUSBDESCENDPOINT epd;
295 PVUSBDESCENDPOINTEX cur_ep;
296
297 type = tmp[1];
298
299 switch ( type ) {
300 case VUSB_DT_INTERFACE:
301 state = 0;
302 ifd = (PVUSBDESCINTERFACE)tmp;
303
304 /* Ignoring this interface */
305 if ( ifd->bInterfaceNumber != ifnum )
306 break;
307
308 /* Check we didn't see this alternate setting already
309 * because that will break stuff
310 */
311 alt = ifd->bAlternateSetting;
312 if ( altmap[alt >> 6] & (1 << (alt & 0x1f)) )
313 return 0;
314 altmap[alt >> 6] |= (1 << (alt & 0x1f));
315
316 cur_if = *id;
317 (*id)++;
318 if ( pIf->cSettings == 0 )
319 pIf->paSettings = cur_if;
320
321 memcpy(cur_if, ifd, sizeof(cur_if->Core));
322 /** @todo copy any additional descriptor bytes into pvMore */
323
324 pIf->cSettings++;
325
326 state = 1;
327 num_ep = 0;
328 break;
329 case VUSB_DT_ENDPOINT:
330 if ( state == 0 )
331 break;
332
333 epd = (PVUSBDESCENDPOINT)tmp;
334
335 cur_ep = *ed;
336 (*ed)++;
337
338 if ( num_ep == 0 )
339 cur_if->paEndpoints = cur_ep;
340
341 if ( num_ep > cur_if->Core.bNumEndpoints )
342 return 0;
343
344 memcpy(cur_ep, epd, sizeof(cur_ep->Core));
345 /** @todo copy any additional descriptor bytes into pvMore */
346 cur_ep->Core.wMaxPacketSize = RT_LE2H_U16(cur_ep->Core.wMaxPacketSize);
347
348 num_ep++;
349 break;
350 default:
351 /** @todo Here be dragons! Additional descriptors needs copying into pvClass
352 * (RTMemDup be your friend). @bugref{2693} */
353 break;
354 }
355 }
356
357 return 1;
358}
359
360/**
361 * Copy all of a devices config descriptors, this is needed so that the USB
362 * core layer knows all about how to map the different functions on to the
363 * virtual USB bus.
364 */
365static bool copy_config(PUSBPROXYDEV pProxyDev, uint8_t idx, PVUSBDESCCONFIGEX out)
366{
367 PVUSBDESCCONFIG cfg;
368 PVUSBINTERFACE pIf;
369 PVUSBDESCINTERFACEEX ifd;
370 PVUSBDESCENDPOINTEX epd;
371 struct desc_counts cnt;
372 void *descs;
373 size_t tot_len;
374 size_t cbIface;
375 uint32_t i, x;
376
377 descs = GetStdDescSync(pProxyDev, VUSB_DT_CONFIG, idx, 0, VUSB_DT_CONFIG_MIN_LEN);
378 if ( descs == NULL ) {
379 Log(("copy_config: GetStdDescSync failed\n"));
380 return false;
381 }
382
383 cfg = (PVUSBDESCCONFIG)descs;
384 tot_len = RT_LE2H_U16(cfg->wTotalLength);
385
386 if ( !count_descriptors(&cnt, (uint8_t *)descs, tot_len) ) {
387 Log(("copy_config: count_descriptors failed\n"));
388 goto err;
389 }
390
391 if ( cfg->bNumInterfaces != cnt.num_if )
392 Log(("usb-proxy: config%u: bNumInterfaces %u != %u\n",
393 idx, cfg->bNumInterfaces, cnt.num_if));
394
395 Log(("usb-proxy: config%u: %u bytes id=%u ed=%u if=%u\n",
396 idx, tot_len, cnt.num_id, cnt.num_ed, cnt.num_if));
397
398 cbIface = cnt.num_if * sizeof(VUSBINTERFACE)
399 + cnt.num_id * sizeof(VUSBDESCINTERFACEEX)
400 + cnt.num_ed * sizeof(VUSBDESCENDPOINTEX);
401 out->paIfs = (PCVUSBINTERFACE)RTMemAllocZ(cbIface);
402 if ( out->paIfs == NULL ) {
403 free_desc(descs);
404 return false;
405 }
406
407 pIf = (PVUSBINTERFACE)out->paIfs;
408 ifd = (PVUSBDESCINTERFACEEX)&pIf[cnt.num_if];
409 epd = (PVUSBDESCENDPOINTEX)&ifd[cnt.num_id];
410
411 out->Core.bLength = cfg->bLength;
412 out->Core.bDescriptorType = cfg->bDescriptorType;
413 out->Core.wTotalLength = 0; /* Auto Calculated */
414 out->Core.bNumInterfaces = (uint8_t)cnt.num_if;
415 out->Core.bConfigurationValue = cfg->bConfigurationValue;
416 out->Core.iConfiguration = cfg->iConfiguration;
417 out->Core.bmAttributes = cfg->bmAttributes;
418 out->Core.MaxPower = cfg->MaxPower;
419
420 for(i=0; i < 4; i++)
421 for(x=0; x < 32; x++)
422 if ( cnt.idmap[i] & (1 << x) )
423 if ( !copy_interface(pIf++, (i << 6) | x, &ifd, &epd, (uint8_t *)descs, tot_len) ) {
424 Log(("copy_interface(%d,,) failed\n", pIf - 1));
425 goto err;
426 }
427
428 free_desc(descs);
429 return true;
430err:
431 Log(("usb-proxy: config%u: Corrupted configuration descriptor\n", idx));
432 free_desc(descs);
433 return false;
434}
435
436
437/**
438 * Edit out masked interface descriptors.
439 *
440 * @param pProxyDev The proxy device
441 */
442static void usbProxyDevEditOutMaskedIfs(PUSBPROXYDEV pProxyDev)
443{
444 unsigned cRemoved = 0;
445
446 PVUSBDESCCONFIGEX paCfgs = pProxyDev->paCfgDescs;
447 for (unsigned iCfg = 0; iCfg < pProxyDev->DevDesc.bNumConfigurations; iCfg++)
448 {
449 PVUSBINTERFACE paIfs = (PVUSBINTERFACE)paCfgs[iCfg].paIfs;
450 for (unsigned iIf = 0; iIf < paCfgs[iCfg].Core.bNumInterfaces; iIf++)
451 for (uint32_t iAlt = 0; iAlt < paIfs[iIf].cSettings; iAlt++)
452 if ( paIfs[iIf].paSettings[iAlt].Core.bInterfaceNumber < 32
453 && ((1 << paIfs[iIf].paSettings[iAlt].Core.bInterfaceNumber) & pProxyDev->fMaskedIfs))
454 {
455 Log(("usb-proxy: removing interface #%d (iIf=%d iAlt=%d) on config #%d (iCfg=%d)\n",
456 paIfs[iIf].paSettings[iAlt].Core.bInterfaceNumber, iIf, iAlt, paCfgs[iCfg].Core.bConfigurationValue, iCfg));
457 cRemoved++;
458
459 paCfgs[iCfg].Core.bNumInterfaces--;
460 unsigned cToCopy = paCfgs[iCfg].Core.bNumInterfaces - iIf;
461 if (cToCopy)
462 memmove(&paIfs[iIf], &paIfs[iIf + 1], sizeof(paIfs[0]) * cToCopy);
463 memset(&paIfs[iIf + cToCopy], '\0', sizeof(paIfs[0]));
464 break;
465 }
466 }
467
468 Log(("usb-proxy: edited out %d interface(s).\n", cRemoved));
469}
470
471
472/**
473 * @copydoc PDMUSBREG::pfnUsbReset
474 *
475 * USB Device Proxy: Call OS specific code to reset the device.
476 */
477static DECLCALLBACK(int) usbProxyDevReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
478{
479 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
480
481 if (pProxyDev->fMaskedIfs)
482 {
483 Log(("usbProxyDevReset: pProxyDev=%s - ignoring reset request fMaskedIfs=%#x\n", pUsbIns->pszName, pProxyDev->fMaskedIfs));
484 return VINF_SUCCESS;
485 }
486 LogFlow(("usbProxyDevReset: pProxyDev=%s\n", pUsbIns->pszName));
487 return pProxyDev->pOps->pfnReset(pProxyDev, fResetOnLinux);
488}
489
490
491/**
492 * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
493 */
494static DECLCALLBACK(PCPDMUSBDESCCACHE) usbProxyDevGetDescriptorCache(PPDMUSBINS pUsbIns)
495{
496 PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
497 return &pThis->DescCache;
498}
499
500
501/**
502 * @copydoc PDMUSBREG::pfnUsbSetConfiguration
503 *
504 * USB Device Proxy: Release claimed interfaces, tell the OS+device about the config change, claim the new interfaces.
505 */
506static DECLCALLBACK(int) usbProxyDevSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
507 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
508{
509 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
510 LogFlow(("usbProxyDevSetConfiguration: pProxyDev=%s iActiveCfg=%d bConfigurationValue=%d\n",
511 pUsbIns->pszName, pProxyDev->iActiveCfg, bConfigurationValue));
512
513 /*
514 * Release the current config.
515 */
516 if (pvOldCfgDesc)
517 {
518 PCVUSBDESCCONFIGEX pOldCfgDesc = (PCVUSBDESCCONFIGEX)pvOldCfgDesc;
519 PCVUSBINTERFACESTATE pOldIfState = (PCVUSBINTERFACESTATE)pvOldIfState;
520 for (unsigned i = 0; i < pOldCfgDesc->Core.bNumInterfaces; i++)
521 if (pOldIfState[i].pCurIfDesc)
522 pProxyDev->pOps->pfnReleaseInterface(pProxyDev, pOldIfState[i].pCurIfDesc->Core.bInterfaceNumber);
523 }
524
525 /*
526 * Do the actual SET_CONFIGURE.
527 * The mess here is because most backends will already have selected a
528 * configuration and there are a bunch of devices which will freak out
529 * if we do SET_CONFIGURE twice with the same value. (PalmOne, TrekStor USB-StickGO, ..)
530 *
531 * After open and reset the backend should use the members iActiveCfg and cIgnoreSetConfigs
532 * to indicate the new configuration state and what to do on the next SET_CONFIGURATION call.
533 */
534 if ( pProxyDev->iActiveCfg != bConfigurationValue
535 || ( bConfigurationValue == 0
536 && pProxyDev->iActiveCfg != -1 /* this test doesn't make sense, we know it's 0 */
537 && pProxyDev->cIgnoreSetConfigs >= 2)
538 || !pProxyDev->cIgnoreSetConfigs)
539 {
540 pProxyDev->cIgnoreSetConfigs = 0;
541 if (!pProxyDev->pOps->pfnSetConfig(pProxyDev, bConfigurationValue))
542 {
543 pProxyDev->iActiveCfg = -1;
544 return VERR_GENERAL_FAILURE;
545 }
546 pProxyDev->iActiveCfg = bConfigurationValue;
547 }
548 else if (pProxyDev->cIgnoreSetConfigs > 0)
549 pProxyDev->cIgnoreSetConfigs--;
550
551 /*
552 * Claim the interfaces.
553 */
554 PCVUSBDESCCONFIGEX pNewCfgDesc = (PCVUSBDESCCONFIGEX)pvNewCfgDesc;
555 Assert(pNewCfgDesc->Core.bConfigurationValue == bConfigurationValue);
556 for (unsigned iIf = 0; iIf < pNewCfgDesc->Core.bNumInterfaces; iIf++)
557 {
558 PCVUSBINTERFACE pIf = &pNewCfgDesc->paIfs[iIf];
559 for (uint32_t iAlt = 0; iAlt < pIf->cSettings; iAlt++)
560 {
561 if (pIf->paSettings[iAlt].Core.bAlternateSetting != 0)
562 continue;
563 pProxyDev->pOps->pfnClaimInterface(pProxyDev, pIf->paSettings[iAlt].Core.bInterfaceNumber);
564 /* ignore failures - the backend deals with that and does the necessary logging. */
565 break;
566 }
567 }
568
569 return VINF_SUCCESS;
570}
571
572
573/**
574 * @copydoc PDMUSBREG::pfnUsbSetInterface
575 *
576 * USB Device Proxy: Call OS specific code to select alternate interface settings.
577 */
578static DECLCALLBACK(int) usbProxyDevSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
579{
580 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
581 LogFlow(("usbProxyDevSetInterface: pProxyDev=%s bInterfaceNumber=%d bAlternateSetting=%d\n",
582 pUsbIns->pszName, bInterfaceNumber, bAlternateSetting));
583
584 /** @todo this is fishy, pfnSetInterface returns true/false from what I can see... */
585 if (pProxyDev->pOps->pfnSetInterface(pProxyDev, bInterfaceNumber, bAlternateSetting) < 0)
586 return VERR_GENERAL_FAILURE;
587 return VINF_SUCCESS;
588}
589
590
591/**
592 * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
593 *
594 * USB Device Proxy: Call OS specific code to clear the endpoint.
595 */
596static DECLCALLBACK(int) usbProxyDevClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
597{
598 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
599 LogFlow(("usbProxyDevClearHaltedEndpoint: pProxyDev=%s uEndpoint=%u\n",
600 pUsbIns->pszName, uEndpoint));
601
602 if (!pProxyDev->pOps->pfnClearHaltedEndpoint(pProxyDev, uEndpoint))
603 return VERR_GENERAL_FAILURE;
604 return VINF_SUCCESS;
605}
606
607
608/**
609 * @copydoc PDMUSBREG::pfnUrbQueue
610 *
611 * USB Device Proxy: Call OS specific code.
612 */
613static DECLCALLBACK(int) usbProxyDevUrbQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
614{
615 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
616 if (!pProxyDev->pOps->pfnUrbQueue(pUrb))
617 return pProxyDev->fDetached
618 ? VERR_VUSB_DEVICE_NOT_ATTACHED
619 : VERR_VUSB_FAILED_TO_QUEUE_URB;
620 return VINF_SUCCESS;
621}
622
623
624/**
625 * @copydoc PDMUSBREG::pfnUrbCancel
626 *
627 * USB Device Proxy: Call OS specific code.
628 */
629static DECLCALLBACK(int) usbProxyDevUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
630{
631 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
632 pProxyDev->pOps->pfnUrbCancel(pUrb);
633 return VINF_SUCCESS;
634}
635
636
637/**
638 * @copydoc PDMUSBREG::pfnUrbReap
639 *
640 * USB Device Proxy: Call OS specific code.
641 */
642static DECLCALLBACK(PVUSBURB) usbProxyDevUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
643{
644 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
645 PVUSBURB pUrb = pProxyDev->pOps->pfnUrbReap(pProxyDev, cMillies);
646 if ( pUrb
647 && pUrb->enmState == VUSBURBSTATE_CANCELLED
648 && pUrb->enmStatus == VUSBSTATUS_OK)
649 pUrb->enmStatus = VUSBSTATUS_DNR;
650 return pUrb;
651}
652
653
654/** @copydoc PDMUSBREG::pfnDestruct */
655static DECLCALLBACK(void) usbProxyDestruct(PPDMUSBINS pUsbIns)
656{
657 PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
658 Log(("usbProxyDestruct: destroying pProxyDev=%s\n", pUsbIns->pszName));
659
660 /* close it. */
661 if (pThis->fOpened)
662 {
663 pThis->pOps->pfnClose(pThis);
664 pThis->fOpened = false;
665 }
666
667 /* free the config descriptors. */
668 if (pThis->paCfgDescs)
669 {
670 for (unsigned i = 0; i < pThis->DevDesc.bNumConfigurations; i++)
671 RTMemFree((void *)pThis->paCfgDescs[i].paIfs);
672 /** @todo bugref{2693} cleanup */
673 RTMemFree(pThis->paCfgDescs);
674 pThis->paCfgDescs = NULL;
675 }
676
677 /* free dev */
678 if (&g_szDummyName[0] != pUsbIns->pszName)
679 RTStrFree(pUsbIns->pszName);
680 pUsbIns->pszName = NULL;
681}
682
683
684/**
685 * Helper function used by usbProxyConstruct when
686 * reading a filter from CFG.
687 *
688 * @returns VBox status code.
689 * @param pFilter The filter.
690 * @param enmFieldIdx The filter field indext.
691 * @param pNode The CFGM node.
692 * @param pszExact The exact value name.
693 * @param pszExpr The expression value name.
694 */
695static int usbProxyQueryNum(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, PCFGMNODE pNode, const char *pszExact, const char *pszExpr)
696{
697 char szTmp[256];
698
699 /* try exact first */
700 uint16_t u16;
701 int rc = CFGMR3QueryU16(pNode, pszExact, &u16);
702 if (RT_SUCCESS(rc))
703 {
704 rc = USBFilterSetNumExact(pFilter, enmFieldIdx, u16, true);
705 AssertRCReturn(rc, rc);
706
707 /* make sure only the exact attribute is present. */
708 rc = CFGMR3QueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
709 if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
710 {
711 szTmp[0] = '\0';
712 CFGMR3GetName(pNode, szTmp, sizeof(szTmp));
713 LogRel(("usbProxyConstruct: %s: Both %s and %s are present!\n", szTmp, pszExact, pszExpr));
714 return VERR_INVALID_PARAMETER;
715 }
716 return VINF_SUCCESS;
717 }
718 if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
719 {
720 szTmp[0] = '\0';
721 CFGMR3GetName(pNode, szTmp, sizeof(szTmp));
722 LogRel(("usbProxyConstruct: %s: %s query failed, rc=%Rrc\n", szTmp, pszExact, rc));
723 return rc;
724 }
725
726 /* expression? */
727 rc = CFGMR3QueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
728 if (RT_SUCCESS(rc))
729 {
730 rc = USBFilterSetNumExpression(pFilter, enmFieldIdx, szTmp, true);
731 AssertRCReturn(rc, rc);
732 return VINF_SUCCESS;
733 }
734 if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
735 {
736 szTmp[0] = '\0';
737 CFGMR3GetName(pNode, szTmp, sizeof(szTmp));
738 LogRel(("usbProxyConstruct: %s: %s query failed, rc=%Rrc\n", szTmp, pszExpr, rc));
739 return rc;
740 }
741
742 return VINF_SUCCESS;
743}
744
745
746/** @copydoc PDMUSBREG::pfnConstruct */
747static DECLCALLBACK(int) usbProxyConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
748{
749 PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
750 LogFlow(("usbProxyConstruct: pUsbIns=%p iInstance=%d\n", pUsbIns, iInstance));
751
752 /*
753 * Initialize the instance data.
754 */
755 pThis->pUsbIns = pUsbIns;
756 pThis->pUsbIns->pszName = g_szDummyName;
757 pThis->iActiveCfg = -1;
758 pThis->fMaskedIfs = 0;
759 pThis->fOpened = false;
760 pThis->fInited = false;
761
762 /*
763 * Read the basic configuration.
764 */
765 char szAddress[1024];
766 int rc = CFGMR3QueryString(pCfg, "Address", szAddress, sizeof(szAddress));
767 AssertRCReturn(rc, rc);
768
769 bool fRemote;
770 rc = CFGMR3QueryBool(pCfg, "Remote", &fRemote);
771 AssertRCReturn(rc, rc);
772
773 void *pvBackend;
774 rc = CFGMR3QueryPtr(pCfg, "pvBackend", &pvBackend);
775 AssertRCReturn(rc, rc);
776
777 /*
778 * Select backend and open the device.
779 */
780 if (!fRemote)
781 pThis->pOps = &g_USBProxyDeviceHost;
782 else
783 pThis->pOps = &g_USBProxyDeviceVRDP;
784 rc = pThis->pOps->pfnOpen(pThis, szAddress, pvBackend);
785 if (RT_FAILURE(rc))
786 return rc;
787 pThis->fOpened = true;
788
789 /*
790 * Get the device descriptor and format the device name (for logging).
791 */
792 if (!usbProxyGetDeviceDesc(pThis, &pThis->DevDesc))
793 {
794 Log(("usbProxyConstruct: usbProxyGetDeviceDesc failed\n"));
795 return VERR_READ_ERROR;
796 }
797
798 RTStrAPrintf(&pUsbIns->pszName, "%p[proxy %04x:%04x]", pThis, pThis->DevDesc.idVendor, pThis->DevDesc.idProduct); /** @todo append the user comment */
799 AssertReturn(pUsbIns->pszName, VERR_NO_MEMORY);
800
801 /*
802 * Get config descriptors.
803 */
804 size_t cbConfigs = pThis->DevDesc.bNumConfigurations * sizeof(pThis->paCfgDescs[0]);
805 pThis->paCfgDescs = (PVUSBDESCCONFIGEX)RTMemAllocZ(cbConfigs);
806 AssertReturn(pThis->paCfgDescs, VERR_NO_MEMORY);
807
808 unsigned i;
809 for (i = 0; i < pThis->DevDesc.bNumConfigurations; i++)
810 if (!copy_config(pThis, i, (PVUSBDESCCONFIGEX)&pThis->paCfgDescs[i]))
811 break;
812 if (i < pThis->DevDesc.bNumConfigurations)
813 {
814 Log(("usbProxyConstruct: copy_config failed, i=%d\n", i));
815 return VERR_READ_ERROR;
816 }
817
818 /*
819 * Pickup best matching global configuration for this device.
820 * The global configuration is organized like this:
821 *
822 * GlobalConfig/Whatever/
823 * |- idVendor = 300
824 * |- idProduct = 300
825 * - Config/
826 *
827 * The first level contains filter attributes which we stuff into a USBFILTER
828 * structure and match against the device info that's available. The highest
829 * ranked match is will be used. If nothing is found, the values will be
830 * queried from the GlobalConfig node (simplifies code and might actually
831 * be useful).
832 */
833 PCFGMNODE pCfgGlobalDev = pCfgGlobal;
834 PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgGlobal);
835 if (pCur)
836 {
837 /*
838 * Create a device filter from the device configuration
839 * descriptor ++. No strings currently.
840 */
841 USBFILTER Device;
842 USBFilterInit(&Device, USBFILTERTYPE_CAPTURE);
843 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_VENDOR_ID, pThis->DevDesc.idVendor, true); AssertRC(rc);
844 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_PRODUCT_ID, pThis->DevDesc.idProduct, true); AssertRC(rc);
845 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_REV, pThis->DevDesc.bcdDevice, true); AssertRC(rc);
846 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_CLASS, pThis->DevDesc.bDeviceClass, true); AssertRC(rc);
847 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_SUB_CLASS, pThis->DevDesc.bDeviceSubClass, true); AssertRC(rc);
848 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_PROTOCOL, pThis->DevDesc.bDeviceProtocol, true); AssertRC(rc);
849 /** @todo manufacturer, product and serial strings */
850
851 int iBestMatchRate = -1;
852 PCFGMNODE pBestMatch = NULL;
853 for (pCur = CFGMR3GetFirstChild(pCfgGlobal); pCur; pCur = CFGMR3GetNextChild(pCur))
854 {
855 /*
856 * Construct a filter from the attributes in the node.
857 */
858 USBFILTER Filter;
859 USBFilterInit(&Filter, USBFILTERTYPE_CAPTURE);
860
861 /* numeric */
862 if ( RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_VENDOR_ID, pCur, "idVendor", "idVendorExpr"))
863 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_PRODUCT_ID, pCur, "idProduct", "idProcutExpr"))
864 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_REV, pCur, "bcdDevice", "bcdDeviceExpr"))
865 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_CLASS, pCur, "bDeviceClass", "bDeviceClassExpr"))
866 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_SUB_CLASS, pCur, "bDeviceSubClass", "bDeviceSubClassExpr"))
867 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_PROTOCOL, pCur, "bDeviceProtocol", "bDeviceProtocolExpr")))
868 continue; /* skip it */
869
870 /* strings */
871 /** @todo manufacturer, product and serial strings */
872
873 /* ignore unknown config values, but not without bitching. */
874 if (!CFGMR3AreValuesValid(pCur,
875 "idVendor\0idVendorExpr\0"
876 "idProduct\0idProductExpr\0"
877 "bcdDevice\0bcdDeviceExpr\0"
878 "bDeviceClass\0bDeviceClassExpr\0"
879 "bDeviceSubClass\0bDeviceSubClassExpr\0"
880 "bDeviceProtocol\0bDeviceProtocolExpr\0"))
881 LogRel(("usbProxyConstruct: Unknown value(s) in config filter (ignored)!\n"));
882
883 /*
884 * Try match it and on match see if it has is a higher rate hit
885 * than the previous match. Quit if its a 100% match.
886 */
887 int iRate = USBFilterMatchRated(&Filter, &Device);
888 if (iRate > iBestMatchRate)
889 {
890 pBestMatch = pCur;
891 iBestMatchRate = iRate;
892 if (iRate >= 100)
893 break;
894 }
895 }
896 if (pBestMatch)
897 pCfgGlobalDev = CFGMR3GetChild(pBestMatch, "Config");
898 if (pCfgGlobalDev)
899 pCfgGlobalDev = pCfgGlobal;
900 }
901
902 /*
903 * Query the rest of the configuration using the global as fallback.
904 */
905 rc = CFGMR3QueryU32(pCfg, "MaskedIfs", &pThis->fMaskedIfs);
906 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
907 rc = CFGMR3QueryU32(pCfgGlobalDev, "MaskedIfs", &pThis->fMaskedIfs);
908 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
909 pThis->fMaskedIfs = 0;
910 else
911 AssertRCReturn(rc, rc);
912
913 bool fForce11Device;
914 rc = CFGMR3QueryBool(pCfg, "Force11Device", &fForce11Device);
915 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
916 rc = CFGMR3QueryBool(pCfgGlobalDev, "Force11Device", &fForce11Device);
917 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
918 fForce11Device = false;
919 else
920 AssertRCReturn(rc, rc);
921
922 bool fForce11PacketSize;
923 rc = CFGMR3QueryBool(pCfg, "Force11PacketSize", &fForce11PacketSize);
924 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
925 rc = CFGMR3QueryBool(pCfgGlobalDev, "Force11PacketSize", &fForce11PacketSize);
926 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
927 fForce11PacketSize = false;
928 else
929 AssertRCReturn(rc, rc);
930
931 /*
932 * If we're masking interfaces, edit the descriptors.
933 */
934 bool fEdited = pThis->fMaskedIfs != 0;
935 if (pThis->fMaskedIfs)
936 usbProxyDevEditOutMaskedIfs(pThis);
937
938 /*
939 * Do 2.0 -> 1.1 device edits if requested to do so.
940 */
941 if ( fForce11PacketSize
942 && pThis->DevDesc.bcdUSB >= 0x0200)
943 {
944 PVUSBDESCCONFIGEX paCfgs = pThis->paCfgDescs;
945 for (unsigned iCfg = 0; iCfg < pThis->DevDesc.bNumConfigurations; iCfg++)
946 {
947 PVUSBINTERFACE paIfs = (PVUSBINTERFACE)paCfgs[iCfg].paIfs;
948 for (unsigned iIf = 0; iIf < paCfgs[iCfg].Core.bNumInterfaces; iIf++)
949 for (uint32_t iAlt = 0; iAlt < paIfs[iIf].cSettings; iAlt++)
950 {
951 /*
952 * USB 1.1 defines the max for control, interrupt and bulk to be 64 bytes.
953 * While isochronous has a max of 1023 bytes.
954 */
955 PVUSBDESCENDPOINTEX paEps = (PVUSBDESCENDPOINTEX)paIfs[iIf].paSettings[iAlt].paEndpoints;
956 for (unsigned iEp = 0; iEp < paIfs[iIf].paSettings[iAlt].Core.bNumEndpoints; iEp++)
957 {
958 const uint16_t cbMax = (paEps[iEp].Core.bmAttributes & 3) == 1 /* isoc */
959 ? 1023
960 : 64;
961 if (paEps[iEp].Core.wMaxPacketSize > cbMax)
962 {
963 Log(("usb-proxy: pProxyDev=%s correcting wMaxPacketSize from %#x to %#x (mainly for vista)\n",
964 pUsbIns->pszName, paEps[iEp].Core.wMaxPacketSize, cbMax));
965 paEps[iEp].Core.wMaxPacketSize = cbMax;
966 fEdited = true;
967 }
968 }
969 }
970 }
971 }
972
973 if ( fForce11Device
974 && pThis->DevDesc.bcdUSB == 0x0200)
975 {
976 /*
977 * Discourages windows from helping you find a 2.0 port.
978 */
979 Log(("usb-proxy: %s correcting USB version 2.0 to 1.1 (to avoid Windows warning)\n", pUsbIns->pszName));
980 pThis->DevDesc.bcdUSB = 0x110;
981 fEdited = true;
982 }
983
984
985 /*
986 * Init the PDM/VUSB descriptor cache.
987 */
988 pThis->DescCache.pDevice = &pThis->DevDesc;
989 pThis->DescCache.paConfigs = pThis->paCfgDescs;
990 pThis->DescCache.paLanguages = NULL;
991 pThis->DescCache.cLanguages = 0;
992 pThis->DescCache.fUseCachedDescriptors = fEdited;
993 pThis->DescCache.fUseCachedStringsDescriptors = false;
994
995 /*
996 * Call the backend if it wishes to do some more initializing
997 * after we've read the config and descriptors.
998 */
999 if (pThis->pOps->pfnInit)
1000 {
1001 rc = pThis->pOps->pfnInit(pThis);
1002 if (RT_FAILURE(rc))
1003 return rc;
1004 }
1005 pThis->fInited = true;
1006
1007 /*
1008 * We're good!
1009 */
1010 Log(("usb-proxy: created pProxyDev=%s address '%s' fMaskedIfs=%#x (rc=%Rrc)\n",
1011 pUsbIns->pszName, szAddress, pThis->fMaskedIfs, rc));
1012 return VINF_SUCCESS;
1013}
1014
1015
1016/**
1017 * The USB proxy device registration record.
1018 */
1019const PDMUSBREG g_UsbDevProxy =
1020{
1021 /* u32Version */
1022 PDM_USBREG_VERSION,
1023 /* szName */
1024 "USBProxy",
1025 /* pszDescription */
1026 "USB Proxy Device.",
1027 /* fFlags */
1028 0,
1029 /* cMaxInstances */
1030 ~0,
1031 /* cbInstance */
1032 sizeof(USBPROXYDEV),
1033 /* pfnConstruct */
1034 usbProxyConstruct,
1035 /* pfnDestruct */
1036 usbProxyDestruct,
1037 /* pfnVMInitComplete */
1038 NULL,
1039 /* pfnVMPowerOn */
1040 NULL,
1041 /* pfnVMReset */
1042 NULL,
1043 /* pfnVMSuspend */
1044 NULL,
1045 /* pfnVMResume */
1046 NULL,
1047 /* pfnVMPowerOff */
1048 NULL,
1049 /* pfnHotPlugged */
1050 NULL,
1051 /* pfnHotUnplugged */
1052 NULL,
1053 /* pfnDriverAttach */
1054 NULL,
1055 /* pfnDriverDetach */
1056 NULL,
1057 /* pfnQueryInterface */
1058 NULL,
1059 /* pfnUsbReset */
1060 usbProxyDevReset,
1061 /* pfnUsbGetDescriptorCache */
1062 usbProxyDevGetDescriptorCache,
1063 /* pfnUsbSetConfiguration */
1064 usbProxyDevSetConfiguration,
1065 /* pfnUsbSetInterface */
1066 usbProxyDevSetInterface,
1067 /* pfnUsbClearHaltedEndpoint */
1068 usbProxyDevClearHaltedEndpoint,
1069 /* pfnUrbNew */
1070 NULL,
1071 /* pfnUrbQueue */
1072 usbProxyDevUrbQueue,
1073 /* pfnUrbCancel */
1074 usbProxyDevUrbCancel,
1075 /* pfnUrbReap */
1076 usbProxyDevUrbReap,
1077
1078 /* u32TheEnd */
1079 PDM_USBREG_VERSION
1080};
1081
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