dolphin/dvd OK

This commit is contained in:
LagoLunatic
2025-03-16 21:52:11 -04:00
parent c91ade372a
commit 6acb5f801b
16 changed files with 3545 additions and 8 deletions
+8 -8
View File
@@ -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(
+63
View File
@@ -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
+3
View File
@@ -1,5 +1,8 @@
#ifndef DVDERROR_H
#define DVDERROR_H
#include "dolphin/types.h"
void __DVDStoreErrorCode(u32 error);
#endif /* DVDERROR_H */
+4
View File
@@ -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 */
+6
View File
@@ -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 */
+6
View File
@@ -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
View File
@@ -1,5 +1,6 @@
#ifndef FSTLOAD_H
#define FSTLOAD_H
void __fstLoad();
#endif /* FSTLOAD_H */
+6
View File
@@ -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
+94
View File
@@ -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();
}
}
+74
View File
@@ -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);
}
+664
View File
@@ -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;
}
+95
View File
@@ -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;
}
+544
View File
@@ -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);
}
+164
View File
@@ -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");
}
}
}
}
}
+82
View File
@@ -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);
}