diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj index 05619e6f0c..ec8e8ecbe4 100644 --- a/Source/Core/Core/Core.vcproj +++ b/Source/Core/Core/Core.vcproj @@ -2119,6 +2119,10 @@ RelativePath=".\Src\IPC_HLE\WII_IPC_HLE_Device_Error.h" > + + diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp new file mode 100644 index 0000000000..397f18b2e5 --- /dev/null +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp @@ -0,0 +1,449 @@ +// Copyright (C) 2003-2008 Dolphin Project. + +// This program 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, version 2.0. + +// This program 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + + + +// ======================================================= +// File description +// ------------- +/* Here we handle /dev/es requests. We have cases for these functions, the exact + DevKitPro name is en parenthesis: + + 0x20 GetTitleID (ES_GetTitleID) (Input: none, Output: 8 bytes) + 0x1d GetDataDir (ES_GetDataDir) (Input: 8 bytes, Output: 30 bytes) + + 0x1b DiGetTicketView (Input: none, Output: 216 bytes) + 0x16 GetConsumption (Input: 8 bytes, Output: 0 bytes, 4 bytes) // there are two output buffers + + 0x12 GetNumTicketViews (ES_GetNumTicketViews) (Input: 8 bytes, Output: 4 bytes) + 0x14 GetTMDViewSize (ES_GetTMDViewSize) (Input: ?, Output: ?) // I don't get this anymore, + it used to come after 0x12 + + but only the first two are correctly supported. For the other four we ignore any potential + input and only write zero to the out buffer. However, most games only use first two, + but some Nintendo developed games use the other ones to: + + 0x1b: Mario Galaxy, Mario Kart, SSBB + 0x16: Mario Galaxy, Mario Kart, SSBB + 0x12: Mario Kart + 0x14: Mario Kart: But only if we don't return a zeroed out buffer for the 0x12 question, + and instead answer for example 1 will this question appear. + +*/ +// ============= + +#include "WII_IPC_HLE_Device_es.h" + +#include "../PowerPC/PowerPC.h" +#include "../VolumeHandler.h" + + +CWII_IPC_HLE_Device_es::CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName, const std::string& _rDefaultContentFile) + : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) + , m_pContentLoader(NULL) + , m_TitleID(-1) + , AccessIdentID(0x6000000) +{ + m_pContentLoader = new DiscIO::CNANDContentLoader(_rDefaultContentFile); + if (m_pContentLoader->IsValid()) + { + m_TitleID = m_pContentLoader->GetTitleID(); + } +} + +CWII_IPC_HLE_Device_es::~CWII_IPC_HLE_Device_es() +{ + delete m_pContentLoader; +} + +bool CWII_IPC_HLE_Device_es::Open(u32 _CommandAddress, u32 _Mode) +{ + Memory::Write_U32(GetDeviceID(), _CommandAddress+4); + return true; +} + +bool CWII_IPC_HLE_Device_es::Close(u32 _CommandAddress) +{ + LOG(WII_IPC_ES, "ES: Close"); + Memory::Write_U32(0, _CommandAddress + 4); + return true; +} + +bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) +{ + SIOCtlVBuffer Buffer(_CommandAddress); + + LOG(WII_IPC_ES, "%s (0x%x)", GetDeviceName().c_str(), Buffer.Parameter); + + // Prepare the out buffer(s) with zeroes as a safety precaution + // to avoid returning bad values + for(u32 i = 0; i < Buffer.NumberPayloadBuffer; i++) + { + Memory::Memset(Buffer.PayloadBuffer[i].m_Address, 0, + Buffer.PayloadBuffer[i].m_Size); + } + + switch(Buffer.Parameter) + { + case IOCTL_ES_OPENTITLECONTENT: // 0x09 + { + u32 CFD = AccessIdentID++; + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address+8); + + m_ContenAccessMap[CFD].m_Position = 0; + m_ContenAccessMap[CFD].m_pContent = AccessContentDevice().GetContentByIndex(Index); + _dbg_assert_(WII_IPC_ES, m_ContenAccessMap[CFD].m_pContent != NULL); + + Memory::Write_U32(CFD, _CommandAddress + 0x4); + + LOG(WII_IPC_ES, "ES: IOCTL_ES_OPENTITLECONTENT: TitleID: %08x/%08x Index %i -> got CFD %x", TitleID>>32, TitleID, Index, CFD); + return true; + } + break; + + case IOCTL_ES_OPENCONTENT: // 0x09 + { + u32 CFD = AccessIdentID++; + u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + + m_ContenAccessMap[CFD].m_Position = 0; + m_ContenAccessMap[CFD].m_pContent = AccessContentDevice().GetContentByIndex(Index); + _dbg_assert_(WII_IPC_ES, m_ContenAccessMap[CFD].m_pContent != NULL); + + Memory::Write_U32(CFD, _CommandAddress + 0x4); + + LOG(WII_IPC_ES, "ES: IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD); + return true; + } + break; + + case IOCTL_ES_READCONTENT: + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); + + u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + u32 Size = Buffer.PayloadBuffer[0].m_Size; + u32 Addr = Buffer.PayloadBuffer[0].m_Address; + + _dbg_assert_(WII_IPC_ES, m_ContenAccessMap.find(CFD) != m_ContenAccessMap.end()); + SContentAccess& rContent = m_ContenAccessMap[CFD]; + + u8* pSrc = &rContent.m_pContent->m_pData[rContent.m_Position]; + u8* pDest = Memory::GetPointer(Addr); + + if (rContent.m_Position + Size > rContent.m_pContent->m_Size) + { + Size = rContent.m_pContent->m_Size-rContent.m_Position; + } + + if (Size > 0) + { + memcpy(pDest,pSrc, Size); + rContent.m_Position += Size; + } + + LOG(WII_IPC_ES, "ES: IOCTL_ES_READCONTENT: CFD %x, Addr 0x%x, Size %i -> stream pos %i", CFD, Addr, Size, rContent.m_Position); + + Memory::Write_U32(Size, _CommandAddress + 0x4); + return true; + } + break; + + case IOCTL_ES_CLOSECONTENT: + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); + u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + + CContenAccessMap::iterator itr = m_ContenAccessMap.find(CFD); + m_ContenAccessMap.erase(itr); + + LOG(WII_IPC_ES, "ES: IOCTL_ES_CLOSECONTENT: CFD %x", CFD); + + Memory::Write_U32(0, _CommandAddress + 0x4); + return true; + } + break; + + case IOCTL_ES_SEEKCONTENT: + { + u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + u32 Addr = Memory::Read_U32(Buffer.InBuffer[1].m_Address); + u32 Mode = Memory::Read_U32(Buffer.InBuffer[2].m_Address); + + _dbg_assert_(WII_IPC_ES, m_ContenAccessMap.find(CFD) != m_ContenAccessMap.end()); + SContentAccess& rContent = m_ContenAccessMap[CFD]; + + switch(Mode) + { + case 0: // SET + rContent.m_Position = Addr; + break; + + case 1: // CUR + rContent.m_Position += Addr; + break; + + case 2: // END + rContent.m_Position = rContent.m_pContent->m_Size; + break; + } + + LOG(WII_IPC_ES, "ES: IOCTL_ES_SEEKCONTENT: CFD %x, Addr 0x%x, Mode %i -> Pos %i", CFD, Addr, Mode, rContent.m_Position); + + Memory::Write_U32(rContent.m_Position, _CommandAddress + 0x4); + return true; + } + break; + + case IOCTL_ES_GETTITLEDIR: // 0x1d + { + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + _dbg_assert_msg_(WII_IPC_ES, TitleID == GetCurrentTitleID(), "Get Dir from unkw title dir?? this can be okay..."); + + char* pTitleID = (char*)&TitleID; + char* Path = (char*)Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); + sprintf(Path, "/%08x/%08x/data", (TitleID >> 32) & 0xFFFFFFFF, TitleID & 0xFFFFFFFF); + + LOG(WII_IPC_ES, "ES: IOCTL_ES_GETTITLEDIR: %s)", Path); + } + break; + + case IOCTL_ES_GETTITLEID: // 0x20 + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "CWII_IPC_HLE_Device_es: IOCTL_ES_GETTITLEID no out buffer"); + + /* This seems to be the right address to write the Title ID to + because then it shows up in the InBuffer of IOCTL_ES_GETTITLEDIR + that is called right after this. I have not seen that this + have any effect by itself, it probably only matters as an input to + IOCTL_ES_GETTITLEDIR. This values is not stored in 0x3180 or anywhere + else as I have seen, it's just used as an input buffer in the following + IOCTL_ES_GETTITLEDIR call and then forgotten. */ + + u64 TitleID = GetCurrentTitleID(); + _dbg_assert_msg_(WII_IPC_ES, TitleID == m_TitleID, "TitleID != m_TitleID - GetCurrentTitleID();"); + + Memory::Write_U64(TitleID, Buffer.PayloadBuffer[0].m_Address); + LOG(WII_IPC_ES, "ES: IOCTL_ES_GETTITLEID: %08x/%08x", TitleID>>32, TitleID); + } + break; + + case IOCTL_ES_SETUID: // 0x21 + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "CWII_IPC_HLE_Device_es: IOCTL_ES_GETTITLEID no in buffer"); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + LOG(WII_IPC_ES, "ES: IOCTL_ES_SETUID titleID: %08x/%08x", TitleID>>32, TitleID ); + } + break; + + case IOCTL_ES_GETVIEWCNT: // 0x12 (Input: 8 bytes, Output: 4 bytes) + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "CWII_IPC_HLE_Device_es: IOCTL_ES_GETVIEWCNT no in buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "CWII_IPC_HLE_Device_es: IOCTL_ES_GETVIEWCNT no out buffer"); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + + // [TODO] here we should have a map from title id to tickets or something like that... + /* if (GetContentSize() > 0) + { + Memory::Write_U32(1, Buffer.PayloadBuffer[0].m_Address); + }*/ + Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address); + + LOG(WII_IPC_ES, "ES: IOCTL_ES_GETVIEWCNT for titleID: %08x/%08x", TitleID>>32, TitleID ); + + Memory::Write_U32(0, _CommandAddress + 0x4); + return true; + } + break; + + case IOCTL_ES_GETTITLECNT: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 0, "IOCTL_ES_GETTITLECNT has an in buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLECNT has no out buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.PayloadBuffer[0].m_Size == 4, "IOCTL_ES_GETTITLECNT payload[0].size != 4"); + + + // TODO + Memory::Write_U32(1, Buffer.PayloadBuffer[0].m_Address); + + LOGV(WII_IPC_ES, 0, "IOCTL_ES_GETTITLECNT: TODO... 1"); + } + break; + + + case IOCTL_ES_GETTITLES: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 1, "IOCTL_ES_GETTITLES has an in buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLES has no out buffer"); + + u32 Count = Memory::Read_U32(Buffer.InBuffer[0].m_Address); + + std::vector TitleIDs; + TitleIDs.push_back(0x0000000100000002); + // TitleIDs.push_back(0x0001000248414341); + // TitleIDs.push_back(0x0001000146414b45); + + for (size_t i=0; i>32, TitleIDs[i]); + } + } + break; + + + + // =============================================================================================== + // unsupported functions + // =============================================================================================== + + case IOCTL_ES_LAUNCH: // 0x08 + { + _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 2); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + + u32 view = Memory::Read_U32(Buffer.InBuffer[1].m_Address); + u64 ticketid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+4); + u32 devicetype =Memory::Read_U32(Buffer.InBuffer[1].m_Address+12); + u64 titleid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+16); + u16 access = Memory::Read_U16(Buffer.InBuffer[1].m_Address+24); + + PanicAlert("IOCTL_ES_LAUNCH: src titleID %08x/%08x -> start %08x/%08x \n" + "This means that dolphin tries to relaunch the WiiMenu or" + "launches code from the an URL. Both wont work and dolphin will prolly hang...", + TitleID>>32, TitleID, titleid>>32, titleid ); + + Memory::Write_U32(0, _CommandAddress + 0x4); + + LOGV(WII_IPC_ES, 0, "IOCTL_ES_LAUNCH"); + + return true; + } + break; + + case IOCTL_ES_GETVIEWS: + { + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETVIEWS no in buffer"); + _dbg_assert_msg_(WII_IPC_ES, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETVIEWS no out buffer"); + + u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + u32 Count = Memory::Read_U32(Buffer.InBuffer[1].m_Address); + + _dbg_assert_msg_(WII_IPC_ES, TitleID==0x0000000100000002ull, "IOCTL_ES_GETVIEWS: TitleID != 00000001/00000002"); + + /* write ticket data... hmmm + typedef struct _tikview { + u32 view; + u64 ticketid; + u32 devicetype; + u64 titleid; + u16 access_mask; + u8 reserved[0x3c]; + u8 cidx_mask[0x40]; + u16 padding; + tiklimit limits[8]; + } __attribute__((packed)) tikview; + */ + + Memory::Write_U32(1, Buffer.PayloadBuffer[0].m_Address); + Memory::Write_U64(m_TitleID, Buffer.PayloadBuffer[0].m_Address+4); + Memory::Write_U32(0x00010001, Buffer.PayloadBuffer[0].m_Address+12); + Memory::Write_U64(m_TitleID, Buffer.PayloadBuffer[0].m_Address+16); + Memory::Write_U16(0x777, Buffer.PayloadBuffer[0].m_Address+24); + + Memory::Write_U32(0, _CommandAddress + 0x4); + + _dbg_assert_msg_(WII_IPC_ES, 0, "IOCTL_ES_GETVIEWS: this looks really wrong..."); + + LOGV(WII_IPC_ES, 0, "IOCTL_ES_LAUNCH"); + return true; + } + break; + + case IOCTL_ES_GETSTOREDTMDSIZE: + { + _dbg_assert_msg_(WII_IPC_ES, 0, "IOCTL_ES_GETSTOREDTMDSIZE: this looks really wrong..."); + + /* u64 TitleId = Memory::Read_U64(Buffer.InBuffer[0].m_Address); + u32 OutBuffer = Memory::Read_U32(Buffer.PayloadBuffer[0].m_Address); + + Memory::Write_U32(0, OutBuffer); + printf("ES_GetStoredTmdSize(%llx)\n", TitleId); + LOG(WII_IPC_ES, "CWII_IPC_HLE_Device_es command:" + " IOCTL_ES_GETSTOREDTMDSIZE: 0x%x", OutBuffer);*/ + } + break; + + case IOCTL_ES_GETTMDVIEWCNT: // 0x14 + _dbg_assert_msg_(WII_IPC_ES, 0, "IOCTL_ES_GETTMDVIEWCNT: this looks really wrong..."); + break; + + case IOCTL_ES_GETCONSUMPTION: // (Input: 8 bytes, Output: 0 bytes, 4 bytes) + _dbg_assert_msg_(WII_IPC_ES, 0, "IOCTL_ES_GETCONSUMPTION: this looks really wrong..."); + break; + + case IOCTL_ES_DIGETTICKETVIEW: // (Input: none, Output: 216 bytes) + _dbg_assert_msg_(WII_IPC_ES, 0, "IOCTL_ES_DIGETTICKETVIEW: this looks really wrong..."); + break; + + + default: + + _dbg_assert_msg_(WII_IPC_ES, 0, "CWII_IPC_HLE_Device_es: 0x%x", Buffer.Parameter); + + DumpCommands(_CommandAddress, 8); + LOG(WII_IPC_ES, "CWII_IPC_HLE_Device_es command:" + "Parameter: 0x%08x", Buffer.Parameter); + + break; + } + + // Write return value (0 means OK) + Memory::Write_U32(0, _CommandAddress + 0x4); + + return true; +} + +u64 CWII_IPC_HLE_Device_es::GetCurrentTitleID() const +{ + u64 TitleID = -1; + + // check for cd ... + if (AccessContentDevice().IsValid()) + { + TitleID = m_TitleID; + } + else if (VolumeHandler::IsValid()) + { + TitleID = ((u64)0x00010000 << 32) | VolumeHandler::Read32(0); + } + else + { + TitleID = ((u64)0x00010000 << 32) | 0xF00DBEEF; + } + + return TitleID; +} + +DiscIO::CNANDContentLoader& CWII_IPC_HLE_Device_es::AccessContentDevice() const +{ + return* m_pContentLoader; +} diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h index 2045f2ca4f..6457b50a8b 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h @@ -15,427 +15,105 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ - - -// ======================================================= -// File description -// ------------- -/* Here we handle /dev/es requests. We have cases for these functions, the exact - DevKitPro name is en parenthesis: - - 0x20 GetTitleID (ES_GetTitleID) (Input: none, Output: 8 bytes) - 0x1d GetDataDir (ES_GetDataDir) (Input: 8 bytes, Output: 30 bytes) - - 0x1b DiGetTicketView (Input: none, Output: 216 bytes) - 0x16 GetConsumption (Input: 8 bytes, Output: 0 bytes, 4 bytes) // there are two output buffers - - 0x12 GetNumTicketViews (ES_GetNumTicketViews) (Input: 8 bytes, Output: 4 bytes) - 0x14 GetTMDViewSize (ES_GetTMDViewSize) (Input: ?, Output: ?) // I don't get this anymore, - it used to come after 0x12 - - but only the first two are correctly supported. For the other four we ignore any potential - input and only write zero to the out buffer. However, most games only use first two, - but some Nintendo developed games use the other ones to: - - 0x1b: Mario Galaxy, Mario Kart, SSBB - 0x16: Mario Galaxy, Mario Kart, SSBB - 0x12: Mario Kart - 0x14: Mario Kart: But only if we don't return a zeroed out buffer for the 0x12 question, - and instead answer for example 1 will this question appear. - -*/ -// ============= - #ifndef _WII_IPC_HLE_DEVICE_ES_H_ #define _WII_IPC_HLE_DEVICE_ES_H_ +#include #include "WII_IPC_HLE_Device.h" -#include "../VolumeHandler.h" - -#include "../Boot/Boot_WiiWAD.h" - -#include "../PowerPC/PowerPC.h" - - -struct SContentAccess -{ - u32 m_Position; - STileMetaContent* m_pContent; -}; - -typedef std::map CContenAccessMap; -CContenAccessMap m_ContenAccessMap; -u32 AccessIdentID = 0x60000000; - - - - - -// http://wiibrew.org/index.php?title=/dev/es +#include "NANDContentLoader.h" class CWII_IPC_HLE_Device_es : public IWII_IPC_HLE_Device { public: - enum - { - IOCTL_ES_ADDTICKET = 0x01, - IOCTL_ES_ADDTITLESTART = 0x02, - IOCTL_ES_ADDCONTENTSTART = 0x03, - IOCTL_ES_ADDCONTENTDATA = 0x04, - IOCTL_ES_ADDCONTENTFINISH = 0x05, - IOCTL_ES_ADDTITLEFINISH = 0x06, - IOCTL_ES_LAUNCH = 0x08, - IOCTL_ES_OPENCONTENT = 0x09, - IOCTL_ES_READCONTENT = 0x0A, - IOCTL_ES_CLOSECONTENT = 0x0B, - IOCTL_ES_GETTITLECOUNT = 0x0E, - IOCTL_ES_GETTITLES = 0x0F, - IOCTL_ES_GETVIEWCNT = 0x12, - IOCTL_ES_GETVIEWS = 0x13, - IOCTL_ES_GETTMDVIEWCNT = 0x14, - IOCTL_ES_GETCONSUMPTION = 0x16, - IOCTL_ES_DIGETTICKETVIEW = 0x1b, - IOCTL_ES_DIVERIFY = 0x1C, - IOCTL_ES_GETTITLEDIR = 0x1D, - IOCTL_ES_GETTITLEID = 0x20, - IOCTL_ES_SEEKCONTENT = 0x23, - IOCTL_ES_ADDTMD = 0x2B, - IOCTL_ES_ADDTITLECANCEL = 0x2F, - IOCTL_ES_GETSTOREDCONTENTCNT = 0x32, - IOCTL_ES_GETSTOREDCONTENTS = 0x33, - IOCTL_ES_GETSTOREDTMDSIZE = 0x34, - IOCTL_ES_GETSTOREDTMD = 0x35, - IOCTL_ES_GETSHAREDCONTENTCNT = 0x36, - IOCTL_ES_GETSHAREDCONTENTS = 0x37, - }; - - - CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName) : - IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) - {} - - virtual ~CWII_IPC_HLE_Device_es() - {} - - virtual bool Open(u32 _CommandAddress, u32 _Mode) - { - Memory::Write_U32(GetDeviceID(), _CommandAddress+4); - return true; - } - - virtual bool Close(u32 _CommandAddress) - { - LOG(WII_IPC_ES, "ES: Close"); - Memory::Write_U32(0, _CommandAddress + 4); - return true; - } - - virtual bool IOCtlV(u32 _CommandAddress) - { - SIOCtlVBuffer Buffer(_CommandAddress); - - LOG(WII_IPC_ES, "%s (0x%x)", GetDeviceName().c_str(), Buffer.Parameter); - - // Prepare the out buffer(s) with zeroes as a safety precaution - // to avoid returning bad values - for(u32 i = 0; i < Buffer.NumberPayloadBuffer; i++) - { - Memory::Memset(Buffer.PayloadBuffer[i].m_Address, 0, - Buffer.PayloadBuffer[i].m_Size); - } - - switch(Buffer.Parameter) - { - case IOCTL_ES_OPENCONTENT: // 0x09 - { - u32 CFD = AccessIdentID++; - u32 Index = Memory::Read_U32(Buffer.InBuffer[0].m_Address); - - m_ContenAccessMap[CFD].m_Position = 0; - m_ContenAccessMap[CFD].m_pContent = &m_TileMetaContent[Index]; - - Memory::Write_U32(CFD, _CommandAddress + 0x4); - - LOG(WII_IPC_ES, "ES: IOCTL_ES_OPENCONTENT: Index %i -> got CFD %x", Index, CFD); - return true; - } - break; - - case IOCTL_ES_READCONTENT: - { - _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); - - u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); - u32 Size = Buffer.PayloadBuffer[0].m_Size; - u32 Addr = Buffer.PayloadBuffer[0].m_Address; - - _dbg_assert_(WII_IPC_ES, m_ContenAccessMap.find(CFD) != m_ContenAccessMap.end()); - SContentAccess& rContent = m_ContenAccessMap[CFD]; - - u8* pSrc = &rContent.m_pContent->m_pData[rContent.m_Position]; - u8* pDest = Memory::GetPointer(Addr); - - if (rContent.m_Position + Size > rContent.m_pContent->m_Size) - { - Size = rContent.m_pContent->m_Size-rContent.m_Position; - } - - if (Size > 0) - { - memcpy(pDest,pSrc, Size); - rContent.m_Position += Size; - } - - LOG(WII_IPC_ES, "ES: IOCTL_ES_READCONTENT: CFD %x, Addr 0x%x, Size %i -> stream pos %i", CFD, Addr, Size, rContent.m_Position); - - Memory::Write_U32(Size, _CommandAddress + 0x4); - return true; - } - break; - - case IOCTL_ES_CLOSECONTENT: - { - _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 1); - u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); - - CContenAccessMap::iterator itr = m_ContenAccessMap.find(CFD); - m_ContenAccessMap.erase(itr); - - LOG(WII_IPC_ES, "ES: IOCTL_ES_CLOSECONTENT: CFD %x", CFD); - - Memory::Write_U32(0, _CommandAddress + 0x4); - return true; - } - break; - - case IOCTL_ES_SEEKCONTENT: - { - u32 CFD = Memory::Read_U32(Buffer.InBuffer[0].m_Address); - u32 Addr = Memory::Read_U32(Buffer.InBuffer[1].m_Address); - u32 Mode = Memory::Read_U32(Buffer.InBuffer[2].m_Address); - - _dbg_assert_(WII_IPC_ES, m_ContenAccessMap.find(CFD) != m_ContenAccessMap.end()); - SContentAccess& rContent = m_ContenAccessMap[CFD]; - - switch(Mode) - { - case 0: // SET - rContent.m_Position = Addr; - break; - - case 1: // CUR - rContent.m_Position += Addr; - break; - - case 2: // END - rContent.m_Position = rContent.m_pContent->m_Size; - break; - } - - LOG(WII_IPC_ES, "ES: IOCTL_ES_SEEKCONTENT: CFD %x, Addr 0x%x, Mode %i -> Pos %i", CFD, Addr, Mode, rContent.m_Position); - - Memory::Write_U32(rContent.m_Position, _CommandAddress + 0x4); - return true; - } - break; - - case IOCTL_ES_GETTITLEDIR: // 0x1d - { - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - _dbg_assert_msg_(WII_IPC_HLE, TitleID == GetCurrentTitleID(), "Get Dir from unkw title dir?? this can be okay..."); - - char* pTitleID = (char*)&TitleID; - char* Path = (char*)Memory::GetPointer(Buffer.PayloadBuffer[0].m_Address); - sprintf(Path, "/%08x/%08x/data", (TitleID >> 32) & 0xFFFFFFFF, TitleID & 0xFFFFFFFF); - - LOG(WII_IPC_ES, "ES: IOCTL_ES_GETTITLEDIR: %s)", Path); - } - break; - - case IOCTL_ES_GETTITLEID: // 0x20 - { - _dbg_assert_msg_(WII_IPC_HLE, Buffer.NumberPayloadBuffer == 1, "CWII_IPC_HLE_Device_es: IOCTL_ES_GETTITLEID no in buffer"); - - - /* This seems to be the right address to write the Title ID to - because then it shows up in the InBuffer of IOCTL_ES_GETTITLEDIR - that is called right after this. I have not seen that this - have any effect by itself, it probably only matters as an input to - IOCTL_ES_GETTITLEDIR. This values is not stored in 0x3180 or anywhere - else as I have seen, it's just used as an input buffer in the following - IOCTL_ES_GETTITLEDIR call and then forgotten. */ - - u64 TitleID = GetCurrentTitleID(); - - Memory::Write_U64(TitleID, Buffer.PayloadBuffer[0].m_Address); - LOG(WII_IPC_ES, "ES: IOCTL_ES_GETTITLEID: 0x%x 0x%x", TitleID>>32, TitleID); - } - break; - - case IOCTL_ES_GETVIEWCNT: // 0x12 (Input: 8 bytes, Output: 4 bytes) - { - _dbg_assert_msg_(WII_IPC_HLE, Buffer.NumberInBuffer == 1, "CWII_IPC_HLE_Device_es: IOCTL_ES_GETVIEWCNT no in buffer"); - _dbg_assert_msg_(WII_IPC_HLE, Buffer.NumberPayloadBuffer == 1, "CWII_IPC_HLE_Device_es: IOCTL_ES_GETVIEWCNT no out buffer"); - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - - // [TODO] here we should have a map from title id to tickets or something like that... - if (m_TileMetaContent.size() > 0) - { - Memory::Write_U32(1, Buffer.PayloadBuffer[0].m_Address); - } - - LOG(WII_IPC_ES, "ES: IOCTL_ES_GETVIEWCNT titleID: %08x/%08x", TitleID>>32, TitleID ); - - Memory::Write_U32(0, _CommandAddress + 0x4); - return true; - } - break; - - - - case IOCTL_ES_GETTITLECOUNT: - { - _dbg_assert_msg_(WII_IPC_HLE, Buffer.NumberInBuffer == 0, "IOCTL_ES_GETTITLECOUNT has an in buffer"); - _dbg_assert_msg_(WII_IPC_HLE, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETTITLECOUNT has no out buffer"); - _dbg_assert_msg_(WII_IPC_HLE, Buffer.PayloadBuffer[0].m_Size == 4, "IOCTL_ES_GETTITLECOUNT payload[0].size != 4"); - - Memory::Write_U64(0, Buffer.PayloadBuffer[0].m_Address); - - LOGV(WII_IPC_ES, 0, "IOCTL_ES_GETTITLECOUNT: TODO - hardcoded to 0 !!!!"); - } - break; - - -// =============================================================================================== -// unsupported functions -// =============================================================================================== - - case IOCTL_ES_LAUNCH: // 0x08 - { - _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 2); - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - - u32 view = Memory::Read_U32(Buffer.InBuffer[1].m_Address); - u64 ticketid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+4); - u32 devicetype =Memory::Read_U32(Buffer.InBuffer[1].m_Address+12); - u64 titleid = Memory::Read_U64(Buffer.InBuffer[1].m_Address+16); - u16 access = Memory::Read_U16(Buffer.InBuffer[1].m_Address+24); - - PanicAlert("IOCTL_ES_LAUNCH: src titleID %08x/%08x -> start %08x/%08x \n" - "This means that dolphin tries to relaunch the WiiMenu or" - "launches code from the an URL. Both wont work and dolphin will prolly hang...", - TitleID>>32, TitleID, titleid>>32, titleid ); - - Memory::Write_U32(0, _CommandAddress + 0x4); - return true; - } - break; - - case IOCTL_ES_GETVIEWS: - { - _dbg_assert_msg_(WII_IPC_HLE, Buffer.NumberInBuffer == 2, "IOCTL_ES_GETVIEWS no in buffer"); - _dbg_assert_msg_(WII_IPC_HLE, Buffer.NumberPayloadBuffer == 1, "IOCTL_ES_GETVIEWS no out buffer"); - - u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - u32 Count = Memory::Read_U32(Buffer.InBuffer[1].m_Address); - - _dbg_assert_msg_(WII_IPC_HLE, TitleID==0x0000000100000002ull, "IOCTL_ES_GETVIEWS: TitleID != 00000001/00000002"); - - /* write ticket data... hmmm - typedef struct _tikview { - u32 view; - u64 ticketid; - u32 devicetype; - u64 titleid; - u16 access_mask; - u8 reserved[0x3c]; - u8 cidx_mask[0x40]; - u16 padding; - tiklimit limits[8]; - } __attribute__((packed)) tikview; - */ - - Memory::Write_U32(0, Buffer.PayloadBuffer[0].m_Address); - Memory::Write_U64(m_TitleID, Buffer.PayloadBuffer[0].m_Address+4); - Memory::Write_U32(0x00010001, Buffer.PayloadBuffer[0].m_Address+12); - Memory::Write_U64(m_TitleID, Buffer.PayloadBuffer[0].m_Address+16); - Memory::Write_U16(0x777, Buffer.PayloadBuffer[0].m_Address+24); - - Memory::Write_U32(0, _CommandAddress + 0x4); - - _dbg_assert_msg_(WII_IPC_HLE, 0, "IOCTL_ES_GETVIEWS: this looks really wrong..."); - - return true; - } - break; - - case IOCTL_ES_GETSTOREDTMDSIZE: - { - _dbg_assert_msg_(WII_IPC_HLE, 0, "IOCTL_ES_GETSTOREDTMDSIZE: this looks really wrong..."); - -/* u64 TitleId = Memory::Read_U64(Buffer.InBuffer[0].m_Address); - u32 OutBuffer = Memory::Read_U32(Buffer.PayloadBuffer[0].m_Address); - - Memory::Write_U32(0, OutBuffer); - printf("ES_GetStoredTmdSize(%llx)\n", TitleId); - LOG(WII_IPC_ES, "CWII_IPC_HLE_Device_es command:" - " IOCTL_ES_GETSTOREDTMDSIZE: 0x%x", OutBuffer);*/ - } - break; - - case IOCTL_ES_GETTMDVIEWCNT: // 0x14 - _dbg_assert_msg_(WII_IPC_HLE, 0, "IOCTL_ES_GETTMDVIEWCNT: this looks really wrong..."); - break; - - case IOCTL_ES_GETCONSUMPTION: // (Input: 8 bytes, Output: 0 bytes, 4 bytes) - _dbg_assert_msg_(WII_IPC_HLE, 0, "IOCTL_ES_GETCONSUMPTION: this looks really wrong..."); - break; - - case IOCTL_ES_DIGETTICKETVIEW: // (Input: none, Output: 216 bytes) - _dbg_assert_msg_(WII_IPC_HLE, 0, "IOCTL_ES_DIGETTICKETVIEW: this looks really wrong..."); - break; - - - default: - - _dbg_assert_msg_(WII_IPC_HLE, 0, "CWII_IPC_HLE_Device_es: 0x%x", Buffer.Parameter); - - DumpCommands(_CommandAddress, 8); - LOG(WII_IPC_HLE, "CWII_IPC_HLE_Device_es command:" - "Parameter: 0x%08x", Buffer.Parameter); - - break; - } - - // Write return value (0 means OK) - Memory::Write_U32(0, _CommandAddress + 0x4); - - return true; - } - - u64 GetCurrentTitleID() - { - u64 TitleID = 0; - - // check for cd ... - if (VolumeHandler::IsValid()) - { - TitleID = ((u64)0x00010000 << 32) | VolumeHandler::Read32(0); - } - else - { - if (m_TileMetaContent.size() > 0) - { - TitleID = m_TitleID; - } - } - if (TitleID == -1) - TitleID = ((u64)0x00010000 << 32) | 0xF00DBEEF; - - return TitleID; - } + CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName, const std::string& _rDefaultContentFile); + + virtual ~CWII_IPC_HLE_Device_es(); + + virtual bool Open(u32 _CommandAddress, u32 _Mode); + + virtual bool Close(u32 _CommandAddress); + + virtual bool IOCtlV(u32 _CommandAddress); + +private: + + enum + { + IOCTL_ES_ADDTICKET = 0x01, + IOCTL_ES_ADDTITLESTART = 0x02, + IOCTL_ES_ADDCONTENTSTART = 0x03, + IOCTL_ES_ADDCONTENTDATA = 0x04, + IOCTL_ES_ADDCONTENTFINISH = 0x05, + IOCTL_ES_ADDTITLEFINISH = 0x06, + IOCTL_ES_GETDEVICEID = 0x07, + IOCTL_ES_LAUNCH = 0x08, + IOCTL_ES_OPENCONTENT = 0x09, + IOCTL_ES_READCONTENT = 0x0A, + IOCTL_ES_CLOSECONTENT = 0x0B, + IOCTL_ES_GETOWNEDTITLECNT = 0x0C, + IOCTL_ES_GETOWNEDTITLES = 0x0D, + IOCTL_ES_GETTITLECNT = 0x0E, + IOCTL_ES_GETTITLES = 0x0F, + IOCTL_ES_GETTITLECONTENTSCNT = 0x10, + IOCTL_ES_GETTITLECONTENTS = 0x11, + IOCTL_ES_GETVIEWCNT = 0x12, + IOCTL_ES_GETVIEWS = 0x13, + IOCTL_ES_GETTMDVIEWCNT = 0x14, + IOCTL_ES_GETTMDVIEWS = 0x15, + IOCTL_ES_GETCONSUMPTION = 0x16, + IOCTL_ES_DELETETITLE = 0x17, + IOCTL_ES_DELETETICKET = 0x18, + // IOCTL_ES_DIGETTMDVIEWSIZE = 0x19, + // IOCTL_ES_DIGETTMDVIEW = 0x1A, + IOCTL_ES_DIGETTICKETVIEW = 0x1B, + IOCTL_ES_DIVERIFY = 0x1C, + IOCTL_ES_GETTITLEDIR = 0x1D, + IOCTL_ES_GETDEVICECERT = 0x1E, + IOCTL_ES_IMPORTBOOT = 0x1F, + IOCTL_ES_GETTITLEID = 0x20, + IOCTL_ES_SETUID = 0x21, + IOCTL_ES_DELETETITLECONTENT = 0x22, + IOCTL_ES_SEEKCONTENT = 0x23, + IOCTL_ES_OPENTITLECONTENT = 0x24, + // IOCTL_ES_LAUNCHBC = 0x25, + // IOCTL_ES_EXPORTTITLEINIT = 0x26, + // IOCTL_ES_EXPORTCONTENTBEGIN = 0x27, + // IOCTL_ES_EXPORTCONTENTDATA = 0x28, + // IOCTL_ES_EXPORTCONTENTEND = 0x29, + // IOCTL_ES_EXPORTTITLEDONE = 0x2A, + IOCTL_ES_ADDTMD = 0x2B, + IOCTL_ES_ENCRYPT = 0x2C, + IOCTL_ES_DECRYPT = 0x2D, + IOCTL_ES_GETBOOT2VERSION = 0x2E, + IOCTL_ES_ADDTITLECANCEL = 0x2F, + IOCTL_ES_SIGN = 0x30, + // IOCTL_ES_VERIFYSIGN = 0x31, + IOCTL_ES_GETSTOREDCONTENTCNT = 0x32, + IOCTL_ES_GETSTOREDCONTENTS = 0x33, + IOCTL_ES_GETSTOREDTMDSIZE = 0x34, + IOCTL_ES_GETSTOREDTMD = 0x35, + IOCTL_ES_GETSHAREDCONTENTCNT = 0x36, + IOCTL_ES_GETSHAREDCONTENTS = 0x37, + }; + + struct SContentAccess + { + u32 m_Position; + DiscIO::SNANDContent* m_pContent; + }; + + typedef std::map CContenAccessMap; + CContenAccessMap m_ContenAccessMap; + + DiscIO::CNANDContentLoader* m_pContentLoader; + + u64 m_TitleID; + u32 AccessIdentID; + + u64 GetCurrentTitleID() const; + + DiscIO::CNANDContentLoader& AccessContentDevice() const; }; + #endif