2011-07-24 18:32:09 +02:00
|
|
|
/*****************************************
|
|
|
|
* This code is from Mighty Channel 11
|
|
|
|
* which is based on the TriiForce source.
|
2011-07-26 10:57:12 +02:00
|
|
|
* Modifications by Dimok.
|
2011-07-24 18:32:09 +02:00
|
|
|
*****************************************/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ogcsys.h>
|
|
|
|
#include <malloc.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2011-07-26 10:57:12 +02:00
|
|
|
#include "system/IosLoader.h"
|
2011-11-12 19:14:09 +01:00
|
|
|
#include "utils/tools.h"
|
2011-07-24 18:32:09 +02:00
|
|
|
#include "gecko.h"
|
2011-07-26 10:57:12 +02:00
|
|
|
#include "NandEmu.h"
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 10:57:12 +02:00
|
|
|
/* 'NAND Device' structure */
|
|
|
|
typedef struct {
|
|
|
|
/* Device name */
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
/* Mode value */
|
|
|
|
u32 mode;
|
|
|
|
|
|
|
|
/* Un/mount command */
|
|
|
|
u32 mountCmd;
|
|
|
|
u32 umountCmd;
|
|
|
|
} nandDevice;
|
2011-07-24 18:32:09 +02:00
|
|
|
|
|
|
|
static nandDevice ndevList[] =
|
|
|
|
{
|
2011-07-26 00:28:22 +02:00
|
|
|
{ "Disable", 0, 0x00, 0x00 },
|
|
|
|
{ "SD/SDHC Card", 1, 0xF0, 0xF1 },
|
|
|
|
{ "USB 2.0 Mass Storage Device", 2, 0xF2, 0xF3 },
|
2011-07-24 18:32:09 +02:00
|
|
|
};
|
|
|
|
|
2011-07-26 10:57:12 +02:00
|
|
|
/* Buffer */
|
|
|
|
static const char fs[] ATTRIBUTE_ALIGN(32) = "/dev/fs";
|
|
|
|
static const char fat[] ATTRIBUTE_ALIGN(32) = "fat";
|
2013-01-06 14:41:22 +01:00
|
|
|
static u32 inbuf[8] ATTRIBUTE_ALIGN(32);
|
2011-11-12 19:14:09 +01:00
|
|
|
static u32 partition ATTRIBUTE_ALIGN(32) = 0;
|
|
|
|
static u32 mode ATTRIBUTE_ALIGN(32) = 0;
|
|
|
|
static char path[32] ATTRIBUTE_ALIGN(32) = "\0";
|
2011-07-24 18:32:09 +02:00
|
|
|
static int fullmode = 0;
|
2011-11-12 19:14:09 +01:00
|
|
|
static int mounted = 0;
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 10:57:12 +02:00
|
|
|
static s32 Nand_Mount(nandDevice *dev)
|
2011-07-24 18:32:09 +02:00
|
|
|
{
|
2011-07-26 00:28:22 +02:00
|
|
|
s32 fd, ret;
|
2013-01-06 14:41:22 +01:00
|
|
|
u32 inlen = 0;
|
2011-07-26 00:28:22 +02:00
|
|
|
ioctlv *vector = NULL;
|
2013-01-06 14:41:22 +01:00
|
|
|
int rev = IOS_GetRevision();
|
2011-07-26 00:28:22 +02:00
|
|
|
|
|
|
|
/* Open FAT module */
|
|
|
|
fd = IOS_Open(fat, 0);
|
|
|
|
if (fd < 0)
|
|
|
|
return fd;
|
|
|
|
|
2011-07-26 10:57:12 +02:00
|
|
|
|
2013-10-01 23:13:08 +02:00
|
|
|
if(rev >= 21 && rev != 65280) // stub version from nintendo
|
2011-11-12 19:14:09 +01:00
|
|
|
{
|
2013-01-06 14:41:22 +01:00
|
|
|
// NOTE:
|
|
|
|
// The official cIOSX rev21 by Waninkoko ignores the partition argument
|
2023-01-01 18:00:17 +01:00
|
|
|
// and the NAND is always expected to be on the 1st partition.
|
2013-01-06 14:41:22 +01:00
|
|
|
// However this way earlier d2x betas having revision 21 take in
|
|
|
|
// consideration the partition argument.
|
|
|
|
inlen = 1;
|
|
|
|
|
|
|
|
/* Allocate memory */
|
|
|
|
vector = (ioctlv *) memalign(32, sizeof(ioctlv));
|
|
|
|
if(vector == NULL)
|
|
|
|
{
|
|
|
|
/* Close FAT module */
|
|
|
|
IOS_Close(fd);
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector[0].data = &partition;
|
|
|
|
vector[0].len = sizeof(u32);
|
2011-11-12 19:14:09 +01:00
|
|
|
}
|
2011-07-26 00:28:22 +02:00
|
|
|
/* Mount device */
|
2013-01-06 14:41:22 +01:00
|
|
|
ret = IOS_Ioctlv(fd, dev->mountCmd, inlen, 0, vector);
|
2011-07-26 00:28:22 +02:00
|
|
|
|
|
|
|
/* Close FAT module */
|
2011-09-03 11:39:26 +02:00
|
|
|
IOS_Close(fd);
|
2011-07-26 00:28:22 +02:00
|
|
|
|
|
|
|
/* Free memory */
|
2011-11-12 19:14:09 +01:00
|
|
|
free(vector);
|
2011-07-26 00:28:22 +02:00
|
|
|
|
|
|
|
return ret;
|
2011-07-24 18:32:09 +02:00
|
|
|
}
|
|
|
|
|
2011-07-26 10:57:12 +02:00
|
|
|
static s32 Nand_Unmount(nandDevice *dev)
|
2011-07-24 18:32:09 +02:00
|
|
|
{
|
2011-07-26 00:28:22 +02:00
|
|
|
s32 fd, ret;
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
// Open FAT module
|
|
|
|
fd = IOS_Open(fat, 0);
|
|
|
|
if (fd < 0)
|
|
|
|
return fd;
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
// Unmount device
|
|
|
|
ret = IOS_Ioctlv(fd, dev->umountCmd, 0, 0, NULL);
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
// Close FAT module
|
|
|
|
IOS_Close(fd);
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
return ret;
|
2011-07-24 18:32:09 +02:00
|
|
|
}
|
|
|
|
|
2011-07-26 10:57:12 +02:00
|
|
|
static s32 Nand_Enable(nandDevice *dev)
|
2011-07-24 18:32:09 +02:00
|
|
|
{
|
2011-07-26 00:28:22 +02:00
|
|
|
s32 fd, ret;
|
2011-11-12 19:14:09 +01:00
|
|
|
ioctlv *vector = NULL;
|
2013-01-06 14:41:22 +01:00
|
|
|
int rev = IOS_GetRevision();
|
2011-07-26 00:28:22 +02:00
|
|
|
|
|
|
|
// Open /dev/fs
|
|
|
|
fd = IOS_Open(fs, 0);
|
|
|
|
if (fd < 0)
|
|
|
|
return fd;
|
|
|
|
|
2013-01-06 14:41:22 +01:00
|
|
|
if (IOS_GetRevision() >= 18)
|
2011-11-12 19:14:09 +01:00
|
|
|
{
|
2013-01-06 14:41:22 +01:00
|
|
|
//FULL NAND emulation since rev18
|
|
|
|
//needed for reading images on triiforce mrc folder using ISFS commands
|
|
|
|
mode = dev->mode | fullmode;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mode = dev->mode;
|
2011-11-12 19:14:09 +01:00
|
|
|
}
|
2011-07-26 10:57:12 +02:00
|
|
|
|
2013-10-01 23:13:08 +02:00
|
|
|
if(rev >= 21 && rev != 65280) // stub version from nintendo
|
2013-01-06 14:41:22 +01:00
|
|
|
{
|
|
|
|
// NOTE:
|
|
|
|
// The official cIOSX rev21 by Waninkoko provides an undocumented feature
|
2023-01-01 18:00:17 +01:00
|
|
|
// to set NAND path when mounting the device.
|
2013-01-06 14:41:22 +01:00
|
|
|
// This feature has been discovered during d2x development.
|
|
|
|
|
|
|
|
/* Allocate memory */
|
|
|
|
vector = (ioctlv *)memalign(32, sizeof(ioctlv)*2);
|
|
|
|
if(vector == NULL)
|
|
|
|
{
|
|
|
|
/* Close FAT module */
|
|
|
|
IOS_Close(fd);
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector[0].data = &mode;
|
|
|
|
vector[0].len = sizeof(u32);
|
|
|
|
vector[1].data = path;
|
|
|
|
vector[1].len = sizeof(path);
|
|
|
|
|
|
|
|
ret = IOS_Ioctlv(fd, 100, 2, 0, vector);
|
|
|
|
|
|
|
|
/* Free memory */
|
|
|
|
free(vector);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memset(inbuf, 0, sizeof(inbuf));
|
|
|
|
inbuf[0] = dev->mode;
|
|
|
|
ret = IOS_Ioctl(fd, 100, inbuf, sizeof(inbuf), NULL, 0);
|
|
|
|
}
|
2011-07-26 00:28:22 +02:00
|
|
|
|
|
|
|
// Close /dev/fs
|
|
|
|
IOS_Close(fd);
|
|
|
|
|
|
|
|
return ret;
|
2011-07-24 18:32:09 +02:00
|
|
|
}
|
|
|
|
|
2011-07-26 10:57:12 +02:00
|
|
|
static s32 Nand_Disable(void)
|
2011-07-24 18:32:09 +02:00
|
|
|
{
|
2011-07-26 00:28:22 +02:00
|
|
|
s32 fd, ret;
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
// Open /dev/fs
|
|
|
|
fd = IOS_Open(fs, 0);
|
|
|
|
if (fd < 0)
|
|
|
|
return fd;
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
// Set input buffer
|
2011-11-12 19:14:09 +01:00
|
|
|
mode = 0;
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
// Disable NAND emulator
|
2011-11-12 19:14:09 +01:00
|
|
|
ret = IOS_Ioctl(fd, 100, &mode, sizeof(mode), NULL, 0);
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
// Close /dev/fs
|
|
|
|
IOS_Close(fd);
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
return ret;
|
2011-07-24 18:32:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
s32 Enable_Emu(int selection)
|
|
|
|
{
|
2013-01-06 14:41:22 +01:00
|
|
|
if(!IosLoader::IsD2X() && IOS_GetRevision() < 17)
|
2011-07-29 22:59:31 +02:00
|
|
|
return -1;
|
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
if(mounted != 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
s32 ret;
|
|
|
|
nandDevice *ndev = NULL;
|
|
|
|
ndev = &ndevList[selection];
|
|
|
|
|
|
|
|
ret = Nand_Mount(ndev);
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
gprintf(" ERROR Mount! (ret = %d)\n", ret);
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = Nand_Enable(ndev);
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
gprintf(" ERROR Enable! (ret = %d)\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
mounted = selection;
|
|
|
|
return 0;
|
2011-07-24 18:32:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
s32 Disable_Emu()
|
|
|
|
{
|
2013-01-06 14:41:22 +01:00
|
|
|
if(!IosLoader::IsD2X() && IOS_GetRevision() < 17)
|
2011-07-29 22:59:31 +02:00
|
|
|
return -1;
|
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
if(mounted==0)
|
|
|
|
return 0;
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
nandDevice *ndev = NULL;
|
|
|
|
ndev = &ndevList[mounted];
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
Nand_Disable();
|
|
|
|
Nand_Unmount(ndev);
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
mounted = 0;
|
2011-07-24 18:32:09 +02:00
|
|
|
|
2011-07-26 00:28:22 +02:00
|
|
|
return 0;
|
2011-07-24 18:32:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Set_Partition(int p)
|
|
|
|
{
|
2011-07-26 00:28:22 +02:00
|
|
|
partition = p;
|
2011-07-24 18:32:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Set_Path(const char* p)
|
|
|
|
{
|
2011-07-26 00:28:22 +02:00
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
while(p[i] != '\0' && i < 31)
|
|
|
|
{
|
|
|
|
path[i] = p[i];
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
while(path[i-1] == '/')
|
|
|
|
{
|
|
|
|
path[i-1] = '\0';
|
|
|
|
--i;
|
|
|
|
}
|
|
|
|
path[i] = '\0';
|
2011-07-24 18:32:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Set_FullMode(int fm)
|
|
|
|
{
|
2011-07-26 00:28:22 +02:00
|
|
|
fullmode = fm ? 0x100 : 0;
|
2011-07-24 18:32:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const char* Get_Path(void)
|
|
|
|
{
|
2011-07-26 00:28:22 +02:00
|
|
|
return path;
|
2011-07-24 18:32:09 +02:00
|
|
|
}
|