/* 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 #include #include "DSi.h" #include "DSi_NWifi.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 }; DSi_NWifi::DSi_NWifi(DSi_SDHost* host) : DSi_SDDevice(host) { TransferCmd = 0xFFFFFFFF; RemSize = 0; } DSi_NWifi::~DSi_NWifi() { // } 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 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) { printf("NWIFI: unknown func0 write %05X %02X\n", addr, val); } u8 DSi_NWifi::F1_Read(u32 addr) { switch (addr) { } printf("NWIFI: unknown func1 read %05X\n", addr); return 0; } void DSi_NWifi::F1_Write(u32 addr, u8 val) { 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); } 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); } 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; u8 data[0x200]; for (u32 i = 0; i < len; i++) { data[i] = SDIO_Read(func, TransferAddr); if (TransferCmd & (1<<26)) { TransferAddr++; TransferAddr &= 0x1FFFF; // checkme } } 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; u8 data[0x200]; 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? } } }