VirtualBox

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

Last change on this file since 106061 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

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