aboutsummaryrefslogtreecommitdiff
path: root/src/DSi_NWifi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/DSi_NWifi.cpp')
-rw-r--r--src/DSi_NWifi.cpp875
1 files changed, 875 insertions, 0 deletions
diff --git a/src/DSi_NWifi.cpp b/src/DSi_NWifi.cpp
new file mode 100644
index 0000000..013173f
--- /dev/null
+++ b/src/DSi_NWifi.cpp
@@ -0,0 +1,875 @@
+/*
+ Copyright 2016-2019 Arisotura
+
+ This file is part of melonDS.
+
+ melonDS is free software: you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#include <string.h>
+#include <stdio.h>
+#include "DSi.h"
+#include "DSi_NWifi.h"
+#include "SPI.h"
+
+
+const u8 CIS0[256] =
+{
+ 0x01, 0x03, 0xD9, 0x01, 0xFF,
+ 0x20, 0x04, 0x71, 0x02, 0x00, 0x02,
+ 0x21, 0x02, 0x0C, 0x00,
+ 0x22, 0x04, 0x00, 0x00, 0x08, 0x32,
+ 0x1A, 0x05, 0x01, 0x01, 0x00, 0x02, 0x07,
+ 0x1B, 0x08, 0xC1, 0x41, 0x30, 0x30, 0xFF, 0xFF, 0x32, 0x00,
+ 0x14, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 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, 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, 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, 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,
+ 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, 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, 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, 0x00, 0x00,
+ 0x00, 0x00, 0x00
+};
+
+const u8 CIS1[256] =
+{
+ 0x20, 0x04, 0x71, 0x02, 0x00, 0x02,
+ 0x21, 0x02, 0x0C, 0x00,
+ 0x22, 0x2A, 0x01,
+ 0x01, 0x11,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08,
+ 0x00, 0x00, 0xFF, 0x80,
+ 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x0A,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x01,
+ 0x80, 0x01, 0x06,
+ 0x81, 0x01, 0x07,
+ 0x82, 0x01, 0xDF,
+ 0xFF,
+ 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, 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, 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, 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, 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, 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, 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, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+// hax
+DSi_NWifi* hax_wifi;
+void triggerirq(u32 param)
+{
+ hax_wifi->SetIRQ_F1_Counter(0);
+}
+
+
+DSi_NWifi::DSi_NWifi(DSi_SDHost* host) : DSi_SDDevice(host)
+{
+ TransferCmd = 0xFFFFFFFF;
+ RemSize = 0;
+
+ F0_IRQEnable = 0;
+ F0_IRQStatus = 0;
+
+ F1_IRQEnable = 0; F1_IRQEnable_CPU = 0; F1_IRQEnable_Error = 0; F1_IRQEnable_Counter = 0;
+ F1_IRQStatus = 0; F1_IRQStatus_CPU = 0; F1_IRQStatus_Error = 0; F1_IRQStatus_Counter = 0;
+
+ WindowData = 0;
+ WindowReadAddr = 0;
+ WindowWriteAddr = 0;
+
+ // TODO: check the actual mailbox size (presumably 0x200)
+ for (int i = 0; i < 8; i++)
+ Mailbox[i] = new FIFO<u8>(0x200);
+
+ u8* mac = SPI_Firmware::GetWifiMAC();
+ printf("NWifi MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ memset(EEPROM, 0, 0x400);
+
+ *(u32*)&EEPROM[0x000] = 0x300;
+ *(u16*)&EEPROM[0x008] = 0x8348; // TODO: determine properly (country code)
+ memcpy(&EEPROM[0x00A], mac, 6);
+ *(u32*)&EEPROM[0x010] = 0x60000000;
+
+ memset(&EEPROM[0x03C], 0xFF, 0x70);
+ memset(&EEPROM[0x140], 0xFF, 0x8);
+
+ u16 chk = 0xFFFF;
+ for (int i = 0; i < 0x300; i+=2)
+ chk ^= *(u16*)&EEPROM[i];
+
+ *(u16*)&EEPROM[0x004] = chk;
+
+ EEPROMReady = 0;
+
+ BootPhase = 0;
+}
+
+DSi_NWifi::~DSi_NWifi()
+{
+ for (int i = 0; i < 8; i++)
+ delete Mailbox[i];
+}
+
+
+// CHECKME
+// can IRQ status bits be set when the corresponding IRQs are disabled in the enable register?
+// otherwise, does disabling them clear the status register?
+
+void DSi_NWifi::UpdateIRQ()
+{
+ F0_IRQStatus = 0;
+ IRQ = false;
+
+ if (F1_IRQStatus & F1_IRQEnable)
+ F0_IRQStatus |= (1<<1);
+
+ if (F0_IRQEnable & (1<<0))
+ {
+ if (F0_IRQStatus & F0_IRQEnable)
+ IRQ = true;
+ }
+
+ Host->SetCardIRQ();
+}
+
+void DSi_NWifi::UpdateIRQ_F1()
+{
+ F1_IRQStatus = 0;
+
+ if (!Mailbox[4]->IsEmpty()) F1_IRQStatus |= (1<<0);
+ if (!Mailbox[5]->IsEmpty()) F1_IRQStatus |= (1<<1);
+ if (!Mailbox[6]->IsEmpty()) F1_IRQStatus |= (1<<2);
+ if (!Mailbox[7]->IsEmpty()) F1_IRQStatus |= (1<<3);
+ if (F1_IRQStatus_Counter & F1_IRQEnable_Counter) F1_IRQStatus |= (1<<4);
+ if (F1_IRQStatus_CPU & F1_IRQEnable_CPU) F1_IRQStatus |= (1<<6);
+ if (F1_IRQStatus_Error & F1_IRQEnable_Error) F1_IRQStatus |= (1<<7);
+
+ UpdateIRQ();
+}
+
+void DSi_NWifi::SetIRQ_F1_Counter(u32 n)
+{
+ F1_IRQStatus_Counter |= (1<<n);
+ UpdateIRQ_F1();
+}
+
+void DSi_NWifi::ClearIRQ_F1_Counter(u32 n)
+{
+ F1_IRQStatus_Counter &= ~(1<<n);
+ UpdateIRQ_F1();
+}
+
+void DSi_NWifi::SetIRQ_F1_CPU(u32 n)
+{
+ F1_IRQStatus_CPU |= (1<<n);
+ UpdateIRQ_F1();
+}
+
+
+u8 DSi_NWifi::F0_Read(u32 addr)
+{
+ switch (addr)
+ {
+ case 0x00000: return 0x11;
+ case 0x00001: return 0x00;
+
+ case 0x00002: return 0x02; // writable??
+ case 0x00003: return 0x02;
+
+ case 0x00004: return F0_IRQEnable;
+ case 0x00005: return F0_IRQStatus;
+
+ case 0x00008: return 0x17;
+
+ case 0x00009: return 0x00;
+ case 0x0000A: return 0x10;
+ case 0x0000B: return 0x00;
+
+ case 0x00012: return 0x03;
+
+ case 0x00109: return 0x00;
+ case 0x0010A: return 0x11;
+ case 0x0010B: return 0x00;
+ }
+
+ if (addr >= 0x01000 && addr < 0x01100)
+ {
+ return CIS0[addr & 0xFF];
+ }
+ if (addr >= 0x01100 && addr < 0x01200)
+ {
+ return CIS1[addr & 0xFF];
+ }
+
+ printf("NWIFI: unknown func0 read %05X\n", addr);
+ return 0;
+}
+
+void DSi_NWifi::F0_Write(u32 addr, u8 val)
+{
+ switch (addr)
+ {
+ case 0x00004:
+ F0_IRQEnable = val;
+ UpdateIRQ();
+ return;
+ }
+
+ printf("NWIFI: unknown func0 write %05X %02X\n", addr, val);
+}
+
+
+u8 DSi_NWifi::F1_Read(u32 addr)
+{
+ if (addr < 0x100)
+ {
+ u8 ret = Mailbox[4]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x200)
+ {
+ u8 ret = Mailbox[5]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x300)
+ {
+ u8 ret = Mailbox[6]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x400)
+ {
+ u8 ret = Mailbox[7]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x800)
+ {
+ switch (addr)
+ {
+ case 0x00400: return F1_IRQStatus;
+ case 0x00401: return F1_IRQStatus_CPU;
+ case 0x00402: return F1_IRQStatus_Error;
+ case 0x00403: return F1_IRQStatus_Counter;
+
+ case 0x00405:
+ {
+ u8 ret = 0;
+
+ if (Mailbox[4]->Level() >= 4) ret |= (1<<0);
+ if (Mailbox[5]->Level() >= 4) ret |= (1<<1);
+ if (Mailbox[6]->Level() >= 4) ret |= (1<<2);
+ if (Mailbox[7]->Level() >= 4) ret |= (1<<3);
+
+ return ret;
+ }
+
+ case 0x00408: return Mailbox[4]->Peek(0);
+ case 0x00409: return Mailbox[4]->Peek(1);
+ case 0x0040A: return Mailbox[4]->Peek(2);
+ case 0x0040B: return Mailbox[4]->Peek(3);
+
+ case 0x00418: return F1_IRQEnable;
+ case 0x00419: return F1_IRQEnable_CPU;
+ case 0x0041A: return F1_IRQEnable_Error;
+ case 0x0041B: return F1_IRQEnable_Counter;
+
+ // GROSS FUCKING HACK
+ case 0x00440: ClearIRQ_F1_Counter(0); return 0;
+ case 0x00450: return 1; // HAX!!
+
+ case 0x00474: return WindowData & 0xFF;
+ case 0x00475: return (WindowData >> 8) & 0xFF;
+ case 0x00476: return (WindowData >> 16) & 0xFF;
+ case 0x00477: return WindowData >> 24;
+ }
+ }
+ else if (addr < 0x1000)
+ {
+ u8 ret = Mailbox[4]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x1800)
+ {
+ u8 ret = Mailbox[5]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x2000)
+ {
+ u8 ret = Mailbox[6]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else if (addr < 0x2800)
+ {
+ u8 ret = Mailbox[7]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+ else
+ {
+ u8 ret = Mailbox[4]->Read();
+ UpdateIRQ_F1();
+ return ret;
+ }
+
+ printf("NWIFI: unknown func1 read %05X\n", addr);
+ return 0;
+}
+
+void DSi_NWifi::F1_Write(u32 addr, u8 val)
+{
+ if (addr < 0x100)
+ {
+ if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n");
+ Mailbox[0]->Write(val);
+ if (addr == 0xFF) HandleCommand();
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x200)
+ {
+ if (Mailbox[1]->IsFull()) printf("!!! NWIFI: MBOX1 FULL\n");
+ Mailbox[1]->Write(val);
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x300)
+ {
+ if (Mailbox[2]->IsFull()) printf("!!! NWIFI: MBOX2 FULL\n");
+ Mailbox[2]->Write(val);
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x400)
+ {
+ if (Mailbox[3]->IsFull()) printf("!!! NWIFI: MBOX3 FULL\n");
+ Mailbox[3]->Write(val);
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x800)
+ {
+ switch (addr)
+ {
+ case 0x00418: F1_IRQEnable = val; UpdateIRQ_F1(); return;
+ case 0x00419: F1_IRQEnable_CPU = val; UpdateIRQ_F1(); return;
+ case 0x0041A: F1_IRQEnable_Error = val; UpdateIRQ_F1(); return;
+ case 0x0041B: F1_IRQEnable_Counter = val; UpdateIRQ_F1(); return;
+
+ // GROSS FUCKING HACK
+ case 0x00440: ClearIRQ_F1_Counter(0); return;
+
+ case 0x00474: WindowData = (WindowData & 0xFFFFFF00) | val; return;
+ case 0x00475: WindowData = (WindowData & 0xFFFF00FF) | (val << 8); return;
+ case 0x00476: WindowData = (WindowData & 0xFF00FFFF) | (val << 16); return;
+ case 0x00477: WindowData = (WindowData & 0x00FFFFFF) | (val << 24); return;
+
+ case 0x00478:
+ WindowWriteAddr = (WindowWriteAddr & 0xFFFFFF00) | val;
+ WindowWrite(WindowWriteAddr, WindowData);
+ return;
+ case 0x00479: WindowWriteAddr = (WindowWriteAddr & 0xFFFF00FF) | (val << 8); return;
+ case 0x0047A: WindowWriteAddr = (WindowWriteAddr & 0xFF00FFFF) | (val << 16); return;
+ case 0x0047B: WindowWriteAddr = (WindowWriteAddr & 0x00FFFFFF) | (val << 24); return;
+
+ case 0x0047C:
+ WindowReadAddr = (WindowReadAddr & 0xFFFFFF00) | val;
+ WindowData = WindowRead(WindowReadAddr);
+ return;
+ case 0x0047D: WindowReadAddr = (WindowReadAddr & 0xFFFF00FF) | (val << 8); return;
+ case 0x0047E: WindowReadAddr = (WindowReadAddr & 0xFF00FFFF) | (val << 16); return;
+ case 0x0047F: WindowReadAddr = (WindowReadAddr & 0x00FFFFFF) | (val << 24); return;
+ }
+ }
+ else if (addr < 0x1000)
+ {
+ if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n");
+ Mailbox[0]->Write(val);
+ if (addr == 0xFFF) HandleCommand();
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x1800)
+ {
+ if (Mailbox[1]->IsFull()) printf("!!! NWIFI: MBOX1 FULL\n");
+ Mailbox[1]->Write(val);
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x2000)
+ {
+ if (Mailbox[2]->IsFull()) printf("!!! NWIFI: MBOX2 FULL\n");
+ Mailbox[2]->Write(val);
+ UpdateIRQ_F1();
+ return;
+ }
+ else if (addr < 0x2800)
+ {
+ if (Mailbox[3]->IsFull()) printf("!!! NWIFI: MBOX3 FULL\n");
+ Mailbox[3]->Write(val);
+ UpdateIRQ_F1();
+ return;
+ }
+ else
+ {
+ if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n");
+ Mailbox[0]->Write(val);
+ if (addr == 0x3FFF) HandleCommand(); // CHECKME
+ UpdateIRQ_F1();
+ return;
+ }
+
+ printf("NWIFI: unknown func1 write %05X %02X\n", addr, val);
+}
+
+
+u8 DSi_NWifi::SDIO_Read(u32 func, u32 addr)
+{
+ switch (func)
+ {
+ case 0: return F0_Read(addr);
+ case 1: return F1_Read(addr);
+ }
+
+ printf("NWIFI: unknown SDIO read %d %05X\n", func, addr);
+ return 0;
+}
+
+void DSi_NWifi::SDIO_Write(u32 func, u32 addr, u8 val)
+{
+ switch (func)
+ {
+ case 0: return F0_Write(addr, val);
+ case 1: return F1_Write(addr, val);
+ }
+
+ printf("NWIFI: unknown SDIO write %d %05X %02X\n", func, addr, val);
+}
+
+
+void DSi_NWifi::SendCMD(u8 cmd, u32 param)
+{
+ switch (cmd)
+ {
+ case 52: // IO_RW_DIRECT
+ {
+ u32 func = (param >> 28) & 0x7;
+ u32 addr = (param >> 9) & 0x1FFFF;
+
+ if (param & (1<<31))
+ {
+ // write
+
+ u8 val = param & 0xFF;
+ SDIO_Write(func, addr, val);
+ if (param & (1<<27))
+ val = SDIO_Read(func, addr); // checkme
+ Host->SendResponse(val | 0x1000, true);
+ }
+ else
+ {
+ // read
+
+ u8 val = SDIO_Read(func, addr);
+ Host->SendResponse(val | 0x1000, true);
+ }
+ }
+ return;
+
+ case 53: // IO_RW_EXTENDED
+ {
+ u32 addr = (param >> 9) & 0x1FFFF;
+
+ TransferCmd = param;
+ TransferAddr = addr;
+ if (param & (1<<27))
+ {
+ RemSize = (param & 0x1FF) << 9; // checkme
+ }
+ else
+ {
+ RemSize = (param & 0x1FF);
+ if (!RemSize) RemSize = 0x200;
+ }
+
+ if (param & (1<<31))
+ {
+ // write
+
+ WriteBlock();
+ Host->SendResponse(0x1000, true);
+ }
+ else
+ {
+ // read
+
+ ReadBlock();
+ Host->SendResponse(0x1000, true);
+ }
+ }
+ return;
+ }
+
+ printf("NWIFI: unknown CMD %d %08X\n", cmd, param);
+}
+
+void DSi_NWifi::SendACMD(u8 cmd, u32 param)
+{
+ printf("NWIFI: unknown ACMD %d %08X\n", cmd, param);
+}
+
+void DSi_NWifi::ContinueTransfer()
+{
+ if (TransferCmd & (1<<31))
+ WriteBlock();
+ else
+ ReadBlock();
+}
+
+void DSi_NWifi::ReadBlock()
+{
+ u32 func = (TransferCmd >> 28) & 0x7;
+ u32 len = (TransferCmd & (1<<27)) ? 0x200 : RemSize;
+
+ len = Host->GetTransferrableLen(len);
+
+ u8 data[0x200];
+
+ for (u32 i = 0; i < len; i++)
+ {
+ data[i] = SDIO_Read(func, TransferAddr);
+ if (TransferCmd & (1<<26))
+ {
+ TransferAddr++;
+ TransferAddr &= 0x1FFFF; // checkme
+ }
+ }
+ len = Host->SendData(data, len);
+
+ if (RemSize > 0)
+ {
+ RemSize -= len;
+ if (RemSize == 0)
+ {
+ // TODO?
+ }
+ }
+}
+
+void DSi_NWifi::WriteBlock()
+{
+ u32 func = (TransferCmd >> 28) & 0x7;
+ u32 len = (TransferCmd & (1<<27)) ? 0x200 : RemSize;
+
+ len = Host->GetTransferrableLen(len);
+
+ u8 data[0x200];
+ if (len = Host->ReceiveData(data, len))
+ {
+ for (u32 i = 0; i < len; i++)
+ {
+ SDIO_Write(func, TransferAddr, data[i]);
+ if (TransferCmd & (1<<26))
+ {
+ TransferAddr++;
+ TransferAddr &= 0x1FFFF; // checkme
+ }
+ }
+
+ if (RemSize > 0)
+ {
+ RemSize -= len;
+ if (RemSize == 0)
+ {
+ // TODO?
+ }
+ }
+ }
+}
+
+
+void DSi_NWifi::HandleCommand()
+{
+ switch (BootPhase)
+ {
+ case 0: return BMI_Command();
+ case 1: return WMI_Command();
+ }
+}
+
+void DSi_NWifi::BMI_Command()
+{
+ // HLE command handling stub
+ u32 cmd = MB_Read32(0);
+
+ switch (cmd)
+ {
+ case 0x01: // BMI_DONE
+ {
+ printf("BMI_DONE\n");
+ EEPROMReady = 1; // GROSS FUCKING HACK
+ u8 ready_msg[8] = {0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00};
+ SendWMIFrame(ready_msg, 8, 0, 0x00, 0x0000);
+ BootPhase = 1;
+ }
+ return;
+
+ case 0x03: // BMI_WRITE_MEMORY
+ {
+ u32 addr = MB_Read32(0);
+ u32 len = MB_Read32(0);
+ printf("BMI mem write %08X %08X\n", addr, len);
+
+ for (int i = 0; i < len; i++)
+ {
+ u8 val = Mailbox[0]->Read();
+
+ // TODO: do something with it!!
+ }
+ }
+ return;
+
+ case 0x04: // BMI_EXECUTE
+ {
+ u32 entry = MB_Read32(0);
+ u32 arg = MB_Read32(0);
+
+ printf("BMI_EXECUTE %08X %08X\n", entry, arg);
+ }
+ return;
+
+ case 0x06: // BMI_READ_SOC_REGISTER
+ {
+ u32 addr = MB_Read32(0);
+ u32 val = WindowRead(addr);
+ MB_Write32(4, val);
+ }
+ return;
+
+ case 0x07: // BMI_WRITE_SOC_REGISTER
+ {
+ u32 addr = MB_Read32(0);
+ u32 val = MB_Read32(0);
+ WindowWrite(addr, val);
+ }
+ return;
+
+ case 0x08: // BMI_GET_TARGET_ID
+ MB_Write32(4, 0xFFFFFFFF);
+ MB_Write32(4, 0x0000000C);
+ //MB_Write32(4, 0x20000118);
+ MB_Write32(4, 0x23000024); // ROM version (TODO: how to determine correct one?)
+ MB_Write32(4, 0x00000002);
+ return;
+
+ case 0x0D: // BMI_LZ_STREAM_START
+ {
+ u32 addr = MB_Read32(0);
+ printf("BMI_LZ_STREAM_START %08X\n", addr);
+ }
+ return;
+
+ case 0x0E: // BMI_LZ_DATA
+ {
+ u32 len = MB_Read32(0);
+ printf("BMI LZ write %08X\n", len);
+ //FILE* f = fopen("wififirm.bin", "ab");
+
+ for (int i = 0; i < len; i++)
+ {
+ u8 val = Mailbox[0]->Read();
+
+ // TODO: do something with it!!
+ //fwrite(&val, 1, 1, f);
+ }
+ //fclose(f);
+ }
+ return;
+
+ default:
+ printf("unknown BMI command %08X\n", cmd);
+ return;
+ }
+}
+
+void DSi_NWifi::WMI_Command()
+{
+ // HLE command handling stub
+ u16 h0 = MB_Read16(0);
+ u16 len = MB_Read16(0);
+ u16 h2 = MB_Read16(0);
+
+ u16 cmd = MB_Read16(0);
+ printf("WMI: cmd %04X\n", cmd);
+
+ switch (cmd)
+ {
+ case 0x0002: // service connect
+ {
+ u16 svc_id = MB_Read16(0);
+ u16 conn_flags = MB_Read16(0);
+
+ u8 svc_resp[10];
+ *(u16*)&svc_resp[0] = 0x0003;
+ *(u16*)&svc_resp[2] = svc_id;
+ svc_resp[4] = 0;
+ svc_resp[5] = (svc_id & 0xFF) + 1;
+ *(u16*)&svc_resp[6] = 0x0001;
+ *(u16*)&svc_resp[8] = 0x0001;
+ SendWMIFrame(svc_resp, 10, 0, 0x00, 0x0000);
+ }
+ break;
+
+ case 0x0004: // setup complete
+ {
+ u8 ready_evt[14];
+ memset(ready_evt, 0, 14);
+ *(u16*)&ready_evt[0] = 0x1001;
+ memcpy(&ready_evt[2], SPI_Firmware::GetWifiMAC(), 6);
+ ready_evt[8] = 0x02;
+ *(u32*)&ready_evt[10] = 0x23000024;
+ // ctrl[0] = trailer size
+ // trailer[1] = trailer extra size
+ // trailer[0] = trailer type???
+ SendWMIFrame(ready_evt, 14, 1, 0x00, 0x0000);
+ }
+ break;
+
+ default:
+ printf("unknown WMI command %04X\n", cmd);
+ break;
+ }
+
+ MB_Drain(0);
+}
+
+void DSi_NWifi::SendWMIFrame(u8* data, u32 len, u8 ep, u8 flags, u16 ctrl)
+{
+ u32 wlen = 0;
+
+ Mailbox[4]->Write(ep); // eid
+ Mailbox[4]->Write(flags); // flags
+ MB_Write16(4, len); // payload length
+ MB_Write16(4, ctrl); // ctrl
+ wlen += 6;
+
+ for (int i = 0; i < len; i++)
+ {
+ Mailbox[4]->Write(data[i]);
+ wlen++;
+ }
+
+ for (; wlen & 0x7F; wlen++)
+ Mailbox[4]->Write(0);
+}
+
+
+u32 DSi_NWifi::WindowRead(u32 addr)
+{
+ printf("NWifi: window read %08X\n", addr);
+
+ if ((addr & 0xFFFF00) == 0x520000)
+ {
+ // RAM host interest area
+ // TODO: different base based on hardware version
+
+ switch (addr & 0xFF)
+ {
+ case 0x54:
+ // base address of EEPROM data
+ // TODO find what the actual address is!
+ return 0x1FFC00;
+ case 0x58: return EEPROMReady; // hax
+ }
+
+ return 0;
+ }
+
+ // hax
+ if ((addr & 0x1FFC00) == 0x1FFC00)
+ {
+ return *(u32*)&EEPROM[addr & 0x3FF];
+ }
+
+ switch (addr)
+ {
+ case 0x40EC: // chip ID
+ // 0D000000 / 0D000001 == AR6013
+ // TODO: check firmware.bin to determine the correct value
+ return 0x0D000001;
+
+ // SOC_RESET_CAUSE
+ case 0x40C0: return 2;
+ }
+
+ return 0;
+}
+
+void DSi_NWifi::WindowWrite(u32 addr, u32 val)
+{
+ printf("NWifi: window write %08X %08X\n", addr, val);
+}