// 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) { #define MAX_OS_FD_LENGTH 256 int i, r; uint8_t os_desc[MAX_OS_FD_LENGTH]; uint32_t length; void* le_type_punning_IS_fine; struct { const char* desc; uint8_t recipient; uint16_t index; uint16_t header_size; } os_fd[2] = { {"Extended Compat ID", LIBUSB_RECIPIENT_DEVICE, 0x0004, 0x10}, {"Extended Properties", LIBUSB_RECIPIENT_INTERFACE, 0x0005, 0x0A} }; if (iface_number < 0) return; // WinUSB has a limitation that forces wIndex to the interface number when issuing // an Interface Request. To work around that, we can force a Device Request for // the Extended Properties, assuming the device answers both equally. if (force_device_request) os_fd[1].recipient = LIBUSB_RECIPIENT_DEVICE; for (i=0; i<2; i++) { printf("\nReading %s OS Feature Descriptor (wIndex = 0x%04d):\n", os_fd[i].desc, os_fd[i].index); // Read the header part r = libusb_control_transfer(handle, (uint8_t)(LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_VENDOR|os_fd[i].recipient), bRequest, (uint16_t)(((iface_number)<< 8)|0x00), os_fd[i].index, os_desc, os_fd[i].header_size, 1000); if (r < os_fd[i].header_size) { perr(" Failed: %s", (r<0)?libusb_strerror((enum libusb_error)r):"header size is too small"); return; } le_type_punning_IS_fine = (void*)os_desc; length = *((uint32_t*)le_type_punning_IS_fine); if (length > MAX_OS_FD_LENGTH) { length = MAX_OS_FD_LENGTH; } // Read the full feature descriptor r = libusb_control_transfer(handle, (uint8_t)(LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_VENDOR|os_fd[i].recipient), bRequest, (uint16_t)(((iface_number)<< 8)|0x00), os_fd[i].index, os_desc, (uint16_t)length, 1000); if (r < 0) { perr(" Failed: %s", libusb_strerror((enum libusb_error)r)); return; } else { display_buffer_hex(os_desc, r); } } }
// 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) { #define MAX_OS_FD_LENGTH 256 int i, r; uint8_t os_desc[MAX_OS_FD_LENGTH]; uint32_t length; void* le_type_punning_IS_fine; struct { const char* desc; uint16_t index; uint16_t header_size; } os_fd[2] = { {"Extended Compat ID", 0x0004, 0x10}, {"Extended Properties", 0x0005, 0x0A} }; if (iface_number < 0) return; for (i=0; i<2; i++) { printf("\nReading %s OS Feature Descriptor (wIndex = 0x%04d):\n", os_fd[i].desc, os_fd[i].index); // Read the header part r = libusb_control_transfer(handle, (uint8_t)(LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE), bRequest, (uint16_t)(((iface_number)<< 8)|0x00), os_fd[i].index, os_desc, os_fd[i].header_size, 1000); if (r < os_fd[i].header_size) { perr(" Failed: %s", (r<0)?libusb_error_name((enum libusb_error)r):"header size is too small"); return; } le_type_punning_IS_fine = (void*)os_desc; length = *((uint32_t*)le_type_punning_IS_fine); if (length > MAX_OS_FD_LENGTH) { length = MAX_OS_FD_LENGTH; } // Read the full feature descriptor r = libusb_control_transfer(handle, (uint8_t)(LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE), bRequest, (uint16_t)(((iface_number)<< 8)|0x00), os_fd[i].index, os_desc, (uint16_t)length, 1000); if (r < 0) { perr(" Failed: %s", libusb_error_name((enum libusb_error)r)); return; } else { display_buffer_hex(os_desc, r); } } }
/* * Display a human readable version of a message in the log */ DEFAULT_VISIBILITY int libcec_decode_message(uint8_t* message, size_t length) { uint8_t src, dst; if ((message == NULL) || (length < 1)) { return LIBCEC_ERROR_INVALID_PARAM; } src = message[0] >> 4; dst = message[0] & 0x0F; // Polling Message if (length == 1) { ceci_info(" o %1X->%1X: <Polling Message>", src, dst); return LIBCEC_SUCCESS; } if ((msg_props[message[1]] & 0x60) == 0) { ceci_warn("unsupported Opcode: %02X", message[1]); return LIBCEC_ERROR_NOT_SUPPORTED; } // Broadcasted messages received as directed messages if ((dst == 0x0F) && ((msg_props[message[1]] & 0x40) == 0)) { ceci_warn("broadcast message received as directed: %02X", message[1]); return LIBCEC_ERROR_OTHER; } if ((dst != 0x0F) && ((msg_props[message[1]] & 0x20) == 0)) { ceci_warn("directed message received as broadcast: %02X", message[1]); return LIBCEC_ERROR_OTHER; } if ( (length-2 < msg_min_max[msg_props[message[1]]&0x1F][0]) || (length-2 > msg_min_max[msg_props[message[1]]&0x1F][1]) ) { ceci_warn("invalid payload length for opcode: %02X", message[1]); return LIBCEC_ERROR_INVALID_PARAM; } ceci_info(" o %1X->%1X: <%s>", src, dst, msg_description[msg_index[message[1]]]); display_buffer_hex(message+1, length-1); return LIBCEC_SUCCESS; }
static 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_strerror((enum libusb_error)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_strerror((enum libusb_error)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_strerror((enum libusb_error)r)); } free(report_buffer); } return 0; }
// Mass Storage device to test bulk transfers (non destructive test) static int test_mass_storage(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t endpoint_out) { int r, size; uint8_t lun; uint32_t expected_tag; uint32_t i, max_lba, block_size; double device_size; uint8_t cdb[16]; // SCSI Command Descriptor Block uint8_t buffer[64]; char vid[9], pid[9], rev[5]; unsigned char *data; FILE *fd; printf("Reading Max LUN:\n"); r = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE, BOMS_GET_MAX_LUN, 0, 0, &lun, 1, 1000); // Some devices send a STALL instead of the actual value. // In such cases we should set lun to 0. if (r == 0) { lun = 0; } else if (r < 0) { perr(" Failed: %s", libusb_strerror((enum libusb_error)r)); } printf(" Max LUN = %d\n", lun); // Send Inquiry printf("Sending Inquiry:\n"); memset(buffer, 0, sizeof(buffer)); memset(cdb, 0, sizeof(cdb)); cdb[0] = 0x12; // Inquiry cdb[4] = INQUIRY_LENGTH; send_mass_storage_command(handle, endpoint_out, lun, cdb, LIBUSB_ENDPOINT_IN, INQUIRY_LENGTH, &expected_tag); CALL_CHECK(libusb_bulk_transfer(handle, endpoint_in, (unsigned char*)&buffer, INQUIRY_LENGTH, &size, 1000)); printf(" received %d bytes\n", size); // The following strings are not zero terminated for (i=0; i<8; i++) { vid[i] = buffer[8+i]; pid[i] = buffer[16+i]; rev[i/2] = buffer[32+i/2]; // instead of another loop } vid[8] = 0; pid[8] = 0; rev[4] = 0; printf(" VID:PID:REV \"%8s\":\"%8s\":\"%4s\"\n", vid, pid, rev); if (get_mass_storage_status(handle, endpoint_in, expected_tag) == -2) { get_sense(handle, endpoint_in, endpoint_out); } // Read capacity printf("Reading Capacity:\n"); memset(buffer, 0, sizeof(buffer)); memset(cdb, 0, sizeof(cdb)); cdb[0] = 0x25; // Read Capacity send_mass_storage_command(handle, endpoint_out, lun, cdb, LIBUSB_ENDPOINT_IN, READ_CAPACITY_LENGTH, &expected_tag); CALL_CHECK(libusb_bulk_transfer(handle, endpoint_in, (unsigned char*)&buffer, READ_CAPACITY_LENGTH, &size, 1000)); printf(" received %d bytes\n", size); max_lba = be_to_int32(&buffer[0]); block_size = be_to_int32(&buffer[4]); device_size = ((double)(max_lba+1))*block_size/(1024*1024*1024); printf(" Max LBA: %08X, Block Size: %08X (%.2f GB)\n", max_lba, block_size, device_size); if (get_mass_storage_status(handle, endpoint_in, expected_tag) == -2) { get_sense(handle, endpoint_in, endpoint_out); } // coverity[tainted_data] data = (unsigned char*) calloc(1, block_size); if (data == NULL) { perr(" unable to allocate data buffer\n"); return -1; } // Send Read printf("Attempting to read %d bytes:\n", block_size); memset(cdb, 0, sizeof(cdb)); cdb[0] = 0x28; // Read(10) cdb[8] = 0x01; // 1 block send_mass_storage_command(handle, endpoint_out, lun, cdb, LIBUSB_ENDPOINT_IN, block_size, &expected_tag); libusb_bulk_transfer(handle, endpoint_in, data, block_size, &size, 5000); printf(" READ: received %d bytes\n", size); if (get_mass_storage_status(handle, endpoint_in, expected_tag) == -2) { get_sense(handle, endpoint_in, endpoint_out); } else { display_buffer_hex(data, size); if ((binary_dump) && ((fd = fopen(binary_name, "w")) != NULL)) { if (fwrite(data, 1, (size_t)size, fd) != (unsigned int)size) { perr(" unable to write binary data\n"); } fclose(fd); } } free(data); return 0; }