static IOReturn HIDCreateOpenDeviceInterface (io_object_t hidDevice, recDevice *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); (*ppPlugInInterface)->Release (ppPlugInInterface); } else HIDReportErrorNum ("Failed to create **plugInInterface via IOCreatePlugInInterfaceForService.", result); } if (NULL != pDevice->interface) { result = (*(pDevice->interface))->open (pDevice->interface, 0); if (kIOReturnSuccess != result) HIDReportErrorNum ("Failed to open pDevice->interface via open.", result); else (*(pDevice->interface))->setRemovalCallback (pDevice->interface, HIDRemovalCallback, pDevice, pDevice); } return result; }
static IOReturn HIDCloseReleaseInterface(recDevice * pDevice) { IOReturn result = kIOReturnSuccess; if ((NULL != pDevice) && (NULL != pDevice->interface)) { /* close the interface */ result = (*(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 = (*(pDevice->interface))->Release(pDevice->interface); if (kIOReturnSuccess != result) HIDReportErrorNum("Failed to release IOHIDDeviceInterface.", result); pDevice->interface = NULL; if ( pDevice->portIterator ) { IOObjectRelease( pDevice->portIterator ); pDevice->portIterator = 0; } } return result; }
// 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 */
static recDevice * HIDDisposeDevice(recDevice ** ppDevice) { kern_return_t result = KERN_SUCCESS; recDevice *pDeviceNext = NULL; if (*ppDevice) { /* save next device prior to disposing of this device */ pDeviceNext = (*ppDevice)->pNext; /* free posible io_service_t */ if ((*ppDevice)->ffservice) { IOObjectRelease((*ppDevice)->ffservice); (*ppDevice)->ffservice = 0; } /* free element lists */ HIDDisposeElementList(&(*ppDevice)->firstAxis); HIDDisposeElementList(&(*ppDevice)->firstButton); HIDDisposeElementList(&(*ppDevice)->firstHat); result = HIDCloseReleaseInterface(*ppDevice); /* function sanity checks interface value (now application does not own device) */ if (kIOReturnSuccess != result) HIDReportErrorNum ("HIDCloseReleaseInterface failed when trying to dipose device.", result); DisposePtr((Ptr) * ppDevice); *ppDevice = NULL; } return pDeviceNext; }
IOReturn HIDCloseReleaseInterface (recDevice *pDevice) { IOReturn result = kIOReturnSuccess; if ((NULL != pDevice) && (NULL != pDevice->interface)) { // close the interface result = (*(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 = (*(pDevice->interface))->Release (pDevice->interface); if (kIOReturnSuccess != result) HIDReportErrorNum ("Failed to release IOHIDDeviceInterface.", result); pDevice->interface = NULL; } 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; IOHIDDeviceRef tIOHIDDeviceRef = HIDGetFirstDevice(); while ( tIOHIDDeviceRef ) { result = HIDDequeueDevice( tIOHIDDeviceRef ); if ( kIOReturnSuccess != result ) { HIDReportErrorNum( "Could not dequeue device.", result ); } tIOHIDDeviceRef = HIDGetNextDevice( tIOHIDDeviceRef ); } return result; } /* HIDReleaseAllDeviceQueues */
// 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 */
static IOReturn HIDCreateOpenDeviceInterface(io_object_t hidDevice, recDevice * 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); (*ppPlugInInterface)->Release(ppPlugInInterface); } else HIDReportErrorNum ("Failed to create **plugInInterface via IOCreatePlugInInterfaceForService.", result); } if (NULL != pDevice->interface) { result = (*(pDevice->interface))->open(pDevice->interface, 0); if (kIOReturnSuccess != result) HIDReportErrorNum ("Failed to open pDevice->interface via open.", result); else { pDevice->portIterator = 0; // It's okay if this fails, we have another detection method below (*(pDevice->interface))->setRemovalCallback(pDevice->interface, HIDRemovalCallback, pDevice, pDevice); /* now connect notification for new devices */ pDevice->notificationPort = IONotificationPortCreate(kIOMasterPortDefault); CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(pDevice->notificationPort), kCFRunLoopDefaultMode); // Register for notifications when a serial port is added to the system result = IOServiceAddInterestNotification(pDevice->notificationPort, hidDevice, kIOGeneralInterest, JoystickDeviceWasRemovedCallback, pDevice, &pDevice->portIterator); if (kIOReturnSuccess != result) { HIDReportErrorNum ("Failed to register for removal callback.", result); } } } return result; }