Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
HID_Queue_Utilities.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Õ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; |
} |
Copyright © 2008 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2008-02-08