VirtualBox

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

Last change on this file since 102788 was 98103, checked in by vboxsync, 20 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
RevLine 
[31888]1/* $Id: USBProxyDevice.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * USBProxy - USB device proxy.
4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[31888]8 *
[96407]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
[31888]26 */
27
28
[57358]29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[31888]32#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
33#include <VBox/usb.h>
34#include <VBox/usbfilter.h>
[35346]35#include <VBox/vmm/pdm.h>
[31888]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"
[35353]43#include "VBoxDD.h"
[31888]44
45
[57358]46/*********************************************************************************************************************************
47* Global Variables *
48*********************************************************************************************************************************/
[31888]49/** A dummy name used early during the construction phase to avoid log crashes. */
50static char g_szDummyName[] = "proxy xxxx:yyyy";
51
[59117]52/**
53 * Array of supported proxy backends.
54 */
55static PCUSBPROXYBACK g_aUsbProxies[] =
56{
57 &g_USBProxyDeviceHost,
58 &g_USBProxyDeviceVRDP,
59 &g_USBProxyDeviceUsbIp
60};
[31888]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{
[61246]67#define GET_DESC_RETRIES 6
[58642]68 int cRetries = 0;
[61246]69 uint16_t cbInitialHint = cbHint;
[58642]70
[90027]71 LogFlow(("GetStdDescSync: pProxyDev=%s, iDescType=%d, iIdx=%d, LangId=%04X, cbHint=%u\n", pProxyDev->pUsbIns->pszName, iDescType, iIdx, LangId, cbHint));
[31888]72 for (;;)
73 {
74 /*
75 * Setup a MSG URB, queue and reap it.
76 */
[50234]77 int rc = VINF_SUCCESS;
[31888]78 VUSBURB Urb;
79 AssertCompile(RT_SIZEOFMEMB(VUSBURB, abData) >= _4K);
[90027]80 RT_ZERO(Urb);
[59700]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;
[31888]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
[61246]100 uint8_t *pbDesc = (uint8_t *)(pSetup + 1);
101 uint32_t cbDesc = 0;
102 PVUSBURB pUrbReaped = NULL;
103
[50234]104 rc = pProxyDev->pOps->pfnUrbQueue(pProxyDev, &Urb);
105 if (RT_FAILURE(rc))
[61246]106 {
[87627]107 Log(("GetStdDescSync: pfnUrbQueue failed, rc=%d\n", rc));
[61246]108 goto err;
109 }
[31888]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
[61246]114 iMac devices may refuse to respond for instance.) */
[61247]115 pUrbReaped = pProxyDev->pOps->pfnUrbReap(pProxyDev, 5000 /* ms */);
[31888]116 if (!pUrbReaped)
117 {
[87627]118 Log(("GetStdDescSync: pfnUrbReap returned NULL, cancel and re-reap\n"));
[50234]119 rc = pProxyDev->pOps->pfnUrbCancel(pProxyDev, &Urb);
120 AssertRC(rc);
[62462]121 /** @todo This breaks the comment above... */
[31888]122 pUrbReaped = pProxyDev->pOps->pfnUrbReap(pProxyDev, RT_INDEFINITE_WAIT);
123 }
124 if (pUrbReaped != &Urb)
125 {
126 Log(("GetStdDescSync: pfnUrbReap failed, pUrbReaped=%p\n", pUrbReaped));
[61246]127 goto err;
[31888]128 }
129
130 if (Urb.enmStatus != VUSBSTATUS_OK)
131 {
132 Log(("GetStdDescSync: Urb.enmStatus=%d\n", Urb.enmStatus));
[61246]133 goto err;
[31888]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));
[61246]144 goto err;
[31888]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));
[61246]153 goto err;
[31888]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;
[61246]164 Log(("GetStdDescSync: Part descriptor, Urb.cbData=%u, cbDesc=%u cbHint=%u\n", Urb.cbData, cbDesc, cbHint));
165
[31888]166 if (cbHint > sizeof(Urb.abData))
[90027]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 }
[61246]172
173 goto err;
[31888]174 }
[61246]175
[62462]176 if (cbDesc > Urb.cbData - sizeof(VUSBSETUP))
[61246]177 {
178 Log(("GetStdDescSync: Descriptor length too short, cbDesc=%u, Urb.cbData=%u\n", cbDesc, Urb.cbData));
179 goto err;
180 }
181
[62462]182 if ( cbInitialHint != cbHint
183 && ( cbDesc != cbHint
184 || Urb.cbData < cbInitialHint) )
[61246]185 {
186 Log(("GetStdDescSync: Descriptor length incorrect, cbDesc=%u, Urb.cbData=%u, cbHint=%u\n", cbDesc, Urb.cbData, cbHint));
187 goto err;
188 }
189
[31888]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);
[61246]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 }
[31888]212 }
[61246]213
[31888]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
[66989]332/* Given the pointer to a configuration/interface/endpoint descriptor, find any following
[36477]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
[66989]340 Assert(*(this_desc + 1) == VUSB_DT_INTERFACE || *(this_desc + 1) == VUSB_DT_ENDPOINT || *(this_desc + 1) == VUSB_DT_CONFIG);
[36477]341 buf = this_desc;
342
[66989]343 /* Skip the current configuration/interface/endpoint descriptor. */
[36477]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
[31888]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
[33540]397 /* Check we didn't see this alternate setting already
[31888]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
[36475]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
[36477]419 cur_if->pvClass = collect_stray_bits(tmp, end, &cur_if->cbClass);
420
[31888]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));
[36475]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
[36477]450 cur_ep->pvClass = collect_stray_bits(tmp, end, &cur_ep->cbClass);
451
[31888]452 cur_ep->Core.wMaxPacketSize = RT_LE2H_U16(cur_ep->Core.wMaxPacketSize);
453
454 num_ep++;
455 break;
456 default:
[36479]457 /* Skip unknown descriptors. */
[31888]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;
[66989]481 uint8_t *tmp, *end;
[31888]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
[36475]513 /* Stash a pointer to the raw config descriptor; we may need bits of it later. */
514 out->pvOriginal = descs;
515
[31888]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
[66989]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
[31888]542 for(i=0; i < 4; i++)
543 for(x=0; x < 32; x++)
544 if ( cnt.idmap[i] & (1 << x) )
[36477]545 if ( !copy_interface(pIf++, (i << 6) | x, &ifd, &epd, (uint8_t *)out->pvOriginal, tot_len) ) {
[31888]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/**
[62956]594 * @interface_method_impl{PDMUSBREG,pfnUsbReset}
[31888]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/**
[62956]613 * @interface_method_impl{PDMUSBREG,pfnUsbGetDescriptorCache}
[31888]614 */
615static DECLCALLBACK(PCPDMUSBDESCCACHE) usbProxyDevGetDescriptorCache(PPDMUSBINS pUsbIns)
616{
617 PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
618 return &pThis->DescCache;
619}
620
621
622/**
[62956]623 * @interface_method_impl{PDMUSBREG,pfnUsbSetConfiguration}
[31888]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;
[50245]662 int rc = pProxyDev->pOps->pfnSetConfig(pProxyDev, bConfigurationValue);
663 if (RT_FAILURE(rc))
[31888]664 {
665 pProxyDev->iActiveCfg = -1;
[50245]666 return rc;
[31888]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/**
[62956]696 * @interface_method_impl{PDMUSBREG,pfnUsbSetInterface}
[31888]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
[50234]706 return pProxyDev->pOps->pfnSetInterface(pProxyDev, bInterfaceNumber, bAlternateSetting);
[31888]707}
708
709
710/**
[62956]711 * @interface_method_impl{PDMUSBREG,pfnUsbClearHaltedEndpoint}
[31888]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
[50234]721 return pProxyDev->pOps->pfnClearHaltedEndpoint(pProxyDev, uEndpoint);
[31888]722}
723
724
725/**
[62956]726 * @interface_method_impl{PDMUSBREG,pfnUrbQueue}
[31888]727 *
728 * USB Device Proxy: Call OS specific code.
729 */
730static DECLCALLBACK(int) usbProxyDevUrbQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
731{
[50234]732 int rc = VINF_SUCCESS;
[31888]733 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
[50234]734 rc = pProxyDev->pOps->pfnUrbQueue(pProxyDev, pUrb);
735 if (RT_FAILURE(rc))
[31888]736 return pProxyDev->fDetached
737 ? VERR_VUSB_DEVICE_NOT_ATTACHED
738 : VERR_VUSB_FAILED_TO_QUEUE_URB;
[50234]739 return rc;
[31888]740}
741
742
743/**
[62956]744 * @interface_method_impl{PDMUSBREG,pfnUrbCancel}
[31888]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);
[50234]751 return pProxyDev->pOps->pfnUrbCancel(pProxyDev, pUrb);
[31888]752}
753
754
755/**
[62956]756 * @interface_method_impl{PDMUSBREG,pfnUrbReap}
[31888]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
[49814]772/**
[62956]773 * @interface_method_impl{PDMUSBREG,pfnWakeup}
[49814]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
[62956]785/** @interface_method_impl{PDMUSBREG,pfnDestruct} */
[31888]786static DECLCALLBACK(void) usbProxyDestruct(PPDMUSBINS pUsbIns)
787{
[62992]788 PDMUSB_CHECK_VERSIONS_RETURN_VOID(pUsbIns);
[31888]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++)
[36475]803 {
[31888]804 RTMemFree((void *)pThis->paCfgDescs[i].paIfs);
[36475]805 RTMemFree((void *)pThis->paCfgDescs[i].pvOriginal);
806 }
[31888]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;
[50228]815
816 if (pThis->pvInstanceDataR3)
817 RTMemFree(pThis->pvInstanceDataR3);
[31888]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.
[91880]828 * @param pHlp The USB helper callback table.
[31888]829 * @param pNode The CFGM node.
830 * @param pszExact The exact value name.
831 * @param pszExpr The expression value name.
832 */
[91880]833static int usbProxyQueryNum(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx,
834 PCPDMUSBHLP pHlp, PCFGMNODE pNode,
835 const char *pszExact, const char *pszExpr)
[31888]836{
837 char szTmp[256];
838
839 /* try exact first */
840 uint16_t u16;
[91880]841 int rc = pHlp->pfnCFGMQueryU16(pNode, pszExact, &u16);
[31888]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. */
[91880]848 rc = pHlp->pfnCFGMQueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
[31888]849 if (RT_UNLIKELY(rc != VERR_CFGM_VALUE_NOT_FOUND))
850 {
851 szTmp[0] = '\0';
[91880]852 pHlp->pfnCFGMGetName(pNode, szTmp, sizeof(szTmp));
[31888]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';
[91880]861 pHlp->pfnCFGMGetName(pNode, szTmp, sizeof(szTmp));
[31888]862 LogRel(("usbProxyConstruct: %s: %s query failed, rc=%Rrc\n", szTmp, pszExact, rc));
863 return rc;
864 }
865
866 /* expression? */
[91880]867 rc = pHlp->pfnCFGMQueryString(pNode, pszExpr, szTmp, sizeof(szTmp));
[31888]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';
[91880]877 pHlp->pfnCFGMGetName(pNode, szTmp, sizeof(szTmp));
[31888]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
[62956]886/** @interface_method_impl{PDMUSBREG,pfnConstruct} */
[31888]887static DECLCALLBACK(int) usbProxyConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
888{
[62992]889 PDMUSB_CHECK_VERSIONS_RETURN(pUsbIns);
890 RT_NOREF(iInstance);
[91880]891 PUSBPROXYDEV pThis = PDMINS_2_DATA(pUsbIns, PUSBPROXYDEV);
892 PCPDMUSBHLP pHlp = pUsbIns->pHlpR3;
893
[31888]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;
[50229]904 pThis->fInited = false;
[31888]905
906 /*
907 * Read the basic configuration.
908 */
909 char szAddress[1024];
[91880]910 int rc = pHlp->pfnCFGMQueryString(pCfg, "Address", szAddress, sizeof(szAddress));
[31888]911 AssertRCReturn(rc, rc);
912
[59117]913 char szBackend[64];
[91880]914 rc = pHlp->pfnCFGMQueryString(pCfg, "Backend", szBackend, sizeof(szBackend));
[31888]915 AssertRCReturn(rc, rc);
916
917 /*
918 * Select backend and open the device.
919 */
[59117]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"));
[50228]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
[94342]937 rc = pThis->pOps->pfnOpen(pThis, szAddress);
[31888]938 if (RT_FAILURE(rc))
[59089]939 {
940 LogRel(("usbProxyConstruct: Failed to open '%s', rc=%Rrc\n", szAddress, rc));
[31888]941 return rc;
[59089]942 }
[31888]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;
[91880]990 PCFGMNODE pCur = pHlp->pfnCFGMGetFirstChild(pCfgGlobal);
[31888]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;
[91880]1009 for (pCur = pHlp->pfnCFGMGetFirstChild(pCfgGlobal); pCur; pCur = pHlp->pfnCFGMGetNextChild(pCur))
[31888]1010 {
1011 /*
1012 * Construct a filter from the attributes in the node.
1013 */
1014 USBFILTER Filter;
1015 USBFilterInit(&Filter, USBFILTERTYPE_CAPTURE);
1016
1017 /* numeric */
[91880]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")))
[31888]1024 continue; /* skip it */
1025
1026 /* strings */
1027 /** @todo manufacturer, product and serial strings */
1028
1029 /* ignore unknown config values, but not without bitching. */
[91880]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"))
[31888]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)
[91880]1053 pCfgGlobalDev = pHlp->pfnCFGMGetChild(pBestMatch, "Config");
[31888]1054 if (pCfgGlobalDev)
1055 pCfgGlobalDev = pCfgGlobal;
1056 }
1057
1058 /*
1059 * Query the rest of the configuration using the global as fallback.
1060 */
[91880]1061 rc = pHlp->pfnCFGMQueryU32(pCfg, "MaskedIfs", &pThis->fMaskedIfs);
[31888]1062 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
[91880]1063 rc = pHlp->pfnCFGMQueryU32(pCfgGlobalDev, "MaskedIfs", &pThis->fMaskedIfs);
[31888]1064 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1065 pThis->fMaskedIfs = 0;
1066 else
1067 AssertRCReturn(rc, rc);
1068
1069 bool fForce11Device;
[91880]1070 rc = pHlp->pfnCFGMQueryBool(pCfg, "Force11Device", &fForce11Device);
[31888]1071 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
[91880]1072 rc = pHlp->pfnCFGMQueryBool(pCfgGlobalDev, "Force11Device", &fForce11Device);
[31888]1073 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1074 fForce11Device = false;
1075 else
1076 AssertRCReturn(rc, rc);
1077
1078 bool fForce11PacketSize;
[91880]1079 rc = pHlp->pfnCFGMQueryBool(pCfg, "Force11PacketSize", &fForce11PacketSize);
[31888]1080 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
[91880]1081 rc = pHlp->pfnCFGMQueryBool(pCfgGlobalDev, "Force11PacketSize", &fForce11PacketSize);
[31888]1082 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1083 fForce11PacketSize = false;
1084 else
1085 AssertRCReturn(rc, rc);
1086
[66807]1087 bool fEditAudioSyncEp;
[91880]1088 rc = pHlp->pfnCFGMQueryBool(pCfg, "EditAudioSyncEp", &fEditAudioSyncEp);
[66807]1089 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
[91880]1090 rc = pHlp->pfnCFGMQueryBool(pCfgGlobalDev, "EditAudioSyncEp", &fEditAudioSyncEp);
[66807]1091 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1092 fEditAudioSyncEp = true; /* NB: On by default! */
1093 else
1094 AssertRCReturn(rc, rc);
1095
[86491]1096 bool fEditRemoteWake;
[91880]1097 rc = pHlp->pfnCFGMQueryBool(pCfg, "EditRemoteWake", &fEditRemoteWake);
[86491]1098 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
[91880]1099 rc = pHlp->pfnCFGMQueryBool(pCfgGlobalDev, "EditRemoteWake", &fEditRemoteWake);
[86491]1100 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1101 fEditRemoteWake = true; /* NB: On by default! */
1102 else
1103 AssertRCReturn(rc, rc);
1104
[31888]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;
[71300]1130 if (!paEps)
1131 continue;
1132
[31888]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 /*
[66807]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;
[71300]1183 if (!paEps)
1184 continue;
1185
[66807]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*/
[66913]1192 if (pbExtra[1] == 0)
1193 continue; /* If bSynchAddress is zero, leave the descriptor alone. */
1194
[66807]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 /*
[86515]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
[86491]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));
[90051]1221 if (paCfgs[iCfg].Core.bmAttributes & RT_BIT(5))
1222 {
[86491]1223 paCfgs[iCfg].Core.bmAttributes = paCfgs[iCfg].Core.bmAttributes & ~RT_BIT(5); /* Remote wakeup. */
[90051]1224 fEdited = true;
1225 LogRel(("VUSB: Disabled '%s' remote wakeup for configuration %d\n", pUsbIns->pszName, iCfg));
1226 }
[86491]1227 }
1228 }
1229
1230 /*
[31888]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 }
[50229]1250 pThis->fInited = true;
[31888]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 */
[40282]1275 ~0U,
[31888]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,
[49814]1322 /* pfnWakeup */
1323 usbProxyDevWakeup,
[31888]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