Skip to content

Commit

Permalink
add Python patching script for better maintainability
Browse files Browse the repository at this point in the history
  • Loading branch information
kosma committed Nov 13, 2022
1 parent 67cc374 commit 955c3eb
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 0 deletions.
20 changes: 20 additions & 0 deletions firmware/patches.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Coolscan LS-50
DF17811 0x170EE "1.02" "2.01" # Version in INQUIRY response
DF17811 0x17106 0x0201 0x0102 # Version in USB descriptor (High Speed)
DF17811 0x17118 0x0201 0x0102 # Version in USB descriptor (Full Speed)
DF17811 0x2A213 0x03 0x42 # Enable adapter ID 3
DF17811 0x2A219 0x05 0x42 # Enable adapter ID 5
DF17811 0x2A21F 0x06 0x42 # Enable adapter ID 6
DF17811 0x49E49 "1.02" "2.01" # Version in strings
DF17811 0x4A114 0x00400000 0x00000000 # READ BUFFER - allowed RAM start
DF17811 0x4A118 0x0041FFFF 0x00FFFFFF # READ BUFFER - allowed RAM end

# Coolscan LS-40
PT17035 0x169F4 "1.20" "2.01" # Version in INQUIRY response
PT17035 0x16A33 0x2001 0x0102 # Version in USB descriptor (High Speed)
PT17035 0x29EB3 0x03 0x42 # Enable adapter ID 3
PT17035 0x29EB9 0x05 0x42 # Enable adapter ID 5
PT17035 0x29EBF 0x06 0x42 # Enable adapter ID 6
PT17035 0x47C3B "1.20" "2.01" # Version in strings
PT17035 0x47F06 0x00400000 0x00000000 # READ BUFFER - allowed RAM start
PT17035 0x47F0A 0x0041FFFF 0x00FFFFFF # READ BUFFER - allowed RAM end
93 changes: 93 additions & 0 deletions scripts/apply_patch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Coolscan firmware patcher. Just a bunch of helper functions really,
# to make the patches easy to understand and apply.


import os


class Patch(object):

def __init__(self, model, offset, length, original, patched):

self.model = model
self.offset = offset
self.length = length
self.original = original
self.patched = patched

def __repr__(self):

return "Patch[%s]<0x%x: %s => %s>" % (self.model, self.offset, self.original.hex(), self.patched.hex())

def apply(self, model, target):

if model != self.model:
return
print(self)
value = bytes(target[self.offset:self.offset+self.length])
assert value == self.original
target[self.offset:self.offset+self.length] = self.patched

@classmethod
def parse(cls, line):

# remove trailing comment
line = line.partition('#')[0]
# remove whitespace
line = line.strip()
# bail out if the line was empty
if not line:
return None
# split into components
model, offset, original, patched = line.split()
# parse/validate them
assert offset.startswith("0x")
offset = int(offset, 0) - 0x10000 # update files start at 0x10000
assert len(original) == len(patched)
if original.startswith("0x"):
length = len(original)//2 - 1
original = int(original, 0).to_bytes(length, byteorder='big')
patched = int(patched, 0).to_bytes(length, byteorder='big')
elif original.startswith("\""):
length = len(original)-2
original = original[1:-1].encode('ascii')
patched = patched[1:-1].encode('ascii')
else:
raise ValueError("Unknown format for original/patched")
return cls(model, offset, length, original, patched)


class Patchset(object):

def __init__(self, path):

self.patches = []
lines = open(path).readlines()
for line in lines:
patch = Patch.parse(line)
if patch is not None:
self.patches.append(patch)

def apply(self, model, target):
for patch in self.patches:
patch.apply(model, target)

def main():
source_dir = "firmware/original"
target_dir = "firmware/patched"
files = [ "DF17811.bin", "PT17035.bin" ]
patchset = Patchset("firmware/patches.txt")

for file in files:
model = file.removesuffix('.bin')
source_path = os.path.join(source_dir, file)
target_path = os.path.join(target_dir, file)
data = bytearray(open(source_path, 'rb').read())
patchset.apply(model, data)
open(target_path, 'wb').write(data)

if __name__ == '__main__':
main()

0 comments on commit 955c3eb

Please sign in to comment.