drive: run drive-prep unlock for EVERY disc, incl. DVD (fix riplock regression)
The v1.0.0-rc.1 unlocker refactor added an `if disc_is_dvd() { return }`
early-return in Drive::init() that skipped the whole drive-prep unlock for
DVDs. That firmware unlock is what lifts riplock and readies max read
speed — a DRIVE-level, disc-independent feature — so skipping it left
every DVD stuck at stock/riplock speed (~0.4x, 3h ETA). UHD was unaffected
because it flows through the unlock.
Remove the skip: init() now runs the identity-keyed drive unlocker for all
discs (disc kind is Unknown at init, so only the drive unlocker matches;
the AACS host-cert handshake and CSS bus-auth still run later, gated on the
real disc kind, on top of the unlocked drive). Speed stays where it
belongs — SET CD SPEED(0xFFFF) at pass-1 start (disc/mod.rs) — not in the
unlocker. Also drop the matching probe_disc DVD skip.
Reverts the SET STREAMING stopgap (separate freemkv-unlock revert): that
treated the symptom; the real bug was the skipped unlock. Drive features
come from the firmware unlock, not a stock speed CDB.
This commit is contained in:
+20
-35
@@ -411,27 +411,18 @@ impl Drive {
|
|||||||
pub fn init(&mut self) -> Result<()> {
|
pub fn init(&mut self) -> Result<()> {
|
||||||
let t0 = std::time::Instant::now();
|
let t0 = std::time::Instant::now();
|
||||||
tracing::info!(target: "freemkv::drive", phase = "init", "begin");
|
tracing::info!(target: "freemkv::drive", phase = "init", "begin");
|
||||||
// Drive-level features (max read speed / riplock lift) — matched on the
|
// Drive-prep runs for EVERY disc, DVD INCLUDED. The drive-level firmware
|
||||||
// DRIVE, applied for ANY disc. STOCK MMC commands only (no firmware
|
// unlock lifts riplock and readies max read speed regardless of disc type
|
||||||
// unlock), so this is safe for a CSS DVD that must stay in stock mode.
|
// — drive features are disc-independent. At init the disc kind is not yet
|
||||||
// Runs BEFORE the DVD early-return below so a DVD is no longer riplocked:
|
// probed (Unknown), so only the identity-keyed DRIVE unlocker matches
|
||||||
// previously only the BD/UHD path (which returns clear content via the
|
// here; the AACS host-cert handshake and the CSS bus-auth handshake run
|
||||||
// firmware unlock + its speed calibration) got up to speed, and DVD fell
|
// LATER, each gated on the actual disc kind, on TOP of the already-
|
||||||
// through with just the legacy SET CD SPEED the drive ignores.
|
// unlocked drive. A genuine transport fault means the bus is dead — abort
|
||||||
crate::unlock_bridge::apply_drive_features(self.scsi.as_mut(), &self.drive_id);
|
// init (the v1.1.0 invariant; `if let Ok` was silently swallowing it).
|
||||||
if self.disc_is_dvd() {
|
// Every other error (NotApplicable / no match) is "nothing applied" —
|
||||||
tracing::info!(target: "freemkv::drive", phase = "init", dvd = true, elapsed_ms = t0.elapsed().as_millis() as u64, "end (stock-mode DVD, drive features applied, no bus unlock)");
|
// fall through to stock mode. NOTE: the `if disc_is_dvd() { return }` skip
|
||||||
self.init_ran = true;
|
// that used to sit here was the v1.0.0-rc.1 regression — it skipped the
|
||||||
return Ok(());
|
// drive-prep for DVD, leaving DVDs riplocked at stock speed.
|
||||||
}
|
|
||||||
// Drive-prep dispatch: the disc structure has not been probed yet, so
|
|
||||||
// the kind is Unknown — only an identity-keyed unlocker can match here.
|
|
||||||
// The first matching unlocker runs; none matching leaves the drive in
|
|
||||||
// stock mode so the host-cert AACS handshake (the OEM route) carries the
|
|
||||||
// disc. A genuine transport fault means the bus is dead — abort init
|
|
||||||
// (the v1.1.0 invariant; `if let Ok` was silently swallowing it). Every
|
|
||||||
// other error (NotApplicable / no match) is "nothing applied" — fall
|
|
||||||
// through to stock mode.
|
|
||||||
self.init_ran = true;
|
self.init_ran = true;
|
||||||
let r: Result<()> = match crate::unlock_bridge::run_unlockers(
|
let r: Result<()> = match crate::unlock_bridge::run_unlockers(
|
||||||
self.scsi.as_mut(),
|
self.scsi.as_mut(),
|
||||||
@@ -457,13 +448,12 @@ impl Drive {
|
|||||||
}),
|
}),
|
||||||
Err(_) => Ok(()),
|
Err(_) => Ok(()),
|
||||||
};
|
};
|
||||||
// Raise the drive to its maximum read speed with a generic SET CD SPEED —
|
// Raise the drive to its maximum read speed — UNCONDITIONALLY whenever
|
||||||
// UNCONDITIONALLY whenever the bus is alive (init didn't transport-fault),
|
// the bus is alive (init didn't transport-fault), whether or not an
|
||||||
// whether or not an unlocker matched. A stock-mode BD/UHD drive (no
|
// unlocker matched, and for ANY disc type (DVD now flows through here too,
|
||||||
// firmware unlocker) still wants max speed; gating this on an unlocker
|
// so it gets max speed on the freshly firmware-unlocked drive instead of
|
||||||
// match left such drives riplocked. (DVD returns earlier in stock mode;
|
// the stock riplock). A stock-mode drive with no firmware unlocker still
|
||||||
// its sweep sets DVD speed separately.) Best-effort: a failure here must
|
// wants max speed. Best-effort: a failure here must NOT fail the rip.
|
||||||
// NOT fail the rip — a slow drive still rips.
|
|
||||||
if r.is_ok() {
|
if r.is_ok() {
|
||||||
self.set_speed(crate::speed::DriveSpeed::Max.to_kbps());
|
self.set_speed(crate::speed::DriveSpeed::Max.to_kbps());
|
||||||
}
|
}
|
||||||
@@ -484,14 +474,9 @@ impl Drive {
|
|||||||
pub fn probe_disc(&mut self) -> Result<()> {
|
pub fn probe_disc(&mut self) -> Result<()> {
|
||||||
let t0 = std::time::Instant::now();
|
let t0 = std::time::Instant::now();
|
||||||
tracing::info!(target: "freemkv::drive", phase = "probe_disc", "begin");
|
tracing::info!(target: "freemkv::drive", phase = "probe_disc", "begin");
|
||||||
// A DVD runs in stock mode (see `init`); skip the OEM/drive-prep
|
|
||||||
// disc calibration, which only applies to the unlocked BD/UHD drive.
|
|
||||||
if self.disc_is_dvd() {
|
|
||||||
tracing::info!(target: "freemkv::drive", phase = "probe_disc", dvd = true, elapsed_ms = t0.elapsed().as_millis() as u64, "end (stock-mode DVD, no calibration)");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
// Disc-speed calibration is unlocker-specific and now lives inside
|
// Disc-speed calibration is unlocker-specific and now lives inside
|
||||||
// the unlocker's `unlock()` (run at `init()`). Nothing to do here.
|
// the unlocker's `unlock()` (run at `init()`, for every disc including
|
||||||
|
// DVD). Nothing to do here — no disc-type branch.
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
target: "freemkv::drive",
|
target: "freemkv::drive",
|
||||||
phase = "probe_disc",
|
phase = "probe_disc",
|
||||||
|
|||||||
@@ -124,26 +124,6 @@ pub(crate) fn run_unlockers(
|
|||||||
Err(fu::UnlockError::NotApplicable)
|
Err(fu::UnlockError::NotApplicable)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply drive-level feature tuning (max read speed / riplock lift) for the
|
|
||||||
/// installed drive, for ANY disc. This is the drive-features capability, kept
|
|
||||||
/// separate from bus removal: it issues only STOCK MMC commands (no firmware
|
|
||||||
/// unlock), so it is safe on a CSS DVD that must stay in stock mode. Each
|
|
||||||
/// unlocker's `apply_drive_features` is self-gating (a no-op unless it recognises
|
|
||||||
/// the drive), so we call every one; disc kind is irrelevant here, so we pass
|
|
||||||
/// `Unknown`. Best-effort — never returns an error to the caller (a slow drive
|
|
||||||
/// still rips).
|
|
||||||
pub(crate) fn apply_drive_features(
|
|
||||||
scsi: &mut dyn crate::scsi::ScsiTransport,
|
|
||||||
drive_id: &crate::identity::DriveId,
|
|
||||||
) {
|
|
||||||
let id = to_fu_drive_id(drive_id);
|
|
||||||
let ctx = fu::UnlockCtx::new(&id, fu::DiscKind::Unknown, &[]);
|
|
||||||
let mut adapter = ScsiAdapter(scsi);
|
|
||||||
for u in fu::all_unlockers() {
|
|
||||||
let _ = u.apply_drive_features(&mut adapter, &ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user