Example #1
0
File: usb.c Project: gtjoseph/ckb
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;
}
Example #2
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);
}
Example #3
0
File: usb.c Project: gtjoseph/ckb
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;
}
Example #4
0
int makedevpath(int index){
    usbdevice* kb = keyboard + index;
    // Create the control path
    char path[strlen(devpath) + 2];
    snprintf(path, sizeof(path), "%s%d", devpath, index);
    if(rm_recursive(path) != 0 && errno != ENOENT){
        printf("Error: Unable to delete %s: %s\n", path, strerror(errno));
        return -1;
    }
    if(mkdir(path, S_READDIR) != 0){
        rm_recursive(path);
        printf("Error: Unable to create %s: %s\n", path, strerror(errno));
        return -1;
    }
    // Create command FIFO
    char fifopath[sizeof(path) + 4];
    snprintf(fifopath, sizeof(fifopath), "%s/cmd", path);
    if(mkfifo(fifopath, S_READWRITE) != 0 || (kb->fifo = open(fifopath, O_RDONLY | O_NONBLOCK)) <= 0){
        rm_recursive(path);
        printf("Error: Unable to create %s: %s\n", fifopath, strerror(errno));
        return -1;
    }
    if(kb->model == -1){
        // Root keyboard: write a list of devices
        updateconnected();
    } else {
        // Write the model and serial to files (doesn't apply to root keyboard)
        char mpath[sizeof(path) + 6], spath[sizeof(path) + 7];
        snprintf(mpath, sizeof(mpath), "%s/model", path);
        snprintf(spath, sizeof(spath), "%s/serial", path);
        FILE* mfile = fopen(mpath, "w");
        if(mfile){
            fputs(kb->name, mfile);
            fputc('\n', mfile);
            fclose(mfile);
            chmod(mpath, S_READ);
        } else {
            printf("Warning: Unable to create %s: %s\n", mpath, strerror(errno));
        }
        FILE* sfile = fopen(spath, "w");
        if(sfile){
            fputs(kb->setting.serial, sfile);
            fputc('\n', sfile);
            fclose(sfile);
            chmod(spath, S_READ);
        } else {
            printf("Warning: Unable to create %s: %s\n", spath, strerror(errno));
        }
    }
    return 0;
}
Example #5
0
File: usb_mac.c Project: 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);
}
Example #6
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;
}