Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Makefile.libretro
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
DEBUG = 0
HAVE_VFS_FD := 1
# Dolphin/JoyBus support
HAVE_DOLPHIN ?= 0
CORE_DIR := .
BUILD_DIR := libretro-build

Expand Down Expand Up @@ -438,6 +440,13 @@ endif

DEFINES += -DHAVE_STRNDUP -DHAVE_STRDUP -DDISABLE_THREADING -DMINIMAL_CORE=2

# Enable Dolphin/JoyBus support on desktop and Android
ifeq ($(HAVE_DOLPHIN),0)
ifneq (,$(or $(findstring unix,$(platform)),$(findstring osx,$(platform)),$(findstring win,$(platform)),$(findstring mingw,$(platform)),$(findstring android,$(platform)),$(findstring linux,$(platform)),$(findstring rpi,$(platform))))
HAVE_DOLPHIN = 1
endif
endif

include $(BUILD_DIR)/Makefile.common

OBJS := $(SOURCES_C:.c=.o) $(SOURCES_ASM:.S=.o)
Expand Down
5 changes: 5 additions & 0 deletions libretro-build/Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,8 @@ endif
else
SOURCES_C += $(CORE_DIR)/src/util/vfs/vfs-file.c
endif

ifeq ($(HAVE_DOLPHIN),1)
SOURCES_C += $(CORE_DIR)/src/gba/sio/dolphin.c
RETRODEFS += -DENABLE_JOYBUS_DOLPHIN
endif
2 changes: 2 additions & 0 deletions libretro-build/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ LOCAL_PATH := $(call my-dir)
CORE_DIR := $(LOCAL_PATH)/../..

HAVE_VFS_FD = 1
# Dolphin/JoyBus support
HAVE_DOLPHIN = 1

include $(CORE_DIR)/libretro-build/Makefile.common

Expand Down
9 changes: 8 additions & 1 deletion src/gba/sio/dolphin.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,14 @@ int32_t _processCommand(struct GBASIODolphin* dol, uint32_t cyclesLate) {
}

if (!dol->active) {
return 0;
/* GBA BIOS: respond so Dolphin doesn't kill the connection */
if (buffer[0] == JOY_RESET || buffer[0] == JOY_POLL) {
buffer[1] = 0x00;
buffer[2] = 0x04;
buffer[3] = 0x00;
SocketSend(dol->data, &buffer[1], 3);
}
return bitsOnLine * CYCLES_PER_BIT - cyclesLate;
}

int sent = GBASIOJOYSendCommand(&dol->d, buffer[0], &buffer[1]);
Expand Down
166 changes: 166 additions & 0 deletions src/platform/libretro/libretro.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
#include <mgba/gba/core.h>
#include <mgba/gba/interface.h>
#include <mgba/internal/gba/gba.h>
#ifdef ENABLE_JOYBUS_DOLPHIN
#include <mgba/internal/gba/sio/dolphin.h>
#include <mgba-util/socket.h>
#endif
#endif
#if defined(ENABLE_JOYBUS_DOLPHIN) && !defined(M_CORE_GBA)
#error "ENABLE_JOYBUS_DOLPHIN requires M_CORE_GBA"
#endif
#include <mgba-util/memory.h>
#include <mgba-util/vfs.h>
Expand Down Expand Up @@ -136,6 +143,13 @@ static int32_t audioLowPassRange = 0;
static int32_t audioLowPassLeftPrev = 0;
static int32_t audioLowPassRightPrev = 0;

#ifdef ENABLE_JOYBUS_DOLPHIN
static struct GBASIODolphin dolphin;
static bool dolphinEnabled;
static int dolphinRetryCounter;
#define DOLPHIN_RETRY_INTERVAL 60
#endif

static const int keymap[] = {
RETRO_DEVICE_ID_JOYPAD_A,
RETRO_DEVICE_ID_JOYPAD_B,
Expand Down Expand Up @@ -1170,6 +1184,76 @@ static void _updateGbPal(void) {
}
#endif

#ifdef ENABLE_JOYBUS_DOLPHIN
static void _connectDolphin(void) {
struct Address addr;
addr.version = IPV4;
addr.ipv4 = 0x7F000001; /* 127.0.0.1 */

if (!GBASIODolphinConnect(&dolphin, &addr, 0, 0)) {
return;
}

core->setPeripheral(core, mPERIPH_GBA_LINK_PORT, &dolphin.d);

if (logCallback) {
logCallback(RETRO_LOG_INFO, "[JoyBus] Connected to Dolphin\n");
}
}

static void _disconnectDolphin(void) {
if (core) {
core->setPeripheral(core, mPERIPH_GBA_LINK_PORT, 0);
}
GBASIODolphinDestroy(&dolphin);
GBASIODolphinCreate(&dolphin);

if (logCallback) {
logCallback(RETRO_LOG_INFO, "[JoyBus] Disconnected from Dolphin\n");
}
}

static bool _isDolphinAlive(void) {
char buf;

if (!GBASIODolphinIsConnected(&dolphin)) {
return false;
}

switch (recv(dolphin.data, &buf, 1, MSG_PEEK)) {
case 0:
return false;
case -1:
return SocketWouldBlock();
default:
return true;
}
}

static void _updateDolphin(void) {
if (!dolphinEnabled) {
return;
}

++dolphinRetryCounter;
if (dolphinRetryCounter < DOLPHIN_RETRY_INTERVAL) {
return;
}
dolphinRetryCounter = 0;

if (GBASIODolphinIsConnected(&dolphin)) {
if (!_isDolphinAlive()) {
if (logCallback) {
logCallback(RETRO_LOG_WARN, "[JoyBus] Lost connection with Dolphin\n");
}
_disconnectDolphin();
}
} else {
_connectDolphin();
}
}
#endif

static void _reloadSettings(void) {
struct mCoreOptions opts = {
.useBios = true,
Expand Down Expand Up @@ -1315,6 +1399,11 @@ void retro_set_environment(retro_environment_t env)

bool categoriesSupported;
libretro_set_core_options(environCallback, &categoriesSupported);

#ifdef ENABLE_JOYBUS_DOLPHIN
bool supportsNoGame = true;
environCallback(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &supportsNoGame);
#endif
}

void retro_set_video_refresh(retro_video_refresh_t video) {
Expand Down Expand Up @@ -1473,6 +1562,13 @@ void retro_init(void) {
retroAudioLatency = 0;
updateAudioLatency = false;
updateAudioRate = false;

#ifdef ENABLE_JOYBUS_DOLPHIN
SocketSubsystemInit();
GBASIODolphinCreate(&dolphin);
dolphinEnabled = false;
dolphinRetryCounter = 0;
#endif
}

void retro_deinit(void) {
Expand Down Expand Up @@ -1515,6 +1611,15 @@ void retro_deinit(void) {
audioLowPassRange = 0;
audioLowPassLeftPrev = 0;
audioLowPassRightPrev = 0;

#ifdef ENABLE_JOYBUS_DOLPHIN
if (GBASIODolphinIsConnected(&dolphin)) {
_disconnectDolphin();
}
dolphinEnabled = false;
dolphinRetryCounter = 0;
SocketSubsystemDeinit();
#endif
}

static int turboclock = 0;
Expand Down Expand Up @@ -1578,7 +1683,35 @@ void retro_run(void) {
#ifdef M_CORE_GB
_updateGbPal();
#endif

#ifdef ENABLE_JOYBUS_DOLPHIN
if (core->platform(core) == mPLATFORM_GBA) {
struct retro_variable dol_var = {
.key = "mgba_joybus_dolphin",
.value = 0
};
if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &dol_var) && dol_var.value) {
bool enabled = strcmp(dol_var.value, "enabled") == 0;
if (enabled != dolphinEnabled) {
dolphinEnabled = enabled;
if (!enabled) {
if (GBASIODolphinIsConnected(&dolphin)) {
_disconnectDolphin();
}
} else {
dolphinRetryCounter = DOLPHIN_RETRY_INTERVAL;
}
}
}
}
#endif
}

#ifdef ENABLE_JOYBUS_DOLPHIN
if (core->platform(core) == mPLATFORM_GBA) {
_updateDolphin();
}
#endif

keys = 0;
int i;
Expand Down Expand Up @@ -1992,7 +2125,19 @@ bool retro_load_game(const struct retro_game_info* game) {
struct VFile* rom;

if (!game) {
#ifdef ENABLE_JOYBUS_DOLPHIN
/* No content, boot to GBA BIOS */
data = NULL;
dataSize = 0;
rom = NULL;
core = mCoreCreate(mPLATFORM_GBA);
if (!core) {
return false;
}
goto core_init;
#else
return false;
#endif
}

if (game->data) {
Expand Down Expand Up @@ -2023,6 +2168,7 @@ bool retro_load_game(const struct retro_game_info* game) {
mappedMemoryFree(data, game->size);
return false;
}
core_init:
mCoreInitConfig(core, NULL);
core->init(core);

Expand Down Expand Up @@ -2147,13 +2293,33 @@ bool retro_load_game(const struct retro_game_info* game) {
}
#endif

#ifdef ENABLE_JOYBUS_DOLPHIN
if (core->platform(core) == mPLATFORM_GBA) {
struct retro_variable var;
var.key = "mgba_joybus_dolphin";
var.value = 0;
if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
dolphinEnabled = strcmp(var.value, "enabled") == 0;
}
dolphinRetryCounter = DOLPHIN_RETRY_INTERVAL;
}
#endif

return true;
}

void retro_unload_game(void) {
if (!core) {
return;
}

#ifdef ENABLE_JOYBUS_DOLPHIN
if (core->platform(core) == mPLATFORM_GBA) {
_disconnectDolphin();
dolphinEnabled = false;
}
#endif

mCoreConfigDeinit(&core->config);
core->deinit(core);
mappedMemoryFree(data, dataSize);
Expand Down
16 changes: 16 additions & 0 deletions src/platform/libretro/libretro_core_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,22 @@ struct retro_core_option_v2_definition option_defs_us[] = {
},
"0"
},
#ifdef ENABLE_JOYBUS_DOLPHIN
{
"mgba_joybus_dolphin",
"Connect to Dolphin",
"Connect to Dolphin",
"Enabling this will allow you to connect to Dolphin via an emulated GameCube/GBA Link Cable. Dolphin must be running locally on this device, and it must have a \"GBA (TCP)\" controller configured. If you can't connect, try completely restarting Dolphin.",
NULL,
"input",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL },
},
"disabled"
},
#endif
{ NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
};

Expand Down