VirtualBox

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

Last change on this file since 91627 was 90051, checked in by vboxsync, 3 years ago

VUSB: Only edit descriptors to hide remote wakeup when device actually reports it (see bugref:10059).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.9 KB
Line 
1/* $Id: USBProxyDevice.cpp 90051 2021-07-06 10:27:32Z vboxsync $ */
2/** @file
3 * USBProxy - USB device proxy.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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 * Array of supported proxy backends.
44 */
45static PCUSBPROXYBACK g_aUsbProxies[] =
46{
47 &g_USBProxyDeviceHost,
48 &g_USBProxyDeviceVRDP,
49 &g_USBProxyDeviceUsbIp
50};
51
52/* Synchronously obtain a standard USB descriptor for a device, used in order
53 * to grab configuration descriptors when we first add the device
54 */
55static void *GetStdDescSync(PUSBPROXYDEV pProxyDev, uint8_t iDescType, uint8_t iIdx, uint16_t LangId, uint16_t cbHint)
56{
57#define GET_DESC_RETRIES 6
58 int cRetries = 0;
59 uint16_t cbInitialHint = cbHint;
60
61 LogFlow(("GetStdDescSync: pProxyDev=%s, iDescType=%d, iIdx=%d, LangId=%04X, cbHint=%u\n", pProxyDev->pUsbIns->pszName, iDescType, iIdx, LangId, cbHint));
62 for (;;)
63 {
64 /*
65 * Setup a MSG URB, queue and reap it.
66 */
67 int rc = VINF_SUCCESS;
68 VUSBURB Urb;
69 AssertCompile(RT_SIZEOFMEMB(VUSBURB, abData) >= _4K);
70 RT_ZERO(Urb);
71 Urb.u32Magic = VUSBURB_MAGIC;
72 Urb.enmState = VUSBURBSTATE_IN_FLIGHT;
73 Urb.pszDesc = (char*)"URB sync";
74 Urb.DstAddress = 0;
75 Urb.EndPt = 0;
76 Urb.enmType = VUSBXFERTYPE_MSG;
77 Urb.enmDir = VUSBDIRECTION_IN;
78 Urb.fShortNotOk = false;
79 Urb.enmStatus = VUSBSTATUS_INVALID;
80 cbHint = RT_MIN(cbHint, sizeof(Urb.abData) - sizeof(VUSBSETUP));
81 Urb.cbData = cbHint + sizeof(VUSBSETUP);
82
83 PVUSBSETUP pSetup = (PVUSBSETUP)Urb.abData;
84 pSetup->bmRequestType = VUSB_DIR_TO_HOST | VUSB_REQ_STANDARD | VUSB_TO_DEVICE;
85 pSetup->bRequest = VUSB_REQ_GET_DESCRIPTOR;
86 pSetup->wValue = (iDescType << 8) | iIdx;
87 pSetup->wIndex = LangId;
88 pSetup->wLength = cbHint;
89
90 uint8_t *pbDesc = (uint8_t *)(pSetup + 1);
91 uint32_t cbDesc = 0;
92 PVUSBURB pUrbReaped = NULL;
93
94 rc = pProxyDev->pOps->pfnUrbQueue(pProxyDev, &Urb);
95 if (RT_FAILURE(rc))
96 {
97 Log(("GetStdDescSync: pfnUrbQueue failed, rc=%d\n", rc));
98 goto err;
99 }
100
101 /* Don't wait forever, it's just a simple request that should
102 return immediately. Since we're executing in the EMT thread
103 it's important not to get stuck here. (Some of the builtin
104 iMac devices may refuse to respond for instance.) */
105 pUrbReaped = pProxyDev->pOps->pfnUrbReap(pProxyDev, 5000 /* ms */);
106 if (!pUrbReaped)
107 {
108 Log(("GetStdDescSync: pfnUrbReap returned NULL, cancel and re-reap\n"));
109 rc = pProxyDev->pOps->pfnUrbCancel(pProxyDev, &Urb);
110 AssertRC(rc);
111 /** @todo This breaks the comment above... */
112 pUrbReaped = pProxyDev->pOps->pfnUrbReap(pProxyDev, RT_INDEFINITE_WAIT);
113 }
114 if (pUrbReaped != &Urb)
115 {
116 Log(("GetStdDescSync: pfnUrbReap failed, pUrbReaped=%p\n", pUrbReaped));
117 goto err;
118 }
119
120 if (Urb.enmStatus != VUSBSTATUS_OK)
121 {
122 Log(("GetStdDescSync: Urb.enmStatus=%d\n", Urb.enmStatus));
123 goto err;
124 }
125
126 /*
127 * Check the length, config descriptors have total_length field
128 */
129 if (iDescType == VUSB_DT_CONFIG)
130 {
131 if (Urb.cbData < sizeof(VUSBSETUP) + 4)
132 {
133 Log(("GetStdDescSync: Urb.cbData=%#x (min 4)\n", Urb.cbData));
134 goto err;
135 }
136 cbDesc = RT_LE2H_U16(((uint16_t *)pbDesc)[1]);
137 }
138 else
139 {
140 if (Urb.cbData < sizeof(VUSBSETUP) + 1)
141 {
142 Log(("GetStdDescSync: Urb.cbData=%#x (min 1)\n", Urb.cbData));
143 goto err;
144 }
145 cbDesc = ((uint8_t *)pbDesc)[0];
146 }
147
148 Log(("GetStdDescSync: got Urb.cbData=%u, cbDesc=%u cbHint=%u\n", Urb.cbData, cbDesc, cbHint));
149
150 if ( Urb.cbData == cbHint + sizeof(VUSBSETUP)
151 && cbDesc > Urb.cbData - sizeof(VUSBSETUP))
152 {
153 cbHint = cbDesc;
154 Log(("GetStdDescSync: Part descriptor, Urb.cbData=%u, cbDesc=%u cbHint=%u\n", Urb.cbData, cbDesc, cbHint));
155
156 if (cbHint > sizeof(Urb.abData))
157 {
158 Log(("GetStdDescSync: cbHint=%u, Urb.abData=%u, retrying immediately\n", cbHint, sizeof(Urb.abData)));
159 /* Not an error, go again without incrementing retry count or delaying. */
160 continue;
161 }
162
163 goto err;
164 }
165
166 if (cbDesc > Urb.cbData - sizeof(VUSBSETUP))
167 {
168 Log(("GetStdDescSync: Descriptor length too short, cbDesc=%u, Urb.cbData=%u\n", cbDesc, Urb.cbData));
169 goto err;
170 }
171
172 if ( cbInitialHint != cbHint
173 && ( cbDesc != cbHint
174 || Urb.cbData < cbInitialHint) )
175 {
176 Log(("GetStdDescSync: Descriptor length incorrect, cbDesc=%u, Urb.cbData=%u, cbHint=%u\n", cbDesc, Urb.cbData, cbHint));
177 goto err;
178 }
179
180#ifdef LOG_ENABLED
181 vusbUrbTrace(&Urb, "GetStdDescSync", true);
182#endif
183
184 /*
185 * Fine, we got everything return a heap duplicate of the descriptor.
186 */
187 return RTMemDup(pbDesc, cbDesc);
188
189err:
190 cRetries++;
191 if (cRetries < GET_DESC_RETRIES)
192 {
193 Log(("GetStdDescSync: Retrying %u/%u\n", cRetries, GET_DESC_RETRIES));
194 RTThreadSleep(100);
195 continue;
196 }
197 else
198 {
199 Log(("GetStdDescSync: Retries exceeded %u/%u. Giving up.\n", cRetries, GET_DESC_RETRIES));
200 break;
201 }
202 }
203
204 return NULL;
205}
206
207/**
208 * Frees a descriptor returned by GetStdDescSync().
209 */
210static void free_desc(void *pvDesc)
211{
212 RTMemFree(pvDesc);
213}
214
215/**
216 * Get and a device descriptor and byteswap it appropriately.
217 */
218static bool usbProxyGetDeviceDesc(PUSBPROXYDEV pProxyDev, PVUSBDESCDEVICE pOut)
219{
220 /*
221 * Get the descriptor from the device.
222 */
223 PVUSBDESCDEVICE pIn = (PVUSBDESCDEVICE)GetStdDescSync(pProxyDev, VUSB_DT_DEVICE, 0, 0, VUSB_DT_DEVICE_MIN_LEN);
224 if (!pIn)
225 {
226 Log(("usbProxyGetDeviceDesc: pProxyDev=%s: GetStdDescSync failed\n", pProxyDev->pUsbIns->pszName));
227 return false;
228 }
229 if (pIn->bLength < VUSB_DT_DEVICE_MIN_LEN)
230 {
231 Log(("usb-proxy: pProxyDev=%s: Corrupted device descriptor. bLength=%d\n", pProxyDev->pUsbIns->pszName, pIn->bLength));
232 return false;
233 }
234
235 /*
236 * Convert it.
237 */
238 pOut->bLength = VUSB_DT_DEVICE_MIN_LEN;
239 pOut->bDescriptorType = VUSB_DT_DEVICE;
240 pOut->bcdUSB = RT_LE2H_U16(pIn->bcdUSB);
241 pOut->bDeviceClass = pIn->bDeviceClass;
242 pOut->bDeviceSubClass = pIn->bDeviceSubClass;
243 pOut->bDeviceProtocol = pIn->bDeviceProtocol;
244 pOut->bMaxPacketSize0 = pIn->bMaxPacketSize0;
245 pOut->idVendor = RT_LE2H_U16(pIn->idVendor);
246 pOut->idProduct = RT_LE2H_U16(pIn->idProduct);
247 pOut->bcdDevice = RT_LE2H_U16(pIn->bcdDevice);
248 pOut->iManufacturer = pIn->iManufacturer;
249 pOut->iProduct = pIn->iProduct;
250 pOut->iSerialNumber = pIn->iSerialNumber;
251 pOut->bNumConfigurations = pIn->bNumConfigurations;
252
253 free_desc(pIn);
254 return true;
255}
256
257/**
258 * Count the numbers and types of each kind of descriptor that we need to
259 * copy out of the config descriptor
260 */
261struct desc_counts
262{
263 size_t num_ed, num_id, num_if;
264 /** bitmap (128 bits) */
265 uint32_t idmap[4];
266};
267
268static int count_descriptors(struct desc_counts *cnt, uint8_t *buf, size_t len)
269{
270 PVUSBDESCCONFIG cfg;
271 uint8_t *tmp, *end;
272 uint32_t i, x;
273
274 memset(cnt, 0, sizeof(*cnt));
275
276 end = buf + len;
277
278 cfg = (PVUSBDESCCONFIG)buf;
279 if ( cfg->bLength < VUSB_DT_CONFIG_MIN_LEN )
280 return 0;
281 if ( cfg->bLength > len )
282 return 0;
283
284 for (tmp = buf + cfg->bLength; ((tmp + 1) < end) && *tmp; tmp += *tmp)
285 {
286 uint8_t type;
287 uint32_t ifnum;
288 PVUSBDESCINTERFACE id;
289 PVUSBDESCENDPOINT ed;
290
291 type = *(tmp + 1);
292
293 switch ( type ) {
294 case VUSB_DT_INTERFACE:
295 id = (PVUSBDESCINTERFACE)tmp;
296 if ( id->bLength < VUSB_DT_INTERFACE_MIN_LEN )
297 return 0;
298 cnt->num_id++;
299 ifnum = id->bInterfaceNumber;
300 cnt->idmap[ifnum >> 6] |= (1 << (ifnum & 0x1f));
301 break;
302 case VUSB_DT_ENDPOINT:
303 ed = (PVUSBDESCENDPOINT)tmp;
304 if ( ed->bLength < VUSB_DT_ENDPOINT_MIN_LEN )
305 return 0;
306 cnt->num_ed++;
307 break;
308 default:
309 break;
310 }
311 }
312
313 /* count interfaces */
314 for(i=0; i < RT_ELEMENTS(cnt->idmap); i++)
315 for(x=1; x; x<<=1)
316 if ( cnt->idmap[i] & x )
317 cnt->num_if++;
318
319 return 1;
320}
321
322/* Given the pointer to a configuration/interface/endpoint descriptor, find any following
323 * non-standard (vendor or class) descriptors.
324 */
325static const void *collect_stray_bits(uint8_t *this_desc, uint8_t *end, uint16_t *cbExtra)
326{
327 uint8_t *tmp, *buf;
328 uint8_t type;
329
330 Assert(*(this_desc + 1) == VUSB_DT_INTERFACE || *(this_desc + 1) == VUSB_DT_ENDPOINT || *(this_desc + 1) == VUSB_DT_CONFIG);
331 buf = this_desc;
332
333 /* Skip the current configuration/interface/endpoint descriptor. */
334 buf += *(uint8_t *)buf;
335
336 /* Loop until we find another descriptor we understand. */
337 for (tmp = buf; ((tmp + 1) < end) && *tmp; tmp += *tmp)
338 {
339 type = *(tmp + 1);
340 if (type == VUSB_DT_INTERFACE || type == VUSB_DT_ENDPOINT)
341 break;
342 }
343 *cbExtra = tmp - buf;
344 if (*cbExtra)
345 return buf;
346 else
347 return NULL;
348}
349
350/* Setup a vusb_interface structure given some preallocated structures
351 * to use, (we counted them already)
352 */
353static int copy_interface(PVUSBINTERFACE pIf, uint8_t ifnum,
354 PVUSBDESCINTERFACEEX *id, PVUSBDESCENDPOINTEX *ed,
355 uint8_t *buf, size_t len)
356{
357 PVUSBDESCINTERFACEEX cur_if = NULL;
358 uint32_t altmap[4] = {0,};
359 uint8_t *tmp, *end = buf + len;
360 uint8_t alt;
361 int state;
362 size_t num_ep = 0;
363
364 buf += *(uint8_t *)buf;
365
366 pIf->cSettings = 0;
367 pIf->paSettings = NULL;
368
369 for (tmp = buf, state = 0; ((tmp + 1) < end) && *tmp; tmp += *tmp)
370 {
371 uint8_t type;
372 PVUSBDESCINTERFACE ifd;
373 PVUSBDESCENDPOINT epd;
374 PVUSBDESCENDPOINTEX cur_ep;
375
376 type = tmp[1];
377
378 switch ( type ) {
379 case VUSB_DT_INTERFACE:
380 state = 0;
381 ifd = (PVUSBDESCINTERFACE)tmp;
382
383 /* Ignoring this interface */
384 if ( ifd->bInterfaceNumber != ifnum )
385 break;
386
387 /* Check we didn't see this alternate setting already
388 * because that will break stuff
389 */
390 alt = ifd->bAlternateSetting;
391 if ( altmap[alt >> 6] & (1 << (alt & 0x1f)) )
392 return 0;
393 altmap[alt >> 6] |= (1 << (alt & 0x1f));
394
395 cur_if = *id;
396 (*id)++;
397 if ( pIf->cSettings == 0 )
398 pIf->paSettings = cur_if;
399
400 memcpy(cur_if, ifd, sizeof(cur_if->Core));
401
402 /* Point to additional interface descriptor bytes, if any. */
403 AssertCompile(sizeof(cur_if->Core) == VUSB_DT_INTERFACE_MIN_LEN);
404 if (cur_if->Core.bLength - VUSB_DT_INTERFACE_MIN_LEN > 0)
405 cur_if->pvMore = tmp + VUSB_DT_INTERFACE_MIN_LEN;
406 else
407 cur_if->pvMore = NULL;
408
409 cur_if->pvClass = collect_stray_bits(tmp, end, &cur_if->cbClass);
410
411 pIf->cSettings++;
412
413 state = 1;
414 num_ep = 0;
415 break;
416 case VUSB_DT_ENDPOINT:
417 if ( state == 0 )
418 break;
419
420 epd = (PVUSBDESCENDPOINT)tmp;
421
422 cur_ep = *ed;
423 (*ed)++;
424
425 if ( num_ep == 0 )
426 cur_if->paEndpoints = cur_ep;
427
428 if ( num_ep > cur_if->Core.bNumEndpoints )
429 return 0;
430
431 memcpy(cur_ep, epd, sizeof(cur_ep->Core));
432
433 /* Point to additional endpoint descriptor bytes, if any. */
434 AssertCompile(sizeof(cur_ep->Core) == VUSB_DT_ENDPOINT_MIN_LEN);
435 if (cur_ep->Core.bLength - VUSB_DT_ENDPOINT_MIN_LEN > 0)
436 cur_ep->pvMore = tmp + VUSB_DT_ENDPOINT_MIN_LEN;
437 else
438 cur_ep->pvMore = NULL;
439
440 cur_ep->pvClass = collect_stray_bits(tmp, end, &cur_ep->cbClass);
441
442 cur_ep->Core.wMaxPacketSize = RT_LE2H_U16(cur_ep->Core.wMaxPacketSize);
443
444 num_ep++;
445 break;
446 default:
447 /* Skip unknown descriptors. */
448 break;
449 }
450 }
451
452 return 1;
453}
454
455/**
456 * Copy all of a devices config descriptors, this is needed so that the USB
457 * core layer knows all about how to map the different functions on to the
458 * virtual USB bus.
459 */
460static bool copy_config(PUSBPROXYDEV pProxyDev, uint8_t idx, PVUSBDESCCONFIGEX out)
461{
462 PVUSBDESCCONFIG cfg;
463 PVUSBINTERFACE pIf;
464 PVUSBDESCINTERFACEEX ifd;
465 PVUSBDESCENDPOINTEX epd;
466 struct desc_counts cnt;
467 void *descs;
468 size_t tot_len;
469 size_t cbIface;
470 uint32_t i, x;
471 uint8_t *tmp, *end;
472
473 descs = GetStdDescSync(pProxyDev, VUSB_DT_CONFIG, idx, 0, VUSB_DT_CONFIG_MIN_LEN);
474 if ( descs == NULL ) {
475 Log(("copy_config: GetStdDescSync failed\n"));
476 return false;
477 }
478
479 cfg = (PVUSBDESCCONFIG)descs;
480 tot_len = RT_LE2H_U16(cfg->wTotalLength);
481
482 if ( !count_descriptors(&cnt, (uint8_t *)descs, tot_len) ) {
483 Log(("copy_config: count_descriptors failed\n"));
484 goto err;
485 }
486
487 if ( cfg->bNumInterfaces != cnt.num_if )
488 Log(("usb-proxy: config%u: bNumInterfaces %u != %u\n",
489 idx, cfg->bNumInterfaces, cnt.num_if));
490
491 Log(("usb-proxy: config%u: %u bytes id=%u ed=%u if=%u\n",
492 idx, tot_len, cnt.num_id, cnt.num_ed, cnt.num_if));
493
494 cbIface = cnt.num_if * sizeof(VUSBINTERFACE)
495 + cnt.num_id * sizeof(VUSBDESCINTERFACEEX)
496 + cnt.num_ed * sizeof(VUSBDESCENDPOINTEX);
497 out->paIfs = (PCVUSBINTERFACE)RTMemAllocZ(cbIface);
498 if ( out->paIfs == NULL ) {
499 free_desc(descs);
500 return false;
501 }
502
503 /* Stash a pointer to the raw config descriptor; we may need bits of it later. */
504 out->pvOriginal = descs;
505
506 pIf = (PVUSBINTERFACE)out->paIfs;
507 ifd = (PVUSBDESCINTERFACEEX)&pIf[cnt.num_if];
508 epd = (PVUSBDESCENDPOINTEX)&ifd[cnt.num_id];
509
510 out->Core.bLength = cfg->bLength;
511 out->Core.bDescriptorType = cfg->bDescriptorType;
512 out->Core.wTotalLength = 0; /* Auto Calculated */
513 out->Core.bNumInterfaces = (uint8_t)cnt.num_if;
514 out->Core.bConfigurationValue = cfg->bConfigurationValue;
515 out->Core.iConfiguration = cfg->iConfiguration;
516 out->Core.bmAttributes = cfg->bmAttributes;
517 out->Core.MaxPower = cfg->MaxPower;
518
519 tmp = (uint8_t *)out->pvOriginal;
520 end = tmp + tot_len;
521
522 /* Point to additional configuration descriptor bytes, if any. */
523 AssertCompile(sizeof(out->Core) == VUSB_DT_CONFIG_MIN_LEN);
524 if (out->Core.bLength - VUSB_DT_CONFIG_MIN_LEN > 0)
525 out->pvMore = tmp + VUSB_DT_CONFIG_MIN_LEN;
526 else
527 out->pvMore = NULL;
528
529 /* Typically there might be an interface association descriptor here. */
530 out->pvClass = collect_stray_bits(tmp, end, &out->cbClass);
531
532 for(i=0; i < 4; i++)
533 for(x=0; x < 32; x++)
534 if ( cnt.idmap[i] & (1 << x) )
535 if ( !copy_interface(pIf++, (i << 6) | x, &ifd, &epd, (uint8_t *)out->pvOriginal, tot_len) ) {
536 Log(("copy_interface(%d,,) failed\n", pIf - 1));
537 goto err;
538 }
539
540 return true;
541err:
542 Log(("usb-proxy: config%u: Corrupted configuration descriptor\n", idx));
543 free_desc(descs);
544 return false;
545}
546
547
548/**
549 * Edit out masked interface descriptors.
550 *
551 * @param pProxyDev The proxy device
552 */
553static void usbProxyDevEditOutMaskedIfs(PUSBPROXYDEV pProxyDev)
554{
555 unsigned cRemoved = 0;
556
557 PVUSBDESCCONFIGEX paCfgs = pProxyDev->paCfgDescs;
558 for (unsigned iCfg = 0; iCfg < pProxyDev->DevDesc.bNumConfigurations; iCfg++)
559 {
560 PVUSBINTERFACE paIfs = (PVUSBINTERFACE)paCfgs[iCfg].paIfs;
561 for (unsigned iIf = 0; iIf < paCfgs[iCfg].Core.bNumInterfaces; iIf++)
562 for (uint32_t iAlt = 0; iAlt < paIfs[iIf].cSettings; iAlt++)
563 if ( paIfs[iIf].paSettings[iAlt].Core.bInterfaceNumber < 32
564 && ((1 << paIfs[iIf].paSettings[iAlt].Core.bInterfaceNumber) & pProxyDev->fMaskedIfs))
565 {
566 Log(("usb-proxy: removing interface #%d (iIf=%d iAlt=%d) on config #%d (iCfg=%d)\n",
567 paIfs[iIf].paSettings[iAlt].Core.bInterfaceNumber, iIf, iAlt, paCfgs[iCfg].Core.bConfigurationValue, iCfg));
568 cRemoved++;
569
570 paCfgs[iCfg].Core.bNumInterfaces--;
571 unsigned cToCopy = paCfgs[iCfg].Core.bNumInterfaces - iIf;
572 if (cToCopy)
573 memmove(&paIfs[iIf], &paIfs[iIf + 1], sizeof(paIfs[0]) * cToCopy);
574 memset(&paIfs[iIf + cToCopy], '\0', sizeof(paIfs[0]));
575 break;
576 }
577 }
578
579 Log(("usb-proxy: edited out %d interface(s).\n", cRemoved));
580}
581
582
583/**
584 * @interface_method_impl{PDMUSBREG,pfnUsbReset}
585 *
586 * USB Device Proxy: Call OS specific code to reset the device.
587 */
588static DECLCALLBACK(int) usbProxyDevReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
589{
590 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
591
592 if (pProxyDev->fMaskedIfs)
593 {
594 Log(("usbProxyDevReset: pProxyDev=%s - ignoring reset request fMaskedIfs=%#x\n", pUsbIns->pszName, pProxyDev->fMaskedIfs));
595 return VINF_SUCCESS;
596 }
597 LogFlow(("usbProxyDevReset: pProxyDev=%s\n", pUsbIns->pszName));
598 return pProxyDev->pOps->pfnReset(pProxyDev, fResetOnLinux);
599}
600
601
602/**
603 * @interface_method_impl{PDMUSBREG,pfnUsbGetDescriptorCache}
604 */
605static DECLCALLBACK(PCPDMUSBDESCCACHE) usbProxyDevGetDescriptorCache(PPDMUSBINS pUsbIns)
606{
607 PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
608 return &pThis->DescCache;
609}
610
611
612/**
613 * @interface_method_impl{PDMUSBREG,pfnUsbSetConfiguration}
614 *
615 * USB Device Proxy: Release claimed interfaces, tell the OS+device about the config change, claim the new interfaces.
616 */
617static DECLCALLBACK(int) usbProxyDevSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
618 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
619{
620 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
621 LogFlow(("usbProxyDevSetConfiguration: pProxyDev=%s iActiveCfg=%d bConfigurationValue=%d\n",
622 pUsbIns->pszName, pProxyDev->iActiveCfg, bConfigurationValue));
623
624 /*
625 * Release the current config.
626 */
627 if (pvOldCfgDesc)
628 {
629 PCVUSBDESCCONFIGEX pOldCfgDesc = (PCVUSBDESCCONFIGEX)pvOldCfgDesc;
630 PCVUSBINTERFACESTATE pOldIfState = (PCVUSBINTERFACESTATE)pvOldIfState;
631 for (unsigned i = 0; i < pOldCfgDesc->Core.bNumInterfaces; i++)
632 if (pOldIfState[i].pCurIfDesc)
633 pProxyDev->pOps->pfnReleaseInterface(pProxyDev, pOldIfState[i].pCurIfDesc->Core.bInterfaceNumber);
634 }
635
636 /*
637 * Do the actual SET_CONFIGURE.
638 * The mess here is because most backends will already have selected a
639 * configuration and there are a bunch of devices which will freak out
640 * if we do SET_CONFIGURE twice with the same value. (PalmOne, TrekStor USB-StickGO, ..)
641 *
642 * After open and reset the backend should use the members iActiveCfg and cIgnoreSetConfigs
643 * to indicate the new configuration state and what to do on the next SET_CONFIGURATION call.
644 */
645 if ( pProxyDev->iActiveCfg != bConfigurationValue
646 || ( bConfigurationValue == 0
647 && pProxyDev->iActiveCfg != -1 /* this test doesn't make sense, we know it's 0 */
648 && pProxyDev->cIgnoreSetConfigs >= 2)
649 || !pProxyDev->cIgnoreSetConfigs)
650 {
651 pProxyDev->cIgnoreSetConfigs = 0;
652 int rc = pProxyDev->pOps->pfnSetConfig(pProxyDev, bConfigurationValue);
653 if (RT_FAILURE(rc))
654 {
655 pProxyDev->iActiveCfg = -1;
656 return rc;
657 }
658 pProxyDev->iActiveCfg = bConfigurationValue;
659 }
660 else if (pProxyDev->cIgnoreSetConfigs > 0)
661 pProxyDev->cIgnoreSetConfigs--;
662
663 /*
664 * Claim the interfaces.
665 */
666 PCVUSBDESCCONFIGEX pNewCfgDesc = (PCVUSBDESCCONFIGEX)pvNewCfgDesc;
667 Assert(pNewCfgDesc->Core.bConfigurationValue == bConfigurationValue);
668 for (unsigned iIf = 0; iIf < pNewCfgDesc->Core.bNumInterfaces; iIf++)
669 {
670 PCVUSBINTERFACE pIf = &pNewCfgDesc->paIfs[iIf];
671 for (uint32_t iAlt = 0; iAlt < pIf->cSettings; iAlt++)
672 {
673 if (pIf->paSettings[iAlt].Core.bAlternateSetting != 0)
674 continue;
675 pProxyDev->pOps->pfnClaimInterface(pProxyDev, pIf->paSettings[iAlt].Core.bInterfaceNumber);
676 /* ignore failures - the backend deals with that and does the necessary logging. */
677 break;
678 }
679 }
680
681 return VINF_SUCCESS;
682}
683
684
685/**
686 * @interface_method_impl{PDMUSBREG,pfnUsbSetInterface}
687 *
688 * USB Device Proxy: Call OS specific code to select alternate interface settings.
689 */
690static DECLCALLBACK(int) usbProxyDevSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
691{
692 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
693 LogFlow(("usbProxyDevSetInterface: pProxyDev=%s bInterfaceNumber=%d bAlternateSetting=%d\n",
694 pUsbIns->pszName, bInterfaceNumber, bAlternateSetting));
695
696 return pProxyDev->pOps->pfnSetInterface(pProxyDev, bInterfaceNumber, bAlternateSetting);
697}
698
699
700/**
701 * @interface_method_impl{PDMUSBREG,pfnUsbClearHaltedEndpoint}
702 *
703 * USB Device Proxy: Call OS specific code to clear the endpoint.
704 */
705static DECLCALLBACK(int) usbProxyDevClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
706{
707 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
708 LogFlow(("usbProxyDevClearHaltedEndpoint: pProxyDev=%s uEndpoint=%u\n",
709 pUsbIns->pszName, uEndpoint));
710
711 return pProxyDev->pOps->pfnClearHaltedEndpoint(pProxyDev, uEndpoint);
712}
713
714
715/**
716 * @interface_method_impl{PDMUSBREG,pfnUrbQueue}
717 *
718 * USB Device Proxy: Call OS specific code.
719 */
720static DECLCALLBACK(int) usbProxyDevUrbQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
721{
722 int rc = VINF_SUCCESS;
723 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
724 rc = pProxyDev->pOps->pfnUrbQueue(pProxyDev, pUrb);
725 if (RT_FAILURE(rc))
726 return pProxyDev->fDetached
727 ? VERR_VUSB_DEVICE_NOT_ATTACHED
728 : VERR_VUSB_FAILED_TO_QUEUE_URB;
729 return rc;
730}
731
732
733/**
734 * @interface_method_impl{PDMUSBREG,pfnUrbCancel}
735 *
736 * USB Device Proxy: Call OS specific code.
737 */
738static DECLCALLBACK(int) usbProxyDevUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
739{
740 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
741 return pProxyDev->pOps->pfnUrbCancel(pProxyDev, pUrb);
742}
743
744
745/**
746 * @interface_method_impl{PDMUSBREG,pfnUrbReap}
747 *
748 * USB Device Proxy: Call OS specific code.
749 */
750static DECLCALLBACK(PVUSBURB) usbProxyDevUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
751{
752 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
753 PVUSBURB pUrb = pProxyDev->pOps->pfnUrbReap(pProxyDev, cMillies);
754 if ( pUrb
755 && pUrb->enmState == VUSBURBSTATE_CANCELLED
756 && pUrb->enmStatus == VUSBSTATUS_OK)
757 pUrb->enmStatus = VUSBSTATUS_DNR;
758 return pUrb;
759}
760
761
762/**
763 * @interface_method_impl{PDMUSBREG,pfnWakeup}
764 *
765 * USB Device Proxy: Call OS specific code.
766 */
767static DECLCALLBACK(int) usbProxyDevWakeup(PPDMUSBINS pUsbIns)
768{
769 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
770
771 return pProxyDev->pOps->pfnWakeup(pProxyDev);
772}
773
774
775/** @interface_method_impl{PDMUSBREG,pfnDestruct} */
776static DECLCALLBACK(void) usbProxyDestruct(PPDMUSBINS pUsbIns)
777{
778 PDMUSB_CHECK_VERSIONS_RETURN_VOID(pUsbIns);
779 PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
780 Log(("usbProxyDestruct: destroying pProxyDev=%s\n", pUsbIns->pszName));
781
782 /* close it. */
783 if (pThis->fOpened)
784 {
785 pThis->pOps->pfnClose(pThis);
786 pThis->fOpened = false;
787 }
788
789 /* free the config descriptors. */
790 if (pThis->paCfgDescs)
791 {
792 for (unsigned i = 0; i < pThis->DevDesc.bNumConfigurations; i++)
793 {
794 RTMemFree((void *)pThis->paCfgDescs[i].paIfs);
795 RTMemFree((void *)pThis->paCfgDescs[i].pvOriginal);
796 }
797 RTMemFree(pThis->paCfgDescs);
798 pThis->paCfgDescs = NULL;
799 }
800
801 /* free dev */
802 if (&g_szDummyName[0] != pUsbIns->pszName)
803 RTStrFree(pUsbIns->pszName);
804 pUsbIns->pszName = NULL;
805
806 if (pThis->pvInstanceDataR3)
807 RTMemFree(pThis->pvInstanceDataR3);
808}
809
810
811/**
812 * Helper function used by usbProxyConstruct when
813 * reading a filter from CFG.
814 *
815 * @returns VBox status code.
816 * @param pFilter The filter.
817 * @param enmFieldIdx The filter field indext.
818 * @param pNode The CFGM node.
819 * @param pszExact The exact value name.
820 * @param pszExpr The expression value name.
821 */
822static int usbProxyQueryNum(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, PCFGMNODE pNode, const char *pszExact, const char *pszExpr)
823{
824 char szTmp[256];
825
826 /* try exact first */
827 uint16_t u16;
828 int rc = CFGMR3QueryU16(pNode, pszExact, &u16);
829 if (RT_SUCCESS(rc))
830 {
831 rc = USBFilterSetNumExact(pFilter, enmFieldIdx, u16, true);
832 AssertRCReturn(rc, rc);
833
834 /* make sure only the exact attribute is present. */
835 rc = CFGMR3QueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
836 if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
837 {
838 szTmp[0] = '\0';
839 CFGMR3GetName(pNode, szTmp, sizeof(szTmp));
840 LogRel(("usbProxyConstruct: %s: Both %s and %s are present!\n", szTmp, pszExact, pszExpr));
841 return VERR_INVALID_PARAMETER;
842 }
843 return VINF_SUCCESS;
844 }
845 if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
846 {
847 szTmp[0] = '\0';
848 CFGMR3GetName(pNode, szTmp, sizeof(szTmp));
849 LogRel(("usbProxyConstruct: %s: %s query failed, rc=%Rrc\n", szTmp, pszExact, rc));
850 return rc;
851 }
852
853 /* expression? */
854 rc = CFGMR3QueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
855 if (RT_SUCCESS(rc))
856 {
857 rc = USBFilterSetNumExpression(pFilter, enmFieldIdx, szTmp, true);
858 AssertRCReturn(rc, rc);
859 return VINF_SUCCESS;
860 }
861 if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
862 {
863 szTmp[0] = '\0';
864 CFGMR3GetName(pNode, szTmp, sizeof(szTmp));
865 LogRel(("usbProxyConstruct: %s: %s query failed, rc=%Rrc\n", szTmp, pszExpr, rc));
866 return rc;
867 }
868
869 return VINF_SUCCESS;
870}
871
872
873/** @interface_method_impl{PDMUSBREG,pfnConstruct} */
874static DECLCALLBACK(int) usbProxyConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
875{
876 PDMUSB_CHECK_VERSIONS_RETURN(pUsbIns);
877 RT_NOREF(iInstance);
878 PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
879 LogFlow(("usbProxyConstruct: pUsbIns=%p iInstance=%d\n", pUsbIns, iInstance));
880
881 /*
882 * Initialize the instance data.
883 */
884 pThis->pUsbIns = pUsbIns;
885 pThis->pUsbIns->pszName = g_szDummyName;
886 pThis->iActiveCfg = -1;
887 pThis->fMaskedIfs = 0;
888 pThis->fOpened = false;
889 pThis->fInited = false;
890
891 /*
892 * Read the basic configuration.
893 */
894 char szAddress[1024];
895 int rc = CFGMR3QueryString(pCfg, "Address", szAddress, sizeof(szAddress));
896 AssertRCReturn(rc, rc);
897
898 char szBackend[64];
899 rc = CFGMR3QueryString(pCfg, "Backend", szBackend, sizeof(szBackend));
900 AssertRCReturn(rc, rc);
901
902 void *pvBackend;
903 rc = CFGMR3QueryPtr(pCfg, "pvBackend", &pvBackend);
904 AssertRCReturn(rc, rc);
905
906 /*
907 * Select backend and open the device.
908 */
909 rc = VERR_NOT_FOUND;
910 for (unsigned i = 0; i < RT_ELEMENTS(g_aUsbProxies); i++)
911 {
912 if (!RTStrICmp(szBackend, g_aUsbProxies[i]->pszName))
913 {
914 pThis->pOps = g_aUsbProxies[i];
915 rc = VINF_SUCCESS;
916 break;
917 }
918 }
919 if (RT_FAILURE(rc))
920 return PDMUSB_SET_ERROR(pUsbIns, rc, N_("USBProxy: Failed to find backend"));
921
922 pThis->pvInstanceDataR3 = RTMemAllocZ(pThis->pOps->cbBackend);
923 if (!pThis->pvInstanceDataR3)
924 return PDMUSB_SET_ERROR(pUsbIns, VERR_NO_MEMORY, N_("USBProxy: can't allocate memory for host backend"));
925
926 rc = pThis->pOps->pfnOpen(pThis, szAddress, pvBackend);
927 if (RT_FAILURE(rc))
928 {
929 LogRel(("usbProxyConstruct: Failed to open '%s', rc=%Rrc\n", szAddress, rc));
930 return rc;
931 }
932 pThis->fOpened = true;
933
934 /*
935 * Get the device descriptor and format the device name (for logging).
936 */
937 if (!usbProxyGetDeviceDesc(pThis, &pThis->DevDesc))
938 {
939 Log(("usbProxyConstruct: usbProxyGetDeviceDesc failed\n"));
940 return VERR_READ_ERROR;
941 }
942
943 RTStrAPrintf(&pUsbIns->pszName, "%p[proxy %04x:%04x]", pThis, pThis->DevDesc.idVendor, pThis->DevDesc.idProduct); /** @todo append the user comment */
944 AssertReturn(pUsbIns->pszName, VERR_NO_MEMORY);
945
946 /*
947 * Get config descriptors.
948 */
949 size_t cbConfigs = pThis->DevDesc.bNumConfigurations * sizeof(pThis->paCfgDescs[0]);
950 pThis->paCfgDescs = (PVUSBDESCCONFIGEX)RTMemAllocZ(cbConfigs);
951 AssertReturn(pThis->paCfgDescs, VERR_NO_MEMORY);
952
953 unsigned i;
954 for (i = 0; i < pThis->DevDesc.bNumConfigurations; i++)
955 if (!copy_config(pThis, i, (PVUSBDESCCONFIGEX)&pThis->paCfgDescs[i]))
956 break;
957 if (i < pThis->DevDesc.bNumConfigurations)
958 {
959 Log(("usbProxyConstruct: copy_config failed, i=%d\n", i));
960 return VERR_READ_ERROR;
961 }
962
963 /*
964 * Pickup best matching global configuration for this device.
965 * The global configuration is organized like this:
966 *
967 * GlobalConfig/Whatever/
968 * |- idVendor = 300
969 * |- idProduct = 300
970 * - Config/
971 *
972 * The first level contains filter attributes which we stuff into a USBFILTER
973 * structure and match against the device info that's available. The highest
974 * ranked match is will be used. If nothing is found, the values will be
975 * queried from the GlobalConfig node (simplifies code and might actually
976 * be useful).
977 */
978 PCFGMNODE pCfgGlobalDev = pCfgGlobal;
979 PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgGlobal);
980 if (pCur)
981 {
982 /*
983 * Create a device filter from the device configuration
984 * descriptor ++. No strings currently.
985 */
986 USBFILTER Device;
987 USBFilterInit(&Device, USBFILTERTYPE_CAPTURE);
988 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_VENDOR_ID, pThis->DevDesc.idVendor, true); AssertRC(rc);
989 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_PRODUCT_ID, pThis->DevDesc.idProduct, true); AssertRC(rc);
990 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_REV, pThis->DevDesc.bcdDevice, true); AssertRC(rc);
991 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_CLASS, pThis->DevDesc.bDeviceClass, true); AssertRC(rc);
992 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_SUB_CLASS, pThis->DevDesc.bDeviceSubClass, true); AssertRC(rc);
993 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_PROTOCOL, pThis->DevDesc.bDeviceProtocol, true); AssertRC(rc);
994 /** @todo manufacturer, product and serial strings */
995
996 int iBestMatchRate = -1;
997 PCFGMNODE pBestMatch = NULL;
998 for (pCur = CFGMR3GetFirstChild(pCfgGlobal); pCur; pCur = CFGMR3GetNextChild(pCur))
999 {
1000 /*
1001 * Construct a filter from the attributes in the node.
1002 */
1003 USBFILTER Filter;
1004 USBFilterInit(&Filter, USBFILTERTYPE_CAPTURE);
1005
1006 /* numeric */
1007 if ( RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_VENDOR_ID, pCur, "idVendor", "idVendorExpr"))
1008 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_PRODUCT_ID, pCur, "idProduct", "idProcutExpr"))
1009 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_REV, pCur, "bcdDevice", "bcdDeviceExpr"))
1010 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_CLASS, pCur, "bDeviceClass", "bDeviceClassExpr"))
1011 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_SUB_CLASS, pCur, "bDeviceSubClass", "bDeviceSubClassExpr"))
1012 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_PROTOCOL, pCur, "bDeviceProtocol", "bDeviceProtocolExpr")))
1013 continue; /* skip it */
1014
1015 /* strings */
1016 /** @todo manufacturer, product and serial strings */
1017
1018 /* ignore unknown config values, but not without bitching. */
1019 if (!CFGMR3AreValuesValid(pCur,
1020 "idVendor\0idVendorExpr\0"
1021 "idProduct\0idProductExpr\0"
1022 "bcdDevice\0bcdDeviceExpr\0"
1023 "bDeviceClass\0bDeviceClassExpr\0"
1024 "bDeviceSubClass\0bDeviceSubClassExpr\0"
1025 "bDeviceProtocol\0bDeviceProtocolExpr\0"))
1026 LogRel(("usbProxyConstruct: Unknown value(s) in config filter (ignored)!\n"));
1027
1028 /*
1029 * Try match it and on match see if it has is a higher rate hit
1030 * than the previous match. Quit if its a 100% match.
1031 */
1032 int iRate = USBFilterMatchRated(&Filter, &Device);
1033 if (iRate > iBestMatchRate)
1034 {
1035 pBestMatch = pCur;
1036 iBestMatchRate = iRate;
1037 if (iRate >= 100)
1038 break;
1039 }
1040 }
1041 if (pBestMatch)
1042 pCfgGlobalDev = CFGMR3GetChild(pBestMatch, "Config");
1043 if (pCfgGlobalDev)
1044 pCfgGlobalDev = pCfgGlobal;
1045 }
1046
1047 /*
1048 * Query the rest of the configuration using the global as fallback.
1049 */
1050 rc = CFGMR3QueryU32(pCfg, "MaskedIfs", &pThis->fMaskedIfs);
1051 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1052 rc = CFGMR3QueryU32(pCfgGlobalDev, "MaskedIfs", &pThis->fMaskedIfs);
1053 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1054 pThis->fMaskedIfs = 0;
1055 else
1056 AssertRCReturn(rc, rc);
1057
1058 bool fForce11Device;
1059 rc = CFGMR3QueryBool(pCfg, "Force11Device", &fForce11Device);
1060 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1061 rc = CFGMR3QueryBool(pCfgGlobalDev, "Force11Device", &fForce11Device);
1062 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1063 fForce11Device = false;
1064 else
1065 AssertRCReturn(rc, rc);
1066
1067 bool fForce11PacketSize;
1068 rc = CFGMR3QueryBool(pCfg, "Force11PacketSize", &fForce11PacketSize);
1069 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1070 rc = CFGMR3QueryBool(pCfgGlobalDev, "Force11PacketSize", &fForce11PacketSize);
1071 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1072 fForce11PacketSize = false;
1073 else
1074 AssertRCReturn(rc, rc);
1075
1076 bool fEditAudioSyncEp;
1077 rc = CFGMR3QueryBool(pCfg, "EditAudioSyncEp", &fEditAudioSyncEp);
1078 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1079 rc = CFGMR3QueryBool(pCfgGlobalDev, "EditAudioSyncEp", &fEditAudioSyncEp);
1080 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1081 fEditAudioSyncEp = true; /* NB: On by default! */
1082 else
1083 AssertRCReturn(rc, rc);
1084
1085 bool fEditRemoteWake;
1086 rc = CFGMR3QueryBool(pCfg, "EditRemoteWake", &fEditRemoteWake);
1087 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1088 rc = CFGMR3QueryBool(pCfgGlobalDev, "EditRemoteWake", &fEditRemoteWake);
1089 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1090 fEditRemoteWake = true; /* NB: On by default! */
1091 else
1092 AssertRCReturn(rc, rc);
1093
1094 /*
1095 * If we're masking interfaces, edit the descriptors.
1096 */
1097 bool fEdited = pThis->fMaskedIfs != 0;
1098 if (pThis->fMaskedIfs)
1099 usbProxyDevEditOutMaskedIfs(pThis);
1100
1101 /*
1102 * Do 2.0 -> 1.1 device edits if requested to do so.
1103 */
1104 if ( fForce11PacketSize
1105 && pThis->DevDesc.bcdUSB >= 0x0200)
1106 {
1107 PVUSBDESCCONFIGEX paCfgs = pThis->paCfgDescs;
1108 for (unsigned iCfg = 0; iCfg < pThis->DevDesc.bNumConfigurations; iCfg++)
1109 {
1110 PVUSBINTERFACE paIfs = (PVUSBINTERFACE)paCfgs[iCfg].paIfs;
1111 for (unsigned iIf = 0; iIf < paCfgs[iCfg].Core.bNumInterfaces; iIf++)
1112 for (uint32_t iAlt = 0; iAlt < paIfs[iIf].cSettings; iAlt++)
1113 {
1114 /*
1115 * USB 1.1 defines the max for control, interrupt and bulk to be 64 bytes.
1116 * While isochronous has a max of 1023 bytes.
1117 */
1118 PVUSBDESCENDPOINTEX paEps = (PVUSBDESCENDPOINTEX)paIfs[iIf].paSettings[iAlt].paEndpoints;
1119 if (!paEps)
1120 continue;
1121
1122 for (unsigned iEp = 0; iEp < paIfs[iIf].paSettings[iAlt].Core.bNumEndpoints; iEp++)
1123 {
1124 const uint16_t cbMax = (paEps[iEp].Core.bmAttributes & 3) == 1 /* isoc */
1125 ? 1023
1126 : 64;
1127 if (paEps[iEp].Core.wMaxPacketSize > cbMax)
1128 {
1129 Log(("usb-proxy: pProxyDev=%s correcting wMaxPacketSize from %#x to %#x (mainly for vista)\n",
1130 pUsbIns->pszName, paEps[iEp].Core.wMaxPacketSize, cbMax));
1131 paEps[iEp].Core.wMaxPacketSize = cbMax;
1132 fEdited = true;
1133 }
1134 }
1135 }
1136 }
1137 }
1138
1139 if ( fForce11Device
1140 && pThis->DevDesc.bcdUSB == 0x0200)
1141 {
1142 /*
1143 * Discourages windows from helping you find a 2.0 port.
1144 */
1145 Log(("usb-proxy: %s correcting USB version 2.0 to 1.1 (to avoid Windows warning)\n", pUsbIns->pszName));
1146 pThis->DevDesc.bcdUSB = 0x110;
1147 fEdited = true;
1148 }
1149
1150
1151 /*
1152 * Turn asynchronous audio endpoints into synchronous ones, see @bugref{8769}
1153 */
1154 if (fEditAudioSyncEp)
1155 {
1156 PVUSBDESCCONFIGEX paCfgs = pThis->paCfgDescs;
1157 for (unsigned iCfg = 0; iCfg < pThis->DevDesc.bNumConfigurations; iCfg++)
1158 {
1159 PVUSBINTERFACE paIfs = (PVUSBINTERFACE)paCfgs[iCfg].paIfs;
1160 for (unsigned iIf = 0; iIf < paCfgs[iCfg].Core.bNumInterfaces; iIf++)
1161 for (uint32_t iAlt = 0; iAlt < paIfs[iIf].cSettings; iAlt++)
1162 {
1163 /* If not an audio class interface, skip. */
1164 if (paIfs[iIf].paSettings[iAlt].Core.bInterfaceClass != 1)
1165 continue;
1166
1167 /* If not a streaming interface, skip. */
1168 if (paIfs[iIf].paSettings[iAlt].Core.bInterfaceSubClass != 2)
1169 continue;
1170
1171 PVUSBDESCENDPOINTEX paEps = (PVUSBDESCENDPOINTEX)paIfs[iIf].paSettings[iAlt].paEndpoints;
1172 if (!paEps)
1173 continue;
1174
1175 for (unsigned iEp = 0; iEp < paIfs[iIf].paSettings[iAlt].Core.bNumEndpoints; iEp++)
1176 {
1177 /* isoch/asynch/data*/
1178 if ((paEps[iEp].Core.bmAttributes == 5) && (paEps[iEp].Core.bLength == 9))
1179 {
1180 uint8_t *pbExtra = (uint8_t *)paEps[iEp].pvMore; /* unconst*/
1181 if (pbExtra[1] == 0)
1182 continue; /* If bSynchAddress is zero, leave the descriptor alone. */
1183
1184 Log(("usb-proxy: pProxyDev=%s async audio with bmAttr=%02X [%02X, %02X] on EP %02X\n",
1185 pUsbIns->pszName, paEps[iEp].Core.bmAttributes, pbExtra[0], pbExtra[1], paEps[iEp].Core.bEndpointAddress));
1186 paEps[iEp].Core.bmAttributes = 0xD; /* isoch/synch/data*/
1187 pbExtra[1] = 0; /* Clear bSynchAddress. */
1188 fEdited = true;
1189 LogRel(("VUSB: Modified '%s' async audio endpoint 0x%02x\n", pUsbIns->pszName, paEps[iEp].Core.bEndpointAddress));
1190 }
1191 }
1192 }
1193 }
1194 }
1195
1196 /*
1197 * Disable remote wakeup capability, see @bugref{9839}. This is done on
1198 * a device/configuration level, no need to dig too deep through the descriptors.
1199 * On most backends, we can't perform a real selective suspend, and more importantly
1200 * can't receive a remote wake notification. If a guest suspends the device and waits
1201 * for a remote wake, the device is effectively dead.
1202 */
1203 if (fEditRemoteWake)
1204 {
1205 PVUSBDESCCONFIGEX paCfgs = pThis->paCfgDescs;
1206 for (unsigned iCfg = 0; iCfg < pThis->DevDesc.bNumConfigurations; iCfg++)
1207 {
1208 Log(("usb-proxy: pProxyDev=%s configuration %d with bmAttr=%02X\n",
1209 pUsbIns->pszName, paCfgs[iCfg].Core.bmAttributes, iCfg));
1210 if (paCfgs[iCfg].Core.bmAttributes & RT_BIT(5))
1211 {
1212 paCfgs[iCfg].Core.bmAttributes = paCfgs[iCfg].Core.bmAttributes & ~RT_BIT(5); /* Remote wakeup. */
1213 fEdited = true;
1214 LogRel(("VUSB: Disabled '%s' remote wakeup for configuration %d\n", pUsbIns->pszName, iCfg));
1215 }
1216 }
1217 }
1218
1219 /*
1220 * Init the PDM/VUSB descriptor cache.
1221 */
1222 pThis->DescCache.pDevice = &pThis->DevDesc;
1223 pThis->DescCache.paConfigs = pThis->paCfgDescs;
1224 pThis->DescCache.paLanguages = NULL;
1225 pThis->DescCache.cLanguages = 0;
1226 pThis->DescCache.fUseCachedDescriptors = fEdited;
1227 pThis->DescCache.fUseCachedStringsDescriptors = false;
1228
1229 /*
1230 * Call the backend if it wishes to do some more initializing
1231 * after we've read the config and descriptors.
1232 */
1233 if (pThis->pOps->pfnInit)
1234 {
1235 rc = pThis->pOps->pfnInit(pThis);
1236 if (RT_FAILURE(rc))
1237 return rc;
1238 }
1239 pThis->fInited = true;
1240
1241 /*
1242 * We're good!
1243 */
1244 Log(("usb-proxy: created pProxyDev=%s address '%s' fMaskedIfs=%#x (rc=%Rrc)\n",
1245 pUsbIns->pszName, szAddress, pThis->fMaskedIfs, rc));
1246 return VINF_SUCCESS;
1247}
1248
1249
1250/**
1251 * The USB proxy device registration record.
1252 */
1253const PDMUSBREG g_UsbDevProxy =
1254{
1255 /* u32Version */
1256 PDM_USBREG_VERSION,
1257 /* szName */
1258 "USBProxy",
1259 /* pszDescription */
1260 "USB Proxy Device.",
1261 /* fFlags */
1262 0,
1263 /* cMaxInstances */
1264 ~0U,
1265 /* cbInstance */
1266 sizeof(USBPROXYDEV),
1267 /* pfnConstruct */
1268 usbProxyConstruct,
1269 /* pfnDestruct */
1270 usbProxyDestruct,
1271 /* pfnVMInitComplete */
1272 NULL,
1273 /* pfnVMPowerOn */
1274 NULL,
1275 /* pfnVMReset */
1276 NULL,
1277 /* pfnVMSuspend */
1278 NULL,
1279 /* pfnVMResume */
1280 NULL,
1281 /* pfnVMPowerOff */
1282 NULL,
1283 /* pfnHotPlugged */
1284 NULL,
1285 /* pfnHotUnplugged */
1286 NULL,
1287 /* pfnDriverAttach */
1288 NULL,
1289 /* pfnDriverDetach */
1290 NULL,
1291 /* pfnQueryInterface */
1292 NULL,
1293 /* pfnUsbReset */
1294 usbProxyDevReset,
1295 /* pfnUsbGetDescriptorCache */
1296 usbProxyDevGetDescriptorCache,
1297 /* pfnUsbSetConfiguration */
1298 usbProxyDevSetConfiguration,
1299 /* pfnUsbSetInterface */
1300 usbProxyDevSetInterface,
1301 /* pfnUsbClearHaltedEndpoint */
1302 usbProxyDevClearHaltedEndpoint,
1303 /* pfnUrbNew */
1304 NULL,
1305 /* pfnUrbQueue */
1306 usbProxyDevUrbQueue,
1307 /* pfnUrbCancel */
1308 usbProxyDevUrbCancel,
1309 /* pfnUrbReap */
1310 usbProxyDevUrbReap,
1311 /* pfnWakeup */
1312 usbProxyDevWakeup,
1313
1314 /* u32TheEnd */
1315 PDM_USBREG_VERSION
1316};
1317
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