IOHIDTransaction.c   [plain text]


/*
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

#include <pthread.h>
#include <CoreFoundation/CFRuntime.h>
#include <IOKit/hid/IOHIDDevicePlugIn.h>
#include "IOHIDLibPrivate.h"
#include "IOHIDDevice.h"
#include "IOHIDTransaction.h"

static IOHIDTransactionRef  __IOHIDTransactionCreate(
                                    CFAllocatorRef          allocator, 
                                    CFAllocatorContext *    context __unused);
static void                 __IOHIDTransactionRelease( CFTypeRef object );
static void                 __IOHIDTransactionCommitCallback(
                                    void *                  context,
                                    IOReturn                result,
                                    void *                  sender);


typedef struct __IOHIDTransaction
{
    CFRuntimeBase                   cfBase;   // base CFType information

    IOHIDDeviceTransactionInterface**     transactionInterface;
    
    CFTypeRef                       asyncEventSource;
    CFRunLoopRef                    runLoop;
    CFStringRef                     runLoopMode;

    IOHIDDeviceRef                  device;
    void *                          context;
    IOHIDCallback                   callback;
} __IOHIDTransaction, *__IOHIDTransactionRef;

static const CFRuntimeClass __IOHIDTransactionClass = {
    0,                          // version
    "IOHIDTransaction",         // className
    NULL,                       // init
    NULL,                       // copy
    __IOHIDTransactionRelease,  // finalize
    NULL,                       // equal
    NULL,                       // hash
    NULL,                       // copyFormattingDesc
    NULL
};

static pthread_once_t   __transactionTypeInit = PTHREAD_ONCE_INIT;
static CFTypeID         __kIOHIDTransactionTypeID = _kCFRuntimeNotATypeID;

//------------------------------------------------------------------------------
// __IOHIDTransactionRegister
//------------------------------------------------------------------------------
void __IOHIDTransactionRegister(void)
{
    __kIOHIDTransactionTypeID = 
                _CFRuntimeRegisterClass(&__IOHIDTransactionClass);
}

//------------------------------------------------------------------------------
// __IOHIDTransactionCreate
//------------------------------------------------------------------------------
IOHIDTransactionRef __IOHIDTransactionCreate(   
                                CFAllocatorRef              allocator, 
                                CFAllocatorContext *        context __unused)
{
    IOHIDTransactionRef transaction = NULL;
    void *              offset      = NULL;
    uint32_t            size;

    /* allocate service */
    size  = sizeof(__IOHIDTransaction) - sizeof(CFRuntimeBase);
    transaction = (IOHIDTransactionRef)_CFRuntimeCreateInstance(
                                                allocator,
                                                IOHIDTransactionGetTypeID(), 
                                                size, 
                                                NULL);
    
    if (!transaction)
        return NULL;

    offset = transaction;
    bzero(offset + sizeof(CFRuntimeBase), size);
    
    return transaction;
}

//------------------------------------------------------------------------------
// __IOHIDTransactionRelease
//------------------------------------------------------------------------------
void __IOHIDTransactionRelease( CFTypeRef object )
{
    IOHIDTransactionRef transaction = (IOHIDTransactionRef)object;
    
    if ( transaction->transactionInterface ) {
        (*transaction->transactionInterface)->Release(
                                            transaction->transactionInterface);
        transaction->transactionInterface = NULL;
    }
    
    if ( transaction->device ) {
        CFRelease(transaction->device);
        transaction->device = NULL;
    }
}

//------------------------------------------------------------------------------
// __IOHIDTransactionCommitCallback
//------------------------------------------------------------------------------
void __IOHIDTransactionCommitCallback(
                                    void *                  context,
                                    IOReturn                result,
                                    void *                  sender)
{
    IOHIDTransactionRef transaction = (IOHIDTransactionRef)context;
    
    if ((transaction->transactionInterface == sender) && transaction->callback)
        (*transaction->callback)(   transaction->context,
                                    result,
                                    transaction);
}

//------------------------------------------------------------------------------
// IOHIDTransactionGetTypeID
//------------------------------------------------------------------------------
CFTypeID IOHIDTransactionGetTypeID(void) 
{
    if ( _kCFRuntimeNotATypeID == __kIOHIDTransactionTypeID )
        pthread_once(&__transactionTypeInit, __IOHIDTransactionRegister);
        
    return __kIOHIDTransactionTypeID;
}

//------------------------------------------------------------------------------
// IOHIDTransactionCreate
//------------------------------------------------------------------------------
IOHIDTransactionRef IOHIDTransactionCreate(
                                CFAllocatorRef                  allocator, 
                                IOHIDDeviceRef                  device,
                                IOHIDTransactionDirectionType   direction,
                                IOOptionBits                    options)
{
    IOCFPlugInInterface **              deviceInterface         = NULL;
    IOHIDDeviceTransactionInterface **  transactionInterface    = NULL;
    IOHIDTransactionRef                 transaction             = NULL;
    IOReturn                            ret;
    
    if ( !device )
        return NULL;
        
    deviceInterface = _IOHIDDeviceGetIOCFPlugInInterface(device);
    
    if ( !deviceInterface )
        return NULL;
        
    ret = (*deviceInterface)->QueryInterface(
                        deviceInterface, 
                        CFUUIDGetUUIDBytes(kIOHIDDeviceTransactionInterfaceID), 
                        (LPVOID)&transactionInterface);
    
    if ( ret != kIOReturnSuccess || !transactionInterface )
        return NULL;
        
    transaction = __IOHIDTransactionCreate(allocator, NULL);
    
    if ( !transaction ) {
        (*transactionInterface)->Release(transactionInterface);
        return NULL;
    }

    transaction->transactionInterface   = transactionInterface;
    transaction->device                 = (IOHIDDeviceRef)CFRetain(device);
    
    (*transaction->transactionInterface)->setDirection(
                            transaction->transactionInterface, 
                            direction, 
                            options);
    
    return transaction;
}

//------------------------------------------------------------------------------
// IOHIDTransactionGetDirection
//------------------------------------------------------------------------------
IOHIDDeviceRef IOHIDTransactionGetDevice(     
                                IOHIDTransactionRef             transaction)
{
    return transaction->device;
}

//------------------------------------------------------------------------------
// IOHIDTransactionGetDirection
//------------------------------------------------------------------------------
IOHIDTransactionDirectionType IOHIDTransactionGetDirection(     
                                IOHIDTransactionRef             transaction)
{
    IOHIDTransactionDirectionType direction = 0;
    (*transaction->transactionInterface)->getDirection(
                                        transaction->transactionInterface, 
                                        &direction);
    
    return direction;
}

//------------------------------------------------------------------------------
// IOHIDTransactionSetDirection
//------------------------------------------------------------------------------
void IOHIDTransactionSetDirection(        
                                IOHIDTransactionRef             transaction,
                                IOHIDTransactionDirectionType   direction)
{
    (*transaction->transactionInterface)->setDirection(
                                        transaction->transactionInterface, 
                                        direction, 
                                        0);
}
                                
//------------------------------------------------------------------------------
// IOHIDTransactionAddElement
//------------------------------------------------------------------------------
void IOHIDTransactionAddElement(      
                                IOHIDTransactionRef             transaction,
                                IOHIDElementRef                 element)
{
    (*transaction->transactionInterface)->addElement(
                                        transaction->transactionInterface, 
                                        element, 
                                        0);
}
                                
//------------------------------------------------------------------------------
// IOHIDTransactionRemoveElement
//------------------------------------------------------------------------------
void IOHIDTransactionRemoveElement(
                                IOHIDTransactionRef             transaction,
                                IOHIDElementRef                 element)
{
    (*transaction->transactionInterface)->removeElement(
                                        transaction->transactionInterface, 
                                        element, 
                                        0);
}
                                
//------------------------------------------------------------------------------
// IOHIDTransactionContainsElement
//------------------------------------------------------------------------------
Boolean IOHIDTransactionContainsElement(
                                IOHIDTransactionRef             transaction,
                                IOHIDElementRef                 element)
{
    Boolean hasElement = FALSE;
    
    (*transaction->transactionInterface)->containsElement(
                                            transaction->transactionInterface, 
                                            element, 
                                            &hasElement, 
                                            0);
                                            
    return hasElement;
}
                                
//------------------------------------------------------------------------------
// IOHIDTransactionScheduleWithRunLoop
//------------------------------------------------------------------------------
void IOHIDTransactionScheduleWithRunLoop(
                                IOHIDTransactionRef             transaction, 
                                CFRunLoopRef                    runLoop, 
                                CFStringRef                     runLoopMode)
{
    if ( !transaction->asyncEventSource) {
        IOReturn ret;
        
        ret = (*transaction->transactionInterface)->getAsyncEventSource(
                                            transaction->transactionInterface,
                                            &transaction->asyncEventSource);
        
        if (ret != kIOReturnSuccess || !transaction->asyncEventSource)
            return;
    }

    transaction->runLoop     = runLoop;
    transaction->runLoopMode = runLoopMode;
        
    if (CFGetTypeID(transaction->asyncEventSource) == CFRunLoopSourceGetTypeID())
        CFRunLoopAddSource( transaction->runLoop, 
                            (CFRunLoopSourceRef)transaction->asyncEventSource, 
                            transaction->runLoopMode);
    else if (CFGetTypeID(transaction->asyncEventSource) == CFRunLoopTimerGetTypeID())
        CFRunLoopAddTimer(  transaction->runLoop, 
                            (CFRunLoopTimerRef)transaction->asyncEventSource, 
                            transaction->runLoopMode);

}

//------------------------------------------------------------------------------
// IOHIDTransactionUnscheduleFromRunLoop
//------------------------------------------------------------------------------
void IOHIDTransactionUnscheduleFromRunLoop(  
                                IOHIDTransactionRef                   transaction, 
                                CFRunLoopRef                    runLoop, 
                                CFStringRef                     runLoopMode)
{
    if ( !transaction->asyncEventSource )
        return;
        
    if (CFGetTypeID(transaction->asyncEventSource) == CFRunLoopSourceGetTypeID())
        CFRunLoopRemoveSource(  runLoop, 
                                (CFRunLoopSourceRef)transaction->asyncEventSource, 
                                runLoopMode);
    else if (CFGetTypeID(transaction->asyncEventSource) == CFRunLoopTimerGetTypeID())
        CFRunLoopRemoveTimer(   runLoop, 
                                (CFRunLoopTimerRef)transaction->asyncEventSource, 
                                runLoopMode);
                                
    transaction->runLoop     = NULL;
    transaction->runLoopMode = NULL;
}
                                
//------------------------------------------------------------------------------
// IOHIDTransactionSetValue
//------------------------------------------------------------------------------
void IOHIDTransactionSetValue(
                                IOHIDTransactionRef             transaction,
                                IOHIDElementRef                 element, 
                                IOHIDValueRef                   value,
                                IOOptionBits                    options)
{
    (*transaction->transactionInterface)->setValue(
                                            transaction->transactionInterface, 
                                            element, 
                                            value, 
                                            options);
}

//------------------------------------------------------------------------------
// IOHIDTransactionGetValue
//------------------------------------------------------------------------------
IOHIDValueRef IOHIDTransactionGetValue(
                                IOHIDTransactionRef             transaction,
                                IOHIDElementRef                 element,
                                IOOptionBits                    options)
{
    IOHIDValueRef value = NULL;
    IOReturn ret;
    
    ret = (*transaction->transactionInterface)->getValue(
                                            transaction->transactionInterface, 
                                            element, 
                                            &value, 
                                            options);
                                            
    return (ret == kIOReturnSuccess) ? value : NULL;
}
       
//------------------------------------------------------------------------------
// IOHIDTransactionCommit
//------------------------------------------------------------------------------
IOReturn IOHIDTransactionCommit(
                                IOHIDTransactionRef             transaction)
{
    return IOHIDTransactionCommitWithCallback(transaction, 0, NULL, NULL);
}
                                
//------------------------------------------------------------------------------
// IOHIDTransactionCommitWithCallback
//------------------------------------------------------------------------------
IOReturn IOHIDTransactionCommitWithCallback(
                                IOHIDTransactionRef             transaction,
                                CFTimeInterval                  timeout, 
                                IOHIDCallback                   callback, 
                                void *                          context)
{
    uint32_t    timeoutMS = timeout / 1000;

    transaction->callback   = callback;
    transaction->context    = context;
    
    return (*transaction->transactionInterface)->commit(
                                            transaction->transactionInterface,
                                            timeoutMS,
                                            __IOHIDTransactionCommitCallback,
                                            transaction,
                                            0);
}

//------------------------------------------------------------------------------
// IOHIDTransactionUnscheduleFromRunLoop
//------------------------------------------------------------------------------
void IOHIDTransactionClear(
                                IOHIDTransactionRef             transaction)
{
    (*transaction->transactionInterface)->clear(
                                            transaction->transactionInterface,
                                            0);
}