123 lines
3.5 KiB
Python
123 lines
3.5 KiB
Python
|
|
import usb.core as ucore
|
|
from binascii import *
|
|
from .util import assert_status, unhex
|
|
from struct import unpack
|
|
from usb.util import claim_interface, release_interface
|
|
from threading import Thread
|
|
from usb.core import USBError
|
|
from .blobs import init_hardcoded, init_hardcoded_clean_slate
|
|
|
|
supported_devices=[
|
|
(0x138a, 0x0097),
|
|
(0x06cb, 0x009a),
|
|
]
|
|
|
|
|
|
def custom_match(d):
|
|
print(d.address)
|
|
return (d.idVendor, d.idProduct) in supported_devices
|
|
|
|
class Usb():
|
|
def __init__(self):
|
|
self.interrupt_cb = None
|
|
self.trace_enabled = False
|
|
self.quit = None
|
|
self.dev = None
|
|
|
|
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:
|
|
dev = ucore.find(custom_match=custom_match)
|
|
|
|
self.open_dev(dev)
|
|
|
|
def open_dev(self, dev):
|
|
self.dev = dev
|
|
self.dev.default_timeout = 15000
|
|
self.thread = Thread(target=lambda: self.int_thread())
|
|
self.thread.daemon = True
|
|
self.thread.start()
|
|
|
|
def close(self):
|
|
if self.dev is not None:
|
|
try:
|
|
self.dev.reset()
|
|
self.dev = None
|
|
except:
|
|
pass
|
|
finally:
|
|
self.thread.join()
|
|
|
|
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')))
|
|
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'))
|
|
|
|
assert_status(self.cmd(init_hardcoded))
|
|
|
|
(err,), rsp = unpack('<H', rsp[:2]), rsp[2:]
|
|
if err != 0:
|
|
# fwext is not loaded
|
|
print('Clean slate')
|
|
self.cmd(init_hardcoded_clean_slate)
|
|
|
|
def cmd(self, out):
|
|
if callable(out):
|
|
out = out()
|
|
if not out:
|
|
return 0
|
|
self.trace('>cmd> %s' % hexlify(out).decode())
|
|
self.dev.write(1, out)
|
|
resp = self.dev.read(129, 100*1024)
|
|
resp = bytes(resp)
|
|
self.trace('<cmd< %s' % hexlify(resp).decode())
|
|
return resp
|
|
|
|
def read_82(self):
|
|
try:
|
|
resp = self.dev.read(130, 1024*1024, timeout=10000)
|
|
resp = bytes(resp)
|
|
self.trace('<130< %s' % hexlify(resp).decode())
|
|
return resp
|
|
except Exception as e:
|
|
self.trace('<130< Error: %s' % repr(e))
|
|
return None
|
|
|
|
def int_thread(self):
|
|
try:
|
|
while True:
|
|
resp = self.dev.read(131, 1024, timeout=0)
|
|
resp = bytes(resp)
|
|
self.trace('<int< %s' % hexlify(resp).decode())
|
|
cb=self.interrupt_cb
|
|
if cb is None:
|
|
print('Ignoring spurious interrupt: %s' % hexlify(resp).decode())
|
|
else:
|
|
try:
|
|
cb(resp)
|
|
except Exception as e:
|
|
print('Exception on the interrupt thread: %s' % e)
|
|
except USBError as e:
|
|
self.trace('<int< Exception on interrupt thread: %s' % repr(e))
|
|
if self.quit != None:
|
|
self.quit(e)
|
|
finally:
|
|
self.trace('<int< Interrupt thread is dead')
|
|
|
|
|
|
def trace(self, s):
|
|
if self.trace_enabled:
|
|
print(s)
|
|
|
|
usb=Usb()
|