void openusb(usbdevice* kb){ // The driver sometimes isn't completely ready yet, so give it a short delay sleep(1); // Handle 3 is the control handle kb->lastkeypress = -1; kb->handle = kb->handles[3]; // Set up the device int setup = setupusb(kb); if(setup == -1){ closehandle(kb); pthread_mutex_unlock(&kb->mutex); pthread_mutex_destroy(&kb->mutex); pthread_mutex_destroy(&kb->keymutex); return; } else if(setup){ // If the setup had a communication error, wait a bit and try again. sleep(1); resetusb(kb); } // Start handling HID reports for the Corsair input IOHIDDeviceRegisterInputReportCallback(kb->handles[2], kb->intinput, MSG_SIZE, reportcallback, kb); // Register for close notification IOHIDDeviceRegisterRemovalCallback(kb->handle, usbremove, kb); // Update connected updateconnected(); notifyconnect(kb, 1); int index = INDEX_OF(kb, keyboard); printf("Device ready at %s%d\n", devpath, index); pthread_mutex_unlock(&kb->mutex); }
int usb_tryreset(usbdevice* kb){ if(reset_stop) return -1; ckb_info("Attempting reset...\n"); while(1){ int res = resetusb(kb); if(!res){ ckb_info("Reset success\n"); return 0; } if(res == -2 || reset_stop) break; } ckb_err("Reset failed. Disconnecting.\n"); return -1; }
int openusb(struct udev_device* dev, int model){ // Make sure it's not connected yet const char* path = udev_device_get_devnode(dev); for(int i = 1; i < DEV_MAX; i++){ if(keyboard[i].udev && !strcmp(path, udev_device_get_devnode(keyboard[i].udev))) return 0; } // Find a free USB slot for(int index = 1; index < DEV_MAX; index++){ usbdevice* kb = keyboard + index; if(!IS_ACTIVE(kb)){ // Open the sysfs device kb->udev = dev; kb->handle = open(path, O_RDWR); kb->model = model; if(kb->handle <= 0){ printf("Error: Failed to open USB device: %s\n", strerror(errno)); closehandle(kb); connectstatus |= 2; return -1; } // Copy device description and serial strncpy(kb->name, udev_device_get_sysattr_value(dev, "product"), NAME_LEN); strncpy(kb->setting.serial, udev_device_get_sysattr_value(dev, "serial"), SERIAL_LEN); printf("Connecting %s (S/N: %s)\n", kb->name, kb->setting.serial); // A USB reset is almost always required in order for it to work correctly printf("Resetting device\n"); if(ioctl(kb->handle, USBDEVFS_RESET, 0)){ printf("Reset failed (%s). Disconnecting.\n", strerror(errno)); closehandle(kb); connectstatus |= 2; return -1; } // Claim the USB interfaces if(usbclaim(kb)){ printf("Error: Failed to claim interface: %s\n", strerror(errno)); closehandle(kb); connectstatus |= 2; return -1; } // Put the M-keys (K95) as well as the Brightness/Lock keys into software-controlled mode. This packet disables their // hardware-based functions. unsigned char datapkt[MSG_SIZE] = { 0x07, 0x04, 0x02 }; struct usbdevfs_ctrltransfer transfer = { 0x21, 0x09, 0x0300, 0x03, MSG_SIZE, 500, datapkt }; // This packet doesn't always succeed, so reset the device if that happens if(ioctl(kb->handle, USBDEVFS_CONTROL, &transfer) != MSG_SIZE){ printf("Couldn't talk to device (%s), trying to reset again...\n", strerror(errno)); if(resetusb(kb) || ioctl(kb->handle, USBDEVFS_CONTROL, &transfer) != MSG_SIZE){ printf("Reset failed (%s). Disconnecting.\n", strerror(errno)); closehandle(kb); connectstatus |= 2; return -1; } } // Set up the device if(setupusb(index)){ closehandle(kb); connectstatus |= 2; return -1; } // Set up the interrupt transfers. kb->INPUT_TEST = 0; setint(kb); // We should receive an interrupt transfer shortly after setting them up. If it doesn't happen, the device // isn't working correctly and needs to be reset int received = 0; for(int wait = 0; wait < 10; wait++){ usleep(50000); if(kb->INPUT_TEST){ received = 1; break; } } if(!received){ printf("Didn't get input, trying to reset again...\n"); if(resetusb(kb)){ printf("Reset failed (%s). Disconnecting.\n", strerror(errno)); closehandle(kb); connectstatus |= 2; return -1; } } updateconnected(); printf("Device ready at %s%d\n", devpath, index); connectstatus |= 1; return 0; } } printf("Error: No free devices\n"); return -1; }