diff --git a/eeprom.bin b/eeprom.bin new file mode 100644 index 0000000..01241fd Binary files /dev/null and b/eeprom.bin differ diff --git a/sram.bin b/sram.bin new file mode 100644 index 0000000..230b8c3 Binary files /dev/null and b/sram.bin differ diff --git a/src/lindbergh/config.c b/src/lindbergh/config.c index 4d2a9a2..a1358d8 100644 --- a/src/lindbergh/config.c +++ b/src/lindbergh/config.c @@ -1,19 +1,66 @@ +#include +#include #include #include "config.h" EmulatorConfig config = {0}; -int initConfig() { +static int detectGame() +{ + + // For a better way of doing this, we should look for strings inside the game + // This will allow patching the game and for it to still be detected. + // strings %s | grep "RIDE TURN TEST" && strings %s | grep "PLEASE SHOOT GRID" + // shows you its hotd4S for example + + if (strstr(program_invocation_name, "segaboot")) + { + config.game = SEGABOOT; + return 0; + } + + if (strstr(program_invocation_name, "hod4")) + { + config.game = THE_HOUSE_OF_THE_DEAD_4; + return 0; + } + + config.game = UNKNOWN; + return 1; +} + +char *getGameName() +{ + switch (config.game) + { + case SEGABOOT: + return "SEGABOOT"; + case THE_HOUSE_OF_THE_DEAD_4: + return "The House of the Dead 4"; + default: + return "Unknown Game"; + } + return "Unknown Game"; +} + +int initConfig() +{ config.emulateRideboard = 0; + config.emulateDriveboard = 0; + config.emulateMotionboard = 0; strcpy(config.eepromPath, "eeprom.bin"); strcpy(config.sramPath, "sram.bin"); config.width = 1024; config.height = 768; + if (detectGame() != 0) + { + printf("Warning: Unsure what game this is, using default configuration values"); + } return 0; } -EmulatorConfig *getConfig() { - +EmulatorConfig *getConfig() +{ return &config; } diff --git a/src/lindbergh/config.h b/src/lindbergh/config.h index 8eb6187..e7d3b6f 100644 --- a/src/lindbergh/config.h +++ b/src/lindbergh/config.h @@ -2,17 +2,27 @@ #define MAX_PATH_LENGTH 1024 +typedef enum { + UNKNOWN, + SEGABOOT, + THE_HOUSE_OF_THE_DEAD_4 +} Game; + typedef struct { int emulateRideboard; + int emulateDriveboard; + int emulateMotionboard; char eepromPath[MAX_PATH_LENGTH]; char sramPath[MAX_PATH_LENGTH]; int width; int height; + Game game; } EmulatorConfig; int initConfig(); EmulatorConfig *getConfig(); +char *getGameName(); diff --git a/src/lindbergh/driveboard.c b/src/lindbergh/driveboard.c index e69de29..9359f19 100644 --- a/src/lindbergh/driveboard.c +++ b/src/lindbergh/driveboard.c @@ -0,0 +1,76 @@ +#include "string.h" + +#include "driveboard.h" + +#define DRIVEBOARD_READY 0x00 +#define DRIVEBOARD_NOT_INIT 0x11 +#define DRIVEBOARD_BUSY 0x44 + +int wheelTest = 0; +unsigned char response = DRIVEBOARD_READY; + +int initDriveboard() +{ + wheelTest = 0; + response = DRIVEBOARD_NOT_INIT; + + return 0; +} + +ssize_t driveboardRead(int fd, void *buf, size_t count) +{ + memcpy(buf, &response, 1); + return 1; +} + +ssize_t driveboardWrite(int fd, const void *buf, size_t count) +{ + + if (count != 4) + { + printf("Error: Drive board count not what expected\n"); + return 1; + } + + unsigned char *buffer = (unsigned char *)buf; + + switch (buffer[0]) + { + case 0xFF: + { + printf("Driveboard: Drive board reset\n"); + response = DRIVEBOARD_READY; + } + break; + + case 0x81: + { + printf("Driveboard: Drive board reset 2\n"); + response = DRIVEBOARD_NOT_INIT; + } + break; + + case 0xFC: + { + printf("Driveboard: Start wheel bounds testing\n"); + wheelTest = 1; + } + break; + + case 0xFD: + { + printf("Driveboard: auto turn wheel mode\n"); + if (wheelTest) + { + printf("Increment wheel until 0.9\n"); + } + } + break; + + default: + printf("Driveboard: Unknown command received\n"); + break; + } + + return 0; +} diff --git a/src/lindbergh/driveboard.h b/src/lindbergh/driveboard.h index e69de29..a96dcf0 100644 --- a/src/lindbergh/driveboard.h +++ b/src/lindbergh/driveboard.h @@ -0,0 +1,5 @@ +#include + +int initDriveboard(); +ssize_t driveboardRead(int fd, void *buf, size_t count); +ssize_t driveboardWrite(int fd, const void *buf, size_t count); diff --git a/src/lindbergh/graphics.c b/src/lindbergh/graphics.c index 3096df8..73e1b2b 100644 --- a/src/lindbergh/graphics.c +++ b/src/lindbergh/graphics.c @@ -1,7 +1,8 @@ #include -#include #include +#include #include +#include #include "config.h" #include "jvs.h" @@ -12,7 +13,10 @@ int gameModeHeight = -1; FGAPI int FGAPIENTRY glutEnterGameMode() { - glutCreateWindow("SEGA Lindbergh (GLUT)"); + char gameTitle[256] = {0}; + strcat(gameTitle, getGameName()); + strcat(gameTitle, " (GLUT)"); + glutCreateWindow(gameTitle); return 1; } @@ -120,6 +124,9 @@ int XNextEvent(Display *display, XEvent *event_return) int XSetStandardProperties(Display *display, Window window, const char *window_name, const char *icon_name, Pixmap icon_pixmap, char **argv, int argc, XSizeHints *hints) { - int (*_XSetStandardProperties)(Display * display, Window window, const char *window_name, const char *icon_name, Pixmap icon_pixmap, char **argv, int argc, XSizeHints *hints) = dlsym(RTLD_NEXT, "XSetStandardProperties"); - return _XSetStandardProperties(display, window, "SEGA Lindbergh (X11)", icon_name, icon_pixmap, argv, argc, hints); + int (*_XSetStandardProperties)(Display * display, Window window, const char *window_name, const char *icon_name, Pixmap icon_pixmap, char **argv, int argc, XSizeHints *hints) = dlsym(RTLD_NEXT, "XSetStandardProperties"); + char gameTitle[256] = {0}; + strcat(gameTitle, getGameName()); + strcat(gameTitle, " (X11)"); + return _XSetStandardProperties(display, window, gameTitle, icon_name, icon_pixmap, argv, argc, hints); } diff --git a/src/lindbergh/hook.c b/src/lindbergh/hook.c index 1bab18e..dd693ee 100644 --- a/src/lindbergh/hook.c +++ b/src/lindbergh/hook.c @@ -14,9 +14,10 @@ #include "baseboard.h" #include "config.h" -#include "rideboard.h" +#include "driveboard.h" #include "eeprom.h" #include "jvs.h" +#include "rideboard.h" #include "securityboard.h" #define HOOK_FILE_NAME "/dev/zero" @@ -33,6 +34,7 @@ uint16_t basePortAddress = 0xFFFF; void __attribute__((constructor)) hook_init() { printf("SEGA Lindbergh Loader\nRobert Dilley 2022\nNot for public consumption\n\n"); + initConfig(); if (initEeprom() != 0) @@ -47,6 +49,12 @@ void __attribute__((constructor)) hook_init() if (initSecurityBoard() != 0) exit(1); + if (getConfig()->emulateDriveboard) + { + if (initDriveboard() != 0) + exit(1); + } + securityBoardSetDipResolution(getConfig()->width, getConfig()->height); printf("Loader init success\n"); @@ -143,6 +151,11 @@ ssize_t read(int fd, void *buf, size_t count) return rideboardRead(fd, buf, count); } + if (fd == hooks[SERIAL0] && getConfig()->emulateDriveboard) + { + return driveboardRead(fd, buf, count); + } + return _read(fd, buf, count); } @@ -160,6 +173,11 @@ ssize_t write(int fd, const void *buf, size_t count) return rideboardWrite(fd, buf, count); } + if (fd == hooks[SERIAL0] && getConfig()->emulateDriveboard) + { + return driveboardWrite(fd, buf, count); + } + return _write(fd, buf, count); } @@ -248,7 +266,7 @@ static void handleSegfault(int signal, siginfo_t *info, void *ptr) { uint16_t port = ctx->uc_mcontext.gregs[REG_EDX] & 0xFFFF; - // The first port called is usually random, but everything after that + // The first port called is usually random, but everything after that // is a constant offset, so this is a hack to fix that. // When run as sudo it works fine!?