Extract drive unlock behind pluggable Unlocker seam

libfreemkv must stay firmware-clean for crates.io. Move ALL drive-unlock
knowledge — firmware blobs, WRITE_BUFFER/MODE SELECT upload, unlock CDBs,
the MT1959 variant-A/B handshake, the 800 KB profiles.json database, and
the DriveProfile parsing — out into the freemkv-unlock-ld crate.

libfreemkv now keeps only the seam:
  - Unlocker trait (name/matches/unlock) + a process-wide ordered registry
    (register_unlocker / route_unlock) in src/unlock.rs
  - Drive::init() walks the registry; the first unlocker whose matches(id)
    is true runs unlock(scsi, id); if none match the drive is left in
    stock mode and the host-cert AACS handshake (the OEM route) carries
    the disc.

The unlocker issues its own CDBs through the public ScsiTransport::execute,
so libfreemkv knows nothing about how unlocking happens.

Removed:
  - profiles.json
  - src/platform/mt1959/{mod,variant_a,variant_b}.rs
  - src/profile.rs (DriveProfile, ProfilesFile, find_by_drive_id, ...)
  - the PlatformDriver trait

Because the Unlocker seam reports only success/failure (no extended-access
marker), VID acquisition is now always via the cert-based handshake; the
per-drive OEM-VID-CDB shortcut and Drive::is_unlocked() (now const false)
are removed/neutralized. Disc-speed calibration moved into the unlocker's
unlock(); Drive::probe_disc() is a no-op.

git grep over src/ is firmware-blob/profiles/WRITE_BUFFER/mt1959-free.
All tests pass on Rust 1.86 (precommit green).
This commit is contained in:
Matthew Jackson
2026-06-22 10:31:51 -07:00
parent f74979bdb4
commit 6dc62bcd84
11 changed files with 291 additions and 5978 deletions
+15 -7
View File
@@ -1,7 +1,9 @@
//! libfreemkv -- Open source optical drive library for 4K UHD / Blu-ray / DVD.
//!
//! Handles drive access, disc structure parsing, AACS decryption, and raw
//! sector reading. 206 bundled drive profiles. No external files needed.
//! sector reading. Drive unlocking is pluggable: libfreemkv owns only the
//! [`Unlocker`] seam and registry — firmware blobs and unlock CDBs live in
//! an external crate (e.g. `freemkv-unlock-ld`).
//!
//! # Quick Start
//!
@@ -44,10 +46,9 @@
//! ```text
//! Drive -- open, identify, unlock, read sectors
//! ├── ScsiTransport -- SG_IO (Linux), IOKit (macOS)
//! ├── DriveProfile -- per-drive unlock parameters (206 bundled)
//! ├── DriveId -- INQUIRY + GET_CONFIG identification
//! └── Platform
//! └── Mt1959 -- MediaTek unlock/read (Renesas planned)
//! └── Unlocker -- pluggable, external (e.g. freemkv-unlock-ld);
//! libfreemkv owns only the trait + registry
//!
//! Disc -- scan titles, streams, AACS state
//! ├── UDF reader -- Blu-ray UDF 2.50 with metadata partitions
@@ -103,12 +104,12 @@ pub(crate) mod mpls;
pub mod mux;
pub mod pes;
pub(crate) mod platform;
pub mod profile;
pub mod progress;
pub mod scsi;
pub mod sector;
pub(crate) mod speed;
pub(crate) mod udf;
pub mod unlock;
pub mod verify;
// Re-export verify types at the crate root for ergonomic imports.
@@ -157,8 +158,15 @@ pub use io::pipeline::{
// ─── Drive events (low-level callbacks) ─────────────────────────────────────
pub use event::{BatchSizeReason, Event, EventKind};
pub use identity::DriveId;
pub use profile::DriveProfile;
// Platform trait is pub(crate) — callers use Drive, not Platform directly.
// ─── Pluggable unlock seam ──────────────────────────────────────────────────
//
// libfreemkv carries no firmware blobs / unlock CDBs / drive profiles. An
// external unlocker crate (e.g. `freemkv-unlock-ld`) implements `Unlocker`
// and registers it once at process start via `register_unlocker`. At
// drive-prep the registry is walked in order; the first matching unlocker
// runs, else the drive falls through to the host-cert AACS handshake.
pub use unlock::{Unlocker, register_unlocker};
// ─── Decryption (AACS / CSS) ────────────────────────────────────────────────
//