// USB device main loop static void* devmain(usbdevice* kb){ // dmutex should still be locked when this is called int kbfifo = kb->infifo - 1; readlines_ctx linectx; readlines_ctx_init(&linectx); while(1){ pthread_mutex_unlock(dmutex(kb)); // Read from FIFO const char* line; int lines = readlines(kbfifo, linectx, &line); pthread_mutex_lock(dmutex(kb)); // End thread when the handle is removed if(!IS_CONNECTED(kb)) break; if(lines){ if(readcmd(kb, line)){ // USB transfer failed; destroy device closeusb(kb); break; } } } pthread_mutex_unlock(dmutex(kb)); readlines_ctx_free(linectx); return 0; }
// USB device main loop static void* devmain(usbdevice* kb){ readlines_ctx linectx; readlines_ctx_init(&linectx); while(1){ pthread_mutex_lock(dmutex(kb)); // End thread when the handle is removed if(!IS_CONNECTED(kb)) break; // Read from FIFO const char* line; euid_guard_start; int lines = readlines(kb->infifo - 1, linectx, &line); euid_guard_stop; if(lines){ if(readcmd(kb, line)){ // USB transfer failed; destroy device closeusb(kb); break; } } // Update indicator LEDs for this keyboard. These are polled rather than processed during events because they don't update // immediately and may be changed externally by the OS. // (also, they can lock the keyboard if they're sent at the wrong time, at least on some firmwares) kb->vtable->updateindicators(kb, 0); // Wait a little bit and then read again pthread_mutex_unlock(dmutex(kb)); DELAY_SHORT(kb); } pthread_mutex_unlock(dmutex(kb)); readlines_ctx_free(linectx); return 0; }
void usbremove(void* context, IOReturn result, void* sender){ pthread_mutex_lock(&kblistmutex); usbdevice* kb = context; for(int i = 0; i < DEV_MAX; i++){ if(keyboard + i == kb){ pthread_mutex_lock(&keyboard[i].mutex); closeusb(keyboard + i); } } pthread_mutex_unlock(&kblistmutex); }
static void* _setupusb(void* context){ usbdevice* kb = context; // Set standard fields short vendor = kb->vendor, product = kb->product; const devcmd* vt = kb->vtable = get_vtable(vendor, product); kb->features = (IS_RGB(vendor, product) ? FEAT_STD_RGB : FEAT_STD_NRGB) & features_mask; if(IS_MOUSE(vendor, product)) kb->features |= FEAT_ADJRATE; if(IS_MONOCHROME(vendor, product)) kb->features |= FEAT_MONOCHROME; kb->usbdelay = USB_DELAY_DEFAULT; // Perform OS-specific setup DELAY_LONG(kb); if(os_setupusb(kb)) goto fail; // Make up a device name and serial if they weren't assigned if(!kb->serial[0]) snprintf(kb->serial, SERIAL_LEN, "%04x:%04x-NoID", kb->vendor, kb->product); if(!kb->name[0]) snprintf(kb->name, KB_NAME_LEN, "%s %s", vendor_str(kb->vendor), product_str(kb->product)); // Set up an input device for key events if(os_inputopen(kb)) goto fail; if(pthread_create(&kb->inputthread, 0, os_inputmain, kb)) goto fail; pthread_detach(kb->inputthread); if(os_setupindicators(kb)) goto fail; // Set up device vt->allocprofile(kb); vt->updateindicators(kb, 1); pthread_mutex_unlock(imutex(kb)); if(vt->start(kb, 0) && usb_tryreset(kb)) goto fail_noinput; // Make /dev path if(mkdevpath(kb)) goto fail_noinput; // Finished. Enter main loop int index = INDEX_OF(kb, keyboard); ckb_info("Setup finished for %s%d\n", devpath, index); updateconnected(); return devmain(kb); fail: pthread_mutex_unlock(imutex(kb)); fail_noinput: closeusb(kb); pthread_mutex_unlock(dmutex(kb)); return 0; }
// Remove a udev device. static void usb_rm_device(struct udev_device* dev){ // Device removed. Look for it in our list of keyboards const char* syspath = udev_device_get_syspath(dev); if(!syspath || syspath[0] == 0) return; for(int i = 1; i < DEV_MAX; i++){ pthread_mutex_lock(devmutex + i); if(!strcmp(syspath, kbsyspath[i])) closeusb(keyboard + i); pthread_mutex_unlock(devmutex + i); } }
static void remove_device(void* context, io_service_t device, uint32_t message_type, void* message_argument){ if(message_type != kIOMessageServiceIsTerminated) return; usbdevice* kb = context; if(kb){ // If the handle is connected to a device, close it pthread_mutex_lock(dmutex(kb)); closeusb(kb); pthread_mutex_unlock(dmutex(kb)); } IOObjectRelease(device); }
void* udevmain(void* context){ // Enumerate all currently connected devices udevenum(); if(connectstatus & 2) // If a device failed to connect, enumerate again to make sure we reconnect it (if possible) udevenum(); // Done scanning. Enter a loop to poll for device updates struct udev_monitor* monitor = udev_monitor_new_from_netlink(udev, "udev"); udev_monitor_filter_add_match_subsystem_devtype(monitor, "usb", 0); udev_monitor_enable_receiving(monitor); // Get an fd for the monitor int fd = udev_monitor_get_fd(monitor); fd_set fds; while(udev){ FD_ZERO(&fds); FD_SET(fd, &fds); // Block until an event is read if(select(fd + 1, &fds, 0, 0, 0) > 0 && FD_ISSET(fd, &fds)){ struct udev_device* dev = udev_monitor_receive_device(monitor); if(dev){ const char* action = udev_device_get_action(dev); if(action && !strcmp(action, "add")){ // Device added. Check vendor and product ID and add the device if it matches. const char* vendor = udev_device_get_sysattr_value(dev, "idVendor"); if(vendor && !strcmp(vendor, V_CORSAIR_STR)){ const char* product = udev_device_get_sysattr_value(dev, "idProduct"); if(product && !strcmp(product, P_K70_STR)){ pthread_mutex_lock(&kblistmutex); openusb(dev, 70); pthread_mutex_unlock(&kblistmutex); } else if(product && !strcmp(product, P_K95_STR)){ pthread_mutex_lock(&kblistmutex); openusb(dev, 95); pthread_mutex_unlock(&kblistmutex); } else // Free the device if it wasn't used udev_device_unref(dev); } else udev_device_unref(dev); // Wait a little bit and then re-enumerate devices. Sometimes the keyboard doesn't get picked up right away. usleep(100000); connectstatus = 0; udevenum(); if(connectstatus & 2) udevenum(); } else if(!strcmp(action, "remove")){ // Device removed. Look for it in our list of keyboards pthread_mutex_lock(&kblistmutex); const char* path = udev_device_get_syspath(dev); for(int i = 1; i < DEV_MAX; i++){ if(keyboard[i].udev && !strcmp(path, udev_device_get_syspath(keyboard[i].udev))){ pthread_mutex_lock(&keyboard[i].mutex); closeusb(i); break; } } pthread_mutex_unlock(&kblistmutex); } } } } udev_monitor_unref(monitor); return 0; }