early-access version 4053
This commit is contained in:
@@ -76,7 +76,7 @@ struct UiSettingsDisplayOptions {
|
||||
bool is_system_or_launcher;
|
||||
bool is_registration_permitted;
|
||||
bool show_skip_button;
|
||||
bool aditional_select;
|
||||
bool additional_select;
|
||||
bool show_user_selector;
|
||||
bool is_unqualified_user_selectable;
|
||||
};
|
||||
|
||||
@@ -10,8 +10,11 @@
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/caps/caps_manager.h"
|
||||
#include "core/hle/service/caps/caps_result.h"
|
||||
#include "core/hle/service/time/time_manager.h"
|
||||
#include "core/hle/service/time/time_zone_content_manager.h"
|
||||
#include "core/hle/service/psc/time/static.h"
|
||||
#include "core/hle/service/psc/time/system_clock.h"
|
||||
#include "core/hle/service/psc/time/time_zone_service.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::Capture {
|
||||
|
||||
@@ -85,7 +88,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, Albu
|
||||
}
|
||||
|
||||
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
|
||||
ContentType contex_type, s64 start_posix_time,
|
||||
ContentType content_type, s64 start_posix_time,
|
||||
s64 end_posix_time, u64 aruid) const {
|
||||
if (!is_mounted) {
|
||||
return ResultIsNotMounted;
|
||||
@@ -94,7 +97,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou
|
||||
std::vector<ApplicationAlbumEntry> album_entries;
|
||||
const auto start_date = ConvertToAlbumDateTime(start_posix_time);
|
||||
const auto end_date = ConvertToAlbumDateTime(end_posix_time);
|
||||
const auto result = GetAlbumFileList(album_entries, contex_type, start_date, end_date, aruid);
|
||||
const auto result = GetAlbumFileList(album_entries, content_type, start_date, end_date, aruid);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
@@ -113,14 +116,14 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou
|
||||
}
|
||||
|
||||
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
|
||||
ContentType contex_type, AlbumFileDateTime start_date,
|
||||
ContentType content_type, AlbumFileDateTime start_date,
|
||||
AlbumFileDateTime end_date, u64 aruid) const {
|
||||
if (!is_mounted) {
|
||||
return ResultIsNotMounted;
|
||||
}
|
||||
|
||||
for (auto& [file_id, path] : album_files) {
|
||||
if (file_id.type != contex_type) {
|
||||
if (file_id.type != content_type) {
|
||||
continue;
|
||||
}
|
||||
if (file_id.date > start_date) {
|
||||
@@ -139,7 +142,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_en
|
||||
.hash{},
|
||||
.datetime = file_id.date,
|
||||
.storage = file_id.storage,
|
||||
.content = contex_type,
|
||||
.content = content_type,
|
||||
.unknown = 1,
|
||||
};
|
||||
out_entries.push_back(entry);
|
||||
@@ -239,10 +242,15 @@ Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
|
||||
const ApplicationData& app_data, std::span<const u8> image_data,
|
||||
u64 aruid) {
|
||||
const u64 title_id = system.GetApplicationProcessProgramID();
|
||||
const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore();
|
||||
|
||||
auto static_service =
|
||||
system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u", true);
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{};
|
||||
static_service->GetStandardUserSystemClock(user_clock);
|
||||
|
||||
s64 posix_time{};
|
||||
Result result = user_clock.GetCurrentTime(system, posix_time);
|
||||
auto result = user_clock->GetCurrentTime(posix_time);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
@@ -257,10 +265,14 @@ Result AlbumManager::SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
|
||||
const ScreenShotAttribute& attribute,
|
||||
const AlbumFileId& file_id,
|
||||
std::span<const u8> image_data) {
|
||||
const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore();
|
||||
auto static_service =
|
||||
system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u", true);
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{};
|
||||
static_service->GetStandardUserSystemClock(user_clock);
|
||||
|
||||
s64 posix_time{};
|
||||
Result result = user_clock.GetCurrentTime(system, posix_time);
|
||||
auto result = user_clock->GetCurrentTime(posix_time);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
@@ -455,19 +467,23 @@ Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const
|
||||
}
|
||||
|
||||
AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const {
|
||||
Time::TimeZone::CalendarInfo calendar_date{};
|
||||
const auto& time_zone_manager =
|
||||
system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
|
||||
auto static_service =
|
||||
system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u", true);
|
||||
|
||||
time_zone_manager.ToCalendarTimeWithMyRules(posix_time, calendar_date);
|
||||
std::shared_ptr<Service::PSC::Time::TimeZoneService> timezone_service{};
|
||||
static_service->GetTimeZoneService(timezone_service);
|
||||
|
||||
Service::PSC::Time::CalendarTime calendar_time{};
|
||||
Service::PSC::Time::CalendarAdditionalInfo additional_info{};
|
||||
timezone_service->ToCalendarTimeWithMyRule(calendar_time, additional_info, posix_time);
|
||||
|
||||
return {
|
||||
.year = calendar_date.time.year,
|
||||
.month = calendar_date.time.month,
|
||||
.day = calendar_date.time.day,
|
||||
.hour = calendar_date.time.hour,
|
||||
.minute = calendar_date.time.minute,
|
||||
.second = calendar_date.time.second,
|
||||
.year = calendar_time.year,
|
||||
.month = calendar_time.month,
|
||||
.day = calendar_time.day,
|
||||
.hour = calendar_time.hour,
|
||||
.minute = calendar_time.minute,
|
||||
.second = calendar_time.second,
|
||||
.unique_id = 0,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -45,10 +45,10 @@ public:
|
||||
Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
|
||||
u8 flags) const;
|
||||
Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
|
||||
ContentType contex_type, s64 start_posix_time, s64 end_posix_time,
|
||||
ContentType content_type, s64 start_posix_time, s64 end_posix_time,
|
||||
u64 aruid) const;
|
||||
Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
|
||||
ContentType contex_type, AlbumFileDateTime start_date,
|
||||
ContentType content_type, AlbumFileDateTime start_date,
|
||||
AlbumFileDateTime end_date, u64 aruid) const;
|
||||
Result GetAutoSavingStorage(bool& out_is_autosaving) const;
|
||||
Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
|
||||
|
||||
@@ -12,7 +12,7 @@ constexpr Result ResultUnknown5(ErrorModule::Capture, 5);
|
||||
constexpr Result ResultUnknown6(ErrorModule::Capture, 6);
|
||||
constexpr Result ResultUnknown7(ErrorModule::Capture, 7);
|
||||
constexpr Result ResultOutOfRange(ErrorModule::Capture, 8);
|
||||
constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12);
|
||||
constexpr Result ResultInvalidTimestamp(ErrorModule::Capture, 12);
|
||||
constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13);
|
||||
constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14);
|
||||
constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21);
|
||||
|
||||
@@ -131,7 +131,7 @@ private:
|
||||
u8 is_favorite;
|
||||
u8 same_app;
|
||||
u8 same_app_played;
|
||||
u8 arbitary_app_played;
|
||||
u8 arbitrary_app_played;
|
||||
u64 group_id;
|
||||
};
|
||||
static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size");
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#include "core/hle/service/glue/ectx.h"
|
||||
#include "core/hle/service/glue/glue.h"
|
||||
#include "core/hle/service/glue/notif.h"
|
||||
#include "core/hle/service/glue/time/manager.h"
|
||||
#include "core/hle/service/glue/time/static.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
|
||||
namespace Service::Glue {
|
||||
@@ -31,6 +34,22 @@ void LoopProcess(Core::System& system) {
|
||||
// Notification Services for application
|
||||
server_manager->RegisterNamedService("notif:a", std::make_shared<NOTIF_A>(system));
|
||||
|
||||
// Time
|
||||
auto time = std::make_shared<Time::TimeManager>(system);
|
||||
|
||||
server_manager->RegisterNamedService(
|
||||
"time:u",
|
||||
std::make_shared<Time::StaticService>(
|
||||
system, Service::PSC::Time::StaticServiceSetupInfo{0, 0, 0, 0, 0, 0}, time, "time:u"));
|
||||
server_manager->RegisterNamedService(
|
||||
"time:a",
|
||||
std::make_shared<Time::StaticService>(
|
||||
system, Service::PSC::Time::StaticServiceSetupInfo{1, 1, 0, 1, 0, 0}, time, "time:a"));
|
||||
server_manager->RegisterNamedService(
|
||||
"time:r",
|
||||
std::make_shared<Time::StaticService>(
|
||||
system, Service::PSC::Time::StaticServiceSetupInfo{0, 0, 0, 0, 1, 0}, time, "time:r"));
|
||||
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
|
||||
|
||||
82
src/core/hle/service/glue/time/alarm_worker.cpp
Executable file
82
src/core/hle/service/glue/time/alarm_worker.cpp
Executable file
@@ -0,0 +1,82 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/hle/service/glue/time/alarm_worker.h"
|
||||
#include "core/hle/service/psc/time/service_manager.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
|
||||
AlarmWorker::AlarmWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource)
|
||||
: m_system{system}, m_ctx{system, "Glue:AlarmWorker"}, m_steady_clock_resource{
|
||||
steady_clock_resource} {}
|
||||
|
||||
AlarmWorker::~AlarmWorker() {
|
||||
m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event);
|
||||
|
||||
m_ctx.CloseEvent(m_timer_event);
|
||||
}
|
||||
|
||||
void AlarmWorker::Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m) {
|
||||
m_time_m = std::move(time_m);
|
||||
|
||||
m_timer_event = m_ctx.CreateEvent("Glue:AlarmWorker:TimerEvent");
|
||||
m_timer_timing_event = Core::Timing::CreateEvent(
|
||||
"Glue:AlarmWorker::AlarmTimer",
|
||||
[this](s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
m_timer_event->Signal();
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
AttachToClosestAlarmEvent();
|
||||
}
|
||||
|
||||
bool AlarmWorker::GetClosestAlarmInfo(Service::PSC::Time::AlarmInfo& out_alarm_info,
|
||||
s64& out_time) {
|
||||
bool is_valid{};
|
||||
Service::PSC::Time::AlarmInfo alarm_info{};
|
||||
s64 closest_time{};
|
||||
|
||||
auto res = m_time_m->GetClosestAlarmInfo(is_valid, alarm_info, closest_time);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
if (is_valid) {
|
||||
out_alarm_info = alarm_info;
|
||||
out_time = closest_time;
|
||||
}
|
||||
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
void AlarmWorker::OnPowerStateChanged() {
|
||||
Service::PSC::Time::AlarmInfo closest_alarm_info{};
|
||||
s64 closest_time{};
|
||||
if (!GetClosestAlarmInfo(closest_alarm_info, closest_time)) {
|
||||
m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event);
|
||||
m_timer_event->Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (closest_alarm_info.alert_time <= closest_time) {
|
||||
m_time_m->CheckAndSignalAlarms();
|
||||
} else {
|
||||
auto next_time{closest_alarm_info.alert_time - closest_time};
|
||||
|
||||
m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event);
|
||||
m_timer_event->Clear();
|
||||
|
||||
m_system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds(next_time),
|
||||
m_timer_timing_event);
|
||||
}
|
||||
}
|
||||
|
||||
Result AlarmWorker::AttachToClosestAlarmEvent() {
|
||||
m_time_m->GetClosestAlarmUpdatedEvent(&m_event);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
53
src/core/hle/service/glue/time/alarm_worker.h
Executable file
53
src/core/hle/service/glue/time/alarm_worker.h
Executable file
@@ -0,0 +1,53 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
class ServiceManager;
|
||||
}
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
class StandardSteadyClockResource;
|
||||
|
||||
class AlarmWorker {
|
||||
public:
|
||||
explicit AlarmWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource);
|
||||
~AlarmWorker();
|
||||
|
||||
void Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m);
|
||||
|
||||
Kernel::KEvent& GetEvent() {
|
||||
return *m_event;
|
||||
}
|
||||
|
||||
Kernel::KEvent& GetTimerEvent() {
|
||||
return *m_timer_event;
|
||||
}
|
||||
|
||||
void OnPowerStateChanged();
|
||||
|
||||
private:
|
||||
bool GetClosestAlarmInfo(Service::PSC::Time::AlarmInfo& out_alarm_info, s64& out_time);
|
||||
Result AttachToClosestAlarmEvent();
|
||||
|
||||
Core::System& m_system;
|
||||
KernelHelpers::ServiceContext m_ctx;
|
||||
std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m;
|
||||
|
||||
Kernel::KEvent* m_event{};
|
||||
Kernel::KEvent* m_timer_event{};
|
||||
std::shared_ptr<Core::Timing::EventType> m_timer_timing_event;
|
||||
StandardSteadyClockResource& m_steady_clock_resource;
|
||||
};
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
23
src/core/hle/service/glue/time/file_timestamp_worker.cpp
Executable file
23
src/core/hle/service/glue/time/file_timestamp_worker.cpp
Executable file
@@ -0,0 +1,23 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/glue/time/file_timestamp_worker.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
#include "core/hle/service/psc/time/system_clock.h"
|
||||
#include "core/hle/service/psc/time/time_zone_service.h"
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
|
||||
void FileTimestampWorker::SetFilesystemPosixTime() {
|
||||
s64 time{};
|
||||
Service::PSC::Time::CalendarTime calendar_time{};
|
||||
Service::PSC::Time::CalendarAdditionalInfo additional_info{};
|
||||
|
||||
if (m_initialized && m_system_clock->GetCurrentTime(time) == ResultSuccess &&
|
||||
m_time_zone->ToCalendarTimeWithMyRule(calendar_time, additional_info, time) ==
|
||||
ResultSuccess) {
|
||||
// TODO IFileSystemProxy::SetCurrentPosixTime
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
28
src/core/hle/service/glue/time/file_timestamp_worker.h
Executable file
28
src/core/hle/service/glue/time/file_timestamp_worker.h
Executable file
@@ -0,0 +1,28 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
class SystemClock;
|
||||
class TimeZoneService;
|
||||
} // namespace Service::PSC::Time
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
|
||||
class FileTimestampWorker {
|
||||
public:
|
||||
FileTimestampWorker() = default;
|
||||
|
||||
void SetFilesystemPosixTime();
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock> m_system_clock{};
|
||||
std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone{};
|
||||
bool m_initialized{};
|
||||
};
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
242
src/core/hle/service/glue/time/manager.cpp
Executable file
242
src/core/hle/service/glue/time/manager.cpp
Executable file
@@ -0,0 +1,242 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/hle/service/glue/time/manager.h"
|
||||
#include "core/hle/service/glue/time/time_zone_binary.h"
|
||||
#include "core/hle/service/psc/time/service_manager.h"
|
||||
#include "core/hle/service/psc/time/static.h"
|
||||
#include "core/hle/service/psc/time/system_clock.h"
|
||||
#include "core/hle/service/psc/time/time_zone_service.h"
|
||||
#include "core/hle/service/set/system_settings_server.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys,
|
||||
const char* category, const char* name) {
|
||||
std::vector<u8> interval_buf;
|
||||
auto res = set_sys->GetSettingsItemValue(interval_buf, category, name);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
T v{};
|
||||
std::memcpy(&v, interval_buf.data(), sizeof(T));
|
||||
return v;
|
||||
}
|
||||
|
||||
s64 CalendarTimeToEpoch(Service::PSC::Time::CalendarTime calendar) {
|
||||
constexpr auto is_leap = [](s32 year) -> bool {
|
||||
return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0));
|
||||
};
|
||||
constexpr std::array<s32, 12> MonthStartDayOfYear{
|
||||
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
|
||||
};
|
||||
|
||||
s16 month_s16{calendar.month};
|
||||
s8 month{static_cast<s8>(((month_s16 * 43) & ~std::numeric_limits<s16>::max()) +
|
||||
((month_s16 * 43) >> 9))};
|
||||
s8 month_index{static_cast<s8>(calendar.month - 12 * month)};
|
||||
if (month_index == 0) {
|
||||
month_index = 12;
|
||||
}
|
||||
s32 year{(month + calendar.year) - !month_index};
|
||||
s32 v8{year >= 0 ? year : year + 3};
|
||||
|
||||
s64 days_since_epoch = calendar.day + MonthStartDayOfYear[month_index - 1];
|
||||
days_since_epoch += (year * 365) + (v8 / 4) - (year / 100) + (year / 400) - 365;
|
||||
|
||||
if (month_index <= 2 && is_leap(year)) {
|
||||
days_since_epoch--;
|
||||
}
|
||||
auto epoch_s{((24ll * days_since_epoch + calendar.hour) * 60ll + calendar.minute) * 60ll +
|
||||
calendar.second};
|
||||
return epoch_s - 62135683200ll;
|
||||
}
|
||||
|
||||
s64 GetEpochTimeFromInitialYear(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys) {
|
||||
Service::PSC::Time::CalendarTime calendar{
|
||||
.year = GetSettingsItemValue<s16>(set_sys, "time", "standard_user_clock_initial_year"),
|
||||
.month = 1,
|
||||
.day = 1,
|
||||
.hour = 0,
|
||||
.minute = 0,
|
||||
.second = 0,
|
||||
};
|
||||
return CalendarTimeToEpoch(calendar);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TimeManager::TimeManager(Core::System& system)
|
||||
: m_steady_clock_resource{system}, m_worker{system, m_steady_clock_resource,
|
||||
m_file_timestamp_worker} {
|
||||
m_time_m =
|
||||
system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true);
|
||||
|
||||
auto res = m_time_m->GetStaticServiceAsServiceManager(m_time_sm);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
m_set_sys =
|
||||
system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
|
||||
|
||||
ResetTimeZoneBinary();
|
||||
res = MountTimeZoneBinary(system);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
m_worker.Initialize(m_time_sm, m_set_sys);
|
||||
|
||||
res = m_time_sm->GetStandardUserSystemClock(m_file_timestamp_worker.m_system_clock);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
res = m_time_sm->GetTimeZoneService(m_file_timestamp_worker.m_time_zone);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
res = SetupStandardSteadyClockCore();
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
Service::PSC::Time::SystemClockContext user_clock_context{};
|
||||
res = m_set_sys->GetUserSystemClockContext(user_clock_context);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
// TODO this clock should initialise with this epoch time, and be updated somewhere else on
|
||||
// first boot, but I haven't been able to find that point (likely via ntc's auto correct as it's
|
||||
// defaulted to be enabled), and to get correct times we need to initialise with the current
|
||||
// time instead.
|
||||
auto epoch_time{GetEpochTimeFromInitialYear(m_set_sys)};
|
||||
if (user_clock_context == Service::PSC::Time::SystemClockContext{}) {
|
||||
m_steady_clock_resource.GetRtcTimeInSeconds(epoch_time);
|
||||
}
|
||||
|
||||
res = m_time_m->SetupStandardLocalSystemClockCore(user_clock_context, epoch_time);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
Service::PSC::Time::SystemClockContext network_clock_context{};
|
||||
res = m_set_sys->GetNetworkSystemClockContext(network_clock_context);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
auto network_accuracy_m{GetSettingsItemValue<s32>(
|
||||
m_set_sys, "time", "standard_network_clock_sufficient_accuracy_minutes")};
|
||||
auto one_minute_ns{
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()};
|
||||
s64 network_accuracy_ns{network_accuracy_m * one_minute_ns};
|
||||
|
||||
res = m_time_m->SetupStandardNetworkSystemClockCore(network_clock_context, network_accuracy_ns);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
bool is_automatic_correction_enabled{};
|
||||
res = m_set_sys->IsUserSystemClockAutomaticCorrectionEnabled(is_automatic_correction_enabled);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
Service::PSC::Time::SteadyClockTimePoint automatic_correction_time_point{};
|
||||
res = m_set_sys->GetUserSystemClockAutomaticCorrectionUpdatedTime(
|
||||
automatic_correction_time_point);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
res = m_time_m->SetupStandardUserSystemClockCore(automatic_correction_time_point,
|
||||
is_automatic_correction_enabled);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
res = m_time_m->SetupEphemeralNetworkSystemClockCore();
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
res = SetupTimeZoneServiceCore();
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
s64 rtc_time_s{};
|
||||
res = m_steady_clock_resource.GetRtcTimeInSeconds(rtc_time_s);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
// TODO system report "launch"
|
||||
// "rtc_reset" = m_steady_clock_resource.m_rtc_reset
|
||||
// "rtc_value" = rtc_time_s
|
||||
|
||||
m_worker.StartThread();
|
||||
|
||||
m_file_timestamp_worker.m_initialized = true;
|
||||
|
||||
s64 system_clock_time{};
|
||||
if (m_file_timestamp_worker.m_system_clock->GetCurrentTime(system_clock_time) ==
|
||||
ResultSuccess) {
|
||||
Service::PSC::Time::CalendarTime calendar_time{};
|
||||
Service::PSC::Time::CalendarAdditionalInfo calendar_additional{};
|
||||
if (m_file_timestamp_worker.m_time_zone->ToCalendarTimeWithMyRule(
|
||||
calendar_time, calendar_additional, system_clock_time) == ResultSuccess) {
|
||||
// TODO IFileSystemProxy::SetCurrentPosixTime(system_clock_time,
|
||||
// calendar_additional.ut_offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Result TimeManager::SetupStandardSteadyClockCore() {
|
||||
Common::UUID external_clock_source_id{};
|
||||
auto res = m_set_sys->GetExternalSteadyClockSourceId(external_clock_source_id);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
s64 external_steady_clock_internal_offset_s{};
|
||||
res = m_set_sys->GetExternalSteadyClockInternalOffset(external_steady_clock_internal_offset_s);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
auto one_second_ns{
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
|
||||
s64 external_steady_clock_internal_offset_ns{external_steady_clock_internal_offset_s *
|
||||
one_second_ns};
|
||||
|
||||
s32 standard_steady_clock_test_offset_m{
|
||||
GetSettingsItemValue<s32>(m_set_sys, "time", "standard_steady_clock_test_offset_minutes")};
|
||||
auto one_minute_ns{
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()};
|
||||
s64 standard_steady_clock_test_offset_ns{standard_steady_clock_test_offset_m * one_minute_ns};
|
||||
|
||||
auto reset_detected = m_steady_clock_resource.GetResetDetected();
|
||||
if (reset_detected) {
|
||||
external_clock_source_id = {};
|
||||
}
|
||||
|
||||
Common::UUID clock_source_id{};
|
||||
m_steady_clock_resource.Initialize(&clock_source_id, &external_clock_source_id);
|
||||
|
||||
if (clock_source_id != external_clock_source_id) {
|
||||
m_set_sys->SetExternalSteadyClockSourceId(clock_source_id);
|
||||
}
|
||||
|
||||
res = m_time_m->SetupStandardSteadyClockCore(clock_source_id, m_steady_clock_resource.GetTime(),
|
||||
external_steady_clock_internal_offset_ns,
|
||||
standard_steady_clock_test_offset_ns,
|
||||
reset_detected);
|
||||
ASSERT(res == ResultSuccess);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result TimeManager::SetupTimeZoneServiceCore() {
|
||||
Service::PSC::Time::LocationName name{};
|
||||
auto res = m_set_sys->GetDeviceTimeZoneLocationName(name);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
Service::PSC::Time::SteadyClockTimePoint time_point{};
|
||||
res = m_set_sys->GetDeviceTimeZoneLocationUpdatedTime(time_point);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
auto location_count = GetTimeZoneCount();
|
||||
Service::PSC::Time::RuleVersion rule_version{};
|
||||
GetTimeZoneVersion(rule_version);
|
||||
|
||||
std::span<const u8> rule_buffer{};
|
||||
size_t rule_size{};
|
||||
res = GetTimeZoneRule(rule_buffer, rule_size, name);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
res = m_time_m->SetupTimeZoneServiceCore(name, time_point, rule_version, location_count,
|
||||
rule_buffer);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
42
src/core/hle/service/glue/time/manager.h
Executable file
42
src/core/hle/service/glue/time/manager.h
Executable file
@@ -0,0 +1,42 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
#include "core/hle/service/glue/time/file_timestamp_worker.h"
|
||||
#include "core/hle/service/glue/time/standard_steady_clock_resource.h"
|
||||
#include "core/hle/service/glue/time/worker.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
class ServiceManager;
|
||||
class StaticService;
|
||||
} // namespace Service::PSC::Time
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
class TimeManager {
|
||||
public:
|
||||
explicit TimeManager(Core::System& system);
|
||||
|
||||
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m{};
|
||||
std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm{};
|
||||
StandardSteadyClockResource m_steady_clock_resource;
|
||||
FileTimestampWorker m_file_timestamp_worker;
|
||||
TimeWorker m_worker;
|
||||
|
||||
private:
|
||||
Result SetupStandardSteadyClockCore();
|
||||
Result SetupTimeZoneServiceCore();
|
||||
};
|
||||
} // namespace Service::Glue::Time
|
||||
13
src/core/hle/service/glue/time/pm_state_change_handler.cpp
Executable file
13
src/core/hle/service/glue/time/pm_state_change_handler.cpp
Executable file
@@ -0,0 +1,13 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/glue/time/pm_state_change_handler.h"
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
|
||||
PmStateChangeHandler::PmStateChangeHandler(AlarmWorker& alarm_worker)
|
||||
: m_alarm_worker{alarm_worker} {
|
||||
// TODO Initialize IPmModule, dependent on Rtc and Fs
|
||||
}
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
18
src/core/hle/service/glue/time/pm_state_change_handler.h
Executable file
18
src/core/hle/service/glue/time/pm_state_change_handler.h
Executable file
@@ -0,0 +1,18 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
class AlarmWorker;
|
||||
|
||||
class PmStateChangeHandler {
|
||||
public:
|
||||
explicit PmStateChangeHandler(AlarmWorker& alarm_worker);
|
||||
|
||||
AlarmWorker& m_alarm_worker;
|
||||
s32 m_priority{};
|
||||
};
|
||||
} // namespace Service::Glue::Time
|
||||
123
src/core/hle/service/glue/time/standard_steady_clock_resource.cpp
Executable file
123
src/core/hle/service/glue/time/standard_steady_clock_resource.cpp
Executable file
@@ -0,0 +1,123 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/hle/service/glue/time/standard_steady_clock_resource.h"
|
||||
#include "core/hle/service/psc/time/errors.h"
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
namespace {
|
||||
[[maybe_unused]] constexpr u32 Max77620PmicSession = 0x3A000001;
|
||||
[[maybe_unused]] constexpr u32 Max77620RtcSession = 0x3B000001;
|
||||
|
||||
Result GetTimeInSeconds(Core::System& system, s64& out_time_s) {
|
||||
if (Settings::values.custom_rtc_enabled) {
|
||||
out_time_s = Settings::values.custom_rtc.GetValue();
|
||||
} else {
|
||||
out_time_s = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
StandardSteadyClockResource::StandardSteadyClockResource(Core::System& system) : m_system{system} {}
|
||||
|
||||
void StandardSteadyClockResource::Initialize(Common::UUID* out_source_id,
|
||||
Common::UUID* external_source_id) {
|
||||
constexpr size_t NUM_TRIES{20};
|
||||
|
||||
size_t i{0};
|
||||
Result res{ResultSuccess};
|
||||
for (; i < NUM_TRIES; i++) {
|
||||
res = SetCurrentTime();
|
||||
if (res == ResultSuccess) {
|
||||
break;
|
||||
}
|
||||
Kernel::Svc::SleepThread(m_system, std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::milliseconds(1))
|
||||
.count());
|
||||
}
|
||||
|
||||
if (i < NUM_TRIES) {
|
||||
m_set_time_result = ResultSuccess;
|
||||
if (*external_source_id != Service::PSC::Time::ClockSourceId{}) {
|
||||
m_clock_source_id = *external_source_id;
|
||||
} else {
|
||||
m_clock_source_id = Common::UUID::MakeRandom();
|
||||
}
|
||||
} else {
|
||||
m_set_time_result = res;
|
||||
auto ticks{m_system.CoreTiming().GetClockTicks()};
|
||||
m_time = -Service::PSC::Time::ConvertToTimeSpan(ticks).count();
|
||||
m_clock_source_id = Common::UUID::MakeRandom();
|
||||
}
|
||||
|
||||
if (out_source_id) {
|
||||
*out_source_id = m_clock_source_id;
|
||||
}
|
||||
}
|
||||
|
||||
bool StandardSteadyClockResource::GetResetDetected() {
|
||||
// TODO:
|
||||
// call Rtc::GetRtcResetDetected(Max77620RtcSession)
|
||||
// if detected:
|
||||
// SetSys::SetExternalSteadyClockSourceId(invalid_id)
|
||||
// Rtc::ClearRtcResetDetected(Max77620RtcSession)
|
||||
// set m_rtc_reset to result
|
||||
// Instead, only set reset to true if we're booting for the first time.
|
||||
m_rtc_reset = false;
|
||||
return m_rtc_reset;
|
||||
}
|
||||
|
||||
Result StandardSteadyClockResource::SetCurrentTime() {
|
||||
auto start_tick{m_system.CoreTiming().GetClockTicks()};
|
||||
|
||||
s64 rtc_time_s{};
|
||||
// TODO R_TRY(Rtc::GetTimeInSeconds(rtc_time_s, Max77620RtcSession))
|
||||
R_TRY(GetTimeInSeconds(m_system, rtc_time_s));
|
||||
|
||||
auto end_tick{m_system.CoreTiming().GetClockTicks()};
|
||||
auto diff{Service::PSC::Time::ConvertToTimeSpan(end_tick - start_tick)};
|
||||
// Why is this here?
|
||||
R_UNLESS(diff < std::chrono::milliseconds(101), Service::PSC::Time::ResultRtcTimeout);
|
||||
|
||||
auto one_second_ns{
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
|
||||
s64 boot_time{rtc_time_s * one_second_ns -
|
||||
Service::PSC::Time::ConvertToTimeSpan(end_tick).count()};
|
||||
|
||||
std::scoped_lock l{m_mutex};
|
||||
m_time = boot_time;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StandardSteadyClockResource::GetRtcTimeInSeconds(s64& out_time) {
|
||||
// TODO
|
||||
// R_TRY(Rtc::GetTimeInSeconds(time_s, Max77620RtcSession)
|
||||
R_RETURN(GetTimeInSeconds(m_system, out_time));
|
||||
}
|
||||
|
||||
void StandardSteadyClockResource::UpdateTime() {
|
||||
constexpr size_t NUM_TRIES{3};
|
||||
|
||||
size_t i{0};
|
||||
Result res{ResultSuccess};
|
||||
for (; i < NUM_TRIES; i++) {
|
||||
res = SetCurrentTime();
|
||||
if (res == ResultSuccess) {
|
||||
break;
|
||||
}
|
||||
Kernel::Svc::SleepThread(m_system, std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::milliseconds(1))
|
||||
.count());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
41
src/core/hle/service/glue/time/standard_steady_clock_resource.h
Executable file
41
src/core/hle/service/glue/time/standard_steady_clock_resource.h
Executable file
@@ -0,0 +1,41 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
class StandardSteadyClockResource {
|
||||
public:
|
||||
StandardSteadyClockResource(Core::System& system);
|
||||
|
||||
void Initialize(Common::UUID* out_source_id, Common::UUID* external_source_id);
|
||||
|
||||
s64 GetTime() const {
|
||||
return m_time;
|
||||
}
|
||||
|
||||
bool GetResetDetected();
|
||||
Result SetCurrentTime();
|
||||
Result GetRtcTimeInSeconds(s64& out_time);
|
||||
void UpdateTime();
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
|
||||
std::mutex m_mutex;
|
||||
Service::PSC::Time::ClockSourceId m_clock_source_id{};
|
||||
s64 m_time{};
|
||||
Result m_set_time_result;
|
||||
bool m_rtc_reset;
|
||||
};
|
||||
} // namespace Service::Glue::Time
|
||||
447
src/core/hle/service/glue/time/static.cpp
Executable file
447
src/core/hle/service/glue/time/static.cpp
Executable file
@@ -0,0 +1,447 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/hle/service/glue/time/file_timestamp_worker.h"
|
||||
#include "core/hle/service/glue/time/static.h"
|
||||
#include "core/hle/service/psc/time/errors.h"
|
||||
#include "core/hle/service/psc/time/service_manager.h"
|
||||
#include "core/hle/service/psc/time/static.h"
|
||||
#include "core/hle/service/psc/time/steady_clock.h"
|
||||
#include "core/hle/service/psc/time/system_clock.h"
|
||||
#include "core/hle/service/psc/time/time_zone_service.h"
|
||||
#include "core/hle/service/set/system_settings_server.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
namespace {
|
||||
template <typename T>
|
||||
T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys,
|
||||
const char* category, const char* name) {
|
||||
std::vector<u8> interval_buf;
|
||||
auto res = set_sys->GetSettingsItemValue(interval_buf, category, name);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
T v{};
|
||||
std::memcpy(&v, interval_buf.data(), sizeof(T));
|
||||
return v;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
StaticService::StaticService(Core::System& system_,
|
||||
Service::PSC::Time::StaticServiceSetupInfo setup_info,
|
||||
std::shared_ptr<TimeManager> time, const char* name)
|
||||
: ServiceFramework{system_, name}, m_system{system_}, m_time_m{time->m_time_m},
|
||||
m_setup_info{setup_info}, m_time_sm{time->m_time_sm},
|
||||
m_file_timestamp_worker{time->m_file_timestamp_worker}, m_standard_steady_clock_resource{
|
||||
time->m_steady_clock_resource} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &StaticService::Handle_GetStandardUserSystemClock, "GetStandardUserSystemClock"},
|
||||
{1, &StaticService::Handle_GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"},
|
||||
{2, &StaticService::Handle_GetStandardSteadyClock, "GetStandardSteadyClock"},
|
||||
{3, &StaticService::Handle_GetTimeZoneService, "GetTimeZoneService"},
|
||||
{4, &StaticService::Handle_GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
|
||||
{5, &StaticService::Handle_GetEphemeralNetworkSystemClock, "GetEphemeralNetworkSystemClock"},
|
||||
{20, &StaticService::Handle_GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
|
||||
{50, &StaticService::Handle_SetStandardSteadyClockInternalOffset, "SetStandardSteadyClockInternalOffset"},
|
||||
{51, &StaticService::Handle_GetStandardSteadyClockRtcValue, "GetStandardSteadyClockRtcValue"},
|
||||
{100, &StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{101, &StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{102, &StaticService::Handle_GetStandardUserSystemClockInitialYear, "GetStandardUserSystemClockInitialYear"},
|
||||
{200, &StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"},
|
||||
{201, &StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
|
||||
{300, &StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"},
|
||||
{400, &StaticService::Handle_GetClockSnapshot, "GetClockSnapshot"},
|
||||
{401, &StaticService::Handle_GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"},
|
||||
{500, &StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"},
|
||||
{501, &StaticService::Handle_CalculateSpanBetween, "CalculateSpanBetween"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
m_set_sys =
|
||||
m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
|
||||
|
||||
if (m_setup_info.can_write_local_clock && m_setup_info.can_write_user_clock &&
|
||||
!m_setup_info.can_write_network_clock && m_setup_info.can_write_timezone_device_location &&
|
||||
!m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) {
|
||||
m_time_m->GetStaticServiceAsAdmin(m_wrapped_service);
|
||||
} else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock &&
|
||||
!m_setup_info.can_write_network_clock &&
|
||||
!m_setup_info.can_write_timezone_device_location &&
|
||||
!m_setup_info.can_write_steady_clock &&
|
||||
!m_setup_info.can_write_uninitialized_clock) {
|
||||
m_time_m->GetStaticServiceAsUser(m_wrapped_service);
|
||||
} else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock &&
|
||||
!m_setup_info.can_write_network_clock &&
|
||||
!m_setup_info.can_write_timezone_device_location &&
|
||||
m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) {
|
||||
m_time_m->GetStaticServiceAsRepair(m_wrapped_service);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
auto res = m_wrapped_service->GetTimeZoneService(m_time_zone);
|
||||
ASSERT(res == ResultSuccess);
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardUserSystemClock(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock> service{};
|
||||
auto res = GetStandardUserSystemClock(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock> service{};
|
||||
auto res = GetStandardNetworkSystemClock(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardSteadyClock(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SteadyClock> service{};
|
||||
auto res = GetStandardSteadyClock(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface(std::move(service));
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetTimeZoneService(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<TimeZoneService> service{};
|
||||
auto res = GetTimeZoneService(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface(std::move(service));
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardLocalSystemClock(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock> service{};
|
||||
auto res = GetStandardLocalSystemClock(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock> service{};
|
||||
auto res = GetEphemeralNetworkSystemClock(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Kernel::KSharedMemory* shared_memory{};
|
||||
auto res = GetSharedMemoryNativeHandle(&shared_memory);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(res);
|
||||
rb.PushCopyObjects(shared_memory);
|
||||
}
|
||||
|
||||
void StaticService::Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto offset_ns{rp.Pop<s64>()};
|
||||
|
||||
auto res = SetStandardSteadyClockInternalOffset(offset_ns);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
s64 rtc_value{};
|
||||
auto res = GetStandardSteadyClockRtcValue(rtc_value);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.Push(rtc_value);
|
||||
}
|
||||
|
||||
void StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
bool is_enabled{};
|
||||
auto res = IsStandardUserSystemClockAutomaticCorrectionEnabled(is_enabled);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push<bool>(is_enabled);
|
||||
}
|
||||
|
||||
void StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto automatic_correction{rp.Pop<bool>()};
|
||||
|
||||
auto res = SetStandardUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
s32 initial_year{};
|
||||
auto res = GetStandardUserSystemClockInitialYear(initial_year);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push(initial_year);
|
||||
}
|
||||
|
||||
void StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
bool is_sufficient{};
|
||||
auto res = IsStandardNetworkSystemClockAccuracySufficient(is_sufficient);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push<bool>(is_sufficient);
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Service::PSC::Time::SteadyClockTimePoint time_point{};
|
||||
auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx,
|
||||
2 + sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32)};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point);
|
||||
}
|
||||
|
||||
void StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
|
||||
|
||||
s64 time{};
|
||||
auto res = CalculateMonotonicSystemClockBaseTimePoint(time, context);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.Push<s64>(time);
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetClockSnapshot(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto type{rp.PopEnum<Service::PSC::Time::TimeType>()};
|
||||
|
||||
Service::PSC::Time::ClockSnapshot snapshot{};
|
||||
auto res = GetClockSnapshot(snapshot, type);
|
||||
|
||||
ctx.WriteBuffer(snapshot);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto user_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
|
||||
auto network_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
|
||||
auto clock_type{rp.PopEnum<Service::PSC::Time::TimeType>()};
|
||||
|
||||
Service::PSC::Time::ClockSnapshot snapshot{};
|
||||
auto res =
|
||||
GetClockSnapshotFromSystemClockContext(snapshot, user_context, network_context, clock_type);
|
||||
|
||||
ctx.WriteBuffer(snapshot);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Service::PSC::Time::ClockSnapshot a{};
|
||||
Service::PSC::Time::ClockSnapshot b{};
|
||||
|
||||
auto a_buffer{ctx.ReadBuffer(0)};
|
||||
auto b_buffer{ctx.ReadBuffer(1)};
|
||||
|
||||
std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
|
||||
std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
|
||||
|
||||
s64 difference{};
|
||||
auto res = CalculateStandardUserSystemClockDifferenceByUser(difference, a, b);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.Push(difference);
|
||||
}
|
||||
|
||||
void StaticService::Handle_CalculateSpanBetween(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Service::PSC::Time::ClockSnapshot a{};
|
||||
Service::PSC::Time::ClockSnapshot b{};
|
||||
|
||||
auto a_buffer{ctx.ReadBuffer(0)};
|
||||
auto b_buffer{ctx.ReadBuffer(1)};
|
||||
|
||||
std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
|
||||
std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
|
||||
|
||||
s64 time{};
|
||||
auto res = CalculateSpanBetween(time, a, b);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.Push(time);
|
||||
}
|
||||
|
||||
// =============================== Implementations ===========================
|
||||
|
||||
Result StaticService::GetStandardUserSystemClock(
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
|
||||
R_RETURN(m_wrapped_service->GetStandardUserSystemClock(out_service));
|
||||
}
|
||||
|
||||
Result StaticService::GetStandardNetworkSystemClock(
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
|
||||
R_RETURN(m_wrapped_service->GetStandardNetworkSystemClock(out_service));
|
||||
}
|
||||
|
||||
Result StaticService::GetStandardSteadyClock(
|
||||
std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service) {
|
||||
R_RETURN(m_wrapped_service->GetStandardSteadyClock(out_service));
|
||||
}
|
||||
|
||||
Result StaticService::GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service) {
|
||||
out_service = std::make_shared<TimeZoneService>(m_system, m_file_timestamp_worker,
|
||||
m_setup_info.can_write_timezone_device_location,
|
||||
m_time_zone);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::GetStandardLocalSystemClock(
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
|
||||
R_RETURN(m_wrapped_service->GetStandardLocalSystemClock(out_service));
|
||||
}
|
||||
|
||||
Result StaticService::GetEphemeralNetworkSystemClock(
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
|
||||
R_RETURN(m_wrapped_service->GetEphemeralNetworkSystemClock(out_service));
|
||||
}
|
||||
|
||||
Result StaticService::GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory) {
|
||||
R_RETURN(m_wrapped_service->GetSharedMemoryNativeHandle(out_shared_memory));
|
||||
}
|
||||
|
||||
Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) {
|
||||
R_UNLESS(m_setup_info.can_write_steady_clock, Service::PSC::Time::ResultPermissionDenied);
|
||||
|
||||
R_RETURN(m_set_sys->SetExternalSteadyClockInternalOffset(
|
||||
offset_ns /
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()));
|
||||
}
|
||||
|
||||
Result StaticService::GetStandardSteadyClockRtcValue(s64& out_rtc_value) {
|
||||
R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(out_rtc_value));
|
||||
}
|
||||
|
||||
Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
|
||||
bool& out_automatic_correction) {
|
||||
R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled(
|
||||
out_automatic_correction));
|
||||
}
|
||||
|
||||
Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled(
|
||||
bool automatic_correction) {
|
||||
R_RETURN(m_wrapped_service->SetStandardUserSystemClockAutomaticCorrectionEnabled(
|
||||
automatic_correction));
|
||||
}
|
||||
|
||||
Result StaticService::GetStandardUserSystemClockInitialYear(s32& out_year) {
|
||||
out_year = GetSettingsItemValue<s32>(m_set_sys, "time", "standard_user_clock_initial_year");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient) {
|
||||
R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient));
|
||||
}
|
||||
|
||||
Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
|
||||
Service::PSC::Time::SteadyClockTimePoint& out_time_point) {
|
||||
R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
|
||||
out_time_point));
|
||||
}
|
||||
|
||||
Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
|
||||
s64& out_time, Service::PSC::Time::SystemClockContext& context) {
|
||||
R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context));
|
||||
}
|
||||
|
||||
Result StaticService::GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot,
|
||||
Service::PSC::Time::TimeType type) {
|
||||
R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type));
|
||||
}
|
||||
|
||||
Result StaticService::GetClockSnapshotFromSystemClockContext(
|
||||
Service::PSC::Time::ClockSnapshot& out_snapshot,
|
||||
Service::PSC::Time::SystemClockContext& user_context,
|
||||
Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type) {
|
||||
R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext(out_snapshot, user_context,
|
||||
network_context, type));
|
||||
}
|
||||
|
||||
Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(
|
||||
s64& out_time, Service::PSC::Time::ClockSnapshot& a, Service::PSC::Time::ClockSnapshot& b) {
|
||||
R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b));
|
||||
}
|
||||
|
||||
Result StaticService::CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a,
|
||||
Service::PSC::Time::ClockSnapshot& b) {
|
||||
R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b));
|
||||
}
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
110
src/core/hle/service/glue/time/static.h
Executable file
110
src/core/hle/service/glue/time/static.h
Executable file
@@ -0,0 +1,110 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/glue/time/manager.h"
|
||||
#include "core/hle/service/glue/time/time_zone.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::Set {
|
||||
class ISystemSettingsServer;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
class StaticService;
|
||||
class SystemClock;
|
||||
class SteadyClock;
|
||||
class TimeZoneService;
|
||||
class ServiceManager;
|
||||
} // namespace Service::PSC::Time
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
class FileTimestampWorker;
|
||||
class StandardSteadyClockResource;
|
||||
|
||||
class StaticService final : public ServiceFramework<StaticService> {
|
||||
public:
|
||||
explicit StaticService(Core::System& system,
|
||||
Service::PSC::Time::StaticServiceSetupInfo setup_info,
|
||||
std::shared_ptr<TimeManager> time, const char* name);
|
||||
|
||||
~StaticService() override = default;
|
||||
|
||||
Result GetStandardUserSystemClock(
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service);
|
||||
Result GetStandardNetworkSystemClock(
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service);
|
||||
Result GetStandardSteadyClock(std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service);
|
||||
Result GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service);
|
||||
Result GetStandardLocalSystemClock(
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service);
|
||||
Result GetEphemeralNetworkSystemClock(
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock>& out_service);
|
||||
Result GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory);
|
||||
Result SetStandardSteadyClockInternalOffset(s64 offset);
|
||||
Result GetStandardSteadyClockRtcValue(s64& out_rtc_value);
|
||||
Result IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_automatic_correction);
|
||||
Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction);
|
||||
Result GetStandardUserSystemClockInitialYear(s32& out_year);
|
||||
Result IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient);
|
||||
Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
|
||||
Service::PSC::Time::SteadyClockTimePoint& out_time_point);
|
||||
Result CalculateMonotonicSystemClockBaseTimePoint(
|
||||
s64& out_time, Service::PSC::Time::SystemClockContext& context);
|
||||
Result GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot,
|
||||
Service::PSC::Time::TimeType type);
|
||||
Result GetClockSnapshotFromSystemClockContext(
|
||||
Service::PSC::Time::ClockSnapshot& out_snapshot,
|
||||
Service::PSC::Time::SystemClockContext& user_context,
|
||||
Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type);
|
||||
Result CalculateStandardUserSystemClockDifferenceByUser(s64& out_time,
|
||||
Service::PSC::Time::ClockSnapshot& a,
|
||||
Service::PSC::Time::ClockSnapshot& b);
|
||||
Result CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a,
|
||||
Service::PSC::Time::ClockSnapshot& b);
|
||||
|
||||
private:
|
||||
Result GetClockSnapshotImpl(Service::PSC::Time::ClockSnapshot& out_snapshot,
|
||||
Service::PSC::Time::SystemClockContext& user_context,
|
||||
Service::PSC::Time::SystemClockContext& network_context,
|
||||
Service::PSC::Time::TimeType type);
|
||||
|
||||
void Handle_GetStandardUserSystemClock(HLERequestContext& ctx);
|
||||
void Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx);
|
||||
void Handle_GetStandardSteadyClock(HLERequestContext& ctx);
|
||||
void Handle_GetTimeZoneService(HLERequestContext& ctx);
|
||||
void Handle_GetStandardLocalSystemClock(HLERequestContext& ctx);
|
||||
void Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx);
|
||||
void Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx);
|
||||
void Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx);
|
||||
void Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx);
|
||||
void Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
|
||||
void Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
|
||||
void Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx);
|
||||
void Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx);
|
||||
void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx);
|
||||
void Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx);
|
||||
void Handle_GetClockSnapshot(HLERequestContext& ctx);
|
||||
void Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx);
|
||||
void Handle_CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx);
|
||||
void Handle_CalculateSpanBetween(HLERequestContext& ctx);
|
||||
|
||||
Core::System& m_system;
|
||||
|
||||
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
|
||||
std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m;
|
||||
std::shared_ptr<Service::PSC::Time::StaticService> m_wrapped_service;
|
||||
|
||||
Service::PSC::Time::StaticServiceSetupInfo m_setup_info;
|
||||
std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm;
|
||||
std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone;
|
||||
FileTimestampWorker& m_file_timestamp_worker;
|
||||
StandardSteadyClockResource& m_standard_steady_clock_resource;
|
||||
};
|
||||
} // namespace Service::Glue::Time
|
||||
377
src/core/hle/service/glue/time/time_zone.cpp
Executable file
377
src/core/hle/service/glue/time/time_zone.cpp
Executable file
@@ -0,0 +1,377 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/hle/service/glue/time/file_timestamp_worker.h"
|
||||
#include "core/hle/service/glue/time/time_zone.h"
|
||||
#include "core/hle/service/glue/time/time_zone_binary.h"
|
||||
#include "core/hle/service/psc/time/time_zone_service.h"
|
||||
#include "core/hle/service/set/system_settings_server.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
namespace {
|
||||
static std::mutex g_list_mutex;
|
||||
static Common::IntrusiveListBaseTraits<Service::PSC::Time::OperationEvent>::ListType g_list_nodes{};
|
||||
} // namespace
|
||||
|
||||
TimeZoneService::TimeZoneService(
|
||||
Core::System& system_, FileTimestampWorker& file_timestamp_worker,
|
||||
bool can_write_timezone_device_location,
|
||||
std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service)
|
||||
: ServiceFramework{system_, "ITimeZoneService"}, m_system{system},
|
||||
m_can_write_timezone_device_location{can_write_timezone_device_location},
|
||||
m_file_timestamp_worker{file_timestamp_worker},
|
||||
m_wrapped_service{std::move(time_zone_service)}, m_operation_event{m_system} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &TimeZoneService::Handle_GetDeviceLocationName, "GetDeviceLocationName"},
|
||||
{1, &TimeZoneService::Handle_SetDeviceLocationName, "SetDeviceLocationName"},
|
||||
{2, &TimeZoneService::Handle_GetTotalLocationNameCount, "GetTotalLocationNameCount"},
|
||||
{3, &TimeZoneService::Handle_LoadLocationNameList, "LoadLocationNameList"},
|
||||
{4, &TimeZoneService::Handle_LoadTimeZoneRule, "LoadTimeZoneRule"},
|
||||
{5, &TimeZoneService::Handle_GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"},
|
||||
{6, &TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime, "GetDeviceLocationNameAndUpdatedTime"},
|
||||
{7, &TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule, "SetDeviceLocationNameWithTimeZoneRule"},
|
||||
{8, &TimeZoneService::Handle_ParseTimeZoneBinary, "ParseTimeZoneBinary"},
|
||||
{20, &TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle, "GetDeviceLocationNameOperationEventReadableHandle"},
|
||||
{100, &TimeZoneService::Handle_ToCalendarTime, "ToCalendarTime"},
|
||||
{101, &TimeZoneService::Handle_ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
|
||||
{201, &TimeZoneService::Handle_ToPosixTime, "ToPosixTime"},
|
||||
{202, &TimeZoneService::Handle_ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
|
||||
g_list_nodes.clear();
|
||||
m_set_sys =
|
||||
m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
|
||||
}
|
||||
|
||||
TimeZoneService::~TimeZoneService() = default;
|
||||
|
||||
void TimeZoneService::Handle_GetDeviceLocationName(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Service::PSC::Time::LocationName name{};
|
||||
auto res = GetDeviceLocationName(name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::LocationName) / sizeof(u32)};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<Service::PSC::Time::LocationName>(name);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_SetDeviceLocationName(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto name{rp.PopRaw<Service::PSC::Time::LocationName>()};
|
||||
|
||||
auto res = SetDeviceLocation(name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_GetTotalLocationNameCount(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
u32 count{};
|
||||
auto res = GetTotalLocationNameCount(count);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push(count);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_LoadLocationNameList(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto index{rp.Pop<u32>()};
|
||||
|
||||
auto max_names{ctx.GetWriteBufferSize() / sizeof(Service::PSC::Time::LocationName)};
|
||||
|
||||
std::vector<Service::PSC::Time::LocationName> names{};
|
||||
u32 count{};
|
||||
auto res = LoadLocationNameList(count, names, max_names, index);
|
||||
|
||||
ctx.WriteBuffer(names);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push(count);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_LoadTimeZoneRule(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto name{rp.PopRaw<Service::PSC::Time::LocationName>()};
|
||||
|
||||
Tz::Rule rule{};
|
||||
auto res = LoadTimeZoneRule(rule, name);
|
||||
|
||||
ctx.WriteBuffer(rule);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Service::PSC::Time::RuleVersion rule_version{};
|
||||
auto res = GetTimeZoneRuleVersion(rule_version);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::RuleVersion) / sizeof(u32)};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<Service::PSC::Time::RuleVersion>(rule_version);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Service::PSC::Time::LocationName name{};
|
||||
Service::PSC::Time::SteadyClockTimePoint time_point{};
|
||||
auto res = GetDeviceLocationNameAndUpdatedTime(time_point, name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx,
|
||||
2 + (sizeof(Service::PSC::Time::LocationName) / sizeof(u32)) +
|
||||
(sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32))};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<Service::PSC::Time::LocationName>(name);
|
||||
rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
auto res = SetDeviceLocationNameWithTimeZoneRule();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_ParseTimeZoneBinary(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(Service::PSC::Time::ResultNotImplemented);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Kernel::KEvent* event{};
|
||||
auto res = GetDeviceLocationNameOperationEventReadableHandle(&event);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(res);
|
||||
rb.PushCopyObjects(event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_ToCalendarTime(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto time{rp.Pop<s64>()};
|
||||
|
||||
auto rule_buffer{ctx.ReadBuffer()};
|
||||
Tz::Rule rule{};
|
||||
std::memcpy(&rule, rule_buffer.data(), sizeof(Tz::Rule));
|
||||
|
||||
Service::PSC::Time::CalendarTime calendar_time{};
|
||||
Service::PSC::Time::CalendarAdditionalInfo additional_info{};
|
||||
auto res = ToCalendarTime(calendar_time, additional_info, time, rule);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx,
|
||||
2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) +
|
||||
(sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time);
|
||||
rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto time{rp.Pop<s64>()};
|
||||
|
||||
LOG_DEBUG(Service_Time, "called. time={}", time);
|
||||
|
||||
Service::PSC::Time::CalendarTime calendar_time{};
|
||||
Service::PSC::Time::CalendarAdditionalInfo additional_info{};
|
||||
auto res = ToCalendarTimeWithMyRule(calendar_time, additional_info, time);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx,
|
||||
2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) +
|
||||
(sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time);
|
||||
rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_ToPosixTime(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()};
|
||||
|
||||
LOG_DEBUG(Service_Time, "called. calendar year {} month {} day {} hour {} minute {} second {}",
|
||||
calendar.year, calendar.month, calendar.day, calendar.hour, calendar.minute,
|
||||
calendar.second);
|
||||
|
||||
auto binary{ctx.ReadBuffer()};
|
||||
|
||||
Tz::Rule rule{};
|
||||
std::memcpy(&rule, binary.data(), sizeof(Tz::Rule));
|
||||
|
||||
u32 count{};
|
||||
std::array<s64, 2> times{};
|
||||
u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
|
||||
|
||||
auto res = ToPosixTime(count, times, times_count, calendar, rule);
|
||||
|
||||
ctx.WriteBuffer(times);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push(count);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()};
|
||||
|
||||
u32 count{};
|
||||
std::array<s64, 2> times{};
|
||||
u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
|
||||
|
||||
auto res = ToPosixTimeWithMyRule(count, times, times_count, calendar);
|
||||
|
||||
ctx.WriteBuffer(times);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push(count);
|
||||
}
|
||||
|
||||
// =============================== Implementations ===========================
|
||||
|
||||
Result TimeZoneService::GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name) {
|
||||
R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name));
|
||||
}
|
||||
|
||||
Result TimeZoneService::SetDeviceLocation(Service::PSC::Time::LocationName& location_name) {
|
||||
R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied);
|
||||
R_UNLESS(IsTimeZoneBinaryValid(location_name), Service::PSC::Time::ResultTimeZoneNotFound);
|
||||
|
||||
std::scoped_lock l{m_mutex};
|
||||
|
||||
std::span<const u8> binary{};
|
||||
size_t binary_size{};
|
||||
R_TRY(GetTimeZoneRule(binary, binary_size, location_name))
|
||||
|
||||
R_TRY(m_wrapped_service->SetDeviceLocationNameWithTimeZoneRule(location_name, binary));
|
||||
|
||||
m_file_timestamp_worker.SetFilesystemPosixTime();
|
||||
|
||||
Service::PSC::Time::SteadyClockTimePoint time_point{};
|
||||
Service::PSC::Time::LocationName name{};
|
||||
R_TRY(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(time_point, name));
|
||||
|
||||
m_set_sys->SetDeviceTimeZoneLocationName(name);
|
||||
m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(time_point);
|
||||
|
||||
std::scoped_lock m{g_list_mutex};
|
||||
for (auto& operation_event : g_list_nodes) {
|
||||
operation_event.m_event->Signal();
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result TimeZoneService::GetTotalLocationNameCount(u32& out_count) {
|
||||
R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count));
|
||||
}
|
||||
|
||||
Result TimeZoneService::LoadLocationNameList(
|
||||
u32& out_count, std::vector<Service::PSC::Time::LocationName>& out_names, size_t max_names,
|
||||
u32 index) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
R_RETURN(GetTimeZoneLocationList(out_count, out_names, max_names, index));
|
||||
}
|
||||
|
||||
Result TimeZoneService::LoadTimeZoneRule(Tz::Rule& out_rule,
|
||||
Service::PSC::Time::LocationName& name) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
std::span<const u8> binary{};
|
||||
size_t binary_size{};
|
||||
R_TRY(GetTimeZoneRule(binary, binary_size, name))
|
||||
R_RETURN(m_wrapped_service->ParseTimeZoneBinary(out_rule, binary));
|
||||
}
|
||||
|
||||
Result TimeZoneService::GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version) {
|
||||
R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version));
|
||||
}
|
||||
|
||||
Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
|
||||
Service::PSC::Time::SteadyClockTimePoint& out_time_point,
|
||||
Service::PSC::Time::LocationName& location_name) {
|
||||
R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(out_time_point, location_name));
|
||||
}
|
||||
|
||||
Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule() {
|
||||
R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied);
|
||||
R_RETURN(Service::PSC::Time::ResultNotImplemented);
|
||||
}
|
||||
|
||||
Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
|
||||
Kernel::KEvent** out_event) {
|
||||
if (!operation_event_initialized) {
|
||||
operation_event_initialized = false;
|
||||
|
||||
m_operation_event.m_ctx.CloseEvent(m_operation_event.m_event);
|
||||
m_operation_event.m_event =
|
||||
m_operation_event.m_ctx.CreateEvent("Psc:TimeZoneService:OperationEvent");
|
||||
operation_event_initialized = true;
|
||||
std::scoped_lock l{m_mutex};
|
||||
g_list_nodes.push_back(m_operation_event);
|
||||
}
|
||||
|
||||
*out_event = m_operation_event.m_event;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result TimeZoneService::ToCalendarTime(
|
||||
Service::PSC::Time::CalendarTime& out_calendar_time,
|
||||
Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule) {
|
||||
R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule));
|
||||
}
|
||||
|
||||
Result TimeZoneService::ToCalendarTimeWithMyRule(
|
||||
Service::PSC::Time::CalendarTime& out_calendar_time,
|
||||
Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time) {
|
||||
R_RETURN(
|
||||
m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time));
|
||||
}
|
||||
|
||||
Result TimeZoneService::ToPosixTime(u32& out_count, std::span<s64, 2> out_times,
|
||||
u32 out_times_count,
|
||||
Service::PSC::Time::CalendarTime& calendar_time,
|
||||
Tz::Rule& rule) {
|
||||
R_RETURN(
|
||||
m_wrapped_service->ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule));
|
||||
}
|
||||
|
||||
Result TimeZoneService::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times,
|
||||
u32 out_times_count,
|
||||
Service::PSC::Time::CalendarTime& calendar_time) {
|
||||
R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, out_times_count,
|
||||
calendar_time));
|
||||
}
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
95
src/core/hle/service/glue/time/time_zone.h
Executable file
95
src/core/hle/service/glue/time/time_zone.h
Executable file
@@ -0,0 +1,95 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Tz {
|
||||
struct Rule;
|
||||
}
|
||||
|
||||
namespace Service::Set {
|
||||
class ISystemSettingsServer;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
class TimeZoneService;
|
||||
}
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
class FileTimestampWorker;
|
||||
|
||||
class TimeZoneService final : public ServiceFramework<TimeZoneService> {
|
||||
public:
|
||||
explicit TimeZoneService(
|
||||
Core::System& system, FileTimestampWorker& file_timestamp_worker,
|
||||
bool can_write_timezone_device_location,
|
||||
std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service);
|
||||
|
||||
~TimeZoneService() override;
|
||||
|
||||
Result GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name);
|
||||
Result SetDeviceLocation(Service::PSC::Time::LocationName& location_name);
|
||||
Result GetTotalLocationNameCount(u32& out_count);
|
||||
Result LoadLocationNameList(u32& out_count,
|
||||
std::vector<Service::PSC::Time::LocationName>& out_names,
|
||||
size_t max_names, u32 index);
|
||||
Result LoadTimeZoneRule(Tz::Rule& out_rule, Service::PSC::Time::LocationName& name);
|
||||
Result GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version);
|
||||
Result GetDeviceLocationNameAndUpdatedTime(
|
||||
Service::PSC::Time::SteadyClockTimePoint& out_time_point,
|
||||
Service::PSC::Time::LocationName& location_name);
|
||||
Result SetDeviceLocationNameWithTimeZoneRule();
|
||||
Result GetDeviceLocationNameOperationEventReadableHandle(Kernel::KEvent** out_event);
|
||||
Result ToCalendarTime(Service::PSC::Time::CalendarTime& out_calendar_time,
|
||||
Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time,
|
||||
Tz::Rule& rule);
|
||||
Result ToCalendarTimeWithMyRule(Service::PSC::Time::CalendarTime& out_calendar_time,
|
||||
Service::PSC::Time::CalendarAdditionalInfo& out_additional_info,
|
||||
s64 time);
|
||||
Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
|
||||
Service::PSC::Time::CalendarTime& calendar_time, Tz::Rule& rule);
|
||||
Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
|
||||
Service::PSC::Time::CalendarTime& calendar_time);
|
||||
|
||||
private:
|
||||
void Handle_GetDeviceLocationName(HLERequestContext& ctx);
|
||||
void Handle_SetDeviceLocationName(HLERequestContext& ctx);
|
||||
void Handle_GetTotalLocationNameCount(HLERequestContext& ctx);
|
||||
void Handle_LoadLocationNameList(HLERequestContext& ctx);
|
||||
void Handle_LoadTimeZoneRule(HLERequestContext& ctx);
|
||||
void Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx);
|
||||
void Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx);
|
||||
void Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx);
|
||||
void Handle_ParseTimeZoneBinary(HLERequestContext& ctx);
|
||||
void Handle_GetDeviceLocationNameOperationEventReadableHandle(HLERequestContext& ctx);
|
||||
void Handle_ToCalendarTime(HLERequestContext& ctx);
|
||||
void Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx);
|
||||
void Handle_ToPosixTime(HLERequestContext& ctx);
|
||||
void Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx);
|
||||
|
||||
Core::System& m_system;
|
||||
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
|
||||
|
||||
bool m_can_write_timezone_device_location;
|
||||
FileTimestampWorker& m_file_timestamp_worker;
|
||||
std::shared_ptr<Service::PSC::Time::TimeZoneService> m_wrapped_service;
|
||||
std::mutex m_mutex;
|
||||
bool operation_event_initialized{};
|
||||
Service::PSC::Time::OperationEvent m_operation_event;
|
||||
};
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
205
src/core/hle/service/glue/time/time_zone_binary.cpp
Executable file
205
src/core/hle/service/glue/time/time_zone_binary.cpp
Executable file
@@ -0,0 +1,205 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/romfs.h"
|
||||
#include "core/file_sys/system_archive/system_archive.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/glue/time/time_zone_binary.h"
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
namespace {
|
||||
constexpr u64 TimeZoneBinaryId = 0x10000000000080E;
|
||||
|
||||
static FileSys::VirtualDir g_time_zone_binary_romfs{};
|
||||
static Result g_time_zone_binary_mount_result{ResultUnknown};
|
||||
static std::vector<u8> g_time_zone_scratch_space(0x2800, 0);
|
||||
|
||||
Result TimeZoneReadBinary(size_t& out_read_size, std::span<u8> out_buffer, size_t out_buffer_size,
|
||||
std::string_view path) {
|
||||
R_UNLESS(g_time_zone_binary_mount_result == ResultSuccess, g_time_zone_binary_mount_result);
|
||||
|
||||
auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)};
|
||||
R_UNLESS(vfs_file, ResultUnknown);
|
||||
|
||||
auto file_size{vfs_file->GetSize()};
|
||||
R_UNLESS(file_size > 0, ResultUnknown);
|
||||
|
||||
R_UNLESS(file_size <= out_buffer_size, Service::PSC::Time::ResultFailed);
|
||||
|
||||
out_read_size = vfs_file->Read(out_buffer.data(), file_size);
|
||||
R_UNLESS(out_read_size > 0, ResultUnknown);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void ResetTimeZoneBinary() {
|
||||
g_time_zone_binary_romfs = {};
|
||||
g_time_zone_binary_mount_result = ResultUnknown;
|
||||
g_time_zone_scratch_space.clear();
|
||||
g_time_zone_scratch_space.resize(0x2800, 0);
|
||||
}
|
||||
|
||||
Result MountTimeZoneBinary(Core::System& system) {
|
||||
auto& fsc{system.GetFileSystemController()};
|
||||
std::unique_ptr<FileSys::NCA> nca{};
|
||||
|
||||
auto* bis_system = fsc.GetSystemNANDContents();
|
||||
|
||||
R_UNLESS(bis_system, ResultUnknown);
|
||||
|
||||
nca = bis_system->GetEntry(TimeZoneBinaryId, FileSys::ContentRecordType::Data);
|
||||
|
||||
R_UNLESS(nca, ResultUnknown);
|
||||
|
||||
g_time_zone_binary_romfs = FileSys::ExtractRomFS(nca->GetRomFS());
|
||||
|
||||
if (!g_time_zone_binary_romfs) {
|
||||
g_time_zone_binary_romfs = FileSys::ExtractRomFS(
|
||||
FileSys::SystemArchive::SynthesizeSystemArchive(TimeZoneBinaryId));
|
||||
}
|
||||
|
||||
R_UNLESS(g_time_zone_binary_romfs, ResultUnknown);
|
||||
|
||||
g_time_zone_binary_mount_result = ResultSuccess;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void GetTimeZoneBinaryListPath(std::string& out_path) {
|
||||
if (g_time_zone_binary_mount_result != ResultSuccess) {
|
||||
return;
|
||||
}
|
||||
// out_path = fmt::format("{}:/binaryList.txt", "TimeZoneBinary");
|
||||
out_path = "/binaryList.txt";
|
||||
}
|
||||
|
||||
void GetTimeZoneBinaryVersionPath(std::string& out_path) {
|
||||
if (g_time_zone_binary_mount_result != ResultSuccess) {
|
||||
return;
|
||||
}
|
||||
// out_path = fmt::format("{}:/version.txt", "TimeZoneBinary");
|
||||
out_path = "/version.txt";
|
||||
}
|
||||
|
||||
void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name) {
|
||||
if (g_time_zone_binary_mount_result != ResultSuccess) {
|
||||
return;
|
||||
}
|
||||
// out_path = fmt::format("{}:/zoneinfo/{}", "TimeZoneBinary", name);
|
||||
out_path = fmt::format("/zoneinfo/{}", name.name.data());
|
||||
}
|
||||
|
||||
bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name) {
|
||||
std::string path{};
|
||||
GetTimeZoneZonePath(path, name);
|
||||
|
||||
auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)};
|
||||
return vfs_file->GetSize() != 0;
|
||||
}
|
||||
|
||||
u32 GetTimeZoneCount() {
|
||||
std::string path{};
|
||||
GetTimeZoneBinaryListPath(path);
|
||||
|
||||
size_t bytes_read{};
|
||||
if (TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, 0x2800, path) != ResultSuccess) {
|
||||
return 0;
|
||||
}
|
||||
if (bytes_read == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto chars = std::span(reinterpret_cast<char*>(g_time_zone_scratch_space.data()), bytes_read);
|
||||
u32 count{};
|
||||
for (auto chr : chars) {
|
||||
if (chr == '\n') {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version) {
|
||||
std::string path{};
|
||||
GetTimeZoneBinaryVersionPath(path);
|
||||
|
||||
auto rule_version_buffer{std::span(reinterpret_cast<u8*>(&out_rule_version),
|
||||
sizeof(Service::PSC::Time::RuleVersion))};
|
||||
size_t bytes_read{};
|
||||
R_TRY(TimeZoneReadBinary(bytes_read, rule_version_buffer, rule_version_buffer.size_bytes(),
|
||||
path));
|
||||
|
||||
rule_version_buffer[bytes_read] = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
|
||||
Service::PSC::Time::LocationName& name) {
|
||||
std::string path{};
|
||||
GetTimeZoneZonePath(path, name);
|
||||
|
||||
size_t bytes_read{};
|
||||
R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space,
|
||||
g_time_zone_scratch_space.size(), path));
|
||||
|
||||
out_rule = std::span(g_time_zone_scratch_space.data(), bytes_read);
|
||||
out_rule_size = bytes_read;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetTimeZoneLocationList(u32& out_count,
|
||||
std::vector<Service::PSC::Time::LocationName>& out_names,
|
||||
size_t max_names, u32 index) {
|
||||
std::string path{};
|
||||
GetTimeZoneBinaryListPath(path);
|
||||
|
||||
size_t bytes_read{};
|
||||
R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space,
|
||||
g_time_zone_scratch_space.size(), path));
|
||||
|
||||
out_count = 0;
|
||||
R_SUCCEED_IF(bytes_read == 0);
|
||||
|
||||
Service::PSC::Time::LocationName current_name{};
|
||||
size_t current_name_len{};
|
||||
std::span<const u8> chars{g_time_zone_scratch_space};
|
||||
u32 name_count{};
|
||||
|
||||
for (auto chr : chars) {
|
||||
if (chr == '\r') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chr == '\n') {
|
||||
if (name_count >= index) {
|
||||
out_names.push_back(current_name);
|
||||
out_count++;
|
||||
if (out_count >= max_names) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
name_count++;
|
||||
current_name_len = 0;
|
||||
current_name = {};
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chr == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
R_UNLESS(current_name_len <= current_name.name.size() - 2,
|
||||
Service::PSC::Time::ResultFailed);
|
||||
|
||||
current_name.name[current_name_len++] = chr;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
32
src/core/hle/service/glue/time/time_zone_binary.h
Executable file
32
src/core/hle/service/glue/time/time_zone_binary.h
Executable file
@@ -0,0 +1,32 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
|
||||
void ResetTimeZoneBinary();
|
||||
Result MountTimeZoneBinary(Core::System& system);
|
||||
void GetTimeZoneBinaryListPath(std::string& out_path);
|
||||
void GetTimeZoneBinaryVersionPath(std::string& out_path);
|
||||
void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name);
|
||||
bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name);
|
||||
u32 GetTimeZoneCount();
|
||||
Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version);
|
||||
Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
|
||||
Service::PSC::Time::LocationName& name);
|
||||
Result GetTimeZoneLocationList(u32& out_count,
|
||||
std::vector<Service::PSC::Time::LocationName>& out_names,
|
||||
size_t max_names, u32 index);
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
338
src/core/hle/service/glue/time/worker.cpp
Executable file
338
src/core/hle/service/glue/time/worker.cpp
Executable file
@@ -0,0 +1,338 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/glue/time/file_timestamp_worker.h"
|
||||
#include "core/hle/service/glue/time/standard_steady_clock_resource.h"
|
||||
#include "core/hle/service/glue/time/worker.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
#include "core/hle/service/psc/time/service_manager.h"
|
||||
#include "core/hle/service/psc/time/static.h"
|
||||
#include "core/hle/service/psc/time/system_clock.h"
|
||||
#include "core/hle/service/set/system_settings_server.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
namespace {
|
||||
|
||||
bool g_ig_report_network_clock_context_set{};
|
||||
Service::PSC::Time::SystemClockContext g_report_network_clock_context{};
|
||||
bool g_ig_report_ephemeral_clock_context_set{};
|
||||
Service::PSC::Time::SystemClockContext g_report_ephemeral_clock_context{};
|
||||
|
||||
template <typename T>
|
||||
T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys,
|
||||
const char* category, const char* name) {
|
||||
std::vector<u8> interval_buf;
|
||||
auto res = set_sys->GetSettingsItemValue(interval_buf, category, name);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
T v{};
|
||||
std::memcpy(&v, interval_buf.data(), sizeof(T));
|
||||
return v;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource,
|
||||
FileTimestampWorker& file_timestamp_worker)
|
||||
: m_system{system}, m_ctx{m_system, "Glue:58"}, m_event{m_ctx.CreateEvent("Glue:58:Event")},
|
||||
m_steady_clock_resource{steady_clock_resource},
|
||||
m_file_timestamp_worker{file_timestamp_worker}, m_timer_steady_clock{m_ctx.CreateEvent(
|
||||
"Glue:58:SteadyClockTimerEvent")},
|
||||
m_timer_file_system{m_ctx.CreateEvent("Glue:58:FileTimeTimerEvent")},
|
||||
m_alarm_worker{m_system, m_steady_clock_resource}, m_pm_state_change_handler{m_alarm_worker} {
|
||||
g_ig_report_network_clock_context_set = false;
|
||||
g_report_network_clock_context = {};
|
||||
g_ig_report_ephemeral_clock_context_set = false;
|
||||
g_report_ephemeral_clock_context = {};
|
||||
|
||||
m_timer_steady_clock_timing_event = Core::Timing::CreateEvent(
|
||||
"Time::SteadyClockEvent",
|
||||
[this](s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
m_timer_steady_clock->Signal();
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
m_timer_file_system_timing_event = Core::Timing::CreateEvent(
|
||||
"Time::SteadyClockEvent",
|
||||
[this](s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
m_timer_file_system->Signal();
|
||||
return std::nullopt;
|
||||
});
|
||||
}
|
||||
|
||||
TimeWorker::~TimeWorker() {
|
||||
m_local_clock_event->Signal();
|
||||
m_network_clock_event->Signal();
|
||||
m_ephemeral_clock_event->Signal();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(16));
|
||||
|
||||
m_thread.request_stop();
|
||||
m_event->Signal();
|
||||
m_thread.join();
|
||||
|
||||
m_ctx.CloseEvent(m_event);
|
||||
m_system.CoreTiming().UnscheduleEvent(m_timer_steady_clock_timing_event);
|
||||
m_ctx.CloseEvent(m_timer_steady_clock);
|
||||
m_system.CoreTiming().UnscheduleEvent(m_timer_file_system_timing_event);
|
||||
m_ctx.CloseEvent(m_timer_file_system);
|
||||
}
|
||||
|
||||
void TimeWorker::Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm,
|
||||
std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys) {
|
||||
m_set_sys = std::move(set_sys);
|
||||
m_time_m =
|
||||
m_system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true);
|
||||
m_time_sm = std::move(time_sm);
|
||||
|
||||
m_alarm_worker.Initialize(m_time_m);
|
||||
|
||||
auto steady_clock_interval_m = GetSettingsItemValue<s32>(
|
||||
m_set_sys, "time", "standard_steady_clock_rtc_update_interval_minutes");
|
||||
|
||||
auto one_minute_ns{
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()};
|
||||
s64 steady_clock_interval_ns{steady_clock_interval_m * one_minute_ns};
|
||||
|
||||
m_system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0),
|
||||
std::chrono::nanoseconds(steady_clock_interval_ns),
|
||||
m_timer_steady_clock_timing_event);
|
||||
|
||||
auto fs_notify_time_s =
|
||||
GetSettingsItemValue<s32>(m_set_sys, "time", "notify_time_to_fs_interval_seconds");
|
||||
auto one_second_ns{
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
|
||||
s64 fs_notify_time_ns{fs_notify_time_s * one_second_ns};
|
||||
|
||||
m_system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0),
|
||||
std::chrono::nanoseconds(fs_notify_time_ns),
|
||||
m_timer_file_system_timing_event);
|
||||
|
||||
auto res = m_time_sm->GetStandardLocalSystemClock(m_local_clock);
|
||||
ASSERT(res == ResultSuccess);
|
||||
res = m_time_m->GetStandardLocalClockOperationEvent(&m_local_clock_event);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
res = m_time_sm->GetStandardNetworkSystemClock(m_network_clock);
|
||||
ASSERT(res == ResultSuccess);
|
||||
res = m_time_m->GetStandardNetworkClockOperationEventForServiceManager(&m_network_clock_event);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
res = m_time_sm->GetEphemeralNetworkSystemClock(m_ephemeral_clock);
|
||||
ASSERT(res == ResultSuccess);
|
||||
res =
|
||||
m_time_m->GetEphemeralNetworkClockOperationEventForServiceManager(&m_ephemeral_clock_event);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
res = m_time_m->GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(
|
||||
&m_standard_user_auto_correct_clock_event);
|
||||
ASSERT(res == ResultSuccess);
|
||||
}
|
||||
|
||||
void TimeWorker::StartThread() {
|
||||
m_thread = std::jthread(std::bind_front(&TimeWorker::ThreadFunc, this));
|
||||
}
|
||||
|
||||
void TimeWorker::ThreadFunc(std::stop_token stop_token) {
|
||||
Common::SetCurrentThreadName("TimeWorker");
|
||||
Common::SetCurrentThreadPriority(Common::ThreadPriority::Low);
|
||||
|
||||
enum class EventType {
|
||||
Exit = 0,
|
||||
IpmModuleService_GetEvent = 1,
|
||||
PowerStateChange = 2,
|
||||
SignalAlarms = 3,
|
||||
UpdateLocalSystemClock = 4,
|
||||
UpdateNetworkSystemClock = 5,
|
||||
UpdateEphemeralSystemClock = 6,
|
||||
UpdateSteadyClock = 7,
|
||||
UpdateFileTimestamp = 8,
|
||||
AutoCorrect = 9,
|
||||
Max = 10,
|
||||
};
|
||||
|
||||
s32 num_objs{};
|
||||
std::array<Kernel::KSynchronizationObject*, static_cast<u32>(EventType::Max)> wait_objs{};
|
||||
std::array<EventType, static_cast<u32>(EventType::Max)> wait_indices{};
|
||||
|
||||
const auto AddWaiter{
|
||||
[&](Kernel::KSynchronizationObject* synchronization_object, EventType type) {
|
||||
// Open a new reference to the object.
|
||||
synchronization_object->Open();
|
||||
|
||||
// Insert into the list.
|
||||
wait_indices[num_objs] = type;
|
||||
wait_objs[num_objs++] = synchronization_object;
|
||||
}};
|
||||
|
||||
while (!stop_token.stop_requested()) {
|
||||
SCOPE_EXIT({
|
||||
for (s32 i = 0; i < num_objs; i++) {
|
||||
wait_objs[i]->Close();
|
||||
}
|
||||
});
|
||||
|
||||
num_objs = {};
|
||||
wait_objs = {};
|
||||
if (m_pm_state_change_handler.m_priority != 0) {
|
||||
AddWaiter(&m_event->GetReadableEvent(), EventType::Exit);
|
||||
// TODO
|
||||
// AddWaiter(gIPmModuleService::GetEvent(), 1);
|
||||
AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange);
|
||||
} else {
|
||||
AddWaiter(&m_event->GetReadableEvent(), EventType::Exit);
|
||||
// TODO
|
||||
// AddWaiter(gIPmModuleService::GetEvent(), 1);
|
||||
AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange);
|
||||
AddWaiter(&m_alarm_worker.GetTimerEvent().GetReadableEvent(), EventType::SignalAlarms);
|
||||
AddWaiter(&m_local_clock_event->GetReadableEvent(), EventType::UpdateLocalSystemClock);
|
||||
AddWaiter(&m_network_clock_event->GetReadableEvent(),
|
||||
EventType::UpdateNetworkSystemClock);
|
||||
AddWaiter(&m_ephemeral_clock_event->GetReadableEvent(),
|
||||
EventType::UpdateEphemeralSystemClock);
|
||||
AddWaiter(&m_timer_steady_clock->GetReadableEvent(), EventType::UpdateSteadyClock);
|
||||
AddWaiter(&m_timer_file_system->GetReadableEvent(), EventType::UpdateFileTimestamp);
|
||||
AddWaiter(&m_standard_user_auto_correct_clock_event->GetReadableEvent(),
|
||||
EventType::AutoCorrect);
|
||||
}
|
||||
|
||||
s32 out_index{-1};
|
||||
Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(),
|
||||
num_objs, -1);
|
||||
ASSERT(out_index >= 0 && out_index < num_objs);
|
||||
|
||||
if (stop_token.stop_requested()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (wait_indices[out_index]) {
|
||||
case EventType::Exit:
|
||||
return;
|
||||
|
||||
case EventType::IpmModuleService_GetEvent:
|
||||
// TODO
|
||||
// IPmModuleService::GetEvent()
|
||||
// clear the event
|
||||
// Handle power state change event
|
||||
break;
|
||||
|
||||
case EventType::PowerStateChange:
|
||||
m_alarm_worker.GetEvent().Clear();
|
||||
if (m_pm_state_change_handler.m_priority <= 1) {
|
||||
m_alarm_worker.OnPowerStateChanged();
|
||||
}
|
||||
break;
|
||||
|
||||
case EventType::SignalAlarms:
|
||||
m_alarm_worker.GetTimerEvent().Clear();
|
||||
m_time_m->CheckAndSignalAlarms();
|
||||
break;
|
||||
|
||||
case EventType::UpdateLocalSystemClock: {
|
||||
m_local_clock_event->Clear();
|
||||
|
||||
Service::PSC::Time::SystemClockContext context{};
|
||||
auto res = m_local_clock->GetSystemClockContext(context);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
m_set_sys->SetUserSystemClockContext(context);
|
||||
|
||||
m_file_timestamp_worker.SetFilesystemPosixTime();
|
||||
} break;
|
||||
|
||||
case EventType::UpdateNetworkSystemClock: {
|
||||
m_network_clock_event->Clear();
|
||||
Service::PSC::Time::SystemClockContext context{};
|
||||
auto res = m_network_clock->GetSystemClockContext(context);
|
||||
ASSERT(res == ResultSuccess);
|
||||
m_set_sys->SetNetworkSystemClockContext(context);
|
||||
|
||||
s64 time{};
|
||||
if (m_network_clock->GetCurrentTime(time) != ResultSuccess) {
|
||||
break;
|
||||
}
|
||||
|
||||
[[maybe_unused]] auto offset_before{
|
||||
g_ig_report_network_clock_context_set ? g_report_network_clock_context.offset : 0};
|
||||
// TODO system report "standard_netclock_operation"
|
||||
// "clock_time" = time
|
||||
// "context_offset_before" = offset_before
|
||||
// "context_offset_after" = context.offset
|
||||
g_report_network_clock_context = context;
|
||||
if (!g_ig_report_network_clock_context_set) {
|
||||
g_ig_report_network_clock_context_set = true;
|
||||
}
|
||||
|
||||
m_file_timestamp_worker.SetFilesystemPosixTime();
|
||||
} break;
|
||||
|
||||
case EventType::UpdateEphemeralSystemClock: {
|
||||
m_ephemeral_clock_event->Clear();
|
||||
|
||||
Service::PSC::Time::SystemClockContext context{};
|
||||
auto res = m_ephemeral_clock->GetSystemClockContext(context);
|
||||
if (res != ResultSuccess) {
|
||||
break;
|
||||
}
|
||||
|
||||
s64 time{};
|
||||
res = m_ephemeral_clock->GetCurrentTime(time);
|
||||
if (res != ResultSuccess) {
|
||||
break;
|
||||
}
|
||||
|
||||
[[maybe_unused]] auto offset_before{g_ig_report_ephemeral_clock_context_set
|
||||
? g_report_ephemeral_clock_context.offset
|
||||
: 0};
|
||||
// TODO system report "ephemeral_netclock_operation"
|
||||
// "clock_time" = time
|
||||
// "context_offset_before" = offset_before
|
||||
// "context_offset_after" = context.offset
|
||||
g_report_ephemeral_clock_context = context;
|
||||
if (!g_ig_report_ephemeral_clock_context_set) {
|
||||
g_ig_report_ephemeral_clock_context_set = true;
|
||||
}
|
||||
} break;
|
||||
|
||||
case EventType::UpdateSteadyClock:
|
||||
m_timer_steady_clock->Clear();
|
||||
|
||||
m_steady_clock_resource.UpdateTime();
|
||||
m_time_m->SetStandardSteadyClockBaseTime(m_steady_clock_resource.GetTime());
|
||||
break;
|
||||
|
||||
case EventType::UpdateFileTimestamp:
|
||||
m_timer_file_system->Clear();
|
||||
|
||||
m_file_timestamp_worker.SetFilesystemPosixTime();
|
||||
break;
|
||||
|
||||
case EventType::AutoCorrect: {
|
||||
m_standard_user_auto_correct_clock_event->Clear();
|
||||
|
||||
bool automatic_correction{};
|
||||
auto res = m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled(
|
||||
automatic_correction);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
Service::PSC::Time::SteadyClockTimePoint time_point{};
|
||||
res = m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
|
||||
ASSERT(res == ResultSuccess);
|
||||
|
||||
m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
|
||||
m_set_sys->SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
|
||||
} break;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
64
src/core/hle/service/glue/time/worker.h
Executable file
64
src/core/hle/service/glue/time/worker.h
Executable file
@@ -0,0 +1,64 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/glue/time/alarm_worker.h"
|
||||
#include "core/hle/service/glue/time/pm_state_change_handler.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
|
||||
namespace Service::Set {
|
||||
class ISystemSettingsServer;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
class StaticService;
|
||||
class SystemClock;
|
||||
} // namespace Service::PSC::Time
|
||||
|
||||
namespace Service::Glue::Time {
|
||||
class FileTimestampWorker;
|
||||
class StandardSteadyClockResource;
|
||||
|
||||
class TimeWorker {
|
||||
public:
|
||||
explicit TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource,
|
||||
FileTimestampWorker& file_timestamp_worker);
|
||||
~TimeWorker();
|
||||
|
||||
void Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm,
|
||||
std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys);
|
||||
|
||||
void StartThread();
|
||||
|
||||
private:
|
||||
void ThreadFunc(std::stop_token stop_token);
|
||||
|
||||
Core::System& m_system;
|
||||
KernelHelpers::ServiceContext m_ctx;
|
||||
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
|
||||
|
||||
std::jthread m_thread;
|
||||
Kernel::KEvent* m_event{};
|
||||
std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m;
|
||||
std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm;
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock> m_network_clock;
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock> m_local_clock;
|
||||
std::shared_ptr<Service::PSC::Time::SystemClock> m_ephemeral_clock;
|
||||
StandardSteadyClockResource& m_steady_clock_resource;
|
||||
FileTimestampWorker& m_file_timestamp_worker;
|
||||
Kernel::KEvent* m_local_clock_event{};
|
||||
Kernel::KEvent* m_network_clock_event{};
|
||||
Kernel::KEvent* m_ephemeral_clock_event{};
|
||||
Kernel::KEvent* m_standard_user_auto_correct_clock_event{};
|
||||
Kernel::KEvent* m_timer_steady_clock{};
|
||||
std::shared_ptr<Core::Timing::EventType> m_timer_steady_clock_timing_event;
|
||||
Kernel::KEvent* m_timer_file_system{};
|
||||
std::shared_ptr<Core::Timing::EventType> m_timer_file_system_timing_event;
|
||||
AlarmWorker m_alarm_worker;
|
||||
PmStateChangeHandler m_pm_state_change_handler;
|
||||
};
|
||||
|
||||
} // namespace Service::Glue::Time
|
||||
@@ -18,23 +18,23 @@ namespace Service::HID {
|
||||
|
||||
void LoopProcess(Core::System& system) {
|
||||
auto server_manager = std::make_unique<ServerManager>(system);
|
||||
std::shared_ptr<ResourceManager> resouce_manager = std::make_shared<ResourceManager>(system);
|
||||
std::shared_ptr<ResourceManager> resource_manager = std::make_shared<ResourceManager>(system);
|
||||
std::shared_ptr<HidFirmwareSettings> firmware_settings =
|
||||
std::make_shared<HidFirmwareSettings>();
|
||||
|
||||
// TODO: Remove this hack until this service is emulated properly.
|
||||
const auto process_list = system.Kernel().GetProcessList();
|
||||
if (!process_list.empty()) {
|
||||
resouce_manager->Initialize();
|
||||
resouce_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true);
|
||||
resource_manager->Initialize();
|
||||
resource_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true);
|
||||
}
|
||||
|
||||
server_manager->RegisterNamedService(
|
||||
"hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings));
|
||||
"hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings));
|
||||
server_manager->RegisterNamedService(
|
||||
"hid:dbg", std::make_shared<IHidDebugServer>(system, resouce_manager));
|
||||
"hid:dbg", std::make_shared<IHidDebugServer>(system, resource_manager));
|
||||
server_manager->RegisterNamedService(
|
||||
"hid:sys", std::make_shared<IHidSystemServer>(system, resouce_manager));
|
||||
"hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager));
|
||||
|
||||
server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system));
|
||||
|
||||
|
||||
@@ -1444,8 +1444,8 @@ void IHidServer::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) {
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, use_center_clamp={}, applet_resource_user_id={}",
|
||||
parameters.use_center_clamp, parameters.applet_resource_user_id);
|
||||
LOG_INFO(Service_HID, "called, use_center_clamp={}, applet_resource_user_id={}",
|
||||
parameters.use_center_clamp, parameters.applet_resource_user_id);
|
||||
|
||||
GetResourceManager()->GetNpad()->SetNpadAnalogStickUseCenterClamp(
|
||||
parameters.applet_resource_user_id, parameters.use_center_clamp);
|
||||
@@ -1466,23 +1466,27 @@ void IHidServer::SetNpadCaptureButtonAssignment(HLERequestContext& ctx) {
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_HID,
|
||||
"(STUBBED) called, npad_styleset={}, applet_resource_user_id={}, button={}",
|
||||
parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button);
|
||||
LOG_INFO(Service_HID, "called, npad_styleset={}, applet_resource_user_id={}, button={}",
|
||||
parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button);
|
||||
|
||||
const auto result = GetResourceManager()->GetNpad()->SetNpadCaptureButtonAssignment(
|
||||
parameters.applet_resource_user_id, parameters.npad_styleset, parameters.button);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidServer::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||
|
||||
const auto result =
|
||||
GetResourceManager()->GetNpad()->ClearNpadCaptureButtonAssignment(applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) {
|
||||
|
||||
@@ -46,7 +46,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
|
||||
{310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"},
|
||||
{311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
|
||||
{312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"},
|
||||
{313, nullptr, "GetNpadCaptureButtonAssignment"},
|
||||
{313, &IHidSystemServer::GetNpadCaptureButtonAssignment, "GetNpadCaptureButtonAssignment"},
|
||||
{314, nullptr, "GetAppletFooterUiType"},
|
||||
{315, &IHidSystemServer::GetAppletDetailedUiType, "GetAppletDetailedUiType"},
|
||||
{316, &IHidSystemServer::GetNpadInterfaceType, "GetNpadInterfaceType"},
|
||||
@@ -54,8 +54,8 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
|
||||
{318, &IHidSystemServer::HasBattery, "HasBattery"},
|
||||
{319, &IHidSystemServer::HasLeftRightBattery, "HasLeftRightBattery"},
|
||||
{321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"},
|
||||
{322, &IHidSystemServer::GetIrSensorState, "GetIrSensorState"},
|
||||
{323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
|
||||
{322, &IHidSystemServer::SetNpadSystemExtStateEnabled, "SetNpadSystemExtStateEnabled"},
|
||||
{323, nullptr, "GetLastActiveUniquePad"},
|
||||
{324, nullptr, "GetUniquePadButtonSet"},
|
||||
{325, nullptr, "GetUniquePadColor"},
|
||||
{326, nullptr, "GetUniquePadAppletDetailedUiType"},
|
||||
@@ -251,25 +251,38 @@ void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void IHidSystemServer::EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||
|
||||
GetResourceManager()->GetNpad()->AssigningSingleOnSlSrPress(applet_resource_user_id, true);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHidSystemServer::DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||
|
||||
GetResourceManager()->GetNpad()->AssigningSingleOnSlSrPress(applet_resource_user_id, false);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_HID, "(STUBBED) called"); // Spams a lot when controller applet is running
|
||||
Core::HID::NpadIdType npad_id{};
|
||||
const Result result = GetResourceManager()->GetNpad()->GetLastActiveNpad(npad_id);
|
||||
|
||||
LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(0); // Dont forget to fix this
|
||||
rb.Push(result);
|
||||
rb.PushEnum(npad_id);
|
||||
}
|
||||
|
||||
void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) {
|
||||
@@ -331,6 +344,27 @@ void IHidSystemServer::SetSupportedNpadStyleSetAll(HLERequestContext& ctx) {
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetNpadCaptureButtonAssignment(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
const auto capture_button_list_size{ctx.GetWriteBufferNumElements<Core::HID::NpadButton>()};
|
||||
|
||||
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||
|
||||
std::vector<Core::HID::NpadButton> capture_button_list(capture_button_list_size);
|
||||
const auto& npad = GetResourceManager()->GetNpad();
|
||||
const u64 list_size =
|
||||
npad->GetNpadCaptureButtonAssignment(capture_button_list, applet_resource_user_id);
|
||||
|
||||
if (list_size != 0) {
|
||||
ctx.WriteBuffer(capture_button_list);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(list_size);
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
@@ -423,13 +457,25 @@ void IHidSystemServer::GetUniquePadsFromNpad(HLERequestContext& ctx) {
|
||||
rb.Push(static_cast<u32>(unique_pads.size()));
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetIrSensorState(HLERequestContext& ctx) {
|
||||
void IHidSystemServer::SetNpadSystemExtStateEnabled(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
bool is_enabled;
|
||||
INSERT_PADDING_BYTES_NOINIT(7);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}",
|
||||
parameters.is_enabled, parameters.applet_resource_user_id);
|
||||
|
||||
const auto result = GetResourceManager()->GetNpad()->SetNpadSystemExtStateEnabled(
|
||||
parameters.applet_resource_user_id, parameters.is_enabled);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
void IHidSystemServer::RegisterAppletResourceUserId(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
@@ -31,13 +31,14 @@ private:
|
||||
void GetNpadFullKeyGripColor(HLERequestContext& ctx);
|
||||
void GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx);
|
||||
void SetSupportedNpadStyleSetAll(HLERequestContext& ctx);
|
||||
void GetNpadCaptureButtonAssignment(HLERequestContext& ctx);
|
||||
void GetAppletDetailedUiType(HLERequestContext& ctx);
|
||||
void GetNpadInterfaceType(HLERequestContext& ctx);
|
||||
void GetNpadLeftRightInterfaceType(HLERequestContext& ctx);
|
||||
void HasBattery(HLERequestContext& ctx);
|
||||
void HasLeftRightBattery(HLERequestContext& ctx);
|
||||
void GetUniquePadsFromNpad(HLERequestContext& ctx);
|
||||
void GetIrSensorState(HLERequestContext& ctx);
|
||||
void SetNpadSystemExtStateEnabled(HLERequestContext& ctx);
|
||||
void RegisterAppletResourceUserId(HLERequestContext& ctx);
|
||||
void UnregisterAppletResourceUserId(HLERequestContext& ctx);
|
||||
void EnableAppletToGetInput(HLERequestContext& ctx);
|
||||
|
||||
@@ -67,7 +67,7 @@ HidBus::~HidBus() {
|
||||
void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) {
|
||||
if (is_hidbus_enabled) {
|
||||
for (std::size_t i = 0; i < devices.size(); ++i) {
|
||||
if (!devices[i].is_device_initializated) {
|
||||
if (!devices[i].is_device_initialized) {
|
||||
continue;
|
||||
}
|
||||
auto& device = devices[i].device;
|
||||
@@ -213,7 +213,7 @@ void HidBus::Initialize(HLERequestContext& ctx) {
|
||||
|
||||
if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) {
|
||||
MakeDevice<RingController>(bus_handle_);
|
||||
devices[device_index.value()].is_device_initializated = true;
|
||||
devices[device_index.value()].is_device_initialized = true;
|
||||
devices[device_index.value()].device->ActivateDevice();
|
||||
cur_entry.is_in_focus = true;
|
||||
cur_entry.is_connected = true;
|
||||
@@ -222,7 +222,7 @@ void HidBus::Initialize(HLERequestContext& ctx) {
|
||||
cur_entry.is_polling_mode = false;
|
||||
} else {
|
||||
MakeDevice<HidbusStubbed>(bus_handle_);
|
||||
devices[device_index.value()].is_device_initializated = true;
|
||||
devices[device_index.value()].is_device_initialized = true;
|
||||
cur_entry.is_in_focus = true;
|
||||
cur_entry.is_connected = false;
|
||||
cur_entry.is_connected_result = ResultSuccess;
|
||||
@@ -261,7 +261,7 @@ void HidBus::Finalize(HLERequestContext& ctx) {
|
||||
const auto entry_index = devices[device_index.value()].handle.internal_index;
|
||||
auto& cur_entry = hidbus_status.entries[entry_index];
|
||||
auto& device = devices[device_index.value()].device;
|
||||
devices[device_index.value()].is_device_initializated = false;
|
||||
devices[device_index.value()].is_device_initialized = false;
|
||||
device->DeactivateDevice();
|
||||
|
||||
cur_entry.is_in_focus = true;
|
||||
|
||||
@@ -89,7 +89,7 @@ private:
|
||||
static_assert(sizeof(HidbusStatusManager) <= 0x1000, "HidbusStatusManager is an invalid size");
|
||||
|
||||
struct HidbusDevice {
|
||||
bool is_device_initializated{};
|
||||
bool is_device_initialized{};
|
||||
BusHandle handle{};
|
||||
std::unique_ptr<HidbusBase> device{nullptr};
|
||||
};
|
||||
|
||||
@@ -182,22 +182,22 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
|
||||
}
|
||||
}
|
||||
|
||||
buffer_x_desciptors.reserve(command_header->num_buf_x_descriptors);
|
||||
buffer_a_desciptors.reserve(command_header->num_buf_a_descriptors);
|
||||
buffer_b_desciptors.reserve(command_header->num_buf_b_descriptors);
|
||||
buffer_w_desciptors.reserve(command_header->num_buf_w_descriptors);
|
||||
buffer_x_descriptors.reserve(command_header->num_buf_x_descriptors);
|
||||
buffer_a_descriptors.reserve(command_header->num_buf_a_descriptors);
|
||||
buffer_b_descriptors.reserve(command_header->num_buf_b_descriptors);
|
||||
buffer_w_descriptors.reserve(command_header->num_buf_w_descriptors);
|
||||
|
||||
for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) {
|
||||
buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>());
|
||||
buffer_x_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>());
|
||||
}
|
||||
for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) {
|
||||
buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
|
||||
buffer_a_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
|
||||
}
|
||||
for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) {
|
||||
buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
|
||||
buffer_b_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
|
||||
}
|
||||
for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) {
|
||||
buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
|
||||
buffer_w_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
|
||||
}
|
||||
|
||||
const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size;
|
||||
@@ -247,7 +247,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
|
||||
IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) {
|
||||
if (command_header->buf_c_descriptor_flags ==
|
||||
IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) {
|
||||
buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
|
||||
buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
|
||||
} else {
|
||||
u32 num_buf_c_descriptors =
|
||||
static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2;
|
||||
@@ -257,7 +257,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
|
||||
ASSERT(num_buf_c_descriptors < 14);
|
||||
|
||||
for (u32 i = 0; i < num_buf_c_descriptors; ++i) {
|
||||
buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
|
||||
buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,19 +234,19 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const {
|
||||
return buffer_x_desciptors;
|
||||
return buffer_x_descriptors;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const {
|
||||
return buffer_a_desciptors;
|
||||
return buffer_a_descriptors;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const {
|
||||
return buffer_b_desciptors;
|
||||
return buffer_b_descriptors;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const {
|
||||
return buffer_c_desciptors;
|
||||
return buffer_c_descriptors;
|
||||
}
|
||||
|
||||
[[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const {
|
||||
@@ -408,11 +408,11 @@ private:
|
||||
std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header;
|
||||
std::optional<IPC::DataPayloadHeader> data_payload_header;
|
||||
std::optional<IPC::DomainMessageHeader> domain_message_header;
|
||||
std::vector<IPC::BufferDescriptorX> buffer_x_desciptors;
|
||||
std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors;
|
||||
std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors;
|
||||
std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors;
|
||||
std::vector<IPC::BufferDescriptorC> buffer_c_desciptors;
|
||||
std::vector<IPC::BufferDescriptorX> buffer_x_descriptors;
|
||||
std::vector<IPC::BufferDescriptorABW> buffer_a_descriptors;
|
||||
std::vector<IPC::BufferDescriptorABW> buffer_b_descriptors;
|
||||
std::vector<IPC::BufferDescriptorABW> buffer_w_descriptors;
|
||||
std::vector<IPC::BufferDescriptorC> buffer_c_descriptors;
|
||||
|
||||
u32_le command{};
|
||||
u64 pid{};
|
||||
|
||||
@@ -65,6 +65,9 @@ Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) {
|
||||
}
|
||||
|
||||
void ServiceContext::CloseEvent(Kernel::KEvent* event) {
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
event->GetReadableEvent().Close();
|
||||
event->Close();
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Service::NFP::AmiiboCrypto {
|
||||
bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
|
||||
const auto& amiibo_data = ntag_file.user_memory;
|
||||
LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", ntag_file.static_lock);
|
||||
LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", ntag_file.compability_container);
|
||||
LOG_DEBUG(Service_NFP, "compatibility_container=0x{0:x}", ntag_file.compatibility_container);
|
||||
LOG_DEBUG(Service_NFP, "write_count={}", static_cast<u16>(amiibo_data.write_counter));
|
||||
|
||||
LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id);
|
||||
@@ -49,7 +49,7 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
|
||||
if (ntag_file.static_lock != 0xE00F) {
|
||||
return false;
|
||||
}
|
||||
if (ntag_file.compability_container != 0xEEFF10F1U) {
|
||||
if (ntag_file.compatibility_container != 0xEEFF10F1U) {
|
||||
return false;
|
||||
}
|
||||
if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) {
|
||||
@@ -78,7 +78,7 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
|
||||
encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2;
|
||||
encoded_data.internal_number = nfc_data.internal_number;
|
||||
encoded_data.static_lock = nfc_data.static_lock;
|
||||
encoded_data.compability_container = nfc_data.compability_container;
|
||||
encoded_data.compatibility_container = nfc_data.compatibility_container;
|
||||
encoded_data.hmac_data = nfc_data.user_memory.hmac_data;
|
||||
encoded_data.constant_value = nfc_data.user_memory.constant_value;
|
||||
encoded_data.write_counter = nfc_data.user_memory.write_counter;
|
||||
@@ -112,7 +112,7 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
|
||||
nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2;
|
||||
nfc_data.internal_number = encoded_data.internal_number;
|
||||
nfc_data.static_lock = encoded_data.static_lock;
|
||||
nfc_data.compability_container = encoded_data.compability_container;
|
||||
nfc_data.compatibility_container = encoded_data.compatibility_container;
|
||||
nfc_data.user_memory.hmac_data = encoded_data.hmac_data;
|
||||
nfc_data.user_memory.constant_value = encoded_data.constant_value;
|
||||
nfc_data.user_memory.write_counter = encoded_data.write_counter;
|
||||
@@ -257,7 +257,7 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou
|
||||
out_data.uid_crc_check2 = in_data.uid_crc_check2;
|
||||
out_data.internal_number = in_data.internal_number;
|
||||
out_data.static_lock = in_data.static_lock;
|
||||
out_data.compability_container = in_data.compability_container;
|
||||
out_data.compatibility_container = in_data.compatibility_container;
|
||||
|
||||
out_data.constant_value = in_data.constant_value;
|
||||
out_data.write_counter = in_data.write_counter;
|
||||
|
||||
@@ -29,7 +29,11 @@
|
||||
#include "core/hle/service/nfc/common/device.h"
|
||||
#include "core/hle/service/nfc/mifare_result.h"
|
||||
#include "core/hle/service/nfc/nfc_result.h"
|
||||
#include "core/hle/service/time/time_manager.h"
|
||||
#include "core/hle/service/psc/time/static.h"
|
||||
#include "core/hle/service/psc/time/steady_clock.h"
|
||||
#include "core/hle/service/psc/time/time_zone_service.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "hid_core/frontend/emulated_controller.h"
|
||||
#include "hid_core/hid_core.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
@@ -75,7 +79,7 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_initalized) {
|
||||
if (!is_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -207,7 +211,7 @@ void NfcDevice::Initialize() {
|
||||
return;
|
||||
}
|
||||
|
||||
is_initalized = npad_device->AddNfcHandle();
|
||||
is_initialized = npad_device->AddNfcHandle();
|
||||
}
|
||||
|
||||
void NfcDevice::Finalize() {
|
||||
@@ -226,7 +230,7 @@ void NfcDevice::Finalize() {
|
||||
}
|
||||
|
||||
device_state = DeviceState::Unavailable;
|
||||
is_initalized = false;
|
||||
is_initialized = false;
|
||||
}
|
||||
|
||||
Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
|
||||
@@ -393,8 +397,7 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet
|
||||
return result;
|
||||
}
|
||||
|
||||
Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
|
||||
std::span<const u8> command_data,
|
||||
Result NfcDevice::SendCommandByPassThrough(const s64& timeout, std::span<const u8> command_data,
|
||||
std::span<u8> out_data) {
|
||||
// Not implemented
|
||||
return ResultSuccess;
|
||||
@@ -1396,27 +1399,41 @@ void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings,
|
||||
}
|
||||
|
||||
NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const {
|
||||
const auto& time_zone_manager =
|
||||
system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
|
||||
Time::TimeZone::CalendarInfo calendar_info{};
|
||||
auto static_service =
|
||||
system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u", true);
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::TimeZoneService> timezone_service{};
|
||||
static_service->GetTimeZoneService(timezone_service);
|
||||
|
||||
Service::PSC::Time::CalendarTime calendar_time{};
|
||||
Service::PSC::Time::CalendarAdditionalInfo additional_info{};
|
||||
|
||||
NFP::AmiiboDate amiibo_date{};
|
||||
|
||||
amiibo_date.SetYear(2000);
|
||||
amiibo_date.SetMonth(1);
|
||||
amiibo_date.SetDay(1);
|
||||
|
||||
if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) {
|
||||
amiibo_date.SetYear(calendar_info.time.year);
|
||||
amiibo_date.SetMonth(calendar_info.time.month);
|
||||
amiibo_date.SetDay(calendar_info.time.day);
|
||||
if (timezone_service->ToCalendarTimeWithMyRule(calendar_time, additional_info, posix_time) ==
|
||||
ResultSuccess) {
|
||||
amiibo_date.SetYear(calendar_time.year);
|
||||
amiibo_date.SetMonth(calendar_time.month);
|
||||
amiibo_date.SetDay(calendar_time.day);
|
||||
}
|
||||
|
||||
return amiibo_date;
|
||||
}
|
||||
|
||||
u64 NfcDevice::GetCurrentPosixTime() const {
|
||||
auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
|
||||
return standard_steady_clock.GetCurrentTimePoint(system).time_point;
|
||||
s64 NfcDevice::GetCurrentPosixTime() const {
|
||||
auto static_service =
|
||||
system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u", true);
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{};
|
||||
static_service->GetStandardSteadyClock(steady_clock);
|
||||
|
||||
Service::PSC::Time::SteadyClockTimePoint time_point{};
|
||||
R_ASSERT(steady_clock->GetCurrentTimePoint(time_point));
|
||||
return time_point.time_point;
|
||||
}
|
||||
|
||||
u64 NfcDevice::RemoveVersionByte(u64 application_id) const {
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "core/hle/service/nfc/nfc_types.h"
|
||||
#include "core/hle/service/nfp/nfp_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
@@ -49,8 +48,8 @@ public:
|
||||
|
||||
Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters);
|
||||
|
||||
Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
|
||||
std::span<const u8> command_data, std::span<u8> out_data);
|
||||
Result SendCommandByPassThrough(const s64& timeout, std::span<const u8> command_data,
|
||||
std::span<u8> out_data);
|
||||
|
||||
Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target);
|
||||
Result Unmount();
|
||||
@@ -108,7 +107,7 @@ private:
|
||||
NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
|
||||
void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) const;
|
||||
NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const;
|
||||
u64 GetCurrentPosixTime() const;
|
||||
s64 GetCurrentPosixTime() const;
|
||||
u64 RemoveVersionByte(u64 application_id) const;
|
||||
void UpdateSettingsCrc();
|
||||
void UpdateRegisterInfoCrc();
|
||||
@@ -126,7 +125,7 @@ private:
|
||||
Kernel::KEvent* deactivate_event = nullptr;
|
||||
Kernel::KEvent* availability_change_event = nullptr;
|
||||
|
||||
bool is_initalized{};
|
||||
bool is_initialized{};
|
||||
NfcProtocol allowed_protocols{};
|
||||
DeviceState device_state{DeviceState::Unavailable};
|
||||
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
#include "core/hle/service/nfc/common/device.h"
|
||||
#include "core/hle/service/nfc/common/device_manager.h"
|
||||
#include "core/hle/service/nfc/nfc_result.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
#include "core/hle/service/time/time_manager.h"
|
||||
#include "core/hle/service/psc/time/static.h"
|
||||
#include "core/hle/service/psc/time/steady_clock.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
#include "hid_core/hid_util.h"
|
||||
|
||||
@@ -82,11 +84,19 @@ Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, std::size_t max
|
||||
continue;
|
||||
}
|
||||
if (skip_fatal_errors) {
|
||||
constexpr u64 MinimumRecoveryTime = 60;
|
||||
auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
|
||||
const u64 elapsed_time = standard_steady_clock.GetCurrentTimePoint(system).time_point -
|
||||
time_since_last_error;
|
||||
constexpr s64 MinimumRecoveryTime = 60;
|
||||
|
||||
auto static_service =
|
||||
system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u",
|
||||
true);
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{};
|
||||
static_service->GetStandardSteadyClock(steady_clock);
|
||||
|
||||
Service::PSC::Time::SteadyClockTimePoint time_point{};
|
||||
R_ASSERT(steady_clock->GetCurrentTimePoint(time_point));
|
||||
|
||||
const s64 elapsed_time = time_point.time_point - time_since_last_error;
|
||||
if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) {
|
||||
continue;
|
||||
}
|
||||
@@ -250,8 +260,7 @@ Result DeviceManager::WriteMifare(u64 device_handle,
|
||||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::SendCommandByPassThrough(u64 device_handle,
|
||||
const Time::Clock::TimeSpanType& timeout,
|
||||
Result DeviceManager::SendCommandByPassThrough(u64 device_handle, const s64& timeout,
|
||||
std::span<const u8> command_data,
|
||||
std::span<u8> out_data) {
|
||||
std::scoped_lock lock{mutex};
|
||||
@@ -741,8 +750,16 @@ Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
|
||||
|
||||
if (operation_result == ResultUnknown112 || operation_result == ResultUnknown114 ||
|
||||
operation_result == ResultUnknown115) {
|
||||
auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
|
||||
time_since_last_error = standard_steady_clock.GetCurrentTimePoint(system).time_point;
|
||||
auto static_service =
|
||||
system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:u", true);
|
||||
|
||||
std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{};
|
||||
static_service->GetStandardSteadyClock(steady_clock);
|
||||
|
||||
Service::PSC::Time::SteadyClockTimePoint time_point{};
|
||||
R_ASSERT(steady_clock->GetCurrentTimePoint(time_point));
|
||||
|
||||
time_since_last_error = time_point.time_point;
|
||||
}
|
||||
|
||||
return operation_result;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "core/hle/service/nfc/nfc_types.h"
|
||||
#include "core/hle/service/nfp/nfp_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
@@ -42,7 +41,7 @@ public:
|
||||
std::span<MifareReadBlockData> read_data);
|
||||
Result WriteMifare(u64 device_handle,
|
||||
std::span<const MifareWriteBlockParameter> write_parameters);
|
||||
Result SendCommandByPassThrough(u64 device_handle, const Time::Clock::TimeSpanType& timeout,
|
||||
Result SendCommandByPassThrough(u64 device_handle, const s64& timeout,
|
||||
std::span<const u8> command_data, std::span<u8> out_data);
|
||||
|
||||
// Nfp device manager
|
||||
@@ -92,7 +91,7 @@ private:
|
||||
const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const;
|
||||
|
||||
bool is_initialized = false;
|
||||
u64 time_since_last_error = 0;
|
||||
s64 time_since_last_error = 0;
|
||||
mutable std::mutex mutex;
|
||||
std::array<std::shared_ptr<NfcDevice>, 10> devices{};
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "core/hle/service/nfc/nfc_result.h"
|
||||
#include "core/hle/service/nfc/nfc_types.h"
|
||||
#include "core/hle/service/nfp/nfp_result.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
|
||||
namespace Service::NFC {
|
||||
@@ -261,10 +260,10 @@ void NfcInterface::WriteMifare(HLERequestContext& ctx) {
|
||||
void NfcInterface::SendCommandByPassThrough(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_handle{rp.Pop<u64>()};
|
||||
const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
|
||||
const auto timeout{rp.PopRaw<s64>()};
|
||||
const auto command_data{ctx.ReadBuffer()};
|
||||
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
|
||||
device_handle, timeout.ToSeconds(), command_data.size());
|
||||
device_handle, timeout, command_data.size());
|
||||
|
||||
std::vector<u8> out_data(1);
|
||||
auto result =
|
||||
|
||||
@@ -243,12 +243,12 @@ static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid si
|
||||
struct NTAG215File {
|
||||
u8 uid_crc_check2;
|
||||
u8 internal_number;
|
||||
u16 static_lock; // Set defined pages as read only
|
||||
u32 compability_container; // Defines available memory
|
||||
HashData hmac_data; // Hash
|
||||
u8 constant_value; // Must be A5
|
||||
u16_be write_counter; // Number of times the amiibo has been written?
|
||||
u8 amiibo_version; // Amiibo file version
|
||||
u16 static_lock; // Set defined pages as read only
|
||||
u32 compatibility_container; // Defines available memory
|
||||
HashData hmac_data; // Hash
|
||||
u8 constant_value; // Must be A5
|
||||
u16_be write_counter; // Number of times the amiibo has been written?
|
||||
u8 amiibo_version; // Amiibo file version
|
||||
AmiiboSettings settings;
|
||||
Service::Mii::Ver3StoreData owner_mii; // Mii data
|
||||
u64_be application_id; // Game id
|
||||
@@ -278,7 +278,7 @@ struct EncryptedNTAG215File {
|
||||
u8 uuid_crc_check2;
|
||||
u8 internal_number;
|
||||
u16 static_lock; // Set defined pages as read only
|
||||
u32 compability_container; // Defines available memory
|
||||
u32 compatibility_container; // Defines available memory
|
||||
EncryptedAmiiboFile user_memory; // Writable data
|
||||
u32 dynamic_lock; // Dynamic lock
|
||||
u32 CFG0; // Defines memory protected by password
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/ns/language.h"
|
||||
#include "core/hle/service/set/set.h"
|
||||
#include "core/hle/service/set/settings_server.h"
|
||||
|
||||
namespace Service::NS {
|
||||
|
||||
@@ -415,4 +415,4 @@ std::optional<Set::LanguageCode> ConvertToLanguageCode(const ApplicationLanguage
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
} // namespace Service::NS
|
||||
} // namespace Service::NS
|
||||
|
||||
@@ -5,10 +5,7 @@
|
||||
|
||||
#include <optional>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::Set {
|
||||
enum class LanguageCode : u64;
|
||||
}
|
||||
#include "core/hle/service/set/system_settings.h"
|
||||
|
||||
namespace Service::NS {
|
||||
/// This is nn::ns::detail::ApplicationLanguage
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
#include "core/hle/service/ns/pdm_qry.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/set/set.h"
|
||||
#include "core/hle/service/set/settings_server.h"
|
||||
|
||||
namespace Service::NS {
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ private:
|
||||
u64_le align;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
|
||||
static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitializeEx is incorrect size");
|
||||
|
||||
struct IoctlFreeSpace {
|
||||
u64_le offset{};
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Service::Nvidia::Devices {
|
||||
nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_)
|
||||
: nvdevice{system_}, events_interface{events_interface_} {
|
||||
error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier");
|
||||
unknown_event = events_interface.CreateEvent("CtrlGpuUknownEvent");
|
||||
unknown_event = events_interface.CreateEvent("CtrlGpuUnknownEvent");
|
||||
}
|
||||
nvhost_ctrl_gpu::~nvhost_ctrl_gpu() {
|
||||
events_interface.FreeEvent(error_notifier_event);
|
||||
|
||||
@@ -51,7 +51,7 @@ enum class NvResult : u32 {
|
||||
DispNoDisplaysAttached = 0x20003,
|
||||
DispModeNotSupported = 0x20004,
|
||||
DispNotFound = 0x20005,
|
||||
DispAttachDissallowed = 0x20006,
|
||||
DispAttachDisallowed = 0x20006,
|
||||
DispTypeNotSupported = 0x20007,
|
||||
DispAuthenticationFailed = 0x20008,
|
||||
DispNotAttached = 0x20009,
|
||||
|
||||
@@ -54,8 +54,8 @@ public:
|
||||
|
||||
class IClkrstSession final : public ServiceFramework<IClkrstSession> {
|
||||
public:
|
||||
explicit IClkrstSession(Core::System& system_, DeviceCode deivce_code_)
|
||||
: ServiceFramework{system_, "IClkrstSession"}, deivce_code(deivce_code_) {
|
||||
explicit IClkrstSession(Core::System& system_, DeviceCode device_code_)
|
||||
: ServiceFramework{system_, "IClkrstSession"}, device_code(device_code_) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "SetClockEnabled"},
|
||||
@@ -93,7 +93,7 @@ private:
|
||||
rb.Push<u32>(clock_rate);
|
||||
}
|
||||
|
||||
DeviceCode deivce_code;
|
||||
DeviceCode device_code;
|
||||
u32 clock_rate{};
|
||||
};
|
||||
|
||||
@@ -118,9 +118,9 @@ private:
|
||||
void OpenSession(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>());
|
||||
const auto unkonwn_input = rp.Pop<u32>();
|
||||
const auto unknown_input = rp.Pop<u32>();
|
||||
|
||||
LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unkonwn_input);
|
||||
LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unknown_input);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
@@ -4,9 +4,13 @@
|
||||
#include <memory>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/psc/psc.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/psc/time/manager.h"
|
||||
#include "core/hle/service/psc/time/power_state_service.h"
|
||||
#include "core/hle/service/psc/time/service_manager.h"
|
||||
#include "core/hle/service/psc/time/static.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::PSC {
|
||||
@@ -76,6 +80,17 @@ void LoopProcess(Core::System& system) {
|
||||
|
||||
server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system));
|
||||
server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system));
|
||||
|
||||
auto time = std::make_shared<Time::TimeManager>(system);
|
||||
|
||||
server_manager->RegisterNamedService(
|
||||
"time:m", std::make_shared<Time::ServiceManager>(system, time, server_manager.get()));
|
||||
server_manager->RegisterNamedService(
|
||||
"time:su", std::make_shared<Time::StaticService>(
|
||||
system, Time::StaticServiceSetupInfo{0, 0, 0, 0, 0, 1}, time, "time:su"));
|
||||
server_manager->RegisterNamedService("time:al",
|
||||
std::make_shared<Time::IAlarmService>(system, time));
|
||||
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
|
||||
|
||||
209
src/core/hle/service/psc/time/alarms.cpp
Executable file
209
src/core/hle/service/psc/time/alarms.cpp
Executable file
@@ -0,0 +1,209 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/psc/time/alarms.h"
|
||||
#include "core/hle/service/psc/time/manager.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
Alarm::Alarm(Core::System& system, KernelHelpers::ServiceContext& ctx, AlarmType type)
|
||||
: m_ctx{ctx}, m_event{ctx.CreateEvent("Psc:Alarm:Event")} {
|
||||
m_event->Clear();
|
||||
|
||||
switch (type) {
|
||||
case WakeupAlarm:
|
||||
m_priority = 1;
|
||||
break;
|
||||
case BackgroundTaskAlarm:
|
||||
m_priority = 0;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Alarm::~Alarm() {
|
||||
m_ctx.CloseEvent(m_event);
|
||||
}
|
||||
|
||||
Alarms::Alarms(Core::System& system, StandardSteadyClockCore& steady_clock,
|
||||
PowerStateRequestManager& power_state_request_manager)
|
||||
: m_system{system}, m_ctx{system, "Psc:Alarms"}, m_steady_clock{steady_clock},
|
||||
m_power_state_request_manager{power_state_request_manager}, m_event{m_ctx.CreateEvent(
|
||||
"Psc:Alarms:Event")} {}
|
||||
|
||||
Alarms::~Alarms() {
|
||||
m_ctx.CloseEvent(m_event);
|
||||
}
|
||||
|
||||
Result Alarms::Enable(Alarm& alarm, s64 time) {
|
||||
R_UNLESS(m_steady_clock.IsInitialized(), ResultClockUninitialized);
|
||||
|
||||
std::scoped_lock l{m_mutex};
|
||||
R_UNLESS(alarm.IsLinked(), ResultAlarmNotRegistered);
|
||||
|
||||
auto time_ns{time + m_steady_clock.GetRawTime()};
|
||||
auto one_second_ns{
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
|
||||
time_ns = Common::AlignUp(time_ns, one_second_ns);
|
||||
alarm.SetAlertTime(time_ns);
|
||||
|
||||
Insert(alarm);
|
||||
R_RETURN(UpdateClosestAndSignal());
|
||||
}
|
||||
|
||||
void Alarms::Disable(Alarm& alarm) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
if (!alarm.IsLinked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Erase(alarm);
|
||||
UpdateClosestAndSignal();
|
||||
}
|
||||
|
||||
void Alarms::CheckAndSignal() {
|
||||
std::scoped_lock l{m_mutex};
|
||||
if (m_alarms.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool alarm_signalled{false};
|
||||
for (auto& alarm : m_alarms) {
|
||||
if (m_steady_clock.GetRawTime() >= alarm.GetAlertTime()) {
|
||||
alarm.Signal();
|
||||
alarm.Lock();
|
||||
Erase(alarm);
|
||||
|
||||
m_power_state_request_manager.UpdatePendingPowerStateRequestPriority(
|
||||
alarm.GetPriority());
|
||||
alarm_signalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!alarm_signalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_power_state_request_manager.SignalPowerStateRequestAvailability();
|
||||
UpdateClosestAndSignal();
|
||||
}
|
||||
|
||||
bool Alarms::GetClosestAlarm(Alarm** out_alarm) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
auto alarm = m_alarms.empty() ? nullptr : std::addressof(m_alarms.front());
|
||||
*out_alarm = alarm;
|
||||
return alarm != nullptr;
|
||||
}
|
||||
|
||||
void Alarms::Insert(Alarm& alarm) {
|
||||
// Alarms are sorted by alert time, then priority
|
||||
auto it{m_alarms.begin()};
|
||||
while (it != m_alarms.end()) {
|
||||
if (alarm.GetAlertTime() < it->GetAlertTime() ||
|
||||
(alarm.GetAlertTime() == it->GetAlertTime() &&
|
||||
alarm.GetPriority() < it->GetPriority())) {
|
||||
m_alarms.insert(it, alarm);
|
||||
return;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
m_alarms.push_back(alarm);
|
||||
}
|
||||
|
||||
void Alarms::Erase(Alarm& alarm) {
|
||||
m_alarms.erase(m_alarms.iterator_to(alarm));
|
||||
}
|
||||
|
||||
Result Alarms::UpdateClosestAndSignal() {
|
||||
m_closest_alarm = m_alarms.empty() ? nullptr : std::addressof(m_alarms.front());
|
||||
R_SUCCEED_IF(m_closest_alarm == nullptr);
|
||||
|
||||
m_event->Signal();
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
IAlarmService::IAlarmService(Core::System& system_, std::shared_ptr<TimeManager> manager)
|
||||
: ServiceFramework{system_, "time:al"}, m_system{system}, m_alarms{manager->m_alarms} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IAlarmService::CreateWakeupAlarm, "CreateWakeupAlarm"},
|
||||
{1, &IAlarmService::CreateBackgroundTaskAlarm, "CreateBackgroundTaskAlarm"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void IAlarmService::CreateWakeupAlarm(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::WakeupAlarm);
|
||||
}
|
||||
|
||||
void IAlarmService::CreateBackgroundTaskAlarm(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::BackgroundTaskAlarm);
|
||||
}
|
||||
|
||||
ISteadyClockAlarm::ISteadyClockAlarm(Core::System& system_, Alarms& alarms, AlarmType type)
|
||||
: ServiceFramework{system_, "ISteadyClockAlarm"}, m_ctx{system, "Psc:ISteadyClockAlarm"},
|
||||
m_alarms{alarms}, m_alarm{system, m_ctx, type} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISteadyClockAlarm::GetAlarmEvent, "GetAlarmEvent"},
|
||||
{1, &ISteadyClockAlarm::Enable, "Enable"},
|
||||
{2, &ISteadyClockAlarm::Disable, "Disable"},
|
||||
{3, &ISteadyClockAlarm::IsEnabled, "IsEnabled"},
|
||||
{10, nullptr, "CreateWakeLock"},
|
||||
{11, nullptr, "DestroyWakeLock"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void ISteadyClockAlarm::GetAlarmEvent(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(m_alarm.GetEventHandle());
|
||||
}
|
||||
|
||||
void ISteadyClockAlarm::Enable(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto time{rp.Pop<s64>()};
|
||||
|
||||
auto res = m_alarms.Enable(m_alarm, time);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void ISteadyClockAlarm::Disable(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
m_alarms.Disable(m_alarm);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISteadyClockAlarm::IsEnabled(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<bool>(m_alarm.IsLinked());
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
139
src/core/hle/service/psc/time/alarms.h
Executable file
139
src/core/hle/service/psc/time/alarms.h
Executable file
@@ -0,0 +1,139 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
#include "core/hle/service/psc/time/power_state_request_manager.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
class TimeManager;
|
||||
|
||||
enum AlarmType : u32 {
|
||||
WakeupAlarm = 0,
|
||||
BackgroundTaskAlarm = 1,
|
||||
};
|
||||
|
||||
struct Alarm : public Common::IntrusiveListBaseNode<Alarm> {
|
||||
using AlarmList = Common::IntrusiveListBaseTraits<Alarm>::ListType;
|
||||
|
||||
Alarm(Core::System& system, KernelHelpers::ServiceContext& ctx, AlarmType type);
|
||||
~Alarm();
|
||||
|
||||
Kernel::KReadableEvent& GetEventHandle() {
|
||||
return m_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
s64 GetAlertTime() const {
|
||||
return m_alert_time;
|
||||
}
|
||||
|
||||
void SetAlertTime(s64 time) {
|
||||
m_alert_time = time;
|
||||
}
|
||||
|
||||
u32 GetPriority() const {
|
||||
return m_priority;
|
||||
}
|
||||
|
||||
void Signal() {
|
||||
m_event->Signal();
|
||||
}
|
||||
|
||||
Result Lock() {
|
||||
// TODO
|
||||
// if (m_lock_service) {
|
||||
// return m_lock_service->Lock();
|
||||
// }
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
KernelHelpers::ServiceContext& m_ctx;
|
||||
|
||||
u32 m_priority;
|
||||
Kernel::KEvent* m_event{};
|
||||
s64 m_alert_time{};
|
||||
// TODO
|
||||
// nn::psc::sf::IPmStateLock* m_lock_service{};
|
||||
};
|
||||
|
||||
class Alarms {
|
||||
public:
|
||||
explicit Alarms(Core::System& system, StandardSteadyClockCore& steady_clock,
|
||||
PowerStateRequestManager& power_state_request_manager);
|
||||
~Alarms();
|
||||
|
||||
Kernel::KEvent& GetEvent() {
|
||||
return *m_event;
|
||||
}
|
||||
|
||||
s64 GetRawTime() {
|
||||
return m_steady_clock.GetRawTime();
|
||||
}
|
||||
|
||||
Result Enable(Alarm& alarm, s64 time);
|
||||
void Disable(Alarm& alarm);
|
||||
void CheckAndSignal();
|
||||
bool GetClosestAlarm(Alarm** out_alarm);
|
||||
|
||||
private:
|
||||
void Insert(Alarm& alarm);
|
||||
void Erase(Alarm& alarm);
|
||||
Result UpdateClosestAndSignal();
|
||||
|
||||
Core::System& m_system;
|
||||
KernelHelpers::ServiceContext m_ctx;
|
||||
|
||||
StandardSteadyClockCore& m_steady_clock;
|
||||
PowerStateRequestManager& m_power_state_request_manager;
|
||||
Alarm::AlarmList m_alarms;
|
||||
Kernel::KEvent* m_event{};
|
||||
Alarm* m_closest_alarm{};
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
class IAlarmService final : public ServiceFramework<IAlarmService> {
|
||||
public:
|
||||
explicit IAlarmService(Core::System& system, std::shared_ptr<TimeManager> manager);
|
||||
|
||||
~IAlarmService() override = default;
|
||||
|
||||
private:
|
||||
void CreateWakeupAlarm(HLERequestContext& ctx);
|
||||
void CreateBackgroundTaskAlarm(HLERequestContext& ctx);
|
||||
|
||||
Core::System& m_system;
|
||||
Alarms& m_alarms;
|
||||
};
|
||||
|
||||
class ISteadyClockAlarm final : public ServiceFramework<ISteadyClockAlarm> {
|
||||
public:
|
||||
explicit ISteadyClockAlarm(Core::System& system, Alarms& alarms, AlarmType type);
|
||||
|
||||
~ISteadyClockAlarm() override = default;
|
||||
|
||||
private:
|
||||
void GetAlarmEvent(HLERequestContext& ctx);
|
||||
void Enable(HLERequestContext& ctx);
|
||||
void Disable(HLERequestContext& ctx);
|
||||
void IsEnabled(HLERequestContext& ctx);
|
||||
|
||||
KernelHelpers::ServiceContext m_ctx;
|
||||
|
||||
Alarms& m_alarms;
|
||||
Alarm m_alarm;
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
83
src/core/hle/service/psc/time/clocks/context_writers.cpp
Executable file
83
src/core/hle/service/psc/time/clocks/context_writers.cpp
Executable file
@@ -0,0 +1,83 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/psc/time/clocks/context_writers.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
void ContextWriter::SignalAllNodes() {
|
||||
std::scoped_lock l{m_mutex};
|
||||
for (auto& operation : m_operation_events) {
|
||||
operation.m_event->Signal();
|
||||
}
|
||||
}
|
||||
|
||||
void ContextWriter::Link(OperationEvent& operation_event) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
m_operation_events.push_back(operation_event);
|
||||
}
|
||||
|
||||
LocalSystemClockContextWriter::LocalSystemClockContextWriter(Core::System& system,
|
||||
SharedMemory& shared_memory)
|
||||
: m_system{system}, m_shared_memory{shared_memory} {}
|
||||
|
||||
Result LocalSystemClockContextWriter::Write(SystemClockContext& context) {
|
||||
if (m_in_use) {
|
||||
R_SUCCEED_IF(context == m_context);
|
||||
m_context = context;
|
||||
} else {
|
||||
m_context = context;
|
||||
m_in_use = true;
|
||||
}
|
||||
|
||||
m_shared_memory.SetLocalSystemContext(context);
|
||||
|
||||
SignalAllNodes();
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
NetworkSystemClockContextWriter::NetworkSystemClockContextWriter(Core::System& system,
|
||||
SharedMemory& shared_memory,
|
||||
SystemClockCore& system_clock)
|
||||
: m_system{system}, m_shared_memory{shared_memory}, m_system_clock{system_clock} {}
|
||||
|
||||
Result NetworkSystemClockContextWriter::Write(SystemClockContext& context) {
|
||||
s64 time{};
|
||||
[[maybe_unused]] auto res = m_system_clock.GetCurrentTime(&time);
|
||||
|
||||
if (m_in_use) {
|
||||
R_SUCCEED_IF(context == m_context);
|
||||
m_context = context;
|
||||
} else {
|
||||
m_context = context;
|
||||
m_in_use = true;
|
||||
}
|
||||
|
||||
m_shared_memory.SetNetworkSystemContext(context);
|
||||
|
||||
SignalAllNodes();
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
EphemeralNetworkSystemClockContextWriter::EphemeralNetworkSystemClockContextWriter(
|
||||
Core::System& system)
|
||||
: m_system{system} {}
|
||||
|
||||
Result EphemeralNetworkSystemClockContextWriter::Write(SystemClockContext& context) {
|
||||
if (m_in_use) {
|
||||
R_SUCCEED_IF(context == m_context);
|
||||
m_context = context;
|
||||
} else {
|
||||
m_context = context;
|
||||
m_in_use = true;
|
||||
}
|
||||
|
||||
SignalAllNodes();
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
79
src/core/hle/service/psc/time/clocks/context_writers.h
Executable file
79
src/core/hle/service/psc/time/clocks/context_writers.h
Executable file
@@ -0,0 +1,79 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/psc/time/clocks/system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
#include "core/hle/service/psc/time/shared_memory.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
class ContextWriter {
|
||||
private:
|
||||
using OperationEventList = Common::IntrusiveListBaseTraits<OperationEvent>::ListType;
|
||||
|
||||
public:
|
||||
virtual ~ContextWriter() = default;
|
||||
|
||||
virtual Result Write(SystemClockContext& context) = 0;
|
||||
void SignalAllNodes();
|
||||
void Link(OperationEvent& operation_event);
|
||||
|
||||
private:
|
||||
OperationEventList m_operation_events;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
class LocalSystemClockContextWriter : public ContextWriter {
|
||||
public:
|
||||
explicit LocalSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory);
|
||||
|
||||
Result Write(SystemClockContext& context) override;
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
|
||||
SharedMemory& m_shared_memory;
|
||||
bool m_in_use{};
|
||||
SystemClockContext m_context{};
|
||||
};
|
||||
|
||||
class NetworkSystemClockContextWriter : public ContextWriter {
|
||||
public:
|
||||
explicit NetworkSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory,
|
||||
SystemClockCore& system_clock);
|
||||
|
||||
Result Write(SystemClockContext& context) override;
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
|
||||
SharedMemory& m_shared_memory;
|
||||
bool m_in_use{};
|
||||
SystemClockContext m_context{};
|
||||
SystemClockCore& m_system_clock;
|
||||
};
|
||||
|
||||
class EphemeralNetworkSystemClockContextWriter : public ContextWriter {
|
||||
public:
|
||||
EphemeralNetworkSystemClockContextWriter(Core::System& system);
|
||||
|
||||
Result Write(SystemClockContext& context) override;
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
|
||||
bool m_in_use{};
|
||||
SystemClockContext m_context{};
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
21
src/core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h
Executable file
21
src/core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h
Executable file
@@ -0,0 +1,21 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/psc/time/clocks/context_writers.h"
|
||||
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
class EphemeralNetworkSystemClockCore : public SystemClockCore {
|
||||
public:
|
||||
explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock)
|
||||
: SystemClockCore{steady_clock} {}
|
||||
~EphemeralNetworkSystemClockCore() override = default;
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
20
src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.cpp
Executable file
20
src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.cpp
Executable file
@@ -0,0 +1,20 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
void StandardLocalSystemClockCore::Initialize(SystemClockContext& context, s64 time) {
|
||||
SteadyClockTimePoint time_point{};
|
||||
if (GetCurrentTimePoint(time_point) == ResultSuccess &&
|
||||
context.steady_time_point.IdMatches(time_point)) {
|
||||
SetContextAndWrite(context);
|
||||
} else if (SetCurrentTime(time) != ResultSuccess) {
|
||||
LOG_ERROR(Service_Time, "Failed to SetCurrentTime");
|
||||
}
|
||||
|
||||
SetInitialized();
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
23
src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.h
Executable file
23
src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.h
Executable file
@@ -0,0 +1,23 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/psc/time/clocks/context_writers.h"
|
||||
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
class StandardLocalSystemClockCore : public SystemClockCore {
|
||||
public:
|
||||
explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock)
|
||||
: SystemClockCore{steady_clock} {}
|
||||
~StandardLocalSystemClockCore() override = default;
|
||||
|
||||
void Initialize(SystemClockContext& context, s64 time);
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
42
src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.cpp
Executable file
42
src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.cpp
Executable file
@@ -0,0 +1,42 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
void StandardNetworkSystemClockCore::Initialize(SystemClockContext& context, s64 accuracy) {
|
||||
if (SetContextAndWrite(context) != ResultSuccess) {
|
||||
LOG_ERROR(Service_Time, "Failed to SetContext");
|
||||
}
|
||||
m_sufficient_accuracy = accuracy;
|
||||
SetInitialized();
|
||||
}
|
||||
|
||||
bool StandardNetworkSystemClockCore::IsAccuracySufficient() {
|
||||
if (!IsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SystemClockContext context{};
|
||||
SteadyClockTimePoint current_time_point{};
|
||||
if (GetCurrentTimePoint(current_time_point) != ResultSuccess ||
|
||||
GetContext(context) != ResultSuccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s64 seconds{};
|
||||
if (GetSpanBetweenTimePoints(&seconds, context.steady_time_point, current_time_point) !=
|
||||
ResultSuccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(seconds))
|
||||
.count() < m_sufficient_accuracy) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
30
src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.h
Executable file
30
src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.h
Executable file
@@ -0,0 +1,30 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/psc/time/clocks/context_writers.h"
|
||||
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
class StandardNetworkSystemClockCore : public SystemClockCore {
|
||||
public:
|
||||
explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock)
|
||||
: SystemClockCore{steady_clock} {}
|
||||
~StandardNetworkSystemClockCore() override = default;
|
||||
|
||||
void Initialize(SystemClockContext& context, s64 accuracy);
|
||||
bool IsAccuracySufficient();
|
||||
|
||||
private:
|
||||
s64 m_sufficient_accuracy{
|
||||
std::chrono ::duration_cast<std::chrono::nanoseconds>(std::chrono::days(10)).count()};
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
100
src/core/hle/service/psc/time/clocks/standard_steady_clock_core.cpp
Executable file
100
src/core/hle/service/psc/time/clocks/standard_steady_clock_core.cpp
Executable file
@@ -0,0 +1,100 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
void StandardSteadyClockCore::Initialize(ClockSourceId clock_source_id, s64 rtc_offset,
|
||||
s64 internal_offset, s64 test_offset,
|
||||
bool is_rtc_reset_detected) {
|
||||
m_clock_source_id = clock_source_id;
|
||||
m_rtc_offset = rtc_offset;
|
||||
m_internal_offset = internal_offset;
|
||||
m_test_offset = test_offset;
|
||||
if (is_rtc_reset_detected) {
|
||||
SetResetDetected();
|
||||
}
|
||||
SetInitialized();
|
||||
}
|
||||
|
||||
void StandardSteadyClockCore::SetRtcOffset(s64 offset) {
|
||||
m_rtc_offset = offset;
|
||||
}
|
||||
|
||||
void StandardSteadyClockCore::SetContinuousAdjustment(ClockSourceId clock_source_id, s64 time) {
|
||||
auto ticks{m_system.CoreTiming().GetClockTicks()};
|
||||
|
||||
m_continuous_adjustment_time_point.rtc_offset = ConvertToTimeSpan(ticks).count();
|
||||
m_continuous_adjustment_time_point.diff_scale = 0;
|
||||
m_continuous_adjustment_time_point.shift_amount = 0;
|
||||
m_continuous_adjustment_time_point.lower = time;
|
||||
m_continuous_adjustment_time_point.upper = time;
|
||||
m_continuous_adjustment_time_point.clock_source_id = clock_source_id;
|
||||
}
|
||||
|
||||
void StandardSteadyClockCore::GetContinuousAdjustment(
|
||||
ContinuousAdjustmentTimePoint& out_time_point) const {
|
||||
out_time_point = m_continuous_adjustment_time_point;
|
||||
}
|
||||
|
||||
void StandardSteadyClockCore::UpdateContinuousAdjustmentTime(s64 in_time) {
|
||||
auto ticks{m_system.CoreTiming().GetClockTicks()};
|
||||
auto global_time_ns{ConvertToTimeSpan(ticks).count()};
|
||||
auto expected_time{((global_time_ns - m_continuous_adjustment_time_point.rtc_offset) *
|
||||
m_continuous_adjustment_time_point.diff_scale) >>
|
||||
m_continuous_adjustment_time_point.shift_amount};
|
||||
|
||||
auto last_time_point{m_continuous_adjustment_time_point.upper};
|
||||
m_continuous_adjustment_time_point.upper = in_time;
|
||||
auto t1{std::min<s64>(expected_time, last_time_point)};
|
||||
expected_time = std::max<s64>(expected_time, last_time_point);
|
||||
expected_time = m_continuous_adjustment_time_point.diff_scale >= 0 ? t1 : expected_time;
|
||||
|
||||
auto new_diff{in_time < expected_time ? -55 : 55};
|
||||
|
||||
m_continuous_adjustment_time_point.rtc_offset = global_time_ns;
|
||||
m_continuous_adjustment_time_point.shift_amount = expected_time == in_time ? 0 : 14;
|
||||
m_continuous_adjustment_time_point.diff_scale = expected_time == in_time ? 0 : new_diff;
|
||||
m_continuous_adjustment_time_point.lower = expected_time;
|
||||
}
|
||||
|
||||
Result StandardSteadyClockCore::GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) {
|
||||
auto current_time_ns = GetCurrentRawTimePointImpl();
|
||||
auto current_time_s =
|
||||
std::chrono::duration_cast<std::chrono::seconds>(std::chrono::nanoseconds(current_time_ns));
|
||||
out_time_point.time_point = current_time_s.count();
|
||||
out_time_point.clock_source_id = m_clock_source_id;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
s64 StandardSteadyClockCore::GetCurrentRawTimePointImpl() {
|
||||
std::scoped_lock l{m_mutex};
|
||||
auto ticks{static_cast<s64>(m_system.CoreTiming().GetClockTicks())};
|
||||
auto current_time_ns = m_rtc_offset + ConvertToTimeSpan(ticks).count();
|
||||
auto time_point = std::max<s64>(current_time_ns, m_cached_time_point);
|
||||
m_cached_time_point = time_point;
|
||||
return time_point;
|
||||
}
|
||||
|
||||
s64 StandardSteadyClockCore::GetTestOffsetImpl() const {
|
||||
return m_test_offset;
|
||||
}
|
||||
|
||||
void StandardSteadyClockCore::SetTestOffsetImpl(s64 offset) {
|
||||
m_test_offset = offset;
|
||||
}
|
||||
|
||||
s64 StandardSteadyClockCore::GetInternalOffsetImpl() const {
|
||||
return m_internal_offset;
|
||||
}
|
||||
|
||||
void StandardSteadyClockCore::SetInternalOffsetImpl(s64 offset) {
|
||||
m_internal_offset = offset;
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
54
src/core/hle/service/psc/time/clocks/standard_steady_clock_core.h
Executable file
54
src/core/hle/service/psc/time/clocks/standard_steady_clock_core.h
Executable file
@@ -0,0 +1,54 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
class StandardSteadyClockCore : public SteadyClockCore {
|
||||
public:
|
||||
explicit StandardSteadyClockCore(Core::System& system) : m_system{system} {}
|
||||
~StandardSteadyClockCore() override = default;
|
||||
|
||||
void Initialize(ClockSourceId clock_source_id, s64 rtc_offset, s64 internal_offset,
|
||||
s64 test_offset, bool is_rtc_reset_detected);
|
||||
|
||||
void SetRtcOffset(s64 offset);
|
||||
void SetContinuousAdjustment(ClockSourceId clock_source_id, s64 time);
|
||||
void GetContinuousAdjustment(ContinuousAdjustmentTimePoint& out_time_point) const;
|
||||
void UpdateContinuousAdjustmentTime(s64 time);
|
||||
|
||||
Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) override;
|
||||
s64 GetCurrentRawTimePointImpl() override;
|
||||
s64 GetTestOffsetImpl() const override;
|
||||
void SetTestOffsetImpl(s64 offset) override;
|
||||
s64 GetInternalOffsetImpl() const override;
|
||||
void SetInternalOffsetImpl(s64 offset) override;
|
||||
|
||||
Result GetRtcValueImpl(s64& out_value) override {
|
||||
R_RETURN(ResultNotImplemented);
|
||||
}
|
||||
|
||||
Result GetSetupResultValueImpl() override {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
|
||||
std::mutex m_mutex;
|
||||
s64 m_test_offset{};
|
||||
s64 m_internal_offset{};
|
||||
ClockSourceId m_clock_source_id{};
|
||||
s64 m_rtc_offset{};
|
||||
s64 m_cached_time_point{};
|
||||
ContinuousAdjustmentTimePoint m_continuous_adjustment_time_point{};
|
||||
};
|
||||
} // namespace Service::PSC::Time
|
||||
66
src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.cpp
Executable file
66
src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.cpp
Executable file
@@ -0,0 +1,66 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
StandardUserSystemClockCore::StandardUserSystemClockCore(
|
||||
Core::System& system, StandardLocalSystemClockCore& local_clock,
|
||||
StandardNetworkSystemClockCore& network_clock)
|
||||
: SystemClockCore{local_clock.GetSteadyClock()}, m_system{system},
|
||||
m_ctx{m_system, "Psc:StandardUserSystemClockCore"}, m_local_system_clock{local_clock},
|
||||
m_network_system_clock{network_clock}, m_event{m_ctx.CreateEvent(
|
||||
"Psc:StandardUserSystemClockCore:Event")} {}
|
||||
|
||||
StandardUserSystemClockCore::~StandardUserSystemClockCore() {
|
||||
m_ctx.CloseEvent(m_event);
|
||||
}
|
||||
|
||||
Result StandardUserSystemClockCore::SetAutomaticCorrection(bool automatic_correction) {
|
||||
if (m_automatic_correction == automatic_correction ||
|
||||
!m_network_system_clock.CheckClockSourceMatches()) {
|
||||
m_automatic_correction = automatic_correction;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
SystemClockContext context{};
|
||||
R_TRY(m_network_system_clock.GetContext(context));
|
||||
R_TRY(m_local_system_clock.SetContextAndWrite(context));
|
||||
|
||||
m_automatic_correction = automatic_correction;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StandardUserSystemClockCore::GetContext(SystemClockContext& out_context) const {
|
||||
if (!m_automatic_correction) {
|
||||
R_RETURN(m_local_system_clock.GetContext(out_context));
|
||||
}
|
||||
|
||||
if (!m_network_system_clock.CheckClockSourceMatches()) {
|
||||
R_RETURN(m_local_system_clock.GetContext(out_context));
|
||||
}
|
||||
|
||||
SystemClockContext context{};
|
||||
R_TRY(m_network_system_clock.GetContext(context));
|
||||
R_TRY(m_local_system_clock.SetContextAndWrite(context));
|
||||
|
||||
R_RETURN(m_local_system_clock.GetContext(out_context));
|
||||
}
|
||||
|
||||
Result StandardUserSystemClockCore::SetContext(SystemClockContext& context) {
|
||||
R_RETURN(ResultNotImplemented);
|
||||
}
|
||||
|
||||
Result StandardUserSystemClockCore::GetTimePoint(SteadyClockTimePoint& out_time_point) {
|
||||
out_time_point = m_time_point;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void StandardUserSystemClockCore::SetTimePointAndSignal(SteadyClockTimePoint& time_point) {
|
||||
m_time_point = time_point;
|
||||
m_event->Signal();
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
55
src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.h
Executable file
55
src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.h
Executable file
@@ -0,0 +1,55 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/psc/time/clocks/context_writers.h"
|
||||
#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
class StandardUserSystemClockCore : public SystemClockCore {
|
||||
public:
|
||||
explicit StandardUserSystemClockCore(Core::System& system,
|
||||
StandardLocalSystemClockCore& local_clock,
|
||||
StandardNetworkSystemClockCore& network_clock);
|
||||
~StandardUserSystemClockCore() override;
|
||||
|
||||
Kernel::KEvent& GetEvent() {
|
||||
return *m_event;
|
||||
}
|
||||
|
||||
bool GetAutomaticCorrection() const {
|
||||
return m_automatic_correction;
|
||||
}
|
||||
Result SetAutomaticCorrection(bool automatic_correction);
|
||||
|
||||
Result GetContext(SystemClockContext& out_context) const override;
|
||||
Result SetContext(SystemClockContext& context) override;
|
||||
|
||||
Result GetTimePoint(SteadyClockTimePoint& out_time_point);
|
||||
void SetTimePointAndSignal(SteadyClockTimePoint& time_point);
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
KernelHelpers::ServiceContext m_ctx;
|
||||
|
||||
bool m_automatic_correction{};
|
||||
StandardLocalSystemClockCore& m_local_system_clock;
|
||||
StandardNetworkSystemClockCore& m_network_system_clock;
|
||||
SteadyClockTimePoint m_time_point{};
|
||||
Kernel::KEvent* m_event{};
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
81
src/core/hle/service/psc/time/clocks/steady_clock_core.h
Executable file
81
src/core/hle/service/psc/time/clocks/steady_clock_core.h
Executable file
@@ -0,0 +1,81 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
class SteadyClockCore {
|
||||
public:
|
||||
SteadyClockCore() = default;
|
||||
virtual ~SteadyClockCore() = default;
|
||||
|
||||
void SetInitialized() {
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
bool IsInitialized() const {
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
void SetResetDetected() {
|
||||
m_reset_detected = true;
|
||||
}
|
||||
|
||||
bool IsResetDetected() const {
|
||||
return m_reset_detected;
|
||||
}
|
||||
|
||||
Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) {
|
||||
R_TRY(GetCurrentTimePointImpl(out_time_point));
|
||||
|
||||
auto one_second_ns{
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
|
||||
out_time_point.time_point += GetTestOffsetImpl() / one_second_ns;
|
||||
out_time_point.time_point += GetInternalOffsetImpl() / one_second_ns;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
s64 GetTestOffset() const {
|
||||
return GetTestOffsetImpl();
|
||||
}
|
||||
|
||||
void SetTestOffset(s64 offset) {
|
||||
SetTestOffsetImpl(offset);
|
||||
}
|
||||
|
||||
s64 GetInternalOffset() const {
|
||||
return GetInternalOffsetImpl();
|
||||
}
|
||||
|
||||
s64 GetRawTime() {
|
||||
return GetCurrentRawTimePointImpl() + GetTestOffsetImpl() + GetInternalOffsetImpl();
|
||||
}
|
||||
|
||||
Result GetRtcValue(s64& out_value) {
|
||||
R_RETURN(GetRtcValueImpl(out_value));
|
||||
}
|
||||
|
||||
Result GetSetupResultValue() {
|
||||
R_RETURN(GetSetupResultValueImpl());
|
||||
}
|
||||
|
||||
private:
|
||||
virtual Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) = 0;
|
||||
virtual s64 GetCurrentRawTimePointImpl() = 0;
|
||||
virtual s64 GetTestOffsetImpl() const = 0;
|
||||
virtual void SetTestOffsetImpl(s64 offset) = 0;
|
||||
virtual s64 GetInternalOffsetImpl() const = 0;
|
||||
virtual void SetInternalOffsetImpl(s64 offset) = 0;
|
||||
virtual Result GetRtcValueImpl(s64& out_value) = 0;
|
||||
virtual Result GetSetupResultValueImpl() = 0;
|
||||
|
||||
bool m_initialized{};
|
||||
bool m_reset_detected{};
|
||||
};
|
||||
} // namespace Service::PSC::Time
|
||||
75
src/core/hle/service/psc/time/clocks/system_clock_core.cpp
Executable file
75
src/core/hle/service/psc/time/clocks/system_clock_core.cpp
Executable file
@@ -0,0 +1,75 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/psc/time/clocks/context_writers.h"
|
||||
#include "core/hle/service/psc/time/clocks/system_clock_core.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
bool SystemClockCore::CheckClockSourceMatches() {
|
||||
SystemClockContext context{};
|
||||
if (GetContext(context) != ResultSuccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SteadyClockTimePoint time_point{};
|
||||
if (m_steady_clock.GetCurrentTimePoint(time_point) != ResultSuccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return context.steady_time_point.IdMatches(time_point);
|
||||
}
|
||||
|
||||
Result SystemClockCore::GetCurrentTime(s64* out_time) const {
|
||||
R_UNLESS(out_time != nullptr, ResultInvalidArgument);
|
||||
|
||||
SystemClockContext context{};
|
||||
SteadyClockTimePoint time_point{};
|
||||
|
||||
R_TRY(m_steady_clock.GetCurrentTimePoint(time_point));
|
||||
R_TRY(GetContext(context));
|
||||
|
||||
R_UNLESS(context.steady_time_point.IdMatches(time_point), ResultClockMismatch);
|
||||
|
||||
*out_time = context.offset + time_point.time_point;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SystemClockCore::SetCurrentTime(s64 time) {
|
||||
SteadyClockTimePoint time_point{};
|
||||
R_TRY(m_steady_clock.GetCurrentTimePoint(time_point));
|
||||
|
||||
SystemClockContext context{
|
||||
.offset = time - time_point.time_point,
|
||||
.steady_time_point = time_point,
|
||||
};
|
||||
R_RETURN(SetContextAndWrite(context));
|
||||
}
|
||||
|
||||
Result SystemClockCore::GetContext(SystemClockContext& out_context) const {
|
||||
out_context = m_context;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SystemClockCore::SetContext(SystemClockContext& context) {
|
||||
m_context = context;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SystemClockCore::SetContextAndWrite(SystemClockContext& context) {
|
||||
R_TRY(SetContext(context));
|
||||
|
||||
if (m_context_writer) {
|
||||
R_RETURN(m_context_writer->Write(context));
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void SystemClockCore::LinkOperationEvent(OperationEvent& operation_event) {
|
||||
if (m_context_writer) {
|
||||
m_context_writer->Link(operation_event);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
55
src/core/hle/service/psc/time/clocks/system_clock_core.h
Executable file
55
src/core/hle/service/psc/time/clocks/system_clock_core.h
Executable file
@@ -0,0 +1,55 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
class ContextWriter;
|
||||
|
||||
class SystemClockCore {
|
||||
public:
|
||||
explicit SystemClockCore(SteadyClockCore& steady_clock) : m_steady_clock{steady_clock} {}
|
||||
virtual ~SystemClockCore() = default;
|
||||
|
||||
SteadyClockCore& GetSteadyClock() {
|
||||
return m_steady_clock;
|
||||
}
|
||||
|
||||
bool IsInitialized() const {
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
void SetInitialized() {
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
void SetContextWriter(ContextWriter& context_writer) {
|
||||
m_context_writer = &context_writer;
|
||||
}
|
||||
|
||||
bool CheckClockSourceMatches();
|
||||
|
||||
Result GetCurrentTime(s64* out_time) const;
|
||||
Result SetCurrentTime(s64 time);
|
||||
|
||||
Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) {
|
||||
R_RETURN(m_steady_clock.GetCurrentTimePoint(out_time_point));
|
||||
}
|
||||
|
||||
virtual Result GetContext(SystemClockContext& out_context) const;
|
||||
virtual Result SetContext(SystemClockContext& context);
|
||||
Result SetContextAndWrite(SystemClockContext& context);
|
||||
|
||||
void LinkOperationEvent(OperationEvent& operation_event);
|
||||
|
||||
private:
|
||||
bool m_initialized{};
|
||||
ContextWriter* m_context_writer{};
|
||||
SteadyClockCore& m_steady_clock;
|
||||
SystemClockContext m_context{};
|
||||
};
|
||||
} // namespace Service::PSC::Time
|
||||
43
src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp
Executable file
43
src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp
Executable file
@@ -0,0 +1,43 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
Result TickBasedSteadyClockCore::GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) {
|
||||
auto ticks{m_system.CoreTiming().GetClockTicks()};
|
||||
auto current_time_s =
|
||||
std::chrono::duration_cast<std::chrono::seconds>(ConvertToTimeSpan(ticks)).count();
|
||||
out_time_point.time_point = current_time_s;
|
||||
out_time_point.clock_source_id = m_clock_source_id;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
s64 TickBasedSteadyClockCore::GetCurrentRawTimePointImpl() {
|
||||
SteadyClockTimePoint time_point{};
|
||||
if (GetCurrentTimePointImpl(time_point) != ResultSuccess) {
|
||||
LOG_ERROR(Service_Time, "Failed to GetCurrentTimePoint!");
|
||||
}
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::seconds(time_point.time_point))
|
||||
.count();
|
||||
}
|
||||
|
||||
s64 TickBasedSteadyClockCore::GetTestOffsetImpl() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TickBasedSteadyClockCore::SetTestOffsetImpl(s64 offset) {}
|
||||
|
||||
s64 TickBasedSteadyClockCore::GetInternalOffsetImpl() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TickBasedSteadyClockCore::SetInternalOffsetImpl(s64 offset) {}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
41
src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h
Executable file
41
src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h
Executable file
@@ -0,0 +1,41 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "common/uuid.h"
|
||||
#include "core/hle/service/psc/time/clocks/steady_clock_core.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
class TickBasedSteadyClockCore : public SteadyClockCore {
|
||||
public:
|
||||
explicit TickBasedSteadyClockCore(Core::System& system) : m_system{system} {}
|
||||
~TickBasedSteadyClockCore() override = default;
|
||||
|
||||
Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) override;
|
||||
s64 GetCurrentRawTimePointImpl() override;
|
||||
s64 GetTestOffsetImpl() const override;
|
||||
void SetTestOffsetImpl(s64 offset) override;
|
||||
s64 GetInternalOffsetImpl() const override;
|
||||
void SetInternalOffsetImpl(s64 offset) override;
|
||||
|
||||
Result GetRtcValueImpl(s64& out_value) override {
|
||||
R_RETURN(ResultNotImplemented);
|
||||
}
|
||||
|
||||
Result GetSetupResultValueImpl() override {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
|
||||
ClockSourceId m_clock_source_id{Common::UUID::MakeRandom()};
|
||||
};
|
||||
} // namespace Service::PSC::Time
|
||||
16
src/core/hle/service/psc/time/common.cpp
Executable file
16
src/core/hle/service/psc/time/common.cpp
Executable file
@@ -0,0 +1,16 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
OperationEvent::OperationEvent(Core::System& system)
|
||||
: m_ctx{system, "Time:OperationEvent"}, m_event{
|
||||
m_ctx.CreateEvent("Time:OperationEvent:Event")} {}
|
||||
|
||||
OperationEvent::~OperationEvent() {
|
||||
m_ctx.CloseEvent(m_event);
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
168
src/core/hle/service/psc/time/common.h
Executable file
168
src/core/hle/service/psc/time/common.h
Executable file
@@ -0,0 +1,168 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/intrusive_list.h"
|
||||
#include "common/uuid.h"
|
||||
#include "common/wall_clock.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/psc/time/errors.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
using ClockSourceId = Common::UUID;
|
||||
|
||||
struct SteadyClockTimePoint {
|
||||
constexpr bool IdMatches(SteadyClockTimePoint& other) {
|
||||
return clock_source_id == other.clock_source_id;
|
||||
}
|
||||
bool operator==(const SteadyClockTimePoint& other) const = default;
|
||||
|
||||
s64 time_point;
|
||||
ClockSourceId clock_source_id;
|
||||
};
|
||||
static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint has the wrong size!");
|
||||
static_assert(std::is_trivial_v<ClockSourceId>);
|
||||
|
||||
struct SystemClockContext {
|
||||
bool operator==(const SystemClockContext& other) const = default;
|
||||
|
||||
s64 offset;
|
||||
SteadyClockTimePoint steady_time_point;
|
||||
};
|
||||
static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext has the wrong size!");
|
||||
static_assert(std::is_trivial_v<SystemClockContext>);
|
||||
|
||||
enum class TimeType : u8 {
|
||||
UserSystemClock,
|
||||
NetworkSystemClock,
|
||||
LocalSystemClock,
|
||||
};
|
||||
|
||||
struct CalendarTime {
|
||||
s16 year;
|
||||
s8 month;
|
||||
s8 day;
|
||||
s8 hour;
|
||||
s8 minute;
|
||||
s8 second;
|
||||
};
|
||||
static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime has the wrong size!");
|
||||
|
||||
struct CalendarAdditionalInfo {
|
||||
s32 day_of_week;
|
||||
s32 day_of_year;
|
||||
std::array<char, 8> name;
|
||||
s32 is_dst;
|
||||
s32 ut_offset;
|
||||
};
|
||||
static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo has the wrong size!");
|
||||
|
||||
struct LocationName {
|
||||
std::array<char, 36> name;
|
||||
};
|
||||
static_assert(sizeof(LocationName) == 0x24, "LocationName has the wrong size!");
|
||||
|
||||
struct RuleVersion {
|
||||
std::array<char, 16> version;
|
||||
};
|
||||
static_assert(sizeof(RuleVersion) == 0x10, "RuleVersion has the wrong size!");
|
||||
|
||||
struct ClockSnapshot {
|
||||
SystemClockContext user_context;
|
||||
SystemClockContext network_context;
|
||||
s64 user_time;
|
||||
s64 network_time;
|
||||
CalendarTime user_calendar_time;
|
||||
CalendarTime network_calendar_time;
|
||||
CalendarAdditionalInfo user_calendar_additional_time;
|
||||
CalendarAdditionalInfo network_calendar_additional_time;
|
||||
SteadyClockTimePoint steady_clock_time_point;
|
||||
LocationName location_name;
|
||||
bool is_automatic_correction_enabled;
|
||||
TimeType type;
|
||||
u16 unk_CE;
|
||||
};
|
||||
static_assert(sizeof(ClockSnapshot) == 0xD0, "ClockSnapshot has the wrong size!");
|
||||
static_assert(std::is_trivial_v<ClockSnapshot>);
|
||||
|
||||
struct ContinuousAdjustmentTimePoint {
|
||||
s64 rtc_offset;
|
||||
s64 diff_scale;
|
||||
s64 shift_amount;
|
||||
s64 lower;
|
||||
s64 upper;
|
||||
ClockSourceId clock_source_id;
|
||||
};
|
||||
static_assert(sizeof(ContinuousAdjustmentTimePoint) == 0x38,
|
||||
"ContinuousAdjustmentTimePoint has the wrong size!");
|
||||
static_assert(std::is_trivial_v<ContinuousAdjustmentTimePoint>);
|
||||
|
||||
struct AlarmInfo {
|
||||
s64 alert_time;
|
||||
u32 priority;
|
||||
};
|
||||
static_assert(sizeof(AlarmInfo) == 0x10, "AlarmInfo has the wrong size!");
|
||||
|
||||
struct StaticServiceSetupInfo {
|
||||
bool can_write_local_clock;
|
||||
bool can_write_user_clock;
|
||||
bool can_write_network_clock;
|
||||
bool can_write_timezone_device_location;
|
||||
bool can_write_steady_clock;
|
||||
bool can_write_uninitialized_clock;
|
||||
};
|
||||
static_assert(sizeof(StaticServiceSetupInfo) == 0x6, "StaticServiceSetupInfo has the wrong size!");
|
||||
|
||||
struct OperationEvent : public Common::IntrusiveListBaseNode<OperationEvent> {
|
||||
using OperationEventList = Common::IntrusiveListBaseTraits<OperationEvent>::ListType;
|
||||
|
||||
OperationEvent(Core::System& system);
|
||||
~OperationEvent();
|
||||
|
||||
KernelHelpers::ServiceContext m_ctx;
|
||||
Kernel::KEvent* m_event{};
|
||||
};
|
||||
|
||||
constexpr inline std::chrono::nanoseconds ConvertToTimeSpan(s64 ticks) {
|
||||
constexpr auto one_second_ns{
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
|
||||
|
||||
constexpr s64 max{Common::WallClock::CNTFRQ *
|
||||
(std::numeric_limits<s64>::max() / one_second_ns)};
|
||||
|
||||
if (ticks > max) {
|
||||
return std::chrono::nanoseconds(std::numeric_limits<s64>::max());
|
||||
} else if (ticks < -max) {
|
||||
return std::chrono::nanoseconds(std::numeric_limits<s64>::min());
|
||||
}
|
||||
|
||||
auto a{ticks / Common::WallClock::CNTFRQ * one_second_ns};
|
||||
auto b{((ticks % Common::WallClock::CNTFRQ) * one_second_ns) / Common::WallClock::CNTFRQ};
|
||||
|
||||
return std::chrono::nanoseconds(a + b);
|
||||
}
|
||||
|
||||
constexpr inline Result GetSpanBetweenTimePoints(s64* out_seconds, SteadyClockTimePoint& a,
|
||||
SteadyClockTimePoint& b) {
|
||||
R_UNLESS(out_seconds, ResultInvalidArgument);
|
||||
R_UNLESS(a.IdMatches(b), ResultInvalidArgument);
|
||||
R_UNLESS(a.time_point >= 0 || b.time_point <= a.time_point + std::numeric_limits<s64>::max(),
|
||||
ResultOverflow);
|
||||
R_UNLESS(a.time_point < 0 || b.time_point >= a.time_point + std::numeric_limits<s64>::min(),
|
||||
ResultOverflow);
|
||||
|
||||
*out_seconds = b.time_point - a.time_point;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
24
src/core/hle/service/psc/time/errors.h
Executable file
24
src/core/hle/service/psc/time/errors.h
Executable file
@@ -0,0 +1,24 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
constexpr Result ResultPermissionDenied{ErrorModule::Time, 1};
|
||||
constexpr Result ResultClockMismatch{ErrorModule::Time, 102};
|
||||
constexpr Result ResultClockUninitialized{ErrorModule::Time, 103};
|
||||
constexpr Result ResultTimeNotFound{ErrorModule::Time, 200};
|
||||
constexpr Result ResultOverflow{ErrorModule::Time, 201};
|
||||
constexpr Result ResultFailed{ErrorModule::Time, 801};
|
||||
constexpr Result ResultInvalidArgument{ErrorModule::Time, 901};
|
||||
constexpr Result ResultTimeZoneOutOfRange{ErrorModule::Time, 902};
|
||||
constexpr Result ResultTimeZoneParseFailed{ErrorModule::Time, 903};
|
||||
constexpr Result ResultRtcTimeout{ErrorModule::Time, 988};
|
||||
constexpr Result ResultTimeZoneNotFound{ErrorModule::Time, 989};
|
||||
constexpr Result ResultNotImplemented{ErrorModule::Time, 990};
|
||||
constexpr Result ResultAlarmNotRegistered{ErrorModule::Time, 1502};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
56
src/core/hle/service/psc/time/manager.h
Executable file
56
src/core/hle/service/psc/time/manager.h
Executable file
@@ -0,0 +1,56 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/psc/time/alarms.h"
|
||||
#include "core/hle/service/psc/time/clocks/context_writers.h"
|
||||
#include "core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h"
|
||||
#include "core/hle/service/psc/time/power_state_request_manager.h"
|
||||
#include "core/hle/service/psc/time/shared_memory.h"
|
||||
#include "core/hle/service/psc/time/time_zone.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
class TimeManager {
|
||||
public:
|
||||
explicit TimeManager(Core::System& system)
|
||||
: m_system{system}, m_standard_steady_clock{system}, m_tick_based_steady_clock{m_system},
|
||||
m_standard_local_system_clock{m_standard_steady_clock},
|
||||
m_standard_network_system_clock{m_standard_steady_clock},
|
||||
m_standard_user_system_clock{m_system, m_standard_local_system_clock,
|
||||
m_standard_network_system_clock},
|
||||
m_ephemeral_network_clock{m_tick_based_steady_clock}, m_shared_memory{m_system},
|
||||
m_power_state_request_manager{m_system}, m_alarms{m_system, m_standard_steady_clock,
|
||||
m_power_state_request_manager},
|
||||
m_local_system_clock_context_writer{m_system, m_shared_memory},
|
||||
m_network_system_clock_context_writer{m_system, m_shared_memory,
|
||||
m_standard_user_system_clock},
|
||||
m_ephemeral_network_clock_context_writer{m_system} {}
|
||||
|
||||
Core::System& m_system;
|
||||
|
||||
StandardSteadyClockCore m_standard_steady_clock;
|
||||
TickBasedSteadyClockCore m_tick_based_steady_clock;
|
||||
StandardLocalSystemClockCore m_standard_local_system_clock;
|
||||
StandardNetworkSystemClockCore m_standard_network_system_clock;
|
||||
StandardUserSystemClockCore m_standard_user_system_clock;
|
||||
EphemeralNetworkSystemClockCore m_ephemeral_network_clock;
|
||||
TimeZone m_time_zone;
|
||||
SharedMemory m_shared_memory;
|
||||
PowerStateRequestManager m_power_state_request_manager;
|
||||
Alarms m_alarms;
|
||||
LocalSystemClockContextWriter m_local_system_clock_context_writer;
|
||||
NetworkSystemClockContextWriter m_network_system_clock_context_writer;
|
||||
EphemeralNetworkSystemClockContextWriter m_ephemeral_network_clock_context_writer;
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
50
src/core/hle/service/psc/time/power_state_request_manager.cpp
Executable file
50
src/core/hle/service/psc/time/power_state_request_manager.cpp
Executable file
@@ -0,0 +1,50 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/psc/time/power_state_request_manager.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
PowerStateRequestManager::PowerStateRequestManager(Core::System& system)
|
||||
: m_system{system}, m_ctx{system, "Psc:PowerStateRequestManager"},
|
||||
m_event{m_ctx.CreateEvent("Psc:PowerStateRequestManager:Event")} {}
|
||||
|
||||
PowerStateRequestManager::~PowerStateRequestManager() {
|
||||
m_ctx.CloseEvent(m_event);
|
||||
}
|
||||
|
||||
void PowerStateRequestManager::UpdatePendingPowerStateRequestPriority(u32 priority) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
if (m_has_pending_request) {
|
||||
m_pending_request_priority = std::max(m_pending_request_priority, priority);
|
||||
} else {
|
||||
m_pending_request_priority = priority;
|
||||
m_has_pending_request = true;
|
||||
}
|
||||
}
|
||||
|
||||
void PowerStateRequestManager::SignalPowerStateRequestAvailability() {
|
||||
std::scoped_lock l{m_mutex};
|
||||
if (m_has_pending_request) {
|
||||
if (!m_has_available_request) {
|
||||
m_has_available_request = true;
|
||||
}
|
||||
m_has_pending_request = false;
|
||||
m_available_request_priority = m_pending_request_priority;
|
||||
m_event->Signal();
|
||||
}
|
||||
}
|
||||
|
||||
bool PowerStateRequestManager::GetAndClearPowerStateRequest(u32& out_priority) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
auto had_request{m_has_available_request};
|
||||
if (m_has_available_request) {
|
||||
out_priority = m_available_request_priority;
|
||||
m_has_available_request = false;
|
||||
m_event->Clear();
|
||||
}
|
||||
return had_request;
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
42
src/core/hle/service/psc/time/power_state_request_manager.h
Executable file
42
src/core/hle/service/psc/time/power_state_request_manager.h
Executable file
@@ -0,0 +1,42 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
class PowerStateRequestManager {
|
||||
public:
|
||||
explicit PowerStateRequestManager(Core::System& system);
|
||||
~PowerStateRequestManager();
|
||||
|
||||
Kernel::KReadableEvent& GetReadableEvent() {
|
||||
return m_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
void UpdatePendingPowerStateRequestPriority(u32 priority);
|
||||
void SignalPowerStateRequestAvailability();
|
||||
bool GetAndClearPowerStateRequest(u32& out_priority);
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
KernelHelpers::ServiceContext m_ctx;
|
||||
|
||||
Kernel::KEvent* m_event{};
|
||||
bool m_has_pending_request{};
|
||||
u32 m_pending_request_priority{};
|
||||
bool m_has_available_request{};
|
||||
u32 m_available_request_priority{};
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
49
src/core/hle/service/psc/time/power_state_service.cpp
Executable file
49
src/core/hle/service/psc/time/power_state_service.cpp
Executable file
@@ -0,0 +1,49 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/psc/time/power_state_service.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
IPowerStateRequestHandler::IPowerStateRequestHandler(
|
||||
Core::System& system_, PowerStateRequestManager& power_state_request_manager)
|
||||
: ServiceFramework{system_, "time:p"}, m_system{system}, m_power_state_request_manager{
|
||||
power_state_request_manager} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IPowerStateRequestHandler::GetPowerStateRequestEventReadableHandle, "GetPowerStateRequestEventReadableHandle"},
|
||||
{1, &IPowerStateRequestHandler::GetAndClearPowerStateRequest, "GetAndClearPowerStateRequest"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void IPowerStateRequestHandler::GetPowerStateRequestEventReadableHandle(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(m_power_state_request_manager.GetReadableEvent());
|
||||
}
|
||||
|
||||
void IPowerStateRequestHandler::GetAndClearPowerStateRequest(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
u32 priority{};
|
||||
auto cleared = m_power_state_request_manager.GetAndClearPowerStateRequest(priority);
|
||||
|
||||
if (cleared) {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(priority);
|
||||
rb.Push(cleared);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(cleared);
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
32
src/core/hle/service/psc/time/power_state_service.h
Executable file
32
src/core/hle/service/psc/time/power_state_service.h
Executable file
@@ -0,0 +1,32 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/psc/time/power_state_request_manager.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
class IPowerStateRequestHandler final : public ServiceFramework<IPowerStateRequestHandler> {
|
||||
public:
|
||||
explicit IPowerStateRequestHandler(Core::System& system,
|
||||
PowerStateRequestManager& power_state_request_manager);
|
||||
|
||||
~IPowerStateRequestHandler() override = default;
|
||||
|
||||
private:
|
||||
void GetPowerStateRequestEventReadableHandle(HLERequestContext& ctx);
|
||||
void GetAndClearPowerStateRequest(HLERequestContext& ctx);
|
||||
|
||||
Core::System& m_system;
|
||||
PowerStateRequestManager& m_power_state_request_manager;
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
462
src/core/hle/service/psc/time/service_manager.cpp
Executable file
462
src/core/hle/service/psc/time/service_manager.cpp
Executable file
@@ -0,0 +1,462 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/psc/time/power_state_service.h"
|
||||
#include "core/hle/service/psc/time/service_manager.h"
|
||||
#include "core/hle/service/psc/time/static.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
ServiceManager::ServiceManager(Core::System& system_, std::shared_ptr<TimeManager> time,
|
||||
ServerManager* server_manager)
|
||||
: ServiceFramework{system_, "time:m"}, m_system{system}, m_time{std::move(time)},
|
||||
m_server_manager{*server_manager},
|
||||
m_local_system_clock{m_time->m_standard_local_system_clock},
|
||||
m_user_system_clock{m_time->m_standard_user_system_clock},
|
||||
m_network_system_clock{m_time->m_standard_network_system_clock},
|
||||
m_steady_clock{m_time->m_standard_steady_clock}, m_time_zone{m_time->m_time_zone},
|
||||
m_ephemeral_network_clock{m_time->m_ephemeral_network_clock},
|
||||
m_shared_memory{m_time->m_shared_memory}, m_alarms{m_time->m_alarms},
|
||||
m_local_system_context_writer{m_time->m_local_system_clock_context_writer},
|
||||
m_network_system_context_writer{m_time->m_network_system_clock_context_writer},
|
||||
m_ephemeral_system_context_writer{m_time->m_ephemeral_network_clock_context_writer},
|
||||
m_local_operation{m_system}, m_network_operation{m_system}, m_ephemeral_operation{m_system} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ServiceManager::Handle_GetStaticServiceAsUser, "GetStaticServiceAsUser"},
|
||||
{5, &ServiceManager::Handle_GetStaticServiceAsAdmin, "GetStaticServiceAsAdmin"},
|
||||
{6, &ServiceManager::Handle_GetStaticServiceAsRepair, "GetStaticServiceAsRepair"},
|
||||
{9, &ServiceManager::Handle_GetStaticServiceAsServiceManager, "GetStaticServiceAsServiceManager"},
|
||||
{10, &ServiceManager::Handle_SetupStandardSteadyClockCore, "SetupStandardSteadyClockCore"},
|
||||
{11, &ServiceManager::Handle_SetupStandardLocalSystemClockCore, "SetupStandardLocalSystemClockCore"},
|
||||
{12, &ServiceManager::Handle_SetupStandardNetworkSystemClockCore, "SetupStandardNetworkSystemClockCore"},
|
||||
{13, &ServiceManager::Handle_SetupStandardUserSystemClockCore, "SetupStandardUserSystemClockCore"},
|
||||
{14, &ServiceManager::Handle_SetupTimeZoneServiceCore, "SetupTimeZoneServiceCore"},
|
||||
{15, &ServiceManager::Handle_SetupEphemeralNetworkSystemClockCore, "SetupEphemeralNetworkSystemClockCore"},
|
||||
{50, &ServiceManager::Handle_GetStandardLocalClockOperationEvent, "GetStandardLocalClockOperationEvent"},
|
||||
{51, &ServiceManager::Handle_GetStandardNetworkClockOperationEventForServiceManager, "GetStandardNetworkClockOperationEventForServiceManager"},
|
||||
{52, &ServiceManager::Handle_GetEphemeralNetworkClockOperationEventForServiceManager, "GetEphemeralNetworkClockOperationEventForServiceManager"},
|
||||
{60, &ServiceManager::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent, "GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent"},
|
||||
{100, &ServiceManager::Handle_SetStandardSteadyClockBaseTime, "SetStandardSteadyClockBaseTime"},
|
||||
{200, &ServiceManager::Handle_GetClosestAlarmUpdatedEvent, "GetClosestAlarmUpdatedEvent"},
|
||||
{201, &ServiceManager::Handle_CheckAndSignalAlarms, "CheckAndSignalAlarms"},
|
||||
{202, &ServiceManager::Handle_GetClosestAlarmInfo, "GetClosestAlarmInfo "},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
|
||||
m_local_system_context_writer.Link(m_local_operation);
|
||||
m_network_system_context_writer.Link(m_network_operation);
|
||||
m_ephemeral_system_context_writer.Link(m_ephemeral_operation);
|
||||
}
|
||||
|
||||
void ServiceManager::SetupSAndP() {
|
||||
if (!m_is_s_and_p_setup) {
|
||||
m_is_s_and_p_setup = true;
|
||||
m_server_manager.RegisterNamedService(
|
||||
"time:s", std::make_shared<StaticService>(
|
||||
m_system, StaticServiceSetupInfo{0, 0, 1, 0, 0, 0}, m_time, "time:s"));
|
||||
m_server_manager.RegisterNamedService("time:p",
|
||||
std::make_shared<IPowerStateRequestHandler>(
|
||||
m_system, m_time->m_power_state_request_manager));
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceManager::CheckAndSetupServicesSAndP() {
|
||||
if (m_local_system_clock.IsInitialized() && m_user_system_clock.IsInitialized() &&
|
||||
m_network_system_clock.IsInitialized() && m_steady_clock.IsInitialized() &&
|
||||
m_time_zone.IsInitialized() && m_ephemeral_network_clock.IsInitialized()) {
|
||||
SetupSAndP();
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_GetStaticServiceAsUser(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<StaticService> service{};
|
||||
auto res = GetStaticServiceAsUser(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface<StaticService>(std::move(service));
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_GetStaticServiceAsAdmin(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<StaticService> service{};
|
||||
auto res = GetStaticServiceAsAdmin(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface<StaticService>(std::move(service));
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_GetStaticServiceAsRepair(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<StaticService> service{};
|
||||
auto res = GetStaticServiceAsRepair(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface<StaticService>(std::move(service));
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_GetStaticServiceAsServiceManager(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<StaticService> service{};
|
||||
auto res = GetStaticServiceAsServiceManager(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface<StaticService>(std::move(service));
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_SetupStandardSteadyClockCore(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto clock_source_id{rp.PopRaw<Common::UUID>()};
|
||||
auto rtc_offset{rp.Pop<s64>()};
|
||||
auto internal_offset{rp.Pop<s64>()};
|
||||
auto test_offset{rp.Pop<s64>()};
|
||||
auto is_rtc_reset_detected{rp.Pop<bool>()};
|
||||
|
||||
auto res = SetupStandardSteadyClockCore(clock_source_id, rtc_offset, internal_offset,
|
||||
test_offset, is_rtc_reset_detected);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_SetupStandardLocalSystemClockCore(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto context{rp.PopRaw<SystemClockContext>()};
|
||||
auto time{rp.Pop<s64>()};
|
||||
|
||||
auto res = SetupStandardLocalSystemClockCore(context, time);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_SetupStandardNetworkSystemClockCore(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto context{rp.PopRaw<SystemClockContext>()};
|
||||
auto accuracy{rp.Pop<s64>()};
|
||||
|
||||
auto res = SetupStandardNetworkSystemClockCore(context, accuracy);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_SetupStandardUserSystemClockCore(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto time_point{rp.PopRaw<SteadyClockTimePoint>()};
|
||||
auto automatic_correction{rp.Pop<bool>()};
|
||||
|
||||
auto res = SetupStandardUserSystemClockCore(time_point, automatic_correction);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_SetupTimeZoneServiceCore(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto name{rp.PopRaw<LocationName>()};
|
||||
auto time_point{rp.PopRaw<SteadyClockTimePoint>()};
|
||||
auto rule_version{rp.PopRaw<RuleVersion>()};
|
||||
auto location_count{rp.Pop<u32>()};
|
||||
|
||||
auto rule_buffer{ctx.ReadBuffer()};
|
||||
|
||||
auto res =
|
||||
SetupTimeZoneServiceCore(name, time_point, rule_version, location_count, rule_buffer);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_SetupEphemeralNetworkSystemClockCore(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
auto res = SetupEphemeralNetworkSystemClockCore();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_GetStandardLocalClockOperationEvent(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Kernel::KEvent* event{};
|
||||
auto res = GetStandardLocalClockOperationEvent(&event);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(res);
|
||||
rb.PushCopyObjects(event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_GetStandardNetworkClockOperationEventForServiceManager(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Kernel::KEvent* event{};
|
||||
auto res = GetStandardNetworkClockOperationEventForServiceManager(&event);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(res);
|
||||
rb.PushCopyObjects(event);
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_GetEphemeralNetworkClockOperationEventForServiceManager(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Kernel::KEvent* event{};
|
||||
auto res = GetEphemeralNetworkClockOperationEventForServiceManager(&event);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(res);
|
||||
rb.PushCopyObjects(event);
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Kernel::KEvent* event{};
|
||||
auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(&event);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(res);
|
||||
rb.PushCopyObjects(event);
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_SetStandardSteadyClockBaseTime(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto base_time{rp.Pop<s64>()};
|
||||
|
||||
auto res = SetStandardSteadyClockBaseTime(base_time);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_GetClosestAlarmUpdatedEvent(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Kernel::KEvent* event{};
|
||||
auto res = GetClosestAlarmUpdatedEvent(&event);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.PushCopyObjects(event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_CheckAndSignalAlarms(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
auto res = CheckAndSignalAlarms();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void ServiceManager::Handle_GetClosestAlarmInfo(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
AlarmInfo alarm_info{};
|
||||
bool is_valid{};
|
||||
s64 time{};
|
||||
auto res = GetClosestAlarmInfo(is_valid, alarm_info, time);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5 + sizeof(AlarmInfo) / sizeof(u32)};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<AlarmInfo>(alarm_info);
|
||||
rb.Push<bool>(is_valid);
|
||||
rb.Push<s64>(time);
|
||||
}
|
||||
|
||||
// =============================== Implementations ===========================
|
||||
|
||||
Result ServiceManager::GetStaticService(std::shared_ptr<StaticService>& out_service,
|
||||
StaticServiceSetupInfo setup_info, const char* name) {
|
||||
out_service = std::make_shared<StaticService>(m_system, setup_info, m_time, name);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::GetStaticServiceAsUser(std::shared_ptr<StaticService>& out_service) {
|
||||
R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{0, 0, 0, 0, 0, 0}, "time:u"));
|
||||
}
|
||||
|
||||
Result ServiceManager::GetStaticServiceAsAdmin(std::shared_ptr<StaticService>& out_service) {
|
||||
R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{1, 1, 0, 1, 0, 0}, "time:a"));
|
||||
}
|
||||
|
||||
Result ServiceManager::GetStaticServiceAsRepair(std::shared_ptr<StaticService>& out_service) {
|
||||
R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{0, 0, 0, 0, 1, 0}, "time:r"));
|
||||
}
|
||||
|
||||
Result ServiceManager::GetStaticServiceAsServiceManager(
|
||||
std::shared_ptr<StaticService>& out_service) {
|
||||
R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{1, 1, 1, 1, 1, 0}, "time:sm"));
|
||||
}
|
||||
|
||||
Result ServiceManager::SetupStandardSteadyClockCore(Common::UUID& clock_source_id, s64 rtc_offset,
|
||||
s64 internal_offset, s64 test_offset,
|
||||
bool is_rtc_reset_detected) {
|
||||
m_steady_clock.Initialize(clock_source_id, rtc_offset, internal_offset, test_offset,
|
||||
is_rtc_reset_detected);
|
||||
auto time = m_steady_clock.GetRawTime();
|
||||
auto ticks = m_system.CoreTiming().GetClockTicks();
|
||||
auto boot_time = time - ConvertToTimeSpan(ticks).count();
|
||||
m_shared_memory.SetSteadyClockTimePoint(clock_source_id, boot_time);
|
||||
m_steady_clock.SetContinuousAdjustment(clock_source_id, boot_time);
|
||||
|
||||
ContinuousAdjustmentTimePoint time_point{};
|
||||
m_steady_clock.GetContinuousAdjustment(time_point);
|
||||
m_shared_memory.SetContinuousAdjustment(time_point);
|
||||
|
||||
CheckAndSetupServicesSAndP();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time) {
|
||||
m_local_system_clock.SetContextWriter(m_local_system_context_writer);
|
||||
m_local_system_clock.Initialize(context, time);
|
||||
|
||||
CheckAndSetupServicesSAndP();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext& context,
|
||||
s64 accuracy) {
|
||||
// TODO this is a hack! The network clock should be updated independently, from the ntc service
|
||||
// and maybe elsewhere. We do not do that, so fix the network clock to the local clock on boot
|
||||
// to avoid it being stuck at 0.
|
||||
m_local_system_clock.GetContext(context);
|
||||
|
||||
m_network_system_clock.SetContextWriter(m_network_system_context_writer);
|
||||
m_network_system_clock.Initialize(context, accuracy);
|
||||
|
||||
CheckAndSetupServicesSAndP();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::SetupStandardUserSystemClockCore(SteadyClockTimePoint& time_point,
|
||||
bool automatic_correction) {
|
||||
// TODO this is a hack! I'm not sure where this clock's time point is initialised, but we don't
|
||||
// want it at 0.
|
||||
// m_local_system_clock.GetCurrentTimePoint(time_point);
|
||||
|
||||
m_user_system_clock.SetAutomaticCorrection(automatic_correction);
|
||||
m_user_system_clock.SetTimePointAndSignal(time_point);
|
||||
m_user_system_clock.SetInitialized();
|
||||
m_shared_memory.SetAutomaticCorrection(automatic_correction);
|
||||
|
||||
CheckAndSetupServicesSAndP();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::SetupTimeZoneServiceCore(LocationName& name,
|
||||
SteadyClockTimePoint& time_point,
|
||||
RuleVersion& rule_version, u32 location_count,
|
||||
std::span<const u8> rule_buffer) {
|
||||
if (m_time_zone.ParseBinary(name, rule_buffer) != ResultSuccess) {
|
||||
LOG_ERROR(Service_Time, "Failed to parse time zone binary!");
|
||||
}
|
||||
|
||||
m_time_zone.SetTimePoint(time_point);
|
||||
m_time_zone.SetTotalLocationNameCount(location_count);
|
||||
m_time_zone.SetRuleVersion(rule_version);
|
||||
m_time_zone.SetInitialized();
|
||||
|
||||
CheckAndSetupServicesSAndP();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::SetupEphemeralNetworkSystemClockCore() {
|
||||
m_ephemeral_network_clock.SetContextWriter(m_ephemeral_system_context_writer);
|
||||
m_ephemeral_network_clock.SetInitialized();
|
||||
|
||||
CheckAndSetupServicesSAndP();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::GetStandardLocalClockOperationEvent(Kernel::KEvent** out_event) {
|
||||
*out_event = m_local_operation.m_event;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::GetStandardNetworkClockOperationEventForServiceManager(
|
||||
Kernel::KEvent** out_event) {
|
||||
*out_event = m_network_operation.m_event;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::GetEphemeralNetworkClockOperationEventForServiceManager(
|
||||
Kernel::KEvent** out_event) {
|
||||
*out_event = m_ephemeral_operation.m_event;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(
|
||||
Kernel::KEvent** out_event) {
|
||||
*out_event = &m_user_system_clock.GetEvent();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::SetStandardSteadyClockBaseTime(s64 base_time) {
|
||||
m_steady_clock.SetRtcOffset(base_time);
|
||||
auto time = m_steady_clock.GetRawTime();
|
||||
auto ticks = m_system.CoreTiming().GetClockTicks();
|
||||
auto diff = time - ConvertToTimeSpan(ticks).count();
|
||||
m_shared_memory.UpdateBaseTime(diff);
|
||||
m_steady_clock.UpdateContinuousAdjustmentTime(diff);
|
||||
|
||||
ContinuousAdjustmentTimePoint time_point{};
|
||||
m_steady_clock.GetContinuousAdjustment(time_point);
|
||||
m_shared_memory.SetContinuousAdjustment(time_point);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::GetClosestAlarmUpdatedEvent(Kernel::KEvent** out_event) {
|
||||
*out_event = &m_alarms.GetEvent();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::CheckAndSignalAlarms() {
|
||||
m_alarms.CheckAndSignal();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServiceManager::GetClosestAlarmInfo(bool& out_is_valid, AlarmInfo& out_info, s64& out_time) {
|
||||
Alarm* alarm{nullptr};
|
||||
out_is_valid = m_alarms.GetClosestAlarm(&alarm);
|
||||
if (out_is_valid) {
|
||||
out_info = {
|
||||
.alert_time = alarm->GetAlertTime(),
|
||||
.priority = alarm->GetPriority(),
|
||||
};
|
||||
out_time = m_alarms.GetRawTime();
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
101
src/core/hle/service/psc/time/service_manager.h
Executable file
101
src/core/hle/service/psc/time/service_manager.h
Executable file
@@ -0,0 +1,101 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
#include "core/hle/service/psc/time/manager.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KReadableEvent;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
class StaticService;
|
||||
|
||||
class ServiceManager final : public ServiceFramework<ServiceManager> {
|
||||
public:
|
||||
explicit ServiceManager(Core::System& system, std::shared_ptr<TimeManager> time,
|
||||
ServerManager* server_manager);
|
||||
~ServiceManager() override = default;
|
||||
|
||||
Result GetStaticServiceAsUser(std::shared_ptr<StaticService>& out_service);
|
||||
Result GetStaticServiceAsAdmin(std::shared_ptr<StaticService>& out_service);
|
||||
Result GetStaticServiceAsRepair(std::shared_ptr<StaticService>& out_service);
|
||||
Result GetStaticServiceAsServiceManager(std::shared_ptr<StaticService>& out_service);
|
||||
Result SetupStandardSteadyClockCore(Common::UUID& clock_source_id, s64 rtc_offset,
|
||||
s64 internal_offset, s64 test_offset,
|
||||
bool is_rtc_reset_detected);
|
||||
Result SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time);
|
||||
Result SetupStandardNetworkSystemClockCore(SystemClockContext& context, s64 accuracy);
|
||||
Result SetupStandardUserSystemClockCore(SteadyClockTimePoint& time_point,
|
||||
bool automatic_correction);
|
||||
Result SetupTimeZoneServiceCore(LocationName& name, SteadyClockTimePoint& time_point,
|
||||
RuleVersion& rule_version, u32 location_count,
|
||||
std::span<const u8> rule_buffer);
|
||||
Result SetupEphemeralNetworkSystemClockCore();
|
||||
Result GetStandardLocalClockOperationEvent(Kernel::KEvent** out_event);
|
||||
Result GetStandardNetworkClockOperationEventForServiceManager(Kernel::KEvent** out_event);
|
||||
Result GetEphemeralNetworkClockOperationEventForServiceManager(Kernel::KEvent** out_event);
|
||||
Result GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(Kernel::KEvent** out_event);
|
||||
Result SetStandardSteadyClockBaseTime(s64 base_time);
|
||||
Result GetClosestAlarmUpdatedEvent(Kernel::KEvent** out_event);
|
||||
Result CheckAndSignalAlarms();
|
||||
Result GetClosestAlarmInfo(bool& out_is_valid, AlarmInfo& out_info, s64& out_time);
|
||||
|
||||
private:
|
||||
void CheckAndSetupServicesSAndP();
|
||||
void SetupSAndP();
|
||||
Result GetStaticService(std::shared_ptr<StaticService>& out_service,
|
||||
StaticServiceSetupInfo setup_info, const char* name);
|
||||
|
||||
void Handle_GetStaticServiceAsUser(HLERequestContext& ctx);
|
||||
void Handle_GetStaticServiceAsAdmin(HLERequestContext& ctx);
|
||||
void Handle_GetStaticServiceAsRepair(HLERequestContext& ctx);
|
||||
void Handle_GetStaticServiceAsServiceManager(HLERequestContext& ctx);
|
||||
void Handle_SetupStandardSteadyClockCore(HLERequestContext& ctx);
|
||||
void Handle_SetupStandardLocalSystemClockCore(HLERequestContext& ctx);
|
||||
void Handle_SetupStandardNetworkSystemClockCore(HLERequestContext& ctx);
|
||||
void Handle_SetupStandardUserSystemClockCore(HLERequestContext& ctx);
|
||||
void Handle_SetupTimeZoneServiceCore(HLERequestContext& ctx);
|
||||
void Handle_SetupEphemeralNetworkSystemClockCore(HLERequestContext& ctx);
|
||||
void Handle_GetStandardLocalClockOperationEvent(HLERequestContext& ctx);
|
||||
void Handle_GetStandardNetworkClockOperationEventForServiceManager(HLERequestContext& ctx);
|
||||
void Handle_GetEphemeralNetworkClockOperationEventForServiceManager(HLERequestContext& ctx);
|
||||
void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(HLERequestContext& ctx);
|
||||
void Handle_SetStandardSteadyClockBaseTime(HLERequestContext& ctx);
|
||||
void Handle_GetClosestAlarmUpdatedEvent(HLERequestContext& ctx);
|
||||
void Handle_CheckAndSignalAlarms(HLERequestContext& ctx);
|
||||
void Handle_GetClosestAlarmInfo(HLERequestContext& ctx);
|
||||
|
||||
Core::System& m_system;
|
||||
std::shared_ptr<TimeManager> m_time;
|
||||
ServerManager& m_server_manager;
|
||||
bool m_is_s_and_p_setup{};
|
||||
StandardLocalSystemClockCore& m_local_system_clock;
|
||||
StandardUserSystemClockCore& m_user_system_clock;
|
||||
StandardNetworkSystemClockCore& m_network_system_clock;
|
||||
StandardSteadyClockCore& m_steady_clock;
|
||||
TimeZone& m_time_zone;
|
||||
EphemeralNetworkSystemClockCore& m_ephemeral_network_clock;
|
||||
SharedMemory& m_shared_memory;
|
||||
Alarms& m_alarms;
|
||||
LocalSystemClockContextWriter& m_local_system_context_writer;
|
||||
NetworkSystemClockContextWriter& m_network_system_context_writer;
|
||||
EphemeralNetworkSystemClockContextWriter& m_ephemeral_system_context_writer;
|
||||
OperationEvent m_local_operation;
|
||||
OperationEvent m_network_operation;
|
||||
OperationEvent m_ephemeral_operation;
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
84
src/core/hle/service/psc/time/shared_memory.cpp
Executable file
84
src/core/hle/service/psc/time/shared_memory.cpp
Executable file
@@ -0,0 +1,84 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/service/psc/time/shared_memory.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
namespace {
|
||||
template <typename T>
|
||||
constexpr inline T ReadFromLockFreeAtomicType(const LockFreeAtomicType<T>* p) {
|
||||
while (true) {
|
||||
// Get the counter.
|
||||
auto counter = p->m_counter;
|
||||
|
||||
// Get the value.
|
||||
auto value = p->m_value[counter % 2];
|
||||
|
||||
// Fence memory.
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
|
||||
// Check that the counter matches.
|
||||
if (counter == p->m_counter) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr inline void WriteToLockFreeAtomicType(LockFreeAtomicType<T>* p, const T& value) {
|
||||
// Get the current counter.
|
||||
auto counter = p->m_counter;
|
||||
|
||||
// Increment the counter.
|
||||
++counter;
|
||||
|
||||
// Store the updated value.
|
||||
p->m_value[counter % 2] = value;
|
||||
|
||||
// Fence memory.
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
|
||||
// Set the updated counter.
|
||||
p->m_counter = counter;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
SharedMemory::SharedMemory(Core::System& system)
|
||||
: m_system{system}, m_k_shared_memory{m_system.Kernel().GetTimeSharedMem()},
|
||||
m_shared_memory_ptr{reinterpret_cast<SharedMemoryStruct*>(m_k_shared_memory.GetPointer())} {
|
||||
std::memset(m_shared_memory_ptr, 0, sizeof(*m_shared_memory_ptr));
|
||||
}
|
||||
|
||||
void SharedMemory::SetLocalSystemContext(SystemClockContext& context) {
|
||||
WriteToLockFreeAtomicType(&m_shared_memory_ptr->local_system_clock_contexts, context);
|
||||
}
|
||||
|
||||
void SharedMemory::SetNetworkSystemContext(SystemClockContext& context) {
|
||||
WriteToLockFreeAtomicType(&m_shared_memory_ptr->network_system_clock_contexts, context);
|
||||
}
|
||||
|
||||
void SharedMemory::SetSteadyClockTimePoint(ClockSourceId clock_source_id, s64 time_point) {
|
||||
WriteToLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points,
|
||||
{time_point, clock_source_id});
|
||||
}
|
||||
|
||||
void SharedMemory::SetContinuousAdjustment(ContinuousAdjustmentTimePoint& time_point) {
|
||||
WriteToLockFreeAtomicType(&m_shared_memory_ptr->continuous_adjustment_time_points, time_point);
|
||||
}
|
||||
|
||||
void SharedMemory::SetAutomaticCorrection(bool automatic_correction) {
|
||||
WriteToLockFreeAtomicType(&m_shared_memory_ptr->automatic_corrections, automatic_correction);
|
||||
}
|
||||
|
||||
void SharedMemory::UpdateBaseTime(s64 time) {
|
||||
SteadyClockTimePoint time_point{
|
||||
ReadFromLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points)};
|
||||
|
||||
time_point.time_point = time;
|
||||
|
||||
WriteToLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points, time_point);
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
70
src/core/hle/service/psc/time/shared_memory.h
Executable file
70
src/core/hle/service/psc/time/shared_memory.h
Executable file
@@ -0,0 +1,70 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KSharedMemory;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
template <typename T>
|
||||
struct LockFreeAtomicType {
|
||||
u32 m_counter;
|
||||
std::array<T, 2> m_value;
|
||||
};
|
||||
|
||||
struct SharedMemoryStruct {
|
||||
LockFreeAtomicType<SteadyClockTimePoint> steady_time_points;
|
||||
LockFreeAtomicType<SystemClockContext> local_system_clock_contexts;
|
||||
LockFreeAtomicType<SystemClockContext> network_system_clock_contexts;
|
||||
LockFreeAtomicType<bool> automatic_corrections;
|
||||
LockFreeAtomicType<ContinuousAdjustmentTimePoint> continuous_adjustment_time_points;
|
||||
std::array<char, 0xEB8> pad0148;
|
||||
};
|
||||
static_assert(offsetof(SharedMemoryStruct, steady_time_points) == 0x0,
|
||||
"steady_time_points are in the wrong place!");
|
||||
static_assert(offsetof(SharedMemoryStruct, local_system_clock_contexts) == 0x38,
|
||||
"local_system_clock_contexts are in the wrong place!");
|
||||
static_assert(offsetof(SharedMemoryStruct, network_system_clock_contexts) == 0x80,
|
||||
"network_system_clock_contexts are in the wrong place!");
|
||||
static_assert(offsetof(SharedMemoryStruct, automatic_corrections) == 0xC8,
|
||||
"automatic_corrections are in the wrong place!");
|
||||
static_assert(offsetof(SharedMemoryStruct, continuous_adjustment_time_points) == 0xD0,
|
||||
"continuous_adjustment_time_points are in the wrong place!");
|
||||
static_assert(sizeof(SharedMemoryStruct) == 0x1000,
|
||||
"Time's SharedMemoryStruct has the wrong size!");
|
||||
static_assert(std::is_trivial_v<SharedMemoryStruct>);
|
||||
|
||||
class SharedMemory {
|
||||
public:
|
||||
explicit SharedMemory(Core::System& system);
|
||||
|
||||
Kernel::KSharedMemory& GetKSharedMemory() {
|
||||
return m_k_shared_memory;
|
||||
}
|
||||
|
||||
void SetLocalSystemContext(SystemClockContext& context);
|
||||
void SetNetworkSystemContext(SystemClockContext& context);
|
||||
void SetSteadyClockTimePoint(ClockSourceId clock_source_id, s64 time_diff);
|
||||
void SetContinuousAdjustment(ContinuousAdjustmentTimePoint& time_point);
|
||||
void SetAutomaticCorrection(bool automatic_correction);
|
||||
void UpdateBaseTime(s64 time);
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
Kernel::KSharedMemory& m_k_shared_memory;
|
||||
SharedMemoryStruct* m_shared_memory_ptr;
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
488
src/core/hle/service/psc/time/static.cpp
Executable file
488
src/core/hle/service/psc/time/static.cpp
Executable file
@@ -0,0 +1,488 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h"
|
||||
#include "core/hle/service/psc/time/manager.h"
|
||||
#include "core/hle/service/psc/time/shared_memory.h"
|
||||
#include "core/hle/service/psc/time/static.h"
|
||||
#include "core/hle/service/psc/time/steady_clock.h"
|
||||
#include "core/hle/service/psc/time/system_clock.h"
|
||||
#include "core/hle/service/psc/time/time_zone.h"
|
||||
#include "core/hle/service/psc/time/time_zone_service.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
namespace {
|
||||
constexpr Result GetTimeFromTimePointAndContext(s64* out_time, SteadyClockTimePoint& time_point,
|
||||
SystemClockContext& context) {
|
||||
R_UNLESS(out_time != nullptr, ResultInvalidArgument);
|
||||
R_UNLESS(time_point.IdMatches(context.steady_time_point), ResultClockMismatch);
|
||||
|
||||
*out_time = context.offset + time_point.time_point;
|
||||
R_SUCCEED();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
StaticService::StaticService(Core::System& system_, StaticServiceSetupInfo setup_info,
|
||||
std::shared_ptr<TimeManager> time, const char* name)
|
||||
: ServiceFramework{system_, name}, m_system{system}, m_setup_info{setup_info}, m_time{time},
|
||||
m_local_system_clock{m_time->m_standard_local_system_clock},
|
||||
m_user_system_clock{m_time->m_standard_user_system_clock},
|
||||
m_network_system_clock{m_time->m_standard_network_system_clock},
|
||||
m_time_zone{m_time->m_time_zone},
|
||||
m_ephemeral_network_clock{m_time->m_ephemeral_network_clock}, m_shared_memory{
|
||||
m_time->m_shared_memory} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &StaticService::Handle_GetStandardUserSystemClock, "GetStandardUserSystemClock"},
|
||||
{1, &StaticService::Handle_GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"},
|
||||
{2, &StaticService::Handle_GetStandardSteadyClock, "GetStandardSteadyClock"},
|
||||
{3, &StaticService::Handle_GetTimeZoneService, "GetTimeZoneService"},
|
||||
{4, &StaticService::Handle_GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},
|
||||
{5, &StaticService::Handle_GetEphemeralNetworkSystemClock, "GetEphemeralNetworkSystemClock"},
|
||||
{20, &StaticService::Handle_GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
|
||||
{50, &StaticService::Handle_SetStandardSteadyClockInternalOffset, "SetStandardSteadyClockInternalOffset"},
|
||||
{51, &StaticService::Handle_GetStandardSteadyClockRtcValue, "GetStandardSteadyClockRtcValue"},
|
||||
{100, &StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{101, &StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||
{102, &StaticService::Handle_GetStandardUserSystemClockInitialYear, "GetStandardUserSystemClockInitialYear"},
|
||||
{200, &StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"},
|
||||
{201, &StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
|
||||
{300, &StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"},
|
||||
{400, &StaticService::Handle_GetClockSnapshot, "GetClockSnapshot"},
|
||||
{401, &StaticService::Handle_GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"},
|
||||
{500, &StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"},
|
||||
{501, &StaticService::Handle_CalculateSpanBetween, "CalculateSpanBetween"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
Result StaticService::GetClockSnapshotImpl(ClockSnapshot& out_snapshot,
|
||||
SystemClockContext& user_context,
|
||||
SystemClockContext& network_context, TimeType type) {
|
||||
out_snapshot.user_context = user_context;
|
||||
out_snapshot.network_context = network_context;
|
||||
|
||||
R_TRY(
|
||||
m_time->m_standard_steady_clock.GetCurrentTimePoint(out_snapshot.steady_clock_time_point));
|
||||
|
||||
out_snapshot.is_automatic_correction_enabled = m_user_system_clock.GetAutomaticCorrection();
|
||||
|
||||
R_TRY(m_time_zone.GetLocationName(out_snapshot.location_name));
|
||||
|
||||
R_TRY(GetTimeFromTimePointAndContext(
|
||||
&out_snapshot.user_time, out_snapshot.steady_clock_time_point, out_snapshot.user_context));
|
||||
|
||||
R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot.user_calendar_time,
|
||||
out_snapshot.user_calendar_additional_time,
|
||||
out_snapshot.user_time));
|
||||
|
||||
if (GetTimeFromTimePointAndContext(&out_snapshot.network_time,
|
||||
out_snapshot.steady_clock_time_point,
|
||||
out_snapshot.network_context) != ResultSuccess) {
|
||||
out_snapshot.network_time = 0;
|
||||
}
|
||||
|
||||
R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot.network_calendar_time,
|
||||
out_snapshot.network_calendar_additional_time,
|
||||
out_snapshot.network_time));
|
||||
out_snapshot.type = type;
|
||||
out_snapshot.unk_CE = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardUserSystemClock(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<SystemClock> service{};
|
||||
auto res = GetStandardUserSystemClock(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface<SystemClock>(std::move(service));
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<SystemClock> service{};
|
||||
auto res = GetStandardNetworkSystemClock(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface<SystemClock>(std::move(service));
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardSteadyClock(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<SteadyClock> service{};
|
||||
auto res = GetStandardSteadyClock(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface(std::move(service));
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetTimeZoneService(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<TimeZoneService> service{};
|
||||
auto res = GetTimeZoneService(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface(std::move(service));
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardLocalSystemClock(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<SystemClock> service{};
|
||||
auto res = GetStandardLocalSystemClock(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface<SystemClock>(std::move(service));
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
std::shared_ptr<SystemClock> service{};
|
||||
auto res = GetEphemeralNetworkSystemClock(service);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
rb.PushIpcInterface<SystemClock>(std::move(service));
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Kernel::KSharedMemory* shared_memory{};
|
||||
auto res = GetSharedMemoryNativeHandle(&shared_memory);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(res);
|
||||
rb.PushCopyObjects(shared_memory);
|
||||
}
|
||||
|
||||
void StaticService::Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(m_setup_info.can_write_steady_clock ? ResultNotImplemented : ResultPermissionDenied);
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultNotImplemented);
|
||||
}
|
||||
|
||||
void StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
bool is_enabled{};
|
||||
auto res = IsStandardUserSystemClockAutomaticCorrectionEnabled(is_enabled);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push<bool>(is_enabled);
|
||||
}
|
||||
|
||||
void StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto automatic_correction{rp.Pop<bool>()};
|
||||
|
||||
auto res = SetStandardUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultNotImplemented);
|
||||
}
|
||||
|
||||
void StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
bool is_sufficient{};
|
||||
auto res = IsStandardNetworkSystemClockAccuracySufficient(is_sufficient);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push<bool>(is_sufficient);
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
SteadyClockTimePoint time_point{};
|
||||
auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(SteadyClockTimePoint) / sizeof(u32)};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<SteadyClockTimePoint>(time_point);
|
||||
}
|
||||
|
||||
void StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto context{rp.PopRaw<SystemClockContext>()};
|
||||
|
||||
s64 time{};
|
||||
auto res = CalculateMonotonicSystemClockBaseTimePoint(time, context);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.Push<s64>(time);
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetClockSnapshot(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto type{rp.PopEnum<TimeType>()};
|
||||
|
||||
ClockSnapshot snapshot{};
|
||||
auto res = GetClockSnapshot(snapshot, type);
|
||||
|
||||
ctx.WriteBuffer(snapshot);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void StaticService::Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto user_context{rp.PopRaw<SystemClockContext>()};
|
||||
auto network_context{rp.PopRaw<SystemClockContext>()};
|
||||
auto clock_type{rp.PopEnum<TimeType>()};
|
||||
|
||||
ClockSnapshot snapshot{};
|
||||
auto res =
|
||||
GetClockSnapshotFromSystemClockContext(snapshot, user_context, network_context, clock_type);
|
||||
|
||||
ctx.WriteBuffer(snapshot);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
ClockSnapshot a{};
|
||||
ClockSnapshot b{};
|
||||
|
||||
auto a_buffer{ctx.ReadBuffer(0)};
|
||||
auto b_buffer{ctx.ReadBuffer(1)};
|
||||
|
||||
std::memcpy(&a, a_buffer.data(), sizeof(ClockSnapshot));
|
||||
std::memcpy(&b, b_buffer.data(), sizeof(ClockSnapshot));
|
||||
|
||||
s64 difference{};
|
||||
auto res = CalculateStandardUserSystemClockDifferenceByUser(difference, a, b);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.Push(difference);
|
||||
}
|
||||
|
||||
void StaticService::Handle_CalculateSpanBetween(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
ClockSnapshot a{};
|
||||
ClockSnapshot b{};
|
||||
|
||||
auto a_buffer{ctx.ReadBuffer(0)};
|
||||
auto b_buffer{ctx.ReadBuffer(1)};
|
||||
|
||||
std::memcpy(&a, a_buffer.data(), sizeof(ClockSnapshot));
|
||||
std::memcpy(&b, b_buffer.data(), sizeof(ClockSnapshot));
|
||||
|
||||
s64 time{};
|
||||
auto res = CalculateSpanBetween(time, a, b);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.Push(time);
|
||||
}
|
||||
|
||||
// =============================== Implementations ===========================
|
||||
|
||||
Result StaticService::GetStandardUserSystemClock(std::shared_ptr<SystemClock>& out_service) {
|
||||
out_service = std::make_shared<SystemClock>(m_system, m_user_system_clock,
|
||||
m_setup_info.can_write_user_clock,
|
||||
m_setup_info.can_write_uninitialized_clock);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::GetStandardNetworkSystemClock(std::shared_ptr<SystemClock>& out_service) {
|
||||
out_service = std::make_shared<SystemClock>(m_system, m_network_system_clock,
|
||||
m_setup_info.can_write_network_clock,
|
||||
m_setup_info.can_write_uninitialized_clock);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::GetStandardSteadyClock(std::shared_ptr<SteadyClock>& out_service) {
|
||||
out_service =
|
||||
std::make_shared<SteadyClock>(m_system, m_time, m_setup_info.can_write_steady_clock,
|
||||
m_setup_info.can_write_uninitialized_clock);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service) {
|
||||
out_service =
|
||||
std::make_shared<TimeZoneService>(m_system, m_time->m_standard_steady_clock, m_time_zone,
|
||||
m_setup_info.can_write_timezone_device_location);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::GetStandardLocalSystemClock(std::shared_ptr<SystemClock>& out_service) {
|
||||
out_service = std::make_shared<SystemClock>(m_system, m_local_system_clock,
|
||||
m_setup_info.can_write_local_clock,
|
||||
m_setup_info.can_write_uninitialized_clock);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::GetEphemeralNetworkSystemClock(std::shared_ptr<SystemClock>& out_service) {
|
||||
out_service = std::make_shared<SystemClock>(m_system, m_ephemeral_network_clock,
|
||||
m_setup_info.can_write_network_clock,
|
||||
m_setup_info.can_write_uninitialized_clock);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory) {
|
||||
*out_shared_memory = &m_shared_memory.GetKSharedMemory();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_is_enabled) {
|
||||
R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
|
||||
|
||||
out_is_enabled = m_user_system_clock.GetAutomaticCorrection();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled(
|
||||
bool automatic_correction) {
|
||||
R_UNLESS(m_user_system_clock.IsInitialized() && m_time->m_standard_steady_clock.IsInitialized(),
|
||||
ResultClockUninitialized);
|
||||
R_UNLESS(m_setup_info.can_write_user_clock, ResultPermissionDenied);
|
||||
|
||||
R_TRY(m_user_system_clock.SetAutomaticCorrection(automatic_correction));
|
||||
|
||||
m_shared_memory.SetAutomaticCorrection(automatic_correction);
|
||||
|
||||
SteadyClockTimePoint time_point{};
|
||||
R_TRY(m_time->m_standard_steady_clock.GetCurrentTimePoint(time_point));
|
||||
|
||||
m_user_system_clock.SetTimePointAndSignal(time_point);
|
||||
m_user_system_clock.GetEvent().Signal();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient) {
|
||||
out_is_sufficient = m_network_system_clock.IsAccuracySufficient();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
|
||||
SteadyClockTimePoint& out_time_point) {
|
||||
R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
|
||||
|
||||
m_user_system_clock.GetTimePoint(out_time_point);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(s64& out_time,
|
||||
SystemClockContext& context) {
|
||||
R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized);
|
||||
|
||||
SteadyClockTimePoint time_point{};
|
||||
R_TRY(m_time->m_standard_steady_clock.GetCurrentTimePoint(time_point));
|
||||
|
||||
R_UNLESS(time_point.IdMatches(context.steady_time_point), ResultClockMismatch);
|
||||
|
||||
auto one_second_ns{
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
|
||||
auto ticks{m_system.CoreTiming().GetClockTicks()};
|
||||
auto current_time{ConvertToTimeSpan(ticks).count()};
|
||||
out_time = ((context.offset + time_point.time_point) - (current_time / one_second_ns));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::GetClockSnapshot(ClockSnapshot& out_snapshot, TimeType type) {
|
||||
SystemClockContext user_context{};
|
||||
R_TRY(m_user_system_clock.GetContext(user_context));
|
||||
|
||||
SystemClockContext network_context{};
|
||||
R_TRY(m_network_system_clock.GetContext(network_context));
|
||||
|
||||
R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
|
||||
}
|
||||
|
||||
Result StaticService::GetClockSnapshotFromSystemClockContext(ClockSnapshot& out_snapshot,
|
||||
SystemClockContext& user_context,
|
||||
SystemClockContext& network_context,
|
||||
TimeType type) {
|
||||
R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
|
||||
}
|
||||
|
||||
Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(s64& out_time,
|
||||
ClockSnapshot& a,
|
||||
ClockSnapshot& b) {
|
||||
auto diff_s =
|
||||
std::chrono::seconds(b.user_context.offset) - std::chrono::seconds(a.user_context.offset);
|
||||
out_time = std::chrono::duration_cast<std::chrono::nanoseconds>(diff_s).count();
|
||||
|
||||
if (a.user_context != b.user_context ||
|
||||
(a.is_automatic_correction_enabled && b.is_automatic_correction_enabled) ||
|
||||
!a.network_context.steady_time_point.IdMatches(b.network_context.steady_time_point)) {
|
||||
out_time = 0;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result StaticService::CalculateSpanBetween(s64& out_time, ClockSnapshot& a, ClockSnapshot& b) {
|
||||
s64 time_s{};
|
||||
auto res =
|
||||
GetSpanBetweenTimePoints(&time_s, a.steady_clock_time_point, b.steady_clock_time_point);
|
||||
|
||||
if (res != ResultSuccess) {
|
||||
R_UNLESS(a.network_time != 0 && b.network_time != 0, ResultTimeNotFound);
|
||||
time_s = b.network_time - a.network_time;
|
||||
}
|
||||
|
||||
out_time =
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(time_s)).count();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
95
src/core/hle/service/psc/time/static.h
Executable file
95
src/core/hle/service/psc/time/static.h
Executable file
@@ -0,0 +1,95 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KSharedMemory;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
class TimeManager;
|
||||
class StandardLocalSystemClockCore;
|
||||
class StandardUserSystemClockCore;
|
||||
class StandardNetworkSystemClockCore;
|
||||
class TimeZone;
|
||||
class SystemClock;
|
||||
class SteadyClock;
|
||||
class TimeZoneService;
|
||||
class EphemeralNetworkSystemClockCore;
|
||||
class SharedMemory;
|
||||
|
||||
class StaticService final : public ServiceFramework<StaticService> {
|
||||
public:
|
||||
explicit StaticService(Core::System& system, StaticServiceSetupInfo setup_info,
|
||||
std::shared_ptr<TimeManager> time, const char* name);
|
||||
|
||||
~StaticService() override = default;
|
||||
|
||||
Result GetStandardUserSystemClock(std::shared_ptr<SystemClock>& out_service);
|
||||
Result GetStandardNetworkSystemClock(std::shared_ptr<SystemClock>& out_service);
|
||||
Result GetStandardSteadyClock(std::shared_ptr<SteadyClock>& out_service);
|
||||
Result GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service);
|
||||
Result GetStandardLocalSystemClock(std::shared_ptr<SystemClock>& out_service);
|
||||
Result GetEphemeralNetworkSystemClock(std::shared_ptr<SystemClock>& out_service);
|
||||
Result GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory);
|
||||
Result IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_is_enabled);
|
||||
Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction);
|
||||
Result IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient);
|
||||
Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
|
||||
SteadyClockTimePoint& out_time_point);
|
||||
Result CalculateMonotonicSystemClockBaseTimePoint(s64& out_time, SystemClockContext& context);
|
||||
Result GetClockSnapshot(ClockSnapshot& out_snapshot, TimeType type);
|
||||
Result GetClockSnapshotFromSystemClockContext(ClockSnapshot& out_snapshot,
|
||||
SystemClockContext& user_context,
|
||||
SystemClockContext& network_context,
|
||||
TimeType type);
|
||||
Result CalculateStandardUserSystemClockDifferenceByUser(s64& out_time, ClockSnapshot& a,
|
||||
ClockSnapshot& b);
|
||||
Result CalculateSpanBetween(s64& out_time, ClockSnapshot& a, ClockSnapshot& b);
|
||||
|
||||
private:
|
||||
Result GetClockSnapshotImpl(ClockSnapshot& out_snapshot, SystemClockContext& user_context,
|
||||
SystemClockContext& network_context, TimeType type);
|
||||
|
||||
void Handle_GetStandardUserSystemClock(HLERequestContext& ctx);
|
||||
void Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx);
|
||||
void Handle_GetStandardSteadyClock(HLERequestContext& ctx);
|
||||
void Handle_GetTimeZoneService(HLERequestContext& ctx);
|
||||
void Handle_GetStandardLocalSystemClock(HLERequestContext& ctx);
|
||||
void Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx);
|
||||
void Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx);
|
||||
void Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx);
|
||||
void Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx);
|
||||
void Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
|
||||
void Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
|
||||
void Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx);
|
||||
void Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx);
|
||||
void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx);
|
||||
void Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx);
|
||||
void Handle_GetClockSnapshot(HLERequestContext& ctx);
|
||||
void Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx);
|
||||
void Handle_CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx);
|
||||
void Handle_CalculateSpanBetween(HLERequestContext& ctx);
|
||||
|
||||
Core::System& m_system;
|
||||
StaticServiceSetupInfo m_setup_info;
|
||||
std::shared_ptr<TimeManager> m_time;
|
||||
StandardLocalSystemClockCore& m_local_system_clock;
|
||||
StandardUserSystemClockCore& m_user_system_clock;
|
||||
StandardNetworkSystemClockCore& m_network_system_clock;
|
||||
TimeZone& m_time_zone;
|
||||
EphemeralNetworkSystemClockCore& m_ephemeral_network_clock;
|
||||
SharedMemory& m_shared_memory;
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
164
src/core/hle/service/psc/time/steady_clock.cpp
Executable file
164
src/core/hle/service/psc/time/steady_clock.cpp
Executable file
@@ -0,0 +1,164 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/psc/time/steady_clock.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
SteadyClock::SteadyClock(Core::System& system_, std::shared_ptr<TimeManager> manager,
|
||||
bool can_write_steady_clock, bool can_write_uninitialized_clock)
|
||||
: ServiceFramework{system_, "ISteadyClock"}, m_system{system},
|
||||
m_clock_core{manager->m_standard_steady_clock},
|
||||
m_can_write_steady_clock{can_write_steady_clock}, m_can_write_uninitialized_clock{
|
||||
can_write_uninitialized_clock} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &SteadyClock::Handle_GetCurrentTimePoint, "GetCurrentTimePoint"},
|
||||
{1, &SteadyClock::Handle_GetTestOffset, "GetTestOffset"},
|
||||
{2, &SteadyClock::Handle_SetTestOffset, "SetTestOffset"},
|
||||
{3, &SteadyClock::Handle_GetRtcValue, "GetRtcValue"},
|
||||
{4, &SteadyClock::Handle_IsRtcResetDetected, "IsRtcResetDetected"},
|
||||
{5, &SteadyClock::Handle_GetSetupResultValue, "GetSetupResultValue"},
|
||||
{6, &SteadyClock::Handle_GetInternalOffset, "GetInternalOffset"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void SteadyClock::Handle_GetCurrentTimePoint(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
SteadyClockTimePoint time_point{};
|
||||
auto res = GetCurrentTimePoint(time_point);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(SteadyClockTimePoint) / sizeof(u32)};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<SteadyClockTimePoint>(time_point);
|
||||
}
|
||||
|
||||
void SteadyClock::Handle_GetTestOffset(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
s64 test_offset{};
|
||||
auto res = GetTestOffset(test_offset);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.Push(test_offset);
|
||||
}
|
||||
|
||||
void SteadyClock::Handle_SetTestOffset(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto test_offset{rp.Pop<s64>()};
|
||||
|
||||
auto res = SetTestOffset(test_offset);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void SteadyClock::Handle_GetRtcValue(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
s64 rtc_value{};
|
||||
auto res = GetRtcValue(rtc_value);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.Push(rtc_value);
|
||||
}
|
||||
|
||||
void SteadyClock::Handle_IsRtcResetDetected(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
bool reset_detected{false};
|
||||
auto res = IsRtcResetDetected(reset_detected);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push(reset_detected);
|
||||
}
|
||||
|
||||
void SteadyClock::Handle_GetSetupResultValue(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Result result_value{ResultSuccess};
|
||||
auto res = GetSetupResultValue(result_value);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push(result_value);
|
||||
}
|
||||
|
||||
void SteadyClock::Handle_GetInternalOffset(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
s64 internal_offset{};
|
||||
auto res = GetInternalOffset(internal_offset);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.Push(internal_offset);
|
||||
}
|
||||
|
||||
// =============================== Implementations ===========================
|
||||
|
||||
Result SteadyClock::GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) {
|
||||
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
|
||||
ResultClockUninitialized);
|
||||
|
||||
R_RETURN(m_clock_core.GetCurrentTimePoint(out_time_point));
|
||||
}
|
||||
|
||||
Result SteadyClock::GetTestOffset(s64& out_test_offset) {
|
||||
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
|
||||
ResultClockUninitialized);
|
||||
|
||||
out_test_offset = m_clock_core.GetTestOffset();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SteadyClock::SetTestOffset(s64 test_offset) {
|
||||
R_UNLESS(m_can_write_steady_clock, ResultPermissionDenied);
|
||||
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
|
||||
ResultClockUninitialized);
|
||||
|
||||
m_clock_core.SetTestOffset(test_offset);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SteadyClock::GetRtcValue(s64& out_rtc_value) {
|
||||
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
|
||||
ResultClockUninitialized);
|
||||
|
||||
R_RETURN(m_clock_core.GetRtcValue(out_rtc_value));
|
||||
}
|
||||
|
||||
Result SteadyClock::IsRtcResetDetected(bool& out_is_detected) {
|
||||
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
|
||||
ResultClockUninitialized);
|
||||
|
||||
out_is_detected = m_clock_core.IsResetDetected();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SteadyClock::GetSetupResultValue(Result& out_result) {
|
||||
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
|
||||
ResultClockUninitialized);
|
||||
|
||||
out_result = m_clock_core.GetSetupResultValue();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SteadyClock::GetInternalOffset(s64& out_internal_offset) {
|
||||
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
|
||||
ResultClockUninitialized);
|
||||
|
||||
out_internal_offset = m_clock_core.GetInternalOffset();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
49
src/core/hle/service/psc/time/steady_clock.h
Executable file
49
src/core/hle/service/psc/time/steady_clock.h
Executable file
@@ -0,0 +1,49 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
#include "core/hle/service/psc/time/manager.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
class SteadyClock final : public ServiceFramework<SteadyClock> {
|
||||
public:
|
||||
explicit SteadyClock(Core::System& system, std::shared_ptr<TimeManager> manager,
|
||||
bool can_write_steady_clock, bool can_write_uninitialized_clock);
|
||||
|
||||
~SteadyClock() override = default;
|
||||
|
||||
Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point);
|
||||
Result GetTestOffset(s64& out_test_offset);
|
||||
Result SetTestOffset(s64 test_offset);
|
||||
Result GetRtcValue(s64& out_rtc_value);
|
||||
Result IsRtcResetDetected(bool& out_is_detected);
|
||||
Result GetSetupResultValue(Result& out_result);
|
||||
Result GetInternalOffset(s64& out_internal_offset);
|
||||
|
||||
private:
|
||||
void Handle_GetCurrentTimePoint(HLERequestContext& ctx);
|
||||
void Handle_GetTestOffset(HLERequestContext& ctx);
|
||||
void Handle_SetTestOffset(HLERequestContext& ctx);
|
||||
void Handle_GetRtcValue(HLERequestContext& ctx);
|
||||
void Handle_IsRtcResetDetected(HLERequestContext& ctx);
|
||||
void Handle_GetSetupResultValue(HLERequestContext& ctx);
|
||||
void Handle_GetInternalOffset(HLERequestContext& ctx);
|
||||
|
||||
Core::System& m_system;
|
||||
|
||||
StandardSteadyClockCore& m_clock_core;
|
||||
bool m_can_write_steady_clock;
|
||||
bool m_can_write_uninitialized_clock;
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
129
src/core/hle/service/psc/time/system_clock.cpp
Executable file
129
src/core/hle/service/psc/time/system_clock.cpp
Executable file
@@ -0,0 +1,129 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/psc/time/system_clock.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
SystemClock::SystemClock(Core::System& system_, SystemClockCore& clock_core, bool can_write_clock,
|
||||
bool can_write_uninitialized_clock)
|
||||
: ServiceFramework{system_, "ISystemClock"}, m_system{system}, m_clock_core{clock_core},
|
||||
m_can_write_clock{can_write_clock}, m_can_write_uninitialized_clock{
|
||||
can_write_uninitialized_clock} {
|
||||
SystemClockContext ctx{};
|
||||
m_clock_core.GetContext(ctx);
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &SystemClock::Handle_GetCurrentTime, "GetCurrentTime"},
|
||||
{1, &SystemClock::Handle_SetCurrentTime, "SetCurrentTime"},
|
||||
{2, &SystemClock::Handle_GetSystemClockContext, "GetSystemClockContext"},
|
||||
{3, &SystemClock::Handle_SetSystemClockContext, "SetSystemClockContext"},
|
||||
{4, &SystemClock::Handle_GetOperationEventReadableHandle, "GetOperationEventReadableHandle"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void SystemClock::Handle_GetCurrentTime(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
s64 time{};
|
||||
auto res = GetCurrentTime(time);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(res);
|
||||
rb.Push<s64>(time);
|
||||
}
|
||||
|
||||
void SystemClock::Handle_SetCurrentTime(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto time{rp.Pop<s64>()};
|
||||
|
||||
auto res = SetCurrentTime(time);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void SystemClock::Handle_GetSystemClockContext(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
SystemClockContext context{};
|
||||
auto res = GetSystemClockContext(context);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(SystemClockContext) / sizeof(u32)};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<SystemClockContext>(context);
|
||||
}
|
||||
|
||||
void SystemClock::Handle_SetSystemClockContext(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto context{rp.PopRaw<SystemClockContext>()};
|
||||
|
||||
auto res = SetSystemClockContext(context);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void SystemClock::Handle_GetOperationEventReadableHandle(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
Kernel::KEvent* event{};
|
||||
auto res = GetOperationEventReadableHandle(&event);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(res);
|
||||
rb.PushCopyObjects(event->GetReadableEvent());
|
||||
}
|
||||
|
||||
// =============================== Implementations ===========================
|
||||
|
||||
Result SystemClock::GetCurrentTime(s64& out_time) {
|
||||
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
|
||||
ResultClockUninitialized);
|
||||
|
||||
R_RETURN(m_clock_core.GetCurrentTime(&out_time));
|
||||
}
|
||||
|
||||
Result SystemClock::SetCurrentTime(s64 time) {
|
||||
R_UNLESS(m_can_write_clock, ResultPermissionDenied);
|
||||
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
|
||||
ResultClockUninitialized);
|
||||
|
||||
R_RETURN(m_clock_core.SetCurrentTime(time));
|
||||
}
|
||||
|
||||
Result SystemClock::GetSystemClockContext(SystemClockContext& out_context) {
|
||||
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
|
||||
ResultClockUninitialized);
|
||||
|
||||
R_RETURN(m_clock_core.GetContext(out_context));
|
||||
}
|
||||
|
||||
Result SystemClock::SetSystemClockContext(SystemClockContext& context) {
|
||||
R_UNLESS(m_can_write_clock, ResultPermissionDenied);
|
||||
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
|
||||
ResultClockUninitialized);
|
||||
|
||||
R_RETURN(m_clock_core.SetContextAndWrite(context));
|
||||
}
|
||||
|
||||
Result SystemClock::GetOperationEventReadableHandle(Kernel::KEvent** out_event) {
|
||||
R_SUCCEED_IF(m_operation_event != nullptr);
|
||||
|
||||
m_operation_event = std::make_unique<OperationEvent>(m_system);
|
||||
R_UNLESS(m_operation_event != nullptr, ResultFailed);
|
||||
|
||||
m_clock_core.LinkOperationEvent(*m_operation_event);
|
||||
|
||||
*out_event = m_operation_event->m_event;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
46
src/core/hle/service/psc/time/system_clock.h
Executable file
46
src/core/hle/service/psc/time/system_clock.h
Executable file
@@ -0,0 +1,46 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
#include "core/hle/service/psc/time/manager.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
class SystemClock final : public ServiceFramework<SystemClock> {
|
||||
public:
|
||||
explicit SystemClock(Core::System& system, SystemClockCore& system_clock_core,
|
||||
bool can_write_clock, bool can_write_uninitialized_clock);
|
||||
|
||||
~SystemClock() override = default;
|
||||
|
||||
Result GetCurrentTime(s64& out_time);
|
||||
Result SetCurrentTime(s64 time);
|
||||
Result GetSystemClockContext(SystemClockContext& out_context);
|
||||
Result SetSystemClockContext(SystemClockContext& context);
|
||||
Result GetOperationEventReadableHandle(Kernel::KEvent** out_event);
|
||||
|
||||
private:
|
||||
void Handle_GetCurrentTime(HLERequestContext& ctx);
|
||||
void Handle_SetCurrentTime(HLERequestContext& ctx);
|
||||
void Handle_GetSystemClockContext(HLERequestContext& ctx);
|
||||
void Handle_SetSystemClockContext(HLERequestContext& ctx);
|
||||
void Handle_GetOperationEventReadableHandle(HLERequestContext& ctx);
|
||||
|
||||
Core::System& m_system;
|
||||
|
||||
SystemClockCore& m_clock_core;
|
||||
bool m_can_write_clock;
|
||||
bool m_can_write_uninitialized_clock;
|
||||
std::unique_ptr<OperationEvent> m_operation_event{};
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
280
src/core/hle/service/psc/time/time_zone.cpp
Executable file
280
src/core/hle/service/psc/time/time_zone.cpp
Executable file
@@ -0,0 +1,280 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/psc/time/time_zone.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
namespace {
|
||||
constexpr Result ValidateRule(Tz::Rule& rule) {
|
||||
if (rule.typecnt > static_cast<s32>(Tz::TZ_MAX_TYPES) ||
|
||||
rule.timecnt > static_cast<s32>(Tz::TZ_MAX_TIMES) ||
|
||||
rule.charcnt > static_cast<s32>(Tz::TZ_MAX_CHARS)) {
|
||||
R_RETURN(ResultTimeZoneOutOfRange);
|
||||
}
|
||||
|
||||
for (s32 i = 0; i < rule.timecnt; i++) {
|
||||
if (rule.types[i] >= rule.typecnt) {
|
||||
R_RETURN(ResultTimeZoneOutOfRange);
|
||||
}
|
||||
}
|
||||
|
||||
for (s32 i = 0; i < rule.typecnt; i++) {
|
||||
if (rule.ttis[i].tt_desigidx >= static_cast<s32>(rule.chars.size())) {
|
||||
R_RETURN(ResultTimeZoneOutOfRange);
|
||||
}
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
constexpr bool GetTimeZoneTime(s64& out_time, Tz::Rule& rule, s64 time, s32 index,
|
||||
s32 index_offset) {
|
||||
s32 found_idx{};
|
||||
s32 expected_index{index + index_offset};
|
||||
s64 time_to_find{time + rule.ttis[rule.types[index]].tt_utoff -
|
||||
rule.ttis[rule.types[expected_index]].tt_utoff};
|
||||
|
||||
if (rule.timecnt > 1 && rule.ats[0] <= time_to_find) {
|
||||
s32 low{1};
|
||||
s32 high{rule.timecnt};
|
||||
|
||||
while (low < high) {
|
||||
auto mid{(low + high) / 2};
|
||||
if (rule.ats[mid] <= time_to_find) {
|
||||
low = mid + 1;
|
||||
} else if (rule.ats[mid] > time_to_find) {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
found_idx = low - 1;
|
||||
}
|
||||
|
||||
if (found_idx == expected_index) {
|
||||
out_time = time_to_find;
|
||||
}
|
||||
return found_idx == expected_index;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void TimeZone::SetTimePoint(SteadyClockTimePoint& time_point) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
m_steady_clock_time_point = time_point;
|
||||
}
|
||||
|
||||
void TimeZone::SetTotalLocationNameCount(u32 count) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
m_total_location_name_count = count;
|
||||
}
|
||||
|
||||
void TimeZone::SetRuleVersion(RuleVersion& rule_version) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
m_rule_version = rule_version;
|
||||
}
|
||||
|
||||
Result TimeZone::GetLocationName(LocationName& out_name) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
R_UNLESS(m_initialized, ResultClockUninitialized);
|
||||
out_name = m_location;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result TimeZone::GetTotalLocationCount(u32& out_count) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
if (!m_initialized) {
|
||||
return ResultClockUninitialized;
|
||||
}
|
||||
|
||||
out_count = m_total_location_name_count;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result TimeZone::GetRuleVersion(RuleVersion& out_rule_version) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
if (!m_initialized) {
|
||||
return ResultClockUninitialized;
|
||||
}
|
||||
out_rule_version = m_rule_version;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result TimeZone::GetTimePoint(SteadyClockTimePoint& out_time_point) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
if (!m_initialized) {
|
||||
return ResultClockUninitialized;
|
||||
}
|
||||
out_time_point = m_steady_clock_time_point;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result TimeZone::ToCalendarTime(CalendarTime& out_calendar_time,
|
||||
CalendarAdditionalInfo& out_additional_info, s64 time,
|
||||
Tz::Rule& rule) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
R_RETURN(ToCalendarTimeImpl(out_calendar_time, out_additional_info, time, rule));
|
||||
}
|
||||
|
||||
Result TimeZone::ToCalendarTimeWithMyRule(CalendarTime& calendar_time,
|
||||
CalendarAdditionalInfo& calendar_additional, s64 time) {
|
||||
// This is checked outside the mutex. Bug?
|
||||
if (!m_initialized) {
|
||||
return ResultClockUninitialized;
|
||||
}
|
||||
|
||||
std::scoped_lock l{m_mutex};
|
||||
R_RETURN(ToCalendarTimeImpl(calendar_time, calendar_additional, time, m_my_rule));
|
||||
}
|
||||
|
||||
Result TimeZone::ParseBinary(LocationName& name, std::span<const u8> binary) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
|
||||
Tz::Rule tmp_rule{};
|
||||
R_TRY(ParseBinaryImpl(tmp_rule, binary));
|
||||
|
||||
m_my_rule = tmp_rule;
|
||||
m_location = name;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result TimeZone::ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
R_RETURN(ParseBinaryImpl(out_rule, binary));
|
||||
}
|
||||
|
||||
Result TimeZone::ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
|
||||
CalendarTime& calendar, Tz::Rule& rule) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
|
||||
auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, rule, -1);
|
||||
|
||||
if (res != ResultSuccess) {
|
||||
if (res == ResultTimeZoneNotFound) {
|
||||
res = ResultSuccess;
|
||||
out_count = 0;
|
||||
}
|
||||
} else if (out_count == 2 && out_times[0] > out_times[1]) {
|
||||
std::swap(out_times[0], out_times[1]);
|
||||
}
|
||||
R_RETURN(res);
|
||||
}
|
||||
|
||||
Result TimeZone::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times,
|
||||
u32 out_times_count, CalendarTime& calendar) {
|
||||
std::scoped_lock l{m_mutex};
|
||||
|
||||
auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, m_my_rule, -1);
|
||||
|
||||
if (res != ResultSuccess) {
|
||||
if (res == ResultTimeZoneNotFound) {
|
||||
res = ResultSuccess;
|
||||
out_count = 0;
|
||||
}
|
||||
} else if (out_count == 2 && out_times[0] > out_times[1]) {
|
||||
std::swap(out_times[0], out_times[1]);
|
||||
}
|
||||
R_RETURN(res);
|
||||
}
|
||||
|
||||
Result TimeZone::ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary) {
|
||||
if (Tz::ParseTimeZoneBinary(out_rule, binary)) {
|
||||
R_RETURN(ResultTimeZoneParseFailed);
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result TimeZone::ToCalendarTimeImpl(CalendarTime& out_calendar_time,
|
||||
CalendarAdditionalInfo& out_additional_info, s64 time,
|
||||
Tz::Rule& rule) {
|
||||
R_TRY(ValidateRule(rule));
|
||||
|
||||
Tz::CalendarTimeInternal calendar_internal{};
|
||||
time_t time_tmp{static_cast<time_t>(time)};
|
||||
if (Tz::localtime_rz(&calendar_internal, &rule, &time_tmp)) {
|
||||
R_RETURN(ResultOverflow);
|
||||
}
|
||||
|
||||
out_calendar_time.year = static_cast<s16>(calendar_internal.tm_year + 1900);
|
||||
out_calendar_time.month = static_cast<s8>(calendar_internal.tm_mon + 1);
|
||||
out_calendar_time.day = static_cast<s8>(calendar_internal.tm_mday);
|
||||
out_calendar_time.hour = static_cast<s8>(calendar_internal.tm_hour);
|
||||
out_calendar_time.minute = static_cast<s8>(calendar_internal.tm_min);
|
||||
out_calendar_time.second = static_cast<s8>(calendar_internal.tm_sec);
|
||||
|
||||
out_additional_info.day_of_week = calendar_internal.tm_wday;
|
||||
out_additional_info.day_of_year = calendar_internal.tm_yday;
|
||||
|
||||
std::memcpy(out_additional_info.name.data(), calendar_internal.tm_zone.data(),
|
||||
out_additional_info.name.size());
|
||||
out_additional_info.name[out_additional_info.name.size() - 1] = '\0';
|
||||
|
||||
out_additional_info.is_dst = calendar_internal.tm_isdst;
|
||||
out_additional_info.ut_offset = calendar_internal.tm_utoff;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
|
||||
CalendarTime& calendar, Tz::Rule& rule, s32 is_dst) {
|
||||
R_TRY(ValidateRule(rule));
|
||||
|
||||
calendar.month -= 1;
|
||||
calendar.year -= 1900;
|
||||
|
||||
Tz::CalendarTimeInternal internal{
|
||||
.tm_sec = calendar.second,
|
||||
.tm_min = calendar.minute,
|
||||
.tm_hour = calendar.hour,
|
||||
.tm_mday = calendar.day,
|
||||
.tm_mon = calendar.month,
|
||||
.tm_year = calendar.year,
|
||||
.tm_wday = 0,
|
||||
.tm_yday = 0,
|
||||
.tm_isdst = is_dst,
|
||||
.tm_zone = {},
|
||||
.tm_utoff = 0,
|
||||
.time_index = 0,
|
||||
};
|
||||
time_t time_tmp{};
|
||||
auto res = Tz::mktime_tzname(&time_tmp, &rule, &internal);
|
||||
s64 time = static_cast<s64>(time_tmp);
|
||||
|
||||
if (res == 1) {
|
||||
R_RETURN(ResultOverflow);
|
||||
} else if (res == 2) {
|
||||
R_RETURN(ResultTimeZoneNotFound);
|
||||
}
|
||||
|
||||
if (internal.tm_sec != calendar.second || internal.tm_min != calendar.minute ||
|
||||
internal.tm_hour != calendar.hour || internal.tm_mday != calendar.day ||
|
||||
internal.tm_mon != calendar.month || internal.tm_year != calendar.year) {
|
||||
R_RETURN(ResultTimeZoneNotFound);
|
||||
}
|
||||
|
||||
if (res != 0) {
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
out_times[0] = time;
|
||||
if (out_times_count < 2) {
|
||||
out_count = 1;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
s64 time2{};
|
||||
if (internal.time_index > 0 && GetTimeZoneTime(time2, rule, time, internal.time_index, -1)) {
|
||||
out_times[1] = time2;
|
||||
out_count = 2;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
if (((internal.time_index + 1) < rule.timecnt) &&
|
||||
GetTimeZoneTime(time2, rule, time, internal.time_index, 1)) {
|
||||
out_times[1] = time2;
|
||||
out_count = 2;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
out_count = 1;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
62
src/core/hle/service/psc/time/time_zone.h
Executable file
62
src/core/hle/service/psc/time/time_zone.h
Executable file
@@ -0,0 +1,62 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
|
||||
#include <tz/tz.h>
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
class TimeZone {
|
||||
public:
|
||||
TimeZone() = default;
|
||||
|
||||
bool IsInitialized() const {
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
void SetInitialized() {
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
void SetTimePoint(SteadyClockTimePoint& time_point);
|
||||
void SetTotalLocationNameCount(u32 count);
|
||||
void SetRuleVersion(RuleVersion& rule_version);
|
||||
Result GetLocationName(LocationName& out_name);
|
||||
Result GetTotalLocationCount(u32& out_count);
|
||||
Result GetRuleVersion(RuleVersion& out_rule_version);
|
||||
Result GetTimePoint(SteadyClockTimePoint& out_time_point);
|
||||
|
||||
Result ToCalendarTime(CalendarTime& out_calendar_time,
|
||||
CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule);
|
||||
Result ToCalendarTimeWithMyRule(CalendarTime& calendar_time,
|
||||
CalendarAdditionalInfo& calendar_additional, s64 time);
|
||||
Result ParseBinary(LocationName& name, std::span<const u8> binary);
|
||||
Result ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary);
|
||||
Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
|
||||
CalendarTime& calendar, Tz::Rule& rule);
|
||||
Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
|
||||
CalendarTime& calendar);
|
||||
|
||||
private:
|
||||
Result ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary);
|
||||
Result ToCalendarTimeImpl(CalendarTime& out_calendar_time,
|
||||
CalendarAdditionalInfo& out_additional_info, s64 time,
|
||||
Tz::Rule& rule);
|
||||
Result ToPosixTimeImpl(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
|
||||
CalendarTime& calendar, Tz::Rule& rule, s32 is_dst);
|
||||
|
||||
bool m_initialized{};
|
||||
std::recursive_mutex m_mutex;
|
||||
LocationName m_location{};
|
||||
Tz::Rule m_my_rule{};
|
||||
SteadyClockTimePoint m_steady_clock_time_point{};
|
||||
u32 m_total_location_name_count{};
|
||||
RuleVersion m_rule_version{};
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
289
src/core/hle/service/psc/time/time_zone_service.cpp
Executable file
289
src/core/hle/service/psc/time/time_zone_service.cpp
Executable file
@@ -0,0 +1,289 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <tz/tz.h>
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/psc/time/time_zone_service.h"
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
TimeZoneService::TimeZoneService(Core::System& system_, StandardSteadyClockCore& clock_core,
|
||||
TimeZone& time_zone, bool can_write_timezone_device_location)
|
||||
: ServiceFramework{system_, "ITimeZoneService"}, m_system{system}, m_clock_core{clock_core},
|
||||
m_time_zone{time_zone}, m_can_write_timezone_device_location{
|
||||
can_write_timezone_device_location} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &TimeZoneService::Handle_GetDeviceLocationName, "GetDeviceLocationName"},
|
||||
{1, &TimeZoneService::Handle_SetDeviceLocationName, "SetDeviceLocationName"},
|
||||
{2, &TimeZoneService::Handle_GetTotalLocationNameCount, "GetTotalLocationNameCount"},
|
||||
{3, &TimeZoneService::Handle_LoadLocationNameList, "LoadLocationNameList"},
|
||||
{4, &TimeZoneService::Handle_LoadTimeZoneRule, "LoadTimeZoneRule"},
|
||||
{5, &TimeZoneService::Handle_GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"},
|
||||
{6, &TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime, "GetDeviceLocationNameAndUpdatedTime"},
|
||||
{7, &TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule, "SetDeviceLocationNameWithTimeZoneRule"},
|
||||
{8, &TimeZoneService::Handle_ParseTimeZoneBinary, "ParseTimeZoneBinary"},
|
||||
{20, &TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle, "GetDeviceLocationNameOperationEventReadableHandle"},
|
||||
{100, &TimeZoneService::Handle_ToCalendarTime, "ToCalendarTime"},
|
||||
{101, &TimeZoneService::Handle_ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
|
||||
{201, &TimeZoneService::Handle_ToPosixTime, "ToPosixTime"},
|
||||
{202, &TimeZoneService::Handle_ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_GetDeviceLocationName(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
LocationName name{};
|
||||
auto res = GetDeviceLocationName(name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(LocationName) / sizeof(u32)};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<LocationName>(name);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_SetDeviceLocationName(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
[[maybe_unused]] auto name{rp.PopRaw<LocationName>()};
|
||||
|
||||
if (!m_can_write_timezone_device_location) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultPermissionDenied);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultNotImplemented);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_GetTotalLocationNameCount(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
u32 count{};
|
||||
auto res = GetTotalLocationNameCount(count);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push(count);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_LoadLocationNameList(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultNotImplemented);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_LoadTimeZoneRule(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultNotImplemented);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
RuleVersion rule_version{};
|
||||
auto res = GetTimeZoneRuleVersion(rule_version);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(RuleVersion) / sizeof(u32)};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<RuleVersion>(rule_version);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
LocationName name{};
|
||||
SteadyClockTimePoint time_point{};
|
||||
auto res = GetDeviceLocationNameAndUpdatedTime(time_point, name);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + (sizeof(LocationName) / sizeof(u32)) +
|
||||
(sizeof(SteadyClockTimePoint) / sizeof(u32))};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<LocationName>(name);
|
||||
rb.PushRaw<SteadyClockTimePoint>(time_point);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto name{rp.PopRaw<LocationName>()};
|
||||
|
||||
auto binary{ctx.ReadBuffer()};
|
||||
auto res = SetDeviceLocationNameWithTimeZoneRule(name, binary);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_ParseTimeZoneBinary(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
auto binary{ctx.ReadBuffer()};
|
||||
|
||||
Tz::Rule rule{};
|
||||
auto res = ParseTimeZoneBinary(rule, binary);
|
||||
|
||||
ctx.WriteBuffer(rule);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(res);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle(
|
||||
HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultNotImplemented);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_ToCalendarTime(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto time{rp.Pop<s64>()};
|
||||
|
||||
auto rule_buffer{ctx.ReadBuffer()};
|
||||
Tz::Rule rule{};
|
||||
std::memcpy(&rule, rule_buffer.data(), sizeof(Tz::Rule));
|
||||
|
||||
CalendarTime calendar_time{};
|
||||
CalendarAdditionalInfo additional_info{};
|
||||
auto res = ToCalendarTime(calendar_time, additional_info, time, rule);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + (sizeof(CalendarTime) / sizeof(u32)) +
|
||||
(sizeof(CalendarAdditionalInfo) / sizeof(u32))};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<CalendarTime>(calendar_time);
|
||||
rb.PushRaw<CalendarAdditionalInfo>(additional_info);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto time{rp.Pop<s64>()};
|
||||
|
||||
CalendarTime calendar_time{};
|
||||
CalendarAdditionalInfo additional_info{};
|
||||
auto res = ToCalendarTimeWithMyRule(calendar_time, additional_info, time);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + (sizeof(CalendarTime) / sizeof(u32)) +
|
||||
(sizeof(CalendarAdditionalInfo) / sizeof(u32))};
|
||||
rb.Push(res);
|
||||
rb.PushRaw<CalendarTime>(calendar_time);
|
||||
rb.PushRaw<CalendarAdditionalInfo>(additional_info);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_ToPosixTime(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto calendar{rp.PopRaw<CalendarTime>()};
|
||||
|
||||
auto binary{ctx.ReadBuffer()};
|
||||
|
||||
Tz::Rule rule{};
|
||||
std::memcpy(&rule, binary.data(), sizeof(Tz::Rule));
|
||||
|
||||
u32 count{};
|
||||
std::array<s64, 2> times{};
|
||||
u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
|
||||
|
||||
auto res = ToPosixTime(count, times, times_count, calendar, rule);
|
||||
|
||||
ctx.WriteBuffer(times);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push(count);
|
||||
}
|
||||
|
||||
void TimeZoneService::Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called.");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto calendar{rp.PopRaw<CalendarTime>()};
|
||||
|
||||
u32 count{};
|
||||
std::array<s64, 2> times{};
|
||||
u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
|
||||
|
||||
auto res = ToPosixTimeWithMyRule(count, times, times_count, calendar);
|
||||
|
||||
ctx.WriteBuffer(times);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(res);
|
||||
rb.Push(count);
|
||||
}
|
||||
|
||||
// =============================== Implementations ===========================
|
||||
|
||||
Result TimeZoneService::GetDeviceLocationName(LocationName& out_lcoation_name) {
|
||||
R_RETURN(m_time_zone.GetLocationName(out_lcoation_name));
|
||||
}
|
||||
|
||||
Result TimeZoneService::GetTotalLocationNameCount(u32& out_count) {
|
||||
R_RETURN(m_time_zone.GetTotalLocationCount(out_count));
|
||||
}
|
||||
|
||||
Result TimeZoneService::GetTimeZoneRuleVersion(RuleVersion& out_rule_version) {
|
||||
R_RETURN(m_time_zone.GetRuleVersion(out_rule_version));
|
||||
}
|
||||
|
||||
Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(SteadyClockTimePoint& out_time_point,
|
||||
LocationName& location_name) {
|
||||
R_TRY(m_time_zone.GetLocationName(location_name));
|
||||
R_RETURN(m_time_zone.GetTimePoint(out_time_point));
|
||||
}
|
||||
|
||||
Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule(LocationName& location_name,
|
||||
std::span<const u8> binary) {
|
||||
R_UNLESS(m_can_write_timezone_device_location, ResultPermissionDenied);
|
||||
R_TRY(m_time_zone.ParseBinary(location_name, binary));
|
||||
|
||||
SteadyClockTimePoint time_point{};
|
||||
R_TRY(m_clock_core.GetCurrentTimePoint(time_point));
|
||||
|
||||
m_time_zone.SetTimePoint(time_point);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result TimeZoneService::ParseTimeZoneBinary(Tz::Rule& out_rule, std::span<const u8> binary) {
|
||||
R_RETURN(m_time_zone.ParseBinaryInto(out_rule, binary));
|
||||
}
|
||||
|
||||
Result TimeZoneService::ToCalendarTime(CalendarTime& out_calendar_time,
|
||||
CalendarAdditionalInfo& out_additional_info, s64 time,
|
||||
Tz::Rule& rule) {
|
||||
R_RETURN(m_time_zone.ToCalendarTime(out_calendar_time, out_additional_info, time, rule));
|
||||
}
|
||||
|
||||
Result TimeZoneService::ToCalendarTimeWithMyRule(CalendarTime& out_calendar_time,
|
||||
CalendarAdditionalInfo& out_additional_info,
|
||||
s64 time) {
|
||||
R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time));
|
||||
}
|
||||
|
||||
Result TimeZoneService::ToPosixTime(u32& out_count, std::span<s64, 2> out_times,
|
||||
u32 out_times_count, CalendarTime& calendar_time,
|
||||
Tz::Rule& rule) {
|
||||
R_RETURN(m_time_zone.ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule));
|
||||
}
|
||||
|
||||
Result TimeZoneService::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times,
|
||||
u32 out_times_count, CalendarTime& calendar_time) {
|
||||
R_RETURN(
|
||||
m_time_zone.ToPosixTimeWithMyRule(out_count, out_times, out_times_count, calendar_time));
|
||||
}
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
69
src/core/hle/service/psc/time/time_zone_service.h
Executable file
69
src/core/hle/service/psc/time/time_zone_service.h
Executable file
@@ -0,0 +1,69 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
#include "core/hle/service/psc/time/manager.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Tz {
|
||||
struct Rule;
|
||||
}
|
||||
|
||||
namespace Service::PSC::Time {
|
||||
|
||||
class TimeZoneService final : public ServiceFramework<TimeZoneService> {
|
||||
public:
|
||||
explicit TimeZoneService(Core::System& system, StandardSteadyClockCore& clock_core,
|
||||
TimeZone& time_zone, bool can_write_timezone_device_location);
|
||||
|
||||
~TimeZoneService() override = default;
|
||||
|
||||
Result GetDeviceLocationName(LocationName& out_lcoation_name);
|
||||
Result GetTotalLocationNameCount(u32& out_count);
|
||||
Result GetTimeZoneRuleVersion(RuleVersion& out_rule_version);
|
||||
Result GetDeviceLocationNameAndUpdatedTime(SteadyClockTimePoint& out_time_point,
|
||||
LocationName& location_name);
|
||||
Result SetDeviceLocationNameWithTimeZoneRule(LocationName& location_name,
|
||||
std::span<const u8> binary);
|
||||
Result ParseTimeZoneBinary(Tz::Rule& out_rule, std::span<const u8> binary);
|
||||
Result ToCalendarTime(CalendarTime& out_calendar_time,
|
||||
CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule);
|
||||
Result ToCalendarTimeWithMyRule(CalendarTime& out_calendar_time,
|
||||
CalendarAdditionalInfo& out_additional_info, s64 time);
|
||||
Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
|
||||
CalendarTime& calendar_time, Tz::Rule& rule);
|
||||
Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count,
|
||||
CalendarTime& calendar_time);
|
||||
|
||||
private:
|
||||
void Handle_GetDeviceLocationName(HLERequestContext& ctx);
|
||||
void Handle_SetDeviceLocationName(HLERequestContext& ctx);
|
||||
void Handle_GetTotalLocationNameCount(HLERequestContext& ctx);
|
||||
void Handle_LoadLocationNameList(HLERequestContext& ctx);
|
||||
void Handle_LoadTimeZoneRule(HLERequestContext& ctx);
|
||||
void Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx);
|
||||
void Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx);
|
||||
void Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx);
|
||||
void Handle_ParseTimeZoneBinary(HLERequestContext& ctx);
|
||||
void Handle_GetDeviceLocationNameOperationEventReadableHandle(HLERequestContext& ctx);
|
||||
void Handle_ToCalendarTime(HLERequestContext& ctx);
|
||||
void Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx);
|
||||
void Handle_ToPosixTime(HLERequestContext& ctx);
|
||||
void Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx);
|
||||
|
||||
Core::System& m_system;
|
||||
|
||||
StandardSteadyClockCore& m_clock_core;
|
||||
TimeZone& m_time_zone;
|
||||
bool m_can_write_timezone_device_location;
|
||||
};
|
||||
|
||||
} // namespace Service::PSC::Time
|
||||
@@ -66,7 +66,6 @@
|
||||
#include "core/hle/service/sockets/sockets.h"
|
||||
#include "core/hle/service/spl/spl_module.h"
|
||||
#include "core/hle/service/ssl/ssl.h"
|
||||
#include "core/hle/service/time/time.h"
|
||||
#include "core/hle/service/usb/usb.h"
|
||||
#include "core/hle/service/vi/vi.h"
|
||||
#include "core/reporter.h"
|
||||
@@ -246,6 +245,9 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
|
||||
kernel.RunOnGuestCoreProcess("fatal", [&] { Fatal::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("fgm", [&] { FGM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("friends", [&] { Friend::LoopProcess(system); });
|
||||
// glue depends on settings and psc, so they must come first
|
||||
kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("glue", [&] { Glue::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("grc", [&] { GRC::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("hid", [&] { HID::LoopProcess(system); });
|
||||
@@ -269,13 +271,10 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
|
||||
kernel.RunOnGuestCoreProcess("pcv", [&] { PCV::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("prepo", [&] { PlayReport::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("time", [&] { Time::LoopProcess(system); });
|
||||
kernel.RunOnGuestCoreProcess("usb", [&] { USB::LoopProcess(system); });
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
63
src/core/hle/service/set/factory_settings_server.cpp
Executable file
63
src/core/hle/service/set/factory_settings_server.cpp
Executable file
@@ -0,0 +1,63 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/set/factory_settings_server.h"
|
||||
|
||||
namespace Service::Set {
|
||||
|
||||
IFactorySettingsServer::IFactorySettingsServer(Core::System& system_)
|
||||
: ServiceFramework{system_, "set:cal"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetBluetoothBdAddress"},
|
||||
{1, nullptr, "GetConfigurationId1"},
|
||||
{2, nullptr, "GetAccelerometerOffset"},
|
||||
{3, nullptr, "GetAccelerometerScale"},
|
||||
{4, nullptr, "GetGyroscopeOffset"},
|
||||
{5, nullptr, "GetGyroscopeScale"},
|
||||
{6, nullptr, "GetWirelessLanMacAddress"},
|
||||
{7, nullptr, "GetWirelessLanCountryCodeCount"},
|
||||
{8, nullptr, "GetWirelessLanCountryCodes"},
|
||||
{9, nullptr, "GetSerialNumber"},
|
||||
{10, nullptr, "SetInitialSystemAppletProgramId"},
|
||||
{11, nullptr, "SetOverlayDispProgramId"},
|
||||
{12, nullptr, "GetBatteryLot"},
|
||||
{14, nullptr, "GetEciDeviceCertificate"},
|
||||
{15, nullptr, "GetEticketDeviceCertificate"},
|
||||
{16, nullptr, "GetSslKey"},
|
||||
{17, nullptr, "GetSslCertificate"},
|
||||
{18, nullptr, "GetGameCardKey"},
|
||||
{19, nullptr, "GetGameCardCertificate"},
|
||||
{20, nullptr, "GetEciDeviceKey"},
|
||||
{21, nullptr, "GetEticketDeviceKey"},
|
||||
{22, nullptr, "GetSpeakerParameter"},
|
||||
{23, nullptr, "GetLcdVendorId"},
|
||||
{24, nullptr, "GetEciDeviceCertificate2"},
|
||||
{25, nullptr, "GetEciDeviceKey2"},
|
||||
{26, nullptr, "GetAmiiboKey"},
|
||||
{27, nullptr, "GetAmiiboEcqvCertificate"},
|
||||
{28, nullptr, "GetAmiiboEcdsaCertificate"},
|
||||
{29, nullptr, "GetAmiiboEcqvBlsKey"},
|
||||
{30, nullptr, "GetAmiiboEcqvBlsCertificate"},
|
||||
{31, nullptr, "GetAmiiboEcqvBlsRootCertificate"},
|
||||
{32, nullptr, "GetUsbTypeCPowerSourceCircuitVersion"},
|
||||
{33, nullptr, "GetAnalogStickModuleTypeL"},
|
||||
{34, nullptr, "GetAnalogStickModelParameterL"},
|
||||
{35, nullptr, "GetAnalogStickFactoryCalibrationL"},
|
||||
{36, nullptr, "GetAnalogStickModuleTypeR"},
|
||||
{37, nullptr, "GetAnalogStickModelParameterR"},
|
||||
{38, nullptr, "GetAnalogStickFactoryCalibrationR"},
|
||||
{39, nullptr, "GetConsoleSixAxisSensorModuleType"},
|
||||
{40, nullptr, "GetConsoleSixAxisSensorHorizontalOffset"},
|
||||
{41, nullptr, "GetBatteryVersion"},
|
||||
{42, nullptr, "GetDeviceId"},
|
||||
{43, nullptr, "GetConsoleSixAxisSensorMountType"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IFactorySettingsServer::~IFactorySettingsServer() = default;
|
||||
|
||||
} // namespace Service::Set
|
||||
20
src/core/hle/service/set/factory_settings_server.h
Executable file
20
src/core/hle/service/set/factory_settings_server.h
Executable file
@@ -0,0 +1,20 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::Set {
|
||||
|
||||
class IFactorySettingsServer final : public ServiceFramework<IFactorySettingsServer> {
|
||||
public:
|
||||
explicit IFactorySettingsServer(Core::System& system_);
|
||||
~IFactorySettingsServer() override;
|
||||
};
|
||||
|
||||
} // namespace Service::Set
|
||||
29
src/core/hle/service/set/firmware_debug_settings_server.cpp
Executable file
29
src/core/hle/service/set/firmware_debug_settings_server.cpp
Executable file
@@ -0,0 +1,29 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/set/firmware_debug_settings_server.h"
|
||||
|
||||
namespace Service::Set {
|
||||
|
||||
IFirmwareDebugSettingsServer::IFirmwareDebugSettingsServer(Core::System& system_)
|
||||
: ServiceFramework{system_, "set:fd"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{2, nullptr, "SetSettingsItemValue"},
|
||||
{3, nullptr, "ResetSettingsItemValue"},
|
||||
{4, nullptr, "CreateSettingsItemKeyIterator"},
|
||||
{10, nullptr, "ReadSettings"},
|
||||
{11, nullptr, "ResetSettings"},
|
||||
{20, nullptr, "SetWebInspectorFlag"},
|
||||
{21, nullptr, "SetAllowedSslHosts"},
|
||||
{22, nullptr, "SetHostFsMountPoint"},
|
||||
{23, nullptr, "SetMemoryUsageRateFlag"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IFirmwareDebugSettingsServer::~IFirmwareDebugSettingsServer() = default;
|
||||
|
||||
} // namespace Service::Set
|
||||
20
src/core/hle/service/set/firmware_debug_settings_server.h
Executable file
20
src/core/hle/service/set/firmware_debug_settings_server.h
Executable file
@@ -0,0 +1,20 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::Set {
|
||||
|
||||
class IFirmwareDebugSettingsServer final : public ServiceFramework<IFirmwareDebugSettingsServer> {
|
||||
public:
|
||||
explicit IFirmwareDebugSettingsServer(Core::System& system_);
|
||||
~IFirmwareDebugSettingsServer() override;
|
||||
};
|
||||
|
||||
} // namespace Service::Set
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/uuid.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
namespace Service::Set {
|
||||
|
||||
@@ -29,14 +29,14 @@ static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid s
|
||||
struct InitialLaunchSettings {
|
||||
InitialLaunchFlag flags;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
Service::Time::Clock::SteadyClockTimePoint timestamp;
|
||||
Service::PSC::Time::SteadyClockTimePoint timestamp;
|
||||
};
|
||||
static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size");
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct InitialLaunchSettingsPacked {
|
||||
InitialLaunchFlag flags;
|
||||
Service::Time::Clock::SteadyClockTimePoint timestamp;
|
||||
Service::PSC::Time::SteadyClockTimePoint timestamp;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C,
|
||||
|
||||
@@ -2,21 +2,24 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/set/set.h"
|
||||
#include "core/hle/service/set/set_cal.h"
|
||||
#include "core/hle/service/set/set_fd.h"
|
||||
#include "core/hle/service/set/set_sys.h"
|
||||
#include "core/hle/service/set/factory_settings_server.h"
|
||||
#include "core/hle/service/set/firmware_debug_settings_server.h"
|
||||
#include "core/hle/service/set/settings.h"
|
||||
#include "core/hle/service/set/settings_server.h"
|
||||
#include "core/hle/service/set/system_settings_server.h"
|
||||
|
||||
namespace Service::Set {
|
||||
|
||||
void LoopProcess(Core::System& system) {
|
||||
auto server_manager = std::make_unique<ServerManager>(system);
|
||||
|
||||
server_manager->RegisterNamedService("set", std::make_shared<SET>(system));
|
||||
server_manager->RegisterNamedService("set:cal", std::make_shared<SET_CAL>(system));
|
||||
server_manager->RegisterNamedService("set:fd", std::make_shared<SET_FD>(system));
|
||||
server_manager->RegisterNamedService("set:sys", std::make_shared<SET_SYS>(system));
|
||||
server_manager->RegisterNamedService("set", std::make_shared<ISettingsServer>(system));
|
||||
server_manager->RegisterNamedService("set:cal",
|
||||
std::make_shared<IFactorySettingsServer>(system));
|
||||
server_manager->RegisterNamedService("set:fd",
|
||||
std::make_shared<IFirmwareDebugSettingsServer>(system));
|
||||
server_manager->RegisterNamedService("set:sys",
|
||||
std::make_shared<ISystemSettingsServer>(system));
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
|
||||
|
||||
166
src/core/hle/service/set/settings_server.cpp
Executable file
166
src/core/hle/service/set/settings_server.cpp
Executable file
@@ -0,0 +1,166 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/set/settings_server.h"
|
||||
|
||||
namespace Service::Set {
|
||||
namespace {
|
||||
constexpr std::size_t PRE_4_0_0_MAX_ENTRIES = 0xF;
|
||||
constexpr std::size_t POST_4_0_0_MAX_ENTRIES = 0x40;
|
||||
|
||||
constexpr Result ResultInvalidLanguage{ErrorModule::Settings, 625};
|
||||
|
||||
void PushResponseLanguageCode(HLERequestContext& ctx, std::size_t num_language_codes) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(num_language_codes));
|
||||
}
|
||||
|
||||
void GetAvailableLanguageCodesImpl(HLERequestContext& ctx, std::size_t max_entries) {
|
||||
const std::size_t requested_amount = ctx.GetWriteBufferNumElements<LanguageCode>();
|
||||
const std::size_t max_amount = std::min(requested_amount, max_entries);
|
||||
const std::size_t copy_amount = std::min(available_language_codes.size(), max_amount);
|
||||
const std::size_t copy_size = copy_amount * sizeof(LanguageCode);
|
||||
|
||||
ctx.WriteBuffer(available_language_codes.data(), copy_size);
|
||||
PushResponseLanguageCode(ctx, copy_amount);
|
||||
}
|
||||
|
||||
void GetKeyCodeMapImpl(HLERequestContext& ctx) {
|
||||
const auto language_code =
|
||||
available_language_codes[static_cast<s32>(Settings::values.language_index.GetValue())];
|
||||
const auto key_code =
|
||||
std::find_if(language_to_layout.cbegin(), language_to_layout.cend(),
|
||||
[=](const auto& element) { return element.first == language_code; });
|
||||
KeyboardLayout layout = KeyboardLayout::EnglishUs;
|
||||
if (key_code == language_to_layout.cend()) {
|
||||
LOG_ERROR(Service_SET,
|
||||
"Could not find keyboard layout for language index {}, defaulting to English us",
|
||||
Settings::values.language_index.GetValue());
|
||||
} else {
|
||||
layout = key_code->second;
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(layout);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
LanguageCode GetLanguageCodeFromIndex(std::size_t index) {
|
||||
return available_language_codes.at(index);
|
||||
}
|
||||
|
||||
ISettingsServer::ISettingsServer(Core::System& system_) : ServiceFramework{system_, "set"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISettingsServer::GetLanguageCode, "GetLanguageCode"},
|
||||
{1, &ISettingsServer::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"},
|
||||
{2, &ISettingsServer::MakeLanguageCode, "MakeLanguageCode"},
|
||||
{3, &ISettingsServer::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"},
|
||||
{4, &ISettingsServer::GetRegionCode, "GetRegionCode"},
|
||||
{5, &ISettingsServer::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"},
|
||||
{6, &ISettingsServer::GetAvailableLanguageCodeCount2, "GetAvailableLanguageCodeCount2"},
|
||||
{7, &ISettingsServer::GetKeyCodeMap, "GetKeyCodeMap"},
|
||||
{8, &ISettingsServer::GetQuestFlag, "GetQuestFlag"},
|
||||
{9, &ISettingsServer::GetKeyCodeMap2, "GetKeyCodeMap2"},
|
||||
{10, nullptr, "GetFirmwareVersionForDebug"},
|
||||
{11, &ISettingsServer::GetDeviceNickName, "GetDeviceNickName"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ISettingsServer::~ISettingsServer() = default;
|
||||
|
||||
void ISettingsServer::GetAvailableLanguageCodes(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
GetAvailableLanguageCodesImpl(ctx, PRE_4_0_0_MAX_ENTRIES);
|
||||
}
|
||||
|
||||
void ISettingsServer::MakeLanguageCode(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto index = rp.Pop<u32>();
|
||||
|
||||
if (index >= available_language_codes.size()) {
|
||||
LOG_ERROR(Service_SET, "Invalid language code index! index={}", index);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(Set::ResultInvalidLanguage);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(available_language_codes[index]);
|
||||
}
|
||||
|
||||
void ISettingsServer::GetAvailableLanguageCodes2(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
GetAvailableLanguageCodesImpl(ctx, POST_4_0_0_MAX_ENTRIES);
|
||||
}
|
||||
|
||||
void ISettingsServer::GetAvailableLanguageCodeCount(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
PushResponseLanguageCode(ctx, PRE_4_0_0_MAX_ENTRIES);
|
||||
}
|
||||
|
||||
void ISettingsServer::GetAvailableLanguageCodeCount2(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
PushResponseLanguageCode(ctx, POST_4_0_0_MAX_ENTRIES);
|
||||
}
|
||||
|
||||
void ISettingsServer::GetQuestFlag(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<s32>(Settings::values.quest_flag.GetValue()));
|
||||
}
|
||||
|
||||
void ISettingsServer::GetLanguageCode(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index.GetValue());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushEnum(
|
||||
available_language_codes[static_cast<s32>(Settings::values.language_index.GetValue())]);
|
||||
}
|
||||
|
||||
void ISettingsServer::GetRegionCode(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(static_cast<u32>(Settings::values.region_index.GetValue()));
|
||||
}
|
||||
|
||||
void ISettingsServer::GetKeyCodeMap(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "Called {}", ctx.Description());
|
||||
GetKeyCodeMapImpl(ctx);
|
||||
}
|
||||
|
||||
void ISettingsServer::GetKeyCodeMap2(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "Called {}", ctx.Description());
|
||||
GetKeyCodeMapImpl(ctx);
|
||||
}
|
||||
|
||||
void ISettingsServer::GetDeviceNickName(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
ctx.WriteBuffer(Settings::values.device_name.GetValue());
|
||||
}
|
||||
|
||||
} // namespace Service::Set
|
||||
95
src/core/hle/service/set/settings_server.h
Executable file
95
src/core/hle/service/set/settings_server.h
Executable file
@@ -0,0 +1,95 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/set/system_settings.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::Set {
|
||||
enum class KeyboardLayout : u64 {
|
||||
Japanese = 0,
|
||||
EnglishUs = 1,
|
||||
EnglishUsInternational = 2,
|
||||
EnglishUk = 3,
|
||||
French = 4,
|
||||
FrenchCa = 5,
|
||||
Spanish = 6,
|
||||
SpanishLatin = 7,
|
||||
German = 8,
|
||||
Italian = 9,
|
||||
Portuguese = 10,
|
||||
Russian = 11,
|
||||
Korean = 12,
|
||||
ChineseSimplified = 13,
|
||||
ChineseTraditional = 14,
|
||||
};
|
||||
|
||||
constexpr std::array<LanguageCode, 18> available_language_codes = {{
|
||||
LanguageCode::JA,
|
||||
LanguageCode::EN_US,
|
||||
LanguageCode::FR,
|
||||
LanguageCode::DE,
|
||||
LanguageCode::IT,
|
||||
LanguageCode::ES,
|
||||
LanguageCode::ZH_CN,
|
||||
LanguageCode::KO,
|
||||
LanguageCode::NL,
|
||||
LanguageCode::PT,
|
||||
LanguageCode::RU,
|
||||
LanguageCode::ZH_TW,
|
||||
LanguageCode::EN_GB,
|
||||
LanguageCode::FR_CA,
|
||||
LanguageCode::ES_419,
|
||||
LanguageCode::ZH_HANS,
|
||||
LanguageCode::ZH_HANT,
|
||||
LanguageCode::PT_BR,
|
||||
}};
|
||||
|
||||
static constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{
|
||||
{LanguageCode::JA, KeyboardLayout::Japanese},
|
||||
{LanguageCode::EN_US, KeyboardLayout::EnglishUs},
|
||||
{LanguageCode::FR, KeyboardLayout::French},
|
||||
{LanguageCode::DE, KeyboardLayout::German},
|
||||
{LanguageCode::IT, KeyboardLayout::Italian},
|
||||
{LanguageCode::ES, KeyboardLayout::Spanish},
|
||||
{LanguageCode::ZH_CN, KeyboardLayout::ChineseSimplified},
|
||||
{LanguageCode::KO, KeyboardLayout::Korean},
|
||||
{LanguageCode::NL, KeyboardLayout::EnglishUsInternational},
|
||||
{LanguageCode::PT, KeyboardLayout::Portuguese},
|
||||
{LanguageCode::RU, KeyboardLayout::Russian},
|
||||
{LanguageCode::ZH_TW, KeyboardLayout::ChineseTraditional},
|
||||
{LanguageCode::EN_GB, KeyboardLayout::EnglishUk},
|
||||
{LanguageCode::FR_CA, KeyboardLayout::FrenchCa},
|
||||
{LanguageCode::ES_419, KeyboardLayout::SpanishLatin},
|
||||
{LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified},
|
||||
{LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional},
|
||||
{LanguageCode::PT_BR, KeyboardLayout::Portuguese},
|
||||
}};
|
||||
|
||||
LanguageCode GetLanguageCodeFromIndex(std::size_t idx);
|
||||
|
||||
class ISettingsServer final : public ServiceFramework<ISettingsServer> {
|
||||
public:
|
||||
explicit ISettingsServer(Core::System& system_);
|
||||
~ISettingsServer() override;
|
||||
|
||||
private:
|
||||
void GetLanguageCode(HLERequestContext& ctx);
|
||||
void GetAvailableLanguageCodes(HLERequestContext& ctx);
|
||||
void MakeLanguageCode(HLERequestContext& ctx);
|
||||
void GetAvailableLanguageCodes2(HLERequestContext& ctx);
|
||||
void GetAvailableLanguageCodeCount(HLERequestContext& ctx);
|
||||
void GetAvailableLanguageCodeCount2(HLERequestContext& ctx);
|
||||
void GetQuestFlag(HLERequestContext& ctx);
|
||||
void GetRegionCode(HLERequestContext& ctx);
|
||||
void GetKeyCodeMap(HLERequestContext& ctx);
|
||||
void GetKeyCodeMap2(HLERequestContext& ctx);
|
||||
void GetDeviceNickName(HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
} // namespace Service::Set
|
||||
@@ -28,7 +28,7 @@ SystemSettings DefaultSystemSettings() {
|
||||
.cmu_mode = CmuMode::None,
|
||||
.tv_underscan = {},
|
||||
.tv_gama = 1.0f,
|
||||
.constrast_ratio = 0.5f,
|
||||
.contrast_ratio = 0.5f,
|
||||
};
|
||||
|
||||
settings.initial_launch_settings_packed = {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/set/private_settings.h"
|
||||
#include "core/hle/service/time/clock_types.h"
|
||||
|
||||
namespace Service::Set {
|
||||
|
||||
@@ -208,7 +207,7 @@ struct TvSettings {
|
||||
CmuMode cmu_mode;
|
||||
u32 tv_underscan;
|
||||
f32 tv_gama;
|
||||
f32 constrast_ratio;
|
||||
f32 contrast_ratio;
|
||||
};
|
||||
static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size");
|
||||
|
||||
@@ -270,7 +269,7 @@ struct EulaVersion {
|
||||
EulaVersionClockType clock_type;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
s64 posix_time;
|
||||
Time::Clock::SteadyClockTimePoint timestamp;
|
||||
Service::PSC::Time::SteadyClockTimePoint timestamp;
|
||||
};
|
||||
static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
|
||||
|
||||
@@ -341,7 +340,7 @@ struct SystemSettings {
|
||||
std::array<u8, 0x3C> reserved_09934;
|
||||
|
||||
// nn::settings::system::ErrorReportSharePermission
|
||||
ErrorReportSharePermission error_report_share_permssion;
|
||||
ErrorReportSharePermission error_report_share_permission;
|
||||
|
||||
std::array<u8, 0x3C> reserved_09974;
|
||||
|
||||
@@ -481,13 +480,13 @@ struct SystemSettings {
|
||||
std::array<u8, 0x64> reserved_2951C;
|
||||
|
||||
// nn::time::SystemClockContext
|
||||
Service::Time::Clock::SystemClockContext user_system_clock_context;
|
||||
Service::Time::Clock::SystemClockContext network_system_clock_context;
|
||||
Service::PSC::Time::SystemClockContext user_system_clock_context;
|
||||
Service::PSC::Time::SystemClockContext network_system_clock_context;
|
||||
bool user_system_clock_automatic_correction_enabled;
|
||||
std::array<u8, 0x3> pad_295C1;
|
||||
std::array<u8, 0x4> reserved_295C4;
|
||||
// nn::time::SteadyClockTimePoint
|
||||
Service::Time::Clock::SteadyClockTimePoint
|
||||
Service::PSC::Time::SteadyClockTimePoint
|
||||
user_system_clock_automatic_correction_updated_time_point;
|
||||
|
||||
std::array<u8, 0x10> reserved_295E0;
|
||||
@@ -580,10 +579,10 @@ struct SystemSettings {
|
||||
std::array<u8, 0x6B> reserved_29ED5;
|
||||
|
||||
// nn::time::LocationName
|
||||
Service::Time::TimeZone::LocationName device_time_zone_location_name;
|
||||
Service::PSC::Time::LocationName device_time_zone_location_name;
|
||||
std::array<u8, 0x4> reserved_29F64;
|
||||
// nn::time::SteadyClockTimePoint
|
||||
Service::Time::Clock::SteadyClockTimePoint device_time_zone_location_updated_time;
|
||||
Service::PSC::Time::SteadyClockTimePoint device_time_zone_location_updated_time;
|
||||
|
||||
std::array<u8, 0xC0> reserved_29F80;
|
||||
|
||||
|
||||
1279
src/core/hle/service/set/system_settings_server.cpp
Executable file
1279
src/core/hle/service/set/system_settings_server.cpp
Executable file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user