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 err_exit(errcode): perr(" {}\n", usb.strerror(usb.error(errcode))) return -1
def read_ms_winsub_feature_descriptors(handle, bRequest, iface_number): # Read the MS WinUSB Feature Descriptors, that are used on Windows 8 for automated driver installation MAX_OS_FD_LENGTH = 256 #int r; os_desc = (ct.c_uint8 * MAX_OS_FD_LENGTH)() class struct_os_fd(ct.Structure): _fields_ = [ ("desc", ct.c_char_p), ("recipient", ct.c_uint8), ("index", ct.c_uint16), ("header_size", ct.c_uint16), ] os_fd = [ struct_os_fd(b"Extended Compat ID", usb.LIBUSB_RECIPIENT_DEVICE, 0x0004, 0x10), struct_os_fd(b"Extended Properties", usb.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 = usb.LIBUSB_RECIPIENT_DEVICE for i in range(2): print("\nReading {} OS Feature Descriptor (wIndex = 0x%04d):".format( os_fd[i].desc, os_fd[i].index)) # Read the header part r = usb.control_transfer(handle, ct.c_uint8(usb.LIBUSB_ENDPOINT_IN | usb.LIBUSB_REQUEST_TYPE_VENDOR | os_fd[i].recipient), bRequest, ct.c_uint16((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: {}", usb.strerror(usb.error(r)) if r < 0 else "header size is too small") return le_type_punning_IS_fine = ct.cast(os_desc, ct.c_void_p) length = ct.cast(le_type_punning_IS_fine, ct.POINTER(ct.c_uint32))[0].value # ct.c_uint32 length = min(length, MAX_OS_FD_LENGTH) # Read the full feature descriptor r = usb.control_transfer(handle, ct.c_uint8(usb.LIBUSB_ENDPOINT_IN | usb.LIBUSB_REQUEST_TYPE_VENDOR | os_fd[i].recipient), bRequest, ct.c_uint16((iface_number << 8) | 0x00), os_fd[i].index, os_desc, ct.c_uint16(length), 1000) if r < 0: perr(" Failed: {}", usb.strerror(usb.error(r))) return else: display_buffer_hex(os_desc, r)
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
def test_mass_storage(handle, endpoint_in, endpoint_out): # Mass Storage device to test bulk transfers (non destructive test) global binary_dump global binary_name #int r; #ct.c_uint32 i print("Reading Max LUN:") lun = ct.c_uint8() r = usb.control_transfer(handle, usb.LIBUSB_ENDPOINT_IN | usb.LIBUSB_REQUEST_TYPE_CLASS | usb.LIBUSB_RECIPIENT_INTERFACE, BOMS_GET_MAX_LUN, 0, 0, ct.byref(lun), 1, 1000) lun = lun.value # Some devices send a STALL instead of the actual value. # In such cases we should set lun to 0. if r == 0: lun = 0 elif r < 0: perr(" Failed: {}".format(usb.strerror(usb.error(r)))) print(" Max LUN = {}".format(lun)) # Send Inquiry print("Sending Inquiry:") buffer = (ct.c_uint8 * 64)() cdb = (ct.c_uint8 * 16)() # SCSI Command Descriptor Block cdb[0] = 0x12 # Inquiry cdb[4] = INQUIRY_LENGTH expected_tag = ct.c_uint32() send_mass_storage_command(handle, endpoint_out, lun, cdb, usb.LIBUSB_ENDPOINT_IN, INQUIRY_LENGTH, ct.pointer(expected_tag)) size = ct.c_int() r = usb.bulk_transfer(handle, endpoint_in, ct.cast(ct.pointer(buffer), ct.POINTER(ct.c_ubyte)), INQUIRY_LENGTH, ct.byref(size), 1000) if r < 0: return err_exit(r) size = size.value print(" received {} bytes".format(size)) # The following strings are not zero terminated vid = (ct.c_char * 9)() pid = (ct.c_char * 9)() rev = (ct.c_char * 5)() for i in range(8): 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 print(" VID:PID:REV \"%8s\":\"%8s\":\"%4s\"".format(vid, pid, rev)) if get_mass_storage_status(handle, endpoint_in, expected_tag) == -2: get_sense(handle, endpoint_in, endpoint_out) # Read capacity print("Reading Capacity:") buffer = (ct.c_uint8 * 64)() cdb = (ct.c_uint8 * 16)() # SCSI Command Descriptor Block cdb[0] = 0x25 # Read Capacity expected_tag = ct.c_uint32() send_mass_storage_command(handle, endpoint_out, lun, cdb, usb.LIBUSB_ENDPOINT_IN, READ_CAPACITY_LENGTH, ct.pointer(expected_tag)) size = ct.c_int() r = usb.bulk_transfer(handle, endpoint_in, ct.cast(ct.pointer(buffer), ct.POINTER(ct.c_ubyte)), READ_CAPACITY_LENGTH, ct.byref(size), 1000) if r < 0: return err_exit(r) size = size.value print(" received {} bytes".format(size)) max_lba = be_to_int32(buffer[0:]) block_size = be_to_int32(buffer[4:]) device_size = (max_lba + 1.0) * block_size / (1024 * 1024 * 1024) print(" Max LBA: {:08X}, Block Size: {:08X} (%.2f GB)".format( 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] try: data = ct.cast(calloc(1, block_size), ct.POINTER(ct.c_ubyte)) # unsigned char* except: perr(" unable to allocate data buffer\n") return -1 # Send Read print("Attempting to read %u bytes:".format(block_size)) cdb = (ct.c_uint8 * 16)() # SCSI Command Descriptor Block cdb[0] = 0x28 # Read(10) cdb[8] = 0x01 # 1 block expected_tag = ct.c_uint32() send_mass_storage_command(handle, endpoint_out, lun, cdb, usb.LIBUSB_ENDPOINT_IN, block_size, ct.pointer(expected_tag)) size = ct.c_int() usb.bulk_transfer(handle, endpoint_in, data, block_size, ct.byref(size), 5000) size = size.value print(" READ: received {} bytes".format(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: try: fd = open(binary_name, "w") except: pass else: with fd: if fd.fwrite(data, ct.c_size_t(size).value) != ct.c_uint(size).value: perr(" unable to write binary data\n") free(data) return 0
def main(argv=sys.argv): global VID, PID global test_mode global binary_dump global binary_name show_help = False # bool debug_mode = False # bool error_lang = None # char* # Default to generic, expecting VID:PID VID = 0 PID = 0 test_mode = USE_GENERIC endian_test = ct.c_uint16(0xBE00) if ct.cast(ct.pointer(endian_test), ct.POINTER(ct.c_uint8))[0] == 0xBE: print("Despite their natural superiority for end users, big endian\n" "CPUs are not supported with this program, sorry.") return 0 #if len(argv) >= 2: for j in range(1, len(argv)): arglen = len(argv[j]) if argv[j][0] in ('-', '/') and arglen >= 2: opt = argv[j][1] if opt == 'd': debug_mode = True elif opt == 'i': extra_info = True elif opt == 'w': force_device_request = True elif opt == 'b': j += 1 if j >= len(argv) or argv[j][0] in ('-', '/'): print(" Option -b requires a file name") return 1 binary_name = argv[j] binary_dump = True elif opt == 'l': j += 1 if j >= len(argv) or argv[j][0] in ('-', '/'): print(" Option -l requires an ISO 639-1 language parameter") return 1 error_lang = argv[j] elif opt == 'j': # OLIMEX ARM-USB-TINY JTAG, 2 channel composite device - 2 interfaces if not VID and not PID: VID = 0x15BA PID = 0x0004 elif opt == 'k': # Generic 2 GB USB Key (SCSI Transparent/Bulk Only) - 1 interface if not VID and not PID: VID = 0x0204 PID = 0x6025 # The following tests will force VID:PID if already provided elif opt == 'p': # Sony PS3 Controller - 1 interface VID = 0x054C PID = 0x0268 test_mode = USE_PS3 elif opt == 's': # Microsoft Sidewinder Precision Pro Joystick - 1 HID interface VID = 0x045E PID = 0x0008 test_mode = USE_HID elif opt == 'x': # Microsoft XBox Controller Type S - 1 interface VID = 0x045E PID = 0x0289 test_mode = USE_XBOX else: show_help = True else: for i in range(arglen): if argv[j][i] == ':': tmp_vid = 0 # unsigned int tmp_pid = 0 # unsigned int if sscanf(argv[j], "%x:%x" , ct.pointer(tmp_vid), ct.pointer(tmp_pid)) != 2: print(" Please specify VID & PID as \"vid:pid\" in hexadecimal format") return 1 VID = ct.c_uint16(tmp_vid) PID = ct.c_uint16(tmp_pid) break else: show_help = True if show_help or len(argv) == 1 or len(argv) > 7: print("usage: {} [-h] [-d] [-i] [-k] [-b file] [-l lang] [-j] [-x] [-s] [-p] [-w] [vid:pid]".format(argv[0])) print(" -h : display usage") print(" -d : enable debug output") print(" -i : print topology and speed info") print(" -j : test composite FTDI based JTAG device") print(" -k : test Mass Storage device") print(" -b file : dump Mass Storage data to file 'file'") print(" -p : test Sony PS3 SixAxis controller") print(" -s : test Microsoft Sidewinder Precision Pro (HID)") print(" -x : test Microsoft XBox Controller Type S") print(" -l lang : language to report errors in (ISO 639-1)") print(" -w : force the use of device requests when querying WCID descriptors") print("If only the vid:pid is provided, xusb attempts to run the most appropriate test") return 0 # xusb is commonly used as a debug tool, so it's convenient to have debug output # during usb.init(), but since we can't call on usb.set_option() before usb.init(), # we use the env variable method old_dbg_str = os.environ.get("LIBUSB_DEBUG", None) if debug_mode: try: os.environ["LIBUSB_DEBUG"] = "4" # usb.LIBUSB_LOG_LEVEL_DEBUG except: print("Unable to set debug level") version = usb.get_version()[0] print("Using libusb v{}.{}.{}.{}\n".format( version.major, version.minor, version.micro, version.nano)) r = usb.init(None) if r < 0: return r try: # If not set externally, and no debug option was given, use info log level if old_dbg_str is None and not debug_mode: usb.set_option(None, usb.LIBUSB_OPTION_LOG_LEVEL, usb.LIBUSB_LOG_LEVEL_INFO) if error_lang is not None: r = usb.setlocale(error_lang) if r < 0: print("Invalid or unsupported locale '{}': {}".format( error_lang, usb.strerror(usb.error(r)))) test_device(VID, PID) finally: usb.exit(None) if debug_mode: #char string[256]; string = "LIBUSB_DEBUG={}".format("" if old_dbg_str is None else old_dbg_str) return 0
def main(): global devh global img_transfer global irq_transfer global do_exit exit_sem = sem_open(SEM_NAME, O_CREAT, 0) if not exit_sem: print("failed to initialise semaphore error {}".format(errno), file=sys.stderr) sys.exit(1) # only using this semaphore in this process so go ahead and unlink it now sem_unlink(SEM_NAME) r = usb.init(None) if r < 0: print("failed to initialise libusb", file=sys.stderr) sys.exit(1) r = find_dpfp_device() try: if r < 0: print("Could not find/open device", file=sys.stderr) return abs(r) r = usb.claim_interface(devh, 0) if r < 0: print("usb_claim_interface error {} {}".format(r, usb.strerror(usb.error(r))), file=sys.stderr) return abs(r) print("claimed interface") r = print_f0_data() if r < 0: usb.release_interface(devh, 0) return abs(r) r = do_init() try: if r < 0: return abs(r) # async from here onwards #sigact = struct_sigaction() #sigact.sa_handler = sighandler #sigemptyset(ct.byref(sigact.sa_mask)) #sigact.sa_flags = 0 signal.signal(signal.SIGINT, sighandler) signal.signal(signal.SIGTERM, sighandler) if hasattr(signal, "SIGQUIT"): signal.signal(signal.SIGQUIT, sighandler) r = pthread_create(ct.byref(poll_thread), NULL, poll_thread_main, NULL) if r: return abs(r) r = alloc_transfers() if r < 0: request_exit(1) pthread_join(poll_thread, NULL) return abs(r) r = init_capture() if r < 0: request_exit(1) pthread_join(poll_thread, NULL) return abs(r) while not do_exit: sem_wait(exit_sem) print("shutting down...") pthread_join(poll_thread, NULL) r = usb.cancel_transfer(irq_transfer) if r < 0: request_exit(1) return abs(r) r = usb.cancel_transfer(img_transfer) if r < 0: request_exit(1) return abs(r) while irq_transfer or img_transfer: if usb.handle_events(None) < 0: break r = 0 if do_exit == 1 else 1 finally: usb.free_transfer(img_transfer) usb.free_transfer(irq_transfer) set_mode(0); set_hwstat(0x80) usb.release_interface(devh, 0) finally: usb.close(devh) usb.exit(None) return abs(r)