diff --git a/config/RMGK01/splits.txt b/config/RMGK01/splits.txt index d02c50579..84e2a2a4c 100644 --- a/config/RMGK01/splits.txt +++ b/config/RMGK01/splits.txt @@ -10281,13 +10281,15 @@ RVL_SDK/base/PPCArch.c: RVL_SDK/os/OS.c: .text start:0x804A2CDC end:0x804A40EC - .data start:0x805EF368 end:0x805EF7E8 + .data start:0x805EF368 end:0x805EF758 .bss start:0x80664DE0 end:0x80664E50 .sdata start:0x806B2A10 end:0x806B2A40 - .sbss start:0x806B7628 end:0x806B7678 + .sbss start:0x806B7628 end:0x806B7670 RVL_SDK/os/OSAlarm.c: .text start:0x804A40EC end:0x804A48D0 + .data start:0x805EF758 end:0x805EF768 + .sbss start:0x806B7670 end:0x806B7678 RVL_SDK/os/OSAlloc.c: .text start:0x804A48D0 end:0x804A4BD8 @@ -10301,6 +10303,7 @@ RVL_SDK/os/OSArena.c: RVL_SDK/os/OSAudioSystem.c: .text start:0x804A4C6C end:0x804A5120 + .data start:0x805EF768 end:0x805EF7E8 RVL_SDK/os/OSCache.c: .text start:0x804A5120 end:0x804A5720 @@ -10325,17 +10328,18 @@ RVL_SDK/os/OSExec.c: RVL_SDK/os/OSFatal.c: .text start:0x804A7E78 end:0x804A8AB0 - .bss start:0x80665188 end:0x80665D70 + .bss start:0x80665188 end:0x806651A0 .sdata start:0x806B2A68 end:0x806B2A78 .sdata2 start:0x806C2088 end:0x806C20D0 RVL_SDK/os/OSFont.c: .text start:0x804A8AB0 end:0x804A9778 - .data start:0x805F0110 end:0x805F0AE0 + .data start:0x805F0110 end:0x805F0AA0 .sbss start:0x806B76A8 end:0x806B76B8 RVL_SDK/os/OSInterrupt.c: .text start:0x804A9778 end:0x804A9EFC + .data start:0x805F0AA0 end:0x805F0AD0 .sbss start:0x806B76B8 end:0x806B76D0 RVL_SDK/os/OSLink.c: @@ -10346,6 +10350,7 @@ RVL_SDK/os/OSMessage.c: RVL_SDK/os/OSMemory.c: .text start:0x804AA1E8 end:0x804AAAC4 + .data start:0x805F0AD0 end:0x805F0AE0 RVL_SDK/os/OSMutex.c: .text start:0x804AAAC4 end:0x804AADC8 @@ -10356,26 +10361,30 @@ RVL_SDK/os/OSReboot.c: RVL_SDK/os/OSReset.c: .text start:0x804AAE48 end:0x804AB790 - .data start:0x805F0AE0 end:0x805FCC08 + .data start:0x805F0AE0 end:0x805F0D68 .sdata start:0x806B2A78 end:0x806B2A80 .sbss start:0x806B76D8 end:0x806B76E8 RVL_SDK/os/OSRtc.c: .text start:0x804AB790 end:0x804AC21C + .bss start:0x806651A0 end:0x806651F8 RVL_SDK/os/OSSync.c: .text start:0x804AC21C end:0x804AC29C RVL_SDK/os/OSThread.c: .text start:0x804AC29C end:0x804AD9FC + .bss start:0x806651F8 end:0x80665C00 .sdata start:0x806B2A80 end:0x806B2A88 .sbss start:0x806B76E8 end:0x806B76F8 RVL_SDK/os/OSTime.c: .text start:0x804AD9FC end:0x804ADE10 + .data start:0x805F0D68 end:0x805F0DC8 RVL_SDK/os/OSUtf.c: .text start:0x804ADE10 end:0x804AE048 + .data start:0x805F0DC8 end:0x805FCC08 RVL_SDK/os/OSIpc.c: .text start:0x804AE048 end:0x804AE070 diff --git a/config/RMGK01/symbols.txt b/config/RMGK01/symbols.txt index 4652457ac..3d349bbf9 100644 --- a/config/RMGK01/symbols.txt +++ b/config/RMGK01/symbols.txt @@ -59860,7 +59860,7 @@ DSPInitCode = .data:0x805EF768; // type:object size:0x80 scope:local @3214 = .data:0x805EFF80; // type:object size:0xB scope:local align:4 data:string lbl_805EFF90 = .data:0x805EFF90; // type:object size:0x180 Zenkaku2Code = .data:0x805F0110; // type:object size:0x98A scope:global align:4 -lbl_805F0AA0 = .data:0x805F0AA0; // type:object size:0x30 data:4byte +InterruptPrioTable = .data:0x805F0AA0; // type:object size:0x30 data:4byte ShutdownFunctionInfo = .data:0x805F0AD0; // type:object size:0x10 scope:local @1720 = .data:0x805F0AE0; // type:object size:0xA scope:local align:4 data:string @1721 = .data:0x805F0AEC; // type:object size:0x29 scope:local align:4 data:string @@ -59878,8 +59878,8 @@ ShutdownFunctionInfo = .data:0x805F0AD0; // type:object size:0x10 scope:local @1782 = .data:0x805F0CB8; // type:object size:0x31 scope:local align:4 data:string @1790 = .data:0x805F0CEC; // type:object size:0x3B scope:local align:4 data:string @1792 = .data:0x805F0D28; // type:object size:0x3A scope:local align:4 data:string -lbl_805F0D68 = .data:0x805F0D68; // type:object size:0x30 -lbl_805F0D98 = .data:0x805F0D98; // type:object size:0x30 +YearDays = .data:0x805F0D68; // type:object size:0x30 +LeapYearDays = .data:0x805F0D98; // type:object size:0x30 lbl_805F0DC8 = .data:0x805F0DC8; // type:object size:0x40 data:2byte lbl_805F0E08 = .data:0x805F0E08; // type:object size:0x200 lbl_805F1008 = .data:0x805F1008; // type:object size:0x200 @@ -61274,8 +61274,8 @@ lbl_80664EC0 = .bss:0x80664EC0; // type:object size:0x2C8 FatalParam = .bss:0x80665188; // type:object size:0xC scope:global align:4 data:byte Scb = .bss:0x806651A0; // type:object size:0x54 scope:local data:4byte DefaultThread = .bss:0x806651F8; // type:object size:0x318 scope:local data:4byte -lbl_80665510 = .bss:0x80665510; // type:object size:0x100 data:4byte -lbl_80665610 = .bss:0x80665610; // type:object size:0x5F0 +RunQueue = .bss:0x80665510; // type:object size:0x100 data:4byte +IdleContext = .bss:0x80665610; // type:object size:0x5F0 StmEhInBuf = .bss:0x80665C00; // type:object size:0x20 scope:local StmEhOutBuf = .bss:0x80665C20; // type:object size:0x20 scope:local data:4byte lbl_80665C40 = .bss:0x80665C40; // type:object size:0x20 data:4byte diff --git a/configure.py b/configure.py index 74cc0bc0c..92c5c79ba 100644 --- a/configure.py +++ b/configure.py @@ -258,7 +258,7 @@ cflags_sdk = [ "-nodefaults", - "-lang c++", + "-lang c", "-proc gekko", "-align powerpc", "-enum int", @@ -2304,7 +2304,7 @@ def JSysLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: SDKLib( "base", [ - Object(NonMatching, "RVL_SDK/base/PPCArch.c") + Object(Matching, "RVL_SDK/base/PPCArch.c") ] ), @@ -2565,27 +2565,27 @@ def JSysLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: "os", [ Object(NonMatching, "RVL_SDK/os/OS.c"), - Object(NonMatching, "RVL_SDK/os/OSAlarm.c"), - Object(NonMatching, "RVL_SDK/os/OSAlloc.c"), - Object(NonMatching, "RVL_SDK/os/OSArena.c"), - Object(NonMatching, "RVL_SDK/os/OSAudioSystem.c"), + Object(Matching, "RVL_SDK/os/OSAlarm.c"), + Object(Matching, "RVL_SDK/os/OSAlloc.c"), + Object(Matching, "RVL_SDK/os/OSArena.c"), + Object(Matching, "RVL_SDK/os/OSAudioSystem.c"), Object(NonMatching, "RVL_SDK/os/OSCache.c"), Object(NonMatching, "RVL_SDK/os/OSContext.c"), Object(NonMatching, "RVL_SDK/os/OSError.c"), Object(NonMatching, "RVL_SDK/os/OSExec.c"), Object(NonMatching, "RVL_SDK/os/OSFatal.c"), Object(NonMatching, "RVL_SDK/os/OSFont.c"), - Object(NonMatching, "RVL_SDK/os/OSInterrupt.c"), - Object(NonMatching, "RVL_SDK/os/OSLink.c"), - Object(NonMatching, "RVL_SDK/os/OSMessage.c"), - Object(NonMatching, "RVL_SDK/os/OSMemory.c"), - Object(NonMatching, "RVL_SDK/os/OSMutex.c"), - Object(NonMatching, "RVL_SDK/os/OSReboot.c"), + Object(Matching, "RVL_SDK/os/OSInterrupt.c"), + Object(Matching, "RVL_SDK/os/OSLink.c"), + Object(Matching, "RVL_SDK/os/OSMessage.c"), + Object(Matching, "RVL_SDK/os/OSMemory.c"), + Object(Matching, "RVL_SDK/os/OSMutex.c"), + Object(Matching, "RVL_SDK/os/OSReboot.c"), Object(NonMatching, "RVL_SDK/os/OSReset.c"), - Object(NonMatching, "RVL_SDK/os/OSRtc.c"), - Object(NonMatching, "RVL_SDK/os/OSSync.c"), - Object(NonMatching, "RVL_SDK/os/OSThread.c"), - Object(NonMatching, "RVL_SDK/os/OSTime.c"), + Object(Matching, "RVL_SDK/os/OSRtc.c"), + Object(Matching, "RVL_SDK/os/OSSync.c"), + Object(Matching, "RVL_SDK/os/OSThread.c"), + Object(Matching, "RVL_SDK/os/OSTime.c"), Object(NonMatching, "RVL_SDK/os/OSUtf.c"), Object(NonMatching, "RVL_SDK/os/OSIpc.c"), Object(NonMatching, "RVL_SDK/os/OSStateTM.c"), @@ -2641,7 +2641,7 @@ def JSysLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: SDKLib( "tpl", [ - Object(NonMatching, "RVL_SDK/tpl/TPL.c") + Object(Matching, "RVL_SDK/tpl/TPL.c") ] ), diff --git a/src/RVLFaceLib/RFL_Format.c b/src/RVLFaceLib/RFL_Format.c index 65a3083b8..ea271b2dd 100644 --- a/src/RVLFaceLib/RFL_Format.c +++ b/src/RVLFaceLib/RFL_Format.c @@ -1,5 +1,5 @@ #include -#include +#include #define MAGIC_OFFICIAL_DB 'RNOD' #define MAGIC_HIDDEN_DB 'RNHD' diff --git a/src/RVLFaceLib/RFL_System.c b/src/RVLFaceLib/RFL_System.c index 54c99941a..6129afcec 100644 --- a/src/RVLFaceLib/RFL_System.c +++ b/src/RVLFaceLib/RFL_System.c @@ -17,12 +17,12 @@ #define RFLGetLastReason_() \ (RFLAvailable() ? RFLiGetLastReason_() : sRFLLastReason) -const char* __RFLVersion = +static char* __RFLVersion = "<< RVL_SDK - RFL \trelease build: Mar 6 2008 17:40:04 (0x4199_60831) >>"; -static const RFLiCoordinateData scCoordinate = {1, 2, 0, FALSE, FALSE, FALSE}; +const RFLiCoordinateData scCoordinate = {1, 2, 0, FALSE, FALSE, FALSE}; -static RFLiManager* sRFLiManager = NULL; +static RFLiManager* sRFLManager = NULL; static RFLErrcode sRFLLastErrCode = RFLErrcode_NotAvailable; static u8 sRFLiFileBrokenType; static s32 sRFLLastReason; @@ -49,11 +49,11 @@ RFLErrcode RFLInitResAsync(void* workBuffer, void* resBuffer, u32 resSize, workSize = deluxeTex ? RFL_DELUXE_WORK_SIZE : RFL_WORK_SIZE; memset(workBuffer, 0, workSize); - sRFLiManager = (RFLiManager*)workBuffer; + sRFLManager = (RFLiManager*)workBuffer; sRFLLastErrCode = RFLErrcode_NotAvailable; sRFLLastReason = NAND_RESULT_OK; sRFLiFileBrokenType = RFLiFileBrokenType_DBNotFound; - sRFLiManager->workBuffer = (u8*)workBuffer + sizeof(RFLiManager); + sRFLManager->workBuffer = (u8*)workBuffer + sizeof(RFLiManager); heapSize = deluxeTex ? RFL_DELUXE_WORK_SIZE - sizeof(RFLiManager) : RFL_WORK_SIZE - sizeof(RFLiManager); @@ -100,7 +100,7 @@ RFLErrcode RFLInitResAsync(void* workBuffer, void* resBuffer, u32 resSize, return error; } -RFLErrcode RFLInitRes(void* workBuffer, void* resBuffer, u32 resSize, +static RFLErrcode RFLInitRes(void* workBuffer, void* resBuffer, u32 resSize, BOOL deluxeTex) { RFLInitResAsync(workBuffer, resBuffer, resSize, deluxeTex); return RFLWaitAsync(); @@ -127,7 +127,7 @@ void RFLExit(void) { MEMDestroyExpHeap(RFLiGetManager()->systemHeap); MEMDestroyExpHeap(RFLiGetManager()->rootHeap); - sRFLiManager = NULL; + sRFLManager = NULL; } static void bootloadDB2Res_(void) { @@ -143,19 +143,19 @@ static void bootloadDB2Res_(void) { } } -RFLErrcode RFLiBootLoadAsync(void) { +static RFLErrcode RFLiBootLoadAsync(void) { return RFLiBootLoadDatabaseAsync(bootloadDB2Res_); } BOOL RFLAvailable(void) { - return sRFLiManager != NULL; + return sRFLManager != NULL; } static void* allocal_(u32 size, s32 align) { return MEMAllocFromExpHeapEx(RFLiGetManager()->tmpHeap, size, align); } -void* RFLiAlloc(u32 size) { +static void* RFLiAlloc(u32 size) { return allocal_(size, 8); } @@ -188,7 +188,7 @@ void RFLiSetWorking(BOOL working) { } RFLiManager* RFLiGetManager(void) { - return sRFLiManager; + return sRFLManager; } RFLErrcode RFLGetAsyncStatus(void) { @@ -211,7 +211,7 @@ s32 RFLGetLastReason(void) { return !RFLAvailable() ? sRFLLastReason : RFLiGetLastReason_(); } -RFLErrcode RFLWaitAsync(void) { +static RFLErrcode RFLWaitAsync(void) { volatile RFLErrcode status; do { @@ -263,7 +263,7 @@ BOOL RFLiNeedRepairError(void) { return *broken >> RFLiFileBrokenType_DBBroken & 1; } -BOOL RFLiCriticalError(void) { +static BOOL RFLiCriticalError(void) { u8* broken = &sRFLiFileBrokenType; if (RFLAvailable()) { diff --git a/src/RVL_SDK/aralt/aralt.c b/src/RVL_SDK/aralt/aralt.c new file mode 100644 index 000000000..df59642f1 --- /dev/null +++ b/src/RVL_SDK/aralt/aralt.c @@ -0,0 +1,33 @@ +#include +#include +#include + +static u32 __ARH_BaseAdr; + +static ARCallback __AR_Callback; + +#ifndef NON_MATCHING +// for some reason has _savegpr +void ARStartDMA(u32 type, u32 ram_addr, u32 aram_addr, u32 len) { + OSDisableScheduler(); + + if (type == 0) { + aram_addr += __ARH_BaseAdr; + DCInvalidateRange((u32*)ram_addr, len); + memcpy((u32*)aram_addr, (u32*)ram_addr, len); + DCFlushRange((u32*)aram_addr, len); + } + else if (type == 1) { + ram_addr += __ARH_BaseAdr; + DCFlushRange((u32*)ram_addr, len); + memcpy((u32*)aram_addr, (u32*)ram_addr, len); + DCFlushRange((u32*)aram_addr, len); + } + + OSEnableScheduler(); + + if (__AR_Callback) { + (*__AR_Callback)(); + } +} +#endif \ No newline at end of file diff --git a/src/RVL_SDK/arc/arc.c b/src/RVL_SDK/arc/arc.c new file mode 100644 index 000000000..3d4788208 --- /dev/null +++ b/src/RVL_SDK/arc/arc.c @@ -0,0 +1,316 @@ +#include +#include +#include + +/* this is here because it won't be inlined otherwise */ +inline int tolower(int c) { + return ((c < 0) || (c >= 0x100)) ? c : (int) (_current_locale.ctype_cmpt_ptr->lower_map_ptr[c]); +} + +typedef struct FSTEntry FSTEntry; + +struct FSTEntry { + unsigned int isDirAndStringOff; + unsigned int parentOrPosition; + unsigned int nextEntryOrLength; +}; + +#define entryIsDir(fstStart, i) \ + ( ( ( fstStart[i].isDirAndStringOff & 0xFF000000 ) == 0 )? FALSE : TRUE ) +#define stringOff(fstStart, i) \ + ( fstStart[i].isDirAndStringOff & 0x00FFFFFF ) +#define parentDir(fstStart, i) \ + ( fstStart[i].parentOrPosition ) +#define nextDir(fstStart, i) \ + ( fstStart[i].nextEntryOrLength ) +#define filePosition(fstStart, i) \ + ( fstStart[i].parentOrPosition ) +#define fileLength(fstStart, i) \ + ( fstStart[i].nextEntryOrLength ) + +BOOL ARCInitHandle(void* arcStart, ARCHandle* handle) { + FSTEntry* FSTEntries; + ARCHeader* arcHeader = (ARCHeader*)arcStart; + + if (arcHeader->magic != 0x55AA382D) { + OSPanic(__FILE__, 0x4A, "ARCInitHandle: bad archive format"); + } + + handle->archiveStartAddr = arcStart; + handle->FSTStart = FSTEntries = (void*)((u32)arcStart + arcHeader->fstStart); + handle->fileStart = (void*)((u32)arcStart + arcHeader->fileStart); + handle->entryNum = nextDir(FSTEntries, 0); + handle->FSTStringStart = (char*)&(FSTEntries[handle->entryNum]); + handle->FSTLength = (u32)arcHeader->fstSize; + handle->currDir = 0; + return TRUE; +} + +BOOL ARCOpen(ARCHandle* handle, const char* fileName, ARCFileInfo* af) { + s32 entry; + char currentDir[128]; + FSTEntry* FSTEntries = (FSTEntry*)handle->FSTStart; + entry = ARCConvertPathToEntrynum(handle, fileName); + + if (0 > entry) { + ARCGetCurrentDir(handle, currentDir, 128); + OSReport("Warning: ARCOpen(): file '%s' was not found under %s in the archive.\n", fileName, currentDir); + return FALSE; + } + + if ((entry < 0) || entryIsDir(FSTEntries, entry)) { + return FALSE; + } + + af->handle = handle; + af->startOffset = filePosition(FSTEntries, entry); + af->length = fileLength(FSTEntries, entry); + + return TRUE; +} + +BOOL ARCFastOpen(ARCHandle* handle, s32 entrynum, ARCFileInfo* af) { + FSTEntry* FSTEntries = (FSTEntry*)handle->FSTStart; + + if ((entrynum < 0) || (entrynum >= handle->entryNum) || entryIsDir(FSTEntries, entrynum)) { + return FALSE; + } + + af->handle = handle; + af->startOffset = filePosition(FSTEntries, entrynum); + af->length = fileLength(FSTEntries, entrynum); + return TRUE; +} + +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 ARCConvertPathToEntrynum(ARCHandle* handle, const char* pathPtr) +{ + const char* ptr; + char* stringPtr; + BOOL isDir; + s32 length; + u32 dirLookAt; + u32 i; + const char* origPathPtr = pathPtr; + FSTEntry* FSTEntries; + + dirLookAt = handle->currDir; + FSTEntries = (FSTEntry*)handle->FSTStart; + + 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(FSTEntries, dirLookAt); + pathPtr += 3; + continue; + } + else if (*(pathPtr + 2) == '\0') { + return (s32)parentDir(FSTEntries, dirLookAt); + } + } + else if (*(pathPtr + 1) == '/') { + pathPtr += 2; + continue; + } + else if (*(pathPtr + 1) == '\0') { + return (s32)dirLookAt; + } + } + + for(ptr = pathPtr; (*ptr != '\0') && (*ptr != '/'); ptr++); + isDir = (*ptr == '\0')? FALSE : TRUE; + length = (s32)(ptr - pathPtr); + ptr = pathPtr; + + for(i = dirLookAt + 1; i < nextDir(FSTEntries, dirLookAt); + i = entryIsDir(FSTEntries, i)? nextDir(FSTEntries, i): (i+1) ) + { +dot: + if ((entryIsDir(FSTEntries, i) == FALSE) && (isDir == TRUE)) { + continue; + } + + stringPtr = handle->FSTStringStart + stringOff(FSTEntries, i); + + if (*stringPtr == '.' && *(stringPtr + 1) == '\0') { + i++; + goto dot; + } + + if (isSame(ptr, stringPtr) == TRUE) { + goto next_hier; + } + } + + return -1; + + next_hier: + if (!isDir) { + return (s32)i; + } + + dirLookAt = i; + pathPtr += length + 1; + } + + // the world ends if this is reached +} + +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(ARCHandle* handle, u32 entry, char* path, u32 maxlen) { + char* name; + u32 loc; + FSTEntry* FSTEntries = (FSTEntry*)handle->FSTStart; + + if (entry == 0) { + return 0; + } + + name = handle->FSTStringStart + stringOff(FSTEntries, entry); + loc = entryToPath(handle, parentDir(FSTEntries, entry), path, maxlen); + + if (loc == maxlen) { + return loc; + } + + *(path + loc++) = '/'; + loc += myStrncpy(path + loc, name, maxlen - loc); + return loc; +} + +static BOOL ARCConvertEntrynumToPath(ARCHandle* handle, s32 entrynum, char* path, u32 maxlen) { + u32 loc; + FSTEntry* FSTEntries = (FSTEntry*)handle->FSTStart; + + loc = entryToPath(handle, (u32)entrynum, path, maxlen); + + if (loc == maxlen) { + path[maxlen - 1] = '\0'; + return FALSE; + } + + if (entryIsDir(FSTEntries, entrynum)) { + if (loc == maxlen - 1) { + path[loc] = '\0'; + return FALSE; + } + + path[loc++] = '/'; + } + + path[loc] = '\0'; + return TRUE; +} + +BOOL ARCGetCurrentDir(ARCHandle* handle, char* path, u32 maxlen) { + return ARCConvertEntrynumToPath(handle, (s32)handle->currDir, path, maxlen); +} + +void* ARCGetStartAddrInMem(ARCFileInfo* af) { + ARCHandle* handle = af->handle; + return (void*)((u32)handle->archiveStartAddr + af->startOffset); +} + +u32 ARCGetLength(ARCFileInfo* af) { + return af->length; +} + +BOOL ARCClose(ARCFileInfo* af) { + return TRUE; +} + +BOOL ARCChangeDir(ARCHandle* handle, const char* dirName) { + s32 entry; + FSTEntry* FSTEntries; + + entry = ARCConvertPathToEntrynum(handle, dirName); + FSTEntries = (FSTEntry*)handle->FSTStart; + + if ((entry < 0) || (entryIsDir(FSTEntries, entry) == FALSE)) { + return FALSE; + } + + handle->currDir = (u32)entry; + return TRUE; +} + +BOOL ARCOpenDir(ARCHandle* handle, const char* dirName, ARCDir* dir) { + s32 entry; + FSTEntry* FSTEntries; + + entry = ARCConvertPathToEntrynum(handle, dirName); + FSTEntries = (FSTEntry*)handle->FSTStart; + + if ((entry < 0) || (entryIsDir(FSTEntries, entry) == FALSE)) { + return FALSE; + } + + dir->handle = handle; + dir->entryNum = (u32)entry; + dir->location = (u32)entry + 1; + dir->next = nextDir(FSTEntries, entry); + return TRUE; +} + +BOOL ARCReadDir(ARCDir* dir, ARCDirEntry* dirent) { + u32 loc; + FSTEntry* FSTEntries; + ARCHandle* handle; + + handle = dir->handle; + FSTEntries = (FSTEntry*)handle->FSTStart; + loc = dir->location; +retry: + if ((loc <= dir->entryNum) || (dir->next <= loc)) { + return FALSE; + } + + dirent->handle = handle; + dirent->entryNum = loc; + dirent->isDir = entryIsDir(FSTEntries, loc); + dirent->name = handle->FSTStringStart + stringOff(FSTEntries, loc); + + if (dirent->name[0] == '.' && dirent->name[1] == '\0') { + loc++; + goto retry; + } + + dir->location = entryIsDir(FSTEntries, loc)? nextDir(FSTEntries, loc) : (loc+1); + return TRUE; +} + +BOOL ARCCloseDir(ARCDir* dir) { + return TRUE; +} \ No newline at end of file diff --git a/src/RVL_SDK/base/PPCArch.c b/src/RVL_SDK/base/PPCArch.c new file mode 100644 index 000000000..c279f8463 --- /dev/null +++ b/src/RVL_SDK/base/PPCArch.c @@ -0,0 +1,174 @@ +#include +#include + +union Fpscr { + f64 f; + + struct { + u32 _0; + u32 fpscr; + } u; +}; + +asm u32 PPCMfmsr(void) { + nofralloc + mfmsr r3 + blr +} + +asm void PPCMtmsr(register u32 val) { + nofralloc + mtmsr val + blr +} + +asm u32 PPCMfhid0(void) { + nofralloc + mfspr r3, 0x3F0 + blr +} + +asm void PPCMthid0(register u32 val) { + nofralloc + mtspr 0x3F0, val + blr +} + +asm u32 PPCMfl2cr(void) { + nofralloc + mfspr r3, 0x3F9 + blr +} + +asm void PPCMtl2cr(register u32 val) { + nofralloc + mtspr 0x3F9, val + blr +} + +asm void PPCMtdec(register u32 val) { + nofralloc + mtdec val + blr +} + +asm void PPCSync(void) { + nofralloc + sc + blr +} + +asm void PPCHalt(void) { + nofralloc + sync + +loop: + nop + li r3, 0 + nop + b loop +} + +asm void PPCMtmmcr0(register u32 val) { + nofralloc + mtspr 0x3B8, val + blr +} + +asm void PPCMtmmcr1(register u32 val) { + nofralloc + mtspr 0x3BC, val + blr +} + +asm void PPCMtpmc1(register u32 val) { + nofralloc + mtspr 0x3B9, val + blr +} + +asm void PPCMtpmc2(register u32 val) { + nofralloc + mtspr 0x3BA, val + blr +} + +asm void PPCMtpmc3(register u32 val) { + nofralloc + mtspr 0x3BD, val + blr +} + +asm void PPCMtpmc4(register u32 val) { + nofralloc + mtspr 0x3BE, val + blr +} + +u32 PPCMffpscr(void) { + union Fpscr m; + + asm { + mffs fp31 + stfd fp31, m.f; + } + + return m.u.fpscr; +} + +void PPCMtfpscr(register u32 val) { + union Fpscr m; + + asm { + li r4, 0 + stw r4, m.u._0; + stw val, m.u.fpscr + lfd fp31, m.f + mtfsf 0xFF, fp31 + }; +} + +asm u32 PPCMfhid2(void) { + nofralloc + mfspr r3, 0x398 + blr +} + +asm void PPCMthid2(u32) { + nofralloc + mtspr 0x398, r3 + blr +} + +asm u32 PPCMfwpar(void) { + nofralloc + sync + mfspr r3, 0x399 + blr +} + +asm void PPCMtwpar(u32) { + mtspr 0x399, r3 + blr +} + +void PPCDisableSpeculation(void) { + PPCMthid0(PPCMfhid0() | 0x200); +} + +asm void PPCSetFpNonIEEEMode(void) { + nofralloc + mtfsb1 29 + blr +} + +void PPCMthid4(register u32 hid) { + if (hid & 0x80000000) { + asm { mtspr 0x3F3, hid } + } + else { + OSReport("H4A should not be cleared because of Broadway errata.\n"); + hid |= 0x80000000; + asm { mtspr 0x3F3, hid } + } +} diff --git a/src/RVL_SDK/db/db.c b/src/RVL_SDK/db/db.c new file mode 100644 index 000000000..170fe5c0a --- /dev/null +++ b/src/RVL_SDK/db/db.c @@ -0,0 +1,37 @@ +#include +#include + +DBInterface* __DBInterface = NULL; +BOOL DBVerbose; + +void __DBExceptionDestination(void); + +void DBInit(void) { + __DBInterface = (DBInterface*)OSPhysicalToCached(0x40); + __DBInterface->exceptionDestination = (void*)OSCachedToPhysical(__DBExceptionDestination); + DBVerbose = 1; +} + +void __DBExceptionDestinationAux(void) { + u32* context_addr = (void*)0xC0; + OSContext* context = (OSContext*)(0x80000000 + *context_addr); + OSReport("DBExceptionDestination\n"); + OSDumpContext(context); + PPCHalt(); +} + +asm void __DBExceptionDestination(void) { + nofralloc + mfmsr r3 + ori r3, r3, 0x30 + mtmsr r3 + b __DBExceptionDestinationAux +} + +BOOL __DBIsExceptionMarked(__OSException ex) { + return __DBInterface->mask & (1 << ex); +} + +void DBPrintf(char *, ...) { + va_list list; +} \ No newline at end of file diff --git a/src/RVL_SDK/dsp/dsp.c b/src/RVL_SDK/dsp/dsp.c new file mode 100644 index 000000000..03ced83be --- /dev/null +++ b/src/RVL_SDK/dsp/dsp.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include + +static BOOL __DSP_init_flag = 0; +extern DSPTaskInfo *__DSP_curr_task; +extern DSPTaskInfo *__DSP_first_task; +extern DSPTaskInfo *__DSP_last_task; +extern DSPTaskInfo *__DSP_tmp_task; + +const char* __DSPVersion = "<< RVL_SDK - DSP \trelease build: Aug 8 2007 01:59:06 (0x4199_60831) >>"; + +u32 DSPCheckMailToDSP(void) { + return ((__DSPRegs[0] & 0x8000) >> 15); +} + +u32 DSPCheckMailFromDSP(void) { + return ((__DSPRegs[2] & 0x8000) >> 15); +} + +u32 DSPReadMailFromDSP(void) { + return ((__DSPRegs[2]) << 16) | __DSPRegs[3]; +} + +void DSPSendMailToDSP(u32 mail) { + __DSPRegs[0] = (mail >> 16); + __DSPRegs[1] = mail; +} + +void DSPAssertInt(void) { + BOOL intr; + u16 reg; + + intr = OSDisableInterrupts(); + reg = __DSPRegs[5]; + reg = (reg & ~0xA8 | 0x2); + __DSPRegs[5] = reg; + OSRestoreInterrupts(intr); +} + +void DSPInit(void) { + BOOL intr; + u16 reg; + + __DSP_debug_printf("DSPInit(): Build Date: %s %s\n", "Aug 8 2007", "01:59:06"); + + if (__DSP_init_flag == 1) { + return; + } + + OSRegisterVersion(__DSPVersion); + intr = OSDisableInterrupts(); + __OSSetInterruptHandler(7, __DSPHandler); + __OSUnmaskInterrupts(0x1000000); + + reg = __DSPRegs[5]; + reg = ((reg & ~(0x20 | 0x8 | 0x80)) | 0x800); + __DSPRegs[5] = reg; + + reg = __DSPRegs[5]; + reg = (reg & ~(0x20 | 0x8 | 0x80 | 0x4)); + __DSPRegs[5] = reg; + + __DSP_first_task = __DSP_last_task = __DSP_curr_task = __DSP_tmp_task = NULL; + __DSP_init_flag = 1; + OSRestoreInterrupts(intr); +} \ No newline at end of file diff --git a/src/RVL_SDK/dsp/dsp_debug.c b/src/RVL_SDK/dsp/dsp_debug.c new file mode 100644 index 000000000..592aee204 --- /dev/null +++ b/src/RVL_SDK/dsp/dsp_debug.c @@ -0,0 +1,7 @@ +#include +#include + +void __DSP_debug_printf(char *pFormat, ...) { + // oops. code was probably #ifdef'd out at some point + va_list list; +} diff --git a/src/RVL_SDK/dsp/dsp_task.c b/src/RVL_SDK/dsp/dsp_task.c new file mode 100644 index 000000000..a5d9abd3a --- /dev/null +++ b/src/RVL_SDK/dsp/dsp_task.c @@ -0,0 +1,118 @@ +#include +#include + +#define WAIT_FOR_MAIL \ + while (DSPCheckMailTDSP()) { } + +DSPTaskInfo* __DSP_curr_task; +DSPTaskInfo* __DSP_first_task; +DSPTaskInfo* __DSP_last_task; +DSPTaskInfo* __DSP_tmp_task; + +void __DSP_exec_task(DSPTaskInfo *pCurrent, DSPTaskInfo *pNext) { + if (pCurrent != NULL) { + DSPSendMailToDSP((u32)pCurrent->dram_mem_addr); + WAIT_FOR_MAIL + DSPSendMailToDSP(pCurrent->dram_len); + WAIT_FOR_MAIL + DSPSendMailToDSP(pCurrent->dram_addr); + WAIT_FOR_MAIL + } + else { + DSPSendMailToDSP(0); + WAIT_FOR_MAIL + DSPSendMailToDSP(0); + WAIT_FOR_MAIL + DSPSendMailToDSP(0); + WAIT_FOR_MAIL + } + + DSPSendMailToDSP((u32)pNext->iram_mmem_addr); + WAIT_FOR_MAIL + DSPSendMailToDSP(pNext->iram_length); + WAIT_FOR_MAIL + DSPSendMailToDSP(pNext->iram_addr); + WAIT_FOR_MAIL + + if (pNext->state == 0) { + DSPSendMailToDSP((u32)pNext->dsp_vector); + WAIT_FOR_MAIL + DSPSendMailToDSP(0); + WAIT_FOR_MAIL + DSPSendMailToDSP(0); + WAIT_FOR_MAIL + DSPSendMailToDSP(0); + WAIT_FOR_MAIL + } + else { + DSPSendMailToDSP((u32)pNext->dsp_res_vector); + WAIT_FOR_MAIL + DSPSendMailToDSP((u32)pNext->dram_mem_addr); + WAIT_FOR_MAIL + DSPSendMailToDSP(pNext->dram_len); + WAIT_FOR_MAIL + DSPSendMailToDSP(pNext->dram_addr); + WAIT_FOR_MAIL + } +} + +void __DSP_boot_task(DSPTaskInfo *pTask) { + // volatile because it's stored in stack but never used + volatile u32 mail; + + while (!DSPCheckMailFromDSP()) { } + mail = DSPRealMailFromDSP(); + + DSPSendMailToDSP(0x80F3A001); + WAIT_FOR_MAIL + DSPSendMailToDSP((u32)(pTask->iram_mmem_addr)); + WAIT_FOR_MAIL + DSPSendMailToDSP(0x80F3C002); + WAIT_FOR_MAIL + DSPSendMailToDSP((u32)(pTask->iram_addr & 0xFFFF)); + WAIT_FOR_MAIL + DSPSendMailToDSP(0x80F3A002); + WAIT_FOR_MAIL + DSPSendMailToDSP(pTask->iram_length); + WAIT_FOR_MAIL + DSPSendMailToDSP(0x80F3B002); + WAIT_FOR_MAIL + DSPSendMailToDSP(0); + WAIT_FOR_MAIL + DSPSendMailToDSP(0x80F3D001); + WAIT_FOR_MAIL + DSPSendMailToDSP((u32)(0xFFFF & pTask->dsp_vector)); + WAIT_FOR_MAIL + + __DSP_debug_printf("DSP is booting task: 0x%08X\n", pTask); + __DSP_debug_printf("__DSP_boot_task() : IRAM MMEM ADDR: 0x%08X\n", (u32)(pTask->iram_mmem_addr)); + __DSP_debug_printf("__DSP_boot_task() : IRAM DSP ADDR : 0x%08X\n", pTask->iram_addr); + __DSP_debug_printf("__DSP_boot_task() : IRAM LENGTH : 0x%08X\n", pTask->iram_length); + __DSP_debug_printf("__DSP_boot_task() : DRAM MMEM ADDR: 0x%08X\n", pTask->dram_len); + __DSP_debug_printf("__DSP_boot_task() : Start Vector : 0x%08X\n", (u32)(pTask->dsp_vector)); +} + +void __DSP_remove_task(DSPTaskInfo *pTask) { + pTask->flags = 0; + pTask->state = 3; + + if (__DSP_first_task == pTask) { + if (pTask->next != NULL) { + __DSP_first_task = pTask->next; + pTask->next->prev = NULL; + } + else { + __DSP_first_task = __DSP_last_task = __DSP_curr_task = NULL; + } + } + else if (__DSP_last_task == pTask) { + __DSP_last_task = pTask->prev; + pTask->prev->next = NULL; + __DSP_curr_task = __DSP_first_task; + } + else { + __DSP_curr_task = pTask->next; + pTask->prev->next = pTask->next; + pTask->next->prev = pTask->prev; + } +} \ No newline at end of file diff --git a/src/RVL_SDK/dvd/dvd.c b/src/RVL_SDK/dvd/dvd.c new file mode 100644 index 000000000..1da457a1d --- /dev/null +++ b/src/RVL_SDK/dvd/dvd.c @@ -0,0 +1,2297 @@ +#include +#include +#include +#include + +#define MIN(a, b) (((a) > (b))? (b) : (a)) + +extern DVDErrorInfo __ErrorInfo; +static DVDCommandBlock* executing; + +static DVDBB2 BB2 __attribute__ ((aligned(32))); +static DVDDiskID CurrDiskID __attribute__ ((aligned(32))); + +static DVDDiskID* IDShouldBe; +static OSBootInfo* bootInfo; +static BOOL autoInvalidation = TRUE; + +static DVDCommandBlock DummyCommandBlock; +DVDCommandBlock __DVDStopMotorCommandBlock; +DVDCommandBlock __DVDRestartMotorCommandBlock; +extern OSThreadQueue __DVDThreadQueue; + +static vu32 CurrCommand; +static vu32 Canceling = FALSE; +static DVDCBCallback CancelCallback; +static vu32 LastError; +static vs32 NumInternalRetry = 0; +static volatile BOOL ResetRequired; +static volatile BOOL PauseFlag; +static volatile BOOL PausingFlag; +static volatile BOOL AutoFinishing = FALSE; +static volatile BOOL FatalErrorFlag = FALSE; +static vu32 WaitingForCoverOpen = FALSE; +static vu32 WaitingForCoverClose = FALSE; +static vu32 MotorStopped = FALSE; +static vu32 ChangedDisc = FALSE; +static volatile BOOL PreparingCover = FALSE; +static u32 MotorState; +static volatile OSTime LastResetEnd; +static vu32 CoverState; + +static vu32 ResumeFromHere = 0; +static vu32 CancelLastError; +static volatile BOOL FirstTimeInBootrom = FALSE; + +static OSAlarm ResetAlarm; +static OSAlarm CoverAlarm; + +extern BOOL __OSInIPL; + +static vu32 Breaking = FALSE; + +static u32 __DVDNumTmdBytes __attribute__ ((aligned(32))); +static u8 __DVDGameTocBuffer[OSRoundUp32B(sizeof(DVDGameTOC) * 4)] __attribute__ ((aligned(32))); +static u8 __DVDPartInfoBuffer[OSRoundUp32B(sizeof(DVDPartitionInfo) * 4)] __attribute__ ((aligned(32))); +static u8 __DVDTmdBuffer[OSRoundUp32B(sizeof(ESTitleMeta))] __attribute__ ((aligned(32))); +static u8 __DVDTicketViewBuffer[OSRoundUp32B(sizeof(ESTicketView))] __attribute__ ((aligned(32))); + +vu16 __OSDeviceCode : (OS_BASE_CACHED | 0x30E6); +vu8 __OSLockedFlag : (OS_BASE_CACHED | 0x3187); +vu32 __OSLaunchPartitionType : (OS_BASE_CACHED | 0x3194); + +typedef void (*stateFunc)(DVDCommandBlock* block); +stateFunc LastState; + +void defaultOptionalCommandChecker(DVDCommandBlock* block, DVDLowCallback cb) { + return; +} + +static DVDOptionalCommandChecker checkOptionalCommand = defaultOptionalCommandChecker; + +volatile u32 CommandInfoCounter = 0; + +__declspec(weak) void StampCommand(u32 command, u32 offset, u32 length) { + BOOL enabled = OSDisableInterrupts(); + + if (CommandInfoCounter >= 5) { + CommandInfoCounter = 0; + } + + __ErrorInfo.lastCommand[CommandInfoCounter].command = command; + __ErrorInfo.lastCommand[CommandInfoCounter].offset = offset; + __ErrorInfo.lastCommand[CommandInfoCounter].length = length; + __ErrorInfo.lastCommand[CommandInfoCounter].tick = OSGetTick(); + CommandInfoCounter++; + OSRestoreInterrupts(enabled); +} + +void StampIntType(u32 intType) { + BOOL enabled = OSDisableInterrupts(); + + if (CommandInfoCounter == 0) { + __ErrorInfo.lastCommand[4].intType = intType; + } + else { + __ErrorInfo.lastCommand[CommandInfoCounter - 1].intType = intType; + } + + OSRestoreInterrupts(enabled); +} + +volatile u32 __DVDLayoutFormat = 2; +static BOOL DVDInitialized = FALSE; +const char* __DVDVersion = "<< RVL_SDK - DVD \trelease build: Feb 22 2008 06:17:35 (0x4199_60831) >>"; + +static void stateDownRotation(DVDCommandBlock *); +static void stateGettingError(void); +static void stateReadingFST(void); +static void stateReady(void); +static void stateGoToRetry(void); +static void stateBusy(DVDCommandBlock *); +static void stateReadingTOC(DVDCommandBlock *); +static void stateCheckID2a(DVDCommandBlock *); +static void stateCheckID3(DVDCommandBlock *); +static void stateReadingPartitionInfo(DVDCommandBlock *); +static void stateOpenPartition(DVDCommandBlock* ); +static void stateOpenPartition2(DVDCommandBlock *); +static void stateTimeout(void); +static void stateSecurityError(void); +static void stateMotorStopped(void); +static void stateCoverClosed(void); +static void stateCoverClosed_CMD(DVDCommandBlock *); + +static void cbForStateReadingFST(u32); +static void cbForStateGoToRetry(u32); +static void cbForStateCheckID1(u32); +static void cbForStateCheckID2(u32); +static void cbForStateCheckID2a(u32); +static void cbForStateCheckID3(u32); +static void cbForStateGettingError(u32); +static void cbForUnrecoveredErrorRetry(u32); +static void cbForUnrecoveredError(u32); +static void cbForStateMotorStopped(u32); +static void cbForStateBusy(u32); +static void cbForStateError(u32); +static void cbForStateDownRotation(u32); +static void cbForStateReset(u32); +static void cbForStoreErrorCode1(s32, DVDCommandBlock *); +static void cbForStoreErrorCode2(s32, DVDCommandBlock *); +static void stateCheckID2(DVDCommandBlock *); +static void cbForStateCoverClosed(u32); +static void cbForStateOpenPartition(u32); + +static void CoverAlarmHandler(OSAlarm *, OSContext *); +static void ResetAlarmHandler(OSAlarm *, OSContext *); + +void DVDInit(void) { + DVDDiskID* id; + s32 rv; + + if (DVDInitialized) { + return; + } + + OSRegisterVersion(__DVDVersion); + DVDInitialized = TRUE; + DVDLowInit(); + + if (!__OSInIPL && __OSLockedFlag == 0x80) { + rv = ESP_InitLib(); + + if (rv == 0) { + rv = ESP_DiGetTicketView(NULL, (ESTicketView*)__DVDTicketViewBuffer); + } + + if (rv == 0) { + rv = ESP_DiGetTmd(NULL, &__DVDNumTmdBytes); + } + + if (rv == 0) { + rv = ESP_DiGetTmd((ESTitleMeta*)__DVDTmdBuffer, &__DVDNumTmdBytes); + } + + ESP_CloseLib(); + } + + __DVDFSInit(); + __DVDClearWaitingQueue(); + + MotorState = 0; + bootInfo = (OSBootInfo*)OSPhysicalToCached(0); + IDShouldBe = &bootInfo->DVDDiskID; + OSInitThreadQueue(&__DVDThreadQueue); + + DVDLowUnmaskStatusInterrupts(); + DVDLowMaskCoverInterrupt(); + + if (bootInfo->magic == 0xE5207C22) { + + } + else if (bootInfo->magic == 0x0D15EA5E) { + + } + else { + FirstTimeInBootrom = TRUE; + } + + memset(&__ErrorInfo, 0, sizeof(DVDErrorInfo)); + id = (DVDDiskID*)OSPhysicalToCached(0); + memcpy(__ErrorInfo.gameName, id->gameName, 4); + __ErrorInfo.diskNumber = id->diskNumber; + __ErrorInfo.gameVersion = id->gameVersion; + __DVDLayoutFormat = 0; + DVDSetAutoFatalMessaging(TRUE); +} + +static void stateReadingFST(void) { + LastState = (stateFunc)stateReadingFST; + + if (!(bootInfo->FSTMaxLength >= BB2.FSTLength)) { + OSPanic(__FILE__, 0x43B, "DVDChangeDisk(): FST in the new disc is too big. "); + } + + DVDLowClearCoverInterrupt(NULL); + StampCommand(1, BB2.FSTPosition >> __DVDLayoutFormat, OSRoundUp32B(BB2.FSTLength << (~__DVDLayoutFormat & 2))); + DVDLowRead(bootInfo->FSTLocation, OSRoundUp32B(BB2.FSTLength << (~__DVDLayoutFormat & 2)), BB2.FSTPosition >> __DVDLayoutFormat, cbForStateReadingFST); +} + +static void cbForStateReadingFST(u32 intType) { + DVDCommandBlock* finished; + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 1) { + NumInternalRetry = 0; + __DVDFSInit(); + finished = executing; + executing = &DummyCommandBlock; + finished->state = 0; + + if (finished->callback) { + (finished->callback)(0, finished); + } + + stateReady(); + } + else { + stateGettingError(); + } +} + +static OSAlarm FatalAlarm; +static void FatalAlarmHandler(OSAlarm* alarm, OSContext* context) { + __DVDPrintFatalMessage(); +} + +static void cbForStateError(u32 intType) { + DVDCommandBlock* finished; + + if (__DVDGetAutoFatalMessaging()) { + OSCreateAlarm(&FatalAlarm); + OSSetAlarm(&FatalAlarm, 1, FatalAlarmHandler); + } + else { + executing->state = -1; + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + FatalErrorFlag = FALSE; + finished = executing; + executing = &DummyCommandBlock; + + if (finished->callback) { + (finished->callback)(-1, finished); + } + + if (Canceling) { + Canceling = FALSE; + + if (CancelCallback) { + (CancelCallback)(0, finished); + } + } + + stateReady(); + } + + return; +} + +static void cbForStoreErrorCode1(s32 result, DVDCommandBlock* block) { + DVDLowStopMotor(FALSE, FALSE, cbForStateError); +} + +static void stateError(u32 error) { + __DVDStoreErrorCode(error, cbForStoreErrorCode1); +} + +static void cbForStoreErrorCode2(s32 result, DVDCommandBlock* block) { + DVDLowSetSpinupFlag(0); + DVDLowReset(cbForStateError); + ResetRequired = FALSE; + ResumeFromHere = 0; +} + +static void stateTimeout(void) { + __DVDStoreErrorCode(0x1234568, cbForStoreErrorCode2); +} + +static void stateSecurityError(void) { + __DVDStoreErrorCode(0x1234569, cbForStoreErrorCode2); +} + +static void stateGettingError(void) { + StampCommand(39, 0, 0); + DVDLowRequestError(cbForStateGettingError); +} + +u32 CategorizeError(u32 error) { + if (error == 0x20400) { + LastError = error; + return 1; + } + + error &= 0xFFFFFF; + + if (error == 0x62800 || error == 0x23A00 || error == 0x53000 || error == 0xB5A01) { + return 0; + } + + if ((error == 0x52000) && ((executing->command == 37) || (LastState == stateDownRotation)) ) { + return 0; + } + + NumInternalRetry++; + if (NumInternalRetry == 2) { + if (error == LastError) { + LastError = error; + return 1; + } + else { + LastError = error; + return 2; + } + } + else { + LastError = error; + + if (error == 0x31100 || executing->command == 5) { + return 2; + } + else { + return 3; + } + } +} + +static BOOL CheckCancel(u32 resume) { + DVDCommandBlock* finished; + + if (Canceling) { + ResumeFromHere = resume; + Canceling = FALSE; + finished = executing; + executing = &DummyCommandBlock; + + finished->state = 10; + if (finished->callback) { + (*finished->callback)(-3, finished); + } + + if (CancelCallback) { + (CancelCallback)(0, finished); + } + + stateReady(); + return TRUE; + } + else { + return FALSE; + } +} + +static void cbForStoreErrorCode3(s32 result, DVDCommandBlock* block) { + stateGoToRetry(); +} + +static void cbForStateGettingError(u32 intType) { + u32 error, status, errorCategory, resume; + + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 2) { + stateError(0x1234567); + return; + } + + error = DVDLowGetImmBufferReg(); + status = error & 0xFF000000; + errorCategory = CategorizeError(error); + + if (errorCategory == 1) { + stateError(error); + return; + } + + if ((errorCategory == 2) || (errorCategory == 3)) { + resume = 0; + } + else { + if (status == 0x1000000) { + resume = 4; + } + else if (status == 0x2000000) { + resume = 6; + } + else if (status == 0x3000000) { + resume = 3; + } + else if (status == 0) { + if (error == 0x53000) { + resume = 1; + } + else { + resume = 5; + } + } + else { + resume = 5; + } + } + + if (CheckCancel(resume)) { + return; + } + + if (errorCategory == 2) { + __DVDStoreErrorCode(error, cbForStoreErrorCode3); + return; + } + + if (errorCategory == 3) { + if ((error & 0xFFFFFF) == 0x31100) { + StampCommand(2, executing->offset, 0); + DVDLowSeek(executing->offset, cbForUnrecoveredError); + } + else { + LastState(executing); + } + + return; + } + + if (status == 0x1000000) { + executing->state = 5; + stateMotorStopped(); + return; + } + else if (status == 0x2000000) { + executing->state = 3; + stateCoverClosed(); + return; + } + else if (status == 0x3000000) { + executing->state = 4; + stateMotorStopped(); + return; + } + else if (status == 0) { + if (error == 0x53000) { + StampCommand(16, 0, 0); + DVDLowStopMotor(FALSE, FALSE, cbForStateCheckID1); + return; + } + else { + stateError(0x1234567); + return; + } + } + else { + stateError(0x1234567); + return; + } +} + +static void cbForUnrecoveredError(u32 intType) { + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 1) { + stateGoToRetry(); + return; + } + + StampCommand(39, 0, 0); + DVDLowRequestError(cbForUnrecoveredErrorRetry); +} + +static void cbForUnrecoveredErrorRetry(u32 intType) { + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 2) { + stateError(0x1234567); + } + else { + stateError(DVDLowGetImmBufferReg()); + } + + return; +} + +static void stateGoToRetry(void) { + StampCommand(16, 0, 0); + DVDLowStopMotor(FALSE, FALSE, cbForStateGoToRetry); +} + +static void cbForStateGoToRetry(u32 intType) { + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 2) { + stateError(0x1234567); + return; + } + + NumInternalRetry = 0; + + if ((CurrCommand == 4 || CurrCommand == 5 || CurrCommand == 13 || CurrCommand == 33 || CurrCommand == 34 || CurrCommand == 41 || CurrCommand == 42 || CurrCommand == 15 || CurrCommand == 37)) { + ResetRequired = TRUE; + } + + if (!CheckCancel(2)) { + executing->state = 11; + stateMotorStopped(); + } +} + +void stateCheckID(void) { + switch (CurrCommand) { + case 3: + ChangedDisc = FALSE; + + if (DVDCompareDiskID(&CurrDiskID, executing->id)) { + memcpy(IDShouldBe, &CurrDiskID, sizeof(DVDDiskID)); + executing->state = 1; + DCInvalidateRange(&BB2, sizeof(DVDBB2)); + NumInternalRetry = 0; + stateReadingTOC(executing); + return; + } + else { + StampCommand(16, 0, 0); + DVDLowStopMotor(FALSE, FALSE, cbForStateCheckID1); + } + break; + + default: + if (memcmp(&CurrDiskID, IDShouldBe, sizeof(DVDDiskID))) { + StampCommand(16, 0, 0); + DVDLowStopMotor(FALSE, FALSE, cbForStateCheckID1); + } + else { + NumInternalRetry = 0; + stateReadingTOC(executing); + } + + break; + } +} + +static void stateCheckID3(DVDCommandBlock* block) { + StampCommand(13, IDShouldBe->streaming, 10); + DVDLowAudioBufferConfig((BOOL)IDShouldBe->streaming, 10, cbForStateCheckID3); +} + +static void stateCheckID2a(DVDCommandBlock* block) { + StampCommand(13, IDShouldBe->streaming, 10); + DVDLowAudioBufferConfig((BOOL)IDShouldBe->streaming, 10, cbForStateCheckID2a); +} + +static void cbForStateCheckID2a(u32 intType) { + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 1) { + NumInternalRetry = 0; + stateCheckID2(executing); + } + else { + stateGettingError(); + } +} + +static DVDGameTOC* GameToc; +static DVDPartitionInfo* PartInfo; +static DVDPartitionInfo* BootGameInfo; +static ESTitleMeta* Tmd; + +static void cbForStateReadingTOC(u32 intType) { + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 1) { + NumInternalRetry = 0; + GameToc = (DVDGameTOC*)__DVDGameTocBuffer; + stateReadingPartitionInfo(executing); + } + else { + stateGettingError(); + } +} + +static void stateReadingTOC(DVDCommandBlock* block) { + DVDLowClearCoverInterrupt(NULL); + StampCommand(33, 0x40000 >> 2, OSRoundUp32B(sizeof(DVDGameTOC))); + DVDLowUnencryptedRead(__DVDGameTocBuffer, OSRoundUp32B(sizeof(DVDGameTOC)), 0x10000, cbForStateReadingTOC); +} + +static void cbForStateReadingPartitionInfo(u32 intType) { + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 1) { + s16 i; + NumInternalRetry = 0; + PartInfo = (DVDPartitionInfo*)__DVDPartInfoBuffer; + BootGameInfo = NULL; + + if (*((u32*)OSPhysicalToCached(0x3198))) { + BootGameInfo = PartInfo; + BootGameInfo->type = *((u32*)OSPhysicalToCached(0x3194)); + BootGameInfo->gamePartition = (DVDGamePartition*)*((u32*)OSPhysicalToCached(0x3198)); + } + else { + for ( i = 0; i < GameToc->numGamePartitions; i++) { + if (PartInfo->type == __OSLaunchPartitionType) { + BootGameInfo = PartInfo; + } + + PartInfo++; + } + } + + if (BootGameInfo) { + switch (CurrCommand) { + case 3: + NumInternalRetry = 0; + stateOpenPartition(executing); + break; + + default: + NumInternalRetry = 0; + stateOpenPartition2(executing); + break; + } + } + else { + if (!CheckCancel(1)) { + executing->state = 6; + stateMotorStopped(); + } + } + } + else { + stateGettingError(); + } +} + +static void stateReadingPartitionInfo(DVDCommandBlock* block) { + DVDLowClearCoverInterrupt(0); + StampCommand(33, (0x40000 + OSRoundUp32B(sizeof(DVDGameTOC))) >> 2, OSRoundUp32B(sizeof(DVDPartitionInfo))); + DVDLowUnencryptedRead(__DVDPartInfoBuffer, OSRoundUp32B(sizeof(DVDPartitionInfo)), (0x40000 + OSRoundUp32B(sizeof(DVDGameTOC))) >> 2, cbForStateReadingPartitionInfo); +} + +static void stateOpenPartition(DVDCommandBlock* block) { + DVDLowClearCoverInterrupt(0); + StampCommand(34, (u32)BootGameInfo->gamePartition, 0); + + if (__OSLockedFlag == 0x80) { + DVDLowOpenPartitionWithTmdAndTicketView((u32)BootGameInfo->gamePartition, (ESTicketView*)__DVDTicketViewBuffer, __DVDNumTmdBytes, (ESTitleMeta*)__DVDTmdBuffer, 0, NULL, cbForStateOpenPartition); + } + else { + DVDLowOpenPartition((u32)BootGameInfo->gamePartition, NULL, 0, 0, (ESTitleMeta*)__DVDTmdBuffer, cbForStateOpenPartition); + } +} + +static void cbForStateOpenPartition(u32 intType) { + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 1) { + NumInternalRetry = 0; + stateCheckID2(executing); + } + else { + stateGettingError(); + } +} + +static void cbForStateOpenPartition2(u32 intType) { + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 1) { + NumInternalRetry = 0; + + if (!CheckCancel(0)) { + executing->state = 1; + stateBusy(executing); + } + } + else { + stateGettingError(); + } +} + +static void stateOpenPartition2(DVDCommandBlock* block) { + DVDLowClearCoverInterrupt(0); + StampCommand(34, (u32)BootGameInfo->gamePartition, 0); + + if (__OSLockedFlag == 0x80) { + DVDLowOpenPartitionWithTmdAndTicketView((u32)BootGameInfo->gamePartition, (ESTicketView*)__DVDTicketViewBuffer, __DVDNumTmdBytes, (ESTitleMeta*)__DVDTmdBuffer, 0, NULL, cbForStateOpenPartition2); + } + else { + DVDLowOpenPartition((u32)BootGameInfo->gamePartition, NULL, 0, 0, (ESTitleMeta*)__DVDTmdBuffer, cbForStateOpenPartition2); + } +} + +static void stateCheckID2(DVDCommandBlock* block) { + DVDLowClearCoverInterrupt(0); + StampCommand(1, (u32)(0x420 >> 2), OSRoundUp32B(sizeof(DVDBB2))); + DVDLowRead(&BB2, OSRoundDown32B(sizeof(DVDBB2)), (u32)(0x420 >> 2), cbForStateCheckID2); +} + +static void cbForStateCheckID1(u32 intType) { + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 2) { + stateError(0x1234567); + return; + } + + NumInternalRetry = 0; + + if (!CheckCancel(1)) { + executing->state = 6; + stateMotorStopped(); + } +} + +static void cbForStateCheckID2(u32 intType) { + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 1) { + NumInternalRetry = 0; + stateReadingFST(); + } + else { + stateGettingError(); + } +} + +static void cbForStateCheckID3(u32 intType) { + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 1) { + NumInternalRetry = 0; + + if (!CheckCancel(0)) { + executing->state = 1; + stateBusy(executing); + } + } + else { + stateGettingError(); + } +} + + +static void stateCoverClosed(void) { + DVDCommandBlock* finished; + MotorState = 1; + + switch (CurrCommand) { + case 5: + case 4: + case 33: + case 34: + case 41: + case 42: + case 13: + case 15: + case 37: + __DVDClearWaitingQueue(); + finished = executing; + executing = &DummyCommandBlock; + + if (finished->callback) { + (finished->callback)(-4, finished); + } + + stateReady(); + break; + + case 32: + MotorState = 0; + + case 35: + case 38: + case 36: + executing->state = 1; + stateBusy(executing); + break; + + case 1: + case 2: + if (__OSInIPL) { + break; + } + + default: + MotorState = 0; + DVDLowSetSpinupFlag(1); + DVDLowReset(cbForStateReset); + break; + } +} + +static void ResetAlarmHandler(OSAlarm* alarm, OSContext* context) { + if (__OSDeviceCode == (u16)(0x8000 | 0x003)) { + LastState = stateDownRotation; + stateDownRotation(executing); + } + else { + DCInvalidateRange(&CurrDiskID, sizeof(DVDDiskID)); + LastState = stateCoverClosed_CMD; + stateCoverClosed_CMD(executing); + } +} + +static void cbForStateReset(u32 intType) { + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 1) { + LastResetEnd = __OSGetSystemTime(); + ResetRequired = FALSE; + ResumeFromHere = 0; + OSCreateAlarm(&ResetAlarm); + OSSetAlarm(&ResetAlarm, DVD_RESETCOVER_TIMELAG_TICKS2, ResetAlarmHandler); + } + else { + stateGettingError(); + } +} + +extern BOOL __OSIsDiag; +void __DVDShowFatalMessageForSystem(u32 command, u32 intType); +static void stateMotorStopped(void) { + MotorState = 1; + + if (WaitingForCoverOpen || WaitingForCoverClose) { + return; + } + + WaitingForCoverOpen = TRUE; + OSCreateAlarm(&CoverAlarm); + OSSetPeriodicAlarm(&CoverAlarm, OSGetTick(), OSMillisecondsToTicks(100), CoverAlarmHandler); +} + +static void cbForStateMotorStopped(u32 intType) { + WaitingForCoverClose = FALSE; + + if (CurrCommand == 3) { + ChangedDisc = TRUE; + } + + if (MotorState == 2) { + if (executing) { + executing->state = 12; + } + + return; + } + + DVDLowMaskCoverInterrupt(); + + if (executing) { + executing->state = 3; + stateCoverClosed(); + } + else { + ResumeFromHere = 7; + } +} + + + +static u32 ImmCommand[] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; +static u32 DmaCommand[] = { 0xFFFFFFFF }; +#define USE_DMA(command) ((command == 1) || \ + (command == 4) || \ + (command == 5) || \ + (command == 33) || \ + (command == 14) ) + +#define REQUEST_AUDIO_STATUS(command) ( (command == 9) || \ + (command == 10) || \ + (command == 11) || \ + (command == 12) ) + +static BOOL IsImmCommandWithResult(u32 command) { + u32 i; + + if (REQUEST_AUDIO_STATUS(command)) { + return TRUE; + } + + for (i = 0; i < sizeof(ImmCommand) / sizeof(ImmCommand[0]); i++) { + if (command == ImmCommand[i]) { + return TRUE; + } + } + + return FALSE; +} + +static BOOL IsDmaCommand(u32 command) { + u32 i; + + if (USE_DMA(command)) { + return TRUE; + } + + for (i = 0 ; i < sizeof(DmaCommand) / (sizeof(DmaCommand[0])); i++) { + if (command == DmaCommand[i]) { + return TRUE; + } + } + + return FALSE; +} + +static void cbForStateBusy(u32 intType) { + DVDCommandBlock* finished; + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if ((CurrCommand == 3) || (CurrCommand == 15)) { + if (intType & 2) { + stateError(0x1234567); + return; + } + + NumInternalRetry = 0; + + if (CurrCommand == 15) { + ResetRequired = TRUE; + } + + if (CheckCancel(7)) { + return; + } + + if (MotorState != 2) { + executing->state = 7; + stateMotorStopped(); + } + + return; + } + else { + if (IsDmaCommand(CurrCommand)) { + executing->transferredSize += (intType & (8 | 1)) ? executing->currTransferSize : 0; + } + + if (Breaking) { + Breaking = FALSE; + Canceling = FALSE; + + finished = executing; + executing = &DummyCommandBlock; + finished->state = 10; + + if (finished->callback) { + (*finished->callback)(-3, finished); + } + + if (CancelCallback) { + (CancelCallback)(0, finished); + } + + stateReady(); + return; + } + + if (intType & 1) { + NumInternalRetry = 0; + + if (CurrCommand == 16) { + if (executing->offset) { + MotorState = 2; + } + else { + MotorState = 1; + } + + finished = executing; + executing = &DummyCommandBlock; + finished->state = 0; + + if (finished->callback) { + (finished->callback)(0, finished); + } + + stateReady(); + return; + } + + if (CurrCommand == 32) { + LastResetEnd = __OSGetSystemTime(); + + ResetRequired = FALSE; + ResumeFromHere = 0; + + finished = executing; + executing = &DummyCommandBlock; + + finished->state = 0; + if (finished->callback) + { + (finished->callback)(0, finished); + } + + stateReady(); + return; + } + + if (CheckCancel(0)) { + return; + } + + if (CurrCommand == 38) { + s32 retVal; + u32 coverReg; + + coverReg = DVDLowGetCoverRegister(); + + if (__OSGetSystemTime() - LastResetEnd < DVD_RESETCOVER_TIMELAG_TICKS2) { + retVal = 0; + } + else if (coverReg & 1) { + retVal = 1; + } + else { + retVal = 2; + } + + finished = executing; + executing = &DummyCommandBlock; + + finished->state = 0; + finished->offset = (u32)retVal; + if (finished->callback) { + (finished->callback)(retVal, finished); + } + + stateReady(); + return; + } + + if (CurrCommand == 36) { + s32 retVal; + u32 coverReg; + + coverReg = DVDLowGetCoverRegister(); + if (((((unsigned long)(coverReg)) & 0x00000004) >> 2) || (coverReg & 1)) { + retVal = FALSE; + } + else { + if (ResumeFromHere != 0) { + retVal = FALSE; + } + else { + retVal = TRUE; + } + } + + finished = executing; + executing = &DummyCommandBlock; + + finished->state = 0; + finished->offset = (u32)retVal; + + if (finished->callback) { + (finished->callback)(retVal, finished); + } + + stateReady(); + return; + } + + if (CurrCommand == 40) { + if (DVDCompareDiskID(&CurrDiskID, executing->id)) { + memcpy(IDShouldBe, &CurrDiskID, sizeof(DVDDiskID)); + finished = executing; + executing = &DummyCommandBlock; + + finished->state = 0; + finished->offset = (u32)TRUE; + if (finished->callback) { + (finished->callback)(TRUE, finished); + } + + NumInternalRetry = 0; + + stateReady(); + return; + } + else { + StampCommand(16, 0, 0); + DVDLowStopMotor(FALSE, FALSE, cbForStateCheckID1); + return; + } + } + + if (CurrCommand == 41) { + DVDPartitionParams* params; + + params = (DVDPartitionParams*)(executing->addr); + if (!params->dataWordOffset) + { + stateBusy(executing); + return; + } + + finished = executing; + executing = &DummyCommandBlock; + + finished->state = 0; + if (finished->callback) + { + (finished->callback)(0, finished); + } + + stateReady(); + return; + } + + if (IsDmaCommand(CurrCommand)) { + if (executing->transferredSize != executing->length) { + stateBusy(executing); + return; + } + + finished = executing; + executing = &DummyCommandBlock; + + finished->state = 0; + if (finished->callback) { + (finished->callback)((s32)finished->transferredSize, finished); + } + stateReady(); + } + else if (IsImmCommandWithResult(CurrCommand)) { + s32 result; + + if ((CurrCommand == 11) || (CurrCommand == 10)) { + result = (s32)(DVDLowGetImmBufferReg() << 2); + } + else { + result = (s32)DVDLowGetImmBufferReg(); + } + + finished = executing; + executing = &DummyCommandBlock; + + finished->state = 0; + if (finished->callback) { + (finished->callback)(result, finished); + } + + stateReady(); + } + else { + finished = executing; + executing = &DummyCommandBlock; + + finished->state = 0; + if (finished->callback) { + (finished->callback)(0, finished); + } + stateReady(); + } + } + else { + if (CurrCommand == 14) { + stateError(0x1234567); + return; + } + + if ((USE_DMA(CurrCommand)) && (executing->transferredSize == executing->length)) { + if (CheckCancel(0)) { + return; + } + + finished = executing; + executing = &DummyCommandBlock; + finished->state = 0; + + if (finished->callback) { + (finished->callback)((s32)finished->transferredSize, finished); + } + + stateReady(); + return; + } + + stateGettingError(); + } + } +} + +static void stateDownRotation(DVDCommandBlock* block) { + DVDLowClearCoverInterrupt(0); + StampCommand(37, 0, 0); + DVDLowSetMaximumRotation(0x20000, cbForStateDownRotation); +} + +static void stateCoverClosed_CMD(DVDCommandBlock *); + +static void cbForStateDownRotation(u32 intType) { + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 1) { + DCInvalidateRange(&CurrDiskID, sizeof(DVDDiskID)); + LastState = stateCoverClosed_CMD; + stateCoverClosed_CMD(executing); + } + else { + stateGettingError(); + } +} + +static void stateCoverClosed_CMD(DVDCommandBlock* block) { + if (CurrCommand == 40) { + NumInternalRetry = 0; + + if (!CheckCancel(0)) { + executing->state = 1; + stateBusy(executing); + } + } + else { + DVDLowClearCoverInterrupt(0); + StampCommand(5, 0, sizeof(DVDDiskID)); + DVDLowReadDiskID(&CurrDiskID, cbForStateCoverClosed); + } +} + +static void cbForStateCoverClosed(u32 intType) { + StampIntType(intType); + + if (intType == 16) { + stateTimeout(); + return; + } + + if (intType == 32) { + stateSecurityError(); + return; + } + + if (intType & 1) { + NumInternalRetry = 0; + stateCheckID(); + } + else { + stateGettingError(); + } +} + +static void cbForPrepareCoverRegister(u32 intType) { + PreparingCover = FALSE; + + if (WaitingForCoverClose) { + if (!(DVDLowGetCoverRegister() & 1)) { + OSCancelAlarm(&CoverAlarm); + WaitingForCoverClose = FALSE; + cbForStateMotorStopped(4); + } + + return; + } + + if (DVDLowGetCoverRegister() & 1) { + WaitingForCoverOpen = FALSE; + WaitingForCoverClose = TRUE; + + if (MotorState == 2) { + executing->state = 12; + } + else { + executing->state = 5; + } + } + else if (DVDLowGetCoverRegister() & 4) { + OSCancelAlarm(&CoverAlarm); + WaitingForCoverOpen = FALSE; + DVDLowClearCoverInterrupt(0); + cbForStateMotorStopped(4); + } +} + +static void CoverAlarmHandler(OSAlarm* alarm, OSContext* context) { + if (!PreparingCover) { + PreparingCover = TRUE; + DVDLowPrepareCoverRegister(cbForPrepareCoverRegister); + } +} + +static void stateReady(void) { + DVDCommandBlock* finished; + + if (!__DVDCheckWaitingQueue()) { + executing = NULL; + return; + } + + if (PauseFlag) { + PausingFlag = TRUE; + executing = NULL; + return; + } + + executing = __DVDPopWaitingQueue(); + + if (FatalErrorFlag) { + executing->state = -1; + finished = executing; + executing = &DummyCommandBlock; + + if (finished->callback) { + (finished->callback)(-1, finished); + } + + stateReady(); + return; + } + + CurrCommand = executing->command; + + if ((CurrCommand == 32) || (CurrCommand == 14) || (CurrCommand == 35)) { + ResumeFromHere = 0; + } + + if (ResumeFromHere) { + switch (ResumeFromHere) { + case 2: + executing->state = 11; + stateMotorStopped(); + break; + case 3: + executing->state = 4; + stateMotorStopped(); + break; + case 4: + executing->state = 5; + stateMotorStopped(); + break; + case 1: + case 7: + case 6: + executing->state = 3; + stateCoverClosed(); + break; + + case 5: + stateError(CancelLastError); + break; + } + + ResumeFromHere = 0; + } + else { + switch (MotorState) { + case 2: + if (MotorStopped) { + executing->state = 12; + } + else { + executing->state = 3; + stateCoverClosed(); + } + break; + case 0: + executing->state = 1; + stateBusy(executing); + break; + case 1: + default: + stateCoverClosed(); + break; + } + } +} + +static void stateBusy(DVDCommandBlock* block) { + DVDCommandBlock* finished; + LastState = stateBusy; + + switch (block->command) { + case 5: + case 2: + case 3: + case 15: + case 14: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 16: + case 34: + case 37: + case 41: + case 42: + StampCommand(block->command, block->offset, block->length); + break; + default: + break; + } + + switch (block->command) { + case 5: + DVDLowClearCoverInterrupt(0); + block->currTransferSize = sizeof(DVDDiskID); + DVDLowReadDiskID(block->addr, cbForStateBusy); + break; + + case 1: + case 4: + if (block->length) { + finished = executing; + executing = &DummyCommandBlock; + finished->state = 0; + + if (finished->callback) { + (finished->callback)(0, finished); + } + + stateReady(); + } + else { + DVDLowClearCoverInterrupt(0); + block->currTransferSize = MIN(block->length - block->transferredSize, 0x80000); + StampCommand(block->command, ((block->offset) + (block->transferredSize >> 2)), block->currTransferSize); + DVDLowRead((void*)((u8*)block->addr + block->transferredSize), block->currTransferSize, ((block->offset) + (block->transferredSize >> 2)), cbForStateBusy); + } + + break; + case 2: + DVDLowClearCoverInterrupt(0); + DVDLowSeek(block->offset, cbForStateBusy); + break; + case 3: + DVDLowStopMotor(FALSE, FALSE, cbForStateBusy); + break; + case 15: + DVDLowStopMotor(FALSE, FALSE, cbForStateBusy); + break; + case 13: + DVDLowClearCoverInterrupt(0); + DVDLowAudioBufferConfig(block->offset, block->length, cbForStateBusy); + break; + case 14: + DVDLowClearCoverInterrupt(0); + block->currTransferSize = sizeof(DVDDriveInfo); + DVDLowInquiry(block->addr, cbForStateBusy); + break; + case 16: + DVDLowClearCoverInterrupt(0); + DVDLowStopMotor(FALSE, FALSE, cbForStateBusy); + break; + case 32: + DVDLowSetSpinupFlag(1); + DVDLowReset(cbForStateBusy); + break; + case 33: + if (block->length == 0) { + finished = executing; + executing = &DummyCommandBlock; + finished->state = 0; + + if (finished->callback) { + (finished->callback)(0, finished); + } + + stateReady(); + } + else { + DVDLowClearCoverInterrupt(0); + block->currTransferSize = MIN(block->length - block->transferredSize, 0x80000); + StampCommand(block->command, ((block->offset) + (block->transferredSize >> 2)), block->currTransferSize); + DVDLowUnencryptedRead((void*)((u8*)block->addr + block->transferredSize), block->currTransferSize, ((block->offset) + (block->transferredSize >> 2)), cbForStateBusy); + } + break; + + case 34: + DVDLowClearCoverInterrupt(0); + DVDLowOpenPartition(block->offset, NULL, 0, 0, (ESTitleMeta*)block->addr, cbForStateBusy); + break; + case 35: + DVDLowClearCoverInterrupt(0); + DVDLowClosePartition(cbForStateBusy); + break; + case 38: + DVDLowPrepareCoverRegister(cbForStateBusy); + break; + case 36: + DVDLowPrepareCoverRegister(cbForStateBusy); + break; + case 37: + DVDLowClearCoverInterrupt(0); + DVDLowSetMaximumRotation(0x20000, cbForStateBusy); + break; + case 40: + DVDLowClearCoverInterrupt(0); + block->addr = &CurrDiskID; + block->currTransferSize = sizeof(DVDDiskID); + DVDLowReadDiskID(block->addr, cbForStateBusy); + break; + case 41: + { + DVDPartitionParams* params; + DVDLowClearCoverInterrupt(0); + params = block->addr; + + if (!params->numTmdBytes && !params->numCertBytes) { + DVDLowGetNoDiscBufferSizes(block->offset, ¶ms->numTmdBytes, ¶ms->numCertBytes, cbForStateBusy); + } + else { + DVDLowGetNoDiscOpenPartitionParams(block->offset, ¶ms->ticket, ¶ms->numTmdBytes, + ¶ms->tmd, ¶ms->numCertBytes, params->certificates, + ¶ms->dataWordOffset, params->h3Hash, cbForStateBusy); + } + break; + } + case 42: + { + DVDPartitionParams* params; + DVDLowClearCoverInterrupt(0); + params = block->addr; + DVDLowOpenPartitionWithTmdAndTicketView(block->offset, ¶ms->ticketView, params->numTmdBytes, ¶ms->tmd, + params->numCertBytes, params->certificates, cbForStateBusy); + break; + } + default: + checkOptionalCommand(block, cbForStateBusy); + break; + + } +} + +static BOOL issueCommand(s32 prio, DVDCommandBlock* block) { + BOOL level, result; + + if (autoInvalidation && USE_DMA(block->command)) { + DCInvalidateRange(block->addr, block->length); + } + + level = OSDisableInterrupts(); + block->state = 2; + result = __DVDPushWaitingQueue(prio, block); + + if ((executing == NULL) && (PauseFlag == FALSE)) { + stateReady(); + } + + OSRestoreInterrupts(level); + return result; +} + +BOOL DVDReadAbsAsyncPrio(DVDCommandBlock* block, void* addr, s32 length, u32 offset, DVDCBCallback callback, s32 prio) { + BOOL idle; + block->command = 1; + block->addr = addr; + block->length = (u32)length; + block->offset = (u32)offset; + block->transferredSize = 0; + block->callback = callback; + idle = issueCommand(prio, block); + return idle; +} + +BOOL DVDInquiryAsync(DVDCommandBlock* block, DVDDriveInfo* info, DVDCBCallback callback) { + BOOL idle; + block->command = 14; + block->addr = (void*)info; + block->length = sizeof(DVDDriveInfo); + block->transferredSize = 0; + block->callback = callback; + idle = issueCommand(2, block); + return idle; +} + +s32 DVDGetCommandBlockStatus(const DVDCommandBlock* block) { + BOOL enabled; + s32 retVal; + DVDCommandBlock* next; + + enabled = OSDisableInterrupts(); + + if (((volatile DVDCommandBlock*)block)->state == 3) { + retVal = 1; + } + else if (((volatile DVDCommandBlock*)block)->state == 5) { + retVal = 4; + } + else if (executing == &__DVDStopMotorCommandBlock) { + next = __DVDGetNextWaitingQueue(); + if (next) { + if(block == next) { + retVal = 1; + } + else { + retVal = ((volatile DVDCommandBlock*)block)->state; + } + } + else { + if (block == &__DVDStopMotorCommandBlock) { + retVal = 0; + } + else { + retVal = ((volatile DVDCommandBlock*)block)->state; + } + } + } + else { + retVal = ((volatile DVDCommandBlock*)block)->state; + } + + OSRestoreInterrupts(enabled); + + return retVal; +} + +s32 DVDGetDriveStatus(void) { + BOOL enabled; + s32 retVal; + + enabled = OSDisableInterrupts(); + + if (FatalErrorFlag) { + retVal = -1; + } + else if (PausingFlag) { + retVal = 8; + } + else { + if (executing == NULL) { + retVal = 0; + } + else if (executing == &DummyCommandBlock) { + retVal = 0; + } + else { + retVal = DVDGetCommandBlockStatus(executing); + } + } + + OSRestoreInterrupts(enabled); + + return retVal; +} + +BOOL DVDSetAutoInvalidation(BOOL autoInval) { + BOOL prev = autoInvalidation; + autoInvalidation = autoInval; + return prev; +} + +BOOL __DVDLowTestAlarm(const OSAlarm *); +static void stateReady(void); + +BOOL __DVDTestAlarm(const OSAlarm* alarm) { + if (alarm == &ResetAlarm) { + return TRUE; + } + + return __DVDLowTestAlarm(alarm); +} + +BOOL __DVDStopMotorAsync(DVDCommandBlock* block, DVDCBCallback callback) { + return TRUE; +} + +void __DVDRestartMotor(void) { + return; +} + +static BOOL __DVDLowBreak(void) { + Breaking = TRUE; + return TRUE; +} + +void DVDPause(void) { + BOOL level = OSDisableInterrupts(); + PauseFlag = TRUE; + + if (executing == NULL) { + PausingFlag = TRUE; + } + + OSRestoreInterrupts(level); +} + +void DVDResume(void) { + BOOL enabled = OSDisableInterrupts(); + PauseFlag = FALSE; + + if (PausingFlag) { + PausingFlag = FALSE; + stateReady(); + } + + OSRestoreInterrupts(enabled); +} + +BOOL DVDCancelAsync(DVDCommandBlock* block, DVDCBCallback callback) { + BOOL enabled; + DVDCommandBlock* finished; + + enabled = OSDisableInterrupts(); + + switch (block->state) { + case -1: + case 0: + case 10: + if (callback) { + (*callback)(0, block); + } + + break; + + case 1: + if (Canceling) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + Canceling = TRUE; + CancelCallback = callback; + + if (block->command == 4 || block->command == 33 || block->command == 34 || block->command == 41 || block->command == 42 || block->command == 1) { + __DVDLowBreak(); + } + + break; + + case 2: + __DVDDequeueWaitingQueue(block); + block->state = 10; + + if (block->callback) { + (block->callback)(-3, block); + } + + if (callback) { + (*callback)(0, block); + } + + break; + + case 3: + switch (block->command) { + case 5: + case 4: + case 13: + case 15: + case 33: + case 34: + case 37: + case 41: + case 42: + if (callback) { + (*callback)(0, block); + } + + break; + + case 1: + case 2: + if (__OSInIPL) { + finished = executing; + executing = &DummyCommandBlock; + block->state = 10; + + if (block->callback) { + (block->callback)(-3, block); + } + + if (callback) { + (*callback)(0, block); + } + + stateReady(); + break; + } + + default: + if (Canceling) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + Canceling = TRUE; + CancelCallback = callback; + break; + } + + break; + + case 4: + case 5: + case 6: + case 7: + case 11: + if (!(WaitingForCoverClose || WaitingForCoverOpen)) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + if (WaitingForCoverOpen) { + OSCancelAlarm(&CoverAlarm); + WaitingForCoverOpen = FALSE; + } + + if (block->state == 4) { + ResumeFromHere = 3; + } + + if (block->state == 5) { + ResumeFromHere = 4; + } + + if (block->state == 6) { + ResumeFromHere = 1; + } + + if (block->state == 11) { + ResumeFromHere = 2; + } + + if (block->state == 7) { + ResumeFromHere = 7; + } + + finished = executing; + executing = &DummyCommandBlock; + block->state = 10; + + if (block->callback) { + (block->callback)(-3, block); + } + + if (callback) { + (callback)(0, block); + } + + stateReady(); + break; + + case 12: + finished = executing; + executing = &DummyCommandBlock; + block->state = 10; + + if (block->callback) { + (block->callback)(-3, block); + } + + if (callback) { + (callback)(0, block); + } + + stateReady(); + break; + } + + OSRestoreInterrupts(enabled); + return TRUE; +} + +static void cbForCancelSync(s32, DVDCommandBlock *); + +s32 DVDCancel(DVDCommandBlock* block) { + BOOL result; + s32 state; + u32 command; + BOOL enabled; + + result = DVDCancelAsync(block, cbForCancelSync); + + if (result == FALSE) { + return -1; + } + + enabled = OSDisableInterrupts(); + + for (;;) { + state = ((volatile DVDCommandBlock*)block)->state; + + if ((state == 0) || (state == -1) || (state == 10)) { + break; + } + + if (state == 3) { + command = ((volatile DVDCommandBlock*)block)->command; + + if ((command == 4) || (command == 5) || (command == 13) || (command == 33) || (command == 34) || (command == 41) || + (command == 42) || (command == 15) || (command == 37)) { + break; + } + } + + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return 0; +} + +static void cbForCancelSync(s32 result, DVDCommandBlock* block) { + OSWakeupThread(&__DVDThreadQueue); +} + +BOOL DVDCancelAllAsync(DVDCBCallback callback) { + BOOL enabled, retVal; + DVDCommandBlock* p; + + enabled = OSDisableInterrupts(); + DVDPause(); + + while ((p = __DVDPopWaitingQueue()) != 0) { + DVDCancelAsync(p, NULL); + } + + if (executing) { + retVal = DVDCancelAsync(executing, callback); + } + else { + retVal = TRUE; + if (callback) { + (*callback)(0, NULL); + } + } + + DVDResume(); + OSRestoreInterrupts(enabled); + return retVal; +} + +DVDDiskID* DVDGetCurrentDiskID(void) { + return (DVDDiskID*)OSPhysicalToCached(0); +} + +static volatile u32 __BS2DVDLowIntType = 0; + +static void __BS2DVDLowCallback(u32 type) { + __BS2DVDLowIntType = type; +} + +u32 __DVDGetCoverStatus(void) { + u32 reg; + __BS2DVDLowIntType = 0; + DVDLowPrepareCoverRegister(__BS2DVDLowCallback); + + while (!__BS2DVDLowIntType) { + + } + + if (!(__BS2DVDLowIntType & 1)) { + return 0; + } + + reg = DVDLowGetCoverRegister(); + + if (__OSGetSystemTime() - LastResetEnd < DVD_RESETCOVER_TIMELAG_TICKS2) { + return 0; + } + else if (reg & 1) { + return 1; + } + else { + return 2; + } +} + +void __DVDResetWithNoSpinup(void) { + __BS2DVDLowIntType = 0; + DVDLowSetSpinupFlag(0); + DVDLowReset(__BS2DVDLowCallback); + + while (!__BS2DVDLowIntType) { + + } +} + +BOOL DVDCheckDiskAsync(DVDCommandBlock* block, DVDCBCallback callback) { + BOOL enabled; + s32 retVal, state; + + enabled = OSDisableInterrupts(); + + if (FatalErrorFlag) { + state = -1; + } + else if (PausingFlag) { + state = 8; + } + else { + if (WaitingForCoverOpen) { + state = 7; + } + if (WaitingForCoverClose) { + state = 5; + } + else if (executing == NULL) { + switch (ResumeFromHere) { + case 3: + { + state = 4; + break; + } + case 4: + { + state = 5; + break; + } + case 1: + { + state = 6; + break; + } + case 2: + { + state = 11; + break; + } + case 7: + { + state = 7; + break; + } + default: + { + state = 0; + break; + } + } + } + else if (executing == &DummyCommandBlock) { + state = 0; + } + else { + state = executing->state; + } + } + + retVal = TRUE; + switch (state) { + case 1: + case 9: + case 10: + case 2: + block->state = 0; + if (callback) { + (*callback)(TRUE, block); + } + OSRestoreInterrupts(enabled); + break; + + case -1: + case 11: + case 7: + case 3: + case 4: + case 5: + case 6: + case 12: + block->state = 0; + if (callback) { + (*callback)(FALSE, block); + } + OSRestoreInterrupts(enabled); + break; + + case 0: + case 8: + OSRestoreInterrupts(enabled); + + block->command = 36; + block->callback = callback; + + retVal = issueCommand(2, block); + break; + } + + return retVal; +} + +void __DVDPrepareResetAsync(DVDCBCallback callback) { + BOOL enabled = OSDisableInterrupts(); + + __DVDClearWaitingQueue(); + + if (Canceling) { + CancelCallback = callback; + } + else { + if (executing != NULL) { + executing->callback = NULL; + } + + DVDCancelAllAsync(callback); + } + + OSRestoreInterrupts(enabled); +} + +static volatile BOOL Prepared; + +static void Callback(s32 result, DVDCommandBlock* block ){ + Prepared = TRUE; +} + +void __DVDPrepareReset(void) { + OSDisableInterrupts(); + + Prepared = FALSE; + + __DVDPrepareResetAsync(Callback); + OSEnableInterrupts(); + + while (!(Prepared == TRUE)) { + + } +} diff --git a/src/RVL_SDK/dvd/dvdDeviceError.c b/src/RVL_SDK/dvd/dvdDeviceError.c new file mode 100644 index 000000000..d7c094cc4 --- /dev/null +++ b/src/RVL_SDK/dvd/dvdDeviceError.c @@ -0,0 +1,203 @@ +#include +#include +#include + +vu8 __OSDeviceCheckCode : (OS_BASE_CACHED + 0x319C); +extern u16 OSSetFontEncode(u16); +extern void __DVDShowFatalMessage(void); +static u8 CheckBuffer[32] __attribute__ ((aligned(32))); + +static volatile BOOL lowDone = TRUE; +static volatile u32 lowIntType = 0; + +static void lowCallback(u32 intType) { + lowIntType = intType; + lowDone = TRUE; +} + +void __DVDShowDeviceErrorMessage(void); + +BOOL __DVDCheckDevice(void) { + u32 checkCode = 0x460A0000; + u32 outOfRangeError = 0xFFFFFFFF; + u32 reportKeyError = 0xFFFFFFFF; + OSIOSRev iosRev; + + if (OSGetPhysicalMem2Size() == 0x08000000) { + return TRUE; + } + + __OSGetIOSRev(&iosRev); + + if (iosRev.major < 30 || iosRev.major >= 254) { + return TRUE; + } + + if (__OSDeviceCheckCode == 129) { + checkCode = 0x7ED40000; + } + + lowDone = FALSE; + DVDLowUnencryptedRead((void*)CheckBuffer, 32, checkCode, lowCallback);\ + + while (!lowDone) { + + } + + switch (lowIntType) { + case 2: + break; + case 1: + goto invalid; + break; + default: + goto fatal; + break; + } + + lowDone = FALSE; + DVDLowRequestError(lowCallback); + + while (!lowDone) { + + } + + outOfRangeError = DVDLowGetImmBufferReg(); + + switch (lowIntType) { + case 1: + { + if ((DVDLowGetImmBufferReg() & 0xFF000000) != 0) { + goto recover; + break; + } + + switch (DVDLowGetImmBufferReg() & 0xFFFFFF) { + case 0x52100: + break; + default: + goto invalid; + break; + } + + break; + } + + default: + goto fatal; + break; + } + + lowDone = FALSE; + DVDLowReportKey((DVDVideoReportKey*)CheckBuffer, 0x40000, 0, lowCallback); + + while (!lowDone) { + + } + + switch (lowIntType) { + case 2: + break; + case 1: + goto invalid; + break; + default: + goto fatal; + break; + } + + lowDone = FALSE; + DVDLowRequestError(lowCallback); + + while (!lowDone) { + + } + + reportKeyError = DVDLowGetImmBufferReg(); + switch (lowIntType) { + case 1: + if ((DVDLowGetImmBufferReg() & 0xFF000000) != 0) { + goto recover; + break; + } + + switch (DVDLowGetImmBufferReg() & 0xFFFFFF) { + case 0x53100: + case 0x52000: + break; + default: + goto invalid; + break; + } + + break; + + default: + goto fatal; + break; + } + +valid: + return TRUE; + +invalid: + __DVDShowDeviceErrorMessage(); + return FALSE; + +recover: + return FALSE; + +fatal: + __DVDShowFatalMessage(); + return FALSE; +} + +const char* const __DVDDeviceErrorMessage[] = { + "\n\n\nエラーコード001。\n" + "不明なデバイスが見つかりました。", + + "\n\n\nError #001,\n" + "unauthorized device has been detected.", + + "\n\n\nFehler #001:\n" + "Es wurde eine unzul舖sige Komponente\n" + "entdeckt.", + + "\n\n\nErreur 001:\n" + "un dispositif non autoris・a 騁・d騁ect・", + + "\n\n\nError 001:\n" + "Se ha detectado un dispositivo no\n" + "autorizado.", + + "\n\n\nErrore #001:\n" + "rilevato un dispositivo non autorizzato.", + + "\n\n\nFout #001:\n" + "ongeoorloofd onderdeel gevonden." +}; + +void __DVDShowDeviceErrorMessage(void) { + const char* message; + const char* const* messageList; + GXColor bg = { 0, 0, 0, 0 }; + GXColor fg = { 255, 255, 255, 0 }; + + if (SCGetLanguage() == 0) { + OSSetFontEncode(1); + } + else { + OSSetFontEncode(0); + } + + messageList = __DVDDeviceErrorMessage; + + if (SCGetLanguage() > 6) { + message = messageList[1]; + } + else { + message = messageList[SCGetLanguage()]; + } + + OSFatal(fg, bg, message); +} \ No newline at end of file diff --git a/src/RVL_SDK/dvd/dvdFatal.c b/src/RVL_SDK/dvd/dvdFatal.c new file mode 100644 index 000000000..35d844100 --- /dev/null +++ b/src/RVL_SDK/dvd/dvdFatal.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include + +extern u16 OSSetFontEncode(u16); + +static void (*FatalFunc)(void) = NULL; + +const char* const __DVDErrorMessageDefault[] = { + "\n\n\nエラーが発生しました。\n" + "\n" + "イジェクトボタンを押してディスクを取り出してか\n" + "ら、本体の電源をOFFにして、本体の取扱説明書の\n" + "指示に従ってください。", + + "\n\n\nAn error has occurred.\n" + "Press the Eject Button, remove the\n" + "Game Disc, and turn the power off.\n" + "Please read the Wii Operations Manual\n" + "for more information.", + + "\n\n\nEin Fehler ist aufgetreten.\n" + "Dr・ke den Ausgabeknopf, entnimm die\n" + "Disc und schalte die Wii-Konsole aus.\n" + "Bitte lies die Wii-Bedienungsanleitung,\n" + "um weitere Informationen zu erhalten.", + + "\n\n\nUne erreur est survenue.\n" + "Appuyez sur le bouton EJECT, retirez\n" + "le disque et 騁eignez la console.\n" + "Veuillez vous r馭駻er au mode d'emploi\n" + "Wii pour plus de d騁ails.", + + "\n\n\nSe ha producido un error.\n" + "Pulsa el Bot EJECT, extrae el disco y\n" + "apaga la consola. Consulta el manual de\n" + "instrucciones de la consola Wii para\n" + "obtener m疽 informaci.", + + "\n\n\nSi ・verificato un errore.\n" + "Premi il pulsante EJECT, estrai il disco\n" + "e spegni la console. Per maggiori\n" + "informazioni, consulta il manuale di\n" + "istruzioni della console Wii.", + + "\n\n\nEr is een fout opgetreden.\n" + "Druk op de EJECT-knop, verwijder de\n" + "disk en zet het Wii-systeem uit. Lees\n" + "de handleiding voor meer informatie." +}; + +const char* const __DVDErrorMessageEurope[] = { + "\n\n\nエラーが発生しました。\n" + "\n" + "イジェクトボタンを押してディスクを取り出してか\n" + "ら、本体の電源をOFFにして、本体の取扱説明書の\n" + "指示に従ってください。", + + "\n\n\nAn error has occurred.\n" + "Press the EJECT Button, remove the\n" + "Game Disc, and turn the power off.\n" + "Please read the Wii Operations Manual\n" + "for more information.", + + "\n\n\nEin Fehler ist aufgetreten.\n" + "Dr・ke den Ausgabeknopf, entnimm die\n" + "Disc und schalte die Wii-Konsole aus.\n" + "Bitte lies die Wii-Bedienungsanleitung,\n" + "um weitere Informationen zu erhalten.", + + "\n\n\nUne erreur est survenue.\n" + "Appuyez sur le bouton EJECT, retirez\n" + "le disque et 騁eignez la console.\n" + "Veuillez vous r馭駻er au mode d'emploi\n" + "Wii pour plus de d騁ails.", + + "\n\n\nSe ha producido un error.\n" + "Pulsa el Bot EJECT, extrae el disco y\n" + "apaga la consola. Consulta el manual de\n" + "instrucciones de la consola Wii para\n" + "obtener m疽 informaci.", + + "\n\n\nSi ・verificato un errore.\n" + "Premi il pulsante EJECT, estrai il disco\n" + "e spegni la console. Per maggiori\n" + "informazioni, consulta il manuale di\n" + "istruzioni della console Wii.", + + "\n\n\nEr is een fout opgetreden.\n" + "Druk op de EJECT-knop, verwijder de\n" + "disk en zet het Wii-systeem uit. Lees\n" + "de handleiding voor meer informatie." +}; + +const char* const __DVDErrorMessage104 [] = { + "\n" + "\n" + "エラーコード104。\n" + "エラーが発生しました。\n" + "\n" + "イジェクトボタンを押してディスクを取り出してか\n" + "ら、本体の電源をOFFにして、本体の取扱説明書の\n" + "指示に従ってください。", + + "\n" + "\n" + "Error #104,\n" + "An error has occurred.\n" + "Press the EJECT Button, remove the\n" + "Game Disc, and turn the power off.\n" + "Please read the Wii Operations Manual\n" + "for more information." +}; + +void __DVDShowFatalMessage(void) { + const char* message; + const char* const* messageList; + GXColor bg = { 0, 0, 0, 0 }; + GXColor fg = { 255, 255, 255, 0 }; + + if (SCGetLanguage() == 0) { + OSSetFontEncode(1); + } + else { + OSSetFontEncode(0); + } + + switch (SCGetProductGameRegion()) { + default: + messageList = __DVDErrorMessage104; + break; + case 2: + messageList = __DVDErrorMessageEurope; + break; + case 4: + case 5: + messageList = __DVDErrorMessageDefault; + break; + } + + if (SCGetLanguage() > 6) { + message = messageList[1]; + } + else { + message = messageList[SCGetLanguage()]; + } + + OSFatal(fg, bg, message); +} + +BOOL DVDSetAutoFatalMessaging(BOOL enable) { + BOOL enabled, prev; + enabled = OSDisableInterrupts(); + prev = FatalFunc ? TRUE : FALSE; + FatalFunc = enable ? __DVDShowFatalMessage : NULL; + OSRestoreInterrupts(enabled); + return prev; +} + +BOOL __DVDGetAutoFatalMessaging(void) { + return FatalFunc ? TRUE : FALSE; +} + +void __DVDPrintFatalMessage(void) { + if (FatalFunc) { + FatalFunc(); + } +} \ No newline at end of file diff --git a/src/RVL_SDK/dvd/dvd_broadway.c b/src/RVL_SDK/dvd/dvd_broadway.c new file mode 100644 index 000000000..470c7e1fb --- /dev/null +++ b/src/RVL_SDK/dvd/dvd_broadway.c @@ -0,0 +1,837 @@ +#include +#include +#include +#include +#include + +IOSFd DiFD = -1; + +static volatile bool requestInProgress = false; +static bool breakRequested; +static bool callbackInProgress; + +static u32 registerBuf[8] __attribute__((aligned(32))); +static u32 statusRegister[8] __attribute__((aligned(32))); +static s32 lastTicketError[8] __attribute__((aligned(32))); + +static u32 readLength; +static u32 spinUpValue; + +static diRegVals_t diRegValCache __attribute__((aligned(32))); + +static bool DVDLowInitCalled = false; + +typedef enum callbackType { + BOGUS_TYPE = 0, + TRANSACTION_CB, + COVER_CB, + COVER_REG_CB +} callbackType_t; + +static int freeCommandBuf = 0; +static diCommand_t* diCommand; +static char* pathBuf; + +typedef struct dvdContext { + DVDLowCallback callback; + callbackType_t callbackType; + bool inUse; + u32 contextMagic; + u32 contextNum; + u32 pad[3]; +} dvdContext_t; + +static int freeDvdContext = 0; +static bool dvdContextsInited = false; +static dvdContext_t dvdContexts[4] __attribute__((aligned(32))); +static IOSIoVector ioVec[10] __attribute__((aligned(32))); + +IOSError doTransactionCallback(IOSError ret, void* context) { + dvdContext_t* dvdContext = context; + + if (dvdContext->contextMagic != 0xFEEBDAED) { + OSReport("(doTransactionCallback) Error - context mangled!\n"); + dvdContext->contextMagic = 0xFEEBDAED; + goto out; + } + + requestInProgress = false; + + if (dvdContext->callback != NULL) { + int callbackArg; + callbackInProgress = TRUE; + callbackArg = ret; + + if (breakRequested == TRUE) { + breakRequested = false; + callbackArg |= 8; + } + + if (callbackArg & 1) { + readLength = 0; + } + + dvdContext->callback((u32)callbackArg); + callbackInProgress = false; + } + +out: + dvdContext->inUse = false; + return 0; +} + +IOSError doPrepareCoverRegisterCallback(IOSError ret, void* context) { + dvdContext_t* dvdContext; + requestInProgress = false; + + diRegValCache.CoverRegVal = registerBuf[0]; + dvdContext = (dvdContext_t*)context; + + if (dvdContext->contextMagic != 0xFEEBDAED) { + OSReport("(doTransactionCallback) Error - context mangled!\n"); + dvdContext->contextMagic = 0xFEEBDAED; + } + else { + if (dvdContext->callback != 0) { + callbackInProgress = true; + + if (breakRequested == true) { + breakRequested = false; + ret |= 8; + } + + dvdContext->callback(ret); + callbackInProgress = false; + } + } + + dvdContext->inUse = false; + return 0; +} + +static void* ddrAllocAligned32(const int size) { + void* low, *high; + + if ((size & 0x1F) != 0) { + return 0; + } + + low = IPCGetBufferLo(); + high = IPCGetBufferHi(); + + if (((u32)low & 0x1F) != 0) { + low = (void*)(((u32)low + 31) & 0x1F); + } + + if ((u32)low + size > (u32)high) { + OSReport("(ddrAllocAligned32) Not enough space to allocate %d bytes\n", size); + } + + IPCSetBufferLo((void*)((u32)low + size)); + return low; +} + +static bool allocateStructures(void) { + if ((diCommand = ddrAllocAligned32(sizeof(diCommand_t) * 4)) == 0) { + OSReport("Allocation of diCommand blocks failed\n"); + return false; + } + + if ((pathBuf = ddrAllocAligned32(32)) == 0) { + OSReport("Allocation of pathBuf failed\n"); + return false; + } + + return true; +} + +static void initDvdContexts(void) { + u32 i; + + for (i = 0; i < 4; i++) { + dvdContexts[i].callback = 0; + dvdContexts[i].callbackType = 0; + dvdContexts[i].inUse = false; + dvdContexts[i].contextMagic = 0xFEEBDAED; + dvdContexts[i].contextNum = i; + } + + freeDvdContext = 0; +} + +static inline dvdContext_t* newContext(const DVDLowCallback callback, const callbackType_t type) { + int returnIndex; + bool use = dvdContexts[freeDvdContext].inUse != 0; + + if (use == 1) { + OSReport("(newContext) ERROR: freeDvdContext.inUse (#%d) is true\n", freeDvdContext); + OSReport("(newContext) Now spinning in infinite loop\n"); + + while (1) { + + } + } + + if (dvdContexts[freeDvdContext].contextMagic != 0xFEEBDAED) { + OSReport("(newContext) Something overwrote the context magic - spinning \n"); + + while (1) { + + } + } + + dvdContexts[freeDvdContext].callback = callback; + dvdContexts[freeDvdContext].callbackType = type; + dvdContexts[freeDvdContext].inUse = true; + returnIndex = freeDvdContext; + freeDvdContext++; + + if (freeDvdContext >= 4) { + freeDvdContext = 0; + } + + return(dvdContexts + returnIndex); +} + +static inline void nextCommandBuf(int* bufNum) { + (*bufNum)++; + + if (*bufNum >= 4) { + *bufNum = 0; + } +} + +bool DVDLowFinalize(void) { + IOSError ret = IOS_Close(DiFD); + + if (ret != IOS_ERROR_OK) { + OSReport("(DVDLowFinish) Error: IOS_Close failed\n"); + return false; + } + + DVDLowInitCalled = false; + return true; +} + +bool DVDLowInit(void) { + IOSError retVal; + + if (DVDLowInitCalled == false) { + DVDLowInitCalled = true; + retVal = IPCCltInit(); + + if (retVal != IOS_ERROR_OK) { + OSReport("IPCCltInit returned error: %d\n", retVal); + return false; + } + + if (allocateStructures() == false) { + return false; + } + + if (dvdContextsInited == false) { + initDvdContexts(); + dvdContextsInited = true; + } + } + + strncpy(pathBuf, "/dev/di", 32); + DiFD = IOS_Open(pathBuf, 0); + + if (DiFD >= 0) { + return true; + } + else { + switch (DiFD) { + case IOS_ERROR_NOEXISTS: + OSReport("(DVDLowInit) Error: IOS_Open failed - pathname '/dev/di' does not exist\n"); + return false; + break; + case IOS_ERROR_ACCESS: + OSReport("(DVDLowInit) Error: IOS_Open failed - calling thread lacks permission\n"); + return false; + break; + case IOS_ERROR_MAX: + OSReport("(DVDLowInit) Error: IOS_Open failed - connection limit has been reached\n"); + return false; + break; + default: + OSReport("(DVDLowInit) IOS_Open failed, errorcode = %d\n", DiFD); + return false; + break; + } + } +} + +bool DVDLowReadDiskID(DVDDiskID* diskID, DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + requestInProgress = true; + dvdContext = newContext(callback, 1); + + if (diskID == 0) { + OSReport("@@@@@@ WARNING - Calling DVDLowReadDiskId with NULL ptr\n"); + } + + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0x70; + + rv = IOS_IoctlAsync(DiFD, 0x70, &diCommand[freeCommandBuf], sizeof(diCommand_t), diskID, sizeof(DVDDiskID), doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowReadDiskID) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowOpenPartition(const u32 partitionWordOffset, const ESTicket* const eTicket, const u32 numCertBytes, const u8* const certificates, ESTitleMeta* tmd, DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + if (eTicket != 0 && !((u32)eTicket & 0x1F)) { + OSReport("(DVDLowOpenPartition) eTicket memory is unaligned\n"); + return false; + } + + if (certificates != 0 && !((u32)certificates & 0x1F)) { + OSReport("(DVDLowOpenPartition) certificates memory is unaligned\n"); + return false; + } + + if (tmd != 0 && !((u32)tmd & 0x1F)) { + OSReport("(DVDLowOpenPartition) certificates memory is unaligned\n"); + return false; + } + + requestInProgress = true; + dvdContext = newContext(callback, 1); + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0x8B; + diCommand[freeCommandBuf].arg[0] = partitionWordOffset; + ioVec[0].base = (u8*)&diCommand[freeCommandBuf]; + ioVec[0].length = sizeof(diCommand_t); + + ioVec[1].base = (u8*)eTicket; + if (eTicket == 0) { + ioVec[1].length = 0; + } + else { + ioVec[1].length = sizeof(ESTicket); + } + + ioVec[2].base = (u8*)certificates; + if (certificates == 0) { + ioVec[2].length = 0; + } + else { + ioVec[2].length = numCertBytes; + } + + ioVec[3].base = (u8*)tmd; + ioVec[3].length = sizeof(ESTitleMeta); + + ioVec[4].base = (u8*)&lastTicketError[0]; + ioVec[4].length = sizeof(lastTicketError); + + rv = IOS_IoctlvAsync(DiFD, 0x8B, 3, 2, ioVec, doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowOpenPartition) IOS_IoctlvAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowOpenPartitionWithTmdAndTicketView(const u32 partitionWordOffset, const ESTicketView* const eTicketView, const u32 numTmdBytes, const ESTitleMeta* const tmd, const u32 numCertBytes, const u8* const certificates, DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + if (certificates != 0 && !((u32)certificates & 0x1F)) { + return false; + } + + if (tmd == 0) { + OSReport("(%s) tmd parameter cannot be NULL\n", __FUNCTION__); + return false; + } + else if (!((u32)tmd & 0x1F)) { + OSReport("(%s) tmd memory is unaligned\n", __FUNCTION__); + return false; + } + + if (eTicketView == 0) { + OSReport("(%s) eTicketView parameter cannot be NULL\n", __FUNCTION__); + return false; + } + else if (!((u32)eTicketView & 0x1F)) { + OSReport("(%s) eTicketView memory is unaligned\n", __FUNCTION__); + return false; + } + + requestInProgress = true; + dvdContext = newContext(callback, 1); + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0x94; + diCommand[freeCommandBuf].arg[0] = partitionWordOffset; + ioVec[0].base = (u8*)&diCommand[freeCommandBuf]; + ioVec[0].length = sizeof(diCommand_t); + + ioVec[1].base = (u8*)eTicketView; + ioVec[1].length = sizeof(ESTicketView); + + ioVec[2].base = (u8*)tmd; + ioVec[2].length = numTmdBytes; + + ioVec[3].base = (u8*)certificates; + if (certificates == 0) { + ioVec[3].length = 0; + } + else { + ioVec[3].length = numCertBytes; + } + + ioVec[4].base = (u8*)&lastTicketError[0]; + ioVec[4].length = sizeof(lastTicketError); + + rv = IOS_IoctlvAsync(DiFD, 0x94, 4, 1, ioVec, doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowOpenPartition) IOS_IoctlvAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowGetNoDiscBufferSizes(const u32 partitionWordOffset, u32* numTmdBytes, u32* numCertBytes, DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + if (numTmdBytes == 0 || numCertBytes == 0) { + OSReport("(%s) Error: NULL pointer argument\n", __FUNCTION__); + return false; + } + + if (!((u32)numTmdBytes & 0x1F)) { + OSReport("(%s) numTmdBytes memory is unaligned\n", __FUNCTION__); + return false; + } + + if (!((u32)numCertBytes & 0x1F)) { + OSReport("(%s) certificates memory is unaligned\n", __FUNCTION__); + return false; + } + + requestInProgress = true; + dvdContext = newContext(callback, 1); + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0x92; + diCommand[freeCommandBuf].arg[0] = partitionWordOffset; + + ioVec[0].base = (u8*)&diCommand[freeCommandBuf]; + ioVec[0].length = sizeof(diCommand_t); + + ioVec[1].base = (u8*)numTmdBytes; + ioVec[1].length = 4; + + ioVec[2].base = (u8*)numCertBytes; + ioVec[2].length = 4; + + rv = IOS_IoctlvAsync(DiFD, 0x92, 1, 2, ioVec, doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (%s) IOS_IoctlvAsync returned error: %d\n", __FUNCTION__, rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +#define is_aligned(addr) (((u32)(addr) & 0x1F) == 0) + +bool DVDLowGetNoDiscOpenPartitionParams(const u32 partitionWordOffset, ESTicket* eTicket, u32* numTmdBytes, ESTitleMeta* tmd, u32* numCertBytes, u8* certificates, u32* dataWordOffset, u8* h3HashPtr, DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + if (eTicket == 0 || numTmdBytes == 0 || tmd == 0 || numCertBytes == 0 || certificates == 0 || dataWordOffset == 0 || h3HashPtr == 0) { + OSReport("(%s) Error: NULL pointer argument\n", __FUNCTION__); + return false; + } + + if (!is_aligned(eTicket) || !is_aligned(numTmdBytes) || !is_aligned(tmd) || !is_aligned(numCertBytes) || !is_aligned(certificates) || !is_aligned(dataWordOffset) || !is_aligned(h3HashPtr)) { + OSReport("(%s) pointer argument is unaligned\n", __FUNCTION__); + return false; + } + + requestInProgress = true; + dvdContext = newContext(callback, 1); + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0x90; + diCommand[freeCommandBuf].arg[0] = partitionWordOffset; + + ioVec[0].base = (u8*)&diCommand[freeCommandBuf]; + ioVec[0].length = sizeof(diCommand_t); + + ioVec[1].base = (u8*)numTmdBytes; + ioVec[1].length = 4; + + ioVec[2].base = (u8*)numCertBytes; + ioVec[2].length = 4; + + ioVec[3].base = (u8*)eTicket; + ioVec[3].length = sizeof(ESTicket); + + ioVec[4].base = (u8 *) numTmdBytes; + ioVec[4].length = 4; + + ioVec[5].base = (u8*)tmd; + ioVec[5].length = *numTmdBytes; + + ioVec[6].base = (u8*)numCertBytes; + ioVec[6].length = 4; + + ioVec[7].base = certificates; + ioVec[7].length = *numCertBytes; + + ioVec[8].base = (u8*)dataWordOffset; + ioVec[8].length = 4; + + ioVec[9].base = h3HashPtr; + ioVec[9].length = 98304; + + rv = IOS_IoctlvAsync(DiFD, 0x90, 3, 7, ioVec, doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (%s) IOS_IoctlvAsync returned error: %d\n", __FUNCTION__, rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowClosePartition(DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0x8C; + + requestInProgress = true; + dvdContext = newContext(callback, 1); + rv = IOS_IoctlAsync(DiFD, 0x8C, &diCommand[freeCommandBuf], sizeof(diCommand_t), 0, 0, doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowClosePartition) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowUnencryptedRead(void* destAddr, u32 length, u32 wordOffset, DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + requestInProgress = true; + dvdContext = newContext(callback, 1); + readLength = length; + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0x8D; + diCommand[freeCommandBuf].arg[0] = length; + diCommand[freeCommandBuf].arg[1] = wordOffset; + + rv = IOS_IoctlAsync(DiFD, 0x8D, &diCommand[freeCommandBuf], sizeof(diCommand_t), destAddr, length, doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowUnencryptedRead) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowStopMotor(bool eject, bool saving, DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + requestInProgress = true; + dvdContext = newContext(callback, 1); + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0xE3; + diCommand[freeCommandBuf].arg[0] = eject; + diCommand[freeCommandBuf].arg[1] = saving; + + rv = IOS_IoctlAsync(DiFD, 0xE3, &diCommand[freeCommandBuf], sizeof(diCommand_t), &diRegValCache, sizeof(diRegVals_t), doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowStopMotor) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowInquiry(DVDDriveInfo* info, DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + requestInProgress = true; + dvdContext = newContext(callback, 1); + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0x12; + rv = IOS_IoctlAsync(DiFD, 0x12, &diCommand[freeCommandBuf], sizeof(diCommand_t), info, sizeof(DVDDriveInfo), doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowInquiry) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowRequestError(DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + requestInProgress = true; + dvdContext = newContext(callback, 1); + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0xE0; + rv = IOS_IoctlAsync(DiFD, 0xE0, &diCommand[freeCommandBuf], sizeof(diCommand_t), &diRegValCache, sizeof(diRegVals_t), doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowInquiry) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowSetSpinupFlag(u32 spinUp) { + spinUpValue = spinUp; + return true; +} + +bool DVDLowReset(DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + requestInProgress = true; + dvdContext = newContext(callback, 1); + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0x8A; + diCommand[freeCommandBuf].arg[0] = spinUpValue; + rv = IOS_IoctlAsync(DiFD, 0x8A, &diCommand[freeCommandBuf], sizeof(diCommand_t), 0, 0, doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowInquiry) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowAudioBufferConfig(bool enable, u32 size, DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + requestInProgress = true; + dvdContext = newContext(callback, 1); + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0xE4; + diCommand[freeCommandBuf].arg[0] = enable; + diCommand[freeCommandBuf].arg[1] = size; + rv = IOS_IoctlAsync(DiFD, 0xE4, &diCommand[freeCommandBuf], sizeof(diCommand_t), &diRegValCache, sizeof(diRegVals_t), doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowAudioBufferConfig) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowReportKey(DVDVideoReportKey* reportKey, u32 format, u32 lsn, DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + requestInProgress = true; + dvdContext = newContext(callback, 1); + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0xA4; + diCommand[freeCommandBuf].arg[0] = format >> 16; + diCommand[freeCommandBuf].arg[1] = lsn; + + rv = IOS_IoctlAsync(DiFD, 0xA4, &diCommand[freeCommandBuf], sizeof(diCommand_t), reportKey, sizeof(DVDVideoReportKey), doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowReportKey) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowSetMaximumRotation(u32 subcmd, DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + requestInProgress = true; + dvdContext = newContext(callback, 1); + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0xDD; + diCommand[freeCommandBuf].arg[0] = (subcmd >> 16) & 3; + rv = IOS_IoctlAsync(DiFD, 0xDD, &diCommand[freeCommandBuf], sizeof(diCommand_t), 0, 0, doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowSetMaximumRotation) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowRead(void* destAddr, u32 length, u32 wordOffset, DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + if (((u32)destAddr & 0x1F) != 0) { + OSReport("(DVDLowRead): ERROR - destAddr buffer is not 32 byte aligned\n"); + return false; + } + + requestInProgress = true; + dvdContext = newContext(callback, 1); + readLength = length; + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0x71; + diCommand[freeCommandBuf].arg[0] = length; + diCommand[freeCommandBuf].arg[1] = wordOffset; + rv = IOS_IoctlAsync(DiFD, 0x71, &diCommand[freeCommandBuf], sizeof(diCommand_t), destAddr, length, doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowRead) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowSeek(u32 wordOffset, DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + requestInProgress = true; + dvdContext = newContext(callback, 1); + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0xAB; + diCommand[freeCommandBuf].arg[0] = wordOffset; + rv = IOS_IoctlAsync(DiFD, 0xAB, &diCommand[freeCommandBuf], sizeof(diCommand_t), 0, 0, doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowSeek) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +u32 DVDLowGetCoverRegister(void) { + return diRegValCache.CoverRegVal; +} + +u32 DVDLowGetStatusRegister(void) { + return statusRegister[0]; +} + +bool DVDLowPrepareCoverRegister(DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0x7A; + requestInProgress = true; + dvdContext = newContext(callback, 1); + rv = IOS_IoctlAsync(DiFD, 0x7A, &diCommand[freeCommandBuf], sizeof(diCommand_t), registerBuf, sizeof(registerBuf), doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowPrepareCoverRegister) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +bool DVDLowPrepareStatusRegister(DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0x95; + requestInProgress = true; + dvdContext = newContext(callback, 1); + rv = IOS_IoctlAsync(DiFD, 0x95, &diCommand[freeCommandBuf], sizeof(diCommand_t), statusRegister, sizeof(statusRegister), doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowPrepareStatusRegister) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +u32 DVDLowGetImmBufferReg(void) { + return diRegValCache.ImmRegVal; +} + +bool DVDLowUnmaskStatusInterrupts(void) { + return true; +} + +bool DVDLowMaskCoverInterrupt(void) { + return true; +} + +bool DVDLowClearCoverInterrupt(DVDLowCallback callback) { + dvdContext_t* dvdContext; + IOSError rv; + + nextCommandBuf(&freeCommandBuf); + diCommand[freeCommandBuf].theCommand = 0x86; + requestInProgress = true; + dvdContext = newContext(callback, 1); + rv = IOS_IoctlAsync(DiFD, 0x86, &diCommand[freeCommandBuf], sizeof(diCommand_t), 0, 0, doTransactionCallback, dvdContext); + + if (rv != IOS_ERROR_OK) { + OSReport("@@@ (DVDLowClearCoverInterrupt) IOS_IoctlAsync returned error: %d\n", rv); + dvdContext->inUse = false; + return false; + } + + return true; +} + +BOOL __DVDLowTestAlarm(const OSAlarm *) { + return FALSE; +} \ No newline at end of file diff --git a/src/RVL_SDK/dvd/dvderror.c b/src/RVL_SDK/dvd/dvderror.c new file mode 100644 index 000000000..78d2c72e2 --- /dev/null +++ b/src/RVL_SDK/dvd/dvderror.c @@ -0,0 +1,190 @@ +#include +#include + +static BOOL ExistFlag = FALSE; +static NANDCommandBlock NandCb; +static NANDFileInfo NandInfo; +static DVDCBCallback Callback; +static u32 NextOffset; +DVDErrorInfo __ErrorInfo __attribute__ ((aligned(32))); +DVDErrorInfo __FirstErrorInfo __attribute__ ((aligned(32))); + +void cbForNandClose(s32 result, NANDCommandBlock* block) { + if (Callback) { + Callback((result == 0) ? 1 : 2, NULL); + } +} + +void cbForNandWrite(s32 result, NANDCommandBlock* block) { + if (NANDCloseAsync(&NandInfo, cbForNandClose, &NandCb) != 0) { + if (Callback) { + Callback(2, NULL); + } + } +} + +void cbForNandSeek(s32 result, NANDCommandBlock* block) { + if (result == sizeof(DVDErrorInfo) * (1 + NextOffset)) { + DCFlushRange((void*)&__ErrorInfo, sizeof(__ErrorInfo)); + + if (NANDWriteAsync(&NandInfo, (void*)&__ErrorInfo, sizeof(__ErrorInfo), cbForNandWrite, &NandCb) != 0) { + cbForNandWrite(-1, NULL); + } + } + else { + if (Callback) { + Callback(2, NULL); + } + } +} + +void cbForNandWrite0(s32 result, NANDCommandBlock* block) { + if (result == sizeof(__FirstErrorInfo)) { + if (NANDSeekAsync(&NandInfo, (s32)(sizeof(DVDErrorInfo) * (1 + NextOffset)), 0, cbForNandSeek, &NandCb) != 0) { + cbForNandSeek(-1, NULL); + } + } + else { + if (Callback) { + Callback(2, NULL); + } + } +} + +void cbForNandSeek2(s32 result, NANDCommandBlock* block) { + if (result == sizeof(DVDErrorInfo)) { + __FirstErrorInfo.nextOffset = (__FirstErrorInfo.nextOffset + 1) % 7; + + if (NANDWriteAsync(&NandInfo, (void*)&__FirstErrorInfo, sizeof(__FirstErrorInfo), cbForNandWrite0, &NandCb) != 0) { + cbForNandWrite0(-1, NULL); + } + } + else { + if (Callback) { + Callback(2, NULL); + } + } +} + +void cbForNandRead(s32 result, NANDCommandBlock* block) { + if (result == sizeof(DVDErrorInfo)) { + NextOffset = __FirstErrorInfo.nextOffset; + + if (NANDSeekAsync(&NandInfo, sizeof(DVDErrorInfo), 0, cbForNandSeek2, &NandCb) != 0) { + cbForNandSeek2(-1, NULL); + } + } + else { + __ErrorInfo.nextOffset = 1; + if (NANDWriteAsync(&NandInfo, (void*)&__ErrorInfo, sizeof(__ErrorInfo), cbForNandWrite, &NandCb) != 0) { + cbForNandWrite(-1, NULL); + } + } +} + +void cbForNandSeek0(s32 result, NANDCommandBlock* block) { + if (result == 0) { + NextOffset = 0; + __ErrorInfo.nextOffset = 1; + + if (NANDWriteAsync(&NandInfo, (void*)&__FirstErrorInfo, sizeof(__FirstErrorInfo), cbForNandWrite0, &NandCb) != 0) { + cbForNandWrite0(-1, NULL); + } + } + else { + if (Callback) { + Callback(2, NULL); + } + } +} + +void cbForNandSeek1(s32 result, NANDCommandBlock* block) { + if (result == sizeof(DVDErrorInfo)) { + if (NANDReadAsync(&NandInfo, (void*)&__FirstErrorInfo, sizeof(__FirstErrorInfo), cbForNandRead, &NandCb) != 0) { + cbForNandRead(-1, NULL); + } + } + else { + if (NANDSeekAsync(&NandInfo, 0, 0, cbForNandSeek0, &NandCb) != 0) { + cbForNandSeek0(-1, NULL); + } + } +} + +void cbForNandOpen(s32 result, NANDCommandBlock* block) { + if (result == 0) { + if (ExistFlag) { + if (NANDSeekAsync(&NandInfo, sizeof(DVDErrorInfo), 0, cbForNandSeek1, &NandCb) != 0) { + cbForNandSeek1(-1, NULL); + } + } + else { + NextOffset = 0; + __ErrorInfo.nextOffset = 1; + if (NANDWriteAsync(&NandInfo, (void*)&__FirstErrorInfo, sizeof(__FirstErrorInfo), cbForNandWrite0, &NandCb) != 0) { + cbForNandWrite0(-1, NULL); + } + } + } + else { + if (Callback) { + Callback(2, NULL); + } + } +} + +void cbForNandCreate(s32 result, NANDCommandBlock* block) { + if (result == 0 || result == -6) { + if (result == -6) { + ExistFlag = TRUE; + } + + if (NANDPrivateOpenAsync("/shared2/test2/dvderror.dat", &NandInfo, 3, cbForNandOpen, &NandCb) != 0) { + if (Callback) { + Callback(2, NULL); + } + } + } + else { + if (Callback) { + Callback(2, NULL); + } + } +} + +void cbForNandCreateDir(s32 result, NANDCommandBlock* block) { + if (result == 0 || result == -6) { + if (NANDPrivateCreateAsync("/shared2/test2/dvderror.dat", 0x3F, 0, cbForNandCreate, &NandCb) != 0) { + if (Callback) { + Callback(2, NULL); + } + } + } + else { + if (Callback) { + Callback(2, NULL); + } + } +} + +void cbForPrepareStatusRegister(u32 intType) { + if (intType == 1) { + __ErrorInfo.status = DVDLowGetStatusRegister(); + } + else { + __ErrorInfo.status = 0xFFFFFFFF; + } + + if (NANDPrivateCreateDirAsync("/shared2/test2", 0x3F, 0, cbForNandCreateDir, &NandCb) != 0) { + if (Callback) { + Callback(2, NULL); + } + } +} + +void __DVDStoreErrorCode(u32 error, DVDCBCallback callback) { + __ErrorInfo.error = error; + __ErrorInfo.dateTime = (u32)OSTicksToSeconds(OSGetTime()); + Callback = callback; + DVDLowPrepareStatusRegister(cbForPrepareStatusRegister); +} \ No newline at end of file diff --git a/src/RVL_SDK/dvd/dvdfs.c b/src/RVL_SDK/dvd/dvdfs.c new file mode 100644 index 000000000..4e0478f6d --- /dev/null +++ b/src/RVL_SDK/dvd/dvdfs.c @@ -0,0 +1,373 @@ +#include +#include +#include +#include +#include + +extern u32 __DVDLayoutFormat; + +typedef struct FSTEntry FSTEntry; + +struct FSTEntry { + u32 isDirAndStringOff; + u32 parentOrPosition; + u32 nextEntryOrLength; +}; + +static OSBootInfo* BootInfo; +static FSTEntry* FstStart; +static char* FstStringStart; +static u32 MaxEntryNum; +static u32 currentDirectory = 0; + +OSThreadQueue __DVDThreadQueue; +u32 __DVDLongFileNameFlag = 1; +#define entryIsDir(i) (((FstStart[i].isDirAndStringOff & 0xFF000000) == 0) ? FALSE : TRUE) +#define stringOff(i) (FstStart[i].isDirAndStringOff & 0x00FFFFFF) +#define parentDir(i) (FstStart[i].parentOrPosition) +#define nextDir(i) (FstStart[i].nextEntryOrLength) +#define filePosition(i) (FstStart[i].parentOrPosition) +#define fileLength(i) (FstStart[i].nextEntryOrLength) +#define offsetof(type, memb) ((u32)&((type *)0)->memb) + +/* this is here because it won't be inlined otherwise */ +inline int tolower(int c) { + return ((c < 0) || (c >= 0x100)) ? c : (int) (_current_locale.ctype_cmpt_ptr->lower_map_ptr[c]); +} + +void __DVDFSInit(void) { + BootInfo = (OSBootInfo*)OSPhysicalToCached(0); + FstStart = (FSTEntry*)BootInfo->FSTLocation; + + if (FstStart != NULL) { + MaxEntryNum = FstStart[0].nextEntryOrLength; + FstStringStart = (char*)&FstStart[MaxEntryNum]; + } +} + +static BOOL isSame(const char* path, const char* str) { + while (*str != '\0') { + if (tolower(*path++) != tolower(*str++)) { + return FALSE; + } + } + + if ((*path == '/') || (*path == '\0')) { + return TRUE; + } + + return FALSE; +} + +s32 DVDConvertPathToEntrynum(const char* pathPtr) { + const char* ptr; + char* stringPtr; + BOOL isDir; + u32 length, dirLookAt, i; + const char* origPathPtr = pathPtr, *extentionStart; + BOOL illegal, 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__, 0x1BB, "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) >> __DVDLayoutFormat; + fileInfo->length = fileLength(entrynum); + fileInfo->callback = (DVDCallback)NULL; + fileInfo->cb.state = 0; + return TRUE; +} + +BOOL DVDOpen(const 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) >> __DVDLayoutFormat; + fileInfo->length = fileLength(entry); + fileInfo->callback = (DVDCallback)NULL; + fileInfo->cb.state = 0; + 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); +} + +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 = 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); +} + +static void cbForReadAsync(s32 result, DVDCommandBlock* block); + +BOOL DVDReadAsyncPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, DVDCallback callback, s32 prio) { + if (!((0 <= offset) && (offset <= fileInfo->length))) { + OSPanic(__FILE__, 0x337, "DVDReadAsync(): specified area is out of the file "); + } + + if (!((0 <= offset + length) && (offset + length < fileInfo->length + 32))) { + OSPanic(__FILE__, 0x33D, "DVDReadAsync(): specified area is out of the file "); + } + + fileInfo->callback = callback; + DVDReadAbsAsyncPrio(&fileInfo->cb, addr, length, (u32)(fileInfo->startAddr + (offset >> 2)), cbForReadAsync, prio); + return TRUE; +} + +static void cbForReadAsync(s32 result, DVDCommandBlock* block) { + DVDFileInfo* fileInfo = (DVDFileInfo*)((char*)block - offsetof(DVDFileInfo, cb)); + + if (fileInfo->callback) { + (fileInfo->callback)(result, fileInfo); + } +} + +static void cbForReadSync(s32 result, DVDCommandBlock* block); + +s32 DVDReadPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, s32 prio) { + BOOL result, enabled; + DVDCommandBlock* block; + s32 state, retVal; + + if (!((0 <= offset) && (offset <= fileInfo->length))) { + OSPanic(__FILE__, 0x37D, "DVDRead(): specified area is out of the file "); + } + + if (!((0 <= offset + length) && (offset + length < fileInfo->length + 32))) { + OSPanic(__FILE__, 0x383, "DVDRead(): specified area is out of the file "); + } + + block = &fileInfo->cb; + result = DVDReadAbsAsyncPrio(block, addr, length, (u32)(fileInfo->startAddr + (offset >> 2)), cbForReadSync, prio); + + if (result == FALSE) { + return -1; + } + + enabled = OSDisableInterrupts(); + + for (;;) { + state = ((DVDCommandBlock*)block)->state; + + if (state == 0) { + retVal = (s32)block->transferredSize; + break; + } + + if (state == -1) { + retVal = -1; + break; + } + + if (state == 10) { + retVal = -3; + break; + } + + OSSleepThread(&__DVDThreadQueue); + } + + OSRestoreInterrupts(enabled); + return retVal; +} + +static void cbForReadSync(s32 result, DVDCommandBlock* block) { + OSWakeupThread(&__DVDThreadQueue); +} + +BOOL DVDOpenDir(const char* dirName, DVDDir* dir) { + s32 entry; + char currentDir[128]; + + entry = DVDConvertPathToEntrynum(dirName); + + if (entry < 0) { + DVDGetCurrentDir(currentDir, 128); + OSReport("Warning: DVDOpenDir(): file '%s' was not found under %s.\n", dirName, currentDir); + return FALSE; + } + + if (!entryIsDir(entry)) { + return FALSE; + } + + dir->entryNum = entry; + dir->location = entry + 1; + dir->next = nextDir(entry); + return TRUE; +} + +BOOL DVDReadDir(DVDDir* dir, DVDDirEntry* dirent) { + u32 loc = dir->location; + + if ((loc <= dir->entryNum) || (dir->next <= loc)) { + return FALSE; + } + + dirent->entryNum = loc; + dirent->isDir = entryIsDir(loc); + dirent->name = FstStringStart + stringOff(loc); + dir->location = entryIsDir(loc) ? nextDir(loc) : (loc + 1); + return TRUE; +} + +BOOL DVDCloseDir(DVDDir* dir) { + return TRUE; +} \ No newline at end of file diff --git a/src/RVL_SDK/dvd/dvdidutils.c b/src/RVL_SDK/dvd/dvdidutils.c new file mode 100644 index 000000000..c1d1f3a5c --- /dev/null +++ b/src/RVL_SDK/dvd/dvdidutils.c @@ -0,0 +1,27 @@ +#include +#include +#include + +BOOL DVDCompareDiskID(const DVDDiskID* id1, const DVDDiskID* id2) { + if (id1->gameName[0] && id2->gameName[0] && + strncmp(&id1->gameName[0], &id2->gameName[0], 4)) { + return FALSE; + } + + if (!id1->company[0] || !id2->company[0] || + strncmp(&id1->company[0], &id2->company[0], 2)) { + return FALSE; + } + + if (id1->diskNumber != 0xFF && id2->diskNumber != 0xFF && + id1->diskNumber != id2->diskNumber) { + return FALSE; + } + + if (id1->gameVersion != 0xFF && id2->gameVersion != 0xFF && + id1->gameVersion != id2->gameVersion) { + return FALSE; + } + + return TRUE; +} \ No newline at end of file diff --git a/src/RVL_SDK/dvd/dvdqueue.c b/src/RVL_SDK/dvd/dvdqueue.c new file mode 100644 index 000000000..096309e6a --- /dev/null +++ b/src/RVL_SDK/dvd/dvdqueue.c @@ -0,0 +1,134 @@ +#include +#include + +typedef struct { + DVDCommandBlock* next; + DVDCommandBlock* prev; +} Queue; + +static Queue WaitingQueue[4]; + +void __DVDClearWaitingQueue(void) { + u32 i; + + for (i = 0; i < 4; i++) { + DVDCommandBlock* 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, *q; + BOOL enabled; + + enabled = OSDisableInterrupts(); + q = (DVDCommandBlock*)&(WaitingQueue[prio]); + + tmp = q->next; + q->next = tmp->next; + tmp->next->prev = q; + + OSRestoreInterrupts(enabled); + + tmp->next = NULL; + tmp->prev = NULL; + return tmp; +} + +DVDCommandBlock* __DVDPopWaitingQueue(void) { + u32 i; + BOOL enabled; + DVDCommandBlock* q; + + enabled = OSDisableInterrupts(); + + for (i = 0; i < 4; i++) { + q = (DVDCommandBlock*)&(WaitingQueue[i]); + + if (q->next != q) { + OSRestoreInterrupts(enabled); + return PopWaitingQueuePrio(i); + } + } + + OSRestoreInterrupts(enabled); + return NULL; +} + +BOOL __DVDCheckWaitingQueue(void) { + u32 i; + BOOL enabled; + DVDCommandBlock* q; + + enabled = OSDisableInterrupts(); + + for (i = 0; i < 4; i++) { + q = (DVDCommandBlock*)&(WaitingQueue[i]); + + if (q->next != q) { + OSRestoreInterrupts(enabled); + return TRUE; + } + } + + OSRestoreInterrupts(enabled); + return FALSE; +} + +DVDCommandBlock* __DVDGetNextWaitingQueue(void) { + u32 i; + BOOL enabled; + DVDCommandBlock* q, *tmp; + + enabled = OSDisableInterrupts(); + + for (i = 0; i < 4; i++) { + q = (DVDCommandBlock*)&(WaitingQueue[i]); + + if (q->next != q) { + tmp = q->next; + OSRestoreInterrupts(enabled); + return tmp; + } + } + + OSRestoreInterrupts(enabled); + return NULL; +} + +BOOL __DVDDequeueWaitingQueue(DVDCommandBlock* block) { + BOOL enabled; + DVDCommandBlock* prev, *next; + + enabled = OSDisableInterrupts(); + + prev = block->prev; + next = block->next; + + if (prev == NULL || next == NULL) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + prev->next = next; + next->prev = prev; + OSRestoreInterrupts(enabled); + return TRUE; +} \ No newline at end of file diff --git a/src/RVL_SDK/esp/esp.c b/src/RVL_SDK/esp/esp.c new file mode 100644 index 000000000..fdab21fff --- /dev/null +++ b/src/RVL_SDK/esp/esp.c @@ -0,0 +1,323 @@ +#include +#include +#include + +static s32 __esFd = -1; + +s32 ESP_InitLib(void) { + s32 ret = 0; + + if (__esFd < 0) { + __esFd = IOS_Open("/dev/es", 0); + + if (__esFd < 0) { + ret = __esFd; + } + } + + return ret; +} + +s32 ESP_CloseLib(void) { + s32 ret = 0; + + if (__esFd >= 0) { + ret = IOS_Close(__esFd); + if (ret == 0) { + __esFd = -1; + } + } + + return ret; +} + +s32 ESP_LaunchTitle(u64 titleID, ESTicketView *pTicketView) { + s32 ret = 0; + // buffer being aligned is required for codegen + u8 buf[256] __attribute__ ((aligned(32))); + IOSIoVector* vec = (IOSIoVector *)(buf + 208); + u64* id = (u64*)buf; + + if (__esFd < 0) { + return -0x3F9; + } + + // check if ptr is aligned to 0x20 + if ((u32)pTicketView & 31) { + return -0x3F9; + } + + *id = titleID; + // this seems to be two vector instances in an array, considering they are accessed via stack at 0xF0, 0xF4, 0xF8, and 0xFC + vec[0].base = (u8*)id; + vec[0].length = 8; + vec[1].base = (u8*)pTicketView; + vec[1].length = 0xD8; + + ret = IOS_IoctlvReboot(__esFd, 8, 2, 0, vec); + __esFd = -1; + return ret; +} + +s32 ESP_GetTicketViews(ESTitleId titleId, ESTicketView* ticketViewList, u32* ticketViewCnt) { + s32 rv = 0; + u8 __esBuf[256] __attribute__ ((aligned(32))); + IOSIoVector* v = (IOSIoVector *)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); + ESTitleId* p1 = (ESTitleId*)__esBuf; + u32* p2 = (u32*)(__esBuf + 32); + + if (__esFd < 0 || ticketViewCnt == NULL) { + rv = -1017; + goto out; + } + + if (((u32)ticketViewList & 31)) { + rv = -1017; + goto out; + } + + *p1 = titleId; + if (ticketViewList == NULL) { + v[0].base = (u8*)p1; + v[0].length = sizeof(ESTitleId); + v[1].base = (u8*)p2; + v[1].length = 4; + rv = IOS_Ioctlv(__esFd, 18, 1, 1, v); + + if (rv == 0) { + *ticketViewCnt = *p2; + } + } + else { + if (*ticketViewCnt == 0) { + rv = -1017; + goto out; + } + + *p2 = *ticketViewCnt; + v[0].base = (u8*)p1; + v[0].length = sizeof(ESTitleId); + v[1].base = (u8*)p2; + v[1].length = 4; + v[2].base = (u8*)ticketViewList; + v[2].length = sizeof(ESTicketView)*(*ticketViewCnt); + rv = IOS_Ioctlv(__esFd, 19, 2, 1, v); + } + +out: + return rv; +} + +s32 ESP_DiGetTicketView(const void* ticket, ESTicketView* ticketView) { + s32 rv = 0; + u8 __esBuf[256] __attribute__ ((aligned(32))); + IOSIoVector* v = (IOSIoVector *)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); + + if (__esFd < 0 || ticketView == NULL) { + rv = -1017; + goto out; + } + + if (((u32)ticket & 31) || ((u32)ticketView & 31)) { + rv = -1017; + goto out; + } + + v[0].base = (u8*)ticket; + + if (ticket == NULL) { + v[0].length = 0; + } + else { + v[0].length = sizeof(ESTicket); + } + + v[1].base = (u8*)ticketView; + v[1].length = sizeof(ESTicketView); + rv = IOS_Ioctlv(__esFd, 27, 1, 1, v); + +out: + return rv; +} + +s32 ESP_DiGetTmd(ESTitleMeta* tmd, u32* tmdSize) { + s32 rv = 0; + u8 __esBuf[256] __attribute__ ((aligned(32))); + IOSIoVector* v = (IOSIoVector *)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); + u32* p1 = (u32*)__esBuf; + + if (__esFd < 0 || tmdSize == NULL) { + rv = -1017; + goto out; + } + + if (((u32)tmd & 31)) { + rv = -1017; + goto out; + } + + if (tmd == NULL) { + v[0].base = (u8*)p1; + v[0].length = 4; + rv = IOS_Ioctlv(__esFd, 57, 0, 1, v); + + if (rv == 0) { + *tmdSize = *p1; + } + } + else { + if (*tmdSize == 0) { + rv = -1017; + goto out; + } + + *p1 = *tmdSize; + v[0].base = (u8*)p1; + v[0].length = 4; + v[1].base = (u8*)tmd; + v[1].length = *tmdSize; + rv = IOS_Ioctlv(__esFd, 58, 1, 1, v); + } + +out: + return rv; +} + +s32 ESP_GetTmdView(ESTitleId titleId, ESTmdView* tmdView, u32* size) { + s32 rv = 0; + u8 __esBuf[256] __attribute__ ((aligned(32))); + IOSIoVector* v = (IOSIoVector *)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); + ESTitleId* p1 = (ESTitleId*)__esBuf; + u32* p2 = (u32*)(__esBuf + 32); + + if (__esFd < 0 || size == NULL) { + rv = -1017; + goto out; + } + + if (((u32)tmdView & 31)) { + rv = -1017; + goto out; + } + + *p1 = titleId; + + if (tmdView == NULL) { + v[0].base = (u8*)p1; + v[0].length = sizeof(ESTitleId); + v[1].base = (u8*)p2; + v[1].length = 4; + rv = IOS_Ioctlv(__esFd, 20, 1, 1, v); + + if (rv == 0) { + *size = *p2; + } + } + else { + if (*size == 0) { + rv = -1017; + goto out; + } + + *p2 = *size; + v[0].base = (u8*)p1; + v[0].length = sizeof(ESTitleId); + v[1].base = (u8*)p2; + v[1].length = 4; + v[2].base = (u8*)tmdView; + v[2].length = *size; + rv = IOS_Ioctlv(__esFd, 21, 2, 1, v); + } + +out: + return rv; +} + +s32 ESP_GetDataDir(ESTitleId titleId, char* dataDir) { + s32 rv = 0; + u8 __esBuf[256] __attribute__ ((aligned(32))); + IOSIoVector* v = (IOSIoVector *)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); + ESTitleId* p1 = (ESTitleId*)__esBuf; + + if (__esFd < 0 || dataDir == NULL) { + rv = -1017; + goto out; + } + + if (((u32)dataDir & 31)) { + rv = -1017; + goto out; + } + + *p1 = titleId; + v[0].base = (u8*)p1; + v[0].length = sizeof(ESTitleId); + v[1].base = (u8*)dataDir; + v[1].length = 0x1E; + rv = IOS_Ioctlv(__esFd, 29, 1, 1, v); + +out: + return rv; +} + +s32 ESP_GetTitleId(ESTitleId* titleId) { + s32 rv = 0; + u8 __esBuf[256] __attribute__ ((aligned(32))); + IOSIoVector* v = (IOSIoVector *)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); + + if (__esFd < 0 || titleId == NULL) { + rv = -1017; + goto out; + } + + v[0].base = __esBuf; + v[0].length = sizeof(ESTitleId); + + rv = IOS_Ioctlv(__esFd, 32, 0, 1, v); + + if (rv == 0) { + *titleId = *(ESTitleId*)__esBuf; + } + +out: + return rv; +} + +s32 ESP_GetConsumption(ESTicketId ticketId, ESLpEntry* entries, u32* nEntries) { + s32 rv = 0; + u8 __esBuf[256] __attribute__ ((aligned(32))); + IOSIoVector* v = (IOSIoVector *)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); + ESTicketId* p1 = (ESTicketId*)__esBuf; + u32* p2 = (u32*)(__esBuf + 32); + + if (__esFd < 0) { + rv = -1017; + goto out; + } + + if (((u32)entries & 31)) { + rv = -1017; + goto out; + } + + *p1 = ticketId; + v[0].base = (u8*)p1; + v[0].length = sizeof(ESTicketId); + + if (entries == NULL) { + v[1].base = NULL; + v[1].length = 0; + } + else { + v[1].base = (u8*)entries; + v[1].length = sizeof(ESLpEntry) * (*nEntries); + *p2 = *nEntries; + } + + v[2].base = (u8*)p2; + v[2].length = 4; + rv = IOS_Ioctlv(__esFd, 22, 1, 2, v); + *nEntries = *p2; +out: + return rv; +} \ No newline at end of file diff --git a/src/RVL_SDK/euart/euart.c b/src/RVL_SDK/euart/euart.c new file mode 100644 index 000000000..f15006742 --- /dev/null +++ b/src/RVL_SDK/euart/euart.c @@ -0,0 +1,149 @@ +#include "revolution/euart.h" +#include "revolution/exi.h" +#include "revolution/os.h" + +static BOOL __EUARTInitialized = FALSE; +static EUARTError __EUARTLastErrorCode = EUART_ERROR_NONE; +static BOOL __EUARTSendStop = FALSE; +static u32 Enabled = 0; + +BOOL EUARTInit(void) { + BOOL enabled; + u8 val; + + if (__EUARTInitialized) { + return TRUE; + } + + if (!(OSGetConsoleType() & 0x10000000)) { + __EUARTLastErrorCode = EUART_ERROR_CANNOT_USE; + return FALSE; + } + + enabled = OSDisableInterrupts(); + + val = -14; + if (!EXIWriteReg(0, 1, 0xB0000000, &val, 1)) { + __EUARTLastErrorCode = EUART_ERROR_INTERNAL; + OSRestoreInterrupts(enabled); + return FALSE; + } + + val = -13; + if (!EXIWriteReg(0, 1, 0xB0000000, &val, 1)) { + __EUARTLastErrorCode = EUART_ERROR_INTERNAL; + OSRestoreInterrupts(enabled); + return FALSE; + } + + OSRestoreInterrupts(enabled); + + __EUARTInitialized = TRUE; + __EUARTLastErrorCode = EUART_ERROR_NONE; + __EUARTSendStop = FALSE; + return TRUE; +} + +UARTError InitializeUART(UARTBaudRate rate) { + if (!(OSGetConsoleType() & 0x10000000)) { + Enabled = 0; + return kUARTConfigurationError; + } + else { + Enabled = 0xA5FF005A; + return kUARTNoError; + } +} + +inline int QueueLength(void) { + u32 cmd, txCnt; + + if (!EXISelect(0, 1, __EXIFreq)) { + return -1; + } + + cmd = 0x30000100; + EXIImm(0, &cmd, 4, 1, NULL); + EXISync(0); + EXIImm(0, &txCnt, sizeof(txCnt), 0, NULL); + EXISync(0); + EXIDeselect(0); + return 32 - (u8)((txCnt >> 24) & 0x3F); +} + +UARTError WriteUARTN(const void *buf, unsigned long len) { + u32 cmd; + int qLen; + UARTError error; + char* sendData = (char*)buf; + u32 uart_txd; + + if (Enabled != 0xA5FF005A) { + return kUARTConfigurationError; + } + + if (!__EUARTInitialized) { + if (!EUARTInit()) { + return kUARTConfigurationError; + } + } + + if (!__EUARTInitialized) { + __EUARTLastErrorCode = EUART_ERROR_UNINITIALIZED; + return kUARTConfigurationError; + } + + if (!EXILock(0, 1, 0)) { + return kUARTNoError; + } + + { + char* p; + + for (p = sendData; (p - buf) < len; p++) { + if (*p == '\n') { + *p = '\r'; + } + } + } + + error = kUARTNoError; + cmd = 0xB0000100; + + while (len != 0) { + qLen = QueueLength(); + + if (qLen < 0) { + error = kUARTBufferOverflow; + break; + } + + if (qLen != 32) { + continue; + } + + if (!EXISelect(0, 1, __EXIFreq)) { + error = kUARTBufferOverflow; + break; + } + + EXIImm(0, &cmd, 4, 1, NULL); + EXISync(0); + + while ((qLen > 0) && (len > 0)) { + uart_txd = (u32)((*sendData & 0xFF) << 24); + + EXIImm(0, &uart_txd, 4, 1, NULL); + EXISync(0); + + sendData++; + qLen--; + len--; + } + + EXIDeselect(0); + } + + EXIUnlock(0); + return error; +} \ No newline at end of file diff --git a/src/RVL_SDK/exi/EXIBios.c b/src/RVL_SDK/exi/EXIBios.c new file mode 100644 index 000000000..8f6facce1 --- /dev/null +++ b/src/RVL_SDK/exi/EXIBios.c @@ -0,0 +1,708 @@ +#include "revolution/exi.h" +#include "private/flipper.h" +#include "private/io_reg.h" +#include + +#define CPR_EXIINTMSK_MASK EXI_0CPR_EXIINTMSK_MASK +#define CPR_EXIINT_MASK EXI_0CPR_EXIINT_MASK +#define CPR_TCINTMSK_MASK EXI_0CPR_TCINTMSK_MASK +#define CPR_TCINT_MASK EXI_0CPR_TCINT_MASK +#define CPR_EXTINTMSK_MASK EXI_0CPR_EXTINTMSK_MASK +#define CPR_EXTINT_MASK EXI_0CPR_EXTINT_MASK +#define CPR_EXT_MASK EXI_0CPR_EXT_MASK + +#define CPR_ALLINTMSK_MASK (CPR_EXTINTMSK_MASK | CPR_EXIINTMSK_MASK | CPR_TCINTMSK_MASK) +#define CPR_ALLINT_MASK (CPR_EXTINT_MASK | CPR_EXIINT_MASK | CPR_TCINT_MASK) +#define CPR_CLK_MASK EXI_0CPR_CLK_MASK +#define CPR_CS_MASK (EXI_0CPR_CS0B_MASK | EXI_0CPR_CS1B_MASK | EXI_0CPR_CS2B_MASK) + +#define EXI_0CR_TSTART_SHIFT 0 +#define EXI_0CR_DMA_SHIFT 1 +#define EXI_0CR_RW_SHIFT 2 +#define EXI_0CR_TLEN_SHIFT 4 + +#define EXI_0CR_GET_TSTART(exi_0cr) \ + ((((unsigned long)(exi_0cr)) & 0x00000001) >> EXI_0CR_TSTART_SHIFT) + +#define EXI_0CR(tstart, dma, rw, tlen) \ + ((((unsigned long)(tstart)) << 0) | \ + (((unsigned long)(dma)) << 1) | \ + (((unsigned long)(rw)) << 2) | \ + (((unsigned long)(tlen)) << 4)) + +extern BOOL __OSInIPL; + +typedef struct EXIControl { + EXICallback exiCallback; + EXICallback tcCallback; + EXICallback extCallback; + vu32 state; + int immLen; + u8* immBuf; + u32 dev; + u32 id; + s32 idTime; + int items; + + struct { + u32 device; + EXICallback cb; + } queue[3]; +} EXIControl; + +static EXIControl Ecb[3]; +s32 __EXIProbeStartTime[2] : (OS_BASE_CACHED | 0x30C0); +static u32 IDSerialPort1; + +static const char* __EXIVersion = "<< RVL_SDK - EXI \trelease build: Aug 8 2007 01:59:22 (0x4199_60831) >>"; + +#define REG(chan, idx) (__EXIRegs[((chan) * 5) + (idx)]) + +void SetExiInterruptMask(s32 chan, EXIControl* exi) { + EXIControl* exi2; + exi2 = &Ecb[2]; + + switch (chan) { + case 0: + if ((exi->exiCallback == 0 && exi2->exiCallback == 0) || (exi->state & 0x10)) { + __OSMaskInterrupts(0x410000); + } + else { + __OSUnmaskInterrupts(0x410000); + } + break; + + case 1: + if (exi->exiCallback == 0 || (exi->state & 0x10)) { + __OSMaskInterrupts(0x80000); + } + else { + __OSUnmaskInterrupts(0x80000); + } + break; + + case 2: + if (__OSGetInterruptHandler(25) == NULL || (exi->state & 0x10)) { + __OSMaskInterrupts(0x40); + } + else { + __OSUnmaskInterrupts(0x40); + } + break; + } +} + +static void CompleteTransfer(s32 chan) { + EXIControl* exi = &Ecb[chan]; + u8* buf; + u32 data; + int i; + int len; + + if (exi->state & 3) { + if ((exi->state & 2) && (exi->immLen != 0)) { + len = exi->immLen; + buf = exi->immBuf; + data = REG(chan, 4); + + for (i = 0; i < len; i++) { + *buf++ = (u8)((data >> ((3 - i) * 8)) & 0xFF); + } + } + + exi->state &= ~3; + } +} + +BOOL EXIImm(s32 chan, void* buf, s32 len, u32 type, EXICallback callback) { + EXIControl* exi = &Ecb[chan]; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + if ((exi->state & 3) || !(exi->state & 4)) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + exi->tcCallback = callback; + + if (exi->tcCallback) { + EXIClearInterrupts(chan, FALSE, TRUE, FALSE); + __OSUnmaskInterrupts(0x200000u >> (3 * chan)); + } + + exi->state |= 2; + + if (type != 0) { + u32 data; + int i; + + data = 0; + + for (i = 0 ; i < len ; i++) { + data |= ((u8*)buf)[i] << ((3 - i) * 8); + } + + REG(chan, 4) = data; + } + + exi->immBuf = buf; + exi->immLen = (type != 1) ? len : 0; + REG(chan, 3) = EXI_0CR(1, 0, type, len-1); + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL EXIImmEx(s32 chan, void* buf, s32 len, u32 mode) { + s32 xLen; + + while (len != 0) { + xLen = (len < 4) ? len : 4; + + if (!EXIImm(chan, buf, xLen, mode, 0)) { + return FALSE; + } + + if (!EXISync(chan)) { + return FALSE; + } + + (u8*)buf += xLen; + len -= xLen; + } + + return TRUE; +} + +u32 EXIClearInterrupts(s32 channel, BOOL exi, BOOL tc, BOOL ext) { + u32 cpr; + u32 prev; + + prev = cpr = REG(channel, EXI_0CPR_IDX); + cpr &= 0x7F5; + + if (exi) { + cpr |= 2; + } + + if (tc) { + cpr |= 8; + } + + if (ext) { + cpr |= 0x800; + } + + REG(channel, EXI_0CPR_IDX) = cpr; + return prev; +} + +BOOL EXIDma(s32 channel, void *buffer, s32 length, u32 type, EXICallback cb) { + EXIControl* exi = &Ecb[channel]; + BOOL isEnabled; + + isEnabled = OSDisableInterrupts(); + + if ((exi->state & 3) || !(exi->state & 4)) { + OSRestoreInterrupts(isEnabled); + return FALSE; + } + + exi->tcCallback = cb; + + if (exi->tcCallback) { + EXIClearInterrupts(channel, FALSE, TRUE, FALSE); + __OSUnmaskInterrupts(0x200000u >> (3 * channel)); + } + + exi->state |= 1; + REG(channel, 1) = (u32)buffer & 0xFFFFFFE0; + REG(channel, 2) = length; + REG(channel, 3) = (4 * type) | 3; + OSRestoreInterrupts(isEnabled); + return TRUE; +} + +extern u32 __OSGetDIConfig(void); +vu16 __OSDeviceCode : (OS_BASE_CACHED | 0x30E6); + +BOOL EXISync(s32 chan) { + EXIControl* exi = &Ecb[chan]; + BOOL rc = FALSE; + BOOL enabled; + + while (exi->state & 4) { + if (EXI_0CR_GET_TSTART(REG(chan, 3)) == 0) { + enabled = OSDisableInterrupts(); + + if (exi->state & 4) + { + CompleteTransfer(chan); + if (__OSGetDIConfig() != 0xFF || ((OSGetConsoleType() & 0xf0000000) == 0x20000000) || exi->immLen != 4 || (REG(chan, 0) & CPR_CLK_MASK) != 0 || + (REG(chan, 4) != 0x1010000 && REG(chan, 4) != 0x5070000 && REG(chan, 4) != 0x4220001) || + __OSDeviceCode == (0x8000 | 0x200)) + { + rc = TRUE; + } + } + + OSRestoreInterrupts(enabled); + break; + } + } + + return rc; +} + +EXICallback EXISetExiCallback(s32 chan, EXICallback exiCallback) { + EXIControl* exi = &Ecb[chan]; + EXICallback prev; + BOOL enabled; + + enabled = OSDisableInterrupts(); + prev = exi->exiCallback; + exi->exiCallback = exiCallback; + + if (chan != 2) { + SetExiInterruptMask(chan, exi); + } + else { + SetExiInterruptMask(0, &Ecb[0]); + } + + OSRestoreInterrupts(enabled); + return prev; +} + +void EXIProbeReset(void) { + __EXIProbeStartTime[0] = __EXIProbeStartTime[1] = 0; + Ecb[0].idTime = Ecb[1].idTime = 0; + + __EXIProbe(0); + __EXIProbe(1); +} + +static BOOL __EXIProbe(s32 chan) { + EXIControl* exi = &Ecb[chan]; + BOOL enabled; + BOOL rc; + u32 cpr; + s32 t; + + if (chan == 2) { + return TRUE; + } + + rc = TRUE; + enabled = OSDisableInterrupts(); + cpr = REG(chan, 0); + + if (!(exi->state & 8)) { + if (cpr & 0x800) { + EXIClearInterrupts(chan, FALSE, FALSE, TRUE); + __EXIProbeStartTime[chan] = exi->idTime = 0; + } + + if (cpr & 0x1000) { + t = (s32)(OSTicksToMilliseconds(OSGetTime()) / 100) + 1; + + if (__EXIProbeStartTime[chan] == 0) { + __EXIProbeStartTime[chan] = t; + } + + if (t - __EXIProbeStartTime[chan] < 300 / 100) { + rc = FALSE; + } + } + else { + __EXIProbeStartTime[chan] = exi->idTime = 0; + rc = FALSE; + } + } + else if (!(cpr & 0x1000) || (cpr & 0x800)) { + __EXIProbeStartTime[chan] = exi->idTime = 0; + rc = FALSE; + } + + OSRestoreInterrupts(enabled); + return rc; +} + +BOOL EXIProbe(s32 chan) { + EXIControl* exi = &Ecb[chan]; + BOOL rc; + u32 id; + + rc = __EXIProbe(chan); + + if (rc && exi->idTime == 0) { + rc = EXIGetID(chan, 0, &id) ? TRUE : FALSE; + } + + return rc; +} + +static BOOL __EXIAttach(s32 chan, EXICallback extCallback) { + EXIControl* exi = &Ecb[chan]; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + if ((exi->state & 8) || __EXIProbe(chan) == FALSE) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + EXIClearInterrupts(chan, TRUE, FALSE, FALSE); + exi->extCallback = extCallback; + __OSUnmaskInterrupts(0x100000u >> (3 * chan)); + exi->state |= 8; + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL EXIAttach(s32 chan, EXICallback extCallback) { + EXIControl* exi = &Ecb[chan]; + BOOL enabled; + BOOL rc; + + EXIProbe(chan); + enabled = OSDisableInterrupts(); + + if (exi->idTime == 0) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + rc = __EXIAttach(chan, extCallback); + OSRestoreInterrupts(enabled); + return rc; +} + +BOOL EXIDetach(s32 chan) { + EXIControl* exi = &Ecb[chan]; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + if (!(exi->state & 8)) { + OSRestoreInterrupts(enabled); + return TRUE; + } + + if ((exi->state & 0x10) && exi->dev == 0) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + exi->state &= 0xFFFFFFF7; + __OSMaskInterrupts(0x500000u >> (3 * chan)); + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL EXISelect(s32 chan, u32 dev, u32 freq) { + EXIControl* exi = &Ecb[chan]; + u32 cpr; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + if ((exi->state & 4) || chan != 2 && (dev == 0 && !(exi->state & 8) && !__EXIProbe(chan) || !(exi->state & 0x10) || (exi->dev != dev))) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + exi->state |= 4; + cpr = REG(chan, 0); + cpr &= 0x405; + cpr |= (1 << dev << 7) | (freq << 4); + REG(chan, 0) = cpr; + + if (exi->state & 8) { + switch (chan) { + case 0: + __OSMaskInterrupts(0x100000); + break; + case 1: + __OSMaskInterrupts(0x20000); + break; + } + } + + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL EXIDeselect(s32 chan) { + EXIControl* exi = &Ecb[chan]; + u32 cpr; + BOOL enabled; + enabled = OSDisableInterrupts(); + + if (!(exi->state & 4)) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + exi->state &= 0xFFFFFFFB; + cpr = REG(chan, 0); + REG(chan, 0) = cpr & 0x405; + + if (exi->state & 8) { + switch (chan) { + case 0: + __OSUnmaskInterrupts(0x100000); + break; + case 1: + __OSUnmaskInterrupts(0x20000); + break; + } + } + + OSRestoreInterrupts(enabled); + + if (chan != 2 && (cpr & 0x80)) { + return __EXIProbe(chan) ? TRUE : FALSE; + } + + return TRUE; +} + +static void EXIIntrruptHandler(__OSInterrupt interrupt, OSContext* context) { + s32 chan; + EXIControl* exi; + EXICallback callback; + + chan = (interrupt - 9) / 3; + exi = &Ecb[chan]; + EXIClearInterrupts(chan, TRUE, FALSE, FALSE); + callback = exi->exiCallback; + + if (callback) { + OSContext exceptionContext; + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + callback(chan, context); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +static void TCIntrruptHandler(__OSInterrupt interrupt, OSContext* context) { + s32 chan; + EXIControl* exi; + EXICallback callback; + chan = (interrupt - 10) / 3; + exi = &Ecb[chan]; + __OSMaskInterrupts(0x80000000u >> interrupt); + EXIClearInterrupts(chan, FALSE, TRUE, FALSE); + callback = exi->tcCallback; + + if (callback) { + OSContext exceptionContext; + exi->tcCallback = 0; + CompleteTransfer(chan); + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + callback(chan, context); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +static void EXTIntrruptHandler(__OSInterrupt interrupt, OSContext* context) { + s32 chan; + EXIControl* exi; + EXICallback callback; + chan = (interrupt - 11) / 3; + __OSMaskInterrupts(0x500000u >> (3 * chan)); + exi = &Ecb[chan]; + callback = exi->extCallback; + exi->state &= 0xFFFFFFF7; + + if (callback) { + OSContext exceptionContext; + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + exi->extCallback = 0; + callback(chan, context); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + } +} + +void EXIInit(void) { + u32 id; + + while(EXI_0CR_GET_TSTART(REG(0, 3)) == 1 || EXI_0CR_GET_TSTART(REG(1, 0)) == 1 || EXI_0CR_GET_TSTART(REG(2, 0)) == 1) { + + } + + __OSMaskInterrupts(0x7F8000); + REG(0, 0) = 0; + REG(1, 0) = 0; + REG(2, 0) = 0; + REG(0, 0) = 0x2000; + + __OSSetInterruptHandler(9, EXIIntrruptHandler); + __OSSetInterruptHandler(10, TCIntrruptHandler); + __OSSetInterruptHandler(11, EXTIntrruptHandler); + __OSSetInterruptHandler(12, EXIIntrruptHandler); + __OSSetInterruptHandler(13, TCIntrruptHandler); + __OSSetInterruptHandler(14, EXTIntrruptHandler); + __OSSetInterruptHandler(15, EXIIntrruptHandler); + __OSSetInterruptHandler(16, TCIntrruptHandler); + + EXIGetID(0, 2, &IDSerialPort1); + + if (__OSInIPL) { + EXIProbeReset(); + } + else { + if (EXIGetID(0, 0, &id) && id == 0x07010000) { + __OSEnableBarnacle(1, 0); + } + else if (EXIGetID(1, 0, &id) && id == 0x07010000) { + __OSEnableBarnacle(0, 2); + } + } + + OSRegisterVersion(__EXIVersion); +} + +BOOL EXILock(s32 chan, u32 dev, EXICallback unlockedCallback) { + EXIControl* exi = &Ecb[chan]; + BOOL enabled; + int i; + + enabled = OSDisableInterrupts(); + + if (exi->state & 0x10) { + if (unlockedCallback) { + for (i = 0; i < exi->items; i++) { + if (exi->queue[i].device == dev) { + OSRestoreInterrupts(enabled); + return FALSE; + } + } + + exi->queue[exi->items].cb = unlockedCallback; + exi->queue[exi->items].device = dev; + exi->items++; + } + + OSRestoreInterrupts(enabled); + return FALSE; + } + + exi->state |= 0x10; + exi->dev = dev; + SetExiInterruptMask(chan, exi); + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL EXIUnlock(s32 chan) { + EXIControl* exi = &Ecb[chan]; + BOOL enabled; + EXICallback unlockedCallback; + + enabled = OSDisableInterrupts(); + + if (!(exi->state & 0x10)) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + exi->state &= 0xFFFFFFEF; + SetExiInterruptMask(chan, exi); + + if (0 < exi->items) { + unlockedCallback = exi->queue[0].cb; + + if (0 < --exi->items) { + memmove(&exi->queue[0], &exi->queue[1], 8 * exi->items); + } + + unlockedCallback(chan, 0); + } + + OSRestoreInterrupts(enabled); + return TRUE; +} + +s32 EXIGetID(s32, u32, u32 *); + +static void UnlockedHandler(s32 chan, OSContext* context) { + u32 id; + EXIGetID(chan, 0, &id); +} + +s32 EXIGetID(s32 chan, u32 dev, u32* id) { + EXIControl* exi = &Ecb[chan]; + BOOL err; + u32 cmd; + s32 startTime; + BOOL enabled; + + if (chan == 0 && dev == 2 && IDSerialPort1 != 0) { + *id = IDSerialPort1; + return 1; + } + + if (chan < 2 && dev == 0) { + if (!__EXIProbe(chan)) { + return 0; + } + + if (exi->idTime == __EXIProbeStartTime[chan]) { + *id = exi->id; + return exi->idTime; + } + + if (!__EXIAttach(chan, 0)) { + return 0; + } + + startTime = __EXIProbeStartTime[chan]; + } + + enabled = OSDisableInterrupts(); + err = !EXILock(chan, dev, (chan < 2 && dev == 0) ? UnlockedHandler : 0); + + if (err == 0) { + err = !EXISelect(chan, dev, 0); + + if (err == 0) { + cmd = 0; + err |= !EXIImm(chan, &cmd, 2, 1, 0); + err |= !EXISync(chan); + err |= !EXIImm(chan, id, 4, 0, 0); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + } + + EXIUnlock(chan); + } + + OSRestoreInterrupts(enabled); + + if (chan < 2 && dev == 0) { + EXIDetach(chan); + + enabled = OSDisableInterrupts(); + err |= (startTime != __EXIProbeStartTime[chan]); + + if (err == 0) { + exi->id = *id; + exi->idTime = startTime; + } + + OSRestoreInterrupts(enabled); + return err ? 0 : exi->idTime; + } + + return err ? 0 : 1; +} \ No newline at end of file diff --git a/src/RVL_SDK/exi/EXICommon.c b/src/RVL_SDK/exi/EXICommon.c new file mode 100644 index 000000000..d2a754742 --- /dev/null +++ b/src/RVL_SDK/exi/EXICommon.c @@ -0,0 +1,45 @@ +#include + +const u32 __EXIFreq = 4; + +static inline u32 __EXISwap32(u32 val) { + return ((val >> 24) & 0x000000FF) | ((val >> 8) & 0x0000FF00) | ((val << 8) & 0x00FF0000) | ((val << 24) & 0xFF000000); +} + +BOOL EXIWriteReg(s32 chan, u32 dev, u32 exiCmd, void* reg, s32 size) { + BOOL ret = FALSE; + u32 reg32; + + switch (size) { + case 1: + reg32 = (u32)((*((u8*)reg) & 0xFF) << 24); + break; + case 2: + reg32 = (u32)(((*((u16 *)reg) & 0xFF) << 24) | ((*((u16*)reg) & 0xFF00) << 8)); + break; + default: + reg32 = __EXISwap32(*((u32*)reg)); + break; + } + + ret |= !EXILock(chan, dev, 0); + + if (ret) { + return FALSE; + } + + ret |= !EXISelect(chan, dev, 4); + + if (ret) { + EXIUnlock(chan); + return FALSE; + } + + ret |= !EXIImm(chan, &exiCmd, 4, 1, NULL); + ret |= !EXISync(chan); + ret |= !EXIImm(chan, ®32, 4, 1, NULL); + ret |= !EXISync(chan); + ret |= !EXIDeselect(chan); + ret |= !EXIUnlock(chan); + return !ret; +} \ No newline at end of file diff --git a/src/RVL_SDK/exi/EXIUart.c b/src/RVL_SDK/exi/EXIUart.c new file mode 100644 index 000000000..10d73a960 --- /dev/null +++ b/src/RVL_SDK/exi/EXIUart.c @@ -0,0 +1,81 @@ +#include + +static s32 Chan; +static u32 Dev; +static u32 Enabled = 0; +static u32 BarnacleEnabled = 0; + +static BOOL ProbeBarnacle(s32 chan, u32 dev, u32* revision) { + BOOL err; + u32 cmd; + + if (chan != 2 && dev == 0 && !EXIAttach(chan, NULL)) { + return FALSE; + } + + err = !EXILock(chan, dev, NULL); + if (err == 0) { + err = !EXISelect(chan, dev, 0); + + if (err == 0) { + cmd = 0x20011300; + err = FALSE; + err |= !EXIImm(chan, &cmd, 4, 1, 0); + err |= !EXISync(chan); + err |= !EXIImm(chan, revision, 4, 0, 0); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + } + + EXIUnlock(chan); + } + + if (chan != 2 && dev == 0) { + EXIDetach(chan); + } + + if (err != 0) { + return FALSE; + } + + return (*revision != 0xFFFFFFFF) ? TRUE : FALSE; +} + +void __OSEnableBarnacle(s32 chan, u32 dev) { + u32 id; + + if (EXIGetID(chan, dev, &id)) { + switch (id) { + case 0xFFFFFFFF: + case 4: + case 8: + case 0x10: + case 0x20: + case 0x01010000: + case 0x01020000: + case 0x02020000: + case 0x03010000: + case 0x04220000: + case 0x04020100: + case 0x04020200: + case 0x04020300: + case 0x04040404: + case 0x04060000: + case 0x04120000: + case 0x04130000: + case 0x80000004: + case 0x80000008: + case 0x80000010: + case 0x80000020: + break; + default: + if (ProbeBarnacle(chan, dev, &id)) { + Chan = chan; + Dev = dev; + Enabled = BarnacleEnabled = 0xa5FF005A; + } + + break; + } + } +} \ No newline at end of file diff --git a/src/RVL_SDK/fs/fs.c b/src/RVL_SDK/fs/fs.c new file mode 100644 index 000000000..3d383da30 --- /dev/null +++ b/src/RVL_SDK/fs/fs.c @@ -0,0 +1,964 @@ +#include +#include +#include +#include +#include + +static IOSFd __fsFd = -1; +static u32 __fsInitialized = FALSE; +static char* __devfs = 0; +static IOSHeapId hId; +static s32 _asynCnt = 0; + +#define ROUNDUP(sz) (((u32)(sz) + 31) & \ + ~(u32)(31)) + +typedef struct isfs_GetAttr { + IOSUid* ownerId; + IOSGid* groupId; + u32* attr; + u32* ownerAcc; + u32* groupAcc; + u32* othersAcc; +} isfs_GetAttr; + +typedef struct isfs_GetUsage { + u32* nblocks; + u32* ninodes; +} isfs_GetUsage; + +typedef struct __isfsCtxt { + u8 ioBuf[ROUNDUP(256)] __attribute__((aligned(32))); + ISFSCallback cb; + void* ctxt; + u32 func; + + union { + ISFSStats* stats; + ISFSFileStats* fstats; + u32* num; + isfs_GetAttr ga; + isfs_GetUsage gu; + } args; +} __isfsCtxt; + +ISFSError ISFS_OpenLib(void) { + ISFSError rc = 0; + static void* lo = 0, *hi = 0; + __isfsCtxt* __fsCtxt = 0; + + if (!__fsInitialized) { + lo = IPCGetBufferLo(); + hi = IPCGetBufferHi(); + } + + __devfs = (char*)ROUNDUP(lo); + if (!__fsInitialized && ((u32)__devfs + ROUNDUP(64)) > (u32)hi) { + OSReport("APP ERROR: Not enough IPC arena\n"); + rc = -22; + goto out; + } + + strcpy(__devfs, "/dev/fs"); + __fsFd = IOS_Open(__devfs, 0); + + if (__fsFd < 0) { + rc = __fsFd; + goto out; + } + + __fsCtxt = (__isfsCtxt*)((u32)__devfs); + + if (!__fsInitialized && ((u32)__fsCtxt + (16 + 1) * ROUNDUP(sizeof(__isfsCtxt))) > (u32)hi) { + OSReport("APP ERROR: Not enough IPC arena\n"); + rc = -22; + goto out; + } + + if (!__fsInitialized) { + IPCSetBufferLo((void*)((u32)__fsCtxt + (17) * ROUNDUP(sizeof(__isfsCtxt)))); + __fsInitialized = TRUE; + } + + hId = iosCreateHeap(__fsCtxt, 17 * ROUNDUP(sizeof(__isfsCtxt))); + + if (hId < 0) { + rc = -22; + goto out; + } + +out: + return rc; +} + +static IOSError _FSGetStatsCb(IOSError ret, void* ctxt) { + __isfsCtxt* _ctxt = (__isfsCtxt*)ctxt; + ISFSError rc = 0; + + if (ret == 0) { + memcpy(_ctxt->args.stats, _ctxt->ioBuf, sizeof(*_ctxt->args.stats)); + } + + return rc; +} + +static IOSError _FSReadDirCb(IOSError ret, void* ctxt) { + ISFSError rc = 0; + __isfsCtxt* _ctxt = (__isfsCtxt*)ctxt; + + if (ret == 0) { + u8* ptr; + IOSIoVector* v = (IOSIoVector*)_ctxt->ioBuf; + ptr = (u8*)ROUNDUP((u8*)&v[4]); + ptr = (u8*)ROUNDUP(ptr + 64); + *_ctxt->args.num = *(u32 *) ptr; + } + + return rc; +} + +static IOSError _FSGetAttrCb(IOSError ret, void* ctxt) { + ISFSError rc = 0; + + if (ret == 0) { + __isfsCtxt* _ctxt = (__isfsCtxt*)ctxt; + ISFSPathAttrArgs* pathAttrArgs = (ISFSPathAttrArgs*)ROUNDUP(_ctxt->ioBuf + 64); + + *_ctxt->args.ga.ownerId = pathAttrArgs->ownerId; + *_ctxt->args.ga.groupId = pathAttrArgs->groupId; + *_ctxt->args.ga.attr = pathAttrArgs->attr; + *_ctxt->args.ga.ownerAcc = pathAttrArgs->ownerAccess; + *_ctxt->args.ga.groupAcc = pathAttrArgs->groupAccess; + *_ctxt->args.ga.othersAcc = pathAttrArgs->othersAccess; + } + + return rc; +} + +static IOSError _FSGetUsageCb(IOSError ret, void* ctxt) { + ISFSError rc = 0; + __isfsCtxt* _ctxt = (__isfsCtxt*)ctxt; + + if (ret == 0) { + u8* ptr; + IOSIoVector* v = (IOSIoVector*)_ctxt->ioBuf; + ptr = (u8*)ROUNDUP((u8*)&v[4]); + ptr = (u8*)ROUNDUP(ptr + 64); + *_ctxt->args.gu.nblocks = *(u32*)ptr; + ptr = (u8*)ROUNDUP(ptr + 4); + *_ctxt->args.gu.ninodes = *(u32*)ptr; + } + + return rc; +} + +static IOSError _FSGetFileStatsCb(IOSError ret, void* ctxt) { + __isfsCtxt* _ctxt = (__isfsCtxt*)ctxt; + ISFSError rc = 0; + + if (ret == 0) { + memcpy(_ctxt->args.fstats, _ctxt->ioBuf, sizeof(*_ctxt->args.fstats)); + } + + return rc; +} + + IOSError _isfsFuncCb(IOSError ret, void* ctxt) { + ISFSError rc = 0; + __isfsCtxt* _ctxt = (__isfsCtxt*)ctxt; + rc = ret; + + if (rc >= 0) { + switch (_ctxt->func) { + case 1: + _FSGetStatsCb(ret, ctxt); + break; + case 2: + _FSReadDirCb(ret, ctxt); + break; + case 3: + _FSGetAttrCb(ret, ctxt); + break; + case 4: + _FSGetUsageCb(ret, ctxt); + break; + case 5: + _FSGetFileStatsCb(ret, ctxt); + break; + default: + break; + } + } + + _asynCnt = 0; + + if (_ctxt->cb) { + _ctxt->cb(rc, _ctxt->ctxt); + } + + if (ctxt) { + iosFree(hId, ctxt); + } + + return rc; +} + +s32 ISFS_CreateDir(const u8* dname, u32 dirAttr, u32 ownerAcc, u32 groupAcc, u32 othersAcc) { + ISFSError rc = ISFS_ERROR_OK; + ISFSPathAttrArgs* pathAttrArgs; + __isfsCtxt* blCtxt = 0; + u32 len; + + if ((dname == NULL) || (__fsFd < 0) || ((len = strnlen(dname, 64)) == 64)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32); + + if (blCtxt == NULL) { + rc = IOS_ERROR_FAIL_ALLOC; + goto out; + } + + pathAttrArgs = (ISFSPathAttrArgs*)blCtxt->ioBuf; + memcpy(pathAttrArgs->path, dname, len + 1); + + pathAttrArgs->attr = (u8)dirAttr; + pathAttrArgs->ownerAccess = (u8)ownerAcc; + pathAttrArgs->groupAccess = (u8)groupAcc; + pathAttrArgs->othersAccess = (u8)othersAcc; + rc = IOS_Ioctl(__fsFd, 3, pathAttrArgs, sizeof(*pathAttrArgs), NULL, 0); + +out: + /* they seem to have had a macro for this, and the programmer forgot it did a NULL check */ + if (blCtxt != NULL) { + if (blCtxt != NULL) { + iosFree(hId, blCtxt); + } + + } + + return rc; +} + +s32 ISFS_CreateDirAsync(const u8* dname, u32 dirAttr, u32 ownerAcc, u32 groupAcc, u32 othersAcc, ISFSCallback cb, void* fsCtxt) { + ISFSError rc = ISFS_ERROR_OK; + u32 len; + ISFSPathAttrArgs* pathAttrArgs; + __isfsCtxt* ctxt; + + if ((dname == NULL) || (__fsFd < 0) || ((len = strnlen(dname, 64)) == 64)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32); + + if (ctxt == NULL) { + rc = ISFS_ERROR_BUSY; + goto out; + } + + ctxt->cb = cb; + ctxt->ctxt = fsCtxt; + ctxt->func = 0; + pathAttrArgs = (ISFSPathAttrArgs*)ctxt->ioBuf; + memcpy(pathAttrArgs->path, (void*)dname, len + 1); + pathAttrArgs->attr = dirAttr; + pathAttrArgs->ownerAccess = ownerAcc; + pathAttrArgs->groupAccess = groupAcc; + pathAttrArgs->othersAccess = othersAcc; + rc = IOS_IoctlAsync(__fsFd, 3, pathAttrArgs, sizeof(*pathAttrArgs), NULL, 0, _isfsFuncCb, ctxt); + +out: + return rc; +} + +s32 ISFS_ReadDir(const u8* dname, u8* nameList, u32* num) { + ISFSError rc = ISFS_ERROR_OK; + IOSIoVector* v = 0; + u32 len, numInputs, numOutputs, *numPtr; + char* dnPtr; + __isfsCtxt* blCtxt = 0; + + if ((dname == NULL) || (num == NULL) || (__fsFd < 0) || ((u32)nameList & 31) || ((len = strnlen(dname, 64)) == 64)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32); + if (blCtxt == NULL) { + rc = IOS_ERROR_FAIL_ALLOC; + goto out; + } + + v = (IOSIoVector*)blCtxt->ioBuf; + dnPtr = (char*)ROUNDUP((u8*)&v[4]); + memcpy(dnPtr, dname, len + 1); + v[0].base = (u8*)dnPtr; + v[0].length = 64; + numPtr = (u32*)ROUNDUP((u32)dnPtr + 64); + v[1].base = (u8*)numPtr; + v[1].length = 4; + + if (nameList != NULL) { + numInputs = 2; + numOutputs = 2; + *numPtr = *num; + v[2].base = nameList; + v[2].length = *num * 13; + v[3].base = (u8*)numPtr; + v[3].length = 4; + } + else { + numInputs = 1; + numOutputs = 1; + } + + rc = IOS_Ioctlv(__fsFd, 4, numInputs, numOutputs, v); + + if (rc != ISFS_ERROR_OK) { + goto out; + } + + *num = *numPtr; + +out: + if (blCtxt != NULL) { + if (blCtxt != NULL) { + iosFree(hId, blCtxt); + } + } + + return rc; +} + +s32 ISFS_ReadDirAsync(const u8* dname, u8* nameList, u32* num, ISFSCallback cb, void* fsCtxt) { + ISFSError rc = ISFS_ERROR_OK; + u32 len, numInputs, numOutputs, *numPtr; + IOSIoVector* v = 0; + __isfsCtxt* ctxt = 0; + char* dnPtr; + + if ((dname == NULL) || (num == NULL) || (__fsFd < 0) || ((u32)nameList & 31) || ((len = strnlen(dname, 64)) == 64)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32); + if (ctxt == NULL) { + rc = ISFS_ERROR_BUSY; + goto out; + } + + ctxt->cb = cb; + ctxt->ctxt = fsCtxt; + ctxt->func = 2; + ctxt->args.num = num; + v = (IOSIoVector*)ctxt->ioBuf; + dnPtr = (char*)ROUNDUP((u8*)&v[4]); + memcpy(dnPtr, dname, len + 1); + v[0].base = (u8*)dnPtr; + v[0].length = 64; + numPtr = (u32*)ROUNDUP((u32)dnPtr + 64); + v[1].base = (u8*)numPtr; + v[1].length = 4; + + if (nameList != NULL) { + numInputs = 2; + numOutputs = 2; + *numPtr = *num; + v[2].base = nameList; + v[2].length = *num * 13; + v[3].base = (u8*)numPtr; + v[3].length = 4; + } + else { + numInputs = 1; + numOutputs = 1; + } + + rc = IOS_IoctlvAsync(__fsFd, 4, numInputs, numOutputs, v, _isfsFuncCb, ctxt); + +out: + return rc; +} + +s32 ISFS_GetAttr(const u8* name, IOSUid* ownerId, IOSGid* groupId, u32* attr, u32* ownerAcc, u32* groupAcc, u32* othersAcc) { + ISFSError rc = ISFS_ERROR_OK; + ISFSPathAttrArgs* pathAttrArgs; + u8* ptr; + u32 len; + __isfsCtxt* blCtxt = 0; + + if ((name == NULL) || (__fsFd < 0) || + ((len = strnlen(name, 64)) == 64) || + (ownerId == NULL) || (groupId == NULL) || (attr == NULL) || + (ownerAcc == NULL) || (groupAcc == NULL) || (othersAcc == NULL)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32); + if (blCtxt == NULL) { + rc = IOS_ERROR_FAIL_ALLOC; + goto out; + } + + ptr = (u8*)blCtxt->ioBuf; + memcpy(ptr, name, len + 1); + pathAttrArgs = (ISFSPathAttrArgs*)ROUNDUP(ptr + 64); + rc = IOS_Ioctl(__fsFd, 6, ptr, 64, pathAttrArgs, sizeof(*pathAttrArgs)); + + if (rc != IOS_ERROR_OK) { + goto out; + } + + *ownerId = pathAttrArgs->ownerId; + *groupId = pathAttrArgs->groupId; + *attr = pathAttrArgs->attr; + *ownerAcc = pathAttrArgs->ownerAccess; + *groupAcc = pathAttrArgs->groupAccess; + *othersAcc = pathAttrArgs->othersAccess; + +out: + if (blCtxt != NULL) { + if (blCtxt != NULL) { + iosFree(hId, blCtxt); + } + } + + return rc; +} + +s32 ISFS_GetAttrAsync(const u8* name, IOSUid* ownerId, IOSGid* groupId, u32* attr, u32* ownerAcc, u32* groupAcc, u32* othersAcc, ISFSCallback cb, void* fsCtxt) { + ISFSError rc = ISFS_ERROR_OK; + __isfsCtxt *ctxt; + ISFSPathAttrArgs *pathAttrArgs; + u8 *ptr; + u32 len; + + if ((name == NULL) || (__fsFd < 0) || + ((len = strnlen(name, 64)) == 64) || + (ownerId == NULL) || (groupId == NULL) || (attr == NULL) || + (ownerAcc == NULL) || (groupAcc == NULL) || (othersAcc == NULL)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32); + if (ctxt == NULL) { + rc = ISFS_ERROR_BUSY; + goto out; + } + + ctxt->args.ga.ownerId = ownerId; + ctxt->args.ga.groupId = groupId; + ctxt->args.ga.attr = attr; + ctxt->args.ga.ownerAcc = ownerAcc; + ctxt->args.ga.groupAcc = groupAcc; + ctxt->args.ga.othersAcc = othersAcc; + ctxt->cb = cb; + ctxt->ctxt = fsCtxt; + ctxt->func = 3; + + ptr = (u8*)ctxt->ioBuf; + memcpy(ptr, name, len + 1); + pathAttrArgs = (ISFSPathAttrArgs*)ROUNDUP(ptr + 64); + + rc = IOS_IoctlAsync(__fsFd, 6, ptr, 64, pathAttrArgs, sizeof(*pathAttrArgs), _isfsFuncCb, ctxt); +out: + return rc; +} + +s32 ISFS_Delete(const u8* name) { + ISFSError rc = ISFS_ERROR_OK; + u32 len; + __isfsCtxt* blCtxt = 0; + + if ((name == NULL) || (__fsFd < 0) || ((len = strnlen(name, 64)) == 64)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32); + if (blCtxt == NULL) { + rc = IOS_ERROR_FAIL_ALLOC; + goto out; + } + + memcpy(blCtxt->ioBuf, name, len + 1); + rc = IOS_Ioctl(__fsFd, 7, blCtxt->ioBuf, 64, NULL, 0); + +out: + if (blCtxt != NULL) { + if (blCtxt != NULL) { + iosFree(hId, blCtxt); + } + } + + return rc; +} + +s32 ISFS_DeleteAsync(const u8* name, ISFSCallback cb, void* fsCtxt) { + ISFSError rc = ISFS_ERROR_OK; + u32 len; + __isfsCtxt* ctxt; + + if ((name == NULL) || (__fsFd < 0) || ((len = strnlen(name, 64)) == 64)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32); + if (ctxt == NULL) { + rc = ISFS_ERROR_BUSY; + goto out; + } + + memcpy(ctxt->ioBuf, name, len + 1); + ctxt->cb = cb; + ctxt->ctxt = fsCtxt; + ctxt->func = 0; + rc = IOS_IoctlAsync(__fsFd, 7, ctxt->ioBuf, 64, NULL, 0, _isfsFuncCb, ctxt); + +out: + return rc; +} + +s32 ISFS_Rename(const u8* oldName, const u8* newName) { + ISFSError rc = ISFS_ERROR_OK; + ISFSPathsArgs* pathsArgs; + u32 oldLen, newLen; + __isfsCtxt* blCtxt = 0; + + if ((oldName == NULL) || (newName == NULL) || (__fsFd < 0) || + ((oldLen = strnlen(oldName, 64)) == 64) || + ((newLen = strnlen(newName, 64)) == 64)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32); + if (blCtxt == NULL) { + rc = IOS_ERROR_FAIL_ALLOC; + goto out; + } + + pathsArgs = (ISFSPathsArgs*)blCtxt->ioBuf; + memcpy(pathsArgs->path1, oldName, oldLen + 1); + memcpy(pathsArgs->path2, newName, newLen + 1); + rc = IOS_Ioctl(__fsFd, 8, pathsArgs, sizeof(*pathsArgs), NULL, 0); + +out: + if (blCtxt != NULL) { + if (blCtxt != NULL) { + iosFree(hId, blCtxt); + } + } + + return rc; +} + +s32 ISFS_RenameAsync(const u8* oldName, const u8* newName, ISFSCallback cb, void* fsCtxt) { + ISFSError rc = ISFS_ERROR_OK; + ISFSPathsArgs* pathsArgs; + u32 oldLen, newLen; + __isfsCtxt* ctxt; + + if ((oldName == NULL) || (newName == NULL) || (__fsFd < 0) || + ((oldLen = strnlen(oldName, 64)) == 64) || + ((newLen = strnlen(newName, 64)) == 64)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32); + if (ctxt == NULL) { + rc = ISFS_ERROR_BUSY; + goto out; + } + + ctxt->cb = cb; + ctxt->ctxt = fsCtxt; + ctxt->func = 0; + + pathsArgs = (ISFSPathsArgs*)ctxt->ioBuf; + memcpy(pathsArgs->path1, oldName, oldLen + 1); + memcpy(pathsArgs->path2, newName, newLen + 1); + rc = IOS_IoctlAsync(__fsFd, 8, pathsArgs, sizeof(*pathsArgs), NULL, 0, _isfsFuncCb, ctxt); + +out: + return rc; +} + +s32 ISFS_GetUsage(const u8* dname, u32* nblocks, u32* ninodes) { + ISFSError rc = ISFS_ERROR_OK; + IOSIoVector* v = 0; + u32 len, *blkPtr, *inodePtr; + char* dnPtr; + __isfsCtxt* blCtxt = 0; + + if ((dname == NULL) || (__fsFd < 0) || + (nblocks == NULL) || (ninodes == NULL) || + ((len = strnlen(dname, 64)) == 64)) { + + rc = ISFS_ERROR_INVALID; + goto out; + } + + blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32); + if (blCtxt == NULL) { + rc = IOS_ERROR_FAIL_ALLOC; + goto out; + } + + v = (IOSIoVector*)blCtxt->ioBuf; + dnPtr = (char*)ROUNDUP((u8*)&v[3]); + memcpy(dnPtr, dname, len + 1); + v[0].base = (u8*)dnPtr; + v[0].length = 64; + + blkPtr = (u32*) ROUNDUP(((u32)dnPtr) + 64); + inodePtr = (u32*) ROUNDUP(((u32)blkPtr) + 4); + v[1].base = (u8*) blkPtr; + v[1].length = 4; + v[2].base = (u8*)inodePtr; + v[2].length = 4; + + rc = IOS_Ioctlv(__fsFd, 12, 1, 2, v); + if (rc != ISFS_ERROR_OK) { + goto out; + } + + *nblocks = *blkPtr; + *ninodes = *inodePtr; + +out: + if (blCtxt != NULL) { + if (blCtxt != NULL) { + iosFree(hId, blCtxt); + } + } + + return rc; +} + +s32 ISFS_CreateFile(const u8* fname, u32 fileAttr, u32 ownerAcc, u32 groupAcc, u32 othersAcc) { + ISFSError rc = ISFS_ERROR_OK; + ISFSPathAttrArgs* pathAttrArgs; + u32 len; + __isfsCtxt* blCtxt = NULL; + + if ((fname == NULL) || (__fsFd < 0) || ((len = strnlen(fname, 64)) == 64)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32); + if (blCtxt == NULL) { + rc = IOS_ERROR_FAIL_ALLOC; + goto out; + } + + pathAttrArgs = (ISFSPathAttrArgs*)blCtxt->ioBuf; + memcpy(pathAttrArgs->path, fname, len + 1); + pathAttrArgs->attr = fileAttr; + pathAttrArgs->ownerAccess = ownerAcc; + pathAttrArgs->groupAccess = groupAcc; + pathAttrArgs->othersAccess = othersAcc; + rc = IOS_Ioctl(__fsFd, 9, pathAttrArgs, sizeof(*pathAttrArgs), NULL, 0); + +out: + if (blCtxt != NULL) { + if (blCtxt != NULL) { + iosFree(hId, blCtxt); + } + } + + return rc; +} + +s32 ISFS_CreateFileAsync(const u8* fname, u32 fileAttr, u32 ownerAcc, u32 groupAcc, u32 othersAcc, ISFSCallback cb, void* fsCtxt) { + ISFSError rc = ISFS_ERROR_OK; + ISFSPathAttrArgs* pathAttrArgs; + u32 len; + __isfsCtxt* ctxt; + + if ((fname == NULL) || (__fsFd < 0) || ((len = strnlen(fname, 64)) == 64)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32); + if (ctxt == NULL) { + rc = ISFS_ERROR_BUSY; + goto out; + } + + ctxt->cb = cb; + ctxt->ctxt = fsCtxt; + ctxt->func = 0; + + pathAttrArgs = (ISFSPathAttrArgs*)ctxt->ioBuf; + memcpy(pathAttrArgs->path, fname, len + 1); + pathAttrArgs->attr = fileAttr; + pathAttrArgs->ownerAccess = ownerAcc; + pathAttrArgs->groupAccess = groupAcc; + pathAttrArgs->othersAccess = othersAcc; + rc = IOS_IoctlAsync(__fsFd, 9, pathAttrArgs, sizeof(*pathAttrArgs), NULL, 0, _isfsFuncCb, ctxt); + +out: + return rc; +} + +IOSFd ISFS_Open(const u8* fname, u32 access) { + ISFSError rc = ISFS_ERROR_OK; + u32 len; + __isfsCtxt* blCtxt = 0; + + if ((fname == NULL) || ((len = strnlen(fname, 64)) == 64)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32); + if (blCtxt == NULL) { + rc = IOS_ERROR_FAIL_ALLOC; + goto out; + } + + memcpy(blCtxt->ioBuf, fname, len + 1); + rc = IOS_Open((const char*)blCtxt->ioBuf, access); + +out: + if (blCtxt != NULL) { + if (blCtxt != NULL) { + iosFree(hId, blCtxt); + } + } + + return rc; +} + +IOSFd ISFS_OpenAsync(const u8* fname, u32 access, ISFSCallback cb, void* fsCtxt) { + ISFSError rc = ISFS_ERROR_OK; + u32 len; + __isfsCtxt* ctxt; + + if ((fname == NULL) || ((len = strnlen(fname, 64)) == 64)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32); + if (ctxt == NULL) { + rc = ISFS_ERROR_BUSY; + goto out; + } + + ctxt->cb = cb; + ctxt->ctxt = fsCtxt; + ctxt->func = 0; + memcpy(ctxt->ioBuf, fname, len + 1); + rc = IOS_OpenAsync((const char*)ctxt->ioBuf, access, _isfsFuncCb, ctxt); + +out: + return rc; +} + +s32 ISFS_GetFileStats(IOSFd fd, ISFSFileStats* stats) { + ISFSError rc = ISFS_ERROR_OK; + __isfsCtxt* blCtxt = 0; + + if ((stats == NULL) || ((u32)stats & 31)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + blCtxt = iosAllocAligned(hId, sizeof(*blCtxt), 32); + if (blCtxt == NULL) { + rc = IOS_ERROR_FAIL_ALLOC; + goto out; + } + + rc = IOS_Ioctl(fd, 11, NULL, 0, blCtxt->ioBuf, sizeof(*stats)); + + if (rc != IOS_ERROR_OK) { + goto out; + } + + memcpy(stats, blCtxt->ioBuf, sizeof(*stats)); + +out: + if (blCtxt != NULL) { + if (blCtxt != NULL) { + iosFree(hId, blCtxt); + } + } + + return rc; +} + +s32 ISFS_GetFileStatsAsync(IOSFd fd, ISFSFileStats* stats, ISFSCallback cb, void* fsCtxt) { + ISFSError rc = ISFS_ERROR_OK; + __isfsCtxt* ctxt; + + if ((stats == NULL) || ((u32)stats & 31)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32); + if (ctxt == NULL) { + rc = ISFS_ERROR_BUSY; + goto out; + } + + ctxt->cb = cb; + ctxt->ctxt = fsCtxt; + ctxt->func = 5; + ctxt->args.fstats = stats; + rc = IOS_IoctlAsync(fd, 11, NULL, 0, ctxt->ioBuf, sizeof(*stats), _isfsFuncCb, ctxt); + +out: + return rc; +} + +s32 ISFS_Seek(IOSFd fd, s32 offset, u32 whence) { + return IOS_Seek(fd, offset, whence); +} + +s32 ISFS_SeekAsync(IOSFd fd, s32 offset, u32 whence, ISFSCallback cb, void* fsCtxt) { + ISFSError rc; + __isfsCtxt* ctxt; + + ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32); + if (ctxt == NULL) { + rc = ISFS_ERROR_BUSY; + goto out; + } + + ctxt->cb = cb; + ctxt->ctxt = fsCtxt; + ctxt->func = 0; + rc = IOS_SeekAsync(fd, offset, whence, _isfsFuncCb, ctxt); + +out: + return rc; +} + +s32 ISFS_Read(s32 fd, u8 *pBuffer, u32 bufSize) { + /* nullptr check and alignment to 0x20 */ + if (pBuffer == NULL || (u32)pBuffer & 31) { + return -101; + } + + return IOS_Read(fd, pBuffer, bufSize); +} + +s32 ISFS_ReadAsync(IOSFd fd, u8* buf, u32 size, ISFSCallback cb, void* fsCtxt) { + ISFSError rc = ISFS_ERROR_OK; + __isfsCtxt* ctxt; + + if ((buf == NULL) || ((u32)buf & 31)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32); + if (ctxt == NULL) { + rc = ISFS_ERROR_BUSY; + goto out; + } + + ctxt->cb = cb; + ctxt->ctxt = fsCtxt; + ctxt->func = 0; + rc = IOS_ReadAsync(fd, buf, size, _isfsFuncCb, ctxt); + +out: + return rc; +} + +s32 ISFS_Write(IOSFd fd, const u8* buf, u32 size) { + ISFSError rc = ISFS_ERROR_OK; + + if ((buf == NULL) || ((u32)buf & 31)) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + rc = IOS_Write(fd, (u8*)buf, size); +out: + return rc; +} + +s32 ISFS_WriteAsync(IOSFd fd, const u8* buf, u32 size, ISFSCallback cb, void* fsCtxt) { + ISFSError rc = 0; + __isfsCtxt* ctxt; + + if ((buf == NULL) || ((u32)buf & (u32)(31))) { + rc = ISFS_ERROR_INVALID; + goto out; + } + + ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32); + if (ctxt == NULL) { + rc = ISFS_ERROR_BUSY; + goto out; + } + + ctxt->cb = cb; + ctxt->ctxt = fsCtxt; + ctxt->func = 0; + rc = IOS_WriteAsync(fd, (void*)buf, size, _isfsFuncCb, ctxt); + +out: + return rc; +} + +s32 ISFS_Close(IOSFd fd) { + return IOS_Close(fd); +} + +s32 ISFS_CloseAsync(IOSFd fd, ISFSCallback cb, void* fsCtxt) { + ISFSError rc; + __isfsCtxt* ctxt; + + ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32); + + if (ctxt == NULL) { + rc = -118; + goto out; + } + + ctxt->cb = cb; + ctxt->ctxt = fsCtxt; + ctxt->func = 0; + rc = IOS_CloseAsync(fd, _isfsFuncCb, ctxt); + +out: + return rc; +} + +s32 ISFS_ShutdownAsync(ISFSCallback cb, void* fsCtxt) { + __isfsCtxt* ctxt; + s32 rc = 0; + + ctxt = iosAllocAligned(hId, sizeof(*ctxt), 32); + + if (__fsFd < 0) { + rc = -101; + goto out; + } + + ctxt->cb = cb; + ctxt->ctxt = fsCtxt; + ctxt->func = 0; + rc = IOS_IoctlAsync(__fsFd, 13, NULL, 0, NULL, 0, _isfsFuncCb, ctxt); + +out: + return rc; +} \ No newline at end of file diff --git a/src/RVL_SDK/gd/GDBase.c b/src/RVL_SDK/gd/GDBase.c new file mode 100644 index 000000000..6b43f5dea --- /dev/null +++ b/src/RVL_SDK/gd/GDBase.c @@ -0,0 +1,30 @@ +#include + +GDLObj* __GDCurrentDL = NULL; +static GDOverflowCallback overflowcb = NULL; + +void GDInitGDLObj(GDLObj* pDL, void* pStart, u32 length) { + pDL->start = pStart; + pDL->ptr = (u8*)pStart; + pDL->top = (u8*)pStart + length; + pDL->length = length; +} + +void GDFlushCurrToMem() { + DCFlushRange(__GDCurrentDL->start, __GDCurrentDL->length); +} + +void GDPadCurr32() { + u32 n = ((u32)__GDCurrentDL->ptr & 31); + if (n) { + for (; n < 32; n++) { + __GDWrite(0); + } + } +} + +void GDOverflowed() { + if (overflowcb) { + (*overflowcb)(); + } +} \ No newline at end of file diff --git a/src/RVL_SDK/gx/GXAttr.c b/src/RVL_SDK/gx/GXAttr.c new file mode 100644 index 000000000..420726825 --- /dev/null +++ b/src/RVL_SDK/gx/GXAttr.c @@ -0,0 +1,91 @@ +#include +#include + +static void __GXXfVtxSpecs(void) { + u32 nCols, nNrm, nTex, reg; + + nNrm = (gx->hasBiNrms) ? 2 : ((gx->hasNrms) ? 1 : 0); + nCols = (u32)__cntlzw((gx->vcdLo & (0x6000 | 0x18000)) >> 13); + nCols = (33 - nCols) >> 1; + + nTex = (u32)__cntlzw((gx->vcdHi & (1 << 16) - 1)); + nTex = (33 - nTex) >> 1; + + reg = (nCols) | (nNrm << 2) | (nTex << 4); + GX_WRITE_XF_REG(0x1008, reg, 0); + gx->bpSentNot = GX_TRUE; +} + +void __GXSetVCD(void) { + GX_WRITE_CP_STRM_REG(5, 0, gx->vcdLo); + GX_WRITE_CP_STRM_REG(6, 0, gx->vcdHi); + __GXXfVtxSpecs(); +} + +void __GXCalculateVLim(void) { + if (gx->vNum > 0) { + static u8 tbl1[4] = { 0, 4, 1, 2 }; + static u8 tbl2[4] = { 0, 8, 1, 2 }; + static u8 tbl3[4] = { 0, 12, 1, 2 }; + GXCompCnt nc; + u32 vlm, b; + u32 vl, vh, va; + + vl = gx->vcdLo; + vh = gx->vcdHi; + va = gx->vatA[GX_VTXFMT0]; + + nc = (GXCompCnt)((va & 0x00000200) >> 9); + + vlm = ((vl >> 0) & 0x1); + vlm += ((vl >> 1) & 0x1); + vlm += ((vl >> 2) & 0x1); + vlm += ((vl >> 3) & 0x1); + vlm += ((vl >> 4) & 0x1); + vlm += ((vl >> 5) & 0x1); + vlm += ((vl >> 6) & 0x1); + vlm += ((vl >> 7) & 0x1); + vlm += ((vl >> 8) & 0x1); + + vlm += tbl3[((vl >> 9) & 0x3)]; + + b = (u32)((nc == GX_NRM_NBT) ? 3 : 1); + vlm += tbl3[((vl >> 11) & 0x3)] * b; + + vlm += tbl1[((vl >> 13) & 0x3)]; + vlm += tbl1[((vl >> 15) & 0x3)]; + + vlm += tbl2[((vh >> (0 * 2)) & 0x3)]; + vlm += tbl2[((vh >> (1 * 2)) & 0x3)]; + vlm += tbl2[((vh >> (2 * 2)) & 0x3)]; + vlm += tbl2[((vh >> (3 * 2)) & 0x3)]; + vlm += tbl2[((vh >> (4 * 2)) & 0x3)]; + vlm += tbl2[((vh >> (5 * 2)) & 0x3)]; + vlm += tbl2[((vh >> (6 * 2)) & 0x3)]; + vlm += tbl2[((vh >> (7 * 2)) & 0x3)]; + + gx->vLim = (u16) vlm; + } +} + +void __GXSetVAT(void) { + s32 i; + u32 dirty; + + dirty = (u32)(gx->dirtyVAT); + i = 0; + + do { + if (dirty & 0x1) { + GX_WRITE_CP_STRM_REG(7, i, gx->vatA[i]); + GX_WRITE_CP_STRM_REG(8, i, gx->vatB[i]); + GX_WRITE_CP_STRM_REG(9, i, gx->vatC[i]); + } + + dirty >>= 1; + ++i; + } while (dirty); + + GX_WRITE_U8(0); + gx->dirtyVAT = 0; +} \ No newline at end of file diff --git a/src/RVL_SDK/gx/GXBump.c b/src/RVL_SDK/gx/GXBump.c new file mode 100644 index 000000000..9b869b757 --- /dev/null +++ b/src/RVL_SDK/gx/GXBump.c @@ -0,0 +1,5 @@ +#include + +void __GXUpdateBPMask(void) { + return; +} \ No newline at end of file diff --git a/src/RVL_SDK/gx/GXFifo.c b/src/RVL_SDK/gx/GXFifo.c new file mode 100644 index 000000000..530a8e4fe --- /dev/null +++ b/src/RVL_SDK/gx/GXFifo.c @@ -0,0 +1,88 @@ +#include +#include +#include + +static __GXFifoObj CPUFifo; +static __GXFifoObj GPFifo; +static GXBool GPFifoReady = FALSE; +static GXBool CPGPLinked; +volatile void* __GXCurrentBP; + +#define TOPHYSICAL(a) (((u32)a) & 0x3FFFFFFF) + +static void __GXFifoLink(GXBool en) { + FAST_FLAG_SET(gx->cpEnable, (en ? 1 : 0), 4, 1); + GX_CP_REG_WRITE_U16(1, (u16)gx->cpEnable); +} + +static void __GXWriteFifoIntEnable(GXBool hi, GXBool lo) { + FAST_FLAG_SET(gx->cpEnable, hi, 2, 1); + FAST_FLAG_SET(gx->cpEnable, lo, 3, 1); + GX_CP_REG_WRITE_U16(1, gx->cpEnable); +} + +static void __GXWriteFifoIntReset(GXBool hiWatermarkClr, GXBool loWatermarkClr) { + FAST_FLAG_SET(gx->cpClr, hiWatermarkClr, 0, 1); + FAST_FLAG_SET(gx->cpClr, loWatermarkClr, 1, 1); + GX_CP_REG_WRITE_U16(2, (u16)gx->cpClr); +} + +static void __GXFifoReadEnable(void) { + FAST_FLAG_SET(gx->cpEnable, 1, 0, 1); + GX_CP_REG_WRITE_U16(1, (u16)gx->cpEnable); +} + +static void __GXFifoReadDisable(void) { + FAST_FLAG_SET(gx->cpEnable, 0, 0, 1); + GX_CP_REG_WRITE_U16(1, (u16)gx->cpEnable); +} + +void __GXCleanGPFifo(void) { + BOOL enabled; + + if (!GPFifoReady) { + return; + } + + enabled = OSDisableInterrupts(); + __GXFifoReadDisable(); + __GXWriteFifoIntEnable(GX_FALSE, GX_FALSE); + + GPFifo.rdPtr = GPFifo.wrPtr; + GPFifo.count = 0; + + GX_CP_REG_WRITE_U16(0x18, GPFifo.count); + GX_CP_REG_WRITE_U16(0x1A, TOPHYSICAL(GPFifo.wrPtr)); + GX_CP_REG_WRITE_U16(0x1C, TOPHYSICAL(GPFifo.rdPtr)); + + GX_CP_REG_WRITE_U16(0x19, GPFifo.count >> 16); + GX_CP_REG_WRITE_U16(0x1B, TOPHYSICAL(GPFifo.wrPtr) >> 16); + GX_CP_REG_WRITE_U16(0x1D, TOPHYSICAL(GPFifo.rdPtr) >> 16); + + PPCSync(); + + if (CPGPLinked) { + u32 reg = 0; + CPUFifo.rdPtr = GPFifo.rdPtr; + CPUFifo.wrPtr = GPFifo.wrPtr; + CPUFifo.count = GPFifo.count; + + FAST_FLAG_SET(reg, (GX_PHY_ADDR(TOPHYSICAL(CPUFifo.wrPtr)) >> 5), 5, 24); + GX_PI_REG_WRITE_U32(0x14, reg); + + __GXWriteFifoIntEnable(GX_TRUE, GX_FALSE); + __GXFifoLink(GX_TRUE); + } + + FAST_FLAG_SET(gx->cpEnable, 0, 1, 1); + FAST_FLAG_SET(gx->cpEnable, 0, 5, 1); + GX_CP_REG_WRITE_U16(1, gx->cpEnable); + __GXCurrentBP = 0; + __GXWriteFifoIntReset(GX_TRUE, GX_TRUE); + __GXFifoReadEnable(); + OSRestoreInterrupts(enabled); +} + +GXBool __GXIsGPFifoReady(void) { + return GPFifoReady; +} \ No newline at end of file diff --git a/src/RVL_SDK/gx/GXGeometry.c b/src/RVL_SDK/gx/GXGeometry.c new file mode 100644 index 000000000..05e3b88b3 --- /dev/null +++ b/src/RVL_SDK/gx/GXGeometry.c @@ -0,0 +1,143 @@ +#include +#include + +inline void __GXSetAmbMat(u32 amState) { + if (amState & 0x100) { + GX_WRITE_XF_REG(0x100A, gx->ambColor[0], 0); + } + + if (amState & 0x200) { + GX_WRITE_XF_REG(0x100B, gx->ambColor[1], 0); + } + + if (amState & 0x400) { + GX_WRITE_XF_REG(0x100C, gx->matColor[0], 0); + } + + if (amState & 0x800) { + GX_WRITE_XF_REG(0x100D, gx->matColor[1], 0); + } +} + +inline void __GXSetLightChan(u32 chState) { + u32 d, i, chIndx = 0x100E; + + if (chState & 0x1000000) { + d = ((gx->genMode & 0x70) >> 4); + GX_WRITE_XF_REG(0x1009, d, 0); + } + + d = (chState & 0xF000) >> 12; + i = 0; + + while (d) { + if (d & 0x1) { + GX_WRITE_XF_REG(chIndx, gx->chanCtrl[i], 0); + } + + i++; + chIndx++; + d >>= 1; + } +} + +inline void __GXSetTexGen(u32 tgState) { + u32 d, i, tgIndx = 0x1040; + u32 dtgIndx = 0x1050; + + if (tgState & 0x2000000) { + d = gx->genMode & 0xF; + GX_WRITE_XF_REG(0x103F, d, 0); + } + + d = (tgState & 0xFF0000) >> 16; + i = 0; + while (d) { + if (d & 0x1) { + GX_WRITE_XF_REG(tgIndx, gx->texGenCtrl[i], 0); + GX_WRITE_XF_REG(dtgIndx, gx->dualTexGenCtrl[i], 0); + } + + dtgIndx++; + tgIndx++; + i++; + d >>= 1; + } +} + +void __GXSetDirtyState() { + u32 dState = gx->dirtyState; + + if (dState & 0x00000001) { + __GXSetSUTexRegs(); + } + + if (dState & 0x00000002) { + __GXUpdateBPMask(); + } + + if (dState & 0x00000004) { + __GXSetGenMode(); + } + + if (dState & 0x00000008) { + __GXSetVCD(); + } + + if (dState & 0x00000010) { + __GXSetVAT(); + } + + if (dState & (0x00000008|0x00000010)) { + __GXCalculateVLim(); + } + + dState &= 0xFFFFFF00; + + if (dState) { + u32 dStateLocal; + + dStateLocal = dState & 0x00000F00; + + if (dStateLocal) { + __GXSetAmbMat(dStateLocal); + } + + dStateLocal = dState & (0x01000000|0x0000F000); + + if (dStateLocal) { + __GXSetLightChan(dStateLocal); + } + + dStateLocal = dState & (0x02000000|0x00FF0000); + + if (dStateLocal) { + __GXSetTexGen(dStateLocal); + } + + dStateLocal = dState & 0x04000000; + if (dStateLocal) { + __GXSetMatrixIndex(GX_VA_PNMTXIDX); + __GXSetMatrixIndex(GX_VA_TEX4MTXIDX); + } + + dStateLocal = dState & 0x10000000; + if (dStateLocal) { + __GXSetViewport(); + } + + dStateLocal = dState & 0x8000000; + if (dStateLocal) { + __GXSetProjection(); + } + + gx->bpSentNot = GX_TRUE; + } + + gx->dirtyState = 0; +} + +void __GXSetGenMode(void) { + GX_WRITE_RA_REG(gx->genMode); + gx->bpSentNot = GX_FALSE; +} \ No newline at end of file diff --git a/src/RVL_SDK/gx/GXInit.c b/src/RVL_SDK/gx/GXInit.c new file mode 100644 index 000000000..74149f6a7 --- /dev/null +++ b/src/RVL_SDK/gx/GXInit.c @@ -0,0 +1,49 @@ +#include +#include + +static GXData gxData; +GXData *const __GXData = &gxData; + +volatile void*__piReg = NULL; +volatile void*__cpReg = NULL; +volatile void*__peReg = NULL; +volatile void*__memReg = NULL; + +void push_fmt(u32 vtxfmt) { + FAST_FLAG_SET(gx->vatB[vtxfmt], 1, 31, 1); + GX_WRITE_CP_STRM_REG(8, (s32)vtxfmt, gx->vatB[vtxfmt]); +} + +void __GXInitRevisionBits(void) { + u32 i; + + for (i = 0; i < GX_MAX_VTXFMT; i++) { + FAST_FLAG_SET(gx->vatA[i], 1, 30, 1); + push_fmt(i); + } + + { + u32 reg1 = 0; + u32 reg2 = 0; + + FAST_FLAG_SET(reg1, 1, 0, 1); + FAST_FLAG_SET(reg1, 1, 1, 1); + FAST_FLAG_SET(reg1, 1, 2, 1); + FAST_FLAG_SET(reg1, 1, 3, 1); + FAST_FLAG_SET(reg1, 1, 4, 1); + FAST_FLAG_SET(reg1, 1, 5, 1); + GX_WRITE_XF_REG(0x1000, reg1, 0); + FAST_FLAG_SET(reg2, 1, 0, 1); + GX_WRITE_XF_REG(0x1012, reg2, 0); + } + + { + u32 reg = 0; + FAST_FLAG_SET(reg, 1, 0, 1); + FAST_FLAG_SET(reg, 1, 1, 1); + FAST_FLAG_SET(reg, 1, 2, 1); + FAST_FLAG_SET(reg, 1, 3, 1); + FAST_FLAG_SET(reg, 0x58, 24, 8); + GX_WRITE_RA_REG(reg); + } +} \ No newline at end of file diff --git a/src/RVL_SDK/gx/GXMisc.c b/src/RVL_SDK/gx/GXMisc.c new file mode 100644 index 000000000..06c48a2fb --- /dev/null +++ b/src/RVL_SDK/gx/GXMisc.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include + +void GXFlush(void) { + if (gx->dirtyState) { + __GXSetDirtyState(); + } + + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + GX_WRITE_U32(0); + PPCSync(); +} + +static void __GXAbortWait(u32 clocks) { + OSTime time0, time1; + time0 = OSGetTime(); + + do { + time1 = OSGetTime(); + } + while (time1 - time0 <= clocks / 4); +} + +static void __GXAbortWaitPECopyDone(void) { + u32 peCnt0, peCnt1; + + peCnt0 = GX_MEM_COUNTER_READ_U32(MEM_PE_REQCOUNT); + do { + peCnt1 = peCnt0; + __GXAbortWait(32); + + peCnt0 = GX_MEM_COUNTER_READ_U32(MEM_PE_REQCOUNT); + } while ( peCnt0 != peCnt1 ); +} + +void __GXAbort(void) { + if (gx->abtWaitPECopy && __GXIsGPFifoReady()) { + __GXAbortWaitPECopyDone(); + } + + __PIRegs[0x18/4] = 1; + __GXAbortWait(200); + __PIRegs[0x18/4] = 0; + __GXAbortWait(20); +} + +void GXAbortFrame(void) { + __GXAbort(); + + if (__GXIsGPFifoReady()) { + __GXCleanGPFifo(); + __GXInitRevisionBits(); + gx->dirtyState = 0; + GXFlush(); + } +} \ No newline at end of file diff --git a/src/RVL_SDK/gx/GXPixel.c b/src/RVL_SDK/gx/GXPixel.c new file mode 100644 index 000000000..94770a387 --- /dev/null +++ b/src/RVL_SDK/gx/GXPixel.c @@ -0,0 +1,154 @@ +#include +#include +#include + +// GXSetFog + +void GXSetFogRangeAdj(GXBool enable, u16 c, const GXFogAdjTable *pTable) { + u32 i; + u32 v0, v1; + + if (enable) { + /* this loop is unrolled */ + for (i = 0; i < 0xA; i += 2) { + v0 = 0; + SET_FLAG(v0, pTable->r[i], 0, 12); + SET_FLAG(v0, pTable->r[i + 1], 12, 12); + SET_FLAG(v0, 0xE9 + (i / 2), 24, 8); + GX_WRITE_REG(v0); + } + } + + v1 = 0; + SET_FLAG(v1, c + 0x156, 0, 10); + SET_FLAG(v1, enable, 10, 1); + SET_FLAG(v1, 0xE8, 24, 8); + GX_WRITE_REG(v1); + gx->bpSentNot = GX_FALSE; +} + +void GXSetBlendMode(GXBlendMode mode, GXBlendFactor src_factor, GXBlendFactor dest_factor, GXLogicOp operation) { + u32 reg; + u32 blend; + + reg = gx->cmode0; + blend = (u32)(mode & 1); + SET_FLAG(reg, (mode == 3), 11, 1); + SET_FLAG(reg, blend, 0, 1); + SET_FLAG(reg, mode == 2, 1, 1); + SET_FLAG(reg, operation, 12, 4); + SET_FLAG(reg, src_factor, 8, 3); + SET_FLAG(reg, dest_factor, 5, 3); + GX_WRITE_REG(reg); + gx->cmode0 = reg; + gx->bpSentNot = GX_FALSE; +} + +void GXSetColorUpdate(GXBool update) { + u32 reg; + + reg = gx->cmode0; + SET_FLAG(reg, update, 3, 1); + GX_WRITE_REG(reg); + gx->cmode0 = reg; + gx->bpSentNot = GX_FALSE; +} + +void GXSetAlphaUpdate(GXBool update) { + u32 reg; + + reg = gx->cmode0; + SET_FLAG(reg, update, 4, 1); + GX_WRITE_REG(reg); + gx->cmode0 = reg; + gx->bpSentNot = GX_FALSE; +} + +void GXSetZMode(GXBool compare, GXCompare func, GXBool update) { + u32 reg; + + reg = gx->zmode; + SET_FLAG(reg, compare, 0, 1); + SET_FLAG(reg, func, 1, 3); + SET_FLAG(reg, update, 4, 1); + GX_WRITE_REG(reg); + gx->zmode = reg; + gx->bpSentNot = GX_FALSE; +} + +void GXSetZCompLoc(GXBool before) { + SET_FLAG(gx->peCtrl, before, 6, 1); + GX_WRITE_REG(gx->peCtrl); + gx->bpSentNot = GX_FALSE; +} + +void GXSetPixelFmt(GXPixelFmt format, GXZFmt16 z_format) { + u32 ctrl; + GXBool aa; + + static u32 p2f[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + + ctrl = gx->peCtrl; + SET_FLAG(gx->peCtrl, p2f[format], 0, 3); + SET_FLAG(gx->peCtrl, z_format, 3, 3); + + if (ctrl != gx->peCtrl) { + GX_WRITE_REG(gx->peCtrl); + + aa = ((format == 2) ? GX_TRUE : GX_FALSE); + SET_FLAG(gx->genMode, aa, 9, 1); + gx->dirtyState |= 4; + } + + if (p2f[format] == 4) { + SET_FLAG(gx->cmode1, (format - 4) & 3, 9, 2); + SET_FLAG(gx->cmode1, 0x42, 24, 8); + GX_WRITE_REG(gx->cmode1); + } + + gx->bpSentNot = GX_FALSE; +} + +void GXSetDither(GXBool dither) { + u32 reg; + + reg = gx->cmode0; + SET_FLAG(reg, dither, 2, 1); + GX_WRITE_REG(reg); + gx->cmode0 = reg; + gx->bpSentNot = GX_FALSE; +} + +void GXSetDstAlpha(GXBool enable, u8 alpha) { + u32 reg; + + reg = gx->cmode1; + SET_FLAG(reg, alpha, 0, 8); + SET_FLAG(reg, enable, 8, 1); + GX_WRITE_REG(reg); + gx->cmode1 = reg; + gx->bpSentNot = GX_FALSE; +} + +void GXSetFieldMask(GXBool odd, GXBool even) { + u32 reg; + + reg = 0; + SET_FLAG(reg, even, 0, 1); + SET_FLAG(reg, odd, 1, 1); + SET_FLAG(reg, 0x44, 24, 8); + GX_WRITE_REG(reg); + gx->bpSentNot = GX_FALSE; +} + +void GXSetFieldMode(GXBool mode, GXBool ratio) { + u32 reg; + + SET_FLAG(gx->lpSize, ratio, 22, 1); + GX_WRITE_REG(gx->lpSize); + + __GXFlushTextureState(); + reg = mode | 0x68000000; + GX_WRITE_REG(reg); + __GXFlushTextureState(); +} \ No newline at end of file diff --git a/src/RVL_SDK/gx/GXTexture.c b/src/RVL_SDK/gx/GXTexture.c new file mode 100644 index 000000000..774be3075 --- /dev/null +++ b/src/RVL_SDK/gx/GXTexture.c @@ -0,0 +1,75 @@ +#include +#include + +void __SetSURegs(u32 tmap, u32 tcoord) NO_INLINE { + u32 w, h; + GXBool s_bias, t_bias; + + w = ((gx->tImage0[tmap] & 0x3FF)); + h = ((gx->tImage0[tmap] & 0xFFC00) >> 10); + FAST_FLAG_SET(gx->suTs0[tcoord], w, 0, 16); + FAST_FLAG_SET(gx->suTs1[tcoord], h, 0, 16); + + s_bias = ((gx->tMode0[tmap] & 0x3)) == GX_REPEAT; + t_bias = ((gx->tMode0[tmap] & 0xC) >> 2) == GX_REPEAT; + FAST_FLAG_SET(gx->suTs0[tcoord], s_bias, 16, 1); + FAST_FLAG_SET(gx->suTs1[tcoord], t_bias, 16, 1); + + GX_WRITE_RA_REG(gx->suTs0[tcoord]); + GX_WRITE_RA_REG(gx->suTs1[tcoord]); + gx->bpSentNot = GX_FALSE; +} + +void __GXSetSUTexRegs(void) { + u32 nStages, nIndStages, i, map, tmap, coord; + u32* ptref; + + if (gx->tcsManEnab == 0xFF) { + return; + } + + nStages = ((gx->genMode & 0x3C00) >> 10) + 1; + nIndStages = ((gx->genMode & 0x70000) >> 16); + + for (i = 0; i < nIndStages; i++) { + switch (i + GX_INDTEXSTAGE0) { + case GX_INDTEXSTAGE0: + tmap = (gx->iref) & 0x7; + coord = ((gx->iref & 0x38) >> 3); + break; + case GX_INDTEXSTAGE1: + tmap = ((gx->iref & 0x1C0) >> 6); + coord = ((gx->iref & 0xE00) >> 9); + break; + case GX_INDTEXSTAGE2: + tmap = ((gx->iref & 0x7000) >> 12); + coord = ((gx->iref & 0x38000) >> 15); + break; + case GX_INDTEXSTAGE3: + tmap = ((gx->iref & 0x1C0000) >> 18); + coord = ((gx->iref & 0xE00000) >> 21); + break; + } + + if (!(gx->tcsManEnab & (1 << coord))) { + __SetSURegs(tmap, coord); + } + } + + for (i = 0; i < nStages; i++) { + ptref = &gx->tref[i / 2]; + map = gx->texmapId[i]; + tmap = map & ~256; + + if (i & 1) { + coord = ((*ptref & 0x38000) >> 15); + } + else { + coord = ((*ptref & 0x38) >> 3); + } + + if ((tmap != GX_TEXMAP_NULL) && !(gx->tcsManEnab & (1 << coord)) && (gx->tevTcEnab & (1 << i))) { + __SetSURegs(tmap, coord); + } + } +} \ No newline at end of file diff --git a/src/RVL_SDK/gx/GXTransform.c b/src/RVL_SDK/gx/GXTransform.c new file mode 100644 index 000000000..a6642edd0 --- /dev/null +++ b/src/RVL_SDK/gx/GXTransform.c @@ -0,0 +1,84 @@ +#include +#include +#include + +static void WriteProjPS(const register f32 proj[6], register volatile void* dest) + { + register f32 p01, p23, p45; + + asm { + psq_l p01, 0(proj), 0, 0 + psq_l p23, 8(proj), 0, 0 + psq_l p45, 16(proj), 0, 0 + psq_st p01, 0(dest), 0, 0 + psq_st p23, 0(dest), 0, 0 + psq_st p45, 0(dest), 0, 0 + } +} + +void __GXSetProjection(void) { + u32 reg = CP_XF_LOADREGS(0x1020, 6); + GX_WRITE_U8(CP_OPCODE(0, 2)); + GX_WRITE_U32(reg); + WriteProjPS(gx->projMtx, (volatile void*)0xCC008000); + GX_WRITE_XF_MEM_U32(0x1026, gx->projType); +} + +void __GXSetViewport(void) { + f32 sx, sy, sz, ox, oy, oz, zmin, zmax; + u32 reg; + + sx = gx->vpWd / 2.0f; + sy = - gx->vpHt / 2.0f; + ox = gx->vpLeft + (gx->vpWd / 2.0f) + 342.0f; + oy = gx->vpTop + (gx->vpHt / 2.0f) + 342.0f; + + zmin = gx->vpNearz * gx->zScale; + zmax = gx->vpFarz * gx->zScale; + + sz = (zmax - zmin); + oz = zmax + gx->zOffset; + + reg = CP_XF_LOADREGS(0x101A, 5); + + GX_WRITE_U8(CP_OPCODE(0, 2)); + GX_WRITE_U32(reg); + GX_WRITE_XF_MEM_F32(XF_SCALEX + 0, sx); + GX_WRITE_XF_MEM_F32(XF_SCALEX + 1, sy); + GX_WRITE_XF_MEM_F32(XF_SCALEX + 2, sz); + GX_WRITE_XF_MEM_F32(XF_SCALEX + 3, ox); + GX_WRITE_XF_MEM_F32(XF_SCALEX + 4, oy); + GX_WRITE_XF_MEM_F32(XF_SCALEX + 5, oz); +} + +void GXSetScissor(u32 left, u32 top, u32 width, u32 height) { + u32 _top, _left, bottom, right; + + _top = top + (u32)342.0f; + _left = left + (u32)342.0f; + bottom = _top + height - 1; + right = _left + width - 1; + + SET_FLAG(gx->suScis0, _top, 0, 11); + SET_FLAG(gx->suScis0, _left, 12, 11); + + SET_FLAG(gx->suScis1, bottom, 0, 11); + SET_FLAG(gx->suScis1, right, 12, 11); + + GX_WRITE_REG(gx->suScis0); + GX_WRITE_REG(gx->suScis1); + gx->bpSentNot = GX_FALSE; +} + +void __GXSetMatrixIndex(GXAttr matIdxAttr) { + if (matIdxAttr < GX_VA_TEX4MTXIDX) { + GX_WRITE_CP_STRM_REG(3, 0, gx->matIdxA); + GX_WRITE_XF_REG(0x1018, gx->matIdxA, 0); + } + else { + GX_WRITE_CP_STRM_REG(4, 0, gx->matIdxB); + GX_WRITE_XF_REG(0x1019, gx->matIdxB, 0); + } + + gx->bpSentNot = GX_TRUE; +} \ No newline at end of file diff --git a/src/RVL_SDK/ipc/ipcMain.c b/src/RVL_SDK/ipc/ipcMain.c new file mode 100644 index 000000000..2c79c4015 --- /dev/null +++ b/src/RVL_SDK/ipc/ipcMain.c @@ -0,0 +1,50 @@ +#include "revolution/ipc.h" +#include "revolution/os/OSIpc.h" +#include "private/flipper.h" + +static void* IPCBufferHi; +static void* IPCBufferLo; + +static void* IPCCurrentBufferHi; +static void* IPCCurrentBufferLo; + +static u8 Initialized; + +void IPCInit(void) { + if (Initialized) { + return; + } + + IPCBufferHi = __OSGetIPCBufferHi(); + IPCBufferLo = __OSGetIPCBufferLo(); + IPCCurrentBufferHi = IPCBufferHi; + IPCCurrentBufferLo = IPCBufferLo; + + Initialized = TRUE; +} + +void IPCReInit(void) { + Initialized = FALSE; + IPCInit(); +} + +u32 IPCReadReg(u32 regIdx) { + u32 reg = __IPCRegs[regIdx]; + return reg; +} + +void IPCWriteReg(u32 regIdx, u32 data) { + __IPCRegs[regIdx] = data; +} + +void* IPCGetBufferHi(void) { + return IPCCurrentBufferHi; +} + +void* IPCGetBufferLo(void) { + return IPCCurrentBufferLo; +} + +void IPCSetBufferLo(void* lo) { + IPCCurrentBufferLo = lo; +} \ No newline at end of file diff --git a/src/RVL_SDK/ipc/ipcProfile.c b/src/RVL_SDK/ipc/ipcProfile.c new file mode 100644 index 000000000..8a85429f7 --- /dev/null +++ b/src/RVL_SDK/ipc/ipcProfile.c @@ -0,0 +1,60 @@ +#include + +static u32 IpcNumPendingReqs = 0; +static u32 IpcNumUnIssuedReqs = 0; +static s32 IpcFdArray[32]; +static u32 IpcReqPtrArray[32]; + +static void AddReqInfo(void *, s32); +static void DelReqInfo(void *, s32); + +void IPCiProfInit(void) { + u32 i; + + IpcNumPendingReqs = 0; + IpcNumUnIssuedReqs = 0; + + for (i = 0; i < 32; ++i) { + IpcReqPtrArray[i] = 0; + IpcFdArray[i] = -1; + } +} + +void IPCiProfQueueReq(void *req, s32 fd) { + ++IpcNumPendingReqs; + ++IpcNumUnIssuedReqs; + AddReqInfo(req, fd); +} + +static void AddReqInfo(void* ptr, s32 fd) { + u32 i; + + for (i = 0; i < 32; ++i) { + if (IpcReqPtrArray[i] == 0 && IpcFdArray[i] == -1) { + IpcReqPtrArray[i] = (u32)ptr; + IpcFdArray[i] = fd; + break; + } + } +} + +void IPCiProfAck(void) { + --IpcNumUnIssuedReqs; +} + +void IPCiProfReply(void* req, s32 fd) { + --IpcNumPendingReqs; + DelReqInfo(req, fd); +} + +static void DelReqInfo(void* ptr, s32 fd) { + u32 i; + + for (i = 0; i < 32; ++i) { + if (IpcReqPtrArray[i] == (u32)ptr && IpcFdArray[i] == fd) { + IpcReqPtrArray[i] = 0; + IpcFdArray[i] = -1; + break; + } + } +} \ No newline at end of file diff --git a/src/RVL_SDK/ipc/ipcclt.c b/src/RVL_SDK/ipc/ipcclt.c new file mode 100644 index 000000000..bb92d7365 --- /dev/null +++ b/src/RVL_SDK/ipc/ipcclt.c @@ -0,0 +1,851 @@ +#include "private/flipper.h" +#include "private/iostypes.h" +#include "private/iosrestypes.h" +#include "private/iosresclt.h" +#include "revolution/os.h" +#include "revolution/ipc.h" +#include + +/* a few of these functions were grabbed from debug builds, because many of these are inlined into functions and they are complex */ + +/* macro for matching __ipcQueueRequest */ +#define diff(a, b) \ + ((a) < (b)) ? ((u32)0xffffffff - (b) + (a) + 1) : ((a) - (b)) + +static s32 __mailboxAck = 1; +static u32 __relnchFl = 0; + +#define OSVirtualToPhysical(addr) OSCachedToPhysical(addr) +#define OSPhysicalToVirtual(addr) OSPhysicalToCached(addr) + +typedef struct IOSRpcRequest { + IOSResourceRequest request; + IOSIpcCb cb __attribute__((aligned(32))); // I am assuming this is aligned due to where cbArg is stored, and I see nothing between cb and callback_arg? + void* callback_arg; + u32 relaunch_flag; + OSThreadQueue thread_queue; +} IOSRpcRequest; + +static IOSRpcRequest *__relnchRpc = 0; +static IOSRpcRequest *__relnchRpcSave = 0; + +#define ROUNDUP(sz) (((u32)(sz) + 31) & \ + ~(u32)(31)) + +static u8 __rpcBuf[ROUNDUP(sizeof(IOSRpcRequest))] __attribute__ ((aligned(32))); + +static struct { + u32 rcount; + u32 wcount; + u32 rptr; + u32 wptr; + IOSResourceRequest *buf[16]; +} __responses; + +static IOSHeapId hid = -1; + +extern void IPCiProfQueueReq(void *, s32); + +/* the MSL_C version of strnlen doesn't match when inlined, cool */ +u32 strnlen(const u8 *str, u32 n) { + const u8 *s = str; + while (*s && n-- > 0) + ++s; + return (s - str); +} + +static inline IOSError ipcFree(IOSRpcRequest *rpc) { + IOSError ret = 0; + iosFree(hid, rpc); + return ret; +} + +static inline void __ipcSendRequest(void) { + IOSRpcRequest *rpc; + + if (diff(__responses.wcount, __responses.rcount) <= 0) { + return; + } + + rpc = (IOSRpcRequest*)__responses.buf[__responses.rptr]; + + if (rpc == 0) { + return; + } + + if (rpc->relaunch_flag) { + __mailboxAck--; + } + + IPCWriteReg(0, OSVirtualToPhysical(rpc)); + __responses.rptr = (__responses.rptr + 1) % (sizeof(__responses.buf) / sizeof(__responses.buf[0])); + __responses.rcount++; + __mailboxAck--; + + IPCWriteReg(1, (IPCReadReg(1) & (1 << 5 | 1 << 4)) | 1 << 0); +} + +void IpcReplyHandler(__OSInterrupt interrupt, OSContext* context) { + OSContext exceptionContext; + IOSResourceRequest* req; + IOSRpcRequest* rep; + u32 addr; + + addr = IPCReadReg(2); + + if (!addr) { + goto err; + } + + rep = (IOSRpcRequest*)OSPhysicalToVirtual(addr); + IPCWriteReg(1, (IPCReadReg(1) & (1 << 5 | 1 << 4) | 1 << 2)); + ACRWriteReg(0x30, 0x40000000); + req = &rep->request; + + DCInvalidateRange(req, sizeof(*req)); + + switch (req->handle) { + case 3: + req->args.read.outPtr = (req->args.read.outPtr) ? OSPhysicalToVirtual((u32)req->args.read.outPtr) : 0; + + if (req->status > 0) { + DCInvalidateRange(req->args.read.outPtr, (u32)req->status); + } + + break; + + case 6: + req->args.ioctl.outPtr = (req->args.ioctl.outPtr) ? OSPhysicalToVirtual((u32)req->args.ioctl.outPtr) : 0; + DCInvalidateRange(req->args.ioctl.inPtr, req->args.ioctl.inLen); + DCInvalidateRange(req->args.ioctl.outPtr, req->args.ioctl.outLen); + break; + + case 7: + { + int i; + IOSResourceIoctlv* v = &req->args.ioctlv; + req->args.ioctlv.vector = (req->args.ioctlv.vector) ? (IOSIoVector*)OSPhysicalToVirtual((u32)req->args.ioctlv.vector) : 0; + DCInvalidateRange(&v->vector[0], (req->args.ioctlv.readCount + req->args.ioctlv.writeCount) * sizeof(IOSIoVector)); + + for (i = 0; i < (req->args.ioctlv.readCount + req->args.ioctlv.writeCount); ++i) { + v->vector[i].base = (v->vector[i].base) ? (u8*)OSPhysicalToVirtual((u32)v->vector[i].base) : 0; + DCInvalidateRange(v->vector[i].base, v->vector[i].length); + } + + if (__relnchFl && __relnchRpcSave == rep) { + __relnchFl = 0; + + if (__mailboxAck < 1) { + __mailboxAck++; + } + } + + break; + } + + default: + break; + } + + if (rep->cb) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + rep->cb(req->status, (void*)rep->callback_arg); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + ipcFree(rep); + } + else { + OSWakeupThread(&rep->thread_queue); + } + + IPCWriteReg(1, (IPCReadReg(1) & (1 << 5 | 1 << 4)) | 1 << 3); + IPCiProfReply(req, (s32)req->handle); + +err: + return; +} + +void IpcAckHandler(__OSInterrupt interrupt, OSContext* context) { + IPCWriteReg(1, (IPCReadReg(1) & (1 << 5 | 1 << 4)) | 1 << 1); + ACRWriteReg(0x30, 0x40000000); + + if (__mailboxAck < 1) { + __mailboxAck++; + IPCiProfAck(); + } + + if (__mailboxAck > 0) { + if (__relnchFl) { + IOSResourceRequest* req = &__relnchRpc->request; + req->status = 0; + __relnchFl = 0; + + OSWakeupThread(&__relnchRpc->thread_queue); + IPCWriteReg(1, (IPCReadReg(1) & (1 << 5 | 1 << 4)) | 1 << 3); + } + + __ipcSendRequest(); + } +} + + +void IPCInterruptHandler(__OSInterrupt interrupt, OSContext* context) { + if ((IPCReadReg(1) & (1 << 4 | 1 << 2)) == (1 << 4 | 1 << 2)) { + IpcReplyHandler(interrupt, context); + } + + if ((IPCReadReg(1) + & (1 << 5 | 1 << 1)) + == (1 << 5 | 1 << 1)) + { + IpcAckHandler(interrupt, context); + } +} + +IOSError IPCCltInit(void) { + static u32 initialized = 0; + u32 i; + IOSError ret = 0; + void* bufferLo; + + if (initialized) { + goto out; + } + + initialized = 1; + + IPCInit(); + + i = ROUNDUP(32 * (ROUNDUP(sizeof(IOSRpcRequest)) + 64)); + bufferLo = IPCGetBufferLo(); + + if ((void*)((u8*)bufferLo + i) > IPCGetBufferHi()) { + ret = -22; + goto out; + } + + hid = iosCreateHeap(bufferLo, i); + IPCSetBufferLo((void*)((u8*)bufferLo + i)); + + __OSSetInterruptHandler(27, IPCInterruptHandler); + __OSUnmaskInterrupts(16); + + IPCWriteReg(1, (1 << 5 | 1<< 4 | 1 << 3)); + IPCiProfInit(); + +out: + return ret; +} + +IOSError IPCCltReInit(void) { + u32 i; + IOSError ret = 0; + void* bufferLo; + + i = ROUNDUP(32 * ROUNDUP(sizeof(IOSRpcRequest))); + bufferLo = IPCGetBufferLo(); + + if ((void*)((u8*)bufferLo + i) > IPCGetBufferHi()) { + ret = -22; + goto out; + } + + hid = iosCreateHeap(bufferLo, i); + IPCSetBufferLo((void*)((u8*)bufferLo + i)); + +out: + return ret; +} + +/* this call seems to be inlined */ +static inline IOSRpcRequest* ipcAllocReq(void ){ + IOSRpcRequest* req = NULL; + req = iosAllocAligned(hid, 0x40, 0x20); + return req; +} + +static inline IOSError __ipcQueueRequest(IOSResourceRequest *req) { + IOSError ret = 0; + + if (diff(__responses.wcount, __responses.rcount) >= sizeof(__responses.buf) / sizeof(__responses.buf[0])) { + ret = -8; + } + else { + __responses.buf[__responses.wptr] = req; + __responses.wptr = (__responses.wptr + 1) % (sizeof(__responses.buf) / sizeof(__responses.buf[0])); + __responses.wcount++; + IPCiProfQueueReq(req, (s32)req->handle); + } + + return ret; +} + +static inline IOSError __ios_Open(IOSRpcRequest *rpc, const char *path, u32 flags) { + IOSError ret = 0; + IOSResourceRequest* req; + + if (!rpc) { + ret = -4; + goto error; + } + + req = &rpc->request; + /* regswap with the strnlen call... */ + DCFlushRange((void*)path, strnlen((const u8*)path, 64) + 1); + req->args.open.path = (u8*)OSVirtualToPhysical(path); + req->args.open.flags = flags; + +error: + return ret; +} + +// the existance of Ipc2 implies the existance of Ipc1, which has a common pattern +// so this code is what I am assuming is a part of Ipc1 +static inline IOSError __ios_Ipc1(IOSFd fd, u32 cmd, IOSIpcCb cb, void *cbArg, IOSRpcRequest **rpc) { + IOSError ret = 0; + IOSResourceRequest *req; + + if (rpc == 0) { + ret = -4; + goto error; + } + + *rpc = (IOSRpcRequest*)ipcAllocReq(); + + if (*rpc == 0) { + ret = -22; + goto error; + } + + req = &(*rpc)->request; + (*rpc)->cb = cb; + (*rpc)->callback_arg = cbArg; + (*rpc)->relaunch_flag = 0; + req->cmd = cmd; + req->handle = (u32)fd; + +error: + return ret; +} + +// this one, however, is not inlined +static IOSError __ios_Ipc2(IOSRpcRequest *rpc, IOSIpcCb cb) { + IOSError ret = 0; + u32 inten; + IOSResourceRequest *req; + + if (rpc == NULL) { + ret = -4; + } + else { + req = &rpc->request; + + if (!cb) { + OSInitThreadQueue(&rpc->thread_queue); + } + + DCFlushRange(req, sizeof(*req)); + inten = OSDisableInterrupts(); + ret = __ipcQueueRequest(req); + + if (ret != 0) { + OSRestoreInterrupts(inten); + + if (cb) { + ipcFree(rpc); + } + } + else { + if (__mailboxAck > 0) { + __ipcSendRequest(); + } + + if (!cb) { + OSSleepThread(&rpc->thread_queue); + } + + OSRestoreInterrupts(inten); + + if (!cb) { + ret = req->status; + } + } + } + + if (rpc && !cb) { + ipcFree(rpc); + } + + return ret; +} + +IOSError IOS_OpenAsync(const char *pPath, u32 flags, IOSIpcCb cb, void *callback_arg) { + IOSRpcRequest* rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(0, 1, cb, callback_arg, &rpc); + + if (ret != 0) { + goto error; + } + + ret = __ios_Open(rpc, pPath, flags); + + if (ret != 0) { + goto error; + } + + ret = __ios_Ipc2(rpc, cb); +error: + return ret; +} + +IOSError IOS_Open(const char *path, u32 flags) { + IOSRpcRequest *rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(0, 1, 0, 0, &rpc); + + if (ret != 0) { + goto error; + } + + ret = __ios_Open(rpc, path, flags); + + if (ret != 0) { + goto error; + } + + ret = __ios_Ipc2(rpc, 0); + +error: + return ret; +} + +IOSError IOS_CloseAsync(IOSFd fd, IOSIpcCb cb, void* cbArg) { + IOSRpcRequest* rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(fd, 2, cb, cbArg, &rpc); + + if (ret == 0) { + ret = __ios_Ipc2(rpc, cb); + } + + return ret; +} + +IOSError IOS_Close(IOSFd fd) { + IOSRpcRequest* rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(fd, 2, 0, 0, &rpc); + + if (ret == 0) { + ret = __ios_Ipc2(rpc, 0); + } + + return ret; +} + +static IOSError __ios_Read(IOSRpcRequest* rpc, void* buf, u32 len) { + IOSError ret = 0; + IOSResourceRequest* req; + + if (!rpc) { + ret = -4; + goto error; + } + + req = &rpc->request; + + DCInvalidateRange(buf, len); + req->args.read.outPtr = (buf) ? (u8*)OSVirtualToPhysical(buf) : 0; + req->args.read.outLen = len; + +error: + return ret; +} + +IOSError IOS_ReadAsync(IOSFd fd, void* buf, u32 len, IOSIpcCb cb, void* cbArg) { + IOSRpcRequest* rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(fd, 3, cb, cbArg, &rpc); + + if (ret != 0) { + goto error; + } + + ret = __ios_Read(rpc, buf, len); + + if (ret != 0) { + goto error; + } + + ret = __ios_Ipc2(rpc, cb); + +error: + return ret; +} + +IOSError IOS_Read(IOSFd fd, void* buf, u32 len) { + IOSRpcRequest* rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(fd, 3, 0, 0, &rpc); + + if (ret != 0) { + goto error; + } + + ret = __ios_Read(rpc, buf, len); + + if (ret != 0) { + goto error; + } + + ret = __ios_Ipc2(rpc, 0); + +error: + return ret; +} + +static IOSError __ios_Write(IOSRpcRequest* rpc, void* buf, u32 len) { + IOSError ret = 0; + IOSResourceRequest* req; + + if (!rpc) { + ret = -4; + goto error; + } + + req = &rpc->request; + req->args.write.inPtr = (buf) ? (u8*)OSVirtualToPhysical(buf) : 0; + req->args.write.inLen = len; + DCFlushRange(buf, len); + +error: + return ret; +} + +IOSError IOS_WriteAsync(IOSFd fd, void* buf, u32 len, IOSIpcCb cb, void* cbArg) { + IOSRpcRequest* rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(fd, 4, cb, cbArg, &rpc); + + if (ret != 0) { + goto error; + } + + ret = __ios_Write(rpc, buf, len); + + if (ret != 0) { + goto error; + } + + ret = __ios_Ipc2(rpc, cb); + +error: + return ret; +} + +IOSError IOS_Write(IOSFd fd, void* buf, u32 len) { + IOSRpcRequest* rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(fd, 4, 0, 0, &rpc); + + if (ret != 0) { + goto error; + } + + ret = __ios_Write(rpc, buf, len); + + if (ret != 0) { + goto error; + } + + ret = __ios_Ipc2(rpc, 0); + +error: + return ret; +} + +static IOSError __ios_Seek(IOSRpcRequest* rpc, s32 offset, u32 whence) { + IOSError ret = 0; + IOSResourceRequest* req; + + if (!rpc) { + ret = -4; + goto error; + } + + req = &rpc->request; + req->args.seek.offset = offset; + req->args.seek.whence = whence; + +error: + return ret; +} + +IOSError IOS_SeekAsync(IOSFd fd, s32 offset, u32 whence, IOSIpcCb cb, void* cbArg) { + IOSRpcRequest* rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(fd, 5, cb, cbArg, &rpc); + + if (ret != 0) { + goto error; + } + + ret = __ios_Seek(rpc, offset, whence); + + if (ret != 0) { + goto error; + } + + ret = __ios_Ipc2(rpc, cb); + +error: + return ret; +} + +IOSError IOS_Seek(IOSFd fd, s32 offset, u32 whence) { + IOSRpcRequest* rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(fd, 5, 0, 0, &rpc); + + if (ret != 0) { + goto error; + } + + ret = __ios_Seek(rpc, offset, whence); + + if (ret != 0) { + goto error; + } + + ret = __ios_Ipc2(rpc, 0); + +error: + return ret; +} + +static IOSError __ios_Ioctl(IOSRpcRequest* rpc, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen) { + IOSError ret = 0; + IOSResourceRequest* req; + + if (!rpc) { + ret = -4; + goto error; + } + + req = &rpc->request; + + req->args.ioctl.cmd = (u32)cmd; + req->args.ioctl.outPtr = (output) ? (u8*)OSVirtualToPhysical(output) : 0; + req->args.ioctl.outLen = outputLen; + req->args.ioctl.inPtr = (input) ? (u8*)OSVirtualToPhysical(input) : 0; + req->args.ioctl.inLen = inputLen; + + DCFlushRange(input, inputLen); + DCFlushRange(output, outputLen); + +error: + return ret; +} + +IOSError IOS_IoctlAsync(IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen, IOSIpcCb cb, void* cbArg) { + IOSRpcRequest* rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(fd, 6, cb, cbArg, &rpc); + + if (ret != 0) { + goto err; + } + + ret = __ios_Ioctl(rpc, cmd, input, inputLen, output, outputLen); + + if (ret != 0) { + goto err; + } + + ret = __ios_Ipc2(rpc, cb); + +err: + return ret; +} + +IOSError IOS_Ioctl(IOSFd fd, s32 cmd, void* input, u32 inputLen, void* output, u32 outputLen) { + IOSRpcRequest* rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(fd, 6, 0, 0, &rpc); + + if (ret != 0) { + goto error; + } + + ret = __ios_Ioctl(rpc, cmd, input, inputLen, output, outputLen); + + if (ret != 0) { + goto error; + } + + ret = __ios_Ipc2(rpc, 0); + +error: + return ret; +} + +static IOSError __ios_Ioctlv(IOSRpcRequest* rpc, s32 cmd, u32 readCount, u32 writeCount, IOSIoVector* vect) { + IOSError ret = 0; + IOSResourceRequest* req; + IOSResourceIoctlv* v; + u32 i, j; + + if (!rpc) { + ret = -4; + goto err; + } + + req = &rpc->request; + req->args.ioctlv.cmd = (u32)cmd; + req->args.ioctlv.readCount = readCount; + req->args.ioctlv.writeCount = writeCount; + req->args.ioctlv.vector = vect; + + v = &req->args.ioctlv; + + for (i = 0, j = v->readCount; i < req->args.ioctlv.writeCount; ++i) { + DCFlushRange(v->vector[j + i].base, v->vector[j + i].length); + v->vector[j + i].base = (v->vector[j + i].base) ? (u8*)OSVirtualToPhysical(v->vector[j + i].base) : 0; + } + + for (i = 0; i < req->args.ioctlv.readCount; ++i) { + DCFlushRange(v->vector[i].base, v->vector[i].length); + v->vector[i].base = (v->vector[i].base) ? (u8*)OSVirtualToPhysical(v->vector[i].base) : 0; + } + + DCFlushRange(&v->vector[0], (v->readCount + v->writeCount) * sizeof(IOSIoVector)); + req->args.ioctlv.vector = (vect) ? (IOSIoVector*)OSVirtualToPhysical(vect) : 0; + +err: + return ret; +} + +IOSError IOS_IoctlvAsync(IOSFd fd, s32 cmd, u32 readCount, u32 writeCount, IOSIoVector* vect, IOSIpcCb cb, void* cbArg) { + IOSRpcRequest* rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(fd, 7, cb, cbArg, &rpc); + + if (ret != 0) { + goto err; + } + + ret = __ios_Ioctlv(rpc, cmd, readCount, writeCount, vect); + + if (ret != 0) { + goto err; + } + + ret = __ios_Ipc2(rpc, cb); + +err: + return ret; +} + +IOSError IOS_Ioctlv(IOSFd fd, s32 cmd, u32 readCount, u32 writeCount, IOSIoVector* vect) { + IOSRpcRequest* rpc; + IOSError ret = 0; + + ret = __ios_Ipc1(fd, 7, 0, 0, &rpc); + + if (ret != 0) { + goto err; + } + + ret = __ios_Ioctlv(rpc, cmd, readCount, writeCount, vect); + + if (ret != 0) { + goto err; + } + + ret = __ios_Ipc2(rpc, 0); + +err: + return ret; +} + +IOSError IOS_IoctlvReboot(IOSFd fd, s32 cmd, u32 readCount, u32 writeCount, IOSIoVector *vect) { + IOSRpcRequest* rpc; + IOSError ret = 0; + u32 inten; + IOSResourceRequest* req; + + inten = OSDisableInterrupts(); + + if (__relnchFl) { + OSRestoreInterrupts(inten); + ret = -10; + goto finish; + } + + __relnchFl = 1; + OSRestoreInterrupts(inten); + + ret = __ios_Ipc1(fd, 7, 0, 0, &rpc); + + if (ret != 0) { + goto err; + } + + __relnchRpcSave = rpc; + rpc->relaunch_flag = 1; + + ret = __ios_Ioctlv(rpc, cmd, readCount, writeCount, vect); + + if (ret != 0) { + goto err; + } + + memcpy(&__rpcBuf, rpc, sizeof(IOSRpcRequest)); + __relnchRpc = (IOSRpcRequest*)&__rpcBuf; + req = &rpc->request; + + OSInitThreadQueue(&__relnchRpc->thread_queue); + DCFlushRange(req, sizeof(*req)); + + inten = OSDisableInterrupts(); + ret = __ipcQueueRequest(req); + + if (ret != 0) { + OSRestoreInterrupts(inten); + goto err; + } + + if (__mailboxAck > 0) { + __ipcSendRequest(); + } + + OSSleepThread(&__relnchRpc->thread_queue); + OSRestoreInterrupts(inten); + ret = (&__relnchRpc->request)->status; + +err: + __relnchFl = 0; + __relnchRpcSave = NULL; + + if (rpc && (ret != 0)) { + ipcFree(rpc); + } + +finish: + return ret; +} \ No newline at end of file diff --git a/src/RVL_SDK/ipc/memory.c b/src/RVL_SDK/ipc/memory.c new file mode 100644 index 000000000..a9cd5cfcd --- /dev/null +++ b/src/RVL_SDK/ipc/memory.c @@ -0,0 +1,243 @@ +#include +#include "private/iostypes.h" + +typedef struct IOSChunk { + u32 status; + u32 size; + struct IOSChunk* prevFree; + struct IOSChunk* nextFree; +} IOSChunk; + +typedef struct { + void *base; + u32 owner; + u32 size; + IOSChunk *freeList; +} IOSHeap; + +static IOSHeap __heaps[8]; + +IOSHeapId iosCreateHeap(void *ptr, u32 size) { + IOSError rv = -4; + u32 mask; + s32 i; + IOSHeap* h; + + mask = OSDisableInterrupts(); + + if ((u32)ptr & 31) { + goto finish; + } + + for (i = 0; i < sizeof(__heaps) / sizeof(__heaps[0]); ++i) { + if (__heaps[i].base == 0) { + break; + } + } + + if (i == 8) { + rv = -5; + goto finish; + } + + h = __heaps + i; + h->base = ptr; + h->size = size; + h->freeList = ptr; + h->freeList->status = 0xBABE0000; + h->freeList->size = size - sizeof(IOSChunk); + h->freeList->prevFree = NULL; + h->freeList->nextFree = NULL; + rv = i; + +finish: + OSRestoreInterrupts(mask); + return rv; +} + +#define CHECK_HEAP_ID(id, err) \ + if (((id) < 0) || ((id) >= 8) || (!__heaps[id].base)) { \ + rv = err; \ + goto finish; \ + } + +#define GET_HEAP(h, id, err) \ + do { \ + CHECK_HEAP_ID(id, err); \ + h = __heaps + id; \ + } while (0) + +static void __iosCoalesceChunk(IOSChunk *p) { + if (p && ((u32)p->nextFree == ((u32)p + p->size + sizeof(IOSChunk)))) { + IOSChunk* next = p->nextFree; + p->nextFree = next->nextFree; + + if (p->nextFree != NULL) { + p->nextFree->prevFree = p; + } + + p->size += next->size + sizeof(IOSChunk); + } +} + +void* __iosAlloc(IOSHeapId id, u32 size, u32 alignment) { + u32 mask; + IOSChunk* p, *best; + IOSHeap* h; + void* rv = NULL; + + mask = OSDisableInterrupts(); + + if (!size) { + goto finish; + } + + if (!alignment || (alignment & (alignment - 1))) { + goto finish; + } + + if (alignment < 32) { + alignment = 32; + } + + size = (size + 31) & ~31; + + GET_HEAP(h, id, NULL); + + p = h->freeList; + best = NULL; + + while (p != NULL) { + u32 ptr = (u32)p + sizeof(IOSChunk); + u32 extra = (alignment - (ptr & (alignment - 1))) & (alignment - 1); + + if ((p->size == size) && !extra) { + best = p; + break; + } + else if ((p->size >= (size + extra)) && (!best || (p->size < best->size))) { + best = p; + } + + p = p->nextFree; + } + + p = best; + + if (p != NULL) { + u32 ptr = (u32)p + sizeof(IOSChunk); + u32 extra = (alignment - (ptr & (alignment - 1))) & (alignment - 1); + + if (p->size > (size + extra + sizeof(IOSChunk))) { + IOSChunk *n = (IOSChunk *)((u8 *)p + size + extra + sizeof(IOSChunk)); + n->status = 0xBABE0000; + n->size = p->size - size - extra - sizeof(IOSChunk); + n->nextFree = p->nextFree; + + if (n->nextFree) { + n->nextFree->prevFree = n; + } + + p->nextFree = n; + p->size = size + extra; + } + + p->status = 0xBABE0001; + + if (p->prevFree) { + p->prevFree->nextFree = p->nextFree; + } + else { + h->freeList = p->nextFree; + } + + if (p->nextFree) { + p->nextFree->prevFree = p->prevFree; + } + + p->prevFree = p->nextFree = NULL; + rv = (u8*)p + extra + sizeof(IOSChunk); + + if (extra) { + IOSChunk* n = (IOSChunk*)rv - 1; + n->status = 0xBABE0002; + n->prevFree = p; + } + } + +finish: + OSRestoreInterrupts(mask); + return rv; +} + +void* iosAllocAligned(IOSHeapId id, u32 size, u32 alignment) { + return __iosAlloc(id, size, alignment); +} + +IOSError iosFree(IOSHeapId id, void* ptr) { + u32 mask; + IOSChunk* p; + IOSHeap* h; + IOSError rv = -4; + IOSChunk* prev; + + mask = OSDisableInterrupts(); + + if (!ptr) { + goto finish; + } + + GET_HEAP(h, id, -4); + + if (((u32)ptr) < (((u32)h->base) + sizeof(IOSChunk)) || ((u32)ptr) > ((u32)h->base + h->size)) { + goto finish; + } + + p = (IOSChunk*)ptr - 1; + + if (p->status == 0xBABE0002) { + p = p->prevFree; + } + + if (p->status != 0xBABE0001) { + goto finish; + } + + p->status = 0xBABE0000; + prev = h->freeList; + + while (prev != NULL) { + if (!prev->nextFree || prev->nextFree > p) { + break; + } + + prev = prev->nextFree; + } + + if (prev && p > prev) { + p->prevFree = prev; + p->nextFree = prev->nextFree; + prev->nextFree = p; + + if (p->nextFree) { + p->nextFree->prevFree = p; + } + } + else { + p->nextFree = h->freeList; + h->freeList = p; + p->prevFree = NULL; + + if (p->nextFree) { + p->nextFree->prevFree = p; + } + } + + __iosCoalesceChunk(p); + __iosCoalesceChunk(p->prevFree); + rv = 0; + +finish: + OSRestoreInterrupts(mask); + return rv; +} \ No newline at end of file diff --git a/src/RVL_SDK/mem/mem_allocator.c b/src/RVL_SDK/mem/mem_allocator.c new file mode 100644 index 000000000..6306f345e --- /dev/null +++ b/src/RVL_SDK/mem/mem_allocator.c @@ -0,0 +1,31 @@ +#include +#include + +static void* AllocatorAllocForExpHeap_(MEMAllocator *pAllocator, u32 size) { + return MEMAllocFromExpHeapEx(pAllocator->pHeap, size, pAllocator->heapParam1); +} + +static void AllocatorFreeForExpHeap_(MEMAllocator *pAllocator, void *pBlock) { + MEMFreeToExpHeap(pAllocator->pHeap, pBlock); +} + +void* MEMAllocFromAllocator(MEMAllocator *pAllocator, u32 size) { + return (*pAllocator->pFunc->pfAlloc)(pAllocator, size); +} + +void MEMFreeToAllocator(MEMAllocator *pAllocator, void *pBlock) { + (*pAllocator->pFunc->pfFree)(pAllocator, pBlock); +} + +void MEMInitAllocatorForExpHeap(MEMAllocator *pAllocator, MEMHeapHandle handle, int align) { + static const MEMAllocatorFunc sAllocatorFunc = + { + AllocatorAllocForExpHeap_, + AllocatorFreeForExpHeap_, + }; + + pAllocator->pFunc = &sAllocatorFunc; + pAllocator->pHeap = handle; + pAllocator->heapParam1 = align; + pAllocator->heapParam2 = 0; +} \ No newline at end of file diff --git a/src/RVL_SDK/mem/mem_heapCommon.c b/src/RVL_SDK/mem/mem_heapCommon.c new file mode 100644 index 000000000..dbdd9966b --- /dev/null +++ b/src/RVL_SDK/mem/mem_heapCommon.c @@ -0,0 +1,35 @@ +#include +#include + +/* +static MEMiHeapHead* FindContainHeap_(MEMList *pList, const void *memBlock) __attribute__((noinline)) { + MEMiHeapHead* v3; + MEMiHeapHead* v5; + MEMiHeapHead* v8; + MEMiHeapHead* v9; + MEMiHeapHead* v10; + MEMList* list; + + v3 = NULL; + + do { + v10 = MEMGetNextListObject(pList, v3); + v3 = v10; + + if (v10 == NULL) { + return NULL; + } + } while (v10->heapStart > memBlock || memBlock >= v10->heapEnd); + + v5 = NULL; + + do { + v9 = MEMGetNextListObject(&v3->childList, v5); + v5 = v9; + + if (v9 == NULL) { + + } + } while (v9->heapStart > memBlock || memBlock >= v9->heapEnd); +} +*/ \ No newline at end of file diff --git a/src/RVL_SDK/mem/mem_list.c b/src/RVL_SDK/mem/mem_list.c new file mode 100644 index 000000000..2bc35f1fc --- /dev/null +++ b/src/RVL_SDK/mem/mem_list.c @@ -0,0 +1,64 @@ +#include + + +// I've tried inlines but only a macro seems to work +#define GetLink(parent_list, obj) ((MEMLink*)(((u32)(obj))+(parent_list)->offs)) + +void MEMInitList(MEMList *pList, u16 offs) { + pList->head = NULL; + pList->tail = NULL; + pList->num = 0; + pList->offs = offs; +} + +void MEMAppendListObject(MEMList *pList, void *pObj) { + MEMLink* link; + + if (pList->head == NULL) { + link = GetLink(pList, pObj); + link->next = NULL; + link->prev = NULL; + pList->head = pObj; + pList->tail = pObj; + pList->num++; + } + else { + link = GetLink(pList, pObj); + link->prev = pList->tail; + link->next = NULL; + + GetLink(pList, pList->tail)->next = pObj; + pList->tail = pObj; + pList->num++; + } +} + +void MEMRemoveListObject(MEMList *pList, void *pObj) { + MEMLink* link = GetLink(pList, pObj); + + if (link->prev == NULL) { + pList->head = link->next; + } + else { + GetLink(pList, link->prev)->next = link->next; + } + + if (link->next == NULL) { + pList->tail = link->prev; + } + else { + GetLink(pList, link->next)->prev = link->prev; + } + + link->prev = NULL; + link->next = NULL; + pList->num--; +} + +void* MEMGetNextListObject(MEMList *pList, void *pObj) { + if (pObj == NULL) { + return pList->head; + } + + return GetLink(pList, pObj)->next; +} \ No newline at end of file diff --git a/src/RVL_SDK/nand/NANDCheck.c b/src/RVL_SDK/nand/NANDCheck.c new file mode 100644 index 000000000..32e959f6e --- /dev/null +++ b/src/RVL_SDK/nand/NANDCheck.c @@ -0,0 +1,97 @@ +#include +#include + +static const char *USER_DIR_LIST[] = +{ + "/meta", + "/ticket", + "/title/00010000", + "/title/00010001", + "/title/00010003", + "/title/00010004", + "/title/00010005", + "/title/00010006", + "/title/00010007", + "/shared2/title", + NULL, +}; + +s32 nandCalcUsage(u32* fsBlock, u32* inode, const char* dir_list[]) { + ISFSError ret = ISFS_ERROR_UNKNOWN; + *fsBlock = 0; + *inode = 0; + + while (*dir_list) { + u32 blk = 0; + u32 node = 0; + ret = ISFS_GetUsage((const u8*)*dir_list, &blk, &node); + + if (ret == ISFS_ERROR_OK) { + *fsBlock += blk; + *inode += node; + } + else if (ret == ISFS_ERROR_NOEXISTS) { + ret = ISFS_ERROR_OK; + } + else { + break; + } + + ++dir_list; + } + + return ret; +} + +ISFSError nandCalcUserUsage(u32* fsBlock, u32* inode) { + return nandCalcUsage(fsBlock, inode, USER_DIR_LIST); +} + +static u32 nandCheck(const u32 reqBlock, const u32 reqInode, const u32 homeBlock, const u32 homeInode, const u32 userBlock, const u32 userInode) { + u32 answer = 0; + + if (homeBlock + reqBlock > 0x400) { + answer |= 1; + } + + if (homeInode + reqInode > 0x21) { + answer |= 2; + } + + if (userBlock + reqBlock > 0x4400) { + answer |= 4; + } + + if (userInode + reqInode > 0xFA0) { + answer |= 8; + } + + return answer; +} + +s32 NANDCheck(const u32 fsBlock, const u32 inode, u32* answer) { + ISFSError ret = ISFS_ERROR_UNKNOWN; + u32 homeBlocks = 0xFFFFFFFF; + u32 homeInodes = 0xFFFFFFFF; + u32 userBlocks = 0xFFFFFFFF; + u32 userInodes = 0xFFFFFFFF; + + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + ret = ISFS_GetUsage((const u8*)nandGetHomeDir(), &homeBlocks, &homeInodes); + + if (ret != ISFS_ERROR_OK) { + return nandConvertErrorCode(ret); + } + + ret = nandCalcUserUsage(&userBlocks, &userInodes); + + if (ret != ISFS_ERROR_OK) { + return nandConvertErrorCode(ret); + } + + *answer = nandCheck(fsBlock, inode, homeBlocks, homeInodes, userBlocks, userInodes); + return NAND_RESULT_OK; +} \ No newline at end of file diff --git a/src/RVL_SDK/nand/NANDCore.c b/src/RVL_SDK/nand/NANDCore.c new file mode 100644 index 000000000..0d509a245 --- /dev/null +++ b/src/RVL_SDK/nand/NANDCore.c @@ -0,0 +1,473 @@ +#include +#include +#include +#include +#include +#include +#include + +const char* __NANDVersion = "<< RVL_SDK - NAND \trelease build: Dec 11 2007 01:35:48 (0x4199_60831) >>"; +enum LibState { + STATE_NOT_INITIALIZED, + STATE_WORKING, + STATE_INITIALIZED +}; + +static enum LibState s_libState = STATE_NOT_INITIALIZED; +static char s_currentDir[64] = "/" __attribute__ ((aligned(32))); +static char s_homeDir[64] = "" __attribute__ ((aligned(32))); + +static BOOL nandOnShutdown(BOOL final, u32 event); +void nandConvertPath(char *, const char *, const char *); +static void nandShutdownCallback(ISFSError, void *); + +static OSShutdownFunctionInfo s_shutdownFuncInfo = +{ + nandOnShutdown, + 255 +}; + +void nandRemoveTailToken(char* newpath, const char* oldpath) { + if (oldpath[0] == '/' && oldpath[1] == '\0') { + newpath[0] = '/'; + newpath[1] = '\0'; + } + else { + int i = 0; + + for (i = (int)(strlen(oldpath)) - 1; i >= 0; --i) { + if (oldpath[i] == '/') { + if (i != 0) { + strncpy(newpath, oldpath, (u32)i); + newpath[i] = '\0'; + break; + } + else { + newpath[0] = '/'; + newpath[1] = '\0'; + break; + } + } + } + } +} + +void nandGetHeadToken(char* token, char* newpath, const char* oldpath) { + unsigned int i = 0; + + for (i = 0; i <= strlen(oldpath); ++i) { + if (oldpath[i] == '/') { + strncpy(token, oldpath, i); + token[i] = '\0'; + + if (oldpath[i + 1] == '\0') { + newpath[0] = '\0'; + } + else { + strcpy(newpath, oldpath + i + 1); + } + + break; + } + else if (oldpath[i] == '\0') { + strncpy(token, oldpath, i); + token[i] = '\0'; + newpath[0] = '\0'; + break; + } + } +} + +void nandGetRelativeName(char* name, const char* path) { + if (strcmp("/", path) == 0) { + strcpy(name, ""); + } + else { + int i = 0; + + for (i = (int)(strlen(path) - 1); i >= 0; --i) { + if (path[i] == '/') { + break; + } + } + + strcpy(name, path + i + 1); + } +} + +void nandConvertPath(char* abspath, const char* wd, const char* relpath) { + char token[128]; + char new_relpath[128]; + + if (strlen(relpath) == 0) { + strcpy(abspath, wd); + return; + } + + nandGetHeadToken(token, new_relpath, relpath); + + if (strcmp(token, ".") == 0) { + nandConvertPath(abspath, wd, new_relpath); + } + else if (strcmp(token, "..") == 0) { + char new_wd[128]; + nandRemoveTailToken(new_wd, wd); + nandConvertPath(abspath, new_wd, new_relpath); + } + else if (token[0] != '\0') { + char new_wd[128]; + if (strcmp(wd, "/") == 0) { + sprintf(new_wd, "/%s", token); + } + else { + sprintf(new_wd, "%s/%s", wd, token); + } + + nandConvertPath(abspath, new_wd, new_relpath); + } + else { + strcpy(abspath, wd); + } +} + +inline BOOL nandIsRelativePath(const char* path) { + if (path[0] == '/') { + return FALSE; + } + else { + return TRUE; + } +} + +BOOL nandIsPrivatePath(const char* path) { + if (strncmp(path, "/shared2", 8) == 0) { + return TRUE; + } + else { + return FALSE; + } +} + +BOOL nandIsUnderPrivatePath(const char* path) { + if ((strncmp(path, "/shared2/", 9) == 0) && (path[9] != '\0')) { + return TRUE; + } + else { + return FALSE; + } +} + +BOOL nandIsInitialized(void) { + if (s_libState == STATE_INITIALIZED) { + return TRUE; + } + else { + return FALSE; + } +} + +void nandReportErrorCode(const ISFSError err) NO_INLINE { + return; +} + +s32 nandConvertErrorCode(const ISFSError err) { + const int ERRMAP[]= + { + ISFS_ERROR_OK, NAND_RESULT_OK, + ISFS_ERROR_ACCESS, NAND_RESULT_ACCESS, + ISFS_ERROR_CORRUPT, NAND_RESULT_CORRUPT, + ISFS_ERROR_ECC_CRIT, NAND_RESULT_ECC_CRIT, + ISFS_ERROR_EXISTS, NAND_RESULT_EXISTS, + ISFS_ERROR_HMAC, NAND_RESULT_AUTHENTICATION, + ISFS_ERROR_INVALID, NAND_RESULT_INVALID, + ISFS_ERROR_MAXBLOCKS, NAND_RESULT_MAXBLOCKS, + ISFS_ERROR_MAXFD, NAND_RESULT_MAXFD, + ISFS_ERROR_MAXFILES, NAND_RESULT_MAXFILES, + ISFS_ERROR_MAXDEPTH, NAND_RESULT_MAXDEPTH, + ISFS_ERROR_NOEXISTS, NAND_RESULT_NOEXISTS, + ISFS_ERROR_NOTEMPTY, NAND_RESULT_NOTEMPTY, + ISFS_ERROR_NOTREADY, NAND_RESULT_UNKNOWN, + ISFS_ERROR_OPENFD, NAND_RESULT_OPENFD, + ISFS_ERROR_UNKNOWN, NAND_RESULT_UNKNOWN, + ISFS_ERROR_BUSY, NAND_RESULT_BUSY, + ISFS_ERROR_SHUTDOWN, NAND_RESULT_FATAL_ERROR, + + IOS_ERROR_ACCESS, NAND_RESULT_ACCESS, + IOS_ERROR_EXISTS, NAND_RESULT_EXISTS, + IOS_ERROR_INTR, NAND_RESULT_UNKNOWN, + IOS_ERROR_INVALID, NAND_RESULT_INVALID, + IOS_ERROR_MAX, NAND_RESULT_UNKNOWN, + IOS_ERROR_NOEXISTS, NAND_RESULT_NOEXISTS, + IOS_ERROR_QEMPTY, NAND_RESULT_UNKNOWN, + IOS_ERROR_QFULL, NAND_RESULT_BUSY, + IOS_ERROR_UNKNOWN, NAND_RESULT_UNKNOWN, + IOS_ERROR_NOTREADY, NAND_RESULT_UNKNOWN, + IOS_ERROR_ECC, NAND_RESULT_UNKNOWN, + IOS_ERROR_ECC_CRIT, NAND_RESULT_ECC_CRIT, + IOS_ERROR_BADBLOCK, NAND_RESULT_UNKNOWN, + + IOS_ERROR_INVALID_OBJTYPE, NAND_RESULT_UNKNOWN, + IOS_ERROR_INVALID_RNG, NAND_RESULT_UNKNOWN, + IOS_ERROR_INVALID_FLAG, NAND_RESULT_UNKNOWN, + IOS_ERROR_INVALID_FORMAT, NAND_RESULT_UNKNOWN, + IOS_ERROR_INVALID_VERSION, NAND_RESULT_UNKNOWN, + IOS_ERROR_INVALID_SIGNER, NAND_RESULT_UNKNOWN, + IOS_ERROR_FAIL_CHECKVALUE, NAND_RESULT_UNKNOWN, + IOS_ERROR_FAIL_INTERNAL, NAND_RESULT_UNKNOWN, + IOS_ERROR_FAIL_ALLOC, NAND_RESULT_ALLOC_FAILED, + IOS_ERROR_INVALID_SIZE, NAND_RESULT_UNKNOWN, + }; + + int i = 0; + + if (err >= 0) { + return err; + } + + for (; i < sizeof(ERRMAP) / 4; i = i + 2) { + if (ERRMAP[i] == err) { + if (err == ISFS_ERROR_ECC_CRIT || err == ISFS_ERROR_HMAC || err == ISFS_ERROR_UNKNOWN || err == IOS_ERROR_UNKNOWN || err == IOS_ERROR_ECC_CRIT) { + char buf[128] __attribute__ ((aligned(64))); + sprintf(buf, "ISFS error code: %d", err); + NANDLoggingAddMessageAsync(0, buf); + } + + nandReportErrorCode(err); + return ERRMAP[i + 1]; + } + } + + OSReport("CAUTION! Unexpected error code [%d] was found.\n", err); + { + char buf[128] __attribute__ ((aligned(64))); + sprintf(buf, "ISFS unexpected error code: %d", err); + NANDLoggingAddMessageAsync(0, buf); + } + + nandReportErrorCode(err); + return -64; +} + +void nandGenerateAbsPath(char* absPath, const char* path) { + if (strlen(path) == 0) { + strcpy(absPath, ""); + } + else if (nandIsRelativePath(path)) { + nandConvertPath(absPath, s_currentDir, path); + } + else { + u32 len = 0xFFFFFFFF; + strcpy(absPath, path); + + len = strlen(absPath); + if (len > 0) { + if ((absPath[len - 1] == '/') && (len - 1 != 0)) { + absPath[len - 1] = '\0'; + } + } + } +} + +void nandGetParentDirectory(char* parentDir, const char* absPath) { + int i = 0; + for (i = (int)strlen(absPath); i >= 0; --i) { + if (absPath[i] == '/') { + break; + } + } + + if (i == 0) { + strcpy(parentDir, "/"); + } + else { + strncpy(parentDir, absPath, (u32)i); + parentDir[i] = '\0'; + } +} + +s32 NANDInit(void) { + BOOL enabled = OSDisableInterrupts(); + + if (s_libState == STATE_WORKING) { + OSRestoreInterrupts(enabled); + return -3; + } + else if (s_libState == 2) { + OSRestoreInterrupts(enabled); + return 0; + } + else { + ISFSError result = -117; + s_libState = STATE_WORKING; + OSRestoreInterrupts(enabled); + + result = ISFS_OpenLib(); + if (result == 0) { + s32 rv; + ESTitleId id; + + rv = ESP_InitLib(); + + if (rv == 0) { + rv = ESP_GetTitleId(&id); + } + + if (rv == 0) { + rv = ESP_GetDataDir(id, s_homeDir); + } + + if (rv == 0) { + strcpy(s_currentDir, s_homeDir); + } + + ESP_CloseLib(); + + if (rv != 0) { + OSReport("Failed to set home directory.\n"); + } + + OSRegisterShutdownFunction(&s_shutdownFuncInfo); + enabled = OSDisableInterrupts(); + s_libState = STATE_INITIALIZED; + OSRestoreInterrupts(enabled); + OSRegisterVersion(__NANDVersion); + return 0; + } + else { + enabled = OSDisableInterrupts(); + s_libState = STATE_NOT_INITIALIZED; + OSRestoreInterrupts(enabled); + return nandConvertErrorCode(result); + } + } +} + +static BOOL nandOnShutdown(BOOL final, u32 event) { + if (!final) { + if (event == 2) { + volatile BOOL flag = FALSE; + OSTime t = OSGetTime(); + ISFS_ShutdownAsync(nandShutdownCallback, (void*)&flag); + + while (OSTicksToMilliseconds(OSGetTime() - t) < 500) { + if (flag) { + break; + } + } + } + + return TRUE; + } + else { + return TRUE; + } +} + +static void nandShutdownCallback(ISFSError result, void* ctxt) { + (void)result; + *(BOOL*)ctxt = TRUE; +} + +s32 NANDGetHomeDir(char* path) { + if (!nandIsInitialized()) { + return -128; + } + + strcpy(path, s_homeDir); + return 0; +} + +void nandCallback(ISFSError result, void* ctxt) { + NANDCommandBlock* b = (NANDCommandBlock*)ctxt; + ((NANDCallback)(b->callback))(nandConvertErrorCode(result), b); +} + +void nandGetTypeCallback(ISFSError result, void* ctxt); + +static ISFSError nandGetType(const char* path, u8* type, NANDCommandBlock* block, const BOOL async_flag, const BOOL privilege_flag) { + if (strlen(path) == 0) { + return ISFS_ERROR_INVALID; + } + + if (async_flag) { + nandGenerateAbsPath(block->absPath, path); + if (!privilege_flag && nandIsUnderPrivatePath(block->absPath)) { + return ISFS_ERROR_ACCESS; + } + else { + block->type = type; + return ISFS_ReadDirAsync((u8*)(block->absPath), NULL, &(block->num), nandGetTypeCallback, block); + } + } + else { + char absPath[64] = ""; + nandGenerateAbsPath(absPath, path); + + if (!privilege_flag && nandIsUnderPrivatePath(absPath)) { + return ISFS_ERROR_ACCESS; + } + else { + u32 dmy = 0; + ISFSError err = ISFS_ReadDir((u8*)absPath, NULL, &dmy); + + if ((err == ISFS_ERROR_OK) || (err == ISFS_ERROR_ACCESS)) { + *type = 2; + err = ISFS_ERROR_OK; + } + else if (err == ISFS_ERROR_INVALID) { + *type = 1; + err = ISFS_ERROR_OK; + } + + return err; + } + } +} + +s32 NANDPrivateGetTypeAsync(const char* path, u8* type, NANDCallback cb, NANDCommandBlock* block) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + block->callback = cb; + return nandConvertErrorCode(nandGetType(path, type, block, TRUE, TRUE)); +} + +void nandGetTypeCallback(ISFSError result, void* ctxt) { + NANDCommandBlock* b = (NANDCommandBlock*)ctxt; + + if ((result == ISFS_ERROR_OK) || (result == ISFS_ERROR_ACCESS)) { + *(b->type) = 2; + result = ISFS_ERROR_OK; + } + else if (result == ISFS_ERROR_INVALID) { + *(b->type) = 1; + result = ISFS_ERROR_OK; + } + + ((NANDCallback)(b->callback))(nandConvertErrorCode(result), b); +} + +const char* nandGetHomeDir(void) { + return s_homeDir; +} + +void NANDInitBanner(NANDBanner* bnr, u32 const flag, const u16* title, const u16* comment) { + memset(bnr, 0, sizeof(NANDBanner)); + bnr->signature = 0x5749424E; + bnr->flag = flag; + + if (wcscmp((wchar_t*)title, L"") == 0) { + wcsncpy(bnr->comment[0], L" ", 32); + } + else { + wcsncpy(bnr->comment[0], (wchar_t*)title, 32); + } + + if (wcscmp((wchar_t*)comment, L"") == 0) { + wcsncpy(bnr->comment[1], L" ", 32); + } + else { + wcsncpy(bnr->comment[1], (wchar_t*)comment, 32); + } +} \ No newline at end of file diff --git a/src/RVL_SDK/nand/NANDLogging.c b/src/RVL_SDK/nand/NANDLogging.c new file mode 100644 index 000000000..b38ea9c03 --- /dev/null +++ b/src/RVL_SDK/nand/NANDLogging.c @@ -0,0 +1,195 @@ +#include +#include +#include +#include +#include + +static IOSFd s_fd = -255; +static int s_stage; +static char s_message[256] __attribute__ ((aligned (64))); +static NANDLoggingCallback s_callback = 0; + +static void asyncRoutine(ISFSError, void *); +static void prepareLine(char line[256], int, const char *); + +BOOL reserveFileDescriptor(void) { + BOOL enabled = FALSE; + BOOL busy_flag = FALSE; + + enabled = OSDisableInterrupts(); + + if (s_fd == -255) { + s_fd = -254; + busy_flag = FALSE; + } + else if (s_fd == -254) { + busy_flag = TRUE; + } + else if (s_fd >= 0) { + busy_flag = TRUE; + } + else { + busy_flag = TRUE; + } + + OSRestoreInterrupts(enabled); + return busy_flag ? FALSE : TRUE; +} + +BOOL NANDLoggingAddMessageAsync(NANDLoggingCallback cb, const char* fmt, ...) { + va_list ap; + ISFSError err = ISFS_ERROR_UNKNOWN; + + if (!reserveFileDescriptor()) { + return FALSE; + } + + va_start(ap, fmt); + vsnprintf(s_message, 256, fmt, ap); + va_end(ap); + + s_callback = cb; + s_stage = 1; + err = ISFS_OpenAsync((const u8*)"/shared2/test2/nanderr.log", 3, asyncRoutine, 0); + + if (err == ISFS_ERROR_OK) { + return TRUE; + } + else { + return FALSE; + } +} + +static void callbackRoutine(BOOL result) { + if (s_callback) { + s_callback(result); + } +} + +static void asyncRoutine(ISFSError result, void *ctxt) { + ISFSError ret = ISFS_ERROR_UNKNOWN; + static char s_rBuf[256] __attribute__ ((aligned (64))); + static char s_wBuf[256] __attribute__ ((aligned (64))); + ++s_stage; + + if (s_stage == 2) { + if (result >= 0) { + s_fd = result; + ret = ISFS_SeekAsync(s_fd, 0, 0, asyncRoutine, 0); + + if (ret != ISFS_ERROR_OK) { + callbackRoutine(FALSE); + } + } + else { + callbackRoutine(FALSE); + } + } + else if (s_stage == 3) { + if (result == 0) { + ret = ISFS_ReadAsync(s_fd, (u8*)s_rBuf, 256, asyncRoutine, 0); + + if (ret != ISFS_ERROR_OK) { + callbackRoutine(FALSE); + } + } + else { + callbackRoutine(FALSE); + } + } + else if (s_stage == 4) { + if (result == 256) { + ret = ISFS_SeekAsync(s_fd, 0, 0, asyncRoutine, 0); + + if (ret != ISFS_ERROR_OK) { + callbackRoutine(FALSE); + } + } + else { + callbackRoutine(FALSE); + } + } + else if (s_stage == 5) { + if (result == 0) { + int n = 0; + s_rBuf[255] = '\0'; + n = atoi(s_rBuf); + prepareLine(s_wBuf, n, s_message); + ret = ISFS_WriteAsync(s_fd, (const u8*)s_wBuf, 256, asyncRoutine, 0); + + if (ret != ISFS_ERROR_OK) { + callbackRoutine(FALSE); + } + } + else { + callbackRoutine(FALSE); + } + } + else if (s_stage == 6) { + if (result == 256) { + int n = atoi(s_rBuf); + ret = ISFS_SeekAsync(s_fd, n * 256, 0, asyncRoutine, 0); + + if (ret != ISFS_ERROR_OK) { + callbackRoutine(FALSE); + } + } + else { + callbackRoutine(FALSE); + } + } + else if (s_stage == 7) { + int n = atoi(s_rBuf); + if (result == n * 256) + { + ret = ISFS_WriteAsync(s_fd, (const u8*)s_wBuf, 256, asyncRoutine, 0); + if (ret != ISFS_ERROR_OK) { + callbackRoutine(FALSE); + } + } + else { + callbackRoutine(FALSE); + } + } + else if (s_stage == 8) { + if (result == 256) { + ret = ISFS_CloseAsync(s_fd, asyncRoutine, 0); + + if (ret != ISFS_ERROR_OK) { + callbackRoutine(FALSE); + } + } + else { + callbackRoutine(FALSE); + } + } + else if (s_stage == 9) { + if (result == ISFS_ERROR_OK) { + s_fd = -255; + callbackRoutine(TRUE); + } + else { + callbackRoutine(FALSE); + } + } +} + +static void prepareLine(char line[256], int n, const char* msg) { + char titleID[64]; + int end = 0; + struct OSCalendarTime cal; + + memset(line, ' ', 254); + OSTicksToCalendarTime(OSGetTime(), &cal); + strncpy(titleID, nandGetHomeDir() + 7, 8 + 1 + 8); + titleID[8] = '-'; + titleID[8 + 1 + 8] = '\0'; + end = snprintf(line, 256, "%d %04d/%02d/%02d %02d:%02d:%02d %s %s", n % (64 - 1) + 1, cal.year, cal.mon + 1, cal.mday, cal.hour, cal.min, cal.sec, titleID, msg); + + if (end < 256) { + line[end] = ' '; + } + + line[254] = '\r'; + line[255] = '\n'; +} \ No newline at end of file diff --git a/src/RVL_SDK/nand/NANDOpenClose.c b/src/RVL_SDK/nand/NANDOpenClose.c new file mode 100644 index 000000000..498f54c27 --- /dev/null +++ b/src/RVL_SDK/nand/NANDOpenClose.c @@ -0,0 +1,462 @@ +#include +#include +#include + +static void nandOpenCallback(ISFSError, void *); +static void nandReadCloseCallback(ISFSError, void *); +static void nandCloseCallback(ISFSError, void *); +static void nandSafeCloseCallback(ISFSError, void *); +static void nandSafeOpenCallback(const ISFSError, void *); +void nandReadOpenCallback(ISFSError, void *); +s32 nandSafeCloseAsync(NANDFileInfo *, NANDCallback, NANDCommandBlock *, BOOL); +s32 nandSafeOpenAsync(const char *, NANDFileInfo *, const u8, void *, const u32, NANDCallback, NANDCommandBlock *, BOOL, BOOL); + +static u32 nandGetUniqueNumber(void) { + static u32 s_counter = 0; + u32 ret; + BOOL enabled = OSDisableInterrupts(); + ret = s_counter++; + OSRestoreInterrupts(enabled); + return ret; +} + +IOSFd nandOpen(const char* path, const u8 accType, NANDCommandBlock* block, const BOOL async_flag, const BOOL privilege_flag) { + IOSFd fd = -117; + char absPath[64] = ""; + u32 access = 0; + + nandGenerateAbsPath(absPath, path); + + if (!privilege_flag && nandIsPrivatePath(absPath)) { + return ISFS_ERROR_ACCESS; + } + else { + switch (accType) { + case 3: + access = 3; + break; + case 1: + access = 1; + break; + case 2: + access = 2; + break; + default: + break; + } + + if (async_flag) { + fd = ISFS_OpenAsync((const u8*)absPath, access, nandOpenCallback, block); + } + else { + fd = ISFS_Open((const u8*)absPath, access); + } + + return fd; + } +} + +s32 NANDOpen(const char* path, NANDFileInfo* info, const u8 accType) { + IOSFd fd = ISFS_ERROR_UNKNOWN; + + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + fd = nandOpen(path, accType, NULL, FALSE, FALSE); + + if (fd >= 0) { + info->fileDescriptor = fd; + info->mark = 1; + return NAND_RESULT_OK; + } + else { + return nandConvertErrorCode(fd); + } +} + +s32 NANDPrivateOpen(const char* path, NANDFileInfo* info, const u8 accType) { + IOSFd fd = ISFS_ERROR_UNKNOWN; + + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + fd = nandOpen(path, accType, NULL, FALSE, TRUE); + + if (fd >= 0) { + info->fileDescriptor = fd; + info->mark = 1; + return NAND_RESULT_OK; + } + else { + return nandConvertErrorCode(fd); + } +} + +s32 NANDOpenAsync(const char* path, NANDFileInfo* info, const u8 accType, NANDCallback cb, NANDCommandBlock* block) { + IOSFd fd = ISFS_ERROR_UNKNOWN; + + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + block->callback = cb; + block->fileInfo = info; + fd = nandOpen(path, accType, block, TRUE, FALSE); + return nandConvertErrorCode(fd); +} + +s32 NANDPrivateOpenAsync(const char* path, NANDFileInfo* info, const u8 accType, NANDCallback cb, NANDCommandBlock* block) { + IOSFd fd = ISFS_ERROR_UNKNOWN; + + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + block->callback = cb; + block->fileInfo = info; + fd = nandOpen(path, accType, block, TRUE, TRUE); + return nandConvertErrorCode(fd); +} + +void nandOpenCallback(ISFSError result, void* ctxt) { + NANDCommandBlock* b = (NANDCommandBlock*)ctxt; + + if (result >= 0) { + ((NANDFileInfo*)(b->fileInfo))->fileDescriptor = result; + ((NANDFileInfo*)(b->fileInfo))->stage = 2; + ((NANDFileInfo*)(b->fileInfo))->mark = 1; + ((NANDCallback)(b->callback))(NAND_RESULT_OK, b); + } + else { + ((NANDCallback)(b->callback))(nandConvertErrorCode(result), b); + } +} + +s32 NANDClose(NANDFileInfo* info) { + ISFSError err = ISFS_ERROR_UNKNOWN; + + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + if (info->mark != 1) { + return NAND_RESULT_INVALID; + } + + err = ISFS_Close(info->fileDescriptor); + + if (err == ISFS_ERROR_OK) { + info->mark = 2; + } + + return nandConvertErrorCode(err); +} + +s32 NANDCloseAsync(NANDFileInfo* info, NANDCallback cb, NANDCommandBlock* block) { + ISFSError err = ISFS_ERROR_UNKNOWN; + + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + if (info->mark != 1) { + return NAND_RESULT_INVALID; + } + + block->callback = cb; + block->fileInfo = info; + err = ISFS_CloseAsync(info->fileDescriptor, nandCloseCallback, block); + return nandConvertErrorCode(err); +} + +s32 NANDPrivateSafeOpenAsync(const char* path, NANDFileInfo* info, const u8 accType, void* buf, const u32 length, NANDCallback cb, NANDCommandBlock* block) { + return nandSafeOpenAsync(path, info, accType, buf, length, cb, block, TRUE, FALSE); +} + +s32 nandSafeOpenAsync(const char* path, NANDFileInfo* info, const u8 accType, void* buf, const u32 length, NANDCallback cb, NANDCommandBlock* block, BOOL privilege_flag, BOOL simple_flag) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + if (simple_flag && ((length & 0x3FFF) != 0)) { + return NAND_RESULT_INVALID; + } + + info->accType = accType; + info->stage = 0; + block->simpleFlag = simple_flag; + nandGenerateAbsPath(info->origPath, path); + + if (!privilege_flag && nandIsPrivatePath(info->origPath)) { + return NAND_RESULT_ACCESS; + } + + if (accType == 1) { + IOSFd fd = -1; + block->fileInfo = info; + block->callback = cb; + fd = ISFS_OpenAsync((u8*)(info->origPath), 1, nandReadOpenCallback, block); + + if (fd == ISFS_ERROR_OK) { + return NAND_RESULT_OK; + } + else { + return nandConvertErrorCode(fd); + } + } + else if (accType == 2 || accType == 3) { + ISFSError ret = ISFS_ERROR_UNKNOWN; + block->fileInfo = info; + block->callback = cb; + block->state = 0; + block->copyBuf = buf; + block->bufLength = length; + ret = ISFS_CreateDirAsync((u8*)"/tmp/sys", 0, 3, 3, 3, nandSafeOpenCallback, block); + + if (ret == ISFS_ERROR_OK) { + return NAND_RESULT_OK; + } + else { + return nandConvertErrorCode(ret); + } + } + else { + return NAND_RESULT_INVALID; + } +} + +void nandSafeOpenCallback(const ISFSError result, void* ctxt) { + NANDCommandBlock* b = (NANDCommandBlock*)ctxt; + + if ((result >= 0) || ((result == ISFS_ERROR_EXISTS) && b->state == 0)) { + NANDFileInfo* info = b->fileInfo; + ISFSError ret = ISFS_ERROR_UNKNOWN; + + if (b->state == 0) { + info->stage = 1; + } + + if (b->state == 2) { + info->origFd = result; + info->stage = 2; + } + + if ((b->state == 2) && b->simpleFlag) { + b->state += 2; + } + else { + ++b->state; + } + + if (b->state == 1) { + ret = ISFS_GetAttrAsync((u8*)(info->origPath), &b->ownerId, &b->groupId, &b->attr, &b->ownerAcc, &b->groupAcc, &b->othersAcc, nandSafeOpenCallback, ctxt); + } + else if (b->state == 2) { + ret = ISFS_OpenAsync((u8*)(info->origPath), 1, nandSafeOpenCallback, ctxt); + } + else if (b->state == 3) { + char tmpDir[64]; + b->uniqNo = nandGetUniqueNumber(); + sprintf(tmpDir, "%s/%08x", "/tmp/sys", b->uniqNo); + ret = ISFS_CreateDirAsync((u8*)tmpDir, 0, 3, 0, 0, nandSafeOpenCallback, ctxt); + } + else if (b->state == 4) { + char filename[13]; + nandGetRelativeName(filename, info->origPath); + + if (!b->simpleFlag) { + info->stage = 3; + sprintf(info->tmpPath, "%s/%08x/%s", "/tmp/sys", b->uniqNo, filename); + } + else { + sprintf(info->tmpPath, "%s/%s", "/tmp/sys", filename); + } + + ret = ISFS_CreateFileAsync((u8*)info->tmpPath, b->attr, b->ownerAcc, b->groupAcc, b->othersAcc, nandSafeOpenCallback, ctxt); + } + else if (b->state == 5) { + info->stage = 4; + + if (info->accType == 2) { + ret = ISFS_OpenAsync((u8*)info->tmpPath, 2, nandSafeOpenCallback, ctxt); + } + else if (info->accType == 3) { + ret = ISFS_OpenAsync((u8*)info->tmpPath, 3, nandSafeOpenCallback, ctxt); + } + else { + ret = ISFS_ERROR_UNKNOWN; + } + } + else if (b->state == 6) { + info->fileDescriptor = result; + info->stage = 5; + b->state = 7; + ret = ISFS_ReadAsync(info->origFd, b->copyBuf, b->bufLength, nandSafeOpenCallback, ctxt); + } + else if (b->state == 7) { + ret = ISFS_ReadAsync(info->origFd, b->copyBuf, b->bufLength, nandSafeOpenCallback, ctxt); + } + else if (b->state == 8) { + if (result > 0) { + b->state = 6; + ret = ISFS_WriteAsync(info->fileDescriptor, b->copyBuf, (u32)result, nandSafeOpenCallback, ctxt); + } + else if (result == 0) { + ret = ISFS_SeekAsync(info->fileDescriptor, 0, 0, nandSafeOpenCallback, ctxt); + } + } + else if (b->state == 9) { + if (result == 0) { + if (!b->simpleFlag) { + info->mark = 3; + } + else { + info->mark = 5; + } + + ((NANDCallback)(b->callback))(nandConvertErrorCode(ISFS_ERROR_OK), b); + } + else { + ((NANDCallback)(b->callback))(nandConvertErrorCode(result), b); + } + + return; + } + + if (ret != ISFS_ERROR_OK) { + ((NANDCallback)(b->callback))(nandConvertErrorCode(ret), b); + } + } + else { + ((NANDCallback)(b->callback))(nandConvertErrorCode(result), b); + } +} + +void nandReadOpenCallback(ISFSError result, void* ctxt) { + NANDCommandBlock* b = (NANDCommandBlock*)ctxt; + + if (result >= 0) { + ((NANDFileInfo*)(b->fileInfo))->fileDescriptor = result; + ((NANDFileInfo*)(b->fileInfo))->stage = 2; + + if (!(b->simpleFlag)) { + ((NANDFileInfo*)(b->fileInfo))->mark = 3; + } + else { + ((NANDFileInfo*)(b->fileInfo))->mark = 5; + } + + ((NANDCallback)(b->callback))(NAND_RESULT_OK, b); + } + else { + ((NANDCallback)(b->callback))(nandConvertErrorCode(result), b); + } +} + +s32 NANDSafeCloseAsync(NANDFileInfo* info, NANDCallback cb, NANDCommandBlock* block) { + return nandSafeCloseAsync(info, cb, block, FALSE); +} + +s32 nandSafeCloseAsync(NANDFileInfo* info, NANDCallback cb, NANDCommandBlock* block, BOOL simple_flag) { + ISFSError err = ISFS_ERROR_UNKNOWN; + + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + if (!(((info->mark == 3) && !simple_flag) || ((info->mark == 5) && simple_flag))) { + return NAND_RESULT_INVALID; + } + + block->simpleFlag = simple_flag; + if (info->accType == 1) { + block->fileInfo = info; + block->callback = cb; + err = ISFS_CloseAsync(info->fileDescriptor, nandReadCloseCallback, block); + } + else if ((info->accType == 2) || (info->accType == 3)) { + block->fileInfo = info; + block->callback = cb; + block->state = 10; + err = ISFS_CloseAsync(info->fileDescriptor, nandSafeCloseCallback, block); + } + else { + err = ISFS_ERROR_INVALID; + } + + return nandConvertErrorCode(err); +} + +void nandSafeCloseCallback(ISFSError result, void* ctxt) { + NANDCommandBlock* b = (NANDCommandBlock*)ctxt; + + if (result == 0) { + NANDFileInfo* info = b->fileInfo; + ISFSError ret = ISFS_ERROR_UNKNOWN; + + if (b->state == 12) { + info->stage = 8; + } + + if ((b->state == 12) && b->simpleFlag) { + b->state += 2; + } + else { + ++b->state; + } + + if (b->state == 11) { + info->stage = 6; + ret = ISFS_CloseAsync(info->origFd, nandSafeCloseCallback, ctxt); + } + else if (b->state == 12) { + info->stage = 7; + ret = ISFS_RenameAsync((u8*)(info->tmpPath), (u8*)(info->origPath), nandSafeCloseCallback, ctxt); + } + else if (b->state == 13) { + char tmpdir[64] = ""; + nandGetParentDirectory(tmpdir, info->tmpPath); + ret = ISFS_DeleteAsync((u8*)tmpdir, nandSafeCloseCallback, ctxt); + } + else if (b->state == 14) { + if (!(b->simpleFlag)) { + info->stage = 9; + } + + info->mark = 4; + ((NANDCallback)(b->callback))(nandConvertErrorCode(result), b); + return; + } + + if (ret != 0) { + ((NANDCallback)(b->callback))(nandConvertErrorCode(ret), b); + } + } + else { + ((NANDCallback)(b->callback))(nandConvertErrorCode(result), b); + } +} + +static void nandReadCloseCallback(ISFSError result, void* ctxt) { + NANDCommandBlock* b = (NANDCommandBlock*)ctxt; + + if (result == 0) { + ((NANDFileInfo*)(b->fileInfo))->stage = 7; + ((NANDFileInfo*)(b->fileInfo))->mark = 4; + } + + ((NANDCallback)(b->callback))(nandConvertErrorCode(result), b); +} + +static void nandCloseCallback(ISFSError result, void* ctxt) { + NANDCommandBlock* b = (NANDCommandBlock*)ctxt; + + if (result == 0) { + ((NANDFileInfo*)(b->fileInfo))->stage = 7; + ((NANDFileInfo*)(b->fileInfo))->mark = 2; + } + + ((NANDCallback)(b->callback))(nandConvertErrorCode(result), b); +} \ No newline at end of file diff --git a/src/RVL_SDK/nand/NANDSecret.c b/src/RVL_SDK/nand/NANDSecret.c new file mode 100644 index 000000000..b227f57f0 --- /dev/null +++ b/src/RVL_SDK/nand/NANDSecret.c @@ -0,0 +1,13 @@ +#include +#include + +s32 NANDSecretGetUsage(const char* path, u32* fsBlock, u32* inode) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + else { + char absPath[64] = ""; + nandGenerateAbsPath(absPath, path); + return nandConvertErrorCode(ISFS_GetUsage((const u8*)absPath, fsBlock, inode)); + } +} \ No newline at end of file diff --git a/src/RVL_SDK/nand/nand.c b/src/RVL_SDK/nand/nand.c new file mode 100644 index 000000000..d9fbc83d0 --- /dev/null +++ b/src/RVL_SDK/nand/nand.c @@ -0,0 +1,470 @@ +#include +#include +#include + + +static BOOL nandInspectPermission(u8); +static void nandSplitPerm(u8, u32 *, u32 *, u32 *); +static void nandGetTypeCallback(ISFSError, void *); +static void nandGetStatusCallback(ISFSError, void *); + +ISFSError nandCreate(const char *path, const u8 perm, const u8 attr, + NANDCommandBlock *block, BOOL async_flag, + BOOL privilege_flag) { + char absPath[64] = ""; + u32 owner = 0, group = 0, others = 0; + nandGenerateAbsPath(absPath, path); + + if (!privilege_flag && nandIsPrivatePath(absPath)) { + return ISFS_ERROR_ACCESS; + } else if (!nandInspectPermission(perm)) { + return ISFS_ERROR_INVALID; + } else { + nandSplitPerm(perm, &owner, &group, &others); + + if (async_flag) { + return ISFS_CreateFileAsync((const u8 *)absPath, attr, owner, group, + others, nandCallback, block); + } else { + return ISFS_CreateFile((const u8 *)absPath, attr, owner, group, others); + } + } +} + +s32 NANDCreate(const char *path, const u8 perm, const u8 attr) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + return nandConvertErrorCode(nandCreate(path, perm, attr, NULL, FALSE, FALSE)); +} + +s32 NANDPrivateCreate(const char *path, u8 perm, u8 attr) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + return nandConvertErrorCode(nandCreate(path, perm, attr, NULL, FALSE, TRUE)); +} + +s32 NANDPrivateCreateAsync(const char *path, u8 perm, u8 attr, NANDCallback cb, + NANDCommandBlock *block) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + block->callback = cb; + return nandConvertErrorCode(nandCreate(path, perm, attr, block, TRUE, TRUE)); +} + +static ISFSError nandDelete(const char *path, NANDCommandBlock *block, + BOOL async_flag, BOOL privilege_flag) { + char absPath[64] = ""; + nandGenerateAbsPath(absPath, path); + + if (!privilege_flag && nandIsPrivatePath(absPath)) { + return ISFS_ERROR_ACCESS; + } else { + if (async_flag) { + return ISFS_DeleteAsync((const u8 *)absPath, nandCallback, block); + } else { + return ISFS_Delete((const u8 *)absPath); + } + } +} + +s32 NANDDelete(const char *path) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + return nandConvertErrorCode(nandDelete(path, NULL, FALSE, FALSE)); +} + +s32 NANDPrivateDelete(const char *path) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + return nandConvertErrorCode(nandDelete(path, NULL, FALSE, TRUE)); +} + +s32 NANDPrivateDeleteAsync(const char *path, NANDCallback cb, + NANDCommandBlock *block) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + block->callback = cb; + return nandConvertErrorCode(nandDelete(path, block, TRUE, TRUE)); +} + +s32 NANDRead(NANDFileInfo *info, void *buf, const u32 length) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + return nandConvertErrorCode( + ISFS_Read(info->fileDescriptor, (u8 *)buf, length)); +} + +s32 NANDReadAsync(NANDFileInfo *info, void *buf, const u32 length, + NANDCallback cb, NANDCommandBlock *block) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + block->callback = cb; + return nandConvertErrorCode(ISFS_ReadAsync(info->fileDescriptor, (u8 *)buf, + length, nandCallback, block)); +} + +s32 NANDWrite(NANDFileInfo *info, const void *buf, const u32 length) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + return nandConvertErrorCode( + ISFS_Write(info->fileDescriptor, (const u8 *)buf, length)); +} + +s32 NANDWriteAsync(NANDFileInfo *info, const void *buf, const u32 length, + NANDCallback cb, NANDCommandBlock *block) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + block->callback = cb; + return nandConvertErrorCode(ISFS_WriteAsync( + info->fileDescriptor, (const u8 *)buf, length, nandCallback, block)); +} + +static ISFSError nandSeek(const IOSFd fd, const s32 offset, const s32 whence, + NANDCommandBlock *block, const BOOL async_flag) { + u32 w = 0xFFFFFFFF; + + switch (whence) { + case 0: + w = 0; + break; + case 1: + w = 1; + break; + case 2: + w = 2; + break; + default: + break; + } + + if (async_flag) { + return ISFS_SeekAsync(fd, offset, w, nandCallback, block); + } else { + return ISFS_Seek(fd, offset, w); + } +} + +s32 NANDSeek(NANDFileInfo *info, const s32 offset, const s32 whence) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + return nandConvertErrorCode( + nandSeek(info->fileDescriptor, offset, whence, NULL, FALSE)); +} + +s32 NANDSeekAsync(NANDFileInfo *info, const s32 offset, const s32 whence, + NANDCallback cb, NANDCommandBlock *block) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + block->callback = cb; + return nandConvertErrorCode( + nandSeek(info->fileDescriptor, offset, whence, block, TRUE)); +} + +ISFSError nandCreateDir(const char *path, const u8 perm, const u8 attr, + NANDCommandBlock *block, const BOOL async_flag, + const BOOL privilege_flag) { + char absPath[64] = ""; + + nandGenerateAbsPath(absPath, path); + if (!privilege_flag && nandIsPrivatePath(absPath)) { + return ISFS_ERROR_ACCESS; + } else if (!nandInspectPermission(perm)) { + return ISFS_ERROR_INVALID; + } else { + u32 owner = 0; + u32 group = 0; + u32 others = 0; + nandSplitPerm(perm, &owner, &group, &others); + + if (async_flag) { + return ISFS_CreateDirAsync((const u8 *)absPath, attr, owner, group, + others, nandCallback, block); + } else { + return ISFS_CreateDir((const u8 *)absPath, attr, owner, group, others); + } + } +} + +s32 NANDPrivateCreateDir(const char *path, u8 perm, u8 attr) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + return nandConvertErrorCode( + nandCreateDir(path, perm, attr, NULL, FALSE, TRUE)); +} + +s32 NANDPrivateCreateDirAsync(const char *path, u8 perm, u8 attr, + NANDCallback cb, NANDCommandBlock *block) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + block->callback = cb; + return nandConvertErrorCode( + nandCreateDir(path, perm, attr, block, TRUE, TRUE)); +} + +ISFSError nandMove(const char *path, const char *destDir, + NANDCommandBlock *block, const BOOL async_flag, + const BOOL privilege_flag) { + char absOldPath[64] = ""; + char absNewPath[64] = ""; + char relativeName[13] = ""; + + nandGenerateAbsPath(absOldPath, path); + nandGetRelativeName(relativeName, absOldPath); + nandGenerateAbsPath(absNewPath, destDir); + if (strcmp(absNewPath, "/") == 0) { + sprintf(absNewPath, "/%s", relativeName); + } else { + strcat(absNewPath, "/"); + strcat(absNewPath, relativeName); + } + + if (!privilege_flag && + (nandIsPrivatePath(absOldPath) || nandIsPrivatePath(absNewPath))) { + return ISFS_ERROR_ACCESS; + } else { + if (async_flag) { + return ISFS_RenameAsync((const u8 *)absOldPath, (const u8 *)absNewPath, + nandCallback, block); + } else { + return ISFS_Rename((const u8 *)absOldPath, (const u8 *)absNewPath); + } + } +} + +s32 NANDMove(const char *path, const char *destDir) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + return nandConvertErrorCode(nandMove(path, destDir, NULL, FALSE, FALSE)); +} + +static ISFSError nandGetFileStatus(IOSFd fd, u32 *length, u32 *pos) { + ISFSFileStats fstat __attribute__((aligned(32))); + ISFSError result = ISFS_GetFileStats(fd, &fstat); + if (result == ISFS_ERROR_OK) { + if (length) { + *length = fstat.size; + } + if (pos) { + *pos = fstat.offset; + } + } + return result; +} + +s32 NANDGetLength(NANDFileInfo *info, u32 *length) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + return nandConvertErrorCode( + nandGetFileStatus(info->fileDescriptor, length, NULL)); +} + +void nandGetFileStatusAsyncCallback(ISFSError result, void *ctxt) { + NANDCommandBlock *b = (NANDCommandBlock *)ctxt; + ISFSFileStats *fstat = (ISFSFileStats *)OSRoundUp32B((u32)(b->absPath)); + + if (result == ISFS_ERROR_OK) { + if (b->length) { + *(b->length) = fstat->size; + } + if (b->pos) { + *(b->pos) = fstat->offset; + } + } + + ((NANDCallback)(b->callback))(nandConvertErrorCode(result), b); +} + +static ISFSError nandGetFileStatusAsync(IOSFd fd, NANDCommandBlock *block) { + ISFSError result = ISFS_ERROR_UNKNOWN; + ISFSFileStats *fstat = (ISFSFileStats *)OSRoundUp32B((u32)(block->absPath)); + return ISFS_GetFileStatsAsync(fd, fstat, nandGetFileStatusAsyncCallback, + block); +} + +s32 NANDGetLengthAsync(NANDFileInfo *info, u32 *length, NANDCallback cb, + NANDCommandBlock *block) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + block->callback = cb; + block->length = length; + block->pos = NULL; + return nandConvertErrorCode( + nandGetFileStatusAsync(info->fileDescriptor, block)); +} + +void nandComposePerm(u8 *perm, const u32 ownerAcc, const u32 groupAcc, + const u32 othersAcc) NO_INLINE { + u32 p = 0; + + if (ownerAcc & 1) { + p = p | 0x10; + } + + if (ownerAcc & 2) { + p = p | 0x20; + } + + if (groupAcc & 1) { + p = p | 4; + } + + if (groupAcc & 2) { + p = p | 8; + } + + if (othersAcc & 1) { + p = p | 1; + } + + if (othersAcc & 2) { + p = p | 2; + } + + *perm = (u8)p; +} + +static void nandSplitPerm(u8 perm, u32 *ownerAcc, u32 *groupAcc, + u32 *othersAcc) { + *ownerAcc = 0; + *groupAcc = 0; + *othersAcc = 0; + + if (perm & 0x10) { + *ownerAcc = *ownerAcc | 1; + } + + if (perm & 0x20) { + *ownerAcc = *ownerAcc | 2; + } + + if (perm & 4) { + *groupAcc = *groupAcc | 1; + } + + if (perm & 8) { + *groupAcc = *groupAcc | 2; + } + + if (perm & 1) { + *othersAcc = *othersAcc | 1; + } + + if (perm & 2) { + *othersAcc = *othersAcc | 2; + } +} + +ISFSError nandGetStatus(const char *path, NANDStatus *stat, + NANDCommandBlock *block, const BOOL async_flag, + const BOOL privilege_flag) { + char absPath[64] = ""; + + nandGenerateAbsPath(absPath, path); + if (!privilege_flag && nandIsUnderPrivatePath(absPath)) { + return ISFS_ERROR_ACCESS; + } else { + if (async_flag) { + return ISFS_GetAttrAsync( + (const u8 *)absPath, &(stat->ownerId), &(stat->groupId), + &(block->attr), &(block->ownerAcc), &(block->groupAcc), + &(block->othersAcc), nandGetStatusCallback, block); + } else { + u32 attr = 0, ownerAcc = 0, groupAcc = 0, othersAcc = 0; + ISFSError result = + ISFS_GetAttr((const u8 *)absPath, &stat->ownerId, &stat->groupId, + &attr, &ownerAcc, &groupAcc, &othersAcc); + if (result == ISFS_ERROR_OK) { + nandComposePerm(&stat->permission, ownerAcc, groupAcc, othersAcc); + stat->attribute = (u8)attr; + } + + return result; + } + } +} + +void nandGetStatusCallback(ISFSError result, void *ctxt) { + NANDCommandBlock *b = (NANDCommandBlock *)ctxt; + if (result == ISFS_ERROR_OK) { + NANDStatus *stat = (NANDStatus *)(b->status); + stat->attribute = (u8)(b->attr); + nandComposePerm(&(stat->permission), b->ownerAcc, b->groupAcc, + b->othersAcc); + } + ((NANDCallback)(b->callback))(nandConvertErrorCode(result), b); +} + +s32 NANDGetStatus(const char *path, NANDStatus *stat) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + return nandConvertErrorCode(nandGetStatus(path, stat, NULL, FALSE, FALSE)); +} + +s32 NANDPrivateGetStatus(const char *path, NANDStatus *stat) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + return nandConvertErrorCode(nandGetStatus(path, stat, NULL, FALSE, TRUE)); +} + +s32 NANDPrivateGetStatusAsync(const char *path, NANDStatus *stat, + NANDCallback cb, NANDCommandBlock *block) { + if (!nandIsInitialized()) { + return NAND_RESULT_FATAL_ERROR; + } + + block->callback = cb; + block->status = stat; + return nandConvertErrorCode(nandGetStatus(path, stat, block, TRUE, TRUE)); +} + +void NANDSetUserData(NANDCommandBlock *block, void *data) { + block->userData = data; +} + +void *NANDGetUserData(const NANDCommandBlock *block) { return block->userData; } + +static BOOL nandInspectPermission(const u8 perm) { + if (perm & 0x10) { + return TRUE; + } else { + return FALSE; + } +} \ No newline at end of file diff --git a/src/RVL_SDK/nwc24/NWC24Ipc.c b/src/RVL_SDK/nwc24/NWC24Ipc.c new file mode 100644 index 000000000..0c14fe31f --- /dev/null +++ b/src/RVL_SDK/nwc24/NWC24Ipc.c @@ -0,0 +1,72 @@ +#include +#include + +static BOOL NWC24iIsRequestPending = FALSE; + +IOSError CallbackAsyncIpc(IOSError, void *); + +NWC24Err NWC24iOpenResourceManager(const char* funcName, const char* path, IOSFd* pFd, u32 flags) { + if (!pFd) { + return NWC24_ERR_INVALID_VALUE; + } + + *pFd = IOS_Open(path, flags); + + if (*pFd < IOS_ERROR_OK) { + if (*pFd == IOS_ERROR_NOEXISTS) { + return NWC24_ERR_INPROGRESS; + } + else if (*pFd == IOS_ERROR_QFULL) { + return NWC24_ERR_BUSY; + } + else { + return NWC24_ERR_INTERNAL_IPC; + } + } + + return NWC24_OK; +} + +NWC24Err NWC24iCloseResourceManager(const char* funcName, IOSFd fd) { + IOSError err = IOS_Close(fd); + + if (err < IOS_ERROR_OK) { + return NWC24_ERR_INTERNAL_IPC; + } + + return NWC24_OK; +} + +NWC24Err NWC24iIoctlResourceManager(const char* funcName, IOSFd fd, s32 cmd, void* input, u32 input_bytes, void* output, u32 output_bytes) { + IOSError err = IOS_Ioctl(fd, cmd, input, input_bytes, output, output_bytes); + + if (err < IOS_ERROR_OK) { + return NWC24_ERR_INTERNAL_IPC; + } + + return NWC24_OK; +} + +NWC24Err NWC24iIoctlResourceManagerAsync(const char* funcName, IOSFd fd, s32 cmd, void* input, u32 input_bytes, void* output, u32 output_bytes, IOSError* ret) { + IOSError err = IOS_IoctlAsync(fd, cmd, input, input_bytes, output, output_bytes, CallbackAsyncIpc, (void*)ret); + + if (err < IOS_ERROR_OK) { + return NWC24_ERR_INTERNAL_IPC; + } + + NWC24iIsRequestPending = TRUE; + return NWC24_OK; +} + +BOOL NWC24iIsAsyncRequestPending(void) { + return NWC24iIsRequestPending; +} + +IOSError CallbackAsyncIpc(IOSError ret, void* ctxt) { + if (ctxt != NULL) { + *(IOSError*)ctxt = ret; + } + + NWC24iIsRequestPending = FALSE; + return IOS_ERROR_OK; +} \ No newline at end of file diff --git a/src/RVL_SDK/nwc24/NWC24Manage.c b/src/RVL_SDK/nwc24/NWC24Manage.c new file mode 100644 index 000000000..af7b025b7 --- /dev/null +++ b/src/RVL_SDK/nwc24/NWC24Manage.c @@ -0,0 +1,26 @@ +#include +#include + +static int Opened = 0; +static int Registered; + +const char* __NWC24Version = "<< RVL_SDK - NWC24 \trelease build: Dec 10 2007 10:02:25 (0x4199_60831) >>"; + +void NWC24iRegister(void) { + if (Registered == 0) { + OSRegisterVersion(__NWC24Version); + Registered = 1; + } +} + +int NWC24IsMsgLibOpened(void) { + return Opened == 1; +} + +int NWC24IsMsgLibOpenedByTool(void) { + return Opened == 2; +} + +int NWC24IsMsgLibOpenBlocking(void) { + return Opened == 3; +} \ No newline at end of file diff --git a/src/RVL_SDK/nwc24/NWC24Schedule.c b/src/RVL_SDK/nwc24/NWC24Schedule.c new file mode 100644 index 000000000..1a74cede9 --- /dev/null +++ b/src/RVL_SDK/nwc24/NWC24Schedule.c @@ -0,0 +1,205 @@ +#include +#include +#include + +static s32 nwc24ScdInitialized; +static OSMutex nwc24ScdCommandMutex; +static OSMutex nwc24ScdCounterMutex; + +static s32 nwc24ScdCommonBuffer[8] __attribute__ ((aligned(32))); +static s32 nwc24ScdCommonResult[8] __attribute__ ((aligned(32))); + +static s32 nwc24ScdSuspendCnt; +static s32 nwc24ScdOpenCnt; + +s32 ExecSuspendScheduler(void); +s32 ExecResumeScheduler(void); +s32 ExecNoParamCommand(const char *, s32, s32 *); + +s32 NWC24SuspendScheduler(void) { + s32 res; + + if (!(nwc24ScdInitialized & 1)) { + BOOL enabled = OSDisableInterrupts(); + + if (!(nwc24ScdInitialized & 1)) { + OSInitMutex(&nwc24ScdCommandMutex); + OSInitMutex(&nwc24ScdCounterMutex); + memset(nwc24ScdCommonBuffer, 0, 0x20); + memset(nwc24ScdCommonResult, 0, 0x20); + nwc24ScdInitialized |= 1; + } + + OSRestoreInterrupts(enabled); + } + + OSLockMutex(&nwc24ScdCounterMutex); + res = ExecSuspendScheduler(); + + if (res >= 0) { + ++nwc24ScdSuspendCnt; + res = res - nwc24ScdOpenCnt; + } + + OSUnlockMutex(&nwc24ScdCounterMutex); + return res; +} + +static void InitScdMutex(void) { + BOOL enabled = OSDisableInterrupts(); + + if (!(nwc24ScdInitialized & 1)) { + OSInitMutex(&nwc24ScdCommandMutex); + OSInitMutex(&nwc24ScdCounterMutex); + memset(nwc24ScdCommonBuffer, 0, sizeof(nwc24ScdCommonBuffer)); + memset(nwc24ScdCommonResult, 0, sizeof(nwc24ScdCommonResult)); + nwc24ScdInitialized |= 1; + } + + OSRestoreInterrupts(enabled); +} + +static void LockCounters(void) { + if (!(nwc24ScdInitialized & 1)) { + InitScdMutex(); + } + + OSLockMutex(&nwc24ScdCounterMutex); +} + +static void UnlockCounters(void) { + OSUnlockMutex(&nwc24ScdCounterMutex); +} + +s32 NWC24ResumeScheduler(void) { + s32 suspend; + + LockCounters(); + + if (nwc24ScdOpenCnt > 0 && nwc24ScdSuspendCnt == 0) { + suspend = 0; + } + else { + suspend = ExecResumeScheduler(); + if (nwc24ScdSuspendCnt > 0) { + --nwc24ScdSuspendCnt; + suspend -= nwc24ScdOpenCnt; + } + } + + UnlockCounters(); + return suspend; +} + +NWC24Err NWC24iSetScriptMode(s32 mode) { + IOSFd fId; + NWC24Err err; + OSThread* thread = OSGetCurrentThread(); + + if (thread == 0) { + err = NWC24_ERR_FATAL; + } + else if (NWC24IsMsgLibOpened() || NWC24IsMsgLibOpenedByTool()) { + err = NWC24_ERR_LIB_OPENED; + } + else if (NWC24IsMsgLibOpenBlocking()) { + err = NWC24_ERR_BUSY; + } + else { + err = NWC24_OK; + } + + if (err < 0) { + return err; + } + else { + NWC24Err resErr; + + LockCounters(); + memset(nwc24ScdCommonBuffer, 0, 0x20); + resErr = NWC24iOpenResourceManager(__FUNCTION__, "/dev/net/kd/request", &fId, 0); + + if (resErr >= 0) { + nwc24ScdCommonBuffer[0] = mode; + resErr = NWC24iIoctlResourceManager(__FUNCTION__, fId, 0x22, nwc24ScdCommonBuffer, 0x20, nwc24ScdCommonResult, 0x20); + + if (resErr >= 0) { + resErr = nwc24ScdCommonResult[0]; + } + + { + + s32 tmp = NWC24iCloseResourceManager(__FUNCTION__, fId); + + if (resErr > 0) { + resErr = tmp; + } + } + } + + UnlockCounters(); + return resErr; + } + + return err; +} + +#pragma auto_inline off +s32 ExecSuspendScheduler(void) { + return ExecNoParamCommand(NULL, 1, NULL); +} + +s32 ExecResumeScheduler(void) { + return ExecNoParamCommand(NULL, 3, NULL); +} +#pragma auto_inline reset + +s32 ExecNoParamCommand(const char* funcName, s32 cmd, s32* event) { + IOSFd fId; + s32 res; + OSThread* thread = OSGetCurrentThread(); + + if (thread == 0) { + return -1; + } + + if (!(nwc24ScdInitialized & 1)) { + BOOL en = OSDisableInterrupts(); + + if (!(nwc24ScdInitialized & 1)) { + OSInitMutex(&nwc24ScdCommandMutex); + OSInitMutex(&nwc24ScdCounterMutex); + memset(nwc24ScdCommonBuffer, 0, 0x20); + memset(nwc24ScdCommonResult, 0, 0x20); + nwc24ScdInitialized |= 1; + } + + OSRestoreInterrupts(en); + } + + OSLockMutex(&nwc24ScdCommandMutex); + res = NWC24iOpenResourceManager(funcName, "/dev/net/kd/request", &fId, 0); + if (res >= 0) { + res = NWC24iIoctlResourceManager(funcName, fId, cmd, NULL, 0, nwc24ScdCommonResult, 0x20); + + if (res >= 0) { + res = nwc24ScdCommonResult[0]; + if (res == -2 || res == -33) { + if (event != NULL) { + *event = nwc24ScdCommonResult[1]; + } + } + } + + { + s32 tmp = NWC24iCloseResourceManager(funcName, fId); + + if (tmp < 0) { + res = tmp; + } + } + } + + OSUnlockMutex(&nwc24ScdCommandMutex); + return res; +} \ No newline at end of file diff --git a/src/RVL_SDK/nwc24/NWC24System.c b/src/RVL_SDK/nwc24/NWC24System.c new file mode 100644 index 000000000..d0abe8fe1 --- /dev/null +++ b/src/RVL_SDK/nwc24/NWC24System.c @@ -0,0 +1,92 @@ +#include +#include + +static s32 nwc24ShtFd = -1; +static s32 nwc24ShtRetryRest = 0; + +static OSShutdownFunctionInfo ShutdownFuncInfo; + +BOOL NWC24Shutdown(BOOL, u32); + +NWC24Err NWC24iPrepareShutdown(void) { + NWC24Err result = NWC24_OK; + u32 status; + + NWC24iRegister(); + ShutdownFuncInfo.func = NWC24Shutdown; + ShutdownFuncInfo.priority = 110; + OSRegisterShutdownFunction(&ShutdownFuncInfo); + + if (nwc24ShtFd < 0) { + result = NWC24iOpenResourceManager(__FUNCTION__, "/dev/net/kd/request", &nwc24ShtFd, 1); + } + + nwc24ShtRetryRest = 5; + + while (1) { + status = SCCheckStatus(); + + if (status == 2) { + break; + } + + if (status != 1) { + SCIdleModeInfo info; + SCGetIdleMode(&info); + __OSSetIdleLEDMode(info.led); + break; + } + } + + if ((OSGetAppType() & 0xFF) == 0x40u) { + NWC24iSetScriptMode(1); + } + + return result; +} + +static NWC24Err NWC24iRequestShutdown(u32 event, IOSError* ret) { + NWC24Err result = NWC24_OK; + NWC24Err resultClose = NWC24_OK; + static s32 shtBuffer[8] __attribute__ ((aligned(32))); + static s32 shtResult[8] __attribute__ ((aligned(32))); + + shtBuffer[0] = (s32)event; + return NWC24iIoctlResourceManagerAsync(__FUNCTION__, nwc24ShtFd, 40, (void*)shtBuffer, sizeof(shtBuffer), (void*)shtResult, sizeof(shtResult), ret); +} + +BOOL NWC24Shutdown(BOOL final, u32 event) { + static BOOL shuttingdwn = FALSE; + static IOSError result = IOS_ERROR_OK; + + if (final) { + return TRUE; + } + + if (shuttingdwn) { + if (NWC24iIsAsyncRequestPending()) { + return FALSE; + } + else { + if (result >= 0) { + return TRUE; + } + else { + if (nwc24ShtRetryRest > 0) { + shuttingdwn = FALSE; + --nwc24ShtRetryRest; + } + else { + return TRUE; + } + } + } + } + else { + if (NWC24iRequestShutdown(event, &result) >= NWC24_OK) { + shuttingdwn = TRUE; + } + } + + return FALSE; +} \ No newline at end of file diff --git a/src/RVL_SDK/nwc24/NWC24Time.c b/src/RVL_SDK/nwc24/NWC24Time.c new file mode 100644 index 000000000..2196e5b74 --- /dev/null +++ b/src/RVL_SDK/nwc24/NWC24Time.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include + +static s32 nwc24TimeInitialized; +static OSMutex nwc24TimeCommandMutex; +static s32 nwc24TimeCommonBuffer[8] __attribute__((align(32))); +static s32 nwc24TimeCommonResult[8] __attribute__((align(32))); +static s32 nwc24ShtFd = -1; +static s32 nwc24ShtRetryRest = 0; +static BOOL NWC24iIsRequestPending = FALSE; +static OSShutdownFunctionInfo ShutdownFuncInfo; + +static NWC24Err GetRTC(u32* rtcCounter) { + OSTime time; + u32 bias, status; + + do { + status = SCCheckStatus(); + if (status == 2) { + return NWC24_ERR_FATAL; + } + } while (status != 0); + + bias = SCGetCounterBias(); + time = OSGetTime(); + *rtcCounter = (u32)(OSTicksToSeconds(time) - bias); + return NWC24_OK; +} + +NWC24Err NWC24iSetRtcCounter(u32 rtcCounter, u32 flags) { + NWC24Err result = NWC24_OK; + NWC24Err resultClose = NWC24_OK; + IOSFd fd; + + if (OSGetCurrentThread() != NULL) { + result = 0; + } + else { + result = -1; + } + + if (result < NWC24_OK) { + return result; + } + + { + if (nwc24TimeInitialized == 0) { + BOOL en = OSDisableInterrupts(); + + if (nwc24TimeInitialized == 0) { + OSInitMutex(&nwc24TimeCommandMutex); + memset(nwc24TimeCommonBuffer, 0, 0x20); + memset(nwc24TimeCommonResult, 0, 0x20); + nwc24TimeInitialized = TRUE; + } + + OSRestoreInterrupts(en); + } + + OSLockMutex(&nwc24TimeCommandMutex); + + result = NWC24iOpenResourceManager(__FUNCTION__, "/dev/net/kd/time", &fd, 0); + + if (result >= NWC24_OK) { + nwc24TimeCommonBuffer[0] = rtcCounter; + nwc24TimeCommonBuffer[1] = flags; + result = NWC24iIoctlResourceManager(__FUNCTION__, fd, 23, nwc24TimeCommonBuffer, 0x20, nwc24TimeCommonResult, 0x20); + + if (result >= NWC24_OK) { + result = nwc24TimeCommonResult[0]; + } + + resultClose = NWC24iCloseResourceManager(__FUNCTION__, fd); + + if (result >= NWC24_OK) { + result = resultClose; + } + + + } + + OSUnlockMutex(&nwc24TimeCommandMutex); + return result; + } +} + +NWC24Err NWC24iSynchronizeRtcCounter(BOOL forceSave) { + NWC24Err err; + u32 rtcCounter; + + err = GetRTC(&rtcCounter); + + if (err != NWC24_OK) { + return err; + } + + return NWC24iSetRtcCounter(rtcCounter, forceSave ? 1 : 0); +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OS.c b/src/RVL_SDK/os/OS.c new file mode 100644 index 000000000..2b6cb9a8d --- /dev/null +++ b/src/RVL_SDK/os/OS.c @@ -0,0 +1,881 @@ +#include +#include +#include +#include +#include +#include +#include +#include "private/flipper.h" + +#include <__ppc_eabi_linker.h> + +static __OSExceptionHandler* OSExceptionTable; + +static u32 __OSExceptionLocations[] = { + 0x100, + 0x200, + 0x300, + 0x400, + 0x500, + 0x600, + 0x700, + 0x800, + 0x900, + 0xC00, + 0xD00, + 0xF00, + 0x1300, + 0x1400, + 0x1700 +}; + + +void __OSEVStart(void); +void __OSEVEnd(void); +void __OSEVSetNumber(void); +void __DBVECTOR(void); +void __OSDBINTSTART(void); +void __OSDBINTEND(void); +void __OSDBJUMPSTART(void); +void __OSDBJUMPEND(void); + +static f64 ZeroF; +static f32 ZeroPS[2]; + +static DVDDriveInfo DriveInfo; +static DVDCommandBlock DriveBlock; +static char GameNameBuffer[5]; +__declspec(weak) BOOL __OSIsGcam = FALSE; +OSTime __OSStartTime; +BOOL __OSInIPL = FALSE; +BOOL __OSInNandBoot = FALSE; +extern BOOL __OSInReboot; +BOOL __OSIsDiag = FALSE; + +static OSBootInfo* volatile BootInfo; + +static u32* BI2DebugFlag; +static u32 BI2DebugFlagHolder; + +vu16 __OSDeviceCode : (OS_BASE_CACHED | 0x30E6); + +extern u8 __ArenaHi[]; +extern u8 __ArenaLo[]; +extern u32 __DVDLongFileNameFlag; +extern u32 __PADSpec; +static BOOL AreWeInitialized = FALSE; +OSExecParams __OSRebootParams; + +static void OSExceptionInit(void); +void OSDefaultExceptionHandler( __OSException exception, OSContext* context ); + +static const char* __OSVersion = "<< RVL_SDK - OS \trelease build: Jan 30 2008 01:38:43 (0x4199_60831) >>"; + +asm void __OSFPRInit(void) { + nofralloc + mfmsr r3 + ori r3, r3, 0x2000 + mtmsr r3 + + mfspr r3, 0x398 + rlwinm. r3, r3, 3, 31, 31 + beq skipPairedSingleInit + + lis r3, ZeroPS@ha + addi r3, r3, ZeroPS@l + psq_l fp0, 0(r3), 0, 0 + ps_mr fp1, fp0 + ps_mr fp2, fp0 + ps_mr fp3, fp0 + ps_mr fp4, fp0 + ps_mr fp5, fp0 + ps_mr fp6, fp0 + ps_mr fp7, fp0 + ps_mr fp8, fp0 + ps_mr fp9, fp0 + ps_mr fp10, fp0 + ps_mr fp11, fp0 + ps_mr fp12, fp0 + ps_mr fp13, fp0 + ps_mr fp14, fp0 + ps_mr fp15, fp0 + ps_mr fp16, fp0 + ps_mr fp17, fp0 + ps_mr fp18, fp0 + ps_mr fp19, fp0 + ps_mr fp20, fp0 + ps_mr fp21, fp0 + ps_mr fp22, fp0 + ps_mr fp23, fp0 + ps_mr fp24, fp0 + ps_mr fp25, fp0 + ps_mr fp26, fp0 + ps_mr fp27, fp0 + ps_mr fp28, fp0 + ps_mr fp29, fp0 + ps_mr fp30, fp0 + ps_mr fp31, fp0 + +skipPairedSingleInit: + lfd fp0, ZeroF + fmr fp1, fp0 + fmr fp2, fp0 + fmr fp3, fp0 + fmr fp4, fp0 + fmr fp5, fp0 + fmr fp6, fp0 + fmr fp7, fp0 + fmr fp8, fp0 + fmr fp9, fp0 + fmr fp10, fp0 + fmr fp11, fp0 + fmr fp12, fp0 + fmr fp13, fp0 + fmr fp14, fp0 + fmr fp15, fp0 + fmr fp16, fp0 + fmr fp17, fp0 + fmr fp18, fp0 + fmr fp19, fp0 + fmr fp20, fp0 + fmr fp21, fp0 + fmr fp22, fp0 + fmr fp23, fp0 + fmr fp24, fp0 + fmr fp25, fp0 + fmr fp26, fp0 + fmr fp27, fp0 + fmr fp28, fp0 + fmr fp29, fp0 + fmr fp30, fp0 + fmr fp31, fp0 + + mtfsf 0xFF, fp0 + blr +} + +void __OSGetIOSRev(OSIOSRev* rev) { + u32 iosVer, iosBuild; + iosVer = *(u32*)OSPhysicalToUncached(0x3140); + iosBuild = *(u32*)OSPhysicalToUncached(0x3144); + + rev->reserved = ((iosVer >> 24) & 0xFF); + rev->major = ((iosVer >> 16) & 0xFF); + rev->minor = ((iosVer >> 8) & 0xFF); + rev->micro = (iosVer & 0xFF); + + rev->month = (((iosBuild >> 20) & 0xF) * 10 + ((iosBuild >> 16) & 0xF)); + rev->date = (((iosBuild >> 12) & 0xF) * 10 + ((iosBuild >> 8) & 0xF)); + rev->year = (((iosBuild >> 4) & 0xF) * 10 + (iosBuild & 0xF) + 2000); + return; +} + +u32 __OSGetHollywoodRev(void) { + return (*(u32*)OSPhysicalToCached((0x3138))); +} + +u32 OSGetConsoleType(void) { + u32 hwRev; + u32 gddrSize; + + if (BootInfo == NULL || BootInfo->consoleType == 0) { + return 0x10000002; + } + + hwRev = __OSGetHollywoodRev(); + + if (__OSDeviceCode & 0x8000) { + switch (__OSDeviceCode & ~0x8000) { + case 2: + case 3: + case 0x203: + switch (hwRev) { + case 0: + return 0x10; + case 1: + return 0x11; + case 2: + return 0x12; + case 0x10: + return 0x20; + case 0x11: + return 0x21; + } + + if (hwRev > 0x11) { + return 0x21; + } + + case 0x202: + case 0x201: + switch (hwRev) { + case 0: + return 0x10000010; + case 1: + return 0x10000011; + case 2: + return 0x10000012; + case 0x10: + return 0x10000020; + case 0x11: + return 0x10000021; + } + + if (hwRev > 0x11) { + return 0x10000031; + } + + case 0x300: + return 0x100; + + default: + break; + } + } + + gddrSize = OSGetPhysicalMem2Size(); + + switch (hwRev) { + case 0: + if (gddrSize == 0x4000000) { + return 0x10; + } + else { + return 0x10000010; + } + + case 0x1: + if (gddrSize == 0x4000000) { + return 0x11; + } + else { + return 0x10000011; + } + + case 0x2: + if (gddrSize == 0x4000000) { + return 0x12; + } + else { + return 0x10000012; + } + + case 0x10: + if (gddrSize == 0x4000000) { + return 0x20; + } + else { + return 0x10000020; + } + + case 0x11: + if (gddrSize == 0x4000000) { + return 0x21; + } + else { + return 0x10000021; + } + } + + if (hwRev > 0x11) { + if (gddrSize == 0x4000000) { + return 0x21; + } + else { + return 0x10000031; + } + } + + return BootInfo->consoleType; +} + +static void MemClear(void *base, u32 size) { + void* lastBase = (size > 0x40000) ? (void*)((u32)base + size - 0x40000) : base; + DCZeroRange(base, size); + DCFlushRange(lastBase, 0x40000); +} + +static void ClearArena(void) NO_INLINE { + if (!OSIsRestart()) { + MemClear(OSGetArenaLo(), (u32)OSGetArenaHi() - (u32)OSGetArenaLo()); + } + else { + if (__OSRebootParams.regionStart == NULL || !OSIsMEM1Region((void*)__OSRebootParams.regionStart)) { + MemClear(OSGetArenaLo(), (u32)OSGetArenaHi() - (u32)OSGetArenaLo()); + } + else { + if ((u32)OSGetArenaLo() < (u32)__OSRebootParams.regionStart) { + if ((u32)OSGetArenaHi() <= (u32)__OSRebootParams.regionStart) { + MemClear(OSGetArenaLo(), (u32)OSGetArenaHi() - (u32)OSGetArenaLo()); + } + else { + MemClear(OSGetArenaLo(), (u32)__OSRebootParams.regionStart - (u32)OSGetArenaLo()); + + if ((u32)OSGetArenaHi() > (u32)__OSRebootParams.regionEnd) { + MemClear(__OSRebootParams.regionEnd, (u32)OSGetArenaHi() - (u32)__OSRebootParams.regionEnd); + } + } + } + } + } +} + +static void ClearMEM2Arena(void) NO_INLINE { + if (!OSIsRestart()) { + MemClear(OSGetMEM2ArenaLo(), (u32)OSGetMEM2ArenaHi() - (u32)OSGetMEM2ArenaLo()); + } + else { + if (__OSRebootParams.regionStart == NULL || !OSIsMEM2Region((void*)__OSRebootParams.regionStart)) { + MemClear(OSGetMEM2ArenaLo(), (u32)OSGetMEM2ArenaHi() - (u32)OSGetMEM2ArenaLo()); + } + else { + if ((u32)OSGetMEM2ArenaLo() < (u32)__OSRebootParams.regionStart) { + if ((u32)OSGetMEM2ArenaHi() <= (u32)__OSRebootParams.regionStart) { + MemClear(OSGetMEM2ArenaLo(), (u32)OSGetMEM2ArenaHi() - (u32)OSGetMEM2ArenaLo()); + } + else { + MemClear(OSGetMEM2ArenaLo(), (u32)__OSRebootParams.regionStart - (u32)OSGetMEM2ArenaLo()); + + if ((u32) OSGetMEM2ArenaHi() > (u32)__OSRebootParams.regionEnd) { + MemClear(__OSRebootParams.regionEnd, (u32)OSGetMEM2ArenaHi() - (u32)__OSRebootParams.regionEnd); + } + } + } + } + } +} + +void InquiryCallback(s32 res, DVDCommandBlock *block) { + switch (block->state) { + case 0: + __OSDeviceCode = (u16)(0x8000 | DriveInfo.deviceCode); + break; + default: + __OSDeviceCode = 1; + break; + } +} + +static void CheckTargets(void) { + switch (*(u8*)OSPhysicalToCached(0x315C)) { + case 0x80: + break; + case 0x81: + OSReport("OS ERROR: boot program is not for RVL target. Please use correct boot program.\n"); + OSPanic(__FILE__, 0x47E, "Failed to run app"); + break; + default: + break; + } + + switch (*(u8*)OSPhysicalToCached(0x315D)) { + case 0x80: + break; + case 0x81: + OSReport("OS ERROR: apploader[D].img is not for RVL target. Please use correct apploader[D].img.\n"); + OSPanic(__FILE__, 0x490, "Failed to run app"); + break; + default: + break; + } +} + +static void DisableWriteGatherPipe(void) { + u32 hid2 = PPCMfhid2(); + hid2 &= 0xBFFFFFFF; + PPCMthid2(hid2); +} + +static void ReportOSInfo(void) { + u32 consoleType; + u32 sysMemSize; + OSIOSRev ios; + + OSReport("\nRevolution OS\n"); + OSReport("Kernel built : %s %s\n", "Jan 30 2008", "01:38:43"); + OSReport("Console Type : " ); + + consoleType = OSGetConsoleType(); + + switch (consoleType & 0xF0000000) { + case 0: + switch (consoleType) { + case 0x11: + OSReport("Pre-production board 1\n"); + break; + case 0x12: + OSReport("Pre-production board 2-1\n"); + break; + case 0x20: + OSReport("Pre-production board 2-2\n"); + break; + case 0x100: + OSReport("RVA 1\n"); + break; + default: + OSReport("Retail %d\n", consoleType); + break; + } + + break; + + case 0x10000000: + switch (consoleType) { + case 0x10000021: + OSReport("NDEV 2.1\n"); + break; + case 0x10000020: + OSReport("NDEV 2.0\n"); + break; + case 0x10000012: + OSReport("NDEV 1.2\n"); + break; + case 0x10000011: + OSReport("NDEV 1.1\n"); + break; + case 0x10000010: + OSReport("NDEV 1.0\n"); + break; + case 0x10000008: + OSReport("Revolution Emulator\n"); + break; + default: + OSReport("Emulation platform (%08x)\n", consoleType); + break; + } + + break; + + case 0x20000000: + OSReport("TDEV-based emulation HW%d\n", (consoleType & ~0xF0000000) - 3); + break; + default: + OSReport("%08x\n", consoleType); + break; + } + + + __OSGetIOSRev(&ios); + OSReport("Firmware : %d.%d.%d ", ios.major, ios.minor, ios.micro); + OSReport("(%d/%d/%d)\n", ios.month, ios.date, ios.year); + sysMemSize = (OSGetConsoleSimulatedMem1Size() + OSGetConsoleSimulatedMem2Size()); + OSReport("Memory %d MB\n", sysMemSize/(1024*1024)); + + OSReport("MEM1 Arena : 0x%x - 0x%x\n", OSGetMEM1ArenaLo(), OSGetMEM1ArenaHi()); + OSReport("MEM2 Arena : 0x%x - 0x%x\n", OSGetMEM2ArenaLo(), OSGetMEM2ArenaHi()); +} + +void OSInit(void) { + void* bi2StartAddr; + void* arenaAddr; + + if (AreWeInitialized != FALSE) { + return; + } + + AreWeInitialized = TRUE; + __OSStartTime = __OSGetSystemTime(); + OSDisableInterrupts(); + __OSGetExecParams(&__OSRebootParams); + + PPCMtmmcr0(0); + PPCMtmmcr1(0); + PPCMtpmc1(0); + PPCMtpmc2(0); + PPCMtpmc3(0); + PPCMtpmc4(0); + PPCMthid4(0x83900000); + PPCDisableSpeculation(); + PPCSetFpNonIEEEMode(); + + BootInfo = (OSBootInfo*)OSPhysicalToCached(0); + BI2DebugFlag = 0; + __DVDLongFileNameFlag = 0; + + bi2StartAddr = *(void**)OSPhysicalToCached(0xF4); + + if (bi2StartAddr != 0) { + BI2DebugFlag = (u32*)((u32)bi2StartAddr + 0xC); + __PADSpec = *(u32*)((u32)bi2StartAddr + 0x24); + + *(u8*)OSPhysicalToCached(0x30E8) = (u8)*BI2DebugFlag; + *(u8*)OSPhysicalToCached(0x30E9) = (u8)__PADSpec; + } + else { + if (((OSBootInfo*)OSPhysicalToCached(0))->arenaHi != NULL) { + BI2DebugFlagHolder = (u32)*(u8*)OSPhysicalToCached(0x30E8); + BI2DebugFlag = &BI2DebugFlagHolder; + __PADSpec = (u32)*(u8*)OSPhysicalToCached(0x30E9); + } + } + + __DVDLongFileNameFlag = 1; + + arenaAddr = (void*)*(u32*)OSPhysicalToCached(0x310C); + + if (arenaAddr == NULL) { + if (OSIsMEM1Region((void*)__ArenaLo)) { + void* tmp = BootInfo->arenaLo; + arenaAddr = tmp == NULL ? (void*)__ArenaLo : tmp; + + if (!BootInfo->arenaLo&& (BI2DebugFlag && (*(BI2DebugFlag) < 2))) { + arenaAddr = (void*)OSRoundUp32B(_stack_addr); + } + } + else { + arenaAddr = (void*)0x80004000; + } + } + + OSSetMEM1ArenaLo(arenaAddr); + + arenaAddr = (void*)*(u32*)OSPhysicalToCached(0x3110); + + if (arenaAddr == NULL) { + void* tmp = BootInfo->arenaHi; + arenaAddr = tmp == NULL ? (void*)__ArenaHi : tmp; + } + + OSSetMEM1ArenaHi(arenaAddr); + + arenaAddr = (void*)*(u32*)OSPhysicalToCached(0x3124); + + if (arenaAddr != 0) { + if (OSIsMEM2Region((void*)__ArenaLo)) { + arenaAddr = (void*)__ArenaLo; + + if ((BI2DebugFlag && (*(BI2DebugFlag) < 2))) { + arenaAddr = (void*)OSRoundUp32B(_stack_addr); + } + } + else { + if ((u32)arenaAddr >= 0x90000000 && (u32)arenaAddr < 0x90000800) { + arenaAddr = (void*)0x90000800; + } + } + + OSSetMEM2ArenaLo(arenaAddr); + } + + + arenaAddr = (void*)*(u32*)OSPhysicalToCached(0x3128); + + if (arenaAddr != 0) { + OSSetMEM2ArenaHi(arenaAddr); + } + + __OSInitIPCBuffer(); + OSExceptionInit(); + __OSInitSystemCall(); + __OSInitAlarm(); + __OSModuleInit(); + __OSInterruptInit(); + __OSContextInit(); + __OSCacheInit(); + EXIInit(); + SIInit(); + __OSInitSram(); + __OSThreadInit(); + __OSInitAudioSystem(); + DisableWriteGatherPipe(); + + if (!__OSInIPL) { + __OSInitMemoryProtection(); + } + + ReportOSInfo(); + OSRegisterVersion(__OSVersion); + + if (BI2DebugFlag && (*(BI2DebugFlag) >= 2)) { + EnableMetroTRKInterrupts(); + } + + if (!__OSInNandBoot && !__OSInReboot) { + ClearArena(); + ClearMEM2Arena(); + } + + OSEnableInterrupts(); + IPCCltInit(); + + if (!__OSInNandBoot && !__OSInReboot) { + __OSInitSTM(); + + SCInit(); + + /* do nothing until SC is not busy */ + while (SCCheckStatus() == 1) { + + } + + __OSInitNet(); + } + + if (!__OSInIPL) { + CheckTargets(); + DVDInit(); + + if (__OSIsGcam) { + __OSDeviceCode = (u16)(0x8000 | 0x1000); + } + else if (!__OSDeviceCode) { + DCInvalidateRange(&DriveInfo, sizeof(DriveInfo)); + DVDInquiryAsync(&DriveBlock, &DriveInfo, InquiryCallback); + } + + if (OSGetAppType() == 0x80 && !__OSInReboot) { + if (!__DVDCheckDevice()) { + OSReturnToMenu(); + } + } + } + + if (!__OSInIPL && !__OSInNandBoot) { + __OSInitPlayTime(); + } + + if (!__OSInIPL && !__OSInNandBoot && !__OSInReboot) { + __OSStartPlayRecord(); + } +} + +static void OSExceptionInit(void) { + __OSException exception; + void* destAddr; + u32* opCodeAddr; + u32 oldOpCode; + u8* handlerStart; + u32 handlerSize; + + opCodeAddr = (u32*)__OSEVSetNumber; + oldOpCode = *opCodeAddr; + handlerStart = (u8*)__OSEVStart; + handlerSize = (u32)((u8*)__OSEVEnd - (u8*)__OSEVStart); + destAddr = (void*)OSPhysicalToCached(0x60); + + if (*(u32*)destAddr == 0) { + DBPrintf("Installing OSDBIntegrator\n"); + memcpy(destAddr, (void*)__OSDBINTSTART, (u32)__OSDBINTEND - (u32)__OSDBINTSTART); + DCFlushRangeNoSync(destAddr, (u32)__OSDBINTEND - (u32)__OSDBINTSTART); + __sync(); + ICInvalidateRange(destAddr, (u32)__OSDBINTEND - (u32)__OSDBINTSTART); + } + + for (exception = 0; exception < 15; exception++) { + if (BI2DebugFlag && (*BI2DebugFlag >= 2) && __DBIsExceptionMarked(exception)) { + DBPrintf(">>> OSINIT: exception %d commandeered by TRK\n", exception); + continue; + } + + *opCodeAddr = oldOpCode | exception; + + if (__DBIsExceptionMarked(exception)) { + DBPrintf(">>> OSINIT: exception %d vectored to debugger\n", exception); + memcpy((void*)__DBVECTOR, (void*)__OSDBJUMPSTART, (u32)__OSDBJUMPEND - (u32)__OSDBJUMPSTART); + } + else { + u32* ops = (u32*)__DBVECTOR; + int cb; + + for (cb = 0; cb < (u32)__OSDBJUMPEND - (u32)__OSDBJUMPSTART; cb += 4) { + // set op to NOP + *ops++ = 0x60000000; + } + } + + destAddr = (void*)OSPhysicalToCached(__OSExceptionLocations[exception]); + memcpy(destAddr, handlerStart, handlerSize); + DCFlushRangeNoSync(destAddr, handlerSize); + __sync(); + ICInvalidateRange(destAddr, handlerSize); + } + + OSExceptionTable = OSPhysicalToCached(0x3000); + + for (exception = 0; exception < 15; exception++) { + __OSSetExceptionHandler(exception, OSDefaultExceptionHandler); + } + + *opCodeAddr = oldOpCode; + DBPrintf("Exceptions initialized...\n"); +} + +static asm void __OSDBIntegrator(void) { + nofralloc + +entry __OSDBINTSTART + li r5, 0x40 + mflr r3 + stw r3, 0xC(r5) + lwz r3, 0x8(r5) + oris r3, r3, 0x8000 + mtlr r3 + li r3, 0x30 + mtmsr r3 + blr + +entry __OSDBINTEND +} + +static asm void __OSDBJump(void) { + nofralloc +entry __OSDBJUMPSTART + bla 0x60 +entry __OSDBJUMPEND +} + +__OSExceptionHandler __OSSetExceptionHandler(__OSException ex, __OSExceptionHandler handler) { + __OSExceptionHandler cur; + cur = OSExceptionTable[ex]; + OSExceptionTable[ex] = handler; + return cur; +} + +__OSExceptionHandler __OSGetExceptionHandler(__OSException ex) { + return OSExceptionTable[ex]; +} + +static asm void OSExceptionVector(void) { + nofralloc +entry __OSEVStart + mtsprg 0, r4 + lwz r4, 0xC0 + stw r3, 12(r4) + mfsprg r3, 0 + stw r3, 16(r4) + stw r5, 20(r4) + lhz r3, 418(r4) + ori r3, r3, 2 + sth r3, 418(r4) + + mfcr r3 + stw r3, 128(r4) + mflr r3 + stw r3, 132(r4) + mfctr r3 + stw r3, 136(r4) + mfxer r3 + stw r3, 140(r4) + mfsrr0 r3 + stw r3, 408(r4) + mfsrr1 r3 + stw r3, 412(r4) + mr r5, r3 + +entry __DBVECTOR + nop + + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + +entry __OSEVSetNumber + addi r3, 0, 0 + + lwz r4, 0xD4 + rlwinm. r5, r5, 0, 30, 30 + bne recover + addis r5, 0, OSDefaultExceptionHandler@ha + addi r5, r5, OSDefaultExceptionHandler@l + mtsrr0 r5 + rfi + +recover: + rlwinm r5, r3, 2, 22, 29 + lwz r5, 0x3000(r5) + mtsrr0 r5 + + rfi + +entry __OSEVEnd + nop +} + +asm void OSDefaultExceptionHandler(register __OSException exception, register OSContext* context) { + nofralloc + + stw r0, 0(context) + stw r1, 4(context) + stw r2, 8(context) + stmw r6, 0x18(context) + + mfspr r0, 0x391 + stw r0, 0x1A8(context) + + mfspr r0, 0x392 + stw r0, 0x1AC(context) + + mfspr r0, 0x393 + stw r0, 0x1B0(context) + + mfspr r0, 0x394 + stw r0, 0x1B4(context) + + mfspr r0, 0x395 + stw r0, 0x1B8(context) + + mfspr r0, 0x396 + stw r0, 0x1BC(context) + + mfspr r0, 0x397 + stw r0, 0x1C0(context) + + mfdsisr r5 + mfdar r6 + stwu r1, -8(r1) + b __OSUnhandledException +} + +void __OSPSInit(void) { + PPCMthid2(PPCMfhid2() | 0xA0000000); + ICFlashInvalidate(); + __sync(); + + asm { + li r3, 0 + mtspr 0x390, r3 + mtspr 0x391, r3 + mtspr 0x392, r3 + mtspr 0x393, r3 + mtspr 0x394, r3 + mtspr 0x395, r3 + mtspr 0x396, r3 + mtspr 0x397, r3 + } +} + +u32 __OSGetDIConfig(void) { + return __DIRegs[9] & 0xFF; +} + +void OSRegisterVersion(const char *id) { + OSReport("%s\n", id); +} + +static const char* AppGameNameForSysMenu = "HAEA"; + +const char* OSGetAppGamename(void) { + const char* appNameSrc = (char*)OSPhysicalToCached(0x3194); + + if (__OSInIPL) { + appNameSrc = AppGameNameForSysMenu; + } + else if ((*appNameSrc < '0') || ('9' < *appNameSrc && *appNameSrc < 'A') || ('Z' < *appNameSrc)) { + appNameSrc = (char*)OSPhysicalToCached(0x3180); + } + + GameNameBuffer[0] = *appNameSrc++; + GameNameBuffer[1] = *appNameSrc++; + GameNameBuffer[2] = *appNameSrc++; + GameNameBuffer[3] = *appNameSrc; + GameNameBuffer[4] = 0x00; + return GameNameBuffer; +} + +const u8 OSGetAppType(void) { + if (__OSInIPL) { + return 0x40; + } + + return *((u8*)OSPhysicalToCached(0x3184)); +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSAlarm.c b/src/RVL_SDK/os/OSAlarm.c new file mode 100644 index 000000000..834125759 --- /dev/null +++ b/src/RVL_SDK/os/OSAlarm.c @@ -0,0 +1,260 @@ +#include +#include +#include + +BOOL __DVDTestAlarm(const OSAlarm *); +static void DecrementerExceptionHandler(__OSException, OSContext *); +static BOOL OnReset(BOOL, u32); + +static struct OSAlarmQueue { + OSAlarm* head; + OSAlarm* tail; +} AlarmQueue; + +static OSShutdownFunctionInfo ShutdownFunctionInfo = { + OnReset, + 0xFFFFFFFF, + 0, + 0 +}; + +void __OSInitAlarm(void) { + if (__OSGetExceptionHandler(8) != DecrementerExceptionHandler) { + AlarmQueue.head = AlarmQueue.tail = 0; + __OSSetExceptionHandler(8, DecrementerExceptionHandler); + OSRegisterShutdownFunction(&ShutdownFunctionInfo); + } +} + +void OSCreateAlarm(OSAlarm* alarm) { + alarm->handler = 0; + alarm->tag = 0; +} + +static void SetTimer(OSAlarm* alarm) { + OSTime delta; + delta = alarm->fire - __OSGetSystemTime(); + + if (delta < 0) { + PPCMtdec(0); + } + else if (delta < 0x80000000) { + PPCMtdec((u32)delta); + } + else { + PPCMtdec(0x7FFFFFFF); + } +} + +static void InsertAlarm(OSAlarm* alarm, OSTime fire, OSAlarmHandler handler) { + OSAlarm* next; + OSAlarm* prev; + + if (0 < alarm->period) { + OSTime time = __OSGetSystemTime(); + fire = alarm->start; + + if (alarm->start < time) { + fire += alarm->period * ((time - alarm->start) / alarm->period + 1); + } + } + + alarm->handler = handler; + alarm->fire = fire; + + for (next = AlarmQueue.head; next; next = next->next) { + if (next->fire <= fire) { + continue; + } + + alarm->prev = next->prev; + next->prev = alarm; + alarm->next = next; + prev = alarm->prev; + + if (prev != 0) { + prev->next = alarm; + } + else { + AlarmQueue.head = alarm; + SetTimer(alarm); + } + + return; + } + + alarm->next = 0; + prev = AlarmQueue.tail; + AlarmQueue.tail = alarm; + alarm->prev = prev; + + if (prev != 0) { + prev->next = alarm; + } + else { + AlarmQueue.head = AlarmQueue.tail = alarm; + SetTimer(alarm); + } +} + +void OSSetAlarm(OSAlarm* alarm, OSTime tick, OSAlarmHandler handler) { + BOOL enabled; + enabled = OSDisableInterrupts(); + alarm->period = 0; + InsertAlarm(alarm, __OSGetSystemTime() + tick, handler); + OSRestoreInterrupts(enabled); +} + +void OSSetPeriodicAlarm(OSAlarm* alarm, OSTime start, OSTime period, OSAlarmHandler handler) { + BOOL enabled; + enabled = OSDisableInterrupts(); + alarm->period = period; + alarm->start = __OSTimeToSystemTime(start); + InsertAlarm(alarm, 0, handler); + OSRestoreInterrupts(enabled); +} + +void OSCancelAlarm(OSAlarm* alarm) { + OSAlarm* next; + BOOL enabled; + enabled = OSDisableInterrupts(); + + if (alarm->handler == 0) { + OSRestoreInterrupts(enabled); + return; + } + + next = alarm->next; + + if (next == 0) { + AlarmQueue.tail = alarm->prev; + } + else { + next->prev = alarm->prev; + } + + if (alarm->prev != 0) { + alarm->prev->next = next; + } + else { + AlarmQueue.head = next; + + if (next != 0) { + SetTimer(next); + } + } + + alarm->handler = 0; + OSRestoreInterrupts(enabled); +} + +static void DecrementerExceptionCallback(register __OSException exception, register OSContext* context) { + OSAlarm* alarm; + OSAlarm* next; + OSAlarmHandler handler; + OSTime time; + OSContext exceptionContext; + + time = __OSGetSystemTime(); + alarm = AlarmQueue.head; + + if (alarm == 0) { + OSLoadContext(context); + } + + if (time < alarm->fire) { + SetTimer(alarm); + OSLoadContext(context); + } + + next = alarm->next; + AlarmQueue.head = next; + + if (next == 0) { + AlarmQueue.tail = 0; + } + else { + next->prev = 0; + } + + handler = alarm->handler; + alarm->handler = 0; + + if (0 < alarm->period) { + InsertAlarm(alarm, 0, handler); + } + + if (AlarmQueue.head != 0) { + SetTimer(AlarmQueue.head); + } + + OSDisableScheduler(); + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + handler(alarm, context); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + OSEnableScheduler(); + __OSReschedule(); + OSLoadContext(context); +} + +asm void DecrementerExceptionHandler(register __OSException exception, register OSContext* context) { + nofralloc + + stw r0, 0(context) + stw r1, 4(context) + stw r2, 8(context) + stmw r6, 0x18(context) + + mfspr r0, 0x391 + stw r0, 0x1A8(context) + + mfspr r0, 0x392 + stw r0, 0x1AC(context) + + mfspr r0, 0x393 + stw r0, 0x1B0(context) + + mfspr r0, 0x394 + stw r0, 0x1B4(context) + + mfspr r0, 0x395 + stw r0, 0x1B8(context) + + mfspr r0, 0x396 + stw r0, 0x1BC(context) + + mfspr r0, 0x397 + stw r0, 0x1C0(context) + + stwu r1, -8(r1) + b DecrementerExceptionCallback +} + +void OSSetAlarmTag(OSAlarm* alarm, u32 tag) { + alarm->tag = tag; +} + +static BOOL OnReset(BOOL final, u32 event) { + OSAlarm* alarm; + OSAlarm* next; + + if (final) { + for (alarm = AlarmQueue.head, next = alarm ? alarm->next : 0; alarm; alarm = next, next = alarm ? alarm->next : 0) { + if (!__DVDTestAlarm(alarm)) { + OSCancelAlarm(alarm); + } + } + } + + return TRUE; +} + +void OSSetAlarmUserData(OSAlarm* alarm, void *userData) { + alarm->userData = userData; +} + +void* OSGetAlarmUserData(const OSAlarm* alarm) { + return alarm->userData; +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSAlloc.c b/src/RVL_SDK/os/OSAlloc.c new file mode 100644 index 000000000..d1608d286 --- /dev/null +++ b/src/RVL_SDK/os/OSAlloc.c @@ -0,0 +1,209 @@ +#include + +#define TRUNC(n, a) (((u32) (n)) & ~((a) - 1)) +#define ROUND(n, a) (((u32) (n) + (a) - 1) & ~((a) - 1)) + +volatile int __OSCurrHeap = -1; +typedef struct Cell Cell; +typedef struct HeapDesc HeapDesc; + +struct Cell { + Cell* prev; // 0x0 + Cell* next; // 0x4 + long size; // 0x8 +}; + +struct HeapDesc { + long size; + Cell* free; + Cell* allocated; +}; + +static HeapDesc* HeapArray; +static int NumHeaps; +static void* ArenaStart; +static void* ArenaEnd; + +static Cell* DLAddFront(Cell* list, Cell* cell) { + cell->next = list; + cell->prev = 0; + + if (list != 0) { + list->prev = cell; + } + + return cell; +} + +static Cell* DLExtract(Cell* list, Cell* cell) { + if (cell->next) { + cell->next->prev = cell->prev; + } + + if (cell->prev == 0) { + return cell->next; + } + else { + cell->prev->next = cell->next; + return list; + } +} + +static Cell* DLInsert(Cell* list, Cell* cell) { + Cell* prev; + Cell* next; + + for (next = list, prev = 0; next; prev = next, next = next->next) { + if (cell <= next) { + break; + } + } + + cell->next = next; + cell->prev = prev; + + if (next != 0) { + next->prev = cell; + + if ((char*)cell + cell->size == (char*)next) { + cell->size += next->size; + cell->next = next = next->next; + + if (next != 0) { + next->prev = cell; + } + } + } + + if (prev != 0) { + prev->next = cell; + + if ((char*)prev + prev->size == (char*)cell) { + prev->size += cell->size; + prev->next = next; + + if (next != 0) { + next->prev = prev; + } + } + + return list; + } + else { + return cell; + } +} + +void* OSAllocFromHeap(int heap, u32 size) { + HeapDesc* desc; + Cell* cell; + Cell* newCell; + long leftSize; + + desc = &HeapArray[heap]; + size += 0x3F; + size = ROUND(size, 32); + + for (cell = desc->free; cell != 0; cell = cell->next) { + if ((long)size <= cell->size) { + break; + } + } + + if (cell == 0) { + return 0; + } + + leftSize = cell->size - size; + + // cast is probably from a macro that they have defined that likely defines a max size of some sort + if (leftSize < (u32)0x40) { + // inlined + desc->free = DLExtract(desc->free, cell); + } + else { + cell->size = size; + newCell = (Cell*)((char*)cell + size); + newCell->size = leftSize; + newCell->prev = cell->prev; + newCell->next = cell->next; + + if (newCell->next != 0) { + newCell->next->prev = newCell; + } + + if (newCell->prev != 0) { + newCell->prev->next = newCell; + } + else { + desc->free = newCell; + } + } + + desc->allocated = DLAddFront(desc->allocated, cell); + return (void*)((char*)cell + 0x20); +} + +void OSFreeToHeap(int heap, void *ptr) { + HeapDesc* desc; + Cell* cell; + + cell = (Cell*)((char*)ptr - 0x20); + desc = &HeapArray[heap]; + desc->allocated = DLExtract(desc->allocated, cell); + desc->free = DLInsert(desc->free, cell); +} + +int OSSetCurrentHeap(int heap) { + int prev; + prev = __OSCurrHeap; + __OSCurrHeap = heap; + return prev; +} + +void* OSInitAlloc(void* arenaStart, void* arenaEnd, int max) { + u32 size; + int i; + size = max * 0xC; + HeapArray = arenaStart; + NumHeaps = max; + + for (i = 0; i < NumHeaps; i++) { + HeapDesc* desc = &HeapArray[i]; + desc->size = -1; + desc->free = desc->allocated = 0; + } + + __OSCurrHeap = -1; + arenaStart = (void*)((char*)HeapArray + size); + arenaStart = (void*)ROUND(arenaStart, 0x20); + ArenaStart = arenaStart; + ArenaEnd = (void*)TRUNC(arenaEnd, 0x20); + return arenaStart; +} + +int OSCreateHeap(void *start, void *end) { + int heap; + HeapDesc* desc; + Cell* cell; + start = (void*)ROUND(start, 0x20); + end = (void*)TRUNC(end, 0x20); + + for (heap = 0; heap < NumHeaps; heap++) { + desc = &HeapArray[heap]; + + // insert the new heap into a heap with size of -1 + if (desc->size < 0) { + desc->size = (char*)end - (char*)start; + cell = (Cell*)start; + cell->prev = 0; + cell->next = 0; + cell->size = desc->size; + desc->free = cell; + desc->allocated = 0; + return heap; + } + } + + return -1; +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSArena.c b/src/RVL_SDK/os/OSArena.c new file mode 100644 index 000000000..cc8593a4b --- /dev/null +++ b/src/RVL_SDK/os/OSArena.c @@ -0,0 +1,69 @@ +#include + +static void* __OSArenaHi = (void*)0x00000000; +static void* __OSArenaLo = (void*)0xFFFFFFFF; + +static void* s_mem2ArenaHi = (void*)0x00000000; +static void* s_mem2ArenaLo = (void*)0xFFFFFFFF; + +#define ROUND(n, a) (((u32) (n) + (a) - 1) & ~((a) - 1)) + +void* OSGetMEM1ArenaHi(void) { + return __OSArenaHi; +} + +void* OSGetMEM2ArenaHi(void) { + return s_mem2ArenaHi; +} + +void* OSGetArenaHi(void) { + return OSGetMEM1ArenaHi(); +} + +void* OSGetMEM1ArenaLo(void) { + return __OSArenaLo; +} + +void* OSGetMEM2ArenaLo(void) { + return s_mem2ArenaLo; +} + +void* OSGetArenaLo(void) { + return OSGetMEM1ArenaLo(); +} + +void OSSetMEM1ArenaHi(void *pNew) { + __OSArenaHi = pNew; +} + +void OSSetMEM2ArenaHi(void *pNew) { + s_mem2ArenaHi = pNew; +} + +void OSSetArenaHi(void *pNew) { + OSSetMEM1ArenaHi(pNew); +} + +void OSSetMEM1ArenaLo(void *pNew) { + __OSArenaLo = pNew; +} + +void OSSetMEM2ArenaLo(void *pNew) { + s_mem2ArenaLo = pNew; +} + +void OSSetArenaLo(void *pNew) { + OSSetMEM1ArenaLo(pNew); +} + +void* OSAllocFromMEM1ArenaLo(u32 size, u32 alignment) { + void* res; + u8* lo; + + res = OSGetMEM1ArenaLo(); + lo = res = (void*)ROUND(res, alignment); + lo += size; + lo = (u8*)ROUND(lo, alignment); + OSSetMEM1ArenaLo(lo); + return res; +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSAudioSystem.c b/src/RVL_SDK/os/OSAudioSystem.c new file mode 100644 index 000000000..9cb471c13 --- /dev/null +++ b/src/RVL_SDK/os/OSAudioSystem.c @@ -0,0 +1,205 @@ +#include "private/flipper.h" +#include +#include + +#define PPCACR_OFFSET (OS_BASE_UNCACHED + 0x800000) +#define PPCACR (0xD000000 + PPCACR_OFFSET) + +u8 DSPInitCode[] = { + 0x02, 0x9F, 0x00, 0x10, 0x02, 0x9F, 0x00, 0x33, + 0x02, 0x9F, 0x00, 0x34, 0x02, 0x9F, 0x00, 0x35, + 0x02, 0x9F, 0x00, 0x36, 0x02, 0x9F, 0x00, 0x37, + 0x02, 0x9F, 0x00, 0x38, 0x02, 0x9F, 0x00, 0x39, + 0x12, 0x06, 0x12, 0x03, 0x12, 0x04, 0x12, 0x05, + 0x00, 0x80, 0x80, 0x00, 0x00, 0x88, 0xFF, 0xFF, + 0x00, 0x84, 0x10, 0x00, 0x00, 0x64, 0x00, 0x1D, + 0x02, 0x18, 0x00, 0x00, 0x81, 0x00, 0x1C, 0x1E, + 0x00, 0x44, 0x1B, 0x1E, 0x00, 0x84, 0x08, 0x00, + 0x00, 0x64, 0x00, 0x27, 0x19, 0x1E, 0x00, 0x00, + 0x00, 0xDE, 0xFF, 0xFC, 0x02, 0xA0, 0x80, 0x00, + 0x02, 0x9C, 0x00, 0x28, 0x16, 0xFC, 0x00, 0x54, + 0x16, 0xFD, 0x43, 0x48, 0x00, 0x21, 0x02, 0xFF, + 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, + 0x02, 0xFF, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +extern BOOL __OSInIPL; + +#define busRd32(addr) (*(volatile u32 *)(addr)) +#define busWrt32(addr, val) (*(volatile u32 *)(addr)) = (val) + +static void waitMicroSec(int usec) { + OSTick t = OSGetTick(); + while (OSTicksToMicroseconds(OSGetTick() - t) < usec); +} + +void __AIClockInit(u32 compatB) { + u32 reg; + + reg = busRd32(PPCACR + 0x180); + reg &= ~((u32)1 << 8); + reg |= ((u32)compatB << 8); + reg &= ~((u32)1 << 7); + busWrt32(PPCACR + 0x180, reg); + + reg = busRd32(PPCACR + 0x1D0); + reg &= ~((u32)1 << 31); + reg &= ~((u32)1 << 30); + busWrt32(PPCACR + 0x1D0, reg); + + waitMicroSec(100); + + if (compatB == 0) { + reg = busRd32(PPCACR + 0x1CC); + reg &= ~0x3FFC0; + reg |= ((u32)63 << 6); + reg &= ~0x3F; + reg &= ~0x7FC0000; + reg |= ((u32)281 << 18); + busWrt32(PPCACR + 0x1CC, reg); + } + else { + reg = busRd32(PPCACR + 0x1CC); + reg &= ~0x3FFC0; + reg |= ((u32)1023 << 6); + reg &= ~0x3F; + reg |= ((u32)14); + reg &= ~0x7FC0000; + reg |= ((u32)300 << 18); + busWrt32(PPCACR + 0x1CC, reg); + } + + waitMicroSec(100); + + reg = busRd32(PPCACR + 0x1D0); + reg &= ~((u32)1 << 28); + busWrt32(PPCACR + 0x1D0, reg); + + waitMicroSec(1000); + + reg = busRd32(PPCACR + 0x1D0); + reg &= ~((u32)1 << 30); + reg |= ((u32)1 << 30); + busWrt32(PPCACR + 0x1D0, reg); + + waitMicroSec(1000); + + reg = busRd32(PPCACR + 0x1D0); + reg &= ~((u32)1 << 31); + reg |= ((u32)1 << 31); + busWrt32(PPCACR + 0x1D0, reg); + + waitMicroSec(1000); +} + + +void __OSInitAudioSystem(void) { + u8 errFlag; + u16 reg16; + OSTick start_tick; + + if (!__OSInIPL) { + __AIClockInit(1); + } + + memcpy((u8*)OSGetArenaHi() - 0x80, (u8*)0x81000000, 0x80); + memcpy((u8*)0x81000000, DSPInitCode, 0x80); + DCFlushRange((u8*)0x81000000, 0x80); + + __DSPRegs[9] = 0x43; + __DSPRegs[5] = 0x8AC; + __DSPRegs[5] |= 1; + + while (__DSPRegs[5] & 1); + + __DSPRegs[0] = 0; + while ((__DSPRegs[2] << 16 | __DSPRegs[3]) & 0x80000000); + + *(u32*)&__DSPRegs[0x10] = 0x1000000; + *(u32*)&__DSPRegs[0x12] = 0; + *(u32*)&__DSPRegs[0x14] = 0x20; + + reg16 = __DSPRegs[5]; + + while (!(reg16 & 0x20)) { + reg16 = __DSPRegs[5]; + } + + __DSPRegs[5] = reg16; + + start_tick = OSGetTick(); + + while(OSDiffTick(OSGetTick(), start_tick) < 2194); + + *(u32*)&__DSPRegs[0x10] = 0x1000000; + *(u32*)&__DSPRegs[0x12] = 0; + *(u32*)&__DSPRegs[0x14] = 0x20; + + reg16 = __DSPRegs[5]; + + while (!(reg16 & 0x20)) { + reg16 = __DSPRegs[5]; + } + + __DSPRegs[5] = reg16; + __DSPRegs[5] &= ~0x800; + + while (__DSPRegs[5] & 0x400); + + __DSPRegs[5] &= ~4; + + errFlag = 0; + + reg16 = __DSPRegs[2]; + + while (!(reg16 & 0x8000)) { + reg16 = __DSPRegs[2]; + } + + /* probably from a assert conditional at some point */ + __DSPRegs[3]; + + __DSPRegs[5] |= 4; + __DSPRegs[5] = 0x8AC; + __DSPRegs[5] |= 1; + + while (__DSPRegs[5] & 1); + + memcpy((u8*)0x81000000, (u8*)OSGetArenaHi() - 0x80, 0x80); +} + +void __OSStopAudioSystem(void) { + u16 reg16; + OSTick start_tick; + + __DSPRegs[5] = 0x804; + reg16 = __DSPRegs[0x1B]; + __DSPRegs[0x1B] = (u16)(reg16 & ~0x8000); + + reg16 = __DSPRegs[5]; + while (reg16 & 0x400) { + reg16 = __DSPRegs[5]; + } + + reg16 = __DSPRegs[5]; + while (reg16 & 0x200) { + reg16 = __DSPRegs[5]; + } + + __DSPRegs[5] = 0x8AC; + __DSPRegs[0] = 0; + + while ((__DSPRegs[2] << 16 | __DSPRegs[3]) & 0x80000000); + + start_tick = OSGetTick(); + while (OSDiffTick(OSGetTick(), start_tick) < 44); + + reg16 = __DSPRegs[5]; + __DSPRegs[5] = (u16)(reg16 | 1); + reg16 = __DSPRegs[5]; + + while (reg16 & 1) { + reg16 = __DSPRegs[5]; + } +} diff --git a/src/RVL_SDK/os/OSCache.c b/src/RVL_SDK/os/OSCache.c new file mode 100644 index 000000000..28e8357a6 --- /dev/null +++ b/src/RVL_SDK/os/OSCache.c @@ -0,0 +1,391 @@ +#include +#include +#include + +asm void DCEnable(void) { + nofralloc + sync + mfspr r3, HID0 + ori r3, r3, 0x4000 + mtspr HID0, r3 + blr +} + +asm void DCInvalidateRange(register void *pAddr, register u32 num) { + nofralloc + cmplwi num, 0 + blelr- + clrlwi r5, pAddr, 27 + add num, num, r5 + addi num, num, 0x1F + srwi num, num, 5 + mtctr num + + loop: + dcbi 0, pAddr + addi pAddr, pAddr, 32 + bdnz loop + + blr +} + +asm void DCFlushRange(register void *pAddr, register u32 num) { + nofralloc + cmplwi num, 0 + blelr- + clrlwi r5, pAddr, 27 + add num, num, r5 + addi num, num, 0x1F + srwi num, num, 5 + mtctr num + + loop: + dcbf 0, pAddr + addi pAddr, pAddr, 32 + bdnz loop + + sc + blr +} + +asm void DCStoreRange(register void *pAddr, register u32 num) { + nofralloc + cmplwi num, 0 + blelr- + clrlwi r5, pAddr, 27 + add num, num, r5 + addi num, num, 0x1F + srwi num, num, 5 + mtctr num + + loop: + dcbst 0, pAddr + addi pAddr, pAddr, 32 + bdnz loop + + sc + blr +} + +asm void DCFlushRangeNoSync(register void *pAddr, register u32 num) { + nofralloc + cmplwi num, 0 + blelr- + clrlwi r5, pAddr, 27 + add num, num, r5 + addi num, num, 0x1F + srwi num, num, 5 + mtctr num + + loop: + dcbf 0, pAddr + addi pAddr, pAddr, 32 + bdnz loop + + blr +} + +asm void DCStoreRangeNoSync(register void *pAddr, register u32 num) { + nofralloc + cmplwi num, 0 + blelr- + clrlwi r5, pAddr, 27 + add num, num, r5 + addi num, num, 0x1F + srwi num, num, 5 + mtctr num + + loop: + dcbst 0, pAddr + addi pAddr, pAddr, 32 + bdnz loop + + blr +} + +asm void DCZeroRange(register void *pAddr, register u32 num) { + nofralloc + cmplwi num, 0 + blelr- + clrlwi r5, pAddr, 27 + add num, num, r5 + addi num, num, 0x1F + srwi num, num, 5 + mtctr num + + loop: + dcbz 0, pAddr + addi pAddr, pAddr, 32 + bdnz loop + + blr +} + +asm void ICInvalidateRange(register void *pAddr, register u32 num) { + nofralloc + cmplwi num, 0 + blelr- + clrlwi r5, pAddr, 27 + add num, num, r5 + addi num, num, 0x1F + srwi num, num, 5 + mtctr num + + loop: + icbi 0, pAddr + addi pAddr, pAddr, 32 + bdnz loop + + sync + isync + blr +} + +asm void ICFlashInvalidate(void) { + nofralloc + mfspr r3, HID0 + ori r3, r3, 0x800 + mtspr HID0, r3 + blr +} + +asm void ICEnable(void) { + nofralloc + isync + mfspr r3, HID0 + ori r3, r3, 0x8000 + mtspr HID0, r3 + blr +} + +static asm void __LCEnable(void) { + nofralloc + mfmsr r5 + ori r5, r5, 0x1000 + mtmsr r5 + + lis r3, -0x8000 + li r4, 0x400 + mtctr r4 + + loop_1: + dcbt 0, r3 + dcbst 0, r3 + addi r3, r3, 0x20 + bdnz loop_1 + + mfspr r4, 0x398 + oris r4, r4, 0x100F + mtspr 0x398, r4 + + /* this is used to seperate the dcbz_l from mtspr HID2 */ + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + + lis r3, -0x2000 + ori r3, r3, 2 + mtspr DBAT3L, r3 + ori r3, r3, 0x1FE + mtspr DBAT3U, r3 + isync + + lis r3, -0x2000 + li r6, 0x200 + mtctr r6 + li r6, 0 + + loop_2: + dcbz_l r6, r3 + addi r3, r3, 0x20 + bdnz+ loop_2 + + // seperate the previous dcbz_l from the next icache load + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + blr +} + +void LCEnable(void) { + BOOL lvl; + lvl = OSDisableInterrupts(); + __LCEnable(); + OSRestoreInterrupts(lvl); +} + +asm void LCDisable(void) { + lis r3, -0x2000 + li r4, 0x200 + mtctr r4 + + loop: + dcbi 0, r3 + addi r3, r3, 0x20 + bdnz loop + + mfspr r4, 0x398 + rlwinm r4, r4, 0, 4, 2 + mtspr 0x398, r4 + blr +} + +asm void LCStoreBlocks(register void *pDest, register void *pSrc, register u32 num) { + nofralloc + /* set the upper bits of the DMA length (num) */ + rlwinm r6, num, 30, 27, 31 + /* set the destination address in the locked cache (DMA_U) */ + rlwinm pDest, pDest, 0, 3, 31 + or r6, r6, pDest + mtspr DMA_U, r6 + /* set the lower bits of the DMA length */ + rlwinm r6, num, 2, 28, 29 + /* now we set the source address inside of the locked cache (DMA_U) */ + or r6, r6, pSrc + ori r6, r6, 2 + mtspr DMA_L, r6 + blr +} + +u32 LCStoreData(void *pDest, void *pSrc, u32 num) { + u32 block_count = (num + 31) / 32; + u32 v1 = (block_count + LC_MAX_DMA_BLOCKS - 1) / LC_MAX_DMA_BLOCKS; + + while (block_count > 0) { + if (block_count < LC_MAX_DMA_BLOCKS) { + LCStoreBlocks(pDest, pSrc, block_count); + block_count = 0; + } + else { + LCStoreBlocks(pDest, pSrc, 0); + block_count -= LC_MAX_DMA_BLOCKS; + pDest = (void*)((u32)pDest + 0x1000); + pSrc = (void*)((u32)pSrc + 0x1000); + } + } + + return v1; +} + +asm void LCQueueWait(register u32 length) { + nofralloc + + loop: + mfspr r4, 0x398 + rlwinm r4, r4, 8, 28, 31 + cmpw r4, length + bgt loop + + blr +} + +static void L2Disable(void); +static void L2GlobalInvalidate(void); + +static inline void L2Init(void) { + u32 old; + old = PPCMfmsr(); + __sync(); + PPCMtmsr(0x30); + __sync(); + L2Disable(); + + L2GlobalInvalidate(); + PPCMtmsr(old); +} + +void inline L2Enable(void) { + PPCMtl2cr((PPCMfl2cr() | 0x80000000) & ~0x200000); +} + +void inline L2Disable(void) { + __sync(); + PPCMtl2cr(PPCMfl2cr() & ~0x80000000); + __sync(); +} + +void inline L2GlobalInvalidate(void) { + L2Disable(); + + PPCMtl2cr(PPCMfl2cr() | 0x200000); + while (PPCMfl2cr() & 1); + PPCMtl2cr(PPCMfl2cr() & ~0x200000); + + while (PPCMfl2cr() & 1) { + DBPrintf(">>> L2 INVALIDATE : SHOULD NEVER HAPPEN\n"); + } +} + +// I don't know what OSError is used for here +void DMAErrorHandler(OSError, OSContext *pContext, ...) { + u32 hid = PPCMfhid2(); + OSReport("Machine check received\n"); + OSReport("HID2 = 0x%x SRR1 = 0x%x\n", hid, pContext->srr1); + + if (!(hid & 0xF00000) || !(pContext->srr1 & 0x00200000)) { + OSReport("Machine check was not DMA/locked cache related\n"); + OSDumpContext(pContext); + PPCHalt(); + } + + OSReport("DMAErrorHandler(): An error occurred while processing DMA.\n"); + OSReport("The following errors have been detected and cleared :\n"); + + if (hid & 0x00800000) { + OSReport("\t- Requested a locked cache tag that was already in the cache\n"); + } + + if (hid & 0x00400000) { + OSReport("\t- DMA attempted to access normal cache\n"); + } + + if (hid & 0x00200000) { + OSReport("\t- DMA missed in data cache\n"); + } + + if (hid & 0x00100000) { + OSReport("\t- DMA queue overflowed\n"); + } + + PPCMthid2(hid); +} + +void __OSCacheInit(void) { + if (!(PPCMfhid0() & 0x8000)) { + ICEnable(); + DBPrintf("L1 i-caches initialized\n"); + } + + if (!(PPCMfhid0() & 0x4000)) { + DCEnable(); + DBPrintf("L1 d-caches initialized\n"); + } + + if (!(PPCMfl2cr() & 0x80000000)) { + // these two functions are inlined + L2Init(); + L2Enable(); + DBPrintf("L2 cache initialized\n"); + } + + OSSetErrorHandler(1, DMAErrorHandler); + DBPrintf("Locked cache machine check handler installed\n"); +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSContext.c b/src/RVL_SDK/os/OSContext.c new file mode 100644 index 000000000..ea6efe7f2 --- /dev/null +++ b/src/RVL_SDK/os/OSContext.c @@ -0,0 +1,633 @@ +#include +#include +#include +#include +#include + +static asm void __OSLoadFPUContext(register u32 dummy, register OSContext *pContext) { + nofralloc + lhz r5, pContext->state + clrlwi. r5, r5, 31 + beq _ret + + lfd f0, 0x190(pContext) + mtfsf 0xFF, f0 + mfspr r5, 0x398 + rlwinm. r5, r5, 3, 31, 31 + bc 12, 2, norm_fpr + + psq_l fp0, OS_CONTEXT_PSF0(pContext), 0, 0 + psq_l fp1, OS_CONTEXT_PSF1(pContext), 0, 0 + psq_l fp2, OS_CONTEXT_PSF2(pContext), 0, 0 + psq_l fp3, OS_CONTEXT_PSF3(pContext), 0, 0 + psq_l fp4, OS_CONTEXT_PSF4(pContext), 0, 0 + psq_l fp5, OS_CONTEXT_PSF5(pContext), 0, 0 + psq_l fp6, OS_CONTEXT_PSF6(pContext), 0, 0 + psq_l fp7, OS_CONTEXT_PSF7(pContext), 0, 0 + psq_l fp8, OS_CONTEXT_PSF8(pContext), 0, 0 + psq_l fp9, OS_CONTEXT_PSF9(pContext), 0, 0 + psq_l fp10, OS_CONTEXT_PSF10(pContext), 0, 0 + psq_l fp11, OS_CONTEXT_PSF11(pContext), 0, 0 + psq_l fp12, OS_CONTEXT_PSF12(pContext), 0, 0 + psq_l fp13, OS_CONTEXT_PSF13(pContext), 0, 0 + psq_l fp14, OS_CONTEXT_PSF14(pContext), 0, 0 + psq_l fp15, OS_CONTEXT_PSF15(pContext), 0, 0 + psq_l fp16, OS_CONTEXT_PSF16(pContext), 0, 0 + psq_l fp17, OS_CONTEXT_PSF17(pContext), 0, 0 + psq_l fp18, OS_CONTEXT_PSF18(pContext), 0, 0 + psq_l fp19, OS_CONTEXT_PSF19(pContext), 0, 0 + psq_l fp20, OS_CONTEXT_PSF20(pContext), 0, 0 + psq_l fp21, OS_CONTEXT_PSF21(pContext), 0, 0 + psq_l fp22, OS_CONTEXT_PSF22(pContext), 0, 0 + psq_l fp23, OS_CONTEXT_PSF23(pContext), 0, 0 + psq_l fp24, OS_CONTEXT_PSF24(pContext), 0, 0 + psq_l fp25, OS_CONTEXT_PSF25(pContext), 0, 0 + psq_l fp26, OS_CONTEXT_PSF26(pContext), 0, 0 + psq_l fp27, OS_CONTEXT_PSF27(pContext), 0, 0 + psq_l fp28, OS_CONTEXT_PSF28(pContext), 0, 0 + psq_l fp29, OS_CONTEXT_PSF29(pContext), 0, 0 + psq_l fp30, OS_CONTEXT_PSF30(pContext), 0, 0 + psq_l fp31, OS_CONTEXT_PSF31(pContext), 0, 0 + +norm_fpr: + lfd fp0, pContext->fpr[0] + lfd fp1, pContext->fpr[1] + lfd fp2, pContext->fpr[2] + lfd fp3, pContext->fpr[3] + lfd fp4, pContext->fpr[4] + lfd fp5, pContext->fpr[5] + lfd fp6, pContext->fpr[6] + lfd fp7, pContext->fpr[7] + lfd fp8, pContext->fpr[8] + lfd fp9, pContext->fpr[9] + lfd fp10, pContext->fpr[10] + lfd fp11, pContext->fpr[11] + lfd fp12, pContext->fpr[12] + lfd fp13, pContext->fpr[13] + lfd fp14, pContext->fpr[14] + lfd fp15, pContext->fpr[15] + lfd fp16, pContext->fpr[16] + lfd fp17, pContext->fpr[17] + lfd fp18, pContext->fpr[18] + lfd fp19, pContext->fpr[19] + lfd fp20, pContext->fpr[20] + lfd fp21, pContext->fpr[21] + lfd fp22, pContext->fpr[22] + lfd fp23, pContext->fpr[23] + lfd fp24, pContext->fpr[24] + lfd fp25, pContext->fpr[25] + lfd fp26, pContext->fpr[26] + lfd fp27, pContext->fpr[27] + lfd fp28, pContext->fpr[28] + lfd fp29, pContext->fpr[29] + lfd fp30, pContext->fpr[30] + lfd fp31, pContext->fpr[31] + +_ret: + blr +} + +static asm void __OSSaveFPUContext(register u32 v0, register u32 v1, register OSContext *pContext) { + nofralloc + lhz r3, pContext->state + ori r3, r3, 1 + sth r3, pContext->state + + stfd fp0, pContext->fpr[0] + stfd fp1, pContext->fpr[1] + stfd fp2, pContext->fpr[2] + stfd fp3, pContext->fpr[3] + stfd fp4, pContext->fpr[4] + stfd fp5, pContext->fpr[5] + stfd fp6, pContext->fpr[6] + stfd fp7, pContext->fpr[7] + stfd fp8, pContext->fpr[8] + stfd fp9, pContext->fpr[9] + stfd fp10, pContext->fpr[10] + stfd fp11, pContext->fpr[11] + stfd fp12, pContext->fpr[12] + stfd fp13, pContext->fpr[13] + stfd fp14, pContext->fpr[14] + stfd fp15, pContext->fpr[15] + stfd fp16, pContext->fpr[16] + stfd fp17, pContext->fpr[17] + stfd fp18, pContext->fpr[18] + stfd fp19, pContext->fpr[19] + stfd fp20, pContext->fpr[20] + stfd fp21, pContext->fpr[21] + stfd fp22, pContext->fpr[22] + stfd fp23, pContext->fpr[23] + stfd fp24, pContext->fpr[24] + stfd fp25, pContext->fpr[25] + stfd fp26, pContext->fpr[26] + stfd fp27, pContext->fpr[27] + stfd fp28, pContext->fpr[28] + stfd fp29, pContext->fpr[29] + stfd fp30, pContext->fpr[30] + stfd fp31, pContext->fpr[31] + + mffs fp0 + stfd fp0, 400(pContext) + lfd fp0, pContext->fpr[0] + mfspr r3, 0x398 + extrwi. r3, r3, 1, 2 + beq _ret + + psq_st fp0, OS_CONTEXT_PSF0(pContext), 0, 0 + psq_st fp1, OS_CONTEXT_PSF1(pContext), 0, 0 + psq_st fp2, OS_CONTEXT_PSF2(pContext), 0, 0 + psq_st fp3, OS_CONTEXT_PSF3(pContext), 0, 0 + psq_st fp4, OS_CONTEXT_PSF4(pContext), 0, 0 + psq_st fp5, OS_CONTEXT_PSF5(pContext), 0, 0 + psq_st fp6, OS_CONTEXT_PSF6(pContext), 0, 0 + psq_st fp7, OS_CONTEXT_PSF7(pContext), 0, 0 + psq_st fp8, OS_CONTEXT_PSF8(pContext), 0, 0 + psq_st fp9, OS_CONTEXT_PSF9(pContext), 0, 0 + psq_st fp10, OS_CONTEXT_PSF10(pContext), 0, 0 + psq_st fp11, OS_CONTEXT_PSF11(pContext), 0, 0 + psq_st fp12, OS_CONTEXT_PSF12(pContext), 0, 0 + psq_st fp13, OS_CONTEXT_PSF13(pContext), 0, 0 + psq_st fp14, OS_CONTEXT_PSF14(pContext), 0, 0 + psq_st fp15, OS_CONTEXT_PSF15(pContext), 0, 0 + psq_st fp16, OS_CONTEXT_PSF16(pContext), 0, 0 + psq_st fp17, OS_CONTEXT_PSF17(pContext), 0, 0 + psq_st fp18, OS_CONTEXT_PSF18(pContext), 0, 0 + psq_st fp19, OS_CONTEXT_PSF19(pContext), 0, 0 + psq_st fp20, OS_CONTEXT_PSF20(pContext), 0, 0 + psq_st fp21, OS_CONTEXT_PSF21(pContext), 0, 0 + psq_st fp22, OS_CONTEXT_PSF22(pContext), 0, 0 + psq_st fp23, OS_CONTEXT_PSF23(pContext), 0, 0 + psq_st fp24, OS_CONTEXT_PSF24(pContext), 0, 0 + psq_st fp25, OS_CONTEXT_PSF25(pContext), 0, 0 + psq_st fp26, OS_CONTEXT_PSF26(pContext), 0, 0 + psq_st fp27, OS_CONTEXT_PSF27(pContext), 0, 0 + psq_st fp28, OS_CONTEXT_PSF28(pContext), 0, 0 + psq_st fp29, OS_CONTEXT_PSF29(pContext), 0, 0 + psq_st fp30, OS_CONTEXT_PSF30(pContext), 0, 0 + psq_st fp31, OS_CONTEXT_PSF31(pContext), 0, 0 + +_ret: + blr +} + +asm void OSSaveFPUContext(register OSContext *pContext) { + nofralloc + addi r4, pContext, 0 + b __OSLoadFPUContext +} + +asm void OSSetCurrentContext(register OSContext *pContext) { + nofralloc + addis r4, r0, -0x8000 + stw pContext, 0xD4(r4) + clrlwi r5, pContext, 2 + stw r5, 0xC0(r4) + lwz r5, 0xD8(r4) + cmpw r5, pContext + beq disableFPU + + lwz r6, pContext->srr1 + ori r6, r6, 0x2000 + stw r6, pContext->srr1 + + mfmsr r6 + ori r6, r6, 2 + mtmsr r6 + blr + +disableFPU: + lwz r6, pContext->srr1 + rlwinm r6, r6, 0, 19, 17 + stw r6, pContext->srr1 + mfmsr r6 + rlwinm r6, r6, 0, 19, 17 + ori r6, r6, 2 + mtmsr r6 + isync + blr +} + +OSContext* OSGetCurrentContext(void) { + return (OSContext*)__OSCurrentContext; +} + +asm u32 OSSaveContext(register OSContext* context) { + nofralloc + stmw r13, context->gpr[13] + + mfspr r0, 0x391 + stw r0, context->gqr[1] + mfspr r0, 0x392 + stw r0, context->gqr[2] + mfspr r0, 0x393 + stw r0, context->gqr[3] + mfspr r0, 0x394 + stw r0, context->gqr[4] + mfspr r0, 0x395 + stw r0, context->gqr[5] + mfspr r0, 0x396 + stw r0, context->gqr[6] + mfspr r0, 0x397 + stw r0, context->gqr[7] + + mfcr r0 + stw r0, context->cr + + mflr r0 + stw r0, context->lr + stw r0, context->srr0 + + mfmsr r0 + stw r0, context->srr1 + + mfctr r0 + stw r0, context->ctr + + mfxer r0 + stw r0, context->xer + + stw r1, context->gpr[1] + stw r2, context->gpr[2] + + li r0, 1 + stw r0, context->gpr[3] + li r3, 0 + blr +} + +asm void OSLoadContext(register OSContext* context) { + nofralloc + + lis r4, __RAS_OSDisableInterrupts_begin@ha + lwz r6, context->srr0 + addi r5, r4, __RAS_OSDisableInterrupts_begin@l + cmplw r6, r5 + ble notInRAS + lis r4, __RAS_OSDisableInterrupts_end@ha + addi r0, r4, __RAS_OSDisableInterrupts_end@l + cmplw r6, r0 + bge notInRAS + stw r5, context->srr0 + +notInRAS: + lwz r0, context->gpr[0] + lwz r1, context->gpr[1] + lwz r2, context->gpr[2] + lhz r4, context->state + rlwinm. r5, r4, 0, 30, 30 + beq notexc + rlwinm r4, r4, 0, 31, 29 + sth r4, context->state + lmw r5, context->gpr[5] + b misc + +notexc: + lmw r13, context->gpr[13] + +misc: + lwz r4, context->gqr[1] + mtspr 0x391, r4 + lwz r4, context->gqr[2] + mtspr 0x392, r4 + lwz r4, context->gqr[3] + mtspr 0x393, r4 + lwz r4, context->gqr[4] + mtspr 0x394, r4 + lwz r4, context->gqr[5] + mtspr 0x395, r4 + lwz r4, context->gqr[6] + mtspr 0x396, r4 + lwz r4, context->gqr[7] + mtspr 0x397, r4 + + lwz r4, context->cr + mtcr r4 + lwz r4, context->lr + mtlr r4 + lwz r4, context->ctr + mtctr r4 + lwz r4, context->xer + mtxer r4 + + mfmsr r4 + rlwinm r4, r4, 0, 17, 15 + rlwinm r4, r4, 0, 31, 29 + mtmsr r4 + + lwz r4, context->srr0 + mtsrr0 r4 + lwz r4, context->srr1 + mtsrr1 r4 + + lwz r4, context->gpr[4] + lwz r3, context->gpr[3] + rfi +} + +asm u32 OSGetStackPointer(void) { + nofralloc + mr r3, r1 + blr +} + +asm int OSSwitchFiber(register u32 pc, register u32 newsp) { + nofralloc + mflr r0 + mr r5, r1 + stwu r5, -8(newsp) + mr r1, newsp + stw r0, 4(r5) + mtlr pc + blrl + + lwz r5, 0(r1) + lwz r0, 4(r5) + mtlr r0 + mr r1, r5 + blr +} + +asm int OSSwitchFiberEx(register u32 arg0, register u32 arg1, register u32 arg2, register u32 arg3, register u32 pc, register u32 newsp) { + nofralloc + mflr r0 + mr r9, r1 + stwu r9, -8(newsp) + mr r1, newsp + stw r0, 4(r9) + mtlr pc + blrl + + lwz r5, 0(r1) + lwz r0, 4(r5) + mtlr r0 + + mr r1, r5 + blr +} + +void OSClearContext(OSContext *pContext) { + pContext->mode = 0; + pContext->state = 0; + + if (pContext == __OSFPUContext) { + __OSFPUContext = 0; + } +} + +asm void OSInitContext(register OSContext* context, register u32 pc, register u32 newsp) { + nofralloc + stw pc, 0x198(context) + stw newsp, OS_CONTEXT_R1(context) + li r11, 0 + ori r11, r11, 0x9032 + stw r11, 0x19C(context) + li r0, 0x0 + stw r0, 0x80(context) + stw r0, 0x8C(context) + stw r2, OS_CONTEXT_R2(context) + stw r13, OS_CONTEXT_R13(context) + + stw r0, OS_CONTEXT_R3(context) + stw r0, OS_CONTEXT_R4(context) + stw r0, OS_CONTEXT_R5(context) + stw r0, OS_CONTEXT_R6(context) + stw r0, OS_CONTEXT_R7(context) + stw r0, OS_CONTEXT_R8(context) + stw r0, OS_CONTEXT_R9(context) + stw r0, OS_CONTEXT_R10(context) + stw r0, OS_CONTEXT_R11(context) + stw r0, OS_CONTEXT_R12(context) + + stw r0, OS_CONTEXT_R14(context) + stw r0, OS_CONTEXT_R15(context) + stw r0, OS_CONTEXT_R16(context) + stw r0, OS_CONTEXT_R17(context) + stw r0, OS_CONTEXT_R18(context) + stw r0, OS_CONTEXT_R19(context) + stw r0, OS_CONTEXT_R20(context) + stw r0, OS_CONTEXT_R21(context) + stw r0, OS_CONTEXT_R22(context) + stw r0, OS_CONTEXT_R23(context) + stw r0, OS_CONTEXT_R24(context) + stw r0, OS_CONTEXT_R25(context) + stw r0, OS_CONTEXT_R26(context) + stw r0, OS_CONTEXT_R27(context) + stw r0, OS_CONTEXT_R28(context) + stw r0, OS_CONTEXT_R29(context) + stw r0, OS_CONTEXT_R30(context) + stw r0, OS_CONTEXT_R31(context) + stw r0, OS_CONTEXT_GQR0(context) + stw r0, OS_CONTEXT_GQR1(context) + stw r0, OS_CONTEXT_GQR2(context) + stw r0, OS_CONTEXT_GQR3(context) + stw r0, OS_CONTEXT_GQR4(context) + stw r0, OS_CONTEXT_GQR5(context) + stw r0, OS_CONTEXT_GQR6(context) + stw r0, OS_CONTEXT_GQR7(context) + b OSClearContext +} + +void OSDumpContext(OSContext* context) { + u32 i; + u32* p; + + OSReport("------------------------- Context 0x%08x -------------------------\n", context); + + for (i = 0; i < 16; ++i) { + OSReport("r%-2d = 0x%08x (%14d) r%-2d = 0x%08x (%14d)\n", i, context->gpr[i], context->gpr[i], i + 16, context->gpr[i + 16], context->gpr[i + 16]); + } + + OSReport("LR = 0x%08x CR = 0x%08x\n", context->lr, context->cr); + OSReport("SRR0 = 0x%08x SRR1 = 0x%08x\n", context->srr0, context->srr1); + OSReport("\nGQRs----------\n"); + + for (i = 0; i < 4; ++i) { + OSReport("gqr%d = 0x%08x \t gqr%d = 0x%08x\n", i, context->gqr[i], i + 4, context->gqr[i + 4]); + } + + if (context->state & 1) { + OSContext* currentContext; + OSContext fpuContext; + BOOL enabled; + enabled = OSDisableInterrupts(); + currentContext = OSGetCurrentContext(); + OSClearContext(&fpuContext); + OSSetCurrentContext(&fpuContext); + + OSReport("\n\nFPRs----------\n"); + for (i = 0; i < 32; i += 2) { + OSReport("ps%d \t= 0x%x \t ps%d \t= 0x%x\n", i, (u32)context->psf[i], i + 1, (u32)context->psf[i + 1]); + } + + OSReport("\n\nPSFs----------\n"); + for (i = 0; i < 32; i += 2) { + OSReport("ps%d \t= 0x%x \t ps%d \t= 0x%x\n", i, (u32)context->psf[i], i + 1, (u32)context->psf[i + 1]); + } + + OSClearContext(&fpuContext); + OSSetCurrentContext(currentContext); + OSRestoreInterrupts(enabled); + } + + OSReport("\nAddress: Back Chain LR Save\n"); + for (i = 0, p = (u32*)context->gpr[1]; p && (u32)p != 0xffffffff && i++ < 16; p = (u32*)*p) { + OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]); + } +} + +inline void SwitchFPUContext(__OSException ex, OSContext *pContext) { + PPCMtmsr(PPCMfmsr() | 0x2000); + pContext->srr1 |= 0x2000; + + if (__OSFPUContext == pContext) { + OSLoadContext(pContext); + } + + if (__OSFPUContext) { + OSSavepContext((OSContext*)__OSFPUContext); + } + + __OSFPUContext = pContext; + OSLoadFPUContext((OSContext*)__OSFPUContext); + OSLoadContext(pContext); +} + +asm void OSLoadFPUContext(register OSContext *pContext) { + nofralloc + addi r4, pContext, 0 + b __OSLoadFPUContext +} + +static asm void OSSwitchFPUContext(register __OSException ex, register OSContext *pContext) { + nofralloc + mfmsr r5 + ori r5, r5, 0x2000 + mtmsr r5 + isync + + lwz r5, 412(pContext) + ori r5, r5, 0x2000 + mtsrr1 r5 + + lis r3, -0x8000 + lwz r5, 0xD8(r3) + stw pContext, 0xD8(r3) + cmpw r5, r4 + beq restore + + cmpwi r5, 0 + beq loadFPU + bl __OSSaveFPUContext + + loadFPU: + bl __OSLoadFPUContext + + restore: + lwz r3, 0x80(pContext) + mtcr r3 + lwz r3, 0x84(pContext) + mtlr r3 + lwz r3, 0x198(pContext) + mtsrr0 r3 + lwz r3, 0x88(pContext) + mtctr r3 + lwz r3, 0x8C(pContext) + mtxer r3 + + lhz r3, pContext->state + rlwinm r3, r3,0, 31, 29 + sth r3, pContext->state + + lwz r5, 0x14(pContext) + lwz r3, 0xC(pContext) + lwz r4, 0x10(pContext) + rfi +} + +void __OSContextInit(void) { + __OSSetExceptionHandler(7, OSSwitchFPUContext); + __OSFPUContext = NULL; + DBPrintf("FPU-unavailable handler installed\n"); +} + +asm void OSFillFPUContext(register OSContext* context) { + nofralloc + mfmsr r5 + ori r5, r5, 0x2000 + mtmsr r5 + isync + + stfd fp0, context->fpr[0] + stfd fp1, context->fpr[1] + stfd fp2, context->fpr[2] + stfd fp3, context->fpr[3] + stfd fp4, context->fpr[4] + stfd fp5, context->fpr[5] + stfd fp6, context->fpr[6] + stfd fp7, context->fpr[7] + stfd fp8, context->fpr[8] + stfd fp9, context->fpr[9] + stfd fp10, context->fpr[10] + stfd fp11, context->fpr[11] + stfd fp12, context->fpr[12] + stfd fp13, context->fpr[13] + stfd fp14, context->fpr[14] + stfd fp15, context->fpr[15] + stfd fp16, context->fpr[16] + stfd fp17, context->fpr[17] + stfd fp18, context->fpr[18] + stfd fp19, context->fpr[19] + stfd fp20, context->fpr[20] + stfd fp21, context->fpr[21] + stfd fp22, context->fpr[22] + stfd fp23, context->fpr[23] + stfd fp24, context->fpr[24] + stfd fp25, context->fpr[25] + stfd fp26, context->fpr[26] + stfd fp27, context->fpr[27] + stfd fp28, context->fpr[28] + stfd fp29, context->fpr[29] + stfd fp30, context->fpr[30] + stfd fp31, context->fpr[31] + mffs fp0 + stfd fp0, 0x190(context) + lfd fp0, context->fpr[0] + mfspr r5, 0x398 + rlwinm. r5, r5, 3, 31, 31 + bc 12, 2, _return + psq_st fp0, OS_CONTEXT_PSF0(context), 0, 0 + psq_st fp1, OS_CONTEXT_PSF1(context), 0, 0 + psq_st fp2, OS_CONTEXT_PSF2(context), 0, 0 + psq_st fp3, OS_CONTEXT_PSF3(context), 0, 0 + psq_st fp4, OS_CONTEXT_PSF4(context), 0, 0 + psq_st fp5, OS_CONTEXT_PSF5(context), 0, 0 + psq_st fp6, OS_CONTEXT_PSF6(context), 0, 0 + psq_st fp7, OS_CONTEXT_PSF7(context), 0, 0 + psq_st fp8, OS_CONTEXT_PSF8(context), 0, 0 + psq_st fp9, OS_CONTEXT_PSF9(context), 0, 0 + psq_st fp10, OS_CONTEXT_PSF10(context), 0, 0 + psq_st fp11, OS_CONTEXT_PSF11(context), 0, 0 + psq_st fp12, OS_CONTEXT_PSF12(context), 0, 0 + psq_st fp13, OS_CONTEXT_PSF13(context), 0, 0 + psq_st fp14, OS_CONTEXT_PSF14(context), 0, 0 + psq_st fp15, OS_CONTEXT_PSF15(context), 0, 0 + psq_st fp16, OS_CONTEXT_PSF16(context), 0, 0 + psq_st fp17, OS_CONTEXT_PSF17(context), 0, 0 + psq_st fp18, OS_CONTEXT_PSF18(context), 0, 0 + psq_st fp19, OS_CONTEXT_PSF19(context), 0, 0 + psq_st fp20, OS_CONTEXT_PSF20(context), 0, 0 + psq_st fp21, OS_CONTEXT_PSF21(context), 0, 0 + psq_st fp22, OS_CONTEXT_PSF22(context), 0, 0 + psq_st fp23, OS_CONTEXT_PSF23(context), 0, 0 + psq_st fp24, OS_CONTEXT_PSF24(context), 0, 0 + psq_st fp25, OS_CONTEXT_PSF25(context), 0, 0 + psq_st fp26, OS_CONTEXT_PSF26(context), 0, 0 + psq_st fp27, OS_CONTEXT_PSF27(context), 0, 0 + psq_st fp28, OS_CONTEXT_PSF28(context), 0, 0 + psq_st fp29, OS_CONTEXT_PSF29(context), 0, 0 + psq_st fp30, OS_CONTEXT_PSF30(context), 0, 0 + psq_st fp31, OS_CONTEXT_PSF31(context), 0, 0 + +_return: + blr +} diff --git a/src/RVL_SDK/os/OSError.c b/src/RVL_SDK/os/OSError.c new file mode 100644 index 000000000..83cb285ba --- /dev/null +++ b/src/RVL_SDK/os/OSError.c @@ -0,0 +1,135 @@ +#include +#include +#include + +OSErrorHandler __OSErrorTable[17]; +u32 __OSFpscrEnableBits = 0xF8; + +__declspec(weak) void OSReport(const char* msg, ...) { + va_list mark; + va_start(mark, msg); + vprintf(msg, mark); + va_end(mark); +} + +__declspec(weak) void OSVReport(const char* msg, va_list list) +{ + vprintf(msg, list); +} + +__declspec(weak) void OSPanic(const char *pFile, int line_num, const char *msg, ...) { + va_list mark; + u32 i; + u32* stackPtr; + + OSDisableInterrupts(); + va_start(mark, msg); + vprintf(msg, mark); + va_end(mark); + // report line number + OSReport(" in \"%s\" on line %d.\n", pFile, line_num); + // report the header of the table for the stack trace + OSReport("\nAddress: Back Chain LR Save\n"); + + // dump stack trace + for (i = 0, stackPtr = (u32*)OSGetStackPointer(); stackPtr && (u32)stackPtr != 0xFFFFFFFF && i++ < 16; stackPtr = (u32*)*stackPtr) { + OSReport("0x%08x: 0x%08x 0x%08x\n", stackPtr, stackPtr[0], stackPtr[1]); + } + + PPCHalt(); +} + +OSErrorHandler OSSetErrorHandler(OSError error, OSErrorHandler handler) { + OSErrorHandler oldHandler; + BOOL enabled; + + enabled = OSDisableInterrupts(); + oldHandler = __OSErrorTable[error]; + __OSErrorTable[error] = handler; + + if (error == 16) { + u32 msr; + u32 fpscr; + OSThread* thread; + msr = PPCMfmsr(); + PPCMtmsr(msr | 0x2000); + fpscr = PPCMffpscr(); + + if (handler) { + for (thread = __OSActiveThreadQueue.head; thread; thread = thread->linkActive.next) { + thread->context.srr1 |= 0x800 | 0x100; + + if ((thread->context.state & 1) == 0) { + int i; + thread->context.state |= 1; + + for (i = 0; i < 32; ++i) { + *(u64*) &thread->context.fpr[i] = (u64) 0xffffffffffffffffLL; + *(u64*) &thread->context.psf[i] = (u64) 0xffffffffffffffffLL; + } + + thread->context.fpscr = 4; + } + + thread->context.fpscr |= __OSFpscrEnableBits & 0xF8; + thread->context.fpscr &= 0x6005F8FF; + } + + fpscr |= __OSFpscrEnableBits & 0xF8; + msr |= 0x800 | 0x100; + } + else { + for (thread = __OSActiveThreadQueue.head; thread; thread = thread->linkActive.next) { + thread->context.srr1 &= ~(0x800 | 0x100); + thread->context.fpscr &= ~0xF8; + thread->context.fpscr &= ~0x6005F8FF; + } + + fpscr &= ~0xF8; + msr &= ~(0x800 | 0x100); + } + + fpscr &= ~(0x6005F8FF); + PPCMtfpscr(fpscr); + PPCMtmsr(msr); + } + + OSRestoreInterrupts(enabled); + return oldHandler; +} + +void __OSUnhandledException(__OSException exception, OSContext *context, u32 dsisr, u32 dar) { + OSTime now; + now = OSGetTime(); + + if (!(context->srr1 & 2)) { + OSReport("Non-recoverable Exception %d", exception); + } + else { + if (exception == 6 && (context->srr1 & (0x80000000 >> 11)) && __OSErrorTable[16] != 0) { + u32 fpscr; + u32 msr; + exception = 16; + msr = PPCMfmsr(); + PPCMtmsr(msr | 0x2000); + + if (__OSFPUContext) { + OSSaveFPUContext((OSContext*)__OSFPUContext); + } + + fpscr = PPCMffpscr(); + fpscr &= 0x6005F8FF; + PPCMtfpscr(fpscr); + + if (__OSFPUContext == context) { + OSDisableScheduler(); + __OSErrorTable[exception](exception, context, dsisr, dar); + context->srr1 &= ~0x2000; + __OSFPUContext = 0; + context->fpscr &= 0x6005F8FF; + OSEnableScheduler(); + + } + } + } +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSExec.c b/src/RVL_SDK/os/OSExec.c new file mode 100644 index 000000000..2a1831a30 --- /dev/null +++ b/src/RVL_SDK/os/OSExec.c @@ -0,0 +1,205 @@ +#include +#include +#include +#include +#include +#include + +static volatile BOOL Prepared; +static volatile u32 DVDLowIntType = 0; +u32 __OSNextPartitionType = 0; + +OSExecParams* __OSExecParamsAddr : OS_BASE_CACHED + 0x30F0; + +BOOL __OSInReboot = FALSE; + +static BOOL PackArgs(void *addr, s32 argc, char* argv[]) { + s32 numArgs; + char* bootInfo2; + char* ptr; + char** list; + u32 i; + + bootInfo2 = (char*)addr; + memset(bootInfo2, 0, 0x2000); + + if (argc == 0) { + *(u32*)&bootInfo2[8] = 0; + } + else { + numArgs = argc; + ptr = bootInfo2 + 0x2000; + while (--argc >= 0) { + ptr -= (strlen(argv[argc]) + 1); + strcpy(ptr, argv[argc]); + argv[argc] = (char*)(ptr - bootInfo2); + } + + ptr = bootInfo2 + ((ptr - bootInfo2) & ~3); + ptr -= 4 * (numArgs + 1); + list = (char**)ptr; + + for (i = 0; i < numArgs + 1; i++) { + list[i] = argv[i]; + } + + ptr -= 4; + *(s32*)ptr = numArgs; + *(u32*)&bootInfo2[8] = (u32)(ptr - bootInfo2); + } + + return TRUE; +} + +static BOOL Utf16ToArg(char *dstArg, u16* srcName) { + char* srcPtr, *dstPtr; + u8 i, mask, shift; + + if (srcName != 0) { + srcPtr = (char*)srcName; + dstPtr = dstArg; + + while (*srcPtr || *(srcPtr + 1)) { + for (i = 0; i < 4; i++) { + mask = (u8)((i & 0x1) ? 0xF : 0xF0); + shift = (u8)((i & 0x1) ? 0 : 4); + + if (0 <= ((*srcPtr & mask) >> shift) && ((*srcPtr & mask) >> shift) < 0xA) { + *dstPtr = (char)(((*srcPtr & mask) >> shift) + 0x30); + } + else if(0xA <= ((*srcPtr & mask) >> shift) && ((*srcPtr & mask) >> shift) < 0x10) { + *dstPtr = (char)(((*srcPtr & mask) >> shift) + 0x57); + } + else { + return FALSE; + } + + dstPtr++; + + if (i & 1) { + srcPtr++; + } + } + } + + *dstPtr++ = 0; + return TRUE; + } + + return FALSE; +} + +BOOL PackInstallerArgs(void *addr, s32 argc, char* argv[]) { + s32 numArgs; + char* bootInfo2; + char* ptr; + char** list; + u32 i; + + bootInfo2 = (char*)addr; + memset(bootInfo2, 0, 0x2000); + + if (argc == 0) { + *(u32*)&bootInfo2[8] = 0; + } + else { + numArgs = argc; + ptr = bootInfo2 + 0x2000; + + while (--argc >= 0) { + if (argc < 2 || (argc % 2)) { + char* val = argv[argc]; + ptr -= (strlen(argv[argc]) + 1); + strcpy(ptr, val); + argv[argc] = (char*)(ptr - bootInfo2); + } + else { + u16* val = (u16*)argv[argc]; + ptr -= (wcslen(val) *4 + 1); + Utf16ToArg(ptr, val); + argv[argc] = (char*)(ptr - bootInfo2); + } + } + + ptr = bootInfo2 + ((ptr - bootInfo2) & ~3); + ptr -= 4 * (numArgs + 1); + + list = (char**)ptr; + + for (i = 0; i < numArgs + 1; i++) { + list[i] = argv[i]; + } + + ptr -= 4; + *(s32*)ptr = numArgs; + + *(u32*)&bootInfo2[8] = (u32)(ptr - bootInfo2); + } + + + return TRUE; +} + +static asm void Run(register void *ptr) { + fralloc + bl ICFlashInvalidate + sync + isync + mtctr ptr + bctr + + frfree + blr +} + +void __OSGetExecParams(OSExecParams *params) { + if (0x80000000 <= (u32)__OSExecParamsAddr) { + memcpy(params, __OSExecParamsAddr, 0x1C); + } + else { + params->valid = FALSE; + } +} + +#define TITLE_ID ((((u64)1) << 32) | (2)) + +void __OSLaunchMenu(void) { + u8 i; + s32 rc; + u32 ticketCnt = 1; + ESTicketView* t; + ESSysVersion version = 0x0000000100000003; + GXColor bg = { 0, 0, 0, 0}; + GXColor fg = { 255, 255, 255, 0 }; + + OSSetArenaLo((void*)0x81280000); + OSSetArenaHi((void*)0x812F0000); + rc = ESP_InitLib(); + + if (rc != 0) { + return; + } + + rc = ESP_GetTicketViews(TITLE_ID, NULL, &ticketCnt); + + if (ticketCnt != 1 || rc != 0) { + return; + } + + t = (ESTicketView*)OSAllocFromMEM1ArenaLo(OSRoundUp32B(sizeof(ESTicketView) * ticketCnt), 32); + rc = ESP_GetTicketViews(TITLE_ID, t, &ticketCnt); + + if (rc != 0) { + return; + } + + rc = ESP_LaunchTitle(TITLE_ID, t); + + if (rc != 0) { + return; + } + + while (1) { + + } +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSFatal.c b/src/RVL_SDK/os/OSFatal.c new file mode 100644 index 000000000..07525e76d --- /dev/null +++ b/src/RVL_SDK/os/OSFatal.c @@ -0,0 +1,262 @@ +#include +#include +#include +#include +#include +#include + +typedef struct OSFatalParam { + GXColor fg; + GXColor bg; + const char* msg; +} OSFatalParam; + +static OSFatalParam FatalParam; +static OSContext FatalContext; + +extern void OSDefaultExceptionHandler(__OSException, OSContext *); +static void Halt(void); + +static void ScreenClear(void* xfb, u16 xfbW, u16 xfbH, GXColor yuv) { + int i, j; + u8* ptr; + + ptr = xfb; + for (i = 0; i < xfbH; i++) { + for (j = 0; j < xfbW; j += 2) { + *ptr++ = yuv.r; + *ptr++ = yuv.g; + *ptr++ = yuv.r; + *ptr++ = yuv.b; + } + } +} + +static void ScreenReport(void* xfb, u16 xfbW, u16 xfbH, GXColor yuv, + s32 x, s32 y, s32 leading, const char* string) +{ + + u8* ptr; + s32 width; + u32 i, j; + u32 image[24 / 8 * 24]; // 24 x 24 + u32 k, l; + u8 Y; + u32 pixel; + s32 col; + +NextLine: + if (xfbH - 24 < y) { + return; + } + + ptr = (u8*) xfb + (y * xfbW + x) * 2; + col = x; + + while (*string) { + if (*string == '\n') { + ++string; + y += leading; + goto NextLine; + } + + if (xfbW - 48 < col) { + y += leading; + goto NextLine; + } + + for (i = 0; i < 24; i++) { + j = 24 * (i / 8) + (i % 8); + image[j] = 0; + image[j + 32 / sizeof(u32)] = 0; + image[j + 64 / sizeof(u32)] = 0; + } + + string = OSGetFontTexel(string, image, 0, 24 / 4, &width); + for (i = 0; i < 24; i++) + { + j = 24 * (i / 8) + (i % 8); + for (k = 0; k < 24; k++) + { + l = j + 8 * (k / 8); + Y = (u8) ((image[l] >> ((7 - (k % 8)) * 4)) & 0xf); + if (0 < Y) + { + Y = (u8) (16 + ((255 - 16) * Y * yuv.r) / 255 / 15); + + pixel = i * xfbW + k; + ptr[pixel * 2] = Y; + + if ((col + k) & 1) { + ptr[pixel * 2 - 1] = yuv.g; + ptr[pixel * 2 + 1] = yuv.b; + } + else { + ptr[pixel * 2 - 1] = yuv.b; + ptr[pixel * 2 + 1] = yuv.g; + } + } + } + } + + ptr += width * 2; + col += width; + } +} + +static void ConfigureVideo(u16 xfbW, u16 xfbH) { + GXRenderModeObj mode; + + mode.fbWidth = xfbW; + mode.efbHeight = 480; + mode.xfbHeight = xfbH; + mode.viXOrigin = (720 - 640) / 2; + mode.viWidth = 640; + mode.viHeight = xfbH; + + switch (VIGetTvFormat()) + { + case VI_NTSC: + case VI_MPAL: + if (((((u32)(__VIRegs[0x36])) & 1))) { + mode.viTVmode = VI_TVMODE_NTSC_PROG; + mode.viYOrigin = (480 - 480) / 2; + mode.xFBmode = VI_XFBMODE_SF; + } + else { + mode.viTVmode = VI_TVMODE_NTSC_INT; + mode.viYOrigin = (480 - 480) / 2; + mode.xFBmode = VI_XFBMODE_DF; + } + break; + + case VI_EURGB60: + mode.viTVmode = VI_TVMODE_EURGB60_INT; + mode.viYOrigin = (480 - 480) / 2; + mode.xFBmode = VI_XFBMODE_DF; + break; + + case VI_PAL: + mode.viTVmode = VI_TVMODE_PAL_INT; + mode.viYOrigin = (574 - 480) / 2; + mode.xFBmode = VI_XFBMODE_DF; + break; + + default: + break; + } + + VIConfigure(&mode); + VIConfigurePan(0, 0, 640, 480); +} + +#define CLAMP(x,l,h) ((x > h) ? h : ((x < l) ? l : x)) + +static GXColor RGB2YUV(GXColor rgb) { + f32 Y, Cb, Cr; + GXColor yuv; + + Y = 0.257f * rgb.r + 0.504f * rgb.g + 0.098f * rgb.b + 16.0f + 0.5f; + Cb = -0.148f * rgb.r - 0.291f * rgb.g + 0.439f * rgb.b + 128.0f + 0.5f; + Cr = 0.439f * rgb.r - 0.368f * rgb.g - 0.071f * rgb.b + 128.0f + 0.5f; + + yuv.r = (u8)CLAMP(Y , 16, 235); + yuv.g = (u8)CLAMP(Cb, 16, 240); + yuv.b = (u8)CLAMP(Cr, 16, 240); + yuv.a = 0; + return yuv; +} + +void OSFatal(GXColor fg, GXColor bg, const char* msg) { + OSBootInfo* bootInfo = (OSBootInfo*)OSPhysicalToCached(0); + u32 count; + OSTime t; + + OSDisableInterrupts(); + OSDisableScheduler(); + OSClearContext(&FatalContext); + OSSetCurrentContext(&FatalContext); + __OSStopAudioSystem(); + VIInit(); + __OSUnmaskInterrupts(128); + VISetBlack(TRUE); + VIFlush(); + VISetPreRetraceCallback(NULL); + VISetPostRetraceCallback(NULL); + OSEnableInterrupts(); + + count = VIGetRetraceCount(); + while ((s32)VIGetRetraceCount() - (s32)count < 1) { + + } + + t = OSGetTime(); + while (!__OSCallShutdownFunctions(FALSE, 0) && (OSGetTime() - t) < OSMillisecondsToTicks(1000)); + + OSDisableInterrupts(); + __OSCallShutdownFunctions(TRUE, 0); + + EXISetExiCallback(0, NULL); + EXISetExiCallback(2, NULL); + + while (!EXILock(0, 1, NULL)) { + EXISync(0); + EXIDeselect(0); + EXIUnlock(0); + } + + EXIUnlock(0); + + while (((((u32)(__EXIRegs[3])) & 1)) == 1); + + __OSSetExceptionHandler(8, OSDefaultExceptionHandler); + GXAbortFrame(); + OSSetArenaLo((void*)0x81400000); + + if (!bootInfo->FSTLocation) { + OSSetArenaHi(*(void**)OSPhysicalToCached(0x3110)); + } + else { + OSSetArenaHi(bootInfo->FSTLocation); + } + + FatalParam.fg = fg; + FatalParam.bg = bg; + FatalParam.msg = msg; + OSSwitchFiber((u32)Halt, (u32)OSGetArenaHi()); +} + +static void Halt(void) { + u32 count; + OSFontHeader* fontData; + void* xfb; + u32 len; + OSFatalParam* fp; + + OSEnableInterrupts(); + fp = &FatalParam; + len = strlen(fp->msg) + 1; + fp->msg = memmove(OSAllocFromMEM1ArenaLo(len, 32), fp->msg, len); + fontData = OSAllocFromMEM1ArenaLo(0xA1004, 32); + OSLoadFont(fontData, OSGetArenaLo()); + xfb = OSAllocFromMEM1ArenaLo((u32)(640 * 480 * 2), 32); + ScreenClear(xfb, 640, 480, RGB2YUV(fp->bg)); + VISetNextFrameBuffer(xfb); + + ConfigureVideo(640, 480); + VIFlush(); + count = VIGetRetraceCount(); + + while ((s32)VIGetRetraceCount() - (s32)count < 2); + + ScreenReport(xfb, 640, 480, RGB2YUV(fp->fg), 48, 100, fontData->leading, fp->msg); + DCFlushRange(xfb, 640 * 480 * 2); + VISetBlack(FALSE); + VIFlush(); + count = VIGetRetraceCount(); + + while ((s32)VIGetRetraceCount() - (s32)count < 1); + OSDisableInterrupts(); + OSReport("%s\n", fp->msg); + PPCHalt(); +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSFont.c b/src/RVL_SDK/os/OSFont.c new file mode 100644 index 000000000..3cc0a4202 --- /dev/null +++ b/src/RVL_SDK/os/OSFont.c @@ -0,0 +1,588 @@ +#include +#include + +static u16 FontEncode = 0xFFFF; +static OSFontHeader* FontDataAnsi; +static OSFontHeader* FontDataSjis; +static BOOL FixedPitch; + +static char* ParseStringS(u16, const char *, OSFontHeader **, int *); +static char* ParseStringW(u16, const char *, OSFontHeader **, int *); +static char* (*ParseString)(u16, const char *, OSFontHeader **, int *); + +static u16 HankakuToCode[] = { + 0x020c, 0x020d, 0x020e, 0x020f, 0x0210, 0x0211, 0x0212, 0x0213, + 0x0214, 0x0215, 0x0216, 0x0217, 0x0218, 0x0219, 0x021a, 0x021b, + 0x021c, 0x021d, 0x021e, 0x021f, 0x0220, 0x0221, 0x0222, 0x0223, + 0x0224, 0x0225, 0x0226, 0x0227, 0x0228, 0x0229, 0x022a, 0x022b, + 0x022c, 0x022d, 0x022e, 0x022f, 0x0230, 0x0231, 0x0232, 0x0233, + 0x0234, 0x0235, 0x0236, 0x0237, 0x0238, 0x0239, 0x023a, 0x023b, + 0x023c, 0x023d, 0x023e, 0x023f, 0x0240, 0x0241, 0x0242, 0x0243, + 0x0244, 0x0245, 0x0246, 0x0247, 0x0248, 0x0249, 0x024a, 0x024b, + 0x024c, 0x024d, 0x024e, 0x024f, 0x0250, 0x0251, 0x0252, 0x0253, + 0x0254, 0x0255, 0x0256, 0x0257, 0x0258, 0x0259, 0x025a, 0x025b, + 0x025c, 0x025d, 0x025e, 0x025f, 0x0260, 0x0261, 0x0262, 0x0263, + 0x0264, 0x0265, 0x0266, 0x0267, 0x0268, 0x0269, 0x026a, 0x020c, + 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, + 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, + 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, + 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, 0x020c, + 0x020c, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f, 0x0270, 0x0271, + 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, 0x0278, 0x0279, + 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, 0x0280, 0x0281, + 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, 0x0288, 0x0289, + 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f, 0x0290, 0x0291, + 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, 0x0298, 0x0299, + 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, 0x02a0, 0x02a1, + 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, 0x02a8, 0x02a9, +}; + +static u16 Zenkaku2Code[] = { + 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, + 0x008, 0x009, 0x00A, 0x00B, 0x00C, 0x00D, 0x00E, 0x00F, + 0x010, 0x011, 0x012, 0x013, 0x014, 0x015, 0x016, 0x017, + 0x018, 0x019, 0x01A, 0x01B, 0x01C, 0x01D, 0x01E, 0x01F, + 0x020, 0x021, 0x022, 0x023, 0x024, 0x025, 0x026, 0x027, + 0x028, 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, + 0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, + 0x038, 0x039, 0x03A, 0x03B, 0x03C, 0x03D, 0x03E, + 0x03F, 0x040, 0x041, 0x042, 0x043, 0x044, 0x045, 0x046, + 0x047, 0x048, 0x049, 0x04A, 0x04B, 0x04C, 0x04D, 0x04E, + 0x04F, 0x050, 0x051, 0x052, 0x053, 0x054, 0x055, 0x056, + 0x057, 0x058, 0x059, 0x05A, 0x05B, 0x05C, 0x05D, 0x05E, + 0x05F, 0x060, 0x061, 0x062, 0x063, 0x064, 0x065, 0x066, + 0x067, 0x068, 0x069, 0x06A, 0x06B, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x06C, 0x06D, 0x06E, 0x06F, 0x070, 0x071, 0x072, 0x073, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x074, 0x075, 0x076, 0x077, 0x078, 0x079, 0x07A, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x07B, 0x07C, 0x07D, 0x07E, 0x07F, 0x080, + 0x081, 0x082, 0x083, 0x084, 0x085, 0x086, 0x087, 0x088, + 0x089, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x08A, 0x08B, 0x08C, 0x08D, 0x08E, 0x08F, 0x090, 0x091, + 0x000, 0x000, 0x000, 0x000, 0x092, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x093, + 0x094, 0x095, 0x096, 0x097, 0x098, 0x099, 0x09A, 0x09B, + 0x09C, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x09D, 0x09E, 0x09F, 0x0A0, 0x0A1, 0x0A2, 0x0A3, 0x0A4, + 0x0A5, 0x0A6, 0x0A7, 0x0A8, 0x0A9, 0x0AA, 0x0AB, 0x0AC, + 0x0AD, 0x0AE, 0x0AF, 0x0B0, 0x0B1, 0x0B2, 0x0B3, 0x0B4, + 0x0B5, 0x0B6, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x0B7, 0x0B8, 0x0B9, 0x0BA, 0x0BB, 0x0BC, 0x0BD, + 0x0BE, 0x0BF, 0x0C0, 0x0C1, 0x0C2, 0x0C3, 0x0C4, 0x0C5, + 0x0C6, 0x0C7, 0x0C8, 0x0C9, 0x0CA, 0x0CB, 0x0CC, 0x0CD, + 0x0CE, 0x0CF, 0x0D0, 0x000, 0x000, 0x000, 0x000, 0x0D1, + 0x0D2, 0x0D3, 0x0D4, 0x0D5, 0x0D6, 0x0D7, 0x0D8, 0x0D9, + 0x0DA, 0x0DB, 0x0DC, 0x0DD, 0x0DE, 0x0DF, 0x0E0, 0x0E1, + 0x0E2, 0x0E3, 0x0E4, 0x0E5, 0x0E6, 0x0E7, 0x0E8, 0x0E9, + 0x0EA, 0x0EB, 0x0EC, 0x0ED, 0x0EE, 0x0EF, 0x0F0, 0x0F1, + 0x0F2, 0x0F3, 0x0F4, 0x0F5, 0x0F6, 0x0F7, 0x0F8, 0x0F9, + 0x0FA, 0x0FB, 0x0FC, 0x0FD, 0x0FE, 0x0FF, 0x100, 0x101, + 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, + 0x10A, 0x10B, 0x10C, 0x10D, 0x10E, 0x10F, 0x110, 0x111, + 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118, 0x119, + 0x11A, 0x11B, 0x11C, 0x11D, 0x11E, 0x11F, 0x120, 0x121, + 0x122, 0x123, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, + 0x124, 0x125, 0x126, 0x127, 0x128, 0x129, 0x12A, 0x12B, + 0x12C, 0x12D, 0x12E, 0x12F, 0x130, 0x131, 0x132, 0x133, + 0x134, 0x135, 0x136, 0x137, 0x138, 0x139, 0x13A, 0x13B, + 0x13C, 0x13D, 0x13E, 0x13F, 0x140, 0x141, 0x142, 0x143, + 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14A, 0x14B, + 0x14C, 0x14D, 0x14E, 0x14F, 0x150, 0x151, 0x152, 0x153, + 0x154, 0x155, 0x156, 0x157, 0x158, 0x159, 0x15A, 0x15B, + 0x15C, 0x15D, 0x15E, 0x15F, 0x160, 0x161, 0x162, + 0x163, 0x164, 0x165, 0x166, 0x167, 0x168, 0x169, 0x16A, + 0x16B, 0x16C, 0x16D, 0x16E, 0x16F, 0x170, 0x171, 0x172, + 0x173, 0x174, 0x175, 0x176, 0x177, 0x178, 0x179, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x17A, + 0x17B, 0x17C, 0x17D, 0x17E, 0x17F, 0x180, 0x181, 0x182, + 0x183, 0x184, 0x185, 0x186, 0x187, 0x188, 0x189, 0x18A, + 0x18B, 0x18C, 0x18D, 0x18E, 0x18F, 0x190, 0x191, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x192, + 0x193, 0x194, 0x195, 0x196, 0x197, 0x198, 0x199, 0x19A, + 0x19B, 0x19C, 0x19D, 0x19E, 0x19F, 0x1A0, 0x1A1, 0x1A2, + 0x1A3, 0x1A4, 0x1A5, 0x1A6, 0x1A7, 0x1A8, 0x1A9, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, + 0x1AA, 0x1AB, 0x1AC, 0x1AD, 0x1AE, 0x1AF, 0x1B0, 0x1B1, + 0x1B2, 0x1B3, 0x1B4, 0x1B5, 0x1B6, 0x1B7, 0x1B8, 0x1B9, + 0x1BA, 0x1BB, 0x1BC, 0x1BD, 0x1BE, 0x1BF, 0x1C0, 0x1C1, + 0x1C2, 0x1C3, 0x1C4, 0x1C5, 0x1C6, 0x1C7, 0x1C8, 0x1C9, + 0x1CA, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x1CB, 0x1CC, 0x1CD, 0x1CE, 0x1CF, 0x1D0, 0x1D1, 0x1D2, + 0x1D3, 0x1D4, 0x1D5, 0x1D6, 0x1D7, 0x1D8, 0x1D9, + 0x1DA, 0x1DB, 0x1DC, 0x1DD, 0x1DE, 0x1DF, 0x1E0, 0x1E1, + 0x1E2, 0x1E3, 0x1E4, 0x1E5, 0x1E6, 0x1E7, 0x1E8, 0x1E9, + 0x1EA, 0x1EB, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x1EC, + 0x1ED, 0x1EE, 0x1EF, 0x1F0, 0x1F1, 0x1F2, 0x1F3, 0x1F4, + 0x1F5, 0x1F6, 0x1F7, 0x1F8, 0x1F9, 0x1FA, 0x1FB, 0x1FC, + 0x1FD, 0x1FE, 0x1FF, 0x200, 0x201, 0x202, 0x203, 0x204, + 0x205, 0x206, 0x207, 0x208, 0x209, 0x20A, 0x20B, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x20C, + 0x20D, 0x20E, 0x20F, 0x210, 0x211, 0x212, 0x213, 0x214, + 0x215, 0x216, 0x217, 0x218, 0x219, 0x21A, 0x21B, 0x21C, + 0x21D, 0x21E, 0x21F, 0x220, 0x221, 0x222, 0x223, 0x224, + 0x225, 0x226, 0x227, 0x228, 0x229, 0x22A, 0x22B, 0x22C, + 0x22D, 0x22E, 0x22F, 0x230, 0x231, 0x232, 0x233, 0x234, + 0x235, 0x236, 0x237, 0x238, 0x239, 0x23A, 0x23B, 0x23C, + 0x23D, 0x23E, 0x23F, 0x240, 0x241, 0x242, 0x243, 0x244, + 0x245, 0x246, 0x247, 0x248, 0x249, 0x24A, 0x24B, + 0x24C, 0x24D, 0x24E, 0x24F, 0x250, 0x251, 0x252, 0x253, + 0x254, 0x255, 0x256, 0x257, 0x258, 0x259, 0x25A, 0x25B, + 0x25C, 0x25D, 0x25E, 0x25F, 0x260, 0x261, 0x262, 0x263, + 0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26A, 0x26B, + 0x26C, 0x26D, 0x26E, 0x26F, 0x270, 0x271, 0x272, 0x273, + 0x274, 0x275, 0x276, 0x277, 0x278, 0x279, 0x27A, 0x27B, + 0x27C, 0x27D, 0x27E, 0x27F, 0x280, 0x281, 0x282, 0x283, + 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28A, 0x28B, + 0x28C, 0x28D, 0x28E, 0x28F, 0x290, 0x291, 0x292, 0x293, + 0x294, 0x295, 0x296, 0x297, 0x298, 0x299, 0x29A, 0x29B, + 0x29C, 0x29D, 0x29E, 0x29F, 0x2A0, 0x2A1, 0x2A2, 0x2A3, + 0x2A4, 0x2A5, 0x2A6, 0x2A7, 0x2A8, 0x2A9, 0x2AA, 0x2AB, + 0x2AC, 0x2AD, 0x2AE, 0x2AF, 0x2B0, 0x2B1, 0x2B2, 0x2B3, + 0x2B4, 0x2B5, 0x2B6, 0x2B7, 0x2B8, 0x2B9, 0x2BA, 0x2BB, + 0x2BC, 0x2BD, 0x2BE, 0x2BF, 0x2C0, 0x2C1, 0x2C2, 0x2C3, + 0x2C4, 0x2C5, 0x2C6, 0x2C7, 0x2C8, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, + 0x2C9, 0x2CA, 0x2CB, 0x2CC, 0x2CD, 0x2CE, 0x2CF, 0x2D0, + 0x2D1, 0x2D2, 0x2D3, 0x2D4, 0x2D5, 0x2D6, 0x2D7, 0x2D8, + 0x2D9, 0x2DA, 0x2DB, 0x2DC, 0x2DD, 0x2DE, 0x2DF, 0x2E0, + 0x2E1, 0x2E2, 0x2E3, 0x2E4, 0x2E5, 0x2E6, 0x000, 0x2E7, + 0x2E8, 0x2E9, 0x2EA, 0x2EB, 0x2EC, 0x2ED, 0x2EE, 0x2EF, + 0x2F0, 0x2F1, 0x2F2, 0x2F3, 0x2F4, 0x2F5, 0x2F6, 0x2F7, + 0x2F8, 0x2F9, 0x2FA, 0x2FB, 0x2FC, 0x2FD, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x2FE, + 0x2FF, 0x300, 0x301, 0x302, 0x303, 0x304, 0x305, 0x306, + 0x307, 0x308, 0x309, 0x30A, 0x30B, 0x30C, 0x30D, 0x30E, + 0x30F, 0x310, 0x311, 0x312, 0x313, 0x314, 0x315, 0x316, + 0x317, 0x318, 0x319, 0x31A, 0x31B, 0x000 +}; + +static BOOL IsSjisLeadByte(u8 c) { + return (0x81 <= c && c <= 0x9F) || (0xE0 <= c && c <= 0xFC); +} + +static BOOL IsSjisTrailByte(u8 c) { + return 0x40 <= c && c <= 0xFC && c != 0x7F; +} + +static int GetFontCode(u16 encode, u16 code) +{ + if (encode == 1) + { + if (0x20 <= code && code <= 0xDF) { + return (int) HankakuToCode[code - 0x20]; + } + else if (0x889E < code && code <= 0x9872) { + int i, j; + + i = ((code >> 8) - 0x88) * 188; + j = code & 255; + if (!IsSjisTrailByte((u8)j)) { + return 0; + } + + j -= 0x40; + + if (j >= 0x40) { + j--; + } + + return (int)(i + j + 0x2BE); + } + else if (0x8140 <= code && code < 0x879E) { + int i, j; + + i = ((code >> 8) - 0x81) * 188; + j = code & 255; + + if (!IsSjisTrailByte((u8)j)) { + return 0; + } + + j -= 0x40; + + if (j >= 0x40) { + j--; + } + + return (int)Zenkaku2Code[i + j]; + } + } + else { + if ((code > 0x20) && (code <= 0xFF)) { + return code - 0x20; + } + } + return 0; +} + +static void Decode(u8 *s, u8 *d) +{ + int i, j, k, p, q, r7, r25, cnt, os; + unsigned flag, code; + + os = *(int*)&s[4]; + r7 = *(int*)&s[8]; + r25 = *(int*)&s[12]; + q = 0; + flag = 0; + p = 16; + + do { + if (flag == 0) { + code = *(unsigned*)&s[p]; + p += 4; + flag = 32; + } + if (code & 0x80000000) { + d[q++] = s[r25++]; + } + else { + j = (s[r7] << 8) | s[r7+1]; + r7 += 2; + k = q - (j & 0xFFF); + cnt = j >> 12; + + if (cnt == 0) { + cnt = s[r25++] + 18; + } + else { + cnt += 2; + } + + for (i = 0; i < cnt; i++, q++, k++) { + d[q] = d[k-1]; + } + } + + code <<= 1; + --flag; + } while (q < os); +} + +static u32 GetFontSize(u8* buf) { + if (buf[0] == 'Y' && buf[1] == 'a' && buf[2] == 'y') { + return *(u32*) &buf[4]; + } + + return 0; +} + +u16 OSGetFontEncode(void) { + if (FontEncode != 0xFFFF) { + return FontEncode; + } + + switch (*(u32*)OSPhysicalToCached(0xCC)) { + case 0: + FontEncode = (u16)((__VIRegs[0x37] & 2) ? 1 : 0); + break; + case 1: + case 2: + default: + FontEncode = 0; + break; + } + + ParseString = ParseStringS; + return FontEncode; +} + +u16 OSSetFontEncode(u16 encode) { + u16 prev = OSGetFontEncode(); + if (encode <= 5) { + FontEncode = encode; + + if (3 <= encode && encode <= 5) { + ParseString = ParseStringW; + } + } + + return prev; +} + +static void ReadROM(void* buf, int length, int offset) { + int len; + + while (0 < length) { + len = (length <= 256) ? length : 256; + length -= len; + while (!__OSReadROM(buf, len, offset)) { + + } + + offset += len; + (u8*)buf += len; + } +} + +#define CharsInSheet(fontData) ((fontData)->sheetColumn * (fontData)->sheetRow) +#define WidthTable(fontData) ((u8*) (fontData) + (fontData)->widthTable) + +u32 ReadFont(void* img, u16 encode, void* fontData) +{ u32 size; + + if (encode == 1) { + ReadROM(img, 0x4D000, 0x1AFF00); + } + else { + ReadROM(img, 0x3000, 0x1AFF00 + 0x4D000); + } + + size = GetFontSize(img); + + if (size <= 0) { + return 0; + } + + Decode(img, fontData); + if (encode == 1) { + OSFontHeader* font = fontData; + int fontCode; + u8* imageSrc; + int sheet; + int numChars; + int row; + int column; + int x, y; + u8* src; + const u16 imageT[4] = { 0x2abe, 0x003d, 0x003d, 0x003d }; + + fontCode = GetFontCode(encode, 'T'); + sheet = fontCode / CharsInSheet(font); + numChars = fontCode - sheet * CharsInSheet(font); + row = numChars / font->sheetColumn; + column = numChars - row * font->sheetColumn; + row *= font->cellHeight; + column *= font->cellWidth; + + imageSrc = (u8*) font + font->sheetImage; + imageSrc += sheet * font->sheetSize / 2; + for (y = 4; y < 8; ++y) { + x = 0; + src = imageSrc + (font->sheetWidth / 8) * 32 / 2 * ((row + y) / 8); + src += 32 / 2 * ((column + x) / 8); + src += (8 / 4) * ((row + y) % 8); + src += ((column + x) % 8) / 4; + + *(u16*)src = imageT[y - 4]; + } + } + return size; +} + +u32 OSLoadFont(OSFontHeader* fontData, void* tmp) { + u16 encode; + u32 size; + + encode = OSGetFontEncode(); + + switch (encode) { + case 0: + FontDataAnsi = fontData; + size = ReadFont(tmp, 0, FontDataAnsi); + break; + case 1: + FontDataSjis = fontData; + size = ReadFont(tmp, 1, FontDataSjis); + break; + case 3: + case 4: + case 5: + FontDataAnsi = fontData; + size = ReadFont(tmp, 0, FontDataAnsi); + if (0 < size) { + FontDataSjis = (OSFontHeader*) ((u8*) FontDataAnsi + size); + size += ReadFont(tmp, 1, FontDataSjis); + } + break; + default: + size = 0; + break; + } + + return size; +} + +static char* ParseStringS(u16 encode, const char* string, OSFontHeader **pfont, int *pfontCode) { + OSFontHeader* font; + u16 code = 0; + + switch (encode) { + case 0: + font = FontDataAnsi; + code = (u8)*string; + + if (code == '\0') { + break; + } + + ++string; + break; + case 1: + font = FontDataSjis; + code = (u8)*string; + + if (code == '\0') { + break; + } + + ++string; + if (IsSjisLeadByte((u8)code) && IsSjisTrailByte((u8)*string)) { + code = (u16)((code << 8) | (u8)*string++); + } + break; + } + + *pfont = font; + *pfontCode = GetFontCode(encode, code); + return (char*)string; +} + +static char* ParseStringW(u16 encode, const char* string, OSFontHeader** pfont, int* pfontCode) { + OSFontHeader* font; + u16 code = 0; + u32 utf32 = 0; + + switch (encode) { + case 0: + font = FontDataAnsi; + code = (u8)*string; + + if (code == '\0') { + break; + } + ++string; + break; + case 1: + font = FontDataSjis; + code = (u8)*string; + if (code == '\0') { + break; + } + ++string; + if (IsSjisLeadByte((u8) code) && IsSjisTrailByte((u8)*string)) { + code = (u16) ((code << 8) | (u8)*string++); + } + break; + case 3: + string = OSUTF8to32(string, &utf32); + break; + case 4: + string = (const char*)OSUTF16to32((const u16*)string, &utf32); + break; + case 5: + utf32 = *(const u32*)string; + if (utf32 != 0) { + string += sizeof(u32); + } + break; + } + if (utf32) { + encode = 0; + font = FontDataAnsi; + code = OSUTF32toANSI(utf32); + if (code == 0 || FixedPitch && utf32 <= 0x7F) { + code = OSUTF32toSJIS(utf32); + if (code) { + encode = 1; + font = FontDataSjis; + } + } + } + + *pfont = font; + *pfontCode = GetFontCode(encode, code); + return (char*)string; +} + +char* OSGetFontTexel(const char* string, void* image, s32 pos, s32 stride, s32* width) { + u16 encode; + OSFontHeader* font; + u8* src; + u8* dst; + int fontCode; + int sheet; + int numChars; + int row; + int column; + int x; + int y; + int offsetSrc; + int offsetDst; + u8* colorIndex; + u8* imageSrc; + + encode = OSGetFontEncode(); + string = (const char*)ParseString(encode, string, &font, &fontCode); + colorIndex = (u8*) &font->c0; + sheet = fontCode / CharsInSheet(font); + numChars = fontCode - sheet * CharsInSheet(font); + row = numChars / font->sheetColumn; + column = numChars - row * font->sheetColumn; + row *= font->cellHeight; + column *= font->cellWidth; + imageSrc = (u8*) font + font->sheetImage; + imageSrc += sheet * font->sheetSize / 2; + + for (y = 0; y < font->cellHeight; ++y) { + for (x = 0; x < font->cellWidth; ++x) { + src = imageSrc + (font->sheetWidth / 8) * 32 / 2 * ((row + y) / 8); + src += 32 / 2 * ((column + x) / 8); + src += (8 / 4) * ((row + y) % 8); + src += ((column + x) % 8) / 4; + offsetSrc = (column + x) % 4; + dst = (u8*)image + (stride * 4 / 8) * 32 * (y / 8); + dst += 32 * ((pos + x) / 8); + dst += (8 / 2) * (y % 8); + dst += ((pos + x) % 8) / 2; + offsetDst = (pos + x) % 2; + + *dst |= (u8)(colorIndex[(*src >> (6 - 2 * offsetSrc)) & 3] & (offsetDst ? 0xF : 0xF0)); + } + } + + if (width) { + *width = WidthTable(font)[fontCode]; + } + return (char*)string; +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSInterrupt.c b/src/RVL_SDK/os/OSInterrupt.c new file mode 100644 index 000000000..fa1dbe35c --- /dev/null +++ b/src/RVL_SDK/os/OSInterrupt.c @@ -0,0 +1,538 @@ +#include +#include +#include +#include + +static __OSInterruptHandler* InterruptHandlerTable; + +static OSInterruptMask InterruptPrioTable[] = +{ + 0x100, + 0x40, + 0xF8000000, + 0x200, + 0x80, + 0x10, + 0x3000, + 0x20, + 0x3FF8C00, + 0x4000000, + 0x4000, + 0xFFFFFFFF +}; + +// forward decl for init +static asm void ExternalInterruptHandler( register __OSException, register OSContext *); + +static OSInterruptMask SetInterruptMask(OSInterruptMask, OSInterruptMask); + +asm BOOL OSDisableInterrupts(void) { + nofralloc + mfmsr r3 + rlwinm r4, r3, 0, 17, 15 + mtmsr r4 + extrwi r3, r3, 1, 16 + blr +} + +BOOL OSEnableInterrupts(void) { + asm { + mfmsr r3 + ori r4, r3, 0x8000 + mtmsr r4 + extrwi r3, r3, 1, 16 + } +} + +BOOL OSRestoreInterrupts(register BOOL level) { + asm { + cmpwi level, 0 + mfmsr r4 + beq disable + ori r5, r4, 0x00008000 + b restore + + disable: + rlwinm r5, r4, 0, 17, 15 + + restore: + mtmsr r5 + extrwi r3, r4, 1, 16 + } +} + +__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt, __OSInterruptHandler handler) { + __OSInterruptHandler oldHandler; + oldHandler = InterruptHandlerTable[interrupt]; + InterruptHandlerTable[interrupt] = handler; + return oldHandler; +} + +__OSInterruptHandler __OSGetInterruptHandler(s32 interrupt) { + return InterruptHandlerTable[interrupt]; +} + +OSInterruptMask __OSMaskInterrupts(OSInterruptMask new_mask) { + BOOL v2; + OSInterruptMask user_interrupt; + OSInterruptMask os_interrupt; + OSInterruptMask mask; + + v2 = OSDisableInterrupts(); + // load the user interrupt mask + user_interrupt = *(OSInterruptMask*)0x800000C4; + os_interrupt = *(OSInterruptMask*)0x800000C8; + mask = ~(user_interrupt | os_interrupt) & new_mask; + // set the new user interrupt mask + new_mask |= user_interrupt; + *(OSInterruptMask*)0x800000C4 = new_mask; + + while (mask) { + mask = SetInterruptMask(mask, new_mask | os_interrupt); + } + + OSRestoreInterrupts(v2); + return user_interrupt; +} + +void __OSInterruptInit(void) { + // set our interrupt handler table to the __OSInterruptTable + InterruptHandlerTable = (void*)0x80003040; + memset(InterruptHandlerTable, 0, 32 * sizeof(__OSInterruptHandler)); + *(OSInterruptMask*)0x800000C4 = 0; + *(OSInterruptMask*)0x800000C8 = 0; + *(int*)0xCC003004 = 240; + *(int*)0xCD000034 = 0x40000000; + + // this function call is inlined + __OSMaskInterrupts(OS_INTERRUPTMASK_MEM | OS_INTERRUPTMASK_DSP | OS_INTERRUPTMASK_AI | OS_INTERRUPTMASK_EXI | OS_INTERRUPTMASK_PI); + __OSSetExceptionHandler(4, ExternalInterruptHandler); +} + +static OSInterruptMask SetInterruptMask(OSInterruptMask mask, OSInterruptMask current) { + u32 reg; + + switch(__cntlzw(mask)) { + case 0: + case 1: + case 2: + case 3: + case 4: + reg = 0; + + if (!(current & 0x80000000)) { + reg |= 1; + } + + if (!(current & 0x40000000)) { + reg |= 2; + } + + if (!(current & 0x20000000)) { + reg |= 4; + } + + if (!(current & 0x10000000)) { + reg |= 8; + } + + if (!(current & 0x8000000)) { + reg |= 16; + } + + __MEMRegs[0xE] = (u16)reg; + mask &= 0x7FFFFFF; + break; + + case 5: + case 6: + case 7: + reg = __DSPRegs[5]; + reg &= 0xFFFFFE07; + + if (!(current & 0x4000000)) { + reg |= 0x10; + } + + if (!(current & 0x2000000)) { + reg |= 0x40; + } + + if (!(current & 0x1000000)) { + reg |= 0x100; + } + + __DSPRegs[5] = (u16)reg; + mask &= 0xF8FFFFFF; + break; + + case 8: + reg = __AIRegs[0]; + reg &= 0xFFFFFFD3; + + if (!(current & 0x800000)) { + reg |= 4; + } + + __AIRegs[0] = reg; + mask &= 0xFF7FFFFF; + break; + + case 9: + case 10: + case 11: + reg = __EXIRegs[0]; + reg &= 0xFFFFD3F0; + + if (!(current & 0x400000)) { + reg |= 1; + } + + if (!(current & 0x200000)) { + reg |= 4; + } + + if (!(current & 0x100000)) { + reg |= 0x400; + } + + __EXIRegs[0] = reg; + mask &= 0xFF8FFFFF; + break; + + case 12: + case 13: + case 14: + reg = __EXIRegs[5]; + reg &= 0xFFFFF3F0; + + if (!(current & 0x80000)) { + reg |= 1; + } + + if (!(current & 0x40000)) { + reg |= 4; + } + + if (!(current & 0x20000)) { + reg |= 0x400; + } + + __EXIRegs[5] = reg; + mask &= 0xFFF1FFFF; + break; + + case 15: + case 16: + reg = __EXIRegs[0xA]; + reg &= 0xFFFFFFF0; + + if (!(current & 0x10000)) { + reg |= 1; + } + + if (!(current & 0x8000)) { + reg |= 4; + } + + __EXIRegs[0xA] = reg; + mask &= 0xFFFE7FFF; + + break; + + case 17: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 18: + case 19: + case 26: + case 27: + reg = 0xF0; + + if (!(current & 0x4000)) { + reg |= 0x800; + } + + if (!(current & 0x800)) { + reg |= 8; + } + + if (!(current & 0x400)) { + reg |= 4; + } + + if (!(current & 0x200)) { + reg |= 2; + } + + if (!(current & 0x100)) { + reg |= 1; + } + + if (!(current & 0x80)) { + reg |= 0x100; + } + + if (!(current & 0x40)) { + reg |= 0x1000; + } + + if (!(current & 0x2000)) { + reg |= 0x200; + } + + if (!(current & 0x1000)) { + reg |= 0x400; + } + + if (!(current & 0x20)) { + reg |= 0x2000; + } + + if (!(current & 0x10)) { + reg |= 0x4000; + } + + __PIRegs[1] = reg; + mask &= 0xFFFF800F; + break; + + default: + break; + } + + return mask; +} + +OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask new_mask) { + BOOL v2; + OSInterruptMask user_interrupt; + OSInterruptMask os_interrupt; + OSInterruptMask mask; + + v2 = OSDisableInterrupts(); + user_interrupt = *(OSInterruptMask*)0x800000C4; + os_interrupt = *(OSInterruptMask*)0x800000C8; + mask = (user_interrupt | os_interrupt) & new_mask; + new_mask = user_interrupt & ~new_mask; + *(OSInterruptMask*)0x800000C4 = new_mask; + + while (mask) { + mask = SetInterruptMask(mask, new_mask | os_interrupt); + } + + OSRestoreInterrupts(v2); + return user_interrupt; +} + +volatile OSTime __OSLastInterruptTime; +volatile __OSInterrupt __OSLastInterrupt; +volatile u32 __OSLastInterruptSrr0; + +void __OSDispatchInterrupt(__OSException exception, OSContext* context) { + u32 instr, mask, reg; + OSInterruptMask cause, unmasked; + OSInterruptMask* prio; + __OSInterrupt interrupt; + __OSInterruptHandler handler; + + instr = __PIRegs[0]; + instr &= 0xFFFEFFFF; + mask = __PIRegs[1]; + + if (instr == 0 || (instr & mask) == 0) { + OSLoadContext(context); + } + + cause = 0; + + if (instr & 0x80) { + reg = __MEMRegs[0xF]; + + if (reg & 0x1) { + cause |= 0x80000000; + } + + if (reg & 0x2) { + cause |= 0x40000000; + } + + if (reg & 0x4) { + cause |= 0x20000000; + } + + if (reg & 0x8) { + cause |= 0x10000000; + } + + if (reg & 0x10) { + cause |= 0x8000000; + } + } + + if (instr & 0x40) { + reg = __DSPRegs[5]; + + if (reg & 0x8) { + cause |= 0x4000000; + } + + if (reg & 0x20) { + cause |= 0x2000000; + } + + if (reg & 0x80) { + cause |= 0x1000000; + } + } + + if (instr & 0x20) { + reg = __AIRegs[0]; + + if (reg & 0x8) { + cause |= 0x800000; + } + } + + if (instr & 0x10) { + reg = __EXIRegs[0]; + + if (reg & 0x2) { + cause |= 0x400000; + } + + if (reg & 0x8) { + cause |= 0x200000; + } + + if (reg & 0x800) { + cause |= 0x100000; + } + + reg = __EXIRegs[5]; + + if (reg & 0x2) { + cause |= 0x80000; + } + + if (reg & 0x8) { + cause |= 0x40000; + } + + if (reg & 0x800) { + cause |= 0x20000; + } + + reg = __EXIRegs[0xA]; + + if (reg & 0x2) { + cause |= 0x10000; + } + + if (reg & 0x8) { + cause |= 0x8000; + } + } + + if ((instr & 0x2000) != 0) { + cause |= 0x20; + } + + + if ((instr & 0x1000) != 0) { + cause |= 0x40; + } + + if ((instr & 0x400) != 0) { + cause |= 0x1000; + } + + if ((instr & 0x200) != 0) { + cause |= 0x2000; + } + + if ((instr & 0x100) != 0) { + cause |= 0x80; + } + + if ((instr & 8) != 0) { + cause |= 0x800; + } + + if ((instr & 4) != 0) { + cause |= 0x400; + } + + if ((instr & 2) != 0) { + cause |= 0x200; + } + + if ((instr & 0x800) != 0) { + cause |= 0x4000; + } + + if ((instr & 1) != 0) { + cause |= 0x100; + } + + if ((instr & 0x4000) != 0) { + cause |= 0x10; + } + + unmasked = cause & ~(*(OSInterruptMask*)OSPhysicalToCached(0xC4) | *(OSInterruptMask*)OSPhysicalToCached(0xC8)); + + if (unmasked) { + for (prio = InterruptPrioTable; ; ++prio) { + if (unmasked & *prio) { + interrupt = (__OSInterrupt)__cntlzw(unmasked & *prio); + break; + } + } + + handler = __OSGetInterruptHandler(interrupt); + + if (handler) { + if (4 < interrupt) { + __OSLastInterrupt = interrupt; + __OSLastInterruptTime = OSGetTime(); + __OSLastInterruptSrr0 = context->srr0; + } + + OSDisableScheduler(); + handler(interrupt, context); + OSEnableScheduler(); + __OSReschedule(); + OSLoadContext(context); + } + } + + OSLoadContext(context); +} + +static asm void ExternalInterruptHandler(register __OSException, register OSContext *pContext) { + nofralloc + stw r0, OS_CONTEXT_R0(pContext) + stw r1, OS_CONTEXT_R1(pContext) + stw r2, OS_CONTEXT_R2(pContext) + stmw r6, OS_CONTEXT_R6(pContext) + mfspr r0, GQR1 + stw r0, OS_CONTEXT_GQR1(pContext) + mfspr r0, GQR2 + stw r0, OS_CONTEXT_GQR2(pContext) + mfspr r0, GQR3 + stw r0, OS_CONTEXT_GQR3(pContext) + mfspr r0, GQR4 + stw r0, OS_CONTEXT_GQR4(pContext) + mfspr r0, GQR5 + stw r0, OS_CONTEXT_GQR5(pContext) + mfspr r0, GQR6 + stw r0, OS_CONTEXT_GQR6(pContext) + mfspr r0, GQR7 + stw r0, OS_CONTEXT_GQR7(pContext) + stwu r1, -8(r1) + b __OSDispatchInterrupt +} diff --git a/src/RVL_SDK/os/OSIpc.c b/src/RVL_SDK/os/OSIpc.c new file mode 100644 index 000000000..469b3cb4e --- /dev/null +++ b/src/RVL_SDK/os/OSIpc.c @@ -0,0 +1,18 @@ +#include +#include + +static void* IpcBufferHi; +static void* IpcBufferLo = (void*)0xFFFFFFFF; + +void* __OSGetIPCBufferHi(void) { + return IpcBufferHi; +} + +void* __OSGetIPCBufferLo(void) { + return IpcBufferLo; +} + +void __OSInitIPCBuffer(void) { + IpcBufferLo = (void*)*(u32*)OSPhysicalToCached(0x3100 + 0x0030); + IpcBufferHi = (void*)*(u32*)OSPhysicalToCached(0x3100 + 0x0034); +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSLink.c b/src/RVL_SDK/os/OSLink.c new file mode 100644 index 000000000..cd63862e3 --- /dev/null +++ b/src/RVL_SDK/os/OSLink.c @@ -0,0 +1,8 @@ +#include + +void __OSModuleInit(void) { + /* SMG1 doesn't use REL so these are never used */ + *(int*)0x800030CC = 0; // last loaded REL + *(int*)0x800030C8 = 0; // first loaded REL + *(int*)0x800030D0 = 0; // REL name table +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSMemory.c b/src/RVL_SDK/os/OSMemory.c new file mode 100644 index 000000000..d0f2f2633 --- /dev/null +++ b/src/RVL_SDK/os/OSMemory.c @@ -0,0 +1,649 @@ +#include +#include +#include + +extern OSErrorHandler __OSErrorTable[]; +static BOOL OnShutdown( BOOL final, u32 event ); + +static OSShutdownFunctionInfo ShutdownFunctionInfo = { + OnShutdown, + 127, + 0, + 0 +}; + +#define TRUNC(n, a) (((u32) (n)) & ~((a) - 1)) +#define ROUND(n, a) (((u32) (n) + (a) - 1) & ~((a) - 1)) + +u32 OSGetPhysicalMem1Size(void) { + return *(u32*)OSPhysicalToCached(0x3100); +} + +u32 OSGetPhysicalMem2Size(void) { + return *(u32*)OSPhysicalToCached(0x3118); +} + +u32 OSGetConsoleSimulatedMem1Size(void) { + return *(u32*)OSPhysicalToCached(0x3104); +} + +u32 OSGetConsoleSimulatedMem2Size(void) { + return *(u32*)OSPhysicalToCached(0x311C); +} + +static BOOL OnShutdown(BOOL final, u32 event) { + if (final != FALSE) { + __MEMRegs[8] = 0xFF; + __OSMaskInterrupts(0xF0000000); + } + + return TRUE; +} + +void MEMIntrruptHandler(__OSInterrupt interrupt, OSContext *context) { + u32 addr, cause; + cause = __MEMRegs[0xF]; + addr = (((u32)(__MEMRegs[0x12] & 0x3FF) << 16) | __MEMRegs[0x11]); + __MEMRegs[0x10] = 0; + + if (__OSErrorTable[15]) { + __OSErrorTable[15](15, context, cause, addr); + return; + } + + __OSUnhandledException(15, context, cause, addr); +} + +void OSProtectRange(u32 chan, void *addr, u32 nBytes, u32 control) { + BOOL enabled; + u32 start, end; + u16 reg; + + if (4 <= chan) { + return; + } + + control &= 3; + end = (u32)addr + nBytes; + start = TRUNC(addr, 1 << 10); + end = ROUND(end, 1 << 10); + DCFlushRange((void*)start, end - start); + enabled = OSDisableInterrupts(); + __OSMaskInterrupts(0x80000000u >> (chan)); + __MEMRegs[0 + 2 * chan] = (u16)(start >> 10); + __MEMRegs[1 + 2 * chan] = (u16)(end >> 10); + reg = __MEMRegs[8]; + reg &= ~(3 << 2 * chan); + reg |= control << 2 * chan; + __MEMRegs[8] = reg; + + if (control != 3) { + __OSUnmaskInterrupts(0x80000000u >> (chan)); + } + + OSRestoreInterrupts(enabled); +} + +static asm void ConfigMEM1_24MB(void) { + nofralloc + addi r7, r0, 0 + + addis r4,r0,0x00000002@ha + addi r4,r4,0x00000002@l + addis r3,r0,0x800001ff@ha + addi r3,r3,0x800001ff@l + + addis r6,r0,0x01000002@ha + addi r6,r6,0x01000002@l + addis r5,r0,0x810000ff@ha + addi r5,r5,0x810000ff@l + + isync + + mtspr dbat0u,r7 + mtspr dbat0l,r4 + mtspr dbat0u,r3 + isync + + mtspr ibat0u,r7 + mtspr ibat0l,r4 + mtspr ibat0u,r3 + isync + + mtspr dbat2u,r7 + mtspr dbat2l,r6 + mtspr dbat2u,r5 + isync + + mtspr ibat2u,r7 + mtspr ibat2l,r6 + mtspr ibat2u,r5 + isync + + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + + mflr r3 + mtsrr0 r3 + rfi +} + +static asm void ConfigMEM1_48MB(void) +{ + nofralloc + + addi r7,r0, 0 + + addis r4,r0,0x00000002@ha + addi r4,r4,0x00000002@l + addis r3,r0,0x800003ff@ha + addi r3,r3,0x800003ff@l + + addis r6,r0,0x02000002@ha + addi r6,r6,0x02000002@l + addis r5,r0,0x820001ff@ha + addi r5,r5,0x820001ff@l + + isync + + mtspr dbat0u,r7 + mtspr dbat0l,r4 + mtspr dbat0u,r3 + isync + + mtspr ibat0u,r7 + mtspr ibat0l,r4 + mtspr ibat0u,r3 + isync + + mtspr dbat2u,r7 + mtspr dbat2l,r6 + mtspr dbat2u,r5 + isync + + mtspr ibat2u,r7 + mtspr ibat2l,r6 + mtspr ibat2u,r5 + isync + + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + + mflr r3 + mtsrr0 r3 + rfi +} + +static asm void ConfigMEM2_52MB(void) { + nofralloc + + addi r7, r0, 0 + + addis r4,r0,0x10000002@ha + addi r4,r4,0x10000002@l + addis r3,r0,0x900003ff@ha + addi r3,r3,0x900003ff@l + + addis r6,r0,0x1000002a@ha + addi r6,r6,0x1000002a@l + addis r5,r0,0xD00007ff@ha + addi r5,r5,0xD00007ff@l + + isync + + mtspr DBAT4U,r7 + mtspr DBAT4L,r4 + mtspr DBAT4U,r3 + isync + + mtspr IBAT4U,r7 + mtspr IBAT4L,r4 + mtspr IBAT4U,r3 + + isync + + mtspr DBAT5U,r7 + mtspr DBAT5L,r6 + mtspr DBAT5U,r5 + isync + + mtspr IBAT5U,r7 + mtspr IBAT5L,r7 + isync + + addis r4,r0,0x12000002@ha + addi r4,r4,0x12000002@l + addis r3,r0,0x920001ff@ha + addi r3,r3,0x920001ff@l + + addis r6,r0,0x13000002@ha + addi r6,r6,0x13000002@l + addis r5,r0,0x9300007f@ha + addi r5,r5,0x9300007f@l + + isync + + mtspr DBAT6U,r7 + mtspr DBAT6L,r4 + mtspr DBAT6U,r3 + isync + + mtspr IBAT6U,r7 + mtspr IBAT6L,r4 + mtspr IBAT6U,r3 + + isync + + mtspr DBAT7U,r7 + mtspr DBAT7L,r6 + mtspr DBAT7U,r5 + isync + + mtspr IBAT7U,r7 + mtspr IBAT7L,r6 + mtspr IBAT7U,r5 + + isync + + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + + mflr r3 + mtsrr0 r3 + rfi +} + +static asm void ConfigMEM2_56MB(void) { + nofralloc + + addi r7,r0, 0 + + addis r4,r0,0x10000002@ha + addi r4,r4,0x10000002@l + addis r3,r0,0x900003ff@ha + addi r3,r3,0x900003ff@l + + addis r6,r0,0x1000002a@ha + addi r6,r6,0x1000002a@l + addis r5,r0,0xD00007ff@ha + addi r5,r5,0xD00007ff@l + + isync + + mtspr DBAT4U,r7 + mtspr DBAT4L,r4 + mtspr DBAT4U,r3 + isync + + mtspr IBAT4U,r7 + mtspr IBAT4L,r4 + mtspr IBAT4U,r3 + + isync + + mtspr DBAT5U,r7 + mtspr DBAT5L,r6 + mtspr DBAT5U,r5 + isync + + mtspr IBAT5U,r7 + mtspr IBAT5L,r7 + isync + + addis r4,r0,0x12000002@ha + addi r4,r4,0x12000002@l + addis r3,r0,0x920001ff@ha + addi r3,r3,0x920001ff@l + + addis r6,r0,0x13000002@ha + addi r6,r6,0x13000002@l + addis r5,r0,0x930000ff@ha + addi r5,r5,0x930000ff@l + + isync + + mtspr DBAT6U,r7 + mtspr DBAT6L,r4 + mtspr DBAT6U,r3 + isync + + mtspr IBAT6U,r7 + mtspr IBAT6L,r4 + mtspr IBAT6U,r3 + + isync + + mtspr DBAT7U,r7 + mtspr DBAT7L,r6 + mtspr DBAT7U,r5 + isync + + mtspr IBAT7U,r7 + mtspr IBAT7L,r6 + mtspr IBAT7U,r5 + + isync + + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + + mflr r3 + mtsrr0 r3 + rfi +} + +static asm void ConfigMEM2_64MB(void) { + nofralloc + + addi r7,r0,0x0000 + + addis r4,r0,0x10000002@ha + addi r4,r4,0x10000002@l + addis r3,r0,0x900007ff@ha + addi r3,r3,0x900007ff@l + + addis r6,r0,0x1000002a@ha + addi r6,r6,0x1000002a@l + addis r5,r0,0xD00007ff@ha + addi r5,r5,0xD00007ff@l + + isync + + mtspr DBAT4U,r7 + mtspr DBAT4L,r4 + mtspr DBAT4U,r3 + isync + + mtspr IBAT4U,r7 + mtspr IBAT4L,r4 + mtspr IBAT4U,r3 + + isync + + mtspr DBAT5U,r7 + mtspr DBAT5L,r6 + mtspr DBAT5U,r5 + isync + + mtspr IBAT5U,r7 + mtspr IBAT5L,r7 + isync + + mtspr IBAT6U,r7 + mtspr IBAT6L,r7 + isync + + mtspr IBAT7U,r7 + mtspr IBAT7L,r7 + isync + + mtspr DBAT6U,r7 + mtspr DBAT6L,r7 + isync + + mtspr DBAT7U,r7 + mtspr DBAT7L,r7 + isync + + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + + mflr r3 + mtsrr0 r3 + rfi +} + +static asm void ConfigMEM2_112MB(void) { + nofralloc + + addi r7, r0, 0 + + addis r4,r0,0x10000002@ha + addi r4,r4,0x10000002@l + addis r3,r0,0x900007ff@ha + addi r3,r3,0x900007ff@l + + addis r6,r0,0x1000002a@ha + addi r6,r6,0x1000002a@l + addis r5,r0,0xD0000fff@ha + addi r5,r5,0xD0000fff@l + + isync + + mtspr DBAT4U,r7 + mtspr DBAT4L,r4 + mtspr DBAT4U,r3 + isync + + mtspr IBAT4U,r7 + mtspr IBAT4L,r4 + mtspr IBAT4U,r3 + + isync + + mtspr DBAT5U,r7 + mtspr DBAT5L,r6 + mtspr DBAT5U,r5 + isync + + mtspr IBAT5U,r7 + mtspr IBAT5L,r7 + isync + + addis r4,r0,0x14000002@ha + addi r4,r4,0x14000002@l + addis r3,r0,0x940003ff@ha + addi r3,r3,0x940003ff@l + + addis r6,r0,0x16000002@ha + addi r6,r6,0x16000002@l + addis r5,r0,0x960001ff@ha + addi r5,r5,0x960001ff@l + + isync + + mtspr DBAT6U,r7 + mtspr DBAT6L,r4 + mtspr DBAT6U,r3 + isync + + mtspr IBAT6U,r7 + mtspr IBAT6L,r4 + mtspr IBAT6U,r3 + isync + + mtspr DBAT7U,r7 + mtspr DBAT7L,r6 + mtspr DBAT7U,r5 + isync + + mtspr IBAT7U,r7 + mtspr IBAT7L,r6 + mtspr IBAT7U,r5 + + isync + + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + + mflr r3 + mtsrr0 r3 + rfi +} + +static asm void ConfigMEM2_128MB(void) { + nofralloc + + addi r7, r0, 0 + + addis r4,r0,0x10000002@ha + addi r4,r4,0x10000002@l + addis r3,r0,0x90000fff@ha + addi r3,r3,0x90000fff@l + + addis r6,r0,0x1000002a@ha + addi r6,r6,0x1000002a@l + addis r5,r0,0xD0000fff@ha + addi r5,r5,0xD0000fff@l + + isync + + mtspr DBAT4U,r7 + mtspr DBAT4L,r4 + mtspr DBAT4U,r3 + isync + + mtspr IBAT4U,r7 + mtspr IBAT4L,r4 + mtspr IBAT4U,r3 + + isync + + mtspr DBAT5U,r7 + mtspr DBAT5L,r6 + mtspr DBAT5U,r5 + isync + + mtspr IBAT5U,r7 + mtspr IBAT5L,r7 + isync + + mtspr IBAT6U,r7 + mtspr IBAT6L,r7 + isync + + mtspr IBAT7U,r7 + mtspr IBAT7L,r7 + isync + + mtspr DBAT6U,r7 + mtspr DBAT6L,r7 + isync + + mtspr DBAT7U,r7 + mtspr DBAT7L,r7 + isync + + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + + mflr r3 + mtsrr0 r3 + rfi +} + +static asm void ConfigMEM_ES1_0(void) { + nofralloc + + addi r7, r0, 0 + + addis r4,r0,0x00000002@ha + addi r4,r4,0x00000002@l + addis r3,r0,0x80000fff@ha + addi r3,r3,0x80000fff@l + + isync + + mtspr dbat0u,r7 + mtspr dbat0l,r4 + mtspr dbat0u,r3 + isync + + mtspr ibat0u,r7 + mtspr ibat0l,r4 + mtspr ibat0u,r3 + isync + + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + + mflr r3 + mtsrr0 r3 + rfi +} + +static asm void RealMode(register u32 addr) { + nofralloc + + clrlwi r3, r3, 2 + mtsrr0 addr + mfmsr r3 + rlwinm r3, r3, 0, 28, 25 + mtsrr1 r3 + rfi +} + +static void BATConfig(void) { + u32 size1, size2, prot; + + if (*(u32*)OSPhysicalToCached(0x3138) == 0) { + if (OSGetPhysicalMem1Size == 0) { + RealMode((u32)ConfigMEM_ES1_0); + return; + } + } + + size1 = OSGetConsoleSimulatedMem1Size(); + + if (size1 < OSGetPhysicalMem1Size() && size1 == 25165824) { + DCInvalidateRange((void*)0x81800000, 25165824); + __MEMRegs[0x14] = 2; + } + + if (size1 <= 25165824) { + RealMode((u32)ConfigMEM1_24MB); + } + else if (size1 <= 50331648) { + RealMode((u32)ConfigMEM1_48MB); + } + + size2 = OSGetConsoleSimulatedMem2Size(); + prot = *(u32*)OSPhysicalToCached(0x3120); + + if (size2 <= 67108864) { + if (prot <= 0x93400000) { + RealMode((u32)ConfigMEM2_52MB); + } + else if (prot <= 0x93800000) { + RealMode((u32)ConfigMEM2_56MB); + } + else { + RealMode((u32)ConfigMEM2_64MB); + } + } + else if (size2 <= 134217728) { + if (prot <= 0x97000000) { + RealMode((u32)ConfigMEM2_112MB); + } + else { + RealMode((u32)ConfigMEM2_128MB); + } + } +} + +void __OSInitMemoryProtection(void) { + static BOOL initialized = FALSE; + BOOL enabled; + + enabled = OSDisableInterrupts(); + __MEMRegs[0x10] = 0; + __MEMRegs[0x8] = 0xFF; + __OSMaskInterrupts(0xF0000000); + __OSSetInterruptHandler(0, MEMIntrruptHandler); + __OSSetInterruptHandler(1, MEMIntrruptHandler); + __OSSetInterruptHandler(2, MEMIntrruptHandler); + __OSSetInterruptHandler(3, MEMIntrruptHandler); + __OSSetInterruptHandler(4, MEMIntrruptHandler); + OSRegisterShutdownFunction(&ShutdownFunctionInfo); + BATConfig(); + __OSUnmaskInterrupts(0x8000000); + OSRestoreInterrupts(enabled); +} diff --git a/src/RVL_SDK/os/OSMessage.c b/src/RVL_SDK/os/OSMessage.c new file mode 100644 index 000000000..634c8134e --- /dev/null +++ b/src/RVL_SDK/os/OSMessage.c @@ -0,0 +1,81 @@ +#include "revolution/os.h" + +void OSInitMessageQueue(OSMessageQueue *mq, OSMessage* msgArray, s32 msgCount) { + OSInitThreadQueue(&mq->queueSend); + OSInitThreadQueue(&mq->queueReceive); + mq->msgArray = msgArray; + mq->msgCount = msgCount; + mq->firstIndex = 0; + mq->usedCount = 0; +} + +BOOL OSSendMessage(OSMessageQueue* mq, OSMessage msg, s32 flags) { + BOOL enabled; + s32 lastIndex; + + enabled = OSDisableInterrupts(); + + while (mq->msgCount <= mq->usedCount) { + if (!(flags & OS_MESSAGE_BLOCK)) { + OSRestoreInterrupts(enabled); + return FALSE; + } + else { + OSSleepThread(&mq->queueSend); + } + } + + lastIndex = (mq->firstIndex + mq->usedCount) % mq->msgCount; + mq->msgArray[lastIndex] = msg; + mq->usedCount++; + OSWakeupThread(&mq->queueReceive); + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL OSReceiveMessage(OSMessageQueue* mq, OSMessage* msg, s32 flags) { + BOOL enabled = OSDisableInterrupts(); + + while (mq->usedCount == 0) { + if (!(flags & OS_MESSAGE_BLOCK)) { + OSRestoreInterrupts(enabled); + return FALSE; + } + else { + OSSleepThread(&mq->queueReceive); + } + } + + if (msg != NULL) { + *msg = mq->msgArray[mq->firstIndex]; + } + + mq->firstIndex = (mq->firstIndex + 1) % mq->msgCount; + mq->usedCount--; + + OSWakeupThread(&mq->queueSend); + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL OSJamMessage(OSMessageQueue* mq, OSMessage msg, s32 flags) { + BOOL enabled = OSDisableInterrupts(); + + while (mq->msgCount <= mq->usedCount) { + if (!(flags & OS_MESSAGE_BLOCK)) { + OSRestoreInterrupts(enabled); + return FALSE; + } + else { + OSSleepThread(&mq->queueSend); + } + } + + mq->firstIndex = (mq->firstIndex + mq->msgCount - 1) % mq->msgCount; + mq->msgArray[mq->firstIndex] = msg; + mq->usedCount++; + + OSWakeupThread(&mq->queueReceive); + OSRestoreInterrupts(enabled); + return TRUE; +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSMutex.c b/src/RVL_SDK/os/OSMutex.c new file mode 100644 index 000000000..bfaedca3c --- /dev/null +++ b/src/RVL_SDK/os/OSMutex.c @@ -0,0 +1,140 @@ +#include + +#define EnqueueTail(queue, mutex, link) \ +do { \ + OSMutex* __prev; \ + \ + __prev = (queue)->tail; \ + if (__prev == NULL) \ + (queue)->head = (mutex); \ + else \ + __prev->link.next = (mutex); \ + (mutex)->link.prev = __prev; \ + (mutex)->link.next = NULL; \ + (queue)->tail = (mutex); \ +} while (0) + +#define DequeueItem(queue, mutex, link) \ +do { \ + OSMutex* __next; \ + OSMutex* __prev; \ + \ + __next = (mutex)->link.next; \ + __prev = (mutex)->link.prev; \ + \ + if (__next == NULL) \ + (queue)->tail = __prev; \ + else \ + __next->link.prev = __prev; \ + \ + if (__prev == NULL) \ + (queue)->head = __next; \ + else \ + __prev->link.next = __next; \ +} while (0) + +#define DequeueHead(queue, mutex, link) \ +do { \ + OSMutex* __next; \ + \ + (mutex) = (queue)->head; \ + __next = (mutex)->link.next; \ + if (__next == NULL) \ + (queue)->tail = NULL; \ + else \ + __next->link.prev = NULL; \ + (queue)->head = __next; \ +} while (0) + +void OSInitMutex(OSMutex* mutex) { + OSInitThreadQueue(&mutex->queue); + mutex->thread = NULL; + mutex->count = 0; +} + +void OSLockMutex(OSMutex* mutex) { + BOOL enabled; + OSThread* currentThread, *ownerThread; + + enabled = OSDisableInterrupts(); + currentThread = OSGetCurrentThread(); + + for (;;) { + ownerThread = ((volatile OSMutex*)mutex)->thread; + + if (ownerThread == NULL) { + mutex->thread = currentThread; + mutex->count++; + EnqueueTail(¤tThread->queueMutex, mutex, link); + break; + } + else if (ownerThread == currentThread) { + mutex->count++; + break; + } + else { + currentThread->mutex = mutex; + __OSPromoteThread(mutex->thread, currentThread->priority); + OSSleepThread(&mutex->queue); + currentThread->mutex = NULL; + } + } + + OSRestoreInterrupts(enabled); +} + +void OSUnlockMutex(OSMutex* mutex) { + BOOL enabled; + OSThread* currentThread; + + enabled = OSDisableInterrupts(); + currentThread = OSGetCurrentThread(); + + if (mutex->thread == currentThread && --mutex->count == 0) { + DequeueItem(¤tThread->queueMutex, mutex, link); + mutex->thread = NULL; + if (currentThread->priority < currentThread->base) { + currentThread->priority = __OSGetEffectivePriority(currentThread); + } + + OSWakeupThread(&mutex->queue); + } + + OSRestoreInterrupts(enabled); +} + +void __OSUnlockAllMutex(OSThread* thread) { + OSMutex* mutex; + while (thread->queueMutex.head) { + DequeueHead(&thread->queueMutex, mutex, link); + ASSERT(mutex->thread == thread); + mutex->count = 0; + mutex->thread = NULL; + OSWakeupThread(&mutex->queue); + } +} + +BOOL OSTryLockMutex(OSMutex* mutex) { + BOOL enabled, locked; + OSThread* currentThread; + + enabled = OSDisableInterrupts(); + currentThread = OSGetCurrentThread(); + + if (mutex->thread == NULL) { + mutex->thread = currentThread; + mutex->count++; + EnqueueTail(¤tThread->queueMutex, mutex, link); + locked = TRUE; + } + else if (mutex->thread == currentThread) { + mutex->count++; + locked = TRUE; + } + else { + locked = FALSE; + } + + OSRestoreInterrupts(enabled); + return locked; +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSNet.c b/src/RVL_SDK/os/OSNet.c new file mode 100644 index 000000000..7e44485f6 --- /dev/null +++ b/src/RVL_SDK/os/OSNet.c @@ -0,0 +1,44 @@ +#include "revolution/os.h" + +extern BOOL __OSInIPL; + +typedef enum NWC24Err { + NWC24_OK = 0, +} NWC24Err; + +NWC24Err NWC24iPrepareShutdown(void); +NWC24Err NWC24iSynchronizeRtcCounter(BOOL); +s32 NWC24SuspendScheduler(void); + +void __OSInitNet(void) { + NWC24Err cur_err; + s32 res; + OSIOSRev iosRev; + + __OSGetIOSRev(&iosRev); + + if (iosRev.major <= 4 || iosRev.major == 9) { + return; + } + + cur_err = NWC24iPrepareShutdown(); + + if (cur_err != NWC24_OK) { + if (cur_err < NWC24_OK) { + OSReport("Failed to register network shutdown function. %d\n", cur_err); + } + + res = NWC24SuspendScheduler(); + if (res < NWC24_OK) { + OSReport("Failed to suspend the WiiConnect24 scheduler. %d\n", res); + } + } + + if (!__OSInIPL) { + cur_err = NWC24iSynchronizeRtcCounter(0); + + if (cur_err != NWC24_OK) { + OSReport("Failed to synchronize time with network resource managers. %d\n", cur_err); + } + } +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSPlayRecord.c b/src/RVL_SDK/os/OSPlayRecord.c new file mode 100644 index 000000000..fbc830669 --- /dev/null +++ b/src/RVL_SDK/os/OSPlayRecord.c @@ -0,0 +1,260 @@ +#include +#include + +static BOOL PlayRecordGet = FALSE; +static OSPlayRecord PlayRecord __attribute__ ((aligned(32))); +static NANDFileInfo FileInfo; +static NANDCommandBlock Block; +static s32 PlayRecordState = 9; +static OSAlarm PlayRecordAlarm; +static BOOL PlayRecordError = FALSE; +static volatile BOOL PlayRecordTerminate = FALSE; +static volatile BOOL PlayRecordTerminated = FALSE; +static BOOL PlayRecordRetry = FALSE; +static OSTime PlayRecordLastCloseTime; +static s32 PlayRecordLastError = NAND_RESULT_OK; + +static void PlayRecordCallback(s32, NANDCommandBlock *); + +void PlayRecordAlarmCallback(OSAlarm* alarm, OSContext* context) { + PlayRecordCallback(NAND_RESULT_OK, NULL); +} + +static u32 RecordCheckSum(OSPlayRecord* record) { + u32 *ptr, i, sum; + ptr = (u32*)record->titleName; + sum = 0; + + for (i = 0; i < (sizeof(PlayRecord) - 4) / 4; i++) { + sum = sum + *ptr; + ptr++; + } + + return sum; +} + +static void PlayRecordCallback(s32 result, NANDCommandBlock* block) { + s32 ret = 0; + PlayRecordLastError = result; + + if (PlayRecordTerminate) { + PlayRecordTerminated = TRUE; + return; + } + + if (!PlayRecordRetry) { + switch (PlayRecordState) { + case 0: + PlayRecordState = 1; + break; + case 1: + if (result == NAND_RESULT_MAXFD) { + PlayRecordRetry = TRUE; + OSCreateAlarm(&PlayRecordAlarm); + OSSetAlarm(&PlayRecordAlarm, (OSTime)1 * OSSecondsToTicks(1), PlayRecordAlarmCallback); + return; + } + else if (result == NAND_RESULT_OK) { + if (!PlayRecordGet) { + PlayRecordState = 2; + } + else { + PlayRecordState = 4; + } + break; + } + else { + PlayRecordError = TRUE; + PlayRecordState = 7; + return; + } + case 2: + if (result == sizeof(OSPlayRecord)) { + PlayRecordGet = TRUE; + PlayRecordLastCloseTime = PlayRecord.playTime; + PlayRecordState = 3; + } + else { + PlayRecordError = TRUE; + PlayRecordState = 6; + } + break; + case 3: + if (result == 0) { + PlayRecordState = 4; + } + else { + PlayRecordError = TRUE; + PlayRecordState = 6; + } + break; + case 4: + PlayRecordState = 5; + break; + case 5: + if (result == sizeof(OSPlayRecord)) { + if (OSGetTime() - PlayRecordLastCloseTime > (OSTime)300 * OSSecondsToTicks(1)) { + PlayRecordState = 6; + } + else { + PlayRecordState = 3; + } + } + else { + PlayRecordError = TRUE; + PlayRecordState = 6; + } + break; + case 6: + if (PlayRecordError) { + PlayRecordState = 7; + return; + } + else { + if (result == NAND_RESULT_OK) { + PlayRecordLastCloseTime = PlayRecord.playTime; + PlayRecordState = 1; + break; + } + else { + PlayRecordState = 7; + PlayRecordError = TRUE; + return; + } + } + default: + PlayRecordState = 7; + PlayRecordError = TRUE; + return; + } + } + + PlayRecordRetry = FALSE; + + switch (PlayRecordState) { + case 1: + ret = NANDOpenAsync("/title/00000001/00000002/data/play_rec.dat", &FileInfo, 3, PlayRecordCallback, &Block); + break; + case 2: + ret = NANDReadAsync(&FileInfo, &PlayRecord, sizeof(OSPlayRecord), PlayRecordCallback, &Block); + break; + case 3: + ret = NANDSeekAsync(&FileInfo, 0, 0, PlayRecordCallback, &Block); + break; + case 4: + OSCreateAlarm(&PlayRecordAlarm); + OSSetAlarm(&PlayRecordAlarm, (OSTime)60 * OSSecondsToTicks(1), PlayRecordAlarmCallback); + break; + case 5: + PlayRecord.playTime = OSGetTime(); + PlayRecord.checkSum = RecordCheckSum(&PlayRecord); + ret = NANDWriteAsync(&FileInfo, &PlayRecord, sizeof(OSPlayRecord), PlayRecordCallback, &Block); + break; + case 6: + ret = NANDCloseAsync(&FileInfo, PlayRecordCallback, &Block); + break; + } + + if (ret != NAND_RESULT_OK) { + if (ret == NAND_RESULT_BUSY) { + OSCreateAlarm(&PlayRecordAlarm); + OSSetAlarm(&PlayRecordAlarm, (OSTime)1 * OSSecondsToTicks(1), PlayRecordAlarmCallback); + PlayRecordRetry = TRUE; + } + else { + PlayRecordError = TRUE; + switch (PlayRecordState) { + case 2: + case 3: + case 5: + PlayRecordState = 6; + ret = NANDCloseAsync(&FileInfo, PlayRecordCallback, &Block); + + if (ret == NAND_RESULT_BUSY) { + PlayRecordRetry = TRUE; + OSCreateAlarm(&PlayRecordAlarm); + OSSetAlarm(&PlayRecordAlarm, 1 * OSSecondsToTicks(1), PlayRecordAlarmCallback); + } + break; + default: + PlayRecordState = 7; + } + } + } + + PlayRecordLastError = ret; +} + +void __OSStartPlayRecord(void) { + if (NANDInit() == NAND_RESULT_OK) { + PlayRecordGet = FALSE; + PlayRecordState = 0; + PlayRecordError = FALSE; + PlayRecordRetry = FALSE; + PlayRecordTerminate = FALSE; + PlayRecordTerminated = FALSE; + PlayRecordLastError = NAND_RESULT_OK; + PlayRecordCallback(NAND_RESULT_OK, NULL); + } +} + +void __OSStopPlayRecord(void) { + BOOL old; + OSTime start; + + old = OSDisableInterrupts(); + + PlayRecordTerminate = TRUE; + + if (PlayRecordState == 7 || PlayRecordState == 0 || + PlayRecordState == 9 || PlayRecordState == 8) + { + OSRestoreInterrupts(old); + } + else if (PlayRecordState == 4) { + OSCancelAlarm(&PlayRecordAlarm); + OSRestoreInterrupts(old); + PlayRecord.playTime = OSGetTime(); + PlayRecord.checkSum = RecordCheckSum(&PlayRecord); + NANDWrite(&FileInfo, &PlayRecord, sizeof(PlayRecord)); + NANDClose(&FileInfo); + } + else { + if (PlayRecordRetry) { + OSCancelAlarm(&PlayRecordAlarm); + OSRestoreInterrupts(old); + } + else { + OSRestoreInterrupts(old); + start = OSGetTime(); + while (1) { + if (PlayRecordTerminated) { + break; + } + if ((OSGetTime() - start) > OSMillisecondsToTicks(500)) { + PlayRecordState = 8; + return; + } + } + } + switch (PlayRecordState) { + case 2: + case 3: + case 5: + NANDClose(&FileInfo); + break; + case 1: + if (PlayRecordLastError == NAND_RESULT_OK && !PlayRecordRetry) { + NANDClose(&FileInfo); + } + break; + case 6: + if (PlayRecordRetry) { + NANDClose(&FileInfo); + } + break; + } + } + + PlayRecordState = 9; +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSPlayTime.c b/src/RVL_SDK/os/OSPlayTime.c new file mode 100644 index 000000000..e695404b6 --- /dev/null +++ b/src/RVL_SDK/os/OSPlayTime.c @@ -0,0 +1,383 @@ +#include +#include +#include +#include + +OSThread* __OSExpireThread; +OSAlarm __OSExpireAlarm; +OSTime __OSExpireTime; +OSPlayTimeCallbackFunc __OSExpireCallback; +BOOL __OSExpireSetExpiredFlag; + +static void __OSPlayTimeRebootCallback(OSAlarm *, OSContext *); +static void* __OSPlayTimeRebootThread(void *); + +extern void __OSHotResetForError(void); + +typedef struct { + s16 new_ai_buffer[2][48*2*3]; + s32 idx_ai_buffer; + s16* src_buffer; + u32 frames; + s16 aLeft; + s16 aRight; + AIDCallback gameAIDCallback; +} __OSExpireAIFadeStruct; + +static __OSExpireAIFadeStruct* __OSExpireAIFade = NULL; + +BOOL OSPlayTimeIsLimited() { + return __OSExpireTime != 0; +} + +void __OSPlayTimeFadeLastAIDCallback(void) { + if (__OSExpireAIFade->gameAIDCallback) { + __OSExpireAIFade->gameAIDCallback(); + } + + if (__OSExpireAIFade->frames == 0) { + __OSExpireAIFade->src_buffer = (s16*)OSPhysicalToCached(AIGetDMAStartAddr()); + } + + if (__OSExpireAIFade->frames == 1) { + DCInvalidateRange(__OSExpireAIFade->src_buffer, 4); + __OSExpireAIFade->aLeft = (s16)(*__OSExpireAIFade->src_buffer++); + __OSExpireAIFade->aRight = (s16)(*__OSExpireAIFade->src_buffer); + } + + if (__OSExpireAIFade->frames >= 1) { + s16* buffer = __OSExpireAIFade->new_ai_buffer[__OSExpireAIFade->idx_ai_buffer]; + s16* dest = buffer; + u32 bytes = AIGetDMALength(); + u32 i = bytes; + f32 delta = 0.995f; + + while (i) { + *dest++ = __OSExpireAIFade->aLeft; + *dest++ = __OSExpireAIFade->aRight; + + __OSExpireAIFade->aLeft *= delta; + __OSExpireAIFade->aRight *= delta; + + i -= 4; + } + + DCFlushRange(buffer, bytes); + AIInitDMA((u32)buffer, bytes); + __OSExpireAIFade->idx_ai_buffer++; + __OSExpireAIFade->idx_ai_buffer &= 1; + } + + __OSExpireAIFade->frames++; +} + +BOOL __OSWriteExpiredFlag(void) { + s32 rv = 0; + NANDFileInfo nInfo; + BOOL openNInfo = FALSE; + u8 titleId[32] __attribute__ ((aligned(32))); + + rv = NANDPrivateCreate("/shared2/expired", 63, 0); + + if (rv != NAND_RESULT_OK && rv != NAND_RESULT_EXISTS) { + goto out; + } + + rv = NANDPrivateOpen("/shared2/expired", &nInfo, 2); + + if (rv != NAND_RESULT_OK) { + goto out; + } + + openNInfo = TRUE; + + rv = ESP_InitLib(); + if (rv != 0) { + goto out; + } + + memset(titleId, 0, 32); + rv = ESP_GetTitleId((ESTitleId*)titleId); + + if (rv != 0) { + goto out; + } + + rv = NANDWrite(&nInfo, titleId, 32); + if (rv < 0) { + goto out; + } + else if (rv != 32) { + rv = NAND_RESULT_INVALID; + goto out; + } + else { + rv = 0; + } + +out: + if (openNInfo) { + NANDClose(&nInfo); + } + + return rv == 0 ? TRUE : FALSE; +} + +static void __OSPlayTimeRebootCallback(OSAlarm* alarm, OSContext* context) { + void* arenaHi; + u32 memSize; + OSThread* thread; + void* stack; + + for (thread = __OSActiveThreadQueue.head; thread; thread = thread->linkActive.next) { + OSSuspendThread(thread); + } + + memSize = OSRoundUp32B(sizeof(OSThread)) + 0x1000; + arenaHi = *(void**)OSPhysicalToCached(0x3128); + arenaHi = (void*)((u32)arenaHi - memSize); + + thread = (OSThread*)arenaHi; + arenaHi = (void*)((u32)arenaHi + OSRoundUp32B(sizeof(OSThread))); + stack = arenaHi; + + if (!OSCreateThread(thread, __OSPlayTimeRebootThread, NULL, (void*)((u32)stack + 0x1000), 0x1000, 0, 0)) { + __OSHotResetForError(); + } + + OSResumeThread(thread); +} + +BOOL __OSWriteExpiredFlagIfSet(void) { + if (__OSExpireSetExpiredFlag) { + return __OSWriteExpiredFlag(); + } + + return FALSE; +} + +void* __OSPlayTimeRebootThread(void* args) { + BOOL enabled; + u32 frames, fadeShift = 1; + __OSExpireAIFadeStruct aiFade __attribute__ ((aligned(32))); + + __OSExpireAIFade = &aiFade; + memset(__OSExpireAIFade, 0, sizeof(__OSExpireAIFadeStruct)); + __OSExpireAIFade->gameAIDCallback = AIRegisterDMACallback(__OSPlayTimeFadeLastAIDCallback); + + for (frames = 0; frames < 20; frames++) { + fadeShift = (frames / 5) + 1; + if (fadeShift > 7) { + fadeShift = 7; + } + + VIWaitForRetrace(); + __OSSetVIForceDimming(TRUE, fadeShift, fadeShift); + } + + AIRegisterDMACallback(NULL); + + VISetBlack(TRUE); + VIFlush(); + + enabled = OSDisableInterrupts(); + + __OSWriteExpiredFlagIfSet(); + OSRestoreInterrupts(enabled); + OSReturnToMenu(); + return NULL; +} + +void __OSPlayTimeAlarmExpired(OSAlarm* alarm, OSContext* context) { + void *arenaHi; + u32 memSize; + OSThread *thread; + void *stack; + + if (__OSExpireThread != NULL) { + for (thread = __OSActiveThreadQueue.head; thread; thread = thread->linkActive.next) { + if (thread != __OSExpireThread) { + OSSuspendThread(thread); + } + } + + OSCreateAlarm(&__OSExpireAlarm); + OSSetAlarm(&__OSExpireAlarm, OSSecondsToTicks((OSTime)0xF0), __OSPlayTimeRebootCallback); + + while (__OSExpireThread->suspend > 0) { + OSResumeThread(__OSExpireThread); + } + } + else { + for (thread = __OSActiveThreadQueue.head; thread; thread = thread->linkActive.next) { + OSSuspendThread(thread); + } + + memSize = OSRoundUp32B(sizeof(OSThread)) + 0x1000; + arenaHi = *(void**)OSPhysicalToCached(0x3128); + arenaHi = (void*)((u32)arenaHi - memSize); + + thread = (OSThread*)arenaHi; + arenaHi = (void*)((u32)arenaHi + OSRoundUp32B(sizeof(OSThread))); + stack = arenaHi; + + if (!OSCreateThread(thread, __OSPlayTimeRebootThread, NULL, (void*)((u32)stack + 0x1000), 0x1000, 0, 0)) { + __OSHotResetForError(); + } + + OSResumeThread(thread); + } +} + +static s32 __OSPlayTimeGetConsumption(ESTicketView *tk, ESLpEntry *lpEntry, u32 *nEntries) { + s32 rv = ESP_GetConsumption(tk->ticketID, NULL, nEntries); + + /* a few of these blocks have useless code, that's because of debug stripped asserts and reports */ + if (rv > 0) { + goto out; + } + else if (rv != 0) { + rv = rv; + goto out; + } + + if (*nEntries != 0) { + rv = ESP_GetConsumption(tk->ticketID, lpEntry, nEntries); + + if (rv != 0) { + rv = rv; + goto out; + } + } + +out: + return rv; +} + +s32 __OSGetPlayTime(ESTicketView *ticket, __OSPlayTimeType *type, u32 *playTime) { + s32 rv; + u32 i; + ESLpEntry lpEntry[8] __attribute__ ((aligned(32))); + u32 numCc = 0, seenOther = 0; + ESTicketView ticketAligned __attribute__ ((aligned(32))); + + if ((u32)(ticket) & 31) { + memcpy(&ticketAligned, ticket, sizeof(ESTicketView)); + ticket = &ticketAligned; + } + + rv = __OSPlayTimeGetConsumption(ticket, lpEntry, &numCc); + if (rv != 0) { + goto out; + } + + for (i = 0; i < 8; i++) { + if (ticket->limits[i].code == 1) { + *type = 1; + + if (numCc == 0) { + *playTime = ticket->limits[i].limit; + } + else { + if (lpEntry[i].limit >= ticket->limits[i].limit) { + *playTime = 0; + } + else { + *playTime = ticket->limits[i].limit - lpEntry[i].limit; + } + } + goto out; + } + else if (ticket->limits[i].code != 0) { + seenOther = i + 1; + } + } + + if (!seenOther) { + *type = 0; + *playTime = 0xFFFFFFFF; + } + else { + seenOther--; + + if (ticket->limits[seenOther].code == 4) { + *type = 4; + *playTime = ticket->limits[seenOther].limit; + + if (numCc > 0) { + *playTime -= lpEntry[seenOther].limit; + } + } + else { + *type = 9; + } + } + +out: + return rv; +} + +s32 __OSGetPlayTimeCurrent(__OSPlayTimeType* type, u32* playTime) { + s32 rv; + ESTicketView ticket __attribute__ ((aligned(32))); + + rv = ESP_DiGetTicketView(NULL, &ticket); + + if (rv == -1017) { + goto out; + } + + if (rv != 0) { + rv = rv; + goto out; + } + + rv = __OSGetPlayTime(&ticket, type, playTime); + +out: + return rv; +} + +void __OSInitPlayTime() { + s32 rv; + u32 limit; + __OSPlayTimeType type; + + __OSExpireTime = 0; + __OSExpireThread = NULL; + __OSExpireSetExpiredFlag = TRUE; + + rv = ESP_InitLib(); + + if (rv != 0) { + rv = rv; + goto out; + } + + rv = __OSGetPlayTimeCurrent(&type, &limit); + + if (rv != 0) { + if (rv != -1017) { + rv = rv; + } + + goto out; + } + + if (type == OSPLAYTIME_PERMANENT) { + goto out; + } + else if (type == OSPLAYTIME_LIMITED) { + if (limit == 0) { + OSPanic(__FILE__, 0x307, "Expired"); + } + + OSCreateAlarm(&__OSExpireAlarm); + OSSetAlarm(&__OSExpireAlarm, OSSecondsToTicks((OSTime)limit + 1), __OSPlayTimeAlarmExpired); + __OSExpireTime = __OSExpireAlarm.fire; + OSReport("PlayTime: %d seconds left\n", limit); + } + +out: + ESP_CloseLib(); +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSReboot.c b/src/RVL_SDK/os/OSReboot.c new file mode 100644 index 000000000..62eacc7b1 --- /dev/null +++ b/src/RVL_SDK/os/OSReboot.c @@ -0,0 +1,22 @@ +#include "revolution/os.h" + +extern OSExecParams __OSRebootParams; +extern u32 __OSNextPartitionType; +vu32 __OSLaunchPartitionType : 0x80003194; +static void* SaveStart = NULL; +static void* SaveEnd = NULL; + +void __OSReboot(u32 resetCode, u32 bootDol) { + char* argvToPass; + OSDisableInterrupts(); + OSSetArenaLo((void*)0x81280000); + OSSetArenaHi((void*)0x812F0000); + argvToPass = NULL; + __OSNextPartitionType = __OSLaunchPartitionType; + __OSBootDol(bootDol, resetCode | 0x80000000, &argvToPass); +} + +void OSGetSaveRegion(void **start, void **end) { + *start = SaveStart; + *end = SaveEnd; +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSReset.c b/src/RVL_SDK/os/OSReset.c new file mode 100644 index 000000000..bcc703460 --- /dev/null +++ b/src/RVL_SDK/os/OSReset.c @@ -0,0 +1,299 @@ +#include +#include +#include +#include +#include +#include +#include + +extern BOOL __OSInNandBoot; +extern BOOL __OSInReboot; + +extern OSExecParams __OSRebootParams; + +typedef struct OSShutdownFunctionQueue +{ + OSShutdownFunctionInfo* head; + OSShutdownFunctionInfo* tail; +} OSShutdownFunctionQueue; + +static OSShutdownFunctionQueue ShutdownFunctionQueue; +static u32 bootThisDol = 0; +volatile BOOL __OSIsReturnToIdle = FALSE; + +#define EnqueueTail(queue, info) \ +do { \ + OSShutdownFunctionInfo* __prev; \ + \ + __prev = (queue)->tail; \ + if (__prev == NULL) \ + (queue)->head = (info); \ + else \ + __prev->next = (info); \ + (info)->prev = __prev; \ + (info)->next = NULL; \ + (queue)->tail = (info); \ +} while (0) + +#define EnqueuePrio(queue, info) \ +do { \ + OSShutdownFunctionInfo* __prev; \ + OSShutdownFunctionInfo* __next; \ + \ + for (__next = (queue)->head; \ + __next && __next->priority <= info->priority; \ + __next = __next->next) \ + ; \ + if (__next == NULL) \ + EnqueueTail(queue, info); \ + else { \ + (info)->next = __next; \ + __prev = __next->prev; \ + __next->prev = (info); \ + (info)->prev = __prev; \ + if (__prev == NULL) \ + (queue)->head = (info); \ + else \ + __prev->next = (info); \ + } \ +} while (0) + +void OSRegisterShutdownFunction(OSShutdownFunctionInfo* info) { + EnqueuePrio(&ShutdownFunctionQueue, info); +} + +BOOL __OSCallShutdownFunctions(BOOL final, u32 event) { + OSShutdownFunctionInfo* info; + BOOL err; + u32 priority = 0; + + err = FALSE; + info = ShutdownFunctionQueue.head; + while (info) { + if (err && priority != info->priority) { + break; + } + + err |= !info->func(final, event); + priority = info->priority; + info = info->next; + } + err |= !__OSSyncSram(); + return err ? FALSE : TRUE; +} + +extern void __OSStopAudioSystem(void); +static void KillThreads(void); + +void __OSShutdownDevices(u32 event) { + BOOL rc, disableRecalibration, doRecal; + + switch(event) { + case 0: + case 5: + case 6: + doRecal = FALSE; + break; + case 2: + case 3: + case 4: + case 1: + default: + doRecal = TRUE; + break; + } + + __OSStopAudioSystem(); + + if (!doRecal) { + disableRecalibration = __PADDisableRecalibration(TRUE); + } + + while (!__OSCallShutdownFunctions(FALSE, event)); + + while (!__OSSyncSram()); + + OSDisableInterrupts(); + rc = __OSCallShutdownFunctions(TRUE, event); + ASSERT(rc); + LCDisable(); + + if (!doRecal) { + __PADDisableRecalibration(disableRecalibration); + } + + KillThreads(); +} + +void __OSHotResetForError(void) { + if (__OSInNandBoot || __OSInReboot) { + __OSInitSTM(); + } + + __OSHotReset(); + + OSPanic(__FILE__, 0x3D3, "__OSHotReset(): Falied to reset system.\n"); +} + +u32 OSGetResetCode(void) { + u32 code; + + if (__OSRebootParams.valid) { + code = (0x80000000 | __OSRebootParams.restartCode); + } + else { + code = (__PIRegs[9] & 0xFFFFFFF8) >> 3; + } + + return code; +} + +void OSResetSystem(int, u32, int) { + OSPanic(__FILE__, 1130, "OSResetSystem() is obsoleted. It doesn't work any longer.\n"); +} + +u8 __OSGetDiscState(u8 last) { + u32 flags; + + if (__DVDGetCoverStatus() != 2) { + return 3; + } + else { + if ((last == 1) && (__OSGetRTCFlags(&flags) && !flags)) { + return 1; + } + else { + return 2; + } + } +} + +void OSRebootSystem(void) { + OSStateFlags state; + + __OSStopPlayRecord(); + __OSUnRegisterStateEvent(); + __DVDPrepareReset(); + __OSReadStateFlags(&state); + state.lastDiscState = __OSGetDiscState(state.lastDiscState); + state.lastShutdown = 2; + __OSClearRTCFlags(); + __OSWriteStateFlags(&state); + OSDisableScheduler(); + __OSShutdownDevices(1); + __OSHotResetForError(); +} + +void OSShutdownSystem(void) { + SCIdleModeInfo idleModeInfo; + OSIOSRev iosRev; + OSStateFlags state; + + memset(&idleModeInfo, 0, sizeof(SCIdleModeInfo)); + + SCInit(); + while ( SCCheckStatus() == 1 ) + {} + + SCGetIdleMode(&idleModeInfo); + __OSStopPlayRecord(); + __OSUnRegisterStateEvent(); + __DVDPrepareReset(); + __OSReadStateFlags(&state); + state.lastDiscState = __OSGetDiscState(state.lastDiscState); + + if(idleModeInfo.mode == 1) { + state.lastShutdown = 5; + } + else { + state.lastShutdown = 1; + } + + __OSClearRTCFlags(); + __OSWriteStateFlags(&state); + __OSGetIOSRev(&iosRev); + + if ( idleModeInfo.mode == 1 ) { + __OSIsReturnToIdle = TRUE; + + OSDisableScheduler(); + __OSShutdownDevices(5); + OSEnableScheduler(); + __OSLaunchMenu(); + } + else { + OSDisableScheduler(); + __OSShutdownDevices(2); + __OSShutdownToSBY(); + } +} + +void OSRestart(u32 resetCode) { + u8 type = OSGetAppType(); + __OSStopPlayRecord(); + __OSUnRegisterStateEvent(); + + if (type == 0x81) { + OSDisableScheduler(); + __OSShutdownDevices(4); + OSEnableScheduler(); + __OSRelaunchTitle(resetCode); + } + else if (type == 0x80) { + OSDisableScheduler(); + __OSShutdownDevices(4); + OSEnableScheduler(); + __OSReboot(resetCode, bootThisDol); + } + + OSDisableScheduler(); + __OSShutdownDevices(1); + __OSHotResetForError(); +} + +static void KillThreads(void) { + OSThread* thread; + OSThread* next; + + for (thread = __OSActiveThreadQueue.head; + thread; + thread = next) + { + next = thread->linkActive.next; + + switch (thread->state) { + case 1: + case 4: + OSCancelThread(thread); + break; + default: + break; + } + } +} + +void __OSReturnToMenu(u8 menuMode) { + OSStateFlags state; + + __OSStopPlayRecord(); + __OSUnRegisterStateEvent(); + __DVDPrepareReset(); + __OSReadStateFlags(&state); + state.lastDiscState = __OSGetDiscState(state.lastDiscState); + state.lastShutdown = 3; + state.menuMode = menuMode; + __OSClearRTCFlags(); + __OSWriteStateFlags(&state); + OSDisableScheduler(); + __OSShutdownDevices(5); + OSEnableScheduler(); + __OSLaunchMenu(); + OSDisableScheduler(); + __VISetRGBModeImm(); + __OSHotResetForError(); +} + +void OSReturnToMenu(void) { + __OSReturnToMenu(0); + OSPanic(__FILE__, 0x348, "OSReturnToMenu(): Falied to boot system menu.\n"); +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSRtc.c b/src/RVL_SDK/os/OSRtc.c new file mode 100644 index 000000000..4fea0413d --- /dev/null +++ b/src/RVL_SDK/os/OSRtc.c @@ -0,0 +1,276 @@ +#include +#include + +typedef struct SramControl { + u8 sram[64]; + u32 offset; + BOOL enabled; + BOOL locked; + BOOL sync; + void (*callback)(void); +} SramControl; + +static SramControl Scb __attribute__ ((aligned (32))); + +static BOOL ReadSram(void* buffer) { + BOOL err; + u32 cmd; + + DCInvalidateRange(buffer, 64); + + if (!EXILock(0, 1, 0)) { + return FALSE; + } + + if (!EXISelect(0, 1, 3)) { + EXIUnlock(0); + return FALSE; + } + + cmd = 0x20000000 | 0x100; + err = FALSE; + err |= !EXIImm(0, &cmd, 4, 1, NULL); + err |= !EXISync(0); + err |= !EXIDma(0, buffer, 64, 0, NULL); + err |= !EXISync(0); + err |= !EXIDeselect(0); + EXIUnlock(0); + return !err; +} + +static BOOL WriteSram(void *, u32, u32); + +static void WriteSramCallback(s32 chan, OSContext* context) { + Scb.sync = WriteSram(Scb.sram + Scb.offset, Scb.offset, 64 - Scb.offset); + + if (Scb.sync) { + Scb.offset = 64; + } +} + +void __OSInitSram(void) { + Scb.locked = Scb.enabled = FALSE; + Scb.sync = ReadSram(Scb.sram); + Scb.offset = 64; + + OSSetGbsMode(OSGetGbsMode()); +} + +static BOOL WriteSram(void *buffer, u32 offset, u32 size) { + BOOL err; + u32 cmd; + + if (!EXILock(0, 1, WriteSramCallback)) { + return FALSE; + } + + if (!EXISelect(0, 1, 3)) { + EXIUnlock(0); + return FALSE; + } + + offset <<= 6; + cmd = 0xA0000000 | 0x000000100 + offset; + err = FALSE; + err |= !EXIImm(0, &cmd, 4, 1, NULL); + err |= !EXISync(0); + err |= !EXIImmEx(0, buffer, size, 1); + err |= !EXIDeselect(0); + EXIUnlock(0); + return !err; +} + +static void* LockSram(u32 offset) { + BOOL enabled; + enabled = OSDisableInterrupts(); + + if (Scb.locked) { + OSRestoreInterrupts(enabled); + return NULL; + } + + Scb.enabled = enabled; + Scb.locked = TRUE; + return Scb.sram + offset; +} + +static OSSramEx* __OSLockSramEx(void) { + return LockSram(sizeof(OSSram)); +} + +BOOL UnlockSram(BOOL commit, u32 offset) { + u16* p; + + if (commit) { + if (offset == 0) { + OSSram* sram = (OSSram*)Scb.sram; + + if ( 2u < (sram->flags & 3)) { + sram->flags &= ~3; + } + + sram->checkSum = sram->checkSumInv = 0; + + for (p = (u16*)&sram->counterBias; p < (u16*)(Scb.sram + sizeof(OSSram)); p++) { + sram->checkSum += *p; + sram->checkSumInv += ~*p; + } + } + + if (offset < Scb.offset) { + Scb.offset = offset; + } + + if (Scb.offset <= sizeof(OSSram)) { + OSSramEx* sram = (OSSramEx*)(Scb.sram + sizeof(OSSram)); + + if ((sram->gbs & 0x7C00) == 0x5000u || (sram->gbs & 0xC0) == 0xC0u) { + sram->gbs = 0; + } + } + + Scb.sync = WriteSram(Scb.sram + Scb.offset, Scb.offset, 64 - Scb.offset); + + if (Scb.sync) { + Scb.offset = 64; + } + } + + Scb.locked = FALSE; + OSRestoreInterrupts(Scb.enabled); + return Scb.sync; +} + +static BOOL __OSUnlockSramEx(BOOL commit) { + return UnlockSram(commit, sizeof(OSSram)); +} + +BOOL __OSSyncSram(void) { + return Scb.sync; +} + +BOOL __OSReadROM(void* buffer, s32 length, s32 offset) { + BOOL err; + u32 cmd; + + DCInvalidateRange(buffer, (u32)length); + + if (!EXILock(0, 1, 0)) { + return FALSE; + } + + if (!EXISelect(0, 1, 3)) { + EXIUnlock(0); + return FALSE; + } + + cmd = (u32)(offset << 6); + err = FALSE; + err |= !EXIImm(0, &cmd, 4, 1, NULL); + err |= !EXISync(0); + err |= !EXIDma(0, buffer, length, 0, NULL); + err |= !EXISync(0); + err |= !EXIDeselect(0); + EXIUnlock(0); + return !err; +} + +u16 OSGetWirelessID(s32 chan) { + OSSramEx* sram; + u16 id; + sram = __OSLockSramEx(); + id = sram->wirelessPadID[chan]; + __OSUnlockSramEx(FALSE); + return id; +} + +void OSSetWirelessID(s32 chan, u16 id) { + OSSramEx* sram; + sram = __OSLockSramEx(); + + if (sram->wirelessPadID[chan] != id) { + sram->wirelessPadID[chan] = id; + __OSUnlockSramEx(TRUE); + } + else { + __OSUnlockSramEx(FALSE); + } +} + +static u16 OSGetGbsMode(void) { + OSSramEx* sram; + u16 mode; + sram = __OSLockSramEx(); + mode = sram->gbs; + __OSUnlockSramEx(FALSE); + return mode; +} + +static void OSSetGbsMode(u16 mode) { + OSSramEx* sram; + + if ((mode & 0x7C00u) == 0x5000 || (mode & 0xC0u) == 0xC0) { + mode = 0; + } + + sram = __OSLockSramEx(); + + if (mode == sram->gbs) { + __OSUnlockSramEx(FALSE); + return; + } + + sram->gbs = mode; + __OSUnlockSramEx(TRUE); +} + +BOOL __OSGetRTCFlags(u32* flags) { + BOOL err; + u32 cmd; + + if (!EXILock(0, 1, 0)) { + return FALSE; + } + + if (!EXISelect(0, 1, 3)) { + EXIUnlock(0); + return FALSE; + } + + cmd = 0x21000800; + err = FALSE; + err |= !EXIImm(0, &cmd, 4, 1, NULL); + err |= !EXISync(0); + err |= !EXIImm(0, &cmd, 4, 0, NULL); + err |= !EXISync(0); + err |= !EXIDeselect(0); + EXIUnlock(0); + *flags = cmd; + return !err; +} + +BOOL __OSClearRTCFlags(void) { + BOOL err; + u32 cmd; + u32 data = 0; + + if (!EXILock(0, 1, 0)) { + return FALSE; + } + + if (!EXISelect(0, 1, 3)) { + EXIUnlock(0); + return FALSE; + } + + cmd = 0xA1000800; + err = FALSE; + err |= !EXIImm(0, &cmd, 4, 1, NULL); + err |= !EXISync(0); + err |= !EXIImm(0, &data, 4, 1, NULL); + err |= !EXISync(0); + err |= !EXIDeselect(0); + EXIUnlock(0); + + return !err; +} diff --git a/src/RVL_SDK/os/OSStateFlags.c b/src/RVL_SDK/os/OSStateFlags.c new file mode 100644 index 000000000..f77e261c8 --- /dev/null +++ b/src/RVL_SDK/os/OSStateFlags.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +static OSStateFlags StateFlags __attribute__ ((aligned(32))); + +static u32 CheckSum(OSStateFlags* flags) { + u32 *ptr, i, sum; + + ptr = (u32*)&flags->lastBootApp; + sum = 0; + + for (i = 0; i < (sizeof(OSStateFlags) - 4) / 4; i++) { + sum = sum + *ptr; + ptr++; + } + + return sum; +} + +BOOL __OSWriteStateFlags(OSStateFlags* flags) { + NANDFileInfo fileInfo; + s32 result; + + memcpy(&StateFlags, flags, sizeof(StateFlags)); + StateFlags.checkSum = CheckSum(&StateFlags); + + result = NANDOpen("/title/00000001/00000002/data/state.dat", &fileInfo, 2); + + if (result == 0) { + result = NANDWrite(&fileInfo, &StateFlags, sizeof(StateFlags)); + + if (result != sizeof(StateFlags)) { + NANDClose(&fileInfo); + return FALSE; + } + + result = NANDClose(&fileInfo); + + if (result != 0) { + return FALSE; + } + } + else { + return FALSE; + } + + return TRUE; +} + +BOOL __OSReadStateFlags(OSStateFlags* flags) { + NANDFileInfo fileInfo; + s32 result; + + result = NANDOpen("/title/00000001/00000002/data/state.dat", &fileInfo, 1); + + if (result == 0) { + result = NANDRead(&fileInfo, &StateFlags, sizeof(OSStateFlags)); + NANDClose(&fileInfo); + + if (result != sizeof(OSStateFlags)) { + NANDDelete("/title/00000001/00000002/data/state.dat"); + memset(flags, 0, sizeof(StateFlags)); + return FALSE; + } + } + else { + memset(flags, 0, sizeof(OSStateFlags)); + return FALSE; + } + + if (CheckSum(&StateFlags) != StateFlags.checkSum) { + memset(flags, 0, sizeof(OSStateFlags)); + return FALSE; + } + + memcpy(flags, &StateFlags, sizeof(OSStateFlags)); + return TRUE; +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSStateTM.c b/src/RVL_SDK/os/OSStateTM.c new file mode 100644 index 000000000..438be7674 --- /dev/null +++ b/src/RVL_SDK/os/OSStateTM.c @@ -0,0 +1,263 @@ +#include +#include +#include +#include +#include +#include + +static u32 StmImInBuf[8] __attribute__((align(32))); +static u32 StmImOutBuf[8] __attribute__((align(32))); + +static u32 StmVdInBuf[8] __attribute__((align(32))); +static u32 StmVdOutBuf[8] __attribute__((align(32))); + +static u32 StmEhInBuf[8]__attribute__((align(32))); +static u32 StmEhOutBuf[8] __attribute__((align(32))); + +static int StmReady = 0; +static int StmImDesc = 0; +static int StmEhDesc = 0; +static int StmEhRegistered = 0; + +static int StmVdInUse = 0; + +static BOOL ResetDown; + +static OSResetCallback ResetCallback; +static OSPowerCallback PowerCallback; + +static BOOL __OSGetResetButtonStateRaw(void); +static s32 __OSStateEventHandler(s32, void *); +static s32 __OSVIDimReplyHandler(s32, void *); +static void __OSDefaultResetCallback(void); +static void __OSDefaultPowerCallback(void); +static void __OSRegisterStateEvent(void); + +#ifdef NON_MATCHING +OSPowerCallback OSSetPowerCallback(OSPowerCallback callback) { + BOOL enabled; + OSPowerCallback prevCallback; + + enabled = OSDisableInterrupts(); + prevCallback = PowerCallback; + + if (callback) { + PowerCallback = callback; + } + else { + PowerCallback = __OSDefaultPowerCallback; + } + + if (!StmEhRegistered) { + __OSRegisterStateEvent(); + } + + OSRestoreInterrupts(enabled); + + if (prevCallback == __OSDefaultResetCallback) { + return NULL; + } + else { + return prevCallback; + } +} +#endif + +// from a debug build of the OS lib, this function is inlined in __OSSetVIForceDimming +static int AccessVIDimRegs(void) { + int res; + res = IOS_IoctlAsync(StmImDesc, 0x5001, StmVdInBuf, 0x20, StmVdOutBuf, 0x20, __OSVIDimReplyHandler, 0); + switch(res) { + default: + return res; + case 0: + return 1; + } +} + +int __OSSetVIForceDimming(BOOL isEnabled, u32 yShift, u32 xShift) { + BOOL en; + + if (!StmReady) { + return -10; + } + + en = OSDisableInterrupts(); + + if (StmVdInUse) { + OSRestoreInterrupts(en); + return 0; + } + + StmVdInUse = 1; + OSRestoreInterrupts(en); + + StmVdInBuf[0] = yShift << 3 | xShift | isEnabled << 7; + StmVdInBuf[1] = 0; + StmVdInBuf[2] = 0; + StmVdInBuf[3] = 0; + StmVdInBuf[4] = 0; + StmVdInBuf[5] = 0xFFFFFFFF; + StmVdInBuf[6] = 0xFFFF0000; + StmVdInBuf[7] = 0; + + return AccessVIDimRegs(); +} + +// this function is inlined but isn't in some games, so thanks +BOOL __OSGetResetButtonStateRaw(void) { + return (!(__PIRegs[0] & 0x10000)) ? TRUE : FALSE; +} + +s32 __OSSetIdleLEDMode(u32 led_mode) { + s32 ret; + + if (StmReady == 0) { + return -6; + } + + StmImInBuf[0] = led_mode; + ret = IOS_Ioctl(StmImDesc, 0x6002, StmImInBuf, 0x20, StmImOutBuf, 0x20); + return ret; +} + +s32 __OSUnRegisterStateEvent(void) { + s32 ret; + + if (StmEhRegistered == 0) { + return 0; + } + + if (StmReady == 0) { + return -6; + } + + ret = IOS_Ioctl(StmImDesc, 0x3002, StmImInBuf, 0x20, StmImOutBuf, 0x20); + + if (ret == 0) { + StmEhRegistered = 0; + } + + return ret; +} + +s32 __OSVIDimReplyHandler(s32 ret, void *pUnused) { + StmVdInUse = 0; + return 0; +} + +static void __OSRegisterStateEvent(void) { + int err, enabled; + enabled = OSDisableInterrupts(); + + err = IOS_IoctlAsync(StmEhDesc, 0x1000, StmEhInBuf, 0x20, StmEhOutBuf, 0x20, __OSStateEventHandler, (void*)0); + + if (err == IOS_ERROR_OK) { + StmEhRegistered = 1; + } + else { + StmEhRegistered = 0; + } + + OSRestoreInterrupts(enabled); +} + +void __OSDefaultResetCallback(void) { + +} + +void __OSDefaultPowerCallback(void) { + +} + +// arg seems to be unused and it's only there so we can register our states +//#ifdef NON_MATCHING +static s32 __OSStateEventHandler(s32 ret, void *pUnused) { + int en; + OSResetCallback cb; + + if (ret != 0) { + OSPanic(__FILE__, 0x314, "Error on STM state event handler\n"); + } + + StmEhRegistered = 0; + + if (StmEhOutBuf[0] == 0x20000) { + // this won't inline properly. sigh + if (__OSGetResetButtonStateRaw()) { + en = OSDisableInterrupts(); + ResetDown = TRUE; + cb = ResetCallback; + ResetCallback = __OSDefaultResetCallback; + cb(); + OSRestoreInterrupts(en); + VIResetDimmingCount(); + } + + __OSRegisterStateEvent(); + } + + if (StmEhOutBuf[0] == 0x800) { + en = OSDisableInterrupts(); + cb = PowerCallback; + PowerCallback = __OSDefaultPowerCallback; + cb(); + OSRestoreInterrupts(en); + } + + return 0; +} +//#endif + +int __OSInitSTM(void) { + PowerCallback = __OSDefaultPowerCallback; + ResetCallback = __OSDefaultResetCallback; + ResetDown = 0; + + if (StmReady) { + return 1; + } + + StmVdInUse = 0; + StmImDesc = IOS_Open("/dev/stm/immediate", 0); + + if (StmImDesc < 0) { + StmReady = 0; + return 0; + } + + StmEhDesc = IOS_Open("/dev/stm/eventhook", 0); + + if (StmEhDesc < 0) { + StmReady = 0; + return 0; + } + + __OSRegisterStateEvent(); + StmReady = 1; + return 1; +} + +static void LockUp(void); + +void __OSHotReset(void) { + int result; + __VIRegs[1] = 0; + + if (!StmReady) { + OSPanic(__FILE__, 380, "Error: The firmware doesn't support reboot feature.\n"); + } + + result = IOS_Ioctl(StmImDesc, 0x2001, StmImInBuf, sizeof(StmImInBuf), StmImOutBuf, sizeof(StmImOutBuf)); + LockUp(); +} + +static void LockUp(void) { + BOOL en = OSDisableInterrupts(); + + ICFlashInvalidate(); + + while (1) { + + } +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSSync.c b/src/RVL_SDK/os/OSSync.c new file mode 100644 index 000000000..6ac0a8dd1 --- /dev/null +++ b/src/RVL_SDK/os/OSSync.c @@ -0,0 +1,31 @@ +#include +#include + +static void __OSSystemCallVectorStart(void); +static void __OSSystemCallVectorEnd(void); +void __OSInitSystemCall(void); + +static asm void SystemCallVector(void) { + nofralloc + +entry __OSSystemCallVectorStart + mfspr r9, hid0 + ori r10, r9, 8 + mtspr hid0, r10 + isync + sync + mtspr hid0, r9 + rfi + +entry __OSSystemCallVectorEnd + nop +} + +void __OSInitSystemCall(void) { + void* addr; + addr = (void*)OSPhysicalToCached(0xC00); + memcpy(addr, __OSSystemCallVectorStart, (u32) __OSSystemCallVectorEnd - (u32) __OSSystemCallVectorStart); + DCFlushRangeNoSync(addr, 0x100); + __sync(); + ICInvalidateRange(addr, 0x100); +} diff --git a/src/RVL_SDK/os/OSThread.c b/src/RVL_SDK/os/OSThread.c new file mode 100644 index 000000000..bfeb6b1c0 --- /dev/null +++ b/src/RVL_SDK/os/OSThread.c @@ -0,0 +1,698 @@ +#include + +extern OSErrorHandler __OSErrorTable[]; + +static void DefaultSwitchThreadCallback(OSThread *, OSThread *); + +#define OFFSET(n, a) (((u32) (n)) & ((a) - 1)) +#define TRUNC(n, a) (((u32) (n)) & ~((a) - 1)) +#define ROUND(n, a) (((u32) (n) + (a) - 1) & ~((a) - 1)) + +static volatile u32 RunQueueBits; +static OSThreadQueue RunQueue[32]; +static volatile BOOL RunQueueHint; + +static volatile s32 Reschedule; +static OSThread IdleThread; +static OSThread DefaultThread; +static OSContext IdleContext; + +static OSSwitchThreadCallback SwitchThreadCallback = DefaultSwitchThreadCallback; + +void UnsetRun(OSThread *) __attribute__((noinline)); + +#define EnqueueTail(queue, thread, link) \ +do { \ + OSThread* __prev; \ + \ + __prev = (queue)->tail; \ + if (__prev == NULL) \ + (queue)->head = (thread); \ + else \ + __prev->link.next = (thread); \ + (thread)->link.prev = __prev; \ + (thread)->link.next = NULL; \ + (queue)->tail = (thread); \ +} while (0) + +#define EnqueuePrio(queue, thread, link) \ +do { \ + OSThread* __prev; \ + OSThread* __next; \ + \ + for (__next = (queue)->head; \ + __next && __next->priority <= thread->priority; \ + __next = __next->link.next) \ + ; \ + if (__next == NULL) \ + EnqueueTail(queue, thread, link); \ + else { \ + (thread)->link.next = __next; \ + __prev = __next->link.prev; \ + __next->link.prev = (thread); \ + (thread)->link.prev = __prev; \ + if (__prev == NULL) \ + (queue)->head = (thread); \ + else \ + __prev->link.next = (thread); \ + } \ +} while (0) + +#define DequeueItem(queue, thread, link) \ +do { \ + OSThread* __next; \ + OSThread* __prev; \ + \ + __next = (thread)->link.next; \ + __prev = (thread)->link.prev; \ + \ + if (__next == NULL) \ + (queue)->tail = __prev; \ + else \ + __next->link.prev = __prev; \ + \ + if (__prev == NULL) \ + (queue)->head = __next; \ + else \ + __prev->link.next = __next; \ +} while (0) + +#define DequeueHead(queue, thread, link) \ +do { \ + OSThread* __next; \ + \ + (thread) = (queue)->head; \ + __next = (thread)->link.next; \ + if (__next == NULL) \ + (queue)->tail = NULL; \ + else \ + __next->link.prev = NULL; \ + (queue)->head = __next; \ +} while (0) + +#define IsSuspended(suspendCount) (0 < (suspendCount)) + +static inline void OSInitMutexQueue(OSMutexQueue* queue) { + queue->head = queue->tail = NULL; +} + +void DefaultSwitchThreadCallback(OSThread *, OSThread *) { + return; +} + +static inline void OSSetCurrentThread(OSThread* thread) { + SwitchThreadCallback(__OSCurrentThread, thread); + __OSCurrentThread = thread; +} + +extern u8 _stack_addr[]; +extern u8 _stack_end[]; + +void __OSThreadInit(void) { + OSThread* thread = &DefaultThread; + int prio; + + thread->state = 2; + thread->attr = 1; + thread->priority = thread->base = 16; + thread->suspend = 0; + thread->value = (void*)-1; + thread->mutex = NULL; + OSInitThreadQueue(&thread->queueJoin); + OSInitMutexQueue(&thread->queueMutex); + __OSFPUContext = &thread->context; + OSClearContext(&thread->context); + OSSetCurrentContext(&thread->context); + + thread->stackBase = (void*)_stack_addr; + thread->stackEnd = (void*)_stack_end; + *(thread->stackEnd) = 0xDEADBABE; + + OSSetCurrentThread(thread); + OSClearStack(0); + + RunQueueBits = 0; + RunQueueHint = FALSE; + + for (prio = 0; prio <= 31; prio++) { + OSInitThreadQueue(&RunQueue[prio]); + } + + OSInitThreadQueue(&__OSActiveThreadQueue); + EnqueueTail(&__OSActiveThreadQueue, thread, linkActive); + OSClearContext(&IdleContext); + Reschedule = 0; +} + +void OSInitThreadQueue(OSThreadQueue *queue) { + queue->head = queue->tail = 0; +} + +OSThread* OSGetCurrentThread(void) { + return __OSCurrentThread; +} + +static void __OSSwitchThread(OSThread *nextThread) { + OSSetCurrentThread(nextThread); + OSSetCurrentContext(&nextThread->context); + OSLoadContext(&nextThread->context); +} + +BOOL OSIsThreadSuspended(OSThread *thread) { + return (0 < thread->suspend) ? TRUE : FALSE; +} + +BOOL OSIsThreadTerminated(OSThread *thread) { + return ((thread->state == 8) || (thread->state == 0)) ? TRUE : FALSE; +} + +static BOOL __OSIsThreadActive(OSThread* thread) { + OSThread* active; + + if (thread->state == 0) { + return FALSE; + } + + for (active = __OSActiveThreadQueue.head; active; active = active->linkActive.next) { + if (thread == active) { + return TRUE; + } + } + + return FALSE; +} + +s32 OSDisableScheduler(void) { + BOOL enabled; + s32 count; + + enabled = OSDisableInterrupts(); + count = Reschedule++; + OSRestoreInterrupts(enabled); + return count; +} + +s32 OSEnableScheduler(void) { + BOOL enabled; + s32 count; + + enabled = OSDisableInterrupts(); + count = Reschedule--; + OSRestoreInterrupts(enabled); + return count; +} + +static void SetRun(OSThread *thread) { + thread->queue = &RunQueue[thread->priority]; + EnqueueTail(thread->queue, thread, link); + RunQueueBits |= 1 << (31 - thread->priority); + RunQueueHint = TRUE; +} + +void UnsetRun(OSThread *thread) { + OSThreadQueue* queue; + queue = thread->queue; + DequeueItem(queue, thread, link); + + if (queue->head == 0) { + RunQueueBits &= ~(1 << (31 - thread->priority)); + } + + thread->queue = 0; +} + +OSPriority __OSGetEffectivePriority(OSThread *thread) { + OSPriority priority; + OSMutex* mutex; + OSThread* blocked; + + priority = thread->base; + + for (mutex = thread->queueMutex.head; mutex; mutex = mutex->link.next) { + blocked = mutex->queue.head; + + if (blocked != 0 && blocked->priority < priority) { + priority = blocked->priority; + } + } + + return priority; +} + +OSThread* SetEffectivePriority(OSThread *thread, OSPriority priority) { + switch (thread->state) { + case 1: + UnsetRun(thread); + thread->priority = priority; + SetRun(thread); + break; + case 4: + DequeueItem(thread->queue, thread, link); + thread->priority = priority; + EnqueuePrio(thread->queue, thread, link); + + if (thread->mutex != 0) { + return thread->mutex->thread; + } + break; + case 2: + RunQueueHint = TRUE; + thread->priority = priority; + break; + } + + return NULL; +} + +static void UpdatePriority(OSThread* thread) { + OSPriority priority; + + do { + if (IsSuspended(thread->suspend)) { + break; + } + priority = __OSGetEffectivePriority(thread); + + if (thread->priority == priority) { + break; + } + thread = SetEffectivePriority(thread, priority); + } while (thread); +} + +void __OSPromoteThread(OSThread *thread, OSPriority priority) { + do { + if ((thread->suspend < 0) || thread->priority <= priority) { + break; + } + + thread = SetEffectivePriority(thread, priority); + } while (thread); +} + +OSThread* SelectThread(BOOL yield) { + OSContext* currentContext; + OSThread* currentThread; + OSThread* nextThread; + OSPriority priority; + OSThreadQueue* queue; + + if (Reschedule < 0) { + return 0; + } + + currentContext = OSGetCurrentContext(); + currentThread = OSGetCurrentThread(); + + if (currentContext != ¤tThread->context) { + return 0; + } + + if (currentThread != 0) { + if (currentThread->state == 2) { + if (!yield) { + priority = __cntlzw(RunQueueBits); + + if (currentThread->priority <= priority) { + return 0; + } + } + + currentThread->state = 1; + SetRun(currentThread); + } + + if (!(currentThread->context.state & 2) && OSSaveContext(¤tThread->context)) { + return 0; + } + } + + if (RunQueueBits == 0) { + OSSetCurrentThread(0); + OSSetCurrentContext(&IdleContext); + + do { + OSEnableInterrupts(); + while (RunQueueBits == 0); + OSDisableInterrupts(); + } while (RunQueueBits == 0); + + OSClearContext(&IdleContext); + } + + RunQueueHint = FALSE; + priority = __cntlzw(RunQueueBits); + queue = &RunQueue[priority]; + DequeueHead(queue, nextThread, link); + + if (queue->head == 0) { + RunQueueBits &= ~(1 << (31 - priority)); + } + + nextThread->queue = 0; + nextThread->state = 2; + __OSSwitchThread(nextThread); + return nextThread; +} + +void __OSReschedule(void) { + if (RunQueueHint) { + SelectThread(FALSE); + } +} + +void OSYieldThread(void) { + BOOL enabled; + enabled = OSDisableInterrupts(); + SelectThread(TRUE); + OSRestoreInterrupts(enabled); +} + +BOOL OSCreateThread(OSThread* thread, void* (*func)(void *), void* param, void* stack, u32 stackSize, OSPriority priority, u16 attr) { + BOOL enabled; + u32 sp; + int i; + + if (priority < 0 || 31 < priority) { + return FALSE; + } + + thread->state = 1; + thread->attr = (u16)(attr & 1); + thread->priority = thread->base = priority; + thread->suspend = 1; + thread->value = (void*)-1; + thread->mutex = NULL; + OSInitThreadQueue(&thread->queueJoin); + OSInitMutexQueue(&thread->queueMutex); + + sp = (u32)stack; + sp = TRUNC(sp, 8); + sp -= 8; + + ((u32*)sp)[0] = 0; + ((u32*)sp)[1] = 0; + + OSInitContext(&thread->context, (u32)func, sp); + thread->context.lr = (u32)OSExitThread; + thread->context.gpr[3] = (u32)param; + thread->stackBase = stack; + thread->stackEnd = (u32*)((u32)stack - stackSize); + *(thread->stackEnd) = 0xDEADBABE; + thread->error = 0; + for (i = 0; i < 2; ++i) { + thread->specific[i] = 0; + } + + enabled = OSDisableInterrupts(); + if (__OSErrorTable[16] != NULL) { + thread->context.srr1 |= 0x900; + thread->context.state |= 1; + thread->context.fpscr = (__OSFpscrEnableBits & 248) | 4; + + for (i = 0; i < 32; ++i) { + *(u64*) &thread->context.fpr[i] = (u64)0xffffffffffffffffLL; + *(u64*) &thread->context.psf[i] = (u64) 0xffffffffffffffffLL; + } + } + + EnqueueTail(&__OSActiveThreadQueue, thread, linkActive); + OSRestoreInterrupts(enabled); + return TRUE; +} + +void OSExitThread(void* val) { + BOOL enabled; + OSThread* currentThread; + + enabled = OSDisableInterrupts(); + currentThread = OSGetCurrentThread(); + OSClearContext(¤tThread->context); + + if (currentThread->attr & 1) { + DequeueItem(&__OSActiveThreadQueue, currentThread, linkActive); + currentThread->state = 0; + } + else { + currentThread->state = 8; + currentThread->value = val; + } + + __OSUnlockAllMutex(currentThread); + OSWakeupThread(¤tThread->queueJoin); + RunQueueHint = TRUE; + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +void OSCancelThread(OSThread* thread) { + BOOL enabled = OSDisableInterrupts(); + + switch (thread->state) { + case OS_THREAD_STATE_READY: + if (!IsSuspended(thread->suspend)) { + UnsetRun(thread); + } + break; + + case OS_THREAD_STATE_RUNNING: + RunQueueHint = TRUE; + break; + + case OS_THREAD_STATE_WAITING: + DequeueItem(thread->queue, thread, link); + thread->queue = NULL; + if (!IsSuspended(thread->suspend) && thread->mutex) { + ASSERT(thread->mutex->thread); + UpdatePriority(thread->mutex->thread); + } + break; + + default: + OSRestoreInterrupts(enabled); + return; + } + + OSClearContext(&thread->context); + if (thread->attr & 1) { + DequeueItem(&__OSActiveThreadQueue, thread, linkActive); + thread->state = 0; + } + else { + thread->state = 8; + } + + __OSUnlockAllMutex(thread); + OSWakeupThread(&thread->queueJoin); + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +BOOL OSJoinThread(OSThread* thread, void** val) { + BOOL enabled = OSDisableInterrupts(); + + if (!(thread->attr & 1) && thread->state != OS_THREAD_STATE_MORIBUND && thread->queueJoin.head == NULL) { + OSSleepThread(&thread->queueJoin); + if (!__OSIsThreadActive(thread)) { + OSRestoreInterrupts(enabled); + return FALSE; + } + } + + if (((volatile OSThread*) thread)->state == OS_THREAD_STATE_MORIBUND) { + if (val) { + *val = thread->value; + } + + DequeueItem(&__OSActiveThreadQueue, thread, linkActive); + thread->state = 0; + OSRestoreInterrupts(enabled); + return TRUE; + } + + OSRestoreInterrupts(enabled); + return FALSE; +} + +void OSDetachThread(OSThread* thread) +{ + BOOL enabled = OSDisableInterrupts(); + + thread->attr |= 1; + if (thread->state == OS_THREAD_STATE_MORIBUND) { + DequeueItem(&__OSActiveThreadQueue, thread, linkActive); + thread->state = 0; + } + + OSWakeupThread(&thread->queueJoin); + OSRestoreInterrupts(enabled); +} + +s32 OSResumeThread(OSThread* thread) { + BOOL enabled; + s32 suspendCount; + + enabled = OSDisableInterrupts(); + + suspendCount = thread->suspend--; + + if (thread->suspend < 0) { + thread->suspend = 0; + } + else if (thread->suspend == 0) { + switch (thread->state) { + case OS_THREAD_STATE_READY: + thread->priority = __OSGetEffectivePriority(thread); + SetRun(thread); + break; + + case OS_THREAD_STATE_WAITING: + ASSERT(thread->queue); + DequeueItem(thread->queue, thread, link); + thread->priority = __OSGetEffectivePriority(thread); + EnqueuePrio(thread->queue, thread, link); + if (thread->mutex) { + UpdatePriority(thread->mutex->thread); + } + break; + } + + __OSReschedule(); + } + + OSRestoreInterrupts(enabled); + return suspendCount; +} + +s32 OSSuspendThread(OSThread* thread) +{ + BOOL enabled; + s32 suspendCount; + + enabled = OSDisableInterrupts(); + suspendCount = thread->suspend++; + + if (suspendCount == 0) { + switch (thread->state) { + case OS_THREAD_STATE_RUNNING: + RunQueueHint = TRUE; + thread->state = OS_THREAD_STATE_READY; + break; + + case OS_THREAD_STATE_READY: + UnsetRun(thread); + break; + + case OS_THREAD_STATE_WAITING: + DequeueItem(thread->queue, thread, link); + thread->priority = 32; + EnqueueTail(thread->queue, thread, link); + + if (thread->mutex) { + ASSERT(thread->mutex->thread); + UpdatePriority(thread->mutex->thread); + } + break; + } + + __OSReschedule(); + } + + OSRestoreInterrupts(enabled); + return suspendCount; +} + +void OSSleepThread(OSThreadQueue* queue) { + BOOL enabled; + OSThread* currentThread; + + enabled = OSDisableInterrupts(); + currentThread = OSGetCurrentThread(); + + currentThread->state = 4; + currentThread->queue = queue; + EnqueuePrio(queue, currentThread, link); + RunQueueHint = TRUE; + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +void OSWakeupThread(OSThreadQueue* queue) { + BOOL enabled; + OSThread* thread; + + enabled = OSDisableInterrupts(); + while (queue->head) { + DequeueHead(queue, thread, link); + thread->state = 1; + + if (!IsSuspended(thread->suspend)) { + SetRun(thread); + } + } + + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +static void OSClearStack(u8 val) { + u32 sp; + u32* p; + u32 pattern; + + pattern = ((u32)val << 24) | ((u32)val << 16) | ((u32)val << 8) | (u32)val; + sp = OSGetStackPointer(); + + for (p = __OSCurrentThread->stackEnd + 1; p < (u32*)sp; ++p) { + *p = pattern; + } +} + +BOOL OSSetThreadPriority(OSThread* thread, OSPriority priority) { + BOOL enabled; + + if (priority < 0 || priority > 31) { + return FALSE; + } + + enabled = OSDisableInterrupts(); + + if (thread->base != priority) { + thread->base = priority; + UpdatePriority(thread); + __OSReschedule(); + } + + OSRestoreInterrupts(enabled); + return TRUE; +} + +OSPriority OSGetThreadPriority(OSThread* thread) { + return thread->base; +} + +static void SleepAlarmHandler(OSAlarm *alarm, OSContext *context) { + OSResumeThread((OSThread*)OSGetAlarmUserData(alarm)); +} + +void OSSleepTicks(OSTime tick) { + BOOL enabled; + OSThread* current; + OSAlarm sleepAlarm; + + enabled = OSDisableInterrupts(); + current = OSGetCurrentThread(); + + if (current == NULL) { + OSRestoreInterrupts(enabled); + return; + } + + OSCreateAlarm(&sleepAlarm); + OSSetAlarmTag(&sleepAlarm, (u32)current); + OSSetAlarmUserData(&sleepAlarm, (void*)current); + OSSetAlarm(&sleepAlarm, tick, SleepAlarmHandler); + OSSuspendThread(current); + OSCancelAlarm(&sleepAlarm); + OSRestoreInterrupts(enabled); +} diff --git a/src/RVL_SDK/os/OSTime.c b/src/RVL_SDK/os/OSTime.c new file mode 100644 index 000000000..be65bd59b --- /dev/null +++ b/src/RVL_SDK/os/OSTime.c @@ -0,0 +1,111 @@ +#include +#include + +static int YearDays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; +static int LeapYearDays[] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; + +asm OSTime OSGetTime(void) { + nofralloc + +loop: + mftbu r3 + mftb r4 + mftbu r5 + cmpw r3, r5 + bne loop + blr +} + +asm OSTick OSGetTick(void) { + nofralloc + mftb r3 + blr +} + +OSTime __OSGetSystemTime(void) { + BOOL en; + OSTime* time = (OSTime*)(0x800030D8); + OSTime res; + + en = OSDisableInterrupts(); + res = *time + OSGetTime(); + OSRestoreInterrupts(en); + return res; +} + +OSTime __OSTimeToSystemTime(OSTime time) { + BOOL en; + OSTime* os_time = (OSTime*)(0x800030D8); + OSTime res; + + en = OSDisableInterrupts(); + res = *os_time + time; + OSRestoreInterrupts(en); + return res; +} + +static BOOL IsLeapYear(int year) { + return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; +} + +static int GetLeapDays(int year) { + if (year < 1) { + return 0; + } + + return (year + 3) / 4 - (year - 1) / 100 + (year - 1) / 400; +} + +static void GetDates(s32 days, OSCalendarTime *pTime) NO_INLINE; + +void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime *pTime) { + int numDays; + int numSecs; + OSTime ticksAfter; + + ticksAfter = ticks % OSSecondsToTicks(1); + + if (ticksAfter < 0) { + ticksAfter += OSSecondsToTicks(1); + } + + pTime->usec = (int)(OSTicksToMicroseconds(ticksAfter) % 1000); + pTime->msec = (int)(OSTicksToMilliseconds(ticksAfter) % 1000); + + ticks -= ticksAfter; + + numDays = (int)(OSTicksToSeconds(ticks) / 86400 + 0xB2575); + numSecs = (int)(OSTicksToSeconds(ticks) % 86400); + + if (numSecs < 0) { + numDays -= 1; + numSecs += 86400; + } + + GetDates(numDays, pTime); + pTime->hour = numSecs / 60 / 60; + pTime->min = (numSecs / 60) % 60; + pTime->sec = numSecs % 60; +} + +static void GetDates(s32 days, OSCalendarTime *pTime) { + int year; + int dayCount; + int month; + int* monthArr; + + pTime->wday = (days + 6) % 7; + + for (year = days / 365; days < (dayCount = GetLeapDays(year) + 365 * year); --year); + + days -= dayCount; + pTime->year = year; + pTime->yday = days; + + monthArr = IsLeapYear(year) ? LeapYearDays : YearDays; + + for (month = 12; days < monthArr[--month];); + + pTime->mon = month; + pTime->mday = days - monthArr[month] + 1; +} \ No newline at end of file diff --git a/src/RVL_SDK/os/OSUtf.c b/src/RVL_SDK/os/OSUtf.c new file mode 100644 index 000000000..f30ee34c3 --- /dev/null +++ b/src/RVL_SDK/os/OSUtf.c @@ -0,0 +1,3554 @@ +#include + +static u16 UcsAnsiTable[] = { + 0x20AC, + 0x0000, + 0x201A, + 0x0192, + 0x201E, + 0x2026, + 0x2020, + 0x2021, + 0x02C6, + 0x2030, + 0x0160, + 0x2039, + 0x0152, + 0x0000, + 0x017D, + 0x0000, + 0x0000, + 0x2018, + 0x2019, + 0x201C, + 0x201D, + 0x2022, + 0x2013, + 0x2014, + 0x02DC, + 0x2122, + 0x0161, + 0x203A, + 0x0153, + 0x0000, + 0x017E, + 0x0178 +}; + +char* OSUTF8to32(const char* utf8, u32* utf32) +{ + u32 u = 0; + u8 c; + unsigned len; + unsigned i; + + c = (u8)*utf8; + if (c != '\0') { + ++utf8; + } + if ((c & 0x80u) == 0) { + u = c; + len = 0; + } + else if ((c & 0xE0u) == 0xC0) { + u = c & 0x1F; + len = 1; + } + else if ((c & 0xF0u) == 0xE0) { + u = c & 0xF; + len = 2; + } + else if ((c & 0xF8) == 0xF0u) { + u = c & 7; + len = 3; + } + else { + return NULL; + } + + for (i = 0; i < len; ++i) { + u <<= 6; + c = (u8)*utf8++; + + if ((c & 0xC0) != 0x80u) { + return NULL; + } + u |= (c & 0x3F); + } + + if (u <= 0x7F) { + if (len != 0) { + return NULL; + } + } + else if (u <= 0x7FF) { + if (len != 1) { + return NULL; + } + } + else if (u <= 0xFFFF) { + if (len != 2) { + return NULL; + } + } + + if (0xD800 <= u && u <= 0xDFFF) { + return NULL; + } + + *utf32 = u; + return (char*)utf8; +} + +u16* OSUTF16to32(const u16* utf16, u32* utf32) { + u16 w1; + u16 w2; + u32 u = 0; + + w1 = *utf16; + if (w1 != 0) { + ++utf16; + } + + if (w1 < 0xD800 || 0xDFFF < w1) { + u = w1; + } + else if (w1 <= 0xDBFF) { + w2 = *utf16++; + + if (0xDC00 <= w2 && w2 <= 0xDFFF) { + u = ((w1 & 0x03FF) << 10) | (w2 & 0x03FF); + u += 0x10000; + } + else { + return NULL; + } + } + else { + return NULL; + } + + *utf32 = u; + return (u16*)utf16; +} + +u8 OSUTF32toANSI(u32 utf32) { + int i; + + if (0xFF < utf32) { + return 0; + } + + if (utf32 < 0x80 || 0x9F < utf32) { + return (u8) utf32; + } + + if (0x0152 <= utf32 && utf32 <= 0x2122) { + for (i = 0; i <= 0x1F; ++i) { + if (UcsAnsiTable[i] == utf32) { + return (u8)(0x80 + i); + } + } + } + return 0; +} + +static u16 Ucs00[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5B, 0x815F, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8191, 0x8192, 0x0, 0x5C, 0x0, 0x8198, + 0x814E, 0x0, 0x0, 0x0, 0x81CA, 0x0, 0x0, 0x0, + 0x818B, 0x817D, 0x0, 0x0, 0x814C, 0x0, 0x81F7, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x817E, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8180, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs03[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x839F, 0x83A0, 0x83A1, 0x83A2, 0x83A3, 0x83A4, 0x83A5, + 0x83A6, 0x83A7, 0x83A8, 0x83A9, 0x83AA, 0x83AB, 0x83AC, 0x83AD, + 0x83AE, 0x83AF, 0x0, 0x83B0, 0x83B1, 0x83B2, 0x83B3, 0x83B4, + 0x83B5, 0x83B6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x83BF, 0x83C0, 0x83C1, 0x83C2, 0x83C3, 0x83C4, 0x83C5, + 0x83C6, 0x83C7, 0x83C8, 0x83C9, 0x83CA, 0x83CB, 0x83CC, 0x83CD, + 0x83CE, 0x83CF, 0x0, 0x83D0, 0x83D1, 0x83D2, 0x83D3, 0x83D4, + 0x83D5, 0x83D6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs04[] = +{ + 0x0, 0x8446, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8440, 0x8441, 0x8442, 0x8443, 0x8444, 0x8445, 0x8447, 0x8448, + 0x8449, 0x844A, 0x844B, 0x844C, 0x844D, 0x844E, 0x844F, 0x8450, + 0x8451, 0x8452, 0x8453, 0x8454, 0x8455, 0x8456, 0x8457, 0x8458, + 0x8459, 0x845A, 0x845B, 0x845C, 0x845D, 0x845E, 0x845F, 0x8460, + 0x8470, 0x8471, 0x8472, 0x8473, 0x8474, 0x8475, 0x8477, 0x8478, + 0x8479, 0x847A, 0x847B, 0x847C, 0x847D, 0x847E, 0x8480, 0x8481, + 0x8482, 0x8483, 0x8484, 0x8485, 0x8486, 0x8487, 0x8488, 0x8489, + 0x848A, 0x848B, 0x848C, 0x848D, 0x848E, 0x848F, 0x8490, 0x8491, + 0x0, 0x8476, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs20[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x815D, 0x0, 0x0, 0x0, 0x0, 0x815C, 0x8161, 0x0, + 0x8165, 0x8166, 0x0, 0x0, 0x8167, 0x8168, 0x0, 0x0, + 0x81F5, 0x81F6, 0x0, 0x0, 0x0, 0x8164, 0x8163, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x81F1, 0x0, 0x818C, 0x818D, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x81A6, 0x0, 0x0, 0x7E, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs21[] = +{ + 0x0, 0x0, 0x0, 0x818E, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x81F0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x81A9, 0x81AA, 0x81A8, 0x81AB, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x81CB, 0x0, 0x81CC, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs22[] = +{ + 0x81CD, 0x0, 0x81DD, 0x81CE, 0x0, 0x0, 0x0, 0x81DE, + 0x81B8, 0x0, 0x0, 0x81B9, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x817C, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x81E3, 0x0, 0x0, 0x81E5, 0x8187, 0x0, + 0x81DA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x81C8, + 0x81C9, 0x81BF, 0x81BE, 0x81E7, 0x81E8, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8188, 0x81E6, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x81E4, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x81E0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8182, 0x81DF, 0x0, 0x0, 0x0, 0x0, 0x8185, 0x8186, + 0x0, 0x0, 0x81E1, 0x81E2, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x81BC, 0x81BD, 0x0, 0x0, 0x81BA, 0x81BB, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x81DB, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs23[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x81DC, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs25[] = +{ + 0x849F, 0x84AA, 0x84A0, 0x84AB, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x84A1, 0x0, 0x0, 0x84AC, + 0x84A2, 0x0, 0x0, 0x84AD, 0x84A4, 0x0, 0x0, 0x84AF, + 0x84A3, 0x0, 0x0, 0x84AE, 0x84A5, 0x84BA, 0x0, 0x0, + 0x84B5, 0x0, 0x0, 0x84B0, 0x84A7, 0x84BC, 0x0, 0x0, + 0x84B7, 0x0, 0x0, 0x84B2, 0x84A6, 0x0, 0x0, 0x84B6, + 0x84BB, 0x0, 0x0, 0x84B1, 0x84A8, 0x0, 0x0, 0x84B8, + 0x84BD, 0x0, 0x0, 0x84B3, 0x84A9, 0x0, 0x0, 0x84B9, + 0x0, 0x0, 0x84BE, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x84B4, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x81A1, 0x81A0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x81A3, 0x81A2, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x81A5, 0x81A4, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x819F, 0x819E, + 0x0, 0x0, 0x0, 0x819B, 0x0, 0x0, 0x819D, 0x819C, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x81FC, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs26[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x819A, 0x8199, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x818A, 0x0, 0x8189, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x81F4, 0x0, 0x0, 0x81F3, 0x0, 0x81F2, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs30[] = +{ + 0x8140, 0x8141, 0x8142, 0x8156, 0x0, 0x8158, 0x8159, 0x815A, + 0x8171, 0x8172, 0x8173, 0x8174, 0x8175, 0x8176, 0x8177, 0x8178, + 0x8179, 0x817A, 0x81A7, 0x81AC, 0x816B, 0x816C, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8160, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x829F, 0x82A0, 0x82A1, 0x82A2, 0x82A3, 0x82A4, 0x82A5, + 0x82A6, 0x82A7, 0x82A8, 0x82A9, 0x82AA, 0x82AB, 0x82AC, 0x82AD, + 0x82AE, 0x82AF, 0x82B0, 0x82B1, 0x82B2, 0x82B3, 0x82B4, 0x82B5, + 0x82B6, 0x82B7, 0x82B8, 0x82B9, 0x82BA, 0x82BB, 0x82BC, 0x82BD, + 0x82BE, 0x82BF, 0x82C0, 0x82C1, 0x82C2, 0x82C3, 0x82C4, 0x82C5, + 0x82C6, 0x82C7, 0x82C8, 0x82C9, 0x82CA, 0x82CB, 0x82CC, 0x82CD, + 0x82CE, 0x82CF, 0x82D0, 0x82D1, 0x82D2, 0x82D3, 0x82D4, 0x82D5, + 0x82D6, 0x82D7, 0x82D8, 0x82D9, 0x82DA, 0x82DB, 0x82DC, 0x82DD, + 0x82DE, 0x82DF, 0x82E0, 0x82E1, 0x82E2, 0x82E3, 0x82E4, 0x82E5, + 0x82E6, 0x82E7, 0x82E8, 0x82E9, 0x82EA, 0x82EB, 0x82EC, 0x82ED, + 0x82EE, 0x82EF, 0x82F0, 0x82F1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x814A, 0x814B, 0x8154, 0x8155, 0x0, + 0x0, 0x8340, 0x8341, 0x8342, 0x8343, 0x8344, 0x8345, 0x8346, + 0x8347, 0x8348, 0x8349, 0x834A, 0x834B, 0x834C, 0x834D, 0x834E, + 0x834F, 0x8350, 0x8351, 0x8352, 0x8353, 0x8354, 0x8355, 0x8356, + 0x8357, 0x8358, 0x8359, 0x835A, 0x835B, 0x835C, 0x835D, 0x835E, + 0x835F, 0x8360, 0x8361, 0x8362, 0x8363, 0x8364, 0x8365, 0x8366, + 0x8367, 0x8368, 0x8369, 0x836A, 0x836B, 0x836C, 0x836D, 0x836E, + 0x836F, 0x8370, 0x8371, 0x8372, 0x8373, 0x8374, 0x8375, 0x8376, + 0x8377, 0x8378, 0x8379, 0x837A, 0x837B, 0x837C, 0x837D, 0x837E, + 0x8380, 0x8381, 0x8382, 0x8383, 0x8384, 0x8385, 0x8386, 0x8387, + 0x8388, 0x8389, 0x838A, 0x838B, 0x838C, 0x838D, 0x838E, 0x838F, + 0x8390, 0x8391, 0x8392, 0x8393, 0x8394, 0x8395, 0x8396, 0x0, + 0x0, 0x0, 0x0, 0x8145, 0x815B, 0x8152, 0x8153, 0x0, +}; + +static u16 Ucs4E[] = +{ + 0x88EA, 0x929A, 0x0, 0x8EB5, 0x0, 0x0, 0x0, 0x969C, + 0x8FE4, 0x8E4F, 0x8FE3, 0x89BA, 0x0, 0x9573, 0x975E, 0x0, + 0x98A0, 0x894E, 0x0, 0x0, 0x8A8E, 0x98A1, 0x90A2, 0x99C0, + 0x8B75, 0x95B8, 0x0, 0x0, 0x0, 0x0, 0x8FE5, 0x0, + 0x0, 0x97BC, 0x0, 0x0, 0x0, 0x0, 0x95C0, 0x0, + 0x0, 0x0, 0x98A2, 0x0, 0x0, 0x9286, 0x0, 0x0, + 0x0, 0x98A3, 0x8BF8, 0x0, 0x0, 0x0, 0x98A4, 0x0, + 0x8ADB, 0x924F, 0x0, 0x8EE5, 0x98A5, 0x0, 0x0, 0x98A6, + 0x0, 0x0, 0x98A7, 0x9454, 0x0, 0x8B76, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9456, 0x0, 0x93E1, 0x8CC1, 0x9652, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE568, 0x98A8, 0x8FE6, + 0x98A9, 0x89B3, 0x0, 0x0, 0x0, 0x8BE3, 0x8CEE, 0x96E7, + 0x0, 0x0, 0x9BA4, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9790, 0x0, 0x93FB, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8AA3, 0x0, + 0x8B54, 0x0, 0x98AA, 0x0, 0x0, 0x98AB, 0x97B9, 0x0, + 0x975C, 0x9188, 0x98AD, 0x8E96, 0x93F1, 0x0, 0x98B0, 0x0, + 0x0, 0x895D, 0x8CDD, 0x0, 0x8CDC, 0x88E4, 0x0, 0x0, + 0x986A, 0x9869, 0x0, 0x8DB1, 0x889F, 0x0, 0x98B1, 0x98B2, + 0x98B3, 0x9653, 0x98B4, 0x0, 0x8CF0, 0x88E5, 0x9692, 0x0, + 0x8B9C, 0x0, 0x0, 0x8B9D, 0x8B9E, 0x92E0, 0x97BA, 0x0, + 0x98B5, 0x0, 0x0, 0x98B6, 0x0, 0x0, 0x98B7, 0x0, + 0x0, 0x0, 0x906C, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8F59, 0x906D, 0x98BC, 0x0, 0x98BA, 0x0, 0x98BB, 0x8B77, + 0x0, 0x0, 0x8DA1, 0x89EE, 0x0, 0x98B9, 0x98B8, 0x95A7, + 0x0, 0x0, 0x0, 0x0, 0x8E65, 0x8E64, 0x91BC, 0x98BD, + 0x9574, 0x90E5, 0x0, 0x0, 0x0, 0x8157, 0x98BE, 0x98C0, + 0x0, 0x0, 0x0, 0x91E3, 0x97DF, 0x88C8, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x98BF, 0x89BC, 0x0, + 0x8BC2, 0x0, 0x9287, 0x0, 0x0, 0x0, 0x8C8F, 0x98C1, + 0x0, 0x0, 0x0, 0x9443, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs4F[] = +{ + 0x0, 0x8AE9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x98C2, 0x88C9, 0x0, 0x0, 0x8CDE, 0x8AEA, 0x959A, + 0x94B0, 0x8B78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x89EF, 0x0, 0x98E5, 0x9360, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x948C, + 0x98C4, 0x0, 0x0, 0x0, 0x94BA, 0x0, 0x97E0, 0x0, + 0x904C, 0x0, 0x8E66, 0x0, 0x8E97, 0x89BE, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x92CF, 0x0, 0x0, 0x9241, 0x98C8, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x88CA, 0x92E1, 0x8F5A, + 0x8DB2, 0x9743, 0x0, 0x91CC, 0x0, 0x89BD, 0x0, 0x98C7, + 0x0, 0x975D, 0x98C3, 0x98C5, 0x8DEC, 0x98C6, 0x9B43, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x98CE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x98D1, + 0x98CF, 0x0, 0x0, 0x89C0, 0x0, 0x95B9, 0x98C9, 0x0, + 0x0, 0x0, 0x0, 0x98CD, 0x8CF1, 0x0, 0x0, 0x8E67, + 0x0, 0x0, 0x0, 0x8AA4, 0x0, 0x0, 0x98D2, 0x0, + 0x98CA, 0x0, 0x0, 0x97E1, 0x0, 0x8E98, 0x0, 0x98CB, + 0x0, 0x98D0, 0x0, 0x0, 0x0, 0x0, 0x98D3, 0x0, + 0x98CC, 0x0, 0x0, 0x8B9F, 0x0, 0x88CB, 0x0, 0x0, + 0x8BA0, 0x89BF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9B44, 0x0, 0x9699, 0x958E, 0x8CF2, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x904E, 0x97B5, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x95D6, + 0x0, 0x0, 0x8C57, 0x91A3, 0x89E2, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8F72, 0x0, 0x0, 0x0, 0x98D7, 0x0, + 0x98DC, 0x98DA, 0x0, 0x0, 0x98D5, 0x0, 0x0, 0x91AD, + 0x98D8, 0x0, 0x98DB, 0x98D9, 0x0, 0x95DB, 0x0, 0x98D6, + 0x0, 0x904D, 0x0, 0x9693, 0x98DD, 0x98DE, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8F43, 0x98EB, + 0x0, 0x0, 0x0, 0x946F, 0x0, 0x9555, 0x98E6, 0x0, + 0x95EE, 0x0, 0x89B4, 0x0, 0x0, 0x0, 0x98EA, 0x0, +}; + +static u16 Ucs50[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x98E4, 0x98ED, 0x0, + 0x0, 0x9171, 0x0, 0x8CC2, 0x0, 0x947B, 0x0, 0xE0C5, + 0x0, 0x98EC, 0x937C, 0x0, 0x98E1, 0x0, 0x8CF4, 0x0, + 0x0, 0x8CF3, 0x98DF, 0x0, 0x0, 0x0, 0x0, 0x8ED8, + 0x0, 0x98E7, 0x0, 0x95ED, 0x926C, 0x98E3, 0x8C91, 0x0, + 0x98E0, 0x98E8, 0x98E2, 0x97CF, 0x98E9, 0x9860, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8BE4, 0x0, + 0x0, 0x8C90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x98EE, 0x0, 0x0, 0x0, 0x98EF, + 0x98F3, 0x88CC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x95CE, + 0x98F2, 0x0, 0x0, 0x0, 0x0, 0x98F1, 0x98F5, 0x0, + 0x0, 0x0, 0x98F4, 0x0, 0x92E2, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8C92, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x98F6, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8EC3, 0x0, 0x91A4, 0x92E3, 0x8BF4, 0x0, + 0x98F7, 0x0, 0x0, 0x0, 0x0, 0x8B55, 0x0, 0x0, + 0x98F8, 0x0, 0x0, 0x0, 0x0, 0x98FA, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9654, 0x0, 0x0, + 0x0, 0x8C86, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8E50, 0x94F5, 0x98F9, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8DC3, 0x9762, 0x0, 0x0, + 0x0, 0x0, 0x98FC, 0x9942, 0x98FB, 0x8DC2, 0x0, 0x8F9D, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8C58, 0x0, + 0x0, 0x0, 0x9943, 0x0, 0x0, 0x8BCD, 0x0, 0x0, + 0x0, 0x9940, 0x9941, 0x0, 0x0, 0x93AD, 0x0, 0x919C, + 0x0, 0x8BA1, 0x0, 0x0, 0x0, 0x966C, 0x9944, 0x0, + 0x0, 0x0, 0x97BB, 0x0, 0x0, 0x0, 0x9945, 0x0, + 0x0, 0x0, 0x0, 0x9948, 0x0, 0x9946, 0x0, 0x916D, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9947, 0x9949, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x994B, 0x0, 0x0, + 0x0, 0x994A, 0x0, 0x95C6, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs51[] = +{ + 0x8B56, 0x994D, 0x994E, 0x0, 0x89AD, 0x0, 0x0, 0x0, + 0x0, 0x994C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8EF2, 0x0, 0x9951, 0x9950, 0x994F, 0x0, + 0x98D4, 0x0, 0x9952, 0x0, 0x0, 0x0, 0x0, 0x8F9E, + 0x0, 0x9953, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9744, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x96D7, 0x0, 0x0, 0x0, 0x0, 0x9955, + 0x0, 0x0, 0x9954, 0x9957, 0x9956, 0x0, 0x0, 0x9958, + 0x9959, 0x88F2, 0x0, 0x8CB3, 0x8C5A, 0x8F5B, 0x929B, 0x8BA2, + 0x90E6, 0x8CF5, 0x0, 0x8D8E, 0x995B, 0x96C6, 0x9365, 0x0, + 0x8E99, 0x0, 0x995A, 0x0, 0x995C, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x937D, 0x0, 0x8A95, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x995D, 0x0, 0x0, 0x93FC, 0x0, 0x0, + 0x9153, 0x995F, 0x9960, 0x94AA, 0x8CF6, 0x985A, 0x9961, 0x0, + 0x0, 0x8BA4, 0x0, 0x0, 0x0, 0x95BA, 0x91B4, 0x8BEF, + 0x9354, 0x0, 0x0, 0x0, 0x8C93, 0x0, 0x0, 0x0, + 0x9962, 0x0, 0x9963, 0x0, 0x0, 0x93E0, 0x897E, 0x0, + 0x0, 0x9966, 0x8DFB, 0x0, 0x9965, 0x8DC4, 0x0, 0x9967, + 0xE3EC, 0x9968, 0x9660, 0x9969, 0x0, 0x996A, 0x996B, 0x8FE7, + 0x0, 0x8ECA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8AA5, 0x0, 0x996E, 0x0, 0x996C, 0x96BB, 0x996D, 0x0, + 0x9579, 0x996F, 0x9970, 0x9971, 0x937E, 0x0, 0x0, 0x0, + 0x9975, 0x9973, 0x9974, 0x9972, 0x8DE1, 0x9976, 0x96E8, 0x97E2, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9977, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x90A6, 0x9978, 0x8F79, 0x0, + 0x0, 0x9979, 0x0, 0x929C, 0x97BD, 0x9380, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x99C3, 0x0, + 0x0, 0x0, 0x0, 0x997A, 0xEAA3, 0x8BC3, 0x0, 0x0, + 0x997B, 0x967D, 0x0, 0x0, 0x0, 0x0, 0x8F88, 0x91FA, + 0x0, 0x997D, 0x93E2, 0x0, 0x0, 0x997E, 0x0, 0x0, + 0x9980, 0x8A4D, 0x0, 0x0, 0x0, 0x9981, 0x8BA5, 0x0, + 0x93CA, 0x899A, 0x8F6F, 0x0, 0x0, 0x949F, 0x9982, 0x0, +}; + +static u16 Ucs52[] = +{ + 0x9381, 0x0, 0x0, 0x906E, 0x9983, 0x0, 0x95AA, 0x90D8, + 0x8AA0, 0x0, 0x8AA7, 0x9984, 0x0, 0x0, 0x9986, 0x0, + 0x0, 0x8C59, 0x0, 0x0, 0x9985, 0x0, 0x0, 0x97F1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8F89, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x94BB, 0x95CA, 0x0, 0x9987, + 0x0, 0x9798, 0x9988, 0x0, 0x0, 0x0, 0x9989, 0x0, + 0x939E, 0x0, 0x0, 0x998A, 0x0, 0x0, 0x90A7, 0x8DFC, + 0x8C94, 0x998B, 0x8E68, 0x8D8F, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x92E4, 0x998D, 0x0, 0x0, 0x91A5, + 0x0, 0x0, 0x8DED, 0x998E, 0x998F, 0x914F, 0x0, 0x998C, + 0x0, 0x0, 0x0, 0x0, 0x9991, 0x0, 0x9655, 0x0, + 0x0, 0x0, 0x0, 0x8D84, 0x0, 0x0, 0x9990, 0x0, + 0x0, 0x0, 0x0, 0x8C95, 0x8DDC, 0x948D, 0x0, 0x0, + 0x0, 0x9994, 0x9992, 0x0, 0x0, 0x0, 0x0, 0x959B, + 0x8FE8, 0x999B, 0x8A84, 0x9995, 0x9993, 0x916E, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9997, 0x0, 0x9996, + 0x0, 0x0, 0x0, 0x8A63, 0x0, 0x0, 0x0, 0x8C80, + 0x999C, 0x97AB, 0x0, 0x0, 0x0, 0x9998, 0x0, 0x0, + 0x0, 0x999D, 0x999A, 0x0, 0x9999, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x97CD, 0x0, 0x0, 0x0, 0x8CF7, + 0x89C1, 0x0, 0x0, 0x97F2, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8F95, 0x9377, 0x8D85, 0x99A0, 0x99A1, 0x0, 0x0, + 0x0, 0x97E3, 0x0, 0x0, 0x984A, 0x99A3, 0x0, 0x0, + 0x0, 0x8CF8, 0x0, 0x0, 0x99A2, 0x0, 0x8A4E, 0x0, + 0x0, 0x99A4, 0x0, 0x9675, 0x0, 0x92BA, 0x0, 0x9745, + 0x0, 0x95D7, 0x0, 0x0, 0x0, 0x99A5, 0x0, 0x0, + 0x0, 0x0, 0xE8D3, 0x0, 0x0, 0x93AE, 0x0, 0x99A6, + 0x8AA8, 0x96B1, 0x0, 0x0, 0x0, 0x8F9F, 0x99A7, 0x95E5, + 0x99AB, 0x0, 0x90A8, 0x99A8, 0x8BCE, 0x0, 0x99A9, 0x8AA9, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8C4D, 0x99AC, 0x0, 0x99AD, 0x0, 0x0, + 0x99AE, 0x99AF, 0x8ED9, 0x0, 0x0, 0x0, 0x8CF9, 0x96DC, +}; + +static u16 Ucs53[] = +{ + 0x0, 0x96E6, 0x93F5, 0x0, 0x0, 0x95EF, 0x99B0, 0x0, + 0x99B1, 0x0, 0x0, 0x0, 0x0, 0x99B3, 0x0, 0x99B5, + 0x99B4, 0x0, 0x0, 0x0, 0x0, 0x99B6, 0x89BB, 0x966B, + 0x0, 0x8DFA, 0x99B7, 0x0, 0x0, 0x9178, 0x0, 0x0, + 0x8FA0, 0x8BA7, 0x0, 0x99B8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x94D9, 0x0, 0x0, 0x0, 0x0, 0x99B9, + 0x0, 0x99BA, 0x0, 0x99BB, 0x0, 0x0, 0x0, 0x0, + 0x99BC, 0x9543, 0x8BE6, 0x88E3, 0x0, 0x0, 0x0, 0x93BD, + 0x99BD, 0x8F5C, 0x0, 0x90E7, 0x0, 0x99BF, 0x99BE, 0x8FA1, + 0x8CDF, 0x99C1, 0x94BC, 0x0, 0x0, 0x99C2, 0x0, 0x0, + 0x0, 0x94DA, 0x91B2, 0x91EC, 0x8BA6, 0x0, 0x0, 0x93EC, + 0x9250, 0x0, 0x948E, 0x0, 0x966D, 0x0, 0x99C4, 0x0, + 0x90E8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8C54, 0x0, + 0x0, 0x99C5, 0x0, 0x0, 0x0, 0x0, 0x99C6, 0x894B, + 0x88F3, 0x8AEB, 0x0, 0x91A6, 0x8B70, 0x9791, 0x0, 0x99C9, + 0x89B5, 0x0, 0x0, 0x99C8, 0x0, 0x0, 0x0, 0x8BA8, + 0x0, 0x0, 0x99CA, 0x0, 0x96EF, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x99CB, 0x0, + 0x97D0, 0x0, 0x8CFA, 0x0, 0x0, 0x0, 0x0, 0x8CB4, + 0x99CC, 0x0, 0x0, 0x0, 0x0, 0x99CE, 0x99CD, 0x0, + 0x907E, 0x8958, 0x0, 0x0, 0x0, 0x897D, 0x99CF, 0x0, + 0x99D0, 0x0, 0x0, 0x8CB5, 0x0, 0x0, 0x99D1, 0x0, + 0x0, 0x0, 0x0, 0x8B8E, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8E51, 0x99D2, 0x0, 0x0, 0x0, 0x0, + 0x9694, 0x8DB3, 0x8B79, 0x9746, 0x916F, 0x94BD, 0x8EFB, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8F66, 0x0, 0x8EE6, 0x8EF3, + 0x0, 0x8F96, 0x0, 0x94BE, 0x0, 0x0, 0x0, 0x99D5, + 0x0, 0x8962, 0x9170, 0x8CFB, 0x8CC3, 0x8BE5, 0x0, 0x0, + 0x99D9, 0x9240, 0x91FC, 0x8BA9, 0x8FA2, 0x99DA, 0x99D8, 0x89C2, + 0x91E4, 0x8EB6, 0x8E6A, 0x8945, 0x0, 0x0, 0x8A90, 0x8D86, + 0x8E69, 0x0, 0x99DB, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs54[] = +{ + 0x0, 0x99DC, 0x0, 0x8B68, 0x8A65, 0x0, 0x0, 0x0, + 0x8D87, 0x8B67, 0x92DD, 0x8944, 0x93AF, 0x96BC, 0x8D40, 0x9799, + 0x9366, 0x8CFC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8C4E, 0x0, 0x99E5, 0x0, 0x8BE1, + 0x9669, 0x0, 0x0, 0x0, 0x0, 0x0, 0x94DB, 0x0, + 0x0, 0x99E4, 0x0, 0x8ADC, 0x99DF, 0x99E0, 0x99E2, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x99E3, 0x0, + 0x8B7A, 0x9081, 0x0, 0x95AB, 0x99E1, 0x99DD, 0x8CE1, 0x0, + 0x99DE, 0x0, 0x9843, 0x0, 0x0, 0x0, 0x95F0, 0x0, + 0x92E6, 0x8CE0, 0x8D90, 0x0, 0x0, 0x0, 0x99E6, 0x0, + 0x0, 0x93DB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x99EA, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8EFC, 0x0, 0x8EF4, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x99ED, 0x99EB, 0x0, 0x96A1, 0x0, 0x99E8, 0x99F1, 0x99EC, + 0x0, 0x0, 0x0, 0x99EF, 0x8CC4, 0x96BD, 0x0, 0x0, + 0x99F0, 0x0, 0x0, 0x0, 0x99F2, 0x0, 0x99F4, 0x0, + 0x0, 0x0, 0x0, 0x8DEE, 0x9861, 0x0, 0x99E9, 0x99E7, + 0x99F3, 0x0, 0x99EE, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x99F6, 0x0, 0x9A42, 0x99F8, 0x0, 0x0, + 0x99FC, 0x0, 0x0, 0x9A40, 0x99F9, 0x0, 0x0, 0x9A5D, + 0x0, 0x0, 0x8DE7, 0x8A50, 0x0, 0x0, 0x0, 0x0, + 0x99F7, 0x0, 0x0, 0x0, 0x9A44, 0x88F4, 0x9A43, 0x0, + 0x88A3, 0x9569, 0x9A41, 0x0, 0x99FA, 0x0, 0x0, 0x99F5, + 0x99FB, 0x8DC6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9A45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x88F5, 0x9A4E, 0x0, 0x0, 0x9A46, 0x9A47, 0x0, + 0x8FA3, 0x9689, 0x0, 0x0, 0x0, 0x9A4C, 0x9A4B, 0x0, + 0x0, 0x0, 0x934E, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9A4D, 0x0, 0x0, 0x9A4A, 0x0, 0x0, +}; + +static u16 Ucs55[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x8953, 0x0, 0x8DB4, 0x904F, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9A48, + 0x9382, 0x0, 0x0, 0x0, 0x9A49, 0x0, 0x88A0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9A53, 0x9742, + 0x0, 0x8FA5, 0x0, 0x9A59, 0x0, 0x0, 0x0, 0x0, + 0x9A58, 0x9A4F, 0x0, 0x0, 0x0, 0x0, 0x91C1, 0x0, + 0x9A50, 0x0, 0x0, 0x0, 0x91ED, 0x9A55, 0x8FA4, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9A52, 0x0, 0x0, 0x96E2, + 0x0, 0x0, 0x0, 0x8C5B, 0x0, 0x0, 0x9A56, 0x9A57, + 0x0, 0x0, 0x0, 0x0, 0x9A54, 0x9A5A, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9A51, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9A60, 0x9A65, 0x0, 0x9A61, 0x0, + 0x9A5C, 0x0, 0x0, 0x9A66, 0x9150, 0x0, 0x0, 0x9A68, + 0x0, 0x8D41, 0x9A5E, 0x929D, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9A62, 0x9A5B, 0x8AAB, 0x0, 0x8AEC, 0x8A85, 0x9A63, 0x9A5F, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8C96, + 0x9A69, 0x9A67, 0x9172, 0x8B69, 0x8BAA, 0x0, 0x9A64, 0x0, + 0x8BF2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8963, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9A6D, 0x9A6B, 0x0, 0x9AA5, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9A70, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9A6A, 0x0, 0x9A6E, 0x0, 0x0, 0x9A6C, + 0x0, 0x0, 0x0, 0x8E6B, 0x9A6F, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9A72, + 0x0, 0x9A77, 0x0, 0x0, 0x0, 0x9A75, 0x9A74, 0x0, +}; + +static u16 Ucs56[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9251, 0x0, + 0x0, 0x89C3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9A71, 0x0, 0x9A73, 0x8FA6, + 0x8952, 0x0, 0x0, 0x9A76, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x89DC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9A82, + 0x0, 0x8FFA, 0x9A7D, 0x0, 0x9A7B, 0x0, 0x9A7C, 0x0, + 0x9A7E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x895C, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9158, 0x0, 0x9A78, 0x0, + 0x9A79, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8A9A, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9A81, 0x0, 0x0, 0x0, + 0x8AED, 0x0, 0x9A84, 0x9A80, 0x9A83, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x95AC, 0x0, 0x0, 0x0, + 0x93D3, 0x0, 0x94B6, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9A86, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9A85, 0x8A64, + 0x0, 0x0, 0x9A87, 0x0, 0x0, 0x0, 0x0, 0x9A8A, + 0x0, 0x0, 0x0, 0x0, 0x9A89, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9A88, 0x0, 0x9458, 0x0, 0x0, 0x9A8B, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9A8C, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9A8E, 0x0, 0x9A8D, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9A90, 0x0, 0x0, 0x0, + 0x9A93, 0x9A91, 0x9A8F, 0x9A92, 0x0, 0x0, 0x0, 0x0, + 0x9A94, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9A95, 0x0, + 0x0, 0x9A96, 0x0, 0x9A97, 0x0, 0x0, 0x0, 0x9A98, + 0x9964, 0x0, 0x8EFA, 0x8E6C, 0x0, 0x0, 0x89F1, 0x0, + 0x88F6, 0x0, 0x0, 0x9263, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9A99, 0x0, + 0x8DA2, 0x0, 0x88CD, 0x907D, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9A9A, 0x8CC5, 0x0, 0x0, 0x8D91, 0x0, 0x9A9C, +}; + +static u16 Ucs57[] = +{ + 0x9A9B, 0x0, 0x0, 0x95DE, 0x9A9D, 0x0, 0x0, 0x0, + 0x9A9F, 0x9A9E, 0x0, 0x9AA0, 0x0, 0x9AA1, 0x0, 0x8C97, + 0x0, 0x0, 0x8980, 0x9AA2, 0x0, 0x0, 0x9AA4, 0x0, + 0x9AA3, 0x0, 0x0, 0x0, 0x9AA6, 0x0, 0x0, 0x9379, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9AA7, 0x88B3, + 0x8DDD, 0x0, 0x0, 0x0, 0x0, 0x8C5C, 0x0, 0x0, + 0x926E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9AA8, + 0x9AA9, 0x0, 0x0, 0x9AAB, 0x0, 0x0, 0x0, 0x0, + 0x9AAC, 0x0, 0x8DE2, 0x0, 0x0, 0x0, 0x0, 0x8BCF, + 0x0, 0x0, 0x9656, 0x0, 0x0, 0x0, 0x9AAA, 0x9AAD, + 0x8DBF, 0x8D42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9AB1, 0x0, 0x0, 0x8DA3, 0x0, 0x9252, 0x0, + 0x0, 0x9AAE, 0x92D8, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9AB2, + 0x0, 0x0, 0x9082, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9AB0, 0x9AB3, 0x0, 0x8C5E, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9AB4, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9AB5, 0x0, 0x8D43, 0x8A5F, 0x9AB7, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9AB8, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9AB9, 0x0, 0x0, 0x9AB6, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9AAF, 0x0, 0x0, 0x9ABA, 0x0, 0x0, 0x9ABB, 0x0, + 0x0, 0x0, 0x0, 0x9684, 0x0, 0x0, 0x8FE9, 0x0, + 0x0, 0x0, 0x9ABD, 0x9ABE, 0x9ABC, 0x0, 0x9AC0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9457, 0x0, 0x0, 0x88E6, + 0x9575, 0x0, 0x0, 0x9AC1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8FFB, 0x0, 0x0, 0x8EB7, + 0x0, 0x947C, 0x8AEE, 0x0, 0x8DE9, 0x0, 0x0, 0x0, +}; + +static u16 Ucs58[] = +{ + 0x9678, 0x0, 0x93B0, 0x0, 0x0, 0x8C98, 0x91CD, 0x0, + 0x0, 0x0, 0x9ABF, 0x9AC2, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x91C2, 0x0, 0x0, + 0x0, 0x9AC3, 0x0, 0x0, 0x0, 0x9AC4, 0x0, 0x0, + 0x0, 0x9AC6, 0x0, 0x0, 0x92E7, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8AAC, 0x0, 0x0, 0x0, 0x0, 0xEA9F, + 0x8981, 0x95F1, 0x0, 0x0, 0x8FEA, 0x9367, 0x0, 0x0, + 0x0, 0x0, 0x8DE4, 0x0, 0x0, 0x9ACC, 0x0, 0x0, + 0x95BB, 0x97DB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x89F2, 0x9AC8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9159, 0x9ACB, 0x0, 0x9383, 0x0, 0x0, 0x9368, + 0x9384, 0x94B7, 0x92CB, 0x0, 0x0, 0x0, 0x8DC7, 0x0, + 0x0, 0x0, 0x9AC7, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8996, 0x0, 0x9355, 0x0, 0x0, 0x0, 0x0, + 0x9AC9, 0x0, 0x9AC5, 0x0, 0x0, 0x906F, 0x0, 0x0, + 0x0, 0x9ACD, 0x0, 0x0, 0x0, 0x0, 0x8F6D, 0x0, + 0x0, 0x0, 0x0, 0x8BAB, 0x0, 0x9ACE, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x95E6, 0x0, 0x0, 0x0, 0x919D, + 0x0, 0x0, 0x0, 0x0, 0x92C4, 0x0, 0x0, 0x9AD0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x966E, 0x0, 0x0, 0x9AD1, 0x0, 0x0, 0x9AD6, 0x0, + 0x0, 0x0, 0x0, 0x95AD, 0x0, 0x0, 0x0, 0x0, + 0x9AD5, 0x9ACF, 0x9AD2, 0x9AD4, 0x0, 0x0, 0x8DA4, 0x0, + 0x0, 0x95C7, 0x0, 0x0, 0x0, 0x9AD7, 0x0, 0x9264, + 0x0, 0x0, 0x89F3, 0x0, 0x8FEB, 0x0, 0x0, 0x0, + 0x0, 0x9AD9, 0x0, 0x9AD8, 0x0, 0x8D88, 0x0, 0x9ADA, + 0x9ADC, 0x9ADB, 0x0, 0x0, 0x9ADE, 0x0, 0x9AD3, 0x9AE0, + 0x0, 0x0, 0x0, 0x0, 0x9ADF, 0x9ADD, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8E6D, 0x9070, 0x0, 0x9173, 0x9AE1, + 0x90BA, 0x88EB, 0x9484, 0x0, 0x0, 0x0, 0x0, 0x92D9, + 0x0, 0x9AE3, 0x9AE2, 0x9AE4, 0x9AE5, 0x9AE6, 0x0, 0x0, +}; + +static u16 Ucs59[] = +{ + 0x0, 0x0, 0x9AE7, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x95CF, 0x9AE8, 0x0, 0x0, 0x0, 0x0, 0x89C4, + 0x9AE9, 0x0, 0x0, 0x0, 0x0, 0x975B, 0x8A4F, 0x0, + 0x99C7, 0x8F67, 0x91BD, 0x9AEA, 0x96E9, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x96B2, 0x0, 0x0, 0x9AEC, 0x0, 0x91E5, + 0x0, 0x9356, 0x91BE, 0x9576, 0x9AED, 0x9AEE, 0x899B, 0x0, + 0x0, 0x8EB8, 0x9AEF, 0x0, 0x0, 0x0, 0x0, 0x88CE, + 0x9AF0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9AF1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8982, 0x0, 0x0, 0x8AEF, + 0x93DE, 0x95F2, 0x0, 0x0, 0x0, 0x0, 0x9AF5, 0x9174, + 0x9AF4, 0x8C5F, 0x0, 0x0, 0x967A, 0x9AF3, 0x0, 0x9385, + 0x9AF7, 0x0, 0x9AF6, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9AF9, 0x0, 0x9AF8, 0x0, 0x0, 0x899C, 0x0, 0x9AFA, + 0x8FA7, 0x9AFC, 0x9244, 0x0, 0x9AFB, 0x0, 0x95B1, 0x0, + 0x0, 0x0, 0x0, 0x8F97, 0x937A, 0x0, 0x0, 0x0, + 0x9B40, 0x0, 0x0, 0x0, 0x0, 0x8D44, 0x0, 0x0, + 0x0, 0x9B41, 0x9440, 0x94DC, 0x96CF, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9444, 0x0, 0x0, 0x9B4A, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8B57, 0x0, 0x0, 0x9764, 0x0, + 0x0, 0x96AD, 0x0, 0x9BAA, 0x0, 0x9B42, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9B45, 0x0, 0x91C3, 0x0, 0x0, + 0x9657, 0x0, 0x0, 0x0, 0x9369, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9B46, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9685, 0x0, 0x8DC8, 0x0, 0x0, 0x8FA8, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9B47, 0x0, + 0x0, 0x8E6F, 0x0, 0x8E6E, 0x0, 0x0, 0x0, 0x0, + 0x88B7, 0x8CC6, 0x0, 0x90A9, 0x88CF, 0x0, 0x0, 0x0, + 0x0, 0x9B4B, 0x9B4C, 0x0, 0x9B49, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8957, 0x8AAD, 0x0, + 0x9B48, 0x0, 0x96C3, 0x9550, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88A6, 0x0, + 0x0, 0x0, 0x0, 0x88F7, 0x0, 0x0, 0x0, 0x8E70, +}; + +static u16 Ucs5A[] = +{ + 0x0, 0x88D0, 0x0, 0x88A1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9B51, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9B4F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x96BA, 0x0, 0x9B52, 0x0, 0x9B50, 0x0, 0x0, 0x9B4E, + 0x9050, 0x0, 0x0, 0x0, 0x0, 0x9B4D, 0x0, 0x0, + 0x0, 0x95D8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8CE2, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9B56, 0x9B57, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8FA9, 0x0, 0x0, 0x0, + 0x9B53, 0x984B, 0x0, 0x0, 0x0, 0x0, 0x946B, 0x0, + 0x0, 0x9B55, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8DA5, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9B58, 0x0, 0x0, 0x0, 0x9577, 0x0, + 0x0, 0x0, 0x9B59, 0x0, 0x9B54, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x96B9, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x947D, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9B5A, 0x9551, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9B5B, 0x9B5F, 0x9B5C, 0x0, + 0x0, 0x89C5, 0x9B5E, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8EB9, 0x0, 0x9B5D, 0x8C99, 0x0, 0x0, 0x0, + 0x9B6B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9B64, 0x9B61, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9284, 0x0, 0x9B60, 0x0, 0x0, 0x9B62, 0x0, + 0x0, 0x9B63, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9B65, 0x9B66, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs5B[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8AF0, 0x0, 0x9B68, 0x9B67, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9B69, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8FEC, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9B6C, 0x0, 0x92DA, 0x0, 0x0, 0x0, + 0x8964, 0x0, 0x9B6A, 0x0, 0x0, 0x0, 0x9B6D, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9B6E, 0x0, + 0x9B71, 0x0, 0x0, 0x9B6F, 0x0, 0x9B70, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8E71, 0x9B72, 0x0, 0x0, 0x8D45, 0x9B73, 0x0, 0x8E9A, + 0x91B6, 0x0, 0x9B74, 0x9B75, 0x8E79, 0x8D46, 0x0, 0x96D0, + 0x0, 0x0, 0x0, 0x8B47, 0x8CC7, 0x9B76, 0x8A77, 0x0, + 0x0, 0x9B77, 0x0, 0x91B7, 0x0, 0x0, 0x0, 0x0, + 0x9B78, 0x9BA1, 0x0, 0x9B79, 0x0, 0x9B7A, 0x0, 0x0, + 0x9B7B, 0x0, 0x9B7D, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9B7E, 0x0, 0x0, 0x9B80, 0x0, 0x91EE, 0x0, 0x8946, + 0x8EE7, 0x88C0, 0x0, 0x9176, 0x8AAE, 0x8EB3, 0x0, 0x8D47, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9386, 0x0, 0x8F40, + 0x8AAF, 0x9288, 0x92E8, 0x88B6, 0x8B58, 0x95F3, 0x0, 0x8EC0, + 0x0, 0x0, 0x8B71, 0x90E9, 0x8EBA, 0x9747, 0x9B81, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8B7B, 0x0, + 0x8DC9, 0x0, 0x0, 0x8A51, 0x8983, 0x8FAA, 0x89C6, 0x0, + 0x9B82, 0x9765, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8F68, + 0x0, 0x0, 0x8EE2, 0x9B83, 0x8AF1, 0x93D0, 0x96A7, 0x9B84, + 0x0, 0x9B85, 0x0, 0x0, 0x9578, 0x0, 0x0, 0x0, + 0x9B87, 0x0, 0x8AA6, 0x8BF5, 0x9B86, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8AB0, 0x0, 0x9051, 0x9B8B, 0x8E40, + 0x0, 0x89C7, 0x9B8A, 0x0, 0x9B88, 0x9B8C, 0x9B89, 0x944A, + 0x9ECB, 0x9052, 0x0, 0x9B8D, 0x0, 0x0, 0x97BE, 0x0, + 0x9B8E, 0x0, 0x0, 0x9B90, 0x0, 0x929E, 0x9B8F, 0x0, + 0x90A1, 0x0, 0x8E9B, 0x0, 0x0, 0x0, 0x91CE, 0x8EF5, +}; + +static u16 Ucs5C[] = +{ + 0x0, 0x9595, 0x90EA, 0x0, 0x8ECB, 0x9B91, 0x8FAB, 0x9B92, + 0x9B93, 0x88D1, 0x91B8, 0x9071, 0x0, 0x9B94, 0x93B1, 0x8FAC, + 0x0, 0x8FAD, 0x0, 0x9B95, 0x0, 0x0, 0x90EB, 0x0, + 0x0, 0x0, 0x8FAE, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9B96, 0x0, 0x9B97, 0x0, 0x96DE, 0x0, 0x0, 0x0, + 0x9B98, 0x0, 0x0, 0x0, 0x0, 0x8BC4, 0x0, 0x0, + 0x0, 0x8F41, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9B99, 0x9B9A, 0x8EDA, 0x904B, 0x93F2, 0x9073, 0x94F6, 0x9441, + 0x8BC7, 0x9B9B, 0x0, 0x0, 0x0, 0x8B8F, 0x9B9C, 0x0, + 0x8BFC, 0x0, 0x93CD, 0x89AE, 0x0, 0x8E72, 0x9B9D, 0x9BA0, + 0x9B9F, 0x8BFB, 0x0, 0x9B9E, 0x0, 0x9357, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x91AE, 0x0, + 0x936A, 0x8EC6, 0x0, 0x0, 0x9177, 0x979A, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9BA2, 0x0, 0x9BA3, 0x93D4, + 0x0, 0x8E52, 0x0, 0x0, 0x0, 0x0, 0x9BA5, 0x0, + 0x0, 0x9BA6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9BA7, 0x0, 0x0, 0x0, + 0x8AF2, 0x9BA8, 0x0, 0x0, 0x9BA9, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x89AA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x915A, 0x8AE2, 0x0, 0x9BAB, 0x96A6, 0x0, 0x0, 0x0, + 0x0, 0x91D0, 0x0, 0x8A78, 0x0, 0x0, 0x9BAD, 0x9BAF, + 0x8ADD, 0x0, 0x0, 0x9BAC, 0x9BAE, 0x0, 0x9BB1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9BB0, 0x0, 0x9BB2, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9BB3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x93BB, 0x8BAC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x89E3, 0x9BB4, 0x9BB9, 0x0, 0x0, 0x9BB7, 0x0, 0x95F5, + 0x95F4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9387, 0x0, + 0x0, 0x0, 0x9BB6, 0x8F73, 0x0, 0x9BB5, 0x0, 0x0, +}; + +static u16 Ucs5D[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9092, + 0x0, 0x0, 0x0, 0x9BBA, 0x0, 0x0, 0x8DE8, 0x0, + 0x0, 0x9BC0, 0x0, 0x0, 0x9BC1, 0x9BBB, 0x8A52, 0x9BBC, + 0x9BC5, 0x9BC4, 0x9BC3, 0x9BBF, 0x0, 0x0, 0x0, 0x9BBE, + 0x0, 0x0, 0x9BC2, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x95F6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9BC9, 0x9BC6, 0x0, 0x9BC8, 0x0, + 0x9792, 0x0, 0x9BC7, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9BBD, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9093, 0x0, 0x0, 0x9BCA, 0x0, 0x0, 0x8DB5, + 0x0, 0x0, 0x0, 0x9BCB, 0x0, 0x0, 0x9BCC, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9BCF, 0x0, 0x9BCE, 0x0, 0x0, 0x9BCD, + 0x0, 0x0, 0x0, 0x9388, 0x9BB8, 0x0, 0x0, 0x0, + 0x9BD5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9BD1, 0x0, 0x0, + 0x0, 0x0, 0x9BD0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9BD2, 0x0, 0x9BD3, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9BD6, + 0x0, 0x0, 0x97E4, 0x0, 0x9BD7, 0x9BD4, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9BD8, 0x0, 0x0, 0x8ADE, 0x9BD9, 0x0, 0x0, + 0x0, 0x0, 0x9BDB, 0x9BDA, 0x0, 0x0, 0x9BDC, 0x0, + 0x0, 0x0, 0x0, 0x9BDD, 0x0, 0x90EC, 0x8F42, 0x0, + 0x0, 0x8F84, 0x0, 0x9183, 0x0, 0x8D48, 0x8DB6, 0x8D49, + 0x8B90, 0x0, 0x0, 0x9BDE, 0x0, 0x0, 0x8DB7, 0x0, + 0x0, 0x8CC8, 0x9BDF, 0x96A4, 0x9462, 0x9BE0, 0x0, 0x8D4A, + 0x0, 0x0, 0x0, 0x8AAA, 0x0, 0x9246, 0x8BD0, 0x0, +}; + +static u16 Ucs5E[] = +{ + 0x0, 0x0, 0x8E73, 0x957A, 0x0, 0x0, 0x94BF, 0x0, + 0x0, 0x0, 0x0, 0x9BE1, 0x8AF3, 0x0, 0x0, 0x0, + 0x0, 0x9BE4, 0x0, 0x0, 0x0, 0x0, 0x929F, 0x0, + 0x0, 0x9BE3, 0x9BE2, 0x9BE5, 0x0, 0x92E9, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9083, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8E74, 0x0, 0x90C8, 0x0, 0x91D1, + 0x8B41, 0x0, 0x0, 0x92A0, 0x0, 0x0, 0x9BE6, 0x9BE7, + 0x8FED, 0x0, 0x0, 0x0, 0x0, 0x9658, 0x0, 0x0, + 0x9BEA, 0x0, 0x0, 0x9BE9, 0x9BE8, 0x959D, 0x0, 0x9BF1, + 0x0, 0x0, 0x0, 0x0, 0x9679, 0x0, 0x9BEB, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9BED, 0x968B, 0x0, 0x9BEC, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9BEE, + 0x0, 0x94A6, 0x9BEF, 0x95BC, 0x9BF0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8AB1, 0x95BD, 0x944E, 0x9BF2, 0x9BF3, 0x0, + 0x8D4B, 0x8AB2, 0x9BF4, 0x8CB6, 0x9763, 0x9748, 0x8AF4, 0x9BF6, + 0x0, 0x92A1, 0x0, 0x8D4C, 0x8FAF, 0x0, 0x0, 0x94DD, + 0x0, 0x0, 0x8FB0, 0x0, 0x0, 0x0, 0x0, 0x8F98, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x92EA, 0x95F7, 0x9358, + 0x0, 0x0, 0x8D4D, 0x0, 0x957B, 0x0, 0x0, 0x0, + 0x9BF7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9378, 0x8DC0, + 0x0, 0x0, 0x0, 0x8CC9, 0x0, 0x92EB, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x88C1, 0x8F8E, 0x8D4E, + 0x9766, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9BF8, 0x9BF9, 0x9470, 0x0, 0x0, 0x0, 0x0, + 0x9BFA, 0x97F5, 0x984C, 0x0, 0x0, 0x0, 0x0, 0x9BFC, + 0x9BFB, 0x0, 0x0, 0x8A66, 0x0, 0x0, 0x9C40, 0x0, + 0x0, 0x0, 0x9C43, 0x9C44, 0x0, 0x9C42, 0x0, 0x955F, + 0x8FB1, 0x9C46, 0x9C45, 0x9C41, 0x0, 0x0, 0x0, 0x0, + 0x9C47, 0x9C48, 0x0, 0x0, 0x9C49, 0x0, 0x0, 0x0, + 0x9C4C, 0x9C4A, 0x0, 0x9C4B, 0x9C4D, 0x0, 0x8984, 0x92EC, + 0x9C4E, 0x0, 0x8C9A, 0x89F4, 0x9455, 0x0, 0x9C4F, 0x93F9, +}; + +static u16 Ucs5F[] = +{ + 0x0, 0x95D9, 0x0, 0x9C50, 0x984D, 0x0, 0x0, 0x0, + 0x0, 0x9C51, 0x95BE, 0x9C54, 0x989F, 0x98AF, 0x0, 0x8EAE, + 0x93F3, 0x9C55, 0x0, 0x8B7C, 0x92A2, 0x88F8, 0x9C56, 0x95A4, + 0x8D4F, 0x0, 0x0, 0x926F, 0x0, 0x0, 0x0, 0x92ED, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x96ED, 0x8CB7, 0x8CCA, + 0x0, 0x9C57, 0x0, 0x0, 0x0, 0x9C58, 0x0, 0x9C5E, + 0x0, 0x8EE3, 0x0, 0x0, 0x0, 0x92A3, 0x0, 0x8BAD, + 0x9C59, 0x0, 0x0, 0x0, 0x954A, 0x0, 0x9265, 0x0, + 0x0, 0x9C5A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9C5B, 0x0, 0x8BAE, 0x0, 0x9C5C, 0x0, 0x9C5D, 0x0, + 0x0, 0x9C5F, 0x0, 0x9396, 0x0, 0x0, 0x9C60, 0x9C61, + 0x0, 0x9C62, 0x0, 0x0, 0x9C53, 0x9C52, 0x0, 0x0, + 0x0, 0x9C63, 0x8C60, 0x0, 0x0, 0x0, 0x9546, 0x0, + 0x0, 0x8DCA, 0x9556, 0x92A4, 0x956A, 0x9C64, 0x0, 0x0, + 0x8FB2, 0x8965, 0x0, 0x9C65, 0x0, 0x0, 0x0, 0x9C66, + 0x0, 0x96F0, 0x0, 0x0, 0x94DE, 0x0, 0x0, 0x9C69, + 0x899D, 0x90AA, 0x9C68, 0x9C67, 0x8C61, 0x91D2, 0x0, 0x9C6D, + 0x9C6B, 0x0, 0x9C6A, 0x97A5, 0x8CE3, 0x0, 0x0, 0x0, + 0x8F99, 0x9C6C, 0x936B, 0x8F5D, 0x0, 0x0, 0x0, 0x93BE, + 0x9C70, 0x9C6F, 0x0, 0x0, 0x0, 0x0, 0x9C6E, 0x0, + 0x9C71, 0x8CE4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9C72, 0x959C, 0x8F7A, 0x0, 0x0, 0x9C73, 0x94F7, 0x0, + 0x0, 0x0, 0x0, 0x93BF, 0x92A5, 0x0, 0x0, 0x0, + 0x0, 0x934F, 0x0, 0x0, 0x9C74, 0x8B4A, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9053, 0x0, 0x954B, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8AF5, 0x9445, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9C75, 0x8E75, + 0x9659, 0x965A, 0x0, 0x0, 0x899E, 0x9C7A, 0x0, 0x0, + 0x9289, 0x0, 0x0, 0x0, 0x9C77, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x89F5, 0x0, 0x0, 0x0, 0x0, + 0x9CAB, 0x9C79, 0x0, 0x0, 0x0, 0x944F, 0x0, 0x0, + 0x9C78, 0x0, 0x0, 0x9C76, 0x0, 0x8D9A, 0x0, 0x9C7C, +}; + +static u16 Ucs60[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9C83, 0x9C89, + 0x9C81, 0x0, 0x937B, 0x0, 0x0, 0x9C86, 0x957C, 0x0, + 0x0, 0x9C80, 0x0, 0x9C85, 0x97E5, 0x8E76, 0x0, 0x0, + 0x91D3, 0x9C7D, 0x0, 0x0, 0x0, 0x8B7D, 0x9C88, 0x90AB, + 0x8985, 0x9C82, 0x89F6, 0x9C87, 0x0, 0x0, 0x0, 0x8BAF, + 0x0, 0x9C84, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9C8A, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9C8C, 0x9C96, 0x9C94, 0x0, 0x0, 0x9C91, 0x0, + 0x0, 0x0, 0x9C90, 0x97F6, 0x0, 0x9C92, 0x0, 0x0, + 0x8BB0, 0x0, 0x8D50, 0x0, 0x0, 0x8F9A, 0x0, 0x0, + 0x0, 0x9C99, 0x9C8B, 0x0, 0x0, 0x0, 0x0, 0x9C8F, + 0x9C7E, 0x0, 0x89F8, 0x9C93, 0x9C95, 0x9270, 0x0, 0x0, + 0x8DA6, 0x89B6, 0x9C8D, 0x9C98, 0x9C97, 0x8BB1, 0x0, 0x91A7, + 0x8A86, 0x0, 0x0, 0x0, 0x0, 0x8C62, 0x0, 0x9C8E, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9C9A, 0x0, 0x9C9D, 0x9C9F, 0x0, 0x0, 0x0, + 0x0, 0x8EBB, 0x0, 0x9CA5, 0x92EE, 0x9C9B, 0x0, 0x0, + 0x0, 0x0, 0x9CA3, 0x0, 0x89F7, 0x0, 0x9CA1, 0x9CA2, + 0x0, 0x0, 0x9C9E, 0x9CA0, 0x0, 0x0, 0x0, 0x8CE5, + 0x9749, 0x0, 0x0, 0x8AB3, 0x0, 0x0, 0x8978, 0x9CA4, + 0x0, 0x9459, 0x88AB, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x94DF, 0x9C7B, 0x9CAA, 0x9CAE, 0x96E3, 0x0, + 0x9CA7, 0x0, 0x0, 0x0, 0x9389, 0x9CAC, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8FEE, 0x9CAD, 0x93D5, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9866, 0x0, 0x9CA9, 0x0, 0x0, 0x0, 0x0, + 0x9CAF, 0x0, 0x8D9B, 0x0, 0x90C9, 0x0, 0x0, 0x88D2, + 0x9CA8, 0x9CA6, 0x0, 0x9179, 0x0, 0x0, 0x0, 0x9C9C, + 0x8E53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x91C4, 0x9CBB, 0x0, 0x917A, 0x9CB6, 0x0, 0x9CB3, 0x9CB4, + 0x0, 0x8EE4, 0x9CB7, 0x9CBA, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs61[] = +{ + 0x9CB5, 0x8F44, 0x0, 0x9CB8, 0x0, 0x0, 0x9CB2, 0x0, + 0x96FA, 0x96F9, 0x0, 0x0, 0x0, 0x9CBC, 0x9CBD, 0x88D3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9CB1, 0x0, 0x0, + 0x0, 0x0, 0x8BF0, 0x88A4, 0x0, 0x0, 0x0, 0x8AB4, + 0x0, 0x9CB9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9CC1, + 0x9CC0, 0x0, 0x0, 0x0, 0x9CC5, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9CC6, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9CC4, 0x9CC7, 0x9CBF, 0x9CC3, + 0x0, 0x0, 0x9CC8, 0x0, 0x9CC9, 0x0, 0x0, 0x9CBE, + 0x8E9C, 0x0, 0x9CC2, 0x91D4, 0x8D51, 0x9CB0, 0x9054, 0x0, + 0x0, 0x0, 0x0, 0x9CD6, 0x0, 0x95E7, 0x0, 0x0, + 0x9CCC, 0x9CCD, 0x9CCE, 0x0, 0x0, 0x9CD5, 0x0, 0x9CD4, + 0x0, 0x0, 0x969D, 0x8AB5, 0x0, 0x9CD2, 0x0, 0x8C64, + 0x8A53, 0x0, 0x0, 0x9CCF, 0x0, 0x0, 0x97B6, 0x9CD1, + 0x88D4, 0x9CD3, 0x0, 0x9CCA, 0x9CD0, 0x9CD7, 0x8C63, 0x9CCB, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x977C, 0x0, + 0x0, 0x0, 0x974A, 0x0, 0x0, 0x0, 0x0, 0x9CDA, + 0x0, 0x0, 0x9CDE, 0x0, 0x0, 0x0, 0x919E, 0x0, + 0x97F7, 0x9CDF, 0x0, 0x0, 0x9CDC, 0x0, 0x9CD9, 0x0, + 0x0, 0x9CD8, 0x9CDD, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x95AE, 0x0, 0x0, 0x93B2, + 0x0, 0x8C65, 0x0, 0x9CE0, 0x9CDB, 0x0, 0x9CE1, 0x0, + 0x0, 0x0, 0x8C9B, 0x0, 0x0, 0x0, 0x89AF, 0x0, + 0x0, 0x0, 0x9CE9, 0x0, 0x0, 0x0, 0x8AB6, 0x0, + 0x0, 0x0, 0x0, 0x9CE7, 0x0, 0x0, 0x9CE8, 0x8DA7, + 0x9CE6, 0x9CE4, 0x9CE3, 0x9CEA, 0x9CE2, 0x9CEC, 0x0, 0x0, + 0x89F9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9CEE, 0x0, 0x0, 0x9CED, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x92A6, 0x0, 0x9CF1, 0x0, 0x9CEF, 0x9CE5, + 0x8C9C, 0x0, 0x9CF0, 0x0, 0x9CF4, 0x9CF3, 0x9CF5, 0x9CF2, +}; + +static u16 Ucs62[] = +{ + 0x9CF6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9CF7, 0x9CF8, 0x95E8, 0x0, 0x9CFA, 0x9CF9, 0x8F5E, 0x0, + 0x90AC, 0x89E4, 0x89FA, 0x0, 0x9CFB, 0x0, 0x88BD, 0x0, + 0x0, 0x0, 0x90CA, 0x9CFC, 0x0, 0xE6C1, 0x9D40, 0x8C81, + 0x0, 0x9D41, 0x0, 0x0, 0x0, 0x0, 0x90ED, 0x0, + 0x0, 0x0, 0x9D42, 0x0, 0x0, 0x0, 0x9D43, 0x8B59, + 0x9D44, 0x0, 0x9D45, 0x9D46, 0x91D5, 0x0, 0x0, 0x0, + 0x8CCB, 0x0, 0x0, 0x96DF, 0x0, 0x0, 0x0, 0x965B, + 0x8F8A, 0x9D47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x90EE, + 0xE7BB, 0x94E0, 0x0, 0x8EE8, 0x0, 0x8DCB, 0x9D48, 0x0, + 0x0, 0x0, 0x0, 0x91C5, 0x0, 0x95A5, 0x0, 0x0, + 0x91EF, 0x0, 0x0, 0x9D4B, 0x0, 0x0, 0x9D49, 0x0, + 0x9D4C, 0x0, 0x0, 0x9D4A, 0x0, 0x0, 0x0, 0x0, + 0x9D4D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x95AF, 0x0, + 0x0, 0x88B5, 0x0, 0x0, 0x0, 0x0, 0x957D, 0x0, + 0x0, 0x94E1, 0x0, 0x0, 0x9D4E, 0x0, 0x9D51, 0x8FB3, + 0x8B5A, 0x0, 0x9D4F, 0x9D56, 0x8FB4, 0x0, 0x0, 0x0, + 0x0, 0x9D50, 0x9463, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x977D, 0x9D52, 0x9D53, 0x9D57, 0x938A, 0x9D54, 0x8D52, + 0x90DC, 0x0, 0x0, 0x9D65, 0x94B2, 0x0, 0x91F0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x94E2, 0x9DAB, 0x0, 0x0, 0x0, + 0x0, 0x95F8, 0x0, 0x0, 0x0, 0x92EF, 0x0, 0x0, + 0x0, 0x9695, 0x0, 0x9D5A, 0x899F, 0x928A, 0x0, 0x0, + 0x0, 0x0, 0x9D63, 0x0, 0x0, 0x9253, 0x9D5D, 0x9D64, + 0x9D5F, 0x9D66, 0x9D62, 0x0, 0x9D61, 0x948F, 0x0, 0x9D5B, + 0x89FB, 0x9D59, 0x8B91, 0x91F1, 0x9D55, 0x0, 0x0, 0x9D58, + 0x8D53, 0x90D9, 0x0, 0x8FB5, 0x9D60, 0x9471, 0x0, 0x0, + 0x8B92, 0x8A67, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8A87, 0x9040, 0x9D68, 0x9D6D, + 0x0, 0x9D69, 0x0, 0x8C9D, 0x0, 0x9D6E, 0x8E41, 0x8D89, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8F45, 0x9D5C, +}; + +static u16 Ucs63[] = +{ + 0x0, 0x8E9D, 0x9D6B, 0x0, 0x0, 0x0, 0x0, 0x8E77, + 0x9D6C, 0x88C2, 0x0, 0x0, 0x9D67, 0x0, 0x0, 0x0, + 0x0, 0x92A7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8B93, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8BB2, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9D6A, + 0x88A5, 0x0, 0x0, 0x8DC1, 0x0, 0x0, 0x0, 0x9055, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x92F0, 0x0, 0x0, 0x94D2, 0x9D70, 0x917D, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x91A8, 0x0, 0x0, 0x8E4A, 0x9D71, 0x0, 0x9D73, + 0x9D6F, 0x0, 0x0, 0x0, 0x0, 0x95DF, 0x0, 0x92BB, + 0x0, 0x0, 0x0, 0x0, 0x917B, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x95F9, + 0x8ECC, 0x9D80, 0x0, 0x9D7E, 0x0, 0x0, 0x9098, 0x0, + 0x0, 0x0, 0x8C9E, 0x0, 0x0, 0x0, 0x9D78, 0x8FB7, + 0x0, 0x0, 0x93E6, 0x9450, 0x0, 0x0, 0x0, 0x0, + 0x9D76, 0x0, 0x0, 0x917C, 0x0, 0x0, 0x0, 0x0, + 0x8EF6, 0x9D7B, 0x0, 0x0, 0x8FB6, 0x0, 0x9D75, 0x9D7A, + 0x0, 0x0, 0x9472, 0x0, 0x0, 0x0, 0x9D74, 0x0, + 0x8C40, 0x0, 0x0, 0x8A7C, 0x0, 0x0, 0x0, 0x9D7C, + 0x97A9, 0x8DCC, 0x9254, 0x9D79, 0x0, 0x90DA, 0x0, 0x8D54, + 0x9084, 0x8986, 0x915B, 0x9D77, 0x8B64, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8C66, 0x0, 0x92CD, 0x9D7D, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x917E, 0x0, 0x0, 0x9D81, 0x0, + 0x9D83, 0x0, 0x0, 0x91B5, 0x9D89, 0x0, 0x9D84, 0x0, + 0x0, 0x9D86, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9560, + 0x92F1, 0x0, 0x9D87, 0x0, 0x0, 0x0, 0x974B, 0x0, + 0x0, 0x0, 0x9767, 0x8AB7, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x88AC, 0x0, 0x9D85, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9D82, 0x0, 0x0, 0x0, 0x0, 0x8AF6, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8987, 0x0, 0x9D88, 0x0, + 0x0, 0x0, 0x9768, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs64[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9D8C, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x91B9, 0x0, 0x9D93, + 0x0, 0x0, 0x0, 0x9D8D, 0x0, 0x0, 0x9D8A, 0x9D91, + 0x0, 0x0, 0x0, 0x0, 0x9D72, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9D8E, 0x0, + 0x9D92, 0x0, 0x0, 0x0, 0x94C0, 0x938B, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9D8B, 0x0, 0x9D8F, 0x0, + 0x0, 0x0, 0x8C67, 0x0, 0x0, 0x0, 0x8DEF, 0x0, + 0x0, 0x0, 0x90DB, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9D97, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9345, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9D94, + 0x0, 0x9680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9D95, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9D96, 0x0, + 0x96CC, 0x0, 0x90A0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8C82, 0x0, 0x0, 0x0, 0x0, + 0x9D9D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8E54, 0x9D9A, 0x0, 0x9D99, 0x0, 0x0, + 0x0, 0x0, 0x9451, 0x0, 0x0, 0x0, 0x93B3, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9350, 0x9D9B, 0x0, 0x0, + 0x0, 0x9D9C, 0x0, 0x958F, 0x0, 0x9464, 0x8E42, 0x0, + 0x90EF, 0x0, 0x966F, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8A68, 0x0, 0x9DA3, 0x9D9E, 0x0, 0x0, 0x0, + 0x0, 0x9769, 0x9DA5, 0x0, 0x0, 0x9DA1, 0x0, 0x9DA2, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9180, 0x0, 0x0, + 0x0, 0x0, 0x9DA0, 0x0, 0x9D5E, 0x0, 0x0, 0x0, + 0x9DA4, 0x0, 0x9D9F, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9DA9, 0x9DAA, 0x9346, 0x9DAC, 0x0, 0x0, 0x8E43, 0x9DA7, + 0x0, 0x0, 0x0, 0x0, 0x8B5B, 0x0, 0x0, 0x9DAD, + 0x0, 0x9DA6, 0x9DB1, 0x0, 0x9DB0, 0x0, 0x9DAF, 0x0, + 0x0, 0x0, 0x9DB2, 0x0, 0x0, 0x9DB4, 0x8FEF, 0x0, +}; + +static u16 Ucs65[] = +{ + 0x9DB3, 0x0, 0x0, 0x0, 0x0, 0x9DB7, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9DB5, 0x0, 0x0, 0x0, 0x9DB6, 0x9D90, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9DB9, 0x9DB8, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9D98, 0x9DBA, 0x9DAE, 0x0, 0x0, 0x8E78, + 0x0, 0x0, 0x0, 0x0, 0x9DBB, 0x9DBC, 0x9DBE, 0x9DBD, + 0x9DBF, 0x89FC, 0x0, 0x8D55, 0x0, 0x0, 0x95FA, 0x90AD, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8CCC, 0x0, 0x0, + 0x9DC1, 0x0, 0x0, 0x0, 0x0, 0x9DC4, 0x0, 0x9571, + 0x0, 0x8B7E, 0x0, 0x0, 0x0, 0x9DC3, 0x9DC2, 0x9473, + 0x9DC5, 0x8BB3, 0x0, 0x0, 0x0, 0x9DC7, 0x9DC6, 0x0, + 0x0, 0x0, 0x8AB8, 0x8E55, 0x0, 0x0, 0x93D6, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8C68, 0x0, 0x0, 0x0, + 0x9094, 0x0, 0x9DC8, 0x0, 0x90AE, 0x9347, 0x0, 0x957E, + 0x9DC9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9DCA, 0x9DCB, 0x0, 0x0, 0x0, 0x95B6, + 0x9B7C, 0x90C4, 0x0, 0x0, 0x956B, 0x0, 0x8DD6, 0x0, + 0x94E3, 0x94C1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x936C, + 0x0, 0x97BF, 0x0, 0x9DCD, 0x8ECE, 0x0, 0x0, 0x9DCE, + 0x0, 0x88B4, 0x0, 0x0, 0x8BD2, 0x90CB, 0x0, 0x9580, + 0x0, 0x0, 0x0, 0x9DCF, 0x8E61, 0x9266, 0x0, 0x8E7A, + 0x9056, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9DD0, + 0x0, 0x95FB, 0x0, 0x0, 0x8997, 0x8E7B, 0x0, 0x0, + 0x0, 0x9DD3, 0x0, 0x9DD1, 0x9DD4, 0x97B7, 0x9DD2, 0x0, + 0x0, 0x0, 0x0, 0x90F9, 0x9DD5, 0x0, 0x0, 0x91B0, + 0x0, 0x0, 0x9DD6, 0x0, 0x0, 0x0, 0x0, 0x8AF8, + 0x0, 0x9DD8, 0x0, 0x9DD7, 0x0, 0x0, 0x0, 0x0, + 0x9DD9, 0x9DDA, 0x8AF9, 0x0, 0x0, 0x93FA, 0x9255, 0x8B8C, + 0x8E7C, 0x9181, 0x0, 0x0, 0x8F7B, 0x88AE, 0x0, 0x0, + 0x0, 0x9DDB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x89A0, 0x9DDF, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs66[] = +{ + 0x0, 0x0, 0x8D56, 0x9DDE, 0x0, 0x0, 0x8DA9, 0x8FB8, + 0x0, 0x0, 0x9DDD, 0x0, 0x8FB9, 0x0, 0x96BE, 0x8DA8, + 0x0, 0x0, 0x0, 0x88D5, 0x90CC, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9DE4, 0x0, 0x0, 0x90AF, + 0x8966, 0x0, 0x0, 0x0, 0x0, 0x8F74, 0x0, 0x9686, + 0x8DF0, 0x0, 0x0, 0x0, 0x0, 0x8FBA, 0x0, 0x90A5, + 0x0, 0x0, 0x0, 0x0, 0x9DE3, 0x9DE1, 0x9DE2, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x928B, 0x0, 0x0, 0x9E45, + 0x0, 0x9DE8, 0x8E9E, 0x8D57, 0x9DE6, 0x0, 0x0, 0x0, + 0x0, 0x9DE7, 0x0, 0x9057, 0x0, 0x0, 0x0, 0x9DE5, + 0x0, 0x0, 0x8E4E, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9DEA, 0x9DE9, 0x9DEE, + 0x0, 0x0, 0x9DEF, 0x0, 0x9DEB, 0x0, 0x8A41, 0x9DEC, + 0x9DED, 0x94D3, 0x0, 0x0, 0x0, 0x0, 0x9581, 0x8C69, + 0x9DF0, 0x0, 0x0, 0x0, 0x90B0, 0x0, 0x8FBB, 0x0, + 0x0, 0x0, 0x9271, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8BC5, 0x0, 0x9DF1, 0x9DF5, 0x0, 0x0, 0x89C9, + 0x9DF2, 0x9DF4, 0x0, 0x0, 0x0, 0x0, 0x9DF3, 0x0, + 0x0, 0x8F8B, 0x0, 0x0, 0x0, 0x0, 0x9267, 0x88C3, + 0x9DF6, 0x0, 0x0, 0x0, 0x0, 0x9DF7, 0x0, 0x0, + 0x0, 0x0, 0x92A8, 0x0, 0x0, 0x0, 0x97EF, 0x0, + 0x0, 0x0, 0x0, 0x8E62, 0x0, 0x0, 0x95E9, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x965C, 0x0, 0x0, 0x0, + 0x9E41, 0x9DF9, 0x0, 0x0, 0x9DFC, 0x0, 0x9DFB, 0x0, + 0x0, 0x9DF8, 0x0, 0x0, 0x9E40, 0x0, 0x0, 0x93DC, + 0x0, 0x9DFA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9E42, 0x0, + 0x0, 0x8F8C, 0x9E43, 0x0, 0x976A, 0x9498, 0x0, 0x0, + 0x9E44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9E46, 0x0, + 0x0, 0x9E47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9E48, 0x0, 0x8BC8, 0x8967, 0x8D58, 0x9E49, 0x0, 0x9E4A, + 0x8F91, 0x9182, 0x0, 0x0, 0x99D6, 0x915D, 0x915C, 0x91D6, +}; + +static u16 Ucs67[] = +{ + 0x8DC5, 0x0, 0x0, 0x98F0, 0x0, 0x0, 0x0, 0x0, + 0x8C8E, 0x974C, 0x0, 0x95FC, 0x0, 0x959E, 0x0, 0x9E4B, + 0x0, 0x0, 0x0, 0x0, 0x8DF1, 0x92BD, 0x9E4C, 0x984E, + 0x0, 0x0, 0x0, 0x965D, 0x0, 0x92A9, 0x9E4D, 0x8AFA, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9E4E, 0x9E4F, + 0x96D8, 0x0, 0x96A2, 0x9696, 0x967B, 0x8E44, 0x9E51, 0x0, + 0x0, 0x8EE9, 0x0, 0x0, 0x9670, 0x0, 0x9E53, 0x9E56, + 0x9E55, 0x0, 0x8AF7, 0x0, 0x0, 0x8B80, 0x0, 0x9E52, + 0x0, 0x9E54, 0x0, 0x0, 0x0, 0x0, 0x9E57, 0x0, + 0x0, 0x9099, 0x0, 0x0, 0x0, 0x0, 0x979B, 0x88C7, + 0x8DDE, 0x91BA, 0x0, 0x8EDB, 0x0, 0x0, 0x8FF1, 0x0, + 0x0, 0x9E5A, 0x0, 0x0, 0x936D, 0x0, 0x9E58, 0x91A9, + 0x9E59, 0x8FF0, 0x96DB, 0x9E5B, 0x9E5C, 0x9788, 0x0, 0x0, + 0x0, 0x0, 0x9E61, 0x0, 0x0, 0x8D59, 0x0, 0x9474, + 0x9E5E, 0x938C, 0x9DDC, 0x9DE0, 0x0, 0x8B6E, 0x0, 0x9466, + 0x0, 0x0, 0x0, 0x0, 0x9E60, 0x0, 0x8FBC, 0x94C2, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9E66, 0x0, 0x94F8, + 0x0, 0x9E5D, 0x0, 0x9E63, 0x9E62, 0x0, 0x0, 0x0, + 0x90CD, 0x0, 0x0, 0x0, 0x0, 0x968D, 0x0, 0x97D1, + 0x0, 0x0, 0x9687, 0x0, 0x89CA, 0x8E7D, 0x0, 0x0, + 0x9867, 0x9E65, 0x9095, 0x0, 0x0, 0x0, 0x9E64, 0x0, + 0x0, 0x9E5F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8CCD, + 0x0, 0x0, 0x0, 0x9E6B, 0x9E69, 0x0, 0x89CB, 0x9E67, + 0x9E6D, 0x9E73, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x91C6, 0x0, 0x0, 0x95BF, 0x0, 0x9E75, 0x0, + 0x0, 0x0, 0x9541, 0x0, 0x0, 0x0, 0x9E74, 0x9490, + 0x965E, 0x8AB9, 0x0, 0x90F5, 0x8F5F, 0x0, 0x0, 0x0, + 0x92D1, 0x0, 0x974D, 0x0, 0x0, 0x9E70, 0x9E6F, 0x0, + 0x0, 0x0, 0x9E71, 0x0, 0x9E6E, 0x0, 0x0, 0x9E76, + 0x0, 0x9E6C, 0x0, 0x0, 0x9E6A, 0x0, 0x9E72, 0x9E68, + 0x0, 0x928C, 0x0, 0x96F6, 0x8EC4, 0x8DF2, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8DB8, 0x0, 0x0, 0x968F, 0x8A60, +}; + +static u16 Ucs68[] = +{ + 0x0, 0x0, 0x92CC, 0x93C8, 0x8968, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x90F0, 0x0, 0x0, 0x90B2, 0x8C49, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9E78, 0x0, + 0x0, 0x8D5A, 0x8A9C, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9E7A, 0x8A94, 0x9E81, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9E7D, 0x0, 0x90F1, 0x0, 0x0, 0x0, + 0x8A6A, 0x8DAA, 0x0, 0x0, 0x8A69, 0x8DCD, 0x0, 0x0, + 0x9E7B, 0x8C85, 0x8C6A, 0x938D, 0x0, 0x0, 0x9E79, 0x0, + 0x88C4, 0x0, 0x0, 0x0, 0x0, 0x9E7C, 0x9E7E, 0x0, + 0x8BCB, 0x8C4B, 0x0, 0x8ABA, 0x8B6A, 0x0, 0x0, 0x0, + 0x0, 0x9E82, 0x0, 0x0, 0x8DF7, 0x9691, 0x0, 0x8E56, + 0x0, 0x0, 0x0, 0x9E83, 0x0, 0x0, 0x0, 0x954F, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9E8F, 0x0, 0x89B1, 0x9E84, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9E95, 0x9E85, + 0x0, 0x97C0, 0x0, 0x9E8C, 0x0, 0x947E, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9E94, 0x0, 0x9E87, + 0x0, 0x0, 0x0, 0x88B2, 0x9E89, 0x0, 0x0, 0x8D5B, + 0x0, 0x0, 0x0, 0x9E8B, 0x0, 0x9E8A, 0x0, 0x9E86, + 0x9E91, 0x0, 0x8FBD, 0x0, 0x0, 0x0, 0x9AEB, 0x8CE6, + 0x979C, 0x0, 0x0, 0x0, 0x0, 0x9E88, 0x0, 0x92F2, + 0x8A42, 0x8DAB, 0x0, 0x9E80, 0x0, 0x9E90, 0x8A81, 0x0, + 0x0, 0x9E8E, 0x9E92, 0x0, 0x938E, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8AFC, 0x0, 0x9EB0, 0x0, + 0x0, 0x96C7, 0x9E97, 0x8AFB, 0x0, 0x9E9E, 0x0, 0x0, + 0x0, 0x0, 0x965F, 0x0, 0x9E9F, 0x9EA1, 0x0, 0x9EA5, + 0x9E99, 0x0, 0x9249, 0x0, 0x0, 0x0, 0x0, 0x938F, + 0x9EA9, 0x9E9C, 0x0, 0x9EA6, 0x0, 0x0, 0x0, 0x9EA0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9058, 0x9EAA, + 0x0, 0x0, 0x90B1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9EA8, 0x8ABB, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs69[] = +{ + 0x986F, 0x9E96, 0x0, 0x0, 0x9EA4, 0x88D6, 0x0, 0x0, + 0x9E98, 0x0, 0x0, 0x96B8, 0x9E9D, 0x9041, 0x92C5, 0x9E93, + 0x0, 0x0, 0x9EA3, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x909A, 0x9EAD, 0x8A91, 0x8C9F, 0x0, 0x0, 0x0, + 0x0, 0x9EAF, 0x9E9A, 0x9EAE, 0x0, 0x9EA7, 0x9E9B, 0x0, + 0x9EAB, 0x0, 0x9EAC, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9EBD, 0x0, 0x0, 0x0, 0x93CC, 0x0, 0x9EA2, 0x0, + 0x0, 0x9EB9, 0x0, 0x0, 0x0, 0x9EBB, 0x0, 0x92D6, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x976B, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9596, 0x9EB6, 0x91C8, 0x0, 0x0, + 0x0, 0x9EBC, 0x915E, 0x0, 0x9EB3, 0x9EC0, 0x9EBF, 0x0, + 0x93ED, 0x9EBE, 0x93E8, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9EC2, 0x9EB5, 0x0, 0x8BC6, 0x9EB8, 0x8F7C, + 0x0, 0x0, 0x0, 0x9480, 0x9EBA, 0x8BC9, 0x0, 0x9EB2, + 0x9EB4, 0x9EB1, 0x0, 0x0, 0x984F, 0x8A79, 0x9EB7, 0x0, + 0x0, 0x9EC1, 0x8A54, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8DE5, 0x0, 0x0, 0x0, 0x897C, 0x0, + 0x0, 0x9ED2, 0x0, 0x0, 0x9850, 0x9ED5, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9059, 0x9ED4, 0x0, 0x0, 0x0, + 0x9ED3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9ED0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9EC4, 0x0, + 0x0, 0x9EE1, 0x9EC3, 0x0, 0x9ED6, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9ECE, 0x0, 0x0, 0x9EC9, 0x9EC6, + 0x0, 0x9EC7, 0x0, 0x9ECF, 0x0, 0x0, 0x0, 0xEAA0, + 0x0, 0x0, 0x9ECC, 0x8D5C, 0x92C6, 0x9184, 0x9ECA, 0x0, + 0x9EC5, 0x0, 0x0, 0x9EC8, 0x0, 0x0, 0x0, 0x0, + 0x976C, 0x968A, 0x0, 0x0, 0x0, 0x9ECD, 0x9ED7, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9EDF, + 0x9ED8, 0x0, 0x0, 0x9EE5, 0x0, 0x9EE3, 0x0, 0x0, + 0x0, 0x0, 0x9EDE, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9EDD, 0x0, 0x92CE, 0x0, 0x9185, 0x0, 0x9EDB, +}; + +static u16 Ucs6A[] = +{ + 0x0, 0x0, 0x9ED9, 0x0, 0x0, 0x9EE0, 0x0, 0x0, + 0x0, 0x0, 0x9EE6, 0x94F3, 0x9EEC, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9EE7, 0x9EEA, 0x9EE4, 0x0, 0x0, 0x9294, + 0x0, 0x9557, 0x0, 0x9EDA, 0x0, 0x0, 0x9EE2, 0x8FBE, + 0x0, 0x96CD, 0x9EF6, 0x9EE9, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8CA0, 0x89A1, 0x8A7E, 0x0, 0x0, 0x9ED1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8FBF, 0x9EEE, 0x0, + 0x9EF5, 0x8EF7, 0x8A92, 0x0, 0x0, 0x924D, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9EEB, 0x0, 0x0, 0x9EF0, + 0x9EF4, 0x0, 0x0, 0x8BB4, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8B6B, 0x9EF2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8B40, + 0x0, 0x93C9, 0x9EF1, 0x0, 0x0, 0x0, 0x9EF3, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9EED, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9EEF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8A80, + 0x9268, 0x0, 0x0, 0x0, 0x9EFA, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9EF8, 0x8CE7, 0x0, + 0x9EF7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9F40, + 0x0, 0x0, 0x0, 0x0, 0x9E77, 0x0, 0x0, 0x0, + 0x9EF9, 0x0, 0x9EFB, 0x9EFC, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9F4B, 0x0, 0x9F47, 0x0, 0x9E8D, 0x0, + 0x0, 0x0, 0x0, 0x9F46, 0x0, 0x0, 0x0, 0x0, + 0x9F45, 0x0, 0x0, 0x9F42, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9EE8, 0x9F44, 0x9F43, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9F49, 0x0, 0x9845, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9F4C, 0x8BF9, 0x0, 0x0, 0x9F48, 0x9F4A, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x94A5, 0x0, 0x9F4D, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9F51, 0x9F4E, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs6B[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x9793, 0x9F4F, 0x0, 0x0, + 0x0, 0x0, 0x9EDC, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9F52, 0x0, 0x0, 0x0, 0x9F53, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8954, 0x0, 0x9F55, + 0x8C87, 0x8E9F, 0x0, 0x8BD3, 0x0, 0x0, 0x0, 0x89A2, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x977E, 0x0, 0x0, 0x0, 0x0, 0x9F57, + 0x9F56, 0x9F59, 0x8B5C, 0x0, 0x0, 0x8BD4, 0x8ABC, 0x0, + 0x0, 0x0, 0x0, 0x9F5C, 0x0, 0x0, 0x0, 0x9F5B, + 0x0, 0x9F5D, 0x0, 0x0, 0x89CC, 0x0, 0x9256, 0x0, + 0x9F5E, 0x0, 0x0, 0x8ABD, 0x9F60, 0x0, 0x0, 0x0, + 0x0, 0x9F5F, 0x0, 0x9F61, 0x0, 0x0, 0x0, 0x9F62, + 0x0, 0x9F63, 0x8E7E, 0x90B3, 0x8D9F, 0x0, 0x9590, 0x0, + 0x0, 0x95E0, 0x9863, 0x0, 0x0, 0x0, 0x0, 0x8E95, + 0x0, 0x0, 0x0, 0x8DCE, 0x97F0, 0x0, 0x0, 0x0, + 0x9F64, 0x9F65, 0x0, 0x8E80, 0x0, 0x0, 0x0, 0x9F66, + 0x9F67, 0x0, 0x0, 0x9F69, 0x9F68, 0x0, 0x9677, 0x0, + 0x0, 0x8F7D, 0x8EEA, 0x8E63, 0x0, 0x9F6A, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9F6C, 0x9042, 0x0, + 0x9F6B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9F6D, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9F6E, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9F6F, 0x9F70, 0x0, 0x0, 0x0, 0x9F71, + 0x0, 0x9F73, 0x9F72, 0x9F74, 0x89A3, 0x9269, 0x0, 0x9F75, + 0x0, 0x0, 0x8E45, 0x8A6B, 0x9F76, 0x0, 0x0, 0x9361, + 0x9ACA, 0x0, 0x0, 0x0, 0x0, 0x8B42, 0x9F77, 0x0, + 0x0, 0x0, 0x0, 0x9F78, 0x0, 0x95EA, 0x9688, 0x0, + 0x0, 0x0, 0x93C5, 0x9F79, 0x94E4, 0x0, 0x0, 0x0, + 0x94F9, 0x0, 0x0, 0x96D1, 0x0, 0x0, 0x0, 0x9F7A, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9F7C, 0x9F7B, 0x0, 0x0, 0x9F7E, + 0x0, 0x0, 0x0, 0x9F7D, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs6C[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9F81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8E81, + 0x0, 0x96AF, 0x0, 0x9F82, 0x9F83, 0x0, 0x0, 0x8B43, + 0x0, 0x0, 0x0, 0x9F84, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9F86, 0x9F85, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9085, 0x0, 0x0, 0x9558, + 0x8969, 0x0, 0x0, 0x0, 0x0, 0x0, 0x94C3, 0x0, + 0x92F3, 0x8F60, 0x8B81, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x94C4, 0x0, + 0x8EAC, 0x0, 0x0, 0x0, 0x0, 0x9F88, 0x0, 0x8ABE, + 0x0, 0x0, 0x8998, 0x0, 0x0, 0x93F0, 0x9F87, 0x8D5D, + 0x9272, 0x0, 0x9F89, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9F91, 0x0, 0x9F8A, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x91BF, 0x0, 0x8B82, 0x9F92, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8C88, 0x0, 0x0, 0x8B44, 0x9F90, 0x0, + 0x0, 0x9F8E, 0x9F8B, 0x9780, 0x0, 0x0, 0x0, 0x0, + 0x92BE, 0x0, 0x0, 0x0, 0x93D7, 0x9F8C, 0x0, 0x0, + 0x9F94, 0x0, 0x9F93, 0x8C42, 0x0, 0x0, 0x89AB, 0x0, + 0x0, 0x8DB9, 0x9F8D, 0x9F8F, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9676, 0x91F2, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9697, 0x0, 0x0, 0x9F9C, 0x0, + 0x0, 0x9F9D, 0x0, 0x89CD, 0x0, 0x0, 0x0, 0x0, + 0x95A6, 0x96FB, 0x9F9F, 0x8EA1, 0x8FC0, 0x9F98, 0x9F9E, 0x8988, + 0x0, 0x8BB5, 0x0, 0x0, 0x9F95, 0x9F9A, 0x0, 0x0, + 0x0, 0x90F2, 0x9491, 0x0, 0x94E5, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9F97, 0x0, 0x9640, 0x0, 0x9F99, + 0x0, 0x9FA2, 0x0, 0x9FA0, 0x0, 0x9F9B, 0x0, 0x0, + 0x0, 0x9641, 0x9467, 0x8B83, 0x0, 0x9344, 0x0, 0x0, + 0x928D, 0x0, 0x9FA3, 0x0, 0x0, 0x0, 0x0, 0x9FA1, + 0x91D7, 0x9F96, 0x0, 0x896A, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs6D[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x976D, 0x9FAE, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9FAD, 0x0, 0x0, 0x0, 0x0, 0x90F4, + 0x0, 0x9FAA, 0x0, 0x978C, 0x0, 0x0, 0x93B4, 0x9FA4, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x92C3, 0x0, 0x0, + 0x0, 0x896B, 0x8D5E, 0x9FA7, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8F46, 0x9FAC, 0x0, 0x9FAB, 0x9FA6, 0x0, + 0x9FA9, 0x0, 0x0, 0x8A88, 0x0, 0x9FA8, 0x9468, 0x0, + 0x0, 0x97AC, 0x0, 0x0, 0x8FF2, 0x90F3, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9FB4, 0x9FB2, 0x0, 0x956C, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9FAF, 0x9FB1, 0x0, 0x8959, 0x0, + 0x0, 0x8D5F, 0x9851, 0x0, 0x8A5C, 0x0, 0x9582, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9781, 0x0, 0x0, 0x8A43, + 0x905A, 0x9FB3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9FB8, 0x0, 0x0, + 0x8FC1, 0x0, 0x0, 0x0, 0x974F, 0x0, 0x9FB5, 0x0, + 0x0, 0x0, 0x0, 0x9FB0, 0x0, 0x9FB6, 0x0, 0x0, + 0x0, 0x97DC, 0x0, 0x9393, 0x93C0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8A55, + 0x0, 0x0, 0x8974, 0x0, 0x0, 0x9FBC, 0x0, 0x0, + 0x9FBF, 0x0, 0x0, 0x0, 0x97C1, 0x0, 0x0, 0x0, + 0x9784, 0x0, 0x0, 0x0, 0x0, 0x9FC6, 0x9FC0, 0x9FBD, + 0x0, 0x0, 0x0, 0x97D2, 0x9FC3, 0x0, 0x0, 0x0, + 0x0, 0x8F69, 0x9FC5, 0x0, 0x0, 0x9FCA, 0x0, 0x0, + 0x9391, 0x9FC8, 0x0, 0x0, 0x0, 0x0, 0x9FC2, 0x0, + 0x0, 0x9257, 0x0, 0x0, 0x9FC9, 0x0, 0x9FBE, 0x0, + 0x9FC4, 0x0, 0x9FCB, 0x88FA, 0x9FC1, 0x0, 0x9FCC, 0x0, + 0x0, 0x905B, 0x0, 0x8F7E, 0x0, 0x95A3, 0x0, 0x8DAC, + 0x0, 0x9FB9, 0x9FC7, 0x9359, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs6E[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x90B4, 0x0, 0x8A89, + 0x8DCF, 0x8FC2, 0x9FBB, 0x8F61, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8C6B, 0x0, 0x9FBA, 0x0, 0x0, + 0x0, 0x9FD0, 0x8F8D, 0x8CB8, 0x0, 0x9FDF, 0x0, 0x9FD9, + 0x8B94, 0x936E, 0x0, 0x9FD4, 0x9FDD, 0x88AD, 0x8951, 0x0, + 0x0, 0x89B7, 0x0, 0x9FD6, 0x91AA, 0x9FCD, 0x9FCF, 0x8D60, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9FE0, 0x0, 0x9FDB, 0x0, 0x0, 0x0, 0x9FD3, 0x0, + 0x0, 0x0, 0x0, 0x9FDA, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x96A9, 0x0, 0x0, 0x9FD8, 0x9FDC, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8CCE, 0x0, + 0x8FC3, 0x0, 0x0, 0x9258, 0x0, 0x0, 0x0, 0x9FD2, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x974E, + 0x0, 0x0, 0x0, 0x9FD5, 0x0, 0x0, 0x9FCE, 0x9392, + 0x0, 0x0, 0x9FD1, 0x0, 0x0, 0x0, 0x9FD7, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9870, 0x8EBC, + 0x969E, 0x0, 0x9FE1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x94AC, 0x0, 0x0, 0x9FED, + 0x8CB9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8F80, 0x0, + 0x9FE3, 0x0, 0x0, 0x0, 0x97AD, 0x8D61, 0x0, 0x9FF0, + 0x0, 0x0, 0x88EC, 0x0, 0x0, 0x9FEE, 0x0, 0x0, + 0x0, 0x0, 0x9FE2, 0x0, 0x0, 0x0, 0x0, 0x9FE8, + 0x0, 0x0, 0x9FEA, 0x0, 0x0, 0x0, 0x976E, 0x9FE5, + 0x0, 0x0, 0x934D, 0x0, 0x0, 0x9FE7, 0x0, 0x0, + 0x0, 0x0, 0x9FEF, 0x0, 0x9FE9, 0x96C5, 0x0, 0x0, + 0x0, 0x9FE4, 0x0, 0x8EA0, 0x9FFC, 0x0, 0x0, 0x0, + 0x0, 0x8A8A, 0x0, 0x9FE6, 0x9FEB, 0x9FEC, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x91EA, 0x91D8, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9FF4, 0x0, 0x0, 0x9FFA, + 0x0, 0x0, 0x9FF8, 0x0, 0x9348, 0x0, 0x0, 0xE042, + 0x9FF5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9FF6, 0x9FDE, +}; + +static u16 Ucs6F[] = +{ + 0x0, 0x8B99, 0x9559, 0x0, 0x0, 0x0, 0x8EBD, 0x0, + 0x0, 0x8D97, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9852, + 0x0, 0x9FF2, 0x0, 0xE041, 0x8989, 0x9186, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9499, 0x0, 0x8ABF, 0x97F8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x969F, 0x92D0, 0x0, 0x0, 0x0, + 0x0, 0x9FF9, 0x9FFB, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9151, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE040, 0x9FF7, + 0x0, 0x9FF1, 0x0, 0x0, 0x0, 0x8AC1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8C89, 0x0, 0x0, 0x0, + 0xE04E, 0x0, 0x0, 0xE049, 0x90F6, 0x0, 0x0, 0x8A83, + 0x0, 0x0, 0x0, 0x0, 0x8F81, 0x0, 0xE052, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE04B, 0x92AA, 0xE048, + 0x92D7, 0x0, 0x0, 0x0, 0xE06B, 0x0, 0x0, 0x0, + 0xE045, 0x0, 0xE044, 0x0, 0xE04D, 0x0, 0x0, 0x0, + 0xE047, 0xE046, 0xE04C, 0x0, 0x909F, 0x0, 0xE043, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE04F, 0x0, + 0x0, 0xE050, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8AC0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE055, 0x0, 0xE054, 0xE056, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE059, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9362, 0x0, 0xE053, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE057, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8C83, 0x91F7, 0xE051, 0x945A, 0x0, 0x0, 0xE058, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE05D, 0xE05B, 0x0, 0x0, + 0xE05E, 0x0, 0x0, 0xE061, 0x0, 0x0, 0x0, 0xE05A, + 0x8D8A, 0x9447, 0x0, 0x0, 0x9FB7, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9794, 0xE05C, 0x0, 0xE060, 0x91F3, + 0x0, 0xE05F, 0x0, 0xE04A, 0x0, 0x0, 0xE889, 0x0, + 0x0, 0x0, 0xE064, 0x0, 0x0, 0x0, 0xE068, 0x0, +}; + +static u16 Ucs70[] = +{ + 0x0, 0xE066, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE062, 0x0, 0xE063, 0x0, 0x0, 0x0, 0xE067, + 0x0, 0xE065, 0x0, 0x0, 0x0, 0x956D, 0x0, 0x0, + 0xE06D, 0x0, 0xE06A, 0xE069, 0x0, 0xE06C, 0x93D2, 0xE06E, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9295, 0x91EB, + 0x0, 0x0, 0x0, 0x0, 0x90A3, 0x0, 0x0, 0x0, + 0xE06F, 0x0, 0xE071, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE070, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9FF3, 0x0, 0x0, 0x0, + 0x0, 0xE072, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x93E5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE073, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x89CE, 0x0, 0x0, 0x0, 0x9394, + 0x8A44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8B84, 0x0, 0x0, 0x0, 0x8EDC, 0x8DD0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9846, 0x9086, 0x0, 0x0, 0x0, 0x898A, 0x0, + 0x0, 0x0, 0xE075, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE074, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE078, 0x9259, 0xE07B, 0xE076, + 0x0, 0x0, 0x0, 0xE07A, 0x0, 0x0, 0x0, 0x0, + 0xE079, 0x935F, 0x88D7, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x97F3, 0x0, 0x0, 0xE07D, 0x0, 0x0, 0x0, 0x8947, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE080, 0x0, 0x0, 0x0, 0xE07E, 0x0, 0xE07C, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE077, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9642, 0x0, 0x0, 0x0, 0xE082, 0x0, 0x0, +}; + +static u16 Ucs71[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE081, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x898B, 0x0, 0x0, 0x0, + 0x0, 0xE084, 0x95B0, 0x0, 0xE083, 0x0, 0x0, 0x0, + 0x0, 0x96B3, 0x0, 0x0, 0x0, 0x0, 0x8FC5, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9152, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8FC4, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x97F9, 0x0, 0x0, 0xE08A, 0x0, 0x90F7, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE086, 0xE08B, 0x0, + 0x0, 0x898C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE089, 0x0, 0x9481, 0xE085, 0xE088, 0x8FC6, + 0x0, 0x94CF, 0x0, 0x0, 0xE08C, 0x0, 0x8ECF, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x90F8, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE08F, 0x0, 0x0, 0x0, + 0xE087, 0x0, 0x8C46, 0x0, 0x0, 0x0, 0x0, 0xE08D, + 0x0, 0x0, 0x0, 0x0, 0x976F, 0xE090, 0x0, 0x0, + 0x0, 0xEAA4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8F6E, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE091, 0x0, 0x0, 0x0, 0xE092, 0x0, 0x0, 0x0, + 0x0, 0x944D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE094, 0x0, 0x0, 0x0, 0x0, 0xE095, 0x0, + 0x0, 0x0, 0x0, 0x9452, 0x0, 0x0, 0x0, 0x0, + 0x9395, 0xE097, 0x0, 0x0, 0x0, 0x0, 0xE099, 0x0, + 0x97D3, 0x0, 0xE096, 0x0, 0xE098, 0x898D, 0x0, 0xE093, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9A7A, + 0xE09A, 0x0, 0x0, 0x0, 0x0, 0x9187, 0x8E57, 0xE09C, + 0x0, 0x0, 0x0, 0x0, 0xE09B, 0x9043, 0x99D7, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE09D, 0x0, 0x0, + 0x0, 0xE09F, 0x0, 0xE08E, 0xE09E, 0x0, 0x0, 0xE0A0, +}; + +static u16 Ucs72[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x949A, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE0A1, 0x0, 0x0, + 0xE0A2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE0A3, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE0A4, 0x0, 0x92DC, 0x0, 0xE0A6, 0xE0A5, 0x0, 0x0, + 0xE0A7, 0x0, 0xE0A8, 0x0, 0x0, 0x8EDD, 0x9583, 0x0, + 0x0, 0x0, 0x96EA, 0xE0A9, 0xE0AA, 0x9175, 0x8EA2, 0xE0AB, + 0xE0AC, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE0AD, 0x95D0, + 0x94C5, 0x0, 0x0, 0xE0AE, 0x9476, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x92AB, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE0AF, 0x89E5, 0x0, 0x8B8D, 0x0, 0x96C4, 0x0, 0x96B4, + 0x0, 0x89B2, 0x9853, 0x0, 0x0, 0x0, 0x0, 0x9671, + 0x0, 0x95A8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x90B5, 0x0, 0xE0B0, 0x0, 0x0, 0x0, + 0x0, 0x93C1, 0x0, 0x0, 0x0, 0x8CA1, 0xE0B1, 0x0, + 0x8DD2, 0xE0B3, 0xE0B2, 0x0, 0x0, 0x0, 0x0, 0xE0B4, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE0B5, 0x0, 0x0, 0x0, 0xE0B6, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8B5D, 0x0, 0xE0B7, 0x0, 0x0, 0x0, 0x0, 0xE0B8, + 0x0, 0x0, 0x0, 0x0, 0x8CA2, 0x0, 0x0, 0x94C6, + 0x0, 0x0, 0xE0BA, 0x0, 0x0, 0x0, 0x8FF3, 0x0, + 0x0, 0xE0B9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8BB6, 0xE0BB, 0xE0BD, 0x0, 0xE0BC, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE0BE, 0x0, + 0x8CCF, 0x0, 0xE0BF, 0x0, 0x0, 0x0, 0x0, 0x8BE7, + 0x0, 0x915F, 0x0, 0x8D9D, 0x0, 0x0, 0x0, 0x0, + 0xE0C1, 0xE0C2, 0xE0C0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8EEB, 0x0, 0x0, 0x93C6, 0x8BB7, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE0C4, + 0x924B, 0xE0C3, 0x0, 0x0, 0x9854, 0x9482, 0x0, 0x0, +}; + +static u16 Ucs73[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE0C7, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE0C9, 0xE0C6, + 0x0, 0x0, 0x0, 0x96D2, 0xE0C8, 0xE0CA, 0x0, 0x97C2, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE0CE, 0x0, 0x0, + 0x0, 0xE0CD, 0x9296, 0x944C, 0x0, 0x0, 0x8CA3, 0xE0CC, + 0x0, 0x0, 0x0, 0x0, 0xE0CB, 0x0, 0x9750, 0x9751, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE0CF, 0x898E, + 0x0, 0x0, 0x0, 0x0, 0x8D96, 0x8E82, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE0D0, 0xE0D1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE0D3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8F62, 0x0, 0x0, 0x0, 0x0, + 0xE0D5, 0x0, 0xE0D4, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE0D6, 0x0, 0x8A6C, 0x0, 0x0, 0xE0D8, 0x0, 0x0, + 0xE0D7, 0x0, 0xE0DA, 0xE0D9, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8CBA, 0x0, 0x0, 0x97A6, + 0x0, 0x8BCA, 0x0, 0x89A4, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8BE8, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8ADF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x97E6, 0xE0DC, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE0DE, 0x0, 0x0, 0x0, 0x0, + 0xE0DF, 0x0, 0x89CF, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE0DB, 0x0, 0x8E58, 0x0, 0x0, 0x92BF, 0xE0DD, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE0E2, 0x0, + 0x8EEC, 0x0, 0x0, 0x0, 0x0, 0xE0E0, 0x0, 0x0, + 0x0, 0x0, 0x8C5D, 0x0, 0x0, 0x94C7, 0xE0E1, 0x0, + 0x0, 0xE0FC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE0E7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8CBB, 0x0, +}; + +static u16 Ucs74[] = +{ + 0x0, 0x0, 0x0, 0x8B85, 0x0, 0xE0E4, 0x979D, 0x0, + 0x0, 0x97AE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x91F4, 0x0, 0x0, 0xE0E6, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE0E8, 0x97D4, 0x8BD5, 0x94FA, 0x9469, 0x0, + 0x0, 0x0, 0xE0E9, 0x0, 0x0, 0x0, 0x0, 0xE0EB, + 0x0, 0xE0EE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE0EA, 0x0, 0x0, + 0x0, 0xE0ED, 0x8CE8, 0x896C, 0xE0EF, 0x0, 0x9090, 0xE0EC, + 0x97DA, 0x0, 0x0, 0xE0F2, 0xEAA2, 0x0, 0x0, 0x0, + 0x0, 0xE0F0, 0xE0F3, 0x0, 0x0, 0x0, 0x0, 0xE0E5, + 0xE0F1, 0x0, 0x0, 0x8DBA, 0x0, 0x0, 0xE0F4, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE0F5, 0x0, + 0x0, 0x0, 0x0, 0x979E, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE0F6, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE0F7, 0x0, + 0x0, 0x0, 0xE0E3, 0x0, 0x0, 0x0, 0x0, 0xE0F8, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8AC2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8EA3, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE0F9, 0x0, 0x0, 0x0, 0x0, 0xE0FA, + 0x0, 0x0, 0x0, 0x0, 0xE0FB, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x895A, 0x0, 0x0, 0x0, + 0xE140, 0x0, 0x955A, 0xE141, 0x0, 0x0, 0x8AA2, 0xE142, + 0x0, 0xE143, 0x0, 0x0, 0x0, 0x0, 0xE144, 0x0, + 0xE146, 0xE147, 0xE145, 0x0, 0x0, 0x0, 0x9572, 0xE149, + 0xE148, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs75[] = +{ + 0x0, 0x0, 0x0, 0xE14B, 0xE14A, 0xE14C, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE14D, 0xE14F, 0xE14E, 0x0, + 0x0, 0x8D99, 0x0, 0xE151, 0x0, 0xE150, 0x0, 0x0, + 0x8AC3, 0x0, 0x9072, 0x0, 0x935B, 0x0, 0xE152, 0x90B6, + 0x0, 0x0, 0x0, 0x8E59, 0x0, 0x8999, 0xE153, 0x0, + 0x9770, 0x0, 0x0, 0x95E1, 0xE154, 0x0, 0x0, 0x0, + 0x9363, 0x9752, 0x8D62, 0x905C, 0x0, 0x0, 0x0, 0x926A, + 0x99B2, 0x0, 0x92AC, 0x89E6, 0xE155, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE156, 0x0, 0xE15B, 0x0, + 0x0, 0xE159, 0xE158, 0x9DC0, 0x8A45, 0xE157, 0x0, 0x88D8, + 0x0, 0x94A8, 0x0, 0x0, 0x94C8, 0x0, 0x0, 0x0, + 0x0, 0x97AF, 0xE15C, 0xE15A, 0x927B, 0x90A4, 0x0, 0x0, + 0x94A9, 0x0, 0x954C, 0x0, 0xE15E, 0x97AA, 0x8C6C, 0xE15F, + 0x0, 0xE15D, 0x94D4, 0xE160, 0x0, 0xE161, 0x0, 0x0, + 0x88D9, 0x0, 0x0, 0x8FF4, 0xE166, 0x0, 0xE163, 0x93EB, + 0xE162, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8B45, + 0x0, 0x0, 0xE169, 0x0, 0x0, 0x0, 0xE164, 0xE165, + 0x0, 0xE168, 0xE167, 0x9544, 0x0, 0x0, 0x9161, 0x9160, + 0x0, 0x8B5E, 0x0, 0x0, 0xE16A, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE16B, 0x0, 0x0, 0xE16C, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE16E, 0x0, 0xE16D, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8975, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE176, 0x94E6, 0xE170, 0x0, 0xE172, 0x0, 0x0, + 0xE174, 0x905D, 0x0, 0x0, 0xE175, 0xE173, 0x8EBE, 0x0, + 0x0, 0x0, 0xE16F, 0xE171, 0x0, 0x9561, 0x0, 0x8FC7, + 0x0, 0x0, 0xE178, 0x0, 0x0, 0xE177, 0x0, 0x0, + 0x0, 0x0, 0xE179, 0x0, 0x8EA4, 0x8DAD, 0x0, 0x0, + 0x9397, 0xE17A, 0x0, 0x92C9, 0x0, 0x0, 0xE17C, 0x0, + 0x0, 0x0, 0x979F, 0xE17B, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9189, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE182, 0x0, 0xE184, 0xE185, 0x9273, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE183, 0x0, 0xE180, 0x0, 0xE17D, 0xE17E, +}; + +static u16 Ucs76[] = +{ + 0x0, 0xE181, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE188, 0x0, 0xE186, 0x0, 0xE187, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE189, + 0xE18B, 0xE18C, 0xE18D, 0x0, 0xE18E, 0x0, 0x0, 0xE18A, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE190, 0x0, 0x0, 0x0, 0xE18F, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE191, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x97C3, 0x0, 0x0, 0x0, 0xE194, 0xE192, + 0xE193, 0x0, 0x0, 0x0, 0x8AE0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x96FC, 0x0, 0x0, 0x0, 0x95C8, 0x0, + 0xE196, 0x0, 0x0, 0x0, 0xE195, 0x0, 0x0, 0x0, + 0x0, 0xE197, 0xE198, 0x0, 0x0, 0x0, 0x0, 0xE19C, + 0xE199, 0xE19A, 0xE19B, 0x0, 0xE19D, 0x0, 0x0, 0x0, + 0xE19E, 0x0, 0xE19F, 0x0, 0x0, 0x0, 0xE1A0, 0x0, + 0xE1A1, 0x0, 0x94AD, 0x936F, 0xE1A2, 0x9492, 0x9553, 0x0, + 0xE1A3, 0x0, 0x0, 0xE1A4, 0x9349, 0x0, 0x8A46, 0x8D63, + 0xE1A5, 0x0, 0x0, 0xE1A6, 0x0, 0x0, 0xE1A7, 0x0, + 0x8E48, 0x0, 0x0, 0xE1A9, 0x0, 0x0, 0xE1A8, 0x0, + 0x0, 0xE1AA, 0xE1AB, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x94E7, 0x0, + 0xE1AC, 0x0, 0x0, 0x0, 0xE1AD, 0x0, 0x0, 0xEA89, + 0xE1AE, 0xE1AF, 0xE1B0, 0x0, 0x0, 0x0, 0x0, 0x8E4D, + 0x0, 0x0, 0xE1B1, 0x9475, 0x0, 0x0, 0x967E, 0x0, + 0x896D, 0x0, 0x8976, 0x0, 0x0, 0xE1B2, 0x0, 0x0, + 0x0, 0x0, 0xE1B4, 0x0, 0x0, 0x0, 0xE1B3, 0x9390, + 0x0, 0x0, 0x0, 0x90B7, 0x9F58, 0x0, 0xE1B5, 0x96BF, + 0x0, 0xE1B6, 0x0, 0x8AC4, 0x94D5, 0xE1B7, 0x0, 0xE1B8, + 0x0, 0x0, 0xE1B9, 0x0, 0x0, 0x0, 0x96DA, 0x0, + 0x0, 0x0, 0x96D3, 0x0, 0x92BC, 0x0, 0x0, 0x0, + 0x918A, 0x0, 0x0, 0xE1BB, 0x0, 0x0, 0x8F82, 0x0, +}; + +static u16 Ucs77[] = +{ + 0x0, 0x8FC8, 0x0, 0x0, 0xE1BE, 0x0, 0x0, 0xE1BD, + 0xE1BC, 0x94FB, 0x0, 0x8AC5, 0x8CA7, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE1C4, 0x0, 0x0, 0xE1C1, 0x905E, + 0x96B0, 0x0, 0x0, 0x0, 0xE1C0, 0xE1C2, 0xE1C3, 0x0, + 0x0, 0xE1BF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE1C5, + 0xE1C6, 0x0, 0x92AD, 0x0, 0x8AE1, 0x0, 0x0, 0x0, + 0x9285, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE1C7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE1C8, 0xE1CB, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9087, 0x0, 0x93C2, 0x0, 0xE1CC, 0x9672, 0x0, + 0xE1C9, 0x0, 0x0, 0xE1CA, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE1CF, 0x0, 0x0, 0x0, 0x0, 0xE1CE, 0xE1CD, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE1D1, 0x0, 0x0, 0xE1D0, 0x0, + 0x0, 0xE1D2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE1D4, 0x0, + 0xE1D3, 0x0, 0x0, 0x0, 0x0, 0x95CB, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8F75, 0x97C4, 0x0, 0x0, + 0xE1D5, 0x0, 0x0, 0x93B5, 0x0, 0x0, 0xE1D6, 0x0, + 0x0, 0xE1D7, 0x0, 0xE1DB, 0xE1D9, 0xE1DA, 0x0, 0xE1D8, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE1DC, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE1DD, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE1DE, + 0x0, 0x0, 0xE1DF, 0x96B5, 0xE1E0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x96EE, 0xE1E1, 0x0, 0x926D, 0x0, 0x948A, + 0x0, 0x8BE9, 0x0, 0x0, 0x0, 0x925A, 0xE1E2, 0x8BB8, + 0x0, 0x0, 0x0, 0x90CE, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE1E3, 0x0, 0x0, 0x0, +}; + +static u16 Ucs78[] = +{ + 0x0, 0x0, 0x8DBB, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE1E4, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE1E5, 0x0, 0x8CA4, 0x8DD3, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE1E7, 0x0, 0x0, 0x0, 0x0, 0x9375, 0x8DD4, 0x8B6D, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9643, 0x0, 0x946A, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9376, 0x0, 0x0, 0x0, 0x0, 0x8D7B, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE1E9, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8FC9, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x97B0, 0x8D64, 0x0, 0x0, 0x8CA5, + 0x0, 0x0, 0x94A1, 0x0, 0xE1EB, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE1ED, 0x0, 0x0, 0x0, + 0x0, 0x8CE9, 0x0, 0x0, 0x0, 0x0, 0xE1EC, 0x92F4, + 0x0, 0x0, 0x0, 0x0, 0xE1EF, 0x8A56, 0xE1EA, 0x0, + 0x0, 0x94E8, 0x0, 0x894F, 0x0, 0x8DEA, 0x0, 0x9871, + 0x0, 0x0, 0xE1EE, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE1F0, 0x0, 0x0, 0x0, 0x95C9, + 0x0, 0x90D7, 0xE1F2, 0x0, 0x0, 0x0, 0x0, 0xE1F3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE1F1, 0x0, 0x0, + 0x0, 0x0, 0x8A6D, 0x0, 0xE1F9, 0x0, 0xE1F8, 0x0, + 0x0, 0x8EA5, 0x0, 0x0, 0x0, 0xE1FA, 0xE1F5, 0x0, + 0x0, 0x0, 0xE1FB, 0xE1F6, 0x0, 0x0, 0x0, 0x0, + 0x94D6, 0xE1F4, 0x0, 0x0, 0xE1F7, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE241, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE240, + 0x9681, 0x0, 0x0, 0x0, 0xE1FC, 0x0, 0x0, 0x88E9, + 0x0, 0x0, 0x0, 0x0, 0xE243, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE242, 0x0, 0x0, +}; + +static u16 Ucs79[] = +{ + 0x0, 0x8FCA, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE244, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9162, 0x0, + 0x0, 0xE246, 0xE245, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE247, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE1E6, 0x0, + 0x0, 0x0, 0xE1E8, 0xE249, 0xE248, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8EA6, 0x0, 0x97E7, 0x0, 0x8ED0, 0x0, + 0xE24A, 0x8C56, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8B5F, + 0x8B46, 0x8E83, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9753, 0x0, 0x0, 0xE250, 0x0, 0xE24F, 0x9163, 0xE24C, + 0x0, 0x0, 0xE24E, 0x0, 0x0, 0x8F6A, 0x905F, 0xE24D, + 0xE24B, 0x0, 0x9449, 0x0, 0x0, 0x8FCB, 0x0, 0x0, + 0x955B, 0x0, 0x0, 0x0, 0x0, 0x8DD5, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9398, + 0x0, 0x0, 0xE251, 0x0, 0x0, 0x0, 0x0, 0xE252, + 0xE268, 0x8BD6, 0x0, 0x0, 0x985C, 0x9154, 0x0, 0x0, + 0x0, 0x0, 0xE253, 0x0, 0x0, 0x89D0, 0x92F5, 0x959F, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE254, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8B9A, 0xE255, + 0x0, 0x0, 0xE257, 0x0, 0x0, 0x0, 0xE258, 0x0, + 0x9448, 0x0, 0x0, 0xE259, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE25A, 0xE25B, 0x0, 0x0, 0x8BD7, 0x89D1, 0x93C3, + 0x8F47, 0x8E84, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE25C, 0x0, 0x8F48, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x89C8, 0x9562, 0x0, 0x0, 0xE25D, 0x0, 0x0, + 0x94E9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9164, + 0x0, 0xE260, 0x0, 0xE261, 0x9489, 0x0, 0x9060, 0xE25E, + 0x0, 0x9281, 0x0, 0x0, 0xE25F, 0x0, 0x0, 0x0, + 0x8FCC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x88DA, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs7A[] = +{ + 0x8B48, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE262, 0x0, 0x0, 0x92F6, 0x0, 0xE263, 0x90C5, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x96AB, 0x0, 0x0, 0x9542, + 0xE264, 0xE265, 0x9274, 0x0, 0x97C5, 0x0, 0x0, 0xE267, + 0xE266, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8EED, 0x0, + 0x0, 0xE269, 0x88EE, 0x0, 0x0, 0x0, 0x0, 0xE26C, + 0x0, 0x0, 0x0, 0xE26A, 0x89D2, 0x8C6D, 0xE26B, 0x8D65, + 0x8D92, 0x0, 0x95E4, 0xE26D, 0x0, 0x0, 0x9673, 0x0, + 0x0, 0xE26F, 0x0, 0x0, 0x0, 0x90CF, 0x896E, 0x89B8, + 0x88AA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE26E, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE270, 0xE271, 0x8FF5, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE272, 0x0, 0x8A6E, 0x0, 0x0, 0x0, 0x0, + 0xE274, 0x0, 0x0, 0x0, 0x8C8A, 0x0, 0x8B86, 0x0, + 0x0, 0xE275, 0x8BF3, 0x0, 0x0, 0xE276, 0x0, 0x90FA, + 0x0, 0x93CB, 0x0, 0x90DE, 0x8DF3, 0x0, 0x0, 0x0, + 0xE277, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9282, 0x918B, 0x0, 0xE279, 0xE27B, 0xE278, + 0xE27A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8C41, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE27C, 0x8C45, 0x0, 0x0, 0x0, 0x8B87, 0x9771, + 0xE27E, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE280, 0x0, + 0x0, 0x0, 0x894D, 0x0, 0x0, 0x0, 0x0, 0xE283, + 0x0, 0x0, 0x0, 0x8A96, 0xE282, 0xE281, 0x0, 0xE285, + 0xE27D, 0x0, 0xE286, 0x97A7, 0x0, 0xE287, 0x0, 0xE288, + 0x0, 0x0, 0x9AF2, 0xE28A, 0x0, 0xE289, 0x0, 0x0, + 0x0, 0xE28B, 0xE28C, 0x0, 0x97B3, 0xE28D, 0x0, 0xE8ED, + 0x8FCD, 0xE28E, 0xE28F, 0x8F76, 0x0, 0x93B6, 0xE290, 0x0, + 0x0, 0x0, 0x9247, 0x0, 0x0, 0xE291, 0x0, 0x925B, + 0xE292, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8BA3, 0x0, + 0x995E, 0x927C, 0x8EB1, 0x0, 0x0, 0x0, 0x0, 0x8AC6, +}; + +static u16 Ucs7B[] = +{ + 0x0, 0x0, 0xE293, 0x0, 0xE2A0, 0x0, 0xE296, 0x0, + 0x8B88, 0x0, 0xE295, 0xE2A2, 0x0, 0x0, 0x0, 0xE294, + 0x0, 0x8FCE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE298, 0xE299, 0x0, 0x934A, 0x0, 0x0, 0xE29A, 0x0, + 0x8A7D, 0x0, 0x0, 0x0, 0x0, 0x9079, 0x9584, 0x0, + 0xE29C, 0x0, 0x0, 0x0, 0x91E6, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE297, 0x0, 0xE29B, 0xE29D, 0x0, + 0x0, 0x8DF9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE2A4, 0x954D, 0x0, + 0x94A4, 0x9399, 0x0, 0x8BD8, 0xE2A3, 0xE2A1, 0x0, 0x94B3, + 0xE29E, 0x927D, 0x939B, 0x0, 0x939A, 0x0, 0x8DF4, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE2B6, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE2A6, 0x0, 0xE2A8, + 0x0, 0x0, 0x0, 0x0, 0xE2AB, 0x0, 0xE2AC, 0x0, + 0xE2A9, 0xE2AA, 0x0, 0x0, 0xE2A7, 0xE2A5, 0x0, 0x0, + 0x0, 0x0, 0xE29F, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x95CD, 0x89D3, + 0x0, 0x0, 0x0, 0xE2B3, 0x0, 0xE2B0, 0x0, 0xE2B5, + 0x0, 0x0, 0xE2B4, 0x0, 0x9493, 0x96A5, 0x0, 0x8E5A, + 0xE2AE, 0xE2B7, 0xE2B2, 0x0, 0xE2B1, 0xE2AD, 0x0, 0xE2AF, + 0x0, 0x8AC7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x925C, 0x0, 0x0, 0x90FB, 0x0, 0x0, + 0x0, 0x94A0, 0x0, 0x0, 0xE2BC, 0x0, 0x0, 0x0, + 0x94A2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x90DF, 0xE2B9, 0x0, 0x0, 0x94CD, 0x0, 0xE2BD, 0x95D1, + 0x0, 0x927A, 0x0, 0xE2B8, 0xE2BA, 0x0, 0x0, 0xE2BB, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE2BE, 0x0, 0x0, + 0x8EC2, 0x0, 0x0, 0x0, 0x93C4, 0xE2C3, 0xE2C2, 0x0, + 0x0, 0xE2BF, 0x0, 0x0, 0x0, 0x9855, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE2C8, 0x0, 0x0, 0xE2CC, 0xE2C9, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs7C[] = +{ + 0xE2C5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE2C6, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE2CB, 0x0, 0x0, + 0x0, 0xE2C0, 0x99D3, 0xE2C7, 0xE2C1, 0x0, 0x0, 0xE2CA, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE2D0, + 0x0, 0x8AC8, 0x0, 0xE2CD, 0x0, 0x0, 0x0, 0xE2CE, + 0x0, 0x0, 0xE2CF, 0xE2D2, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE2D1, + 0x94F4, 0x0, 0x0, 0x0, 0x0, 0xE2D3, 0x97FA, 0x95EB, + 0xE2D8, 0x0, 0x0, 0xE2D5, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE2D4, 0x90D0, 0x0, 0xE2D7, + 0xE2D9, 0x0, 0x0, 0x0, 0xE2D6, 0x0, 0xE2DD, 0x0, + 0xE2DA, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE2DB, + 0xE2C4, 0x0, 0x0, 0x0, 0xE2DC, 0xE2DE, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE2DF, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x95C4, 0x0, 0xE2E0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x96E0, 0x0, + 0x0, 0x8BCC, 0x8C48, 0xE2E1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x95B2, 0x0, 0x9088, 0x0, 0x96AE, 0x0, 0x0, + 0xE2E2, 0x0, 0x97B1, 0x0, 0x0, 0x9494, 0x0, 0x9165, + 0x9453, 0x0, 0x0, 0x8F6C, 0x0, 0x0, 0x0, 0x88BE, + 0x0, 0xE2E7, 0xE2E5, 0x0, 0xE2E3, 0x8A9F, 0x0, 0x8FCF, + 0xE2E8, 0x0, 0x0, 0xE2E6, 0x0, 0xE2E4, 0xE2EC, 0x0, + 0x0, 0xE2EB, 0xE2EA, 0xE2E9, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE2ED, 0x0, 0x0, 0x0, 0xE2EE, 0x90B8, 0x0, + 0xE2EF, 0x0, 0xE2F1, 0x0, 0x0, 0xE2F0, 0x0, 0x0, + 0x0, 0x0, 0x8CD0, 0x0, 0x0, 0x0, 0x9157, 0x0, + 0x0, 0x0, 0xE2F3, 0x0, 0x0, 0x0, 0x939C, 0x0, + 0xE2F2, 0x0, 0x0, 0x0, 0xE2F4, 0x0, 0x95B3, 0x918C, + 0x8D66, 0x0, 0xE2F5, 0x0, 0x0, 0x0, 0x0, 0x97C6, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE2F7, + 0x0, 0x0, 0xE2F8, 0x0, 0xE2F9, 0x0, 0xE2FA, 0x0, + 0x8E85, 0x0, 0xE2FB, 0x8C6E, 0x0, 0x0, 0x8B8A, 0x0, +}; + +static u16 Ucs7D[] = +{ + 0x8B49, 0x0, 0xE340, 0x0, 0x96F1, 0x8D67, 0xE2FC, 0x0, + 0x0, 0x0, 0xE343, 0x96E4, 0x0, 0x945B, 0x0, 0x0, + 0x9552, 0x0, 0x0, 0x0, 0x8F83, 0xE342, 0x0, 0x8ED1, + 0x8D68, 0x8E86, 0x8B89, 0x95B4, 0xE341, 0x0, 0x0, 0x0, + 0x9166, 0x9661, 0x8DF5, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8E87, 0x92DB, 0x0, 0xE346, 0x97DD, + 0x8DD7, 0x0, 0xE347, 0x9061, 0x0, 0xE349, 0x0, 0x0, + 0x0, 0x8FD0, 0x8DAE, 0x0, 0x0, 0x0, 0x0, 0xE348, + 0x0, 0x0, 0x8F49, 0x8CBC, 0x9167, 0xE344, 0xE34A, 0x0, + 0x0, 0x0, 0x0, 0xE345, 0x8C6F, 0x0, 0xE34D, 0xE351, + 0x8C8B, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE34C, 0x0, + 0x0, 0x0, 0x0, 0xE355, 0x0, 0x0, 0x8D69, 0x0, + 0x0, 0x978D, 0x88BA, 0xE352, 0x0, 0x0, 0x8B8B, 0x0, + 0xE34F, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE350, 0x0, + 0x0, 0x939D, 0xE34E, 0xE34B, 0x0, 0x8A47, 0x90E2, 0x0, + 0x0, 0x8CA6, 0x0, 0x0, 0x0, 0xE357, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE354, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE356, + 0x0, 0x0, 0x0, 0xE353, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8C70, 0x91B1, 0xE358, 0x918E, 0x0, 0x0, 0xE365, + 0x0, 0x0, 0xE361, 0xE35B, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE35F, 0x8EF8, 0x88DB, 0xE35A, 0xE362, + 0xE366, 0x8D6A, 0x96D4, 0x0, 0x92D4, 0xE35C, 0x0, 0x0, + 0xE364, 0x0, 0xE359, 0x925D, 0x0, 0xE35E, 0x88BB, 0x96C8, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE35D, + 0x0, 0x0, 0x8BD9, 0x94EA, 0x0, 0x0, 0x0, 0x918D, + 0x0, 0x97CE, 0x8F8F, 0x0, 0x0, 0xE38E, 0x0, 0x0, + 0xE367, 0x0, 0x90FC, 0x0, 0xE363, 0xE368, 0xE36A, 0x0, + 0x92F7, 0xE36D, 0x0, 0x0, 0xE369, 0x0, 0x0, 0x0, + 0x95D2, 0x8AC9, 0x0, 0x0, 0x96C9, 0x0, 0x0, 0x88DC, + 0x0, 0x0, 0xE36C, 0x0, 0x97FB, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE36B, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs7E[] = +{ + 0x0, 0x898F, 0x0, 0x0, 0x93EA, 0xE36E, 0x0, 0x0, + 0x0, 0xE375, 0xE36F, 0xE376, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE372, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x949B, 0x0, 0x0, 0x8EC8, 0xE374, + 0x0, 0xE371, 0xE377, 0xE370, 0x0, 0x0, 0x8F63, 0x0, + 0x0, 0x0, 0x0, 0x9644, 0x0, 0x0, 0x8F6B, 0x0, + 0x0, 0xE373, 0xE380, 0x0, 0x0, 0xE37B, 0x0, 0xE37E, + 0x0, 0xE37C, 0xE381, 0xE37A, 0x0, 0xE360, 0x90D1, 0x0, + 0x0, 0x94C9, 0x0, 0xE37D, 0x0, 0x0, 0xE378, 0x0, + 0x0, 0x0, 0x9140, 0x8C71, 0x0, 0x8F4A, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9044, 0x9155, 0xE384, 0x0, + 0x0, 0xE386, 0xE387, 0x0, 0x0, 0xE383, 0xE385, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE379, 0xE382, + 0x0, 0xE38A, 0xE389, 0x0, 0x0, 0x969A, 0x0, 0x0, + 0x8C4A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE388, 0x0, 0xE38C, 0xE38B, 0xE38F, 0x0, 0xE391, + 0x0, 0x0, 0x8E5B, 0xE38D, 0x0, 0x0, 0x0, 0x0, + 0xE392, 0xE393, 0x0, 0x0, 0xE394, 0x0, 0xE39A, 0x935A, + 0xE396, 0x0, 0xE395, 0xE397, 0xE398, 0x0, 0xE399, 0x0, + 0x0, 0x0, 0x0, 0xE39B, 0xE39C, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs7F[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8ACA, 0x0, + 0xE39D, 0x0, 0xE39E, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE39F, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE3A0, 0xE3A1, 0xE3A2, 0x0, + 0xE3A3, 0xE3A4, 0x0, 0x0, 0xE3A6, 0xE3A5, 0x0, 0x0, + 0xE3A7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE3A8, + 0xE3A9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE3AC, + 0xE3AA, 0xE3AB, 0x8DDF, 0x8C72, 0x0, 0x0, 0x9275, 0x0, + 0x94B1, 0x0, 0x8F90, 0x0, 0x0, 0x946C, 0x0, 0x94EB, + 0xE3AD, 0x9CEB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE3AE, 0xE3B0, 0x0, 0x9785, 0xE3AF, 0xE3B2, + 0xE3B1, 0x0, 0x9772, 0x0, 0xE3B3, 0x0, 0x94FC, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE3B4, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE3B7, 0x0, 0x0, 0xE3B6, 0xE3B5, 0x0, + 0x0, 0x0, 0x0, 0xE3B8, 0x8C51, 0x0, 0x0, 0x0, + 0x9141, 0x8B60, 0x0, 0x0, 0x0, 0x0, 0xE3BC, 0xE3B9, + 0x0, 0x0, 0xE3BA, 0x0, 0x0, 0x0, 0xE3BD, 0x0, + 0xE3BE, 0xE3BB, 0x0, 0x0, 0x0, 0x8948, 0x0, 0x0, + 0x0, 0x89A5, 0x0, 0x0, 0x0, 0xE3C0, 0xE3C1, 0x0, + 0x0, 0x0, 0xE3C2, 0x0, 0x9782, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8F4B, 0x0, 0xE3C4, 0xE3C3, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9089, 0xE3C5, 0x0, 0x0, 0x0, 0x0, 0xE3C6, 0x0, + 0x0, 0xE3C7, 0x0, 0x8AE3, 0x0, 0x0, 0x0, 0x0, + 0x8ACB, 0x0, 0x0, 0xE3C8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE3C9, 0x0, 0x967C, 0x9783, 0x0, 0x0, 0x0, +}; + +static u16 Ucs80[] = +{ + 0x9773, 0x9856, 0x0, 0x8D6C, 0xE3CC, 0x8ED2, 0xE3CB, 0x0, + 0x0, 0x0, 0x0, 0xE3CD, 0x8EA7, 0x0, 0x0, 0x0, + 0x91CF, 0x0, 0xE3CE, 0x0, 0x0, 0x8D6B, 0x0, 0x96D5, + 0xE3CF, 0xE3D0, 0x0, 0x0, 0xE3D1, 0x0, 0x0, 0x0, + 0x0, 0xE3D2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE3D3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8EA8, 0x0, 0x0, 0x96EB, 0x0, + 0x0, 0x0, 0x0, 0xE3D5, 0x0, 0x925E, 0x0, 0xE3D4, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE3D7, 0x0, + 0x0, 0x0, 0xE3D6, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE3D8, 0x0, 0x0, 0x0, 0x90B9, 0x0, + 0xE3D9, 0x0, 0xE3DA, 0x0, 0x0, 0x0, 0x95B7, 0xE3DB, + 0x0, 0x918F, 0xE3DC, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE3DD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x97FC, + 0xE3E0, 0x0, 0xE3DF, 0xE3DE, 0x92AE, 0x0, 0xE3E1, 0x9045, + 0x0, 0xE3E2, 0x0, 0x0, 0x0, 0xE3E3, 0x9857, 0xE3E4, + 0x0, 0x0, 0x0, 0x0, 0xE3E5, 0xE3E7, 0xE3E6, 0x94A3, + 0x0, 0x93F7, 0x0, 0x985D, 0x94A7, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE3E9, 0x0, 0x0, 0x8FD1, 0x0, + 0x9549, 0x0, 0xE3EA, 0xE3E8, 0x0, 0x8ACC, 0x0, 0x0, + 0x0, 0x8CD2, 0x8E88, 0x0, 0x0, 0x94EC, 0x0, 0x0, + 0x0, 0x8CA8, 0x9662, 0x0, 0xE3ED, 0xE3EB, 0x0, 0x8D6D, + 0x0, 0x8D6E, 0x88E7, 0x0, 0x8DE6, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9478, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x88DD, 0xE3F2, 0x0, 0x925F, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9477, 0x0, 0x91D9, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE3F4, 0x0, + 0x0, 0xE3F0, 0xE3F3, 0xE3EE, 0x0, 0xE3F1, 0x9645, 0x0, + 0x0, 0x8CD3, 0x0, 0x0, 0x88FB, 0xE3EF, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE3F6, + 0x0, 0xE3F7, 0x0, 0x0, 0x93B7, 0x0, 0x0, 0x0, + 0x8BB9, 0x0, 0x0, 0x0, 0xE445, 0x945C, 0x0, 0x0, +}; + +static u16 Ucs81[] = +{ + 0x0, 0x0, 0x8E89, 0x0, 0x0, 0x8BBA, 0x90C6, 0x9865, + 0x96AC, 0xE3F5, 0x90D2, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8B72, 0xE3F8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE3FA, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE3F9, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE3FB, + 0x0, 0x9245, 0x0, 0x945D, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x92AF, 0x0, 0x0, 0x0, 0x0, 0xE442, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE441, 0x0, + 0x0, 0x0, 0x0, 0xE3FC, 0x0, 0x0, 0x9074, 0x0, + 0x9585, 0xE444, 0x0, 0xE443, 0x8D6F, 0x9872, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE454, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE448, 0xE449, 0x0, + 0x0, 0x0, 0x0, 0x8EEE, 0x0, 0x0, 0xE447, 0x0, + 0x8D98, 0xE446, 0x0, 0x0, 0xE44A, 0x0, 0x0, 0x0, + 0x92B0, 0x95A0, 0x9142, 0x0, 0x0, 0x0, 0x0, 0x91DA, + 0xE44E, 0x0, 0xE44F, 0xE44B, 0x0, 0x0, 0x0, 0x0, + 0xE44C, 0x0, 0xE44D, 0x0, 0x0, 0x0, 0x0, 0x8D70, + 0x0, 0x0, 0x0, 0xE455, 0x0, 0xE451, 0x0, 0x0, + 0x0, 0x0, 0x9586, 0x0, 0x968C, 0x9547, 0x0, 0x0, + 0xE450, 0x0, 0x0, 0xE453, 0xE452, 0x0, 0x0, 0x0, + 0x9663, 0xE456, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE457, 0x0, 0x0, 0x9156, 0x0, 0xE458, 0x0, 0x0, + 0xE45A, 0x0, 0xE45E, 0x0, 0x0, 0xE45B, 0xE459, 0x945E, + 0xE45C, 0x0, 0xE45D, 0x0, 0x0, 0x0, 0x89B0, 0x0, + 0xE464, 0xE45F, 0x0, 0x0, 0x0, 0xE460, 0x0, 0x0, + 0x0, 0xE461, 0x0, 0x919F, 0x0, 0x0, 0x0, 0x0, + 0xE463, 0xE462, 0xE465, 0x0, 0x0, 0x0, 0x0, 0xE466, + 0xE467, 0x0, 0x0, 0x9062, 0x0, 0x89E7, 0x0, 0xE468, + 0x97D5, 0x0, 0x8EA9, 0x0, 0x0, 0x8F4C, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8E8A, 0x9276, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE469, 0xE46A, 0x8950, 0x0, 0xE46B, 0x0, +}; + +static u16 Ucs82[] = +{ + 0x0, 0xE46C, 0xE46D, 0x0, 0x0, 0xE46E, 0x0, 0xE46F, + 0x8BBB, 0x9DA8, 0xE470, 0x0, 0x90E3, 0xE471, 0x8EC9, 0x0, + 0xE472, 0x0, 0x98AE, 0x0, 0x0, 0x0, 0xE473, 0x95DC, + 0x8ADA, 0x0, 0x0, 0x9143, 0x8F77, 0x0, 0x9591, 0x8F4D, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE474, 0x8D71, 0xE475, 0x94CA, 0x0, 0xE484, 0x0, + 0x0, 0x0, 0x0, 0xE477, 0x0, 0x91C7, 0x9495, 0x8CBD, + 0xE476, 0x9144, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE478, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x92F8, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE47A, 0xE479, 0xE47C, 0x0, 0x0, 0xE47B, 0x0, 0xE47D, + 0x0, 0x0, 0xE480, 0x0, 0xE47E, 0x0, 0x8ACD, 0x0, + 0xE481, 0x0, 0xE482, 0xE483, 0x0, 0x0, 0x8DAF, 0x97C7, + 0x0, 0xE485, 0x9046, 0x0, 0x0, 0x0, 0x8990, 0xE486, + 0xE487, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE488, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x88F0, 0x0, 0xE489, 0x0, 0x0, + 0x0, 0x0, 0xE48A, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9587, 0x0, 0x0, 0x0, 0x8EC5, 0x0, 0xE48C, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8A48, 0x88B0, 0x0, + 0x0, 0x0, 0x0, 0xE48B, 0xE48E, 0x946D, 0x0, 0x9063, + 0x0, 0x89D4, 0x0, 0x9646, 0x0, 0x0, 0x0, 0x0, + 0x8C7C, 0x8BDA, 0x0, 0xE48D, 0x0, 0x89E8, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8AA1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8991, 0xE492, 0x97E8, 0x91DB, 0x0, 0x0, 0x9563, + 0x0, 0xE49E, 0x0, 0x89D5, 0xE49C, 0x0, 0xE49A, 0xE491, + 0x0, 0xE48F, 0x0, 0xE490, 0x0, 0x8EE1, 0x8BEA, 0x9297, + 0x0, 0x0, 0x0, 0x93CF, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8970, 0x0, 0xE494, 0xE493, 0x0, 0x0, 0x0, + 0x0, 0xE499, 0xE495, 0xE498, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs83[] = +{ + 0x0, 0x0, 0x96CE, 0xE497, 0x89D6, 0x8A9D, 0xE49B, 0x0, + 0x0, 0xE49D, 0x0, 0x0, 0x0, 0x0, 0x8C73, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE4A1, 0xE4AA, + 0xE4AB, 0x0, 0x0, 0x0, 0x88A9, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE4B2, 0x0, 0x0, 0x0, 0x0, + 0x88EF, 0x0, 0x0, 0xE4A9, 0x0, 0x0, 0x0, 0xE4A8, + 0x0, 0xE4A3, 0xE4A2, 0x0, 0xE4A0, 0xE49F, 0x9283, 0x0, + 0x91F9, 0xE4A5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE4A4, 0x0, 0x0, 0x0, 0x0, 0xE4A7, 0x0, 0x0, + 0x0, 0x9190, 0x8C74, 0x0, 0x0, 0x0, 0x0, 0x8960, + 0xE4A6, 0x0, 0x8D72, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9191, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE4B8, 0x0, 0xE4B9, 0x0, 0x89D7, + 0x0, 0x0, 0x0, 0x89AC, 0xE4B6, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE4AC, 0x0, 0xE4B4, + 0x0, 0xE4BB, 0xE4B5, 0x0, 0x0, 0x0, 0xE4B3, 0x0, + 0x0, 0x0, 0x0, 0xE496, 0x0, 0x0, 0xE4B1, 0x0, + 0x0, 0x0, 0xE4AD, 0x0, 0x0, 0x0, 0x8ACE, 0xE4AF, + 0xE4BA, 0x0, 0xE4B0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE4BC, 0x0, 0xE4AE, 0x949C, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9789, 0x0, 0x0, 0x0, 0xE4B7, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE4CD, 0x0, 0x0, + 0x0, 0xE4C5, 0x0, 0x0, 0x0, 0x909B, 0x0, 0x0, + 0x0, 0x0, 0x8B65, 0x0, 0x8BDB, 0x0, 0xE4C0, 0x0, + 0x0, 0x0, 0x0, 0x89D9, 0x0, 0x0, 0x8FD2, 0x0, + 0xE4C3, 0x0, 0x0, 0x0, 0x8DD8, 0x0, 0x0, 0x9370, + 0xE4C8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x95EC, 0x0, 0xE4BF, 0x0, 0x0, 0x0, 0x89D8, + 0x8CD4, 0x9548, 0xE4C9, 0x0, 0xE4BD, 0x0, 0x0, 0xE4C6, + 0x0, 0x0, 0x0, 0xE4D0, 0x0, 0xE4C1, 0x0, 0x0, +}; + +static u16 Ucs84[] = +{ + 0x0, 0x0, 0x0, 0xE4C2, 0x93B8, 0x0, 0x0, 0xE4C7, + 0x0, 0x0, 0x0, 0xE4C4, 0x9647, 0xE4CA, 0x88DE, 0x0, + 0x0, 0x0, 0x0, 0xE4BE, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE4CC, 0x0, 0xE4CB, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x948B, 0xE4D2, 0x0, 0xE4DD, 0x0, 0x0, 0x0, + 0x0, 0x8A9E, 0x0, 0x0, 0x0, 0xE4E0, 0x0, 0x0, + 0xE4CE, 0x0, 0x0, 0x0, 0xE4D3, 0x978E, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE4DC, 0x0, + 0x0, 0x9774, 0x0, 0x0, 0x0, 0x0, 0x97A8, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9298, + 0x0, 0x0, 0x0, 0x8A8B, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9592, 0xE4E2, 0x939F, 0x0, 0x0, 0x88AF, 0x0, + 0x0, 0xE4DB, 0x0, 0xE4D7, 0x9192, 0xE4D1, 0xE4D9, 0xE4DE, + 0x0, 0x944B, 0x0, 0x0, 0x0, 0x88A8, 0x0, 0xE4D6, + 0x0, 0xE4DF, 0x9598, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE4DA, 0x0, 0xE4D5, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8FD3, 0x0, 0x0, 0x0, 0x0, + 0x8F4E, 0x0, 0x0, 0x0, 0x8EAA, 0x0, 0x0, 0x0, + 0x0, 0x96D6, 0x0, 0x0, 0x9566, 0x0, 0x0, 0xE4E5, + 0x0, 0xE4EE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE4D8, 0x0, 0x0, + 0x0, 0x0, 0x8A97, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8FF6, 0xE4E3, 0x0, 0xE4E8, 0x9193, 0x0, 0x0, 0xE4E4, + 0x0, 0xE4EB, 0x0, 0x0, 0x927E, 0x0, 0xE4EC, 0x0, + 0x0, 0x9775, 0xE4E1, 0x8A57, 0x0, 0xE4E7, 0x0, 0x0, + 0xE4EA, 0x96AA, 0x0, 0x0, 0x0, 0x0, 0xE4ED, 0x0, + 0x0, 0xE4E6, 0xE4E9, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9648, 0x0, 0x9840, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE4F1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE4F8, 0x0, 0x0, 0xE4F0, +}; + +static u16 Ucs85[] = +{ + 0x8EC1, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE4CF, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x95CC, 0x0, 0x96A0, 0xE4F7, 0xE4F6, 0x0, 0xE4F2, + 0xE4F3, 0x0, 0x8955, 0x0, 0x0, 0x0, 0x0, 0xE4F5, + 0x0, 0xE4EF, 0x0, 0x0, 0x0, 0x0, 0x92D3, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE4F4, 0x88FC, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x91A0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x95C1, 0x0, 0x0, + 0xE4F9, 0xE540, 0x0, 0x94D7, 0x0, 0x0, 0x0, 0x0, + 0xE4FC, 0x8FD4, 0x8EC7, 0xE542, 0x0, 0x0, 0x8BBC, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE543, 0x0, 0x9599, + 0xE4FB, 0x0, 0xE4D4, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE4FA, 0x0, 0x0, 0x0, 0x0, + 0x986E, 0x93A0, 0x9593, 0x0, 0x0, 0xE54A, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE550, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE551, 0x0, + 0xE544, 0x0, 0x0, 0x0, 0x9496, 0x0, 0x0, 0xE54E, + 0xE546, 0x0, 0xE548, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE552, 0xE547, 0x0, 0x0, 0xE54B, 0x0, 0x0, 0x8992, + 0x0, 0x93E3, 0x0, 0xE54C, 0xE54F, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE545, 0x0, 0x9145, 0x0, + 0xE549, 0x8E46, 0x9064, 0x8C4F, 0x96F2, 0x0, 0x96F7, 0x8F92, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE556, 0xE554, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x986D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE553, 0x0, 0x0, 0x0, 0x9795, 0x0, 0xE555, + 0xE557, 0x0, 0x0, 0x0, 0x0, 0xE558, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE55B, 0xE559, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x93A1, 0xE55A, 0x0, 0x0, + 0x0, 0x94CB, 0xE54D, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8F93, + 0x0, 0xE55C, 0xE561, 0x9194, 0x0, 0x0, 0xE560, 0x0, +}; + +static u16 Ucs86[] = +{ + 0x0, 0x0, 0xE541, 0x0, 0x0, 0x0, 0xE562, 0x9168, + 0x0, 0x0, 0xE55D, 0xE55F, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE55E, 0x0, 0x0, 0x9F50, 0x9F41, + 0x0, 0x0, 0xE564, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE563, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9796, 0x0, 0xE1BA, + 0xE565, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE566, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE567, 0x8CD5, 0x0, + 0x8B73, 0x0, 0x0, 0x0, 0xE569, 0x997C, 0x0, 0x0, + 0x0, 0x0, 0x8B95, 0x0, 0x97B8, 0x0, 0x8BF1, 0xE56A, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE56B, + 0x0, 0x0, 0x0, 0x928E, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE56C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x93F8, 0x0, 0x88B8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x89E1, 0xE571, 0xE572, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE56D, 0x0, 0x8E5C, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE56E, 0x9461, 0x0, 0x0, 0x0, + 0x0, 0xE56F, 0xE570, 0xE57A, 0x0, 0x0, 0x0, 0xE574, + 0xE577, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE573, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE575, 0x0, 0xE576, 0x8ED6, + 0x0, 0xE578, 0x0, 0x9260, 0x0, 0x8C75, 0x8A61, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE57B, 0x0, 0x0, 0x0, + 0x0, 0x8A5E, 0x0, 0xE581, 0x0, 0x0, 0xE57C, 0xE580, + 0x0, 0x0, 0x0, 0x0, 0x94B8, 0x0, 0x0, 0x0, + 0x0, 0xE57D, 0x0, 0x0, 0xE57E, 0x9567, 0x94D8, 0xE582, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x91FB, 0xE58C, 0x0, 0xE588, 0x0, 0x0, 0x89E9, 0x0, +}; + +static u16 Ucs87[] = +{ + 0xE586, 0x0, 0x9649, 0xE587, 0x0, 0x0, 0xE584, 0x0, + 0xE585, 0xE58A, 0xE58D, 0x0, 0x0, 0xE58B, 0x0, 0x0, + 0x0, 0xE589, 0xE583, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9277, 0x0, 0xE594, 0x0, 0x96A8, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE592, 0x0, 0x0, + 0x0, 0xE593, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE58E, 0x0, 0x0, 0xE590, + 0x0, 0x0, 0x0, 0xE591, 0x0, 0x0, 0x0, 0xE58F, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x90E4, 0x0, 0x9858, 0xE598, 0x0, 0xE599, 0x0, + 0x0, 0x0, 0x0, 0xE59F, 0x0, 0x9049, 0x0, 0xE59B, + 0x0, 0xE59E, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE596, + 0xE595, 0x0, 0x0, 0xE5A0, 0x0, 0x0, 0x89DA, 0x0, + 0xE59C, 0x0, 0xE5A1, 0x0, 0x0, 0x0, 0xE59D, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE59A, 0x0, 0x92B1, 0x0, + 0xE597, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9488, + 0x0, 0x0, 0xE5A5, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x975A, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE5A4, + 0x0, 0x0, 0xE5A3, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE5AC, 0x0, 0x0, 0x0, 0xE5A6, + 0x0, 0x0, 0x0, 0xE5AE, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9786, 0xE5B1, 0x0, 0xE5A8, 0x0, 0x0, + 0xE5A9, 0x0, 0x0, 0x0, 0xE5AD, 0x0, 0xE5B0, 0xE5AF, + 0x0, 0x0, 0x0, 0xE5A7, 0x0, 0x0, 0x0, 0x0, + 0xE5AA, 0x0, 0xE5BB, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE5B4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE5B2, + 0x0, 0x0, 0xE5B3, 0x0, 0x0, 0x0, 0xE5B8, 0xE5B9, + 0x0, 0x8A49, 0x0, 0x8B61, 0x0, 0x0, 0xE5B7, 0x0, +}; + +static u16 Ucs88[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE5A2, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE5B6, 0xE5BA, 0xE5B5, + 0x0, 0xE5BC, 0x0, 0x0, 0x0, 0xE5BE, 0xE5BD, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE5C0, 0xE5BF, 0xE579, 0x0, 0x0, 0x0, 0xE5C4, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE5C1, 0x0, 0x0, 0x0, 0x0, 0xE5C2, 0x0, + 0x0, 0xE5C3, 0x0, 0xE5C5, 0x0, 0x0, 0x0, 0x0, + 0x8C8C, 0x0, 0xE5C7, 0x0, 0xE5C6, 0x0, 0x8F4F, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8D73, 0x9FA5, 0x0, 0x0, + 0x0, 0x0, 0xE5C8, 0x8F70, 0x0, 0x0, 0x0, 0x8A58, + 0x0, 0xE5C9, 0x0, 0x8971, 0x0, 0x8FD5, 0xE5CA, 0x0, + 0x0, 0x8D74, 0xE5CB, 0x88DF, 0x0, 0x0, 0x0, 0x0, + 0x955C, 0x0, 0x0, 0xE5CC, 0x0, 0x0, 0x0, 0x0, + 0x908A, 0x0, 0xE5D3, 0x0, 0x0, 0xE5D0, 0x0, 0x928F, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE5D1, 0xE5CE, 0x8BDC, + 0x0, 0xE5CD, 0xE5D4, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8C55, 0x0, 0x0, 0x91DC, 0x0, 0xE5DA, 0x0, 0x0, + 0x0, 0x0, 0xE5D6, 0x0, 0x0, 0x0, 0x91B3, 0xE5D5, + 0x0, 0xE5D8, 0x0, 0x0, 0x0, 0x0, 0xE5CF, 0x0, + 0x0, 0x0, 0xE5D9, 0x0, 0xE5DB, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x94ED, 0x0, 0x0, 0xE5D7, 0x0, + 0xE5DC, 0xE5DE, 0x0, 0x0, 0x8CD1, 0xE5D2, 0x0, 0x88BF, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE5DD, + 0x0, 0x8DD9, 0x97F4, 0xE5DF, 0xE5E0, 0x9195, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x97A0, + 0x0, 0x0, 0x0, 0x0, 0xE5E1, 0x9754, 0x0, 0x0, + 0xE5E2, 0xE5E3, 0x0, 0x0, 0x95E2, 0xE5E4, 0x0, 0x8DBE, + 0x0, 0x97A1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE5E9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE5EA, 0x8FD6, 0xE5E8, 0x0, 0x0, 0x0, + 0x9787, 0xE5E5, 0x0, 0x0, 0xE5E7, 0x90BB, 0x909E, 0x0, +}; + +static u16 Ucs89[] = +{ + 0x0, 0x0, 0xE5E6, 0x0, 0xE5EB, 0x0, 0x0, 0x95A1, + 0x0, 0x0, 0xE5ED, 0x0, 0xE5EC, 0x0, 0x0, 0x0, + 0x8A8C, 0x0, 0x964A, 0xE5EE, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE5FA, 0xE5F0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE5F1, 0x0, 0x0, + 0x0, 0x0, 0xE5F2, 0xE5F3, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE5F7, 0x0, + 0xE5F8, 0x0, 0x0, 0xE5F6, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE5F4, 0x0, 0xE5EF, 0xE5F5, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE5F9, 0xE8B5, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x89A6, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE5FC, 0x8BDD, + 0xE5FB, 0x0, 0x0, 0x0, 0xE641, 0x0, 0xE640, 0x0, + 0x0, 0x0, 0xE643, 0x0, 0x0, 0xE642, 0x0, 0xE644, + 0x0, 0x0, 0x8F50, 0x0, 0xE645, 0x0, 0x0, 0xE646, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE647, 0x90BC, + 0x0, 0x9776, 0x0, 0xE648, 0x0, 0x0, 0x95A2, 0x9465, + 0xE649, 0x0, 0xE64A, 0x8CA9, 0x0, 0x0, 0x0, 0x8B4B, + 0x0, 0x0, 0x0, 0xE64B, 0x0, 0x0, 0x8E8B, 0x9460, + 0xE64C, 0x0, 0x8A6F, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE64D, 0x0, 0x0, 0x0, 0x0, 0xE64F, 0x9797, + 0x0, 0xE64E, 0x9065, 0x0, 0xE650, 0x0, 0x0, 0xE651, + 0x0, 0x0, 0xE652, 0x8ACF, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE653, 0x0, 0x0, 0xE654, 0x0, 0xE655, + 0xE656, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8A70, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE657, 0x0, 0xE658, 0xE659, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x89F0, 0x0, 0x0, 0x9047, 0xE65A, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE65B, 0x0, 0x0, 0x0, + 0xE65C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs8A[] = +{ + 0x8CBE, 0x0, 0x92F9, 0xE65D, 0x0, 0x0, 0x0, 0x0, + 0x8C76, 0x0, 0x9075, 0x0, 0xE660, 0x0, 0x93A2, 0x0, + 0xE65F, 0x0, 0x0, 0x8C50, 0x0, 0x0, 0xE65E, 0x91F5, + 0x8B4C, 0x0, 0x0, 0xE661, 0x0, 0xE662, 0x0, 0x8FD7, + 0x0, 0x0, 0x0, 0x8C8D, 0x0, 0xE663, 0x0, 0x0, + 0x0, 0x0, 0x964B, 0x0, 0x0, 0x90DD, 0x0, 0x0, + 0x0, 0x8B96, 0x0, 0x96F3, 0x9169, 0x0, 0xE664, 0x0, + 0x0, 0x0, 0x9066, 0x9290, 0x8FD8, 0x0, 0x0, 0x0, + 0x0, 0xE665, 0x0, 0x0, 0x0, 0x0, 0xE668, 0x0, + 0xE669, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8DBC, 0x91C0, 0xE667, 0x0, 0x8FD9, 0x955D, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE666, 0x0, 0x0, 0x8E8C, 0x0, + 0x8972, 0x0, 0xE66D, 0x8C77, 0x0, 0x0, 0x8E8E, 0x0, + 0x0, 0x8E8D, 0x0, 0x986C, 0xE66C, 0xE66B, 0x9146, 0x0, + 0x8B6C, 0x9862, 0x8A59, 0x8FDA, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE66A, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE66F, 0x0, 0xE670, 0xE66E, 0x0, 0x8CD6, + 0x0, 0x975F, 0x0, 0x0, 0x8E8F, 0x9446, 0x0, 0x0, + 0x0, 0xE673, 0x0, 0x90BE, 0x0, 0x9261, 0x0, 0x0, + 0x9755, 0x0, 0xE676, 0x0, 0x0, 0x0, 0x8CEA, 0x0, + 0x90BD, 0xE672, 0x0, 0xE677, 0x8CEB, 0xE674, 0xE675, 0x0, + 0xE671, 0x0, 0x0, 0x0, 0x90E0, 0x93C7, 0x0, 0x0, + 0x924E, 0x0, 0x89DB, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x94EE, 0x0, 0x0, 0x8B62, 0x0, 0x0, 0x92B2, + 0x0, 0x0, 0xE67A, 0x0, 0xE678, 0x0, 0x0, 0x926B, + 0x0, 0x0, 0x0, 0x90BF, 0x8AD0, 0xE679, 0x0, 0x907A, + 0x0, 0x0, 0x97C8, 0x0, 0x0, 0x0, 0x985F, 0x0, + 0x0, 0x0, 0xE67B, 0xE687, 0x92B3, 0x0, 0xE686, 0x0, + 0xE683, 0xE68B, 0xE684, 0x0, 0xE680, 0x0, 0x92FA, 0xE67E, + 0x0, 0x0, 0x0, 0xE67C, 0x0, 0x9740, 0x8E90, 0x0, + 0x0, 0xE681, 0x0, 0xE67D, 0x0, 0x0, 0x0, 0xE685, + 0x8F94, 0x0, 0x8CBF, 0x0, 0x0, 0x0, 0x91F8, 0x0, +}; + +static u16 Ucs8B[] = +{ + 0x9664, 0x8979, 0x88E0, 0x0, 0x93A3, 0x0, 0x0, 0xE689, + 0x0, 0x0, 0x0, 0x0, 0xE688, 0x0, 0x93E4, 0x0, + 0xE68D, 0x0, 0x0, 0x0, 0xE682, 0x0, 0xE68C, 0xE68E, + 0x0, 0x8CAA, 0xE68A, 0x8D75, 0x0, 0x8ED3, 0x0, 0x0, + 0xE68F, 0x9777, 0x0, 0x0, 0x0, 0x0, 0xE692, 0x0, + 0xE695, 0x0, 0x0, 0xE693, 0x9554, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE690, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8BDE, 0x0, 0x0, 0x0, 0x0, 0xE694, 0x0, + 0x0, 0xE696, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE69A, 0x0, 0x0, 0xE697, 0x0, 0xE699, 0xE698, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE69B, 0x0, + 0x8EAF, 0x0, 0xE69D, 0xE69C, 0x9588, 0x0, 0x0, 0xE69F, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8C78, 0x0, + 0x0, 0x0, 0x0, 0xE69E, 0xE6A0, 0x0, 0x0, 0xE6A1, + 0x8B63, 0xE3BF, 0x8FF7, 0x0, 0xE6A2, 0x0, 0x0, 0x8CEC, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE6A3, 0x0, 0x0, + 0xE6A4, 0x0, 0x0, 0x8E5D, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9DCC, 0x0, 0xE6A5, 0x0, 0xE6A6, 0x0, + 0x8F51, 0x0, 0xE6A7, 0xE6A8, 0x0, 0x0, 0xE6A9, 0x0, + 0x0, 0xE6AA, 0xE6AB, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs8C[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x924A, + 0x0, 0x0, 0xE6AC, 0x0, 0x0, 0x0, 0x0, 0xE6AE, + 0x0, 0xE6AD, 0x0, 0x0, 0x0, 0x0, 0x93A4, 0x0, + 0xE6AF, 0x0, 0x964C, 0x0, 0xE6B0, 0x0, 0xE6B1, 0x0, + 0xE6B2, 0x0, 0x0, 0x0, 0x0, 0xE6B3, 0x0, 0x0, + 0x0, 0x0, 0x93D8, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8FDB, 0xE6B4, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8D8B, 0x98AC, 0xE6B5, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE6B6, 0x955E, 0xE6B7, 0x0, 0xE6BF, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE6B8, 0x0, 0x0, 0xE6BA, 0x0, 0x0, + 0x0, 0xE6B9, 0xE6BB, 0x0, 0x9665, 0xE6BC, 0xE6BD, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE6BE, 0x0, 0x0, 0x0, + 0xE6C0, 0x0, 0x0, 0x0, 0x0, 0x8A4C, 0x92E5, 0x0, + 0x9589, 0x8DE0, 0x8D76, 0x0, 0x0, 0x0, 0x0, 0x956E, + 0x89DD, 0x94CC, 0xE6C3, 0x8AD1, 0x90D3, 0xE6C2, 0xE6C7, 0x9299, + 0x96E1, 0x0, 0xE6C5, 0xE6C6, 0x8B4D, 0x0, 0xE6C8, 0x9483, + 0x91DD, 0x0, 0x0, 0x94EF, 0x935C, 0xE6C4, 0x0, 0x9666, + 0x89EA, 0xE6CA, 0x9847, 0x92C0, 0x9864, 0x0, 0x0, 0x8E91, + 0xE6C9, 0x0, 0x91AF, 0x0, 0x0, 0xE6DA, 0x9147, 0x0, + 0x0, 0x93F6, 0x0, 0x956F, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE6CD, 0x8E5E, 0x8E92, 0x0, 0x8FDC, 0x0, + 0x9485, 0x0, 0x8CAB, 0xE6CC, 0xE6CB, 0x0, 0x958A, 0x0, + 0x0, 0x0, 0x8EBF, 0x0, 0x0, 0x9371, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE6CF, 0xE6D0, 0x8D77, 0xE6CE, 0x0, 0x0, +}; + +static u16 Ucs8D[] = +{ + 0x0, 0x0, 0x0, 0x0, 0xE6D1, 0xE6D2, 0x0, 0xE6D4, + 0x91A1, 0x0, 0xE6D3, 0x8AE4, 0x0, 0xE6D6, 0x0, 0xE6D5, + 0xE6D7, 0x0, 0x0, 0xE6D9, 0xE6DB, 0x0, 0xE6DC, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x90D4, 0x0, 0x8ECD, 0xE6DD, + 0x0, 0x0, 0x0, 0x8A71, 0x0, 0xE6DE, 0x0, 0x0, + 0x9196, 0xE6DF, 0x0, 0xE6E0, 0x958B, 0x0, 0x0, 0x8B4E, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE6E1, 0x0, 0x0, 0x0, 0x92B4, 0x0, 0x0, + 0x0, 0x0, 0x897A, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE6E2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8EEF, 0x0, 0x0, 0x0, 0x0, + 0x9096, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x91AB, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE6E5, 0x0, 0x0, 0x0, 0xE6E4, 0x0, + 0x0, 0x0, 0xE6E3, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE6EB, 0xE6E9, 0x0, 0x0, 0xE6E6, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE6E8, 0x0, + 0x0, 0x0, 0xE6E7, 0xE6EA, 0x0, 0x8B97, 0x0, 0xE6EE, + 0x0, 0x90D5, 0x0, 0xE6EF, 0x0, 0x0, 0x0, 0x0, + 0x8CD7, 0x0, 0xE6EC, 0xE6ED, 0x0, 0x0, 0x0, 0x9848, + 0x0, 0x0, 0x0, 0x92B5, 0x0, 0x9148, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE6F0, 0x0, 0x0, 0xE6F3, +}; + +static u16 Ucs8E[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE6F1, 0xE6F2, 0x9778, 0x0, 0x0, 0x0, 0x0, 0x93A5, + 0xE6F6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE6F4, 0xE6F5, 0xE6F7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE748, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE6FA, 0x0, 0x0, 0x0, 0xE6FB, 0xE6F9, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE6F8, 0x0, 0x92FB, 0x0, 0x0, 0xE740, + 0xE744, 0xE741, 0xE6FC, 0x0, 0xE742, 0x0, 0x0, 0x0, + 0xE743, 0x0, 0x0, 0x0, 0x0, 0xE74A, 0x0, 0x0, + 0x0, 0xE745, 0x0, 0x0, 0x0, 0x0, 0x0, 0x90D6, + 0xE747, 0x0, 0x0, 0xE749, 0xE746, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE74C, 0x0, 0x8F52, 0x0, 0xE74B, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE74D, 0x0, 0x0, 0x0, + 0x0, 0xE74E, 0x0, 0x0, 0xE751, 0xE750, 0x0, 0xE74F, + 0x0, 0x0, 0xE753, 0xE752, 0x0, 0x96F4, 0x0, 0x0, + 0x0, 0xE755, 0x0, 0xE754, 0xE756, 0x0, 0x0, 0x0, + 0x0, 0xE757, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE759, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE758, 0x9067, 0xE75A, 0x0, 0x0, 0x8BEB, + 0xE75B, 0xE75D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE75E, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE75F, 0xE75C, 0x0, + 0xE760, 0x0, 0x8ED4, 0xE761, 0x8B4F, 0x8C52, 0x0, 0x0, + 0x0, 0x0, 0x8CAC, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE762, 0x0, 0x0, 0x0, 0x93EE, + 0x0, 0x0, 0x935D, 0xE763, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE766, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8EB2, 0x0, 0x0, 0xE765, 0xE764, 0x8C79, 0xE767, 0x0, +}; + +static u16 Ucs8F[] = +{ + 0x0, 0x0, 0x0, 0x8A72, 0x0, 0xE769, 0x0, 0x0, + 0x0, 0x8DDA, 0xE768, 0x0, 0xE771, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE76B, 0xE76D, 0x95E3, 0xE76A, 0x0, 0x0, + 0x0, 0xE76C, 0x0, 0xE770, 0xE76E, 0x8B50, 0x0, 0xE76F, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE772, 0x0, + 0x0, 0x9479, 0x97D6, 0x0, 0x0, 0x0, 0x0, 0x8F53, + 0x0, 0x0, 0x0, 0xE773, 0x0, 0x0, 0x0, 0x0, + 0x9741, 0xE775, 0x0, 0xE774, 0x0, 0x0, 0xE778, 0x9760, + 0x0, 0x0, 0xE777, 0x0, 0x8A8D, 0xE776, 0xE77B, 0x0, + 0x0, 0xE77A, 0x0, 0x0, 0xE779, 0x9351, 0xE77C, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE77D, + 0x0, 0x0, 0x0, 0x0, 0xE77E, 0x0, 0x0, 0x8D8C, + 0x0, 0x8C44, 0xE780, 0xE781, 0xE782, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9068, 0xE783, 0x0, 0x8EAB, 0xE784, + 0x0, 0x0, 0x0, 0xE785, 0x0, 0x0, 0x0, 0x999F, + 0x999E, 0x0, 0x0, 0x0, 0x0, 0xE786, 0xE390, 0xE787, + 0x9243, 0x904A, 0x945F, 0x0, 0x0, 0x0, 0x0, 0xE788, + 0x0, 0x0, 0x95D3, 0x92D2, 0x8D9E, 0x0, 0x0, 0x9248, + 0x0, 0x0, 0x8949, 0x0, 0x9698, 0x9076, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8C7D, 0x0, + 0x0, 0x8BDF, 0x0, 0x0, 0x95D4, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE789, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE78B, 0x0, 0x0, 0xE78A, 0x89DE, 0x0, + 0x0, 0x93F4, 0xE78C, 0x9497, 0x0, 0x9352, 0x0, 0xE78D, + 0x8F71, 0x0, 0x0, 0x0, 0xE78F, 0x0, 0x0, 0x96C0, + 0xE79E, 0xE791, 0xE792, 0x0, 0x0, 0x92C7, 0x0, 0x0, +}; + +static u16 Ucs90[] = +{ + 0x91DE, 0x9197, 0x0, 0x93A6, 0x0, 0xE790, 0x8B74, 0x0, + 0x0, 0x0, 0x0, 0xE799, 0x0, 0xE796, 0xE7A3, 0x93A7, + 0x9280, 0xE793, 0x0, 0x92FC, 0x9372, 0xE794, 0xE798, 0x9080, + 0x0, 0x9487, 0x92CA, 0x0, 0x0, 0x90C0, 0xE797, 0x91AC, + 0x91A2, 0xE795, 0x88A7, 0x9841, 0x0, 0x0, 0x0, 0xE79A, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x91DF, 0x0, + 0x0, 0x8F54, 0x9069, 0x0, 0x0, 0xE79C, 0xE79B, 0x0, + 0x88ED, 0xE79D, 0x0, 0x0, 0x954E, 0x0, 0xE7A5, 0x0, + 0x0, 0x93D9, 0x908B, 0x0, 0x0, 0x9278, 0x0, 0x8BF6, + 0x0, 0xE7A4, 0x9756, 0x895E, 0x0, 0x95D5, 0x89DF, 0xE79F, + 0xE7A0, 0xE7A1, 0xE7A2, 0x93B9, 0x9242, 0x88E1, 0xE7A6, 0x0, + 0xE7A7, 0xEAA1, 0x0, 0x0, 0x91BB, 0x0, 0xE7A8, 0x0, + 0x8993, 0x916B, 0x0, 0x8CAD, 0x0, 0x9779, 0x0, 0x0, + 0xE7A9, 0x934B, 0x0, 0x0, 0x0, 0x9198, 0x8ED5, 0xE7AA, + 0x0, 0x0, 0xE7AD, 0x0, 0x0, 0x8F85, 0xE7AB, 0x914A, + 0x9149, 0x0, 0x88E2, 0x0, 0x97C9, 0xE7AF, 0x0, 0x94F0, + 0xE7B1, 0xE7B0, 0xE7AE, 0xE284, 0x8AD2, 0x0, 0x0, 0xE78E, + 0x0, 0xE7B3, 0xE7B2, 0x0, 0x0, 0x0, 0x0, 0xE7B4, + 0x0, 0x9757, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x93DF, 0x0, 0x0, 0x964D, 0x0, + 0xE7B5, 0x0, 0x8ED7, 0x0, 0x0, 0x0, 0x0, 0xE7B6, + 0x0, 0xE7B7, 0x0, 0x0, 0x0, 0xE7B8, 0x0, 0x0, + 0x9340, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x88E8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x8D78, 0x0, 0x0, 0x0, 0x9859, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE7BC, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8C53, 0xE7B9, 0x0, 0xE7BA, 0x0, 0x0, 0x0, + 0x9594, 0x0, 0x0, 0x0, 0x0, 0x8A73, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9758, 0x0, 0x8BBD, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9373, 0x0, 0x0, +}; + +static u16 Ucs91[] = +{ + 0x0, 0x0, 0xE7BD, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE7BE, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE7BF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9341, 0x0, 0x0, + 0xE7C1, 0x0, 0xE7C0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x93D1, 0xE7C2, 0x8F55, 0x8EDE, 0x947A, 0x9291, 0x0, + 0x0, 0x0, 0x8EF0, 0x0, 0x908C, 0x0, 0xE7C3, 0x0, + 0xE7C4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x907C, 0xE7C5, 0x0, 0xE7C6, 0x0, 0x0, + 0x0, 0xE7C7, 0x978F, 0x0, 0x8F56, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE7C9, 0xE7C8, 0x0, 0x8D79, 0x0, 0x8D93, + 0x8E5F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE7CC, 0x0, 0x0, 0x0, 0x0, 0x8F86, + 0x0, 0xE7CB, 0x0, 0xE7CA, 0x0, 0x91E7, 0x0, 0x0, + 0x8CED, 0x0, 0x90C1, 0x0, 0x0, 0x0, 0x0, 0x94AE, + 0x0, 0x0, 0x0, 0x0, 0x8F58, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE7CD, 0x0, 0x8FDD, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE7D0, 0xE7CE, 0x0, 0x0, 0x0, 0xE7CF, + 0x0, 0x0, 0x0, 0x0, 0xE7D2, 0xE7D1, 0x0, 0x0, + 0x8FF8, 0x0, 0xE7D3, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE7D4, 0xE7D5, 0x0, 0x0, 0x0, 0x0, 0x94CE, 0x8DD1, + 0x8EDF, 0xE7D6, 0x0, 0xE7D7, 0x97A2, 0x8F64, 0x96EC, 0x97CA, + 0xE7D8, 0x8BE0, 0x0, 0x0, 0x0, 0x0, 0xE7D9, 0x0, + 0x9342, 0x0, 0x0, 0xE7DC, 0x8A98, 0x906A, 0x0, 0xE7DA, + 0x0, 0xE7DB, 0x0, 0x92DE, 0x0, 0x0, 0x9674, 0x8BFA, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE7DE, 0xE7DF, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE7DD, 0x0, 0x0, 0xE7E1, +}; + +static u16 Ucs92[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x93DD, 0x8A62, 0x0, + 0x0, 0xE7E5, 0x0, 0x0, 0xE7E2, 0xE7E4, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE7E0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE86E, 0x0, 0x0, 0xE7E3, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x97E9, 0x0, 0x0, 0x8CD8, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE7ED, + 0x0, 0x0, 0x0, 0x0, 0x9353, 0xE7E8, 0x0, 0x0, + 0xE7EB, 0xE7E9, 0x0, 0xE7EE, 0x0, 0x0, 0x0, 0x0, + 0xE7EF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE7E7, + 0x0, 0x0, 0xE7F4, 0x8994, 0x0, 0x0, 0xE7E6, 0x0, + 0x0, 0x0, 0x94AB, 0x0, 0xE7EA, 0x0, 0x8FDE, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8D7A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9667, 0x0, + 0x8BE2, 0x0, 0x0, 0x8F65, 0x0, 0x93BA, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x914C, 0x0, 0xE7F2, 0x0, 0xE7EC, 0xE7F1, 0x0, + 0x96C1, 0x0, 0x92B6, 0xE7F3, 0xE7F0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x914B, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE7F7, + 0x0, 0xE7F6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE7F5, + 0x0, 0x0, 0x964E, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8F9B, 0x0, 0x0, 0x0, + 0x0, 0xE7F8, 0x95DD, 0x0, 0x0, 0x8973, 0x0, 0x0, + 0x0, 0x0, 0x9565, 0x9292, 0x0, 0x0, 0x0, 0x0, + 0x8B98, 0x0, 0xE7FA, 0x0, 0x8D7C, 0x0, 0x0, 0x0, +}; + +static u16 Ucs93[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8E4B, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE7F9, + 0x908D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x908E, 0xE840, 0xE842, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8FF9, 0x0, 0xE841, 0xE843, 0x0, 0x0, 0x8BD1, 0x0, + 0x9564, 0x0, 0x0, 0x8EE0, 0x9842, 0x0, 0xE7FC, 0x8DF6, + 0x0, 0x0, 0x985E, 0x0, 0x0, 0xE845, 0x0, 0x0, + 0x0, 0x0, 0xE844, 0xE846, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE7FB, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x93E7, 0x0, 0x9374, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x92D5, 0x0, 0xE84B, 0x0, + 0x0, 0x0, 0x0, 0x9262, 0xE847, 0x0, 0x0, 0x0, + 0xE848, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8C4C, 0x0, 0xE84A, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8CAE, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE849, 0x0, 0x8FDF, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8A99, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE84F, 0x0, 0x8DBD, 0x9199, + 0x0, 0x0, 0x92C8, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8A5A, + 0x0, 0x0, 0x0, 0x0, 0xE84D, 0xE84E, 0x92C1, 0x0, + 0xE84C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE850, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE856, 0x0, 0x0, 0x0, 0x0, + 0xE859, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE858, 0x934C, 0x0, 0x0, 0x0, 0x0, 0xE851, 0xE852, + 0xE855, 0x0, 0x0, 0x0, 0x0, 0xE857, 0x0, 0x0, + 0x0, 0x8BBE, 0x0, 0x0, 0xE85A, 0xE854, 0x0, 0x0, + 0xE853, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs94[] = +{ + 0x0, 0x0, 0x0, 0xE85E, 0x0, 0x0, 0x0, 0xE85F, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE860, 0x0, 0x0, 0xE85D, 0xE85C, 0x0, 0x0, 0x0, + 0x8FE0, 0x93A8, 0xE85B, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE864, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE862, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE863, 0xE861, 0x0, + 0x91F6, 0x0, 0xE865, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE866, 0x0, 0x0, 0xE868, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8AD3, 0xE867, 0x96F8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE873, 0xE869, 0x0, 0x0, 0xE86C, 0x0, + 0xE86A, 0x0, 0xE86B, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xE86D, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE86F, 0x0, 0x0, 0x0, 0x0, 0xE870, 0x0, 0xE871, + 0x0, 0x0, 0x0, 0x0, 0xE874, 0xE872, 0xE875, 0xE877, + 0x0, 0xE876, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs95[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x92B7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x96E5, 0x0, 0xE878, 0x914D, 0x0, 0x0, 0x0, 0xE879, + 0x0, 0x95C2, 0xE87A, 0x8A4A, 0x0, 0x0, 0x0, 0x895B, + 0x0, 0x8AD5, 0x0, 0x8AD4, 0xE87B, 0x0, 0xE87C, 0x0, + 0xE87D, 0xE87E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE880, 0x0, 0x8AD6, 0x8A74, 0x8D7D, 0x94B4, 0x0, 0xE882, + 0xE881, 0x0, 0x0, 0x0, 0x0, 0xE883, 0x0, 0x0, + 0x0, 0x0, 0x897B, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE886, 0x0, 0xE885, 0xE884, 0x0, 0xE887, 0x0, + 0x0, 0x0, 0x0, 0xE88A, 0x0, 0x0, 0x0, 0x88C5, + 0x0, 0x0, 0xE888, 0x0, 0xE88C, 0xE88B, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE88E, 0xE88D, 0xE88F, 0x0, + 0x93AC, 0x0, 0x0, 0x0, 0xE890, 0x0, 0x0, 0x0, + 0x0, 0xE891, 0xE893, 0x0, 0x0, 0xE892, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs96[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x958C, 0x0, 0x0, 0x0, + 0x0, 0xE894, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE895, 0x0, 0x8DE3, 0x0, 0x0, 0x0, 0xE896, 0xE897, + 0x0, 0x0, 0x9668, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x916A, 0x0, 0x0, 0x0, 0x88A2, + 0x91C9, 0x0, 0xE898, 0x0, 0x958D, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE89B, 0xE899, 0x8D7E, 0x0, 0xE89A, + 0x8CC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x95C3, 0xE89D, 0xE89F, 0xE89E, 0xE8A0, + 0x0, 0x0, 0x8940, 0x9077, 0x8F9C, 0x8AD7, 0xE8A1, 0x0, + 0x0, 0x0, 0x9486, 0x0, 0xE8A3, 0x0, 0x0, 0x0, + 0x8941, 0x0, 0xE8A2, 0x92C2, 0x0, 0x97CB, 0x93A9, 0xE89C, + 0x97A4, 0x0, 0x8CAF, 0x0, 0x0, 0x977A, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8BF7, 0x97B2, 0x0, + 0x8C47, 0x0, 0x91E0, 0xE440, 0x0, 0xE8A4, 0x8A4B, 0x908F, + 0x0, 0x0, 0x0, 0x0, 0x8A75, 0xE8A6, 0x0, 0xE8A7, + 0xE8A5, 0x8C84, 0x0, 0x8DDB, 0x8FE1, 0x0, 0x0, 0x0, + 0x8942, 0x0, 0x0, 0x97D7, 0x0, 0x0, 0x0, 0xE8A9, + 0xE7AC, 0x0, 0xE8A8, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE8AC, 0xE8AA, 0xE8AB, 0x0, 0xE8AD, 0x0, 0xE8AE, 0x97EA, + 0xE8AF, 0xE8B0, 0x0, 0x90C7, 0x94B9, 0x0, 0x0, 0x0, + 0x909D, 0x8AE5, 0x0, 0x0, 0x9759, 0x89EB, 0x8F57, 0x8CD9, + 0x0, 0xE8B3, 0x0, 0xE8B2, 0x8E93, 0xE8B4, 0xE8B1, 0x0, + 0x0, 0x8E47, 0x0, 0x0, 0x0, 0xE8B8, 0xE5AB, 0x0, + 0x0, 0x99D4, 0x0, 0x9097, 0xE8B6, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x97A3, 0x93EF, 0x0, 0x0, 0x0, 0x0, + 0x894A, 0x0, 0x90E1, 0x8EB4, 0x0, 0x0, 0x0, 0x0, + 0x95B5, 0x0, 0x895F, 0x0, 0x0, 0x0, 0x97EB, 0x978B, + 0x0, 0xE8B9, 0x0, 0x9364, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs97[] = +{ + 0x8EF9, 0x0, 0x0, 0x0, 0xE8BA, 0x0, 0xE8BB, 0x906B, + 0xE8BC, 0x0, 0x97EC, 0x0, 0x0, 0xE8B7, 0xE8BE, 0xE8C0, + 0x0, 0xE8BF, 0x0, 0xE8BD, 0x0, 0x0, 0xE8C1, 0x0, + 0x0, 0xE8C2, 0x0, 0x0, 0x919A, 0x0, 0x89E0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE8C3, 0x0, 0x0, 0x96B6, + 0x0, 0x0, 0xE8C4, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE8C5, 0x0, 0x9849, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9E50, 0xE8C6, 0x0, 0x0, 0x0, 0xE8C7, 0xE8C8, 0x0, + 0x0, 0x0, 0xE8CC, 0x0, 0xE8C9, 0x0, 0xE8CA, 0x0, + 0xE8CB, 0xE8CD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x90C2, 0x0, 0x0, 0x0, 0x96F5, 0x0, + 0x0, 0x90C3, 0x0, 0x0, 0xE8CE, 0x0, 0x94F1, 0x0, + 0xE8CF, 0xEA72, 0x96CA, 0x0, 0xE8D0, 0x0, 0xE8D1, 0x0, + 0xE8D2, 0x8A76, 0x0, 0xE8D4, 0x0, 0x9078, 0x0, 0x0, + 0x0, 0xE8D5, 0x0, 0x0, 0x8C43, 0x0, 0x0, 0x0, + 0x0, 0xE8D6, 0xE8DA, 0x0, 0xE8D8, 0x0, 0x0, 0x0, + 0x0, 0xE8D9, 0x0, 0x0, 0x8A93, 0xE8D7, 0xE8DB, 0x0, + 0x0, 0x0, 0x0, 0xE8DC, 0x0, 0x88C6, 0x0, 0xE8DD, + 0xE8DE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8FE2, 0x0, 0x0, 0x0, 0xE8DF, 0x0, 0x0, 0x0, + 0x8B66, 0x0, 0x0, 0xE8E2, 0x0, 0x0, 0xE8E1, 0x0, + 0xE8E0, 0x0, 0x0, 0xE691, 0x0, 0x95DA, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE8E3, 0xE8E4, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE8E5, 0x0, 0x0, 0xE8E6, 0x0, + 0xE8E7, 0x0, 0x0, 0xE8E8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8AD8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE8E9, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE8EA, 0x9442, 0x0, + 0x0, 0x0, 0xE8EC, 0x89B9, 0x0, 0xE8EF, 0xE8EE, 0x0, + 0x0, 0x0, 0x0, 0x8943, 0x0, 0x0, 0x0, 0x8BBF, +}; + +static u16 Ucs98[] = +{ + 0x0, 0x95C5, 0x92B8, 0x8DA0, 0x0, 0x8D80, 0x8F87, 0x0, + 0x907B, 0x0, 0x0, 0x0, 0xE8F1, 0x0, 0x0, 0xE8F0, + 0x9761, 0x8AE6, 0x94D0, 0x93DA, 0x0, 0x0, 0x0, 0x909C, + 0x97CC, 0x0, 0x8C7A, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE8F4, 0x0, 0x0, 0xE8F3, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x966A, 0x93AA, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x896F, 0x0, 0x0, 0xE8F5, + 0xE8F2, 0x0, 0x0, 0x9570, 0x978A, 0xE8F6, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE8F7, 0x0, + 0x0, 0x0, 0x0, 0xE8F9, 0x91E8, 0x8A7A, 0x8A7B, 0xE8F8, + 0x0, 0x0, 0x0, 0x0, 0x8AE7, 0x8CB0, 0x0, 0x0, + 0x8AE8, 0x0, 0x0, 0x935E, 0x0, 0x0, 0x97DE, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8CDA, + 0x0, 0x0, 0x0, 0xE8FA, 0x0, 0x0, 0x0, 0xE8FB, + 0xE8FC, 0xE940, 0x0, 0xE942, 0xE941, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9597, 0x0, 0xE943, 0x0, 0x0, 0x0, 0x0, 0xE944, + 0x0, 0xE945, 0x0, 0x0, 0x0, 0x0, 0xE946, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE948, 0xE947, 0x0, 0xE949, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x94F2, 0xE3CA, 0x0, 0x0, 0x9048, + 0x0, 0x0, 0x8B51, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE94A, 0x0, 0xE94B, 0x0, 0x99AA, 0x9F5A, 0x94D1, + 0x0, 0x0, 0x88F9, 0x0, 0x88B9, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8E94, 0x964F, 0x8FFC, 0x0, +}; + +static u16 Ucs99[] = +{ + 0x0, 0x0, 0x0, 0xE94C, 0x0, 0x96DD, 0x0, 0x0, + 0x0, 0xE94D, 0x977B, 0x0, 0x8961, 0x0, 0x0, 0x0, + 0x8E60, 0x0, 0xE94E, 0x89EC, 0xE94F, 0x0, 0x0, 0x0, + 0xE950, 0x0, 0x0, 0x0, 0x0, 0xE952, 0xE953, 0x0, + 0xE955, 0xE951, 0x0, 0x0, 0xE954, 0x0, 0x0, 0x0, + 0x8AD9, 0x0, 0x0, 0x0, 0xE956, 0x0, 0xE957, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE958, 0xE959, 0x0, + 0x0, 0x0, 0xE95A, 0x0, 0x0, 0xE95C, 0x0, 0x0, + 0x0, 0xE95B, 0x0, 0xE95E, 0xE961, 0x0, 0x0, 0x0, + 0xE95D, 0xE95F, 0xE960, 0x0, 0x0, 0xE962, 0x0, 0x8BC0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8EF1, 0xE963, + 0xE964, 0x8D81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE965, 0x0, 0x0, + 0x8A5D, 0x0, 0x0, 0x0, 0x946E, 0xE966, 0xE967, 0x0, + 0x0, 0x0, 0x0, 0x9279, 0x93E9, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE968, 0x0, 0x0, 0x0, + 0x0, 0x949D, 0x0, 0x0, 0x91CA, 0x8977, 0x8BEC, 0x0, + 0x8BED, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9293, 0xE96D, 0x8BEE, 0x0, 0x0, 0x89ED, 0x0, 0x0, + 0xE96C, 0x0, 0x0, 0xE96A, 0x0, 0xE96B, 0x0, 0xE969, + 0x0, 0x0, 0xE977, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE96E, 0xE96F, 0x0, + 0x0, 0xE970, 0xE971, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE973, 0x0, 0x0, 0xE972, 0x0, 0x0, 0x0, 0x8F78, +}; + +static u16 Ucs9A[] = +{ + 0x0, 0xE974, 0x0, 0x0, 0x0, 0xE976, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8B52, 0xE975, + 0x0, 0x0, 0x919B, 0x8CB1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE978, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x91CB, 0x0, 0x0, 0xE979, 0x0, 0x0, 0x0, 0x0, + 0x93AB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE97A, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE980, 0x0, + 0xE97D, 0x0, 0xE97C, 0xE97E, 0x0, 0xE97B, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE982, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE981, 0x0, 0xE984, + 0x0, 0x0, 0x8BC1, 0xE983, 0x0, 0x0, 0x0, 0xE985, + 0x0, 0x0, 0xE986, 0x0, 0xE988, 0xE987, 0x0, 0x0, + 0x0, 0xE989, 0xE98B, 0xE98A, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8D9C, 0x0, 0x0, 0x0, 0x0, 0xE98C, 0x0, 0x0, + 0xE98D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x8A5B, 0x0, 0x0, 0x0, 0xE98E, 0x0, 0x0, 0x0, + 0xE98F, 0x0, 0x0, 0x0, 0x9091, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE990, + 0x0, 0xE991, 0x0, 0xE992, 0xE993, 0x0, 0x0, 0x0, + 0x8D82, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE994, 0xE995, + 0x0, 0x0, 0xE996, 0xE997, 0x0, 0x0, 0xE998, 0x0, + 0x0, 0x0, 0x94AF, 0xE99A, 0x0, 0x9545, 0xE99B, 0xE999, + 0x0, 0xE99D, 0x0, 0x0, 0xE99C, 0x0, 0x0, 0xE99E, + 0x0, 0x0, 0x0, 0xE99F, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs9B[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE9A0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE9A1, 0x0, 0xE9A2, 0x0, 0x0, 0x0, 0x0, 0xE9A3, + 0x0, 0x0, 0xE9A4, 0xE9A5, 0x0, 0xE9A6, 0x0, 0xE9A7, + 0xE9A8, 0xE9A9, 0xE9AA, 0x0, 0x0, 0x0, 0xE9AB, 0xE9AC, + 0x0, 0x9F54, 0xE9AD, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE2F6, 0x8B53, 0x0, 0x0, 0x0, + 0x0, 0x8A40, 0x8DB0, 0xE9AF, 0xE9AE, 0x96A3, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xE9B1, 0xE9B2, 0xE9B0, + 0x0, 0xE9B3, 0x0, 0x0, 0x9682, 0x0, 0x0, 0x0, + 0xE9B4, 0x0, 0x8B9B, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9844, + 0x0, 0x0, 0x0, 0x0, 0xE9B5, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE9B7, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88BC, 0x0, + 0x0, 0xE9B8, 0x95A9, 0xE9B6, 0x0, 0x0, 0xE9B9, 0xE9BA, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE9BB, + 0xE9BC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE9BD, 0x0, 0x968E, 0x8E4C, 0x0, 0x8DF8, 0x914E, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xE9BE, 0x0, 0x0, 0x0, + 0x0, 0xE9C1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE9BF, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE9C2, 0x0, + 0x0, 0x8CEF, 0xE9C0, 0x0, 0x0, 0x0, 0x0, 0xE9C3, + 0x0, 0xE9C4, 0xE9C5, 0x0, 0xE9C9, 0x0, 0x8E49, 0x0, + 0x0, 0x0, 0x0, 0x91E2, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE9CA, 0xE9C7, 0xE9C6, 0xE9C8, 0x0, 0x0, 0x0, + 0x8C7E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE9CE, 0xE9CD, 0xE9CC, 0x0, 0x0, 0x88B1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs9C[] = +{ + 0x0, 0x0, 0x0, 0x0, 0xE9D8, 0x0, 0xE9D4, 0x0, + 0xE9D5, 0xE9D1, 0xE9D7, 0x0, 0xE9D3, 0x8A82, 0x0, 0x0, + 0x986B, 0x0, 0xE9D6, 0xE9D2, 0xE9D0, 0xE9CF, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xE9DA, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xE9DD, 0x0, 0x0, 0xE9DC, 0xE9DB, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9568, 0xE9D9, 0x88F1, + 0xE9DE, 0x0, 0xE9E0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8A8F, 0xE9CB, 0x8956, 0x0, 0x0, 0xE9E2, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE9E1, 0xE9DF, + 0x924C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x9690, 0x0, 0x0, 0x0, 0x0, 0x97D8, + 0x0, 0x0, 0xE9E3, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xE9E4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE9E5, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE9E6, 0x0, + 0xE9E7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x92B9, 0x0, 0xE9E8, + 0x0, 0x94B5, 0x0, 0xE9ED, 0xE9E9, 0x0, 0x0, 0x0, + 0xE9EA, 0x0, 0x0, 0x9650, 0x96C2, 0x0, 0x93CE, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 Ucs9D[] = +{ + 0x0, 0x0, 0x0, 0xE9EE, 0x0, 0x0, 0xE9EF, 0x93BC, + 0xE9EC, 0xE9EB, 0x0, 0x0, 0x0, 0x0, 0x89A8, 0x0, + 0x0, 0x0, 0xE9F7, 0x0, 0x0, 0xE9F6, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8995, 0x0, 0x0, 0x0, 0xE9F4, + 0x0, 0x0, 0x0, 0xE9F3, 0x0, 0x0, 0xE9F1, 0x0, + 0x8A9B, 0x0, 0xE9F0, 0x8EB0, 0x89A7, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8D83, 0x0, 0x0, 0xE9FA, 0xE9F9, + 0x0, 0xE9F8, 0x0, 0x0, 0xE9F5, 0x0, 0xE9FB, 0x0, + 0xE9FC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xEA44, 0xEA43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xEA45, 0x0, 0x0, 0x894C, 0xEA40, 0xEA41, 0x0, + 0x8D94, 0x96B7, 0x0, 0x0, 0xEA42, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x9651, 0x0, 0x0, 0xEA4A, + 0x0, 0x0, 0xEA46, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xEA4B, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xEA48, + 0x0, 0xEA47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8C7B, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xEA4C, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xEA4D, 0x0, 0x0, 0x0, + 0x0, 0xEA4E, 0x0, 0xEA49, 0x0, 0x0, 0x0, 0xE9F2, + 0x0, 0x0, 0xEA4F, 0x0, 0x92DF, 0x0, 0x0, 0x0, + 0xEA53, 0x0, 0xEA54, 0xEA52, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xEA51, 0xEA57, 0x0, 0xEA50, 0x0, 0xEA55, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xEA56, + 0x0, 0x0, 0x0, 0xEA59, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xEA58, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xEA5B, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xEA5C, 0x0, 0xEA5D, + 0x0, 0x0, 0x9868, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xEA5A, 0x91E9, 0x8DEB, 0x0, 0x0, 0xEA5E, 0x0, 0x0, +}; + +static u16 Ucs9E[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xEA5F, 0xEA60, 0x0, 0x0, 0xEA61, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xEA62, 0x0, 0x0, + 0x8CB2, 0xEA63, 0x0, 0x0, 0x0, 0xEA64, 0x0, 0x8EAD, + 0x0, 0xEA65, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xEA66, 0x0, 0x0, 0xEA67, 0xEA68, 0x0, 0x0, 0x0, + 0x0, 0xEA6B, 0xEA69, 0x985B, 0x0, 0xEA6A, 0x0, 0x97ED, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xEA6C, 0x0, 0x97D9, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xEA6D, 0x949E, 0x0, + 0x0, 0xEA6E, 0xEA70, 0x0, 0x0, 0xEA71, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xEA6F, 0x8D8D, 0x96CB, 0x9683, 0x9BF5, 0x0, 0x9F80, 0x969B, + 0x0, 0x0, 0x0, 0x0, 0x89A9, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xEA73, 0x8B6F, 0xEA74, 0xEA75, + 0xEA76, 0x0, 0x8D95, 0x0, 0xEA77, 0x0, 0x0, 0x0, + 0xE0D2, 0x96D9, 0x0, 0x91E1, 0xEA78, 0xEA7A, 0xEA79, 0x0, + 0xEA7B, 0x0, 0x0, 0x0, 0x0, 0xEA7C, 0x0, 0x0, + 0xEA7D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xEA7E, + 0x0, 0x0, 0x0, 0x0, 0xEA80, 0x0, 0xEA81, 0xEA82, + 0x0, 0xEA83, 0x0, 0xEA84, 0xEA85, 0xEA86, 0x0, 0x0, +}; + +static u16 Ucs9F[] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xEA87, + 0xEA88, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9343, 0x0, + 0x0, 0x0, 0x0, 0x8CDB, 0x0, 0xEA8A, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x916C, 0xEA8B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xEA8C, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9540, 0x0, 0x0, 0xEA8D, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xEA8E, 0xE256, 0x0, 0x0, 0xE6D8, 0xE8EB, + 0x0, 0x0, 0xEA8F, 0x0, 0xEA90, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xEA92, + 0xEA93, 0xEA94, 0x97EE, 0xEA91, 0x0, 0x0, 0xEA95, 0xEA96, + 0x0, 0x0, 0xEA98, 0x0, 0xEA97, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xEA9A, 0x0, 0x0, 0x0, 0xEA9B, 0xEA99, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x97B4, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xEA9C, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xEA9D, 0xE273, 0x0, 0x0, + 0xEA9E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16 UcsFF[] = +{ + 0x0, 0x8149, 0x0, 0x8194, 0x8190, 0x8193, 0x8195, 0x0, + 0x8169, 0x816A, 0x8196, 0x817B, 0x8143, 0x0, 0x8144, 0x815E, + 0x824F, 0x8250, 0x8251, 0x8252, 0x8253, 0x8254, 0x8255, 0x8256, + 0x8257, 0x8258, 0x8146, 0x8147, 0x8183, 0x8181, 0x8184, 0x8148, + 0x8197, 0x8260, 0x8261, 0x8262, 0x8263, 0x8264, 0x8265, 0x8266, + 0x8267, 0x8268, 0x8269, 0x826A, 0x826B, 0x826C, 0x826D, 0x826E, + 0x826F, 0x8270, 0x8271, 0x8272, 0x8273, 0x8274, 0x8275, 0x8276, + 0x8277, 0x8278, 0x8279, 0x816D, 0x0, 0x816E, 0x814F, 0x8151, + 0x814D, 0x8281, 0x8282, 0x8283, 0x8284, 0x8285, 0x8286, 0x8287, + 0x8288, 0x8289, 0x828A, 0x828B, 0x828C, 0x828D, 0x828E, 0x828F, + 0x8290, 0x8291, 0x8292, 0x8293, 0x8294, 0x8295, 0x8296, 0x8297, + 0x8298, 0x8299, 0x829A, 0x816F, 0x8162, 0x8170, 0x0, 0x0, + 0x0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8150, 0x0, 0x818F, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +}; + +static u16* UcsSjisTable[] = +{ + Ucs00, NULL, NULL, Ucs03, Ucs04, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + Ucs20, Ucs21, Ucs22, Ucs23, NULL, Ucs25, Ucs26, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + Ucs30, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, Ucs4E, Ucs4F, + Ucs50, Ucs51, Ucs52, Ucs53, Ucs54, Ucs55, Ucs56, Ucs57, + Ucs58, Ucs59, Ucs5A, Ucs5B, Ucs5C, Ucs5D, Ucs5E, Ucs5F, + Ucs60, Ucs61, Ucs62, Ucs63, Ucs64, Ucs65, Ucs66, Ucs67, + Ucs68, Ucs69, Ucs6A, Ucs6B, Ucs6C, Ucs6D, Ucs6E, Ucs6F, + Ucs70, Ucs71, Ucs72, Ucs73, Ucs74, Ucs75, Ucs76, Ucs77, + Ucs78, Ucs79, Ucs7A, Ucs7B, Ucs7C, Ucs7D, Ucs7E, Ucs7F, + Ucs80, Ucs81, Ucs82, Ucs83, Ucs84, Ucs85, Ucs86, Ucs87, + Ucs88, Ucs89, Ucs8A, Ucs8B, Ucs8C, Ucs8D, Ucs8E, Ucs8F, + Ucs90, Ucs91, Ucs92, Ucs93, Ucs94, Ucs95, Ucs96, Ucs97, + Ucs98, Ucs99, Ucs9A, Ucs9B, Ucs9C, Ucs9D, Ucs9E, Ucs9F, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, UcsFF +}; + +u16 OSUTF32toSJIS(u32 utf32) { + u16* table; + + if (0x10000 <= utf32) { + return 0; + } + + table = UcsSjisTable[(utf32 >> 8) & 0xFF]; + + if (table) { + return table[utf32 & 0xFF]; + } + + return 0; +} \ No newline at end of file diff --git a/src/RVL_SDK/os/__ppc_eabi_init.cpp b/src/RVL_SDK/os/__ppc_eabi_init.cpp new file mode 100644 index 000000000..e0b72f48c --- /dev/null +++ b/src/RVL_SDK/os/__ppc_eabi_init.cpp @@ -0,0 +1,82 @@ +#include "revolution/base/PPCArch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*funcPtr) (void); +__declspec(section ".ctors") extern funcPtr _ctors[]; +__declspec(section ".dtors") extern funcPtr _dtors[]; +extern void exit(int); +static void __init_cpp(void); + +extern void __OSCacheInit(void); +extern void __OSFPRInit(void); +extern void __OSPSInit(void); + +asm void __init_hardware(void) { + nofralloc + mfmsr r0 + ori r0, r0, 0x2000 + mtmsr r0 + mflr r31 + bl __OSPSInit + bl __OSFPRInit + bl __OSCacheInit + mtlr r31 + blr +} + +/* written in assembly to generate the frame allocations */ +asm void __init_user(void) { + fralloc + bl __init_cpp + frfree + blr +} + +static void __init_cpp(void) { + funcPtr* ctor; + + for (ctor = _ctors; *ctor; ctor++) { + (*ctor)(); + } +} + +static void __fini_cpp(void) { + funcPtr* dtor; + + for (dtor = _dtors; *dtor; dtor++) { + (*dtor)(); + } +} + +void exit(int status) { + __fini_cpp(); + PPCHalt(); +} + +asm void __flush_cache(void *, unsigned int) { + nofralloc + + lis r5, 0xFFFF + ori r5, r5, 0xFFF1 + and r5, r5, r3 + subf r3, r5, r3 + add r4, r4, r3 + +loop: + dcbst 0,r5 + sync + icbi 0,r5 + addic r5,r5,0x8 + subic. r4,r4,0x8 + bge loop + isync + + blr +} + +#ifdef __cplusplus +} +#endif diff --git a/src/RVL_SDK/os/__start.c b/src/RVL_SDK/os/__start.c new file mode 100644 index 000000000..543101a61 --- /dev/null +++ b/src/RVL_SDK/os/__start.c @@ -0,0 +1,246 @@ +#include +#include +#include <__ppc_eabi_init.h> +#include <__ppc_eabi_linker.h> + +#pragma section code_type ".init" + +u16 Pad3Button : 0x800030E4; +static u8 Debug_BBA = 0; + +static void __init_registers(void); +static void __init_data(void); + +extern void OSInit(void); +extern void DBInit(void); + +extern void main(void); + +void InitMetroTRK(void) { + return; +} + +void InitMetroTRK_BBA(void) { + return; +} + +void exit(void) { + return; +} + +static void __check_pad3(void) { + if ((Pad3Button & 0xEEF) == 0xEEF) { + OSResetSystem(0, 0, FALSE); + } +} + +static void __set_debug_bba(void) { + Debug_BBA = 1; +} + +static u8 __get_debug_bba(void) { + return Debug_BBA; +} + +__declspec(weak) asm void __start(void) { + nofralloc + bl __init_registers + bl __init_hardware + li r0, 0xFFFF + stwu r1, -8(r1) + stw r0, 4(r1) + stw r0, 0(r1) + bl __init_data + + li r0, 0 + lis r6, 0x80000044@ha + addi r6, r6, 0x80000044@l + stw r0, 0(r6) + +check_trk: + lis r6, 0x800000F4@ha + addi r6, r6, 0x800000F4@l + lwz r6, 0(r6) + cmplwi r6, 0 + beq load_debug_flag + lwz r7, 0xC(r6) + b check_debug + +load_debug_flag: + lis r5, 0x80000034@ha + addi r5, r5, 0x80000034@l + lwz r5, 0(r5) + cmplwi r5, 0 + beq go_to_main + + lis r7, 0x800030E8@ha + addi r7, r7, 0x800030E8@l + lwz r7, 0(r7) + +check_debug: + li r5, 0 + cmplwi r7, 2 + beq go_to_init_trk + cmplwi r7, 3 + li r5, 1 + beq go_to_init_trk + cmplwi r7, 4 + bne go_to_main + li r5, 2 + bl __set_debug_bba + b go_to_main + +go_to_init_trk: + lis r6, InitMetroTRK@ha + addi r6, r6, InitMetroTRK@l + mtlr r6 + blrl + +go_to_main: + lis r6, 0x800000F4@ha + addi r6, r6, 0x800000F4@l + lwz r5, 0(r6) + cmplwi r5, 0 + beq+ no_args + lwz r6, 8(r5) + cmplwi r6, 0 + beq+ no_args + add r6, r5, r6 + + lwz r14, 0(r6) + cmplwi r14, 0 + beq- no_args + addi r15, r6, 4 + mtctr r14 + +loop: + addi r6, r6, 4 + lwz r7, 0(r6) + add r7, r7, r5 + stw r7, 0(r6) + bdnz loop + + lis r5, 0x80000034@ha + addi r5, r5, 0x80000034@l + clrrwi r7, r15, 5 + stw r7, 0(r5) + + lis r5, 0x80003110@ha + addi r5, r5, 0x80003110@l + clrrwi r7, r15, 5 + stw r7, 0(r5) + + b end_args + +no_args: + li r14, 0 + li r15, 0 + +end_args: + bl DBInit + bl OSInit + + lis r4, 0x800030E6@ha + addi r4, r4, 0x800030E6@l + lhz r3, 0(r4) + andi. r5, r3, 0x8000 + beq check_pad + andi. r3, r3, 0x7FFF + cmplwi r3, 1 + bne skip_crc + +check_pad: + bl __check_pad3 + +skip_crc: + bl __get_debug_bba + cmplwi r3, 1 + bne skip_init + bl InitMetroTRK_BBA + +skip_init: + bl __init_user + + mr r3, r14 + mr r4, r15 + bl main + b exit +} + +asm static void __init_registers(void) { + nofralloc + li r0, 0x0 + li r3, 0x0 + li r4, 0x0 + li r5, 0x0 + li r6, 0x0 + li r7, 0x0 + li r8, 0x0 + li r9, 0x0 + li r10, 0x0 + li r11, 0x0 + li r12, 0x0 + li r14, 0x0 + li r15, 0x0 + li r16, 0x0 + li r17, 0x0 + li r18, 0x0 + li r19, 0x0 + li r20, 0x0 + li r21, 0x0 + li r22, 0x0 + li r23, 0x0 + li r24, 0x0 + li r25, 0x0 + li r26, 0x0 + li r27, 0x0 + li r28, 0x0 + li r29, 0x0 + li r30, 0x0 + li r31, 0x0 + lis r1, _stack_addr@h + ori r1, r1, _stack_addr@l + lis r2, _SDA2_BASE_@h + ori r2, r2, _SDA2_BASE_@l + lis r13, _SDA_BASE_@h + ori r13, r13, _SDA_BASE_@l + blr +} + +static void __copy_rom_section(void *pDest, const void *pSrc, u32 sectionSize) { + if (sectionSize && (pDest != pSrc)) { + memcpy(pDest, pSrc, sectionSize); + __flush_cache(pDest, sectionSize); + } +} + +static void __init_bss_section(void *pDest, u32 size) { + if (size != 0) { + memset(pDest, 0, size); + } +} + +static void __init_data(void) { + __rom_copy_info* romInfo; + __bss_init_info* bssInfo; + + romInfo = _rom_copy_info; + while (1) { + if (romInfo->size == 0) { + break; + } + + __copy_rom_section(romInfo->addr, romInfo->rom, romInfo->size); + romInfo++; + } + + bssInfo = _bss_init_info; + while (1) { + if (bssInfo->size == 0) { + break; + } + + __init_bss_section(bssInfo->addr, bssInfo->size); + bssInfo++; + } +} diff --git a/src/RVL_SDK/pad/Pad.c b/src/RVL_SDK/pad/Pad.c new file mode 100644 index 000000000..70b4e7336 --- /dev/null +++ b/src/RVL_SDK/pad/Pad.c @@ -0,0 +1,21 @@ +#include +#include + +u8 GameChoice : (OS_BASE_CACHED | 0x30E3); + +u32 __PADSpec; + +BOOL __PADDisableRecalibration(BOOL disable) { + BOOL enabled, prev; + + enabled = OSDisableInterrupts(); + prev = (GameChoice & 0x40) ? TRUE : FALSE; + GameChoice &= ~0x40; + + if (disable) { + GameChoice |= 0x40; + } + + OSRestoreInterrupts(enabled); + return prev; +} \ No newline at end of file diff --git a/src/RVL_SDK/sc/scapi.c b/src/RVL_SDK/sc/scapi.c new file mode 100644 index 000000000..aceb87728 --- /dev/null +++ b/src/RVL_SDK/sc/scapi.c @@ -0,0 +1,87 @@ +#include + +s8 SCGetDisplayOffsetH(void) { + s8 offset; + + if (!SCFindS8Item(&offset, 5)) { + offset = 0; + } + else { + if (offset < -32) { + offset = -32; + } + else if (offset > 32) { + offset = 32; + } + } + + offset &= ~1; + return offset; +} + +u8 SCGetEuRgb60Mode(void) { + u8 mode; + + if (!SCFindU8Item(&mode, 6)) { + mode = 0; + } + else { + if (mode != 1) { + mode = 0; + } + } + + return mode; +} + +BOOL SCGetIdleMode(SCIdleModeInfo *info) { + return SCFindByteArrayItem(info, sizeof(*info), 9); +} + +u8 SCGetLanguage(void) { + u8 lang; + s8 area; + + if (!SCFindU8Item(&lang, 11)) { + area = SCGetProductArea(); + + if (area == 0) { + lang = 0; + } + else { + lang = 1; + } + } + else { + if (lang > 9) { + lang = 1; + } + } + + return lang; +} + +u8 SCGetScreenSaverMode(void) { + u8 mode; + + if (!SCFindU8Item(&mode, 15)) { + mode = 1; + } + else { + if (mode != 1) { + mode = 0; + } + } + + return mode; +} + +u32 SCGetCounterBias(void) { + u32 bias; + + if (!SCFindU32Item(&bias, 0)) { + bias = 189388800; + } + + return bias; +} \ No newline at end of file diff --git a/src/RVL_SDK/sc/scapi_prdinfo.c b/src/RVL_SDK/sc/scapi_prdinfo.c new file mode 100644 index 000000000..dc421ce51 --- /dev/null +++ b/src/RVL_SDK/sc/scapi_prdinfo.c @@ -0,0 +1,136 @@ +#include +#include +#include + +typedef struct { + s8 area; + char string[4]; +} SCProductAreaAndString; + +static SCProductAreaAndString ProductAreaAndStringTbl[] = { + 0, "JPN", + 1, "USA", + 2, "EUR", + 3, "AUS", + 4, "BRA", + 5, "TWN", + 6, "ROC", + 7, "KOR", + 8, "HKG", + 9, "ASI", + 10, "LTN", + 11, "SAF", + 12, "CHN", + -1 +}; + +BOOL SCGetProductAreaString(char* buf, u32 bufSize) { + return __SCF1("AREA", buf, bufSize); +} + +s8 SCGetProductArea(void) { + char buf[4]; + SCProductAreaAndString* p = ProductAreaAndStringTbl; + + if (SCGetProductAreaString(buf, sizeof(buf))) { + while (p->area != -1) { + if (strcmp(p->string, buf) == 0) { + return p->area; + } + + p++; + } + } + + return -1; +} + +BOOL __SCF1(const char* keyword, char* buf, u32 bufSize) { + BOOL result = FALSE; + u8* p = (u8*)OSPhysicalToCached(0x3800); + u32 size = 0x100, i, seed = 0x73b5dbfa, kwOffset = 0; + u8 data; + u32 bufOffset = 0; + + for (i = 0; i < size; i++) { + data = p[i]; + + if (data != 0) { + data ^= seed; + + if (keyword[kwOffset] == '\0') { + if (data == '=') { + result = TRUE; + break; + } + } + + if (((keyword[kwOffset] ^ data) & 0xDF) == 0) { + kwOffset++; + } + else { + kwOffset = 0; + } + } + + seed = (u32)((seed >> 31) | (seed << 1)); + } + + if (result) { + i++; + + while (i < size && bufOffset < bufSize) { + seed = (u32)((seed >> 31) | (seed << 1)); + data = p[i]; + + if (data != 0) { + data ^= seed; + + if (data == '\x0d' || data == '\x0a') { + data = 0; + } + } + + buf[bufOffset] = (char)data; + bufOffset++; + if (data == 0) { + return TRUE; + } + + i++; + } + } + + return FALSE; +} + +typedef struct { + s8 game; + char string[3]; +} SCProductGameRegionAndString; + +static SCProductGameRegionAndString ProductGameRegionAndStringTbl[] = { + 0, "JP", + 1, "US", + 2, "EU", + 4, "KR", + 5, "CN", + -1 +}; + +s8 SCGetProductGameRegion(void) { + char buf[3]; + SCProductGameRegionAndString* p = ProductGameRegionAndStringTbl; + + if (__SCF1("GAME", buf, sizeof(buf))) { + while (p->game != -1) { + if (strcmp(p->string, buf) == 0) { + return p->game; + } + + p++; + } + } + + return -1; +} \ No newline at end of file diff --git a/src/RVL_SDK/sc/scsystem.c b/src/RVL_SDK/sc/scsystem.c new file mode 100644 index 000000000..a3782693d --- /dev/null +++ b/src/RVL_SDK/sc/scsystem.c @@ -0,0 +1,741 @@ +#include +#include +#include + +typedef struct { + char *name; + SCItemID id; +} NameAndID; + +static NameAndID NameAndIDTbl[36] = { + "IPL.CB", SC_ITEM_ID_IPL_COUNTER_BIAS, + "IPL.AR", SC_ITEM_ID_IPL_ASPECT_RATIO, + "IPL.ARN", SC_ITEM_ID_IPL_AUTORUN_MODE, + "IPL.CD", SC_ITEM_ID_IPL_CONFIG_DONE, + "IPL.CD2", SC_ITEM_ID_IPL_CONFIG_DONE2, + "IPL.DH", SC_ITEM_ID_IPL_DISPLAY_OFFSET_H, + "IPL.E60", SC_ITEM_ID_IPL_EURGB60_MODE, + "IPL.EULA", SC_ITEM_ID_IPL_EULA, + "IPL.FRC", SC_ITEM_ID_IPL_FREE_CHANNEL_APP_COUNT, + "IPL.IDL", SC_ITEM_ID_IPL_IDLE_MODE, + "IPL.INC", SC_ITEM_ID_IPL_INSTALLED_CHANNEL_APP_COUNT, + "IPL.LNG", SC_ITEM_ID_IPL_LANGUAGE, + "IPL.NIK", SC_ITEM_ID_IPL_OWNER_NICKNAME, + "IPL.PC", SC_ITEM_ID_IPL_PARENTAL_CONTROL, + "IPL.PGS", SC_ITEM_ID_IPL_PROGRESSIVE_MODE, + "IPL.SSV", SC_ITEM_ID_IPL_SCREEN_SAVER_MODE, + "IPL.SADR", SC_ITEM_ID_IPL_SIMPLE_ADDRESS, + "IPL.SND", SC_ITEM_ID_IPL_SOUND_MODE, + "IPL.UPT", SC_ITEM_ID_IPL_UPDATE_TYPE, + "NET.CNF", SC_ITEM_ID_NET_CONFIG, + "NET.CTPC", SC_ITEM_ID_NET_CONTENT_RESTRICTIONS, + "NET.PROF", SC_ITEM_ID_NET_PROFILE, + "NET.WCPC", SC_ITEM_ID_NET_WC_RESTRICTION, + "NET.WCFG", SC_ITEM_ID_NET_WC_FLAGS, + "DEV.BTM", SC_ITEM_ID_DEV_BOOT_MODE, + "DEV.VIM", SC_ITEM_ID_DEV_VIDEO_MODE, + "DEV.CTC", SC_ITEM_ID_DEV_COUNTRY_CODE, + "DEV.DSM", SC_ITEM_ID_DEV_DRIVESAVING_MODE, + "BT.DINF", SC_ITEM_ID_BT_DEVICE_INFO, + "BT.CDIF", SC_ITEM_ID_BT_CMPDEV_INFO, + "BT.SENS", SC_ITEM_ID_BT_DPD_SENSIBILITY, + "BT.SPKV", SC_ITEM_ID_BT_SPEAKER_VOLUME, + "BT.MOT", SC_ITEM_ID_BT_MOTOR_MODE, + "BT.BAR", SC_ITEM_ID_BT_SENSOR_BAR_POSITION, + "DVD.CNF", SC_ITEM_ID_DVD_CONFIG, + "WWW.RST", SC_ITEM_ID_WWW_RESTRICTION, +}; + +static const char ConfDirName[] = "/shared2/sys"; +static const char ConfFileName[] = "/shared2/sys/SYSCONF"; +static const char ProductInfoFileName[] = "/title/00000001/00000002/data/setting.txt"; + +static u8 ConfBuf [16384] __attribute__ ((aligned (32))); +static u8 ConfBufForFlush [16384] __attribute__ ((aligned (32))); + +static u8 Initialized; +static u8 DirtyFlag; +static u8 IsDevKit; +static vu8 BgJobStatus = 0; +static u32 ItemIDOffsetTblOffset; +static u32 ItemIDMaxPlus1; +static u32 ItemNumTotal; +static u32 ItemRestSize; +static SCControl Control; + +const char* __SCVersion = "<< RVL_SDK - SC \trelease build: Feb 22 2008 06:21:38 (0x4199_60831) >>"; + +static void OpenCallbackFromReload(s32, NANDCommandBlock *); +static void ReadCallbackFromReload(s32 result, NANDCommandBlock *block); +static void CloseCallbackFromReloadError(s32 result, NANDCommandBlock *block); +static void CloseCallbackFromReload(s32 result, NANDCommandBlock *block); +static void ErrorFromReload(s32 result); +void FinishFromReload(void); +BOOL UnpackItem(const u8 *, SCItem *); + +static u8* __SCGetConfBuf(void) { + return ConfBuf; +} + +static u32 __SCGetConfBufSize(void) { + return sizeof(ConfBuf); +} + +static void SetBgJobStatus(u32 status) { + BgJobStatus = (u8)status; +} + +static void ClearConfBuf(u8* bufp) { + u32 size = __SCGetConfBufSize(); + memset(bufp, 0, size); + + if (size > 12) { + memcpy(bufp, "SCv0", 4); + memcpy(bufp + 0x3FFC, "SCed", 4); + *((u16*)bufp + 3) = 8; + } +} + +static BOOL ParseGetBEValue(const u8* bufp, const u8* bufEndp, u32* varp, u32 varSize) { + u32 value = 0; + + if ((bufp + varSize) > bufEndp) { + return FALSE; + } + + while (varSize) { + value = (value << 8) | *bufp; + bufp++; + varSize--; + } + + *varp = value; + return TRUE; +} + +void SCInit(void) { + BOOL enabled = OSDisableInterrupts(); + + if (Initialized) { + OSRestoreInterrupts(enabled); + return; + } + + Initialized = TRUE; + SetBgJobStatus(1); + OSRestoreInterrupts(enabled); + + OSRegisterVersion(__SCVersion); + OSInitThreadQueue(&Control.threadQueue); + + if (OSGetConsoleType() & 0x10000000) { + IsDevKit = TRUE; + } + + if (NANDInit() != 0 || SCReloadConfFileAsync(__SCGetConfBuf(), __SCGetConfBufSize(), NULL) != 0) { + SetBgJobStatus(2); + } +} + +u32 ParseConfBuf(u8* bufp, u32 bufSize) { + u8* bufTop, *bufEndp; + u32 numItems, loopItem; + SCItem item; + u32 itemOffset; + u16* itemOfsp; + u16* runtimeRefp; + u32 restSize; + NameAndID* tblp = NameAndIDTbl; + NameAndID* tblEndp; + char* name; + + if ((bufSize < 12) || (bufSize > __SCGetConfBufSize())) { + goto error; + } + + bufTop = bufp; + bufEndp = bufp + bufSize - 4; + ItemIDMaxPlus1 = 36; + + if (memcmp(bufp, "SCv0", 4) || memcmp(bufEndp, "SCed", 4)) { + goto error; + } + + bufp += 4; + + if (bufSize < __SCGetConfBufSize()) { + u32 expandSize = __SCGetConfBufSize() - bufSize; + memset(bufEndp, 0, expandSize); + bufEndp += expandSize; + memcpy(bufEndp, "SCed", 4); + } + + if (ParseGetBEValue(bufp, bufEndp, &numItems, 2) == FALSE) { + goto error; + } + + bufp += 2; + itemOfsp = (u16*)bufp; + itemOffset = ((u8*)(itemOfsp + numItems + 1) - bufTop); + + for (loopItem = 0; loopItem < numItems; loopItem++) { + if (itemOffset > bufSize || ((u8*)&itemOfsp[loopItem] - bufTop) > bufSize) { + goto error; + } + + if (itemOffset != itemOfsp[loopItem] || UnpackItem(bufTop + itemOffset, &item) == FALSE) { + goto error; + } + + itemOffset += item.packedSize; + } + + if (itemOffset > bufSize) { + goto error; + } + + if (itemOffset != itemOfsp[loopItem]) { + goto error; + } + + runtimeRefp = (u16*)(bufEndp - 2 * (35)); + + if ((u8*)(bufTop + itemOffset) > (u8*)runtimeRefp){ + goto error; + } + + restSize = (u32)((u8 *)runtimeRefp - (u8 *)(bufTop + itemOffset)); + memset(runtimeRefp, 0, (u32)(bufEndp - (u8 *)runtimeRefp)); + runtimeRefp = (u16*)(bufEndp - 2); + tblEndp = tblp + ItemIDMaxPlus1; + + while (tblp < tblEndp && (name = tblp->name) != NULL) { + u32 nameLen; + u8* p; + + nameLen = strlen(name); + + for (loopItem = 0; loopItem < numItems; loopItem++) { + p = bufTop + itemOfsp[loopItem]; + + if (nameLen == (u32)(((*p) & ~0xE0) + 1) && memcmp(name, p + sizeof(SCType), nameLen) == 0) { + runtimeRefp[-tblp->id] = (u16)((u8 *)(&itemOfsp[loopItem]) - bufTop); + break; + } + } + + tblp++; + } + + ItemIDOffsetTblOffset = (u32)((u8*)runtimeRefp - bufTop); + ItemNumTotal = numItems; + ItemRestSize = restSize; + return 0; + +error: + return 2; +} + +static BOOL UnpackItem(const u8* bufp, SCItem* itemp) { + SCType type; + + memset(itemp, 0, sizeof(SCItem)); + type = (u8)(*bufp & 0xE0); + itemp->name = (char*)(bufp + sizeof(SCType)); + itemp->nameLen = (u32)((*bufp & ~0xE0) + 1); + itemp->data = (u8*)(bufp + sizeof(SCType) + itemp->nameLen); + + switch (type) { + case 0x60: + case 0xE0: + itemp->dataSize = sizeof(u8); + break; + case 0x80: + itemp->dataSize = sizeof(u16); + break; + case 0xA0: + itemp->dataSize = sizeof(u32); + break; + case 0xC0: + itemp->dataSize = sizeof(u64); + break; + case 0x40: + itemp->dataSize = (u32)(*(itemp->data) + 1); + itemp->data++; + itemp->packedSize++; + break; + case 0x20: + itemp->dataSize = (u32)((((*(itemp->data)) << 8) | (*(itemp->data + 1))) + 1); + itemp->data += 2; + itemp->packedSize += 2; + break; + default: + goto err; + } + + if (type == 0x40 || type == 0x20) { + itemp->typeByteArray = 0x40; + } + else { + itemp->typeInteger = type; + memcpy(&itemp->integer, itemp->data, itemp->dataSize); + } + + itemp->packedSize += sizeof(SCType) + itemp->nameLen + itemp->dataSize; + +err: + return (itemp->dataSize != 0); +} + +static BOOL FindItemByID(SCItemID id, SCItem* itemp) { + u8* conf = __SCGetConfBuf(); + u16* refp; + + if (id < ItemIDMaxPlus1 && ItemIDOffsetTblOffset != 0) { + refp = (u16*)(conf + ItemIDOffsetTblOffset); + if (refp[-id] != 0) { + return UnpackItem(conf + *(u16*)(conf + refp[-id]), itemp); + } + } + + return FALSE; +} + +static void __SCSetDirtyFlag(void); + +void DeleteItemByID(SCItemID id) { + u8* conf = __SCGetConfBuf(); + u32 targetRef, initialTopOfFreeSpace, moveSize, shrinkSize, i; + u16* refp, *itemOfsTop, *itemOfsTargetp, *itemOfsEndp, *itemOfsp; + + if (id < ItemIDMaxPlus1 && ItemIDOffsetTblOffset != 0) { + refp = (u16 *)(conf + ItemIDOffsetTblOffset); + targetRef = refp[-id]; + + if (targetRef != 0 && ItemNumTotal != 0) { + itemOfsTop = (u16*)(conf + 4); + itemOfsTargetp = (u16 *)(conf + targetRef); + itemOfsEndp = itemOfsTop + ItemNumTotal; + initialTopOfFreeSpace = *itemOfsEndp; + shrinkSize = 2 + (itemOfsTargetp[1] - itemOfsTargetp[0]); + + moveSize = *itemOfsTargetp - (targetRef + 4); + memmove(conf + targetRef, conf + targetRef + 4, moveSize); + + for (itemOfsp = itemOfsEndp - 1; itemOfsp >= itemOfsTop; itemOfsp--) { + if (itemOfsp < itemOfsTargetp) { + *itemOfsp -= 2; + } else { + *itemOfsp -= shrinkSize; + } + } + + memmove(conf + itemOfsTargetp[0], conf + (itemOfsTargetp[0] + shrinkSize), initialTopOfFreeSpace - (itemOfsTargetp[0] + shrinkSize)); + memset(conf + (initialTopOfFreeSpace - shrinkSize), 0, shrinkSize); + + for (i = 0; i < ItemIDMaxPlus1; i++) { + if (refp[-i] < targetRef) { + // empty branch? + } else if (refp[-i] > targetRef) { + refp[-i] -= 2; + } else { + refp[-i] = 0; + } + } + ItemRestSize += shrinkSize; + ItemNumTotal--; + *(u16*)(conf + 4) = (u16)ItemNumTotal; + __SCSetDirtyFlag(); + } + } +} + +BOOL CreateItemByID(SCItemID id, SCType type, const u8 *data, u32 size) +{ + u8 *conf = __SCGetConfBuf(); + u8 *p; + u32 nameLen; + u32 packedSize = sizeof(SCType); + NameAndID *tblp = NameAndIDTbl; + char *name; + u32 topOfFreeSpace; + u16 *refp; + u16 *itemOfsTop; + u16 *itemOfsEndp; + u16 *itemOfsp; + + if (id < ItemIDMaxPlus1 && data != NULL && ItemNumTotal < 0xFFFF && ItemIDOffsetTblOffset != 0) { + + switch (type) { + case 0xE0: + case 0x60: + size = 1; + break; + + case 0x80: + size = 2; + break; + + case 0xA0: + size = 4; + break; + + case 0xC0: + size = 8; + break; + + case 0x40: + if (size == 0 || size > 65536) { + goto error; + } + if (size > 256) { + packedSize += 2; + type = 0x20; + } else { + packedSize += 1; + } + break; + + default: + goto error; + } + + packedSize += size; + + while ((name = tblp->name) != NULL) { + if (tblp->id == id) { + break; + } + + tblp++; + } + + if (name == NULL) { + goto error; + } + + nameLen = strlen(name); + if (nameLen > 32) { + goto error; + } + + packedSize += nameLen; + if (ItemRestSize < (2 + packedSize)) { + goto error; + } + + + itemOfsTop = (u16 *)(conf + 6); + itemOfsEndp = itemOfsTop + ItemNumTotal; + topOfFreeSpace = *itemOfsEndp; + memmove(conf + (itemOfsTop[0] + 2), conf + itemOfsTop[0], topOfFreeSpace - itemOfsTop[0]); + + itemOfsp = itemOfsTop; + do { + *itemOfsp += 2; + itemOfsp++; + } while (itemOfsp <= itemOfsEndp); + + topOfFreeSpace = *itemOfsEndp; + p = (u8 *)(conf + topOfFreeSpace); + + *p = (SCType)(type | (nameLen - 1)); + memcpy(p + sizeof(SCType), name, nameLen); + p += sizeof(SCType) + nameLen; + if (type == 0x40) { + *p++ = (u8)(size - 1); + } else if (type == 0x20) { + *p++ = (u8)((size - 1) >> 8); + *p++ = (u8)(size - 1); + } + memcpy(p, data, size); + p += size; + + refp = (u16 *)(conf + ItemIDOffsetTblOffset); + refp[-id] = (u16)((u8 *)itemOfsEndp - conf); + itemOfsEndp[1] = (u16)(itemOfsEndp[0] + packedSize); + ItemRestSize -= 2 + packedSize; + ItemNumTotal++; + *(u16 *)(conf + 4) = (u16)ItemNumTotal; + __SCSetDirtyFlag(); + + return TRUE; + } + +error: + return FALSE; +} + +BOOL SCFindByteArrayItem(void* data, u32 size, SCItemID id) { + SCItem item; + BOOL result = FALSE; + BOOL enabled = OSDisableInterrupts(); + + if (data != NULL && FindItemByID(id, &item) && item.typeByteArray != 0 && item.dataSize == size) { + memcpy(data, item.data, size); + result = TRUE; + } + + OSRestoreInterrupts(enabled); + return result; +} + +BOOL SCReplaceByteArrayItem(const void* data, u32 size, SCItemID id) { + SCItem item; + BOOL result = FALSE; + BOOL enabled = OSDisableInterrupts(); + + if (data != NULL) { + if (FindItemByID(id, &item)) { + if (item.typeByteArray != 0 && item.dataSize == size) { + if (memcmp(item.data, data, size) != 0) { + memcpy(item.data, data, size); + __SCSetDirtyFlag(); + } + + result = TRUE; + goto finish; + } + else { + DeleteItemByID(id); + } + } + result = CreateItemByID(id, 0x40, data, size); + } + +finish: + OSRestoreInterrupts(enabled); + return result; +} + +static BOOL SCFindIntegerItem(void* data, SCItemID id, SCType type) { + SCItem item; + BOOL result = FALSE; + BOOL enabled = OSDisableInterrupts(); + + if (FindItemByID(id, &item) && item.typeInteger == type) { + memcpy(data, item.data, item.dataSize); + result = TRUE; + } + + OSRestoreInterrupts(enabled); + return result; +} + +BOOL SCReplaceIntegerItem(const void* data, SCItemID id, SCType type) NO_INLINE { + SCItem item; + BOOL result = FALSE; + BOOL enabled = OSDisableInterrupts(); + + if (FindItemByID(id, &item)) { + if (item.typeInteger == type) { + if (memcmp(item.data, data, item.dataSize) != 0) { + memcpy(item.data, data, item.dataSize); + __SCSetDirtyFlag(); + } + + result = TRUE; + goto finish; + } + else { + DeleteItemByID(id); + } + } + + result = CreateItemByID(id, type, data, 0); + +finish: + OSRestoreInterrupts(enabled); + return result; +} + +BOOL SCFindU8Item(u8* data, SCItemID id) { + return SCFindIntegerItem(data, id, 0x60); +} + +BOOL SCFindS8Item(s8* data, SCItemID id) { + return SCFindIntegerItem(data, id, 0x60); +} + +BOOL SCFindU32Item(u32* data, SCItemID id) { + return SCFindIntegerItem(data, id, 0xA0); +} + +BOOL SCReplaceU8Item(u8 data, SCItemID id) { + return SCReplaceIntegerItem(&data, id, 0x60); +} + +static void __SCSetDirtyFlag(void) { + DirtyFlag = TRUE; +} + +static void __SCClearDirtyFlag(void) { + DirtyFlag = FALSE; +} + +u32 SCCheckStatus(void) { + BOOL enabled; + u32 ret; + + enabled = OSDisableInterrupts(); + ret = BgJobStatus; + + if (ret == 3) { + SetBgJobStatus(1); + OSRestoreInterrupts(enabled); + + if (ParseConfBuf(Control.reloadBufp[0], Control.reloadedSize[0]) == 0) { + enabled = OSDisableInterrupts(); + + if (__SCGetConfBuf() != Control.reloadBufp[0]) { + memcpy(__SCGetConfBuf(), Control.reloadBufp[0], __SCGetConfBufSize()); + } + + __SCClearDirtyFlag(); + OSRestoreInterrupts(enabled); + } + else { + enabled = OSDisableInterrupts(); + ClearConfBuf(Control.reloadBufp[0]); + __SCClearDirtyFlag(); + OSRestoreInterrupts(enabled); + } + + ret = 0; + SetBgJobStatus(ret); + } + else { + OSRestoreInterrupts(enabled); + } + + return ret; +} + +static s32 SCReloadConfFileAsync(u8* bufp, u32 bufSize, SCReloadConfFileCallback callback) { + u32 i; + + if (bufSize < __SCGetConfBufSize()) { + return -128; + } + + SetBgJobStatus(1); + Control.reloadCallback = callback; + Control.reloadResult = 0; + Control.reloadFileCount = 0; + + for (i = 0; i < 2; i++) { + Control.reloadedSize[i] = 0; + } + + Control.reloadFileName[0] = ConfFileName; + Control.reloadFileName[1] = ProductInfoFileName; + Control.reloadBufp[0] = bufp; + Control.reloadBufp[1] = (u8*)OSPhysicalToCached(0x3800); + Control.reloadSizeExpected[0] = __SCGetConfBufSize(); + Control.reloadSizeExpected[1] = 0x100; + ClearConfBuf(bufp); + ItemIDOffsetTblOffset = 0; + ItemNumTotal = 0; + ItemRestSize = 0; + Control.nandNeedClose = FALSE; + return NANDPrivateOpenAsync(Control.reloadFileName[Control.reloadFileCount], &Control.nandFileInfo, 1,OpenCallbackFromReload, &Control.nandCommandBlock); +} + +static void OpenCallbackFromReload(s32 result, NANDCommandBlock* block) { + if (result == 0) { + Control.nandNeedClose = TRUE; + + if (NANDReadAsync(&Control.nandFileInfo, + Control.reloadBufp[Control.reloadFileCount], + Control.reloadSizeExpected[Control.reloadFileCount], + ReadCallbackFromReload, + &Control.nandCommandBlock) == 0) { + return; + } + } + + ErrorFromReload(result); +} + +static void ReadCallbackFromReload(s32 result, NANDCommandBlock* block) { + if (result == Control.reloadSizeExpected[Control.reloadFileCount]) { + Control.reloadedSize[Control.reloadFileCount] = (u32)result; + Control.nandNeedClose = FALSE; + + if (NANDCloseAsync(&Control.nandFileInfo, CloseCallbackFromReload, &Control.nandCommandBlock) == 0) { + return; + } + } + + ErrorFromReload((s32)((result == 0) ? -128 : result)); +} + +static void CloseCallbackFromReload(s32 result, NANDCommandBlock* block) { + if (result == 0) { + FinishFromReload(); + return; + } + + ErrorFromReload(result); +} + +void FinishFromReload(void) { + u32 status; + +nextFile: + Control.reloadFileCount++; + + if (Control.reloadFileCount < 2) { + Control.nandNeedClose = FALSE; + + if (NANDPrivateOpenAsync(Control.reloadFileName[Control.reloadFileCount], + &Control.nandFileInfo, 1, OpenCallbackFromReload, + &Control.nandCommandBlock) == 0) { + return; + } + + goto nextFile; + } + + switch (Control.reloadResult) { + case 0: + status = 3; + break; + default: + case -12: + ClearConfBuf(Control.reloadBufp[0]); + Control.reloadedSize[0] = Control.reloadSizeExpected[0]; + status = 3; + break; + } + + *(u8*)((u8*)OSPhysicalToCached(0x3800) + 0x100 - 1) = '\0'; + + if (Control.reloadCallback) { + Control.reloadCallback(Control.reloadResult); + Control.reloadCallback = NULL; + } + + SetBgJobStatus(status); +} + +static void ErrorFromReload(s32 result) { + if (Control.reloadFileCount == 0) { + Control.reloadResult = result; + } + + Control.reloadedSize[Control.reloadFileCount] = 0; + + if (Control.nandNeedClose) { + if (NANDCloseAsync(&Control.nandFileInfo, CloseCallbackFromReloadError, + &Control.nandCommandBlock) == 0) { + return; + } + } + + FinishFromReload(); +} + +static void CloseCallbackFromReloadError(s32 result, NANDCommandBlock* block) { + FinishFromReload(); +} diff --git a/src/RVL_SDK/si/SIBios.c b/src/RVL_SDK/si/SIBios.c new file mode 100644 index 000000000..fa28c74b1 --- /dev/null +++ b/src/RVL_SDK/si/SIBios.c @@ -0,0 +1,475 @@ +#include +#include +#include +#include + +#define OFFSET(n, a) (((u32) (n)) & ((a) - 1)) +#define ROUND(n, a) (((u32) (n) + (a) - 1) & ~((a) - 1)) + +typedef struct SIControl { + s32 chan; + u32 poll; + u32 inputBytes; + void* input; + SICallback callback; +} SIControl; + +static SIControl Si = { + -1 +}; + +static SIPacket Packet[4]; +static OSAlarm Alarm[4]; + +static u32 Type[4] = { + 8, + 8, + 8, + 8 +}; + +static OSTime TypeTime[4]; +static OSTime XferTime[4]; +static SITypeAndStatusCallback TypeCallback[4][4]; +static __OSInterruptHandler RDSTHandler[4]; +u32 __PADFixBits; + +static BOOL InputBufferValid[4]; +static u32 InputBuffer[4][2]; +static vu32 InputBufferVcount[4]; + +static const char* __SIVersion = "<< RVL_SDK - SI \trelease build: Aug 8 2007 02:07:10 (0x4199_60831) >>"; + +static void GetTypeCallback(s32, u32, OSContext *); + +BOOL SIIsChanBusy(s32 chan) { + return Packet[chan].chan != -1 || Si.chan == chan; +} + +static void SIClearTCInterrupt(void){ + u32 reg; + reg = __SIRegs[0xD]; + reg |= 0x80000000; + reg &= 0xFFFFFFFE; + __SIRegs[0xD] = reg; +} + +static u32 CompleteTransfer(void) { + u32 sr; + u32 i; + u32 rLen; + u8* input; + + sr = __SIRegs[0xE]; + SIClearTCInterrupt(); + + if (Si.chan != -1) { + XferTime[Si.chan] = __OSGetSystemTime(); + input = Si.input; + rLen = Si.inputBytes / 4; + + for (i = 0; i < rLen; i++) { + *(u32*)input = __SIRegs[0x20 + i]; + input += 4; + } + + rLen = OFFSET(Si.inputBytes, 4); + if (rLen) { + u32 temp = __SIRegs[0x20 + i]; + + for (i = 0; i < rLen; i++) { + *input++ = (u8)((temp >> ((3 - i) * 8)) & 0xFF); + } + } + + if (__SIRegs[0xD] & 0x20000000) { + sr >>= 8 * (3 - Si.chan); + sr &= 0xF; + + if ((sr & 8) && !(Type[Si.chan] & 0x80)) { + Type[Si.chan] = 8; + } + + if (sr == 0) { + sr = 4; + } + } + else { + TypeTime[Si.chan] = __OSGetSystemTime(); + sr = 0; + } + + Si.chan = -1; + } + + return sr; +} + +static void SITransferNext(s32 chan) { + int i; + SIPacket* packet; + + for (i = 0; i < 4; ++i) { + ++chan; + chan %= 4; + packet = &Packet[chan]; + + if (packet->chan != -1 && packet->fire <= __OSGetSystemTime()) { + if (__SITransfer(packet->chan, packet->output, packet->outputBytes, packet->input, packet->inputBytes, packet->callback)) { + OSCancelAlarm(&Alarm[chan]); + packet->chan = -1; + } + + break; + } + } +} + +void SIInterruptHandler(__OSInterrupt interrupt, OSContext* context) { + u32 reg = __SIRegs[0xD]; + + if ((reg & 0xC0000000) == 0xC0000000) { + s32 chan; + u32 sr; + SICallback callback; + chan = Si.chan; + sr = CompleteTransfer(); + callback = Si.callback; + Si.callback = 0; + + SITransferNext(chan); + + if (callback) { + callback(chan, sr, context); + } + + sr = __SIRegs[0xE]; + sr &= 0xF000000 >> (8 * chan); + __SIRegs[0xE] = sr; + + if (Type[chan] == 0x80 && !SIIsChanBusy(chan)) { + static u32 cmdTypeAndStatus = 0; + SITransfer(chan, &cmdTypeAndStatus, 1, &Type[chan], 3, GetTypeCallback, (OSTime)OSMicrosecondsToTicks(65)); + } + } + + if ((reg & 0x18000000) == 0x18000000) { + int i; + u32 vcount; + u32 x; + + vcount = VIGetCurrentLine() + 1; + x = (Si.poll & 0x03FF0000) >> 16; + + for (i = 0; i < 4; i++) { + if (SIGetResponseRaw(i)) { + InputBufferVcount[i] = vcount; + } + } + + for (i = 0; i < 4; i++) { + if (!(Si.poll & (0x80000000 >> (31 - 7 + i)))) { + continue; + } + + if (InputBufferVcount[i] == 0 || InputBufferVcount[i] + (x / 2) < vcount) { + return; + } + } + + for (i = 0; i < 4; i++) { + InputBufferVcount[i] = 0; + } + + for (i = 0; i < 4; i++) { + if (RDSTHandler[i]) { + RDSTHandler[i](interrupt, context); + } + } + } +} + +u32 SIGetStatus(s32 chan) { + BOOL enabled; + u32 sr; + int chanShift; + + enabled = OSDisableInterrupts(); + sr = __SIRegs[0xE]; + chanShift = 8 * (3 - chan); + sr >>= chanShift; + + if (sr & 8) { + if (!(Type[chan] & 0x80)) { + Type[chan] = 8; + } + } + + OSRestoreInterrupts(enabled); + return sr; +} + +static BOOL SIGetResponseRaw(s32 chan) { + u32 sr; + + sr = SIGetStatus(chan); + + if (sr & 0x20) { + InputBuffer[chan][0] = __SIRegs[3 * chan + 1]; + InputBuffer[chan][1] = __SIRegs[3 * chan + 2]; + InputBufferValid[chan] = TRUE; + return TRUE; + } + + return FALSE; +} + +void SIInit(void) { + static BOOL Initialized = FALSE; + + if (Initialized) { + return; + } + + OSRegisterVersion(__SIVersion); + Packet[0].chan = Packet[1].chan = Packet[2].chan = Packet[3].chan = -1; + Si.poll = 0; + SISetSamplingRate(0); + + while (__SIRegs[0xD] & 1) { } + + __SIRegs[0xD] = 0x80000000; + __OSSetInterruptHandler(20, SIInterruptHandler); + __OSUnmaskInterrupts(0x800); + + SIGetType(0); + SIGetType(1); + SIGetType(2); + SIGetType(3); + Initialized = TRUE; +} + +BOOL __SITransfer(s32 chan, void* output, u32 outputBytes, void* input, u32 inputBytes, SICallback callback) { + BOOL enabled; + u32 rLen; + u32 i; + u32 sr; + si_comcsr_u comcsr; + + enabled = OSDisableInterrupts(); + + if (Si.chan != -1) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + sr = __SIRegs[0xE]; + sr &= 0xF000000 >> (8 * chan); + __SIRegs[0xE] = sr; + + Si.chan = chan; + Si.callback = callback; + Si.inputBytes = inputBytes; + Si.input = input; + + rLen = ROUND(outputBytes, 4) / 4; + + for (i = 0; i < rLen; i++) { + __SIRegs[0x20 + i] = ((u32*)output)[i]; + } + + comcsr.val = __SIRegs[0xD]; + comcsr.f.tcint = 1; + comcsr.f.tcintmsk = callback ? 1 : 0; + comcsr.f.outlngth = (outputBytes == 128) ? 0 : outputBytes; + comcsr.f.inlngth = (inputBytes == 128) ? 0 : inputBytes; + comcsr.f.channel = chan; + comcsr.f.tstart = 1; + __SIRegs[0xD] = comcsr.val; + OSRestoreInterrupts(enabled); + return TRUE; +} + +u32 SISetXY(u32 x, u32 y) { + u32 poll; + BOOL enabled; + + poll = x << 16; + poll |= y << 8; + + enabled = OSDisableInterrupts(); + Si.poll &= ~(0x3FF0000 | 0xFF00); + Si.poll |= poll; + poll = Si.poll; + __SIRegs[0xC] = poll; + OSRestoreInterrupts(enabled); + return poll; +} + +static void AlarmHandler(OSAlarm* alarm, OSContext* context) { + s32 chan; + SIPacket* packet; + + chan = alarm - Alarm; + packet = &Packet[chan]; + + if (packet->chan != -1) { + if (__SITransfer(packet->chan, packet->output, packet->outputBytes, packet->input, packet->inputBytes, packet->callback)) { + packet->chan = -1; + } + } +} + +BOOL SITransfer(s32 chan, void* output, u32 outputBytes, void* input, u32 inputBytes, SICallback callback, OSTime delay) { + BOOL enabled; + SIPacket* packet = &Packet[chan]; + OSTime now; + OSTime fire; + + enabled = OSDisableInterrupts(); + + if (packet->chan != -1 || Si.chan == chan) { + OSRestoreInterrupts(enabled); + return FALSE; + } + + now = __OSGetSystemTime(); + + if (delay == 0) { + fire = now; + } + else { + fire = XferTime[chan] + delay; + } + + if (now < fire) { + delay = fire - now; + OSSetAlarm(&Alarm[chan], delay, AlarmHandler); + } + else if (__SITransfer(chan, output, outputBytes, input, inputBytes, callback)) { + OSRestoreInterrupts(enabled); + return TRUE; + } + + packet->chan = chan; + packet->output = output; + packet->outputBytes = outputBytes; + packet->input = input; + packet->inputBytes = inputBytes; + packet->callback = callback; + packet->fire = fire; + OSRestoreInterrupts(enabled); + return TRUE; +} + +static void CallTypeAndStatusCallback(s32 chan, u32 type) { + SITypeAndStatusCallback callback; + int i; + + for (i = 0; i < 4; ++i) { + callback = TypeCallback[chan][i]; + + if (callback) { + TypeCallback[chan][i] = 0; + callback(chan, type); + } + } +} + +static void GetTypeCallback(s32 chan, u32 error, OSContext* context) { + static u32 cmdFixDevice[4]; + u32 type; + u32 chanBit; + BOOL fix; + u32 id; + + Type[chan] &= 0xFFFFFF7F; + Type[chan] |= error; + TypeTime[chan] = __OSGetSystemTime(); + type = Type[chan]; + chanBit = 0x80000000 >> chan; + fix = __PADFixBits & chanBit; + __PADFixBits &= ~chanBit; + + if ((error & 0xF) || (type & 0x18000000) != 0x08000000 || !(type & 0x80000000) || (type & 0x4000000)) { + OSSetWirelessID(chan, 0); + CallTypeAndStatusCallback(chan, Type[chan]); + return; + } + + id = OSGetWirelessID(chan) << 8; + + if (fix && (id & 0x100000)) { + cmdFixDevice[chan] = 0x4E << 24 | (id & 0xCFFF00) | 0x4E100000; + Type[chan] = 0x80; + SITransfer(chan, &cmdFixDevice[chan], 3, &Type[chan], 3, GetTypeCallback, 0); + return; + } + + if (type & 0x100000) { + if ((id & 0xCFFF00) != (type & 0xCFFF00)) { + if (!(id & 0x00100000)) { + id = type & 0xCFFF00; + id |= 0x00100000; + OSSetWirelessID(chan, (u16)((id >> 8) & 0xFFFF)); + } + + cmdFixDevice[chan] = 0x4E << 24 | id; + Type[chan] = 0x80; + SITransfer(chan, &cmdFixDevice[chan], 3, &Type[chan], 3, GetTypeCallback, 0); + return; + } + } + else if (type & 0x40000000) { + id = type & 0xCFFF00; + id |= 0x00100000; + + OSSetWirelessID(chan, (u16)((id >> 8) & 0xFFFF)); + cmdFixDevice[chan] = 0x4E << 24 | id; + Type[chan] = 0x80; + SITransfer(chan, &cmdFixDevice[chan], 3, &Type[chan], 3, GetTypeCallback, 0); + return; + } + else { + OSSetWirelessID(chan, 0); + } + + CallTypeAndStatusCallback(chan, Type[chan]); +} + +u32 SIGetType(s32 chan) { + static u32 cmdTypeAndStatus = 0; + BOOL enabled; + u32 type; + OSTime diff; + + enabled = OSDisableInterrupts(); + type = Type[chan]; + diff = __OSGetSystemTime() - TypeTime[chan]; + + if (Si.poll & (0x80 >> chan)) { + if (type != 8) { + TypeTime[chan] = __OSGetSystemTime(); + OSRestoreInterrupts(enabled); + return type; + } + else { + type = Type[chan] = 0x80; + } + } + else if (diff <= OSMillisecondsToTicks(50) && type != 8) { + OSRestoreInterrupts(enabled); + return type; + } + else if (diff <= OSMillisecondsToTicks(75)) { + Type[chan] = 0x80; + } + else { + type = Type[chan] = 0x80; + } + + TypeTime[chan] = __OSGetSystemTime(); + SITransfer(chan, &cmdTypeAndStatus, 1, &Type[chan], 3, GetTypeCallback, OSMicrosecondsToTicks(65)); + OSRestoreInterrupts(enabled); + return type; +} \ No newline at end of file diff --git a/src/RVL_SDK/si/SISamplingRate.c b/src/RVL_SDK/si/SISamplingRate.c new file mode 100644 index 000000000..2c1b04461 --- /dev/null +++ b/src/RVL_SDK/si/SISamplingRate.c @@ -0,0 +1,77 @@ +#include +#include +#include + +static u32 SamplingRate; + +typedef struct XY { + u16 line; + u8 count; +} XY; + +static struct XY XYNTSC[12] = { + 246, 2, + 14, 19, + 30, 9, + 44, 6, + 52, 5, + 65, 4, + 87, 3, + 87, 3, + 87, 3, + 131, 2, + 131, 2, + 131, 2, +}; + +static struct XY XYPAL[12] = { + 296, 2, + 15, 21, + 29, 11, + 45, 7, + 52, 6, + 63, 5, + 78, 4, + 104, 3, + 104, 3, + 104, 3, + 104, 3, + 156, 2, +}; + +void SISetSamplingRate(u32 msec) { + XY* xy; + BOOL progressive; + BOOL enabled; + + if (11 < msec) { + msec = 11; + } + + enabled = OSDisableInterrupts(); + SamplingRate = msec; + + switch (VIGetTvFormat()) { + case VI_NTSC: + case VI_MPAL: + case VI_EURGB60: + xy = XYNTSC; + break; + case VI_PAL: + xy = XYPAL; + break; + default: + OSReport("SISetSamplingRate: unknown TV format. Use default."); + msec = 0; + xy = XYNTSC; + break; + } + + progressive = __VIRegs[0x36] & 1; + SISetXY((progressive ? 2 : 1) * xy[msec].line, xy[msec].count); + OSRestoreInterrupts(enabled); +} + +void SIRefreshSamplingRate(void) { + SISetSamplingRate(SamplingRate); +} \ No newline at end of file diff --git a/src/RVL_SDK/thp/THPAudio.c b/src/RVL_SDK/thp/THPAudio.c new file mode 100644 index 000000000..560cef87d --- /dev/null +++ b/src/RVL_SDK/thp/THPAudio.c @@ -0,0 +1,151 @@ +#include + +u32 THPAudioDecode(s16 *audioBuffer, u8 *audioFrame, s32 flag) { + THPAudioRecordHeader *header; + THPAudioDecodeInfo decInfo; + u8 *left, *right; + s16 *decLeftPtr, *decRightPtr; + s16 yn1, yn2; + s32 i; + s32 step; + s32 sample; + s64 yn; + + if (audioBuffer == NULL || audioFrame == NULL) { + return 0; + } + + header = (THPAudioRecordHeader*)audioFrame; + left = audioFrame + sizeof(THPAudioRecordHeader); + right = left + header->offsetNextChannel; + + if (flag == 1) { + decRightPtr = audioBuffer; + decLeftPtr = audioBuffer + header->sampleSize; + step = 1; + } + else { + decRightPtr = audioBuffer; + decLeftPtr = audioBuffer + 1; + step = 2; + } + + if (header->offsetNextChannel == 0) { + __THPAudioInitialize(&decInfo, left); + + yn1 = header->lYn1; + yn2 = header->lYn2; + + for (i = 0; i < header->sampleSize; i++) { + sample = __THPAudioGetNewSample(&decInfo); + yn = header->lCoef[decInfo.predictor][1] * yn2; + yn += header->lCoef[decInfo.predictor][0] * yn1; + yn += (sample << decInfo.scale) << 11; + yn <<= 5; + yn += 0x8000; + + if (yn > 2147483647LL) { + yn = 2147483647LL; + } + + if (yn < -2147483648LL) { + yn = -2147483648LL; + } + + *decLeftPtr = (s16)(yn >> 16); + decLeftPtr += step; + *decRightPtr = (s16)(yn >> 16); + decRightPtr += step; + yn2 = yn1; + yn1 = (s16)(yn >> 16); + } + } + else { + __THPAudioInitialize(&decInfo, left); + + yn1 = header->lYn1; + yn2 = header->lYn2; + + for (i = 0 ; i < header->sampleSize ; i++) { + sample = __THPAudioGetNewSample(&decInfo); + yn = header->lCoef[decInfo.predictor][1] * yn2; + yn += header->lCoef[decInfo.predictor][0] * yn1; + yn += (sample << decInfo.scale) << 11; + yn <<= 5; + yn += 0x8000; + + if (yn > 2147483647LL) { + yn = 2147483647LL; + } + + if (yn < -2147483648LL) { + yn = -2147483648LL; + } + + *decLeftPtr = (s16)(yn >> 16); + decLeftPtr += step; + yn2 = yn1; + yn1 = (s16)(yn >> 16); + } + + __THPAudioInitialize(&decInfo, right); + + yn1 = header->rYn1; + yn2 = header->rYn2; + + for (i = 0 ; i < header->sampleSize ; i++) { + sample = __THPAudioGetNewSample(&decInfo); + yn = header->rCoef[decInfo.predictor][1] * yn2; + yn += header->rCoef[decInfo.predictor][0] * yn1; + yn += (sample << decInfo.scale) << 11; + yn <<= 5; + yn += 0x8000; + + if (yn > 2147483647LL) { + yn = 2147483647LL; + } + + if (yn < -2147483648LL) { + yn = -2147483648LL; + } + + *decRightPtr = (s16)(yn >> 16); + decRightPtr += step; + yn2 = yn1; + yn1 = (s16)(yn >> 16); + } + } + + return header->sampleSize; +} + +static s32 __THPAudioGetNewSample(THPAudioDecodeInfo* info) { + s32 sample; + + if (!(info->offsetNibbles & 0x0f)) { + info->predictor = (u8)((*(info->encodeData) & 0x70) >> 4); + info->scale = (u8)((*(info->encodeData) & 0xF)); + info->encodeData++; + info->offsetNibbles += 2; + } + + if (info->offsetNibbles & 0x1) { + sample = (s32)((*(info->encodeData) & 0xF) << 28) >> 28; + info->encodeData++; + } + else { + sample = (s32)((*(info->encodeData) & 0xF0) << 24) >> 28; + } + + info->offsetNibbles++; + return sample; +} + +static void __THPAudioInitialize(THPAudioDecodeInfo* info, u8* ptr) { + info->encodeData = ptr; + info->offsetNibbles = 2; + info->predictor = (u8)((*(info->encodeData) & 0x70) >> 4); + info->scale = (u8)((*(info->encodeData) & 0xF)); + info->encodeData++; + return; +} diff --git a/src/RVL_SDK/thp/THPDec.c b/src/RVL_SDK/thp/THPDec.c new file mode 100644 index 000000000..898d24168 --- /dev/null +++ b/src/RVL_SDK/thp/THPDec.c @@ -0,0 +1,2219 @@ +#include + +const char* __THPVersion = "<< RVL_SDK - THP \trelease build: Aug 8 2007 01:31:54 (0x4199_60831) >>"; + +static THPHuffmanTab* Ydchuff __attribute__((aligned(32))); +static THPHuffmanTab* Udchuff __attribute__((aligned(32))); +static THPHuffmanTab* Vdchuff __attribute__((aligned(32))); +static THPHuffmanTab* Yachuff __attribute__((aligned(32))); +static THPHuffmanTab* Uachuff __attribute__((aligned(32))); +static THPHuffmanTab* Vachuff __attribute__((aligned(32))); +static f32 __THPIDCTWorkspace[64] __attribute__((aligned(32))); +static u8* __THPHuffmanBits; +static u8* __THPHuffmanSizeTab; +static u16* __THPHuffmanCodeTab; +static THPSample* Gbase __attribute__((aligned(32))); +static u32 Gwid __attribute__((aligned(32))); +static f32* Gq __attribute__((aligned(32))); +static u8 *__THPLCWork512[3]; +static u8 *__THPLCWork672[3]; +static u32 __THPOldGQR5; +static u32 __THPOldGQR6; +static u8* __THPWorkArea; +static THPCoeff* __THPMCUBuffer[6]; +static THPFileInfo* __THPInfo; +static BOOL __THPInitFlag = FALSE; + +#define ROUNDUP(a, b) ((((s32)(a)) + ((s32)(b) - 1L)) / ((s32)(b))) + +void __THPInverseDCTY8(register THPCoeff *, register u32); + +s32 THPVideoDecode(void *file, void *tileY, void *tileU, void *tileV, void *work) { + u8 all_done, status; + s32 errorCode; + + if (!file) { + goto _err_no_input; + } + + if (tileY == NULL || tileU == NULL || tileV == NULL) { + goto _err_no_output; + } + + if (!work) { + goto _err_no_work; + } + + if (!(PPCMfhid2() & 0x10000000)) { + goto _err_lc_not_enabled; + } + + if (__THPInitFlag == FALSE) { + goto _err_not_initialized; + } + + __THPWorkArea = (u8*)work; + __THPInfo = (THPFileInfo*)OSRoundUp32B(__THPWorkArea); + __THPWorkArea = (u8*)OSRoundUp32B(__THPWorkArea) + sizeof(THPFileInfo); + DCZeroRange(__THPInfo, sizeof(THPFileInfo)); + __THPInfo->cnt = 33; + __THPInfo->decompressedY = 0; + __THPInfo->c = (u8*)file; + all_done = FALSE; + + for (;;) { + if ((*(__THPInfo->c)++) != 255) { + goto _err_bad_syntax; + } + + while (*__THPInfo->c == 255) { + ((__THPInfo->c)++); + } + + status = (*(__THPInfo->c)++); + + if (status <= 0xD7) { + if (status == 196) { + status = __THPReadHuffmanTableSpecification(); + if (status != 0) { + goto _err_bad_status; + } + } + + else if (status == 192) { + status = __THPReadFrameHeader(); + if (status != 0) { + goto _err_bad_status; + } + } + + else { + goto _err_unsupported_marker; + } + } + + else if (0xD8 <= status && status <= 0xDF) { + if (status == 221) { + __THPRestartDefinition(); + } + + else if (status == 219) { + status = __THPReadQuantizationTable(); + if (status != 0) { + goto _err_bad_status; + } + } + + else if (status == 218) { + status = __THPReadScaneHeader(); + if (status != 0) { + goto _err_bad_status; + } + + all_done = TRUE; + } + else if (status == 216) { + // empty but required for match + } + else { + goto _err_unsupported_marker; + } + } + + else if (0xE0 <= status) { + if ((224 <= status && status <= 239) || status == 254) { + __THPInfo->c += (__THPInfo->c)[0] << 8 | (__THPInfo->c)[1]; + } + else { + goto _err_unsupported_marker; + } + } + + if (all_done) { + break; + } + } + + __THPSetupBuffers(); + __THPDecompressYUV(tileY, tileU, tileV); + return 0; + + +_err_no_input: + errorCode = 25; + goto _err_exit; + +_err_no_output: + errorCode = 27; + goto _err_exit; + +_err_no_work: + errorCode = 26; + goto _err_exit; + +_err_unsupported_marker: + errorCode = 11; + goto _err_exit; + +_err_bad_resource: + errorCode = 1; + goto _err_exit; + +_err_no_mem: + errorCode = 6; + goto _err_exit; + +_err_bad_syntax: + errorCode = 3; + goto _err_exit; + +_err_bad_status: + errorCode = status; + goto _err_exit; + +_err_lc_not_enabled: + errorCode = 28; + goto _err_exit; + +_err_not_initialized: + errorCode = 29; + goto _err_exit; + +_err_exit: + return errorCode; +} + +static void __THPSetupBuffers(void) { + u8 i; + THPCoeff* buffer; + + buffer = (THPCoeff*)OSRoundUp32B(__THPWorkArea); + + for (i = 0; i < 6; i++) { + __THPMCUBuffer[i] = &buffer[i * 64]; + } +} + +u8 __THPReadFrameHeader(void) { + u8 i, utmp8; + + __THPInfo->c += 2; + + utmp8 = (*(__THPInfo->c)++); + + if (utmp8 != 8) { + return 10; + } + + __THPInfo->yPixelSize = (u16)((__THPInfo->c)[0] << 8 | (__THPInfo->c)[1]); + __THPInfo->c += 2; + __THPInfo->xPixelSize = (u16)((__THPInfo->c)[0] << 8 | (__THPInfo->c)[1]); + __THPInfo->c += 2; + + utmp8 = (*(__THPInfo->c)++); + if (utmp8 != 3) { + return 12; + } + + for (i = 0; i < 3; i++) { + utmp8 = (*(__THPInfo->c)++); + utmp8 = (*(__THPInfo->c)++); + if ((i == 0 && utmp8 != 0x22) || (i > 0 && utmp8 != 0x11)) { + return 19; + } + + __THPInfo->components[i].quantizationTableSelector = (*(__THPInfo->c)++); + } + + return 0; +} + +/* there is an EXTREMELY tiny schedule swap but otherwise matching */ +u8 __THPReadScaneHeader(void) { + u8 i, utmp8; + __THPInfo->c += 2; + + utmp8 = (*(__THPInfo->c)++); + + if (utmp8 != 3) { + return 12; + } + + for (i = 0; i < 3; i++) { + utmp8 = (*(__THPInfo->c)++); + + utmp8 = (*(__THPInfo->c)++); + __THPInfo->components[i].DCTableSelector = (u8)(utmp8 >> 4); + __THPInfo->components[i].ACTableSelector = (u8)(utmp8 & 15); + + if ((__THPInfo->validHuffmanTabs & (1 << ((utmp8 >> 4)))) == 0) { + return 15; + } + + if ((__THPInfo->validHuffmanTabs & (1 << ((utmp8 & 15) + 1))) == 0) { + return 15; + } + } + + __THPInfo->c += 3; + __THPInfo->MCUsPerRow = (u16)ROUNDUP(__THPInfo->xPixelSize, 16); + __THPInfo->components[0].predDC = 0; + __THPInfo->components[1].predDC = 0; + __THPInfo->components[2].predDC = 0; + return 0; +} + +u8 __THPReadQuantizationTable(void) { + u16 length, id, i, row, col; + f32 q_temp[64]; + + length = (u16)((__THPInfo->c)[0] << 8 | (__THPInfo->c)[1]); + __THPInfo->c += 2; + length -= 2; + + for (;;) { + id = (*(__THPInfo->c)++); + + for (i = 0; i < 64; i++) { + q_temp[__THPJpegNaturalOrder[i]] = (f32)(*(__THPInfo->c)++); + } + + i = 0; + for (row = 0; row < 8; row++) { + for (col = 0; col < 8; col++) { + __THPInfo->quantTabs[id][i] = (f32)((f64)q_temp[i] * __THPAANScaleFactor[row] * __THPAANScaleFactor[col]); + i++; + } + } + + length -= 65; + if (!length) { + break; + } + } + + return 0; +} + +u8 __THPReadHuffmanTableSpecification(void) { + u8 t_class, id, i, tab_index; + u16 length, num_Vij; + + __THPHuffmanSizeTab = __THPWorkArea; + __THPHuffmanCodeTab = (u16 *)((u32)__THPWorkArea + 256 + 1); + length = (u16)((__THPInfo->c)[0] << 8 | (__THPInfo->c)[1]); + __THPInfo->c += 2; + length -= 2; + + for(;;) { + i = (*(__THPInfo->c)++); + id = (u8)(i & 15); + t_class = (u8)(i >> 4); + __THPHuffmanBits = __THPInfo->c; + tab_index = (u8)((id << 1) + t_class); + num_Vij = 0; + + for (i = 0; i < 16; i++) { + num_Vij += (*(__THPInfo->c)++); + } + + __THPInfo->huffmanTabs[tab_index].Vij = __THPInfo->c; + __THPInfo->c += num_Vij; + __THPHuffGenerateSizeTable(); + __THPHuffGenerateCodeTable(); + __THPHuffGenerateDecoderTables(tab_index); + __THPInfo->validHuffmanTabs |= 1 << tab_index; + length -= 17 + num_Vij; + + if (length == 0) { + break; + } + } + + return 0; +} + +static void __THPHuffGenerateCodeTable(void) { + u8 si; + u16 p, code; + + p = 0; + code = 0; + si = __THPHuffmanSizeTab[0]; + + while (__THPHuffmanSizeTab[p]) { + while (__THPHuffmanSizeTab[p] == si) { + __THPHuffmanCodeTab[p++] = code; + code++; + } + + code <<= 1; + si++; + } +} + +static void __THPHuffGenerateDecoderTables(u8 tabIndex) { + s32 p, l; + THPHuffmanTab* h; + + p = 0; + h = &__THPInfo->huffmanTabs[tabIndex]; + for (l = 1; l <= 16; l++) { + if (__THPHuffmanBits[l - 1]) { + h->valPtr[l] = p - __THPHuffmanCodeTab[p]; + p += __THPHuffmanBits[l - 1]; + h->maxCode[l] = __THPHuffmanCodeTab[p-1]; + } + else { + h->maxCode[l] = -1; + h->valPtr[l] = -1; + } + } + + h->maxCode[17] = 0xfffffL; +} + +static void __THPRestartDefinition(void) { + __THPInfo->RST = TRUE; + __THPInfo->c += 2; + __THPInfo->nMCU = (u16)((__THPInfo->c)[0] << 8 | (__THPInfo->c)[1]); + __THPInfo->c += 2; + __THPInfo->currMCU = __THPInfo->nMCU; +} + +static void __THPHuffGenerateSizeTable(void) { + s32 p, l, i; + p = 0; + + for (l = 1; l <= 16; l++) { + i = (s32)__THPHuffmanBits[l - 1]; + while (i--) { + __THPHuffmanSizeTab[p++] = (u8)l; + } + } + + __THPHuffmanSizeTab[p] = 0; +} + +static inline void __THPGQRSetup(void) { + register u32 tmp1, tmp2; + + asm { + mfspr tmp1, GQR5; + mfspr tmp2, GQR6; + } + + __THPOldGQR5 = tmp1; + __THPOldGQR6 = tmp2; + + asm { + li r3, 0x0007 + oris r3, r3, 0x0007 + mtspr GQR5, r3 + li r3, 0x3D04 + oris r3, r3, 0x3D04 + mtspr GQR6, r3 + } +} + +static inline void __THPGQRRestore(void) { + register u32 tmp1, tmp2; + tmp1 = __THPOldGQR5; + tmp2 = __THPOldGQR6; + + asm { + mtspr GQR5, tmp1; + mtspr GQR6, tmp2; + } +} + +void __THPPrepBitStream(void) { + u32* ptr; + u32 offset, i, j, k; + + ptr = (u32*)((u32)__THPInfo->c & 0xFFFFFFFC); + offset = (u32)__THPInfo->c & 3; + + if (__THPInfo->cnt != 33) { + __THPInfo->cnt -= (3 - offset)* 8; + } + else { + __THPInfo->cnt = (offset * 8) + 1; + } + + __THPInfo->c = (u8*)ptr; + __THPInfo->currByte = *ptr; + + for (i = 0; i < 4; i++) { + if (__THPInfo->validHuffmanTabs & (1 << i)) { + for (j = 0; j < 32; j++) { + __THPInfo->huffmanTabs[i].quick[j] = 0xFF; + + for (k = 0; k < 5; k++) { + s32 code = (s32)(j >> (5-k-1)); + + if (code <= __THPInfo->huffmanTabs[i].maxCode[k + 1]) { + __THPInfo->huffmanTabs[i].quick[j] = __THPInfo->huffmanTabs[i].Vij[(s32)(code + __THPInfo->huffmanTabs[i].valPtr[k + 1])]; + __THPInfo->huffmanTabs[i].increment[j] = (u8)(k + 1); + k = 99; + } + else { + } + } + } + } + } + + { + s32 YdcTab, UdcTab, VdcTab, YacTab, UacTab, VacTab; + + YdcTab = (__THPInfo->components[0].DCTableSelector << 1); + UdcTab = (__THPInfo->components[1].DCTableSelector << 1); + VdcTab = (__THPInfo->components[2].DCTableSelector << 1); + + YacTab = (__THPInfo->components[0].ACTableSelector << 1) + 1; + UacTab = (__THPInfo->components[1].ACTableSelector << 1) + 1; + VacTab = (__THPInfo->components[2].ACTableSelector << 1) + 1; + + Ydchuff = &__THPInfo->huffmanTabs[YdcTab]; + Udchuff = &__THPInfo->huffmanTabs[UdcTab]; + Vdchuff = &__THPInfo->huffmanTabs[VdcTab]; + + Yachuff = &__THPInfo->huffmanTabs[YacTab]; + Uachuff = &__THPInfo->huffmanTabs[UacTab]; + Vachuff = &__THPInfo->huffmanTabs[VacTab]; + } +} + +void __THPDecompressYUV(void *tileY, void *tileU, void *tileV) { + u16 currentY, targetY; + __THPInfo->dLC[0] = tileY; + __THPInfo->dLC[1] = tileU; + __THPInfo->dLC[2] = tileV; + + currentY = __THPInfo->decompressedY; + targetY = __THPInfo->yPixelSize; + + __THPGQRSetup(); + __THPPrepBitStream(); + + if (__THPInfo->xPixelSize == 512 && targetY == 448) { + while (currentY < targetY) { + __THPDecompressiMCURow512x448(); + currentY += 16; + } + } + else if (__THPInfo->xPixelSize == 640 && targetY == 480) { + while (currentY < targetY) { + __THPDecompressiMCURow640x480(); + currentY += 16; + } + } + else { + while (currentY < targetY) { + __THPDecompressiMCURowNxN(); + currentY += 16; + } + } + + __THPGQRRestore(); +} + +void __THPDecompressiMCURow512x448(void) { + u8 cl_num; + u32 x_pos; + THPComponent* comp; + + LCQueueWait(3); + + for (cl_num = 0; cl_num < __THPInfo->MCUsPerRow; cl_num++) { + __THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[0]); + __THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[1]); + __THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[2]); + __THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[3]); + __THPHuffDecodeDCTCompU(__THPInfo, __THPMCUBuffer[4]); + __THPHuffDecodeDCTCompV(__THPInfo, __THPMCUBuffer[5]); + + comp = &__THPInfo->components[0]; + Gbase = __THPLCWork512[0]; + Gwid = 512; + Gq = __THPInfo->quantTabs[comp->quantizationTableSelector]; + x_pos = (u32)(cl_num * 16); + __THPInverseDCTNoYPos(__THPMCUBuffer[0], x_pos); + __THPInverseDCTNoYPos(__THPMCUBuffer[1], x_pos + 8); + __THPInverseDCTY8(__THPMCUBuffer[2], x_pos); + __THPInverseDCTY8(__THPMCUBuffer[3], x_pos + 8); + + comp = &__THPInfo->components[1]; + Gbase = __THPLCWork512[1]; + Gwid = 256; + Gq = __THPInfo->quantTabs[comp->quantizationTableSelector]; + x_pos /= 2; + __THPInverseDCTNoYPos(__THPMCUBuffer[4], x_pos); + comp = &__THPInfo->components[2]; + Gbase = __THPLCWork512[2]; + Gq = __THPInfo->quantTabs[comp->quantizationTableSelector]; + __THPInverseDCTNoYPos(__THPMCUBuffer[5], x_pos); + + if (__THPInfo->RST != 0) { + if ((--__THPInfo->currMCU) == 0) { + __THPInfo->currMCU = __THPInfo->nMCU ; + __THPInfo->cnt = 1 + ((__THPInfo->cnt + 6) & 0xFFFFFFF8); + + if (__THPInfo->cnt > 33) { + __THPInfo->cnt = 33; + } + + __THPInfo->components[0].predDC = 0 ; + __THPInfo->components[1].predDC = 0 ; + __THPInfo->components[2].predDC = 0 ; + } + } + } + + LCStoreData(__THPInfo->dLC[0], __THPLCWork512[0], 0x2000); + LCStoreData(__THPInfo->dLC[1], __THPLCWork512[1], 0x800); + LCStoreData(__THPInfo->dLC[2], __THPLCWork512[2], 0x800); + + __THPInfo->dLC[0] += 0x2000; + __THPInfo->dLC[1] += 0x800; + __THPInfo->dLC[2] += 0x800; +} + +void __THPInverseDCTNoYPos(register THPCoeff *in, register u32 xPos) { + register f32 *q, *ws; + register f32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9; + register f32 tmp10, tmp11, tmp12, tmp13; + register f32 tmp20, tmp21, tmp22, tmp23; + register f32 cc4 = 1.414213562F; + register f32 cc2 = 1.847759065F; + register f32 cc2c6s = 1.082392200F; + register f32 cc2c6a = -2.613125930F; + register f32 bias = 1024.0F; + q = Gq; + ws = &__THPIDCTWorkspace[0] - 2; + + { + register u32 itmp0, itmp1, itmp2, itmp3; + asm { + li itmp2, 8 + mtctr itmp2 + + _loopHead0: + psq_l tmp10, 0(in), 0, 5 + psq_l tmp11, 0(q), 0, 0 + lwz itmp0, 12(in) + lwz itmp3, 8(in) + ps_mul tmp10, tmp10, tmp11 + lwz itmp1, 4(in) + lhz itmp2, 2(in) + or. itmp0, itmp0, itmp3 + + _loopHead1: + cmpwi itmp0, 0 + bne _regularIDCT + ps_merge00 tmp0, tmp10, tmp10 + cmpwi itmp1, 0 + psq_st tmp0, 8(ws), 0, 0 + bne _halfIDCT + psq_st tmp0, 16(ws), 0, 0 + cmpwi itmp2, 0 + psq_st tmp0, 24(ws), 0, 0 + bne _quarterIDCT + addi q, q, 8*sizeof(f32) + psq_stu tmp0, 32(ws), 0, 0 + addi in, in, 8*sizeof(THPCoeff) + bdnz _loopHead0 + b _loopEnd + + _quarterIDCT: + addi in, in, 8*sizeof(THPCoeff) + ps_msub tmp2, tmp10, cc2, tmp10 + addi q, q, 8*sizeof(f32) + ps_merge00 tmp9, tmp10, tmp10 + lwz itmp1, 4(in) + ps_sub tmp1, cc2, cc2c6s + ps_msub tmp3, tmp10, cc4, tmp2 + lhz itmp2, 2(in) + ps_merge11 tmp5, tmp10, tmp2 + psq_l tmp11, 0(q), 0, 0 + ps_nmsub tmp4, tmp10, tmp1, tmp3 + ps_add tmp7, tmp9, tmp5 + psq_l tmp10, 0(in), 0, 5 + ps_merge11 tmp6, tmp3, tmp4 + ps_sub tmp5, tmp9, tmp5 + lwz itmp0, 12(in) + ps_add tmp8, tmp9, tmp6 + lwz itmp3, 8(in) + ps_sub tmp6, tmp9, tmp6 + psq_stu tmp7, 8(ws), 0, 0 + ps_merge10 tmp6, tmp6, tmp6 + psq_stu tmp8, 8(ws), 0, 0 + ps_merge10 tmp5, tmp5, tmp5 + or itmp0, itmp0, itmp3 + psq_stu tmp6, 8(ws), 0, 0 + ps_mul tmp10, tmp10, tmp11 + psq_stu tmp5, 8(ws), 0, 0 + bdnz _loopHead1 + b _loopEnd + + _halfIDCT: + psq_l tmp1, 4(in), 0, 5 + psq_l tmp9, 8(q), 0, 0 + addi in, in, 8*sizeof(THPCoeff) + ps_mul tmp1, tmp1, tmp9 + addi q, q, 8*sizeof(f32) + ps_sub tmp3, tmp10, tmp1 + ps_add tmp2, tmp10, tmp1 + lwz itmp0, 12(in) + ps_madd tmp4, tmp1, cc4, tmp3 + ps_nmsub tmp5, tmp1, cc4, tmp2 + ps_mul tmp8, tmp3, cc2 + ps_merge00 tmp4, tmp2, tmp4 + lwz itmp3, 8(in) + ps_nmsub tmp6, tmp1, cc2c6a, tmp8 + ps_merge00 tmp5, tmp5, tmp3 + lwz itmp1, 4(in) + ps_sub tmp6, tmp6, tmp2 + ps_nmsub tmp7, tmp10, cc2c6s, tmp8 + lhz itmp2, 2(in) + ps_merge11 tmp2, tmp2, tmp6 + ps_msub tmp8, tmp3, cc4, tmp6 + psq_l tmp10, 0(in), 0, 5 + ps_add tmp9, tmp4, tmp2 + ps_sub tmp7, tmp7, tmp8 + psq_l tmp11, 0(q), 0, 0 + ps_merge11 tmp3, tmp8, tmp7 + ps_sub tmp4, tmp4, tmp2 + psq_stu tmp9, 8(ws), 0, 0 + ps_add tmp0, tmp5, tmp3 + ps_sub tmp1, tmp5, tmp3 + or itmp0, itmp0, itmp3 + psq_stu tmp0, 8(ws), 0, 0 + ps_merge10 tmp1, tmp1, tmp1 + ps_merge10 tmp4, tmp4, tmp4 + psq_stu tmp1, 8(ws), 0, 0 + ps_mul tmp10, tmp10, tmp11 + psq_stu tmp4, 8(ws), 0, 0 + bdnz _loopHead1 + b _loopEnd + + _regularIDCT: + psq_l tmp9, 4(in), 0, 5 + psq_l tmp5, 8(q), 0, 0 + ps_mul tmp9, tmp9, tmp5 + psq_l tmp2, 8(in), 0, 5 + psq_l tmp6, 16(q), 0, 0 + ps_merge01 tmp0, tmp10, tmp9 + psq_l tmp3, 12(in), 0, 5 + ps_merge01 tmp1, tmp9, tmp10 + psq_l tmp7, 24(q), 0, 0 + addi in, in, 8*sizeof(THPCoeff) + ps_madd tmp4, tmp2, tmp6, tmp0 + ps_nmsub tmp5, tmp2, tmp6, tmp0 + ps_madd tmp6, tmp3, tmp7, tmp1 + ps_nmsub tmp7, tmp3, tmp7, tmp1 + addi q, q, 8*sizeof(f32) + ps_add tmp0, tmp4, tmp6 + ps_sub tmp3, tmp4, tmp6 + ps_msub tmp2, tmp7, cc4, tmp6 + lwz itmp0, 12(in) + ps_sub tmp8, tmp7, tmp5 + ps_add tmp1, tmp5, tmp2 + ps_sub tmp2, tmp5, tmp2 + ps_mul tmp8, tmp8, cc2 + lwz itmp3, 8(in) + ps_merge00 tmp1, tmp0, tmp1 + ps_nmsub tmp6, tmp5, cc2c6a, tmp8 + ps_msub tmp4, tmp7, cc2c6s, tmp8 + lwz itmp1, 4(in) + ps_sub tmp6, tmp6, tmp0 + ps_merge00 tmp2, tmp2, tmp3 + lhz itmp2, 2(in) + ps_madd tmp5, tmp3, cc4, tmp6 + ps_merge11 tmp7, tmp0, tmp6 + psq_l tmp10, 0(in), 0, 5 + ps_sub tmp4, tmp4, tmp5 + ps_add tmp3, tmp1, tmp7 + psq_l tmp11, 0(q), 0, 0 + ps_merge11 tmp4, tmp5, tmp4 + ps_sub tmp0, tmp1, tmp7 + ps_mul tmp10, tmp10, tmp11 + ps_add tmp5, tmp2, tmp4 + ps_sub tmp6, tmp2, tmp4 + ps_merge10 tmp5, tmp5, tmp5 + psq_stu tmp3, 8(ws), 0, 0 + ps_merge10 tmp0, tmp0, tmp0 + psq_stu tmp6, 8(ws), 0, 0 + psq_stu tmp5, 8(ws), 0, 0 + or itmp0, itmp0, itmp3 + psq_stu tmp0, 8(ws), 0, 0 + bdnz _loopHead1 + + _loopEnd: + + } + } + + ws = &__THPIDCTWorkspace[0]; + + { + register THPSample *obase = Gbase; + register u32 wid = Gwid; + + register u32 itmp0, off0, off1; + register THPSample *out0, *out1; + + asm { + psq_l tmp10, 8*0*sizeof(f32)(ws), 0, 0 + slwi xPos, xPos, 2 + psq_l tmp11, 8*4*sizeof(f32)(ws), 0, 0 + slwi off1, wid, 2 + psq_l tmp12, 8*2*sizeof(f32)(ws), 0, 0 + mr off0, xPos + ps_add tmp6, tmp10, tmp11 + psq_l tmp13, 8*6*sizeof(f32)(ws), 0, 0 + ps_sub tmp8, tmp10, tmp11 + add off1, off0, off1 + ps_add tmp6, tmp6, bias + li itmp0, 3 + ps_add tmp7, tmp12, tmp13 + add out0, obase, off0 + ps_sub tmp9, tmp12, tmp13 + ps_add tmp0, tmp6, tmp7 + add out1, obase, off1 + ps_add tmp8, tmp8, bias + mtctr itmp0 + + _loopHead10: + psq_l tmp4, 8*1*sizeof(f32)(ws), 0, 0 + ps_msub tmp9, tmp9, cc4, tmp7 + psq_l tmp5, 8*3*sizeof(f32)(ws), 0, 0 + ps_sub tmp3, tmp6, tmp7 + ps_add tmp1, tmp8, tmp9 + psq_l tmp6, 8*5*sizeof(f32)(ws), 0, 0 + ps_sub tmp2, tmp8, tmp9 + psq_l tmp7, 8*7*sizeof(f32)(ws), 0, 0 + ps_add tmp8, tmp6, tmp5 + ps_sub tmp6, tmp6, tmp5 + addi ws, ws, 2*sizeof(f32) + ps_add tmp9, tmp4, tmp7 + ps_sub tmp4, tmp4, tmp7 + psq_l tmp10, 8*0*sizeof(f32)(ws), 0, 0 + ps_add tmp7, tmp9, tmp8 + ps_sub tmp5, tmp9, tmp8 + ps_add tmp8, tmp6, tmp4 + psq_l tmp11, 8*4*sizeof(f32)(ws), 0, 0 + ps_add tmp9, tmp0, tmp7 + ps_mul tmp8, tmp8, cc2 + psq_l tmp12, 8*2*sizeof(f32)(ws), 0, 0 + ps_sub tmp23, tmp0, tmp7 + ps_madd tmp6, tmp6, cc2c6a, tmp8 + psq_l tmp13, 8*6*sizeof(f32)(ws), 0, 0 + ps_sub tmp6, tmp6, tmp7 + addi off0, off0, 2*sizeof(THPSample) + psq_st tmp9, 0(out0), 0, 6 + ps_msub tmp4, tmp4, cc2c6s, tmp8 + ps_add tmp9, tmp1, tmp6 + ps_msub tmp5, tmp5, cc4, tmp6 + ps_sub tmp22, tmp1, tmp6 + psq_st tmp9, 8(out0), 0, 6 + ps_add tmp8, tmp2, tmp5 + ps_add tmp4, tmp4, tmp5 + psq_st tmp8, 16(out0), 0, 6 + addi off1, off1, 2*sizeof(THPSample) + ps_sub tmp9, tmp3, tmp4 + ps_add tmp20, tmp3, tmp4 + psq_st tmp9, 24(out0), 0, 6 + ps_sub tmp21, tmp2, tmp5 + ps_add tmp6, tmp10, tmp11 + psq_st tmp20, 0(out1), 0, 6 + ps_sub tmp8, tmp10, tmp11 + ps_add tmp6, tmp6, bias + psq_st tmp21, 8(out1), 0, 6 + ps_add tmp7, tmp12, tmp13 + ps_sub tmp9, tmp12, tmp13 + psq_st tmp22, 16(out1), 0, 6 + add out0, obase, off0 + ps_add tmp0, tmp6, tmp7 + psq_st tmp23, 24(out1), 0, 6 + ps_add tmp8, tmp8, bias + add out1, obase, off1 + bdnz _loopHead10 + psq_l tmp4, 8*1*sizeof(f32)(ws), 0, 0 + ps_msub tmp9, tmp9, cc4, tmp7 + psq_l tmp5, 8*3*sizeof(f32)(ws), 0, 0 + ps_sub tmp3, tmp6, tmp7 + ps_add tmp1, tmp8, tmp9 + psq_l tmp6, 8*5*sizeof(f32)(ws), 0, 0 + ps_sub tmp2, tmp8, tmp9 + psq_l tmp7, 8*7*sizeof(f32)(ws), 0, 0 + ps_add tmp8, tmp6, tmp5 + ps_sub tmp6, tmp6, tmp5 + ps_add tmp9, tmp4, tmp7 + ps_sub tmp4, tmp4, tmp7 + ps_add tmp7, tmp9, tmp8 + ps_sub tmp5, tmp9, tmp8 + ps_add tmp8, tmp6, tmp4 + ps_add tmp9, tmp0, tmp7 + ps_mul tmp8, tmp8, cc2 + ps_sub tmp23, tmp0, tmp7 + ps_madd tmp6, tmp6, cc2c6a, tmp8 + psq_st tmp9, 0(out0), 0, 6 + ps_sub tmp6, tmp6, tmp7 + ps_msub tmp4, tmp4, cc2c6s, tmp8 + psq_st tmp23, 24(out1), 0, 6 + ps_add tmp9, tmp1, tmp6 + ps_msub tmp5, tmp5, cc4, tmp6 + ps_sub tmp22, tmp1, tmp6 + psq_st tmp9, 8(out0), 0, 6 + ps_add tmp8, tmp2, tmp5 + ps_add tmp4, tmp4, tmp5 + psq_st tmp22, 16(out1), 0, 6 + psq_st tmp8, 16(out0), 0, 6 + ps_sub tmp9, tmp3, tmp4 + ps_add tmp20, tmp3, tmp4 + psq_st tmp9, 24(out0), 0, 6 + ps_sub tmp21, tmp2, tmp5 + psq_st tmp20, 0(out1), 0, 6 + psq_st tmp21, 8(out1), 0, 6 + } + } +} + +inline s32 __THPHuffDecodeTab(register THPFileInfo* info, register THPHuffmanTab* h) { + register s32 code; + register u32 cnt; + register s32 cb; + register u32 increment; + register s32 tmp; + + +#define cnt4 code + asm + { + lwz cnt, info->cnt; + addi increment, h, 32; + lwz cb, info->currByte; + addi cnt4, cnt, 4; + cmpwi cnt, 28; + rlwnm tmp, cb, cnt4, 27, 31; + bgt _notEnoughBits; + lbzx code, h, tmp; + lbzx increment, increment, tmp; + cmpwi code, 0xFF; + beq _FailedCheckEnoughBits; + add cnt, cnt, increment; + stw cnt, info->cnt; + } + _done: + return code; + + { + register u32 maxcodebase; + register u32 tmp2; + + _FailedCheckEnoughBits: + maxcodebase = (u32)&(h->maxCode); + cnt += 5; + + asm { + li tmp2, sizeof(s32)*(5); + li code, 5; + add maxcodebase, maxcodebase, tmp2; + __WHILE_START: + cmpwi cnt, 33; + slwi tmp, tmp, 1 + + beq _FCEB_faster; + rlwnm increment, cb, cnt, 31, 31; + lwzu tmp2, 4(maxcodebase); + or tmp, tmp, increment + addi cnt, cnt, 1; + b __WHILE_CHECK; + + _FCEB_faster: + lwz increment, info->c; + li cnt, 1; + lwzu cb, 4(increment); + lwzu tmp2, 4(maxcodebase); + + stw increment, info->c; + rlwimi tmp, cb, 1,31,31; + stw cb, info->currByte; + b __FL_WHILE_CHECK; + + __FL_WHILE_START: + slwi tmp, tmp, 1; + rlwnm increment, cb, cnt, 31, 31; + lwzu tmp2, 4(maxcodebase); + or tmp, tmp, increment; + + __FL_WHILE_CHECK: + cmpw tmp,tmp2 + addi cnt, cnt, 1; + addi code, code, 1 + bgt __FL_WHILE_START; + b _FCEB_Done; + + __WHILE_CHECK: + cmpw tmp,tmp2 + addi code, code, 1 + bgt __WHILE_START; + } + } + _FCEB_Done: + info->cnt = cnt; + return (h->Vij[(s32)(tmp + h->valPtr[code])]); + + asm + {// 6684 + _notEnoughBits: + cmpwi cnt, 33; + lwz tmp, info->c; + beq _getfullword; + + cmpwi cnt, 32; + rlwnm code, cb, cnt4, 27, 31 + beq _1bitleft; + + lbzx tmp, h, code; + lbzx increment, increment, code; + cmpwi tmp, 0xFF; + add code, cnt, increment; + beq _FailedCheckNoBits0; + + cmpwi code, 33; + stw code, info->cnt; + bgt _FailedCheckNoBits1; + } + return tmp; + + asm + { + _1bitleft: + lwzu cb, 4(tmp); + + stw tmp, info->c; + rlwimi code, cb, 4, 28, 31; + lbzx tmp, h, code; + lbzx increment, increment, code + stw cb, info->currByte; + cmpwi tmp, 0xFF + stw increment, info->cnt; + beq _DammitRead4; + + } + return tmp; + + _DammitRead4: + { + register u32 maxcodebase = (u32)&(h->maxCode); + register u32 tmp2; + + asm + { + li cnt, sizeof(s32)*5; + add maxcodebase, maxcodebase, cnt; + + slwi tmp, code, 32-5; + li cnt,5; + rlwimi tmp, cb, 32-1, 1,31; + + __DR4_WHILE_START: + + subfic cb, cnt, 31; + lwzu tmp2, 4(maxcodebase); + srw code, tmp, cb; + __DR4_WHILE_CHECK: + cmpw code, tmp2 + addi cnt, cnt, 1 + bgt __DR4_WHILE_START; + + } + } + + info->cnt = cnt; + __CODE_PLUS_VP_CNT: + return (h->Vij[(s32)(code + h->valPtr[cnt])]); + + _getfullword: + asm + { + lwzu cb, 4(tmp); + + rlwinm code, cb, 5, 27, 31 + stw tmp, info->c; + lbzx cnt, h, code; + lbzx increment, increment, code; + cmpwi cnt, 0xFF + stw cb, info->currByte; + addi increment, increment, 1 + beq _FailedCheckEnoughbits_Updated; + + stw increment, info->cnt; + } + return (s32)cnt; + + _FailedCheckEnoughbits_Updated: + + cnt = 5; + do + { + asm + { + subfic tmp, cnt, 31; + addi cnt, cnt, 1; + srw code, cb, tmp; + } + } while (code > h->maxCode[cnt]); + + info->cnt = cnt+1; + goto __CODE_PLUS_VP_CNT; + +#undef cnt4 + + _FailedCheckNoBits0: + _FailedCheckNoBits1: + + + { + register u32 mask = 0xFFFFFFFF << (33 - cnt); + register u32 tmp2; + + code = (s32)(cb & (~mask)); + mask = (u32)&(h->maxCode); + + asm + { + lwz tmp, info->c; + subfic tmp2, cnt, 33; + addi cnt, tmp2, 1; + slwi tmp2, tmp2, 2; + lwzu cb, 4(tmp); + add mask,mask, tmp2; + stw tmp, info->c; + slwi code, code, 1; + stw cb, info->currByte; + rlwimi code, cb, 1, 31, 31; + lwzu tmp2, 4(mask); + li tmp, 2; + b __FCNB1_WHILE_CHECK; + + __FCNB1_WHILE_START: + slwi code, code, 1; + + addi cnt, cnt, 1; + lwzu tmp2, 4(mask); + add code, code, increment; + addi tmp, tmp, 1; + + __FCNB1_WHILE_CHECK: + cmpw code, tmp2; + rlwnm increment, cb, tmp, 31, 31; + bgt __FCNB1_WHILE_START; + + } + } + + info->cnt = (u32)tmp; + return (h->Vij[(s32)(code + h->valPtr[cnt])]); + +} + +void __THPInverseDCTY8(register THPCoeff *in, register u32 xPos) { + register f32 *q, *ws; + register f32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9; + register f32 tmp10, tmp11, tmp12, tmp13; + register f32 tmp20, tmp21, tmp22, tmp23; + register f32 cc4 = 1.414213562F; + register f32 cc2 = 1.847759065F; + register f32 cc2c6s = 1.082392200F; + register f32 cc2c6a = -2.613125930F; + register f32 bias = 1024.0F; + + q = Gq; + ws = &__THPIDCTWorkspace[0] - 2; + + { + register u32 itmp0, itmp1, itmp2, itmp3; + + asm { + li itmp2, 8 + mtctr itmp2 + + _loopHead0: + psq_l tmp10, 0(in), 0, 5 + psq_l tmp11, 0(q), 0, 0 + lwz itmp0, 12(in) + lwz itmp3, 8(in) + ps_mul tmp10, tmp10, tmp11 + lwz itmp1, 4(in) + lhz itmp2, 2(in) + or itmp0, itmp0, itmp3 + + _loopHead1: + cmpwi itmp0, 0 + bne _regularIDCT + ps_merge00 tmp0, tmp10, tmp10 + cmpwi itmp1, 0 + psq_st tmp0, 8(ws), 0, 0 + bne _halfIDCT + psq_st tmp0, 16(ws), 0, 0 + cmpwi itmp2, 0 + psq_st tmp0, 24(ws), 0, 0 + bne _quarterIDCT + addi q, q, 8*sizeof(f32) + psq_stu tmp0, 32(ws), 0, 0 + addi in, in, 8*sizeof(THPCoeff) + bdnz _loopHead0 + b _loopEnd + + _quarterIDCT: + ps_msub tmp2, tmp10, cc2, tmp10 + addi in, in, 8*sizeof(THPCoeff) + ps_merge00 tmp9, tmp10, tmp10 + addi q, q, 8*sizeof(f32) + ps_sub tmp1, cc2, cc2c6s + lwz itmp1, 4(in) + ps_msub tmp3, tmp10, cc4, tmp2 + lhz itmp2, 2(in) + ps_merge11 tmp5, tmp10, tmp2 + psq_l tmp11, 0(q), 0, 0 + ps_nmsub tmp4, tmp10, tmp1, tmp3 + ps_add tmp7, tmp9, tmp5 + psq_l tmp10, 0(in), 0, 5 + ps_merge11 tmp6, tmp3, tmp4 + ps_sub tmp5, tmp9, tmp5 + lwz itmp0, 12(in) + ps_add tmp8, tmp9, tmp6 + lwz itmp3, 8(in) + ps_sub tmp6, tmp9, tmp6 + psq_stu tmp7, 8(ws), 0, 0 + ps_merge10 tmp6, tmp6, tmp6 + psq_stu tmp8, 8(ws), 0, 0 + ps_merge10 tmp5, tmp5, tmp5 + or itmp0, itmp0, itmp3 + psq_stu tmp6, 8(ws), 0, 0 + ps_mul tmp10, tmp10, tmp11 + psq_stu tmp5, 8(ws), 0, 0 + bdnz _loopHead1 + b _loopEnd + + _halfIDCT: + psq_l tmp1, 4(in), 0, 5 + psq_l tmp9, 8(q), 0, 0 + addi in, in, 8*sizeof(THPCoeff) + ps_mul tmp1, tmp1, tmp9 + addi q, q, 8*sizeof(f32) + ps_sub tmp3, tmp10, tmp1 + ps_add tmp2, tmp10, tmp1 + lwz itmp0, 12(in) + ps_madd tmp4, tmp1, cc4, tmp3 + ps_nmsub tmp5, tmp1, cc4, tmp2 + ps_mul tmp8, tmp3, cc2 + ps_merge00 tmp4, tmp2, tmp4 + lwz itmp3, 8(in) + ps_nmsub tmp6, tmp1, cc2c6a, tmp8 + ps_merge00 tmp5, tmp5, tmp3 + lwz itmp1, 4(in) + ps_sub tmp6, tmp6, tmp2 + ps_nmsub tmp7, tmp10, cc2c6s, tmp8 + lhz itmp2, 2(in) + ps_merge11 tmp2, tmp2, tmp6 + ps_msub tmp8, tmp3, cc4, tmp6 + psq_l tmp10, 0(in), 0, 5 + ps_add tmp9, tmp4, tmp2 + ps_sub tmp7, tmp7, tmp8 + psq_l tmp11, 0(q), 0, 0 + ps_merge11 tmp3, tmp8, tmp7 + ps_sub tmp4, tmp4, tmp2 + psq_stu tmp9, 8(ws), 0, 0 + ps_add tmp0, tmp5, tmp3 + ps_sub tmp1, tmp5, tmp3 + or itmp0, itmp0, itmp3 + psq_stu tmp0, 8(ws), 0, 0 + ps_merge10 tmp1, tmp1, tmp1 + ps_merge10 tmp4, tmp4, tmp4 + psq_stu tmp1, 8(ws), 0, 0 + ps_mul tmp10, tmp10, tmp11 + psq_stu tmp4, 8(ws), 0, 0 + bdnz _loopHead1 + b _loopEnd + + _regularIDCT: + psq_l tmp9, 4(in), 0, 5 + psq_l tmp5, 8(q), 0, 0 + ps_mul tmp9, tmp9, tmp5 + psq_l tmp2, 8(in), 0, 5 + psq_l tmp6, 16(q), 0, 0 + ps_merge01 tmp0, tmp10, tmp9 + psq_l tmp3, 12(in), 0, 5 + ps_merge01 tmp1, tmp9, tmp10 + psq_l tmp7, 24(q), 0, 0 + addi in, in, 8*sizeof(THPCoeff) + ps_madd tmp4, tmp2, tmp6, tmp0 + ps_nmsub tmp5, tmp2, tmp6, tmp0 + ps_madd tmp6, tmp3, tmp7, tmp1 + ps_nmsub tmp7, tmp3, tmp7, tmp1 + addi q, q, 8*sizeof(f32) + ps_add tmp0, tmp4, tmp6 + ps_sub tmp3, tmp4, tmp6 + ps_msub tmp2, tmp7, cc4, tmp6 + lwz itmp0, 12(in) + ps_sub tmp8, tmp7, tmp5 + ps_add tmp1, tmp5, tmp2 + ps_sub tmp2, tmp5, tmp2 + ps_mul tmp8, tmp8, cc2 + lwz itmp3, 8(in) + ps_merge00 tmp1, tmp0, tmp1 + ps_nmsub tmp6, tmp5, cc2c6a, tmp8 + ps_msub tmp4, tmp7, cc2c6s, tmp8 + lwz itmp1, 4(in) + ps_sub tmp6, tmp6, tmp0 + ps_merge00 tmp2, tmp2, tmp3 + lhz itmp2, 2(in) + ps_madd tmp5, tmp3, cc4, tmp6 + ps_merge11 tmp7, tmp0, tmp6 + psq_l tmp10, 0(in), 0, 5 + ps_sub tmp4, tmp4, tmp5 + ps_add tmp3, tmp1, tmp7 + psq_l tmp11, 0(q), 0, 0 + ps_merge11 tmp4, tmp5, tmp4 + ps_sub tmp0, tmp1, tmp7 + ps_mul tmp10, tmp10, tmp11 + ps_add tmp5, tmp2, tmp4 + ps_sub tmp6, tmp2, tmp4 + ps_merge10 tmp5, tmp5, tmp5 + psq_stu tmp3, 8(ws), 0, 0 + ps_merge10 tmp0, tmp0, tmp0 + psq_stu tmp6, 8(ws), 0, 0 + psq_stu tmp5, 8(ws), 0, 0 + or itmp0, itmp0, itmp3 + psq_stu tmp0, 8(ws), 0, 0 + bdnz _loopHead1 + + _loopEnd: + + } + + } + + ws = &__THPIDCTWorkspace[0]; + + { + register THPSample *obase = Gbase; + register u32 wid = Gwid; + + register u32 itmp0, off0, off1; + register THPSample *out0, *out1; + + asm { + psq_l tmp10, 8*0*sizeof(f32)(ws), 0, 0 + slwi off0, wid, 3; + psq_l tmp11, 8*4*sizeof(f32)(ws), 0, 0 + slwi xPos, xPos, 2 + psq_l tmp12, 8*2*sizeof(f32)(ws), 0, 0 + slwi off1, wid, 2 + ps_add tmp6, tmp10, tmp11 + add off0, off0, xPos + psq_l tmp13, 8*6*sizeof(f32)(ws), 0, 0 + ps_sub tmp8, tmp10, tmp11 + add off1, off0, off1 + ps_add tmp6, tmp6, bias + li itmp0, 3 + ps_add tmp7, tmp12, tmp13 + add out0, obase, off0 + ps_sub tmp9, tmp12, tmp13 + ps_add tmp0, tmp6, tmp7 + add out1, obase, off1 + ps_add tmp8, tmp8, bias + mtctr itmp0 + + _loopHead10: + psq_l tmp4, 8*1*sizeof(f32)(ws), 0, 0 + ps_msub tmp9, tmp9, cc4, tmp7 + psq_l tmp5, 8*3*sizeof(f32)(ws), 0, 0 + ps_sub tmp3, tmp6, tmp7 + ps_add tmp1, tmp8, tmp9 + psq_l tmp6, 8*5*sizeof(f32)(ws), 0, 0 + ps_sub tmp2, tmp8, tmp9 + psq_l tmp7, 8*7*sizeof(f32)(ws), 0, 0 + ps_add tmp8, tmp6, tmp5 + ps_sub tmp6, tmp6, tmp5 + addi ws, ws, 2*sizeof(f32) + ps_add tmp9, tmp4, tmp7 + ps_sub tmp4, tmp4, tmp7 + psq_l tmp10, 8*0*sizeof(f32)(ws), 0, 0 + ps_add tmp7, tmp9, tmp8 + ps_sub tmp5, tmp9, tmp8 + ps_add tmp8, tmp6, tmp4 + psq_l tmp11, 8*4*sizeof(f32)(ws), 0, 0 + ps_add tmp9, tmp0, tmp7 + ps_mul tmp8, tmp8, cc2 + psq_l tmp12, 8*2*sizeof(f32)(ws), 0, 0 + ps_sub tmp23, tmp0, tmp7 + ps_madd tmp6, tmp6, cc2c6a, tmp8 + psq_l tmp13, 8*6*sizeof(f32)(ws), 0, 0 + ps_sub tmp6, tmp6, tmp7 + addi off0, off0, 2*sizeof(THPSample) + psq_st tmp9, 0(out0), 0, 6 + ps_msub tmp4, tmp4, cc2c6s, tmp8 + ps_add tmp9, tmp1, tmp6 + ps_msub tmp5, tmp5, cc4, tmp6 + ps_sub tmp22, tmp1, tmp6 + psq_st tmp9, 8(out0), 0, 6 + ps_add tmp8, tmp2, tmp5 + ps_add tmp4, tmp4, tmp5 + psq_st tmp8, 16(out0), 0, 6 + addi off1, off1, 2*sizeof(THPSample) + ps_sub tmp9, tmp3, tmp4 + ps_add tmp20, tmp3, tmp4 + psq_st tmp9, 24(out0), 0, 6 + ps_sub tmp21, tmp2, tmp5 + ps_add tmp6, tmp10, tmp11 + psq_st tmp20, 0(out1), 0, 6 + ps_sub tmp8, tmp10, tmp11 + ps_add tmp6, tmp6, bias + psq_st tmp21, 8(out1), 0, 6 + ps_add tmp7, tmp12, tmp13 + ps_sub tmp9, tmp12, tmp13 + psq_st tmp22, 16(out1), 0, 6 + add out0, obase, off0 + ps_add tmp0, tmp6, tmp7 + psq_st tmp23, 24(out1), 0, 6 + ps_add tmp8, tmp8, bias + add out1, obase, off1 + + bdnz _loopHead10 + psq_l tmp4, 8*1*sizeof(f32)(ws), 0, 0 + ps_msub tmp9, tmp9, cc4, tmp7 + psq_l tmp5, 8*3*sizeof(f32)(ws), 0, 0 + ps_sub tmp3, tmp6, tmp7 + ps_add tmp1, tmp8, tmp9 + psq_l tmp6, 8*5*sizeof(f32)(ws), 0, 0 + ps_sub tmp2, tmp8, tmp9 + psq_l tmp7, 8*7*sizeof(f32)(ws), 0, 0 + ps_add tmp8, tmp6, tmp5 + ps_sub tmp6, tmp6, tmp5 + ps_add tmp9, tmp4, tmp7 + ps_sub tmp4, tmp4, tmp7 + ps_add tmp7, tmp9, tmp8 + ps_sub tmp5, tmp9, tmp8 + ps_add tmp8, tmp6, tmp4 + ps_add tmp9, tmp0, tmp7 + ps_mul tmp8, tmp8, cc2 + ps_sub tmp23, tmp0, tmp7 + ps_madd tmp6, tmp6, cc2c6a, tmp8 + psq_st tmp9, 0(out0), 0, 6 + ps_sub tmp6, tmp6, tmp7 + ps_msub tmp4, tmp4, cc2c6s, tmp8 + psq_st tmp23, 24(out1), 0, 6 + ps_add tmp9, tmp1, tmp6 + ps_msub tmp5, tmp5, cc4, tmp6 + ps_sub tmp22, tmp1, tmp6 + psq_st tmp9, 8(out0), 0, 6 + ps_add tmp8, tmp2, tmp5 + ps_add tmp4, tmp4, tmp5 + psq_st tmp8, 16(out0), 0, 6 + ps_sub tmp9, tmp3, tmp4 + psq_st tmp22, 16(out1), 0, 6 + ps_add tmp20, tmp3, tmp4 + psq_st tmp9, 24(out0), 0, 6 + ps_sub tmp21, tmp2, tmp5 + psq_st tmp20, 0(out1), 0, 6 + psq_st tmp21, 8(out1), 0, 6 + + } + } +} + +void __THPDecompressiMCURow640x480(void) { + u8 cl_num; + u32 x_pos; + THPComponent* comp; + + LCQueueWait(3); + + { + for (cl_num = 0; cl_num < __THPInfo->MCUsPerRow; cl_num++) { + THPFileInfo* um = __THPInfo; + __THPHuffDecodeDCTCompY(um, __THPMCUBuffer[0]); + __THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[1]); + __THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[2]); + __THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[3]); + __THPHuffDecodeDCTCompU(__THPInfo, __THPMCUBuffer[4]); + __THPHuffDecodeDCTCompV(__THPInfo, __THPMCUBuffer[5]); + + comp = &__THPInfo->components[0]; + Gbase = __THPLCWork672[0]; + Gwid = 640; + Gq = __THPInfo->quantTabs[comp->quantizationTableSelector]; + x_pos = (u32)(cl_num * 16); + __THPInverseDCTNoYPos(__THPMCUBuffer[0], x_pos); + __THPInverseDCTNoYPos(__THPMCUBuffer[1], x_pos + 8); + __THPInverseDCTY8(__THPMCUBuffer[2], x_pos); + __THPInverseDCTY8(__THPMCUBuffer[3], x_pos + 8); + + comp = &__THPInfo->components[1]; + Gbase = __THPLCWork672[1]; + Gwid = 320; + Gq = __THPInfo->quantTabs[comp->quantizationTableSelector]; + x_pos /= 2; + __THPInverseDCTNoYPos(__THPMCUBuffer[4], x_pos); + + comp = &__THPInfo->components[2]; + Gbase = __THPLCWork672[2]; + Gq = __THPInfo->quantTabs[comp->quantizationTableSelector]; + __THPInverseDCTNoYPos(__THPMCUBuffer[5], x_pos); + + if (__THPInfo->RST != 0) { + __THPInfo->currMCU --; + if (__THPInfo->currMCU == 0) { + __THPInfo->currMCU = __THPInfo->nMCU ; + + __THPInfo->cnt = 1 + ((__THPInfo->cnt + 6) & 0xFFFFFFF8); + + if (__THPInfo->cnt > 32) { + __THPInfo->cnt = 33; + } + + __THPInfo->components[0].predDC = 0 ; + __THPInfo->components[1].predDC = 0 ; + __THPInfo->components[2].predDC = 0 ; + } + } + } + } + + LCStoreData(__THPInfo->dLC[0], __THPLCWork672[0], 0x2800); + LCStoreData(__THPInfo->dLC[1], __THPLCWork672[1], 0xA00); + LCStoreData(__THPInfo->dLC[2], __THPLCWork672[2], 0xA00); + + __THPInfo->dLC[0] += 0x2800; + __THPInfo->dLC[1] += 0xA00; + __THPInfo->dLC[2] += 0xA00; +} + +void __THPDecompressiMCURowNxN(void) { + u8 cl_num; + u32 x_pos, x; + THPComponent* comp; + + x = __THPInfo->xPixelSize; + + LCQueueWait(3); + + for (cl_num = 0; cl_num < __THPInfo->MCUsPerRow; cl_num++) { + __THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[0]); + __THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[1]); + __THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[2]); + __THPHuffDecodeDCTCompY(__THPInfo, __THPMCUBuffer[3]); + __THPHuffDecodeDCTCompU(__THPInfo, __THPMCUBuffer[4]); + __THPHuffDecodeDCTCompV(__THPInfo, __THPMCUBuffer[5]); + + comp = &__THPInfo->components[0]; + Gbase = __THPLCWork672[0]; + Gwid = x; + Gq = __THPInfo->quantTabs[comp->quantizationTableSelector]; + x_pos = (u32)(cl_num * 16); + __THPInverseDCTNoYPos(__THPMCUBuffer[0], x_pos); + __THPInverseDCTNoYPos(__THPMCUBuffer[1], x_pos + 8); + __THPInverseDCTY8(__THPMCUBuffer[2], x_pos); + __THPInverseDCTY8(__THPMCUBuffer[3], x_pos + 8); + + comp = &__THPInfo->components[1]; + Gbase = __THPLCWork672[1]; + Gwid = x / 2; + Gq = __THPInfo->quantTabs[comp->quantizationTableSelector]; + x_pos /= 2; + __THPInverseDCTNoYPos(__THPMCUBuffer[4], x_pos); + + comp = &__THPInfo->components[2]; + Gbase = __THPLCWork672[2]; + Gq = __THPInfo->quantTabs[comp->quantizationTableSelector]; + __THPInverseDCTNoYPos(__THPMCUBuffer[5], x_pos); + + if (__THPInfo->RST != 0) { + __THPInfo->currMCU--; + if (__THPInfo->currMCU == 0) { + __THPInfo->currMCU = __THPInfo->nMCU ; + __THPInfo->cnt = 1 + ((__THPInfo->cnt + 6) & 0xFFFFFFF8); + + if (__THPInfo->cnt > 32) { + __THPInfo->cnt = 33; + } + + __THPInfo->components[0].predDC = 0; + __THPInfo->components[1].predDC = 0; + __THPInfo->components[2].predDC = 0; + } + } + } + + LCStoreData(__THPInfo->dLC[0], __THPLCWork672[0], ((4 * sizeof(u8) * 64) * (x / 16))); + LCStoreData(__THPInfo->dLC[1], __THPLCWork672[1], ((sizeof(u8) * 64) * (x / 16))); + LCStoreData(__THPInfo->dLC[2], __THPLCWork672[2], ((sizeof(u8) * 64) * (x / 16))); + __THPInfo->dLC[0] += ((4 * sizeof(u8) * 64) * (x / 16)); + __THPInfo->dLC[1] += ((sizeof(u8) * 64) * (x / 16)); + __THPInfo->dLC[2] += ((sizeof(u8) * 64) * (x / 16)); +} + +void __THPHuffDecodeDCTCompY(register THPFileInfo* info, THPCoeff* block) { + { + register s32 t; + THPCoeff dc; + register THPCoeff diff; + + __dcbz((void*)block, 0); + t = __THPHuffDecodeTab(info, Ydchuff); + __dcbz((void*)block, 32); + diff = 0; + __dcbz((void*)block, 64); + + if (t) { + { + register s32 v; + register u32 cb; + register u32 cnt; + register u32 cnt33; + register u32 tmp; + register u32 cnt1; + register u32 tmp1; + asm { + lwz cnt,info->cnt; + subfic cnt33,cnt,33; + lwz cb,info->currByte; + + subfc. tmp, cnt33, t; + subi cnt1,cnt,1; + + bgt _notEnoughBitsDIFF; + add v,cnt,t; + + slw cnt,cb,cnt1; + stw v,info->cnt; + subfic v,t,32; + srw diff,cnt,v; + } + + asm { + b _DoneDIFF; + _notEnoughBitsDIFF: + lwz tmp1, info->c; + slw v, cb, cnt1; + lwzu cb, 4(tmp1); + addi tmp, tmp, 1; + stw cb, info->currByte; + srw cb, cb, cnt33; + stw tmp1, info->c; + add v, cb, v; + stw tmp, info->cnt; + subfic tmp, t,32; + srw diff, v, tmp; + _DoneDIFF: + } + + } + + if (__cntlzw((u32)diff) > 32 - t) { + diff += ((0xFFFFFFFF << t) + 1); + } + }; + + __dcbz((void*)block, 96); + dc = (s16)(info->components[0].predDC + diff); + block[0] = info->components[0].predDC = dc; + } + + + { + register s32 k; + register s32 code; + register u32 cnt; + register u32 cb; + register u32 increment; + register s32 tmp; + register THPHuffmanTab *h = Yachuff; + +#define cnt4 code + asm + { + lwz cnt, info->cnt; + addi increment, h, 32; + lwz cb, info->currByte; + } + + for( k = 1; k < 64; k++) { + register s32 ssss; + register s32 rrrr; + + asm { + addi cnt4, cnt, 4; + cmpwi cnt, 28; + rlwnm tmp, cb, cnt4, 27, 31; + bgt _notEnoughBits; + + lbzx ssss, h, tmp; + lbzx code, increment, tmp; + cmpwi ssss, 0xFF; + + beq _FailedCheckEnoughBits; + add cnt, cnt, code; + b _DoneDecodeTab; + } + + { + register u32 maxcodebase; + register u32 tmp2; + + _FailedCheckEnoughBits: + cnt += 5; + maxcodebase = (u32)&(h->maxCode); + asm { + li tmp2, sizeof(s32)*(5); + li code, 5; + add maxcodebase, maxcodebase, tmp2; + __WHILE_START: + cmpwi cnt, 33; + slwi tmp, tmp, 1 + + beq _FCEB_faster; + rlwnm ssss, cb, cnt, 31, 31; + lwzu tmp2, 4(maxcodebase); + or tmp, tmp, ssss + addi cnt, cnt, 1; + b __WHILE_CHECK; + + _FCEB_faster: + lwz ssss, info->c; + li cnt, 1; + lwzu cb, 4(ssss); + + lwzu tmp2, 4(maxcodebase); + + stw ssss, info->c; + rlwimi tmp, cb, 1,31,31; + b __FL_WHILE_CHECK; + + __FL_WHILE_START: + slwi tmp, tmp, 1; + + rlwnm ssss, cb, cnt, 31, 31; + lwzu tmp2, 4(maxcodebase); + or tmp, tmp, ssss; + + __FL_WHILE_CHECK: + cmpw tmp,tmp2 + addi cnt, cnt, 1; + addi code, code, 1 + bgt __FL_WHILE_START; + b _FCEB_Done; + + __WHILE_CHECK: + cmpw tmp,tmp2 + addi code, code, 1 + bgt __WHILE_START; + } + } + _FCEB_Done: + ssss= (h->Vij[(s32)(tmp + h->valPtr[code])]); + goto _DoneDecodeTab; + + _notEnoughBits: + asm + { + cmpwi cnt, 33; + lwz tmp, info->c; + beq _getfullword; + + cmpwi cnt, 32; + rlwnm code, cb, cnt4, 27, 31 + beq _1bitleft; + + lbzx ssss, h, code; + lbzx rrrr, increment, code; + cmpwi ssss, 0xFF; + add code, cnt, rrrr; + beq _FailedCheckNoBits0; + + cmpwi code, 33; + bgt _FailedCheckNoBits1; + } + cnt = (u32)code; + goto _DoneDecodeTab; + + _getfullword: + { + asm + { + lwzu cb, 4(tmp); + rlwinm code, cb, 5, 27, 31 + stw tmp, info->c; + lbzx ssss, h, code; + lbzx tmp, increment, code; + cmpwi ssss, 0xFF + addi cnt, tmp, 1 + beq _FailedCheckEnoughbits_Updated; + } + } + goto _DoneDecodeTab; + + + _FailedCheckEnoughbits_Updated: + ssss = 5; + do { + asm + { + subfic tmp, ssss, 31; + addi ssss, ssss, 1; + srw code, cb, tmp; + } + } while (code > h->maxCode[ssss]); + + cnt = (u32)(ssss+1); + ssss = (h->Vij[(s32)(code + h->valPtr[ssss])]); + + goto _DoneDecodeTab; + + _1bitleft: + asm { + lwzu cb, 4(tmp); + + stw tmp, info->c; + rlwimi code, cb, 4, 28, 31; + lbzx ssss, h, code; + lbzx cnt, increment, code + cmpwi ssss, 0xFF + beq _DammitRead4; + + } + + goto _DoneDecodeTab; + + _DammitRead4: + { + register u32 maxcodebase = (u32)&(h->maxCode); + register u32 tmp2; + + asm { + li cnt, sizeof(s32)*5; + add maxcodebase, maxcodebase, cnt; + + slwi tmp, code, 32-5; + li cnt,5; + rlwimi tmp, cb, 32-1, 1,31; + + __DR4_WHILE_START: + + subfic ssss, cnt, 31; + lwzu tmp2, 4(maxcodebase); + srw code, tmp, ssss; + __DR4_WHILE_CHECK: + cmpw code, tmp2 + addi cnt, cnt, 1 + bgt __DR4_WHILE_START; + + } + } + ssss = (h->Vij[(s32)(code + h->valPtr[cnt])]); + goto _DoneDecodeTab; + + + _FailedCheckNoBits0: + _FailedCheckNoBits1: + _REALFAILEDCHECKNOBITS: + { + register u32 mask = 0xFFFFFFFF << (33 - cnt); + register u32 tmp2; + register u32 tmp3; + code = (s32)(cb & (~mask)); + mask = (u32)&(h->maxCode); + + asm { + lwz tmp, info->c; + subfic tmp2, cnt, 33; + addi tmp3, tmp2, 1; + slwi tmp2, tmp2, 2; + lwzu cb, 4(tmp); + add mask,mask, tmp2; + stw tmp, info->c; + slwi code, code, 1; + rlwimi code, cb, 1, 31, 31; + lwzu tmp2, 4(mask); + li cnt, 2; + b __FCNB1_WHILE_CHECK; + + __FCNB1_WHILE_START: + slwi code, code, 1; + + addi tmp3, tmp3, 1; + lwzu tmp2, 4(mask); + add code, code, rrrr; + addi cnt, cnt, 1; + + __FCNB1_WHILE_CHECK: + cmpw code, tmp2; + rlwnm rrrr, cb, cnt, 31, 31; + bgt __FCNB1_WHILE_START; + + } + ssss= (h->Vij[(s32)(code + h->valPtr[tmp3])]); + } + + goto _DoneDecodeTab; + + _DoneDecodeTab: + asm { + andi. rrrr, ssss, 15; + srawi ssss, ssss, 4; + beq _RECV_SSSS_ZERO; + } + + { + k += ssss; + { + register s32 v; + #define cnt33 code + register u32 cnt1; + register u32 tmp1; + asm + { + subfic cnt33,cnt,33; + subfc. tmp, cnt33, rrrr; + subi cnt1,cnt,1; + bgt _RECVnotEnoughBits; + add cnt,cnt,rrrr; + slw tmp1,cb,cnt1; + subfic v,rrrr,32; + srw ssss,tmp1,v; + } + asm { + b _RECVDone; + _RECVnotEnoughBits: + lwz tmp1, info->c; + slw v, cb, cnt1; + lwzu cb, 4(tmp1); + addi cnt, tmp, 1; + stw tmp1, info->c; + srw tmp1, cb, cnt33; + + add v, tmp1, v; + subfic tmp, rrrr,32; + srw ssss, v, tmp; + _RECVDone: + } + } + + #undef cnt33 + + if (__cntlzw((u32)ssss) > 32 - rrrr) { + ssss += ((0xFFFFFFFF << rrrr) + 1); + } + + block[__THPJpegNaturalOrder[k]] = (s16)ssss; + goto _RECV_END; + + } + + { + _RECV_SSSS_ZERO: + if (ssss != 15) { + break; + } + + k += 15; + }; + + asm + { + _RECV_END: + } + } + info->cnt = cnt; + info->currByte = cb; + } +#undef cnt4 +} + +void __THPHuffDecodeDCTCompU(register THPFileInfo* info, THPCoeff* block) { + register s32 t; + register THPCoeff diff; + THPCoeff dc; + register s32 v; + register u32 cb; + register u32 cnt; + register u32 cnt33; + register u32 tmp; + register u32 cnt1; + register u32 tmp1; + register s32 k; + register s32 ssss; + register s32 rrrr; + + __dcbz((void*)block, 0); + t = __THPHuffDecodeTab(info, Udchuff); + __dcbz((void*)block, 32); + diff = 0; + __dcbz((void*)block, 64); + + if (t) { + asm + { + lwz cnt,info->cnt; + subfic cnt33,cnt,33; + lwz cb,info->currByte; + subfc. tmp, cnt33, t; + subi cnt1,cnt,1; + bgt _notEnoughBitsDIFF; + add v,cnt,t; + slw cnt,cb,cnt1; + stw v,info->cnt; + subfic v,t,32; + srw diff,cnt,v; + } + + asm + { + b _DoneDIFF; + _notEnoughBitsDIFF: + lwz tmp1, info->c; + slw v, cb, cnt1; + lwzu cb, 4(tmp1); + addi tmp, tmp, 1; + stw cb, info->currByte; + srw cb, cb, cnt33; + stw tmp1, info->c; + add v, cb, v; + stw tmp, info->cnt; + subfic tmp, t,32; + srw diff, v, tmp; + _DoneDIFF: + } + + if (__cntlzw((u32)diff) > 32 - t) { + diff += ((0xFFFFFFFF << t) + 1); + } + } + + __dcbz((void*)block, 96); + dc = (s16)(info->components[1].predDC + diff); + block[0] = info->components[1].predDC = dc; + + for (k = 1; k < 64; k++) { + ssss = __THPHuffDecodeTab(info, Uachuff); + rrrr = ssss >> 4; + ssss &= 15; + + if (ssss) { + k += rrrr; + asm + { + lwz cnt,info->cnt; + subfic cnt33,cnt,33; + lwz cb,info->currByte; + subf. tmp, cnt33, ssss; + subi cnt1,cnt,1; + bgt _notEnoughBits; + add v,cnt,ssss; + slw cnt,cb,cnt1; + stw v,info->cnt; + subfic v,ssss,32; + srw rrrr,cnt,v; + } + + asm + { + b _Done; + _notEnoughBits: + lwz tmp1, info->c; + slw v, cb, cnt1; + lwzu cb, 4(tmp1); + addi tmp, tmp, 1; + stw cb, info->currByte; + srw cb, cb, cnt33; + stw tmp1, info->c; + add v, cb, v; + stw tmp, info->cnt; + subfic tmp, ssss,32; + srw rrrr, v, tmp; + _Done: + } + + if (__cntlzw((u32)rrrr) > 32 - ssss) { + rrrr += ((0xFFFFFFFF << ssss) + 1); + } + + block[__THPJpegNaturalOrder[k]] = (s16)rrrr; + } + + else { + if (rrrr != 15) break; + k += 15; + } + } +} + +void __THPHuffDecodeDCTCompV(register THPFileInfo* info, THPCoeff* block) { + register s32 t; + register THPCoeff diff; + THPCoeff dc; + register s32 v; + register u32 cb; + register u32 cnt; + register u32 cnt33; + register u32 tmp; + register u32 cnt1; + register u32 tmp1; + register s32 k; + register s32 ssss; + register s32 rrrr; + + __dcbz((void*)block, 0); + t = __THPHuffDecodeTab(info, Vdchuff); + __dcbz((void*)block, 32); + diff = 0; + __dcbz((void*)block, 64); + + if (t){ + asm + { + lwz cnt,info->cnt; + subfic cnt33,cnt,33; + lwz cb,info->currByte; + subf. tmp, cnt33, t; + subi cnt1,cnt,1; + bgt _notEnoughBitsDIFF; + add v,cnt,t; + slw cnt,cb,cnt1; + stw v,info->cnt; + subfic v,t,32; + srw diff,cnt,v; + } + + asm + { + b _DoneDIFF; + _notEnoughBitsDIFF: + lwz tmp1, info->c; + slw v, cb, cnt1; + lwzu cb, 4(tmp1); + addi tmp, tmp, 1; + stw cb, info->currByte; + srw cb, cb, cnt33; + stw tmp1, info->c; + add v, cb, v; + stw tmp, info->cnt; + subfic tmp, t,32; + srw diff, v, tmp; + _DoneDIFF: + } + + if (__cntlzw((u32)diff) > 32 - t) { + diff += ((0xFFFFFFFF << t) + 1); + } + } + + __dcbz((void*)block, 96); + + dc = (s16)(info->components[2].predDC + diff); + block[0] = info->components[2].predDC = dc; + + for (k = 1; k < 64; k++) + { + ssss = __THPHuffDecodeTab(info, Vachuff); + rrrr = ssss >> 4; + ssss &= 15; + + if (ssss) { + k += rrrr; + + asm + { + lwz cnt,info->cnt; + subfic cnt33,cnt,33; + lwz cb,info->currByte; + + subf. tmp, cnt33, ssss; + subi cnt1,cnt,1; + + bgt _notEnoughBits; + add v,cnt,ssss; + + slw cnt,cb,cnt1; + stw v,info->cnt; + subfic v,ssss,32; + srw rrrr,cnt,v; + } + + asm + { + b _Done; + _notEnoughBits: + lwz tmp1, info->c; + slw v, cb, cnt1; + lwzu cb, 4(tmp1); + addi tmp, tmp, 1; + stw cb, info->currByte; + srw cb, cb, cnt33; + stw tmp1, info->c; + add v, cb, v; + stw tmp, info->cnt; + subfic tmp, ssss,32; + srw rrrr, v, tmp; + _Done: + } + + + if (__cntlzw((u32)rrrr) > 32 - ssss) { + rrrr += ((0xFFFFFFFF << ssss) + 1); + } + + block[__THPJpegNaturalOrder[k]] = (s16)rrrr; + } + else { + if (rrrr != 15) break; + k += 15; + } + } +} + +BOOL THPInit(void) { + u8* base; + OSRegisterVersion(__THPVersion); + base = (u8*)(0xE000 << 16); // lc base + + __THPLCWork512[0] = base; + base += 0x2000; + __THPLCWork512[1] = base; + base += 0x800; + __THPLCWork512[2] = base; + base += 0x200; + + base = (u8*)(0xE000 << 16); // lc base + __THPLCWork672[0] = base; + base += 0x2A00; + __THPLCWork672[1] = base; + base += 0xA80; + __THPLCWork672[2] = base; + base += 0xA80; + + // OSInitFastCast + __asm { + li r3, 4 + oris r3, r3, 4 + mtspr 0x392, r3 + li r3, 5 + oris r3, r3, 5 + mtspr 0x393, r3 + li r3, 6 + oris r3, r3, 6 + mtspr 0x394, r3 + li r3, 7 + oris r3, r3, 7 + mtspr 0x395, r3 + }; + + __THPInitFlag = TRUE; + return TRUE; +} diff --git a/src/RVL_SDK/tpl/TPL.c b/src/RVL_SDK/tpl/TPL.c new file mode 100644 index 000000000..84f8a6b9d --- /dev/null +++ b/src/RVL_SDK/tpl/TPL.c @@ -0,0 +1,37 @@ +#include "revolution/tpl.h" +#include "revolution/os.h" + +void TPLBind(TPLPalettePtr ptr) { + u16 i; + + if (ptr->versionNumber != 2142000) { + OSPanic(__FILE__, 0x19, "invalid version number for texture palette"); + } + + ptr->descriptorArray = (TPLDescriptorPtr)(((u32)(ptr->descriptorArray)) + ((u32)ptr)); + + for (i = 0; i < ptr->numDescriptors; i++) { + if (ptr->descriptorArray[i].textureHeader) { + ptr->descriptorArray[i].textureHeader = (TPLHeaderPtr)(((u32)(ptr->descriptorArray[i].textureHeader)) + ((u32)ptr)); + + if (!ptr->descriptorArray[i].textureHeader->unpacked) { + ptr->descriptorArray[i].textureHeader->data = (char*)((u32)(ptr->descriptorArray[i].textureHeader->data) + (u32)ptr); + ptr->descriptorArray[i].textureHeader->unpacked = 1; + } + } + + if (ptr->descriptorArray[i].CLUTHeader) { + ptr->descriptorArray[i].CLUTHeader = (TPLClutHeaderPtr)((u32)(ptr->descriptorArray[i].CLUTHeader) + (u32)ptr); + + if (!ptr->descriptorArray[i].CLUTHeader->unpacked) { + ptr->descriptorArray[i].CLUTHeader->data = (char*)((u32)(ptr->descriptorArray[i].CLUTHeader->data) + (u32)ptr); + ptr->descriptorArray[i].CLUTHeader->unpacked = 1; + } + } + } +} + +TPLDescriptorPtr TPLGet(TPLPalettePtr ptr, u32 id) { + id %= ptr->numDescriptors; + return &ptr->descriptorArray[id]; +} \ No newline at end of file diff --git a/src/RVL_SDK/vi/i2c.c b/src/RVL_SDK/vi/i2c.c new file mode 100644 index 000000000..bbd76e9bc --- /dev/null +++ b/src/RVL_SDK/vi/i2c.c @@ -0,0 +1,240 @@ +#include + +static volatile u32 __i2c_ident_flag = 1; +static volatile u32 __i2c_ident_first = 0; + +#define busRd32(addr) (*(volatile u32 *)(addr)) +#define busWrt32(addr, val) (*(volatile u32 *)(addr)) = (val) + +void WaitMicroTime(s32 usec) { + OSTime t = __OSGetSystemTime(); + + while (OSTicksToMicroseconds(__OSGetSystemTime() - t) < usec); +} + +static void VICheckI2C(void) { + __i2c_ident_flag = 1; +} + +static BOOL __VISetSCL(u32 value) { + u32 reg; + value &= 1; + + reg = busRd32(0xCD8000C0); + reg &= ~(1 << 14); + reg = (u32)(reg | (value << 14)); + busWrt32(0xCD8000C0, reg); + return TRUE; +} + +static BOOL __VISetSDA(u32 value) { + u32 reg; + value &= 1; + reg = busRd32(0xCD8000C0); + reg &= ~(1 << 15); + reg = (u32)(reg | (value << 15)); + busWrt32(0xCD8000C0, reg); + return TRUE; +} + +static u32 __VIGetSDA(void) { + u32 reg = busRd32(0xCD8000C0); + return (u32)((reg >> 15) & 1); +} + +static void __VIOpenI2C(u32 dir) { + u32 reg = busRd32(0xCD8000C4); + reg = (u32)(reg & ~(1 << 15)); + reg = (u32)(reg | (1 << 14) | (dir << 15)); + busWrt32(0xCD8000C4, reg); +} + +static int wait4ClkHigh(void) { + WaitMicroTime(2); + return 1; +} + +static s32 sendSlaveAddr(u8 slaveAddr) { + int i; + + if (0 == __i2c_ident_flag) { + __VISetSDA(1); + } + else { + __VISetSDA(0); + } + + WaitMicroTime(2); + __VISetSCL(0); + + for (i = 0; i < 8; i++) { + if (slaveAddr & 0x80) { + if (0 == __i2c_ident_flag) { + __VISetSDA(0); + } + else { + __VISetSDA(1); + } + } + else { + if (0 == __i2c_ident_flag) { + __VISetSDA(1); + } + else { + __VISetSDA(0); + } + } + + WaitMicroTime(2); + __VISetSCL(1); + + if (!wait4ClkHigh()) { + return 0; + } + + __VISetSCL(0); + slaveAddr <<= 1; + } + + __VIOpenI2C(0); + WaitMicroTime(2); + __VISetSCL(1); + + if (!wait4ClkHigh()) { + return 0; + } + + if (1 == __i2c_ident_flag) { + if (__VIGetSDA() != 0) { + return 0; + } + } + + if (0 == __i2c_ident_flag) { + __VISetSDA(1); + } + else { + __VISetSDA(0); + } + + __VIOpenI2C(1); + __VISetSCL(0); + + return 1; +} + +s32 __VISendI2CData(u8 slaveAddr, u8 *pData, s32 nBytes) { + int i; + u8 data; + BOOL enabled; + + if (__i2c_ident_first == 0) { + VICheckI2C(); + __i2c_ident_first = 1; + } + + enabled = OSDisableInterrupts(); + + __VIOpenI2C(1); + __VISetSCL(1); + + if(0 == __i2c_ident_flag) { + __VISetSDA(0); + } + else { + __VISetSDA(1); + } + + WaitMicroTime(2); + WaitMicroTime(2); + + if (!sendSlaveAddr(slaveAddr)) { + OSRestoreInterrupts(enabled); + return 0; + } + + __VIOpenI2C(1); + + while (nBytes) { + data = *pData++; + + for (i = 0; i < 8; i++) { + if (data & 0x80) { + if (0 == __i2c_ident_flag) { + __VISetSDA(0); + } + else { + __VISetSDA(1); + } + } + else { + if (0 == __i2c_ident_flag) { + __VISetSDA(1); + } + else { + __VISetSDA(0); + } + } + + WaitMicroTime(2); + __VISetSCL(1); + + if (!wait4ClkHigh()) { + OSRestoreInterrupts(enabled); + return 0; + } + __VISetSCL(0); + data <<= 1; + } + + __VIOpenI2C(0); + WaitMicroTime(2); + __VISetSCL(1); + + if (!wait4ClkHigh()) { + OSRestoreInterrupts(enabled); + return 0; + } + + if (1 == __i2c_ident_flag) { + if (__VIGetSDA() != 0) { + OSRestoreInterrupts(enabled); + return 0; + } + } + + if (0 == __i2c_ident_flag) { + __VISetSDA(1); + } + else { + __VISetSDA(0); + } + + __VIOpenI2C(1); + __VISetSCL(0); + nBytes--; + } + + __VIOpenI2C(1); + + if (0 == __i2c_ident_flag) { + __VISetSDA(1); + } + else { + __VISetSDA(0); + } + + WaitMicroTime(2); + __VISetSCL(1); + WaitMicroTime(2); + + if(0 == __i2c_ident_flag) { + __VISetSDA(0); + } + else { + __VISetSDA(1); + } + + OSRestoreInterrupts(enabled); + return 1; +} \ No newline at end of file diff --git a/src/RVL_SDK/vi/vi.c b/src/RVL_SDK/vi/vi.c new file mode 100644 index 000000000..02f84f814 --- /dev/null +++ b/src/RVL_SDK/vi/vi.c @@ -0,0 +1,1717 @@ +#include +#include +#include +#include +#include "private/flipper.h" + +const char* __VIVersion = "<< RVL_SDK - VI \trelease build: Aug 8 2007 02:07:17 (0x4199_60831) >>"; + +extern BOOL __OSIsDiag; +static BOOL IsInitialized = FALSE; +static void __VIRetraceHandler(__OSInterrupt, OSContext *); + +static volatile u32 retraceCount; +static volatile u32 flushFlag; +static volatile u32 flushFlag3in1; +static vu32 vsync_timing_err_cnt = 0; +static vu32 vsync_timing_test_flag = 0; + +static volatile BOOL __VIDimming_All_Clear = FALSE; +static volatile BOOL __VIDimmingFlag_Enable; +static volatile BOOL __VIDVDStopFlag_Enable; +static volatile VITimeToDIM g_current_time_to_dim; +static vu32 THD_TIME_TO_DIMMING = 0; +static vu32 NEW_TIME_TO_DIMMING = 0; +static vu32 THD_TIME_TO_DVD_STOP = 0; +static vu32 _gIdleCount_dimming = 0; +static vu32 _gIdleCount_dvd = 0; +static vu32 __VIDimmingFlag_RF_IDLE; +static vu32 __VIDimmingFlag_SI_IDLE; +static vu32 __VIDimmingFlag_DEV_IDLE[10]; +static volatile BOOL __VIDimmingState = FALSE; + +extern VIVideo Vdac_Flag_Region; +extern volatile u32 Vdac_Flag_Changed = 0; + +static OSThreadQueue retraceQueue; + +static vu32 __VIDimmingFlag_DEV_IDLE[10]; + +#define ToPhysical(fb) (u32)(((u32)(fb)) & 0x3FFFFFFF) +#define IS_LOWER_16MB(x) ((x) < 16*1024*1024) +#define ONES(x) ((1 << (x)) - 1) + +#define VI_NUMREGS (sizeof(__VIRegs)/sizeof(__VIRegs[0])) + +static vu32 changeMode = 0; +static vu64 changed = 0; +static u16 regs[VI_NUMREGS]; + +static vu32 shdwChangeMode = 0; +static vu64 shdwChanged = 0; +static u16 shdwRegs[VI_NUMREGS]; + +static HorVer_s HorVer; +static timing_s* CurrTiming; +static u32 CurrTvMode; + +static u32 NextBufAddr; +static u32 CurrBufAddr; + +static u32 FBSet = 0; + +static VIRetraceCallback PreCB; +static VIRetraceCallback PostCB; +static VIPositionCallback PositionCallback = NULL; + +static u32 encoderType; +static s16 displayOffsetH = 0; +static s16 displayOffsetV = 0; + +static BOOL OnShutdown( BOOL final, u32 event ); +static OSShutdownFunctionInfo ShutdownFunctionInfo = { + OnShutdown, + 127 +}; + +static timing_s timing[] = { + { + 6, + 240, + 24, + 25, + 3, + 2, + 12, + 13, + 12, + 13, + 520, + 519, + 520, + 519, + 525, + 429, + 64, + 71, + 105, + 162, + 373, + 122, + 412, + }, + { + 6, + 240, + 24, + 24, + 4, + 4, + 12, + 12, + 12, + 12, + 520, + 520, + 520, + 520, + 526, + 429, + 64, + 71, + 105, + 162, + 373, + 122, + 412, + }, + + { + 5, + 287, + 35, + 36, + 1, + 0, + 13, + 12, + 11, + 10, + 619, + 618, + 617, + 620, + 625, + 432, + 64, + 75, + 106, + 172, + 380, + 133, + 420, + }, + + { + 5, + 287, + 33, + 33, + 2, + 2, + 13, + 11, + 13, + 11, + 619, + 621, + 619, + 621, + 624, + 432, + 64, + 75, + 106, + 172, + 380, + 133, + 420, + }, + + { + 6, + 240, + 24, + 25, + 3, + 2, + 16, + 15, + 14, + 13, + 518, + 517, + 516, + 519, + 525, + 429, + 64, + 78, + 112, + 162, + 373, + 122, + 412, + }, + + { + 6, + 240, + 24, + 24, + 4, + 4, + 16, + 14, + 16, + 14, + 518, + 520, + 518, + 520, + 526, + 429, + 64, + 78, + 112, + 162, + 373, + 122, + 412, + }, + + { + 12, + 480, + 48, + 48, + 6, + 6, + 24, + 24, + 24, + 24, + 1038, + 1038, + 1038, + 1038, + 1050, + 429, + 64, + 71, + 105, + 162, + 373, + 122, + 412, + }, + + { + 12, + 480, + 44, + 44, + 10, + 10, + 24, + 24, + 24, + 24, + 1038, + 1038, + 1038, + 1038, + 1050, + 429, + 64, + 71, + 105, + 168, + 379, + 122, + 412, + }, + + { + 6, + 241, + 24, + 25, + 1, + 0, + 12, + 13, + 12, + 13, + 520, + 519, + 520, + 519, + 525, + 429, + 64, + 71, + 105, + 159, + 370, + 122, + 412, + }, + + { + 12, + 480, + 48, + 48, + 6, + 6, + 24, + 24, + 24, + 24, + 1038, + 1038, + 1038, + 1038, + 1050, + 429, + 64, + 71, + 105, + 180, + 391, + 122, + 412, + }, + + { + 10, + 576, + 62, + 62, + 6, + 6, + 20, + 20, + 20, + 20, + 1240, + 1240, + 1240, + 1240, + 1250, + 432, + 64, + 75, + 106, + 172, + 380, + 122, + 412, + } +}; + +static timing_s* timingExtra = NULL; + +static u16 taps[] = { + 0x1f0, + 0x1dc, + 0x1ae, + 0x174, + 0x129, + 0x0db, + 0x08e, + 0x046, + 0x0c, + 0xe2, + 0xcb, + 0xc0, + 0xc4, + 0xcf, + 0xde, + 0xec, + 0xfc, + 0x08, + 0x0f, + 0x13, + 0x13, + 0x0f, + 0x0c, + 0x08, + 0x01, +}; + +static BOOL OnShutdown(BOOL final, u32 event) { + BOOL retval; + static BOOL first = TRUE; + static u32 count; + + if (final == FALSE) { + switch (event) { + case 3: + case 1: + case 2: + if (first) { + VISetRGBModeImm(); + VIFlush(); + count = retraceCount; + first = FALSE; + retval = FALSE; + } + else { + if (count == retraceCount) { + retval = FALSE; + } + else { + retval = TRUE; + } + } + break; + + case 4: + case 0: + case 6: + case 5: + retval = TRUE; + break; + } + } + else { + retval = TRUE; + } + + return retval; +} + +static void GetCurrentDisplayPosition(u32 *hct, u32 *vct) { + u32 hcount, vcount0, vcount; + + vcount = (u32)((__VIRegs[0x16]) & 0x7FF); + + do { + vcount0 = vcount; + hcount = (u32)(__VIRegs[0x17] & 0x7FF); + vcount = (u32)(__VIRegs[0x16] & 0x7FF); + } while (vcount0 != vcount); + + *hct = hcount; + *vct = vcount; +} + +static u32 getCurrentFieldEvenOdd(void); +static s32 cntlzd(u64); + +static BOOL VISetRegs(void) { + s32 regIndex; + + if (!((shdwChangeMode == 1) && (getCurrentFieldEvenOdd() == 0))) { + while (shdwChanged) { + regIndex = cntlzd(shdwChanged); + __VIRegs[regIndex] = shdwRegs[regIndex]; + shdwChanged &= ~(1ull << (63 - (regIndex))); + } + + shdwChangeMode = 0; + CurrTiming = HorVer.timing; + CurrTvMode = HorVer.tv; + CurrBufAddr = NextBufAddr; + + return TRUE; + } + else { + return FALSE; + } +} + +extern DVDCommandBlock __DVDStopMotorCommandBlock; + +static void __VIRetraceHandler(__OSInterrupt interrupt, OSContext* context) { + OSContext exceptionContext; + u16 reg; + u32 inter = 0; + u32 regIndex; + static u32 old_dtvStatus = 999; + static u32 old_tvtype = 999; + u32 now_dtvStatus = 0; + u32 now_tvtype = 0; + static BOOL __VIDimmingFlag_Enable_old = TRUE; + static BOOL __VIDVDStopFlag_Enable_old = TRUE; + u32 i; + static u32 DimmingON_Pending = 0; + static u32 DimmingOFF_Pending = 0; + + reg = __VIRegs[0x18]; + if (reg & 0x8000) { + __VIRegs[0x18] = (u16)(reg & ~0x8000); + inter |= 1; + } + + reg = __VIRegs[0x1A]; + if (reg & 0x8000) { + __VIRegs[0x1A] = (u16)(reg & ~0x8000); + inter |= 2; + } + + reg = __VIRegs[0x1C]; + if (reg & 0x8000) { + __VIRegs[0x1C] = (u16)(reg & ~0x8000); + inter |= 4; + } + + reg = __VIRegs[0x1E]; + if (reg & 0x8000) { + __VIRegs[0x1E] = (u16)(reg & ~0x8000); + inter |= 8; + } + + reg = __VIRegs[0x1E]; + + if ((inter & 4) || (inter & 8)) { + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + + if (PositionCallback) { + s16 x, y; + __VIGetCurrentPosition(&x, &y); + (*PositionCallback)(x, y); + } + + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + return; + } + + retraceCount++; + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + + if (PreCB) { + (*PreCB)(retraceCount); + } + + if (vsync_timing_test_flag) { + u32 hcount, vcount; + + GetCurrentDisplayPosition(&hcount, &vcount); + + if(!((vcount == 1) || (vcount == (CurrTiming->nhlines / 2 + 1)))) { + vsync_timing_err_cnt++; + } + } + + if (flushFlag) { + if (VISetRegs()) { + flushFlag = 0; + SIRefreshSamplingRate(); + } + } + + now_dtvStatus = VIGetDTVStatus(); + if(now_dtvStatus != old_dtvStatus) { + __VISetYUVSEL((VIBool)now_dtvStatus); + } + + old_dtvStatus = now_dtvStatus; + now_tvtype = VIGetTvFormat(); + + if (now_tvtype != old_tvtype) { + if (now_tvtype == VI_EURGB60) { + __VISetFilter4EURGB60(VI_ENABLE); + } + else { + __VISetFilter4EURGB60(VI_DISABLE); + } + + switch (now_tvtype) { + case VI_PAL: + switch(g_current_time_to_dim) { + case VI_DM_10M: + NEW_TIME_TO_DIMMING = 30000; + break; + case VI_DM_15M: + NEW_TIME_TO_DIMMING = 45000; + break; + default: + NEW_TIME_TO_DIMMING = 15000; + break; + } + THD_TIME_TO_DVD_STOP = 90000; + break; + default: + switch(g_current_time_to_dim) { + case VI_DM_10M: + NEW_TIME_TO_DIMMING = 36000; + break; + case VI_DM_15M: + NEW_TIME_TO_DIMMING = 54000; + break; + default: + NEW_TIME_TO_DIMMING = 18000; + break; + } + THD_TIME_TO_DVD_STOP = 108000; + break; + } + + _gIdleCount_dimming = 0; + _gIdleCount_dvd = 0; + } + + old_tvtype = now_tvtype; + + + if (flushFlag3in1) { + while (Vdac_Flag_Changed) { + regIndex = (u32)__cntlzw(Vdac_Flag_Changed); + regIndex = (u32)(1 << (31 - regIndex)); + + switch(regIndex) { + case 1: + __VISetCGMS(); + break; + case 2: + __VISetWSS(); + break; + case 4: + __VISetClosedCaption(); + break; + case 8: + __VISetMacrovision(); + break; + case 0x10: + __VISetGamma(); + break; + case 0x20: + __VISetTrapFilter(); + break; + case 0x40: + __VISetRGBOverDrive(); + break; + case 0x80: + __VISetRGBModeImm(); + break; + } + + Vdac_Flag_Changed &= ~regIndex; + } + + flushFlag3in1 = 0; + } + + + if (PostCB) { + OSClearContext(&exceptionContext); + (*PostCB)(retraceCount); + } + + OSWakeupThread(&retraceQueue); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + + if (__VIDimming_All_Clear == TRUE) { + if(__OSSetVIForceDimming(FALSE, 0, 0) == TRUE) { + __VIDimming_All_Clear = FALSE; + _gIdleCount_dimming = 0; + } + } + + for (i = 0; i < 10; i++) { + if(__VIDimmingFlag_DEV_IDLE[i] == 0) { + __VIDimmingFlag_DEV_IDLE[0] = 0; + break; + } + } + + if(__VIDimmingFlag_RF_IDLE && __VIDimmingFlag_SI_IDLE && __VIDimmingFlag_DEV_IDLE[0]) { + if ((__VIDimmingFlag_Enable == TRUE) && (_gIdleCount_dimming < 0xFFFFFFFF)) { + _gIdleCount_dimming++; + } + + if ((__VIDVDStopFlag_Enable == TRUE) && (_gIdleCount_dvd < 0xFFFFFFFF)) { + _gIdleCount_dvd++; + } + } + else { + if (_gIdleCount_dimming >= THD_TIME_TO_DIMMING) { + DimmingOFF_Pending = 1; + } + if (_gIdleCount_dvd >= THD_TIME_TO_DVD_STOP) { + __DVDRestartMotor(); + } + + _gIdleCount_dimming = 0; + _gIdleCount_dvd = 0; + THD_TIME_TO_DIMMING = NEW_TIME_TO_DIMMING; + } + + if (__VIDimmingFlag_Enable_old != __VIDimmingFlag_Enable) { + if (__VIDimmingFlag_Enable == FALSE) { + if (_gIdleCount_dimming >= THD_TIME_TO_DIMMING) { + DimmingOFF_Pending = 1; + } + } + + _gIdleCount_dimming = 0; + THD_TIME_TO_DIMMING = NEW_TIME_TO_DIMMING; + } + + if (_gIdleCount_dimming == THD_TIME_TO_DIMMING) { + DimmingON_Pending = 1; + } + + if (DimmingOFF_Pending) { + if (__OSSetVIForceDimming(FALSE, 2, 2) == TRUE) { + DimmingOFF_Pending = 0; + __VIDimmingState = FALSE; + } + } + + if (DimmingON_Pending) { + if (__OSSetVIForceDimming(TRUE, 2, 2) == TRUE) { + DimmingON_Pending = 0; + __VIDimmingState = TRUE; + } + } + + if (__VIDVDStopFlag_Enable_old != __VIDVDStopFlag_Enable) { + if (__VIDVDStopFlag_Enable == FALSE) { + if (_gIdleCount_dvd >= THD_TIME_TO_DVD_STOP) { + __DVDRestartMotor(); + } + } + _gIdleCount_dvd = 0; + } + + if(_gIdleCount_dvd == THD_TIME_TO_DVD_STOP) { + __DVDStopMotorAsync(&__DVDStopMotorCommandBlock, NULL); + } + + __VIDimmingFlag_RF_IDLE = 1; + __VIDimmingFlag_SI_IDLE = 1; + + for(i = 0; i < 10; i++) + { + __VIDimmingFlag_DEV_IDLE[i] = 1; + } + + __VIDimmingFlag_Enable_old = __VIDimmingFlag_Enable; + __VIDVDStopFlag_Enable_old = __VIDVDStopFlag_Enable; + + if ((NEW_TIME_TO_DIMMING > _gIdleCount_dimming) && (__VIDimmingState == FALSE)) { + THD_TIME_TO_DIMMING = NEW_TIME_TO_DIMMING; + } +} + +static void setScalingRegs(u16 panSizeX, u16 dispSizeX, BOOL threeD) { + u32 scale; + + panSizeX = (u16)(threeD? panSizeX * 2 : panSizeX); + + if (panSizeX < dispSizeX) { + scale = (256 * (u32)panSizeX + (u32)dispSizeX - 1)/ (u32)dispSizeX; + + regs[0x25] = (u16)((((unsigned long)(scale)) ) | (((unsigned long)(1)) << 12)); + changed |= (1ull << (63 - (0x25))); + + regs[0x38] = (u16)((((unsigned long)(panSizeX)) )); + changed |= (1ull << (63 - (0x38))); + } + else { + regs[0x25] = (u16)((((unsigned long)(256)) ) | (((unsigned long)(0)) << 12)); + changed |= (1ull << (63 - (0x25))); + } +} + +static void calcFbbs(u32 bufAddr, u16 panPosX, u16 panPosY, u8 wordPerLine, VIXFBMode xfbMode, u16 dispPosY, u32* tfbb, u32* bfbb) { + u32 bytesPerLine, xoffInWords; + xoffInWords = (u32)panPosX / 16; + bytesPerLine = (u32)wordPerLine * 32; + + *tfbb = bufAddr + xoffInWords * 32 + bytesPerLine * panPosY; + *bfbb = (xfbMode == VI_XFBMODE_SF) ? *tfbb : (*tfbb + bytesPerLine); + + if (dispPosY % 2 == 1) { + u32 tmp = *tfbb; + *tfbb = *bfbb; + *bfbb = tmp; + } + + *tfbb = ToPhysical(*tfbb); + *bfbb = ToPhysical(*bfbb); +} + +void setFbbRegs(HorVer_s* HorVer, u32* tfbb, u32* bfbb, u32* rtfbb, u32* rbfbb) { + u32 shifted; + calcFbbs(HorVer->bufAddr, HorVer->PanPosX, HorVer->AdjustedPanPosY, HorVer->wordPerLine, HorVer->FBMode, HorVer->AdjustedDispPosY, tfbb, bfbb); + + if (HorVer->threeD) { + calcFbbs(HorVer->rbufAddr, HorVer->PanPosX, HorVer->AdjustedPanPosY, HorVer->wordPerLine, HorVer->FBMode, HorVer->AdjustedDispPosY, rtfbb, rbfbb); + } + + if (IS_LOWER_16MB(*tfbb) && IS_LOWER_16MB(*bfbb) && IS_LOWER_16MB(*rtfbb) && IS_LOWER_16MB(*rbfbb)) { + shifted = 0; + } + else { + shifted = 1; + } + + if (shifted) { + *tfbb >>= 5; + *bfbb >>= 5; + *rtfbb >>= 5; + *rbfbb >>= 5; + } + + regs[0xF] = (u16)(*tfbb & 0xFFFF); + changed |= (1ull << (63 - (0xF))); + + regs[0xE] = (u16)((((*tfbb >> 16))) | HorVer->xof << 8 | shifted << 12); + changed |= (1ull << (63 - (0xE))); + + regs[0x13] = (u16)(*bfbb & 0xFFFF); + changed |= (1ull << (63 - (0x13))); + + regs[0x12] = (u16)(*bfbb >> 16); + changed |= (1ull << (63 - (0x12))); + + if (HorVer->threeD) { + regs[0x11] = *rtfbb & 0xffff; + changed |= (1ull << (63 - (0x11))); + + regs[0x10] = *rtfbb >> 16; + changed |= (1ull << (63 - (0x10))); + + regs[0x15] = *rbfbb & 0xFFFF; + changed |= (1ull << (63 - (0x15))); + + regs[0x16] = *rbfbb >> 16; + changed |= (1ull << (63 - (0x14))); + } +} + +void setHorizontalRegs(timing_s* tm, u16 dispPosX, u16 dispSizeX) { + u32 hbe, hbs, hbeLo, hbeHi; + + regs[0x3] = (u16)tm->hlw; + changed |= (1ull << (63 - (0x3))); + + regs[2] = (u16)(tm->hce | tm->hcs << 8); + changed |= (1ull << (63 - (0x2))); + + if (HorVer.tv == 8) { + hbe = (u32)(tm->hbe640 + 172); + hbs = tm->hbs640; + } + else { + hbe = (u32)(tm->hbe640 - 40 + dispPosX); + hbs = (u32)(tm->hbs640 + 40 + dispPosX - (720 - dispSizeX)); + } + + hbeLo = hbe & ONES(9); + hbeHi = hbe >> 9; + + regs[5] = (u16)(tm->hsy | hbeLo << 7); + changed |= (1ull << (63 - (0x05))); + + regs[4] = (u16)(hbeHi| hbs << 1); + changed |= (1ull << (63 - (0x04))); +} + +void setVerticalRegs(u16 dispPosY, u16 dispSizeY, u8 equ, u16 acv, u16 prbOdd, u16 prbEven, u16 psbOdd, u16 psbEven, BOOL black) { + u16 actualPrbOdd, actualPrbEven, actualPsbOdd, actualPsbEven, actualAcv, c, d; + + if ((HorVer.nonInter == 2) || (HorVer.nonInter == 3)) { + c = 1; + d = 2; + } + else { + c = 2; + d = 1; + } + + if (dispPosY % 2 == 0) { + actualPrbOdd = (u16)(prbOdd + d * dispPosY); + actualPsbOdd = (u16)(psbOdd + d * ((c * acv - dispSizeY) - dispPosY)); + actualPrbEven = (u16)(prbEven + d * dispPosY); + actualPsbEven = (u16)(psbEven + d * ((c * acv - dispSizeY) - dispPosY)); + } + else { + actualPrbOdd = (u16)(prbEven + d * dispPosY); + actualPsbOdd = (u16)(psbEven + d * ((c * acv - dispSizeY) - dispPosY)); + actualPrbEven = (u16)(prbOdd + d * dispPosY); + actualPsbEven = (u16)(psbOdd + d * ((c * acv - dispSizeY) - dispPosY)); + } + + actualAcv = (u16)(dispSizeY / c); + + if (black) { + actualPrbOdd += 2 * actualAcv - 2; + actualPsbOdd += 2; + actualPrbEven += 2 * actualAcv - 2; + actualPsbEven += 2; + actualAcv = 0; + } + + regs[0] = (u16)(equ | actualAcv << 4); + changed |= (1ull << (63 - (0x00))); + + regs[7] = (u16)actualPrbOdd; + changed |= (1ull << (63 - (0x07))); + + regs[6] = (u16)actualPsbOdd; + changed |= (1ull << (63 - (0x06))); + + regs[9] = (u16)actualPrbEven; + changed |= (1ull << (63 - (0x09))); + + regs[8] = (u16)actualPsbEven; + changed |= (1ull << (63 - (0x08))); +} + +static u32 getCurrentHalfLine(void) { + u32 hcount; + u32 vcount; + + GetCurrentDisplayPosition(&hcount, &vcount); + + return ((vcount - 1) << 1) + ((hcount - 1) / CurrTiming->hlw); +} + +static u32 getCurrentFieldEvenOdd(void) { + return (getCurrentHalfLine() < CurrTiming->nhlines) ? 1u : 0u; +} + +VIRetraceCallback VISetPreRetraceCallback(VIRetraceCallback cb) { + BOOL enabled; + VIRetraceCallback oldcb = PreCB; + enabled = OSDisableInterrupts(); + PreCB = cb; + OSRestoreInterrupts(enabled); + return oldcb; +} + + +VIRetraceCallback VISetPostRetraceCallback(VIRetraceCallback cb) { + BOOL enabled; + VIRetraceCallback oldcb = PostCB; + enabled = OSDisableInterrupts(); + PostCB = cb; + OSRestoreInterrupts(enabled); + return oldcb; +} + +static timing_s* getTiming(VITVMode mode) { + switch (mode) { + case VI_TVMODE_NTSC_INT: + return &timing[0]; + break; + case VI_TVMODE_NTSC_DS: + return &timing[1]; + break; + case VI_TVMODE_PAL_INT: + return &timing[2]; + break; + case VI_TVMODE_PAL_DS: + return &timing[3]; + break; + case VI_TVMODE_EURGB60_INT: + return &timing[0]; + break; + case VI_TVMODE_EURGB60_DS: + return &timing[1]; + break; + case VI_TVMODE_MPAL_INT: + return &timing[4]; + break; + case VI_TVMODE_MPAL_DS: + return &timing[5]; + break; + case VI_TVMODE_NTSC_PROG: + case VI_TVMODE_MPAL_PROG: + case VI_TVMODE_EURGB60_PROG: + return &timing[6]; + break; + case VI_TVMODE_NTSC_3D: + return &timing[7]; + break; + case VI_TVMODE_DEBUG_PAL_INT: + return &timing[2]; + break; + case VI_TVMODE_DEBUG_PAL_DS: + return &timing[3]; + break; + case VI_TVMODE_GCA_INT: + return &timing[8]; + break; + case VI_TVMODE_GCA_PROG: + return &timing[9]; + break; + case VI_TVMODE_PAL_PROG: + return &timing[10]; + break; + case VI_TVMODE_EXTRA_INT: + case VI_TVMODE_EXTRA_DS: + case VI_TVMODE_EXTRA_PROG: + case VI_TVMODE_HD720_PROG: + return timingExtra; + break; + } + + return NULL; +} + +void __VIInit(VITVMode mode) { + timing_s* tm; + u32 nonInter; + u32 tv, tvForReg; + vu32 a; + u16 hct; + u16 vct; + + nonInter = (u32)mode & 3; + tv = (u32)mode >> 2; + + *(u32*)OSPhysicalToCached(0xCC) = tv; + + tm = getTiming(mode); + + __VIRegs[1] = 2; + for(a = 0; a < 1000; a++) + ; + + __VIRegs[0] = 0; + __VIRegs[3] = (u16)((((unsigned long)(tm->hlw)) << 0)); + __VIRegs[2] = (u16)((((unsigned long)(tm->hce)) << 0) | (((unsigned long)(tm->hcs)) << 8)); + __VIRegs[5] = (u16)((((unsigned long)(tm->hsy)) << 0) | (((unsigned long)(tm->hbe640 & ( (1 << (9)) - 1 ))) << 7)); + __VIRegs[4] = (u16)((((unsigned long)(tm->hbe640 >> 9)) << 0) | (((unsigned long)(tm->hbs640)) << 1)); + + if (encoderType == 0) { + __VIRegs[0x39] = (u16)((((unsigned long)(tm->hbeCCIR656)) << 0) | (((unsigned long)(1)) << 15)); + __VIRegs[0x3A] = (u16)((((unsigned long)(tm->hbsCCIR656)) << 0)); + } + + __VIRegs[0] = (u16)((((unsigned long)(tm->equ)) << 0) | (((unsigned long)(0)) << 4)); + __VIRegs[7] = (u16)((((unsigned long)(tm->prbOdd + tm->acv * 2 - 2)) << 0)); + __VIRegs[6] = (u16)((((unsigned long)(tm->psbOdd + 2)) << 0)); + __VIRegs[9] = (u16)((((unsigned long)(tm->prbEven + tm->acv * 2 - 2)) << 0)); + __VIRegs[8] = (u16)((((unsigned long)(tm->psbEven + 2)) << 0)); + __VIRegs[0xB] = (u16)((((unsigned long)(tm->bs1)) << 0) | (((unsigned long)(tm->be1)) << 5)); + __VIRegs[0xA] = (u16)((((unsigned long)(tm->bs3)) << 0) | (((unsigned long)(tm->be3)) << 5)); + __VIRegs[0xD] = (u16)((((unsigned long)(tm->bs2)) << 0) | (((unsigned long)(tm->be2)) << 5)); + __VIRegs[0xC] = (u16)((((unsigned long)(tm->bs4)) << 0) | (((unsigned long)(tm->be4)) << 5)); + __VIRegs[0x24] = (u16)((((unsigned long)(40)) << 0) | (((unsigned long)(40)) << 8)); + __VIRegs[0x1B] = 1; + __VIRegs[0x1A] = (u16)((((unsigned long)(1)) << 0) | (((unsigned long)(1)) << 12) | (((unsigned long)(0)) << 15)); + + hct = (u16)(tm->hlw + 1); + vct = (u16)(tm->nhlines / 2 + 1); + __VIRegs[0x19] = (u16)hct; + __VIRegs[0x18] = (u16)((((unsigned long)(vct)) << 0) | (((unsigned long)(1)) << 12) | (((unsigned long)(0)) << 15)); + + switch (tv) { + case VI_PAL: + case VI_MPAL: + case VI_DEBUG: + tvForReg = tv; + break; + + default: + tvForReg = VI_NTSC; + break; + } + + if ((nonInter == VI_INTERLACE) || (nonInter == VI_NON_INTERLACE)) { + __VIRegs[1] = (u16)((((unsigned long)(1)) << 0) | (((unsigned long)(0)) << 1) | (((unsigned long)(nonInter & 1)) << 2) | (((unsigned long)(0)) << 3) | (((unsigned long)(0)) << 4) | (((unsigned long)(0)) << 6) | (((unsigned long)(tvForReg)) << 8)); + __VIRegs[0x36] = 0; + } + else { + __VIRegs[1] = (u16)((((unsigned long)(1)) << 0) | (((unsigned long)(0)) << 1) | (((unsigned long)(1)) << 2) | (((unsigned long)(0)) << 3) | (((unsigned long)(0)) << 4) | (((unsigned long)(0)) << 6) | (((unsigned long)(tvForReg)) << 8)); + __VIRegs[0x36] = 1; + } +} + +#define CLAMP(x,l,h) (((x) > (h)) ? (h) : (((x) < (l)) ? (l) : (x))) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +static void AdjustPosition(u16 acv) { + s32 coeff, frac; + + HorVer.AdjustedDispPosX = (u16)CLAMP((s16)HorVer.DispPosX + displayOffsetH, + 0, 720 - HorVer.DispSizeX); + + coeff = (HorVer.FBMode == VI_XFBMODE_SF)? 2 : 1; + frac = HorVer.DispPosY & 1; + + HorVer.AdjustedDispPosY = (u16)MAX((s16)HorVer.DispPosY + displayOffsetV, frac); + + HorVer.AdjustedDispSizeY = (u16)(HorVer.DispSizeY + + MIN((s16)HorVer.DispPosY + displayOffsetV - frac, 0) + - MAX((s16)HorVer.DispPosY + (s16)HorVer.DispSizeY + + displayOffsetV - ((s16)acv*2 - frac), 0)); + + HorVer.AdjustedPanPosY = (u16)(HorVer.PanPosY + - MIN((s16)HorVer.DispPosY + displayOffsetV - frac, 0) / coeff); + + HorVer.AdjustedPanSizeY = (u16)(HorVer.PanSizeY + + MIN((s16)HorVer.DispPosY + displayOffsetV - frac, 0) / coeff + - MAX((s16)HorVer.DispPosY + (s16)HorVer.DispSizeY + + displayOffsetV - ((s16)acv*2 - frac), 0) / coeff); +} + +static void ImportAdjustingValues(void) { + displayOffsetH = SCGetDisplayOffsetH(); + displayOffsetV = 0; +} + +void VIInit(void) { + u16 dspCfg; + u32 value, tv, tvInBootrom; + + if (IsInitialized) { + return; + } + + OSRegisterVersion(__VIVersion); + IsInitialized = TRUE; + + if (!(__VIRegs[1] & 1)) { + __VIInit(VI_TVMODE_NTSC_INT); + } + + retraceCount = 0; + changed = 0; + shdwChanged = 0; + changeMode = 0; + shdwChangeMode = 0; + flushFlag = 0; + flushFlag3in1 = 0; + + __VIRegs[0x27] = (u16)((((unsigned long)(taps[0])) << 0) | (((unsigned long)(taps[1] & ( (1 << (6)) - 1 ))) << 10)); + __VIRegs[0x26] = (u16)((((unsigned long)(taps[1] >> 6)) << 0) | (((unsigned long)(taps[2])) << 4)); + __VIRegs[0x29] = (u16)((((unsigned long)(taps[3])) << 0) | (((unsigned long)(taps[4] & ( (1 << (6)) - 1 ))) << 10)); + __VIRegs[0x28] = (u16)((((unsigned long)(taps[4] >> 6)) << 0) | (((unsigned long)(taps[5])) << 4)); + __VIRegs[0x2B] = (u16)((((unsigned long)(taps[6])) << 0) | (((unsigned long)(taps[7] & ( (1 << (6)) - 1 ))) << 10)); + __VIRegs[0x2A] = (u16)((((unsigned long)(taps[7] >> 6)) << 0) | (((unsigned long)(taps[8])) << 4)); + __VIRegs[0x2D] = (u16)((((unsigned long)(taps[9])) << 0) | (((unsigned long)(taps[10])) << 8)); + __VIRegs[0x2C] = (u16)((((unsigned long)(taps[11])) << 0) | (((unsigned long)(taps[12])) << 8)); + __VIRegs[0x2F] = (u16)((((unsigned long)(taps[13])) << 0) | (((unsigned long)(taps[14])) << 8)); + __VIRegs[0x2E] = (u16)((((unsigned long)(taps[15])) << 0) | (((unsigned long)(taps[16])) << 8)); + __VIRegs[0x31] = (u16)((((unsigned long)(taps[17])) << 0) | (((unsigned long)(taps[18])) << 8)); + __VIRegs[0x30] = (u16)((((unsigned long)(taps[19])) << 0) | (((unsigned long)(taps[20])) << 8)); + __VIRegs[0x33] = (u16)((((unsigned long)(taps[21])) << 0) | (((unsigned long)(taps[22])) << 8)); + __VIRegs[0x32] = (u16)((((unsigned long)(taps[23])) << 0) | (((unsigned long)(taps[24])) << 8)); + + __VIRegs[0x38] = (u16)640; + ImportAdjustingValues(); + tvInBootrom = *(u32*)OSPhysicalToCached(0xCC); + dspCfg = __VIRegs[1]; + HorVer.nonInter = VIGetScanMode(); + + HorVer.tv = ((((unsigned long)(dspCfg)) & 0x00000300) >> 8); + if ((tvInBootrom == VI_EURGB60) ||( (tvInBootrom == VI_PAL) && (HorVer.tv == VI_NTSC))) { + HorVer.tv = VI_EURGB60; + } + + tv = (HorVer.tv == VI_DEBUG)? VI_NTSC : HorVer.tv; + HorVer.timing = getTiming((VITVMode)VI_TVMODE(tv, HorVer.nonInter)); + regs[1] = dspCfg; + CurrTiming = HorVer.timing; + CurrTvMode = HorVer.tv; + HorVer.DispSizeX = 640; + HorVer.DispSizeY = (u16)(CurrTiming->acv * 2); + HorVer.DispPosX = (u16)( (720 - HorVer.DispSizeX) / 2 ); + HorVer.DispPosY = 0; + AdjustPosition(CurrTiming->acv); + HorVer.FBSizeX = 640; + HorVer.FBSizeY = (u16)(CurrTiming->acv * 2); + HorVer.PanPosX = 0; + HorVer.PanPosY = 0; + HorVer.PanSizeX = 640; + HorVer.PanSizeY = (u16)(CurrTiming->acv * 2); + HorVer.FBMode = VI_XFBMODE_SF; + HorVer.wordPerLine = 40; + HorVer.std = 40; + HorVer.wpl = 40; + HorVer.xof = 0; + HorVer.black = TRUE; + HorVer.threeD = FALSE; + + OSInitThreadQueue(&retraceQueue); + + value = __VIRegs[0x18]; + value = (((unsigned long)(value)) & ~0x00008000) | (((unsigned long)(0)) << 15); + __VIRegs[0x18] = (u16)value; + + value = __VIRegs[0x1A]; + value = (((unsigned long)(value)) & ~0x00008000) | (((unsigned long)(0)) << 15); + __VIRegs[0x1A] = (u16)value; + + PreCB = (VIRetraceCallback)NULL; + PostCB = (VIRetraceCallback)NULL; + + __OSSetInterruptHandler(24, __VIRetraceHandler); + __OSUnmaskInterrupts((0x80000000u >> (24))); + OSRegisterShutdownFunction(&ShutdownFunctionInfo); + + switch(VIGetTvFormat()) { + case VI_PAL: + THD_TIME_TO_DIMMING = 15000; + NEW_TIME_TO_DIMMING = 15000; + THD_TIME_TO_DVD_STOP = 90000; + break; + default: + THD_TIME_TO_DIMMING = 18000; + NEW_TIME_TO_DIMMING = 18000; + THD_TIME_TO_DVD_STOP = 108000; + break; + } + _gIdleCount_dimming = 0; + _gIdleCount_dvd = 0; + g_current_time_to_dim = VI_DM_DEFAULT; + __VIDimming_All_Clear = TRUE; + __VIDimmingState = FALSE; + VIEnableDimming(TRUE); + + VIEnableDVDStopMotor(FALSE); + __VISetRevolutionModeSimple(); +} + +void VIWaitForRetrace(void) { + BOOL enabled; + u32 count; + + enabled = OSDisableInterrupts(); + count = retraceCount; + + do { + OSSleepThread(&retraceQueue); + } while (count == retraceCount); + + OSRestoreInterrupts(enabled); +} + +static void setInterruptRegs(timing_s* tm) { + u16 vct, hct, borrow; + + vct = (u16)(tm->nhlines / 2); + borrow = (u16)(tm->nhlines % 2); + hct = (u16)((borrow)? tm->hlw : (u16)0); + + vct++; + hct++; + + regs[0x19] = (u16)hct; + changed |= (1ull << (63 - (0x19))); + + regs[0x18] = (u16)((((unsigned long)(vct)) ) | (((unsigned long)(1)) << 12) | (((unsigned long)(0)) << 15)); + changed |= (1ull << (63 - (0x18))); +} + +static void setPicConfig(u16 fbSizeX, VIXFBMode xfbMode, u16 panPosX, + u16 panSizeX, u8* wordPerLine, u8* std, u8* wpl, + u8* xof) +{ + *wordPerLine = (u8)( (fbSizeX + 15)/16 ); + *std = (u8)((xfbMode == VI_XFBMODE_SF)? *wordPerLine : (u8)( 2 * *wordPerLine )); + *xof = (u8)( panPosX % 16 ); + *wpl = (u8)( (*xof + panSizeX + 15) / 16 ); + + regs[0x24] = (u16)((((unsigned long)(*std)) ) | (((unsigned long)(*wpl)) << 8)); + changed |= (1ull << (63 - (0x24))); +} + +static void setBBIntervalRegs(timing_s* tm) { + u16 val; + + val = (u16)((((unsigned long)(tm->bs1))) | (((unsigned long)(tm->be1)) << 5)); + regs[0xB] = val; + changed |= (1ull << (63 - (0x0b))); + + val = (u16)((((unsigned long)(tm->bs3))) | (((unsigned long)(tm->be3)) << 5)); + regs[0xA] = val; + changed |= (1ull << (63 - (0x0a))); + + val = (u16)((((unsigned long)(tm->bs2))) | (((unsigned long)(tm->be2)) << 5)); + regs[0xD] = val; + changed |= (1ull << (63 - (0x0d))); + + val = (u16)((((unsigned long)(tm->bs4))) | (((unsigned long)(tm->be4)) << 5)); + regs[0xC] = val; + changed |= (1ull << (63 - (0x0c))); +} + +void VISetBlack(BOOL black) { + BOOL enabled; + timing_s* tm; + + enabled = OSDisableInterrupts(); + HorVer.black = black; + tm = HorVer.timing; + setVerticalRegs(HorVer.AdjustedDispPosY, HorVer.DispSizeY, tm->equ, tm->acv, tm->prbOdd, tm->prbEven, tm->psbOdd, tm->psbEven, HorVer.black); + OSRestoreInterrupts(enabled); +} + +u32 VIGetRetraceCount(void) { + return retraceCount; +} + +u32 VIGetCurrentLine(void) { + u32 halfLine; + timing_s* tm; + BOOL enabled; + + tm = CurrTiming; + enabled = OSDisableInterrupts(); + halfLine = getCurrentHalfLine(); + OSRestoreInterrupts(enabled); + + if (halfLine >= tm->nhlines) { + halfLine -= tm->nhlines; + } + + return (halfLine >> 1); +} + +static s32 cntlzd(u64 bit) { + u32 hi, lo; + s32 value; + + hi = (u32)(bit >> 32); + lo = (u32)(bit & 0xFFFFFFFF); + value = __cntlzw(hi); + + if (value < 32) { + return value; + } + + return (32 + __cntlzw(lo)); +} + +static void PrintDebugPalCaution(void) { + static u32 message = 0; + + if (message == 0) { + message = 1; + OSReport("***************************************\n"); + OSReport(" ! ! ! C A U T I O N ! ! ! \n"); + OSReport("This TV format \"DEBUG_PAL\" is only for \n"); + OSReport("temporary solution until PAL DAC board \n"); + OSReport("is available. Please do NOT use this \n"); + OSReport("mode in real games!!! \n"); + OSReport("***************************************\n"); + } +} + +void VIConfigure(const GXRenderModeObj* rm) { + timing_s* tm; + u32 regDspCfg, regClksel; + BOOL enabled; + u32 newNonInter, tvInBootrom, tvInGame; + + enabled = OSDisableInterrupts(); + newNonInter = (u32)rm->viTVmode & 3; + + if (HorVer.nonInter != newNonInter) { + changeMode = 1; + HorVer.nonInter = newNonInter; + } + + tvInGame = (u32)rm->viTVmode >> 2; + tvInBootrom = *(u32*)OSPhysicalToCached(0xCC); + + if (tvInGame == VI_DEBUG_PAL) { + PrintDebugPalCaution(); + } + + if ( ((tvInBootrom != VI_PAL && tvInBootrom != VI_EURGB60) && + (tvInGame == VI_PAL || tvInGame == VI_EURGB60)) || + ((tvInBootrom == VI_PAL || tvInBootrom == VI_EURGB60) && + (tvInGame != VI_PAL && tvInGame != VI_EURGB60))) { + + OSPanic(__FILE__, 0xA57, "VIConfigure(): Tried to change mode from (%d) to (%d), which is forbidden\n", tvInBootrom, tvInGame); + } + + if ( (tvInGame == VI_NTSC) || (tvInGame == VI_MPAL) ) { + HorVer.tv = tvInBootrom; + } + else { + HorVer.tv = tvInGame; + } + + HorVer.DispPosX = rm->viXOrigin; + HorVer.DispPosY = (u16)((HorVer.nonInter == VI_NON_INTERLACE) ? (u16)(rm->viYOrigin * 2) : rm->viYOrigin); + HorVer.DispSizeX = rm->viWidth; + HorVer.FBSizeX = rm->fbWidth; + HorVer.FBSizeY = rm->xfbHeight; + HorVer.FBMode = rm->xFBmode; + HorVer.PanSizeX = HorVer.FBSizeX; + HorVer.PanSizeY = HorVer.FBSizeY; + HorVer.PanPosX = 0; + HorVer.PanPosY = 0; + + HorVer.DispSizeY = (u16)((HorVer.nonInter == VI_PROGRESSIVE)? HorVer.PanSizeY : + (HorVer.nonInter == VI_3D)? HorVer.PanSizeY : + (HorVer.FBMode == VI_XFBMODE_SF)? (u16)(2 * HorVer.PanSizeY) : HorVer.PanSizeY); + + HorVer.threeD = (HorVer.nonInter == VI_3D) ? TRUE : FALSE; + + tm = getTiming((VITVMode)VI_TVMODE(HorVer.tv, HorVer.nonInter)); + HorVer.timing = tm; + + AdjustPosition(tm->acv); + setInterruptRegs(tm); + + regDspCfg = regs[1]; + regClksel = regs[0x36]; + + if ((HorVer.nonInter == VI_PROGRESSIVE) || (HorVer.nonInter == VI_3D)) { + regDspCfg = (((unsigned long)(regDspCfg)) & ~0x00000004) | (((unsigned long)(1)) << 2); + + if (HorVer.tv == VI_HD720) { + regClksel = (((unsigned long)(regClksel)) & ~0x00000001) | (((unsigned long)(0))); + } + else { + regClksel = (((unsigned long)(regClksel)) & ~0x00000001) | (((unsigned long)(1))); + } + } + else + { + regDspCfg = (((unsigned long)(regDspCfg)) & ~0x00000004) | (((unsigned long)(HorVer.nonInter & 1)) << 2); + regClksel = (((unsigned long)(regClksel)) & ~0x00000001) | (((unsigned long)(0))); + } + + regDspCfg = (((unsigned long)(regDspCfg)) & ~0x00000008) | (((unsigned long)(HorVer.threeD)) << 3); + + if ((HorVer.tv == VI_PAL) || (HorVer.tv == VI_MPAL) || (HorVer.tv == VI_DEBUG)) { + regDspCfg = (((unsigned long)(regDspCfg)) & ~0x00000300) | (((unsigned long)(HorVer.tv)) << 8); + } + else { + regDspCfg = (((unsigned long)(regDspCfg)) & ~0x00000300) | (((unsigned long)(0)) << 8); + } + + regs[1] = (u16)regDspCfg; + regs[0x36] = (u16)regClksel; + changed |= (1ull << (63 - (0x01))); + changed |= (1ull << (63 - (0x36))); + + setScalingRegs(HorVer.PanSizeX, HorVer.DispSizeX, HorVer.threeD); + setHorizontalRegs(tm, HorVer.AdjustedDispPosX, HorVer.DispSizeX); + setBBIntervalRegs(tm); + setPicConfig(HorVer.FBSizeX, HorVer.FBMode, HorVer.PanPosX, HorVer.PanSizeX, &HorVer.wordPerLine, &HorVer.std, &HorVer.wpl, &HorVer.xof); + + if (FBSet) { + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, &HorVer.rbfbb); + } + + setVerticalRegs(HorVer.AdjustedDispPosY, HorVer.AdjustedDispSizeY, tm->equ, tm->acv, tm->prbOdd, tm->prbEven, tm->psbOdd, tm->psbEven, HorVer.black); + OSRestoreInterrupts(enabled); +} + +void VIConfigurePan(u16 xOrg, u16 yOrg, u16 width, u16 height) { + BOOL enabled; + timing_s* tm; + + enabled = OSDisableInterrupts(); + + HorVer.PanPosX = xOrg; + HorVer.PanPosY = yOrg; + HorVer.PanSizeX = width; + HorVer.PanSizeY = height; + HorVer.DispSizeY = (u16)((HorVer.nonInter == VI_PROGRESSIVE)? HorVer.PanSizeY : + (HorVer.nonInter == VI_3D)? HorVer.PanSizeY : + (HorVer.FBMode == VI_XFBMODE_SF)? (u16)(2 * HorVer.PanSizeY) : HorVer.PanSizeY); + + tm = HorVer.timing; + + AdjustPosition(tm->acv); + setScalingRegs(HorVer.PanSizeX, HorVer.DispSizeX, HorVer.threeD); + setPicConfig(HorVer.FBSizeX, HorVer.FBMode, HorVer.PanPosX, HorVer.PanSizeX, + &HorVer.wordPerLine, &HorVer.std, &HorVer.wpl, &HorVer.xof); + + if (FBSet) { + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, &HorVer.rbfbb); + } + + setVerticalRegs(HorVer.AdjustedDispPosY, HorVer.DispSizeY, tm->equ, tm->acv, + tm->prbOdd, tm->prbEven, tm->psbOdd, tm->psbEven, + HorVer.black); + + OSRestoreInterrupts(enabled); +} + +void VIFlush(void) { + BOOL enabled; + s32 regIndex; + + enabled = OSDisableInterrupts(); + shdwChangeMode |= changeMode; + changeMode = 0; + shdwChanged |= changed; + + while (changed) { + regIndex = cntlzd(changed); + shdwRegs[regIndex] = regs[regIndex]; + changed &= ~(1ull << (63 - (regIndex))); + } + + flushFlag = 1; + flushFlag3in1 = 1; + NextBufAddr = HorVer.bufAddr; + OSRestoreInterrupts(enabled); +} + +void VISetNextFrameBuffer(void* fb) { + BOOL enabled = OSDisableInterrupts(); + HorVer.bufAddr = (u32)fb; + FBSet = 1; + setFbbRegs(&HorVer, &HorVer.tfbb, &HorVer.bfbb, &HorVer.rtfbb, &HorVer.rbfbb); + OSRestoreInterrupts(enabled); +} + +u32 VIGetTvFormat(void) { + u32 format; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + switch(CurrTvMode) { + case 0: + case 3: + case 6: + case 7: + case 8: + format = 0; + break; + + case 1: + case 4: + format = 1; + break; + + case 5: + case 2: + format = CurrTvMode; + break; + + default: + break; + } + + OSRestoreInterrupts(enabled); + + return format; +} + +u32 VIGetScanMode(void) { + u32 scanMode; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + if (((((unsigned long)(__VIRegs[0x36])) & 0x00000001) >> 0) == 1) + { + scanMode = VI_PROGRESSIVE; + } + else + { + if (((((unsigned long)(__VIRegs[0x01])) & 0x00000004) >> 2) == 0) + { + scanMode = VI_INTERLACE; + } + else + { + scanMode = VI_NON_INTERLACE; + } + } + OSRestoreInterrupts(enabled); + + return scanMode; +} + +u32 VIGetDTVStatus(void) { + u32 dtvStatus; + BOOL enabled; + + enabled = OSDisableInterrupts(); + dtvStatus = ((((unsigned long)(__VIRegs[0x37])) & 0x00000003) >> 0); + OSRestoreInterrupts(enabled); + + return (dtvStatus & 0x01); +} + +void __VIDisplayPositionToXY(u32 hct, u32 vct, s16 *x, s16 *y) { + u32 halfLine = ((vct - 1) << 1) + ( (hct-1) / CurrTiming->hlw ); + + if (HorVer.nonInter == VI_INTERLACE) { + if (halfLine < CurrTiming->nhlines) { + if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbOdd) { + *y = -1; + } + else if (halfLine >= CurrTiming->nhlines - CurrTiming->psbOdd) { + *y = -1; + } + else { + *y = (s16)((halfLine - CurrTiming->equ * 3 - CurrTiming->prbOdd) & ~1); + } + } + else { + halfLine -= CurrTiming->nhlines; + + if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbEven) { + *y = -1; + } + else if (halfLine >= CurrTiming->nhlines - CurrTiming->psbEven) { + *y = -1; + } + else { + *y = (s16)(( (halfLine - CurrTiming->equ * 3 - CurrTiming->prbEven) & ~1)+1); + } + } + } + else if (HorVer.nonInter == VI_NON_INTERLACE) { + if (halfLine >= CurrTiming->nhlines) { + halfLine -= CurrTiming->nhlines; + } + + if (halfLine < CurrTiming->equ*3 + CurrTiming->prbOdd) { + *y = -1; + } + else if (halfLine >= CurrTiming->nhlines - CurrTiming->psbOdd) { + *y = -1; + } + else { + *y = (s16)((halfLine - CurrTiming->equ * 3 - CurrTiming->prbOdd) & ~1); + } + } + else if (HorVer.nonInter == VI_PROGRESSIVE) { + if (halfLine < CurrTiming->nhlines) { + if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbOdd) { + *y = -1; + } + else if (halfLine >= CurrTiming->nhlines - CurrTiming->psbOdd) { + *y = -1; + } + else { + *y = (s16)(halfLine - CurrTiming->equ * 3 - CurrTiming->prbOdd); + } + } + else { + halfLine -= CurrTiming->nhlines; + + if (halfLine < CurrTiming->equ * 3 + CurrTiming->prbEven) { + *y = -1; + } + else if (halfLine >= CurrTiming->nhlines - CurrTiming->psbEven) { + *y = -1; + } + else + *y = (s16)((halfLine - CurrTiming->equ*3 - CurrTiming->prbEven) & ~1); + } + } + + *x = (s16)(hct - 1); +} + +void __VIGetCurrentPosition(s16 *x, s16 *y) +{ + u32 hcount; + u32 vcount; + + GetCurrentDisplayPosition(&hcount, &vcount); + __VIDisplayPositionToXY(hcount, vcount, x, y); +} + +BOOL __VIResetDev0Idle(void) { + __VIDimmingFlag_DEV_IDLE[0] = 0; + return TRUE; +} + +BOOL VIResetDimmingCount(void) { + return __VIResetDev0Idle(); +} + +BOOL VIEnableDVDStopMotor(BOOL enable) { + BOOL old = __VIDVDStopFlag_Enable; + __VIDVDStopFlag_Enable = enable; + return old; +} + +u32 VIGetDVDStopMotorCount(void) { + u32 count; + + if (_gIdleCount_dvd >= THD_TIME_TO_DVD_STOP) { + count = 0; + } + else { + count = (u32)THD_TIME_TO_DVD_STOP - _gIdleCount_dvd; + } + + return count; +} + +BOOL VIEnableDimming(BOOL enable) { + u8 value; + BOOL old = __VIDimmingFlag_Enable; + + if (enable == TRUE) { + value = SCGetScreenSaverMode(); + + if (value == 0) { + enable = FALSE; + } + } + + __VIDimmingFlag_Enable = enable; + return old; +} diff --git a/src/RVL_SDK/vi/vi3in1.c b/src/RVL_SDK/vi/vi3in1.c new file mode 100644 index 000000000..cc76de306 --- /dev/null +++ b/src/RVL_SDK/vi/vi3in1.c @@ -0,0 +1,877 @@ +#include +#include + +static VIVideo Vdac_Flag_Region; +volatile u32 Vdac_Flag_Changed = 0; +static VIACPType __type; +static u32 __tvType = 0xFF; + +static VIGammaObj gammaSet[] = { + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0030,0x0397,0x3B49, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x1000,0x1000,0x1000,0x1080,0x1B80,0xEB00, + 0x0000,0x0028,0x005A,0x02DB,0x0D8D,0x3049, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x1000,0x1040,0x1100,0x1880,0x4200,0xEB00, + 0x0000,0x007A,0x023C,0x076D,0x129C,0x2724, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x1000,0x10C0,0x1580,0x2900,0x6200,0xEB00, + 0x004E,0x0199,0x052D,0x0B24,0x1429,0x20A4, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x1040,0x12C0,0x1DC0,0x3B00,0x78C0,0xEB00, + 0x00EC,0x03D7,0x0800,0x0D9E,0x143E,0x1BDB, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x10C0,0x16C0,0x27C0,0x4B80,0x8980,0xEB00, + 0x0276,0x0666,0x0A96,0x0EF3,0x13AC,0x1849, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x1200,0x1C00,0x3280,0x59C0,0x9600,0xEB00, + 0x04EC,0x08F5,0x0C96,0x0FCF,0x12C6,0x1580, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x1400,0x2200,0x3CC0,0x6640,0x9FC0,0xEB00, + 0x0800,0x0BAE,0x0E00,0x1030,0x11CB,0x1349, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x1680,0x28C0,0x4680,0x7100,0xA780,0xEB00, + 0x0BB1,0x0E14,0x0F2D,0x1018,0x10E5,0x1180, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x1980,0x2F80,0x4FC0,0x7A00,0xADC0,0xEB00, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x10,0x20,0x40,0x60,0x80,0xA0,0xEB, + 0x1000,0x2000,0x4000,0x6000,0x8000,0xA000,0xEB00, + 0x14EC,0x11C2,0x1078,0x0FB6,0x0F2F,0x0EB6, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x2100,0x3CC0,0x5FC0,0x8900,0xB780,0xEB00, + 0x19D8,0x1333,0x10D2,0x0F6D,0x0E5E,0x0DA4, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x2500,0x4300,0x66C0,0x8F40,0xBB40,0xEB00, + 0x1EC4,0x147A,0x110F,0x0F0C,0x0DA1,0x0CB6, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x2900,0x4900,0x6D40,0x94C0,0xBE80,0xEB00, + 0x2400,0x1570,0x110F,0x0EAA,0x0D0F,0x0BDB, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x2D40,0x4EC0,0x7300,0x9980,0xC180,0xEB00, + 0x293B,0x163D,0x110F,0x0E30,0x0C7D,0x0B24, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x3180,0x5440,0x7880,0x9DC0,0xC400,0xEB00, + 0x2E27,0x170A,0x10D2,0x0DE7,0x0BEB,0x0A80, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x3580,0x5980,0x7D40,0xA1C0,0xC640,0xEB00, + 0x3362,0x175C,0x10D2,0x0D6D,0x0B6D,0x09ED, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x39C0,0x5E40,0x8200,0xA540,0xC840,0xEB00, + 0x384E,0x17AE,0x10B4,0x0D0C,0x0AF0,0x096D, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x3DC0,0x62C0,0x8640,0xA880,0xCA00,0xEB00, + 0x3D3B,0x1800,0x105A,0x0CC3,0x0A72,0x0900, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x41C0,0x6740,0x8A00,0xAB80,0xCB80,0xEB00, + 0x41D8,0x1828,0x103C,0x0C49,0x0A1F,0x0892, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x4580,0x6B40,0x8DC0,0xAE00,0xCD00,0xEB00, + 0x4676,0x1851,0x0FE1,0x0C00,0x09B6,0x0836, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x4940,0x6F40,0x9100,0xB080,0xCE40,0xEB00, + 0x4AC4,0x187A,0x0FA5,0x0B9E,0x0963,0x07DB, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x4CC0,0x7300,0x9440,0xB2C0,0xCF80,0xEB00, + 0x4F13,0x1851,0x0F69,0x0B6D,0x090F,0x0780, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x5040,0x7640,0x9700,0xB500,0xD0C0,0xEB00, + 0x5313,0x187A,0x0F0F,0x0B24,0x08BC,0x0736, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x5380,0x79C0,0x99C0,0xB700,0xD1C0,0xEB00, + 0x5713,0x1851,0x0EF0,0x0AC3,0x087D,0x06ED, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x56C0,0x7CC0,0x9C80,0xB8C0,0xD2C0,0xEB00, + 0x5B13,0x1828,0x0E96,0x0A92,0x0829,0x06B6, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x5A00,0x7FC0,0x9EC0,0xBA80,0xD380,0xEB00, + 0x5EC4,0x1800,0x0E78,0x0A30,0x0800,0x066D, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x5D00,0x8280,0xA140,0xBC00,0xD480,0xEB00, + 0x6276,0x17D7,0x0E1E,0x0A00,0x07C1,0x0636, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x6000,0x8540,0xA340,0xBD80,0xD540,0xEB00, + 0x65D8,0x17AE,0x0DE1,0x09CF,0x0782,0x0600, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x62C0,0x87C0,0xA540,0xBF00,0xD600,0xEB00, + 0x693B,0x1785,0x0DA5,0x0986,0x0743,0x05DB, + 0x0010,0x001D,0x0036,0x0058,0x0082,0x00B3,0x00EB, + 0x1000,0x6580,0x8A40,0xA740,0xC040,0xD680,0xEB00 +}; + +VIMacroVisionObj VINtscACPType1 = { + 0x36, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x1B, + 0x1B, + 0x24, + 0x07, + 0xF8, + 0x00, + 0x00, + 0x0F, + 0x0F, + 0x60, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; + +VIMacroVisionObj VINtscACPType2 = { + 0x3E, + 0x1D, + 0x11, + 0x25, + 0x11, + 0x01, + 0x07, + 0x00, + 0x1B, + 0x1B, + 0x24, + 0x07, + 0xF8, + 0x00, + 0x00, + 0x0F, + 0x0F, + 0x60, + 0x01, + 0x0A, + 0x00, + 0x05, + 0x04, + 0x03, + 0xFF, + 0x00 +}; + +VIMacroVisionObj VINtscACPType3 = { + 0x3E, + 0x17, + 0x15, + 0x21, + 0x15, + 0x05, + 0x05, + 0x02, + 0x1B, + 0x1B, + 0x24, + 0x07, + 0xF8, + 0x00, + 0x00, + 0x0F, + 0x0F, + 0x60, + 0x01, + 0x0A, + 0x00, + 0x05, + 0x04, + 0x03, + 0xFF, + 0x00 +}; + +VIMacroVisionObj VIPalACPType1 = { + 0x36, + 0x1A, + 0x22, + 0x2A, + 0x22, + 0x05, + 0x02, + 0x00, + 0x1C, + 0x3D, + 0x14, + 0x03, + 0xFE, + 0x01, + 0x54, + 0xFE, + 0x7E, + 0x60, + 0x00, + 0x08, + 0x00, + 0x04, + 0x07, + 0x01, + 0x55, + 0x01 +}; + +VIMacroVisionObj VIPalACPType2 = { + 0x36, + 0x1A, + 0x22, + 0x2A, + 0x22, + 0x05, + 0x02, + 0x00, + 0x1C, + 0x3D, + 0x14, + 0x03, + 0xFE, + 0x01, + 0x54, + 0xFE, + 0x7E, + 0x60, + 0x00, + 0x08, + 0x00, + 0x04, + 0x07, + 0x01, + 0x55, + 0x01 +}; + +VIMacroVisionObj VIPalACPType3 = { + 0x36, + 0x1A, + 0x22, + 0x2A, + 0x22, + 0x05, + 0x02, + 0x00, + 0x1C, + 0x3D, + 0x14, + 0x03, + 0xFE, + 0x01, + 0x54, + 0xFE, + 0x7E, + 0x60, + 0x00, + 0x08, + 0x00, + 0x04, + 0x07, + 0x01, + 0x55, + 0x01 +}; + +VIMacroVisionObj VIEurgb60ACPType1 = { + 0x36, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x1B, + 0x1B, + 0x24, + 0x07, + 0xF8, + 0x00, + 0x00, + 0x1E, + 0x1E, + 0x60, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01 +}; + +VIMacroVisionObj VIEurgb60ACPType2 = { + 0x36, + 0x1D, + 0x11, + 0x25, + 0x11, + 0x01, + 0x07, + 0x00, + 0x1B, + 0x1B, + 0x24, + 0x07, + 0xF8, + 0x00, + 0x00, + 0x1E, + 0x1E, + 0x60, + 0x01, + 0x0A, + 0x00, + 0x05, + 0x04, + 0x03, + 0xFF, + 0x01 +}; + +VIMacroVisionObj VIEurgb60ACPType3 = { + 0x36, + 0x17, + 0x15, + 0x21, + 0x15, + 0x05, + 0x05, + 0x02, + 0x1B, + 0x1B, + 0x24, + 0x07, + 0xF8, + 0x00, + 0x00, + 0x1E, + 0x1E, + 0x60, + 0x01, + 0x0A, + 0x00, + 0x05, + 0x04, + 0x03, + 0xFF, + 0x01 +}; + +VIMacroVisionObj VIMpalACPType1 = { + 0x36, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x1B, + 0x1B, + 0x24, + 0x07, + 0xF8, + 0x00, + 0x00, + 0x0F, + 0x0F, + 0x60, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; + +VIMacroVisionObj VIMpalACPType2 = { + 0x36, + 0x1D, + 0x11, + 0x25, + 0x11, + 0x01, + 0x07, + 0x00, + 0x1B, + 0x1B, + 0x24, + 0x07, + 0xF8, + 0x00, + 0x00, + 0x0F, + 0x0F, + 0x60, + 0x01, + 0x0A, + 0x00, + 0x05, + 0x04, + 0x03, + 0xFF, + 0x00 +}; + +VIMacroVisionObj VIMpalACPType3 = { + 0x36, + 0x17, + 0x15, + 0x21, + 0x15, + 0x05, + 0x05, + 0x02, + 0x1B, + 0x1B, + 0x24, + 0x07, + 0xF8, + 0x00, + 0x00, + 0x0F, + 0x0F, + 0x60, + 0x01, + 0x0A, + 0x00, + 0x05, + 0x04, + 0x03, + 0xFF, + 0x00 +}; + +VIMacroVisionObj VIProgressiveACPType = { + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; + +VIMacroVisionObj VIZeroACPType = { + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; + +extern s32 __VISendI2CData(u8, u8 *, s32); +extern void WaitMicroTime(s32); + +void __VISetYUVSEL(VIBool outsel) NO_INLINE { + u8 buffer[2]; + u32 tv; + + tv = *(u32*)OSPhysicalToCached(0xCC); + + switch (tv) { + case VI_PAL: + case VI_EURGB60: + Vdac_Flag_Region = VI_VMODE_PAL; + break; + case VI_MPAL: + Vdac_Flag_Region = VI_VMODE_MPAL; + break; + case VI_NTSC: + Vdac_Flag_Region = VI_VMODE_NTSC; + break; + default: + Vdac_Flag_Region = VI_VMODE_NTSC; + break; + } + + buffer[0] = 0x1; + buffer[1] = (u8)((outsel << 5) | Vdac_Flag_Region); + __VISendI2CData((u8)0xE0, buffer, 2); + WaitMicroTime(2); +} + +void __VISetTiming(VITiming timing) { + u8 buffer[2]; + + buffer[0] = 0x0; + buffer[1] = timing; + __VISendI2CData((u8)0xE0, buffer, 2); + WaitMicroTime(2); +} + +void __VISetFilter4EURGB60(VIBool enable) { + u8 buffer[2]; + buffer[0] = 0x6E; + buffer[1] = enable; + __VISendI2CData((u8)0xE0, buffer, 2); + WaitMicroTime(2); +} + +void __VISetVBICtrl(VIBool cgms, VIBool wss, VIBool cc) { + u8 buffer[2]; + + buffer[0] = 0x2; + buffer[1] = (u8)(((~wss & 0x1) << 2) | ((~cgms & 0x1) << 1) | (~cc & 0x1)); + __VISendI2CData((u8)0xE0, buffer, 2); + WaitMicroTime(2); +} + +static u8 __wd0 = 0xFF; +static u8 __wd1 = 0xFF; +static u8 __wd2 = 0xFF; + +void __VISetCGMS(void) { + u8 buffer[3]; + buffer[0] = 5; + buffer[1] = (u8)(((__wd1 & 0xF) << 2) | (__wd0 & 3)); + buffer[2] = __wd2; + __VISendI2CData((u8)0xE0, buffer, 3); + WaitMicroTime(2); +} + +void __VISetCGMSClear(void) { + __wd0 = 0; + __wd1 = 0; + __wd2 = 0; + __VISetCGMS(); +} + +static u8 __gp1 = 0xFF; +static u8 __gp2 = 0xFF; +static u8 __gp3 = 0xFF; +static u8 __gp4 = 0xFF; + +void __VISetWSS(void) { + u8 buffer[3]; + buffer[0] = 0x8; + buffer[1] = (u8)(((__gp2 & 0xf) << 4) | (__gp1 & 0xf)); + buffer[2] = (u8)(((__gp4 & 0x7) << 3) | (__gp3 & 0x7)); + __VISendI2CData((u8)0xE0, buffer, 3); + WaitMicroTime(2); +} + +void VISetWSS(u8 gp1, u8 gp2, u8 gp3, u8 gp4) { + if ((__gp1 == gp1) && (__gp2 == gp2) && (__gp3 == gp3) && (__gp4 == gp4)) { + return; + } + + __gp1 = gp1; + __gp2 = gp2; + __gp3 = gp3; + __gp4 = gp4; + + Vdac_Flag_Changed |= 2; +} + +static u8 __cc1 = 0xFF; +static u8 __cc2 = 0xFF; +static u8 __cc3 = 0xFF; +static u8 __cc4 = 0xFF; + +void __VISetClosedCaption(void) { + u8 buffer[5]; + buffer[0] = 0x7A; + buffer[1] = (u8)(__cc1 & 0x7F); + buffer[2] = (u8)(__cc2 & 0x7F); + buffer[3] = (u8)(__cc3 & 0x7F); + buffer[4] = (u8)(__cc4 & 0x7F); + __VISendI2CData((u8)0xE0, buffer, 5); + WaitMicroTime(2); +} + +void VISetClosedCaption(u8 cc1, u8 cc2, u8 cc3, u8 cc4) { + if ((__cc1 == cc1) && (__cc2 == cc2) && (__cc3 == cc3) && (__cc4 == cc4)) { + return; + } + + __cc1 = cc1; + __cc2 = cc2; + __cc3 = cc3; + __cc4 = cc4; + + Vdac_Flag_Changed |= 4; +} + +void __VISetMacrovisionImm(VIMacroVisionObj *mparam) { + u8 i; + u8 buffer[27]; + + buffer[0] = 0x40; + + for(i = 1; i < 27; i++) { + buffer[i] = mparam->m[i - 1]; + } + + __VISendI2CData((u8)0xE0, buffer, 27); + WaitMicroTime(2); +} + +void __VISetMacrovision(void) { + switch (__type) { + case 2: + switch (__tvType) { + case VI_NTSC: + __VISetMacrovisionImm(&VINtscACPType1); + break; + case VI_PAL: + __VISetMacrovisionImm(&VIPalACPType1); + break; + case VI_MPAL: + __VISetMacrovisionImm(&VIMpalACPType1); + break; + case VI_EURGB60: + __VISetMacrovisionImm(&VIEurgb60ACPType1); + break; + } + break; + case 3: + switch (__tvType) { + case VI_NTSC: + __VISetMacrovisionImm(&VINtscACPType2); + break; + case VI_PAL: + __VISetMacrovisionImm(&VIPalACPType2); + break; + case VI_MPAL: + __VISetMacrovisionImm(&VIMpalACPType2); + break; + case VI_EURGB60: + __VISetMacrovisionImm(&VIEurgb60ACPType2); + break; + } + break; + case 4: + switch (__tvType) { + case VI_NTSC: + __VISetMacrovisionImm(&VINtscACPType3); + break; + case VI_PAL: + __VISetMacrovisionImm(&VIPalACPType3); + break; + case VI_MPAL: + __VISetMacrovisionImm(&VIMpalACPType3); + break; + case VI_EURGB60: + __VISetMacrovisionImm(&VIEurgb60ACPType3); + break; + } + break; + case 1: + __VISetMacrovisionImm(&VIZeroACPType); + break; + } +} + +void __VISetGammaImm(VIGammaObj *gamma) { + u8 i, j; + u8 buffer[34]; + + buffer[0] = 0x10; + i = 1; + for (j = 0; j < 6; j++) { + buffer[i] = (u8)((gamma->a[j] >> 8) & 0xFF); + buffer[i + 1] = (u8)(gamma->a[j] & 0xFF); + i += 2; + } + + for (j = 0; j < 7; j++) { + buffer[i] = gamma->yin[j]; + i++; + } + + for (j = 0; j < 7; j++) { + buffer[i] = (u8)((gamma->yout[j] >> 8) & 0xFF); + buffer[i + 1] = (u8)(gamma->yout[j] & 0xC0); + i += 2; + } + + __VISendI2CData((u8)0xE0, buffer, 34); + WaitMicroTime(2); +} + +static VIGamma __gamma; +void __VISetGamma(void) { + __VISetGammaImm(&gammaSet[__gamma]); +} + +static VIBool __filter = 0xFF; + +void __VISetTrapFilter(void) { + u8 buffer[2]; + + buffer[0] = 0x3; + + if (__filter == VI_TRUE) { + buffer[1] = VI_FALSE; + } + else { + buffer[1] = VI_TRUE; + } + + __VISendI2CData((u8)0xE0, buffer, 2); + WaitMicroTime(2); +} + +void __VISetTrapFilterImm(VIBool filter) { + u8 buffer[2]; + buffer[0] = 0x3; + + if (filter == VI_TRUE) { + buffer[1] = VI_FALSE; + } + else { + buffer[1] = VI_TRUE; + } + __VISendI2CData((u8)0xE0, buffer, 2); + WaitMicroTime(2); +} + +void VISetTrapFilter(VIBool filter) { + if (__filter == filter) { + return; + } + + __filter = filter; + Vdac_Flag_Changed |= 0x20; +} + +static VIOverDrive __level; + +void __VISetRGBOverDrive(void) { + u8 buffer[2]; + + if (Vdac_Flag_Region == VI_VMODE_RGB) { + buffer[0] = 0xA; + buffer[1] = (u8)((__level << 1) | VI_ENABLE); + __VISendI2CData((u8)0xE0, buffer, 2); + WaitMicroTime(2); + } + else { + buffer[0] = 0xA; + buffer[1] = VI_DISABLE; + __VISendI2CData((u8)0xE0, buffer, 2); + WaitMicroTime(2); + } +} + +void VISetRGBOverDrive(VIOverDrive level) { + if (__level == level) { + return; + } + __level = level; + Vdac_Flag_Changed |= 0x40; +} + +void VISetRGBModeImm( void ) { + Vdac_Flag_Changed |= 0x80; +} + +static void __VISetVideoMode(VIVideo vmode, VIBool outsel) { + u8 buffer[2]; + Vdac_Flag_Region = vmode; + buffer[0] = 1; + buffer[1] = (u8)((outsel << 5) | Vdac_Flag_Region); + __VISendI2CData(0xE0, buffer, 2); + WaitMicroTime(2); +} + +static void __VISetCCSEL(VIBool ccsel) { + u8 buffer[2]; + + buffer[0] = 0x6A; + buffer[1] = VI_ENABLE; + __VISendI2CData((u8)0xE0, buffer, 2); + WaitMicroTime(2); +} + +static void __VISetOverSampling(VIBool os) { + u8 buffer[2]; + buffer[0] = 0x65; + buffer[1] = VI_ENABLE; + __VISendI2CData((u8)0xE0, buffer, 2); + WaitMicroTime(2); +} + +void __VISetVolume(u8 volumeL, u8 volumeR) { + u8 buffer[3]; + buffer[0] = 0x71; + buffer[1] = volumeL; + buffer[2] = volumeR; + __VISendI2CData((u8)0xE0, buffer, 3); + WaitMicroTime(2); +} + +void __VISetRGBModeImm(void) { + __VISetVideoMode(VI_VMODE_RGB, VI_DISABLE); +} + +void __VISetRevolutionModeSimple(void) { + u32 dtv; + + __VISetCCSEL(VI_TRUE); + __VISetOverSampling(VI_TRUE); + dtv = VIGetDTVStatus(); + __VISetYUVSEL((VIBool)dtv); + __VISetTiming(VI_TMG_GAME); + __VISetVolume(0x8E, 0x8E); + __VISetVBICtrl(VI_DISABLE, VI_DISABLE, VI_DISABLE); + __VISetCGMSClear(); + VISetWSS(0, 0, 0, 0); + __VISetWSS(); + VISetClosedCaption(0, 0, 0, 0); + __VISetClosedCaption(); + __VISetMacrovisionImm(&VIZeroACPType); + VISetRGBOverDrive(VI_ODV_L1); + __VISetRGBOverDrive(); + __VISetTrapFilterImm(VI_DISABLE); + __VISetGammaImm(&gammaSet[VI_GM_1_0]); +} \ No newline at end of file