pub struct Cd { /* private fields */ }Expand description
The CD-ROM controller and DMA channel 3.
Implementations§
Source§impl Cd
impl Cd
Sourcepub fn command(
&mut self,
command: u8,
params: &[u8],
) -> Result<Response, CdError>
pub fn command( &mut self, command: u8, params: &[u8], ) -> Result<Response, CdError>
Send a command and return its first response packet, waiting at most
DEFAULT_COMMAND_SPINS polls for each step.
Returns CdError::Timeout when the controller never answers and
CdError::DriveError when the drive reports an error. A timed-out
command leaves CD-ROM IRQ output masked, as Self::try_command does.
Sourcepub fn command_within(
&mut self,
command: u8,
params: &[u8],
spin_limit: u32,
) -> Result<Response, CdError>
pub fn command_within( &mut self, command: u8, params: &[u8], spin_limit: u32, ) -> Result<Response, CdError>
Self::command with an explicit poll budget per step.
Sourcepub fn try_command(
&mut self,
command: u8,
params: &[u8],
spin_limit: u32,
) -> Option<Response>
pub fn try_command( &mut self, command: u8, params: &[u8], spin_limit: u32, ) -> Option<Response>
Try to send a command and capture its first response packet.
Returns None if the controller does not expose parameter room or
a response within spin_limit polls, or if the drive reports an error
(Self::command_within tells the two apart). Use this for gameplay paths
where a not-ready drive should not stall rendering forever. If a
dispatched command times out, CD-ROM IRQ output remains masked so a
late ACK cannot interrupt a polling caller.
Sourcepub fn irq_flag_value(&mut self) -> u8
pub fn irq_flag_value(&mut self) -> u8
Current CD-ROM IRQ flag value (0 = none, 1 = data ready, 2 = complete, 3 = ack, 5 = error).
Exposed so callers can build their own wait loops bounded by a hardware timer rather than by a poll count. A poll budget is only a proxy for time and drifts with CPU and bus speed, which matters when the thing being measured is mechanical.
Sourcepub fn acknowledge_irq(&mut self, bits: u8)
pub fn acknowledge_irq(&mut self, bits: u8)
Acknowledge the given CD-ROM IRQ bits.
Sourcepub fn discard_response(&mut self)
pub fn discard_response(&mut self)
Drain any pending response bytes, discarding them.
Sourcepub fn dispatch_command(
&mut self,
command: u8,
params: &[u8],
spin_limit: u32,
) -> Option<u8>
pub fn dispatch_command( &mut self, command: u8, params: &[u8], spin_limit: u32, ) -> Option<u8>
Send a command without waiting for any response. Pairs with
Self::irq_flag_value for caller-timed waits.
Returns the CD-ROM IRQ enable to give back to
restore_irq_output, or None if the
parameter FIFO never made room. Leaves CD-ROM IRQ
output masked exactly as the polled helpers do, so a late ACK cannot
interrupt the caller mid-measurement; call Self::restore_irq_output when done.
Sourcepub fn restore_irq_output(&mut self, saved: u8)
pub fn restore_irq_output(&mut self, saved: u8)
Restore the CD-ROM IRQ enable saved by Self::dispatch_command.
Sourcepub fn poll_data_sector(&mut self) -> Result<bool, SectorPollError>
pub fn poll_data_sector(&mut self) -> Result<bool, SectorPollError>
Nonblocking readiness probe for a sector reader that owns the INT1 ACK. Data-ready is never acknowledged here. Other completion responses are drained (at most 256 bytes) and acknowledged; drive errors also reset the parameter FIFO. A ready data FIFO is accepted if no classified IRQ remains.
Sourcepub fn try_wait_data_sector(&mut self, spin_limit: u32) -> bool
pub fn try_wait_data_sector(&mut self, spin_limit: u32) -> bool
Wait for the next streamed data sector (INT1) and acknowledge it.
Use between Self::try_start_reading and Self::try_pause_until_complete to step through
a sector stream. Unrelated pending IRQs are drained and acknowledged so a
stale response cannot be mistaken for a sector arrival. Returns false on
a drive error or if no sector arrives within spin_limit polls.
Sourcepub fn try_status(&mut self, spin_limit: u32) -> Option<Response>
pub fn try_status(&mut self, spin_limit: u32) -> Option<Response>
Try to get the CD-ROM drive status byte.
Sourcepub fn set_mode(&mut self, mode: u8) -> Result<Response, CdError>
pub fn set_mode(&mut self, mode: u8) -> Result<Response, CdError>
Set the CD-ROM controller mode byte.
Sourcepub fn try_set_mode(&mut self, mode: u8, spin_limit: u32) -> Option<Response>
pub fn try_set_mode(&mut self, mode: u8, spin_limit: u32) -> Option<Response>
Try to set the CD-ROM controller mode byte.
Sourcepub fn try_set_target_lba(
&mut self,
lba: u32,
spin_limit: u32,
) -> Option<Response>
pub fn try_set_target_lba( &mut self, lba: u32, spin_limit: u32, ) -> Option<Response>
Seek to a logical data-sector LBA (the command receives absolute BCD MSF).
Sourcepub fn try_start_reading(&mut self, spin_limit: u32) -> Option<Response>
pub fn try_start_reading(&mut self, spin_limit: u32) -> Option<Response>
Begin a normal data-sector stream at the most recently selected location.
Sourcepub fn unmute(&mut self) -> Result<Response, CdError>
pub fn unmute(&mut self) -> Result<Response, CdError>
Route CD-DA/XA output out of the CD-ROM controller.
Sourcepub fn try_unmute(&mut self, spin_limit: u32) -> Option<Response>
pub fn try_unmute(&mut self, spin_limit: u32) -> Option<Response>
Try to route CD-DA/XA output out of the CD-ROM controller.
Sourcepub fn mute(&mut self) -> Result<Response, CdError>
pub fn mute(&mut self) -> Result<Response, CdError>
Mute CD-DA/XA output at the CD-ROM controller.
Sourcepub fn try_mute(&mut self, spin_limit: u32) -> Option<Response>
pub fn try_mute(&mut self, spin_limit: u32) -> Option<Response>
Try to mute CD-DA/XA output at the CD-ROM controller.
Sourcepub fn play_track(&mut self, track: u8) -> Result<Response, CdError>
pub fn play_track(&mut self, track: u8) -> Result<Response, CdError>
Start CD-DA playback at a 1-based track number.
The number is relative to this program’s own tracks; on a multi-program
disc crate::disc_base shifts it past whatever came before.
Sourcepub fn try_play_track(&mut self, track: u8, spin_limit: u32) -> Option<Response>
pub fn try_play_track(&mut self, track: u8, spin_limit: u32) -> Option<Response>
Try to start CD-DA playback at a 1-based track number. Shifted like
Self::play_track.
Sourcepub fn try_pause(&mut self, spin_limit: u32) -> Option<Response>
pub fn try_pause(&mut self, spin_limit: u32) -> Option<Response>
Try to pause CD-DA/read playback.
Sourcepub fn try_pause_until_complete(&mut self, spin_limit: u32) -> bool
pub fn try_pause_until_complete(&mut self, spin_limit: u32) -> bool
Try to pause CD-DA/read playback and wait for the completion IRQ.
Unlike Self::try_stop, this leaves the drive spun up, which makes it the
right handoff before gameplay code starts issuing data-read commands.
Sourcepub fn try_stop(&mut self, spin_limit: u32) -> Option<Response>
pub fn try_stop(&mut self, spin_limit: u32) -> Option<Response>
Try to stop the CD-ROM motor/playback.
This returns when the command is ACCEPTED, not when the drive is
done. On real hardware the motor then winds down for one to two
seconds, during which GetStat reports no activity bits and data-read
commands fail; an emulator answers instantly and hides the window
(proven by a demo-disc burn whose every chain-load died this way). If
data reads follow, either call Self::stop_and_settle, or better, keep the
drive spun up with Self::try_pause_until_complete.
Sourcepub fn stop_and_settle(&mut self, spin_limit: u32, max_polls: u32) -> bool
pub fn stop_and_settle(&mut self, spin_limit: u32, max_polls: u32) -> bool
Stop playback and wait until the drive has genuinely gone quiet:
GetStat reporting neither playing nor seeking on two consecutive polls,
with a short pause between polls. Bounded by max_polls so a wedged
drive cannot hang the caller; returns whether the drive settled.
This is the safe prelude to issuing data-read commands after CD-DA.
Self::try_pause_until_complete is the faster choice when the next reads
are imminent, since it keeps the motor spinning.
Sourcepub fn play_position(&mut self) -> Result<Response, CdError>
pub fn play_position(&mut self) -> Result<Response, CdError>
Get the current physical play position (CdlGetlocP). The 8-byte reply is
[Track(bcd), Index(raw), RMM, RSS, RSECT, AMM, ASS, ASECT]; parse it with
PlayPosition::parse.
Sourcepub fn try_play_position(&mut self, spin_limit: u32) -> Option<Response>
pub fn try_play_position(&mut self, spin_limit: u32) -> Option<Response>
Try to get the current physical play position, giving up after spin_limit.
Sourcepub fn try_command_until_complete(
&mut self,
command: u8,
params: &[u8],
spin_limit: u32,
) -> bool
pub fn try_command_until_complete( &mut self, command: u8, params: &[u8], spin_limit: u32, ) -> bool
Send a command and wait for its SECOND response (the completion IRQ), not just the initial acknowledgement.
Seek, read and init all acknowledge immediately and finish much later, so
timing them against the ack measures command dispatch rather than the
mechanical operation. Returns false if either response fails to arrive
within spin_limit polls.
Sourcepub fn set_audio_mixer(
&mut self,
left_to_left: u8,
left_to_right: u8,
right_to_right: u8,
right_to_left: u8,
)
pub fn set_audio_mixer( &mut self, left_to_left: u8, left_to_right: u8, right_to_right: u8, right_to_left: u8, )
Program the drive’s audio mixer (CD-DA and XA-ADPCM on their way to
the SPU’s CD input) and apply it. Volumes are 0..=0xFF with 0x80 as
unity; (0x80, 0, 0x80, 0) is plain stereo. The SPU side still needs
its CD input enabled and a CD volume (psx-spu).
Source§impl Cd
Register-level steps, for a driver that sequences commands itself, such as
the polled reader::SectorReader.
impl Cd
Register-level steps, for a driver that sequences commands itself, such as
the polled reader::SectorReader.
Each is one controller access or a short fixed run of them, and each leaves register index 0 selected, so the byte steps that follow need not select it again.
Sourcepub fn acknowledge_all_and_reset_parameters(&mut self)
pub fn acknowledge_all_and_reset_parameters(&mut self)
Acknowledge every controller IRQ (writing 0x5F, which also resets
the parameter FIFO) and the CD-ROM bit of I_STAT.
Sourcepub fn irq_enable_mask(&mut self) -> u8
pub fn irq_enable_mask(&mut self) -> u8
The controller’s IRQ enable bits.
Sourcepub fn set_irq_enable_mask(&mut self, mask: u8)
pub fn set_irq_enable_mask(&mut self, mask: u8)
Set the controller’s IRQ enable bits (five are defined).
Sourcepub fn drain_response_limited(&mut self, limit: u32)
pub fn drain_response_limited(&mut self, limit: u32)
Pop and discard up to limit response bytes. The FIFO is 16 bytes
deep; the bound is for a controller wedged “not empty”.
Sourcepub fn is_data_fifo_ready(&mut self) -> bool
pub fn is_data_fifo_ready(&mut self) -> bool
Whether the data FIFO holds sector bytes to pop.
Sourcepub fn wait_parameter_room(&mut self, spins: u32) -> bool
pub fn wait_parameter_room(&mut self, spins: u32) -> bool
Wait for the parameter FIFO to have room, for at most spins more
status reads. false on timeout.
Sourcepub fn reset_parameter_fifo(&mut self)
pub fn reset_parameter_fifo(&mut self)
Empty the parameter FIFO.
Sourcepub fn send_parameter_byte(&mut self, byte: u8)
pub fn send_parameter_byte(&mut self, byte: u8)
Push one parameter byte. Wait for room first.
Sourcepub fn send_command_byte(&mut self, byte: u8)
pub fn send_command_byte(&mut self, byte: u8)
Write the command byte, which starts the command.
Sourcepub fn read_response_byte(&mut self) -> u8
pub fn read_response_byte(&mut self) -> u8
Pop one response byte.
Sourcepub fn status_register(&mut self) -> u8
pub fn status_register(&mut self) -> u8
The status register: FIFO flags and the busy bit.
Sourcepub fn request_data(&mut self)
pub fn request_data(&mut self)
Arm the data FIFO so the drive’s buffered sector can be popped with
read_data_byte once
is_data_fifo_ready says it filled.
Sourcepub fn clear_data_request(&mut self)
pub fn clear_data_request(&mut self)
Drop the data request, which resets the data FIFO.
Sourcepub fn read_data_byte(&mut self) -> u8
pub fn read_data_byte(&mut self) -> u8
Pop one byte of sector data.