1
0
mirror of synced 2025-02-17 10:38:32 +01:00
This commit is contained in:
Bobby Dilley 2023-12-12 15:27:37 +00:00
parent 59c18b3c2c
commit c2e29d9e26
17 changed files with 831 additions and 184 deletions

View File

@ -9,6 +9,7 @@
"ioctl.h": "c",
"segaeax.h": "c",
"passthrough.h": "c",
"pthread.h": "c"
}
"config.h": "c"
},
"C_Cpp.errorSquiggles": "disabled"
}

View File

@ -26,3 +26,6 @@ libkswapapi.so: src/libkswapapi/libkswapapi.o
clean:
rm -rf $(BUILD)
rm -f src/lindbergh/*.o
rm -f src/libsegaapi/*.o
rm -f src/libkswapapi/*.o

View File

@ -30,38 +30,44 @@ EMULATE_JVS 1
# Set if the emulator should emulate the rideboard used in the special games here
# If this is set to 0, then the emulator will route the traffic to the serial device
# defined in RIDEBOARD_PATH if it has been defined.
# EMULATE_RIDEBOARD 0
EMULATE_RIDEBOARD 0
# Set if the emulator should emulate the driveboard used in driving games here
# If this is set to 0, then the emulator will route the traffic to the serial device
# defined in DRIVEBOARD_PATH if it has been defined.
# EMULATE_DRIVEBOARD 0
EMULATE_DRIVEBOARD 0
# Set if the emulator should emulate the motion board from Outrun 2 SP SDX here
# If this is set to 0, then the emulator will route the traffic to the serial device
# defined in MOTIONBOARD_PATH if it has been defined.
# EMULATE_MOTIONBOARD 0
EMULATE_MOTIONBOARD 0
# Define the path to pass the JVS packets to
# JVS_PATH /dev/ttyUSB0
JVS_PATH /dev/ttyUSB0
# Define the path to pass the rideboard packets to
# RIDEBOARD_PATH /dev/ttyUSB0
RIDEBOARD_PATH /dev/ttyUSB0
# Define the path to pass the driveboard packets to
# DRIVEBOARD_PATH /dev/ttyUSB0
DRIVEBOARD_PATH /dev/ttyUSB0
# Define the path to pass the motionboard packets to
# MOTIONBOARD_PATH /dev/ttyUSB0
MOTIONBOARD_PATH /dev/ttyUSB0
# Define the path to the sram.bin file
# SRAM_PATH sram.bin
SRAM_PATH sram.bin
# Define the path to the eeprom.bin file
# EEPROM_PATH eeprom.bin
EEPROM_PATH eeprom.bin
# Set if the emulator should go full screen
# FULLSCREEN 0
FULLSCREEN 0
# Set if you would like to apply AMD CPU / GPU Fixes
# AMD_FIX 0
AMD_FIX 0
# Set the Region ( JP/US/EX )
REGION EX
# Set if you want the game to be Free Play
FREEPLAY 1

View File

@ -10,6 +10,7 @@ Working is defined by getting into attract mode and running the game, but not ne
- After Burner Climax
- Ghost Squad Evolution
- Harley Davidson
- Let's Go Jungle
- Let's Go Jungle Special (boots to ride error)
- Outrun 2 SP SDX
- R-Tuned
@ -19,20 +20,12 @@ Working is defined by getting into attract mode and running the game, but not ne
- The House Of The Dead 4 Special
- The House Of The Dead Ex
- Virtua Fighter 5
## Games that do not work or haven't been tested
- Hummer
- Initial D 4
- Initial D 5
- Let's Go Jungle
- Primevil
- Virtua Tennis 3
## How to run specific games
## Games that current do not work
### Let's Go Jungle
- Hummer
- Initial D 5
- Primevil
No, this game will not start.
```LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. LD_PRELOAD=lindbergh.so TEA_DIR=`pwd` ./lgj_final```

Binary file not shown.

View File

@ -40,6 +40,13 @@ static int detectGame(uint32_t elf_crc)
return 0;
}
if (elf_crc == 0x3cc635ee)
{
config.game = SEGABOOT_2_4_SYM;
config.gameStatus = WORKING;
return 0;
}
if (elf_crc == 0xbc0c9ffa)
{
config.game = THE_HOUSE_OF_THE_DEAD_4;
@ -124,6 +131,13 @@ static int detectGame(uint32_t elf_crc)
if (elf_crc == 0xc4b7e89)
{
config.game = VIRTUA_TENNIS_3;
config.gameStatus = WORKING;
return 0;
}
if (elf_crc == 0xffe3b0fd)
{
config.game = VIRTUA_TENNIS_3_TEST;
config.gameStatus = NOT_WORKING;
return 0;
}
@ -198,9 +212,11 @@ char *getGameName()
case SEGABOOT:
return "Segaboot";
case SEGABOOT_2_4:
return "Segaboot from 2.4 Kernel";
return "SEGABOOT 2.4";
case SEGABOOT_2_4_SYM:
return "SEGABOOT 2.4 Symbols";
case SEGABOOT_2_6:
return "Segaboot from 2.6 Kernel";
return "SEGABOOT 2.6";
case SEGA_RACE_TV:
return "SEGA Race TV";
case THE_HOUSE_OF_THE_DEAD_4:
@ -235,6 +251,8 @@ char *getGameName()
return "Virtua Fighter 5 Rev D";
case VIRTUA_TENNIS_3:
return "Virtua Tennis 3";
case VIRTUA_TENNIS_3_TEST:
return "Virtua Tennis 3 - Testmode";
default:
return unknownGameTitle;
}
@ -288,6 +306,18 @@ int readConfig(FILE *configFile, EmulatorConfig *config)
else if (strcmp(command, "JVS_PATH") == 0)
strcpy(config->jvsPath, getNextToken(NULL, " ", &saveptr));
else if (strcmp(command, "RIDEBOARD_PATH") == 0)
strcpy(config->rideboardPath, getNextToken(NULL, " ", &saveptr));
else if (strcmp(command, "DRIVEBOARD_PATH") == 0)
strcpy(config->driveboardPath, getNextToken(NULL, " ", &saveptr));
else if (strcmp(command, "MOTIONBOARD_PATH") == 0)
strcpy(config->motionboardPath, getNextToken(NULL, " ", &saveptr));
else if (strcmp(command, "FREEPLAY") == 0)
config->freeplay = atoi(getNextToken(NULL, " ", &saveptr));
else if (strcmp(command, "LINDBERGH_COLOUR") == 0)
{
char colour[256];
@ -295,6 +325,19 @@ int readConfig(FILE *configFile, EmulatorConfig *config)
if (strcmp(colour, "RED") == 0)
config->lindberghColour = RED;
}
else if (strcmp(command, "REGION") == 0)
{
char region[256];
strcpy(region, getNextToken(NULL, " ", &saveptr));
if (strcmp(region, "JP") == 0)
config->region = JP;
else if (strcmp(region, "US") == 0)
config->region = US;
else
config->region = EX;
}
else
printf("Error: Unknown settings command %s\n", command);
}
@ -320,10 +363,11 @@ int initConfig()
config.width = 1024;
config.height = 768;
config.crc32 = elf_crc;
config.region = US;
config.freeplay = 1;
if (detectGame(config.crc32) != 0)
{
printf("Warning: Unsure what game this is. Please submit this new game to the GitHub repository: https://github.com/bobbydilley/lindbergh-loader/issues/new?title=Please+add+new+game+0x%X&body=I+tried+to+launch+the+following+game:\n", config.crc32);
printf("Warning: Unsure what game with CRC 0x%X is. Please submit this new game to the GitHub repository: https://github.com/bobbydilley/lindbergh-loader/issues/new?title=Please+add+new+game+0x%X&body=I+tried+to+launch+the+following+game:\n", config.crc32, config.crc32);
}
configFile = fopen(CONFIG_PATH, "r");

View File

@ -28,6 +28,7 @@ typedef enum
R_TUNED,
SEGABOOT,
SEGABOOT_2_4,
SEGABOOT_2_4_SYM,
SEGABOOT_2_6,
SEGA_RACE_TV,
THE_HOUSE_OF_THE_DEAD_4,
@ -45,7 +46,8 @@ typedef enum
VIRTUA_FIGHTER_5_REVB,
VIRTUA_FIGHTER_5_REVC,
VIRTUA_FIGHTER_5_R_REVD,
VIRTUA_TENNIS_3
VIRTUA_TENNIS_3,
VIRTUA_TENNIS_3_TEST
} Game;
typedef enum
@ -60,6 +62,13 @@ typedef enum
NOT_WORKING
} GameStatus;
typedef enum
{
JP,
US,
EX
} GameRegion;
typedef struct
{
int emulateRideboard;
@ -80,6 +89,8 @@ typedef struct
Colour lindberghColour;
GameStatus gameStatus;
uint32_t crc32;
GameRegion region;
int freeplay;
} EmulatorConfig;
int initConfig();

View File

@ -3,6 +3,7 @@
#include <stdint.h>
#include "eeprom.h"
#include "eeprom_settings.h"
#include "config.h"
#define I2C_SMBUS_BLOCK_MAX 32
@ -46,6 +47,19 @@ int initEeprom()
eeprom = fopen(eepromPath, "rb+");
if(eepromSettingsInit(eeprom) !=0)
{
printf("Error initializing eeprom settings.");
fclose(eeprom);
return 1;
}
if(getRegion() != getConfig()->region)
setRegion(eeprom, getConfig()->region);
if(getFreeplay() != getConfig()->freeplay)
setFreeplay(eeprom, getConfig()->freeplay);
fseek(eeprom, 0, SEEK_SET);
return 0;

View File

@ -0,0 +1,332 @@
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "eeprom_settings.h"
uint32_t crc32_table[255];
typedef struct
{
uint16_t offset;
uint16_t size;
} eepromOffsets;
typedef enum
{
STATIC,
NETWORK_TYPE,
ETH0,
ETH1,
CREDIT,
BACKUP
} eepromSection;
eepromOffsets eepromOffsetTable[] = {
{0x0000, 0x0020}, // amSysDataRecord_Static
{0x00A0, 0x0010}, // amSysDataRecord_NetworkType
{0x00B0, 0x0020}, // amSysDataRecord_Eth0
{0x00D0, 0x0020}, // amSysDataRecord_Eth1
{0x0100, 0x0040}, // amSysDataRecord_Credit
{0x0400, 0x0060}}; // amSysDataRecord_Backup
unsigned char eepromBuffer[512];
void build_crc32_table()
{
for (uint32_t i = 0; i < 256; i++)
{
uint32_t ch = i;
uint32_t crc = 0;
for (size_t j = 0; j < 8; j++)
{
uint32_t b = (ch ^ crc) & 1;
crc >>= 1;
if (b)
crc = crc ^ 0xEDB88320;
ch >>= 1;
}
crc32_table[i] = crc;
}
}
uint32_t gen_crc(int section, size_t n)
{
unsigned char *buff = &eepromBuffer[eepromOffsetTable[section].offset + 4];
unsigned long crc = 0xfffffffful;
size_t i;
for (i = 0; i < n; i++)
crc = crc32_table[*buff++ ^ (crc & 0xff)] ^ (crc >> 8);
return (crc);
}
void addCRCtoBuffer(int section)
{
uint32_t crc = gen_crc(section, eepromOffsetTable[section].size - 4);
memcpy(&eepromBuffer[eepromOffsetTable[section].offset], &crc, sizeof(uint32_t));
}
int fillBuffer(FILE *file)
{
fseek(file, 0, SEEK_SET);
int b = fread(eepromBuffer, 1, 512, file);
if (b < 512)
return 1;
return 0;
}
int checkCRCinBuffer(int section)
{
uint32_t crc;
memcpy(&crc, &eepromBuffer[eepromOffsetTable[section].offset], 4);
if (crc != gen_crc(section, eepromOffsetTable[section].size - 4))
return 1;
return 0;
}
int createStaticSection()
{
unsigned char *buff = &eepromBuffer[eepromOffsetTable[STATIC].offset];
memset(buff, 0, eepromOffsetTable[STATIC].size);
buff[14] = 0;
memcpy(buff + 15, "AAGX-01A00009999", 16);
return 0;
}
int createNetworkTypeSection()
{
memset(&eepromBuffer[eepromOffsetTable[NETWORK_TYPE].offset], 0,
eepromOffsetTable[NETWORK_TYPE].size);
return 0;
}
int createEthSection(int section)
{
unsigned char *buff = &eepromBuffer[eepromOffsetTable[section].offset];
memset(buff, 0, eepromOffsetTable[section].size);
uint32_t value = 1;
memcpy(buff + 8, &value, sizeof(uint32_t));
value = inet_addr("10.0.0.1");
if (section == ETH1)
value += (1 << 24);
memcpy(buff + 12, &value, sizeof(uint32_t));
value = inet_addr("255.255.255.0");
memcpy(buff + 16, &value, sizeof(uint32_t));
value = inet_addr("0.0.0.0");
memcpy(buff + 20, &value, sizeof(uint32_t));
memcpy(buff + 24, &value, sizeof(uint32_t));
memcpy(buff + 28, &value, sizeof(uint32_t));
return 0;
}
int createCreditSection()
{
unsigned char *buff = &eepromBuffer[eepromOffsetTable[CREDIT].offset];
memset(buff, 0, eepromOffsetTable[CREDIT].size);
buff[32] = 99;
buff[33] = 9;
buff[34] = 4;
buff[35] = 0; // Coin chute type [COMMON (Default) / INDIVIDUAL]
buff[36] = 1; // Service Type [COMMON / INDIVIDUAL (Default)]
buff[38] = 1; //
buff[39] = 0; // Freeplay set to 1
buff[40] = 1; // Credits Chute #1
buff[41] = 1; // Credits Chute #1
buff[42] = 0; //
buff[43] = 1; // Coins
for (size_t i = 0; i < 8; i++)
{
buff[44 + i] = 1;
}
return 0;
}
int writeSectiontoFile(FILE *file, int section)
{
unsigned char *buff = &eepromBuffer[eepromOffsetTable[section].offset];
// Original
if (fseek(file, eepromOffsetTable[section].offset, SEEK_SET) != 0)
return 1;
if (fwrite(buff, eepromOffsetTable[section].size, 1, file) != 1)
return 1;
// Duplicate
if (fseek(file, eepromOffsetTable[section].offset + 0x200, SEEK_SET) != 0)
return 1;
if (fwrite(buff, eepromOffsetTable[section].size, 1, file) != 1)
return 1;
return 0;
}
int getRegion()
{
return eepromBuffer[14];
}
int setRegion(FILE *eeprom, int region)
{
eepromBuffer[14] = region;
addCRCtoBuffer(STATIC);
if (writeSectiontoFile(eeprom, STATIC) != 0)
{
printf("Error setting the .");
return 1;
}
return 0;
}
int getFreeplay()
{
return eepromBuffer[eepromOffsetTable[CREDIT].offset + 39];
}
int setFreeplay(FILE *eeprom, int freeplay)
{
if (createCreditSection() != 0)
{
printf("Error setting Free Play.");
return 1;
}
eepromBuffer[eepromOffsetTable[CREDIT].offset + 39] = freeplay;
addCRCtoBuffer(CREDIT);
if (writeSectiontoFile(eeprom, CREDIT) != 0)
{
printf("Error setting Free Play.");
return 1;
}
return 0;
}
int eepromSettingsInit( FILE *eeprom)
{
build_crc32_table();
eeprom = fopen("eeprom.bin", "r+b");
if (eeprom == NULL)
{
printf("eeprom.bin cannot be opened, let's create a new one.\n");
eeprom = fopen("eeprom.bin", "w+b");
}
fseek(eeprom, 0, SEEK_END);
int size = ftell(eeprom);
fseek(eeprom, 0, SEEK_SET);
if (size >= 832) // eeprom initialized at least by SEGABOOT
{
fillBuffer(eeprom); // Fills buffer with 1st 512 bytes of the eeprom file
if (checkCRCinBuffer(STATIC) != 0)
{
// Create section from scratch
if (createStaticSection() != 0)
{
printf("Error creating Static Section.\n");
return 1;
}
else
{
addCRCtoBuffer(STATIC);
if (writeSectiontoFile(eeprom, STATIC) != 0)
{
printf("Error writing to eeprom.bin [STATIC].");
return 1;
}
}
}
if (checkCRCinBuffer(NETWORK_TYPE) != 0)
{
// Create section from scratch
if (createNetworkTypeSection() != 0)
{
printf("Error creating NetworkType Section.\n");
return 1;
}
else
{
addCRCtoBuffer(NETWORK_TYPE);
if (writeSectiontoFile(eeprom, NETWORK_TYPE) != 0)
{
printf("Error writing to eeprom.bin [NETWORK_TYPE].");
return 1;
}
}
}
if (checkCRCinBuffer(ETH0) != 0)
{
// Create section from scratch
if (createEthSection(ETH0) != 0)
{
printf("Error creating Eth0 Section.\n");
return 1;
}
else
{
addCRCtoBuffer(ETH0);
if (writeSectiontoFile(eeprom, ETH0) != 0)
{
printf("Error writing to eeprom.bin [ETH0].");
return 1;
}
}
}
if (checkCRCinBuffer(ETH1) != 0)
{
// Create section from scratch
if (createEthSection(ETH1) != 0)
{
printf("Error creating Eth0 Section.\n");
return 1;
}
else
{
addCRCtoBuffer(ETH1);
if (writeSectiontoFile(eeprom, ETH1) != 0)
{
printf("Error writing to eeprom.bin [ETH1].");
return 1;
}
}
}
if (checkCRCinBuffer(CREDIT) != 0)
{
// Create section from scratch
if (createCreditSection() != 0)
{
printf("Error creating CREDIT Section.\n");
return 1;
}
else
{
addCRCtoBuffer(CREDIT);
if (writeSectiontoFile(eeprom, NETWORK_TYPE) != 0)
{
printf("Error writing to eeprom.bin [CREDIT]].");
return 1;
}
}
}
}
else
{
// Create all sections from scratch
if ((createStaticSection() != 0) || (createNetworkTypeSection() != 0) ||
(createEthSection(ETH0) != 0) || (createEthSection(ETH1) != 0) || (createCreditSection() != 0))
{
printf("Error creating section from scratch.\n");
return 1;
}
addCRCtoBuffer(STATIC);
addCRCtoBuffer(NETWORK_TYPE);
addCRCtoBuffer(ETH0);
addCRCtoBuffer(ETH1);
addCRCtoBuffer(CREDIT);
if ((writeSectiontoFile(eeprom, STATIC) != 0) || (writeSectiontoFile(eeprom, NETWORK_TYPE) != 0) ||
(writeSectiontoFile(eeprom, ETH0) != 0) || (writeSectiontoFile(eeprom, ETH1) != 0) ||
(writeSectiontoFile(eeprom, CREDIT) != 0))
{
printf("Error writing section from scratch.\n");
return 1;
}
}
return 0;
}

View File

@ -0,0 +1,5 @@
int eepromSettingsInit(FILE *eeprom);
int getRegion();
int getFreeplay();
int setRegion(FILE *eeprom, int region);
int setFreeplay(FILE *eeprom, int freeplay);

View File

@ -142,102 +142,6 @@ int XStoreName(Display *display, Window w, const char *window_name)
return _XStoreName(display, w, gameTitle);
}
int XNextEvent(Display *display, XEvent *event_return)
{
int (*_XNextEvent)(Display *display, XEvent *event_return) = dlsym(RTLD_NEXT, "XNextEvent");
int returnValue = _XNextEvent(display, event_return);
// Return now if we're not emulating JVS
if (!getConfig()->emulateJVS)
{
return returnValue;
}
switch (event_return->type)
{
case KeyRelease:
case KeyPress:
{
switch (event_return->xkey.keycode)
{
case 28:
setSwitch(SYSTEM, BUTTON_TEST, event_return->type == KeyPress);
break;
case 39:
setSwitch(PLAYER_1, BUTTON_SERVICE, event_return->type == KeyPress);
break;
case 14:
incrementCoin(PLAYER_1, event_return->type == KeyPress);
break;
case 15:
incrementCoin(PLAYER_2, event_return->type == KeyPress);
break;
case 111:
setSwitch(PLAYER_1, BUTTON_UP, event_return->type == KeyPress);
break;
case 116:
setSwitch(PLAYER_1, BUTTON_DOWN, event_return->type == KeyPress);
break;
case 113:
setSwitch(PLAYER_1, BUTTON_LEFT, event_return->type == KeyPress);
break;
case 114:
setSwitch(PLAYER_1, BUTTON_RIGHT, event_return->type == KeyPress);
break;
case 10:
setSwitch(PLAYER_1, BUTTON_START, event_return->type == KeyPress);
break;
case 24:
setSwitch(PLAYER_1, BUTTON_1, event_return->type == KeyPress);
break;
case 25:
setSwitch(PLAYER_1, BUTTON_2, event_return->type == KeyPress);
break;
case 26:
setSwitch(PLAYER_1, BUTTON_3, event_return->type == KeyPress);
break;
case 27:
setSwitch(PLAYER_1, BUTTON_4, event_return->type == KeyPress);
break;
default:
break;
}
}
break;
case MotionNotify:
{
setAnalogue(ANALOGUE_1, ((double)event_return->xmotion.x / (double)getConfig()->width) * 255);
setAnalogue(ANALOGUE_2, ((double)event_return->xmotion.y / (double)getConfig()->height) * 255);
}
break;
case ButtonPress:
case ButtonRelease:
{
switch (event_return->xbutton.button)
{
case 1: // Trigger
setSwitch(PLAYER_1, BUTTON_1, event_return->type == ButtonPress);
break;
case 3: // Reload
setSwitch(PLAYER_1, BUTTON_2, event_return->type == ButtonPress);
break;
case 9: // Gun Button
setSwitch(PLAYER_1, BUTTON_3, event_return->type == ButtonPress);
break;
default:
break;
}
}
break;
}
return returnValue;
}
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");

View File

@ -16,6 +16,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cpuid.h>
#include <unistd.h>
#include "hook.h"
@ -27,6 +28,8 @@
#include "rideboard.h"
#include "securityboard.h"
#include "patch.h"
#include "pcidata.h"
#include "input.h"
#define HOOK_FILE_NAME "/dev/zero"
@ -37,10 +40,12 @@
#define CPUINFO 0
#define OSRELEASE 1
#define PCI_CARD_1F0 2
int hooks[5] = {-1, -1, -1, -1};
FILE *fileHooks[2] = {NULL, NULL};
int fileRead[2] = {0, 0};
FILE *fileHooks[3] = {NULL, NULL, NULL};
int fileRead[3] = {0, 0, 0};
char envpath[100];
uint32_t elf_crc = 0;
cpuvendor cpu_vendor = {0};
@ -59,8 +64,6 @@ static void handleSegfault(int signal, siginfo_t *info, void *ptr)
{
ucontext_t *ctx = ptr;
//printf("Caught segfault at address %p\n", info->si_addr);
// Get the address of the instruction causing the segfault
uint8_t *code = (uint8_t *)ctx->uc_mcontext.gregs[REG_EIP];
@ -130,7 +133,6 @@ static void handleSegfault(int signal, siginfo_t *info, void *ptr)
}
}
void __attribute__((constructor)) hook_init()
{
printf("SEGA Lindbergh Loader\nRobert Dilley 2023\nNot for public consumption\n\n");
@ -149,7 +151,7 @@ void __attribute__((constructor)) hook_init()
initConfig();
if(initPatch() != 0)
if (initPatch() != 0)
exit(1);
if (initEeprom() != 0)
@ -176,10 +178,13 @@ void __attribute__((constructor)) hook_init()
exit(1);
}
if(initInput() != 0)
exit(1);
securityBoardSetDipResolution(getConfig()->width, getConfig()->height);
printf("Now emulating %s", getGameName());
if(getConfig()->gameStatus == WORKING)
if (getConfig()->gameStatus == WORKING)
{
printf((" - Game is in working state.\n"));
}
@ -198,14 +203,12 @@ int open(const char *pathname, int flags)
if (strcmp(pathname, "/dev/lbb") == 0)
{
hooks[BASEBOARD] = _open(HOOK_FILE_NAME, flags);
printf("Baseboard opened %d\n", hooks[BASEBOARD]);
return hooks[BASEBOARD];
}
if (strcmp(pathname, "/dev/i2c/0") == 0)
{
hooks[EEPROM] = _open(HOOK_FILE_NAME, flags);
printf("EEPROM opened %d\n", hooks[EEPROM]);
return hooks[EEPROM];
}
@ -215,7 +218,7 @@ int open(const char *pathname, int flags)
return -1;
hooks[SERIAL0] = _open(HOOK_FILE_NAME, flags);
printf("SERIAL0 Opened %d\n", hooks[SERIAL0]);
printf("Warning: SERIAL0 Opened %d\n", hooks[SERIAL0]);
return hooks[SERIAL0];
}
@ -225,7 +228,7 @@ int open(const char *pathname, int flags)
return -1;
hooks[SERIAL1] = _open(HOOK_FILE_NAME, flags);
printf("SERIAL1 opened %d\n", hooks[SERIAL1]);
printf("Warning: SERIAL1 opened %d\n", hooks[SERIAL1]);
return hooks[SERIAL1];
}
@ -252,7 +255,7 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode)
return _fopen("lindbergrc", mode);
}
if (strcmp(pathname, "/usr/lib/boot/logo.tga") == 0)
if ((strcmp(pathname, "/usr/lib/boot/logo.tga") == 0) || (strcmp(pathname, "/usr/lib/boot/logo.tga") == 0))
{
return _fopen("logo.tga", mode);
}
@ -274,6 +277,26 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode)
return fileHooks[CPUINFO];
}
if (strcmp(pathname, "/usr/lib/boot/logo_red.tga") == 0)
{
return _fopen("logo_red.tga", mode);
}
if (strcmp(pathname, "/usr/lib/boot/SEGA_KakuGothic-DB-Roman_12.tga") == 0)
{
return _fopen("SEGA_KakuGothic-DB-Roman_12.tga", mode);
}
if (strcmp(pathname, "/usr/lib/boot/SEGA_KakuGothic-DB-Roman_12.abc") == 0)
{
return _fopen("SEGA_KakuGothic-DB-Roman_12.abc", mode);
}
if (strcmp(pathname, "/proc/bus/pci/00/1f.0") == 0)
{
fileRead[PCI_CARD_1F0] = 0;
fileHooks[PCI_CARD_1F0] = _fopen(HOOK_FILE_NAME, mode);
return fileHooks[PCI_CARD_1F0];
}
return _fopen(pathname, mode);
}
@ -313,6 +336,20 @@ FILE *fopen64(const char *pathname, const char *mode)
return _fopen64(pathname, mode);
}
int fclose(FILE *stream)
{
int (*_fclose)(FILE *stream) = dlsym(RTLD_NEXT, "fclose");
for (int i = 0; i < 3; i++)
{
if (fileHooks[i] == stream)
{
int r = _fclose(stream);
fileHooks[i] = NULL;
return r;
}
}
return _fclose(stream);
}
int openat(int dirfd, const char *pathname, int flags)
{
int (*_openat)(int dirfd, const char *pathname, int flags) = dlsym(RTLD_NEXT, "openat");
@ -404,6 +441,18 @@ ssize_t read(int fd, void *buf, size_t count)
return _read(fd, buf, count);
}
size_t fread(void *buf, size_t size, size_t count, FILE *stream)
{
size_t (*_fread)(void *buf, size_t size, size_t count, FILE *stream) = dlsym(RTLD_NEXT, "fread");
if (stream == fileHooks[PCI_CARD_1F0])
{
memcpy(buf, pcidata, 68);
return 68;
}
return _fread(buf, size, count, stream);
}
ssize_t write(int fd, const void *buf, size_t count)
{
int (*_write)(int fd, const void *buf, size_t count) = dlsym(RTLD_NEXT, "write");
@ -565,31 +614,34 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
/**
* Function to calculate CRC32 checksum in memory.
*/
uint32_t get_crc32(const char *s,size_t n)
*/
uint32_t get_crc32(const char *s, size_t n)
{
uint32_t crc=0xFFFFFFFF;
uint32_t crc = 0xFFFFFFFF;
for(size_t i=0;i<n;i++) {
char ch=s[i];
for(size_t j=0;j<8;j++) {
uint32_t b=(ch^crc)&1;
crc>>=1;
if(b) crc=crc^0xEDB88320;
ch>>=1;
}
for (size_t i = 0; i < n; i++)
{
char ch = s[i];
for (size_t j = 0; j < 8; j++)
{
uint32_t b = (ch ^ crc) & 1;
crc >>= 1;
if (b)
crc = crc ^ 0xEDB88320;
ch >>= 1;
}
}
return ~crc;
}
/**
* Callback function to get the offset and size of the execution program in memory of the ELF we hook to.
*/
static int callback(struct dl_phdr_info *info, size_t size, void *data)
*/
static int callback(struct dl_phdr_info *info, size_t size, void *data)
{
if((info->dlpi_phnum >= 3) && (info->dlpi_phdr[2].p_type == PT_LOAD) && (info->dlpi_phdr[2].p_flags == 5))
if ((info->dlpi_phnum >= 3) && (info->dlpi_phdr[2].p_type == PT_LOAD) && (info->dlpi_phdr[2].p_flags == 5))
{
elf_crc = get_crc32((void *)(info->dlpi_addr + info->dlpi_phdr[2].p_vaddr+10),128);
elf_crc = get_crc32((void *)(info->dlpi_addr + info->dlpi_phdr[2].p_vaddr + 10), 128);
}
return 1;
}
@ -599,7 +651,7 @@ void getCPUID()
unsigned eax;
eax = 0;
__get_cpuid(0, &eax, &cpu_vendor.ebx, &cpu_vendor.ecx, &cpu_vendor.edx);
printf("CPU Vendor: %.4s%.4s%.4s\n", (const char*)&cpu_vendor.ebx,(const char*)&cpu_vendor.edx,(const char*)&cpu_vendor.ecx);
printf("CPU Vendor: %.4s%.4s%.4s\n", (const char *)&cpu_vendor.ebx, (const char *)&cpu_vendor.edx, (const char *)&cpu_vendor.ecx);
}
/**
@ -617,6 +669,33 @@ int setenv(const char *name, const char *value, int overwrite)
return _setenv(name, value, overwrite);
}
/**
* Fake the TEA_DIR environment variable to games that require it to run
*/
char *getenv(const char *name)
{
char *(*_getenv)(const char *name) = dlsym(RTLD_NEXT, "getenv");
if ((strcmp(name, "TEA_DIR") == 0) && getConfig()->game == VIRTUA_TENNIS_3)
{
if (getcwd(envpath, 100) == NULL)
return "";
char *ptr = strrchr(envpath, '/');
if (ptr == NULL)
return "";
*ptr = '\0';
return envpath;
}
else if (strcmp(name, "TEA_DIR") == 0)
{
if (getcwd(envpath, 100) == NULL)
return "";
return envpath;
}
return _getenv(name);
}
/**
* Stop the game unsetting the DISPLAY environment variable
*/

117
src/lindbergh/input.c Normal file
View File

@ -0,0 +1,117 @@
#define _GNU_SOURCE
#include "jvs.h"
#include "config.h"
#include <GL/freeglut.h>
#include <GL/glx.h>
#include <X11/extensions/xf86vmode.h>
#include <X11/Xatom.h>
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <pthread.h>
int initInput()
{
return 0;
}
int XNextEvent(Display *display, XEvent *event_return)
{
int (*_XNextEvent)(Display *display, XEvent *event_return) = dlsym(RTLD_NEXT, "XNextEvent");
int returnValue = _XNextEvent(display, event_return);
// Return now if we're not emulating JVS
if (!getConfig()->emulateJVS)
{
return returnValue;
}
switch (event_return->type)
{
case KeyRelease:
case KeyPress:
{
switch (event_return->xkey.keycode)
{
case 28:
setSwitch(SYSTEM, BUTTON_TEST, event_return->type == KeyPress);
break;
case 39:
setSwitch(PLAYER_1, BUTTON_SERVICE, event_return->type == KeyPress);
break;
case 14:
incrementCoin(PLAYER_1, event_return->type == KeyPress);
break;
case 15:
incrementCoin(PLAYER_2, event_return->type == KeyPress);
break;
case 111:
setSwitch(PLAYER_1, BUTTON_UP, event_return->type == KeyPress);
break;
case 116:
setSwitch(PLAYER_1, BUTTON_DOWN, event_return->type == KeyPress);
break;
case 113:
setSwitch(PLAYER_1, BUTTON_LEFT, event_return->type == KeyPress);
break;
case 114:
setSwitch(PLAYER_1, BUTTON_RIGHT, event_return->type == KeyPress);
break;
case 10:
setSwitch(PLAYER_1, BUTTON_START, event_return->type == KeyPress);
break;
case 24:
setSwitch(PLAYER_1, BUTTON_1, event_return->type == KeyPress);
break;
case 25:
setSwitch(PLAYER_1, BUTTON_2, event_return->type == KeyPress);
break;
case 26:
setSwitch(PLAYER_1, BUTTON_3, event_return->type == KeyPress);
break;
case 27:
setSwitch(PLAYER_1, BUTTON_4, event_return->type == KeyPress);
break;
default:
break;
}
}
break;
case MotionNotify:
{
setAnalogue(ANALOGUE_1, ((double)event_return->xmotion.x / (double)getConfig()->width) * 255);
setAnalogue(ANALOGUE_2, ((double)event_return->xmotion.y / (double)getConfig()->height) * 255);
}
break;
case ButtonPress:
case ButtonRelease:
{
switch (event_return->xbutton.button)
{
case 1: // Trigger
setSwitch(PLAYER_1, BUTTON_1, event_return->type == ButtonPress);
break;
case 3: // Reload
setSwitch(PLAYER_1, BUTTON_2, event_return->type == ButtonPress);
break;
case 9: // Gun Button
setSwitch(PLAYER_1, BUTTON_3, event_return->type == ButtonPress);
break;
default:
break;
}
}
break;
}
return returnValue;
}

1
src/lindbergh/input.h Normal file
View File

@ -0,0 +1 @@
int initInput();

View File

@ -7,6 +7,7 @@
#include "patch.h"
#include "config.h"
#include "hook.h"
#include "securityboard.h"
extern cpuvendor cpu_vendor;
@ -89,6 +90,76 @@ int amDongleUpdate()
return 0;
}
int amLibInit()
{
uint32_t *amLibContext = (uint32_t *)0x08dfa2c0; // 0x0809cb00;
*amLibContext = 1;
uint32_t *amLibInitializad = (uint32_t *)0x08dfa2c4; // 0x0809cb04;
uint16_t *amLibPort1 = (uint16_t *)(0x08dfa2c4 + 4); //(0x0809cb04 + 4);
uint16_t *amLibPort2 = (uint16_t *)(0x08dfa2c4 + 4); //(0x0809cb04 + 6);
uint32_t *bcLibInitialized = (uint32_t *)(0x08dfa2c4 + 8); // 0x0809cb0c;
*amLibInitializad = 1;
*amLibPort1 = 0xd000;
*amLibPort2 = 0x0004;
*bcLibInitialized = 0;
int res = ((int (*)(void))0x084dedc4)(); // 0x08065d80)();
if (res == 1)
*bcLibInitialized = 1;
return 0;
}
int amDipswInit()
{
uint32_t *amDipswContext = (uint32_t *)0x08df9cec; // 0x0809c12c;
uint32_t *amDipswContext1 = (uint32_t *)(0x08df9cec + 4); //(0x0809c12c + 4);
uint32_t *amDipswContext2 = (uint32_t *)(0x08df9cec + 8); //(0x0809c12c + 8);
uint32_t *amDipswContext3 = (uint32_t *)(0x08df9cec + 12); //(0x0809c12c + 12);
// typedef void *(*___constant_c_and_count_memset)(uint32_t *, int, size_t);
//___constant_c_and_count_memset func = (___constant_c_and_count_memset)//0x0805c3d5;
// func(amDipswContext, 0, 4);
*amDipswContext = 1;
*amDipswContext1 = 1;
*amDipswContext2 = 1;
*amDipswContext3 = 1;
return 0;
}
void print_binary(unsigned int number)
{
if (number >> 1)
{
print_binary(number >> 1);
}
putc((number & 1) ? '1' : '0', stdout);
}
int amDipswGetData(uint8_t *dip)
{
// printf("amDipswGetData Called!!!!!\n");
uint8_t result;
uint32_t data;
securityBoardIn(0x38, &data);
result = (~data & 4) != 0; // Test Button
if ((~data & 8) != 0)
result |= 2; // Service Button
if ((~data & 0x10) != 0)
result |= 4; // ??
if ((char)data >= 0)
result |= 8; // ??
if ((~data & 0x100) != 0)
result |= 0x10; // Rotation
if ((~data & 0x200) != 0)
result |= 0x20; // Resolution Dip 4
if ((~data & 0x400) != 0)
result |= 0x40; // Resolution Dip 5
if ((~data & 0x800) != 0)
result |= 0x80; // Resolution Dip 6
*dip = result;
return 0;
}
void _putConsole(const char *format, ...)
{
va_list args;
@ -159,6 +230,10 @@ int initPatch()
detourFunction(0x084d5b40, amDongleInit);
detourFunction(0x084d45f9, amDongleIsAvailable);
detourFunction(0x084d4fef, amDongleUpdate);
detourFunction(0x084d44fc, stub0);
detourFunction(0x084d4485, amDipswGetData);
detourFunction(0x084d9118, amLibInit);
detourFunction(0x084d438c, amDipswInit);
}
break;
case AFTER_BURNER_CLIMAX_REVA:
@ -282,28 +357,31 @@ int initPatch()
case LETS_GO_JUNGLE:
{
setVariable(0x08c083a4, 2); // amBackupDebugLevel
setVariable(0x08c083c0, 2); // amCreditDebugLevel
setVariable(0x08c08618, 2); // amDipswDebugLevel
setVariable(0x08c0861c, 2); // amDongleDebugLevel
setVariable(0x08c08620, 2); // amEepromDebugLevel
setVariable(0x08c08624, 2); // amHwmonitorDebugLevel
setVariable(0x08c08628, 2); // amJvsDebugLevel
setVariable(0x08c0862c, 2); // amLibDebugLevel
setVariable(0x08c08630, 2); // amMiscDebugLevel
setVariable(0x08c08638, 2); // amSysDataDebugLevel
setVariable(0x08c08640, 2); // bcLibDebugLevel
setVariable(0x08c08634, 2); // amOsinfoDebugLevel
setVariable(0x08c08644, 0x0FFFFFFF); // s_logMask
setVariable(0x08c083a4, 2); // amBackupDebugLevel
setVariable(0x08c083c0, 2); // amCreditDebugLevel
setVariable(0x08c08618, 2); // amDipswDebugLevel
setVariable(0x08c0861c, 2); // amDongleDebugLevel
setVariable(0x08c08620, 2); // amEepromDebugLevel
setVariable(0x08c08624, 2); // amHwmonitorDebugLevel
setVariable(0x08c08628, 2); // amJvsDebugLevel
setVariable(0x08c0862c, 2); // amLibDebugLevel
setVariable(0x08c08630, 2); // amMiscDebugLevel
setVariable(0x08c08638, 2); // amSysDataDebugLevel
setVariable(0x08c08640, 2); // bcLibDebugLevel
setVariable(0x08c08634, 2); // amOsinfoDebugLevel
setVariable(0x08c08644, 0x0FFFFFFF); // s_logMask
detourFunction(0x08074a8c, _putConsole); // Debug Messages
detourFunction(0x084e50d8, amDongleInit);
detourFunction(0x084e5459, amDongleIsAvailable);
detourFunction(0x084e537d, amDongleUpdate);
detourFunction(0x08074a8c, _putConsole);
detourFunction(0x084e500e, amDipswGetData);
setVariable(0x080d1f02, 0x90909090); // Patch acpSystem::checkDongle
setVariable(0x080d1f06, 0xE8C3C990); // Patch acpSystem::checkDongle
setVariable(0x0807b76a, 0xc2839090); // Patch initializeArcadeBackup
// setVariable(0x082E006b, 0x00000280); // Set ResX
// setVariable(0x082E0078, 0x000001E0); // Set ResY
// setVariable(0x082E006b, 0x00000280); // Set ResX
// setVariable(0x082E0078, 0x000001E0); // Set ResY
detourFunction(0x084e4efc, stub0); // Stub amDipswInit
detourFunction(0x084e500e, stub0); // Stub amDipswGetData
@ -366,10 +444,12 @@ int initPatch()
setVariable(0x08d719e0, 2); // bcLibDebugLevel
setVariable(0x08d719d4, 2); // amOsinfoDebugLevel
setVariable(0x08d719e4, 0x0FFFFFFF); // s_logMask
detourFunction(0x086e2336, amDongleInit);
detourFunction(0x086e0d81, amDongleIsAvailable);
detourFunction(0x086e17e5, amDongleUpdate);
detourFunction(0x086e0c0d, amDipswGetData);
detourFunction(0x086e0c84, stub0);
detourFunction(0x0808f9a8, _putConsole);
setVariable(0x080dad63, 0x90909090); // Patch acpSystem::checkDongle
@ -377,6 +457,36 @@ int initPatch()
setVariable(0x0807e609, 0x90909090); // Patch initializeArcadeBackup
setVariable(0x0807e60D, 0xC2839090); // Patch initializeArcadeBackup
}
break;
case SEGABOOT_2_4_SYM:
{
detourFunction(0x0805e8b0, amDongleInit);
detourFunction(0x0805ebc3, amDongleIsAvailable);
detourFunction(0x0805eb2a, amDongleUpdate);
// detourFunction(0x08062cf8, amLibInit);
// detourFunction(0x0805c200, amDipswInit);
detourFunction(0x0805c30b, amDipswGetData);
}
break;
case VIRTUA_TENNIS_3:
{
detourFunction(0x0831c724, amDongleInit);
detourFunction(0x0831ca37, amDongleIsAvailable);
detourFunction(0x0831c99e, amDongleUpdate);
detourFunction(0x0831c5d7, amDipswGetData);
detourFunction(0x0831c64f, stub0);
setVariable(0x0827ae1b, 0x34891beb); // Disable Fullscreen
}
case VIRTUA_TENNIS_3_TEST:
{
detourFunction(0x0815f610, amDongleInit);
detourFunction(0x0815f923, amDongleIsAvailable);
detourFunction(0x0815f88a, amDongleUpdate);
detourFunction(0x0815d06b, amDipswGetData);
detourFunction(0x0815d0e3, stub0);
// setVariable(0x0827ae1b, 0x34891beb); //Disable Fullscreen
}
break;
default:
// Don't do any patches for random games
break;

28
src/lindbergh/pcidata.h Normal file
View File

@ -0,0 +1,28 @@
const char pcidata[256] = {
0x86, 0x80, 0x18, 0x29, 0x03, 0x01, 0x00, 0x00, 0x02, 0x00, 0x01,
0x06, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf4, 0x1a, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06,
0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x8a, 0x8b,
0x8b, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x8a, 0x8b, 0x8b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0,
0xd1, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00
};
const int pcidata_length = 256;

View File

@ -77,7 +77,6 @@ int securityBoardSetDipSwitch(int switchNumber, int value)
int securityBoardSetSwitch(JVSInput switchNumber, int value)
{
printf("Pressed\n");
switch (switchNumber)
{
case BUTTON_TEST:
@ -107,26 +106,26 @@ int securityBoardIn(uint16_t port, uint32_t *data)
case SECURITY_BOARD_FRONT_PANEL:
{
uint32_t result = 0xFFFFFFFF;
if (securityBoard.serviceSwitch)
result &= ~0x08;
if (securityBoard.testSwitch)
result &= ~0x04;
if (securityBoard.dipSwitch[6])
if (securityBoard.dipSwitch[6]) // bit12
result &= ~0x800; // DIP 6
if (securityBoard.dipSwitch[5])
if (securityBoard.dipSwitch[5]) // bit11
result &= ~0x400; // DIP 5
if (securityBoard.dipSwitch[4])
if (securityBoard.dipSwitch[4]) // bit10
result &= ~0x200; // DIP 4
if (securityBoard.dipSwitch[3])
if (securityBoard.dipSwitch[3]) // bit9
result &= ~0x100; // DIP 3
if (securityBoard.dipSwitch[2])
if (securityBoard.dipSwitch[2]) // bit8
result &= ~0x80; // DIP 2
if (securityBoard.dipSwitch[1])
if (securityBoard.dipSwitch[1]) // bit7
result &= ~0x40; // DIP 1
if (securityBoard.dipSwitch[8])
if (securityBoard.dipSwitch[8]) // bit6
result &= ~0x20;
if (securityBoard.dipSwitch[7])
if (securityBoard.dipSwitch[7]) // bit5
result &= ~0x10;
if (securityBoard.serviceSwitch) // bit4
result &= ~0x08;
if (securityBoard.testSwitch) // bit3
result &= ~0x04;
*data = result;
}
break;