diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp index e3b246f4e7..ab8348c3f5 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp @@ -133,20 +133,30 @@ void Shutdown() void SetDefaultContentFile(const std::string& _rFilename) { - CWII_IPC_HLE_Device_es* pDevice = (CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es"))); + CWII_IPC_HLE_Device_es* pDevice = + (CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es"))); if (pDevice) pDevice->LoadWAD(_rFilename); } void ES_DIVerify(u8 *_pTMD, u32 _sz) { - CWII_IPC_HLE_Device_es* pDevice = (CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es"))); + CWII_IPC_HLE_Device_es* pDevice = + (CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es"))); if (pDevice) pDevice->ES_DIVerify(_pTMD, _sz); else ERROR_LOG(WII_IPC_ES, "DIVerify called but /dev/es is not available"); } +void SDIO_EventNotify() +{ + CWII_IPC_HLE_Device_sdio_slot0 *pDevice = + (CWII_IPC_HLE_Device_sdio_slot0*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/sdio/slot0"))); + if (pDevice) + pDevice->EventNotify(); +} + int GetDeviceIDByName(const std::string& _rDeviceName) { TDeviceMap::const_iterator itr = g_DeviceMap.begin(); diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h index 5770d39bfd..cbef421f45 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h @@ -44,6 +44,8 @@ void DoState(PointerWrap &p); void SetDefaultContentFile(const std::string& _rFilename); void ES_DIVerify(u8 *_pTMD, u32 _sz); +void SDIO_EventNotify(); + int GetDeviceIDByName(const std::string& _rDeviceName); IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID); diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp index cd515092e1..75040d8b90 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp @@ -20,6 +20,7 @@ #include "SDCardUtil.h" +#include "WII_IPC_HLE.h" #include "WII_IPC_HLE_Device_sdio_slot0.h" #include "../HW/CPU.h" @@ -43,6 +44,18 @@ CWII_IPC_HLE_Device_sdio_slot0::~CWII_IPC_HLE_Device_sdio_slot0() } } +void CWII_IPC_HLE_Device_sdio_slot0::EventNotify() +{ + if ((SConfig::GetInstance().m_WiiSDCard && m_event.type == EVENT_INSERT) || + (!SConfig::GetInstance().m_WiiSDCard && m_event.type == EVENT_REMOVE)) + { + Memory::Write_U32(m_event.type, m_event.addr + 4); + WII_IPC_HLE_Interface::EnqReply(m_event.addr); + m_event.addr = 0; + m_event.type = EVENT_NONE; + } +} + bool CWII_IPC_HLE_Device_sdio_slot0::Open(u32 _CommandAddress, u32 _Mode) { INFO_LOG(WII_IPC_SD, "Open"); @@ -159,10 +172,8 @@ bool CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress) break; case IOCTL_SENDCMD: - if (Memory::Read_U32(BufferIn) != SDHC_CAPABILITIES) - { - INFO_LOG(WII_IPC_SD, "IOCTL_SENDCMD 0x%08x", Memory::Read_U32(BufferIn)); - } + INFO_LOG(WII_IPC_SD, "IOCTL_SENDCMD %x ipc:%08x", + Memory::Read_U32(BufferIn), _CommandAddress); ReturnValue = ExecuteCommand(BufferIn, BufferInSize, 0, 0, BufferOut, BufferOutSize); break; @@ -172,7 +183,7 @@ bool CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress) else m_Status = CARD_NOT_EXIST; INFO_LOG(WII_IPC_SD, "IOCTL_GETSTATUS. Replying that SD card is %s%s", - (m_Status & CARD_INSERTED) ? "inserted" : "not exitsting", + (m_Status & CARD_INSERTED) ? "inserted" : "not present", (m_Status & CARD_INITIALIZED) ? " and initialized" : ""); Memory::Write_U32(m_Status, BufferOut); break; @@ -192,9 +203,32 @@ bool CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress) // INFO_LOG(WII_IPC_SD, "OutBuffer"); // DumpCommands(BufferOut, BufferOutSize/4, LogTypes::WII_IPC_SD); - Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); - - return true; + if (ReturnValue == RET_EVENT_REGISTER) + { + // async + m_event.addr = _CommandAddress; + Memory::Write_U32(0, _CommandAddress + 0x4); + // Check if the condition is already true + EventNotify(); + return false; + } + else if (ReturnValue == RET_EVENT_UNREGISTER) + { + // release returns 0 + // unknown sd int + // technically we do it out of order, oh well + Memory::Write_U32(EVENT_INVALID, m_event.addr + 4); + WII_IPC_HLE_Interface::EnqReply(m_event.addr); + m_event.addr = 0; + m_event.type = EVENT_NONE; + Memory::Write_U32(0, _CommandAddress + 0x4); + return true; + } + else + { + Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); + return true; + } } bool CWII_IPC_HLE_Device_sdio_slot0::IOCtlV(u32 _CommandAddress) @@ -264,7 +298,7 @@ u32 CWII_IPC_HLE_Device_sdio_slot0::ExecuteCommand(u32 _BufferIn, u32 _BufferInS // Note: req.addr is the virtual address of _rwBuffer - u32 rwFail = 0; + u32 ret = RET_OK; switch (req.command) { @@ -365,7 +399,7 @@ u32 CWII_IPC_HLE_Device_sdio_slot0::ExecuteCommand(u32 _BufferIn, u32 _BufferInS "read %lx, error %i, eof? %i", (unsigned long)nRead, ferror(m_Card), feof(m_Card)); - rwFail = 1; + ret = RET_FAIL; } delete[] buffer; @@ -402,7 +436,7 @@ u32 CWII_IPC_HLE_Device_sdio_slot0::ExecuteCommand(u32 _BufferIn, u32 _BufferInS "wrote %lx, error %i, eof? %i", (unsigned long)nWritten, ferror(m_Card), feof(m_Card)); - rwFail = 1; + ret = RET_FAIL; } delete[] buffer; @@ -411,23 +445,16 @@ u32 CWII_IPC_HLE_Device_sdio_slot0::ExecuteCommand(u32 _BufferIn, u32 _BufferInS Memory::Write_U32(0x900, _BufferOut); break; - case SDHC_CAPABILITIES: - { - DEBUG_LOG(WII_IPC_SD, "SDHC_CAPABILITIES"); - // SDHC 1.0 supports only 10-63 MHz. - // So of course we reply 63MHz :) - u32 freq = (63 << 8) + (1 << 7) + 63; - // Only support 3.3V - u32 voltage = 1 << 24; - // High Speed support - u32 speed = 1 << 21; - u32 caps = freq | voltage | speed; - Memory::Write_U32(caps, _BufferOut); - break; - } + case EVENT_REGISTER: // async + DEBUG_LOG(WII_IPC_SD, "Register event %x", req.arg); + m_event.type = (EventType)req.arg; + ret = RET_EVENT_REGISTER; + break; - case CRAZY_BIGN65: - // Just means unmount/detach, but we don't care + case EVENT_UNREGISTER: // synchronous + DEBUG_LOG(WII_IPC_SD, "Unregister event %x", req.arg); + m_event.type = (EventType)req.arg; + ret = RET_EVENT_UNREGISTER; break; default: @@ -435,5 +462,5 @@ u32 CWII_IPC_HLE_Device_sdio_slot0::ExecuteCommand(u32 _BufferIn, u32 _BufferInS break; } - return rwFail; + return ret; } diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h index a6e20086cb..6fcf3debc0 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.h @@ -35,6 +35,8 @@ public: bool IOCtl(u32 _CommandAddress); bool IOCtlV(u32 _CommandAddress); + void EventNotify(); + private: enum @@ -67,6 +69,15 @@ private: IOCTLV_SENDCMD = 0x07, }; + // ExecuteCommand + enum + { + RET_OK, + RET_FAIL, + RET_EVENT_REGISTER, // internal state only - not actually returned + RET_EVENT_UNREGISTER + }; + // Status enum { @@ -95,10 +106,30 @@ private: ACMD_SENDOPCOND = 0x29, ACMD_SENDSCR = 0x33, - SDHC_CAPABILITIES = 0x40, - CRAZY_BIGN65 = 0x41, + EVENT_REGISTER = 0x40, + EVENT_UNREGISTER = 0x41, }; + enum EventType + { + EVENT_NONE = 0, + EVENT_INSERT, + EVENT_REMOVE, + // from unregister, i think it is just meant to be invalid + EVENT_INVALID = 0xc210000 + }; + + // TODO do we need more than one? + struct Event + { + EventType type; + u32 addr; + Event() + : type(EVENT_NONE) + , addr() + {} + } m_event; + u32 m_Status; u32 m_BlockLength; u32 m_BusWidth; diff --git a/Source/Core/DolphinWX/Src/ConfigMain.cpp b/Source/Core/DolphinWX/Src/ConfigMain.cpp index 464e66c362..4388d4eacb 100644 --- a/Source/Core/DolphinWX/Src/ConfigMain.cpp +++ b/Source/Core/DolphinWX/Src/ConfigMain.cpp @@ -27,6 +27,7 @@ #include "HW/SI.h" #include "HW/DSPHLE/DSPHLE.h" #include "HW/DSPLLE/DSPLLE.h" +#include "IPC_HLE/WII_IPC_HLE.h" #include "Globals.h" // Local #include "ConfigMain.h" @@ -1268,6 +1269,7 @@ void CConfigMain::WiiSettingsChanged(wxCommandEvent& event) // Wii - Devices case ID_WII_SD_CARD: SConfig::GetInstance().m_WiiSDCard = WiiSDCard->IsChecked(); + WII_IPC_HLE_Interface::SDIO_EventNotify(); break; case ID_WII_KEYBOARD: SConfig::GetInstance().m_WiiKeyboard = WiiKeyboard->IsChecked(); diff --git a/Source/TestSuite/WSD/source/dolphintest_wsd.cpp b/Source/TestSuite/WSD/source/dolphintest_wsd.cpp index 00bc199a1a..52fbe4bbf8 100644 --- a/Source/TestSuite/WSD/source/dolphintest_wsd.cpp +++ b/Source/TestSuite/WSD/source/dolphintest_wsd.cpp @@ -1,146 +1,135 @@ -// Thanks to: -// SD Card Directory Listing Demo -// Updated 12/19/2008 by PunMaster +// SD card insertion/removal callback demo -#include -#include #include #include -#include -#include -#include +#include +#include +#include #include -#include -#include -#include -#include -#include + +#define IOCTL_SDIO_SENDCMD 0x07 + +#define SDIO_CMD_REGINTR 0x40 +#define SDIO_CMD_UNREGINTR 0x41 + +#define SD_INSERT_EVENT 0x01 +#define SD_REMOVE_EVENT 0x02 + +static struct _sdiorequest +{ + u32 cmd; + u32 cmd_type; + u32 rsp_type; + u32 arg; + u32 blk_cnt; + u32 blk_size; + void *dma_addr; + u32 isdma; + u32 pad0; +} sd_req; + +static struct _sdioresponse +{ + u32 rsp_fields[3]; + u32 acmd12_response; +} sd_resp; + +static s32 __sd0_fd = -1; +static const char _sd0_fs[] ATTRIBUTE_ALIGN(32) = "/dev/sdio/slot0"; + +static s32 __sdio_getinterrupt(u32 hook, ipccallback cb) +{ + memset(&sd_req, 0, sizeof(sd_req)); + + sd_req.cmd = SDIO_CMD_REGINTR; + sd_req.arg = hook; + + if (hook==SD_INSERT_EVENT) + printf("Requesting insert event %p %p\n", cb, &sd_resp); + else if (hook==SD_REMOVE_EVENT) + printf("Requesting removal event %p %p\n", cb, &sd_resp); + else + printf("I don't know what I'm requesting here: hook=%u\n", hook); + + if (__sd0_fd<0) + __sd0_fd = IOS_Open(_sd0_fs,1); + + if (__sd0_fd>=0) + return IOS_IoctlAsync(__sd0_fd,IOCTL_SDIO_SENDCMD,&sd_req,sizeof(sd_req),&sd_resp,sizeof(sd_resp),cb,NULL); + + // else return the IOS_Open error code + return __sd0_fd; +} + +static s32 __sdio_releaseinterrupt(void) +{ + if (__sd0_fd<0) + return 0; + + // this command makes the IOS_IoctlAsync call above return a response immediately + + // sd_req.arg is already set to the right value (1 or 2, whatever was used last) + sd_req.cmd = SDIO_CMD_UNREGINTR; + return IOS_Ioctl(__sd0_fd,IOCTL_SDIO_SENDCMD,&sd_req,sizeof(sd_req),&sd_resp,sizeof(sd_resp)); +} + +static void sd_cb(u32 ret, void* unused) +{ + printf("Got an SD interrupt, ret = %08X\n", ret); + printf("Response data: %08X %08X %08X %08X\n", sd_resp.rsp_fields[0], sd_resp.rsp_fields[1], sd_resp.rsp_fields[2], sd_resp.acmd12_response); + + if (ret==SD_INSERT_EVENT) + { + printf("SD card was inserted\n"); + // tell us when it gets removed + __sdio_getinterrupt(SD_REMOVE_EVENT, (ipccallback)sd_cb); + } + else if (ret==SD_REMOVE_EVENT) + { + printf("SD card was removed\n"); + // tell us when something is inserted + __sdio_getinterrupt(SD_INSERT_EVENT, (ipccallback)sd_cb); + } + else + printf("Unknown SD int: %08X\n", ret); +} + + static void *xfb = NULL; +static GXRModeObj *rmode = NULL; -u32 first_frame = 1; -GXRModeObj *rmode; +int main(int argc, char **argv) { + VIDEO_Init(); + WPAD_Init(); + rmode = VIDEO_GetPreferredMode(NULL); + xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); + console_init(xfb,20,20,rmode->fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ); + VIDEO_Configure(rmode); + VIDEO_SetNextFramebuffer(xfb); + VIDEO_SetBlack(FALSE); + VIDEO_Flush(); + VIDEO_WaitVSync(); + if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); -void Initialise() -{ - // Initialise the video system - VIDEO_Init(); + printf("\x1b[2;0H"); + printf("SD Card insertion/removal demo\n"); + printf("Press HOME at any time to exit\n"); - // This function initialises the attached controllers - PAD_Init(); - WPAD_Init(); + __sdio_getinterrupt(SD_INSERT_EVENT, (ipccallback)sd_cb); - // Obtain the preferred video mode from the system - // This will correspond to the settings in the Wii menu - rmode = VIDEO_GetPreferredMode(NULL); + while(1) { + WPAD_ScanPads(); + u32 pressed = WPAD_ButtonsDown(0); + if ( pressed & WPAD_BUTTON_HOME ) break; + VIDEO_WaitVSync(); + } - // Allocate memory for the display in the uncached region - xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode)); + printf("SD event release returned %d\n", __sdio_releaseinterrupt()); + IOS_Close(__sd0_fd); - // Initialise the console, required for printf - console_init(xfb,20,20,rmode->fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ); + sleep(4); - // Set up the video registers with the chosen mode - VIDEO_Configure(rmode); - - // Tell the video hardware where our display memory is - VIDEO_SetNextFramebuffer(xfb); - - // Make the display visible - VIDEO_SetBlack(FALSE); - - // Flush the video register changes to the hardware - VIDEO_Flush(); - - // Wait for Video setup to complete - VIDEO_WaitVSync(); - if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); -} - -void dirlist(char* path) -{ - DIR* pdir = opendir(path); - - if (pdir != NULL) - { - u32 sentinel = 0; - - while(true) - { - struct dirent* pent = readdir(pdir); - if(pent == NULL) break; - - if(strcmp(".", pent->d_name) != 0 && strcmp("..", pent->d_name) != 0) - { - char dnbuf[260]; - sprintf(dnbuf, "%s/%s", path, pent->d_name); - - struct stat statbuf; - stat(dnbuf, &statbuf); - - if(S_ISDIR(statbuf.st_mode)) - { - printf("%s \n", dnbuf); - dirlist(dnbuf); - } - else - { - printf("%s (%d)\n", dnbuf, (int)statbuf.st_size); - } - sentinel++; - } - } - - if (sentinel == 0) - printf("empty\n"); - - closedir(pdir); - printf("\n"); - } - else - { - printf("opendir() failure.\n"); - } -} - -int main() -{ - bool canList = false; - - Initialise(); - - printf("\x1b[10;0H"); - - if(fatInitDefault()) - { - printf("\nPress A to list dirs\n"); - canList = true; - } - else - printf("\nfatInitDefault() failure.\n"); - - while(1) - { - // Call WPAD_ScanPads each loop, this reads the latest controller states - PAD_ScanPads(); - WPAD_ScanPads(); - - // WPAD_ButtonsDown tells us which buttons were wpressed in this loop - // this is a "one shot" state which will not fire again until the button has been released - u32 pressed = PAD_ButtonsDown(0); - u32 wpressed = WPAD_ButtonsDown(0); - - if ((wpressed & WPAD_BUTTON_A || pressed & PAD_BUTTON_A) && canList) - dirlist("/"); - - // We return to the launcher application via exit - if (wpressed & WPAD_BUTTON_HOME || pressed & PAD_BUTTON_START) - exit(0); - - // Wait for the next frame - VIDEO_WaitVSync(); - } - - return 0; + return 0; }