VirtualBox

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

Last change on this file since 71741 was 71300, checked in by vboxsync, 7 years ago

VUSB: Fishy devices may have interfaces with no endpoints, work around that.

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