Beispiel #1
0
int setactive_mouse(usbdevice* kb, int active){
    if(NEEDS_FW_UPDATE(kb))
        return 0;
    uchar msg[2][MSG_SIZE] = {
        { 0x07, 0x04, 0 },                                                          // Disables or enables HW control for DPI and Sniper button
        { 0x07, 0x40, 0x08, 0,
          1, 0x80, 2, 0x80, 3, 0x80, 4, 0x80, 5, 0x80, 6, 0x80, 7, 0x80, 8, 0x80 }, // Enable button input. This is similar to the keyboard input selection, but we want everything to come through the HID reports.
    };
    if(active)
        // Put the mouse into SW mode
        msg[0][2] = 2;
    else
        // Restore HW mode
        msg[0][2] = 1;
    pthread_mutex_lock(imutex(kb));
    kb->active = !!active;
    kb->profile->lastlight.forceupdate = 1;
    // Clear input
    memset(&kb->input.keys, 0, sizeof(kb->input.keys));
    inputupdate(kb);
    pthread_mutex_unlock(imutex(kb));
    if(!usbsend(kb, msg[0], 1))
        return -1;
    if(active && !usbsend(kb, msg[1], 1))
        return -1;
    return 0;
}
Beispiel #2
0
int _usbrecv(usbdevice* kb, const uchar* out_msg, uchar* in_msg, const char* file, int line){
    // Try a maximum of 3 times
    for(int try = 0; try < 5; try++){
        // Send the output message
        DELAY_SHORT(kb);
        int res = os_usbsend(kb, out_msg, 1, file, line);
        if(res == 0)
            return 0;
        else if(res == -1){
            // Retry on temporary failure
            if(reset_stop)
                return 0;
            DELAY_LONG(kb);
            continue;
        }
        // Wait for the response
        DELAY_MEDIUM(kb);
        res = os_usbrecv(kb, in_msg, file, line);
        if(res == 0)
            return 0;
        else if(res != -1)
            return res;
        if(reset_stop || hwload_mode != 2)
            return 0;
        DELAY_LONG(kb);
    }
    // Give up
    ckb_err_fn("Too many send/recv failures. Dropping.\n", file, line);
    return 0;
}

int closeusb(usbdevice* kb){
    pthread_mutex_lock(imutex(kb));
    if(kb->handle){
        int index = INDEX_OF(kb, keyboard);
        ckb_info("Disconnecting %s%d\n", devpath, index);
        os_inputclose(kb);
        updateconnected();
        // Close USB device
        os_closeusb(kb);
    } else
        updateconnected();
    rmdevpath(kb);

    // Wait for thread to close
    pthread_mutex_unlock(imutex(kb));
    pthread_mutex_unlock(dmutex(kb));
    pthread_join(kb->thread, 0);
    pthread_mutex_lock(dmutex(kb));

    // Delete the profile and the control path
    if(!kb->vtable)
        return 0;
    kb->vtable->freeprofile(kb);
    memset(kb, 0, sizeof(usbdevice));
    return 0;
}
Beispiel #3
0
void cmd_notify(usbdevice* kb, usbmode* mode, int nnumber, int keyindex, const char* toggle){
    if(keyindex >= N_KEYS_INPUT)
        return;
    pthread_mutex_lock(imutex(kb));
    if(!strcmp(toggle, "on") || *toggle == 0)
        SET_KEYBIT(mode->notify[nnumber], keyindex);
    else if(!strcmp(toggle, "off"))
        CLEAR_KEYBIT(mode->notify[nnumber], keyindex);
    pthread_mutex_unlock(imutex(kb));
}
Beispiel #4
0
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;
}
Beispiel #5
0
void* os_inputmain(void* context){
    usbdevice* kb = context;
    int index = INDEX_OF(kb, keyboard);
    // Schedule async events for the device on this thread
    CFRunLoopRef runloop = CFRunLoopGetCurrent();
    int count = (IS_RGB(kb->vendor, kb->product)) ? 4 : 3;
    for(int i = 0; i < count; i++){
        CFTypeRef eventsource;
        kern_return_t res = (*kb->handles[i])->getAsyncEventSource(kb->handles[i], &eventsource);
        if(res != kIOReturnSuccess){
            ckb_err("Failed to start input thread for %s%d: %x\n", devpath, index, res);
            return 0;
        }
        if(CFGetTypeID(eventsource) == CFRunLoopSourceGetTypeID())
            CFRunLoopAddSource(runloop, (CFRunLoopSourceRef)eventsource, kCFRunLoopDefaultMode);
        else if(CFGetTypeID(eventsource) == CFRunLoopTimerGetTypeID())
            CFRunLoopAddTimer(runloop, (CFRunLoopTimerRef)eventsource, kCFRunLoopDefaultMode);
    }
    ckb_info("Starting input thread for %s%d\n", devpath, index);

    // Start getting reports
    uint8_t* urbinput[] = { malloc(8), malloc(32), malloc(MSG_SIZE) };
    (*kb->handles[0])->setInputReportCallback(kb->handles[0], urbinput[0], 8, intreport, kb, 0);
    if(IS_RGB(kb->vendor, kb->product)){
        (*kb->handles[1])->setInputReportCallback(kb->handles[1], urbinput[1], 21, intreport, kb, 0);
        (*kb->handles[2])->setInputReportCallback(kb->handles[2], urbinput[2], MSG_SIZE, intreport, kb, 0);
    } else {
        (*kb->handles[1])->setInputReportCallback(kb->handles[1], urbinput[1], 4, intreport, kb, 0);
        (*kb->handles[2])->setInputReportCallback(kb->handles[2], urbinput[2], 15, intreport, kb, 0);
    }

    // Run the run loop for up to 2ms at a time, then check for key repeats
    while(1){
        CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002, false);
        pthread_mutex_lock(imutex(kb));
        if(!IS_CONNECTED(kb)){
            // Make sure the device hasn't disconnected
            pthread_mutex_unlock(imutex(kb));
            break;
        }
        keyretrigger(kb);
        pthread_mutex_unlock(imutex(kb));
    }

    // Clean up
    ckb_info("Stopping input thread for %s%d\n", devpath, index);
    free(urbinput[0]);
    free(urbinput[1]);
    free(urbinput[2]);
    return 0;
}
Beispiel #6
0
static void intreport(void* context, IOReturn result, void* sender, IOHIDReportType reporttype, uint32_t reportid, uint8_t* data, CFIndex length){
    usbdevice* kb = context;
    pthread_mutex_lock(imutex(kb));
    if(IS_MOUSE(kb->vendor, kb->product)){
        if(length == 10)
            hid_mouse_translate(kb->input.keys, &kb->input.rel_x, &kb->input.rel_y, -2, length, data);
    } else if(HAS_FEATURES(kb, FEAT_RGB)){
        switch(length){
        case 8:
            // RGB EP 1: 6KRO (BIOS mode) input
            hid_kb_translate(kb->input.keys, -1, length, data);
            break;
        case 21:
        case 5:
            // RGB EP 2: NKRO (non-BIOS) input. Accept only if keyboard is inactive
            if(!kb->active)
                hid_kb_translate(kb->input.keys, -2, length, data);
            break;
        case MSG_SIZE:
            // RGB EP 3: Corsair input
            memcpy(kb->input.keys, data, N_KEYBYTES_KB);
            break;
        }
    } else {
        switch(length){
        case 8:
            // Non-RGB EP 1: 6KRO input
            hid_kb_translate(kb->input.keys, 1, length, data);
            break;
        case 4:
            // Non-RGB EP 2: media keys
            hid_kb_translate(kb->input.keys, 2, length, data);
            break;
        case 15:
            // Non-RGB EP 3: NKRO input
            hid_kb_translate(kb->input.keys, 3, length, data);
            break;
        }
    }
    inputupdate(kb);
    pthread_mutex_unlock(imutex(kb));
}
Beispiel #7
0
void setupusb(usbdevice* kb){
    pthread_mutex_lock(imutex(kb));
    if(pthread_create(&kb->thread, 0, _setupusb, kb))
        ckb_err("Failed to create USB thread\n");
}
Beispiel #8
0
void cmd_get(usbdevice* kb, usbmode* mode, int nnumber, int dummy, const char* setting){
    pthread_mutex_lock(imutex(kb));
    _cmd_get(kb, mode, nnumber, setting);
    pthread_mutex_unlock(imutex(kb));
}
Beispiel #9
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;
}