VirtualBox

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

Last change on this file since 59083 was 58645, checked in by vboxsync, 9 years ago

build fix

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