Merge pull request #442 from gamemasterplc/main

Link in arq and most of dvd
This commit is contained in:
Liam Coleman 2024-11-10 18:28:44 -06:00 committed by GitHub
commit 2438b1119a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 1487 additions and 10 deletions

View file

@ -3911,7 +3911,7 @@ lbl_8012E70A = .data:0x8012E70A; // type:object size:0xB data:string
lbl_8012E715 = .data:0x8012E715; // type:object size:0x273
lbl_8012E988 = .data:0x8012E988; // type:object size:0x12 data:string
lbl_8012E99A = .data:0x8012E99A; // type:object size:0xD6
HuSndGrpTbl = .data:0x8012EA70; // type:object size:0x5B0
sndGrpTable = .data:0x8012EA70; // type:object size:0x5B0
lbl_8012F020 = .data:0x8012F020; // type:object size:0x94
lbl_8012F0B4 = .data:0x8012F0B4; // type:object size:0x11 data:string
lbl_8012F0C5 = .data:0x8012F0C5; // type:object size:0x3A
@ -5692,7 +5692,7 @@ shdwChanged = .sbss:0x801D4460; // type:object size:0x8 scope:local align:8 data
CurrTiming = .sbss:0x801D4468; // type:object size:0x4 scope:local data:4byte
CurrTvMode = .sbss:0x801D446C; // type:object size:0x4 scope:local data:4byte
FBSet = .sbss:0x801D4470; // type:object size:0x4 scope:local data:4byte
message$343 = .sbss:0x801D4474; // type:object size:0x4 scope:local data:4byte
message$320 = .sbss:0x801D4474; // type:object size:0x4 scope:local data:4byte
rmode = .sbss:0x801D4478; // type:object size:0x8 scope:local data:4byte
fontShift = .sbss:0x801D4480; // type:object size:0x8 scope:local data:4byte
DemoStat = .sbss:0x801D4488; // type:object size:0x4 scope:local data:4byte

View file

@ -494,18 +494,18 @@ config.libs = [
DolphinLib(
"dvd",
[
Object(NonMatching, "dolphin/dvd/dvdlow.c"),
Object(NonMatching, "dolphin/dvd/dvdfs.c"),
Object(Matching, "dolphin/dvd/dvdlow.c"),
Object(Matching, "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/fstload.c"),
Object(Matching, "dolphin/dvd/dvdqueue.c"),
Object(Matching, "dolphin/dvd/dvderror.c"),
Object(Matching, "dolphin/dvd/fstload.c"),
],
),
DolphinLib(
"vi",
[
Object(NonMatching, "dolphin/vi.c"),
Object(Matching, "dolphin/vi.c"),
],
),
DolphinLib(
@ -534,7 +534,7 @@ config.libs = [
"ar",
[
Object(NonMatching, "dolphin/ar/ar.c"),
Object(NonMatching, "dolphin/ar/arq.c"),
Object(Matching, "dolphin/ar/arq.c"),
],
),
DolphinLib(

View file

@ -4,7 +4,7 @@
#include "dolphin/DVDPriv.h"
#include "dolphin/types.h"
typedef struct OSBootInfo {
typedef struct OSBootInfo_s {
DVDDiskID DVDDiskID;
u32 magic;
u32 version;

251
src/dolphin/ar/ar.c Normal file
View file

@ -0,0 +1,251 @@
#include "dolphin/ar.h"
#include "dolphin/hw_regs.h"
#include "dolphin/os.h"
static ARCallback __AR_Callback;
static u32 __AR_Size;
static u32 __AR_InternalSize;
static u32 __AR_ExpansionSize;
static u32 __AR_StackPointer;
static u32 __AR_FreeBlocks;
static u32* __AR_BlockLength;
static volatile BOOL __AR_init_flag = FALSE;
static void __ARHandler(__OSInterrupt interrupt, OSContext* context);
static void __ARChecksize(void);
static void __ARClearArea(u32 start_addr, u32 length);
ARCallback ARRegisterDMACallback(ARCallback callback) {
ARCallback oldCb;
BOOL enabled;
oldCb = __AR_Callback;
enabled = OSDisableInterrupts();
__AR_Callback = callback;
OSRestoreInterrupts(enabled);
return oldCb;
}
u32 ARGetDMAStatus() {
BOOL enabled;
u32 val;
enabled = OSDisableInterrupts();
val = __DSPRegs[5] & 0x0200;
OSRestoreInterrupts(enabled);
return val;
}
void ARStartDMA(u32 type, u32 mainmem_addr, u32 aram_addr, u32 length) {
BOOL enabled;
enabled = OSDisableInterrupts();
__DSPRegs[16] = (u16)(__DSPRegs[16] & ~0x3ff) | (u16)(mainmem_addr >> 16);
__DSPRegs[17] = (u16)(__DSPRegs[17] & ~0xffe0) | (u16)(mainmem_addr & 0xffff);
__DSPRegs[18] = (u16)(__DSPRegs[18] & ~0x3ff) | (u16)(aram_addr >> 16);
__DSPRegs[19] = (u16)(__DSPRegs[19] & ~0xffe0) | (u16)(aram_addr & 0xffff);
__DSPRegs[20] = (u16)((__DSPRegs[20] & ~0x8000) | (type << 15));
__DSPRegs[20] = (u16)(__DSPRegs[20] & ~0x3ff) | (u16)(length >> 16);
__DSPRegs[21] = (u16)(__DSPRegs[21] & ~0xffe0) | (u16)(length & 0xffff);
OSRestoreInterrupts(enabled);
}
u32 ARAlloc(u32 length) {
u32 tmp;
BOOL enabled;
enabled = OSDisableInterrupts();
tmp = __AR_StackPointer;
__AR_StackPointer += length;
*__AR_BlockLength = length;
__AR_BlockLength++;
__AR_FreeBlocks--;
OSRestoreInterrupts(enabled);
return tmp;
}
#if NONMATCHING
u32 ARFree(u32* length) {
BOOL old;
old = OSDisableInterrupts();
__AR_BlockLength--;
if (length) {
*length = *__AR_BlockLength;
}
__AR_StackPointer -= *__AR_BlockLength;
__AR_FreeBlocks++;
OSRestoreInterrupts(old);
return __AR_StackPointer;
}
#else
/* clang-format off */
#pragma push
#pragma optimization_level 0
#pragma optimizewithasm off
asm u32 ARFree(u32* length) {
nofralloc
mflr r0
stw r0, 4(r1)
stwu r1, -0x18(r1)
stw r31, 0x14(r1)
mr r31, r3
bl OSDisableInterrupts
lwz r4, __AR_BlockLength
cmplwi r31, 0
addi r0, r4, -4
stw r0, __AR_BlockLength
beq lbl_8036DAB4
lwz r4, __AR_BlockLength
lwz r0, 0(r4)
stw r0, 0(r31)
lbl_8036DAB4:
lwz r5, __AR_BlockLength
lwz r4, __AR_FreeBlocks
lwz r6, 0(r5)
addi r0, r4, 1
lwz r5, __AR_StackPointer
stw r0, __AR_FreeBlocks
subf r0, r6, r5
stw r0, __AR_StackPointer
bl OSRestoreInterrupts
lwz r3, __AR_StackPointer
lwz r0, 0x1c(r1)
lwz r31, 0x14(r1)
addi r1, r1, 0x18
mtlr r0
blr
}
#pragma pop
/* clang-format on */
#endif
BOOL ARCheckInit() { return __AR_init_flag; }
u32 ARInit(u32* stack_index_addr, u32 num_entries) {
BOOL old;
u16 refresh;
if (__AR_init_flag == TRUE) {
return 0x4000;
}
old = OSDisableInterrupts();
__AR_Callback = NULL;
__OSSetInterruptHandler(__OS_INTERRUPT_DSP_ARAM, __ARHandler);
__OSUnmaskInterrupts(OS_INTERRUPTMASK_DSP_ARAM);
__AR_StackPointer = 0x4000;
__AR_FreeBlocks = num_entries;
__AR_BlockLength = stack_index_addr;
refresh = (u16)(__DSPRegs[13] & 0x000000ff);
__DSPRegs[13] = (u16)((__DSPRegs[13] & ~0x000000ff) | (refresh & 0x000000ff));
__ARChecksize();
__AR_init_flag = TRUE;
OSRestoreInterrupts(old);
return __AR_StackPointer;
}
u32 ARGetBaseAddress(void) { return 0x4000; }
void ARSetSize(void)
{
}
u32 ARGetSize() { return __AR_Size; }
static void __ARHandler(__OSInterrupt interrupt, OSContext* context) {
OSContext exceptionContext;
u16 tmp;
tmp = __DSPRegs[5];
tmp = (u16)((tmp & ~0x00000088) | 0x20);
__DSPRegs[5] = tmp;
OSClearContext(&exceptionContext);
OSSetCurrentContext(&exceptionContext);
if (__AR_Callback) {
(*__AR_Callback)();
}
OSClearContext(&exceptionContext);
OSSetCurrentContext(context);
}
#define RoundUP32(x) (((u32)(x) + 32 - 1) & ~(32 - 1))
void __ARClearInterrupt(void) {
u16 tmp;
tmp = __DSPRegs[5];
tmp = (u16)((tmp & ~(0x00000080 | 0x00000008)) | 0x00000020);
__DSPRegs[5] = tmp;
}
u16 __ARGetInterruptStatus(void) { return ((u16)(__DSPRegs[5] & 0x0200)); }
static void __ARWaitForDMA(void) {
while (__DSPRegs[5] & 0x0200) {
}
}
static void __ARWriteDMA(u32 mmem_addr, u32 aram_addr, u32 length) {
__DSPRegs[16] = (u16)((__DSPRegs[16] & ~0x03ff) | (u16)(mmem_addr >> 16));
__DSPRegs[16 + 1] = (u16)((__DSPRegs[16 + 1] & ~0xffe0) | (u16)(mmem_addr & 0xffff));
__DSPRegs[18] = (u16)((__DSPRegs[18] & ~0x03ff) | (u16)(aram_addr >> 16));
__DSPRegs[18 + 1] = (u16)((__DSPRegs[18 + 1] & ~0xffe0) | (u16)(aram_addr & 0xffff));
__DSPRegs[20] = (u16)(__DSPRegs[20] & ~0x8000);
__DSPRegs[20] = (u16)((__DSPRegs[20] & ~0x03ff) | (u16)(length >> 16));
__DSPRegs[20 + 1] = (u16)((__DSPRegs[20 + 1] & ~0xffe0) | (u16)(length & 0xffff));
__ARWaitForDMA();
__ARClearInterrupt();
}
static void __ARReadDMA(u32 mmem_addr, u32 aram_addr, u32 length) {
__DSPRegs[16] = (u16)((__DSPRegs[16] & ~0x03ff) | (u16)(mmem_addr >> 16));
__DSPRegs[16 + 1] = (u16)((__DSPRegs[16 + 1] & ~0xffe0) | (u16)(mmem_addr & 0xffff));
__DSPRegs[18] = (u16)((__DSPRegs[18] & ~0x03ff) | (u16)(aram_addr >> 16));
__DSPRegs[18 + 1] = (u16)((__DSPRegs[18 + 1] & ~0xffe0) | (u16)(aram_addr & 0xffff));
__DSPRegs[20] = (u16)(__DSPRegs[20] | 0x8000);
__DSPRegs[20] = (u16)((__DSPRegs[20] & ~0x03ff) | (u16)(length >> 16));
__DSPRegs[20 + 1] = (u16)((__DSPRegs[20 + 1] & ~0xffe0) | (u16)(length & 0xffff));
__ARWaitForDMA();
__ARClearInterrupt();
}
static void __ARChecksize(void) {
//TODO: Implement for this SDK version
}

168
src/dolphin/ar/arq.c Normal file
View file

@ -0,0 +1,168 @@
#include "dolphin/arq.h"
#include "dolphin/os.h"
static ARQRequest* __ARQRequestQueueHi;
static ARQRequest* __ARQRequestTailHi;
static ARQRequest* __ARQRequestQueueLo;
static ARQRequest* __ARQRequestTailLo;
static ARQRequest* __ARQRequestPendingHi;
static ARQRequest* __ARQRequestPendingLo;
static ARQCallback __ARQCallbackHi;
static ARQCallback __ARQCallbackLo;
static u32 __ARQChunkSize;
static volatile BOOL __ARQ_init_flag = FALSE;
void __ARQPopTaskQueueHi(void);
void __ARQServiceQueueLo(void);
void __ARQCallbackHack(void);
void __ARQInterruptServiceRoutine(void);
void __ARQInitTempQueue(void);
void __ARQPushTempQueue(ARQRequest* task);
void __ARQPopTaskQueueHi(void) {
if (__ARQRequestQueueHi) {
if (__ARQRequestQueueHi->type == ARQ_TYPE_MRAM_TO_ARAM) {
ARStartDMA(__ARQRequestQueueHi->type, __ARQRequestQueueHi->source, __ARQRequestQueueHi->dest,
__ARQRequestQueueHi->length);
} else {
ARStartDMA(__ARQRequestQueueHi->type, __ARQRequestQueueHi->dest, __ARQRequestQueueHi->source,
__ARQRequestQueueHi->length);
}
__ARQCallbackHi = __ARQRequestQueueHi->callback;
__ARQRequestPendingHi = __ARQRequestQueueHi;
__ARQRequestQueueHi = __ARQRequestQueueHi->next;
}
}
void __ARQServiceQueueLo(void) {
if ((__ARQRequestPendingLo == NULL) && (__ARQRequestQueueLo)) {
__ARQRequestPendingLo = __ARQRequestQueueLo;
__ARQRequestQueueLo = __ARQRequestQueueLo->next;
}
if (__ARQRequestPendingLo) {
if (__ARQRequestPendingLo->length <= __ARQChunkSize) {
if (__ARQRequestPendingLo->type == ARQ_TYPE_MRAM_TO_ARAM)
ARStartDMA(__ARQRequestPendingLo->type, __ARQRequestPendingLo->source,
__ARQRequestPendingLo->dest, __ARQRequestPendingLo->length);
else
ARStartDMA(__ARQRequestPendingLo->type, __ARQRequestPendingLo->dest,
__ARQRequestPendingLo->source, __ARQRequestPendingLo->length);
__ARQCallbackLo = __ARQRequestPendingLo->callback;
} else {
if (__ARQRequestPendingLo->type == ARQ_TYPE_MRAM_TO_ARAM)
ARStartDMA(__ARQRequestPendingLo->type, __ARQRequestPendingLo->source,
__ARQRequestPendingLo->dest, __ARQChunkSize);
else
ARStartDMA(__ARQRequestPendingLo->type, __ARQRequestPendingLo->dest,
__ARQRequestPendingLo->source, __ARQChunkSize);
}
__ARQRequestPendingLo->length -= __ARQChunkSize;
__ARQRequestPendingLo->source += __ARQChunkSize;
__ARQRequestPendingLo->dest += __ARQChunkSize;
}
}
void __ARQCallbackHack(void) { return; }
void __ARQInterruptServiceRoutine(void) {
if (__ARQCallbackHi) {
(*__ARQCallbackHi)((u32)__ARQRequestPendingHi);
__ARQRequestPendingHi = NULL;
__ARQCallbackHi = NULL;
}
else if (__ARQCallbackLo) {
(*__ARQCallbackLo)((u32)__ARQRequestPendingLo);
__ARQRequestPendingLo = NULL;
__ARQCallbackLo = NULL;
}
__ARQPopTaskQueueHi();
if (__ARQRequestPendingHi == NULL)
__ARQServiceQueueLo();
}
void ARQInit(void) {
if (TRUE == __ARQ_init_flag) {
return;
}
__ARQRequestQueueHi = __ARQRequestQueueLo = NULL;
__ARQChunkSize = ARQ_CHUNK_SIZE_DEFAULT;
ARRegisterDMACallback(&__ARQInterruptServiceRoutine);
__ARQRequestPendingHi = NULL;
__ARQRequestPendingLo = NULL;
__ARQCallbackHi = NULL;
__ARQCallbackLo = NULL;
__ARQ_init_flag = TRUE;
}
void ARQPostRequest(ARQRequest* request, u32 owner, u32 type, u32 priority, u32 source, u32 dest,
u32 length, ARQCallback callback) {
BOOL enabled;
request->next = NULL;
request->owner = owner;
request->type = type;
request->source = source;
request->dest = dest;
request->length = length;
if (callback) {
request->callback = callback;
} else {
request->callback = (ARQCallback)&__ARQCallbackHack;
}
enabled = OSDisableInterrupts();
switch (priority) {
case ARQ_PRIORITY_LOW:
if (__ARQRequestQueueLo) {
__ARQRequestTailLo->next = request;
} else {
__ARQRequestQueueLo = request;
}
__ARQRequestTailLo = request;
break;
case ARQ_PRIORITY_HIGH:
if (__ARQRequestQueueHi) {
__ARQRequestTailHi->next = request;
} else {
__ARQRequestQueueHi = request;
}
__ARQRequestTailHi = request;
break;
}
if ((__ARQRequestPendingHi == NULL) && (__ARQRequestPendingLo == NULL)) {
__ARQPopTaskQueueHi();
if (__ARQRequestPendingHi == NULL) {
__ARQServiceQueueLo();
}
}
OSRestoreInterrupts(enabled);
}
u32 ARQGetChunkSize(void) { return __ARQChunkSize; }

View file

@ -0,0 +1,56 @@
#include "dolphin/DVDPriv.h"
#include "dolphin/OSRtcPriv.h"
static u32 ErrorTable[] = {
0, 0x00023A00, 0x00062800, 0x00030200, 0x00031100, 0x00052000,
0x00052001, 0x00052100, 0x00052400, 0x00052401, 0x00052402, 0x000B5A01,
0x00056300, 0x00020401, 0x00020400, 0x00040800, 0x00100007, 0,
};
static u8 ErrorCode2Num(u32 errorCode) {
u32 i;
for (i = 0; i < sizeof(ErrorTable) / sizeof(ErrorTable[0]); i++) {
if (ErrorTable[i] == errorCode) {
return (u8)i;
}
}
if ((errorCode >= 0x00100000) && (errorCode <= 0x00100008)) {
return 17;
}
return 29;
}
static u8 Convert(u32 error) {
u32 statusCode;
u32 errorCode;
u8 errorNum;
if (error == 0x01234567)
return 255;
if (error == 0x01234568)
return 254;
statusCode = (error & 0xff000000) >> 24;
errorCode = error & 0x00ffffff;
errorNum = ErrorCode2Num(errorCode);
if (statusCode >= 6)
statusCode = 6;
return (u8)(statusCode * 30 + errorNum);
}
void __DVDStoreErrorCode(u32 error) {
OSSramEx* sram;
u8 num;
num = Convert(error);
sram = __OSLockSramEx();
sram->dvdErrorCode = num;
__OSUnlockSramEx(TRUE);
}

356
src/dolphin/dvd/dvdfs.c Normal file
View file

@ -0,0 +1,356 @@
#include "dolphin/DVDPriv.h"
#include "dolphin/os.h"
#include "dolphin/os/OSBootInfo.h"
typedef struct FSTEntry FSTEntry;
struct FSTEntry {
unsigned int isDirAndStringOff;
unsigned int parentOrPosition;
unsigned int nextEntryOrLength;
};
static OSBootInfo* BootInfo;
static FSTEntry* FstStart;
static char* FstStringStart;
static u32 MaxEntryNum;
static u32 currentDirectory = 0;
OSThreadQueue __DVDThreadQueue;
u32 __DVDLongFileNameFlag = 0;
static void cbForReadAsync(s32 result, DVDCommandBlock* block);
static void cbForReadSync(s32 result, DVDCommandBlock* block);
static void cbForSeekAsync(s32 result, DVDCommandBlock* block);
static void cbForSeekSync(s32 result, DVDCommandBlock* block);
static void cbForPrepareStreamAsync(s32 result, DVDCommandBlock* block);
static void cbForPrepareStreamSync(s32 result, DVDCommandBlock* block);
void __DVDFSInit() {
BootInfo = (OSBootInfo*)OSPhysicalToCached(0);
FstStart = (FSTEntry*)BootInfo->FSTLocation;
if (FstStart) {
MaxEntryNum = FstStart[0].nextEntryOrLength;
FstStringStart = (char*)&(FstStart[MaxEntryNum]);
}
}
/* For convenience */
#define entryIsDir(i) (((FstStart[i].isDirAndStringOff & 0xff000000) == 0) ? FALSE : TRUE)
#define stringOff(i) (FstStart[i].isDirAndStringOff & ~0xff000000)
#define parentDir(i) (FstStart[i].parentOrPosition)
#define nextDir(i) (FstStart[i].nextEntryOrLength)
#define filePosition(i) (FstStart[i].parentOrPosition)
#define fileLength(i) (FstStart[i].nextEntryOrLength)
static BOOL isSame(const char* path, const char* string) {
while (*string != '\0') {
if (tolower(*path++) != tolower(*string++)) {
return FALSE;
}
}
if ((*path == '/') || (*path == '\0')) {
return TRUE;
}
return FALSE;
}
s32 DVDConvertPathToEntrynum(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;
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__, 376,
"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) {
if ((entrynum < 0) || (entrynum >= MaxEntryNum) || entryIsDir(entrynum)) {
return FALSE;
}
fileInfo->startAddr = filePosition(entrynum);
fileInfo->length = fileLength(entrynum);
fileInfo->callback = (DVDCallback)NULL;
fileInfo->cb.state = DVD_STATE_END;
return TRUE;
}
BOOL DVDOpen(char* fileName, DVDFileInfo* fileInfo) {
s32 entry;
char currentDir[128];
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)) {
return FALSE;
}
fileInfo->startAddr = filePosition(entry);
fileInfo->length = fileLength(entry);
fileInfo->callback = (DVDCallback)NULL;
fileInfo->cb.state = DVD_STATE_END;
return TRUE;
}
BOOL DVDClose(DVDFileInfo* fileInfo) {
DVDCancel(&(fileInfo->cb));
return TRUE;
}
static u32 myStrncpy(char* dest, char* src, u32 maxlen) {
u32 i = maxlen;
while ((i > 0) && (*src != 0)) {
*dest++ = *src++;
i--;
}
return (maxlen - i);
}
static u32 entryToPath(u32 entry, char* path, u32 maxlen) {
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;
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) {
return DVDConvertEntrynumToPath((s32)currentDirectory, path, maxlen);
}
BOOL DVDChangeDir(char* dirName) {
s32 entry;
entry = DVDConvertPathToEntrynum(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) {
if (!((0 <= offset) && (offset < fileInfo->length))) {
OSPanic(__FILE__, 739, "DVDReadAsync(): specified area is out of the file ");
}
if (!((0 <= offset + length) && (offset + length < fileInfo->length + DVD_MIN_TRANSFER_SIZE))) {
OSPanic(__FILE__, 745, "DVDReadAsync(): specified area is out of the file ");
}
fileInfo->callback = callback;
DVDReadAbsAsyncPrio(&(fileInfo->cb), addr, length, (s32)(fileInfo->startAddr + 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, cb));
if (fileInfo->callback) {
(fileInfo->callback)(result, fileInfo);
}
}
/* This is based on the revolution SDK, these may not match in all cases I have also left the line numbers at 0 */
BOOL DVDReadPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, s32 prio) {
BOOL result;
DVDCommandBlock* block;
s32 state;
BOOL enabled;
s32 retVal;
if (!((0 <= offset) && (offset < fileInfo->length))) {
OSPanic(__FILE__, 809, "DVDRead(): specified area is out of the file ");
}
if (!((0 <= offset + length) && (offset + length < fileInfo->length + DVD_MIN_TRANSFER_SIZE))) {
OSPanic(__FILE__, 815, "DVDRead(): specified area is out of the file ");
}
block = &(fileInfo->cb);
result = DVDReadAbsAsyncPrio(block, addr, length, (s32)(fileInfo->startAddr + offset),
cbForReadSync, prio);
if (result == FALSE) {
return -1;
}
enabled = OSDisableInterrupts();
while(1) {
state = ((volatile DVDCommandBlock*)block)->state;
if (state == DVD_STATE_END) {
retVal = (s32)block->transferredSize;
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;
}
/* This is based on the revolution SDK, these may not match in all cases */
static void cbForReadSync(s32 result, DVDCommandBlock* block) { OSWakeupThread(&__DVDThreadQueue); }

436
src/dolphin/dvd/dvdlow.c Normal file
View file

@ -0,0 +1,436 @@
#include "dolphin/DVDPriv.h"
#include "dolphin/os.h"
extern DVDDiskID* DVDGetCurrentDiskID();
extern OSTime __OSGetSystemTime();
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 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 vu32 NextCommandNumber = 0;
typedef struct DVDBuffer {
void* addr;
u32 length;
u32 offset;
} DVDBuffer;
typedef struct DVDCommand {
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;
ASSERT(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;
OSCancelAlarm(&AlarmForTimeout);
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;
}
__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 error = ProcessNextCommand();
ASSERTMSG(error != FALSE, "Failed assertion processed");
}
static void AlarmHandlerForTimeout(OSAlarm* alarm, OSContext* context) {
OSContext tmpContext;
DVDLowCallback callback;
__OSMaskInterrupts(0x400);
OSClearContext(&tmpContext);
OSSetCurrentContext(&tmpContext);
callback = Callback;
Callback = NULL;
if (callback != NULL) {
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) {
StopAtNextInt = FALSE;
LastCommandWasRead = TRUE;
Callback = callback;
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));
}
}
BOOL HitCache(DVDBuffer* cur, DVDBuffer* prev) {
u32 uVar1 = (prev->offset + prev->length - 1) >> 15;
u32 uVar2 = (cur->offset >> 15);
u32 iVar3 = (DVDGetCurrentDiskID()->streaming ? TRUE : FALSE) ? 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 = offset & ~0x7FFF;
if (!newOffset) {
newOffset = 0;
} else {
newOffset += 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) {
OSTime diff;
u32 prev;
__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 {
prev = (Prev.offset + Prev.length - 1) >> 15;
if (prev == Curr.offset >> 15 || prev + 1 == Curr.offset >> 15) {
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);
}
}
}
}
return TRUE;
}
BOOL DVDLowSeek(u32 offset, DVDLowCallback callback) {
ASSERTMSG(offset & 3, "DVDLowSeek(): offset must be a multiple of 4.");
StopAtNextInt = FALSE;
Callback = callback;
__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) {
StopAtNextInt = FALSE;
Callback = callback;
__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) {
StopAtNextInt = FALSE;
Callback = callback;
__DIRegs[2] = 0xe3000000;
__DIRegs[7] = 1;
SetTimeoutAlarm(OSSecondsToTicks(10));
return TRUE;
}
BOOL DVDLowRequestError(DVDLowCallback callback) {
StopAtNextInt = FALSE;
Callback = callback;
__DIRegs[2] = 0xe0000000;
__DIRegs[7] = 1;
SetTimeoutAlarm(OSSecondsToTicks(10));
return TRUE;
}
BOOL DVDLowInquiry(DVDDriveInfo* info, DVDLowCallback callback) {
StopAtNextInt = FALSE;
Callback = callback;
__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) {
StopAtNextInt = FALSE;
Callback = callback;
__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) {
StopAtNextInt = FALSE;
Callback = callback;
__DIRegs[2] = subcmd | 0xe2000000;
__DIRegs[7] = 1;
SetTimeoutAlarm(OSSecondsToTicks(10));
return TRUE;
}
BOOL DVDLowAudioBufferConfig(BOOL enable, u32 size, DVDLowCallback callback) {
StopAtNextInt = FALSE;
Callback = callback;
__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 | 5;
ResetOccurred = TRUE;
LastResetEnd = __OSGetSystemTime();
}
BOOL DVDLowBreak() {
StopAtNextInt = TRUE;
Breaking = TRUE;
return TRUE;
}
DVDLowCallback DVDLowClearCallback() {
DVDLowCallback old;
__DIRegs[1] = 0;
old = Callback;
Callback = NULL;
return old;
}
void __DVDLowSetWAType(u32 type, u32 location) {
BOOL enabled;
enabled = OSDisableInterrupts();
WorkAroundType = type;
WorkAroundSeekLocation = location;
OSRestoreInterrupts(enabled);
}

142
src/dolphin/dvd/dvdqueue.c Normal file
View file

@ -0,0 +1,142 @@
#include "dolphin/DVDPriv.h"
#define MAX_QUEUES 4
typedef struct {
DVDCommandBlock* next;
DVDCommandBlock* prev;
} DVDQueue;
static DVDQueue WaitingQueue[MAX_QUEUES];
void __DVDClearWaitingQueue(void) {
u32 i;
for (i = 0; i < MAX_QUEUES; i++) {
DVDCommandBlock* q;
q = (DVDCommandBlock*)&(WaitingQueue[i]);
q->next = q;
q->prev = q;
}
}
BOOL __DVDPushWaitingQueue(s32 prio, DVDCommandBlock* block) {
BOOL enabled;
DVDCommandBlock* q;
enabled = OSDisableInterrupts();
q = (DVDCommandBlock*)&(WaitingQueue[prio]);
q->prev->next = block;
block->prev = q->prev;
block->next = q;
q->prev = block;
OSRestoreInterrupts(enabled);
return TRUE;
}
static DVDCommandBlock* PopWaitingQueuePrio(s32 prio) {
DVDCommandBlock* tmp;
BOOL enabled;
DVDCommandBlock* q;
enabled = OSDisableInterrupts();
q = (DVDCommandBlock*)&(WaitingQueue[prio]);
tmp = q->next;
q->next = tmp->next;
tmp->next->prev = q;
OSRestoreInterrupts(enabled);
tmp->next = (DVDCommandBlock*)NULL;
tmp->prev = (DVDCommandBlock*)NULL;
return tmp;
}
DVDCommandBlock* __DVDPopWaitingQueue(void) {
u32 i;
BOOL enabled;
DVDCommandBlock* q;
enabled = OSDisableInterrupts();
for (i = 0; i < MAX_QUEUES; i++) {
q = (DVDCommandBlock*)&(WaitingQueue[i]);
if (q->next != q) {
OSRestoreInterrupts(enabled);
return PopWaitingQueuePrio((s32)i);
}
}
OSRestoreInterrupts(enabled);
return (DVDCommandBlock*)NULL;
}
BOOL __DVDCheckWaitingQueue(void) {
u32 i;
BOOL enabled;
DVDCommandBlock* q;
enabled = OSDisableInterrupts();
for (i = 0; i < MAX_QUEUES; i++) {
q = (DVDCommandBlock*)&(WaitingQueue[i]);
if (q->next != q) {
OSRestoreInterrupts(enabled);
return TRUE;
}
}
OSRestoreInterrupts(enabled);
return FALSE;
}
BOOL __DVDDequeueWaitingQueue(DVDCommandBlock* block) {
BOOL enabled;
DVDCommandBlock* prev;
DVDCommandBlock* next;
enabled = OSDisableInterrupts();
prev = block->prev;
next = block->next;
if ((prev == (DVDCommandBlock*)NULL) || (next == (DVDCommandBlock*)NULL)) {
OSRestoreInterrupts(enabled);
return FALSE;
}
prev->next = next;
next->prev = prev;
OSRestoreInterrupts(enabled);
return TRUE;
}
BOOL __DVDIsBlockInWaitingQueue(DVDCommandBlock* block) {
u32 i;
DVDCommandBlock* start;
DVDCommandBlock* q;
for (i = 0; i < MAX_QUEUES; i++) {
start = (DVDCommandBlock*)&(WaitingQueue[i]);
if (start->next != start) {
for (q = start->next; q != start; q = q->next) {
if (q == block)
return TRUE;
}
}
}
return FALSE;
}

68
src/dolphin/dvd/fstload.c Normal file
View file

@ -0,0 +1,68 @@
#include <dolphin/DVDPriv.h>
#include <dolphin/dvd.h>
#include <dolphin/hw_regs.h>
#include <dolphin/os.h>
#include <dolphin/os/OSBootInfo.h>
#include <string.h>
static s32 status = 0;
static u8 bb2Buf[OSRoundUp32B(sizeof(DVDBB2)) + 31];
static DVDBB2* bb2 = 0;
static DVDDiskID* idTmp = NULL;
static void cb(s32 result, DVDCommandBlock* block) {
if (result > 0) {
switch (status) {
case 0:
status = 1;
DVDReadAbsAsyncForBS(block, bb2, OSRoundUp32B(sizeof(bb2)), 0x420, cb);
break;
case 1:
status = 2;
DVDReadAbsAsyncForBS(block, bb2->FSTAddress, OSRoundUp32B(bb2->FSTLength), bb2->FSTPosition,
cb);
}
} else if (result == -1) {
} else if (result == -4) {
status = 0;
DVDReset();
DVDReadDiskID(block, idTmp, cb);
}
}
void __fstLoad() {
OSBootInfo* bootInfo;
DVDDiskID* id;
u8 idTmpBuf[sizeof(DVDDiskID) + 31];
static DVDCommandBlock block;
void* arenaHi;
arenaHi = OSGetArenaHi();
bootInfo = (OSBootInfo*)OSPhysicalToCached(0);
idTmp = (DVDDiskID*)(OSRoundUp32B(idTmpBuf));
bb2 = (DVDBB2*)(OSRoundUp32B(bb2Buf));
DVDReset();
DVDReadDiskID(&block, idTmp, cb);
while (DVDGetDriveStatus() != 0);
bootInfo->FSTLocation = bb2->FSTAddress;
bootInfo->FSTMaxLength = bb2->FSTMaxLength;
id = &bootInfo->DVDDiskID;
memcpy(id, idTmp, sizeof(DVDDiskID));
OSReport("\n");
OSReport(" Game Name ... %c%c%c%c\n", id->gameName[0], id->gameName[1], id->gameName[2],
id->gameName[3]);
OSReport(" Company ..... %c%c\n", id->company[0], id->company[1]);
OSReport(" Disk # ...... %d\n", id->diskNumber);
OSReport(" Game ver .... %d\n", id->gameVersion);
OSReport(" Streaming ... %s\n", (id->streaming == 0) ? "OFF" : "ON");
OSReport("\n");
OSSetArenaHi(bb2->FSTAddress);
}