~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Main/src-server/linux/USBGetDevices.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: USBGetDevices.cpp 35599 2011-01-18 09:52:52Z vboxsync $ */
 
2
/** @file
 
3
 * VirtualBox Linux host USB device enumeration.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2006-2010 Oracle Corporation
 
8
 *
 
9
 * This file is part of VirtualBox Open Source Edition (OSE), as
 
10
 * available from http://www.virtualbox.org. This file is free software;
 
11
 * you can redistribute it and/or modify it under the terms of the GNU
 
12
 * General Public License (GPL) as published by the Free Software
 
13
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 
14
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 
15
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 
16
 */
 
17
 
 
18
 
 
19
/*******************************************************************************
 
20
*   Header Files                                                               *
 
21
*******************************************************************************/
 
22
 
 
23
#include "USBGetDevices.h"
 
24
 
 
25
#include <VBox/usb.h>
 
26
#include <VBox/usblib.h>
 
27
 
 
28
#include <iprt/linux/sysfs.h>
 
29
#include <iprt/cdefs.h>
 
30
#include <iprt/ctype.h>
 
31
#include <iprt/err.h>
 
32
#include <iprt/fs.h>
 
33
#include <iprt/log.h>
 
34
#include <iprt/mem.h>
 
35
#include <iprt/param.h>
 
36
#include <iprt/path.h>
 
37
#include <iprt/string.h>
 
38
#include "vector.h"
 
39
 
 
40
#ifdef VBOX_WITH_LINUX_COMPILER_H
 
41
# include <linux/compiler.h>
 
42
#endif
 
43
#include <linux/usbdevice_fs.h>
 
44
 
 
45
#include <sys/types.h>
 
46
#include <sys/stat.h>
 
47
#include <sys/vfs.h>
 
48
 
 
49
#include <dirent.h>
 
50
#include <dlfcn.h>
 
51
#include <errno.h>
 
52
#include <fcntl.h>
 
53
#include <stdio.h>
 
54
#include <string.h>
 
55
#include <unistd.h>
 
56
 
 
57
/*******************************************************************************
 
58
*   Structures and Typedefs                                                    *
 
59
*******************************************************************************/
 
60
/** Suffix translation. */
 
61
typedef struct USBSUFF
 
62
{
 
63
    char        szSuff[4];
 
64
    unsigned    cchSuff;
 
65
    unsigned    uMul;
 
66
    unsigned    uDiv;
 
67
} USBSUFF, *PUSBSUFF;
 
68
typedef const USBSUFF *PCUSBSUFF;
 
69
 
 
70
/** Structure describing a host USB device */
 
71
typedef struct USBDeviceInfo
 
72
{
 
73
    /** The device node of the device. */
 
74
    char *mDevice;
 
75
    /** The system identifier of the device.  Specific to the probing
 
76
     * method. */
 
77
    char *mSysfsPath;
 
78
    /** List of interfaces as sysfs paths */
 
79
    VECTOR_PTR(char *) mvecpszInterfaces;
 
80
} USBDeviceInfo;
 
81
 
 
82
/*******************************************************************************
 
83
*   Global Variables                                                           *
 
84
*******************************************************************************/
 
85
/**
 
86
 * Suffixes for the endpoint polling interval.
 
87
 */
 
88
static const USBSUFF s_aIntervalSuff[] =
 
89
{
 
90
    { "ms", 2,    1,       0 },
 
91
    { "us", 2,    1,    1000 },
 
92
    { "ns", 2,    1, 1000000 },
 
93
    { "s",  1, 1000,       0 },
 
94
    { "",   0,    0,       0 }  /* term */
 
95
};
 
96
 
 
97
/**
 
98
 * List of well-known USB device tree locations.
 
99
 */
 
100
static const USBDEVTREELOCATION s_aTreeLocations[] =
 
101
{
 
102
    { "/proc/bus/usb", false },
 
103
    { "/dev/bus/usb",  false },
 
104
    { "/dev/vboxusb",  true },
 
105
    { "/dev/bus/usb",  true },
 
106
};
 
107
 
 
108
 
 
109
/**
 
110
 * "reads" the number suffix. It's more like validating it and
 
111
 * skipping the necessary number of chars.
 
112
 */
 
113
static int usbReadSkipSuffix(char **ppszNext)
 
114
{
 
115
    char *pszNext = *ppszNext;
 
116
    if (!RT_C_IS_SPACE(*pszNext) && *pszNext)
 
117
    {
 
118
        /* skip unit */
 
119
        if (pszNext[0] == 'm' && pszNext[1] == 's')
 
120
            pszNext += 2;
 
121
        else if (pszNext[0] == 'm' && pszNext[1] == 'A')
 
122
            pszNext += 2;
 
123
 
 
124
        /* skip parenthesis */
 
125
        if (*pszNext == '(')
 
126
        {
 
127
            pszNext = strchr(pszNext, ')');
 
128
            if (!pszNext++)
 
129
            {
 
130
                AssertMsgFailed(("*ppszNext=%s\n", *ppszNext));
 
131
                return VERR_PARSE_ERROR;
 
132
            }
 
133
        }
 
134
 
 
135
        /* blank or end of the line. */
 
136
        if (!RT_C_IS_SPACE(*pszNext) && *pszNext)
 
137
        {
 
138
            AssertMsgFailed(("pszNext=%s\n", pszNext));
 
139
            return VERR_PARSE_ERROR;
 
140
        }
 
141
 
 
142
        /* it's ok. */
 
143
        *ppszNext = pszNext;
 
144
    }
 
145
 
 
146
    return VINF_SUCCESS;
 
147
}
 
148
 
 
149
 
 
150
/**
 
151
 * Reads a USB number returning the number and the position of the next character to parse.
 
152
 */
 
153
static int usbReadNum(const char *pszValue, unsigned uBase, uint32_t u32Mask, PCUSBSUFF paSuffs, void *pvNum, char **ppszNext)
 
154
{
 
155
    /*
 
156
     * Initialize return value to zero and strip leading spaces.
 
157
     */
 
158
    switch (u32Mask)
 
159
    {
 
160
        case 0xff: *(uint8_t *)pvNum = 0; break;
 
161
        case 0xffff: *(uint16_t *)pvNum = 0; break;
 
162
        case 0xffffffff: *(uint32_t *)pvNum = 0; break;
 
163
    }
 
164
    pszValue = RTStrStripL(pszValue);
 
165
    if (*pszValue)
 
166
    {
 
167
        /*
 
168
         * Try convert the number.
 
169
         */
 
170
        char *pszNext;
 
171
        uint32_t u32 = 0;
 
172
        RTStrToUInt32Ex(pszValue, &pszNext, uBase, &u32);
 
173
        if (pszNext == pszValue)
 
174
        {
 
175
            AssertMsgFailed(("pszValue=%d\n", pszValue));
 
176
            return VERR_NO_DATA;
 
177
        }
 
178
 
 
179
        /*
 
180
         * Check the range.
 
181
         */
 
182
        if (u32 & ~u32Mask)
 
183
        {
 
184
            AssertMsgFailed(("pszValue=%d u32=%#x lMask=%#x\n", pszValue, u32, u32Mask));
 
185
            return VERR_OUT_OF_RANGE;
 
186
        }
 
187
 
 
188
        /*
 
189
         * Validate and skip stuff following the number.
 
190
         */
 
191
        if (paSuffs)
 
192
        {
 
193
            if (!RT_C_IS_SPACE(*pszNext) && *pszNext)
 
194
            {
 
195
                for (PCUSBSUFF pSuff = paSuffs; pSuff->szSuff[0]; pSuff++)
 
196
                {
 
197
                    if (    !strncmp(pSuff->szSuff, pszNext, pSuff->cchSuff)
 
198
                        &&  (!pszNext[pSuff->cchSuff] || RT_C_IS_SPACE(pszNext[pSuff->cchSuff])))
 
199
                    {
 
200
                        if (pSuff->uDiv)
 
201
                            u32 /= pSuff->uDiv;
 
202
                        else
 
203
                            u32 *= pSuff->uMul;
 
204
                        break;
 
205
                    }
 
206
                }
 
207
            }
 
208
        }
 
209
        else
 
210
        {
 
211
            int rc = usbReadSkipSuffix(&pszNext);
 
212
            if (RT_FAILURE(rc))
 
213
                return rc;
 
214
        }
 
215
 
 
216
        *ppszNext = pszNext;
 
217
 
 
218
        /*
 
219
         * Set the value.
 
220
         */
 
221
        switch (u32Mask)
 
222
        {
 
223
            case 0xff: *(uint8_t *)pvNum = (uint8_t)u32; break;
 
224
            case 0xffff: *(uint16_t *)pvNum = (uint16_t)u32; break;
 
225
            case 0xffffffff: *(uint32_t *)pvNum = (uint32_t)u32; break;
 
226
        }
 
227
    }
 
228
    return VINF_SUCCESS;
 
229
}
 
230
 
 
231
 
 
232
static int usbRead8(const char *pszValue, unsigned uBase, uint8_t *pu8, char **ppszNext)
 
233
{
 
234
    return usbReadNum(pszValue, uBase, 0xff, NULL, pu8, ppszNext);
 
235
}
 
236
 
 
237
 
 
238
static int usbRead16(const char *pszValue, unsigned uBase, uint16_t *pu16, char **ppszNext)
 
239
{
 
240
    return usbReadNum(pszValue, uBase, 0xffff, NULL, pu16, ppszNext);
 
241
}
 
242
 
 
243
 
 
244
#if 0
 
245
static int usbRead16Suff(const char *pszValue, unsigned uBase, PCUSBSUFF paSuffs, uint16_t *pu16,  char **ppszNext)
 
246
{
 
247
    return usbReadNum(pszValue, uBase, 0xffff, paSuffs, pu16, ppszNext);
 
248
}
 
249
#endif
 
250
 
 
251
 
 
252
/**
 
253
 * Reads a USB BCD number returning the number and the position of the next character to parse.
 
254
 * The returned number contains the integer part in the high byte and the decimal part in the low byte.
 
255
 */
 
256
static int usbReadBCD(const char *pszValue, unsigned uBase, uint16_t *pu16, char **ppszNext)
 
257
{
 
258
    /*
 
259
     * Initialize return value to zero and strip leading spaces.
 
260
     */
 
261
    *pu16 = 0;
 
262
    pszValue = RTStrStripL(pszValue);
 
263
    if (*pszValue)
 
264
    {
 
265
        /*
 
266
         * Try convert the number.
 
267
         */
 
268
        /* integer part */
 
269
        char *pszNext;
 
270
        uint32_t u32Int = 0;
 
271
        RTStrToUInt32Ex(pszValue, &pszNext, uBase, &u32Int);
 
272
        if (pszNext == pszValue)
 
273
        {
 
274
            AssertMsgFailed(("pszValue=%s\n", pszValue));
 
275
            return VERR_NO_DATA;
 
276
        }
 
277
        if (u32Int & ~0xff)
 
278
        {
 
279
            AssertMsgFailed(("pszValue=%s u32Int=%#x (int)\n", pszValue, u32Int));
 
280
            return VERR_OUT_OF_RANGE;
 
281
        }
 
282
 
 
283
        /* skip dot and read decimal part */
 
284
        if (*pszNext != '.')
 
285
        {
 
286
            AssertMsgFailed(("pszValue=%s pszNext=%s (int)\n", pszValue, pszNext));
 
287
            return VERR_PARSE_ERROR;
 
288
        }
 
289
        char *pszValue2 = RTStrStripL(pszNext + 1);
 
290
        uint32_t u32Dec = 0;
 
291
        RTStrToUInt32Ex(pszValue2, &pszNext, uBase, &u32Dec);
 
292
        if (pszNext == pszValue)
 
293
        {
 
294
            AssertMsgFailed(("pszValue=%s\n", pszValue));
 
295
            return VERR_NO_DATA;
 
296
        }
 
297
        if (u32Dec & ~0xff)
 
298
        {
 
299
            AssertMsgFailed(("pszValue=%s u32Dec=%#x\n", pszValue, u32Dec));
 
300
            return VERR_OUT_OF_RANGE;
 
301
        }
 
302
 
 
303
        /*
 
304
         * Validate and skip stuff following the number.
 
305
         */
 
306
        int rc = usbReadSkipSuffix(&pszNext);
 
307
        if (RT_FAILURE(rc))
 
308
            return rc;
 
309
        *ppszNext = pszNext;
 
310
 
 
311
        /*
 
312
         * Set the value.
 
313
         */
 
314
        *pu16 = (uint16_t)u32Int << 8 | (uint16_t)u32Dec;
 
315
    }
 
316
    return VINF_SUCCESS;
 
317
}
 
318
 
 
319
 
 
320
/**
 
321
 * Reads a string, i.e. allocates memory and copies it.
 
322
 *
 
323
 * We assume that a string is Utf8 and if that's not the case
 
324
 * (pre-2.6.32-kernels used Latin-1, but so few devices return non-ASCII that
 
325
 * this usually goes unnoticed) then we mercilessly force it to be so.
 
326
 */
 
327
static int usbReadStr(const char *pszValue, const char **ppsz)
 
328
{
 
329
    char *psz;
 
330
 
 
331
    if (*ppsz)
 
332
        RTStrFree((char *)*ppsz);
 
333
    psz = RTStrDup(pszValue);
 
334
    if (psz)
 
335
    {
 
336
        RTStrPurgeEncoding(psz);
 
337
        *ppsz = psz;
 
338
        return VINF_SUCCESS;
 
339
    }
 
340
    return VERR_NO_MEMORY;
 
341
}
 
342
 
 
343
 
 
344
/**
 
345
 * Skips the current property.
 
346
 */
 
347
static char *usbReadSkip(char *pszValue)
 
348
{
 
349
    char *psz = strchr(pszValue, '=');
 
350
    if (psz)
 
351
        psz = strchr(psz + 1, '=');
 
352
    if (!psz)
 
353
        return strchr(pszValue,  '\0');
 
354
    while (psz > pszValue && !RT_C_IS_SPACE(psz[-1]))
 
355
        psz--;
 
356
    Assert(psz > pszValue);
 
357
    return psz;
 
358
}
 
359
 
 
360
 
 
361
/**
 
362
 * Determine the USB speed.
 
363
 */
 
364
static int usbReadSpeed(const char *pszValue, USBDEVICESPEED *pSpd, char **ppszNext)
 
365
{
 
366
    pszValue = RTStrStripL(pszValue);
 
367
    /* verified with Linux 2.4.0 ... Linux 2.6.25 */
 
368
    if (!strncmp(pszValue, "1.5", 3))
 
369
        *pSpd = USBDEVICESPEED_LOW;
 
370
    else if (!strncmp(pszValue, "12 ", 3))
 
371
        *pSpd = USBDEVICESPEED_FULL;
 
372
    else if (!strncmp(pszValue, "480", 3))
 
373
        *pSpd = USBDEVICESPEED_HIGH;
 
374
    else
 
375
        *pSpd = USBDEVICESPEED_UNKNOWN;
 
376
    while (pszValue[0] != '\0' && !RT_C_IS_SPACE(pszValue[0]))
 
377
        pszValue++;
 
378
    *ppszNext = (char *)pszValue;
 
379
    return VINF_SUCCESS;
 
380
}
 
381
 
 
382
 
 
383
/**
 
384
 * Compare a prefix and returns pointer to the char following it if it matches.
 
385
 */
 
386
static char *usbPrefix(char *psz, const char *pszPref, size_t cchPref)
 
387
{
 
388
    if (strncmp(psz, pszPref, cchPref))
 
389
        return NULL;
 
390
    return psz + cchPref;
 
391
}
 
392
 
 
393
 
 
394
/**
 
395
 * Does some extra checks to improve the detected device state.
 
396
 *
 
397
 * We cannot distinguish between USED_BY_HOST_CAPTURABLE and
 
398
 * USED_BY_GUEST, HELD_BY_PROXY all that well and it shouldn't be
 
399
 * necessary either.
 
400
 *
 
401
 * We will however, distinguish between the device we have permissions
 
402
 * to open and those we don't. This is necessary for two reasons.
 
403
 *
 
404
 * Firstly, because it's futile to even attempt opening a device which we
 
405
 * don't have access to, it only serves to confuse the user. (That said,
 
406
 * it might also be a bit confusing for the user to see that a USB device
 
407
 * is grayed out with no further explanation, and no way of generating an
 
408
 * error hinting at why this is the case.)
 
409
 *
 
410
 * Secondly and more importantly, we're racing against udevd with respect
 
411
 * to permissions and group settings on newly plugged devices. When we
 
412
 * detect a new device that we cannot access we will poll on it for a few
 
413
 * seconds to give udevd time to fix it. The polling is actually triggered
 
414
 * in the 'new device' case in the compare loop.
 
415
 *
 
416
 * The USBDEVICESTATE_USED_BY_HOST state is only used for this no-access
 
417
 * case, while USBDEVICESTATE_UNSUPPORTED is only used in the 'hub' case.
 
418
 * When it's neither of these, we set USBDEVICESTATE_UNUSED or
 
419
 * USBDEVICESTATE_USED_BY_HOST_CAPTURABLE depending on whether there is
 
420
 * a driver associated with any of the interfaces.
 
421
 *
 
422
 * All except the access check and a special idVendor == 0 precaution
 
423
 * is handled at parse time.
 
424
 *
 
425
 * @returns The adjusted state.
 
426
 * @param   pDevice     The device.
 
427
 */
 
428
static USBDEVICESTATE usbDeterminState(PCUSBDEVICE pDevice)
 
429
{
 
430
    /*
 
431
     * If it's already flagged as unsupported, there is nothing to do.
 
432
     */
 
433
    USBDEVICESTATE enmState = pDevice->enmState;
 
434
    if (enmState == USBDEVICESTATE_UNSUPPORTED)
 
435
        return USBDEVICESTATE_UNSUPPORTED;
 
436
 
 
437
    /*
 
438
     * Root hubs and similar doesn't have any vendor id, just
 
439
     * refuse these device.
 
440
     */
 
441
    if (!pDevice->idVendor)
 
442
        return USBDEVICESTATE_UNSUPPORTED;
 
443
 
 
444
    /*
 
445
     * Check if we've got access to the device, if we haven't flag
 
446
     * it as used-by-host.
 
447
     */
 
448
#ifndef VBOX_USB_WITH_SYSFS
 
449
    const char *pszAddress = pDevice->pszAddress;
 
450
#else
 
451
    if (pDevice->pszAddress == NULL)
 
452
        /* We can't do much with the device without an address. */
 
453
        return USBDEVICESTATE_UNSUPPORTED;
 
454
    const char *pszAddress = strstr(pDevice->pszAddress, "//device:");
 
455
    pszAddress = pszAddress != NULL
 
456
               ? pszAddress + sizeof("//device:") - 1
 
457
               : pDevice->pszAddress;
 
458
#endif
 
459
    if (    access(pszAddress, R_OK | W_OK) != 0
 
460
        &&  errno == EACCES)
 
461
        return USBDEVICESTATE_USED_BY_HOST;
 
462
 
 
463
#ifdef VBOX_USB_WITH_SYSFS
 
464
    /**
 
465
     * @todo Check that any other essential fields are present and mark as
 
466
     * invalid if not.  Particularly to catch the case where the device was
 
467
     * unplugged while we were reading in its properties.
 
468
     */
 
469
#endif
 
470
 
 
471
    return enmState;
 
472
}
 
473
 
 
474
 
 
475
/** Just a worker for USBProxyServiceLinux::getDevices that avoids some code duplication. */
 
476
static int addDeviceToChain(PUSBDEVICE pDev, PUSBDEVICE *ppFirst, PUSBDEVICE **pppNext, const char *pcszUsbfsRoot, bool testfs, int rc)
 
477
{
 
478
    /* usbDeterminState requires the address. */
 
479
    PUSBDEVICE pDevNew = (PUSBDEVICE)RTMemDup(pDev, sizeof(*pDev));
 
480
    if (pDevNew)
 
481
    {
 
482
        RTStrAPrintf((char **)&pDevNew->pszAddress, "%s/%03d/%03d", pcszUsbfsRoot, pDevNew->bBus, pDevNew->bDevNum);
 
483
        if (pDevNew->pszAddress)
 
484
        {
 
485
            pDevNew->enmState = usbDeterminState(pDevNew);
 
486
            if (pDevNew->enmState != USBDEVICESTATE_UNSUPPORTED || testfs)
 
487
            {
 
488
                if (*pppNext)
 
489
                    **pppNext = pDevNew;
 
490
                else
 
491
                    *ppFirst = pDevNew;
 
492
                *pppNext = &pDevNew->pNext;
 
493
            }
 
494
            else
 
495
                deviceFree(pDevNew);
 
496
        }
 
497
        else
 
498
        {
 
499
            deviceFree(pDevNew);
 
500
            rc = VERR_NO_MEMORY;
 
501
        }
 
502
    }
 
503
    else
 
504
    {
 
505
        rc = VERR_NO_MEMORY;
 
506
        deviceFreeMembers(pDev);
 
507
    }
 
508
 
 
509
    return rc;
 
510
}
 
511
 
 
512
 
 
513
static int openDevicesFile(const char *pcszUsbfsRoot, FILE **ppFile)
 
514
{
 
515
    char *pszPath;
 
516
    FILE *pFile;
 
517
    RTStrAPrintf(&pszPath, "%s/devices", pcszUsbfsRoot);
 
518
    if (!pszPath)
 
519
        return VERR_NO_MEMORY;
 
520
    pFile = fopen(pszPath, "r");
 
521
    RTStrFree(pszPath);
 
522
    if (!pFile)
 
523
        return RTErrConvertFromErrno(errno);
 
524
    *ppFile = pFile;
 
525
    return VINF_SUCCESS;
 
526
}
 
527
 
 
528
/**
 
529
 * USBProxyService::getDevices() implementation for usbfs.  The @a testfs flag
 
530
 * tells the function to return information about unsupported devices as well.
 
531
 * This is used as a sanity test to check that a devices file is really what
 
532
 * we expect.
 
533
 */
 
534
static PUSBDEVICE getDevicesFromUsbfs(const char *pcszUsbfsRoot, bool testfs)
 
535
{
 
536
    PUSBDEVICE pFirst = NULL;
 
537
    FILE *pFile = NULL;
 
538
    int rc;
 
539
    rc = openDevicesFile(pcszUsbfsRoot, &pFile);
 
540
    if (RT_SUCCESS(rc))
 
541
    {
 
542
        PUSBDEVICE     *ppNext = NULL;
 
543
        int             cHits = 0;
 
544
        char            szLine[1024];
 
545
        USBDEVICE       Dev;
 
546
        RT_ZERO(Dev);
 
547
        Dev.enmState = USBDEVICESTATE_UNUSED;
 
548
 
 
549
        /* Set close on exit and hope no one is racing us. */
 
550
        rc =   fcntl(fileno(pFile), F_SETFD, FD_CLOEXEC) >= 0
 
551
             ? VINF_SUCCESS
 
552
             : RTErrConvertFromErrno(errno);
 
553
        while (     RT_SUCCESS(rc)
 
554
               &&   fgets(szLine, sizeof(szLine), pFile))
 
555
        {
 
556
            char   *psz;
 
557
            char   *pszValue;
 
558
 
 
559
            /* validate and remove the trailing newline. */
 
560
            psz = strchr(szLine, '\0');
 
561
            if (psz[-1] != '\n' && !feof(pFile))
 
562
            {
 
563
                AssertMsgFailed(("Line too long. (cch=%d)\n", strlen(szLine)));
 
564
                continue;
 
565
            }
 
566
 
 
567
            /* strip */
 
568
            psz = RTStrStrip(szLine);
 
569
            if (!*psz)
 
570
                continue;
 
571
 
 
572
            /*
 
573
             * Interpret the line.
 
574
             * (Ordered by normal occurrence.)
 
575
             */
 
576
            char ch = psz[0];
 
577
            if (psz[1] != ':')
 
578
                continue;
 
579
            psz = RTStrStripL(psz + 3);
 
580
#define PREFIX(str) ( (pszValue = usbPrefix(psz, str, sizeof(str) - 1)) != NULL )
 
581
            switch (ch)
 
582
            {
 
583
                /*
 
584
                 * T:  Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd
 
585
                 * |   |      |      |       |       |      |        |       |__MaxChildren
 
586
                 * |   |      |      |       |       |      |        |__Device Speed in Mbps
 
587
                 * |   |      |      |       |       |      |__DeviceNumber
 
588
                 * |   |      |      |       |       |__Count of devices at this level
 
589
                 * |   |      |      |       |__Connector/Port on Parent for this device
 
590
                 * |   |      |      |__Parent DeviceNumber
 
591
                 * |   |      |__Level in topology for this bus
 
592
                 * |   |__Bus number
 
593
                 * |__Topology info tag
 
594
                 */
 
595
                case 'T':
 
596
                    /* add */
 
597
                    AssertMsg(cHits >= 3 || cHits == 0, ("cHits=%d\n", cHits));
 
598
                    if (cHits >= 3)
 
599
                        rc = addDeviceToChain(&Dev, &pFirst, &ppNext, pcszUsbfsRoot, testfs, rc);
 
600
                    else
 
601
                        deviceFreeMembers(&Dev);
 
602
 
 
603
                    /* Reset device state */
 
604
                    memset(&Dev, 0, sizeof (Dev));
 
605
                    Dev.enmState = USBDEVICESTATE_UNUSED;
 
606
                    cHits = 1;
 
607
 
 
608
                    /* parse the line. */
 
609
                    while (*psz && RT_SUCCESS(rc))
 
610
                    {
 
611
                        if (PREFIX("Bus="))
 
612
                            rc = usbRead8(pszValue, 10, &Dev.bBus, &psz);
 
613
                        else if (PREFIX("Port="))
 
614
                            rc = usbRead8(pszValue, 10, &Dev.bPort, &psz);
 
615
                        else if (PREFIX("Spd="))
 
616
                            rc = usbReadSpeed(pszValue, &Dev.enmSpeed, &psz);
 
617
                        else if (PREFIX("Dev#="))
 
618
                            rc = usbRead8(pszValue, 10, &Dev.bDevNum, &psz);
 
619
                        else
 
620
                            psz = usbReadSkip(psz);
 
621
                        psz = RTStrStripL(psz);
 
622
                    }
 
623
                    break;
 
624
 
 
625
                /*
 
626
                 * Bandwidth info:
 
627
                 * B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
 
628
                 * |   |                       |         |__Number of isochronous requests
 
629
                 * |   |                       |__Number of interrupt requests
 
630
                 * |   |__Total Bandwidth allocated to this bus
 
631
                 * |__Bandwidth info tag
 
632
                 */
 
633
                case 'B':
 
634
                    break;
 
635
 
 
636
                /*
 
637
                 * D:  Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
 
638
                 * |   |        |             |      |       |       |__NumberConfigurations
 
639
                 * |   |        |             |      |       |__MaxPacketSize of Default Endpoint
 
640
                 * |   |        |             |      |__DeviceProtocol
 
641
                 * |   |        |             |__DeviceSubClass
 
642
                 * |   |        |__DeviceClass
 
643
                 * |   |__Device USB version
 
644
                 * |__Device info tag #1
 
645
                 */
 
646
                case 'D':
 
647
                    while (*psz && RT_SUCCESS(rc))
 
648
                    {
 
649
                        if (PREFIX("Ver="))
 
650
                            rc = usbReadBCD(pszValue, 16, &Dev.bcdUSB, &psz);
 
651
                        else if (PREFIX("Cls="))
 
652
                        {
 
653
                            rc = usbRead8(pszValue, 16, &Dev.bDeviceClass, &psz);
 
654
                            if (RT_SUCCESS(rc) && Dev.bDeviceClass == 9 /* HUB */)
 
655
                                Dev.enmState = USBDEVICESTATE_UNSUPPORTED;
 
656
                        }
 
657
                        else if (PREFIX("Sub="))
 
658
                            rc = usbRead8(pszValue, 16, &Dev.bDeviceSubClass, &psz);
 
659
                        else if (PREFIX("Prot="))
 
660
                            rc = usbRead8(pszValue, 16, &Dev.bDeviceProtocol, &psz);
 
661
                        //else if (PREFIX("MxPS="))
 
662
                        //    rc = usbRead16(pszValue, 10, &Dev.wMaxPacketSize, &psz);
 
663
                        else if (PREFIX("#Cfgs="))
 
664
                            rc = usbRead8(pszValue, 10, &Dev.bNumConfigurations, &psz);
 
665
                        else
 
666
                            psz = usbReadSkip(psz);
 
667
                        psz = RTStrStripL(psz);
 
668
                    }
 
669
                    cHits++;
 
670
                    break;
 
671
 
 
672
                /*
 
673
                 * P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx
 
674
                 * |   |           |           |__Product revision number
 
675
                 * |   |           |__Product ID code
 
676
                 * |   |__Vendor ID code
 
677
                 * |__Device info tag #2
 
678
                 */
 
679
                case 'P':
 
680
                    while (*psz && RT_SUCCESS(rc))
 
681
                    {
 
682
                        if (PREFIX("Vendor="))
 
683
                            rc = usbRead16(pszValue, 16, &Dev.idVendor, &psz);
 
684
                        else if (PREFIX("ProdID="))
 
685
                            rc = usbRead16(pszValue, 16, &Dev.idProduct, &psz);
 
686
                        else if (PREFIX("Rev="))
 
687
                            rc = usbReadBCD(pszValue, 16, &Dev.bcdDevice, &psz);
 
688
                        else
 
689
                            psz = usbReadSkip(psz);
 
690
                        psz = RTStrStripL(psz);
 
691
                    }
 
692
                    cHits++;
 
693
                    break;
 
694
 
 
695
                /*
 
696
                 * String.
 
697
                 */
 
698
                case 'S':
 
699
                    if (PREFIX("Manufacturer="))
 
700
                        rc = usbReadStr(pszValue, &Dev.pszManufacturer);
 
701
                    else if (PREFIX("Product="))
 
702
                        rc = usbReadStr(pszValue, &Dev.pszProduct);
 
703
                    else if (PREFIX("SerialNumber="))
 
704
                    {
 
705
                        rc = usbReadStr(pszValue, &Dev.pszSerialNumber);
 
706
                        if (RT_SUCCESS(rc))
 
707
                            Dev.u64SerialHash = USBLibHashSerial(pszValue);
 
708
                    }
 
709
                    break;
 
710
 
 
711
                /*
 
712
                 * C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
 
713
                 * | | |       |       |      |__MaxPower in mA
 
714
                 * | | |       |       |__Attributes
 
715
                 * | | |       |__ConfiguratioNumber
 
716
                 * | | |__NumberOfInterfaces
 
717
                 * | |__ "*" indicates the active configuration (others are " ")
 
718
                 * |__Config info tag
 
719
                 */
 
720
                case 'C':
 
721
                    break;
 
722
 
 
723
                /*
 
724
                 * I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
 
725
                 * |   |      |      |       |             |      |       |__Driver name
 
726
                 * |   |      |      |       |             |      |          or "(none)"
 
727
                 * |   |      |      |       |             |      |__InterfaceProtocol
 
728
                 * |   |      |      |       |             |__InterfaceSubClass
 
729
                 * |   |      |      |       |__InterfaceClass
 
730
                 * |   |      |      |__NumberOfEndpoints
 
731
                 * |   |      |__AlternateSettingNumber
 
732
                 * |   |__InterfaceNumber
 
733
                 * |__Interface info tag
 
734
                 */
 
735
                case 'I':
 
736
                {
 
737
                    /* Check for thing we don't support.  */
 
738
                    while (*psz && RT_SUCCESS(rc))
 
739
                    {
 
740
                        if (PREFIX("Driver="))
 
741
                        {
 
742
                            const char *pszDriver = NULL;
 
743
                            rc = usbReadStr(pszValue, &pszDriver);
 
744
                            if (   !pszDriver
 
745
                                || !*pszDriver
 
746
                                || !strcmp(pszDriver, "(none)")
 
747
                                || !strcmp(pszDriver, "(no driver)"))
 
748
                                /* no driver */;
 
749
                            else if (!strcmp(pszDriver, "hub"))
 
750
                                Dev.enmState = USBDEVICESTATE_UNSUPPORTED;
 
751
                            else if (Dev.enmState == USBDEVICESTATE_UNUSED)
 
752
                                Dev.enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
 
753
                            RTStrFree((char *)pszDriver);
 
754
                            break; /* last attrib */
 
755
                        }
 
756
                        else if (PREFIX("Cls="))
 
757
                        {
 
758
                            uint8_t bInterfaceClass;
 
759
                            rc = usbRead8(pszValue, 16, &bInterfaceClass, &psz);
 
760
                            if (RT_SUCCESS(rc) && bInterfaceClass == 9 /* HUB */)
 
761
                                Dev.enmState = USBDEVICESTATE_UNSUPPORTED;
 
762
                        }
 
763
                        else
 
764
                            psz = usbReadSkip(psz);
 
765
                        psz = RTStrStripL(psz);
 
766
                    }
 
767
                    break;
 
768
                }
 
769
 
 
770
 
 
771
                /*
 
772
                 * E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
 
773
                 * |   |        |            |         |__Interval (max) between transfers
 
774
                 * |   |        |            |__EndpointMaxPacketSize
 
775
                 * |   |        |__Attributes(EndpointType)
 
776
                 * |   |__EndpointAddress(I=In,O=Out)
 
777
                 * |__Endpoint info tag
 
778
                 */
 
779
                case 'E':
 
780
                    break;
 
781
 
 
782
            }
 
783
#undef PREFIX
 
784
        } /* parse loop */
 
785
        fclose(pFile);
 
786
 
 
787
        /*
 
788
         * Add the current entry.
 
789
         */
 
790
        AssertMsg(cHits >= 3 || cHits == 0, ("cHits=%d\n", cHits));
 
791
        if (cHits >= 3)
 
792
            rc = addDeviceToChain(&Dev, &pFirst, &ppNext, pcszUsbfsRoot, testfs, rc);
 
793
 
 
794
        /*
 
795
         * Success?
 
796
         */
 
797
        if (RT_FAILURE(rc))
 
798
        {
 
799
            while (pFirst)
 
800
            {
 
801
                PUSBDEVICE pFree = pFirst;
 
802
                pFirst = pFirst->pNext;
 
803
                deviceFree(pFree);
 
804
            }
 
805
        }
 
806
    }
 
807
    if (RT_FAILURE(rc))
 
808
        LogFlow(("USBProxyServiceLinux::getDevices: rc=%Rrc\n", rc));
 
809
    return pFirst;
 
810
}
 
811
 
 
812
#ifdef VBOX_USB_WITH_SYSFS
 
813
 
 
814
static void USBDevInfoCleanup(USBDeviceInfo *pSelf)
 
815
{
 
816
    RTStrFree(pSelf->mDevice);
 
817
    RTStrFree(pSelf->mSysfsPath);
 
818
    pSelf->mDevice = pSelf->mSysfsPath = NULL;
 
819
    VEC_CLEANUP_PTR(&pSelf->mvecpszInterfaces);
 
820
}
 
821
 
 
822
static int USBDevInfoInit(USBDeviceInfo *pSelf, const char *aDevice,
 
823
                   const char *aSystemID)
 
824
{
 
825
    pSelf->mDevice = aDevice ? RTStrDup(aDevice) : NULL;
 
826
    pSelf->mSysfsPath = aSystemID ? RTStrDup(aSystemID) : NULL;
 
827
    VEC_INIT_PTR(&pSelf->mvecpszInterfaces, char *, RTStrFree);
 
828
    if ((aDevice && !pSelf->mDevice) || (aSystemID && ! pSelf->mSysfsPath))
 
829
    {
 
830
        USBDevInfoCleanup(pSelf);
 
831
        return 0;
 
832
    }
 
833
    return 1;
 
834
}
 
835
 
 
836
#define USBDEVICE_MAJOR 189
 
837
 
 
838
/** Deduce the bus that a USB device is plugged into from the device node
 
839
 * number.  See drivers/usb/core/hub.c:usb_new_device as of Linux 2.6.20. */
 
840
static unsigned usbBusFromDevNum(dev_t devNum)
 
841
{
 
842
    AssertReturn(devNum, 0);
 
843
    AssertReturn(major(devNum) == USBDEVICE_MAJOR, 0);
 
844
    return (minor(devNum) >> 7) + 1;
 
845
}
 
846
 
 
847
 
 
848
/** Deduce the device number of a USB device on the bus from the device node
 
849
 * number.  See drivers/usb/core/hub.c:usb_new_device as of Linux 2.6.20. */
 
850
static unsigned usbDeviceFromDevNum(dev_t devNum)
 
851
{
 
852
    AssertReturn(devNum, 0);
 
853
    AssertReturn(major(devNum) == USBDEVICE_MAJOR, 0);
 
854
    return (minor(devNum) & 127) + 1;
 
855
}
 
856
 
 
857
 
 
858
/**
 
859
 * If a file @a pcszNode from /sys/bus/usb/devices is a device rather than an
 
860
 * interface add an element for the device to @a pvecDevInfo.
 
861
 */
 
862
static int addIfDevice(const char *pcszDevicesRoot,
 
863
                       const char *pcszNode,
 
864
                       VECTOR_OBJ(USBDeviceInfo) *pvecDevInfo)
 
865
{
 
866
    const char *pcszFile = strrchr(pcszNode, '/');
 
867
    if (strchr(pcszFile, ':'))
 
868
        return VINF_SUCCESS;
 
869
    dev_t devnum = RTLinuxSysFsReadDevNumFile("%s/dev", pcszNode);
 
870
    /* Sanity test of our static helpers */
 
871
    Assert(usbBusFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 5);
 
872
    Assert(usbDeviceFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 6);
 
873
    if (!devnum)
 
874
        return VINF_SUCCESS;
 
875
    char szDevPath[RTPATH_MAX];
 
876
    ssize_t cchDevPath;
 
877
    cchDevPath = RTLinuxFindDevicePath(devnum, RTFS_TYPE_DEV_CHAR,
 
878
                                       szDevPath, sizeof(szDevPath),
 
879
                                       "%s/%.3d/%.3d",
 
880
                                       pcszDevicesRoot,
 
881
                                       usbBusFromDevNum(devnum),
 
882
                                       usbDeviceFromDevNum(devnum));
 
883
    if (cchDevPath < 0)
 
884
        return VINF_SUCCESS;
 
885
 
 
886
    USBDeviceInfo info;
 
887
    if (USBDevInfoInit(&info, szDevPath, pcszNode))
 
888
        if (RT_SUCCESS(VEC_PUSH_BACK_OBJ(pvecDevInfo, USBDeviceInfo,
 
889
                                         &info)))
 
890
            return VINF_SUCCESS;
 
891
    USBDevInfoCleanup(&info);
 
892
    return VERR_NO_MEMORY;
 
893
}
 
894
 
 
895
/** The logic for testing whether a sysfs address corresponds to an
 
896
 * interface of a device.  Both must be referenced by their canonical
 
897
 * sysfs paths.  This is not tested, as the test requires file-system
 
898
 * interaction. */
 
899
static bool muiIsAnInterfaceOf(const char *pcszIface, const char *pcszDev)
 
900
{
 
901
    size_t cchDev = strlen(pcszDev);
 
902
 
 
903
    AssertPtr(pcszIface);
 
904
    AssertPtr(pcszDev);
 
905
    Assert(pcszIface[0] == '/');
 
906
    Assert(pcszDev[0] == '/');
 
907
    Assert(pcszDev[cchDev - 1] != '/');
 
908
    /* If this passes, pcszIface is at least cchDev long */
 
909
    if (strncmp(pcszIface, pcszDev, cchDev))
 
910
        return false;
 
911
    /* If this passes, pcszIface is longer than cchDev */
 
912
    if (pcszIface[cchDev] != '/')
 
913
        return false;
 
914
    /* In sysfs an interface is an immediate subdirectory of the device */
 
915
    if (strchr(pcszIface + cchDev + 1, '/'))
 
916
        return false;
 
917
    /* And it always has a colon in its name */
 
918
    if (!strchr(pcszIface + cchDev + 1, ':'))
 
919
        return false;
 
920
    /* And hopefully we have now elimitated everything else */
 
921
    return true;
 
922
}
 
923
 
 
924
#ifdef DEBUG
 
925
# ifdef __cplusplus
 
926
/** Unit test the logic in muiIsAnInterfaceOf in debug builds. */
 
927
class testIsAnInterfaceOf
 
928
{
 
929
public:
 
930
    testIsAnInterfaceOf()
 
931
    {
 
932
        Assert(muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0",
 
933
               "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
 
934
        Assert(!muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-1",
 
935
               "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
 
936
        Assert(!muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/driver",
 
937
               "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
 
938
    }
 
939
};
 
940
static testIsAnInterfaceOf testIsAnInterfaceOfInst;
 
941
# endif /* __cplusplus */
 
942
#endif /* DEBUG */
 
943
 
 
944
/**
 
945
 * Tell whether a file in /sys/bus/usb/devices is an interface rather than a
 
946
 * device.  To be used with getDeviceInfoFromSysfs().
 
947
 */
 
948
static int addIfInterfaceOf(const char *pcszNode, USBDeviceInfo *pInfo)
 
949
{
 
950
    if (!muiIsAnInterfaceOf(pcszNode, pInfo->mSysfsPath))
 
951
        return VINF_SUCCESS;
 
952
    char *pszDup = (char *)RTStrDup(pcszNode);
 
953
    if (pszDup)
 
954
        if (RT_SUCCESS(VEC_PUSH_BACK_PTR(&pInfo->mvecpszInterfaces,
 
955
                                         char *, pszDup)))
 
956
            return VINF_SUCCESS;
 
957
    RTStrFree(pszDup);
 
958
    return VERR_NO_MEMORY;
 
959
}
 
960
 
 
961
/** Helper for readFilePaths().  Adds the entries from the open directory
 
962
 * @a pDir to the vector @a pvecpchDevs using either the full path or the
 
963
 * realpath() and skipping hidden files and files on which realpath() fails. */
 
964
static int readFilePathsFromDir(const char *pcszPath, DIR *pDir,
 
965
                                VECTOR_PTR(char *) *pvecpchDevs)
 
966
{
 
967
    struct dirent entry, *pResult;
 
968
    int err, rc;
 
969
 
 
970
    for (err = readdir_r(pDir, &entry, &pResult); pResult;
 
971
         err = readdir_r(pDir, &entry, &pResult))
 
972
    {
 
973
        char szPath[RTPATH_MAX + 1], szRealPath[RTPATH_MAX + 1], *pszPath;
 
974
        if (entry.d_name[0] == '.')
 
975
            continue;
 
976
        if (snprintf(szPath, sizeof(szPath), "%s/%s", pcszPath,
 
977
                     entry.d_name) < 0)
 
978
            return RTErrConvertFromErrno(errno);
 
979
        if (!realpath(szPath, szRealPath))
 
980
            return RTErrConvertFromErrno(errno);
 
981
        pszPath = RTStrDup(szRealPath);
 
982
        if (!pszPath)
 
983
            return VERR_NO_MEMORY;
 
984
        if (RT_FAILURE(rc = VEC_PUSH_BACK_PTR(pvecpchDevs, char *, pszPath)))
 
985
            return rc;
 
986
    }
 
987
    return RTErrConvertFromErrno(err);
 
988
}
 
989
 
 
990
/**
 
991
 * Dump the names of a directory's entries into a vector of char pointers.
 
992
 *
 
993
 * @returns zero on success or (positive) posix error value.
 
994
 * @param   pcszPath      the path to dump.
 
995
 * @param   pvecpchDevs   an empty vector of char pointers - must be cleaned up
 
996
 *                        by the caller even on failure.
 
997
 * @param   withRealPath  whether to canonicalise the filename with realpath
 
998
 */
 
999
static int readFilePaths(const char *pcszPath, VECTOR_PTR(char *) *pvecpchDevs)
 
1000
{
 
1001
    DIR *pDir;
 
1002
    int rc;
 
1003
 
 
1004
    AssertPtrReturn(pvecpchDevs, EINVAL);
 
1005
    AssertReturn(VEC_SIZE_PTR(pvecpchDevs) == 0, EINVAL);
 
1006
    AssertPtrReturn(pcszPath, EINVAL);
 
1007
 
 
1008
    pDir = opendir(pcszPath);
 
1009
    if (!pDir)
 
1010
        return RTErrConvertFromErrno(errno);
 
1011
    rc = readFilePathsFromDir(pcszPath, pDir, pvecpchDevs);
 
1012
    if (closedir(pDir) < 0 && RT_SUCCESS(rc))
 
1013
        rc = RTErrConvertFromErrno(errno);
 
1014
    return rc;
 
1015
}
 
1016
 
 
1017
/**
 
1018
 * Logic for USBSysfsEnumerateHostDevices.
 
1019
 * @param pvecDevInfo  vector of device information structures to add device
 
1020
 *                     information to
 
1021
 * @param pvecpchDevs  empty scratch vector which will be freed by the caller,
 
1022
 *                     to simplify exit logic
 
1023
 */
 
1024
static int doSysfsEnumerateHostDevices(const char *pcszDevicesRoot,
 
1025
                                       VECTOR_OBJ(USBDeviceInfo) *pvecDevInfo,
 
1026
                                       VECTOR_PTR(char *) *pvecpchDevs)
 
1027
{
 
1028
    char **ppszEntry;
 
1029
    USBDeviceInfo *pInfo;
 
1030
    int rc;
 
1031
 
 
1032
    AssertPtrReturn(pvecDevInfo, VERR_INVALID_POINTER);
 
1033
    LogFlowFunc (("pvecDevInfo=%p\n", pvecDevInfo));
 
1034
 
 
1035
    rc = readFilePaths("/sys/bus/usb/devices", pvecpchDevs);
 
1036
    if (RT_FAILURE(rc))
 
1037
        return rc;
 
1038
    VEC_FOR_EACH(pvecpchDevs, char *, ppszEntry)
 
1039
        if (RT_FAILURE(rc = addIfDevice(pcszDevicesRoot, *ppszEntry,
 
1040
                                        pvecDevInfo)))
 
1041
            return rc;
 
1042
    VEC_FOR_EACH(pvecDevInfo, USBDeviceInfo, pInfo)
 
1043
        VEC_FOR_EACH(pvecpchDevs, char *, ppszEntry)
 
1044
            if (RT_FAILURE(rc = addIfInterfaceOf(*ppszEntry, pInfo)))
 
1045
                return rc;
 
1046
    return VINF_SUCCESS;
 
1047
}
 
1048
 
 
1049
static int USBSysfsEnumerateHostDevices(const char *pcszDevicesRoot,
 
1050
                                        VECTOR_OBJ(USBDeviceInfo) *pvecDevInfo)
 
1051
{
 
1052
    VECTOR_PTR(char *) vecpchDevs;
 
1053
    int rc = VERR_NOT_IMPLEMENTED;
 
1054
 
 
1055
    AssertReturn(VEC_SIZE_OBJ(pvecDevInfo) == 0, VERR_INVALID_PARAMETER);
 
1056
    LogFlowFunc(("entered\n"));
 
1057
    VEC_INIT_PTR(&vecpchDevs, char *, RTStrFree);
 
1058
    rc = doSysfsEnumerateHostDevices(pcszDevicesRoot, pvecDevInfo,
 
1059
                                     &vecpchDevs);
 
1060
    VEC_CLEANUP_PTR(&vecpchDevs);
 
1061
    LogFlowFunc(("rc=%Rrc\n", rc));
 
1062
    return rc;
 
1063
}
 
1064
 
 
1065
/**
 
1066
 * Helper function for extracting the port number on the parent device from
 
1067
 * the sysfs path value.
 
1068
 *
 
1069
 * The sysfs path is a chain of elements separated by forward slashes, and for
 
1070
 * USB devices, the last element in the chain takes the form
 
1071
 *   <port>-<port>.[...].<port>[:<config>.<interface>]
 
1072
 * where the first <port> is the port number on the root hub, and the following
 
1073
 * (optional) ones are the port numbers on any other hubs between the device
 
1074
 * and the root hub.  The last part (:<config.interface>) is only present for
 
1075
 * interfaces, not for devices.  This API should only be called for devices.
 
1076
 * For compatibility with usbfs, which enumerates from zero up, we subtract one
 
1077
 * from the port number.
 
1078
 *
 
1079
 * For root hubs, the last element in the chain takes the form
 
1080
 *   usb<hub number>
 
1081
 * and usbfs always returns port number zero.
 
1082
 *
 
1083
 * @returns VBox status. pu8Port is set on success.
 
1084
 * @param   pszPath     The sysfs path to parse.
 
1085
 * @param   pu8Port     Where to store the port number.
 
1086
 */
 
1087
static int usbGetPortFromSysfsPath(const char *pszPath, uint8_t *pu8Port)
 
1088
{
 
1089
    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
 
1090
    AssertPtrReturn(pu8Port, VERR_INVALID_POINTER);
 
1091
 
 
1092
    /*
 
1093
     * This should not be possible until we get PCs with USB as their primary bus.
 
1094
     * Note: We don't assert this, as we don't expect the caller to validate the
 
1095
     *       sysfs path.
 
1096
     */
 
1097
    const char *pszLastComp = strrchr(pszPath, '/');
 
1098
    if (!pszLastComp)
 
1099
    {
 
1100
        Log(("usbGetPortFromSysfsPath(%s): failed [1]\n", pszPath));
 
1101
        return VERR_INVALID_PARAMETER;
 
1102
    }
 
1103
    pszLastComp++; /* skip the slash */
 
1104
 
 
1105
    /*
 
1106
     * This API should not be called for interfaces, so the last component
 
1107
     * of the path should not contain a colon.  We *do* assert this, as it
 
1108
     * might indicate a caller bug.
 
1109
     */
 
1110
    AssertMsgReturn(strchr(pszLastComp, ':') == NULL, ("%s\n", pszPath), VERR_INVALID_PARAMETER);
 
1111
 
 
1112
    /*
 
1113
     * Look for the start of the last number.
 
1114
     */
 
1115
    const char *pchDash = strrchr(pszLastComp, '-');
 
1116
    const char *pchDot  = strrchr(pszLastComp, '.');
 
1117
    if (!pchDash && !pchDot)
 
1118
    {
 
1119
        /* No -/. so it must be a root hub. Check that it's usb<something>. */
 
1120
        if (strncmp(pszLastComp, "usb", sizeof("usb") - 1) != 0)
 
1121
        {
 
1122
            Log(("usbGetPortFromSysfsPath(%s): failed [2]\n", pszPath));
 
1123
            return VERR_INVALID_PARAMETER;
 
1124
        }
 
1125
        return VERR_NOT_SUPPORTED;
 
1126
    }
 
1127
    else
 
1128
    {
 
1129
        const char *pszLastPort = pchDot != NULL
 
1130
                                ? pchDot  + 1
 
1131
                                : pchDash + 1;
 
1132
        int rc = RTStrToUInt8Full(pszLastPort, 10, pu8Port);
 
1133
        if (rc != VINF_SUCCESS)
 
1134
        {
 
1135
            Log(("usbGetPortFromSysfsPath(%s): failed [3], rc=%Rrc\n", pszPath, rc));
 
1136
            return VERR_INVALID_PARAMETER;
 
1137
        }
 
1138
        if (*pu8Port == 0)
 
1139
        {
 
1140
            Log(("usbGetPortFromSysfsPath(%s): failed [4]\n", pszPath));
 
1141
            return VERR_INVALID_PARAMETER;
 
1142
        }
 
1143
 
 
1144
        /* usbfs compatibility, 0-based port number. */
 
1145
        *pu8Port -= 1;
 
1146
    }
 
1147
    return VINF_SUCCESS;
 
1148
}
 
1149
 
 
1150
 
 
1151
/**
 
1152
 * Dumps a USBDEVICE structure to the log using LogLevel 3.
 
1153
 * @param   pDev        The structure to log.
 
1154
 * @todo    This is really common code.
 
1155
 */
 
1156
DECLINLINE(void) usbLogDevice(PUSBDEVICE pDev)
 
1157
{
 
1158
    NOREF(pDev);
 
1159
 
 
1160
    Log3(("USB device:\n"));
 
1161
    Log3(("Product: %s (%x)\n", pDev->pszProduct, pDev->idProduct));
 
1162
    Log3(("Manufacturer: %s (Vendor ID %x)\n", pDev->pszManufacturer, pDev->idVendor));
 
1163
    Log3(("Serial number: %s (%llx)\n", pDev->pszSerialNumber, pDev->u64SerialHash));
 
1164
    Log3(("Device revision: %d\n", pDev->bcdDevice));
 
1165
    Log3(("Device class: %x\n", pDev->bDeviceClass));
 
1166
    Log3(("Device subclass: %x\n", pDev->bDeviceSubClass));
 
1167
    Log3(("Device protocol: %x\n", pDev->bDeviceProtocol));
 
1168
    Log3(("USB version number: %d\n", pDev->bcdUSB));
 
1169
    Log3(("Device speed: %s\n",
 
1170
            pDev->enmSpeed == USBDEVICESPEED_UNKNOWN  ? "unknown"
 
1171
          : pDev->enmSpeed == USBDEVICESPEED_LOW      ? "1.5 MBit/s"
 
1172
          : pDev->enmSpeed == USBDEVICESPEED_FULL     ? "12 MBit/s"
 
1173
          : pDev->enmSpeed == USBDEVICESPEED_HIGH     ? "480 MBit/s"
 
1174
          : pDev->enmSpeed == USBDEVICESPEED_VARIABLE ? "variable"
 
1175
          :                                             "invalid"));
 
1176
    Log3(("Number of configurations: %d\n", pDev->bNumConfigurations));
 
1177
    Log3(("Bus number: %d\n", pDev->bBus));
 
1178
    Log3(("Port number: %d\n", pDev->bPort));
 
1179
    Log3(("Device number: %d\n", pDev->bDevNum));
 
1180
    Log3(("Device state: %s\n",
 
1181
            pDev->enmState == USBDEVICESTATE_UNSUPPORTED   ? "unsupported"
 
1182
          : pDev->enmState == USBDEVICESTATE_USED_BY_HOST  ? "in use by host"
 
1183
          : pDev->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE ? "in use by host, possibly capturable"
 
1184
          : pDev->enmState == USBDEVICESTATE_UNUSED        ? "not in use"
 
1185
          : pDev->enmState == USBDEVICESTATE_HELD_BY_PROXY ? "held by proxy"
 
1186
          : pDev->enmState == USBDEVICESTATE_USED_BY_GUEST ? "used by guest"
 
1187
          :                                                  "invalid"));
 
1188
    Log3(("OS device address: %s\n", pDev->pszAddress));
 
1189
}
 
1190
 
 
1191
/**
 
1192
 * In contrast to usbReadBCD() this function can handle BCD values without
 
1193
 * a decimal separator. This is necessary for parsing bcdDevice.
 
1194
 * @param   pszBuf      Pointer to the string buffer.
 
1195
 * @param   pu15        Pointer to the return value.
 
1196
 * @returns IPRT status code.
 
1197
 */
 
1198
static int convertSysfsStrToBCD(const char *pszBuf, uint16_t *pu16)
 
1199
{
 
1200
    char *pszNext;
 
1201
    int32_t i32;
 
1202
 
 
1203
    pszBuf = RTStrStripL(pszBuf);
 
1204
    int rc = RTStrToInt32Ex(pszBuf, &pszNext, 16, &i32);
 
1205
    if (   RT_FAILURE(rc)
 
1206
        || rc == VWRN_NUMBER_TOO_BIG
 
1207
        || i32 < 0)
 
1208
        return VERR_NUMBER_TOO_BIG;
 
1209
    if (*pszNext == '.')
 
1210
    {
 
1211
        if (i32 > 255)
 
1212
            return VERR_NUMBER_TOO_BIG;
 
1213
        int32_t i32Lo;
 
1214
        rc = RTStrToInt32Ex(pszNext+1, &pszNext, 16, &i32Lo);
 
1215
        if (   RT_FAILURE(rc)
 
1216
            || rc == VWRN_NUMBER_TOO_BIG
 
1217
            || i32Lo > 255
 
1218
            || i32Lo < 0)
 
1219
            return VERR_NUMBER_TOO_BIG;
 
1220
        i32 = (i32 << 8) | i32Lo;
 
1221
    }
 
1222
    if (   i32 > 65535
 
1223
        || (*pszNext != '\0' && *pszNext != ' '))
 
1224
        return VERR_NUMBER_TOO_BIG;
 
1225
 
 
1226
    *pu16 = (uint16_t)i32;
 
1227
    return VINF_SUCCESS;
 
1228
}
 
1229
 
 
1230
#endif  /* VBOX_USB_WITH_SYSFS */
 
1231
 
 
1232
static void fillInDeviceFromSysfs(USBDEVICE *Dev, USBDeviceInfo *pInfo)
 
1233
{
 
1234
    int rc;
 
1235
    const char *pszSysfsPath = pInfo->mSysfsPath;
 
1236
 
 
1237
    /* Fill in the simple fields */
 
1238
    Dev->enmState           = USBDEVICESTATE_UNUSED;
 
1239
    Dev->bBus               = RTLinuxSysFsReadIntFile(10, "%s/busnum", pszSysfsPath);
 
1240
    Dev->bDeviceClass       = RTLinuxSysFsReadIntFile(16, "%s/bDeviceClass", pszSysfsPath);
 
1241
    Dev->bDeviceSubClass    = RTLinuxSysFsReadIntFile(16, "%s/bDeviceSubClass", pszSysfsPath);
 
1242
    Dev->bDeviceProtocol    = RTLinuxSysFsReadIntFile(16, "%s/bDeviceProtocol", pszSysfsPath);
 
1243
    Dev->bNumConfigurations = RTLinuxSysFsReadIntFile(10, "%s/bNumConfigurations", pszSysfsPath);
 
1244
    Dev->idVendor           = RTLinuxSysFsReadIntFile(16, "%s/idVendor", pszSysfsPath);
 
1245
    Dev->idProduct          = RTLinuxSysFsReadIntFile(16, "%s/idProduct", pszSysfsPath);
 
1246
    Dev->bDevNum            = RTLinuxSysFsReadIntFile(10, "%s/devnum", pszSysfsPath);
 
1247
 
 
1248
    /* Now deal with the non-numeric bits. */
 
1249
    char szBuf[1024];  /* Should be larger than anything a sane device
 
1250
                        * will need, and insane devices can be unsupported
 
1251
                        * until further notice. */
 
1252
    ssize_t cchRead;
 
1253
 
 
1254
    /* For simplicity, we just do strcmps on the next one. */
 
1255
    cchRead = RTLinuxSysFsReadStrFile(szBuf, sizeof(szBuf), "%s/speed",
 
1256
                                      pszSysfsPath);
 
1257
    if (cchRead <= 0 || (size_t) cchRead == sizeof(szBuf))
 
1258
        Dev->enmState = USBDEVICESTATE_UNSUPPORTED;
 
1259
    else
 
1260
        Dev->enmSpeed =   !strcmp(szBuf, "1.5") ? USBDEVICESPEED_LOW
 
1261
                        : !strcmp(szBuf, "12")  ? USBDEVICESPEED_FULL
 
1262
                        : !strcmp(szBuf, "480") ? USBDEVICESPEED_HIGH
 
1263
                        : USBDEVICESPEED_UNKNOWN;
 
1264
 
 
1265
    cchRead = RTLinuxSysFsReadStrFile(szBuf, sizeof(szBuf), "%s/version",
 
1266
                                      pszSysfsPath);
 
1267
    if (cchRead <= 0 || (size_t) cchRead == sizeof(szBuf))
 
1268
        Dev->enmState = USBDEVICESTATE_UNSUPPORTED;
 
1269
    else
 
1270
    {
 
1271
        rc = convertSysfsStrToBCD(szBuf, &Dev->bcdUSB);
 
1272
        if (RT_FAILURE(rc))
 
1273
        {
 
1274
            Dev->enmState = USBDEVICESTATE_UNSUPPORTED;
 
1275
            Dev->bcdUSB = (uint16_t)-1;
 
1276
        }
 
1277
    }
 
1278
 
 
1279
    cchRead = RTLinuxSysFsReadStrFile(szBuf, sizeof(szBuf), "%s/bcdDevice",
 
1280
                                      pszSysfsPath);
 
1281
    if (cchRead <= 0 || (size_t) cchRead == sizeof(szBuf))
 
1282
        Dev->bcdDevice = (uint16_t)-1;
 
1283
    else
 
1284
    {
 
1285
        rc = convertSysfsStrToBCD(szBuf, &Dev->bcdDevice);
 
1286
        if (RT_FAILURE(rc))
 
1287
            Dev->bcdDevice = (uint16_t)-1;
 
1288
    }
 
1289
 
 
1290
    /* Now do things that need string duplication */
 
1291
    cchRead = RTLinuxSysFsReadStrFile(szBuf, sizeof(szBuf), "%s/product",
 
1292
                                      pszSysfsPath);
 
1293
    if (cchRead > 0 && (size_t) cchRead < sizeof(szBuf))
 
1294
    {
 
1295
        RTStrPurgeEncoding(szBuf);
 
1296
        Dev->pszProduct = RTStrDup(szBuf);
 
1297
    }
 
1298
 
 
1299
    cchRead = RTLinuxSysFsReadStrFile(szBuf, sizeof(szBuf), "%s/serial",
 
1300
                                      pszSysfsPath);
 
1301
    if (cchRead > 0 && (size_t) cchRead < sizeof(szBuf))
 
1302
    {
 
1303
        RTStrPurgeEncoding(szBuf);
 
1304
        Dev->pszSerialNumber = RTStrDup(szBuf);
 
1305
        Dev->u64SerialHash = USBLibHashSerial(szBuf);
 
1306
    }
 
1307
 
 
1308
    cchRead = RTLinuxSysFsReadStrFile(szBuf, sizeof(szBuf), "%s/manufacturer",
 
1309
                                      pszSysfsPath);
 
1310
    if (cchRead > 0 && (size_t) cchRead < sizeof(szBuf))
 
1311
    {
 
1312
        RTStrPurgeEncoding(szBuf);
 
1313
        Dev->pszManufacturer = RTStrDup(szBuf);
 
1314
    }
 
1315
 
 
1316
    /* Work out the port number */
 
1317
    if (RT_FAILURE(usbGetPortFromSysfsPath(pszSysfsPath, &Dev->bPort)))
 
1318
        Dev->enmState = USBDEVICESTATE_UNSUPPORTED;
 
1319
 
 
1320
    /* Check the interfaces to see if we can support the device. */
 
1321
    char **ppszIf;
 
1322
    VEC_FOR_EACH(&pInfo->mvecpszInterfaces, char *, ppszIf)
 
1323
    {
 
1324
        ssize_t cb = RTLinuxSysFsGetLinkDest(szBuf, sizeof(szBuf), "%s/driver",
 
1325
                                             *ppszIf);
 
1326
        if (cb > 0 && Dev->enmState != USBDEVICESTATE_UNSUPPORTED)
 
1327
            Dev->enmState = (strcmp(szBuf, "hub") == 0)
 
1328
                          ? USBDEVICESTATE_UNSUPPORTED
 
1329
                          : USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
 
1330
        if (RTLinuxSysFsReadIntFile(16, "%s/bInterfaceClass",
 
1331
                                    *ppszIf) == 9 /* hub */)
 
1332
            Dev->enmState = USBDEVICESTATE_UNSUPPORTED;
 
1333
    }
 
1334
 
 
1335
    /* We use a double slash as a separator in the pszAddress field.  This is
 
1336
     * alright as the two paths can't contain a slash due to the way we build
 
1337
     * them. */
 
1338
    char *pszAddress = NULL;
 
1339
    RTStrAPrintf(&pszAddress, "sysfs:%s//device:%s", pszSysfsPath,
 
1340
                 pInfo->mDevice);
 
1341
    Dev->pszAddress = pszAddress;
 
1342
 
 
1343
    /* Work out from the data collected whether we can support this device. */
 
1344
    Dev->enmState = usbDeterminState(Dev);
 
1345
    usbLogDevice(Dev);
 
1346
}
 
1347
 
 
1348
/**
 
1349
 * USBProxyService::getDevices() implementation for sysfs.
 
1350
 */
 
1351
static PUSBDEVICE getDevicesFromSysfs(const char *pcszDevicesRoot, bool testfs)
 
1352
{
 
1353
#ifdef VBOX_USB_WITH_SYSFS
 
1354
    /* Add each of the devices found to the chain. */
 
1355
    PUSBDEVICE pFirst = NULL;
 
1356
    PUSBDEVICE pLast  = NULL;
 
1357
    VECTOR_OBJ(USBDeviceInfo) vecDevInfo;
 
1358
    USBDeviceInfo *pInfo;
 
1359
    int rc;
 
1360
 
 
1361
    VEC_INIT_OBJ(&vecDevInfo, USBDeviceInfo, USBDevInfoCleanup);
 
1362
    rc = USBSysfsEnumerateHostDevices(pcszDevicesRoot, &vecDevInfo);
 
1363
    if (RT_FAILURE(rc))
 
1364
        return NULL;
 
1365
    VEC_FOR_EACH(&vecDevInfo, USBDeviceInfo, pInfo)
 
1366
    {
 
1367
        USBDEVICE *Dev = (USBDEVICE *)RTMemAllocZ(sizeof(USBDEVICE));
 
1368
        if (!Dev)
 
1369
            rc = VERR_NO_MEMORY;
 
1370
        if (RT_SUCCESS(rc))
 
1371
        {
 
1372
            fillInDeviceFromSysfs(Dev, pInfo);
 
1373
        }
 
1374
        if (   RT_SUCCESS(rc)
 
1375
            && (   Dev->enmState != USBDEVICESTATE_UNSUPPORTED
 
1376
                || testfs)
 
1377
            && Dev->pszAddress != NULL
 
1378
           )
 
1379
        {
 
1380
            if (pLast != NULL)
 
1381
            {
 
1382
                pLast->pNext = Dev;
 
1383
                pLast = pLast->pNext;
 
1384
            }
 
1385
            else
 
1386
                pFirst = pLast = Dev;
 
1387
        }
 
1388
        else
 
1389
            deviceFree(Dev);
 
1390
        if (RT_FAILURE(rc))
 
1391
            break;
 
1392
    }
 
1393
    if (RT_FAILURE(rc))
 
1394
        deviceListFree(&pFirst);
 
1395
 
 
1396
    VEC_CLEANUP_OBJ(&vecDevInfo);
 
1397
    return pFirst;
 
1398
#else  /* !VBOX_USB_WITH_SYSFS */
 
1399
    return NULL;
 
1400
#endif  /* !VBOX_USB_WITH_SYSFS */
 
1401
}
 
1402
 
 
1403
/** Is inotify available and working on this system?  This is a requirement
 
1404
 * for using USB with sysfs */
 
1405
/** @todo test the "inotify in glibc but not in the kernel" case. */
 
1406
static bool inotifyAvailable(void)
 
1407
{
 
1408
    int (*inotify_init)(void);
 
1409
 
 
1410
    *(void **)(&inotify_init) = dlsym(RTLD_DEFAULT, "inotify_init");
 
1411
    if (!inotify_init)
 
1412
        return false;
 
1413
    int fd = inotify_init();
 
1414
    if (fd == -1)
 
1415
        return false;
 
1416
    close(fd);
 
1417
    return true;
 
1418
}
 
1419
 
 
1420
PCUSBDEVTREELOCATION USBProxyLinuxGetDeviceRoot(bool fPreferSysfs)
 
1421
{
 
1422
    PCUSBDEVTREELOCATION pcBestUsbfs = NULL;
 
1423
    PCUSBDEVTREELOCATION pcBestSysfs = NULL;
 
1424
 
 
1425
    bool fHaveInotify = inotifyAvailable();
 
1426
    for (unsigned i = 0; i < RT_ELEMENTS(s_aTreeLocations); ++i)
 
1427
        if (!s_aTreeLocations[i].fUseSysfs)
 
1428
        {
 
1429
            if (!pcBestUsbfs)
 
1430
            {
 
1431
                PUSBDEVICE pDevices;
 
1432
 
 
1433
                pDevices = getDevicesFromUsbfs(s_aTreeLocations[i].szDevicesRoot,
 
1434
                                               true);
 
1435
                if (pDevices)
 
1436
                {
 
1437
                    pcBestUsbfs = &s_aTreeLocations[i];
 
1438
                    deviceListFree(&pDevices);
 
1439
                }
 
1440
            }
 
1441
        }
 
1442
        else
 
1443
        {
 
1444
            if (   fHaveInotify
 
1445
                && !pcBestSysfs
 
1446
                && RTPathExists(s_aTreeLocations[i].szDevicesRoot))
 
1447
            {
 
1448
                PUSBDEVICE pDevices;
 
1449
 
 
1450
                pDevices = getDevicesFromSysfs(s_aTreeLocations[i].szDevicesRoot,
 
1451
                                               true);
 
1452
                if (pDevices)
 
1453
                {
 
1454
                    pcBestSysfs = &s_aTreeLocations[i];
 
1455
                    deviceListFree(&pDevices);
 
1456
                }
 
1457
            }
 
1458
        }
 
1459
    if (pcBestUsbfs && !fPreferSysfs)
 
1460
        return pcBestUsbfs;
 
1461
    return pcBestSysfs;
 
1462
}
 
1463
 
 
1464
 
 
1465
PUSBDEVICE USBProxyLinuxGetDevices(const char *pcszDevicesRoot,
 
1466
                                   bool fUseSysfs)
 
1467
{
 
1468
    if (!fUseSysfs)
 
1469
        return getDevicesFromUsbfs(pcszDevicesRoot, false);
 
1470
    else
 
1471
        return getDevicesFromSysfs(pcszDevicesRoot, false);
 
1472
}