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); }