IPC ES emulation are two files now
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2456 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
c76c477a6d
commit
ca372ba0f2
|
@ -2119,6 +2119,10 @@
|
|||
RelativePath=".\Src\IPC_HLE\WII_IPC_HLE_Device_Error.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\IPC_HLE\WII_IPC_HLE_Device_es.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\IPC_HLE\WII_IPC_HLE_Device_es.h"
|
||||
>
|
||||
|
|
|
@ -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<u64> TitleIDs;
|
||||
TitleIDs.push_back(0x0000000100000002);
|
||||
// TitleIDs.push_back(0x0001000248414341);
|
||||
// TitleIDs.push_back(0x0001000146414b45);
|
||||
|
||||
for (size_t i=0; i<TitleIDs.size();i++)
|
||||
{
|
||||
Memory::Write_U64(TitleIDs[i], Buffer.PayloadBuffer[0].m_Address + i*8);
|
||||
LOGV(WII_IPC_ES, 0, "IOCTL_ES_GETTITLES: %08x/%08x", TitleIDs[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;
|
||||
}
|
|
@ -15,68 +15,29 @@
|
|||
// 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 <map>
|
||||
#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<u32, SContentAccess> 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:
|
||||
|
||||
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,
|
||||
|
@ -85,23 +46,49 @@ public:
|
|||
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_GETTITLECOUNT = 0x0E,
|
||||
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_DIGETTICKETVIEW = 0x1b,
|
||||
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,
|
||||
|
@ -110,332 +97,23 @@ public:
|
|||
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)
|
||||
struct SContentAccess
|
||||
{
|
||||
Memory::Write_U32(GetDeviceID(), _CommandAddress+4);
|
||||
return true;
|
||||
}
|
||||
u32 m_Position;
|
||||
DiscIO::SNANDContent* m_pContent;
|
||||
};
|
||||
|
||||
virtual bool Close(u32 _CommandAddress)
|
||||
{
|
||||
LOG(WII_IPC_ES, "ES: Close");
|
||||
Memory::Write_U32(0, _CommandAddress + 4);
|
||||
return true;
|
||||
}
|
||||
typedef std::map<u32, SContentAccess> CContenAccessMap;
|
||||
CContenAccessMap m_ContenAccessMap;
|
||||
|
||||
virtual bool IOCtlV(u32 _CommandAddress)
|
||||
{
|
||||
SIOCtlVBuffer Buffer(_CommandAddress);
|
||||
DiscIO::CNANDContentLoader* m_pContentLoader;
|
||||
|
||||
LOG(WII_IPC_ES, "%s (0x%x)", GetDeviceName().c_str(), Buffer.Parameter);
|
||||
u64 m_TitleID;
|
||||
u32 AccessIdentID;
|
||||
|
||||
// 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);
|
||||
}
|
||||
u64 GetCurrentTitleID() const;
|
||||
|
||||
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;
|
||||
}
|
||||
DiscIO::CNANDContentLoader& AccessContentDevice() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue