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
This commit is contained in:
MattJackson
2026-04-06 11:21:27 -07:00
parent afb43c69b3
commit c26b6f6819
7 changed files with 914 additions and 520 deletions
+824 -412
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -100,7 +100,7 @@ fn print_human(
println!(); println!();
match matched { match matched {
Some(p) => { Some(p) => {
println!("Profile: FOUND ({})", p.platform.name()); println!("Profile: FOUND ({})", p.chipset.name());
println!("Raw Read: Supported"); println!("Raw Read: Supported");
} }
None => { None => {
+1 -1
View File
@@ -34,7 +34,7 @@ fn main() {
}; };
println!(" Drive ID: {}", session.profile.drive_id); println!(" Drive ID: {}", session.profile.drive_id);
println!(" Platform: {}", session.profile.platform.name()); println!(" Chipset: {}", session.profile.chipset.name());
println!(); println!();
// Enable raw read mode // Enable raw read mode
+9 -17
View File
@@ -8,7 +8,7 @@ use std::path::Path;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::scsi::{SgIoTransport, ScsiTransport}; use crate::scsi::{SgIoTransport, ScsiTransport};
use crate::identity::DriveId; use crate::identity::DriveId;
use crate::profile::{self, DriveProfile, PlatformType}; use crate::profile::{self, DriveProfile, Chipset};
use crate::platform::{Platform, DriveStatus}; use crate::platform::{Platform, DriveStatus};
use crate::platform::mt1959::Mt1959; use crate::platform::mt1959::Mt1959;
@@ -42,23 +42,15 @@ impl DriveSession {
product_revision: drive_id.product_revision.trim().to_string(), product_revision: drive_id.product_revision.trim().to_string(),
})?; })?;
if !profile.supported { let platform: Box<dyn Platform> = match profile.chipset {
return Err(Error::UnsupportedDrive { Chipset::MediaTek => {
vendor_id: drive_id.vendor_id.trim().to_string(),
product_id: drive_id.product_id.trim().to_string(),
product_revision: drive_id.product_revision.trim().to_string(),
});
}
let platform: Box<dyn Platform> = match profile.platform {
PlatformType::Mt1959A | PlatformType::Mt1959B => {
Box::new(Mt1959::new(profile.clone())) Box::new(Mt1959::new(profile.clone()))
} }
PlatformType::Pioneer => { Chipset::Renesas => {
return Err(Error::UnsupportedDrive { return Err(Error::UnsupportedDrive {
vendor_id: drive_id.vendor_id.trim().to_string(), vendor_id: drive_id.vendor_id.trim().to_string(),
product_id: drive_id.product_id.trim().to_string(), product_id: drive_id.product_id.trim().to_string(),
product_revision: "Pioneer not yet implemented".to_string(), product_revision: "Renesas not yet implemented".to_string(),
}); });
} }
}; };
@@ -76,15 +68,15 @@ impl DriveSession {
let mut transport = SgIoTransport::open(device)?; let mut transport = SgIoTransport::open(device)?;
let drive_id = DriveId::from_drive(&mut transport)?; let drive_id = DriveId::from_drive(&mut transport)?;
let platform: Box<dyn Platform> = match profile.platform { let platform: Box<dyn Platform> = match profile.chipset {
PlatformType::Mt1959A | PlatformType::Mt1959B => { Chipset::MediaTek => {
Box::new(Mt1959::new(profile.clone())) Box::new(Mt1959::new(profile.clone()))
} }
PlatformType::Pioneer => { Chipset::Renesas => {
return Err(Error::UnsupportedDrive { return Err(Error::UnsupportedDrive {
vendor_id: drive_id.vendor_id.trim().to_string(), vendor_id: drive_id.vendor_id.trim().to_string(),
product_id: drive_id.product_id.trim().to_string(), product_id: drive_id.product_id.trim().to_string(),
product_revision: "Pioneer not yet implemented".to_string(), product_revision: "Renesas not yet implemented".to_string(),
}); });
} }
}; };
+2 -3
View File
@@ -25,10 +25,9 @@
//! //!
//! let mut session = DriveSession::open( //! let mut session = DriveSession::open(
//! Path::new("/dev/sr0"), //! Path::new("/dev/sr0"),
//! Path::new("profiles/"),
//! ).unwrap(); //! ).unwrap();
//! //!
//! session.enable().unwrap(); //! session.unlock().unwrap();
//! session.calibrate().unwrap(); //! session.calibrate().unwrap();
//! //!
//! let mut buf = vec![0u8; 2048]; //! let mut buf = vec![0u8; 2048];
@@ -46,7 +45,7 @@ pub mod speed;
pub use error::{Error, Result}; pub use error::{Error, Result};
pub use drive::DriveSession; pub use drive::DriveSession;
pub use identity::DriveId; pub use identity::DriveId;
pub use profile::{DriveProfile, PlatformType}; pub use profile::{DriveProfile, Chipset};
pub use platform::{Platform, DriveStatus}; pub use platform::{Platform, DriveStatus};
pub use scsi::ScsiTransport; pub use scsi::ScsiTransport;
pub use speed::DriveSpeed; pub use speed::DriveSpeed;
+2 -2
View File
@@ -25,8 +25,8 @@ pub struct Mt1959 {
impl Mt1959 { impl Mt1959 {
pub fn new(profile: DriveProfile) -> Self { pub fn new(profile: DriveProfile) -> Self {
let mode = profile.platform.mode(); let mode = profile.unlock_mode;
let buffer_id = profile.platform.buffer_id(); let buffer_id = profile.unlock_buf_id;
Mt1959 { Mt1959 {
profile, profile,
mode, mode,
+74 -83
View File
@@ -30,17 +30,18 @@ pub struct DriveProfile {
#[serde(default)] #[serde(default)]
pub firmware_date: String, pub firmware_date: String,
/// Chipset platform type determining the READ BUFFER variant. /// Chipset manufacturer determining unlock/read command structure.
#[serde(default)] #[serde(default)]
pub platform: PlatformType, pub chipset: Chipset,
/// Whether this drive supports raw disc access mode. /// READ BUFFER mode byte for unlock CDB (e.g. 0x01 for MT1959-A, 0x02 for MT1959-B).
#[serde(default)] #[serde(default = "default_unlock_mode")]
pub supported: bool, pub unlock_mode: u8,
/// READ BUFFER buffer ID for unlock CDB (e.g. 0x44 for MT1959-A, 0x77 for MT1959-B).
#[serde(default = "default_unlock_buf_id")]
pub unlock_buf_id: u8,
/// Current readiness status of this drive.
#[serde(default)]
pub status: ReadinessStatus,
/// Drive identifier string from the profile database. /// Drive identifier string from the profile database.
#[serde(default)] #[serde(default)]
@@ -87,70 +88,39 @@ fn default_verify() -> [u8; 4] {
*b"MMkv" *b"MMkv"
} }
/// Chipset platform type. Determines the READ BUFFER mode and buffer ID. fn default_unlock_mode() -> u8 {
0x01
}
fn default_unlock_buf_id() -> u8 {
0x44
}
/// Drive chipset — determines CDB structure for unlock and raw read commands.
#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Deserialize)]
pub enum PlatformType { pub enum Chipset {
/// MediaTek MT1959 variant A: mode=0x01, buffer_id=0x44. /// MediaTek MT1959 — LG, ASUS, hp drives.
#[serde(rename = "mt1959_a")] /// CDB: READ_BUFFER with mode and buf_id from profile.
Mt1959A, #[serde(rename = "mediatek")]
/// MediaTek MT1959 variant B: mode=0x02, buffer_id=0x77. MediaTek,
#[serde(rename = "mt1959_b")] /// Renesas RS8xxx/RS9xxx — Pioneer, some HL-DT-ST drives.
Mt1959B, /// Not yet implemented.
/// Pioneer chipset (not yet implemented). #[serde(rename = "renesas")]
#[serde(rename = "pioneer")] Renesas,
Pioneer,
} }
impl Default for PlatformType { impl Default for Chipset {
fn default() -> Self { fn default() -> Self {
PlatformType::Mt1959A Chipset::MediaTek
} }
} }
/// Readiness status of a drive for raw disc access. impl Chipset {
#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] /// Human-readable name for this chipset.
pub enum ReadinessStatus {
/// Drive is ready — raw disc access can be enabled.
Ready,
/// Drive firmware needs an update before raw access is possible.
NeedsFirmwareUpdate,
/// Drive uses encrypted commands (not yet supported).
Encrypted,
/// Status unknown.
Unknown,
}
impl Default for ReadinessStatus {
fn default() -> Self {
ReadinessStatus::Unknown
}
}
impl PlatformType {
/// Human-readable name for this platform.
pub fn name(&self) -> &'static str { pub fn name(&self) -> &'static str {
match self { match self {
PlatformType::Mt1959A => "MT1959-A", Chipset::MediaTek => "MediaTek MT1959",
PlatformType::Mt1959B => "MT1959-B", Chipset::Renesas => "Renesas",
PlatformType::Pioneer => "Pioneer",
}
}
/// READ BUFFER mode byte for this chipset platform.
pub fn mode(&self) -> u8 {
match self {
PlatformType::Mt1959A => 0x01,
PlatformType::Mt1959B => 0x02,
PlatformType::Pioneer => 0x01, // TBD
}
}
/// READ BUFFER buffer ID for this chipset platform.
pub fn buffer_id(&self) -> u8 {
match self {
PlatformType::Mt1959A => 0x44,
PlatformType::Mt1959B => 0x77,
PlatformType::Pioneer => 0x44, // TBD
} }
} }
} }
@@ -206,28 +176,19 @@ pub fn load_from_json(json: &serde_json::Value) -> Result<DriveProfile> {
let revision = json["product_revision"].as_str().unwrap_or("").to_string(); let revision = json["product_revision"].as_str().unwrap_or("").to_string();
let firmware_type = json["vendor_specific"].as_str().unwrap_or("").to_string(); let firmware_type = json["vendor_specific"].as_str().unwrap_or("").to_string();
let firmware_date = json["firmware_date"].as_str().unwrap_or("").to_string(); let firmware_date = json["firmware_date"].as_str().unwrap_or("").to_string();
let program = json["program"].as_str().unwrap_or("unknown"); let chipset_str = json["chipset"].as_str().unwrap_or("unknown");
let platform = match program { let chipset = match chipset_str {
"mt1959_a" => PlatformType::Mt1959A, "mediatek" => Chipset::MediaTek,
"mt1959_b" => PlatformType::Mt1959B, "renesas" => Chipset::Renesas,
_ => PlatformType::Mt1959A, // default _ => Chipset::MediaTek,
}; };
let unlock_mode = json["unlock_mode"].as_u64().map(|v| v as u8).unwrap_or(0x01);
let unlock_buf_id = json["unlock_buf_id"].as_u64().map(|v| v as u8).unwrap_or(0x44);
let sig_str = json["signature"].as_str().unwrap_or(""); let sig_str = json["signature"].as_str().unwrap_or("");
// Drive is supported if it has a known program and valid signature
let has_program = matches!(program, "mt1959_a" | "mt1959_b");
let has_signature = sig_str.len() == 8;
let supported = has_program && has_signature;
let status = if supported {
ReadinessStatus::Ready
} else if json["status"].as_str() == Some("needs_flash") || program == "none" {
ReadinessStatus::NeedsFirmwareUpdate
} else {
ReadinessStatus::Unknown
};
let signature = if sig_str.len() == 8 { let signature = if sig_str.len() == 8 {
parse_hex4(sig_str)? parse_hex4(sig_str)?
} else { } else {
@@ -260,9 +221,9 @@ pub fn load_from_json(json: &serde_json::Value) -> Result<DriveProfile> {
product_revision: revision, product_revision: revision,
vendor_specific: firmware_type, vendor_specific: firmware_type,
firmware_date, firmware_date,
platform, chipset,
supported, unlock_mode,
status, unlock_buf_id,
drive_id: json["drive_id"].as_str().unwrap_or("").to_string(), drive_id: json["drive_id"].as_str().unwrap_or("").to_string(),
drive_version: json["drive_version"].as_str().unwrap_or("").to_string(), drive_version: json["drive_version"].as_str().unwrap_or("").to_string(),
signature, signature,
@@ -335,3 +296,33 @@ pub fn find_by_drive_id<'a>(
&& p.vendor_specific.trim() == vs && p.vendor_specific.trim() == vs
})) }))
} }
#[cfg(test)]
mod tests {
use super::*;
use crate::identity::DriveId;
fn make_drive_id(vendor: &str, rev: &str, vs: &str, date: &str) -> DriveId {
let mut inquiry = vec![0u8; 96];
inquiry[8..8+vendor.len().min(8)].copy_from_slice(&vendor.as_bytes()[..vendor.len().min(8)]);
inquiry[32..32+rev.len().min(4)].copy_from_slice(&rev.as_bytes()[..rev.len().min(4)]);
inquiry[36..36+vs.len().min(7)].copy_from_slice(&vs.as_bytes()[..vs.len().min(7)]);
DriveId::from_inquiry(&inquiry, date)
}
#[test]
fn test_find_known_drive() {
let profiles = load_bundled().unwrap();
let id = make_drive_id("HL-DT-ST", "1.03", "NM00000", "211810241934");
let p = find_by_drive_id(&profiles, &id).unwrap();
assert_eq!(p.vendor_id.trim(), "HL-DT-ST");
assert_eq!(p.vendor_specific.trim(), "NM00000");
}
#[test]
fn test_find_unknown_drive() {
let profiles = load_bundled().unwrap();
let id = make_drive_id("FAKE-VND", "9.99", "XX12345", "");
assert!(find_by_drive_id(&profiles, &id).is_none());
}
}