Skip to content

Instantly share code, notes, and snippets.

@dweinstein
Created August 20, 2012 01:32
Show Gist options
  • Save dweinstein/3399105 to your computer and use it in GitHub Desktop.
Save dweinstein/3399105 to your computer and use it in GitHub Desktop.
main function for interacting with accessory protocol
//
// main.cpp
// AccessoryMode
//
// Created by David Weinstein on 07/30/2012.
// Copyright (c) 2012 David Weinstein. All rights reserved.
// Code based on documentation from apple: Working With USB Device Interfaces
// see https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/USBBook/index.html
//
// *Important* If your application is sandboxed, it must request the
// com.apple.security.device.usb entitlement in order to access USB devices.
//
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/usb/IOUSBLib.h>
#include "accessory.h"
#define DBGPRINT printf("DEBUG: \"%s\", line %d: ", __FILE__,__LINE__),printf
//
// vendor / product identifiers for target device
// can grab these from e.g., USB Prober.app
// the following is for the Samsung Galaxy Nexus Android device
//
#define kGoogleVendorID 0x18D1
#define kAccessoryProductID 0x2D00
#define kAccessoryADBProductID 0x2D01
//#define kAccessoryADBProductID 0x2D00
#define kNexusVendorID 0x04E8
#define kNexusProductID 0x6860
//#define kNexusProductID 0x685C
static IONotificationPortRef gNotifyPort;
static io_iterator_t gAddedIter;
static CFRunLoopRef gRunLoop;
int main(int argc, const char *argv[])
{
CFMutableDictionaryRef matchingDict, matchingDict2;
CFRunLoopSourceRef runLoopSource;
CFNumberRef numberRef;
kern_return_t kr;
long usbVendor = kNexusVendorID;
long usbProduct = kNexusProductID;
long googleUSBVendor = kGoogleVendorID;
long googleUSBProduct = kAccessoryADBProductID;
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.
matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
if (matchingDict == NULL) {
fprintf(stderr, "IOServiceMatching returned NULL.\n");
return -1;
}
matchingDict2 = IOServiceMatching(kIOUSBDeviceClassName);
if (matchingDict2 == NULL) {
fprintf(stderr, "IOServiceMatching returned NULL.\n");
return -1;
}
// We are interested in USB devices (as opposed to USB interfaces).
// 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 CFNumber for the accessory mode vendor and product IDs
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &googleUSBVendor);
CFDictionarySetValue(matchingDict2,
CFSTR(kUSBVendorID),
numberRef);
CFRelease(numberRef);
numberRef = NULL;
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &googleUSBProduct);
CFDictionarySetValue(matchingDict2,
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);
if (1) {
// 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);
}
if (1) {
// Now set up a notification to be called when a device is first matched by I/O Kit.
kr = IOServiceAddMatchingNotification(gNotifyPort, // notifyPort
kIOFirstMatchNotification, // notificationType
matchingDict2, // matching
AccessoryModeDeviceAdded, // callback
NULL, // refCon
&gAddedIter // notification
);
// Iterate once to get already-present devices and arm the notification
AccessoryModeDeviceAdded(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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment