Created
January 21, 2026 20:30
-
-
Save Tombarr/d336f2da2f9e5138f10b236c4424ddaf to your computer and use it in GitHub Desktop.
Automatically boot into fastboot mode on the TCL Flip 2, for unlocking phones with KEKA firmware
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # original by neutronscott: https://github.com/neutronscott/flip2/blob/main/autobooter.py | |
| # 2026-01-21 tombarr rewrote to use pyserial for macOS | |
| import serial | |
| import serial.tools.list_ports | |
| import time | |
| import sys | |
| # MTK Preloader constants | |
| VID = 0x0E8D | |
| PID = 0x2000 | |
| def get_ports(): | |
| """Finds ports matching the MTK Preloader VID/PID on macOS.""" | |
| ports = [] | |
| all_ports = serial.tools.list_ports.comports() | |
| for p in all_ports: | |
| # Check if the hardware IDs match | |
| if p.vid == VID and p.pid == PID: | |
| ports.append(p.device) | |
| return ports | |
| def try_port(port, bootseq): | |
| confirm = b"READY" + bytes(bootseq[:-4:-1], "ascii") | |
| try: | |
| # Prefer 'cu.' devices over 'tty.' for calls | |
| s = serial.Serial(port, 115200, timeout=1) | |
| print(f"\nConnected to {port}. Sending {bootseq}") | |
| s.write(bytes(bootseq, "ascii")) | |
| resp = s.read(8) | |
| if resp == confirm: | |
| print(f"Success! Entered fastboot mode on {port}") | |
| sys.exit(0) | |
| else: | |
| if resp: | |
| print(f"Unknown response: {resp.hex()} on {port}") | |
| s.close() | |
| except (OSError, serial.SerialException): | |
| # Port might be busy or disappearing (common during boot) | |
| print(".", end="", flush=True) | |
| def main(): | |
| print("Instructions: Have USB attached, then insert battery/reset device.") | |
| bootseq = sys.argv[1] if len(sys.argv) > 1 else "FASTBOOT" | |
| print("Scanning for MTK Preloader (VID:0E8D PID:2000)...", end="") | |
| while True: | |
| ports = get_ports() | |
| for port in ports: | |
| try_port(port, bootseq) | |
| time.sleep(0.1) | |
| print(".", end="", flush=True) | |
| if __name__ == '__main__': | |
| try: | |
| main() | |
| except KeyboardInterrupt: | |
| print("\nUser Canceled!") | |
| sys.exit(101) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment