diff options
author | Pete Batard <pete@akeo.ie> | 2012-05-11 23:34:03 +0100 |
---|---|---|
committer | Pete Batard <pete@akeo.ie> | 2012-05-28 10:57:51 +0100 |
commit | 3fae93a941669be8a87ca49dd09f836d2d9647aa (patch) | |
tree | 43e3a8db0401e349e19b5bdd389cae0ce325b41d /examples | |
parent | 500b037e7dd6784f9db0bab5f1c3ff417ed875e2 (diff) | |
download | libusb-3fae93a941669be8a87ca49dd09f836d2d9647aa.tar.gz |
Windows: Restore HID support
Diffstat (limited to 'examples')
-rw-r--r-- | examples/xusb.c | 171 |
1 files changed, 169 insertions, 2 deletions
diff --git a/examples/xusb.c b/examples/xusb.c index 08de6ba..3f00f34 100644 --- a/examples/xusb.c +++ b/examples/xusb.c @@ -80,9 +80,14 @@ static int perr(char const *format, ...) // HID Class-Specific Requests values. See section 7.2 of the HID specifications #define HID_GET_REPORT 0x01 +#define HID_GET_IDLE 0x02 +#define HID_GET_PROTOCOL 0x03 #define HID_SET_REPORT 0x09 +#define HID_SET_IDLE 0x0A +#define HID_SET_PROTOCOL 0x0B #define HID_REPORT_TYPE_INPUT 0x01 #define HID_REPORT_TYPE_OUTPUT 0x02 +#define HID_REPORT_TYPE_FEATURE 0x03 // Mass Storage Requests values. See section 3 of the Bulk-Only Mass Storage Class specifications #define BOMS_RESET 0xFF @@ -132,6 +137,7 @@ enum test_type { USE_PS3, USE_XBOX, USE_SCSI, + USE_HID, } test_mode; uint16_t VID, PID; @@ -525,6 +531,157 @@ static int test_mass_storage(libusb_device_handle *handle, uint8_t endpoint_in, return 0; } +// HID +int get_hid_record_size(uint8_t *hid_report_descriptor, int size, int type) +{ + uint8_t i, j = 0; + uint8_t offset; + int record_size[3] = {0, 0, 0}; + int nb_bits = 0, nb_items = 0; + bool found_record_marker; + + found_record_marker = false; + for (i = hid_report_descriptor[0]+1; i < size; i += offset) { + offset = (hid_report_descriptor[i]&0x03) + 1; + if (offset == 4) + offset = 5; + switch (hid_report_descriptor[i] & 0xFC) { + case 0x74: // bitsize + nb_bits = hid_report_descriptor[i+1]; + break; + case 0x94: // count + nb_items = 0; + for (j=1; j<offset; j++) { + nb_items = ((uint32_t)hid_report_descriptor[i+j]) << (8*(j-1)); + } + break; + case 0x80: // input + found_record_marker = true; + j = 0; + break; + case 0x90: // output + found_record_marker = true; + j = 1; + break; + case 0xb0: // feature + found_record_marker = true; + j = 2; + break; + case 0xC0: // end of collection + nb_items = 0; + nb_bits = 0; + break; + default: + continue; + } + if (found_record_marker) { + found_record_marker = false; + record_size[j] += nb_items*nb_bits; + } + } + if ((type < HID_REPORT_TYPE_INPUT) || (type > HID_REPORT_TYPE_FEATURE)) { + return 0; + } else { + return (record_size[type - HID_REPORT_TYPE_INPUT]+7)/8; + } +} + +int test_hid(libusb_device_handle *handle, uint8_t endpoint_in) +{ + int r, size, descriptor_size; + uint8_t hid_report_descriptor[256]; + uint8_t *report_buffer; + FILE *fd; + + printf("\nReading HID Report Descriptors:\n"); + descriptor_size = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_STANDARD|LIBUSB_RECIPIENT_INTERFACE, + LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_DT_REPORT<<8, 0, hid_report_descriptor, sizeof(hid_report_descriptor), 1000); + if (descriptor_size < 0) { + printf(" Failed\n"); + return -1; + } + display_buffer_hex(hid_report_descriptor, descriptor_size); + if ((binary_dump) && ((fd = fopen(binary_name, "w")) != NULL)) { + if (fwrite(hid_report_descriptor, 1, descriptor_size, fd) != descriptor_size) { + printf(" Error writing descriptor to file\n"); + } + fclose(fd); + } + + size = get_hid_record_size(hid_report_descriptor, descriptor_size, HID_REPORT_TYPE_FEATURE); + if (size <= 0) { + printf("\nSkipping Feature Report readout (None detected)\n"); + } else { + report_buffer = (uint8_t*) calloc(size, 1); + if (report_buffer == NULL) { + return -1; + } + + printf("\nReading Feature Report (length %d)...\n", size); + r = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE, + HID_GET_REPORT, (HID_REPORT_TYPE_FEATURE<<8)|0, 0, report_buffer, (uint16_t)size, 5000); + if (r >= 0) { + display_buffer_hex(report_buffer, size); + } else { + switch(r) { + case LIBUSB_ERROR_NOT_FOUND: + printf(" No Feature Report available for this device\n"); + break; + case LIBUSB_ERROR_PIPE: + printf(" Detected stall - resetting pipe...\n"); + libusb_clear_halt(handle, 0); + break; + default: + printf(" Error: %s\n", libusb_error_name(r)); + break; + } + } + free(report_buffer); + } + + size = get_hid_record_size(hid_report_descriptor, descriptor_size, HID_REPORT_TYPE_INPUT); + if (size <= 0) { + printf("\nSkipping Input Report readout (None detected)\n"); + } else { + report_buffer = (uint8_t*) calloc(size, 1); + if (report_buffer == NULL) { + return -1; + } + + printf("\nReading Input Report (length %d)...\n", size); + r = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE, + HID_GET_REPORT, (HID_REPORT_TYPE_INPUT<<8)|0x00, 0, report_buffer, (uint16_t)size, 5000); + if (r >= 0) { + display_buffer_hex(report_buffer, size); + } else { + switch(r) { + case LIBUSB_ERROR_TIMEOUT: + printf(" Timeout! Please make sure you act on the device within the 5 seconds allocated...\n"); + break; + case LIBUSB_ERROR_PIPE: + printf(" Detected stall - resetting pipe...\n"); + libusb_clear_halt(handle, 0); + break; + default: + printf(" Error: %s\n", libusb_error_name(r)); + break; + } + } + + // Attempt a bulk read from endpoint 0 (this should just return a raw input report) + printf("\nTesting interrupt read using endpoint %02X...\n", endpoint_in); + r = libusb_interrupt_transfer(handle, endpoint_in, report_buffer, size, &size, 5000); + if (r >= 0) { + display_buffer_hex(report_buffer, size); + } else { + printf(" %s\n", libusb_error_name(r)); + } + + free(report_buffer); + } + return 0; +} + // Read the MS WinUSB Feature Descriptors, that are used on Windows 8 for automated driver installation static void read_ms_winsub_feature_descriptors(libusb_device_handle *handle, uint8_t bRequest, int iface_number) { @@ -654,8 +811,8 @@ static int test_device(uint16_t vid, uint16_t pid) for (k=0; k<conf_desc->usb_interface[i].altsetting[j].bNumEndpoints; k++) { endpoint = &conf_desc->usb_interface[i].altsetting[j].endpoint[k]; printf(" endpoint[%d].address: %02X\n", k, endpoint->bEndpointAddress); - // Use the first bulk IN/OUT endpoints found as default for testing - if ((endpoint->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_BULK) { + // Use the first interrupt or bulk IN/OUT endpoints as default for testing + if ((endpoint->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) & (LIBUSB_TRANSFER_TYPE_BULK | LIBUSB_TRANSFER_TYPE_INTERRUPT)) { if (endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) { if (!endpoint_in) endpoint_in = endpoint->bEndpointAddress; @@ -718,6 +875,9 @@ static int test_device(uint16_t vid, uint16_t pid) msleep(2000); CALL_CHECK(set_xbox_actuators(handle, 0, 0)); break; + case USE_HID: + test_hid(handle, endpoint_in); + break; case USE_SCSI: CALL_CHECK(test_mass_storage(handle, endpoint_in, endpoint_out)); case USE_GENERIC: @@ -803,6 +963,12 @@ int main(int argc, char** argv) PID = 0x0268; test_mode = USE_PS3; break; + case 's': + // Microsoft Sidewinder Precision Pro Joystick - 1 HID interface + VID = 0x045E; + PID = 0x0008; + test_mode = USE_HID; + break; case 'x': // Microsoft XBox Controller Type S - 1 interface VID = 0x045E; @@ -841,6 +1007,7 @@ int main(int argc, char** argv) printf(" -k: test generic Mass Storage USB device (using WinUSB)\n"); printf(" -j: test FTDI based JTAG device (using WinUSB)\n"); printf(" -p: test Sony PS3 SixAxis controller (using WinUSB)\n"); + printf(" -s: test Microsoft Sidewinder Precision Pro (using HID)\n"); printf(" -x: test Microsoft XBox Controller Type S (using WinUSB)\n"); return 0; } |