9 static CFRunLoopRef mainloop = 0;
 
   10 static IONotificationPortRef notify = 0;
 
   29 static CFMachPortRef mouse_event_tap;
 
   31 static long hidgetlong(hid_dev_t handle, CFStringRef 
key){
 
   34     if((*handle)->getProperty(handle, key, &cf) != kIOReturnSuccess)
 
   36     if(!cf || CFGetTypeID(cf) != CFNumberGetTypeID() || !CFNumberGetValue(cf, kCFNumberLongType, &raw))
 
   41 static void hidgetstr(hid_dev_t handle, CFStringRef key, 
char* output, 
int out_len){
 
   43     if((*handle)->getProperty(handle, key, &cf) != kIOReturnSuccess){
 
   47     if(!cf || CFGetTypeID(cf) != CFStringGetTypeID() || !CFStringGetCString(cf, output, out_len, kCFStringEncodingASCII))
 
   52 void u16dec(
ushort* in, 
char* out, 
size_t* srclen, 
size_t* dstlen);
 
   54 static void usbgetstr(usb_dev_t handle, uint8 string_index, 
char* output, 
int out_len){
 
   56     char buffer[256] = { 0 };
 
   57     IOUSBDevRequest rq = { 0x80, 0x06, 0x0300 | string_index, 0x0409, 
sizeof(buffer) - 2, buffer, 0};
 
   58     kern_return_t res = (*handle)->DeviceRequest(handle, &rq);
 
   59     if(res != kIOReturnSuccess){
 
   63     size_t inl = 
sizeof(buffer) / 2, outl = out_len;
 
   65     output[out_len - 1] = 0;
 
   68 #define INCOMPLETE (usb_dev_t)-1l 
   69 #define HAS_ALL_HANDLES(kb) ((kb)->epcount > 0 && (kb)->epcount_hid + (kb)->epcount_usb >= (kb)->epcount) 
   72 #define wait_loop(error, operation)  do {               \ 
   74     while(((error) = (operation)) != kIOReturnSuccess){ \ 
   80 #define IS_TEMP_FAILURE(res)        ((res) == kIOUSBTransactionTimeout || (res) == kIOUSBTransactionReturned || (res) == kIOUSBPipeStalled) 
   81 #define IS_DISCONNECT_FAILURE(res)  ((res) == kIOReturnBadArgument || (res) == kIOReturnNoDevice || (res) == kIOReturnNotOpen || (res) == kIOReturnNotAttached || (res) == kIOReturnExclusiveAccess) 
   84 static int get_pipe_index(usb_iface_t handle, 
int desired_direction){
 
   86     if((*handle)->GetNumEndpoints(handle, &count) != kIOReturnSuccess)
 
   88     for(
int i = 0; i < count; i++){
 
   89         uchar direction, number, transfertype, interval;
 
   91         if((*handle)->GetPipeProperties(handle, i + 1, &direction, &number, &transfertype, &maxpacketsize, &interval) == kIOReturnSuccess){
 
   92             if(direction == desired_direction)
 
  101     kern_return_t res = kIOReturnSuccess;
 
  107         IOUSBDevRequestTO rq = { 0x21, 0x09, 0x0200, ep - 1, 
MSG_SIZE, (
void*)out_msg, 0, 5000, 5000 };
 
  109         if(res == kIOReturnNotOpen){
 
  111             usb_iface_t h_usb = kb->ifusb[ep - 1];
 
  112             hid_dev_t h_hid = kb->ifhid[ep - 1];
 
  114                 res = (*h_usb)->ControlRequestTO(h_usb, 0, &rq);
 
  116                 res = (*h_hid)->setReport(h_hid, kIOHIDReportTypeFeature, 0, out_msg, MSG_SIZE, 5000, 0, 0, 0);
 
  121         usb_iface_t h_usb = kb->ifusb[ep - 1];
 
  122         hid_dev_t h_hid = kb->ifhid[ep - 1];
 
  124             res = (*h_usb)->WritePipe(h_usb, get_pipe_index(h_usb, kUSBOut), (
void*)out_msg, MSG_SIZE);
 
  126             res = (*h_hid)->setReport(h_hid, kIOHIDReportTypeOutput, 0, out_msg, MSG_SIZE, 5000, 0, 0, 0);
 
  128     kb->lastresult = res;
 
  129     if(res != kIOReturnSuccess){
 
  130         ckb_err_fn(
"Got return value 0x%x\n", file, line, res);
 
  131         if(IS_TEMP_FAILURE(res))
 
  141     IOUSBDevRequestTO rq = { 0xa1, 0x01, 0x0200, ep - 1, 
MSG_SIZE, in_msg, 0, 5000, 5000 };
 
  142     kern_return_t res = (*kb->
handle)->DeviceRequestTO(kb->
handle, &rq);
 
  143     CFIndex length = rq.wLenDone;
 
  144     if(res == kIOReturnNotOpen){
 
  146         usb_iface_t h_usb = kb->ifusb[ep - 1];
 
  147         hid_dev_t h_hid = kb->ifhid[ep - 1];
 
  149             res = (*h_usb)->ControlRequestTO(h_usb, 0, &rq);
 
  151             res = (*h_hid)->getReport(h_hid, kIOHIDReportTypeFeature, 0, in_msg, &length, 5000, 0, 0, 0);
 
  153     kb->lastresult = res;
 
  154     if(res != kIOReturnSuccess){
 
  155         ckb_err_fn(
"Got return value 0x%x\n", file, line, res);
 
  156         if(IS_TEMP_FAILURE(res))
 
  161     if(length != MSG_SIZE)
 
  162         ckb_err_fn(
"Read %ld bytes (expected %d)\n", file, line, length, MSG_SIZE);
 
  167     IOUSBDevRequestTO rq = { 0x40, bRequest, wValue, 0, 0, 0, 0, 5000, 5000 };
 
  168     kern_return_t res = (*kb->
handle)->DeviceRequestTO(kb->
handle, &rq);
 
  169     if(res != kIOReturnSuccess){
 
  170         ckb_err_fn(
"Got return value 0x%x\n", file, line, res);
 
  177     IOUSBDevRequestTO rq = { 0x21, 0x09, 0x0200, 0x00, 1, &kb->
ileds, 0, 500, 500 };
 
  178     kern_return_t res = (*kb->
handle)->DeviceRequestTO(kb->
handle, &rq);
 
  179     if(res == kIOReturnNotOpen){
 
  181         hid_dev_t handle = kb->ifhid[0];
 
  185             long ledpage = kHIDPage_LEDs;
 
  186             const void* keys[] = { CFSTR(kIOHIDElementUsagePageKey) };
 
  187             const void* values[] = { CFNumberCreate(kCFAllocatorDefault, kCFNumberLongType, &ledpage) };
 
  188             CFDictionaryRef matching = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 
  189             CFRelease(values[0]);
 
  191             kern_return_t res = (*handle)->copyMatchingElements(handle, matching, &leds, 0);
 
  193             if(res != kIOReturnSuccess)
 
  196             CFIndex count = CFArrayGetCount(leds);
 
  197             for(CFIndex i = 0; i < count; i++){
 
  198                 IOHIDElementRef led = (
void*)CFArrayGetValueAtIndex(leds, i);
 
  199                 uint32_t usage = IOHIDElementGetUsage(led);
 
  200                 IOHIDValueRef value = IOHIDValueCreateWithIntegerValue(kCFAllocatorDefault, led, 0, !!(ileds & (1 << (usage - 1))));
 
  201                 (*handle)->setValue(handle, led, value, 5000, 0, 0, 0);
 
  207     if(res != kIOReturnSuccess)
 
  208         ckb_err(
"Got return value 0x%x\n", res);
 
  212     kern_return_t res = kb->lastresult;
 
  213     if(IS_DISCONNECT_FAILURE(res))
 
  221 static void intreport(
void* context, IOReturn result, 
void* sender, IOHIDReportType reporttype, uint32_t reportid, uint8_t* data, CFIndex length){
 
  223     pthread_mutex_lock(
imutex(kb));
 
  270     pthread_mutex_unlock(
imutex(kb));
 
  281 static void pipecomplete(
void* refcon, IOReturn result, 
void* arg0){
 
  282     if(result != kIOReturnSuccess)
 
  284     intptr_t length = (intptr_t)arg0;
 
  285     urbctx* ctx = refcon;
 
  288     uchar* buffer = ctx->buffer;
 
  289     intreport(kb, result, 0, 0, 0, buffer, length);
 
  291     usb_iface_t handle = kb->ifusb[ctx->index];
 
  292     (*handle)->ReadPipeAsync(handle, ctx->pipe, buffer, ctx->maxsize, pipecomplete, ctx);
 
  297 CGEventRef mouse_event_modifier_callback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, 
void* refcon) {
 
  298     if (type == kCGEventTapDisabledByTimeout) {
 
  299         CGEventTapEnable(mouse_event_tap, 
true);
 
  307         CGEventFlags existingFlags = CGEventSourceFlagsState(kCGEventSourceStateHIDSystemState);
 
  308         for(
int i = 0; i < 
DEV_MAX; i++){
 
  314                     pthread_mutex_lock(
imutex(kb));
 
  315                     CGEventSetFlags(event, (kCGEventFlagMaskNonCoalesced | kb->modifiers | existingFlags));
 
  316                     pthread_mutex_unlock(
imutex(kb));
 
  328 void register_mouse_event_tap(CFRunLoopRef run_loop) {
 
  333     CGEventMask mask = CGEventMaskBit(kCGEventLeftMouseDown) |
 
  334                         CGEventMaskBit(kCGEventLeftMouseUp) |
 
  335                         CGEventMaskBit(kCGEventRightMouseDown) |
 
  336                         CGEventMaskBit(kCGEventRightMouseUp) |
 
  337                         CGEventMaskBit(kCGEventMouseMoved) |
 
  338                         CGEventMaskBit(kCGEventLeftMouseDragged) |
 
  339                         CGEventMaskBit(kCGEventRightMouseDragged) |
 
  340                         CGEventMaskBit(kCGEventScrollWheel) |
 
  341                         CGEventMaskBit(kCGEventTabletPointer) |
 
  342                         CGEventMaskBit(kCGEventTabletProximity) |
 
  343                         CGEventMaskBit(kCGEventOtherMouseDown) |
 
  344                         CGEventMaskBit(kCGEventOtherMouseUp) |
 
  345                         CGEventMaskBit(kCGEventOtherMouseDragged);
 
  349     mouse_event_tap = CGEventTapCreate(kCGHIDEventTap,
 
  350                                  kCGHeadInsertEventTap,
 
  351                                  kCGEventTapOptionDefault,
 
  353                                  mouse_event_modifier_callback,
 
  357     if (mouse_event_tap) {
 
  358         CFRunLoopSourceRef run_loop_source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, mouse_event_tap, 0);
 
  359         if (run_loop_source) {
 
  360             ckb_info(
"Registering EventTap for modifier keys.\n");
 
  361             CFRunLoopAddSource(run_loop, run_loop_source, kCFRunLoopCommonModes);
 
  362             CGEventTapEnable(mouse_event_tap, 
true);
 
  363             CFRelease(run_loop_source);
 
  370 extern void keyretrigger(CFRunLoopTimerRef timer, 
void* info);
 
  379     CFRunLoopRef runloop = kb->input_loop = CFRunLoopGetCurrent();
 
  380     for(
int i = 0; i < count; i++){
 
  381         CFTypeRef eventsource;
 
  384             res = (*kb->ifusb[i])->CreateInterfaceAsyncEventSource(kb->ifusb[i], (CFRunLoopSourceRef*)&eventsource);
 
  385         else if(kb->ifhid[i])
 
  386             res = (*kb->ifhid[i])->getAsyncEventSource(kb->ifhid[i], &eventsource);
 
  389         if(res != kIOReturnSuccess){
 
  390             ckb_err(
"Failed to start input thread for %s%d: %x\n", 
devpath, index, res);
 
  393         if(CFGetTypeID(eventsource) == CFRunLoopSourceGetTypeID())
 
  394             CFRunLoopAddSource(runloop, (CFRunLoopSourceRef)eventsource, kCFRunLoopDefaultMode);
 
  395         else if(CFGetTypeID(eventsource) == CFRunLoopTimerGetTypeID())
 
  396             CFRunLoopAddTimer(runloop, (CFRunLoopTimerRef)eventsource, kCFRunLoopDefaultMode);
 
  402     memset(input, 0, 
sizeof(input));
 
  403     for(
int i = 0; i < count; i++){
 
  405             usb_iface_t handle = kb->ifusb[i];
 
  406             int pipe = get_pipe_index(handle, kUSBIn);
 
  407             uchar direction, number, transfertype, interval;
 
  409             (*handle)->GetPipeProperties(handle, pipe, &direction, &number, &transfertype, &maxpacketsize, &interval);
 
  410             if(direction != kUSBIn && direction != kUSBAnyDirn)
 
  412             uchar* buffer = malloc(maxpacketsize);
 
  414             input[i].buffer = buffer;
 
  416             input[i].pipe = pipe;
 
  417             input[i].maxsize = maxpacketsize;
 
  418             (*handle)->ReadPipeAsync(handle, 1, buffer, maxpacketsize, pipecomplete, input + i);
 
  419         } 
else if(kb->ifhid[i]){
 
  420             hid_dev_t handle = kb->ifhid[i];
 
  421             long maxsize = hidgetlong(handle, CFSTR(kIOHIDMaxInputReportSizeKey));
 
  422             uchar* buffer = malloc(maxsize);
 
  423             input[i].buffer = buffer;
 
  424             (*handle)->setInputReportCallback(handle, buffer, maxsize, intreport, kb, 0);
 
  429     CFRunLoopTimerContext krctx = { 0, kb, NULL, NULL, NULL };
 
  430     CFRunLoopTimerRef krtimer = kb->krtimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
 
  431                                                                    CFAbsoluteTimeGetCurrent() + 0.001, 0.001,   
 
  433                                                                    keyretrigger, &krctx);
 
  434     CFRunLoopTimerSetTolerance(krtimer, 0.015);         
 
  442         pthread_mutex_lock(
imutex(kb));
 
  444             pthread_mutex_unlock(
imutex(kb));
 
  447         pthread_mutex_unlock(
imutex(kb));
 
  452     for(
int i = 0; i < count; i++)
 
  453         free(input[i].buffer);
 
  466     int count = kb->epcount_hid;
 
  467     for(
int i = 0; i < count; i++){
 
  468         hid_dev_t iface = kb->ifhid[i];
 
  470             (*iface)->close(iface, kIOHIDOptionsTypeNone);
 
  471             (*iface)->Release(iface);
 
  477     count = kb->epcount_usb;
 
  478     for(
int i = 0; i < count; i++){
 
  479         usb_iface_t iface = kb->ifusb[i];
 
  481             (*iface)->USBInterfaceClose(iface);
 
  482             (*iface)->Release(iface);
 
  487     usb_dev_t iface = kb->
handle;
 
  489         (*iface)->USBDeviceClose(iface);
 
  490         (*iface)->Release(iface);
 
  495         CFRunLoopStop(kb->input_loop);
 
  500 static void remove_device(
void* context, io_service_t device, uint32_t message_type, 
void* message_argument){
 
  501     if(message_type != kIOMessageServiceIsTerminated)
 
  506         pthread_mutex_lock(
dmutex(kb));
 
  508         pthread_mutex_unlock(
dmutex(kb));
 
  510     IOObjectRelease(device);
 
  515 static int find_device(uint16_t idvendor, uint16_t idproduct, uint32_t location, 
int handle_idx){
 
  517     for(
int i = 1; i < 
DEV_MAX; i++){
 
  518         if(pthread_mutex_trylock(
devmutex + i))
 
  522             for(
int iface = 0; iface <= 
IFACE_MAX; iface++){
 
  523                 if(
keyboard[i].location_id[iface] == location){
 
  525                     keyboard[i].location_id[handle_idx] = location;
 
  534     for(
int i = 1; i < 
DEV_MAX; i++){
 
  535         if(pthread_mutex_trylock(
devmutex + i))
 
  540             keyboard[i].location_id[handle_idx] = location;
 
  551 static int seize_wait(
long location){
 
  554     char location_var[18], location_fixed[18];
 
  555     snprintf(location_var, 
sizeof(location_var), 
"@%lx", location);
 
  556     snprintf(location_fixed, 
sizeof(location_fixed), 
"@%08x", (
int)location);
 
  558     static mach_port_t master = 0;
 
  560     if(!master && (res = IOMasterPort(bootstrap_port, &master)) != kIOReturnSuccess){
 
  562         ckb_warn(
"Unable to open master port: 0x%08x\n", res);
 
  565     const int max_tries = 20;     
 
  566     for(
int try = 0; 
try < max_tries; 
try++){
 
  569         io_iterator_t child_iter;
 
  570         if((res = IORegistryCreateIterator(master, kIOServicePlane, kIORegistryIterateRecursively, &child_iter)) != kIOReturnSuccess)
 
  573         io_registry_entry_t child_service;
 
  574         while((child_service = IOIteratorNext(child_iter)) != 0){
 
  576             IORegistryEntryGetPath(child_service, kIOServicePlane, path);
 
  577             IOObjectRelease(child_service);
 
  579             if((strstr(path, location_var) || strstr(path, location_fixed)) && strstr(path, 
"HID")){
 
  580                 IOObjectRelease(child_iter);
 
  584         IOObjectRelease(child_iter);
 
  590 static usbdevice* add_usb(usb_dev_t handle, io_object_t** rm_notify){
 
  591     int iface_count = 0, iface_success = 0;
 
  592     io_iterator_t iterator = 0;
 
  593     io_service_t iface = 0;
 
  595     UInt16 idvendor, idproduct;
 
  597     (*handle)->GetDeviceVendor(handle, &idvendor);
 
  598     (*handle)->GetDeviceProduct(handle, &idproduct);
 
  599     (*handle)->GetLocationID(handle, &location);
 
  601     int index = find_device(idvendor, idproduct, location, 0);
 
  611         ckb_warn(
"Tried to set up handle for device ckb%d, but it was already set up. Skipping...\n", index);
 
  618         UInt8 serial_idx, product_idx;
 
  619         if((*handle)->USBGetSerialNumberStringIndex(handle, &serial_idx) == kIOReturnSuccess)
 
  621         if((*handle)->USBGetProductStringIndex(handle, &product_idx) == kIOReturnSuccess)
 
  627     if(seize_wait(location))
 
  628         ckb_warn(
"seize_wait failed, connecting anyway...\n");
 
  629     IOUSBFindInterfaceRequest interfaceRequest;
 
  630     interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare;
 
  631     interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
 
  632     interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
 
  633     interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare;
 
  634     (*handle)->CreateInterfaceIterator(handle, &interfaceRequest, &iterator);
 
  636     while((iface = IOIteratorNext(iterator)) != 0){
 
  638             ckb_warn(
"Too many interfaces. Dropping the rest.\n");
 
  639             IOObjectRelease(iface);
 
  643         IOCFPlugInInterface** plugin = 0;
 
  646         wait_loop(err, IOCreatePlugInInterfaceForService(iface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score));
 
  647         if(err != kIOReturnSuccess){
 
  648             ckb_err(
"Failed to create interface plugin: %x\n", err);
 
  651         usb_iface_t if_handle;
 
  652         wait_loop(err, (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID183), (LPVOID)&if_handle));
 
  653         if(err != kIOReturnSuccess){
 
  654             ckb_err(
"QueryInterface failed: %x\n", err);
 
  658         IODestroyPlugInInterface(plugin);
 
  661         (*if_handle)->GetLocationID(if_handle, kb->location_id + iface_count + 1);
 
  663         err = (*if_handle)->USBInterfaceOpenSeize(if_handle);   
 
  664         if(err == kIOReturnSuccess){
 
  665             kb->ifusb[iface_count] = if_handle;
 
  668             IOServiceAddInterestNotification(notify, iface, kIOGeneralInterest, remove_device, kb, kb->rm_notify + 1 + iface_count);
 
  670             kb->ifusb[iface_count] = 0;
 
  671             (*if_handle)->Release(if_handle);
 
  676         IOObjectRelease(iface);
 
  678     if(iface_count == 0){
 
  681         ckb_warn(
"Unable to count endpoints, assuming %d...\n", iface_count);
 
  684     kb->epcount_usb = iface_success;
 
  687     if(HAS_ALL_HANDLES(kb))
 
  690         pthread_mutex_unlock(
devmutex + index);
 
  691     *rm_notify = kb->rm_notify;
 
  695     pthread_mutex_unlock(
devmutex + index);
 
  699 static void iterate_devices_usb(
void* context, io_iterator_t iterator){
 
  702     while((device = IOIteratorNext(iterator)) != 0){
 
  703         IOCFPlugInInterface** plugin = 0;
 
  706         wait_loop(err, IOCreatePlugInInterfaceForService(device, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score));
 
  707         if(err != kIOReturnSuccess){
 
  708             ckb_err(
"Failed to create device plugin: %x\n", err);
 
  713         wait_loop(err, (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID182), (LPVOID*)&handle));
 
  714         if(err != kIOReturnSuccess){
 
  715             ckb_err(
"QueryInterface failed: %x\n", err);
 
  719         IODestroyPlugInInterface(plugin);
 
  721         err = (*handle)->USBDeviceOpenSeize(handle);
 
  722         if(err == kIOReturnExclusiveAccess){
 
  724             ckb_warn(
"Unable to seize USB handle, continuing anyway...\n");
 
  725         } 
else if(err != kIOReturnSuccess){
 
  726             ckb_err(
"USBDeviceOpen failed: %x\n", err);
 
  730         io_object_t* rm_notify = 0;
 
  731         usbdevice* kb = add_usb(handle, &rm_notify);
 
  734             IOServiceAddInterestNotification(notify, device, kIOGeneralInterest, remove_device, kb, rm_notify);
 
  737             (*handle)->USBDeviceClose(handle);
 
  739         IOObjectRelease(device);
 
  744 static usbdevice* add_hid(hid_dev_t handle, io_object_t** rm_notify){
 
  748     long input = hidgetlong(handle, CFSTR(kIOHIDMaxInputReportSizeKey));
 
  749     long output = hidgetlong(handle, CFSTR(kIOHIDMaxOutputReportSizeKey));
 
  750     long feature = hidgetlong(handle, CFSTR(kIOHIDMaxFeatureReportSizeKey));
 
  756     else if(feature == 0 &&
 
  758                input == 15) && output == 0) ||
 
  759             (input == 64 && output == 64) ||    
 
  760             (input <= 1 && output == 64)))      
 
  763     else if(output <= 1 && feature <= 1 &&
 
  768     else if(output <= 1 && feature <= 1 &&
 
  769             (input == 21 || input == 10 ||
 
  774         ckb_warn(
"Got unknown handle (I: %d, O: %d, F: %d)\n", (
int)input, (
int)output, (
int)feature);
 
  779     uint16_t idvendor = hidgetlong(handle, CFSTR(kIOHIDVendorIDKey)), idproduct = hidgetlong(handle, CFSTR(kIOHIDProductIDKey));
 
  781     uint32_t location = hidgetlong(handle, CFSTR(kIOHIDLocationIDKey));
 
  782     int index = find_device(idvendor, idproduct, location, handle_idx + 1);
 
  798     if(kb->ifhid[handle_idx]){
 
  800         ckb_warn(
"Tried to set up ifhid[%d] for device ckb%d, but it was already set up. Skipping...\n", handle_idx, index);
 
  803     kb->ifhid[handle_idx] = handle;
 
  805     if(HAS_ALL_HANDLES(kb))
 
  810         pthread_mutex_unlock(
devmutex + index);
 
  811     *rm_notify = kb->rm_notify + 
IFACE_MAX + 1 + handle_idx;
 
  815     pthread_mutex_unlock(
devmutex + index);
 
  819 static void iterate_devices_hid(
void* context, io_iterator_t iterator){
 
  822     while((device = IOIteratorNext(iterator)) != 0){
 
  824         IOCFPlugInInterface** plugin = 0;
 
  827         wait_loop(err, IOCreatePlugInInterfaceForService(device, kIOHIDDeviceTypeID, kIOCFPlugInInterfaceID, &plugin, &score));
 
  828         if(err != kIOReturnSuccess){
 
  829             ckb_err(
"Failed to create device plugin: %x\n", err);
 
  834         wait_loop(err, (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOHIDDeviceDeviceInterfaceID), (LPVOID*)&handle));
 
  835         if(err != kIOReturnSuccess){
 
  836             ckb_err(
"QueryInterface failed: %x\n", err);
 
  840         IODestroyPlugInInterface(plugin);
 
  842         if(seize_wait(hidgetlong(handle, CFSTR(kIOHIDLocationIDKey))))
 
  843             ckb_warn(
"seize_wait failed, connecting anyway...\n");
 
  844         wait_loop(err, (*handle)->open(handle, kIOHIDOptionsTypeSeizeDevice));
 
  845         if(err != kIOReturnSuccess){
 
  846             ckb_warn(
"Failed to open device: %x\n", err);
 
  850         io_object_t* rm_notify = 0;
 
  851         usbdevice* kb = add_hid(handle, &rm_notify);
 
  854             IOServiceAddInterestNotification(notify, device, kIOGeneralInterest, remove_device, kb, rm_notify);
 
  857             (*handle)->close(handle, kIOHIDOptionsTypeSeizeDevice);
 
  859         IOObjectRelease(device);
 
  868         P_K65, 
P_K65_NRGB, 
P_K65_LUX, 
P_K65_RFIRE, 
P_K70, 
P_K70_NRGB, 
P_K70_LUX, 
P_K70_LUX_NRGB, 
P_K70_RFIRE, 
P_K70_RFIRE_NRGB, 
P_K95, 
P_K95_NRGB, 
P_K95_PLATINUM, 
P_STRAFE, 
P_STRAFE_NRGB,
 
  874     notify = IONotificationPortCreate(kIOMasterPortDefault);
 
  875     mainloop = CFRunLoopGetCurrent();
 
  876     CFRunLoopAddSource(mainloop, IONotificationPortGetRunLoopSource(notify), kCFRunLoopDefaultMode);
 
  886     CFMutableDictionaryRef match = IOServiceMatching(kIOUSBDeviceClassName);
 
  887     CFNumberRef cfvendor = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendor);
 
  888     CFDictionarySetValue(match, CFSTR(kUSBVendorName), cfvendor);
 
  890     CFMutableArrayRef cfproducts = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
 
  891     for(uint i = 0; i < 
sizeof(products) / 
sizeof(
int); i++){
 
  892         int product = products[i];
 
  893         CFNumberRef cfproduct = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &product);
 
  894         CFArrayAppendValue(cfproducts, cfproduct);
 
  895         CFRelease(cfproduct);
 
  897     CFDictionarySetValue(match, CFSTR(kUSBProductIdsArrayName), cfproducts);
 
  898     CFRelease(cfproducts);
 
  900     io_iterator_t iterator_usb = 0;
 
  901     IOReturn res = IOServiceAddMatchingNotification(notify, kIOMatchedNotification, match, iterate_devices_usb, 0, &iterator_usb);
 
  902     if(res != kIOReturnSuccess){
 
  903         ckb_fatal(
"Failed to list USB devices: %x\n", res);
 
  908         iterate_devices_usb(0, iterator_usb);
 
  912     match = IOServiceMatching(kIOHIDDeviceKey);
 
  913     cfvendor = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendor);
 
  914     CFDictionarySetValue(match, CFSTR(kIOHIDVendorIDKey), cfvendor);
 
  916     cfproducts = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
 
  917     for(uint i = 0; i < 
sizeof(products) / 
sizeof(
int); i++){
 
  918         int product = products[i];
 
  919         CFNumberRef cfproduct = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &product);
 
  920         CFArrayAppendValue(cfproducts, cfproduct);
 
  921         CFRelease(cfproduct);
 
  923     CFDictionarySetValue(match, CFSTR(kIOHIDProductIDArrayKey), cfproducts);
 
  924     CFRelease(cfproducts);
 
  926     io_iterator_t iterator_hid = 0;
 
  927     res = IOServiceAddMatchingNotification(notify, kIOMatchedNotification, match, iterate_devices_hid, 0, &iterator_hid);
 
  928     if(res != kIOReturnSuccess){
 
  929         ckb_fatal(
"Failed to list HID devices: %x\n", res);
 
  934         iterate_devices_hid(0, iterator_hid);
 
  936     register_mouse_event_tap(mainloop);
 
  944     CFRunLoopStop(mainloop);
 
void setupusb(usbdevice *kb)
 
int usbmain()
Start the USB main loop. Returns program exit code when finished. 
 
#define ckb_err(fmt, args...)
 
usbdevice keyboard[9]
remember all usb devices. Needed for closeusb(). 
 
uchar keys[((((152+3+12)+25)+7)/8)]
 
int os_resetusb(usbdevice *kb, const char *file, int line)
os_resetusb is the os specific implementation for resetting usb 
 
void * os_inputmain(void *context)
os_inputmain is run in a separate thread and will be detached from the main thread, so it needs to clean up its own resources. 
 
void os_closeusb(usbdevice *kb)
os_closeusb unclaim it, destroy the udev device and clear data structures at kb 
 
pthread_mutex_t devmutex[9]
Mutex for handling the usbdevice structure. 
 
int os_usbrecv(usbdevice *kb, uchar *in_msg, const char *file, int line)
os_usbrecv receives a max MSGSIZE long buffer from usb device 
 
int os_setupusb(usbdevice *kb)
os_setupusb OS-specific setup for a specific usb device. 
 
#define ckb_fatal(fmt, args...)
 
#define IS_MOUSE(vendor, product)
Mouse vs keyboard test. 
 
void hid_mouse_translate(unsigned char *kbinput, short *xaxis, short *yaxis, int endpoint, int length, const unsigned char *urbinput)
 
#define ckb_warn(fmt, args...)
 
void corsair_mousecopy(unsigned char *kbinput, int endpoint, const unsigned char *urbinput)
 
const char *const devpath
 
#define ckb_info(fmt, args...)
 
#define INDEX_OF(entry, array)
 
int closeusb(usbdevice *kb)
 
#define IS_RGB_DEV(kb)
For calling with a usbdevice*, vendor and product are extracted and IS_RGB() is returned. 
 
void hid_kb_translate(unsigned char *kbinput, int endpoint, int length, const unsigned char *urbinput)
 
#define IS_MOUSE_DEV(kb)
For calling with a usbdevice*, vendor and product are extracted and IS_MOUSE() is returned...
 
#define HAS_FEATURES(kb, feat)
 
Definitions for using USB interface. 
 
void os_sendindicators(usbdevice *kb)
os_sendindicators update the indicators for the special keys (Numlock, Capslock and what else...
 
void corsair_kbcopy(unsigned char *kbinput, int endpoint, const unsigned char *urbinput)
 
#define V_CORSAIR
For the following Defines please see "Detailed Description". 
 
int _nk95cmd(usbdevice *kb, uchar bRequest, ushort wValue, const char *file, int line)
_nk95cmd If we control a non RGB keyboard, set the keyboard via ioctl with usbdevfs_ctrltransfer ...
 
void usbkill()
Stop the USB system. 
 
int os_usbsend(usbdevice *kb, const uchar *out_msg, int is_recv, const char *file, int line)
os_usbsend sends a data packet (MSG_SIZE = 64) Bytes long 
 
void u16dec(ushort *in, char *out, size_t *srclen, size_t *dstlen)
 
#define ckb_err_fn(fmt, file, line, args...)