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

« back to all changes in this revision

Viewing changes to src/VBox/Main/freebsd/HostHardwareFreeBSD.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2009-12-18 16:44:29 UTC
  • mfrom: (0.3.3 upstream) (0.4.6 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091218164429-jd34ccexpv5na11a
Tags: 3.1.2-dfsg-1ubuntu1
* Merge from Debian unstable (LP: #498219), remaining changes:
  - Disable update action
    - debian/patches/u01-disable-update-action.dpatch
  - VirtualBox should go in Accessories, not in System tools (LP: #288590)
    - debian/virtualbox-ose-qt.files/virtualbox-ose.desktop
  - Add Apport hook
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Add Launchpad integration
    - debian/control
    - debian/lpi-bug.xpm
    - debian/patches/u02-lp-integration.dpatch
* Fixes the following bugs:
  - Kernel module fails to build with Linux >= 2.6.32 (LP: #474625)
  - X.Org drivers need to be rebuilt against X-Server 1.7 (LP: #495935)
  - The *-source packages try to build the kernel modules even though the
    kernel headers aren't available (LP: #473334)
* Replace *-source packages with transitional packages for *-dkms.
* Adapt u01-disable-update-action.dpatch and u02-lp-integration.dpatch for
  new upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: HostHardwareFreeBSD.cpp $ */
 
2
/** @file
 
3
 * Classes for handling hardware detection under FreeBSD.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2008 Sun Microsystems, Inc.
 
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
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 
18
 * Clara, CA 95054 USA or visit http://www.sun.com if you need
 
19
 * additional information or have any questions.
 
20
 */
 
21
 
 
22
#define LOG_GROUP LOG_GROUP_MAIN
 
23
 
 
24
/*******************************************************************************
 
25
*   Header Files                                                               *
 
26
*******************************************************************************/
 
27
 
 
28
#include <HostHardwareLinux.h>
 
29
 
 
30
#include <VBox/log.h>
 
31
 
 
32
#include <iprt/dir.h>
 
33
#include <iprt/env.h>
 
34
#include <iprt/file.h>
 
35
#include <iprt/mem.h>
 
36
#include <iprt/param.h>
 
37
#include <iprt/path.h>
 
38
#include <iprt/thread.h>  /* for RTThreadSleep() */
 
39
#include <iprt/string.h>
 
40
 
 
41
#ifdef RT_OS_FREEBSD
 
42
# include <sys/types.h>
 
43
# include <sys/stat.h>
 
44
# include <unistd.h>
 
45
# include <sys/ioctl.h>
 
46
# include <fcntl.h>
 
47
# include <cam/cam.h>
 
48
# include <cam/cam_ccb.h>
 
49
# include <cam/scsi/scsi_pass.h>
 
50
#endif /* RT_OS_FREEBSD */
 
51
#include <vector>
 
52
 
 
53
/******************************************************************************
 
54
*   Typedefs and Defines                                                      *
 
55
******************************************************************************/
 
56
 
 
57
static int getDriveInfoFromEnv(const char *pcszVar, DriveInfoList *pList,
 
58
                               bool isDVD, bool *pfSuccess);
 
59
static int getDVDInfoFromCAM(DriveInfoList *pList, bool *pfSuccess);
 
60
 
 
61
/** Find the length of a string, ignoring trailing non-ascii or control
 
62
 * characters */
 
63
static size_t strLenStripped(const char *pcsz)
 
64
{
 
65
    size_t cch = 0;
 
66
    for (size_t i = 0; pcsz[i] != '\0'; ++i)
 
67
        if (pcsz[i] > 32 && pcsz[i] < 127)
 
68
            cch = i;
 
69
    return cch + 1;
 
70
}
 
71
 
 
72
static void strLenRemoveTrailingWhiteSpace(char *psz, size_t cchStr)
 
73
{
 
74
    while (   (cchStr > 0)
 
75
           && (psz[cchStr -1] == ' '))
 
76
        psz[--cchStr] = '\0';
 
77
}
 
78
 
 
79
/**
 
80
 * Initialise the device description for a DVD drive based on
 
81
 * vendor and model name strings.
 
82
 * @param pcszVendor  the vendor ID string
 
83
 * @param pcszModel   the product ID string
 
84
 * @param pszDesc    where to store the description string (optional)
 
85
 * @param cchDesc    the size of the buffer in @pszDesc
 
86
 */
 
87
/* static */
 
88
void dvdCreateDeviceString(const char *pcszVendor, const char *pcszModel,
 
89
                            char *pszDesc, size_t cchDesc)
 
90
{
 
91
    AssertPtrReturnVoid(pcszVendor);
 
92
    AssertPtrReturnVoid(pcszModel);
 
93
    AssertPtrNullReturnVoid(pszDesc);
 
94
    AssertReturnVoid(!pszDesc || cchDesc > 0);
 
95
    size_t cchVendor = strLenStripped(pcszVendor);
 
96
    size_t cchModel = strLenStripped(pcszModel);
 
97
 
 
98
    /* Construct the description string as "Vendor Product" */
 
99
    if (pszDesc)
 
100
    {
 
101
        if (cchVendor > 0)
 
102
            RTStrPrintf(pszDesc, cchDesc, "%.*s %s", cchVendor, pcszVendor,
 
103
                        cchModel > 0 ? pcszModel : "(unknown drive model)");
 
104
        else
 
105
            RTStrPrintf(pszDesc, cchDesc, "%s", pcszModel);
 
106
    }
 
107
}
 
108
 
 
109
 
 
110
int VBoxMainDriveInfo::updateDVDs ()
 
111
{
 
112
    LogFlowThisFunc(("entered\n"));
 
113
    int rc = VINF_SUCCESS;
 
114
    bool fSuccess = false;  /* Have we succeeded in finding anything yet? */
 
115
 
 
116
    try
 
117
    {
 
118
        mDVDList.clear ();
 
119
        /* Always allow the user to override our auto-detection using an
 
120
         * environment variable. */
 
121
        if (RT_SUCCESS(rc) && !fSuccess)
 
122
            rc = getDriveInfoFromEnv("VBOX_CDROM", &mDVDList, true /* isDVD */,
 
123
                                     &fSuccess);
 
124
        if (RT_SUCCESS(rc) && !fSuccess)
 
125
            rc = getDVDInfoFromCAM(&mDVDList, &fSuccess);
 
126
    }
 
127
    catch(std::bad_alloc &e)
 
128
    {
 
129
        rc = VERR_NO_MEMORY;
 
130
    }
 
131
    LogFlowThisFunc(("rc=%Rrc\n", rc));
 
132
    return rc;
 
133
}
 
134
 
 
135
int VBoxMainDriveInfo::updateFloppies ()
 
136
{
 
137
    LogFlowThisFunc(("entered\n"));
 
138
    int rc = VINF_SUCCESS;
 
139
    bool fSuccess = false;  /* Have we succeeded in finding anything yet? */
 
140
 
 
141
    try
 
142
    {
 
143
        mFloppyList.clear ();
 
144
        /* Always allow the user to override our auto-detection using an
 
145
         * environment variable. */
 
146
        if (RT_SUCCESS(rc) && !fSuccess)
 
147
            rc = getDriveInfoFromEnv("VBOX_FLOPPY", &mFloppyList, false /* isDVD */,
 
148
                                     &fSuccess);
 
149
    }
 
150
    catch(std::bad_alloc &e)
 
151
    {
 
152
        rc = VERR_NO_MEMORY;
 
153
    }
 
154
    LogFlowThisFunc(("rc=%Rrc\n", rc));
 
155
    return rc;
 
156
}
 
157
 
 
158
/**
 
159
 * Search for available CD/DVD drives using the CAM layer.
 
160
 *
 
161
 * @returns iprt status code
 
162
 * @param   pList      the list to append the drives found to
 
163
 * @param   pfSuccess  this will be set to true if we found at least one drive
 
164
 *                     and to false otherwise.  Optional.
 
165
 */
 
166
static int getDVDInfoFromCAM(DriveInfoList *pList, bool *pfSuccess)
 
167
{
 
168
    int rc = VINF_SUCCESS;
 
169
    RTFILE FileXpt;
 
170
 
 
171
    rc = RTFileOpen(&FileXpt, "/dev/xpt0", RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
 
172
    if (RT_SUCCESS(rc))
 
173
    {
 
174
        union ccb DeviceCCB;
 
175
        struct dev_match_pattern DeviceMatchPattern;
 
176
        struct dev_match_result *paMatches = NULL;
 
177
 
 
178
        memset(&DeviceCCB, 0, sizeof(union ccb));
 
179
        memset(&DeviceMatchPattern, 0, sizeof(struct device_match_pattern));
 
180
 
 
181
        /* We want to get all devices. */
 
182
        DeviceCCB.ccb_h.func_code  = XPT_DEV_MATCH;
 
183
        DeviceCCB.ccb_h.path_id    = CAM_XPT_PATH_ID;
 
184
        DeviceCCB.ccb_h.target_id  = CAM_TARGET_WILDCARD;
 
185
        DeviceCCB.ccb_h.target_lun = CAM_LUN_WILDCARD;
 
186
 
 
187
        /* Setup the pattern */
 
188
        DeviceMatchPattern.type = DEV_MATCH_DEVICE;
 
189
        DeviceMatchPattern.pattern.device_pattern.path_id    = CAM_XPT_PATH_ID;
 
190
        DeviceMatchPattern.pattern.device_pattern.target_id  = CAM_TARGET_WILDCARD;
 
191
        DeviceMatchPattern.pattern.device_pattern.target_lun = CAM_LUN_WILDCARD;
 
192
        DeviceMatchPattern.pattern.device_pattern.flags      = DEV_MATCH_INQUIRY;
 
193
        DeviceMatchPattern.pattern.device_pattern.inq_pat.type = T_CDROM;
 
194
        DeviceMatchPattern.pattern.device_pattern.inq_pat.media_type  = SIP_MEDIA_REMOVABLE | SIP_MEDIA_FIXED;
 
195
        DeviceMatchPattern.pattern.device_pattern.inq_pat.vendor[0]   = '*'; /* Matches anything */
 
196
        DeviceMatchPattern.pattern.device_pattern.inq_pat.product[0]  = '*'; /* Matches anything */
 
197
        DeviceMatchPattern.pattern.device_pattern.inq_pat.revision[0] = '*'; /* Matches anything */
 
198
        DeviceCCB.cdm.num_patterns    = 1;
 
199
        DeviceCCB.cdm.pattern_buf_len = sizeof(struct dev_match_result);
 
200
        DeviceCCB.cdm.patterns        = &DeviceMatchPattern;
 
201
 
 
202
        /*
 
203
         * Allocate the buffer holding the matches.
 
204
         * We will allocate for 10 results and call
 
205
         * CAM multiple times if we have more results.
 
206
         */
 
207
        paMatches = (struct dev_match_result *)RTMemAllocZ(10 * sizeof(struct dev_match_result));
 
208
        if (paMatches)
 
209
        {
 
210
            DeviceCCB.cdm.num_matches   = 0;
 
211
            DeviceCCB.cdm.match_buf_len = 10 * sizeof(struct dev_match_result);
 
212
            DeviceCCB.cdm.matches       = paMatches;
 
213
 
 
214
            do
 
215
            {
 
216
                rc = RTFileIoCtl(FileXpt, CAMIOCOMMAND, &DeviceCCB, sizeof(union ccb), NULL);
 
217
                if (RT_FAILURE(rc))
 
218
                {
 
219
                    Log(("Error while querying available CD/DVD devices rc=%Rrc\n", rc));
 
220
                    break;
 
221
                }
 
222
 
 
223
                for (unsigned i = 0; i < DeviceCCB.cdm.num_matches; i++)
 
224
                {
 
225
                    if (paMatches[i].type == DEV_MATCH_DEVICE)
 
226
                    {
 
227
                        /* We have the drive now but need the appropriate device node */
 
228
                        struct device_match_result *pDevResult = &paMatches[i].result.device_result;
 
229
                        union ccb PeriphCCB;
 
230
                        struct dev_match_pattern PeriphMatchPattern;
 
231
                        struct dev_match_result aPeriphMatches[2];
 
232
                        struct periph_match_result *pPeriphResult = NULL;
 
233
                        unsigned iPeriphMatch = 0;
 
234
 
 
235
                        memset(&PeriphCCB, 0, sizeof(union ccb));
 
236
                        memset(&PeriphMatchPattern, 0, sizeof(struct dev_match_pattern));
 
237
                        memset(aPeriphMatches, 0, sizeof(aPeriphMatches));
 
238
 
 
239
                        /* This time we only want the specific nodes for the device. */
 
240
                        PeriphCCB.ccb_h.func_code  = XPT_DEV_MATCH;
 
241
                        PeriphCCB.ccb_h.path_id    = paMatches[i].result.device_result.path_id;
 
242
                        PeriphCCB.ccb_h.target_id  = paMatches[i].result.device_result.target_id;
 
243
                        PeriphCCB.ccb_h.target_lun = paMatches[i].result.device_result.target_lun;
 
244
 
 
245
                        /* Setup the pattern */
 
246
                        PeriphMatchPattern.type = DEV_MATCH_PERIPH;
 
247
                        PeriphMatchPattern.pattern.periph_pattern.path_id    = paMatches[i].result.device_result.path_id;
 
248
                        PeriphMatchPattern.pattern.periph_pattern.target_id  = paMatches[i].result.device_result.target_id;
 
249
                        PeriphMatchPattern.pattern.periph_pattern.target_lun = paMatches[i].result.device_result.target_lun;
 
250
                        PeriphMatchPattern.pattern.periph_pattern.flags      = PERIPH_MATCH_PATH | PERIPH_MATCH_TARGET | PERIPH_MATCH_LUN;
 
251
                        PeriphCCB.cdm.num_patterns    = 1;
 
252
                        PeriphCCB.cdm.pattern_buf_len = sizeof(struct dev_match_result);
 
253
                        PeriphCCB.cdm.patterns        = &PeriphMatchPattern;
 
254
                        PeriphCCB.cdm.num_matches   = 0;
 
255
                        PeriphCCB.cdm.match_buf_len = sizeof(aPeriphMatches);
 
256
                        PeriphCCB.cdm.matches       = aPeriphMatches;
 
257
 
 
258
                        do
 
259
                        {
 
260
                            rc = RTFileIoCtl(FileXpt, CAMIOCOMMAND, &PeriphCCB, sizeof(union ccb), NULL);
 
261
                            if (RT_FAILURE(rc))
 
262
                            {
 
263
                                Log(("Error while querying available periph devices rc=%Rrc\n", rc));
 
264
                                break;
 
265
                            }
 
266
 
 
267
                            for (iPeriphMatch = 0; iPeriphMatch < PeriphCCB.cdm.num_matches; iPeriphMatch++)
 
268
                            {
 
269
                                if (   (aPeriphMatches[iPeriphMatch].type == DEV_MATCH_PERIPH)
 
270
                                    && (!strcmp(aPeriphMatches[iPeriphMatch].result.periph_result.periph_name, "cd")))
 
271
                                {
 
272
                                    pPeriphResult = &aPeriphMatches[iPeriphMatch].result.periph_result;
 
273
                                    break; /* We found the periph device */
 
274
                                }
 
275
                            }
 
276
 
 
277
                            if (iPeriphMatch < PeriphCCB.cdm.num_matches)
 
278
                                break;
 
279
 
 
280
                        } while (   (DeviceCCB.ccb_h.status == CAM_REQ_CMP)
 
281
                                 && (DeviceCCB.cdm.status == CAM_DEV_MATCH_MORE));
 
282
 
 
283
                        if (pPeriphResult)
 
284
                        {
 
285
                            char szPath[RTPATH_MAX];
 
286
                            char szDesc[256];
 
287
 
 
288
                            RTStrPrintf(szPath, sizeof(szPath), "/dev/%s%d",
 
289
                                        pPeriphResult->periph_name, pPeriphResult->unit_number);
 
290
 
 
291
                            /* Remove trailing white space. */
 
292
                            strLenRemoveTrailingWhiteSpace(pDevResult->inq_data.vendor,
 
293
                                                            sizeof(pDevResult->inq_data.vendor));
 
294
                            strLenRemoveTrailingWhiteSpace(pDevResult->inq_data.product,
 
295
                                                            sizeof(pDevResult->inq_data.product));
 
296
 
 
297
                            dvdCreateDeviceString(pDevResult->inq_data.vendor,
 
298
                                                    pDevResult->inq_data.product,
 
299
                                                    szDesc, sizeof(szDesc));
 
300
 
 
301
                            pList->push_back(DriveInfo(szPath, NULL, szDesc));
 
302
                            if (pfSuccess)
 
303
                                *pfSuccess = true;
 
304
                        }
 
305
                    }
 
306
                }
 
307
            } while (   (DeviceCCB.ccb_h.status == CAM_REQ_CMP)
 
308
                     && (DeviceCCB.cdm.status == CAM_DEV_MATCH_MORE));
 
309
 
 
310
            RTMemFree(paMatches);
 
311
        }
 
312
        else
 
313
            rc = VERR_NO_MEMORY;
 
314
 
 
315
        RTFileClose(FileXpt);
 
316
    }
 
317
 
 
318
    return rc;
 
319
}
 
320
 
 
321
/**
 
322
 * Extract the names of drives from an environment variable and add them to a
 
323
 * list if they are valid.
 
324
 * @returns iprt status code
 
325
 * @param   pcszVar     the name of the environment variable.  The variable
 
326
 *                     value should be a list of device node names, separated
 
327
 *                     by ':' characters.
 
328
 * @param   pList      the list to append the drives found to
 
329
 * @param   isDVD      are we looking for DVD drives or for floppies?
 
330
 * @param   pfSuccess  this will be set to true if we found at least one drive
 
331
 *                     and to false otherwise.  Optional.
 
332
 */
 
333
static int getDriveInfoFromEnv(const char *pcszVar, DriveInfoList *pList,
 
334
                               bool isDVD, bool *pfSuccess)
 
335
{
 
336
    AssertPtrReturn(pcszVar, VERR_INVALID_POINTER);
 
337
    AssertPtrReturn(pList, VERR_INVALID_POINTER);
 
338
    AssertPtrNullReturn(pfSuccess, VERR_INVALID_POINTER);
 
339
    LogFlowFunc(("pcszVar=%s, pList=%p, isDVD=%d, pfSuccess=%p\n", pcszVar,
 
340
                 pList, isDVD, pfSuccess));
 
341
    int rc = VINF_SUCCESS;
 
342
    bool success = false;
 
343
 
 
344
    try
 
345
    {
 
346
        const char *pcszCurrent = RTEnvGet (pcszVar);
 
347
        while (pcszCurrent && *pcszCurrent != '\0')
 
348
        {
 
349
            const char *pcszNext = strchr(pcszCurrent, ':');
 
350
            char szPath[RTPATH_MAX], szReal[RTPATH_MAX];
 
351
            char szDesc[256], szUdi[256];
 
352
            if (pcszNext)
 
353
                RTStrPrintf(szPath, sizeof(szPath), "%.*s",
 
354
                            pcszNext - pcszCurrent - 1, pcszCurrent);
 
355
            else
 
356
                RTStrPrintf(szPath, sizeof(szPath), "%s", pcszCurrent);
 
357
            if (RT_SUCCESS(RTPathReal(szPath, szReal, sizeof(szReal))))
 
358
            {
 
359
                pList->push_back(DriveInfo(szReal, szUdi, szDesc));
 
360
                success = true;
 
361
            }
 
362
            pcszCurrent = pcszNext ? pcszNext + 1 : NULL;
 
363
        }
 
364
        if (pfSuccess != NULL)
 
365
            *pfSuccess = success;
 
366
    }
 
367
    catch(std::bad_alloc &e)
 
368
    {
 
369
        rc = VERR_NO_MEMORY;
 
370
    }
 
371
    LogFlowFunc (("rc=%Rrc, success=%d\n", rc, success));
 
372
    return rc;
 
373
}
 
374
 
 
375
#if 0
 
376
int VBoxMainUSBDeviceInfo::UpdateDevices ()
 
377
{
 
378
    LogFlowThisFunc(("entered\n"));
 
379
    int rc = VINF_SUCCESS;
 
380
    bool success = false;  /* Have we succeeded in finding anything yet? */
 
381
    try
 
382
    {
 
383
        bool halSuccess = false;
 
384
        mDeviceList.clear();
 
385
#if defined(RT_OS_LINUX)
 
386
#ifdef VBOX_WITH_DBUS
 
387
        if (   RT_SUCCESS(rc)
 
388
            && RT_SUCCESS(RTDBusLoadLib())
 
389
            && (!success || testing()))
 
390
            rc = getUSBDeviceInfoFromHal(&mDeviceList, &halSuccess);
 
391
        /* Try the old API if the new one *succeeded* as only one of them will
 
392
         * pick up devices anyway. */
 
393
        if (RT_SUCCESS(rc) && halSuccess && (!success || testing()))
 
394
            rc = getOldUSBDeviceInfoFromHal(&mDeviceList, &halSuccess);
 
395
        if (!success)
 
396
            success = halSuccess;
 
397
#endif /* VBOX_WITH_DBUS defined */
 
398
#endif /* RT_OS_LINUX */
 
399
    }
 
400
    catch(std::bad_alloc &e)
 
401
    {
 
402
        rc = VERR_NO_MEMORY;
 
403
    }
 
404
    LogFlowThisFunc(("rc=%Rrc\n", rc));
 
405
    return rc;
 
406
}
 
407
 
 
408
struct VBoxMainHotplugWaiter::Context
 
409
{
 
410
#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
 
411
    /** The connection to DBus */
 
412
    RTMemAutoPtr <DBusConnection, VBoxHalShutdownPrivate> mConnection;
 
413
    /** Semaphore which is set when a device is hotplugged and reset when
 
414
     * it is read. */
 
415
    volatile bool mTriggered;
 
416
    /** A flag to say that we wish to interrupt the current wait. */
 
417
    volatile bool mInterrupt;
 
418
    /** Constructor */
 
419
    Context() : mTriggered(false), mInterrupt(false) {}
 
420
#endif  /* defined RT_OS_LINUX && defined VBOX_WITH_DBUS */
 
421
};
 
422
 
 
423
/* This constructor sets up a private connection to the DBus daemon, connects
 
424
 * to the hal service and installs a filter which sets the mTriggered flag in
 
425
 * the Context structure when a device (not necessarily USB) is added or
 
426
 * removed. */
 
427
VBoxMainHotplugWaiter::VBoxMainHotplugWaiter ()
 
428
{
 
429
#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
 
430
    int rc = VINF_SUCCESS;
 
431
 
 
432
    mContext = new Context;
 
433
    if (RT_SUCCESS(RTDBusLoadLib()))
 
434
    {
 
435
        for (unsigned i = 0; RT_SUCCESS(rc) && i < 5 && !mContext->mConnection; ++i)
 
436
        {
 
437
            rc = halInitPrivate (&mContext->mConnection);
 
438
        }
 
439
        if (!mContext->mConnection)
 
440
            rc = VERR_NOT_SUPPORTED;
 
441
        DBusMessage *pMessage;
 
442
        while (   RT_SUCCESS(rc)
 
443
               && (pMessage = dbus_connection_pop_message (mContext->mConnection.get())) != NULL)
 
444
            dbus_message_unref (pMessage); /* empty the message queue. */
 
445
        if (   RT_SUCCESS(rc)
 
446
            && !dbus_connection_add_filter (mContext->mConnection.get(),
 
447
                                            dbusFilterFunction,
 
448
                                            (void *) &mContext->mTriggered, NULL))
 
449
            rc = VERR_NO_MEMORY;
 
450
        if (RT_FAILURE(rc))
 
451
            mContext->mConnection.reset();
 
452
    }
 
453
#endif /* defined RT_OS_LINUX && defined VBOX_WITH_DBUS */
 
454
}
 
455
 
 
456
/* Destructor */
 
457
VBoxMainHotplugWaiter::~VBoxMainHotplugWaiter ()
 
458
{
 
459
#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
 
460
    if (!!mContext->mConnection)
 
461
        dbus_connection_remove_filter (mContext->mConnection.get(), dbusFilterFunction,
 
462
                                       (void *) &mContext->mTriggered);
 
463
    delete mContext;
 
464
#endif /* defined RT_OS_LINUX && defined VBOX_WITH_DBUS */
 
465
}
 
466
 
 
467
/* Currently this is implemented using a timed out wait on our private DBus
 
468
 * connection.  Because the connection is private we don't have to worry about
 
469
 * blocking other users. */
 
470
int VBoxMainHotplugWaiter::Wait(unsigned cMillies)
 
471
{
 
472
    int rc = VINF_SUCCESS;
 
473
#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
 
474
    if (!mContext->mConnection)
 
475
        rc = VERR_NOT_SUPPORTED;
 
476
    bool connected = true;
 
477
    mContext->mTriggered = false;
 
478
    mContext->mInterrupt = false;
 
479
    unsigned cRealMillies;
 
480
    if (cMillies != RT_INDEFINITE_WAIT)
 
481
        cRealMillies = cMillies;
 
482
    else
 
483
        cRealMillies = DBUS_POLL_TIMEOUT;
 
484
    while (   RT_SUCCESS(rc) && connected && !mContext->mTriggered
 
485
           && !mContext->mInterrupt)
 
486
    {
 
487
        connected = dbus_connection_read_write_dispatch (mContext->mConnection.get(),
 
488
                                                         cRealMillies);
 
489
        if (mContext->mInterrupt)
 
490
            LogFlowFunc(("wait loop interrupted\n"));
 
491
        if (cMillies != RT_INDEFINITE_WAIT)
 
492
            mContext->mInterrupt = true;
 
493
    }
 
494
    if (!connected)
 
495
        rc = VERR_TRY_AGAIN;
 
496
#else  /* !(defined RT_OS_LINUX && defined VBOX_WITH_DBUS) */
 
497
    rc = VERR_NOT_IMPLEMENTED;
 
498
#endif  /* !(defined RT_OS_LINUX && defined VBOX_WITH_DBUS) */
 
499
    return rc;
 
500
}
 
501
 
 
502
/* Set a flag to tell the Wait not to resume next time it times out. */
 
503
void VBoxMainHotplugWaiter::Interrupt()
 
504
{
 
505
#if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
 
506
    LogFlowFunc(("\n"));
 
507
    mContext->mInterrupt = true;
 
508
#endif  /* defined RT_OS_LINUX && defined VBOX_WITH_DBUS */
 
509
}
 
510
#endif
 
511