def send_mass_storage_command(handle, endpoint, lun, cdb, direction, data_length, ret_tag): global _tag #int i, r; cbw = command_block_wrapper() if not cdb: return -1 if endpoint & usb.LIBUSB_ENDPOINT_IN: perr("send_mass_storage_command: cannot send command on IN endpoint\n") return -1 #ct.c_uint8 cdb_len; cdb_len = cdb_length[cdb[0]] if cdb_len == 0 or cdb_len > ct.sizeof(cbw.CBWCB): perr( "send_mass_storage_command: don't know how to handle this command ({:02X}, length {})\n", cdb[0], cdb_len) return -1 cbw.dCBWSignature[0] = 'U' cbw.dCBWSignature[1] = 'S' cbw.dCBWSignature[2] = 'B' cbw.dCBWSignature[3] = 'C' ret_tag[0] = _tag cbw.dCBWTag = _tag cbw.dCBWDataTransferLength = data_length cbw.bmCBWFlags = direction cbw.bCBWLUN = lun _tag += 1 # Subclass is 1 or 6 => cdb_len cbw.bCBWCBLength = cdb_len memcpy(cbw.CBWCB, cdb, cdb_len) i = 0 while True: # The transfer length must always be exactly 31 bytes. size = ct.c_int() r = usb.bulk_transfer(handle, endpoint, ct.cast(ct.pointer(cbw), ct.POINTER(ct.c_ubyte)), 31, ct.byref(size), 1000) if r == usb.LIBUSB_ERROR_PIPE: usb.clear_halt(handle, endpoint) i += 1 if r != usb.LIBUSB_ERROR_PIPE or i >= RETRY_MAX: break if r != usb.LIBUSB_SUCCESS: perr(" send_mass_storage_command: {}\n", usb.strerror(usb.error(r))) return -1 print(" sent {} CDB bytes".format(cdb_len)) return 0
def get_mass_storage_status(handle, endpoint, expected_tag): #int r; csw = command_status_wrapper() # The device is allowed to STALL this transfer. If it does, you have to # clear the stall and try again. i = 0 while True: size = ct.c_int() r = usb.bulk_transfer(handle, endpoint, ct.cast(ct.pointer(csw), ct.POINTER(ct.c_ubyte)), 13, ct.byref(size), 1000) if r == usb.LIBUSB_ERROR_PIPE: usb.clear_halt(handle, endpoint) i += 1 if r != usb.LIBUSB_ERROR_PIPE or i >= RETRY_MAX: break if r != usb.LIBUSB_SUCCESS: perr(" get_mass_storage_status: {}\n", usb.strerror(usb.error(r))) return -1 size = size.value if size != 13: perr(" get_mass_storage_status: received {} bytes (expected 13)\n", size) return -1 if csw.dCSWTag != expected_tag: perr( " get_mass_storage_status: mismatched tags (expected {:08X}, received {:08X})\n", expected_tag, csw.dCSWTag) return -1 # For this test, we ignore the dCSWSignature check for validity... print(" Mass Storage Status: {:02X} ({})".format( csw.bCSWStatus, "FAILED" if csw.bCSWStatus else "Success")) if csw.dCSWTag != expected_tag: return -1 if csw.bCSWStatus: # REQUEST SENSE is appropriate only if bCSWStatus is 1, meaning that the # command failed somehow. Larger values (2 in particular) mean that # the command couldn't be understood. if csw.bCSWStatus == 1: return -2 # request Get Sense else: return -1 # In theory we also should check dCSWDataResidue. But lots of devices # set it wrongly. return 0
def test_hid(handle, endpoint_in): global binary_dump global binary_name #int r; hid_report_descriptor = (ct.c_uint8 * 256)() report_buffer = ct.POINTER(ct.c_uint8) print("\nReading HID Report Descriptors:") descriptor_size = usb.control_transfer(handle, usb.LIBUSB_ENDPOINT_IN | usb.LIBUSB_REQUEST_TYPE_STANDARD | usb.LIBUSB_RECIPIENT_INTERFACE, usb.LIBUSB_REQUEST_GET_DESCRIPTOR, usb.LIBUSB_DT_REPORT << 8, 0, hid_report_descriptor, ct.sizeof(hid_report_descriptor), 1000) if descriptor_size < 0: print(" Failed") return -1 display_buffer_hex(hid_report_descriptor, descriptor_size) if binary_dump: try: fd = open(binary_name, "w") except: pass else: with fd: if fd.fwrite(hid_report_descriptor, descriptor_size) != descriptor_size: print(" Error writing descriptor to file") size = get_hid_record_size(hid_report_descriptor, descriptor_size, HID_REPORT_TYPE_FEATURE) if size <= 0: print("\nSkipping Feature Report readout (None detected)") else: report_buffer = ct.cast(calloc(size, 1), ct.POINTER(ct.c_uint8)) if not report_buffer: return -1 print("\nReading Feature Report (length {})...".format(size)) r = usb.control_transfer(handle, usb.LIBUSB_ENDPOINT_IN | usb.LIBUSB_REQUEST_TYPE_CLASS | usb.LIBUSB_RECIPIENT_INTERFACE, HID_GET_REPORT, (HID_REPORT_TYPE_FEATURE << 8) | 0, 0, report_buffer, ct.c_uint16(size), 5000) if r >= 0: display_buffer_hex(report_buffer, size) else: if r == usb.LIBUSB_ERROR_NOT_FOUND: print(" No Feature Report available for this device") elif r == usb.LIBUSB_ERROR_PIPE: print(" Detected stall - resetting pipe...") usb.clear_halt(handle, 0) else: print(" Error: {}".format(usb.strerror(usb.error(r)))) free(report_buffer) size = get_hid_record_size(hid_report_descriptor, descriptor_size, HID_REPORT_TYPE_INPUT) if size <= 0: print("\nSkipping Input Report readout (None detected)") else: report_buffer = ct.cast(calloc(size, 1), ct.POINTER(ct.c_uint8)) if not report_buffer: return -1 print("\nReading Input Report (length {})...".format(size)) r = usb.control_transfer(handle, usb.LIBUSB_ENDPOINT_IN | usb.LIBUSB_REQUEST_TYPE_CLASS | usb.LIBUSB_RECIPIENT_INTERFACE, HID_GET_REPORT, (HID_REPORT_TYPE_INPUT << 8) | 0x00, 0, report_buffer, ct.c_uint16(size), 5000) if r >= 0: display_buffer_hex(report_buffer, size) else: if r == usb.LIBUSB_ERROR_TIMEOUT: print(" Timeout! Please make sure you act on the device within the 5 seconds allocated...") elif r == usb.LIBUSB_ERROR_PIPE: print(" Detected stall - resetting pipe...") usb.clear_halt(handle, 0) else: print(" Error: {}".format(usb.strerror(usb.error(r)))) # Attempt a bulk read from endpoint 0 (this should just return a raw input report) print("\nTesting interrupt read using endpoint {:02X}...".format(endpoint_in)) r = usb.interrupt_transfer(handle, endpoint_in, report_buffer, size, ct.byref(size), 5000) if r >= 0: display_buffer_hex(report_buffer, size) else: print(" {}".format(usb.strerror(usb.error(r)))) free(report_buffer) return 0