|
|
@@ -0,0 +1,829 @@
|
|
|
+#include "USBMicroX.h"
|
|
|
+#define UNLESS(S) if(!(S))
|
|
|
+
|
|
|
+#define USBMX_ID_PRODUCT 0x01A5
|
|
|
+#define USBMX_ID_VENDOR 0x0DE7
|
|
|
+
|
|
|
+static long dict_get_long(CFDictionaryRef properties, CFStringRef key)
|
|
|
+{
|
|
|
+ long number;
|
|
|
+ CFTypeRef value = CFDictionaryGetValue(properties, key);
|
|
|
+ if (!value) return 0;
|
|
|
+ CFTypeID type = CFGetTypeID(value);
|
|
|
+ if (type != CFNumberGetTypeID()) return 0 ;
|
|
|
+ CFNumberGetValue((CFNumberRef)value, kCFNumberLongType, (void *)&number);
|
|
|
+ return number;
|
|
|
+}
|
|
|
+
|
|
|
+static char* dict_get_string(CFDictionaryRef properties, CFStringRef key, CFStringEncoding encoding)
|
|
|
+{
|
|
|
+ static char cstring[512];
|
|
|
+ CFTypeRef value = CFDictionaryGetValue(properties, key);
|
|
|
+ if (!value) return "";
|
|
|
+ CFTypeID type = CFGetTypeID(value) ;
|
|
|
+ if (type != CFStringGetTypeID()) return "";
|
|
|
+ CFStringGetCString((CFStringRef)value, cstring, sizeof(cstring), encoding);
|
|
|
+ return cstring; // WARNING: be sure to copy string after return
|
|
|
+}
|
|
|
+
|
|
|
+static void nsp(int L) {
|
|
|
+ int i = 0;
|
|
|
+ while(i++ < L) printf(" ");
|
|
|
+}
|
|
|
+
|
|
|
+static void cftype_dump(CFTypeRef o, int L);
|
|
|
+
|
|
|
+static void cftype_dump_arrayapply(const void *value, void *context) {
|
|
|
+ int L = (int)context;
|
|
|
+ nsp(L); printf("0x%08x\n", value);
|
|
|
+ cftype_dump((CFTypeRef)value, L+1);
|
|
|
+}
|
|
|
+
|
|
|
+static void cftype_dump_dictapply (const void *key, const void *value, void *context) {
|
|
|
+ int L = (int)context;
|
|
|
+ nsp(L); printf("\"%s\" => 0x%08x\n",
|
|
|
+ CFStringGetCStringPtr(key, CFStringGetSystemEncoding()), value);
|
|
|
+ cftype_dump((CFTypeRef)value, L+1);
|
|
|
+}
|
|
|
+
|
|
|
+static void cftype_dump(CFTypeRef o, int L)
|
|
|
+{
|
|
|
+ if(CFGetTypeID(o) == CFArrayGetTypeID()) {
|
|
|
+ nsp(L); printf("[\n");
|
|
|
+ CFArrayApplyFunction(
|
|
|
+ o,
|
|
|
+ CFRangeMake(0, CFArrayGetCount(o)),
|
|
|
+ cftype_dump_arrayapply,
|
|
|
+ (void*)(L+1));
|
|
|
+ nsp(L); printf("]\n");
|
|
|
+ } else if(CFGetTypeID(o) == CFDictionaryGetTypeID()) {
|
|
|
+ nsp(L); printf("{\n");
|
|
|
+ CFDictionaryApplyFunction(
|
|
|
+ o,
|
|
|
+ cftype_dump_dictapply,
|
|
|
+ (void*)(L+1));
|
|
|
+ nsp(L); printf("}\n");
|
|
|
+ } else if(CFGetTypeID(o) == CFNumberGetTypeID()) {
|
|
|
+ long number;
|
|
|
+ CFNumberGetValue((CFNumberRef)o, kCFNumberLongType, (void*)&number);
|
|
|
+ nsp(L); printf("number: 0x%08x\n", number);
|
|
|
+ } else if(CFGetTypeID(o) == CFStringGetTypeID()) {
|
|
|
+ const char *s = CFStringGetCStringPtr(o, CFStringGetSystemEncoding());
|
|
|
+ nsp(L); printf("string: \"%s\"\n", s);
|
|
|
+ } else if(CFGetTypeID(o) == CFBooleanGetTypeID()) {
|
|
|
+ nsp(L); printf("boolean: %s\n", CFBooleanGetValue(o)?"TRUE":"FALSE");
|
|
|
+ } else {
|
|
|
+ nsp(L); printf("??? unknown type\n");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_DeviceAddedHandler(
|
|
|
+ USBmX_ContextRef ctx,
|
|
|
+ USBmX_DeviceAddedProc proc,
|
|
|
+ void *cookie)
|
|
|
+{
|
|
|
+ ctx->deviceAdded = proc;
|
|
|
+ ctx->deviceAdded_cookie = cookie;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_DeviceRemovedHandler(
|
|
|
+ USBmX_ContextRef ctx,
|
|
|
+ USBmX_DeviceRemovedProc proc,
|
|
|
+ void *cookie)
|
|
|
+{
|
|
|
+ ctx->deviceRemoved = proc;
|
|
|
+ ctx->deviceRemoved_cookie = cookie;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_DeviceInfo(USBmX_DeviceRef dev)
|
|
|
+{
|
|
|
+ if(!dev) goto err;
|
|
|
+ cftype_dump(dev->properties, 0);
|
|
|
+ return 0;
|
|
|
+err:
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+static void DumpBuffer(const u_char buf[], unsigned int buf_size)
|
|
|
+{
|
|
|
+ const u_char *p = buf;
|
|
|
+ while(buf_size--) printf("0x%02x ", *p++);
|
|
|
+ printf("\n");
|
|
|
+}
|
|
|
+
|
|
|
+void USBmX_DumpCommand(u_char buf[])
|
|
|
+{
|
|
|
+ DumpBuffer(buf, 8);
|
|
|
+}
|
|
|
+
|
|
|
+void DeviceAddedHandler(void *refCon, io_iterator_t iterator)
|
|
|
+{
|
|
|
+ #if USBMX_DEBUG_LOG
|
|
|
+ USBMX_LOG("Device added notification");
|
|
|
+ #endif
|
|
|
+ io_object_t o;
|
|
|
+ USBmX_ContextRef ctx;
|
|
|
+ // Must iterate in order to re-arm notification
|
|
|
+ while(o = IOIteratorNext(iterator)) {
|
|
|
+ IOObjectRelease(o);
|
|
|
+ }
|
|
|
+ ctx = (USBmX_ContextRef)refCon;
|
|
|
+ #if USBMX_DEBUG_LOG
|
|
|
+ USBMX_LOG("ctx = %x", ctx);
|
|
|
+ #endif
|
|
|
+ USBmX_ScanForDevices(ctx);
|
|
|
+}
|
|
|
+
|
|
|
+void DestroyDeviceRef(USBmX_DeviceRef d)
|
|
|
+{
|
|
|
+ #if USBMX_DEBUG_LOG
|
|
|
+ USBMX_LOG("Destroying: %x %x %x %x", d->properties, d->serialNumber, d->interface, d);
|
|
|
+ #endif
|
|
|
+ CFRelease(d->properties);
|
|
|
+ free((void *)d->serialNumber);
|
|
|
+ free((void *)d->deviceName);
|
|
|
+ free((void *)d->manufacturer);
|
|
|
+ (*d->interface)->close(d->interface);
|
|
|
+ free(d);
|
|
|
+}
|
|
|
+
|
|
|
+void DeviceRemovedHandler(void *target, IOReturn result, void *refcon, void *sender)
|
|
|
+{
|
|
|
+ USBmX_DeviceRef d = (USBmX_DeviceRef)refcon;
|
|
|
+ USBmX_ContextRef ctx = d->ctx;
|
|
|
+ #if USBMX_DEBUG_LOG
|
|
|
+ USBMX_LOG("Device Removed (# %s)", d->serialNumber);
|
|
|
+ #endif
|
|
|
+
|
|
|
+ USBmX_DeviceRef p = ctx->deviceList;
|
|
|
+ USBmX_DeviceRef pl = NULL;
|
|
|
+ while(p) {
|
|
|
+ if(p == d)
|
|
|
+ {
|
|
|
+ if(pl == NULL) ctx->deviceList = d->next;
|
|
|
+ else pl->next = d->next;
|
|
|
+ ////////////////////////////
|
|
|
+ //USBMX_LOG("NEED TO CALL DEVICE REMOVED CALLBACK");
|
|
|
+ if(ctx->deviceRemoved)
|
|
|
+ {
|
|
|
+ (*ctx->deviceRemoved)(d, ctx->deviceRemoved_cookie);
|
|
|
+ }
|
|
|
+ ////////////////////////////
|
|
|
+ DestroyDeviceRef(d);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ pl = p;
|
|
|
+ p = p->next;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void InterruptReportHandler(
|
|
|
+ void *target,
|
|
|
+ IOReturn result,
|
|
|
+ void *refcon,
|
|
|
+ void *sender,
|
|
|
+ UInt32 bufferSize)
|
|
|
+{
|
|
|
+ USBmX_DeviceRef d = (USBmX_DeviceRef)target;
|
|
|
+
|
|
|
+ #if USBMX_DEBUG_LOG
|
|
|
+ printf("Response: ");
|
|
|
+ DumpBuffer(d->response_buffer, bufferSize);
|
|
|
+ #endif
|
|
|
+
|
|
|
+ d->response_ready = 1;
|
|
|
+}
|
|
|
+
|
|
|
+static int SetReport(USBmX_DeviceRef d, const u_char *buf, unsigned int buf_size)
|
|
|
+{
|
|
|
+ #if USBMX_DEBUG_LOG
|
|
|
+ printf("Report: "); DumpBuffer(buf, buf_size);
|
|
|
+ #endif
|
|
|
+ d->response_ready = 0;
|
|
|
+ IOReturn rc = (*d->interface)->setReport(
|
|
|
+ d->interface,
|
|
|
+ kIOHIDReportTypeFeature,
|
|
|
+ 0, //reportID
|
|
|
+ (void *)buf,
|
|
|
+ buf_size,
|
|
|
+ 1000, //timeout
|
|
|
+ NULL,
|
|
|
+ NULL,
|
|
|
+ NULL
|
|
|
+ );
|
|
|
+ while(!d->response_ready) {
|
|
|
+ SInt32 r = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, false);
|
|
|
+ #if USBMX_DEBUG_LOG
|
|
|
+ printf("wait r=%x\n", r);
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+ if(rc != kIOReturnSuccess) {
|
|
|
+ USBMX_LOG("SetReport: (*interface)->setReport() Error %x", rc);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_DeviceCount(USBmX_ContextRef ctx)
|
|
|
+{
|
|
|
+ if(!ctx) return 0;
|
|
|
+ USBmX_DeviceRef d = ctx->deviceList;
|
|
|
+ int count = 0;
|
|
|
+ while(d) {
|
|
|
+ ++count;
|
|
|
+ d = d->next;
|
|
|
+ }
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+USBmX_DeviceRef USBmX_DefaultDevice(USBmX_ContextRef ctx)
|
|
|
+{
|
|
|
+ if(ctx) return ctx->deviceList;
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+USBmX_DeviceRef USBmX_DeviceWithSerial(USBmX_ContextRef ctx, const char *serial)
|
|
|
+{
|
|
|
+ if(!ctx || !serial) return NULL;
|
|
|
+ USBmX_DeviceRef dev = ctx->deviceList;
|
|
|
+ #if USBMX_DEBUG_LOG
|
|
|
+ USBMX_LOG("Searching for device...");
|
|
|
+ #endif
|
|
|
+ while(dev) {
|
|
|
+ if(!strcmp(serial, dev->serialNumber))
|
|
|
+ {
|
|
|
+ #if USBMX_DEBUG_LOG
|
|
|
+ USBMX_LOG("Device found! %x (# %s)", dev, dev->serialNumber);
|
|
|
+ #endif
|
|
|
+ return dev;
|
|
|
+ }
|
|
|
+ dev = dev->next;
|
|
|
+ }
|
|
|
+ #if USBMX_DEBUG_LOG
|
|
|
+ USBMX_LOG("Device not found");
|
|
|
+ #endif
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_RawCommand(USBmX_DeviceRef dev,
|
|
|
+ const u_char command[8],
|
|
|
+ u_char response[8])
|
|
|
+{
|
|
|
+ if(!dev) goto err;
|
|
|
+ if(SetReport(dev, command, 8) < 0) goto err;
|
|
|
+ if(response) {
|
|
|
+ memcpy(response, dev->response_buffer, 8);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+err:
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+static int CreateDeviceRef(USBmX_ContextRef ctx, io_object_t dev, USBmX_DeviceRef *dev_out)
|
|
|
+{
|
|
|
+ IOReturn rc;
|
|
|
+ kern_return_t result;
|
|
|
+
|
|
|
+ USBmX_DeviceRef dr = USBMX_ALLOC(USBmX_Device);
|
|
|
+ dr->next = NULL;
|
|
|
+ dr->ctx = ctx;
|
|
|
+ dr->userData = NULL;
|
|
|
+
|
|
|
+ // Get device properties
|
|
|
+ result = IORegistryEntryCreateCFProperties(
|
|
|
+ dev, &dr->properties,
|
|
|
+ kCFAllocatorDefault, kNilOptions);
|
|
|
+ if(result != KERN_SUCCESS || !dr->properties) {
|
|
|
+ USBMX_LOG("IORegistryEntryCreateCFProperties Error %x", result);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ dr->serialNumber = strdup(
|
|
|
+ dict_get_string(
|
|
|
+ dr->properties,
|
|
|
+ CFSTR(kIOHIDSerialNumberKey),
|
|
|
+ CFStringGetSystemEncoding()));
|
|
|
+ dr->deviceName = strdup(
|
|
|
+ dict_get_string(
|
|
|
+ dr->properties,
|
|
|
+ CFSTR(kIOHIDProductKey),
|
|
|
+ CFStringGetSystemEncoding()));
|
|
|
+ dr->manufacturer = strdup(
|
|
|
+ dict_get_string(
|
|
|
+ dr->properties,
|
|
|
+ CFSTR(kIOHIDManufacturerKey),
|
|
|
+ CFStringGetSystemEncoding()));
|
|
|
+
|
|
|
+ // Add device to head of list if we don't already have it
|
|
|
+ if(USBmX_DeviceWithSerial(ctx, dr->serialNumber) == NULL)
|
|
|
+ {
|
|
|
+ #if USBMX_DEBUG_LOG
|
|
|
+ USBMX_LOG("Adding device");
|
|
|
+ #endif
|
|
|
+ dr->next = ctx->deviceList;
|
|
|
+ ctx->deviceList = dr;
|
|
|
+ } else {
|
|
|
+ #if USBMX_DEBUG_LOG
|
|
|
+ USBMX_LOG("Already have device");
|
|
|
+ #endif
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ #if USBMX_DEBUG_LOG
|
|
|
+ USBMX_LOG("Found Device (# %s)", dr->serialNumber);
|
|
|
+ USBMX_LOG("kIOHIDManufacturerKey: \"%s\"",
|
|
|
+ dict_get_string(dr->properties,
|
|
|
+ CFSTR(kIOHIDManufacturerKey), CFStringGetSystemEncoding()));
|
|
|
+ #endif
|
|
|
+
|
|
|
+ { // Set up the device
|
|
|
+ SInt32 score = 0;
|
|
|
+ IOCFPlugInInterface **plugIn;
|
|
|
+
|
|
|
+ if((rc = IOCreatePlugInInterfaceForService(
|
|
|
+ dev,
|
|
|
+ kIOHIDDeviceUserClientTypeID,
|
|
|
+ kIOCFPlugInInterfaceID,
|
|
|
+ &plugIn, &score)) != kIOReturnSuccess)
|
|
|
+ {
|
|
|
+ USBMX_LOG("IOCreatePlugInInterfaceForService Error %x", rc);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Grab interface
|
|
|
+ IOHIDDeviceInterface **interface;
|
|
|
+ HRESULT prc;
|
|
|
+ prc = (*plugIn)->QueryInterface(plugIn,
|
|
|
+ CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
|
|
|
+ (LPVOID)&interface);
|
|
|
+ (*plugIn)->Release(plugIn);
|
|
|
+ if(prc != S_OK) {
|
|
|
+ USBMX_LOG("QueryInterface Error %x", prc);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ dr->interface = interface;
|
|
|
+
|
|
|
+ // Set up removal callback
|
|
|
+ if((rc = (*interface)->setRemovalCallback(interface,
|
|
|
+ DeviceRemovedHandler, NULL, (void *)dr)) != kIOReturnSuccess)
|
|
|
+ {
|
|
|
+ USBMX_LOG("(*interface)->setRemovalCallback() Error %x", rc);
|
|
|
+ goto err1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if((rc = (*interface)->open(interface, 0)) != kIOReturnSuccess)
|
|
|
+ {
|
|
|
+ USBMX_LOG("(*interface)->open() Error %x", rc);
|
|
|
+ goto err1;
|
|
|
+ }
|
|
|
+
|
|
|
+ mach_port_t async_port;
|
|
|
+ if((rc = (*interface)->createAsyncPort(interface, &async_port)) != kIOReturnSuccess)
|
|
|
+ {
|
|
|
+ USBMX_LOG("(*interface)->createAsyncPort() Error %x", rc);
|
|
|
+ goto err1;
|
|
|
+ }
|
|
|
+
|
|
|
+ CFRunLoopSourceRef rl_source;
|
|
|
+ if((rc = (*interface)->createAsyncEventSource(interface, &rl_source)) != kIOReturnSuccess)
|
|
|
+ {
|
|
|
+ USBMX_LOG("(*interface)->createAsyncEventSource() Error %x", rc);
|
|
|
+ goto err1;
|
|
|
+ }
|
|
|
+
|
|
|
+ CFRunLoopAddSource(
|
|
|
+ CFRunLoopGetCurrent(),
|
|
|
+ rl_source,
|
|
|
+ kCFRunLoopDefaultMode);
|
|
|
+ if((rc = ((IOHIDDeviceInterface122*)*interface)->setInterruptReportHandlerCallback(
|
|
|
+ interface,
|
|
|
+ dr->response_buffer,
|
|
|
+ USBMX_RESPONSE_BUFFER_SIZE,
|
|
|
+ InterruptReportHandler,
|
|
|
+ (void *)dr,
|
|
|
+ NULL)) != kIOReturnSuccess)
|
|
|
+ {
|
|
|
+ USBMX_LOG("(*interface)->setInterruptReportHandlerCallback() Error %x", rc);
|
|
|
+ goto err1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ *dev_out = dr;
|
|
|
+ ////////////////
|
|
|
+ //USBMX_LOG("NEED TO CALL DEVICE ADDED CALLBACK");
|
|
|
+ if(ctx->deviceAdded)
|
|
|
+ {
|
|
|
+ (*ctx->deviceAdded)(dr, ctx->deviceAdded_cookie);
|
|
|
+ }
|
|
|
+ ////////////////
|
|
|
+ return 0;
|
|
|
+err1:
|
|
|
+ (*dr->interface)->Release(dr->interface);
|
|
|
+err:
|
|
|
+ IOObjectRelease(dev);
|
|
|
+ free(dr);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_ScanForDevices(USBmX_ContextRef ctx)
|
|
|
+{
|
|
|
+ IOReturn rc;
|
|
|
+ io_iterator_t iterator;
|
|
|
+ io_object_t d;
|
|
|
+ int n_devices = 0;
|
|
|
+
|
|
|
+ CFRetain(ctx->matchingDict);
|
|
|
+
|
|
|
+ // Narrow it down to devices matching vendor and product IDs
|
|
|
+ if(rc = IOServiceGetMatchingServices(
|
|
|
+ kIOMasterPortDefault,
|
|
|
+ ctx->matchingDict,
|
|
|
+ &iterator) != kIOReturnSuccess)
|
|
|
+ {
|
|
|
+ USBMX_LOG("IOServiceGetMatchingServices Error %x", rc);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Iterate over each found device
|
|
|
+ while(d = IOIteratorNext(iterator))
|
|
|
+ {
|
|
|
+ USBmX_DeviceRef dev;
|
|
|
+ if(CreateDeviceRef(ctx, d, &dev) < 0) goto err1;
|
|
|
+ n_devices++;
|
|
|
+ }
|
|
|
+
|
|
|
+ IOObjectRelease(iterator);
|
|
|
+
|
|
|
+noerr:
|
|
|
+ return n_devices;
|
|
|
+err1:
|
|
|
+ IOObjectRelease(iterator);
|
|
|
+err:
|
|
|
+ USBMX_LOG("USBmX_FindDevices Failed!");
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+USBmX_ContextRef USBmX_Create(void)
|
|
|
+{
|
|
|
+ USBmX_ContextRef ctx = NULL;
|
|
|
+ if(ctx = USBMX_ALLOC(USBmX_Context))
|
|
|
+ {
|
|
|
+ ctx->deviceList = NULL;
|
|
|
+ ctx->matchingDict = NULL;
|
|
|
+ ctx->deviceAdded = NULL;
|
|
|
+ ctx->deviceRemoved = NULL;
|
|
|
+ ctx->deviceAdded_cookie = NULL;
|
|
|
+ ctx->deviceRemoved_cookie = NULL;
|
|
|
+ }
|
|
|
+ return ctx;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_Begin(USBmX_ContextRef ctx)
|
|
|
+{
|
|
|
+// USBmX_ContextRef ctx = USBMX_ALLOC(USBmX_Context);
|
|
|
+// ctx->deviceList = NULL;
|
|
|
+// ctx->matchingDict = NULL;
|
|
|
+ if(!ctx) return -1;
|
|
|
+
|
|
|
+ // Grab root IOKit HID services
|
|
|
+ UNLESS(ctx->matchingDict = IOServiceMatching(kIOHIDDeviceKey))
|
|
|
+ {
|
|
|
+ USBMX_LOG("IOServiceMatching(kIOHIDDeviceKey) Error");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ { // Add product and vendor keys to matchingDict
|
|
|
+ SInt32 product = USBMX_ID_PRODUCT;
|
|
|
+ SInt32 vendor = USBMX_ID_VENDOR;
|
|
|
+ CFNumberRef num = NULL;
|
|
|
+ #define USBMX_DNA(NAME, VALUE) \
|
|
|
+ UNLESS(num = CFNumberCreate( \
|
|
|
+ kCFAllocatorDefault, \
|
|
|
+ kCFNumberSInt32Type, \
|
|
|
+ & VALUE )) { \
|
|
|
+ USBMX_LOG("CFNumber Error"); \
|
|
|
+ goto err; \
|
|
|
+ } \
|
|
|
+ CFDictionaryAddValue(ctx->matchingDict, CFSTR(NAME), num); \
|
|
|
+ CFRelease(num);
|
|
|
+ USBMX_DNA(kIOHIDVendorIDKey, vendor)
|
|
|
+ USBMX_DNA(kIOHIDProductIDKey, product)
|
|
|
+ #undef USBMX_DNA
|
|
|
+ }
|
|
|
+
|
|
|
+ { // Set up onPlug handler
|
|
|
+ io_iterator_t plugIterator;
|
|
|
+ IONotificationPortRef plugPort;
|
|
|
+ //CFRunLoopSourceRef runLoopSource;
|
|
|
+
|
|
|
+ //CFMutableDictionaryRef hd = IOServiceMatching(kIOHIDDeviceKey);
|
|
|
+ CFRetain(ctx->matchingDict);
|
|
|
+
|
|
|
+ UNLESS(plugPort = IONotificationPortCreate(kIOMasterPortDefault))
|
|
|
+ {
|
|
|
+ USBMX_LOG("IONotificationPortCreate error");
|
|
|
+ }
|
|
|
+
|
|
|
+ CFRunLoopAddSource(
|
|
|
+ CFRunLoopGetCurrent(),
|
|
|
+ IONotificationPortGetRunLoopSource(plugPort),
|
|
|
+ kCFRunLoopDefaultMode);
|
|
|
+ if(IOServiceAddMatchingNotification(
|
|
|
+ plugPort,
|
|
|
+ kIOFirstMatchNotification,
|
|
|
+ ctx->matchingDict,
|
|
|
+ DeviceAddedHandler,
|
|
|
+ (void *)ctx,
|
|
|
+ &plugIterator) != KERN_SUCCESS)
|
|
|
+ {
|
|
|
+ USBMX_LOG("IOServiceAddMatchingNotification error");
|
|
|
+ }
|
|
|
+ DeviceAddedHandler((void *)ctx, plugIterator);
|
|
|
+ }
|
|
|
+
|
|
|
+ //if(USBmX_ScanForDevices(ctx) < 0) goto err;
|
|
|
+noerr:
|
|
|
+ //return ctx;
|
|
|
+ return 0;
|
|
|
+err:
|
|
|
+ USBMX_LOG("USBmX_Init Failed!");
|
|
|
+ free(ctx);
|
|
|
+ //return NULL;
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_Destroy(USBmX_ContextRef ctx)
|
|
|
+{
|
|
|
+ if(!ctx) return -1;
|
|
|
+ free(ctx);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_InitPorts(USBmX_DeviceRef dev)
|
|
|
+{
|
|
|
+ int r;
|
|
|
+ u_char res[8];
|
|
|
+ static const u_char cmd[8] = {
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00
|
|
|
+ };
|
|
|
+ r = USBmX_RawCommand(dev, cmd, res);
|
|
|
+ if(r < 0) return r;
|
|
|
+ if(res[0] != cmd[0]) return -1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_WriteA(USBmX_DeviceRef dev, u_char value)
|
|
|
+{
|
|
|
+ int r;
|
|
|
+ u_char res[8];
|
|
|
+ u_char cmd[8] = {
|
|
|
+ 0x01,
|
|
|
+ value,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00
|
|
|
+ };
|
|
|
+ r = USBmX_RawCommand(dev, cmd, res);
|
|
|
+ if(r < 0) return r;
|
|
|
+ if(res[0] != cmd[0]) return -1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_WriteB(USBmX_DeviceRef dev, u_char value)
|
|
|
+{
|
|
|
+ int r;
|
|
|
+ u_char res[8];
|
|
|
+ u_char cmd[8] = {
|
|
|
+ 0x02,
|
|
|
+ value,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00
|
|
|
+ };
|
|
|
+ r = USBmX_RawCommand(dev, cmd, res);
|
|
|
+ if(r < 0) return r;
|
|
|
+ if(res[0] != cmd[0]) return -1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_WriteABit(USBmX_DeviceRef dev, u_char v_and, u_char v_or)
|
|
|
+{
|
|
|
+ int r;
|
|
|
+ u_char res[8];
|
|
|
+ u_char cmd[8] = {
|
|
|
+ 0x03,
|
|
|
+ v_and,
|
|
|
+ v_or,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00
|
|
|
+ };
|
|
|
+ r = USBmX_RawCommand(dev, cmd, res);
|
|
|
+ if(r < 0) return r;
|
|
|
+ if(res[0] != cmd[0]) return -1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_WriteBBit(USBmX_DeviceRef dev, u_char v_and, u_char v_or)
|
|
|
+{
|
|
|
+ int r;
|
|
|
+ u_char res[8];
|
|
|
+ u_char cmd[8] = {
|
|
|
+ 0x04,
|
|
|
+ v_and,
|
|
|
+ v_or,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00
|
|
|
+ };
|
|
|
+ r = USBmX_RawCommand(dev, cmd, res);
|
|
|
+ if(r < 0) return r;
|
|
|
+ if(res[0] != cmd[0]) return -1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_ReadA(USBmX_DeviceRef dev, u_char *value_out)
|
|
|
+{
|
|
|
+ int r;
|
|
|
+ u_char res[8];
|
|
|
+ u_char cmd[8] = {
|
|
|
+ 0x05,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00
|
|
|
+ };
|
|
|
+ r = USBmX_RawCommand(dev, cmd, res);
|
|
|
+ if(value_out) *value_out = res[1];
|
|
|
+ if(r < 0) return r;
|
|
|
+ if(res[0] != cmd[0]) return -1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_ReadB(USBmX_DeviceRef dev, u_char *value_out)
|
|
|
+{
|
|
|
+ int r;
|
|
|
+ u_char res[8];
|
|
|
+ u_char cmd[8] = {
|
|
|
+ 0x06,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00
|
|
|
+ };
|
|
|
+ r = USBmX_RawCommand(dev, cmd, res);
|
|
|
+ if(value_out) *value_out = res[1];
|
|
|
+ if(r < 0) return r;
|
|
|
+ if(res[0] != cmd[0]) return -1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_SetBit(USBmX_DeviceRef dev, u_char line)
|
|
|
+{
|
|
|
+ int r;
|
|
|
+ u_char res[8];
|
|
|
+ u_char cmd[8] = {
|
|
|
+ 0x07,
|
|
|
+ line,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00
|
|
|
+ };
|
|
|
+ r = USBmX_RawCommand(dev, cmd, res);
|
|
|
+ if(r < 0) return r;
|
|
|
+ if(res[0] != cmd[0]) return -1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_ResetBit(USBmX_DeviceRef dev, u_char line)
|
|
|
+{
|
|
|
+ int r;
|
|
|
+ u_char res[8];
|
|
|
+ u_char cmd[8] = {
|
|
|
+ 0x08,
|
|
|
+ line,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00
|
|
|
+ };
|
|
|
+ r = USBmX_RawCommand(dev, cmd, res);
|
|
|
+ if(r < 0) return r;
|
|
|
+ if(res[0] != cmd[0]) return -1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_DirectionA(USBmX_DeviceRef dev, u_char dir0, u_char dir1)
|
|
|
+{
|
|
|
+ int r;
|
|
|
+ u_char res[8];
|
|
|
+ u_char cmd[8] = {
|
|
|
+ 0x09,
|
|
|
+ dir0,
|
|
|
+ dir1,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00
|
|
|
+ };
|
|
|
+ r = USBmX_RawCommand(dev, cmd, res);
|
|
|
+ if(r < 0) return r;
|
|
|
+ if(res[0] != cmd[0]) return -1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_DirectionB(USBmX_DeviceRef dev, u_char dir0, u_char dir1)
|
|
|
+{
|
|
|
+ int r;
|
|
|
+ u_char res[8];
|
|
|
+ u_char cmd[8] = {
|
|
|
+ 0x0A,
|
|
|
+ dir0,
|
|
|
+ dir1,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00,
|
|
|
+ 0x00
|
|
|
+ };
|
|
|
+ r = USBmX_RawCommand(dev, cmd, res);
|
|
|
+ if(r < 0) return r;
|
|
|
+ if(res[0] != cmd[0]) return -1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_StrobeWrite(USBmX_DeviceRef dev,
|
|
|
+ u_char data,
|
|
|
+ u_char port_select,
|
|
|
+ u_char strobe_line,
|
|
|
+ u_char pulse_length)
|
|
|
+{
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_StrobeRead(USBmX_DeviceRef dev,
|
|
|
+ u_char *data_out,
|
|
|
+ u_char port_select,
|
|
|
+ u_char strobe_line,
|
|
|
+ u_char pulse_length)
|
|
|
+{
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_StrobeWrites(USBmX_DeviceRef dev,
|
|
|
+ u_char n_bytes,
|
|
|
+ u_char bytes[])
|
|
|
+{
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_InitLCD(USBmX_DeviceRef dev,
|
|
|
+ u_char rw_select,
|
|
|
+ u_char rs_select,
|
|
|
+ u_char port_select,
|
|
|
+ u_char e_select)
|
|
|
+{
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_LCDCmd(USBmX_DeviceRef dev, u_char cmd)
|
|
|
+{
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+int USBmX_LCDData(USBmX_DeviceRef dev, u_char data)
|
|
|
+{
|
|
|
+ return -1;
|
|
|
+}
|