VirtualBox

source: vbox/trunk/src/VBox/Main/HostUSBDeviceImpl.cpp@ 33238

Last change on this file since 33238 was 32718, checked in by vboxsync, 14 years ago

com/string: Remove bool conversion operator and other convenience error operators. They are hiding programming errors (like incorrect empty string checks, and in one case a free of the wrong pointer).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 91.4 KB
Line 
1/* $Id: HostUSBDeviceImpl.cpp 32718 2010-09-23 12:57:52Z vboxsync $ */
2/** @file
3 * VirtualBox IHostUSBDevice COM interface implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <iprt/types.h> /* for UINT64_C */
19
20#include "HostUSBDeviceImpl.h"
21#include "MachineImpl.h"
22#include "HostImpl.h"
23#include "VirtualBoxErrorInfoImpl.h"
24#include "USBProxyService.h"
25
26#include "AutoCaller.h"
27#include "Logging.h"
28
29#include <VBox/err.h>
30#include <iprt/cpp/utils.h>
31
32// constructor / destructor
33/////////////////////////////////////////////////////////////////////////////
34
35DEFINE_EMPTY_CTOR_DTOR (HostUSBDevice)
36
37HRESULT HostUSBDevice::FinalConstruct()
38{
39 mUSBProxyService = NULL;
40 mUsb = NULL;
41
42 return S_OK;
43}
44
45void HostUSBDevice::FinalRelease()
46{
47 uninit();
48}
49
50// public initializer/uninitializer for internal purposes only
51/////////////////////////////////////////////////////////////////////////////
52
53/**
54 * Initializes the USB device object.
55 *
56 * @returns COM result indicator
57 * @param aUsb Pointer to the usb device structure for which the object is to be a wrapper.
58 * This structure is now fully owned by the HostUSBDevice object and will be
59 * freed when it is destructed.
60 * @param aUSBProxyService Pointer to the USB Proxy Service object.
61 */
62HRESULT HostUSBDevice::init(PUSBDEVICE aUsb, USBProxyService *aUSBProxyService)
63{
64 ComAssertRet(aUsb, E_INVALIDARG);
65
66 /* Enclose the state transition NotReady->InInit->Ready */
67 AutoInitSpan autoInitSpan(this);
68 AssertReturn(autoInitSpan.isOk(), E_FAIL);
69
70 /*
71 * We need a unique ID for this VBoxSVC session.
72 * The UUID isn't stored anywhere.
73 */
74 unconst(mId).create();
75
76 /*
77 * Set the initial device state.
78 */
79 AssertMsgReturn( aUsb->enmState >= USBDEVICESTATE_UNSUPPORTED
80 && aUsb->enmState < USBDEVICESTATE_USED_BY_GUEST, /* used-by-guest is not a legal initial state. */
81 ("%d\n", aUsb->enmState), E_FAIL);
82 mUniState = (HostUSBDeviceState)aUsb->enmState;
83 mUniSubState = kHostUSBDeviceSubState_Default;
84 mPendingUniState = kHostUSBDeviceState_Invalid;
85 mPrevUniState = mUniState;
86 mIsPhysicallyDetached = false;
87
88 /* Other data members */
89 mUSBProxyService = aUSBProxyService;
90 mUsb = aUsb;
91
92 /* Set the name. */
93 mNameObj = getName();
94 mName = mNameObj.c_str();
95
96 /* Confirm the successful initialization */
97 autoInitSpan.setSucceeded();
98
99 return S_OK;
100}
101
102/**
103 * Uninitializes the instance and sets the ready flag to FALSE.
104 * Called either from FinalRelease() or by the parent when it gets destroyed.
105 */
106void HostUSBDevice::uninit()
107{
108 /* Enclose the state transition Ready->InUninit->NotReady */
109 AutoUninitSpan autoUninitSpan(this);
110 if (autoUninitSpan.uninitDone())
111 return;
112
113 if (mUsb != NULL)
114 {
115 USBProxyService::freeDevice (mUsb);
116 mUsb = NULL;
117 }
118
119 mUSBProxyService = NULL;
120 mUniState = kHostUSBDeviceState_Invalid;
121}
122
123// IUSBDevice properties
124/////////////////////////////////////////////////////////////////////////////
125
126STDMETHODIMP HostUSBDevice::COMGETTER(Id)(BSTR *aId)
127{
128 CheckComArgOutPointerValid(aId);
129
130 AutoCaller autoCaller(this);
131 if (FAILED(autoCaller.rc())) return autoCaller.rc();
132
133 /* mId is constant during life time, no need to lock */
134 mId.toUtf16().cloneTo(aId);
135
136 return S_OK;
137}
138
139STDMETHODIMP HostUSBDevice::COMGETTER(VendorId)(USHORT *aVendorId)
140{
141 CheckComArgOutPointerValid(aVendorId);
142
143 AutoCaller autoCaller(this);
144 if (FAILED(autoCaller.rc())) return autoCaller.rc();
145
146 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
147
148 *aVendorId = mUsb->idVendor;
149
150 return S_OK;
151}
152
153STDMETHODIMP HostUSBDevice::COMGETTER(ProductId)(USHORT *aProductId)
154{
155 CheckComArgOutPointerValid(aProductId);
156
157 AutoCaller autoCaller(this);
158 if (FAILED(autoCaller.rc())) return autoCaller.rc();
159
160 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
161
162 *aProductId = mUsb->idProduct;
163
164 return S_OK;
165}
166
167STDMETHODIMP HostUSBDevice::COMGETTER(Revision)(USHORT *aRevision)
168{
169 CheckComArgOutPointerValid(aRevision);
170
171 AutoCaller autoCaller(this);
172 if (FAILED(autoCaller.rc())) return autoCaller.rc();
173
174 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
175
176 *aRevision = mUsb->bcdDevice;
177
178 return S_OK;
179}
180
181STDMETHODIMP HostUSBDevice::COMGETTER(Manufacturer)(BSTR *aManufacturer)
182{
183 CheckComArgOutPointerValid(aManufacturer);
184
185 AutoCaller autoCaller(this);
186 if (FAILED(autoCaller.rc())) return autoCaller.rc();
187
188 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
189
190 Bstr (mUsb->pszManufacturer).cloneTo(aManufacturer);
191
192 return S_OK;
193}
194
195STDMETHODIMP HostUSBDevice::COMGETTER(Product)(BSTR *aProduct)
196{
197 CheckComArgOutPointerValid(aProduct);
198
199 AutoCaller autoCaller(this);
200 if (FAILED(autoCaller.rc())) return autoCaller.rc();
201
202 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
203
204 Bstr (mUsb->pszProduct).cloneTo(aProduct);
205
206 return S_OK;
207}
208
209STDMETHODIMP HostUSBDevice::COMGETTER(SerialNumber)(BSTR *aSerialNumber)
210{
211 CheckComArgOutPointerValid(aSerialNumber);
212
213 AutoCaller autoCaller(this);
214 if (FAILED(autoCaller.rc())) return autoCaller.rc();
215
216 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
217
218 Bstr (mUsb->pszSerialNumber).cloneTo(aSerialNumber);
219
220 return S_OK;
221}
222
223STDMETHODIMP HostUSBDevice::COMGETTER(Address)(BSTR *aAddress)
224{
225 CheckComArgOutPointerValid(aAddress);
226
227 AutoCaller autoCaller(this);
228 if (FAILED(autoCaller.rc())) return autoCaller.rc();
229
230 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
231
232 Bstr (mUsb->pszAddress).cloneTo(aAddress);
233
234 return S_OK;
235}
236
237STDMETHODIMP HostUSBDevice::COMGETTER(Port)(USHORT *aPort)
238{
239 CheckComArgOutPointerValid(aPort);
240
241 AutoCaller autoCaller(this);
242 if (FAILED(autoCaller.rc())) return autoCaller.rc();
243
244 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
245
246#if !defined(RT_OS_WINDOWS) /// @todo check up the bPort value on Windows before enabling this.
247 *aPort = mUsb->bPort;
248#else
249 *aPort = 0;
250#endif
251
252 return S_OK;
253}
254
255STDMETHODIMP HostUSBDevice::COMGETTER(Version)(USHORT *aVersion)
256{
257 CheckComArgOutPointerValid(aVersion);
258
259 AutoCaller autoCaller(this);
260 if (FAILED(autoCaller.rc())) return autoCaller.rc();
261
262 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
263
264 *aVersion = mUsb->bcdUSB >> 8;
265
266 return S_OK;
267}
268
269STDMETHODIMP HostUSBDevice::COMGETTER(PortVersion)(USHORT *aPortVersion)
270{
271 CheckComArgOutPointerValid(aPortVersion);
272
273 AutoCaller autoCaller(this);
274 if (FAILED(autoCaller.rc())) return autoCaller.rc();
275
276 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
277
278 /* Port version is 2 (EHCI) if and only if the device runs at high speed;
279 * if speed is unknown, fall back to the old and innacurate method.
280 */
281 if (mUsb->enmSpeed == USBDEVICESPEED_UNKNOWN)
282 *aPortVersion = mUsb->bcdUSB >> 8;
283 else
284 *aPortVersion = (mUsb->enmSpeed == USBDEVICESPEED_HIGH) ? 2 : 1;
285
286 return S_OK;
287}
288
289STDMETHODIMP HostUSBDevice::COMGETTER(Remote)(BOOL *aRemote)
290{
291 CheckComArgOutPointerValid(aRemote);
292
293 AutoCaller autoCaller(this);
294 if (FAILED(autoCaller.rc())) return autoCaller.rc();
295
296 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
297
298 *aRemote = FALSE;
299
300 return S_OK;
301}
302
303// IHostUSBDevice properties
304/////////////////////////////////////////////////////////////////////////////
305
306STDMETHODIMP HostUSBDevice::COMGETTER(State) (USBDeviceState_T *aState)
307{
308 CheckComArgOutPointerValid(aState);
309
310 AutoCaller autoCaller(this);
311 if (FAILED(autoCaller.rc())) return autoCaller.rc();
312
313 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
314
315 *aState = canonicalState();
316
317 return S_OK;
318}
319
320
321// public methods only for internal purposes
322////////////////////////////////////////////////////////////////////////////////
323
324/**
325 * @note Locks this object for reading.
326 */
327Utf8Str HostUSBDevice::getName()
328{
329 Utf8Str name;
330
331 AutoCaller autoCaller(this);
332 AssertComRCReturn (autoCaller.rc(), name);
333
334 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
335
336 bool haveManufacturer = mUsb->pszManufacturer && *mUsb->pszManufacturer;
337 bool haveProduct = mUsb->pszProduct && *mUsb->pszProduct;
338 if (haveManufacturer && haveProduct)
339 name = Utf8StrFmt ("%s %s", mUsb->pszManufacturer, mUsb->pszProduct);
340 else if (haveManufacturer)
341 name = Utf8StrFmt ("%s", mUsb->pszManufacturer);
342 else if (haveProduct)
343 name = Utf8StrFmt ("%s", mUsb->pszProduct);
344 else
345 name = "<unknown>";
346
347 return name;
348}
349
350/**
351 * Requests the USB proxy service capture the device (from the host)
352 * and attach it to a VM.
353 *
354 * As a convenience, this method will operate like attachToVM() if the device
355 * is already held by the proxy. Note that it will then perform IPC to the VM
356 * process, which means it will temporarily leave all locks. (Is this a good idea?)
357 *
358 * @param aMachine Machine this device should be attach to.
359 * @param aSetError Whether to set full error message or not to bother.
360 * @param aMaskedIfs The interfaces to hide from the guest.
361 *
362 * @returns Status indicating whether it was successfully captured and/or attached.
363 * @retval S_OK on success.
364 * @retval E_UNEXPECTED if the device state doesn't permit for any attaching.
365 * @retval E_* as appropriate.
366 *
367 * @note Must be called from under the object write lock.
368 * @note May lock the given machine object for reading.
369 */
370HRESULT HostUSBDevice::requestCaptureForVM(SessionMachine *aMachine, bool aSetError, ULONG aMaskedIfs /* = 0*/)
371{
372 LogFlowThisFunc(("{%s} aMachine=%p aMaskedIfs=%#x\n", mName, aMachine, aMaskedIfs));
373
374 /*
375 * Validate preconditions and input.
376 */
377 AssertReturn(aMachine, E_INVALIDARG);
378 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
379 if (aSetError)
380 {
381 if (mUniState == kHostUSBDeviceState_Unsupported)
382 return setError(E_INVALIDARG,
383 tr("USB device '%s' with UUID {%RTuuid} cannot be accessed by guest computers"),
384 mName, mId.raw());
385 if (mUniState == kHostUSBDeviceState_UsedByHost)
386 return setError(E_INVALIDARG,
387 tr("USB device '%s' with UUID {%RTuuid} is being exclusively used by the host computer"),
388 mName, mId.raw());
389 if (mUniState == kHostUSBDeviceState_UsedByVM)
390 {
391 /* Machine::name() requires a read lock */
392 AutoReadLock machLock(mMachine COMMA_LOCKVAL_SRC_POS);
393 return setError(E_INVALIDARG,
394 tr("USB device '%s' with UUID {%RTuuid} is already captured by the virtual machine '%ls'"),
395 mName, mId.raw(), mMachine->getName().c_str());
396 }
397 if (mUniState >= kHostUSBDeviceState_FirstTransitional)
398 return setError(E_INVALIDARG,
399 tr("USB device '%s' with UUID {%RTuuid} is busy with a previous request. Please try again later"),
400 mName, mId.raw());
401 if ( mUniState != kHostUSBDeviceState_Unused
402 && mUniState != kHostUSBDeviceState_HeldByProxy
403 && mUniState != kHostUSBDeviceState_Capturable)
404 return setError(E_INVALIDARG,
405 tr("USB device '%s' with UUID {%RTuuid} is not in the right state for capturing (%s)"),
406 mName, mId.raw(), getStateName());
407 }
408
409 AssertReturn( mUniState == kHostUSBDeviceState_HeldByProxy
410 || mUniState == kHostUSBDeviceState_Unused
411 || mUniState == kHostUSBDeviceState_Capturable,
412 E_UNEXPECTED);
413 Assert(mMachine.isNull());
414
415 /*
416 * If it's already held by the proxy, we'll simply call
417 * attachToVM synchronously.
418 */
419 if (mUniState == kHostUSBDeviceState_HeldByProxy)
420 {
421 HRESULT hrc = attachToVM(aMachine, aMaskedIfs);
422 return SUCCEEDED(hrc);
423 }
424
425 /*
426 * Need to capture the device before it can be used.
427 *
428 * The device will be attached to the VM by the USB proxy service thread
429 * when the request succeeds (i.e. asynchronously).
430 */
431 LogFlowThisFunc(("{%s} capturing the device.\n", mName));
432#if (defined(RT_OS_DARWIN) && defined(VBOX_WITH_NEW_USB_CODE_ON_DARWIN)) /* PORTME */ \
433 || defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS)
434 setState(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_UsedByVM, kHostUSBDeviceSubState_AwaitingDetach);
435#else
436 setState(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_UsedByVM);
437#endif
438 mMachine = aMachine;
439 mMaskedIfs = aMaskedIfs;
440 int rc = mUSBProxyService->captureDevice(this);
441 if (RT_FAILURE(rc))
442 {
443 failTransition();
444 mMachine.setNull();
445 if (rc == VERR_SHARING_VIOLATION)
446 return setError(E_FAIL,
447 tr("USB device '%s' with UUID {%RTuuid} is in use by someone else"),
448 mName, mId.raw());
449 return E_FAIL;
450 }
451
452 return S_OK;
453}
454
455/**
456 * Attempts to attach the USB device to a VM.
457 *
458 * The device must be in the HeldByProxy state or about to exit the
459 * Capturing state.
460 *
461 * This method will make an IPC to the VM process and do the actual
462 * attaching. While in the IPC locks will be abandond.
463 *
464 * @returns Status indicating whether it was successfully attached or not.
465 * @retval S_OK on success.
466 * @retval E_UNEXPECTED if the device state doesn't permit for any attaching.
467 * @retval E_* as appropriate.
468 *
469 * @param aMachine Machine this device should be attach to.
470 * @param aMaskedIfs The interfaces to hide from the guest.
471 */
472HRESULT HostUSBDevice::attachToVM(SessionMachine *aMachine, ULONG aMaskedIfs /* = 0*/)
473{
474 /*
475 * Validate and update the state.
476 */
477 AssertReturn( mUniState == kHostUSBDeviceState_Capturing
478 || mUniState == kHostUSBDeviceState_HeldByProxy
479 || mUniState == kHostUSBDeviceState_AttachingToVM,
480 E_UNEXPECTED);
481 setState(kHostUSBDeviceState_AttachingToVM, kHostUSBDeviceState_UsedByVM);
482
483 /*
484 * The VM process will query the object, so grab a refernce to ourselves and leave the locks.
485 */
486 ComPtr<IUSBDevice> d = this;
487
488 AutoWriteLock alockSelf(this COMMA_LOCKVAL_SRC_POS);
489 alockSelf.leave();
490 AutoWriteLock alockProxy(mUSBProxyService COMMA_LOCKVAL_SRC_POS);
491 alockProxy.leave();
492
493 /*
494 * Call the VM process (IPC) and request it to attach the device.
495 *
496 * There are many reasonas for this to fail, so, as a consequence we don't
497 * assert the return code as it will crash the daemon and annoy the heck
498 * out of people.
499 */
500 LogFlowThisFunc(("{%s} Calling machine->onUSBDeviceAttach()...\n", mName));
501 HRESULT hrc = aMachine->onUSBDeviceAttach (d, NULL, aMaskedIfs);
502 LogFlowThisFunc(("{%s} Done machine->onUSBDeviceAttach()=%08X\n", mName, hrc));
503
504 /*
505 * As we re-enter the lock, we'll have to check if the device was
506 * physically detached while we were busy.
507 */
508 alockProxy.enter();
509 alockSelf.enter();
510
511 if (SUCCEEDED(hrc))
512 {
513 mMachine = aMachine;
514 if (!mIsPhysicallyDetached)
515 setState(kHostUSBDeviceState_UsedByVM);
516 else
517 {
518 detachFromVM(kHostUSBDeviceState_PhysDetached);
519 hrc = E_UNEXPECTED;
520 }
521 }
522 else
523 {
524 mMachine.setNull();
525 if (!mIsPhysicallyDetached)
526 {
527 setState(kHostUSBDeviceState_HeldByProxy);
528 if (hrc == E_UNEXPECTED)
529 hrc = E_FAIL; /* No confusion. */
530 }
531 else
532 {
533 onPhysicalDetachedInternal();
534 hrc = E_UNEXPECTED;
535 }
536 }
537 return hrc;
538}
539
540
541/**
542 * Detaches the device from the VM.
543 *
544 * This is used for a special scenario in attachToVM() and from
545 * onPhysicalDetachedInternal().
546 *
547 * @param aFinalState The final state (PhysDetached).
548 */
549void HostUSBDevice::detachFromVM(HostUSBDeviceState aFinalState)
550{
551 NOREF(aFinalState);
552
553 /*
554 * Assert preconditions.
555 */
556 Assert(aFinalState == kHostUSBDeviceState_PhysDetached);
557 Assert( mUniState == kHostUSBDeviceState_AttachingToVM
558 || mUniState == kHostUSBDeviceState_UsedByVM);
559 Assert(!mMachine.isNull());
560
561 /*
562 * Change the state and abandond the locks. The VM may query
563 * data and we don't want to deadlock - the state protects us,
564 * so, it's not a bit issue here.
565 */
566 setState(kHostUSBDeviceState_PhysDetachingFromVM, kHostUSBDeviceState_PhysDetached);
567 AutoWriteLock alockSelf(this COMMA_LOCKVAL_SRC_POS);
568 alockSelf.leave();
569 AutoWriteLock alockProxy(mUSBProxyService COMMA_LOCKVAL_SRC_POS);
570 alockProxy.leave();
571
572 /*
573 * Call the VM process (IPC) and request it to detach the device.
574 *
575 * There are many reasonas for this to fail, so, as a consequence we don't
576 * assert the return code as it will crash the daemon and annoy the heck
577 * out of people.
578 */
579 LogFlowThisFunc(("{%s} Calling machine->onUSBDeviceDetach()...\n", mName));
580 HRESULT hrc = mMachine->onUSBDeviceDetach(mId.toUtf16().raw(), NULL);
581 LogFlowThisFunc(("{%s} Done machine->onUSBDeviceDetach()=%Rhrc\n", mName, hrc));
582 NOREF(hrc);
583
584 /*
585 * Re-enter the locks and complete the transition.
586 */
587 alockProxy.enter();
588 alockSelf.enter();
589 advanceTransition();
590}
591
592/**
593 * Called when the VM process to inform us about the device being
594 * detached from it.
595 *
596 * This is NOT called when we detach the device via onUSBDeviceDetach.
597 *
598 *
599 * @param[in] aMachine The machine making the request.
600 * This must be the machine this device is currently attached to.
601 * @param[in] aDone When set to false, the VM just informs us that it's about
602 * to detach this device but hasn't done it just yet.
603 * When set to true, the VM informs us that it has completed
604 * the detaching of this device.
605 * @param[out] aRunFilters Whether to run filters.
606 * @param[in] aAbnormal Set if we're cleaning up after a crashed VM.
607 *
608 * @returns S_OK on success, and E_UNEXPECTED if the device isn't in the right state.
609 *
610 * @note Must be called from under the object write lock.
611 */
612HRESULT HostUSBDevice::onDetachFromVM(SessionMachine *aMachine, bool aDone, bool *aRunFilters, bool aAbnormal /*= true*/)
613{
614 LogFlowThisFunc(("{%s} state=%s aDone=%RTbool aAbnormal=%RTbool\n", mName, getStateName(), aDone, aAbnormal));
615
616 /*
617 * Validate preconditions.
618 */
619 AssertPtrReturn(aRunFilters, E_INVALIDARG);
620 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
621 if (!aDone)
622 {
623 if (mUniState != kHostUSBDeviceState_UsedByVM)
624 return setError(E_INVALIDARG,
625 tr("USB device '%s' with UUID {%RTuuid} is busy (state '%s'). Please try again later"),
626 mName, mId.raw(), getStateName());
627 }
628 else
629 AssertMsgReturn( mUniState == kHostUSBDeviceState_DetachingFromVM /** @todo capturing for VM ends up here on termination. */
630 || (mUniState == kHostUSBDeviceState_UsedByVM && aAbnormal),
631 ("{%s} %s\n", mName, getStateName()), E_UNEXPECTED);
632 AssertMsgReturn((mMachine == aMachine), ("%p != %p\n", (void *)mMachine, aMachine), E_FAIL);
633
634 /*
635 * Change the state.
636 */
637 if (!aDone)
638 {
639 *aRunFilters = startTransition(kHostUSBDeviceState_DetachingFromVM, kHostUSBDeviceState_HeldByProxy);
640 /* PORTME: This might require host specific changes if you re-enumerate the device. */
641 }
642 else if (aAbnormal && mUniState == kHostUSBDeviceState_UsedByVM)
643 {
644 /* Fast forward thru the DetachingFromVM state and on to HeldByProxy. */
645 /** @todo need to update the state machine to handle crashed VMs. */
646 startTransition(kHostUSBDeviceState_DetachingFromVM, kHostUSBDeviceState_HeldByProxy);
647 *aRunFilters = advanceTransition();
648 mMachine.setNull();
649 /* PORTME: ditto / trouble if you depend on the VM process to do anything. */
650 }
651 else
652 {
653 /* normal completion. */
654 Assert(mUniSubState == kHostUSBDeviceSubState_Default); /* PORTME: ditto */
655 *aRunFilters = advanceTransition();
656 mMachine.setNull();
657 }
658
659 return S_OK;
660}
661
662/**
663 * Requests the USB proxy service to release the device back to the host.
664 *
665 * This method will ignore (not assert) calls for devices that already
666 * belong to the host because it simplifies the usage a bit.
667 *
668 * @returns COM status code.
669 * @retval S_OK on success.
670 * @retval E_UNEXPECTED on bad state.
671 * @retval E_* as appropriate.
672 *
673 * @note Must be called from under the object write lock.
674 */
675HRESULT HostUSBDevice::requestReleaseToHost()
676{
677 LogFlowThisFunc(("{%s}\n", mName));
678
679 /*
680 * Validate preconditions.
681 */
682 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
683 Assert(mMachine.isNull());
684 if ( mUniState == kHostUSBDeviceState_Unused
685 || mUniState == kHostUSBDeviceState_Capturable)
686 return S_OK;
687 AssertMsgReturn(mUniState == kHostUSBDeviceState_HeldByProxy, ("{%s} %s\n", mName, getStateName()), E_UNEXPECTED);
688
689 /*
690 * Try release it.
691 */
692#if (defined(RT_OS_DARWIN) && defined(VBOX_WITH_NEW_USB_CODE_ON_DARWIN)) /* PORTME */ \
693 || defined(RT_OS_WINDOWS)
694 startTransition(kHostUSBDeviceState_ReleasingToHost, kHostUSBDeviceState_Unused, kHostUSBDeviceSubState_AwaitingDetach);
695#else
696 startTransition(kHostUSBDeviceState_ReleasingToHost, kHostUSBDeviceState_Unused);
697#endif
698 int rc = mUSBProxyService->releaseDevice(this);
699 if (RT_FAILURE(rc))
700 {
701 failTransition();
702 return E_FAIL;
703 }
704 return S_OK;
705}
706
707/**
708 * Requests the USB proxy service to capture and hold the device.
709 *
710 * The device must be owned by the host at the time of the call. But for
711 * the callers convenience, calling this method on a device that is already
712 * being held will success without any assertions.
713 *
714 * @returns COM status code.
715 * @retval S_OK on success.
716 * @retval E_UNEXPECTED on bad state.
717 * @retval E_* as appropriate.
718 *
719 * @note Must be called from under the object write lock.
720 */
721HRESULT HostUSBDevice::requestHold()
722{
723 LogFlowThisFunc(("{%s}\n", mName));
724
725 /*
726 * Validate preconditions.
727 */
728 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
729 AssertMsgReturn( mUniState == kHostUSBDeviceState_Unused
730 || mUniState == kHostUSBDeviceState_Capturable
731 || mUniState == kHostUSBDeviceState_HeldByProxy,
732 ("{%s} %s\n", mName, getStateName()),
733 E_UNEXPECTED);
734
735 Assert(mMachine.isNull());
736 mMachine.setNull();
737
738 if (mUniState == kHostUSBDeviceState_HeldByProxy)
739 return S_OK;
740
741 /*
742 * Do the job.
743 */
744#if (defined(RT_OS_DARWIN) && defined(VBOX_WITH_NEW_USB_CODE_ON_DARWIN)) /* PORTME */ \
745 || defined(RT_OS_WINDOWS)
746 startTransition(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_HeldByProxy, kHostUSBDeviceSubState_AwaitingDetach);
747#else
748 startTransition(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_HeldByProxy);
749#endif
750 int rc = mUSBProxyService->captureDevice(this);
751 if (RT_FAILURE(rc))
752 {
753 failTransition();
754 return E_FAIL;
755 }
756 return S_OK;
757}
758
759
760/**
761 * Check a detach detected by the USB Proxy Service to see if
762 * it's a real one or just a logical following a re-enumeration.
763 *
764 * This will work the internal sub state of the device and do time
765 * outs, so it does more than just querying data!
766 *
767 * @returns true if it was actually detached, false if it's just a re-enumeration.
768 */
769bool HostUSBDevice::wasActuallyDetached()
770{
771 /*
772 * This only applies to the detach and re-attach states.
773 */
774 switch (mUniState)
775 {
776 case kHostUSBDeviceState_Capturing:
777 case kHostUSBDeviceState_ReleasingToHost:
778 case kHostUSBDeviceState_AttachingToVM:
779 case kHostUSBDeviceState_DetachingFromVM:
780 switch (mUniSubState)
781 {
782 /*
783 * If we're awaiting a detach, the this has now occurred
784 * and the state should be advanced.
785 */
786 case kHostUSBDeviceSubState_AwaitingDetach:
787 advanceTransition();
788 return false; /* not physically detached. */
789
790 /*
791 * Check for timeouts.
792 */
793 case kHostUSBDeviceSubState_AwaitingReAttach:
794 {
795#ifndef RT_OS_WINDOWS /* check the implementation details here. */
796 uint64_t elapsedNanoseconds = RTTimeNanoTS() - mLastStateChangeTS;
797 if (elapsedNanoseconds > UINT64_C (60000000000) ) /* 60 seconds */
798 {
799 LogRel (("USB: Async operation timed out for device %s (state: %s)\n", mName, getStateName()));
800 failTransition();
801 }
802#endif
803 return false; /* not physically detached. */
804 }
805
806 /* not applicable.*/
807 case kHostUSBDeviceSubState_Default:
808 break;
809 }
810 break;
811
812 /* not applicable. */
813 case kHostUSBDeviceState_Unsupported:
814 case kHostUSBDeviceState_UsedByHost:
815 case kHostUSBDeviceState_Capturable:
816 case kHostUSBDeviceState_Unused:
817 case kHostUSBDeviceState_HeldByProxy:
818 case kHostUSBDeviceState_UsedByVM:
819 case kHostUSBDeviceState_PhysDetachingFromVM:
820 case kHostUSBDeviceState_PhysDetached:
821 break;
822
823 default:
824 AssertLogRelMsgFailed (("this=%p %s\n", this, getStateName()));
825 break;
826 }
827
828 /* It was detached. */
829 return true;
830}
831
832/**
833 * Notification from the USB Proxy that the device was physically detached.
834 *
835 * If a transition is pending, mIsPhysicallyDetached will be set and
836 * handled when the transition advances forward.
837 *
838 * Otherwsie the device will be detached from any VM currently using it - this
839 * involves IPC and will temporarily abandond locks - and all the device data
840 * reset.
841 *
842 * @note Must be called from under the object write lock.
843 */
844void HostUSBDevice::onPhysicalDetached()
845{
846 LogFlowThisFunc(("{%s}\n", mName));
847 AssertReturnVoid(isWriteLockOnCurrentThread());
848
849 mIsPhysicallyDetached = true;
850 if (mUniState < kHostUSBDeviceState_FirstTransitional)
851 onPhysicalDetachedInternal();
852}
853
854
855/**
856 * Do the physical detach work for a device in a stable state or
857 * at a transition state change.
858 *
859 * See onPhysicalDetach() for details.
860 *
861 * @note Must be called from under the object write lock.
862 */
863void HostUSBDevice::onPhysicalDetachedInternal()
864{
865 LogFlowThisFunc(("{%s}\n", mName));
866 AssertReturnVoid(isWriteLockOnCurrentThread());
867 Assert(mIsPhysicallyDetached);
868
869 /*
870 * Do we need to detach it from the VM first?
871 */
872 if ( !mMachine.isNull()
873 && ( mUniState == kHostUSBDeviceState_UsedByVM
874 || mUniState == kHostUSBDeviceState_AttachingToVM))
875 detachFromVM(kHostUSBDeviceState_PhysDetached);
876 else
877 AssertMsg(mMachine.isNull(), ("%s\n", getStateName()));
878
879 /*
880 * Reset the data and enter the final state.
881 */
882 mMachine.setNull();
883 setState(kHostUSBDeviceState_PhysDetached);
884}
885
886
887/**
888 * Returns true if this device matches the given filter data.
889 *
890 * @note It is assumed, that the filter data owner is appropriately
891 * locked before calling this method.
892 *
893 * @note
894 * This method MUST correlate with
895 * USBController::hasMatchingFilter (IUSBDevice *)
896 * in the sense of the device matching logic.
897 *
898 * @note Locks this object for reading.
899 */
900bool HostUSBDevice::isMatch(const USBDeviceFilter::Data &aData)
901{
902 AutoCaller autoCaller(this);
903 AssertComRCReturn(autoCaller.rc(), false);
904
905 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
906
907 if (!aData.mActive)
908 return false;
909
910 if (!aData.mRemote.isMatch(FALSE))
911 return false;
912
913 if (!USBFilterMatchDevice(&aData.mUSBFilter, mUsb))
914 return false;
915
916 /* Don't match busy devices with a 100% wildcard filter - this will
917 later become a filter prop (ring-3 only). */
918 if ( mUsb->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
919 && !USBFilterHasAnySubstatialCriteria(&aData.mUSBFilter))
920 return false;
921
922 LogFlowThisFunc(("returns true\n"));
923 return true;
924}
925
926/**
927 * Compares this device with a USBDEVICE and decides if the match or which comes first.
928 *
929 * This will take into account device re-attaching and omit the bits
930 * that may change during a device re-enumeration.
931 *
932 * @param aDev2 Device 2.
933 *
934 * @returns < 0 if this should come before aDev2.
935 * @returns 0 if this and aDev2 are equal.
936 * @returns > 0 if this should come after aDev2.
937 *
938 * @note Must be called from under the object write lock.
939 */
940int HostUSBDevice::compare(PCUSBDEVICE aDev2)
941{
942 AssertReturn(isWriteLockOnCurrentThread(), -1);
943 //Log3(("%Rfn: %p {%s}\n", __PRETTY_FUNCTION__, this, mName));
944 return compare(mUsb, aDev2,
945 mUniSubState == kHostUSBDeviceSubState_AwaitingDetach /* (In case we don't get the detach notice.) */
946 || mUniSubState == kHostUSBDeviceSubState_AwaitingReAttach);
947}
948
949/**
950 * Compares two USBDEVICE structures and decides if the match or which comes first.
951 *
952 * @param aDev1 Device 1.
953 * @param aDev2 Device 2.
954 * @param aIsAwaitingReAttach Whether to omit bits that will change in a device
955 * re-enumeration (true) or not (false).
956 *
957 * @returns < 0 if aDev1 should come before aDev2.
958 * @returns 0 if aDev1 and aDev2 are equal.
959 * @returns > 0 if aDev1 should come after aDev2.
960 */
961/*static*/
962int HostUSBDevice::compare(PCUSBDEVICE aDev1, PCUSBDEVICE aDev2, bool aIsAwaitingReAttach /*= false */)
963{
964 /*
965 * Things that stays the same everywhere.
966 *
967 * The more uniquely these properties identifies a device the less the chance
968 * that we mix similar devices during re-enumeration. Bus+port would help
969 * provide ~99.8% accuracy if the host can provide those attributes.
970 */
971 int iDiff = aDev1->idVendor - aDev2->idVendor;
972 if (iDiff)
973 return iDiff;
974
975 iDiff = aDev1->idProduct - aDev2->idProduct;
976 if (iDiff)
977 return iDiff;
978
979 iDiff = aDev1->bcdDevice - aDev2->bcdDevice;
980 if (iDiff)
981 {
982 //Log3(("compare: bcdDevice: %#x != %#x\n", aDev1->bcdDevice, aDev2->bcdDevice));
983 return iDiff;
984 }
985
986#ifdef RT_OS_WINDOWS /* the string query may fail on windows during replugging, ignore serial mismatch if this is the case. */
987 if ( aDev1->u64SerialHash != aDev2->u64SerialHash
988 && ( !aIsAwaitingReAttach
989 || (aDev2->pszSerialNumber && *aDev2->pszSerialNumber)
990 || (aDev2->pszManufacturer && *aDev2->pszManufacturer)
991 || (aDev2->pszProduct && *aDev2->pszProduct))
992 )
993#else
994 if (aDev1->u64SerialHash != aDev2->u64SerialHash)
995#endif
996 {
997 //Log3(("compare: u64SerialHash: %#llx != %#llx\n", aDev1->u64SerialHash, aDev2->u64SerialHash));
998 return aDev1->u64SerialHash < aDev2->u64SerialHash ? -1 : 1;
999 }
1000
1001 /* The hub/bus + port should help a lot in a re-attach situation. */
1002#ifdef RT_OS_WINDOWS
1003 iDiff = strcmp(aDev1->pszHubName, aDev2->pszHubName);
1004 if (iDiff)
1005 {
1006 //Log3(("compare: HubName: %s != %s\n", aDev1->pszHubName, aDev2->pszHubName));
1007 return iDiff;
1008 }
1009#else
1010 iDiff = aDev1->bBus - aDev2->bBus;
1011 if (iDiff)
1012 {
1013 //Log3(("compare: bBus: %#x != %#x\n", aDev1->bBus, aDev2->bBus));
1014 return iDiff;
1015 }
1016#endif
1017
1018 iDiff = aDev1->bPort - aDev2->bPort; /* shouldn't change anywhere and help pinpoint it very accurately. */
1019 if (iDiff)
1020 {
1021 //Log3(("compare: bPort: %#x != %#x\n", aDev1->bPort, aDev2->bPort));
1022 return iDiff;
1023 }
1024
1025 /*
1026 * Things that usually doesn't stay the same when re-enumerating
1027 * a device. The fewer things in the category the better chance
1028 * that we avoid messing up when more than one device of the same
1029 * kind is attached.
1030 */
1031 if (aIsAwaitingReAttach)
1032 {
1033 //Log3(("aDev1=%p == aDev2=%p\n", aDev1, aDev2));
1034 return 0;
1035 }
1036 /* device number always changes. */
1037 return strcmp(aDev1->pszAddress, aDev2->pszAddress);
1038}
1039
1040/**
1041 * Updates the state of the device.
1042 *
1043 * If this method returns @c true, Host::onUSBDeviceStateChanged() will be
1044 * called to process the state change (complete the state change request,
1045 * inform the VM process etc.).
1046 *
1047 * If this method returns @c false, it is assumed that the given state change
1048 * is "minor": it doesn't require any further action other than update the
1049 * mState field with the actual state value.
1050 *
1051 * Regardless of the return value, this method always takes ownership of the
1052 * new USBDEVICE structure passed in and updates the pNext and pPrev fiends in
1053 * it using the values of the old structure.
1054 *
1055 * @param[in] aDev The current device state as seen by the proxy backend.
1056 * @param[out] aRunFilters Whether the state change should be accompanied by
1057 * running filters on the device.
1058 * @param[out] aIgnoreMachine Machine to ignore when running filters.
1059 *
1060 * @returns Whether the Host object should be bothered with this state change.
1061 *
1062 * @note Locks this object for writing.
1063 *
1064 * @todo Just do everything here, that is, call filter runners and everything that
1065 * works by state change. Using 3 return codes/parameters is just plain ugly.
1066 */
1067bool HostUSBDevice::updateState(PCUSBDEVICE aDev, bool *aRunFilters, SessionMachine **aIgnoreMachine)
1068{
1069 *aRunFilters = false;
1070 *aIgnoreMachine = NULL;
1071
1072 /*
1073 * Locking.
1074 */
1075 AssertReturn(isWriteLockOnCurrentThread(), false);
1076 AutoCaller autoCaller(this);
1077 AssertComRCReturn(autoCaller.rc(), false);
1078 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1079
1080
1081 /*
1082 * Replace the existing structure by the new one.
1083 */
1084 const USBDEVICESTATE enmOldState = mUsb->enmState; NOREF(enmOldState);
1085 if (mUsb != aDev)
1086 {
1087 aDev->pNext = mUsb->pNext;
1088 aDev->pPrev = mUsb->pPrev;
1089 USBProxyService::freeDevice (mUsb);
1090 mUsb = aDev;
1091 }
1092
1093/** @def HOSTUSBDEVICE_FUZZY_STATE
1094 * Defined on hosts where we have a driver that keeps proper device states.
1095 */
1096# if defined(RT_OS_LINUX) || defined(DOXYGEN_RUNNING)
1097# define HOSTUSBDEVICE_FUZZY_STATE 1
1098# else
1099# undef HOSTUSBDEVICE_FUZZY_STATE
1100# endif
1101 /*
1102 * For some hosts we'll have to be pretty carefule here because
1103 * they don't always have a clue what is going on. This is
1104 * particularly true on linux and solaris, while windows and
1105 * darwin generally knows a bit more.
1106 */
1107 bool fIsImportant = false;
1108 if (enmOldState != mUsb->enmState)
1109 {
1110 LogFlowThisFunc(("%p {%s} %s\n", this, mName, getStateName()));
1111 switch (mUsb->enmState)
1112 {
1113 /*
1114 * Little fuzzyness here, except where we fake capture.
1115 */
1116 case USBDEVICESTATE_USED_BY_HOST:
1117 switch (mUniState)
1118 {
1119 /* Host drivers installed, that's fine. */
1120 case kHostUSBDeviceState_Capturable:
1121 case kHostUSBDeviceState_Unused:
1122 LogThisFunc(("{%s} %s -> %s\n", mName, getStateName(), stateName(kHostUSBDeviceState_UsedByHost)));
1123 *aRunFilters = setState(kHostUSBDeviceState_UsedByHost);
1124 break;
1125 case kHostUSBDeviceState_UsedByHost:
1126 break;
1127
1128 /* Can only mean that we've failed capturing it. */
1129 case kHostUSBDeviceState_Capturing:
1130 LogThisFunc(("{%s} capture failed!\n", mName));
1131 mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
1132 *aRunFilters = failTransition();
1133 mMachine.setNull();
1134 break;
1135
1136 /* Guess we've successfully released it. */
1137 case kHostUSBDeviceState_ReleasingToHost:
1138 LogThisFunc(("{%s} %s -> %s\n", mName, getStateName(), stateName(kHostUSBDeviceState_UsedByHost)));
1139 mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
1140 *aRunFilters = setState(kHostUSBDeviceState_UsedByHost);
1141 break;
1142
1143 /* These are IPC states and should be left alone. */
1144 case kHostUSBDeviceState_AttachingToVM:
1145 case kHostUSBDeviceState_DetachingFromVM:
1146 case kHostUSBDeviceState_PhysDetachingFromVM:
1147 LogThisFunc(("{%s} %s - changed to USED_BY_HOST...\n", mName, getStateName()));
1148 break;
1149
1150#ifdef HOSTUSBDEVICE_FUZZY_STATE
1151 /* Fake: We can't prevent anyone from grabbing it. */
1152 case kHostUSBDeviceState_HeldByProxy:
1153 LogThisFunc(("{%s} %s -> %s!\n", mName, getStateName(), stateName(kHostUSBDeviceState_UsedByHost)));
1154 *aRunFilters = setState(kHostUSBDeviceState_UsedByHost);
1155 break;
1156 //case kHostUSBDeviceState_UsedByVM:
1157 // /** @todo needs to be detached from the VM. */
1158 // break;
1159#endif
1160 /* Not supposed to happen... */
1161#ifndef HOSTUSBDEVICE_FUZZY_STATE
1162 case kHostUSBDeviceState_HeldByProxy:
1163#endif
1164 case kHostUSBDeviceState_UsedByVM:
1165 case kHostUSBDeviceState_PhysDetached:
1166 case kHostUSBDeviceState_Unsupported:
1167 default:
1168 AssertMsgFailed(("{%s} %s\n", mName, getStateName()));
1169 break;
1170 }
1171 break;
1172
1173 /*
1174 * It changed to capturable. Fuzzy hosts might easily
1175 * confuse UsedByVM with this one.
1176 */
1177 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
1178 switch (mUniState)
1179 {
1180 /* No change. */
1181#ifdef HOSTUSBDEVICE_FUZZY_STATE
1182 case kHostUSBDeviceState_HeldByProxy:
1183 case kHostUSBDeviceState_UsedByVM:
1184#endif
1185 case kHostUSBDeviceState_Capturable:
1186 break;
1187
1188 /* Changed! */
1189 case kHostUSBDeviceState_UsedByHost:
1190 fIsImportant = true;
1191 case kHostUSBDeviceState_Unused:
1192 LogThisFunc(("{%s} %s -> %s\n", mName, getStateName(), stateName(kHostUSBDeviceState_Capturable)));
1193 *aRunFilters = setState(kHostUSBDeviceState_Capturable);
1194 break;
1195
1196 /* Can only mean that we've failed capturing it. */
1197 case kHostUSBDeviceState_Capturing:
1198 LogThisFunc(("{%s} capture failed!\n", mName));
1199 mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
1200 *aRunFilters = failTransition();
1201 mMachine.setNull();
1202 break;
1203
1204 /* Guess we've successfully released it. */
1205 case kHostUSBDeviceState_ReleasingToHost:
1206 LogThisFunc(("{%s} %s -> %s\n", mName, getStateName(), stateName(kHostUSBDeviceState_Capturable)));
1207 mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
1208 *aRunFilters = setState(kHostUSBDeviceState_Capturable);
1209 break;
1210
1211 /* These are IPC states and should be left alone. */
1212 case kHostUSBDeviceState_AttachingToVM:
1213 case kHostUSBDeviceState_DetachingFromVM:
1214 case kHostUSBDeviceState_PhysDetachingFromVM:
1215 LogThisFunc(("{%s} %s - changed to USED_BY_HOST_CAPTURABLE...\n", mName, getStateName()));
1216 break;
1217
1218 /* Not supposed to happen*/
1219#ifndef HOSTUSBDEVICE_FUZZY_STATE
1220 case kHostUSBDeviceState_HeldByProxy:
1221 case kHostUSBDeviceState_UsedByVM:
1222#endif
1223 case kHostUSBDeviceState_Unsupported:
1224 case kHostUSBDeviceState_PhysDetached:
1225 default:
1226 AssertMsgFailed(("{%s} %s\n", mName, getStateName()));
1227 break;
1228 }
1229 break;
1230
1231
1232 /*
1233 * It changed to capturable. Fuzzy hosts might easily
1234 * confuse UsedByVM and HeldByProxy with this one.
1235 */
1236 case USBDEVICESTATE_UNUSED:
1237 switch (mUniState)
1238 {
1239 /* No change. */
1240#ifdef HOSTUSBDEVICE_FUZZY_STATE
1241 case kHostUSBDeviceState_HeldByProxy:
1242 case kHostUSBDeviceState_UsedByVM:
1243#endif
1244 case kHostUSBDeviceState_Unused:
1245 break;
1246
1247 /* Changed! */
1248 case kHostUSBDeviceState_UsedByHost:
1249 case kHostUSBDeviceState_Capturable:
1250 fIsImportant = true;
1251 LogThisFunc(("{%s} %s -> %s\n", mName, getStateName(), stateName(kHostUSBDeviceState_Unused)));
1252 *aRunFilters = setState(kHostUSBDeviceState_Unused);
1253 break;
1254
1255 /* Can mean that we've failed capturing it, but on windows it is the detach signal. */
1256 case kHostUSBDeviceState_Capturing:
1257#if defined(RT_OS_WINDOWS)
1258 if (mUniSubState == kHostUSBDeviceSubState_AwaitingDetach)
1259 {
1260 LogThisFunc(("{%s} capture advancing thru UNUSED...\n", mName));
1261 *aRunFilters = advanceTransition();
1262 }
1263 else
1264#endif
1265 {
1266 LogThisFunc(("{%s} capture failed!\n", mName));
1267 mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
1268 *aRunFilters = failTransition();
1269 mMachine.setNull();
1270 }
1271 break;
1272
1273 /* Guess we've successfully released it. */
1274 case kHostUSBDeviceState_ReleasingToHost:
1275 LogThisFunc(("{%s} %s -> %s\n", mName, getStateName(), stateName(kHostUSBDeviceState_Unused)));
1276 mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
1277 *aRunFilters = setState(kHostUSBDeviceState_Unused);
1278 break;
1279
1280 /* These are IPC states and should be left alone. */
1281 case kHostUSBDeviceState_AttachingToVM:
1282 case kHostUSBDeviceState_DetachingFromVM:
1283 case kHostUSBDeviceState_PhysDetachingFromVM:
1284 LogThisFunc(("{%s} %s - changed to UNUSED...\n", mName, getStateName()));
1285 break;
1286
1287 /* Not supposed to happen*/
1288#ifndef HOSTUSBDEVICE_FUZZY_STATE
1289 case kHostUSBDeviceState_HeldByProxy:
1290 case kHostUSBDeviceState_UsedByVM:
1291#endif
1292 case kHostUSBDeviceState_Unsupported:
1293 case kHostUSBDeviceState_PhysDetached:
1294 default:
1295 AssertMsgFailed(("{%s} %s\n", mName, getStateName()));
1296 break;
1297 }
1298 break;
1299
1300 /*
1301 * This is pretty straight forward, except that everyone
1302 * might sometimes confuse this and the UsedByVM state.
1303 */
1304 case USBDEVICESTATE_HELD_BY_PROXY:
1305 switch (mUniState)
1306 {
1307 /* No change. */
1308 case kHostUSBDeviceState_HeldByProxy:
1309 break;
1310 case kHostUSBDeviceState_UsedByVM:
1311 LogThisFunc(("{%s} %s - changed to HELD_BY_PROXY...\n", mName, getStateName()));
1312 break;
1313
1314 /* Guess we've successfully captured it. */
1315 case kHostUSBDeviceState_Capturing:
1316 LogThisFunc(("{%s} capture succeeded!\n", mName));
1317 mUSBProxyService->captureDeviceCompleted(this, true /* aSuccess */);
1318 *aRunFilters = advanceTransition(true /* fast forward thru re-attach */);
1319
1320 /* Take action if we're supposed to attach it to a VM. */
1321 if (mUniState == kHostUSBDeviceState_AttachingToVM)
1322 attachToVM(mMachine, mMaskedIfs);
1323 break;
1324
1325 /* Can only mean that we've failed capturing it. */
1326 case kHostUSBDeviceState_ReleasingToHost:
1327 LogThisFunc(("{%s} %s failed!\n", mName, getStateName()));
1328 mUSBProxyService->releaseDeviceCompleted(this, false /* aSuccess */);
1329 *aRunFilters = setState(kHostUSBDeviceState_HeldByProxy);
1330 break;
1331
1332 /* These are IPC states and should be left alone. */
1333 case kHostUSBDeviceState_AttachingToVM:
1334 case kHostUSBDeviceState_DetachingFromVM:
1335 case kHostUSBDeviceState_PhysDetachingFromVM:
1336 LogThisFunc(("{%s} %s - changed to HELD_BY_PROXY...\n", mName, getStateName()));
1337 break;
1338
1339 /* Not supposed to happen. */
1340 case kHostUSBDeviceState_Unsupported:
1341 case kHostUSBDeviceState_UsedByHost:
1342 case kHostUSBDeviceState_Capturable:
1343 case kHostUSBDeviceState_Unused:
1344 case kHostUSBDeviceState_PhysDetached:
1345 default:
1346 AssertMsgFailed(("{%s} %s\n", mName, getStateName()));
1347 break;
1348 }
1349 break;
1350
1351 /*
1352 * This is very straight forward and only Darwin implements it.
1353 */
1354 case USBDEVICESTATE_USED_BY_GUEST:
1355 switch (mUniState)
1356 {
1357 /* No change. */
1358 case kHostUSBDeviceState_HeldByProxy:
1359 LogThisFunc(("{%s} %s - changed to USED_BY_GUEST...\n", mName, getStateName()));
1360 break;
1361 case kHostUSBDeviceState_UsedByVM:
1362 break;
1363
1364 /* These are IPC states and should be left alone. */
1365 case kHostUSBDeviceState_AttachingToVM:
1366 case kHostUSBDeviceState_DetachingFromVM:
1367 case kHostUSBDeviceState_PhysDetachingFromVM:
1368 LogThisFunc(("{%s} %s - changed to USED_BY_GUEST...\n", mName, getStateName()));
1369 break;
1370
1371 /* Not supposed to happen. */
1372 case kHostUSBDeviceState_Unsupported:
1373 case kHostUSBDeviceState_Capturable:
1374 case kHostUSBDeviceState_Unused:
1375 case kHostUSBDeviceState_UsedByHost:
1376 case kHostUSBDeviceState_PhysDetached:
1377 case kHostUSBDeviceState_ReleasingToHost:
1378 case kHostUSBDeviceState_Capturing:
1379 default:
1380 AssertMsgFailed(("{%s} %s\n", mName, getStateName()));
1381 break;
1382 }
1383 break;
1384
1385 /*
1386 * This is not supposed to happen and indicates a bug in the backend!
1387 */
1388 case USBDEVICESTATE_UNSUPPORTED:
1389 AssertMsgFailed(("enmOldState=%d {%s} %s\n", enmOldState, mName, getStateName()));
1390 break;
1391 default:
1392 AssertMsgFailed(("enmState=%d {%s} %s\n", mUsb->enmState, mName, getStateName()));
1393 break;
1394 }
1395 }
1396 else if ( mUniSubState == kHostUSBDeviceSubState_AwaitingDetach
1397 && hasAsyncOperationTimedOut())
1398 {
1399 LogRel(("USB: timeout in %s for {%RTuuid} / {%s}\n",
1400 getStateName(), mId.raw(), mName));
1401 *aRunFilters = failTransition();
1402 fIsImportant = true;
1403 }
1404 else
1405 {
1406 LogFlowThisFunc(("%p {%s} %s - no change %d\n", this, mName, getStateName(), enmOldState));
1407 /** @todo might have to handle some stuff here too if we cannot make the release/capture handling deal with that above ... */
1408 }
1409
1410 return fIsImportant;
1411
1412}
1413
1414
1415/**
1416 * Updates the state of the device, checking for cases which we fake.
1417 *
1418 * See HostUSBDevice::updateState() for details.
1419 *
1420 * @param[in] aDev See HostUSBDevice::updateState().
1421 * @param[out] aRunFilters See HostUSBDevice::updateState()
1422 * @param[out] aIgnoreMachine See HostUSBDevice::updateState()
1423 *
1424 * @returns See HostUSBDevice::updateState()
1425 *
1426 * @note Caller must write lock the object.
1427 */
1428bool HostUSBDevice::updateStateFake(PCUSBDEVICE aDev, bool *aRunFilters, SessionMachine **aIgnoreMachine)
1429{
1430 const HostUSBDeviceState enmState = mUniState;
1431 switch (enmState)
1432 {
1433 case kHostUSBDeviceState_Capturing:
1434 case kHostUSBDeviceState_ReleasingToHost:
1435 {
1436 Assert(isWriteLockOnCurrentThread());
1437
1438 *aIgnoreMachine = mUniState == kHostUSBDeviceState_ReleasingToHost ? mMachine : NULL;
1439 *aRunFilters = advanceTransition();
1440 LogThisFunc(("{%s} %s\n", mName, getStateName()));
1441
1442 if (mUsb != aDev)
1443 {
1444 aDev->pNext = mUsb->pNext;
1445 aDev->pPrev = mUsb->pPrev;
1446 USBProxyService::freeDevice(mUsb);
1447 mUsb = aDev;
1448 }
1449
1450 /* call the completion method */
1451 if (enmState == kHostUSBDeviceState_Capturing)
1452 mUSBProxyService->captureDeviceCompleted(this, true /* aSuccess */);
1453 else
1454 mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
1455
1456 /* Take action if we're supposed to attach it to a VM. */
1457 if (mUniState == kHostUSBDeviceState_AttachingToVM)
1458 attachToVM(mMachine, mMaskedIfs);
1459 return true;
1460 }
1461
1462 default:
1463 return updateState(aDev, aRunFilters, aIgnoreMachine);
1464 }
1465}
1466
1467
1468/**
1469 * Checks if there is a pending asynchronous operation and whether
1470 * it has timed out or not.
1471 *
1472 * @returns true on timeout, false if not.
1473 *
1474 * @note Caller must have read or write locked the object before calling.
1475 */
1476bool HostUSBDevice::hasAsyncOperationTimedOut() const
1477{
1478 switch (mUniSubState)
1479 {
1480#ifndef RT_OS_WINDOWS /* no timeouts on windows yet since I don't have all the details here... */
1481 case kHostUSBDeviceSubState_AwaitingDetach:
1482 case kHostUSBDeviceSubState_AwaitingReAttach:
1483 {
1484 uint64_t elapsedNanoseconds = RTTimeNanoTS() - mLastStateChangeTS;
1485 return elapsedNanoseconds > UINT64_C(60000000000); /* 60 seconds */ /* PORTME */
1486 }
1487#endif
1488 default:
1489 return false;
1490 }
1491}
1492
1493
1494/**
1495 * Translate the state into
1496 *
1497 * @returns
1498 * @param aState
1499 * @param aSubState
1500 * @param aPendingState
1501 */
1502/*static*/ const char *HostUSBDevice::stateName(HostUSBDeviceState aState,
1503 HostUSBDeviceState aPendingState /*= kHostUSBDeviceState_Invalid*/,
1504 HostUSBDeviceSubState aSubState /*= kHostUSBDeviceSubState_Default*/)
1505{
1506 switch (aState)
1507 {
1508 case kHostUSBDeviceState_Unsupported:
1509 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "Unsupported{bad}");
1510 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "Unsupported[bad]");
1511 return "Unsupported";
1512
1513 case kHostUSBDeviceState_UsedByHost:
1514 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "UsedByHost{bad}");
1515 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "UsedByHost[bad]");
1516 return "UsedByHost";
1517
1518 case kHostUSBDeviceState_Capturable:
1519 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "Capturable{bad}");
1520 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "Capturable[bad]");
1521 return "Capturable";
1522
1523 case kHostUSBDeviceState_Unused:
1524 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "Unused{bad}");
1525 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "Unused[bad]");
1526 return "Unused";
1527
1528 case kHostUSBDeviceState_HeldByProxy:
1529 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "HeldByProxy{bad}");
1530 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "HeldByProxy[bad]");
1531 return "HeldByProxy";
1532
1533 case kHostUSBDeviceState_UsedByVM:
1534 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "UsedByVM{bad}");
1535 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "UsedByVM[bad]");
1536 return "UsedByVM";
1537
1538 case kHostUSBDeviceState_PhysDetached:
1539 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "PhysDetached{bad}");
1540 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "PhysDetached[bad]");
1541 return "PhysDetached";
1542
1543 case kHostUSBDeviceState_Capturing:
1544 switch (aPendingState)
1545 {
1546 case kHostUSBDeviceState_UsedByVM:
1547 switch (aSubState)
1548 {
1549 case kHostUSBDeviceSubState_Default:
1550 return "CapturingForVM";
1551 case kHostUSBDeviceSubState_AwaitingDetach:
1552 return "CapturingForVM[Detach]";
1553 case kHostUSBDeviceSubState_AwaitingReAttach:
1554 return "CapturingForVM[Attach]";
1555 default:
1556 AssertFailedReturn("CapturingForVM[bad]");
1557 }
1558 break;
1559
1560 case kHostUSBDeviceState_HeldByProxy:
1561 switch (aSubState)
1562 {
1563 case kHostUSBDeviceSubState_Default:
1564 return "CapturingForProxy";
1565 case kHostUSBDeviceSubState_AwaitingDetach:
1566 return "CapturingForProxy[Detach]";
1567 case kHostUSBDeviceSubState_AwaitingReAttach:
1568 return "CapturingForProxy[Attach]";
1569 default:
1570 AssertFailedReturn("CapturingForProxy[bad]");
1571 }
1572 break;
1573
1574 default:
1575 AssertFailedReturn("Capturing{bad}");
1576 }
1577 break;
1578
1579 case kHostUSBDeviceState_ReleasingToHost:
1580 switch (aPendingState)
1581 {
1582 case kHostUSBDeviceState_Unused:
1583 switch (aSubState)
1584 {
1585 case kHostUSBDeviceSubState_Default:
1586 return "ReleasingToHost";
1587 case kHostUSBDeviceSubState_AwaitingDetach:
1588 return "ReleasingToHost[Detach]";
1589 case kHostUSBDeviceSubState_AwaitingReAttach:
1590 return "ReleasingToHost[Attach]";
1591 default:
1592 AssertFailedReturn("ReleasingToHost[bad]");
1593 }
1594 break;
1595 default:
1596 AssertFailedReturn("ReleasingToHost{bad}");
1597 }
1598 break;
1599
1600 case kHostUSBDeviceState_DetachingFromVM:
1601 switch (aPendingState)
1602 {
1603 case kHostUSBDeviceState_HeldByProxy:
1604 switch (aSubState)
1605 {
1606 case kHostUSBDeviceSubState_Default:
1607 return "DetatchingFromVM>Proxy";
1608 case kHostUSBDeviceSubState_AwaitingDetach:
1609 return "DetatchingFromVM>Proxy[Detach]";
1610 case kHostUSBDeviceSubState_AwaitingReAttach:
1611 return "DetatchingFromVM>Proxy[Attach]";
1612 default:
1613 AssertFailedReturn("DetatchingFromVM>Proxy[bad]");
1614 }
1615 break;
1616
1617 case kHostUSBDeviceState_Unused:
1618 switch (aSubState)
1619 {
1620 case kHostUSBDeviceSubState_Default:
1621 return "DetachingFromVM>Host";
1622 case kHostUSBDeviceSubState_AwaitingDetach:
1623 return "DetachingFromVM>Host[Detach]";
1624 case kHostUSBDeviceSubState_AwaitingReAttach:
1625 return "DetachingFromVM>Host[Attach]";
1626 default:
1627 AssertFailedReturn("DetachingFromVM>Host[bad]");
1628 }
1629 break;
1630
1631 default:
1632 AssertFailedReturn("DetachingFromVM{bad}");
1633 }
1634 break;
1635
1636 case kHostUSBDeviceState_AttachingToVM:
1637 switch (aPendingState)
1638 {
1639 case kHostUSBDeviceState_UsedByVM:
1640 switch (aSubState)
1641 {
1642 case kHostUSBDeviceSubState_Default:
1643 return "AttachingToVM";
1644 case kHostUSBDeviceSubState_AwaitingDetach:
1645 return "AttachingToVM[Detach]";
1646 case kHostUSBDeviceSubState_AwaitingReAttach:
1647 return "AttachingToVM[Attach]";
1648 default:
1649 AssertFailedReturn("AttachingToVM[bad]");
1650 }
1651 break;
1652
1653 default:
1654 AssertFailedReturn("AttachingToVM{bad}");
1655 }
1656 break;
1657
1658
1659 case kHostUSBDeviceState_PhysDetachingFromVM:
1660 switch (aPendingState)
1661 {
1662 case kHostUSBDeviceState_PhysDetached:
1663 switch (aSubState)
1664 {
1665 case kHostUSBDeviceSubState_Default:
1666 return "PhysDetachingFromVM";
1667 default:
1668 AssertFailedReturn("AttachingToVM[bad]");
1669 }
1670 break;
1671
1672 default:
1673 AssertFailedReturn("AttachingToVM{bad}");
1674 }
1675 break;
1676
1677 default:
1678 AssertFailedReturn("BadState");
1679
1680 }
1681
1682 AssertFailedReturn("shouldn't get here");
1683}
1684
1685/**
1686 * Set the device state.
1687 *
1688 * This method will verify that the state transition is a legal one
1689 * according to the statemachine. It will also take care of the
1690 * associated house keeping and determin if filters needs to be applied.
1691 *
1692 * @param aNewState The new state.
1693 * @param aNewPendingState The final state of a transition when applicable.
1694 * @param aNewSubState The new sub-state when applicable.
1695 *
1696 * @returns true if filters should be applied to the device, false if not.
1697 *
1698 * @note The caller must own the write lock for this object.
1699 */
1700bool HostUSBDevice::setState(HostUSBDeviceState aNewState, HostUSBDeviceState aNewPendingState /*= kHostUSBDeviceState_Invalid*/,
1701 HostUSBDeviceSubState aNewSubState /*= kHostUSBDeviceSubState_Default*/)
1702{
1703 Assert(isWriteLockOnCurrentThread());
1704 Assert( aNewSubState == kHostUSBDeviceSubState_Default
1705 || aNewSubState == kHostUSBDeviceSubState_AwaitingDetach
1706 || aNewSubState == kHostUSBDeviceSubState_AwaitingReAttach);
1707
1708 /*
1709 * If the state is unchanged, then don't bother going
1710 * thru the validation and setting. This saves a bit of code.
1711 */
1712 if ( aNewState == mUniState
1713 && aNewPendingState == mPendingUniState
1714 && aNewSubState == mUniSubState)
1715 return false;
1716
1717 /*
1718 * Welcome to the switch orgies!
1719 * You're welcome to check out the ones in startTransition(),
1720 * advanceTransition(), failTransition() and getStateName() too. Enjoy!
1721 */
1722
1723 bool fFilters = false;
1724 HostUSBDeviceState NewPrevState = mUniState;
1725 switch (mUniState)
1726 {
1727 /*
1728 * Not much can be done with a device in this state.
1729 */
1730 case kHostUSBDeviceState_Unsupported:
1731 switch (aNewState)
1732 {
1733 case kHostUSBDeviceState_PhysDetached:
1734 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1735 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1736 break;
1737 default:
1738 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, getStateName(),
1739 stateName(aNewState, aNewPendingState, aNewSubState)), false);
1740 }
1741 break;
1742
1743 /*
1744 * Only the host OS (or the user) can make changes
1745 * that'll make a device get out of this state.
1746 */
1747 case kHostUSBDeviceState_UsedByHost:
1748 switch (aNewState)
1749 {
1750 case kHostUSBDeviceState_Capturable:
1751 case kHostUSBDeviceState_Unused:
1752 fFilters = true;
1753 case kHostUSBDeviceState_PhysDetached:
1754 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1755 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1756 break;
1757 default:
1758 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
1759 stateName(aNewState, aNewPendingState, aNewSubState)), false);
1760 }
1761 break;
1762
1763 /*
1764 * Now it gets interesting.
1765 */
1766 case kHostUSBDeviceState_Capturable:
1767 switch (aNewState)
1768 {
1769 /* Host changes. */
1770 case kHostUSBDeviceState_Unused:
1771 fFilters = true; /* Wildcard only... */
1772 case kHostUSBDeviceState_UsedByHost:
1773 case kHostUSBDeviceState_PhysDetached:
1774 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1775 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1776 break;
1777
1778 /* VBox actions */
1779 case kHostUSBDeviceState_Capturing:
1780 switch (aNewPendingState)
1781 {
1782 case kHostUSBDeviceState_HeldByProxy:
1783 case kHostUSBDeviceState_UsedByVM:
1784 break;
1785 default:
1786 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
1787 stateName(aNewState, aNewPendingState, aNewSubState)), false);
1788 }
1789 break;
1790 default:
1791 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
1792 stateName(aNewState, aNewPendingState, aNewSubState)), false);
1793 }
1794 break;
1795
1796 case kHostUSBDeviceState_Unused:
1797 switch (aNewState)
1798 {
1799 /* Host changes. */
1800 case kHostUSBDeviceState_PhysDetached:
1801 case kHostUSBDeviceState_UsedByHost:
1802 case kHostUSBDeviceState_Capturable:
1803 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1804 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1805 break;
1806
1807 /* VBox actions */
1808 case kHostUSBDeviceState_Capturing:
1809 switch (aNewPendingState)
1810 {
1811 case kHostUSBDeviceState_HeldByProxy:
1812 case kHostUSBDeviceState_UsedByVM:
1813 break;
1814 default:
1815 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
1816 stateName(aNewState, aNewPendingState, aNewSubState)), false);
1817 }
1818 break;
1819 default:
1820 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
1821 stateName(aNewState, aNewPendingState, aNewSubState)), false);
1822 }
1823 break;
1824
1825 /*
1826 * VBox owns this device now, what's next...
1827 */
1828 case kHostUSBDeviceState_HeldByProxy:
1829 switch (aNewState)
1830 {
1831 /* Host changes. */
1832 case kHostUSBDeviceState_PhysDetached:
1833 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1834 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1835 break;
1836
1837 /* VBox actions */
1838 case kHostUSBDeviceState_AttachingToVM:
1839 switch (aNewPendingState)
1840 {
1841 case kHostUSBDeviceState_UsedByVM:
1842 break;
1843 default:
1844 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
1845 stateName(aNewState, aNewPendingState, aNewSubState)), false);
1846 }
1847 break;
1848 case kHostUSBDeviceState_ReleasingToHost:
1849 switch (aNewPendingState)
1850 {
1851 case kHostUSBDeviceState_Unused: /* Only this! */
1852 break;
1853 default:
1854 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
1855 stateName(aNewState, aNewPendingState, aNewSubState)), false);
1856 }
1857 break;
1858 default:
1859 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
1860 stateName(aNewState, aNewPendingState, aNewSubState)), false);
1861 }
1862 break;
1863
1864
1865 case kHostUSBDeviceState_UsedByVM:
1866 switch (aNewState)
1867 {
1868 /* Host changes. */
1869 case kHostUSBDeviceState_PhysDetachingFromVM:
1870 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1871 Assert(aNewPendingState == kHostUSBDeviceState_PhysDetached);
1872 break;
1873
1874 /* VBox actions */
1875 case kHostUSBDeviceState_DetachingFromVM:
1876 switch (aNewPendingState)
1877 {
1878 case kHostUSBDeviceState_HeldByProxy:
1879 case kHostUSBDeviceState_Unused: /* Only this! */
1880 break;
1881 default:
1882 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
1883 stateName(aNewState, aNewPendingState, aNewSubState)), false);
1884 }
1885 break;
1886 default:
1887 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
1888 stateName(aNewState, aNewPendingState, aNewSubState)), false);
1889 }
1890 break;
1891
1892 /*
1893 * The final state.
1894 */
1895 case kHostUSBDeviceState_PhysDetached:
1896 switch (mUniState)
1897 {
1898 case kHostUSBDeviceState_Unsupported:
1899 case kHostUSBDeviceState_UsedByHost:
1900 case kHostUSBDeviceState_Capturable:
1901 case kHostUSBDeviceState_Unused:
1902 case kHostUSBDeviceState_HeldByProxy:
1903 case kHostUSBDeviceState_PhysDetachingFromVM:
1904 case kHostUSBDeviceState_DetachingFromVM: // ??
1905 case kHostUSBDeviceState_Capturing:
1906 case kHostUSBDeviceState_ReleasingToHost:
1907 break;
1908
1909 case kHostUSBDeviceState_AttachingToVM: // ??
1910 case kHostUSBDeviceState_UsedByVM:
1911 default:
1912 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
1913 stateName(aNewState, aNewPendingState, aNewSubState)), false);
1914 }
1915 break;
1916
1917
1918 /*
1919 * The transitional states.
1920 */
1921 case kHostUSBDeviceState_Capturing:
1922 NewPrevState = mPrevUniState;
1923 switch (aNewState)
1924 {
1925 /* Sub state advance. */
1926 case kHostUSBDeviceState_Capturing:
1927 switch (aNewSubState)
1928 {
1929 case kHostUSBDeviceSubState_AwaitingReAttach:
1930 Assert(mUniSubState == kHostUSBDeviceSubState_AwaitingDetach);
1931 Assert(aNewPendingState == mPendingUniState);
1932 break;
1933 default:
1934 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
1935 }
1936 break;
1937
1938 /* Host/User/Failure. */
1939 case kHostUSBDeviceState_PhysDetached:
1940 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1941 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1942 break;
1943 case kHostUSBDeviceState_UsedByHost:
1944 case kHostUSBDeviceState_Capturable:
1945 case kHostUSBDeviceState_Unused:
1946 Assert(aNewState == mPrevUniState);
1947 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1948 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1949 break;
1950
1951 /* VBox */
1952 case kHostUSBDeviceState_HeldByProxy:
1953 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1954 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1955 Assert( mPendingUniState == kHostUSBDeviceState_HeldByProxy
1956 || mPendingUniState == kHostUSBDeviceState_UsedByVM /* <- failure */ );
1957 break;
1958 case kHostUSBDeviceState_AttachingToVM:
1959 Assert(aNewPendingState == kHostUSBDeviceState_UsedByVM);
1960 NewPrevState = kHostUSBDeviceState_HeldByProxy;
1961 break;
1962
1963 default:
1964 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
1965 stateName(aNewState, aNewPendingState, aNewSubState)), false);
1966 }
1967 break;
1968
1969 case kHostUSBDeviceState_ReleasingToHost:
1970 Assert(mPrevUniState == kHostUSBDeviceState_HeldByProxy);
1971 NewPrevState = mPrevUniState;
1972 switch (aNewState)
1973 {
1974 /* Sub state advance. */
1975 case kHostUSBDeviceState_ReleasingToHost:
1976 switch (aNewSubState)
1977 {
1978 case kHostUSBDeviceSubState_AwaitingReAttach:
1979 Assert(mUniSubState == kHostUSBDeviceSubState_AwaitingDetach);
1980 Assert(aNewPendingState == mPendingUniState);
1981 break;
1982 default:
1983 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
1984 }
1985 break;
1986
1987 /* Host/Failure. */
1988 case kHostUSBDeviceState_PhysDetached:
1989 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1990 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1991 break;
1992 case kHostUSBDeviceState_HeldByProxy:
1993 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1994 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1995 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
1996 break;
1997
1998 /* Success */
1999 case kHostUSBDeviceState_UsedByHost:
2000 case kHostUSBDeviceState_Capturable:
2001 case kHostUSBDeviceState_Unused:
2002 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2003 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2004 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2005 break;
2006
2007 default:
2008 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
2009 stateName(aNewState, aNewPendingState, aNewSubState)), false);
2010 }
2011 break;
2012
2013 case kHostUSBDeviceState_AttachingToVM:
2014 Assert(mPrevUniState == kHostUSBDeviceState_HeldByProxy);
2015 NewPrevState = mPrevUniState;
2016 switch (aNewState)
2017 {
2018 /* Host/Failure. */
2019 case kHostUSBDeviceState_PhysDetachingFromVM:
2020 Assert(aNewPendingState == kHostUSBDeviceState_PhysDetached);
2021 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2022 break;
2023 case kHostUSBDeviceState_HeldByProxy:
2024 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2025 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2026 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2027 break;
2028
2029 /* Success */
2030 case kHostUSBDeviceState_UsedByVM:
2031 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2032 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2033 Assert(mPendingUniState == kHostUSBDeviceState_UsedByVM);
2034 break;
2035
2036 default:
2037 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
2038 stateName(aNewState, aNewPendingState, aNewSubState)), false);
2039 }
2040 break;
2041
2042 case kHostUSBDeviceState_DetachingFromVM:
2043 Assert(mPrevUniState == kHostUSBDeviceState_UsedByVM);
2044 NewPrevState = mPrevUniState;
2045 switch (aNewState)
2046 {
2047 /* Host/Failure. */
2048 case kHostUSBDeviceState_PhysDetached: //??
2049 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2050 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2051 break;
2052 case kHostUSBDeviceState_PhysDetachingFromVM:
2053 Assert(aNewPendingState == kHostUSBDeviceState_PhysDetached);
2054 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2055 break;
2056
2057 /* Success */
2058 case kHostUSBDeviceState_HeldByProxy:
2059 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2060 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2061 Assert(mPendingUniState == kHostUSBDeviceState_HeldByProxy);
2062 fFilters = true;
2063 break;
2064
2065 case kHostUSBDeviceState_ReleasingToHost:
2066 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2067 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2068 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2069 NewPrevState = kHostUSBDeviceState_HeldByProxy;
2070 break;
2071
2072 default:
2073 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
2074 stateName(aNewState, aNewPendingState, aNewSubState)), false);
2075 }
2076 break;
2077
2078 case kHostUSBDeviceState_PhysDetachingFromVM:
2079 Assert( mPrevUniState == kHostUSBDeviceState_DetachingFromVM
2080 || mPrevUniState == kHostUSBDeviceState_AttachingToVM
2081 || mPrevUniState == kHostUSBDeviceState_UsedByVM);
2082 NewPrevState = mPrevUniState; /* preserving it is more useful. */
2083 switch (aNewState)
2084 {
2085 case kHostUSBDeviceState_PhysDetached:
2086 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2087 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2088 break;
2089 default:
2090 AssertLogRelMsgFailedReturn (("this=%p %s -X-> %s\n", this, getStateName(),
2091 stateName(aNewState, aNewPendingState, aNewSubState)), false);
2092 }
2093 break;
2094
2095 default:
2096 AssertReleaseMsgFailedReturn (("this=%p mUniState=%d\n", this, mUniState), false);
2097 }
2098
2099 /*
2100 * Make the state change.
2101 */
2102 if (NewPrevState != mPrevUniState)
2103 LogFlowThisFunc(("%s -> %s (prev: %s -> %s) [%s]\n",
2104 getStateName(), stateName(aNewState, aNewPendingState, aNewSubState),
2105 stateName(mPrevUniState), stateName(NewPrevState), mName));
2106 else
2107 LogFlowThisFunc(("%s -> %s (prev: %s) [%s]\n",
2108 getStateName(), stateName(aNewState, aNewPendingState, aNewSubState), stateName(NewPrevState), mName));
2109 mPrevUniState = NewPrevState;
2110 mUniState = aNewState;
2111 mUniSubState = aNewSubState;
2112 mPendingUniState = aNewPendingState;
2113 mLastStateChangeTS = RTTimeNanoTS();
2114
2115 return fFilters;
2116}
2117
2118
2119
2120/**
2121 * A convenience for entering a transitional state.
2122
2123 * @param aNewState The new state (transitional).
2124 * @param aFinalSubState The final state of the transition (non-transitional).
2125 * @param aNewSubState The new sub-state when applicable.
2126 *
2127 * @returns Always false because filters are never applied for the start of a transition.
2128 *
2129 * @note The caller must own the write lock for this object.
2130 */
2131bool HostUSBDevice::startTransition (HostUSBDeviceState aNewState, HostUSBDeviceState aFinalState,
2132 HostUSBDeviceSubState aNewSubState /*= kHostUSBDeviceSubState_Default*/)
2133{
2134 /*
2135 * A quick prevalidation thing. Not really necessary since setState
2136 * verifies this too, but it's very easy here.
2137 */
2138 switch (mUniState)
2139 {
2140 case kHostUSBDeviceState_Unsupported:
2141 case kHostUSBDeviceState_UsedByHost:
2142 case kHostUSBDeviceState_Capturable:
2143 case kHostUSBDeviceState_Unused:
2144 case kHostUSBDeviceState_HeldByProxy:
2145 case kHostUSBDeviceState_UsedByVM:
2146 break;
2147
2148 case kHostUSBDeviceState_DetachingFromVM:
2149 case kHostUSBDeviceState_Capturing:
2150 case kHostUSBDeviceState_ReleasingToHost:
2151 case kHostUSBDeviceState_AttachingToVM:
2152 case kHostUSBDeviceState_PhysDetachingFromVM:
2153 AssertMsgFailedReturn (("this=%p %s is a transitional state.\n", this, getStateName()), false);
2154
2155 case kHostUSBDeviceState_PhysDetached:
2156 default:
2157 AssertReleaseMsgFailedReturn (("this=%p mUniState=%d\n", this, mUniState), false);
2158 }
2159
2160 return setState (aNewState, aFinalState, aNewSubState);
2161}
2162
2163
2164/**
2165 * A convenience for advancing a transitional state forward.
2166 *
2167 * @param aSkipReAttach Fast forwards thru the re-attach substate if
2168 * applicable.
2169 *
2170 * @returns true if filters should be applied to the device, false if not.
2171 *
2172 * @note The caller must own the write lock for this object.
2173 */
2174bool HostUSBDevice::advanceTransition(bool aSkipReAttach /* = false */)
2175{
2176 HostUSBDeviceState enmPending = mPendingUniState;
2177 HostUSBDeviceSubState enmSub = mUniSubState;
2178 HostUSBDeviceState enmState = mUniState;
2179 switch (enmState)
2180 {
2181 case kHostUSBDeviceState_Capturing:
2182 switch (enmSub)
2183 {
2184 case kHostUSBDeviceSubState_AwaitingDetach:
2185 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2186 break;
2187 case kHostUSBDeviceSubState_AwaitingReAttach:
2188 enmSub = kHostUSBDeviceSubState_Default;
2189 /* fall thru */
2190 case kHostUSBDeviceSubState_Default:
2191 switch (enmPending)
2192 {
2193 case kHostUSBDeviceState_UsedByVM:
2194 enmState = kHostUSBDeviceState_AttachingToVM;
2195 break;
2196 case kHostUSBDeviceState_HeldByProxy:
2197 enmState = enmPending;
2198 enmPending = kHostUSBDeviceState_Invalid;
2199 break;
2200 default:
2201 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n", this, enmPending, getStateName()), false);
2202 }
2203 break;
2204 default:
2205 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2206 }
2207 break;
2208
2209 case kHostUSBDeviceState_ReleasingToHost:
2210 switch (enmSub)
2211 {
2212 case kHostUSBDeviceSubState_AwaitingDetach:
2213 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2214 break;
2215 case kHostUSBDeviceSubState_AwaitingReAttach:
2216 enmSub = kHostUSBDeviceSubState_Default;
2217 /* fall thru */
2218 case kHostUSBDeviceSubState_Default:
2219 switch (enmPending)
2220 {
2221 /* Use Unused here since it implies that filters has been applied
2222 and will make sure they aren't applied if the final state really
2223 is Capturable. */
2224 case kHostUSBDeviceState_Unused:
2225 enmState = enmPending;
2226 enmPending = kHostUSBDeviceState_Invalid;
2227 break;
2228 default:
2229 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n", this, enmPending, getStateName()), false);
2230 }
2231 break;
2232 default:
2233 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2234 }
2235 break;
2236
2237 case kHostUSBDeviceState_AttachingToVM:
2238 switch (enmSub)
2239 {
2240 case kHostUSBDeviceSubState_AwaitingDetach:
2241 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2242 break;
2243 case kHostUSBDeviceSubState_AwaitingReAttach:
2244 enmSub = kHostUSBDeviceSubState_Default;
2245 /* fall thru */
2246 case kHostUSBDeviceSubState_Default:
2247 switch (enmPending)
2248 {
2249 case kHostUSBDeviceState_UsedByVM:
2250 enmState = enmPending;
2251 enmPending = kHostUSBDeviceState_Invalid;
2252 break;
2253 default:
2254 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n", this, enmPending, getStateName()), false);
2255 }
2256 break;
2257 default:
2258 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2259 }
2260 break;
2261
2262 case kHostUSBDeviceState_DetachingFromVM:
2263 switch (enmSub)
2264 {
2265 case kHostUSBDeviceSubState_AwaitingDetach:
2266 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2267 break;
2268 case kHostUSBDeviceSubState_AwaitingReAttach:
2269 enmSub = kHostUSBDeviceSubState_Default;
2270 /* fall thru */
2271 case kHostUSBDeviceSubState_Default:
2272 switch (enmPending)
2273 {
2274 case kHostUSBDeviceState_HeldByProxy:
2275 enmState = enmPending;
2276 enmPending = kHostUSBDeviceState_Invalid;
2277 break;
2278 case kHostUSBDeviceState_Unused:
2279 enmState = kHostUSBDeviceState_ReleasingToHost;
2280 break;
2281 default:
2282 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n", this, enmPending, getStateName()), false);
2283 }
2284 break;
2285 default:
2286 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2287 }
2288 break;
2289
2290 case kHostUSBDeviceState_PhysDetachingFromVM:
2291 switch (enmSub)
2292 {
2293 case kHostUSBDeviceSubState_Default:
2294 switch (enmPending)
2295 {
2296 case kHostUSBDeviceState_PhysDetached:
2297 enmState = enmPending;
2298 enmPending = kHostUSBDeviceState_Invalid;
2299 break;
2300 default:
2301 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n", this, enmPending, getStateName()), false);
2302 }
2303 break;
2304 default:
2305 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2306 }
2307 break;
2308
2309 case kHostUSBDeviceState_Unsupported:
2310 case kHostUSBDeviceState_UsedByHost:
2311 case kHostUSBDeviceState_Capturable:
2312 case kHostUSBDeviceState_Unused:
2313 case kHostUSBDeviceState_HeldByProxy:
2314 case kHostUSBDeviceState_UsedByVM:
2315 AssertMsgFailedReturn(("this=%p %s is not transitional\n", this, getStateName()), false);
2316 case kHostUSBDeviceState_PhysDetached:
2317 default:
2318 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, enmState), false);
2319
2320 }
2321
2322 bool fRc = setState(enmState, enmPending, enmSub);
2323 if (aSkipReAttach && mUniSubState == kHostUSBDeviceSubState_AwaitingReAttach)
2324 fRc |= advanceTransition(false /* don't fast forward re-attach */);
2325 return fRc;
2326}
2327
2328/**
2329 * A convenience for failing a transitional state.
2330 *
2331 * @return true if filters should be applied to the device, false if not.
2332 *
2333 * @note The caller must own the write lock for this object.
2334 */
2335bool HostUSBDevice::failTransition()
2336{
2337 HostUSBDeviceSubState enmSub = mUniSubState;
2338 HostUSBDeviceState enmState = mUniState;
2339 switch (enmState)
2340 {
2341 /*
2342 * There are just two cases, either we got back to the
2343 * previous state (assumes Capture+Attach-To-VM updates it)
2344 * or we assume the device has been unplugged (physically).
2345 */
2346 case kHostUSBDeviceState_DetachingFromVM:
2347 case kHostUSBDeviceState_Capturing:
2348 case kHostUSBDeviceState_ReleasingToHost:
2349 case kHostUSBDeviceState_AttachingToVM:
2350 switch (enmSub)
2351 {
2352 case kHostUSBDeviceSubState_AwaitingDetach:
2353 enmSub = kHostUSBDeviceSubState_Default;
2354 /* fall thru */
2355 case kHostUSBDeviceSubState_Default:
2356 enmState = mPrevUniState;
2357 break;
2358 case kHostUSBDeviceSubState_AwaitingReAttach:
2359 enmSub = kHostUSBDeviceSubState_Default;
2360 enmState = kHostUSBDeviceState_PhysDetached;
2361 break;
2362 default:
2363 AssertReleaseMsgFailedReturn (("this=%p mUniState=%d\n", this, mUniState), false);
2364 }
2365 break;
2366
2367 case kHostUSBDeviceState_PhysDetachingFromVM:
2368 AssertMsgFailedReturn (("this=%p %s shall not fail\n", this, getStateName()), false);
2369
2370 case kHostUSBDeviceState_Unsupported:
2371 case kHostUSBDeviceState_UsedByHost:
2372 case kHostUSBDeviceState_Capturable:
2373 case kHostUSBDeviceState_Unused:
2374 case kHostUSBDeviceState_HeldByProxy:
2375 case kHostUSBDeviceState_UsedByVM:
2376 AssertMsgFailedReturn (("this=%p %s is not transitional\n", this, getStateName()), false);
2377 case kHostUSBDeviceState_PhysDetached:
2378 default:
2379 AssertReleaseMsgFailedReturn (("this=%p mUniState=%d\n", this, mUniState), false);
2380
2381 }
2382
2383 return setState(enmState, kHostUSBDeviceState_Invalid, enmSub);
2384}
2385
2386
2387/**
2388 * Determins the canonical state of the device.
2389 *
2390 * @returns canonical state.
2391 *
2392 * @note The caller must own the read (or write) lock for this object.
2393 */
2394USBDeviceState_T HostUSBDevice::canonicalState() const
2395{
2396 switch (mUniState)
2397 {
2398 /*
2399 * Straight forward.
2400 */
2401 case kHostUSBDeviceState_Unsupported:
2402 return USBDeviceState_NotSupported;
2403
2404 case kHostUSBDeviceState_UsedByHost:
2405 return USBDeviceState_Unavailable;
2406
2407 case kHostUSBDeviceState_Capturable:
2408 return USBDeviceState_Busy;
2409
2410 case kHostUSBDeviceState_Unused:
2411 return USBDeviceState_Available;
2412
2413 case kHostUSBDeviceState_HeldByProxy:
2414 return USBDeviceState_Held;
2415
2416 case kHostUSBDeviceState_UsedByVM:
2417 return USBDeviceState_Captured;
2418
2419 /*
2420 * Pretend we've reached the final state.
2421 */
2422 case kHostUSBDeviceState_Capturing:
2423 Assert( mPendingUniState == kHostUSBDeviceState_UsedByVM
2424 || mPendingUniState == kHostUSBDeviceState_HeldByProxy);
2425 return mPendingUniState == kHostUSBDeviceState_UsedByVM
2426 ? (USBDeviceState_T)USBDeviceState_Captured
2427 : (USBDeviceState_T)USBDeviceState_Held;
2428 /* The cast ^^^^ is because xidl is using different enums for
2429 each of the values. *Very* nice idea... :-) */
2430
2431 case kHostUSBDeviceState_AttachingToVM:
2432 return USBDeviceState_Captured;
2433
2434 /*
2435 * Return the previous state.
2436 */
2437 case kHostUSBDeviceState_ReleasingToHost:
2438 Assert( mPrevUniState == kHostUSBDeviceState_UsedByVM
2439 || mPrevUniState == kHostUSBDeviceState_HeldByProxy);
2440 return mPrevUniState == kHostUSBDeviceState_UsedByVM
2441 ? (USBDeviceState_T)USBDeviceState_Captured
2442 : (USBDeviceState_T)USBDeviceState_Held;
2443 /* The cast ^^^^ is because xidl is using different enums for
2444 each of the values. *Very* nice idea... :-) */
2445
2446 case kHostUSBDeviceState_DetachingFromVM:
2447 return USBDeviceState_Captured;
2448 case kHostUSBDeviceState_PhysDetachingFromVM:
2449 return USBDeviceState_Captured;
2450
2451 case kHostUSBDeviceState_PhysDetached:
2452 default:
2453 AssertReleaseMsgFailedReturn (("this=%p mUniState=%d\n", this, mUniState), USBDeviceState_NotSupported);
2454 }
2455 /* won't ever get here. */
2456}
2457/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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