VirtualBox

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

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

USB: Store original config descriptor and refer to it for some non-standard data.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.4 KB
Line 
1/* $Id: USBProxyDevice.cpp 36475 2011-03-30 16:08:57Z 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
323 /* Point to additional interface descriptor bytes, if any. */
324 AssertCompile(sizeof(cur_if->Core) == VUSB_DT_INTERFACE_MIN_LEN);
325 if (cur_if->Core.bLength - VUSB_DT_INTERFACE_MIN_LEN > 0)
326 cur_if->pvMore = tmp + VUSB_DT_INTERFACE_MIN_LEN;
327 else
328 cur_if->pvMore = NULL;
329
330 pIf->cSettings++;
331
332 state = 1;
333 num_ep = 0;
334 break;
335 case VUSB_DT_ENDPOINT:
336 if ( state == 0 )
337 break;
338
339 epd = (PVUSBDESCENDPOINT)tmp;
340
341 cur_ep = *ed;
342 (*ed)++;
343
344 if ( num_ep == 0 )
345 cur_if->paEndpoints = cur_ep;
346
347 if ( num_ep > cur_if->Core.bNumEndpoints )
348 return 0;
349
350 memcpy(cur_ep, epd, sizeof(cur_ep->Core));
351
352 /* Point to additional endpoint descriptor bytes, if any. */
353 AssertCompile(sizeof(cur_ep->Core) == VUSB_DT_ENDPOINT_MIN_LEN);
354 if (cur_ep->Core.bLength - VUSB_DT_ENDPOINT_MIN_LEN > 0)
355 cur_ep->pvMore = tmp + VUSB_DT_ENDPOINT_MIN_LEN;
356 else
357 cur_ep->pvMore = NULL;
358
359 cur_ep->Core.wMaxPacketSize = RT_LE2H_U16(cur_ep->Core.wMaxPacketSize);
360
361 num_ep++;
362 break;
363 default:
364 /** @todo Here be dragons! Additional descriptors needs copying into pvClass
365 * (RTMemDup be your friend). @bugref{2693} */
366 break;
367 }
368 }
369
370 return 1;
371}
372
373/**
374 * Copy all of a devices config descriptors, this is needed so that the USB
375 * core layer knows all about how to map the different functions on to the
376 * virtual USB bus.
377 */
378static bool copy_config(PUSBPROXYDEV pProxyDev, uint8_t idx, PVUSBDESCCONFIGEX out)
379{
380 PVUSBDESCCONFIG cfg;
381 PVUSBINTERFACE pIf;
382 PVUSBDESCINTERFACEEX ifd;
383 PVUSBDESCENDPOINTEX epd;
384 struct desc_counts cnt;
385 void *descs;
386 size_t tot_len;
387 size_t cbIface;
388 uint32_t i, x;
389
390 descs = GetStdDescSync(pProxyDev, VUSB_DT_CONFIG, idx, 0, VUSB_DT_CONFIG_MIN_LEN);
391 if ( descs == NULL ) {
392 Log(("copy_config: GetStdDescSync failed\n"));
393 return false;
394 }
395
396 cfg = (PVUSBDESCCONFIG)descs;
397 tot_len = RT_LE2H_U16(cfg->wTotalLength);
398
399 if ( !count_descriptors(&cnt, (uint8_t *)descs, tot_len) ) {
400 Log(("copy_config: count_descriptors failed\n"));
401 goto err;
402 }
403
404 if ( cfg->bNumInterfaces != cnt.num_if )
405 Log(("usb-proxy: config%u: bNumInterfaces %u != %u\n",
406 idx, cfg->bNumInterfaces, cnt.num_if));
407
408 Log(("usb-proxy: config%u: %u bytes id=%u ed=%u if=%u\n",
409 idx, tot_len, cnt.num_id, cnt.num_ed, cnt.num_if));
410
411 cbIface = cnt.num_if * sizeof(VUSBINTERFACE)
412 + cnt.num_id * sizeof(VUSBDESCINTERFACEEX)
413 + cnt.num_ed * sizeof(VUSBDESCENDPOINTEX);
414 out->paIfs = (PCVUSBINTERFACE)RTMemAllocZ(cbIface);
415 if ( out->paIfs == NULL ) {
416 free_desc(descs);
417 return false;
418 }
419
420 /* Stash a pointer to the raw config descriptor; we may need bits of it later. */
421 out->pvOriginal = descs;
422
423 pIf = (PVUSBINTERFACE)out->paIfs;
424 ifd = (PVUSBDESCINTERFACEEX)&pIf[cnt.num_if];
425 epd = (PVUSBDESCENDPOINTEX)&ifd[cnt.num_id];
426
427 out->Core.bLength = cfg->bLength;
428 out->Core.bDescriptorType = cfg->bDescriptorType;
429 out->Core.wTotalLength = 0; /* Auto Calculated */
430 out->Core.bNumInterfaces = (uint8_t)cnt.num_if;
431 out->Core.bConfigurationValue = cfg->bConfigurationValue;
432 out->Core.iConfiguration = cfg->iConfiguration;
433 out->Core.bmAttributes = cfg->bmAttributes;
434 out->Core.MaxPower = cfg->MaxPower;
435
436 for(i=0; i < 4; i++)
437 for(x=0; x < 32; x++)
438 if ( cnt.idmap[i] & (1 << x) )
439 if ( !copy_interface(pIf++, (i << 6) | x, &ifd, &epd, (uint8_t *)descs, tot_len) ) {
440 Log(("copy_interface(%d,,) failed\n", pIf - 1));
441 goto err;
442 }
443
444 return true;
445err:
446 Log(("usb-proxy: config%u: Corrupted configuration descriptor\n", idx));
447 free_desc(descs);
448 return false;
449}
450
451
452/**
453 * Edit out masked interface descriptors.
454 *
455 * @param pProxyDev The proxy device
456 */
457static void usbProxyDevEditOutMaskedIfs(PUSBPROXYDEV pProxyDev)
458{
459 unsigned cRemoved = 0;
460
461 PVUSBDESCCONFIGEX paCfgs = pProxyDev->paCfgDescs;
462 for (unsigned iCfg = 0; iCfg < pProxyDev->DevDesc.bNumConfigurations; iCfg++)
463 {
464 PVUSBINTERFACE paIfs = (PVUSBINTERFACE)paCfgs[iCfg].paIfs;
465 for (unsigned iIf = 0; iIf < paCfgs[iCfg].Core.bNumInterfaces; iIf++)
466 for (uint32_t iAlt = 0; iAlt < paIfs[iIf].cSettings; iAlt++)
467 if ( paIfs[iIf].paSettings[iAlt].Core.bInterfaceNumber < 32
468 && ((1 << paIfs[iIf].paSettings[iAlt].Core.bInterfaceNumber) & pProxyDev->fMaskedIfs))
469 {
470 Log(("usb-proxy: removing interface #%d (iIf=%d iAlt=%d) on config #%d (iCfg=%d)\n",
471 paIfs[iIf].paSettings[iAlt].Core.bInterfaceNumber, iIf, iAlt, paCfgs[iCfg].Core.bConfigurationValue, iCfg));
472 cRemoved++;
473
474 paCfgs[iCfg].Core.bNumInterfaces--;
475 unsigned cToCopy = paCfgs[iCfg].Core.bNumInterfaces - iIf;
476 if (cToCopy)
477 memmove(&paIfs[iIf], &paIfs[iIf + 1], sizeof(paIfs[0]) * cToCopy);
478 memset(&paIfs[iIf + cToCopy], '\0', sizeof(paIfs[0]));
479 break;
480 }
481 }
482
483 Log(("usb-proxy: edited out %d interface(s).\n", cRemoved));
484}
485
486
487/**
488 * @copydoc PDMUSBREG::pfnUsbReset
489 *
490 * USB Device Proxy: Call OS specific code to reset the device.
491 */
492static DECLCALLBACK(int) usbProxyDevReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
493{
494 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
495
496 if (pProxyDev->fMaskedIfs)
497 {
498 Log(("usbProxyDevReset: pProxyDev=%s - ignoring reset request fMaskedIfs=%#x\n", pUsbIns->pszName, pProxyDev->fMaskedIfs));
499 return VINF_SUCCESS;
500 }
501 LogFlow(("usbProxyDevReset: pProxyDev=%s\n", pUsbIns->pszName));
502 return pProxyDev->pOps->pfnReset(pProxyDev, fResetOnLinux);
503}
504
505
506/**
507 * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
508 */
509static DECLCALLBACK(PCPDMUSBDESCCACHE) usbProxyDevGetDescriptorCache(PPDMUSBINS pUsbIns)
510{
511 PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
512 return &pThis->DescCache;
513}
514
515
516/**
517 * @copydoc PDMUSBREG::pfnUsbSetConfiguration
518 *
519 * USB Device Proxy: Release claimed interfaces, tell the OS+device about the config change, claim the new interfaces.
520 */
521static DECLCALLBACK(int) usbProxyDevSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
522 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
523{
524 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
525 LogFlow(("usbProxyDevSetConfiguration: pProxyDev=%s iActiveCfg=%d bConfigurationValue=%d\n",
526 pUsbIns->pszName, pProxyDev->iActiveCfg, bConfigurationValue));
527
528 /*
529 * Release the current config.
530 */
531 if (pvOldCfgDesc)
532 {
533 PCVUSBDESCCONFIGEX pOldCfgDesc = (PCVUSBDESCCONFIGEX)pvOldCfgDesc;
534 PCVUSBINTERFACESTATE pOldIfState = (PCVUSBINTERFACESTATE)pvOldIfState;
535 for (unsigned i = 0; i < pOldCfgDesc->Core.bNumInterfaces; i++)
536 if (pOldIfState[i].pCurIfDesc)
537 pProxyDev->pOps->pfnReleaseInterface(pProxyDev, pOldIfState[i].pCurIfDesc->Core.bInterfaceNumber);
538 }
539
540 /*
541 * Do the actual SET_CONFIGURE.
542 * The mess here is because most backends will already have selected a
543 * configuration and there are a bunch of devices which will freak out
544 * if we do SET_CONFIGURE twice with the same value. (PalmOne, TrekStor USB-StickGO, ..)
545 *
546 * After open and reset the backend should use the members iActiveCfg and cIgnoreSetConfigs
547 * to indicate the new configuration state and what to do on the next SET_CONFIGURATION call.
548 */
549 if ( pProxyDev->iActiveCfg != bConfigurationValue
550 || ( bConfigurationValue == 0
551 && pProxyDev->iActiveCfg != -1 /* this test doesn't make sense, we know it's 0 */
552 && pProxyDev->cIgnoreSetConfigs >= 2)
553 || !pProxyDev->cIgnoreSetConfigs)
554 {
555 pProxyDev->cIgnoreSetConfigs = 0;
556 if (!pProxyDev->pOps->pfnSetConfig(pProxyDev, bConfigurationValue))
557 {
558 pProxyDev->iActiveCfg = -1;
559 return VERR_GENERAL_FAILURE;
560 }
561 pProxyDev->iActiveCfg = bConfigurationValue;
562 }
563 else if (pProxyDev->cIgnoreSetConfigs > 0)
564 pProxyDev->cIgnoreSetConfigs--;
565
566 /*
567 * Claim the interfaces.
568 */
569 PCVUSBDESCCONFIGEX pNewCfgDesc = (PCVUSBDESCCONFIGEX)pvNewCfgDesc;
570 Assert(pNewCfgDesc->Core.bConfigurationValue == bConfigurationValue);
571 for (unsigned iIf = 0; iIf < pNewCfgDesc->Core.bNumInterfaces; iIf++)
572 {
573 PCVUSBINTERFACE pIf = &pNewCfgDesc->paIfs[iIf];
574 for (uint32_t iAlt = 0; iAlt < pIf->cSettings; iAlt++)
575 {
576 if (pIf->paSettings[iAlt].Core.bAlternateSetting != 0)
577 continue;
578 pProxyDev->pOps->pfnClaimInterface(pProxyDev, pIf->paSettings[iAlt].Core.bInterfaceNumber);
579 /* ignore failures - the backend deals with that and does the necessary logging. */
580 break;
581 }
582 }
583
584 return VINF_SUCCESS;
585}
586
587
588/**
589 * @copydoc PDMUSBREG::pfnUsbSetInterface
590 *
591 * USB Device Proxy: Call OS specific code to select alternate interface settings.
592 */
593static DECLCALLBACK(int) usbProxyDevSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
594{
595 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
596 LogFlow(("usbProxyDevSetInterface: pProxyDev=%s bInterfaceNumber=%d bAlternateSetting=%d\n",
597 pUsbIns->pszName, bInterfaceNumber, bAlternateSetting));
598
599 /** @todo this is fishy, pfnSetInterface returns true/false from what I can see... */
600 if (pProxyDev->pOps->pfnSetInterface(pProxyDev, bInterfaceNumber, bAlternateSetting) < 0)
601 return VERR_GENERAL_FAILURE;
602 return VINF_SUCCESS;
603}
604
605
606/**
607 * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
608 *
609 * USB Device Proxy: Call OS specific code to clear the endpoint.
610 */
611static DECLCALLBACK(int) usbProxyDevClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
612{
613 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
614 LogFlow(("usbProxyDevClearHaltedEndpoint: pProxyDev=%s uEndpoint=%u\n",
615 pUsbIns->pszName, uEndpoint));
616
617 if (!pProxyDev->pOps->pfnClearHaltedEndpoint(pProxyDev, uEndpoint))
618 return VERR_GENERAL_FAILURE;
619 return VINF_SUCCESS;
620}
621
622
623/**
624 * @copydoc PDMUSBREG::pfnUrbQueue
625 *
626 * USB Device Proxy: Call OS specific code.
627 */
628static DECLCALLBACK(int) usbProxyDevUrbQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
629{
630 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
631 if (!pProxyDev->pOps->pfnUrbQueue(pUrb))
632 return pProxyDev->fDetached
633 ? VERR_VUSB_DEVICE_NOT_ATTACHED
634 : VERR_VUSB_FAILED_TO_QUEUE_URB;
635 return VINF_SUCCESS;
636}
637
638
639/**
640 * @copydoc PDMUSBREG::pfnUrbCancel
641 *
642 * USB Device Proxy: Call OS specific code.
643 */
644static DECLCALLBACK(int) usbProxyDevUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
645{
646 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
647 pProxyDev->pOps->pfnUrbCancel(pUrb);
648 return VINF_SUCCESS;
649}
650
651
652/**
653 * @copydoc PDMUSBREG::pfnUrbReap
654 *
655 * USB Device Proxy: Call OS specific code.
656 */
657static DECLCALLBACK(PVUSBURB) usbProxyDevUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
658{
659 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
660 PVUSBURB pUrb = pProxyDev->pOps->pfnUrbReap(pProxyDev, cMillies);
661 if ( pUrb
662 && pUrb->enmState == VUSBURBSTATE_CANCELLED
663 && pUrb->enmStatus == VUSBSTATUS_OK)
664 pUrb->enmStatus = VUSBSTATUS_DNR;
665 return pUrb;
666}
667
668
669/** @copydoc PDMUSBREG::pfnDestruct */
670static DECLCALLBACK(void) usbProxyDestruct(PPDMUSBINS pUsbIns)
671{
672 PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
673 Log(("usbProxyDestruct: destroying pProxyDev=%s\n", pUsbIns->pszName));
674
675 /* close it. */
676 if (pThis->fOpened)
677 {
678 pThis->pOps->pfnClose(pThis);
679 pThis->fOpened = false;
680 }
681
682 /* free the config descriptors. */
683 if (pThis->paCfgDescs)
684 {
685 for (unsigned i = 0; i < pThis->DevDesc.bNumConfigurations; i++)
686 {
687 RTMemFree((void *)pThis->paCfgDescs[i].paIfs);
688 RTMemFree((void *)pThis->paCfgDescs[i].pvOriginal);
689 }
690 /** @todo bugref{2693} cleanup */
691 RTMemFree(pThis->paCfgDescs);
692 pThis->paCfgDescs = NULL;
693 }
694
695 /* free dev */
696 if (&g_szDummyName[0] != pUsbIns->pszName)
697 RTStrFree(pUsbIns->pszName);
698 pUsbIns->pszName = NULL;
699}
700
701
702/**
703 * Helper function used by usbProxyConstruct when
704 * reading a filter from CFG.
705 *
706 * @returns VBox status code.
707 * @param pFilter The filter.
708 * @param enmFieldIdx The filter field indext.
709 * @param pNode The CFGM node.
710 * @param pszExact The exact value name.
711 * @param pszExpr The expression value name.
712 */
713static int usbProxyQueryNum(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, PCFGMNODE pNode, const char *pszExact, const char *pszExpr)
714{
715 char szTmp[256];
716
717 /* try exact first */
718 uint16_t u16;
719 int rc = CFGMR3QueryU16(pNode, pszExact, &u16);
720 if (RT_SUCCESS(rc))
721 {
722 rc = USBFilterSetNumExact(pFilter, enmFieldIdx, u16, true);
723 AssertRCReturn(rc, rc);
724
725 /* make sure only the exact attribute is present. */
726 rc = CFGMR3QueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
727 if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
728 {
729 szTmp[0] = '\0';
730 CFGMR3GetName(pNode, szTmp, sizeof(szTmp));
731 LogRel(("usbProxyConstruct: %s: Both %s and %s are present!\n", szTmp, pszExact, pszExpr));
732 return VERR_INVALID_PARAMETER;
733 }
734 return VINF_SUCCESS;
735 }
736 if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
737 {
738 szTmp[0] = '\0';
739 CFGMR3GetName(pNode, szTmp, sizeof(szTmp));
740 LogRel(("usbProxyConstruct: %s: %s query failed, rc=%Rrc\n", szTmp, pszExact, rc));
741 return rc;
742 }
743
744 /* expression? */
745 rc = CFGMR3QueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
746 if (RT_SUCCESS(rc))
747 {
748 rc = USBFilterSetNumExpression(pFilter, enmFieldIdx, szTmp, true);
749 AssertRCReturn(rc, rc);
750 return VINF_SUCCESS;
751 }
752 if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
753 {
754 szTmp[0] = '\0';
755 CFGMR3GetName(pNode, szTmp, sizeof(szTmp));
756 LogRel(("usbProxyConstruct: %s: %s query failed, rc=%Rrc\n", szTmp, pszExpr, rc));
757 return rc;
758 }
759
760 return VINF_SUCCESS;
761}
762
763
764/** @copydoc PDMUSBREG::pfnConstruct */
765static DECLCALLBACK(int) usbProxyConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
766{
767 PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
768 LogFlow(("usbProxyConstruct: pUsbIns=%p iInstance=%d\n", pUsbIns, iInstance));
769
770 /*
771 * Initialize the instance data.
772 */
773 pThis->pUsbIns = pUsbIns;
774 pThis->pUsbIns->pszName = g_szDummyName;
775 pThis->iActiveCfg = -1;
776 pThis->fMaskedIfs = 0;
777 pThis->fOpened = false;
778 pThis->fInited = false;
779
780 /*
781 * Read the basic configuration.
782 */
783 char szAddress[1024];
784 int rc = CFGMR3QueryString(pCfg, "Address", szAddress, sizeof(szAddress));
785 AssertRCReturn(rc, rc);
786
787 bool fRemote;
788 rc = CFGMR3QueryBool(pCfg, "Remote", &fRemote);
789 AssertRCReturn(rc, rc);
790
791 void *pvBackend;
792 rc = CFGMR3QueryPtr(pCfg, "pvBackend", &pvBackend);
793 AssertRCReturn(rc, rc);
794
795 /*
796 * Select backend and open the device.
797 */
798 if (!fRemote)
799 pThis->pOps = &g_USBProxyDeviceHost;
800 else
801 pThis->pOps = &g_USBProxyDeviceVRDP;
802 rc = pThis->pOps->pfnOpen(pThis, szAddress, pvBackend);
803 if (RT_FAILURE(rc))
804 return rc;
805 pThis->fOpened = true;
806
807 /*
808 * Get the device descriptor and format the device name (for logging).
809 */
810 if (!usbProxyGetDeviceDesc(pThis, &pThis->DevDesc))
811 {
812 Log(("usbProxyConstruct: usbProxyGetDeviceDesc failed\n"));
813 return VERR_READ_ERROR;
814 }
815
816 RTStrAPrintf(&pUsbIns->pszName, "%p[proxy %04x:%04x]", pThis, pThis->DevDesc.idVendor, pThis->DevDesc.idProduct); /** @todo append the user comment */
817 AssertReturn(pUsbIns->pszName, VERR_NO_MEMORY);
818
819 /*
820 * Get config descriptors.
821 */
822 size_t cbConfigs = pThis->DevDesc.bNumConfigurations * sizeof(pThis->paCfgDescs[0]);
823 pThis->paCfgDescs = (PVUSBDESCCONFIGEX)RTMemAllocZ(cbConfigs);
824 AssertReturn(pThis->paCfgDescs, VERR_NO_MEMORY);
825
826 unsigned i;
827 for (i = 0; i < pThis->DevDesc.bNumConfigurations; i++)
828 if (!copy_config(pThis, i, (PVUSBDESCCONFIGEX)&pThis->paCfgDescs[i]))
829 break;
830 if (i < pThis->DevDesc.bNumConfigurations)
831 {
832 Log(("usbProxyConstruct: copy_config failed, i=%d\n", i));
833 return VERR_READ_ERROR;
834 }
835
836 /*
837 * Pickup best matching global configuration for this device.
838 * The global configuration is organized like this:
839 *
840 * GlobalConfig/Whatever/
841 * |- idVendor = 300
842 * |- idProduct = 300
843 * - Config/
844 *
845 * The first level contains filter attributes which we stuff into a USBFILTER
846 * structure and match against the device info that's available. The highest
847 * ranked match is will be used. If nothing is found, the values will be
848 * queried from the GlobalConfig node (simplifies code and might actually
849 * be useful).
850 */
851 PCFGMNODE pCfgGlobalDev = pCfgGlobal;
852 PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgGlobal);
853 if (pCur)
854 {
855 /*
856 * Create a device filter from the device configuration
857 * descriptor ++. No strings currently.
858 */
859 USBFILTER Device;
860 USBFilterInit(&Device, USBFILTERTYPE_CAPTURE);
861 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_VENDOR_ID, pThis->DevDesc.idVendor, true); AssertRC(rc);
862 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_PRODUCT_ID, pThis->DevDesc.idProduct, true); AssertRC(rc);
863 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_REV, pThis->DevDesc.bcdDevice, true); AssertRC(rc);
864 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_CLASS, pThis->DevDesc.bDeviceClass, true); AssertRC(rc);
865 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_SUB_CLASS, pThis->DevDesc.bDeviceSubClass, true); AssertRC(rc);
866 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_PROTOCOL, pThis->DevDesc.bDeviceProtocol, true); AssertRC(rc);
867 /** @todo manufacturer, product and serial strings */
868
869 int iBestMatchRate = -1;
870 PCFGMNODE pBestMatch = NULL;
871 for (pCur = CFGMR3GetFirstChild(pCfgGlobal); pCur; pCur = CFGMR3GetNextChild(pCur))
872 {
873 /*
874 * Construct a filter from the attributes in the node.
875 */
876 USBFILTER Filter;
877 USBFilterInit(&Filter, USBFILTERTYPE_CAPTURE);
878
879 /* numeric */
880 if ( RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_VENDOR_ID, pCur, "idVendor", "idVendorExpr"))
881 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_PRODUCT_ID, pCur, "idProduct", "idProcutExpr"))
882 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_REV, pCur, "bcdDevice", "bcdDeviceExpr"))
883 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_CLASS, pCur, "bDeviceClass", "bDeviceClassExpr"))
884 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_SUB_CLASS, pCur, "bDeviceSubClass", "bDeviceSubClassExpr"))
885 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_PROTOCOL, pCur, "bDeviceProtocol", "bDeviceProtocolExpr")))
886 continue; /* skip it */
887
888 /* strings */
889 /** @todo manufacturer, product and serial strings */
890
891 /* ignore unknown config values, but not without bitching. */
892 if (!CFGMR3AreValuesValid(pCur,
893 "idVendor\0idVendorExpr\0"
894 "idProduct\0idProductExpr\0"
895 "bcdDevice\0bcdDeviceExpr\0"
896 "bDeviceClass\0bDeviceClassExpr\0"
897 "bDeviceSubClass\0bDeviceSubClassExpr\0"
898 "bDeviceProtocol\0bDeviceProtocolExpr\0"))
899 LogRel(("usbProxyConstruct: Unknown value(s) in config filter (ignored)!\n"));
900
901 /*
902 * Try match it and on match see if it has is a higher rate hit
903 * than the previous match. Quit if its a 100% match.
904 */
905 int iRate = USBFilterMatchRated(&Filter, &Device);
906 if (iRate > iBestMatchRate)
907 {
908 pBestMatch = pCur;
909 iBestMatchRate = iRate;
910 if (iRate >= 100)
911 break;
912 }
913 }
914 if (pBestMatch)
915 pCfgGlobalDev = CFGMR3GetChild(pBestMatch, "Config");
916 if (pCfgGlobalDev)
917 pCfgGlobalDev = pCfgGlobal;
918 }
919
920 /*
921 * Query the rest of the configuration using the global as fallback.
922 */
923 rc = CFGMR3QueryU32(pCfg, "MaskedIfs", &pThis->fMaskedIfs);
924 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
925 rc = CFGMR3QueryU32(pCfgGlobalDev, "MaskedIfs", &pThis->fMaskedIfs);
926 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
927 pThis->fMaskedIfs = 0;
928 else
929 AssertRCReturn(rc, rc);
930
931 bool fForce11Device;
932 rc = CFGMR3QueryBool(pCfg, "Force11Device", &fForce11Device);
933 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
934 rc = CFGMR3QueryBool(pCfgGlobalDev, "Force11Device", &fForce11Device);
935 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
936 fForce11Device = false;
937 else
938 AssertRCReturn(rc, rc);
939
940 bool fForce11PacketSize;
941 rc = CFGMR3QueryBool(pCfg, "Force11PacketSize", &fForce11PacketSize);
942 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
943 rc = CFGMR3QueryBool(pCfgGlobalDev, "Force11PacketSize", &fForce11PacketSize);
944 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
945 fForce11PacketSize = false;
946 else
947 AssertRCReturn(rc, rc);
948
949 /*
950 * If we're masking interfaces, edit the descriptors.
951 */
952 bool fEdited = pThis->fMaskedIfs != 0;
953 if (pThis->fMaskedIfs)
954 usbProxyDevEditOutMaskedIfs(pThis);
955
956 /*
957 * Do 2.0 -> 1.1 device edits if requested to do so.
958 */
959 if ( fForce11PacketSize
960 && pThis->DevDesc.bcdUSB >= 0x0200)
961 {
962 PVUSBDESCCONFIGEX paCfgs = pThis->paCfgDescs;
963 for (unsigned iCfg = 0; iCfg < pThis->DevDesc.bNumConfigurations; iCfg++)
964 {
965 PVUSBINTERFACE paIfs = (PVUSBINTERFACE)paCfgs[iCfg].paIfs;
966 for (unsigned iIf = 0; iIf < paCfgs[iCfg].Core.bNumInterfaces; iIf++)
967 for (uint32_t iAlt = 0; iAlt < paIfs[iIf].cSettings; iAlt++)
968 {
969 /*
970 * USB 1.1 defines the max for control, interrupt and bulk to be 64 bytes.
971 * While isochronous has a max of 1023 bytes.
972 */
973 PVUSBDESCENDPOINTEX paEps = (PVUSBDESCENDPOINTEX)paIfs[iIf].paSettings[iAlt].paEndpoints;
974 for (unsigned iEp = 0; iEp < paIfs[iIf].paSettings[iAlt].Core.bNumEndpoints; iEp++)
975 {
976 const uint16_t cbMax = (paEps[iEp].Core.bmAttributes & 3) == 1 /* isoc */
977 ? 1023
978 : 64;
979 if (paEps[iEp].Core.wMaxPacketSize > cbMax)
980 {
981 Log(("usb-proxy: pProxyDev=%s correcting wMaxPacketSize from %#x to %#x (mainly for vista)\n",
982 pUsbIns->pszName, paEps[iEp].Core.wMaxPacketSize, cbMax));
983 paEps[iEp].Core.wMaxPacketSize = cbMax;
984 fEdited = true;
985 }
986 }
987 }
988 }
989 }
990
991 if ( fForce11Device
992 && pThis->DevDesc.bcdUSB == 0x0200)
993 {
994 /*
995 * Discourages windows from helping you find a 2.0 port.
996 */
997 Log(("usb-proxy: %s correcting USB version 2.0 to 1.1 (to avoid Windows warning)\n", pUsbIns->pszName));
998 pThis->DevDesc.bcdUSB = 0x110;
999 fEdited = true;
1000 }
1001
1002
1003 /*
1004 * Init the PDM/VUSB descriptor cache.
1005 */
1006 pThis->DescCache.pDevice = &pThis->DevDesc;
1007 pThis->DescCache.paConfigs = pThis->paCfgDescs;
1008 pThis->DescCache.paLanguages = NULL;
1009 pThis->DescCache.cLanguages = 0;
1010 pThis->DescCache.fUseCachedDescriptors = fEdited;
1011 pThis->DescCache.fUseCachedStringsDescriptors = false;
1012
1013 /*
1014 * Call the backend if it wishes to do some more initializing
1015 * after we've read the config and descriptors.
1016 */
1017 if (pThis->pOps->pfnInit)
1018 {
1019 rc = pThis->pOps->pfnInit(pThis);
1020 if (RT_FAILURE(rc))
1021 return rc;
1022 }
1023 pThis->fInited = true;
1024
1025 /*
1026 * We're good!
1027 */
1028 Log(("usb-proxy: created pProxyDev=%s address '%s' fMaskedIfs=%#x (rc=%Rrc)\n",
1029 pUsbIns->pszName, szAddress, pThis->fMaskedIfs, rc));
1030 return VINF_SUCCESS;
1031}
1032
1033
1034/**
1035 * The USB proxy device registration record.
1036 */
1037const PDMUSBREG g_UsbDevProxy =
1038{
1039 /* u32Version */
1040 PDM_USBREG_VERSION,
1041 /* szName */
1042 "USBProxy",
1043 /* pszDescription */
1044 "USB Proxy Device.",
1045 /* fFlags */
1046 0,
1047 /* cMaxInstances */
1048 ~0,
1049 /* cbInstance */
1050 sizeof(USBPROXYDEV),
1051 /* pfnConstruct */
1052 usbProxyConstruct,
1053 /* pfnDestruct */
1054 usbProxyDestruct,
1055 /* pfnVMInitComplete */
1056 NULL,
1057 /* pfnVMPowerOn */
1058 NULL,
1059 /* pfnVMReset */
1060 NULL,
1061 /* pfnVMSuspend */
1062 NULL,
1063 /* pfnVMResume */
1064 NULL,
1065 /* pfnVMPowerOff */
1066 NULL,
1067 /* pfnHotPlugged */
1068 NULL,
1069 /* pfnHotUnplugged */
1070 NULL,
1071 /* pfnDriverAttach */
1072 NULL,
1073 /* pfnDriverDetach */
1074 NULL,
1075 /* pfnQueryInterface */
1076 NULL,
1077 /* pfnUsbReset */
1078 usbProxyDevReset,
1079 /* pfnUsbGetDescriptorCache */
1080 usbProxyDevGetDescriptorCache,
1081 /* pfnUsbSetConfiguration */
1082 usbProxyDevSetConfiguration,
1083 /* pfnUsbSetInterface */
1084 usbProxyDevSetInterface,
1085 /* pfnUsbClearHaltedEndpoint */
1086 usbProxyDevClearHaltedEndpoint,
1087 /* pfnUrbNew */
1088 NULL,
1089 /* pfnUrbQueue */
1090 usbProxyDevUrbQueue,
1091 /* pfnUrbCancel */
1092 usbProxyDevUrbCancel,
1093 /* pfnUrbReap */
1094 usbProxyDevUrbReap,
1095
1096 /* u32TheEnd */
1097 PDM_USBREG_VERSION
1098};
1099
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