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:
+1
-3
@@ -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
@@ -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
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user