VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBFE/USBProxyServiceLinux.cpp@ 486

Last change on this file since 486 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.1 KB
Line 
1/** @file
2 *
3 * VBox frontends: Basic Frontend (BFE):
4 * Implementation of USBProxyServiceLinux class
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include "USBProxyService.h"
28#include "Logging.h"
29
30#include <VBox/usb.h>
31#include <VBox/err.h>
32
33#include <iprt/string.h>
34#include <iprt/alloc.h>
35#include <iprt/assert.h>
36#include <iprt/file.h>
37#include <iprt/err.h>
38
39#include <stdlib.h>
40#include <string.h>
41#include <stdio.h>
42#include <ctype.h>
43#include <errno.h>
44#include <sys/statfs.h>
45#include <sys/poll.h>
46#include <unistd.h>
47#include <linux/usbdevice_fs.h>
48
49
50
51/*******************************************************************************
52* Structures and Typedefs *
53*******************************************************************************/
54/** Suffix translation. */
55typedef struct USBSUFF
56{
57 char szSuff[4];
58 unsigned cchSuff;
59 unsigned uMul;
60 unsigned uDiv;
61} USBSUFF, *PUSBSUFF;
62typedef const USBSUFF *PCUSBSUFF;
63
64
65/*******************************************************************************
66* Global Variables *
67*******************************************************************************/
68/**
69 * Suffixes for the endpoint polling interval.
70 */
71static const USBSUFF s_aIntervalSuff[] =
72{
73 { "ms", 2, 1, 0 },
74 { "us", 2, 1, 1000 },
75 { "ns", 2, 1, 1000000 },
76 { "s", 1, 1000, 0 },
77 { "", 0, 0, 0 } /* term */
78};
79
80
81/**
82 * Initialize data members.
83 */
84USBProxyServiceLinux::USBProxyServiceLinux (HostUSB *aHost, const char *aUsbfsRoot /* = "/proc/bus/usb" */)
85 : USBProxyService (aHost), mFile (NIL_RTFILE), mStream (NULL), mWakeupPipeR (NIL_RTFILE),
86 mWakeupPipeW (NIL_RTFILE), mUsbfsRoot (aUsbfsRoot)
87{
88 LogFlowMember (("USBProxyServiceLinux::USBProxyServiceLinux: aHost=%p aUsbfsRoot=%p:{%s}\n", aHost, aUsbfsRoot, aUsbfsRoot));
89
90 /*
91 * Open the devices file.
92 */
93 int rc = VERR_NO_MEMORY;
94 char *pszDevices;
95 RTStrAPrintf (&pszDevices, "%s/devices", aUsbfsRoot);
96 if (pszDevices)
97 {
98 rc = RTFileOpen (&mFile, pszDevices, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
99 if (VBOX_SUCCESS (rc))
100 {
101 /*
102 * Check that we're actually on the usbfs.
103 */
104 struct statfs StFS;
105 if (!fstatfs (mFile, &StFS))
106 {
107 if (StFS.f_type == USBDEVICE_SUPER_MAGIC)
108 {
109 int pipes[2];
110 if (!pipe (pipes))
111 {
112 mWakeupPipeR = pipes[0];
113 mWakeupPipeW = pipes[1];
114 mStream = fdopen (mFile, "r");
115 if (mStream)
116 {
117 /*
118 * Start the poller thread.
119 */
120 rc = start();
121 if (VBOX_SUCCESS (rc))
122 {
123 RTStrFree (pszDevices);
124 LogFlowMember (("USBProxyServiceLinux::USBProxyServiceLinux: returns successfully - mFile=%d mStream=%p mWakeupPipeR/W=%d/%d\n",
125 mFile, mStream, mWakeupPipeR, mWakeupPipeW));
126 return;
127 }
128
129 fclose (mStream);
130 mStream = NULL;
131 mFile = NIL_RTFILE;
132 }
133
134 RTFileClose (mWakeupPipeR);
135 RTFileClose (mWakeupPipeW);
136 mWakeupPipeW = mWakeupPipeR = NIL_RTFILE;
137 }
138 }
139 else
140 {
141 Log (("USBProxyServiceLinux::USBProxyServiceLinux: StFS.f_type=%d expected=%d\n", StFS.f_type, USBDEVICE_SUPER_MAGIC));
142 rc = VERR_INVALID_PARAMETER;
143 }
144 }
145 else
146 {
147 rc = RTErrConvertFromErrno (errno);
148 Log (("USBProxyServiceLinux::USBProxyServiceLinux: fstatfs failed, errno=%d\n", errno));
149 }
150 RTFileClose (mFile);
151 mFile = NIL_RTFILE;
152 }
153 else
154 {
155#ifndef DEBUG_fm3
156 /* I'm currently using Linux with disabled USB support */
157 AssertRC (rc);
158#endif
159 Log (("USBProxyServiceLinux::USBProxyServiceLinux: RTFileOpen(,%s,,) -> %Vrc\n", pszDevices, rc));
160 }
161 RTStrFree (pszDevices);
162 }
163 else
164 Log (("USBProxyServiceLinux::USBProxyServiceLinux: out of memory!\n"));
165
166 mLastError = rc;
167 LogFlowMember (("USBProxyServiceLinux::USBProxyServiceLinux: returns failure!!! (rc=%Vrc)\n", rc));
168}
169
170
171/**
172 * Stop all service threads and free the device chain.
173 */
174USBProxyServiceLinux::~USBProxyServiceLinux()
175{
176 LogFlowMember (("USBProxyServiceLinux::~USBProxyServiceLinux:\n"));
177
178 /*
179 * Stop the service.
180 */
181 if (isActive())
182 stop();
183
184 /*
185 * Free resources.
186 */
187 if (mStream)
188 {
189 fclose (mStream);
190 mStream = NULL;
191 mFile = NIL_RTFILE;
192 }
193 else if (mFile != NIL_RTFILE)
194 {
195 RTFileClose (mFile);
196 mFile = NIL_RTFILE;
197 }
198
199 RTFileClose (mWakeupPipeR);
200 RTFileClose (mWakeupPipeW);
201 mWakeupPipeW = mWakeupPipeR = NIL_RTFILE;
202}
203
204
205int USBProxyServiceLinux::captureDevice (HostUSBDevice *aDevice)
206{
207 /*
208 * Don't think we need to do anything when the device is held...
209 */
210 return VINF_SUCCESS;
211}
212
213
214int USBProxyServiceLinux::holdDevice (HostUSBDevice *pDevice)
215{
216 /*
217 * This isn't really implemented, we can usually wrestle
218 * any user when we need it... Anyway, I don't have anywhere to store
219 * any info per device atm.
220 */
221 return VINF_SUCCESS;
222}
223
224
225int USBProxyServiceLinux::releaseDevice (HostUSBDevice *aDevice)
226{
227 /*
228 * We're not really holding it atm.
229 */
230 return VINF_SUCCESS;
231}
232
233
234int USBProxyServiceLinux::resetDevice (HostUSBDevice *aDevice)
235{
236 /*
237 * We don't dare reset anything, but the USB Proxy Device
238 * will reset upon detach, so this should be ok.
239 */
240 return VINF_SUCCESS;
241}
242
243
244int USBProxyServiceLinux::wait (unsigned aMillies)
245{
246 struct pollfd PollFds[2];
247
248 memset(&PollFds, 0, sizeof(PollFds));
249 PollFds[0].fd = mFile;
250 PollFds[0].events = POLLIN;
251 PollFds[1].fd = mWakeupPipeR;
252 PollFds[1].events = POLLIN | POLLERR | POLLHUP;
253
254 int rc = poll (&PollFds[0], 2, aMillies);
255 if (rc == 0)
256 return VERR_TIMEOUT;
257 if (rc > 0)
258 return VINF_SUCCESS;
259 return RTErrConvertFromErrno (errno);
260}
261
262
263int USBProxyServiceLinux::interruptWait (void)
264{
265 int rc = RTFileWrite (mWakeupPipeW, "Wakeup!", sizeof("Wakeup!") - 1, NULL);
266 if (VBOX_SUCCESS (rc))
267 fsync (mWakeupPipeW);
268 return rc;
269}
270
271
272/**
273 * "reads" the number suffix. It's more like validating it and
274 * skipping the necessary number of chars.
275 */
276static int usbReadSkipSuffix (char **ppszNext)
277{
278 char *pszNext = *ppszNext;
279 if (!isspace (*pszNext) && *pszNext)
280 {
281 /* skip unit */
282 if (pszNext[0] == 'm' && pszNext[1] == 's')
283 pszNext += 2;
284 else if (pszNext[0] == 'm' && pszNext[1] == 'A')
285 pszNext += 2;
286
287 /* skip parenthesis */
288 if (*pszNext == '(')
289 {
290 pszNext = strchr (pszNext, ')');
291 if (!pszNext++)
292 {
293 AssertMsgFailed (("*ppszNext=%s\n", *ppszNext));
294 return VERR_PARSE_ERROR;
295 }
296 }
297
298 /* blank or end of the line. */
299 if (!isspace (*pszNext) && *pszNext)
300 {
301 AssertMsgFailed (("pszNext=%s\n", pszNext));
302 return VERR_PARSE_ERROR;
303 }
304
305 /* it's ok. */
306 *ppszNext = pszNext;
307 }
308
309 return VINF_SUCCESS;
310}
311
312
313/**
314 * Reads a USB number returning the number and the position of the next character to parse.
315 */
316static int usbReadNum (const char *pszValue, unsigned uBase, uint32_t u32Mask, PCUSBSUFF paSuffs, void *pvNum, char **ppszNext)
317{
318 /*
319 * Initialize return value to zero and strip leading spaces.
320 */
321 switch (u32Mask)
322 {
323 case 0xff: *(uint8_t *)pvNum = 0; break;
324 case 0xffff: *(uint16_t *)pvNum = 0; break;
325 case 0xffffffff: *(uint32_t *)pvNum = 0; break;
326 }
327 pszValue = RTStrStripL (pszValue);
328 if (*pszValue)
329 {
330 /*
331 * Try convert the number.
332 */
333 char *pszNext;
334 uint32_t u32 = 0;
335 RTStrToUInt32Ex (pszValue, &pszNext, uBase, &u32);
336 if (pszNext == pszValue)
337 {
338 AssertMsgFailed (("pszValue=%d\n", pszValue));
339 return VERR_NO_DATA;
340 }
341
342 /*
343 * Check the range.
344 */
345 if (u32 & ~u32Mask)
346 {
347 AssertMsgFailed (("pszValue=%d u32=%#x lMask=%#x\n", pszValue, u32, u32Mask));
348 return VERR_OUT_OF_RANGE;
349 }
350
351 /*
352 * Validate and skip stuff following the number.
353 */
354 if (paSuffs)
355 {
356 if (!isspace (*pszNext) && *pszNext)
357 {
358 for (PCUSBSUFF pSuff = paSuffs; pSuff->szSuff[0]; pSuff++)
359 {
360 if ( !strncmp (pSuff->szSuff, pszNext, pSuff->cchSuff)
361 && (!pszNext[pSuff->cchSuff] || isspace (pszNext[pSuff->cchSuff])))
362 {
363 if (pSuff->uDiv)
364 u32 /= pSuff->uDiv;
365 else
366 u32 *= pSuff->uMul;
367 break;
368 }
369 }
370 }
371 }
372 else
373 {
374 int rc = usbReadSkipSuffix (&pszNext);
375 if (VBOX_FAILURE (rc))
376 return rc;
377 }
378
379 *ppszNext = pszNext;
380
381 /*
382 * Set the value.
383 */
384 switch (u32Mask)
385 {
386 case 0xff: *(uint8_t *)pvNum = (uint8_t)u32; break;
387 case 0xffff: *(uint16_t *)pvNum = (uint16_t)u32; break;
388 case 0xffffffff: *(uint32_t *)pvNum = (uint32_t)u32; break;
389 }
390 }
391 return VINF_SUCCESS;
392}
393
394static int usbRead8 (const char *pszValue, unsigned uBase, uint8_t *pu8, char **ppszNext)
395{
396 return usbReadNum (pszValue, uBase, 0xff, NULL, pu8, ppszNext);
397}
398
399static int usbRead16 (const char *pszValue, unsigned uBase, uint16_t *pu16, char **ppszNext)
400{
401 return usbReadNum (pszValue, uBase, 0xffff, NULL, pu16, ppszNext);
402}
403
404static int usbRead16Suff (const char *pszValue, unsigned uBase, PCUSBSUFF paSuffs, uint16_t *pu16, char **ppszNext)
405{
406 return usbReadNum (pszValue, uBase, 0xffff, paSuffs, pu16, ppszNext);
407}
408
409/**
410 * Reads a USB BCD number returning the number and the position of the next character to parse.
411 * The returned number contains the integer part in the high byte and the decimal part in the low byte.
412 */
413static int usbReadBCD (const char *pszValue, unsigned uBase, uint16_t *pu16, char **ppszNext)
414{
415 /*
416 * Initialize return value to zero and strip leading spaces.
417 */
418 *pu16 = 0;
419 pszValue = RTStrStripL (pszValue);
420 if (*pszValue)
421 {
422 /*
423 * Try convert the number.
424 */
425 /* integer part */
426 char *pszNext;
427 uint32_t u32Int = 0;
428 RTStrToUInt32Ex (pszValue, &pszNext, uBase, &u32Int);
429 if (pszNext == pszValue)
430 {
431 AssertMsgFailed (("pszValue=%s\n", pszValue));
432 return VERR_NO_DATA;
433 }
434 if (u32Int & ~0xff)
435 {
436 AssertMsgFailed (("pszValue=%s u32Int=%#x (int)\n", pszValue, u32Int));
437 return VERR_OUT_OF_RANGE;
438 }
439
440 /* skip dot and read decimal part */
441 if (*pszNext != '.')
442 {
443 AssertMsgFailed (("pszValue=%s pszNext=%s (int)\n", pszValue, pszNext));
444 return VERR_PARSE_ERROR;
445 }
446 char *pszValue2 = RTStrStripL (pszNext + 1);
447 uint32_t u32Dec = 0;
448 RTStrToUInt32Ex (pszValue2, &pszNext, uBase, &u32Dec);
449 if (pszNext == pszValue)
450 {
451 AssertMsgFailed (("pszValue=%s\n", pszValue));
452 return VERR_NO_DATA;
453 }
454 if (u32Dec & ~0xff)
455 {
456 AssertMsgFailed (("pszValue=%s u32Dec=%#x\n", pszValue, u32Dec));
457 return VERR_OUT_OF_RANGE;
458 }
459
460 /*
461 * Validate and skip stuff following the number.
462 */
463 int rc = usbReadSkipSuffix (&pszNext);
464 if (VBOX_FAILURE (rc))
465 return rc;
466 *ppszNext = pszNext;
467
468 /*
469 * Set the value.
470 */
471 *pu16 = (uint16_t)u32Int << 8 | (uint16_t)u32Dec;
472 }
473 return VINF_SUCCESS;
474}
475
476
477/**
478 * Reads a string, i.e. allocates memory and copies it.
479 *
480 * We assume that a string is pure ASCII, if that's not the case
481 * tell me how to figure out the codeset please.
482 */
483static int usbReadStr (const char *pszValue, const char **ppsz)
484{
485 if (*ppsz)
486 RTStrFree ((char *)*ppsz);
487 *ppsz = RTStrDup (pszValue);
488 if (*ppsz)
489 return VINF_SUCCESS;
490 return VERR_NO_MEMORY;
491}
492
493
494/**
495 * Skips the current property.
496 */
497static char * usbReadSkip (const char *pszValue)
498{
499 char *psz = strchr (pszValue, '=');
500 if (psz)
501 psz = strchr (psz + 1, '=');
502 if (!psz)
503 return strchr (pszValue, '\0');
504 while (psz > pszValue && !isspace (psz[-1]))
505 psz--;
506 Assert (psz > pszValue);
507 return psz;
508}
509
510
511/**
512 * Compare a prefix and returns pointer to the char following it if it matches.
513 */
514static char *usbPrefix (char *psz, const char *pszPref, size_t cchPref)
515{
516 if (strncmp (psz, pszPref, cchPref))
517 return NULL;
518 return psz + cchPref;
519}
520
521
522/**
523 * Checks which state the device is in.
524 */
525static USBDEVICESTATE usbDeterminState (PCUSBDEVICE pDevice)
526{
527 if (!pDevice->idVendor)
528 return USBDEVICESTATE_UNSUPPORTED;
529
530 /*
531 * We cannot distinguish between USED_BY_HOST_CAPTURABLE and
532 * USED_BY_GUEST, HELD_BY_PROXY all that well and it shouldn't be
533 * necessary either.
534 */
535 USBDEVICESTATE enmState = USBDEVICESTATE_UNUSED;
536 for (int iCfg = pDevice->bNumConfigurations - 1; iCfg >= 0; iCfg--)
537 for (int iIf = pDevice->paConfigurations[iCfg].bConfigurationValue - 1; iIf >= 0; iIf--)
538 {
539 const char *pszDriver = pDevice->paConfigurations[iCfg].paInterfaces[iIf].pszDriver;
540 if (pszDriver)
541 {
542 if (!strcmp (pszDriver, "hub"))
543 {
544 enmState = USBDEVICESTATE_USED_BY_HOST;
545 break;
546 }
547 enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
548 }
549 }
550
551 return enmState;
552}
553
554
555PUSBDEVICE USBProxyServiceLinux::getDevices (void)
556{
557 PUSBDEVICE pFirst = NULL;
558 if (mStream)
559 {
560 PUSBDEVICE *ppNext = NULL;
561 USBDEVICE Dev = {0};
562 int cHits = 0;
563 int iCfg = 0;
564 PUSBCONFIG pCfg = NULL;
565 PUSBINTERFACE pIf = NULL;
566 int iEp = 0;
567 PUSBENDPOINT pEp = NULL;
568 char szLine[1024];
569
570 rewind (mStream);
571 int rc = VINF_SUCCESS;
572 while ( VBOX_SUCCESS (rc)
573 && fgets (szLine, sizeof (szLine), mStream))
574 {
575 char *psz;
576 char *pszValue;
577
578 /* validate and remove the trailing newline. */
579 psz = strchr (szLine, '\0');
580 if (psz[-1] != '\n' && !feof (mStream))
581 {
582 AssertMsgFailed (("Line too long. (cch=%d)\n", strlen (szLine)));
583 continue;
584 }
585
586 /* strip */
587 psz = RTStrStrip (szLine);
588 if (!*psz)
589 continue;
590
591 /*
592 * Interpret the line.
593 * (Ordered by normal occurence.)
594 */
595 char ch = psz[0];
596 if (psz[1] != ':')
597 continue;
598 psz = RTStrStripL (psz + 3);
599 #define PREFIX(str) ( (pszValue = usbPrefix (psz, str, sizeof (str) - 1)) != NULL )
600 switch (ch)
601 {
602 /*
603 * T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd
604 * | | | | | | | | |__MaxChildren
605 * | | | | | | | |__Device Speed in Mbps
606 * | | | | | | |__DeviceNumber
607 * | | | | | |__Count of devices at this level
608 * | | | | |__Connector/Port on Parent for this device
609 * | | | |__Parent DeviceNumber
610 * | | |__Level in topology for this bus
611 * | |__Bus number
612 * |__Topology info tag
613 */
614 case 'T':
615 /* add */
616 AssertMsg (cHits >= 3 || cHits == 0, ("cHits=%d\n", cHits));
617 if (cHits >= 3)
618 {
619 Dev.enmState = usbDeterminState (&Dev);
620 PUSBDEVICE pDev = (PUSBDEVICE) RTMemAlloc (sizeof(*pDev));
621 if (pDev)
622 {
623 *pDev = Dev;
624 if (Dev.enmState != USBDEVICESTATE_UNSUPPORTED)
625 {
626 RTStrAPrintf((char **)&pDev->pszAddress, "%s/%03d/%03d", mUsbfsRoot.c_str(), pDev->bBus, pDev->bDevNum);
627 if (pDev->pszAddress)
628 {
629 if (ppNext)
630 *ppNext = pDev;
631 else
632 pFirst = pDev;
633 ppNext = &pDev->pNext;
634 }
635 else
636 {
637 freeDevice (pDev);
638 rc = VERR_NO_MEMORY;
639 }
640 }
641 else
642 freeDevice (pDev);
643 memset (&Dev, 0, sizeof (Dev));
644 }
645 else
646 rc = VERR_NO_MEMORY;
647 }
648
649 /* Reset device state */
650 cHits = 1;
651 iCfg = 0;
652 pCfg = NULL;
653 pIf = NULL;
654 iEp = 0;
655 pEp = NULL;
656
657
658 /* parse the line. */
659 while (*psz && VBOX_SUCCESS (rc))
660 {
661 if (PREFIX ("Bus="))
662 rc = usbRead8 (pszValue, 10, &Dev.bBus, &psz);
663 else if (PREFIX ("Lev="))
664 rc = usbRead8 (pszValue, 10, &Dev.bLevel, &psz);
665 else if (PREFIX ("Dev#="))
666 rc = usbRead8 (pszValue, 10, &Dev.bDevNum, &psz);
667 else if (PREFIX ("Prnt="))
668 rc = usbRead8 (pszValue, 10, &Dev.bDevNumParent, &psz);
669 else if (PREFIX ("Port="))
670 rc = usbRead8 (pszValue, 10, &Dev.bPort, &psz);
671 else if (PREFIX ("Cnt="))
672 rc = usbRead8 (pszValue, 10, &Dev.bNumDevices, &psz);
673 //else if (PREFIX ("Spd="))
674 // rc = usbReadSpeed (pszValue, &Dev.cbSpeed, &psz);
675 else if (PREFIX ("MxCh="))
676 rc = usbRead8 (pszValue, 10, &Dev.bMaxChildren, &psz);
677 else
678 psz = usbReadSkip (psz);
679 psz = RTStrStripL (psz);
680 }
681 break;
682
683 /*
684 * Bandwidth info:
685 * B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
686 * | | | |__Number of isochronous requests
687 * | | |__Number of interrupt requests
688 * | |__Total Bandwidth allocated to this bus
689 * |__Bandwidth info tag
690 */
691 case 'B':
692 break;
693
694 /*
695 * D: Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
696 * | | | | | | |__NumberConfigurations
697 * | | | | | |__MaxPacketSize of Default Endpoint
698 * | | | | |__DeviceProtocol
699 * | | | |__DeviceSubClass
700 * | | |__DeviceClass
701 * | |__Device USB version
702 * |__Device info tag #1
703 */
704 case 'D':
705 while (*psz && VBOX_SUCCESS (rc))
706 {
707 if (PREFIX ("Ver="))
708 rc = usbReadBCD (pszValue, 16, &Dev.bcdUSB, &psz);
709 else if (PREFIX ("Cls="))
710 rc = usbRead8 (pszValue, 16, &Dev.bDeviceClass, &psz);
711 else if (PREFIX ("Sub="))
712 rc = usbRead8 (pszValue, 16, &Dev.bDeviceSubClass, &psz);
713 else if (PREFIX ("Prot="))
714 rc = usbRead8 (pszValue, 16, &Dev.bDeviceProtocol, &psz);
715 //else if (PREFIX ("MxPS="))
716 // rc = usbRead16 (pszValue, 10, &Dev.wMaxPacketSize, &psz);
717 else if (PREFIX ("#Cfgs="))
718 rc = usbRead8 (pszValue, 10, &Dev.bNumConfigurations, &psz);
719 else
720 psz = usbReadSkip (psz);
721 psz = RTStrStripL (psz);
722 }
723 cHits++;
724 break;
725
726 /*
727 * P: Vendor=xxxx ProdID=xxxx Rev=xx.xx
728 * | | | |__Product revision number
729 * | | |__Product ID code
730 * | |__Vendor ID code
731 * |__Device info tag #2
732 */
733 case 'P':
734 while (*psz && VBOX_SUCCESS (rc))
735 {
736 if (PREFIX ("Vendor="))
737 rc = usbRead16 (pszValue, 16, &Dev.idVendor, &psz);
738 else if (PREFIX ("ProdID="))
739 rc = usbRead16 (pszValue, 16, &Dev.idProduct, &psz);
740 else if (PREFIX ("Rev="))
741 rc = usbReadBCD (pszValue, 16, &Dev.bcdDevice, &psz);
742 else
743 psz = usbReadSkip (psz);
744 psz = RTStrStripL (psz);
745 }
746 cHits++;
747 break;
748
749 /*
750 * String.
751 */
752 case 'S':
753 if (PREFIX ("Manufacturer="))
754 rc = usbReadStr (pszValue, &Dev.pszManufacturer);
755 else if (PREFIX ("Product="))
756 rc = usbReadStr (pszValue, &Dev.pszProduct);
757 else if (PREFIX ("SerialNumber="))
758 {
759 rc = usbReadStr (pszValue, &Dev.pszSerialNumber);
760 if (VBOX_SUCCESS (rc))
761 Dev.u64SerialHash = calcSerialHash (pszValue);
762 }
763 break;
764
765 /*
766 * C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
767 * | | | | | |__MaxPower in mA
768 * | | | | |__Attributes
769 * | | | |__ConfiguratioNumber
770 * | | |__NumberOfInterfaces
771 * | |__ "*" indicates the active configuration (others are " ")
772 * |__Config info tag
773 */
774 case 'C':
775 {
776 USBCONFIG Cfg = {0};
777 Cfg.fActive = psz[-2] == '*';
778 while (*psz && VBOX_SUCCESS (rc))
779 {
780 if (PREFIX ("#Ifs="))
781 rc = usbRead8 (pszValue, 10, &Cfg.bNumInterfaces, &psz);
782 else if (PREFIX ("Cfg#="))
783 rc = usbRead8 (pszValue, 10, &Cfg.bConfigurationValue, &psz);
784 else if (PREFIX ("Atr="))
785 rc = usbRead8 (pszValue, 16, &Cfg.bmAttributes, &psz);
786 else if (PREFIX ("MxPwr="))
787 rc = usbRead16 (pszValue, 10, &Cfg.u16MaxPower, &psz);
788 else
789 psz = usbReadSkip (psz);
790 psz = RTStrStripL (psz);
791 }
792 if (VBOX_SUCCESS (rc))
793 {
794 if (iCfg < Dev.bNumConfigurations)
795 {
796 /* Add the config. */
797 if (!Dev.paConfigurations)
798 {
799 Dev.paConfigurations = pCfg = (PUSBCONFIG) RTMemAllocZ (sizeof (Cfg) * Dev.bNumConfigurations);
800 if (pCfg)
801 {
802 *pCfg = Cfg;
803 iCfg = 1;
804 }
805 else
806 rc = VERR_NO_MEMORY;
807 }
808 else
809 {
810 *++pCfg = Cfg;
811 iCfg++;
812 }
813 }
814 else
815 {
816 AssertMsgFailed (("iCfg=%d bNumConfigurations=%d\n", iCfg, Dev.bNumConfigurations));
817 rc = VERR_INTERNAL_ERROR;
818 }
819 }
820
821 /* new config, so, start anew with interfaces and endpoints. */
822 pIf = NULL;
823 iEp = 0;
824 pEp = NULL;
825 break;
826 }
827
828 /*
829 * I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
830 * | | | | | | | |__Driver name
831 * | | | | | | | or "(none)"
832 * | | | | | | |__InterfaceProtocol
833 * | | | | | |__InterfaceSubClass
834 * | | | | |__InterfaceClass
835 * | | | |__NumberOfEndpoints
836 * | | |__AlternateSettingNumber
837 * | |__InterfaceNumber
838 * |__Interface info tag
839 */
840 case 'I':
841 {
842 USBINTERFACE If = {0};
843 while (*psz && VBOX_SUCCESS (rc))
844 {
845 if (PREFIX ("If#="))
846 rc = usbRead8 (pszValue, 10, &If.bInterfaceNumber, &psz);
847 else if (PREFIX ("Alt="))
848 rc = usbRead8 (pszValue, 10, &If.bAlternateSetting, &psz);
849 else if (PREFIX ("#EPs="))
850 rc = usbRead8 (pszValue, 10, &If.bNumEndpoints, &psz);
851 else if (PREFIX ("Cls="))
852 rc = usbRead8 (pszValue, 16, &If.bInterfaceClass, &psz);
853 else if (PREFIX ("Sub="))
854 rc = usbRead8 (pszValue, 16, &If.bInterfaceSubClass, &psz);
855 else if (PREFIX ("Prot="))
856 rc = usbRead8 (pszValue, 16, &If.bInterfaceProtocol, &psz);
857 else if (PREFIX ("Driver="))
858 {
859 rc = usbReadStr (pszValue, &If.pszDriver);
860 if ( If.pszDriver
861 && ( !strcmp (If.pszDriver, "(none)")
862 || !strcmp (If.pszDriver, "(no driver)"))
863 || !*If.pszDriver)
864 {
865 RTStrFree ((char *)If.pszDriver);
866 If.pszDriver = NULL;
867 }
868 break;
869 }
870 else
871 psz = usbReadSkip (psz);
872 psz = RTStrStripL (psz);
873 }
874 if (VBOX_SUCCESS (rc))
875 {
876 if (pCfg && If.bInterfaceNumber < pCfg->bNumInterfaces)
877 {
878 /* Add the config. */
879 if (!pCfg->paInterfaces)
880 {
881 pCfg->paInterfaces = pIf = (PUSBINTERFACE) RTMemAllocZ (sizeof (If) * pCfg->bNumInterfaces);
882 if (pIf)
883 {
884 Assert (!If.bInterfaceNumber); Assert (!If.bAlternateSetting);
885 *pIf = If;
886 }
887 else
888 rc = VERR_NO_MEMORY;
889 }
890 else
891 {
892 /*
893 * Alternate settings makes life *difficult*!
894 * ASSUMES: ORDER ASC bInterfaceNumber, bAlternateSetting
895 */
896 pIf = &pCfg->paInterfaces[If.bInterfaceNumber];
897 if (!If.bAlternateSetting)
898 *pIf = If;
899 else
900 {
901 PUSBINTERFACE paAlts = (PUSBINTERFACE) RTMemRealloc (pIf->paAlts, (pIf->cAlts + 1) * sizeof(*pIf));
902 if (paAlts)
903 {
904 pIf->paAlts = paAlts;
905 pIf = &paAlts[pIf->cAlts++];
906 *pIf = If;
907 }
908 else
909 rc = VERR_NO_MEMORY;
910 }
911 }
912 }
913 else
914 {
915 AssertMsgFailed (("iCfg=%d bInterfaceNumber=%d bNumInterfaces=%d\n", iCfg, If.bInterfaceNumber, pCfg->bNumInterfaces));
916 rc = VERR_INTERNAL_ERROR;
917 }
918 }
919
920 /* start anew with endpoints. */
921 iEp = 0;
922 pEp = NULL;
923 break;
924 }
925
926
927 /*
928 * E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
929 * | | | | |__Interval (max) between transfers
930 * | | | |__EndpointMaxPacketSize
931 * | | |__Attributes(EndpointType)
932 * | |__EndpointAddress(I=In,O=Out)
933 * |__Endpoint info tag
934 */
935 case 'E':
936 {
937 USBENDPOINT Ep = {0};
938 while (*psz && VBOX_SUCCESS (rc))
939 {
940 if (PREFIX ("Ad="))
941 rc = usbRead8 (pszValue, 16, &Ep.bEndpointAddress, &psz);
942 else if (PREFIX ("Atr="))
943 rc = usbRead8 (pszValue, 16, &Ep.bmAttributes, &psz);
944 else if (PREFIX ("MxPS="))
945 rc = usbRead16 (pszValue, 10, &Ep.wMaxPacketSize, &psz);
946 else if (PREFIX ("Ivl="))
947 rc = usbRead16Suff (pszValue, 10, &s_aIntervalSuff[0], &Ep.u16Interval, &psz);
948 else
949 psz = usbReadSkip (psz);
950 psz = RTStrStripL (psz);
951 }
952 if (VBOX_SUCCESS (rc))
953 {
954 if (pIf && iEp < pIf->bNumEndpoints)
955 {
956 /* Add the config. */
957 if (!pIf->paEndpoints)
958 {
959 pIf->paEndpoints = pEp = (PUSBENDPOINT) RTMemAllocZ (sizeof (Ep) * pIf->bNumEndpoints);
960 if (pEp)
961 {
962 *pEp = Ep;
963 iEp = 1;
964 }
965 else
966 rc = VERR_NO_MEMORY;
967 }
968 else
969 {
970 *++pEp = Ep;
971 iEp++;
972 }
973 }
974 else
975 {
976 AssertMsgFailed (("iCfg=%d bInterfaceNumber=%d iEp=%d bNumInterfaces=%d\n", iCfg, pIf->bInterfaceNumber, iEp, pIf->bNumEndpoints));
977 rc = VERR_INTERNAL_ERROR;
978 }
979 }
980 break;
981 }
982
983 }
984 #undef PREFIX
985 } /* parse loop */
986
987 /*
988 * Add the current entry.
989 */
990 AssertMsg (cHits >= 3 || cHits == 0, ("cHits=%d\n", cHits));
991 if (cHits >= 3)
992 {
993 Dev.enmState = usbDeterminState (&Dev);
994 PUSBDEVICE pDev = (PUSBDEVICE) RTMemAlloc (sizeof(*pDev));
995 if (pDev)
996 {
997 *pDev = Dev;
998 if (Dev.enmState != USBDEVICESTATE_UNSUPPORTED)
999 {
1000 RTStrAPrintf((char **)&pDev->pszAddress, "%s/%03d/%03d", mUsbfsRoot.c_str(), pDev->bBus, pDev->bDevNum);
1001 if (pDev->pszAddress)
1002 {
1003 if (ppNext)
1004 *ppNext = pDev;
1005 else
1006 pFirst = pDev;
1007 ppNext = &pDev->pNext;
1008 }
1009 else
1010 {
1011 rc = VERR_NO_MEMORY;
1012 freeDevice (pDev);
1013 }
1014 }
1015 else
1016 freeDevice (pDev);
1017 }
1018 else
1019 rc = VERR_NO_MEMORY;
1020 }
1021
1022 /*
1023 * Success?
1024 */
1025 if (VBOX_FAILURE (rc))
1026 {
1027 LogFlow (("USBProxyServiceLinux::getDevices: rc=%Vrc\n", rc));
1028 while (pFirst)
1029 {
1030 PUSBDEVICE pFree = pFirst;
1031 pFirst = pFirst->pNext;
1032 freeDevice (pFree);
1033 }
1034 }
1035 }
1036 return pFirst;
1037}
1038
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