shieldD revolution dvd/nand mostly done (#2922)

* shieldD revo dvd mostly done

* shieldD revo nand mostly done

* shieldD revo fs mostly done

* shieldD revo ipc mostly done

* shieldD revo sdk pad done
This commit is contained in:
TakaRikka 2025-12-08 02:44:29 -08:00 committed by GitHub
parent 251d49c6f1
commit 353721578d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
53 changed files with 11021 additions and 135 deletions

View File

@ -4330,7 +4330,7 @@ revolution/dvd/dvdDeviceError.c:
.rodata start:0x8065EA50 end:0x8065EA70
.data start:0x8073A040 end:0x8073A1D8
.sdata start:0x8074BFE0 end:0x8074BFE8
.sbss start:0x8074D530 end:0x8074D53C
.sbss start:0x8074D530 end:0x8074D538
.sdata2 start:0x80752E30 end:0x80752E38
.bss start:0x80801880 end:0x808018A0
@ -4338,7 +4338,7 @@ revolution/dvd/dvd_broadway.c:
.text start:0x80607A70 end:0x80609A20
.data start:0x8073A1D8 end:0x8073B118
.sdata start:0x8074BFE8 end:0x8074BFF8
.sbss start:0x8074D53C end:0x8074D560
.sbss start:0x8074D538 end:0x8074D560
.bss start:0x808018A0 end:0x80801A20
revolution/ai/ai.c:
@ -4412,7 +4412,7 @@ revolution/sc/scsystem.c:
.rodata start:0x8065EE18 end:0x8065EE70
.data start:0x8073DB08 end:0x8073DDB0
.sdata start:0x8074C078 end:0x8074C1C0
.sbss start:0x8074D5EC end:0x8074D604
.sbss start:0x8074D5EC end:0x8074D600
.bss start:0x80801DC0 end:0x80809F60
revolution/sc/scapi.c:
@ -4435,7 +4435,7 @@ revolution/esp/esp.c:
revolution/ipc/ipcMain.c:
.text start:0x80612240 end:0x806123B0
.data start:0x8073DE10 end:0x8073DE48
.sbss start:0x8074D604 end:0x8074D618
.sbss start:0x8074D600 end:0x8074D618
revolution/ipc/ipcclt.c:
.text start:0x806123B0 end:0x80613CC0

View File

@ -397,6 +397,7 @@ cflags_revolution_retail = [
cflags_revolution_debug = [
*cflags_revolution_base,
"-opt off",
"-inline off",
"-DDEBUG=1",
]
@ -1497,6 +1498,52 @@ config.libs = [
Object(MatchingFor("ShieldD"), "revolution/os/__ppc_eabi_init.cpp"),
],
),
RevolutionLib(
"dvd",
[
Object(NonMatching, "revolution/dvd/dvdfs.c", extra_cflags=["-char signed"]),
Object(NonMatching, "revolution/dvd/dvd.c", extra_cflags=["-char signed"]),
Object(NonMatching, "revolution/dvd/dvdqueue.c", extra_cflags=["-char signed"]),
Object(NonMatching, "revolution/dvd/dvderror.c", extra_cflags=["-char signed"]),
Object(NonMatching, "revolution/dvd/dvdidutils.c", extra_cflags=["-char signed"]),
Object(NonMatching, "revolution/dvd/dvdFatal.c", extra_cflags=["-char signed"]),
Object(NonMatching, "revolution/dvd/dvdDeviceError.c", extra_cflags=["-char signed"]),
Object(NonMatching, "revolution/dvd/dvd_broadway.c", extra_cflags=["-char signed"]),
],
),
RevolutionLib(
"nand",
[
Object(NonMatching, "revolution/nand/nand.c"),
Object(NonMatching, "revolution/nand/NANDOpenClose.c"),
Object(NonMatching, "revolution/nand/NANDCore.c"),
Object(NonMatching, "revolution/nand/NANDCheck.c"),
Object(NonMatching, "revolution/nand/NANDLogging.c"),
Object(NonMatching, "revolution/nand/NANDErrorMessage.c"),
],
),
RevolutionLib(
"fs",
[
Object(NonMatching, "revolution/fs/fs.c"),
],
),
RevolutionLib(
"ipc",
[
Object(NonMatching, "revolution/ipc/ipcMain.c"),
Object(NonMatching, "revolution/ipc/ipcclt.c"),
Object(NonMatching, "revolution/ipc/memory.c"),
Object(NonMatching, "revolution/ipc/ipcProfile.c"),
],
),
RevolutionLib(
"pad",
[
Object(NonMatching, "revolution/pad/Padclamp.c"),
Object(NonMatching, "revolution/pad/Pad.c"),
],
),
{
"lib": "Runtime.PPCEABI.H",
"mw_version": MWVersion(config.version),

View File

@ -66,6 +66,8 @@ extern "C" {
#define DVD_COMMAND_BS_CHANGE_DISK 15
#define DVD_COMMAND_UNK_16 16
#define DVD_RESETCOVER_TIMELAG_TICKS2 OSMillisecondsToTicks(100)
typedef struct DVDDiskID {
char gameName[4];
char company[2];
@ -137,6 +139,29 @@ typedef struct DVDDriveInfo {
/* 0x08 */ u8 padding[24];
} DVDDriveInfo;
typedef struct DVDCommandInfo DVDCommandInfo;
struct DVDCommandInfo {
u32 command;
u32 offset;
u32 length;
u32 intType;
u32 tick;
};
typedef struct DVDErrorInfo DVDErrorInfo;
struct DVDErrorInfo {
char gameName[4];
u8 diskNumber;
u8 gameVersion;
u8 reserved0[2];
u32 error;
u32 dateTime;
u32 status;
u32 unk_0x14;
u32 nextOffset;
DVDCommandInfo lastCommand[5];
};
typedef struct DVDGamePartition {
ESTicket ticket;
u32 tmdSize;
@ -157,25 +182,50 @@ typedef struct DVDGameTOC {
DVDPartitionInfo* partitionInfos;
} DVDGameTOC;
#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1))
typedef struct DVDPartitionParams DVDPartitionParams;
struct DVDPartitionParams {
ESTicket ticket;
u8 padding0[ROUND(sizeof(ESTicket), 32) - sizeof(ESTicket)];
ESTicketView ticketView;
u8 padding1[ROUND(sizeof(ESTicketView), 32) - sizeof(ESTicketView)];
u32 numTmdBytes;
u8 padding2[28];
ESTitleMeta tmd;
u8 padding3[ROUND(sizeof(ESTitleMeta), 32) - sizeof(ESTitleMeta)];
u32 numCertBytes;
u8 padding4[28];
u8 certificates[4096];
u32 dataWordOffset;
u8 padding5[28];
u8 h3Hash[98304];
};
typedef struct diRegVals {
u32 ImmRegVal;
u32 CoverRegVal;
u32 pad[6];
} diRegVals_t;
typedef struct diCommand {
u8 theCommand;
u8 pad1[3];
u32 arg[5];
u32 pad2[2];
} diCommand_t;
typedef struct DVDVideoReportKey {
u8 data[32];
} DVDVideoReportKey;
// DVD
void DVDInit(void);
int DVDReadAbsAsyncPrio(DVDCommandBlock* block, void* addr, s32 length, s32 offset, DVDCBCallback callback, s32 prio);
int DVDSeekAbsAsyncPrio(DVDCommandBlock* block, s32 offset, DVDCBCallback callback, s32 prio);
int DVDReadAbsAsyncForBS(DVDCommandBlock* block, void* addr, s32 length, s32 offset, DVDCBCallback callback);
int DVDReadDiskID(DVDCommandBlock* block, DVDDiskID* diskID, DVDCBCallback callback);
int DVDPrepareStreamAbsAsync(DVDCommandBlock* block, u32 length, u32 offset, DVDCBCallback callback);
int DVDCancelStreamAsync(DVDCommandBlock* block, DVDCBCallback callback);
s32 DVDCancelStream(DVDCommandBlock* block);
int DVDStopStreamAtEndAsync(DVDCommandBlock* block, DVDCBCallback callback);
s32 DVDStopStreamAtEnd(DVDCommandBlock* block);
int DVDGetStreamErrorStatusAsync(DVDCommandBlock* block, DVDCBCallback callback);
s32 DVDGetStreamErrorStatus(DVDCommandBlock* block);
int DVDGetStreamPlayAddrAsync(DVDCommandBlock* block, DVDCBCallback callback);
s32 DVDGetStreamPlayAddr(DVDCommandBlock* block);
int DVDGetStreamStartAddrAsync(DVDCommandBlock* block, DVDCBCallback callback);
s32 DVDGetStreamStartAddr(DVDCommandBlock* block);
int DVDGetStreamLengthAsync(DVDCommandBlock* block, DVDCBCallback callback);
s32 DVDGetStreamLength(DVDCommandBlock* block);
int DVDChangeDiskAsyncForBS(DVDCommandBlock* block, DVDCBCallback callback);
int DVDChangeDiskAsync(DVDCommandBlock* block, DVDDiskID* id, DVDCBCallback callback);
s32 DVDChangeDisk(DVDCommandBlock* block, DVDDiskID* id);
@ -191,7 +241,7 @@ BOOL DVDSetAutoInvalidation(BOOL autoInval);
void DVDPause(void);
void DVDResume(void);
int DVDCancelAsync(DVDCommandBlock* block, DVDCBCallback callback);
s32 DVDCancel(volatile DVDCommandBlock* block);
s32 DVDCancel(DVDCommandBlock* block);
int DVDCancelAllAsync(DVDCBCallback callback);
s32 DVDCancelAll(void);
DVDDiskID* DVDGetCurrentDiskID(void);
@ -199,6 +249,7 @@ BOOL DVDCheckDisk(void);
// DVD FATAL
int DVDSetAutoFatalMessaging(BOOL enable);
BOOL __DVDGetAutoFatalMessaging(void);
// DVD FS
s32 DVDConvertPathToEntrynum(const char* pathPtr);
@ -218,9 +269,6 @@ int DVDOpenDir(const char* dirName, DVDDir* dir);
int DVDReadDir(DVDDir* dir, DVDDirEntry* dirent);
int DVDCloseDir(DVDDir* dir);
void DVDRewindDir(DVDDir* dir);
void* DVDGetFSTLocation(void);
BOOL DVDPrepareStreamAsync(DVDFileInfo* fileInfo, u32 length, u32 offset, DVDCallback callback);
s32 DVDPrepareStream(DVDFileInfo* fileInfo, u32 length, u32 offset);
s32 DVDGetTransferredSize(DVDFileInfo* fileinfo);
#define DVDReadAsync(fileInfo, addr, length, offset, callback) \
@ -233,16 +281,11 @@ DVDDiskID* DVDGenerateDiskID(DVDDiskID* id, const char* game, const char* compan
// DVD LOW
BOOL DVDLowRead(void* addr, u32 length, u32 offset, DVDLowCallback callback);
BOOL DVDLowSeek(u32 offset, DVDLowCallback callback);
BOOL DVDLowWaitCoverClose(DVDLowCallback callback);
BOOL DVDLowReadDiskID(DVDDiskID* diskID, DVDLowCallback callback);
BOOL DVDLowStopMotor(DVDLowCallback callback);
BOOL DVDLowRequestError(DVDLowCallback callback);
BOOL DVDLowInquiry(DVDDriveInfo* info, DVDLowCallback callback);
BOOL DVDLowAudioStream(u32 subcmd, u32 length, u32 offset, DVDLowCallback callback);
BOOL DVDLowRequestAudioStatus(u32 subcmd, DVDLowCallback callback);
BOOL DVDLowAudioBufferConfig(BOOL enable, u32 size, DVDLowCallback callback);
void DVDLowReset(void);
DVDLowCallback DVDLowSetResetCoverCallback(DVDLowCallback callback);
BOOL DVDLowAudioBufferConfig(u8 enable, u32 size, DVDLowCallback callback);
BOOL DVDLowReset(DVDLowCallback callback);
BOOL DVDLowBreak(void);
DVDLowCallback DVDLowClearCallback(void);
u32 DVDLowGetCoverStatus(void);
@ -250,8 +293,24 @@ u32 DVDLowGetCoverStatus(void);
// DVD QUEUE
void DVDDumpWaitingQueue(void);
// unsorted revo
// DVD BROADWAY
BOOL DVDLowFinalize(void);
BOOL DVDLowInit(void);
BOOL DVDLowUnmaskStatusInterrupts(void);
BOOL DVDLowMaskCoverInterrupt(void);
BOOL DVDLowClearCoverInterrupt(DVDLowCallback callback);
BOOL DVDLowSetSpinupFlag(u32 spinUp);
u32 DVDLowGetImmBufferReg(void);
BOOL DVDLowSetMaximumRotation(u32 subcmd, DVDLowCallback callback);
u32 DVDLowGetCoverRegister(void);
BOOL DVDLowPrepareCoverRegister(DVDLowCallback callback);
BOOL DVDLowGetNoDiscBufferSizes(const u32 partitionWordOffset, u32* numTmdBytes, u32* numCertBytes, DVDLowCallback callback);
BOOL DVDLowGetNoDiscOpenPartitionParams(const u32 partitionWordOffset, ESTicket* eTicket, u32* numTmdBytes, ESTitleMeta* tmd, u32* numCertBytes, u8* certificates, u32* dataWordOffset, u8* h3HashPtr, DVDLowCallback callback);
BOOL DVDLowReportKey(DVDVideoReportKey* reportKey, u32 format, u32 lsn, DVDLowCallback callback);
u32 DVDLowGetControlRegister(void);
u32 DVDLowGetStatusRegister(void);
BOOL DVDLowPrepareControlRegister(DVDLowCallback callback);
BOOL DVDLowPrepareStatusRegister(DVDLowCallback callback);
BOOL DVDLowUnencryptedRead(void*, u32, u32, DVDLowCallback);
BOOL DVDLowClosePartition(DVDLowCallback);
BOOL DVDLowOpenPartitionWithTmdAndTicketView(const u32, const ESTicketView* const, const u32, const ESTitleMeta* const, const u32, const u8* const, DVDLowCallback);

100
include/revolution/fs.h Normal file
View File

@ -0,0 +1,100 @@
#ifndef _REVOLUTION_FS_H_
#define _REVOLUTION_FS_H_
#include <revolution/types.h>
#include <revolution/private/iostypes.h>
#include <revolution/private/iosrestypes.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ISFS_ERROR_OK 0
#define ISFS_ERROR_INVALID -101
#define ISFS_ERROR_ACCESS -102
#define ISFS_ERROR_CORRUPT -103
#define ISFS_ERROR_NOTREADY -104
#define ISFS_ERROR_EXISTS -105
#define ISFS_ERROR_NOEXISTS -106
#define ISFS_ERROR_MAXFILES -107
#define ISFS_ERROR_MAXBLOCKS -108
#define ISFS_ERROR_MAXFD -109
#define ISFS_ERROR_MAXDEPTH -110
#define ISFS_ERROR_OPENFD -111
#define ISFS_ERROR_BADBLOCK -112
#define ISFS_ERROR_ECC -113
#define ISFS_ERROR_ECC_CRIT -114
#define ISFS_ERROR_NOTEMPTY -115
#define ISFS_ERROR_HMAC -116
#define ISFS_ERROR_UNKNOWN -117
#define ISFS_ERROR_BUSY -118
#define ISFS_ERROR_SHUTDOWN -119
#define ISFS_INODE_NAMELEN 12
typedef s32 ISFSError;
typedef void (*ISFSCallback) (ISFSError, void *ctxt);
typedef struct {
u32 blockSize;
u32 freeBlocks;
u32 occupiedBlcocks;
u32 badBlocks;
u32 reservedBlocks;
u32 freeInodes;
u32 occupedInodes;
} ISFSStats;
typedef struct {
u32 size;
u32 offset;
} ISFSFileStats;
typedef struct {
IOSUid ownerId;
IOSGid groupId;
u8 path[64];
u8 ownerAccess;
u8 groupAccess;
u8 othersAccess;
u8 attr;
} ISFSPathAttrArgs;
typedef struct {
u8 path1[64];
u8 path2[64];
} ISFSPathsArgs;
ISFSError ISFS_OpenLib(void);
s32 ISFS_CreateDir(const u8* dname, u32 dirAttr, u32 ownerAcc, u32 groupAcc, u32 othersAcc);
s32 ISFS_CreateDirAsync(const u8* dname, u32 dirAttr, u32 ownerAcc, u32 groupAcc, u32 othersAcc, ISFSCallback cb, void* fsCtxt);
s32 ISFS_ReadDir(const u8* dname, u8* nameList, u32* num);
s32 ISFS_ReadDirAsync(const u8* dname, u8* nameList, u32* num, ISFSCallback cb, void* fsCtxt);
s32 ISFS_GetAttr(const u8* name, IOSUid* ownerId, IOSGid* groupId, u32* attr, u32* ownerAcc, u32* groupAcc, u32* othersAcc);
s32 ISFS_GetAttrAsync(const u8* name, IOSUid* ownerId, IOSGid* groupId, u32* attr, u32* ownerAcc, u32* groupAcc, u32* othersAcc, ISFSCallback cb, void* fsCtxt);
s32 ISFS_Delete(const u8* name);
s32 ISFS_DeleteAsync(const u8* name, ISFSCallback cb, void* fsCtxt);
s32 ISFS_Rename(const u8* oldName, const u8* newName);
s32 ISFS_RenameAsync(const u8* oldName, const u8* newName, ISFSCallback cb, void* fsCtxt);
s32 ISFS_GetUsage(const u8* dname, u32* nblocks, u32* ninodes);
s32 ISFS_CreateFile(const u8* fname, u32 fileAttr, u32 ownerAcc, u32 groupAcc, u32 othersAcc);
s32 ISFS_CreateFileAsync(const u8* fname, u32 fileAttr, u32 ownerAcc, u32 groupAcc, u32 othersAcc, ISFSCallback cb, void* fsCtxt);
IOSFd ISFS_Open(const u8* fname, u32 access);
IOSFd ISFS_OpenAsync(const u8* fname, u32 access, ISFSCallback cb, void* fsCtxt);
s32 ISFS_GetFileStats(IOSFd fd, ISFSFileStats* stats);
s32 ISFS_GetFileStatsAsync(IOSFd fd, ISFSFileStats* stats, ISFSCallback cb, void* fsCtxt);
s32 ISFS_Seek(IOSFd fd, s32 offset, u32 whence);
s32 ISFS_SeekAsync(IOSFd fd, s32 offset, u32 whence, ISFSCallback cb, void* fsCtxt);
s32 ISFS_Read(s32 fd, u8* pBuffer, u32 bufSize);
s32 ISFS_ReadAsync(IOSFd fd, u8* buf, u32 size, ISFSCallback cb, void* fsCtxt);
s32 ISFS_Write(IOSFd fd, const u8* buf, u32 size);
s32 ISFS_WriteAsync(IOSFd fd, const u8* buf, u32 size, ISFSCallback cb, void* fsCtxt);
s32 ISFS_Close(IOSFd fd);
s32 ISFS_CloseAsync(IOSFd fd, ISFSCallback cb, void* fsCtxt);
s32 ISFS_ShutdownAsync(ISFSCallback cb, void* fsCtxt);
#ifdef __cplusplus
}
#endif
#endif // _REVOLUTION_FS_H_

24
include/revolution/ipc.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef _REVOLUTION_IPC_H_
#define _REVOLUTION_IPC_H_
#include <revolution/ipc/ipcclt.h>
#include <revolution/ipc/ipcProfile.h>
#include <revolution/ipc/memory.h>
#ifdef __cplusplus
extern "C" {
#endif
void IPCInit(void);
void IPCReInit(void);
u32 IPCReadReg(u32 regIdx);
void IPCWriteReg(u32 regIdx, u32 data);
void* IPCGetBufferHi(void);
void* IPCGetBufferLo(void);
void IPCSetBufferLo(void* newLo);
#ifdef __cplusplus
}
#endif
#endif // _REVOLUTION_IPC_H_

View File

@ -0,0 +1,19 @@
#ifndef _REVOLUTION_IPCPROFILE_H_
#define _REVOLUTION_IPCPROFILE_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <revolution/types.h>
void IPCiProfInit(void);
void IPCiProfQueueReq(void* req, s32 handle);
void IPCiProfReply(void* req, s32 handle);
void IPCiProfAck(void);
#ifdef __cplusplus
}
#endif
#endif // _REVOLUTION_IPCPROFILE_H_

View File

@ -0,0 +1,37 @@
#ifndef _REVOLUTION_IPCCLT_H_
#define _REVOLUTION_IPCCLT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <revolution/types.h>
#include <revolution/private/iosrestypes.h>
#include <revolution/private/iostypes.h>
typedef IOSError (*IOSIpcCb)(IOSError, void*);
IOSError IPCCltInit(void);
IOSError IPCCltReInit(void);
IOSError IOS_OpenAsync(const char* pPath, u32 flags, IOSIpcCb cb, void* callback_arg);
IOSError IOS_Open(const char* path, u32 flags);
IOSError IOS_CloseAsync(IOSFd fd, IOSIpcCb cb, void* cbArg);
IOSError IOS_Close(IOSFd fd);
IOSError IOS_ReadAsync(IOSFd fd, void* buf, u32 len, IOSIpcCb cb, void* cbArg);
IOSError IOS_Read(IOSFd fd, void* buf, u32 len);
IOSError IOS_WriteAsync(IOSFd fd, void* buf, u32 len, IOSIpcCb cb, void* cbArg);
IOSError IOS_Write(IOSFd fd, void* buf, u32 len);
IOSError IOS_SeekAsync(IOSFd fd, s32 offset, u32 whence, IOSIpcCb cb, void* cbArg);
IOSError IOS_Seek(IOSFd fd, s32 offset, u32 whence);
IOSError IOS_IoctlAsync(IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen, IOSIpcCb cb, void* cbArg);
IOSError IOS_Ioctl(IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen);
IOSError IOS_IoctlvAsync(IOSFd fd, s32 cmd, u32 readCount, u32 writeCount, IOSIoVector* vect, IOSIpcCb cb, void* cbArg);
IOSError IOS_Ioctlv(IOSFd fd, s32 cmd, u32 readCount, u32 writeCount, IOSIoVector* vect);
IOSError IOS_IoctlvReboot(IOSFd fd, s32 cmd, u32 readCount, u32 writeCount, IOSIoVector* vect);
#ifdef __cplusplus
}
#endif
#endif // _REVOLUTION_IPCCLT_H_

View File

@ -0,0 +1,18 @@
#ifndef _REVOLUTION_IPCMEMORY_H_
#define _REVOLUTION_IPCMEMORY_H_
#include <revolution/private/iostypes.h>
#ifdef __cplusplus
extern "C" {
#endif
IOSError iosFree(IOSHeapId id, void* ptr);
void* iosAllocAligned(IOSHeapId id, u32 size, u32 alignment);
IOSHeapId iosCreateHeap(void* ptr, u32 size);
#ifdef __cplusplus
}
#endif
#endif // _REVOLUTION_IPCMEMORY_H_

View File

@ -2,6 +2,7 @@
#define _REVOLUTION_NAND_H_
#include <revolution/types.h>
#include <revolution/fs.h>
#ifdef __cplusplus
extern "C" {
@ -122,11 +123,56 @@ typedef struct {
typedef void (*NANDCallback)(s32, NANDCommandBlock*);
typedef void (*NANDAsyncCallback)(s32 result, struct NANDCommandBlock* block);
typedef void (*NANDLoggingCallback)(BOOL, s32);
// NAND
s32 NANDCreate(const char* path, const u8 perm, const u8 attr);
s32 NANDPrivateCreate(const char* path, u8 perm, u8 attr);
s32 NANDPrivateCreateAsync(const char *path, u8 perm, u8 attr, NANDCallback cb, NANDCommandBlock* block);
s32 NANDDelete(const char* path);
s32 NANDPrivateDelete(const char* path);
s32 NANDPrivateDeleteAsync(const char* path, NANDCallback cb, NANDCommandBlock* block);
s32 NANDRead(NANDFileInfo* info, void* buf, const u32 length);
s32 NANDReadAsync(NANDFileInfo* info, void* buf, const u32 length,
NANDCallback cb, NANDCommandBlock* block);
s32 NANDWrite(NANDFileInfo* info, const void* buf, const u32 length);
s32 NANDWriteAsync(NANDFileInfo* info, const void* buf, const u32 length,
NANDCallback cb, NANDCommandBlock* block);
s32 NANDSeek(NANDFileInfo* info, const s32 offset, const s32 whence);
s32 NANDSeekAsync(NANDFileInfo* info, const s32 offset, const s32 whence,
NANDCallback cb, NANDCommandBlock* block);
s32 NANDPrivateCreateDir(const char* path, u8 perm, u8 attr);
s32 NANDPrivateCreateDirAsync(const char *path, u8 perm, u8 attr, NANDCallback cb, NANDCommandBlock *block);
s32 NANDMove(const char* path, const char* destDir);
s32 NANDGetLength(NANDFileInfo* info, u32* length);
s32 NANDGetLengthAsync(NANDFileInfo* info, u32* length, NANDCallback cb,
NANDCommandBlock* block);
s32 NANDGetStatus(const char* path, NANDStatus* stat);
s32 NANDPrivateGetStatus(const char* path, NANDStatus* stat);
s32 NANDPrivateGetStatusAsync(const char* path, NANDStatus* stat,
NANDCallback cb, NANDCommandBlock* block);
void NANDSetUserData(NANDCommandBlock* block, void* data);
void* NANDGetUserData(const NANDCommandBlock* block);
// NANDCore
s32 NANDInit(void);
s32 NANDGetHomeDir(char[NAND_MAX_PATH]);
s32 NANDPrivateGetTypeAsync(const char* path, u8* type, NANDCallback cb, NANDCommandBlock* block);
void NANDInitBanner(NANDBanner* bnr, u32 const flag, const u16* title, const u16* comment);
s32 NANDCreate(const char*, u8, u8);
s32 NANDPrivateCreate(const char*, u8, u8);
// NANDCheck
s32 NANDCheck(const u32 fsBlock, const u32 inode, u32* answer);
// NANDOpenClose
s32 NANDOpen(const char*, NANDFileInfo*, u8);
s32 NANDPrivateOpen(const char*, NANDFileInfo*, u8);
s32 NANDOpenAsync(const char*, NANDFileInfo*, u8, NANDCallback, NANDCommandBlock*);
@ -134,31 +180,30 @@ s32 NANDPrivateOpenAsync(const char*, NANDFileInfo*, const u8, NANDCallback, NAN
s32 NANDClose(NANDFileInfo*);
s32 NANDCloseAsync(NANDFileInfo*, NANDCallback, NANDCommandBlock*);
s32 NANDRead(NANDFileInfo*, void*, u32);
s32 NANDReadAsync(NANDFileInfo*, void*, u32, NANDCallback, NANDCommandBlock*);
s32 NANDGetLength(NANDFileInfo*, u32*);
s32 NANDSimpleSafeOpen(const char* path, NANDFileInfo* info, const u8 accType, void* buf, const u32 length);
s32 NANDSimpleSafeClose(NANDFileInfo* info);
s32 NANDPrivateSafeOpenAsync(const char* path, NANDFileInfo* info, const u8 accType, void* buf, const u32 length, NANDCallback cb, NANDCommandBlock* block);
s32 NANDSafeCloseAsync(NANDFileInfo* info, NANDCallback cb, NANDCommandBlock* block);
s32 NANDDelete(const char*);
// NANDLogging
BOOL NANDLoggingAddMessageAsync(NANDLoggingCallback cb, s32 errorCode, const char* fmt, ...);
s32 NANDMove(const char*, const char*);
// NANDErrorMessage
BOOL NANDSetAutoErrorMessaging(BOOL show);
void __NANDPrintErrorMessage(s32 errorCode);
s32 NANDCheck(u32, u32, u32*);
s32 NANDWrite(NANDFileInfo*, const void*, u32);
s32 NANDWriteAsync(NANDFileInfo*, const void*, u32, NANDCallback, NANDCommandBlock*);
s32 NANDSeekAsync(NANDFileInfo*, s32, s32, NANDCallback, NANDCommandBlock*);
s32 NANDPrivateGetStatus(const char*, NANDStatus*);
s32 NANDPrivateDelete(const char*);
s32 NANDPrivateCreate(const char*, u8, u8);
s32 NANDGetHomeDir(char[NAND_MAX_PATH]);
s32 NANDGetStatus(const char*, NANDStatus*);
s32 NANDSecretGetUsage(const char*, u32*, u32*);
const char* nandGetHomeDir();
void nandGenerateAbsPath(char* absPath, const char* path);
BOOL nandIsPrivatePath(const char* path);
BOOL nandIsInitialized(void);
s32 nandConvertErrorCode(const ISFSError err);
void nandGetRelativeName(char* name, const char* path);
BOOL nandIsUnderPrivatePath(const char* path);
BOOL nandIsRelativePath(const char* path);
void nandGetParentDirectory(char* parentDir, const char* absPath);
BOOL nandIsAbsolutePath(const char* path);
#ifdef __cplusplus
}

View File

@ -46,6 +46,7 @@ typedef u32 OSTick;
#include <revolution/os/OSStateFlags.h>
#include <revolution/os/OSIpc.h>
#include <revolution/os/OSNandbootInfo.h>
#include <revolution/os/OSNet.h>
// private macro, maybe shouldn't be defined here?
#define OFFSET(addr, align) (((u32)(addr) & ((align)-1)))
@ -68,16 +69,29 @@ OSThread* __OSCurrentThread AT_ADDRESS(OS_BASE_CACHED | 0x00E4);
u32 __OSSimulatedMemSize AT_ADDRESS(OS_BASE_CACHED | 0x00F0);
u32 __OSBusClock AT_ADDRESS(OS_BASE_CACHED | 0x00F8);
u32 __OSCoreClock AT_ADDRESS(OS_BASE_CACHED | 0x00FC);
volatile u16 __OSDeviceCode AT_ADDRESS(OS_BASE_CACHED | 0x30E6);
vu16 __OSDeviceCode AT_ADDRESS(OS_BASE_CACHED | 0x30E6);
vu8 __OSLockedFlag AT_ADDRESS(OS_BASE_CACHED | 0x3187);
u16 __OSWirelessPadFixMode AT_ADDRESS(OS_BASE_CACHED | 0x30E0);
vu32 __OSLaunchPartitionType AT_ADDRESS(OS_BASE_CACHED | 0x3194);
vu8 __OSDeviceCheckCode AT_ADDRESS(OS_BASE_CACHED | 0x319C);
// unknowns
OSThread* __gUnkThread1 AT_ADDRESS(OS_BASE_CACHED | 0x00D8);
int __gUnknown800030C0[2] AT_ADDRESS(OS_BASE_CACHED | 0x30C0);
u8 __gUnknown800030E3 AT_ADDRESS(OS_BASE_CACHED | 0x30E3);
#else
#define __OSBusClock (*(u32 *)(OS_BASE_CACHED | 0x00F8))
#define __OSCoreClock (*(u32 *)(OS_BASE_CACHED | 0x00FC))
#define __OSPhysicalMemSize (*(u32*)(OS_BASE_CACHED | 0x0028))
#define __OSTVMode (*(volatile int*)(OS_BASE_CACHED | 0x00CC))
#define __OSActiveThreadQueue (*(OSThreadQueue*)(OS_BASE_CACHED | 0x00DC))
#define __OSCurrentThread ((OSThread*)(OS_BASE_CACHED | 0x00E4))
#define __OSSimulatedMemSize (*(u32*)(OS_BASE_CACHED | 0x00F0))
#define __OSBusClock (*(u32*)(OS_BASE_CACHED | 0x00F8))
#define __OSCoreClock (*(u32*)(OS_BASE_CACHED | 0x00FC))
#define __OSDeviceCode (*(vu16*)(OS_BASE_CACHED | 0x30E6))
#define __OSLockedFlag (*(vu8*)(OS_BASE_CACHED | 0x3187))
#define __OSWirelessPadFixMode (*(u16*)(OS_BASE_CACHED | 0x30E0))
#define __OSLaunchPartitionType (*(vu32*)(OS_BASE_CACHED | 0x3194))
#define __OSDeviceCheckCode (*(vu8*)(OS_BASE_CACHED | 0x319C))
#endif
#define OS_BUS_CLOCK __OSBusClock

View File

@ -0,0 +1,29 @@
#ifndef _REVOLUTION_OSNET_H_
#define _REVOLUTION_OSNET_H_
#include <revolution/ipc.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum NWC24Err {
NWC24_OK = 0,
} NWC24Err;
NWC24Err NWC24iPrepareShutdown(void);
NWC24Err NWC24iSynchronizeRtcCounter(BOOL);
NWC24Err NWC24iOpenResourceManager_(const char* callerName, const char* path, IOSFd* fd, u32 flags);
NWC24Err NWC24SuspendScheduler(void);
NWC24Err NWC24iSetRtcCounter_(int rtc, BOOL);
NWC24Err NWC24iIoctlResourceManager_(const char* callerName, IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen);
NWC24Err NWC24iCloseResourceManager_(const char* callerName, IOSFd);
NWC24Err NWC24iRequestShutdown(u32 event, s32* result);
NWC24Err NWC24iIoctlResourceManagerAsync_(const char* callerName, IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen, void* cbArg);
BOOL NWC24iIsAsyncRequestPending_(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -3,6 +3,10 @@
#include <revolution/os.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
u32 checkSum;
u16 titleName[2][21];
@ -16,4 +20,8 @@ typedef struct {
void __OSStartPlayRecord(void);
void __OSStopPlayRecord(void);
#ifdef __cplusplus
}
#endif
#endif // OSPLAYRECORD_H

View File

@ -17,10 +17,10 @@ typedef struct OSShutdownFunctionQueue {
OSShutdownFunctionInfo* tail;
} OSShutdownFunctionQueue;
typedef BOOL (*OSResetFunction)(BOOL, u32);
typedef BOOL (*OSShutdownFunction)(BOOL, u32);
struct OSShutdownFunctionInfo {
OSResetFunction func;
OSShutdownFunction func;
u32 priority;
OSShutdownFunctionInfo* next;
OSShutdownFunctionInfo* prev;

View File

@ -1,9 +0,0 @@
#pragma once
#include <revolution/private/iosrestypes.h>
#include <revolution/private/iostypes.h>
#include <revolution/types.h>
typedef IOSError (*IOSIpcCb) (IOSError, void *);
s32 IOS_Read(s32, void*, u32);

View File

@ -33,19 +33,19 @@ typedef u32 IOSResourceHandle;
#define IOS_ERROR_INVALID_SIZE -23
typedef struct {
u8 *path;
u8* path;
u32 flags;
IOSUid uid;
IOSGid gid;
} IOSResourceOpen;
typedef struct {
u8 *outPtr;
u8* outPtr;
u32 outLen;
} IOSResourceRead;
typedef struct {
u8 *inPtr;
u8* inPtr;
u32 inLen;
} IOSResourceWrite;
@ -56,14 +56,14 @@ typedef struct {
typedef struct {
u32 cmd;
u8 *inPtr;
u8* inPtr;
u32 inLen;
u8 *outPtr;
u8* outPtr;
u32 outLen;
} IOSResourceIoctl;
typedef struct {
u8 *base;
u8* base;
u32 length;
} IOSIoVector;
@ -71,7 +71,7 @@ typedef struct {
u32 cmd;
u32 readCount;
u32 writeCount;
IOSIoVector *vector;
IOSIoVector* vector;
} IOSResourceIoctlv;
typedef struct {

View File

@ -1,8 +1,8 @@
#ifndef _DOLPHIN_DVD_INTERNAL_H_
#define _DOLPHIN_DVD_INTERNAL_H_
#ifndef _REVOLUTION_DVD_INTERNAL_H_
#define _REVOLUTION_DVD_INTERNAL_H_
#include <dolphin/os.h>
#include <dolphin/dvd.h>
#include <revolution/os.h>
#include <revolution/dvd.h>
#ifdef __cplusplus
extern "C" {
@ -11,17 +11,21 @@ extern "C" {
// DVD
DVDCommandChecker __DVDSetOptionalCommandChecker(DVDCommandChecker func);
void __DVDSetImmCommand(u32 command);
void __DVDSetDmaCommand(u32 command);
void* __DVDGetIssueCommandAddr(void);
void __DVDAudioBufferConfig(DVDCommandBlock* block, u32 enable, u32 size, DVDCBCallback callback);
void __DVDPrepareResetAsync(DVDCBCallback callback);
int __DVDTestAlarm(const OSAlarm* alarm);
BOOL __DVDLowBreak(void);
u32 __DVDGetCoverStatus(void);
void __DVDPrepareReset(void);
extern vu32 __DVDLayoutFormat;
// DVD ERROR
void __DVDStoreErrorCode(u32 error);
void __DVDStoreErrorCode(u32 error, DVDCBCallback callback);
BOOL __DVDCheckDevice(void);
// DVD FATAL
void __DVDPrintFatalMessage(void);
void __DVDShowFatalMessage(void);
// DVD FS
extern OSThreadQueue __DVDThreadQueue;
@ -29,10 +33,7 @@ extern u32 __DVDLongFileNameFlag;
void __DVDFSInit(void);
// DVD LOW
void __DVDInitWA(void);
void __DVDInterruptHandler(__OSInterrupt interrupt, OSContext* context);
void __DVDLowSetWAType(u32 type, s32 seekLoc);
// DVD BROADWAY
int __DVDLowTestAlarm(const OSAlarm* alarm);
// DVD QUEUE
@ -42,15 +43,10 @@ DVDCommandBlock* __DVDPopWaitingQueue(void);
int __DVDCheckWaitingQueue(void);
int __DVDDequeueWaitingQueue(DVDCommandBlock* block);
int __DVDIsBlockInWaitingQueue(DVDCommandBlock* block);
// FST LOAD
void __fstLoad(void);
// unsorted
u32 __DVDGetCoverStatus(void);
DVDCommandBlock* __DVDGetNextWaitingQueue(void);
#ifdef __cplusplus
}
#endif
#endif // _DOLPHIN_DVD_INTERNAL_H_
#endif // _REVOLUTION_DVD_INTERNAL_H_

2553
src/revolution/dvd/dvd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,200 @@
#include <revolution/os.h>
#include <revolution/dvd.h>
#include <revolution/sc.h>
#include "__os.h"
#include "__dvd.h"
static u8 CheckBuffer[32] ATTRIBUTE_ALIGN(32);
static volatile BOOL lowDone = TRUE;
static volatile u32 lowIntType = 0;
static void lowCallback(u32 intType) {
lowIntType = intType;
lowDone = TRUE;
}
void __DVDShowDeviceErrorMessage(void);
BOOL __DVDCheckDevice(void) {
u32 checkCode = 0x460A0000;
u32 outOfRangeError = 0xFFFFFFFF;
u32 reportKeyError = 0xFFFFFFFF;
OSIOSRev iosRev;
if (OSGetPhysicalMem2Size() == 0x08000000) {
return TRUE;
}
__OSGetIOSRev(&iosRev);
if (iosRev.major < 30 || iosRev.major >= 254) {
return TRUE;
}
if (__OSDeviceCheckCode == 129) {
checkCode = 0x7ED40000;
}
lowDone = FALSE;
DVDLowUnencryptedRead((void*)CheckBuffer, 32, checkCode, lowCallback);\
while (!lowDone) {
}
switch (lowIntType) {
case 2:
break;
case 1:
goto invalid;
break;
default:
goto fatal;
break;
}
lowDone = FALSE;
DVDLowRequestError(lowCallback);
while (!lowDone) {
}
outOfRangeError = DVDLowGetImmBufferReg();
switch (lowIntType) {
case 1: {
if ((DVDLowGetImmBufferReg() & 0xFF000000) != 0) {
goto recover;
break;
}
switch (DVDLowGetImmBufferReg() & 0xFFFFFF) {
case 0x52100:
break;
default:
goto invalid;
break;
}
break;
}
default:
goto fatal;
break;
}
lowDone = FALSE;
DVDLowReportKey((DVDVideoReportKey*)CheckBuffer, 0x40000, 0, lowCallback);
while (!lowDone) {
}
switch (lowIntType) {
case 2:
break;
case 1:
goto invalid;
break;
default:
goto fatal;
break;
}
lowDone = FALSE;
DVDLowRequestError(lowCallback);
while (!lowDone) {
}
reportKeyError = DVDLowGetImmBufferReg();
switch (lowIntType) {
case 1:
if ((DVDLowGetImmBufferReg() & 0xFF000000) != 0) {
goto recover;
break;
}
switch (DVDLowGetImmBufferReg() & 0xFFFFFF) {
case 0x53100:
case 0x52000:
break;
default:
goto invalid;
break;
}
break;
default:
goto fatal;
break;
}
valid:
return TRUE;
invalid:
__DVDShowDeviceErrorMessage();
return FALSE;
recover:
return FALSE;
fatal:
__DVDShowFatalMessage();
return FALSE;
}
const char* const __DVDDeviceErrorMessage[] = {
"\n\n\nエラーコード001。\n"
"不明なデバイスが見つかりました。",
"\n\n\nError #001,\n"
"unauthorized device has been detected.",
"\n\n\nFehler #001:\n"
"Es wurde eine unzul舖sige Komponente\n"
"entdeckt.",
"\n\n\nErreur 001:\n"
"un dispositif non autoris\xE9\x20""a \xE9\x74\xE9\x20""d\xE9\x74""ect\xE9\x2E",
"\n\n\nError 001:\n"
"Se ha detectado un dispositivo no\n"
"autorizado.",
"\n\n\nErrore #001:\n"
"rilevato un dispositivo non autorizzato.",
"\n\n\nFout #001:\n"
"ongeoorloofd onderdeel gevonden."
};
void __DVDShowDeviceErrorMessage(void) {
const char* message;
const char* const* messageList;
GXColor bg = { 0, 0, 0, 0 };
GXColor fg = { 255, 255, 255, 0 };
if (SCGetLanguage() == 0) {
OSSetFontEncode(1);
} else {
OSSetFontEncode(0);
}
messageList = __DVDDeviceErrorMessage;
if (SCGetLanguage() > 6) {
message = messageList[1];
} else {
message = messageList[SCGetLanguage()];
}
OSFatal(fg, bg, message);
}

View File

@ -0,0 +1,211 @@
#include <revolution.h>
#include <revolution/dvd.h>
#include <revolution/sc.h>
#include "__dvd.h"
static void (*FatalFunc)();
const char* const __DVDErrorMessageDefault[] = {
"\n"
"\n"
"\n"
"エラーが発生しました。\n"
"\n"
"イジェクトボタンを押してディスクを取り出してか\n"
"ら、本体の電源をOFFにして、本体の取扱説明書の\n"
"指示に従ってください。",
"\n"
"\n"
"\n"
"An error has occurred.\n"
"Press the Eject Button, remove the\n"
"Game Disc, and turn off the power to the\n"
"console. Please read the Wii Operations\n"
"Manual for further instructions.",
"\n"
"\n"
"\n"
"Ein Fehler ist aufgetreten.\n"
"Dr""\xFC""cke den Ausgabeknopf, entnimm die\n"
"Disc und schalte die Wii-Konsole aus.\n"
"Bitte lies die Wii-Bedienungsanleitung,\n"
"um weitere Informationen zu erhalten.",
"\n"
"\n"
"\n"
"Une erreur est survenue.\n"
"Appuyez sur le bouton EJECT, retirez\n"
"le disque et ""\xE9""teignez la console.\n"
"Veuillez vous r""\xE9""f""\xE9""rer au Mode d'emploi\n"
"de la Wii pour plus de d""\xE9""tails.",
"\n"
"\n"
"\n"
"Ocurri\xF3 un Error.\n"
"Oprime el Bot\xF3n EJECT, saca el disco\n"
"y apaga la consola. Consulta el manual\n"
"de operaciones de la consola Wii para\n"
"obtener m\xE1s informaci\xF3n.",
"\n"
"\n"
"\n"
"Si \xE8 verificato un errore.\n"
"Premi il pulsante EJECT, estrai il disco\n"
"e spegni la console. Per maggiori\n"
"informazioni, consulta il manuale di\n"
"istruzioni della console Wii.",
"\n"
"\n"
"\n"
"Er is een fout opgetreden.\n"
"Druk op de EJECT-knop, verwijder de\n"
"disk en zet het Wii-systeem uit. Lees\n"
"de Wii-handleiding voor meer informatie."
};
const char* const __DVDErrorMessageEurope[] = {
"\n"
"\n"
"\n"
"エラーが発生しました。\n"
"\n"
"イジェクトボタンを押してディスクを取り出してか\n"
"ら、本体の電源をOFFにして、本体の取扱説明書の\n"
"指示に従ってください。",
"\n"
"\n"
"\n"
"An error has occurred.\n"
"Press the EJECT Button, remove the Disc,\n"
"and turn off the power to the console.\n"
"Please refer to the Wii Operations Manual\n"
"for details.",
"\n"
"\n"
"\n"
"Ein Fehler ist aufgetreten.\n"
"Dr""\xFC""cke den Ausgabeknopf, entnimm die\n"
"Disc und schalte die Wii-Konsole aus.\n"
"Bitte lies die Wii-Bedienungsanleitung,\n"
"um weitere Informationen zu erhalten.",
"\n"
"\n"
"\n"
"Une erreur est survenue.\n"
"Appuyez sur le bouton EJECT, retirez\n"
"le disque et ""\xE9""teignez la console.\n"
"Veuillez vous r""\xE9""f""\xE9""rer au mode d'emploi\n"
"Wii pour plus de d""\xE9""tails.",
"\n"
"\n"
"\n"
"Se ha producido un error.\n"
"Pulsa el Bot\xF3n EJECT, extrae el disco y\n"
"apaga la consola. Consulta el manual de\n"
"instrucciones de la consola Wii para\n"
"obtener m\xE1s informaci\xF3n.",
"\n"
"\n"
"\n"
"Si \xE8 verificato un errore.\n"
"Premi il pulsante EJECT, estrai il disco\n"
"e spegni la console. Per maggiori\n"
"informazioni, consulta il manuale di\n"
"istruzioni della console Wii.",
"\n"
"\n"
"\n"
"Er is een fout opgetreden.\n"
"Druk op de EJECT-knop, verwijder de\n"
"disk en zet het Wii-systeem uit. Lees\n"
"de Wii-handleiding voor meer informatie."
};
const char* __DVDErrorMessageChinaKorea [] = {
"\n"
"\n"
"エラーコード104。\n"
"エラーが発生しました。\n"
"\n"
"イジェクトボタンを押してディスクを取り出してか\n"
"ら、本体の電源をOFFにして、本体の取扱説明書の\n"
"指示に従ってください。",
"\n"
"\n"
"Error #104,\n"
"An error has occurred.\n"
"Press the EJECT Button, remove the\n"
"Game Disc, and turn the power off.\n"
"Please read the Wii Operations Manual\n"
"for more information."
};
void __DVDShowFatalMessage(void) {
const char* message;
const char* const* messageList;
GXColor bg = { 0, 0, 0, 0 };
GXColor fg = { 255, 255, 255, 0 };
if (SCGetLanguage() == SC_LANG_JAPANESE) {
OSSetFontEncode(OS_FONT_ENCODE_SJIS);
} else {
OSSetFontEncode(OS_FONT_ENCODE_ANSI);
}
switch (SCGetProductGameRegion()) {
case 0:
case 1:
case 3:
default:
messageList = __DVDErrorMessageDefault;
break;
case 2:
messageList = __DVDErrorMessageEurope;
break;
case 4:
case 5:
messageList = __DVDErrorMessageChinaKorea;
break;
}
if (SCGetLanguage() > SC_LANG_DUTCH) {
message = messageList[1];
} else {
message = messageList[SCGetLanguage()];
}
OSFatal(fg, bg, message);
}
BOOL DVDSetAutoFatalMessaging(BOOL enable) {
BOOL enabled, prev;
enabled = OSDisableInterrupts();
prev = FatalFunc ? TRUE : FALSE;
FatalFunc = enable ? __DVDShowFatalMessage : NULL;
OSRestoreInterrupts(enabled);
return prev;
}
BOOL __DVDGetAutoFatalMessaging(void) {
return FatalFunc ? TRUE : FALSE;
}
void __DVDPrintFatalMessage(void) {
if (FatalFunc) {
FatalFunc();
}
}

View File

@ -0,0 +1,978 @@
#include <revolution/os.h>
#include <revolution/esp.h>
#include <revolution/ipc.h>
IOSFd DiFD = -1;
static volatile u8 requestInProgress = FALSE;
static u8 breakRequested;
static u8 callbackInProgress;
static u32 registerBuf[8] ATTRIBUTE_ALIGN(32);
static u32 statusRegister[8] ATTRIBUTE_ALIGN(32);
static u32 controlRegister[8] ATTRIBUTE_ALIGN(32);
static s32 lastTicketError[8] ATTRIBUTE_ALIGN(32);
static u32 readLength;
static u32 spinUpValue;
static diRegVals_t diRegValCache ATTRIBUTE_ALIGN(32);
static u8 DVDLowInitCalled = FALSE;
typedef enum callbackType {
BOGUS_TYPE = 0,
TRANSACTION_CB,
COVER_CB,
COVER_REG_CB
} callbackType_t;
static int freeCommandBuf = 0;
static diCommand_t* diCommand;
static char* pathBuf;
typedef struct dvdContext {
DVDLowCallback callback;
callbackType_t callbackType;
u8 inUse;
u32 contextMagic;
u32 contextNum;
u32 pad[3];
} dvdContext_t;
static int freeDvdContext = 0;
static u8 dvdContextsInited = FALSE;
static dvdContext_t dvdContexts[4] ATTRIBUTE_ALIGN(32);
static IOSIoVector ioVec[10] ATTRIBUTE_ALIGN(32);
static void* ddrAllocAligned32(const int size) {
void* low, *high;
if ((size & 0x1F) != 0) {
OSReport("(ddrAllocAligned32) size is not a multiple of 32 !!! \n");
return 0;
}
low = IPCGetBufferLo();
high = IPCGetBufferHi();
if (((u32)low & 0x1F) != 0) {
low = (void*)(((u32)low + 31) & 0x1F);
}
if ((u32)low + size > (u32)high) {
OSReport("(ddrAllocAligned32) Not enough space to allocate %d bytes\n", size);
}
IPCSetBufferLo((void*)((u32)low + size));
return low;
}
static BOOL allocateStructures(void) {
if ((diCommand = ddrAllocAligned32(sizeof(diCommand_t) * 4)) == 0) {
OSReport("Allocation of diCommand blocks failed\n");
return FALSE;
}
if ((pathBuf = ddrAllocAligned32(32)) == 0) {
OSReport("Allocation of pathBuf failed\n");
return FALSE;
}
return TRUE;
}
static void initDvdContexts(void) {
{
u32 i;
for (i = 0; i < 4; i++) {
dvdContexts[i].callback = 0;
dvdContexts[i].callbackType = 0;
dvdContexts[i].inUse = FALSE;
dvdContexts[i].contextMagic = 0xFEEBDAED;
dvdContexts[i].contextNum = i;
}
}
freeDvdContext = 0;
}
IOSError doTransactionCallback(IOSError ret, void* context) {
dvdContext_t* dvdContext = context;
if (dvdContext->contextMagic != 0xFEEBDAED) {
OSReport("(doTransactionCallback) Error - context mangled!\n");
dvdContext->contextMagic = 0xFEEBDAED;
goto out;
}
requestInProgress = FALSE;
if (dvdContext->callback != NULL) {
int callbackArg;
callbackInProgress = TRUE;
callbackArg = ret;
if (breakRequested == TRUE) {
breakRequested = FALSE;
callbackArg |= 8;
}
if (callbackArg & 1) {
readLength = 0;
}
dvdContext->callback((u32)callbackArg);
callbackInProgress = FALSE;
}
out:
dvdContext->inUse = FALSE;
return 0;
}
// NOTE: function doesn't exist in TP debug, needed for string data
IOSError doCoverCallback(IOSError err, void* context) {
OSReport("(doCoverCallback) Error - context mangled!\n");
return 0;
}
IOSError doPrepareCoverRegisterCallback(IOSError err, void* context) {
dvdContext_t* dvdContext;
requestInProgress = FALSE;
diRegValCache.CoverRegVal = registerBuf[0];
dvdContext = (dvdContext_t*)context;
if (dvdContext->contextMagic != 0xFEEBDAED) {
OSReport("(doTransactionCallback) Error - context mangled!\n");
dvdContext->contextMagic = 0xFEEBDAED;
} else {
IOSError ret;
if (dvdContext->callback != 0) {
callbackInProgress = TRUE;
ret = err;
if (breakRequested == TRUE) {
breakRequested = FALSE;
ret |= 8;
}
dvdContext->callback(ret);
callbackInProgress = FALSE;
}
}
dvdContext->inUse = FALSE;
return 0;
}
static inline void nextCommandBuf(int* bufNum) {
(*bufNum)++;
if (*bufNum >= 4) {
*bufNum = 0;
}
}
static inline dvdContext_t* newContext(const DVDLowCallback callback, const callbackType_t type) {
int returnIndex;
if ((dvdContexts[freeDvdContext].inUse != 0) == (u32)1) {
OSReport("(newContext) ERROR: freeDvdContext.inUse (#%d) is true\n", freeDvdContext);
OSReport("(newContext) Now spinning in infinite loop\n");
while (1) {
}
}
if (dvdContexts[freeDvdContext].contextMagic != 0xFEEBDAED) {
OSReport("(newContext) Something overwrote the context magic - spinning \n");
while (1) {
}
}
dvdContexts[freeDvdContext].callback = callback;
dvdContexts[freeDvdContext].callbackType = type;
dvdContexts[freeDvdContext].inUse = TRUE;
returnIndex = freeDvdContext;
freeDvdContext++;
if (freeDvdContext >= 4) {
freeDvdContext = 0;
}
return(dvdContexts + returnIndex);
}
BOOL DVDLowFinalize(void) {
IOSError ret = IOS_Close(DiFD);
if (ret != IOS_ERROR_OK) {
OSReport("(DVDLowFinish) Error: IOS_Close failed\n");
return FALSE;
}
DVDLowInitCalled = FALSE;
return TRUE;
}
BOOL DVDLowInit(void) {
IOSError retVal;
if (DVDLowInitCalled == FALSE) {
DVDLowInitCalled = TRUE;
retVal = IPCCltInit();
if (retVal != IOS_ERROR_OK) {
OSReport("IPCCltInit returned error: %d\n", retVal);
return FALSE;
}
if (allocateStructures() == FALSE) {
return FALSE;
}
if (dvdContextsInited == FALSE) {
initDvdContexts();
dvdContextsInited = TRUE;
}
}
strncpy(pathBuf, "/dev/di", 32);
DiFD = IOS_Open(pathBuf, 0);
if (DiFD >= 0) {
return TRUE;
} else {
switch (DiFD) {
case IOS_ERROR_NOEXISTS:
OSReport("(DVDLowInit) Error: IOS_Open failed - pathname '/dev/di' does not exist\n");
return FALSE;
break;
case IOS_ERROR_ACCESS:
OSReport("(DVDLowInit) Error: IOS_Open failed - calling thread lacks permission\n");
return FALSE;
break;
case IOS_ERROR_MAX:
OSReport("(DVDLowInit) Error: IOS_Open failed - connection limit has been reached\n");
return FALSE;
break;
default:
OSReport("(DVDLowInit) IOS_Open failed, errorcode = %d\n", DiFD);
return FALSE;
break;
}
}
}
BOOL DVDLowReadDiskID(DVDDiskID* diskID, DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
if (diskID == 0) {
OSReport("@@@@@@ WARNING - Calling DVDLowReadDiskId with NULL ptr\n");
}
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x70;
rv = IOS_IoctlAsync(DiFD, 0x70, &diCommand[freeCommandBuf], sizeof(diCommand_t), diskID, sizeof(DVDDiskID), doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowReadDiskID) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
BOOL DVDLowOpenPartition(const u32 partitionWordOffset, const ESTicket* const eTicket, const u32 numCertBytes, const u8* const certificates, ESTitleMeta* tmd, DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
if (eTicket != 0 && ((u32)eTicket & 0x1F)) {
OSReport("(DVDLowOpenPartition) eTicket memory is unaligned\n");
return FALSE;
}
if (certificates != 0 && ((u32)certificates & 0x1F)) {
OSReport("(DVDLowOpenPartition) certificates memory is unaligned\n");
return FALSE;
}
if (tmd != 0 && ((u32)tmd & 0x1F)) {
OSReport("(DVDLowOpenPartition) certificates memory is unaligned\n");
return FALSE;
}
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x8B;
diCommand[freeCommandBuf].arg[0] = partitionWordOffset;
ioVec[0].base = (u8*)&diCommand[freeCommandBuf];
ioVec[0].length = sizeof(diCommand_t);
ioVec[1].base = (u8*)eTicket;
if (eTicket == 0) {
ioVec[1].length = 0;
} else {
ioVec[1].length = sizeof(ESTicket);
}
ioVec[2].base = (u8*)certificates;
if (certificates == 0) {
ioVec[2].length = 0;
} else {
ioVec[2].length = numCertBytes;
}
ioVec[3].base = (u8*)tmd;
ioVec[3].length = sizeof(ESTitleMeta);
ioVec[4].base = (u8*)&lastTicketError[0];
ioVec[4].length = sizeof(lastTicketError);
rv = IOS_IoctlvAsync(DiFD, 0x8B, 3, 2, ioVec, doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowOpenPartition) IOS_IoctlvAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowOpenPartitionWithTmdAndTicket() {
OSReport("(%s) eTicket memory is unaligned\n", __FUNCTION__);
OSReport("(%s) tmd parameter cannot be NULL\n", __FUNCTION__);
OSReport("(%s) tmd memory is unaligned\n", __FUNCTION__);
OSReport("(%s) eTicket parameter cannot be NULL\n", __FUNCTION__);
return TRUE;
}
BOOL DVDLowOpenPartitionWithTmdAndTicketView(const u32 partitionWordOffset, const ESTicketView* const eTicketView, const u32 numTmdBytes, const ESTitleMeta* const tmd, const u32 numCertBytes, const u8* const certificates, DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
if (certificates != 0 && ((u32)certificates & 0x1F)) {
return FALSE;
}
if (tmd == 0) {
OSReport("(%s) tmd parameter cannot be NULL\n", __FUNCTION__);
return FALSE;
} else if (((u32)tmd & 0x1F)) {
OSReport("(%s) tmd memory is unaligned\n", __FUNCTION__);
return FALSE;
}
if (eTicketView == 0) {
OSReport("(%s) eTicketView parameter cannot be NULL\n", __FUNCTION__);
return FALSE;
} else if (((u32)eTicketView & 0x1F)) {
OSReport("(%s) eTicketView memory is unaligned\n", __FUNCTION__);
return FALSE;
}
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x94;
diCommand[freeCommandBuf].arg[0] = partitionWordOffset;
ioVec[0].base = (u8*)&diCommand[freeCommandBuf];
ioVec[0].length = sizeof(diCommand_t);
ioVec[1].base = (u8*)eTicketView;
ioVec[1].length = sizeof(ESTicketView);
ioVec[2].base = (u8*)tmd;
ioVec[2].length = numTmdBytes;
ioVec[3].base = (u8*)certificates;
if (certificates == 0) {
ioVec[3].length = 0;
} else {
ioVec[3].length = numCertBytes;
}
ioVec[4].base = (u8*)&lastTicketError[0];
ioVec[4].length = sizeof(lastTicketError);
rv = IOS_IoctlvAsync(DiFD, 0x94, 4, 1, ioVec, doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowOpenPartition) IOS_IoctlvAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
BOOL DVDLowGetNoDiscBufferSizes(const u32 partitionWordOffset, u32* numTmdBytes, u32* numCertBytes, DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
if (numTmdBytes == 0 || numCertBytes == 0) {
OSReport("(%s) Error: NULL pointer argument\n", __FUNCTION__);
return FALSE;
}
if (((u32)numTmdBytes & 0x1F)) {
OSReport("(%s) numTmdBytes memory is unaligned\n", __FUNCTION__);
return FALSE;
}
if (((u32)numCertBytes & 0x1F)) {
OSReport("(%s) certificates memory is unaligned\n", __FUNCTION__);
return FALSE;
}
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x92;
diCommand[freeCommandBuf].arg[0] = partitionWordOffset;
ioVec[0].base = (u8*)&diCommand[freeCommandBuf];
ioVec[0].length = sizeof(diCommand_t);
ioVec[1].base = (u8*)numTmdBytes;
ioVec[1].length = 4;
ioVec[2].base = (u8*)numCertBytes;
ioVec[2].length = 4;
rv = IOS_IoctlvAsync(DiFD, 0x92, 1, 2, ioVec, doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (%s) IOS_IoctlvAsync returned error: %d\n", __FUNCTION__, rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
#define is_aligned(addr) (((u32)(addr) & 0x1F) == 0)
BOOL DVDLowGetNoDiscOpenPartitionParams(const u32 partitionWordOffset, ESTicket* eTicket, u32* numTmdBytes, ESTitleMeta* tmd, u32* numCertBytes, u8* certificates, u32* dataWordOffset, u8* h3HashPtr, DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
if (eTicket == 0 || numTmdBytes == 0 || tmd == 0 || numCertBytes == 0 || certificates == 0 || dataWordOffset == 0 || h3HashPtr == 0) {
OSReport("(%s) Error: NULL pointer argument\n", __FUNCTION__);
return FALSE;
}
if (!is_aligned(eTicket) || !is_aligned(numTmdBytes) || !is_aligned(tmd) || !is_aligned(numCertBytes) || !is_aligned(certificates) || !is_aligned(dataWordOffset) || !is_aligned(h3HashPtr)) {
OSReport("(%s) pointer argument is unaligned\n", __FUNCTION__);
return FALSE;
}
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x90;
diCommand[freeCommandBuf].arg[0] = partitionWordOffset;
ioVec[0].base = (u8*)&diCommand[freeCommandBuf];
ioVec[0].length = sizeof(diCommand_t);
ioVec[1].base = (u8*)numTmdBytes;
ioVec[1].length = 4;
ioVec[2].base = (u8*)numCertBytes;
ioVec[2].length = 4;
ioVec[3].base = (u8*)eTicket;
ioVec[3].length = sizeof(ESTicket);
ioVec[4].base = (u8 *) numTmdBytes;
ioVec[4].length = 4;
ioVec[5].base = (u8*)tmd;
ioVec[5].length = *numTmdBytes;
ioVec[6].base = (u8*)numCertBytes;
ioVec[6].length = 4;
ioVec[7].base = certificates;
ioVec[7].length = *numCertBytes;
ioVec[8].base = (u8*)dataWordOffset;
ioVec[8].length = 4;
ioVec[9].base = h3HashPtr;
ioVec[9].length = 98304;
rv = IOS_IoctlvAsync(DiFD, 0x90, 3, 7, ioVec, doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (%s) IOS_IoctlvAsync returned error: %d\n", __FUNCTION__, rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowNoDiscOpenPartition() {
OSReport("DVDLowNoDiscOpenPartition");
return TRUE;
}
BOOL DVDLowClosePartition(DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x8C;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
rv = IOS_IoctlAsync(DiFD, 0x8C, &diCommand[freeCommandBuf], sizeof(diCommand_t), 0, 0, doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowClosePartition) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
BOOL DVDLowUnencryptedRead(void* destAddr, u32 length, u32 wordOffset, DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
readLength = length;
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x8D;
diCommand[freeCommandBuf].arg[0] = length;
diCommand[freeCommandBuf].arg[1] = wordOffset;
rv = IOS_IoctlAsync(DiFD, 0x8D, &diCommand[freeCommandBuf], sizeof(diCommand_t), destAddr, length, doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowUnencryptedRead) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
BOOL DVDLowStopMotor(u8 eject, u8 saving, DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0xE3;
diCommand[freeCommandBuf].arg[0] = eject;
diCommand[freeCommandBuf].arg[1] = saving;
rv = IOS_IoctlAsync(DiFD, 0xE3, &diCommand[freeCommandBuf], sizeof(diCommand_t), &diRegValCache, sizeof(diRegVals_t), doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowStopMotor) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowWaitForCoverClose() {
OSReport("@@@ (DVDLowWaitForCoverClose) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}
BOOL DVDLowInquiry(DVDDriveInfo* info, DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
if (breakRequested == 0) {}
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x12;
rv = IOS_IoctlAsync(DiFD, 0x12, &diCommand[freeCommandBuf], sizeof(diCommand_t), info, sizeof(DVDDriveInfo), doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowInquiry) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
BOOL DVDLowRequestError(DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0xE0;
rv = IOS_IoctlAsync(DiFD, 0xE0, &diCommand[freeCommandBuf], sizeof(diCommand_t), &diRegValCache, sizeof(diRegVals_t), doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowRequestError) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
BOOL DVDLowSetSpinupFlag(u32 spinUp) {
"(DVDLowSetSpinupFlag): Synch functions can't be called in callbacks\n"; // dead string
spinUpValue = spinUp;
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowNotifyReset() {
OSReport("@@@ (DVDLowNotifyReset) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}
BOOL DVDLowReset(DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x8A;
diCommand[freeCommandBuf].arg[0] = spinUpValue;
rv = IOS_IoctlAsync(DiFD, 0x8A, &diCommand[freeCommandBuf], sizeof(diCommand_t), 0, 0, doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowReset) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
BOOL DVDLowAudioBufferConfig(u8 enable, u32 size, DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0xE4;
diCommand[freeCommandBuf].arg[0] = enable;
diCommand[freeCommandBuf].arg[1] = size;
rv = IOS_IoctlAsync(DiFD, 0xE4, &diCommand[freeCommandBuf], sizeof(diCommand_t), &diRegValCache, sizeof(diRegVals_t), doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowAudioBufferConfig) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
u32 DVDLowGetCoverStatus() {
OSReport("(DVDLowGetCoverStatus): Synch functions can't be called in callbacks\n");
OSReport("@@@ (DVDLowGetCoverStatus) IOS_Ioctl returned error: %d\n");
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
u32 DVDLowReadDVD() {
OSReport("@@@ (DVDLowReadDVD) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowReadDVDConfig() {
OSReport("@@@ (DVDLowReadDVDConfig) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowReadDvdCopyright() {
OSReport("@@@ (DVDLowReadDvdCopyright) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowReadDvdPhysical() {
OSReport("@@@ (DVDLowReadDvdPhysical) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowReadDvdDiscKey() {
OSReport("@@@ (DVDLowReadDvdDiscKey) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}
BOOL DVDLowReportKey(DVDVideoReportKey* reportKey, u32 format, u32 lsn, DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0xA4;
diCommand[freeCommandBuf].arg[0] = format >> 16;
diCommand[freeCommandBuf].arg[1] = lsn;
rv = IOS_IoctlAsync(DiFD, 0xA4, &diCommand[freeCommandBuf], sizeof(diCommand_t), reportKey, sizeof(DVDVideoReportKey), doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowReportKey) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowOffset() {
OSReport("@@@ (DVDLowOffset) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowStopLaser() {
OSReport("@@@ (DVDLowStopLaser) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowReadDiskBca() {
OSReport("@@@ (DVDLowReadDiskBca) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowSerMeasControl() {
OSReport("@@@ (DVDLowSerMeasControl) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowRequestDiscStatus() {
OSReport("@@@ (DVDLowRequestDiscStatus) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowRequestRetryNumber() {
OSReport("@@@ (DVDLowRequestRetryNumber) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}
BOOL DVDLowSetMaximumRotation(u32 subcmd, DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0xDD;
diCommand[freeCommandBuf].arg[0] = (subcmd >> 16) & 3;
rv = IOS_IoctlAsync(DiFD, 0xDD, &diCommand[freeCommandBuf], sizeof(diCommand_t), 0, 0, doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowSetMaxRotation) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
BOOL DVDLowRead(void* destAddr, u32 length, u32 wordOffset, DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
if (((u32)destAddr & 0x1F) != 0) {
OSReport("(DVDLowRead): ERROR - destAddr buffer is not 32 byte aligned\n");
return FALSE;
}
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
readLength = length;
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x71;
diCommand[freeCommandBuf].arg[0] = length;
diCommand[freeCommandBuf].arg[1] = wordOffset;
rv = IOS_IoctlAsync(DiFD, 0x71, &diCommand[freeCommandBuf], sizeof(diCommand_t), destAddr, length, doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowRead) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
BOOL DVDLowSeek(u32 wordOffset, DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0xAB;
diCommand[freeCommandBuf].arg[0] = wordOffset;
rv = IOS_IoctlAsync(DiFD, 0xAB, &diCommand[freeCommandBuf], sizeof(diCommand_t), 0, 0, doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowSeek) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowGetCoverReg() {
OSReport("(DVDLowGetCoverReg): Synch functions can't be called in callbacks\n");
OSReport("@@@ (DVDLowGetCoverReg) IOS_Ioctl returned error: %d\n");
return TRUE;
}
u32 DVDLowGetCoverRegister(void) {
return diRegValCache.CoverRegVal;
}
u32 DVDLowGetStatusRegister(void) {
return statusRegister[0];
}
u32 DVDLowGetControlRegister(void) {
return controlRegister[0];
}
BOOL DVDLowPrepareCoverRegister(DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x7A;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
rv = IOS_IoctlAsync(DiFD, 0x7A, &diCommand[freeCommandBuf], sizeof(diCommand_t), registerBuf, sizeof(registerBuf), doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowPrepareCoverRegsiter) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
BOOL DVDLowPrepareStatusRegister(DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x95;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
rv = IOS_IoctlAsync(DiFD, 0x95, &diCommand[freeCommandBuf], sizeof(diCommand_t), statusRegister, sizeof(statusRegister), doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowPrepareStatusRegsiter) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
BOOL DVDLowPrepareControlRegister(DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x96;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
rv = IOS_IoctlAsync(DiFD, 0x96, &diCommand[freeCommandBuf], sizeof(diCommand_t), controlRegister, sizeof(controlRegister), doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowPrepareControlRegister) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
u32 DVDLowGetImmBufferReg(void) {
return diRegValCache.ImmRegVal;
}
BOOL DVDLowUnmaskStatusInterrupts(void) {
return TRUE;
}
BOOL DVDLowMaskCoverInterrupt(void) {
return TRUE;
}
BOOL DVDLowClearCoverInterrupt(DVDLowCallback callback) {
dvdContext_t* dvdContext;
IOSError rv;
nextCommandBuf(&freeCommandBuf);
diCommand[freeCommandBuf].theCommand = 0x86;
requestInProgress = TRUE;
dvdContext = newContext(callback, 1);
rv = IOS_IoctlAsync(DiFD, 0x86, &diCommand[freeCommandBuf], sizeof(diCommand_t), 0, 0, doTransactionCallback, dvdContext);
if (rv != IOS_ERROR_OK) {
OSReport("@@@ (DVDLowClearCoverInterrupt) IOS_IoctlAsync returned error: %d\n", rv);
dvdContext->inUse = FALSE;
return FALSE;
}
return TRUE;
}
BOOL __DVDLowTestAlarm(const OSAlarm *) {
return FALSE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
BOOL DVDLowEnableDvdVideo() {
OSReport("@@@ (DVDLowEnableDvdVideo) IOS_IoctlAsync returned error: %d\n");
return TRUE;
}

View File

@ -0,0 +1,202 @@
#include <revolution.h>
#include <revolution/os.h>
#include <revolution/dvd.h>
#include <revolution/nand.h>
#include "os/__os.h"
#include "__dvd.h"
static BOOL ExistFlag = FALSE;
static NANDCommandBlock NandCb;
static NANDFileInfo NandInfo;
static DVDCBCallback Callback;
static u32 NextOffset;
DVDErrorInfo __ErrorInfo ATTRIBUTE_ALIGN(32);
DVDErrorInfo __FirstErrorInfo ATTRIBUTE_ALIGN(32);
void cbForNandClose(s32 result, NANDCommandBlock* block) {
if (Callback) {
Callback((result == 0) ? 1 : 2, NULL);
}
}
void cbForNandWrite(s32 result, NANDCommandBlock* block) {
if (NANDCloseAsync(&NandInfo, cbForNandClose, &NandCb) != 0) {
if (Callback) {
Callback(2, NULL);
}
}
}
void cbForNandSeek(s32 result, NANDCommandBlock* block) {
if (result == sizeof(DVDErrorInfo) * (1 + NextOffset)) {
if (NextOffset == 0) {
__ErrorInfo.nextOffset = (1 + NextOffset) % 7;
}
DCFlushRange((void*)&__ErrorInfo, sizeof(__ErrorInfo));
if (NANDWriteAsync(&NandInfo, (void*)&__ErrorInfo, sizeof(__ErrorInfo), cbForNandWrite, &NandCb) != 0) {
cbForNandWrite(-1, NULL);
}
} else {
if (Callback) {
Callback(2, NULL);
}
}
}
void cbForNandWrite0(s32 result, NANDCommandBlock* block) {
if (result == sizeof(__FirstErrorInfo)) {
if (NANDSeekAsync(&NandInfo, (s32)(sizeof(DVDErrorInfo) * (1 + NextOffset)), 0, cbForNandSeek, &NandCb) != 0) {
cbForNandSeek(-1, NULL);
}
} else {
if (Callback) {
Callback(2, NULL);
}
}
}
void cbForNandSeek2(s32 result, NANDCommandBlock* block) {
if (result == sizeof(DVDErrorInfo)) {
__FirstErrorInfo.nextOffset = (__FirstErrorInfo.nextOffset + 1) % 7;
if (NANDWriteAsync(&NandInfo, (void*)&__FirstErrorInfo, sizeof(__FirstErrorInfo), cbForNandWrite0, &NandCb) != 0) {
cbForNandWrite0(-1, NULL);
}
} else {
if (Callback) {
Callback(2, NULL);
}
}
}
void cbForNandRead(s32 result, NANDCommandBlock* block) {
if (result == sizeof(DVDErrorInfo)) {
NextOffset = __FirstErrorInfo.nextOffset;
if (NANDSeekAsync(&NandInfo, sizeof(DVDErrorInfo), 0, cbForNandSeek2, &NandCb) != 0) {
cbForNandSeek2(-1, NULL);
}
} else {
__ErrorInfo.nextOffset = 1;
if (NANDWriteAsync(&NandInfo, (void*)&__ErrorInfo, sizeof(__ErrorInfo), cbForNandWrite, &NandCb) != 0) {
cbForNandWrite(-1, NULL);
}
}
}
void cbForNandSeek0(s32 result, NANDCommandBlock* block) {
if (result == 0) {
NextOffset = 0;
__ErrorInfo.nextOffset = 1;
if (NANDWriteAsync(&NandInfo, (void*)&__FirstErrorInfo, sizeof(__FirstErrorInfo), cbForNandWrite0, &NandCb) != 0) {
cbForNandWrite0(-1, NULL);
}
} else {
if (Callback) {
Callback(2, NULL);
}
}
}
void cbForNandSeek1(s32 result, NANDCommandBlock* block) {
if (result == sizeof(DVDErrorInfo)) {
if (NANDReadAsync(&NandInfo, (void*)&__FirstErrorInfo, sizeof(__FirstErrorInfo), cbForNandRead, &NandCb) != 0) {
cbForNandRead(-1, NULL);
}
} else {
if (NANDSeekAsync(&NandInfo, 0, 0, cbForNandSeek0, &NandCb) != 0) {
cbForNandSeek0(-1, NULL);
}
}
}
void cbForNandOpen(s32 result, NANDCommandBlock* block) {
if (result == 0) {
if (ExistFlag) {
if (NANDSeekAsync(&NandInfo, sizeof(DVDErrorInfo), 0, cbForNandSeek1, &NandCb) != 0) {
cbForNandSeek1(-1, NULL);
}
} else {
NextOffset = 0;
__ErrorInfo.nextOffset = 1;
if (NANDWriteAsync(&NandInfo, (void*)&__FirstErrorInfo, sizeof(__FirstErrorInfo), cbForNandWrite0, &NandCb) != 0) {
cbForNandWrite0(-1, NULL);
}
}
} else {
if (Callback) {
Callback(2, NULL);
}
}
}
void cbForNandCreate(s32 result, NANDCommandBlock* block) {
if (result == 0 || result == -6) {
if (result == -6) {
ExistFlag = TRUE;
}
if (NANDPrivateOpenAsync("/shared2/test2/dvderror.dat", &NandInfo, 3, cbForNandOpen, &NandCb) != 0) {
if (Callback) {
Callback(2, NULL);
}
}
} else {
if (Callback) {
Callback(2, NULL);
}
}
}
void cbForNandCreateDir(s32 result, NANDCommandBlock* block) {
if (result == 0 || result == -6) {
if (NANDPrivateCreateAsync("/shared2/test2/dvderror.dat", 0x3F, 0, cbForNandCreate, &NandCb) != 0) {
if (Callback) {
Callback(2, NULL);
}
}
} else {
if (Callback) {
Callback(2, NULL);
}
}
}
void cbForPrepareControlRegister(u32 intType) {
if (intType == 1) {
__ErrorInfo.unk_0x14 = DVDLowGetControlRegister();
} else {
__ErrorInfo.unk_0x14 = 0xFFFFFFFF;
}
if (NANDPrivateCreateDirAsync("/shared2/test2", 0x3F, 0, cbForNandCreateDir, &NandCb) != 0) {
if (Callback) {
Callback(2, NULL);
}
}
}
void cbForPrepareStatusRegister(u32 intType) {
if (intType == 1) {
__ErrorInfo.status = DVDLowGetStatusRegister();
} else {
__ErrorInfo.status = 0xFFFFFFFF;
}
if (DVDLowPrepareControlRegister(cbForPrepareControlRegister) == 0) {
if (Callback) {
Callback(2, NULL);
}
}
}
void __DVDStoreErrorCode(u32 error, DVDCBCallback callback) {
__ErrorInfo.error = error;
__ErrorInfo.dateTime = (u32)OSTicksToSeconds(OSGetTime());
Callback = callback;
DVDLowPrepareStatusRegister(cbForPrepareStatusRegister);
}

557
src/revolution/dvd/dvdfs.c Normal file
View File

@ -0,0 +1,557 @@
#include <revolution.h>
#include <revolution/dvd.h>
#include "__dvd.h"
typedef struct FSTEntry {
/* 0x00 */ unsigned int isDirAndStringOff;
/* 0x04 */ unsigned int parentOrPosition;
/* 0x08 */ unsigned int nextEntryOrLength;
} FSTEntry;
static OSBootInfo* BootInfo;
static FSTEntry* FstStart;
static char* FstStringStart;
static u32 MaxEntryNum;
static u32 currentDirectory;
OSThreadQueue __DVDThreadQueue;
u32 __DVDLongFileNameFlag = 1;
// prototypes
static BOOL isSame(const char* path, const char* string);
static u32 myStrncpy(char* dest, char* src, u32 maxlen);
static u32 entryToPath(u32 entry, char* path, u32 maxlen);
static BOOL DVDConvertEntrynumToPath(s32 entrynum, char* path, u32 maxlen);
static void cbForReadAsync(s32 result, DVDCommandBlock* block);
static void cbForReadSync(s32 result, DVDCommandBlock* block);
static void cbForSeekAsync(s32 result, DVDCommandBlock* block);
static void cbForSeekSync(s32 result, DVDCommandBlock* block);
static void cbForPrepareStreamAsync(s32 result, DVDCommandBlock* block);
static void cbForPrepareStreamSync(s32 result, DVDCommandBlock* block);
void __DVDFSInit(void) {
BootInfo = (void*)OSPhysicalToCached(0);
FstStart = BootInfo->FSTLocation;
if (FstStart) {
MaxEntryNum = FstStart->nextEntryOrLength;
FstStringStart = (char*)FstStart + (MaxEntryNum* sizeof(FSTEntry));
}
}
/* For convenience */
#define entryIsDir(i) (((FstStart[i].isDirAndStringOff & 0xff000000) == 0) ? FALSE : TRUE)
#define stringOff(i) (FstStart[i].isDirAndStringOff & ~0xff000000)
#define parentDir(i) (FstStart[i].parentOrPosition)
#define nextDir(i) (FstStart[i].nextEntryOrLength)
#define filePosition(i) (FstStart[i].parentOrPosition)
#define fileLength(i) (FstStart[i].nextEntryOrLength)
static BOOL isSame(const char* path, const char* string) {
while (*string != '\0') {
if (tolower(*path++) != tolower(*string++)) {
return FALSE;
}
}
if (*path == '/' || *path == '\0') {
return TRUE;
}
return FALSE;
}
s32 DVDConvertPathToEntrynum(const char* pathPtr) {
const char* ptr;
char* stringPtr;
BOOL isDir;
u32 length;
u32 dirLookAt;
u32 i;
const char* origPathPtr = pathPtr;
const char* extentionStart;
BOOL illegal;
BOOL extention;
ASSERTMSGLINE(383, pathPtr, "DVDConvertPathToEntrynum(): null pointer is specified ");
dirLookAt = currentDirectory;
while (1) {
if (*pathPtr == '\0') {
return (s32)dirLookAt;
} else if (*pathPtr == '/') {
dirLookAt = 0;
pathPtr++;
continue;
} else if (*pathPtr == '.') {
if (*(pathPtr + 1) == '.') {
if (*(pathPtr + 2) == '/') {
dirLookAt = parentDir(dirLookAt);
pathPtr += 3;
continue;
} else if (*(pathPtr + 2) == '\0') {
return (s32)parentDir(dirLookAt);
}
} else if (*(pathPtr + 1) == '/') {
pathPtr += 2;
continue;
} else if (*(pathPtr + 1) == '\0') {
return (s32)dirLookAt;
}
}
if (__DVDLongFileNameFlag == 0) {
extention = FALSE;
illegal = FALSE;
for (ptr = pathPtr; (*ptr != '\0') && (*ptr != '/'); ptr++) {
if (*ptr == '.') {
if ((ptr - pathPtr > 8) || (extention == TRUE)) {
illegal = TRUE;
break;
}
extention = TRUE;
extentionStart = ptr + 1;
} else if (*ptr == ' ')
illegal = TRUE;
}
if ((extention == TRUE) && (ptr - extentionStart > 3))
illegal = TRUE;
if (illegal)
OSPanic(__FILE__, 452,
"DVDConvertEntrynumToPath(possibly DVDOpen or DVDChangeDir or DVDOpenDir): "
"specified directory or file (%s) doesn't match standard 8.3 format. This is a "
"temporary restriction and will be removed soon\n",
origPathPtr);
} else {
for (ptr = pathPtr; (*ptr != '\0') && (*ptr != '/'); ptr++)
;
}
isDir = (*ptr == '\0') ? FALSE : TRUE;
length = (u32)(ptr - pathPtr);
ptr = pathPtr;
for (i = dirLookAt + 1; i < nextDir(dirLookAt); i = entryIsDir(i) ? nextDir(i) : (i + 1)) {
if ((entryIsDir(i) == FALSE) && (isDir == TRUE)) {
continue;
}
stringPtr = FstStringStart + stringOff(i);
if (isSame(ptr, stringPtr) == TRUE) {
goto next_hier;
}
}
return -1;
next_hier:
if (!isDir) {
return (s32)i;
}
dirLookAt = i;
pathPtr += length + 1;
}
}
BOOL DVDFastOpen(s32 entrynum, DVDFileInfo* fileInfo) {
ASSERTMSGLINE(536, fileInfo, "DVDFastOpen(): null pointer is specified to file info address ");
ASSERTMSG1LINE(539, (entrynum >= 0) && ((u32) entrynum < (u32) MaxEntryNum), "DVDFastOpen(): specified entry number '%d' is out of range ", entrynum);
ASSERTMSG1LINE(542, !entryIsDir(entrynum), "DVDFastOpen(): entry number '%d' is assigned to a directory ", entrynum);
if (entrynum < 0 || entrynum >= MaxEntryNum || entryIsDir(entrynum)) {
return FALSE;
}
fileInfo->startAddr = filePosition(entrynum) >> __DVDLayoutFormat;
fileInfo->length = fileLength(entrynum);
fileInfo->callback = (DVDCallback)NULL;
fileInfo->cb.state = DVD_STATE_END;
return TRUE;
}
BOOL DVDOpen(const char* fileName, DVDFileInfo* fileInfo) {
s32 entry;
char currentDir[128];
ASSERTMSGLINE(572, fileName, "DVDOpen(): null pointer is specified to file name ");
ASSERTMSGLINE(573, fileInfo, "DVDOpen(): null pointer is specified to file info address ");
entry = DVDConvertPathToEntrynum(fileName);
if (0 > entry) {
DVDGetCurrentDir(currentDir, 128);
OSReport("Warning: DVDOpen(): file '%s' was not found under %s.\n", fileName, currentDir);
return FALSE;
}
if (entryIsDir(entry)) {
ASSERTMSG1LINE(587, !entryIsDir(entry), "DVDOpen(): directory '%s' is specified as a filename ", fileName);
return FALSE;
}
fileInfo->startAddr = filePosition(entry) >> __DVDLayoutFormat;
fileInfo->length = fileLength(entry);
fileInfo->callback = (DVDCallback)NULL;
fileInfo->cb.state = DVD_STATE_END;
return TRUE;
}
BOOL DVDClose(DVDFileInfo* fileInfo) {
ASSERTMSGLINE(611, fileInfo, "DVDClose(): null pointer is specified to file info address ");
DVDCancel(&(fileInfo->cb));
return TRUE;
}
static u32 myStrncpy(char* dest, char* src, u32 maxlen) {
u32 i = maxlen;
while ((i > 0) && (*src != 0)) {
*dest++ = *src++;
i--;
}
return (maxlen - i);
}
static u32 entryToPath(u32 entry, char* path, u32 maxlen) {
u32 i;
char* name;
u32 loc;
if (entry == 0) {
return 0;
}
name = FstStringStart + stringOff(entry);
if (entryIsDir(entry)) {
i = parentDir(entry);
} else {
i = entry;
while (i != 0) {
if (entryIsDir(i) && nextDir(i) > entry) {
break;
}
i--;
}
}
loc = entryToPath(i, path, maxlen);
if (loc == maxlen) {
return loc;
}
*(path + loc++) = '/';
loc += myStrncpy(path + loc, name, maxlen - loc);
return loc;
}
static BOOL DVDConvertEntrynumToPath(s32 entrynum, char* path, u32 maxlen) {
u32 loc;
ASSERTMSG1LINE(721, (entrynum >= 0) && (entrynum < MaxEntryNum), "DVDConvertEntrynumToPath: specified entrynum(%d) is out of range ", entrynum);
ASSERTMSG1LINE(723, maxlen > 1, "DVDConvertEntrynumToPath: maxlen should be more than 1 (%d is specified)", maxlen);
loc = entryToPath((u32)entrynum, path, maxlen);
if (loc == maxlen) {
path[maxlen - 1] = '\0';
return FALSE;
}
if (entryIsDir(entrynum)) {
if (loc == maxlen - 1) {
path[loc] = '\0';
return FALSE;
}
path[loc++] = '/';
}
path[loc] = '\0';
return TRUE;
}
BOOL DVDGetCurrentDir(char* path, u32 maxlen) {
ASSERTMSG1LINE(765, (maxlen > 1), "DVDGetCurrentDir: maxlen should be more than 1 (%d is specified)", maxlen);
return DVDConvertEntrynumToPath((s32)currentDirectory, path, maxlen);
}
BOOL DVDChangeDir(const char* dirName) {
s32 entry;
char currentDir[128];
ASSERTMSGLINE(787, dirName, "DVDChangeDir(): null pointer is specified to directory name ");
entry = DVDConvertPathToEntrynum(dirName);
ASSERTMSG2LINE(795, entry >= 0, "DVDChangeDir(): directory '%s' is not found under %s ", dirName, (DVDGetCurrentDir(currentDir, 128), currentDir));
ASSERTMSG1LINE(799, entryIsDir(entry), "DVDChangeDir(): file '%s' is specified as a directory name ", dirName);
if (entry < 0 || entryIsDir(entry) == FALSE) {
return FALSE;
}
currentDirectory = (u32)entry;
return TRUE;
}
BOOL DVDReadAsyncPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, DVDCallback callback, s32 prio) {
ASSERTMSGLINE(831, fileInfo, "DVDReadAsync(): null pointer is specified to file info address ");
ASSERTMSGLINE(832, addr, "DVDReadAsync(): null pointer is specified to addr ");
ASSERTMSGLINE(836, !OFFSET(addr, 32), "DVDReadAsync(): address must be aligned with 32 byte boundaries ");
ASSERTMSGLINE(838, !(length & 0x1F), "DVDReadAsync(): length must be multiple of 32 byte ");
ASSERTMSGLINE(840, !(offset & 3), "DVDReadAsync(): offset must be multiple of 4 byte ");
DVD_ASSERTMSGLINE(845, (0 <= offset) && (offset <= fileInfo->length), "DVDReadAsync(): specified area is out of the file ");
DVD_ASSERTMSGLINE(851, (0 <= offset + length) && (offset + length < fileInfo->length + DVD_MIN_TRANSFER_SIZE), "DVDReadAsync(): specified area is out of the file ");
fileInfo->callback = callback;
DVDReadAbsAsyncPrio(&(fileInfo->cb), addr, length, (s32)(fileInfo->startAddr + (offset >> 2)),
cbForReadAsync, prio);
return TRUE;
}
#ifndef offsetof
#define offsetof(type, memb) ((u32) & ((type*)0)->memb)
#endif
static void cbForReadAsync(s32 result, DVDCommandBlock* block) {
DVDFileInfo* fileInfo;
fileInfo = (DVDFileInfo*)((char*)block - offsetof(DVDFileInfo, cb));
ASSERTLINE(869, (void*) &fileInfo->cb == (void*) block);
if (fileInfo->callback) {
(fileInfo->callback)(result, fileInfo);
}
}
s32 DVDReadPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, s32 prio) {
int result;
DVDCommandBlock* block;
s32 state;
BOOL enabled;
s32 retVal;
ASSERTMSGLINE(901, fileInfo, "DVDRead(): null pointer is specified to file info address ");
ASSERTMSGLINE(902, addr, "DVDRead(): null pointer is specified to addr ");
ASSERTMSGLINE(906, !OFFSET(addr, 32), "DVDRead(): address must be aligned with 32 byte boundaries ");
ASSERTMSGLINE(908, !(length & 0x1F), "DVDRead(): length must be multiple of 32 byte ");
ASSERTMSGLINE(910, !(offset & 3), "DVDRead(): offset must be multiple of 4 byte ");
DVD_ASSERTMSGLINE(915, (0 <= offset) && (offset <= fileInfo->length), "DVDRead(): specified area is out of the file ");
DVD_ASSERTMSGLINE(921, (0 <= offset + length) && (offset + length < fileInfo->length + DVD_MIN_TRANSFER_SIZE), "DVDRead(): specified area is out of the file ");
block = &fileInfo->cb;
result = DVDReadAbsAsyncPrio(block, addr, length, fileInfo->startAddr + (offset >> 2), cbForReadSync, prio);
if (result == 0) {
return -1;
}
enabled = OSDisableInterrupts();
while (1) {
state = ((volatile DVDCommandBlock*)block)->state;
if (state == 0) {
retVal = (s32)block->transferredSize;
break;
} else if (state == -1) {
retVal = -1;
break;
} else if (state == 10) {
retVal = -3;
break;
}
OSSleepThread(&__DVDThreadQueue);
}
OSRestoreInterrupts(enabled);
return retVal;
}
static void cbForReadSync(s32 result, DVDCommandBlock* block) {
OSWakeupThread(&__DVDThreadQueue);
}
int DVDSeekAsyncPrio(DVDFileInfo* fileInfo, s32 offset, DVDCallback callback, s32 prio) {
ASSERTMSGLINE(898, fileInfo, "DVDSeek(): null pointer is specified to file info address ");
ASSERTMSGLINE(902, !(offset & 3), "DVDSeek(): offset must be multiple of 4 byte ");
DVD_ASSERTMSGLINE(907, (0 <= offset) && (offset <= fileInfo->length), "DVDSeek(): offset is out of the file ");
fileInfo->callback = callback;
DVDSeekAbsAsyncPrio(&fileInfo->cb, (u32)(char*)fileInfo->startAddr + offset, cbForSeekAsync, prio);
return 1;
}
static void cbForSeekAsync(s32 result, DVDCommandBlock* block) {
DVDFileInfo* fileInfo;
fileInfo = (DVDFileInfo *)&block->next;
ASSERTLINE(925, (void*) &fileInfo->cb == (void*) block);
if (fileInfo->callback) {
(fileInfo->callback)(result, fileInfo);
}
}
s32 DVDSeekPrio(DVDFileInfo* fileInfo, s32 offset, s32 prio) {
int result;
DVDCommandBlock* block;
s32 state;
BOOL enabled;
s32 retVal;
ASSERTMSGLINE(955, fileInfo, "DVDSeek(): null pointer is specified to file info address ");
ASSERTMSGLINE(959, !(offset & 3), "DVDSeek(): offset must be multiple of 4 byte ");
ASSERTMSGLINE(963, (offset >= 0) && ((u32) offset <= (u32) fileInfo->length), "DVDSeek(): offset is out of the file ");
block = &fileInfo->cb;
result = DVDSeekAbsAsyncPrio(block, (u32)(char*)fileInfo->startAddr + offset, cbForSeekSync, prio);
if (!result) {
return -1;
}
enabled = OSDisableInterrupts();
while (1) {
state = ((volatile DVDCommandBlock*)block)->state;
if (state == 0) {
retVal = 0;
break;
} else if (state == -1) {
retVal = -1;
break;
} else if (state == 10) {
retVal = -3;
break;
}
OSSleepThread(&__DVDThreadQueue);
}
OSRestoreInterrupts(enabled);
return retVal;
}
static void cbForSeekSync(s32 result, DVDCommandBlock* block) {
OSWakeupThread(&__DVDThreadQueue);
}
s32 DVDGetFileInfoStatus(const DVDFileInfo* fileInfo) {
return DVDGetCommandBlockStatus(&fileInfo->cb);
}
BOOL DVDFastOpenDir(s32 entrynum, DVDDir* dir) {
ASSERTMSGLINE(1048, dir, "DVDFastOpenDir(): null pointer is specified to dir structure address ");
ASSERTMSG1LINE(1051, entrynum >= 0 && entrynum < MaxEntryNum, "DVDFastOpenDir(): specified entry number \'%d\' is out of range ", entrynum);
ASSERTMSG1LINE(1054, entryIsDir(entrynum), "DVDFastOpenDir(): entry number \'%d\' is assigned to a file ", entrynum);
if (entrynum < 0 || entrynum >= MaxEntryNum || !entryIsDir(entrynum)) {
return FALSE;
}
dir->entryNum = entrynum;
dir->location = entrynum + 1;
dir->next = FstStart[entrynum].nextEntryOrLength;
return TRUE;
}
BOOL DVDOpenDir(const char* dirName, DVDDir* dir) {
s32 entry;
char currentDir[128];
ASSERTMSGLINE(1178, dirName, "DVDOpendir(): null pointer is specified to directory name ");
ASSERTMSGLINE(1179, dir, "DVDOpenDir(): null pointer is specified to dir structure address ");
entry = DVDConvertPathToEntrynum(dirName);
if (entry < 0) {
DVDGetCurrentDir(currentDir, sizeof(currentDir));
OSReport("Warning: DVDOpenDir(): file \'%s\' was not found under %s.\n", dirName, currentDir);
return FALSE;
}
if (!entryIsDir(entry)) {
ASSERTMSG1LINE(1193, entryIsDir(entry), "DVDOpendir(): file \'%s\' is specified as a directory name ", dirName);
return FALSE;
}
dir->entryNum = entry;
dir->location = entry + 1;
dir->next = nextDir(entry);
return TRUE;
}
int DVDReadDir(DVDDir* dir, DVDDirEntry* dirent) {
u32 loc;
loc = dir->location;
if ((loc <= (u32) dir->entryNum) || ((u32) dir->next <= loc)) {
return 0;
}
dirent->entryNum = loc;
dirent->isDir = entryIsDir(loc);
dirent->name = FstStringStart + stringOff(loc);
dir->location = entryIsDir(loc) ? nextDir(loc) : loc + 1;
return 1;
}
int DVDCloseDir(DVDDir* dir) {
return 1;
}
void DVDRewindDir(DVDDir* dir) {
dir->location = dir->entryNum + 1;
}
void* DVDGetFSTLocation(void) {
return BootInfo->FSTLocation;
}
s32 DVDGetTransferredSize(DVDFileInfo* fileinfo) {
s32 bytes;
DVDCommandBlock* cb;
cb = &(fileinfo->cb);
switch (cb->state) {
case DVD_STATE_COVER_CLOSED:
case DVD_STATE_NO_DISK:
case DVD_STATE_COVER_OPEN:
case DVD_STATE_WRONG_DISK:
case DVD_STATE_FATAL_ERROR:
case DVD_STATE_MOTOR_STOPPED:
case DVD_STATE_CANCELED:
case DVD_STATE_RETRY:
case DVD_STATE_END:
bytes = (s32)cb->transferredSize;
break;
case DVD_STATE_WAITING:
bytes = 0;
break;
case DVD_STATE_BUSY:
bytes = (s32)(cb->transferredSize + (cb->currTransferSize - __DIRegs[6]));
break;
default:
ASSERTMSG1LINE(1391, FALSE, "DVDGetTransferredSize(): Illegal state (%d)", cb->state);
break;
}
return bytes;
}
// NOTE: function doesn't exist in TP debug, needed for string data
void DVDGetEntrynum() {
OSReport("DVDGetEntrynum(): null pointer is specified to file info address ");
}
// NOTE: function doesn't exist in TP debug, needed for string data
void DVDGetEntryName() {
OSReport("DVDGetEntryName: specified entrynum(%d) is out of range ");
}

View File

@ -0,0 +1,98 @@
#include <revolution.h>
#include <revolution/dvd.h>
#include <string.h>
#include "__dvd.h"
static u32 strnlen(const char* str, u32 maxlen) {
u32 i;
for (i = 0; i < maxlen; i++) {
if (*str++ == 0) {
return i;
}
}
return maxlen;
}
int DVDCompareDiskID(const DVDDiskID* id1, const DVDDiskID* id2) {
#ifdef DEBUG
const char* game1;
const char* game2;
const char* company1;
const char* company2;
u8 diskNum1;
u8 diskNum2;
u8 version1;
u8 version2;
u32 length;
ASSERTMSGLINE(70, id1, "DVDCompareDiskID(): Specified id1 is NULL\n");
ASSERTMSGLINE(71, id2, "DVDCompareDiskID(): Specified id2 is NULL\n");
game1 = id1->gameName;
game2 = id2->gameName;
company1 = id1->company;
company2 = id2->company;
diskNum1 = id1->diskNumber;
diskNum2 = id2->diskNumber;
version1 = id1->gameVersion;
version2 = id2->gameVersion;
length = strnlen(game1, sizeof(game1));
ASSERTMSGLINE(84, length == 0 || length == 4, "DVDCompareDiskID(): Specified game name for id1 is neither NULL nor 4 character long\n");
ASSERTMSGLINE(85, company1, "DVDCompareDiskID(): Specified company name for id1 is NULL\n");
ASSERTMSGLINE(86, company1[1] != 0, "DVDCompareDiskID(): Specified company name for id1 is not 2 character long\n");
ASSERTMSGLINE(87, diskNum1 == 0xFF || ((diskNum1 / 16) < 10 && diskNum1 % 16 < 10), "DVDCompareDiskID(): Specified disk number for id1 is neither 0xff nor a BCD number");
ASSERTMSGLINE(88, version1 == 0xFF || ((version1 / 16) < 10 && version1 % 16 < 10), "DVDCompareDiskID(): Specified version number for id1 is neither 0xff nor a BCD number");
length = strnlen(game2, sizeof(game2));
ASSERTMSGLINE(91, length == 0 || length == 4, "DVDCompareDiskID(): Specified game name for id2 is neither NULL nor 4 character long\n");
ASSERTMSGLINE(92, company2, "DVDCompareDiskID(): Specified company name for id2 is NULL\n");
ASSERTMSGLINE(93, company2[1] != 0, "DVDCompareDiskID(): Specified company name for id2 is not 2 character long\n");
ASSERTMSGLINE(94, diskNum2 == 0xFF || ((diskNum2 / 16) < 10 && diskNum2 % 16 < 10), "DVDCompareDiskID(): Specified disk number for id2 is neither 0xff nor a BCD number");
ASSERTMSGLINE(95, version2 == 0xFF || ((version2 / 16) < 10 && version2 % 16 < 10), "DVDCompareDiskID(): Specified version number for id2 is neither 0xff nor a BCD number");
#endif
if (id1->gameName[0] != 0 && id2->gameName[0] != 0 && strncmp(id1->gameName, id2->gameName, 4) != 0) {
return 0;
}
if (id1->company[0] == 0 || id2->company[0] == 0 || strncmp(id1->company, id2->company, 2) != 0) {
return 0;
}
if (id1->diskNumber != 0xFF && id2->diskNumber != 0xFF && id1->diskNumber != id2->diskNumber) {
return 0;
}
if (id1->gameVersion != 0xFF && id2->gameVersion != 0xFF && id1->gameVersion != id2->gameVersion) {
return 0;
}
return 1;
}
DVDDiskID* DVDGenerateDiskID(DVDDiskID* id, const char* game, const char* company, u8 diskNum, u8 version) {
ASSERTMSGLINE(123, id, "DVDGenerateDiskID(): Specified id is NULL\n");
ASSERTMSGLINE(124, game == NULL || strlen(game) == 4, "DVDGenerateDiskID(): Specified game name is neither NULL nor 4 character long\n");
ASSERTMSGLINE(125, company, "DVDGenerateDiskID(): Specified company name is NULL\n");
ASSERTMSGLINE(126, strlen(company) == 2, "DVDGenerateDiskID(): Specified company name is not 2 character long\n");
ASSERTMSGLINE(127, diskNum == 0xFF || ((diskNum / 16) < 10 && diskNum % 16 < 10), "DVDGenerateDiskID(): Specified disk number is neither 0xff nor a BCD number");
ASSERTMSGLINE(128, version == 0xFF || ((version / 16) < 10 && version % 16 < 10), "DVDGenerateDiskID(): Specified version number is neither 0xff nor a BCD number");
memset(id, 0, sizeof(DVDDiskID));
if (game != NULL) {
strncpy(id->gameName, game, 4);
}
if (company != NULL) {
strncpy(id->company, company, 2);
}
id->diskNumber = diskNum;
id->gameVersion = version;
return id;
}

View File

@ -0,0 +1,192 @@
#include <revolution.h>
#include <revolution/dvd.h>
#include "__dvd.h"
static struct {
/* 0x00 */ DVDCommandBlock* next;
/* 0x04 */ DVDCommandBlock* prev;
} WaitingQueue[4];
// prototypes
static DVDCommandBlock* PopWaitingQueuePrio(s32 prio);
void __DVDClearWaitingQueue(void) {
u32 i;
for(i = 0; i < 4; i++) {
DVDCommandBlock* q = (DVDCommandBlock*)&WaitingQueue[i].next;
q->next = q;
q->prev = q;
}
}
int __DVDPushWaitingQueue(s32 prio, DVDCommandBlock* block) {
BOOL enabled = OSDisableInterrupts();
DVDCommandBlock* q = (DVDCommandBlock*)&WaitingQueue[prio];
q->prev->next = block;
block->prev = q->prev;
block->next = q;
q->prev = block;
OSRestoreInterrupts(enabled);
return 1;
}
static DVDCommandBlock* PopWaitingQueuePrio(s32 prio) {
DVDCommandBlock* tmp;
BOOL enabled;
DVDCommandBlock* q;
enabled = OSDisableInterrupts();
q = (DVDCommandBlock*)&WaitingQueue[prio];
ASSERTLINE(99, q->next != q);
tmp = q->next;
q->next = tmp->next;
tmp->next->prev = q;
OSRestoreInterrupts(enabled);
tmp->next = 0;
tmp->prev = 0;
return tmp;
}
DVDCommandBlock* __DVDPopWaitingQueue(void) {
u32 i;
BOOL enabled;
DVDCommandBlock* q;
enabled = OSDisableInterrupts();
for (i = 0; i < 4; i++) {
q = (DVDCommandBlock*)&WaitingQueue[i];
if (q->next != q) {
OSRestoreInterrupts(enabled);
return PopWaitingQueuePrio(i);
}
}
OSRestoreInterrupts(enabled);
return NULL;
}
int __DVDCheckWaitingQueue(void) {
u32 i;
BOOL enabled;
DVDCommandBlock* q;
enabled = OSDisableInterrupts();
for (i = 0; i < 4; i++) {
q = (DVDCommandBlock*)&WaitingQueue[i];
if (q->next != q) {
OSRestoreInterrupts(enabled);
return 1;
}
}
OSRestoreInterrupts(enabled);
return 0;
}
DVDCommandBlock* __DVDGetNextWaitingQueue(void) {
u32 i;
BOOL enabled;
DVDCommandBlock* q, *tmp;
enabled = OSDisableInterrupts();
for (i = 0; i < 4; i++) {
q = (DVDCommandBlock*)&(WaitingQueue[i]);
if (q->next != q) {
tmp = q->next;
OSRestoreInterrupts(enabled);
return tmp;
}
}
OSRestoreInterrupts(enabled);
return NULL;
}
int __DVDDequeueWaitingQueue(DVDCommandBlock* block) {
BOOL enabled;
DVDCommandBlock* prev;
DVDCommandBlock* next;
enabled = OSDisableInterrupts();
prev = block->prev;
next = block->next;
if (prev == NULL || next == NULL) {
OSRestoreInterrupts(enabled);
return 0;
}
prev->next = next;
next->prev = prev;
OSRestoreInterrupts(enabled);
return 1;
}
int __DVDIsBlockInWaitingQueue(DVDCommandBlock* block) {
u32 i;
DVDCommandBlock* start;
DVDCommandBlock* q;
for (i = 0; i < 4; i++) {
start = (DVDCommandBlock*)&WaitingQueue[i];
if (start->next == start) {
continue;
}
for (q = start->next; q != start; q = q->next) {
if (q == block) {
return 1;
}
}
}
return 0;
}
static char* CommandNames[16] = {
"",
"READ",
"SEEK",
"CHANGE_DISK",
"BSREAD",
"READID",
"INITSTREAM",
"CANCELSTREAM",
"STOP_STREAM_AT_END",
"REQUEST_AUDIO_ERROR",
"REQUEST_PLAY_ADDR",
"REQUEST_START_ADDR",
"REQUEST_LENGTH",
"AUDIO_BUFFER_CONFIG",
"INQUIRY",
"BS_CHANGE_DISK",
};
void DVDDumpWaitingQueue(void) {
u32 i;
DVDCommandBlock* start;
DVDCommandBlock* q;
OSReport("==== DVD Waiting Queue Status ====\n");
for (i = 0; i < 4; i++) {
OSReport("< Queue #%d > ", i);
start = (DVDCommandBlock*)&WaitingQueue[i];
if (start->next == start) {
OSReport("None\n");
} else {
OSReport("\n");
for (q = start->next; q != start; q = q->next) {
OSReport("0x%08x: Command: %s ", q, CommandNames[q->command]);
if (q->command == 1) {
OSReport("Disk offset: %d, Length: %d, Addr: 0x%08x\n", q->offset, q->length, q->addr);
} else {
OSReport("\n");
}
}
}
}
}

973
src/revolution/fs/fs.c Normal file
View File

@ -0,0 +1,973 @@
#include <revolution/fs.h>
#include <revolution/ipc.h>
#include <string.h>
static IOSFd __fsFd = -1;
static u32 __fsInitialized = FALSE;
static char* __devfs = 0;
static IOSHeapId hId;
static s32 _asynCnt = 0;
#define ROUNDUP(sz) (((u32)(sz) + 31) & ~(u32)(31))
typedef struct isfs_GetAttr {
IOSUid* ownerId;
IOSGid* groupId;
u32* attr;
u32* ownerAcc;
u32* groupAcc;
u32* othersAcc;
} isfs_GetAttr;
typedef struct isfs_GetUsage {
u32* nblocks;
u32* ninodes;
} isfs_GetUsage;
typedef struct __isfsCtxt {
u8 ioBuf[ROUNDUP(256)] ATTRIBUTE_ALIGN(32);
ISFSCallback cb;
void* ctxt;
u32 func;
union {
ISFSStats* stats;
ISFSFileStats* fstats;
u32* num;
isfs_GetAttr ga;
isfs_GetUsage gu;
} args;
} __isfsCtxt;
static IOSError _FSGetStatsCb(IOSError ret, void* ctxt);
static IOSError _FSReadDirCb(IOSError ret, void* ctxt);
static IOSError _FSGetAttrCb(IOSError ret, void* ctxt);
static IOSError _FSGetUsageCb(IOSError ret, void* ctxt);
static IOSError _FSGetFileStatsCb(IOSError ret, void* ctxt);
ISFSError ISFS_OpenLib(void) {
ISFSError rc = 0;
static void* lo = 0, *hi = 0;
__isfsCtxt* __fsCtxt = 0;
if (!__fsInitialized) {
lo = IPCGetBufferLo();
hi = IPCGetBufferHi();
}
__devfs = (char*)ROUNDUP(lo);
if (!__fsInitialized && ((u32)__devfs + ROUNDUP(64)) > (u32)hi) {
OSReport("APP ERROR: Not enough IPC arena\n");
rc = -22;
goto out;
}
strcpy(__devfs, "/dev/fs");
__fsFd = IOS_Open(__devfs, 0);
if (__fsFd < 0) {
rc = __fsFd;
goto out;
}
__fsCtxt = (__isfsCtxt*)((u32)__devfs);
if (!__fsInitialized && ((u32)__fsCtxt + (16 + 1) * ROUNDUP(sizeof(__isfsCtxt))) > (u32)hi) {
OSReport("APP ERROR: Not enough IPC arena\n");
rc = -22;
goto out;
}
if (!__fsInitialized) {
IPCSetBufferLo((void*)((u32)__fsCtxt + (17) * ROUNDUP(sizeof(__isfsCtxt))));
__fsInitialized = TRUE;
}
hId = iosCreateHeap(__fsCtxt, 17 * ROUNDUP(sizeof(__isfsCtxt)));
if (hId < 0) {
rc = -22;
goto out;
}
out:
return rc;
}
IOSError _isfsFuncCb(IOSError ret, void* ctxt) {
ISFSError rc = 0;
__isfsCtxt* _ctxt = (__isfsCtxt*)ctxt;
rc = ret;
if (rc >= 0) {
switch (_ctxt->func) {
case 1:
_FSGetStatsCb(ret, ctxt);
break;
case 2:
_FSReadDirCb(ret, ctxt);
break;
case 3:
_FSGetAttrCb(ret, ctxt);
break;
case 4:
_FSGetUsageCb(ret, ctxt);
break;
case 5:
_FSGetFileStatsCb(ret, ctxt);
break;
default:
break;
}
}
_asynCnt = 0;
if (_ctxt->cb) {
_ctxt->cb(rc, _ctxt->ctxt);
}
if (ctxt) {
iosFree(hId, ctxt);
}
return rc;
}
static IOSError _FSGetStatsCb(IOSError ret, void* ctxt) {
__isfsCtxt* _ctxt = (__isfsCtxt*)ctxt;
ISFSError rc = ISFS_ERROR_OK;
if (ret == 0) {
memcpy(_ctxt->args.stats, _ctxt->ioBuf, sizeof(*_ctxt->args.stats));
}
return rc;
}
s32 ISFS_CreateDir(const u8* dname, u32 dirAttr, u32 ownerAcc, u32 groupAcc, u32 othersAcc) {
ISFSError rc = ISFS_ERROR_OK;
ISFSPathAttrArgs* pathAttrArgs;
__isfsCtxt* blCtxt = 0;
u32 len;
if (dname == NULL || __fsFd < 0 || (len = strnlen(dname, 64)) == 64) {
rc = ISFS_ERROR_INVALID;
goto out;
}
blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32);
if (blCtxt == 0) {
rc = IOS_ERROR_FAIL_ALLOC;
goto out;
}
pathAttrArgs = (ISFSPathAttrArgs*)blCtxt->ioBuf;
memcpy(pathAttrArgs->path, dname, len + 1);
pathAttrArgs->attr = (u8)dirAttr;
pathAttrArgs->ownerAccess = (u8)ownerAcc;
pathAttrArgs->groupAccess = (u8)groupAcc;
pathAttrArgs->othersAccess = (u8)othersAcc;
rc = IOS_Ioctl(__fsFd, 3, pathAttrArgs, sizeof(*pathAttrArgs), NULL, 0);
out:
/* they seem to have had a macro for this, and the programmer forgot it did a NULL check */
if (blCtxt != 0) {
if (blCtxt != 0) {
iosFree(hId, blCtxt);
}
}
return rc;
}
s32 ISFS_CreateDirAsync(const u8* dname, u32 dirAttr, u32 ownerAcc, u32 groupAcc, u32 othersAcc, ISFSCallback cb, void* fsCtxt) {
ISFSError rc = ISFS_ERROR_OK;
u32 len;
ISFSPathAttrArgs* pathAttrArgs;
__isfsCtxt* ctxt;
if (dname == NULL || __fsFd < 0 || (len = strnlen(dname, 64)) == 64) {
rc = ISFS_ERROR_INVALID;
goto out;
}
ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32);
if (ctxt == 0) {
rc = ISFS_ERROR_BUSY;
goto out;
}
ctxt->cb = cb;
ctxt->ctxt = fsCtxt;
ctxt->func = 0;
pathAttrArgs = (ISFSPathAttrArgs*)ctxt->ioBuf;
memcpy(pathAttrArgs->path, (void*)dname, len + 1);
pathAttrArgs->attr = dirAttr;
pathAttrArgs->ownerAccess = ownerAcc;
pathAttrArgs->groupAccess = groupAcc;
pathAttrArgs->othersAccess = othersAcc;
rc = IOS_IoctlAsync(__fsFd, 3, pathAttrArgs, sizeof(*pathAttrArgs), NULL, 0, _isfsFuncCb, ctxt);
out:
return rc;
}
s32 ISFS_ReadDir(const u8* dname, u8* nameList, u32* num) {
ISFSError rc = ISFS_ERROR_OK;
IOSIoVector* v = 0;
u32 len, numInputs, numOutputs, *numPtr;
char* dnPtr;
__isfsCtxt* blCtxt = 0;
if (dname == NULL || num == NULL || __fsFd < 0 || (u32)nameList & 31 || (len = strnlen(dname, 64)) == 64) {
rc = ISFS_ERROR_INVALID;
goto out;
}
blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32);
if (blCtxt == 0) {
rc = IOS_ERROR_FAIL_ALLOC;
goto out;
}
v = (IOSIoVector*)blCtxt->ioBuf;
dnPtr = (char*)ROUNDUP((u8*)&v[4]);
memcpy(dnPtr, dname, len + 1);
v[0].base = (u8*)dnPtr;
v[0].length = 64;
numPtr = (u32*)ROUNDUP((u32)dnPtr + 64);
v[1].base = (u8*)numPtr;
v[1].length = 4;
if (nameList != 0) {
numInputs = 2;
numOutputs = 2;
*numPtr = *num;
v[2].base = nameList;
v[2].length = *num * 13;
v[3].base = (u8*)numPtr;
v[3].length = 4;
} else {
numInputs = 1;
numOutputs = 1;
}
rc = IOS_Ioctlv(__fsFd, 4, numInputs, numOutputs, v);
if (rc != ISFS_ERROR_OK) {
goto out;
}
*num = *numPtr;
out:
if (blCtxt != 0) {
if (blCtxt != 0) {
iosFree(hId, blCtxt);
}
}
return rc;
}
static IOSError _FSReadDirCb(IOSError ret, void* ctxt) {
ISFSError rc = ISFS_ERROR_OK;
__isfsCtxt* _ctxt = (__isfsCtxt*)ctxt;
if (ret == 0) {
u8* ptr;
IOSIoVector* v = (IOSIoVector*)_ctxt->ioBuf;
ptr = (u8*)ROUNDUP((u8*)&v[4]);
ptr = (u8*)ROUNDUP(ptr + 64);
*_ctxt->args.num = *(u32 *) ptr;
}
return rc;
}
s32 ISFS_ReadDirAsync(const u8* dname, u8* nameList, u32* num, ISFSCallback cb, void* fsCtxt) {
ISFSError rc = ISFS_ERROR_OK;
u32 len, numOutputs, numInputs, *numPtr;
IOSIoVector* v;
__isfsCtxt* ctxt;
char* dnPtr;
if (dname == NULL || num == NULL || __fsFd < 0 || (u32)nameList & 31 || (len = strnlen(dname, 64)) == 64) {
rc = ISFS_ERROR_INVALID;
goto out;
}
ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32);
if (ctxt == 0) {
rc = ISFS_ERROR_BUSY;
goto out;
}
ctxt->cb = cb;
ctxt->ctxt = fsCtxt;
ctxt->func = 2;
ctxt->args.num = num;
v = (IOSIoVector*)ctxt->ioBuf;
dnPtr = (char*)ROUNDUP((u8*)&v[4]);
memcpy(dnPtr, dname, len + 1);
v[0].base = (u8*)dnPtr;
v[0].length = 64;
numPtr = (u32*)ROUNDUP((u32)dnPtr + 64);
v[1].base = (u8*)numPtr;
v[1].length = 4;
if (nameList != 0) {
numInputs = 2;
numOutputs = 2;
*numPtr = *num;
v[2].base = nameList;
v[2].length = *num * 13;
v[3].base = (u8*)numPtr;
v[3].length = 4;
} else {
numInputs = 1;
numOutputs = 1;
}
rc = IOS_IoctlvAsync(__fsFd, 4, numInputs, numOutputs, v, _isfsFuncCb, ctxt);
out:
return rc;
}
s32 ISFS_GetAttr(const u8* name, IOSUid* ownerId, IOSGid* groupId, u32* attr, u32* ownerAcc, u32* groupAcc, u32* othersAcc) {
ISFSError rc = ISFS_ERROR_OK;
ISFSPathAttrArgs* pathAttrArgs;
u8* ptr;
u32 len;
__isfsCtxt* blCtxt = 0;
if (name == NULL || __fsFd < 0 ||
(len = strnlen(name, 64)) == 64 ||
ownerId == NULL || groupId == NULL || attr == NULL ||
ownerAcc == NULL || groupAcc == NULL || othersAcc == NULL) {
rc = ISFS_ERROR_INVALID;
goto out;
}
blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32);
if (blCtxt == 0) {
rc = IOS_ERROR_FAIL_ALLOC;
goto out;
}
ptr = (u8*)blCtxt->ioBuf;
memcpy(ptr, name, len + 1);
pathAttrArgs = (ISFSPathAttrArgs*)ROUNDUP(ptr + 64);
rc = IOS_Ioctl(__fsFd, 6, ptr, 64, pathAttrArgs, sizeof(*pathAttrArgs));
if (rc != IOS_ERROR_OK) {
goto out;
}
*ownerId = pathAttrArgs->ownerId;
*groupId = pathAttrArgs->groupId;
*attr = pathAttrArgs->attr;
*ownerAcc = pathAttrArgs->ownerAccess;
*groupAcc = pathAttrArgs->groupAccess;
*othersAcc = pathAttrArgs->othersAccess;
out:
if (blCtxt != 0) {
if (blCtxt != 0) {
iosFree(hId, blCtxt);
}
}
return rc;
}
static IOSError _FSGetAttrCb(IOSError ret, void* ctxt) {
ISFSError rc = ret;
if (ret == 0) {
__isfsCtxt* _ctxt = (__isfsCtxt*)ctxt;
ISFSPathAttrArgs* pathAttrArgs = (ISFSPathAttrArgs*)ROUNDUP(_ctxt->ioBuf + 64);
*_ctxt->args.ga.ownerId = pathAttrArgs->ownerId;
*_ctxt->args.ga.groupId = pathAttrArgs->groupId;
*_ctxt->args.ga.attr = pathAttrArgs->attr;
*_ctxt->args.ga.ownerAcc = pathAttrArgs->ownerAccess;
*_ctxt->args.ga.groupAcc = pathAttrArgs->groupAccess;
*_ctxt->args.ga.othersAcc = pathAttrArgs->othersAccess;
}
return rc;
}
s32 ISFS_GetAttrAsync(const u8* name, IOSUid* ownerId, IOSGid* groupId, u32* attr, u32* ownerAcc, u32* groupAcc, u32* othersAcc, ISFSCallback cb, void* fsCtxt) {
ISFSError rc = ISFS_ERROR_OK;
__isfsCtxt *ctxt;
ISFSPathAttrArgs *pathAttrArgs;
u8 *ptr;
u32 len;
if (name == NULL || __fsFd < 0 ||
(len = strnlen(name, 64)) == 64 ||
ownerId == NULL || groupId == NULL || attr == NULL ||
ownerAcc == NULL || groupAcc == NULL || othersAcc == NULL) {
rc = ISFS_ERROR_INVALID;
goto out;
}
ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32);
if (ctxt == 0) {
rc = ISFS_ERROR_BUSY;
goto out;
}
ctxt->args.ga.ownerId = ownerId;
ctxt->args.ga.groupId = groupId;
ctxt->args.ga.attr = attr;
ctxt->args.ga.ownerAcc = ownerAcc;
ctxt->args.ga.groupAcc = groupAcc;
ctxt->args.ga.othersAcc = othersAcc;
ctxt->cb = cb;
ctxt->ctxt = fsCtxt;
ctxt->func = 3;
ptr = (u8*)ctxt->ioBuf;
memcpy(ptr, name, len + 1);
pathAttrArgs = (ISFSPathAttrArgs*)ROUNDUP(ptr + 64);
rc = IOS_IoctlAsync(__fsFd, 6, ptr, 64, pathAttrArgs, sizeof(*pathAttrArgs), _isfsFuncCb, ctxt);
out:
return rc;
}
s32 ISFS_Delete(const u8* name) {
ISFSError rc = ISFS_ERROR_OK;
u32 len;
__isfsCtxt* blCtxt = 0;
if (name == NULL || __fsFd < 0 || (len = strnlen(name, 64)) == 64) {
rc = ISFS_ERROR_INVALID;
goto out;
}
blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32);
if (blCtxt == 0) {
rc = IOS_ERROR_FAIL_ALLOC;
goto out;
}
memcpy(blCtxt->ioBuf, name, len + 1);
rc = IOS_Ioctl(__fsFd, 7, blCtxt->ioBuf, 64, NULL, 0);
out:
if (blCtxt != 0) {
if (blCtxt != 0) {
iosFree(hId, blCtxt);
}
}
return rc;
}
s32 ISFS_DeleteAsync(const u8* name, ISFSCallback cb, void* fsCtxt) {
ISFSError rc = ISFS_ERROR_OK;
u32 len;
__isfsCtxt* ctxt;
if (name == NULL || __fsFd < 0 || (len = strnlen(name, 64)) == 64) {
rc = ISFS_ERROR_INVALID;
goto out;
}
ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32);
if (ctxt == 0) {
rc = ISFS_ERROR_BUSY;
goto out;
}
memcpy(ctxt->ioBuf, name, len + 1);
ctxt->cb = cb;
ctxt->ctxt = fsCtxt;
ctxt->func = 0;
rc = IOS_IoctlAsync(__fsFd, 7, ctxt->ioBuf, 64, NULL, 0, _isfsFuncCb, ctxt);
out:
return rc;
}
s32 ISFS_Rename(const u8* oldName, const u8* newName) {
ISFSError rc = ISFS_ERROR_OK;
ISFSPathsArgs* pathsArgs;
u32 oldLen, newLen;
__isfsCtxt* blCtxt = 0;
if (oldName == NULL || newName == NULL || __fsFd < 0 ||
(oldLen = strnlen(oldName, 64)) == 64 ||
(newLen = strnlen(newName, 64)) == 64) {
rc = ISFS_ERROR_INVALID;
goto out;
}
blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32);
if (blCtxt == 0) {
rc = IOS_ERROR_FAIL_ALLOC;
goto out;
}
pathsArgs = (ISFSPathsArgs*)blCtxt->ioBuf;
memcpy(pathsArgs->path1, oldName, oldLen + 1);
memcpy(pathsArgs->path2, newName, newLen + 1);
rc = IOS_Ioctl(__fsFd, 8, pathsArgs, sizeof(*pathsArgs), NULL, 0);
out:
if (blCtxt != 0) {
if (blCtxt != 0) {
iosFree(hId, blCtxt);
}
}
return rc;
}
s32 ISFS_RenameAsync(const u8* oldName, const u8* newName, ISFSCallback cb, void* fsCtxt) {
ISFSError rc = ISFS_ERROR_OK;
ISFSPathsArgs* pathsArgs;
u32 oldLen, newLen;
__isfsCtxt* ctxt;
if ((oldName == NULL) || newName == NULL || __fsFd < 0 ||
(oldLen = strnlen(oldName, 64)) == 64 ||
(newLen = strnlen(newName, 64)) == 64) {
rc = ISFS_ERROR_INVALID;
goto out;
}
ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32);
if (ctxt == NULL) {
rc = ISFS_ERROR_BUSY;
goto out;
}
ctxt->cb = cb;
ctxt->ctxt = fsCtxt;
ctxt->func = 0;
pathsArgs = (ISFSPathsArgs*)ctxt->ioBuf;
memcpy(pathsArgs->path1, oldName, oldLen + 1);
memcpy(pathsArgs->path2, newName, newLen + 1);
rc = IOS_IoctlAsync(__fsFd, 8, pathsArgs, sizeof(*pathsArgs), NULL, 0, _isfsFuncCb, ctxt);
out:
return rc;
}
s32 ISFS_GetUsage(const u8* dname, u32* nblocks, u32* ninodes) {
ISFSError rc = ISFS_ERROR_OK;
IOSIoVector* v = 0;
u32 len, *blkPtr, *inodePtr;
char* dnPtr;
__isfsCtxt* blCtxt = 0;
if (dname == NULL || __fsFd < 0 ||
nblocks == NULL || ninodes == NULL ||
(len = strnlen(dname, 64)) == 64) {
rc = ISFS_ERROR_INVALID;
goto out;
}
blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32);
if (blCtxt == 0) {
rc = IOS_ERROR_FAIL_ALLOC;
goto out;
}
v = (IOSIoVector*)blCtxt->ioBuf;
dnPtr = (char*)ROUNDUP((u8*)&v[3]);
memcpy(dnPtr, dname, len + 1);
v[0].base = (u8*)dnPtr;
v[0].length = 64;
blkPtr = (u32*) ROUNDUP(((u32)dnPtr) + 64);
inodePtr = (u32*) ROUNDUP(((u32)blkPtr) + 4);
v[1].base = (u8*) blkPtr;
v[1].length = 4;
v[2].base = (u8*)inodePtr;
v[2].length = 4;
rc = IOS_Ioctlv(__fsFd, 12, 1, 2, v);
if (rc != ISFS_ERROR_OK) {
goto out;
}
*nblocks = *blkPtr;
*ninodes = *inodePtr;
out:
if (blCtxt != 0) {
if (blCtxt != 0) {
iosFree(hId, blCtxt);
}
}
return rc;
}
static IOSError _FSGetUsageCb(IOSError ret, void* ctxt) {
ISFSError rc = ISFS_ERROR_OK;
__isfsCtxt* _ctxt = (__isfsCtxt*)ctxt;
if (ret == 0) {
u8* ptr;
IOSIoVector* v = (IOSIoVector*)_ctxt->ioBuf;
ptr = (u8*)ROUNDUP((u8*)&v[4]);
ptr = (u8*)ROUNDUP(ptr + 64);
*_ctxt->args.gu.nblocks = *(u32*)ptr;
ptr = (u8*)ROUNDUP(ptr + 4);
*_ctxt->args.gu.ninodes = *(u32*)ptr;
}
return rc;
}
s32 ISFS_CreateFile(const u8* fname, u32 fileAttr, u32 ownerAcc, u32 groupAcc, u32 othersAcc) {
ISFSError rc = ISFS_ERROR_OK;
ISFSPathAttrArgs* pathAttrArgs;
u32 len;
__isfsCtxt* blCtxt = NULL;
if (fname == NULL || __fsFd < 0 || (len = strnlen(fname, 64)) == 64) {
rc = ISFS_ERROR_INVALID;
goto out;
}
blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32);
if (blCtxt == 0) {
rc = IOS_ERROR_FAIL_ALLOC;
goto out;
}
pathAttrArgs = (ISFSPathAttrArgs*)blCtxt->ioBuf;
memcpy(pathAttrArgs->path, fname, len + 1);
pathAttrArgs->attr = fileAttr;
pathAttrArgs->ownerAccess = ownerAcc;
pathAttrArgs->groupAccess = groupAcc;
pathAttrArgs->othersAccess = othersAcc;
rc = IOS_Ioctl(__fsFd, 9, pathAttrArgs, sizeof(*pathAttrArgs), NULL, 0);
out:
if (blCtxt != 0) {
if (blCtxt != 0) {
iosFree(hId, blCtxt);
}
}
return rc;
}
s32 ISFS_CreateFileAsync(const u8* fname, u32 fileAttr, u32 ownerAcc, u32 groupAcc, u32 othersAcc, ISFSCallback cb, void* fsCtxt) {
ISFSError rc = ISFS_ERROR_OK;
ISFSPathAttrArgs* pathAttrArgs;
u32 len;
__isfsCtxt* ctxt;
if (fname == NULL || __fsFd < 0 || (len = strnlen(fname, 64)) == 64) {
rc = ISFS_ERROR_INVALID;
goto out;
}
ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32);
if (ctxt == 0) {
rc = ISFS_ERROR_BUSY;
goto out;
}
ctxt->cb = cb;
ctxt->ctxt = fsCtxt;
ctxt->func = 0;
pathAttrArgs = (ISFSPathAttrArgs*)ctxt->ioBuf;
memcpy(pathAttrArgs->path, fname, len + 1);
pathAttrArgs->attr = fileAttr;
pathAttrArgs->ownerAccess = ownerAcc;
pathAttrArgs->groupAccess = groupAcc;
pathAttrArgs->othersAccess = othersAcc;
rc = IOS_IoctlAsync(__fsFd, 9, pathAttrArgs, sizeof(*pathAttrArgs), NULL, 0, _isfsFuncCb, ctxt);
out:
return rc;
}
IOSFd ISFS_Open(const u8* fname, u32 access) {
ISFSError rc = ISFS_ERROR_OK;
u32 len;
__isfsCtxt* blCtxt = 0;
if (fname == NULL || (len = strnlen(fname, 64)) == 64) {
rc = ISFS_ERROR_INVALID;
goto out;
}
blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32);
if (blCtxt == 0) {
rc = IOS_ERROR_FAIL_ALLOC;
goto out;
}
memcpy(blCtxt->ioBuf, fname, len + 1);
rc = IOS_Open((const char*)blCtxt->ioBuf, access);
out:
if (blCtxt != 0) {
if (blCtxt != 0) {
iosFree(hId, blCtxt);
}
}
return rc;
}
IOSFd ISFS_OpenAsync(const u8* fname, u32 access, ISFSCallback cb, void* fsCtxt) {
ISFSError rc = ISFS_ERROR_OK;
u32 len;
__isfsCtxt* ctxt;
if (fname == NULL || (len = strnlen(fname, 64)) == 64) {
rc = ISFS_ERROR_INVALID;
goto out;
}
ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32);
if (ctxt == 0) {
rc = ISFS_ERROR_BUSY;
goto out;
}
ctxt->cb = cb;
ctxt->ctxt = fsCtxt;
ctxt->func = 0;
memcpy(ctxt->ioBuf, fname, len + 1);
rc = IOS_OpenAsync((const char*)ctxt->ioBuf, access, _isfsFuncCb, ctxt);
out:
return rc;
}
static IOSError _FSGetFileStatsCb(IOSError ret, void* ctxt) {
__isfsCtxt* _ctxt = (__isfsCtxt*)ctxt;
ISFSError rc = ISFS_ERROR_OK;
if (ret == 0) {
memcpy(_ctxt->args.fstats, _ctxt->ioBuf, sizeof(*_ctxt->args.fstats));
}
return rc;
}
s32 ISFS_GetFileStats(IOSFd fd, ISFSFileStats* stats) {
ISFSError rc = ISFS_ERROR_OK;
__isfsCtxt* blCtxt = 0;
if (stats == NULL || ((u32)stats & 31)) {
rc = ISFS_ERROR_INVALID;
goto out;
}
blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32);
if (blCtxt == 0) {
rc = IOS_ERROR_FAIL_ALLOC;
goto out;
}
rc = IOS_Ioctl(fd, 11, NULL, 0, blCtxt->ioBuf, sizeof(*stats));
if (rc != IOS_ERROR_OK) {
goto out;
}
memcpy(stats, blCtxt->ioBuf, sizeof(*stats));
out:
if (blCtxt != 0) {
if (blCtxt != 0) {
iosFree(hId, blCtxt);
}
}
return rc;
}
s32 ISFS_GetFileStatsAsync(IOSFd fd, ISFSFileStats* stats, ISFSCallback cb, void* fsCtxt) {
ISFSError rc = ISFS_ERROR_OK;
__isfsCtxt* ctxt;
if (stats == NULL || ((u32)stats & 31)) {
rc = ISFS_ERROR_INVALID;
goto out;
}
ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32);
if (ctxt == 0) {
rc = ISFS_ERROR_BUSY;
goto out;
}
ctxt->cb = cb;
ctxt->ctxt = fsCtxt;
ctxt->func = 5;
ctxt->args.fstats = stats;
rc = IOS_IoctlAsync(fd, 11, NULL, 0, ctxt->ioBuf, sizeof(*stats), _isfsFuncCb, ctxt);
out:
return rc;
}
s32 ISFS_Seek(IOSFd fd, s32 offset, u32 whence) {
ISFSError rc = ISFS_ERROR_OK;
rc = IOS_Seek(fd, offset, whence);
return rc;
}
s32 ISFS_SeekAsync(IOSFd fd, s32 offset, u32 whence, ISFSCallback cb, void* fsCtxt) {
ISFSError rc;
__isfsCtxt* ctxt;
ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32);
if (ctxt == 0) {
rc = ISFS_ERROR_BUSY;
goto out;
}
ctxt->cb = cb;
ctxt->ctxt = fsCtxt;
ctxt->func = 0;
rc = IOS_SeekAsync(fd, offset, whence, _isfsFuncCb, ctxt);
out:
return rc;
}
s32 ISFS_Read(s32 fd, u8* pBuffer, u32 bufSize) {
ISFSError rc = ISFS_ERROR_OK;
/* nullptr check and alignment to 0x20 */
if (pBuffer == NULL || (u32)pBuffer & 31) {
rc = ISFS_ERROR_INVALID;
} else {
rc = IOS_Read(fd, pBuffer, bufSize);;
}
return rc;
}
s32 ISFS_ReadAsync(IOSFd fd, u8* buf, u32 size, ISFSCallback cb, void* fsCtxt) {
ISFSError rc = ISFS_ERROR_OK;
__isfsCtxt* ctxt;
if (buf == NULL || ((u32)buf & 31)) {
rc = ISFS_ERROR_INVALID;
goto out;
}
ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32);
if (ctxt == 0) {
rc = ISFS_ERROR_BUSY;
goto out;
}
ctxt->cb = cb;
ctxt->ctxt = fsCtxt;
ctxt->func = 0;
rc = IOS_ReadAsync(fd, buf, size, _isfsFuncCb, ctxt);
out:
return rc;
}
s32 ISFS_Write(IOSFd fd, const u8* buf, u32 size) {
ISFSError rc = ISFS_ERROR_OK;
if (buf == NULL || ((u32)buf & 31)) {
rc = ISFS_ERROR_INVALID;
goto out;
}
rc = IOS_Write(fd, (u8*)buf, size);
out:
return rc;
}
s32 ISFS_WriteAsync(IOSFd fd, const u8* buf, u32 size, ISFSCallback cb, void* fsCtxt) {
ISFSError rc = ISFS_ERROR_OK;
__isfsCtxt* ctxt;
if (buf == NULL || ((u32)buf & (u32)(31))) {
rc = ISFS_ERROR_INVALID;
goto out;
}
ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32);
if (ctxt == 0) {
rc = ISFS_ERROR_BUSY;
goto out;
}
ctxt->cb = cb;
ctxt->ctxt = fsCtxt;
ctxt->func = 0;
rc = IOS_WriteAsync(fd, (void*)buf, size, _isfsFuncCb, ctxt);
out:
return rc;
}
s32 ISFS_Close(IOSFd fd) {
ISFSError rc = ISFS_ERROR_OK;
rc = IOS_Close(fd);
return rc;
}
s32 ISFS_CloseAsync(IOSFd fd, ISFSCallback cb, void* fsCtxt) {
ISFSError rc;
__isfsCtxt* ctxt;
ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32);
if (ctxt == 0) {
rc = ISFS_ERROR_BUSY;
goto out;
}
ctxt->cb = cb;
ctxt->ctxt = fsCtxt;
ctxt->func = 0;
rc = IOS_CloseAsync(fd, _isfsFuncCb, ctxt);
out:
return rc;
}
s32 ISFS_ShutdownAsync(ISFSCallback cb, void* fsCtxt) {
__isfsCtxt* ctxt;
s32 rc = ISFS_ERROR_OK;
ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32);
if (__fsFd < 0) {
rc = ISFS_ERROR_INVALID;
goto out;
}
ctxt->cb = cb;
ctxt->ctxt = fsCtxt;
ctxt->func = 0;
rc = IOS_IoctlAsync(__fsFd, 13, NULL, 0, NULL, 0, _isfsFuncCb, ctxt);
out:
return rc;
}

View File

@ -0,0 +1,51 @@
#include <revolution/ipc.h>
#include <revolution/os/OSIpc.h>
#include <revolution/os.h>
static void* IPCBufferHi;
static void* IPCBufferLo;
static void* IPCCurrentBufferHi;
static void* IPCCurrentBufferLo;
static u8 Initialized;
void IPCInit(void) {
if (Initialized) {
return;
}
IPCBufferHi = __OSGetIPCBufferHi();
IPCBufferLo = __OSGetIPCBufferLo();
IPCCurrentBufferHi = IPCBufferHi;
IPCCurrentBufferLo = IPCBufferLo;
Initialized = TRUE;
}
void IPCReInit(void) {
Initialized = FALSE;
IPCInit();
}
u32 IPCReadReg(u32 regIdx) {
u32 reg = __IPCRegs[regIdx];
return reg;
}
void IPCWriteReg(u32 regIdx, u32 data) {
__IPCRegs[regIdx] = data;
}
void* IPCGetBufferHi(void) {
return IPCCurrentBufferHi;
}
void* IPCGetBufferLo(void) {
return IPCCurrentBufferLo;
}
void IPCSetBufferLo(void* newLo) {
ASSERTLINE(296, IPCBufferLo <= newLo);
IPCCurrentBufferLo = newLo;
}

View File

@ -0,0 +1,53 @@
#include <revolution.h>
#include <string.h>
static u32 IpcReqPtrArray[96] = {0};
static u32 IpcReqArray[0x300] = {0};
static OSTime IpcStartTimeArray[96];
static u8 IpcHandlePathBuf[0x1800];
static u8 IpcOpenPathBuf[0x1200];
static u32 IpcNumPendingReqs = 0;
static u32 IpcNumUnIssuedReqs = 0;
static void AddReqInfo(void* req);
static void DelReqInfo(void* req);
void IPCiProfInit(void) {
u32 i;
IpcNumPendingReqs = 0;
IpcNumUnIssuedReqs = 0;
for (i = 0; i < 96; ++i) {
IpcReqPtrArray[i] = 0;
IpcStartTimeArray[i] = 0;
}
memset(IpcHandlePathBuf, 0, sizeof(IpcHandlePathBuf));
memset(IpcOpenPathBuf, 0, sizeof(IpcOpenPathBuf));
memset(IpcReqArray, 0, sizeof(IpcReqArray));
}
void IPCiProfQueueReq(void* req, s32 handle) {
++IpcNumPendingReqs;
++IpcNumUnIssuedReqs;
AddReqInfo(req);
}
void IPCiProfAck(void) {
--IpcNumUnIssuedReqs;
}
void IPCiProfReply(void* req, s32 handle) {
--IpcNumPendingReqs;
DelReqInfo(req);
}
static void AddReqInfo(void* ptr) {
// NONMATCHING
}
static void DelReqInfo(void* ptr) {
// NONMATCHING
}

835
src/revolution/ipc/ipcclt.c Normal file
View File

@ -0,0 +1,835 @@
#include <revolution/private/iostypes.h>
#include <revolution/private/iosrestypes.h>
#include <revolution/os.h>
#include <revolution/ipc.h>
#include <string.h>
/* macro for matching __ipcQueueRequest */
#define diff(a, b) \
((a) < (b)) ? ((u32)0xffffffff - (b) + (a) + 1) : ((a) - (b))
static s32 __mailboxAck = 1;
static u32 __relnchFl = 0;
#define OSVirtualToPhysical(addr) OSCachedToPhysical(addr)
#define OSPhysicalToVirtual(addr) OSPhysicalToCached(addr)
typedef struct IOSRpcRequest {
IOSResourceRequest request;
IOSIpcCb cb ATTRIBUTE_ALIGN(32); // I am assuming this is aligned due to where cbArg is stored, and I see nothing between cb and callback_arg?
void* callback_arg;
u32 relaunch_flag;
OSThreadQueue thread_queue;
} IOSRpcRequest;
static IOSRpcRequest* __relnchRpc = 0;
static IOSRpcRequest* __relnchRpcSave = 0;
#define ROUNDUP(sz) (((u32)(sz) + 31) & ~(u32)(31))
static u8 __rpcBuf[ROUNDUP(sizeof(IOSRpcRequest))] ATTRIBUTE_ALIGN(32);
static struct {
u32 rcount;
u32 wcount;
u32 rptr;
u32 wptr;
IOSResourceRequest* buf[48];
} __responses;
static OSAlarm __timeout_alarm;
static IOSHeapId hid = -1;
extern void ACRWriteReg(u32 param_0, u32 param_1);
extern void IPCiProfQueueReq(void*, s32);
/* the MSL_C version of strnlen doesn't match when inlined, cool */
u32 strnlen(const u8 *str, u32 n) {
const u8 *s = str;
while (*s && n-- > 0)
++s;
return (s - str);
}
static IOSRpcRequest* ipcAllocReq(void) {
IOSRpcRequest* req = NULL;
req = iosAllocAligned(hid, 0x40, 0x20);
return req;
}
static IOSError ipcFree(IOSRpcRequest *rpc) {
IOSError ret = 0;
iosFree(hid, rpc);
return ret;
}
static IOSError __ipcQueueRequest(IOSResourceRequest *req) {
IOSError ret = 0;
if (diff(__responses.wcount, __responses.rcount) >= sizeof(__responses.buf) / sizeof(__responses.buf[0])) {
ret = -8;
} else {
__responses.buf[__responses.wptr] = req;
__responses.wptr = (__responses.wptr + 1) % (sizeof(__responses.buf) / sizeof(__responses.buf[0]));
__responses.wcount++;
IPCiProfQueueReq(req, (s32)req->handle);
}
return ret;
}
static void __ipcSendRequest(void) {
IOSRpcRequest *rpc;
if (diff(__responses.wcount, __responses.rcount) <= 0) {
return;
}
rpc = (IOSRpcRequest*)__responses.buf[__responses.rptr];
if (rpc == 0) {
return;
}
if (rpc->relaunch_flag) {
__mailboxAck--;
}
IPCWriteReg(0, OSVirtualToPhysical(rpc));
__responses.rptr = (__responses.rptr + 1) % (sizeof(__responses.buf) / sizeof(__responses.buf[0]));
__responses.rcount++;
__mailboxAck--;
IPCWriteReg(1, (IPCReadReg(1) & (1 << 5 | 1 << 4)) | 1 << 0);
}
void IpcReplyHandler(__OSInterrupt interrupt, OSContext* context) {
OSContext exceptionContext;
IOSResourceRequest* req;
IOSRpcRequest* rep;
u32 addr;
addr = IPCReadReg(2);
if (!addr) {
goto err;
}
rep = (IOSRpcRequest*)OSPhysicalToVirtual(addr);
IPCWriteReg(1, (IPCReadReg(1) & (1 << 5 | 1 << 4) | 1 << 2));
ACRWriteReg(0x30, 0x40000000);
req = &rep->request;
DCInvalidateRange(req, sizeof(*req));
switch (req->handle) {
case 3:
req->args.read.outPtr = (req->args.read.outPtr) ? OSPhysicalToVirtual((u32)req->args.read.outPtr) : 0;
if (req->status > 0) {
DCInvalidateRange(req->args.read.outPtr, (u32)req->status);
}
break;
case 6:
req->args.ioctl.outPtr = (req->args.ioctl.outPtr) ? OSPhysicalToVirtual((u32)req->args.ioctl.outPtr) : 0;
DCInvalidateRange(req->args.ioctl.inPtr, req->args.ioctl.inLen);
DCInvalidateRange(req->args.ioctl.outPtr, req->args.ioctl.outLen);
break;
case 7:
{
int i;
IOSResourceIoctlv* v = &req->args.ioctlv;
req->args.ioctlv.vector = (req->args.ioctlv.vector) ? (IOSIoVector*)OSPhysicalToVirtual((u32)req->args.ioctlv.vector) : 0;
DCInvalidateRange(&v->vector[0], (req->args.ioctlv.readCount + req->args.ioctlv.writeCount) * sizeof(IOSIoVector));
for (i = 0; i < (req->args.ioctlv.readCount + req->args.ioctlv.writeCount); ++i) {
v->vector[i].base = (v->vector[i].base) ? (u8*)OSPhysicalToVirtual((u32)v->vector[i].base) : 0;
DCInvalidateRange(v->vector[i].base, v->vector[i].length);
}
if (__relnchFl && __relnchRpcSave == rep) {
__relnchFl = 0;
if (__mailboxAck < 1) {
__mailboxAck++;
}
}
break;
}
default:
break;
}
if (rep->cb) {
OSClearContext(&exceptionContext);
OSSetCurrentContext(&exceptionContext);
rep->cb(req->status, (void*)rep->callback_arg);
OSClearContext(&exceptionContext);
OSSetCurrentContext(context);
ipcFree(rep);
} else {
OSWakeupThread(&rep->thread_queue);
}
IPCWriteReg(1, (IPCReadReg(1) & (1 << 5 | 1 << 4)) | 1 << 3);
IPCiProfReply(req, (s32)req->handle);
err:
return;
}
static void IpcAckHandler(__OSInterrupt interrupt, OSContext* context) {
IPCWriteReg(1, (IPCReadReg(1) & (1 << 5 | 1 << 4)) | 1 << 1);
ACRWriteReg(0x30, 0x40000000);
if (__mailboxAck < 1) {
__mailboxAck++;
IPCiProfAck();
}
if (__mailboxAck > 0) {
if (__relnchFl) {
IOSResourceRequest* req = &__relnchRpc->request;
req->status = 0;
__relnchFl = 0;
OSWakeupThread(&__relnchRpc->thread_queue);
IPCWriteReg(1, (IPCReadReg(1) & (1 << 5 | 1 << 4)) | 1 << 3);
}
__ipcSendRequest();
}
}
void IPCInterruptHandler(__OSInterrupt interrupt, OSContext* context) {
if ((IPCReadReg(1) & (1 << 4 | 1 << 2)) == (1 << 4 | 1 << 2)) {
IpcReplyHandler(interrupt, context);
}
if ((IPCReadReg(1) & (1 << 5 | 1 << 1)) == (1 << 5 | 1 << 1)) {
IpcAckHandler(interrupt, context);
}
}
IOSError IPCCltInit(void) {
static u32 initialized = 0;
u32 i;
IOSError ret = 0;
void* bufferLo;
if (initialized) {
goto out;
}
initialized = 1;
IPCInit();
i = ROUNDUP(64 * (ROUNDUP(sizeof(IOSRpcRequest)) + 64));
bufferLo = IPCGetBufferLo();
if ((void*)((u8*)bufferLo + i) > IPCGetBufferHi()) {
ret = -22;
goto out;
}
hid = iosCreateHeap(bufferLo, i);
IPCSetBufferLo((void*)((u8*)bufferLo + i));
__OSSetInterruptHandler(27, IPCInterruptHandler);
__OSUnmaskInterrupts(16);
IPCWriteReg(1, (1 << 5 | 1<< 4 | 1 << 3));
IPCiProfInit();
OSCreateAlarm(&__timeout_alarm);
out:
return ret;
}
IOSError IPCCltReInit(void) {
u32 i;
IOSError ret = 0;
void* bufferLo;
i = ROUNDUP(64 * ROUNDUP(sizeof(IOSRpcRequest)));
bufferLo = IPCGetBufferLo();
if ((void*)((u8*)bufferLo + i) > IPCGetBufferHi()) {
ret = -22;
goto out;
}
hid = iosCreateHeap(bufferLo, i);
IPCSetBufferLo((void*)((u8*)bufferLo + i));
out:
return ret;
}
static IOSError __ios_Ipc1(IOSFd fd, u32 cmd, IOSIpcCb cb, void* cbArg, IOSRpcRequest** rpc) {
IOSError ret = 0;
IOSResourceRequest *req;
if (rpc == 0) {
ret = -4;
goto error;
}
*rpc = (IOSRpcRequest*)ipcAllocReq();
if (*rpc == 0) {
ret = -22;
goto error;
}
req = &(*rpc)->request;
(*rpc)->cb = cb;
(*rpc)->callback_arg = cbArg;
(*rpc)->relaunch_flag = 0;
req->cmd = cmd;
req->handle = (u32)fd;
error:
return ret;
}
static IOSError __ios_Ipc2(IOSRpcRequest* rpc, IOSIpcCb cb) {
IOSError ret = 0;
u32 inten;
IOSResourceRequest* req;
if (rpc == 0) {
ret = -4;
} else {
req = &rpc->request;
if (!cb) {
OSInitThreadQueue(&rpc->thread_queue);
}
DCFlushRange(req, sizeof(*req));
inten = OSDisableInterrupts();
ret = __ipcQueueRequest(req);
if (ret != 0) {
OSRestoreInterrupts(inten);
if (cb) {
ipcFree(rpc);
}
} else {
if (__mailboxAck > 0) {
__ipcSendRequest();
}
if (!cb) {
OSSleepThread(&rpc->thread_queue);
}
OSRestoreInterrupts(inten);
if (!cb) {
ret = req->status;
}
}
}
if (rpc && !cb) {
ipcFree(rpc);
}
return ret;
}
static IOSError __ios_Open(IOSRpcRequest* rpc, const char* path, u32 flags) {
IOSError ret = 0;
IOSResourceRequest* req;
if (!rpc) {
ret = -4;
goto error;
}
req = &rpc->request;
DCFlushRange((void*)path, strnlen((const u8*)path, 64) + 1);
req->args.open.path = (u8*)OSVirtualToPhysical((void*)path);
req->args.open.flags = flags;
error:
return ret;
}
IOSError IOS_OpenAsync(const char* pPath, u32 flags, IOSIpcCb cb, void* callback_arg) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(0, 1, cb, callback_arg, &rpc);
if (ret != 0) {
goto error;
}
ret = __ios_Open(rpc, pPath, flags);
if (ret != 0) {
goto error;
}
ret = __ios_Ipc2(rpc, cb);
error:
return ret;
}
IOSError IOS_Open(const char* path, u32 flags) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(0, 1, 0, 0, &rpc);
if (ret != 0) {
goto error;
}
ret = __ios_Open(rpc, path, flags);
if (ret != 0) {
goto error;
}
ret = __ios_Ipc2(rpc, 0);
error:
return ret;
}
IOSError IOS_CloseAsync(IOSFd fd, IOSIpcCb cb, void* cbArg) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(fd, 2, cb, cbArg, &rpc);
if (ret == 0) {
ret = __ios_Ipc2(rpc, cb);
}
return ret;
}
IOSError IOS_Close(IOSFd fd) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(fd, 2, 0, 0, &rpc);
if (ret == 0) {
ret = __ios_Ipc2(rpc, 0);
}
return ret;
}
static IOSError __ios_Read(IOSRpcRequest* rpc, void* buf, u32 len) {
IOSError ret = 0;
IOSResourceRequest* req;
if (!rpc) {
ret = -4;
goto error;
}
req = &rpc->request;
DCInvalidateRange(buf, len);
req->args.read.outPtr = (buf) ? (u8*)OSVirtualToPhysical(buf) : 0;
req->args.read.outLen = len;
error:
return ret;
}
IOSError IOS_ReadAsync(IOSFd fd, void* buf, u32 len, IOSIpcCb cb, void* cbArg) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(fd, 3, cb, cbArg, &rpc);
if (ret != 0) {
goto error;
}
ret = __ios_Read(rpc, buf, len);
if (ret != 0) {
goto error;
}
ret = __ios_Ipc2(rpc, cb);
error:
return ret;
}
IOSError IOS_Read(IOSFd fd, void* buf, u32 len) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(fd, 3, 0, 0, &rpc);
if (ret != 0) {
goto error;
}
ret = __ios_Read(rpc, buf, len);
if (ret != 0) {
goto error;
}
ret = __ios_Ipc2(rpc, 0);
error:
return ret;
}
static IOSError __ios_Write(IOSRpcRequest* rpc, void* buf, u32 len) {
IOSError ret = 0;
IOSResourceRequest* req;
if (!rpc) {
ret = -4;
goto error;
}
req = &rpc->request;
req->args.write.inPtr = (buf) ? (u8*)OSVirtualToPhysical(buf) : 0;
req->args.write.inLen = len;
DCFlushRange(buf, len);
error:
return ret;
}
IOSError IOS_WriteAsync(IOSFd fd, void* buf, u32 len, IOSIpcCb cb, void* cbArg) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(fd, 4, cb, cbArg, &rpc);
if (ret != 0) {
goto error;
}
ret = __ios_Write(rpc, buf, len);
if (ret != 0) {
goto error;
}
ret = __ios_Ipc2(rpc, cb);
error:
return ret;
}
IOSError IOS_Write(IOSFd fd, void* buf, u32 len) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(fd, 4, 0, 0, &rpc);
if (ret != 0) {
goto error;
}
ret = __ios_Write(rpc, buf, len);
if (ret != 0) {
goto error;
}
ret = __ios_Ipc2(rpc, 0);
error:
return ret;
}
static IOSError __ios_Seek(IOSRpcRequest* rpc, s32 offset, u32 whence) {
IOSError ret = 0;
IOSResourceRequest* req;
if (!rpc) {
ret = -4;
goto error;
}
req = &rpc->request;
req->args.seek.offset = offset;
req->args.seek.whence = whence;
error:
return ret;
}
IOSError IOS_SeekAsync(IOSFd fd, s32 offset, u32 whence, IOSIpcCb cb, void* cbArg) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(fd, 5, cb, cbArg, &rpc);
if (ret != 0) {
goto error;
}
ret = __ios_Seek(rpc, offset, whence);
if (ret != 0) {
goto error;
}
ret = __ios_Ipc2(rpc, cb);
error:
return ret;
}
IOSError IOS_Seek(IOSFd fd, s32 offset, u32 whence) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(fd, 5, 0, 0, &rpc);
if (ret != 0) {
goto error;
}
ret = __ios_Seek(rpc, offset, whence);
if (ret != 0) {
goto error;
}
ret = __ios_Ipc2(rpc, 0);
error:
return ret;
}
static IOSError __ios_Ioctl(IOSRpcRequest* rpc, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen) {
IOSError ret = 0;
IOSResourceRequest* req;
if (!rpc) {
ret = -4;
goto error;
}
req = &rpc->request;
req->args.ioctl.cmd = (u32)cmd;
req->args.ioctl.outPtr = (output) ? (u8*)OSVirtualToPhysical(output) : 0;
req->args.ioctl.outLen = outputLen;
req->args.ioctl.inPtr = (input) ? (u8*)OSVirtualToPhysical(input) : 0;
req->args.ioctl.inLen = inputLen;
DCFlushRange(input, inputLen);
DCFlushRange(output, outputLen);
error:
return ret;
}
IOSError IOS_IoctlAsync(IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen, IOSIpcCb cb, void* cbArg) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(fd, 6, cb, cbArg, &rpc);
if (ret != 0) {
goto err;
}
ret = __ios_Ioctl(rpc, cmd, input, inputLen, output, outputLen);
if (ret != 0) {
goto err;
}
ret = __ios_Ipc2(rpc, cb);
err:
return ret;
}
IOSError IOS_Ioctl(IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(fd, 6, 0, 0, &rpc);
if (ret != 0) {
goto error;
}
ret = __ios_Ioctl(rpc, cmd, input, inputLen, output, outputLen);
if (ret != 0) {
goto error;
}
ret = __ios_Ipc2(rpc, 0);
error:
return ret;
}
static IOSError __ios_Ioctlv(IOSRpcRequest* rpc, s32 cmd, u32 readCount, u32 writeCount, IOSIoVector* vect) {
IOSError ret = 0;
IOSResourceRequest* req;
IOSResourceIoctlv* v;
u32 i, j;
if (!rpc) {
ret = -4;
goto err;
}
req = &rpc->request;
req->args.ioctlv.cmd = (u32)cmd;
req->args.ioctlv.readCount = readCount;
req->args.ioctlv.writeCount = writeCount;
req->args.ioctlv.vector = vect;
v = &req->args.ioctlv;
for (i = 0, j = v->readCount; i < req->args.ioctlv.writeCount; ++i) {
DCFlushRange(v->vector[j + i].base, v->vector[j + i].length);
v->vector[j + i].base = (v->vector[j + i].base) ? (u8*)OSVirtualToPhysical(v->vector[j + i].base) : 0;
}
for (i = 0; i < req->args.ioctlv.readCount; ++i) {
DCFlushRange(v->vector[i].base, v->vector[i].length);
v->vector[i].base = (v->vector[i].base) ? (u8*)OSVirtualToPhysical(v->vector[i].base) : 0;
}
DCFlushRange(&v->vector[0], (v->readCount + v->writeCount) * sizeof(IOSIoVector));
req->args.ioctlv.vector = (vect) ? (IOSIoVector*)OSVirtualToPhysical(vect) : 0;
err:
return ret;
}
IOSError IOS_IoctlvAsync(IOSFd fd, s32 cmd, u32 readCount, u32 writeCount, IOSIoVector* vect, IOSIpcCb cb, void* cbArg) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(fd, 7, cb, cbArg, &rpc);
if (ret != 0) {
goto err;
}
ret = __ios_Ioctlv(rpc, cmd, readCount, writeCount, vect);
if (ret != 0) {
goto err;
}
ret = __ios_Ipc2(rpc, cb);
err:
return ret;
}
IOSError IOS_Ioctlv(IOSFd fd, s32 cmd, u32 readCount, u32 writeCount, IOSIoVector* vect) {
IOSRpcRequest* rpc;
IOSError ret = 0;
ret = __ios_Ipc1(fd, 7, 0, 0, &rpc);
if (ret != 0) {
goto err;
}
ret = __ios_Ioctlv(rpc, cmd, readCount, writeCount, vect);
if (ret != 0) {
goto err;
}
ret = __ios_Ipc2(rpc, 0);
err:
return ret;
}
IOSError IOS_IoctlvReboot(IOSFd fd, s32 cmd, u32 readCount, u32 writeCount, IOSIoVector* vect) {
IOSRpcRequest* rpc;
IOSError ret = 0;
u32 inten;
IOSResourceRequest* req;
inten = OSDisableInterrupts();
if (__relnchFl) {
OSRestoreInterrupts(inten);
ret = -10;
goto finish;
}
__relnchFl = 1;
OSRestoreInterrupts(inten);
ret = __ios_Ipc1(fd, 7, 0, 0, &rpc);
if (ret != 0) {
goto err;
}
__relnchRpcSave = rpc;
rpc->relaunch_flag = 1;
ret = __ios_Ioctlv(rpc, cmd, readCount, writeCount, vect);
if (ret != 0) {
goto err;
}
memcpy(&__rpcBuf, rpc, sizeof(IOSRpcRequest));
__relnchRpc = (IOSRpcRequest*)&__rpcBuf;
req = &rpc->request;
OSInitThreadQueue(&__relnchRpc->thread_queue);
DCFlushRange(req, sizeof(*req));
inten = OSDisableInterrupts();
ret = __ipcQueueRequest(req);
if (ret != 0) {
OSRestoreInterrupts(inten);
goto err;
}
if (__mailboxAck > 0) {
__ipcSendRequest();
}
OSSleepThread(&__relnchRpc->thread_queue);
OSRestoreInterrupts(inten);
ret = (&__relnchRpc->request)->status;
err:
__relnchFl = 0;
__relnchRpcSave = NULL;
if (rpc && (ret != 0)) {
ipcFree(rpc);
}
finish:
return ret;
}

240
src/revolution/ipc/memory.c Normal file
View File

@ -0,0 +1,240 @@
#include <revolution.h>
#include <revolution/private/iostypes.h>
typedef struct IOSChunk {
u32 status;
u32 size;
struct IOSChunk* prevFree;
struct IOSChunk* nextFree;
} IOSChunk;
typedef struct {
void* base;
u32 owner;
u32 size;
IOSChunk *freeList;
} IOSHeap;
static IOSHeap __heaps[8];
static void __iosCoalesceChunk(IOSChunk* p) {
if (p && ((u32)p->nextFree == ((u32)p + p->size + sizeof(IOSChunk)))) {
IOSChunk* next = p->nextFree;
p->nextFree = next->nextFree;
if (p->nextFree != 0) {
p->nextFree->prevFree = p;
}
p->size += next->size + sizeof(IOSChunk);
}
}
IOSHeapId iosCreateHeap(void* ptr, u32 size) {
IOSError rv = -4;
u32 mask;
s32 i;
IOSHeap* h;
mask = OSDisableInterrupts();
if ((u32)ptr & 31) {
goto finish;
}
for (i = 0; i < sizeof(__heaps) / sizeof(__heaps[0]); ++i) {
if (__heaps[i].base == 0) {
break;
}
}
if (i == 8) {
rv = -5;
goto finish;
}
h = __heaps + i;
h->base = ptr;
h->size = size;
h->freeList = ptr;
h->freeList->status = 0xBABE0000;
h->freeList->size = size - sizeof(IOSChunk);
h->freeList->prevFree = NULL;
h->freeList->nextFree = NULL;
rv = i;
finish:
OSRestoreInterrupts(mask);
return rv;
}
#define CHECK_HEAP_ID(id, err) \
if (((id) < 0) || ((id) >= 8) || (!__heaps[id].base)) { \
rv = err; \
goto finish; \
}
#define GET_HEAP(h, id, err) \
do { \
CHECK_HEAP_ID(id, err); \
h = __heaps + id; \
} while (0)
void* __iosAlloc(IOSHeapId id, u32 size, u32 alignment) {
u32 mask;
IOSChunk* p, *best;
IOSHeap* h;
void* rv = NULL;
mask = OSDisableInterrupts();
if (!size) {
goto finish;
}
if (!alignment || (alignment & (alignment - 1))) {
goto finish;
}
if (alignment < 32) {
alignment = 32;
}
size = (size + 31) & ~31;
GET_HEAP(h, id, NULL);
p = h->freeList;
best = NULL;
while (p != 0) {
u32 ptr = (u32)p + sizeof(IOSChunk);
u32 extra = (alignment - (ptr & (alignment - 1))) & (alignment - 1);
if ((p->size == size) && !extra) {
best = p;
break;
} else if ((p->size >= (size + extra)) && (!best || (p->size < best->size))) {
best = p;
}
p = p->nextFree;
}
p = best;
if (p != 0) {
u32 ptr = (u32)p + sizeof(IOSChunk);
u32 extra = (alignment - (ptr & (alignment - 1))) & (alignment - 1);
if (p->size > (size + extra + sizeof(IOSChunk))) {
IOSChunk *n = (IOSChunk *)((u8 *)p + size + extra + sizeof(IOSChunk));
n->status = 0xBABE0000;
n->size = p->size - size - extra - sizeof(IOSChunk);
n->nextFree = p->nextFree;
if (n->nextFree) {
n->nextFree->prevFree = n;
}
p->nextFree = n;
p->size = size + extra;
}
p->status = 0xBABE0001;
if (p->prevFree) {
p->prevFree->nextFree = p->nextFree;
} else {
h->freeList = p->nextFree;
}
if (p->nextFree) {
p->nextFree->prevFree = p->prevFree;
}
p->prevFree = p->nextFree = NULL;
rv = (u8*)p + extra + sizeof(IOSChunk);
if (extra) {
IOSChunk* n = (IOSChunk*)rv - 1;
n->status = 0xBABE0002;
n->prevFree = p;
}
}
finish:
OSRestoreInterrupts(mask);
return rv;
}
void* iosAllocAligned(IOSHeapId id, u32 size, u32 alignment) {
return __iosAlloc(id, size, alignment);
}
IOSError iosFree(IOSHeapId id, void* ptr) {
u32 mask;
IOSChunk* p;
IOSHeap* h;
IOSError rv = -4;
IOSChunk* prev;
mask = OSDisableInterrupts();
if (!ptr) {
goto finish;
}
GET_HEAP(h, id, -4);
if (((u32)ptr) < (((u32)h->base) + sizeof(IOSChunk)) || ((u32)ptr) > ((u32)h->base + h->size)) {
goto finish;
}
p = (IOSChunk*)ptr - 1;
if (p->status == 0xBABE0002) {
p = p->prevFree;
}
if (p->status != 0xBABE0001) {
goto finish;
}
p->status = 0xBABE0000;
prev = h->freeList;
while (prev != 0) {
if (!prev->nextFree || prev->nextFree > p) {
break;
}
prev = prev->nextFree;
}
if (prev && p > prev) {
p->prevFree = prev;
p->nextFree = prev->nextFree;
prev->nextFree = p;
if (p->nextFree) {
p->nextFree->prevFree = p;
}
} else {
p->nextFree = h->freeList;
h->freeList = p;
p->prevFree = NULL;
if (p->nextFree) {
p->nextFree->prevFree = p;
}
}
__iosCoalesceChunk(p);
__iosCoalesceChunk(p->prevFree);
rv = 0;
finish:
OSRestoreInterrupts(mask);
return rv;
}

View File

@ -0,0 +1,94 @@
#include <revolution/nand.h>
#include <revolution/fs.h>
static const char* USER_DIR_LIST[] = {
"/meta",
"/ticket",
"/title/00010000",
"/title/00010001",
"/title/00010003",
"/title/00010004",
"/title/00010005",
"/title/00010006",
"/title/00010007",
"/shared2/title",
NULL,
};
s32 nandCalcUsage(u32* fsBlock, u32* inode, const char* dir_list[]) {
ISFSError ret = ISFS_ERROR_UNKNOWN;
*fsBlock = 0;
*inode = 0;
while (*dir_list) {
u32 blk = 0;
u32 node = 0;
ret = ISFS_GetUsage((const u8*)*dir_list, &blk, &node);
if (ret == ISFS_ERROR_OK) {
*fsBlock += blk;
*inode += node;
} else if (ret == ISFS_ERROR_NOEXISTS) {
ret = ISFS_ERROR_OK;
} else {
break;
}
++dir_list;
}
return ret;
}
ISFSError nandCalcUserUsage(u32* fsBlock, u32* inode) {
return nandCalcUsage(fsBlock, inode, USER_DIR_LIST);
}
static u32 nandCheck(const u32 reqBlock, const u32 reqInode, const u32 homeBlock, const u32 homeInode, const u32 userBlock, const u32 userInode) {
u32 answer = 0;
if (homeBlock + reqBlock > 0x400) {
answer |= 1;
}
if (homeInode + reqInode > 0x21) {
answer |= 2;
}
if (userBlock + reqBlock > 0x4400) {
answer |= 4;
}
if (userInode + reqInode > 0xFA0) {
answer |= 8;
}
return answer;
}
s32 NANDCheck(const u32 fsBlock, const u32 inode, u32* answer) {
ISFSError ret = ISFS_ERROR_UNKNOWN;
u32 homeBlocks = 0xFFFFFFFF;
u32 homeInodes = 0xFFFFFFFF;
u32 userBlocks = 0xFFFFFFFF;
u32 userInodes = 0xFFFFFFFF;
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
ret = ISFS_GetUsage((const u8*)nandGetHomeDir(), &homeBlocks, &homeInodes);
if (ret != ISFS_ERROR_OK) {
return nandConvertErrorCode(ret);
}
ret = nandCalcUserUsage(&userBlocks, &userInodes);
if (ret != ISFS_ERROR_OK) {
return nandConvertErrorCode(ret);
}
*answer = nandCheck(fsBlock, inode, homeBlocks, homeInodes, userBlocks, userInodes);
return NAND_RESULT_OK;
}

View File

@ -0,0 +1,514 @@
#include <revolution/nand.h>
#include <revolution/esp.h>
#include <revolution/fs.h>
#include <revolution/os.h>
#include <string.h>
#ifdef SDK_AUG2010
#define BUILD_DATE "Aug 23 2010"
#if DEBUG
#define BUILD_TIME "17:28:24"
#else
#define BUILD_TIME "17:33:06"
#endif
#elif SDK_SEP2006
#define BUILD_DATE "Sep 21 2006"
#define BUILD_TIME "14:32:13"
#endif
#ifdef SDK_AUG2010
#if DEBUG
const char* __NANDVersion = "<< RVL_SDK - NAND \tdebug build: "BUILD_DATE" "BUILD_TIME" (0x4302_145) >>";
#else
const char* __NANDVersion = "<< RVL_SDK - NAND \trelease build: "BUILD_DATE" "BUILD_TIME" (0x4302_145) >>";
#endif
#elif SDK_SEP2006
const char* __NANDVersion = "<< RVL_SDK - NAND \trelease build: "BUILD_DATE" "BUILD_TIME" (0x4200_60422) >>";
#endif
enum LibState {
STATE_NOT_INITIALIZED,
STATE_WORKING,
STATE_INITIALIZED
};
static enum LibState s_libState = STATE_NOT_INITIALIZED;
static char s_currentDir[64] ATTRIBUTE_ALIGN(32) = "/";
static char s_homeDir[64] ATTRIBUTE_ALIGN(32) = "";
static BOOL nandOnShutdown(BOOL final, u32 event);
void nandConvertPath(char* abspath, const char* wd, const char* relpath);
static void nandShutdownCallback(ISFSError result, void* ctxt);
static OSShutdownFunctionInfo s_shutdownFuncInfo = {
nandOnShutdown,
255
};
void nandRemoveTailToken(char* newpath, const char* oldpath) {
ASSERTMSGLINE(189, newpath, "null pointer is detected in argument of newpath\n");
ASSERTMSGLINE(190, oldpath, "null pointer is detected in argument of oldpath\n");
ASSERTMSGLINE(191, oldpath[0] == '/', "Head of path must be \'/\' .\n");
if (oldpath[0] == '/' && oldpath[1] == '\0') {
newpath[0] = '/';
newpath[1] = '\0';
} else {
int i = 0;
for (i = (int)(strlen(oldpath)) - 1; i >= 0; --i) {
if (oldpath[i] == '/') {
if (i != 0) {
strncpy(newpath, oldpath, (u32)i);
newpath[i] = '\0';
break;
} else {
newpath[0] = '/';
newpath[1] = '\0';
break;
}
}
}
}
}
void nandGetHeadToken(char* token, char* newpath, const char* oldpath) {
unsigned int i = 0;
ASSERTMSGLINE(224, token && newpath && oldpath, "Null pointer detected!\n");
ASSERTMSGLINE(225, strlen(oldpath) != 0, "Null string was detected!\n");
ASSERTMSGLINE(226, oldpath[0] != '/', "Head of relative path must not be \'/\' .\n");
for (i = 0; i <= strlen(oldpath); ++i) {
if (oldpath[i] == '/') {
strncpy(token, oldpath, i);
token[i] = '\0';
if (oldpath[i + 1] == '\0') {
newpath[0] = '\0';
} else {
strcpy(newpath, oldpath + i + 1);
}
break;
} else if (oldpath[i] == '\0') {
strncpy(token, oldpath, i);
token[i] = '\0';
newpath[0] = '\0';
break;
}
}
}
void nandGetRelativeName(char* name, const char* path) {
if (strcmp("/", path) == 0) {
strcpy(name, "");
} else {
int i = 0;
ASSERTMSGLINE(260, nandIsAbsolutePath(path), "path must be absolute path.");
ASSERTMSGLINE(261, path[strlen(path) - 1] != '/', "path must not be terminated with \'/\'.");
for (i = (int)(strlen(path) - 1); i >= 0; --i) {
if (path[i] == '/') {
break;
}
}
ASSERTMSGLINE(270, strlen(path + i + 1) <= ISFS_INODE_NAMELEN, "path must be smaller than or equal to ISFS_INODE_NAMELEN.");
strcpy(name, path + i + 1);
}
}
void nandConvertPath(char* abspath, const char* wd, const char* relpath) {
char token[128];
char new_relpath[128];
ASSERTMSGLINE(283, abspath && wd && relpath, "Null pointer detected!\n");
ASSERTMSGLINE(284, wd[0] == '/', "Head of \'wd\' must be \'/\'.\n");
if (strlen(relpath) == 0) {
strcpy(abspath, wd);
return;
}
nandGetHeadToken(token, new_relpath, relpath);
if (strcmp(token, ".") == 0) {
nandConvertPath(abspath, wd, new_relpath);
} else if (strcmp(token, "..") == 0) {
char new_wd[128];
nandRemoveTailToken(new_wd, wd);
nandConvertPath(abspath, new_wd, new_relpath);
} else if (token[0] != '\0') {
char new_wd[128];
if (strcmp(wd, "/") == 0) {
sprintf(new_wd, "/%s", token);
} else {
sprintf(new_wd, "%s/%s", wd, token);
}
nandConvertPath(abspath, new_wd, new_relpath);
} else {
strcpy(abspath, wd);
}
}
BOOL nandIsRelativePath(const char* path) {
if (path[0] == '/') {
return FALSE;
} else {
return TRUE;
}
}
BOOL nandIsAbsolutePath(const char* path) {
if (nandIsRelativePath(path)) {
return FALSE;
} else {
return TRUE;
}
}
BOOL nandIsPrivatePath(const char* path) {
if (strncmp(path, "/shared2", 8) == 0) {
return TRUE;
} else {
return FALSE;
}
}
BOOL nandIsUnderPrivatePath(const char* path) {
if (strncmp(path, "/shared2/", 9) == 0 && path[9] != '\0') {
return TRUE;
} else {
return FALSE;
}
}
BOOL nandIsInitialized(void) {
if (s_libState == STATE_INITIALIZED) {
return TRUE;
} else {
return FALSE;
}
}
void nandReportErrorCode(const ISFSError err) {
// NONMATCHING
return;
}
void nandLoggingCallback(BOOL, ISFSError err) {
if (err == ISFS_ERROR_UNKNOWN || err == IOS_ERROR_UNKNOWN) {
__NANDPrintErrorMessage(err);
}
}
s32 nandConvertErrorCode(const ISFSError err) {
const int ERRMAP[] = {
ISFS_ERROR_OK, NAND_RESULT_OK,
ISFS_ERROR_ACCESS, NAND_RESULT_ACCESS,
ISFS_ERROR_CORRUPT, NAND_RESULT_CORRUPT,
ISFS_ERROR_ECC_CRIT, NAND_RESULT_ECC_CRIT,
ISFS_ERROR_EXISTS, NAND_RESULT_EXISTS,
ISFS_ERROR_HMAC, NAND_RESULT_AUTHENTICATION,
ISFS_ERROR_INVALID, NAND_RESULT_INVALID,
ISFS_ERROR_MAXBLOCKS, NAND_RESULT_MAXBLOCKS,
ISFS_ERROR_MAXFD, NAND_RESULT_MAXFD,
ISFS_ERROR_MAXFILES, NAND_RESULT_MAXFILES,
ISFS_ERROR_MAXDEPTH, NAND_RESULT_MAXDEPTH,
ISFS_ERROR_NOEXISTS, NAND_RESULT_NOEXISTS,
ISFS_ERROR_NOTEMPTY, NAND_RESULT_NOTEMPTY,
ISFS_ERROR_NOTREADY, NAND_RESULT_UNKNOWN,
ISFS_ERROR_OPENFD, NAND_RESULT_OPENFD,
ISFS_ERROR_UNKNOWN, NAND_RESULT_UNKNOWN,
ISFS_ERROR_BUSY, NAND_RESULT_BUSY,
ISFS_ERROR_SHUTDOWN, NAND_RESULT_FATAL_ERROR,
IOS_ERROR_ACCESS, NAND_RESULT_ACCESS,
IOS_ERROR_EXISTS, NAND_RESULT_EXISTS,
IOS_ERROR_INTR, NAND_RESULT_UNKNOWN,
IOS_ERROR_INVALID, NAND_RESULT_INVALID,
IOS_ERROR_MAX, NAND_RESULT_UNKNOWN,
IOS_ERROR_NOEXISTS, NAND_RESULT_NOEXISTS,
IOS_ERROR_QEMPTY, NAND_RESULT_UNKNOWN,
IOS_ERROR_QFULL, NAND_RESULT_BUSY,
IOS_ERROR_UNKNOWN, NAND_RESULT_UNKNOWN,
IOS_ERROR_NOTREADY, NAND_RESULT_UNKNOWN,
IOS_ERROR_ECC, NAND_RESULT_UNKNOWN,
IOS_ERROR_ECC_CRIT, NAND_RESULT_ECC_CRIT,
IOS_ERROR_BADBLOCK, NAND_RESULT_UNKNOWN,
IOS_ERROR_INVALID_OBJTYPE, NAND_RESULT_UNKNOWN,
IOS_ERROR_INVALID_RNG, NAND_RESULT_UNKNOWN,
IOS_ERROR_INVALID_FLAG, NAND_RESULT_UNKNOWN,
IOS_ERROR_INVALID_FORMAT, NAND_RESULT_UNKNOWN,
IOS_ERROR_INVALID_VERSION, NAND_RESULT_UNKNOWN,
IOS_ERROR_INVALID_SIGNER, NAND_RESULT_UNKNOWN,
IOS_ERROR_FAIL_CHECKVALUE, NAND_RESULT_UNKNOWN,
IOS_ERROR_FAIL_INTERNAL, NAND_RESULT_UNKNOWN,
IOS_ERROR_FAIL_ALLOC, NAND_RESULT_ALLOC_FAILED,
IOS_ERROR_INVALID_SIZE, NAND_RESULT_UNKNOWN,
};
int i = 0;
if (err >= 0) {
return err;
}
for (; i < sizeof(ERRMAP) / 4; i = i + 2) {
if (ERRMAP[i] == err) {
if (err == ISFS_ERROR_ECC_CRIT || err == ISFS_ERROR_HMAC || err == ISFS_ERROR_UNKNOWN || err == IOS_ERROR_UNKNOWN || err == IOS_ERROR_ECC_CRIT) {
char buf[128] ATTRIBUTE_ALIGN(64);
sprintf(buf, "ISFS error code: %d", err);
NANDLoggingAddMessageAsync(nandLoggingCallback, err, buf);
}
nandReportErrorCode(err);
if (err == ISFS_ERROR_MAXBLOCKS || err == ISFS_ERROR_MAXFILES || err == ISFS_ERROR_CORRUPT || err == ISFS_ERROR_BUSY || err == IOS_ERROR_QFULL || err == IOS_ERROR_FAIL_ALLOC) {
__NANDPrintErrorMessage(err);
}
return ERRMAP[i + 1];
}
}
OSReport("CAUTION! Unexpected error code [%d] was found.\n", err);
{
char buf[128] ATTRIBUTE_ALIGN(64);
sprintf(buf, "ISFS unexpected error code: %d", err);
NANDLoggingAddMessageAsync(nandLoggingCallback, err, buf);
}
nandReportErrorCode(err);
return -64;
}
void nandGenerateAbsPath(char* absPath, const char* path) {
if (strlen(path) == 0) {
strcpy(absPath, "");
} else if (nandIsRelativePath(path)) {
nandConvertPath(absPath, s_currentDir, path);
} else {
u32 len = 0xFFFFFFFF;
strcpy(absPath, path);
len = strlen(absPath);
if (len > 0) {
if ((absPath[len - 1] == '/') && (len - 1 != 0)) {
absPath[len - 1] = '\0';
}
}
}
}
void nandGetParentDirectory(char* parentDir, const char* absPath) {
int i = 0;
for (i = (int)strlen(absPath); i >= 0; --i) {
if (absPath[i] == '/') {
break;
}
}
if (i == 0) {
strcpy(parentDir, "/");
} else {
strncpy(parentDir, absPath, (u32)i);
parentDir[i] = '\0';
}
}
s32 NANDInit(void) {
BOOL enabled = OSDisableInterrupts();
if (s_libState == STATE_WORKING) {
OSRestoreInterrupts(enabled);
return -3;
} else if (s_libState == 2) {
OSRestoreInterrupts(enabled);
return 0;
} else {
ISFSError result = ISFS_ERROR_UNKNOWN;
s_libState = STATE_WORKING;
OSRestoreInterrupts(enabled);
result = ISFS_OpenLib();
if (result == 0) {
s32 rv;
ESTitleId id;
rv = ESP_InitLib();
if (rv == 0) {
rv = ESP_GetTitleId(&id);
}
if (rv == 0) {
rv = ESP_GetDataDir(id, s_homeDir);
}
if (rv == 0) {
strcpy(s_currentDir, s_homeDir);
}
ESP_CloseLib();
if (rv != 0) {
OSReport("Failed to set home directory.\n");
}
OSRegisterShutdownFunction(&s_shutdownFuncInfo);
enabled = OSDisableInterrupts();
s_libState = STATE_INITIALIZED;
OSRestoreInterrupts(enabled);
NANDSetAutoErrorMessaging(1);
OSRegisterVersion(__NANDVersion);
return 0;
} else {
enabled = OSDisableInterrupts();
s_libState = STATE_NOT_INITIALIZED;
OSRestoreInterrupts(enabled);
return nandConvertErrorCode(result);
}
}
}
static BOOL nandOnShutdown(BOOL final, u32 event) {
if (!final) {
if (event == 2) {
volatile BOOL flag = FALSE;
OSTime t = OSGetTime();
ISFS_ShutdownAsync(nandShutdownCallback, (void*)&flag);
while (OSTicksToMilliseconds(OSGetTime() - t) < 500) {
if (flag) {
break;
}
}
}
return TRUE;
} else {
return TRUE;
}
}
static void nandShutdownCallback(ISFSError result, void* ctxt) {
(void)result;
*(BOOL*)ctxt = TRUE;
}
// NOTE: function doesn't exist in TP debug, needed for string data
s32 NANDGetCurrentDir() {
OSReport("NANDGetCurrentDir");
}
s32 NANDGetHomeDir(char* path) {
ASSERTMSG1LINE(0, path, "NULL pointer is detected: %s()", "NANDGetHomeDir");
if (!nandIsInitialized()) {
return -128;
}
strcpy(path, s_homeDir);
return 0;
}
void nandCallback(ISFSError result, void* ctxt) {
NANDCommandBlock* b = (NANDCommandBlock*)ctxt;
((NANDCallback)(b->callback))(nandConvertErrorCode(result), b);
}
void nandGetTypeCallback(ISFSError result, void* ctxt);
static ISFSError nandGetType(const char* path, u8* type, NANDCommandBlock* block, const BOOL async_flag, const BOOL privilege_flag) {
ASSERTMSG1LINE(1133, path, "NULL pointer is detected: %s()", __FUNCTION__);
ASSERTMSG1LINE(1134, type, "NULL pointer is detected: %s()", __FUNCTION__);
if (strlen(path) == 0) {
return ISFS_ERROR_INVALID;
}
if (async_flag) {
nandGenerateAbsPath(block->absPath, path);
if (!privilege_flag && nandIsUnderPrivatePath(block->absPath)) {
return ISFS_ERROR_ACCESS;
} else {
block->type = type;
return ISFS_ReadDirAsync((u8*)(block->absPath), NULL, &(block->num), nandGetTypeCallback, block);
}
} else {
char absPath[64] = "";
nandGenerateAbsPath(absPath, path);
if (!privilege_flag && nandIsUnderPrivatePath(absPath)) {
return ISFS_ERROR_ACCESS;
} else {
u32 dmy = 0;
ISFSError err = ISFS_ReadDir((u8*)absPath, NULL, &dmy);
if (err == ISFS_ERROR_OK || err == ISFS_ERROR_ACCESS) {
*type = 2;
err = ISFS_ERROR_OK;
} else if (err == ISFS_ERROR_INVALID) {
*type = 1;
err = ISFS_ERROR_OK;
}
return err;
}
}
}
s32 NANDPrivateGetTypeAsync(const char* path, u8* type, NANDCallback cb, NANDCommandBlock* block) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
block->callback = cb;
return nandConvertErrorCode(nandGetType(path, type, block, TRUE, TRUE));
}
void nandGetTypeCallback(ISFSError result, void* ctxt) {
NANDCommandBlock* b = (NANDCommandBlock*)ctxt;
if (result == ISFS_ERROR_OK || result == ISFS_ERROR_ACCESS) {
*(b->type) = 2;
result = ISFS_ERROR_OK;
} else if (result == ISFS_ERROR_INVALID) {
*(b->type) = 1;
result = ISFS_ERROR_OK;
}
((NANDCallback)(b->callback))(nandConvertErrorCode(result), b);
}
const char* nandGetHomeDir(void) {
return s_homeDir;
}
void NANDInitBanner(NANDBanner* bnr, u32 const flag, const u16* title, const u16* comment) {
ASSERTMSG1LINE(1253, bnr, "Null pointer is detected at %s()", __FUNCTION__);
ASSERTMSG1LINE(1254, title, "Null pointer is detected at %s()", __FUNCTION__);
ASSERTMSG1LINE(1255, comment, "Null pointer is detected at %s()", __FUNCTION__);
memset(bnr, 0, sizeof(NANDBanner));
bnr->signature = 0x5749424E;
bnr->flag = flag;
if (wcscmp((wchar_t*)title, L"") == 0) {
wcsncpy(bnr->comment[0], L" ", 32);
} else {
wcsncpy(bnr->comment[0], (wchar_t*)title, 32);
}
if (wcscmp((wchar_t*)comment, L"") == 0) {
wcsncpy(bnr->comment[1], L" ", 32);
} else {
wcsncpy(bnr->comment[1], (wchar_t*)comment, 32);
}
}

View File

@ -0,0 +1,235 @@
#include <revolution/os.h>
#include <revolution/nand.h>
#include <revolution/fs.h>
#include <revolution/sc.h>
#define REGION_DEFAULT 0
#define REGION_EUROPE 1
#define REGION_CHNKOR 2
const char* const __NANDMaxBlocksErrorMessageDefault[] = {
"\n\n\nWii本体保存メモリの空き容量が異常です。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\n\nThere is no more available space in\nWii system memory. Refer to the Wii\nOperations Manual for details.",
"\n\n\nDer Speicher der Wii-Konsole ist belegt.\nBitte lies die Wii-Bedienungsanleitung,\num weitere Informationen zu erhalten.",
"\n\n\nIl n'y a pas assez d'espace libre\ndans la m駑oire de la console Wii.\nVeuillez vous r馭駻er au Mode d'emploi\nde la Wii pour plus de d騁ails.",
"\n\n\nNo queda espacio libre en la memoria\nde la consola Wii. Consulta el manual\nde operaciones de la consola Wii para\nobtener m疽 informaci\xF3n.",
"\n\n\nNon c'\xE8 pi\xF9 spazio libero nella memoria\ndella console Wii. Per maggiori\ninformazioni, consulta il manuale di\nistruzioni della console Wii.",
"\n\n\nEr is geen vrije ruimte meer in het\ninterne geheugen van het Wii-systeem.\nLees de handleiding voor meer informatie.",
};
const char* const __NANDMaxBlocksErrorMessageEurope[] = {
"\n\n\nWii本体保存メモリの空き容量が異常です。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\n\nThere is no more available space in\nthe Wii System Memory. Please refer to\nthe Wii Operations Manual for details.",
"\n\n\nDer Speicher der Wii-Konsole ist belegt.\nBitte lies die Wii-Bedienungsanleitung,\num weitere Informationen zu erhalten.",
"\n\n\nIl n'y a pas assez d'espace libre dans\nla m駑oire de la console Wii. Veuillez\nvous r馭駻er au mode d'emploi Wii pour\nplus de d騁ails.",
"\n\n\nNo queda espacio libre en la memoria de\nla consola Wii. Consulta el manual de\ninstrucciones de la consola Wii para\nobtener m疽 informaci\xF3n.",
"\n\n\nNon c'\xE8 pi\xF9 spazio libero nella memoria\ndella console Wii. Per maggiori\ninformazioni, consulta il manuale di\nistruzioni della console Wii.",
"\n\n\nEr is geen vrije ruimte meer in het\ninterne geheugen van het Wii-systeem.\nLees de handleiding voor meer informatie.",
};
const char* const __NANDMaxBlocksErrorMessageChinaKorea[] = {
"\n\nエラーコード405。\n\nWii本体保存メモリの空き容量が異常です。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\nError #405,\n\nThere is no more available space in\nWii system memory. Refer to the Wii\nOperations Manual for details.",
};
const char* const __NANDMaxFilesErrorMessageDefault[] = {
"\n\n\nWii本体保存メモリの空きファイル数が異常です。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\n\nThere is no more available space in\nWii system memory. Refer to the Wii\nOperations Manual for details.",
"\n\n\nDer Speicher der Wii-Konsole ist belegt.\nBitte lies die Wii-Bedienungsanleitung,\num weitere Informationen zu erhalten.",
"\n\n\nIl n'y a pas assez d'espace libre dans\nla m駑oire de la console Wii. Veuillez\nvous r馭駻er au Mode d'emploi de la Wii\npour plus de d騁ails.",
"\n\n\nNo queda espacio libre en la memoria de\nla consola Wii. Consulta el manual de\noperaciones de la consola Wii para\nobtener m疽 informaci\xF3n.",
"\n\n\nImpossibile salvare altri dati nella\nmemoria della console Wii. Per maggiori\ninformazioni, consulta il manuale di\nistruzioni della console Wii.",
"\n\n\nEr is geen ruimte meer beschikbaar\nin het interne geheugen van het\nWii-systeem. Lees de handleiding voor\nmeer informatie.",
};
const char* const __NANDMaxFilesErrorMessageEurope[] = {
"\n\n\nWii本体保存メモリの空きファイル数が異常です。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\n\nThere is no more available space in\nthe Wii System Memory. Please refer to\nthe Wii Operations Manual for details.",
"\n\n\nDer Speicher der Wii-Konsole ist belegt.\nBitte lies die Wii-Bedienungsanleitung,\num weitere Informationen zu erhalten.",
"\n\n\nIl n'y a pas assez d'espace libre dans\nla m駑oire de la console Wii. Veuillez\nvous r馭駻er au mode d'emploi Wii pour\nplus de d騁ails.",
"\n\n\nNo queda espacio libre en la memoria de\nla consola Wii. Consulta el manual de\ninstrucciones de la consola Wii para\nobtener m疽 informaci\xF3n.",
"\n\n\nImpossibile salvare altri dati nella\nmemoria della console Wii. Per maggiori\ninformazioni, consulta il manuale di\nistruzioni della console Wii.",
"\n\n\nEr is geen ruimte meer beschikbaar\nin het interne geheugen van het\nWii-systeem. Lees de handleiding voor\nmeer informatie.",
};
const char* const __NANDMaxFilesErrorMessageChinaKorea[] = {
"\n\nエラーコード406。\n\nWii本体保存メモリの空きファイル数が異常です。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\nError #406,\n\nThere is no more available space in\nWii system memory. Refer to the Wii\nOperations Manual for details.",
};
const char* const __NANDCorruptErrorMessageDefault[] = {
"\n\n\nWii本体保存メモリが壊れました。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\n\nThe Wii system memory has been damaged.\nRefer to the Wii Operations Manual for\ndetails.",
"\n\n\nDer Speicher der Wii-Konsole\nist besch臈igt. Bitte lies die\nWii-Bedienungsanleitung, um weitere\nInformationen zu erhalten.",
"\n\n\nLa m駑oire de la console Wii a 騁\xE9 \nendommag馥. Veuillez vous r馭駻er au\nMode d'emploi de la Wii pour plus de\nd騁ails.",
"\n\n\nLa memoria de la consola Wii\nest\xE1 da\xF1""ada. Consulta el manual de\noperaciones de la consola Wii para\nobtener m疽 informaci\xF3n.",
"\n\n\nLa memoria della console Wii e\ndanneggiata. Per maggiori informazioni,\nconsulta il manuale di istruzioni della\nconsole Wii.",
"\n\n\nHet interne geheugen van het\nWii-systeem is beschadigd. Lees de\nWii-handleiding voor meer informatie.",
};
const char* const __NANDCorruptErrorMessageEurope[] = {
"\n\n\nWii本体保存メモリが壊れました。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\n\nThe Wii System Memory has been damaged.\nPlease refer to the Wii Operations Manual\nfor details.",
"\n\n\nDer Speicher der Wii-Konsole\nist beschadigt. Bitte lies die\nWii-Bedienungsanleitung, um weitere\nInformationen zu erhalten.",
"\n\n\nLa m駑oire de la console Wii est\nendommag馥. Veuillez vous r馭駻er au\nmode d'emploi Wii pour plus de d騁ails.\n",
"\n\n\nLa memoria de la consola Wii est\xE1 da\xF1""ada.\nConsulta el manual de instrucciones de la\nconsola Wii para obtener m疽 informaci\xF3n.",
"\n\n\nLa memoria della console Wii e\ndanneggiata. Per maggiori informazioni,\nconsulta il manuale di istruzioni della\nconsole Wii.",
"\n\n\nHet interne geheugen van het\nWii-systeem is beschadigd. Lees de\nWii-handleiding voor meer informatie.",
};
const char* const __NANDCorruptErrorMessageChinaKorea[] = {
"\n\nエラーコード408。\n\nWii本体保存メモリが壊れました。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\nError #408,\n\nThe Wii system memory has been damaged.\nRefer to the Wii Operations Manual for\ndetails.",
};
const char* const __NANDBusyErrorMessageDefault[] = {
"\n\n\nWii本体保存メモリの書き込み/読み出しが\nできませんでした。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\n\nCould not access Wii system memory.\nRefer to the Wii Operations Manual for\ndetails.",
"\n\n\nAuf den Speicher der Wii-Konsole konnte\nnicht zugegriffen werden. Bitte lies die\nWii-Bedienungsanleitung, um weitere\nInformationen zu erhalten.",
"\n\n\nImpossible d'acc馘er \xE0 la m駑oire de\nla console Wii. Veuillez vous r馭駻er\nau Mode d'emploi de la Wii pour plus\nde d騁ails.",
"\n\n\nNo se ha podido acceder a la memoria de\nla consola Wii. Consulta el manual de\noperaciones de la consola Wii para\nobtener m疽 informaci\xF3n.",
"\n\n\nImpossibile accedere alla memoria della\nconsole Wii. Per maggiori informazioni,\nconsulta il manuale di istruzioni della\nconsole Wii.",
"\n\n\nHet interne geheugen van het Wii-systeem\nkan niet worden gelezen of beschreven.\nLees de Wii-handleiding voor meer\ninformatie.",
};
const char* const __NANDBusyErrorMessageEurope[] = {
"\n\n\nWii本体保存メモリの書き込み/読み出しが\nできませんでした。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\n\nCould not access the Wii System Memory.Please refer to the Wii Operations Manual\nfor details.",
"\n\n\nAuf den Speicher der Wii-Konsole konnte\nnicht zugegriffen werden. Bitte lies die\nWii-Bedienungsanleitung, um weitere\nInformationen zu erhalten.",
"\n\n\nImpossible d'acc馘er \xE0 la m駑oire de la\nconsole Wii. Veuillez vous r馭駻er au\nmode d'emploi Wii pour plus de d騁ails.",
"\n\n\nNo se ha podido acceder a la memoria de\nla consola Wii. Consulta el manual de\ninstrucciones de la consola Wii para\nobtener m疽 informaci\xF3n.",
"\n\n\nImpossibile accedere alla memoria della\nconsole Wii. Per maggiori informazioni,\nconsulta il manuale di istruzioni della\nconsole Wii.",
"\n\n\nHet interne geheugen van het Wii-systeem\nkan niet worden gelezen of beschreven.\nLees de Wii-handleiding voor meer\ninformatie.",
};
const char* const __NANDBusyErrorMessageChinaKorea[] = {
"\n\nエラーコード411。\n\nWii本体保存メモリの書き込み/読み出しが\nできませんでした。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\nError #411,\n\nCould not access Wii system memory.\nRefer to the Wii Operations Manual for\ndetails.",
};
const char* const __NANDUnknownErrorMessageDefault[] = {
"\n\n\nWii本体保存メモリの書き込み/読み出し中に\nエラーが発生しました。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\n\nAn error occurred while accessing Wii\nsystem memory. Refer to the Wii\nOperations Manual for details.",
"\n\n\nBeim Zugriff auf den Speicher der\nWii-Konsole ist ein Fehler aufgetreten.\nBitte lies die Wii-Bedienungsanleitung,\num weitere Informationen zu erhalten.",
"\n\n\nUne erreur est survenue pendant le\nprocessus de lecture ou d'馗riture\ndans la m駑oire de la console Wii.\nVeuillez vous r馭駻er au Mode d'emploi\nde la Wii pour plus de d騁ails.",
"\n\n\nSe ha producido un error al intentar\nacceder a la memoria de la consola Wii.\nConsulta el manual de operaciones\nde la consola Wii para obtener m疽\ninformaci\xF3n.",
"\n\n\nSi \xE8 verificato un errore durante la\nlettura o la modifica dei dati\nall'interno della memoria della\nconsole Wii. Per maggiori informazioni,\nconsulta il manuale di istruzioni della\nconsole Wii.",
"\n\n\nEr is een fout opgetreden tijdens het\nlezen of beschrijven van het interne\ngeheugen van het Wii-systeem. Lees de\nWii-handleiding voor meer informatie.",
};
const char* const __NANDUnknownErrorMessageEurope[] = {
"\n\n\nWii本体保存メモリの書き込み/読み出し中に\nエラーが発生しました。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\n\nAn error occurred during the process of\nreading from or writing to the Wii System\nMemory. Please refer to the Wii Operations\nManual for details.",
"\n\n\nBeim Zugriff auf den Speicher der\nWii-Konsole ist ein Fehler aufgetreten.\nBitte lies die Wii-Bedienungsanleitung,\num weitere Informationen zu erhalten.",
"\n\n\nUne erreur est survenue avec la m駑oire\nde la console Wii pendant le processus\nde lecture ou d'馗riture. Veuillez vous\nr馭駻er au mode d'emploi Wii pour plus\nde d鑼ails.",
"\n\n\nSe ha producido un error durante la\nlectura o escritura de la memoria de\nla consola Wii. Consulta el manual de\ninstrucciones de la consola Wii para\nobtener m疽 informaci\xF3n.",
"\n\n\nSi \xE8 verificato un errore durante la\nlettura o la modifica dei dati\nall'interno della memoria della\nconsole Wii. Per maggiori informazioni,\nconsulta il manuale di istruzioni della\nconsole Wii.",
"\n\n\nEr is een fout opgetreden tijdens het\nlezen of beschrijven van het interne\ngeheugen van het Wii-systeem. Lees de\nWii-handleiding voor meer informatie.",
};
const char* const __NANDUnknownErrorMessageChinaKorea[] = {
"\n\nエラーコード412。\n\nWii本体保存メモリの書き込み/読み出し中に\nエラーが発生しました。\nくわしくはWii本体の取扱説明書をお読み\nください。",
"\n\nError #412,\n\nAn error occurred while accessing Wii\nsystem memory. Refer to the Wii\nOperations Manual for details.",
};
static void (*NANDErrorFunc)(s32 errorCode);
const char* const* __NANDSetErrorMessageList(s32 errorCode, s32 region) {
u8 i = 0;
struct {
int errorCode;
int region;
const char* const* messageList;
} errorMessageList[] = {
{ISFS_ERROR_MAXBLOCKS, REGION_DEFAULT, __NANDMaxBlocksErrorMessageDefault},
{ISFS_ERROR_MAXFILES, REGION_DEFAULT, __NANDMaxFilesErrorMessageDefault},
{ISFS_ERROR_CORRUPT, REGION_DEFAULT, __NANDCorruptErrorMessageDefault},
{ISFS_ERROR_BUSY, REGION_DEFAULT, __NANDBusyErrorMessageDefault},
{IOS_ERROR_FAIL_ALLOC, REGION_DEFAULT, __NANDBusyErrorMessageDefault},
{ISFS_ERROR_UNKNOWN, REGION_DEFAULT, __NANDUnknownErrorMessageDefault},
{IOS_ERROR_UNKNOWN, REGION_DEFAULT, __NANDUnknownErrorMessageDefault},
{ISFS_ERROR_MAXBLOCKS, REGION_EUROPE, __NANDMaxBlocksErrorMessageEurope},
{ISFS_ERROR_MAXFILES, REGION_EUROPE, __NANDMaxFilesErrorMessageEurope},
{ISFS_ERROR_CORRUPT, REGION_EUROPE, __NANDCorruptErrorMessageEurope},
{ISFS_ERROR_BUSY, REGION_EUROPE, __NANDBusyErrorMessageEurope},
{IOS_ERROR_FAIL_ALLOC, REGION_EUROPE, __NANDBusyErrorMessageEurope},
{ISFS_ERROR_UNKNOWN, REGION_EUROPE, __NANDUnknownErrorMessageEurope},
{IOS_ERROR_UNKNOWN, REGION_EUROPE, __NANDUnknownErrorMessageEurope},
{ISFS_ERROR_MAXBLOCKS, REGION_CHNKOR, __NANDMaxBlocksErrorMessageChinaKorea},
{ISFS_ERROR_MAXFILES, REGION_CHNKOR, __NANDMaxFilesErrorMessageChinaKorea},
{ISFS_ERROR_CORRUPT, REGION_CHNKOR, __NANDCorruptErrorMessageChinaKorea},
{ISFS_ERROR_BUSY, REGION_CHNKOR, __NANDBusyErrorMessageChinaKorea},
{IOS_ERROR_FAIL_ALLOC, REGION_CHNKOR, __NANDBusyErrorMessageChinaKorea},
{ISFS_ERROR_UNKNOWN, REGION_CHNKOR, __NANDUnknownErrorMessageChinaKorea},
{IOS_ERROR_UNKNOWN, REGION_CHNKOR, __NANDUnknownErrorMessageChinaKorea},
};
while (i < 21) {
if (region == errorMessageList[i].region) {
if (errorCode == errorMessageList[i].errorCode) {
return errorMessageList[i].messageList;
}
i++;
continue;
}
i = i + 7;
}
return __NANDUnknownErrorMessageDefault;
}
void __NANDShowErrorMessage(s32 errorCode) {
const char* message;
const char* const* messageList;
GXColor bg = { 0, 0, 0, 0 };
GXColor fg = { 255, 255, 255, 0 };
if (SCGetLanguage() == SC_LANG_JAPANESE) {
OSSetFontEncode(OS_FONT_ENCODE_SJIS);
} else {
OSSetFontEncode(OS_FONT_ENCODE_ANSI);
}
switch (SCGetProductGameRegion()) {
case 0:
case 1:
case 3:
default:
messageList = __NANDSetErrorMessageList(errorCode, REGION_DEFAULT);
break;
case 2:
messageList = __NANDSetErrorMessageList(errorCode, REGION_EUROPE);
break;
case 4:
case 5:
messageList = __NANDSetErrorMessageList(errorCode, REGION_CHNKOR);
break;
}
if (SCGetLanguage() > SC_LANG_DUTCH) {
message = messageList[1];
} else {
message = messageList[SCGetLanguage()];
}
OSFatal(fg, bg, message);
}
BOOL NANDSetAutoErrorMessaging(BOOL show) {
BOOL enabled = OSDisableInterrupts();
BOOL var_r30 = NANDErrorFunc != NULL ? TRUE : FALSE;
NANDErrorFunc = show ? __NANDShowErrorMessage : NULL;
OSRestoreInterrupts(enabled);
return var_r30;
}
void __NANDPrintErrorMessage(s32 errorCode) {
if (NANDErrorFunc) {
NANDErrorFunc(errorCode);
}
}

View File

@ -0,0 +1,181 @@
#include <revolution/os.h>
#include <revolution/fs.h>
#include <revolution/nand.h>
#include <string.h>
#include <printf.h>
static IOSFd s_fd = -255;
static IOSError s_err = ISFS_ERROR_UNKNOWN;
static int s_stage;
static char s_message[256] ATTRIBUTE_ALIGN(64);
static NANDLoggingCallback s_callback = 0;
static void asyncRoutine(ISFSError, void*);
static void prepareLine(char line[256], int, const char*);
BOOL reserveFileDescriptor(void) {
BOOL enabled = FALSE;
BOOL busy_flag = FALSE;
enabled = OSDisableInterrupts();
if (s_fd == -255) {
s_fd = -254;
busy_flag = FALSE;
} else if (s_fd == -254) {
busy_flag = TRUE;
} else if (s_fd >= 0) {
busy_flag = TRUE;
} else {
busy_flag = TRUE;
}
OSRestoreInterrupts(enabled);
return busy_flag ? FALSE : TRUE;
}
BOOL NANDLoggingAddMessageAsync(NANDLoggingCallback cb, s32 errorCode, const char* fmt, ...) {
va_list ap;
ISFSError err = ISFS_ERROR_UNKNOWN;
if (!reserveFileDescriptor()) {
return FALSE;
}
va_start(ap, fmt);
vsnprintf(s_message, 256, fmt, ap);
va_end(ap);
s_callback = cb;
s_stage = 1;
if (errorCode == ISFS_ERROR_UNKNOWN || errorCode == IOS_ERROR_UNKNOWN) {
s_err = errorCode;
}
err = ISFS_OpenAsync((const u8*)"/shared2/test2/nanderr.log", 3, asyncRoutine, 0);
if (err == ISFS_ERROR_OK) {
return TRUE;
} else {
return FALSE;
}
}
static void callbackRoutine(BOOL result) {
if (s_callback) {
s_callback(result, s_err);
}
}
static void asyncRoutine(ISFSError result, void *ctxt) {
ISFSError ret = ISFS_ERROR_UNKNOWN;
static char s_rBuf[256] ATTRIBUTE_ALIGN(64);
static char s_wBuf[256] ATTRIBUTE_ALIGN(64);
++s_stage;
if (s_stage == 2) {
if (result >= 0) {
s_fd = result;
ret = ISFS_SeekAsync(s_fd, 0, 0, asyncRoutine, 0);
if (ret != ISFS_ERROR_OK) {
callbackRoutine(FALSE);
}
} else {
callbackRoutine(FALSE);
}
} else if (s_stage == 3) {
if (result == 0) {
ret = ISFS_ReadAsync(s_fd, (u8*)s_rBuf, 256, asyncRoutine, 0);
if (ret != ISFS_ERROR_OK) {
callbackRoutine(FALSE);
}
} else {
callbackRoutine(FALSE);
}
} else if (s_stage == 4) {
if (result == 256) {
ret = ISFS_SeekAsync(s_fd, 0, 0, asyncRoutine, 0);
if (ret != ISFS_ERROR_OK) {
callbackRoutine(FALSE);
}
} else {
callbackRoutine(FALSE);
}
} else if (s_stage == 5) {
if (result == 0) {
int n = 0;
s_rBuf[255] = '\0';
n = atoi(s_rBuf);
prepareLine(s_wBuf, n, s_message);
ret = ISFS_WriteAsync(s_fd, (const u8*)s_wBuf, 256, asyncRoutine, 0);
if (ret != ISFS_ERROR_OK) {
callbackRoutine(FALSE);
}
} else {
callbackRoutine(FALSE);
}
} else if (s_stage == 6) {
if (result == 256) {
int n = atoi(s_rBuf);
ret = ISFS_SeekAsync(s_fd, n * 256, 0, asyncRoutine, 0);
if (ret != ISFS_ERROR_OK) {
callbackRoutine(FALSE);
}
} else {
callbackRoutine(FALSE);
}
} else if (s_stage == 7) {
int n = atoi(s_rBuf);
if (result == n * 256) {
ret = ISFS_WriteAsync(s_fd, (const u8*)s_wBuf, 256, asyncRoutine, 0);
if (ret != ISFS_ERROR_OK) {
callbackRoutine(FALSE);
}
} else {
callbackRoutine(FALSE);
}
} else if (s_stage == 8) {
if (result == 256) {
ret = ISFS_CloseAsync(s_fd, asyncRoutine, 0);
if (ret != ISFS_ERROR_OK) {
callbackRoutine(FALSE);
}
} else {
callbackRoutine(FALSE);
}
} else if (s_stage == 9) {
if (result == ISFS_ERROR_OK) {
s_fd = -255;
callbackRoutine(TRUE);
} else {
callbackRoutine(FALSE);
}
}
}
static void prepareLine(char line[256], int n, const char* msg) {
char titleID[64];
int end = 0;
struct OSCalendarTime cal;
memset(line, ' ', 254);
OSTicksToCalendarTime(OSGetTime(), &cal);
strncpy(titleID, nandGetHomeDir() + 7, 8 + 1 + 8);
titleID[8] = '-';
titleID[8 + 1 + 8] = '\0';
end = snprintf(line, 256, "%d %04d/%02d/%02d %02d:%02d:%02d %s %s", n % (64 - 1) + 1, cal.year, cal.mon + 1, cal.mday, cal.hour, cal.min, cal.sec, titleID, msg);
if (end < 256) {
line[end] = ' ';
}
line[254] = '\r';
line[255] = '\n';
}

View File

@ -0,0 +1,683 @@
#include <revolution/os.h>
#include <revolution/nand.h>
#include <revolution/fs.h>
static void nandOpenCallback(ISFSError, void *);
static void nandReadCloseCallback(ISFSError, void *);
static void nandCloseCallback(ISFSError, void *);
static void nandSafeCloseCallback(ISFSError, void *);
static void nandSafeOpenCallback(const ISFSError, void *);
void nandReadOpenCallback(ISFSError, void *);
s32 nandSafeCloseAsync(NANDFileInfo *, NANDCallback, NANDCommandBlock *, BOOL);
s32 nandSafeOpenAsync(const char *, NANDFileInfo *, const u8, void *, const u32, NANDCallback, NANDCommandBlock *, BOOL, BOOL);
s32 nandSafeOpen(const char* path, NANDFileInfo* info, const u8 accType, void* buf, const u32 length, BOOL privilege_flag, BOOL simple_flag);
s32 nandSafeClose(NANDFileInfo* info, BOOL simple_flag);
static ISFSError nandCopy(s32 fd, s32 origFd, void* buf, const u32 length);
static u32 nandGetUniqueNumber(void);
IOSFd nandOpen(const char* path, const u8 accType, NANDCommandBlock* block, const BOOL async_flag, const BOOL privilege_flag) {
IOSFd fd = ISFS_ERROR_UNKNOWN;
char absPath[64] = "";
u32 access = 0;
ASSERTMSGLINE(188, path, "NULL pointer is detected.");
ASSERTMSGLINE(192, accType == 1 || accType == 2 || accType == 3, "Access type is illegal.");
nandGenerateAbsPath(absPath, path);
if (!privilege_flag && nandIsPrivatePath(absPath)) {
return ISFS_ERROR_ACCESS;
} else {
switch (accType) {
case 3:
access = 3;
break;
case 1:
access = 1;
break;
case 2:
access = 2;
break;
default:
break;
}
if (async_flag) {
fd = ISFS_OpenAsync((const u8*)absPath, access, nandOpenCallback, block);
} else {
fd = ISFS_Open((const u8*)absPath, access);
}
return fd;
}
}
s32 NANDOpen(const char* path, NANDFileInfo* info, const u8 accType) {
IOSFd fd = ISFS_ERROR_UNKNOWN;
ASSERTMSGLINE(234, info, "NULL pointer is detected.");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
fd = nandOpen(path, accType, NULL, FALSE, FALSE);
if (fd >= 0) {
info->fileDescriptor = fd;
info->mark = 1;
return NAND_RESULT_OK;
} else {
return nandConvertErrorCode(fd);
}
}
s32 NANDPrivateOpen(const char* path, NANDFileInfo* info, const u8 accType) {
IOSFd fd = ISFS_ERROR_UNKNOWN;
ASSERTMSGLINE(259, info, "NULL pointer is detected.");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
fd = nandOpen(path, accType, NULL, FALSE, TRUE);
if (fd >= 0) {
info->fileDescriptor = fd;
info->mark = 1;
return NAND_RESULT_OK;
} else {
return nandConvertErrorCode(fd);
}
}
s32 NANDOpenAsync(const char* path, NANDFileInfo* info, const u8 accType, NANDCallback cb, NANDCommandBlock* block) {
IOSFd fd = ISFS_ERROR_UNKNOWN;
ASSERTMSGLINE(284, info, "NULL pointer is detected.");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
block->callback = cb;
block->fileInfo = info;
fd = nandOpen(path, accType, block, TRUE, FALSE);
return nandConvertErrorCode(fd);
}
s32 NANDPrivateOpenAsync(const char* path, NANDFileInfo* info, const u8 accType, NANDCallback cb, NANDCommandBlock* block) {
IOSFd fd = ISFS_ERROR_UNKNOWN;
ASSERTMSGLINE(301, info, "NULL pointer is detected.");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
block->callback = cb;
block->fileInfo = info;
fd = nandOpen(path, accType, block, TRUE, TRUE);
return nandConvertErrorCode(fd);
}
void nandOpenCallback(ISFSError result, void* ctxt) {
NANDCommandBlock* b = (NANDCommandBlock*)ctxt;
if (result >= 0) {
((NANDFileInfo*)(b->fileInfo))->fileDescriptor = result;
((NANDFileInfo*)(b->fileInfo))->stage = 2;
((NANDFileInfo*)(b->fileInfo))->mark = 1;
((NANDCallback)(b->callback))(NAND_RESULT_OK, b);
} else {
((NANDCallback)(b->callback))(nandConvertErrorCode(result), b);
}
}
s32 NANDClose(NANDFileInfo* info) {
ISFSError err = ISFS_ERROR_UNKNOWN;
ASSERTMSGLINE(341, info, "NULL pointer is detected.");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
if (info->mark != 1) {
return NAND_RESULT_INVALID;
}
err = ISFS_Close(info->fileDescriptor);
if (err == ISFS_ERROR_OK) {
info->mark = 2;
}
return nandConvertErrorCode(err);
}
s32 NANDCloseAsync(NANDFileInfo* info, NANDCallback cb, NANDCommandBlock* block) {
ISFSError err = ISFS_ERROR_UNKNOWN;
ASSERTMSGLINE(364, info, "NULL pointer is detected.");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
if (info->mark != 1) {
return NAND_RESULT_INVALID;
}
block->callback = cb;
block->fileInfo = info;
err = ISFS_CloseAsync(info->fileDescriptor, nandCloseCallback, block);
return nandConvertErrorCode(err);
}
s32 NANDSimpleSafeOpen(const char* path, NANDFileInfo* info, const u8 accType, void* buf, const u32 length) {
return nandSafeOpen(path, info, accType, buf, length, FALSE, TRUE);
}
s32 nandSafeOpen(const char* path, NANDFileInfo* info, const u8 accType, void* buf, const u32 length, BOOL privilege_flag, BOOL simple_flag) {
ASSERTMSGLINE(411, path, "NULL pointer detected.\n");
ASSERTMSGLINE(412, info, "NULL pointer detected.\n");
ASSERTMSGLINE(413, accType == 1 || accType == 2 || accType == 3, "Illegal access type.\n");
ASSERTMSGLINE(414, buf, "NULL pointer detected.\n");
ASSERTMSGLINE(415, !((u32)buf & 0x1F), "32byte alignment is required.\n");
ASSERTMSGLINE(416, !(length & 0x1F), "Buffer size must be multiples of 32.\n");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
if (simple_flag && ((length & 0x3FFF) != 0)) {
return NAND_RESULT_INVALID;
}
info->accType = accType;
info->stage = 0;
nandGenerateAbsPath(info->origPath, path);
if (!privilege_flag && nandIsPrivatePath(info->origPath)) {
return NAND_RESULT_ACCESS;
}
if (accType == 1) {
IOSFd fd = ISFS_Open((u8*)(info->origPath), 1);
if (fd >= ISFS_ERROR_OK) {
info->fileDescriptor = fd;
info->stage = 2;
if (!simple_flag) {
info->mark = 3;
} else {
info->mark = 5;
}
return NAND_RESULT_OK;
} else {
return nandConvertErrorCode(fd);
}
} else if (accType == 2 || accType == 3) {
char dirName[64];
char relName[13] = {0};
ISFSError ret = ISFS_ERROR_UNKNOWN;
IOSUid ownerId;
IOSGid groupId;
u32 attr;
u32 ownerAcc;
u32 groupAcc;
u32 othersAcc;
u32 sp48 = -1;
ret = ISFS_CreateDir((u8*)"/tmp/sys", 0, 3, 3, 3);
if (ret != ISFS_ERROR_OK && ret != ISFS_ERROR_EXISTS) {
return nandConvertErrorCode(ret);
} else {
info->stage = 1;
ret = ISFS_GetAttr((const u8*)info->origPath, &ownerId, &groupId, &attr, &ownerAcc, &groupAcc, &othersAcc);
if (ret != ISFS_ERROR_OK) {
return nandConvertErrorCode(ret);
}
info->origFd = ISFS_Open((u8*)info->origPath, 1);
if (info->origFd < 0) {
return nandConvertErrorCode(info->origFd);
}
info->stage = 2;
if (!simple_flag) {
sp48 = nandGetUniqueNumber();
sprintf(dirName, "%s/%08x", "/tmp/sys", sp48);
ret = ISFS_CreateDir((const u8*)dirName, 0, 3, 0, 0);
if (ret != 0) {
return nandConvertErrorCode(ret);
}
info->stage = 3;
}
nandGetRelativeName(relName, info->origPath);
if (!simple_flag) {
sprintf(info->tmpPath, "%s/%08x/%s", "/tmp/sys", sp48, relName);
} else {
sprintf(info->tmpPath, "%s/%s", "/tmp/sys", relName);
}
ret = ISFS_CreateFile((const u8*)info->tmpPath, attr, ownerAcc, groupAcc, othersAcc);
if (ret != 0) {
return nandConvertErrorCode(ret);
}
info->stage = 4;
if (accType == 2) {
info->fileDescriptor = ISFS_Open((const u8*)info->tmpPath, 2);
} else if (accType == 3) {
info->fileDescriptor = ISFS_Open((const u8*)info->tmpPath, 3);
}
if (info->fileDescriptor < 0) {
return nandConvertErrorCode(info->fileDescriptor);
}
info->stage = 5;
ret = nandCopy(info->fileDescriptor, info->origFd, buf, length);
if (ret != 0) {
return nandConvertErrorCode(ret);
}
ret = ISFS_Seek(info->fileDescriptor, 0, 0);
if (ret == 0) {
ret = 0;
} else {
return nandConvertErrorCode(ret);
}
if (ret == 0) {
if (simple_flag) {
info->mark = 5;
} else {
info->mark = 3;
}
}
return nandConvertErrorCode(ret);
}
} else {
return NAND_RESULT_INVALID;
}
}
s32 NANDSimpleSafeClose(NANDFileInfo* info) {
return nandSafeClose(info, TRUE);
}
s32 nandSafeClose(NANDFileInfo* info, BOOL simple_flag) {
ISFSError err = ISFS_ERROR_UNKNOWN;
char tmpdir[64] = "";
ASSERTMSGLINE(612, info, "NULL pointer detected.\n");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
if (!((info->mark == 3 && !simple_flag) || (info->mark == 5 && simple_flag))) {
return NAND_RESULT_INVALID;
}
if (info->accType == 1) {
err = ISFS_Close(info->fileDescriptor);
if (err == 0) {
info->stage = 7;
if (!simple_flag) {
info->mark = 4;
} else {
info->mark = 6;
}
}
return nandConvertErrorCode(err);
} else if (info->accType == 2 || info->accType == 3) {
err = ISFS_Close(info->fileDescriptor);
if (err != 0) {
return nandConvertErrorCode(err);
}
info->stage = 6;
err = ISFS_Close(info->origFd);
if (err != 0) {
return nandConvertErrorCode(err);
}
info->stage = 7;
err = ISFS_Rename((const u8*)info->tmpPath, (const u8*)info->origPath);
if (err != 0) {
return nandConvertErrorCode(err);
}
info->stage = 8;
if (!simple_flag) {
nandGetParentDirectory(tmpdir, info->tmpPath);
err = ISFS_Delete((const u8*)tmpdir);
if (err == 0) {
info->stage = 9;
info->mark = 4;
}
} else {
info->mark = 6;
}
return nandConvertErrorCode(err);
} else {
OSReport("Illegal NANDFileInfo.\n");
}
return NAND_RESULT_INVALID;
}
s32 NANDPrivateSafeOpenAsync(const char* path, NANDFileInfo* info, const u8 accType, void* buf, const u32 length, NANDCallback cb, NANDCommandBlock* block) {
return nandSafeOpenAsync(path, info, accType, buf, length, cb, block, TRUE, FALSE);
}
s32 nandSafeOpenAsync(const char* path, NANDFileInfo* info, const u8 accType, void* buf, const u32 length, NANDCallback cb, NANDCommandBlock* block, BOOL privilege_flag, BOOL simple_flag) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
if (simple_flag && ((length & 0x3FFF) != 0)) {
return NAND_RESULT_INVALID;
}
info->accType = accType;
info->stage = 0;
block->simpleFlag = simple_flag;
nandGenerateAbsPath(info->origPath, path);
if (!privilege_flag && nandIsPrivatePath(info->origPath)) {
return NAND_RESULT_ACCESS;
}
if (accType == 1) {
IOSFd fd = -1;
block->fileInfo = info;
block->callback = cb;
fd = ISFS_OpenAsync((u8*)(info->origPath), 1, nandReadOpenCallback, block);
if (fd == ISFS_ERROR_OK) {
return NAND_RESULT_OK;
} else {
return nandConvertErrorCode(fd);
}
} else if (accType == 2 || accType == 3) {
ISFSError ret = ISFS_ERROR_UNKNOWN;
block->fileInfo = info;
block->callback = cb;
block->state = 0;
block->copyBuf = buf;
block->bufLength = length;
ret = ISFS_CreateDirAsync((u8*)"/tmp/sys", 0, 3, 3, 3, nandSafeOpenCallback, block);
if (ret == ISFS_ERROR_OK) {
return NAND_RESULT_OK;
} else {
return nandConvertErrorCode(ret);
}
} else {
return NAND_RESULT_INVALID;
}
}
void nandSafeOpenCallback(const ISFSError result, void* ctxt) {
NANDCommandBlock* b = (NANDCommandBlock*)ctxt;
if (result >= 0 || (result == ISFS_ERROR_EXISTS && b->state == 0)) {
NANDFileInfo* info = b->fileInfo;
ISFSError ret = ISFS_ERROR_UNKNOWN;
if (b->state == 0) {
info->stage = 1;
}
if (b->state == 2) {
info->origFd = result;
info->stage = 2;
}
if (b->state == 2 && b->simpleFlag) {
b->state += 2;
} else {
++b->state;
}
if (b->state == 1) {
ret = ISFS_GetAttrAsync((u8*)(info->origPath), &b->ownerId, &b->groupId, &b->attr, &b->ownerAcc, &b->groupAcc, &b->othersAcc, nandSafeOpenCallback, ctxt);
} else if (b->state == 2) {
ret = ISFS_OpenAsync((u8*)(info->origPath), 1, nandSafeOpenCallback, ctxt);
} else if (b->state == 3) {
char tmpDir[64];
b->uniqNo = nandGetUniqueNumber();
sprintf(tmpDir, "%s/%08x", "/tmp/sys", b->uniqNo);
ret = ISFS_CreateDirAsync((u8*)tmpDir, 0, 3, 0, 0, nandSafeOpenCallback, ctxt);
} else if (b->state == 4) {
char filename[13];
nandGetRelativeName(filename, info->origPath);
if (!b->simpleFlag) {
info->stage = 3;
sprintf(info->tmpPath, "%s/%08x/%s", "/tmp/sys", b->uniqNo, filename);
}
else {
sprintf(info->tmpPath, "%s/%s", "/tmp/sys", filename);
}
ret = ISFS_CreateFileAsync((u8*)info->tmpPath, b->attr, b->ownerAcc, b->groupAcc, b->othersAcc, nandSafeOpenCallback, ctxt);
} else if (b->state == 5) {
info->stage = 4;
if (info->accType == 2) {
ret = ISFS_OpenAsync((u8*)info->tmpPath, 2, nandSafeOpenCallback, ctxt);
} else if (info->accType == 3) {
ret = ISFS_OpenAsync((u8*)info->tmpPath, 3, nandSafeOpenCallback, ctxt);
} else {
ret = ISFS_ERROR_UNKNOWN;
}
} else if (b->state == 6) {
info->fileDescriptor = result;
info->stage = 5;
b->state = 7;
ret = ISFS_ReadAsync(info->origFd, b->copyBuf, b->bufLength, nandSafeOpenCallback, ctxt);
} else if (b->state == 7) {
ret = ISFS_ReadAsync(info->origFd, b->copyBuf, b->bufLength, nandSafeOpenCallback, ctxt);
} else if (b->state == 8) {
if (result > 0) {
b->state = 6;
ret = ISFS_WriteAsync(info->fileDescriptor, b->copyBuf, (u32)result, nandSafeOpenCallback, ctxt);
} else if (result == 0) {
ret = ISFS_SeekAsync(info->fileDescriptor, 0, 0, nandSafeOpenCallback, ctxt);
}
} else if (b->state == 9) {
if (result == 0) {
if (!b->simpleFlag) {
info->mark = 3;
} else {
info->mark = 5;
}
((NANDCallback)(b->callback))(nandConvertErrorCode(ISFS_ERROR_OK), b);
} else {
((NANDCallback)(b->callback))(nandConvertErrorCode(result), b);
}
return;
}
if (ret != ISFS_ERROR_OK) {
((NANDCallback)(b->callback))(nandConvertErrorCode(ret), b);
}
} else {
((NANDCallback)(b->callback))(nandConvertErrorCode(result), b);
}
}
void nandReadOpenCallback(ISFSError result, void* ctxt) {
NANDCommandBlock* b = (NANDCommandBlock*)ctxt;
if (result >= 0) {
((NANDFileInfo*)(b->fileInfo))->fileDescriptor = result;
((NANDFileInfo*)(b->fileInfo))->stage = 2;
if (!(b->simpleFlag)) {
((NANDFileInfo*)(b->fileInfo))->mark = 3;
} else {
((NANDFileInfo*)(b->fileInfo))->mark = 5;
}
((NANDCallback)(b->callback))(NAND_RESULT_OK, b);
} else {
((NANDCallback)(b->callback))(nandConvertErrorCode(result), b);
}
}
void dummyStrings() {
OSReport("NULL pointer detected.");
}
s32 NANDSafeCloseAsync(NANDFileInfo* info, NANDCallback cb, NANDCommandBlock* block) {
return nandSafeCloseAsync(info, cb, block, FALSE);
}
s32 nandSafeCloseAsync(NANDFileInfo* info, NANDCallback cb, NANDCommandBlock* block, BOOL simple_flag) {
ISFSError err = ISFS_ERROR_UNKNOWN;
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
if (!((info->mark == 3 && !simple_flag) || (info->mark == 5 && simple_flag))) {
return NAND_RESULT_INVALID;
}
block->simpleFlag = simple_flag;
if (info->accType == 1) {
block->fileInfo = info;
block->callback = cb;
err = ISFS_CloseAsync(info->fileDescriptor, nandReadCloseCallback, block);
} else if (info->accType == 2 || info->accType == 3) {
block->fileInfo = info;
block->callback = cb;
block->state = 10;
err = ISFS_CloseAsync(info->fileDescriptor, nandSafeCloseCallback, block);
} else {
err = ISFS_ERROR_INVALID;
}
return nandConvertErrorCode(err);
}
void nandSafeCloseCallback(ISFSError result, void* ctxt) {
NANDCommandBlock* b = (NANDCommandBlock*)ctxt;
if (result == 0) {
NANDFileInfo* info = b->fileInfo;
ISFSError ret = ISFS_ERROR_UNKNOWN;
if (b->state == 12) {
info->stage = 8;
}
if (b->state == 12 && b->simpleFlag) {
b->state += 2;
} else {
++b->state;
}
if (b->state == 11) {
info->stage = 6;
ret = ISFS_CloseAsync(info->origFd, nandSafeCloseCallback, ctxt);
} else if (b->state == 12) {
info->stage = 7;
ret = ISFS_RenameAsync((u8*)(info->tmpPath), (u8*)(info->origPath), nandSafeCloseCallback, ctxt);
} else if (b->state == 13) {
char tmpdir[64] = "";
nandGetParentDirectory(tmpdir, info->tmpPath);
ret = ISFS_DeleteAsync((u8*)tmpdir, nandSafeCloseCallback, ctxt);
} else if (b->state == 14) {
if (!(b->simpleFlag)) {
info->stage = 9;
}
info->mark = 4;
((NANDCallback)(b->callback))(nandConvertErrorCode(result), b);
return;
}
if (ret != 0) {
((NANDCallback)(b->callback))(nandConvertErrorCode(ret), b);
}
} else {
((NANDCallback)(b->callback))(nandConvertErrorCode(result), b);
}
}
static void nandReadCloseCallback(ISFSError result, void* ctxt) {
NANDCommandBlock* b = (NANDCommandBlock*)ctxt;
if (result == 0) {
((NANDFileInfo*)(b->fileInfo))->stage = 7;
((NANDFileInfo*)(b->fileInfo))->mark = 4;
}
((NANDCallback)(b->callback))(nandConvertErrorCode(result), b);
}
static void nandCloseCallback(ISFSError result, void* ctxt) {
NANDCommandBlock* b = (NANDCommandBlock*)ctxt;
if (result == 0) {
((NANDFileInfo*)(b->fileInfo))->stage = 7;
((NANDFileInfo*)(b->fileInfo))->mark = 2;
}
((NANDCallback)(b->callback))(nandConvertErrorCode(result), b);
}
static ISFSError nandCopy(s32 fd, s32 origFd, void* buf, const u32 length) {
while (1) {
ISFSError ret;
ISFSError ret2;
ret = ISFS_Read(origFd, buf, length);
if (ret == 0) {
return 0;
}
if (ret < 0) {
return ret;
}
ret2 = ISFS_Write(fd, buf, ret);
if (ret2 < 0) {
return ret2;
}
if (ret2 != ret) {}
}
}
static u32 nandGetUniqueNumber(void) {
static u32 s_counter = 0;
u32 ret;
BOOL enabled = OSDisableInterrupts();
ret = s_counter++;
OSRestoreInterrupts(enabled);
return ret;
}

565
src/revolution/nand/nand.c Normal file
View File

@ -0,0 +1,565 @@
#include <revolution/os.h>
#include <revolution/fs.h>
#include <revolution/nand.h>
#include <string.h>
static BOOL nandInspectPermission(u8);
static void nandSplitPerm(u8, u32*, u32*, u32*);
static void nandGetTypeCallback(ISFSError, void*);
static void nandGetStatusCallback(ISFSError, void*);
BOOL nandCheckPathName(const char* path);
BOOL nandCheckCharacter(char character);
void nandCallback(ISFSError, void*);
ISFSError nandCreate(const char* path, const u8 perm, const u8 attr, NANDCommandBlock* block, BOOL async_flag,
BOOL privilege_flag) {
char absPath[64] = "";
u32 owner = 0, group = 0, others = 0;
ASSERTMSGLINE(254, path, "NULL pointer is detected.");
if (!nandCheckPathName(path)) {
return ISFS_ERROR_INVALID;
}
nandGenerateAbsPath(absPath, path);
if (!privilege_flag && nandIsPrivatePath(absPath)) {
return ISFS_ERROR_ACCESS;
} else if (!nandInspectPermission(perm)) {
return ISFS_ERROR_INVALID;
} else {
nandSplitPerm(perm, &owner, &group, &others);
if (async_flag) {
return ISFS_CreateFileAsync((const u8*)absPath, attr, owner, group, others, nandCallback, block);
} else {
return ISFS_CreateFile((const u8*)absPath, attr, owner, group, others);
}
}
}
s32 NANDCreate(const char* path, const u8 perm, const u8 attr) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
return nandConvertErrorCode(nandCreate(path, perm, attr, NULL, FALSE, FALSE));
}
s32 NANDPrivateCreate(const char* path, u8 perm, u8 attr) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
return nandConvertErrorCode(nandCreate(path, perm, attr, NULL, FALSE, TRUE));
}
s32 NANDPrivateCreateAsync(const char* path, u8 perm, u8 attr, NANDCallback cb,
NANDCommandBlock* block) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
block->callback = cb;
return nandConvertErrorCode(nandCreate(path, perm, attr, block, TRUE, TRUE));
}
static ISFSError nandDelete(const char* path, NANDCommandBlock* block,
BOOL async_flag, BOOL privilege_flag) {
char absPath[64] = "";
nandGenerateAbsPath(absPath, path);
if (!privilege_flag && nandIsPrivatePath(absPath)) {
return ISFS_ERROR_ACCESS;
} else {
if (async_flag) {
return ISFS_DeleteAsync((const u8*)absPath, nandCallback, block);
} else {
return ISFS_Delete((const u8*)absPath);
}
}
}
s32 NANDDelete(const char* path) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
return nandConvertErrorCode(nandDelete(path, NULL, FALSE, FALSE));
}
s32 NANDPrivateDelete(const char* path) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
return nandConvertErrorCode(nandDelete(path, NULL, FALSE, TRUE));
}
s32 NANDPrivateDeleteAsync(const char* path, NANDCallback cb, NANDCommandBlock* block) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
block->callback = cb;
return nandConvertErrorCode(nandDelete(path, block, TRUE, TRUE));
}
s32 NANDRead(NANDFileInfo* info, void* buf, const u32 length) {
ASSERTMSGLINE(412, info, "*info is NULL pointer!");
ASSERTMSGLINE(413, buf, "*buf is NULL pointer!");
ASSERTMSGLINE(414, !((u32)buf & 0x1F), "Buffer must be 32 bytes aligned.");
ASSERTMSGLINE(415, !(length & 0x1F), "Buffer length must be multiples of 32 bytes.");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
return nandConvertErrorCode(ISFS_Read(info->fileDescriptor, (u8*)buf, length));
}
s32 NANDReadAsync(NANDFileInfo* info, void* buf, const u32 length, NANDCallback cb, NANDCommandBlock* block) {
ASSERTMSGLINE(428, info, "*info is NULL pointer!");
ASSERTMSGLINE(429, buf, "*buf is NULL pointer!");
ASSERTMSGLINE(430, !((u32)buf & 0x1F), "Buffer must be 32 bytes aligned.");
ASSERTMSGLINE(431, !(length & 0x1F), "Buffer length must be multiples of 32 bytes.");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
block->callback = cb;
return nandConvertErrorCode(ISFS_ReadAsync(info->fileDescriptor, (u8*)buf, length, nandCallback, block));
}
s32 NANDWrite(NANDFileInfo* info, const void* buf, const u32 length) {
ASSERTMSGLINE(448, info, "*info is NULL pointer!");
ASSERTMSGLINE(449, buf, "*buf is NULL pointer!");
ASSERTMSGLINE(450, !((u32)buf & 0x1F), "Buffer must be 32 bytes aligned.");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
return nandConvertErrorCode(ISFS_Write(info->fileDescriptor, (const u8*)buf, length));
}
s32 NANDWriteAsync(NANDFileInfo* info, const void* buf, const u32 length,
NANDCallback cb, NANDCommandBlock* block) {
ASSERTMSGLINE(463, info, "*info is NULL pointer!");
ASSERTMSGLINE(464, buf, "*buf is NULL pointer!");
ASSERTMSGLINE(465, !((u32)buf & 0x1F), "Buffer must be 32 bytes aligned.");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
block->callback = cb;
return nandConvertErrorCode(ISFS_WriteAsync(info->fileDescriptor, (const u8*)buf, length, nandCallback, block));
}
static ISFSError nandSeek(const IOSFd fd, const s32 offset, const s32 whence,
NANDCommandBlock* block, const BOOL async_flag) {
u32 w = 0xFFFFFFFF;
switch (whence) {
case 0:
w = 0;
break;
case 1:
w = 1;
break;
case 2:
w = 2;
break;
default:
break;
}
if (async_flag) {
return ISFS_SeekAsync(fd, offset, w, nandCallback, block);
} else {
return ISFS_Seek(fd, offset, w);
}
}
s32 NANDSeek(NANDFileInfo* info, const s32 offset, const s32 whence) {
ASSERTMSGLINE(513, info, "*info is NULL pointer!");
ASSERTMSGLINE(514, whence == 0 || whence == 1 || whence == 2, "Illegal whence parameter.");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
return nandConvertErrorCode(nandSeek(info->fileDescriptor, offset, whence, NULL, FALSE));
}
s32 NANDSeekAsync(NANDFileInfo* info, const s32 offset, const s32 whence,
NANDCallback cb, NANDCommandBlock* block) {
ASSERTMSGLINE(527, info, "*info is NULL pointer!");
ASSERTMSGLINE(528, whence == 0 || whence == 1 || whence == 2, "Illegal whence parameter.");
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
block->callback = cb;
return nandConvertErrorCode(nandSeek(info->fileDescriptor, offset, whence, block, TRUE));
}
ISFSError nandCreateDir(const char* path, const u8 perm, const u8 attr,
NANDCommandBlock* block, const BOOL async_flag,
const BOOL privilege_flag) {
char absPath[64] = "";
if (!nandCheckPathName(path)) {
return ISFS_ERROR_INVALID;
}
nandGenerateAbsPath(absPath, path);
if (!privilege_flag && nandIsPrivatePath(absPath)) {
return ISFS_ERROR_ACCESS;
} else if (!nandInspectPermission(perm)) {
return ISFS_ERROR_INVALID;
} else {
u32 owner = 0;
u32 group = 0;
u32 others = 0;
nandSplitPerm(perm, &owner, &group, &others);
if (async_flag) {
return ISFS_CreateDirAsync((const u8*)absPath, attr, owner, group, others, nandCallback, block);
} else {
return ISFS_CreateDir((const u8*)absPath, attr, owner, group, others);
}
}
}
s32 NANDPrivateCreateDir(const char* path, u8 perm, u8 attr) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
return nandConvertErrorCode(nandCreateDir(path, perm, attr, NULL, FALSE, TRUE));
}
s32 NANDPrivateCreateDirAsync(const char* path, u8 perm, u8 attr,
NANDCallback cb, NANDCommandBlock* block) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
block->callback = cb;
return nandConvertErrorCode(nandCreateDir(path, perm, attr, block, TRUE, TRUE));
}
ISFSError nandMove(const char* path, const char* destDir,
NANDCommandBlock* block, const BOOL async_flag,
const BOOL privilege_flag) {
char absOldPath[64] = "";
char absNewPath[64] = "";
char relativeName[13] = "";
nandGenerateAbsPath(absOldPath, path);
nandGetRelativeName(relativeName, absOldPath);
nandGenerateAbsPath(absNewPath, destDir);
if (strcmp(absNewPath, "/") == 0) {
sprintf(absNewPath, "/%s", relativeName);
} else {
strcat(absNewPath, "/");
strcat(absNewPath, relativeName);
}
if (!privilege_flag && (nandIsPrivatePath(absOldPath) || nandIsPrivatePath(absNewPath))) {
return ISFS_ERROR_ACCESS;
} else {
if (async_flag) {
return ISFS_RenameAsync((const u8*)absOldPath, (const u8*)absNewPath, nandCallback, block);
} else {
return ISFS_Rename((const u8*)absOldPath, (const u8*)absNewPath);
}
}
}
s32 NANDMove(const char* path, const char* destDir) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
return nandConvertErrorCode(nandMove(path, destDir, NULL, FALSE, FALSE));
}
static ISFSError nandGetFileStatus(IOSFd fd, u32* length, u32* pos) {
ISFSFileStats fstat ATTRIBUTE_ALIGN(32);
ISFSError result = ISFS_GetFileStats(fd, &fstat);
if (result == ISFS_ERROR_OK) {
if (length) {
*length = fstat.size;
}
if (pos) {
*pos = fstat.offset;
}
}
return result;
}
s32 NANDGetLength(NANDFileInfo* info, u32* length) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
return nandConvertErrorCode(nandGetFileStatus(info->fileDescriptor, length, NULL));
}
void nandGetFileStatusAsyncCallback(ISFSError result, void* ctxt) {
NANDCommandBlock* b = (NANDCommandBlock*)ctxt;
ISFSFileStats* fstat = (ISFSFileStats*)OSRoundUp32B((u32)(b->absPath));
if (result == ISFS_ERROR_OK) {
if (b->length) {
*(b->length) = fstat->size;
}
if (b->pos) {
*(b->pos) = fstat->offset;
}
}
((NANDCallback)(b->callback))(nandConvertErrorCode(result), b);
}
static ISFSError nandGetFileStatusAsync(IOSFd fd, NANDCommandBlock* block) {
ISFSError result = ISFS_ERROR_UNKNOWN;
ISFSFileStats* fstat = (ISFSFileStats*)OSRoundUp32B((u32)(block->absPath));
return ISFS_GetFileStatsAsync(fd, fstat, nandGetFileStatusAsyncCallback, block);
}
s32 NANDGetLengthAsync(NANDFileInfo* info, u32* length, NANDCallback cb, NANDCommandBlock* block) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
block->callback = cb;
block->length = length;
block->pos = NULL;
return nandConvertErrorCode(nandGetFileStatusAsync(info->fileDescriptor, block));
}
void dummyStrings() {
OSReport("NULL pointer is detected.\n");
OSReport("NAND library internal error: bytes value must be illegal.");
OSReport("NAND library internal error: inodes value must be illegal.");
OSReport("NAND library internal error: length value must be illegal.");
OSReport("NULL pointer detected.");
}
void nandComposePerm(u8* perm, const u32 ownerAcc, const u32 groupAcc, const u32 othersAcc) {
u32 p = 0;
if (ownerAcc & 1) {
p = p | 0x10;
}
if (ownerAcc & 2) {
p = p | 0x20;
}
if (groupAcc & 1) {
p = p | 4;
}
if (groupAcc & 2) {
p = p | 8;
}
if (othersAcc & 1) {
p = p | 1;
}
if (othersAcc & 2) {
p = p | 2;
}
ASSERTMSGLINE(1007, (p & ~0xFF) == 0, "NAND library internal error.\n");
*perm = (u8)p;
}
static void nandSplitPerm(u8 perm, u32* ownerAcc, u32* groupAcc, u32* othersAcc) {
*ownerAcc = 0;
*groupAcc = 0;
*othersAcc = 0;
if (perm & 0x10) {
*ownerAcc = *ownerAcc | 1;
}
if (perm & 0x20) {
*ownerAcc = *ownerAcc | 2;
}
if (perm & 4) {
*groupAcc = *groupAcc | 1;
}
if (perm & 8) {
*groupAcc = *groupAcc | 2;
}
if (perm & 1) {
*othersAcc = *othersAcc | 1;
}
if (perm & 2) {
*othersAcc = *othersAcc | 2;
}
}
ISFSError nandGetStatus(const char* path, NANDStatus* stat,
NANDCommandBlock* block, const BOOL async_flag,
const BOOL privilege_flag) {
char absPath[64] = "";
ASSERTMSGLINE(1052, path, "NULL pointer detected.");
ASSERTMSGLINE(1053, stat, "NULL pointer detected.");
nandGenerateAbsPath(absPath, path);
if (!privilege_flag && nandIsUnderPrivatePath(absPath)) {
return ISFS_ERROR_ACCESS;
} else {
if (async_flag) {
return ISFS_GetAttrAsync(
(const u8*)absPath, &(stat->ownerId), &(stat->groupId),
&(block->attr), &(block->ownerAcc), &(block->groupAcc),
&(block->othersAcc), nandGetStatusCallback, block);
} else {
u32 attr = 0, ownerAcc = 0, groupAcc = 0, othersAcc = 0;
ISFSError result =
ISFS_GetAttr((const u8*)absPath, &stat->ownerId, &stat->groupId,
&attr, &ownerAcc, &groupAcc, &othersAcc);
if (result == ISFS_ERROR_OK) {
nandComposePerm(&stat->permission, ownerAcc, groupAcc, othersAcc);
stat->attribute = (u8)attr;
}
return result;
}
}
}
void nandGetStatusCallback(ISFSError result, void* ctxt) {
NANDCommandBlock* b = (NANDCommandBlock*)ctxt;
if (result == ISFS_ERROR_OK) {
NANDStatus* stat = (NANDStatus*)(b->status);
stat->attribute = (u8)(b->attr);
nandComposePerm(&(stat->permission), b->ownerAcc, b->groupAcc,
b->othersAcc);
}
((NANDCallback)(b->callback))(nandConvertErrorCode(result), b);
}
s32 NANDGetStatus(const char* path, NANDStatus* stat) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
return nandConvertErrorCode(nandGetStatus(path, stat, NULL, FALSE, FALSE));
}
s32 NANDPrivateGetStatus(const char* path, NANDStatus* stat) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
return nandConvertErrorCode(nandGetStatus(path, stat, NULL, FALSE, TRUE));
}
s32 NANDPrivateGetStatusAsync(const char* path, NANDStatus* stat,
NANDCallback cb, NANDCommandBlock* block) {
if (!nandIsInitialized()) {
return NAND_RESULT_FATAL_ERROR;
}
block->callback = cb;
block->status = stat;
return nandConvertErrorCode(nandGetStatus(path, stat, block, TRUE, TRUE));
}
void NANDSetUserData(NANDCommandBlock* block, void* data) {
block->userData = data;
}
void* NANDGetUserData(const NANDCommandBlock* block) {
return block->userData;
}
static BOOL nandInspectPermission(const u8 perm) {
if (perm & 0x10) {
return TRUE;
} else {
return FALSE;
}
}
BOOL nandCheckPathName(const char* path) {
char absNewPath[64];
char relativeName[13];
int len = -1;
ASSERTMSGLINE(1266, path, "null pointer is detected in argument of path\n");
len = strlen(path);
if (len == 0) {
return 0;
} else {
u32 i;
if (nandIsRelativePath(path)) {
for (i = 0; i < len; i++) {
if (!nandCheckCharacter(path[i])) {
return 0;
}
}
} else {
strcpy(absNewPath, path);
if (absNewPath[len - 1] == '/' && len - 1 != 0) {
absNewPath[len - 1] = 0;
}
nandGetRelativeName(relativeName, absNewPath);
len = strlen(relativeName);
for (i = 0; i < len; i++) {
if (!nandCheckCharacter(relativeName[i])) {
return 0;
}
}
}
}
return 1;
}
BOOL nandCheckCharacter(char character) {
u32 i;
const char legal_characters[66] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_./";
for (i = 0; i < sizeof(legal_characters); i++) {
if (character == legal_characters[i]) {
return TRUE;
}
}
return FALSE;
}
void dummyStrings2() {
OSReport("/tmp/count_tmpdir");
OSReport("countfile");
OSReport("*number is NULL pointer!");
OSReport("*cleaning is NULL pointer!");
OSReport("NAND library internal error: free_inodes value must be illegal.");
OSReport("%s/%s_%.2d");
OSReport("count_tmp.count must be less than ISFS_FD_ENTRIES.!");
}

View File

@ -4,16 +4,17 @@
#include <revolution/si.h>
#include <revolution/db.h>
#include <revolution/sc.h>
#include <revolution/ipc.h>
#include "__os.h"
#include "__dvd.h"
#include <string.h>
#define NOP 0x60000000
// external functions
extern void EnableMetroTRKInterrupts(void);
extern void __OSInitMemoryProtection(void);
extern void IPCCltInit(void);
extern BOOL __DVDCheckDevice(void);
#define DB_EXCEPTIONRET_OFFSET 0xC
#define DB_EXCEPTIONDEST_OFFSET 0x8

View File

@ -16,7 +16,7 @@ static void DecrementerExceptionCallback(__REGISTER __OSException exception, __R
static void DecrementerExceptionHandler(__OSException exception, OSContext* context);
static BOOL OnReset(BOOL final, u32 event);
static OSShutdownFunctionInfo ResetFunctionInfo = {OnReset, 0xFFFFFFFF, NULL, NULL};
static OSShutdownFunctionInfo ShutdownFunctionInfo = {OnReset, 0xFFFFFFFF, NULL, NULL};
static OSAlarmQueue AlarmQueue;
#define ASSERTREPORT(line, cond) \
@ -52,7 +52,7 @@ void __OSInitAlarm(void) {
if (__OSGetExceptionHandler(8) != DecrementerExceptionHandler) {
AlarmQueue.head = AlarmQueue.tail = NULL;
__OSSetExceptionHandler(8, DecrementerExceptionHandler);
OSRegisterShutdownFunction(&ResetFunctionInfo);
OSRegisterShutdownFunction(&ShutdownFunctionInfo);
}
}

View File

@ -1,6 +1,8 @@
#include <revolution.h>
#include <revolution/os.h>
#include <string.h>
#include "__os.h"
// prototypes

View File

@ -1,13 +1,14 @@
#include <revolution.h>
#include <revolution/os.h>
#include <revolution/esp.h>
#include <revolution/ipc.h>
#include <string.h>
#include "__os.h"
#include "__dvd.h"
// extern
extern size_t wcslen(const wchar_t *);
extern int __DVDLayoutFormat;
extern volatile u32 BOOT_REGION_START AT_ADDRESS(0x812FDFF0);
extern volatile u32 BOOT_REGION_END AT_ADDRESS(0x812FDFEC);

View File

@ -1,5 +1,6 @@
#include <revolution.h>
#include <revolution/os.h>
#include <string.h>
#include "__os.h"

View File

@ -1,5 +1,6 @@
#include <revolution.h>
#include <revolution/os.h>
#include <string.h>
#include "__os.h"

View File

@ -1,5 +1,6 @@
#include <revolution.h>
#include <revolution/os.h>
#include <string.h>
#include "__os.h"

View File

@ -1,6 +1,8 @@
#include <revolution/os.h>
#include <revolution/sc.h>
#include <revolution/private/iosresclt.h>
#include <revolution/ipc.h>
#include "__os.h"
static OSShutdownFunctionInfo ShutdownFuncInfo;
@ -8,21 +10,6 @@ static IOSFd nwc24ShtFd = -1;
static int nwc24ShtRetryRest = 0;
static BOOL NWC24iIsRequestPending = FALSE;
typedef enum NWC24Err {
NWC24_OK = 0,
} NWC24Err;
NWC24Err NWC24iPrepareShutdown(void);
NWC24Err NWC24iSynchronizeRtcCounter(BOOL);
NWC24Err NWC24iOpenResourceManager_(const char* callerName, const char* path, IOSFd* fd, u32 flags);
NWC24Err NWC24SuspendScheduler(void);
NWC24Err NWC24iSetRtcCounter_(int rtc, BOOL);
NWC24Err NWC24iIoctlResourceManager_(const char* callerName, IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen);
NWC24Err NWC24iCloseResourceManager_(const char* callerName, IOSFd);
NWC24Err NWC24iRequestShutdown(u32 event, s32* result);
NWC24Err NWC24iIoctlResourceManagerAsync_(const char* callerName, IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen, void* cbArg);
BOOL NWC24iIsAsyncRequestPending_(void);
BOOL NWC24Shutdown_(BOOL, u32);
static void REXInit(void);

View File

@ -2,6 +2,10 @@
#include <revolution/os.h>
#include <revolution/esp.h>
#include <revolution/nand.h>
#include <revolution/vi.h>
#include <string.h>
#include "__os.h"
OSAlarm __OSExpireAlarm;
OSTime __OSExpireTime;

View File

@ -1,6 +1,8 @@
#include <revolution.h>
#include <revolution/os.h>
#include <revolution/os/OSPlayRecord.h>
#include <revolution/sc.h>
#include <string.h>
#include "__os.h"
#include "__dvd.h"

View File

@ -1,6 +1,6 @@
#include <revolution/os.h>
#include <revolution/nand.h>
#include <stdio.h>
#include <string.h>
static OSStateFlags StateFlags ATTRIBUTE_ALIGN(32);

View File

@ -1,6 +1,7 @@
#include <revolution/os.h>
#include <revolution/os/OSResetSW.h>
#include <revolution/vi.h>
#include <revolution/ipc.h>
#include <revolution/private/iosrestypes.h>
@ -29,6 +30,7 @@ static void __OSDefaultResetCallback(void);
static void __OSDefaultPowerCallback(void);
static void __OSRegisterStateEvent(void);
static int AccessVIDimRegs(void);
static void LockUp(void);
OSPowerCallback OSSetPowerCallback(OSPowerCallback callback) {

View File

@ -1,5 +1,6 @@
#include <revolution.h>
#include <revolution/os.h>
#include <string.h>
#include "__os.h"

View File

@ -542,7 +542,7 @@ void OSCancelThread(OSThread* thread) {
int OSJoinThread(OSThread* thread, void* val) {
BOOL enabled = OSDisableInterrupts();
ASSERTMSG1LINE(LINE(1061, 1092, 1092), __OSIsThreadActive(thread) != 0, "OSJoinThread(): thread %p is not active.", thread);
ASSERTMSG1LINE(1061, __OSIsThreadActive(thread) != 0, "OSJoinThread(): thread %p is not active.", thread);
if (!(thread->attr & 1) && (thread->state != OS_THREAD_STATE_MORIBUND) && (thread->queueJoin.head == NULL)) {
OSSleepThread(&thread->queueJoin);
@ -851,7 +851,7 @@ void OSSetThreadSpecific(s32 index, void* ptr) {
OSThread* thread;
thread = __OSCurrentThread;
ASSERTLINE(LINE(1573, 1604, 1604), 0 <= index && index < OS_THREAD_SPECIFIC_MAX);
ASSERTLINE(1573, 0 <= index && index < OS_THREAD_SPECIFIC_MAX);
if (thread != 0 && index >= 0 && index < OS_THREAD_SPECIFIC_MAX) {
thread->specific[index] = ptr;
@ -862,7 +862,7 @@ void* OSGetThreadSpecific(s32 index) {
OSThread* thread;
thread = __OSCurrentThread;
ASSERTLINE(LINE(1584, 1615, 1615), 0 <= index && index < OS_THREAD_SPECIFIC_MAX);
ASSERTLINE(1584, 0 <= index && index < OS_THREAD_SPECIFIC_MAX);
if (thread != 0 && index >= 0 && index < OS_THREAD_SPECIFIC_MAX) {
return thread->specific[index];

View File

@ -13,11 +13,7 @@ extern char* __OSExceptionNames[17]; // D ONLY
u32 __OSIsDebuggerPresent(void);
void __OSPSInit(void);
void __OSInitIPCBuffer(void);
void __OSInitSTM(void);
void __OSInitNet(void);
void __OSInitPlayTime(void);
void __OSStartPlayRecord(void);
void __OSGetIOSRev(OSIOSRev* rev);
// OSAlarm
void __OSInitAlarm(void);
@ -44,6 +40,7 @@ void __OSGetExecParams(OSExecParams* params);
void __OSSetExecParams(const OSExecParams* params, OSExecParams* addr);
void __OSBootDolSimple(u32 doloffset, u32 restartCode, void* regionStart, void* regionEnd, BOOL argsUseDefault, s32 argc, char** argv);
void __OSBootDol(u32 doloffset, u32 restartCode, const char** argv);
void __OSLaunchMenu();
extern u32 __OSNextPartitionType;
// OSInterrupt
@ -62,25 +59,37 @@ OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask global);
void __OSDispatchInterrupt(__OSException exception, OSContext* context);
void __OSModuleInit(void);
// OSIpc
void __OSInitIPCBuffer(void);
// OSLaunch
void __OSRelaunchTitle(u32 resetCode);
// OSMemory
void __OSInitMemoryProtection(void);
void __OSRestoreCodeExecOnMEM1(u32 param_0);
// OSMutex
void __OSUnlockAllMutex(OSThread* thread);
int __OSCheckDeadLock(OSThread* thread);
int __OSCheckMutexes(OSThread* thread);
// OSNet
void __OSInitNet(void);
// OSPlayTime
void __OSGetPlayTime(ESTicketView* ticket, __OSPlayTimeType* type, u32* playTime);
void __OSInitPlayTime(void);
s32 __OSGetPlayTime(ESTicketView* ticket, __OSPlayTimeType* type, u32* playTime);
BOOL __OSWriteExpiredFlagIfSet(void);
// OSPlayRecord
void __OSStartPlayRecord(void);
// OSReset
void __OSDoHotReset(u32 resetCode);
void __OSShutdownDevices(u32 event);
int __OSCallShutdownFunctions(BOOL final, u32 event);
// OSResetSW
void __OSResetSWInterruptHandler(s16 exception, OSContext* context);
void __OSSetResetButtonTimer(u8 min);
void __OSReturnToMenuForError(void);
void __OSHotResetForError(void);
// OSRtc
int __OSGetRTC(u32* rtc);
@ -96,6 +105,8 @@ int __OSReadROM(void* buffer, s32 length, s32 offset);
int __OSReadROMAsync(void* buffer, s32 length, s32 offset, void (*callback)());
u8 __OSGetBootMode(void);
void __OSSetBootMode(u8 ntd);
BOOL __OSGetRTCFlags(u32* flags);
BOOL __OSClearRTCFlags(void);
// OSSync
extern void __OSSystemCallVectorStart();
@ -103,6 +114,14 @@ extern void __OSSystemCallVectorEnd();
void __OSInitSystemCall(void);
// OSStateTM
void __OSInitSTM(void);
BOOL __OSWriteExpiredFlag(void);
int __OSSetVIForceDimming(BOOL isEnabled, u32 yShift, u32 xShift);
s32 __OSUnRegisterStateEvent(void);
void __OSShutdownToSBY(void);
void __OSHotReset(void);
// OSThread
void __OSThreadInit(void);
s32 __OSGetEffectivePriority(OSThread* thread);
@ -137,12 +156,6 @@ OSTime __get_clock(void);
u32 __get_time(void);
int __to_gm_time(void);
// unsorted
void __OSWriteExpiredFlag(void);
void __OSReturnToMenuForError(void);
void __OSHotResetForError(void);
#ifdef __cplusplus
}
#endif

894
src/revolution/pad/Pad.c Normal file
View File

@ -0,0 +1,894 @@
#include <revolution.h>
#include <revolution/pad.h>
#include <revolution/si.h>
#include <string.h>
#include "__si.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#ifdef SDK_AUG2010
#define BUILD_DATE "Aug 23 2010"
#if DEBUG
#define BUILD_TIME "17:27:55"
#else
#define BUILD_TIME "17:33:06"
#endif
#elif SDK_SEP2006
#define BUILD_DATE "Sep 21 2006"
#define BUILD_TIME "14:32:13"
#endif
#ifdef SDK_AUG2010
#if DEBUG
const char* __PADVersion = "<< RVL_SDK - PAD \tdebug build: "BUILD_DATE" "BUILD_TIME" (0x4302_145) >>";
#else
const char* __PADVersion = "<< RVL_SDK - PAD \trelease build: "BUILD_DATE" "BUILD_TIME" (0x4302_145) >>";
#endif
#elif SDK_SEP2006
const char* __PADVersion = "<< RVL_SDK - PAD \trelease build: "BUILD_DATE" "BUILD_TIME" (0x4200_60422) >>";
#endif
#define PAD_ALL \
( \
PAD_BUTTON_LEFT | \
PAD_BUTTON_RIGHT | \
PAD_BUTTON_DOWN | \
PAD_BUTTON_UP | \
PAD_TRIGGER_Z | \
PAD_TRIGGER_R | \
PAD_TRIGGER_L | \
PAD_BUTTON_A | \
PAD_BUTTON_B | \
PAD_BUTTON_X | \
PAD_BUTTON_Y | \
PAD_BUTTON_MENU | \
0x2000 | \
0x0080 \
)
static s32 ResettingChan = 0x20;
static u32 XPatchBits = PAD_CHAN0_BIT | PAD_CHAN1_BIT | PAD_CHAN2_BIT | PAD_CHAN3_BIT;
static u32 AnalogMode = 0x300;
static u32 Spec = PAD_SPEC_5;
static BOOL Initialized;
static u32 EnabledBits;
static u32 ResettingBits;
static u32 RecalibrateBits;
static u32 WaitingBits;
static u32 CheckingBits;
static u32 PendingBits;
static u32 BarrelBits;
static u32 Type[4];
static PADStatus Origin[4];
u32 __PADSpec;
// prototypes
static void PADTypeAndStatusCallback(s32 chan, u32 type);
static u16 GetWirelessID(s32 chan);
static void SetWirelessID(s32 chan, u16 id);
static void DoReset();
static void PADEnable(s32 chan);
static void ProbeWireless(s32 chan);
static void PADProbeCallback(s32 chan, u32 error, OSContext *context);
static void PADDisable(s32 chan);
static void UpdateOrigin(s32 chan);
static void PADOriginCallback(s32 chan, u32 error, OSContext *context);
static void PADFixCallback(s32 unused, u32 error, struct OSContext *context);
static void PADResetCallback(s32 unused, u32 error, struct OSContext *context);
static void PADReceiveCheckCallback(s32 chan, u32 error);
static void SPEC0_MakeStatus(s32 chan, PADStatus *status, u32 data[2]);
static void SPEC1_MakeStatus(s32 chan, PADStatus *status, u32 data[2]);
static s8 ClampS8(s8 var, s8 org);
static u8 ClampU8(u8 var, u8 org);
static void SPEC2_MakeStatus(s32 chan, PADStatus *status, u32 data[2]);
static BOOL OnShutdown(BOOL f, u32);
void __PADDisableXPatch(void);
BOOL __PADDisableRumble(BOOL disable);
typedef void (*SPECCallback)(s32, PADStatus*, u32*);
static SPECCallback MakeStatus = SPEC2_MakeStatus;
static u32 CmdTypeAndStatus;
static u32 CmdReadOrigin = 0x41000000;
static u32 CmdCalibrate = 0x42000000;
static u32 CmdProbeDevice[4];
static OSShutdownFunctionInfo ShutdownFunctionInfo = {
OnShutdown,
127,
NULL,
NULL,
};
static void PADEnable(s32 chan) {
u32 cmd;
u32 chanBit;
u32 data[2];
chanBit = PAD_CHAN0_BIT >> chan;
EnabledBits |= chanBit;
SIGetResponse(chan, &data);
cmd = (AnalogMode | 0x400000);
SISetCommand(chan, cmd);
SIEnablePolling(EnabledBits);
}
static void PADDisable(s32 chan) {
BOOL enabled;
u32 chanBit;
enabled = OSDisableInterrupts();
chanBit = PAD_CHAN0_BIT >> chan;
SIDisablePolling(chanBit);
EnabledBits &= ~chanBit;
WaitingBits &= ~chanBit;
CheckingBits &= ~chanBit;
PendingBits &= ~chanBit;
BarrelBits &= ~chanBit;
OSSetWirelessID(chan, 0);
OSRestoreInterrupts(enabled);
}
static void DoReset() {
u32 chanBit;
ResettingChan = __cntlzw(ResettingBits);
if (ResettingChan != 32) {
ASSERTLINE(589, 0 <= ResettingChan && ResettingChan < SI_MAX_CHAN);
chanBit = (PAD_CHAN0_BIT >> ResettingChan);
ResettingBits &= ~chanBit;
memset(&Origin[ResettingChan], 0, sizeof(PADStatus));
SIGetTypeAsync(ResettingChan, PADTypeAndStatusCallback);
}
}
static void UpdateOrigin(s32 chan) {
PADStatus* origin;
u32 chanBit = PAD_CHAN0_BIT >> chan;
origin = &Origin[chan];
switch (AnalogMode & 0x00000700u) {
case 0x00000000u:
case 0x00000500u:
case 0x00000600u:
case 0x00000700u:
origin->triggerLeft &= ~15;
origin->triggerRight &= ~15;
origin->analogA &= ~15;
origin->analogB &= ~15;
break;
case 0x00000100u:
origin->substickX &= ~15;
origin->substickY &= ~15;
origin->analogA &= ~15;
origin->analogB &= ~15;
break;
case 0x00000200u:
origin->substickX &= ~15;
origin->substickY &= ~15;
origin->triggerLeft &= ~15;
origin->triggerRight &= ~15;
break;
case 0x00000300u: break;
case 0x00000400u: break;
}
origin->stickX -= 128;
origin->stickY -= 128;
origin->substickX -= 128;
origin->substickY -= 128;
if (XPatchBits & chanBit) {
if (64 < origin->stickX && (SIGetType(chan) & 0xFFFF0000) == SI_GC_CONTROLLER) {
origin->stickX = 0;
}
}
}
static void PADOriginCallback(s32 chan, u32 error, OSContext* context) {
ASSERTLINE(671, 0 <= ResettingChan && ResettingChan < SI_MAX_CHAN);
ASSERTLINE(672, chan == ResettingChan);
if (!(error & (SI_ERROR_UNDER_RUN | SI_ERROR_OVER_RUN | SI_ERROR_NO_RESPONSE | SI_ERROR_COLLISION)))
{
UpdateOrigin(ResettingChan);
PADEnable(ResettingChan);
}
DoReset();
}
static void PADOriginUpdateCallback(s32 chan, u32 error, OSContext* context) {
ASSERTLINE(701, 0 <= chan && chan < SI_MAX_CHAN);
if (!(EnabledBits & (PAD_CHAN0_BIT >> chan)))
return;
if (!(error & (SI_ERROR_UNDER_RUN | SI_ERROR_OVER_RUN | SI_ERROR_NO_RESPONSE | SI_ERROR_COLLISION)))
UpdateOrigin(chan);
if (error & SI_ERROR_NO_RESPONSE) {
PADDisable(chan);
}
}
static void PADProbeCallback(s32 chan, u32 error, OSContext* context) {
u32 type;
ASSERTLINE(740, 0 <= ResettingChan && ResettingChan < SI_MAX_CHAN);
ASSERTLINE(741, chan == ResettingChan);
ASSERTLINE(743, (Type[chan] & SI_WIRELESS_CONT_MASK) == SI_WIRELESS_CONT && !(Type[chan] & SI_WIRELESS_LITE));
if (!(error & (SI_ERROR_UNDER_RUN | SI_ERROR_OVER_RUN | SI_ERROR_NO_RESPONSE | SI_ERROR_COLLISION)))
{
PADEnable(ResettingChan);
WaitingBits |= PAD_CHAN0_BIT >> ResettingChan;
}
DoReset();
}
static void PADTypeAndStatusCallback(s32 chan, u32 type) {
u32 chanBit;
u32 recalibrate;
BOOL rc = TRUE;
u32 error;
ASSERTLINE(776, 0 <= ResettingChan && ResettingChan < SI_MAX_CHAN);
ASSERTLINE(777, chan == ResettingChan);
chanBit = PAD_CHAN0_BIT >> ResettingChan;
error = type & 0xFF;
ASSERTLINE(786, !(error & SI_ERROR_BUSY));
recalibrate = RecalibrateBits & chanBit;
RecalibrateBits &= ~chanBit;
if (error & (SI_ERROR_UNDER_RUN | SI_ERROR_OVER_RUN | SI_ERROR_NO_RESPONSE | SI_ERROR_COLLISION))
{
DoReset();
return;
}
type &= ~0xFF;
Type[ResettingChan] = type;
if ((type & SI_TYPE_MASK) != SI_TYPE_GC || !(type & SI_GC_STANDARD)) {
DoReset();
return;
}
if (Spec < PAD_SPEC_2) {
PADEnable(ResettingChan);
DoReset();
return;
}
if (!(type & SI_GC_WIRELESS) || (type & SI_WIRELESS_IR)) {
if (recalibrate) {
rc = SITransfer(ResettingChan, &CmdCalibrate, 3, &Origin[ResettingChan], 10,
PADOriginCallback, 0);
} else {
rc = SITransfer(ResettingChan, &CmdReadOrigin, 1, &Origin[ResettingChan], 10,
PADOriginCallback, 0);
}
} else if ((type & SI_WIRELESS_FIX_ID) && (type & SI_WIRELESS_CONT_MASK) == SI_WIRELESS_CONT &&
!(type & SI_WIRELESS_LITE))
{
if (type & SI_WIRELESS_RECEIVED) {
rc = SITransfer(ResettingChan, &CmdReadOrigin, 1, &Origin[ResettingChan], 10,
PADOriginCallback, 0);
} else {
rc = SITransfer(ResettingChan, &CmdProbeDevice[ResettingChan], 3,
&Origin[ResettingChan], 8, PADProbeCallback, 0);
}
}
if (!rc) {
PendingBits |= chanBit;
DoReset();
return;
}
}
static void PADReceiveCheckCallback(s32 chan, u32 type) {
u32 error;
u32 chanBit;
chanBit = PAD_CHAN0_BIT >> chan;
if (EnabledBits & chanBit) {
error = type & 0xFF;
type &= ~0xFF;
WaitingBits &= ~chanBit;
CheckingBits &= ~chanBit;
if (!(error &
(SI_ERROR_UNDER_RUN | SI_ERROR_OVER_RUN | SI_ERROR_NO_RESPONSE | SI_ERROR_COLLISION)) &&
(type & SI_GC_WIRELESS) && (type & SI_WIRELESS_FIX_ID) && (type & SI_WIRELESS_RECEIVED) &&
!(type & SI_WIRELESS_IR) && (type & SI_WIRELESS_CONT_MASK) == SI_WIRELESS_CONT &&
!(type & SI_WIRELESS_LITE))
{
SITransfer(chan, &CmdReadOrigin, 1, &Origin[chan], 10, PADOriginUpdateCallback, 0);
} else {
PADDisable(chan);
}
}
}
int PADReset(u32 mask) {
BOOL enabled;
u32 disableBits;
ASSERTMSGLINE(927, !(mask & 0x0FFFFFFF), "PADReset(): invalid mask");
enabled = OSDisableInterrupts();
mask |= PendingBits;
PendingBits = 0;
mask &= ~(WaitingBits | CheckingBits);
ResettingBits |= mask;
disableBits = ResettingBits & EnabledBits;
EnabledBits &= ~mask;
BarrelBits &= ~mask;
if (Spec == 4) {
RecalibrateBits |= mask;
}
SIDisablePolling(disableBits);
if (ResettingChan == 0x20) {
DoReset();
}
OSRestoreInterrupts(enabled);
return 1;
}
BOOL PADRecalibrate(u32 mask) {
BOOL enabled;
u32 disableBits;
ASSERTMSGLINE(969, !(mask & 0x0FFFFFFF), "PADReset(): invalid mask");
enabled = OSDisableInterrupts();
mask |= PendingBits;
PendingBits = 0;
mask &= ~(WaitingBits | CheckingBits);
ResettingBits |= mask;
disableBits = ResettingBits & EnabledBits;
EnabledBits &= ~mask;
BarrelBits &= ~mask;
if (!(__gUnknown800030E3 & 0x40)) {
RecalibrateBits |= mask;
}
SIDisablePolling(disableBits);
if (ResettingChan == 32)
DoReset();
OSRestoreInterrupts(enabled);
return 1;
}
BOOL PADInit() {
s32 chan;
if (Initialized) {
return 1;
}
OSRegisterVersion(__PADVersion);
if (__PADSpec)
PADSetSpec(__PADSpec);
Initialized = TRUE;
if (__PADFixBits != 0) {
OSTime time = OSGetTime();
__OSWirelessPadFixMode
= (u16)((((time)&0xffff) + ((time >> 16) & 0xffff) + ((time >> 32) & 0xffff) + ((time >> 48) & 0xffff))
& 0x3fffu);
RecalibrateBits = PAD_CHAN0_BIT | PAD_CHAN1_BIT | PAD_CHAN2_BIT | PAD_CHAN3_BIT;
}
for (chan = 0; chan < SI_MAX_CHAN; ++chan) {
CmdProbeDevice[chan] = (0x4D << 24) | (chan << 22) | ((__OSWirelessPadFixMode & 0x3fffu) << 8);
}
SIRefreshSamplingRate();
OSRegisterShutdownFunction(&ShutdownFunctionInfo);
return PADReset(PAD_CHAN0_BIT | PAD_CHAN1_BIT | PAD_CHAN2_BIT | PAD_CHAN3_BIT);
}
u32 PADRead(PADStatus* status) {
BOOL enabled;
s32 chan;
u32 data[2];
u32 chanBit;
u32 sr;
int chanShift;
u32 motor;
static PADStatus pre_status[4];
int threshold;
threshold = 3;
enabled = OSDisableInterrupts();
motor = 0;
for (chan = 0; chan < 4; chan++, status++) {
chanBit = PAD_CHAN0_BIT >> chan;
chanShift = 8 * (SI_MAX_CHAN - 1 - chan);
if (PendingBits & chanBit) {
PADReset(0);
status->err = PAD_ERR_NOT_READY;
memset(status, 0, offsetof(PADStatus, err));
} else if ((ResettingBits & chanBit) || ResettingChan == chan) {
status->err = PAD_ERR_NOT_READY;
memset(status, 0, offsetof(PADStatus, err));
} else if (!(EnabledBits & chanBit)) {
status->err = PAD_ERR_NO_CONTROLLER;
memset(status, 0, offsetof(PADStatus, err));
} else if (SIIsChanBusy(chan)) {
status->err = PAD_ERR_TRANSFER;
memset(status, 0, offsetof(PADStatus, err));
} else {
sr = SIGetStatus(chan);
if (sr & SI_ERROR_NO_RESPONSE) {
SIGetResponse(chan, data);
if (WaitingBits & chanBit) {
status->err = PAD_ERR_NONE;
memset(status, 0, offsetof(PADStatus, err));
if (!(CheckingBits & chanBit)) {
CheckingBits |= chanBit;
SIGetTypeAsync(chan, PADReceiveCheckCallback);
}
} else {
PADDisable(chan);
status->err = PAD_ERR_NO_CONTROLLER;
memset(status, 0, offsetof(PADStatus, err));
}
} else {
if (!(SIGetType(chan) & SI_GC_NOMOTOR)) {
motor |= chanBit;
}
if (!SIGetResponse(chan, &data)) {
status->err = PAD_ERR_TRANSFER;
memset(status, 0, offsetof(PADStatus, err));
} else if (data[0] & 0x80000000) {
status->err = PAD_ERR_TRANSFER;
memset(status, 0, offsetof(PADStatus, err));
} else {
MakeStatus(chan, status, data);
if (((Type[chan] & (0xFFFF0000)) == SI_GC_CONTROLLER) && ((status->button & 0x80) ^ 0x80)) {
threshold = 10;
} else {
threshold = 3;
}
#ifdef __MWERKS__
#define abs(x) __abs(x)
#else
#define abs(x) __builtin_abs(x)
#endif
if (abs(abs(status->stickX) - abs(pre_status[chan].stickX)) >= threshold ||
abs(abs(status->stickY) - abs(pre_status[chan].stickY)) >= threshold ||
abs(abs(status->substickX) - abs(pre_status[chan].substickX)) >= threshold ||
abs(abs(status->substickY) - abs(pre_status[chan].substickY)) >= threshold ||
abs(abs(status->triggerLeft) - abs(pre_status[chan].triggerLeft)) >= threshold ||
abs(abs(status->triggerRight) - abs(pre_status[chan].triggerRight)) >= threshold ||
pre_status[chan].button != status->button)
{
__VIResetSIIdle();
}
#undef abs
memcpy(&pre_status[chan], status, sizeof(PADStatus));
// Check and clear PAD_ORIGIN bit
if (status->button & 0x2000) {
status->err = PAD_ERR_TRANSFER;
memset(status, 0, offsetof(PADStatus, err));
// Get origin. It is okay if the following transfer fails
// since the PAD_ORIGIN bit remains until the read origin
// command complete.
SITransfer(chan, &CmdReadOrigin, 1, &Origin[chan], 10, PADOriginUpdateCallback, 0);
} else {
status->err = PAD_ERR_NONE;
// Clear PAD_INTERFERE bit
status->button &= ~0x0080;
}
}
}
}
}
OSRestoreInterrupts(enabled);
return motor;
}
typedef struct XY {
u8 line;
u8 count;
} XY;
void PADSetSamplingRate(u32 msec) {
SISetSamplingRate(msec);
}
#if DEBUG
void __PADTestSamplingRate(u32 tvmode) {
__SITestSamplingRate(tvmode);
}
#endif
void PADControlAllMotors(const u32* commandArray) {
BOOL enabled;
int chan;
u32 command;
BOOL commit;
u32 chanBit;
enabled = OSDisableInterrupts();
commit = FALSE;
for (chan = 0; chan < SI_MAX_CHAN; chan++, commandArray++) {
chanBit = PAD_CHAN0_BIT >> chan;
if ((EnabledBits & chanBit) && !(SIGetType(chan) & 0x20000000)) {
command = *commandArray;
ASSERTMSGLINE(0x4B5, !(command & 0xFFFFFFFC), "PADControlAllMotors(): invalid command");
if (Spec < PAD_SPEC_2 && command == PAD_MOTOR_STOP_HARD)
command = PAD_MOTOR_STOP;
if (__gUnknown800030E3 & 0x20)
command = PAD_MOTOR_STOP;
SISetCommand(chan, (0x40 << 16) | AnalogMode | (command & (0x00000001 | 0x00000002)));
commit = TRUE;
}
}
if (commit)
SITransferCommands();
OSRestoreInterrupts(enabled);
}
void PADControlMotor(s32 chan, u32 command) {
BOOL enabled;
u32 chanBit;
ASSERTMSGLINE(1308, !(command & 0xFFFFFFFC), "PADControlMotor(): invalid command");
enabled = OSDisableInterrupts();
chanBit = PAD_CHAN0_BIT >> chan;
if ((EnabledBits & chanBit) && !(SIGetType(chan) & SI_GC_NOMOTOR)) {
if (Spec < PAD_SPEC_2 && command == PAD_MOTOR_STOP_HARD)
command = PAD_MOTOR_STOP;
if (__gUnknown800030E3 & 0x20)
command = PAD_MOTOR_STOP;
SISetCommand(chan, (0x40 << 16) | AnalogMode | (command & (0x00000001 | 0x00000002)));
SITransferCommands();
}
OSRestoreInterrupts(enabled);
}
void PADSetSpec(u32 spec) {
ASSERTLINE(1346, !Initialized);
__PADSpec = 0;
switch (spec) {
case PAD_SPEC_0:
MakeStatus = SPEC0_MakeStatus;
break;
case PAD_SPEC_1:
MakeStatus = SPEC1_MakeStatus;
break;
case PAD_SPEC_2:
case PAD_SPEC_3:
case PAD_SPEC_4:
case PAD_SPEC_5:
MakeStatus = SPEC2_MakeStatus;
break;
}
Spec = spec;
}
u32 PADGetSpec(void) {
return Spec;
}
static void SPEC0_MakeStatus(s32 chan, PADStatus* status, u32 data[2]) {
status->button = 0;
status->button |= ((data[0] >> 16) & 0x0008) ? PAD_BUTTON_A : 0;
status->button |= ((data[0] >> 16) & 0x0020) ? PAD_BUTTON_B : 0;
status->button |= ((data[0] >> 16) & 0x0100) ? PAD_BUTTON_X : 0;
status->button |= ((data[0] >> 16) & 0x0001) ? PAD_BUTTON_Y : 0;
status->button |= ((data[0] >> 16) & 0x0010) ? PAD_BUTTON_START : 0;
status->stickX = (s8)(data[1] >> 16);
status->stickY = (s8)(data[1] >> 24);
status->substickX = (s8)(data[1]);
status->substickY = (s8)(data[1] >> 8);
status->triggerLeft = (u8)(data[0] >> 8);
status->triggerRight = (u8)data[0];
status->analogA = 0;
status->analogB = 0;
if (170 <= status->triggerLeft)
status->button |= PAD_TRIGGER_L;
if (170 <= status->triggerRight)
status->button |= PAD_TRIGGER_R;
status->stickX -= 128;
status->stickY -= 128;
status->substickX -= 128;
status->substickY -= 128;
}
static void SPEC1_MakeStatus(s32 chan, PADStatus* status, u32 data[2]) {
status->button = 0;
status->button |= ((data[0] >> 16) & 0x0080) ? PAD_BUTTON_A : 0;
status->button |= ((data[0] >> 16) & 0x0100) ? PAD_BUTTON_B : 0;
status->button |= ((data[0] >> 16) & 0x0020) ? PAD_BUTTON_X : 0;
status->button |= ((data[0] >> 16) & 0x0010) ? PAD_BUTTON_Y : 0;
status->button |= ((data[0] >> 16) & 0x0200) ? PAD_BUTTON_START : 0;
status->stickX = (s8)(data[1] >> 16);
status->stickY = (s8)(data[1] >> 24);
status->substickX = (s8)(data[1]);
status->substickY = (s8)(data[1] >> 8);
status->triggerLeft = (u8)(data[0] >> 8);
status->triggerRight = (u8)data[0];
status->analogA = 0;
status->analogB = 0;
if (170 <= status->triggerLeft)
status->button |= PAD_TRIGGER_L;
if (170 <= status->triggerRight)
status->button |= PAD_TRIGGER_R;
status->stickX -= 128;
status->stickY -= 128;
status->substickX -= 128;
status->substickY -= 128;
}
static s8 ClampS8(s8 var, s8 org) {
if (0 < org) {
s8 min = (s8)(-128 + org);
if (var < min)
var = min;
} else if (org < 0) {
s8 max = (s8)(127 + org);
if (max < var)
var = max;
}
return var -= org;
}
static u8 ClampU8(u8 var, u8 org) {
if (var < org)
var = org;
return var -= org;
}
static void SPEC2_MakeStatus(s32 chan, PADStatus* status, u32 data[2]) {
PADStatus* origin;
status->button = (u16)((data[0] >> 16) & PAD_ALL);
status->stickX = (s8)(data[0] >> 8);
status->stickY = (s8)(data[0]);
switch (AnalogMode & 0x00000700) {
case 0x00000000:
case 0x00000500:
case 0x00000600:
case 0x00000700:
status->substickX = (s8)(data[1] >> 24);
status->substickY = (s8)(data[1] >> 16);
status->triggerLeft = (u8)(((data[1] >> 12) & 0x0f) << 4);
status->triggerRight = (u8)(((data[1] >> 8) & 0x0f) << 4);
status->analogA = (u8)(((data[1] >> 4) & 0x0f) << 4);
status->analogB = (u8)(((data[1] >> 0) & 0x0f) << 4);
break;
case 0x00000100:
status->substickX = (s8)(((data[1] >> 28) & 0x0f) << 4);
status->substickY = (s8)(((data[1] >> 24) & 0x0f) << 4);
status->triggerLeft = (u8)(data[1] >> 16);
status->triggerRight = (u8)(data[1] >> 8);
status->analogA = (u8)(((data[1] >> 4) & 0x0f) << 4);
status->analogB = (u8)(((data[1] >> 0) & 0x0f) << 4);
break;
case 0x00000200:
status->substickX = (s8)(((data[1] >> 28) & 0x0f) << 4);
status->substickY = (s8)(((data[1] >> 24) & 0x0f) << 4);
status->triggerLeft = (u8)(((data[1] >> 20) & 0x0f) << 4);
status->triggerRight = (u8)(((data[1] >> 16) & 0x0f) << 4);
status->analogA = (u8)(data[1] >> 8);
status->analogB = (u8)(data[1] >> 0);
break;
case 0x00000300:
status->substickX = (s8)(data[1] >> 24);
status->substickY = (s8)(data[1] >> 16);
status->triggerLeft = (u8)(data[1] >> 8);
status->triggerRight = (u8)(data[1] >> 0);
status->analogA = 0;
status->analogB = 0;
break;
case 0x00000400:
status->substickX = (s8)(data[1] >> 24);
status->substickY = (s8)(data[1] >> 16);
status->triggerLeft = 0;
status->triggerRight = 0;
status->analogA = (u8)(data[1] >> 8);
status->analogB = (u8)(data[1] >> 0);
break;
}
status->stickX -= 128;
status->stickY -= 128;
status->substickX -= 128;
status->substickY -= 128;
if (((Type[chan] & (0xFFFF0000)) == SI_GC_CONTROLLER) && ((status->button & 0x80) ^ 0x80)) {
BarrelBits |= (PAD_CHAN0_BIT >> chan);
status->stickX = 0;
status->stickY = 0;
status->substickX = 0;
status->substickY = 0;
return;
} else {
BarrelBits &= ~(PAD_CHAN0_BIT >> chan);
}
origin = &Origin[chan];
status->stickX = ClampS8(status->stickX, origin->stickX);
status->stickY = ClampS8(status->stickY, origin->stickY);
status->substickX = ClampS8(status->substickX, origin->substickX);
status->substickY = ClampS8(status->substickY, origin->substickY);
status->triggerLeft = ClampU8(status->triggerLeft, origin->triggerLeft);
status->triggerRight = ClampU8(status->triggerRight, origin->triggerRight);
}
int PADGetType(s32 chan, u32* type) {
u32 chanBit;
*type = SIGetType(chan);
chanBit = PAD_CHAN0_BIT >> chan;
if (ResettingBits & chanBit || ResettingChan == chan || !(EnabledBits & chanBit)) {
return 0;
}
return 1;
}
BOOL PADSync(void) {
return ResettingBits == 0 && (s32)ResettingChan == 32 && !SIBusy();
}
void PADSetAnalogMode(u32 mode) {
BOOL enabled;
u32 mask;
ASSERTMSGLINE(1681, (mode < 8), "PADSetAnalogMode(): invalid mode");
enabled = OSDisableInterrupts();
AnalogMode = mode << 8;
mask = EnabledBits;
EnabledBits &= ~mask;
WaitingBits &= ~mask;
CheckingBits &= ~mask;
SIDisablePolling(mask);
OSRestoreInterrupts(enabled);
}
static void (*SamplingCallback)();
static BOOL OnShutdown(BOOL final, u32 event) {
BOOL sync;
static BOOL recalibrated = FALSE;
if (SamplingCallback)
PADSetSamplingCallback(NULL);
if (!final) {
sync = PADSync();
if (!recalibrated && sync) {
recalibrated = PADRecalibrate(PAD_CHAN0_BIT | PAD_CHAN1_BIT | PAD_CHAN2_BIT | PAD_CHAN3_BIT);
return FALSE;
}
return sync;
} else
recalibrated = FALSE;
return TRUE;
}
void __PADDisableXPatch(void) {
XPatchBits = 0;
}
static void SamplingHandler(__OSInterrupt interrupt, OSContext* context) {
OSContext exceptionContext;
if (SamplingCallback) {
OSClearContext(&exceptionContext);
OSSetCurrentContext(&exceptionContext);
SamplingCallback();
OSClearContext(&exceptionContext);
OSSetCurrentContext(context);
}
}
PADSamplingCallback PADSetSamplingCallback(PADSamplingCallback callback) {
PADSamplingCallback prev;
prev = SamplingCallback;
SamplingCallback = callback;
if (callback) {
SIRegisterPollingHandler(SamplingHandler);
} else {
SIUnregisterPollingHandler(SamplingHandler);
}
return prev;
}
BOOL __PADDisableRecalibration(BOOL disable) {
BOOL enabled;
BOOL prev;
enabled = OSDisableInterrupts();
prev = (__gUnknown800030E3 & 0x40) ? TRUE : FALSE;
__gUnknown800030E3 &= ~0x40;
if (disable) {
__gUnknown800030E3 |= 0x40;
}
OSRestoreInterrupts(enabled);
return prev;
}
BOOL __PADDisableRumble(BOOL disable) {
BOOL enabled;
BOOL prev;
enabled = OSDisableInterrupts();
prev = (__gUnknown800030E3 & 0x20) ? TRUE : FALSE;
__gUnknown800030E3 &= ~0x20;
if (disable) {
__gUnknown800030E3 |= 0x20;
}
OSRestoreInterrupts(enabled);
return prev;
}
BOOL PADIsBarrel(s32 chan) {
if (chan < 0 || chan >= 4) {
return FALSE;
}
if (BarrelBits & (PAD_CHAN0_BIT >> chan)) {
return TRUE;
}
return FALSE;
}

View File

@ -0,0 +1,153 @@
#include <revolution.h>
#include <revolution/pad.h>
extern f32 sqrtf(f32);
static const PADClampRegion ClampRegion = {
// Triggers
30,
180,
// Left stick
15,
72,
40,
// Right stick
15,
59,
31,
// Stick radii
56,
44,
};
// prototypes
static void ClampStick(s8* px, s8* py, s8 max, s8 xy, s8 min);
static void ClampCircle(s8* px, s8* py, s8 radius, s8 min);
static void ClampTrigger(u8* trigger, u8 min, u8 max);
static void ClampStick(s8* px, s8* py, s8 max, s8 xy, s8 min) {
int x = *px;
int y = *py;
int signX;
int signY;
int d;
if (0 <= x) {
signX = 1;
} else {
signX = -1;
x = -x;
}
if (0 <= y) {
signY = 1;
} else {
signY = -1;
y = -y;
}
if (x <= min) {
x = 0;
} else {
x -= min;
}
if (y <= min) {
y = 0;
} else {
y -= min;
}
if (x == 0 && y == 0) {
*px = *py = 0;
return;
}
if (xy * y <= xy * x) {
d = xy * x + (max - xy) * y;
if (xy * max < d) {
x = (s8)(xy * max * x / d);
y = (s8)(xy * max * y / d);
}
} else {
d = xy * y + (max - xy) * x;
if (xy * max < d) {
x = (s8)(xy * max * x / d);
y = (s8)(xy * max * y / d);
}
}
*px = (s8)(signX * x);
*py = (s8)(signY * y);
}
static void ClampCircle(s8* px, s8* py, s8 radius, s8 min) {
int x = *px;
int y = *py;
int squared;
int length;
if (-min < x && x < min) {
x = 0;
} else if (0 < x) {
x -= min;
} else {
x += min;
}
if (-min < y && y < min) {
y = 0;
} else if (0 < y) {
y -= min;
} else {
y += min;
}
squared = x * x + y * y;
if (radius * radius < squared) {
length = sqrtf(squared);
x = (x * radius) / length;
y = (y * radius) / length;
}
*px = x;
*py = y;
}
static void ClampTrigger(u8* trigger, u8 min, u8 max) {
if (*trigger <= min) {
*trigger = 0;
} else {
if (max < *trigger) {
*trigger = max;
}
*trigger -= min;
}
}
void PADClamp(PADStatus * status) {
int i;
for (i = 0; i < 4; i++, status++) {
if (status->err == PAD_ERR_NONE) {
ClampStick(&status->stickX, &status->stickY, ClampRegion.maxStick, ClampRegion.xyStick, ClampRegion.minStick);
ClampStick(&status->substickX, &status->substickY, ClampRegion.maxSubstick, ClampRegion.xySubstick, ClampRegion.minSubstick);
ClampTrigger(&status->triggerLeft, ClampRegion.minTrigger, ClampRegion.maxTrigger);
ClampTrigger(&status->triggerRight, ClampRegion.minTrigger, ClampRegion.maxTrigger);
}
}
}
void PADClampCircle(PADStatus* status) {
int i;
for (i = 0; i < 4; ++i, status++) {
if (status->err == PAD_ERR_NONE) {
ClampCircle(&status->stickX, &status->stickY, ClampRegion.radStick, ClampRegion.minStick);
ClampCircle(&status->substickX, &status->substickY, ClampRegion.radSubstick, ClampRegion.minSubstick);
ClampTrigger(&status->triggerLeft, ClampRegion.minTrigger, ClampRegion.maxTrigger);
ClampTrigger(&status->triggerRight, ClampRegion.minTrigger, ClampRegion.maxTrigger);
}
}
}

21
src/revolution/si/__si.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef _REVOLUTION_SI_INTERNAL_H_
#define _REVOLUTION_SI_INTERNAL_H_
#include <revolution/types.h>
#ifdef __cplusplus
extern "C" {
#endif
void __SISteeringEnable(s32 chan);
s32 __SISteeringTransfer(s32 chan, u32 outputBytes, u32 inputBytes, void (*proc)(s32));
void __SISteeringSyncCallback(s32 chan, s32);
s32 __SISteeringSync(s32 chan);
void __SISteeringDisable(s32 chan);
void __SITestSamplingRate(u32 tvmode);
#ifdef __cplusplus
}
#endif
#endif