int VoodooI2CHIDDevice::i2c_hid_fetch_hid_descriptor(i2c_hid *ihid) {
    struct i2c_hid_desc *hdesc = &ihid->hdesc;
    //UInt dsize;
    int ret;
    
    ret = i2c_hid_command(ihid, &hid_descr_cmd, ihid->hdesc_buffer, sizeof(struct i2c_hid_desc));
    
    if (ret)
    {
        IOLog("%s::%s::hid_descr_cmd failed\n", getName(), hid_device->name);
        return -1;
    }
    
    if((UInt16)(hdesc->bcdVersion) != 0x0100) {
        IOLog("%s::%s::Unexpected HID descriptor bcdVersion %x\n", getName(), hid_device->name, (UInt16)(hdesc->bcdVersion));
        return -1;
    }
    
    //dsize = (UInt16)(hdesc->wHIDDescLength);
    
    //if (dsize != sizeof(struct i2c_hid_desc)) {
    //    IOLog("%s::%s::weird size of HID descriptor\n", getName(), _dev->name);
    //    return -1;
    //}
    
    return 0;
}
bool VoodooI2CHIDDevice::i2c_hid_get_report_descriptor(i2c_hid *ihid){
    UInt rsize;
    int ret;
    
    IOLog("reg: 0x%x\n",ihid->hdesc.wReportDescRegister);
    
    rsize = UInt16(ihid->hdesc.wReportDescLength);
    
    unsigned char* rdesc = (unsigned char *)IOMalloc(rsize);
    
    i2c_hid_hwreset(ihid);
    
    if (!rdesc){
        return -1;
    }
    /*
    if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE){
        IOLog("%s::%s::Weird size of report descriptor (%u)\n", getName(), hid_device->name, rsize);ƒ
        return 1;
    }
    */
    
    ret = i2c_hid_command(ihid, &hid_report_desc_cmd, rdesc, rsize);
    
    if (!ret){
        IOLog("it worked!\n");
    }
    
    
    
    //_controller->registerDump(_controller->_dev);
    
    /*
    if (ret) {
        IOLog("%s::%s::Reading report descriptor failed", getName(), hid_device->name);
        return -1;
    }
    
    
    IOLog("%s::%s::Report descriptor: %s\n", getName(), hid_device->name, rdesc);
     
    */
    
    IOLog("===Report Descriptor===\n");
    for (int i = 0; i < UInt16(ihid->hdesc.wReportDescLength); i++)
        IOLog("0x%02x\n", (UInt8) rdesc[i]);
    IOLog("===Report Descriptor===\n");
    
    IOFree(rdesc, rsize);
    
    return 0;
    
};
bool VoodooI2CHIDDevice::i2c_hid_hwreset(i2c_hid *ihid) {
    int ret;
    
    ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
    
    if (ret)
        return ret;

    ret = i2c_hid_command(ihid, &hid_reset_cmd, NULL, 0);
    if (ret) {
        i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
        return ret;
    }
    
    return 0;
};
void VoodooI2CHIDDevice::i2c_hid_get_input(OSObject* owner, IOTimerEventSource* sender) {
//    IOLog("getting input\n");
    if (hid_device->reading)
        return;

    UInt rsize;
    int ret;

    rsize = UInt16(ihid->hdesc.wMaxInputLength);
    
    unsigned char* rdesc = (unsigned char *)IOMalloc(rsize);
    
    ret = i2c_hid_command(ihid, &hid_input_cmd, rdesc, rsize);

//    IOLog("===Input (%d)===\n", rsize);
//    for (int i = 0; i < rsize; i++)
//        IOLog("0x%02x ", (UInt8) rdesc[i]);
//    IOLog("\n");

    int return_size = rdesc[0] | rdesc[1] << 8;
    if (return_size == 0) {
        /* host or device initiated RESET completed */
        // test/clear bit?
        hid_device->timerSource->setTimeoutMS(10);
        return;
    }

    if (return_size > rsize) {
        IOLog("%s: Incomplete report %d/%d\n", __func__, rsize, return_size);
    }

    IOBufferMemoryDescriptor *buffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, return_size);
    buffer->writeBytes(0, rdesc + 2, return_size - 2);

    IOReturn err = _wrapper->handleReport(buffer, kIOHIDReportTypeInput);
    if (err != kIOReturnSuccess)
        IOLog("Error handling report: 0x%.8x\n", err);

    buffer->release();

    IOFree(rdesc, rsize);
    
    hid_device->timerSource->setTimeoutMS(10);
}
bool VoodooI2CHIDDevice::i2c_hid_hwreset(i2c_hid *ihid) {
    int ret;
    unsigned char buf[2];
    
    ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
    
    if (ret)
        return ret;

    /* Need to read back two NULL bytes after reset! */
    ret = i2c_hid_command(ihid, &hid_reset_cmd, buf, 2);
    if (ret || (*buf != 0) || (*(buf+1) != 0))
    {
        i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
        return ret;
    }
    
    return 0;
};
void VoodooI2CHIDDevice::write_report_descriptor_to_buffer(IOBufferMemoryDescriptor *buffer){
    UInt rsize;
    int ret;
    
    IOLog("Report descriptor register: 0x%x\n",ihid->hdesc.wReportDescRegister);
    
    rsize = UInt16(ihid->hdesc.wReportDescLength);
    
    unsigned char* rdesc = (unsigned char *)IOMalloc(rsize);
    
    i2c_hid_hwreset(ihid);
    
    ret = i2c_hid_command(ihid, &hid_report_desc_cmd, rdesc, rsize);

    if (!ret)
        IOLog("Report descriptor was fetched\n");

    buffer->writeBytes(0, rdesc, rsize);
    IOLog("Report Descriptor written to buffer (%d)\n", rsize);

    IOFree(rdesc, rsize);
}
void VoodooI2CHIDDevice::i2c_hid_get_input(OSObject* owner, IOTimerEventSource* sender) {
//    IOLog("getting input\n");
    UInt rsize;
    int ret;
    static unsigned char* rdesc_prev = NULL;
    static UInt rsize_prev = 0;
    bool new_report = true;
    
    rsize = UInt16(ihid->hdesc.wMaxInputLength);
    
    unsigned char* rdesc = (unsigned char *)IOMalloc(rsize);
    
    ret = i2c_hid_command(ihid, &hid_input_cmd, rdesc, rsize);

//    IOLog("===Input (%d)===\n", rsize);
//    for (int i = 0; i < rsize; i++)
//        IOLog("0x%02x ", (UInt8) rdesc[i]);
//    IOLog("\n");

    int return_size = rdesc[0] | rdesc[1] << 8;
    if (return_size == 0) {
        /* host or device initiated RESET completed */
        // test/clear bit?
        hid_device->timerSource->setTimeoutMS(10);
        return;
    }

    if (return_size > rsize) {
        IOLog("%s: Incomplete report %d/%d\n", __func__, rsize, return_size);
    }

    IOBufferMemoryDescriptor *buffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, return_size);
    buffer->writeBytes(0, rdesc + 2, return_size - 2);

#define FILTER_REPEATED_REPORTS /* Needed on my ASUS/Skylake ELAN1000 */

#ifdef FILTER_REPEATED_REPORTS
    /* Compare to previous report */
    if (rdesc_prev)
    {
        /* See if they're different! */
        if (rsize == rsize_prev)
        {
            if (memcmp(rdesc_prev, rdesc, rsize))
            {
                new_report = true;
            } else {
                new_report = false;
            }
        } else {
            new_report = true;
        }

        /* We don't need the previous report anymore */
        IOFree(rdesc_prev, rsize_prev);
    }
    else
    {
        new_report = true;
    }

    /* Keep for next comparison */
    rdesc_prev = rdesc;
    rsize_prev = rsize;

    if (new_report)
    {
        IOReturn err = _wrapper->handleReport(buffer, kIOHIDReportTypeInput);
        if (err != kIOReturnSuccess)
            IOLog("Error handling report: 0x%.8x\n", err);
    }

#else /* non filtered for repeating reports */
    IOReturn err = _wrapper->handleReport(buffer, kIOHIDReportTypeInput);
    if (err != kIOReturnSuccess)
        IOLog("Error handling report: 0x%.8x\n", err);
#endif

    buffer->release();

#ifndef FILTER_REPEATED_REPORTS
    IOFree(rdesc, rsize);
#endif

    hid_device->timerSource->setTimeoutMS(10);
}