Commit Graph
21 Commits
Author SHA1 Message Date
MattJackson 65996ade59 Remove SpeedTable, add probe_disc(), named constants, clean architecture
- Removed SpeedTable entirely — drive manages speeds after probe
- Renamed read_speed_table() → probe_disc()
- Named all SCSI constants: SUB_CMD_UNLOCK, SUB_CMD_INIT, SUB_CMD_PROBE,
  INIT_ADDR_BD, INIT_ADDR_UHD, PROBE_COARSE_END, PROBE_FINE_END, etc.
- Auto-detect BD vs UHD from disc capacity for correct probe init address
- Fixed NOMINAL_SPEED_B (was invalid CDB, removed — single max instead)
- Added session.set_speed() for simple speed control
- Error recovery: re-init on first error, BD2x on repeated errors
- Batch size uses full kernel limit (was 80%, now 100%)
- Clean variant_a/variant_b with named constants

API: open() → wait_ready() → init() → probe_disc() → scan() → read
2026-04-09 15:17:25 -07:00
MattJackson 09f5bb7816 Speed table: generic zone-based speed management
- SpeedTable: maps disc positions to optimal speeds
- Default: max speed everywhere (drive manages itself)
- After read_speed_table(): calibrated per-zone speeds
- One u32 comparison per read on hot path
- Error recovery: reduce() / resume() override table temporarily
- Replaces old tier-based speed management in ContentReader
- MT1959 split into mod.rs + variant_a.rs + variant_b.rs
- PlatformDriver: init() + read_speed_table() + is_ready()
2026-04-09 13:33:02 -07:00
MattJackson d23632931b Profiles v2: chipset+variant top-level keys, minimal per-drive data
profiles.json: { "mt1959_a": [...], "mt1959_b": [...], "renesas": [] }
Each profile: identity + signature + firmware (3 fields)
Platform enum replaces Chipset — section determines variant
2026-04-09 12:50:44 -07:00
MattJackson 0c11623666 v0.6.0: Clean API, chipset-keyed profiles, streamlined platform driver
- API: open() is OEM-only, wait_ready() separate, init() optional
- Profiles: chipset-keyed JSON ({ "mt1959": [...], "renesas": [] })
- Profiles: identity group, variant + signature + firmware per drive
- Platform constants: mode, buffer_id, nominal speed, verify commands
  moved from profiles to code (variant-determined, not per-drive)
- Removed unused fields: register CDBs, speed tables, status data
- Platform driver: unlock + firmware upload + calibrate + speed only
- Cross-compile fix: build.rs uses CARGO_CFG_TARGET_OS for framework linking
2026-04-09 12:38:02 -07:00
MattJackson 6456e24bb5 Lock down Platform trait: pub(crate), only init/set_read_speed/is_ready
Platform trait is no longer publicly exported. External code uses
DriveSession only — cannot call unlock, load_firmware, calibrate directly.

- Platform trait: pub(crate) with 3 methods only
- All handlers are private methods on Mt1959
- DriveStatus moved to mt1959 internal struct
- init() has guard: no re-init if already ready
- set_read_speed() has guard: no-op if not calibrated
- Removed open_unlocked() — open() is the only entry
- Removed Platform and DriveStatus from public exports

Prevents: out-of-sequence SCSI commands, double-init, wrong firmware writes.
2026-04-08 21:41:57 -07:00
MattJackson 0b19154bd3 Clean pipeline: one open, one init, no double-init
- Removed open_unlocked() — open() is the only entry
- Removed redundant init() call from open_title()
- init() called once in open(), handles everything
- Each function does one thing: open→init→scan→read
2026-04-08 21:35:48 -07:00
MattJackson ce8ddb48bb DriveProfile with all per-drive fields, drive.rs uses init() as single entry
DriveProfile now has every field traced from firmware:
- drive_signature, unlock_init_value, unlock_response_size_minus_init
- ld_microcode (base64, ~1888B firmware payload)
- hardware_register_a_cdb, hardware_register_b_cdb (10B pre-built CDBs)
- drive_nominal_speed_cdb (12B calibration speed)
- speed_zone_table (28B), speed_calc_table (25B)

drive.rs simplified:
- open() calls init() instead of unlock()
- init() is the ONLY entry point — handles full dispatch sequence internally
- Removed read_config, read_register, maintain_speed, read_sectors from public API
- Added set_read_speed() for per-zone speed during content reads
- disc.rs updated to call init() instead of unlock()

Compiles clean, all tests pass.
2026-04-08 20:15:25 -07:00
MattJackson 3fcab4d8d9 Strip to bare minimum for speed test: no calibration, no maintain_speed
Back to basics: open, unlock, SET CD SPEED max, read.
Remove all calibration probes, register reads, maintain_speed calls.
This is closest to the build that hit 17 MB/s earlier.

Also: drive discovery moved to libfreemkv (find_drive, resolve_device),
AACS via UDF only, clean pipeline, sg device support.
2026-04-08 15:46:42 -07:00
MattJackson f46d9706eb Fix rip: extent LBA offset, u16 truncation, batch reads, read_content
- Fixed: extents were relative to m2ts file, not absolute disc LBAs
- Fixed: u16 truncation of remaining sector count (13M → 36!)
- Added: UdfFs::file_start_lba() for m2ts LBA lookup
- Added: DriveSession::read_content() with 30s timeout for bulk reads
- Added: SET CD SPEED 0xFFFF on title open
- Added: adaptive batch reading (96→48→3 on error, ramp back up)
- Rip working end-to-end: scan → AACS → decrypt → write
2026-04-08 10:12:07 -07:00
MattJackson 0bb815ca22 Restructure labels: detect-then-parse, named parsers, raw disc data
Architecture:
- Each BD-J format in own file: paramount.rs, criterion.rs, pixelogic.rs, ctrm.rs
- Standard interface: detect() → bool, parse() → Option<Vec<StreamLabel>>
- PARSERS array in mod.rs — drop in a new parser with one line
- Shared vocab.rs for BD spec codec names only (MLP→TrueHD, AC3→Dolby Digital)
- All other label data passes through raw from disc — no guessing

Changes:
- New: paramount.rs (playlists.xml — Paramount/onQ format)
- Renamed: bluray_project.rs → pixelogic.rs
- Renamed: stream_properties.rs → criterion.rs
- Merged: language_streams.rs + menu_base.rs → ctrm.rs
- Removed: jar module (superseded by labels), dead apply functions
- Added: DriveSession::eject() with PREVENT ALLOW MEDIUM REMOVAL
- Added: DiscRegion enum (Free/BluRay/Dvd)
- Fixed: capture sector ranges now include all files (only skip STREAM/)
- Renamed: StreamLabel.region → variant (not a BD spec field)
2026-04-07 20:29:44 -07:00
MattJackson fd443e3a2f Add disc title, format, streams to Disc::scan() — move logic from CLI to lib
- Disc.volume_id: UDF Volume ID from PVD (always present)
- Disc.meta_title: from META/DL/bdmt_eng.xml (falls back to other languages)
- Disc.format: UHD/BluRay/DVD detected from video codec
- Disc.capacity_bytes, Disc.layers
- Disc.jar_labels: extracted from BDMV/JAR
- Fixed MPLS STN parsing: 16-byte header (was 8), proper stream entry offsets
- Streams now include: HDR, color space, Dolby Vision EL, secondary audio/video
- parse_dstring() for UDF d-string fields
- wait_ready() polls TEST UNIT READY before unlock

Tested on 12 disc captures — all return correct titles, streams, format.
2026-04-07 15:36:05 -07:00
MattJackson d0c5c7fb97 Named constants, error codes, SCSI opcodes, flow documentation
- Error codes as public constants (E_DEVICE_NOT_FOUND etc.) — single source of truth
- SCSI opcodes as named constants (SCSI_READ_10, SCSI_REPORT_KEY, etc.)
- AACS key class constant, MKB format constant
- No magic numbers in CDB construction
- docs/disc-to-rip.md — end-to-end flow from disc insert to decrypted content
- Links all module docs together as a starting point
2026-04-07 12:26:30 -07:00
MattJackson 272215c551 Clean up for public release: docs, zero warnings, no hardcoded paths
Documentation:
- docs/aacs.md — AACS encryption (1.0 + 2.0), key resolution, decrypt
- docs/udf.md — UDF 2.50 filesystem with metadata partitions
- docs/mpls.md — MPLS playlist format, STN stream table
- docs/clpi.md — CLPI clip info, EP map, sector extents
- docs/architecture.md — library module map, design principles
- docs/drive-access.md — drive sessions, SCSI transport, unlock

Code cleanup:
- Zero compiler warnings
- Removed all debug eprintln from library code
- No hardcoded private paths — KEYDB tests use KEYDB_PATH env var
- KEYDB search locations as named constants
- drive.rs: extracted create_platform(), deduplicated open methods
- lib.rs: updated doc examples to show Disc::scan() API
- Fixed UDF file reads (partition_start, not metadata_start)
- Exported KeySource from disc module
2026-04-07 12:12:24 -07:00
MattJackson cc58ab1754 AACS graceful fallback: handshake optional, disc-hash-only KEYDB path
- SCSI handshake now optional: if drive doesn't support AACS layer
 (e.g. raw-mode drives where AACS feature current=0), falls back
 to disc-hash-only KEYDB lookup
- open_no_unlock(): open drive without entering raw mode
- device_path tracking on DriveSession
- Real drive test: BU40N with Civil War UHD
 - Handshake correctly fails (05/6F/01 key not present — expected)
 - Scan continues, finds AACS directory, reads Unit_Key_RO.inf
 - KEYDB lookup attempted (disc hash matching WIP)
2026-04-07 11:41:34 -07:00
MattJackson eb3b84216a Reduce read_disc timeout to 5s (was 30s)
Prevents indefinite hangs on encrypted/unreadable sectors.
Some discs put MPLS/CLPI/JAR data in AACS-encrypted regions
that block reads without proper AACS authentication.
2026-04-06 18:22:43 -07:00
MattJackson a07a7aebf2 Always unlock on DriveSession::open()
Silently ignores unlock failures (unencrypted discs).
Fixes disc-info on discs that gate reads behind AACS auth.
2026-04-06 17:06:32 -07:00
MattJackson 7db4606038 Add disc format parsers: UDF, MPLS, CLPI
- udf.rs: read files from Blu-ray disc filesystem
- mpls.rs: parse playlists → titles with clips and timestamps
- clpi.rs: parse clip info → EP map with coarse/fine SPN entries
- disc.rs: high-level title scanning, sector extent mapping
- drive.rs: add read_disc() for unencrypted reads, scsi_execute()
- error.rs: add E6000 DiscError

Stage 1 of freemkv rip: identify titles and their sector ranges.
2026-04-06 14:27:48 -07:00
MattJackson e094fc66ba Platform-agnostic SCSI transport with cfg gates
- scsi::open() returns Box<dyn ScsiTransport> on any platform
- Linux SG_IO behind #[cfg(target_os = "linux")]
- macOS IOKit and Windows SPTI stubs with TODO
- drive.rs uses scsi::open() — no platform-specific imports
- Compiles on macOS (returns "platform not yet supported")
2026-04-06 11:34:33 -07:00
MattJackson c26b6f6819 Refactor: Chipset architecture, remove supported/status gatekeeping
- PlatformType → Chipset enum (MediaTek, Renesas)
- unlock_mode + unlock_buf_id stored in profile, not derived from enum
- Removed ReadinessStatus, supported field, needs_flash — library is agnostic
- Removed DriveMatch/Flashable — if we have a profile, try unlock
- profiles.json: chipset + unlock_mode + unlock_buf_id, no program/supported
- mt1959.rs reads mode/buf_id from profile fields directly
- Tests: find_known_drive, find_unknown_drive
2026-04-06 11:21:27 -07:00
MattJackson cbf510e70e Structured error codes: E1000-E5000, no user-facing text in library
Error codes:
 1000-1001: device errors (not found, permission)
 2000-2002: profile errors (unsupported, not found, parse)
 3000-3003: unlock errors (failed, signature, not unlocked, not calibrated)
 4000-4001: SCSI errors (command failed, timeout)
 5000: I/O errors

All errors carry structured data (vendor_id, opcode, etc).
Applications format their own user-facing messages.
Library returns code + data, never English text.
2026-04-06 10:17:43 -07:00
MattJackson b9ea1d29dd libfreemkv v0.1.0 — Open source 4K UHD / Blu-ray / DVD drive library
Features:
- Open drive identification via SPC-4 INQUIRY + MMC-6 GET CONFIGURATION
- 141 supported drives with bundled profiles
- MT1959 platform: unlock, calibrate, raw sector reads
- DriveSpeed enum: BD1x-BD12x, DVD1x-DVD16x
- Field names follow SPC-4 §6.4.2 and MMC-6 §5.3.10 standards
- No proprietary fingerprints — open matching by SCSI fields
- Zero config: profiles compiled into binary

Tested on real hardware: HL-DT-ST BD-RE BU40N 1.03
2026-04-06 10:00:00 -07:00