VirtualBox

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

Last change on this file since 50228 was 50228, checked in by vboxsync, 11 years ago

USB/Proxy: Start a source code cleanup, remove unused struct members and make the generic proxy code do the backend specific memory allocation (fixes a small memory leak in the VRDP backend when closing a proxy device)

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette