VirtualBox

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

最後變更 在這個檔案從31888是 31888,由 vboxsync 提交於 15 年 前

Devices: export USB proxy device to OSE

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

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