aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/psxcd
diff options
context:
space:
mode:
authorspicyjpeg <thatspicyjpeg@gmail.com>2022-11-17 22:20:38 +0100
committerspicyjpeg <thatspicyjpeg@gmail.com>2022-11-17 22:20:38 +0100
commitfc021dc6d6f06f8eff7edc72929faddd1e1f0d1b (patch)
treec088d292c6cc974854c2e7d3a4024c4951ef3602 /libpsn00b/psxcd
parent85d765f30595fe7f27c1b065c5a1934c3d389cef (diff)
downloadpsn00bsdk-fc021dc6d6f06f8eff7edc72929faddd1e1f0d1b.tar.gz
Refactor libpsxcd, add new CD-ROM APIs, fix SPU DMA read
Diffstat (limited to 'libpsn00b/psxcd')
-rw-r--r--libpsn00b/psxcd/_cd_control.s144
-rw-r--r--libpsn00b/psxcd/cdmix.s34
-rw-r--r--libpsn00b/psxcd/cdread.c168
-rw-r--r--libpsn00b/psxcd/common.c435
-rw-r--r--libpsn00b/psxcd/getsector.c51
-rw-r--r--libpsn00b/psxcd/isofs.c72
-rw-r--r--libpsn00b/psxcd/misc.c151
-rw-r--r--libpsn00b/psxcd/psxcd.c371
-rw-r--r--libpsn00b/psxcd/psxcd_asm.s487
-rw-r--r--libpsn00b/psxcd/readme.txt40
10 files changed, 800 insertions, 1153 deletions
diff --git a/libpsn00b/psxcd/_cd_control.s b/libpsn00b/psxcd/_cd_control.s
deleted file mode 100644
index 5fa336a..0000000
--- a/libpsn00b/psxcd/_cd_control.s
+++ /dev/null
@@ -1,144 +0,0 @@
-.set noreorder
-
-.include "hwregs_a.inc"
-
-.section .text
-
-#
-# Issues command and parameter bytes to CD controller directly
-#
-.global _cd_control
-.type _cd_control, @function
-_cd_control:
-
- # a0 - command value
- # a1 - pointer to parameters
- # a2 - length of parameters
-
- addiu $sp, -16
- sw $ra, 0($sp)
- sw $a0, 4($sp)
- sw $a1, 8($sp)
- sw $a2, 12($sp)
-
-# move $a3, $a2 # Debug
-# move $a2, $a1
-# move $a1, $a0
-# la $a0, _cd_control_msg
-# jal printf
-# addiu $sp, -16
-# addiu $sp, 16
-
- lw $a0, 4($sp)
- lw $a1, 8($sp)
- lw $a2, 12($sp)
-
- li $v0, 1 # Set acknowledge wait flag
- la $v1, _cd_ack_wait
- sb $v0, 0($v1)
-
- # Commands that have a 'completion' interrupt (CDIRQ2)
-
- beq $a0, 0x07, .Lset_complete # CdlStandby
- nop
- beq $a0, 0x08, .Lset_complete # CdlStop
- nop
- beq $a0, 0x09, .Lset_complete # CdlPause
- nop
- beq $a0, 0x0A, .Lset_complete # CdlInit
- nop
- beq $a0, 0x12, .Lset_complete # CdlSetsession
- nop
- beq $a0, 0x15, .Lset_complete # CdlSeekL
- nop
- beq $a0, 0x16, .Lset_complete # CdlSeekP
- nop
- beq $a0, 0x1A, .Lset_complete # GetID
- nop
- beq $a0, 0x1D, .Lset_complete # GetQ
- nop
-
- la $v1, _cd_complt_wait # Set wait complete flag
- sb $0 , 0($v1)
-
- b .Lno_complete
- nop
-
-.Lset_complete:
-
- la $v1, _cd_complt_wait # Set wait complete flag
- sb $v0, 0($v1)
-
-.Lno_complete:
-
- bne $a0, 0x0E, .Lnot_mode
- lbu $v0, 0($a1)
- la $v1, _cd_last_mode
- sb $v0, 0($v1)
-
-.Lnot_mode:
-
- la $v1, _cd_last_int # Clear last IRQ value
- sb $0 , 0($v1)
-
- la $v1, _cd_last_cmd # Save command as last command
- sb $a0, 0($v1)
-
- lui $v1, IOBASE
-
-.Lbusy_wait:
- lbu $v0, CD_REG0($v1)
- nop
- andi $v0, 0x80
- bnez $v0, .Lbusy_wait
- nop
-
- li $v0, 1 # Clear parameter FIFO (in case it wasn't cleared)
- sb $v0, CD_REG0($v1)
- li $v0, 0x40
- sb $v0, CD_REG3($v1)
-
-#.Lflush_response: # Flush response FIFO
-# lbu $v0, CD_REG1($v1)
-# nop
-# lbu $v0, CD_REG0($v1)
-# nop
-# andi $v0, 0x20
-# beqz $v0, .Lflush_response
-# nop
-
-.Lcmd_wait: # Wait for CD to become ready for commands
- lbu $v0, CD_REG0($v1)
- nop
- andi $v0, 0x80
- bnez $v0, .Lcmd_wait
- nop
-
- sb $0 , CD_REG0($v1)
-
- beqz $a2, .Lno_params
- nop
-
-.Lfeed_params: # Feed parameters to parameter FIFO
- lbu $v0, 0($a1)
- addi $a2, -1
- sb $v0, CD_REG2($v1)
- bgtz $a2, .Lfeed_params
- addiu $a1, 1
-
-.Lno_params:
-
- sb $0 , CD_REG0($v1) # Feed command value
- sb $a0, CD_REG1($v1)
-
- lw $ra, 0($sp)
- addiu $sp, 16
- jr $ra
- nop
-
-
-#.section .data
-
-#_cd_control_msg:
-# .asciiz "CdControl(%d, %x, %d)\n"
- \ No newline at end of file
diff --git a/libpsn00b/psxcd/cdmix.s b/libpsn00b/psxcd/cdmix.s
deleted file mode 100644
index 40cd181..0000000
--- a/libpsn00b/psxcd/cdmix.s
+++ /dev/null
@@ -1,34 +0,0 @@
-.set noreorder
-
-.include "hwregs_a.inc"
-
-.section .text
-
-
-.global CdMix
-.type CdMix, @function
-CdMix:
-
- lui $a3, IOBASE
-
- lbu $t0, 0($a0)
- lbu $t1, 1($a0)
- lbu $t2, 2($a0)
- lbu $t3, 3($a0)
-
- li $v0, 2
- sb $v0, CD_REG0($a3)
- sb $t0, CD_REG2($a3)
- sb $t1, CD_REG3($a3)
-
- li $v0, 3
- sb $v0, CD_REG0($a3)
- sb $t2, CD_REG1($a3)
- sb $t3, CD_REG2($a3)
-
- li $v0, 0x20
- sb $v0, CD_REG3($a3)
-
- jr $ra
- li $v0, 1
- \ No newline at end of file
diff --git a/libpsn00b/psxcd/cdread.c b/libpsn00b/psxcd/cdread.c
new file mode 100644
index 0000000..d211a01
--- /dev/null
+++ b/libpsn00b/psxcd/cdread.c
@@ -0,0 +1,168 @@
+/*
+ * PSn00bSDK CD-ROM library (high-level reading API)
+ * (C) 2020-2022 Lameguy64, spicyjpeg - MPL licensed
+ *
+ * CdRead() and its related functions are separate from the "main" psxcd code
+ * since handling retries is fairly complicated. In particular the drive
+ * controller will not process any command properly for some time after a
+ * CdlPause command, so an external timer (the vblank counter) and manual
+ * polling are required to defer the next attempt.
+ */
+
+#include <stdint.h>
+#include <assert.h>
+#include <psxgpu.h>
+#include <psxapi.h>
+#include <psxcd.h>
+
+#define CD_READ_TIMEOUT 180
+#define CD_READ_COOLDOWN 60
+
+/* Internal globals */
+
+static CdlCB _read_callback = (CdlCB) 0;
+
+static int _total_sectors, _sector_size;
+static uint8_t _read_result[4];
+
+static volatile uint32_t *_read_addr;
+static volatile int _read_timeout, _pending_attempts, _pending_sectors;
+
+extern CdlCB _cd_override_callback;
+
+/* Private utilities and sector callback */
+
+static void _sector_callback(CdlIntrResult irq, uint8_t *result) {
+ if (irq == CdlDataReady) {
+ CdGetSector((void *) _read_addr, _sector_size);
+ _read_addr += _sector_size;
+
+ if (--_pending_sectors > 0) {
+ _read_timeout = VSync(-1) + CD_READ_TIMEOUT;
+ return;
+ }
+ }
+
+ // Stop reading if an error occurred or if no more sectors need to be read.
+ CdCommandF(CdlPause, 0, 0);
+
+ _cd_override_callback = (CdlCB) 0;
+ if (!_pending_attempts && _read_callback)
+ _read_callback(irq, result);
+
+ _read_timeout = VSync(-1) + CD_READ_COOLDOWN;
+}
+
+static int _poll_retry(void) {
+ if (!_pending_attempts) {
+ _sdk_log("CdRead() failed, too many attempts\n");
+
+ _pending_sectors = 0;
+ return -1;
+ }
+
+ //CdControlB(CdlPause, 0, 0);
+
+ _sdk_log("CdRead() failed, retrying (%d sectors pending)\n", _pending_sectors);
+ _pending_attempts--;
+
+ // Restart from the first sector that returned an error.
+ CdlLOC pos;
+ CdIntToPos(
+ CdPosToInt(CdLastPos()) + _total_sectors - _pending_sectors,
+ &pos
+ );
+
+ _read_timeout = VSync(-1) + CD_READ_TIMEOUT;
+ _total_sectors = _pending_sectors;
+
+ FastEnterCriticalSection();
+ _cd_override_callback = &_sector_callback;
+ FastExitCriticalSection();
+
+ if (CdCommand(CdlSetloc, (uint8_t *) &pos, 3, _read_result))
+ CdCommand(CdlReadN, 0, 0, _read_result);
+
+ return _pending_sectors;
+}
+
+/* Public API */
+
+int CdReadRetry(int sectors, uint32_t *buf, int mode, int attempts) {
+ if (CdReadSync(1, 0) > 0) {
+ _sdk_log("CdRead() failed, another read in progress (%d sectors pending)\n", _pending_sectors);
+ return 0;
+ }
+
+ _read_addr = buf;
+ _read_timeout = VSync(-1) + CD_READ_TIMEOUT;
+ _pending_attempts = attempts - 1;
+ _pending_sectors = sectors;
+ _total_sectors = sectors;
+ _sector_size = (mode & CdlModeSize) ? 585 : 512;
+
+ FastEnterCriticalSection();
+ _cd_override_callback = &_sector_callback;
+ FastExitCriticalSection();
+
+ uint8_t _mode = mode;
+ if (!CdCommand(CdlSetmode, &_mode, 1, 0))
+ return 0;
+ if (!CdCommand(CdlReadN, 0, 0, _read_result))
+ return 0;
+
+ return 1;
+}
+
+int CdRead(int sectors, uint32_t *buf, int mode) {
+ return CdReadRetry(sectors, buf, mode, 1);
+}
+
+void CdReadBreak(void) {
+ if (_pending_sectors > 0)
+ _pending_sectors = -1;
+}
+
+int CdReadSync(int mode, uint8_t *result) {
+ if (mode) {
+ if (_pending_sectors < 0)
+ return -2;
+ if (!_pending_sectors)
+ return 0;
+
+ if (VSync(-1) > _read_timeout)
+ return _poll_retry();
+ if (CdSync(1, 0) == CdlDiskError)
+ return -1;
+
+ return _pending_sectors;
+ }
+
+ while (_pending_sectors > 0) {
+ if (VSync(-1) > _read_timeout) {
+ if (_poll_retry() < 0)
+ return -1;
+ }
+
+ //if (CdSync(1, 0) == CdlDiskError)
+ //return -1;
+ }
+
+ CdlIntrResult status = CdSync(0, result);
+ if (_pending_sectors < 0)
+ return -2;
+ if (status != CdlComplete)
+ return -1;
+
+ return 0;
+}
+
+CdlCB CdReadCallback(CdlCB func) {
+ FastEnterCriticalSection();
+
+ CdlCB old_callback = _read_callback;
+ _read_callback = func;
+
+ FastExitCriticalSection();
+ return old_callback;
+}
diff --git a/libpsn00b/psxcd/common.c b/libpsn00b/psxcd/common.c
new file mode 100644
index 0000000..6b20df2
--- /dev/null
+++ b/libpsn00b/psxcd/common.c
@@ -0,0 +1,435 @@
+/*
+ * PSn00bSDK CD-ROM library (common functions)
+ * (C) 2020-2022 Lameguy64, spicyjpeg - MPL licensed
+ */
+
+#include <stdint.h>
+#include <assert.h>
+#include <psxetc.h>
+#include <psxapi.h>
+#include <psxcd.h>
+#include <hwregs_c.h>
+
+#define CD_ACK_TIMEOUT 0x100000
+#define CD_SYNC_TIMEOUT 0x100000
+
+/* Internal globals */
+
+static CdlCB _ready_callback = (CdlCB) 0;
+static CdlCB _sync_callback = (CdlCB) 0;
+static CdlCB _pause_callback = (CdlCB) 0;
+
+static uint8_t *_result_ptr;
+static uint8_t _last_command, _last_mode;
+static CdlLOC _last_pos;
+
+static volatile uint8_t _last_status, _last_irq, _last_error;
+static volatile uint8_t _ack_pending, _sync_pending;
+
+// These globals are accessed by other parts of the library.
+CdlCB _cd_override_callback;
+volatile int _cd_media_changed;
+
+/* Command metadata */
+
+// The original implementation of CdControlF() and the IRQ handler used a
+// ridiculous number of branches to account for command-specific behavior.
+// Storing that information as an array of bitfields is far more efficient.
+typedef enum {
+ PARAM_1 = 1,
+ PARAM_2 = 2,
+ PARAM_3 = 3,
+ STATUS = 1 << 2, // First byte of CdlAcknowledge response is status
+ C_STATUS = 1 << 3, // First byte of CdlComplete response is status
+ BLOCKING = 1 << 4, // Command triggers CdlComplete interrupt
+ OPTIONAL = 1 << 5, // Parameter is optional for the command
+ SETLOC = 1 << 6 // Parameter shall be sent as a separate CdlSetloc
+} CommandFlags;
+
+// https://problemkaputt.de/psx-spx.htm#cdromcontrollercommandsummary
+static const uint8_t _command_flags[] = {
+ 0,
+ STATUS, // CdlNop
+ STATUS | PARAM_3, // CdlSetloc
+ STATUS | OPTIONAL | PARAM_1, // CdlPlay
+ //STATUS | SETLOC, // CdlPlay
+ STATUS, // CdlForward
+ STATUS, // CdlBackward
+ STATUS | SETLOC, // CdlReadN
+ STATUS | C_STATUS | BLOCKING, // CdlStandby
+ STATUS | C_STATUS | BLOCKING, // CdlStop
+ STATUS | C_STATUS | BLOCKING, // CdlPause
+ STATUS | C_STATUS | BLOCKING, // CdlInit
+ STATUS, // CdlMute
+ STATUS, // CdlDemute
+ STATUS | PARAM_2, // CdlSetfilter
+ STATUS | PARAM_1, // CdlSetmode
+ STATUS, // CdlGetparam
+ 0, // CdlGetlocL
+ 0, // CdlGetlocP
+ STATUS | C_STATUS | BLOCKING | PARAM_1, // CdlSetsession
+ STATUS, // CdlGetTN
+ STATUS | PARAM_1, // CdlGetTD
+ STATUS | C_STATUS | BLOCKING | SETLOC, // CdlSeekL
+ STATUS | C_STATUS | BLOCKING | SETLOC, // CdlSeekP
+ 0,
+ 0,
+ PARAM_1, // CdlTest
+ STATUS | C_STATUS | BLOCKING, // CdlGetID
+ STATUS | SETLOC, // CdlReadS
+ STATUS, // CdlReset
+ STATUS | BLOCKING | PARAM_2, // CdlGetQ
+ STATUS | C_STATUS | BLOCKING // CdlReadTOC
+};
+
+/* Private interrupt handler */
+
+static void _update_status(uint8_t status) {
+ uint8_t last = _last_status;
+ _last_status = status;
+
+ if (!(last & CdlStatError) && (status & CdlStatError))
+ _sdk_log("drive error, status=0x%02x, code=0x%02x\n", _last_status, _last_error);
+
+ if (!(last & CdlStatShellOpen) && (status & CdlStatShellOpen)) {
+ _sdk_log("shell opened, invalidating cache\n");
+ _cd_media_changed = 1;
+ }
+}
+
+static void _cd_irq_handler(void) {
+ CD_REG(0) = 1;
+ CdlIntrResult irq = CD_REG(3) & 7;
+
+ if (irq == CdlDataReady) {
+ // TODO: are the first 4 accesses really needed, or was this just
+ // Sony's (dumb) way to flush the KUSEG write queue? We definitely
+ // don't need to do that since we're using KSEG1.
+ CD_REG(0) = 0;
+ CD_REG(0);
+ CD_REG(3) = 0;
+ CD_REG(3);
+ CD_REG(0) = 0;
+ CD_REG(3) = 0x80; // Request data
+ }
+
+ CD_REG(0) = 1;
+ CD_REG(3) = 0x1f; // Acknowledge all IRQs
+ CD_REG(3) = 0x40; // Reset parameter buffer
+
+ //while (CD_REG(0) & (1 << 5))
+ //CD_REG(1);
+ for (int i = 0; i < 50; i++)
+ __asm__ volatile("");
+
+ if (!irq || (irq > CdlDiskError))
+ return;
+
+ // Fetch the result from the drive if a buffer was previously set up. The
+ // first byte is always read as it contains the drive status for most
+ // commands.
+ uint8_t first_byte = CD_REG(1);
+ CdlCB callback;
+
+ if (_result_ptr) {
+ _result_ptr[0] = first_byte;
+
+ for (int i = 1; (CD_REG(0) & 0x20) && (i < 8); i++)
+ _result_ptr[i] = CD_REG(1);
+ }
+
+ switch (irq) {
+ case CdlDataReady:
+ // CdRead() can override any callback set using CdReadyCallback()
+ // by setting _cd_override_callback.
+ callback = _cd_override_callback;
+ if (!callback)
+ callback = _ready_callback;
+
+ _update_status(first_byte);
+ break;
+
+ case CdlComplete:
+ _sync_pending = 0;
+ callback = _sync_callback;
+
+ if (_last_command <= CdlReadTOC) {
+ if (_command_flags[_last_command] & C_STATUS)
+ _update_status(first_byte);
+ }
+ break;
+
+ case CdlAcknowledge:
+ _ack_pending = 0;
+ callback = (CdlCB) 0;
+
+ if (_last_command <= CdlReadTOC) {
+ if (_command_flags[_last_command] & STATUS)
+ _update_status(first_byte);
+ }
+ break;
+
+ case CdlDataEnd:
+ callback = _pause_callback;
+
+ _update_status(first_byte);
+ break;
+
+ case CdlDiskError:
+ _last_error = CD_REG(1);
+ callback = _ready_callback;
+
+ if (_ack_pending || _sync_pending) {
+ if (_sync_callback)
+ _sync_callback(irq, _result_ptr);
+
+ _ack_pending = 0;
+ _sync_pending = 0;
+ }
+
+ _update_status(first_byte);
+ break;
+ }
+
+ if (callback)
+ callback(irq, _result_ptr);
+
+ _last_command = 0;
+ _last_irq = irq;
+ _result_ptr = (uint8_t *) 0;
+}
+
+/* Initialization */
+
+int CdInit(void) {
+ EnterCriticalSection();
+ InterruptCallback(IRQ_CD, &_cd_irq_handler);
+ ExitCriticalSection();
+
+ CD_DELAY_SIZE = 0x00020943;
+
+ CD_REG(0) = 1;
+ CD_REG(3) = 0x1f; // Acknowledge all IRQs
+ CD_REG(2) = 0x1f; // Enable all IRQs
+ CD_REG(0) = 0;
+ CD_REG(3) = 0x00; // Clear any pending request
+
+ CdlATV mix = { 0x80, 0x00, 0x80, 0x00 };
+ CdMix(&mix);
+
+ DMA_DPCR |= 0x0000b000; // Enable DMA3
+ DMA_CHCR(DMA_CD) = 0x00000000; // Stop DMA3
+
+ _last_mode = 0;
+ _ack_pending = 0;
+ _sync_pending = 0;
+
+ _cd_override_callback = (CdlCB) 0;
+ _cd_media_changed = 1;
+
+ // Initialize the drive.
+ CdCommand(CdlNop, 0, 0, 0);
+ CdCommand(CdlInit, 0, 0, 0);
+
+ if (CdSync(0, 0) == CdlDiskError) {
+ _sdk_log("setup error, bad disc/drive or no disc inserted\n");
+ return 0;
+ }
+
+ CdCommand(CdlDemute, 0, 0, 0);
+ _sdk_log("setup done\n");
+ return 1;
+}
+
+/* Low-level command API */
+
+int CdCommandF(CdlCommand cmd, const void *param, int length) {
+ const uint8_t *_param = (const uint8_t *) param;
+
+ _last_command = (uint8_t) cmd;
+ _ack_pending = 1;
+
+ if (cmd <= CdlReadTOC) {
+ if (_command_flags[cmd] & BLOCKING)
+ _sync_pending = 1;
+
+ // Keep track of the last mode and seek location set (so retries can be
+ // attempted).
+
+ if (cmd == CdlSetloc) {
+ _last_pos.minute = _param[0];
+ _last_pos.second = _param[1];
+ _last_pos.sector = _param[2];
+ } else if (cmd == CdlSetmode) {
+ _last_mode = _param[0];
+ }
+ }
+
+ // Request a command FIFO write.
+ while (CD_REG(0) & 0x80)
+ __asm__ volatile("");
+
+ CD_REG(0) = 1;
+ CD_REG(3) = 0x40; // Reset parameter buffer
+
+ //while (CD_REG(0) & (1 << 5))
+ //CD_REG(1);
+ for (int i = 0; i < 50; i++)
+ __asm__ volatile("");
+
+ // Wait for the FIFO to become ready, then send the parameters followed by
+ // the command index.
+ while (CD_REG(0) & (1 << 7))
+ __asm__ volatile("");
+
+ CD_REG(0) = 0;
+ for (; length; length--)
+ CD_REG(2) = *(_param++);
+
+ CD_REG(0) = 0;
+ CD_REG(1) = (uint8_t) cmd;
+ return 1;
+}
+
+int CdCommand(CdlCommand cmd, const void *param, int length, uint8_t *result) {
+ /*if (_ack_pending) {
+ _sdk_log("CdCommand(0x%02x) failed, drive busy\n", cmd);
+ return 0;
+ }*/
+
+ _result_ptr = result;
+ CdCommandF(cmd, param, length);
+
+ // Wait for the command to be acknowledged.
+ for (int i = CD_ACK_TIMEOUT; i; i--) {
+ if (!_ack_pending)
+ return 1;
+ }
+
+ _sdk_log("CdCommand(0x%02x) failed, acknowledge timeout\n", cmd);
+ return 0;
+}
+
+/* High-level command API */
+
+int CdControlF(CdlCommand cmd, const void *param) {
+ // Assume no parameters need to be passed if the command is unknown.
+ uint8_t flags = (cmd <= CdlReadTOC) ? _command_flags[cmd] : 0;
+ int length;
+
+ if (flags & OPTIONAL) {
+ // The command may optionally take a parameter.
+ length = param ? (flags & 3) : 0;
+ } else if (flags & SETLOC) {
+ // The command takes no parameter, but the API allows specifying a
+ // location to be sent to the drive as a separate CdlSetloc command.
+ length = 0;
+ if (param)
+ CdCommandF(CdlSetloc, param, 3);
+ } else {
+ // The command takes a mandatory parameter or no parameter.
+ length = flags & 3;
+ if (length && !param)
+ return -1;
+ }
+
+ return CdCommandF(cmd, param, length);
+}
+
+int CdControl(CdlCommand cmd, const void *param, uint8_t *result) {
+ /*if (_ack_pending) {
+ _sdk_log("CdControl(0x%02x) failed, drive busy\n", cmd);
+ return 0;
+ }*/
+
+ _result_ptr = result;
+ CdControlF(cmd, param);
+
+ // Wait for the command to be acknowledged.
+ for (int i = CD_ACK_TIMEOUT; i; i--) {
+ if (!_ack_pending)
+ return 1;
+ }
+
+ _sdk_log("CdControl(0x%02x) failed, acknowledge timeout\n", cmd);
+ return 0;
+}
+
+int CdControlB(CdlCommand cmd, const void *param, uint8_t *result) {
+ int error = CdControl(cmd, param, result);
+ if (error != 1)
+ return error;
+
+ error = CdSync(0, 0);
+ return (error == CdlDiskError) ? 0 : 1;
+}
+
+/* Other APIs and callback setters */
+
+CdlIntrResult CdSync(int mode, uint8_t *result) {
+ if (mode) {
+ if (_sync_pending)
+ return CdlNoIntr;
+
+ if (result)
+ *result = _last_status;
+ if (_last_irq == CdlAcknowledge)
+ return CdlComplete;
+
+ return _last_irq;
+ }
+
+ for (int i = CD_SYNC_TIMEOUT; i; i--) {
+ if (!_sync_pending)
+ return CdSync(1, result); // :P
+ }
+
+ _sdk_log("CdSync() timeout\n");
+ return -1;
+}
+
+CdlCommand CdLastCom(void) {
+ return _last_command;
+}
+
+const CdlLOC *CdLastPos(void) {
+ return &_last_pos;
+}
+
+int CdMode(void) {
+ return _last_mode;
+}
+
+int CdStatus(void) {
+ return _last_status;
+}
+
+CdlCB CdReadyCallback(CdlCB func) {
+ FastEnterCriticalSection();
+
+ CdlCB old_callback = _ready_callback;
+ _ready_callback = func;
+
+ FastExitCriticalSection();
+ return old_callback;
+}
+
+CdlCB CdSyncCallback(CdlCB func) {
+ FastEnterCriticalSection();
+
+ CdlCB old_callback = _sync_callback;
+ _sync_callback = func;
+
+ FastExitCriticalSection();
+ return old_callback;
+}
+
+CdlCB CdAutoPauseCallback(CdlCB func) {
+ FastEnterCriticalSection();
+
+ CdlCB old_callback = _pause_callback;
+ _pause_callback = func;
+
+ FastExitCriticalSection();
+ return old_callback;
+}
diff --git a/libpsn00b/psxcd/getsector.c b/libpsn00b/psxcd/getsector.c
deleted file mode 100644
index a214d7a..0000000
--- a/libpsn00b/psxcd/getsector.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * PSn00bSDK CD drive library (sector DMA API)
- * (C) 2022 spicyjpeg - MPL licensed
- */
-
-#include <stdint.h>
-#include <assert.h>
-#include <psxcd.h>
-#include <hwregs_c.h>
-
-#define DATA_SYNC_TIMEOUT 0x100000
-
-/* DMA transfer functions */
-
-int CdGetSector(void *madr, int size) {
- //while (!(CD_STAT & (1 << 6)))
- //__asm__ volatile("");
-
- DMA_MADR(3) = (uint32_t) madr;
- DMA_BCR(3) = size | (1 << 16);
- DMA_CHCR(3) = 0x11000000;
-
- while (DMA_CHCR(3) & (1 << 24))
- __asm__ volatile("");
-
- return 1;
-}
-
-int CdGetSector2(void *madr, int size) {
- //while (!(CD_STAT & (1 << 6)))
- //__asm__ volatile("");
-
- DMA_MADR(3) = (uint32_t) madr;
- DMA_BCR(3) = size | (1 << 16);
- DMA_CHCR(3) = 0x11400100; // Transfer 1 word every 16 CPU cycles
-
- return 1;
-}
-
-int CdDataSync(int mode) {
- if (mode)
- return (DMA_CHCR(3) >> 24) & 1;
-
- for (int i = DATA_SYNC_TIMEOUT; i; i--) {
- if (!(DMA_CHCR(3) & (1 << 24)))
- return 0;
- }
-
- _sdk_log("CdDataSync() timeout\n");
- return -1;
-}
diff --git a/libpsn00b/psxcd/isofs.c b/libpsn00b/psxcd/isofs.c
index e00ddeb..0ac782b 100644
--- a/libpsn00b/psxcd/isofs.c
+++ b/libpsn00b/psxcd/isofs.c
@@ -11,6 +11,7 @@
#include <psxcd.h>
#include "isofs.h"
+#define CD_READ_ATTEMPTS 3
#define DEFAULT_PATH_SEP '\\'
#define IS_PATH_SEP(ch) (((ch) == '/') || ((ch) == '\\'))
@@ -21,7 +22,7 @@ typedef struct _CdlDIR_INT
uint8_t *_dir;
} CdlDIR_INT;
-extern int _cd_media_changed;
+extern volatile int _cd_media_changed;
static int _cd_iso_last_dir_lba;
@@ -77,7 +78,7 @@ static int _CdReadIsoDescriptor(int session_offs)
_sdk_log("Read sectors.\n");
// Read volume descriptor
- CdRead(1, (uint32_t*)_cd_iso_descriptor_buff, CdlModeSpeed);
+ CdReadRetry(1, (uint32_t*)_cd_iso_descriptor_buff, CdlModeSpeed, CD_READ_ATTEMPTS);
if( CdReadSync(0, 0) )
{
@@ -115,7 +116,7 @@ static int _CdReadIsoDescriptor(int session_offs)
// Read path table
CdIntToPos(descriptor->pathTable1Offs, &loc);
CdControl(CdlSetloc, (uint8_t*)&loc, 0);
- CdRead(i>>11, (uint32_t*)_cd_iso_pathtable_buff, CdlModeSpeed);
+ CdReadRetry(i>>11, (uint32_t*)_cd_iso_pathtable_buff, CdlModeSpeed, CD_READ_ATTEMPTS);
if( CdReadSync(0, 0) )
{
_sdk_log("Error reading ISO path table.\n");
@@ -163,7 +164,7 @@ static int _CdReadIsoDirectory(int lba)
// Read first sector of directory record
_cd_iso_directory_buff = (uint8_t*)malloc(2048);
- CdRead(1, (uint32_t*)_cd_iso_directory_buff, CdlModeSpeed);
+ CdReadRetry(1, (uint32_t*)_cd_iso_directory_buff, CdlModeSpeed, CD_READ_ATTEMPTS);
if( CdReadSync(0, 0) )
{
_sdk_log("Error reading initial directory record.\n");
@@ -194,7 +195,7 @@ static int _CdReadIsoDirectory(int lba)
_sdk_log("Allocated %d bytes for directory record.\n", i);
- CdRead(i>>11, (uint32_t*)_cd_iso_directory_buff, CdlModeSpeed);
+ CdReadRetry(i>>11, (uint32_t*)_cd_iso_directory_buff, CdlModeSpeed, CD_READ_ATTEMPTS);
if( CdReadSync(0, 0) )
{
_sdk_log("Error reading remaining directory record.\n");
@@ -485,13 +486,13 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename)
}
else
{
- _sdk_log("Longest path: %s|\n", rbuff);
+ _sdk_log("Longest path: %s\n", rbuff);
}
#endif
if( get_pathname(search_path, filename) )
{
- _sdk_log("Search path = %s|\n", search_path);
+ _sdk_log("Search path = %s\n", search_path);
}
// Search the pathtable for a matching path
@@ -499,7 +500,7 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename)
for(i=1; i<num_dirs; i++)
{
rbuff = resolve_pathtable_path(i, tpath_rbuff+127);
- _sdk_log("Found = %s|\n", rbuff);
+ _sdk_log("Found = %s\n", rbuff);
if( rbuff )
{
@@ -580,7 +581,7 @@ CdlDIR *CdOpenDir(const char* path)
for( i=1; i<num_dirs; i++ )
{
rbuff = resolve_pathtable_path( i, tpath_rbuff+127 );
- _sdk_log( "Found = %s|\n", rbuff );
+ _sdk_log( "Found = %s\n", rbuff );
if( rbuff )
{
@@ -666,11 +667,9 @@ int CdReadDir(CdlDIR *dir, CdlFILE* file)
file->size = dir_entry->entrySize.lsb;
- _sdk_log("dir_entry->entryLength = %d, ", dir_entry->entryLength);
-
d_dir->_pos += dir_entry->entryLength;
- _sdk_log("d_dir->_pos = %d\n", d_dir->_pos);
+ _sdk_log("dir_entry->entryLength = %d, d_dir->_pos = %d\n", dir_entry->entryLength, d_dir->_pos);
// Check if padding is reached (end of record sector)
if( d_dir->_dir[d_dir->_pos] == 0 )
@@ -697,34 +696,29 @@ int CdIsoError()
return _cd_iso_error;
}
-int CdGetVolumeLabel(char* label)
+int CdGetVolumeLabel(char *label)
{
- int i;
+ int i, length = 31;
ISO_DESCRIPTOR* descriptor;
-
+
if( _CdReadIsoDescriptor(0) )
- {
return -1;
- }
-
+
descriptor = (ISO_DESCRIPTOR*)_cd_iso_descriptor_buff;
-
- i = 0;
- for( i=0; (descriptor->volumeID[i]!=0x20)&&(i<32); i++ )
- {
- label[i] = descriptor->volumeID[i];
- }
-
- label[i] = 0x00;
-
- return 0;
+
+ while (descriptor->volumeID[length] == 0x20)
+ length--;
+
+ length++;
+ memcpy(label, descriptor->volumeID, length);
+ label[length] = 0x00;
+
+ return length;
}
// Session load routine
-void _cd_control(unsigned char com, unsigned char *param, int plen);
-
static volatile unsigned int _ready_oldcb;
static volatile int _ses_scanfound;
@@ -733,7 +727,7 @@ static volatile int _ses_scancomplete;
//static volatile char _ses_scan_resultbuff[8];
static volatile char *_ses_scanbuff;
-static void _scan_callback(int status, unsigned char *result)
+static void _scan_callback(CdlIntrResult status, unsigned char *result)
{
if( status == CdlDataReady )
{
@@ -743,7 +737,7 @@ static void _scan_callback(int status, unsigned char *result)
{
if( strncmp((const char*)_ses_scanbuff+1, "CD001", 5) == 0 )
{
- _cd_control(CdlPause, 0, 0);
+ CdControlF(CdlPause, 0);
_ses_scancomplete = 1;
_ses_scanfound = 1;
return;
@@ -752,7 +746,7 @@ static void _scan_callback(int status, unsigned char *result)
_ses_scancount++;
if( _ses_scancount >= 512 )
{
- _cd_control(CdlPause, 0, 0);
+ CdControlF(CdlPause, 0);
_ses_scancomplete = 1;
return;
}
@@ -760,7 +754,7 @@ static void _scan_callback(int status, unsigned char *result)
if( status == CdlDiskError )
{
- _cd_control(CdlPause, 0, 0);
+ CdControlF(CdlPause, 0);
_ses_scancomplete = 1;
}
}
@@ -768,7 +762,7 @@ static void _scan_callback(int status, unsigned char *result)
int CdLoadSession(int session)
{
CdlLOC *loc;
- unsigned int ready_oldcb;
+ CdlCB ready_oldcb;
char scanbuff[2048];
char resultbuff[16];
int i;
@@ -791,9 +785,7 @@ int CdLoadSession(int session)
}
// Set search routine callback
- EnterCriticalSection();
ready_oldcb = CdReadyCallback(_scan_callback);
- ExitCriticalSection();
_ses_scanfound = 0;
_ses_scancount = 0;
@@ -810,26 +802,20 @@ int CdLoadSession(int session)
// Wait until scan complete
while(!_ses_scancomplete);
- EnterCriticalSection();
CdReadyCallback((void*)_ready_oldcb);
- ExitCriticalSection();
if( !_ses_scanfound )
{
_sdk_log("CdLoadSession(): Did not find volume descriptor.\n");
_cd_iso_error = CdlIsoInvalidFs;
- EnterCriticalSection();
CdReadyCallback((CdlCB)ready_oldcb);
- ExitCriticalSection();
return -1;
}
// Restore old callback if any
- EnterCriticalSection();
CdReadyCallback((CdlCB)ready_oldcb);
- ExitCriticalSection();
// Wait until CD-ROM has completely stopped reading, to get a consistent
// fix of the CD-ROM pickup's current location
diff --git a/libpsn00b/psxcd/misc.c b/libpsn00b/psxcd/misc.c
new file mode 100644
index 0000000..8fd2a4d
--- /dev/null
+++ b/libpsn00b/psxcd/misc.c
@@ -0,0 +1,151 @@
+/*
+ * PSn00bSDK CD-ROM library (misc. functions)
+ * (C) 2020-2022 Lameguy64, spicyjpeg - MPL licensed
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <psxetc.h>
+#include <psxcd.h>
+#include <hwregs_c.h>
+
+#define DATA_SYNC_TIMEOUT 0x100000
+
+/* Private types */
+
+typedef struct {
+ uint8_t status, first_track, last_track;
+} TrackInfo;
+
+/* Sector DMA transfer functions */
+
+int CdGetSector(void *madr, int size) {
+ //while (!(CD_REG(0) & (1 << 6)))
+ //__asm__ volatile("");
+
+ DMA_MADR(DMA_CD) = (uint32_t) madr;
+ DMA_BCR(DMA_CD) = size | (1 << 16);
+ DMA_CHCR(DMA_CD) = 0x11000000;
+
+ while (DMA_CHCR(DMA_CD) & (1 << 24))
+ __asm__ volatile("");
+
+ return 1;
+}
+
+int CdGetSector2(void *madr, int size) {
+ //while (!(CD_REG(0) & (1 << 6)))
+ //__asm__ volatile("");
+
+ DMA_MADR(DMA_CD) = (uint32_t) madr;
+ DMA_BCR(DMA_CD) = size | (1 << 16);
+ DMA_CHCR(DMA_CD) = 0x11400100; // Transfer 1 word every 16 CPU cycles
+
+ return 1;
+}
+
+int CdDataSync(int mode) {
+ if (mode)
+ return (DMA_CHCR(DMA_CD) >> 24) & 1;
+
+ for (int i = DATA_SYNC_TIMEOUT; i; i--) {
+ if (!(DMA_CHCR(DMA_CD) & (1 << 24)))
+ return 0;
+ }
+
+ _sdk_log("CdDataSync() timeout\n");
+ return -1;
+}
+
+/* LBA/MSF conversion */
+
+CdlLOC *CdIntToPos(int i, CdlLOC *p) {
+ i += 150;
+
+ p->minute = itob(i / (75 * 60));
+ p->second = itob((i / 75) % 60);
+ p->sector = itob(i % 75);
+ return p;
+}
+
+int CdPosToInt(const CdlLOC *p) {
+ return (
+ (btoi(p->minute) * (75 * 60)) +
+ (btoi(p->second) * 75) +
+ btoi(p->sector)
+ ) - 150;
+}
+
+/* Misc. functions */
+
+int CdGetToc(CdlLOC *toc) {
+ TrackInfo track_info;
+
+ if (!CdCommand(CdlGetTN, 0, 0, (uint8_t *) &track_info))
+ return 0;
+ if (CdSync(1, 0) != CdlComplete)
+ return 0;
+
+ int first = btoi(track_info.first_track);
+ int tracks = btoi(track_info.last_track) + 1 - first;
+ //assert(first == 1);
+
+ for (int i = 0; i < tracks; i++) {
+ uint8_t track = itob(first + i);
+
+ if (!CdCommand(CdlGetTD, &track, 1, (uint8_t *) &toc[i]))
+ return 0;
+ if (CdSync(1, 0) != CdlComplete)
+ return 0;
+
+ toc[i].sector = 0;
+ toc[i].track = track;
+ }
+
+ return tracks;
+}
+
+CdlRegionCode CdGetRegion(void) {
+ uint8_t param = 0x22;
+ uint8_t result[16];
+
+ // Test command 0x22 is unsupported in firmware version C0, which was used
+ // exclusively in the SCPH-1000 Japanese model. It's thus safe to assume
+ // that the console is Japanese if the command returns a valid error.
+ // https://psx-spx.consoledev.net/cdromdrive/#19h22h-int3for-europe
+ memset(result, 0, 16);
+
+ if (!CdCommand(CdlTest, &param, 1, result)) {
+ _sdk_log("failed to probe drive region\n");
+ return (result[1] == 0x10) ? CdlRegionSCEI : CdlRegionUnknown;
+ }
+
+ _sdk_log("drive region: %s\n", result);
+
+ if (!strcmp(result, "for Japan"))
+ return CdlRegionSCEI;
+ if (!strcmp(result, "for U/C"))
+ return CdlRegionSCEA;
+ if (!strcmp(result, "for Europe"))
+ return CdlRegionSCEE;
+ if (!strcmp(result, "for NETNA") || !strcmp(result, "for NETEU"))
+ return CdlRegionSCEW;
+ if (!strcmp(result, "for US/AEP"))
+ return CdlRegionDebug;
+
+ return CdlRegionUnknown;
+}
+
+int CdMix(const CdlATV *vol) {
+ CD_REG(0) = 2;
+ CD_REG(2) = vol->val0;
+ CD_REG(3) = vol->val1;
+
+ CD_REG(0) = 3;
+ CD_REG(1) = vol->val2;
+ CD_REG(2) = vol->val3;
+
+ CD_REG(3) = 0x20; // Unmute XA, apply volume changes
+ return 1;
+}
diff --git a/libpsn00b/psxcd/psxcd.c b/libpsn00b/psxcd/psxcd.c
deleted file mode 100644
index 9392d30..0000000
--- a/libpsn00b/psxcd/psxcd.c
+++ /dev/null
@@ -1,371 +0,0 @@
-#include <stdint.h>
-#include <assert.h>
-#include <psxgpu.h>
-#include <psxapi.h>
-#include <psxcd.h>
-
-#define READ_TIMEOUT 600 // 10 seconds for NTSC
-
-extern volatile char _cd_ack_wait;
-extern volatile uint8_t _cd_last_int;
-extern volatile uint8_t _cd_last_mode;
-extern volatile uint8_t _cd_status;
-extern volatile CdlCB _cd_callback_int1_data;
-
-volatile uint8_t *_cd_result_ptr;
-
-// For read retry
-volatile CdlLOC _cd_last_setloc;
-volatile uint32_t *_cd_last_read_addr;
-volatile int _cd_last_sector_count;
-
-int _cd_media_changed;
-
-void _cd_init(void);
-void _cd_control(unsigned char com, const void *param, int plen);
-void _cd_wait_ack(void);
-void _cd_wait(void);
-
-int CdInit(void) {
- // Sets up CD-ROM hardware and low-level subsystem
- _cd_init();
-
- // So CD ISO file system component will update the ISO descriptor
- _cd_media_changed = 1;
-
- // Issue commands to initialize the CD-ROM hardware
- CdControl(CdlNop, 0, 0);
- CdControl(CdlInit, 0, 0);
-
- if(CdSync(0, 0) != CdlDiskError) {
- CdControl(CdlDemute, 0, 0);
- _sdk_log("setup done\n");
- } else {
- _sdk_log("setup error, bad disc/drive or no disc inserted\n");
- }
-
- return 1;
-}
-
-int CdControl(unsigned char com, const void *param, unsigned char *result)
-{
- // Don't issue command if ack is not received yet
- if( _cd_ack_wait )
- {
- return 0;
- }
-
- _cd_result_ptr = result;
-
- CdControlF(com, param);
- _cd_wait_ack();
-
- // Set media changed flag if lid had been opened
- if( (CdStatus()&0x10) )
- {
- _cd_media_changed = 1;
- }
-
- return 1;
-}
-
-int CdControlB(unsigned char com, const void *param, unsigned char *result)
-{
- if( !CdControl(com, param, result) )
- {
- return 0;
- }
-
- CdSync(0, 0);
- return 1;
-}
-
-int CdControlF(unsigned char com, const void *param)
-{
- int param_len=0;
-
- // Command specific parameters
- switch(com)
- {
- case CdlSetloc:
- param_len = 3;
- _cd_last_setloc = *((CdlLOC*)param);
- break;
- case CdlPlay:
- if( param )
- {
- param_len = 1;
- }
- break;
- case CdlSetfilter:
- param_len = 2;
- break;
- case CdlSetmode:
- case CdlSetsession:
- case CdlTest:
- case CdlGetTD:
- param_len = 1;
- break;
- case CdlReadN:
- case CdlReadS:
- case CdlSeekL:
- case CdlSeekP:
- if( param )
- {
- _cd_control(CdlSetloc, param, 3);
- _cd_last_setloc = *((CdlLOC*)param);
- }
- break;
- }
-
- // Issue CD command
- _cd_control(com, param, param_len);
-
- return 1;
-}
-
-int CdSync(int mode, unsigned char *result)
-{
- int cdirq;
-
- if( mode )
- {
- if( result )
- {
- *result = _cd_status;
- }
-
- cdirq = _cd_last_int;
- if( cdirq == CdlAcknowledge )
- {
- cdirq = CdlComplete;
- }
- return cdirq;
- }
-
- _cd_wait();
-
- if( result )
- {
- *result = _cd_status;
- }
-
- cdirq = _cd_last_int;
- if( cdirq == CdlAcknowledge )
- {
- cdirq = CdlComplete;
- }
-
- return cdirq;
-}
-
-int CdGetToc(CdlLOC *toc)
-{
- uint8_t track_info[8];
- int i,tracks;
-
- // Get number of tracks
- if( !CdControl(CdlGetTN, 0, track_info) )
- {
- return 0;
- }
-
- if( CdSync(1, 0) != CdlComplete )
- {
- return 0;
- }
-
- tracks = 1+(btoi(track_info[2])-btoi(track_info[1]));
-
- // Get track positions
- for(i=0; i<tracks; i++)
- {
- int t = itob(1+i);
- if( !CdControl(CdlGetTD, (uint8_t*)&t, (uint8_t*)&toc[i]) )
- {
- return 0;
- }
- if( CdSync(1, 0) != CdlComplete )
- {
- return 0;
- }
- toc[i].sector = 0;
- toc[i].track = 1+i;
- }
-
- return tracks;
-}
-
-CdlLOC *CdIntToPos(int i, CdlLOC *p) {
-
- i += 150;
-
- p->minute = itob((i/75)/60);
- p->second = itob((i/75)%60);
- p->sector = itob(i%75);
-
- return p;
-
-}
-
-int CdPosToInt(const CdlLOC *p)
-{
- return ((75*(btoi(p->minute)*60))+(75*btoi(p->second))+btoi(p->sector))-150;
-}
-
-int CdStatus(void)
-{
- return _cd_status;
-}
-
-int CdMode(void)
-{
- return _cd_last_mode;
-}
-
-
-// CD data read routines
-volatile int _cd_sector_count = 0;
-volatile uint32_t *_cd_read_addr;
-volatile uint8_t _cd_read_result[8];
-volatile uint32_t _cd_read_oldcb;
-volatile uint32_t _cd_read_sector_sz;
-volatile uint32_t _cd_read_counter;
-
-
-
-volatile CdlCB _cd_read_cb;
-
-// Sector callback
-static void _CdReadReadyCallback(int status, unsigned char *result)
-{
- _cd_read_counter = VSync(-1);
-
- if( status == CdlDataReady )
- {
- // Fetch sector from CD controller
- CdGetSector((void*)_cd_read_addr, _cd_read_sector_sz);
-
- // Increment destination address
- _cd_read_addr += _cd_read_sector_sz;
-
- // Subtract sector count
- _cd_sector_count--;
- }
-
- // End reading with pause command when sector count reaches zero
- // or when an error occurs
- if( ( _cd_sector_count <= 0 ) || ( status == CdlDiskError ) )
- {
- // Stop reading
- _cd_control(CdlPause, 0, 0);
-
- // Revert previous ready callback
- _cd_callback_int1_data = (CdlCB)_cd_read_oldcb;
-
- // Execute read completion callback
- if( _cd_read_cb )
- {
- _cd_read_cb(status, result);
- }
- }
-}
-
-int CdRead(int sectors, uint32_t *buf, int mode)
-{
- // Set sectors to read count
- _cd_sector_count = sectors;
- _cd_last_sector_count = sectors;
- _cd_last_read_addr = buf;
- _cd_read_addr = buf;
-
- // Determine sector based on mode flags
- if( mode & CdlModeSize )
- _cd_read_sector_sz = 2340 / 4;
- else
- _cd_read_sector_sz = 2048 / 4;
-
- _cd_read_counter = VSync(-1);
-
- // Set read callback
- EnterCriticalSection();
- _cd_read_oldcb = CdReadyCallback(_CdReadReadyCallback);
- ExitCriticalSection();
-
- // Set specified mode
- CdControl(CdlSetmode, (uint8_t*)&mode, 0);
-
- // Begin reading sectors
- CdControl(CdlReadN, 0, (uint8_t*)_cd_read_result);
-
- return 0;
-}
-
-static void CdDoRetry()
-{
- int cb;
-
- _sdk_log("retrying read...\n");
-
- // Stop reading
- CdControl(CdlPause, 0, 0);
- CdSync(0, 0);
-
- // Reset parameters for retrying read operation
- _cd_sector_count = _cd_last_sector_count;
- _cd_read_addr = _cd_last_read_addr;
-
- // Reset timeout
- _cd_read_counter = VSync(-1);
-
- EnterCriticalSection();
- CdReadyCallback(_CdReadReadyCallback);
- ExitCriticalSection();
-
- // Retry read
- CdControl(CdlSetloc, (void*)&_cd_last_setloc, 0);
- CdControl(CdlReadN, 0, (uint8_t*)_cd_read_result);
-}
-
-int CdReadSync(int mode, uint8_t *result)
-{
- if( (VSync(-1)-_cd_read_counter) > READ_TIMEOUT )
- {
- CdDoRetry();
- }
-
- if( mode )
- {
- if( CdSync(1, 0) == CdlDiskError )
- {
- return -1;
- }
- return _cd_sector_count;
- }
-
- while(_cd_sector_count > 0)
- {
- if( (VSync(-1)-_cd_read_counter) > READ_TIMEOUT )
- {
- CdDoRetry();
- }
- }
-
- if( CdSync(0, result) != CdlComplete )
- {
- return -1;
- }
-
- return 0;
-}
-
-uint32_t CdReadCallback(CdlCB func)
-{
- unsigned int old_func;
-
- old_func = (unsigned int)_cd_read_cb;
-
- _cd_read_cb = func;
-
- return old_func;
-}
diff --git a/libpsn00b/psxcd/psxcd_asm.s b/libpsn00b/psxcd/psxcd_asm.s
deleted file mode 100644
index c0a5312..0000000
--- a/libpsn00b/psxcd/psxcd_asm.s
+++ /dev/null
@@ -1,487 +0,0 @@
-.set noreorder
-
-.include "hwregs_a.inc"
-
-.section .text
-
-.global _cd_init
-.type _cd_init, @function
-_cd_init:
-
- addiu $sp, -4
- sw $ra, 0($sp)
-
- jal EnterCriticalSection
- nop
-
- lui $a3, IOBASE # Acknowledge all CD IRQs
-
- li $v0, 0x20943 # Set CD-ROM Delay/Size and common delay
- sw $v0, CD_DELAY_SIZE($a3)
- li $v0, 0x1325
- sw $v0, COM_DELAY_CFG($a3)
-
- li $v0, 1
- sb $v0, CD_REG0($a3)
- li $v0, 0x1f
- sb $v0, CD_REG3($a3)
- sb $v0, CD_REG2($a3) # Enable all IRQs
-
- sb $0 , CD_REG0($a3)
- sb $0 , CD_REG3($a3)
-
- la $a1, _cd_handler
- jal InterruptCallback
- li $a0, 2
-
- li $v0, 2 # Set CD left volume
- sb $v0, CD_REG0($a3)
- li $v0, 0x80
- sb $v0, CD_REG2($a3)
-
- li $v0, 3 # Set CD right volume
- sb $v0, CD_REG0($a3)
- li $v0, 0x80
- sb $v0, CD_REG1($a3)
-
- li $v0, 0x20 # Apply volume
- sb $v0, CD_REG3($a3)
-
- # Clear a bunch of stats
- la $v0, _cd_ack_wait
- sb $0 , 0($v0)
- la $v0, _cd_complt_wait
- sb $0 , 0($v0)
- la $v0, _cd_last_cmd
- sb $0 , 0($v0)
- la $v0, _cd_last_mode
- sb $0 , 0($v0)
- la $v0, _cd_last_int
- sb $0 , 0($v0)
-
- la $v0, _cd_result_ptr
- sw $0 , 0($v0)
-
- # Clear callback hooks
- la $v0, _cd_callback_int1_data
- sw $0 , 0($v0)
- la $v0, _cd_callback_int4
- sw $0 , 0($v0)
-
- la $v0, _cd_read_cb
- sw $0 , 0($v0)
-
- lw $v0, DMA_DPCR($a3)
- li $v1, 0xB000
- or $v0, $v1
- sw $v0, DMA_DPCR($a3)
-
- jal ExitCriticalSection
- nop
-
- lw $ra, 0($sp)
- addiu $sp, 4
- jr $ra
- nop
-
-
-.global _cd_wait
-.type _cd_wait, @function
-_cd_wait:
- la $v0, _cd_ack_wait
- lbu $v0, 0($v0)
- nop
- bnez $v0, _cd_wait
- nop
-.Lcomplete:
- la $v0, _cd_complt_wait
- lbu $v0, 0($v0)
- nop
- bnez $v0, .Lcomplete
- nop
- jr $ra
- nop
-
-
-.global _cd_wait_ack
-.type _cd_wait_ack, @function
-_cd_wait_ack:
- la $v0, _cd_ack_wait
- lbu $v0, 0($v0)
- nop
- bnez $v0, _cd_wait_ack
- nop
- jr $ra
- nop
-
-
-.global _cd_wait_complt
-.type _cd_wait_complt, @function
-_cd_wait_complt:
- la $v0, _cd_complt_wait
- lbu $v0, 0($v0)
- nop
- bnez $v0, _cd_wait_complt
- nop
- jr $ra
- nop
-
-
-.type _cd_handler, @function
-_cd_handler:
-
- addiu $sp, -4
- sw $ra, 0($sp)
-
- lui $a3, IOBASE # Get IRQ number
- li $v0, 1
- sb $v0, CD_REG0($a3)
-
- lbu $v0, CD_REG3($a3)
- nop
- andi $v0, 0x7
-
- la $v1, _cd_last_int # Save last IRQ value
- sb $v0, 0($v1)
-
- bne $v0, 0x1, .Lno_data
- nop
-
- sb $0 , CD_REG0($a3)
- lbu $v1, CD_REG0($a3)
- sb $0 , CD_REG3($a3)
- lbu $v1, CD_REG3($a3)
-
- sb $0 , CD_REG0($a3) # Load data FIFO on INT1
- li $v1, 0x80
- sb $v1, CD_REG3($a3)
-
-.Lno_data:
-
- li $v1, 1
- sb $v1, CD_REG0($a3) # Clear CD interrupt and parameter FIFO
- li $v1, 0x5f
- sb $v1, CD_REG3($a3)
- li $v1, 0x40
- sb $v1, CD_REG3($a3)
-
- li $v1, 0 # Delay when clearing parameter FIFO
- sw $v1, 0($0)
- li $v1, 1
- sw $v1, 0($0)
- li $v1, 2
- sw $v1, 0($0)
- li $v1, 3
- sw $v1, 0($0)
-
- la $v1, _cd_last_int
- lbu $v0, 0($v1)
-
- beq $v0, 0x1, .Lirq_1 # Data ready
- nop
- beq $v0, 0x2, .Lirq_2 # Command finish
- nop
- beq $v0, 0x3, .Lirq_3 # Acknowledge
- nop
- beq $v0, 0x4, .Lirq_4 # Data/track end
- nop
- beq $v0, 0x5, .Lirq_5 # Error
- nop
-
- b .Lirq_misc
- nop
-
-.Lirq_1: # Data ready
-
- jal _cd_fetch_result
- nop
-
- la $v0, _cd_callback_int1_data
- lw $v0, 0($v0)
- nop
- beqz $v0, .Lirq_misc
- nop
-
- la $a0, _cd_last_int
- lbu $a0, 0($a0)
- la $a1, _cd_result_ptr
- lw $a1, 0($a1)
-
- jalr $v0
- addiu $sp, -16
- addiu $sp, 16
-
- b .Lirq_misc
- nop
-
-.Lirq_2: # Command complete
-
- jal _cd_fetch_result
- nop
-
- la $v0, _cd_complt_wait
- sb $0 , 0($v0)
-
- la $v0, _cd_sync_cb
- lw $v0, 0($v0)
- nop
- beqz $v0, .Lirq_misc
- nop
-
- la $a0, _cd_last_int
- lbu $a0, 0($a0)
- la $a1, _cd_result_ptr
- lw $a1, 0($a1)
- jalr $v0
- addiu $sp, -16
- addiu $sp, 16
-
- b .Lirq_misc
- nop
-
-.Lirq_3: # Command acknowledge
-
- jal _cd_fetch_result
- nop
-
- la $v0, _cd_ack_wait
- sb $0 , 0($v0)
-
- b .Lirq_misc
- nop
-
-.Lirq_4:
-
- jal _cd_fetch_result
- nop
-
- la $v0, _cd_callback_int4
- lw $v0, 0($v0)
- nop
- beqz $v0, .Lirq_misc
- nop
-
- jalr $v0
- addiu $sp, -16
- addiu $sp, 16
-
- b .Lirq_misc
- nop
-
-.Lirq_5: # Error
-
- jal _cd_fetch_result
- nop
-
- la $v0, _cd_complt_wait
- lbu $v0, 0($v0)
- nop
- beqz $v0, .Lno_complete
- nop
-
- la $v0, _cd_sync_cb
- lw $v0, 0($v0)
- nop
- beqz $v0, .Lno_complete
- nop
-
- li $a0, 0x05 # CdlDiskError
- la $a1, _cd_result_ptr
- lw $a1, 0($a1)
- jalr $v0
- addiu $sp, -16
- addiu $sp, 16
-
-.Lno_complete:
-
- la $v0, _cd_complt_wait
- sb $0 , 0($v0)
- la $v0, _cd_ack_wait
- sb $0 , 0($v0)
-
- la $v0, _cd_callback_int1_data
- lw $v0, 0($v0)
- nop
- beqz $v0, .Lirq_misc
- nop
-
- li $a0, 0x05 # CdlDiskError
- la $a1, _cd_result_ptr
- lw $a1, 0($a1)
-
- jalr $v0
- addiu $sp, -16
- addiu $sp, 16
-
-.Lirq_misc:
-
- lw $ra, 0($sp)
- addiu $sp, 4
- jr $ra
- nop
-
-
-_cd_fetch_result:
-
- lui $a3, IOBASE
-
- la $a0, _cd_status
- lbu $v0, CD_REG1($a3)
-
- la $v1, _cd_last_int
- lbu $v1, 0($v1)
- nop
- beq $v1, 0x2, .Lirq2_checks
- nop
-
- # IRQ3 checks
-
- la $v1, _cd_last_cmd
- lbu $v1, 0($v1)
- nop
- beq $v1, 0x10, .Lskip_status
- nop
- beq $v1, 0x11, .Lskip_status
- nop
-
- b .Lwrite_status
- nop
-
- # IRQ2 checks
-
-.Lirq2_checks:
-
- la $v1, _cd_last_cmd
- lbu $v1, 0($v1)
- nop
- beq $v1, 0x1D, .Lskip_status
- nop
-
-.Lwrite_status:
-
- sb $v0, 0($a0)
-
-.Lskip_status:
-
- la $a0, _cd_result_ptr
- lw $a0, 0($a0)
- nop
- beqz $a0, .Lno_result
- nop
- sb $v0, 0($a0)
- addiu $a0, 1
-
- move $a1, $0
-.Lread_futher_result:
-
- lbu $v0, CD_REG0($a3)
- nop
- andi $v0, 0x20
- beqz $v0, .Lno_result
- addu $a1, 1
- bge $a1, 7, .Lno_result # timeout (locks up here on PSIO)
- nop
- lbu $v0, CD_REG1($a3)
- lbu $v1, CD_REG0($a3)
- sb $v0, 0($a0)
-
- andi $v1, 0x20 # when performing a CD-ROM read
- bnez $v1, .Lread_futher_result
- addiu $a0, 1
-
-.Lno_result:
-
-# lbu $v0, CD_REG0($a3) # Flush response FIFO
-# nop
-# andi $v0, 0x20
-# bnez $v0, .Lno_result
-# lbu $v0, CD_REG1($a3)
-
- jr $ra
- nop
-
-
-.global CdAutoPauseCallback
-.type CdAutoPauseCallback, @function
-CdAutoPauseCallback:
-
- addiu $sp, -8
- sw $ra, 0($sp)
- sw $a0, 4($sp)
-
- la $v1, _cd_callback_int4
- lw $v0, 0($v1)
-
- la $v1, _cd_callback_int4
-
- lw $a0, 4($sp)
- nop
- sw $a0, 0($v1)
-
- lw $ra, 0($sp)
- addiu $sp, 8
- jr $ra
- nop
-
-
-.global CdReadyCallback
-.type CdReadyCallback, @function
-CdReadyCallback:
-
- addiu $sp, -12
- sw $ra, 0($sp)
- sw $a0, 4($sp)
-
- la $v1, _cd_callback_int1_data
- lw $v0, 0($v1)
-
- la $v1, _cd_callback_int1_data
- sw $v0, 8($sp)
-
- lw $a0, 4($sp)
- nop
- sw $a0, 0($v1)
-
- lw $ra, 0($sp)
- lw $v0, 8($sp)
- jr $ra
- addiu $sp, 12
-
-
-.global CdSyncCallback
-.type CdSyncCallback, @function
-CdSyncCallback:
- addiu $sp, -12
- sw $ra, 0($sp)
- sw $a0, 4($sp)
-
- la $v1, _cd_sync_cb
- lw $v0, 0($v1)
-
- la $v1, _cd_sync_cb
- sw $v0, 8($sp)
-
- lw $a0, 4($sp)
- nop
- sw $a0, 0($v1)
-
- lw $ra, 0($sp)
- lw $v0, 8($sp)
- jr $ra
- addiu $sp, 12
-
-
-.section .data
-
-.comm _cd_last_cmd, 1, 1
-.comm _cd_last_mode, 1, 1
-.comm _cd_ack_wait, 1, 1
-.comm _cd_complt_wait, 1, 1
-
-.comm _cd_status, 1, 1
-.comm _cd_last_int, 1, 1
-
-# Callback hooks
-.comm _cd_callback_int1_data, 4, 4 # Data IRQ callback
-.comm _cd_callback_int4, 4, 4 # Autopause callback
-.comm _cd_sync_cb, 4, 4
diff --git a/libpsn00b/psxcd/readme.txt b/libpsn00b/psxcd/readme.txt
index 64643ed..dcb40b6 100644
--- a/libpsn00b/psxcd/readme.txt
+++ b/libpsn00b/psxcd/readme.txt
@@ -1,45 +1,39 @@
PSX CD-ROM library, part of PSn00bSDK
-2020 Lameguy64 / Meido-Tek Productions
+2020-2022 Lameguy64 / Meido-Tek Productions
Licensed under Mozilla Public License
- Open source implementation of the long awaited CD-ROM library that
-provides greater functionality than the BIOS CD-ROM subsystem. Supports
-pretty much all features of the CD-ROM hardware such as CD data read,
-CD Audio and XA audio playback. Data streaming should also be possible
-with the use of CdlReadN/CdlReadS commands and CdReadyCallback().
+Open source implementation of the long awaited CD-ROM library that provides
+greater functionality than the BIOS CD-ROM subsystem. Supports pretty much all
+features of the CD-ROM hardware such as CD data read, CD Audio and XA audio
+playback, with the exception of the St*() APIs for .STR playback (but manual
+streaming using CdReadyCallback() is still supported).
- Library also includes an ISO9660 file system parser for locating
-files within the CD-ROM file system. Unlike the file system parser in
-the official libraries libpsxcd can parse directories containing any
-number of files. Rock-ridge and Joliet extensions are not supported
-however.
-
- Be aware that the CD-ROM library might have some loose ends as it
-is still a work in progress, but should work flawlessly in most use
-cases.
+An ISO9660 file system driver for locating files within the CD-ROM is also
+included. Unlike the ISO9660 parser in the official libraries, libpsxcd can
+parse directories containing any number of files. Currently no ISO9660
+extensions are supported.
+Be aware that the CD-ROM library might have some loose ends as it is still a
+work in progress, but should work flawlessly in most use cases.
Library developer(s):
- Lameguy64
-
+ Lameguy64 (ISO9660 driver, initial implementation of low-level functions)
+ spicyjpeg (C rewrite)
Library header(s):
psxcd.h
-
Todo list:
* Command query mechanism so that more than 2 CD-ROM commands can
easily be issued in callbacks. Official library probably does this.
-
+
* Helper functions for handling disc changes (CdDiskReady and
CdGetDiskType) are not yet implemented.
-
- * CdReadBreak() not yet implemented.
-
+
* Data streaming functions (prefixed with St*) not yet implemented.
Would require devising a PSn00bSDK equivalent of the STR file
- format. \ No newline at end of file
+ format.