Skip to content
This repository was archived by the owner on Oct 30, 2026. It is now read-only.

Add the iPad 5 Wi-Fi (J71t) adapter and multi-adapter discovery - #2

Closed
brkosebay wants to merge 5 commits into
OrchardLinux:mainfrom
brkosebay:j71t-support
Closed

brkosebay wants to merge 5 commits into
OrchardLinux:mainfrom
brkosebay:j71t-support

Conversation

@brkosebay

@brkosebay brkosebay commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

iPad 5 (J71t) port: three PRs, in release order

  1. Add iPad 5 Wi-Fi (J71t) hardware support orchard#6: kernel series, device data, firmware recipe, recovery and runtime
  2. Add the iPad 5 Wi-Fi (J71t) adapter and multi-adapter discovery #2: J71t adapter and multi-adapter discovery
  3. Build Omarchy A for iPad 5 Wi-Fi (J71t) beside J71b omarchy-a#4: J71t image and release

Kernel source: brkosebay/linux a9/orchard-j71t · Project: brkosebay/omarchy-ipad5

Depends on the hardware PR (it needs a hardware wheel with devices/j71t).

Summary

  • Discovery with several adapters.
    • Adapters raise UnsupportedDevice (a ValueError subclass in
      contracts.py) when the connected target is a different model.
    • choose() skips those refusals, reports shared USB errors once and refuses
      if two adapters claim a target.
    • When nothing matches, it says which devices are supported. The J71b adapter
      now raises the refusal for other chips/boards and for a foreign recovery
      product string; its own errors are unchanged.
    • docs/adapter-contract.md documents the rule.
  • Commands.
    • orchard devices merges every adapter's observations.
    • orchard mixin picks the profile from the ADT model (matched against the
      hardware descriptors), or takes --profile.
    • resolve --profile still defaults to j71b but accepts only registered
      profiles.
  • SmartIO extractor moved to apple/smartio.py. It takes the kext bundle
    as a parameter, and J71b's default is unchanged.
  • Video-decoder firmware. apple/d5500.py copies the VXD (DEVA) image out
    of the AppleD5500 kext in the pinned kernelcache. The kext has no
    __firmware section, so the image is found through its pointer record in
    __DATA.__data (name, build, sizes, image pointer), not by offsets. The
    prelinked-kext lookup that SmartIO used moved to apple/prelink.py and is
    shared; SmartIO's behaviour and messages are unchanged. The kernelcache is
    extracted once for both.
  • New orchard_cli.j71t (adapter, config, inputs, prepare, mixin):
    • touch.py: validates the N1 boot packet from J71t.mtprops (C1F15,1,
      header/length/checksums) and returns it unmodified. J71t needs no Z2FW
      wrapper.
    • calibration.py: the j71t-adt generator. It copies multi-touch-calibration
      (1024 B), alsCalibration, usb-input-limit-calibration and the Bluetooth
      local-mac-address from the fresh recovery ADT, and rejects unresolved
      syscfg/ placeholders, blank, wrong-size and non-unicast values.
    • inputs.py derives four inputs: the Bluetooth patchram, SmartIO, the N1
      packet and vxd-deva.bin.
    • capture_adt requires iPad6,11 and J71tAP. iPad6,11 also ships as J71s
      (S8000), which discovery refuses (chip 0x8000). The J71t unit we test
      reports CPID 0x8003 and BDID 0x10 in DFU.
  • Packaging. pyproject, mypy and typecheck_adapter.py (J71T: Adapter)
    updated; README and NOTICE too.

Testing done

  • Unit tests. python -m unittest discover -s tests with the hardware and
    CLI wheels installed: 153 tests OK on Python 3.12 and 3.9 (136 before). One
    skipped test runs only with ORCHARD_TEST_LOCAL_J71T. A synthetic
    kernelcache test covers the VXD record lookup, including no record, two
    records and a missing kext.
  • Types. uv tool run --from 'mypy==1.18.2' mypy --config-file pyproject.toml
    reports no issues.
  • Pinned hashes. With ORCHARD_TEST_LOCAL_J71T pointing at files from
    the same 20H350 build (its kernelcache, BlueTool, J71t.mtprops), the
    local test reproduces the recipe pins for s8000-smartio.bin,
    vxd-deva.bin, BCM4355C0-FearA-USI.hcd and j71t-n1.bin.
  • ADT generator. Run on a J71t boot ADT captured from m1n1, it matched,
    byte for byte, the calibration files the same drivers use on that unit in
    the omarchy-ipad5 port. The
    outputs were discarded; no device data is in the repository.

Not tested

  • inputs.ensure() against a real IPSW download (mocked in tests).
  • Any device step through Orchard: discovery, recovery boot, ADT capture and
    mixin on a J71t. The kernel drivers themselves passed 13 of 13 device checks
    through the omarchy-ipad5 port's own boot path.

How to test

  1. Install the hardware and CLI wheels, then run
    python -m unittest discover -s tests and the mypy command above.
  2. With a J71t in DFU, orchard devices, then boot recovery and run
    orchard capture-adt, orchard mixin --adt … --firmware-dir … --output …
    and orchard prepare --recovery ….

Credits

  • Touch format and VXD record. The N1 packet, calibration facts and the
    AppleD5500 firmware record layout come from the
    omarchy-ipad5 iPad 5 port,
    which builds on Paul Praschl's (Pauli1Go) HoolockLinux A10 work and
    HoolockLinux.
  • Structure. The adapter structure follows the J71b reference adapter.

🤖 Generated with Claude Code

brkosebay and others added 5 commits October 27, 2026 16:32
Discovery tried every registered adapter but treated another model's
refusal as an error, so a second adapter could only report "Unsupported
device" for the first. Adapters now raise UnsupportedDevice (a ValueError)
for targets they do not support; choose() ignores those refusals, reports
shared USB errors once and names the supported devices when nothing
matches. `orchard devices` lists every adapter's observations, and
`orchard mixin` selects its profile from the ADT model or --profile
instead of a hidden default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move the legacy prelinked-kernelcache SmartIO extractor out of the J71b
package into the shared Apple tooling and select the kext by bundle
identifier. J71b keeps the AppleT8010SmartIO default unchanged; A9
devices use AppleS8000SmartIO.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Register a J71t (iPad6,11, S8003) host adapter beside J71b. It discovers
DFU chip 0x8003 / board 0x10 and "J71t Recovery", and requires the J71tAP
board in the captured ADT because iPad6,11 also ships as J71s (S8000).

Firmware inputs follow the hardware recipe: Wi-Fi and Bluetooth files from
the iPadOS 16.7.10 IPSW, S8000 SmartIO firmware from its kernelcache, and
the unmodified N1 touch boot packet from J71t.mtprops. The "j71t-adt"
generator copies the unit's touch, ambient-light, charger and Bluetooth
address records from the fresh recovery ADT, rejecting unresolved or
blank records, and stages them with receipts for the data-only mixin.

Tests use synthetic ADT, packet and kernelcache fixtures only. An optional
check reproduces the pinned derived hashes from a developer's own 20H350
files when ORCHARD_TEST_LOCAL_J71T is set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
List the supported devices and their profiles in the README, note that
both registered adapters are statically checked against the contract, and
credit the J71t touch and calibration preparation sources.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The J71t kernel now carries the VXD stateless H.264 decoder. Its DEVA
firmware ships inside the AppleD5500 kext of the pinned iPadOS
kernelcache, found by its pointer record in __DATA.__data. apple/d5500.py
copies the image unchanged; the hardware recipe pins it as vxd-deva.bin.

The kext lookup SmartIO already used moves to apple/prelink.py and is
shared; SmartIO behavior and messages are unchanged. The kernelcache is
extracted once for both inputs. NOTICE names the public omarchy-ipad5
port as the source of the J71t touch, calibration and record layout
code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@brkosebay

Copy link
Copy Markdown
Contributor Author

Update: J71t charging is validated; no change needed in this PR

The charging fix is kernel-only. It is a new patch in OrchardLinux/orchard#6 (commit 0dd7ae0 on a9/orchard-j71t).

The CLI is unaffected:

  • no new firmware inputs;
  • the charger still reads only its usb-input-limit-calibration from the device's ADT through the j71t-adt generator.

With the updated hardware wheel installed, the tests still pass: 153 OK and 1 skipped (local inputs only), with mypy clean.

Computers and USB-C chargers now charge at up to 2.4 A on the iPad 5 (validated 2026-10-27 through the omarchy-ipad5 port's boot path).

@henrikklee

Copy link
Copy Markdown
Contributor

Thank you, Berkay. The shared parts of this PR are merged on main with your authorship: 91fea99 (your prelink.py, smartio.py and d5500.py) and dbf78a7 (your touch packet as a recipe step), plus the recipe steps the iPad 5 firmware uses. The J71t adapter and multi-adapter discovery aren't needed any more, because the CLI now has one adapter driven by device descriptors. Details are in docs/integration/j71t.md (topic 18) on the hardware branch feature/j71t-integration. Closing this one as merged that way.

@henrikklee henrikklee closed this Oct 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants