mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-05-06 03:01:10 -04:00
Yellow squiggly lines begone! Done automatically on .cpp files through `run-clang-tidy`, with manual corrections to the mistakes. If an import is directly used, but is technically unnecessary since it's recursively imported by something else, it is *not* removed. The tool doesn't touch .h files, so I did some of them by hand while fixing errors due to old recursive imports. Not everything is removed, but the cleanup should be substantial enough. Because this done on Linux, code that isn't used on it is mostly untouched. (Hopefully no open PR is depending on these imports...)
302 lines
8.7 KiB
C++
302 lines
8.7 KiB
C++
// Copyright 2019 Dolphin Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include "Core/IOS/DolphinDevice.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
#include "Common/CommonPaths.h"
|
|
#include "Common/FileUtil.h"
|
|
#include "Common/IOFile.h"
|
|
#include "Common/SettingsHandler.h"
|
|
#include "Common/Timer.h"
|
|
#include "Common/Version.h"
|
|
#include "Core/Config/MainSettings.h"
|
|
#include "Core/Config/UISettings.h"
|
|
#include "Core/Core.h"
|
|
#include "Core/HW/Memmap.h"
|
|
#include "Core/Host.h"
|
|
#include "Core/System.h"
|
|
|
|
namespace IOS::HLE
|
|
{
|
|
namespace
|
|
{
|
|
enum
|
|
{
|
|
IOCTL_DOLPHIN_GET_ELAPSED_TIME = 0x01,
|
|
IOCTL_DOLPHIN_GET_VERSION = 0x02,
|
|
IOCTL_DOLPHIN_GET_SPEED_LIMIT = 0x03,
|
|
IOCTL_DOLPHIN_SET_SPEED_LIMIT = 0x04,
|
|
IOCTL_DOLPHIN_GET_CPU_SPEED = 0x05,
|
|
IOCTL_DOLPHIN_GET_REAL_PRODUCTCODE = 0x06,
|
|
IOCTL_DOLPHIN_DISCORD_SET_CLIENT = 0x07,
|
|
IOCTL_DOLPHIN_DISCORD_SET_PRESENCE = 0x08,
|
|
IOCTL_DOLPHIN_DISCORD_RESET = 0x09,
|
|
IOCTL_DOLPHIN_GET_SYSTEM_TIME = 0x0A,
|
|
|
|
};
|
|
|
|
IPCReply GetVersion(Core::System& system, const IOCtlVRequest& request)
|
|
{
|
|
if (!request.HasNumberOfValidVectors(0, 1))
|
|
{
|
|
return IPCReply(IPC_EINVAL);
|
|
}
|
|
|
|
const auto length = std::min(size_t(request.io_vectors[0].size), Common::GetScmDescStr().size());
|
|
|
|
auto& memory = system.GetMemory();
|
|
memory.Memset(request.io_vectors[0].address, 0, request.io_vectors[0].size);
|
|
memory.CopyToEmu(request.io_vectors[0].address, Common::GetScmDescStr().data(), length);
|
|
|
|
return IPCReply(IPC_SUCCESS);
|
|
}
|
|
|
|
IPCReply GetCPUSpeed(Core::System& system, const IOCtlVRequest& request)
|
|
{
|
|
if (!request.HasNumberOfValidVectors(0, 1))
|
|
{
|
|
return IPCReply(IPC_EINVAL);
|
|
}
|
|
|
|
if (request.io_vectors[0].size != 4)
|
|
{
|
|
return IPCReply(IPC_EINVAL);
|
|
}
|
|
|
|
const bool oc = system.GetCoreTiming().GetOverclock();
|
|
const u32 core_clock = u32(float(system.GetSystemTimers().GetTicksPerSecond()) * oc);
|
|
|
|
auto& memory = system.GetMemory();
|
|
memory.Write_U32(core_clock, request.io_vectors[0].address);
|
|
|
|
return IPCReply(IPC_SUCCESS);
|
|
}
|
|
|
|
IPCReply GetSpeedLimit(Core::System& system, const IOCtlVRequest& request)
|
|
{
|
|
// get current speed limit
|
|
if (!request.HasNumberOfValidVectors(0, 1))
|
|
{
|
|
return IPCReply(IPC_EINVAL);
|
|
}
|
|
|
|
if (request.io_vectors[0].size != 4)
|
|
{
|
|
return IPCReply(IPC_EINVAL);
|
|
}
|
|
|
|
const u32 speed_percent = Config::Get(Config::MAIN_EMULATION_SPEED) * 100;
|
|
|
|
auto& memory = system.GetMemory();
|
|
memory.Write_U32(speed_percent, request.io_vectors[0].address);
|
|
|
|
return IPCReply(IPC_SUCCESS);
|
|
}
|
|
|
|
IPCReply SetSpeedLimit(Core::System& system, const IOCtlVRequest& request)
|
|
{
|
|
// set current speed limit
|
|
if (!request.HasNumberOfValidVectors(1, 0))
|
|
{
|
|
return IPCReply(IPC_EINVAL);
|
|
}
|
|
|
|
if (request.in_vectors[0].size != 4)
|
|
{
|
|
return IPCReply(IPC_EINVAL);
|
|
}
|
|
|
|
auto& memory = system.GetMemory();
|
|
const float speed = float(memory.Read_U32(request.in_vectors[0].address)) / 100.0f;
|
|
Config::SetCurrent(Config::MAIN_EMULATION_SPEED, speed);
|
|
|
|
return IPCReply(IPC_SUCCESS);
|
|
}
|
|
|
|
IPCReply GetRealProductCode(Core::System& system, const IOCtlVRequest& request)
|
|
{
|
|
if (!request.HasNumberOfValidVectors(0, 1))
|
|
{
|
|
return IPCReply(IPC_EINVAL);
|
|
}
|
|
|
|
const std::string backup_file_path = File::GetUserPath(D_BACKUP_IDX) + DIR_SEP + WII_SETTING;
|
|
|
|
File::IOFile file(backup_file_path, "rb");
|
|
if (!file)
|
|
return IPCReply(IPC_ENOENT);
|
|
|
|
Common::SettingsBuffer data;
|
|
|
|
if (!file.ReadBytes(data.data(), data.size()))
|
|
return IPCReply(IPC_ENOENT);
|
|
|
|
const Common::SettingsReader settings_reader(data);
|
|
const std::string code = settings_reader.GetValue("CODE");
|
|
|
|
const size_t length = std::min<size_t>(request.io_vectors[0].size, code.length());
|
|
if (length == 0)
|
|
return IPCReply(IPC_ENOENT);
|
|
|
|
auto& memory = system.GetMemory();
|
|
memory.Memset(request.io_vectors[0].address, 0, request.io_vectors[0].size);
|
|
memory.CopyToEmu(request.io_vectors[0].address, code.c_str(), length);
|
|
return IPCReply(IPC_SUCCESS);
|
|
}
|
|
|
|
IPCReply SetDiscordClient(Core::System& system, const IOCtlVRequest& request)
|
|
{
|
|
if (!Config::Get(Config::MAIN_USE_DISCORD_PRESENCE))
|
|
return IPCReply(IPC_EACCES);
|
|
|
|
if (!request.HasNumberOfValidVectors(1, 0))
|
|
return IPCReply(IPC_EINVAL);
|
|
|
|
auto& memory = system.GetMemory();
|
|
std::string new_client_id =
|
|
memory.GetString(request.in_vectors[0].address, request.in_vectors[0].size);
|
|
|
|
Host_UpdateDiscordClientID(new_client_id);
|
|
|
|
return IPCReply(IPC_SUCCESS);
|
|
}
|
|
|
|
IPCReply SetDiscordPresence(Core::System& system, const IOCtlVRequest& request)
|
|
{
|
|
if (!Config::Get(Config::MAIN_USE_DISCORD_PRESENCE))
|
|
return IPCReply(IPC_EACCES);
|
|
|
|
if (!request.HasNumberOfValidVectors(10, 0))
|
|
return IPCReply(IPC_EINVAL);
|
|
|
|
auto& memory = system.GetMemory();
|
|
|
|
std::string details = memory.GetString(request.in_vectors[0].address, request.in_vectors[0].size);
|
|
std::string state = memory.GetString(request.in_vectors[1].address, request.in_vectors[1].size);
|
|
std::string large_image_key =
|
|
memory.GetString(request.in_vectors[2].address, request.in_vectors[2].size);
|
|
std::string large_image_text =
|
|
memory.GetString(request.in_vectors[3].address, request.in_vectors[3].size);
|
|
std::string small_image_key =
|
|
memory.GetString(request.in_vectors[4].address, request.in_vectors[4].size);
|
|
std::string small_image_text =
|
|
memory.GetString(request.in_vectors[5].address, request.in_vectors[5].size);
|
|
|
|
int64_t start_timestamp = memory.Read_U64(request.in_vectors[6].address);
|
|
int64_t end_timestamp = memory.Read_U64(request.in_vectors[7].address);
|
|
int party_size = memory.Read_U32(request.in_vectors[8].address);
|
|
int party_max = memory.Read_U32(request.in_vectors[9].address);
|
|
|
|
bool ret = Host_UpdateDiscordPresenceRaw(details, state, large_image_key, large_image_text,
|
|
small_image_key, small_image_text, start_timestamp,
|
|
end_timestamp, party_size, party_max);
|
|
|
|
if (!ret)
|
|
return IPCReply(IPC_EACCES);
|
|
|
|
return IPCReply(IPC_SUCCESS);
|
|
}
|
|
|
|
IPCReply ResetDiscord(const IOCtlVRequest& request)
|
|
{
|
|
if (!Config::Get(Config::MAIN_USE_DISCORD_PRESENCE))
|
|
return IPCReply(IPC_EACCES);
|
|
|
|
Host_UpdateDiscordClientID();
|
|
|
|
return IPCReply(IPC_SUCCESS);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
IPCReply DolphinDevice::GetElapsedTime(const IOCtlVRequest& request) const
|
|
{
|
|
if (!request.HasNumberOfValidVectors(0, 1))
|
|
{
|
|
return IPCReply(IPC_EINVAL);
|
|
}
|
|
|
|
if (request.io_vectors[0].size != 4)
|
|
{
|
|
return IPCReply(IPC_EINVAL);
|
|
}
|
|
|
|
// This ioctl is used by emulated software to judge if emulation is running too fast or slow.
|
|
// By using Common::Timer, the same clock Dolphin uses internally for the same task is exposed.
|
|
// Return elapsed time instead of current timestamp to make buggy emulated code less likely to
|
|
// have issues.
|
|
const u32 milliseconds = static_cast<u32>(m_timer.ElapsedMs());
|
|
|
|
auto& system = GetSystem();
|
|
auto& memory = system.GetMemory();
|
|
memory.Write_U32(milliseconds, request.io_vectors[0].address);
|
|
|
|
return IPCReply(IPC_SUCCESS);
|
|
}
|
|
|
|
IPCReply DolphinDevice::GetSystemTime(const IOCtlVRequest& request) const
|
|
{
|
|
if (!request.HasNumberOfValidVectors(0, 1))
|
|
{
|
|
return IPCReply(IPC_EINVAL);
|
|
}
|
|
|
|
if (request.io_vectors[0].size != 8)
|
|
{
|
|
return IPCReply(IPC_EINVAL);
|
|
}
|
|
|
|
auto& system = GetSystem();
|
|
auto& memory = system.GetMemory();
|
|
|
|
// Write Unix timestamp in milliseconds to memory address
|
|
const u64 milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
std::chrono::system_clock::now().time_since_epoch())
|
|
.count();
|
|
memory.Write_U64(milliseconds, request.io_vectors[0].address);
|
|
return IPCReply(IPC_SUCCESS);
|
|
}
|
|
|
|
DolphinDevice::DolphinDevice(EmulationKernel& ios, const std::string& device_name)
|
|
: EmulationDevice(ios, device_name)
|
|
{
|
|
m_timer.Start();
|
|
}
|
|
|
|
std::optional<IPCReply> DolphinDevice::IOCtlV(const IOCtlVRequest& request)
|
|
{
|
|
if (Core::WantsDeterminism())
|
|
return IPCReply(IPC_EACCES);
|
|
|
|
switch (request.request)
|
|
{
|
|
case IOCTL_DOLPHIN_GET_ELAPSED_TIME:
|
|
return GetElapsedTime(request);
|
|
case IOCTL_DOLPHIN_GET_VERSION:
|
|
return GetVersion(GetSystem(), request);
|
|
case IOCTL_DOLPHIN_GET_SPEED_LIMIT:
|
|
return GetSpeedLimit(GetSystem(), request);
|
|
case IOCTL_DOLPHIN_SET_SPEED_LIMIT:
|
|
return SetSpeedLimit(GetSystem(), request);
|
|
case IOCTL_DOLPHIN_GET_CPU_SPEED:
|
|
return GetCPUSpeed(GetSystem(), request);
|
|
case IOCTL_DOLPHIN_GET_REAL_PRODUCTCODE:
|
|
return GetRealProductCode(GetSystem(), request);
|
|
case IOCTL_DOLPHIN_DISCORD_SET_CLIENT:
|
|
return SetDiscordClient(GetSystem(), request);
|
|
case IOCTL_DOLPHIN_DISCORD_SET_PRESENCE:
|
|
return SetDiscordPresence(GetSystem(), request);
|
|
case IOCTL_DOLPHIN_DISCORD_RESET:
|
|
return ResetDiscord(request);
|
|
case IOCTL_DOLPHIN_GET_SYSTEM_TIME:
|
|
return GetSystemTime(request);
|
|
|
|
default:
|
|
return IPCReply(IPC_EINVAL);
|
|
}
|
|
}
|
|
} // namespace IOS::HLE
|