libretro: support disk control interface
[pcsx_rearmed.git] / frontend / libretro.c
index e7153ac..e22ef5b 100644 (file)
 #include "../libpcsxcore/psxcounters.h"
 #include "../libpcsxcore/psxmem_map.h"
 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
 #include "../libpcsxcore/psxcounters.h"
 #include "../libpcsxcore/psxmem_map.h"
 #include "../libpcsxcore/new_dynarec/new_dynarec.h"
+#include "../libpcsxcore/cdrom.h"
+#include "../libpcsxcore/cdriso.h"
 #include "../libpcsxcore/cheat.h"
 #include "../plugins/dfsound/out.h"
 #include "../libpcsxcore/cheat.h"
 #include "../plugins/dfsound/out.h"
-#include "../plugins/gpulib/cspace.h"
+#include "cspace.h"
 #include "main.h"
 #include "plugin.h"
 #include "plugin_lib.h"
 #include "main.h"
 #include "plugin.h"
 #include "plugin_lib.h"
@@ -35,6 +37,7 @@ static bool vout_can_dupe;
 
 static int samples_sent, samples_to_send;
 static int plugins_opened;
 
 static int samples_sent, samples_to_send;
 static int plugins_opened;
+static int is_pal_mode;
 
 /* memory card data */
 extern char Mcd1Data[MCD_SIZE];
 
 /* memory card data */
 extern char Mcd1Data[MCD_SIZE];
@@ -182,6 +185,7 @@ void pl_frame_limit(void)
 
 void pl_timing_prepare(int is_pal)
 {
 
 void pl_timing_prepare(int is_pal)
 {
+       is_pal_mode = is_pal;
 }
 
 void plat_trigger_vibrate(int is_strong)
 }
 
 void plat_trigger_vibrate(int is_strong)
@@ -254,7 +258,7 @@ void retro_get_system_info(struct retro_system_info *info)
 void retro_get_system_av_info(struct retro_system_av_info *info)
 {
        memset(info, 0, sizeof(*info));
 void retro_get_system_av_info(struct retro_system_av_info *info)
 {
        memset(info, 0, sizeof(*info));
-       info->timing.fps            = 60;
+       info->timing.fps            = is_pal_mode ? 50 : 60;
        info->timing.sample_rate    = 44100;
        info->geometry.base_width   = 320;
        info->geometry.base_height  = 240;
        info->timing.sample_rate    = 44100;
        info->geometry.base_width   = 320;
        info->geometry.base_height  = 240;
@@ -361,6 +365,7 @@ bool retro_unserialize(const void *data, size_t size)
        return ret == 0 ? true : false;
 }
 
        return ret == 0 ? true : false;
 }
 
+/* cheats */
 void retro_cheat_reset(void)
 {
        ClearAllCheats();
 void retro_cheat_reset(void)
 {
        ClearAllCheats();
@@ -386,8 +391,132 @@ void retro_cheat_set(unsigned index, bool enabled, const char *code)
                Cheats[index].Enabled = enabled;
 }
 
                Cheats[index].Enabled = enabled;
 }
 
+/* multidisk support */
+static bool disk_ejected;
+static unsigned int disk_current_index;
+static struct disks_state {
+       char *fname;
+       int internal_index; // for multidisk eboots
+} disks[8];
+
+static bool disk_set_eject_state(bool ejected)
+{
+       // weird PCSX API..
+       SetCdOpenCaseTime(ejected ? -1 : (time(NULL) + 2));
+       LidInterrupt();
+
+       disk_ejected = ejected;
+       return true;
+}
+
+static bool disk_get_eject_state(void)
+{
+       /* can't be controlled by emulated software */
+       return disk_ejected;
+}
+
+static unsigned int disk_get_image_index(void)
+{
+       return disk_current_index;
+}
+
+static bool disk_set_image_index(unsigned int index)
+{
+       if (index >= sizeof(disks) / sizeof(disks[0]))
+               return false;
+
+       CdromId[0] = '\0';
+       CdromLabel[0] = '\0';
+
+       if (disks[index].fname == NULL) {
+               SysPrintf("missing disk #%u\n", index);
+               CDR_shutdown();
+
+               // RetroArch specifies "no disk" with index == count,
+               // so don't fail here..
+               disk_current_index = index;
+               return true;
+       }
+
+       SysPrintf("switching to disk %u: \"%s\" #%d\n", index,
+               disks[index].fname, disks[index].internal_index);
+
+       cdrIsoMultidiskSelect = disks[index].internal_index;
+       set_cd_image(disks[index].fname);
+       if (ReloadCdromPlugin() < 0) {
+               SysPrintf("failed to load cdr plugin\n");
+               return false;
+       }
+       if (CDR_open() < 0) {
+               SysPrintf("failed to open cdr plugin\n");
+               return false;
+       }
+
+       if (!disk_ejected) {
+               SetCdOpenCaseTime(time(NULL) + 2);
+               LidInterrupt();
+       }
+
+       disk_current_index = index;
+       return true;
+}
+
+static unsigned int disk_get_num_images(void)
+{
+       unsigned int count = 0;
+       size_t i;
+
+       for (i = 0; i < sizeof(disks) / sizeof(disks[0]); i++)
+               if (disks[i].fname != NULL)
+                       count++;
+
+       return count;
+}
+
+static bool disk_replace_image_index(unsigned index,
+       const struct retro_game_info *info)
+{
+       char *old_fname;
+       bool ret = true;
+
+       if (index >= sizeof(disks) / sizeof(disks[0]))
+               return false;
+
+       old_fname = disks[index].fname;
+       disks[index].fname = NULL;
+       disks[index].internal_index = 0;
+
+       if (info != NULL) {
+               disks[index].fname = strdup(info->path);
+               if (index == disk_current_index)
+                       ret = disk_set_image_index(index);
+       }
+
+       if (old_fname != NULL)
+               free(old_fname);
+
+       return ret;
+}
+
+static bool disk_add_image_index(void)
+{
+       // TODO??
+       return true;
+}
+
+static struct retro_disk_control_callback disk_control = {
+       .set_eject_state = disk_set_eject_state,
+       .get_eject_state = disk_get_eject_state,
+       .get_image_index = disk_get_image_index,
+       .set_image_index = disk_set_image_index,
+       .get_num_images = disk_get_num_images,
+       .replace_image_index = disk_replace_image_index,
+       .add_image_index = disk_add_image_index,
+};
+
 bool retro_load_game(const struct retro_game_info *info)
 {
 bool retro_load_game(const struct retro_game_info *info)
 {
+       size_t i;
 #ifdef FRONTEND_SUPPORTS_RGB565
        enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
        if (environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) {
 #ifdef FRONTEND_SUPPORTS_RGB565
        enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
        if (environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) {
@@ -395,12 +524,28 @@ bool retro_load_game(const struct retro_game_info *info)
        }
 #endif
 
        }
 #endif
 
+       if (info == NULL || info->path == NULL) {
+               SysPrintf("info->path required\n");
+               return false;
+       }
+
        if (plugins_opened) {
                ClosePlugins();
                plugins_opened = 0;
        }
 
        if (plugins_opened) {
                ClosePlugins();
                plugins_opened = 0;
        }
 
-       set_cd_image(info->path);
+       for (i = 0; i < sizeof(disks) / sizeof(disks[0]); i++) {
+               if (disks[i].fname != NULL) {
+                       free(disks[i].fname);
+                       disks[i].fname = NULL;
+               }
+               disks[i].internal_index = 0;
+       }
+
+       disk_current_index = 0;
+       disks[0].fname = strdup(info->path);
+
+       set_cd_image(disks[0].fname);
 
        /* have to reload after set_cd_image for correct cdr plugin */
        if (LoadPlugins() == -1) {
 
        /* have to reload after set_cd_image for correct cdr plugin */
        if (LoadPlugins() == -1) {
@@ -432,6 +577,12 @@ bool retro_load_game(const struct retro_game_info *info)
        }
        emu_on_new_cd(0);
 
        }
        emu_on_new_cd(0);
 
+       // multidisk images
+       for (i = 1; i < sizeof(disks) / sizeof(disks[0]) && i < cdrIsoMultidiskCount; i++) {
+               disks[i].fname = strdup(info->path);
+               disks[i].internal_index = i;
+       }
+
        return true;
 }
 
        return true;
 }
 
@@ -446,7 +597,7 @@ void retro_unload_game(void)
 
 unsigned retro_get_region(void)
 {
 
 unsigned retro_get_region(void)
 {
-       return RETRO_REGION_NTSC;
+       return is_pal_mode ? RETRO_REGION_PAL : RETRO_REGION_NTSC;
 }
 
 void *retro_get_memory_data(unsigned id)
 }
 
 void *retro_get_memory_data(unsigned id)
@@ -501,7 +652,7 @@ void retro_run(void)
        stop = 0;
        psxCpu->Execute();
 
        stop = 0;
        psxCpu->Execute();
 
-       samples_to_send += 44100 / 60;
+       samples_to_send += is_pal_mode ? 44100 / 50 : 44100 / 60;
 
        video_cb((vout_fb_dirty || !vout_can_dupe) ? vout_buf : NULL,
                vout_width, vout_height, vout_width * 2);
 
        video_cb((vout_fb_dirty || !vout_can_dupe) ? vout_buf : NULL,
                vout_width, vout_height, vout_width * 2);
@@ -549,6 +700,7 @@ void retro_init(void)
        environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
 
        environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &vout_can_dupe);
        environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
 
        environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &vout_can_dupe);
+       environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE, &disk_control);
 
        /* Set how much slower PSX CPU runs * 100 (so that 200 is 2 times)
         * we have to do this because cache misses and some IO penalties
 
        /* Set how much slower PSX CPU runs * 100 (so that 200 is 2 times)
         * we have to do this because cache misses and some IO penalties