From: notaz Date: Wed, 2 Oct 2024 23:56:07 +0000 (+0300) Subject: new async cdrom + cdrom cleanup X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=de499a35956351db03148534c2a4e4bc94215ec4;p=pcsx_rearmed.git new async cdrom + cdrom cleanup Should've split this really, but that's lots of extra work... Beware of breakage, but please report bugs. --- diff --git a/Makefile b/Makefile index d1da30b6..f327cbbf 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,8 @@ CFLAGS += -DPCNT endif # core -OBJS += libpcsxcore/cdriso.o libpcsxcore/cdrom.o libpcsxcore/cheat.o libpcsxcore/database.o \ +OBJS += libpcsxcore/cdriso.o libpcsxcore/cdrom.o libpcsxcore/cdrom-async.o \ + libpcsxcore/cheat.o libpcsxcore/database.o \ libpcsxcore/decode_xa.o libpcsxcore/mdec.o \ libpcsxcore/misc.o libpcsxcore/plugins.o libpcsxcore/ppf.o libpcsxcore/psxbios.o \ libpcsxcore/psxcommon.o libpcsxcore/psxcounters.o libpcsxcore/psxdma.o \ @@ -250,9 +251,6 @@ plugins/gpu_unai/gpulib_if.o: CFLAGS += -DREARMED -O3 CC_LINK = $(CXX) endif -# cdrcimg -OBJS += plugins/cdrcimg/cdrcimg.o - # libchdr ifeq "$(HAVE_CHD)" "1" LCHDR = deps/libchdr @@ -361,10 +359,13 @@ ifeq "$(HAVE_PHYSICAL_CDROM)" "1" OBJS += frontend/libretro-cdrom.o OBJS += deps/libretro-common/lists/string_list.o OBJS += deps/libretro-common/memmap/memalign.o -OBJS += deps/libretro-common/rthreads/rthreads.o OBJS += deps/libretro-common/vfs/vfs_implementation_cdrom.o CFLAGS += -DHAVE_CDROM endif +ifeq "$(USE_ASYNC_CDROM)" "1" +OBJS += frontend/libretro-rthreads.o +CFLAGS += -DUSE_ASYNC_CDROM +endif ifeq "$(USE_LIBRETRO_VFS)" "1" OBJS += deps/libretro-common/compat/compat_posix_string.o OBJS += deps/libretro-common/compat/fopen_utf8.o diff --git a/Makefile.libretro b/Makefile.libretro index 743d9fce..cf976ba0 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -4,6 +4,7 @@ DEBUG ?= 0 WANT_ZLIB ?= 1 HAVE_CHD ?= 1 HAVE_PHYSICAL_CDROM ?= 1 +USE_ASYNC_CDROM ?= 1 USE_LIBRETRO_VFS ?= 0 # Dynarec options: lightrec, ari64 diff --git a/frontend/libretro-rthreads.c b/frontend/libretro-rthreads.c new file mode 100644 index 00000000..96c861d3 --- /dev/null +++ b/frontend/libretro-rthreads.c @@ -0,0 +1,9 @@ +// temporary(?) workaround: +// https://github.com/libretro/libretro-common/pull/216 +#ifdef _3DS +#include <3ds/svc.h> +#include <3ds/services/apt.h> +#include +#endif + +#include "../deps/libretro-common/rthreads/rthreads.c" diff --git a/frontend/libretro.c b/frontend/libretro.c index 52c2c1c9..b5c3b92d 100644 --- a/frontend/libretro.c +++ b/frontend/libretro.c @@ -26,6 +26,7 @@ #include "../libpcsxcore/psxmem_map.h" #include "../libpcsxcore/new_dynarec/new_dynarec.h" #include "../libpcsxcore/cdrom.h" +#include "../libpcsxcore/cdrom-async.h" #include "../libpcsxcore/cdriso.h" #include "../libpcsxcore/cheat.h" #include "../libpcsxcore/r3000a.h" @@ -1315,12 +1316,6 @@ static void disk_init(void) } } -#ifdef HAVE_CDROM -static long CALLBACK rcdrom_open(void); -static long CALLBACK rcdrom_close(void); -static void rcdrom_stop_thread(void); -#endif - static bool disk_set_eject_state(bool ejected) { if (ejected != disk_ejected) @@ -1331,12 +1326,12 @@ static bool disk_set_eject_state(bool ejected) LidInterrupt(); #ifdef HAVE_CDROM - if (CDR_open == rcdrom_open && ejected != disk_ejected) { - rcdrom_stop_thread(); + if (cdra_is_physical() && ejected != disk_ejected) { + cdra_stop_thread(); if (!ejected) { // likely the real cd was also changed - rescan - rcdrom_close(); - rcdrom_open(); + cdra_close(); + cdra_open(); } } #endif @@ -1366,7 +1361,7 @@ static bool disk_set_image_index(unsigned int index) if (disks[index].fname == NULL) { LogErr("missing disk #%u\n", index); - CDR_shutdown(); + cdra_shutdown(); // RetroArch specifies "no disk" with index == count, // so don't fail here.. @@ -1384,7 +1379,7 @@ static bool disk_set_image_index(unsigned int index) LogErr("failed to load cdr plugin\n"); return false; } - if (CDR_open() < 0) + if (cdra_open() < 0) { LogErr("failed to open cdr plugin\n"); return false; @@ -1593,308 +1588,6 @@ static void extract_directory(char *buf, const char *path, size_t size) } } -// raw cdrom support -#ifdef HAVE_CDROM -#include "vfs/vfs_implementation.h" -#include "vfs/vfs_implementation_cdrom.h" -#include "libretro-cdrom.h" -#include "rthreads/rthreads.h" -#include "retro_timers.h" -struct cached_buf { - unsigned char buf[2352]; - unsigned int lba; -}; -static struct { - libretro_vfs_implementation_file *h; - sthread_t *thread; - slock_t *read_lock; - slock_t *buf_lock; - scond_t *cond; - struct cached_buf *buf; - unsigned int buf_cnt, thread_exit, do_prefetch; - unsigned int total_lba, prefetch_lba; - int check_eject_delay; -} rcdrom; - -static void lbacache_do(unsigned int lba) -{ - unsigned char m, s, f, buf[2352]; - unsigned int i = lba % rcdrom.buf_cnt; - int ret; - - cdrom_lba_to_msf(lba + 150, &m, &s, &f); - slock_lock(rcdrom.read_lock); - ret = cdrom_read_sector(rcdrom.h, lba, buf); - slock_lock(rcdrom.buf_lock); - slock_unlock(rcdrom.read_lock); - //printf("%d:%02d:%02d m%d f%d\n", m, s, f, buf[12+3], ((buf[12+4+2] >> 5) & 1) + 1); - if (ret) { - rcdrom.do_prefetch = 0; - slock_unlock(rcdrom.buf_lock); - LogErr("prefetch: cdrom_read_sector failed for lba %d\n", lba); - return; - } - rcdrom.check_eject_delay = 100; - - if (lba != rcdrom.buf[i].lba) { - memcpy(rcdrom.buf[i].buf, buf, sizeof(rcdrom.buf[i].buf)); - rcdrom.buf[i].lba = lba; - } - slock_unlock(rcdrom.buf_lock); - retro_sleep(0); // why does the main thread stall without this? -} - -static int lbacache_get(unsigned int lba, void *buf) -{ - unsigned int i; - int ret = 0; - - i = lba % rcdrom.buf_cnt; - slock_lock(rcdrom.buf_lock); - if (lba == rcdrom.buf[i].lba) { - memcpy(buf, rcdrom.buf[i].buf, 2352); - ret = 1; - } - slock_unlock(rcdrom.buf_lock); - return ret; -} - -static void rcdrom_prefetch_thread(void *unused) -{ - unsigned int buf_cnt, lba, lba_to; - - slock_lock(rcdrom.buf_lock); - while (!rcdrom.thread_exit) - { -#ifdef __GNUC__ - __asm__ __volatile__("":::"memory"); // barrier -#endif - if (!rcdrom.do_prefetch) - scond_wait(rcdrom.cond, rcdrom.buf_lock); - if (!rcdrom.do_prefetch || !rcdrom.h || rcdrom.thread_exit) - continue; - - buf_cnt = rcdrom.buf_cnt; - lba = rcdrom.prefetch_lba; - lba_to = lba + buf_cnt; - if (lba_to > rcdrom.total_lba) - lba_to = rcdrom.total_lba; - for (; lba < lba_to; lba++) { - if (lba != rcdrom.buf[lba % buf_cnt].lba) - break; - } - if (lba == lba_to) { - // caching complete - rcdrom.do_prefetch = 0; - continue; - } - - slock_unlock(rcdrom.buf_lock); - lbacache_do(lba); - slock_lock(rcdrom.buf_lock); - } - slock_unlock(rcdrom.buf_lock); -} - -static void rcdrom_stop_thread(void) -{ - rcdrom.thread_exit = 1; - if (rcdrom.buf_lock) { - slock_lock(rcdrom.buf_lock); - rcdrom.do_prefetch = 0; - if (rcdrom.cond) - scond_signal(rcdrom.cond); - slock_unlock(rcdrom.buf_lock); - } - if (rcdrom.thread) { - sthread_join(rcdrom.thread); - rcdrom.thread = NULL; - } - if (rcdrom.cond) { scond_free(rcdrom.cond); rcdrom.cond = NULL; } - if (rcdrom.buf_lock) { slock_free(rcdrom.buf_lock); rcdrom.buf_lock = NULL; } - if (rcdrom.read_lock) { slock_free(rcdrom.read_lock); rcdrom.read_lock = NULL; } - free(rcdrom.buf); - rcdrom.buf = NULL; -} - -// the thread is optional, if anything fails we can do direct reads -static void rcdrom_start_thread(void) -{ - rcdrom_stop_thread(); - rcdrom.thread_exit = rcdrom.prefetch_lba = rcdrom.do_prefetch = 0; - if (rcdrom.buf_cnt == 0) - return; - rcdrom.buf = calloc(rcdrom.buf_cnt, sizeof(rcdrom.buf[0])); - rcdrom.buf_lock = slock_new(); - rcdrom.read_lock = slock_new(); - rcdrom.cond = scond_new(); - if (rcdrom.buf && rcdrom.buf_lock && rcdrom.read_lock && rcdrom.cond) { - rcdrom.thread = sthread_create(rcdrom_prefetch_thread, NULL); - rcdrom.buf[0].lba = ~0; - } - if (!rcdrom.thread) { - LogErr("cdrom precache thread init failed.\n"); - rcdrom_stop_thread(); - } -} - -static long CALLBACK rcdrom_open(void) -{ - const char *name = GetIsoFile(); - //printf("%s %s\n", __func__, name); - rcdrom.h = retro_vfs_file_open_impl(name, RETRO_VFS_FILE_ACCESS_READ, - RETRO_VFS_FILE_ACCESS_HINT_NONE); - if (rcdrom.h) { - int ret = cdrom_set_read_speed_x(rcdrom.h, 4); - if (ret) LogErr("CD speed set failed\n"); - const cdrom_toc_t *toc = retro_vfs_file_get_cdrom_toc(); - const cdrom_track_t *last = &toc->track[toc->num_tracks - 1]; - unsigned int lba = cdrom_msf_to_lba(last->min, last->sec, last->frame) - 150; - rcdrom.total_lba = lba + last->track_size; - //cdrom_get_current_config_random_readable(rcdrom.h); - //cdrom_get_current_config_multiread(rcdrom.h); - //cdrom_get_current_config_cdread(rcdrom.h); - //cdrom_get_current_config_profiles(rcdrom.h); - rcdrom_start_thread(); - return 0; - } - LogErr("retro_vfs_file_open failed for '%s'\n", name); - return -1; -} - -static long CALLBACK rcdrom_close(void) -{ - //printf("%s\n", __func__); - if (rcdrom.h) { - rcdrom_stop_thread(); - retro_vfs_file_close_impl(rcdrom.h); - rcdrom.h = NULL; - } - return 0; -} - -static long CALLBACK rcdrom_getTN(unsigned char *tn) -{ - const cdrom_toc_t *toc = retro_vfs_file_get_cdrom_toc(); - tn[0] = 1; - tn[1] = toc->num_tracks; - //printf("%s -> %d %d\n", __func__, tn[0], tn[1]); - return 0; -} - -static long CALLBACK rcdrom_getTD(unsigned char track, unsigned char *rt) -{ - const cdrom_toc_t *toc = retro_vfs_file_get_cdrom_toc(); - rt[0] = 0, rt[1] = 2, rt[2] = 0; - if (track == 0) { - cdrom_lba_to_msf(rcdrom.total_lba + 150, &rt[2], &rt[1], &rt[0]); - } - else if (track <= toc->num_tracks) { - int i = track - 1; - rt[2] = toc->track[i].min; - rt[1] = toc->track[i].sec; - rt[0] = toc->track[i].frame; - } - //printf("%s %d -> %d:%02d:%02d\n", __func__, track, rt[2], rt[1], rt[0]); - return 0; -} - -static long CALLBACK rcdrom_prefetch(unsigned char m, unsigned char s, unsigned char f) -{ - unsigned int lba = cdrom_msf_to_lba(m, s, f) - 150; - if (rcdrom.cond && rcdrom.h) { - rcdrom.prefetch_lba = lba; - rcdrom.do_prefetch = 1; - scond_signal(rcdrom.cond); - } - if (rcdrom.buf) { - unsigned int c = rcdrom.buf_cnt; - if (c) - return rcdrom.buf[lba % c].lba == lba; - } - return 1; -} - -static int rcdrom_read_msf(unsigned char m, unsigned char s, unsigned char f, - void *buf, const char *func) -{ - unsigned int lba = cdrom_msf_to_lba(m, s, f) - 150; - int hit = 0, ret = -1; - if (rcdrom.buf_lock) - hit = lbacache_get(lba, buf); - if (!hit && rcdrom.read_lock) { - // maybe still prefetching - slock_lock(rcdrom.read_lock); - slock_unlock(rcdrom.read_lock); - hit = lbacache_get(lba, buf); - if (hit) - hit = 2; - } - if (!hit) { - slock_t *lock = rcdrom.read_lock; - rcdrom.do_prefetch = 0; - if (lock) - slock_lock(lock); - if (rcdrom.h) { - ret = cdrom_read_sector(rcdrom.h, lba, buf); - if (ret) - LogErr("cdrom_read_sector failed for lba %d\n", lba); - } - if (lock) - slock_unlock(lock); - } - else - ret = 0; - rcdrom.check_eject_delay = ret ? 0 : 100; - //printf("%s %d:%02d:%02d -> %d hit %d\n", func, m, s, f, ret, hit); - return ret; -} - -static boolean CALLBACK rcdrom_readTrack(unsigned char *time) -{ - unsigned char m = btoi(time[0]), s = btoi(time[1]), f = btoi(time[2]); - return !rcdrom_read_msf(m, s, f, ISOgetBuffer() - 12, __func__); -} - -static long CALLBACK rcdrom_readCDDA(unsigned char m, unsigned char s, unsigned char f, - unsigned char *buffer) -{ - return rcdrom_read_msf(m, s, f, buffer, __func__); -} - -static unsigned char * CALLBACK rcdrom_getBuffer(void) -{ - //printf("%s\n", __func__); - return ISOgetBuffer(); -} - -static unsigned char * CALLBACK rcdrom_getBufferSub(int sector) -{ - //printf("%s %d %d\n", __func__, sector, rcdrom_h->cdrom.last_frame_lba); - return NULL; -} - -static long CALLBACK rcdrom_getStatus(struct CdrStat *stat) -{ - const cdrom_toc_t *toc = retro_vfs_file_get_cdrom_toc(); - //printf("%s %p\n", __func__, stat); - CDR__getStatus(stat); - stat->Type = toc->track[0].audio ? 2 : 1; - return 0; -} - -static void rcdrom_check_eject(void) -{ - bool media_inserted; - if (!rcdrom.h || rcdrom.do_prefetch || rcdrom.check_eject_delay-- > 0) - return; - rcdrom.check_eject_delay = 100; - media_inserted = cdrom_is_media_inserted(rcdrom.h); // 1-2ms - if (!media_inserted != disk_ejected) - disk_set_eject_state(!media_inserted); -} -#endif // HAVE_CDROM - #if defined(__QNX__) || defined(_WIN32) /* Blackberry QNX doesn't have strcasestr */ @@ -2147,18 +1840,7 @@ bool retro_load_game(const struct retro_game_info *info) } if (!strncmp(info->path, "cdrom:", 6)) { -#ifdef HAVE_CDROM - CDR_open = rcdrom_open; - CDR_close = rcdrom_close; - CDR_getTN = rcdrom_getTN; - CDR_getTD = rcdrom_getTD; - CDR_readTrack = rcdrom_readTrack; - CDR_getBuffer = rcdrom_getBuffer; - CDR_getBufferSub = rcdrom_getBufferSub; - CDR_getStatus = rcdrom_getStatus; - CDR_readCDDA = rcdrom_readCDDA; - CDR_prefetch = rcdrom_prefetch; -#elif !defined(USE_LIBRETRO_VFS) +#if !defined(HAVE_CDROM) && !defined(USE_LIBRETRO_VFS) ReleasePlugins(); LogErr("%s\n", "Physical CD-ROM support is not compiled in."); show_notification("Physical CD-ROM support is not compiled in.", 6000, 3); @@ -2233,7 +1915,7 @@ bool retro_load_game(const struct retro_game_info *info) LogErr("failed to reload cdr plugins\n"); return false; } - if (CDR_open() < 0) + if (cdra_open() < 0) { LogErr("failed to open cdr plugin\n"); return false; @@ -2567,23 +2249,12 @@ static void update_variables(bool in_flight) Config.TurboCD = false; } -#ifdef HAVE_CDROM +#if defined(HAVE_CDROM) || defined(USE_ASYNC_CDROM) var.value = NULL; - var.key = "pcsx_rearmed_phys_cd_readahead"; + var.key = "pcsx_rearmed_cd_readahead"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { - long newval = strtol(var.value, NULL, 10); - bool changed = rcdrom.buf_cnt != newval; - if (rcdrom.h && changed) - rcdrom_stop_thread(); - rcdrom.buf_cnt = newval; - if (rcdrom.h && changed) { - rcdrom_start_thread(); - if (rcdrom.cond && rcdrom.prefetch_lba) { - rcdrom.do_prefetch = 1; - scond_signal(rcdrom.cond); - } - } + cdra_set_buf_count(strtol(var.value, NULL, 10)); } #endif @@ -3585,8 +3256,12 @@ void retro_run(void) vout_fb_dirty = 0; #ifdef HAVE_CDROM - if (CDR_open == rcdrom_open) - rcdrom_check_eject(); + int inserted; + if (cdra_check_eject(&inserted) > 0) { + bool media_inserted = inserted != 0; + if (!media_inserted != disk_ejected) + disk_set_eject_state(!media_inserted); + } #endif } diff --git a/frontend/libretro_core_options.h b/frontend/libretro_core_options.h index 47a3ed4e..86fe7834 100644 --- a/frontend/libretro_core_options.h +++ b/frontend/libretro_core_options.h @@ -180,19 +180,29 @@ struct retro_core_option_v2_definition option_defs_us[] = { "sync", }, #endif -#ifdef HAVE_CDROM +#if defined(HAVE_CDROM) || defined(USE_ASYNC_CDROM) #define V(x) { #x, NULL } { - "pcsx_rearmed_phys_cd_readahead", - "Physical CD read-ahead", + "pcsx_rearmed_cd_readahead", + "CD read-ahead", NULL, - "(Hardware CD-ROM only) Reads the specified amount of sectors ahead of time to try to avoid later stalls. 333000 will try to read the complete disk (requires an additional 750MB of RAM).", + "Reads the specified amount of sectors ahead of time to try to avoid later stalls. " +#ifdef HAVE_CDROM + "Affects both physical CD-ROM and CD images. " +#endif +#if !defined(_3DS) && !defined(VITA) + "333000 will try to read the complete disk (requires an additional 750MB of RAM)." +#endif + , NULL, "system", { V(0), V(1), V(2), V(3), V(4), V(5), V(6), V(7), V(8), V(9), V(10), V(11), V(12), V(13), V(14), V(15), - V(16), V(32), V(64), V(128), V(256), V(512), V(1024), V(333000), + V(16), V(32), V(64), V(128), V(256), V(512), V(1024), +#if !defined(_3DS) && !defined(VITA) + V(333000), +#endif { NULL, NULL}, }, "12", diff --git a/frontend/main.c b/frontend/main.c index 4c051e2c..61dbf637 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -25,6 +25,7 @@ #include "../libpcsxcore/cheat.h" #include "../libpcsxcore/sio.h" #include "../libpcsxcore/database.h" +#include "../libpcsxcore/cdrom-async.h" #include "../libpcsxcore/new_dynarec/new_dynarec.h" #include "../plugins/cdrcimg/cdrcimg.h" #include "../plugins/dfsound/spu_config.h" @@ -66,7 +67,7 @@ enum sched_action emu_action, emu_action_old; char hud_msg[64]; int hud_new_msg; -static void make_path(char *buf, size_t size, const char *dir, const char *fname) +static inline void make_path(char *buf, size_t size, const char *dir, const char *fname) { if (fname) snprintf(buf, size, ".%s%s", dir, fname); @@ -95,21 +96,7 @@ static int get_gameid_filename(char *buf, int size, const char *fmt, int i) { void set_cd_image(const char *fname) { - const char *ext = NULL; - - if (fname != NULL) - ext = strrchr(fname, '.'); - - if (ext && ( - strcasecmp(ext, ".z") == 0 || strcasecmp(ext, ".bz") == 0 || - strcasecmp(ext, ".znx") == 0 /*|| strcasecmp(ext, ".pbp") == 0*/)) { - SetIsoFile(NULL); - cdrcimg_set_fname(fname); - strcpy(Config.Cdr, "builtin_cdrcimg"); - } else { - SetIsoFile(fname); - strcpy(Config.Cdr, "builtin_cdr"); - } + SetIsoFile(fname); } static void set_default_paths(void) @@ -124,7 +111,6 @@ static void set_default_paths(void) strcpy(Config.PluginsDir, "plugins"); strcpy(Config.Gpu, "builtin_gpu"); strcpy(Config.Spu, "builtin_spu"); - strcpy(Config.Cdr, "builtin_cdr"); strcpy(Config.Pad1, "builtin_pad"); strcpy(Config.Pad2, "builtin_pad"); strcpy(Config.Net, "Disabled"); @@ -819,9 +805,6 @@ void SysReset() { // reset can run code, timing must be set pl_timing_prepare(Config.PsxType); - // hmh core forgets this - CDR_stop(); - EmuReset(); GPU_updateLace = real_lace; @@ -946,7 +929,7 @@ static int _OpenPlugins(void) { signal(SIGPIPE, SignalExit); #endif - ret = CDR_open(); + ret = cdra_open(); if (ret < 0) { SysMessage(_("Error opening CD-ROM plugin!")); return -1; } ret = SPU_open(); if (ret < 0) { SysMessage(_("Error opening SPU plugin!")); return -1; } @@ -960,64 +943,6 @@ static int _OpenPlugins(void) { ret = PAD2_open(&gpuDisp); if (ret < 0) { SysMessage(_("Error opening Controller 2 plugin!")); return -1; } - if (Config.UseNet && !NetOpened) { - netInfo info; - char path[MAXPATHLEN * 2]; - char dotdir[MAXPATHLEN]; - - MAKE_PATH(dotdir, "/.pcsx/plugins/", NULL); - - strcpy(info.EmuName, "PCSX"); - memcpy(info.CdromID, CdromId, 9); /* no \0 trailing character? */ - memcpy(info.CdromLabel, CdromLabel, 9); - info.CdromLabel[9] = '\0'; - info.psxMem = psxM; - info.GPU_showScreenPic = GPU_showScreenPic; - info.GPU_displayText = GPU_displayText; - info.GPU_showScreenPic = GPU_showScreenPic; - info.PAD_setSensitive = PAD1_setSensitive; - sprintf(path, "%s%s", Config.BiosDir, Config.Bios); - strcpy(info.BIOSpath, path); - strcpy(info.MCD1path, Config.Mcd1); - strcpy(info.MCD2path, Config.Mcd2); - sprintf(path, "%s%s", dotdir, Config.Gpu); - strcpy(info.GPUpath, path); - sprintf(path, "%s%s", dotdir, Config.Spu); - strcpy(info.SPUpath, path); - sprintf(path, "%s%s", dotdir, Config.Cdr); - strcpy(info.CDRpath, path); - NET_setInfo(&info); - - ret = NET_open(&gpuDisp); - if (ret < 0) { - if (ret == -2) { - // -2 is returned when something in the info - // changed and needs to be synced - char *ptr; - - PARSEPATH(Config.Bios, info.BIOSpath); - PARSEPATH(Config.Gpu, info.GPUpath); - PARSEPATH(Config.Spu, info.SPUpath); - PARSEPATH(Config.Cdr, info.CDRpath); - - strcpy(Config.Mcd1, info.MCD1path); - strcpy(Config.Mcd2, info.MCD2path); - return -2; - } else { - Config.UseNet = FALSE; - } - } else { - if (NET_queryPlayer() == 1) { - if (SendPcsxInfo() == -1) Config.UseNet = FALSE; - } else { - if (RecvPcsxInfo() == -1) Config.UseNet = FALSE; - } - } - NetOpened = TRUE; - } else if (Config.UseNet) { - NET_resume(); - } - return 0; } @@ -1040,32 +965,25 @@ void ClosePlugins() { signal(SIGPIPE, SIG_DFL); #endif - ret = CDR_close(); - if (ret < 0) { SysMessage(_("Error closing CD-ROM plugin!")); return; } + cdra_close(); ret = SPU_close(); - if (ret < 0) { SysMessage(_("Error closing SPU plugin!")); return; } + if (ret < 0) { SysMessage(_("Error closing SPU plugin!")); } ret = PAD1_close(); - if (ret < 0) { SysMessage(_("Error closing Controller 1 Plugin!")); return; } + if (ret < 0) { SysMessage(_("Error closing Controller 1 Plugin!")); } ret = PAD2_close(); - if (ret < 0) { SysMessage(_("Error closing Controller 2 plugin!")); return; } + if (ret < 0) { SysMessage(_("Error closing Controller 2 plugin!")); } // pcsx-rearmed: we handle gpu elsewhere //ret = GPU_close(); //if (ret < 0) { SysMessage(_("Error closing GPU plugin!")); return; } - - if (Config.UseNet) { - NET_pause(); - } } /* we hook statically linked plugins here */ static const char *builtin_plugins[] = { - "builtin_gpu", "builtin_spu", "builtin_cdr", "builtin_pad", - "builtin_cdrcimg", + "builtin_gpu", "builtin_spu", "builtin_pad", }; static const int builtin_plugin_ids[] = { - PLUGIN_GPU, PLUGIN_SPU, PLUGIN_CDR, PLUGIN_PAD, - PLUGIN_CDRCIMG, + PLUGIN_GPU, PLUGIN_SPU, PLUGIN_PAD, }; void *SysLoadLibrary(const char *lib) { diff --git a/frontend/menu.c b/frontend/menu.c index 15034a90..275028c5 100644 --- a/frontend/menu.c +++ b/frontend/menu.c @@ -38,6 +38,7 @@ #include "libpicofe/plat.h" #include "../libpcsxcore/misc.h" #include "../libpcsxcore/cdrom.h" +#include "../libpcsxcore/cdrom-async.h" #include "../libpcsxcore/cdriso.h" #include "../libpcsxcore/cheat.h" #include "../libpcsxcore/ppf.h" @@ -2285,7 +2286,7 @@ static int swap_cd_image(void) menu_update_msg("failed to load cdr plugin"); return -1; } - if (CDR_open() < 0) { + if (cdra_open() < 0) { menu_update_msg("failed to open cdr plugin"); return -1; } @@ -2303,8 +2304,8 @@ static int swap_cd_multidisk(void) CdromId[0] = '\0'; CdromLabel[0] = '\0'; - CDR_close(); - if (CDR_open() < 0) { + cdra_close(); + if (cdra_open() < 0) { menu_update_msg("failed to open cdr plugin"); return -1; } @@ -2759,11 +2760,6 @@ void menu_prepare_emu(void) menu_sync_config(); psxCpu->ApplyConfig(); - // core doesn't care about Config.Cdda changes, - // so handle them manually here - if (Config.Cdda) - CDR_stop(); - if (cpu_clock > 0) plat_target_cpu_clock_set(cpu_clock); diff --git a/frontend/plugin.c b/frontend/plugin.c index b3ad3bd9..19143251 100644 --- a/frontend/plugin.c +++ b/frontend/plugin.c @@ -20,29 +20,6 @@ #undef CALLBACK #define CALLBACK -/* CDR */ -struct CdrStat; -static long CALLBACK CDRinit(void) { return 0; } -static long CALLBACK CDRshutdown(void) { return 0; } -static long CALLBACK CDRopen(void) { return 0; } -static long CALLBACK CDRclose(void) { return 0; } -static long CALLBACK CDRgetTN(unsigned char *_) { return 0; } -static long CALLBACK CDRgetTD(unsigned char _, unsigned char *__) { return 0; } -static boolean CALLBACK CDRreadTrack(unsigned char *_) { return FALSE; } -static unsigned char * CALLBACK CDRgetBuffer(void) { return NULL; } -static unsigned char * CALLBACK CDRgetBufferSub(int sector) { return NULL; } -static long CALLBACK CDRconfigure(void) { return 0; } -static long CALLBACK CDRtest(void) { return 0; } -static void CALLBACK CDRabout(void) { return; } -static long CALLBACK CDRplay(unsigned char *_) { return 0; } -static long CALLBACK CDRstop(void) { return 0; } -static long CALLBACK CDRsetfilename(char *_) { return 0; } -static long CALLBACK CDRgetStatus(struct CdrStat *_) { return 0; } -static char * CALLBACK CDRgetDriveLetter(void) { return NULL; } -static long CALLBACK CDRreadCDDA(unsigned char _, unsigned char __, unsigned char ___, unsigned char *____) { return 0; } -static long CALLBACK CDRgetTE(unsigned char _, unsigned char *__, unsigned char *___, unsigned char *____) { return 0; } -static long CALLBACK CDRprefetch(unsigned char m, unsigned char s, unsigned char f) { return 1; } - /* GPU */ static void CALLBACK GPUdisplayText(char *_) { return; } @@ -134,7 +111,6 @@ extern void GPUrearmedCallbacks(const struct rearmed_cbs *cbs); #define DIRECT(id, name) \ { id, #name, name } -#define DIRECT_CDR(name) DIRECT(PLUGIN_CDR, name) #define DIRECT_SPU(name) DIRECT(PLUGIN_SPU, name) #define DIRECT_GPU(name) DIRECT(PLUGIN_GPU, name) #define DIRECT_PAD(name) DIRECT(PLUGIN_PAD, name) @@ -144,27 +120,6 @@ static const struct { const char *name; void *func; } plugin_funcs[] = { - /* CDR */ - DIRECT_CDR(CDRinit), - DIRECT_CDR(CDRshutdown), - DIRECT_CDR(CDRopen), - DIRECT_CDR(CDRclose), - DIRECT_CDR(CDRtest), - DIRECT_CDR(CDRgetTN), - DIRECT_CDR(CDRgetTD), - DIRECT_CDR(CDRreadTrack), - DIRECT_CDR(CDRgetBuffer), - DIRECT_CDR(CDRgetBufferSub), - DIRECT_CDR(CDRplay), - DIRECT_CDR(CDRstop), - DIRECT_CDR(CDRgetStatus), - DIRECT_CDR(CDRgetDriveLetter), - DIRECT_CDR(CDRconfigure), - DIRECT_CDR(CDRabout), - DIRECT_CDR(CDRsetfilename), - DIRECT_CDR(CDRreadCDDA), - DIRECT_CDR(CDRgetTE), - DIRECT_CDR(CDRprefetch), /* SPU */ DIRECT_SPU(SPUinit), DIRECT_SPU(SPUshutdown), @@ -230,9 +185,6 @@ void *plugin_link(enum builtint_plugins_e id, const char *sym) { int i; - if (id == PLUGIN_CDRCIMG) - return cdrcimg_get_sym(sym); - for (i = 0; i < ARRAY_SIZE(plugin_funcs); i++) { if (id != plugin_funcs[i].id) continue; diff --git a/frontend/plugin.h b/frontend/plugin.h index a96d6098..996da557 100644 --- a/frontend/plugin.h +++ b/frontend/plugin.h @@ -10,9 +10,7 @@ enum builtint_plugins_e { PLUGIN_GPU, PLUGIN_SPU, - PLUGIN_CDR, PLUGIN_PAD, - PLUGIN_CDRCIMG, }; void *plugin_link(enum builtint_plugins_e id, const char *sym); diff --git a/jni/Android.mk b/jni/Android.mk index bce8dcd5..bba07cc5 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -5,6 +5,7 @@ $(shell cd "$(LOCAL_PATH)" && (diff -q ../frontend/revision.h_ ../frontend/revis $(shell cd "$(LOCAL_PATH)" && (rm ../frontend/revision.h_)) USE_LIBRETRO_VFS ?= 0 +USE_ASYNC_CDROM ?= 1 ROOT_DIR := $(LOCAL_PATH)/.. CORE_DIR := $(ROOT_DIR)/libpcsxcore @@ -23,6 +24,7 @@ EXTRA_INCLUDES := # core SOURCES_C := $(CORE_DIR)/cdriso.c \ $(CORE_DIR)/cdrom.c \ + $(CORE_DIR)/cdrom-async.c \ $(CORE_DIR)/cheat.c \ $(CORE_DIR)/database.c \ $(CORE_DIR)/decode_xa.c \ @@ -120,6 +122,11 @@ SOURCES_C += \ $(LIBRETRO_COMMON)/vfs/vfs_implementation.c COREFLAGS += -DUSE_LIBRETRO_VFS endif +ifeq ($(USE_ASYNC_CDROM),1) +SOURCES_C += \ + $(FRONTEND_DIR)/libretro-rthreads.c +COREFLAGS += -DUSE_ASYNC_CDROM +endif EXTRA_INCLUDES += $(LIBRETRO_COMMON)/include HAVE_ARI64=0 diff --git a/libpcsxcore/cdriso.c b/libpcsxcore/cdriso.c index 27ac760d..ee76b753 100644 --- a/libpcsxcore/cdriso.c +++ b/libpcsxcore/cdriso.c @@ -20,7 +20,6 @@ ***************************************************************************/ #include "psxcommon.h" -#include "plugins.h" #include "cdrom.h" #include "cdriso.h" #include "ppf.h" @@ -37,16 +36,7 @@ #include #include #include -#if P_HAVE_PTHREAD -#include -#include #endif -#endif - -// to enable the USE_READ_THREAD code, fix: -// - https://github.com/notaz/pcsx_rearmed/issues/257 -// - ISOgetBufferSub to not race with async code -#define USE_READ_THREAD 0 //P_HAVE_PTHREAD #ifdef USE_LIBRETRO_VFS #include @@ -73,7 +63,6 @@ static boolean subChanRaw = FALSE; static boolean multifile = FALSE; static unsigned char cdbuffer[CD_FRAMESIZE_RAW]; -static unsigned char subbuffer[SUB_FRAMESIZE]; static boolean cddaBigEndian = FALSE; /* Frame offset into CD image where pregap data would be found if it was there. @@ -108,16 +97,9 @@ static struct { #endif 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); -long CALLBACK CDR__test(void); -void CALLBACK CDR__about(void); -long CALLBACK CDR__setfilename(char *filename); -long CALLBACK CDR__prefetch(u8 m, u8 s, u8 f); +static int (*cdimg_read_sub_func)(FILE *f, int sector, void *dest); -static void DecodeRawSubData(void); +static void DecodeRawSubData(unsigned char *subbuffer); struct trackinfo { enum {DATA=1, CDDA} type; @@ -133,11 +115,13 @@ static int numtracks = 0; static struct trackinfo ti[MAXTRACKS]; // get a sector from a msf-array -static unsigned int msf2sec(char *msf) { +static unsigned int msf2sec(const void *msf_) { + const unsigned char *msf = msf_; return ((msf[0] * 60 + msf[1]) * 75) + msf[2]; } -static void sec2msf(unsigned int s, char *msf) { +static void sec2msf(unsigned int s, void *msf_) { + unsigned char *msf = msf_; msf[0] = s / 75 / 60; s = s - msf[0] * 75 * 60; msf[1] = s / 75; @@ -1092,204 +1076,13 @@ static int opensbifile(const char *isoname) { return LoadSBI(sbiname, s); } -#if !USE_READ_THREAD -static void readThreadStop() {} -static void readThreadStart() {} -#else -static pthread_t read_thread_id; - -static pthread_cond_t read_thread_msg_avail; -static pthread_cond_t read_thread_msg_done; -static pthread_mutex_t read_thread_msg_lock; - -static pthread_cond_t sectorbuffer_cond; -static pthread_mutex_t sectorbuffer_lock; - -static boolean read_thread_running = FALSE; -static int read_thread_sector_start = -1; -static int read_thread_sector_end = -1; - -typedef struct { - int sector; - long ret; - unsigned char data[CD_FRAMESIZE_RAW]; -} SectorBufferEntry; - -#define SECTOR_BUFFER_SIZE 4096 - -static SectorBufferEntry *sectorbuffer; -static size_t sectorbuffer_index; - -int (*sync_cdimg_read_func)(FILE *f, unsigned int base, void *dest, int sector); -unsigned char *(*sync_CDR_getBuffer)(void); - -static unsigned char * CALLBACK ISOgetBuffer_async(void); -static int cdread_async(FILE *f, unsigned int base, void *dest, int sector); - -static void *readThreadMain(void *param) { - int max_sector = -1; - int requested_sector_start = -1; - int requested_sector_end = -1; - int last_read_sector = -1; - int index = 0; - - int ra_sector = -1; - int max_ra = 128; - int initial_ra = 1; - int speedmult_ra = 4; - - int ra_count = 0; - int how_far_ahead = 0; - - unsigned char tmpdata[CD_FRAMESIZE_RAW]; - long ret; - - max_sector = msf2sec(ti[numtracks].start) + msf2sec(ti[numtracks].length); - - while(1) { - pthread_mutex_lock(&read_thread_msg_lock); - - // If we don't have readahead and we don't have a sector request, wait for one. - // If we still have readahead to go, don't block, just keep going. - // And if we ever have a sector request pending, acknowledge and reset it. - - if (!ra_count) { - if (read_thread_sector_start == -1 && read_thread_running) { - pthread_cond_wait(&read_thread_msg_avail, &read_thread_msg_lock); - } - } - - if (read_thread_sector_start != -1) { - requested_sector_start = read_thread_sector_start; - requested_sector_end = read_thread_sector_end; - read_thread_sector_start = -1; - read_thread_sector_end = -1; - pthread_cond_signal(&read_thread_msg_done); - } - - pthread_mutex_unlock(&read_thread_msg_lock); - - if (!read_thread_running) - break; - - // Readahead code, based on the implementation in mednafen psx's cdromif.cpp - if (requested_sector_start != -1) { - if (last_read_sector != -1 && last_read_sector == (requested_sector_start - 1)) { - how_far_ahead = ra_sector - requested_sector_end; - - if(how_far_ahead <= max_ra) - ra_count = (max_ra - how_far_ahead + 1 ? max_ra - how_far_ahead + 1 : speedmult_ra); - else - ra_count++; - } else if (requested_sector_end != last_read_sector) { - ra_sector = requested_sector_end; - ra_count = initial_ra; - } - - last_read_sector = requested_sector_end; - } - - index = ra_sector % SECTOR_BUFFER_SIZE; - - // check for end of CD - if (ra_count && ra_sector >= max_sector) { - ra_count = 0; - pthread_mutex_lock(§orbuffer_lock); - sectorbuffer[index].ret = -1; - sectorbuffer[index].sector = ra_sector; - pthread_cond_signal(§orbuffer_cond); - pthread_mutex_unlock(§orbuffer_lock); - } - - if (ra_count) { - pthread_mutex_lock(§orbuffer_lock); - if (sectorbuffer[index].sector != ra_sector) { - pthread_mutex_unlock(§orbuffer_lock); - - ret = sync_cdimg_read_func(cdHandle, 0, tmpdata, ra_sector); - - pthread_mutex_lock(§orbuffer_lock); - sectorbuffer[index].ret = ret; - sectorbuffer[index].sector = ra_sector; - memcpy(sectorbuffer[index].data, tmpdata, CD_FRAMESIZE_RAW); - } - pthread_cond_signal(§orbuffer_cond); - pthread_mutex_unlock(§orbuffer_lock); - - ra_sector++; - ra_count--; - } - } - - return NULL; -} - -static void readThreadStop() { - if (read_thread_running == TRUE) { - read_thread_running = FALSE; - pthread_cond_signal(&read_thread_msg_avail); - pthread_join(read_thread_id, NULL); - } - - pthread_cond_destroy(&read_thread_msg_done); - pthread_cond_destroy(&read_thread_msg_avail); - pthread_mutex_destroy(&read_thread_msg_lock); - - pthread_cond_destroy(§orbuffer_cond); - pthread_mutex_destroy(§orbuffer_lock); - - CDR_getBuffer = sync_CDR_getBuffer; - cdimg_read_func = sync_cdimg_read_func; - - free(sectorbuffer); - sectorbuffer = NULL; -} - -static void readThreadStart() { - SysPrintf("Starting async CD thread\n"); - - if (read_thread_running == TRUE) - return; - - read_thread_running = TRUE; - read_thread_sector_start = -1; - read_thread_sector_end = -1; - sectorbuffer_index = 0; - - sectorbuffer = calloc(SECTOR_BUFFER_SIZE, sizeof(SectorBufferEntry)); - if(!sectorbuffer) - goto error; - - sectorbuffer[0].sector = -1; // Otherwise we might think we've already fetched sector 0! - - sync_CDR_getBuffer = CDR_getBuffer; - CDR_getBuffer = ISOgetBuffer_async; - sync_cdimg_read_func = cdimg_read_func; - cdimg_read_func = cdread_async; - - if (pthread_cond_init(&read_thread_msg_avail, NULL) || - pthread_cond_init(&read_thread_msg_done, NULL) || - pthread_mutex_init(&read_thread_msg_lock, NULL) || - pthread_cond_init(§orbuffer_cond, NULL) || - pthread_mutex_init(§orbuffer_lock, NULL) || - pthread_create(&read_thread_id, NULL, readThreadMain, NULL)) - goto error; - - return; - - error: - SysPrintf("Error starting async CD thread\n"); - SysPrintf("Falling back to sync\n"); - - readThreadStop(); -} -#endif - static int cdread_normal(FILE *f, unsigned int base, void *dest, int sector) { int ret; if (!f) return -1; + if (!dest) + dest = cdbuffer; if (fseeko(f, base + sector * CD_FRAMESIZE_RAW, SEEK_SET)) goto fail_io; ret = fread(dest, 1, CD_FRAMESIZE_RAW, f); @@ -1309,6 +1102,8 @@ static int cdread_sub_mixed(FILE *f, unsigned int base, void *dest, int sector) if (!f) return -1; + if (!dest) + dest = cdbuffer; if (fseeko(f, base + sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE), SEEK_SET)) goto fail_io; ret = fread(dest, 1, CD_FRAMESIZE_RAW, f); @@ -1321,16 +1116,16 @@ fail_io: return -1; } -static int cdread_sub_sub_mixed(FILE *f, int sector) +static int cdread_sub_sub_mixed(FILE *f, int sector, void *buffer) { if (!f) return -1; if (fseeko(f, sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE) + CD_FRAMESIZE_RAW, SEEK_SET)) goto fail_io; - if (fread(subbuffer, 1, SUB_FRAMESIZE, f) != SUB_FRAMESIZE) + if (fread(buffer, 1, SUB_FRAMESIZE, f) != SUB_FRAMESIZE) goto fail_io; - return SUB_FRAMESIZE; + return 0; fail_io: SysPrintf("subchannel: file IO error %d, sector %u\n", errno, sector); @@ -1411,7 +1206,7 @@ static int cdread_compressed(FILE *f, unsigned int base, void *dest, int sector) if (fread(is_compressed ? compr_img->buff_compressed : compr_img->buff_raw[0], 1, size, cdHandle) != size) { - SysPrintf("read error for block %d at %x: ", block, start_byte); + SysPrintf("read error for block %d at %zx: ", block, start_byte); perror(NULL); return -1; } @@ -1434,7 +1229,7 @@ static int cdread_compressed(FILE *f, unsigned int base, void *dest, int sector) compr_img->current_block = block; finish: - if (dest != cdbuffer) // copy avoid HACK + if (dest != NULL) memcpy(dest, compr_img->buff_raw[compr_img->sector_in_blk], CD_FRAMESIZE_RAW); return CD_FRAMESIZE_RAW; @@ -1468,13 +1263,13 @@ static int cdread_chd(FILE *f, unsigned int base, void *dest, int sector) chd_img->current_hunk[chd_img->current_buffer] = hunk; } - if (dest != cdbuffer) // copy avoid HACK + if (dest != NULL) memcpy(dest, chd_get_sector(chd_img->current_buffer, chd_img->sector_in_hunk), CD_FRAMESIZE_RAW); return CD_FRAMESIZE_RAW; } -static int cdread_sub_chd(FILE *f, int sector) +static int cdread_sub_chd(FILE *f, int sector, void *buffer_ptr) { unsigned int sector_in_hunk; unsigned int buffer; @@ -1498,99 +1293,48 @@ static int cdread_sub_chd(FILE *f, int sector) chd_img->current_hunk[buffer] = hunk; } - memcpy(subbuffer, chd_get_sector(buffer, sector_in_hunk) + CD_FRAMESIZE_RAW, SUB_FRAMESIZE); - return SUB_FRAMESIZE; + memcpy(buffer_ptr, chd_get_sector(buffer, sector_in_hunk) + CD_FRAMESIZE_RAW, SUB_FRAMESIZE); + return 0; } #endif static int cdread_2048(FILE *f, unsigned int base, void *dest, int sector) { + unsigned char *dst = dest ? dest : cdbuffer; int ret; if (!f) return -1; + fseeko(f, base + sector * 2048, SEEK_SET); - ret = fread((char *)dest + 12 * 2, 1, 2048, f); + ret = fread(dst + 12 * 2, 1, 2048, f); // not really necessary, fake mode 2 header - memset(cdbuffer, 0, 12 * 2); - sec2msf(sector + 2 * 75, (char *)&cdbuffer[12]); - cdbuffer[12 + 3] = 1; + memset(dst, 0, 12 * 2); + sec2msf(sector + 2 * 75, dst + 12); + dst[12 + 0] = itob(dst[12 + 0]); + dst[12 + 1] = itob(dst[12 + 1]); + dst[12 + 2] = itob(dst[12 + 2]); + dst[12 + 3] = 1; return 12*2 + ret; } -#if USE_READ_THREAD - -static int cdread_async(FILE *f, unsigned int base, void *dest, int sector) { - boolean found = FALSE; - int i = sector % SECTOR_BUFFER_SIZE; - long ret; - - if (f != cdHandle || base != 0 || dest != cdbuffer) { - // Async reads are only supported for cdbuffer, so call the sync - // function directly. - return sync_cdimg_read_func(f, base, dest, sector); - } - - pthread_mutex_lock(&read_thread_msg_lock); - - // Only wait if we're not trying to read the next sector and - // sector_start is set (meaning the last request hasn't been - // processed yet) - while(read_thread_sector_start != -1 && read_thread_sector_end + 1 != sector) { - pthread_cond_wait(&read_thread_msg_done, &read_thread_msg_lock); - } - - if (read_thread_sector_start == -1) - read_thread_sector_start = sector; - - read_thread_sector_end = sector; - pthread_cond_signal(&read_thread_msg_avail); - pthread_mutex_unlock(&read_thread_msg_lock); - - do { - pthread_mutex_lock(§orbuffer_lock); - if (sectorbuffer[i].sector == sector) { - sectorbuffer_index = i; - ret = sectorbuffer[i].ret; - found = TRUE; - } - - if (!found) { - pthread_cond_wait(§orbuffer_cond, §orbuffer_lock); - } - pthread_mutex_unlock(§orbuffer_lock); - } while (!found); - - return ret; +static void * ISOgetBuffer_normal(void) { + return cdbuffer + 12; } -#endif - -static unsigned char * CALLBACK ISOgetBuffer_compr(void) { - return compr_img->buff_raw[compr_img->sector_in_blk] + 12; +static void * ISOgetBuffer_compr(void) { + return compr_img->buff_raw[compr_img->sector_in_blk] + 12; } #ifdef HAVE_CHD -static unsigned char * CALLBACK ISOgetBuffer_chd(void) { - return chd_get_sector(chd_img->current_buffer, chd_img->sector_in_hunk) + 12; +static void * ISOgetBuffer_chd(void) { + return chd_get_sector(chd_img->current_buffer, chd_img->sector_in_hunk) + 12; } #endif -#if USE_READ_THREAD -static unsigned char * CALLBACK ISOgetBuffer_async(void) { - unsigned char *buffer; - pthread_mutex_lock(§orbuffer_lock); - buffer = sectorbuffer[sectorbuffer_index].data; - pthread_mutex_unlock(§orbuffer_lock); - return buffer + 12; -} -#endif - -unsigned char * CALLBACK ISOgetBuffer(void) { - return cdbuffer + 12; -} +void * (*ISOgetBuffer)(void) = ISOgetBuffer_normal; static void PrintTracks(void) { int i; @@ -1606,7 +1350,8 @@ static void PrintTracks(void) { // This function is invoked by the front-end when opening an ISO // file for playback -static long CALLBACK ISOopen(void) { +int ISOopen(const char *fname) +{ boolean isMode1ISO = FALSE; char alt_bin_filename[MAXPATHLEN]; const char *bin_filename; @@ -1617,16 +1362,16 @@ static long CALLBACK ISOopen(void) { return 0; // it's already open } - cdHandle = fopen(GetIsoFile(), "rb"); + cdHandle = fopen(fname, "rb"); if (cdHandle == NULL) { SysPrintf(_("Could't open '%s' for reading: %s\n"), - GetIsoFile(), strerror(errno)); + fname, strerror(errno)); return -1; } size_main = get_size(cdHandle); snprintf(image_str, sizeof(image_str) - 6*4 - 1, - "Loaded CD Image: %s", GetIsoFile()); + "Loaded CD Image: %s", fname); cddaBigEndian = FALSE; subChanMixed = FALSE; @@ -1635,36 +1380,36 @@ static long CALLBACK ISOopen(void) { cdrIsoMultidiskCount = 1; multifile = 0; - CDR_getBuffer = ISOgetBuffer; + ISOgetBuffer = ISOgetBuffer_normal; cdimg_read_func = cdread_normal; cdimg_read_sub_func = NULL; - if (parsetoc(GetIsoFile()) == 0) { + if (parsetoc(fname) == 0) { strcat(image_str, "[+toc]"); } - else if (parseccd(GetIsoFile()) == 0) { + else if (parseccd(fname) == 0) { strcat(image_str, "[+ccd]"); } - else if (parsemds(GetIsoFile()) == 0) { + else if (parsemds(fname) == 0) { strcat(image_str, "[+mds]"); } - else if (parsecue(GetIsoFile()) == 0) { + else if (parsecue(fname) == 0) { strcat(image_str, "[+cue]"); } - if (handlepbp(GetIsoFile()) == 0) { + if (handlepbp(fname) == 0) { strcat(image_str, "[+pbp]"); - CDR_getBuffer = ISOgetBuffer_compr; + ISOgetBuffer = ISOgetBuffer_compr; cdimg_read_func = cdread_compressed; } - else if (handlecbin(GetIsoFile()) == 0) { + else if (handlecbin(fname) == 0) { strcat(image_str, "[+cbin]"); - CDR_getBuffer = ISOgetBuffer_compr; + ISOgetBuffer = ISOgetBuffer_compr; cdimg_read_func = cdread_compressed; } #ifdef HAVE_CHD - else if (handlechd(GetIsoFile()) == 0) { + else if (handlechd(fname) == 0) { strcat(image_str, "[+chd]"); - CDR_getBuffer = ISOgetBuffer_chd; + ISOgetBuffer = ISOgetBuffer_chd; cdimg_read_func = cdread_chd; cdimg_read_sub_func = cdread_sub_chd; fclose(cdHandle); @@ -1672,15 +1417,15 @@ static long CALLBACK ISOopen(void) { } #endif - if (!subChanMixed && opensubfile(GetIsoFile()) == 0) { + if (!subChanMixed && opensubfile(fname) == 0) { strcat(image_str, "[+sub]"); } - if (opensbifile(GetIsoFile()) == 0) { + if (opensbifile(fname) == 0) { strcat(image_str, "[+sbi]"); } // maybe user selected metadata file instead of main .bin .. - bin_filename = GetIsoFile(); + bin_filename = fname; if (cdHandle && size_main < 2352 * 0x10) { static const char *exts[] = { ".bin", ".BIN", ".img", ".IMG" }; FILE *tmpf = NULL; @@ -1731,13 +1476,11 @@ static long CALLBACK ISOopen(void) { cdimg_read_sub_func = NULL; } - if (Config.AsyncCD) { - readThreadStart(); - } return 0; } -static long CALLBACK ISOclose(void) { +int ISOclose(void) +{ int i; if (cdHandle != NULL) { @@ -1776,32 +1519,31 @@ static long CALLBACK ISOclose(void) { UnloadSBI(); memset(cdbuffer, 0, sizeof(cdbuffer)); - CDR_getBuffer = ISOgetBuffer; - - if (Config.AsyncCD) { - readThreadStop(); - } + ISOgetBuffer = ISOgetBuffer_normal; return 0; } -static long CALLBACK ISOinit(void) { +int ISOinit(void) +{ assert(cdHandle == NULL); assert(subHandle == NULL); + numtracks = 0; return 0; // do nothing } -static long CALLBACK ISOshutdown(void) { - ISOclose(); - return 0; +int ISOshutdown(void) +{ + return ISOclose(); } // return Starting and Ending Track // buffer: // byte 0 - start track // byte 1 - end track -static long CALLBACK ISOgetTN(unsigned char *buffer) { +int ISOgetTN(unsigned char *buffer) +{ buffer[0] = 1; if (numtracks > 0) { @@ -1816,23 +1558,18 @@ static long CALLBACK ISOgetTN(unsigned char *buffer) { // return Track Time // buffer: -// byte 0 - frame +// byte 0 - minute // byte 1 - second -// byte 2 - minute -static long CALLBACK ISOgetTD(unsigned char track, unsigned char *buffer) { +// byte 2 - frame +int ISOgetTD(int track, unsigned char *buffer) +{ if (track == 0) { unsigned int sect; - unsigned char time[3]; sect = msf2sec(ti[numtracks].start) + msf2sec(ti[numtracks].length); - sec2msf(sect, (char *)time); - buffer[2] = time[0]; - buffer[1] = time[1]; - buffer[0] = time[2]; + sec2msf(sect, buffer); } else if (numtracks > 0 && track <= numtracks) { - buffer[2] = ti[track].start[0]; - buffer[1] = ti[track].start[1]; - buffer[0] = ti[track].start[2]; + memcpy(buffer, ti[track].start, 3); } else { buffer[2] = 0; @@ -1844,7 +1581,7 @@ static long CALLBACK ISOgetTD(unsigned char track, unsigned char *buffer) { } // decode 'raw' subchannel data ripped by cdrdao -static void DecodeRawSubData(void) { +static void DecodeRawSubData(unsigned char *subbuffer) { unsigned char subQData[12]; int i; @@ -1860,64 +1597,68 @@ static void DecodeRawSubData(void) { } // read track -// time: byte 0 - minute; byte 1 - second; byte 2 - frame -// uses bcd format -static boolean CALLBACK ISOreadTrack(unsigned char *time) { - int sector = MSF2SECT(btoi(time[0]), btoi(time[1]), btoi(time[2])); +// time: byte 0 - minute; byte 1 - second; byte 2 - frame (non-bcd) +// buf: if NULL, data is kept in internal buffer accessible by ISOgetBuffer() +int ISOreadTrack(const unsigned char *time, void *buf) +{ + int sector = msf2sec(time); long ret; if (!cdHandle && !chd_img) - return 0; + return -1; + if (numtracks > 1 && sector >= msf2sec(ti[2].start)) + return ISOreadCDDA(time, buf); + + sector -= 2 * 75; if (pregapOffset && sector >= pregapOffset) sector -= 2 * 75; - ret = cdimg_read_func(cdHandle, 0, cdbuffer, sector); - if (ret < 12*2 + 2048) - return 0; - - return 1; -} + ret = cdimg_read_func(cdHandle, 0, buf, sector); + if (ret < 12*2 + 2048) { + if (multifile && sector >= msf2sec(ti[1].length)) { + // assume a gap not backed by a file + memset(buf, 0, CD_FRAMESIZE_RAW); + return 0; + } + return -1; + } -// plays cdda audio -// sector: byte 0 - minute; byte 1 - second; byte 2 - frame -// does NOT uses bcd format -static long CALLBACK ISOplay(unsigned char *time) { return 0; } -// stops cdda audio -static long CALLBACK ISOstop(void) { - return 0; -} +// read subchannel data +int ISOreadSub(const unsigned char *time, void *buffer) +{ + int ret, sector = MSF2SECT(time[0], time[1], time[2]); -// gets subchannel data -static unsigned char* CALLBACK ISOgetBufferSub(int sector) { if (pregapOffset && sector >= pregapOffset) { sector -= 2 * 75; if (sector < pregapOffset) // ? - return NULL; + return -1; } if (cdimg_read_sub_func != NULL) { - if (cdimg_read_sub_func(cdHandle, sector) != SUB_FRAMESIZE) - return NULL; + if ((ret = cdimg_read_sub_func(cdHandle, sector, buffer))) + return ret; } else if (subHandle != NULL) { if (fseeko(subHandle, sector * SUB_FRAMESIZE, SEEK_SET)) - return NULL; - if (fread(subbuffer, 1, SUB_FRAMESIZE, subHandle) != SUB_FRAMESIZE) - return NULL; + return -1; + if (fread(buffer, 1, SUB_FRAMESIZE, subHandle) != SUB_FRAMESIZE) + return -1; } else { - return NULL; + return -1; } - if (subChanRaw) DecodeRawSubData(); - return subbuffer; + if (subChanRaw) + DecodeRawSubData(buffer); + return 0; } -static long CALLBACK ISOgetStatus(struct CdrStat *stat) { +int ISOgetStatus(struct CdrStat *stat) +{ CDR__getStatus(stat); // BIOS - boot ID (CD type) @@ -1927,14 +1668,14 @@ static long CALLBACK ISOgetStatus(struct CdrStat *stat) { } // read CDDA sector into buffer -long CALLBACK ISOreadCDDA(unsigned char m, unsigned char s, unsigned char f, unsigned char *buffer) { - unsigned char msf[3] = {m, s, f}; +int ISOreadCDDA(const unsigned char *time, void *buffer) +{ unsigned int track, track_start = 0; FILE *handle = cdHandle; unsigned int cddaCurPos; - int ret; + int ret, ret_clear = -1; - cddaCurPos = msf2sec((char *)msf); + cddaCurPos = msf2sec(time); // find current track index for (track = numtracks; ; track--) { @@ -1947,8 +1688,8 @@ long CALLBACK ISOreadCDDA(unsigned char m, unsigned char s, unsigned char f, uns // data tracks play silent if (ti[track].type != CDDA) { - memset(buffer, 0, CD_FRAMESIZE_RAW); - return 0; + ret_clear = 0; + goto clear_return; } if (multifile) { @@ -1961,57 +1702,32 @@ long CALLBACK ISOreadCDDA(unsigned char m, unsigned char s, unsigned char f, uns } } } - if (!handle && !chd_img) { - memset(buffer, 0, CD_FRAMESIZE_RAW); - return -1; - } + if (!handle && !chd_img) + goto clear_return; ret = cdimg_read_func(handle, ti[track].start_offset, buffer, cddaCurPos - track_start); if (ret != CD_FRAMESIZE_RAW) { - memset(buffer, 0, CD_FRAMESIZE_RAW); - return -1; + if (multifile && cddaCurPos - track_start >= msf2sec(ti[track].length)) + ret_clear = 0; // gap + goto clear_return; } - if (cddaBigEndian) { + if (cddaBigEndian && buffer) { + unsigned char tmp, *buf = buffer; int i; - unsigned char tmp; for (i = 0; i < CD_FRAMESIZE_RAW / 2; i++) { - tmp = buffer[i * 2]; - buffer[i * 2] = buffer[i * 2 + 1]; - buffer[i * 2 + 1] = tmp; + tmp = buf[i * 2]; + buf[i * 2] = buf[i * 2 + 1]; + buf[i * 2 + 1] = tmp; } } return 0; -} - -void cdrIsoInit(void) { - CDR_init = ISOinit; - CDR_shutdown = ISOshutdown; - CDR_open = ISOopen; - CDR_close = ISOclose; - CDR_getTN = ISOgetTN; - CDR_getTD = ISOgetTD; - CDR_readTrack = ISOreadTrack; - CDR_getBuffer = ISOgetBuffer; - CDR_play = ISOplay; - CDR_stop = ISOstop; - CDR_getBufferSub = ISOgetBufferSub; - CDR_getStatus = ISOgetStatus; - CDR_readCDDA = ISOreadCDDA; - - CDR_getDriveLetter = CDR__getDriveLetter; - CDR_configure = CDR__configure; - CDR_test = CDR__test; - CDR_about = CDR__about; - CDR_setfilename = CDR__setfilename; - CDR_prefetch = CDR__prefetch; - numtracks = 0; -} - -int cdrIsoActive(void) { - return (cdHandle || chd_img); +clear_return: + if (buffer) + memset(buffer, 0, CD_FRAMESIZE_RAW); + return ret_clear; } diff --git a/libpcsxcore/cdriso.h b/libpcsxcore/cdriso.h index 079e0b8c..ed79d60e 100644 --- a/libpcsxcore/cdriso.h +++ b/libpcsxcore/cdriso.h @@ -25,9 +25,20 @@ extern "C" { #endif -void cdrIsoInit(void); -int cdrIsoActive(void); -unsigned char * CALLBACK ISOgetBuffer(void); +struct CdrStat; + +int ISOinit(void); +int ISOshutdown(void); +int ISOopen(const char *fname); +int ISOclose(void); +int ISOgetTN(unsigned char *buffer); +int ISOgetTD(int track, unsigned char *buffer); +int ISOreadTrack(const unsigned char *time, void *buf); +int ISOreadCDDA(const unsigned char *time, void *buffer); +int ISOreadSub(const unsigned char *time, void *buffer); +int ISOgetStatus(struct CdrStat *stat); + +extern void * (*ISOgetBuffer)(void); extern unsigned int cdrIsoMultidiskCount; extern unsigned int cdrIsoMultidiskSelect; diff --git a/libpcsxcore/cdrom-async.c b/libpcsxcore/cdrom-async.c new file mode 100644 index 00000000..026a3451 --- /dev/null +++ b/libpcsxcore/cdrom-async.c @@ -0,0 +1,566 @@ +/*************************************************************************** + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + ***************************************************************************/ + +#include +#include +#include "system.h" +#include "plugins.h" +#include "cdriso.h" +#include "cdrom.h" +#include "cdrom-async.h" + +#if 0 +#define acdrom_dbg printf +#else +#define acdrom_dbg(...) +#endif + +#ifdef HAVE_CDROM + +#include "vfs/vfs_implementation.h" +#include "vfs/vfs_implementation_cdrom.h" +#include "../frontend/libretro-cdrom.h" + +static libretro_vfs_implementation_file *g_cd_handle; + +static int rcdrom_open(const char *name, u32 *total_lba) +{ + g_cd_handle = retro_vfs_file_open_impl(name, RETRO_VFS_FILE_ACCESS_READ, + RETRO_VFS_FILE_ACCESS_HINT_NONE); + if (!g_cd_handle) { + SysPrintf("retro_vfs_file_open failed for '%s'\n", name); + return -1; + } + else { + int ret = cdrom_set_read_speed_x(g_cd_handle, 4); + if (ret) SysPrintf("CD speed set failed\n"); + const cdrom_toc_t *toc = retro_vfs_file_get_cdrom_toc(); + const cdrom_track_t *last = &toc->track[toc->num_tracks - 1]; + unsigned int lba = MSF2SECT(last->min, last->sec, last->frame); + *total_lba = lba + last->track_size; + //cdrom_get_current_config_random_readable(acdrom.h); + //cdrom_get_current_config_multiread(acdrom.h); + //cdrom_get_current_config_cdread(acdrom.h); + //cdrom_get_current_config_profiles(acdrom.h); + return 0; + } +} + +static void rcdrom_close(void) +{ + if (g_cd_handle) { + retro_vfs_file_close_impl(g_cd_handle); + g_cd_handle = NULL; + } +} + +static int rcdrom_getTN(u8 *tn) +{ + const cdrom_toc_t *toc = retro_vfs_file_get_cdrom_toc(); + if (toc) { + tn[0] = 1; + tn[1] = toc->num_tracks; + return 0; + } + return -1; +} + +static int rcdrom_getTD(u32 total_lba, u8 track, u8 *rt) +{ + const cdrom_toc_t *toc = retro_vfs_file_get_cdrom_toc(); + rt[0] = 0, rt[1] = 2, rt[2] = 0; + if (track == 0) { + lba2msf(total_lba + 150, &rt[0], &rt[1], &rt[2]); + } + else if (track <= toc->num_tracks) { + int i = track - 1; + rt[0] = toc->track[i].min; + rt[1] = toc->track[i].sec; + rt[2] = toc->track[i].frame; + } + return 0; +} + +static int rcdrom_getStatus(struct CdrStat *stat) +{ + const cdrom_toc_t *toc = retro_vfs_file_get_cdrom_toc(); + stat->Type = toc->track[0].audio ? 2 : 1; + return 0; +} + +#elif defined(USE_ASYNC_CDROM) + +#define g_cd_handle 0 + +static int rcdrom_open(const char *name, u32 *total_lba) { return -1; } +static void rcdrom_close(void) {} +static int rcdrom_getTN(u8 *tn) { return -1; } +static int rcdrom_getTD(u32 total_lba, u8 track, u8 *rt) { return -1; } +static int rcdrom_getStatus(struct CdrStat *stat) { return -1; } + +static int cdrom_read_sector(void *stream, unsigned int lba, void *b) { return -1; } +static int cdrom_is_media_inserted(void *stream) { return 0; } + +#endif + +#ifdef USE_ASYNC_CDROM + +#include "rthreads/rthreads.h" +#include "retro_timers.h" + +struct cached_buf { + u32 lba; + u8 buf[CD_FRAMESIZE_RAW]; + u8 buf_sub[SUB_FRAMESIZE]; +}; +static struct { + sthread_t *thread; + slock_t *read_lock; + slock_t *buf_lock; + scond_t *cond; + struct cached_buf *buf_cache; + u32 buf_cnt, thread_exit, do_prefetch, prefetch_failed, have_subchannel; + u32 total_lba, prefetch_lba; + int check_eject_delay; + u8 buf_local[CD_FRAMESIZE_RAW]; // single sector cache, not touched by the thread +} acdrom; + +static void lbacache_do(u32 lba) +{ + unsigned char msf[3], buf[CD_FRAMESIZE_RAW], buf_sub[SUB_FRAMESIZE]; + u32 i = lba % acdrom.buf_cnt; + int ret; + + lba2msf(lba + 150, &msf[0], &msf[1], &msf[2]); + slock_lock(acdrom.read_lock); + if (g_cd_handle) + ret = cdrom_read_sector(g_cd_handle, lba, buf); + else + ret = ISOreadTrack(msf, buf); + if (acdrom.have_subchannel) + ret |= ISOreadSub(msf, buf_sub); + + slock_lock(acdrom.buf_lock); + slock_unlock(acdrom.read_lock); + acdrom_dbg("c %d:%02d:%02d %2d m%d f%d\n", msf[0], msf[1], msf[2], ret, + buf[12+3], ((buf[12+4+2] >> 5) & 1) + 1); + if (ret) { + acdrom.do_prefetch = 0; + acdrom.prefetch_failed = 1; + slock_unlock(acdrom.buf_lock); + SysPrintf("prefetch: read failed for lba %d: %d\n", lba, ret); + return; + } + acdrom.prefetch_failed = 0; + acdrom.check_eject_delay = 100; + + if (lba != acdrom.buf_cache[i].lba) { + acdrom.buf_cache[i].lba = lba; + memcpy(acdrom.buf_cache[i].buf, buf, sizeof(acdrom.buf_cache[i].buf)); + if (acdrom.have_subchannel) + memcpy(acdrom.buf_cache[i].buf_sub, buf_sub, sizeof(buf_sub)); + } + slock_unlock(acdrom.buf_lock); + if (g_cd_handle) + retro_sleep(0); // why does the main thread stall without this? +} + +static int lbacache_get(unsigned int lba, void *buf, void *sub_buf) +{ + unsigned int i; + int ret = 0; + + i = lba % acdrom.buf_cnt; + slock_lock(acdrom.buf_lock); + if (lba == acdrom.buf_cache[i].lba) { + if (!buf) + buf = acdrom.buf_local; + memcpy(buf, acdrom.buf_cache[i].buf, CD_FRAMESIZE_RAW); + if (sub_buf) + memcpy(sub_buf, acdrom.buf_cache[i].buf_sub, SUB_FRAMESIZE); + ret = 1; + } + slock_unlock(acdrom.buf_lock); + return ret; +} + +// note: This has races on some vars but that's ok, main thread can deal +// with it. Only unsafe buffer accesses and simultaneous reads are prevented. +static void cdra_prefetch_thread(void *unused) +{ + u32 buf_cnt, lba, lba_to; + + slock_lock(acdrom.buf_lock); + while (!acdrom.thread_exit) + { +#ifdef __GNUC__ + __asm__ __volatile__("":::"memory"); // barrier +#endif + if (!acdrom.do_prefetch) + scond_wait(acdrom.cond, acdrom.buf_lock); + if (!acdrom.do_prefetch || acdrom.thread_exit) + continue; + + buf_cnt = acdrom.buf_cnt; + lba = acdrom.prefetch_lba; + lba_to = lba + buf_cnt; + if (lba_to > acdrom.total_lba) + lba_to = acdrom.total_lba; + for (; lba < lba_to; lba++) { + if (lba != acdrom.buf_cache[lba % buf_cnt].lba) + break; + } + if (lba == lba_to || lba >= acdrom.total_lba) { + // caching complete + acdrom.do_prefetch = 0; + continue; + } + + slock_unlock(acdrom.buf_lock); + lbacache_do(lba); + slock_lock(acdrom.buf_lock); + } + slock_unlock(acdrom.buf_lock); +} + +void cdra_stop_thread(void) +{ + acdrom.thread_exit = 1; + if (acdrom.buf_lock) { + slock_lock(acdrom.buf_lock); + acdrom.do_prefetch = 0; + if (acdrom.cond) + scond_signal(acdrom.cond); + slock_unlock(acdrom.buf_lock); + } + if (acdrom.thread) { + sthread_join(acdrom.thread); + acdrom.thread = NULL; + } + if (acdrom.cond) { scond_free(acdrom.cond); acdrom.cond = NULL; } + if (acdrom.buf_lock) { slock_free(acdrom.buf_lock); acdrom.buf_lock = NULL; } + if (acdrom.read_lock) { slock_free(acdrom.read_lock); acdrom.read_lock = NULL; } + free(acdrom.buf_cache); + acdrom.buf_cache = NULL; +} + +// the thread is optional, if anything fails we can do direct reads +static void cdra_start_thread(void) +{ + cdra_stop_thread(); + acdrom.thread_exit = acdrom.prefetch_lba = acdrom.do_prefetch = 0; + acdrom.prefetch_failed = 0; + if (acdrom.buf_cnt == 0) + return; + acdrom.buf_cache = calloc(acdrom.buf_cnt, sizeof(acdrom.buf_cache[0])); + acdrom.buf_lock = slock_new(); + acdrom.read_lock = slock_new(); + acdrom.cond = scond_new(); + if (acdrom.buf_cache && acdrom.buf_lock && acdrom.read_lock && acdrom.cond) + { + int i; + acdrom.thread = sthread_create(cdra_prefetch_thread, NULL); + for (i = 0; i < acdrom.buf_cnt; i++) + acdrom.buf_cache[i].lba = ~0; + } + if (acdrom.thread) { + SysPrintf("cdrom precache: %d buffers%s\n", + acdrom.buf_cnt, acdrom.have_subchannel ? " +sub" : ""); + } + else { + SysPrintf("cdrom precache thread init failed.\n"); + cdra_stop_thread(); + } +} + +int cdra_init(void) +{ + return ISOinit(); +} + +void cdra_shutdown(void) +{ + cdra_close(); +} + +int cdra_open(void) +{ + const char *name = GetIsoFile(); + u8 buf_sub[SUB_FRAMESIZE]; + int ret = -1, ret2; + + acdrom_dbg("%s %s\n", __func__, name); + acdrom.have_subchannel = 0; + if (!strncmp(name, "cdrom:", 6)) + ret = rcdrom_open(name, &acdrom.total_lba); + + // try ISO even if it's cdrom:// as it might work through libretro vfs + if (ret < 0) { + ret = ISOopen(name); + if (ret == 0) { + u8 msf[3]; + ISOgetTD(0, msf); + acdrom.total_lba = MSF2SECT(msf[0], msf[1], msf[2]); + msf[0] = 0; msf[1] = 2; msf[2] = 16; + ret2 = ISOreadSub(msf, buf_sub); + acdrom.have_subchannel = (ret2 == 0); + } + } + if (ret == 0) + cdra_start_thread(); + return ret; +} + +void cdra_close(void) +{ + acdrom_dbg("%s\n", __func__); + cdra_stop_thread(); + if (g_cd_handle) + rcdrom_close(); + else + ISOclose(); +} + +int cdra_getTN(unsigned char *tn) +{ + int ret; + if (g_cd_handle) + ret = rcdrom_getTN(tn); + else + ret = ISOgetTN(tn); + acdrom_dbg("%s -> %d %d\n", __func__, tn[0], tn[1]); + return ret; +} + +int cdra_getTD(int track, unsigned char *rt) +{ + int ret; + if (g_cd_handle) + ret = rcdrom_getTD(acdrom.total_lba, track, rt); + else + ret = ISOgetTD(track, rt); + //acdrom_dbg("%s %d -> %d:%02d:%02d\n", __func__, track, rt[2], rt[1], rt[0]); + return ret; +} + +int cdra_prefetch(unsigned char m, unsigned char s, unsigned char f) +{ + u32 lba = MSF2SECT(m, s, f); + int ret = 1; + if (acdrom.cond) { + acdrom.prefetch_lba = lba; + acdrom.do_prefetch = 1; + scond_signal(acdrom.cond); + } + if (acdrom.buf_cache && !acdrom.prefetch_failed) { + u32 c = acdrom.buf_cnt; + if (c) + ret = acdrom.buf_cache[lba % c].lba == lba; + acdrom_dbg("p %d:%02d:%02d %d\n", m, s, f, ret); + } + return ret; +} + +static int cdra_do_read(const unsigned char *time, int cdda, + void *buf, void *buf_sub) +{ + u32 lba = MSF2SECT(time[0], time[1], time[2]); + int hit = 0, ret = -1, read_locked = 0; + do + { + if (acdrom.buf_lock) { + hit = lbacache_get(lba, buf, buf_sub); + if (hit) + break; + } + if (acdrom.read_lock) { + // maybe still prefetching + slock_lock(acdrom.read_lock); + read_locked = 1; + hit = lbacache_get(lba, buf, buf_sub); + if (hit) { + hit = 2; + break; + } + } + acdrom.do_prefetch = 0; + if (!buf) + buf = acdrom.buf_local; + if (g_cd_handle) + ret = cdrom_read_sector(g_cd_handle, lba, buf); + else if (buf_sub) + ret = ISOreadSub(time, buf_sub); + else if (cdda) + ret = ISOreadCDDA(time, buf); + else + ret = ISOreadTrack(time, buf); + if (ret) + SysPrintf("cdrom read failed for lba %d: %d\n", lba, ret); + } + while (0); + if (read_locked) + slock_unlock(acdrom.read_lock); + if (hit) + ret = 0; + acdrom.check_eject_delay = ret ? 0 : 100; + acdrom_dbg("f%c %d:%02d:%02d %d%s\n", + buf_sub ? 's' : (cdda ? 'c' : 'd'), + time[0], time[1], time[2], hit, ret ? " ERR" : ""); + return ret; +} + +// time: msf in non-bcd format +int cdra_readTrack(const unsigned char *time) +{ + if (!acdrom.thread && !g_cd_handle) { + // just forward to ISOreadTrack to avoid extra copying + return ISOreadTrack(time, NULL); + } + return cdra_do_read(time, 0, NULL, NULL); +} + +int cdra_readCDDA(const unsigned char *time, void *buffer) +{ + return cdra_do_read(time, 1, buffer, NULL); +} + +int cdra_readSub(const unsigned char *time, void *buffer) +{ + if (!acdrom.thread && !g_cd_handle) + return ISOreadSub(time, buffer); + if (!acdrom.have_subchannel) + return -1; + acdrom_dbg("s %d:%02d:%02d\n", time[0], time[1], time[2]); + return cdra_do_read(time, 0, NULL, buffer); +} + +// pointer to cached buffer from last cdra_readTrack() call +void *cdra_getBuffer(void) +{ + //acdrom_dbg("%s\n", __func__); + if (!acdrom.thread && !g_cd_handle) + return ISOgetBuffer(); + return acdrom.buf_local + 12; +} + +int cdra_getStatus(struct CdrStat *stat) +{ + int ret; + CDR__getStatus(stat); + if (g_cd_handle) + ret = rcdrom_getStatus(stat); + else + ret = ISOgetStatus(stat); + return ret; +} + +int cdra_is_physical(void) +{ + return !!g_cd_handle; +} + +int cdra_check_eject(int *inserted) +{ + if (!g_cd_handle || acdrom.do_prefetch || acdrom.check_eject_delay-- > 0) + return 0; + acdrom.check_eject_delay = 100; + *inserted = cdrom_is_media_inserted(g_cd_handle); // 1-2ms + return 1; +} + +void cdra_set_buf_count(int newcount) +{ + if (acdrom.buf_cnt == newcount) + return; + cdra_stop_thread(); + acdrom.buf_cnt = newcount; + cdra_start_thread(); +} + +#else + +// phys. CD-ROM without a cache is unusable so not implemented +#ifdef HAVE_CDROM +#error "HAVE_CDROM requires USE_ASYNC_CDROM" +#endif + +// just forward to cdriso +int cdra_init(void) +{ + return ISOinit(); +} + +void cdra_shutdown(void) +{ + ISOshutdown(); +} + +int cdra_open(void) +{ + return ISOopen(GetIsoFile()); +} + +void cdra_close(void) +{ + ISOclose(); +} + +int cdra_getTN(unsigned char *tn) +{ + return ISOgetTN(tn); +} + +int cdra_getTD(int track, unsigned char *rt) +{ + return ISOgetTD(track, rt); +} + +int cdra_prefetch(unsigned char m, unsigned char s, unsigned char f) +{ + return 1; // always hit +} + +// time: msf in non-bcd format +int cdra_readTrack(const unsigned char *time) +{ + return ISOreadTrack(time, NULL); +} + +int cdra_readCDDA(const unsigned char *time, void *buffer) +{ + return ISOreadCDDA(time, buffer); +} + +int cdra_readSub(const unsigned char *time, void *buffer) +{ + return ISOreadSub(time, buffer); +} + +// pointer to cached buffer from last cdra_readTrack() call +void *cdra_getBuffer(void) +{ + return ISOgetBuffer(); +} + +int cdra_getStatus(struct CdrStat *stat) +{ + return ISOgetStatus(stat); +} + +int cdra_is_physical(void) { return 0; } +int cdra_check_eject(int *inserted) { return 0; } +void cdra_stop_thread(void) {} +void cdra_set_buf_count(int newcount) {} + +#endif + +// vim:sw=3:ts=3:expandtab diff --git a/libpcsxcore/cdrom-async.h b/libpcsxcore/cdrom-async.h new file mode 100644 index 00000000..02fe6b71 --- /dev/null +++ b/libpcsxcore/cdrom-async.h @@ -0,0 +1,29 @@ + +#ifdef __cplusplus +extern "C" { +#endif + +struct CdrStat; + +int cdra_init(void); +void cdra_shutdown(void); +int cdra_open(void); +void cdra_close(void); +int cdra_getTN(unsigned char *tn); +int cdra_getTD(int track, unsigned char *rt); +int cdra_getStatus(struct CdrStat *stat); +int cdra_readTrack(const unsigned char *time); +int cdra_readCDDA(const unsigned char *time, void *buffer); +int cdra_readSub(const unsigned char *time, void *buffer); +int cdra_prefetch(unsigned char m, unsigned char s, unsigned char f); + +int cdra_is_physical(void); +int cdra_check_eject(int *inserted); +void cdra_stop_thread(void); +void cdra_set_buf_count(int count); + +void *cdra_getBuffer(void); + +#ifdef __cplusplus +} +#endif diff --git a/libpcsxcore/cdrom.c b/libpcsxcore/cdrom.c index 335c2dc5..516ca8ed 100644 --- a/libpcsxcore/cdrom.c +++ b/libpcsxcore/cdrom.c @@ -23,6 +23,7 @@ #include #include "cdrom.h" +#include "cdrom-async.h" #include "misc.h" #include "ppf.h" #include "psxdma.h" @@ -125,6 +126,18 @@ static struct { } cdr; static s16 read_buf[CD_FRAMESIZE_RAW/2]; +struct SubQ { + char res0[12]; + unsigned char ControlAndADR; + unsigned char TrackNumber; + unsigned char IndexNumber; + unsigned char TrackRelativeAddress[3]; + unsigned char Filler; + unsigned char AbsoluteAddress[3]; + unsigned char CRC[2]; + char res1[72]; +}; + /* CD-ROM magic numbers */ #define CdlSync 0 /* nocash documentation : "Uh, actually, returns error code 40h = Invalid Command...?" */ #define CdlNop 1 @@ -238,19 +251,6 @@ static unsigned int msf2sec(const u8 *msf) { return ((msf[0] * 60 + msf[1]) * 75) + msf[2]; } -// for that weird psemu API.. -static unsigned int fsm2sec(const u8 *msf) { - return ((msf[2] * 60 + msf[1]) * 75) + msf[0]; -} - -static void sec2msf(unsigned int s, u8 *msf) { - msf[0] = s / 75 / 60; - s = s - msf[0] * 75 * 60; - msf[1] = s / 75; - s = s - msf[1] * 75; - msf[2] = s; -} - // cdrPlayReadInterrupt #define CDRPLAYREAD_INT(eCycle, isFirst) { \ u32 e_ = eCycle; \ @@ -269,7 +269,6 @@ static void sec2msf(unsigned int s, u8 *msf) { } #define StopCdda() { \ - if (cdr.Play && !Config.Cdda) CDR_stop(); \ cdr.Play = FALSE; \ cdr.FastForward = 0; \ cdr.FastBackward = 0; \ @@ -327,7 +326,7 @@ void cdrLidSeekInterrupt(void) //StopReading(); SetPlaySeekRead(cdr.StatP, 0); - if (CDR_getStatus(&cdr_stat) == -1) + if (cdra_getStatus(&cdr_stat) == -1) return; if (cdr_stat.Status & STATUS_SHELLOPEN) @@ -339,7 +338,7 @@ void cdrLidSeekInterrupt(void) break; case DRIVESTATE_LID_OPEN: - if (CDR_getStatus(&cdr_stat) == -1) + if (cdra_getStatus(&cdr_stat) != 0) cdr_stat.Status &= ~STATUS_SHELLOPEN; // 02, 12, 10 @@ -412,8 +411,8 @@ static void Find_CurTrack(const u8 *time) current = msf2sec(time); for (cdr.CurTrack = 1; cdr.CurTrack < cdr.ResultTN[1]; cdr.CurTrack++) { - CDR_getTD(cdr.CurTrack + 1, cdr.ResultTD); - sect = fsm2sec(cdr.ResultTD); + cdra_getTD(cdr.CurTrack + 1, cdr.ResultTD); + sect = msf2sec(cdr.ResultTD); if (sect - current >= 150) break; } @@ -425,22 +424,20 @@ static void generate_subq(const u8 *time) unsigned int this_s, start_s, next_s, pregap; int relative_s; - CDR_getTD(cdr.CurTrack, start); + cdra_getTD(cdr.CurTrack, start); if (cdr.CurTrack + 1 <= cdr.ResultTN[1]) { pregap = 150; - CDR_getTD(cdr.CurTrack + 1, next); + cdra_getTD(cdr.CurTrack + 1, next); } else { // last track - cd size pregap = 0; - next[0] = cdr.SetSectorEnd[2]; - next[1] = cdr.SetSectorEnd[1]; - next[2] = cdr.SetSectorEnd[0]; + memcpy(next, cdr.SetSectorEnd, 3); } this_s = msf2sec(time); - start_s = fsm2sec(start); - next_s = fsm2sec(next); + start_s = msf2sec(start); + next_s = msf2sec(next); cdr.TrackChanged = FALSE; @@ -457,7 +454,8 @@ static void generate_subq(const u8 *time) cdr.subq.Index = 0; relative_s = -relative_s; } - sec2msf(relative_s, cdr.subq.Relative); + lba2msf(relative_s, &cdr.subq.Relative[0], + &cdr.subq.Relative[1], &cdr.subq.Relative[2]); cdr.subq.Track = itob(cdr.CurTrack); cdr.subq.Relative[0] = itob(cdr.subq.Relative[0]); @@ -470,41 +468,37 @@ static void generate_subq(const u8 *time) static int ReadTrack(const u8 *time) { - unsigned char tmp[3]; - int read_ok; + int ret; - tmp[0] = itob(time[0]); - tmp[1] = itob(time[1]); - tmp[2] = itob(time[2]); + CDR_LOG("ReadTrack *** %02d:%02d:%02d\n", tmp[0], tmp[1], tmp[2]); - CDR_LOG("ReadTrack *** %02x:%02x:%02x\n", tmp[0], tmp[1], tmp[2]); - - if (memcmp(cdr.Prev, tmp, 3) == 0) + if (memcmp(cdr.Prev, time, 3) == 0) return 1; - read_ok = CDR_readTrack(tmp); - if (read_ok) - memcpy(cdr.Prev, tmp, 3); - return read_ok; + ret = cdra_readTrack(time); + if (ret != 0) + memcpy(cdr.Prev, time, 3); + return ret == 0; } static void UpdateSubq(const u8 *time) { - const struct SubQ *subq; - int s = MSF2SECT(time[0], time[1], time[2]); + int ret = -1, s = MSF2SECT(time[0], time[1], time[2]); + struct SubQ subq; u16 crc; if (CheckSBI(s)) return; - subq = (struct SubQ *)CDR_getBufferSub(s); - if (subq != NULL && cdr.CurTrack == 1) { - crc = calcCrc((u8 *)subq + 12, 10); - if (crc == (((u16)subq->CRC[0] << 8) | subq->CRC[1])) { - cdr.subq.Track = subq->TrackNumber; - cdr.subq.Index = subq->IndexNumber; - memcpy(cdr.subq.Relative, subq->TrackRelativeAddress, 3); - memcpy(cdr.subq.Absolute, subq->AbsoluteAddress, 3); + if (cdr.CurTrack == 1) + ret = cdra_readSub(time, &subq); + if (ret == 0) { + crc = calcCrc((u8 *)&subq + 12, 10); + if (crc == (((u16)subq.CRC[0] << 8) | subq.CRC[1])) { + cdr.subq.Track = subq.TrackNumber; + cdr.subq.Index = subq.IndexNumber; + memcpy(cdr.subq.Relative, subq.TrackRelativeAddress, 3); + memcpy(cdr.subq.Absolute, subq.AbsoluteAddress, 3); } else { CDR_LOG_I("subq bad crc @%02d:%02d:%02d\n", @@ -669,7 +663,7 @@ static int msfiEq(const u8 *a, const u8 *b) void cdrPlayReadInterrupt(void) { - int hit = CDR_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]); + int hit = cdra_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]); if (!hit && cdr.PhysCdPropagations++ < 222) { // this propagates real cdrom delays to the emulated game CDRPLAYREAD_INT(cdReadTime / 2, 0); @@ -699,7 +693,7 @@ void cdrPlayReadInterrupt(void) cdr.DriveState = DRIVESTATE_PAUSED; } else { - CDR_readCDDA(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2], (u8 *)read_buf); + cdra_readCDDA(cdr.SetSectorPlay, read_buf); } if (!cdr.IrqStat && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT))) @@ -711,7 +705,7 @@ void cdrPlayReadInterrupt(void) } msfiAdd(cdr.SetSectorPlay, 1); - CDR_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]); + cdra_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]); // update for CdlGetlocP/autopause generate_subq(cdr.SetSectorPlay); @@ -721,7 +715,7 @@ void cdrPlayReadInterrupt(void) static void softReset(void) { - CDR_getStatus(&cdr_stat); + cdra_getStatus(&cdr_stat); if (cdr_stat.Status & STATUS_SHELLOPEN) { cdr.DriveState = DRIVESTATE_LID_OPEN; cdr.StatP = STATUS_SHELLOPEN; @@ -753,7 +747,6 @@ void cdrInterrupt(void) { u32 second_resp_time = 0; const void *buf; u8 ParamC; - u8 set_loc[3]; int read_ok; u16 not_ready = 0; u8 IrqStat = Acknowledge; @@ -768,7 +761,7 @@ void cdrInterrupt(void) { } if (cdr.Irq1Pending) { // hand out the "newest" sector, according to nocash - cdrUpdateTransferBuf(CDR_getBuffer()); + cdrUpdateTransferBuf(cdra_getBuffer()); CDR_LOG_I("%x:%02x:%02x loaded on ack, cmd=%02x res=%02x\n", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2], cdr.CmdInProgress, cdr.Irq1Pending); @@ -833,6 +826,7 @@ void cdrInterrupt(void) { } else { + u8 set_loc[3]; for (i = 0; i < 3; i++) set_loc[i] = btoi(cdr.Param[i]); if ((msfiEq(cdr.SetSector, set_loc)) //|| msfiEq(cdr.Param, cdr.Transfer)) @@ -866,11 +860,9 @@ void cdrInterrupt(void) { CDR_LOG("PLAY track %d\n", cdr.CurTrack); - if (CDR_getTD((u8)cdr.CurTrack, cdr.ResultTD) != -1) { - for (i = 0; i < 3; i++) - set_loc[i] = cdr.ResultTD[2 - i]; - seekTime = cdrSeekTime(set_loc); - memcpy(cdr.SetSectorPlay, set_loc, 3); + if (cdra_getTD(cdr.CurTrack, cdr.ResultTD) != -1) { + seekTime = cdrSeekTime(cdr.ResultTD); + memcpy(cdr.SetSectorPlay, cdr.ResultTD, 3); } } else if (cdr.SetlocPending) { @@ -903,9 +895,6 @@ void cdrInterrupt(void) { cdr.ReportDelay = 60; cdr.sectorsRead = 0; - if (!Config.Cdda) - CDR_play(cdr.SetSectorPlay); - SetPlaySeekRead(cdr.StatP, STATUS_SEEK | STATUS_ROTATING); // BIOS player - set flag again @@ -950,11 +939,8 @@ void cdrInterrupt(void) { case CdlStop: if (cdr.Play) { // grab time for current track - CDR_getTD((u8)(cdr.CurTrack), cdr.ResultTD); - - cdr.SetSectorPlay[0] = cdr.ResultTD[2]; - cdr.SetSectorPlay[1] = cdr.ResultTD[1]; - cdr.SetSectorPlay[2] = cdr.ResultTD[0]; + cdra_getTD(cdr.CurTrack, cdr.ResultTD); + memcpy(cdr.SetSectorPlay, cdr.ResultTD, 3); } StopCdda(); @@ -1097,7 +1083,7 @@ void cdrInterrupt(void) { break; case CdlGetTN: - if (CDR_getTN(cdr.ResultTN) == -1) { + if (cdra_getTN(cdr.ResultTN) != 0) { assert(0); } SetResultSize_(3); @@ -1107,15 +1093,15 @@ void cdrInterrupt(void) { case CdlGetTD: cdr.Track = btoi(cdr.Param[0]); - if (CDR_getTD(cdr.Track, cdr.ResultTD) == -1) { + if (cdra_getTD(cdr.Track, cdr.ResultTD) != 0) { error = ERROR_BAD_ARGVAL; goto set_error; } SetResultSize_(3); - cdr.Result[1] = itob(cdr.ResultTD[2]); + cdr.Result[1] = itob(cdr.ResultTD[0]); cdr.Result[2] = itob(cdr.ResultTD[1]); // no sector number - //cdr.Result[3] = itob(cdr.ResultTD[0]); + //cdr.Result[3] = itob(cdr.ResultTD[2]); break; case CdlSeekL: @@ -1128,7 +1114,7 @@ void cdrInterrupt(void) { seekTime = cdrSeekTime(cdr.SetSector); memcpy(cdr.SetSectorPlay, cdr.SetSector, 4); cdr.DriveState = DRIVESTATE_SEEK; - CDR_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], + cdra_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]); /* Crusaders of Might and Magic = 0.5x-4x @@ -1155,7 +1141,7 @@ void cdrInterrupt(void) { Find_CurTrack(cdr.SetSectorPlay); read_ok = ReadTrack(cdr.SetSectorPlay); - if (read_ok && (buf = CDR_getBuffer())) + if (read_ok && (buf = cdra_getBuffer())) memcpy(cdr.LocL, buf, 8); UpdateSubq(cdr.SetSectorPlay); cdr.DriveState = DRIVESTATE_STANDBY; @@ -1193,7 +1179,7 @@ void cdrInterrupt(void) { cdr.Result[3] = 0; // 0x10 - audio | 0x40 - disk missing | 0x80 - unlicensed - if (CDR_getStatus(&cdr_stat) == -1 || cdr_stat.Type == 0 || cdr_stat.Type == 0xff) { + if (cdra_getStatus(&cdr_stat) != 0 || cdr_stat.Type == 0 || cdr_stat.Type == 0xff) { cdr.Result[1] = 0xc0; } else { @@ -1267,7 +1253,7 @@ void cdrInterrupt(void) { cdr.SubqForwardSectors = 1; cdr.sectorsRead = 0; cdr.DriveState = DRIVESTATE_SEEK; - CDR_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], + cdra_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]); cycles = (cdr.Mode & MODE_SPEED) ? cdReadTime : cdReadTime * 2; @@ -1385,7 +1371,7 @@ static void cdrReadInterrupt(void) read_ok = ReadTrack(cdr.SetSectorPlay); if (read_ok) - buf = CDR_getBuffer(); + buf = cdra_getBuffer(); if (buf == NULL) read_ok = 0; @@ -1448,7 +1434,7 @@ static void cdrReadInterrupt(void) cdrReadInterruptSetResult(cdr.StatP); msfiAdd(cdr.SetSectorPlay, 1); - CDR_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]); + cdra_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]); CDRPLAYREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime, 0); } @@ -1750,13 +1736,8 @@ void cdrDmaInterrupt(void) static void getCdInfo(void) { - u8 tmp; - - CDR_getTN(cdr.ResultTN); - CDR_getTD(0, cdr.SetSectorEnd); - tmp = cdr.SetSectorEnd[0]; - cdr.SetSectorEnd[0] = cdr.SetSectorEnd[2]; - cdr.SetSectorEnd[2] = tmp; + cdra_getTN(cdr.ResultTN); + cdra_getTD(0, cdr.SetSectorEnd); } void cdrReset() { @@ -1781,10 +1762,7 @@ int cdrFreeze(void *f, int Mode) { u32 tmp; u8 tmpp[3]; - if (Mode == 0 && !Config.Cdda) - CDR_stop(); - - cdr.freeze_ver = 0x63647202; + cdr.freeze_ver = 0x63647203; gzfreeze(&cdr, sizeof(cdr)); if (Mode == 1) { @@ -1804,9 +1782,12 @@ int cdrFreeze(void *f, int Mode) { cdr.SubqForwardSectors = SUBQ_FORWARD_SECTORS; // read right sub data - tmpp[0] = btoi(cdr.Prev[0]); - tmpp[1] = btoi(cdr.Prev[1]); - tmpp[2] = btoi(cdr.Prev[2]); + memcpy(tmpp, cdr.Prev, sizeof(tmpp)); + if (cdr.freeze_ver < 0x63647203) { + tmpp[0] = btoi(tmpp[0]); + tmpp[1] = btoi(tmpp[1]); + tmpp[2] = btoi(tmpp[2]); + } cdr.Prev[0]++; ReadTrack(tmpp); @@ -1815,8 +1796,6 @@ int cdrFreeze(void *f, int Mode) { memcpy(cdr.SetSectorPlay, cdr.SetSector, 3); Find_CurTrack(cdr.SetSectorPlay); - if (!Config.Cdda) - CDR_play(cdr.SetSectorPlay); } if (!cdr.Muted) ll = cdr.AttenuatorLeftToLeft, lr = cdr.AttenuatorLeftToLeft, diff --git a/libpcsxcore/cdrom.h b/libpcsxcore/cdrom.h index ee0b4d4b..b8682b03 100644 --- a/libpcsxcore/cdrom.h +++ b/libpcsxcore/cdrom.h @@ -38,13 +38,21 @@ extern "C" { #define MIN_VALUE(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; }) #define MAX_VALUE(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _a : _b; }) -#define MSF2SECT(m, s, f) (((m) * 60 + (s) - 2) * 75 + (f)) - #define CD_FRAMESIZE_RAW 2352 #define DATA_SIZE (CD_FRAMESIZE_RAW - 12) #define SUB_FRAMESIZE 96 +#define MSF2SECT(m, s, f) (((m) * 60 + (s) - 2) * 75 + (f)) + +static inline void lba2msf(unsigned int lba, u8 *m, u8 *s, u8 *f) { + *m = lba / 75 / 60; + lba = lba - *m * 75 * 60; + *s = lba / 75; + lba = lba - *s * 75; + *f = lba; +} + void cdrReset(); void cdrInterrupt(void); diff --git a/libpcsxcore/database.c b/libpcsxcore/database.c index 2e382e3c..c05b80cd 100644 --- a/libpcsxcore/database.c +++ b/libpcsxcore/database.c @@ -1,6 +1,7 @@ #include "misc.h" #include "sio.h" #include "ppf.h" +#include "cdrom-async.h" #include "new_dynarec/new_dynarec.h" #include "lightrec/plugin.h" @@ -274,7 +275,9 @@ static const u16 libcrypt_sectors[16] = { int check_unsatisfied_libcrypt(void) { const char *p = CdromId + 4; + u8 buf_sub[SUB_FRAMESIZE]; u16 id, key = 0; + u8 msf[3]; size_t i; if (strncmp(CdromId, "SCE", 3) && strncmp(CdromId, "SLE", 3)) @@ -289,7 +292,8 @@ int check_unsatisfied_libcrypt(void) return 0; // detected a protected game - if (!CDR_getBufferSub(libcrypt_sectors[0]) && !sbi_sectors) { + lba2msf(libcrypt_sectors[0] + 150, &msf[0], &msf[1], &msf[2]); + if (!sbi_sectors && cdra_readSub(msf, buf_sub) != 0) { SysPrintf("==================================================\n"); SysPrintf("LibCrypt game detected with missing SBI/subchannel\n"); SysPrintf("==================================================\n"); diff --git a/libpcsxcore/misc.c b/libpcsxcore/misc.c index d4c886f4..68982abd 100644 --- a/libpcsxcore/misc.c +++ b/libpcsxcore/misc.c @@ -26,6 +26,7 @@ #include #include "misc.h" #include "cdrom.h" +#include "cdrom-async.h" #include "mdec.h" #include "gpu.h" #include "ppf.h" @@ -71,17 +72,12 @@ static void mmssdd( char *b, char *p ) s = block / 75; // seconds d = block - s * 75; // seconds rest - m = ((m / 10) << 4) | m % 10; - s = ((s / 10) << 4) | s % 10; - d = ((d / 10) << 4) | d % 10; - p[0] = m; p[1] = s; p[2] = d; } #define incTime() \ - time[0] = btoi(time[0]); time[1] = btoi(time[1]); time[2] = btoi(time[2]); \ time[2]++; \ if(time[2] == 75) { \ time[2] = 0; \ @@ -91,11 +87,10 @@ static void mmssdd( char *b, char *p ) time[0]++; \ } \ } \ - time[0] = itob(time[0]); time[1] = itob(time[1]); time[2] = itob(time[2]); #define READTRACK() \ - if (!CDR_readTrack(time)) return -1; \ - buf = (void *)CDR_getBuffer(); \ + if (cdra_readTrack(time)) return -1; \ + buf = cdra_getBuffer(); \ if (buf == NULL) return -1; \ else CheckPPFCache((u8 *)buf, time[0], time[1], time[2]); @@ -216,7 +211,7 @@ int LoadCdrom() { return 0; } - time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10); + time[0] = 0; time[1] = 2; time[2] = 0x10; READTRACK(); @@ -320,7 +315,7 @@ int LoadCdromFile(const char *filename, EXE_HEADER *head, u8 *time_bcd_out) { p1++; snprintf(exename, sizeof(exename), "%s", p1); - time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10); + time[0] = 0; time[1] = 2; time[2] = 0x10; READTRACK(); @@ -374,14 +369,14 @@ int CheckCdrom() { memset(CdromId, 0, sizeof(CdromId)); memset(exename, 0, sizeof(exename)); - time[0] = itob(0); - time[1] = itob(2); - time[2] = itob(0x10); + time[0] = 0; + time[1] = 2; + time[2] = 0x10; if (!Config.HLE && Config.SlowBoot) { // boot to BIOS in case of CDDA or lid is open - CDR_getStatus(&stat); - if ((stat.Status & 0x10) || stat.Type == 2 || !CDR_readTrack(time)) + cdra_getStatus(&stat); + if ((stat.Status & 0x10) || stat.Type == 2 || cdra_readTrack(time)) return 0; } READTRACK(); @@ -967,7 +962,7 @@ static unsigned short crctab[256] = { 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 }; -u16 calcCrc(u8 *d, int len) { +u16 calcCrc(const u8 *d, int len) { u16 crc = 0; int i; diff --git a/libpcsxcore/misc.h b/libpcsxcore/misc.h index 22245d88..303af7b7 100644 --- a/libpcsxcore/misc.h +++ b/libpcsxcore/misc.h @@ -72,7 +72,7 @@ int SendPcsxInfo(); int RecvPcsxInfo(); void trim(char *str); -u16 calcCrc(u8 *d, int len); +u16 calcCrc(const u8 *d, int len); #ifdef __cplusplus } diff --git a/libpcsxcore/plugins.c b/libpcsxcore/plugins.c index 369ea974..e59e8c60 100644 --- a/libpcsxcore/plugins.c +++ b/libpcsxcore/plugins.c @@ -23,6 +23,7 @@ #include "plugins.h" #include "cdriso.h" +#include "cdrom-async.h" #include "psxcounters.h" static char IsoFile[MAXPATHLEN] = ""; @@ -49,27 +50,6 @@ GPUshowScreenPic GPU_showScreenPic; GPUvBlank GPU_vBlank; GPUgetScreenInfo GPU_getScreenInfo; -CDRinit CDR_init; -CDRshutdown CDR_shutdown; -CDRopen CDR_open; -CDRclose CDR_close; -CDRtest CDR_test; -CDRgetTN CDR_getTN; -CDRgetTD CDR_getTD; -CDRreadTrack CDR_readTrack; -CDRgetBuffer CDR_getBuffer; -CDRplay CDR_play; -CDRstop CDR_stop; -CDRgetStatus CDR_getStatus; -CDRgetDriveLetter CDR_getDriveLetter; -CDRgetBufferSub CDR_getBufferSub; -CDRconfigure CDR_configure; -CDRabout CDR_about; -CDRsetfilename CDR_setfilename; -CDRreadCDDA CDR_readCDDA; -CDRgetTE CDR_getTE; -CDRprefetch CDR_prefetch; - SPUinit SPU_init; SPUshutdown SPU_shutdown; SPUopen SPU_open; @@ -239,12 +219,7 @@ static int LoadGPUplugin(const char *GPUdll) { return 0; } -void *hCDRDriver = NULL; - -long CALLBACK CDR__play(unsigned char *sector) { return 0; } -long CALLBACK CDR__stop(void) { return 0; } - -long CALLBACK CDR__getStatus(struct CdrStat *stat) { +int CDR__getStatus(struct CdrStat *stat) { if (cdOpenCaseTime < 0 || cdOpenCaseTime > (s64)time(NULL)) stat->Status = 0x10; else @@ -253,61 +228,6 @@ long CALLBACK CDR__getStatus(struct CdrStat *stat) { return 0; } -char* CALLBACK CDR__getDriveLetter(void) { return NULL; } -long CALLBACK CDR__configure(void) { return 0; } -long CALLBACK CDR__test(void) { return 0; } -void CALLBACK CDR__about(void) {} -long CALLBACK CDR__setfilename(char*filename) { return 0; } -long CALLBACK CDR__prefetch(u8 m, u8 s, u8 f) { return 1; } - -#define LoadCdrSym1(dest, name) \ - LoadSym(CDR_##dest, CDR##dest, name, TRUE); - -#define LoadCdrSym0(dest, name) \ - LoadSym(CDR_##dest, CDR##dest, name, FALSE); \ - if (CDR_##dest == NULL) CDR_##dest = (CDR##dest) CDR__##dest; - -#define LoadCdrSymN(dest, name) \ - LoadSym(CDR_##dest, CDR##dest, name, FALSE); - -static int LoadCDRplugin(const char *CDRdll) { - void *drv; - - if (CDRdll == NULL) { - cdrIsoInit(); - return 0; - } - - hCDRDriver = SysLoadLibrary(CDRdll); - if (hCDRDriver == NULL) { - CDR_configure = NULL; - SysMessage (_("Could not load CD-ROM plugin %s!"), CDRdll); return -1; - } - drv = hCDRDriver; - LoadCdrSym1(init, "CDRinit"); - LoadCdrSym1(shutdown, "CDRshutdown"); - LoadCdrSym1(open, "CDRopen"); - LoadCdrSym1(close, "CDRclose"); - LoadCdrSym1(getTN, "CDRgetTN"); - LoadCdrSym1(getTD, "CDRgetTD"); - LoadCdrSym1(readTrack, "CDRreadTrack"); - LoadCdrSym1(getBuffer, "CDRgetBuffer"); - LoadCdrSym1(getBufferSub, "CDRgetBufferSub"); - LoadCdrSym0(play, "CDRplay"); - LoadCdrSym0(stop, "CDRstop"); - LoadCdrSym0(getStatus, "CDRgetStatus"); - LoadCdrSym0(getDriveLetter, "CDRgetDriveLetter"); - LoadCdrSym0(configure, "CDRconfigure"); - LoadCdrSym0(test, "CDRtest"); - LoadCdrSym0(about, "CDRabout"); - LoadCdrSym0(setfilename, "CDRsetfilename"); - LoadCdrSymN(readCDDA, "CDRreadCDDA"); - LoadCdrSymN(getTE, "CDRgetTE"); - LoadCdrSym0(prefetch, "CDRprefetch"); - - return 0; -} - static void *hSPUDriver = NULL; static void CALLBACK SPU__registerScheduleCb(void (CALLBACK *cb)(unsigned int)) {} static void CALLBACK SPU__setCDvol(unsigned char ll, unsigned char lr, @@ -1161,19 +1081,12 @@ static int LoadSIO1plugin(const char *SIO1dll) { #endif int LoadPlugins() { - int ret; char Plugin[MAXPATHLEN * 2]; + int ret; ReleasePlugins(); SysLibError(); - if (UsingIso()) { - LoadCDRplugin(NULL); - } else { - sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Cdr); - if (LoadCDRplugin(Plugin) == -1) return -1; - } - sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Gpu); if (LoadGPUplugin(Plugin) == -1) return -1; @@ -1199,7 +1112,7 @@ int LoadPlugins() { if (LoadSIO1plugin(Plugin) == -1) return -1; #endif - ret = CDR_init(); + ret = cdra_init(); if (ret < 0) { SysMessage (_("Error initializing CD-ROM plugin: %d"), ret); return -1; } ret = GPU_init(); if (ret < 0) { SysMessage (_("Error initializing GPU plugin: %d"), ret); return -1; } @@ -1231,7 +1144,7 @@ void ReleasePlugins() { } NetOpened = FALSE; - if (hCDRDriver != NULL || cdrIsoActive()) CDR_shutdown(); + cdra_shutdown(); if (hGPUDriver != NULL) GPU_shutdown(); if (hSPUDriver != NULL) SPU_shutdown(); if (hPAD1Driver != NULL) PAD1_shutdown(); @@ -1239,7 +1152,6 @@ void ReleasePlugins() { if (Config.UseNet && hNETDriver != NULL) NET_shutdown(); - if (hCDRDriver != NULL) { SysCloseLibrary(hCDRDriver); hCDRDriver = NULL; } if (hGPUDriver != NULL) { SysCloseLibrary(hGPUDriver); hGPUDriver = NULL; } if (hSPUDriver != NULL) { SysCloseLibrary(hSPUDriver); hSPUDriver = NULL; } if (hPAD1Driver != NULL) { SysCloseLibrary(hPAD1Driver); hPAD1Driver = NULL; } @@ -1261,18 +1173,8 @@ void ReleasePlugins() { // for CD swap int ReloadCdromPlugin() { - if (hCDRDriver != NULL || cdrIsoActive()) CDR_shutdown(); - if (hCDRDriver != NULL) { SysCloseLibrary(hCDRDriver); hCDRDriver = NULL; } - - if (UsingIso()) { - LoadCDRplugin(NULL); - } else { - char Plugin[MAXPATHLEN * 2]; - sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Cdr); - if (LoadCDRplugin(Plugin) == -1) return -1; - } - - return CDR_init(); + cdra_shutdown(); + return cdra_init(); } void SetIsoFile(const char *filename) { diff --git a/libpcsxcore/plugins.h b/libpcsxcore/plugins.h index 4054bf67..b2efbcea 100644 --- a/libpcsxcore/plugins.h +++ b/libpcsxcore/plugins.h @@ -97,67 +97,14 @@ extern GPUshowScreenPic GPU_showScreenPic; extern GPUvBlank GPU_vBlank; extern GPUgetScreenInfo GPU_getScreenInfo; -// CD-ROM Functions -typedef long (CALLBACK* CDRinit)(void); -typedef long (CALLBACK* CDRshutdown)(void); -typedef long (CALLBACK* CDRopen)(void); -typedef long (CALLBACK* CDRclose)(void); -typedef long (CALLBACK* CDRgetTN)(unsigned char *); -typedef long (CALLBACK* CDRgetTD)(unsigned char, unsigned char *); -typedef boolean (CALLBACK* CDRreadTrack)(unsigned char *); -typedef unsigned char* (CALLBACK* CDRgetBuffer)(void); -typedef unsigned char* (CALLBACK* CDRgetBufferSub)(int sector); -typedef long (CALLBACK* CDRconfigure)(void); -typedef long (CALLBACK* CDRtest)(void); -typedef void (CALLBACK* CDRabout)(void); -typedef long (CALLBACK* CDRplay)(unsigned char *); -typedef long (CALLBACK* CDRstop)(void); -typedef long (CALLBACK* CDRsetfilename)(char *); +// CD-ROM struct CdrStat { uint32_t Type; // DATA, CDDA uint32_t Status; // same as cdr.StatP unsigned char Time_[3]; // unused }; -typedef long (CALLBACK* CDRgetStatus)(struct CdrStat *); -typedef char* (CALLBACK* CDRgetDriveLetter)(void); -struct SubQ { - char res0[12]; - unsigned char ControlAndADR; - unsigned char TrackNumber; - unsigned char IndexNumber; - unsigned char TrackRelativeAddress[3]; - unsigned char Filler; - unsigned char AbsoluteAddress[3]; - unsigned char CRC[2]; - char res1[72]; -}; -typedef long (CALLBACK* CDRreadCDDA)(unsigned char, unsigned char, unsigned char, unsigned char *); -typedef long (CALLBACK* CDRgetTE)(unsigned char, unsigned char *, unsigned char *, unsigned char *); -typedef long (CALLBACK* CDRprefetch)(unsigned char, unsigned char, unsigned char); - -// CD-ROM function pointers -extern CDRinit CDR_init; -extern CDRshutdown CDR_shutdown; -extern CDRopen CDR_open; -extern CDRclose CDR_close; -extern CDRtest CDR_test; -extern CDRgetTN CDR_getTN; -extern CDRgetTD CDR_getTD; -extern CDRreadTrack CDR_readTrack; -extern CDRgetBuffer CDR_getBuffer; -extern CDRgetBufferSub CDR_getBufferSub; -extern CDRplay CDR_play; -extern CDRstop CDR_stop; -extern CDRgetStatus CDR_getStatus; -extern CDRgetDriveLetter CDR_getDriveLetter; -extern CDRconfigure CDR_configure; -extern CDRabout CDR_about; -extern CDRsetfilename CDR_setfilename; -extern CDRreadCDDA CDR_readCDDA; -extern CDRgetTE CDR_getTE; -extern CDRprefetch CDR_prefetch; -long CALLBACK CDR__getStatus(struct CdrStat *stat); +int CDR__getStatus(struct CdrStat *stat); // SPU Functions typedef long (CALLBACK* SPUinit)(void); diff --git a/libpcsxcore/ppf.c b/libpcsxcore/ppf.c index 6a88e053..3dcf416e 100644 --- a/libpcsxcore/ppf.c +++ b/libpcsxcore/ppf.c @@ -94,7 +94,7 @@ void FreePPFCache() { void CheckPPFCache(unsigned char *pB, unsigned char m, unsigned char s, unsigned char f) { PPF_CACHE *pcstart, *pcend, *pcpos; - int addr = MSF2SECT(btoi(m), btoi(s), btoi(f)), pos, anz, start; + int addr = MSF2SECT(m, s, f), pos, anz, start; if (ppfCache == NULL) return; diff --git a/libpcsxcore/psxcommon.h b/libpcsxcore/psxcommon.h index 0a0bd863..68c32a91 100644 --- a/libpcsxcore/psxcommon.h +++ b/libpcsxcore/psxcommon.h @@ -117,7 +117,6 @@ void __Log(char *fmt, ...); typedef struct { char Gpu[MAXPATHLEN]; char Spu[MAXPATHLEN]; - char Cdr[MAXPATHLEN]; char Pad1[MAXPATHLEN]; char Pad2[MAXPATHLEN]; char Net[MAXPATHLEN]; @@ -132,7 +131,6 @@ typedef struct { boolean Mdec; boolean PsxAuto; boolean Cdda; - boolean AsyncCD; boolean CHD_Precache; /* loads disk image into memory, works with CHD only. */ boolean HLE; boolean SlowBoot;