USBLib-darwin.cpp revision c58f1213e628a545081c70e26c6b67a841cff880
/** $Id$ */
/** @file
* USBLib - Library for wrapping up the VBoxUSB functionality, Darwin flavor.
*/
/*
* Copyright (C) 2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <VBox/usblib.h>
#include <VBox/err.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 = NULL;
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(), 0, &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 = NULL;
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);
}