Clean pipeline: one open, one init, no double-init

- Removed open_unlocked() — open() is the only entry
- Removed redundant init() call from open_title()
- init() called once in open(), handles everything
- Each function does one thing: open→init→scan→read
This commit is contained in:
MattJackson
2026-04-08 21:35:48 -07:00
parent ecc6cd9f6b
commit 0b19154bd3
3 changed files with 20 additions and 27 deletions
+1 -3
View File
@@ -798,9 +798,7 @@ impl Disc {
detail: format!("title index {} out of range (have {})", title_idx, self.titles.len()), detail: format!("title index {} out of range (have {})", title_idx, self.titles.len()),
})?; })?;
if !session.is_unlocked() { // init() already called by DriveSession::open(). No re-init needed.
let _ = session.init();
}
let speed_cdb = crate::scsi::build_set_cd_speed(0xFFFF); let speed_cdb = crate::scsi::build_set_cd_speed(0xFFFF);
let mut dummy = [0u8; 0]; let mut dummy = [0u8; 0];
+4 -14
View File
@@ -30,10 +30,11 @@ pub struct DriveSession {
} }
impl DriveSession { impl DriveSession {
/// Open a drive — identify, wait for disc, and unlock for raw reads.
/// ///
/// This is the standard entry point. After `open()`, the drive is /// This is the only entry point. After `open()`, the drive is
/// ready for scanning and content reads. /// ready for scanning and content reads. init() handles everything:
/// unlock, firmware upload if needed, calibration, registers.
/// Called once per session. Non-fatal if init fails (BD works without it).
pub fn open(device: &Path) -> Result<Self> { pub fn open(device: &Path) -> Result<Self> {
let mut session = Self::open_no_unlock(device)?; let mut session = Self::open_no_unlock(device)?;
session.wait_ready()?; session.wait_ready()?;
@@ -41,17 +42,6 @@ impl DriveSession {
Ok(session) Ok(session)
} }
/// Open a drive and immediately init for raw reads.
///
/// Use this when you need raw disc access without AACS (e.g. capture,
/// sector dumps). Skips AACS authentication — cannot be done after init.
pub fn open_unlocked(device: &Path) -> Result<Self> {
let mut session = Self::open_no_unlock(device)?;
session.wait_ready()?;
let _ = session.init();
Ok(session)
}
/// Open a drive — identify only, no wait, no unlock. /// Open a drive — identify only, no wait, no unlock.
/// ///
/// Low-level entry point. Caller is responsible for wait_ready() /// Low-level entry point. Caller is responsible for wait_ready()
+15 -10
View File
@@ -463,11 +463,21 @@ impl Platform for Mt1959 {
/// Phase 5: cmd 9 × 6 retries (status) /// Phase 5: cmd 9 × 6 retries (status)
fn init(&mut self, scsi: &mut dyn ScsiTransport) -> Result<()> { fn init(&mut self, scsi: &mut dyn ScsiTransport) -> Result<()> {
// Phase 1: Unlock + firmware upload (6 retries) // Phase 1: Unlock + firmware upload (6 retries)
//
// Three unlock outcomes:
// Ok → warm drive, firmware loaded, skip to calibrate
// Err(other) → cold drive or SCSI error, try load_firmware
let mut unlocked = false; let mut unlocked = false;
for _attempt in 0..6 { for _attempt in 0..6 {
match self.unlock(scsi) { match self.unlock(scsi) {
Ok(_) => { unlocked = true; break; } Ok(_) => { unlocked = true; break; }
Err(Error::SignatureMismatch { .. }) => {
return Err(Error::UnlockFailed {
detail: "signature mismatch — wrong profile for this drive".into(),
});
}
Err(_) => { Err(_) => {
// Cold boot or SCSI error — try uploading firmware
if self.load_firmware(scsi).is_ok() { if self.load_firmware(scsi).is_ok() {
unlocked = true; unlocked = true;
break; break;
@@ -493,17 +503,12 @@ impl Platform for Mt1959 {
return Err(Error::ScsiError { opcode: 0x3C, status: 0xFF, sense_key: 0 }); return Err(Error::ScsiError { opcode: 0x3C, status: 0xFF, sense_key: 0 });
} }
// If fails: cmd 5 fallback (keepalive) // Phase 3: Read registers — non-fatal
// In our context: this fetches a display string, not critical for reads // x86 retries 5×, but we do a single attempt each. Not required for reads.
let _ = self.probe(scsi, 0x00, 0, 0x3FF); let _ = self.read_register_a(scsi);
let _ = self.read_register_b(scsi);
for _attempt in 0..5 { // Phase 4: Status — non-fatal, single attempt
let a_ok = self.read_register_a(scsi).is_ok();
let b_ok = self.read_register_b(scsi).is_ok();
if a_ok && b_ok { break; }
}
// Phase 5: Status — non-fatal, single attempt
// Some drives reject sub_cmd 0x13. Not required for reads. // Some drives reject sub_cmd 0x13. Not required for reads.
let _ = self.status(scsi); let _ = self.status(scsi);