VirtualBox

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

Last change on this file since 4861 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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