From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../src-server/freebsd/USBProxyBackendFreeBSD.cpp | 353 +++++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp (limited to 'src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp') diff --git a/src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp b/src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp new file mode 100644 index 00000000..79543717 --- /dev/null +++ b/src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp @@ -0,0 +1,353 @@ +/* $Id: USBProxyBackendFreeBSD.cpp $ */ +/** @file + * VirtualBox USB Proxy Service, FreeBSD Specialization. + */ + +/* + * Copyright (C) 2005-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_MAIN_USBPROXYBACKEND +#include "USBProxyBackend.h" +#include "LoggingNew.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/** + * Initialize data members. + */ +USBProxyBackendFreeBSD::USBProxyBackendFreeBSD() + : USBProxyBackend(), mNotifyEventSem(NIL_RTSEMEVENT) +{ + LogFlowThisFunc(("\n")); +} + +USBProxyBackendFreeBSD::~USBProxyBackendFreeBSD() +{ + LogFlowThisFunc(("\n")); +} + +/** + * Initializes the object (called right after construction). + * + * @returns S_OK on success and non-fatal failures, some COM error otherwise. + */ +int USBProxyBackendFreeBSD::init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, + const com::Utf8Str &strAddress, bool fLoadingSettings) +{ + USBProxyBackend::init(pUsbProxyService, strId, strAddress, fLoadingSettings); + + unconst(m_strBackend) = Utf8Str("host"); + + /* + * Create semaphore. + */ + int vrc = RTSemEventCreate(&mNotifyEventSem); + if (RT_FAILURE(vrc)) + return vrc; + + /* + * Start the poller thread. + */ + start(); + return VINF_SUCCESS; +} + + +/** + * Stop all service threads and free the device chain. + */ +void USBProxyBackendFreeBSD::uninit() +{ + LogFlowThisFunc(("\n")); + + /* + * Stop the service. + */ + if (isActive()) + stop(); + + RTSemEventDestroy(mNotifyEventSem); + mNotifyEventSem = NULL; + USBProxyBackend::uninit(); +} + + +int USBProxyBackendFreeBSD::captureDevice(HostUSBDevice *aDevice) +{ + 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())); + + /* + * Don't think we need to do anything when the device is held... fake it. + */ + Assert(aDevice->i_getUnistate() == kHostUSBDeviceState_Capturing); + devLock.release(); + interruptWait(); + + return VINF_SUCCESS; +} + + +int USBProxyBackendFreeBSD::releaseDevice(HostUSBDevice *aDevice) +{ + 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())); + + /* + * We're not really holding it atm., just fake it. + */ + Assert(aDevice->i_getUnistate() == kHostUSBDeviceState_ReleasingToHost); + devLock.release(); + interruptWait(); + + return VINF_SUCCESS; +} + + +bool USBProxyBackendFreeBSD::isFakeUpdateRequired() +{ + return true; +} + + +int USBProxyBackendFreeBSD::wait(RTMSINTERVAL aMillies) +{ + return RTSemEventWait(mNotifyEventSem, aMillies < 1000 ? 1000 : 5000); +} + + +int USBProxyBackendFreeBSD::interruptWait(void) +{ + return RTSemEventSignal(mNotifyEventSem); +} + + +/** + * Dumps a USBDEVICE structure to the log using LogLevel 3. + * @param pDev The structure to log. + * @todo This is really common code. + */ +DECLINLINE(void) usbLogDevice(PUSBDEVICE pDev) +{ + NOREF(pDev); + + Log3(("USB device:\n")); + Log3(("Product: %s (%x)\n", pDev->pszProduct, pDev->idProduct)); + Log3(("Manufacturer: %s (Vendor ID %x)\n", pDev->pszManufacturer, pDev->idVendor)); + Log3(("Serial number: %s (%llx)\n", pDev->pszSerialNumber, pDev->u64SerialHash)); + Log3(("Device revision: %d\n", pDev->bcdDevice)); + Log3(("Device class: %x\n", pDev->bDeviceClass)); + Log3(("Device subclass: %x\n", pDev->bDeviceSubClass)); + Log3(("Device protocol: %x\n", pDev->bDeviceProtocol)); + Log3(("USB version number: %d\n", pDev->bcdUSB)); + Log3(("Device speed: %s\n", + pDev->enmSpeed == USBDEVICESPEED_UNKNOWN ? "unknown" + : pDev->enmSpeed == USBDEVICESPEED_LOW ? "1.5 MBit/s" + : pDev->enmSpeed == USBDEVICESPEED_FULL ? "12 MBit/s" + : pDev->enmSpeed == USBDEVICESPEED_HIGH ? "480 MBit/s" + : pDev->enmSpeed == USBDEVICESPEED_VARIABLE ? "variable" + : "invalid")); + Log3(("Number of configurations: %d\n", pDev->bNumConfigurations)); + Log3(("Bus number: %d\n", pDev->bBus)); + Log3(("Port number: %d\n", pDev->bPort)); + Log3(("Device number: %d\n", pDev->bDevNum)); + Log3(("Device state: %s\n", + pDev->enmState == USBDEVICESTATE_UNSUPPORTED ? "unsupported" + : pDev->enmState == USBDEVICESTATE_USED_BY_HOST ? "in use by host" + : pDev->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE ? "in use by host, possibly capturable" + : pDev->enmState == USBDEVICESTATE_UNUSED ? "not in use" + : pDev->enmState == USBDEVICESTATE_HELD_BY_PROXY ? "held by proxy" + : pDev->enmState == USBDEVICESTATE_USED_BY_GUEST ? "used by guest" + : "invalid")); + Log3(("OS device address: %s\n", pDev->pszAddress)); +} + + +PUSBDEVICE USBProxyBackendFreeBSD::getDevices(void) +{ + PUSBDEVICE pDevices = NULL; + int FileUsb = 0; + int iBus = 0; + int iAddr = 1; + int vrc = VINF_SUCCESS; + char *pszDevicePath = NULL; + uint32_t PlugTime = 0; + + for (;;) + { + vrc = RTStrAPrintf(&pszDevicePath, "/dev/%s%d.%d", USB_GENERIC_NAME, iBus, iAddr); + if (RT_FAILURE(vrc)) + break; + + LogFlowFunc((": Opening %s\n", pszDevicePath)); + + FileUsb = open(pszDevicePath, O_RDONLY); + if (FileUsb < 0) + { + RTStrFree(pszDevicePath); + + if ((errno == ENOENT) && (iAddr > 1)) + { + iAddr = 1; + iBus++; + continue; + } + else if (errno == EACCES) + { + /* Skip devices without the right permission. */ + iAddr++; + continue; + } + else + break; + } + + LogFlowFunc((": %s opened successfully\n", pszDevicePath)); + + struct usb_device_info UsbDevInfo; + RT_ZERO(UsbDevInfo); + + vrc = ioctl(FileUsb, USB_GET_DEVICEINFO, &UsbDevInfo); + if (vrc < 0) + { + LogFlowFunc((": Error querying device info vrc=%Rrc\n", RTErrConvertFromErrno(errno))); + close(FileUsb); + RTStrFree(pszDevicePath); + break; + } + + /* Filter out hubs */ + if (UsbDevInfo.udi_class != 0x09) + { + PUSBDEVICE pDevice = (PUSBDEVICE)RTMemAllocZ(sizeof(USBDEVICE)); + if (!pDevice) + { + close(FileUsb); + RTStrFree(pszDevicePath); + break; + } + + pDevice->enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE; + pDevice->bBus = UsbDevInfo.udi_bus; + pDevice->bPort = UsbDevInfo.udi_hubport; + pDevice->bDeviceClass = UsbDevInfo.udi_class; + pDevice->bDeviceSubClass = UsbDevInfo.udi_subclass; + pDevice->bDeviceProtocol = UsbDevInfo.udi_protocol; + pDevice->bNumConfigurations = UsbDevInfo.udi_config_no; + pDevice->idVendor = UsbDevInfo.udi_vendorNo; + pDevice->idProduct = UsbDevInfo.udi_productNo; + pDevice->bDevNum = UsbDevInfo.udi_index; + + switch (UsbDevInfo.udi_speed) + { + case USB_SPEED_LOW: + pDevice->enmSpeed = USBDEVICESPEED_LOW; + break; + case USB_SPEED_FULL: + pDevice->enmSpeed = USBDEVICESPEED_FULL; + break; + case USB_SPEED_HIGH: + pDevice->enmSpeed = USBDEVICESPEED_HIGH; + break; + case USB_SPEED_SUPER: + pDevice->enmSpeed = USBDEVICESPEED_SUPER; + break; + case USB_SPEED_VARIABLE: + pDevice->enmSpeed = USBDEVICESPEED_VARIABLE; + break; + default: + pDevice->enmSpeed = USBDEVICESPEED_UNKNOWN; + break; + } + + if (UsbDevInfo.udi_vendor[0] != '\0') + { + USBLibPurgeEncoding(UsbDevInfo.udi_vendor); + pDevice->pszManufacturer = RTStrDupN(UsbDevInfo.udi_vendor, sizeof(UsbDevInfo.udi_vendor)); + } + + if (UsbDevInfo.udi_product[0] != '\0') + { + USBLibPurgeEncoding(UsbDevInfo.udi_product); + pDevice->pszProduct = RTStrDupN(UsbDevInfo.udi_product, sizeof(UsbDevInfo.udi_product)); + } + + if (UsbDevInfo.udi_serial[0] != '\0') + { + USBLibPurgeEncoding(UsbDevInfo.udi_serial); + pDevice->pszSerialNumber = RTStrDupN(UsbDevInfo.udi_serial, sizeof(UsbDevInfo.udi_serial)); + pDevice->u64SerialHash = USBLibHashSerial(UsbDevInfo.udi_serial); + } + vrc = ioctl(FileUsb, USB_GET_PLUGTIME, &PlugTime); + if (vrc == 0) + pDevice->u64SerialHash += PlugTime; + + pDevice->pszAddress = RTStrDup(pszDevicePath); + pDevice->pszBackend = RTStrDup("host"); + + usbLogDevice(pDevice); + + pDevice->pNext = pDevices; + if (pDevices) + pDevices->pPrev = pDevice; + pDevices = pDevice; + } + close(FileUsb); + RTStrFree(pszDevicePath); + iAddr++; + } + + return pDevices; +} -- cgit v1.2.3