// 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 */
// 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 HIDReportErrorNum( "Failed to create queue via create", result ); } else { result = kIOReturnSuccess; } } } else { HIDReportErrorNum( "HID device ref does not exist for queue creation", result ); } return result; } /* HIDCreateQueue */
// 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 */
// 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 */
// --------------------------------- // 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 */
// --------------------------------- // 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 */
// --------------------------------- // 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 */
// --------------------------------- // 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 */
// utility routine to dump device info void HIDDumpDeviceInfo(IOHIDDeviceRef inIOHIDDeviceRef) { char cstring[256]; printf("Device: %p = { ", inIOHIDDeviceRef); char manufacturer[256] = ""; // name of manufacturer CFStringRef tCFStringRef = IOHIDDevice_GetManufacturer(inIOHIDDeviceRef); if (tCFStringRef) { (void) CFStringGetCString(tCFStringRef, manufacturer, sizeof(manufacturer), kCFStringEncodingUTF8); } char product[256] = ""; // name of product tCFStringRef = IOHIDDevice_GetProduct(inIOHIDDeviceRef); if (tCFStringRef) { (void) CFStringGetCString(tCFStringRef, product, sizeof(product), kCFStringEncodingUTF8); } printf("%s - %s, ", manufacturer, product); long vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef); if (vendorID) { if ( HIDGetVendorNameFromVendorID(vendorID, cstring) ) { printf(" vendorID: 0x%04lX (\"%s\"), ", vendorID, cstring); } else { printf(" vendorID: 0x%04lX, ", vendorID); } } long productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef); if (productID) { if ( HIDGetProductNameFromVendorProductID(vendorID, productID, cstring) ) { printf(" productID: 0x%04lX (\"%s\"), ", productID, cstring); } else { printf(" productID: 0x%04lX, ", productID); } } uint32_t usagePage = IOHIDDevice_GetUsagePage(inIOHIDDeviceRef); uint32_t usage = IOHIDDevice_GetUsage(inIOHIDDeviceRef); if (!usagePage || !usage) { usagePage = IOHIDDevice_GetPrimaryUsagePage(inIOHIDDeviceRef); usage = IOHIDDevice_GetPrimaryUsage(inIOHIDDeviceRef); } printf("usage: 0x%04lX:0x%04lX, ", (long unsigned int) usagePage, (long unsigned int) usage); tCFStringRef = HIDCopyUsageName(usagePage, usage); if (tCFStringRef) { (void) CFStringGetCString(tCFStringRef, cstring, sizeof(cstring), kCFStringEncodingUTF8); printf("\"%s\", ", cstring); CFRelease(tCFStringRef); } tCFStringRef = IOHIDDevice_GetTransport(inIOHIDDeviceRef); if (tCFStringRef) { (void) CFStringGetCString(tCFStringRef, cstring, sizeof(cstring), kCFStringEncodingUTF8); printf("Transport: \"%s\", ", cstring); } long vendorIDSource = IOHIDDevice_GetVendorIDSource(inIOHIDDeviceRef); if (vendorIDSource) { printf("VendorIDSource: %ld, ", vendorIDSource); } long version = IOHIDDevice_GetVersionNumber(inIOHIDDeviceRef); if (version) { printf("version: %ld, ", version); } tCFStringRef = IOHIDDevice_GetSerialNumber(inIOHIDDeviceRef); if (tCFStringRef) { (void) CFStringGetCString(tCFStringRef, cstring, sizeof(cstring), kCFStringEncodingUTF8); printf("SerialNumber: \"%s\", ", cstring); } long country = IOHIDDevice_GetCountryCode(inIOHIDDeviceRef); if (country) { printf("CountryCode: %ld, ", country); } long locationID = IOHIDDevice_GetLocationID(inIOHIDDeviceRef); if (locationID) { printf("locationID: 0x%08lX, ", locationID); } #if false CFArrayRef pairs = IOHIDDevice_GetUsagePairs(inIOHIDDeviceRef); if (pairs) { CFIndex idx, cnt = CFArrayGetCount(pairs); for (idx = 0; idx < cnt; idx++) { const void * pair = CFArrayGetValueAtIndex(pairs, idx); CFShow(pair); } } #endif // if false long maxInputReportSize = IOHIDDevice_GetMaxInputReportSize(inIOHIDDeviceRef); if (maxInputReportSize) { printf("MaxInputReportSize: %ld, ", maxInputReportSize); } long maxOutputReportSize = IOHIDDevice_GetMaxOutputReportSize(inIOHIDDeviceRef); if (maxOutputReportSize) { printf("MaxOutputReportSize: %ld, ", maxOutputReportSize); } long maxFeatureReportSize = IOHIDDevice_GetMaxFeatureReportSize(inIOHIDDeviceRef); if (maxFeatureReportSize) { printf("MaxFeatureReportSize: %ld, ", maxOutputReportSize); } long reportInterval = IOHIDDevice_GetReportInterval(inIOHIDDeviceRef); if (reportInterval) { printf("ReportInterval: %ld, ", reportInterval); } IOHIDQueueRef queueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); if (queueRef) { printf("queue: %p, ", queueRef); } IOHIDTransactionRef transactionRef = IOHIDDevice_GetTransaction(inIOHIDDeviceRef); if (transactionRef) { printf("transaction: %p, ", transactionRef); } printf("}\n"); fflush(stdout); } // HIDDumpDeviceInfo