VirtualBox

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

Last change on this file since 29809 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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