2 // File: HID_Queue_Utilities.c
4 // Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple")
5 // in consideration of your agreement to the following terms, and your use,
6 // installation, modification or redistribution of this Apple software
7 // constitutes acceptance of these terms. If you do not agree with these
8 // terms, please do not use, install, modify or redistribute this Apple
11 // In consideration of your agreement to abide by the following terms, and
12 // subject to these terms, Apple grants you a personal, non - exclusive
13 // license, under Apple's copyrights in this original Apple software ( the
14 // "Apple Software" ), to use, reproduce, modify and redistribute the Apple
15 // Software, with or without modifications, in source and / or binary forms;
16 // provided that if you redistribute the Apple Software in its entirety and
17 // without modifications, you must retain this notice and the following text
18 // and disclaimers in all such redistributions of the Apple Software. Neither
19 // the name, trademarks, service marks or logos of Apple Inc. may be used to
20 // endorse or promote products derived from the Apple Software without specific
21 // prior written permission from Apple. Except as expressly stated in this
22 // notice, no other rights or licenses, express or implied, are granted by
23 // Apple herein, including but not limited to any patent rights that may be
24 // infringed by your derivative works or by other works in which the Apple
25 // Software may be incorporated.
27 // The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
28 // WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
29 // WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
30 // PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
31 // ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
33 // IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
34 // CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 // INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
37 // AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
38 // UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR
39 // OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 // Copyright © 2001-2009 Apple Inc. All Rights Reserved.
44 #include "HID_Utilities_External.h"
46 // ==================================
49 // creates a queue for a device, creates and opens device interface if required
50 static IOReturn
HIDCreateQueue( IOHIDDeviceRef inIOHIDDeviceRef
)
52 IOReturn result
= kIOReturnSuccess
;
54 if ( inIOHIDDeviceRef
) {
55 assert( IOHIDDeviceGetTypeID() == CFGetTypeID( inIOHIDDeviceRef
) );
57 // do we already have a queue?
58 IOHIDQueueRef tIOHIDQueueRef
= IOHIDDevice_GetQueue( inIOHIDDeviceRef
);
60 if ( tIOHIDQueueRef
) { // (yes)
61 assert( IOHIDQueueGetTypeID() == CFGetTypeID( tIOHIDQueueRef
) );
63 tIOHIDQueueRef
= IOHIDQueueCreate( kCFAllocatorDefault
, inIOHIDDeviceRef
, kDeviceQueueSize
, kIOHIDOptionsTypeNone
);
65 if ( tIOHIDQueueRef
) { // did that work
66 HIDReportErrorNum( "Failed to create queue via create", result
);
68 result
= kIOReturnSuccess
;
72 HIDReportErrorNum( "HID device ref does not exist for queue creation", result
);
75 } /* HIDCreateQueue */
77 // ---------------------------------
78 // returns true if queue is empty false otherwise
79 // error if no device, empty if no queue
80 static unsigned char HIDIsDeviceQueueEmpty( IOHIDDeviceRef inIOHIDDeviceRef
)
82 if ( inIOHIDDeviceRef
) { // need device and queue
83 assert( IOHIDDeviceGetTypeID() == CFGetTypeID( inIOHIDDeviceRef
) );
84 IOHIDQueueRef tIOHIDQueueRef
= IOHIDDevice_GetQueue( inIOHIDDeviceRef
);
85 if ( tIOHIDQueueRef
) {
86 IOHIDElementRef tIOHIDElementRef
= HIDGetFirstDeviceElement( inIOHIDDeviceRef
, kHIDElementTypeIO
);
87 while ( tIOHIDElementRef
) {
88 if ( IOHIDQueueContainsElement( tIOHIDQueueRef
, tIOHIDElementRef
) ) {
91 tIOHIDElementRef
= HIDGetNextDeviceElement( tIOHIDElementRef
, kHIDElementTypeIO
);
94 HIDReportError( "NULL device passed to HIDIsDeviceQueueEmpty." );
97 HIDReportError( "NULL device passed to HIDIsDeviceQueueEmpty." );
100 } /* HIDIsDeviceQueueEmpty */
102 // ---------------------------------
104 // disposes and releases queue, sets queue to NULL,.
105 // Note: will have no effect if device or queue do not exist
106 static IOReturn
HIDDisposeReleaseQueue( IOHIDDeviceRef inIOHIDDeviceRef
)
108 IOReturn result
= kIOReturnSuccess
;
110 if ( inIOHIDDeviceRef
) {
111 IOHIDQueueRef tIOHIDQueueRef
= IOHIDDevice_GetQueue( inIOHIDDeviceRef
);
112 if ( tIOHIDQueueRef
) {
114 IOHIDQueueStop( tIOHIDQueueRef
);
117 CFRelease( tIOHIDQueueRef
);
120 HIDReportError( "NULL device passed to HIDDisposeReleaseQueue." );
123 } /* HIDDisposeReleaseQueue */
125 // ==================================
127 // ----------------------------------
129 // queues specific element, performing any device queue set up required
130 // queue is started and ready to return events on exit from this function
131 int HIDQueueElement( IOHIDDeviceRef inIOHIDDeviceRef
, IOHIDElementRef inIOHIDElementRef
)
133 IOReturn result
= kIOReturnSuccess
;
135 if ( inIOHIDDeviceRef
) {
136 assert( IOHIDDeviceGetTypeID() == CFGetTypeID( inIOHIDDeviceRef
) );
137 if ( inIOHIDElementRef
) {
138 assert( IOHIDElementGetTypeID() == CFGetTypeID( inIOHIDElementRef
) );
139 IOHIDQueueRef tIOHIDQueueRef
= IOHIDDevice_GetQueue( inIOHIDDeviceRef
);
140 if ( !tIOHIDQueueRef
) { // if no queue create queue
141 result
= HIDCreateQueue( inIOHIDDeviceRef
);
142 if ( kIOReturnSuccess
== result
) {
143 tIOHIDQueueRef
= IOHIDDevice_GetQueue( inIOHIDDeviceRef
);
146 if ( tIOHIDQueueRef
) {
149 IOHIDQueueStop( tIOHIDQueueRef
);
152 if ( !IOHIDQueueContainsElement( tIOHIDQueueRef
, inIOHIDElementRef
) ) {
153 IOHIDQueueAddElement( tIOHIDQueueRef
, inIOHIDElementRef
);
157 IOHIDQueueStart( tIOHIDQueueRef
);
159 HIDReportError( "No queue for device passed to HIDQueueElement." );
160 if ( kIOReturnSuccess
== result
) {
161 result
= kIOReturnError
;
165 HIDReportError( "NULL element passed to HIDQueueElement." );
166 result
= kIOReturnBadArgument
;
169 HIDReportError( "NULL device passed to HIDQueueElement." );
170 result
= kIOReturnBadArgument
;
173 } /* HIDQueueElement */
174 // ---------------------------------
176 // adds all elements to queue, performing any device queue set up required
177 // queue is started and ready to return events on exit from this function
178 int HIDQueueDevice( IOHIDDeviceRef inIOHIDDeviceRef
)
180 IOReturn result
= kIOReturnSuccess
;
183 if ( !inIOHIDDeviceRef
) {
184 HIDReportError( "Device does not exist, cannot queue device." );
185 return kIOReturnBadArgument
;
188 if ( !inIOHIDDeviceRef
) { // must have interface
189 HIDReportError( "Device does not have hid device ref, cannot queue device." );
190 return kIOReturnError
;
193 IOHIDQueueRef tIOHIDQueueRef
= IOHIDDevice_GetQueue( inIOHIDDeviceRef
);
194 if ( !tIOHIDQueueRef
) { // if no queue create queue
195 result
= HIDCreateQueue( inIOHIDDeviceRef
);
196 if ( kIOReturnSuccess
== result
) {
197 tIOHIDQueueRef
= IOHIDDevice_GetQueue( inIOHIDDeviceRef
);
201 if ( ( kIOReturnSuccess
!= result
) || ( !tIOHIDQueueRef
) ) {
202 printf("queue NOT created successfully\n");
204 HIDReportErrorNum( "Could not queue device due to problem creating queue.", result
);
206 if ( kIOReturnSuccess
!= result
) {
209 return kIOReturnError
;
214 IOHIDQueueStop( tIOHIDQueueRef
);
217 IOHIDElementRef tIOHIDElementRef
= HIDGetFirstDeviceElement( inIOHIDDeviceRef
, kHIDElementTypeIO
);
218 while ( tIOHIDElementRef
) {
219 if ( !IOHIDQueueContainsElement( tIOHIDQueueRef
, tIOHIDElementRef
) ) {
220 IOHIDQueueAddElement( tIOHIDQueueRef
, tIOHIDElementRef
);
222 tIOHIDElementRef
= HIDGetNextDeviceElement( tIOHIDElementRef
, kHIDElementTypeIO
);
226 IOHIDQueueStart( tIOHIDQueueRef
);
229 } /* HIDQueueDevice */
231 // ---------------------------------
232 // removes element for queue, if last element in queue will release queue and closes device interface
233 int HIDDequeueElement( IOHIDDeviceRef inIOHIDDeviceRef
, IOHIDElementRef inIOHIDElementRef
)
235 IOReturn result
= kIOReturnSuccess
;
237 if ( inIOHIDDeviceRef
) {
238 assert( IOHIDDeviceGetTypeID() == CFGetTypeID( inIOHIDDeviceRef
) );
239 if ( inIOHIDElementRef
) {
240 assert( IOHIDElementGetTypeID() == CFGetTypeID( inIOHIDElementRef
) );
241 IOHIDQueueRef tIOHIDQueueRef
= IOHIDDevice_GetQueue( inIOHIDDeviceRef
);
242 if ( tIOHIDQueueRef
) {
244 IOHIDQueueStop( tIOHIDQueueRef
);
247 if ( IOHIDQueueContainsElement( tIOHIDQueueRef
, inIOHIDElementRef
) ) {
248 IOHIDQueueRemoveElement( tIOHIDQueueRef
, inIOHIDElementRef
);
251 // release device queue and close interface if queue empty
252 if ( HIDIsDeviceQueueEmpty( inIOHIDDeviceRef
) ) {
253 result
= HIDDisposeReleaseQueue( inIOHIDDeviceRef
);
255 if ( kIOReturnSuccess
!= result
) {
256 HIDReportErrorNum( "Failed to dispose and release queue.", result
);
258 } else { // not empty so restart queue
259 IOHIDQueueStart( tIOHIDQueueRef
);
262 HIDReportError( "No queue for device passed to HIDDequeueElement." );
263 if ( kIOReturnSuccess
== result
) {
264 result
= kIOReturnError
;
268 HIDReportError( "NULL element passed to HIDDequeueElement." );
269 result
= kIOReturnBadArgument
;
272 HIDReportError( "NULL device passed to HIDDequeueElement." );
273 result
= kIOReturnBadArgument
;
276 } /* HIDDequeueElement */
278 // ---------------------------------
279 // completely removes all elements from queue and releases queue and closes device interface
280 // does not release device interfaces, application must call ReleaseHIDDeviceList on exit
281 int HIDDequeueDevice( IOHIDDeviceRef inIOHIDDeviceRef
)
284 IOReturn result
= kIOReturnSuccess
;
287 if ( !inIOHIDDeviceRef
) {
288 HIDReportError( "Device does not exist, cannot queue device." );
289 return kIOReturnBadArgument
;
292 if ( !inIOHIDDeviceRef
) { // must have interface
293 HIDReportError( "Device does not have hid device ref, cannot queue device." );
294 return kIOReturnError
;
297 IOHIDQueueRef tIOHIDQueueRef
= IOHIDDevice_GetQueue( inIOHIDDeviceRef
);
299 if ( tIOHIDQueueRef
) {
300 // iterate through elements and if queued, remove
301 IOHIDElementRef tIOHIDElementRef
= HIDGetFirstDeviceElement( inIOHIDDeviceRef
, kHIDElementTypeIO
);
302 while ( tIOHIDElementRef
) {
304 if ( IOHIDQueueContainsElement( tIOHIDQueueRef
, tIOHIDElementRef
) ) {
305 IOHIDQueueRemoveElement( tIOHIDQueueRef
, tIOHIDElementRef
);
307 tIOHIDElementRef
= HIDGetNextDeviceElement( tIOHIDElementRef
, kHIDElementTypeIO
);
309 // ensure queue is disposed and released
310 result
= HIDDisposeReleaseQueue( inIOHIDDeviceRef
);
312 if ( kIOReturnSuccess
!= result
) {
313 HIDReportErrorNum( "Failed to dispose and release queue.", result
);
316 HIDReportError( "No queue for device passed to HIDDequeueElement." );
317 if ( kIOReturnSuccess
== result
) {
318 result
= kIOReturnError
;
322 } /* HIDDequeueDevice */
323 // ---------------------------------
325 // releases all device queues for quit or rebuild (must be called)
326 // does not release device interfaces, application must call ReleaseHIDDeviceList on exit
327 IOReturn
HIDReleaseAllDeviceQueues( void )
329 IOReturn result
= kIOReturnSuccess
;
330 IOHIDDeviceRef tIOHIDDeviceRef
= HIDGetFirstDevice();
331 while ( tIOHIDDeviceRef
) {
332 result
= HIDDequeueDevice( tIOHIDDeviceRef
);
334 if ( kIOReturnSuccess
!= result
) {
335 HIDReportErrorNum( "Could not dequeue device.", result
);
337 tIOHIDDeviceRef
= HIDGetNextDevice( tIOHIDDeviceRef
);
340 } /* HIDReleaseAllDeviceQueues */
342 // ---------------------------------
343 // Get the next event in the queue for a device
344 // elements or entire device should be queued prior to calling this with HIDQueueElement or HIDQueueDevice
345 // returns true if an event is avialable for the element and fills out *pHIDEvent structure, returns false otherwise
346 // Note: kIOReturnUnderrun returned from getNextEvent indicates an empty queue not an error condition
347 // Note: application should pass in a pointer to a IOHIDEventStruct cast to a void (for CFM compatibility)
348 unsigned char HIDGetEvent( IOHIDDeviceRef inIOHIDDeviceRef
, IOHIDValueRef
* pIOHIDValueRef
)
350 if ( inIOHIDDeviceRef
) {
351 IOHIDQueueRef tIOHIDQueueRef
= IOHIDDevice_GetQueue( inIOHIDDeviceRef
);
352 if ( tIOHIDQueueRef
) {
353 printf("There is a queue!\n");
354 if ( pIOHIDValueRef
) {
355 *pIOHIDValueRef
= IOHIDQueueCopyNextValueWithTimeout( tIOHIDQueueRef
, 0.0 );
357 if ( *pIOHIDValueRef
) {
362 printf("There is not a queue!\n");
363 HIDReportError( "Could not get HID event, hid queue reference does not exist." );
366 HIDReportError( "Could not get HID event, device does not exist." );
368 return false; // did not get event