mirror of
https://github.com/darlinghq/darling-glut.git
synced 2024-11-23 12:19:42 +00:00
486 lines
18 KiB
C
486 lines
18 KiB
C
//
|
||
// File: HID_Queue_Utilities.c
|
||
//
|
||
// 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 ) 2001-2008 Apple Inc. All Rights Reserved.
|
||
//
|
||
|
||
#include "HID_Utilities_Internal.h"
|
||
#include "HID_Utilities_External.h"
|
||
|
||
static IOReturn HIDCreateQueue (pRecDevice pDevice);
|
||
static unsigned char HIDIsDeviceQueueEmpty (pRecDevice pDevice);
|
||
static IOReturn HIDDisposeReleaseQueue (pRecDevice pDevice);
|
||
|
||
// ==================================
|
||
// private functions
|
||
|
||
// creates a queue for a device, creates and opens device interface if required
|
||
|
||
static IOReturn HIDCreateQueue (pRecDevice pDevice)
|
||
{
|
||
IOReturn result = kIOReturnSuccess;
|
||
if (NULL == pDevice->queue) // do we already have a queue
|
||
{
|
||
if (NULL != pDevice->interface)
|
||
{
|
||
pDevice->queue =(void *) (*(IOHIDDeviceInterface **) pDevice->interface)->allocQueue (pDevice->interface); // alloc queue
|
||
if (pDevice->queue)
|
||
{
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->create (pDevice->queue, 0, kDeviceQueueSize); // create actual queue
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to create queue via create", result);
|
||
}
|
||
else
|
||
{
|
||
HIDReportError ("Failed to alloc IOHIDQueueInterface ** via allocQueue");
|
||
result = kIOReturnError; // synthesis error
|
||
}
|
||
}
|
||
else
|
||
HIDReportErrorNum ("Device inteface does not exist for queue creation", result);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
// ---------------------------------
|
||
|
||
// returns true if queue is empty false otherwise
|
||
// error if no device, empty if no queue
|
||
|
||
static unsigned char HIDIsDeviceQueueEmpty (pRecDevice pDevice)
|
||
{
|
||
if (pDevice && pDevice->queue) // need device and queue
|
||
{
|
||
pRecElement pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO);
|
||
while (pElement)
|
||
{
|
||
if ((*(IOHIDQueueInterface **) pDevice->queue)->hasElement (pDevice->queue, pElement->cookie))
|
||
return false;
|
||
pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO);
|
||
}
|
||
}
|
||
else if (NULL == pDevice) // if no device (if just no queue then queue must be empty)
|
||
HIDReportError ("NULL device passed to DeviceQueueEmpty.");
|
||
return true;
|
||
}
|
||
|
||
// ---------------------------------
|
||
|
||
// disposes and releases queue, sets queue to NULL,.
|
||
// Note: will have no effect if device or queue do not exist
|
||
|
||
static IOReturn HIDDisposeReleaseQueue (pRecDevice pDevice)
|
||
{
|
||
IOReturn result = kIOReturnSuccess;
|
||
|
||
if ((NULL != pDevice) && (NULL != pDevice->queue))
|
||
{
|
||
// stop queue
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->stop (pDevice->queue);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to stop queue.", result);
|
||
// dispose of queue
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->dispose (pDevice->queue);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to dipose queue.", result);
|
||
// release the queue
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->Release (pDevice->queue);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to release queue.", result);
|
||
|
||
pDevice->queue = NULL;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
// ==================================
|
||
// public functions
|
||
|
||
// Create and open an interface to device, required prior to extracting values or building queues
|
||
// Note: appliction now owns the device and must close and release it prior to exiting
|
||
|
||
IOReturn HIDCreateOpenDeviceInterface (io_object_t hidDevice, pRecDevice pDevice)
|
||
{
|
||
IOReturn result = kIOReturnSuccess;
|
||
HRESULT plugInResult = S_OK;
|
||
SInt32 score = 0;
|
||
IOCFPlugInInterface ** ppPlugInInterface = NULL;
|
||
|
||
if (NULL == pDevice->interface)
|
||
{
|
||
result = IOCreatePlugInInterfaceForService (hidDevice, kIOHIDDeviceUserClientTypeID,
|
||
kIOCFPlugInInterfaceID, &ppPlugInInterface, &score);
|
||
if (kIOReturnSuccess == result)
|
||
{
|
||
// Call a method of the intermediate plug-in to create the device interface
|
||
plugInResult = (*ppPlugInInterface)->QueryInterface (ppPlugInInterface,
|
||
CFUUIDGetUUIDBytes (kIOHIDDeviceInterfaceID), (void *) &(pDevice->interface));
|
||
if (S_OK != plugInResult)
|
||
HIDReportErrorNum ("Couldn<EFBFBD>t query HID class device interface from plugInInterface", plugInResult);
|
||
IODestroyPlugInInterface (ppPlugInInterface); // replace (*ppPlugInInterface)->Release (ppPlugInInterface)
|
||
}
|
||
else
|
||
HIDReportErrorNum ("Failed to create **plugInInterface via IOCreatePlugInInterfaceForService.", result);
|
||
}
|
||
if (NULL != pDevice->interface)
|
||
{
|
||
result = (*(IOHIDDeviceInterface **)pDevice->interface)->open (pDevice->interface, 0);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to open pDevice->interface via open.", result);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
// ---------------------------------
|
||
|
||
// 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 (pRecDevice pDevice, pRecElement pElement)
|
||
{
|
||
IOReturn result = kIOReturnSuccess;
|
||
|
||
// error checking
|
||
if ((NULL == pDevice) || (NULL == pElement))
|
||
{
|
||
HIDReportError ("Device or element does not exist, cannot queue element.");
|
||
return kIOReturnBadArgument;
|
||
}
|
||
if (NULL == pDevice->interface) // must have interface
|
||
{
|
||
HIDReportError ("Device does not have interface, cannot queue element.");
|
||
return kIOReturnError;
|
||
}
|
||
if (NULL == pDevice->queue) // if no queue create queue
|
||
result = HIDCreateQueue (pDevice);
|
||
if ((kIOReturnSuccess != result) || (NULL == pDevice->queue))
|
||
{
|
||
HIDReportErrorNum ("Could not queue element due to problem creating queue.", result);
|
||
if (kIOReturnSuccess != result)
|
||
return result;
|
||
else
|
||
return kIOReturnError;
|
||
}
|
||
|
||
// stop queue
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->stop (pDevice->queue);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportError ("Failed to stop queue.");
|
||
|
||
// queue element
|
||
if (!(*(IOHIDQueueInterface **) pDevice->queue)->hasElement (pDevice->queue, pElement->cookie))
|
||
{
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->addElement (pDevice->queue, pElement->cookie, 0);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportError ("Failed to add element to queue via addElement.");
|
||
}
|
||
|
||
// restart queue
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->start (pDevice->queue);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportError ("Failed to start queue.");
|
||
|
||
return result;
|
||
}
|
||
|
||
// ---------------------------------
|
||
|
||
// 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 (pRecDevice pDevice)
|
||
{
|
||
IOReturn result = kIOReturnSuccess;
|
||
pRecElement pElement;
|
||
|
||
// error checking
|
||
if (NULL == pDevice)
|
||
{
|
||
HIDReportError ("Device does not exist, cannot queue device.");
|
||
return kIOReturnBadArgument;
|
||
}
|
||
if (NULL == pDevice->interface) // must have interface
|
||
{
|
||
HIDReportError ("Device does not have interface, cannot queue device.");
|
||
return kIOReturnError;
|
||
}
|
||
if (NULL == pDevice->queue) // if no queue create queue
|
||
result = HIDCreateQueue (pDevice);
|
||
if ((kIOReturnSuccess != result) || (NULL == pDevice->queue))
|
||
{
|
||
HIDReportErrorNum ("Could not queue device due to problem creating queue.", result);
|
||
if (kIOReturnSuccess != result)
|
||
return result;
|
||
else
|
||
return kIOReturnError;
|
||
}
|
||
|
||
// stop queue
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->stop (pDevice->queue);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to stop queue.", result);
|
||
|
||
// queue element
|
||
pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO);
|
||
while (pElement)
|
||
{
|
||
if (!(*(IOHIDQueueInterface **) pDevice->queue)->hasElement (pDevice->queue, pElement->cookie))
|
||
{
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->addElement (pDevice->queue, pElement->cookie, 0);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to add element to queue via addElement", result);
|
||
}
|
||
pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO);
|
||
}
|
||
|
||
// start queue
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->start (pDevice->queue);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to start queue.", result);
|
||
|
||
return result;
|
||
}
|
||
|
||
// ---------------------------------
|
||
|
||
// removes element for queue, if last element in queue will release queue and closes device interface
|
||
|
||
int HIDDequeueElement (pRecDevice pDevice, pRecElement pElement)
|
||
{
|
||
IOReturn result = kIOReturnSuccess;
|
||
if (!pDevice || !pElement)
|
||
result = kIOReturnBadArgument;
|
||
else
|
||
{
|
||
if ((pDevice->interface) && (pDevice->queue))
|
||
{
|
||
// stop queue
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->stop (pDevice->queue);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to stop queue.", result);
|
||
|
||
if ((*(IOHIDQueueInterface **) pDevice->queue)->hasElement (pDevice->queue, pElement->cookie)) // if has element then remove
|
||
{
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->removeElement (pDevice->queue, pElement->cookie);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to add element to queue via addElement", result);
|
||
}
|
||
|
||
if (HIDIsDeviceQueueEmpty (pDevice)) // release device queue and close interface if queue empty
|
||
{
|
||
result = HIDDisposeReleaseQueue (pDevice);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to dispose and release queue.", result);
|
||
}
|
||
else // not empty so restart queue
|
||
{
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->start (pDevice->queue);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to start queue.", result);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
HIDReportError ("No device inteface or queue.");
|
||
return kIOReturnError;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
// ---------------------------------
|
||
|
||
// 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 (pRecDevice pDevice)
|
||
{
|
||
IOReturn result = kIOReturnSuccess;
|
||
if (!pDevice)
|
||
result = kIOReturnBadArgument;
|
||
else
|
||
{
|
||
if ((pDevice->interface) && (pDevice->queue))
|
||
{
|
||
// iterate through elements and if queued, remove
|
||
pRecElement pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO);
|
||
while (pElement)
|
||
{
|
||
if ((*(IOHIDQueueInterface **) pDevice->queue)->hasElement (pDevice->queue, pElement->cookie))
|
||
{
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->removeElement (pDevice->queue, pElement->cookie);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to add element to queue via addElement", result);
|
||
}
|
||
pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO);
|
||
}
|
||
}
|
||
// ensure queue is disposed and released
|
||
// interface will be closed and released on call to ReleaseHIDDeviceList
|
||
result = HIDDisposeReleaseQueue (pDevice);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to dispose and release queue.", result);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
// ---------------------------------
|
||
|
||
// 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;
|
||
pRecDevice pDevice = HIDGetFirstDevice ();
|
||
while (pDevice)
|
||
{
|
||
result = HIDDequeueDevice (pDevice);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Could not dequeue device.", result);
|
||
pDevice = HIDGetNextDevice (pDevice);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
// ---------------------------------
|
||
|
||
// Closes and releases interface to device, should be done prior to exting application
|
||
// Note: will have no affect if device or interface do not exist
|
||
// application will "own" the device if interface is not closed
|
||
// (device may have to be plug and re-plugged in different location to get it working again without a restart)
|
||
|
||
IOReturn HIDCloseReleaseInterface (pRecDevice pDevice)
|
||
{
|
||
IOReturn result = kIOReturnSuccess;
|
||
|
||
if ((NULL != pDevice) && (NULL != pDevice->interface))
|
||
{
|
||
// close the interface
|
||
result = (*(IOHIDDeviceInterface **) pDevice->interface)->close (pDevice->interface);
|
||
if (kIOReturnNotOpen == result)
|
||
{
|
||
// do nothing as device was not opened, thus can't be closed
|
||
}
|
||
else if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to close IOHIDDeviceInterface.", result);
|
||
//release the interface
|
||
result = (*(IOHIDDeviceInterface **) pDevice->interface)->Release (pDevice->interface);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Failed to release IOHIDDeviceInterface.", result);
|
||
pDevice->interface = NULL;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
// ---------------------------------
|
||
|
||
// 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 (pRecDevice pDevice, void * pHIDEvent)
|
||
{
|
||
IOReturn result = kIOReturnSuccess;
|
||
AbsoluteTime zeroTime = {0,0};
|
||
if (pDevice)
|
||
{
|
||
if (pDevice->queue)
|
||
{
|
||
result = (*(IOHIDQueueInterface **) pDevice->queue)->getNextEvent (pDevice->queue, (IOHIDEventStruct *)pHIDEvent, zeroTime, 0);
|
||
if (kIOReturnUnderrun == result)
|
||
return false; // no events in queue not an error per say
|
||
else if (kIOReturnSuccess != result) // actual error versus just an empty queue
|
||
HIDReportErrorNum ("Could not get HID event via getNextEvent.", result);
|
||
else
|
||
return true;
|
||
}
|
||
else
|
||
HIDReportError ("Could not get HID event, queue does not exist.");
|
||
}
|
||
else
|
||
HIDReportError ("Could not get HID event, device does not exist.");
|
||
return false; // did not get event
|
||
}
|
||
|
||
// ---------------------------------
|
||
|
||
// returns current value for element, polling element
|
||
// will return 0 on error conditions which should be accounted for by application
|
||
|
||
int HIDGetElementValue (pRecDevice pDevice, pRecElement pElement)
|
||
{
|
||
IOReturn result = kIOReturnSuccess;
|
||
IOHIDEventStruct hidEvent;
|
||
hidEvent.value = 0;
|
||
|
||
if (NULL != pDevice)
|
||
{
|
||
if (NULL != pElement)
|
||
{
|
||
if (NULL != pDevice->interface)
|
||
{
|
||
result = (*(IOHIDDeviceInterface **) pDevice->interface)->getElementValue (pDevice->interface, pElement->cookie, &hidEvent);
|
||
if (kIOReturnSuccess != result)
|
||
HIDReportErrorNum ("Could not get HID element value via getElementValue.", result);
|
||
// on 10.0.x this returns the incorrect result for negative ranges, so fix it!!!
|
||
// this is not required on Mac OS X 10.1+
|
||
if ((pElement->min < 0) && (hidEvent.value > pElement->max)) // assume range problem
|
||
hidEvent.value = hidEvent.value + pElement->min - pElement->max - 1;
|
||
}
|
||
else
|
||
HIDReportError ("Did not have interface for device prior to getting element value.");
|
||
}
|
||
else
|
||
HIDReportError ("Bad element passed to GetElementValue.");
|
||
}
|
||
else
|
||
HIDReportError ("Bad device passed to GetElementValue.");
|
||
// record min and max for auto scale and auto ...
|
||
if (hidEvent.value < pElement->minReport)
|
||
pElement->minReport = hidEvent.value;
|
||
if (hidEvent.value > pElement->maxReport)
|
||
pElement->maxReport = hidEvent.value;
|
||
|
||
return hidEvent.value;
|
||
}
|