mirror of
https://github.com/zeldaret/tww.git
synced 2026-08-21 22:10:59 -04:00
dolphin/dvd OK
This commit is contained in:
+8
-8
@@ -1085,14 +1085,14 @@ config.libs = [
|
||||
DolphinLib(
|
||||
"dvd",
|
||||
[
|
||||
Object(NonMatching, "dolphin/dvd/dvdlow.c"),
|
||||
Object(NonMatching, "dolphin/dvd/dvdfs.c"),
|
||||
Object(NonMatching, "dolphin/dvd/dvd.c"),
|
||||
Object(NonMatching, "dolphin/dvd/dvdqueue.c"),
|
||||
Object(NonMatching, "dolphin/dvd/dvderror.c"),
|
||||
Object(NonMatching, "dolphin/dvd/dvdidutils.c"),
|
||||
Object(NonMatching, "dolphin/dvd/dvdFatal.c"),
|
||||
Object(NonMatching, "dolphin/dvd/fstload.c"),
|
||||
Object(Matching, "dolphin/dvd/dvdlow.c"),
|
||||
Object(Matching, "dolphin/dvd/dvdfs.c"),
|
||||
Object(Matching, "dolphin/dvd/dvd.c"),
|
||||
Object(Matching, "dolphin/dvd/dvdqueue.c"),
|
||||
Object(Matching, "dolphin/dvd/dvderror.c"),
|
||||
Object(Matching, "dolphin/dvd/dvdidutils.c"),
|
||||
Object(Matching, "dolphin/dvd/dvdFatal.c"),
|
||||
Object(Matching, "dolphin/dvd/fstload.c"),
|
||||
],
|
||||
),
|
||||
DolphinLib(
|
||||
|
||||
@@ -54,9 +54,13 @@ typedef struct DVDDiskID {
|
||||
|
||||
struct DVDFileInfo;
|
||||
struct DVDCommandBlock;
|
||||
typedef struct DVDCommandBlock DVDCommandBlock;
|
||||
typedef void (*DVDCBCallback)(s32 result, struct DVDCommandBlock* block);
|
||||
typedef void (*DVDCallback)(s32 result, struct DVDFileInfo* info);
|
||||
|
||||
typedef void (*DVDCommandCheckerCallback)(u32);
|
||||
typedef void (*DVDCommandChecker)(DVDCommandBlock*, DVDCommandCheckerCallback);
|
||||
|
||||
typedef struct DVDCommandBlock {
|
||||
/* 0x00 */ struct DVDCommandBlock* next;
|
||||
/* 0x04 */ struct DVDCommandBlock* prev;
|
||||
@@ -105,8 +109,54 @@ typedef struct DVDBB2 {
|
||||
u32 padding0;
|
||||
} DVDBB2;
|
||||
|
||||
#define DVD_RESULT_GOOD 0
|
||||
#define DVD_RESULT_FATAL_ERROR -1
|
||||
#define DVD_RESULT_IGNORED -2
|
||||
#define DVD_RESULT_CANCELED -3
|
||||
|
||||
#define DVD_STATE_FATAL_ERROR -1
|
||||
#define DVD_STATE_END 0
|
||||
#define DVD_STATE_BUSY 1
|
||||
#define DVD_STATE_WAITING 2
|
||||
#define DVD_STATE_COVER_CLOSED 3
|
||||
#define DVD_STATE_NO_DISK 4
|
||||
#define DVD_STATE_COVER_OPEN 5
|
||||
#define DVD_STATE_WRONG_DISK 6
|
||||
#define DVD_STATE_MOTOR_STOPPED 7
|
||||
#define DVD_STATE_PAUSING 8
|
||||
#define DVD_STATE_IGNORED 9
|
||||
#define DVD_STATE_CANCELED 10
|
||||
#define DVD_STATE_RETRY 11
|
||||
|
||||
#define DVD_MIN_TRANSFER_SIZE 32
|
||||
|
||||
// could be bitfields
|
||||
#define DVD_INTTYPE_TC 1
|
||||
#define DVD_INTTYPE_DE 2
|
||||
// unk type 3
|
||||
#define DVD_INTTYPE_CVR 4
|
||||
|
||||
// DVD Commands
|
||||
|
||||
#define DVD_COMMAND_NONE 0
|
||||
#define DVD_COMMAND_READ 1
|
||||
#define DVD_COMMAND_SEEK 2
|
||||
#define DVD_COMMAND_CHANGE_DISK 3
|
||||
#define DVD_COMMAND_BSREAD 4
|
||||
#define DVD_COMMAND_READID 5
|
||||
#define DVD_COMMAND_INITSTREAM 6
|
||||
#define DVD_COMMAND_CANCELSTREAM 7
|
||||
#define DVD_COMMAND_STOP_STREAM_AT_END 8
|
||||
#define DVD_COMMAND_REQUEST_AUDIO_ERROR 9
|
||||
#define DVD_COMMAND_REQUEST_PLAY_ADDR 10
|
||||
#define DVD_COMMAND_REQUEST_START_ADDR 11
|
||||
#define DVD_COMMAND_REQUEST_LENGTH 12
|
||||
#define DVD_COMMAND_AUDIO_BUFFER_CONFIG 13
|
||||
#define DVD_COMMAND_INQUIRY 14
|
||||
#define DVD_COMMAND_BS_CHANGE_DISK 15
|
||||
|
||||
#define DVD_WATYPE_MAX 2
|
||||
|
||||
typedef void (*DVDOptionalCommandChecker)(DVDCommandBlock* block, void (*cb)(u32 intType));
|
||||
|
||||
#define DVDGetLength(fi) (fi)->length
|
||||
@@ -144,9 +194,22 @@ static BOOL DVDCancelAsync(DVDCommandBlock* block, DVDCBCallback callback);
|
||||
s32 DVDCancel(DVDCommandBlock* block);
|
||||
void __DVDPrepareResetAsync(DVDCBCallback callbac);
|
||||
BOOL DVDCompareDiskID(DVDDiskID* id1, DVDDiskID* id2);
|
||||
void __DVDAudioBufferConfig(struct DVDCommandBlock * block, unsigned long enable, unsigned long size, void (* callback)(long, struct DVDCommandBlock *));
|
||||
|
||||
DVDCommandBlock* __DVDPopWaitingQueue(void);
|
||||
|
||||
#define DVD_ASSERTMSGLINE(line, cond, msg) \
|
||||
if (!(cond)) \
|
||||
OSPanic(__FILE__, line, msg)
|
||||
|
||||
#define DVD_ASSERTMSG1LINE(line, cond, msg, arg1) \
|
||||
if (!(cond)) \
|
||||
OSPanic(__FILE__, line, msg, arg1)
|
||||
|
||||
#define DVD_ASSERTMSG2LINE(line, cond, msg, arg1, arg2) \
|
||||
if (!(cond)) \
|
||||
OSPanic(__FILE__, line, msg, arg1, arg2)
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#ifndef DVDERROR_H
|
||||
#define DVDERROR_H
|
||||
|
||||
#include "dolphin/types.h"
|
||||
|
||||
void __DVDStoreErrorCode(u32 error);
|
||||
|
||||
#endif /* DVDERROR_H */
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
#define DVDFS_H
|
||||
|
||||
#include "dolphin/types.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
extern struct OSThreadQueue __DVDThreadQueue;
|
||||
extern u32 __DVDLongFileNameFlag;
|
||||
|
||||
void __DVDFSInit();
|
||||
|
||||
#endif /* DVDFS_H */
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
#ifndef DVDLOW_H
|
||||
#define DVDLOW_H
|
||||
|
||||
#include "dolphin/dvd/dvd.h" // IWYU pragma: export
|
||||
#include "dolphin/types.h"
|
||||
#include "dolphin/os/OSUtil.h"
|
||||
|
||||
typedef void (*DVDLowCallback)(u32 intType);
|
||||
vu32 __DIRegs[16] AT_ADDRESS(0xCC006000);
|
||||
|
||||
void __DVDInitWA(void);
|
||||
void __DVDInterruptHandler(short unused, struct OSContext * context);
|
||||
void __DVDLowSetWAType(u32 type, u32 location);
|
||||
DVDLowCallback DVDLowClearCallback(void);
|
||||
|
||||
#endif /* DVDLOW_H */
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#ifndef DVDQUEUE_H
|
||||
#define DVDQUEUE_H
|
||||
|
||||
void __DVDClearWaitingQueue();
|
||||
int __DVDPushWaitingQueue(long prio, struct DVDCommandBlock * block);
|
||||
struct DVDCommandBlock * __DVDPopWaitingQueue();
|
||||
int __DVDCheckWaitingQueue();
|
||||
int __DVDDequeueWaitingQueue(struct DVDCommandBlock * block);
|
||||
int __DVDIsBlockInWaitingQueue(struct DVDCommandBlock * block);
|
||||
|
||||
#endif /* DVDQUEUE_H */
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#ifndef FSTLOAD_H
|
||||
#define FSTLOAD_H
|
||||
|
||||
void __fstLoad();
|
||||
|
||||
#endif /* FSTLOAD_H */
|
||||
|
||||
@@ -285,6 +285,12 @@ struct GLOBAL_MEMORY {
|
||||
|
||||
#define OS_ASSERT(...)
|
||||
|
||||
#define ASSERTLINE(line, cond) (void)0
|
||||
#define ASSERTMSGLINE(line, cond, msg) (void)0
|
||||
#define ASSERTMSG1LINE(line, cond, msg, arg1) (void)0
|
||||
#define ASSERTMSG2LINE(line, cond, msg, arg1, arg2) (void)0
|
||||
#define ASSERTMSGLINEV(line, cond, ...) (void)0
|
||||
|
||||
#define OSPhysicalToCached(paddr) ((void*)((u32)(paddr) + OS_BASE_CACHED))
|
||||
#define OSPhysicalToUncached(paddr) ((void*)((u32)(paddr) + OS_BASE_UNCACHED))
|
||||
#define OSCachedToPhysical(caddr) ((u32)((u8*)(caddr)-OS_BASE_CACHED))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,94 @@
|
||||
#include "dolphin/dvd/dvdFatal.h"
|
||||
#include "dolphin/gx/GXStruct.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
static void (*FatalFunc)();
|
||||
|
||||
const char* Japanese =
|
||||
"\n\n\nエラーが発生しました。\n\n"
|
||||
"本体のパワーボタンを押して電源をOFFにし、\n"
|
||||
"本体の取扱説明書の指示に従ってください。";
|
||||
|
||||
const char* English =
|
||||
"\n\n\nAn error has occurred.\n"
|
||||
"Turn the power off and refer to the\n"
|
||||
"Nintendo GameCube Instruction Booklet\n"
|
||||
"for further instructions.";
|
||||
|
||||
// TODO: need solution to compile special characters in a cleaner way
|
||||
const char* const Europe[6] = {
|
||||
{
|
||||
"\n\n\nAn error has occurred.\n"
|
||||
"Turn the power off and refer to the\n"
|
||||
"Nintendo GameCube Instruction Booklet\n"
|
||||
"for further instructions."
|
||||
},
|
||||
{
|
||||
"\n\n\nEin Fehler ist aufgetreten.\n"
|
||||
"Bitte schalten Sie den Nintendo GameCube\n"
|
||||
"aus und lesen Sie die Bedienungsanleitung,\n"
|
||||
"um weitere Informationen zu erhalten."
|
||||
},
|
||||
{
|
||||
"\n\n\nUne erreur est survenue.\n"
|
||||
"Eteignez la console et r\xE9" "f" "\xE9rez-vous au\n"
|
||||
"manuel d'instructions Nintendo GameCube\n"
|
||||
"pour de plus amples informations."
|
||||
},
|
||||
{
|
||||
"\n\n\nSe ha producido un error.\n"
|
||||
"Apaga la consola y consulta el manual\n"
|
||||
"de instrucciones de Nintendo GameCube\n"
|
||||
"para obtener m\xE1" "s informaci\xF3" "n."
|
||||
},
|
||||
{
|
||||
"\n\n\nSi \xE8" " verificato un errore.\n"
|
||||
"Spegni (OFF) e controlla il manuale\n"
|
||||
"d'istruzioni del Nintendo GameCube\n"
|
||||
"per ulteriori indicazioni."
|
||||
},
|
||||
{
|
||||
"\n\n\nEr is een fout opgetreden.\n"
|
||||
"Zet de Nintendo GameCube uit en\n"
|
||||
"raadpleeg de handleiding van de\n"
|
||||
"Nintendo GameCube voor nadere\n"
|
||||
"instructies."
|
||||
},
|
||||
};
|
||||
|
||||
static void ShowMessage(void) {
|
||||
const char* message;
|
||||
GXColor bg = {0x00, 0x00, 0x00, 0x00};
|
||||
GXColor fg = {0xFF, 0xFF, 0xFF, 0x00};
|
||||
|
||||
if (VIGetTvFormat() == VI_NTSC) {
|
||||
if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS) {
|
||||
message = Japanese;
|
||||
} else {
|
||||
message = English;
|
||||
}
|
||||
} else {
|
||||
message = Europe[OSGetLanguage()];
|
||||
}
|
||||
|
||||
OSFatal(fg, bg, message);
|
||||
}
|
||||
|
||||
int DVDSetAutoFatalMessaging(BOOL enable) {
|
||||
BOOL enabled;
|
||||
int prev;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
prev = FatalFunc ? 1 : 0;
|
||||
FatalFunc = enable ? ShowMessage : NULL;
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return prev;
|
||||
}
|
||||
|
||||
void __DVDPrintFatalMessage(void) {
|
||||
if (FatalFunc) {
|
||||
FatalFunc();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "dolphin/dvd/dvderror.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
static u32 ErrorTable[18] = {
|
||||
0x00000000,
|
||||
0x00023A00,
|
||||
0x00062800,
|
||||
0x00030200,
|
||||
0x00031100,
|
||||
0x00052000,
|
||||
0x00052001,
|
||||
0x00052100,
|
||||
0x00052400,
|
||||
0x00052401,
|
||||
0x00052402,
|
||||
0x000B5A01,
|
||||
0x00056300,
|
||||
0x00020401,
|
||||
0x00020400,
|
||||
0x00040800,
|
||||
0x00100007,
|
||||
0x00000000,
|
||||
};
|
||||
|
||||
#define DIDNT_MATCH 29
|
||||
|
||||
static u8 ErrorCode2Num(u32 errorCode) {
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < 18; i++) {
|
||||
if (errorCode == ErrorTable[i]) {
|
||||
ASSERTLINE(0x49, i < DIDNT_MATCH);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
if (errorCode >= 0x100000 && errorCode <= 0x100008) {
|
||||
return 17;
|
||||
}
|
||||
|
||||
return DIDNT_MATCH;
|
||||
}
|
||||
|
||||
static u8 Convert(u32 error) {
|
||||
u32 statusCode;
|
||||
u32 errorCode;
|
||||
u8 errorNum;
|
||||
|
||||
if (error == 0x01234567) {
|
||||
return -1;
|
||||
} else if (error == 0x01234568) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
statusCode = (error >> 24) & 0xFF;
|
||||
errorCode = error & 0x00FFFFFF;
|
||||
errorNum = ErrorCode2Num(errorCode);
|
||||
if (statusCode >= 6) {
|
||||
statusCode = 6;
|
||||
}
|
||||
|
||||
return statusCode * 30 + errorNum;
|
||||
}
|
||||
|
||||
void __DVDStoreErrorCode(u32 error)
|
||||
{
|
||||
OSSramEx* sram;
|
||||
u8 num;
|
||||
|
||||
num = Convert(error);
|
||||
sram = __OSLockSramEx();
|
||||
sram->dvdErrorCode = num;
|
||||
__OSUnlockSramEx(TRUE);
|
||||
}
|
||||
@@ -0,0 +1,664 @@
|
||||
#include "dolphin/dvd/dvdfs.h"
|
||||
#include "dolphin/dvd/dvdlow.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
struct FSTEntry {
|
||||
/* 0x00 */ u32 isDirAndStringOff;
|
||||
/* 0x04 */ u32 parentOrPosition;
|
||||
/* 0x08 */ u32 nextEntryOrLength;
|
||||
};
|
||||
|
||||
// .sbss
|
||||
static struct OSBootInfo * BootInfo; // size: 0x4, address: 0x0
|
||||
static struct FSTEntry * FstStart; // size: 0x4, address: 0x4
|
||||
static char * FstStringStart; // size: 0x4, address: 0x8
|
||||
static unsigned long MaxEntryNum; // size: 0x4, address: 0xC
|
||||
static unsigned long currentDirectory; // size: 0x4, address: 0x10
|
||||
struct OSThreadQueue __DVDThreadQueue; // size: 0x8, address: 0x18
|
||||
unsigned long __DVDLongFileNameFlag; // size: 0x4, address: 0x14
|
||||
|
||||
// functions
|
||||
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();
|
||||
static void cbForSeekAsync(long result, struct DVDCommandBlock * block);
|
||||
static void cbForSeekSync();
|
||||
static void cbForPrepareStreamAsync(s32 result, DVDCommandBlock* block);
|
||||
static void cbForPrepareStreamSync();
|
||||
|
||||
void __DVDFSInit() {
|
||||
BootInfo = (void*)OSPhysicalToCached(0);
|
||||
FstStart = BootInfo->fst_location;
|
||||
if (FstStart) {
|
||||
MaxEntryNum = FstStart->nextEntryOrLength;
|
||||
FstStringStart = (char*)FstStart + (MaxEntryNum * 0xC);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
int 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(0x133, 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__, 0x17B,
|
||||
"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(0x1BC, fileInfo, "DVDFastOpen(): null pointer is specified to file info address ");
|
||||
ASSERTMSG1LINE(0x1BF, (entrynum >= 0) && ((u32) entrynum < (u32) MaxEntryNum), "DVDFastOpen(): specified entry number '%d' is out of range ", entrynum);
|
||||
ASSERTMSG1LINE(0x1C2, !entryIsDir(entrynum), "DVDFastOpen(): entry number '%d' is assigned to a directory ", entrynum);
|
||||
|
||||
if ((entrynum < 0) || (entrynum >= MaxEntryNum) || entryIsDir(entrynum)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fileInfo->start_address = filePosition(entrynum);
|
||||
fileInfo->length = fileLength(entrynum);
|
||||
fileInfo->callback = (DVDCallback)NULL;
|
||||
fileInfo->block.state = DVD_STATE_END;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DVDOpen(const char* fileName, DVDFileInfo* fileInfo) {
|
||||
s32 entry;
|
||||
char currentDir[128];
|
||||
|
||||
ASSERTMSGLINE(0x1E0, fileName, "DVDOpen(): null pointer is specified to file name ");
|
||||
ASSERTMSGLINE(0x1E1, 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(0x1EF, !entryIsDir(entry), "DVDOpen(): directory '%s' is specified as a filename ", fileName);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fileInfo->start_address = filePosition(entry);
|
||||
fileInfo->length = fileLength(entry);
|
||||
fileInfo->callback = (DVDCallback)NULL;
|
||||
fileInfo->block.state = DVD_STATE_END;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DVDClose(DVDFileInfo* fileInfo) {
|
||||
ASSERTMSGLINE(0x207, fileInfo, "DVDClose(): null pointer is specified to file info address ");
|
||||
DVDCancel(&(fileInfo->block));
|
||||
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) {
|
||||
char* name;
|
||||
u32 loc;
|
||||
|
||||
if (entry == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
name = FstStringStart + stringOff(entry);
|
||||
|
||||
loc = entryToPath(parentDir(entry), 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(0x263, (entrynum >= 0) && (entrynum < MaxEntryNum), "DVDConvertEntrynumToPath: specified entrynum(%d) is out of range ", entrynum);
|
||||
ASSERTMSG1LINE(0x265, maxlen > 1, "DVDConvertEntrynumToPath: maxlen should be more than 1 (%d is specified)", maxlen);
|
||||
ASSERTMSGLINE(0x26A, entryIsDir(entrynum), "DVDConvertEntrynumToPath: cannot convert an entry num for a file to path ");
|
||||
|
||||
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(0x294, (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(0x2AA, dirName, "DVDChangeDir(): null pointer is specified to directory name ");
|
||||
entry = DVDConvertPathToEntrynum(dirName);
|
||||
ASSERTMSG2LINE(0x2B2, entry >= 0, "DVDChangeDir(): directory '%s' is not found under %s ", dirName, (DVDGetCurrentDir(currentDir, 128), currentDir));
|
||||
ASSERTMSG1LINE(0x2B6, 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(0x2D5, fileInfo, "DVDReadAsync(): null pointer is specified to file info address ");
|
||||
ASSERTMSGLINE(0x2D6, addr, "DVDReadAsync(): null pointer is specified to addr ");
|
||||
ASSERTMSGLINE(0x2DA, !OFFSET(addr, 32), "DVDReadAsync(): address must be aligned with 32 byte boundaries ");
|
||||
ASSERTMSGLINE(0x2DC, !(length & 0x1F), "DVDReadAsync(): length must be multiple of 32 byte ");
|
||||
ASSERTMSGLINE(0x2DE, !(offset & 3), "DVDReadAsync(): offset must be multiple of 4 byte ");
|
||||
|
||||
if (!((0 <= offset) && (offset < fileInfo->length))) {
|
||||
OSPanic(__FILE__, 0x2E6, "DVDReadAsync(): specified area is out of the file ");
|
||||
}
|
||||
|
||||
if (!((0 <= offset + length) && (offset + length < fileInfo->length + DVD_MIN_TRANSFER_SIZE))) {
|
||||
OSPanic(__FILE__, 0x2EC, "DVDReadAsync(): specified area is out of the file ");
|
||||
}
|
||||
|
||||
fileInfo->callback = callback;
|
||||
DVDReadAbsAsyncPrio(&(fileInfo->block), addr, length, (s32)(fileInfo->start_address + offset),
|
||||
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, block));
|
||||
ASSERTLINE(0x2FB, (void*) &fileInfo->block == (void*) block);
|
||||
if (fileInfo->callback) {
|
||||
(fileInfo->callback)(result, fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
int DVDReadPrio(struct DVDFileInfo * fileInfo, void * addr, long length, long offset, long prio) {
|
||||
int result;
|
||||
struct DVDCommandBlock * block;
|
||||
long state;
|
||||
int enabled;
|
||||
long retVal;
|
||||
|
||||
ASSERTMSGLINE(0x31B, fileInfo, "DVDRead(): null pointer is specified to file info address ");
|
||||
ASSERTMSGLINE(0x31C, addr, "DVDRead(): null pointer is specified to addr ");
|
||||
ASSERTMSGLINE(0x320, !OFFSET(addr, 32), "DVDRead(): address must be aligned with 32 byte boundaries ");
|
||||
ASSERTMSGLINE(0x322, !(length & 0x1F), "DVDRead(): length must be multiple of 32 byte ");
|
||||
ASSERTMSGLINE(0x324, !(offset & 3), "DVDRead(): offset must be multiple of 4 byte ");
|
||||
|
||||
if (!((0 <= offset) && (offset < fileInfo->length))) {
|
||||
OSPanic(__FILE__, 0x32C, "DVDRead(): specified area is out of the file ");
|
||||
}
|
||||
|
||||
if (!((0 <= offset + length) && (offset + length < fileInfo->length + DVD_MIN_TRANSFER_SIZE))) {
|
||||
OSPanic(__FILE__, 0x332, "DVDRead(): specified area is out of the file ");
|
||||
}
|
||||
|
||||
block = &fileInfo->block;
|
||||
result = DVDReadAbsAsyncPrio(block, addr, length, fileInfo->start_address + offset, cbForReadSync, prio);
|
||||
if (result == 0) {
|
||||
return -1;
|
||||
}
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
while(1) {
|
||||
state = ((volatile DVDCommandBlock*)block)->state;
|
||||
if (state == 0) {
|
||||
retVal = (s32)block->transferred_size;
|
||||
break;
|
||||
} else if (state == -1) {
|
||||
retVal = -1;
|
||||
break;
|
||||
} else if (state == 10) {
|
||||
retVal = -3;
|
||||
break;
|
||||
}
|
||||
OSSleepThread(&__DVDThreadQueue);
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static void cbForReadSync() {
|
||||
OSWakeupThread(&__DVDThreadQueue);
|
||||
}
|
||||
|
||||
int DVDSeekAsyncPrio(struct DVDFileInfo * fileInfo, long offset, void (* callback)(long, struct DVDFileInfo *), long prio) {
|
||||
ASSERTMSGLINE(0x377, fileInfo, "DVDSeek(): null pointer is specified to file info address ");
|
||||
ASSERTMSGLINE(0x37B, !(offset & 3), "DVDSeek(): offset must be multiple of 4 byte ");
|
||||
|
||||
if (!((0 <= offset) && (offset < fileInfo->length))) {
|
||||
OSPanic(__FILE__, 0x380, "DVDSeek(): offset is out of the file ");
|
||||
}
|
||||
|
||||
fileInfo->callback = callback;
|
||||
DVDSeekAbsAsyncPrio(&fileInfo->block, (u32)(char*)fileInfo->start_address + offset, cbForSeekAsync, prio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void cbForSeekAsync(long result, struct DVDCommandBlock * block) {
|
||||
struct DVDFileInfo * fileInfo;
|
||||
|
||||
fileInfo = (struct DVDFileInfo *)&block->next;
|
||||
ASSERTLINE(0x392, (void*) &fileInfo->block == (void*) block);
|
||||
if (fileInfo->callback) {
|
||||
(fileInfo->callback)(result, fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
long DVDSeekPrio(struct DVDFileInfo * fileInfo, long offset, long prio) {
|
||||
int result;
|
||||
struct DVDCommandBlock * block;
|
||||
long state;
|
||||
int enabled;
|
||||
long retVal;
|
||||
|
||||
ASSERTMSGLINE(0x3B0, fileInfo, "DVDSeek(): null pointer is specified to file info address ");
|
||||
ASSERTMSGLINE(0x3B4, !(offset & 3), "DVDSeek(): offset must be multiple of 4 byte ");
|
||||
ASSERTMSGLINE(0x3B8, (offset >= 0) && ((u32) offset < (u32) fileInfo->length), "DVDSeek(): offset is out of the file ");
|
||||
|
||||
block = &fileInfo->block;
|
||||
result = DVDSeekAbsAsyncPrio(block, (u32)(char*)fileInfo->start_address + 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() {
|
||||
OSWakeupThread(&__DVDThreadQueue);
|
||||
}
|
||||
|
||||
// long DVDGetFileInfoStatus(struct DVDFileInfo * fileInfo) {
|
||||
// return DVDGetCommandBlockStatus(&fileInfo->block);
|
||||
// }
|
||||
|
||||
BOOL DVDFastOpenDir(s32 entrynum, DVDDirectory * dir) {
|
||||
ASSERTMSGLINE(0x40D, dir, "DVDFastOpenDir(): null pointer is specified to dir structure address ");
|
||||
ASSERTMSG1LINE(0x410, entrynum >= 0 && entrynum < MaxEntryNum, "DVDFastOpenDir(): specified entry number \'%d\' is out of range ", entrynum);
|
||||
ASSERTMSG1LINE(0x413, entryIsDir(entrynum), "DVDFastOpenDir(): entry number \'%d\' is assigned to a file ", entrynum);
|
||||
|
||||
if (entrynum < 0 || entrynum >= MaxEntryNum || !entryIsDir(entrynum)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dir->entry_number = entrynum;
|
||||
dir->location = entrynum + 1;
|
||||
dir->next = FstStart[entrynum].nextEntryOrLength;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DVDOpenDir(const char* dirName, DVDDirectory* dir) {
|
||||
long entry;
|
||||
char currentDir[128];
|
||||
|
||||
ASSERTMSGLINE(0x430, dirName, "DVDOpendir(): null pointer is specified to directory name ");
|
||||
ASSERTMSGLINE(0x431, 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(0x43F, entryIsDir(entry), "DVDOpendir(): file \'%s\' is specified as a directory name ", dirName);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dir->entry_number = entry;
|
||||
dir->location = entry + 1;
|
||||
dir->next = nextDir(entry);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int DVDReadDir(DVDDirectory * dir, DVDDirectoryEntry* dirent) {
|
||||
unsigned long loc;
|
||||
|
||||
loc = dir->location;
|
||||
if ((loc <= (u32) dir->entry_number) || ((u32) dir->next <= loc)) {
|
||||
return 0;
|
||||
}
|
||||
dirent->entry_number = loc;
|
||||
dirent->is_directory = entryIsDir(loc);
|
||||
dirent->name = FstStringStart + stringOff(loc);
|
||||
dir->location = entryIsDir(loc) ? nextDir(loc) : loc + 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DVDCloseDir(DVDDirectory* dir) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void * DVDGetFSTLocation() {
|
||||
return BootInfo->fst_location;
|
||||
}
|
||||
|
||||
#define RoundUp32KB(x) (((u32)(x) + 32 * 1024 - 1) & ~(32 * 1024 - 1))
|
||||
#define Is32KBAligned(x) (((u32)(x) & (32 * 1024 - 1)) == 0)
|
||||
|
||||
BOOL DVDPrepareStreamAsync(DVDFileInfo* fileInfo, u32 length, u32 offset, DVDCallback callback) {
|
||||
u32 start;
|
||||
|
||||
ASSERTMSGLINE(0x49C, fileInfo, "DVDPrepareStreamAsync(): NULL file info was specified");
|
||||
|
||||
start = fileInfo->start_address + offset;
|
||||
|
||||
if (!Is32KBAligned(start)) {
|
||||
OSPanic(__FILE__, 0x4A5,
|
||||
"DVDPrepareStreamAsync(): Specified start address (filestart(0x%x) + offset(0x%x)) is "
|
||||
"not 32KB aligned",
|
||||
fileInfo->start_address, offset);
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
length = fileInfo->length - offset;
|
||||
|
||||
if (!Is32KBAligned(length)) {
|
||||
OSPanic(__FILE__, 0x4AF,
|
||||
"DVDPrepareStreamAsync(): Specified length (0x%x) is not a multiple of 32768(32*1024)",
|
||||
length);
|
||||
}
|
||||
|
||||
if (!((offset < fileInfo->length) && (offset + length <= fileInfo->length))) {
|
||||
OSPanic(__FILE__, 0x4B7,
|
||||
"DVDPrepareStreamAsync(): The area specified (offset(0x%x), length(0x%x)) is out of "
|
||||
"the file",
|
||||
offset, length);
|
||||
}
|
||||
|
||||
fileInfo->callback = callback;
|
||||
return DVDPrepareStreamAbsAsync(&(fileInfo->block), length, fileInfo->start_address + offset,
|
||||
cbForPrepareStreamAsync);
|
||||
}
|
||||
|
||||
static void cbForPrepareStreamAsync(s32 result, DVDCommandBlock* block) {
|
||||
DVDFileInfo* fileInfo;
|
||||
|
||||
fileInfo = (DVDFileInfo*)((char*)block - offsetof(DVDFileInfo, block));
|
||||
|
||||
ASSERTLINE(0x4C7, (void*) &fileInfo->block == (void*) block);
|
||||
|
||||
if (fileInfo->callback) {
|
||||
(fileInfo->callback)(result, fileInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is based on the revolution SDK, these may not match in all cases */
|
||||
s32 DVDPrepareStream(DVDFileInfo* fileInfo, u32 length, u32 offset) {
|
||||
BOOL result;
|
||||
DVDCommandBlock* block;
|
||||
s32 state;
|
||||
BOOL enabled;
|
||||
s32 retVal;
|
||||
u32 start;
|
||||
|
||||
ASSERTMSGLINE(0x4E9, fileInfo, "DVDPrepareStream(): NULL file info was specified");
|
||||
|
||||
start = fileInfo->start_address + offset;
|
||||
|
||||
if (!Is32KBAligned(start)) {
|
||||
OSPanic(__FILE__, 0x4EF,
|
||||
"DVDPrepareStream(): Specified start address (filestart(0x%x) + offset(0x%x)) is not "
|
||||
"32KB aligned",
|
||||
fileInfo->start_address, offset);
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
length = fileInfo->length - offset;
|
||||
|
||||
if (!Is32KBAligned(length)) {
|
||||
OSPanic(__FILE__, 0x4F9,
|
||||
"DVDPrepareStream(): Specified length (0x%x) is not a multiple of 32768(32*1024)",
|
||||
length);
|
||||
}
|
||||
|
||||
if (!((offset < fileInfo->length) && (offset + length <= fileInfo->length))) {
|
||||
OSPanic(
|
||||
__FILE__, 0x501,
|
||||
"DVDPrepareStream(): The area specified (offset(0x%x), length(0x%x)) is out of the file",
|
||||
offset, length);
|
||||
}
|
||||
|
||||
block = &(fileInfo->block);
|
||||
result = DVDPrepareStreamAbsAsync(block, length, start, cbForPrepareStreamSync);
|
||||
|
||||
if (result == FALSE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
while(1) {
|
||||
state = ((volatile DVDCommandBlock*)block)->state;
|
||||
|
||||
if (state == DVD_STATE_END) {
|
||||
retVal = 0;
|
||||
break;
|
||||
}
|
||||
if (state == DVD_STATE_FATAL_ERROR) {
|
||||
retVal = DVD_RESULT_FATAL_ERROR;
|
||||
break;
|
||||
}
|
||||
if (state == DVD_STATE_CANCELED) {
|
||||
retVal = DVD_RESULT_CANCELED;
|
||||
break;
|
||||
}
|
||||
|
||||
OSSleepThread(&__DVDThreadQueue);
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static void cbForPrepareStreamSync(s32 result, DVDCommandBlock* block) {
|
||||
OSWakeupThread(&__DVDThreadQueue);
|
||||
}
|
||||
|
||||
s32 DVDGetTransferredSize(DVDFileInfo* fileinfo) {
|
||||
s32 bytes;
|
||||
DVDCommandBlock* cb;
|
||||
|
||||
cb = &(fileinfo->block);
|
||||
|
||||
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->transferred_size;
|
||||
break;
|
||||
case DVD_STATE_WAITING:
|
||||
bytes = 0;
|
||||
break;
|
||||
case DVD_STATE_BUSY:
|
||||
bytes = (s32)(cb->transferred_size + (cb->current_transfer_size - __DIRegs[6]));
|
||||
break;
|
||||
default:
|
||||
ASSERTMSG1LINE(0x556, FALSE, "DVDGetTransferredSize(): Illegal state (%d)", cb->state);
|
||||
break;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
#include "dolphin/dvd/dvdidutils.h"
|
||||
#include "dolphin/os/OS.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(DVDDiskID* id1, 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(64, id1, "DVDCompareDiskID(): Specified id1 is NULL\n");
|
||||
ASSERTMSGLINE(65, id2, "DVDCompareDiskID(): Specified id2 is NULL\n");
|
||||
|
||||
game1 = id1->game_name;
|
||||
game2 = id2->game_name;
|
||||
company1 = id1->company;
|
||||
company2 = id2->company;
|
||||
diskNum1 = id1->disk_number;
|
||||
diskNum2 = id2->disk_number;
|
||||
version1 = id1->game_version;
|
||||
version2 = id2->game_version;
|
||||
|
||||
length = strnlen(game1, sizeof(game1));
|
||||
ASSERTMSGLINE(78, length == 0 || length == 4, "DVDCompareDiskID(): Specified game name for id1 is neither NULL nor 4 character long\n");
|
||||
ASSERTMSGLINE(79, company1, "DVDCompareDiskID(): Specified company name for id1 is NULL\n");
|
||||
ASSERTMSGLINE(80, company1[1] != 0, "DVDCompareDiskID(): Specified company name for id1 is not 2 character long\n");
|
||||
ASSERTMSGLINE(81, diskNum1 == 0xFF || ((diskNum1 / 16) < 10 && diskNum1 % 16 < 10), "DVDCompareDiskID(): Specified disk number for id1 is neither 0xff nor a BCD number");
|
||||
ASSERTMSGLINE(82, 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(85, length == 0 || length == 4, "DVDCompareDiskID(): Specified game name for id2 is neither NULL nor 4 character long\n");
|
||||
ASSERTMSGLINE(86, company2, "DVDCompareDiskID(): Specified company name for id2 is NULL\n");
|
||||
ASSERTMSGLINE(87, company2[1] != 0, "DVDCompareDiskID(): Specified company name for id2 is not 2 character long\n");
|
||||
ASSERTMSGLINE(88, diskNum2 == 0xFF || ((diskNum2 / 16) < 10 && diskNum2 % 16 < 10), "DVDCompareDiskID(): Specified disk number for id2 is neither 0xff nor a BCD number");
|
||||
ASSERTMSGLINE(89, version2 == 0xFF || ((version2 / 16) < 10 && version2 % 16 < 10), "DVDCompareDiskID(): Specified version number for id2 is neither 0xff nor a BCD number");
|
||||
#endif
|
||||
|
||||
if (id1->game_name[0] != 0 && id2->game_name[0] != 0 && strncmp(id1->game_name, id2->game_name, 4) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (id1->company[0] == 0 || id2->company[0] == 0 || strncmp(id1->company, id2->company, 2) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (id1->disk_number != 0xFF && id2->disk_number != 0xFF && id1->disk_number != id2->disk_number) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (id1->game_version != 0xFF && id2->game_version != 0xFF && id1->game_version != id2->game_version) {
|
||||
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->game_name, game, 4);
|
||||
}
|
||||
|
||||
if (company != NULL) {
|
||||
strncpy(id->company, company, 2);
|
||||
}
|
||||
|
||||
id->disk_number = diskNum;
|
||||
id->game_version = version;
|
||||
return id;
|
||||
}
|
||||
@@ -0,0 +1,544 @@
|
||||
#include "dolphin/dvd/dvdlow.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
static BOOL FirstRead = TRUE;
|
||||
static volatile BOOL StopAtNextInt = FALSE;
|
||||
static u32 LastLength = 0;
|
||||
static DVDLowCallback Callback = NULL;
|
||||
static DVDLowCallback ResetCoverCallback = NULL;
|
||||
static volatile OSTime LastResetEnd = 0;
|
||||
static volatile u32 ResetOccurred = FALSE;
|
||||
static volatile BOOL WaitingCoverClose = FALSE;
|
||||
static volatile BOOL Breaking = FALSE;
|
||||
static volatile u32 WorkAroundType = 0;
|
||||
static u32 WorkAroundSeekLocation = 0;
|
||||
static volatile OSTime LastReadFinished = 0;
|
||||
static OSTime LastReadIssued = 0;
|
||||
static volatile BOOL LastCommandWasRead = FALSE;
|
||||
static volatile u32 NextCommandNumber = 0;
|
||||
|
||||
typedef struct {
|
||||
void* addr;
|
||||
u32 length;
|
||||
u32 offset;
|
||||
} DVDBuffer;
|
||||
|
||||
typedef struct {
|
||||
s32 cmd;
|
||||
void* addr;
|
||||
u32 length;
|
||||
u32 offset;
|
||||
DVDLowCallback callback;
|
||||
} DVDCommand;
|
||||
|
||||
static DVDCommand CommandList[3];
|
||||
static OSAlarm AlarmForWA;
|
||||
static OSAlarm AlarmForTimeout;
|
||||
static OSAlarm AlarmForBreak;
|
||||
static DVDBuffer Prev;
|
||||
static DVDBuffer Curr;
|
||||
|
||||
void __DVDInitWA()
|
||||
{
|
||||
NextCommandNumber = 0;
|
||||
CommandList[0].cmd = -1;
|
||||
__DVDLowSetWAType(0, 0);
|
||||
OSInitAlarm();
|
||||
}
|
||||
|
||||
static void Read(void* addr, u32 length, u32 offset, DVDLowCallback callback);
|
||||
|
||||
static BOOL ProcessNextCommand()
|
||||
{
|
||||
s32 n = NextCommandNumber;
|
||||
|
||||
ASSERTLINE(0x127, n < 3);
|
||||
if (CommandList[n].cmd == 1) {
|
||||
++NextCommandNumber;
|
||||
Read(CommandList[n].addr, CommandList[n].length, CommandList[n].offset, CommandList[n].callback);
|
||||
return TRUE;
|
||||
} else if (CommandList[n].cmd == 2) {
|
||||
++NextCommandNumber;
|
||||
DVDLowSeek(CommandList[n].offset, CommandList[n].callback);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void __DVDInterruptHandler(__OSInterrupt interrupt, OSContext* context)
|
||||
{
|
||||
DVDLowCallback cb;
|
||||
OSContext exceptionContext;
|
||||
u32 cause = 0;
|
||||
u32 reg;
|
||||
u32 intr;
|
||||
u32 mask;
|
||||
|
||||
if (LastCommandWasRead) {
|
||||
LastReadFinished = __OSGetSystemTime();
|
||||
FirstRead = FALSE;
|
||||
Prev.addr = Curr.addr;
|
||||
Prev.length = Curr.length;
|
||||
Prev.offset = Curr.offset;
|
||||
if (StopAtNextInt == TRUE) {
|
||||
cause |= 8;
|
||||
}
|
||||
}
|
||||
|
||||
LastCommandWasRead = FALSE;
|
||||
StopAtNextInt = FALSE;
|
||||
reg = __DIRegs[0];
|
||||
mask = reg & 0x2a;
|
||||
intr = (reg & 0x54) & (mask << 1);
|
||||
|
||||
if (intr & 0x40) {
|
||||
cause |= 8;
|
||||
}
|
||||
|
||||
if (intr & 0x10) {
|
||||
cause |= 1;
|
||||
}
|
||||
|
||||
if (intr & 4) {
|
||||
cause |= 2;
|
||||
}
|
||||
|
||||
if (cause) {
|
||||
ResetOccurred = FALSE;
|
||||
OSCancelAlarm(&AlarmForTimeout);
|
||||
}
|
||||
|
||||
__DIRegs[0] = intr | mask;
|
||||
|
||||
if (ResetOccurred && (__OSGetSystemTime() - LastResetEnd) < OSMillisecondsToTicks(200)) {
|
||||
reg = __DIRegs[1];
|
||||
mask = reg & 0x2;
|
||||
intr = (reg & 4) & (mask << 1);
|
||||
if (intr & 4) {
|
||||
if (ResetCoverCallback) {
|
||||
ResetCoverCallback(4);
|
||||
}
|
||||
ResetCoverCallback = NULL;
|
||||
}
|
||||
|
||||
__DIRegs[1] = __DIRegs[1];
|
||||
} else if (WaitingCoverClose) {
|
||||
reg = __DIRegs[1];
|
||||
mask = reg & 2;
|
||||
intr = (reg & 4) & (mask << 1);
|
||||
|
||||
if (intr & 4) {
|
||||
cause |= 4;
|
||||
}
|
||||
|
||||
__DIRegs[1] = intr | mask;
|
||||
WaitingCoverClose = FALSE;
|
||||
} else {
|
||||
__DIRegs[1] = 0;
|
||||
}
|
||||
|
||||
if ((cause & 8) && !Breaking) {
|
||||
cause &= ~8;
|
||||
}
|
||||
|
||||
if ((cause & 1)) {
|
||||
if (ProcessNextCommand()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
CommandList[0].cmd = -1;
|
||||
NextCommandNumber = 0;
|
||||
}
|
||||
|
||||
OSClearContext(&exceptionContext);
|
||||
OSSetCurrentContext(&exceptionContext);
|
||||
|
||||
if (cause) {
|
||||
cb = Callback;
|
||||
Callback = NULL;
|
||||
if (cb) {
|
||||
cb(cause);
|
||||
}
|
||||
|
||||
Breaking = FALSE;
|
||||
}
|
||||
|
||||
OSClearContext(&exceptionContext);
|
||||
OSSetCurrentContext(context);
|
||||
}
|
||||
|
||||
static void AlarmHandler(OSAlarm* alarm, OSContext* context) {
|
||||
BOOL processed = ProcessNextCommand();
|
||||
|
||||
ASSERTLINE(0x28A, processed);
|
||||
}
|
||||
|
||||
static void AlarmHandlerForTimeout(OSAlarm* alarm, OSContext* context)
|
||||
{
|
||||
OSContext tmpContext;
|
||||
DVDLowCallback callback;
|
||||
__OSMaskInterrupts(0x400);
|
||||
OSClearContext(&tmpContext);
|
||||
OSSetCurrentContext(&tmpContext);
|
||||
callback = Callback;
|
||||
Callback = NULL;
|
||||
if (callback) {
|
||||
callback(0x10);
|
||||
}
|
||||
OSClearContext(&tmpContext);
|
||||
OSSetCurrentContext(context);
|
||||
}
|
||||
|
||||
static void SetTimeoutAlarm(OSTime timeout)
|
||||
{
|
||||
OSCreateAlarm(&AlarmForTimeout);
|
||||
OSSetAlarm(&AlarmForTimeout, timeout, AlarmHandlerForTimeout);
|
||||
}
|
||||
|
||||
static void Read(void* addr, u32 length, u32 offset, DVDLowCallback callback)
|
||||
{
|
||||
Callback = callback;
|
||||
StopAtNextInt = FALSE;
|
||||
LastCommandWasRead = TRUE;
|
||||
LastReadIssued = __OSGetSystemTime();
|
||||
|
||||
__DIRegs[2] = 0xa8000000;
|
||||
__DIRegs[3] = offset / 4;
|
||||
__DIRegs[4] = length;
|
||||
__DIRegs[5] = (u32)addr;
|
||||
__DIRegs[6] = length;
|
||||
LastLength = length;
|
||||
__DIRegs[7] = 3;
|
||||
|
||||
if (length > 0xa00000) {
|
||||
SetTimeoutAlarm(OSSecondsToTicks(20));
|
||||
} else {
|
||||
SetTimeoutAlarm(OSSecondsToTicks(10));
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL AudioBufferOn(void)
|
||||
{
|
||||
DVDDiskID* id;
|
||||
|
||||
id = DVDGetCurrentDiskID();
|
||||
if (id->is_streaming) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL HitCache(DVDBuffer* cur, DVDBuffer* prev)
|
||||
{
|
||||
u32 uVar1 = (prev->offset + prev->length - 1) >> 15;
|
||||
u32 uVar2 = (cur->offset >> 15);
|
||||
u32 iVar3 = AudioBufferOn() ? 5 : 15;
|
||||
|
||||
if ((uVar2 > uVar1 - 2) || (uVar2 < uVar1 + iVar3 + 3)) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void DoJustRead(void* addr, u32 length, u32 offset, DVDLowCallback callback)
|
||||
{
|
||||
CommandList[0].cmd = -1;
|
||||
NextCommandNumber = 0;
|
||||
Read(addr, length, offset, callback);
|
||||
}
|
||||
|
||||
static void SeekTwiceBeforeRead(void* addr, u32 length, u32 offset, DVDLowCallback callback)
|
||||
{
|
||||
u32 newOffset;
|
||||
if ((offset & ~0x7FFF) == 0) {
|
||||
newOffset = 0;
|
||||
} else {
|
||||
newOffset = (offset & ~0x7FFF) + WorkAroundSeekLocation;
|
||||
}
|
||||
CommandList[0].cmd = 2;
|
||||
CommandList[0].offset = newOffset;
|
||||
CommandList[0].callback = callback;
|
||||
CommandList[1].cmd = 1;
|
||||
CommandList[1].addr = addr;
|
||||
CommandList[1].length = length;
|
||||
CommandList[1].offset = offset;
|
||||
CommandList[1].callback = callback;
|
||||
CommandList[2].cmd = -1;
|
||||
NextCommandNumber = 0;
|
||||
DVDLowSeek(newOffset, callback);
|
||||
}
|
||||
|
||||
static void WaitBeforeRead(void* addr, u32 length, u32 offset, DVDLowCallback callback, OSTime timeout)
|
||||
{
|
||||
CommandList[0].cmd = 1;
|
||||
CommandList[0].addr = addr;
|
||||
CommandList[0].length = length;
|
||||
CommandList[0].offset = offset;
|
||||
CommandList[0].callback = callback;
|
||||
CommandList[1].cmd = -1;
|
||||
NextCommandNumber = 0;
|
||||
OSCreateAlarm(&AlarmForWA);
|
||||
OSSetAlarm(&AlarmForWA, timeout, AlarmHandler);
|
||||
}
|
||||
|
||||
BOOL DVDLowRead(void* addr, u32 length, u32 offset, DVDLowCallback callback)
|
||||
{
|
||||
u32 blockNumOfPrevEnd;
|
||||
u32 blockNumOfCurrStart;
|
||||
OSTime diff;
|
||||
|
||||
ASSERTMSGLINE(0x341, (((u32)addr) & 31) == 0, "DVDLowRead(): address must be aligned with 32 byte boundary.");
|
||||
ASSERTMSGLINE(0x342, (length & 31) == 0, "DVDLowRead(): length must be a multiple of 32.");
|
||||
ASSERTMSGLINE(0x343, (offset & 3) == 0, "DVDLowRead(): offset must be a multiple of 4.");
|
||||
ASSERTMSGLINE(0x345, length != 0, "DVD read: 0 was specified to length of the read\n");
|
||||
|
||||
__DIRegs[6] = length;
|
||||
Curr.addr = addr;
|
||||
Curr.length = length;
|
||||
Curr.offset = offset;
|
||||
|
||||
if (WorkAroundType == 0) {
|
||||
DoJustRead(addr, length, offset, callback);
|
||||
} else if (WorkAroundType == 1) {
|
||||
if (FirstRead) {
|
||||
SeekTwiceBeforeRead(addr, length, offset, callback);
|
||||
} else {
|
||||
if (!HitCache(&Curr, &Prev)) {
|
||||
DoJustRead(addr, length, offset, callback);
|
||||
} else {
|
||||
blockNumOfPrevEnd = (u32)((Prev.offset + Prev.length - 1) >> 15) & 0x1FFFF;
|
||||
blockNumOfCurrStart = (u32)((Curr.offset >> 15) & 0x1FFFF);
|
||||
if (blockNumOfPrevEnd == blockNumOfCurrStart || blockNumOfPrevEnd + 1 == blockNumOfCurrStart) {
|
||||
diff = __OSGetSystemTime() - LastReadFinished;
|
||||
if (OSMillisecondsToTicks(5) < diff) {
|
||||
DoJustRead(addr, length, offset, callback);
|
||||
} else {
|
||||
WaitBeforeRead(addr, length, offset, callback, OSMillisecondsToTicks(5) - diff + OSMicrosecondsToTicks(500));
|
||||
}
|
||||
} else {
|
||||
SeekTwiceBeforeRead(addr, length, offset, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ASSERTLINE(0x380, FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DVDLowSeek(u32 offset, DVDLowCallback callback)
|
||||
{
|
||||
ASSERTMSGLINE(0x394, (offset & 3) == 0, "DVDLowSeek(): offset must be a multiple of 4.");
|
||||
|
||||
Callback = callback;
|
||||
StopAtNextInt = FALSE;
|
||||
__DIRegs[2] = 0xab000000;
|
||||
__DIRegs[3] = offset / 4;
|
||||
__DIRegs[7] = 1;
|
||||
SetTimeoutAlarm(OSSecondsToTicks(10));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DVDLowWaitCoverClose(DVDLowCallback callback)
|
||||
{
|
||||
Callback = callback;
|
||||
WaitingCoverClose = TRUE;
|
||||
StopAtNextInt = FALSE;
|
||||
__DIRegs[1] = 2;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DVDLowReadDiskID(DVDDiskID* diskID, DVDLowCallback callback)
|
||||
{
|
||||
ASSERTMSGLINE(0x3d2, (((u32)diskID) & 31) == 0, "DVDLowReadID(): id must be aligned with 32 byte boundary.");
|
||||
|
||||
Callback = callback;
|
||||
StopAtNextInt = FALSE;
|
||||
__DIRegs[2] = 0xa8000040;
|
||||
__DIRegs[3] = 0;
|
||||
__DIRegs[4] = sizeof(DVDDiskID);
|
||||
__DIRegs[5] = (u32)diskID;
|
||||
__DIRegs[6] = sizeof(DVDDiskID);
|
||||
__DIRegs[7] = 3;
|
||||
SetTimeoutAlarm(OSSecondsToTicks(10));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DVDLowStopMotor(DVDLowCallback callback)
|
||||
{
|
||||
Callback = callback;
|
||||
StopAtNextInt = FALSE;
|
||||
__DIRegs[2] = 0xe3000000;
|
||||
__DIRegs[7] = 1;
|
||||
SetTimeoutAlarm(OSSecondsToTicks(10));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DVDLowRequestError(DVDLowCallback callback)
|
||||
{
|
||||
Callback = callback;
|
||||
StopAtNextInt = FALSE;
|
||||
__DIRegs[2] = 0xe0000000;
|
||||
__DIRegs[7] = 1;
|
||||
SetTimeoutAlarm(OSSecondsToTicks(10));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DVDLowInquiry(DVDDriveInfo* info, DVDLowCallback callback)
|
||||
{
|
||||
Callback = callback;
|
||||
StopAtNextInt = FALSE;
|
||||
__DIRegs[2] = 0x12000000;
|
||||
__DIRegs[4] = sizeof(DVDDriveInfo);
|
||||
__DIRegs[5] = (u32)info;
|
||||
__DIRegs[6] = sizeof(DVDDriveInfo);
|
||||
__DIRegs[7] = 3;
|
||||
SetTimeoutAlarm(OSSecondsToTicks(10));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DVDLowAudioStream(u32 subcmd, u32 length, u32 offset, DVDLowCallback callback)
|
||||
{
|
||||
Callback = callback;
|
||||
StopAtNextInt = FALSE;
|
||||
__DIRegs[2] = subcmd | 0xe1000000;
|
||||
__DIRegs[3] = offset >> 2;
|
||||
__DIRegs[4] = length;
|
||||
__DIRegs[7] = 1;
|
||||
SetTimeoutAlarm(OSSecondsToTicks(10));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DVDLowRequestAudioStatus(u32 subcmd, DVDLowCallback callback)
|
||||
{
|
||||
Callback = callback;
|
||||
StopAtNextInt = FALSE;
|
||||
__DIRegs[2] = subcmd | 0xe2000000;
|
||||
__DIRegs[7] = 1;
|
||||
SetTimeoutAlarm(OSSecondsToTicks(10));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL DVDLowAudioBufferConfig(BOOL enable, u32 size, DVDLowCallback callback)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
u32 bufSize;
|
||||
u32 trigger;
|
||||
#endif
|
||||
|
||||
Callback = callback;
|
||||
StopAtNextInt = FALSE;
|
||||
|
||||
#ifdef DEBUG
|
||||
bufSize = size & 0xF;
|
||||
trigger = (size >> 4) & 0xF;
|
||||
ASSERTLINE(0x4BD, bufSize < 16);
|
||||
ASSERTLINE(0x4BE, trigger <= 2);
|
||||
#endif
|
||||
|
||||
__DIRegs[2] = 0xe4000000 | (enable != 0 ? 0x10000 : 0) | size;
|
||||
__DIRegs[7] = 1;
|
||||
SetTimeoutAlarm(OSSecondsToTicks(10));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void DVDLowReset()
|
||||
{
|
||||
u32 reg;
|
||||
OSTime resetStart;
|
||||
|
||||
__DIRegs[1] = 2;
|
||||
reg = __PIRegs[9];
|
||||
__PIRegs[9] = (reg & ~4) | 1;
|
||||
|
||||
resetStart = __OSGetSystemTime();
|
||||
while ((__OSGetSystemTime() - resetStart) < OSMicrosecondsToTicks(12))
|
||||
;
|
||||
|
||||
__PIRegs[9] = reg | 4 | 1;
|
||||
ResetOccurred = TRUE;
|
||||
LastResetEnd = __OSGetSystemTime();
|
||||
}
|
||||
|
||||
DVDLowCallback DVDLowSetResetCoverCallback(DVDLowCallback callback)
|
||||
{
|
||||
DVDLowCallback old;
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
old = ResetCoverCallback;
|
||||
ResetCoverCallback = callback;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return old;
|
||||
}
|
||||
|
||||
static void DoBreak(void)
|
||||
{
|
||||
u32 statusReg;
|
||||
|
||||
statusReg = __DIRegs[0];
|
||||
statusReg |= 0x40 | 1;
|
||||
__DIRegs[0] = statusReg;
|
||||
Breaking = TRUE;
|
||||
}
|
||||
|
||||
static void SetBreakAlarm(OSTime timeout);
|
||||
|
||||
static void AlarmHandlerForBreak(OSAlarm* alarm, OSContext* context)
|
||||
{
|
||||
if (__DIRegs[6] < LastLength) {
|
||||
DoBreak();
|
||||
} else {
|
||||
SetBreakAlarm(OSMillisecondsToTicks(20));
|
||||
}
|
||||
}
|
||||
|
||||
static void SetBreakAlarm(OSTime timeout)
|
||||
{
|
||||
OSCreateAlarm(&AlarmForBreak);
|
||||
OSSetAlarm(&AlarmForBreak, timeout, AlarmHandlerForBreak);
|
||||
}
|
||||
|
||||
BOOL DVDLowBreak()
|
||||
{
|
||||
StopAtNextInt = TRUE;
|
||||
Breaking = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DVDLowCallback DVDLowClearCallback()
|
||||
{
|
||||
DVDLowCallback old;
|
||||
__DIRegs[1] = 0;
|
||||
old = Callback;
|
||||
Callback = NULL;
|
||||
return old;
|
||||
}
|
||||
|
||||
u32 DVDLowGetCoverStatus(void)
|
||||
{
|
||||
if ((__OSGetSystemTime() - LastResetEnd) < OSMillisecondsToTicks(100)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (__DIRegs[1] & 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
void __DVDLowSetWAType(u32 type, u32 location)
|
||||
{
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
ASSERTLINE(0x5B1, type < DVD_WATYPE_MAX);
|
||||
WorkAroundType = type;
|
||||
WorkAroundSeekLocation = location;
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
#include "dolphin/dvd/dvdqueue.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
static struct {
|
||||
/* 0x00 */ struct DVDCommandBlock * next;
|
||||
/* 0x04 */ struct DVDCommandBlock * prev;
|
||||
} WaitingQueue[4];
|
||||
|
||||
static struct DVDCommandBlock * PopWaitingQueuePrio(long prio);
|
||||
|
||||
void __DVDClearWaitingQueue(void) {
|
||||
unsigned long i;
|
||||
struct DVDCommandBlock * q;
|
||||
|
||||
for(i = 0; i < 4; i++) {
|
||||
q = (struct DVDCommandBlock *)&WaitingQueue[i].next;
|
||||
q->next = q;
|
||||
q->prev = q;
|
||||
}
|
||||
}
|
||||
|
||||
int __DVDPushWaitingQueue(long prio, struct DVDCommandBlock * block) {
|
||||
int enabled = OSDisableInterrupts();
|
||||
struct DVDCommandBlock * q = (struct DVDCommandBlock *)&WaitingQueue[prio];
|
||||
|
||||
q->prev->next = block;
|
||||
block->prev = q->prev;
|
||||
block->next = q;
|
||||
q->prev = block;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct DVDCommandBlock * PopWaitingQueuePrio(long prio) {
|
||||
struct DVDCommandBlock * tmp;
|
||||
int enabled;
|
||||
struct DVDCommandBlock * q;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
q = (struct DVDCommandBlock *)&WaitingQueue[prio];
|
||||
ASSERTLINE(0x57, q->next != q);
|
||||
tmp = q->next;
|
||||
q->next = tmp->next;
|
||||
tmp->next->prev = q;
|
||||
OSRestoreInterrupts(enabled);
|
||||
tmp->next = 0;
|
||||
tmp->prev = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
struct DVDCommandBlock * __DVDPopWaitingQueue(void) {
|
||||
unsigned long i;
|
||||
int enabled;
|
||||
struct DVDCommandBlock * q;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
for(i = 0; i < 4; i++) {
|
||||
q = (struct DVDCommandBlock *)&WaitingQueue[i];
|
||||
if (q->next != q) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return PopWaitingQueuePrio(i);
|
||||
}
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int __DVDCheckWaitingQueue(void) {
|
||||
unsigned long i;
|
||||
int enabled;
|
||||
struct DVDCommandBlock * q;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
for(i = 0; i < 4; i++) {
|
||||
q = (struct DVDCommandBlock *)&WaitingQueue[i];
|
||||
if (q->next != q) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __DVDDequeueWaitingQueue(struct DVDCommandBlock * block) {
|
||||
int enabled;
|
||||
struct DVDCommandBlock * prev;
|
||||
struct 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(struct DVDCommandBlock * block) {
|
||||
unsigned long i;
|
||||
struct DVDCommandBlock * start;
|
||||
struct DVDCommandBlock * q;
|
||||
|
||||
for(i = 0; i < 4; i++) {
|
||||
start = (struct 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) {
|
||||
unsigned long i;
|
||||
struct DVDCommandBlock * start;
|
||||
struct DVDCommandBlock * q;
|
||||
|
||||
OSReport("==== DVD Waiting Queue Status ====\n");
|
||||
for(i = 0; i < 4; i++) {
|
||||
OSReport("< Queue #%d > ", i);
|
||||
start = (struct 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->buffer);
|
||||
} else {
|
||||
OSReport("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#include "dolphin/dvd/fstload.h"
|
||||
#include "dolphin/os/OS.h"
|
||||
|
||||
// .bss
|
||||
static unsigned char bb2Buf[63]; // size: 0x3F, address: 0x0
|
||||
|
||||
// .sbss
|
||||
static unsigned long status; // size: 0x4, address: 0x0
|
||||
static struct DVDBB2 * bb2; // size: 0x4, address: 0x4
|
||||
static struct DVDDiskID * idTmp; // size: 0x4, address: 0x8
|
||||
|
||||
// functions
|
||||
static void cb(long result, struct DVDCommandBlock * block);
|
||||
void __fstLoad();
|
||||
|
||||
static void cb(long result, struct DVDCommandBlock * block) {
|
||||
if (result > 0) {
|
||||
switch(status) {
|
||||
case 0:
|
||||
status = 1;
|
||||
DVDReadAbsAsyncForBS(block, bb2, 0x20, 0x420, cb);
|
||||
return;
|
||||
case 1:
|
||||
status = 2;
|
||||
DVDReadAbsAsyncForBS(block, bb2->FSTAddress, (bb2->FSTLength + 0x1F) & 0xFFFFFFE0, bb2->FSTPosition, cb);
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (result == -1) {
|
||||
return;
|
||||
} else if (result == -4) {
|
||||
status = 0;
|
||||
DVDReset();
|
||||
DVDReadDiskID(block, idTmp, cb);
|
||||
}
|
||||
}
|
||||
|
||||
void __fstLoad() {
|
||||
struct OSBootInfo * bootInfo;
|
||||
struct DVDDiskID * id;
|
||||
unsigned char idTmpBuf[63];
|
||||
long state;
|
||||
void * arenaHi;
|
||||
static struct DVDCommandBlock block;
|
||||
|
||||
arenaHi = OSGetArenaHi();
|
||||
bootInfo = (void*)OSPhysicalToCached(0);
|
||||
idTmp = (void*)OSRoundUp32B(idTmpBuf);
|
||||
bb2 = (void*)OSRoundUp32B(bb2Buf);
|
||||
DVDReset();
|
||||
DVDReadDiskID(&block, idTmp, cb);
|
||||
while (1) {
|
||||
state = DVDGetDriveStatus();
|
||||
if (state == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// weird switch that seemingly wont do anything but break out of its own switch. What was this for? Early DVD development pre-hardware?
|
||||
switch(state) {
|
||||
case DVD_STATE_FATAL_ERROR: break;
|
||||
case DVD_STATE_BUSY: break;
|
||||
case DVD_STATE_WAITING: break;
|
||||
case DVD_STATE_COVER_CLOSED: break;
|
||||
case DVD_STATE_NO_DISK: break;
|
||||
case DVD_STATE_COVER_OPEN: break;
|
||||
case DVD_STATE_MOTOR_STOPPED: break;
|
||||
}
|
||||
}
|
||||
bootInfo->fst_location = (void*)bb2->FSTAddress;
|
||||
bootInfo->fst_max_length = bb2->FSTMaxLength;
|
||||
id = &bootInfo->disk_info;
|
||||
memcpy(id, idTmp, 0x20);
|
||||
OSReport("\n");
|
||||
OSReport(" Game Name ... %c%c%c%c\n", id->game_name[0], id->game_name[1], id->game_name[2], id->game_name[3]);
|
||||
OSReport(" Company ..... %c%c\n", id->company[0], id->company[1]);
|
||||
OSReport(" Disk # ...... %d\n", id->disk_number);
|
||||
OSReport(" Game ver .... %d\n", id->game_version);
|
||||
OSReport(" Streaming ... %s\n", !(id->is_streaming) ? "OFF" : "ON");
|
||||
OSReport("\n");
|
||||
OSSetArenaHi(bb2->FSTAddress);
|
||||
}
|
||||
Reference in New Issue
Block a user