Sample Code
OSX Driver and Kext Samples/ USBPrivateDataSample/ USBPrivateDataSample/ USBPrivateDataSample.c/
/* File: USBPrivateDataSample.c Description: This sample demonstrates how to use IOKitLib and IOUSBLib to set up asynchronous callbacks when a USB device is attached to or removed from the system. It also shows how to associate arbitrary data with each device instance. Copyright: � Copyright 2001-2006 Apple Computer, Inc. All rights reserved. Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, 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 Computer, 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. Change History (most recent first): 1.2 10/04/2006 Updated to produce a universal binary. Now requires Xcode 2.2.1 or later to build. Modernized and incorporated bug fixes. 1.1 04/24/2002 Added comments, release of interface object, use of USB location ID 1.0 10/30/2001 New sample. */ #include <CoreFoundation/CoreFoundation.h> #include <IOKit/IOKitLib.h> #include <IOKit/IOMessage.h> #include <IOKit/IOCFPlugIn.h> #include <IOKit/usb/IOUSBLib.h> // Change these two constants to match your device's idVendor and idProduct. // Or, just pass your idVendor and idProduct as command line arguments when running this sample. #define kMyVendorID 1351 #define kMyProductID 8193 typedef struct MyPrivateData { io_object_t notification; IOUSBDeviceInterface **deviceInterface; CFStringRef deviceName; UInt32 locationID; } MyPrivateData; static IONotificationPortRef gNotifyPort; static io_iterator_t gAddedIter; static CFRunLoopRef gRunLoop; //================================================================================================ // // DeviceNotification // // This routine will get called whenever any kIOGeneralInterest notification happens. We are // interested in the kIOMessageServiceIsTerminated message so that's what we look for. Other // messages are defined in IOMessage.h. // //================================================================================================ void DeviceNotification(void *refCon, io_service_t service, natural_t messageType, void *messageArgument) { kern_return_t kr; MyPrivateData *privateDataRef = (MyPrivateData *) refCon; if (messageType == kIOMessageServiceIsTerminated) { fprintf(stderr, "Device removed.\n"); // Dump our private data to stderr just to see what it looks like. fprintf(stderr, "privateDataRef->deviceName: "); CFShow(privateDataRef->deviceName); fprintf(stderr, "privateDataRef->locationID: 0x%lx.\n\n", privateDataRef->locationID); // Free the data we're no longer using now that the device is going away CFRelease(privateDataRef->deviceName); if (privateDataRef->deviceInterface) { kr = (*privateDataRef->deviceInterface)->Release(privateDataRef->deviceInterface); } kr = IOObjectRelease(privateDataRef->notification); free(privateDataRef); } } //================================================================================================ // // DeviceAdded // // This routine is the callback for our IOServiceAddMatchingNotification. When we get called // we will look at all the devices that were added and we will: // // 1. Create some private data to relate to each device (in this case we use the service's name // and the location ID of the device // 2. Submit an IOServiceAddInterestNotification of type kIOGeneralInterest for this device, // using the refCon field to store a pointer to our private data. When we get called with // this interest notification, we can grab the refCon and access our private data. // //================================================================================================ void DeviceAdded(void *refCon, io_iterator_t iterator) { kern_return_t kr; io_service_t usbDevice; IOCFPlugInInterface **plugInInterface = NULL; SInt32 score; HRESULT res; while ((usbDevice = IOIteratorNext(iterator))) { io_name_t deviceName; CFStringRef deviceNameAsCFString; MyPrivateData *privateDataRef = NULL; UInt32 locationID; printf("Device added.\n"); // Add some app-specific information about this device. // Create a buffer to hold the data. privateDataRef = malloc(sizeof(MyPrivateData)); bzero(privateDataRef, sizeof(MyPrivateData)); // Get the USB device's name. kr = IORegistryEntryGetName(usbDevice, deviceName); if (KERN_SUCCESS != kr) { deviceName[0] = '\0'; } deviceNameAsCFString = CFStringCreateWithCString(kCFAllocatorDefault, deviceName, kCFStringEncodingASCII); // Dump our data to stderr just to see what it looks like. fprintf(stderr, "deviceName: "); CFShow(deviceNameAsCFString); // Save the device's name to our private data. privateDataRef->deviceName = deviceNameAsCFString; // Now, get the locationID of this device. In order to do this, we need to create an IOUSBDeviceInterface // for our device. This will create the necessary connections between our userland application and the // kernel object for the USB Device. kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); if ((kIOReturnSuccess != kr) || !plugInInterface) { fprintf(stderr, "IOCreatePlugInInterfaceForService returned 0x%08x.\n", kr); continue; } // Use the plugin interface to retrieve the device interface. res = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*) &privateDataRef->deviceInterface); // Now done with the plugin interface. (*plugInInterface)->Release(plugInInterface); if (res || privateDataRef->deviceInterface == NULL) { fprintf(stderr, "QueryInterface returned %d.\n", (int) res); continue; } // Now that we have the IOUSBDeviceInterface, we can call the routines in IOUSBLib.h. // In this case, fetch the locationID. The locationID uniquely identifies the device // and will remain the same, even across reboots, so long as the bus topology doesn't change. kr = (*privateDataRef->deviceInterface)->GetLocationID(privateDataRef->deviceInterface, &locationID); if (KERN_SUCCESS != kr) { fprintf(stderr, "GetLocationID returned 0x%08x.\n", kr); continue; } else { fprintf(stderr, "Location ID: 0x%lx\n\n", locationID); } privateDataRef->locationID = locationID; // Register for an interest notification of this device being removed. Use a reference to our // private data as the refCon which will be passed to the notification callback. kr = IOServiceAddInterestNotification(gNotifyPort, // notifyPort usbDevice, // service kIOGeneralInterest, // interestType DeviceNotification, // callback privateDataRef, // refCon &(privateDataRef->notification) // notification ); if (KERN_SUCCESS != kr) { printf("IOServiceAddInterestNotification returned 0x%08x.\n", kr); } // Done with this USB device; release the reference added by IOIteratorNext kr = IOObjectRelease(usbDevice); } } //================================================================================================ // // SignalHandler // // This routine will get called when we interrupt the program (usually with a Ctrl-C from the // command line). // //================================================================================================ void SignalHandler(int sigraised) { fprintf(stderr, "\nInterrupted.\n"); exit(0); } //================================================================================================ // main //================================================================================================ int main(int argc, const char *argv[]) { CFMutableDictionaryRef matchingDict; CFRunLoopSourceRef runLoopSource; CFNumberRef numberRef; kern_return_t kr; long usbVendor = kMyVendorID; long usbProduct = kMyProductID; sig_t oldHandler; // pick up command line arguments if (argc > 1) { usbVendor = atoi(argv[1]); } if (argc > 2) { usbProduct = atoi(argv[2]); } // Set up a signal handler so we can clean up when we're interrupted from the command line // Otherwise we stay in our run loop forever. oldHandler = signal(SIGINT, SignalHandler); if (oldHandler == SIG_ERR) { fprintf(stderr, "Could not establish new signal handler."); } fprintf(stderr, "Looking for devices matching vendor ID=%ld and product ID=%ld.\n", usbVendor, usbProduct); // Set up the matching criteria for the devices we're interested in. The matching criteria needs to follow // the same rules as kernel drivers: mainly it needs to follow the USB Common Class Specification, pp. 6-7. // See also Technical Q&A QA1076 "Tips on USB driver matching on Mac OS X" // <http://developer.apple.com/qa/qa2001/qa1076.html>. // One exception is that you can use the matching dictionary "as is", i.e. without adding any matching // criteria to it and it will match every IOUSBDevice in the system. IOServiceAddMatchingNotification will // consume this dictionary reference, so there is no need to release it later on. matchingDict = IOServiceMatching(kIOUSBDeviceClassName); // Interested in instances of class // IOUSBDevice and its subclasses if (matchingDict == NULL) { fprintf(stderr, "IOServiceMatching returned NULL.\n"); return -1; } // We are interested in all USB devices (as opposed to USB interfaces). The Common Class Specification // tells us that we need to specify the idVendor, idProduct, and bcdDevice fields, or, if we're not interested // in particular bcdDevices, just the idVendor and idProduct. Note that if we were trying to match an // IOUSBInterface, we would need to set more values in the matching dictionary (e.g. idVendor, idProduct, // bInterfaceNumber and bConfigurationValue. // Create a CFNumber for the idVendor and set the value in the dictionary numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbVendor); CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), numberRef); CFRelease(numberRef); // Create a CFNumber for the idProduct and set the value in the dictionary numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbProduct); CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), numberRef); CFRelease(numberRef); numberRef = NULL; // Create a notification port and add its run loop event source to our run loop // This is how async notifications get set up. gNotifyPort = IONotificationPortCreate(kIOMasterPortDefault); runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort); gRunLoop = CFRunLoopGetCurrent(); CFRunLoopAddSource(gRunLoop, runLoopSource, kCFRunLoopDefaultMode); // Now set up a notification to be called when a device is first matched by I/O Kit. kr = IOServiceAddMatchingNotification(gNotifyPort, // notifyPort kIOFirstMatchNotification, // notificationType matchingDict, // matching DeviceAdded, // callback NULL, // refCon &gAddedIter // notification ); // Iterate once to get already-present devices and arm the notification DeviceAdded(NULL, gAddedIter); // Start the run loop. Now we'll receive notifications. fprintf(stderr, "Starting run loop.\n\n"); CFRunLoopRun(); // We should never get here fprintf(stderr, "Unexpectedly back from CFRunLoopRun()!\n"); return 0; }
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials