VirtualBox

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

Last change on this file since 12467 was 8539, checked in by vboxsync, 17 years ago

Drop the USBDEVICE bits we don't currently need.

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