diff options
Diffstat (limited to 'src/Dolphin/exi/EXIUart.c')
-rw-r--r-- | src/Dolphin/exi/EXIUart.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/src/Dolphin/exi/EXIUart.c b/src/Dolphin/exi/EXIUart.c new file mode 100644 index 0000000..aafc628 --- /dev/null +++ b/src/Dolphin/exi/EXIUart.c @@ -0,0 +1,174 @@ +#include "dolphin/os.h" + +#define EXI_TX 0x800400u +#define EXI_MAGIC 0xa5ff005a + +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) { + err = !EXISelect(chan, dev, EXI_FREQ_1M); + if (!err) { + cmd = 0x20011300; + err = FALSE; + err |= !EXIImm(chan, &cmd, 4, EXI_WRITE, NULL); + err |= !EXISync(chan); + err |= !EXIImm(chan, revision, 4, EXI_READ, NULL); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + } + EXIUnlock(chan); + } + + if (chan != 2 && dev == 0) { + EXIDetach(chan); + } + + if (err) { + 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 EXI_MEMORY_CARD_59: + case EXI_MEMORY_CARD_123: + case EXI_MEMORY_CARD_251: + case EXI_MEMORY_CARD_507: + case EXI_USB_ADAPTER: + case EXI_NPDP_GDEV: + case EXI_MODEM: + case EXI_MARLIN: + case 0x04220000: + case 0x04020100: + case 0x04020200: + case 0x04020300: + case 0x04040404: + case 0x04060000: + case 0x04120000: + case 0x04130000: + case 0x80000000 | EXI_MEMORY_CARD_59: + case 0x80000000 | EXI_MEMORY_CARD_123: + case 0x80000000 | EXI_MEMORY_CARD_251: + case 0x80000000 | EXI_MEMORY_CARD_507: + break; + default: + if (ProbeBarnacle(chan, dev, &id)) { + Chan = chan; + Dev = dev; + Enabled = BarnacleEnabled = EXI_MAGIC; + } + break; + } + } +} + +u32 InitializeUART(u32 baudRate) { + if (BarnacleEnabled == EXI_MAGIC) { + return 0; + } + + if (!(OSGetConsoleType() & OS_CONSOLE_DEVELOPMENT)) { + Enabled = 0; + return 2; + } else { + Chan = 0; + Dev = 1; + Enabled = EXI_MAGIC; + return 0; + } +} + +u32 ReadUARTN(void* bytes, unsigned long length) { return 4; } + +static int QueueLength(void) { + u32 cmd; + + if (!EXISelect(Chan, Dev, EXI_FREQ_8M)) + return -1; + + cmd = EXI_TX << 6; + EXIImm(Chan, &cmd, 4, EXI_WRITE, NULL); + EXISync(Chan); + + EXIImm(Chan, &cmd, 1, EXI_READ, NULL); + EXISync(Chan); + EXIDeselect(Chan); + + return 16 - (int)((cmd >> 24) & 0xff); +} + +u32 WriteUARTN(const void* buf, unsigned long len) { + u32 cmd; + int qLen; + long xLen; + char* ptr; + BOOL locked; + u32 error; + + if (Enabled != EXI_MAGIC) + return 2; + + locked = EXILock(Chan, Dev, 0); + if (!locked) { + return 0; + } + + for (ptr = (char*)buf; ptr - buf < len; ptr++) { + if (*ptr == '\n') + *ptr = '\r'; + } + + error = 0; + cmd = (EXI_TX | 0x2000000) << 6; + while (len) { + qLen = QueueLength(); + if (qLen < 0) { + error = 3; + break; + } + + if (qLen < 12 && qLen < len) + continue; + + if (!EXISelect(Chan, Dev, EXI_FREQ_8M)) { + error = 3; + break; + } + + EXIImm(Chan, &cmd, 4, EXI_WRITE, NULL); + EXISync(Chan); + + while (qLen && len) { + if (qLen < 4 && qLen < len) + break; + xLen = (len < 4) ? (long)len : 4; + EXIImm(Chan, (void*)buf, xLen, EXI_WRITE, NULL); + (u8*)buf += xLen; + len -= xLen; + qLen -= xLen; + EXISync(Chan); + } + EXIDeselect(Chan); + } + + EXIUnlock(Chan); + return error; +} |