Merge pull request #4784 from leoetlino/mios
IOS: Implement MIOS functionality
This commit is contained in:
commit
17e4b450fb
|
@ -37,6 +37,7 @@ public:
|
|||
// Returns true if a map file exists, false if none could be found.
|
||||
static bool FindMapFile(std::string* existing_map_file, std::string* writable_map_file,
|
||||
std::string* title_id = nullptr);
|
||||
static bool LoadMapFromFilename();
|
||||
|
||||
private:
|
||||
static bool DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt);
|
||||
|
@ -44,7 +45,6 @@ private:
|
|||
|
||||
static void UpdateDebugger_MapLoaded();
|
||||
|
||||
static bool LoadMapFromFilename();
|
||||
static bool Boot_ELF(const std::string& filename);
|
||||
static bool Boot_WiiWAD(const std::string& filename);
|
||||
|
||||
|
|
|
@ -278,7 +278,7 @@ bool CBoot::SetupWiiMemory(u64 ios_title_id)
|
|||
Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable
|
||||
Memory::Write_U32(0x00000000, 0x000030f0); // Apploader
|
||||
|
||||
if (!IOS::HLE::SetupMemory(ios_title_id))
|
||||
if (!IOS::HLE::Reload(ios_title_id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ const char* ElfReader::GetSectionName(int section) const
|
|||
}
|
||||
|
||||
// This is just a simple elf loader, good enough to load elfs generated by devkitPPC
|
||||
bool ElfReader::LoadIntoMemory()
|
||||
bool ElfReader::LoadIntoMemory(bool only_in_mem1)
|
||||
{
|
||||
INFO_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx);
|
||||
|
||||
|
@ -133,6 +133,9 @@ bool ElfReader::LoadIntoMemory()
|
|||
u32 srcSize = p->p_filesz;
|
||||
u32 dstSize = p->p_memsz;
|
||||
|
||||
if (only_in_mem1 && p->p_vaddr >= Memory::REALRAM_SIZE)
|
||||
continue;
|
||||
|
||||
Memory::CopyToEmu(writeAddr, src, srcSize);
|
||||
if (srcSize < dstSize)
|
||||
Memory::Memset(writeAddr + srcSize, 0, dstSize - srcSize); // zero out bss
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); }
|
||||
u32 GetEntryPoint() const { return entryPoint; }
|
||||
u32 GetFlags() const { return (u32)(header->e_flags); }
|
||||
bool LoadIntoMemory();
|
||||
bool LoadIntoMemory(bool only_in_mem1 = false);
|
||||
bool LoadSymbols();
|
||||
|
||||
int GetNumSegments() const { return (int)(header->e_phnum); }
|
||||
|
|
|
@ -140,6 +140,7 @@ set(SRCS ActionReplay.cpp
|
|||
IOS/Device.cpp
|
||||
IOS/DeviceStub.cpp
|
||||
IOS/IPC.cpp
|
||||
IOS/MIOS.cpp
|
||||
IOS/DI/DI.cpp
|
||||
IOS/ES/ES.cpp
|
||||
IOS/ES/Formats.cpp
|
||||
|
|
|
@ -188,6 +188,7 @@ struct SConfig : NonCopyable
|
|||
BOOT_ELF,
|
||||
BOOT_DOL,
|
||||
BOOT_WII_NAND,
|
||||
BOOT_MIOS,
|
||||
BOOT_BS2,
|
||||
BOOT_DFF
|
||||
};
|
||||
|
|
|
@ -528,9 +528,11 @@ void EmuThread()
|
|||
Wiimote::LoadConfig();
|
||||
|
||||
// Activate Wiimotes which don't have source set to "None"
|
||||
const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>(
|
||||
IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305"));
|
||||
for (unsigned int i = 0; i != MAX_BBMOTES; ++i)
|
||||
if (g_wiimote_sources[i])
|
||||
IOS::HLE::GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(true);
|
||||
if (g_wiimote_sources[i] && bt)
|
||||
bt->AccessWiiMote(i | 0x100)->Activate(true);
|
||||
}
|
||||
|
||||
AudioCommon::InitSoundStream();
|
||||
|
@ -632,10 +634,6 @@ void EmuThread()
|
|||
|
||||
FileMon::Close();
|
||||
|
||||
// Stop audio thread - Actually this does nothing when using HLE
|
||||
// emulation, but stops the DSP Interpreter when using LLE emulation.
|
||||
DSP::GetDSPEmulator()->DSP_StopSoundStream();
|
||||
|
||||
// We must set up this flag before executing HW::Shutdown()
|
||||
s_hardware_initialized = false;
|
||||
INFO_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str());
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
<ClCompile Include="IOS\Device.cpp" />
|
||||
<ClCompile Include="IOS\DeviceStub.cpp" />
|
||||
<ClCompile Include="IOS\IPC.cpp" />
|
||||
<ClCompile Include="IOS\MIOS.cpp" />
|
||||
<ClCompile Include="IOS\DI\DI.cpp" />
|
||||
<ClCompile Include="IOS\ES\ES.cpp" />
|
||||
<ClCompile Include="IOS\ES\Formats.cpp" />
|
||||
|
@ -408,6 +409,7 @@
|
|||
<ClInclude Include="IOS\Device.h" />
|
||||
<ClInclude Include="IOS\DeviceStub.h" />
|
||||
<ClInclude Include="IOS\IPC.h" />
|
||||
<ClInclude Include="IOS\MIOS.h" />
|
||||
<ClInclude Include="IOS\DI\DI.h" />
|
||||
<ClInclude Include="IOS\ES\ES.h" />
|
||||
<ClInclude Include="IOS\ES\Formats.h" />
|
||||
|
|
|
@ -752,6 +752,9 @@
|
|||
<ClCompile Include="IOS\IPC.cpp">
|
||||
<Filter>IOS</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IOS\MIOS.cpp">
|
||||
<Filter>IOS</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IOS\Network\Net.cpp">
|
||||
<Filter>IOS\Network</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1419,6 +1422,9 @@
|
|||
<ClInclude Include="IOS\IPC.h">
|
||||
<Filter>IOS</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IOS\MIOS.h">
|
||||
<Filter>IOS</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
|
|
|
@ -364,6 +364,16 @@ void LogPendingEvents()
|
|||
}
|
||||
}
|
||||
|
||||
// Should only be called from the CPU thread after the PPC clock has changed
|
||||
void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock)
|
||||
{
|
||||
for (Event& ev : s_event_queue)
|
||||
{
|
||||
const s64 ticks = (ev.time - g_global_timer) * new_ppc_clock / old_ppc_clock;
|
||||
ev.time = g_global_timer + ticks;
|
||||
}
|
||||
}
|
||||
|
||||
void Idle()
|
||||
{
|
||||
if (SConfig::GetInstance().bSyncGPUOnSkipIdleHack)
|
||||
|
|
|
@ -91,6 +91,8 @@ void LogPendingEvents();
|
|||
|
||||
std::string GetScheduledEventsSummary();
|
||||
|
||||
void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock);
|
||||
|
||||
u32 GetFakeDecStartValue();
|
||||
void SetFakeDecStartValue(u32 val);
|
||||
u64 GetFakeDecStartTicks();
|
||||
|
|
|
@ -177,6 +177,13 @@ DSPEmulator* GetDSPEmulator()
|
|||
}
|
||||
|
||||
void Init(bool hle)
|
||||
{
|
||||
Reinit(hle);
|
||||
s_et_GenerateDSPInterrupt = CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt);
|
||||
s_et_CompleteARAM = CoreTiming::RegisterEvent("ARAMint", CompleteARAM);
|
||||
}
|
||||
|
||||
void Reinit(bool hle)
|
||||
{
|
||||
s_dsp_emulator = CreateDSPEmulator(hle);
|
||||
s_dsp_is_lle = s_dsp_emulator->IsLLE();
|
||||
|
@ -206,9 +213,6 @@ void Init(bool hle)
|
|||
s_ARAM_Info.Hex = 0;
|
||||
s_AR_MODE = 1; // ARAM Controller has init'd
|
||||
s_AR_REFRESH = 156; // 156MHz
|
||||
|
||||
s_et_GenerateDSPInterrupt = CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt);
|
||||
s_et_CompleteARAM = CoreTiming::RegisterEvent("ARAMint", CompleteARAM);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
|
|
|
@ -60,6 +60,7 @@ union UDSPControl
|
|||
};
|
||||
|
||||
void Init(bool hle);
|
||||
void Reinit(bool hle);
|
||||
void Shutdown();
|
||||
|
||||
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
|
||||
|
|
|
@ -37,6 +37,12 @@ static bool s_request_disable_thread;
|
|||
|
||||
DSPLLE::DSPLLE() = default;
|
||||
|
||||
DSPLLE::~DSPLLE()
|
||||
{
|
||||
DSPCore_Shutdown();
|
||||
DSP_StopSoundStream();
|
||||
}
|
||||
|
||||
void DSPLLE::DoState(PointerWrap& p)
|
||||
{
|
||||
bool is_hle = false;
|
||||
|
|
|
@ -22,6 +22,7 @@ class DSPLLE : public DSPEmulator
|
|||
{
|
||||
public:
|
||||
DSPLLE();
|
||||
~DSPLLE();
|
||||
|
||||
bool Initialize(bool wii, bool dsp_thread) override;
|
||||
void Shutdown() override;
|
||||
|
|
|
@ -419,8 +419,24 @@ void Init()
|
|||
{
|
||||
DVDThread::Start();
|
||||
|
||||
s_DISR.Hex = 0;
|
||||
Reset();
|
||||
s_DICVR.Hex = 1; // Disc Channel relies on cover being open when no disc is inserted
|
||||
s_disc_inside = false;
|
||||
|
||||
s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback);
|
||||
s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback);
|
||||
|
||||
s_finish_executing_command =
|
||||
CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback);
|
||||
|
||||
u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::INT_TCINT);
|
||||
CoreTiming::ScheduleEvent(0, s_finish_executing_command, userdata);
|
||||
}
|
||||
|
||||
// This doesn't reset any inserted disc or the cover state.
|
||||
void Reset()
|
||||
{
|
||||
s_DISR.Hex = 0;
|
||||
s_DICMDBUF[0].Hex = 0;
|
||||
s_DICMDBUF[1].Hex = 0;
|
||||
s_DICMDBUF[2].Hex = 0;
|
||||
|
@ -441,7 +457,6 @@ void Init()
|
|||
s_pending_samples = 0;
|
||||
|
||||
s_error_code = 0;
|
||||
s_disc_inside = false;
|
||||
|
||||
// The buffer is empty at start
|
||||
s_read_buffer_start_offset = 0;
|
||||
|
@ -450,15 +465,6 @@ void Init()
|
|||
s_read_buffer_end_time = 0;
|
||||
|
||||
s_disc_path_to_insert.clear();
|
||||
|
||||
s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback);
|
||||
s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback);
|
||||
|
||||
s_finish_executing_command =
|
||||
CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback);
|
||||
|
||||
u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::INT_TCINT);
|
||||
CoreTiming::ScheduleEvent(0, s_finish_executing_command, userdata);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
|
|
|
@ -102,6 +102,7 @@ enum class ReplyType : u32
|
|||
};
|
||||
|
||||
void Init();
|
||||
void Reset();
|
||||
void Shutdown();
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
|
|
|
@ -232,7 +232,10 @@ void CEXIIPL::SetCS(int _iCS)
|
|||
|
||||
void CEXIIPL::UpdateRTC()
|
||||
{
|
||||
u32 epoch = SConfig::GetInstance().bWii ? WII_EPOCH : GC_EPOCH;
|
||||
u32 epoch =
|
||||
(SConfig::GetInstance().bWii || SConfig::GetInstance().m_BootType == SConfig::BOOT_MIOS) ?
|
||||
WII_EPOCH :
|
||||
GC_EPOCH;
|
||||
u32 rtc = Common::swap32(GetEmulatedTime(epoch));
|
||||
std::memcpy(m_RTC, &rtc, sizeof(u32));
|
||||
}
|
||||
|
|
|
@ -61,12 +61,11 @@ void Init()
|
|||
|
||||
void Shutdown()
|
||||
{
|
||||
// IOS should always be shut down regardless of bWii because it can be running in GC mode (MIOS).
|
||||
IOS::HLE::Shutdown(); // Depends on Memory
|
||||
IOS::Shutdown();
|
||||
if (SConfig::GetInstance().bWii)
|
||||
{
|
||||
IOS::HLE::Shutdown(); // Depends on Memory
|
||||
IOS::Shutdown();
|
||||
Core::ShutdownWiiRoot();
|
||||
}
|
||||
|
||||
SystemTimers::Shutdown();
|
||||
CPU::Shutdown();
|
||||
|
|
|
@ -223,10 +223,17 @@ static void ThrottleCallback(u64 last_time, s64 cyclesLate)
|
|||
// SystemTimers::Init
|
||||
void PreInit()
|
||||
{
|
||||
if (SConfig::GetInstance().bWii)
|
||||
ChangePPCClock(SConfig::GetInstance().bWii ? Mode::Wii : Mode::GC);
|
||||
}
|
||||
|
||||
void ChangePPCClock(Mode mode)
|
||||
{
|
||||
const u32 previous_clock = s_cpu_core_clock;
|
||||
if (mode == Mode::Wii)
|
||||
s_cpu_core_clock = 729000000u;
|
||||
else
|
||||
s_cpu_core_clock = 486000000u;
|
||||
CoreTiming::AdjustEventQueueTimes(s_cpu_core_clock, previous_clock);
|
||||
}
|
||||
|
||||
void Init()
|
||||
|
|
|
@ -33,10 +33,17 @@ enum
|
|||
TIMER_RATIO = 12
|
||||
};
|
||||
|
||||
enum class Mode
|
||||
{
|
||||
GC,
|
||||
Wii,
|
||||
};
|
||||
|
||||
u32 GetTicksPerSecond();
|
||||
void PreInit();
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void ChangePPCClock(Mode mode);
|
||||
|
||||
// Notify timing system that somebody wrote to the decrementer
|
||||
void DecrementerSet();
|
||||
|
|
|
@ -317,6 +317,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
|
|||
return Decrypt(request);
|
||||
case IOCTL_ES_LAUNCH:
|
||||
return Launch(request);
|
||||
case IOCTL_ES_LAUNCHBC:
|
||||
return LaunchBC(request);
|
||||
case IOCTL_ES_CHECKKOREAREGION:
|
||||
return CheckKoreaRegion(request);
|
||||
case IOCTL_ES_GETDEVICECERT:
|
||||
|
@ -1103,7 +1105,6 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request)
|
|||
{
|
||||
_dbg_assert_(IOS_ES, request.in_vectors.size() == 2);
|
||||
bool bSuccess = false;
|
||||
bool bReset = false;
|
||||
|
||||
u64 TitleID = Memory::Read_U64(request.in_vectors[0].address);
|
||||
u32 view = Memory::Read_U32(request.in_vectors[1].address);
|
||||
|
@ -1112,6 +1113,9 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request)
|
|||
u64 titleid = Memory::Read_U64(request.in_vectors[1].address + 16);
|
||||
u16 access = Memory::Read_U16(request.in_vectors[1].address + 24);
|
||||
|
||||
NOTICE_LOG(IOS_ES, "IOCTL_ES_LAUNCH %016" PRIx64 " %08x %016" PRIx64 " %08x %016" PRIx64 " %04x",
|
||||
TitleID, view, ticketid, devicetype, titleid, access);
|
||||
|
||||
// ES_LAUNCH should probably reset thw whole state, which at least means closing all open files.
|
||||
// leaving them open through ES_LAUNCH may cause hangs and other funky behavior
|
||||
// (supposedly when trying to re-open those files).
|
||||
|
@ -1168,63 +1172,65 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request)
|
|||
}
|
||||
else
|
||||
{
|
||||
bool* wiiMoteConnected = new bool[MAX_BBMOTES];
|
||||
if (!SConfig::GetInstance().m_bt_passthrough_enabled)
|
||||
{
|
||||
BluetoothEmu* s_Usb = GetUsbPointer();
|
||||
for (unsigned int i = 0; i < MAX_BBMOTES; i++)
|
||||
wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected();
|
||||
}
|
||||
|
||||
Reset(true);
|
||||
Reinit();
|
||||
SetupMemory(ios_to_load);
|
||||
bReset = true;
|
||||
|
||||
if (!SConfig::GetInstance().m_bt_passthrough_enabled)
|
||||
{
|
||||
BluetoothEmu* s_Usb = GetUsbPointer();
|
||||
for (unsigned int i = 0; i < MAX_BBMOTES; i++)
|
||||
{
|
||||
if (wiiMoteConnected[i])
|
||||
{
|
||||
s_Usb->m_WiiMotes[i].Activate(false);
|
||||
s_Usb->m_WiiMotes[i].Activate(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
s_Usb->m_WiiMotes[i].Activate(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] wiiMoteConnected;
|
||||
ResetAfterLaunch(ios_to_load);
|
||||
SetDefaultContentFile(tContentFile);
|
||||
}
|
||||
|
||||
// Note: If we just reset the PPC, don't write anything to the command buffer. This
|
||||
// could clobber the DOL we just loaded.
|
||||
|
||||
ERROR_LOG(IOS_ES, "IOCTL_ES_LAUNCH %016" PRIx64 " %08x %016" PRIx64 " %08x %016" PRIx64 " %04x",
|
||||
TitleID, view, ticketid, devicetype, titleid, access);
|
||||
// IOCTL_ES_LAUNCH 0001000248414341 00000001 0001c0fef3df2cfa 00000000
|
||||
// 0001000248414341 ffff
|
||||
|
||||
// This is necessary because Reset(true) above deleted this object. Ew.
|
||||
|
||||
if (!bReset)
|
||||
{
|
||||
// The command type is overwritten with the reply type.
|
||||
Memory::Write_U32(IPC_REPLY, request.address);
|
||||
// IOS also writes back the command that was responded to in the FD field.
|
||||
Memory::Write_U32(IPC_CMD_IOCTLV, request.address + 8);
|
||||
}
|
||||
|
||||
// Generate a "reply" to the IPC command. ES_LAUNCH is unique because it
|
||||
// involves restarting IOS; IOS generates two acknowledgements in a row.
|
||||
// Note: If we just reset the PPC, don't write anything to the command buffer. This
|
||||
// could clobber the DOL we just loaded.
|
||||
EnqueueCommandAcknowledgement(request.address, 0);
|
||||
return GetNoReply();
|
||||
}
|
||||
|
||||
IPCCommandResult ES::LaunchBC(const IOCtlVRequest& request)
|
||||
{
|
||||
if (request.in_vectors.size() != 0 || request.io_vectors.size() != 0)
|
||||
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
|
||||
|
||||
// Here, IOS checks the clock speed and prevents ioctlv 0x25 from being used in GC mode.
|
||||
// An alternative way to do this is to check whether the current active IOS is MIOS.
|
||||
if (GetVersion() == 0x101)
|
||||
return GetDefaultReply(ES_PARAMETER_SIZE_OR_ALIGNMENT);
|
||||
|
||||
ResetAfterLaunch(0x00000001'00000100);
|
||||
EnqueueCommandAcknowledgement(request.address, 0);
|
||||
return GetNoReply();
|
||||
}
|
||||
|
||||
void ES::ResetAfterLaunch(const u64 ios_to_load) const
|
||||
{
|
||||
auto bt = std::static_pointer_cast<BluetoothEmu>(GetDeviceByName("/dev/usb/oh1/57e/305"));
|
||||
bool* wiiMoteConnected = new bool[MAX_BBMOTES];
|
||||
if (!SConfig::GetInstance().m_bt_passthrough_enabled && bt)
|
||||
{
|
||||
for (unsigned int i = 0; i < MAX_BBMOTES; i++)
|
||||
wiiMoteConnected[i] = bt->m_WiiMotes[i].IsConnected();
|
||||
}
|
||||
|
||||
Reload(ios_to_load);
|
||||
|
||||
// Get the new Bluetooth device. Note that it is not guaranteed to exist.
|
||||
bt = std::static_pointer_cast<BluetoothEmu>(GetDeviceByName("/dev/usb/oh1/57e/305"));
|
||||
if (!SConfig::GetInstance().m_bt_passthrough_enabled && bt)
|
||||
{
|
||||
for (unsigned int i = 0; i < MAX_BBMOTES; i++)
|
||||
{
|
||||
if (wiiMoteConnected[i])
|
||||
{
|
||||
bt->m_WiiMotes[i].Activate(false);
|
||||
bt->m_WiiMotes[i].Activate(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
bt->m_WiiMotes[i].Activate(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] wiiMoteConnected;
|
||||
}
|
||||
|
||||
IPCCommandResult ES::CheckKoreaRegion(const IOCtlVRequest& request)
|
||||
{
|
||||
// note by DacoTaco : name is unknown, I just tried to name it SOMETHING.
|
||||
|
|
|
@ -90,7 +90,7 @@ private:
|
|||
IOCTL_ES_DELETETITLECONTENT = 0x22,
|
||||
IOCTL_ES_SEEKCONTENT = 0x23,
|
||||
IOCTL_ES_OPENTITLECONTENT = 0x24,
|
||||
// IOCTL_ES_LAUNCHBC = 0x25,
|
||||
IOCTL_ES_LAUNCHBC = 0x25,
|
||||
// IOCTL_ES_EXPORTTITLEINIT = 0x26,
|
||||
// IOCTL_ES_EXPORTCONTENTBEGIN = 0x27,
|
||||
// IOCTL_ES_EXPORTCONTENTDATA = 0x28,
|
||||
|
@ -182,6 +182,7 @@ private:
|
|||
IPCCommandResult Encrypt(const IOCtlVRequest& request);
|
||||
IPCCommandResult Decrypt(const IOCtlVRequest& request);
|
||||
IPCCommandResult Launch(const IOCtlVRequest& request);
|
||||
IPCCommandResult LaunchBC(const IOCtlVRequest& request);
|
||||
IPCCommandResult CheckKoreaRegion(const IOCtlVRequest& request);
|
||||
IPCCommandResult GetDeviceCertificate(const IOCtlVRequest& request);
|
||||
IPCCommandResult Sign(const IOCtlVRequest& request);
|
||||
|
@ -189,6 +190,8 @@ private:
|
|||
IPCCommandResult DIGetTicketView(const IOCtlVRequest& request);
|
||||
IPCCommandResult GetOwnedTitleCount(const IOCtlVRequest& request);
|
||||
|
||||
void ResetAfterLaunch(u64 ios_to_load) const;
|
||||
|
||||
const DiscIO::CNANDContentLoader& AccessContentDevice(u64 title_id);
|
||||
u32 OpenTitleContent(u32 CFD, u64 TitleID, u16 Index);
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "Core/IOS/FS/FS.h"
|
||||
#include "Core/IOS/FS/FileIO.h"
|
||||
#include "Core/IOS/IPC.h"
|
||||
#include "Core/IOS/MIOS.h"
|
||||
#include "Core/IOS/Network/Net.h"
|
||||
#include "Core/IOS/Network/SSL.h"
|
||||
#include "Core/IOS/Network/Socket.h"
|
||||
|
@ -111,6 +112,7 @@ struct IosMemoryValues
|
|||
u32 ram_vendor;
|
||||
u32 unknown_begin;
|
||||
u32 unknown_end;
|
||||
u32 sysmenu_sync;
|
||||
};
|
||||
|
||||
constexpr u32 ADDR_MEM1_SIZE = 0x3100;
|
||||
|
@ -162,210 +164,210 @@ constexpr std::array<IosMemoryValues, 31> ios_memory_values = {
|
|||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||
},
|
||||
{
|
||||
12, 0xc020e, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||
},
|
||||
{
|
||||
13, 0xd0408, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||
},
|
||||
{
|
||||
14, 0xe0408, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||
},
|
||||
{
|
||||
15, 0xf0408, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||
},
|
||||
{
|
||||
17, 0x110408, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||
},
|
||||
{
|
||||
21, 0x15040f, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||
},
|
||||
{
|
||||
22, 0x16050e, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||
},
|
||||
{
|
||||
28, 0x1c070f, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93800000, MEM2_ARENA_BEGIN,
|
||||
0x937E0000, 0x937E0000, 0x93800000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93800000, 0x93820000,
|
||||
RAM_VENDOR, 0x93800000, 0x93820000, 0,
|
||||
},
|
||||
{
|
||||
31, 0x1f0e18, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
33, 0x210e18, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
34, 0x220e18, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
35, 0x230e18, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
36, 0x240e18, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
37, 0x25161f, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
38, 0x26101c, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
41, 0x290e17, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
43, 0x2b0e17, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
45, 0x2d0e17, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
46, 0x2e0e17, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
48, 0x30101c, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
53, 0x35161f, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
55, 0x37161f, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
56, 0x38161e, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
57, 0x39171f, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
58, 0x3a1820, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
59, 0x3b1c21, 0x101811, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
61, 0x3d161e, 0x030110, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
62, 0x3e191e, 0x022712, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
80, 0x501b20, 0x030310, MEM1_SIZE,
|
||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
||||
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||
},
|
||||
{
|
||||
257,
|
||||
|
@ -387,6 +389,7 @@ constexpr std::array<IosMemoryValues, 31> ios_memory_values = {
|
|||
RAM_VENDOR_MIOS,
|
||||
PLACEHOLDER,
|
||||
PLACEHOLDER,
|
||||
PLACEHOLDER,
|
||||
}}};
|
||||
|
||||
static void EnqueueEvent(u64 userdata, s64 cycles_late = 0)
|
||||
|
@ -421,7 +424,7 @@ u32 GetVersion()
|
|||
return static_cast<u32>(s_active_title_id);
|
||||
}
|
||||
|
||||
bool SetupMemory(u64 ios_title_id)
|
||||
static bool SetupMemory(u64 ios_title_id)
|
||||
{
|
||||
auto target_imv = std::find_if(
|
||||
ios_memory_values.begin(), ios_memory_values.end(),
|
||||
|
@ -433,8 +436,6 @@ bool SetupMemory(u64 ios_title_id)
|
|||
return false;
|
||||
}
|
||||
|
||||
s_active_title_id = ios_title_id;
|
||||
|
||||
Memory::Write_U32(target_imv->mem1_physical_size, ADDR_MEM1_SIZE);
|
||||
Memory::Write_U32(target_imv->mem1_simulated_size, ADDR_MEM1_SIM_SIZE);
|
||||
Memory::Write_U32(target_imv->mem1_end, ADDR_MEM1_END);
|
||||
|
@ -461,7 +462,7 @@ bool SetupMemory(u64 ios_title_id)
|
|||
Memory::Write_U8(0xDE, ADDR_BOOT_FLAG);
|
||||
Memory::Write_U8(0xAD, ADDR_APPLOADER_FLAG);
|
||||
Memory::Write_U16(0xBEEF, ADDR_DEVKIT_BOOT_PROGRAM_VERSION);
|
||||
Memory::Write_U32(0x00000000, ADDR_SYSMENU_SYNC);
|
||||
Memory::Write_U32(target_imv->sysmenu_sync, ADDR_SYSMENU_SYNC);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -477,7 +478,7 @@ std::shared_ptr<T> AddDevice(const char* device_name)
|
|||
return device;
|
||||
}
|
||||
|
||||
void Reinit()
|
||||
static void AddStaticDevices()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_device_map_mutex);
|
||||
_assert_msg_(IOS, s_device_map.empty(), "Reinit called while already initialized");
|
||||
|
@ -519,13 +520,11 @@ void Reinit()
|
|||
|
||||
void Init()
|
||||
{
|
||||
Reinit();
|
||||
|
||||
s_event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent);
|
||||
s_event_sdio_notify = CoreTiming::RegisterEvent("SDIO_EventNotify", SDIO_EventNotify_CPUThread);
|
||||
}
|
||||
|
||||
void Reset(bool hard)
|
||||
void Reset(const bool clear_devices)
|
||||
{
|
||||
CoreTiming::RemoveAllEvents(s_event_enqueue);
|
||||
|
||||
|
@ -538,7 +537,7 @@ void Reset(bool hard)
|
|||
device.reset();
|
||||
}
|
||||
|
||||
if (hard)
|
||||
if (clear_devices)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_device_map_mutex);
|
||||
s_device_map.clear();
|
||||
|
@ -555,6 +554,35 @@ void Shutdown()
|
|||
Reset(true);
|
||||
}
|
||||
|
||||
constexpr u64 BC_TITLE_ID = 0x0000000100000100;
|
||||
constexpr u64 MIOS_TITLE_ID = 0x0000000100000101;
|
||||
|
||||
bool Reload(const u64 ios_title_id)
|
||||
{
|
||||
// A real Wii goes through several steps before getting to MIOS.
|
||||
//
|
||||
// * The System Menu detects a GameCube disc and launches BC (1-100) instead of the game.
|
||||
// * BC (similar to boot1) lowers the clock speed to the Flipper's and then launches boot2.
|
||||
// * boot2 sees the lowered clock speed and launches MIOS (1-101) instead of the System Menu.
|
||||
//
|
||||
// Because we currently don't have boot1 and boot2, and BC is only ever used to launch MIOS
|
||||
// (indirectly via boot2), we can just launch MIOS when BC is launched.
|
||||
if (ios_title_id == BC_TITLE_ID)
|
||||
return Reload(MIOS_TITLE_ID);
|
||||
|
||||
if (!SetupMemory(ios_title_id))
|
||||
return false;
|
||||
|
||||
s_active_title_id = ios_title_id;
|
||||
Reset(true);
|
||||
|
||||
if (ios_title_id == MIOS_TITLE_ID)
|
||||
return MIOS::Load();
|
||||
|
||||
AddStaticDevices();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetDefaultContentFile(const std::string& file_name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_device_map_mutex);
|
||||
|
@ -618,6 +646,10 @@ void DoState(PointerWrap& p)
|
|||
p.Do(s_request_queue);
|
||||
p.Do(s_reply_queue);
|
||||
p.Do(s_last_reply_time);
|
||||
p.Do(s_active_title_id);
|
||||
|
||||
if (s_active_title_id == MIOS_TITLE_ID)
|
||||
return;
|
||||
|
||||
// We need to make sure all file handles are closed so IOS::HLE::Device::FS::DoState can
|
||||
// successfully save or re-create /tmp
|
||||
|
|
|
@ -45,21 +45,16 @@ enum IPCCommandType : u32
|
|||
IPC_REPLY = 8,
|
||||
};
|
||||
|
||||
// Init
|
||||
// Init events and devices
|
||||
void Init();
|
||||
|
||||
// Needs to be called after Reset(true) to recreate the device tree
|
||||
void Reinit();
|
||||
|
||||
u32 GetVersion();
|
||||
|
||||
bool SetupMemory(u64 ios_title_id);
|
||||
|
||||
// Reset all events and devices (and optionally clear them)
|
||||
void Reset(bool clear_devices = false);
|
||||
// Shutdown
|
||||
void Shutdown();
|
||||
|
||||
// Reset
|
||||
void Reset(bool hard = false);
|
||||
// Reload IOS (to a possibly different version); set up memory and devices.
|
||||
bool Reload(u64 ios_title_id);
|
||||
u32 GetVersion();
|
||||
|
||||
// Do State
|
||||
void DoState(PointerWrap& p);
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonFuncs.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/NandPaths.h"
|
||||
#include "Core/Boot/Boot.h"
|
||||
#include "Core/Boot/ElfReader.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/DSPEmulator.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HW/DSP.h"
|
||||
#include "Core/HW/DVDInterface.h"
|
||||
#include "Core/HW/DVDThread.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
#include "Core/IOS/MIOS.h"
|
||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "DiscIO/NANDContentLoader.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
|
||||
namespace IOS
|
||||
{
|
||||
namespace HLE
|
||||
{
|
||||
namespace MIOS
|
||||
{
|
||||
constexpr u64 MIOS_TITLE_ID = 0x0000000100000101;
|
||||
|
||||
// Source: https://wiibrew.org/wiki/ARM_Binaries
|
||||
struct ARMBinary final
|
||||
{
|
||||
explicit ARMBinary(const std::vector<u8>& bytes);
|
||||
explicit ARMBinary(std::vector<u8>&& bytes);
|
||||
|
||||
bool IsValid() const;
|
||||
std::vector<u8> GetElf() const;
|
||||
u32 GetHeaderSize() const;
|
||||
u32 GetElfOffset() const;
|
||||
u32 GetElfSize() const;
|
||||
|
||||
private:
|
||||
std::vector<u8> m_bytes;
|
||||
};
|
||||
|
||||
ARMBinary::ARMBinary(const std::vector<u8>& bytes) : m_bytes(bytes)
|
||||
{
|
||||
}
|
||||
|
||||
ARMBinary::ARMBinary(std::vector<u8>&& bytes) : m_bytes(std::move(bytes))
|
||||
{
|
||||
}
|
||||
|
||||
bool ARMBinary::IsValid() const
|
||||
{
|
||||
// The header is at least 0x10.
|
||||
if (m_bytes.size() < 0x10)
|
||||
return false;
|
||||
return m_bytes.size() >= (GetHeaderSize() + GetElfOffset() + GetElfSize());
|
||||
}
|
||||
|
||||
std::vector<u8> ARMBinary::GetElf() const
|
||||
{
|
||||
const auto iterator = m_bytes.cbegin() + GetHeaderSize() + GetElfOffset();
|
||||
return std::vector<u8>(iterator, iterator + GetElfSize());
|
||||
}
|
||||
|
||||
u32 ARMBinary::GetHeaderSize() const
|
||||
{
|
||||
return Common::swap32(m_bytes.data());
|
||||
}
|
||||
|
||||
u32 ARMBinary::GetElfOffset() const
|
||||
{
|
||||
return Common::swap32(m_bytes.data() + 0x4);
|
||||
}
|
||||
|
||||
u32 ARMBinary::GetElfSize() const
|
||||
{
|
||||
return Common::swap32(m_bytes.data() + 0x8);
|
||||
}
|
||||
|
||||
static std::vector<u8> GetMIOSBinary()
|
||||
{
|
||||
const auto& loader =
|
||||
DiscIO::CNANDContentManager::Access().GetNANDLoader(MIOS_TITLE_ID, Common::FROM_SESSION_ROOT);
|
||||
if (!loader.IsValid())
|
||||
return {};
|
||||
|
||||
const auto* content = loader.GetContentByIndex(loader.GetBootIndex());
|
||||
if (!content)
|
||||
return {};
|
||||
|
||||
return content->m_Data->Get();
|
||||
}
|
||||
|
||||
static void ReinitHardware()
|
||||
{
|
||||
SConfig::GetInstance().bWii = false;
|
||||
|
||||
// IOS clears mem2 and overwrites it with pseudo-random data (for security).
|
||||
std::memset(Memory::m_pEXRAM, 0, Memory::EXRAM_SIZE);
|
||||
// MIOS appears to only reset the DI and the PPC.
|
||||
DVDInterface::Reset();
|
||||
PowerPC::Reset();
|
||||
// Note: this is specific to Dolphin and is required because we initialised it in Wii mode.
|
||||
DSP::Reinit(SConfig::GetInstance().bDSPHLE);
|
||||
DSP::GetDSPEmulator()->Initialize(SConfig::GetInstance().bWii, SConfig::GetInstance().bDSPThread);
|
||||
|
||||
SystemTimers::ChangePPCClock(SystemTimers::Mode::GC);
|
||||
}
|
||||
|
||||
static void UpdateRunningGame()
|
||||
{
|
||||
DVDThread::WaitUntilIdle();
|
||||
const DiscIO::IVolume& volume = DVDInterface::GetVolume();
|
||||
SConfig::GetInstance().m_BootType = SConfig::BOOT_MIOS;
|
||||
SConfig::GetInstance().m_strName = volume.GetInternalName();
|
||||
SConfig::GetInstance().m_strGameID = volume.GetGameID();
|
||||
SConfig::GetInstance().m_revision = volume.GetRevision();
|
||||
|
||||
g_symbolDB.Clear();
|
||||
CBoot::LoadMapFromFilename();
|
||||
::HLE::Clear();
|
||||
::HLE::PatchFunctions();
|
||||
|
||||
NOTICE_LOG(IOS, "Running game: %s (%s)", SConfig::GetInstance().m_strName.c_str(),
|
||||
SConfig::GetInstance().m_strGameID.c_str());
|
||||
}
|
||||
|
||||
constexpr u32 ADDRESS_INIT_SEMAPHORE = 0x30f8;
|
||||
|
||||
bool Load()
|
||||
{
|
||||
Memory::Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE);
|
||||
Memory::Write_U32(0x09142001, 0x3180);
|
||||
|
||||
ARMBinary mios{GetMIOSBinary()};
|
||||
if (!mios.IsValid())
|
||||
{
|
||||
PanicAlertT("Failed to load MIOS. It is required for launching GameCube titles from Wii mode.");
|
||||
Core::QueueHostJob(Core::Stop);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<u8> elf_bytes = mios.GetElf();
|
||||
ElfReader elf{elf_bytes.data()};
|
||||
if (!elf.LoadIntoMemory(true))
|
||||
{
|
||||
PanicAlertT("Failed to load MIOS ELF into memory.");
|
||||
Core::QueueHostJob(Core::Stop);
|
||||
return false;
|
||||
}
|
||||
|
||||
ReinitHardware();
|
||||
NOTICE_LOG(IOS, "Reinitialised hardware.");
|
||||
|
||||
// Load symbols for the IPL if they exist.
|
||||
g_symbolDB.Clear();
|
||||
if (g_symbolDB.LoadMap(File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map"))
|
||||
{
|
||||
::HLE::Clear();
|
||||
::HLE::PatchFunctions();
|
||||
}
|
||||
|
||||
const PowerPC::CoreMode core_mode = PowerPC::GetMode();
|
||||
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
|
||||
MSR = 0;
|
||||
PC = 0x3400;
|
||||
NOTICE_LOG(IOS, "Loaded MIOS and bootstrapped PPC.");
|
||||
|
||||
// IOS writes 0 to 0x30f8 before bootstrapping the PPC. Once started, the IPL eventually writes
|
||||
// 0xdeadbeef there, then waits for it to be cleared by IOS before continuing.
|
||||
while (Memory::Read_U32(ADDRESS_INIT_SEMAPHORE) != 0xdeadbeef)
|
||||
PowerPC::SingleStep();
|
||||
PowerPC::SetMode(core_mode);
|
||||
|
||||
Memory::Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE);
|
||||
NOTICE_LOG(IOS, "IPL ready.");
|
||||
UpdateRunningGame();
|
||||
return true;
|
||||
}
|
||||
} // namespace MIOS
|
||||
} // namespace HLE
|
||||
} // namespace IOS
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace IOS
|
||||
{
|
||||
namespace HLE
|
||||
{
|
||||
namespace MIOS
|
||||
{
|
||||
bool Load();
|
||||
} // namespace MIOS
|
||||
} // namespace HLE
|
||||
} // namespace IOS
|
|
@ -50,7 +50,6 @@ BluetoothEmu::BluetoothEmu(u32 device_id, const std::string& device_name)
|
|||
// Activate only first Wii Remote by default
|
||||
|
||||
_conf_pads BT_DINF;
|
||||
SetUsbPointer(this);
|
||||
if (!sysconf.GetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads)))
|
||||
{
|
||||
PanicAlertT("Trying to read from invalid SYSCONF\nWii Remote Bluetooth IDs are not available");
|
||||
|
@ -103,8 +102,8 @@ BluetoothEmu::BluetoothEmu(u32 device_id, const std::string& device_name)
|
|||
|
||||
BluetoothEmu::~BluetoothEmu()
|
||||
{
|
||||
Host_SetWiiMoteConnectionState(0);
|
||||
m_WiiMotes.clear();
|
||||
SetUsbPointer(nullptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -25,18 +25,6 @@ namespace IOS
|
|||
{
|
||||
namespace HLE
|
||||
{
|
||||
static Device::BluetoothEmu* s_Usb = nullptr;
|
||||
|
||||
Device::BluetoothEmu* GetUsbPointer()
|
||||
{
|
||||
return s_Usb;
|
||||
}
|
||||
|
||||
void SetUsbPointer(Device::BluetoothEmu* ptr)
|
||||
{
|
||||
s_Usb = ptr;
|
||||
}
|
||||
|
||||
WiimoteDevice::WiimoteDevice(Device::BluetoothEmu* host, int number, bdaddr_t bd, bool ready)
|
||||
: m_BD(bd),
|
||||
m_Name(number == WIIMOTE_BALANCE_BOARD ? "Nintendo RVL-WBC-01" : "Nintendo RVL-CNT-01"),
|
||||
|
@ -943,6 +931,9 @@ void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _
|
|||
DEBUG_LOG(WIIMOTE, " Data: %s", ArrayToString(pData, _Size, 50).c_str());
|
||||
DEBUG_LOG(WIIMOTE, " Channel: %x", _channelID);
|
||||
|
||||
IOS::HLE::s_Usb->m_WiiMotes[_number].ReceiveL2capData(_channelID, _pData, _Size);
|
||||
const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>(
|
||||
IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305"));
|
||||
if (bt)
|
||||
bt->m_WiiMotes[_number].ReceiveL2capData(_channelID, _pData, _Size);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,9 +23,6 @@ namespace Device
|
|||
class BluetoothEmu;
|
||||
}
|
||||
|
||||
Device::BluetoothEmu* GetUsbPointer();
|
||||
void SetUsbPointer(Device::BluetoothEmu* ptr);
|
||||
|
||||
class CBigEndianBuffer
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -521,11 +521,13 @@ void ChangeWiiPads(bool instantly)
|
|||
if (instantly && (s_controllers >> 4) == controllers)
|
||||
return;
|
||||
|
||||
const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>(
|
||||
IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305"));
|
||||
for (int i = 0; i < MAX_WIIMOTES; ++i)
|
||||
{
|
||||
g_wiimote_sources[i] = IsUsingWiimote(i) ? WIIMOTE_SRC_EMU : WIIMOTE_SRC_NONE;
|
||||
if (!SConfig::GetInstance().m_bt_passthrough_enabled)
|
||||
IOS::HLE::GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(IsUsingWiimote(i));
|
||||
if (!SConfig::GetInstance().m_bt_passthrough_enabled && bt)
|
||||
bt->AccessWiiMote(i | 0x100)->Activate(IsUsingWiimote(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -189,11 +189,7 @@ void Init(int cpu_core)
|
|||
s_invalidate_cache_thread_safe =
|
||||
CoreTiming::RegisterEvent("invalidateEmulatedCache", InvalidateCacheThreadSafe);
|
||||
|
||||
ppcState.pagetable_base = 0;
|
||||
ppcState.pagetable_hashmask = 0;
|
||||
ppcState.tlb = {};
|
||||
|
||||
ResetRegisters();
|
||||
Reset();
|
||||
|
||||
InitializeCPUCore(cpu_core);
|
||||
ppcState.iCache.Init();
|
||||
|
@ -202,6 +198,16 @@ void Init(int cpu_core)
|
|||
breakpoints.ClearAllTemporary();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
ppcState.pagetable_base = 0;
|
||||
ppcState.pagetable_hashmask = 0;
|
||||
ppcState.tlb = {};
|
||||
|
||||
ResetRegisters();
|
||||
ppcState.iCache.Reset();
|
||||
}
|
||||
|
||||
void ScheduleInvalidateCacheThreadSafe(u32 address)
|
||||
{
|
||||
if (CPU::GetState() == CPU::State::CPU_RUNNING)
|
||||
|
|
|
@ -136,6 +136,7 @@ extern MemChecks memchecks;
|
|||
extern PPCDebugInterface debug_interface;
|
||||
|
||||
void Init(int cpu_core);
|
||||
void Reset();
|
||||
void Shutdown();
|
||||
void DoState(PointerWrap& p);
|
||||
void ScheduleInvalidateCacheThreadSafe(u32 address);
|
||||
|
|
|
@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
|
|||
static std::thread g_save_thread;
|
||||
|
||||
// Don't forget to increase this after doing changes on the savestate system
|
||||
static const u32 STATE_VERSION = 76; // Last changed in PR 4829
|
||||
static const u32 STATE_VERSION = 77; // Last changed in PR 4784
|
||||
|
||||
// Maps savestate versions to Dolphin versions.
|
||||
// Versions after 42 don't need to be added to this list,
|
||||
|
@ -156,6 +156,19 @@ static std::string DoState(PointerWrap& p)
|
|||
return version_created_by;
|
||||
}
|
||||
|
||||
bool is_wii =
|
||||
SConfig::GetInstance().bWii || SConfig::GetInstance().m_BootType == SConfig::BOOT_MIOS;
|
||||
const bool is_wii_currently = is_wii;
|
||||
p.Do(is_wii);
|
||||
if (is_wii != is_wii_currently)
|
||||
{
|
||||
OSD::AddMessage(StringFromFormat("Cannot load a savestate created under %s mode in %s mode",
|
||||
is_wii ? "Wii" : "GC", is_wii_currently ? "Wii" : "GC"),
|
||||
OSD::Duration::NORMAL, OSD::Color::RED);
|
||||
p.SetMode(PointerWrap::MODE_MEASURE);
|
||||
return version_created_by;
|
||||
}
|
||||
|
||||
// Begin with video backend, so that it gets a chance to clear its caches and writeback modified
|
||||
// things to RAM
|
||||
g_video_backend->DoState(p);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
#include "DolphinWX/DolphinSlider.h"
|
||||
#include "DolphinWX/WxEventUtils.h"
|
||||
|
||||
|
@ -181,12 +182,12 @@ void AdvancedConfigPane::OnCustomRTCTimeChanged(wxCommandEvent& event)
|
|||
|
||||
void AdvancedConfigPane::UpdateCPUClock()
|
||||
{
|
||||
bool wii = SConfig::GetInstance().bWii;
|
||||
int percent = (int)(std::roundf(SConfig::GetInstance().m_OCFactor * 100.f));
|
||||
int clock = (int)(std::roundf(SConfig::GetInstance().m_OCFactor * (wii ? 729.f : 486.f)));
|
||||
int core_clock = SystemTimers::GetTicksPerSecond() / pow(10, 6);
|
||||
int percent = static_cast<int>(std::round(SConfig::GetInstance().m_OCFactor * 100.f));
|
||||
int clock = static_cast<int>(std::round(SConfig::GetInstance().m_OCFactor * core_clock));
|
||||
|
||||
m_clock_override_text->SetLabel(
|
||||
SConfig::GetInstance().m_OCEnable ? wxString::Format("%d %% (%d mhz)", percent, clock) : "");
|
||||
SConfig::GetInstance().m_OCEnable ? wxString::Format("%d %% (%d MHz)", percent, clock) : "");
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::LoadCustomRTC()
|
||||
|
|
|
@ -1245,7 +1245,10 @@ void CFrame::ConnectWiimote(int wm_idx, bool connect)
|
|||
!SConfig::GetInstance().m_bt_passthrough_enabled)
|
||||
{
|
||||
bool was_unpaused = Core::PauseAndLock(true);
|
||||
IOS::HLE::GetUsbPointer()->AccessWiiMote(wm_idx | 0x100)->Activate(connect);
|
||||
const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>(
|
||||
IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305"));
|
||||
if (bt)
|
||||
bt->AccessWiiMote(wm_idx | 0x100)->Activate(connect);
|
||||
const char* message = connect ? "Wii Remote %i connected" : "Wii Remote %i disconnected";
|
||||
Core::DisplayMessage(StringFromFormat(message, wm_idx + 1), 3000);
|
||||
Host_UpdateMainFrame();
|
||||
|
@ -1258,10 +1261,11 @@ void CFrame::OnConnectWiimote(wxCommandEvent& event)
|
|||
if (SConfig::GetInstance().m_bt_passthrough_enabled)
|
||||
return;
|
||||
bool was_unpaused = Core::PauseAndLock(true);
|
||||
ConnectWiimote(event.GetId() - IDM_CONNECT_WIIMOTE1,
|
||||
!IOS::HLE::GetUsbPointer()
|
||||
->AccessWiiMote((event.GetId() - IDM_CONNECT_WIIMOTE1) | 0x100)
|
||||
->IsConnected());
|
||||
const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>(
|
||||
IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305"));
|
||||
const bool is_connected =
|
||||
bt && bt->AccessWiiMote((event.GetId() - IDM_CONNECT_WIIMOTE1) | 0x100)->IsConnected();
|
||||
ConnectWiimote(event.GetId() - IDM_CONNECT_WIIMOTE1, !is_connected);
|
||||
Core::PauseAndLock(false, was_unpaused);
|
||||
}
|
||||
|
||||
|
@ -1416,8 +1420,9 @@ void CFrame::UpdateGUI()
|
|||
// Tools
|
||||
GetMenuBar()->FindItem(IDM_CHEATS)->Enable(SConfig::GetInstance().bEnableCheats);
|
||||
|
||||
bool ShouldEnableWiimotes =
|
||||
Running && SConfig::GetInstance().bWii && !SConfig::GetInstance().m_bt_passthrough_enabled;
|
||||
const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>(
|
||||
IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305"));
|
||||
bool ShouldEnableWiimotes = Running && bt && !SConfig::GetInstance().m_bt_passthrough_enabled;
|
||||
GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Enable(ShouldEnableWiimotes);
|
||||
GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Enable(ShouldEnableWiimotes);
|
||||
GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Enable(ShouldEnableWiimotes);
|
||||
|
@ -1426,21 +1431,13 @@ void CFrame::UpdateGUI()
|
|||
if (ShouldEnableWiimotes)
|
||||
{
|
||||
bool was_unpaused = Core::PauseAndLock(true);
|
||||
GetMenuBar()
|
||||
->FindItem(IDM_CONNECT_WIIMOTE1)
|
||||
->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0100)->IsConnected());
|
||||
GetMenuBar()
|
||||
->FindItem(IDM_CONNECT_WIIMOTE2)
|
||||
->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0101)->IsConnected());
|
||||
GetMenuBar()
|
||||
->FindItem(IDM_CONNECT_WIIMOTE3)
|
||||
->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0102)->IsConnected());
|
||||
GetMenuBar()
|
||||
->FindItem(IDM_CONNECT_WIIMOTE4)
|
||||
->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0103)->IsConnected());
|
||||
GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Check(bt->AccessWiiMote(0x0100)->IsConnected());
|
||||
GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Check(bt->AccessWiiMote(0x0101)->IsConnected());
|
||||
GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Check(bt->AccessWiiMote(0x0102)->IsConnected());
|
||||
GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE4)->Check(bt->AccessWiiMote(0x0103)->IsConnected());
|
||||
GetMenuBar()
|
||||
->FindItem(IDM_CONNECT_BALANCEBOARD)
|
||||
->Check(IOS::HLE::GetUsbPointer()->AccessWiiMote(0x0104)->IsConnected());
|
||||
->Check(bt->AccessWiiMote(0x0104)->IsConnected());
|
||||
Core::PauseAndLock(false, was_unpaused);
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,10 @@ void Host_ConnectWiimote(int wm_idx, bool connect)
|
|||
{
|
||||
Core::QueueHostJob([=] {
|
||||
bool was_unpaused = Core::PauseAndLock(true);
|
||||
IOS::HLE::GetUsbPointer()->AccessWiiMote(wm_idx | 0x100)->Activate(connect);
|
||||
const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>(
|
||||
IOS::HLE::GetDeviceByName("/dev/usb/oh1/57e/305"));
|
||||
if (bt)
|
||||
bt->AccessWiiMote(wm_idx | 0x100)->Activate(connect);
|
||||
Host_UpdateMainFrame();
|
||||
Core::PauseAndLock(false, was_unpaused);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue