VirtualBox

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

Last change on this file since 59767 was 59704, checked in by vboxsync, 9 years ago

VUSB: Some structural cleanup (#3 Make the VUSB URB specific data private to the VUSB stack, some interface changes required for XHCI because it previously required access to some VUsb members)

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