Here's my code, I stripped down a lot of things that I didn't need, but the part you're after is between the DL detection comments in get_settings().
For regular users, this code includes:
- Only Wii games dumping
- DL detection on d2pro chips, possibility to change the DL if it's not right on some games (should work though)
- Dumping only on USB drive with enough space to hold the whole dump (expect errors otherwise)
- .bat file to import games on PC hard drive and auto delete files on the drive, change the directories in the code
- Dumping only on FAT drives
- All other original features have been stripped, including the UI, now in console mode
Use it all you want, I did this for myself only, so use it at your own risks, I won't update it beyond this point, so don't ask me.
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <gccore.h>
#include <errno.h>
#include <math.h>
#include <unistd.h>
#include <di/di.h>
#include <ogc/lwp_watchdog.h>
#include <ogc/usbstorage.h>
#include <sdcard/wiisd_io.h>
#include <wiiuse/wpad.h>
#include <ntfs.h>
#include <fat.h>
#include "gc_dvd.h"
#include "main.h"
static GXRModeObj *rmode = NULL;
static void *xfb = NULL;
static char gameName[32];
static char mountPath[512];
static char wpadNeedScan = 0;
static char padNeedScan = 0;
u32 iosversion = -1;
const DISC_INTERFACE* usb = &__io_usbstorage;
char txtbuffer[2048];
bool discIsDL = false;
u32 get_buttons_pressed() {
WPADData *wiiPad;
u32 buttons = 0;
if (padNeedScan) {
PAD_ScanPads();
padNeedScan = 0;
}
if (wpadNeedScan) {
WPAD_ScanPads();
wpadNeedScan = 0;
}
u16 gcPad = PAD_ButtonsDown(0);
wiiPad = WPAD_Data(0);
if ((gcPad & PAD_BUTTON_B) || (wiiPad->btns_h & WPAD_BUTTON_B)) {
buttons |= PAD_BUTTON_B;
}
if ((gcPad & PAD_BUTTON_A) || (wiiPad->btns_h & WPAD_BUTTON_A)) {
buttons |= PAD_BUTTON_A;
}
if ((gcPad & PAD_BUTTON_LEFT) || (wiiPad->btns_h & WPAD_BUTTON_LEFT)) {
buttons |= PAD_BUTTON_LEFT;
}
if ((gcPad & PAD_BUTTON_RIGHT) || (wiiPad->btns_h & WPAD_BUTTON_RIGHT)) {
buttons |= PAD_BUTTON_RIGHT;
}
if ((gcPad & PAD_BUTTON_UP) || (wiiPad->btns_h & WPAD_BUTTON_UP)) {
buttons |= PAD_BUTTON_UP;
}
if ((gcPad & PAD_BUTTON_DOWN) || (wiiPad->btns_h & WPAD_BUTTON_DOWN)) {
buttons |= PAD_BUTTON_DOWN;
}
if ((gcPad & PAD_TRIGGER_Z) || (wiiPad->btns_h & WPAD_BUTTON_HOME)) {
DI_Close();
void (*rld)() = (void(*)()) 0x80001800;
rld();
}
return buttons;
}
void wait_press_A() {
printf("Press A to continue\r");
while ((get_buttons_pressed() & PAD_BUTTON_A));
while (!(get_buttons_pressed() & PAD_BUTTON_A));
printf(" \r");
}
static void InvalidatePADS() {
padNeedScan = wpadNeedScan = 1;
}
static int have_hw_access() {
if ((*(volatile unsigned int*) HW_ARMIRQMASK)
&& (*(volatile unsigned int*) HW_ARMIRQFLAG)) {
return 1;
}
return 0;
}
void ShutdownWii() {
SYS_ResetSystem(SYS_POWEROFF, 0, 0);
}
static void Initialise() {
VIDEO_Init();
PAD_Init();
CONF_Init();
WPAD_Init();
WPAD_SetIdleTimeout(120);
WPAD_SetPowerButtonCallback((WPADShutdownCallback) ShutdownWii);
SYS_SetPowerCallback(ShutdownWii);
rmode = VIDEO_GetPreferredMode(NULL);
xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
console_init(xfb,20,20,rmode->fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ);
VIDEO_Configure(rmode);
VIDEO_SetNextFramebuffer(xfb);
VIDEO_SetPostRetraceCallback(InvalidatePADS);
VIDEO_SetBlack(FALSE);
VIDEO_Flush();
VIDEO_WaitVSync();
if (rmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();
// The console understands VT terminal escape codes
// This positions the cursor on row 2, column 0
printf("\x1b[%d;%dH", 2, 0);
}
/* FindIOS - borrwed from Tantric */
static int FindIOS(u32 ios) {
s32 ret;
u32 n;
u64 *titles = NULL;
u32 num_titles = 0;
ret = ES_GetNumTitles(&num_titles);
if (ret < 0)
return 0;
if (num_titles < 1)
return 0;
titles = (u64 *) memalign(32, num_titles * sizeof(u64) + 32);
if (!titles)
return 0;
ret = ES_GetTitles(titles, num_titles);
if (ret < 0) {
free(titles);
return 0;
}
for (n = 0; n < num_titles; n++) {
if ((titles[n] & 0xFFFFFFFF) == ios) {
free(titles);
return 1;
}
}
free(titles);
return 0;
}
static void hardware_checks() {
int ios58exists = FindIOS(58);
if (!have_hw_access()) {
printf("AHBPROT check failed!\r\n");
printf("Please install the latest HBC!\r\n");
wait_press_A();
}
if (ios58exists && iosversion != 58) {
printf("IOS version check failed!\r\n");
printf("IOS 58 exists but is not in use!\r\n");
wait_press_A();
}
if (!ios58exists) {
printf("IOS version check failed!\r\n");
printf("Please install IOS58!\r\n");
wait_press_A();
}
}
static int initialise_dvd() {
printf("Insert a Wii disc\r\n");
wait_press_A();
printf("Initialising disc ... ");
int ret = init_dvd();
if (ret == NO_DISC) {
printf("no disc detected!\r\n");
} else {
printf("\r \r");
}
return ret;
}
static int initialise_device() {
int ret = fatMountSimple("fat", usb);
sprintf(&mountPath[0], "fat:/");
if (ret != 1) {
printf("Error mounting device [%08X]!\r\n", ret);
wait_press_A();
}
return ret;
}
static void identify_disc() {
char *readbuf = (char*)READ_BUFFER;
DVD_LowRead64(readbuf, 2048, 0ULL);
if (readbuf[0]) {
strncpy(&gameName[0], readbuf, 6);
printf("Game: %s\r\n", &gameName[0]);
} else {
printf("HUH??? Shouln'd happen, problem with game name!!!\r\n");
wait_press_A();
}
}
static void get_settings() {
while ((get_buttons_pressed() & PAD_BUTTON_A));
// DL detection start
u32 endLBA = WII_D5_SIZE;
char *readbuf = (char*)READ_BUFFER;
DVD_LowRead64(readbuf, 2048, (u64) (((u64) endLBA) << 11));
//printf("DL data: %s\r\n", readbuf);
discIsDL = !(strcmp(&gameName[0], readbuf) == 0);
// DL detection end
while (1) {
printf("Dual Layer: %s (press A to continue, L/R to change)\r", (discIsDL ? "Yes" : "No "));
while (!(get_buttons_pressed() & (PAD_BUTTON_RIGHT | PAD_BUTTON_LEFT | PAD_BUTTON_A)));
u32 btns = get_buttons_pressed();
if(btns & PAD_BUTTON_RIGHT) {
discIsDL = true;
}
if(btns & PAD_BUTTON_LEFT) {
discIsDL = false;
}
if(btns & PAD_BUTTON_A) {
break;
}
while (get_buttons_pressed() & (PAD_BUTTON_RIGHT | PAD_BUTTON_LEFT | PAD_BUTTON_A));
}
printf("\n");
while(get_buttons_pressed() & PAD_BUTTON_B);
}
void prompt_new_file(FILE *fp, int chunk) {
fclose(fp);
fp = NULL;
sprintf(txtbuffer, "%s%s_%i.bin", &mountPath[0], &gameName[0], chunk);
remove(&txtbuffer[0]);
fp = fopen(&txtbuffer[0], "wb");
if (fp == NULL) {
printf("Failed to create file %s!\r\n", txtbuffer);
wait_press_A();
}
}
void dump_info() {
char infoLine[1024];
memset(infoLine, 0, 1024);
if (!discIsDL) {
sprintf(infoLine, "@ECHO OFF\r\n"
"ECHO Transfering game %s...\r\n"
"copy /B %s_0.bin+%s_1.bin D:\\Data\\Roms\\WII\\%s.iso > NUL\r\n"
"DEL %s_0.bin\r\n"
"DEL %s_1.bin\r\n"
"DEL %s.bat\r\n",
&gameName[0], &gameName[0], &gameName[0], &gameName[0], &gameName[0], &gameName[0], &gameName[0]);
} else {
sprintf(infoLine, "@ECHO OFF\r\n"
"ECHO Transfering game %s...\r\n"
"copy /B %s_0.bin+%s_1.bin+%s_2.bin D:\\Data\\Roms\\WII\\%s.iso > NUL\r\n"
"DEL %s_0.bin\r\n"
"DEL %s_1.bin\r\n"
"DEL %s_2.bin\r\n"
"DEL %s.bat\r\n",
&gameName[0], &gameName[0], &gameName[0], &gameName[0], &gameName[0], &gameName[0], &gameName[0], &gameName[0], &gameName[0]);
}
sprintf(txtbuffer, "%s%s.bat", &mountPath[0], &gameName[0]);
remove(&txtbuffer[0]);
FILE *fp = fopen(txtbuffer, "wb");
if (fp) {
fwrite(infoLine, 1, strlen(&infoLine[0]), fp);
fclose(fp);
}
}
void dump_game() {
int opt_read_size = ONE_MEGABYTE;
u32 previousLBA = 0;
u32 startLBA = 0;
u32 endLBA = (discIsDL ? WII_D9_SIZE : WII_D5_SIZE);
u32 opt_chunk_size = 3 * ONE_GIGABYTE;
char *buffer = (char*) READ_BUFFER;
int ret = 0;
int chunk = 1;
sprintf(txtbuffer, "%s%s_0.bin", &mountPath[0], &gameName[0]);
remove(&txtbuffer[0]);
FILE *fp = fopen(&txtbuffer[0], "wb");
if (fp == NULL) {
printf("Failed to create file %s!\r\n", txtbuffer);
wait_press_A();
}
long long copyTime = gettime();
long long startTime = gettime();
while (!ret && (startLBA + opt_read_size) < endLBA) {
if (startLBA > (opt_chunk_size * chunk)) {
prompt_new_file(fp, chunk);
chunk++;
}
ret = DVD_LowRead64(buffer, (u32) (opt_read_size << 11), (u64) (((u64) startLBA) << 11));
int bytes_written = fwrite(buffer, 1, (u32) (opt_read_size << 11), fp);
if (bytes_written != (u32) (opt_read_size << 11)) {
fclose(fp);
printf("Write error!\r\n");
wait_press_A();
}
if (get_buttons_pressed() & PAD_BUTTON_B) {
ret = -61;
}
startLBA+=opt_read_size;
int timePassed = diff_msec(copyTime, gettime());
if (timePassed >= 1000) {
copyTime = gettime();
int msecPerRead = (((startLBA - previousLBA) << 11) / timePassed);
u64 remainder = (endLBA - startLBA);
u32 etaTime = (remainder / msecPerRead) * timePassed;
printf("%i%% %dMb %4.0fkb/s - ETA %02d:%02d:%02d\r",
(int)((float)((float)startLBA/(float)endLBA)*100),
(int) (((u64) ((u64) startLBA << 11)) / (1024 * 1024)),
(float)(msecPerRead),
(int)(((etaTime/1000)/60/60)%60),(int)(((etaTime/1000)/60)%60),(int)((etaTime/1000)%60));
previousLBA = startLBA;
}
}
// Remainder of data ???
if(!ret && startLBA < endLBA) {
ret = DVD_LowRead64(buffer, (u32)((endLBA-startLBA)<<11), (u64)((u64)startLBA<<11));
int bytes_written = fwrite(buffer, 1, (u32)((endLBA-startLBA)<<11), fp);
if(bytes_written != (u32)((endLBA-startLBA)<<11)) {
fclose(fp);
printf("Write error!\r\n");
wait_press_A();
}
}
fflush(fp);
fclose(fp);
dvd_motor_off();
if(ret != -61 && ret) {
printf("\n");
printf("Error: %s\r\n",dvd_error_str());
wait_press_A();
}
else if (ret == -61) {
printf(" \r");
printf("Copy cancelled!\r\n");
wait_press_A();
}
else {
printf(" \r");
printf("Copy completed in %d mins\r\n",diff_sec(startTime, gettime())/60);
dump_info();
wait_press_A();
}
}
int main(int argc, char **argv) {
int ret = 0;
Initialise();
iosversion = IOS_GetVersion();
printf("CleanRip 1.0.4 by GrEvilKin based on emu_kidid's\r\n");
hardware_checks();
while (1) {
ret = -1;
while (ret != 1) {
ret = initialise_device();
}
ret = NO_DISC;
while (ret == NO_DISC) {
ret = initialise_dvd();
}
identify_disc();
get_settings();
dump_game();
}
return 0;
}