static boolean subChanMixed = FALSE;
static boolean subChanRaw = FALSE;
-static boolean subChanMissing = FALSE;
static boolean multifile = FALSE;
} *chd_img;
#endif
-int (*cdimg_read_func)(FILE *f, unsigned int base, void *dest, int sector);
+static int (*cdimg_read_func)(FILE *f, unsigned int base, void *dest, int sector);
+static int (*cdimg_read_sub_func)(FILE *f, int sector);
char* CALLBACK CDR__getDriveLetter(void);
long CALLBACK CDR__configure(void);
static int cdread_normal(FILE *f, unsigned int base, void *dest, int sector)
{
- fseek(f, base + sector * CD_FRAMESIZE_RAW, SEEK_SET);
- return fread(dest, 1, CD_FRAMESIZE_RAW, f);
+ int ret;
+ if (fseek(f, base + sector * CD_FRAMESIZE_RAW, SEEK_SET))
+ goto fail_io;
+ ret = fread(dest, 1, CD_FRAMESIZE_RAW, f);
+ if (ret <= 0)
+ goto fail_io;
+ return ret;
+
+fail_io:
+ // often happens in cdda gaps of a split cue/bin, so not logged
+ //SysPrintf("File IO error %d, base %u, sector %u\n", errno, base, sector);
+ return -1;
}
static int cdread_sub_mixed(FILE *f, unsigned int base, void *dest, int sector)
{
int ret;
- fseek(f, base + sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE), SEEK_SET);
+ if (fseek(f, base + sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE), SEEK_SET))
+ goto fail_io;
ret = fread(dest, 1, CD_FRAMESIZE_RAW, f);
+ if (ret <= 0)
+ goto fail_io;
+ return ret;
+
+fail_io:
+ //SysPrintf("File IO error %d, base %u, sector %u\n", errno, base, sector);
+ return -1;
+}
+
+static int cdread_sub_sub_mixed(FILE *f, int sector)
+{
+ if (fseek(f, sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE) + CD_FRAMESIZE_RAW, SEEK_SET))
+ goto fail_io;
if (fread(subbuffer, 1, SUB_FRAMESIZE, f) != SUB_FRAMESIZE)
goto fail_io;
- if (subChanRaw) DecodeRawSubData();
- goto done;
+ return SUB_FRAMESIZE;
fail_io:
-#ifndef NDEBUG
- SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
-#endif
-
-done:
- return ret;
+ SysPrintf("subchannel: file IO error %d, sector %u\n", errno, sector);
+ return -1;
}
static int uncompress2_pcsx(void *out, unsigned long *out_size, void *in, unsigned long in_size)
{
int hunk;
- if (base)
- sector += base;
+ sector += base;
hunk = sector / chd_img->sectors_per_hunk;
chd_img->sector_in_hunk = sector % chd_img->sectors_per_hunk;
if (dest != cdbuffer) // copy avoid HACK
memcpy(dest, chd_img->buffer[chd_img->sector_in_hunk],
CD_FRAMESIZE_RAW);
- if (subChanMixed) {
- memcpy(subbuffer, chd_img->buffer[chd_img->sector_in_hunk] + CD_FRAMESIZE_RAW,
- SUB_FRAMESIZE);
- if (subChanRaw)
- DecodeRawSubData();
- }
return CD_FRAMESIZE_RAW;
}
+
+static int cdread_sub_chd(FILE *f, int sector)
+{
+ int hunk;
+
+ if (!subChanMixed)
+ return -1;
+
+ hunk = sector / chd_img->sectors_per_hunk;
+ chd_img->sector_in_hunk = sector % chd_img->sectors_per_hunk;
+
+ if (hunk != chd_img->current_hunk)
+ {
+ chd_read(chd_img->chd, hunk, chd_img->buffer);
+ chd_img->current_hunk = hunk;
+ }
+
+ memcpy(subbuffer, chd_img->buffer[chd_img->sector_in_hunk] + CD_FRAMESIZE_RAW, SUB_FRAMESIZE);
+ return SUB_FRAMESIZE;
+}
#endif
static int cdread_2048(FILE *f, unsigned int base, void *dest, int sector)
CDR_getBuffer = ISOgetBuffer;
cdimg_read_func = cdread_normal;
+ cdimg_read_sub_func = NULL;
if (parsetoc(GetIsoFile()) == 0) {
strcat(image_str, "[+toc]");
strcat(image_str, "[+chd]");
CDR_getBuffer = ISOgetBuffer_chd;
cdimg_read_func = cdread_chd;
+ cdimg_read_sub_func = cdread_sub_chd;
is_chd = 1;
}
#endif
PrintTracks();
- if (subChanMixed && !is_chd)
+ if (subChanMixed && !is_chd) {
cdimg_read_func = cdread_sub_mixed;
- else if (isMode1ISO)
+ cdimg_read_sub_func = cdread_sub_sub_mixed;
+ }
+ else if (isMode1ISO) {
cdimg_read_func = cdread_2048;
+ cdimg_read_sub_func = NULL;
+ }
// make sure we have another handle open for cdda
if (numtracks > 1 && ti[1].handle == NULL) {
return 0;
}
- if (pregapOffset) {
- subChanMissing = FALSE;
- if (sector >= pregapOffset) {
- sector -= 2 * 75;
- if (sector < pregapOffset)
- subChanMissing = TRUE;
- }
- }
+ if (pregapOffset && sector >= pregapOffset)
+ sector -= 2 * 75;
ret = cdimg_read_func(cdHandle, 0, cdbuffer, sector);
if (ret < 12*2 + 2048)
return 0;
- if (subHandle != NULL) {
- fseek(subHandle, sector * SUB_FRAMESIZE, SEEK_SET);
- if (fread(subbuffer, 1, SUB_FRAMESIZE, subHandle) != SUB_FRAMESIZE)
- /* Faulty subchannel data shouldn't cause a read failure */
- return 1;
-
- if (subChanRaw) DecodeRawSubData();
- }
-
return 1;
}
}
// gets subchannel data
-static unsigned char* CALLBACK ISOgetBufferSub(void) {
- if ((subHandle != NULL || subChanMixed) && !subChanMissing) {
- return subbuffer;
+static unsigned char* CALLBACK ISOgetBufferSub(int sector) {
+ if (pregapOffset && sector >= pregapOffset) {
+ sector -= 2 * 75;
+ if (sector < pregapOffset) // ?
+ return NULL;
}
- return NULL;
+ if (cdimg_read_sub_func != NULL) {
+ if (cdimg_read_sub_func(cdHandle, sector) != SUB_FRAMESIZE)
+ return NULL;
+ }
+ else if (subHandle != NULL) {
+ if (fseek(subHandle, sector * SUB_FRAMESIZE, SEEK_SET))
+ return NULL;
+ if (fread(subbuffer, 1, SUB_FRAMESIZE, subHandle) != SUB_FRAMESIZE)
+ return NULL;
+ }
+ else {
+ return NULL;
+ }
+
+ if (subChanRaw) DecodeRawSubData();
+ return subbuffer;
}
static long CALLBACK ISOgetStatus(struct CdrStat *stat) {
* Handles all CD-ROM registers and functions.
*/
+#include <assert.h>
#include "cdrom.h"
#include "ppf.h"
#include "psxdma.h"
unsigned char ResultP;
unsigned char ResultReady;
unsigned char Cmd;
- unsigned char unused4;
+ unsigned char SubqForwardSectors;
unsigned char SetlocPending;
u32 Reading;
#define cdReadTime (PSXCLK / 75)
#define LOCL_INVALID 0xff
+#define SUBQ_FORWARD_SECTORS 2u
enum drive_state {
DRIVESTATE_STANDBY = 0, // pause, play, read
cdr.subq.Absolute[2] = itob(time[2]);
}
-static int ReadTrack(const u8 *time) {
+static int ReadTrack(const u8 *time)
+{
unsigned char tmp[3];
- struct SubQ *subq;
int read_ok;
- u16 crc;
tmp[0] = itob(time[0]);
tmp[1] = itob(time[1]);
read_ok = CDR_readTrack(tmp);
if (read_ok)
memcpy(cdr.Prev, tmp, 3);
+ return read_ok;
+}
+
+static void UpdateSubq(const u8 *time)
+{
+ const struct SubQ *subq;
+ u16 crc;
if (CheckSBI(time))
- return read_ok;
+ return;
- subq = (struct SubQ *)CDR_getBufferSub();
+ subq = (struct SubQ *)CDR_getBufferSub(MSF2SECT(time[0], time[1], time[2]));
if (subq != NULL && cdr.CurTrack == 1) {
crc = calcCrc((u8 *)subq + 12, 10);
if (crc == (((u16)subq->CRC[0] << 8) | subq->CRC[1])) {
memcpy(cdr.subq.Absolute, subq->AbsoluteAddress, 3);
}
else {
- CDR_LOG_I("subq bad crc @%02x:%02x:%02x\n",
- tmp[0], tmp[1], tmp[2]);
+ CDR_LOG_I("subq bad crc @%02d:%02d:%02d\n",
+ time[0], time[1], time[2]);
}
}
else {
cdr.subq.Track, cdr.subq.Index,
cdr.subq.Relative[0], cdr.subq.Relative[1], cdr.subq.Relative[2],
cdr.subq.Absolute[0], cdr.subq.Absolute[1], cdr.subq.Absolute[2]);
-
- return read_ok;
}
static void cdrPlayInterrupt_Autopause()
static void cdrPrepCdda(s16 *buf, int samples);
static void cdrAttenuate(s16 *buf, int samples, int stereo);
+static void msfiAdd(u8 *msfi, u32 count)
+{
+ assert(count < 75);
+ msfi[2] += count;
+ if (msfi[2] >= 75) {
+ msfi[2] -= 75;
+ msfi[1]++;
+ if (msfi[1] == 60) {
+ msfi[1] = 0;
+ msfi[0]++;
+ }
+ }
+}
+
void cdrPlayReadInterrupt(void)
{
if (cdr.Reading) {
cdr.FirstSector = 0;
}
- cdr.SetSectorPlay[2]++;
- if (cdr.SetSectorPlay[2] == 75) {
- cdr.SetSectorPlay[2] = 0;
- cdr.SetSectorPlay[1]++;
- if (cdr.SetSectorPlay[1] == 60) {
- cdr.SetSectorPlay[1] = 0;
- cdr.SetSectorPlay[0]++;
- }
- }
+ msfiAdd(cdr.SetSectorPlay, 1);
// update for CdlGetlocP/autopause
generate_subq(cdr.SetSectorPlay);
- plays tracks without retry play
*/
Find_CurTrack(cdr.SetSectorPlay);
- ReadTrack(cdr.SetSectorPlay);
+ generate_subq(cdr.SetSectorPlay);
cdr.LocL[0] = LOCL_INVALID;
+ cdr.SubqForwardSectors = 1;
cdr.TrackChanged = FALSE;
cdr.FirstSector = 1;
read_ok = ReadTrack(cdr.SetSectorPlay);
if (read_ok && (buf = CDR_getBuffer()))
memcpy(cdr.LocL, buf, 8);
+ UpdateSubq(cdr.SetSectorPlay);
cdr.TrackChanged = FALSE;
break;
// Fighting Force 2 - update subq time immediately
// - fixes new game
- ReadTrack(cdr.SetSectorPlay);
+ UpdateSubq(cdr.SetSectorPlay);
cdr.LocL[0] = LOCL_INVALID;
+ cdr.SubqForwardSectors = 1;
cycles = (cdr.Mode & 0x80) ? cdReadTime : cdReadTime * 2;
cycles += seekTime;
static void cdrReadInterrupt(void)
{
u8 *buf = NULL, *hdr;
+ u8 subqPos[3];
int read_ok;
SetPlaySeekRead(cdr.StatP, STATUS_READ | STATUS_ROTATING);
+ memcpy(subqPos, cdr.SetSectorPlay, sizeof(subqPos));
+ msfiAdd(subqPos, cdr.SubqForwardSectors);
+ UpdateSubq(subqPos);
+ if (cdr.SubqForwardSectors < SUBQ_FORWARD_SECTORS) {
+ cdr.SubqForwardSectors++;
+ CDRPLAYREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime, 0);
+ return;
+ }
+
read_ok = ReadTrack(cdr.SetSectorPlay);
if (read_ok)
buf = CDR_getBuffer();
if (!(cdr.Mode & MODE_STRSND) || !(buf[4+2] & 0x4))
cdrReadInterruptSetResult(cdr.StatP);
- cdr.SetSectorPlay[2]++;
- if (cdr.SetSectorPlay[2] == 75) {
- cdr.SetSectorPlay[2] = 0;
- cdr.SetSectorPlay[1]++;
- if (cdr.SetSectorPlay[1] == 60) {
- cdr.SetSectorPlay[1] = 0;
- cdr.SetSectorPlay[0]++;
- }
- }
-
- if (!cdr.Irq1Pending) {
- // update for CdlGetlocP
- ReadTrack(cdr.SetSectorPlay);
- }
+ msfiAdd(cdr.SetSectorPlay, 1);
CDRPLAYREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime, 0);
}
cdr.FifoOffset = tmp < DATA_SIZE ? tmp : DATA_SIZE;
cdr.FifoSize = (cdr.Mode & 0x20) ? 2340 : 2048 + 12;
+ if (cdr.SubqForwardSectors > SUBQ_FORWARD_SECTORS)
+ cdr.SubqForwardSectors = SUBQ_FORWARD_SECTORS;
// read right sub data
tmpp[0] = btoi(cdr.Prev[0]);