VirtualBox

Changeset 3001 in vbox


Ignore:
Timestamp:
Jun 3, 2007 7:29:42 PM (18 years ago)
Author:
vboxsync
Message:

Main/Frontends: Next step to support asynchronous USB device flow.

Location:
trunk/src/VBox
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxSDL/VBoxSDL.cpp

    r2980 r3001  
    486486        gfGuestCapsLockPressed   = fCapsLock;
    487487        gfGuestScrollLockPressed = fScrollLock;
     488        return S_OK;
     489    }
     490
     491    STDMETHOD(OnUSBDeviceStateChange)(IUSBDevice *device, BOOL attached,
     492                                      IVirtualBoxErrorInfo *message)
     493    {
    488494        return S_OK;
    489495    }
  • trunk/src/VBox/Frontends/VirtualBox/src/VBoxConsoleView.cpp

    r2981 r3001  
    383383                                 new ModifierKeyChangeEvent (fNumLock, fCapsLock,
    384384                                                             fScrollLock));
     385        return S_OK;
     386    }
     387
     388    STDMETHOD(OnUSBDeviceStateChange)(IUSBDevice *device, BOOL attached,
     389                                      IVirtualBoxErrorInfo *error)
     390    {
     391        Q_UNUSED (device);
     392        Q_UNUSED (attached);
     393        Q_UNUSED (error);
     394
     395        /// @todo update menu entries
     396
    385397        return S_OK;
    386398    }
  • trunk/src/VBox/Main/ConsoleImpl.cpp

    r2981 r3001  
    19461946            tr ("The virtual machine does not have a USB controller"));
    19471947
    1948     PVUSBIRHCONFIG pRhConfig = (PVUSBIRHCONFIG) pBase->
    1949         pfnQueryInterface (pBase, PDMINTERFACE_VUSB_RH_CONFIG);
    1950     ComAssertRet (pRhConfig, E_FAIL);
    1951 
    1952     /// @todo (dmik) REMOTE_USB
    1953     //  when remote USB devices are ready, first search for a device with the
    1954     //  given UUID in mRemoteUSBDevices. If found, request a capture from
    1955     //  a remote client. If not found, search it on the local host as done below
    1956 
    1957     /*
    1958      *  Try attach the given host USB device (a proper errror message should
    1959      *  be returned in case of error).
    1960      */
    1961     ComPtr <IUSBDevice> hostDevice;
    1962     HRESULT hrc = mControl->CaptureUSBDevice (aId, hostDevice.asOutParam());
    1963     CheckComRCReturnRC (hrc);
    1964 
    1965     return attachUSBDevice (hostDevice, true /* aManual */, pRhConfig);
     1948    /* Request the device capture */
     1949    HRESULT rc = mControl->CaptureUSBDevice (aId);
     1950    CheckComRCReturnRC (rc);
     1951
     1952    return rc;
    19661953}
    19671954
     
    19911978    if (!device)
    19921979        return setError (E_INVALIDARG,
    1993             tr ("Cannot detach the USB device (UUID: %s) as it is not attached here."),
    1994             Guid (aId).toString().raw());
    1995 
    1996     /* protect mpVM */
    1997     AutoVMCaller autoVMCaller (this);
    1998     CheckComRCReturnRC (autoVMCaller.rc());
    1999 
    2000     PPDMIBASE pBase = NULL;
    2001     int vrc = PDMR3QueryLun (mpVM, "usb-ohci", 0, 0, &pBase);
    2002 
    2003     /* if the device is attached, then there must be a USB controller */
    2004     ComAssertRCRet (vrc, E_FAIL);
    2005 
    2006     PVUSBIRHCONFIG pRhConfig = (PVUSBIRHCONFIG) pBase->
    2007         pfnQueryInterface (pBase, PDMINTERFACE_VUSB_RH_CONFIG);
    2008     ComAssertRet (pRhConfig, E_FAIL);
    2009 
    2010     Guid Uuid(aId);
    2011 
    2012     LogFlowThisFunc (("Detaching USB proxy device {%Vuuid}...\n", Uuid.raw()));
    2013 
    2014     /* leave the lock before a VMR3* call (EMT will call us back)! */
    2015     alock.leave();
    2016 
    2017     PVMREQ pReq = NULL;
    2018     vrc = VMR3ReqCall (mpVM, &pReq, RT_INDEFINITE_WAIT,
    2019                        (PFNRT) usbDetachCallback, 5,
    2020                        this, &it, true /* aManual */, pRhConfig, Uuid.raw());
    2021     if (VBOX_SUCCESS (vrc))
    2022         vrc = pReq->iStatus;
    2023     VMR3ReqFree (pReq);
    2024 
    2025     HRESULT hrc = S_OK;
    2026 
    2027     if (VBOX_SUCCESS (vrc))
    2028         device.queryInterfaceTo (aDevice);
    2029     else
    2030         hrc = setError (E_FAIL,
    2031             tr ("Error detaching the USB device.  (Failed to destroy the USB proxy device: %Vrc)"), vrc);
    2032 
    2033     return hrc;
     1980            tr ("USB device with UUID {%Vuuid} is not attached to this machine"),
     1981            Guid (aId).raw());
     1982
     1983    /* Request the device release */
     1984    HRESULT rc = mControl->ReleaseUSBDevice (aId);
     1985    CheckComRCReturnRC (rc);
     1986
     1987    return rc;
    20341988}
    20351989
     
    32213175 *  @note Locks this object for writing.
    32223176 */
    3223 HRESULT Console::onUSBDeviceAttach (IUSBDevice *aDevice)
    3224 {
    3225     LogFlowThisFunc (("aDevice=%p\n", aDevice));
     3177HRESULT Console::onUSBDeviceAttach (IUSBDevice *aDevice, IVirtualBoxErrorInfo *aError)
     3178{
     3179    LogFlowThisFunc (("aDevice=%p aError=%p\n", aDevice, aError));
    32263180
    32273181    AutoCaller autoCaller (this);
     
    32363190                          mMachineState));
    32373191        return E_FAIL;
     3192    }
     3193
     3194    if (aError != NULL)
     3195    {
     3196        /* notify callback about an error */
     3197        onUSBDeviceStateChange (aDevice, true /* aAttached */, aError);
     3198        return S_OK;
    32383199    }
    32393200
     
    32553216    ComAssertRet (pRhConfig, E_FAIL);
    32563217
    3257     return attachUSBDevice (aDevice, false /* aManual */, pRhConfig);
     3218    /// @todo notify listeners of IConsoleCallback in case of error
     3219    return attachUSBDevice (aDevice, pRhConfig);
    32583220}
    32593221
     
    32643226 *  @note Locks this object for writing.
    32653227 */
    3266 HRESULT Console::onUSBDeviceDetach (INPTR GUIDPARAM aId)
     3228HRESULT Console::onUSBDeviceDetach (INPTR GUIDPARAM aId,
     3229                                    IVirtualBoxErrorInfo *aError)
    32673230{
    32683231    Guid Uuid (aId);
    3269     LogFlowThisFunc (("aId={%Vuuid}\n", Uuid.raw()));
     3232    LogFlowThisFunc (("aId={%Vuuid} aError=%p\n", Uuid.raw(), aError));
    32703233
    32713234    AutoCaller autoCaller (this);
     
    33023265    }
    33033266
     3267    if (aError != NULL)
     3268    {
     3269        /* notify callback about an error */
     3270        onUSBDeviceStateChange (device, false /* aAttached */, aError);
     3271        return S_OK;
     3272    }
     3273
    33043274    /* protect mpVM */
    33053275    AutoVMCaller autoVMCaller (this);
     
    33243294    vrc = VMR3ReqCall (mpVM, &pReq, RT_INDEFINITE_WAIT,
    33253295                       (PFNRT) usbDetachCallback, 5,
    3326                        this, &it, false /* aManual */, pRhConfig, Uuid.raw());
     3296                       this, &it, pRhConfig, Uuid.raw());
    33273297    if (VBOX_SUCCESS (vrc))
    33283298        vrc = pReq->iStatus;
     
    33313301    AssertRC (vrc);
    33323302
     3303    /// @todo notify listeners of IConsoleCallback in case of error
    33333304    return VBOX_SUCCESS (vrc) ? S_OK : E_FAIL;
    33343305}
     
    35203491    while (it != mCallbacks.end())
    35213492        (*it++)->OnKeyboardLedsChange(fNumLock, fCapsLock, fScrollLock);
     3493}
     3494
     3495/**
     3496 *  @note Locks this object for reading.
     3497 */
     3498void Console::onUSBDeviceStateChange (IUSBDevice *aDevice, bool aAttached,
     3499                                      IVirtualBoxErrorInfo *aError)
     3500{
     3501    AutoCaller autoCaller (this);
     3502    AssertComRCReturnVoid (autoCaller.rc());
     3503
     3504    AutoReaderLock alock (this);
     3505
     3506    CallbackList::iterator it = mCallbacks.begin();
     3507    while (it != mCallbacks.end())
     3508        (*it++)->OnUSBDeviceStateChange (aDevice, aAttached, aError);
    35223509}
    35233510
     
    41884175 *  mUSBDevices collection.
    41894176 *
    4190  *  If \a aManual is true and a failure occures, the given device
    4191  *  will be returned back to the USB proxy manager.
    4192  *
    41934177 *  @param aHostDevice  device to attach
    4194  *  @param aManual      true if device is being manually attached
    41954178 *
    41964179 *  @note Locks this object for writing.
    41974180 *  @note Synchronously calls EMT.
    41984181 */
    4199 HRESULT Console::attachUSBDevice (IUSBDevice *aHostDevice, bool aManual,
    4200                                   PVUSBIRHCONFIG aConfig)
     4182HRESULT Console::attachUSBDevice (IUSBDevice *aHostDevice, PVUSBIRHCONFIG aConfig)
    42014183{
    42024184    AssertReturn (aHostDevice && aConfig, E_FAIL);
     
    42624244        LogWarningThisFunc (("Failed to create proxy device for '%s' {%Vuuid} (%Vrc)\n",
    42634245                             Address.raw(), Uuid.ptr(), vrc));
    4264 
    4265         if (aManual)
    4266         {
    4267             /*
    4268              *  Neither SessionMachine::ReleaseUSBDevice() nor Host::releaseUSBDevice()
    4269              *  should call the Console back, so keep the lock to provide atomicity
    4270              *  (to protect Host reapplying USB filters)
    4271              */
    4272             hrc = mControl->ReleaseUSBDevice (Uuid);
    4273             AssertComRC (hrc);
    4274         }
    42754246
    42764247        switch (vrc)
     
    43484319        that->mUSBDevices.push_back (device);
    43494320        LogFlowFunc (("Attached device {%Vuuid}\n", device->id().raw()));
     4321
     4322        /* notify callbacks */
     4323        that->onUSBDeviceStateChange (device, true /* aAttached */, NULL);
    43504324    }
    43514325
     
    43674341DECLCALLBACK(int)
    43684342Console::usbDetachCallback (Console *that, USBDeviceList::iterator *aIt,
    4369                             bool aManual, PVUSBIRHCONFIG aConfig, PCRTUUID aUuid)
     4343                            PVUSBIRHCONFIG aConfig, PCRTUUID aUuid)
    43704344{
    43714345    LogFlowFuncEnter();
     
    44014375        LogFlowFunc (("Detached device {%Vuuid}\n", (**aIt)->id().raw()));
    44024376
    4403         /// @todo (dmik) REMOTE_USB
    4404         //  if the device is remote, notify a remote client that we have
    4405         //  detached the device
    4406 
    4407         /* If it's a manual detach, give it back to the USB Proxy */
    4408         if (aManual)
    4409         {
    4410             /*
    4411              *  Neither SessionMachine::ReleaseUSBDevice() nor Host::releaseUSBDevice()
    4412              *  should call the Console back, so keep the lock to provide atomicity
    4413              *  (to protect Host reapplying USB filters)
    4414              */
    4415             LogFlowFunc (("Giving it back it to USB proxy...\n"));
    4416             HRESULT hrc = that->mControl->ReleaseUSBDevice (Guid (*aUuid));
    4417             AssertComRC (hrc);
    4418             vrc = SUCCEEDED (hrc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
    4419         }
     4377        /* notify callbacks */
     4378        that->onUSBDeviceStateChange (**aIt, false /* aAttached */, NULL);
    44204379    }
    44214380
     
    62066165
    62076166/**
    6208  *  Captures and attaches USB devices to a newly created VM.
     6167 *  Captures USB devices that match filters of the VM.
     6168 *  Called at VM startup.
    62096169 *
    62106170 *  @param   pVM     The VM handle.
     
    62196179    ComAssertRet (isLockedOnCurrentThread(), E_FAIL);
    62206180
    6221     /*
    6222      *  If the machine has an USB controller, capture devices and attach
    6223      *  them to it.
    6224      */
     6181    /* If the machine has an USB controller, ask the USB proxy service to
     6182     * capture devices */
    62256183    PPDMIBASE pBase;
    62266184    int vrc = PDMR3QueryLun (pVM, "usb-ohci", 0, 0, &pBase);
    62276185    if (VBOX_SUCCESS (vrc))
    62286186    {
    6229         PVUSBIRHCONFIG pRhConfig = (PVUSBIRHCONFIG) pBase->
    6230             pfnQueryInterface (pBase, PDMINTERFACE_VUSB_RH_CONFIG);
    6231         ComAssertRet (pRhConfig, E_FAIL);
    6232 
    6233         /*
    6234          *  Get the list of USB devices that should be captured and attached to
    6235          *  the newly created machine.
    6236          */
    6237         ComPtr <IUSBDeviceCollection> coll;
    6238         HRESULT hrc = mControl->AutoCaptureUSBDevices (coll.asOutParam());
     6187        HRESULT hrc = mControl->AutoCaptureUSBDevices();
    62396188        ComAssertComRCRetRC (hrc);
    6240 
    6241         /*
    6242          *  Enumerate the devices and attach them.
    6243          *  Failing to attach an device is currently ignored and the device
    6244          *  released.
    6245          */
    6246         ComPtr <IUSBDeviceEnumerator> en;
    6247         hrc = coll->Enumerate (en.asOutParam());
    6248         ComAssertComRCRetRC (hrc);
    6249 
    6250         BOOL hasMore = FALSE;
    6251         while (SUCCEEDED (en->HasMore (&hasMore)) && hasMore)
    6252         {
    6253             ComPtr <IUSBDevice> hostDevice;
    6254             hrc = en->GetNext (hostDevice.asOutParam());
    6255             ComAssertComRCRetRC (hrc);
    6256             ComAssertRet (!hostDevice.isNull(), E_FAIL);
    6257 
    6258             hrc = attachUSBDevice (hostDevice, true /* aManual */, pRhConfig);
    6259 
    6260             /// @todo (r=dmik) warning reporting subsystem
    6261         }
    62626189    }
    62636190    else if (   vrc == VERR_PDM_DEVICE_NOT_FOUND
     
    63916318            if (fMatched)
    63926319            {
    6393                 hrc = onUSBDeviceAttach(device);
     6320                hrc = onUSBDeviceAttach (device, NULL);
    63946321
    63956322                /// @todo (r=dmik) warning reporting subsystem
     
    64576384            Guid uuid;
    64586385            device->COMGETTER (Id) (uuid.asOutParam());
    6459             onUSBDeviceDetach (uuid);
     6386            onUSBDeviceDetach (uuid, NULL);
    64606387        }
    64616388
  • trunk/src/VBox/Main/HostImpl.cpp

    r2981 r3001  
    110110HRESULT Host::init (VirtualBox *parent)
    111111{
    112     LogFlowMember(("Host::init(): isReady=%d\n", isReady()));
     112    LogFlowThisFunc (("isReady=%d\n", isReady()));
    113113
    114114    ComAssertRet (parent, E_INVALIDARG);
     
    142142void Host::uninit()
    143143{
    144     LogFlowMember(("Host::uninit(): isReady=%d\n", isReady()));
     144    LogFlowThisFunc (("isReady=%d\n", isReady()));
    145145
    146146    AssertReturn (isReady(), (void) 0);
    147147
    148     // uninit all USB device filters still referenced by clients
     148    /* wait for USB proxy service to terminate before we uninit all USB
     149     * devices */
     150    LogFlowThisFunc (("Stopping USB proxy service...\n"));
     151    delete mUSBProxyService;
     152    LogFlowThisFunc (("Done stopping USB proxy service.\n"));
     153    mUSBProxyService = NULL;
     154
     155    /* uninit all USB device filters still referenced by clients */
    149156    uninitDependentChildren();
    150 
    151     delete mUSBProxyService;
    152     mUSBProxyService = NULL;
    153157
    154158    mUSBDeviceFilters.clear();
     
    12021206
    12031207/**
    1204  *  Marks the given host USB device as captured by the given machine and returns
    1205  *  it as IUSBDevice to the caller.
     1208 *  Requests the USB proxy service to capture the given host USB device.
     1209 *
     1210 *  When the request is completed,
     1211 *  IInternalSessionControl::onUSBDeviceAttach() will be called on the given
     1212 *  machine object.
    12061213 *
    12071214 *  Called by Console from the VM process (throug IInternalMachineControl).
    12081215 *  Must return extended error info in case of errors.
    12091216 */
    1210 HRESULT Host::captureUSBDevice (SessionMachine *aMachine, INPTR GUIDPARAM aId,
    1211                                 IUSBDevice **aHostDevice)
     1217HRESULT Host::captureUSBDevice (SessionMachine *aMachine, INPTR GUIDPARAM aId)
    12121218{
    12131219    ComAssertRet (aMachine, E_INVALIDARG);
    1214     ComAssertRet (aHostDevice, E_POINTER);
    12151220
    12161221    AutoLock lock (this);
     
    12301235    if (!device)
    12311236        return setError (E_INVALIDARG,
    1232             tr ("USB device with UUID {%s} is not currently attached to the host"),
    1233             id.toString().raw());
     1237            tr ("USB device with UUID {%Vuuid} is not currently attached to the host"),
     1238            id.raw());
    12341239
    12351240    AutoLock devLock (device);
     1241
     1242    if (device->isStatePending())
     1243        return setError (E_INVALIDARG,
     1244            tr ("USB device '%s' with UUID {%Vuuid} is busy (waiting for a pending "
     1245                "state change). Please try later"),
     1246            device->name().raw(), id.raw());
    12361247
    12371248    if (device->state() == USBDeviceState_USBDeviceNotSupported)
    12381249        return setError (E_INVALIDARG,
    1239             tr ("USB device '%s' with UUID {%s} cannot be accessed by guest "
     1250            tr ("USB device '%s' with UUID {%Vuuid} cannot be accessed by guest "
    12401251                "computers"),
    1241             device->name().raw(), id.toString().raw());
     1252            device->name().raw(), id.raw());
    12421253
    12431254    if (device->state() == USBDeviceState_USBDeviceUnavailable)
    12441255        return setError (E_INVALIDARG,
    1245             tr ("USB device '%s' with UUID {%s} is being exclusively used by the "
     1256            tr ("USB device '%s' with UUID {%Vuuid} is being exclusively used by the "
    12461257                "host computer"),
    1247             device->name().raw(), id.toString().raw());
     1258            device->name().raw(), id.raw());
    12481259
    12491260    if (device->state() == USBDeviceState_USBDeviceCaptured)
    12501261        return setError (E_INVALIDARG,
    1251             tr ("USB device '%s' with UUID {%s} is already captured by the virtual "
     1262            tr ("USB device '%s' with UUID {%Vuuid} is already captured by the virtual "
    12521263                "machine '%ls'"),
    1253             device->name().raw(), id.toString().raw(),
     1264            device->name().raw(), id.raw(),
    12541265            aMachine->userData()->mName.raw());
    12551266
    1256     // try capture the device
    1257     bool ok = device->setCaptured (aMachine);
    1258     if (!ok)
    1259     {
    1260         if (device->state() == USBDeviceState_USBDeviceBusy)
    1261             return setError (E_FAIL,
    1262                 tr ("USB device with UUID {%s} is being accessed by the host "
    1263                     "computer and cannot be attached to the virtual machine."
    1264                     "Please try later"),
    1265                 id.toString().raw());
    1266         else
    1267             ComAssertRet (ok, E_FAIL);
    1268     }
    1269 
    1270     // return the device to the caller as IUSBDevice
    1271     device.queryInterfaceTo (aHostDevice);
     1267    /* try to capture the device */
     1268    device->requestCapture (aMachine);
     1269
    12721270    return S_OK;
    12731271}
     
    12771275 *  machine the device is currently marked as captured by.
    12781276 *
     1277 *  When the request is completed,
     1278 *  IInternalSessionControl::onUSBDeviceDetach() will be called on the given
     1279 *  machine object.
     1280 *
    12791281 *  Called by Console from the VM process (throug IInternalMachineControl).
    12801282 */
     
    12991301    AutoLock devLock (device);
    13001302
     1303    LogFlowThisFunc (("id={%Vuuid} state=%d isStatePending=%RTbool pendingState=%d\n",
     1304                      device->id().raw(), device->state(), device->isStatePending(),
     1305                      device->pendingState()));
     1306
     1307    if (device->isStatePending())
     1308        return setError (E_INVALIDARG,
     1309            tr ("USB device '%s' with UUID {%Vuuid} is busy (waiting for a pending "
     1310                "state change). Please try later"),
     1311                         device->name().raw(), device->id().raw());
     1312
    13011313    ComAssertRet (device->machine() == aMachine, E_FAIL);
    13021314
    1303     /* reset the device and apply filters */
    1304     int vrc = device->reset();
    1305     ComAssertRCRet (vrc, E_FAIL);
    1306 
    1307     HRESULT rc = applyAllUSBFilters (device, aMachine);
     1315    /* re-apply filters on the device before giving it back to the host */
     1316    device->setHeld();
     1317    HRESULT rc = applyAllUSBFilters (device);
    13081318    ComAssertComRC (rc);
    13091319
     
    13121322
    13131323/**
    1314  *  Runs the filters of the given machine against all currently available USB
    1315  *  devices, marks those that match as captured and returns them as the colection
    1316  *  of IUSBDevice instances.
     1324 *  Asks the USB proxy service to capture all currently available USB devices
     1325 *  that match filters of the given machine.
     1326 *
     1327 *  When the request is completed,
     1328 *  IInternalSessionControl::onUSBDeviceDetach() will be called on the given
     1329 *  machine object per every captured USB device.
    13171330 *
    13181331 *  Called by Console from the VM process (through IInternalMachineControl)
     
    13221335 *  to the new locking scheme).
    13231336 */
    1324 HRESULT Host::autoCaptureUSBDevices (SessionMachine *aMachine,
    1325                                      IUSBDeviceCollection **aHostDevices)
     1337HRESULT Host::autoCaptureUSBDevices (SessionMachine *aMachine)
    13261338{
    13271339    LogFlowThisFunc (("aMachine=%p\n", aMachine));
     
    13301342    CHECK_READY();
    13311343
    1332     std::list <ComPtr <IUSBDevice> > list;
    1333 
    1334     USBDeviceList::iterator it = mUSBDevices.begin();
    1335     while (it != mUSBDevices.end())
     1344    for (USBDeviceList::iterator it = mUSBDevices.begin();
     1345         it != mUSBDevices.end();
     1346         ++ it)
    13361347    {
    13371348        ComObjPtr <HostUSBDevice> device = *it;
     
    13391350        AutoLock devLock (device);
    13401351
    1341 /// @todo remove
    1342 #if 0
    1343         if (device->isIgnored())
     1352        /* skip pending devices */
     1353        if (device->isStatePending())
    13441354            continue;
    1345 #endif
    13461355
    13471356        if (device->state() == USBDeviceState_USBDeviceBusy ||
     
    13501359        {
    13511360            applyMachineUSBFilters (aMachine, device);
    1352 
    1353             if (device->state() == USBDeviceState_USBDeviceCaptured)
    1354             {
    1355                 /* put the device to the return list */
    1356                 ComPtr <IUSBDevice> d;
    1357                 device.queryInterfaceTo (d.asOutParam());
    1358                 Assert (!d.isNull());
    1359                 list.push_back (d);
    1360             }
    1361         }
    1362         ++ it;
    1363     }
    1364 
    1365     ComObjPtr <IfaceUSBDeviceCollection> coll;
    1366     coll.createObject();
    1367     coll->init (list);
    1368     coll.queryInterfaceTo (aHostDevices);
     1361        }
     1362    }
    13691363
    13701364    return S_OK;
     
    13961390        if (device->machine() == aMachine)
    13971391        {
    1398             /* reset the device and apply filters */
    1399             device->reset();
    1400             HRESULT rc = applyAllUSBFilters (device, aMachine);
    1401             ComAssertComRC (rc);
     1392            if (!device->isStatePending())
     1393            {
     1394                Assert (device->state() == USBDeviceState_USBDeviceCaptured);
     1395
     1396                /* re-apply filters on the device before giving it back to the
     1397                 * host */
     1398                device->setHeld();
     1399                HRESULT rc = applyAllUSBFilters (device);
     1400                AssertComRC (rc);
     1401            }
     1402            else
     1403            {
     1404                device->cancelPendingState();
     1405            }
    14021406        }
    14031407        ++ it;
     
    18331837
    18341838/**
    1835  *  Runs through all global filters to determine the state of the given
    1836  *  USB device, then unless ignored, runs trhough filters of all running machines
    1837  *  (excluding the given one) to automatically capture the device when there is a
    1838  *  match (the state of the device will be set to USBDeviceCaptured if so, and
    1839  *  the machine's process will be informed about the auto-capture).
    1840  *
    1841  *  @param aDevice  USB device to set state for
    1842  *  @param aMachine the machine whose filters are to be excluded (can be NULL)
    1843  *
    1844  *  @note the method must be called from under this object's lock
    1845  */
    1846 HRESULT Host::applyAllUSBFilters (ComObjPtr <HostUSBDevice> &aDevice,
    1847                                   SessionMachine *aMachine /* = NULL  */)
     1839 *  Applies all (golbal and VM) filters to the given USB device. The device
     1840 *  must be either a newly attached device or a device released by a VM.
     1841 *
     1842 *  This method will request the USB proxy service to release the device (give
     1843 *  it back to the host) if none of the global or VM filters want to capture
     1844 *  the device.
     1845 *
     1846 *  @param aDevice  USB device to apply filters to.
     1847 *
     1848 *  @note the method must be called from under this object's write lock and
     1849 *  from the aDevice's write lock.
     1850 */
     1851HRESULT Host::applyAllUSBFilters (ComObjPtr <HostUSBDevice> &aDevice)
    18481852{
    18491853    LogFlowThisFunc (("\n"));
    18501854
     1855    /// @todo must check for read lock, it's enough here
    18511856    AssertReturn (isLockedOnCurrentThread(), E_FAIL);
    18521857
    1853     AutoLock devLock (aDevice);
     1858    AssertReturn (aDevice->isLockedOnCurrentThread(), E_FAIL);
     1859
     1860    AssertReturn (aDevice->state() != USBDeviceState_USBDeviceCaptured, E_FAIL);
     1861
     1862    AssertReturn (aDevice->isStatePending() == false, E_FAIL);
    18541863
    18551864    /* ignore unsupported devices */
     
    18631872    mParent->getOpenedMachines (machines);
    18641873
     1874    /// @todo it may be better to take a copy of filters to iterate and leave
     1875    /// the host lock before calling HostUSBDevice:requestCapture() (which
     1876    /// calls the VM process).
     1877
    18651878    /* apply global filters */
    18661879    USBDeviceFilterList::const_iterator it = mUSBDeviceFilters.begin();
    1867     while (it != mUSBDeviceFilters.end())
     1880    for (; it != mUSBDeviceFilters.end(); ++ it)
    18681881    {
    18691882        AutoLock filterLock (*it);
     
    18721885        {
    18731886            if (data.mAction == USBDeviceFilterAction_USBDeviceFilterIgnore)
     1887            {
     1888                /* request to give the device back to the host*/
     1889                aDevice->requestRelease();
     1890                /* nothing to do any more */
    18741891                return S_OK;
     1892            }
    18751893            if (data.mAction == USBDeviceFilterAction_USBDeviceFilterHold)
    18761894                break;
    18771895        }
    1878         ++ it;
    18791896    }
    18801897
    18811898    /* apply machine filters */
    1882     for (size_t i = 0; i < machines.size(); i++)
    1883     {
    1884         if (aMachine && machines [i] == aMachine)
     1899    size_t i = 0;
     1900    for (; i < machines.size(); ++ i)
     1901    {
     1902        /* skip the machine the device was just detached from */
     1903        if (aDevice->machine() && machines [i] == aDevice->machine())
    18851904            continue;
    18861905
    1887         applyMachineUSBFilters (machines [i], aDevice);
    1888 
    1889         if (aDevice->state() == USBDeviceState_USBDeviceCaptured)
    1890         {
    1891             /* inform the VM process about the auto-capture */
    1892             ComPtr <IUSBDevice> d;
    1893             aDevice.queryInterfaceTo (d.asOutParam());
    1894 
    1895             /* the VM process will query the object, so leave the lock */
    1896             devLock.leave();
    1897 
    1898             HRESULT rc = machines [i]->onUSBDeviceAttach (d);
    1899             if (SUCCEEDED(rc))
    1900                 return rc;
    1901 
    1902             devLock.enter();
    1903 
    1904             /* the machine rejected it, continue applying filters. */
    1905             aDevice->reset();
    1906         }
    1907     }
    1908 
    1909     /* no machine filters were matched.
    1910      * if no global filters were matched as well, release the device
    1911      * to make it available on the host */
    1912     if (    it == mUSBDeviceFilters.end()
    1913         &&  aDevice->state() == USBDeviceState_USBDeviceHeld)
    1914         aDevice->setHostDriven();
    1915 /** @todo dmik, what about USBDeviceFilterHold??? */
     1906        if (applyMachineUSBFilters (machines [i], aDevice))
     1907            break;
     1908    }
     1909
     1910    if (i == machines.size())
     1911    {
     1912        /* no matched machine filters, check what to do */
     1913        if (it == mUSBDeviceFilters.end())
     1914        {
     1915            /* no any filter matched at all */
     1916            /* request to give the device back to the host */
     1917            aDevice->requestRelease();
     1918        }
     1919        else
     1920        {
     1921            /* there was a global Hold filter */
     1922            aDevice->requestHold();
     1923        }
     1924    }
     1925
     1926    return S_OK;
     1927}
     1928
    19161929/**
    1917  *  bird, everything's ok from what I see. if USBDeviceFilterHold filter was
    1918  *  matched, setHostDevice() will not (and should not) be called
    1919  *  (because it != mUSBDeviceFilters.end() in that case).
    1920  */
    1921 
    1922     return S_OK;
    1923 }
    1924 
    1925 /**
    1926  *  Runs through filters of the given machine in order to automatically capture
    1927  *  the given USB device when there is a match (the state of the device will
    1928  *  be set to USBDeviceCaptured if so, but the machine's process will *NOT* be)
    1929  *  informed about the auto-capture).
    1930  *
    1931  *  @param aMachine the machine whose filters are to be run
    1932  *  @param aDevice  USB device, a candidate for auto-attaching
     1930 *  Runs through filters of the given machine and asks the USB proxy service
     1931 *  to capture the given USB device when there is a match.
     1932 *
     1933 *  @param aMachine Machine whose filters are to be run.
     1934 *  @param aDevice  USB device, a candidate for auto-capturing.
     1935 *  @return         @c true if there was a match and @c false otherwise.
     1936 *
     1937 *  @note the method must be called from under this object's write lock and
     1938 *  from the aDevice's write lock.
    19331939 *
    19341940 *  @note Locks aMachine for reading.
    19351941 */
    1936 void Host::applyMachineUSBFilters (SessionMachine *aMachine,
     1942bool Host::applyMachineUSBFilters (SessionMachine *aMachine,
    19371943                                   ComObjPtr <HostUSBDevice> &aDevice)
    19381944{
    19391945    LogFlowThisFunc (("\n"));
    19401946
    1941     AssertReturnVoid (isLockedOnCurrentThread());
    1942     AssertReturnVoid (aDevice->isLockedOnCurrentThread());
    1943 
    1944     AssertReturnVoid (aMachine);
    1945     AssertReturnVoid (aDevice->state() != USBDeviceState_USBDeviceUnavailable);
    1946 
    1947     /* We're going to use aMachine which is not our child/parent, add a caller */
    1948     AutoCaller autoCaller (aMachine);
    1949     if (!autoCaller.isOk())
    1950     {
    1951         /* silently return, the machine might be not running any more */
    1952         return;
    1953     }
    1954 
    1955     /* enter the machine's lock because we want to access its USB controller */
    1956     AutoReaderLock machineLock (aMachine);
    1957 
    1958     if (aMachine->usbController()->hasMatchingFilter (aDevice))
    1959     {
    1960         /* try capture the device */
    1961         bool ok = aDevice->setCaptured (aMachine);
    1962 
    1963         /*
    1964          *  false is valid only when the state remains USBDeviceBusy meaning that
    1965          *  the device is currently busy (being accessed by the host)
    1966          */
    1967         Assert (ok || aDevice->state() == USBDeviceState_USBDeviceBusy);
    1968         NOREF (ok);
    1969     }
     1947    AssertReturn (aMachine, false);
     1948
     1949    /// @todo must check for read lock, it's enough here
     1950    AssertReturn (isLockedOnCurrentThread(), false);
     1951
     1952    AssertReturn (aDevice->isLockedOnCurrentThread(), false);
     1953
     1954    AssertReturn (aDevice->state() != USBDeviceState_USBDeviceNotSupported, false);
     1955    AssertReturn (aDevice->state() != USBDeviceState_USBDeviceUnavailable, false);
     1956
     1957    AssertReturn (aDevice->isStatePending() == false, false);
     1958
     1959    bool hasMatch = false;
     1960
     1961    {
     1962        /* We're going to use aMachine which is not our child/parent, add a
     1963         * caller */
     1964        AutoCaller autoCaller (aMachine);
     1965        if (!autoCaller.isOk())
     1966        {
     1967            /* silently return, the machine might be not running any more */
     1968            return false;
     1969        }
     1970
     1971        /* enter the machine's lock because we want to access its USB controller */
     1972        AutoReaderLock machineLock (aMachine);
     1973        hasMatch = aMachine->usbController()->hasMatchingFilter (aDevice);
     1974    }
     1975
     1976    if (hasMatch)
     1977    {
     1978        /* try to capture the device */
     1979        return aDevice->requestCapture (aMachine);
     1980    }
     1981
     1982    return hasMatch;
    19701983}
    19711984
     
    19821995    AssertReturnVoid (aDevice);
    19831996
    1984     /// @todo (dmik) check locks
    1985     AutoLock alock (this);
    1986 
    1987     AutoLock devLock (aDevice);
     1997    AssertReturnVoid (isLockedOnCurrentThread());
     1998    AssertReturnVoid (aDevice->isLockedOnCurrentThread());
     1999
     2000    LogFlowThisFunc (("id={%Vuuid} state=%d isStatePending=%RTbool pendingState=%d\n",
     2001                      aDevice->id().raw(), aDevice->state(), aDevice->isStatePending(),
     2002                      aDevice->pendingState()));
     2003
     2004    Assert (aDevice->isStatePending() == false);
    19882005
    19892006    /* add to the collecion */
     
    19972014
    19982015/**
    1999  *  Called by USB proxy service (?) when the device is physically detached
     2016 *  Called by USB proxy service when the device is physically detached
    20002017 *  from the host.
    20012018 *
     
    20082025    AssertReturnVoid (aDevice);
    20092026
    2010     /// @todo (dmik) check locks
    2011     AutoLock alock (this);
    2012 
    2013     AutoLock devLock (aDevice);
     2027    AssertReturnVoid (isLockedOnCurrentThread());
     2028    AssertReturnVoid (aDevice->isLockedOnCurrentThread());
     2029
     2030    LogFlowThisFunc (("id={%Vuuid} state=%d isStatePending=%RTbool pendingState=%d\n",
     2031                      aDevice->id().raw(), aDevice->state(), aDevice->isStatePending(),
     2032                      aDevice->pendingState()));
    20142033
    20152034    Guid id = aDevice->id();
     
    20322051    mUSBDevices.erase (it);
    20332052
    2034     if (device->machine())
    2035     {
    2036         /* the device is captured by a machine, instruct it to release */
    2037 
    2038         devLock.leave();
    2039         alock.leave();
    2040 
    2041         HRESULT rc = device->machine()->onUSBDeviceDetach (device->id());
    2042         AssertComRC (rc);
    2043     }
     2053    /* reset all data */
     2054    device->reset();
    20442055}
    20452056
    20462057/**
    2047  *  Called by USB proxy service  when the state of the host-driven device
    2048  *  has changed because of non proxy interaction.
     2058 *  Called by USB proxy service when the state of the device has changed
     2059 *  either because of the state change request or because of some external
     2060 *  interaction.
    20492061 *
    20502062 *  @param  aDevice     The device in question.
     
    20542066    LogFlowThisFunc (("aDevice=%p\n", aDevice));
    20552067
    2056     /// @todo (dmik) check locks
    2057     AutoLock alock (this);
    2058 
    2059     /** @todo dmik, is there anything we should do here? For instance if the device now is available? */
     2068    AssertReturnVoid (aDevice);
     2069
     2070    AssertReturnVoid (isLockedOnCurrentThread());
     2071    AssertReturnVoid (aDevice->isLockedOnCurrentThread());
     2072
     2073    LogFlowThisFunc (("id={%Vuuid} state=%d isStatePending=%RTbool pendingState=%d\n",
     2074                      aDevice->id().raw(), aDevice->state(), aDevice->isStatePending(),
     2075                      aDevice->pendingState()));
     2076
     2077    if (aDevice->isStatePending())
     2078    {
     2079        /* it was a state change request */
     2080        aDevice->handlePendingStateChange();
     2081    }
     2082    else
     2083    {
     2084        /* some external state change */
     2085
     2086        /// @todo re-run all USB filters probably
     2087        AssertFailed();
     2088    }
    20602089}
    20612090
  • trunk/src/VBox/Main/HostUSBDeviceImpl.cpp

    r2981 r3001  
    2121
    2222#include "HostUSBDeviceImpl.h"
     23#include "MachineImpl.h"
     24#include "VirtualBoxErrorInfoImpl.h"
    2325#include "USBProxyService.h"
     26
    2427#include "Logging.h"
    2528
     
    9699            break;
    97100        case USBDEVICESTATE_USED_BY_GUEST:
    98             mState = USBDeviceState_USBDeviceCaptured;
     101            /* @todo USBDEVICESTATE_USED_BY_GUEST seems not to be used
     102             * anywhere in the proxy code; it's quite logical because the
     103             * proxy doesn't know anything about guest VMs. */
     104            AssertFailedReturn (E_FAIL);
    99105            break;
    100106    }
     
    104110    /* Other data members */
    105111    mIsStatePending = false;
    106 /// @todo remove
    107 #if 0
    108     mIgnored = false;
    109 #endif
    110112    mUSBProxyService = aUSBProxyService;
    111113    mUsb = aUsb;
     
    339341}
    340342
    341 /// @todo remove
    342 #if 0
    343 /**
    344  * Sets the ignored flag and returns the device to the host.
    345  *
    346  * @note Locks this object for writing.
    347  */
    348 void HostUSBDevice::setIgnored()
    349 {
    350     AutoCaller autoCaller (this);
    351     AssertComRCReturnVoid (autoCaller.rc());
    352 
    353     AutoLock alock (this);
    354 
    355     AssertReturnVoid (!mIgnored);
    356 
    357     mIgnored = true;
    358 
    359     setHostDriven();
    360 }
    361 #endif
    362 
    363 /**
    364  * @note Locks this object for writing.
    365  */
    366 bool HostUSBDevice::setCaptured (SessionMachine *aMachine)
    367 {
     343/**
     344 *  Requests the USB proxy service to capture the device and sets the pending
     345 *  state to Captured.
     346 *
     347 *  If the state change may be performed immediately (for example, Hold ->
     348 *  Captured), then the machine is informed before this method returns.
     349 *
     350 *  @param aMachine     Machine that will capture this device on success.
     351 *  @return             @c false if the device could be immediately captured
     352 *                      but the VM process refused to grab it;
     353 *                      @c true otherwise.
     354 *
     355 *  @note Must be called from under the object write lock.
     356 *
     357 *  @note May lock the given machine object for reading.
     358 */
     359bool HostUSBDevice::requestCapture (SessionMachine *aMachine)
     360{
     361    LogFlowThisFunc (("\n"));
     362
    368363    AssertReturn (aMachine, false);
    369364
    370     AutoCaller autoCaller (this);
    371     AssertComRCReturn (autoCaller.rc(), false);
    372 
    373     AutoLock alock (this);
     365    AssertReturn (isLockedOnCurrentThread(), false);
     366
     367    AssertReturn (mIsStatePending == false, false);
    374368
    375369    AssertReturn (
     
    379373        false);
    380374
    381     mState = USBDeviceState_USBDeviceCaptured;
     375    if (mState == USBDeviceState_USBDeviceHeld)
     376    {
     377        /* can perform immediate capture, inform the VM process */
     378
     379        ComPtr <IUSBDevice> d = this;
     380
     381        mIsStatePending = true;
     382
     383        /* the VM process will query the object, so leave the lock */
     384        AutoLock alock (this);
     385        alock.leave();
     386
     387        LogFlowThisFunc (("Calling machine->onUSBDeviceAttach()...\n"));
     388
     389        HRESULT rc = aMachine->onUSBDeviceAttach (d, NULL);
     390
     391        LogFlowThisFunc (("Done machine->onUSBDeviceAttach()=%08X\n", rc));
     392
     393        alock.enter();
     394
     395        mIsStatePending = false;
     396
     397        if (SUCCEEDED (rc))
     398        {
     399            mState = mPendingState = USBDeviceState_USBDeviceCaptured;
     400            mMachine = aMachine;
     401            return true;
     402        }
     403
     404        return false;
     405    }
     406
     407    mIsStatePending = true;
     408    mPendingState = USBDeviceState_USBDeviceCaptured;
    382409    mMachine = aMachine;
    383410
     
    388415
    389416/**
    390  * Returns the device back to the host
    391  *
    392  * @returns VBox status code.
    393  *
    394  * @note Locks this object for writing.
    395  */
    396 int HostUSBDevice::setHostDriven()
    397 {
    398     AutoCaller autoCaller (this);
    399     AssertComRCReturn (autoCaller.rc(), VERR_INVALID_PARAMETER);
    400 
    401     AutoLock alock (this);
    402 
    403     AssertReturn (mState == USBDeviceState_USBDeviceHeld, VERR_INVALID_PARAMETER);
    404 
    405     mState = USBDeviceState_USBDeviceAvailable;
    406 
    407     return mUSBProxyService->releaseDevice (this);
    408 }
    409 
    410 /**
    411  * Resets the device as if it were just attached to the host
    412  *
    413  * @returns VBox status code.
    414  *
    415  * @note Locks this object for writing.
    416  */
    417 int HostUSBDevice::reset()
    418 {
    419     AutoCaller autoCaller (this);
    420     AssertComRCReturn (autoCaller.rc(), VERR_INVALID_PARAMETER);
    421 
    422     AutoLock alock (this);
     417 *  Requests the USB proxy service to release the device and sets the pending
     418 *  state to Available.
     419 *
     420 *  If the state change may be performed immediately (for example, the current
     421 *  state is Busy), this method does nothing.
     422 *
     423 *  @note Must be called from under the object write lock.
     424 */
     425void HostUSBDevice::requestRelease()
     426{
     427    LogFlowThisFunc (("\n"));
     428
     429    AssertReturnVoid (isLockedOnCurrentThread());
     430
     431    AssertReturnVoid (mIsStatePending == false);
     432
     433    AssertReturnVoid (
     434        mState == USBDeviceState_USBDeviceBusy ||
     435        mState == USBDeviceState_USBDeviceAvailable ||
     436        mState == USBDeviceState_USBDeviceHeld);
     437
     438    if (mState != USBDeviceState_USBDeviceHeld)
     439        return;
     440
     441    mIsStatePending = true;
     442    mPendingState = USBDeviceState_USBDeviceAvailable;
     443
     444    mUSBProxyService->releaseDevice (this);
     445}
     446
     447/**
     448 *  Requests the USB proxy service to release the device, sets the pending
     449 *  state to Held and removes the machine association if any.
     450 *
     451 *  If the state change may be performed immediately (for example, the current
     452 *  state is already Held), this method does nothing but removes the machine
     453 *  association.
     454 *
     455 *  @note Must be called from under the object write lock.
     456 */
     457void HostUSBDevice::requestHold()
     458{
     459    LogFlowThisFunc (("\n"));
     460
     461    AssertReturnVoid (isLockedOnCurrentThread());
     462
     463    AssertReturnVoid (mIsStatePending == false);
     464
     465    AssertReturnVoid (
     466        mState == USBDeviceState_USBDeviceBusy ||
     467        mState == USBDeviceState_USBDeviceAvailable ||
     468        mState == USBDeviceState_USBDeviceHeld);
     469
     470    mMachine.setNull();
     471
     472    if (mState == USBDeviceState_USBDeviceHeld)
     473        return;
     474
     475    mIsStatePending = true;
     476    mPendingState = USBDeviceState_USBDeviceHeld;
     477
     478    mUSBProxyService->captureDevice (this);
     479}
     480
     481/**
     482 *  Sets the device state from Captured to Held and preserves the machine
     483 *  association (if any). Usually called before applying filters.
     484 *
     485 *  @note Must be called from under the object write lock.
     486 */
     487void HostUSBDevice::setHeld()
     488{
     489    LogFlowThisFunc (("\n"));
     490
     491    AssertReturnVoid (isLockedOnCurrentThread());
     492
     493    AssertReturnVoid (mState == USBDeviceState_USBDeviceCaptured);
     494    AssertReturnVoid (mPendingState == USBDeviceState_USBDeviceCaptured);
     495    AssertReturnVoid (mIsStatePending == false);
    423496
    424497    mState = USBDeviceState_USBDeviceHeld;
    425     mMachine.setNull();
    426 /// @todo remove
    427 #if 0
    428     mIgnored = false;
    429 #endif
    430 
    431     /** @todo this operation might fail and cause the device to the reattached with a different address and all that. */
    432     return mUSBProxyService->resetDevice (this);
    433 }
    434 
    435 /// @todo remove
    436 #if 0
    437 /**
    438  *  Sets the state of the device, as it was reported by the host.
    439  *  This method applicable only for devices currently controlled by the host.
    440  *
    441  *  @param  aState      new state
    442  *
    443  *  @note Locks this object for writing.
    444  */
    445 void HostUSBDevice::setHostState (USBDeviceState_T aState)
    446 {
    447     AutoCaller autoCaller (this);
    448     AssertComRCReturnVoid (autoCaller.rc());
    449 
    450     AutoLock alock (this);
    451 
    452     AssertReturn (
    453         aState == USBDeviceState_USBDeviceUnavailable ||
    454         aState == USBDeviceState_USBDeviceBusy ||
    455         aState == USBDeviceState_USBDeviceAvailable,
    456         (void) 0);
    457 
    458     AssertReturn (
    459         mState == USBDeviceState_USBDeviceNotSupported || /* initial state */
    460         mState == USBDeviceState_USBDeviceUnavailable ||
    461         mState == USBDeviceState_USBDeviceBusy ||
    462         mState == USBDeviceState_USBDeviceAvailable,
    463         (void) 0);
    464 
    465     if (mState != aState)
    466     {
    467         mState = aState;
    468     }
    469 }
    470 #endif
     498}
     499
     500/**
     501 *  Resets all device data and informs the machine (if any) about the
     502 *  detachment. Must be called when this device is physically detached from
     503 *  the host.
     504 *
     505 *  @note Must be called from under the object write lock.
     506 */
     507void HostUSBDevice::reset()
     508{
     509    LogFlowThisFunc (("\n"));
     510
     511    AssertReturnVoid (isLockedOnCurrentThread());
     512
     513    if (!mMachine.isNull() && mState == USBDeviceState_USBDeviceCaptured)
     514    {
     515        /* the device is captured by a machine, instruct it to release */
     516
     517        mIsStatePending = true;
     518
     519        /* the VM process will query the object, so leave the lock */
     520        AutoLock alock (this);
     521        alock.leave();
     522
     523        LogFlowThisFunc (("Calling machine->onUSBDeviceDetach()...\n"));
     524
     525        HRESULT rc = mMachine->onUSBDeviceDetach (mId, NULL);
     526        AssertComRC (rc);
     527
     528        LogFlowThisFunc (("Done machine->onUSBDeviceDetach()=%08X\n", rc));
     529
     530        alock.enter();
     531
     532        mIsStatePending = false;
     533        mState = mPendingState = USBDeviceState_USBDeviceNotSupported;
     534    }
     535}
     536
     537/**
     538 *  Handles the finished pending state change and informs the VM process if
     539 *  necessary.
     540 *
     541 *  @note Must be called from under the object write lock.
     542 */
     543void HostUSBDevice::handlePendingStateChange()
     544{
     545    LogFlowThisFunc (("\n"));
     546
     547    AssertReturnVoid (isLockedOnCurrentThread());
     548
     549    AssertReturnVoid (mIsStatePending == true);
     550    AssertReturnVoid (mState != USBDeviceState_USBDeviceCaptured);
     551
     552    bool wasCapture = false;
     553    bool wasRelease = false;
     554
     555    HRESULT requestRC = S_OK;
     556    Bstr errorText;
     557
     558    switch (mPendingState)
     559    {
     560        case USBDeviceState_USBDeviceCaptured:
     561        {
     562            if (mState == USBDeviceState_USBDeviceHeld)
     563            {
     564                if (!mMachine.isNull())
     565                    wasCapture = true;
     566                else
     567                {
     568                    /* it is a canceled capture request. Give the device back
     569                     * to the host. */
     570                    mPendingState = USBDeviceState_USBDeviceAvailable;
     571                    mUSBProxyService->releaseDevice (this);
     572                }
     573            }
     574            else
     575            {
     576                /* couldn't capture the device, will report an error */
     577                wasCapture = true;
     578
     579                Assert (!mMachine.isNull());
     580               
     581                /// @todo more detailed error message depending on the state?
     582                //  probably need some error code/string from the USB proxy itself
     583               
     584                requestRC = E_FAIL;
     585                errorText = Utf8StrFmt (
     586                    tr ("USB device '%s' with UUID {%Vuuid} is being accessed by the host "
     587                        "computer and cannot be attached to the virtual machine."
     588                        "Please try later"),
     589                    name().raw(), id().raw());
     590            }
     591            break;
     592        }
     593        case USBDeviceState_USBDeviceAvailable:
     594        {
     595            if (mState == USBDeviceState_USBDeviceHeld)
     596            {
     597                /* couldn't release the device */
     598                wasRelease = true;
     599
     600                Assert (!mMachine.isNull());
     601
     602                /* return the captured state back */
     603                mState = USBDeviceState_USBDeviceCaptured;
     604
     605                /// @todo more detailed error message depending on the state?
     606                //  probably need some error code/string from the USB proxy itself
     607               
     608                requestRC = E_FAIL;
     609                errorText = Utf8StrFmt (
     610                    tr ("USB device '%s' with UUID {%Vuuid} is being accessed by the guest "
     611                        "computer and cannot be attached from the virtual machine."
     612                        "Please try later"),
     613                    name().raw(), id().raw());
     614            }
     615            else
     616            {
     617                if (!mMachine.isNull())
     618                    wasRelease = true;
     619                else
     620                {
     621                    /* it is a canceled release request. Leave at the host */
     622                    /// @todo we may want to re-run all filters in this case
     623                }
     624            }
     625            break;
     626        }
     627        case USBDeviceState_USBDeviceHeld:
     628        {
     629            if (mState == USBDeviceState_USBDeviceHeld)
     630            {
     631                break;
     632            }
     633            else
     634            {
     635                /* couldn't capture the device requested by the global
     636                 * filter, there is nobody to report an error to. */
     637            }
     638            break;
     639        }
     640        default:
     641            AssertFailed();
     642    }
     643
     644    ComObjPtr <VirtualBoxErrorInfo> error;
     645    if (FAILED (requestRC))
     646    {
     647        LogFlowThisFunc (("Request failed, requestRC=%08X, text='%ls'\n",
     648                          requestRC, errorText.raw()));
     649
     650        error.createObject();
     651        error->init (requestRC, COM_IIDOF (IHostUSBDevice),
     652                     Bstr (HostUSBDevice::getComponentName()),
     653                     errorText.raw());
     654    }
     655
     656    if (wasCapture)
     657    {
     658        /* inform the VM process */
     659
     660        ComPtr <IUSBDevice> d = this;
     661
     662        /* the VM process will query the object, so leave the lock */
     663        AutoLock alock (this);
     664        alock.leave();
     665
     666        LogFlowThisFunc (("Calling machine->onUSBDeviceAttach()...\n"));
     667
     668        HRESULT rc = mMachine->onUSBDeviceAttach (d, error);
     669        /// @todo we will probably want to re-run all filters on failure
     670        //  instead of asserting
     671        AssertComRC (rc);
     672
     673        LogFlowThisFunc (("Done machine->onUSBDeviceAttach()=%08X\n", rc));
     674
     675        alock.enter();
     676
     677        if (SUCCEEDED (requestRC) && SUCCEEDED (rc))
     678        {
     679            mIsStatePending = false;
     680            mState = mPendingState = USBDeviceState_USBDeviceCaptured;
     681            return;
     682        }
     683    }
     684    else if (wasRelease)
     685    {
     686        /* inform the VM process */
     687
     688        /* the VM process will query the object, so leave the lock */
     689        AutoLock alock (this);
     690        alock.leave();
     691
     692        LogFlowThisFunc (("Calling machine->onUSBDeviceDetach()...\n"));
     693
     694        HRESULT rc = mMachine->onUSBDeviceDetach (mId, error);
     695
     696        /* This call may expectedly fail with rc = NS_ERROR_FAILURE (on XPCOM)
     697         * if the VM process requests device release right before termination
     698         * and then terminates before onUSBDeviceDetach() is reached
     699         * it. Therefore, we don't assert here. On MS COM, there should be
     700         * something similar (with the different error code). */
     701
     702        LogFlowThisFunc (("Done machine->onUSBDeviceDetach()=%08X\n", rc));
     703
     704        alock.enter();
     705
     706        if (SUCCEEDED (requestRC))
     707        {
     708            /* deassociate from the machine */
     709            mMachine.setNull();
     710        }
     711    }
     712
     713    mIsStatePending = false;
     714    mPendingState = mState;
     715}
     716
     717/**
     718 *  Cancels pending state change due to machine termination.
     719 *
     720 *  @note Must be called from under the object write lock.
     721 */
     722void HostUSBDevice::cancelPendingState()
     723{
     724    LogFlowThisFunc (("\n"));
     725
     726    AssertReturnVoid (isLockedOnCurrentThread());
     727
     728    AssertReturnVoid (mIsStatePending == true);
     729    AssertReturnVoid (!mMachine.isNull());
     730
     731    switch (mPendingState)
     732    {
     733        case USBDeviceState_USBDeviceCaptured:
     734        {
     735            /* reset mMachine to deassociate it from the filter and tell
     736             * handlePendingStateChange() what to do */
     737            mMachine.setNull();
     738            break;
     739        }
     740        case USBDeviceState_USBDeviceAvailable:
     741        {
     742            /* reset mMachine to deassociate it from the filter and tell
     743             * handlePendingStateChange() what to do */
     744            mMachine.setNull();
     745            break;
     746        }
     747        default:
     748            AssertFailed();
     749    }
     750}
    471751
    472752/**
     
    495775    if (!aData.mVendorId.isMatch (mUsb->idVendor))
    496776    {
    497         LogFlowMember (("HostUSBDevice::isMatch: vendor not match %04X\n",
    498                         mUsb->idVendor));
     777        LogFlowThisFunc (("vendor not match %04X\n",
     778                          mUsb->idVendor));
    499779        return false;
    500780    }
    501781    if (!aData.mProductId.isMatch (mUsb->idProduct))
    502782    {
    503         LogFlowMember (("HostUSBDevice::isMatch: product id not match %04X\n",
    504                         mUsb->idProduct));
     783        LogFlowThisFunc (("product id not match %04X\n",
     784                          mUsb->idProduct));
    505785        return false;
    506786    }
    507787    if (!aData.mRevision.isMatch (mUsb->bcdDevice))
    508788    {
    509         LogFlowMember (("HostUSBDevice::isMatch: rev not match %04X\n",
    510                         mUsb->bcdDevice));
     789        LogFlowThisFunc (("rev not match %04X\n",
     790                          mUsb->bcdDevice));
    511791        return false;
    512792    }
     
    564844        return false;
    565845
    566     LogFlowMember (("HostUSBDevice::isMatch: returns true\n"));
     846    LogFlowThisFunc (("returns true\n"));
    567847    return true;
    568848}
     
    570850
    571851/**
    572  * Compares this device with a USBDEVICE and decides which comes first.
    573  *
    574  * @returns < 0 if this should come before pDev2.
    575  * @returns   0 if this and pDev2 are equal.
    576  * @returns > 0 if this should come after pDev2.
    577  *
    578  * @param   pDev2   Device 2.
     852 *  Compares this device with a USBDEVICE and decides which comes first.
     853 *
     854 *  @return < 0 if this should come before pDev2.
     855 *  @return   0 if this and pDev2 are equal.
     856 *  @return > 0 if this should come after pDev2.
     857 *
     858 *  @param   pDev2   Device 2.
     859 *
     860 *  @note Must be called from under the object write lock.
    579861 */
    580862int HostUSBDevice::compare (PCUSBDEVICE pDev2)
    581863{
     864    AssertReturn (isLockedOnCurrentThread(), -1);
     865
    582866    return compare (mUsb, pDev2);
    583867}
     
    585869
    586870/**
    587  * Compares two USB devices and decides which comes first.
    588  *
    589  * @returns < 0 if pDev1 should come before pDev2.
    590  * @returns   0 if pDev1 and pDev2 are equal.
    591  * @returns > 0 if pDev1 should come after pDev2.
    592  *
    593  * @param   pDev1   Device 1.
    594  * @param   pDev2   Device 2.
     871 *  Compares two USB devices and decides which comes first.
     872 *
     873 *  @return < 0 if pDev1 should come before pDev2.
     874 *  @return   0 if pDev1 and pDev2 are equal.
     875 *  @return > 0 if pDev1 should come after pDev2.
     876 *
     877 *  @param   pDev1   Device 1.
     878 *  @param   pDev2   Device 2.
    595879 */
    596880/*static*/ int HostUSBDevice::compare (PCUSBDEVICE pDev1, PCUSBDEVICE pDev2)
     
    609893
    610894/**
    611  * Updates the state of the device.
    612  *
    613  * @return true if the state has actually changed.
    614  * @return false if the state didn't change, or the change might have been caused by VBox.
    615  *
    616  * @param   aDev    The current device state as seen by the proxy backend.
    617  *
    618  * @note Locks this object for writing.
     895 *  Updates the state of the device.
     896 *
     897 *  If this method returns @c true, Host::onUSBDeviceStateChanged() will be
     898 *  called to process the state change (complete the state change request,
     899 *  inform the VM process etc.).
     900 *
     901 *  If this method returns @c false, it is assumed that the given state change
     902 *  is "minor": it doesn't require any further action other than update the
     903 *  mState field with the actual state value.
     904 *
     905 *  @param   aDev    The current device state as seen by the proxy backend.
     906 *
     907 *  @note Locks this object for writing.
    619908 */
    620909bool HostUSBDevice::updateState (PCUSBDEVICE aDev)
    621910{
     911    LogFlowThisFunc (("\n"));
     912
     913    AssertReturn (isLockedOnCurrentThread(), false);
     914
    622915    AutoCaller autoCaller (this);
    623916    AssertComRCReturn (autoCaller.rc(), false);
    624917
    625918    AutoLock alock (this);
     919
     920    bool isImportant = false;
    626921
    627922    /*
     
    629924     * doesn't necessarily know everything that's going on. So, rather
    630925     * be overly careful than changing the state once when we shouldn't!
     926     *
     927     * In particular, we treat changing between three states Unavailable, Busy
     928     * and Available as non-important (because they all mean that the device
     929     * is owned by the host) and return false in this case. We may want to
     930     * change it later and, e.g. re-run all USB filters when the device goes from
     931     * from Busy to Available).
    631932     */
     933
    632934    switch (aDev->enmState)
    633935    {
     
    642944            {
    643945                case USBDeviceState_USBDeviceUnavailable:
    644                 /* the proxy may confuse following states with unavailable */
    645                 case USBDeviceState_USBDeviceHeld:
    646                 case USBDeviceState_USBDeviceCaptured:
    647946                    return false;
     947                /* the following state changes don't require any action for now */
     948                case USBDeviceState_USBDeviceBusy:
     949                case USBDeviceState_USBDeviceAvailable:
     950                    isImportant = false;
    648951                default:
    649                     LogFlowMember ((" HostUSBDevice::updateState: %d -> %d\n",
    650                                     mState, USBDeviceState_USBDeviceUnavailable));
    651                     mState = USBDeviceState_USBDeviceUnavailable;
    652                     return true;
     952                    isImportant = true;
    653953            }
    654             break;
     954            LogFlowThisFunc (("%d -> %d\n",
     955                              mState, USBDeviceState_USBDeviceUnavailable));
     956            mState = USBDeviceState_USBDeviceUnavailable;
     957            return isImportant;
    655958
    656959        case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
     
    658961            {
    659962                case USBDeviceState_USBDeviceBusy:
    660                 /* the proxy may confuse following states with capturable */
    661                 case USBDeviceState_USBDeviceHeld:
    662                 case USBDeviceState_USBDeviceCaptured:
    663963                    return false;
     964                /* the following state changes don't require any action for now */
     965                case USBDeviceState_USBDeviceUnavailable:
     966                case USBDeviceState_USBDeviceAvailable:
     967                    isImportant = false;
    664968                default:
    665                     LogFlowMember ((" HostUSBDevice::updateState: %d -> %d\n",
    666                                     mState, USBDeviceState_USBDeviceBusy));
    667                     mState = USBDeviceState_USBDeviceBusy;
    668                     return true;
     969                    isImportant = true;
    669970            }
    670             break;
     971            LogFlowThisFunc (("%d -> %d\n",
     972                              mState, USBDeviceState_USBDeviceBusy));
     973            mState = USBDeviceState_USBDeviceBusy;
     974            return isImportant;
    671975
    672976        case USBDEVICESTATE_UNUSED:
     
    674978            {
    675979                case USBDeviceState_USBDeviceAvailable:
    676                 /* the proxy may confuse following state(s) with available */
    677                 case USBDeviceState_USBDeviceHeld:
    678                 case USBDeviceState_USBDeviceCaptured:
    679980                    return false;
     981                /* the following state changes don't require any action for now */
     982                case USBDeviceState_USBDeviceUnavailable:
     983                case USBDeviceState_USBDeviceBusy:
     984                    isImportant = false;
    680985                default:
    681                     LogFlowMember ((" HostUSBDevice::updateState: %d -> %d\n",
    682                                     mState, USBDeviceState_USBDeviceAvailable));
    683                     mState = USBDeviceState_USBDeviceAvailable;
    684                     return true;
     986                    isImportant = true;
    685987            }
    686             break;
     988            LogFlowThisFunc (("%d -> %d\n",
     989                              mState, USBDeviceState_USBDeviceAvailable));
     990            mState = USBDeviceState_USBDeviceAvailable;
     991            return isImportant;
    687992
    688993        case USBDEVICESTATE_HELD_BY_PROXY:
     
    690995            {
    691996                case USBDeviceState_USBDeviceHeld:
    692                 /* the proxy may confuse following state(s) with held */
    693                 case USBDeviceState_USBDeviceAvailable:
    694                 case USBDeviceState_USBDeviceBusy:
    695                 case USBDeviceState_USBDeviceCaptured:
    696997                    return false;
    697998                default:
    698                     LogFlowMember ((" HostUSBDevice::updateState: %d -> %d\n",
    699                                     mState, USBDeviceState_USBDeviceHeld));
     999                    LogFlowThisFunc (("%d -> %d\n",
     1000                                      mState, USBDeviceState_USBDeviceHeld));
    7001001                    mState = USBDeviceState_USBDeviceHeld;
    7011002                    return true;
     
    7041005
    7051006        case USBDEVICESTATE_USED_BY_GUEST:
     1007            /* @todo USBDEVICESTATE_USED_BY_GUEST seems not to be used
     1008             * anywhere in the proxy code; it's quite logical because the
     1009             * proxy doesn't know anything about guest VMs. */
     1010            AssertFailed();
     1011#if 0
    7061012            switch (mState)
    7071013            {
     
    7131019                    return false;
    7141020                default:
    715                     LogFlowMember ((" HostUSBDevice::updateState: %d -> %d\n",
    716                                     mState, USBDeviceState_USBDeviceHeld));
     1021                    LogFlowThisFunc (("%d -> %d\n",
     1022                                      mState, USBDeviceState_USBDeviceHeld));
    7171023                    mState = USBDeviceState_USBDeviceHeld;
    7181024                    return true;
    7191025            }
     1026#endif
    7201027            break;
    7211028    }
  • trunk/src/VBox/Main/MachineImpl.cpp

    r2980 r3001  
    77097709 *  @note Locks the same as Host::captureUSBDevice() does.
    77107710 */
    7711 STDMETHODIMP SessionMachine::CaptureUSBDevice (INPTR GUIDPARAM aId,
    7712                                                IUSBDevice **aHostDevice)
     7711STDMETHODIMP SessionMachine::CaptureUSBDevice (INPTR GUIDPARAM aId)
    77137712{
    77147713    LogFlowThisFunc (("\n"));
    77157714
    7716     if (!aHostDevice)
    7717         return E_POINTER;
    7718 
    77197715    AutoCaller autoCaller (this);
    77207716    AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
    77217717
    77227718    // if cautureUSBDevice() fails, it must have set extended error info
    7723     return mParent->host()->captureUSBDevice (this, aId, aHostDevice);
     7719    return mParent->host()->captureUSBDevice (this, aId);
    77247720}
    77257721
     
    77457741 *  @note Locks what called methods lock.
    77467742 */
    7747 STDMETHODIMP SessionMachine::AutoCaptureUSBDevices (IUSBDeviceCollection **aHostDevices)
     7743STDMETHODIMP SessionMachine::AutoCaptureUSBDevices()
    77487744{
    77497745    LogFlowThisFunc (("\n"));
     
    77567752    NOREF (rc);
    77577753
    7758     return mParent->host()->autoCaptureUSBDevices (this, aHostDevices);
     7754    return mParent->host()->autoCaptureUSBDevices (this);
    77597755}
    77607756
     
    85848580 *  @note Locks this object for reading.
    85858581 */
    8586 HRESULT SessionMachine::onUSBDeviceAttach (IUSBDevice *aDevice)
     8582HRESULT SessionMachine::onUSBDeviceAttach (IUSBDevice *aDevice,
     8583                                           IVirtualBoxErrorInfo *aError)
    85878584{
    85888585    LogFlowThisFunc (("\n"));
     
    86018598        return S_OK;
    86028599
    8603     return directControl->OnUSBDeviceAttach (aDevice);
     8600    return directControl->OnUSBDeviceAttach (aDevice, aError);
    86048601}
    86058602
     
    86078604 *  @note Locks this object for reading.
    86088605 */
    8609 HRESULT SessionMachine::onUSBDeviceDetach (INPTR GUIDPARAM aId)
     8606HRESULT SessionMachine::onUSBDeviceDetach (INPTR GUIDPARAM aId,
     8607                                           IVirtualBoxErrorInfo *aError)
    86108608{
    86118609    LogFlowThisFunc (("\n"));
     
    86248622        return S_OK;
    86258623
    8626     return directControl->OnUSBDeviceDetach (aId);
     8624    return directControl->OnUSBDeviceDetach (aId, aError);
    86278625}
    86288626
  • trunk/src/VBox/Main/SessionImpl.cpp

    r2981 r3001  
    562562}
    563563
    564 STDMETHODIMP Session::OnUSBDeviceAttach (IUSBDevice *aDevice)
     564STDMETHODIMP Session::OnUSBDeviceAttach (IUSBDevice *aDevice,
     565                                         IVirtualBoxErrorInfo *aError)
    565566{
    566567    LogFlowThisFunc (("\n"));
     
    573574                  mType == SessionType_DirectSession, E_FAIL);
    574575
    575     return mConsole->onUSBDeviceAttach (aDevice);
    576 }
    577 
    578 STDMETHODIMP Session::OnUSBDeviceDetach (INPTR GUIDPARAM aId)
     576    return mConsole->onUSBDeviceAttach (aDevice, aError);
     577}
     578
     579STDMETHODIMP Session::OnUSBDeviceDetach (INPTR GUIDPARAM aId,
     580                                         IVirtualBoxErrorInfo *aError)
    579581{
    580582    LogFlowThisFunc (("\n"));
     
    587589                  mType == SessionType_DirectSession, E_FAIL);
    588590
    589     return mConsole->onUSBDeviceDetach (aId);
     591    return mConsole->onUSBDeviceDetach (aId, aError);
    590592}
    591593
  • trunk/src/VBox/Main/USBControllerImpl.cpp

    r2981 r3001  
    10111011    AutoReaderLock alock (this);
    10121012
     1013    /* Disabled USB controllers cannot actually work with USB devices */
     1014    if (!mData->mEnabled)
     1015        return false;
     1016
    10131017    bool match = false;
    10141018
     
    10451049
    10461050    AutoReaderLock alock (this);
     1051
     1052    /* Disabled USB controllers cannot actually work with USB devices */
     1053    if (!mData->mEnabled)
     1054        return false;
    10471055
    10481056    HRESULT rc = S_OK;
  • trunk/src/VBox/Main/USBProxyService.cpp

    r2981 r3001  
    3636    : mHost (aHost), mThread (NIL_RTTHREAD), mTerminate (false), mDevices (), mLastError (VINF_SUCCESS)
    3737{
    38     LogFlowMember (("USBProxyService::USBProxyService: aHost=%p\n", aHost));
     38    LogFlowThisFunc (("aHost=%p\n", aHost));
    3939}
    4040
     
    4545USBProxyService::~USBProxyService()
    4646{
    47     LogFlowMember (("USBProxyService::~USBProxyService: \n"));
     47    LogFlowThisFunc (("\n"));
    4848    Assert (mThread == NIL_RTTHREAD);
    4949    mDevices.clear();
     
    8484        AssertRC (rc);
    8585        if (VBOX_SUCCESS (rc))
    86             LogFlow (("USBProxyService::start: started mThread=%RTthrd\n", mThread));
     86            LogFlowThisFunc (("started mThread=%RTthrd\n", mThread));
    8787        else
    8888        {
     
    9292    }
    9393    else
    94         LogFlow (("USBProxyService::start: already running, mThread=%RTthrd\n", mThread));
     94        LogFlowThisFunc (("already running, mThread=%RTthrd\n", mThread));
    9595    return rc;
    9696}
     
    117117        if (VBOX_SUCCESS (rc))
    118118        {
    119             LogFlowMember (("USBProxyService::stop: stopped mThread=%RTthrd\n", mThread));
     119            LogFlowThisFunc (("stopped mThread=%RTthrd\n", mThread));
    120120            mThread = NIL_RTTHREAD;
    121121            mTerminate = false;
     
    128128    }
    129129    else
    130         LogFlowMember (("USBProxyService::stop: not active\n"));
     130        LogFlowThisFunc (("not active\n"));
    131131
    132132    return rc;
     
    186186void USBProxyService::processChanges (void)
    187187{
    188     LogFlowMember (("USBProxyService::processChanges: \n"));
     188    LogFlowThisFunc (("\n"));
    189189
    190190    /*
     
    195195    {
    196196        pDevices = sortDevices (pDevices);
     197
     198        /* we need to lock the host object for writing because
     199         * a) the subsequent code may call Host methods that require a write
     200         *    lock
     201         * b) we will lock HostUSBDevice objects below and want to make sure
     202         *    the lock order is always the same (Host, HostUSBDevice, as
     203         *    expected by Host) to avoid cross-deadlocks */
     204
     205        AutoLock hostLock (mHost);
    197206
    198207        /*
     
    204213               ||   pDevices)
    205214        {
     215            ComObjPtr <HostUSBDevice> DevPtr;
     216
     217            if (It != mDevices.end())
     218                DevPtr = *It;
     219
     220            /// @todo we want to AddCaller here to make sure the device hasn't
     221            //  been uninitialized (needs support for the no-op AddCaller when
     222            //  its argument is NULL)
     223
     224            /* Lock the device object since we will read/write it's
     225             * properties. All Host callbacks also imply the object is
     226             * locked. */
     227            AutoLock devLock (DevPtr.isNull() ? NULL : DevPtr);
     228
    206229            /*
    207230             * Compare.
    208231             */
    209             ComObjPtr <HostUSBDevice> DevPtr;
    210232            int iDiff;
    211             if (It == mDevices.end())
     233            if (DevPtr.isNull())
    212234                iDiff = 1;
    213235            else
    214236            {
    215                 DevPtr = *It;
    216237                if (!pDevices)
    217238                    iDiff = -1;
     
    248269                          (HostUSBDevice *)NewObj, pNew, pNew->idVendor, pNew->idProduct, pNew->pszProduct, pNew->pszManufacturer));
    249270
     271                    /* not really necessary to lock here, but make Assert
     272                     * checks happy */
     273                    AutoLock newDevLock (NewObj);
     274                   
    250275                    mDevices.insert (It, NewObj);
    251276                    mHost->onUSBDeviceAttached (NewObj);
     
    257282                     */
    258283                    /** @todo add a timeout here. */
    259                     if (!DevPtr->isStatePendingUnlocked())
     284                    if (!DevPtr->isStatePending())
    260285                    {
    261286                        It = mDevices.erase (It);
     
    263288                        Log (("USBProxyService::processChanges: detached %p\n", (HostUSBDevice *)DevPtr)); /** @todo add details .*/
    264289                    }
    265                     /* else: operation pending */
     290                    else
     291                    {
     292                        /* a state change (re-cycle) request is pending, go
     293                         * to the next device */
     294                        It++;
     295                    }
    266296                }
    267297            }
     
    270300    else
    271301    {
     302        /* we need to lock the host object for writing because
     303         * a) the subsequent code may call Host methods that require a write
     304         *    lock
     305         * b) we will lock HostUSBDevice objects below and want to make sure
     306         *    the lock order is always the same (Host, HostUSBDevice, as
     307         *    expected by Host) to avoid cross-deadlocks */
     308
     309        AutoLock hostLock (mHost);
     310
    272311        /* All devices were detached */
    273312        HostUSBDeviceList::iterator It = this->mDevices.begin();
     
    275314        {
    276315            ComObjPtr <HostUSBDevice> DevPtr = *It;
     316           
     317            AutoLock devLock (DevPtr);
     318
    277319            /*
    278320             * DevPtr was detached.
     
    284326    }
    285327
    286     LogFlowMember (("USBProxyService::processChanges: returns void\n"));
     328    LogFlowThisFunc (("returns void\n"));
    287329}
    288330
     
    291333{
    292334    USBProxyService *pThis = (USBProxyService *)pvUser;
    293     LogFlow (("USBProxyService::serviceThread: pThis=%p\n", pThis));
     335    LogFlowFunc (("pThis=%p\n", pThis));
    294336    pThis->serviceThreadInit();
    295337
     
    306348
    307349    pThis->serviceThreadTerm();
    308     LogFlow (("USBProxyService::serviceThread: returns VINF_SUCCESS\n"));
     350    LogFlowFunc (("returns VINF_SUCCESS\n"));
    309351    return VINF_SUCCESS;
    310352}
     
    378420bool USBProxyService::updateDeviceStateFake (HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice)
    379421{
    380     if (aDevice->isStatePendingUnlocked())
    381     {
    382         switch (aDevice->pendingStateUnlocked())
    383         {
    384             case USBDeviceState_USBDeviceCaptured:      aUSBDevice->enmState = USBDEVICESTATE_USED_BY_GUEST; break;
     422    AssertReturn (aDevice, false);
     423    AssertReturn (aDevice->isLockedOnCurrentThread(), false);
     424
     425    if (aDevice->isStatePending())
     426    {
     427        switch (aDevice->pendingState())
     428        {
     429            /* @todo USBDEVICESTATE_USED_BY_GUEST seems not to be used anywhere in the proxy code; it's
     430             * quite logical because the proxy doesn't know anything about guest VMs. We use HELD_BY_PROXY
     431             * instead -- it is sufficient and is what Main expects. */
     432            case USBDeviceState_USBDeviceCaptured:      aUSBDevice->enmState = USBDEVICESTATE_HELD_BY_PROXY; break;
    385433            case USBDeviceState_USBDeviceHeld:          aUSBDevice->enmState = USBDEVICESTATE_HELD_BY_PROXY; break;
    386434            case USBDeviceState_USBDeviceAvailable:     aUSBDevice->enmState = USBDEVICESTATE_UNUSED; break;
     
    388436            case USBDeviceState_USBDeviceBusy:          aUSBDevice->enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE; break;
    389437            default:
    390                 AssertMsgFailed(("%d\n", aDevice->pendingStateUnlocked()));
     438                AssertMsgFailed(("%d\n", aDevice->pendingState()));
    391439                break;
    392440        }
     
    471519bool USBProxyService::updateDeviceState (HostUSBDevice *pDevice, PUSBDEVICE pUSBDevice)
    472520{
     521    AssertReturn (pDevice, false);
     522    AssertReturn (pDevice->isLockedOnCurrentThread(), false);
     523
    473524    return pDevice->updateState (pUSBDevice);
    474525}
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r2988 r3001  
    16001600    <interface
    16011601        name="IInternalMachineControl" extends="$unknown"
    1602         uuid="e780b585-585d-47e2-ab53-e94dc552353c"
     1602        uuid="67ef427d-5f01-4791-a45e-ae5e646ed7c6"
    16031603        internal="yes"
    16041604        wsmap="suppress"
     
    16371637        <method name="captureUSBDevice">
    16381638            <desc>
    1639                 Requests a capture of the given host USB device, and returns
    1640                 the captured device (as IUSBDevice) to the caller.
    1641                 <note>
    1642                     The server must mark the device as USBDeviceCaptured
    1643                     during this call.
    1644 
    1645                     This method must return extended error info in case of any
    1646                     eroror (<link to="IConsole::detachUSBDevice()"/>) relies
    1647                     on this.
    1648                 </note>
     1639                Requests a capture of the given host USB device.
     1640                When the request is completed, the VM process will
     1641                get a <link to="IInternalSessionControl::onUSBDeviceAttach"/>
     1642                notification.
    16491643            </desc>
    16501644            <param name="id" type="uuid" dir="in"/>
    1651             <param name="hostDevice" type="IUSBDevice" dir="return"/>
    16521645        </method>
    16531646
    16541647        <method name="releaseUSBDevice">
    16551648            <desc>
    1656                 Releases the given USB device.
     1649                Requests to release the given USB device.
     1650                When the request is completed, the VM process will
     1651                get a <link to="IInternalSessionControl::onUSBDeviceDetach"/>
     1652                notification.
    16571653                <note>
    16581654                    The server must run its own filters and filters of all VMs
    1659                     but this one on the given device as if it were just attached
    1660                     to the host computer.
     1655                    but this one on all released devices as if they were just
     1656                    attached to the host computer.
    16611657                </note>
    16621658            </desc>
     
    16661662        <method name="autoCaptureUSBDevices">
    16671663            <desc>
    1668                 Queries the list of available devices that must be auto-captured
    1669                 according to this VM's filters. Devices returned as IUSBDevice
    1670                 instances.
    1671                 <note>
    1672                     The server must mark all returned devices as USBDeviceCaptured
    1673                     during this call.
    1674                 </note>
    1675             </desc>
    1676             <param name="hostDevices" type="IUSBDeviceCollection" dir="return"/>
     1664                Requests a capture all matching USB devices attached to the host.
     1665                When the request is completed, the VM process will
     1666                get a <link to="IInternalSessionControl::onUSBDeviceAttach"/>
     1667                notification per every captured device.
     1668            </desc>
    16771669        </method>
    16781670
     
    26472639    <interface
    26482640        name="IConsoleCallback" extends="$unknown"
    2649         uuid="a56eff10-6db9-4985-a12a-039b604b491b"
     2641        uuid="ebd0c5f2-7b11-4508-803f-012099caee03"
    26502642        wsmap="suppress"
    26512643    >
     
    27482740                find out what has changed.
    27492741            </desc>
     2742        </method>
     2743
     2744        <method name="onUSBDeviceStateChange">
     2745            <desc>
     2746                Notification when a USB device is attached to or detached from
     2747                the virtual USB controller.
     2748
     2749                This notification is sent as a result of the indirect
     2750                request to attach the device because it matches one of the
     2751                machine USB filters, or as a result of the direct request
     2752                issued by <link to="IConsole::attachUSBDevice"/> or
     2753                <link to="IConsole::detachUSBDevice"/>.
     2754
     2755                This notification is sent in case of both a succeeded and a
     2756                failed request completion. When the request succeeds, the @a
     2757                error parameter is @c null, and the given device has been
     2758                already added to (when @a attached is @c true) or removed from
     2759                (when @a attached is @c false) the collection represented by
     2760                <link to="IConsole::USBDevices"/>. On failure, the collection
     2761                doesn't change and the @a error perameter represents the error
     2762                message describing the failure.
     2763
     2764            </desc>
     2765            <param name="device" type="IUSBDevice" dir="in">
     2766                <desc>Device that is subject to state change.</desc>
     2767            </param>
     2768            <param name="attached" type="boolean" dir="in">
     2769                <desc>
     2770                    <tt>true</tt> if the device was attached
     2771                    and <tt>false</tt> otherwise.
     2772                </desc>
     2773            </param>
     2774            <param name="error" type="IVirtualBoxErrorInfo" dir="in">
     2775                <desc>
     2776                   <tt>null</tt> on success or an error message object on
     2777                   failure.
     2778                </desc>
     2779            </param>
    27502780        </method>
    27512781
     
    74117441    <interface
    74127442        name="IInternalSessionControl" extends="$unknown"
    7413         uuid="9c6bec01-4135-40a0-b9d3-ab119a9c5412"
     7443        uuid="80a9b698-cc60-48cf-ab88-a7c2ea4013a6"
    74147444        internal="yes"
    74157445        wsmap="suppress"
     
    74997529        <method name="onUSBDeviceAttach">
    75007530            <desc>
    7501                 Triggered when a USB device has just been attached to the host
    7502                 computer and is to be auto-captured by the machine according
    7503                 to its USB filters.
     7531                Triggered when a request to capture a USB device (as a result
     7532                of matched USB filters or direct call to
     7533                <link to="IConsole::attachUSBDevice"/>) has completed.
     7534                A @c null @a error object means success, otherwise it
     7535                describes a failure.
    75047536            </desc>
    75057537            <param name="device" type="IUSBDevice" dir="in"/>
     7538            <param name="error" type="IVirtualBoxErrorInfo" dir="in"/>
    75067539        </method>
    75077540
    75087541        <method name="onUSBDeviceDetach">
    75097542            <desc>
    7510                 Triggered when a USB device has just been detached from the host
    7511                 computer and needs to be detached from the machine.
     7543                Triggered when a request to release the USB device (as a result
     7544                of machine termination or direct call to
     7545                <link to="IConsole::detachUSBDevice"/>) has completed.
     7546                A @c null @a error object means success, otherwise it
    75127547            </desc>
    75137548            <param name="id" type="uuid" dir="in"/>
     7549            <param name="error" type="IVirtualBoxErrorInfo" dir="in"/>
    75147550        </method>
    75157551
  • trunk/src/VBox/Main/include/ConsoleImpl.h

    r2981 r3001  
    174174    HRESULT onVRDPServerChange();
    175175    HRESULT onUSBControllerChange();
    176     HRESULT onUSBDeviceAttach(IUSBDevice *aDevice);
    177     HRESULT onUSBDeviceDetach(INPTR GUIDPARAM aId);
     176    HRESULT onUSBDeviceAttach (IUSBDevice *aDevice, IVirtualBoxErrorInfo *aError);
     177    HRESULT onUSBDeviceDetach (INPTR GUIDPARAM aId, IVirtualBoxErrorInfo *aError);
    178178
    179179    VMMDev *getVMMDev() { return mVMMDev; }
     
    198198    void onAdditionsOutdated();
    199199    void onKeyboardLedsChange (bool fNumLock, bool fCapsLock, bool fScrollLock);
     200    void onUSBDeviceStateChange (IUSBDevice *aDevice, bool aAttached,
     201                                 IVirtualBoxErrorInfo *aError);
    200202    void onRuntimeError (BOOL aFatal, INPTR BSTR aErrorID, INPTR BSTR aMessage);
    201203    HRESULT onShowWindow (BOOL aCheck, BOOL *aCanShow, ULONG64 *aWinId);
     
    369371                                          const char *pszPath, bool fPassthrough);
    370372
    371     HRESULT attachUSBDevice (IUSBDevice *aHostDevice, bool aManual,
    372                              PVUSBIRHCONFIG aConfig);
     373    HRESULT attachUSBDevice (IUSBDevice *aHostDevice, PVUSBIRHCONFIG aConfig);
    373374
    374375    static DECLCALLBACK(int)
     
    378379    static DECLCALLBACK(int)
    379380    usbDetachCallback (Console *that, USBDeviceList::iterator *aIt,
    380                        bool aManual, PVUSBIRHCONFIG aConfig, PCRTUUID aUuid);
     381                       PVUSBIRHCONFIG aConfig, PCRTUUID aUuid);
    381382
    382383    static DECLCALLBACK (int)
  • trunk/src/VBox/Main/include/DisplayImpl.h

    r2981 r3001  
    103103    }
    104104
     105    STDMETHOD(OnUSBDeviceStateChange)(IUSBDevice *device, BOOL attached,
     106                                      IVirtualBoxErrorInfo *message)
     107    {
     108        return S_OK;
     109    }
     110
    105111    STDMETHOD(OnRuntimeError)(BOOL fatal, INPTR BSTR id, INPTR BSTR message)
    106112    {
  • trunk/src/VBox/Main/include/HostImpl.h

    r2981 r3001  
    105105    HRESULT saveSettings (CFGNODE aGlobal);
    106106
    107     HRESULT captureUSBDevice (SessionMachine *aMachine, INPTR GUIDPARAM aId,
    108                               IUSBDevice **aHostDevice);
     107    HRESULT captureUSBDevice (SessionMachine *aMachine, INPTR GUIDPARAM aId);
    109108    HRESULT releaseUSBDevice (SessionMachine *aMachine, INPTR GUIDPARAM aId);
    110     HRESULT autoCaptureUSBDevices (SessionMachine *aMachine,
    111                                    IUSBDeviceCollection **aHostDevices);
     109    HRESULT autoCaptureUSBDevices (SessionMachine *aMachine);
    112110    HRESULT releaseAllUSBDevices (SessionMachine *aMachine);
    113111
     
    149147    }
    150148
    151     HRESULT applyAllUSBFilters (ComObjPtr <HostUSBDevice> &aDevice,
    152                                 SessionMachine *aMachine = NULL);
    153     void applyMachineUSBFilters (SessionMachine *aMachine,
     149    HRESULT applyAllUSBFilters (ComObjPtr <HostUSBDevice> &aDevice);
     150
     151    bool applyMachineUSBFilters (SessionMachine *aMachine,
    154152                                 ComObjPtr <HostUSBDevice> &aDevice);
    155153
  • trunk/src/VBox/Main/include/HostUSBDeviceImpl.h

    r2981 r3001  
    9191    USBDeviceState_T state() const { return mState; }
    9292
    93     /** Same as state() except you don't need to lock any thing. */
    94     USBDeviceState_T stateUnlocked() const
    95     {
    96         AutoReaderLock (this);
    97         return state();
    98     }
    99 
    10093    /* @note Must be called from under the object read lock. */
    10194    USBDeviceState_T pendingState() const { return mPendingState; }
    10295
    103     /** Same as pendingState() except you don't need to lock any thing. */
    104     USBDeviceState_T pendingStateUnlocked() const
    105     {
    106         AutoReaderLock (this);
    107         return pendingState();
    108     }
    109 
    11096    /* @note Must be called from under the object read lock. */
    11197    ComObjPtr <SessionMachine, ComWeakRef> &machine() { return mMachine; }
    11298
    113 /// @todo remove
    114 #if 0
    115     /* @note Must be called from under the object read lock. */
    116     bool isIgnored() { return mIgnored; }
    117 #endif
    118 
    11999    /* @note Must be called from under the object read lock. */
    120100    bool isStatePending() const { return mIsStatePending; }
    121101
    122     /** Same as isStatePending() except you don't need to lock any thing. */
    123     bool isStatePendingUnlocked() const
    124     {
    125         AutoReaderLock (this);
    126         return isStatePending();
    127     }
    128 
    129102    /* @note Must be called from under the object read lock. */
    130103    PCUSBDEVICE usbData() const { return mUsb; }
     
    132105    Utf8Str name();
    133106
    134 /// @todo remove
    135 #if 0
    136     void setIgnored();
    137 #endif
    138 
    139     bool setCaptured (SessionMachine *aMachine);
    140     int  setHostDriven();
    141     int  reset();
    142 
    143 /// @todo remove
    144 #if 0
    145     void setHostState (USBDeviceState_T aState);
    146 #endif
     107    bool requestCapture (SessionMachine *aMachine);
     108    void requestRelease();
     109    void requestHold();
     110
     111    void setHeld();
     112    void reset();
     113
     114    void handlePendingStateChange();
     115    void cancelPendingState();
    147116
    148117    bool isMatch (const USBDeviceFilter::Data &aData);
     
    163132    ComObjPtr <SessionMachine, ComWeakRef> mMachine;
    164133    bool mIsStatePending : 1;
    165 /// @todo remove
    166 #if 0
    167     bool mIgnored : 1;
    168 #endif
    169134
    170135    /** Pointer to the USB Proxy Service instance. */
  • trunk/src/VBox/Main/include/MachineImpl.h

    r2981 r3001  
    727727    STDMETHOD(GetIPCId)(BSTR *id);
    728728    STDMETHOD(RunUSBDeviceFilters) (IUSBDevice *aUSBDevice, BOOL *aMatched);
    729     STDMETHOD(CaptureUSBDevice) (INPTR GUIDPARAM aId, IUSBDevice **aHostDevice);
     729    STDMETHOD(CaptureUSBDevice) (INPTR GUIDPARAM aId);
    730730    STDMETHOD(ReleaseUSBDevice) (INPTR GUIDPARAM aId);
    731     STDMETHOD(AutoCaptureUSBDevices) (IUSBDeviceCollection **aHostDevices);
     731    STDMETHOD(AutoCaptureUSBDevices)();
    732732    STDMETHOD(ReleaseAllUSBDevices)();
    733733    STDMETHOD(OnSessionEnd)(ISession *aSession, IProgress **aProgress);
     
    758758    HRESULT onVRDPServerChange();
    759759    HRESULT onUSBControllerChange();
    760     HRESULT onUSBDeviceAttach (IUSBDevice *aDevice);
    761     HRESULT onUSBDeviceDetach (INPTR GUIDPARAM aId);
     760    HRESULT onUSBDeviceAttach (IUSBDevice *aDevice,
     761                               IVirtualBoxErrorInfo *aError);
     762    HRESULT onUSBDeviceDetach (INPTR GUIDPARAM aId,
     763                               IVirtualBoxErrorInfo *aError);
    762764
    763765private:
  • trunk/src/VBox/Main/include/SessionImpl.h

    r2981 r3001  
    100100    STDMETHOD(OnVRDPServerChange)();
    101101    STDMETHOD(OnUSBControllerChange)();
    102     STDMETHOD(OnUSBDeviceAttach) (IUSBDevice *aDevice);
    103     STDMETHOD(OnUSBDeviceDetach) (INPTR GUIDPARAM aId);
     102    STDMETHOD(OnUSBDeviceAttach) (IUSBDevice *aDevice, IVirtualBoxErrorInfo *aError);
     103    STDMETHOD(OnUSBDeviceDetach) (INPTR GUIDPARAM aId, IVirtualBoxErrorInfo *aError);
    104104    STDMETHOD(OnShowWindow) (BOOL aCheck, BOOL *aCanShow, ULONG64 *aWinId);
    105105
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette