diff options
author | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2022-01-13 07:29:50 +0000 |
---|---|---|
committer | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2022-01-13 07:29:50 +0000 |
commit | 9e5dc8f7ed4c3c5d5159d7c4c6201e1158721276 (patch) | |
tree | b6399b1126e25ebc5f2cdc2f3b59a5b5a4244e90 /src/VBox/HostDrivers/VBoxUSB | |
parent | dd5db78dc0a3d0f85d123ad6373e4eacbd7d2807 (diff) | |
download | VirtualBox-svn-9e5dc8f7ed4c3c5d5159d7c4c6201e1158721276.tar.gz |
HostDrivers,Installer,Devices: Clean out the VBoxUSB driver which is completely unused since some time now, bugref:9808
git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@93217 cfe28804-0f27-0410-a406-dd0f0b0b656f
Diffstat (limited to 'src/VBox/HostDrivers/VBoxUSB')
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/Makefile.kmk | 4 | ||||
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/darwin/Info.plist | 89 | ||||
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/darwin/Makefile.kmk | 94 | ||||
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/darwin/USBLib-darwin.cpp | 201 | ||||
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/darwin/VBoxUSB.cpp | 1890 | ||||
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/darwin/VBoxUSBInterface.h | 65 | ||||
-rwxr-xr-x | src/VBox/HostDrivers/VBoxUSB/darwin/loadusb.sh | 70 | ||||
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/darwin/testcase/Makefile.kup | 0 | ||||
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/darwin/testcase/tstOpenUSBDev.cpp | 295 |
9 files changed, 1 insertions, 2707 deletions
diff --git a/src/VBox/HostDrivers/VBoxUSB/Makefile.kmk b/src/VBox/HostDrivers/VBoxUSB/Makefile.kmk index 2a3e332f15d..d51d4bbbeb1 100644 --- a/src/VBox/HostDrivers/VBoxUSB/Makefile.kmk +++ b/src/VBox/HostDrivers/VBoxUSB/Makefile.kmk @@ -28,7 +28,7 @@ SUB_DEPTH = ../../../.. include $(KBUILD_PATH)/subheader.kmk # Include sub-makefiles. -if1of ($(KBUILD_TARGET), darwin solaris win) +if1of ($(KBUILD_TARGET), solaris win) include $(PATH_SUB_CURRENT)/$(KBUILD_TARGET)/Makefile.kmk endif @@ -49,8 +49,6 @@ USBLib_SOURCES = \ USBFilter.cpp # OS specific bits if applicable. -USBLib_SOURCES.darwin = \ - darwin/USBLib-darwin.cpp USBLib_SOURCES.os2 = \ os2/usbcalls.c USBLib_SOURCES.solaris = \ diff --git a/src/VBox/HostDrivers/VBoxUSB/darwin/Info.plist b/src/VBox/HostDrivers/VBoxUSB/darwin/Info.plist deleted file mode 100644 index 16aac548116..00000000000 --- a/src/VBox/HostDrivers/VBoxUSB/darwin/Info.plist +++ /dev/null @@ -1,89 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>CFBundleDevelopmentRegion</key> <string>English</string> - <key>CFBundleExecutable</key> <string>VBoxUSB</string> - <key>CFBundleIdentifier</key> <string>org.virtualbox.kext.VBoxUSB</string> - <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> - <key>CFBundleName</key> <string>VBoxUSB</string> - <key>CFBundlePackageType</key> <string>KEXT</string> - <key>CFBundleSignature</key> <string>????</string> - <key>CFBundleVersion</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string> - <key>CFBundleShortVersionString</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string> - <key>CFBundleGetInfoString</key> <string>@VBOX_PRODUCT@ @VBOX_VERSION_STRING@, © 2007-@VBOX_C_YEAR@ @VBOX_VENDOR@</string> - <key>IOKitPersonalities</key> - <dict> - <key>VBoxUSB</key> - <dict> - <key>CFBundleIdentifier</key> <string>org.virtualbox.kext.VBoxUSB</string> - <key>IOClass</key> <string>org_virtualbox_VBoxUSB</string> - <key>IOMatchCategory</key> <string>org_virtualbox_VBoxUSB</string> - <key>IOProviderClass</key> <string>IOResources</string> - <key>IOResourceMatch</key> <string>IOKit</string> - <key>IOUserClientClass</key> <string>org_virtualbox_VBoxUSBClient</string> - </dict> - <key>VBoxUSBDevice</key> - <dict> - <key>CFBundleIdentifier</key> <string>org.virtualbox.kext.VBoxUSB</string> - <key>IOClass</key> <string>org_virtualbox_VBoxUSBDevice</string> - <key>IOProviderClass</key> <string>IOUSBDevice</string> - <key>idVendor</key> <string>*</string> - <key>idProduct</key> <string>*</string> - <key>bcdDevice</key> <string>*</string> - <key>IOProbeScore</key> <integer>9942</integer> - <key>IOProviderMergeProperties</key> - <dict> - <key>IOCFPlugInTypes</key> - <dict> - <key>9dc7b780-9ec0-11d4-a54f-000a27052861</key> <string>IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle</string> - </dict> - <key>IOUserClientClass</key> <string>IOUSBDeviceUserClientV2</string> - </dict> - </dict> - <key>VBoxUSBInterface</key> - <dict> - <key>CFBundleIdentifier</key> <string>org.virtualbox.kext.VBoxUSB</string> - <key>IOClass</key> <string>org_virtualbox_VBoxUSBInterface</string> - <key>IOProviderClass</key> <string>IOUSBInterface</string> - <key>idVendor</key> <string>*</string> - <key>idProduct</key> <string>*</string> - <key>bcdDevice</key> <string>*</string> - <key>bConfigurationValue</key> <string>*</string> - <key>bInterfaceNumber</key> <string>*</string> - <key>IOProbeScore</key> <integer>9942</integer> - <key>IOProviderMergeProperties</key> - <dict> - <key>IOCFPlugInTypes</key> - <dict> - <key>2d9786c6-9ef3-11d4-ad51-000a27052861</key> <string>IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle</string> - </dict> - <key>IOUserClientClass</key> <string>IOUSBInterfaceUserClientV2</string> - </dict> - </dict> - </dict> - <key>OSBundleLibraries</key> - <dict> - <key>com.apple.iokit.IOUSBFamily</key> <string>3.0.0</string> - <key>com.apple.iokit.IOUSBUserClient</key> <string>3.0.0</string> - <key>com.apple.kpi.iokit</key> <string>9.0.0</string> - <key>com.apple.kpi.bsd</key> <string>9.0.0</string> - <key>com.apple.kpi.mach</key> <string>9.0.0</string> - <key>com.apple.kpi.libkern</key> <string>9.0.0</string> - <key>com.apple.kpi.unsupported</key> <string>9.0.0</string> - <key>org.virtualbox.kext.VBoxDrv</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string> - </dict> - <key>OSBundleLibraries_x86_64</key> - <dict> - <key>com.apple.iokit.IOUSBFamily</key> <string>3.5.0a25</string> - <key>com.apple.iokit.IOUSBUserClient</key> <string>3.5.0a25</string> - <key>com.apple.kpi.iokit</key> <string>10.0.0d3</string> - <key>com.apple.kpi.bsd</key> <string>10.0.0d3</string> - <key>com.apple.kpi.mach</key> <string>10.0.0d3</string> - <key>com.apple.kpi.libkern</key> <string>10.0.0d3</string> - <key>com.apple.kpi.unsupported</key> <string>10.0.0d3</string> - <key>org.virtualbox.kext.VBoxDrv</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string> - </dict> -</dict> -</plist> - diff --git a/src/VBox/HostDrivers/VBoxUSB/darwin/Makefile.kmk b/src/VBox/HostDrivers/VBoxUSB/darwin/Makefile.kmk deleted file mode 100644 index 06d490e45a5..00000000000 --- a/src/VBox/HostDrivers/VBoxUSB/darwin/Makefile.kmk +++ /dev/null @@ -1,94 +0,0 @@ -# $Id$ -## @file -# Sub-Makefile for the Darwin VBoxUSB kernel extension. -# - -# -# Copyright (C) 2006-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. -# -# The contents of this file may alternatively be used under the terms -# of the Common Development and Distribution License Version 1.0 -# (CDDL) only, as it comes in the "COPYING.CDDL" file of the -# VirtualBox OSE distribution, in which case the provisions of the -# CDDL are applicable instead of those of the GPL. -# -# You may elect to license modified versions of this file under the -# terms and conditions of either the GPL or the CDDL or both. -# - -SUB_DEPTH = ../../../../.. -include $(KBUILD_PATH)/subheader.kmk -ifn1of ($(KBUILD_TARGET_ARCH), arm64) - -# -# VBoxUSB.kext - The Darwin Kernel Extension. -# - -# Leopard (x86) and Snow Leopard (x86/amd64) -SYSMODS.darwin += VBoxUSB -VBoxUSB_TEMPLATE := VBOXR0DRV -ifdef KMK_WITH_VERSION_COMPARE ## @todo @bugref{9790}: Remove after updating kmk. -if "$(VBOX_DEF_MACOSX_VERSION_MIN)" vge "10.11" # The IOUSBDevice.h header was removed in 10.11. -VBoxUSB_TEMPLATE := VBoxR0DrvOSX10.10 -endif -endif ## @todo @bugref{9790}: Remove after updating kmk. -VBoxUSB_INST = $(INST_VBOXUSB)Contents/MacOS/ -VBoxUSB_DEBUG_INST.darwin = $(patsubst %/,%,$(INST_VBOXUSB)) -VBoxUSB_INCS = \ - . \ - .. -#VBoxUSB_LDFLAGS = -v -Wl,-whyload -Wl,-v -Wl,-whatsloaded -VBoxUSB_SOURCES := \ - VBoxUSB.cpp \ - ../USBFilter.cpp \ - ../VBoxUSBFilterMgr.cpp - -INSTALLS += VBoxUSB.kext -VBoxUSB.kext_INST = $(INST_VBOXUSB)Contents/ -VBoxUSB.kext_SOURCES = $(VBoxUSB.kext_0_OUTDIR)/Contents/Info.plist -VBoxUSB.kext_CLEAN = $(VBoxUSB.kext_0_OUTDIR)/Contents/Info.plist -VBoxUSB.kext_BLDDIRS = $(VBoxUSB.kext_0_OUTDIR)/Contents/ - -$$(VBoxUSB.kext_0_OUTDIR)/Contents/Info.plist: $(PATH_SUB_CURRENT)/Info.plist $(VBOX_VERSION_MK) | $$(dir $$@) - $(call MSG_GENERATE,VBoxUSB,$@,$<) - $(QUIET)$(RM) -f $@ - $(QUIET)$(SED) \ - -e 's/@VBOX_VERSION_STRING@/$(VBOX_VERSION_STRING)/g' \ - -e 's/@VBOX_VERSION_MAJOR@/$(VBOX_VERSION_MAJOR)/g' \ - -e 's/@VBOX_VERSION_MINOR@/$(VBOX_VERSION_MINOR)/g' \ - -e 's/@VBOX_VERSION_BUILD@/$(VBOX_VERSION_BUILD)/g' \ - -e 's/@VBOX_VENDOR@/$(VBOX_VENDOR)/g' \ - -e 's/@VBOX_PRODUCT@/$(VBOX_PRODUCT)/g' \ - -e 's/@VBOX_C_YEAR@/$(VBOX_C_YEAR)/g' \ - --output $@ \ - $< - -$(evalcall2 VBOX_TEST_SIGN_KEXT,VBoxUSB) - -# Common manual loader script. -INSTALLS += ScriptsUSB -ScriptsUSB_INST = $(INST_DIST) -ScriptsUSB_EXEC_SOURCES = \ - loadusb.sh - -ifdef VBOX_WITH_TESTCASES -# -# Testcase for doing some manual driver testing... -# -PROGRAMS += tstOpenUSBDev -tstOpenUSBDev_TEMPLATE = VBOXR3TSTEXE -tstOpenUSBDev_SOURCES = testcase/tstOpenUSBDev.cpp -tstOpenUSBDev_LDFLAGS = -framework CoreFoundation -framework IOKit -endif - -endif # ! arm64 -include $(FILE_KBUILD_SUB_FOOTER) - diff --git a/src/VBox/HostDrivers/VBoxUSB/darwin/USBLib-darwin.cpp b/src/VBox/HostDrivers/VBoxUSB/darwin/USBLib-darwin.cpp deleted file mode 100644 index 3bd956a5787..00000000000 --- a/src/VBox/HostDrivers/VBoxUSB/darwin/USBLib-darwin.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/** $Id$ */ -/** @file - * USBLib - Library for wrapping up the VBoxUSB functionality, Darwin flavor. - */ - -/* - * Copyright (C) 2007-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. - * - * The contents of this file may alternatively be used under the terms - * of the Common Development and Distribution License Version 1.0 - * (CDDL) only, as it comes in the "COPYING.CDDL" file of the - * VirtualBox OSE distribution, in which case the provisions of the - * CDDL are applicable instead of those of the GPL. - * - * You may elect to license modified versions of this file under the - * terms and conditions of either the GPL or the CDDL or both. - */ - - -/********************************************************************************************************************************* -* Header Files * -*********************************************************************************************************************************/ -#include <VBox/usblib.h> -#include <iprt/errcore.h> -#include <VBox/log.h> -#include "VBoxUSBInterface.h" - -#include <iprt/assert.h> -#include <iprt/asm.h> - -#include <mach/mach_port.h> -#include <IOKit/IOKitLib.h> - - -/********************************************************************************************************************************* -* Defined Constants And Macros * -*********************************************************************************************************************************/ -/** The IOClass key of the service (see VBoxUSB.cpp / Info.plist). */ -#define IOCLASS_NAME "org_virtualbox_VBoxUSB" - - -/********************************************************************************************************************************* -* Global Variables * -*********************************************************************************************************************************/ -/** Reference counter. */ -static uint32_t volatile g_cUsers = 0; -/** The IOMasterPort. */ -static mach_port_t g_MasterPort = 0; -/** The current service connection. */ -static io_connect_t g_Connection = 0; - - - -USBLIB_DECL(int) USBLibInit(void) -{ - /* - * Already open? - * This isn't properly serialized, but we'll be fine with the current usage. - */ - if (g_cUsers) - { - ASMAtomicIncU32(&g_cUsers); - return VINF_SUCCESS; - } - - /* - * Finding the VBoxUSB service. - */ - mach_port_t MasterPort; - kern_return_t kr = IOMasterPort(MACH_PORT_NULL, &MasterPort); - if (kr != kIOReturnSuccess) - { - LogRel(("USBLib: IOMasterPort -> %#x\n", kr)); - return RTErrConvertFromDarwinKern(kr); - } - - CFDictionaryRef ClassToMatch = IOServiceMatching(IOCLASS_NAME); - if (!ClassToMatch) - { - LogRel(("USBLib: IOServiceMatching(\"%s\") failed.\n", IOCLASS_NAME)); - return VERR_GENERAL_FAILURE; - } - - /* Create an io_iterator_t for all instances of our drivers class that exist in the IORegistry. */ - io_iterator_t Iterator; - kr = IOServiceGetMatchingServices(g_MasterPort, ClassToMatch, &Iterator); - if (kr != kIOReturnSuccess) - { - LogRel(("USBLib: IOServiceGetMatchingServices returned %#x\n", kr)); - return RTErrConvertFromDarwinKern(kr); - } - - /* Get the first item in the iterator and release it. */ - io_service_t ServiceObject = IOIteratorNext(Iterator); - IOObjectRelease(Iterator); - if (!ServiceObject) - { - LogRel(("USBLib: Couldn't find any matches.\n")); - return VERR_GENERAL_FAILURE; - } - - /* - * Open the service. - * This will cause the user client class in VBoxUSB.cpp to be instantiated. - */ - kr = IOServiceOpen(ServiceObject, mach_task_self(), VBOXUSB_DARWIN_IOSERVICE_COOKIE, &g_Connection); - IOObjectRelease(ServiceObject); - if (kr != kIOReturnSuccess) - { - LogRel(("USBLib: IOServiceOpen returned %#x\n", kr)); - return RTErrConvertFromDarwinKern(kr); - } - - ASMAtomicIncU32(&g_cUsers); - return VINF_SUCCESS; -} - - -USBLIB_DECL(int) USBLibTerm(void) -{ - if (!g_cUsers) - return VERR_WRONG_ORDER; - if (ASMAtomicDecU32(&g_cUsers) != 0) - return VINF_SUCCESS; - - /* - * We're the last guy, close down the connection. - */ - kern_return_t kr = IOServiceClose(g_Connection); - if (kr != kIOReturnSuccess) - { - LogRel(("USBLib: Warning: IOServiceClose(%p) returned %#x\n", g_Connection, kr)); - AssertMsgFailed(("%#x\n", kr)); - } - g_Connection = 0; - - return VINF_SUCCESS; -} - - -USBLIB_DECL(void *) USBLibAddFilter(PCUSBFILTER pFilter) -{ - VBOXUSBADDFILTEROUT Out = { 0, VERR_WRONG_ORDER }; -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 - IOByteCount cbOut = sizeof(Out); - kern_return_t kr = IOConnectMethodStructureIStructureO(g_Connection, - VBOXUSBMETHOD_ADD_FILTER, - sizeof(*pFilter), - &cbOut, - (void *)pFilter, - &Out); -#else /* 10.5 and later */ - size_t cbOut = sizeof(Out); - kern_return_t kr = IOConnectCallStructMethod(g_Connection, - VBOXUSBMETHOD_ADD_FILTER, - (void *)pFilter, sizeof(*pFilter), - &Out, &cbOut); -#endif /* 10.5 and later */ - if ( kr == kIOReturnSuccess - && RT_SUCCESS(Out.rc)) - { - Assert(cbOut == sizeof(Out)); - Assert((void *)Out.uId != NULL); - return (void *)Out.uId; - } - - AssertMsgFailed(("kr=%#x Out.rc=%Rrc\n", kr, Out.rc)); - return NULL; -} - - -USBLIB_DECL(void) USBLibRemoveFilter(void *pvId) -{ - int rc = VERR_WRONG_ORDER; -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 - IOByteCount cbOut = sizeof(rc); - kern_return_t kr = IOConnectMethodStructureIStructureO(g_Connection, - VBOXUSBMETHOD_REMOVE_FILTER, - sizeof(pvId), - &cbOut, - &pvId, - &rc); -#else /* 10.5 and later */ - size_t cbOut = sizeof(rc); - kern_return_t kr = IOConnectCallStructMethod(g_Connection, - VBOXUSBMETHOD_REMOVE_FILTER, - (void *)&pvId, sizeof(pvId), - &rc, &cbOut); -#endif /* 10.5 and later */ - AssertMsg(kr == kIOReturnSuccess && RT_SUCCESS(rc), ("kr=%#x rc=%Rrc\n", kr, rc)); - NOREF(kr); -} - diff --git a/src/VBox/HostDrivers/VBoxUSB/darwin/VBoxUSB.cpp b/src/VBox/HostDrivers/VBoxUSB/darwin/VBoxUSB.cpp deleted file mode 100644 index 3d91e49b598..00000000000 --- a/src/VBox/HostDrivers/VBoxUSB/darwin/VBoxUSB.cpp +++ /dev/null @@ -1,1890 +0,0 @@ -/* $Id$ */ -/** @file - * VirtualBox USB driver for Darwin. - * - * This driver is responsible for hijacking USB devices when any of the - * VBoxSVC daemons requests it. It is also responsible for arbitrating - * access to hijacked USB devices. - */ - -/* - * Copyright (C) 2006-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. - * - * The contents of this file may alternatively be used under the terms - * of the Common Development and Distribution License Version 1.0 - * (CDDL) only, as it comes in the "COPYING.CDDL" file of the - * VirtualBox OSE distribution, in which case the provisions of the - * CDDL are applicable instead of those of the GPL. - * - * You may elect to license modified versions of this file under the - * terms and conditions of either the GPL or the CDDL or both. - */ - - -/********************************************************************************************************************************* -* Header Files * -*********************************************************************************************************************************/ -#define LOG_GROUP LOG_GROUP_USB_DRV -/* Deal with conflicts first. - * (This is mess inherited from BSD. The *BSDs has clean this up long ago.) */ -#include <sys/param.h> -#undef PVM -#include <IOKit/IOLib.h> /* Assert as function */ - -#include "VBoxUSBInterface.h" -#include "VBoxUSBFilterMgr.h" -#include <VBox/version.h> -#include <VBox/usblib-darwin.h> -#include <VBox/log.h> -#include <iprt/types.h> -#include <iprt/initterm.h> -#include <iprt/assert.h> -#include <iprt/semaphore.h> -#include <iprt/process.h> -#include <iprt/alloc.h> -#include <iprt/errcore.h> -#include <iprt/asm.h> - -#include <mach/kmod.h> -#include <miscfs/devfs/devfs.h> -#include <sys/conf.h> -#include <sys/errno.h> -#include <sys/ioccom.h> -#include <sys/malloc.h> -#include <sys/proc.h> -#include <kern/task.h> -#include <IOKit/IOService.h> -#include <IOKit/IOUserClient.h> -#include <IOKit/IOKitKeys.h> -#include <IOKit/usb/USB.h> -#include <IOKit/usb/IOUSBDevice.h> -#include <IOKit/usb/IOUSBInterface.h> -#include <IOKit/usb/IOUSBUserClient.h> - -/* private: */ -RT_C_DECLS_BEGIN -extern void *get_bsdtask_info(task_t); -RT_C_DECLS_END - - -/********************************************************************************************************************************* -* Defined Constants And Macros * -*********************************************************************************************************************************/ -/** Locks the lists. */ -#define VBOXUSB_LOCK() do { int rc = RTSemFastMutexRequest(g_Mtx); AssertRC(rc); } while (0) -/** Unlocks the lists. */ -#define VBOXUSB_UNLOCK() do { int rc = RTSemFastMutexRelease(g_Mtx); AssertRC(rc); } while (0) - - -/********************************************************************************************************************************* -* Internal Functions * -*********************************************************************************************************************************/ -RT_C_DECLS_BEGIN -static kern_return_t VBoxUSBStart(struct kmod_info *pKModInfo, void *pvData); -static kern_return_t VBoxUSBStop(struct kmod_info *pKModInfo, void *pvData); -RT_C_DECLS_END - - -/********************************************************************************************************************************* -* Structures and Typedefs * -*********************************************************************************************************************************/ -/** - * The service class. - * - * This is the management service that VBoxSVC and the VMs speak to. - * - * @remark The method prototypes are ordered somewhat after their order of - * invocation, while the implementation is ordered by pair. - */ -class org_virtualbox_VBoxUSB : public IOService -{ - OSDeclareDefaultStructors(org_virtualbox_VBoxUSB); - -public: - RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT(); - - /** @name IOService - * @{ */ - virtual bool init(OSDictionary *pDictionary = 0); - virtual bool start(IOService *pProvider); - virtual bool open(IOService *pForClient, IOOptionBits fOptions = 0, void *pvArg = 0); - virtual bool terminate(IOOptionBits fOptions); - virtual void close(IOService *pForClient, IOOptionBits fOptions = 0); - virtual void stop(IOService *pProvider); - virtual void free(); - /** @} */ - -private: - /** Guard against the parent class growing and us using outdated headers. */ - uint8_t m_abSafetyPadding[256]; -}; -OSDefineMetaClassAndStructors(org_virtualbox_VBoxUSB, IOService); - - -/** - * The user client class that pairs up with org_virtualbox_VBoxUSB. - */ -class org_virtualbox_VBoxUSBClient : public IOUserClient -{ - OSDeclareDefaultStructors(org_virtualbox_VBoxUSBClient); - -public: - RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT(); - - /** @name IOService & IOUserClient - * @{ */ - virtual bool initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type); - virtual bool start(IOService *pProvider); - virtual IOReturn clientClose(void); - virtual IOReturn clientDied(void); - virtual bool terminate(IOOptionBits fOptions = 0); - virtual bool finalize(IOOptionBits fOptions); - virtual void stop(IOService *pProvider); - virtual void free(); - virtual IOExternalMethod *getTargetAndMethodForIndex(IOService **ppService, UInt32 iMethod); - /** @} */ - - /** @name User client methods - * @{ */ - IOReturn addFilter(PUSBFILTER pFilter, PVBOXUSBADDFILTEROUT pOut, IOByteCount cbFilter, IOByteCount *pcbOut); - IOReturn removeFilter(uintptr_t *puId, int *prc, IOByteCount cbIn, IOByteCount *pcbOut); - /** @} */ - - static bool isClientTask(task_t ClientTask); - -private: - /** Guard against the parent class growing and us using outdated headers. */ - uint8_t m_abSafetyPadding[256]; - /** The service provider. */ - org_virtualbox_VBoxUSB *m_pProvider; - /** The client task. */ - task_t m_Task; - /** The client process. */ - RTPROCESS m_Process; - /** Pointer to the next user client. */ - org_virtualbox_VBoxUSBClient * volatile m_pNext; - /** List of user clients. Protected by g_Mtx. */ - static org_virtualbox_VBoxUSBClient * volatile s_pHead; -}; -OSDefineMetaClassAndStructors(org_virtualbox_VBoxUSBClient, IOUserClient); - - -/** - * The IOUSBDevice driver class. - * - * The main purpose of this is hijack devices matching current filters. - * - * @remarks This is derived from IOUSBUserClientInit instead of IOService because we must make - * sure IOUSBUserClientInit::start() gets invoked for this provider. The problem is that - * there is some kind of magic that prevents this from happening if we boost the probe - * score to high. With the result that we don't have the required plugin entry for - * user land and consequently cannot open it. - * - * So, to avoid having to write a lot of code we just inherit from IOUSBUserClientInit - * and make some possibly bold assumptions about it not changing. This just means - * we'll have to keep an eye on the source apple releases or only call - * IOUSBUserClientInit::start() and hand the rest of the super calls to IOService. For - * now we're doing it by the C++ book. - */ -class org_virtualbox_VBoxUSBDevice : public IOUSBUserClientInit -{ - OSDeclareDefaultStructors(org_virtualbox_VBoxUSBDevice); - -public: - RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT(); - - /** @name IOService - * @{ */ - virtual bool init(OSDictionary *pDictionary = 0); - virtual IOService *probe(IOService *pProvider, SInt32 *pi32Score); - virtual bool start(IOService *pProvider); - virtual bool terminate(IOOptionBits fOptions = 0); - virtual void stop(IOService *pProvider); - virtual void free(); - virtual IOReturn message(UInt32 enmMsg, IOService *pProvider, void *pvArg = 0); - /** @} */ - - static void scheduleReleaseByOwner(RTPROCESS Owner); -private: - /** Padding to guard against parent class expanding (see class remarks). */ - uint8_t m_abSafetyPadding[256]; - /** The interface we're driving (aka. the provider). */ - IOUSBDevice *m_pDevice; - /** The owner process, meaning the VBoxSVC process. */ - RTPROCESS volatile m_Owner; - /** The client process, meaning the VM process. */ - RTPROCESS volatile m_Client; - /** The ID of the matching filter. */ - uintptr_t m_uId; - /** Have we opened the device or not? */ - bool volatile m_fOpen; - /** Should be open the device on the next close notification message? */ - bool volatile m_fOpenOnWasClosed; - /** Whether to re-enumerate this device when the client closes it. - * This is something we'll do when the filter owner dies. */ - bool volatile m_fReleaseOnClose; - /** Whether we're being unloaded or not. - * Only valid in stop(). */ - bool m_fBeingUnloaded; - /** Pointer to the next device in the list. */ - org_virtualbox_VBoxUSBDevice * volatile m_pNext; - /** Pointer to the list head. Protected by g_Mtx. */ - static org_virtualbox_VBoxUSBDevice * volatile s_pHead; - -#ifdef DEBUG - /** The interest notifier. */ - IONotifier *m_pNotifier; - - static IOReturn MyInterestHandler(void *pvTarget, void *pvRefCon, UInt32 enmMsgType, - IOService *pProvider, void * pvMsgArg, vm_size_t cbMsgArg); -#endif -}; -OSDefineMetaClassAndStructors(org_virtualbox_VBoxUSBDevice, IOUSBUserClientInit); - - -/** - * The IOUSBInterface driver class. - * - * The main purpose of this is hijack interfaces which device is driven - * by org_virtualbox_VBoxUSBDevice. - * - * @remarks See org_virtualbox_VBoxUSBDevice for why we use IOUSBUserClientInit. - */ -class org_virtualbox_VBoxUSBInterface : public IOUSBUserClientInit -{ - OSDeclareDefaultStructors(org_virtualbox_VBoxUSBInterface); - -public: - RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT(); - - /** @name IOService - * @{ */ - virtual bool init(OSDictionary *pDictionary = 0); - virtual IOService *probe(IOService *pProvider, SInt32 *pi32Score); - virtual bool start(IOService *pProvider); - virtual bool terminate(IOOptionBits fOptions = 0); - virtual void stop(IOService *pProvider); - virtual void free(); - virtual IOReturn message(UInt32 enmMsg, IOService *pProvider, void *pvArg = 0); - /** @} */ - -private: - /** Padding to guard against parent class expanding (see class remarks). */ - uint8_t m_abSafetyPadding[256]; - /** The interface we're driving (aka. the provider). */ - IOUSBInterface *m_pInterface; - /** Have we opened the device or not? */ - bool volatile m_fOpen; - /** Should be open the device on the next close notification message? */ - bool volatile m_fOpenOnWasClosed; -}; -OSDefineMetaClassAndStructors(org_virtualbox_VBoxUSBInterface, IOUSBUserClientInit); - - - - - -/********************************************************************************************************************************* -* Global Variables * -*********************************************************************************************************************************/ -/* - * Declare the module stuff. - */ -RT_C_DECLS_BEGIN -extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData); -extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData); - -KMOD_EXPLICIT_DECL(VBoxDrv, VBOX_VERSION_STRING, _start, _stop) -DECL_HIDDEN_DATA(kmod_start_func_t *) _realmain = VBoxUSBStart; -DECL_HIDDEN_DATA(kmod_stop_func_t *) _antimain = VBoxUSBStop; -DECL_HIDDEN_DATA(int) _kext_apple_cc = __APPLE_CC__; -RT_C_DECLS_END - -/** Mutex protecting the lists. */ -static RTSEMFASTMUTEX g_Mtx = NIL_RTSEMFASTMUTEX; -org_virtualbox_VBoxUSBClient * volatile org_virtualbox_VBoxUSBClient::s_pHead = NULL; -org_virtualbox_VBoxUSBDevice * volatile org_virtualbox_VBoxUSBDevice::s_pHead = NULL; - -/** Global instance count - just for checking proving that everything is destroyed correctly. */ -static volatile uint32_t g_cInstances = 0; - - -/** - * Start the kernel module. - */ -static kern_return_t VBoxUSBStart(struct kmod_info *pKModInfo, void *pvData) -{ - RT_NOREF(pKModInfo, pvData); - int rc; - Log(("VBoxUSBStart\n")); - - /* - * Initialize IPRT. - */ - rc = RTR0Init(0); - if (RT_SUCCESS(rc)) - { - /* - * Create the spinlock. - */ - rc = RTSemFastMutexCreate(&g_Mtx); - if (RT_SUCCESS(rc)) - { - rc = VBoxUSBFilterInit(); - if (RT_SUCCESS(rc)) - { -#if 0 /* testing */ - USBFILTER Flt; - USBFilterInit(&Flt, USBFILTERTYPE_CAPTURE); - USBFilterSetNumExact(&Flt, USBFILTERIDX_VENDOR_ID, 0x096e, true); - uintptr_t uId; - rc = VBoxUSBFilterAdd(&Flt, 1, &uId); - printf("VBoxUSB: VBoxUSBFilterAdd #1 -> %d + %p\n", rc, uId); - - USBFilterInit(&Flt, USBFILTERTYPE_CAPTURE); - USBFilterSetStringPattern(&Flt, USBFILTERIDX_PRODUCT_STR, "*DISK*", true); - rc = VBoxUSBFilterAdd(&Flt, 2, &uId); - printf("VBoxUSB: VBoxUSBFilterAdd #2 -> %d + %p\n", rc, uId); -#endif - return KMOD_RETURN_SUCCESS; - } - printf("VBoxUSB: VBoxUSBFilterInit failed (rc=%d)\n", rc); - RTSemFastMutexDestroy(g_Mtx); - g_Mtx = NIL_RTSEMFASTMUTEX; - } - else - printf("VBoxUSB: RTSemFastMutexCreate failed (rc=%d)\n", rc); - RTR0Term(); - } - else - printf("VBoxUSB: failed to initialize IPRT (rc=%d)\n", rc); - - return KMOD_RETURN_FAILURE; -} - - -/** - * Stop the kernel module. - */ -static kern_return_t VBoxUSBStop(struct kmod_info *pKModInfo, void *pvData) -{ - RT_NOREF(pKModInfo, pvData); - Log(("VBoxUSBStop: g_cInstances=%d\n", g_cInstances)); - - /** @todo Fix problem with crashing when unloading a driver that's in use. */ - - /* - * Undo the work done during start (in reverse order). - */ - VBoxUSBFilterTerm(); - - int rc = RTSemFastMutexDestroy(g_Mtx); - AssertRC(rc); - g_Mtx = NIL_RTSEMFASTMUTEX; - - RTR0Term(); - - Log(("VBoxUSBStop - done\n")); - return KMOD_RETURN_SUCCESS; -} - - - - - -#ifdef LOG_ENABLED -/** - * Gets the name of a IOKit message. - * - * @returns Message name (read only). - * @param enmMsg The message. - */ -DECLINLINE(const char *) DbgGetIOKitMessageName(UInt32 enmMsg) -{ - switch (enmMsg) - { -# define MY_CASE(enm) case enm: return #enm; break - MY_CASE(kIOMessageServiceIsTerminated); - MY_CASE(kIOMessageServiceIsSuspended); - MY_CASE(kIOMessageServiceIsResumed); - MY_CASE(kIOMessageServiceIsRequestingClose); - MY_CASE(kIOMessageServiceIsAttemptingOpen); - MY_CASE(kIOMessageServiceWasClosed); - MY_CASE(kIOMessageServiceBusyStateChange); - MY_CASE(kIOMessageServicePropertyChange); - MY_CASE(kIOMessageCanDevicePowerOff); - MY_CASE(kIOMessageDeviceWillPowerOff); - MY_CASE(kIOMessageDeviceWillNotPowerOff); - MY_CASE(kIOMessageDeviceHasPoweredOn); - MY_CASE(kIOMessageCanSystemPowerOff); - MY_CASE(kIOMessageSystemWillPowerOff); - MY_CASE(kIOMessageSystemWillNotPowerOff); - MY_CASE(kIOMessageCanSystemSleep); - MY_CASE(kIOMessageSystemWillSleep); - MY_CASE(kIOMessageSystemWillNotSleep); - MY_CASE(kIOMessageSystemHasPoweredOn); - MY_CASE(kIOMessageSystemWillRestart); - MY_CASE(kIOMessageSystemWillPowerOn); - MY_CASE(kIOUSBMessageHubResetPort); - MY_CASE(kIOUSBMessageHubSuspendPort); - MY_CASE(kIOUSBMessageHubResumePort); - MY_CASE(kIOUSBMessageHubIsDeviceConnected); - MY_CASE(kIOUSBMessageHubIsPortEnabled); - MY_CASE(kIOUSBMessageHubReEnumeratePort); - MY_CASE(kIOUSBMessagePortHasBeenReset); - MY_CASE(kIOUSBMessagePortHasBeenResumed); - MY_CASE(kIOUSBMessageHubPortClearTT); - MY_CASE(kIOUSBMessagePortHasBeenSuspended); - MY_CASE(kIOUSBMessageFromThirdParty); - MY_CASE(kIOUSBMessagePortWasNotSuspended); - MY_CASE(kIOUSBMessageExpressCardCantWake); -// MY_CASE(kIOUSBMessageCompositeDriverReconfigured); -# undef MY_CASE - } - return "unknown"; -} -#endif /* LOG_ENABLED */ - - - - - -/* - * - * org_virtualbox_VBoxUSB - * - */ - - -/** - * Initialize the object. - * @remark Only for logging. - */ -bool -org_virtualbox_VBoxUSB::init(OSDictionary *pDictionary) -{ - uint32_t cInstances = ASMAtomicIncU32(&g_cInstances); - Log(("VBoxUSB::init([%p], %p) new g_cInstances=%d\n", this, pDictionary, cInstances)); - RT_NOREF_PV(cInstances); - - if (IOService::init(pDictionary)) - { - /* init members. */ - return true; - } - ASMAtomicDecU32(&g_cInstances); - return false; -} - - -/** - * Free the object. - * @remark Only for logging. - */ -void -org_virtualbox_VBoxUSB::free() -{ - uint32_t cInstances = ASMAtomicDecU32(&g_cInstances); NOREF(cInstances); - Log(("VBoxUSB::free([%p]) new g_cInstances=%d\n", this, cInstances)); - IOService::free(); -} - - -/** - * Start this service. - */ -bool -org_virtualbox_VBoxUSB::start(IOService *pProvider) -{ - Log(("VBoxUSB::start([%p], %p {%s})\n", this, pProvider, pProvider->getName())); - - if (IOService::start(pProvider)) - { - /* register the service. */ - registerService(); - return true; - } - return false; -} - - -/** - * Stop this service. - * @remark Only for logging. - */ -void -org_virtualbox_VBoxUSB::stop(IOService *pProvider) -{ - Log(("VBoxUSB::stop([%p], %p (%s))\n", this, pProvider, pProvider->getName())); - IOService::stop(pProvider); -} - - -/** - * Stop this service. - * @remark Only for logging. - */ -bool -org_virtualbox_VBoxUSB::open(IOService *pForClient, IOOptionBits fOptions/* = 0*/, void *pvArg/* = 0*/) -{ - Log(("VBoxUSB::open([%p], %p, %#x, %p)\n", this, pForClient, fOptions, pvArg)); - bool fRc = IOService::open(pForClient, fOptions, pvArg); - Log(("VBoxUSB::open([%p], %p, %#x, %p) -> %d\n", this, pForClient, fOptions, pvArg, fRc)); - return fRc; -} - - -/** - * Stop this service. - * @remark Only for logging. - */ -void -org_virtualbox_VBoxUSB::close(IOService *pForClient, IOOptionBits fOptions/* = 0*/) -{ - Log(("VBoxUSB::close([%p], %p, %#x)\n", this, pForClient, fOptions)); - IOService::close(pForClient, fOptions); -} - - -/** - * Terminate request. - * @remark Only for logging. - */ -bool -org_virtualbox_VBoxUSB::terminate(IOOptionBits fOptions) -{ - Log(("VBoxUSB::terminate([%p], %#x): g_cInstances=%d\n", this, fOptions, g_cInstances)); - bool fRc = IOService::terminate(fOptions); - Log(("VBoxUSB::terminate([%p], %#x): returns %d\n", this, fOptions, fRc)); - return fRc; -} - - - - - - - - - - - -/* - * - * org_virtualbox_VBoxUSBClient - * - */ - - -/** - * Initializer called when the client opens the service. - */ -bool -org_virtualbox_VBoxUSBClient::initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type) -{ - if (!OwningTask) - { - Log(("VBoxUSBClient::initWithTask([%p], %p, %p, %#x) -> false (no task)\n", this, OwningTask, pvSecurityId, u32Type)); - return false; - } - if (u32Type != VBOXUSB_DARWIN_IOSERVICE_COOKIE) - { - Log(("VBoxUSBClient::initWithTask: Bade cookie %#x\n", u32Type)); - return false; - } - - proc_t pProc = (proc_t)get_bsdtask_info(OwningTask); /* we need the pid */ - Log(("VBoxUSBClient::initWithTask([%p], %p(->%p:{.pid=%d}, %p, %#x)\n", - this, OwningTask, pProc, pProc ? proc_pid(pProc) : -1, pvSecurityId, u32Type)); - - if (IOUserClient::initWithTask(OwningTask, pvSecurityId , u32Type)) - { - /* - * In theory we have to call task_reference() to make sure that the task is - * valid during the lifetime of this object. The pointer is only used to check - * for the context this object is called in though and never dereferenced - * or passed to anything which might, so we just skip this step. - */ - m_pProvider = NULL; - m_Task = OwningTask; - m_Process = pProc ? proc_pid(pProc) : NIL_RTPROCESS; - m_pNext = NULL; - - uint32_t cInstances = ASMAtomicIncU32(&g_cInstances); - Log(("VBoxUSBClient::initWithTask([%p], %p(->%p:{.pid=%d}, %p, %#x) -> true; new g_cInstances=%d\n", - this, OwningTask, pProc, pProc ? proc_pid(pProc) : -1, pvSecurityId, u32Type, cInstances)); - RT_NOREF_PV(cInstances); - return true; - } - - Log(("VBoxUSBClient::initWithTask([%p], %p(->%p:{.pid=%d}, %p, %#x) -> false\n", - this, OwningTask, pProc, pProc ? proc_pid(pProc) : -1, pvSecurityId, u32Type)); - return false; -} - - -/** - * Free the object. - * @remark Only for logging. - */ -void -org_virtualbox_VBoxUSBClient::free() -{ - uint32_t cInstances = ASMAtomicDecU32(&g_cInstances); NOREF(cInstances); - Log(("VBoxUSBClient::free([%p]) new g_cInstances=%d\n", this, cInstances)); - IOUserClient::free(); -} - - -/** - * Start the client service. - */ -bool -org_virtualbox_VBoxUSBClient::start(IOService *pProvider) -{ - Log(("VBoxUSBClient::start([%p], %p)\n", this, pProvider)); - if (IOUserClient::start(pProvider)) - { - m_pProvider = OSDynamicCast(org_virtualbox_VBoxUSB, pProvider); - if (m_pProvider) - { - /* - * Add ourselves to the list of user clients. - */ - VBOXUSB_LOCK(); - - m_pNext = s_pHead; - s_pHead = this; - - VBOXUSB_UNLOCK(); - - return true; - } - Log(("VBoxUSBClient::start: %p isn't org_virtualbox_VBoxUSB\n", pProvider)); - } - return false; -} - - -/** - * Client exits normally. - */ -IOReturn -org_virtualbox_VBoxUSBClient::clientClose(void) -{ - Log(("VBoxUSBClient::clientClose([%p:{.m_Process=%d}])\n", this, (int)m_Process)); - - /* - * Remove this process from the client list. - */ - VBOXUSB_LOCK(); - - org_virtualbox_VBoxUSBClient *pPrev = NULL; - for (org_virtualbox_VBoxUSBClient *pCur = s_pHead; pCur; pCur = pCur->m_pNext) - { - if (pCur == this) - { - if (pPrev) - pPrev->m_pNext = m_pNext; - else - s_pHead = m_pNext; - m_pNext = NULL; - break; - } - pPrev = pCur; - } - - VBOXUSB_UNLOCK(); - - /* - * Drop all filters owned by this client. - */ - if (m_Process != NIL_RTPROCESS) - VBoxUSBFilterRemoveOwner(m_Process); - - /* - * Schedule all devices owned (filtered) by this process for - * immediate release or release upon close. - */ - if (m_Process != NIL_RTPROCESS) - org_virtualbox_VBoxUSBDevice::scheduleReleaseByOwner(m_Process); - - /* - * Initiate termination. - */ - m_pProvider = NULL; - terminate(); - - return kIOReturnSuccess; -} - - -/** - * The client exits abnormally / forgets to do cleanups. - * @remark Only for logging. - */ -IOReturn -org_virtualbox_VBoxUSBClient::clientDied(void) -{ - Log(("VBoxUSBClient::clientDied([%p]) m_Task=%p R0Process=%p Process=%d\n", - this, m_Task, RTR0ProcHandleSelf(), RTProcSelf())); - - /* IOUserClient::clientDied() calls clientClose... */ - return IOUserClient::clientDied(); -} - - -/** - * Terminate the service (initiate the destruction). - * @remark Only for logging. - */ -bool -org_virtualbox_VBoxUSBClient::terminate(IOOptionBits fOptions) -{ - /* kIOServiceRecursing, kIOServiceRequired, kIOServiceTerminate, kIOServiceSynchronous - interesting option bits */ - Log(("VBoxUSBClient::terminate([%p], %#x)\n", this, fOptions)); - return IOUserClient::terminate(fOptions); -} - - -/** - * The final stage of the client service destruction. - * @remark Only for logging. - */ -bool -org_virtualbox_VBoxUSBClient::finalize(IOOptionBits fOptions) -{ - Log(("VBoxUSBClient::finalize([%p], %#x)\n", this, fOptions)); - return IOUserClient::finalize(fOptions); -} - - -/** - * Stop the client service. - */ -void -org_virtualbox_VBoxUSBClient::stop(IOService *pProvider) -{ - Log(("VBoxUSBClient::stop([%p])\n", this)); - IOUserClient::stop(pProvider); - - /* - * Paranoia. - */ - VBOXUSB_LOCK(); - - org_virtualbox_VBoxUSBClient *pPrev = NULL; - for (org_virtualbox_VBoxUSBClient *pCur = s_pHead; pCur; pCur = pCur->m_pNext) - { - if (pCur == this) - { - if (pPrev) - pPrev->m_pNext = m_pNext; - else - s_pHead = m_pNext; - m_pNext = NULL; - break; - } - pPrev = pCur; - } - - VBOXUSB_UNLOCK(); -} - - -/** - * Translate a user method index into a service object and an external method structure. - * - * @returns Pointer to external method structure descripting the method. - * NULL if the index isn't valid. - * @param ppService Where to store the service object on success. - * @param iMethod The method index. - */ -IOExternalMethod * -org_virtualbox_VBoxUSBClient::getTargetAndMethodForIndex(IOService **ppService, UInt32 iMethod) -{ - static IOExternalMethod s_aMethods[VBOXUSBMETHOD_END] = - { - /*[VBOXUSBMETHOD_ADD_FILTER] = */ - { - (IOService *)0, /* object */ - (IOMethod)&org_virtualbox_VBoxUSBClient::addFilter, /* func */ - kIOUCStructIStructO, /* flags - struct input (count0) and struct output (count1) */ - sizeof(USBFILTER), /* count0 - size of the input struct. */ - sizeof(VBOXUSBADDFILTEROUT) /* count1 - size of the return struct. */ - }, - /* [VBOXUSBMETHOD_FILTER_REMOVE] = */ - { - (IOService *)0, /* object */ - (IOMethod)&org_virtualbox_VBoxUSBClient::removeFilter, /* func */ - kIOUCStructIStructO, /* flags - struct input (count0) and struct output (count1) */ - sizeof(uintptr_t), /* count0 - size of the input (id) */ - sizeof(int) /* count1 - size of the output (rc) */ - }, - }; - - if (RT_UNLIKELY(iMethod >= RT_ELEMENTS(s_aMethods))) - return NULL; - - *ppService = this; - return &s_aMethods[iMethod]; -} - - -/** - * Add filter user request. - * - * @returns IOKit status code. - * @param pFilter The filter to add. - * @param pOut Pointer to the output structure. - * @param cbFilter Size of the filter structure. - * @param pcbOut In/Out - sizeof(*pOut). - */ -IOReturn -org_virtualbox_VBoxUSBClient::addFilter(PUSBFILTER pFilter, PVBOXUSBADDFILTEROUT pOut, IOByteCount cbFilter, IOByteCount *pcbOut) -{ - Log(("VBoxUSBClient::addFilter: [%p:{.m_Process=%d}] pFilter=%p pOut=%p\n", this, (int)m_Process, pFilter, pOut)); - - /* - * Validate input. - */ - if (RT_UNLIKELY( cbFilter != sizeof(*pFilter) - || *pcbOut != sizeof(*pOut))) - { - printf("VBoxUSBClient::addFilter: cbFilter=%#x expected %#x; *pcbOut=%#x expected %#x\n", - (int)cbFilter, (int)sizeof(*pFilter), (int)*pcbOut, (int)sizeof(*pOut)); - return kIOReturnBadArgument; - } - - /* - * Log the filter details. - */ -#ifdef DEBUG - Log2(("VBoxUSBClient::addFilter: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x\n", - USBFilterGetNum(pFilter, USBFILTERIDX_VENDOR_ID), - USBFilterGetNum(pFilter, USBFILTERIDX_PRODUCT_ID), - USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_REV), - USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_CLASS), - USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_SUB_CLASS), - USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_PROTOCOL), - USBFilterGetNum(pFilter, USBFILTERIDX_BUS), - USBFilterGetNum(pFilter, USBFILTERIDX_PORT))); - Log2(("VBoxUSBClient::addFilter: Manufacturer=%s Product=%s Serial=%s\n", - USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>", - USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>", - USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>")); -#endif - - /* - * Since we cannot query the bus number, make sure the filter - * isn't requiring that field to be present. - */ - int rc = USBFilterSetMustBePresent(pFilter, USBFILTERIDX_BUS, false /* fMustBePresent */); AssertRC(rc); - - /* - * Add the filter. - */ - pOut->uId = 0; - pOut->rc = VBoxUSBFilterAdd(pFilter, m_Process, &pOut->uId); - - Log(("VBoxUSBClient::addFilter: returns *pOut={.rc=%d, .uId=%p}\n", pOut->rc, (void *)pOut->uId)); - return kIOReturnSuccess; -} - - -/** - * Removes filter user request. - * - * @returns IOKit status code. - * @param puId Where to get the filter ID. - * @param prc Where to store the return code. - * @param cbIn sizeof(*puId). - * @param pcbOut In/Out - sizeof(*prc). - */ -IOReturn -org_virtualbox_VBoxUSBClient::removeFilter(uintptr_t *puId, int *prc, IOByteCount cbIn, IOByteCount *pcbOut) -{ - Log(("VBoxUSBClient::removeFilter: [%p:{.m_Process=%d}] *puId=%p m_Proc\n", this, (int)m_Process, *puId)); - - /* - * Validate input. - */ - if (RT_UNLIKELY( cbIn != sizeof(*puId) - || *pcbOut != sizeof(*prc))) - { - printf("VBoxUSBClient::removeFilter: cbIn=%#x expected %#x; *pcbOut=%#x expected %#x\n", - (int)cbIn, (int)sizeof(*puId), (int)*pcbOut, (int)sizeof(*prc)); - return kIOReturnBadArgument; - } - - /* - * Remove the filter. - */ - *prc = VBoxUSBFilterRemove(m_Process, *puId); - - Log(("VBoxUSBClient::removeFilter: returns *prc=%d\n", *prc)); - return kIOReturnSuccess; -} - - -/** - * Checks whether the specified task is a VBoxUSB client task or not. - * - * This is used to validate clients trying to open any of the device - * or interfaces that we've hijacked. - * - * @returns true / false. - * @param ClientTask The task. - * - * @remark This protecting against other user clients is not currently implemented - * as it turned out to be more bothersome than first imagined. - */ -/* static*/ bool -org_virtualbox_VBoxUSBClient::isClientTask(task_t ClientTask) -{ - VBOXUSB_LOCK(); - - for (org_virtualbox_VBoxUSBClient *pCur = s_pHead; pCur; pCur = pCur->m_pNext) - if (pCur->m_Task == ClientTask) - { - VBOXUSB_UNLOCK(); - return true; - } - - VBOXUSB_UNLOCK(); - return false; -} - - - - - - - - - - - - - - -/* - * - * org_virtualbox_VBoxUSBDevice - * - */ - -/** - * Initialize instance data. - * - * @returns Success indicator. - * @param pDictionary The dictionary that will become the registry entry's - * property table, or NULL. Hand it up to our parents. - */ -bool -org_virtualbox_VBoxUSBDevice::init(OSDictionary *pDictionary) -{ - uint32_t cInstances = ASMAtomicIncU32(&g_cInstances); - Log(("VBoxUSBDevice::init([%p], %p) new g_cInstances=%d\n", this, pDictionary, cInstances)); - RT_NOREF_PV(cInstances); - - m_pDevice = NULL; - m_Owner = NIL_RTPROCESS; - m_Client = NIL_RTPROCESS; - m_uId = ~(uintptr_t)0; - m_fOpen = false; - m_fOpenOnWasClosed = false; - m_fReleaseOnClose = false; - m_fBeingUnloaded = false; - m_pNext = NULL; -#ifdef DEBUG - m_pNotifier = NULL; -#endif - - return IOUSBUserClientInit::init(pDictionary); -} - -/** - * Free the object. - * @remark Only for logging. - */ -void -org_virtualbox_VBoxUSBDevice::free() -{ - uint32_t cInstances = ASMAtomicDecU32(&g_cInstances); NOREF(cInstances); - Log(("VBoxUSBDevice::free([%p]) new g_cInstances=%d\n", this, cInstances)); - IOUSBUserClientInit::free(); -} - - -/** - * The device/driver probing. - * - * I/O Kit will iterate all device drivers suitable for this kind of device - * (this is something it figures out from the property file) and call their - * probe() method in order to try determine which is the best match for the - * device. We will match the device against the registered filters and set - * a ridiculously high score if we find it, thus making it extremely likely - * that we'll be the first driver to be started. We'll also set a couple of - * attributes so that it's not necessary to do a rematch in init to find - * the appropriate filter (might not be necessary..., see todo). - * - * @returns Service instance to be started and *pi32Score if matching. - * NULL if not a device suitable for this driver. - * - * @param pProvider The provider instance. - * @param pi32Score Where to store the probe score. - */ -IOService * -org_virtualbox_VBoxUSBDevice::probe(IOService *pProvider, SInt32 *pi32Score) -{ - Log(("VBoxUSBDevice::probe([%p], %p {%s}, %p={%d})\n", this, - pProvider, pProvider->getName(), pi32Score, pi32Score ? *pi32Score : 0)); - - /* - * Check against filters. - */ - USBFILTER Device; - USBFilterInit(&Device, USBFILTERTYPE_CAPTURE); - - static const struct - { - const char *pszName; - USBFILTERIDX enmIdx; - bool fNumeric; - } s_aProps[] = - { - { kUSBVendorID, USBFILTERIDX_VENDOR_ID, true }, - { kUSBProductID, USBFILTERIDX_PRODUCT_ID, true }, - { kUSBDeviceReleaseNumber, USBFILTERIDX_DEVICE_REV, true }, - { kUSBDeviceClass, USBFILTERIDX_DEVICE_CLASS, true }, - { kUSBDeviceSubClass, USBFILTERIDX_DEVICE_SUB_CLASS, true }, - { kUSBDeviceProtocol, USBFILTERIDX_DEVICE_PROTOCOL, true }, - { "PortNum", USBFILTERIDX_PORT, true }, - /// @todo { , USBFILTERIDX_BUS, true }, - must be derived :-/ - /// Seems to be the upper byte of locationID and our "grand parent" has a USBBusNumber prop. - { "USB Vendor Name", USBFILTERIDX_MANUFACTURER_STR, false }, - { "USB Product Name", USBFILTERIDX_PRODUCT_STR, false }, - { "USB Serial Number", USBFILTERIDX_SERIAL_NUMBER_STR, false }, - }; - for (unsigned i = 0; i < RT_ELEMENTS(s_aProps); i++) - { - OSObject *pObj = pProvider->getProperty(s_aProps[i].pszName); - if (!pObj) - continue; - if (s_aProps[i].fNumeric) - { - OSNumber *pNum = OSDynamicCast(OSNumber, pObj); - if (pNum) - { - uint16_t u16 = pNum->unsigned16BitValue(); - Log2(("VBoxUSBDevice::probe: %d/%s - %#x (32bit=%#x)\n", i, s_aProps[i].pszName, u16, pNum->unsigned32BitValue())); - int vrc = USBFilterSetNumExact(&Device, s_aProps[i].enmIdx, u16, true); - if (RT_FAILURE(vrc)) - Log(("VBoxUSBDevice::probe: pObj=%p pNum=%p - %d/%s - rc=%d!\n", pObj, pNum, i, s_aProps[i].pszName, vrc)); - } - else - Log(("VBoxUSBDevice::probe: pObj=%p pNum=%p - %d/%s!\n", pObj, pNum, i, s_aProps[i].pszName)); - } - else - { - OSString *pStr = OSDynamicCast(OSString, pObj); - if (pStr) - { - Log2(("VBoxUSBDevice::probe: %d/%s - %s\n", i, s_aProps[i].pszName, pStr->getCStringNoCopy())); - int vrc = USBFilterSetStringExact(&Device, s_aProps[i].enmIdx, pStr->getCStringNoCopy(), - true /*fMustBePresent*/, true /*fPurge*/); - if (RT_FAILURE(vrc)) - Log(("VBoxUSBDevice::probe: pObj=%p pStr=%p - %d/%s - rc=%d!\n", pObj, pStr, i, s_aProps[i].pszName, vrc)); - } - else - Log(("VBoxUSBDevice::probe: pObj=%p pStr=%p - %d/%s\n", pObj, pStr, i, s_aProps[i].pszName)); - } - } - /** @todo try figure the blasted bus number */ - - /* - * Run filters on it. - */ - uintptr_t uId = 0; - RTPROCESS Owner = VBoxUSBFilterMatch(&Device, &uId); - USBFilterDelete(&Device); - if (Owner == NIL_RTPROCESS) - { - Log(("VBoxUSBDevice::probe: returns NULL uId=%d\n", uId)); - return NULL; - } - - /* - * It matched. Save the owner in the provider registry (hope that works). - */ - /*IOService *pRet = IOUSBUserClientInit::probe(pProvider, pi32Score); - call always returns NULL on 10.11+ */ - /*AssertMsg(pRet == this, ("pRet=%p this=%p *pi32Score=%d \n", pRet, this, pi32Score ? *pi32Score : 0)); - call always returns NULL on 10.11+ */ - IOService *pRet = this; - m_Owner = Owner; - m_uId = uId; - Log(("%p: m_Owner=%d m_uId=%d\n", this, (int)m_Owner, (int)m_uId)); - *pi32Score = _1G; - Log(("VBoxUSBDevice::probe: returns %p and *pi32Score=%d\n", pRet, *pi32Score)); - return pRet; -} - - -/** - * Try start the device driver. - * - * We will do device linking, copy the filter and owner properties from the provider, - * set the client property, retain the device, and try open (seize) the device. - * - * @returns Success indicator. - * @param pProvider The provider instance. - */ -bool -org_virtualbox_VBoxUSBDevice::start(IOService *pProvider) -{ - Log(("VBoxUSBDevice::start([%p:{.m_Owner=%d, .m_uId=%p}], %p {%s})\n", - this, m_Owner, m_uId, pProvider, pProvider->getName())); - - m_pDevice = OSDynamicCast(IOUSBDevice, pProvider); - if (!m_pDevice) - { - printf("VBoxUSBDevice::start([%p], %p {%s}): failed!\n", (void *)this, (void *)pProvider, pProvider->getName()); - return false; - } - -#ifdef DEBUG - /* for some extra log messages */ - m_pNotifier = pProvider->registerInterest(gIOGeneralInterest, - &org_virtualbox_VBoxUSBDevice::MyInterestHandler, - this, /* pvTarget */ - NULL); /* pvRefCon */ -#endif - - /* - * Exploit IOUSBUserClientInit to process IOProviderMergeProperties. - */ - IOUSBUserClientInit::start(pProvider); /* returns false */ - - /* - * Link ourselves into the list of hijacked device. - */ - VBOXUSB_LOCK(); - - m_pNext = s_pHead; - s_pHead = this; - - VBOXUSB_UNLOCK(); - - /* - * Set the VBoxUSB properties. - */ - if (!setProperty(VBOXUSB_OWNER_KEY, (unsigned long long)m_Owner, sizeof(m_Owner) * 8 /* bits */)) - Log(("VBoxUSBDevice::start: failed to set the '" VBOXUSB_OWNER_KEY "' property!\n")); - if (!setProperty(VBOXUSB_CLIENT_KEY, (unsigned long long)m_Client, sizeof(m_Client) * 8 /* bits */)) - Log(("VBoxUSBDevice::start: failed to set the '" VBOXUSB_CLIENT_KEY "' property!\n")); - if (!setProperty(VBOXUSB_FILTER_KEY, (unsigned long long)m_uId, sizeof(m_uId) * 8 /* bits */)) - Log(("VBoxUSBDevice::start: failed to set the '" VBOXUSB_FILTER_KEY "' property!\n")); - - /* - * Retain and open the device. - */ - m_pDevice->retain(); - m_fOpen = m_pDevice->open(this, kIOServiceSeize, 0); - if (!m_fOpen) - Log(("VBoxUSBDevice::start: failed to open the device!\n")); - m_fOpenOnWasClosed = !m_fOpen; - - Log(("VBoxUSBDevice::start: returns %d\n", true)); - return true; -} - - -/** - * Stop the device driver. - * - * We'll unlink the device, start device re-enumeration and close it. And call - * the parent stop method of course. - * - * @param pProvider The provider instance. - */ -void -org_virtualbox_VBoxUSBDevice::stop(IOService *pProvider) -{ - Log(("VBoxUSBDevice::stop([%p], %p {%s})\n", this, pProvider, pProvider->getName())); - - /* - * Remove ourselves from the list of device. - */ - VBOXUSB_LOCK(); - - org_virtualbox_VBoxUSBDevice *pPrev = NULL; - for (org_virtualbox_VBoxUSBDevice *pCur = s_pHead; pCur; pCur = pCur->m_pNext) - { - if (pCur == this) - { - if (pPrev) - pPrev->m_pNext = m_pNext; - else - s_pHead = m_pNext; - m_pNext = NULL; - break; - } - pPrev = pCur; - } - - VBOXUSB_UNLOCK(); - - /* - * Should we release the device? - */ - if (m_fBeingUnloaded) - { - if (m_pDevice) - { - IOReturn irc = m_pDevice->ReEnumerateDevice(0); NOREF(irc); - Log(("VBoxUSBDevice::stop([%p], %p {%s}): m_pDevice=%p unload & ReEnumerateDevice -> %#x\n", - this, pProvider, pProvider->getName(), m_pDevice, irc)); - } - else - { - IOUSBDevice *pDevice = OSDynamicCast(IOUSBDevice, pProvider); - if (pDevice) - { - IOReturn irc = pDevice->ReEnumerateDevice(0); NOREF(irc); - Log(("VBoxUSBDevice::stop([%p], %p {%s}): pDevice=%p unload & ReEnumerateDevice -> %#x\n", - this, pProvider, pProvider->getName(), pDevice, irc)); - } - else - Log(("VBoxUSBDevice::stop([%p], %p {%s}): failed to cast provider to IOUSBDevice\n", - this, pProvider, pProvider->getName())); - } - } - else if (m_fReleaseOnClose) - { - ASMAtomicWriteBool(&m_fReleaseOnClose, false); - if (m_pDevice) - { - IOReturn irc = m_pDevice->ReEnumerateDevice(0); NOREF(irc); - Log(("VBoxUSBDevice::stop([%p], %p {%s}): m_pDevice=%p close & ReEnumerateDevice -> %#x\n", - this, pProvider, pProvider->getName(), m_pDevice, irc)); - } - } - - /* - * Close and release the IOUSBDevice if didn't do that already in message(). - */ - if (m_pDevice) - { - /* close it */ - if (m_fOpen) - { - m_fOpenOnWasClosed = false; - m_fOpen = false; - m_pDevice->close(this, 0); - } - - /* release it (see start()) */ - m_pDevice->release(); - m_pDevice = NULL; - } - -#ifdef DEBUG - /* avoid crashing on unload. */ - if (m_pNotifier) - { - m_pNotifier->release(); - m_pNotifier = NULL; - } -#endif - - IOUSBUserClientInit::stop(pProvider); - Log(("VBoxUSBDevice::stop: returns void\n")); -} - - -/** - * Terminate the service (initiate the destruction). - * @remark Only for logging. - */ -bool -org_virtualbox_VBoxUSBDevice::terminate(IOOptionBits fOptions) -{ - /* kIOServiceRecursing, kIOServiceRequired, kIOServiceTerminate, kIOServiceSynchronous - interesting option bits */ - Log(("VBoxUSBDevice::terminate([%p], %#x)\n", this, fOptions)); - - /* - * There aren't too many reasons why we gets terminated. - * The most common one is that the device is being unplugged. Another is - * that we've triggered reenumeration. In both cases we'll get a - * kIOMessageServiceIsTerminated message before we're stopped. - * - * But, when we're unloaded the provider service isn't terminated, and - * for some funny reason we're frequently causing kernel panics when the - * device is detached (after we're unloaded). So, for now, let's try - * re-enumerate it in stop. - * - * To avoid creating unnecessary trouble we'll try guess if we're being - * unloaded from the option bit mask. (kIOServiceRecursing is private btw.) - */ - /** @todo would be nice if there was a documented way of doing the unload detection this, or - * figure out what exactly we're doing wrong in the unload scenario. */ - if ((fOptions & 0xffff) == (kIOServiceRequired | kIOServiceSynchronous)) - m_fBeingUnloaded = true; - - return IOUSBUserClientInit::terminate(fOptions); -} - - -/** - * Intercept open requests and only let Mr. Right (the VM process) open the device. - * This is where it all gets a bit complicated... - * - * @return Status code. - * - * @param enmMsg The message number. - * @param pProvider Pointer to the provider instance. - * @param pvArg Message argument. - */ -IOReturn -org_virtualbox_VBoxUSBDevice::message(UInt32 enmMsg, IOService *pProvider, void *pvArg) -{ - Log(("VBoxUSBDevice::message([%p], %#x {%s}, %p {%s}, %p) - pid=%d\n", - this, enmMsg, DbgGetIOKitMessageName(enmMsg), pProvider, pProvider->getName(), pvArg, RTProcSelf())); - - IOReturn irc; - switch (enmMsg) - { - /* - * This message is send to the current IOService client from IOService::handleOpen(), - * expecting it to call pProvider->close() if it agrees to the other party seizing - * the service. It is also called in IOService::didTerminate() and perhaps some other - * odd places. The way to find out is to examin the pvArg, which would be including - * kIOServiceSeize if it's the handleOpen case. - * - * How to validate that the other end is actually our VM process? Well, IOKit doesn't - * provide any clue about the new client really. But fortunately, it seems like the - * calling task/process context when the VM tries to open the device is the VM process. - * We'll ASSUME this'll remain like this for now... - */ - case kIOMessageServiceIsRequestingClose: - irc = kIOReturnExclusiveAccess; - /* If it's not a seize request, assume it's didTerminate and pray that it isn't a rouge driver. - ... weird, doesn't seem to match for the post has-terminated messages. */ - if (!((uintptr_t)pvArg & kIOServiceSeize)) - { - Log(("VBoxUSBDevice::message([%p],%p {%s}, %p) - pid=%d: not seize - closing...\n", - this, pProvider, pProvider->getName(), pvArg, RTProcSelf())); - m_fOpen = false; - m_fOpenOnWasClosed = false; - if (m_pDevice) - m_pDevice->close(this, 0); - m_Client = NIL_RTPROCESS; - irc = kIOReturnSuccess; - } - else - { - if (org_virtualbox_VBoxUSBClient::isClientTask(current_task())) - { - Log(("VBoxUSBDevice::message([%p],%p {%s}, %p) - pid=%d task=%p: client process, closing.\n", - this, pProvider, pProvider->getName(), pvArg, RTProcSelf(), current_task())); - m_fOpen = false; - m_fOpenOnWasClosed = false; - if (m_pDevice) - m_pDevice->close(this, 0); - m_fOpenOnWasClosed = true; - m_Client = RTProcSelf(); - irc = kIOReturnSuccess; - } - else - Log(("VBoxUSBDevice::message([%p],%p {%s}, %p) - pid=%d task=%p: not client process!\n", - this, pProvider, pProvider->getName(), pvArg, RTProcSelf(), current_task())); - } - if (!setProperty(VBOXUSB_CLIENT_KEY, (unsigned long long)m_Client, sizeof(m_Client) * 8 /* bits */)) - Log(("VBoxUSBDevice::message: failed to set the '" VBOXUSB_CLIENT_KEY "' property!\n")); - break; - - /* - * The service was closed by the current client. - * Update the client property, check for scheduled re-enumeration and re-open. - * - * Note that we will not be called if we're doing the closing. (Even if we was - * called in that case, the code should be able to handle it.) - */ - case kIOMessageServiceWasClosed: - /* - * Update the client property value. - */ - if (m_Client != NIL_RTPROCESS) - { - m_Client = NIL_RTPROCESS; - if (!setProperty(VBOXUSB_CLIENT_KEY, (unsigned long long)m_Client, sizeof(m_Client) * 8 /* bits */)) - Log(("VBoxUSBDevice::message: failed to set the '" VBOXUSB_CLIENT_KEY "' property!\n")); - } - - if (m_pDevice) - { - /* - * Should we release the device? - */ - if (ASMAtomicXchgBool(&m_fReleaseOnClose, false)) - { - m_fOpenOnWasClosed = false; - irc = m_pDevice->ReEnumerateDevice(0); - Log(("VBoxUSBDevice::message([%p], %p {%s}) - ReEnumerateDevice() -> %#x\n", - this, pProvider, pProvider->getName(), irc)); - } - /* - * Should we attempt to re-open the device? - */ - else if (m_fOpenOnWasClosed) - { - Log(("VBoxUSBDevice::message: attempting to re-open the device...\n")); - m_fOpenOnWasClosed = false; - m_fOpen = m_pDevice->open(this, kIOServiceSeize, 0); - if (!m_fOpen) - Log(("VBoxUSBDevice::message: failed to open the device!\n")); - m_fOpenOnWasClosed = !m_fOpen; - } - } - - irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg); - break; - - /* - * The IOUSBDevice is shutting down, so close it if we've opened it. - */ - case kIOMessageServiceIsTerminated: - m_fBeingUnloaded = false; - ASMAtomicWriteBool(&m_fReleaseOnClose, false); - if (m_pDevice) - { - /* close it */ - if (m_fOpen) - { - m_fOpen = false; - m_fOpenOnWasClosed = false; - Log(("VBoxUSBDevice::message: closing the device (%p)...\n", m_pDevice)); - m_pDevice->close(this, 0); - } - - /* release it (see start()) */ - Log(("VBoxUSBDevice::message: releasing the device (%p)...\n", m_pDevice)); - m_pDevice->release(); - m_pDevice = NULL; - } - - irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg); - break; - - default: - irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg); - break; - } - - Log(("VBoxUSBDevice::message([%p], %#x {%s}, %p {%s}, %p) -> %#x\n", - this, enmMsg, DbgGetIOKitMessageName(enmMsg), pProvider, pProvider->getName(), pvArg, irc)); - return irc; -} - - -/** - * Schedule all devices belonging to the specified process for release. - * - * Devices that aren't currently in use will be released immediately. - * - * @param Owner The owner process. - */ -/* static */ void -org_virtualbox_VBoxUSBDevice::scheduleReleaseByOwner(RTPROCESS Owner) -{ - Log2(("VBoxUSBDevice::scheduleReleaseByOwner: Owner=%d\n", Owner)); - AssertReturnVoid(Owner && Owner != NIL_RTPROCESS); - - /* - * Walk the list of devices looking for device belonging to this process. - * - * If we release a device, we have to lave the spinlock and will therefore - * have to restart the search. - */ - VBOXUSB_LOCK(); - - org_virtualbox_VBoxUSBDevice *pCur; - do - { - for (pCur = s_pHead; pCur; pCur = pCur->m_pNext) - { - Log2(("VBoxUSBDevice::scheduleReleaseByOwner: pCur=%p m_Owner=%d (%s) m_fReleaseOnClose=%d\n", - pCur, pCur->m_Owner, pCur->m_Owner == Owner ? "match" : "mismatch", pCur->m_fReleaseOnClose)); - if (pCur->m_Owner == Owner) - { - /* make sure we won't hit it again. */ - pCur->m_Owner = NIL_RTPROCESS; - IOUSBDevice *pDevice = pCur->m_pDevice; - if ( pDevice - && !pCur->m_fReleaseOnClose) - { - pCur->m_fOpenOnWasClosed = false; - if (pCur->m_Client != NIL_RTPROCESS) - { - /* It's currently open, so just schedule it for re-enumeration on close. */ - ASMAtomicWriteBool(&pCur->m_fReleaseOnClose, true); - Log(("VBoxUSBDevice::scheduleReleaseByOwner: %p {%s} - used by %d\n", - pDevice, pDevice->getName(), pCur->m_Client)); - } - else - { - /* - * Get the USBDevice object and do the re-enumeration now. - * Retain the device so we don't run into any trouble. - */ - pDevice->retain(); - VBOXUSB_UNLOCK(); - - IOReturn irc = pDevice->ReEnumerateDevice(0); NOREF(irc); - Log(("VBoxUSBDevice::scheduleReleaseByOwner: %p {%s} - ReEnumerateDevice -> %#x\n", - pDevice, pDevice->getName(), irc)); - - pDevice->release(); - VBOXUSB_LOCK(); - break; - } - } - } - } - } while (pCur); - - VBOXUSB_UNLOCK(); -} - - -#ifdef DEBUG -/*static*/ IOReturn -org_virtualbox_VBoxUSBDevice::MyInterestHandler(void *pvTarget, void *pvRefCon, UInt32 enmMsgType, - IOService *pProvider, void * pvMsgArg, vm_size_t cbMsgArg) -{ - org_virtualbox_VBoxUSBDevice *pThis = (org_virtualbox_VBoxUSBDevice *)pvTarget; - if (!pThis) - return kIOReturnError; - - switch (enmMsgType) - { - case kIOMessageServiceIsAttemptingOpen: - /* pvMsgArg == the open() fOptions, so we could check for kIOServiceSeize if we care. - We'll also get a kIIOServiceRequestingClose message() for that... */ - Log(("VBoxUSBDevice::MyInterestHandler: kIOMessageServiceIsAttemptingOpen - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n", - pvRefCon, pProvider, pvMsgArg, cbMsgArg)); - break; - - case kIOMessageServiceWasClosed: - Log(("VBoxUSBDevice::MyInterestHandler: kIOMessageServiceWasClosed - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n", - pvRefCon, pProvider, pvMsgArg, cbMsgArg)); - break; - - case kIOMessageServiceIsTerminated: - Log(("VBoxUSBDevice::MyInterestHandler: kIOMessageServiceIsTerminated - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n", - pvRefCon, pProvider, pvMsgArg, cbMsgArg)); - break; - - case kIOUSBMessagePortHasBeenReset: - Log(("VBoxUSBDevice::MyInterestHandler: kIOUSBMessagePortHasBeenReset - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n", - pvRefCon, pProvider, pvMsgArg, cbMsgArg)); - break; - - default: - Log(("VBoxUSBDevice::MyInterestHandler: %#x (%s) - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n", - enmMsgType, DbgGetIOKitMessageName(enmMsgType), pvRefCon, pProvider, pvMsgArg, cbMsgArg)); - break; - } - - return kIOReturnSuccess; -} -#endif /* DEBUG */ - - - - - - - - - - - - - - -/* - * - * org_virtualbox_VBoxUSBInterface - * - */ - -/** - * Initialize our data members. - */ -bool -org_virtualbox_VBoxUSBInterface::init(OSDictionary *pDictionary) -{ - uint32_t cInstances = ASMAtomicIncU32(&g_cInstances); - Log(("VBoxUSBInterface::init([%p], %p) new g_cInstances=%d\n", this, pDictionary, cInstances)); - RT_NOREF_PV(cInstances); - - m_pInterface = NULL; - m_fOpen = false; - m_fOpenOnWasClosed = false; - - return IOUSBUserClientInit::init(pDictionary); -} - - -/** - * Free the object. - * @remark Only for logging. - */ -void -org_virtualbox_VBoxUSBInterface::free() -{ - uint32_t cInstances = ASMAtomicDecU32(&g_cInstances); NOREF(cInstances); - Log(("VBoxUSBInterfaces::free([%p]) new g_cInstances=%d\n", this, cInstances)); - IOUSBUserClientInit::free(); -} - - -/** - * Probe the interface to see if we're the right driver for it. - * - * We implement this similarly to org_virtualbox_VBoxUSBDevice, except that - * we don't bother matching filters but instead just check if the parent is - * handled by org_virtualbox_VBoxUSBDevice or not. - */ -IOService * -org_virtualbox_VBoxUSBInterface::probe(IOService *pProvider, SInt32 *pi32Score) -{ - Log(("VBoxUSBInterface::probe([%p], %p {%s}, %p={%d})\n", this, - pProvider, pProvider->getName(), pi32Score, pi32Score ? *pi32Score : 0)); - - /* - * Check if VBoxUSBDevice is the parent's driver. - */ - bool fHijackIt = false; - const IORegistryPlane *pServicePlane = getPlane(kIOServicePlane); - IORegistryEntry *pParent = pProvider->getParentEntry(pServicePlane); - if (pParent) - { - Log(("VBoxUSBInterface::probe: pParent=%p {%s}\n", pParent, pParent->getName())); - - OSIterator *pSiblings = pParent->getChildIterator(pServicePlane); - if (pSiblings) - { - IORegistryEntry *pSibling; - while ( (pSibling = OSDynamicCast(IORegistryEntry, pSiblings->getNextObject())) ) - { - const OSMetaClass *pMetaClass = pSibling->getMetaClass(); - Log2(("sibling: %p - %s - %s\n", pMetaClass, pSibling->getName(), pMetaClass->getClassName())); - if (pMetaClass == &org_virtualbox_VBoxUSBDevice::gMetaClass) - { - fHijackIt = true; - break; - } - } - pSiblings->release(); - } - } - if (!fHijackIt) - { - Log(("VBoxUSBInterface::probe: returns NULL\n")); - return NULL; - } - - /* IOService *pRet = IOUSBUserClientInit::probe(pProvider, pi32Score); - call always returns NULL on 10.11+ */ - IOService *pRet = this; - *pi32Score = _1G; - Log(("VBoxUSBInterface::probe: returns %p and *pi32Score=%d - hijack it.\n", pRet, *pi32Score)); - return pRet; -} - - -/** - * Start the driver (this), retain and open the USB interface object (pProvider). - */ -bool -org_virtualbox_VBoxUSBInterface::start(IOService *pProvider) -{ - Log(("VBoxUSBInterface::start([%p], %p {%s})\n", this, pProvider, pProvider->getName())); - - /* - * Exploit IOUSBUserClientInit to process IOProviderMergeProperties. - */ - IOUSBUserClientInit::start(pProvider); /* returns false */ - - /* - * Retain the and open the interface (stop() or message() cleans up). - */ - bool fRc = true; - m_pInterface = OSDynamicCast(IOUSBInterface, pProvider); - if (m_pInterface) - { - m_pInterface->retain(); - m_fOpen = m_pInterface->open(this, kIOServiceSeize, 0); - if (!m_fOpen) - Log(("VBoxUSBInterface::start: failed to open the interface!\n")); - m_fOpenOnWasClosed = !m_fOpen; - } - else - { - printf("VBoxUSBInterface::start([%p], %p {%s}): failed!\n", (void *)this, (void *)pProvider, pProvider->getName()); - fRc = false; - } - - Log(("VBoxUSBInterface::start: returns %d\n", fRc)); - return fRc; -} - - -/** - * Close and release the USB interface object (pProvider) and stop the driver (this). - */ -void -org_virtualbox_VBoxUSBInterface::stop(IOService *pProvider) -{ - Log(("org_virtualbox_VBoxUSBInterface::stop([%p], %p {%s})\n", this, pProvider, pProvider->getName())); - - /* - * Close and release the IOUSBInterface if didn't do that already in message(). - */ - if (m_pInterface) - { - /* close it */ - if (m_fOpen) - { - m_fOpenOnWasClosed = false; - m_fOpen = false; - m_pInterface->close(this, 0); - } - - /* release it (see start()) */ - m_pInterface->release(); - m_pInterface = NULL; - } - - IOUSBUserClientInit::stop(pProvider); - Log(("VBoxUSBInterface::stop: returns void\n")); -} - - -/** - * Terminate the service (initiate the destruction). - * @remark Only for logging. - */ -bool -org_virtualbox_VBoxUSBInterface::terminate(IOOptionBits fOptions) -{ - /* kIOServiceRecursing, kIOServiceRequired, kIOServiceTerminate, kIOServiceSynchronous - interesting option bits */ - Log(("VBoxUSBInterface::terminate([%p], %#x)\n", this, fOptions)); - return IOUSBUserClientInit::terminate(fOptions); -} - - -/** - * @copydoc org_virtualbox_VBoxUSBDevice::message - */ -IOReturn -org_virtualbox_VBoxUSBInterface::message(UInt32 enmMsg, IOService *pProvider, void *pvArg) -{ - Log(("VBoxUSBInterface::message([%p], %#x {%s}, %p {%s}, %p)\n", - this, enmMsg, DbgGetIOKitMessageName(enmMsg), pProvider, pProvider->getName(), pvArg)); - - IOReturn irc; - switch (enmMsg) - { - /* - * See explanation in org_virtualbox_VBoxUSBDevice::message. - */ - case kIOMessageServiceIsRequestingClose: - irc = kIOReturnExclusiveAccess; - if (!((uintptr_t)pvArg & kIOServiceSeize)) - { - Log(("VBoxUSBInterface::message([%p],%p {%s}, %p) - pid=%d: not seize - closing...\n", - this, pProvider, pProvider->getName(), pvArg, RTProcSelf())); - m_fOpen = false; - m_fOpenOnWasClosed = false; - if (m_pInterface) - m_pInterface->close(this, 0); - irc = kIOReturnSuccess; - } - else - { - if (org_virtualbox_VBoxUSBClient::isClientTask(current_task())) - { - Log(("VBoxUSBInterface::message([%p],%p {%s}, %p) - pid=%d task=%p: client process, closing.\n", - this, pProvider, pProvider->getName(), pvArg, RTProcSelf(), current_task())); - m_fOpen = false; - m_fOpenOnWasClosed = false; - if (m_pInterface) - m_pInterface->close(this, 0); - m_fOpenOnWasClosed = true; - irc = kIOReturnSuccess; - } - else - Log(("VBoxUSBInterface::message([%p],%p {%s}, %p) - pid=%d task=%p: not client process!\n", - this, pProvider, pProvider->getName(), pvArg, RTProcSelf(), current_task())); - } - break; - - /* - * The service was closed by the current client, check for re-open. - */ - case kIOMessageServiceWasClosed: - if (m_pInterface && m_fOpenOnWasClosed) - { - Log(("VBoxUSBInterface::message: attempting to re-open the interface...\n")); - m_fOpenOnWasClosed = false; - m_fOpen = m_pInterface->open(this, kIOServiceSeize, 0); - if (!m_fOpen) - Log(("VBoxUSBInterface::message: failed to open the interface!\n")); - m_fOpenOnWasClosed = !m_fOpen; - } - - irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg); - break; - - /* - * The IOUSBInterface/Device is shutting down, so close and release. - */ - case kIOMessageServiceIsTerminated: - if (m_pInterface) - { - /* close it */ - if (m_fOpen) - { - m_fOpen = false; - m_fOpenOnWasClosed = false; - m_pInterface->close(this, 0); - } - - /* release it (see start()) */ - m_pInterface->release(); - m_pInterface = NULL; - } - - irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg); - break; - - default: - irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg); - break; - } - - Log(("VBoxUSBInterface::message([%p], %#x {%s}, %p {%s}, %p) -> %#x\n", - this, enmMsg, DbgGetIOKitMessageName(enmMsg), pProvider, pProvider->getName(), pvArg, irc)); - return irc; -} - diff --git a/src/VBox/HostDrivers/VBoxUSB/darwin/VBoxUSBInterface.h b/src/VBox/HostDrivers/VBoxUSB/darwin/VBoxUSBInterface.h deleted file mode 100644 index 6944e3e85a2..00000000000 --- a/src/VBox/HostDrivers/VBoxUSB/darwin/VBoxUSBInterface.h +++ /dev/null @@ -1,65 +0,0 @@ -/** $Id$ */ -/** @file - * VirtualBox USB Driver User<->Kernel Interface. - */ - -/* - * Copyright (C) 2007-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. - * - * The contents of this file may alternatively be used under the terms - * of the Common Development and Distribution License Version 1.0 - * (CDDL) only, as it comes in the "COPYING.CDDL" file of the - * VirtualBox OSE distribution, in which case the provisions of the - * CDDL are applicable instead of those of the GPL. - * - * You may elect to license modified versions of this file under the - * terms and conditions of either the GPL or the CDDL or both. - */ - -#ifndef VBOX_INCLUDED_SRC_VBoxUSB_darwin_VBoxUSBInterface_h -#define VBOX_INCLUDED_SRC_VBoxUSB_darwin_VBoxUSBInterface_h -#ifndef RT_WITHOUT_PRAGMA_ONCE -# pragma once -#endif - -#include <VBox/usbfilter.h> - -/** - * org_virtualbox_VBoxUSBClient method indexes. - */ -typedef enum VBOXUSBMETHOD -{ - /** org_virtualbox_VBoxUSBClient::addFilter */ - VBOXUSBMETHOD_ADD_FILTER = 0, - /** org_virtualbox_VBoxUSBClient::removeFilter */ - VBOXUSBMETHOD_REMOVE_FILTER, - /** End/max. */ - VBOXUSBMETHOD_END -} VBOXUSBMETHOD; - -/** - * Output from a VBOXUSBMETHOD_ADD_FILTER call. - */ -typedef struct VBOXUSBADDFILTEROUT -{ - /** The ID. */ - uintptr_t uId; - /** The return code. */ - int rc; -} VBOXUSBADDFILTEROUT; -/** Pointer to a VBOXUSBADDFILTEROUT. */ -typedef VBOXUSBADDFILTEROUT *PVBOXUSBADDFILTEROUT; - -/** Cookie used to fend off some unwanted clients to the IOService. */ -#define VBOXUSB_DARWIN_IOSERVICE_COOKIE UINT32_C(0x62735556) /* 'VUsb' */ - -#endif /* !VBOX_INCLUDED_SRC_VBoxUSB_darwin_VBoxUSBInterface_h */ - diff --git a/src/VBox/HostDrivers/VBoxUSB/darwin/loadusb.sh b/src/VBox/HostDrivers/VBoxUSB/darwin/loadusb.sh deleted file mode 100755 index b470a10c6cf..00000000000 --- a/src/VBox/HostDrivers/VBoxUSB/darwin/loadusb.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash -## @file -# For development. -# - -# -# Copyright (C) 2006-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. -# -# The contents of this file may alternatively be used under the terms -# of the Common Development and Distribution License Version 1.0 -# (CDDL) only, as it comes in the "COPYING.CDDL" file of the -# VirtualBox OSE distribution, in which case the provisions of the -# CDDL are applicable instead of those of the GPL. -# -# You may elect to license modified versions of this file under the -# terms and conditions of either the GPL or the CDDL or both. -# - -SCRIPT_NAME="loadusb" -XNU_VERSION=`LC_ALL=C uname -r | LC_ALL=C cut -d . -f 1` - -DRVNAME="VBoxUSB.kext" -BUNDLE="org.virtualbox.kext.VBoxUSB" - -DEP_DRVNAME="VBoxDrv.kext" -DEP_BUNDLE="org.virtualbox.kext.VBoxDrv" - - -DIR=`dirname "$0"` -DIR=`cd "$DIR" && pwd` -DEP_DIR="$DIR/$DEP_DRVNAME" -DIR="$DIR/$DRVNAME" -if [ ! -d "$DIR" ]; then - echo "Cannot find $DIR or it's not a directory..." - exit 1; -fi -if [ ! -d "$DEP_DIR" ]; then - echo "Cannot find $DEP_DIR or it's not a directory... (dependency)" - exit 1; -fi -if [ -n "$*" ]; then - OPTS="$*" -else - OPTS="-t" -fi - -trap "sudo chown -R `whoami` $DIR $DEP_DIR; exit 1" INT - -# Try unload any existing instance first. -LOADED=`kextstat -b $BUNDLE -l` -if test -n "$LOADED"; then - echo "${SCRIPT_NAME}.sh: Unloading $BUNDLE..." - sudo kextunload -v 6 -b $BUNDLE - LOADED=`kextstat -b $BUNDLE -l` - if test -n "$LOADED"; then - echo "${SCRIPT_NAME}.sh: failed to unload $BUNDLE, see above..." - exit 1; - fi - echo "${SCRIPT_NAME}.sh: Successfully unloaded $BUNDLE" -fi - -# We are now done since VBoxUSB.kext is no longer used. diff --git a/src/VBox/HostDrivers/VBoxUSB/darwin/testcase/Makefile.kup b/src/VBox/HostDrivers/VBoxUSB/darwin/testcase/Makefile.kup deleted file mode 100644 index e69de29bb2d..00000000000 --- a/src/VBox/HostDrivers/VBoxUSB/darwin/testcase/Makefile.kup +++ /dev/null diff --git a/src/VBox/HostDrivers/VBoxUSB/darwin/testcase/tstOpenUSBDev.cpp b/src/VBox/HostDrivers/VBoxUSB/darwin/testcase/tstOpenUSBDev.cpp deleted file mode 100644 index 1c2d1d386ee..00000000000 --- a/src/VBox/HostDrivers/VBoxUSB/darwin/testcase/tstOpenUSBDev.cpp +++ /dev/null @@ -1,295 +0,0 @@ -/* $Id$ */ -/** @file - * Testcase that attempts to locate and open the specified device. - */ - -/* - * Copyright (C) 2006-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. - * - * The contents of this file may alternatively be used under the terms - * of the Common Development and Distribution License Version 1.0 - * (CDDL) only, as it comes in the "COPYING.CDDL" file of the - * VirtualBox OSE distribution, in which case the provisions of the - * CDDL are applicable instead of those of the GPL. - * - * You may elect to license modified versions of this file under the - * terms and conditions of either the GPL or the CDDL or both. - */ - - -/********************************************************************************************************************************* -* Header Files * -*********************************************************************************************************************************/ -#include <mach/mach.h> -#include <Carbon/Carbon.h> -#include <IOKit/IOKitLib.h> -#include <IOKit/storage/IOStorageDeviceCharacteristics.h> -#include <IOKit/scsi/SCSITaskLib.h> -#include <mach/mach_error.h> -#include <IOKit/usb/IOUSBLib.h> -#include <IOKit/IOCFPlugIn.h> - -#include <iprt/err.h> -#include <iprt/mem.h> -#include <iprt/string.h> -#include <iprt/process.h> -#include <iprt/assert.h> -#include <iprt/thread.h> -#include <iprt/getopt.h> -#include <iprt/initterm.h> -#include <iprt/stream.h> - - -/** - * Gets an unsigned 32-bit integer value. - * - * @returns Success indicator (true/false). - * @param DictRef The dictionary. - * @param KeyStrRef The key name. - * @param pu32 Where to store the key value. - */ -static bool tstDictGetU32(CFMutableDictionaryRef DictRef, CFStringRef KeyStrRef, uint32_t *pu32) -{ - CFTypeRef ValRef = CFDictionaryGetValue(DictRef, KeyStrRef); - if (ValRef) - { - if (CFNumberGetValue((CFNumberRef)ValRef, kCFNumberSInt32Type, pu32)) - return true; - } - *pu32 = 0; - return false; -} - - -/** - * Gets an unsigned 64-bit integer value. - * - * @returns Success indicator (true/false). - * @param DictRef The dictionary. - * @param KeyStrRef The key name. - * @param pu64 Where to store the key value. - */ -static bool tstDictGetU64(CFMutableDictionaryRef DictRef, CFStringRef KeyStrRef, uint64_t *pu64) -{ - CFTypeRef ValRef = CFDictionaryGetValue(DictRef, KeyStrRef); - if (ValRef) - { - if (CFNumberGetValue((CFNumberRef)ValRef, kCFNumberSInt64Type, pu64)) - return true; - } - *pu64 = 0; - return false; -} - - -static int tstDoWork(io_object_t USBDevice, const char *argv0) -{ - /* - * Create a plugin interface for the device and query its IOUSBDeviceInterface. - */ - int vrc = VINF_SUCCESS; - SInt32 Score = 0; - IOCFPlugInInterface **ppPlugInInterface = NULL; - IOReturn irc = IOCreatePlugInInterfaceForService(USBDevice, kIOUSBDeviceUserClientTypeID, - kIOCFPlugInInterfaceID, &ppPlugInInterface, &Score); - if (irc == kIOReturnSuccess) - { - IOUSBDeviceInterface245 **ppDevI = NULL; - HRESULT hrc = (*ppPlugInInterface)->QueryInterface(ppPlugInInterface, - CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID245), - (LPVOID *)&ppDevI); - irc = IODestroyPlugInInterface(ppPlugInInterface); Assert(irc == kIOReturnSuccess); - ppPlugInInterface = NULL; - if (hrc == S_OK) - { - /* - * Try open the device for exclusive access. - */ - irc = (*ppDevI)->USBDeviceOpenSeize(ppDevI); - if (irc == kIOReturnExclusiveAccess) - { - RTThreadSleep(20); - irc = (*ppDevI)->USBDeviceOpenSeize(ppDevI); - } - if (irc == kIOReturnSuccess) - { -#if 0 - /* - * Re-enumerate the device and bail out. - */ - irc = (*ppDevI)->USBDeviceReEnumerate(ppDevI, 0); - if (irc != kIOReturnSuccess) - { - vrc = RTErrConvertFromDarwinIO(irc); - RTPrintf("%s: Failed to re-enumerate the device, irc=%#x (vrc=%Rrc).\n", argv0, irc, vrc); - } -#endif - - (*ppDevI)->USBDeviceClose(ppDevI); - } - else if (irc == kIOReturnExclusiveAccess) - { - vrc = VERR_SHARING_VIOLATION; - RTPrintf("%s: The device is being used by another process (irc=kIOReturnExclusiveAccess)\n", argv0); - } - else - { - vrc = VERR_OPEN_FAILED; - RTPrintf("%s: Failed to open the device, irc=%#x (vrc=%Rrc).\n", argv0, irc, vrc); - } - } - else - { - vrc = VERR_OPEN_FAILED; - RTPrintf("%s: Failed to create plugin interface for the device, hrc=%#x (vrc=%Rrc).\n", argv0, hrc, vrc); - } - - (*ppDevI)->Release(ppDevI); - } - else - { - vrc = RTErrConvertFromDarwinIO(irc); - RTPrintf("%s: Failed to open the device, plug-in creation failed with irc=%#x (vrc=%Rrc).\n", argv0, irc, vrc); - } - - return vrc; -} - - -static int tstSyntax(const char *argv0) -{ - RTPrintf("syntax: %s [criteria]\n" - "\n" - "Criteria:\n" - " -l <location>\n" - " -s <session>\n" - , argv0); - return 1; -} - - -int main(int argc, char **argv) -{ - RTR3InitExe(argc, &argv, 0); - - /* - * Show help if not arguments. - */ - if (argc <= 1) - return tstSyntax(argv[0]); - - /* - * Parse arguments. - */ - static const RTGETOPTDEF g_aOptions[] = - { - { "--location", 'l', RTGETOPT_REQ_UINT32 }, - { "--session", 's', RTGETOPT_REQ_UINT64 }, - }; - - kern_return_t krc; - uint64_t u64SessionId = 0; - uint32_t u32LocationId = 0; - - int ch; - RTGETOPTUNION ValueUnion; - RTGETOPTSTATE GetState; - RTGetOptInit(&GetState, argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), 1, 0 /* fFlags */); - while ((ch = RTGetOpt(&GetState, &ValueUnion))) - { - switch (ch) - { - case 'l': - u32LocationId = ValueUnion.u32; - break; - case 's': - u64SessionId = ValueUnion.u64; - break; - case 'h': - return tstSyntax(argv[0]); - case 'V': - RTPrintf("$Revision$\n"); - return 0; - - default: - return RTGetOptPrintError(ch, &ValueUnion); - } - } - - /* - * Open the master port. - */ - mach_port_t MasterPort = MACH_PORT_NULL; - krc = IOMasterPort(MACH_PORT_NULL, &MasterPort); - if (krc != KERN_SUCCESS) - { - RTPrintf("%s: IOMasterPort -> %x\n", argv[0], krc); - return 1; - } - - /* - * Iterate the USB devices and find all that matches. - */ - CFMutableDictionaryRef RefMatchingDict = IOServiceMatching(kIOUSBDeviceClassName); - if (!RefMatchingDict) - { - RTPrintf("%s: IOServiceMatching failed\n", argv[0]); - return 1; - } - - io_iterator_t USBDevices = IO_OBJECT_NULL; - IOReturn irc = IOServiceGetMatchingServices(MasterPort, RefMatchingDict, &USBDevices); - if (irc != kIOReturnSuccess) - { - RTPrintf("%s: IOServiceGetMatchingServices -> %#x\n", argv[0], irc); - return 1; - } - RefMatchingDict = NULL; /* the reference is consumed by IOServiceGetMatchingServices. */ - - unsigned cDevices = 0; - unsigned cMatches = 0; - io_object_t USBDevice; - while ((USBDevice = IOIteratorNext(USBDevices))) - { - cDevices++; - CFMutableDictionaryRef PropsRef = 0; - krc = IORegistryEntryCreateCFProperties(USBDevice, &PropsRef, kCFAllocatorDefault, kNilOptions); - if (krc == KERN_SUCCESS) - { - uint64_t u64CurSessionId; - uint32_t u32CurLocationId; - if ( ( !u64SessionId - || ( tstDictGetU64(PropsRef, CFSTR("sessionID"), &u64CurSessionId) - && u64CurSessionId == u64SessionId)) - && ( !u32LocationId - || ( tstDictGetU32(PropsRef, CFSTR(kUSBDevicePropertyLocationID), &u32CurLocationId) - && u32CurLocationId == u32LocationId)) - ) - { - cMatches++; - CFRelease(PropsRef); - tstDoWork(USBDevice, argv[0]); - } - else - CFRelease(PropsRef); - } - IOObjectRelease(USBDevice); - } - IOObjectRelease(USBDevices); - - /* - * Bitch if we didn't find anything matching the criteria. - */ - if (!cMatches) - RTPrintf("%s: No matching devices found from a total of %d.\n", argv[0], cDevices); - return !cMatches; -} - |