def _get_descriptor_fields(self): """ Return a list of available descriptor property fields. :return: list of strings. """ if not self.__libusb_dev_desc__: self.__libusb_dev_desc__ = usb.device_descriptor() usb.get_device_descriptor(self.__libusb_dev__, ct.byref(self.__libusb_dev_desc__)) fields = sorted([fld[0] for fld in self.__libusb_dev_desc__._fields_]) return fields
def _find_devices(self): """ Find all attached USB devices that match the filter. """ self.error = False self.device_count = 0 self._usb_devices = list() # Get device list from libusb. dev_list = ct.POINTER(ct.POINTER(usb.device))() cnt = usb.get_device_list(None, ct.byref(dev_list)) if cnt < 0: usb_error(cnt, _('Failed to find attached USB devices.')) self.error = True return _logger.debug(_('Vendor filters: ') + ', '.join(self._filters)) _logger.debug(_('Searching for Ultimarc USB devices...')) for dev in dev_list: if not dev: # We must always look for the Null device and quit the loop. break dev_desc = usb.device_descriptor() ret = usb.get_device_descriptor(dev, ct.byref(dev_desc)) if ret != usb.LIBUSB_SUCCESS: usb_error(ret, _('failed to get USB device descriptor.')) continue if not self._filters or f'{dev_desc.idVendor:04x}' in self._filters: ud = USBDeviceInfo(dev, dev_desc) self._usb_devices.append(ud) self.device_count += 1 _logger.debug(_('Device search complete.')) usb.free_device_list(dev_list, 1)
def _get_device_handle(self): """ Return the raw LibUSB device handle pointer for our device. Must only be called from __enter__(). :return: LibUSBDeviceHandle """ # Get device list from libusb. self.__dev_list__ = ct.POINTER(ct.POINTER(usb.device))() cnt = usb.get_device_list(None, ct.byref(self.__dev_list__)) if cnt < 0: usb_error(cnt, _('Failed to find attached USB devices.')) return None for dev in self.__dev_list__: if not dev: # We must always look for the Null device and quit the loop. break dev_desc = usb.device_descriptor() ret = usb.get_device_descriptor(dev, ct.byref(dev_desc)) if ret != usb.LIBUSB_SUCCESS: usb_error(ret, _('failed to get USB device descriptor.')) continue if self.vendor_id == dev_desc.idVendor and self.product_id == dev_desc.idProduct and \ self.bus == usb.get_bus_number(dev) and self.address == usb.get_device_address(dev): dev_handle = ct.POINTER(usb.device_handle)() ret = usb.open(dev, ct.byref(dev_handle)) if ret == usb.LIBUSB_SUCCESS: return dev_handle usb_error(ret, _('Failed to open device') + f' {self.dev_key}.') self._close_device_list_handle() _logger.debug( _('Device was not found on host when trying to open it.')) return None
def print_devs(devs): path = (ct.c_uint8 * 8)() i = 0 while devs[i]: dev = devs[i] desc = usb.device_descriptor() r = usb.get_device_descriptor(dev, ct.byref(desc)) if r < 0: print("failed to get device descriptor", file=sys.stderr) return print("{:04x}:{:04x} (bus {:d}, device {:d})".format( desc.idVendor, desc.idProduct, usb.get_bus_number(dev), usb.get_device_address(dev)), end="") r = usb.get_port_numbers(dev, path, ct.sizeof(path)) if r > 0: print(" path: {:d}".format(path[0]), end="") for j in range(1, r): print(".{:d}".format(path[j]), end="") print() i += 1
def print_devs(devs): path = (ct.c_uint8 * 8)() i = 0 while devs[i]: dev = devs[i] dev_handle = ct.POINTER(usb.device_handle)() vendor_str = '' product_str = 'unknown' desc = usb.device_descriptor() r = usb.get_device_descriptor(dev, ct.byref(desc)) if r < 0: print("failed to get device descriptor", file=sys.stderr) return r = usb.open(dev, ct.byref(dev_handle)) buf = ct.create_string_buffer(1024) if r >= 0: # for field in desc._fields_: if desc.iProduct: ret = usb.get_string_descriptor_ascii( dev_handle, desc.idProduct, ct.cast(buf, ct.POINTER(ct.c_ubyte)), ct.sizeof(buf)) if ret > 0: product_str = buf.value.decode('utf-8') else: print(f'Error: returned {usb.error_name(r).decode("utf-8")} ({r})') print( "{:04x}:{:04x} (bus {:d}, device {:d} : Vendor: {}, Product: {})". format(desc.idVendor, desc.idProduct, usb.get_bus_number(dev), usb.get_device_address(dev), vendor_str, product_str), end="") r = usb.get_port_numbers(dev, path, ct.sizeof(path)) if r > 0: print(" path: {:d}".format(path[0]), end="") for j in range(1, r): print(".{:d}".format(path[j]), end="") print() i += 1
def hotplug_callback(ctx, dev, event, user_data): global handle, done desc = usb.device_descriptor() rc = usb.get_device_descriptor(dev, ct.byref(desc)) if rc != usb.LIBUSB_SUCCESS: print("Error getting device descriptor", file=sys.stderr) print("Device attached: {:04x}:{:04x}".format(desc.idVendor, desc.idProduct)) if handle: usb.close(handle) handle = ct.POINTER(usb.device_handle)() rc = usb.open(dev, ct.byref(handle)) if rc != usb.LIBUSB_SUCCESS: print("Error opening device", file=sys.stderr) done += 1 return 0
def test_device(vid, pid): speed_name = [ "Unknown", "1.5 Mbit/s (USB LowSpeed)", "12 Mbit/s (USB FullSpeed)", "480 Mbit/s (USB HighSpeed)", "5000 Mbit/s (USB SuperSpeed)", ] handle = usb.open_device_with_vid_pid(None, vid, pid) if not handle: perr(" Failed.\n") return -1 try: dev = usb.get_device(handle) # usb.device* bus = usb.get_bus_number(dev) # c_uint8 port_path = (c_uint8 * 8)() r = usb.get_port_numbers(dev, port_path, sizeof(port_path)) if r > 0: print("\nDevice properties:") print(" bus number: {}".format(bus)) print(" port path: {}".format(port_path[0]), end="") for i in range(1, r): print("->{}".format(port_path[i]), end="") print(" (from root hub)") r = usb.get_device_speed(dev) if r < 0 or r > 4: r = 0 print(" speed: {}".format(speed_name[r])) print("\nReading device descriptor:") dev_desc = usb.device_descriptor() r = usb.get_device_descriptor(dev, byref(dev_desc)) if r < 0: return err_exit(r) print(" length: {}".format(dev_desc.bLength)) print(" device class: {}".format(dev_desc.bDeviceClass)) print(" VID:PID: {:04X}:{:04X}".format( dev_desc.idVendor, dev_desc.idProduct)) print(" bcdDevice: {:04X}".format(dev_desc.bcdDevice)) # Copy the string descriptors for easier parsing string_index = {} # indexes of the string descriptors string_index["Manufacturer"] = dev_desc.iManufacturer string_index["Product"] = dev_desc.iProduct string_index["Serial Number"] = dev_desc.iSerialNumber print("\nReading string descriptors:") string = (c_uint8 * 128)() for key in string_index.keys(): if string_index[key] == 0: continue r = usb.get_string_descriptor_ascii(handle, string_index[key], string, sizeof(string)) if r > 0: print(" {}: {}".format(key, bytearray(string[:r]).decode())) # MS OS 1.0 Descriptors read_ms_os_10_descriptors(handle) print("\nReading BOS descriptor: ", end="") bos_desc = POINTER(usb.bos_descriptor)() if usb.get_bos_descriptor(handle, pointer(bos_desc)) == usb.LIBUSB_SUCCESS: print((bos_desc[0].bNumDeviceCaps)) caps = cast(pointer(bos_desc[0].dev_capability), POINTER(POINTER(usb.bos_dev_capability_descriptor))) for i in range(bos_desc[0].bNumDeviceCaps): # print_device_cap(caps[i]) if caps[i][0].bDevCapabilityType == 0x05: desc = cast(caps[i], POINTER(PlatformCapabilityDescriptor))[0] uuid = uuid_to_string(desc.PlatformCapabilityUUID) if uuid == MS_OS_20_PLATFORM_CAPABILITY_UUID: print(" MS OS 2.0 Platform Capability Descriptor") print(" UUID: {}".format(uuid)) desc = cast( caps[i], POINTER(MSOS20PlatformCapabilityDescriptor))[0] print(" VendorCode: 0x{:02X}".format( desc.bVendorCode)) read_ms_os_20_descriptors(handle, desc.bVendorCode) elif uuid == WEBUSB_PLATFORM_CAPABILITY_UUID: print(" WebUSB Platform Capability UUID") print(" UUID: {}".format(uuid)) desc = cast( caps[i], POINTER(WebUSBPlatformCapabilityDescriptor))[0] print(" VendorCode: 0x{:02X}".format( desc.bVendorCode)) else: print(" UUID: {}".format(uuid)) usb.free_bos_descriptor(bos_desc) else: print("no descriptor") finally: usb.close(handle) return 0
def main(argv=sys.argv): global verbose FIRMWARE = 0 LOADER = 1 known_devices = FX_KNOWN_DEVICES paths = [None, None] # [const char*] device_id = None # const char* device_path = os.environ.get("DEVICE", None) target_type = None # const char* fx_names = FX_TYPE_NAMES img_names = IMG_TYPE_NAMES fx_type = FX_TYPE_UNDEFINED # int img_types = [0] * len(paths) # [int] #opt; # int #status; # int #ext; # const char* #i, j; # unsigned int vid = 0 # unsigned pid = 0 # unsigned busnum = 0 # unsigned devaddr = 0 # unsigned #_busnum; # unsigned #_devaddr; # unsigned dev = ct.POINTER(usb.device)() devs = ct.POINTER(ct.POINTER(usb.device))() device = ct.POINTER(usb.device_handle)() desc = usb.device_descriptor() try: opts, args = getopt.getopt(argv[1:], "qvV?hd:p:i:I:s:S:t:") except getopt.GetoptError: return print_usage(-1) for opt, optarg in opts: if opt == "-d": device_id = optarg if sscanf(device_id, "%x:%x", ct.byref(vid), ct.byref(pid)) != 2: print( "please specify VID & PID as \"vid:pid\" in hexadecimal format", file=sys.stderr) return -1 elif opt == "-p": device_path = optarg if sscanf(device_path, "%u,%u", ct.byref(busnum), ct.byref(devaddr)) != 2: print( "please specify bus number & device number as \"bus,dev\" in decimal format", file=sys.stderr) return -1 elif opt in ("-i", "-I"): paths[FIRMWARE] = optarg elif opt in ("-s", "-S"): paths[LOADER] = optarg elif opt == "-V": print(FXLOAD_VERSION) return 0 elif opt == "-t": target_type = optarg elif opt == "-v": verbose += 1 elif opt == "-q": verbose -= 1 elif opt in ("-?", "-h"): return print_usage(-1) else: return print_usage(-1) if paths[FIRMWARE] is None: logerror("no firmware specified!\n") return print_usage(-1) if device_id is not None and device_path is not None: logerror("only one of -d or -p can be specified\n") return print_usage(-1) # determine the target type if target_type is not None: for i in range(FX_TYPE_MAX): if fx_names[i] == target_type: fx_type = i break else: logerror("illegal microcontroller type: {}\n", target_type) return print_usage(-1) # open the device using libusb status = usb.init(None) if status < 0: logerror("usb.init() failed: {}\n", usb.error_name(status)) return -1 try: usb.set_option(None, usb.LIBUSB_OPTION_LOG_LEVEL, verbose) # try to pick up missing parameters from known devices if target_type is None or device_id is None or device_path is not None: if usb.get_device_list(None, ct.byref(devs)) < 0: logerror("libusb.get_device_list() failed: {}\n", usb.error_name(status)) return -1 i = 0 while True: dev = devs[i] if not dev: usb.free_device_list(devs, 1) logerror( "could not find a known device - please specify type and/or vid:pid and/or bus,dev\n" ) return print_usage(-1) _busnum = usb.get_bus_number(dev) _devaddr = usb.get_device_address(dev) if target_type is not None and device_path is not None: # if both a type and bus,addr were specified, we just need to find our match if (usb.get_bus_number(dev) == busnum and usb.get_device_address(dev) == devaddr): break else: status = usb.get_device_descriptor(dev, ct.byref(desc)) if status >= 0: if verbose >= 3: logerror("examining {:04x}:{:04x} ({},{})\n", desc.idVendor, desc.idProduct, _busnum, _devaddr) if_break = False for known_device in known_devices: if (desc.idVendor == known_device.vid and desc.idProduct == known_device.pid): if ( # nothing was specified (target_type is None and device_id is None and device_path is None) or # vid:pid was specified and we have a match (target_type is None and device_id is not None and vid == desc.idVendor and pid == desc.idProduct) or # bus,addr was specified and we have a match (target_type is None and device_path is not None and busnum == _busnum and devaddr == _devaddr) or # type was specified and we have a match (target_type is not None and device_id is None and device_path is None and fx_type == known_device.type)): fx_type = known_device.type vid = desc.idVendor pid = desc.idProduct busnum = _busnum devaddr = _devaddr if_break = True break if if_break: if verbose: logerror( "found device '{}' [{:04x}:{:04x}] ({},{})\n", known_device.designation, vid, pid, busnum, devaddr) break i += 1 status = usb.open(dev, ct.byref(device)) usb.free_device_list(devs, 1) if status < 0: logerror("usb.open() failed: {}\n", usb.error_name(status)) return -1 elif device_id is not None: device = usb.open_device_with_vid_pid(None, ct.c_uint16(vid), ct.c_uint16(pid)) if not device: logerror("usb.open() failed\n") return -1 # We need to claim the first interface usb.set_auto_detach_kernel_driver(device, 1) status = usb.claim_interface(device, 0) if status != usb.LIBUSB_SUCCESS: usb.close(device) logerror("libusb.claim_interface failed: {}\n", usb.error_name(status)) return -1 if verbose: logerror("microcontroller type: {}\n", fx_names[fx_type]) for i, path in enumerate(paths): if path is not None: ext = path[-4:] if ext.lower() == ".hex" or ext == ".ihx": img_types[i] = IMG_TYPE_HEX elif ext.lower() == ".iic": img_types[i] = IMG_TYPE_IIC elif ext.lower() == ".bix": img_types[i] = IMG_TYPE_BIX elif ext.lower() == ".img": img_types[i] = IMG_TYPE_IMG else: logerror("{} is not a recognized image type\n", path) return -1 if verbose and path is not None: logerror("{}: type {}\n", path, img_names[img_types[i]]) if paths[LOADER] is None: # single stage, put into internal memory if verbose > 1: logerror("single stage: load on-chip memory\n") status = ezusb_load_ram(device, paths[FIRMWARE], fx_type, img_types[FIRMWARE], 0) else: # two-stage, put loader into internal memory if verbose > 1: logerror("1st stage: load 2nd stage loader\n") status = ezusb_load_ram(device, paths[LOADER], fx_type, img_types[LOADER], 0) if status == 0: # two-stage, put firmware into internal memory if verbose > 1: logerror("2nd state: load on-chip memory\n") status = ezusb_load_ram(device, paths[FIRMWARE], fx_type, img_types[FIRMWARE], 1) usb.release_interface(device, 0) usb.close(device) finally: usb.exit(None) return status
def test_device(vid, pid): #int r; speed_name = [ "Unknown", "1.5 Mbit/s (USB LowSpeed)", "12 Mbit/s (USB FullSpeed)", "480 Mbit/s (USB HighSpeed)", "5000 Mbit/s (USB SuperSpeed)", ] print("Opening device {:04X}:{:04X}...".format(vid, pid)) #handle = ct.POINTER(usb.device_handle)() handle = usb.open_device_with_vid_pid(None, vid, pid) if not handle: perr(" Failed.\n") return -1 endpoint_in = 0 # default IN endpoint endpoint_out = 0 # default OUT endpoint try: dev = usb.get_device(handle) # usb.device* bus = usb.get_bus_number(dev) # ct.c_uint8 if extra_info: port_path = (ct.c_uint8 * 8)() r = usb.get_port_numbers(dev, port_path, ct.sizeof(port_path)) if r > 0: print("\nDevice properties:") print(" bus number: {}".format(bus)) print(" port path: {}".format(port_path[0]), end="") for i in range(1, r): print("->{}".format(port_path[i]), end="") print(" (from root hub)") r = usb.get_device_speed(dev) if r < 0 or r > 4: r = 0 print(" speed: {}".format(speed_name[r])) print("\nReading device descriptor:") dev_desc = usb.device_descriptor() r = usb.get_device_descriptor(dev, ct.byref(dev_desc)) if r < 0: return err_exit(r) print(" length: {}".format(dev_desc.bLength)) print(" device class: {}".format(dev_desc.bDeviceClass)) print(" S/N: {}".format(dev_desc.iSerialNumber)) print(" VID:PID: {:04X}:{:04X}".format(dev_desc.idVendor, dev_desc.idProduct)) print(" bcdDevice: {:04X}".format(dev_desc.bcdDevice)) print(" iMan:iProd:iSer: {}:{}:{}".format( dev_desc.iManufacturer, dev_desc.iProduct, dev_desc.iSerialNumber)) print(" nb confs: {}".format(dev_desc.bNumConfigurations)) # Copy the string descriptors for easier parsing string_index = (ct.c_uint8 * 3)() # indexes of the string descriptors string_index[0] = dev_desc.iManufacturer string_index[1] = dev_desc.iProduct string_index[2] = dev_desc.iSerialNumber print("\nReading BOS descriptor: ", end="") bos_desc = usb.bos_descriptor*() if usb.get_bos_descriptor(handle, ct.byref(bos_desc)) == usb.LIBUSB_SUCCESS: print("{} caps".format(bos_desc[0].bNumDeviceCaps)) for i in range(bos_desc[0].bNumDeviceCaps): print_device_cap(bos_desc[0].dev_capability[i]) usb.free_bos_descriptor(bos_desc) else: print("no descriptor") print("\nReading first configuration descriptor:") conf_desc = usb.config_descriptor*() r = usb.get_config_descriptor(dev, 0, ct.byref(conf_desc)) if r < 0: return err_exit(r) nb_ifaces = conf_desc[0].bNumInterfaces # int print(" nb interfaces: {}".format(nb_ifaces)) first_iface = (conf_desc[0].usb_interface[0].altsetting[0].bInterfaceNumber if nb_ifaces > 0 else -1) for i in range(nb_ifaces): usb_interface = conf_desc[0].usb_interface[i] print(" interface[{}]: id = {}".format( i, usb_interface.altsetting[0].bInterfaceNumber)) for j in range(usb_interface.num_altsetting): altsetting = usb_interface.altsetting[j] print("interface[{}].altsetting[{}]: num endpoints = {}".format( i, j, altsetting.bNumEndpoints)) print(" Class.SubClass.Protocol: {:02X}.{:02X}.{:02X}".format( altsetting.bInterfaceClass, altsetting.bInterfaceSubClass, altsetting.bInterfaceProtocol)) if (altsetting.bInterfaceClass == usb.LIBUSB_CLASS_MASS_STORAGE and (altsetting.bInterfaceSubClass == 0x01 or altsetting.bInterfaceSubClass == 0x06) and altsetting.bInterfaceProtocol == 0x50): # Mass storage devices that can use basic SCSI commands test_mode = USE_SCSI for k in range(altsetting.bNumEndpoints): endpoint = altsetting.endpoint[k] # const usb.endpoint_descriptor* print(" endpoint[{}].address: {:02X}".format( k, endpoint.bEndpointAddress)) # Use the first interrupt or bulk IN/OUT endpoints as default for testing if ((endpoint.bmAttributes & usb.LIBUSB_TRANSFER_TYPE_MASK) & (usb.LIBUSB_TRANSFER_TYPE_BULK | usb.LIBUSB_TRANSFER_TYPE_INTERRUPT)): if endpoint.bEndpointAddress & usb.LIBUSB_ENDPOINT_IN: if not endpoint_in: endpoint_in = endpoint.bEndpointAddress else: if not endpoint_out: endpoint_out = endpoint.bEndpointAddress print(" max packet size: {:04X}".format(endpoint.wMaxPacketSize)) print(" polling interval: {:02X}".format(endpoint.bInterval)) ep_comp = ct.POINTER(usb.ss_endpoint_companion_descriptor)() usb.get_ss_endpoint_companion_descriptor(None, ct.byref(altsetting.endpoint[k]), ct.byref(ep_comp)) if ep_comp: print(" max burst: {:02X} (USB 3.0)".format(ep_comp[0].bMaxBurst)) print(" bytes per interval: {:04X} (USB 3.0)".format(ep_comp[0].wBytesPerInterval)) usb.free_ss_endpoint_companion_descriptor(ep_comp) usb.free_config_descriptor(conf_desc) usb.set_auto_detach_kernel_driver(handle, 1) for iface in range(nb_ifaces): print("\nClaiming interface {}...".format(iface)) r = usb.claim_interface(handle, iface) if r != usb.LIBUSB_SUCCESS: perr(" Failed.\n") print("\nReading string descriptors:") string = (ct.c_char * 128)() for i in range(3): if string_index[i] == 0: continue if usb.get_string_descriptor_ascii(handle, string_index[i], ct.cast(string, ct.POINTER(ct.c_ubyte)), ct.sizeof(string)) > 0: print(" String ({:#04X}): \"{}\"".format(string_index[i], string)) # Read the OS String Descriptor r = usb.get_string_descriptor(handle, MS_OS_DESC_STRING_INDEX, 0, ct.cast(string, ct.POINTER(ct.c_ubyte)), MS_OS_DESC_STRING_LENGTH) if r == MS_OS_DESC_STRING_LENGTH and memcmp(ms_os_desc_string, string, sizeof(ms_os_desc_string)) == 0: # If this is a Microsoft OS String Descriptor, # attempt to read the WinUSB extended Feature Descriptors read_ms_winsub_feature_descriptors(handle, string[MS_OS_DESC_VENDOR_CODE_OFFSET], first_iface) if test_mode == USE_PS3: r = display_ps3_status(handle) if r < 0: return err_exit(r) elif test_mode == USE_XBOX: r = display_xbox_status(handle) if r < 0: return err_exit(r) r = set_xbox_actuators(handle, 128, 222) if r < 0: return err_exit(r) msleep(2000) r = set_xbox_actuators(handle, 0, 0) if r < 0: return err_exit(r) elif test_mode == USE_HID: test_hid(handle, endpoint_in) elif test_mode == USE_SCSI: r = test_mass_storage(handle, endpoint_in, endpoint_out) if r < 0: return err_exit(r) elif test_mode == USE_GENERIC: pass print() for iface in range(nb_ifaces): print("Releasing interface {}...".format(iface)) usb.release_interface(handle, iface) print("Closing device...") finally: usb.close(handle) return 0
def print_device(device_p, level): global verbose string_descr = ct.create_string_buffer(256) desc = usb.device_descriptor() ret = usb.get_device_descriptor(device_p, ct.byref(desc)) if ret < 0: print("failed to get device descriptor", file=sys.stderr) return -1 handle = ct.POINTER(usb.device_handle)() ret = usb.open(device_p, ct.byref(handle)) if ret == usb.LIBUSB_SUCCESS: if desc.iManufacturer: ret = usb.get_string_descriptor_ascii( handle, desc.iManufacturer, ct.cast(string_descr, ct.POINTER(ct.c_ubyte)), ct.sizeof(string_descr)) if ret > 0: description = "{!s} - ".format(string_descr.value.decode()) else: description = "{:04X} - ".format(desc.idVendor) else: description = "{:04X} - ".format(desc.idVendor) if desc.iProduct: ret = usb.get_string_descriptor_ascii( handle, desc.iProduct, ct.cast(string_descr, ct.POINTER(ct.c_ubyte)), ct.sizeof(string_descr)) if ret > 0: description += "{!s}".format(string_descr.value.decode()) else: description += "{:04X}".format(desc.idProduct) else: description += "{:04X}".format(desc.idProduct) else: description = "{:04X} - {:04X}".format(desc.idVendor, desc.idProduct) print("{:<{width}}Dev (bus {:d}, device {:d}): {}".format( " " * 20, usb.get_bus_number(device_p), usb.get_device_address(device_p), description, width=level * 2)) if handle and verbose: if desc.iSerialNumber: ret = usb.get_string_descriptor_ascii( handle, desc.iSerialNumber, ct.cast(string_descr, ct.POINTER(ct.c_ubyte)), ct.sizeof(string_descr)) if ret > 0: print("{:<{width}} - Serial Number: {!s}".format( " " * 20, string_descr.value.decode(), width=level * 2)) if verbose: for i in range(desc.bNumConfigurations): config = ct.POINTER(usb.config_descriptor)() ret = usb.get_config_descriptor(device_p, i, ct.byref(config)) if ret != usb.LIBUSB_SUCCESS: print(" Couldn't retrieve descriptors") continue print_configuration(config[0]) usb.free_config_descriptor(config) if handle and desc.bcdUSB >= 0x0201: print_bos(handle[0]) if handle: usb.close(handle) return 0