├── .gitattributes ├── .gitignore ├── FORTUNA_Launcher.c ├── FORTUNA_Launcher.h ├── Makefile ├── OSDInit.c ├── OSDInit.h ├── README.md ├── libcdvd_add.c ├── libcdvd_add.h ├── pad.c ├── pad.h ├── usbd.irx └── usbhdfsd.irx /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | *.bak 54 | -------------------------------------------------------------------------------- /FORTUNA_Launcher.c: -------------------------------------------------------------------------------- 1 | //Working Title: 'FORTUNA' Homebrew Launcher 2 | //Written by VTSTech (veritas@vts-tech.org) 3 | //Version: 0.46 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "FORTUNA_Launcher.h" 20 | #include "OSDInit.h" 21 | #include "libcdvd_add.h" 22 | 23 | u64 Timer(void) 24 | { 25 | return (clock() / (CLOCKS_PER_SEC / 1000)); 26 | } 27 | 28 | //thx sp193 29 | void ResetIOP() 30 | { 31 | SifInitRpc(0); 32 | while(!SifIopReset("", 0)){}; 33 | while(!SifIopSync()){}; 34 | SifInitRpc(0); 35 | } 36 | 37 | //** Function LoadElf() from main.c MPLUS-LOADER3.ELF 38 | //** http://lukasz.dk/2008/04/22/datel-memory-plus-64-mb/ 39 | //slightly modified 40 | void LoadElf(const char *elf, char* path) 41 | { 42 | char* args[1]; 43 | t_ExecData exec; 44 | 45 | SifLoadElf(elf, &exec); 46 | 47 | #ifdef DEBUG 48 | scr_printf("Trying to load ELF: %s\n", elf); 49 | #endif 50 | 51 | if(exec.epc > 0) 52 | { 53 | //FlushCache(0); 54 | //FlushCache(2); 55 | 56 | // Reset IOP, since not all ELF's do it and we've loaded additional IOP 57 | // modules which need to be unloaded 58 | ResetIOP(); 59 | 60 | if(path != 0) 61 | { 62 | args[0] = path; 63 | ExecPS2((void*)exec.epc, (void*)exec.gp, 1, args); 64 | } 65 | else 66 | { 67 | ExecPS2((void*)exec.epc, (void*)exec.gp, 0, NULL); 68 | } 69 | } 70 | } 71 | 72 | extern u64 WaitTime; 73 | extern u64 CurrTime; 74 | 75 | 76 | 77 | u64 WaitTime; 78 | u64 CurrTime; 79 | u64 init_delay_start; 80 | u64 timeout_start; 81 | 82 | void banner() 83 | { 84 | scr_clear(); 85 | sleep(1); 86 | scr_printf("============================================== \n"); 87 | scr_printf("=FORTUNA Homebrew Launcher v0.46===12-29-2019= \n"); 88 | scr_printf("=BOOT.ELF Written by VTSTech of PSX-Place.com= \n"); 89 | scr_printf("=FORTUNA Project by krat0s of PS2-Home.com==== \n"); 90 | scr_printf("=www.vts-tech.org============================= \n\n"); 91 | } 92 | 93 | void InitPS2() 94 | { 95 | init_scr(); 96 | ResetIOP(); 97 | SifInitIopHeap(); 98 | SifLoadFileInit(); 99 | fioInit(); 100 | //wipeUserMem(); 101 | sbv_patch_disable_prefix_check(); 102 | SifLoadModule("rom0:SIO2MAN", 0, NULL); 103 | SifLoadModule("rom0:MCMAN", 0, NULL); 104 | SifLoadModule("rom0:MCSERV", 0, NULL); 105 | SifLoadModule("rom0:PADMAN", 0, NULL); 106 | sceCdInit(SCECdINoD); 107 | //cdInitAdd(); 108 | sleep(1); 109 | } 110 | 111 | int getFileSize(int fd) { 112 | int size = fioLseek(fd, 0, SEEK_END); 113 | fioLseek(fd, 0, SEEK_SET); 114 | return size; 115 | } 116 | 117 | int main(int argc, char *argv[], char **envp) 118 | { 119 | char *target, *path; 120 | char device[50]; 121 | char folder[50]; 122 | int CdStatus; 123 | int devshown = 0; 124 | int devset = 0; 125 | int menushown = 0; 126 | int fd = 0; 127 | int FORTUNA = 0; 128 | int MC0T = 0; 129 | int MC1T = 0; 130 | InitPS2(); 131 | //IRX from: 132 | //./usr/local/ps2dev/ps2sdk/iop/irx/usbd.irx 133 | //./usr/local/ps2dev/ps2sdk/iop/irx/usbhdfsd.irx 134 | SifLoadModule("mc0:/FORTUNA/usbd.irx", 0, NULL); 135 | SifLoadModule("mc0:/FORTUNA/usbhdfsd.irx", 0, NULL); 136 | banner(); 137 | path=""; 138 | setupPad(); 139 | sleep(1); 140 | int state = padGetState(0,0); 141 | //WaitTime = Timer(); 142 | CdStatus = sceCdStatus(); 143 | OSDInitSystemPaths(); 144 | if (state == 6) { 145 | while(1) { 146 | //int state; 147 | state = readpad(); 148 | //CdStatus = sceCdStatus(); 149 | if (devshown == 0 && menushown == 0) { 150 | fioClose(fd); 151 | fd = fioOpen("mc0:/FORTUNA/icon.icn", O_RDONLY); 152 | if (getFileSize(fd) == 51040){ 153 | scr_printf(" FORTUNA rev1 detected on mc0! (Newer version available) \n"); 154 | FORTUNA = 1; 155 | MC0T = 1; 156 | strcpy(device,"mc0:"); 157 | strcpy(folder,"/FORTUNA/"); 158 | } else if (getFileSize(fd) == 16876){ 159 | scr_printf(" FORTUNA rev2 detected on mc0! \n"); 160 | FORTUNA = 1; 161 | MC0T = 1; 162 | strcpy(device,"mc0:"); 163 | strcpy(folder,"/FORTUNA/"); 164 | } 165 | fioClose(fd); 166 | fd = fioOpen("mc1:/FORTUNA/icon.icn", O_RDONLY); 167 | if (getFileSize(fd) == 51040){ 168 | scr_printf(" FORTUNA rev1 detected on mc1! (Newer version available) \n"); 169 | FORTUNA = 1; 170 | MC1T = 1; 171 | strcpy(device,"mc1:"); 172 | strcpy(folder,"/FORTUNA/"); 173 | } else if (getFileSize(fd) == 16876){ 174 | scr_printf(" FORTUNA rev2 detected on mc1! \n"); 175 | FORTUNA = 1; 176 | MC1T = 1; 177 | strcpy(device,"mc1:"); 178 | strcpy(folder,"/FORTUNA/"); 179 | } 180 | fioClose(fd); 181 | scr_printf(" \n * CROSS * Use Device: mc0 and Folder: FORTUNA \n"); 182 | scr_printf(" \n * CIRCLE * Use Device: mass and Folder: FORTUNA \n"); 183 | scr_printf(" \n * TRIANGLE * Use Device: mc0 and Folder: APPS \n"); 184 | scr_printf(" \n * SQUARE * Use Device: mass and Folder: APPS \n"); 185 | scr_printf(" \n * L1 * Use Device: mc1 and Folder: FORTUNA \n"); 186 | scr_printf(" \n * R1 * Use Device: mc1 and Folder: APPS \n"); 187 | scr_printf(" \n * SELECT * Launch FMCB from mc0 \n"); 188 | scr_printf(" \n * START * Launch FMCB from mc1 \n"); 189 | devshown = 1; 190 | } 191 | if (state != 1) { 192 | //scr_printf("Debug: %d \n",state); 193 | //scr_printf("Debug: %d \n", new_pad); 194 | if (menushown == 1 && devshown == 1 && devset == 1) { 195 | if (new_pad == 32768) { 196 | target = device; 197 | strcat(target,folder); 198 | path = target; 199 | strcat(target,"snes_emu.elf"); 200 | scr_printf(" \nPreparing to run SNESStation (%s) ... \n", target); 201 | sleep(1); 202 | LoadElf(target,path); 203 | } else if (new_pad == 16384) { 204 | target = device; 205 | strcat(target,folder); 206 | path = target; 207 | strcat(target,"WLE.ELF"); 208 | scr_printf(" \nPreparing to run wLaunchElf (%s) ... \n", target); 209 | sleep(1); 210 | LoadElf(target,path); 211 | } else if (new_pad == 8192) { 212 | target = device; 213 | strcat(target,folder); 214 | path = target; 215 | strcat(target,"OPL.ELF"); 216 | scr_printf(" \nPreparing to run OPL Open PS2 Loader (%s) ... \n", target); 217 | sleep(1); 218 | LoadElf(target,path); 219 | } else if (new_pad == 4096) { 220 | target = device; 221 | strcat(target,folder); 222 | path = target; 223 | strcat(target,"GSM.ELF"); 224 | scr_printf(" \nPreparing to run GSM (%s) ... \n", target); 225 | sleep(1); 226 | LoadElf(target,path); 227 | } else if (new_pad == 2048) { 228 | target = device; 229 | strcat(target,folder); 230 | path = target; 231 | strcat(target,"retroarchps2_picodrive.elf"); 232 | scr_printf(" \nPreparing to run RetroArch PicoDrive Core (%s) ... \n", target); 233 | sleep(1); 234 | LoadElf(target,path); 235 | } else if (new_pad == 1024) { 236 | target = device; 237 | strcat(target,folder); 238 | path = target; 239 | strcat(target,"retroarchps2_2048.elf"); 240 | scr_printf(" \nPreparing to run RetroArch 2048 Core (%s) ... \n", target); 241 | sleep(1); 242 | LoadElf(target,path); 243 | } else if (new_pad == 512) { 244 | target = device; 245 | strcat(target,folder); 246 | path = target; 247 | strcat(target,"retroarchps2_quicknes.elf"); 248 | scr_printf(" \nPreparing to run RetroArch QuickNES Core (%s) ... \n", target); 249 | sleep(1); 250 | LoadElf(target,path); 251 | } else if (new_pad == 256) { 252 | target = device; 253 | strcat(target,folder); 254 | path = target; 255 | strcat(target,"retroarchps2_fceumm.elf"); 256 | scr_printf(" \nPreparing to run RetroArch FCEUmm Core (%s) ... \n", target); 257 | sleep(1); 258 | LoadElf(target,path); 259 | } else if (new_pad == 128) { 260 | target = device; 261 | strcat(target,folder); 262 | path = target; 263 | strcat(target,"CUSTOM1.ELF"); 264 | scr_printf(" \nPreparing to run CUSTOM1 (%s) ... \n", target); 265 | sleep(1); 266 | LoadElf(target,path); 267 | } else if (new_pad == 64) { 268 | target = device; 269 | strcat(target,folder); 270 | path = target; 271 | strcat(target,"HDL.ELF"); 272 | scr_printf(" \nPreparing to run HDL (%s) ... \n", target); 273 | sleep(1); 274 | LoadElf(target,path); 275 | } else if (new_pad == 32) { 276 | target = device; 277 | strcat(target,folder); 278 | path = target; 279 | strcat(target,"CUSTOM2.ELF"); 280 | scr_printf(" \nPreparing to run CUSTOM2 (%s) ... \n", target); 281 | sleep(1); 282 | LoadElf(target,path); 283 | } else if (new_pad == 16) { 284 | target = device; 285 | strcat(target,folder); 286 | path = target; 287 | strcat(target,"ESR.ELF"); 288 | scr_printf(" \nPreparing to run ESR (%s) ... \n", target); 289 | sleep(1); 290 | LoadElf(target,path); 291 | } else if (new_pad == 8) { 292 | target = device; 293 | strcat(target,folder); 294 | path = target; 295 | strcat(target,"BOOT.ELF"); 296 | scr_printf(" \nPreparing to return to OSD ...\n"); 297 | sleep(1); 298 | break; 299 | } else if (new_pad == 4) { 300 | target = device; 301 | strcat(target,folder); 302 | path = target; 303 | strcat(target,"PS2Ident.elf"); 304 | scr_printf(" \nPreparing to run PS2Ident (%s) ... \n", target); 305 | sleep(1); 306 | LoadElf(target,path); 307 | } else if (new_pad == 2) { 308 | target = device; 309 | strcat(target,folder); 310 | path = target; 311 | strcat(target,"retroarchps2_mgba.elf"); 312 | scr_printf(" \nPreparing to run RetroArch mGBA Core (%s) ... \n", target); 313 | sleep(1); 314 | LoadElf(target,path); 315 | } 316 | } //devshown,devset,menushown 317 | }// state,cdstatus 318 | //SEL = 1 319 | //L3 = 2 320 | //R3 = 4 321 | //STR = 8 322 | //UP = 16 323 | //RGT = 32 324 | //DWN = 64 325 | //LFT = 128 326 | //L2 = 256 327 | //R2 = 512 328 | //L1 = 1024 329 | //R1 = 2048 330 | // /\ = 4096 331 | // O = 8192 332 | // X = 16384 333 | //[ ] = 32768 334 | if (menushown == 0 && devset == 1) { 335 | banner(); 336 | scr_printf("Device: %s Folder: %s \n", device, folder); 337 | scr_printf(" \n * CROSS * Run wLaunchElf"); 338 | scr_printf(" \n * CIRCLE * Run OPL Open PS2 Loader"); 339 | scr_printf(" \n * TRIANGLE * Run GSM"); 340 | scr_printf(" \n * SQUARE * Run SNESStation"); 341 | scr_printf(" \n * L1 * Run RetroArch 2048"); 342 | scr_printf(" \n * L2 * Run RetroArch FCEUmm"); 343 | scr_printf(" \n * L3 * Run RetroArch mGBA"); 344 | scr_printf(" \n * R1 * Run RetroArch PicoDrive"); 345 | scr_printf(" \n * R2 * Run RetroArch QuickNES"); 346 | scr_printf(" \n * R3 * Run PS2Ident"); 347 | scr_printf(" \n * UP * Run ESR"); 348 | scr_printf(" \n * DOWN * Run HDL"); 349 | scr_printf(" \n * LEFT * Run CUSTOM1.ELF"); 350 | scr_printf(" \n * RIGHT * Run CUSTOM2.ELF"); 351 | scr_printf(" \n \nPush START to exit. \n"); 352 | //scr_printf(" \n \nController ready. Waiting for input... \n"); 353 | menushown = 1; 354 | } 355 | if (devshown == 1 && devset == 0) { 356 | if (new_pad != 0) { 357 | //scr_printf("Debug: %d \n", new_pad); 358 | //scr_printf("Debug: %s \n", OSDGetSystemExecFolder()); 359 | } 360 | if (new_pad == 16384) { 361 | strcpy(device,"mc0:"); 362 | strcpy(folder,"/FORTUNA/"); 363 | scr_setXY(1,7); 364 | scr_printf("Device: %s Folder: %s \n", device, folder); 365 | devset = 1; 366 | } else if (new_pad == 8192) { 367 | strcpy(device,"mass:"); 368 | strcpy(folder,"/FORTUNA/"); 369 | scr_setXY(1,7); 370 | scr_printf("Device: %s Folder: %s \n", device, folder); 371 | devset = 1; 372 | } else if (new_pad == 4096) { 373 | strcpy(device,"mc0:"); 374 | strcpy(folder,"/APPS/"); 375 | scr_setXY(1,7); 376 | scr_printf("Device: %s Folder: %s \n", device, folder); 377 | devset = 1; 378 | } else if (new_pad == 32768) { 379 | strcpy(device,"mass:"); 380 | strcpy(folder,"/APPS/"); 381 | scr_setXY(1,7); 382 | scr_printf("Device: %s Folder: %s \n", device, folder); 383 | devset = 1; 384 | } else if (new_pad == 1024) { 385 | strcpy(device,"mc1:"); 386 | strcpy(folder,"/FORTUNA/"); 387 | scr_setXY(1,7); 388 | scr_printf("Device: %s Folder: %s \n", device, folder); 389 | devset = 1; 390 | } else if (new_pad == 2048) { 391 | strcpy(device,"mc1:"); 392 | strcpy(folder,"/APPS/"); 393 | scr_setXY(1,7); 394 | scr_printf("Device: %s Folder: %s \n", device, folder); 395 | devset = 1; 396 | } else if (new_pad == 1) { 397 | //not sure how, but device names appear to be backwards. Only for LoadExecPS2(), Not ExecPS2() 398 | //specify mc1: get FMCB menu from mc0, speciy mc0: get FMCB menu from mc1 399 | strncpy(device,"-x mc1:/",8); 400 | strncpy(folder,OSDGetSystemExecFolder(),13); 401 | scr_setXY(1,7); 402 | //scr_printf("Device: %s Folder: %s \n", device, folder); 403 | target = device; 404 | strncat(target,folder,13); 405 | path = target; 406 | strncat(target,"/osdmain.elf",12); 407 | char *args[3]; 408 | args[0] = "-m rom0:SIO2MAN"; 409 | args[1] = "-m rom0:MCMAN"; 410 | args[2] = target; 411 | scr_printf(" \n Preparing to launch FMCB from Memory Card Slot 1 (mc0:) \n \n \n \n \n \n \n \n \n \n \n \n \n \n"); 412 | sleep(2); 413 | LoadExecPS2("moduleload", 3, args); 414 | devset = 0; 415 | } else if (new_pad == 8) { 416 | //not sure how, but device names appear to be backwards. Only for LoadExecPS2(), Not ExecPS2() 417 | //specify mc1: get FMCB menu from mc0, speciy mc0: get FMCB menu from mc1 418 | strncpy(device,"-x mc0:/",8); 419 | strncpy(folder,OSDGetSystemExecFolder(),13); 420 | scr_setXY(1,7); 421 | //scr_printf("Device: %s Folder: %s \n", device, folder); 422 | target = device; 423 | strncat(target,folder,13); 424 | path = target; 425 | strncat(target,"/osdmain.elf",12); 426 | char *args[3]; 427 | args[0] = "-m rom0:SIO2MAN"; 428 | args[1] = "-m rom0:MCMAN"; 429 | args[2] = target; 430 | scr_printf(" \n Preparing to launch FMCB from Memory Card Slot 2 (mc1:) \n \n \n \n \n \n \n \n \n \n \n \n \n \n"); 431 | sleep(2); 432 | LoadExecPS2("moduleload", 3, args); 433 | devset = 0; 434 | } 435 | } 436 | //scr_printf("Debug: %d \n", devset); 437 | } //main loop 438 | } // controller ready 439 | return 0; 440 | } 441 | -------------------------------------------------------------------------------- /FORTUNA_Launcher.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //** pad.c and pad related functions from wLaunchElf 8d4a0c2 5 | 6 | #define PAD_R3_V0 0x010000 7 | #define PAD_R3_V1 0x020000 8 | #define PAD_R3_H0 0x040000 9 | #define PAD_R3_H1 0x080000 10 | #define PAD_L3_V0 0x100000 11 | #define PAD_L3_V1 0x200000 12 | #define PAD_L3_H0 0x400000 13 | #define PAD_L3_H1 0x800000 14 | 15 | extern u32 joy_value; 16 | extern u32 new_pad; 17 | int setupPad(void); 18 | int readpad(void); 19 | int readpad_no_KB(void); 20 | int readpad_noRepeat(void); 21 | void waitPadReady(int port, int slot); 22 | void waitAnyPadReady(void); 23 | //** end 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION = 0.46 2 | 3 | EE_BIN = FORTUNA_Launcher.ELF 4 | EE_BIN_PACKED = BOOT-packed.ELF 5 | EE_BIN_STRIPPED = BOOT-stripped.ELF 6 | EE_OBJS = FORTUNA_Launcher.o pad.o OSDInit.o libcdvd_add.o 7 | EE_LIBS = -lc -lcdvd -lpatches -ldebug -lpad 8 | 9 | all: 10 | @echo "Building FORTUNA Launcher $(VERSION) ..." 11 | $(MAKE) $(EE_BIN_PACKED) 12 | 13 | clean: 14 | @echo "Cleaning ..." 15 | rm -fr $(EE_BIN) $(EE_BIN_PACKED) $(EE_BIN_STRIPPED) *.o *.bak 16 | 17 | run: $(EE_BIN) 18 | ps2client execee host:$(EE_BIN) 19 | 20 | reset: 21 | ps2client reset 22 | 23 | $(EE_BIN_STRIPPED): $(EE_BIN) 24 | @echo "Stripping ..." 25 | $(EE_STRIP) -o $@ $< 26 | 27 | $(EE_BIN_PACKED): $(EE_BIN_STRIPPED) 28 | @echo "Compressing ..." 29 | ~/ps2homebrew/ps2-packer/ps2-packer -v $< $@ 30 | 31 | include $(PS2SDK)/samples/Makefile.pref 32 | include $(PS2SDK)/samples/Makefile.eeglobal -------------------------------------------------------------------------------- /OSDInit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "libcdvd_add.h" 6 | #include 7 | 8 | #include "OSDInit.h" 9 | 10 | /* Parsing of values from the EEPROM and setting them into the EE kernel 11 | was done in different ways, across different browser versions. 12 | 13 | The early browsers of ROM v1.00 and v1.01 (SCPH-10000/SCPH-15000) 14 | parsed the values within the EEPROM into global variables, 15 | which are used to set the individual fields in the OSD configuration. 16 | 17 | The newer browsers parsed the values into a bitfield structure, 18 | which does not have the same layout as the OSD configuration structure. 19 | 20 | Both designs had the parsing and the preparation of the OSD 21 | configuration data separated, presumably for clarity of code and 22 | to achieve low-coupling (perhaps they belonged to different modules). */ 23 | 24 | static int ConsoleRegion = -1, ConsoleOSDRegion = -1, ConsoleOSDLanguage = -1; 25 | static int ConsoleOSDRegionInitStatus = 0, ConsoleRegionParamInitStatus = 0; //0 = Not init. 1 = Init complete. <0 = Init failed. 26 | static u8 ConsoleRegionData[16] = {0, 0, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 27 | 28 | //Perhaps it once used to read more configuration blocks (original capacity was 7 blocks). 29 | static u8 OSDConfigBuffer[CONFIG_BLOCK_SIZE * 2]; 30 | 31 | //Local function prototypes 32 | static int InitMGRegion(void); 33 | static int ConsoleInitRegion(void); 34 | static int ConsoleRegionParamsInitPS1DRV(const char *romver); 35 | static int GetConsoleRegion(void); 36 | static int CdReadOSDRegionParams(char *OSDVer); 37 | static int GetOSDRegion(void); 38 | static void InitOSDDefaultLanguage(int region, const char *language); 39 | static int ReadOSDConfigPS2(OSDConfig2_t *config, const OSDConfigStore_t* OSDConfigBuffer); 40 | static void ReadOSDConfigPS1(OSDConfig1_t *config, const OSDConfigStore_t* OSDConfigBuffer); 41 | static void WriteOSDConfigPS1(OSDConfigStore_t* OSDConfigBuffer, const OSDConfig1_t *config); 42 | static void WriteOSDConfigPS2(OSDConfigStore_t* OSDConfigBuffer, const OSDConfig2_t *config, u8 invalid); 43 | static void ReadConfigFromNVM(u8 *buffer); 44 | static void WriteConfigToNVM(const u8 *buffer); 45 | 46 | //Directory names 47 | static char SystemDataFolder[]="BRDATA-SYSTEM"; 48 | static char SystemExecFolder[]="BREXEC-SYSTEM"; 49 | static char DVDPLExecFolder[]="BREXEC-DVDPLAYER"; 50 | 51 | char ConsoleROMVER[ROMVER_MAX_LEN]; 52 | 53 | static int InitMGRegion(void) 54 | { 55 | u32 stat; 56 | int result; 57 | 58 | if(ConsoleRegionParamInitStatus == 0) 59 | { 60 | do{ 61 | if((result = sceCdReadRegionParams(ConsoleRegionData, &stat)) == 0) 62 | { //Failed. 63 | ConsoleRegionParamInitStatus=1; 64 | } 65 | else 66 | { 67 | if(stat & 0x100) 68 | { 69 | //MECHACON does not support this function. 70 | ConsoleRegionParamInitStatus=-1; 71 | break; 72 | } 73 | else 74 | { //Status OK, but the result yielded an error. 75 | ConsoleRegionParamInitStatus=1; 76 | } 77 | } 78 | }while((result == 0) || (stat & 0x80)); 79 | } 80 | 81 | return ConsoleRegionParamInitStatus; 82 | } 83 | 84 | void OSDInitSystemPaths(void) 85 | { 86 | int region; 87 | char regions[CONSOLE_REGION_COUNT]={'I', 'A', 'E', 'C'}; 88 | 89 | region = OSDGetConsoleRegion(); 90 | if(region>=0 && region=0)?ConsoleRegionData[8]:0); 101 | } 102 | 103 | static int ConsoleInitRegion(void) 104 | { 105 | GetOSDRegion(); 106 | return InitMGRegion(); 107 | } 108 | 109 | static int ConsoleRegionParamsInitPS1DRV(const char *romver) 110 | { 111 | int result; 112 | 113 | if(ConsoleInitRegion() >= 0) 114 | { 115 | ConsoleRegionData[2] = romver[4]; 116 | result = 1; 117 | } else 118 | result = 0; 119 | 120 | return result; 121 | } 122 | 123 | /* Present here, but not sure what it is (unused) 124 | int OSDGetROMRegion(char *out) 125 | { 126 | int result; 127 | 128 | if(ConsoleInitRegion() >= 0) 129 | { 130 | out[4] = ConsoleRegionData[2]; 131 | result = 1; 132 | } 133 | else 134 | result = 0; 135 | 136 | return result; 137 | } */ 138 | 139 | int OSDGetPS1DRVRegion(char *region) 140 | { 141 | int result; 142 | 143 | if(ConsoleInitRegion() >= 0) 144 | { 145 | *region = ConsoleRegionData[2]; 146 | result = 1; 147 | } 148 | else 149 | result = 0; 150 | 151 | return result; 152 | } 153 | 154 | int OSDGetDVDPlayerRegion(char *region) 155 | { 156 | int result; 157 | 158 | if(ConsoleInitRegion() >= 0) 159 | { 160 | *region = ConsoleRegionData[8]; 161 | result = 1; 162 | } 163 | else 164 | result = 0; 165 | 166 | return result; 167 | } 168 | 169 | static int GetConsoleRegion(void) 170 | { 171 | char romver[16]; 172 | int fd, result; 173 | 174 | if((result=ConsoleRegion)<0) 175 | { 176 | if((fd = open("rom0:ROMVER", O_RDONLY)) >= 0) 177 | { 178 | read(fd, romver, sizeof(romver)); 179 | close(fd); 180 | ConsoleRegionParamsInitPS1DRV(romver); 181 | 182 | switch(romver[4]) 183 | { 184 | case 'C': 185 | ConsoleRegion=CONSOLE_REGION_CHINA; 186 | break; 187 | case 'E': 188 | ConsoleRegion=CONSOLE_REGION_EUROPE; 189 | break; 190 | case 'H': 191 | case 'A': 192 | ConsoleRegion=CONSOLE_REGION_USA; 193 | break; 194 | case 'J': 195 | ConsoleRegion=CONSOLE_REGION_JAPAN; 196 | } 197 | 198 | result=ConsoleRegion; 199 | } else 200 | result = -1; 201 | } 202 | 203 | return result; 204 | } 205 | 206 | static int CdReadOSDRegionParams(char *OSDVer) 207 | { 208 | int result; 209 | 210 | if(OSDVer[4] == '?') 211 | { 212 | if(InitMGRegion() >= 0) 213 | { 214 | result = 1; 215 | OSDVer[4] = ConsoleRegionData[3]; 216 | OSDVer[5] = ConsoleRegionData[4]; 217 | OSDVer[6] = ConsoleRegionData[5]; 218 | OSDVer[7] = ConsoleRegionData[6]; 219 | } else 220 | result = 0; 221 | } else { 222 | ConsoleRegionParamInitStatus = -256; 223 | result = 0; 224 | } 225 | 226 | return result; 227 | } 228 | 229 | static int GetOSDRegion(void) 230 | { 231 | char OSDVer[16]; 232 | int fd; 233 | 234 | if(ConsoleOSDRegionInitStatus == 0 || ConsoleOSDRegion == -1) 235 | { 236 | ConsoleOSDRegionInitStatus = 1; 237 | if((fd = open("rom0:OSDVER", O_RDONLY)) >= 0) 238 | { 239 | read(fd, OSDVer, sizeof(OSDVer)); 240 | close(fd); 241 | CdReadOSDRegionParams(OSDVer); 242 | switch(OSDVer[4]) 243 | { 244 | case 'A': 245 | ConsoleOSDRegion = OSD_REGION_USA; 246 | break; 247 | case 'C': 248 | ConsoleOSDRegion = OSD_REGION_CHINA; 249 | break; 250 | case 'E': 251 | ConsoleOSDRegion = OSD_REGION_EUROPE; 252 | break; 253 | case 'H': 254 | ConsoleOSDRegion = OSD_REGION_ASIA; 255 | break; 256 | case 'J': 257 | ConsoleOSDRegion = OSD_REGION_JAPAN; 258 | break; 259 | case 'K': 260 | ConsoleOSDRegion = OSD_REGION_KOREA; 261 | break; 262 | case 'R': 263 | ConsoleOSDRegion = OSD_REGION_RUSSIA; 264 | break; 265 | default: 266 | ConsoleOSDRegion = OSD_REGION_INVALID; 267 | } 268 | 269 | if(ConsoleOSDRegion != OSD_REGION_INVALID) 270 | InitOSDDefaultLanguage(ConsoleOSDRegion, &OSDVer[5]); 271 | } else 272 | ConsoleOSDRegion = OSD_REGION_INVALID; 273 | } 274 | 275 | return ConsoleOSDRegion; 276 | } 277 | 278 | static void InitOSDDefaultLanguage(int region, const char *language) 279 | { 280 | int DefaultLang; 281 | 282 | DefaultLang = -1; 283 | if(ConsoleOSDLanguage == -1) 284 | { 285 | if(language != NULL) 286 | { 287 | if(strncmp(language, "jpn", 3) == 0) 288 | DefaultLang = LANGUAGE_JAPANESE; 289 | else if(strncmp(language, "eng", 3) == 0) 290 | DefaultLang = LANGUAGE_ENGLISH; 291 | else if(strncmp(language, "fre", 3) == 0) 292 | DefaultLang = LANGUAGE_FRENCH; 293 | else if(strncmp(language, "spa", 3) == 0) 294 | DefaultLang = LANGUAGE_SPANISH; 295 | else if(strncmp(language, "ger", 3) == 0) 296 | DefaultLang = LANGUAGE_GERMAN; 297 | else if(strncmp(language, "ita", 3) == 0) 298 | DefaultLang = LANGUAGE_ITALIAN; 299 | else if(strncmp(language, "dut", 3) == 0) 300 | DefaultLang = LANGUAGE_DUTCH; 301 | else if(strncmp(language, "por", 3) == 0) 302 | DefaultLang = LANGUAGE_PORTUGUESE; 303 | else if(strncmp(language, "rus", 3) == 0) 304 | DefaultLang = LANGUAGE_RUSSIAN; 305 | else if(strncmp(language, "kor", 3) == 0) 306 | DefaultLang = LANGUAGE_KOREAN; 307 | else if(strncmp(language, "tch", 3) == 0) 308 | DefaultLang = LANGUAGE_TRAD_CHINESE; 309 | else if(strncmp(language, "sch", 3) == 0) 310 | DefaultLang = LANGUAGE_SIMPL_CHINESE; 311 | else DefaultLang = -1; 312 | } 313 | 314 | //Check if the specified language is valid for the region 315 | if(!OSDIsLanguageValid(region, DefaultLang)) 316 | { 317 | switch(region) 318 | { 319 | case OSD_REGION_JAPAN: 320 | DefaultLang = LANGUAGE_JAPANESE; 321 | break; 322 | case OSD_REGION_CHINA: 323 | DefaultLang = LANGUAGE_SIMPL_CHINESE; 324 | break; 325 | case OSD_REGION_RUSSIA: 326 | DefaultLang = LANGUAGE_RUSSIAN; 327 | break; 328 | case OSD_REGION_KOREA: 329 | DefaultLang = LANGUAGE_KOREAN; 330 | break; 331 | case OSD_REGION_USA: 332 | case OSD_REGION_EUROPE: 333 | case OSD_REGION_ASIA: 334 | default: 335 | DefaultLang = LANGUAGE_ENGLISH; 336 | } 337 | } 338 | 339 | ConsoleOSDLanguage = DefaultLang; 340 | } 341 | } 342 | 343 | int OSDIsLanguageValid(int region, int language) 344 | { 345 | switch(region) 346 | { 347 | case OSD_REGION_JAPAN: 348 | return(language == LANGUAGE_JAPANESE || language == LANGUAGE_ENGLISH) ? language : -1; 349 | case OSD_REGION_CHINA: 350 | return(language == LANGUAGE_ENGLISH || language == LANGUAGE_SIMPL_CHINESE) ? language : -1; 351 | case OSD_REGION_RUSSIA: 352 | return(language == LANGUAGE_ENGLISH || language == LANGUAGE_RUSSIAN) ? language : -1; 353 | case OSD_REGION_KOREA: 354 | return(language == LANGUAGE_ENGLISH || language == LANGUAGE_KOREAN) ? language : -1; 355 | case OSD_REGION_ASIA: 356 | return(language == LANGUAGE_ENGLISH || language == LANGUAGE_TRAD_CHINESE) ? language : -1; 357 | case OSD_REGION_USA: 358 | case OSD_REGION_EUROPE: 359 | default: 360 | return(language <= LANGUAGE_PORTUGUESE && region > OSD_REGION_JAPAN) ? language : -1; 361 | } 362 | } 363 | 364 | int OSDGetConsoleRegion(void) 365 | { //Default to Japan, if the region cannot be obtained. 366 | int result; 367 | 368 | result=GetConsoleRegion(); 369 | 370 | return(result < 0 ? 0 : result); 371 | } 372 | 373 | int OSDGetVideoMode(void) 374 | { 375 | return(GetConsoleRegion() == CONSOLE_REGION_EUROPE); 376 | } 377 | 378 | int OSDGetRegion(void) 379 | { 380 | int region; 381 | 382 | if((region = GetOSDRegion()) < 0) 383 | { 384 | region = OSDGetConsoleRegion(); 385 | InitOSDDefaultLanguage(region, NULL); 386 | } 387 | 388 | return region; 389 | } 390 | 391 | int OSDGetDefaultLanguage(void) 392 | { 393 | if(ConsoleOSDLanguage == -1) 394 | OSDGetRegion(); 395 | 396 | return ConsoleOSDLanguage; 397 | } 398 | 399 | /* Notes: 400 | Version = 0 (Protokernel consoles only) NTSC-J, 1 = ROM versions up to v1.70, 2 = v1.80 and later. 2 = support for extended languages (Osd2 bytes 3 and 4) 401 | In the homebrew PS2SDK, this was previously known as the "region". 402 | japLanguage = 0 (Japanese, protokernel consoles only), 1 = non-Japanese (Protokernel consoles only). Newer browsers have this set always to 1. 403 | */ 404 | static int ReadOSDConfigPS2(OSDConfig2_t *config, const OSDConfigStore_t* OSDConfigBuffer) 405 | { 406 | config->spdifMode = OSDConfigBuffer->PS2.spdifMode; 407 | config->screenType = OSDConfigBuffer->PS2.screenType; 408 | config->videoOutput = OSDConfigBuffer->PS2.videoOutput; 409 | 410 | if (OSDConfigBuffer->PS2.extendedLanguage) //Extended/Basic language set 411 | { //One of the 8 standard languages 412 | config->language = OSDConfigBuffer->PS2.language; 413 | } 414 | else 415 | { //Japanese/English 416 | config->language = OSDConfigBuffer->PS2.japLanguage; 417 | } 418 | 419 | config->daylightSaving = OSDConfigBuffer->PS2.daylightSaving; 420 | config->timeFormat = OSDConfigBuffer->PS2.timeFormat; 421 | config->dateFormat = OSDConfigBuffer->PS2.dateFormat; 422 | config->timezoneOffset = OSDConfigBuffer->PS2.timezoneOffsetLo | ((u32)OSDConfigBuffer->PS2.timezoneOffsetHi) << 8; 423 | config->timezone = OSDConfigBuffer->PS2.timezoneLo | (((u32)OSDConfigBuffer->PS2.timezoneHi) << 8); 424 | config->rcEnabled = OSDConfigBuffer->PS2.rcEnabled; 425 | config->rcGameFunction = OSDConfigBuffer->PS2.rcGameFunction; 426 | config->rcSupported = OSDConfigBuffer->PS2.rcSupported; 427 | config->dvdpProgressive = OSDConfigBuffer->PS2.dvdpProgressive; 428 | 429 | return(OSDConfigBuffer->PS2.osdInit ^ 1); 430 | } 431 | 432 | static void ReadOSDConfigPS1(OSDConfig1_t *config, const OSDConfigStore_t* OSDConfigBuffer) 433 | { 434 | int i; 435 | 436 | for(i = 0; i < CONFIG_BLOCK_SIZE; i++) 437 | config->data[i] = OSDConfigBuffer->PS1.bytes[i]; 438 | } 439 | 440 | static void WriteOSDConfigPS1(OSDConfigStore_t* OSDConfigBuffer, const OSDConfig1_t *config) 441 | { 442 | int i; 443 | 444 | for(i = 0; i < CONFIG_BLOCK_SIZE; i++) 445 | OSDConfigBuffer->PS1.bytes[i] = config->data[i]; 446 | } 447 | 448 | static void WriteOSDConfigPS2(OSDConfigStore_t* OSDConfigBuffer, const OSDConfig2_t *config, u8 invalid) 449 | { 450 | int japLanguage, version, osdInitValue; 451 | 452 | osdInitValue = invalid ^ 1; 453 | version = OSDConfigBuffer->PS2.extendedLanguage == 0 ? 1 : OSDConfigBuffer->PS2.extendedLanguage; 454 | 455 | if(config->language <= LANGUAGE_ENGLISH) 456 | japLanguage = config->language; 457 | else //Do not update the legacy language option if the language was changed to something unsupported. 458 | japLanguage = OSDConfigBuffer->PS2.japLanguage; 459 | 460 | //0x0F 461 | OSDConfigBuffer->PS2.videoOutput = config->videoOutput; 462 | OSDConfigBuffer->PS2.japLanguage = japLanguage; 463 | OSDConfigBuffer->PS2.extendedLanguage = 1; 464 | OSDConfigBuffer->PS2.spdifMode = config->spdifMode; 465 | OSDConfigBuffer->PS2.screenType = config->screenType; 466 | 467 | //0x10 468 | OSDConfigBuffer->PS2.language = config->language; 469 | OSDConfigBuffer->PS2.version = version; 470 | 471 | //0x11 472 | OSDConfigBuffer->PS2.timezoneOffsetHi = config->timezoneOffset >> 8; 473 | OSDConfigBuffer->PS2.dateFormat = config->dateFormat; 474 | OSDConfigBuffer->PS2.timeFormat = config->timeFormat; 475 | OSDConfigBuffer->PS2.daylightSaving = config->daylightSaving; 476 | OSDConfigBuffer->PS2.osdInit = osdInitValue; 477 | 478 | //0x12 479 | OSDConfigBuffer->PS2.timezoneOffsetLo = config->timezoneOffset; 480 | 481 | //0x13 482 | OSDConfigBuffer->PS2.timezoneHi = config->timezone >> 8; 483 | OSDConfigBuffer->PS2.unknownB13_01 = OSDConfigBuffer->PS2.unknownB13_01; //Carry over 484 | OSDConfigBuffer->PS2.rcEnabled = config->rcEnabled; 485 | OSDConfigBuffer->PS2.rcGameFunction = config->rcGameFunction; 486 | OSDConfigBuffer->PS2.rcSupported = config->rcSupported; 487 | OSDConfigBuffer->PS2.dvdpProgressive = config->dvdpProgressive; 488 | 489 | //0x14 490 | OSDConfigBuffer->PS2.timezoneLo = config->timezone; 491 | } 492 | 493 | static void ReadConfigFromNVM(u8 *buffer) 494 | { /* Hmm. What should the check for stat be? In v1.xx, it seems to be a check against 0x9. In v2.20, it checks against 0x81. 495 | In the HDD Browser, reading checks against 0x81, while writing checks against 0x9. 496 | But because we are targeting all consoles, it would be probably safer to follow the HDD Browser. */ 497 | int result; 498 | u32 stat; 499 | 500 | do{ 501 | sceCdOpenConfig(1, 0, 2, &stat); 502 | }while(stat & 0x81); 503 | 504 | do{ 505 | result=sceCdReadConfig(buffer, &stat); 506 | }while((stat & 0x81) || (result == 0)); 507 | 508 | do{ 509 | result=sceCdCloseConfig(&stat); 510 | }while((stat & 0x81) || (result == 0)); 511 | } 512 | 513 | static void WriteConfigToNVM(const u8 *buffer) 514 | { // Read the comment in ReadConfigFromNVM() about the error status bits. 515 | u32 stat; 516 | int result; 517 | 518 | do{ 519 | sceCdOpenConfig(1, 1, 2, &stat); 520 | }while(stat & 0x09); 521 | 522 | do{ 523 | result=sceCdWriteConfig(buffer, &stat); 524 | }while((stat & 0x09) || (result == 0)); 525 | 526 | do{ 527 | result=sceCdCloseConfig(&stat); 528 | }while((stat & 9) || (result == 0)); 529 | } 530 | 531 | int OSDLoadConfigFromNVM(OSDConfig1_t *osdConfigPS1, OSDConfig2_t *osdConfigPS2) 532 | { 533 | int result; 534 | 535 | ReadConfigFromNVM(OSDConfigBuffer); 536 | result = ReadOSDConfigPS2(osdConfigPS2, (const OSDConfigStore_t*)OSDConfigBuffer); 537 | ReadOSDConfigPS1(osdConfigPS1, (const OSDConfigStore_t*)OSDConfigBuffer); 538 | 539 | return result; 540 | } 541 | 542 | int OSDSaveConfigToNVM(const OSDConfig1_t *osdConfigPS1, const OSDConfig2_t *osdConfigPS2, u8 invalid) 543 | { 544 | WriteOSDConfigPS1((OSDConfigStore_t*)OSDConfigBuffer, osdConfigPS1); 545 | WriteOSDConfigPS2((OSDConfigStore_t*)OSDConfigBuffer, osdConfigPS2, invalid); 546 | WriteConfigToNVM(OSDConfigBuffer); 547 | 548 | return 0; 549 | } 550 | 551 | //Directory management 552 | const char *OSDGetHistoryDataFolder(void) 553 | { 554 | return SystemDataFolder; 555 | } 556 | 557 | const char *OSDGetSystemDataFolder(void) 558 | { 559 | return SystemDataFolder; 560 | } 561 | 562 | const char *OSDGetSystemExecFolder(void) 563 | { 564 | return SystemExecFolder; 565 | } 566 | 567 | const char *OSDGetDVDPLExecFolder(void) 568 | { 569 | return DVDPLExecFolder; 570 | } 571 | 572 | int OSDInitROMVER(void) 573 | { 574 | int fd; 575 | 576 | memset(ConsoleROMVER, 0, ROMVER_MAX_LEN); 577 | if((fd = open("rom0:ROMVER", O_RDONLY)) >= 0) 578 | { 579 | read(fd, ConsoleROMVER, ROMVER_MAX_LEN); 580 | close(fd); 581 | } 582 | 583 | return 0; 584 | } 585 | -------------------------------------------------------------------------------- /OSDInit.h: -------------------------------------------------------------------------------- 1 | #define ROMVER_MAX_LEN 16 2 | 3 | int OSDInitROMVER(void); 4 | 5 | #define CONFIG_BLOCK_SIZE 15 6 | 7 | enum CONSOLE_REGION{ 8 | CONSOLE_REGION_INVALID = -1, 9 | CONSOLE_REGION_JAPAN = 0, 10 | CONSOLE_REGION_USA, //USA and Asia 11 | CONSOLE_REGION_EUROPE, 12 | CONSOLE_REGION_CHINA, 13 | 14 | CONSOLE_REGION_COUNT 15 | }; 16 | 17 | enum OSD_REGION{ 18 | OSD_REGION_INVALID = -1, 19 | OSD_REGION_JAPAN = 0, 20 | OSD_REGION_USA, 21 | OSD_REGION_EUROPE, 22 | OSD_REGION_CHINA, 23 | OSD_REGION_RUSSIA, 24 | OSD_REGION_KOREA, 25 | OSD_REGION_ASIA, 26 | 27 | OSD_REGION_COUNT 28 | }; 29 | 30 | //Used to store the values, as obtained from the EEPROM/NVM 31 | typedef struct { 32 | /** 0=enabled, 1=disabled */ 33 | /*00*/u32 spdifMode:1; 34 | /** 0=4:3, 1=fullscreen, 2=16:9 */ 35 | /*01*/u32 screenType:2; 36 | /** 0=rgb(scart), 1=component */ 37 | /*03*/u32 videoOutput:1; 38 | /** LANGUAGE_??? value */ 39 | /*04*/u32 language:5; 40 | /** Timezone minutes offset from GMT */ 41 | /*09*/u32 timezoneOffset:11; 42 | /** Timezone ID */ 43 | /*20*/u32 timezone:9; 44 | /** 0=standard(winter), 1=daylight savings(summer) */ 45 | /*29*/u32 daylightSaving:1; 46 | /** 0=24 hour, 1=12 hour */ 47 | /*30*/u32 timeFormat:1; 48 | 49 | /** 0=YYYYMMDD, 1=MMDDYYYY, 2=DDMMYYYY */ 50 | /*00*/u32 dateFormat:2; 51 | /** Remote Control On/Off option */ 52 | /*02*/u32 rcEnabled:1; 53 | /** Remote Control Game Function On/Off */ 54 | /*03*/u32 rcGameFunction:1; 55 | /** Whether the Remote Control is supported by the PlayStation 2. */ 56 | /*04*/u32 rcSupported:1; 57 | /** Whether the DVD player should have progressive scanning enabled. */ 58 | /*05*/u32 dvdpProgressive:1; 59 | } OSDConfig2_t; 60 | 61 | typedef struct { 62 | u8 data[CONFIG_BLOCK_SIZE]; 63 | u8 padding; 64 | } OSDConfig1_t; 65 | 66 | //Structure of OSD Configuration block within EEPROM 67 | typedef struct { 68 | union { 69 | //0x00-0x0E 70 | struct { 71 | u8 ps1drv; 72 | u8 unused[14]; 73 | }; 74 | u8 bytes[CONFIG_BLOCK_SIZE]; 75 | } PS1; 76 | 77 | union { 78 | struct { 79 | //0x0F 80 | u8 spdifMode:1; 81 | u8 screenType:2; 82 | u8 videoOutput:1; 83 | u8 japLanguage:1; 84 | u8 extendedLanguage:1; 85 | u8 unused1:2; //Neither set nor read anywhere. 86 | 87 | //0x10 88 | u8 language:5; 89 | u8 version:3; 90 | 91 | //0x11 92 | u8 timezoneOffsetHi:3; 93 | u8 daylightSaving:1; 94 | u8 timeFormat:1; 95 | u8 dateFormat:2; 96 | u8 osdInit:1; 97 | 98 | //0x12 99 | u8 timezoneOffsetLo; 100 | 101 | //0x13 102 | u8 timezoneHi:1; 103 | u8 unknownB13_01:3; //Value is carried over 104 | u8 dvdpProgressive:1; 105 | u8 rcSupported:1; 106 | u8 rcGameFunction:1; 107 | u8 rcEnabled:1; 108 | 109 | //0x14 110 | u8 timezoneLo; 111 | 112 | //0x15-0x1E 113 | u8 unusedBytes[9]; 114 | }; 115 | 116 | u8 bytes[CONFIG_BLOCK_SIZE]; 117 | } PS2; 118 | } OSDConfigStore_t; 119 | 120 | int OSDIsLanguageValid(int region, int language); //Returns >= 0 if language is valid for use in the specified region. 121 | int OSDGetConsoleRegion(void); //Initializes and returns the console's region (CONSOLE_REGION). 122 | void OSDInitSystemPaths(void); //Initializes system directory names 123 | int OSDGetDefaultLanguage(void); //Returns the default language for the console 124 | int OSDGetRegion(void); //Initializes and returns the OSD region (OSD_REGION). 125 | int OSDGetVideoMode(void); //0 = NTSC, 1 = PAL 126 | 127 | //MagicGate-related functions that are applicable to ROM v2.20 and later 128 | int OSDGetPS1DRVRegion(char *region); //Returns the MagicGate region letter for the PlayStation Driver (returns 0 on error) 129 | int OSDGetDVDPlayerRegion(char *region); //Returns the MagicGate region letter for the DVD Player (returns 0 on error) 130 | int OSDGetMGRegion(void); //Returns MagicGate region letter (returns '\0' on error) 131 | 132 | //Low-level OSD configuration-management functions (Please use the functions in OSDConfig instead) 133 | int OSDLoadConfigFromNVM(OSDConfig1_t *osdConfigPS1, OSDConfig2_t *osdConfigPS2); //Load OSD configuration from NVRAM. Returns 0 on success. 134 | int OSDSaveConfigToNVM(const OSDConfig1_t *osdConfigPS1, const OSDConfig2_t *osdConfigPS2, u8 osdInit); //Save OSD configuration to NVRAM. Returns 0 on success. 135 | 136 | //For retrieving various folder names 137 | const char *OSDGetSystemExecFolder(void); 138 | const char *OSDGetSystemDataFolder(void); 139 | const char *OSDGetDVDPLExecFolder(void); 140 | const char *OSDGetHistoryDataFolder(void); 141 | 142 | //For compatibility with the homebrew SDK 143 | #define sceMcInit mcInit 144 | #define sceMcGetInfo mcGetInfo 145 | #define sceMcOpen mcOpen 146 | #define sceMcClose mcClose 147 | #define sceMcSeek mcSeek 148 | #define sceMcRead mcRead 149 | #define sceMcWrite mcWrite 150 | #define sceMcGetDir mcGetDir 151 | #define sceMcMkDir mcMkDir 152 | #define sceMcSetFileInfo mcSetFileInfo 153 | #define sceMcDelete mcDelete 154 | #define sceMcSync mcSync 155 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PS2_FORTUNA_Launcher 2 | PS2 FORTUNA Homebrew Launcher (BOOT.ELF Replacement) 3 | 4 | 5 | 6 | 7 | 8 | In case anyone missed it, There is a new exploit (PS2 FORTUNA Project) by krat0s https://www.ps2-home.com/forum/viewtopic.php?f=107&t=8542 9 | 10 | This is designed to work with that package/folder/savefile 11 | 12 | Rename FORTUNA_Launcher.elf (or BOOT-packed.ELF) to BOOT.ELF and copy BOOT.ELF, usbd.irx & usbhdfsd.irx to your mc0:/FORTUNA/ folder 13 | 14 | PSX-Place FORTUNA Launcher Release Thread https://www.psx-place.com/threads/fortuna-launcher-by-vtstech-boot-elf-replacement.27254/ 15 | 16 | Demo: https://www.youtube.com/watch?v=bbVLOnL8_W8 17 | 18 | It can use the following paths: 19 | 20 |
 21 | 
 22 | wLaunchElf
 23 | 
 24 | mc0:/FORTUNA/WLE.ELF
 25 | mass:/FORTUNA/WLE.ELF
 26 | mc0:/APPS/WLE.ELF
 27 | mass:/APPS/WLE.ELF
 28 | 
 29 | OPL
 30 | 
 31 | mc0:/FORTUNA/OPL.ELF
 32 | mass:/FORTUNA/OPL.ELF
 33 | mc0:/APPS/OPL.ELF
 34 | mass:/APPS/OPL.ELF
 35 | 
 36 | GSM
 37 | 
 38 | mc0:/FORTUNA/GSM.ELF
 39 | mass:/FORTUNA/GSM.ELF
 40 | mc0:/APPS/GSM.ELF
 41 | mass:/APPS/GSM.ELF
 42 | 
 43 | ESR
 44 | 
 45 | mc0:/FORTUNA/ESR.ELF
 46 | mass:/FORTUNA/ESR.ELF
 47 | mc0:/APPS/ESR.ELF
 48 | mass:/APPS/ESR.ELF
 49 | 
 50 | HDL
 51 | 
 52 | mc0:/FORTUNA/HDL.ELF
 53 | mass:/FORTUNA/HDL.ELF
 54 | mc0:/APPS/HDL.ELF
 55 | mass:/APPS/HDL.ELF
 56 | 
 57 | RetroArch
 58 | 
 59 | mc0:/FORTUNA/retroarchps2_2048.elf
 60 | mc0:/FORTUNA/retroarchps2_fceumm.elf
 61 | mc0:/FORTUNA/retroarchps2_mgba.elf
 62 | mc0:/FORTUNA/retroarchps2_picodrive.elf
 63 | mc0:/FORTUNA/retroarchps2_quicknes.elf
 64 | mass:/FORTUNA/retroarchps2_2048.elf
 65 | mass:/FORTUNA/retroarchps2_fceumm.elf
 66 | mass:/FORTUNA/retroarchps2_mgba.elf
 67 | mass:/FORTUNA/retroarchps2_picodrive.elf
 68 | mass:/FORTUNA/retroarchps2_quicknes.elf
 69 | mc0:/APPS/retroarchps2_2048.elf
 70 | mc0:/APPS/retroarchps2_fceumm.elf
 71 | mc0:/APPS/retroarchps2_mgba.elf
 72 | mc0:/APPS/retroarchps2_picodrive.elf
 73 | mc0:/APPS/retroarchps2_quicknes.elf
 74 | mass:/APPS/retroarchps2_2048.elf
 75 | mass:/APPS/retroarchps2_fceumm.elf
 76 | mass:/APPS/retroarchps2_mgba.elf
 77 | mass:/APPS/retroarchps2_picodrive.elf
 78 | mass:/APPS/retroarchps2_quicknes.elf
 79 | 
 80 | SNESStation
 81 | 
 82 | mc0:/FORTUNA/snes_emu.elf
 83 | mass:/FORTUNA/snes_emu.elf
 84 | mc0:/APPS/snes_emu.elf
 85 | mass:/APPS/snes_emu.elf
 86 | 
 87 | PS2Ident
 88 | 
 89 | mc0:/FORTUNA/PS2Ident.elf
 90 | mass:/FORTUNA/PS2Ident.elf
 91 | mc0:/APPS/PS2Ident.elf
 92 | mass:/APPS/PS2Ident.elf
 93 | 
94 | 95 | 96 | Credits 97 |
 98 | pad.c/h from wLaunchElf 8d4a0c2 by AKuHAK and SP193
 99 | Uses OSDInit.c/h & libcdvd_add.c/h from 'OSD Initialization Libraries' by SP193
100 | PS2 FORTUNA Project by krat0s (not included, icon.icn & icon.sys)
101 | Compiled with current PS2SDK as of Nov 2019
102 | usbd.irx & usbhdfsd.irx from /ps2dev/ps2sdk/iop/irx/ as of Nov 2019
103 | Packed with PS2-Packer v1.1.0 by Nicolas "Pixel" Noble
104 | 
105 | 106 | 107 | Changelog 108 |
109 | v0.45
110 | Now loading, referencing and including:
111 | 
112 | /ps2dev/ps2sdk/iop/irx/usbd.irx
113 | /ps2dev/ps2sdk/iop/irx/usbhdfsd.irx
114 | 
115 | Fixes red screen when using USB.
116 | 
117 | Must be in mc0:/FORTUNA/ for now
118 | 
119 | v0.44
120 | Added support for HDLoader
121 | Added support for user specific CUSTOM1/2.ELF
122 | Removed a few 1s delays
123 | Code optimizations
124 | 
125 | v0.43
126 | Changed button menu display
127 | Experimental FMCB Support mc0/mc1
128 | (Needs testing on non-FMCB compatible PS2)
129 | pad.c/h from wLaunchElf 8d4a0c2 by AKuHAK and SP193
130 | libcdvd_add.c/h & OSDInit.c/h from PS2Ident v0.835 by l_Oliveira and SP193
131 | 
132 | v0.42
133 | Experimental FMCB support mc1
134 | Removed versions strings/release dates
135 | Code optmizations
136 | 
137 | v0.41
138 | Correct release date of OPL
139 | Minor text display adjustments
140 | 
141 | v0.4
142 | Minor code cleanup
143 | Removed few debug messages
144 | Added support for ESR
145 | Bump OPL to r1650
146 | 
147 | v0.3
148 | Can now use different paths and devices!
149 | Can select mc0 or mass
150 | Can select FORTUNA or APPS
151 | No more sub folders
152 | Source Code released
153 | 
154 | v0.2
155 | Added GSM
156 | Added PS2Ident
157 | Added many more RetroArch Cores
158 | Now Initializes DVD Drive and stops CD if it is present.
159 | 
160 | v0.1
161 | First release
162 | pad.c and pad related functions from wLaunchElf.elf 8d4a0c2
163 | Function ResetIOP() from main.c MPLUS-LOADER3.ELF
164 | Function LoadElf() from main.c MPLUS-LOADER3.ELF 
165 | -------------------------------------------------------------------------------- /libcdvd_add.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "libcdvd_add.h" 8 | 9 | static unsigned char MECHACON_CMD_S36_supported = 0, MECHACON_CMD_S27_supported = 0, MECHACON_CMD_S24_supported = 0; 10 | 11 | //Initialize add-on functions. Currently only retrieves the MECHACON's version to determine what sceCdAltGetRegionParams() should do. 12 | int cdInitAdd(void) 13 | { 14 | int result, status, i; 15 | u8 MECHA_version_data[3]; 16 | unsigned int MECHA_version; 17 | 18 | //Like how CDVDMAN checks sceCdMV(), do not continuously attempt to get the MECHACON version because some consoles (e.g. DTL-H301xx) can't return one. 19 | for(i = 0; i <= 100; i++) 20 | { 21 | if((result=sceCdMV(MECHA_version_data, &status)) != 0 && ((status&0x80) == 0)) 22 | { 23 | MECHA_version = MECHA_version_data[2] | ((unsigned int)MECHA_version_data[1] << 8) | ((unsigned int)MECHA_version_data[0] << 16); 24 | MECHACON_CMD_S36_supported = (0x5FFFF < MECHA_version); //v6.0 and later 25 | MECHACON_CMD_S27_supported = (0x501FF < MECHA_version); //v5.2 and later 26 | MECHACON_CMD_S24_supported = (0x4FFFF < MECHA_version); //v5.0 and later 27 | return 0; 28 | } 29 | } 30 | 31 | // printf("Failed to get MECHACON version: %d 0x%x\n", result, status); 32 | 33 | return -1; 34 | } 35 | 36 | /* 37 | This function provides an equivalent of the sceCdGetRegionParams function from the newer CDVDMAN modules. The old CDVDFSV and CDVDMAN modules don't support this S-command. 38 | It's supported by only slimline consoles, and returns regional information (e.g. MECHACON version, MG region mask, DVD player region letter etc.). 39 | */ 40 | int sceCdReadRegionParams(u8 *data, u32 *stat) 41 | { 42 | unsigned char RegionData[15]; 43 | int result; 44 | 45 | memset(data, 0, 13); 46 | if(MECHACON_CMD_S36_supported) 47 | { 48 | if((result = sceCdApplySCmd(0x36, NULL, 0, RegionData, sizeof(RegionData))) != 0) 49 | { 50 | *stat = RegionData[0]; 51 | memcpy(data, &RegionData[1], 13); 52 | } 53 | } 54 | else 55 | { 56 | *stat = 0x100; 57 | result = 1; 58 | } 59 | 60 | return result; 61 | } 62 | 63 | // This function provides an equivalent of the sceCdBootCertify function from the newer CDVDMAN modules. The old CDVDFSV and CDVDMAN modules don't support this S-command. 64 | int sceCdBootCertify(const u8* data) 65 | { 66 | int result; 67 | unsigned char CmdResult; 68 | 69 | if((result=sceCdApplySCmd(0x1A, data, 4, &CmdResult, 1))!=0) 70 | { 71 | result=CmdResult; 72 | } 73 | 74 | return result; 75 | } 76 | 77 | int sceCdRM(char *ModelName, u32 *stat) 78 | { 79 | unsigned char rdata[9]; 80 | unsigned char sdata; 81 | int result1, result2; 82 | 83 | sdata=0; 84 | result1=sceCdApplySCmd(0x17, &sdata, 1, rdata, 9); 85 | 86 | *stat=rdata[0]; 87 | memcpy(ModelName, &rdata[1], 8); 88 | 89 | sdata=8; 90 | result2=sceCdApplySCmd(0x17, &sdata, 1, rdata, 9); 91 | 92 | *stat|=rdata[0]; 93 | memcpy(&ModelName[8], &rdata[1], 8); 94 | 95 | return((result1!=0&&result2!=0)?1:0); 96 | } 97 | 98 | /* 99 | This function provides an equivalent of the sceCdReadPS1BootParam function from the newer CDVDMAN modules. The old CDVDFSV and CDVDMAN modules don't support this S-command. 100 | It's supported by only slimline consoles, and returns the boot path for the inserted PlayStation disc. 101 | */ 102 | int sceCdReadPS1BootParam(char *param, u32 *stat) 103 | { 104 | u8 out[16]; 105 | int result; 106 | 107 | memset(param, 0, 11); 108 | if(MECHACON_CMD_S27_supported) 109 | { 110 | if((result = sceCdApplySCmd(0x27, NULL, 0, out, 13)) != 0) 111 | { 112 | *stat = out[0]; 113 | memcpy(param, &out[1], 11); //Yes, one byte is not copied. 114 | } 115 | } 116 | else 117 | { 118 | *stat = 0x100; 119 | result = 1; 120 | } 121 | 122 | return result; 123 | } 124 | 125 | int sceCdRcBypassCtl(int bypass, u32 *stat) 126 | { //TODO: not implemented. 127 | u8 in[16], out[16]; 128 | int result; 129 | 130 | memset(in, 0, 11); 131 | if(MECHACON_CMD_S24_supported) 132 | { 133 | // TODO 134 | if((result = sceCdApplySCmd(0x24, &bypass, 4, out, 13)) != 0) 135 | { 136 | *stat = out[0]; 137 | } 138 | } 139 | else 140 | { 141 | *stat = 0x100; 142 | result = 1; 143 | } 144 | 145 | return result; 146 | } 147 | 148 | -------------------------------------------------------------------------------- /libcdvd_add.h: -------------------------------------------------------------------------------- 1 | int cdInitAdd(void); 2 | int sceCdReadRegionParams(u8 *data, u32 *stat); 3 | int sceCdReadPS1BootParam(char *param, u32 *stat); 4 | int sceCdBootCertify(const u8* data); 5 | int sceCdRM(char *ModelName, u32 *stat); 6 | int sceCdRcBypassCtl(int bypass, u32 *stat); //TODO: Not implemented. 7 | -------------------------------------------------------------------------------- /pad.c: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------- 2 | // File name: pad.c 3 | //--------------------------------------------------------------------------- 4 | #include "FORTUNA_Launcher.h" 5 | 6 | static char padBuf_t[2][256] __attribute__((aligned(64))); 7 | struct padButtonStatus buttons_t[2]; 8 | u32 padtype_t[2]; 9 | u32 paddata, paddata_t[2]; 10 | u32 old_pad = 0, old_pad_t[2] = {0, 0}; 11 | u32 new_pad, new_pad_t[2]; 12 | u32 joy_value = 0; 13 | static int test_joy = 0; 14 | u64 Timer(void); 15 | 16 | //--------------------------------------------------------------------------- 17 | // read PAD, without KB, and allow no auto-repeat. This is needed in code 18 | // that is used regardless of VSync cycles, and where KB is not wanted. 19 | //--------------------------------------------------------------------------- 20 | int readpad_noKBnoRepeat(void) 21 | { 22 | int port, state, ret[2]; 23 | 24 | for (port = 0; port < 2; port++) { 25 | if ((state = padGetState(port, 0)) == PAD_STATE_STABLE || (state == PAD_STATE_FINDCTP1)) { 26 | //Deal with cases where pad state is valid for padRead 27 | ret[port] = padRead(port, 0, &buttons_t[port]); 28 | if (ret[port] != 0) { 29 | paddata_t[port] = 0xffff ^ buttons_t[port].btns; 30 | new_pad_t[port] = paddata_t[port] & ~old_pad_t[port]; 31 | old_pad_t[port] = paddata_t[port]; 32 | } 33 | } else { 34 | //Deal with cases where pad state is not valid for padRead 35 | new_pad_t[port] = 0; 36 | } //ends 'if' testing for state valid for padRead 37 | } //ends for 38 | new_pad = new_pad_t[0] | new_pad_t[1]; //This has only new button bits 39 | paddata = paddata_t[0] | paddata_t[1]; //This has all pressed button bits 40 | return (ret[0] | ret[1]); 41 | } 42 | //------------------------------ 43 | //endfunc readpad_noKBnoRepeat 44 | //--------------------------------------------------------------------------- 45 | // read PAD, but ignore KB. This is needed in code with own KB handlers, 46 | // such as the virtual keyboard input routines for 'Rename' and 'New Dir' 47 | //--------------------------------------------------------------------------- 48 | int readpad_no_KB(void) 49 | { 50 | static u64 rpt_time[2] = {0, 0}; 51 | static int rpt_count[2]; 52 | int port, state, ret[2]; 53 | 54 | for (port = 0; port < 2; port++) { 55 | if ((state = padGetState(port, 0)) == PAD_STATE_STABLE || (state == PAD_STATE_FINDCTP1)) { 56 | //Deal with cases where pad state is valid for padRead 57 | ret[port] = padRead(port, 0, &buttons_t[port]); 58 | if (ret[port] != 0) { 59 | paddata_t[port] = 0xffff ^ buttons_t[port].btns; 60 | if ((padtype_t[port] == 2) && (1 & (test_joy++))) { //DualShock && time for joy scan 61 | joy_value = 0; 62 | if (buttons_t[port].rjoy_h >= 0xbf) { 63 | paddata_t[port] = PAD_R3_H1; 64 | joy_value = buttons_t[port].rjoy_h - 0xbf; 65 | } else if (buttons_t[port].rjoy_h <= 0x40) { 66 | paddata_t[port] = PAD_R3_H0; 67 | joy_value = -(buttons_t[port].rjoy_h - 0x40); 68 | } else if (buttons_t[port].rjoy_v <= 0x40) { 69 | paddata_t[port] = PAD_R3_V0; 70 | joy_value = -(buttons_t[port].rjoy_v - 0x40); 71 | } else if (buttons_t[port].rjoy_v >= 0xbf) { 72 | paddata_t[port] = PAD_R3_V1; 73 | joy_value = buttons_t[port].rjoy_v - 0xbf; 74 | } else if (buttons_t[port].ljoy_h >= 0xbf) { 75 | paddata_t[port] = PAD_L3_H1; 76 | joy_value = buttons_t[port].ljoy_h - 0xbf; 77 | } else if (buttons_t[port].ljoy_h <= 0x40) { 78 | paddata_t[port] = PAD_L3_H0; 79 | joy_value = -(buttons_t[port].ljoy_h - 0x40); 80 | } else if (buttons_t[port].ljoy_v <= 0x40) { 81 | paddata_t[port] = PAD_L3_V0; 82 | joy_value = -(buttons_t[port].ljoy_v - 0x40); 83 | } else if (buttons_t[port].ljoy_v >= 0xbf) { 84 | paddata_t[port] = PAD_L3_V1; 85 | joy_value = buttons_t[port].ljoy_v - 0xbf; 86 | } 87 | } 88 | new_pad_t[port] = paddata_t[port] & ~old_pad_t[port]; 89 | if (old_pad_t[port] == paddata_t[port]) { 90 | //no change of pad data 91 | if (Timer() > rpt_time[port]) { 92 | new_pad_t[port] = paddata_t[port]; //Accept repeated buttons as new 93 | rpt_time[port] = Timer() + 40; //Min delay = 40ms => 25Hz repeat 94 | if (rpt_count[port]++ < 20) 95 | rpt_time[port] += 43; //Early delays = 83ms => 12Hz repeat 96 | } 97 | } else { 98 | //pad data has changed ! 99 | rpt_count[port] = 0; 100 | rpt_time[port] = Timer() + 400; //Init delay = 400ms 101 | old_pad_t[port] = paddata_t[port]; 102 | } 103 | } 104 | } else { 105 | //Deal with cases where pad state is not valid for padRead 106 | //NB: This should NOT clear KB repeat test variables 107 | new_pad_t[port] = 0; 108 | //old_pad_t[port]=0; //Clearing this could cause hasty repeats 109 | } //ends 'if' testing for state valid for padRead 110 | } //ends for 111 | new_pad = new_pad_t[0] | new_pad_t[1]; 112 | paddata = paddata_t[0] | paddata_t[1]; //This has all pressed button bits 113 | return (ret[0] | ret[1]); 114 | } 115 | //------------------------------ 116 | //endfunc readpad_no_KB 117 | //--------------------------------------------------------------------------- 118 | 119 | int readpad(void) 120 | { 121 | int ret; 122 | 123 | if ((ret = readpad_no_KB()) && new_pad) 124 | return ret; 125 | 126 | //return simPadKB(); 127 | return 1; 128 | } 129 | //------------------------------ 130 | //endfunc readpad 131 | //--------------------------------------------------------------------------- 132 | // readpad_noRepeat calls readpad_noKBnoRepeat, and if no new pad buttons are 133 | // found, it also attempts reading data from a USB keyboard, and map this as 134 | // a virtual gamepad. (Very improvised and sloppy, but it should work fine.) 135 | //--------------------------------------------------------------------------- 136 | int readpad_noRepeat(void) 137 | { 138 | int ret; 139 | 140 | if ((ret = readpad_noKBnoRepeat()) && new_pad) 141 | return ret; 142 | 143 | //return simPadKB(); 144 | return 1; 145 | } 146 | //------------------------------ 147 | //endfunc readpad_noRepeat 148 | //--------------------------------------------------------------------------- 149 | // Wait for specific PAD, but also accept disconnected state 150 | void waitPadReady(int port, int slot) 151 | { 152 | int state, lastState; 153 | char stateString[16]; 154 | 155 | state = padGetState(port, slot); 156 | lastState = -1; 157 | while ((state != PAD_STATE_DISCONN) && (state != PAD_STATE_STABLE) && (state != PAD_STATE_FINDCTP1)) { 158 | if (state != lastState) 159 | padStateInt2String(state, stateString); 160 | lastState = state; 161 | state = padGetState(port, slot); 162 | } 163 | } 164 | //--------------------------------------------------------------------------- 165 | // Wait for any PAD, but also accept disconnected states 166 | void waitAnyPadReady(void) 167 | { 168 | int state_1, state_2; 169 | 170 | state_1 = padGetState(0, 0); 171 | state_2 = padGetState(1, 0); 172 | while ((state_1 != PAD_STATE_DISCONN) && (state_2 != PAD_STATE_DISCONN) && (state_1 != PAD_STATE_STABLE) && (state_2 != PAD_STATE_STABLE) && (state_1 != PAD_STATE_FINDCTP1) && (state_2 != PAD_STATE_FINDCTP1)) { 173 | state_1 = padGetState(0, 0); 174 | state_2 = padGetState(1, 0); 175 | } 176 | } 177 | //--------------------------------------------------------------------------- 178 | // setup PAD 179 | int setupPad(void) 180 | { 181 | int ret, i, port, state, modes; 182 | 183 | padInit(0); 184 | 185 | for (port = 0; port < 2; port++) { 186 | padtype_t[port] = 0; //Assume that we don't have a proper PS2 controller 187 | if ((ret = padPortOpen(port, 0, &padBuf_t[port][0])) == 0) 188 | return 0; 189 | waitPadReady(port, 0); 190 | state = padGetState(port, 0); 191 | if (state != PAD_STATE_DISCONN) { //if anything connected to this port 192 | modes = padInfoMode(port, 0, PAD_MODETABLE, -1); 193 | if (modes != 0) { //modes != 0, so it may be a dualshock type 194 | for (i = 0; i < modes; i++) { 195 | if (padInfoMode(port, 0, PAD_MODETABLE, i) == PAD_TYPE_DUALSHOCK) { 196 | padtype_t[port] = 2; //flag normal PS2 controller 197 | break; 198 | } 199 | } //ends for (modes) 200 | } else { //modes == 0, so this is a digital controller 201 | padtype_t[port] = 1; //flag digital controller 202 | } 203 | if (padtype_t[port] == 2) //if DualShock 204 | padSetMainMode(port, 0, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); //Set DualShock 205 | else //else 206 | padSetMainMode(port, 0, PAD_MMODE_DIGITAL, PAD_MMODE_UNLOCK); //Set Digital 207 | waitPadReady(port, 0); //Await completion 208 | } else { //Nothing is connected to this port 209 | padSetMainMode(port, 0, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); //Fake DualShock 210 | waitPadReady(port, 0); //Await completion 211 | } 212 | } //ends for (port) 213 | return 1; 214 | } 215 | //--------------------------------------------------------------------------- 216 | // End of file: pad.c 217 | //--------------------------------------------------------------------------- 218 | -------------------------------------------------------------------------------- /pad.h: -------------------------------------------------------------------------------- 1 | #ifndef PAD_H 2 | #define PAD_H 3 | 4 | #include 5 | #include 6 | 7 | typedef enum delayTime { 8 | DELAYTIME_FAST = 2, 9 | DELAYTIME_SLOW = 6 10 | } delayTime_t; 11 | 12 | // Initialize pad 13 | void padInitialize(); 14 | 15 | // Poll controller for button status 16 | void padPoll(delayTime_t delayTime); 17 | 18 | // Get buttons pressed momentarily 19 | inline u32 padPressed(); 20 | 21 | // Get buttons held down 22 | inline u32 padHeld(); 23 | 24 | #endif // PAD_H 25 | -------------------------------------------------------------------------------- /usbd.irx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VTSTech/PS2_FORTUNA_Launcher/a31d374d74d6f7dd68e83aada6db9bf8743b2b7f/usbd.irx -------------------------------------------------------------------------------- /usbhdfsd.irx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VTSTech/PS2_FORTUNA_Launcher/a31d374d74d6f7dd68e83aada6db9bf8743b2b7f/usbhdfsd.irx --------------------------------------------------------------------------------