// Checks if devices are available, prints name of device being detected for slow init devices void populateDeviceAvailability() { DrawFrameStart(); DrawMessageBox(D_INFO, "Detecting devices ...\nThis can be skipped by holding B next time"); DrawFrameFinish(); if(PAD_ButtonsHeld(0) & PAD_BUTTON_B) { deviceHandler_setAllDevicesAvailable(); return; } const DISC_INTERFACE* carda = &__io_gcsda; const DISC_INTERFACE* cardb = &__io_gcsdb; // DVD deviceHandler_setDeviceAvailable(DVD_DISC, swissSettings.hasDVDDrive); // SD Gecko DrawFrameStart(); DrawMessageBox(D_INFO, "Detecting devices [SD] ...\nThis can be skipped by holding B next time"); DrawFrameFinish(); deviceHandler_setDeviceAvailable(SD_CARD, carda->isInserted() || cardb->isInserted()); // IDE-EXI DrawFrameStart(); DrawMessageBox(D_INFO, "Detecting devices [IDE-EXI] ...\nThis can be skipped by holding B next time"); DrawFrameFinish(); deviceHandler_setDeviceAvailable(IDEEXI, ide_exi_inserted(0) || ide_exi_inserted(1)); // Qoob deviceHandler_setDeviceAvailable(QOOB_FLASH, 0); // Hidden by default, add auto detect at some point // WODE deviceHandler_setDeviceAvailable(WODE, 0); // Hidden by default, add auto detect at some point // Memory card DrawFrameStart(); DrawMessageBox(D_INFO, "Detecting devices [Memory Card] ...\nThis can be skipped by holding B next time"); DrawFrameFinish(); deviceHandler_setDeviceAvailable(MEMCARD, (initialize_card(0)==CARD_ERROR_READY) || (initialize_card(1)==CARD_ERROR_READY)); // WKF/WASP DrawFrameStart(); DrawMessageBox(D_INFO, "Detecting devices [WKF/WASP] ...\nThis can be skipped by holding B next time"); DrawFrameFinish(); deviceHandler_setDeviceAvailable(WKF, swissSettings.hasDVDDrive && (__wkfSpiReadId() != 0 && __wkfSpiReadId() != 0xFFFFFFFF)); // USB Gecko deviceHandler_setDeviceAvailable(USBGECKO, usb_isgeckoalive(1)); // BBA/SAMBA deviceHandler_setDeviceAvailable(SAMBA, exi_bba_exists()); // System, always there deviceHandler_setDeviceAvailable(SYS, 1); }
void load_config(int forceSlot) { // Try to open up the config .ini in case it hasn't been opened already (SD, IDE-EXI only) if(!config_init(forceSlot)) { if(curDevice == SD_CARD || curDevice == IDEEXI || forceSlot) { if(!config_create(forceSlot)) { DrawFrameStart(); DrawMessageBox(D_INFO,"Failed to create configuration file!"); DrawFrameFinish(); sleep(1); } } } else { DrawFrameStart(); sprintf(txtbuffer,"Loaded %i entries from the config file",config_get_count()); DrawMessageBox(D_INFO,txtbuffer); DrawFrameFinish(); memcpy(&swissSettings, config_get_swiss_settings(), sizeof(SwissSettings)); } }
int deviceHandler_USBGecko_init(file_handle* file) { DrawFrameStart(); DrawMessageBox(D_INFO,"Looking for USBGecko in Slot B"); DrawFrameFinish(); if(usb_isgeckoalive(1)) { int retries = 1000; DrawFrameStart(); DrawMessageBox(D_INFO,"Waiting for PC ..."); DrawFrameFinish(); usb_flush(1); usbgecko_lock_file(0); // Wait for the PC and retry 1000 times while(!usbgecko_pc_ready() && retries) { VIDEO_WaitVSync(); retries--; } if(!retries) { DrawFrameStart(); DrawMessageBox(D_INFO,"Couldn't find PC!"); DrawFrameFinish(); sleep(5); return 0; // Didn't find the PC } else { DrawFrameStart(); DrawMessageBox(D_INFO,"Found PC !!"); DrawFrameFinish(); return 1; } } else { return 0; } }
int deviceHandler_USBGecko_readDir(file_handle* ffile, file_handle** dir, unsigned int type){ // Set everything up to read int num_entries = 0, i = 0; file_handle *entry = NULL; if(strlen(ffile->name)!=1) { i = num_entries = 1; *dir = malloc( num_entries * sizeof(file_handle) ); memset(*dir,0,sizeof(file_handle) * num_entries); (*dir)[0].fileAttrib = IS_SPECIAL; strcpy((*dir)[0].name, ".."); } DrawFrameStart(); DrawMessageBox(D_INFO,"Read directory!"); DrawFrameFinish(); // Read each entry of the directory int res = usbgecko_open_dir(&ffile->name[0]); if(!res) return -1; while( (entry = usbgecko_get_entry()) != NULL ){ // Make sure we have room for this one if(i == num_entries) { ++num_entries; *dir = realloc( *dir, num_entries * sizeof(file_handle) ); } sprintf((*dir)[i].name, "%s", entry->name); (*dir)[i].offset = 0; (*dir)[i].size = entry->size; (*dir)[i].fileAttrib = entry->fileAttrib; (*dir)[i].fp = 0; (*dir)[i].fileBase = 0; (*dir)[i].meta = 0; ++i; } return num_entries; }
/* Initialise Video, PAD, DVD, Font */ void* Initialise (void) { VIDEO_Init (); PAD_Init (); DVD_Init(); *(volatile unsigned long*)0xcc00643c = 0x00000000; //allow 32mhz exi bus // Disable IPL modchips to allow access to IPL ROM fonts ipl_set_config(6); usleep(1000); //wait for modchip to disable (overkill) __SYS_ReadROM(IPLInfo,256,0); // Read IPL tag // Wii has no IPL tags for "PAL" so let libOGC figure out the video mode if(!is_gamecube()) { vmode = VIDEO_GetPreferredMode(NULL); //Last mode used } else { // Gamecube, determine based on IPL int retPAD = 0, retCnt = 10000; while(retPAD <= 0 && retCnt >= 0) { retPAD = PAD_ScanPads(); usleep(100); retCnt--; } // L Trigger held down ignores the fact that there's a component cable plugged in. if(VIDEO_HaveComponentCable() && !(PAD_ButtonsDown(0) & PAD_TRIGGER_L)) { if(strstr(IPLInfo,"MPAL")!=NULL) { swissSettings.sramVideo = 2; vmode = &TVMpal480Prog; //Progressive 480p } else if((strstr(IPLInfo,"PAL")!=NULL)) { swissSettings.sramVideo = 1; vmode = &TVPal576ProgScale; //Progressive 576p } else { swissSettings.sramVideo = 0; vmode = &TVNtsc480Prog; //Progressive 480p } } else { //try to use the IPL region if(strstr(IPLInfo,"MPAL")!=NULL) { swissSettings.sramVideo = 2; vmode = &TVMpal480IntDf; //PAL-M } else if(strstr(IPLInfo,"PAL")!=NULL) { swissSettings.sramVideo = 1; vmode = &TVPal576IntDfScale; //PAL } else { swissSettings.sramVideo = 0; vmode = &TVNtsc480IntDf; //NTSC } } } initialise_video(vmode); populateVideoStr(vmode); init_font(); init_textures(); whichfb = 0; drive_version(&driveVersion[0]); swissSettings.hasDVDDrive = *(u32*)&driveVersion[0] ? 1 : 0; if(!driveVersion[0]) { // Reset DVD if there was a modchip DrawFrameStart(); WriteFontStyled(640/2, 250, "Initialise DVD .. (HOLD B if NO DVD Drive)", 0.8f, true, defaultColor); DrawFrameFinish(); dvd_reset(); // low-level, basic dvd_read_id(); if(!(PAD_ButtonsHeld(0) & PAD_BUTTON_B)) { dvd_set_streaming(*(char*)0x80000008); } drive_version(&driveVersion[0]); swissSettings.hasDVDDrive = *(u32*)&driveVersion[0] ? 1 : 0; if(!swissSettings.hasDVDDrive) { DrawFrameStart(); DrawMessageBox(D_INFO, "No DVD Drive Detected !!"); DrawFrameFinish(); sleep(2); } } return xfb[0]; }
// Returns the number of filesToPatch and fills out the filesToPatch array passed in (pre-allocated) int parse_gcm(file_handle *file, ExecutableFile *filesToPatch) { DiskHeader header; char *FST; char filename[256]; int numFiles = 0; // Grab disc header memset(&header,0,sizeof(DiskHeader)); deviceHandler_seekFile(file,0,DEVICE_HANDLER_SEEK_SET); if(deviceHandler_readFile(file,&header,sizeof(DiskHeader)) != sizeof(DiskHeader)) { return -1; } // Alloc and read FST FST=(char*)memalign(32,header.FSTSize); if(!FST) { return -1; } deviceHandler_seekFile(file,header.FSTOffset,DEVICE_HANDLER_SEEK_SET); if(deviceHandler_readFile(file,FST,header.FSTSize) != header.FSTSize) { free(FST); return -1; } u32 entries=*(unsigned int*)&FST[8]; u32 string_table_offset=FST_ENTRY_SIZE*entries; int i; // go through every entry for (i=1;i<entries;i++) { u32 offset=i*0x0c; if(FST[offset]==0) //skip directories { u32 file_offset,size = 0; u32 filename_offset=((*(unsigned int*)&FST[offset]) & 0x00FFFFFF); memset(&filename[0],0,256); memcpy(&filename[0],&FST[string_table_offset+filename_offset],255); memcpy(&file_offset,&FST[offset+4],4); memcpy(&size,&FST[offset+8],4); if(endsWith(filename,".dol") || endsWith(filename,".DOL")) { filesToPatch[numFiles].offset = file_offset; filesToPatch[numFiles].size = size; filesToPatch[numFiles].type = PATCH_DOL; memcpy(&filesToPatch[numFiles].name,&filename[0],64); numFiles++; } if((endsWith(filename,".elf") || endsWith(filename,".ELF")) && size < 12*1024*1024) { filesToPatch[numFiles].offset = file_offset; filesToPatch[numFiles].size = size; filesToPatch[numFiles].type = PATCH_ELF; memcpy(&filesToPatch[numFiles].name,&filename[0],64); numFiles++; } if(strstr(filename,"execD.img")) { filesToPatch[numFiles].offset = file_offset; filesToPatch[numFiles].size = size; filesToPatch[numFiles].type = PATCH_LOADER; memcpy(&filesToPatch[numFiles].name,&filename[0],64); numFiles++; } if(endsWith(filename,".tgc") || endsWith(filename,".TGC")) { // Go through all the TGC's internal files ExecutableFile *filesInTGCToPatch = memalign(32, sizeof(ExecutableFile)*32); int numTGCFilesToPatch = parse_tgc(file, filesInTGCToPatch, file_offset), j; for(j=0; j<numTGCFilesToPatch; j++) { memcpy(&filesToPatch[numFiles], &filesInTGCToPatch[j], sizeof(ExecutableFile)); numFiles++; } free(filesInTGCToPatch); } } } free(FST); // Some games contain a single "default.dol", these do not need // pre-patching because they are what is actually pointed to by the apploader (and loaded by us) if(numFiles==1 && (!strcmp(&filesToPatch[0].name[0],"default.dol"))) { numFiles = 0; } // Multi-DOL games may re-load the main DOL, so make sure we patch it too. if(numFiles>0) { DOLHEADER dolhdr; u32 main_dol_size = 0; // Calc size deviceHandler_seekFile(file,GCMDisk.DOLOffset,DEVICE_HANDLER_SEEK_SET); if(deviceHandler_readFile(file,&dolhdr,DOLHDRLENGTH) != DOLHDRLENGTH) { DrawFrameStart(); DrawMessageBox(D_FAIL, "Failed to read Main DOL Header"); DrawFrameFinish(); while(1); } for (i = 0; i < MAXTEXTSECTION; i++) { if (dolhdr.textLength[i] + dolhdr.textOffset[i] > main_dol_size) main_dol_size = dolhdr.textLength[i] + dolhdr.textOffset[i]; } for (i = 0; i < MAXDATASECTION; i++) { if (dolhdr.dataLength[i] + dolhdr.dataOffset[i] > main_dol_size) main_dol_size = dolhdr.dataLength[i] + dolhdr.dataOffset[i]; } filesToPatch[numFiles].offset = GCMDisk.DOLOffset; filesToPatch[numFiles].size = main_dol_size; filesToPatch[numFiles].type = PATCH_DOL; sprintf(filesToPatch[numFiles].name, "Main DOL"); numFiles++; // Patch the apploader too! // Calc Apploader trailer size u32 appldr_info[2]; deviceHandler_seekFile(file,0x2454,DEVICE_HANDLER_SEEK_SET); if(deviceHandler_readFile(file,&appldr_info,8) != 8) { DrawFrameStart(); DrawMessageBox(D_FAIL, "Failed to read Apploader info"); DrawFrameFinish(); while(1); } filesToPatch[numFiles].size = appldr_info[1]; filesToPatch[numFiles].offset = 0x2460 + appldr_info[0]; filesToPatch[numFiles].type = PATCH_LOADER; sprintf(filesToPatch[numFiles].name, "Apploader Trailer"); numFiles++; } return numFiles; }
int patch_gcm(file_handle *file, ExecutableFile *filesToPatch, int numToPatch, int multiDol) { int i, num_patched = 0; // If the current device isn't SD Gecko, init SD Gecko Slot A or B to write patches. if(deviceHandler_initial != &initial_SD0 && deviceHandler_initial != &initial_SD1) { deviceHandler_setStatEnabled(0); if(deviceHandler_FAT_init(&initial_SD0)) { savePatchDevice = 0; } else if(deviceHandler_FAT_init(&initial_SD1)) { savePatchDevice = 1; } deviceHandler_setStatEnabled(1); } // Already using SD Gecko if(deviceHandler_initial == &initial_SD0) savePatchDevice = 0; else if(deviceHandler_initial == &initial_SD1) savePatchDevice = 1; if(savePatchDevice == -1) { DrawFrameStart(); DrawMessageBox(D_FAIL, "No writable device present\nA SD Gecko must be inserted in\n order to utilise patches for this game."); DrawFrameFinish(); sleep(5); return 0; } char patchFileName[256]; char patchDirName[256]; char patchBaseDirName[256]; char gameID[8]; memset(&gameID, 0, 8); memset(&patchDirName, 0, 256); memset(&patchBaseDirName, 0, 256); strncpy((char*)&gameID, (char*)&GCMDisk, 4); sprintf(&patchDirName[0],"%s:/swiss_patches/%s",(savePatchDevice ? "sdb":"sda"), &gameID[0]); sprintf(&patchBaseDirName[0],"%s:/swiss_patches",(savePatchDevice ? "sdb":"sda")); print_gecko("Patch dir will be: %s if required\r\n", patchDirName); *(u32*)VAR_EXECD_OFFSET = 0xFFFFFFFF; // Go through all the possible files we think need patching.. for(i = 0; i < numToPatch; i++) { u32 patched = 0, crc32 = 0; sprintf(txtbuffer, "Patching File %i/%i",i+1,numToPatch); DrawFrameStart(); DrawProgressBar((int)(((float)(i+1)/(float)numToPatch)*100), txtbuffer); DrawFrameFinish(); // Round up to 32 bytes if(filesToPatch[i].size % 0x20) { filesToPatch[i].size += (0x20-(filesToPatch[i].size%0x20)); } if(filesToPatch[i].size > 8*1024*1024) { print_gecko("Skipping %s %iKB too large\r\n", filesToPatch[i].name, filesToPatch[i].size/1024); continue; } print_gecko("Checking %s %iKb\r\n", filesToPatch[i].name, filesToPatch[i].size/1024); if(strstr(filesToPatch[i].name, "execD.")) { *(u32*)VAR_EXECD_OFFSET = filesToPatch[i].offset; } if(strstr(filesToPatch[i].name, "iwanagaD.dol") || strstr(filesToPatch[i].name, "switcherD.dol")) { continue; // skip unused PSO files } int sizeToRead = filesToPatch[i].size; u8 *buffer = (u8*)memalign(32, sizeToRead); deviceHandler_seekFile(file,filesToPatch[i].offset, DEVICE_HANDLER_SEEK_SET); if(deviceHandler_readFile(file,buffer,sizeToRead)!= sizeToRead) { DrawFrameStart(); DrawMessageBox(D_FAIL, "Failed to read!"); DrawFrameFinish(); sleep(5); return 0; } if(curDevice != DVD_DISC) { u32 ret = Patch_DVDLowLevelRead(buffer, sizeToRead, filesToPatch[i].type); if(READ_PATCHED_ALL != ret) { DrawFrameStart(); DrawMessageBox(D_FAIL, "Failed to find necessary functions for patching!"); DrawFrameFinish(); sleep(5); } else patched += 1; } if(swissSettings.debugUSB && usb_isgeckoalive(1) && !swissSettings.wiirdDebug) { patched += Patch_Fwrite(buffer, sizeToRead); } if(swissSettings.wiirdDebug || getEnabledCheatsSize() > 0) { Patch_CheatsHook(buffer, sizeToRead, filesToPatch[i].type); } if(curDevice == DVD_DISC && is_gamecube()) { patched += Patch_DVDLowLevelReadForDVD(buffer, sizeToRead, filesToPatch[i].type); patched += Patch_DVDReset(buffer, sizeToRead); } patched += Patch_VidMode(buffer, sizeToRead, filesToPatch[i].type); patched += Patch_FontEnc(buffer, sizeToRead); if(swissSettings.forceWidescreen) Patch_WideAspect(buffer, sizeToRead, filesToPatch[i].type); if(swissSettings.forceAnisotropy) Patch_TexFilt(buffer, sizeToRead, filesToPatch[i].type); if(patched) { // File handle for a patch we might need to write FILE *patchFile = 0; memset(patchFileName, 0, 256); // Make a base patches dir if we don't have one already if(mkdir(&patchBaseDirName[0], 0777) != 0) { if(errno != EEXIST) { return -2; } } if(mkdir(&patchDirName[0], 0777) != 0) { if(errno != EEXIST) { return -2; } } sprintf(patchFileName, "%s/%i",patchDirName, num_patched); // Work out the crc32 crc32 = Crc32_ComputeBuf( 0, buffer, (u32) sizeToRead); // See if this file already exists, if it does, match crc patchFile = fopen( patchFileName, "rb" ); if(patchFile) { //print_gecko("Old Patch exists\r\n"); u32 oldCrc32 = 0; fseek(patchFile, 0L, SEEK_END); u32 file_size = ftell(patchFile); fseek(patchFile, file_size-4, SEEK_SET); fread(&oldCrc32, 1, 4, patchFile); if(oldCrc32 == crc32) { num_patched++; fclose(patchFile); free(buffer); print_gecko("CRC matched, no need to patch again\r\n"); continue; } else { remove(patchFileName); fclose(patchFile); print_gecko("CRC mismatch, writing patch again\r\n"); } } // Otherwise, write a file out for this game with the patched buffer inside. print_gecko("Writing patch file: %s %i bytes (disc offset %08X)\r\n", patchFileName, sizeToRead, filesToPatch[i].offset); patchFile = fopen(patchFileName, "wb"); fwrite(buffer, 1, sizeToRead, patchFile); u32 magic = SWISS_MAGIC; fwrite(&filesToPatch[i].offset, 1, 4, patchFile); fwrite(&filesToPatch[i].size, 1, 4, patchFile); fwrite(&magic, 1, 4, patchFile); fwrite(&crc32, 1, 4, patchFile); fclose(patchFile); num_patched++; } free(buffer); } return num_patched; }
int show_settings(file_handle *file, ConfigEntry *config) { int page = 0, option = 0; // Refresh SRAM in case user changed it from IPL refreshSRAM(); // Copy current settings to a temp copy in case the user cancels out memcpy((void*)&tempSettings,(void*)&swissSettings, sizeof(SwissSettings)); // Setup the settings for the current game if(config != NULL) { page = 2; } while (PAD_ButtonsHeld(0) & PAD_BUTTON_A) { VIDEO_WaitVSync (); } while(1) { settings_draw_page(page, option, file); while (!((PAD_ButtonsHeld(0) & PAD_BUTTON_RIGHT) || (PAD_ButtonsHeld(0) & PAD_BUTTON_LEFT) || (PAD_ButtonsHeld(0) & PAD_BUTTON_UP) || (PAD_ButtonsHeld(0) & PAD_BUTTON_DOWN) || (PAD_ButtonsHeld(0) & PAD_BUTTON_B) || (PAD_ButtonsHeld(0) & PAD_BUTTON_A) || (PAD_ButtonsHeld(0) & PAD_TRIGGER_R) || (PAD_ButtonsHeld(0) & PAD_TRIGGER_L))) { VIDEO_WaitVSync (); } u16 btns = PAD_ButtonsHeld(0); if(btns & PAD_BUTTON_RIGHT) { // If we're on a button (Back, Next, Save, Exit), allow left/right movement if((page != 1) && (option >= settings_count_pp[page]-2) && option < settings_count_pp[page]) { option++; } else if((page == 1) && (option >= settings_count_pp[page]-3) && option < settings_count_pp[page]) { option++; } else { settings_toggle(page, option, 1, file); } } if(btns & PAD_BUTTON_LEFT) { // If we're on a button (Back, Next, Save, Exit), allow left/right movement if((page != 1) && (option > settings_count_pp[page]-2)) { option--; } else if((page == 1) && (option > settings_count_pp[page]-3)) { option--; } else { settings_toggle(page, option, -1, file); } } if((btns & PAD_BUTTON_DOWN) && option < settings_count_pp[page]) option++; if((btns & PAD_BUTTON_UP) && option > 0) option--; if((btns & PAD_TRIGGER_R) && page < 2) { page++; option = 0; } if((btns & PAD_TRIGGER_L) && page > 0) { page--; option = 0; } if((btns & PAD_BUTTON_B)) option = settings_count_pp[page]; // Handle all options/buttons here if((btns & PAD_BUTTON_A)) { // Generic Save/Cancel/Back/Next button actions if(option == settings_count_pp[page]-1) { DrawFrameStart(); DrawMessageBox(D_INFO,"Saving changes!"); DrawFrameFinish(); // Change Swiss video mode if it was modified. if(tempSettings.uiVMode != swissSettings.uiVMode) { GXRModeObj *newmode = getModeFromSwissSetting(swissSettings.uiVMode); initialise_video(newmode); vmode = newmode; } // Save settings to SRAM sram = __SYS_LockSram(); sram->lang = swissSettings.sramLanguage; sram->flags = swissSettings.sramStereo ? (sram->flags|0x04):(sram->flags&~0x04); sram->flags = (swissSettings.sramVideo&0x03)|(sram->flags&~0x03); __SYS_UnlockSram(1); while(!__SYS_SyncSram()); // Update our .ini if(config != NULL) { config->gameVMode = swissSettings.gameVMode; config->softProgressive = swissSettings.softProgressive; config->muteAudioStreaming = swissSettings.muteAudioStreaming; config->forceWidescreen = swissSettings.forceWidescreen; config->forceAnisotropy = swissSettings.forceAnisotropy; config->forceEncoding = swissSettings.forceEncoding; } else { // Save the Swiss system settings since we're called from the main menu if((curDevice == SD_CARD)||(curDevice == IDEEXI)) { DrawFrameStart(); DrawMessageBox(D_INFO,"Saving Config ..."); DrawFrameFinish(); config_copy_swiss_settings(&swissSettings); if(config_update_file()) { DrawFrameStart(); DrawMessageBox(D_INFO,"Config Saved Successfully!"); DrawFrameFinish(); } else { DrawFrameStart(); DrawMessageBox(D_INFO,"Config Failed to Save!"); DrawFrameFinish(); } } } return 1; } if(option == settings_count_pp[page]) { // Exit without saving (revert) memcpy((void*)&swissSettings, (void*)&tempSettings, sizeof(SwissSettings)); return 0; } if((page != 2) && (option == settings_count_pp[page]-2)) { page++; option = 0; } if((page != 0) && (option == settings_count_pp[page]-(page != 2 ? 3:2))) { page--; option = 0; } } while ((PAD_ButtonsHeld(0) & PAD_BUTTON_RIGHT) || (PAD_ButtonsHeld(0) & PAD_BUTTON_LEFT) || (PAD_ButtonsHeld(0) & PAD_BUTTON_UP) || (PAD_ButtonsHeld(0) & PAD_BUTTON_DOWN) || (PAD_ButtonsHeld(0) & PAD_BUTTON_B) || (PAD_ButtonsHeld(0) & PAD_BUTTON_A) || (PAD_ButtonsHeld(0) & PAD_TRIGGER_R) || (PAD_ButtonsHeld(0) & PAD_TRIGGER_L)) { VIDEO_WaitVSync (); } } }