diff --git a/.vscode/settings.json b/.vscode/settings.json index fdc3f2f..b959085 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,7 @@ "ioctl.h": "c", "segaeax.h": "c", "passthrough.h": "c", - "pthread.h": "c" - } + "config.h": "c" + }, + "C_Cpp.errorSquiggles": "disabled" } diff --git a/Makefile b/Makefile index 5bdf27b..b74ad07 100644 --- a/Makefile +++ b/Makefile @@ -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 \ No newline at end of file diff --git a/docs/lindbergh.conf b/docs/lindbergh.conf index 4964038..af609cf 100644 --- a/docs/lindbergh.conf +++ b/docs/lindbergh.conf @@ -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 diff --git a/docs/supported.md b/docs/supported.md index 9ea9245..c51c564 100644 --- a/docs/supported.md +++ b/docs/supported.md @@ -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``` diff --git a/src/libkswapapi/libkswapapi.o b/src/libkswapapi/libkswapapi.o index d480686..b98c5e3 100644 Binary files a/src/libkswapapi/libkswapapi.o and b/src/libkswapapi/libkswapapi.o differ diff --git a/src/lindbergh/config.c b/src/lindbergh/config.c index 0e3452d..75a4fb8 100644 --- a/src/lindbergh/config.c +++ b/src/lindbergh/config.c @@ -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"); diff --git a/src/lindbergh/config.h b/src/lindbergh/config.h index 09af474..bc21378 100644 --- a/src/lindbergh/config.h +++ b/src/lindbergh/config.h @@ -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(); diff --git a/src/lindbergh/eeprom.c b/src/lindbergh/eeprom.c index c814309..072632c 100644 --- a/src/lindbergh/eeprom.c +++ b/src/lindbergh/eeprom.c @@ -3,6 +3,7 @@ #include #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; diff --git a/src/lindbergh/eeprom_settings.c b/src/lindbergh/eeprom_settings.c new file mode 100644 index 0000000..faf6001 --- /dev/null +++ b/src/lindbergh/eeprom_settings.c @@ -0,0 +1,332 @@ +#include +#include +#include +#include + +#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; +} diff --git a/src/lindbergh/eeprom_settings.h b/src/lindbergh/eeprom_settings.h new file mode 100644 index 0000000..39f7173 --- /dev/null +++ b/src/lindbergh/eeprom_settings.h @@ -0,0 +1,5 @@ +int eepromSettingsInit(FILE *eeprom); +int getRegion(); +int getFreeplay(); +int setRegion(FILE *eeprom, int region); +int setFreeplay(FILE *eeprom, int freeplay); diff --git a/src/lindbergh/graphics.c b/src/lindbergh/graphics.c index 53ea574..b4e7343 100644 --- a/src/lindbergh/graphics.c +++ b/src/lindbergh/graphics.c @@ -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"); diff --git a/src/lindbergh/hook.c b/src/lindbergh/hook.c index 8b9831f..802901f 100644 --- a/src/lindbergh/hook.c +++ b/src/lindbergh/hook.c @@ -16,6 +16,7 @@ #include #include #include +#include #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>=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 */ diff --git a/src/lindbergh/input.c b/src/lindbergh/input.c new file mode 100644 index 0000000..5268cf2 --- /dev/null +++ b/src/lindbergh/input.c @@ -0,0 +1,117 @@ +#define _GNU_SOURCE + +#include "jvs.h" + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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; +} diff --git a/src/lindbergh/input.h b/src/lindbergh/input.h new file mode 100644 index 0000000..ec59b90 --- /dev/null +++ b/src/lindbergh/input.h @@ -0,0 +1 @@ +int initInput(); diff --git a/src/lindbergh/patch.c b/src/lindbergh/patch.c index 633b177..2f3f6f7 100644 --- a/src/lindbergh/patch.c +++ b/src/lindbergh/patch.c @@ -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; diff --git a/src/lindbergh/pcidata.h b/src/lindbergh/pcidata.h new file mode 100644 index 0000000..b9614ee --- /dev/null +++ b/src/lindbergh/pcidata.h @@ -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; \ No newline at end of file diff --git a/src/lindbergh/securityboard.c b/src/lindbergh/securityboard.c index 149a7ce..3b5415e 100644 --- a/src/lindbergh/securityboard.c +++ b/src/lindbergh/securityboard.c @@ -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;