VirtualBox

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

Last change on this file since 89153 was 87627, checked in by vboxsync, 4 years ago

VUSB: Minor logging improvements.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.7 KB
Line 
1/* $Id: USBProxyDevice.cpp 87627 2021-02-05 16:49:57Z 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\n", pProxyDev->pUsbIns->pszName));
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 Urb.u32Magic = VUSBURB_MAGIC;
71 Urb.enmState = VUSBURBSTATE_IN_FLIGHT;
72 Urb.pszDesc = (char*)"URB sync";
73 Urb.pHci = NULL;
74 Urb.paTds = NULL;
75 Urb.Dev.pvPrivate = NULL;
76 Urb.Dev.pNext = NULL;
77 Urb.DstAddress = 0;
78 Urb.EndPt = 0;
79 Urb.enmType = VUSBXFERTYPE_MSG;
80 Urb.enmDir = VUSBDIRECTION_IN;
81 Urb.fShortNotOk = false;
82 Urb.enmStatus = VUSBSTATUS_INVALID;
83 Urb.pVUsb = NULL;
84 cbHint = RT_MIN(cbHint, sizeof(Urb.abData) - sizeof(VUSBSETUP));
85 Urb.cbData = cbHint + sizeof(VUSBSETUP);
86
87 PVUSBSETUP pSetup = (PVUSBSETUP)Urb.abData;
88 pSetup->bmRequestType = VUSB_DIR_TO_HOST | VUSB_REQ_STANDARD | VUSB_TO_DEVICE;
89 pSetup->bRequest = VUSB_REQ_GET_DESCRIPTOR;
90 pSetup->wValue = (iDescType << 8) | iIdx;
91 pSetup->wIndex = LangId;
92 pSetup->wLength = cbHint;
93
94 uint8_t *pbDesc = (uint8_t *)(pSetup + 1);
95 uint32_t cbDesc = 0;
96 PVUSBURB pUrbReaped = NULL;
97
98 rc = pProxyDev->pOps->pfnUrbQueue(pProxyDev, &Urb);
99 if (RT_FAILURE(rc))
100 {
101 Log(("GetStdDescSync: pfnUrbQueue failed, rc=%d\n", rc));
102 goto err;
103 }
104
105 /* Don't wait forever, it's just a simple request that should
106 return immediately. Since we're executing in the EMT thread
107 it's important not to get stuck here. (Some of the builtin
108 iMac devices may refuse to respond for instance.) */
109 pUrbReaped = pProxyDev->pOps->pfnUrbReap(pProxyDev, 5000 /* ms */);
110 if (!pUrbReaped)
111 {
112 Log(("GetStdDescSync: pfnUrbReap returned NULL, cancel and re-reap\n"));
113 rc = pProxyDev->pOps->pfnUrbCancel(pProxyDev, &Urb);
114 AssertRC(rc);
115 /** @todo This breaks the comment above... */
116 pUrbReaped = pProxyDev->pOps->pfnUrbReap(pProxyDev, RT_INDEFINITE_WAIT);
117 }
118 if (pUrbReaped != &Urb)
119 {
120 Log(("GetStdDescSync: pfnUrbReap failed, pUrbReaped=%p\n", pUrbReaped));
121 goto err;
122 }
123
124 if (Urb.enmStatus != VUSBSTATUS_OK)
125 {
126 Log(("GetStdDescSync: Urb.enmStatus=%d\n", Urb.enmStatus));
127 goto err;
128 }
129
130 /*
131 * Check the length, config descriptors have total_length field
132 */
133 if (iDescType == VUSB_DT_CONFIG)
134 {
135 if (Urb.cbData < sizeof(VUSBSETUP) + 4)
136 {
137 Log(("GetStdDescSync: Urb.cbData=%#x (min 4)\n", Urb.cbData));
138 goto err;
139 }
140 cbDesc = RT_LE2H_U16(((uint16_t *)pbDesc)[1]);
141 }
142 else
143 {
144 if (Urb.cbData < sizeof(VUSBSETUP) + 1)
145 {
146 Log(("GetStdDescSync: Urb.cbData=%#x (min 1)\n", Urb.cbData));
147 goto err;
148 }
149 cbDesc = ((uint8_t *)pbDesc)[0];
150 }
151
152 Log(("GetStdDescSync: got Urb.cbData=%u, cbDesc=%u cbHint=%u\n", Urb.cbData, cbDesc, cbHint));
153
154 if ( Urb.cbData == cbHint + sizeof(VUSBSETUP)
155 && cbDesc > Urb.cbData - sizeof(VUSBSETUP))
156 {
157 cbHint = cbDesc;
158 Log(("GetStdDescSync: Part descriptor, Urb.cbData=%u, cbDesc=%u cbHint=%u\n", Urb.cbData, cbDesc, cbHint));
159
160 if (cbHint > sizeof(Urb.abData))
161 Log(("GetStdDescSync: cbHint=%u, Urb.abData=%u\n", cbHint, sizeof(Urb.abData)));
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 paCfgs[iCfg].Core.bmAttributes = paCfgs[iCfg].Core.bmAttributes & ~RT_BIT(5); /* Remote wakeup. */
1211 fEdited = true;
1212 LogRel(("VUSB: Disabled '%s' remote wakeup for configuration %d\n", pUsbIns->pszName, iCfg));
1213 }
1214 }
1215
1216 /*
1217 * Init the PDM/VUSB descriptor cache.
1218 */
1219 pThis->DescCache.pDevice = &pThis->DevDesc;
1220 pThis->DescCache.paConfigs = pThis->paCfgDescs;
1221 pThis->DescCache.paLanguages = NULL;
1222 pThis->DescCache.cLanguages = 0;
1223 pThis->DescCache.fUseCachedDescriptors = fEdited;
1224 pThis->DescCache.fUseCachedStringsDescriptors = false;
1225
1226 /*
1227 * Call the backend if it wishes to do some more initializing
1228 * after we've read the config and descriptors.
1229 */
1230 if (pThis->pOps->pfnInit)
1231 {
1232 rc = pThis->pOps->pfnInit(pThis);
1233 if (RT_FAILURE(rc))
1234 return rc;
1235 }
1236 pThis->fInited = true;
1237
1238 /*
1239 * We're good!
1240 */
1241 Log(("usb-proxy: created pProxyDev=%s address '%s' fMaskedIfs=%#x (rc=%Rrc)\n",
1242 pUsbIns->pszName, szAddress, pThis->fMaskedIfs, rc));
1243 return VINF_SUCCESS;
1244}
1245
1246
1247/**
1248 * The USB proxy device registration record.
1249 */
1250const PDMUSBREG g_UsbDevProxy =
1251{
1252 /* u32Version */
1253 PDM_USBREG_VERSION,
1254 /* szName */
1255 "USBProxy",
1256 /* pszDescription */
1257 "USB Proxy Device.",
1258 /* fFlags */
1259 0,
1260 /* cMaxInstances */
1261 ~0U,
1262 /* cbInstance */
1263 sizeof(USBPROXYDEV),
1264 /* pfnConstruct */
1265 usbProxyConstruct,
1266 /* pfnDestruct */
1267 usbProxyDestruct,
1268 /* pfnVMInitComplete */
1269 NULL,
1270 /* pfnVMPowerOn */
1271 NULL,
1272 /* pfnVMReset */
1273 NULL,
1274 /* pfnVMSuspend */
1275 NULL,
1276 /* pfnVMResume */
1277 NULL,
1278 /* pfnVMPowerOff */
1279 NULL,
1280 /* pfnHotPlugged */
1281 NULL,
1282 /* pfnHotUnplugged */
1283 NULL,
1284 /* pfnDriverAttach */
1285 NULL,
1286 /* pfnDriverDetach */
1287 NULL,
1288 /* pfnQueryInterface */
1289 NULL,
1290 /* pfnUsbReset */
1291 usbProxyDevReset,
1292 /* pfnUsbGetDescriptorCache */
1293 usbProxyDevGetDescriptorCache,
1294 /* pfnUsbSetConfiguration */
1295 usbProxyDevSetConfiguration,
1296 /* pfnUsbSetInterface */
1297 usbProxyDevSetInterface,
1298 /* pfnUsbClearHaltedEndpoint */
1299 usbProxyDevClearHaltedEndpoint,
1300 /* pfnUrbNew */
1301 NULL,
1302 /* pfnUrbQueue */
1303 usbProxyDevUrbQueue,
1304 /* pfnUrbCancel */
1305 usbProxyDevUrbCancel,
1306 /* pfnUrbReap */
1307 usbProxyDevUrbReap,
1308 /* pfnWakeup */
1309 usbProxyDevWakeup,
1310
1311 /* u32TheEnd */
1312 PDM_USBREG_VERSION
1313};
1314
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