VirtualBox

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

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

Main,VMM/PDMUsb,Devices/USB,VRDP: Drop passing pointers through CFGM in favor of using VMM2USERMETHODS::pfnQueryGenericObject, bugref:10053

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