import errno import logging import typing from binascii import hexlify, unhexlify from enum import Enum from struct import unpack import usb.core as ucore from usb.core import USBError from .blobs import init_hardcoded, init_hardcoded_clean_slate from .util import assert_status class SupportedDevices(Enum): """USB IDs for supported devices""" DEV_90 = (0x138a, 0x0090) DEV_97 = (0x138a, 0x0097) DEV_9d = (0x138a, 0x009d) DEV_9a = (0x06cb, 0x009a) @classmethod def from_usbid(cls, vendorid, productid): return supported_devices[(vendorid, productid)] supported_devices = dict((dev.value, dev) for dev in SupportedDevices) class CancelledException(Exception): pass class Usb: def __init__(self): self.trace_enabled = False self.dev: typing.Optional[ucore.Device] = None self.cancel = False def open(self, vendor=None, product=None): if vendor is not None and product is not None: dev = ucore.find(idVendor=vendor, idProduct=product) else: def match(d): return (d.idVendor, d.idProduct) in supported_devices dev = ucore.find(custom_match=match) self.open_dev(dev) def open_devpath(self, busnum: int, address: int): def match(d): return d.bus == busnum and d.address == address dev = ucore.find(custom_match=match) self.open_dev(dev) def open_dev(self, dev: ucore.Device): if dev is None: raise Exception('No matching devices found') self.dev = dev self.dev.default_timeout = 15000 def close(self): if self.dev is not None: try: self.dev.reset() self.dev = None except: pass def usb_dev(self): return self.dev def send_init(self): # self.dev.set_configuration() # TODO analyse responses, detect hardware type assert_status(self.cmd(unhexlify('01'))) # RomInfo.get() assert_status(self.cmd(unhexlify('19'))) # 43 -- get partition header(?) (02 -- fwext partition) # c28c745a in response is a FwextBuildtime = 0x5A748CC2 rsp = self.cmd(unhexlify('4302')) # get_fw_info() assert_status(self.cmd(init_hardcoded)) (err, ), rsp = unpack('cmd> %s' % hexlify(out).decode()) self.dev.write(1, out) resp = self.dev.read(129, 100 * 1024) resp = bytes(resp) self.trace('