You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
88 lines
4.2 KiB
88 lines
4.2 KiB
#!/usr/bin/env python3
|
|
import sys, os, zlib, struct, hashlib
|
|
from hexdump import hexdump
|
|
from tinygrad.helpers import DEBUG, getenv, fetch
|
|
from tinygrad.runtime.support.usb import USB3
|
|
|
|
def patch(input_filepath, file_hash, patches):
|
|
with open(input_filepath, 'rb') as infile: data = bytearray(infile.read())
|
|
|
|
if_hash = hashlib.md5(data).hexdigest()
|
|
if if_hash != file_hash:
|
|
raise ValueError(f"File hash mismatch: expected {file_hash}, got {if_hash}")
|
|
|
|
for offset, expected_bytes, new_bytes in patches:
|
|
if len(expected_bytes) != len(new_bytes):
|
|
raise ValueError("Expected bytes and new bytes must be the same length")
|
|
|
|
if offset + len(new_bytes) > len(data): return False
|
|
current_bytes = data[offset:offset + len(expected_bytes)]
|
|
assert bytes(current_bytes) == expected_bytes, f"Expected {expected_bytes} at offset {offset:x}, but got {current_bytes}"
|
|
data[offset:offset + len(new_bytes)] = new_bytes
|
|
|
|
checksum = sum(data[4:-6]) & 0xff
|
|
crc32 = zlib.crc32(data[4:-6]).to_bytes(4, 'little')
|
|
data[-5] = checksum
|
|
data[-4] = crc32[0]
|
|
data[-3] = crc32[1]
|
|
data[-2] = crc32[2]
|
|
data[-1] = crc32[3]
|
|
return data
|
|
|
|
path = os.path.dirname(os.path.abspath(__file__))
|
|
file_hash = "5284e618d96ef804c06f47f3b73656b7"
|
|
file_path = os.path.join(path, "Software/AS_USB4_240417_85_00_00.bin")
|
|
|
|
if not os.path.exists(file_path):
|
|
url = "https://web.archive.org/web/20250430124720/https://www.station-drivers.com/index.php/en/component/remository/func-download/6341/chk,3ef8b04704a18eb2fc57ff60382379ad/no_html,1/lang,en-gb/"
|
|
os.system(f'curl -o "{path}/fw.zip" "{url}"')
|
|
os.system(f'unzip -o "{path}/fw.zip" "Software/AS_USB4_240417_85_00_00.bin" -d "{path}"')
|
|
|
|
patches = [(0x2a0d + 1 + 4, b'\x0a', b'\x05')]
|
|
patched_fw = patch(file_path, file_hash, patches)
|
|
|
|
vendor, device = [int(x, base=16) for x in getenv("USBDEV", "174C:2464").split(":")]
|
|
try: dev = USB3(vendor, device, 0x81, 0x83, 0x02, 0x04)
|
|
except RuntimeError as e:
|
|
raise RuntimeError(f'{e}. You can set USBDEV environment variable to your device\'s vendor and device ID (e.g., USBDEV="174C:2464")') from e
|
|
|
|
config1 = bytes([
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x30, 0x30, 0x36, 0x30,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x74, 0x69, 0x6E, 0x79, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x74, 0x69, 0x6E, 0x79,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0x55, 0x53, 0x42, 0x20, 0x33, 0x2E, 0x32, 0x20, 0x50, 0x43, 0x49, 0x65,
|
|
0x20, 0x54, 0x69, 0x6E, 0x79, 0x45, 0x6E, 0x63, 0x6C, 0x6F, 0x73, 0x75, 0x72, 0x65, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0x54, 0x69, 0x6E, 0x79, 0x45, 0x6E, 0x63, 0x6C, 0x6F, 0x73, 0x75, 0x72,
|
|
0x65, 0xFF, 0xFF, 0xFF, 0xD1, 0xAD, 0x01, 0x00, 0x00, 0x01, 0xCF, 0xFF, 0x02, 0xFF, 0x5A, 0x94])
|
|
|
|
config2 = bytes([
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0x47, 0x6F, 0x70, 0x6F, 0x64, 0x20, 0x47, 0x72, 0x6F, 0x75, 0x70, 0x20,
|
|
0x4C, 0x69, 0x6D, 0x69, 0x74, 0x65, 0x64, 0x2E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x55, 0x53, 0x42, 0x34,
|
|
0x20, 0x4E, 0x56, 0x4D, 0x65, 0x20, 0x53, 0x53, 0x44, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x45, 0x6E,
|
|
0x63, 0x6C, 0x6F, 0x73, 0x75, 0x72, 0x65, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0x8C, 0xBF, 0xFF, 0x97, 0xC1, 0xF3, 0xFF, 0xFF, 0x01, 0x2D, 0x66, 0xD6,
|
|
0x66, 0x06, 0x00, 0xC0, 0x87, 0x01, 0x5A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCA, 0x01, 0x66, 0xD6,
|
|
0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xA5, 0x67])
|
|
|
|
part1 = patched_fw[:0xff00]
|
|
part2 = patched_fw[0xff00:]
|
|
|
|
# config patch
|
|
cdb = struct.pack('>BBB12x', 0xe1, 0x50, 0x0)
|
|
dev.send_batch(cdbs=[cdb], odata=[config1])
|
|
|
|
cdb = struct.pack('>BBB12x', 0xe1, 0x50, 0x1)
|
|
dev.send_batch(cdbs=[cdb], odata=[config2])
|
|
|
|
cdb = struct.pack('>BBI', 0xe3, 0x50, len(part1))
|
|
dev.send_batch(cdbs=[cdb], odata=[part1])
|
|
|
|
cdb = struct.pack('>BBI', 0xe3, 0xd0, len(part2))
|
|
dev.send_batch(cdbs=[cdb], odata=[part2])
|
|
|
|
cdb = struct.pack('>BB13x', 0xe8, 0x51)
|
|
dev.send_batch(cdbs=[cdb])
|
|
|
|
print("done, you can disconnect the controller!")
|
|
|