Ejemplo n.º 1
0
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);
}
Ejemplo n.º 2
0
int usbadd(struct udev_device* dev, short vendor, short product){
    const char* path = udev_device_get_devnode(dev);
    const char* syspath = udev_device_get_syspath(dev);
    if(!path || !syspath || path[0] == 0 || syspath[0] == 0){
        ckb_err("Failed to get device path\n");
        return -1;
    }
    // Find a free USB slot
    for(int index = 1; index < DEV_MAX; index++){
        usbdevice* kb = keyboard + index;
        if(pthread_mutex_trylock(dmutex(kb))){
            // If the mutex is locked then the device is obviously in use, so keep going
            if(!strcmp(syspath, kbsyspath[index])){
                // Make sure this existing keyboard doesn't have the same syspath (this shouldn't happen)
                return 0;
            }
            continue;
        }
        if(!IS_CONNECTED(kb)){
            // Open the sysfs device
            kb->handle = open(path, O_RDWR);
            if(kb->handle <= 0){
                ckb_err("Failed to open USB device: %s\n", strerror(errno));
                kb->handle = 0;
                pthread_mutex_unlock(dmutex(kb));
                return -1;
            } else {
                // Set up device
                kb->udev = dev;
                kb->vendor = vendor;
                kb->product = product;
                strncpy(kbsyspath[index], syspath, FILENAME_MAX);
                // Mutex remains locked
                setupusb(kb);
                return 0;
            }
        }
        pthread_mutex_unlock(dmutex(kb));
    }
    ckb_err("No free devices\n");
    return -1;
}
Ejemplo n.º 3
0
Archivo: usb_mac.c Proyecto: jsnel/ckb
void openusb(usbdevice* kb, short vendor, short product){
    kb->lastkeypress = KEY_NONE;
    if(IS_RGB(vendor, product))
        // Handle 3 is the control handle
        kb->handle = kb->handles[3];
    else
        // Non RGB keyboards don't have one, so just use 0
        kb->handle = kb->handles[0];

    // Set up the device
    int setup = setupusb(kb, vendor, product);
    if(setup == -1 || (setup && usb_tryreset(kb))){
        closehandle(kb);
        pthread_mutex_unlock(&kb->mutex);
        pthread_mutex_destroy(&kb->mutex);
        pthread_mutex_destroy(&kb->keymutex);
        return;
    }

    // Start handling HID reports for the input
    IOHIDDeviceRegisterInputReportCallback(kb->handles[0], kb->urbinput, 8, reportcallback, kb);
    if(IS_RGB(vendor, product))
        IOHIDDeviceRegisterInputReportCallback(kb->handles[1], kb->urbinput + 8, 21, reportcallback, kb);
    else
        IOHIDDeviceRegisterInputReportCallback(kb->handles[1], kb->urbinput + 8, 4, reportcallback, kb);
    if(IS_RGB(vendor, product))
        IOHIDDeviceRegisterInputReportCallback(kb->handles[2], kb->kbinput, MSG_SIZE, reportcallback, kb);
    else
        IOHIDDeviceRegisterInputReportCallback(kb->handles[2], kb->urbinput + 8 + 4, 15, 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);
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
usbdevice* usbadd(hid_dev_t handle, io_object_t** rm_notify){
    // Get the model and serial number
    long idvendor = V_CORSAIR, idproduct = usbgetlong(handle, CFSTR(kIOHIDProductIDKey));
    // Each keyboard generates multiple match events (one for each endpoint)
    // Use the location ID key to group the handles together
    long location = usbgetlong(handle, CFSTR(kIOHIDLocationIDKey));

    // Look for any partially-set up boards matching this device
    int index = -1;
    for(int i = 1; i < DEV_MAX; i++){
        if(pthread_mutex_trylock(devmutex + i))
            // If the mutex is locked then the device is obviously set up already, keep going
            continue;
        if(keyboard[i].handle == INCOMPLETE
                && keyboard[i].vendor == idvendor && keyboard[i].product == idproduct
                && keyboard[i].location_id == location){
            // Matched; continue setting up this device
            index = i;
            // Device mutex remains locked
            break;
        }
        pthread_mutex_unlock(devmutex + i);
    }
    // If none was found, grab the first free device
    if(index == -1){
        for(int i = 1; i < DEV_MAX; i++){
            if(pthread_mutex_trylock(devmutex + i))
                continue;
            if(!keyboard[i].handle){
                // Mark the device as in use and print out a message
                index = i;
                keyboard[i].handle = INCOMPLETE;
                keyboard[i].location_id = location;
                keyboard[i].vendor = idvendor;
                keyboard[i].product = idproduct;
                // Read the serial number and name
                usbgetstr(handle, CFSTR(kIOHIDSerialNumberKey), keyboard[i].serial, SERIAL_LEN);
                usbgetstr(handle, CFSTR(kIOHIDProductKey), keyboard[i].name, KB_NAME_LEN);
                ckb_info("Connecting %s (S/N: %s)\n", keyboard[i].name, keyboard[i].serial);
                // Device mutex remains locked
                break;
            }
            pthread_mutex_unlock(devmutex + i);
        }
    }
    if(index == -1){
        ckb_err("No free devices\n");
        return 0;
    }
    usbdevice* kb = keyboard + index;
    // There's no direct way to tell which of the endpoints this is, but there's a workaround
    // Each handle has a unique maximum packet size combination, so use that to place them
    long input = usbgetlong(handle, CFSTR(kIOHIDMaxInputReportSizeKey));
    long output = usbgetlong(handle, CFSTR(kIOHIDMaxOutputReportSizeKey));
    long feature = usbgetlong(handle, CFSTR(kIOHIDMaxFeatureReportSizeKey));

    int handle_idx;
    // Handle 0 is for BIOS mode input (RGB) or non-RGB key input
    if(((input == 8 && output == 1)             // Keyboards
            || (input == 7 && output == 0))     // Mice
            && feature == 0)
        handle_idx = 0;
    // Handle 1 is for standard HID input (RGB) or media keys (non-RGB)
    else if(((input == 21 || input == 10) && output == 1 && feature == 1)
            || (input == 4 && output == 0 && feature == 0))
        handle_idx = 1;
    // Handle 2 is for Corsair inputs, unused on non-RGB
    else if(((input == 64 || input == 15) && output == 0 && feature == 0)
            || (input == 64 && output == 64 && feature == 0))           // FW >= 1.20
        handle_idx = 2;
    // Handle 3 is for controlling the device (only exists for RGB)
    else if((input == 0 && output == 0 && feature == 64)
            || (input == 64 && output == 64 && feature == 64))          // FW >= 1.20
        handle_idx = 3;
    else {
        ckb_warn("Got unknown handle (I: %d, O: %d, F: %d)\n", (int)input, (int)output, (int)feature);
        return 0;
    }

    // If all handles have been set up, finish initializing the keyboard
    kb->handles[handle_idx] = handle;
    if(kb->handles[0] && kb->handles[1] && kb->handles[2]
            && (kb->handles[3] || !IS_RGB(idvendor, idproduct)))
        setupusb(kb);
    else
        pthread_mutex_unlock(devmutex + index);
    *rm_notify = kb->rm_notify + handle_idx;
    return kb;
}