diff --git a/Makefile b/Makefile index 379cf5b..68027d6 100644 --- a/Makefile +++ b/Makefile @@ -1,151 +1,11 @@ -#--------------------------------------------------------------------------------- -# Clear the implicit built in rules -#--------------------------------------------------------------------------------- -.SUFFIXES: -#--------------------------------------------------------------------------------- -#DEVKITPRO = /opt/devkitPPC -#DEVKITPPC = /opt/devkitPPC +all: + make -f Makefile.de + make -f Makefile.en -ifeq ($(strip $(DEVKITPPC)),) -$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") -endif - -include $(DEVKITPPC)/wii_rules - -#--------------------------------------------------------------------------------- -# TARGET is the name of the output -# BUILD is the directory where object files & intermediate files will be placed -# SOURCES is a list of directories containing source code -# INCLUDES is a list of directories containing extra header files -#--------------------------------------------------------------------------------- -TARGET := YAWMM_DE/boot -BUILD := build -SOURCES := source source/libtinysmb source/libpng source/libpng/pngu -DATA := data -INCLUDES := - -#--------------------------------------------------------------------------------- -# options for code generation -#--------------------------------------------------------------------------------- - -CFLAGS = -Os -Wall -mrvl $(MACHDEP) $(INCLUDE) -CXXFLAGS = $(CFLAGS) - -LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map -T../rvl.ld - -#--------------------------------------------------------------------------------- -# any extra libraries we wish to link with the project -#--------------------------------------------------------------------------------- -LIBS := -ltinysmb -lpng -lfat -lwiiuse -lbte -logc -lm -lz -lwiilight -lruntimeiospatch - -#--------------------------------------------------------------------------------- -# list of directories containing libraries, this must be the top level containing -# include and lib -#--------------------------------------------------------------------------------- -LIBDIRS := - -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- - -export OUTPUT := $(CURDIR)/$(TARGET) - -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) - -export DEPSDIR := $(CURDIR)/$(BUILD) - -#--------------------------------------------------------------------------------- -# automatically build a list of object files for our project -#--------------------------------------------------------------------------------- -CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) -CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) -sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) -SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) - -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) - export LD := $(CC) -else - export LD := $(CXX) -endif - -export OFILES := $(addsuffix .o,$(BINFILES)) \ - $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ - $(sFILES:.s=.o) $(SFILES:.S=.o) - -#--------------------------------------------------------------------------------- -# build a list of include paths -#--------------------------------------------------------------------------------- -export INCLUDE := $(foreach dir,$(INCLUDES), -iquote $(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) \ - -I$(LIBOGC_INC) - -#--------------------------------------------------------------------------------- -# build a list of library paths -#--------------------------------------------------------------------------------- -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ - -L$(LIBOGC_LIB) - -export OUTPUT := $(CURDIR)/$(TARGET) -.PHONY: $(BUILD) clean - -#--------------------------------------------------------------------------------- -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- clean: - @echo clean ... - @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol + make -f Makefile.de clean + make -f Makefile.en clean -#--------------------------------------------------------------------------------- run: - wiiload $(TARGET).dol - - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -$(OUTPUT).dol: $(OUTPUT).elf -$(OUTPUT).elf: $(OFILES) - -#--------------------------------------------------------------------------------- -# This rule links in binary data with the .jpg extension -#--------------------------------------------------------------------------------- -%.jpg.o : %.jpg -#--------------------------------------------------------------------------------- - @echo $(notdir $<) - $(bin2o) - -%.elf.o : %.elf - @echo $(notdir $<) - $(bin2o) - -%.dat.o : %.dat - @echo $(notdir $<) - $(bin2o) - -%.png.o : %.png - @echo $(notdir $<) - $(bin2o) - --include $(DEPENDS) - -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- - + make -f Makefile.de run + make -f Makefile.en run diff --git a/Makefile.de b/Makefile.de new file mode 100644 index 0000000..9311bfa --- /dev/null +++ b/Makefile.de @@ -0,0 +1,151 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +#DEVKITPRO = /opt/devkitPPC +#DEVKITPPC = /opt/devkitPPC + +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +endif + +include $(DEVKITPPC)/wii_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := YAWMM_DE/boot +BUILD := build +SOURCES := source source/libtinysmb source/libpng source/libpng/pngu +DATA := data +INCLUDES := + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -Os -Wall -mrvl $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) + +LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map -T../rvl.ld + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -ltinysmb -lpng -lfat -lwiiuse -lbte -logc -lm -lz -lwiilight -lruntimeiospatch + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES), -iquote $(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) \ + -I$(LIBOGC_INC) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + -L$(LIBOGC_LIB) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.de + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol + +#--------------------------------------------------------------------------------- +run: + wiiload $(TARGET).dol + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).dol: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .jpg extension +#--------------------------------------------------------------------------------- +%.jpg.o : %.jpg +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + $(bin2o) + +%.elf.o : %.elf + @echo $(notdir $<) + $(bin2o) + +%.dat.o : %.dat + @echo $(notdir $<) + $(bin2o) + +%.png.o : %.png + @echo $(notdir $<) + $(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + diff --git a/Makefile.en b/Makefile.en new file mode 100644 index 0000000..709ee5b --- /dev/null +++ b/Makefile.en @@ -0,0 +1,151 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +#DEVKITPRO = /opt/devkitPPC +#DEVKITPPC = /opt/devkitPPC + +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +endif + +include $(DEVKITPPC)/wii_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := YAWMM_EN/boot +BUILD := build.en +SOURCES := source.en source.en/libtinysmb source.en/libpng source.en/libpng/pngu +DATA := data +INCLUDES := + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -Os -Wall -mrvl $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) + +LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map -T../rvl.ld + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -ltinysmb -lpng -lfat -lwiiuse -lbte -logc -lm -lz -lwiilight -lruntimeiospatch + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES), -iquote $(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) \ + -I$(LIBOGC_INC) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + -L$(LIBOGC_LIB) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.en + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol + +#--------------------------------------------------------------------------------- +run: + wiiload $(TARGET).dol + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).dol: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .jpg extension +#--------------------------------------------------------------------------------- +%.jpg.o : %.jpg +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + $(bin2o) + +%.elf.o : %.elf + @echo $(notdir $<) + $(bin2o) + +%.dat.o : %.dat + @echo $(notdir $<) + $(bin2o) + +%.png.o : %.png + @echo $(notdir $<) + $(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + diff --git a/source.en/fat.c b/source.en/fat.c new file mode 100644 index 0000000..5c8081b --- /dev/null +++ b/source.en/fat.c @@ -0,0 +1,58 @@ +#include +#include +#include +//#include + +#include "fat.h" + + +s32 Fat_Mount(fatDevice *dev) +{ + s32 ret; + + /* Initialize interface */ + ret = dev->interface->startup(); + if (!ret) + return -1; + + /* Mount device */ + ret = fatMountSimple(dev->mount, dev->interface); + if (!ret) + return -1; + + return 0; +} + +void Fat_Unmount(fatDevice *dev) +{ + /* Unmount device */ + fatUnmount(dev->mount); + + /* Shutdown interface */ + dev->interface->shutdown(); +} + +char *Fat_ToFilename(const char *filename) +{ + static char buffer[128]; + + u32 cnt, idx, len; + + /* Clear buffer */ + memset(buffer, 0, sizeof(buffer)); + + /* Get filename length */ + len = strlen(filename); + + for (cnt = idx = 0; idx < len; idx++) { + char c = filename[idx]; + + /* Valid characters */ + if ( (c >= '#' && c <= ')') || (c >= '-' && c <= '.') || + (c >= '0' && c <= '9') || (c >= 'A' && c <= 'z') || + (c >= 'a' && c <= 'z') || (c == '!') ) + buffer[cnt++] = c; + } + + return buffer; +} diff --git a/source.en/fat.h b/source.en/fat.h new file mode 100644 index 0000000..43033fd --- /dev/null +++ b/source.en/fat.h @@ -0,0 +1,55 @@ +#ifndef _FAT_H_ +#define _FAT_H_ + +/* libfat header */ +#include +#include + +/* SD headers */ +#include +#include + + +/* 'FAT Device' structure */ +typedef struct { + /* Device mount point */ + char *mount; + + /* Device name */ + char *name; + + /* Device interface */ + const DISC_INTERFACE *interface; +} fatDevice; + +/* 'FAT File' structure */ +typedef struct { + /* Filename */ + char filename[128]; + /* 1 = Batch Install, 2 = Batch Uninstall - Leathl */ + int install; + + int installstate; + + int old_ios; + int new_ios; + bool old_ahbprot; + bool new_ahbprot; + bool old_pass; + bool new_pass; + + u32 high_id; + u32 low_id; + + /* Filestat */ + struct dirent entry; +} fatFile; + + +/* Prototypes */ +s32 Fat_Mount(fatDevice *); +void Fat_Unmount(fatDevice *); +char *Fat_ToFilename(const char *); + +#endif + diff --git a/source.en/globals.h b/source.en/globals.h new file mode 100644 index 0000000..e4d7f25 --- /dev/null +++ b/source.en/globals.h @@ -0,0 +1,57 @@ +#ifndef _GLOBALS_H_ +#define _GLOBALS_H_ + +// Constants +#define CIOS_VERSION 249 +#define ENTRIES_PER_PAGE 12 +#define MAX_FILE_PATH_LEN 1024 +#define MAX_DIR_LEVELS 10 +#define WAD_DIRECTORY "/" + +#define MAX_PASSWORD_LENGTH 10 +#define MAX_FAT_DEVICE_LENGTH 10 +#define MAX_NAND_DEVICE_LENGTH 10 + +#define WM_CONFIG_FILE_PATH ":/wad/wm_config.txt" +#define WM_BACKGROUND_PATH ":/wad/background.png" + +// These are indices into the fatDevice fdevList +#define FAT_DEVICE_INDEX_WII_SD 0 +#define FAT_DEVICE_INDXE_USB 1 +#define FAT_DEVICE_INDEX_USB2 2 +#define FAT_DEVICE_INDEX_GC_SDA 3 +#define FAT_DEVICE_INDEX_GC_SDB 4 +#define FAT_DEVICE_INDEX_INVALID -1 + +// These are the indices into the nandDevice ndevList +#define NAND_DEVICE_INDEX_DISABLE 0 +#define NAND_DEVICE_INDEX_SD 1 +#define NAND_DEVICE_INDEX_USB 2 +#define NAND_DEVICE_INDEX_INVALID -1 + +#define CIOS_VERSION_INVALID -1 + +// For the WiiLight +#define WII_LIGHT_OFF 0 +#define WII_LIGHT_ON 1 + +typedef struct +{ + char password[MAX_PASSWORD_LENGTH]; + char startupPath [256]; + int cIOSVersion; + int fatDeviceIndex; + int nandDeviceIndex; + const char *smbuser; + const char *smbpassword; + const char *share; + const char *ip; +} CONFIG; + + +extern CONFIG gConfig; +extern nandDevice ndevList[]; +extern fatDevice fdevList[]; + + +#endif diff --git a/source.en/gpio.h b/source.en/gpio.h new file mode 100644 index 0000000..ec80fc2 --- /dev/null +++ b/source.en/gpio.h @@ -0,0 +1,58 @@ +/* + mini - a Free Software replacement for the Nintendo/BroadOn IOS. + GPIO pin-out constants + +Copyright (C) 2008, 2009 Hector Martin "marcan" + +# This code is licensed to you under the terms of the GNU GPL, version 2; +# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +*/ + +#ifndef __GPIO_H__ +#define __GPIO_H__ + +enum { + GP_POWER = 0x000001, + GP_SHUTDOWN = 0x000002, + GP_FAN = 0x000004, + GP_DCDC = 0x000008, + GP_DISPIN = 0x000010, + GP_SLOTLED = 0x000020, + GP_EJECTBTN = 0x000040, + GP_SLOTIN = 0x000080, + GP_SENSORBAR = 0x000100, + GP_DOEJECT = 0x000200, + GP_EEP_CS = 0x000400, + GP_EEP_CLK = 0x000800, + GP_EEP_MOSI = 0x001000, + GP_EEP_MISO = 0x002000, + GP_AVE_SCL = 0x004000, + GP_AVE_SDA = 0x008000, + GP_DEBUG0 = 0x010000, + GP_DEBUG1 = 0x020000, + GP_DEBUG2 = 0x040000, + GP_DEBUG3 = 0x080000, + GP_DEBUG4 = 0x100000, + GP_DEBUG5 = 0x200000, + GP_DEBUG6 = 0x400000, + GP_DEBUG7 = 0x800000, +}; + +#define GP_DEBUG_SHIFT 16 +#define GP_DEBUG_MASK 0xFF0000 + +#define GP_ALL 0xFFFFFF +#define GP_OWNER_PPC (GP_AVE_SDA | GP_AVE_SCL | GP_DOEJECT | GP_SENSORBAR | GP_SLOTIN | GP_SLOTLED) +#define GP_OWNER_ARM (GP_ALL ^ GP_OWNER_PPC) +#define GP_INPUTS (GP_POWER | GP_EJECTBTN | GP_SLOTIN | GP_EEP_MISO | GP_AVE_SDA) +#define GP_OUTPUTS (GP_ALL ^ GP_INPUTS) +#define GP_ARM_INPUTS (GP_INPUTS & GP_OWNER_ARM) +#define GP_PPC_INPUTS (GP_INPUTS & GP_OWNER_PPC) +#define GP_ARM_OUTPUTS (GP_OUTPUTS & GP_OWNER_ARM) +#define GP_PPC_OUTPUTS (GP_OUTPUTS & GP_OWNER_PPC) +#define GP_DEFAULT_ON (GP_AVE_SCL | GP_DCDC | GP_FAN) +#define GP_ARM_DEFAULT_ON (GP_DEFAULT_ON & GP_OWNER_ARM) +#define GP_PPC_DEFAULT_ON (GP_DEFAULT_ON & GP_OWNER_PPC) + +#endif + diff --git a/source.en/gui.c b/source.en/gui.c new file mode 100644 index 0000000..ba8a245 --- /dev/null +++ b/source.en/gui.c @@ -0,0 +1,90 @@ +#include +#include +#include + +#include "video.h" +#include "fat.h" +#include "menu.h" +#include "nand.h" +#include "globals.h" + +/* Constants */ +#define CONSOLE_XCOORD 50 +#define CONSOLE_YCOORD 100 +#define CONSOLE_WIDTH 540 +#define CONSOLE_HEIGHT 320 + +bool file_exists(const char * filename) +{ + FILE * file; + if (file = fopen(filename, "r")) + { + fclose(file); + return true; + } + return false; +} + + +s32 __Gui_DrawPng(void *img, u32 x, u32 y) +{ + IMGCTX ctx = NULL; + PNGUPROP imgProp; + + s32 ret; + + fatDevice *fdev = &fdevList[0]; + ret = Fat_Mount(fdev); + if (file_exists("sd:/wad/background.png")) ctx = PNGU_SelectImageFromDevice ("sd:/wad/background.png"); + + if (ret < 0) + { + fdev = &fdevList[2]; + Fat_Mount(fdev); + if (file_exists("usb2:/wad/background.png")) ctx = PNGU_SelectImageFromDevice ("usb2:/wad/background.png"); + } + + if(!ctx) + { + /* Select PNG data */ + ctx = PNGU_SelectImageFromBuffer(img); + if (!ctx) { + ret = -1; + goto out; + } + } + /* Get image properties */ + ret = PNGU_GetImageProperties(ctx, &imgProp); + if (ret != PNGU_OK) { + ret = -1; + goto out; + } + + /* Draw image */ + Video_DrawPng(ctx, imgProp, x, y); + + /* Success */ + ret = 0; + +out: + /* Free memory */ + if (ctx) + PNGU_ReleaseImageContext(ctx); + + return ret; +} + + +void Gui_InitConsole(void) +{ + /* Initialize console */ + Con_Init(CONSOLE_XCOORD, CONSOLE_YCOORD, CONSOLE_WIDTH, CONSOLE_HEIGHT); +} + +void Gui_DrawBackground(void) +{ + extern char bgData[]; + + /* Draw background */ + __Gui_DrawPng(bgData, 0, 0); +} diff --git a/source.en/gui.h b/source.en/gui.h new file mode 100644 index 0000000..80f174c --- /dev/null +++ b/source.en/gui.h @@ -0,0 +1,8 @@ +#ifndef _GUI_H_ +#define _GUI_H_ + +/* Prototypes */ +void Gui_InitConsole(void); +void Gui_DrawBackground(void); + +#endif diff --git a/source.en/hollywood.h b/source.en/hollywood.h new file mode 100644 index 0000000..3543861 --- /dev/null +++ b/source.en/hollywood.h @@ -0,0 +1,179 @@ +/* + mini - a Free Software replacement for the Nintendo/BroadOn IOS. + Hollywood register definitions + +Copyright (C) 2008, 2009 Haxx Enterprises +Copyright (C) 2008, 2009 Sven Peter +Copyright (C) 2008, 2009 Hector Martin "marcan" +Copyright (C) 2008, 2009 John Kelley + +# This code is licensed to you under the terms of the GNU GPL, version 2; +# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +*/ + +#ifndef __HOLLYWOOD_H__ +#define __HOLLYWOOD_H__ + +/* Hollywood Registers */ + +#define HW_PPC_REG_BASE 0xd000000 +#define HW_REG_BASE 0xd800000 + +// The PPC can only see the first three IPC registers +#define HW_IPC_PPCMSG (HW_REG_BASE + 0x000) +#define HW_IPC_PPCCTRL (HW_REG_BASE + 0x004) +#define HW_IPC_ARMMSG (HW_REG_BASE + 0x008) +#define HW_IPC_ARMCTRL (HW_REG_BASE + 0x00c) + +#define HW_TIMER (HW_REG_BASE + 0x010) +#define HW_ALARM (HW_REG_BASE + 0x014) + +#define HW_PPCIRQFLAG (HW_REG_BASE + 0x030) +#define HW_PPCIRQMASK (HW_REG_BASE + 0x034) + +#define HW_ARMIRQFLAG (HW_REG_BASE + 0x038) +#define HW_ARMIRQMASK (HW_REG_BASE + 0x03c) + +#define HW_MEMMIRR (HW_REG_BASE + 0x060) +#define HW_AHBPROT (HW_REG_BASE + 0x064) + +// something to do with PPCBOOT +// and legacy DI it seems ?!? +#define HW_EXICTRL (HW_REG_BASE + 0x070) +#define EXICTRL_ENABLE_EXI 1 + +// PPC side of GPIO1 (Starlet can access this too) +// Output state +#define HW_GPIO1BOUT (HW_REG_BASE + 0x0c0) +// Direction (1=output) +#define HW_GPIO1BDIR (HW_REG_BASE + 0x0c4) +// Input state +#define HW_GPIO1BIN (HW_REG_BASE + 0x0c8) +// Interrupt level +#define HW_GPIO1BINTLVL (HW_REG_BASE + 0x0cc) +// Interrupt flags (write 1 to clear) +#define HW_GPIO1BINTFLAG (HW_REG_BASE + 0x0d0) +// Interrupt propagation enable +// Do these interrupts go anywhere??? +#define HW_GPIO1BINTENABLE (HW_REG_BASE + 0x0d4) +//??? seems to be a mirror of inputs at some point... power-up state? +#define HW_GPIO1BINMIR (HW_REG_BASE + 0x0d8) +// 0xFFFFFF by default, if cleared disables respective outputs. Top bits non-settable. +#define HW_GPIO1ENABLE (HW_REG_BASE + 0x0dc) + +#define HW_GPIO1_SLOT 0x000020 +#define HW_GPIO1_DEBUG 0xFF0000 +#define HW_GPIO1_DEBUG_SH 16 + +// Starlet side of GPIO1 +// Output state +#define HW_GPIO1OUT (HW_REG_BASE + 0x0e0) +// Direction (1=output) +#define HW_GPIO1DIR (HW_REG_BASE + 0x0e4) +// Input state +#define HW_GPIO1IN (HW_REG_BASE + 0x0e8) +// Interrupt level +#define HW_GPIO1INTLVL (HW_REG_BASE + 0x0ec) +// Interrupt flags (write 1 to clear) +#define HW_GPIO1INTFLAG (HW_REG_BASE + 0x0f0) +// Interrupt propagation enable (interrupts go to main interrupt 0x800) +#define HW_GPIO1INTENABLE (HW_REG_BASE + 0x0f4) +//??? seems to be a mirror of inputs at some point... power-up state? +#define HW_GPIO1INMIR (HW_REG_BASE + 0x0f8) +// Owner of each GPIO bit. If 1, GPIO1B registers assume control. If 0, GPIO1 registers assume control. +#define HW_GPIO1OWNER (HW_REG_BASE + 0x0fc) + +// ???? +#define HW_DIFLAGS (HW_REG_BASE + 0x180) +#define DIFLAGS_BOOT_CODE 0x100000 + +// maybe a GPIO??? +#define HW_RESETS (HW_REG_BASE + 0x194) + +#define HW_CLOCKS (HW_REG_BASE + 0x1b4) + +#define HW_GPIO2OUT (HW_REG_BASE + 0x1c8) +#define HW_GPIO2DIR (HW_REG_BASE + 0x1cc) +#define HW_GPIO2IN (HW_REG_BASE + 0x1d0) + +#define HW_OTPCMD (HW_REG_BASE + 0x1ec) +#define HW_OTPDATA (HW_REG_BASE + 0x1f0) +#define HW_VERSION (HW_REG_BASE + 0x214) + +/* NAND Registers */ + +#define NAND_REG_BASE 0xd010000 + +#define NAND_CMD (NAND_REG_BASE + 0x000) +#define NAND_STATUS NAND_CMD +#define NAND_CONF (NAND_REG_BASE + 0x004) +#define NAND_ADDR0 (NAND_REG_BASE + 0x008) +#define NAND_ADDR1 (NAND_REG_BASE + 0x00c) +#define NAND_DATA (NAND_REG_BASE + 0x010) +#define NAND_ECC (NAND_REG_BASE + 0x014) +#define NAND_UNK1 (NAND_REG_BASE + 0x018) +#define NAND_UNK2 (NAND_REG_BASE + 0x01c) + +/* AES Registers */ + +#define AES_REG_BASE 0xd020000 + +#define AES_CMD (AES_REG_BASE + 0x000) +#define AES_SRC (AES_REG_BASE + 0x004) +#define AES_DEST (AES_REG_BASE + 0x008) +#define AES_KEY (AES_REG_BASE + 0x00c) +#define AES_IV (AES_REG_BASE + 0x010) + +/* SHA-1 Registers */ + +#define SHA_REG_BASE 0xd030000 + +#define SHA_CMD (SHA_REG_BASE + 0x000) +#define SHA_SRC (SHA_REG_BASE + 0x004) +#define SHA_H0 (SHA_REG_BASE + 0x008) +#define SHA_H1 (SHA_REG_BASE + 0x00c) +#define SHA_H2 (SHA_REG_BASE + 0x010) +#define SHA_H3 (SHA_REG_BASE + 0x014) +#define SHA_H4 (SHA_REG_BASE + 0x018) + +/* SD Host Controller Registers */ + +#define SDHC_REG_BASE 0xd070000 + +/* EXI Registers */ + +#define EXI_REG_BASE 0xd806800 +#define EXI0_REG_BASE (EXI_REG_BASE+0x000) +#define EXI1_REG_BASE (EXI_REG_BASE+0x014) +#define EXI2_REG_BASE (EXI_REG_BASE+0x028) + +#define EXI0_CSR (EXI0_REG_BASE+0x000) +#define EXI0_MAR (EXI0_REG_BASE+0x004) +#define EXI0_LENGTH (EXI0_REG_BASE+0x008) +#define EXI0_CR (EXI0_REG_BASE+0x00c) +#define EXI0_DATA (EXI0_REG_BASE+0x010) + +#define EXI1_CSR (EXI1_REG_BASE+0x000) +#define EXI1_MAR (EXI1_REG_BASE+0x004) +#define EXI1_LENGTH (EXI1_REG_BASE+0x008) +#define EXI1_CR (EXI1_REG_BASE+0x00c) +#define EXI1_DATA (EXI1_REG_BASE+0x010) + +#define EXI2_CSR (EXI2_REG_BASE+0x000) +#define EXI2_MAR (EXI2_REG_BASE+0x004) +#define EXI2_LENGTH (EXI2_REG_BASE+0x008) +#define EXI2_CR (EXI2_REG_BASE+0x00c) +#define EXI2_DATA (EXI2_REG_BASE+0x010) + +#define EXI_BOOT_BASE (EXI_REG_BASE+0x040) + +/* MEMORY CONTROLLER Registers */ + +#define MEM_REG_BASE 0xd8b4000 +#define MEM_PROT (MEM_REG_BASE+0x20a) +#define MEM_PROT_START (MEM_REG_BASE+0x20c) +#define MEM_PROT_END (MEM_REG_BASE+0x20e) +#define MEM_FLUSHREQ (MEM_REG_BASE+0x228) +#define MEM_FLUSHACK (MEM_REG_BASE+0x22a) + +#endif diff --git a/source.en/libpng/pngu/pngu.c b/source.en/libpng/pngu/pngu.c new file mode 100644 index 0000000..2f6a3b2 --- /dev/null +++ b/source.en/libpng/pngu/pngu.c @@ -0,0 +1,1132 @@ +/******************************************************************************************** + +PNGU Version : 0.2a + +Coder : frontier + +More info : http://frontier-dev.net + +********************************************************************************************/ +#include +#include +#include "pngu.h" +#include + + +// Constants +#define PNGU_SOURCE_BUFFER 1 +#define PNGU_SOURCE_DEVICE 2 + + +// Prototypes of helper functions +int pngu_info (IMGCTX ctx); +int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlpha); +void pngu_free_info (IMGCTX ctx); +void pngu_read_data_from_buffer (png_structp png_ptr, png_bytep data, png_size_t length); +void pngu_write_data_to_buffer (png_structp png_ptr, png_bytep data, png_size_t length); +void pngu_flush_data_to_buffer (png_structp png_ptr); +int pngu_clamp (int value, int min, int max); + + +// PNGU Image context struct +struct _IMGCTX +{ + int source; + void *buffer; + char *filename; + PNGU_u32 cursor; + + PNGU_u32 propRead; + PNGUPROP prop; + + PNGU_u32 infoRead; + png_structp png_ptr; + png_infop info_ptr; + FILE *fd; + + png_bytep *row_pointers; + png_bytep img_data; +}; + + +// PNGU Implementation // + +IMGCTX PNGU_SelectImageFromBuffer (const void *buffer) +{ + IMGCTX ctx = NULL; + + if (!buffer) + return NULL; + + ctx = malloc (sizeof (struct _IMGCTX)); + if (!ctx) + return NULL; + + ctx->buffer = (void *) buffer; + ctx->source = PNGU_SOURCE_BUFFER; + ctx->cursor = 0; + ctx->filename = NULL; + ctx->propRead = 0; + ctx->infoRead = 0; + + return ctx; +} + + +IMGCTX PNGU_SelectImageFromDevice (const char *filename) +{ + IMGCTX ctx = NULL; + + if (!filename) + return NULL; + + ctx = malloc (sizeof (struct _IMGCTX)); + if (!ctx) + return NULL; + + ctx->buffer = NULL; + ctx->source = PNGU_SOURCE_DEVICE; + ctx->cursor = 0; + + ctx->filename = malloc (strlen (filename) + 1); + if (!ctx->filename) + { + free (ctx); + return NULL; + } + strcpy(ctx->filename, filename); + + ctx->propRead = 0; + ctx->infoRead = 0; + + return ctx; +} + + +void PNGU_ReleaseImageContext (IMGCTX ctx) +{ + if (!ctx) + return; + + if (ctx->filename) + free (ctx->filename); + + if ((ctx->propRead) && (ctx->prop.trans)) + free (ctx->prop.trans); + + pngu_free_info (ctx); + + free (ctx); +} + + +int PNGU_GetImageProperties (IMGCTX ctx, PNGUPROP *imgprop) +{ + int res; + + if (!ctx->propRead) + { + res = pngu_info (ctx); + if (res != PNGU_OK) + return res; + } + + *imgprop = ctx->prop; + + return PNGU_OK; +} + + +int PNGU_DecodeToYCbYCr (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) +{ + int result; + PNGU_u32 x, y, buffWidth; + + // width needs to be divisible by two + if (width % 2) + return PNGU_ODD_WIDTH; + + // stride needs to be divisible by two + if (stride % 2) + return PNGU_ODD_STRIDE; + + result = pngu_decode (ctx, width, height, 1); + if (result != PNGU_OK) + return result; + + // Copy image to the output buffer + buffWidth = (width + stride) / 2; + for (y = 0; y < height; y++) + for (x = 0; x < (width / 2); x++) + ((PNGU_u32 *)buffer)[y*buffWidth+x] = PNGU_RGB8_TO_YCbYCr (*(ctx->row_pointers[y]+x*6), *(ctx->row_pointers[y]+x*6+1), *(ctx->row_pointers[y]+x*6+2), + *(ctx->row_pointers[y]+x*6+3), *(ctx->row_pointers[y]+x*6+4), *(ctx->row_pointers[y]+x*6+5)); + + // Free resources + free (ctx->img_data); + free (ctx->row_pointers); + + // Success + return PNGU_OK; +} + + +int PNGU_DecodeToRGB565 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) +{ + int result; + PNGU_u32 x, y, buffWidth; + + result = pngu_decode (ctx, width, height, 1); + if (result != PNGU_OK) + return result; + + buffWidth = width + stride; + + // Copy image to the output buffer + for (y = 0; y < height; y++) + for (x = 0; x < width; x++) + ((PNGU_u16 *)buffer)[y*buffWidth+x] = + (((PNGU_u16) (ctx->row_pointers[y][x*3] & 0xF8)) << 8) | + (((PNGU_u16) (ctx->row_pointers[y][x*3+1] & 0xFC)) << 3) | + (((PNGU_u16) (ctx->row_pointers[y][x*3+2] & 0xF8)) >> 3); + + // Free resources + free (ctx->img_data); + free (ctx->row_pointers); + + // Success + return PNGU_OK; +} + + +int PNGU_DecodeToRGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride, PNGU_u8 default_alpha) +{ + int result; + PNGU_u32 x, y, buffWidth; + + result = pngu_decode (ctx, width, height, 0); + if (result != PNGU_OK) + return result; + + buffWidth = width + stride; + + // Check is source image has an alpha channel + if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA) ) + { + // Alpha channel present, copy image to the output buffer + for (y = 0; y < height; y++) + memcpy (buffer + (y * buffWidth * 4), ctx->row_pointers[y], width * 4); + } + else + { + // No alpha channel present, copy image to the output buffer + for (y = 0; y < height; y++) + for (x = 0; x < width; x++) + ((PNGU_u32 *)buffer)[y*buffWidth+x] = + (((PNGU_u32) ctx->row_pointers[y][x*3]) << 24) | + (((PNGU_u32) ctx->row_pointers[y][x*3+1]) << 16) | + (((PNGU_u32) ctx->row_pointers[y][x*3+2]) << 8) | + ((PNGU_u32) default_alpha); + } + + // Free resources + free (ctx->img_data); + free (ctx->row_pointers); + + // Success + return PNGU_OK; +} + + +int PNGU_DecodeTo4x4RGB565 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer) +{ + int result; + PNGU_u32 x, y, qwidth, qheight; + + // width and height need to be divisible by four + if ((width % 4) || (height % 4)) + return PNGU_INVALID_WIDTH_OR_HEIGHT; + + result = pngu_decode (ctx, width, height, 1); + if (result != PNGU_OK) + return result; + + // Copy image to the output buffer + qwidth = width / 4; + qheight = height / 4; + + for (y = 0; y < qheight; y++) + for (x = 0; x < qwidth; x++) + { + int blockbase = (y * qwidth + x) * 4; + + PNGU_u64 field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4]+x*12)); + PNGU_u64 field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase] = + (((field64 & 0xF800000000000000ULL) | ((field64 & 0xFC000000000000ULL) << 3) | ((field64 & 0xF80000000000ULL) << 5)) | + (((field64 & 0xF800000000ULL) << 8) | ((field64 & 0xFC000000ULL) << 11) | ((field64 & 0xF80000ULL) << 13)) | + (((field64 & 0xF800ULL) << 16) | ((field64 & 0xFCULL) << 19) | ((field32 & 0xF8000000ULL) >> 11)) | + (((field32 & 0xF80000ULL) >> 8) | ((field32 & 0xFC00ULL) >> 5) | ((field32 & 0xF8ULL) >> 3))); + + field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+1]+x*12)); + field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+1]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase+1] = + (((field64 & 0xF800000000000000ULL) | ((field64 & 0xFC000000000000ULL) << 3) | ((field64 & 0xF80000000000ULL) << 5)) | + (((field64 & 0xF800000000ULL) << 8) | ((field64 & 0xFC000000ULL) << 11) | ((field64 & 0xF80000ULL) << 13)) | + (((field64 & 0xF800ULL) << 16) | ((field64 & 0xFCULL) << 19) | ((field32 & 0xF8000000ULL) >> 11)) | + (((field32 & 0xF80000ULL) >> 8) | ((field32 & 0xFC00ULL) >> 5) | ((field32 & 0xF8ULL) >> 3))); + + field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+2]+x*12)); + field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+2]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase+2] = + (((field64 & 0xF800000000000000ULL) | ((field64 & 0xFC000000000000ULL) << 3) | ((field64 & 0xF80000000000ULL) << 5)) | + (((field64 & 0xF800000000ULL) << 8) | ((field64 & 0xFC000000ULL) << 11) | ((field64 & 0xF80000ULL) << 13)) | + (((field64 & 0xF800ULL) << 16) | ((field64 & 0xFCULL) << 19) | ((field32 & 0xF8000000ULL) >> 11)) | + (((field32 & 0xF80000ULL) >> 8) | ((field32 & 0xFC00ULL) >> 5) | ((field32 & 0xF8ULL) >> 3))); + + field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+3]+x*12)); + field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+3]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase+3] = + (((field64 & 0xF800000000000000ULL) | ((field64 & 0xFC000000000000ULL) << 3) | ((field64 & 0xF80000000000ULL) << 5)) | + (((field64 & 0xF800000000ULL) << 8) | ((field64 & 0xFC000000ULL) << 11) | ((field64 & 0xF80000ULL) << 13)) | + (((field64 & 0xF800ULL) << 16) | ((field64 & 0xFCULL) << 19) | ((field32 & 0xF8000000ULL) >> 11)) | + (((field32 & 0xF80000ULL) >> 8) | ((field32 & 0xFC00ULL) >> 5) | ((field32 & 0xF8ULL) >> 3))); + } + + // Free resources + free (ctx->img_data); + free (ctx->row_pointers); + + // Success + return PNGU_OK; +} + + +int PNGU_DecodeTo4x4RGB5A3 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u8 default_alpha) +{ + int result; + PNGU_u32 x, y, qwidth, qheight; + PNGU_u64 alphaMask; + + // width and height need to be divisible by four + if ((width % 4) || (height % 4)) + return PNGU_INVALID_WIDTH_OR_HEIGHT; + + result = pngu_decode (ctx, width, height, 0); + if (result != PNGU_OK) + return result; + + // Init some vars + qwidth = width / 4; + qheight = height / 4; + + // Check is source image has an alpha channel + if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA) ) + { + // Alpha channel present, copy image to the output buffer + for (y = 0; y < qheight; y++) + for (x = 0; x < qwidth; x++) + { + int blockbase = (y * qwidth + x) * 4; + PNGU_u64 tmp; + + PNGU_u64 fieldA = *((PNGU_u64 *)(ctx->row_pointers[y*4]+x*16)); + PNGU_u64 fieldB = *((PNGU_u64 *)(ctx->row_pointers[y*4]+x*16+8)); + // If first pixel is opaque set MSB to 1 and encode colors in RGB555, else set MSB to 0 and encode colors in ARGB3444 + if ((fieldA & 0xE000000000ULL) == 0xE000000000ULL) + tmp = 0x8000000000000000ULL | ((fieldA & 0xF800000000000000ULL) >> 1) | ((fieldA & 0xF8000000000000ULL) << 2) | ((fieldA & 0xF80000000000ULL) << 5); + else + tmp = ((fieldA & 0xE000000000ULL) << 23) | ((fieldA & 0xF000000000000000ULL) >> 4) | (fieldA & 0xF0000000000000ULL) | ((fieldA & 0xF00000000000ULL) << 4); + + // If second pixel is opaque set MSB to 1 and encode colors in RGB555, else set MSB to 0 and encode colors in ARGB3444 + if ((fieldA & 0xE0ULL) == 0xE0ULL) + tmp = tmp | 0x800000000000ULL | ((fieldA & 0xF8000000ULL) << 15) | ((fieldA & 0xF80000ULL) << 18) | ((fieldA & 0xF800ULL) << 21); + else + tmp = tmp | ((fieldA & 0xE0ULL) << 39) | ((fieldA & 0xF0000000ULL) << 12) | ((fieldA & 0xF00000ULL) << 16) | ((fieldA & 0xF000ULL) << 20); + + // If third pixel is opaque set MSB to 1 and encode colors in RGB555, else set MSB to 0 and encode colors in ARGB3444 + if ((fieldB & 0xE000000000ULL) == 0xE000000000ULL) + tmp = tmp | 0x80000000ULL | ((fieldB & 0xF800000000000000ULL) >> 33) | ((fieldB & 0xF8000000000000ULL) >> 30) | ((fieldB & 0xF80000000000ULL) >> 27); + else + tmp = tmp | ((fieldB & 0xE000000000ULL) >> 9) | ((fieldB & 0xF000000000000000ULL) >> 36) | ((fieldB & 0xF0000000000000ULL) >> 32) | ((fieldB & 0xF00000000000ULL) >> 28); + + // If fourth pixel is opaque set MSB to 1 and encode colors in RGB555, else set MSB to 0 and encode colors in ARGB3444 + if ((fieldB & 0xE0ULL) == 0xE0ULL) + tmp = tmp | 0x8000ULL | ((fieldB & 0xF8000000ULL) >> 17) | ((fieldB & 0xF80000ULL) >> 14) | ((fieldB & 0xF800ULL) >> 11); + else + tmp = tmp | ((fieldB & 0xE0ULL) << 7) | ((fieldB & 0xF0000000ULL) >> 20) | ((fieldB & 0xF00000ULL) >> 16) | ((fieldB & 0xF000ULL) >> 12); + ((PNGU_u64 *) buffer)[blockbase] = tmp; + + fieldA = *((PNGU_u64 *)(ctx->row_pointers[y*4+1]+x*16)); + fieldB = *((PNGU_u64 *)(ctx->row_pointers[y*4+1]+x*16+8)); + if ((fieldA & 0xE000000000ULL) == 0xE000000000ULL) + // Opaque pixel, so set MSB to 1 and encode colors in RGB555 + tmp = 0x8000000000000000ULL | ((fieldA & 0xF800000000000000ULL) >> 1) | ((fieldA & 0xF8000000000000ULL) << 2) | ((fieldA & 0xF80000000000ULL) << 5); + else + // Tranlucid pixel, so set MSB to 0 and encode colors in ARGB3444 + tmp = ((fieldA & 0xE000000000ULL) << 23) | ((fieldA & 0xF000000000000000ULL) >> 4) | (fieldA & 0xF0000000000000ULL) | ((fieldA & 0xF00000000000ULL) << 4); + + if ((fieldA & 0xE0ULL) == 0xE0ULL) + // Opaque pixel, so set MSB to 1 and encode colors in RGB555 + tmp = tmp | 0x800000000000ULL | ((fieldA & 0xF8000000ULL) << 15) | ((fieldA & 0xF80000ULL) << 18) | ((fieldA & 0xF800ULL) << 21); + else + // Tranlucid pixel, so set MSB to 0 and encode colors in ARGB3444 + tmp = tmp | ((fieldA & 0xE0ULL) << 39) | ((fieldA & 0xF0000000ULL) << 12) | ((fieldA & 0xF00000ULL) << 16) | ((fieldA & 0xF000ULL) << 20); + + if ((fieldB & 0xE000000000ULL) == 0xE000000000ULL) + // Opaque pixel, so set MSB to 1 and encode colors in RGB555 + tmp = tmp | 0x80000000ULL | ((fieldB & 0xF800000000000000ULL) >> 33) | ((fieldB & 0xF8000000000000ULL) >> 30) | ((fieldB & 0xF80000000000ULL) >> 27); + else + // Tranlucid pixel, so set MSB to 0 and encode colors in ARGB3444 + tmp = tmp | ((fieldB & 0xE000000000ULL) >> 9) | ((fieldB & 0xF000000000000000ULL) >> 36) | ((fieldB & 0xF0000000000000ULL) >> 32) | ((fieldB & 0xF00000000000ULL) >> 28); + + if ((fieldB & 0xE0ULL) == 0xE0ULL) + // Opaque pixel, so set MSB to 1 and encode colors in RGB555 + tmp = tmp | 0x8000ULL | ((fieldB & 0xF8000000ULL) >> 17) | ((fieldB & 0xF80000ULL) >> 14) | ((fieldB & 0xF800ULL) >> 11); + else + // Tranlucid pixel, so set MSB to 0 and encode colors in ARGB3444 + tmp = tmp | ((fieldB & 0xE0ULL) << 7) | ((fieldB & 0xF0000000ULL) >> 20) | ((fieldB & 0xF00000ULL) >> 16) | ((fieldB & 0xF000ULL) >> 12); + ((PNGU_u64 *) buffer)[blockbase+1] = tmp; + + fieldA = *((PNGU_u64 *)(ctx->row_pointers[y*4+2]+x*16)); + fieldB = *((PNGU_u64 *)(ctx->row_pointers[y*4+2]+x*16+8)); + if ((fieldA & 0xE000000000ULL) == 0xE000000000ULL) + // Opaque pixel, so set MSB to 1 and encode colors in RGB555 + tmp = 0x8000000000000000ULL | ((fieldA & 0xF800000000000000ULL) >> 1) | ((fieldA & 0xF8000000000000ULL) << 2) | ((fieldA & 0xF80000000000ULL) << 5); + else + // Tranlucid pixel, so set MSB to 0 and encode colors in ARGB3444 + tmp = ((fieldA & 0xE000000000ULL) << 23) | ((fieldA & 0xF000000000000000ULL) >> 4) | (fieldA & 0xF0000000000000ULL) | ((fieldA & 0xF00000000000ULL) << 4); + + if ((fieldA & 0xE0ULL) == 0xE0ULL) + // Opaque pixel, so set MSB to 1 and encode colors in RGB555 + tmp = tmp | 0x800000000000ULL | ((fieldA & 0xF8000000ULL) << 15) | ((fieldA & 0xF80000ULL) << 18) | ((fieldA & 0xF800ULL) << 21); + else + // Tranlucid pixel, so set MSB to 0 and encode colors in ARGB3444 + tmp = tmp | ((fieldA & 0xE0ULL) << 39) | ((fieldA & 0xF0000000ULL) << 12) | ((fieldA & 0xF00000ULL) << 16) | ((fieldA & 0xF000ULL) << 20); + + if ((fieldB & 0xE000000000ULL) == 0xE000000000ULL) + // Opaque pixel, so set MSB to 1 and encode colors in RGB555 + tmp = tmp | 0x80000000ULL | ((fieldB & 0xF800000000000000ULL) >> 33) | ((fieldB & 0xF8000000000000ULL) >> 30) | ((fieldB & 0xF80000000000ULL) >> 27); + else + // Tranlucid pixel, so set MSB to 0 and encode colors in ARGB3444 + tmp = tmp | ((fieldB & 0xE000000000ULL) >> 9) | ((fieldB & 0xF000000000000000ULL) >> 36) | ((fieldB & 0xF0000000000000ULL) >> 32) | ((fieldB & 0xF00000000000ULL) >> 28); + + if ((fieldB & 0xE0ULL) == 0xE0ULL) + // Opaque pixel, so set MSB to 1 and encode colors in RGB555 + tmp = tmp | 0x8000ULL | ((fieldB & 0xF8000000ULL) >> 17) | ((fieldB & 0xF80000ULL) >> 14) | ((fieldB & 0xF800ULL) >> 11); + else + // Tranlucid pixel, so set MSB to 0 and encode colors in ARGB3444 + tmp = tmp | ((fieldB & 0xE0ULL) << 7) | ((fieldB & 0xF0000000ULL) >> 20) | ((fieldB & 0xF00000ULL) >> 16) | ((fieldB & 0xF000ULL) >> 12); + ((PNGU_u64 *) buffer)[blockbase+2] = tmp; + + fieldA = *((PNGU_u64 *)(ctx->row_pointers[y*4+3]+x*16)); + fieldB = *((PNGU_u64 *)(ctx->row_pointers[y*4+3]+x*16+8)); + if ((fieldA & 0xE000000000ULL) == 0xE000000000ULL) + // Opaque pixel, so set MSB to 1 and encode colors in RGB555 + tmp = 0x8000000000000000ULL | ((fieldA & 0xF800000000000000ULL) >> 1) | ((fieldA & 0xF8000000000000ULL) << 2) | ((fieldA & 0xF80000000000ULL) << 5); + else + // Tranlucid pixel, so set MSB to 0 and encode colors in ARGB3444 + tmp = ((fieldA & 0xE000000000ULL) << 23) | ((fieldA & 0xF000000000000000ULL) >> 4) | (fieldA & 0xF0000000000000ULL) | ((fieldA & 0xF00000000000ULL) << 4); + + if ((fieldA & 0xE0ULL) == 0xE0ULL) + // Opaque pixel, so set MSB to 1 and encode colors in RGB555 + tmp = tmp | 0x800000000000ULL | ((fieldA & 0xF8000000ULL) << 15) | ((fieldA & 0xF80000ULL) << 18) | ((fieldA & 0xF800ULL) << 21); + else + // Tranlucid pixel, so set MSB to 0 and encode colors in ARGB3444 + tmp = tmp | ((fieldA & 0xE0ULL) << 39) | ((fieldA & 0xF0000000ULL) << 12) | ((fieldA & 0xF00000ULL) << 16) | ((fieldA & 0xF000ULL) << 20); + + if ((fieldB & 0xE000000000ULL) == 0xE000000000ULL) + // Opaque pixel, so set MSB to 1 and encode colors in RGB555 + tmp = tmp | 0x80000000ULL | ((fieldB & 0xF800000000000000ULL) >> 33) | ((fieldB & 0xF8000000000000ULL) >> 30) | ((fieldB & 0xF80000000000ULL) >> 27); + else + // Tranlucid pixel, so set MSB to 0 and encode colors in ARGB3444 + tmp = tmp | ((fieldB & 0xE000000000ULL) >> 9) | ((fieldB & 0xF000000000000000ULL) >> 36) | ((fieldB & 0xF0000000000000ULL) >> 32) | ((fieldB & 0xF00000000000ULL) >> 28); + + if ((fieldB & 0xE0ULL) == 0xE0ULL) + // Opaque pixel, so set MSB to 1 and encode colors in RGB555 + tmp = tmp | 0x8000ULL | ((fieldB & 0xF8000000ULL) >> 17) | ((fieldB & 0xF80000ULL) >> 14) | ((fieldB & 0xF800ULL) >> 11); + else + // Tranlucid pixel, so set MSB to 0 and encode colors in ARGB3444 + tmp = tmp | ((fieldB & 0xE0ULL) << 7) | ((fieldB & 0xF0000000ULL) >> 20) | ((fieldB & 0xF00000ULL) >> 16) | ((fieldB & 0xF000ULL) >> 12); + ((PNGU_u64 *) buffer)[blockbase+3] = tmp; + } + } + else + { + // No alpha channel present, copy image to the output buffer + default_alpha = (default_alpha >> 5); + if (default_alpha == 7) + { + // The user wants an opaque texture, so set MSB to 1 and encode colors in RGB555 + alphaMask = 0x8000800080008000ULL; + + for (y = 0; y < qheight; y++) + for (x = 0; x < qwidth; x++) + { + int blockbase = (y * qwidth + x) * 4; + + PNGU_u64 field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4]+x*12)); + PNGU_u64 field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase] = + alphaMask | ((field64 & 0xF800000000000000ULL) >> 1) | ((field64 & 0xF8000000000000ULL) << 2) | + ((field64 & 0xF80000000000ULL) << 5) | ((field64 & 0xF800000000ULL) << 7) | ((field64 & 0xF8000000ULL) << 10) | + ((field64 & 0xF80000ULL) << 13) | ((field64 & 0xF800ULL) << 15) | ((field64 & 0xF8ULL) << 18) | + ((field32 & 0xF8000000ULL) >> 11) | ((field32 & 0xF80000ULL) >> 9) | ((field32 & 0xF800ULL) >> 6) | ((field32 & 0xF8ULL) >> 3); + + field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+1]+x*12)); + field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+1]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase+1] = + alphaMask | ((field64 & 0xF800000000000000ULL) >> 1) | ((field64 & 0xF8000000000000ULL) << 2) | + ((field64 & 0xF80000000000ULL) << 5) | ((field64 & 0xF800000000ULL) << 7) | ((field64 & 0xF8000000ULL) << 10) | + ((field64 & 0xF80000ULL) << 13) | ((field64 & 0xF800ULL) << 15) | ((field64 & 0xF8ULL) << 18) | + ((field32 & 0xF8000000ULL) >> 11) | ((field32 & 0xF80000ULL) >> 9) | ((field32 & 0xF800ULL) >> 6) | ((field32 & 0xF8ULL) >> 3); + + field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+2]+x*12)); + field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+2]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase+2] = + alphaMask | ((field64 & 0xF800000000000000ULL) >> 1) | ((field64 & 0xF8000000000000ULL) << 2) | + ((field64 & 0xF80000000000ULL) << 5) | ((field64 & 0xF800000000ULL) << 7) | ((field64 & 0xF8000000ULL) << 10) | + ((field64 & 0xF80000ULL) << 13) | ((field64 & 0xF800ULL) << 15) | ((field64 & 0xF8ULL) << 18) | + ((field32 & 0xF8000000ULL) >> 11) | ((field32 & 0xF80000ULL) >> 9) | ((field32 & 0xF800ULL) >> 6) | ((field32 & 0xF8ULL) >> 3); + + field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+3]+x*12)); + field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+3]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase+3] = + alphaMask | ((field64 & 0xF800000000000000ULL) >> 1) | ((field64 & 0xF8000000000000ULL) << 2) | + ((field64 & 0xF80000000000ULL) << 5) | ((field64 & 0xF800000000ULL) << 7) | ((field64 & 0xF8000000ULL) << 10) | + ((field64 & 0xF80000ULL) << 13) | ((field64 & 0xF800ULL) << 15) | ((field64 & 0xF8ULL) << 18) | + ((field32 & 0xF8000000ULL) >> 11) | ((field32 & 0xF80000ULL) >> 9) | ((field32 & 0xF800ULL) >> 6) | ((field32 & 0xF8ULL) >> 3); + } + } + else + { + // The user wants a translucid texture, so set MSB to 0 and encode colors in ARGB3444 + default_alpha = (default_alpha << 4); + alphaMask = (((PNGU_u64) default_alpha) << 56) | (((PNGU_u64) default_alpha) << 40) | + (((PNGU_u64) default_alpha) << 24) | (((PNGU_u64) default_alpha) << 8); + + for (y = 0; y < qheight; y++) + for (x = 0; x < qwidth; x++) + { + int blockbase = (y * qwidth + x) * 4; + + PNGU_u64 field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4]+x*12)); + PNGU_u64 field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase] = + alphaMask | ((field64 & 0xF000000000000000ULL) >> 4) | (field64 & 0xF0000000000000ULL) | ((field64 & 0xF00000000000ULL) << 4) | + ((field64 & 0xF000000000ULL) << 4) | ((field64 & 0xF0000000ULL) << 8) | ((field64 & 0xF00000ULL) << 12) | + ((field64 & 0xF000ULL) << 12) | ((field64 & 0xF0ULL) << 16) | ((field32 & 0xF0000000ULL) >> 12) | + ((field32 & 0xF00000ULL) >> 12) | ((field32 & 0xF000ULL) >> 8) | ((field32 & 0xF0ULL) >> 4); + + field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+1]+x*12)); + field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+1]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase+1] = + alphaMask | ((field64 & 0xF000000000000000ULL) >> 4) | (field64 & 0xF0000000000000ULL) | ((field64 & 0xF00000000000ULL) << 4) | + ((field64 & 0xF000000000ULL) << 4) | ((field64 & 0xF0000000ULL) << 8) | ((field64 & 0xF00000ULL) << 12) | + ((field64 & 0xF000ULL) << 12) | ((field64 & 0xF0ULL) << 16) | ((field32 & 0xF0000000ULL) >> 12) | + ((field32 & 0xF00000ULL) >> 12) | ((field32 & 0xF000ULL) >> 8) | ((field32 & 0xF0ULL) >> 4); + + field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+2]+x*12)); + field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+2]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase+2] = + alphaMask | ((field64 & 0xF000000000000000ULL) >> 4) | (field64 & 0xF0000000000000ULL) | ((field64 & 0xF00000000000ULL) << 4) | + ((field64 & 0xF000000000ULL) << 4) | ((field64 & 0xF0000000ULL) << 8) | ((field64 & 0xF00000ULL) << 12) | + ((field64 & 0xF000ULL) << 12) | ((field64 & 0xF0ULL) << 16) | ((field32 & 0xF0000000ULL) >> 12) | + ((field32 & 0xF00000ULL) >> 12) | ((field32 & 0xF000ULL) >> 8) | ((field32 & 0xF0ULL) >> 4); + + field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+3]+x*12)); + field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+3]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase+3] = + alphaMask | ((field64 & 0xF000000000000000ULL) >> 4) | (field64 & 0xF0000000000000ULL) | ((field64 & 0xF00000000000ULL) << 4) | + ((field64 & 0xF000000000ULL) << 4) | ((field64 & 0xF0000000ULL) << 8) | ((field64 & 0xF00000ULL) << 12) | + ((field64 & 0xF000ULL) << 12) | ((field64 & 0xF0ULL) << 16) | ((field32 & 0xF0000000ULL) >> 12) | + ((field32 & 0xF00000ULL) >> 12) | ((field32 & 0xF000ULL) >> 8) | ((field32 & 0xF0ULL) >> 4); + } + } + } + + // Free resources + free (ctx->img_data); + free (ctx->row_pointers); + + // Success + return PNGU_OK; +} + + +int PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u8 default_alpha) +{ + int result; + PNGU_u32 x, y, qwidth, qheight; + PNGU_u64 alphaMask; + + // width and height need to be divisible by four + if ((width % 4) || (height % 4)) + return PNGU_INVALID_WIDTH_OR_HEIGHT; + + result = pngu_decode (ctx, width, height, 0); + if (result != PNGU_OK) + return result; + + // Init some variables + qwidth = width / 4; + qheight = height / 4; + + // Check is source image has an alpha channel + if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA) ) + { + // Alpha channel present, copy image to the output buffer + for (y = 0; y < qheight; y++) + for (x = 0; x < qwidth; x++) + { + int blockbase = (y * qwidth + x) * 8; + + PNGU_u64 fieldA = *((PNGU_u64 *)(ctx->row_pointers[y*4]+x*16)); + PNGU_u64 fieldB = *((PNGU_u64 *)(ctx->row_pointers[y*4]+x*16+8)); + ((PNGU_u64 *) buffer)[blockbase] = + ((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) | + ((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) | + ((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) | + ((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24); + ((PNGU_u64 *) buffer)[blockbase+4] = + ((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) | + ((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8); + + fieldA = *((PNGU_u64 *)(ctx->row_pointers[y*4+1]+x*16)); + fieldB = *((PNGU_u64 *)(ctx->row_pointers[y*4+1]+x*16+8)); + ((PNGU_u64 *) buffer)[blockbase+1] = + ((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) | + ((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) | + ((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) | + ((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24); + ((PNGU_u64 *) buffer)[blockbase+5] = + ((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) | + ((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8); + + fieldA = *((PNGU_u64 *)(ctx->row_pointers[y*4+2]+x*16)); + fieldB = *((PNGU_u64 *)(ctx->row_pointers[y*4+2]+x*16+8)); + ((PNGU_u64 *) buffer)[blockbase+2] = + ((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) | + ((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) | + ((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) | + ((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24); + ((PNGU_u64 *) buffer)[blockbase+6] = + ((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) | + ((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8); + + fieldA = *((PNGU_u64 *)(ctx->row_pointers[y*4+3]+x*16)); + fieldB = *((PNGU_u64 *)(ctx->row_pointers[y*4+3]+x*16+8)); + ((PNGU_u64 *) buffer)[blockbase+3] = + ((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) | + ((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) | + ((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) | + ((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24); + ((PNGU_u64 *) buffer)[blockbase+7] = + ((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) | + ((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8); + } + } + else + { + // No alpha channel present, copy image to the output buffer + alphaMask = (((PNGU_u64)default_alpha) << 56) | (((PNGU_u64)default_alpha) << 40) | + (((PNGU_u64)default_alpha) << 24) | (((PNGU_u64)default_alpha) << 8); + + for (y = 0; y < qheight; y++) + for (x = 0; x < qwidth; x++) + { + int blockbase = (y * qwidth + x) * 8; + + PNGU_u64 field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4]+x*12)); + PNGU_u64 field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase] = + (((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) | + ((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask); + ((PNGU_u64 *) buffer)[blockbase+4] = + (((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) | + ((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL)); + + field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+1]+x*12)); + field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+1]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase+1] = + (((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) | + ((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask); + ((PNGU_u64 *) buffer)[blockbase+5] = + (((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) | + ((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL)); + + field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+2]+x*12)); + field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+2]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase+2] = + (((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) | + ((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask); + ((PNGU_u64 *) buffer)[blockbase+6] = + (((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) | + ((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL)); + + field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+3]+x*12)); + field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+3]+x*12+8)); + ((PNGU_u64 *) buffer)[blockbase+3] = + (((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) | + ((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask); + ((PNGU_u64 *) buffer)[blockbase+7] = + (((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) | + ((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL)); + } + } + + // Free resources + free (ctx->img_data); + free (ctx->row_pointers); + + // Success + return PNGU_OK; +} + + +int PNGU_EncodeFromYCbYCr (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride) +{ + png_uint_32 rowbytes; + PNGU_u32 x, y, buffWidth; + + // Erase from the context any readed info + pngu_free_info (ctx); + ctx->propRead = 0; + + // Check if the user has selected a file to write the image + if (ctx->source == PNGU_SOURCE_BUFFER); + + else if (ctx->source == PNGU_SOURCE_DEVICE) + { + // Open file + if (!(ctx->fd = fopen (ctx->filename, "wb"))) + return PNGU_CANT_OPEN_FILE; + } + + else + return PNGU_NO_FILE_SELECTED; + + // Allocation of libpng structs + ctx->png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!(ctx->png_ptr)) + { + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + ctx->info_ptr = png_create_info_struct (ctx->png_ptr); + if (!(ctx->info_ptr)) + { + png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + if (ctx->source == PNGU_SOURCE_BUFFER) + { + // Installation of our custom data writer function + ctx->cursor = 0; + png_set_write_fn (ctx->png_ptr, ctx, pngu_write_data_to_buffer, pngu_flush_data_to_buffer); + } + else if (ctx->source == PNGU_SOURCE_DEVICE) + { + // Default data writer uses function fwrite, so it needs to use our FILE* + png_init_io (ctx->png_ptr, ctx->fd); + } + + // Setup output file properties + png_set_IHDR (ctx->png_ptr, ctx->info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + // Allocate memory to store the image in RGB format + rowbytes = width * 3; + if (rowbytes % 4) + rowbytes = ((rowbytes / 4) + 1) * 4; // Add extra padding so each row starts in a 4 byte boundary + + ctx->img_data = malloc (rowbytes * height); + if (!ctx->img_data) + { + png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + ctx->row_pointers = malloc (sizeof (png_bytep) * height); + if (!ctx->row_pointers) + { + png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + // Encode YCbYCr image into RGB8 format + buffWidth = (width + stride) / 2; + for (y = 0; y < height; y++) + { + ctx->row_pointers[y] = ctx->img_data + (y * rowbytes); + + for (x = 0; x < (width / 2); x++) + PNGU_YCbYCr_TO_RGB8 ( ((PNGU_u32 *)buffer)[y*buffWidth+x], + ((PNGU_u8 *) ctx->row_pointers[y]+x*6), ((PNGU_u8 *) ctx->row_pointers[y]+x*6+1), + ((PNGU_u8 *) ctx->row_pointers[y]+x*6+2), ((PNGU_u8 *) ctx->row_pointers[y]+x*6+3), + ((PNGU_u8 *) ctx->row_pointers[y]+x*6+4), ((PNGU_u8 *) ctx->row_pointers[y]+x*6+5) ); + } + + // Tell libpng where is our image data + png_set_rows (ctx->png_ptr, ctx->info_ptr, ctx->row_pointers); + + // Write file header and image data + png_write_png (ctx->png_ptr, ctx->info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + // Tell libpng we have no more data to write + png_write_end (ctx->png_ptr, (png_infop) NULL); + + // Free resources + free (ctx->img_data); + free (ctx->row_pointers); + png_destroy_write_struct (&(ctx->png_ptr), &(ctx->info_ptr)); + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + + // Success + return PNGU_OK; +} + + +// This function is taken from a libogc example +PNGU_u32 PNGU_RGB8_TO_YCbYCr (PNGU_u8 r1, PNGU_u8 g1, PNGU_u8 b1, PNGU_u8 r2, PNGU_u8 g2, PNGU_u8 b2) +{ + int y1, cb1, cr1, y2, cb2, cr2, cb, cr; + + y1 = (299 * r1 + 587 * g1 + 114 * b1) / 1000; + cb1 = (-16874 * r1 - 33126 * g1 + 50000 * b1 + 12800000) / 100000; + cr1 = (50000 * r1 - 41869 * g1 - 8131 * b1 + 12800000) / 100000; + + y2 = (299 * r2 + 587 * g2 + 114 * b2) / 1000; + cb2 = (-16874 * r2 - 33126 * g2 + 50000 * b2 + 12800000) / 100000; + cr2 = (50000 * r2 - 41869 * g2 - 8131 * b2 + 12800000) / 100000; + + cb = (cb1 + cb2) >> 1; + cr = (cr1 + cr2) >> 1; + + return (PNGU_u32) ((y1 << 24) | (cb << 16) | (y2 << 8) | cr); +} + + +void PNGU_YCbYCr_TO_RGB8 (PNGU_u32 ycbycr, PNGU_u8 *r1, PNGU_u8 *g1, PNGU_u8 *b1, PNGU_u8 *r2, PNGU_u8 *g2, PNGU_u8 *b2) +{ + PNGU_u8 *val = (PNGU_u8 *) &ycbycr; + int r, g, b; + + r = 1.371f * (val[3] - 128); + g = - 0.698f * (val[3] - 128) - 0.336f * (val[1] - 128); + b = 1.732f * (val[1] - 128); + + *r1 = pngu_clamp (val[0] + r, 0, 255); + *g1 = pngu_clamp (val[0] + g, 0, 255); + *b1 = pngu_clamp (val[0] + b, 0, 255); + + *r2 = pngu_clamp (val[2] + r, 0, 255); + *g2 = pngu_clamp (val[2] + g, 0, 255); + *b2 = pngu_clamp (val[2] + b, 0, 255); +} + + +int pngu_info (IMGCTX ctx) +{ + png_byte magic[8]; + png_uint_32 width; + png_uint_32 height; + png_color_16p background; + png_bytep trans; + png_color_16p trans_values; + int scale, i; + + // Check if there is a file selected and if it is a valid .png + if (ctx->source == PNGU_SOURCE_BUFFER) + memcpy (magic, ctx->buffer, 8); + + else if (ctx->source == PNGU_SOURCE_DEVICE) + { + // Open file + if (!(ctx->fd = fopen (ctx->filename, "rb"))) + return PNGU_CANT_OPEN_FILE; + + // Load first 8 bytes into magic buffer + if (fread (magic, 1, 8, ctx->fd) != 8) + { + fclose (ctx->fd); + return PNGU_CANT_READ_FILE; + } + } + + else + return PNGU_NO_FILE_SELECTED;; + + if (png_sig_cmp(magic, 0, 8) != 0) + { + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_FILE_IS_NOT_PNG; + } + + // Allocation of libpng structs + ctx->png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!(ctx->png_ptr)) + { + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + return PNGU_LIB_ERROR; + } + + ctx->info_ptr = png_create_info_struct (ctx->png_ptr); + if (!(ctx->info_ptr)) + { + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + png_destroy_read_struct (&(ctx->png_ptr), (png_infopp)NULL, (png_infopp)NULL); + return PNGU_LIB_ERROR; + } + + if (ctx->source == PNGU_SOURCE_BUFFER) + { + // Installation of our custom data provider function + ctx->cursor = 0; + png_set_read_fn (ctx->png_ptr, ctx, pngu_read_data_from_buffer); + } + else if (ctx->source == PNGU_SOURCE_DEVICE) + { + // Default data provider uses function fread, so it needs to use our FILE* + png_init_io (ctx->png_ptr, ctx->fd); + png_set_sig_bytes (ctx->png_ptr, 8); // We have read 8 bytes already to check PNG authenticity + } + + // Read png header + png_read_info (ctx->png_ptr, ctx->info_ptr); + + // Query image properties if they have not been queried before + if (!ctx->propRead) + { + png_get_IHDR(ctx->png_ptr, ctx->info_ptr, &width, &height, + (int *) &(ctx->prop.imgBitDepth), + (int *) &(ctx->prop.imgColorType), + NULL, NULL, NULL); + + ctx->prop.imgWidth = width; + ctx->prop.imgHeight = height; + switch (ctx->prop.imgColorType) + { + case PNG_COLOR_TYPE_GRAY: + ctx->prop.imgColorType = PNGU_COLOR_TYPE_GRAY; + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + ctx->prop.imgColorType = PNGU_COLOR_TYPE_GRAY_ALPHA; + break; + case PNG_COLOR_TYPE_PALETTE: + ctx->prop.imgColorType = PNGU_COLOR_TYPE_PALETTE; + break; + case PNG_COLOR_TYPE_RGB: + ctx->prop.imgColorType = PNGU_COLOR_TYPE_RGB; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + ctx->prop.imgColorType = PNGU_COLOR_TYPE_RGB_ALPHA; + break; + default: + ctx->prop.imgColorType = PNGU_COLOR_TYPE_UNKNOWN; + break; + } + + // Constant used to scale 16 bit values to 8 bit values + scale = 1; + if (ctx->prop.imgBitDepth == 16) + scale = 256; + + // Query background color, if any. + ctx->prop.validBckgrnd = 0; + if (((ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA)) && + (png_get_bKGD (ctx->png_ptr, ctx->info_ptr, &background))) + { + ctx->prop.validBckgrnd = 1; + ctx->prop.bckgrnd.r = background->red / scale; + ctx->prop.bckgrnd.g = background->green / scale; + ctx->prop.bckgrnd.b = background->blue / scale; + } + else if (((ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA)) && + (png_get_bKGD (ctx->png_ptr, ctx->info_ptr, &background))) + { + ctx->prop.validBckgrnd = 1; + ctx->prop.bckgrnd.r = ctx->prop.bckgrnd.g = ctx->prop.bckgrnd.b = background->gray / scale; + } + + // Query list of transparent colors, if any. + ctx->prop.numTrans = 0; + ctx->prop.trans = NULL; + if (((ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA)) && + (png_get_tRNS (ctx->png_ptr, ctx->info_ptr, &trans, (int *) &(ctx->prop.numTrans), &trans_values))) + { + if (ctx->prop.numTrans) + { + ctx->prop.trans = malloc (sizeof (PNGUCOLOR) * ctx->prop.numTrans); + if (ctx->prop.trans) + for (i = 0; i < ctx->prop.numTrans; i++) + { + ctx->prop.trans[i].r = trans_values[i].red / scale; + ctx->prop.trans[i].g = trans_values[i].green / scale; + ctx->prop.trans[i].b = trans_values[i].blue / scale; + } + else + ctx->prop.numTrans = 0; + } + } + else if (((ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA)) && + (png_get_tRNS (ctx->png_ptr, ctx->info_ptr, &trans, (int *) &(ctx->prop.numTrans), &trans_values))) + { + if (ctx->prop.numTrans) + { + ctx->prop.trans = malloc (sizeof (PNGUCOLOR) * ctx->prop.numTrans); + if (ctx->prop.trans) + for (i = 0; i < ctx->prop.numTrans; i++) + ctx->prop.trans[i].r = ctx->prop.trans[i].g = ctx->prop.trans[i].b = + trans_values[i].gray / scale; + else + ctx->prop.numTrans = 0; + } + } + + ctx->propRead = 1; + } + + // Success + ctx->infoRead = 1; + + return PNGU_OK; +} + + +int pngu_decode (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stripAlpha) +{ + png_uint_32 rowbytes; + int i; + + // Read info if it hasn't been read before + if (!ctx->infoRead) + { + i = pngu_info (ctx); + if (i != PNGU_OK) + return i; + } + + // Check if the user has specified the real width and height of the image + if ( (ctx->prop.imgWidth != width) || (ctx->prop.imgHeight != height) ) + return PNGU_INVALID_WIDTH_OR_HEIGHT; + + // Check if color type is supported by PNGU + if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_PALETTE) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_UNKNOWN) ) + return PNGU_UNSUPPORTED_COLOR_TYPE; + + // Scale 16 bit samples to 8 bit + if (ctx->prop.imgBitDepth == 16) + png_set_strip_16 (ctx->png_ptr); + + // Remove alpha channel if we don't need it + if (stripAlpha && ((ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA))) + png_set_strip_alpha (ctx->png_ptr); + + // Expand 1, 2 and 4 bit samples to 8 bit + if (ctx->prop.imgBitDepth < 8) + png_set_packing (ctx->png_ptr); + + // Transform grayscale images to RGB + if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA) ) + png_set_gray_to_rgb (ctx->png_ptr); + + // Flush transformations + png_read_update_info (ctx->png_ptr, ctx->info_ptr); + + // Allocate memory to store the image + rowbytes = png_get_rowbytes (ctx->png_ptr, ctx->info_ptr); + if (rowbytes % 4) + rowbytes = ((rowbytes / 4) + 1) * 4; // Add extra padding so each row starts in a 4 byte boundary + + ctx->img_data = malloc (rowbytes * ctx->prop.imgHeight); + if (!ctx->img_data) + { + pngu_free_info (ctx); + return PNGU_LIB_ERROR; + } + + ctx->row_pointers = malloc (sizeof (png_bytep) * ctx->prop.imgHeight); + if (!ctx->row_pointers) + { + free (ctx->img_data); + pngu_free_info (ctx); + return PNGU_LIB_ERROR; + } + + for (i = 0; i < ctx->prop.imgHeight; i++) + ctx->row_pointers[i] = ctx->img_data + (i * rowbytes); + + // Transform the image and copy it to our allocated memory + png_read_image (ctx->png_ptr, ctx->row_pointers); + + // Free resources + pngu_free_info (ctx); + + // Success + return PNGU_OK; +} + + +void pngu_free_info (IMGCTX ctx) +{ + if (ctx->infoRead) + { + if (ctx->source == PNGU_SOURCE_DEVICE) + fclose (ctx->fd); + + png_destroy_read_struct (&(ctx->png_ptr), &(ctx->info_ptr), (png_infopp)NULL); + + ctx->infoRead = 0; + } +} + + +// Custom data provider function used for reading from memory buffers. +void pngu_read_data_from_buffer (png_structp png_ptr, png_bytep data, png_size_t length) +{ + IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr); + memcpy (data, ctx->buffer + ctx->cursor, length); + ctx->cursor += length; +} + + +// Custom data writer function used for writing to memory buffers. +void pngu_write_data_to_buffer (png_structp png_ptr, png_bytep data, png_size_t length) +{ + IMGCTX ctx = (IMGCTX) png_get_io_ptr (png_ptr); + memcpy (ctx->buffer + ctx->cursor, data, length); + ctx->cursor += length; +} + + +// Custom data flusher function used for writing to memory buffers. +void pngu_flush_data_to_buffer (png_structp png_ptr) +{ + // Nothing to do here +} + + +// Function used in YCbYCr to RGB decoding +int pngu_clamp (int value, int min, int max) +{ + if (value < min) + value = min; + else if (value > max) + value = max; + + return value; +} + diff --git a/source.en/libpng/pngu/pngu.h b/source.en/libpng/pngu/pngu.h new file mode 100644 index 0000000..12c3ad4 --- /dev/null +++ b/source.en/libpng/pngu/pngu.h @@ -0,0 +1,171 @@ +/******************************************************************************************** + +PNGU Version : 0.2a + +Coder : frontier + +More info : http://frontier-dev.net + +********************************************************************************************/ +#ifndef __PNGU__ +#define __PNGU__ + +// Return codes +#define PNGU_OK 0 +#define PNGU_ODD_WIDTH 1 +#define PNGU_ODD_STRIDE 2 +#define PNGU_INVALID_WIDTH_OR_HEIGHT 3 +#define PNGU_FILE_IS_NOT_PNG 4 +#define PNGU_UNSUPPORTED_COLOR_TYPE 5 +#define PNGU_NO_FILE_SELECTED 6 +#define PNGU_CANT_OPEN_FILE 7 +#define PNGU_CANT_READ_FILE 8 +#define PNGU_LIB_ERROR 9 + +// Color types +#define PNGU_COLOR_TYPE_GRAY 1 +#define PNGU_COLOR_TYPE_GRAY_ALPHA 2 +#define PNGU_COLOR_TYPE_PALETTE 3 +#define PNGU_COLOR_TYPE_RGB 4 +#define PNGU_COLOR_TYPE_RGB_ALPHA 5 +#define PNGU_COLOR_TYPE_UNKNOWN 6 + + +#ifdef __cplusplus + extern "C" { +#endif + +// Types +typedef unsigned char PNGU_u8; +typedef unsigned short PNGU_u16; +typedef unsigned int PNGU_u32; +typedef unsigned long long PNGU_u64; + +typedef struct +{ + PNGU_u8 r; + PNGU_u8 g; + PNGU_u8 b; +} PNGUCOLOR; + +typedef struct +{ + PNGU_u32 imgWidth; // In pixels + PNGU_u32 imgHeight; // In pixels + PNGU_u32 imgBitDepth; // In bitx + PNGU_u32 imgColorType; // PNGU_COLOR_TYPE_* + PNGU_u32 validBckgrnd; // Non zero if there is a background color + PNGUCOLOR bckgrnd; // Backgroun color + PNGU_u32 numTrans; // Number of transparent colors + PNGUCOLOR *trans; // Transparent colors +} PNGUPROP; + +// Image context, always initialize with SelectImageFrom* and free with ReleaseImageContext +struct _IMGCTX; +typedef struct _IMGCTX *IMGCTX; + + +/**************************************************************************** +* Pixel conversion * +****************************************************************************/ + +// Macro to convert RGB8 values to RGB565 +#define PNGU_RGB8_TO_RGB565(r,g,b) ( ((((PNGU_u16) r) & 0xF8U) << 8) | ((((PNGU_u16) g) & 0xFCU) << 3) | (((PNGU_u16) b) >> 3) ) + +// Macro to convert RGBA8 values to RGB5A3 +#define PNGU_RGB8_TO_RGB5A3(r,g,b,a) (PNGU_u16) (((a & 0xE0U) == 0xE0U) ? \ + (0x8000U | ((((PNGU_u16) r) & 0xF8U) << 7) | ((((PNGU_u16) g) & 0xF8U) << 2) | (((PNGU_u16) b) >> 3)) : \ + (((((PNGU_u16) a) & 0xE0U) << 7) | ((((PNGU_u16) r) & 0xF0U) << 4) | (((PNGU_u16) g) & 0xF0U) | ((((PNGU_u16) b) & 0xF0U) >> 4))) + +// Function to convert two RGB8 values to YCbYCr +PNGU_u32 PNGU_RGB8_TO_YCbYCr (PNGU_u8 r1, PNGU_u8 g1, PNGU_u8 b1, PNGU_u8 r2, PNGU_u8 g2, PNGU_u8 b2); + +// Function to convert an YCbYCr to two RGB8 values. +void PNGU_YCbYCr_TO_RGB8 (PNGU_u32 ycbycr, PNGU_u8 *r1, PNGU_u8 *g1, PNGU_u8 *b1, PNGU_u8 *r2, PNGU_u8 *g2, PNGU_u8 *b2); + + +/**************************************************************************** +* Image context handling * +****************************************************************************/ + +// Selects a PNG file, previosly loaded into a buffer, and creates an image context for subsequent procesing. +IMGCTX PNGU_SelectImageFromBuffer (const void *buffer); + +// Selects a PNG file, from any devoptab device, and creates an image context for subsequent procesing. +IMGCTX PNGU_SelectImageFromDevice (const char *filename); + +// Frees resources associated with an image context. Always call this function when you no longer need the IMGCTX. +void PNGU_ReleaseImageContext (IMGCTX ctx); + + +/**************************************************************************** +* Miscelaneous * +****************************************************************************/ + +// Retrieves info from selected PNG file, including image dimensions, color format, background and transparency colors. +int PNGU_GetImageProperties (IMGCTX ctx, PNGUPROP *fileproperties); + + +/**************************************************************************** +* Image conversion * +****************************************************************************/ + +// Expands selected image into an YCbYCr buffer. You need to specify context, image dimensions, +// destination address and stride in pixels (stride = buffer width - image width). +int PNGU_DecodeToYCbYCr (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride); + +// Macro for decoding an image inside a buffer at given coordinates. +#define PNGU_DECODE_TO_COORDS_YCbYCr(ctx,coordX,coordY,imgWidth,imgHeight,bufferWidth,bufferHeight,buffer) \ + \ + PNGU_DecodeToYCbYCr (ctx, imgWidth, imgHeight, ((void *) buffer) + (coordY) * (bufferWidth) * 2 + \ + (coordX) * 2, (bufferWidth) - (imgWidth)) + +// Expands selected image into a linear RGB565 buffer. You need to specify context, image dimensions, +// destination address and stride in pixels (stride = buffer width - image width). +int PNGU_DecodeToRGB565 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride); + +// Macro for decoding an image inside a buffer at given coordinates. +#define PNGU_DECODE_TO_COORDS_RGB565(ctx,coordX,coordY,imgWidth,imgHeight,bufferWidth,bufferHeight,buffer) \ + \ + PNGU_DecodeToRGB565 (ctx, imgWidth, imgHeight, ((void *) buffer) + (coordY) * (bufferWidth) * 2 + \ + (coordX) * 2, (bufferWidth) - (imgWidth)) + +// Expands selected image into a linear RGBA8 buffer. You need to specify context, image dimensions, +// destination address, stride in pixels and default alpha value, which is used if the source image +// doesn't have an alpha channel. +int PNGU_DecodeToRGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride, PNGU_u8 default_alpha); + +// Macro for decoding an image inside a buffer at given coordinates. +#define PNGU_DECODE_TO_COORDS_RGBA8(ctx,coordX,coordY,imgWidth,imgHeight,default_alpha,bufferWidth,bufferHeight,buffer) \ + \ + PNGU_DecodeToRGBA8 (ctx, imgWidth, imgHeight, ((void *) buffer) + (coordY) * (bufferWidth) * 2 + \ + (coordX) * 2, (bufferWidth) - (imgWidth), default_alpha) + +// Expands selected image into a 4x4 tiled RGB565 buffer. You need to specify context, image dimensions +// and destination address. +int PNGU_DecodeTo4x4RGB565 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer); + +// Expands selected image into a 4x4 tiled RGB5A3 buffer. You need to specify context, image dimensions, +// destination address and default alpha value, which is used if the source image doesn't have an alpha channel. +int PNGU_DecodeTo4x4RGB5A3 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u8 default_alpha); + +// Expands selected image into a 4x4 tiled RGBA8 buffer. You need to specify context, image dimensions, +// destination address and default alpha value, which is used if the source image doesn't have an alpha channel. +int PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u8 default_alpha); + +// Encodes an YCbYCr image in PNG format and stores it in the selected device or memory buffer. You need to +// specify context, image dimensions, destination address and stride in pixels (stride = buffer width - image width). +int PNGU_EncodeFromYCbYCr (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride); + +// Macro for encoding an image stored into an YCbYCr buffer at given coordinates. +#define PNGU_ENCODE_TO_COORDS_YCbYCr(ctx,coordX,coordY,imgWidth,imgHeight,bufferWidth,bufferHeight,buffer) \ + \ + PNGU_EncodeFromYCbYCr (ctx, imgWidth, imgHeight, ((void *) buffer) + (coordY) * (bufferWidth) * 2 + \ + (coordX) * 2, (bufferWidth) - (imgWidth)) + +#ifdef __cplusplus + } +#endif + +#endif + diff --git a/source.en/menu.c b/source.en/menu.c new file mode 100644 index 0000000..f6ff148 --- /dev/null +++ b/source.en/menu.c @@ -0,0 +1,1478 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sys.h" +#include "fat.h" +#include "nand.h" +#include "restart.h" +#include "title.h" +#include "usbstorage.h" +#include "utils.h" +#include "video.h" +#include "wad.h" +#include "wpad.h" +#include +#include "globals.h" + + + +/* FAT device list */ +//static fatDevice fdevList[] = { +fatDevice fdevList[] = { + { "sd", "SD Card", &__io_wiisd }, + { "usb", "USB Storage", &__io_usbstorage }, + { "usb2", "USB2.0 Storage", &__io_wiiums }, + { "gcsda", "SD Gecko (Slot A)", &__io_gcsda }, + { "gcsdb", "SD Gecko (Slot B)", &__io_gcsdb }, + //{ "smb", "SMB share", NULL }, +}; + +/* NAND device list */ +//static nandDevice ndevList[] = { +nandDevice ndevList[] = { + { "Disabled", 0, 0x00, 0x00 }, + { "SD/SDHC Card", 1, 0xF0, 0xF1 }, + { "USB2.0 Device", 2, 0xF2, 0xF3 }, +}; + +/* FAT device */ +static fatDevice *fdev = NULL; +static nandDevice *ndev = NULL; + +// wiiNinja: Define a buffer holding the previous path names as user +// traverses the directory tree. Max of 10 levels is define at this point +static u8 gDirLevel = 0; +static char gDirList [MAX_DIR_LEVELS][MAX_FILE_PATH_LEN]; +static s32 gSeleted[MAX_DIR_LEVELS]; +static s32 gStart[MAX_DIR_LEVELS]; + +/* Macros */ +#define NB_FAT_DEVICES (sizeof(fdevList) / sizeof(fatDevice)) +#define NB_NAND_DEVICES (sizeof(ndevList) / sizeof(nandDevice)) + +// Local prototypes: wiiNinja +void WaitPrompt (char *prompt); +int PushCurrentDir(char *dirStr, s32 Selected, s32 Start); +char *PopCurrentDir(s32 *Selected, s32 *Start); +bool IsListFull (void); +char *PeekCurrentDir (void); +u32 WaitButtons(void); +u32 Pad_GetButtons(void); +void WiiLightControl (int state); + +s32 __Menu_IsGreater(const void *p1, const void *p2) +{ + u32 n1 = *(u32 *)p1; + u32 n2 = *(u32 *)p2; + + /* Equal */ + if (n1 == n2) + return 0; + + return (n1 > n2) ? 1 : -1; +} + + +s32 __Menu_EntryCmp(const void *p1, const void *p2) +{ + fatFile *f1 = (fatFile *)p1; + fatFile *f2 = (fatFile *)p2; + + /* Compare entries */ // wiiNinja: Include directory + if ((f1->entry.d_type==DT_DIR) && !(f2->entry.d_type==DT_DIR)) + return (-1); + else if (!(f1->entry.d_type==DT_DIR) && (f2->entry.d_type==DT_DIR)) + return (1); + else + return strcmp(f1->filename, f2->filename); +} + +char gFileName[MAX_FILE_PATH_LEN]; +s32 __Menu_RetrieveList(char *inPath, fatFile **outbuf, u32 *outlen) +{ + fatFile *buffer = NULL; + DIR *dir = NULL; + + struct dirent *entry; + + //struct stat filestat; + + //char dirpath[256], filename[768]; + u32 cnt = 0; + + /* Generate dirpath */ + //sprintf(dirpath, "%s:" WAD_DIRECTORY, fdev->mount); + + /* Open directory */ + dir = opendir(inPath); + if (!dir) + return -1; + + while ((entry = readdir(dir))) { + cnt++; + } + + /* Count entries */ + /*for (cnt = 0; !dirnext(dir, gFileName, &filestat);) { + // if (!(filestat.st_mode & S_IFDIR)) // wiiNinja + cnt++; + }*/ + + if (cnt > 0) { + /* Allocate memory */ + buffer = malloc(sizeof(fatFile) * cnt); + if (!buffer) { + closedir(dir); + return -2; + } + + /* Reset directory */ + //dirreset(dir); + closedir(dir); + dir = opendir(inPath); + + /* Get entries */ + for (cnt = 0; (entry = readdir(dir));) + { + bool addFlag = false; + + if (entry->d_type==DT_DIR) + { + // Add only the item ".." which is the previous directory + // AND if we're not at the root directory + if ((strcmp (entry->d_name, "..") == 0) && (gDirLevel > 1)) + addFlag = true; + else if (strcmp (entry->d_name, ".") != 0) + addFlag = true; + } + else + { + if(strlen(entry->d_name)>4) + { + if(!stricmp(entry->d_name+strlen(entry->d_name)-4, ".wad")) + addFlag = true; + } + } + + if (addFlag == true) + { + fatFile *file = &buffer[cnt++]; + + /* File name */ + strcpy(file->filename, entry->d_name); + + /* File stats */ + file->entry = *entry; + } + } + + /* Sort list */ + qsort(buffer, cnt, sizeof(fatFile), __Menu_EntryCmp); + } + + /* Close directory */ + closedir(dir); + + /* Set values */ + *outbuf = buffer; + *outlen = cnt; + + return 0; +} + + +void Menu_SelectIOS(void) +{ + u8 *iosVersion = NULL; + u32 iosCnt; + u8 tmpVersion; + + u32 cnt; + s32 ret, selected = 0; + bool found = false; + + /* Get IOS versions */ + ret = Title_GetIOSVersions(&iosVersion, &iosCnt); + if (ret < 0) + return; + + /* Sort list */ + qsort(iosVersion, iosCnt, sizeof(u8), __Menu_IsGreater); + + if (gConfig.cIOSVersion < 0) + tmpVersion = CIOS_VERSION; + else + { + tmpVersion = (u8)gConfig.cIOSVersion; + // For debugging only + //printf ("User pre-selected cIOS: %i\n", tmpVersion); + //WaitButtons(); + } + + /* Set default version */ + for (cnt = 0; cnt < iosCnt; cnt++) { + u8 version = iosVersion[cnt]; + + /* Custom IOS available */ + //if (version == CIOS_VERSION) + if (version == tmpVersion) + { + selected = cnt; + found = true; + break; + } + + /* Current IOS */ + if (version == IOS_GetVersion()) + selected = cnt; + } + + /* Ask user for IOS version */ + if ((gConfig.cIOSVersion < 0) || (found == false)) + { + for (;;) + { + /* Clear console */ + Con_Clear(); + + printf("\t>> Select what IOS to use: < IOS%d >\n\n", iosVersion[selected]); + + printf("\t Press LEFT/RIGHT to change the IOS\n\n"); + + printf("\t Press [A] to continue.\n"); + printf("\t Press [HOME] to exit.\n"); + + u32 buttons = WaitButtons(); + + /* LEFT/RIGHT buttons */ + if (buttons & WPAD_BUTTON_LEFT) { + if ((--selected) <= -1) + selected = (iosCnt - 1); + } + if (buttons & WPAD_BUTTON_RIGHT) { + if ((++selected) >= iosCnt) + selected = 0; + } + + /* HOME button */ + if (buttons & WPAD_BUTTON_HOME) + Restart(); + + /* A button */ + if (buttons & WPAD_BUTTON_A) + break; + } + } + + + u8 version = iosVersion[selected]; + + if (IOS_GetVersion() != version) { + /* Shutdown subsystems */ + Wpad_Disconnect(); + //mload_close(); + + /* Load IOS */ + + if(!loadIOS(version)) Wpad_Init(), Menu_SelectIOS(); + + /* Initialize subsystems */ + Wpad_Init(); + } +} + +void Menu_FatDevice(void) +{ + s32 ret, selected = 0; + + /* Unmount FAT device */ + //if (fdev) + //Fat_Unmount(fdev); + //if (((fdevList[selected].mount[0] == 's') && (ndev->name[0] == 'S'))) + //selected++; + + /* Select source device */ + if (gConfig.fatDeviceIndex < 0) + { + for (;;) { + /* Clear console */ + Con_Clear(); + + /* Selected device */ + fdev = &fdevList[selected]; + + printf("\t>> Select the WAD location: < %s >\n\n", fdev->name); + + printf("\t Press LEFT/RIGHT to change the location.\n\n"); + + printf("\t Press [A] to continue.\n"); + printf("\t Press [HOME] to exit.\n\n"); + + u32 buttons = WaitButtons(); + + /* LEFT/RIGHT buttons */ + if (buttons & WPAD_BUTTON_LEFT) { + if ((--selected) <= -1) + selected = (NB_FAT_DEVICES - 1); + if ((fdevList[selected].mount[0] == 's') && (ndev->name[0] == 'S')) + selected--; + if ((fdevList[selected].mount[0] == 'u' && fdevList[selected].mount[3] == '2') && (ndev->name[0] == 'U')) + selected--; + if ((selected) <= -1) + selected = (NB_FAT_DEVICES - 1); + } + if (buttons & WPAD_BUTTON_RIGHT) { + if ((++selected) >= NB_FAT_DEVICES) + selected = 0; + if ((fdevList[selected].mount[0] == 's') && (ndev->name[0] == 'S')) + selected++; + if ((fdevList[selected].mount[0] == 'u' && fdevList[selected].mount[3] == '2') && (ndev->name[0] == 'U')) + selected++; + } + + /* HOME button */ + if (buttons & WPAD_BUTTON_HOME) + Restart(); + + /* A button */ + if (buttons & WPAD_BUTTON_A) + break; + } + } + else + { + sleep(5); + fdev = &fdevList[gConfig.fatDeviceIndex]; + } + + printf("[+] Loading %s device, please wait...", fdev->name); + fflush(stdout); + + /* Mount FAT device */ + + ret = Fat_Mount(fdev); + if (ret < 0) { + printf("\n ERROR! (ret = %d)\n", ret); + goto err; + } else + printf("\n Success!\n"); + + return; + +err: + + if(gConfig.fatDeviceIndex >= 0) gConfig.fatDeviceIndex = -1; + WiiLightControl (WII_LIGHT_OFF); + printf("\n"); + printf(" Press any key to continue...\n"); + + WaitButtons(); + + /* Prompt menu again */ + Menu_FatDevice(); +} + +void Menu_NandDevice(void) +{ + s32 ret, selected = 0; + + /* Disable NAND emulator */ + if (ndev) { + Nand_Unmount(ndev); + Nand_Disable(); + } + + /* Select source device */ + if (gConfig.nandDeviceIndex < 0) + { + for (;;) { + /* Clear console */ + Con_Clear(); + + /* Selected device */ + ndev = &ndevList[selected]; + + printf("\t>> Select NAND-Emulation device: < %s >\n\n", ndev->name); + + printf("\t Press LEFT/RIGHT to change the device.\n\n"); + + printf("\t Press [A] to continue.\n"); + printf("\t Press [HOME] to exit.\n\n"); + + u32 buttons = WaitButtons(); + + /* LEFT/RIGHT buttons */ + if (buttons & WPAD_BUTTON_LEFT) { + if ((--selected) <= -1) + selected = (NB_NAND_DEVICES - 1); + } + if (buttons & WPAD_BUTTON_RIGHT) { + if ((++selected) >= NB_NAND_DEVICES) + selected = 0; + } + + /* HOME button */ + if (buttons & WPAD_BUTTON_HOME) + Restart(); + + /* A button */ + if (buttons & WPAD_BUTTON_A) + break; + } + } + else + { + ndev = &ndevList[gConfig.nandDeviceIndex]; + } + + /* No NAND device */ + if (!ndev->mode) + return; + + printf("[+] Enabling NAND-Emulation..."); + fflush(stdout); + + /* Mount NAND device */ + ret = Nand_Mount(ndev); + if (ret < 0) { + printf("\n ERROR! (ret = %d)\n", ret); + goto err; + } + + /* Enable NAND emulator */ + ret = Nand_Enable(ndev); + if (ret < 0) { + printf("\n ERROR! (ret = %d)\n", ret); + goto err; + } else + printf("\n Success!\n"); + + return; + +err: + printf("\n"); + printf(" Press any key to continue...\n"); + + WaitButtons(); + + /* Prompt menu again */ + Menu_NandDevice(); +} + +char gTmpFilePath[MAX_FILE_PATH_LEN]; +/* Install and/or Uninstall multiple WADs - Leathl */ +int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath, int installCnt, int uninstallCnt) +{ + int count; + + for (;;) + { + Con_Clear(); + + if ((installCnt > 0) & (uninstallCnt == 0)) { + printf("[+] %d file%s selected for installation.\n\n", installCnt, (installCnt == 1) ? "" : "s"); + printf(" Do you want to continue?\n"); + } + else if ((installCnt == 0) & (uninstallCnt > 0)) { + printf("[+] %d file%s selected for uninstallation.\n\n", uninstallCnt, (uninstallCnt == 1) ? "" : "s"); + printf(" Do you want to continue?\n"); + } + else { + printf("[+] %d file%s selected for installation.\n\n", installCnt, (installCnt == 1) ? "" : "s"); + printf(" %d file%s selected for uninstallation.\n\n", uninstallCnt, (uninstallCnt == 1) ? "" : "s"); + printf(" Do you want to continue?\n"); + } + + printf("\t Press [A] to continue.\n"); + printf("\t Press [HOME] to exit.\n"); + + u32 buttons = WaitButtons(); + + if (buttons & WPAD_BUTTON_A) + break; + + if (buttons & WPAD_BUTTON_B) + return 0; + } + + WiiLightControl (WII_LIGHT_ON); + int errors = 0; + int success = 0; + s32 ret; + + for (count = 0; count < fileCount; count++) + { + fatFile *thisFile = &files[count]; + + if ((thisFile->install == 1) | (thisFile->install == 2)) { + int mode = thisFile->install; + Con_Clear(); + printf("[+] Opening \"%s\", please wait...", thisFile->filename); + + sprintf(gTmpFilePath, "%s/%s", inFilePath, thisFile->filename); + + FILE *fp = fopen(gTmpFilePath, "rb"); + if (!fp) + { + printf("\n ERROR!\n"); + errors += 1; + continue; + } + + printf("[+] %s WAD, please wait...\n", (mode == 2) ? "Uninstalling" : "Installing"); + if (mode == 2) + ret = Wad_Uninstall(fp); + else + ret = Wad_Install(fp, thisFile); + + if (ret < 0) errors += 1; + else success += 1; + + thisFile->installstate = ret; + + if (fp) + fclose(fp); + } + } + + WiiLightControl (WII_LIGHT_OFF); + + printf("\n"); + printf(" %d file(s) successfully installed and %d failed...\n", success, errors); + + if (errors > 0) + { + printf("\n Not all files were successfully installed"); + printf("\n Press [A] to view list.\n"); + printf(" Press [B] to skip list.\n"); + + u32 buttons = WaitButtons(); + + if ((buttons & WPAD_BUTTON_A)) + { + Con_Clear(); + + int i=0; + for (count = 0; count < fileCount; count++) + { + fatFile *thisFile = &files[count]; + + if (thisFile->installstate <0) + { + char str[41]; + strncpy(str, thisFile->filename, 40); //Only 40 chars to fit the screen + str[40]=0; + i++; + if(thisFile->installstate == -999) printf(" %s BRICK BLOCKED\n", str); + else if(thisFile->installstate == -998) printf(" %s skipped\n", str); + else if(thisFile->installstate == -106) printf(" %s not installed?\n", str); + else if(thisFile->installstate == -1036 ) printf(" %s missing needed IOS\n", str); + else if(thisFile->installstate == -4100 ) printf(" %s no trucha bug?\n", str); + else printf(" %s error %d\n", str, thisFile->installstate); + if( i == 17 ) + { + printf("\n Press any key to continue...\n"); + WaitButtons(); + i = 0; + } + } + } + } + } + printf("\n Press any key to continue...\n"); + WaitButtons(); + + return 1; +} + +/* File Operations - Leathl */ +int Menu_FileOperations(fatFile *file, char *inFilePath) +{ + //f32 filesize = (file->filestat.st_size / MB_SIZE); + + for (;;) + { + Con_Clear(); + + printf("[+] WAD filename : %s\n", file->filename); + //printf(" WAD-Dateigr%csse : %.2f MB\n\n",148, filesize); + + + printf("[+] Choose action: < %s WAD >\n\n", "delete"); //There's yet nothing else than delete + + printf(" Press LEFT/RIGHT to change action.\n\n"); + + printf(" Press [A] to continue.\n"); + printf(" Press [B] for the file browser.\n"); + + u32 buttons = WaitButtons(); + + /* A button */ + if (buttons & WPAD_BUTTON_A) + break; + + /* B button */ + if (buttons & WPAD_BUTTON_B) + return 0; + } + + Con_Clear(); + + printf("[+] Deleting \"%s\", please wait...\n", file->filename); + + sprintf(gTmpFilePath, "%s/%s", inFilePath, file->filename); + int error = remove(gTmpFilePath); + if (error != 0) + printf(" FEHLER!"); + else + printf(" Successfully deleted!"); + + printf("\n"); + printf(" Press any key to continue...\n"); + + WaitButtons(); + + return !error; +} + +void Menu_WadEdit(fatFile *file) +{ + /******************************************************************************************/ + // ios liste + /******************************************************************************************/ + u8 *iosVersion = NULL; + u32 iosCnt; + + u32 cnt; + s32 ret, ios_selected = 0; + + /* Get IOS versions */ + ret = Title_GetIOSVersions(&iosVersion, &iosCnt); + if (ret < 0) + return; + + /* Sort list */ + qsort(iosVersion, iosCnt, sizeof(u8), __Menu_IsGreater); + + /* Set default version */ + for (cnt = 0; cnt < iosCnt; cnt++) + { + u8 version = iosVersion[cnt]; + + /* Channel IOS */ + if (version == file->new_ios) + { + ios_selected = cnt; + break; + } + + /* Current IOS */ + if (version == IOS_GetVersion()) + ios_selected = cnt; + } + /******************************************************************************************/ + + int selected = 0; + bool ahbprot = file->new_ahbprot; + bool pass = file->new_pass; + char ios_text[30]; + + while(1) + { + /* Clear console */ + Con_Clear(); + + if(iosVersion[ios_selected] == 58) + sprintf(ios_text, "(USB2, recommended)"); + else + ios_text[0] = '\0'; + + printf("[+] Advanced Settings\n\n"); + + printf("%2s Launch-IOS of the channel: %i %s\n", (selected == 0) ? ">>" : " ", iosVersion[ios_selected], ios_text); + printf("%2s AHBPROT enabled: %s\n", (selected == 1) ? ">>" : " ", (!ahbprot) ? "No" : "Yes"); + printf("%2s Age restriction: %s\n\n", (selected == 2) ? ">>" : " ", (!pass) ? "No" : "Yes"); + + printf(" Press LEFT/RIGHT to change setting.\n\n"); + + Con_FgColor(1, 1); + printf(" NOTE: Channels or applications with IOS=RELOAD,\n will disable the AHBPROT flag.\n\n"); + + Con_FgColor(7, 1); + printf(" Press the [A] button to save.\n"); + printf(" Press the [B] button to abort.\n\n"); + + u32 buttons = Wpad_WaitButtons(); + + /* UP button */ + if (buttons & WPAD_BUTTON_UP && selected > 0) + selected--; + + /* DOWN button */ + if (buttons & WPAD_BUTTON_DOWN && selected < 2) + selected++; + + /* LEFT/RIGHT buttons */ + if (buttons & (WPAD_BUTTON_LEFT | WPAD_BUTTON_RIGHT)) + { + if(selected == 0) + { + if(buttons & WPAD_BUTTON_LEFT && --ios_selected <= -1) + ios_selected = (iosCnt - 1); + + else if(buttons & WPAD_BUTTON_RIGHT && ++ios_selected >= iosCnt) + ios_selected = 0; + } + + else if(selected == 1) + ahbprot ^= 1; + + else if(selected == 2) + pass ^= 1; + } + + /* A button */ + if (buttons & WPAD_BUTTON_A) + break; + + /* B button */ + if (buttons & WPAD_BUTTON_B) + return; + } + + printf(" saved\n\n"); + file->new_ios = iosVersion[ios_selected]; + file->new_ahbprot = ahbprot; + file->new_pass = pass; + + /* Wait for button */ + printf(" Press any button to continue...\n"); + Wpad_WaitButtons(); +} + +void Menu_WadManage(fatFile *file, char *inFilePath) +{ + FILE *fp = NULL; + + //char filepath[128]; + //f32 filesize = 0; + u32 mode = 0; + + /* File size in megabytes */ + //filesize = (file->filestat.st_size / MB_SIZE); + + for (;;) { + /* Clear console */ + Con_Clear(); + + printf("[+] WAD-Filename : %s\n", file->filename); + //printf(" WAD-Size : %.2f MB\n\n",148, filesize); + + + printf("[+] Select operation: < %s WAD >\n\n", (!mode) ? "Install" : "Uninstall"); + + printf(" Press left/right to select the operation.\n\n"); + + printf(" Press the [A] button to continue.\n"); + printf(" Press the [B] button to return to the file selection.\n"); + if(file->new_ios) + printf(" Press the (1) button to enter the advanced settings."); + + u32 buttons = WaitButtons(); + + /* LEFT/RIGHT buttons */ + if (buttons & (WPAD_BUTTON_LEFT | WPAD_BUTTON_RIGHT)) + mode ^= 1; + + /* A button */ + if (buttons & WPAD_BUTTON_A) + break; + + /* B button */ + if (buttons & WPAD_BUTTON_B) + return; + + /* 1 button */ + if (buttons & WPAD_BUTTON_1 && file->new_ios) + Menu_WadEdit(file); + } + + /* Clear console */ + Con_Clear(); + + printf("[+] Opening \"%s\", please wait...", file->filename); + fflush(stdout); + + /* Generate filepath */ + // sprintf(filepath, "%s:" WAD_DIRECTORY "/%s", fdev->mount, file->filename); + sprintf(gTmpFilePath, "%s/%s", inFilePath, file->filename); // wiiNinja + + /* Open WAD */ + fp = fopen(gTmpFilePath, "rb"); + if (!fp) + { + printf(" ERROR!\n"); + goto out; + } + else + printf(" OK!\n\n"); + + printf("[+] %s the WAD, please wait...\n", (!mode) ? "Installing" : "Uninstalling"); + + /* Do install/uninstall */ + WiiLightControl (WII_LIGHT_ON); + if (!mode) + Wad_Install(fp, file); + else + Wad_Uninstall(fp); + WiiLightControl (WII_LIGHT_OFF); + +out: + /* Close file */ + if (fp) + fclose(fp); + + printf("\n"); + printf(" Press any button to continue...\n"); + + /* Wait for button */ + WaitButtons(); +} + +void Menu_WadList(void) +{ + char str [100]; + fatFile *fileList = NULL; + u32 fileCnt; + s32 ret, selected = 0, start = 0; + char *tmpPath = malloc (MAX_FILE_PATH_LEN); + int installCnt = 0; + int uninstallCnt = 0; + + //fatFile *installFiles = malloc(sizeof(fatFile) * 50); + //int installCount = 0; + + // wiiNinja: check for malloc error + if (tmpPath == NULL) + { + printf(" ERROR while reading the directory!"); + return; + } + + printf("[+] Creating file list..."); + fflush(stdout); + + gDirLevel = 0; + + // wiiNinja: The root is always the primary folder + // But if the user has a /wad directory, just go there. This makes + // both sides of the argument win + sprintf(tmpPath, "%s:" WAD_DIRECTORY, fdev->mount); + PushCurrentDir(tmpPath,0,0); + //if (strcmp (WAD_DIRECTORY, WAD_ROOT_DIRECTORY) != 0) + if (strcmp (WAD_DIRECTORY, gConfig.startupPath) != 0) + { + // If the directory can be successfully opened, it must exists + //DIR_ITER *tmpDirPtr = NULL; + //tmpDirPtr = diropen(WAD_ROOT_DIRECTORY); + //if (tmpDirPtr) + //{ + // dirclose (tmpDirPtr); + + // Now push the /wad directory as the current operating folder + //sprintf(tmpPath, "%s:" WAD_ROOT_DIRECTORY, fdev->mount); + sprintf(tmpPath, "%s:%s", fdev->mount, gConfig.startupPath); + //printf ("\nThe final startupPath is: %s\n", tmpPath); + //WaitButtons (); + PushCurrentDir(tmpPath,0,0); // wiiNinja + //} + } + + /* Retrieve filelist */ +getList: + if (fileList) + { + free (fileList); + fileList = NULL; + } + + ret = __Menu_RetrieveList(tmpPath, &fileList, &fileCnt); + if (ret < 0) { + printf(" ERROR! (ret = %d)\n", ret); + goto err; + } + + /* No files */ + if (!fileCnt) { + printf(" Directory is empty!\n"); + goto err; + } + + /* Set install-values to 0 - Leathl */ + int counter; + for (counter = 0; counter < fileCnt; counter++) { + fatFile *file = &fileList[counter]; + file->install = 0; + + sprintf(gTmpFilePath, "%s/%s", tmpPath, file->filename); + if (file->entry.d_type==DT_REG) + Wad_Read(fopen(gTmpFilePath, "r"), &file->old_ios, &file->old_ahbprot, &file->old_pass, &file->high_id, &file->low_id); + + file->new_ios = file->old_ios; + file->new_ahbprot = file->old_ahbprot; + file->new_pass = file->old_pass; + } + + for (;;) + { + u32 cnt; + s32 index; + + /* Clear console */ + Con_Clear(); + + /** Print entries **/ + cnt = strlen(tmpPath); + if(cnt>26) + index = cnt-26; + else + index = 0; + + printf("[+] WAD files in [%s]:", tmpPath+index); + Con_FgColor(2, 1); + printf("\x1b[0;48H"); + printf("IOS HW Pass\n\n"); + Con_FgColor(7, 1); + + /* Print entries */ + for (cnt = start; cnt < fileCnt; cnt++) + { + fatFile *file = &fileList[cnt]; + + // zeile markieren + if(cnt == selected) + Con_BgColor(6, 0); + else + Con_BgColor(0, 0); + + /* Entries per page limit */ + if ((cnt - start) >= ENTRIES_PER_PAGE) + break; + + strncpy(str, file->filename, 40); //Only 40 chars to fit the screen + str[40]=0; + + /* Print filename */ + if (file->entry.d_type==DT_DIR) // wiiNinja + printf(" %2s %-42s (DIRECTORY) \n", (cnt == selected) ? ">>" : " ", str); + else if(file->new_ios) + printf(" %2s%s %-42s %-4i %-6s %-6s\n", (cnt == selected) ? ">>" : " ", (file->install == 1) ? "+" : ((file->install == 2) ? "-" : " "), str, file->new_ios, (file->new_ahbprot) ? "Yes" : "No", (file->new_pass) ? "Yes" : "No"); + else + printf(" %2s%s %-61s\n", (cnt == selected) ? ">>" : " ", (file->install == 1) ? "+" : ((file->install == 2) ? "-" : " "), str); + } + + Con_BgColor(0, 0); + Con_FgColor(2, 1); + printf("\n IOS = Channel IOS | HW = HW_AHBPROT | Pass = Age restriction\n"); + Con_FgColor(7, 1); + printf(" Press the [A] button to open the selected WAD/directory.\n"); + if(gDirLevel>1) + printf(" Press the [B] button to leave the current directory.\n"); + else + printf(" Press the [B] button to return to the device selection.\n"); + printf(" Press the (1) button to enter the advanced settings.\n"); + printf(" Press the +/- button to select/deselect a file."); + + /** Controls **/ + u32 buttons = WaitButtons(); + + /* DPAD buttons */ + if (buttons & (WPAD_BUTTON_UP | WPAD_BUTTON_LEFT)) + { + selected -= (buttons & WPAD_BUTTON_LEFT) ? ENTRIES_PER_PAGE : 1; + + if (selected <= -1) + selected = (fileCnt - 1); + } + if (buttons & (WPAD_BUTTON_DOWN | WPAD_BUTTON_RIGHT)) + { + selected += (buttons & WPAD_BUTTON_RIGHT) ? ENTRIES_PER_PAGE : 1; + + if (selected >= fileCnt) + selected = 0; + } + + /* HOME button */ + if (buttons & WPAD_BUTTON_HOME) + Restart(); + + /* Plus Button - Leathl */ + if (buttons & WPAD_BUTTON_PLUS) + { + if(Wpad_TimeButton()) + { + installCnt = 0; + int i = 0; + while( i < fileCnt) + { + fatFile *file = &fileList[i]; + if (((file->entry.d_type==DT_DIR) == false) & (file->install == 0)) { + file->install = 1; + + installCnt += 1; + } + else if (((file->entry.d_type==DT_DIR) == false) & (file->install == 1)) { + file->install = 0; + + installCnt -= 1; + } + else if (((file->entry.d_type==DT_DIR) == false) & (file->install == 2)) { + file->install = 1; + + installCnt += 1; + uninstallCnt -= 1; + } + i++; + } + + } + else + { + fatFile *file = &fileList[selected]; + if (((file->entry.d_type==DT_DIR) == false) & (file->install == 0)) { + file->install = 1; + + installCnt += 1; + } + else if (((file->entry.d_type==DT_DIR) == false) & (file->install == 1)) { + file->install = 0; + + installCnt -= 1; + } + else if (((file->entry.d_type==DT_DIR) == false) & (file->install == 2)) { + file->install = 1; + + installCnt += 1; + uninstallCnt -= 1; + } + selected++; + + if (selected >= fileCnt) + selected = 0; + } + } + + /* Minus Button - Leathl */ + if (buttons & WPAD_BUTTON_MINUS) + { + + if(Wpad_TimeButton()) + { + installCnt = 0; + int i = 0; + while( i < fileCnt) + { + fatFile *file = &fileList[i]; + if (((file->entry.d_type==DT_DIR) == false) & (file->install == 0)) { + file->install = 2; + + uninstallCnt += 1; + } + else if (((file->entry.d_type==DT_DIR) == false) & (file->install == 1)) { + file->install = 2; + + uninstallCnt += 1; + installCnt -= 1; + } + else if (((file->entry.d_type==DT_DIR) == false) & (file->install == 2)) { + file->install = 0; + + uninstallCnt -= 1; + } + i++; + } + + } + else + { + fatFile *file = &fileList[selected]; + if (((file->entry.d_type==DT_DIR) == false) & (file->install == 0)) { + file->install = 2; + + uninstallCnt += 1; + } + else if (((file->entry.d_type==DT_DIR) == false) & (file->install == 1)) { + file->install = 2; + + uninstallCnt += 1; + installCnt -= 1; + } + else if (((file->entry.d_type==DT_DIR) == false) & (file->install == 2)) { + file->install = 0; + + uninstallCnt -= 1; + } + selected++; + + if (selected >= fileCnt) + selected = 0; + } + } + + /* 1 Button - Leathl */ + if (buttons & WPAD_BUTTON_1) + { + fatFile *tmpFile = &fileList[selected]; + if(tmpFile->new_ios) + { + char *tmpCurPath = PeekCurrentDir (); + if (tmpCurPath != NULL) { + Menu_WadEdit(tmpFile); + // int res = Menu_FileOperations(tmpFile, tmpCurPath); + // if (res != 0) + // goto getList; + } + } + } + + + /* A button */ + if (buttons & WPAD_BUTTON_A) + { + fatFile *tmpFile = &fileList[selected]; + char *tmpCurPath; + if (tmpFile->entry.d_type==DT_DIR) // wiiNinja + { + if (strcmp (tmpFile->filename, "..") == 0) + { + selected = 0; + start = 0; + + // Previous dir + tmpCurPath = PopCurrentDir(&selected, &start); + if (tmpCurPath != NULL) + sprintf(tmpPath, "%s", tmpCurPath); + + installCnt = 0; + uninstallCnt = 0; + + goto getList; + } + else if (IsListFull () == true) + { + WaitPrompt ("Maximale Anzahl an Unterordnern erreicht.\n"); + } + else + { + tmpCurPath = PeekCurrentDir (); + if (tmpCurPath != NULL) + { + if(gDirLevel>1) + sprintf(tmpPath, "%s/%s", tmpCurPath, tmpFile->filename); + else + sprintf(tmpPath, "%s%s", tmpCurPath, tmpFile->filename); + } + // wiiNinja: Need to PopCurrentDir + PushCurrentDir (tmpPath, selected, start); + selected = 0; + start = 0; + + installCnt = 0; + uninstallCnt = 0; + + goto getList; + } + } + else + { + //If at least one WAD is marked, goto batch screen - Leathl + if ((installCnt > 0) | (uninstallCnt > 0)) { + char *thisCurPath = PeekCurrentDir (); + if (thisCurPath != NULL) { + int res = Menu_BatchProcessWads(fileList, fileCnt, thisCurPath, installCnt, uninstallCnt); + + if (res == 1) { + int counter; + for (counter = 0; counter < fileCnt; counter++) { + fatFile *temp = &fileList[counter]; + temp->install = 0; + } + + installCnt = 0; + uninstallCnt = 0; + } + } + } + //else use standard wadmanage menu - Leathl + else { + tmpCurPath = PeekCurrentDir (); + if (tmpCurPath != NULL) + Menu_WadManage(tmpFile, tmpCurPath); + } + } + } + + /* B button */ + if (buttons & WPAD_BUTTON_B) + { + if(gDirLevel<=1) + { + return; + } + + char *tmpCurPath; + selected = 0; + start = 0; + // Previous dir + tmpCurPath = PopCurrentDir(&selected, &start); + if (tmpCurPath != NULL) + sprintf(tmpPath, "%s", tmpCurPath); + goto getList; + //return; + } + + /** Scrolling **/ + /* List scrolling */ + index = (selected - start); + + if (index >= ENTRIES_PER_PAGE) + start += index - (ENTRIES_PER_PAGE - 1); + if (index <= -1) + start += index; + } + +err: + printf("\n"); + printf(" Press any button to continue...\n"); + + free (tmpPath); + + /* Wait for button */ + WaitButtons(); +} + + +void Menu_Loop(void) +{ + u8 iosVersion; + + /* Select IOS menu */ + if (AHBPROT_DISABLED) + { + + u32 mode = 0; + while(1) + { + /* Clear console */ + Con_Clear(); + printf(" HW_AHBPROT is disabled\n"); + printf(" Do you want to load another IOS anyways?: < %s >\n\n", (!mode) ? "No" : "Yes"); + printf(" Press the [A] button to continue.\n"); + printf(" Press the [HOME] button to quit.\n"); + u32 buttons = WaitButtons(); + /* LEFT/RIGHT buttons */ + if (buttons & (WPAD_BUTTON_LEFT | WPAD_BUTTON_RIGHT)) + mode ^= 1; + + /* HOME button */ + if (buttons & WPAD_BUTTON_HOME) + Restart(); + + /* A button */ + if (buttons & WPAD_BUTTON_A) + break; + } + + if(mode) + Menu_SelectIOS(); + } + else + Menu_SelectIOS(); + + /* Retrieve IOS version */ + iosVersion = IOS_GetVersion(); + + ndev = &ndevList[0]; + + /* NAND device menu */ + if ((iosVersion == CIOS_VERSION || iosVersion == 250) && IOS_GetRevision() >13) + { + Menu_NandDevice(); + } + for (;;) { + /* FAT device menu */ + Menu_FatDevice(); + + /* WAD list menu */ + Menu_WadList(); + } +} + +// Start of wiiNinja's added routines + +int PushCurrentDir (char *dirStr, s32 Selected, s32 Start) +{ + int retval = 0; + + // Store dirStr into the list and increment the gDirLevel + // WARNING: Make sure dirStr is no larger than MAX_FILE_PATH_LEN + if (gDirLevel < MAX_DIR_LEVELS) + { + strcpy (gDirList [gDirLevel], dirStr); + gSeleted[gDirLevel]=Selected; + gStart[gDirLevel]=Start; + gDirLevel++; + //if (gDirLevel >= MAX_DIR_LEVELS) + // gDirLevel = 0; + } + else + retval = -1; + + return (retval); +} + +char *PopCurrentDir(s32 *Selected, s32 *Start) +{ + if (gDirLevel > 1) + gDirLevel--; + else + gDirLevel = 0; + + *Selected = gSeleted[gDirLevel]; + *Start = gStart[gDirLevel]; + return PeekCurrentDir(); +} + +bool IsListFull (void) +{ + if (gDirLevel < MAX_DIR_LEVELS) + return (false); + else + return (true); +} + +char *PeekCurrentDir (void) +{ + // Return the current path + if (gDirLevel > 0) + return (gDirList [gDirLevel-1]); + else + return (NULL); +} + +void WaitPrompt (char *prompt) +{ + printf("\n%s", prompt); + printf(" Press any button to continue...\n"); + + /* Wait for button */ + WaitButtons(); +} + +u32 Pad_GetButtons(void) +{ + u32 buttons = 0, cnt; + + /* Scan pads */ + PAD_ScanPads(); + + /* Get pressed buttons */ + //for (cnt = 0; cnt < MAX_WIIMOTES; cnt++) + for (cnt = 0; cnt < 4; cnt++) + buttons |= PAD_ButtonsDown(cnt); + + return buttons; +} + + +// Routine to wait for a button from either the Wiimote or a gamecube +// controller. The return value will mimic the WPAD buttons to minimize +// the amount of changes to the original code, that is expecting only +// Wiimote button presses. Note that the "HOME" button on the Wiimote +// is mapped to the "SELECT" button on the Gamecube Ctrl. (wiiNinja 5/15/2009) +u32 WaitButtons(void) +{ + u32 buttons = 0; + u32 buttonsGC = 0; + + /* Wait for button pressing */ + while (!buttons && !buttonsGC) + { + // GC buttons + buttonsGC = Pad_GetButtons (); + + // Wii buttons + buttons = Wpad_GetButtons(); + + VIDEO_WaitVSync(); + } + + if (buttonsGC) + { + if(buttonsGC & PAD_BUTTON_A) + { + //printf ("Button A on the GC controller\n"); + buttons |= WPAD_BUTTON_A; + } + else if(buttonsGC & PAD_BUTTON_B) + { + //printf ("Button B on the GC controller\n"); + buttons |= WPAD_BUTTON_B; + } + else if(buttonsGC & PAD_BUTTON_LEFT) + { + //printf ("Button LEFT on the GC controller\n"); + buttons |= WPAD_BUTTON_LEFT; + } + else if(buttonsGC & PAD_BUTTON_RIGHT) + { + //printf ("Button RIGHT on the GC controller\n"); + buttons |= WPAD_BUTTON_RIGHT; + } + else if(buttonsGC & PAD_BUTTON_DOWN) + { + //printf ("Button DOWN on the GC controller\n"); + buttons |= WPAD_BUTTON_DOWN; + } + else if(buttonsGC & PAD_BUTTON_UP) + { + //printf ("Button UP on the GC controller\n"); + buttons |= WPAD_BUTTON_UP; + } + else if(buttonsGC & PAD_BUTTON_START) + { + //printf ("Button START on the GC controller\n"); + buttons |= WPAD_BUTTON_HOME; + } + } + + return buttons; +} // WaitButtons + + +void WiiLightControl (int state) +{ + switch (state) + { + case WII_LIGHT_ON: + /* Turn on Wii Light */ + WIILIGHT_SetLevel(255); + WIILIGHT_TurnOn(); + break; + + case WII_LIGHT_OFF: + default: + /* Turn off Wii Light */ + WIILIGHT_SetLevel(0); + WIILIGHT_TurnOn(); + WIILIGHT_Toggle(); + break; + } +} // WiiLightControl + diff --git a/source.en/menu.h b/source.en/menu.h new file mode 100644 index 0000000..92cd259 --- /dev/null +++ b/source.en/menu.h @@ -0,0 +1,8 @@ +#ifndef _MENU_H_ +#define _MENU_H_ + +/* Prototypes */ +void Menu_Loop(void); + +#endif + diff --git a/source.en/mload.c b/source.en/mload.c new file mode 100644 index 0000000..8b1bab4 --- /dev/null +++ b/source.en/mload.c @@ -0,0 +1,399 @@ +/* mload.c (for PPC) (c) 2009, Hermes + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "mload.h" + +static const char mload_fs[] ATTRIBUTE_ALIGN(32) = "/dev/mload"; + +static s32 mload_fd = -1; + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to init/test if the device is running + +int mload_init() +{ +int n; + + if(mload_fd>=0) return 0; + + for(n=0;n<10;n++) // try 2.5 seconds + { + mload_fd=IOS_Open(mload_fs, 0); + + if(mload_fd>=0) break; + + usleep(250*1000); + } + +return mload_fd; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to close the device (remember call it when rebooting the IOS!) + +int mload_close() +{ +int ret; + + if(mload_fd<0) return -1; + + ret=IOS_Close(mload_fd); + + mload_fd=-1; + +return ret; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to get the thread id of mload + +int mload_get_thread_id() +{ +int ret; +s32 hid = -1; + + + if(mload_init()<0) return -1; + + hid = iosCreateHeap(0x800); + + if(hid<0) return hid; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_MLOAD_THREAD_ID, ":"); + + + //iosDestroyHeap(hid); + +return ret; + +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// get the base and the size of the memory readable/writable to load modules + +int mload_get_load_base(u32 *starlet_base, int *size) +{ +int ret; +s32 hid = -1; + + + if(mload_init()<0) return -1; + + hid = iosCreateHeap(0x800); + + if(hid<0) return hid; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_GET_LOAD_BASE, ":ii",starlet_base, size); + + + //iosDestroyHeap(hid); + +return ret; + +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// load and run a module from starlet (it need to allocate MEM2 to send the elf file) +// the module must be a elf made with stripios + +int mload_module(void *addr, int len) +{ +int ret; +void *buf=NULL; +s32 hid = -1; + + if(mload_init()<0) return -1; + + hid = iosCreateHeap(len+0x800); + + if(hid<0) return hid; + + buf= iosAlloc(hid, len); + + if(!buf) {ret= -1;goto out;} + + + memcpy(buf, addr,len); + + ret = IOS_IoctlvFormat(hid, mload_fd, MLOAD_LOAD_MODULE, ":d", buf, len); + + if(ret<0) goto out; + + ret=IOS_IoctlvFormat(hid, mload_fd, MLOAD_RUN_MODULE, ":"); + + if(ret<0) {ret= -666;goto out;} + +out: + + //iosDestroyHeap(hid); + +return ret; + +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// load a module from the PPC +// the module must be a elf made with stripios + +int mload_elf(void *my_elf, data_elf *data_elf) +{ +int n,m; +int p; +u8 *adr; +u32 elf=(u32) my_elf; + +if(elf & 3) return -1; // aligned to 4 please! + +elfheader *head=(void *) elf; +elfphentry *entries; + +if(head->ident0!=0x7F454C46) return -1; +if(head->ident1!=0x01020161) return -1; +if(head->ident2!=0x01000000) return -1; + +p=head->phoff; + +data_elf->start=(void *) head->entry; + +for(n=0; nphnum; n++) + { + entries=(void *) (elf+p); + p+=sizeof(elfphentry); + + if(entries->type == 4) + { + adr=(void *) (elf + entries->offset); + + if(getbe32(0)!=0) return -2; // bad info (sure) + + for(m=4; m < entries->memsz; m+=8) + { + switch(getbe32(m)) + { + case 0x9: + data_elf->start= (void *) getbe32(m+4); + break; + case 0x7D: + data_elf->prio= getbe32(m+4); + break; + case 0x7E: + data_elf->size_stack= getbe32(m+4); + break; + case 0x7F: + data_elf->stack= (void *) (getbe32(m+4)); + break; + + } + + } + + } + else + if(entries->type == 1 && entries->memsz != 0 && entries->vaddr!=0) + { + + if(mload_memset((void *) entries->vaddr, 0, entries->memsz)<0) return -1; + if(mload_seek(entries->vaddr, SEEK_SET)<0) return -1; + if(mload_write((void *) (elf + entries->offset), entries->filesz)<0) return -1; + + } + } + +return 0; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// run one thread (you can use to load modules or binary files) + +int mload_run_thread(void *starlet_addr, void *starlet_top_stack, int stack_size, int priority) +{ +int ret; +s32 hid = -1; + + + if(mload_init()<0) return -1; + + hid = iosCreateHeap(0x800); + + if(hid<0) return hid; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_RUN_THREAD, "iiii:", starlet_addr,starlet_top_stack, stack_size, priority); + + + //iosDestroyHeap(hid); + +return ret; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// stops one starlet thread + +int mload_stop_thread(int id) +{ +int ret; +s32 hid = -1; + + + if(mload_init()<0) return -1; + + hid = iosCreateHeap(0x800); + + if(hid<0) return hid; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_STOP_THREAD, "i:", id); + + + //iosDestroyHeap(hid); + +return ret; + +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// continue one stopped starlet thread + +int mload_continue_thread(int id) +{ +int ret; +s32 hid = -1; + + + if(mload_init()<0) return -1; + + hid = iosCreateHeap(0x800); + + if(hid<0) return hid; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_CONTINUE_THREAD, "i:", id); + + + //iosDestroyHeap(hid); + +return ret; + +} +/*--------------------------------------------------------------------------------------------------------------*/ + +// fix starlet address to read/write (uses SEEK_SET, etc as mode) + +int mload_seek(int offset, int mode) +{ + if(mload_init()<0) return -1; + return IOS_Seek(mload_fd, offset, mode); +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// read bytes from starlet (it update the offset) + +int mload_read(void* buf, u32 size) +{ + if(mload_init()<0) return -1; + return IOS_Read(mload_fd, buf, size); +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// write bytes from starlet (it update the offset) + +int mload_write(const void * buf, u32 size) +{ + if(mload_init()<0) return -1; + return IOS_Write(mload_fd, buf, size); +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// fill a block (similar to memset) + +int mload_memset(void *starlet_addr, int set, int len) +{ +int ret; +s32 hid = -1; + + + if(mload_init()<0) return -1; + + hid = iosCreateHeap(0x800); + + if(hid<0) return hid; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_MEMSET, "iii:", starlet_addr, set, len); + + + //iosDestroyHeap(hid); + +return ret; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// get the ehci datas ( ehcmodule.elf uses this address) + +void * mload_get_ehci_data() +{ +int ret; +s32 hid = -1; + + + if(mload_init()<0) return NULL; + + hid = iosCreateHeap(0x800); + + if(hid<0) return NULL; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_GET_EHCI_DATA, ":"); + if(ret<0) return NULL; + + //iosDestroyHeap(hid); + +return (void *) ret; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +// set the dev/es ioctlv in routine + +int mload_set_ES_ioctlv_vector(void *starlet_addr) +{ +int ret; +s32 hid = -1; + + + if(mload_init()<0) return -1; + + hid = iosCreateHeap(0x800); + + if(hid<0) return hid; + + ret= IOS_IoctlvFormat(hid, mload_fd, MLOAD_SET_ES_IOCTLV, "i:", starlet_addr); + + + //iosDestroyHeap(hid); + +return ret; +} + diff --git a/source.en/mload.h b/source.en/mload.h new file mode 100644 index 0000000..b50eeb6 --- /dev/null +++ b/source.en/mload.h @@ -0,0 +1,194 @@ +/* mload.c (for PPC) (c) 2009, Hermes + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __MLOAD_H__ +#define __MLOAD_H__ + + +#include +#include +#include +#include +#include +#include "unistd.h" + +#define MLOAD_MLOAD_THREAD_ID 0x4D4C4400 +#define MLOAD_LOAD_MODULE 0x4D4C4480 +#define MLOAD_RUN_MODULE 0x4D4C4481 +#define MLOAD_RUN_THREAD 0x4D4C4482 + +#define MLOAD_STOP_THREAD 0x4D4C4484 +#define MLOAD_CONTINUE_THREAD 0x4D4C4485 + +#define MLOAD_GET_LOAD_BASE 0x4D4C4490 +#define MLOAD_MEMSET 0x4D4C4491 + +#define MLOAD_GET_EHCI_DATA 0x4D4C44A0 + +#define MLOAD_SET_ES_IOCTLV 0x4D4C44B0 + +#ifdef __cplusplus +extern "C" { +#endif + + +// from IOS ELF stripper of neimod + +#define getbe32(x) ((adr[x]<<24) | (adr[x+1]<<16) | (adr[x+2]<<8) | (adr[x+3])) + +typedef struct +{ + u32 ident0; + u32 ident1; + u32 ident2; + u32 ident3; + u32 machinetype; + u32 version; + u32 entry; + u32 phoff; + u32 shoff; + u32 flags; + u16 ehsize; + u16 phentsize; + u16 phnum; + u16 shentsize; + u16 shnum; + u16 shtrndx; +} elfheader; + +typedef struct +{ + u32 type; + u32 offset; + u32 vaddr; + u32 paddr; + u32 filesz; + u32 memsz; + u32 flags; + u32 align; +} elfphentry; + +typedef struct +{ + void *start; + int prio; + void *stack; + int size_stack; +} data_elf; + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to init/test if the device is running + +int mload_init(); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to close the device (remember call it when rebooting the IOS!) + +int mload_close(); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// to get the thread id of mload + +int mload_get_thread_id(); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// get the base and the size of the memory readable/writable to load modules + +int mload_get_load_base(u32 *starlet_base, int *size); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// load and run a module from starlet (it need to allocate MEM2 to send the elf file) +// the module must be a elf made with stripios + +int mload_module(void *addr, int len); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// load a module from the PPC +// the module must be a elf made with stripios + +int mload_elf(void *my_elf, data_elf *data_elf); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// run one thread (you can use to load modules or binary files) + +int mload_run_thread(void *starlet_addr, void *starlet_top_stack, int stack_size, int priority); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// stops one starlet thread + +int mload_stop_thread(int id); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// continue one stopped starlet thread + +int mload_continue_thread(int id); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// fix starlet address to read/write (uses SEEK_SET, etc as mode) + +int mload_seek(int offset, int mode); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// read bytes from starlet (it update the offset) + +int mload_read(void* buf, u32 size); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// write bytes from starlet (it update the offset) + +int mload_write(const void * buf, u32 size); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// fill a block (similar to memset) + +int mload_memset(void *starlet_addr, int set, int len); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// get the ehci datas ( ehcmodule.elf uses this address) + +void * mload_get_ehci_data(); + +/*--------------------------------------------------------------------------------------------------------------*/ + +// set the dev/es ioctlv in routine + +int mload_set_ES_ioctlv_vector(void *starlet_addr); + +/*--------------------------------------------------------------------------------------------------------------*/ + + + +#ifdef __cplusplus + } +#endif + + +#endif diff --git a/source.en/nand.c b/source.en/nand.c new file mode 100644 index 0000000..a5c99be --- /dev/null +++ b/source.en/nand.c @@ -0,0 +1,86 @@ +#include +#include + +#include "nand.h" + +/* Buffer */ +static u32 inbuf[8] ATTRIBUTE_ALIGN(32); + + +s32 Nand_Mount(nandDevice *dev) +{ + s32 fd, ret; + + /* Open FAT module */ + fd = IOS_Open("fat", 0); + if (fd < 0) + return fd; + + /* Mount device */ + ret = IOS_Ioctlv(fd, dev->mountCmd, 0, 0, NULL); + + /* Close FAT module */ + IOS_Close(fd); + + return ret; +} + +s32 Nand_Unmount(nandDevice *dev) +{ + s32 fd, ret; + + /* Open FAT module */ + fd = IOS_Open("fat", 0); + if (fd < 0) + return fd; + + /* Unmount device */ + ret = IOS_Ioctlv(fd, dev->umountCmd, 0, 0, NULL); + + /* Close FAT module */ + IOS_Close(fd); + + return ret; +} + +s32 Nand_Enable(nandDevice *dev) +{ + s32 fd, ret; + + /* Open /dev/fs */ + fd = IOS_Open("/dev/fs", 0); + if (fd < 0) + return fd; + + /* Set input buffer */ + inbuf[0] = dev->mode; + + /* Enable NAND emulator */ + ret = IOS_Ioctl(fd, 100, inbuf, sizeof(inbuf), NULL, 0); + + /* Close /dev/fs */ + IOS_Close(fd); + + return ret; +} + +s32 Nand_Disable(void) +{ + s32 fd, ret; + + /* Open /dev/fs */ + fd = IOS_Open("/dev/fs", 0); + if (fd < 0) + return fd; + + /* Set input buffer */ + inbuf[0] = 0; + + /* Disable NAND emulator */ + ret = IOS_Ioctl(fd, 100, inbuf, sizeof(inbuf), NULL, 0); + + /* Close /dev/fs */ + IOS_Close(fd); + + return ret; +} diff --git a/source.en/nand.h b/source.en/nand.h new file mode 100644 index 0000000..0b769d8 --- /dev/null +++ b/source.en/nand.h @@ -0,0 +1,24 @@ +#ifndef _NAND_H_ +#define _NAND_H_ + +/* 'NAND Device' structure */ +typedef struct { + /* Device name */ + char *name; + + /* Mode value */ + u32 mode; + + /* Un/mount command */ + u32 mountCmd; + u32 umountCmd; +} nandDevice; + + +/* Prototypes */ +s32 Nand_Mount(nandDevice *); +s32 Nand_Unmount(nandDevice *); +s32 Nand_Enable(nandDevice *); +s32 Nand_Disable(void); + +#endif diff --git a/source.en/restart.c b/source.en/restart.c new file mode 100644 index 0000000..1e29efb --- /dev/null +++ b/source.en/restart.c @@ -0,0 +1,33 @@ +#include +#include + +#include "nand.h" +#include "sys.h" +#include "wpad.h" +//#include "video.h" + + +void Restart(void) +{ + printf("\n End the WAD-Manager..."); + fflush(stdout); + + /* Disable NAND emulator */ + Nand_Disable(); + + /* Load system menu */ + Sys_LoadMenu(); +} + +void Restart_Wait(void) +{ + printf("\n Press any key to restart..."); + fflush(stdout); + + /* Wait for button */ + Wpad_WaitButtons(); + + /* Restart */ + Restart(); +} + diff --git a/source.en/restart.h b/source.en/restart.h new file mode 100644 index 0000000..3df94d7 --- /dev/null +++ b/source.en/restart.h @@ -0,0 +1,8 @@ +#ifndef _RESTART_H_ +#define _RESTART_H_ + +/* Prototypes */ +void Restart(void); +void Restart_Wait(void); + +#endif diff --git a/source.en/sha1.c b/source.en/sha1.c new file mode 100644 index 0000000..7ce9e6d --- /dev/null +++ b/source.en/sha1.c @@ -0,0 +1,177 @@ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd if true. */ +#define SHA1HANDSOFF + +#include +#include +#include "sha1.h" + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifdef LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + +typedef struct { + unsigned long state[5]; + unsigned long count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(unsigned long state[5], unsigned char buffer[64]) +{ +unsigned long a, b, c, d, e; +typedef union { + unsigned char c[64]; + unsigned long l[16]; +} CHAR64LONG16; +CHAR64LONG16* block; +#ifdef SHA1HANDSOFF +static unsigned char workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*)buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len) +{ +unsigned int i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ +unsigned long i, j; +unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (unsigned char *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (unsigned char *)"\0", 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + i = j = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(&finalcount, 0, 8); +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ + SHA1Transform(context->state, context->buffer); +#endif +} + +void SHA1(unsigned char *ptr, unsigned int size, unsigned char *outbuf) { + SHA1_CTX ctx; + + SHA1Init(&ctx); + SHA1Update(&ctx, ptr, size); + SHA1Final(outbuf, &ctx); +} diff --git a/source.en/sha1.h b/source.en/sha1.h new file mode 100644 index 0000000..35b3388 --- /dev/null +++ b/source.en/sha1.h @@ -0,0 +1,6 @@ +#ifndef _SHA1_H_ +#define _SHA1_H_ + +void SHA1(unsigned char *, unsigned int, unsigned char *); + +#endif diff --git a/source.en/stub.S b/source.en/stub.S new file mode 100644 index 0000000..418c838 --- /dev/null +++ b/source.en/stub.S @@ -0,0 +1,6 @@ + .rodata + + .globl bgData + .balign 32 +bgData: + .incbin "../data/background" diff --git a/source.en/sys.c b/source.en/sys.c new file mode 100644 index 0000000..4829eba --- /dev/null +++ b/source.en/sys.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include + +#include "sys.h" +#include "mload.h" +#include "ehcmodule_elf.h" + +/* Constants */ +#define CERTS_LEN 0x280 + +/* Variables */ +static const char certs_fs[] ATTRIBUTE_ALIGN(32) = "/sys/cert.sys"; + +void __Sys_ResetCallback(void) +{ + /* Reboot console */ + Sys_Reboot(); +} + +void __Sys_PowerCallback(void) +{ + /* Poweroff console */ + Sys_Shutdown(); +} + +bool isIOSstub(u8 ios_number) +{ + u32 tmd_size; + tmd_view *ios_tmd; + + + if((boot2version >= 5) && ( ios_number == 202 || ios_number == 222 || ios_number == 223 || ios_number == 224)) return true; + + ES_GetTMDViewSize(0x0000000100000000ULL | ios_number, &tmd_size); + if (!tmd_size) + { + //getting size failed. invalid or fake tmd for sure! + //gprintf("failed to get tmd for ios %d\n",ios_number); + return true; + } + ios_tmd = (tmd_view *)memalign( 32, (tmd_size+31)&(~31) ); + if(!ios_tmd) + { + //gprintf("failed to mem align the TMD struct!\n"); + return true; + } + memset(ios_tmd , 0, tmd_size); + ES_GetTMDView(0x0000000100000000ULL | ios_number, (u8*)ios_tmd , tmd_size); + //gprintf("IOS %d is rev %d(0x%x) with tmd size of %u and %u contents\n",ios_number,ios_tmd->title_version,ios_tmd->title_version,tmd_size,ios_tmd->num_contents); + /*Stubs have a few things in common: + - title version : it is mostly 65280 , or even better : in hex the last 2 digits are 0. + example : IOS 60 rev 6400 = 0x1900 = 00 = stub + - exception for IOS21 which is active, the tmd size is 592 bytes (or 140 with the views) + - the stub ios' have 1 app of their own (type 0x1) and 2 shared apps (type 0x8001). + eventho the 00 check seems to work fine , we'll only use other knowledge as well cause some + people/applications install an ios with a stub rev >_> ...*/ + u8 Version = ios_tmd->title_version; + + if((boot2version >= 5) && (ios_number == 249 || ios_number == 250) && (Version < 18)) return true; + if(( ios_number == 202 || ios_number == 222 || ios_number == 223 || ios_number == 224) && (Version < 4)) return true; + //version now contains the last 2 bytes. as said above, if this is 00, its a stub + if ( Version == 0 ) + { + if ( ( ios_tmd->num_contents == 3) && (ios_tmd->contents[0].type == 1 && ios_tmd->contents[1].type == 0x8001 && ios_tmd->contents[2].type == 0x8001) ) + { + //gprintf("IOS %d is a stub\n",ios_number); + free(ios_tmd); + return true; + } + else + { + //gprintf("IOS %d is active\n",ios_number); + free(ios_tmd); + return false; + } + } + //gprintf("IOS %d is active\n",ios_number); + free(ios_tmd); + return false; +} + + +bool loadIOS(int ios) +{ + if(isIOSstub(ios)) return false; + mload_close(); + if(IOS_ReloadIOS(ios)>=0) + { + if (IOS_GetVersion() != 249 && IOS_GetVersion() != 250) + { + if (mload_init() >= 0) + { + data_elf my_data_elf; + mload_elf((void *) ehcmodule_elf, &my_data_elf); + mload_run_thread(my_data_elf.start, my_data_elf.stack, my_data_elf.size_stack, 0x47); + } + } + return true; + } + return false; +} + +void Sys_Init(void) +{ + /* Initialize video subsytem */ + VIDEO_Init(); + + /* Set RESET/POWER button callback */ + SYS_SetResetCallback(__Sys_ResetCallback); + SYS_SetPowerCallback(__Sys_PowerCallback); +} + +void Sys_Reboot(void) +{ + /* Restart console */ + STM_RebootSystem(); +} + +void Sys_Shutdown(void) +{ + /* Poweroff console */ + if(CONF_GetShutdownMode() == CONF_SHUTDOWN_IDLE) { + s32 ret; + + /* Set LED mode */ + ret = CONF_GetIdleLedMode(); + if(ret >= 0 && ret <= 2) + STM_SetLedMode(ret); + + /* Shutdown to idle */ + STM_ShutdownToIdle(); + } else { + /* Shutdown to standby */ + STM_ShutdownToStandby(); + } +} + +void Sys_LoadMenu(void) +{ + int HBC = 0; + char * sig = (char *)0x80001804; + if( + sig[0] == 'S' && + sig[1] == 'T' && + sig[2] == 'U' && + sig[3] == 'B' && + sig[4] == 'H' && + sig[5] == 'A' && + sig[6] == 'X' && + sig[7] == 'X') + HBC=1; // Exit to HBC + + + /* Homebrew Channel stub */ + if (HBC == 1) + exit(0); + + /* Return to the Wii system menu */ + SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); +} + +s32 Sys_GetCerts(signed_blob **certs, u32 *len) +{ + static signed_blob certificates[CERTS_LEN] ATTRIBUTE_ALIGN(32); + + s32 fd, ret; + + /* Open certificates file */ + fd = IOS_Open(certs_fs, 1); + if (fd < 0) + return fd; + + /* Read certificates */ + ret = IOS_Read(fd, certificates, sizeof(certificates)); + + /* Close file */ + IOS_Close(fd); + + /* Set values */ + if (ret > 0) { + *certs = certificates; + *len = sizeof(certificates); + } + + return ret; +} diff --git a/source.en/sys.h b/source.en/sys.h new file mode 100644 index 0000000..419ed68 --- /dev/null +++ b/source.en/sys.h @@ -0,0 +1,14 @@ +#ifndef _SYS_H_ +#define _SYS_H_ + +u32 boot2version; +/* Prototypes */ +bool isIOSstub(u8 ios_number); +bool loadIOS(int ios); +void Sys_Init(void); +void Sys_Reboot(void); +void Sys_Shutdown(void); +void Sys_LoadMenu(void); +s32 Sys_GetCerts(signed_blob **, u32 *); + +#endif diff --git a/source.en/title.c b/source.en/title.c new file mode 100644 index 0000000..76fe3a6 --- /dev/null +++ b/source.en/title.c @@ -0,0 +1,324 @@ +#include +#include +#include +#include +#include +#include + +#include "sha1.h" +#include "utils.h" + + +s32 Title_ZeroSignature(signed_blob *p_sig) +{ + u8 *ptr = (u8 *)p_sig; + + /* Fill signature with zeroes */ + memset(ptr + 4, 0, SIGNATURE_SIZE(p_sig) - 4); + + return 0; +} + +s32 Title_FakesignTik(signed_blob *p_tik) +{ + tik *tik_data = NULL; + u16 fill; + + /* Zero signature */ + Title_ZeroSignature(p_tik); + + /* Ticket data */ + tik_data = (tik *)SIGNATURE_PAYLOAD(p_tik); + + for (fill = 0; fill < USHRT_MAX; fill++) { + sha1 hash; + + /* Modify ticket padding field */ + tik_data->padding = fill; + + /* Calculate hash */ + SHA1((u8 *)tik_data, sizeof(tik), hash); + + /* Found valid hash */ + if (!hash[0]) + return 0; + } + + return -1; +} + +s32 Title_FakesignTMD(signed_blob *p_tmd) +{ + tmd *tmd_data = NULL; + u16 fill; + + /* Zero signature */ + Title_ZeroSignature(p_tmd); + + /* TMD data */ + tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); + + for (fill = 0; fill < USHRT_MAX; fill++) { + sha1 hash; + + /* Modify TMD fill field */ + tmd_data->fill3 = fill; + + /* Calculate hash */ + SHA1((u8 *)tmd_data, TMD_SIZE(tmd_data), hash); + + /* Found valid hash */ + if (!hash[0]) + return 0; + } + + return -1; +} + +s32 Title_GetList(u64 **outbuf, u32 *outlen) +{ + u64 *titles = NULL; + + u32 len, nb_titles; + s32 ret; + + /* Get number of titles */ + ret = ES_GetNumTitles(&nb_titles); + if (ret < 0) + return ret; + + /* Calculate buffer lenght */ + len = round_up(sizeof(u64) * nb_titles, 32); + + /* Allocate memory */ + titles = memalign(32, len); + if (!titles) + return -1; + + /* Get titles */ + ret = ES_GetTitles(titles, nb_titles); + if (ret < 0) + goto err; + + /* Set values */ + *outbuf = titles; + *outlen = nb_titles; + + return 0; + +err: + /* Free memory */ + if (titles) + free(titles); + + return ret; +} + +s32 Title_GetTicketViews(u64 tid, tikview **outbuf, u32 *outlen) +{ + tikview *views = NULL; + + u32 nb_views; + s32 ret; + + /* Get number of ticket views */ + ret = ES_GetNumTicketViews(tid, &nb_views); + if (ret < 0) + return ret; + + /* Allocate memory */ + views = (tikview *)memalign(32, sizeof(tikview) * nb_views); + if (!views) + return -1; + + /* Get ticket views */ + ret = ES_GetTicketViews(tid, views, nb_views); + if (ret < 0) + goto err; + + /* Set values */ + *outbuf = views; + *outlen = nb_views; + + return 0; + +err: + /* Free memory */ + if (views) + free(views); + + return ret; +} + +s32 Title_GetTMD(u64 tid, signed_blob **outbuf, u32 *outlen) +{ + void *p_tmd = NULL; + + u32 len; + s32 ret; + + /* Get TMD size */ + ret = ES_GetStoredTMDSize(tid, &len); + if (ret < 0) + return ret; + + /* Allocate memory */ + p_tmd = memalign(32, round_up(len, 32)); + if (!p_tmd) + return -1; + + /* Read TMD */ + ret = ES_GetStoredTMD(tid, p_tmd, len); + if (ret < 0) + goto err; + + /* Set values */ + *outbuf = p_tmd; + *outlen = len; + + return 0; + +err: + /* Free memory */ + if (p_tmd) + free(p_tmd); + + return ret; +} + +s32 Title_GetVersion(u64 tid, u16 *outbuf) +{ + signed_blob *p_tmd = NULL; + tmd *tmd_data = NULL; + + u32 len; + s32 ret; + + /* Get title TMD */ + ret = Title_GetTMD(tid, &p_tmd, &len); + if (ret < 0) + return ret; + + /* Retrieve TMD info */ + tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); + + /* Set values */ + *outbuf = tmd_data->title_version; + + /* Free memory */ + free(p_tmd); + + return 0; +} + +s32 Title_GetSysVersion(u64 tid, u64 *outbuf) +{ + signed_blob *p_tmd = NULL; + tmd *tmd_data = NULL; + + u32 len; + s32 ret; + + /* Get title TMD */ + ret = Title_GetTMD(tid, &p_tmd, &len); + if (ret < 0) + return ret; + + /* Retrieve TMD info */ + tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); + + /* Set values */ + *outbuf = tmd_data->sys_version; + + /* Free memory */ + free(p_tmd); + + return 0; +} + +s32 Title_GetSize(u64 tid, u32 *outbuf) +{ + signed_blob *p_tmd = NULL; + tmd *tmd_data = NULL; + + u32 cnt, len, size = 0; + s32 ret; + + /* Get title TMD */ + ret = Title_GetTMD(tid, &p_tmd, &len); + if (ret < 0) + return ret; + + /* Retrieve TMD info */ + tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); + + /* Calculate title size */ + for (cnt = 0; cnt < tmd_data->num_contents; cnt++) { + tmd_content *content = &tmd_data->contents[cnt]; + + /* Add content size */ + size += content->size; + } + + /* Set values */ + *outbuf = size; + + /* Free memory */ + free(p_tmd); + + return 0; +} + +s32 Title_GetIOSVersions(u8 **outbuf, u32 *outlen) +{ + u8 *buffer = NULL; + u64 *list = NULL; + + u32 count, cnt, idx; + s32 ret; + + /* Get title list */ + ret = Title_GetList(&list, &count); + if (ret < 0) + return ret; + + /* Count IOS */ + for (cnt = idx = 0; idx < count; idx++) { + u32 tidh = (list[idx] >> 32); + u32 tidl = (list[idx] & 0xFFFFFFFF); + + /* Title is IOS */ + if ((tidh == 0x1) && (tidl >= 3) && (tidl <= 255)) + cnt++; + } + + /* Allocate memory */ + buffer = (u8 *)memalign(32, cnt); + if (!buffer) { + ret = -1; + goto out; + } + + /* Copy IOS */ + for (cnt = idx = 0; idx < count; idx++) { + u32 tidh = (list[idx] >> 32); + u32 tidl = (list[idx] & 0xFFFFFFFF); + + /* Title is IOS */ + if ((tidh == 0x1) && (tidl >= 3) && (tidl <= 255)) + buffer[cnt++] = (u8)(tidl & 0xFF); + } + + /* Set values */ + *outbuf = buffer; + *outlen = cnt; + + goto out; + +out: + /* Free memory */ + if (list) + free(list); + + return ret; +} diff --git a/source.en/title.h b/source.en/title.h new file mode 100644 index 0000000..4faba41 --- /dev/null +++ b/source.en/title.h @@ -0,0 +1,19 @@ +#ifndef _TITLE_H_ +#define _TITLE_H_ + +/* Constants */ +#define BLOCK_SIZE 1024 + +/* Prototypes */ +s32 Title_ZeroSignature(signed_blob *); +s32 Title_FakesignTik(signed_blob *); +s32 Title_FakesignTMD(signed_blob *); +s32 Title_GetList(u64 **, u32 *); +s32 Title_GetTicketViews(u64, tikview **, u32 *); +s32 Title_GetTMD(u64, signed_blob **, u32 *); +s32 Title_GetVersion(u64, u16 *); +s32 Title_GetSysVersion(u64, u64 *); +s32 Title_GetSize(u64, u32 *); +s32 Title_GetIOSVersions(u8 **, u32 *); + +#endif diff --git a/source.en/usbstorage.c b/source.en/usbstorage.c new file mode 100644 index 0000000..d0d3432 --- /dev/null +++ b/source.en/usbstorage.c @@ -0,0 +1,400 @@ +/*------------------------------------------------------------- + +usbstorage_starlet.c -- USB mass storage support, inside starlet +Copyright (C) 2009 Kwiirk + +If this driver is linked before libogc, this will replace the original +usbstorage driver by svpe from libogc +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#include +#include +#include +#include + +/* IOCTL commands */ +#define UMS_BASE (('U'<<24)|('M'<<16)|('S'<<8)) +#define USB_IOCTL_UMS_INIT (UMS_BASE+0x1) +#define USB_IOCTL_UMS_GET_CAPACITY (UMS_BASE+0x2) +#define USB_IOCTL_UMS_READ_SECTORS (UMS_BASE+0x3) +#define USB_IOCTL_UMS_WRITE_SECTORS (UMS_BASE+0x4) +#define USB_IOCTL_UMS_READ_STRESS (UMS_BASE+0x5) +#define USB_IOCTL_UMS_SET_VERBOSE (UMS_BASE+0x6) +#define USB_IOCTL_UMS_UNMOUNT (UMS_BASE+0x10) +#define USB_IOCTL_UMS_WATCHDOG (UMS_BASE+0x80) + +#define WBFS_BASE (('W'<<24)|('F'<<16)|('S'<<8)) +#define USB_IOCTL_WBFS_OPEN_DISC (WBFS_BASE+0x1) +#define USB_IOCTL_WBFS_READ_DISC (WBFS_BASE+0x2) +#define USB_IOCTL_WBFS_READ_DEBUG (WBFS_BASE+0x3) +#define USB_IOCTL_WBFS_SET_DEVICE (WBFS_BASE+0x4) +#define USB_IOCTL_WBFS_SET_FRAGLIST (WBFS_BASE+0x5) + +#define UMS_HEAPSIZE 0x1000 + +/* Variables */ +static char fs[] ATTRIBUTE_ALIGN(32) = "/dev/usb2"; +static char fs2[] ATTRIBUTE_ALIGN(32) = "/dev/usb/ehc"; +static char fs3[] ATTRIBUTE_ALIGN(32) = "/dev/usb/usb123"; + +static s32 hid = -1, fd = -1; +static u32 sector_size; + +s32 USBStorage_GetCapacity(u32 *_sector_size) { + if (fd > 0) { + s32 ret; + + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_GET_CAPACITY, ":i", §or_size); + + if (ret && _sector_size) + *_sector_size = sector_size; + + return ret; + } + + return IPC_ENOENT; +} + +s32 USBStorage_Init(void) { + s32 ret; + + /* Already open */ + if (fd > 0) + return 0; + + /* Create heap */ + if (hid < 0) { + hid = iosCreateHeap(UMS_HEAPSIZE); + if (hid < 0) + return IPC_ENOMEM; + } + + /* Open USB device */ + fd = IOS_Open(fs, 0); + if (fd < 0) + fd = IOS_Open(fs2, 0); + if (fd < 0) + fd = IOS_Open(fs3, 0); + if (fd < 0) + return fd; + + /* Initialize USB storage */ + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_INIT, ":"); + if (ret<0) goto err; + + /* Get device capacity */ + ret = USBStorage_GetCapacity(NULL); + if (!ret) + goto err; + + return 0; + +err: + /* Close USB device */ + if (fd > 0) { + IOS_Close(fd); + fd = -1; + } + + return -1; +} + +/** Hermes **/ +s32 USBStorage_Watchdog(u32 on_off) { + if (fd >= 0) { + s32 ret; + + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_WATCHDOG, "i:", on_off); + + return ret; + } + + return IPC_ENOENT; +} + +s32 USBStorage_Umount(void) { + if (fd >= 0) { + s32 ret; + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_UNMOUNT, ":"); + return ret; + } + + return IPC_ENOENT; +} + +void USBStorage_Deinit(void) { + /* Close USB device */ + if (fd > 0) { + IOS_Close(fd); + fd = -1; + } +} + +s32 USBStorage_ReadSectors(u32 sector, u32 numSectors, void *buffer) { + +// void *buf = (void *)buffer; + u32 len = (sector_size * numSectors); + + s32 ret; + + /* Device not opened */ + if (fd < 0) + return fd; + + + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_READ_SECTORS, "ii:d", sector, numSectors, buffer, len); + return ret; +} + +s32 USBStorage_WriteSectors(u32 sector, u32 numSectors, const void *buffer) { + u32 len = (sector_size * numSectors); + + s32 ret; + + /* Device not opened */ + if (fd < 0) + return fd; + + /* Write data */ + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_UMS_WRITE_SECTORS, "ii:d", sector, numSectors, buffer, len); + + return ret; +} + +static bool __io_usb_Startup(void) +{ + return USBStorage_Init() >= 0; +} + +static bool __io_usb_IsInserted(void) +{ + s32 ret; + if (fd < 0) return false; + ret = USBStorage_GetCapacity(NULL); + if (ret == 0) return false; + return true; +} + +bool __io_usb_ReadSectors(u32 sector, u32 count, void *buffer) +{ + s32 ret = USBStorage_ReadSectors(sector, count, buffer); + return ret > 0; +} + +bool __io_usb_WriteSectors(u32 sector, u32 count, void *buffer) +{ + s32 ret = USBStorage_WriteSectors(sector, count, buffer); + return ret > 0; +} + +static bool __io_usb_ClearStatus(void) +{ + return true; +} + +static bool __io_usb_Shutdown(void) +{ + // do nothing + return true; +} + +static bool __io_usb_NOP(void) +{ + // do nothing + return true; +} + +const DISC_INTERFACE __io_usbstorage_ro = { + DEVICE_TYPE_WII_USB, + FEATURE_MEDIUM_CANREAD | FEATURE_WII_USB, + (FN_MEDIUM_STARTUP) &__io_usb_Startup, + (FN_MEDIUM_ISINSERTED) &__io_usb_IsInserted, + (FN_MEDIUM_READSECTORS) &__io_usb_ReadSectors, + (FN_MEDIUM_WRITESECTORS) &__io_usb_NOP, //&__io_usb_WriteSectors, + (FN_MEDIUM_CLEARSTATUS) &__io_usb_ClearStatus, + (FN_MEDIUM_SHUTDOWN) &__io_usb_Shutdown +}; + +s32 USBStorage_WBFS_Open(char *buffer) +{ + u32 len = 8; + + s32 ret; + + /* Device not opened */ + if (fd < 0) + return fd; + + extern u32 wbfs_part_lba; + u32 part = wbfs_part_lba; + + /* Read data */ + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_WBFS_OPEN_DISC, "dd:", buffer, len, &part, 4); + + return ret; +} + +// woffset is in 32bit words, len is in bytes +s32 USBStorage_WBFS_Read(u32 woffset, u32 len, void *buffer) +{ + s32 ret; + + USBStorage_Init(); + /* Device not opened */ + if (fd < 0) + return fd; + + /* Read data */ + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_WBFS_READ_DISC, "ii:d", woffset, len, buffer, len); + + return ret; +} + + +s32 USBStorage_WBFS_ReadDebug(u32 off, u32 size, void *buffer) +{ + s32 ret; + + USBStorage_Init(); + /* Device not opened */ + if (fd < 0) + return fd; + + /* Read data */ + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_WBFS_READ_DEBUG, "ii:d", off, size, buffer, size); + + return ret; +} + + +s32 USBStorage_WBFS_SetDevice(int dev) +{ + s32 ret; + static s32 retval = 0; + retval = 0; + USBStorage_Init(); + // Device not opened + if (fd < 0) return fd; + // ioctl + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_WBFS_SET_DEVICE, "i:i", dev, &retval); + if (retval) return retval; + return ret; +} + +s32 USBStorage_WBFS_SetFragList(void *p, int size) +{ + s32 ret; + USBStorage_Init(); + // Device not opened + if (fd < 0) return fd; + // ioctl + ret = IOS_IoctlvFormat(hid, fd, USB_IOCTL_WBFS_SET_FRAGLIST, "d:", p, size); + return ret; +} + +#define DEVICE_TYPE_WII_UMS (('W'<<24)|('U'<<16)|('M'<<8)|'S') + +bool umsio_Startup() { + return USBStorage_Init() == 0; +} + +bool umsio_IsInserted() { + return true; // allways true +} + +bool umsio_ReadSectors(sec_t sector, sec_t numSectors, u8 *buffer) { + u32 cnt = 0; + s32 ret; + /* Do reads */ + while (cnt < numSectors) { + u32 sectors = (numSectors - cnt); + + /* Read sectors is too big */ + if (sectors > 32) + sectors = 32; + + /* USB read */ + ret = USBStorage_ReadSectors(sector + cnt, sectors, &buffer[cnt*512]); + if (ret < 0) + return false; + + /* Increment counter */ + cnt += sectors; + } + + return true; +} + +bool umsio_WriteSectors(sec_t sector, sec_t numSectors, const u8* buffer) { + u32 cnt = 0; + s32 ret; + + /* Do writes */ + while (cnt < numSectors) { + u32 sectors = (numSectors - cnt); + + /* Write sectors is too big */ + if (sectors > 32) + sectors = 32; + + /* USB write */ + ret = USBStorage_WriteSectors(sector + cnt, sectors, &buffer[cnt * 512]); + if (ret < 0) + return false; + + /* Increment counter */ + cnt += sectors; + } + + return true; +} + +bool umsio_ClearStatus(void) { + return true; +} + +bool umsio_Shutdown() { + USBStorage_Deinit(); + return true; +} + +const DISC_INTERFACE __io_wiiums = { + DEVICE_TYPE_WII_UMS, + FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_USB, + (FN_MEDIUM_STARTUP) &umsio_Startup, + (FN_MEDIUM_ISINSERTED) &umsio_IsInserted, + (FN_MEDIUM_READSECTORS) &umsio_ReadSectors, + (FN_MEDIUM_WRITESECTORS) &umsio_WriteSectors, + (FN_MEDIUM_CLEARSTATUS) &umsio_ClearStatus, + (FN_MEDIUM_SHUTDOWN) &umsio_Shutdown +}; + +const DISC_INTERFACE __io_wiiums_ro = { + DEVICE_TYPE_WII_UMS, + FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_USB, + (FN_MEDIUM_STARTUP) &umsio_Startup, + (FN_MEDIUM_ISINSERTED) &umsio_IsInserted, + (FN_MEDIUM_READSECTORS) &umsio_ReadSectors, + (FN_MEDIUM_WRITESECTORS) &__io_usb_NOP, + (FN_MEDIUM_CLEARSTATUS) &umsio_ClearStatus, + (FN_MEDIUM_SHUTDOWN) &umsio_Shutdown +}; diff --git a/source.en/usbstorage.h b/source.en/usbstorage.h new file mode 100644 index 0000000..6c6cec5 --- /dev/null +++ b/source.en/usbstorage.h @@ -0,0 +1,27 @@ +#ifndef _USBSTORAGE_H_ +#define _USBSTORAGE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + /* Prototypes */ + s32 USBStorage_GetCapacity(u32 *); + s32 USBStorage_Init(void); + void USBStorage_Deinit(void); + s32 USBStorage_Watchdog(u32 on_off); + s32 USBStorage_ReadSectors(u32, u32, void *); + s32 USBStorage_WriteSectors(u32, u32, const void *); + + s32 USBStorage_WBFS_Open(char *buf_id); + s32 USBStorage_WBFS_Read(u32 woffset, u32 len, void *buffer); + s32 USBStorage_WBFS_ReadDebug(u32 off, u32 size, void *buffer); + s32 USBStorage_WBFS_SetDevice(int dev); + s32 USBStorage_WBFS_SetFragList(void *p, int size); + + extern const DISC_INTERFACE __io_wiiums; + extern const DISC_INTERFACE __io_wiiums_ro; +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source.en/utils.h b/source.en/utils.h new file mode 100644 index 0000000..3a4862b --- /dev/null +++ b/source.en/utils.h @@ -0,0 +1,15 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +/* Constants */ +#define KB_SIZE 1024.0 +#define MB_SIZE 1048576.0 +#define GB_SIZE 1073741824.0 + +/* Macros */ +#define round_up(x,n) (-(-(x) & -(n))) + +/* Prototypes */ +u32 swap32(u32); + +#endif diff --git a/source.en/video.c b/source.en/video.c new file mode 100644 index 0000000..0182671 --- /dev/null +++ b/source.en/video.c @@ -0,0 +1,141 @@ +#include +#include + +#include "sys.h" +#include "video.h" + +/* Video variables */ +static void *framebuffer = NULL; +static GXRModeObj *vmode = NULL; + + +void Con_Init(u32 x, u32 y, u32 w, u32 h) +{ + /* Create console in the framebuffer */ + CON_InitEx(vmode, x, y, w, h); +} + +void Con_Clear(void) +{ + /* Clear console */ + printf("\x1b[2J"); + fflush(stdout); +} + +void Con_ClearLine(void) +{ + s32 cols, rows; + u32 cnt; + + printf("\r"); + fflush(stdout); + + /* Get console metrics */ + CON_GetMetrics(&cols, &rows); + + /* Erase line */ + for (cnt = 1; cnt < cols; cnt++) { + printf(" "); + fflush(stdout); + } + + printf("\r"); + fflush(stdout); +} + +void Con_FgColor(u32 color, u8 bold) +{ + /* Set foreground color */ + printf("\x1b[%u;%um", color + 30, bold); + fflush(stdout); +} + +void Con_BgColor(u32 color, u8 bold) +{ + /* Set background color */ + printf("\x1b[%u;%um", color + 40, bold); + fflush(stdout); +} + +void Con_FillRow(u32 row, u32 color, u8 bold) +{ + s32 cols, rows; + u32 cnt; + + /* Set color */ + printf("\x1b[%u;%um", color + 40, bold); + fflush(stdout); + + /* Get console metrics */ + CON_GetMetrics(&cols, &rows); + + /* Save current row and col */ + printf("\x1b[s"); + fflush(stdout); + + /* Move to specified row */ + printf("\x1b[%u;0H", row); + fflush(stdout); + + /* Fill row */ + for (cnt = 0; cnt < cols; cnt++) { + printf(" "); + fflush(stdout); + } + + /* Load saved row and col */ + printf("\x1b[u"); + fflush(stdout); + + /* Set default color */ + Con_BgColor(0, 0); + Con_FgColor(7, 1); +} + +void Video_Configure(GXRModeObj *rmode) +{ + /* Configure the video subsystem */ + VIDEO_Configure(rmode); + + /* Setup video */ + VIDEO_SetBlack(FALSE); + VIDEO_Flush(); + VIDEO_WaitVSync(); + + if (rmode->viTVMode & VI_NON_INTERLACE) + VIDEO_WaitVSync(); +} + +void Video_SetMode(void) +{ + /* Select preferred video mode */ + vmode = VIDEO_GetPreferredMode(NULL); + + /* Allocate memory for the framebuffer */ + framebuffer = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode)); + + /* Configure the video subsystem */ + VIDEO_Configure(vmode); + + /* Setup video */ + VIDEO_SetNextFramebuffer(framebuffer); + VIDEO_SetBlack(FALSE); + VIDEO_Flush(); + VIDEO_WaitVSync(); + + if (vmode->viTVMode & VI_NON_INTERLACE) + VIDEO_WaitVSync(); + + /* Clear the screen */ + Video_Clear(COLOR_BLACK); +} + +void Video_Clear(s32 color) +{ + VIDEO_ClearFrameBuffer(vmode, framebuffer, color); +} + +void Video_DrawPng(IMGCTX ctx, PNGUPROP imgProp, u16 x, u16 y) +{ + PNGU_DECODE_TO_COORDS_YCbYCr(ctx, x, y, imgProp.imgWidth, imgProp.imgHeight, vmode->fbWidth, vmode->xfbHeight, framebuffer); +} diff --git a/source.en/video.h b/source.en/video.h new file mode 100644 index 0000000..e0fb7fd --- /dev/null +++ b/source.en/video.h @@ -0,0 +1,19 @@ +#ifndef _VIDEO_H_ +#define _VIDEO_H_ + +#include "libpng/pngu/pngu.h" + +/* Prototypes */ +void Con_Init(u32, u32, u32, u32); +void Con_Clear(void); +void Con_ClearLine(void); +void Con_FgColor(u32, u8); +void Con_BgColor(u32, u8); +void Con_FillRow(u32, u32, u8); + +void Video_Configure(GXRModeObj *); +void Video_SetMode(void); +void Video_Clear(s32); +void Video_DrawPng(IMGCTX, PNGUPROP, u16, u16); + +#endif diff --git a/source.en/wad-manager.c b/source.en/wad-manager.c new file mode 100644 index 0000000..6aba421 --- /dev/null +++ b/source.en/wad-manager.c @@ -0,0 +1,490 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sys.h" +#include "gui.h" +#include "menu.h" +#include "restart.h" +#include "sys.h" +#include "video.h" +#include "wpad.h" +#include "fat.h" +#include "nand.h" +#include "globals.h" +#include "xyzzy.h" + + +// Globals +CONFIG gConfig; + +// Prototypes +extern u32 WaitButtons (void); +void CheckPassword (void); +void SetDefaultConfig (void); +int ReadConfigFile (char *configFilePath); +int GetIntParam (char *inputStr); +int GetStartupPath (char *startupPath, char *inputStr); +int GetStringParam (char *outParam, char *inputStr, int maxChars); + +// Default password Up-Down-Left-Right-Up-Down +//#define PASSWORD "UDLRUD" +void CheckPassword (void) +{ + char curPassword [11]; // Max 10 characters password, NULL terminated + int count = 0; + + if (strlen (gConfig.password) == 0) + return; + + // Ask user for a password. Press "B" to restart Wii + printf("[+] [Enter password to continue]:\n\n"); + + printf(">> Press [A] to continue.\n"); + printf(">> Press [B] to exit.\n"); + + /* Wait for user answer */ + for (;;) + { + u32 buttons = WaitButtons(); + + if (buttons & WPAD_BUTTON_A) + { + // A button, validate the pw + curPassword [count] = 0; + //if (strcmp (curPassword, PASSWORD) == 0) + if (strcmp (curPassword, gConfig.password) == 0) + { + printf(">> Password accepted...\n"); + break; + } + else + { + printf ("\n"); + printf(">> Incorrect password. Try again...\n"); + printf("[+] [Enter password to continue]:\n\n"); + printf(">> Press [A] to continue.\n"); + printf(">> Press [B] to exit.\n"); + count = 0; + } + } + else if (buttons & WPAD_BUTTON_B) + // B button, restart + Restart(); + else + { + if (count < 10) + { + // Other buttons, build the password + if (buttons & WPAD_BUTTON_LEFT) + { + curPassword [count++] = 'L'; + printf ("*"); + } + else if (buttons & WPAD_BUTTON_RIGHT) + { + curPassword [count++] = 'R'; + printf ("*"); + } + else if (buttons & WPAD_BUTTON_UP) + { + curPassword [count++] = 'U'; + printf ("*"); + } + else if (buttons & WPAD_BUTTON_DOWN) + { + curPassword [count++] = 'D'; + printf ("*"); + } + else if (buttons & WPAD_BUTTON_1) + { + curPassword [count++] = '1'; + printf ("*"); + } + else if (buttons & WPAD_BUTTON_2) + { + curPassword [count++] = '2'; + printf ("*"); + } + } + } + } +} + +void Disclaimer(void) +{ + /* Print disclaimer */ + printf("[+] [DISCLAIMER]:\n\n"); + + printf(" THIS APPLICATION COMES WITH NO WARRANTY AT ALL,\n"); + printf(" NEITHER EXPRESS NOR IMPLIED.\n"); + printf(" I DO NOT TAKE ANY RESPONSIBILITY FOR ANY DAMAGE IN YOUR\n"); + printf(" WII CONSOLE BECAUSE OF A IMPROPER USAGE OF THIS SOFTWARE.\n\n"); + + printf(">> Press [A] to continue.\n"); + printf(">> Otherwise, press [B] to restart.\n"); + + /* Wait for user answer */ + for (;;) { + // u32 buttons = Wpad_WaitButtons(); + u32 buttons = WaitButtons(); + + /* A button */ + if (buttons & WPAD_BUTTON_A) + break; + + /* B button */ + if (buttons & WPAD_BUTTON_B) + Restart(); + } +} + +void farbe(void) +{ + /* Print disclaimer */ + Con_BgColor(0, 1); + printf(" \n"); + Con_BgColor(0, 0); + printf(" \n"); + Con_BgColor(1, 1); + printf(" \n"); + Con_BgColor(1, 0); + printf(" \n"); + Con_BgColor(2, 1); + printf(" \n"); + Con_BgColor(2, 0); + printf(" \n"); + Con_BgColor(3, 1); + printf(" \n"); + Con_BgColor(3, 0); + printf(" \n"); + Con_BgColor(4, 1); + printf(" \n"); + Con_BgColor(4, 0); + printf(" \n"); + Con_BgColor(5, 1); + printf(" \n"); + Con_BgColor(5, 0); + printf(" \n"); + Con_BgColor(6, 1); + printf(" \n"); + Con_BgColor(6, 0); + printf(" \n"); + Con_BgColor(7, 1); + printf(" \n"); + Con_BgColor(7, 0); + printf(" \n"); + + + + /* Wait for user answer */ + for (;;) { + // u32 buttons = Wpad_WaitButtons(); + u32 buttons = WaitButtons(); + + /* A button */ + if (buttons & WPAD_BUTTON_HOME) + exit(0); + + } +} + +int main(int argc, char **argv) +{ + ES_GetBoot2Version(&boot2version); +/* + if(boot2version < 5) + { + if(!loadIOS(202)) if(!loadIOS(222)) if(!loadIOS(223)) if(!loadIOS(224)) if(!loadIOS(249)) loadIOS(36); + }else{ + if(!loadIOS(249)) loadIOS(36); + } +*/ /* Initialize subsystems */ + Sys_Init(); + + /* Set video mode */ + Video_SetMode(); + + /* Initialize console */ + Gui_InitConsole(); + + /* Draw background */ + Gui_DrawBackground(); + + if (AHBPROT_DISABLED) { + fatDevice *fdev = &fdevList[0]; + Fat_Unmount(fdev); + + IosPatch_RUNTIME(true, true, true, true); + + Fat_Mount(fdev); + keydump(); + Fat_Unmount(fdev); + + sleep(2); + Con_Clear(); + } + + /* Initialize Wiimote and GC Controller */ + Wpad_Init(); + PAD_Init (); + WIILIGHT_Init(); + + /* Print disclaimer */ +// farbe(); + Disclaimer(); + + // Set the defaults + SetDefaultConfig (); + + // Read the config file + ReadConfigFile (WM_CONFIG_FILE_PATH); + + // Check password + CheckPassword (); + + /* Menu loop */ + Menu_Loop(); + + /* Restart Wii */ + Restart_Wait(); + + return 0; +} + + +int ReadConfigFile (char *configFilePath) +{ + int retval = 0; + FILE *fptr; + char *tmpStr = malloc (MAX_FILE_PATH_LEN); + char tmpOutStr [40], path[128]; + int i; + + if (tmpStr == NULL) + return (-1); + + fatDevice *fdev = &fdevList[0]; + s32 ret = Fat_Mount(fdev); + snprintf(path, sizeof(path), "%s%s", fdev->mount, configFilePath); + + if (ret < 0) + { + fdev = &fdevList[2]; + ret = Fat_Mount(fdev); + snprintf(path, sizeof(path), "%s%s", fdev->mount, configFilePath); + snprintf(path, sizeof(path), "%s%s", fdev->mount, configFilePath); + } + + if (ret < 0) + { + printf(" ERROR! (ret = %d)\n", ret); + // goto err; + retval = -1; + } + else + { + // Read the file + fptr = fopen (path, "rb"); + if (fptr != NULL) + { + // Read the options + char done = 0; + + while (!done) + { + if (fgets (tmpStr, MAX_FILE_PATH_LEN, fptr) == NULL) + done = 1; + else if (isalpha(tmpStr[0])) + { + // Get the password + if (strncmp (tmpStr, "Password", 8) == 0) + { + // Get password + // GetPassword (gConfig.password, tmpStr); + GetStringParam (gConfig.password, tmpStr, MAX_PASSWORD_LENGTH); + + // If password is too long, ignore it + if (strlen (gConfig.password) > 10) + { + gConfig.password [0] = 0; + printf ("Passwords longer than 10 characters are ignored. Press a button...\n"); + WaitButtons (); + } + } + + // Get startup path + else if (strncmp (tmpStr, "StartupPath", 11) == 0) + { + // Get startup Path + GetStartupPath (gConfig.startupPath, tmpStr); + } + + // cIOS + else if (strncmp (tmpStr, "cIOSVersion", 11) == 0) + { + // Get cIOSVersion + gConfig.cIOSVersion = (u8)GetIntParam (tmpStr); + } + + // FatDevice + else if (strncmp (tmpStr, "FatDevice", 9) == 0) + { + // Get fatDevice + GetStringParam (tmpOutStr, tmpStr, MAX_FAT_DEVICE_LENGTH); + for (i = 0; i < 5; i++) + { + if (strncmp (fdevList[i].mount, tmpOutStr, 4) == 0) + { + gConfig.fatDeviceIndex = i; + } + } + } + + // NandDevice + else if (strncmp (tmpStr, "NANDDevice", 10) == 0) + { + // Get fatDevice + GetStringParam (tmpOutStr, tmpStr, MAX_NAND_DEVICE_LENGTH); + for (i = 0; i < 3; i++) + { + if (strncmp (ndevList[i].name, tmpOutStr, 2) == 0) + { + gConfig.nandDeviceIndex = i; + } + } + } + } + } // EndWhile + + // Close the config file + fclose (fptr); + } + else + { + // If the wm_config.txt file is not found, just take the default config params + //printf ("Config file is not found\n"); // This is for testing only + //WaitButtons(); + } + Fat_Unmount(fdev); + } + + // Free memory + free (tmpStr); + + return (retval); +} // ReadConfig + + +void SetDefaultConfig (void) +{ + // Default password is NULL or no password + gConfig.password [0] = 0; + + // Default startup folder + strcpy (gConfig.startupPath, WAD_DIRECTORY); + + gConfig.cIOSVersion = CIOS_VERSION_INVALID; // Means that user has to select later + gConfig.fatDeviceIndex = FAT_DEVICE_INDEX_INVALID; // Means that user has to select + gConfig.nandDeviceIndex = NAND_DEVICE_INDEX_INVALID; // Means that user has to select + +} // SetDefaultConfig + + +int GetStartupPath (char *startupPath, char *inputStr) +{ + int i = 0; + int len = strlen (inputStr); + + // Find the "=" + while ((inputStr [i] != '=') && (i < len)) + { + i++; + } + i++; + + // Get to the "/" + while ((inputStr [i] != '/') && (i < len)) + { + i++; + } + + // Get the startup Path + int count = 0; + while (isascii(inputStr [i]) && (i < len) && (inputStr [i] != '\n') && + (inputStr [i] != '\r') && (inputStr [i] != ' ')) + { + startupPath [count++] = inputStr [i++]; + } + startupPath [count] = 0; // NULL terminate + + return (0); +} // GetStartupPath + +int GetIntParam (char *inputStr) +{ + int retval = 0; + int i = 0; + int len = strlen (inputStr); + char outParam [40]; + + // Find the "=" + while ((inputStr [i] != '=') && (i < len)) + { + i++; + } + i++; + + // Get to the first alpha numeric character + while ((isdigit(inputStr [i]) == 0) && (i < len)) + { + i++; + } + + // Get the string param + int outCount = 0; + while ((isdigit(inputStr [i])) && (i < len) && (outCount < 40)) + { + outParam [outCount++] = inputStr [i++]; + } + outParam [outCount] = 0; // NULL terminate + retval = atoi (outParam); + + return (retval); +} // GetIntParam + + +int GetStringParam (char *outParam, char *inputStr, int maxChars) +{ + int i = 0; + int len = strlen (inputStr); + + // Find the "=" + while ((inputStr [i] != '=') && (i < len)) + { + i++; + } + i++; + + // Get to the first alpha character + while ((isalpha(inputStr [i]) == 0) && (i < len)) + { + i++; + } + + // Get the string param + int outCount = 0; + while ((isalnum(inputStr [i])) && (i < len) && (outCount < maxChars)) + { + outParam [outCount++] = inputStr [i++]; + } + outParam [outCount] = 0; // NULL terminate + + return (0); +} // GetStringParam diff --git a/source.en/wad.c b/source.en/wad.c new file mode 100644 index 0000000..2e6a9f4 --- /dev/null +++ b/source.en/wad.c @@ -0,0 +1,797 @@ +#include +#include +#include +#include +#include + +#include "sys.h" +#include "title.h" +#include "utils.h" +#include "video.h" +#include "wad.h" +#include "wpad.h" + +// Turn upper and lower into a full title ID +#define TITLE_ID(x,y) (((u64)(x) << 32) | (y)) +// Get upper or lower half of a title ID +#define TITLE_UPPER(x) ((u32)((x) >> 32)) +#define TITLE_LOWER(x) ((u32)(x)) + +typedef struct { + int version; + int region; + +} SMRegion; + +SMRegion regionlist[] = { + {33, 'X'}, + {128, 'J'}, {97, 'E'}, {130, 'P'}, + {162, 'P'}, + {192, 'J'}, {193, 'E'}, {194, 'P'}, + {224, 'J'}, {225, 'E'}, {226, 'P'}, + {256, 'J'}, {257, 'E'}, {258, 'P'}, + {288, 'J'}, {289, 'E'}, {290, 'P'}, + {352, 'J'}, {353, 'E'}, {354, 'P'}, {326, 'K'}, + {384, 'J'}, {385, 'E'}, {386, 'P'}, + {390, 'K'}, + {416, 'J'}, {417, 'E'}, {418, 'P'}, + {448, 'J'}, {449, 'E'}, {450, 'P'}, {454, 'K'}, + {480, 'J'}, {481, 'E'}, {482, 'P'}, {486, 'K'}, + {512, 'E'}, {513, 'E'}, {514, 'P'}, {518, 'K'}, +}; + +#define NB_SM (sizeof(regionlist) / sizeof(SMRegion)) + +static u8 wadBuffer[BLOCK_SIZE] ATTRIBUTE_ALIGN(32); + +u32 WaitButtons(void); + +u32 be32(const u8 *p) +{ + return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; +} + +u64 be64(const u8 *p) +{ + return ((u64)be32(p) << 32) | be32(p + 4); +} + +u64 get_title_ios(u64 title) { + s32 ret, fd; + static char filepath[256] ATTRIBUTE_ALIGN(32); + + // Check to see if title exists + if (ES_GetDataDir(title, filepath) >= 0 ) { + u32 tmd_size; + static u8 tmd_buf[MAX_SIGNED_TMD_SIZE] ATTRIBUTE_ALIGN(32); + + ret = ES_GetStoredTMDSize(title, &tmd_size); + if (ret < 0){ + // If we fail to use the ES function, try reading manually + // This is a workaround added since some IOS (like 21) don't like our + // call to ES_GetStoredTMDSize + + //printf("Error! ES_GetStoredTMDSize: %d\n", ret); + + sprintf(filepath, "/title/%08x/%08x/content/title.tmd", TITLE_UPPER(title), TITLE_LOWER(title)); + + ret = ISFS_Open(filepath, ISFS_OPEN_READ); + if (ret <= 0) + { + //printf("Error! ISFS_Open (ret = %d)\n", ret); + return 0; + } + + fd = ret; + + ret = ISFS_Seek(fd, 0x184, 0); + if (ret < 0) + { + //printf("Error! ISFS_Seek (ret = %d)\n", ret); + return 0; + } + + ret = ISFS_Read(fd,tmd_buf,8); + if (ret < 0) + { + //printf("Error! ISFS_Read (ret = %d)\n", ret); + return 0; + } + + ret = ISFS_Close(fd); + if (ret < 0) + { + //printf("Error! ISFS_Close (ret = %d)\n", ret); + return 0; + } + + return be64(tmd_buf); + + } else { + // Normal versions of IOS won't have a problem, so we do things the "right" way. + + // Some of this code adapted from bushing's title_lister.c + signed_blob *s_tmd = (signed_blob *)tmd_buf; + ret = ES_GetStoredTMD(title, s_tmd, tmd_size); + if (ret < 0){ + //printf("Error! ES_GetStoredTMD: %d\n", ret); + return -1; + } + tmd *t = SIGNATURE_PAYLOAD(s_tmd); + return t->sys_version; + } + + + } + return 0; +} + +int get_sm_region_basic() +{ + u32 tmd_size; + + u64 title = TITLE_ID(1, 2); + static u8 tmd_buf[MAX_SIGNED_TMD_SIZE] ATTRIBUTE_ALIGN(32); + + int ret = ES_GetStoredTMDSize(title, &tmd_size); + + // Some of this code adapted from bushing's title_lister.c + signed_blob *s_tmd = (signed_blob *)tmd_buf; + ret = ES_GetStoredTMD(title, s_tmd, tmd_size); + if (ret < 0){ + //printf("Error! ES_GetStoredTMD: %d\n", ret); + return -1; + } + tmd *t = SIGNATURE_PAYLOAD(s_tmd); + ret = t->title_version; + int i = 0; + while( i <= NB_SM) + { + if( regionlist[i].version == ret) return regionlist[i].region; + i++; + } + return 0; +} + +/* 'WAD Header' structure */ +typedef struct { + /* Header length */ + u32 header_len; + + /* WAD type */ + u16 type; + + /* Padding */ + u16 padding; + + /* Data length */ + u32 certs_len; + u32 crl_len; + u32 tik_len; + u32 tmd_len; + u32 data_len; + u32 footer_len; +} ATTRIBUTE_PACKED wadHeader; + +/* Variables */ +static u8 wadBuffer[BLOCK_SIZE] ATTRIBUTE_ALIGN(32); + + +s32 __Wad_ReadFile(FILE *fp, void *outbuf, u32 offset, u32 len) +{ + s32 ret; + + /* Seek to offset */ + fseek(fp, offset, SEEK_SET); + + /* Read data */ + ret = fread(outbuf, len, 1, fp); + if (ret < 0) + return ret; + + return 0; +} + +s32 __Wad_ReadAlloc(FILE *fp, void **outbuf, u32 offset, u32 len) +{ + void *buffer = NULL; + s32 ret; + + /* Allocate memory */ + buffer = memalign(32, len); + if (!buffer) + return -1; + + /* Read file */ + ret = __Wad_ReadFile(fp, buffer, offset, len); + if (ret < 0) { + free(buffer); + return ret; + } + + /* Set pointer */ + *outbuf = buffer; + + return 0; +} + +s32 __Wad_GetTitleID(FILE *fp, wadHeader *header, u64 *tid) +{ + signed_blob *p_tik = NULL; + tik *tik_data = NULL; + + u32 offset = 0; + s32 ret; + + /* Ticket offset */ + offset += round_up(header->header_len, 64); + offset += round_up(header->certs_len, 64); + offset += round_up(header->crl_len, 64); + + /* Read ticket */ + ret = __Wad_ReadAlloc(fp, (void *)&p_tik, offset, header->tik_len); + if (ret < 0) + goto out; + + /* Ticket data */ + tik_data = (tik *)SIGNATURE_PAYLOAD(p_tik); + + /* Copy title ID */ + *tid = tik_data->titleid; + +out: + /* Free memory */ + if (p_tik) + free(p_tik); + + return ret; +} + +void __Wad_FixTicket(signed_blob *p_tik) +{ + u8 *data = (u8 *)p_tik; + u8 *ckey = data + 0x1F1; + + /* Check common key */ + if (*ckey > 1) + *ckey = 0; + + /* Fakesign ticket */ + Title_FakesignTik(p_tik); +} + +s32 Wad_Install(FILE *fp, fatFile *file) +{ + wadHeader *header = NULL; + signed_blob *p_certs = NULL, *p_crl = NULL, *p_tik = NULL, *p_tmd = NULL; + + tmd *tmd_data = NULL; + + u32 cnt, offset = 0; + s32 ret; + u64 tid; + + printf("\t\t>> Reading WAD data..."); + fflush(stdout); + + ret = __Wad_ReadAlloc(fp, (void *)&header, offset, sizeof(wadHeader)); + if (ret >= 0) + offset += round_up(header->header_len, 64); + else + goto err; + + //Don't try to install boot2 + __Wad_GetTitleID(fp, header, &tid); + + if (tid == TITLE_ID(1, 1)) + { + printf("\n Will not install this title (boot2 wad?)\n"); + ret = -999; + goto out; + } + + /* WAD certificates */ + ret = __Wad_ReadAlloc(fp, (void *)&p_certs, offset, header->certs_len); + if (ret >= 0) + offset += round_up(header->certs_len, 64); + else + goto err; + + /* WAD crl */ + if (header->crl_len) { + ret = __Wad_ReadAlloc(fp, (void *)&p_crl, offset, header->crl_len); + if (ret < 0) + goto err; + else + offset += round_up(header->crl_len, 64); + } + + /* WAD ticket */ + ret = __Wad_ReadAlloc(fp, (void *)&p_tik, offset, header->tik_len); + if (ret < 0) + goto err; + else + offset += round_up(header->tik_len, 64); + + /* WAD TMD */ + ret = __Wad_ReadAlloc(fp, (void *)&p_tmd, offset, header->tmd_len); + if (ret < 0) + goto err; + else + offset += round_up(header->tmd_len, 64); + + Con_ClearLine(); + + /* Get TMD info */ + + tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); + + if(TITLE_LOWER(tmd_data->sys_version) != NULL && isIOSstub(TITLE_LOWER(tmd_data->sys_version))) + { + printf("\n This wad uses IOS%i, but the installed version\n is a stub.\n", TITLE_LOWER(tmd_data->sys_version)); + ret = -999; + goto err; + } + + if(get_title_ios(TITLE_ID(1, 2)) == tid) + { + if ( ( tmd_data->num_contents == 3) && (tmd_data->contents[0].type == 1 && tmd_data->contents[1].type == 0x8001 && tmd_data->contents[2].type == 0x8001) ) + { + printf("\n Will not install stub for System Menu\n"); + ret = -999; + goto err; + } + } + + if(tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | 'E')) || tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | 'P')) || tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | 'J')) || tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | 'K'))) + { + if ( ( tmd_data->num_contents == 3) && (tmd_data->contents[0].type == 1 && tmd_data->contents[1].type == 0x8001 && tmd_data->contents[2].type == 0x8001) ) + { + printf("\n Will not install stub for the EULA\n"); + ret = -999; + goto err; + } + } + + if(tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | 'E')) || tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | 'P')) || tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | 'J')) || tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | 'K'))) + { + if ( ( tmd_data->num_contents == 3) && (tmd_data->contents[0].type == 1 && tmd_data->contents[1].type == 0x8001 && tmd_data->contents[2].type == 0x8001) ) + { + printf("\n Will not install stub for the Region Select\n"); + ret = -999; + goto err; + } + } + if (tid == get_title_ios(TITLE_ID(0x10001, 0x48415858)) || tid == get_title_ios(TITLE_ID(0x10001, 0x4A4F4449))) + { + if ( ( tmd_data->num_contents == 3) && (tmd_data->contents[0].type == 1 && tmd_data->contents[1].type == 0x8001 && tmd_data->contents[2].type == 0x8001) ) + { + printf("\n Are you sure you want to install a stub for HBC?\n"); + printf("\n Press [A] to continue.\n"); + printf(" Press [B] to skip."); + + u32 buttons = WaitButtons(); + + if (!(buttons & WPAD_BUTTON_A)) + { + ret = -998; + goto err; + } + } + } + + if (tid == TITLE_ID(1, 2)) + { + if(get_sm_region_basic() == 0) + { + printf("\n Cannot determine region of System Menu\n"); + printf("\n Press [A] to continue.\n"); + printf(" Press [B] to skip."); + + u32 buttons = WaitButtons(); + + if (!(buttons & WPAD_BUTTON_A)) + { + ret = -999; + goto err; + } + } + int i, ret = -1; + for(i = 0; i <= NB_SM; i++) + { + if( regionlist[i].version == tmd_data->title_version) + { + ret = 1; + break; + } + } + if(ret -1) + { + printf("\n Cannot determine region of System Menu\n"); + printf("\n Press [A] to continue.\n"); + printf(" Press [B] to skip."); + + u32 buttons = WaitButtons(); + + if (!(buttons & WPAD_BUTTON_A)) + { + ret = -999; + goto err; + } + } + if( get_sm_region_basic() != regionlist[i].region) + { + printf("\n Cannot determine region of System Menu\n"); + printf("\n Press [A] to continue.\n"); + printf(" Press [B] to skip."); + + u32 buttons = WaitButtons(); + + if (!(buttons & WPAD_BUTTON_A)) + { + ret = -999; + goto err; + } + } + if(tmd_data->title_version < 416) + { + if(boot2version == 4) + { + printf("\n This version of the System Menu\n is not compatible with your Wii\n"); + ret = -999; + goto err; + } + } + } + + /* Fix ticket */ + __Wad_FixTicket(p_tik); + + printf("\t\t>> Install Ticket..."); + fflush(stdout); + + /* Install ticket */ + ret = ES_AddTicket(p_tik, header->tik_len, p_certs, header->certs_len, p_crl, header->crl_len); + if (ret < 0) + goto err; + + Con_ClearLine(); + + printf("\r\t\t>> Install Title..."); + fflush(stdout); + + /* Install title */ + ret = ES_AddTitleStart(p_tmd, header->tmd_len, p_certs, header->certs_len, p_crl, header->crl_len); + if (ret < 0) + goto err; + + /* Install contents */ + for (cnt = 0; cnt < tmd_data->num_contents; cnt++) { + tmd_content *content = &tmd_data->contents[cnt]; + + u32 idx = 0, len; + s32 cfd; + + Con_ClearLine(); + + printf("\r\t\t>> Install Content #%02d...", content->cid); + fflush(stdout); + + /* Encrypted content size */ + len = round_up(content->size, 64); + + /* Install content */ + cfd = ES_AddContentStart(tmd_data->title_id, content->cid); + if (cfd < 0) { + ret = cfd; + goto err; + } + + /* Install content data */ + while (idx < len) { + u32 size; + + /* Data length */ + size = (len - idx); + if (size > BLOCK_SIZE) + size = BLOCK_SIZE; + + /* Read data */ + ret = __Wad_ReadFile(fp, &wadBuffer, offset, size); + if (ret < 0) + goto err; + + /* Install data */ + ret = ES_AddContentData(cfd, wadBuffer, size); + if (ret < 0) + goto err; + + /* Increase variables */ + idx += size; + offset += size; + } + + /* Finish content installation */ + ret = ES_AddContentFinish(cfd); + if (ret < 0) + goto err; + } + + Con_ClearLine(); + + printf("\r\t\t>> Complete Installation..."); + fflush(stdout); + + /* Finish title install */ + ret = ES_AddTitleFinish(); + if (ret >= 0) + { + if(file->old_ios != file->new_ios || file->old_ahbprot != file->new_ahbprot || file->old_pass != file->new_pass) + { + Con_ClearLine(); + + printf("\r\t\t>> Patch TMD"); + fflush(stdout); + + ISFS_Initialize(); + + s32 fd; + + char filepath[ISFS_MAXPATH]; + sprintf(filepath, "/title/%08x/%08x/content/title.tmd", file->high_id, file->low_id); + + static fstats filestats ATTRIBUTE_ALIGN(32); + static u8 filearray[1024] ATTRIBUTE_ALIGN(32); + + fd = ISFS_Open(filepath, ISFS_OPEN_READ); + if (fd <= 0) + ISFS_Close(fd); + + ISFS_GetFileStats(fd, &filestats); + ISFS_Read(fd, filearray, filestats.file_length); + ISFS_Close(fd); + + if(filestats.file_length >= 0) + { + fd = ISFS_Open(filepath, ISFS_OPEN_RW); + + filearray[395] = file->new_ios; + if(file->new_ahbprot) + { + filearray[472] = 0; + filearray[473] = 0; + filearray[474] = 0; + filearray[475] = 3; + } + else + { + filearray[472] = 0; + filearray[473] = 0; + filearray[474] = 0; + filearray[475] = 0; + } + if(!file->new_pass) + filearray[417] = 0; + else + filearray[417] = 16; + + ISFS_Write(fd, filearray, sizeof( filearray )); + ISFS_Close(fd); + } + + ISFS_Deinitialize(); + } + + printf(" OK!\n"); + goto out; + } + +err: + printf(" Error! (ret = %d)\n", ret); + + /* Cancel install */ + ES_AddTitleCancel(); + +out: + /* Free memory */ + if (header) + free(header); + if (p_certs) + free(p_certs); + if (p_crl) + free(p_crl); + if (p_tik) + free(p_tik); + if (p_tmd) + free(p_tmd); + + return ret; +} + +s32 Wad_Uninstall(FILE *fp) +{ + wadHeader *header = NULL; + tikview *viewData = NULL; + + u64 tid; + u32 viewCnt; + s32 ret; + + printf("\t\t>> Reading WAD data..."); + fflush(stdout); + + /* WAD header */ + ret = __Wad_ReadAlloc(fp, (void *)&header, 0, sizeof(wadHeader)); + if (ret < 0) { + printf(" ERROR! (ret = %d)\n", ret); + goto out; + } + + /* Get title ID */ + ret = __Wad_GetTitleID(fp, header, &tid); + if (ret < 0) { + printf(" ERROR! (ret = %d)\n", ret); + goto out; + } + //Assorted Checks + if (TITLE_UPPER(tid) == 1 && get_title_ios(TITLE_ID(1, 2)) == 0) + { + printf("\n I can't determine the System Menus IOS\nDeleting system titles is disabled\n"); + ret = -999; + goto out; + } + if (tid == TITLE_ID(1, 1)) + { + printf("\n I won't try to uninstall boot2\n"); + ret = -999; + goto out; + } + if (tid == TITLE_ID(1, 2)) + { + printf("\n I won't uninstall the System Menu\n"); + ret = -999; + goto out; + } + if(get_title_ios(TITLE_ID(1, 2)) == tid) + { + printf("\n I won't uninstall the System Menus IOS\n"); + ret = -999; + goto out; + } + if (tid == get_title_ios(TITLE_ID(0x10001, 0x48415858)) || tid == get_title_ios(TITLE_ID(0x10001, 0x4A4F4449))) + { + printf("\n This is the HBCs IOS, uninstalling will break the HBC!\n"); + printf("\n Press A to continue.\n"); + printf(" Press B skip."); + + u32 buttons = WaitButtons(); + + if (!(buttons & WPAD_BUTTON_A)) + { + ret = -998; + goto out; + } + } + if((tid == TITLE_ID(0x10008, 0x48414B00 | 'E') || tid == TITLE_ID(0x10008, 0x48414B00 | 'P') || tid == TITLE_ID(0x10008, 0x48414B00 | 'J') || tid == TITLE_ID(0x10008, 0x48414B00 | 'K') + || (tid == TITLE_ID(0x10008, 0x48414C00 | 'E') || tid == TITLE_ID(0x10008, 0x48414C00 | 'P') || tid == TITLE_ID(0x10008, 0x48414C00 | 'J') || tid == TITLE_ID(0x10008, 0x48414C00 | 'K'))) && get_sm_region_basic() == 0) + { + printf("\n Can't get the SM region\n Please check the site for updates\n"); + ret = -999; + goto out; + } + if(tid == TITLE_ID(0x10008, 0x48414B00 | get_sm_region_basic())) + { + printf("\n I won't uninstall the EULA\n"); + ret = -999; + goto out; + } + if(tid == TITLE_ID(0x10008, 0x48414C00 | get_sm_region_basic())) + { + printf("\n I won't uninstall rgsel\n"); + ret = -999; + goto out; + } + if(tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | get_sm_region_basic()))) + { + printf("\n I won't uninstall the EULAs IOS\n"); + ret = -999; + goto out; + } + if(tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | get_sm_region_basic()))) + { + printf("\n I won't uninstall the rgsel IOS\n"); + ret = -999; + goto out; + } + + Con_ClearLine(); + + printf("\t\t>> Deleting tickets..."); + fflush(stdout); + + /* Get ticket views */ + ret = Title_GetTicketViews(tid, &viewData, &viewCnt); + if (ret < 0) + printf(" ERROR! (ret = %d)\n", ret); + + /* Delete tickets */ + if (ret >= 0) { + u32 cnt; + + /* Delete all tickets */ + for (cnt = 0; cnt < viewCnt; cnt++) { + ret = ES_DeleteTicket(&viewData[cnt]); + if (ret < 0) + break; + } + + if (ret < 0) + printf(" ERROR! (ret = %d\n", ret); + else + printf(" OK!\n"); + } + + printf("\t\t>> Deleting title contents..."); + fflush(stdout); + + /* Delete title contents */ + ret = ES_DeleteTitleContent(tid); + if (ret < 0) + printf(" ERROR! (ret = %d)\n", ret); + else + printf(" OK!\n"); + + + printf("\t\t>> Deleting title..."); + fflush(stdout); + + /* Delete title */ + ret = ES_DeleteTitle(tid); + if (ret < 0) + printf(" ERROR! (ret = %d)\n", ret); + else + printf(" OK!\n"); + +out: + /* Free memory */ + if (header) + free(header); + return ret; +} + +void Wad_Read(FILE *fp, int *ios, bool *ahbprot, bool *pass, u32 *high_id, u32 *low_id) +{ + wadHeader *header = NULL; + + /* WAD header */ + __Wad_ReadAlloc(fp, (void *)&header, 0, sizeof(wadHeader)); + __Wad_ReadFile(fp, &wadBuffer, 3328, header->tmd_len); + + + *ios = wadBuffer[395]; + if(ios > 0) + { + if(wadBuffer[472] == 0 && wadBuffer[473] == 0 && wadBuffer[474] == 0 && wadBuffer[475] == 3) + *ahbprot = true; + else + *ahbprot = false; + + if(wadBuffer[417] < 16) + *pass = false; + else + *pass = true; + + signed_blob *p_tmd = NULL; + + __Wad_ReadAlloc(fp, (void *)&p_tmd, 3328, header->tmd_len); + tmd *tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); + + *high_id = TITLE_UPPER(tmd_data->title_id); + *low_id = TITLE_LOWER(tmd_data->title_id); + + if (p_tmd) + free(p_tmd); + } + if (header) + free(header); +} diff --git a/source.en/wad.h b/source.en/wad.h new file mode 100644 index 0000000..4f4ca74 --- /dev/null +++ b/source.en/wad.h @@ -0,0 +1,9 @@ +#ifndef _WAD_H_ +#define _WAD_H_ +#include "fat.h" + +/* Prototypes */ +s32 Wad_Install(FILE *, fatFile *file); +s32 Wad_Uninstall(FILE *); +void Wad_Read(FILE *, int *ios, bool *ahbprot, bool *pass, u32 *high_id, u32 *low_id); +#endif diff --git a/source.en/wkb.c b/source.en/wkb.c new file mode 100644 index 0000000..f04ed68 --- /dev/null +++ b/source.en/wkb.c @@ -0,0 +1,47 @@ +#include "wkb.h" + +/* + +s32 USBKeyboard_Open(const eventcallback cb); +void USBKeyboard_Close(void); + +bool USBKeyboard_IsConnected(void); +s32 USBKeyboard_Scan(void); + +s32 USBKeyboard_SetLed(const USBKeyboard_led led, bool on); +s32 USBKeyboard_ToggleLed(const USBKeyboard_led led); +*/ + +s32 WkbInit(void) +{ + s32 retval = 0; + + retval = USBKeyboard_Initialize(); + + return (retval); + +} // WkbInit + +s32 WkbDeInit(void) +{ + s32 retval = 0; + + retval = USBKeyboard_Deinitialize(); + + return (retval); + +} // WkbDeInit + +u32 WkbWaitKey (void) +{ + u32 retval = 0; + + // Stub + return (retval); + +} // WkbWaitKey + +//void Wpad_Disconnect(void); +//u32 Wpad_GetButtons(void); + + diff --git a/source.en/wkb.h b/source.en/wkb.h new file mode 100644 index 0000000..568572f --- /dev/null +++ b/source.en/wkb.h @@ -0,0 +1,19 @@ +#ifndef _WKB_H_ +#define _WKB_H_ + +//#include +//#include +//#include +//#include +#include // u8, u16, etc... + +#include +#include + +/* Prototypes */ +s32 WkbInit(void); +u32 WkbWaitKey (void); +//void Wpad_Disconnect(void); +//u32 Wpad_GetButtons(void); + +#endif diff --git a/source.en/wpad.c b/source.en/wpad.c new file mode 100644 index 0000000..2d60dfe --- /dev/null +++ b/source.en/wpad.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include + +#include "sys.h" +#include "wpad.h" +//#include "wkb.h" + +/* Constants */ +#define MAX_WIIMOTES 4 + +int start; + +void __Wpad_PowerCallback(s32 chan) +{ + /* Poweroff console */ + Sys_Shutdown(); +} + + +s32 Wpad_Init(void) +{ + s32 ret; + + /* Initialize Wiimote subsystem */ + ret = WPAD_Init(); + if (ret < 0) + return ret; + + /* Set POWER button callback */ + WPAD_SetPowerButtonCallback(__Wpad_PowerCallback); + + return ret; +} + +void Wpad_Disconnect(void) +{ + u32 cnt; + + /* Disconnect Wiimotes */ + for (cnt = 0; cnt < MAX_WIIMOTES; cnt++) + WPAD_Disconnect(cnt); + + /* Shutdown Wiimote subsystem */ + WPAD_Shutdown(); +} + +u32 Wpad_GetButtons(void) +{ + u32 buttons = 0, cnt; + + /* Scan pads */ + WPAD_ScanPads(); + + /* Get pressed buttons */ + for (cnt = 0; cnt < MAX_WIIMOTES; cnt++) + buttons |= WPAD_ButtonsDown(cnt); + + return buttons; +} + +u32 Wpad_WaitButtons(void) +{ + u32 buttons = 0; + /* Wait for button pressing */ + while (!buttons) { + buttons = Wpad_GetButtons(); + VIDEO_WaitVSync(); + } + + return buttons; +} + +u32 Wpad_HeldButtons(void) +{ + u32 buttons = 0, cnt; + + /* Scan pads */ + WPAD_ScanPads(); + + /* Get pressed buttons */ + for (cnt = 0; cnt < MAX_WIIMOTES; cnt++) + buttons |= WPAD_ButtonsHeld(cnt); + + return buttons; +} + +bool Wpad_TimeButton(void) +{ + u32 buttons = 1; + + time_t start,end; + time (&start); + int dif; + /* Wait for button pressing */ + while (buttons) { + buttons = Wpad_HeldButtons(); + VIDEO_WaitVSync(); + time (&end); + dif = difftime (end,start); + if(dif>=2) return true; + } + return false; +} \ No newline at end of file diff --git a/source.en/wpad.h b/source.en/wpad.h new file mode 100644 index 0000000..913973d --- /dev/null +++ b/source.en/wpad.h @@ -0,0 +1,13 @@ +#ifndef _WPAD_H_ +#define _WPAD_H_ + +#include + +/* Prototypes */ +s32 Wpad_Init(void); +void Wpad_Disconnect(void); +u32 Wpad_GetButtons(void); +u32 Wpad_WaitButtons(void); +bool Wpad_TimeButton(void); + +#endif diff --git a/source.en/xyzzy.c b/source.en/xyzzy.c new file mode 100644 index 0000000..5ff3d09 --- /dev/null +++ b/source.en/xyzzy.c @@ -0,0 +1,173 @@ +/* xyzzy -- keydumper for Wii + + Copyright (C) 2008 bushing + Copyright (C) 2011 R2-D2199 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hollywood.h" +#include "gpio.h" +#include "xyzzy.h" + +#define eeprom_delay() udelay(5) +#define HAVE_AHBPROT ((*(vu32*)0xcd800064 == 0xFFFFFFFF) ? 1 : 0) + +keys *keys_bin; +void udelay(int us); + + + +static inline void set32(u32 addr, u32 set) +{ + write32(addr, read32(addr) | set); +} + +static inline void clear32(u32 addr, u32 clear) +{ + write32(addr, read32(addr)&(~clear)); +} + +void send_bits(int b, int bits) +{ + while(bits--) + { + if(b & (1 << bits)) + set32(HW_GPIO1OUT, GP_EEP_MOSI); + else + clear32(HW_GPIO1OUT, GP_EEP_MOSI); + eeprom_delay(); + set32(HW_GPIO1OUT, GP_EEP_CLK); + eeprom_delay(); + clear32(HW_GPIO1OUT, GP_EEP_CLK); + eeprom_delay(); + } +} + +int recv_bits(int bits) +{ + int res = 0; + while(bits--) + { + res <<= 1; + set32(HW_GPIO1OUT, GP_EEP_CLK); + eeprom_delay(); + clear32(HW_GPIO1OUT, GP_EEP_CLK); + eeprom_delay(); + res |= !!(read32(HW_GPIO1IN) & GP_EEP_MISO); + } + return res; +} + +int seeprom_read(void *dst, int offset, int size) +{ + int i; + u16 *ptr = (u16 *)dst; + u16 recv; + + if(size & 1) + return -1; + + clear32(HW_GPIO1OUT, GP_EEP_CLK); + clear32(HW_GPIO1OUT, GP_EEP_CS); + eeprom_delay(); + + for(i = 0; i < size; ++i) + { + set32(HW_GPIO1OUT, GP_EEP_CS); + send_bits((0x600 | (offset + i)), 11); + recv = recv_bits(16); + *ptr++ = recv; + clear32(HW_GPIO1OUT, GP_EEP_CS); + eeprom_delay(); + } + + return size; +} + +void crypto_read_otp(void) +{ + otp_t *otpd = memalign(32, sizeof(otp_t)); + u32 buffer[0x20]; + int i; + for (i=0; i< 0x20; i++) { + write32(HW_OTPCMD,0x80000000|i); + buffer[i] = read32(HW_OTPDATA); + } + memcpy(otpd, buffer, sizeof(otp_t)); + memcpy(keys_bin->boot1Hash, otpd->boot1_hash, sizeof(otpd->boot1_hash)); + memcpy(keys_bin->commonKey, otpd->common_key, sizeof(otpd->common_key)); + keys_bin->consoleID = otpd->ng_id; + snprintf(keys_bin->text, sizeof(keys_bin->text), "YAWMM_DE, ConsoleID: %08x", otpd->ng_id); + memset(keys_bin->text+29, 0, sizeof(keys_bin->text)-30); + memcpy(keys_bin->privateKey, otpd->ng_priv, sizeof(otpd->ng_priv)); + memcpy(keys_bin->nandHmac, otpd->nand_hmac, sizeof(otpd->nand_hmac)); + memcpy(keys_bin->nandKey, otpd->nand_key, sizeof(otpd->nand_key)); + memcpy(keys_bin->rngKey, otpd->rng_key, sizeof(otpd->rng_key)); + memcpy(keys_bin->nandKey, otpd->nand_key, sizeof(otpd->nand_key)); + keys_bin->unk1 = otpd->unk1; + keys_bin->unk2 = otpd->unk2; + free(otpd); +} + +void seeprom_read_seeprom(void) { + u32 buffer[sizeof(seeprom_t) / 4]; + seeprom_t *seeprom = memalign(32, sizeof(seeprom_t)); + seeprom_read(&buffer, 0, sizeof(seeprom_t) / 2); + memcpy(seeprom, buffer, sizeof(seeprom_t)); + + memset(keys_bin->blank, 0, 136); + keys_bin->ngKeyID = seeprom->ng_key_id; + memcpy(keys_bin->ngSig, seeprom->ng_sig, sizeof(seeprom->ng_sig)); + memset(keys_bin->blank2, 0, 440); + free(seeprom); +} + +int keydump() { + static char buf[128]; + snprintf(buf, 128, "sd:/keys.bin"); + FILE *fp = NULL; + fp = fopen(buf, "r"); + if (fp) { + fclose(fp); + return 0; + } + printf(" Dumpe keys.bin"); + keys_bin = memalign(32, sizeof(keys)); + printf("."); + crypto_read_otp(); + printf("."); + seeprom_read_seeprom(); + printf("."); + + fp = fopen(buf, "wb"); + printf("."); + if (fp) + { + fwrite((u8 *)keys_bin, 1, sizeof(keys), fp); + fclose(fp); + } + free(keys_bin); + printf("OK\n"); + return 0; +} diff --git a/source.en/xyzzy.h b/source.en/xyzzy.h new file mode 100644 index 0000000..d347422 --- /dev/null +++ b/source.en/xyzzy.h @@ -0,0 +1,74 @@ +typedef struct +{ + u8 boot1_hash[20]; + u8 common_key[16]; + u32 ng_id; + union { + struct { + u8 ng_priv[30]; + u8 _wtf1[18]; + }; + struct { + u8 _wtf2[28]; + u8 nand_hmac[20]; + }; + }; + u8 nand_key[16]; + u8 rng_key[16]; + u32 unk1; + u32 unk2; // 0x00000007 +} __attribute__((packed)) otp_t; + +typedef struct +{ + u8 boot2version; + u8 unknown1; + u8 unknown2; + u8 pad; + u32 update_tag; + u16 checksum; +} __attribute__((packed)) eep_ctr_t; + +typedef struct +{ + union { + struct { + u32 ms_id; + u32 ca_id; + u32 ng_key_id; + u8 ng_sig[60]; + eep_ctr_t counters[2]; + u8 fill[0x18]; + u8 korean_key[16]; + }; + u8 data[256]; + }; +} __attribute__((packed)) seeprom_t; + +typedef struct { + char text[0x100]; + u8 boot1Hash[20]; + u8 commonKey[16]; + u32 consoleID; + union { + struct { + u8 privateKey[30]; + u8 _wtf1[18]; + }; + struct { + u8 _wtf2[28]; + u8 nandHmac[20]; + }; + }; + u8 nandKey[16]; + u8 rngKey[16]; + u32 unk1; + u32 unk2; // 0x00000007 + char blank[136]; + u32 ngKeyID; + u8 ngSig[60]; + char blank2[440]; + +} keys; + +int keydump(); \ No newline at end of file