Exemplo n.º 1
0
void* os_inputmain(void* context){
    usbdevice* kb = context;
    int fd = kb->handle;
    short vendor = kb->vendor, product = kb->product;
    int index = INDEX_OF(kb, keyboard);
    ckb_info("Starting input thread for %s%d\n", devpath, index);

    // Monitor input transfers on all endpoints
    int urbcount = 3;
    struct usbdevfs_urb urbs[urbcount];
    memset(urbs, 0, sizeof(urbs));
    urbs[0].buffer_length = 8;
    if(IS_RGB(vendor, product)){
        if(IS_MOUSE(vendor, product))
            urbs[1].buffer_length = 10;
        else
            urbs[1].buffer_length = 21;
        urbs[2].buffer_length = MSG_SIZE;
        urbs[3].buffer_length = MSG_SIZE;
    } else {
        urbs[1].buffer_length = 4;
        urbs[2].buffer_length = 15;
    }
    // Submit URBs
    for(int i = 0; i < urbcount; i++){
        urbs[i].type = USBDEVFS_URB_TYPE_INTERRUPT;
        urbs[i].endpoint = 0x80 | (i + 1);
        urbs[i].buffer = malloc(urbs[i].buffer_length);
        ioctl(fd, USBDEVFS_SUBMITURB, urbs + i);
    }
    // Start monitoring input
    while(1){
        struct usbdevfs_urb* urb = 0;
        if(ioctl(fd, USBDEVFS_REAPURB, &urb)){
            if(errno == ENODEV || errno == ENOENT || errno == ESHUTDOWN)
                // Stop the thread if the handle closes
                break;
            else if(errno == EPIPE && urb){
                // On EPIPE, clear halt on the endpoint
                ioctl(fd, USBDEVFS_CLEAR_HALT, &urb->endpoint);
                // Re-submit the URB
                if(urb)
                    ioctl(fd, USBDEVFS_SUBMITURB, urb);
                urb = 0;
            }
        }
        if(urb){
            // Process input (if any)
            pthread_mutex_lock(imutex(kb));
            if(IS_MOUSE(vendor, product)){
                if(urb->endpoint == 0x82){
                    // RGB mouse input
                    hid_mouse_translate(kb->input.keys, &kb->input.rel_x, &kb->input.rel_y, -(urb->endpoint & 0xF), urb->actual_length, urb->buffer);
                }
            } else if(IS_RGB(vendor, product)){
                switch(urb->endpoint){
                case 0x81:
                    // RGB EP 1: 6KRO (BIOS mode) input
                    hid_kb_translate(kb->input.keys, -1, urb->actual_length, urb->buffer);
                    break;
                case 0x82:
                    // RGB EP 2: NKRO (non-BIOS) input. Accept only if keyboard is inactive
                    if(!kb->active)
                        hid_kb_translate(kb->input.keys, -2, urb->actual_length, urb->buffer);
                    break;
                case 0x83:
                    // RGB EP 3: Corsair input
                    memcpy(kb->input.keys, urb->buffer, N_KEYBYTES_KB);
                    break;
                }
            } else
                // Non-RGB input
                hid_kb_translate(kb->input.keys, urb->endpoint & 0xF, urb->actual_length, urb->buffer);
            inputupdate(kb);
            pthread_mutex_unlock(imutex(kb));
            // Re-submit the URB
            ioctl(fd, USBDEVFS_SUBMITURB, urb);
            urb = 0;
        }
    }
    // Clean up
    ckb_info("Stopping input thread for %s%d\n", devpath, index);
    for(int i = 0; i < urbcount; i++){
        ioctl(fd, USBDEVFS_DISCARDURB, urbs + i);
        free(urbs[i].buffer);
    }
    return 0;
}
Exemplo n.º 2
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;
}