Compare commits
18
Commits
e0bf264538
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28a6e50ede | ||
|
|
3c5cfd02d9 | ||
|
|
93588379c6 | ||
|
|
cc4c9e496d | ||
|
|
4a6f0dee19 | ||
|
|
93988bebba | ||
|
|
c5cf5e6a0c | ||
|
|
71380a0b26 | ||
|
|
f1cedd63d9 | ||
|
|
fb7d74039f | ||
|
|
aa82e9cf6b | ||
|
|
d32d43c2e2 | ||
|
|
eb35571632 | ||
|
|
075352158c | ||
|
|
9fbbe15b29 | ||
|
|
b7f34c46bc | ||
|
|
4120d38151 | ||
|
|
ca8119a167 |
@@ -0,0 +1,46 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [1.6.0] — UNRELEASED
|
||||||
|
|
||||||
|
Version sync with the workspace. No functional change in this crate.
|
||||||
|
|
||||||
|
## [1.5.2] — 2026-07-22
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- The DVD read-unlocker (bus-auth) is renamed `CSS` → `DVD`: it reports the
|
||||||
|
medium it unlocks, not whether a title-key crack ran. The unlocker report now
|
||||||
|
reads `DVD: yes` on any DVD.
|
||||||
|
|
||||||
|
## [1.4.1] — 2026-07-14
|
||||||
|
|
||||||
|
Version sync with the workspace; inherits libfreemkv 1.4.1.
|
||||||
|
|
||||||
|
## [1.4.0] — 2026-07-13
|
||||||
|
|
||||||
|
Version sync with the workspace; inherits libfreemkv 1.4.0.
|
||||||
|
|
||||||
|
## [1.3.2] — 2026-07-10
|
||||||
|
|
||||||
|
Version sync with the workspace; inherits libfreemkv 1.3.2.
|
||||||
|
|
||||||
|
## [1.3.1] — 2026-07-10
|
||||||
|
|
||||||
|
### Licensing
|
||||||
|
|
||||||
|
- **Relicensed to the MIT License, from 1.3.1 onwards** (releases up to and
|
||||||
|
including 1.3.0 remain under AGPL-3.0).
|
||||||
|
|
||||||
|
Version sync with the workspace; inherits libfreemkv 1.3.1.
|
||||||
|
|
||||||
|
## [1.3.0] — 2026-07-08
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **`Unlocker` is now two capability methods.** `unlock_features` (drive
|
||||||
|
riplock / speed / OEM VID at drive-prep) and `unlock_bus` (bus-encryption
|
||||||
|
removal for the mounted disc) replace the single `matches()` + `unlock()`
|
||||||
|
contract. Each defaults to `NotApplicable`, so an unlocker implements only the
|
||||||
|
capabilities it actually provides.
|
||||||
|
- **`DriveId` gains a `product_id` field** carrying the SCSI INQUIRY product
|
||||||
|
string, so consumers can match on it.
|
||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "freemkv-unlock"
|
name = "freemkv-unlock"
|
||||||
version = "1.3.0"
|
version = "1.6.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
rust-version = "1.86"
|
rust-version = "1.86"
|
||||||
license = "AGPL-3.0-only"
|
license = "MIT"
|
||||||
description = "Unlock layer for the freemkv toolchain: the Unlocker contract + self-contained firmware/AACS/CSS unlocker modules. libfreemkv depends on this and dispatches via all_unlockers()."
|
description = "Unlock layer for the freemkv toolchain: the Unlocker contract + self-contained firmware/AACS/CSS unlocker modules. libfreemkv depends on this and dispatches via all_unlockers()."
|
||||||
repository = "https://github.com/freemkv/freemkv-unlock"
|
repository = "https://github.com/freemkv/freemkv-unlock"
|
||||||
# NEVER crates.io: this crate carries drive firmware. Consumed only by git tag.
|
# NEVER crates.io: this crate carries drive firmware. Consumed only by git tag.
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Matthew Jackson & Contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -14,9 +14,17 @@ clients of libfreemkv are oblivious to unlockers entirely (as they are to the
|
|||||||
SCSI layer).
|
SCSI layer).
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
use freemkv_unlock::UnlockError;
|
||||||
|
|
||||||
|
// Drive-prep: try each unlocker's feature unlock until one claims the drive.
|
||||||
|
// `NotApplicable` means "not this unlocker's drive" — move on; a transport
|
||||||
|
// error means a dead bus — abort. `unlock_bus` follows the same contract for
|
||||||
|
// removing per-disc bus encryption.
|
||||||
for u in freemkv_unlock::all_unlockers() {
|
for u in freemkv_unlock::all_unlockers() {
|
||||||
if u.matches(&ctx) {
|
match u.unlock_features(&mut scsi, &ctx) {
|
||||||
return u.unlock(&mut scsi, &ctx);
|
Ok(unlocked) => return Ok(unlocked),
|
||||||
|
Err(UnlockError::NotApplicable) => continue,
|
||||||
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -24,4 +32,4 @@ for u in freemkv_unlock::all_unlockers() {
|
|||||||
To remove an unlocker, delete its module directory and its one line in
|
To remove an unlocker, delete its module directory and its one line in
|
||||||
`all_unlockers()` — nothing else changes.
|
`all_unlockers()` — nothing else changes.
|
||||||
|
|
||||||
License: AGPL-3.0-only.
|
License: MIT.
|
||||||
|
|||||||
+40
-19
@@ -141,27 +141,38 @@ pub fn unlock_css_reads(scsi: &mut dyn ScsiTransport, lba: u32) -> Result<()> {
|
|||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The CSS unlocker — the DVD peer of the firmware and AACS-cert unlockers in
|
/// The DVD unlocker (registry name `"DVD"`) — the DVD peer of the firmware and
|
||||||
/// the uniform [`crate::Unlocker`] registry. It removes the CSS
|
/// AACS-cert unlockers in the uniform [`crate::Unlocker`] registry. It removes
|
||||||
/// scrambled-read barrier (drive ASF=1) and learns no VID or bus key — the
|
/// the DVD scrambled-read barrier (drive ASF=1) via bus-auth and learns no VID
|
||||||
/// descramble key is recovered keylessly downstream (the Stevenson attack).
|
/// or bus key — the descramble key is recovered keylessly downstream (the
|
||||||
pub struct CssUnlocker;
|
/// Stevenson attack). Named for the medium it unlocks (DVD), not the CSS
|
||||||
|
/// scheme: the bus-auth is required to read a CSS-protected DVD at all, whether
|
||||||
|
/// or not any given sector turns out to be scrambled. Lives in the `css` module
|
||||||
|
/// beside the CSS-scheme primitives it drives.
|
||||||
|
pub struct DvdUnlocker;
|
||||||
|
|
||||||
impl CssUnlocker {
|
impl DvdUnlocker {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
CssUnlocker
|
DvdUnlocker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CssUnlocker {
|
impl Default for DvdUnlocker {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::Unlocker for CssUnlocker {
|
impl crate::Unlocker for DvdUnlocker {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"CSS"
|
// User-facing unlocker label. This unlocker's job is the DVD
|
||||||
|
// read-enablement bus-auth (it clears the drive's scrambled-read
|
||||||
|
// barrier and learns no key) — a property of the DVD medium, NOT of
|
||||||
|
// whether the content happens to be CSS-scrambled. Reporting it as
|
||||||
|
// "DVD" is honest: on any DVD the bus-auth ran; the CSS descramble
|
||||||
|
// itself is keyless and handled downstream, so it is not a separate
|
||||||
|
// "did an unlocker run" signal.
|
||||||
|
"DVD"
|
||||||
}
|
}
|
||||||
|
|
||||||
/// CSS removes the scrambled-sector barrier (a bus-level concern); it
|
/// CSS removes the scrambled-sector barrier (a bus-level concern); it
|
||||||
@@ -179,8 +190,8 @@ impl crate::Unlocker for CssUnlocker {
|
|||||||
if !mounted_disc_is_dvd(scsi) {
|
if !mounted_disc_is_dvd(scsi) {
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
target: "freemkv::css",
|
target: "freemkv::css",
|
||||||
phase = "css_unlocker_not_dvd",
|
phase = "dvd_unlocker_not_dvd",
|
||||||
"CssUnlocker invoked on a non-DVD profile; refusing (NotApplicable)"
|
"DvdUnlocker invoked on a non-DVD profile; refusing (NotApplicable)"
|
||||||
);
|
);
|
||||||
return Err(crate::UnlockError::NotApplicable);
|
return Err(crate::UnlockError::NotApplicable);
|
||||||
}
|
}
|
||||||
@@ -193,7 +204,7 @@ impl crate::Unlocker for CssUnlocker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Transport-level "is the mounted disc a DVD?" probe (GET CONFIGURATION
|
/// Transport-level "is the mounted disc a DVD?" probe (GET CONFIGURATION
|
||||||
/// current-profile, DVD family `0x0010..=0x001F`). Lets the CssUnlocker
|
/// current-profile, DVD family `0x0010..=0x001F`). Lets the DvdUnlocker
|
||||||
/// self-verify against the drive instead of trusting the caller's DiscKind.
|
/// self-verify against the drive instead of trusting the caller's DiscKind.
|
||||||
fn mounted_disc_is_dvd(scsi: &mut dyn ScsiTransport) -> bool {
|
fn mounted_disc_is_dvd(scsi: &mut dyn ScsiTransport) -> bool {
|
||||||
// RT=0: the 8-byte feature header carries the Current Profile in bytes 6-7.
|
// RT=0: the 8-byte feature header carries the Current Profile in bytes 6-7.
|
||||||
@@ -922,9 +933,19 @@ mod tests {
|
|||||||
assert_eq!(cdb[9], 0x04, "low byte of 2052-byte transfer");
|
assert_eq!(cdb[9], 0x04, "low byte of 2052-byte transfer");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// CssUnlocker provides bus removal only — it never provides drive features.
|
/// The unlocker's user-facing name is "DVD" (the medium it read-unlocks),
|
||||||
|
/// not "CSS" (the scheme). Apps render the unlocker report from this name,
|
||||||
|
/// so it is a stable contract — the bus-auth ran on any DVD, encrypted or
|
||||||
|
/// not, and the report must say so rather than conflate it with a CSS crack.
|
||||||
#[test]
|
#[test]
|
||||||
fn css_unlocker_provides_no_features() {
|
fn dvd_unlocker_is_named_dvd() {
|
||||||
|
use crate::Unlocker;
|
||||||
|
assert_eq!(DvdUnlocker::new().name(), "DVD");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// DvdUnlocker provides bus removal only — it never provides drive features.
|
||||||
|
#[test]
|
||||||
|
fn dvd_unlocker_provides_no_features() {
|
||||||
use crate::scsi::{DataDirection, ScsiResult};
|
use crate::scsi::{DataDirection, ScsiResult};
|
||||||
use crate::{DiscKind, DriveId, UnlockCtx, UnlockError, Unlocker};
|
use crate::{DiscKind, DriveId, UnlockCtx, UnlockError, Unlocker};
|
||||||
struct DeadTransport;
|
struct DeadTransport;
|
||||||
@@ -942,16 +963,16 @@ mod tests {
|
|||||||
let id = DriveId::default();
|
let id = DriveId::default();
|
||||||
let mut t = DeadTransport;
|
let mut t = DeadTransport;
|
||||||
let r =
|
let r =
|
||||||
CssUnlocker::new().unlock_features(&mut t, &UnlockCtx::new(&id, DiscKind::Css, &[]));
|
DvdUnlocker::new().unlock_features(&mut t, &UnlockCtx::new(&id, DiscKind::Css, &[]));
|
||||||
assert_eq!(r.unwrap_err(), UnlockError::NotApplicable);
|
assert_eq!(r.unwrap_err(), UnlockError::NotApplicable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defense in depth: even when the caller declares `DiscKind::Css`, the
|
/// Defense in depth: even when the caller declares `DiscKind::Css`, the
|
||||||
/// CssUnlocker self-verifies against the drive's GET CONFIGURATION profile.
|
/// DvdUnlocker self-verifies against the drive's GET CONFIGURATION profile.
|
||||||
/// A drive reporting a Blu-ray profile → `NotApplicable`, and NOT a single
|
/// A drive reporting a Blu-ray profile → `NotApplicable`, and NOT a single
|
||||||
/// CSS CDB is issued (no bus-auth fired at a BD).
|
/// CSS CDB is issued (no bus-auth fired at a BD).
|
||||||
#[test]
|
#[test]
|
||||||
fn css_unlocker_self_guards_against_non_dvd() {
|
fn dvd_unlocker_self_guards_against_non_dvd() {
|
||||||
use crate::scsi::{DataDirection, ScsiResult};
|
use crate::scsi::{DataDirection, ScsiResult};
|
||||||
use crate::{DiscKind, DriveId, UnlockCtx, UnlockError, Unlocker};
|
use crate::{DiscKind, DriveId, UnlockCtx, UnlockError, Unlocker};
|
||||||
|
|
||||||
@@ -994,7 +1015,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut t = BdTransport { non_config_cdbs: 0 };
|
let mut t = BdTransport { non_config_cdbs: 0 };
|
||||||
let r = CssUnlocker::new().unlock_bus(&mut t, &UnlockCtx::new(&id, DiscKind::Css, &[]));
|
let r = DvdUnlocker::new().unlock_bus(&mut t, &UnlockCtx::new(&id, DiscKind::Css, &[]));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
r.unwrap_err(),
|
r.unwrap_err(),
|
||||||
UnlockError::NotApplicable,
|
UnlockError::NotApplicable,
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# ld — the LibreDrive unlocker
|
||||||
|
|
||||||
|
The **LibreDrive** unlocker module for freemkv-unlock.
|
||||||
|
|
||||||
|
freemkv-unlock defines the generic `Unlocker` contract; this module is one
|
||||||
|
implementation of it. It recognizes a bundled catalog of supported drives
|
||||||
|
(`profiles.json`) and, for a matching drive, lifts the drive-level
|
||||||
|
bus-encryption barrier so the drive serves readable sectors. Content-key
|
||||||
|
decryption is a separate concern, handled by the consumer.
|
||||||
|
|
||||||
|
Clients never name this module directly —
|
||||||
|
[libfreemkv](https://github.com/freemkv/libfreemkv) dispatches through
|
||||||
|
`freemkv_unlock::all_unlockers()`, and this module answers `unlock_features()` /
|
||||||
|
`unlock_bus()` when the drive identity is one it supports.
|
||||||
|
|
||||||
|
## Scope: non-persistent unlock only
|
||||||
|
|
||||||
|
This module performs only the **non-persistent** unlock — the access state it
|
||||||
|
sets up lives in drive RAM and is gone on power cycle. The one-time, permanent
|
||||||
|
drive preparation is the drive owner's own manual step and is **never**
|
||||||
|
automated here.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
LibreDrive was created by **Mike Chen** and the **MakeMKV team**. This module
|
||||||
|
builds on their work — our thanks and full credit to them for the LibreDrive
|
||||||
|
capabilities.
|
||||||
+2
-2
@@ -115,7 +115,7 @@ pub enum UnlockError {
|
|||||||
/// here — that is the consumer's concern, not bus removal.
|
/// here — that is the consumer's concern, not bus removal.
|
||||||
pub trait Unlocker: Send + Sync {
|
pub trait Unlocker: Send + Sync {
|
||||||
/// Short, stable identifier for this unlocker (e.g. "LibreDrive", "AACS",
|
/// Short, stable identifier for this unlocker (e.g. "LibreDrive", "AACS",
|
||||||
/// "CSS", "Renesas"). The ONE place a name lives — apps render the unlocker
|
/// "DVD", "Renesas"). The ONE place a name lives — apps render the unlocker
|
||||||
/// report from [`all_unlockers`], never hardcoding names, so adding/removing
|
/// report from [`all_unlockers`], never hardcoding names, so adding/removing
|
||||||
/// an unlocker updates every report with no app change.
|
/// an unlocker updates every report with no app change.
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
@@ -167,6 +167,6 @@ pub fn all_unlockers() -> Vec<Box<dyn Unlocker>> {
|
|||||||
Box::new(ld::LibreDrive::new()),
|
Box::new(ld::LibreDrive::new()),
|
||||||
Box::new(renesis::Renesis::new()),
|
Box::new(renesis::Renesis::new()),
|
||||||
Box::new(aacs::AacsCert::new()),
|
Box::new(aacs::AacsCert::new()),
|
||||||
Box::new(css::CssUnlocker::new()),
|
Box::new(css::DvdUnlocker::new()),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-31
@@ -1,16 +1,10 @@
|
|||||||
//! renesis — the Renesas-platform unlocker (Pioneer + HL-DT-ST Renesas drives).
|
//! renesis — Renesas-platform detection (Pioneer + HL-DT-ST Renesas drives).
|
||||||
//!
|
//!
|
||||||
//! Optical drives split into two controller families: MediaTek (handled by
|
//! Optical drives split into two controller families: MediaTek (handled by
|
||||||
//! [`crate::ld`], per-drive firmware) and Renesas. This module owns the Renesas
|
//! [`crate::ld`]) and Renesas. This module identifies the Renesas side via a
|
||||||
//! side. Detection is a single vendor probe — a Renesas controller serves the
|
//! single vendor identity probe (see [`is_renesas`]) and reports the match so a
|
||||||
//! READ_BUFFER 0x02/0xF1 identity block (ASCII `SAT` interface marker at
|
//! Renesas drive is named honestly. It does not modify drive state; AACS bus
|
||||||
//! `[16..19]`); a MediaTek drive rejects the command with ILLEGAL REQUEST. See
|
//! decryption is handled by the host cert.
|
||||||
//! [`is_renesas`].
|
|
||||||
//!
|
|
||||||
//! renesis provides the drive-FEATURES capability ([`Renesis::unlock_features`])
|
|
||||||
//! and NOT bus removal (the cert handles the bus). The feature unlock is a no-op
|
|
||||||
//! for now — it recognizes the drive and reports the match, deferring the bus to
|
|
||||||
//! the cert stage.
|
|
||||||
|
|
||||||
use crate::scsi::{DataDirection, ScsiTransport};
|
use crate::scsi::{DataDirection, ScsiTransport};
|
||||||
use crate::{UnlockCtx, UnlockError, Unlocked, Unlocker};
|
use crate::{UnlockCtx, UnlockError, Unlocked, Unlocker};
|
||||||
@@ -22,17 +16,6 @@ const RB_F1_LEN: usize = 48;
|
|||||||
const RENESAS_MARKER: &[u8] = b"SAT";
|
const RENESAS_MARKER: &[u8] = b"SAT";
|
||||||
const RENESAS_MARKER_OFFSET: usize = 16;
|
const RENESAS_MARKER_OFFSET: usize = 16;
|
||||||
|
|
||||||
/// Renesas feature-unlock command (RS8xxx+ platforms). A single fixed vendor
|
|
||||||
/// WRITE BUFFER (opcode `0x3B`, mode `0x02`, buffer id `0x41`): issuing it
|
|
||||||
/// authenticates the host and enables the drive's extended feature set.
|
|
||||||
///
|
|
||||||
/// Platform-invariant — the same command unlocks every supported Renesas
|
|
||||||
/// firmware; it does not vary per drive or per firmware revision. Sent by
|
|
||||||
/// [`Renesis::unlock_features`]. (Verify on hardware before relying on it.)
|
|
||||||
#[allow(dead_code)]
|
|
||||||
const RENESAS_CHALLENGE_CDB: [u8; 10] =
|
|
||||||
[0x3B, 0x02, 0x41, 0xA5, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00];
|
|
||||||
|
|
||||||
/// True if `scsi` is a Renesas-platform drive (Pioneer or HL-DT-ST Renesas).
|
/// True if `scsi` is a Renesas-platform drive (Pioneer or HL-DT-ST Renesas).
|
||||||
///
|
///
|
||||||
/// Issues the vendor READ_BUFFER 0x02/0xF1 probe: a Renesas controller serves a
|
/// Issues the vendor READ_BUFFER 0x02/0xF1 probe: a Renesas controller serves a
|
||||||
@@ -68,12 +51,10 @@ impl Unlocker for Renesis {
|
|||||||
"Renesas"
|
"Renesas"
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `if is_renesas() { recognized }`. Renesas is a distinct platform from
|
/// Report whether the drive is a Renesas platform. On a match, returns `Ok`
|
||||||
/// LibreDrive (MediaTek): it provides DRIVE FEATURES only — it does NOT remove
|
/// with `drive_unlocked: false` — the drive is recognized but its state is
|
||||||
/// AACS bus encryption (`unlock_bus` is left at the default, so the cert stage
|
/// not modified here (AACS bus decryption is handled by the host cert). A
|
||||||
/// handles the bus). The feature unlock itself is not implemented yet (no-op),
|
/// non-Renesas drive → `NotApplicable`.
|
||||||
/// but the match IS reported (`Ok`, `drive_unlocked: false`) so the drive is
|
|
||||||
/// recognized as Renesas. A non-Renesas drive → `NotApplicable`.
|
|
||||||
fn unlock_features(
|
fn unlock_features(
|
||||||
&self,
|
&self,
|
||||||
scsi: &mut dyn ScsiTransport,
|
scsi: &mut dyn ScsiTransport,
|
||||||
@@ -82,12 +63,10 @@ impl Unlocker for Renesis {
|
|||||||
if !is_renesas(scsi) {
|
if !is_renesas(scsi) {
|
||||||
return Err(UnlockError::NotApplicable);
|
return Err(UnlockError::NotApplicable);
|
||||||
}
|
}
|
||||||
// Recognized Renesas drive (Pioneer / HL-DT-ST Renesas). Feature unlock:
|
|
||||||
// TODO. `drive_unlocked: false` → bus encryption is left for the cert.
|
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
target: "freemkv::disc",
|
target: "freemkv::disc",
|
||||||
phase = "renesas_recognized",
|
phase = "renesas_recognized",
|
||||||
"Renesas drive recognized; feature unlock TODO, bus deferred to cert"
|
"Renesas drive recognized; bus handled by cert"
|
||||||
);
|
);
|
||||||
Ok(Unlocked {
|
Ok(Unlocked {
|
||||||
vid: None,
|
vid: None,
|
||||||
|
|||||||
Reference in New Issue
Block a user