qzdoom-gpl/src/cocoa/HID_Queue_Utilities.c

354 lines
13 KiB
C
Executable file

// File: HID_Queue_Utilities.c
// Abstract: HID Queue Utilities.
// Version: 2.0
//
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
// Inc. ("Apple") in consideration of your agreement to the following
// terms, and your use, installation, modification or redistribution of
// this Apple software constitutes acceptance of these terms. If you do
// not agree with these terms, please do not use, install, modify or
// redistribute this Apple software.
//
// In consideration of your agreement to abide by the following terms, and
// subject to these terms, Apple grants you a personal, non-exclusive
// license, under Apple's copyrights in this original Apple software (the
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
// Software, with or without modifications, in source and/or binary forms;
// provided that if you redistribute the Apple Software in its entirety and
// without modifications, you must retain this notice and the following
// text and disclaimers in all such redistributions of the Apple Software.
// Neither the name, trademarks, service marks or logos of Apple Inc. may
// be used to endorse or promote products derived from the Apple Software
// without specific prior written permission from Apple. Except as
// expressly stated in this notice, no other rights or licenses, express or
// implied, are granted by Apple herein, including but not limited to any
// patent rights that may be infringed by your derivative works or by other
// works in which the Apple Software may be incorporated.
//
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
//
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (C) 2009 Apple Inc. All Rights Reserved.
//
//*****************************************************
#include "HID_Utilities_External.h"
// ==================================
// private functions
// creates a queue for a device, creates and opens device interface if required
static IOReturn HIDCreateQueue(IOHIDDeviceRef inIOHIDDeviceRef) {
IOReturn result = kIOReturnSuccess;
if ( inIOHIDDeviceRef ) {
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
// do we already have a queue?
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
if ( tIOHIDQueueRef ) { // (yes)
assert( IOHIDQueueGetTypeID() == CFGetTypeID(tIOHIDQueueRef) );
} else {
tIOHIDQueueRef = IOHIDQueueCreate(kCFAllocatorDefault, inIOHIDDeviceRef, kDeviceQueueSize, kIOHIDOptionsTypeNone);
if ( tIOHIDQueueRef ) { // did that work
IOHIDDevice_SetQueue(inIOHIDDeviceRef, tIOHIDQueueRef);
result = kIOReturnSuccess;
} else {
HIDReportErrorNum("Failed to create queue via create", result);
}
}
} else {
HIDReportErrorNum("HID device ref does not exist for queue creation", result);
}
return (result);
} /* HIDCreateQueue */
// ---------------------------------
// returns true if queue is empty false otherwise
// error if no device, empty if no queue
static unsigned char HIDIsDeviceQueueEmpty(IOHIDDeviceRef inIOHIDDeviceRef) {
if ( inIOHIDDeviceRef ) { // need device and queue
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
if ( tIOHIDQueueRef ) {
IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO);
while ( tIOHIDElementRef ) {
if ( IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) {
return (false);
}
tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO);
}
} else {
HIDReportError("NULL device passed to HIDIsDeviceQueueEmpty.");
}
} else {
HIDReportError("NULL device passed to HIDIsDeviceQueueEmpty.");
}
return (true);
} /* HIDIsDeviceQueueEmpty */
// ---------------------------------
// disposes and releases queue, sets queue to NULL,.
// Note: will have no effect if device or queue do not exist
static IOReturn HIDDisposeReleaseQueue(IOHIDDeviceRef inIOHIDDeviceRef) {
IOReturn result = kIOReturnSuccess;
if ( inIOHIDDeviceRef ) {
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
if ( tIOHIDQueueRef ) {
// stop queue
IOHIDQueueStop(tIOHIDQueueRef);
// release the queue
CFRelease(tIOHIDQueueRef);
}
} else {
HIDReportError("NULL device passed to HIDDisposeReleaseQueue.");
}
return (result);
} /* HIDDisposeReleaseQueue */
// ==================================
// public functions
// ----------------------------------
// queues specific element, performing any device queue set up required
// queue is started and ready to return events on exit from this function
int HIDQueueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) {
IOReturn result = kIOReturnSuccess;
if ( inIOHIDDeviceRef ) {
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
if ( inIOHIDElementRef ) {
assert( IOHIDElementGetTypeID() == CFGetTypeID(inIOHIDElementRef) );
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
if ( !tIOHIDQueueRef ) { // if no queue create queue
result = HIDCreateQueue(inIOHIDDeviceRef);
if ( kIOReturnSuccess == result ) {
tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
}
}
if ( tIOHIDQueueRef ) {
// stop queue
IOHIDQueueStop(tIOHIDQueueRef);
// queue element
if ( !IOHIDQueueContainsElement(tIOHIDQueueRef, inIOHIDElementRef) ) {
IOHIDQueueAddElement(tIOHIDQueueRef, inIOHIDElementRef);
}
// restart queue
IOHIDQueueStart(tIOHIDQueueRef);
} else {
HIDReportError("No queue for device passed to HIDQueueElement.");
if ( kIOReturnSuccess == result ) {
result = kIOReturnError;
}
}
} else {
HIDReportError("NULL element passed to HIDQueueElement.");
result = kIOReturnBadArgument;
}
} else {
HIDReportError("NULL device passed to HIDQueueElement.");
result = kIOReturnBadArgument;
}
return (result);
} /* HIDQueueElement */
// ---------------------------------
// adds all elements to queue, performing any device queue set up required
// queue is started and ready to return events on exit from this function
int HIDQueueDevice(IOHIDDeviceRef inIOHIDDeviceRef) {
IOReturn result = kIOReturnSuccess;
// error checking
if ( !inIOHIDDeviceRef ) {
HIDReportError("Device does not exist, cannot queue device.");
return (kIOReturnBadArgument);
}
if ( !inIOHIDDeviceRef ) { // must have interface
HIDReportError("Device does not have hid device ref, cannot queue device.");
return (kIOReturnError);
}
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
if ( !tIOHIDQueueRef ) { // if no queue create queue
result = HIDCreateQueue(inIOHIDDeviceRef);
if ( kIOReturnSuccess == result ) {
tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
}
}
if ( (kIOReturnSuccess != result) || (!tIOHIDQueueRef) ) {
HIDReportErrorNum("Could not queue device due to problem creating queue.", result);
if ( kIOReturnSuccess != result ) {
return (result);
} else {
return (kIOReturnError);
}
}
// stop queue
IOHIDQueueStop(tIOHIDQueueRef);
// queue element
IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO);
while ( tIOHIDElementRef ) {
if ( !IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) {
IOHIDQueueAddElement(tIOHIDQueueRef, tIOHIDElementRef);
}
tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO);
}
// restart queue
IOHIDQueueStart(tIOHIDQueueRef);
return (result);
} /* HIDQueueDevice */
// ---------------------------------
// removes element for queue, if last element in queue will release queue and closes device interface
int HIDDequeueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) {
IOReturn result = kIOReturnSuccess;
if ( inIOHIDDeviceRef ) {
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
if ( inIOHIDElementRef ) {
assert( IOHIDElementGetTypeID() == CFGetTypeID(inIOHIDElementRef) );
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
if ( tIOHIDQueueRef ) {
// stop queue
IOHIDQueueStop(tIOHIDQueueRef);
// de-queue element
if ( IOHIDQueueContainsElement(tIOHIDQueueRef, inIOHIDElementRef) ) {
IOHIDQueueRemoveElement(tIOHIDQueueRef, inIOHIDElementRef);
}
// release device queue and close interface if queue empty
if ( HIDIsDeviceQueueEmpty(inIOHIDDeviceRef) ) {
result = HIDDisposeReleaseQueue(inIOHIDDeviceRef);
if ( kIOReturnSuccess != result ) {
HIDReportErrorNum("Failed to dispose and release queue.", result);
}
} else { // not empty so restart queue
IOHIDQueueStart(tIOHIDQueueRef);
}
} else {
HIDReportError("No queue for device passed to HIDDequeueElement.");
if ( kIOReturnSuccess == result ) {
result = kIOReturnError;
}
}
} else {
HIDReportError("NULL element passed to HIDDequeueElement.");
result = kIOReturnBadArgument;
}
} else {
HIDReportError("NULL device passed to HIDDequeueElement.");
result = kIOReturnBadArgument;
}
return (result);
} /* HIDDequeueElement */
// ---------------------------------
// completely removes all elements from queue and releases queue and closes device interface
// does not release device interfaces, application must call ReleaseHIDDeviceList on exit
int HIDDequeueDevice(IOHIDDeviceRef inIOHIDDeviceRef) {
IOReturn result = kIOReturnSuccess;
// error checking
if ( !inIOHIDDeviceRef ) {
HIDReportError("Device does not exist, cannot queue device.");
return (kIOReturnBadArgument);
}
if ( !inIOHIDDeviceRef ) { // must have interface
HIDReportError("Device does not have hid device ref, cannot queue device.");
return (kIOReturnError);
}
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
if ( tIOHIDQueueRef ) {
// iterate through elements and if queued, remove
IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO);
while ( tIOHIDElementRef ) {
// de-queue element
if ( IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) {
IOHIDQueueRemoveElement(tIOHIDQueueRef, tIOHIDElementRef);
}
tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO);
}
// ensure queue is disposed and released
result = HIDDisposeReleaseQueue(inIOHIDDeviceRef);
if ( kIOReturnSuccess != result ) {
HIDReportErrorNum("Failed to dispose and release queue.", result);
}
} else {
HIDReportError("No queue for device passed to HIDDequeueElement.");
if ( kIOReturnSuccess == result ) {
result = kIOReturnError;
}
}
return (result);
} /* HIDDequeueDevice */
// ---------------------------------
// releases all device queues for quit or rebuild (must be called)
// does not release device interfaces, application must call ReleaseHIDDeviceList on exit
IOReturn HIDReleaseAllDeviceQueues(void) {
IOReturn result = kIOReturnSuccess;
IOHIDDeviceRef tIOHIDDeviceRef = HIDGetFirstDevice();
while ( tIOHIDDeviceRef ) {
result = HIDDequeueDevice(tIOHIDDeviceRef);
if ( kIOReturnSuccess != result ) {
HIDReportErrorNum("Could not dequeue device.", result);
}
tIOHIDDeviceRef = HIDGetNextDevice(tIOHIDDeviceRef);
}
return (result);
} /* HIDReleaseAllDeviceQueues */
// ---------------------------------
// Get the next event in the queue for a device
// elements or entire device should be queued prior to calling this with HIDQueueElement or HIDQueueDevice
// returns true if an event is avialable for the element and fills out *pHIDEvent structure, returns false otherwise
// Note: kIOReturnUnderrun returned from getNextEvent indicates an empty queue not an error condition
// Note: application should pass in a pointer to a IOHIDEventStruct cast to a void (for CFM compatibility)
unsigned char HIDGetEvent(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDValueRef *pIOHIDValueRef) {
if ( inIOHIDDeviceRef ) {
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
if ( tIOHIDQueueRef ) {
if ( pIOHIDValueRef ) {
*pIOHIDValueRef = IOHIDQueueCopyNextValueWithTimeout(tIOHIDQueueRef, 0.0);
if ( *pIOHIDValueRef ) {
return (true);
}
}
} else {
HIDReportError("Could not get HID event, hid queue reference does not exist.");
}
} else {
HIDReportError("Could not get HID event, device does not exist.");
}
return (false); // did not get event
} /* HIDGetEvent */