VirtualBox

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

Last change on this file since 94125 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.3 KB
Line 
1/* $Id: USBProxyDevice.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * USBProxy - USB device proxy.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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 pHlp The USB helper callback table.
819 * @param pNode The CFGM node.
820 * @param pszExact The exact value name.
821 * @param pszExpr The expression value name.
822 */
823static int usbProxyQueryNum(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx,
824 PCPDMUSBHLP pHlp, PCFGMNODE pNode,
825 const char *pszExact, const char *pszExpr)
826{
827 char szTmp[256];
828
829 /* try exact first */
830 uint16_t u16;
831 int rc = pHlp->pfnCFGMQueryU16(pNode, pszExact, &u16);
832 if (RT_SUCCESS(rc))
833 {
834 rc = USBFilterSetNumExact(pFilter, enmFieldIdx, u16, true);
835 AssertRCReturn(rc, rc);
836
837 /* make sure only the exact attribute is present. */
838 rc = pHlp->pfnCFGMQueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
839 if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
840 {
841 szTmp[0] = '\0';
842 pHlp->pfnCFGMGetName(pNode, szTmp, sizeof(szTmp));
843 LogRel(("usbProxyConstruct: %s: Both %s and %s are present!\n", szTmp, pszExact, pszExpr));
844 return VERR_INVALID_PARAMETER;
845 }
846 return VINF_SUCCESS;
847 }
848 if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
849 {
850 szTmp[0] = '\0';
851 pHlp->pfnCFGMGetName(pNode, szTmp, sizeof(szTmp));
852 LogRel(("usbProxyConstruct: %s: %s query failed, rc=%Rrc\n", szTmp, pszExact, rc));
853 return rc;
854 }
855
856 /* expression? */
857 rc = pHlp->pfnCFGMQueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
858 if (RT_SUCCESS(rc))
859 {
860 rc = USBFilterSetNumExpression(pFilter, enmFieldIdx, szTmp, true);
861 AssertRCReturn(rc, rc);
862 return VINF_SUCCESS;
863 }
864 if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
865 {
866 szTmp[0] = '\0';
867 pHlp->pfnCFGMGetName(pNode, szTmp, sizeof(szTmp));
868 LogRel(("usbProxyConstruct: %s: %s query failed, rc=%Rrc\n", szTmp, pszExpr, rc));
869 return rc;
870 }
871
872 return VINF_SUCCESS;
873}
874
875
876/** @interface_method_impl{PDMUSBREG,pfnConstruct} */
877static DECLCALLBACK(int) usbProxyConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
878{
879 PDMUSB_CHECK_VERSIONS_RETURN(pUsbIns);
880 RT_NOREF(iInstance);
881 PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
882 PCPDMUSBHLP pHlp = pUsbIns->pHlpR3;
883
884 LogFlow(("usbProxyConstruct: pUsbIns=%p iInstance=%d\n", pUsbIns, iInstance));
885
886 /*
887 * Initialize the instance data.
888 */
889 pThis->pUsbIns = pUsbIns;
890 pThis->pUsbIns->pszName = g_szDummyName;
891 pThis->iActiveCfg = -1;
892 pThis->fMaskedIfs = 0;
893 pThis->fOpened = false;
894 pThis->fInited = false;
895
896 /*
897 * Read the basic configuration.
898 */
899 char szAddress[1024];
900 int rc = pHlp->pfnCFGMQueryString(pCfg, "Address", szAddress, sizeof(szAddress));
901 AssertRCReturn(rc, rc);
902
903 char szBackend[64];
904 rc = pHlp->pfnCFGMQueryString(pCfg, "Backend", szBackend, sizeof(szBackend));
905 AssertRCReturn(rc, rc);
906
907 void *pvBackend;
908 rc = pHlp->pfnCFGMQueryPtr(pCfg, "pvBackend", &pvBackend);
909 AssertRCReturn(rc, rc);
910
911 /*
912 * Select backend and open the device.
913 */
914 rc = VERR_NOT_FOUND;
915 for (unsigned i = 0; i < RT_ELEMENTS(g_aUsbProxies); i++)
916 {
917 if (!RTStrICmp(szBackend, g_aUsbProxies[i]->pszName))
918 {
919 pThis->pOps = g_aUsbProxies[i];
920 rc = VINF_SUCCESS;
921 break;
922 }
923 }
924 if (RT_FAILURE(rc))
925 return PDMUSB_SET_ERROR(pUsbIns, rc, N_("USBProxy: Failed to find backend"));
926
927 pThis->pvInstanceDataR3 = RTMemAllocZ(pThis->pOps->cbBackend);
928 if (!pThis->pvInstanceDataR3)
929 return PDMUSB_SET_ERROR(pUsbIns, VERR_NO_MEMORY, N_("USBProxy: can't allocate memory for host backend"));
930
931 rc = pThis->pOps->pfnOpen(pThis, szAddress, pvBackend);
932 if (RT_FAILURE(rc))
933 {
934 LogRel(("usbProxyConstruct: Failed to open '%s', rc=%Rrc\n", szAddress, rc));
935 return rc;
936 }
937 pThis->fOpened = true;
938
939 /*
940 * Get the device descriptor and format the device name (for logging).
941 */
942 if (!usbProxyGetDeviceDesc(pThis, &pThis->DevDesc))
943 {
944 Log(("usbProxyConstruct: usbProxyGetDeviceDesc failed\n"));
945 return VERR_READ_ERROR;
946 }
947
948 RTStrAPrintf(&pUsbIns->pszName, "%p[proxy %04x:%04x]", pThis, pThis->DevDesc.idVendor, pThis->DevDesc.idProduct); /** @todo append the user comment */
949 AssertReturn(pUsbIns->pszName, VERR_NO_MEMORY);
950
951 /*
952 * Get config descriptors.
953 */
954 size_t cbConfigs = pThis->DevDesc.bNumConfigurations * sizeof(pThis->paCfgDescs[0]);
955 pThis->paCfgDescs = (PVUSBDESCCONFIGEX)RTMemAllocZ(cbConfigs);
956 AssertReturn(pThis->paCfgDescs, VERR_NO_MEMORY);
957
958 unsigned i;
959 for (i = 0; i < pThis->DevDesc.bNumConfigurations; i++)
960 if (!copy_config(pThis, i, (PVUSBDESCCONFIGEX)&pThis->paCfgDescs[i]))
961 break;
962 if (i < pThis->DevDesc.bNumConfigurations)
963 {
964 Log(("usbProxyConstruct: copy_config failed, i=%d\n", i));
965 return VERR_READ_ERROR;
966 }
967
968 /*
969 * Pickup best matching global configuration for this device.
970 * The global configuration is organized like this:
971 *
972 * GlobalConfig/Whatever/
973 * |- idVendor = 300
974 * |- idProduct = 300
975 * - Config/
976 *
977 * The first level contains filter attributes which we stuff into a USBFILTER
978 * structure and match against the device info that's available. The highest
979 * ranked match is will be used. If nothing is found, the values will be
980 * queried from the GlobalConfig node (simplifies code and might actually
981 * be useful).
982 */
983 PCFGMNODE pCfgGlobalDev = pCfgGlobal;
984 PCFGMNODE pCur = pHlp->pfnCFGMGetFirstChild(pCfgGlobal);
985 if (pCur)
986 {
987 /*
988 * Create a device filter from the device configuration
989 * descriptor ++. No strings currently.
990 */
991 USBFILTER Device;
992 USBFilterInit(&Device, USBFILTERTYPE_CAPTURE);
993 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_VENDOR_ID, pThis->DevDesc.idVendor, true); AssertRC(rc);
994 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_PRODUCT_ID, pThis->DevDesc.idProduct, true); AssertRC(rc);
995 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_REV, pThis->DevDesc.bcdDevice, true); AssertRC(rc);
996 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_CLASS, pThis->DevDesc.bDeviceClass, true); AssertRC(rc);
997 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_SUB_CLASS, pThis->DevDesc.bDeviceSubClass, true); AssertRC(rc);
998 rc = USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_PROTOCOL, pThis->DevDesc.bDeviceProtocol, true); AssertRC(rc);
999 /** @todo manufacturer, product and serial strings */
1000
1001 int iBestMatchRate = -1;
1002 PCFGMNODE pBestMatch = NULL;
1003 for (pCur = pHlp->pfnCFGMGetFirstChild(pCfgGlobal); pCur; pCur = pHlp->pfnCFGMGetNextChild(pCur))
1004 {
1005 /*
1006 * Construct a filter from the attributes in the node.
1007 */
1008 USBFILTER Filter;
1009 USBFilterInit(&Filter, USBFILTERTYPE_CAPTURE);
1010
1011 /* numeric */
1012 if ( RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_VENDOR_ID, pHlp, pCur, "idVendor", "idVendorExpr"))
1013 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_PRODUCT_ID, pHlp, pCur, "idProduct", "idProcutExpr"))
1014 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_REV, pHlp, pCur, "bcdDevice", "bcdDeviceExpr"))
1015 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_CLASS, pHlp, pCur, "bDeviceClass", "bDeviceClassExpr"))
1016 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_SUB_CLASS, pHlp, pCur, "bDeviceSubClass", "bDeviceSubClassExpr"))
1017 || RT_FAILURE(usbProxyQueryNum(&Filter, USBFILTERIDX_DEVICE_PROTOCOL, pHlp, pCur, "bDeviceProtocol", "bDeviceProtocolExpr")))
1018 continue; /* skip it */
1019
1020 /* strings */
1021 /** @todo manufacturer, product and serial strings */
1022
1023 /* ignore unknown config values, but not without bitching. */
1024 if (!pHlp->pfnCFGMAreValuesValid(pCur,
1025 "idVendor\0idVendorExpr\0"
1026 "idProduct\0idProductExpr\0"
1027 "bcdDevice\0bcdDeviceExpr\0"
1028 "bDeviceClass\0bDeviceClassExpr\0"
1029 "bDeviceSubClass\0bDeviceSubClassExpr\0"
1030 "bDeviceProtocol\0bDeviceProtocolExpr\0"))
1031 LogRel(("usbProxyConstruct: Unknown value(s) in config filter (ignored)!\n"));
1032
1033 /*
1034 * Try match it and on match see if it has is a higher rate hit
1035 * than the previous match. Quit if its a 100% match.
1036 */
1037 int iRate = USBFilterMatchRated(&Filter, &Device);
1038 if (iRate > iBestMatchRate)
1039 {
1040 pBestMatch = pCur;
1041 iBestMatchRate = iRate;
1042 if (iRate >= 100)
1043 break;
1044 }
1045 }
1046 if (pBestMatch)
1047 pCfgGlobalDev = pHlp->pfnCFGMGetChild(pBestMatch, "Config");
1048 if (pCfgGlobalDev)
1049 pCfgGlobalDev = pCfgGlobal;
1050 }
1051
1052 /*
1053 * Query the rest of the configuration using the global as fallback.
1054 */
1055 rc = pHlp->pfnCFGMQueryU32(pCfg, "MaskedIfs", &pThis->fMaskedIfs);
1056 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1057 rc = pHlp->pfnCFGMQueryU32(pCfgGlobalDev, "MaskedIfs", &pThis->fMaskedIfs);
1058 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1059 pThis->fMaskedIfs = 0;
1060 else
1061 AssertRCReturn(rc, rc);
1062
1063 bool fForce11Device;
1064 rc = pHlp->pfnCFGMQueryBool(pCfg, "Force11Device", &fForce11Device);
1065 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1066 rc = pHlp->pfnCFGMQueryBool(pCfgGlobalDev, "Force11Device", &fForce11Device);
1067 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1068 fForce11Device = false;
1069 else
1070 AssertRCReturn(rc, rc);
1071
1072 bool fForce11PacketSize;
1073 rc = pHlp->pfnCFGMQueryBool(pCfg, "Force11PacketSize", &fForce11PacketSize);
1074 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1075 rc = pHlp->pfnCFGMQueryBool(pCfgGlobalDev, "Force11PacketSize", &fForce11PacketSize);
1076 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1077 fForce11PacketSize = false;
1078 else
1079 AssertRCReturn(rc, rc);
1080
1081 bool fEditAudioSyncEp;
1082 rc = pHlp->pfnCFGMQueryBool(pCfg, "EditAudioSyncEp", &fEditAudioSyncEp);
1083 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1084 rc = pHlp->pfnCFGMQueryBool(pCfgGlobalDev, "EditAudioSyncEp", &fEditAudioSyncEp);
1085 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1086 fEditAudioSyncEp = true; /* NB: On by default! */
1087 else
1088 AssertRCReturn(rc, rc);
1089
1090 bool fEditRemoteWake;
1091 rc = pHlp->pfnCFGMQueryBool(pCfg, "EditRemoteWake", &fEditRemoteWake);
1092 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1093 rc = pHlp->pfnCFGMQueryBool(pCfgGlobalDev, "EditRemoteWake", &fEditRemoteWake);
1094 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1095 fEditRemoteWake = true; /* NB: On by default! */
1096 else
1097 AssertRCReturn(rc, rc);
1098
1099 /*
1100 * If we're masking interfaces, edit the descriptors.
1101 */
1102 bool fEdited = pThis->fMaskedIfs != 0;
1103 if (pThis->fMaskedIfs)
1104 usbProxyDevEditOutMaskedIfs(pThis);
1105
1106 /*
1107 * Do 2.0 -> 1.1 device edits if requested to do so.
1108 */
1109 if ( fForce11PacketSize
1110 && pThis->DevDesc.bcdUSB >= 0x0200)
1111 {
1112 PVUSBDESCCONFIGEX paCfgs = pThis->paCfgDescs;
1113 for (unsigned iCfg = 0; iCfg < pThis->DevDesc.bNumConfigurations; iCfg++)
1114 {
1115 PVUSBINTERFACE paIfs = (PVUSBINTERFACE)paCfgs[iCfg].paIfs;
1116 for (unsigned iIf = 0; iIf < paCfgs[iCfg].Core.bNumInterfaces; iIf++)
1117 for (uint32_t iAlt = 0; iAlt < paIfs[iIf].cSettings; iAlt++)
1118 {
1119 /*
1120 * USB 1.1 defines the max for control, interrupt and bulk to be 64 bytes.
1121 * While isochronous has a max of 1023 bytes.
1122 */
1123 PVUSBDESCENDPOINTEX paEps = (PVUSBDESCENDPOINTEX)paIfs[iIf].paSettings[iAlt].paEndpoints;
1124 if (!paEps)
1125 continue;
1126
1127 for (unsigned iEp = 0; iEp < paIfs[iIf].paSettings[iAlt].Core.bNumEndpoints; iEp++)
1128 {
1129 const uint16_t cbMax = (paEps[iEp].Core.bmAttributes & 3) == 1 /* isoc */
1130 ? 1023
1131 : 64;
1132 if (paEps[iEp].Core.wMaxPacketSize > cbMax)
1133 {
1134 Log(("usb-proxy: pProxyDev=%s correcting wMaxPacketSize from %#x to %#x (mainly for vista)\n",
1135 pUsbIns->pszName, paEps[iEp].Core.wMaxPacketSize, cbMax));
1136 paEps[iEp].Core.wMaxPacketSize = cbMax;
1137 fEdited = true;
1138 }
1139 }
1140 }
1141 }
1142 }
1143
1144 if ( fForce11Device
1145 && pThis->DevDesc.bcdUSB == 0x0200)
1146 {
1147 /*
1148 * Discourages windows from helping you find a 2.0 port.
1149 */
1150 Log(("usb-proxy: %s correcting USB version 2.0 to 1.1 (to avoid Windows warning)\n", pUsbIns->pszName));
1151 pThis->DevDesc.bcdUSB = 0x110;
1152 fEdited = true;
1153 }
1154
1155
1156 /*
1157 * Turn asynchronous audio endpoints into synchronous ones, see @bugref{8769}
1158 */
1159 if (fEditAudioSyncEp)
1160 {
1161 PVUSBDESCCONFIGEX paCfgs = pThis->paCfgDescs;
1162 for (unsigned iCfg = 0; iCfg < pThis->DevDesc.bNumConfigurations; iCfg++)
1163 {
1164 PVUSBINTERFACE paIfs = (PVUSBINTERFACE)paCfgs[iCfg].paIfs;
1165 for (unsigned iIf = 0; iIf < paCfgs[iCfg].Core.bNumInterfaces; iIf++)
1166 for (uint32_t iAlt = 0; iAlt < paIfs[iIf].cSettings; iAlt++)
1167 {
1168 /* If not an audio class interface, skip. */
1169 if (paIfs[iIf].paSettings[iAlt].Core.bInterfaceClass != 1)
1170 continue;
1171
1172 /* If not a streaming interface, skip. */
1173 if (paIfs[iIf].paSettings[iAlt].Core.bInterfaceSubClass != 2)
1174 continue;
1175
1176 PVUSBDESCENDPOINTEX paEps = (PVUSBDESCENDPOINTEX)paIfs[iIf].paSettings[iAlt].paEndpoints;
1177 if (!paEps)
1178 continue;
1179
1180 for (unsigned iEp = 0; iEp < paIfs[iIf].paSettings[iAlt].Core.bNumEndpoints; iEp++)
1181 {
1182 /* isoch/asynch/data*/
1183 if ((paEps[iEp].Core.bmAttributes == 5) && (paEps[iEp].Core.bLength == 9))
1184 {
1185 uint8_t *pbExtra = (uint8_t *)paEps[iEp].pvMore; /* unconst*/
1186 if (pbExtra[1] == 0)
1187 continue; /* If bSynchAddress is zero, leave the descriptor alone. */
1188
1189 Log(("usb-proxy: pProxyDev=%s async audio with bmAttr=%02X [%02X, %02X] on EP %02X\n",
1190 pUsbIns->pszName, paEps[iEp].Core.bmAttributes, pbExtra[0], pbExtra[1], paEps[iEp].Core.bEndpointAddress));
1191 paEps[iEp].Core.bmAttributes = 0xD; /* isoch/synch/data*/
1192 pbExtra[1] = 0; /* Clear bSynchAddress. */
1193 fEdited = true;
1194 LogRel(("VUSB: Modified '%s' async audio endpoint 0x%02x\n", pUsbIns->pszName, paEps[iEp].Core.bEndpointAddress));
1195 }
1196 }
1197 }
1198 }
1199 }
1200
1201 /*
1202 * Disable remote wakeup capability, see @bugref{9839}. This is done on
1203 * a device/configuration level, no need to dig too deep through the descriptors.
1204 * On most backends, we can't perform a real selective suspend, and more importantly
1205 * can't receive a remote wake notification. If a guest suspends the device and waits
1206 * for a remote wake, the device is effectively dead.
1207 */
1208 if (fEditRemoteWake)
1209 {
1210 PVUSBDESCCONFIGEX paCfgs = pThis->paCfgDescs;
1211 for (unsigned iCfg = 0; iCfg < pThis->DevDesc.bNumConfigurations; iCfg++)
1212 {
1213 Log(("usb-proxy: pProxyDev=%s configuration %d with bmAttr=%02X\n",
1214 pUsbIns->pszName, paCfgs[iCfg].Core.bmAttributes, iCfg));
1215 if (paCfgs[iCfg].Core.bmAttributes & RT_BIT(5))
1216 {
1217 paCfgs[iCfg].Core.bmAttributes = paCfgs[iCfg].Core.bmAttributes & ~RT_BIT(5); /* Remote wakeup. */
1218 fEdited = true;
1219 LogRel(("VUSB: Disabled '%s' remote wakeup for configuration %d\n", pUsbIns->pszName, iCfg));
1220 }
1221 }
1222 }
1223
1224 /*
1225 * Init the PDM/VUSB descriptor cache.
1226 */
1227 pThis->DescCache.pDevice = &pThis->DevDesc;
1228 pThis->DescCache.paConfigs = pThis->paCfgDescs;
1229 pThis->DescCache.paLanguages = NULL;
1230 pThis->DescCache.cLanguages = 0;
1231 pThis->DescCache.fUseCachedDescriptors = fEdited;
1232 pThis->DescCache.fUseCachedStringsDescriptors = false;
1233
1234 /*
1235 * Call the backend if it wishes to do some more initializing
1236 * after we've read the config and descriptors.
1237 */
1238 if (pThis->pOps->pfnInit)
1239 {
1240 rc = pThis->pOps->pfnInit(pThis);
1241 if (RT_FAILURE(rc))
1242 return rc;
1243 }
1244 pThis->fInited = true;
1245
1246 /*
1247 * We're good!
1248 */
1249 Log(("usb-proxy: created pProxyDev=%s address '%s' fMaskedIfs=%#x (rc=%Rrc)\n",
1250 pUsbIns->pszName, szAddress, pThis->fMaskedIfs, rc));
1251 return VINF_SUCCESS;
1252}
1253
1254
1255/**
1256 * The USB proxy device registration record.
1257 */
1258const PDMUSBREG g_UsbDevProxy =
1259{
1260 /* u32Version */
1261 PDM_USBREG_VERSION,
1262 /* szName */
1263 "USBProxy",
1264 /* pszDescription */
1265 "USB Proxy Device.",
1266 /* fFlags */
1267 0,
1268 /* cMaxInstances */
1269 ~0U,
1270 /* cbInstance */
1271 sizeof(USBPROXYDEV),
1272 /* pfnConstruct */
1273 usbProxyConstruct,
1274 /* pfnDestruct */
1275 usbProxyDestruct,
1276 /* pfnVMInitComplete */
1277 NULL,
1278 /* pfnVMPowerOn */
1279 NULL,
1280 /* pfnVMReset */
1281 NULL,
1282 /* pfnVMSuspend */
1283 NULL,
1284 /* pfnVMResume */
1285 NULL,
1286 /* pfnVMPowerOff */
1287 NULL,
1288 /* pfnHotPlugged */
1289 NULL,
1290 /* pfnHotUnplugged */
1291 NULL,
1292 /* pfnDriverAttach */
1293 NULL,
1294 /* pfnDriverDetach */
1295 NULL,
1296 /* pfnQueryInterface */
1297 NULL,
1298 /* pfnUsbReset */
1299 usbProxyDevReset,
1300 /* pfnUsbGetDescriptorCache */
1301 usbProxyDevGetDescriptorCache,
1302 /* pfnUsbSetConfiguration */
1303 usbProxyDevSetConfiguration,
1304 /* pfnUsbSetInterface */
1305 usbProxyDevSetInterface,
1306 /* pfnUsbClearHaltedEndpoint */
1307 usbProxyDevClearHaltedEndpoint,
1308 /* pfnUrbNew */
1309 NULL,
1310 /* pfnUrbQueue */
1311 usbProxyDevUrbQueue,
1312 /* pfnUrbCancel */
1313 usbProxyDevUrbCancel,
1314 /* pfnUrbReap */
1315 usbProxyDevUrbReap,
1316 /* pfnWakeup */
1317 usbProxyDevWakeup,
1318
1319 /* u32TheEnd */
1320 PDM_USBREG_VERSION
1321};
1322
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