From 47d5d1e0b94ad7b4c08f74e6d1633955a96c6b6c Mon Sep 17 00:00:00 2001
From: Matthew Jackson <1085847+MattJackson@users.noreply.github.com>
Date: Mon, 22 Jun 2026 11:05:30 -0700
Subject: [PATCH] Rename to the generic Unlocker contract; add
set_max_read_speed
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Track libfreemkv's finalized 3-capability Unlocker trait:
- unlock(...) -> unlock_drive(...)
- read_vid(...) -> read_volume_id(...)
- add set_max_read_speed(...)
set_max_read_speed issues the matched profile's set_speed_max_cdb
(0xBB SET CD SPEED, to max) over the raw transport; a profile without a
set_speed_max_cdb (or no matching profile) is a no-op so the drive stays at
its current speed. read_disc_keys_cdb is left untouched — inert profile data,
never issued, no trait method.
README: document the 3-method contract, the delete-to-comply fallback, and the
#2-only boundary (freemkv uploads RAM microcode to an already-bootloader-flashed
drive; the permanent bootloader flash #1 is the owner's one-time manual step,
never automated). Left a marked MakeMKV attribution placeholder for the
maintainer to author.
Tests: renamed read_vid tests; added set_max_read_speed tests (issues the CDB
when present, no-op when the profile carries none).
---
README.md | 29 ++++++++++++++-
src/lib.rs | 102 +++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 124 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index ab4982b..1d5583a 100644
--- a/README.md
+++ b/README.md
@@ -20,4 +20,31 @@ That single line is the whole plug. Any drive whose identity matches a bundled
profile is firmware-unlocked at drive-prep; everything else falls through to
libfreemkv's host-certificate AACS handshake.
-
+## The `Unlocker` contract
+
+This crate is the LibreDrive unlocker — an implementation of libfreemkv's
+`Unlocker` trait. The trait is a 3-method capability contract:
+
+- `unlock_drive` — put the drive into extended-access mode. The one required
+ capability.
+- `read_volume_id` — read the disc Volume ID directly, bypassing the AACS cert
+ handshake. `None` → libfreemkv falls back to the cert-based read. No-op
+ default.
+- `set_max_read_speed` — raise the drive to its maximum read speed. No-op
+ default.
+
+libfreemkv's AACS layer is the always-present baseline; it uses an unlocker's
+capabilities when one matches, and does the full cert handshake when none do.
+Remove this crate and libfreemkv still compiles and rips — every capability
+falls back to the OEM/baseline path.
+
+## Scope: RAM microcode only (`#2`), never the bootloader flash (`#1`)
+
+freemkv uploads the RAM microcode to an **already-bootloader-flashed** drive.
+The permanent bootloader flash (`#1`) is the drive owner's one-time manual
+step; it is **never** automated by freemkv. This crate only performs the
+non-persistent `#2` step — the microcode lives in RAM and is gone on power
+cycle.
+
+
+
diff --git a/src/lib.rs b/src/lib.rs
index 059b187..c1b5133 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -56,7 +56,7 @@ impl Unlocker for LibreDrive {
profile::find_bundled(id).is_some()
}
- fn unlock(&self, scsi: &mut dyn ScsiTransport, id: &DriveId) -> Result<()> {
+ fn unlock_drive(&self, scsi: &mut dyn ScsiTransport, id: &DriveId) -> Result<()> {
let Some(m) = profile::find_bundled(id) else {
// matches() returned true but the profile vanished — treat as
// "nothing to do"; the caller falls back to the cert handshake.
@@ -101,7 +101,11 @@ impl Unlocker for LibreDrive {
/// * `[3]` reserved
/// * `[4..20]` 16-byte Volume ID
/// * `[20..36]` reserved / per-drive padding
- fn read_vid(&self, scsi: &mut dyn ScsiTransport, id: &DriveId) -> Result