mirror of https://github.com/zeldaret/tp
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:
parent
251d49c6f1
commit
353721578d
|
|
@ -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
|
||||
|
|
|
|||
47
configure.py
47
configure.py
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 ");
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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';
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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.!");
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
// prototypes
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include <revolution/os.h>
|
||||
#include <revolution/nand.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static OSStateFlags StateFlags ATTRIBUTE_ALIGN(32);
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue