VirtualBox

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

Last change on this file since 2456 was 994, checked in by vboxsync, 18 years ago

NO_COMPILER_H -> VBOX_WITHOUT_LINUX_COMPILER_H

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