Skip to content

Instantly share code, notes, and snippets.

@hiszpanski
Created August 2, 2014 10:45
Show Gist options
  • Select an option

  • Save hiszpanski/0ebc53ab4989d904a04c to your computer and use it in GitHub Desktop.

Select an option

Save hiszpanski/0ebc53ab4989d904a04c to your computer and use it in GitHub Desktop.
Prints vendor and product ids of USB devices as they are added
//
// main.c
// usblog
//
#include <assert.h>
#include <stdio.h>
#import <IOKit/usb/IOUSBLib.h>
// @brief (callback) Called when USB device is added
static void usbDeviceEvent(void *refcon, io_iterator_t iterator)
{
io_service_t dev;
kern_return_t kr;
while (dev = IOIteratorNext(iterator), dev) {
HRESULT res;
SInt32 score;
UInt16 pid, vid;
IOCFPlugInInterface **plugInInterface = NULL;
IOUSBDeviceInterface **deviceInterface = NULL;
kr = IOCreatePlugInInterfaceForService(dev, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score);
assert(kr == kIOReturnSuccess);
assert(plugInInterface);
res = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*) &deviceInterface);
(*plugInInterface)->Release(plugInInterface);
assert(!res);
assert(deviceInterface);
kr = (*deviceInterface)->GetDeviceVendor(deviceInterface, &vid);
assert(kr == kIOReturnSuccess);
kr = (*deviceInterface)->GetDeviceProduct(deviceInterface, &pid);
assert(kr == kIOReturnSuccess);
fprintf(stderr, "%s: vid = 0x%04x pid = 0x%04x\n", (const char *)refcon, vid, pid);
kr = IOObjectRelease(dev);
assert(kr == kIOReturnSuccess);
}
}
// @brief Main loop
int main(int argc, const char * argv[])
{
io_iterator_t deviceAddedIterator;
// io_iterator_t deviceRemovedIterator;
io_service_t device;
kern_return_t kr;
// Create port for receiving I/O Kit notifications
IONotificationPortRef notifyPort = IONotificationPortCreate(kIOMasterPortDefault);
assert(notifyPort);
// Get runloop source for port
CFRunLoopSourceRef runLoopSource = IONotificationPortGetRunLoopSource(notifyPort);
// Add source to current runloop
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
// Matching dictionary for any USB device
CFDictionaryRef matching = IOServiceMatching(kIOUSBDeviceClassName);
// Matching dictionary used twice, once for addition and once for removal, so increase reference count
matching = (CFDictionaryRef)CFRetain(matching);
// Add matching notifications
kr = IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, matching, usbDeviceEvent, "added", &deviceAddedIterator);
assert(kr == kIOReturnSuccess);
// kr = IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, matching, usbDeviceEvent, "removed", &deviceRemovedIterator);
// assert(kr == kIOReturnSuccess);
// Arm notifications and handle existing devices
do {
usbDeviceEvent("added", deviceAddedIterator);
} while ((device = IOIteratorNext(deviceAddedIterator)));
// do {
// usbDeviceEvent("removed", deviceRemovedIterator);
// } while ((device = IOIteratorNext(deviceRemovedIterator)));
// Run
CFRunLoopRun();
return 0;
}
@PurpleElephantSoftware
Copy link

Beautiful job and exactly what I needed. I am working on an open source serial driver with extra features for interfacing to Vintage Atari 8-bit Computers via SIO2PC. Sadly the VID/PIDs are all over the place.

Does this code have a license?

Thanks!

@hiszpanski
Copy link
Author

Thanks! Hereby licensing under LGPL. Use it as you wish.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment