/* $Id: USBProxyBackendDarwin.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */ /** @file * VirtualBox USB Proxy Service (in VBoxSVC), Darwin Specialization. */ /* * Copyright (C) 2005-2022 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #define LOG_GROUP LOG_GROUP_MAIN_USBPROXYBACKEND #include "USBProxyBackend.h" #include "LoggingNew.h" #include "iokit.h" #include #include #include #include #include #include #include #include #include /** * Initialize data members. */ USBProxyBackendDarwin::USBProxyBackendDarwin() : USBProxyBackend(), mServiceRunLoopRef(NULL), mNotifyOpaque(NULL), mWaitABitNextTime(false) { } USBProxyBackendDarwin::~USBProxyBackendDarwin() { } /** * Initializes the object (called right after construction). * * @returns VBox status code. */ int USBProxyBackendDarwin::init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress, bool fLoadingSettings) { USBProxyBackend::init(pUsbProxyService, strId, strAddress, fLoadingSettings); unconst(m_strBackend) = Utf8Str("host"); /* * Start the poller thread. */ start(); return VINF_SUCCESS; } /** * Stop all service threads and free the device chain. */ void USBProxyBackendDarwin::uninit() { LogFlowThisFunc(("\n")); /* * Stop the service. */ if (isActive()) stop(); USBProxyBackend::uninit(); } int USBProxyBackendDarwin::captureDevice(HostUSBDevice *aDevice) { /* * Check preconditions. */ AssertReturn(aDevice, VERR_GENERAL_FAILURE); AssertReturn(!aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE); AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("aDevice=%s\n", aDevice->i_getName().c_str())); Assert(aDevice->i_getUnistate() == kHostUSBDeviceState_Capturing); devLock.release(); interruptWait(); return VINF_SUCCESS; } int USBProxyBackendDarwin::releaseDevice(HostUSBDevice *aDevice) { /* * Check preconditions. */ AssertReturn(aDevice, VERR_GENERAL_FAILURE); AssertReturn(!aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE); AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("aDevice=%s\n", aDevice->i_getName().c_str())); Assert(aDevice->i_getUnistate() == kHostUSBDeviceState_ReleasingToHost); devLock.release(); interruptWait(); return VINF_SUCCESS; } bool USBProxyBackendDarwin::isFakeUpdateRequired() { return true; } int USBProxyBackendDarwin::wait(RTMSINTERVAL aMillies) { SInt32 rc = CFRunLoopRunInMode(CFSTR(VBOX_IOKIT_MODE_STRING), mWaitABitNextTime && aMillies >= 1000 ? 1.0 /* seconds */ : aMillies >= 5000 /* Temporary measure to poll for status changes (MSD). */ ? 5.0 /* seconds */ : aMillies / 1000.0, true); mWaitABitNextTime = rc != kCFRunLoopRunTimedOut; return VINF_SUCCESS; } int USBProxyBackendDarwin::interruptWait(void) { if (mServiceRunLoopRef) CFRunLoopStop(mServiceRunLoopRef); return 0; } PUSBDEVICE USBProxyBackendDarwin::getDevices(void) { /* call iokit.cpp */ return DarwinGetUSBDevices(); } void USBProxyBackendDarwin::serviceThreadInit(void) { mServiceRunLoopRef = CFRunLoopGetCurrent(); mNotifyOpaque = DarwinSubscribeUSBNotifications(); } void USBProxyBackendDarwin::serviceThreadTerm(void) { DarwinUnsubscribeUSBNotifications(mNotifyOpaque); mServiceRunLoopRef = NULL; } /** * Wrapper called from iokit.cpp. * * @param pCur The USB device to free. */ void DarwinFreeUSBDeviceFromIOKit(PUSBDEVICE pCur) { USBProxyBackend::freeDevice(pCur); }